This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

1use crate::{Fill, Filter, Point, Region, Transformation}; 2#[cfg(feature = "web")] 3use wasm_bindgen::prelude::*; 4 5use super::{fill::FillOperations, Color}; 6 7#[derive(Debug, Clone, PartialEq, Eq)] 8pub enum LineSegment { 9 Straight(Point), 10 InwardCurve(Point), 11 OutwardCurve(Point), 12} 13 14#[derive(Debug, Clone)] 15pub enum Object { 16 Polygon(Point, Vec<LineSegment>), 17 Line(Point, Point, f32), 18 CurveOutward(Point, Point, f32), 19 CurveInward(Point, Point, f32), 20 SmallCircle(Point), 21 Dot(Point), 22 BigCircle(Point), 23 Text(Point, String, f32), 24 CenteredText(Point, String, f32), 25 // FittedText(Region, String), 26 Rectangle(Point, Point), 27 Image(Region, String), 28 RawSVG(String), 29 // Tiling(Region, Box<Object>), 30} 31 32impl Object { 33 pub fn filled(self, fill: Fill) -> ColoredObject { 34 ColoredObject::from((self, Some(fill))) 35 } 36 37 pub fn colored(self, color: Color) -> ColoredObject { 38 ColoredObject::from((self, None)).colored(color) 39 } 40 41 pub fn filtered(self, filter: Filter) -> ColoredObject { 42 ColoredObject::from((self, None)).filtered(filter) 43 } 44 45 pub fn transform(self, transformation: Transformation) -> ColoredObject { 46 ColoredObject::from((self, None)).transformed(transformation) 47 } 48} 49 50#[derive(Debug, Clone)] 51pub struct ColoredObject { 52 pub object: Object, 53 pub fill: Option<Fill>, 54 pub filters: Vec<Filter>, 55 pub transformations: Vec<Transformation>, 56} 57 58impl ColoredObject { 59 pub fn filtered(mut self, filter: Filter) -> Self { 60 self.filters.push(filter); 61 self 62 } 63 64 pub fn transformed(mut self, transformation: Transformation) -> Self { 65 self.transformations.push(transformation); 66 self 67 } 68 69 pub fn filled(mut self, fill: Fill) -> Self { 70 self.fill = Some(fill); 71 self 72 } 73 74 pub fn colored(mut self, color: Color) -> Self { 75 self.fill = Some(Fill::Solid(color)); 76 self 77 } 78 79 pub fn opacified(mut self, opacity: f32) -> Self { 80 if let Some(fill) = &mut self.fill { 81 *fill = fill.opacify(opacity); 82 } 83 self 84 } 85 86 pub fn clear_filters(&mut self) { 87 self.filters.clear(); 88 } 89 90 pub fn refill(&mut self, fill: Fill) { 91 self.fill = Some(fill); 92 } 93 94 pub fn recolor(&mut self, color: Color) { 95 self.fill = Some(Fill::Solid(color)) 96 } 97 98 pub fn filter(&mut self, filter: Filter) { 99 self.filters.push(filter) 100 } 101 102 pub fn region(&self) -> Region { 103 self.object.region() 104 } 105} 106 107impl std::fmt::Display for ColoredObject { 108 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 109 let ColoredObject { 110 object, 111 fill, 112 filters, 113 transformations, 114 } = self; 115 116 if fill.is_some() { 117 write!(f, "{:?} {:?}", fill.unwrap(), object)?; 118 } else { 119 write!(f, "transparent {:?}", object)?; 120 } 121 122 if !filters.is_empty() { 123 write!(f, " with filters {:?}", filters)?; 124 } 125 126 if !transformations.is_empty() { 127 write!(f, " with transformations {:?}", transformations)?; 128 } 129 130 Ok(()) 131 } 132} 133 134impl From<Object> for ColoredObject { 135 fn from(value: Object) -> Self { 136 ColoredObject { 137 object: value, 138 fill: None, 139 filters: vec![], 140 transformations: vec![], 141 } 142 } 143} 144 145impl From<(Object, Option<Fill>)> for ColoredObject { 146 fn from((object, fill): (Object, Option<Fill>)) -> Self { 147 ColoredObject { 148 object, 149 fill, 150 filters: vec![], 151 transformations: vec![], 152 } 153 } 154} 155 156#[cfg_attr(feature = "web", wasm_bindgen)] 157#[derive(Debug, Clone, Copy)] 158pub struct ObjectSizes { 159 pub empty_shape_stroke_width: f32, 160 pub small_circle_radius: f32, 161 pub dot_radius: f32, 162 pub default_line_width: f32, 163} 164 165impl Default for ObjectSizes { 166 fn default() -> Self { 167 Self { 168 empty_shape_stroke_width: 0.5, 169 small_circle_radius: 5.0, 170 dot_radius: 2.0, 171 default_line_width: 2.0, 172 } 173 } 174} 175 176impl Object { 177 pub fn translate(&mut self, dx: i32, dy: i32) { 178 match self { 179 Object::Polygon(start, lines) => { 180 start.translate(dx, dy); 181 for line in lines { 182 match line { 183 LineSegment::InwardCurve(anchor) 184 | LineSegment::OutwardCurve(anchor) 185 | LineSegment::Straight(anchor) => { 186 anchor.translate(dx, dy) 187 } 188 } 189 } 190 } 191 Object::Line(start, end, _) 192 | Object::CurveInward(start, end, _) 193 | Object::CurveOutward(start, end, _) 194 | Object::Rectangle(start, end) => { 195 start.translate(dx, dy); 196 end.translate(dx, dy); 197 } 198 Object::Text(anchor, _, _) 199 | Object::CenteredText(anchor, ..) 200 | Object::Dot(anchor) 201 | Object::SmallCircle(anchor) => anchor.translate(dx, dy), 202 Object::BigCircle(center) => center.translate(dx, dy), 203 Object::Image(region, ..) => region.translate(dx, dy), 204 Object::RawSVG(_) => { 205 unimplemented!() 206 } 207 } 208 } 209 210 pub fn translate_with(&mut self, delta: (i32, i32)) { 211 self.translate(delta.0, delta.1) 212 } 213 214 pub fn teleport(&mut self, x: i32, y: i32) { 215 let Point(current_x, current_y) = self.region().start; 216 let delta_x = x - current_x as i32; 217 let delta_y = y - current_y as i32; 218 self.translate(delta_x, delta_y); 219 } 220 221 pub fn teleport_with(&mut self, position: (i32, i32)) { 222 self.teleport(position.0, position.1) 223 } 224 225 pub fn region(&self) -> Region { 226 match self { 227 Object::Polygon(start, lines) => { 228 let mut region: Region = (start, start).into(); 229 for line in lines { 230 match line { 231 LineSegment::InwardCurve(anchor) 232 | LineSegment::OutwardCurve(anchor) 233 | LineSegment::Straight(anchor) => { 234 // println!( 235 // "extending region {} with {}", 236 // region, 237 // Region::from((start, anchor)) 238 // ); 239 region = *region.max(&(start, anchor).into()) 240 } 241 } 242 } 243 // println!("region for {:?} -> {}", self, region); 244 region 245 } 246 Object::Line(start, end, _) 247 | Object::CurveInward(start, end, _) 248 | Object::CurveOutward(start, end, _) 249 | Object::Rectangle(start, end) => (start, end).into(), 250 Object::Text(anchor, _, _) 251 | Object::CenteredText(anchor, ..) 252 | Object::Dot(anchor) 253 | Object::SmallCircle(anchor) => anchor.region(), 254 Object::BigCircle(center) => center.region(), 255 Object::Image(region, ..) => *region, 256 Object::RawSVG(_) => { 257 unimplemented!() 258 } 259 } 260 } 261 262 pub fn fillable(&self) -> bool { 263 !matches!( 264 self, 265 Object::Line(..) | Object::CurveInward(..) | Object::CurveOutward(..) 266 ) 267 } 268 269 pub fn hatchable(&self) -> bool { 270 self.fillable() && !matches!(self, Object::Dot(..)) 271 } 272}