1use std::borrow::BorrowMut;
2
3use euclid::default::Point2D;
4use euclid::{point2, Trig};
5use num_traits::{Float, FloatConst, FromPrimitive};
6use svg_path_ops::{absolutize, normalize};
7use svgtypes::{PathParser, PathSegment};
8
9use super::core::{Options, _c};
10use crate::core::{FillStyle, Op, OpSet, OpSetType, OpType, _cc};
11use crate::filler::get_filler;
12use crate::filler::FillerType::{
13 DashedFiller, DotFiller, HatchFiller, ScanLineHachure, ZigZagFiller, ZigZagLineFiller,
14};
15use crate::geometry::{convert_bezier_quadratic_to_cubic, BezierQuadratic};
16
17#[derive(PartialEq, Eq, Debug)]
18pub struct EllipseParams<F: Float> {
19 pub rx: F,
20 pub ry: F,
21 pub increment: F,
22}
23
24pub struct EllipseResult<F: Float + FromPrimitive + Trig> {
25 pub opset: OpSet<F>,
26 pub estimated_points: Vec<Point2D<F>>,
27}
28
29pub fn line<F: Float + Trig + FromPrimitive>(
54 x1: F,
55 y1: F,
56 x2: F,
57 y2: F,
58 o: &mut Options,
59) -> OpSet<F> {
60 OpSet {
61 op_set_type: OpSetType::Path,
62 ops: _double_line(x1, y1, x2, y2, o, false),
63 size: None,
64 path: None,
65 }
66}
67
68pub fn linear_path<F: Float + Trig + FromPrimitive>(
99 points: &[Point2D<F>],
100 close: bool,
101 o: &mut Options,
102) -> OpSet<F> {
103 let len = points.len();
104 if len > 2 {
105 let mut ops: Vec<Op<F>> = Vec::new();
106 let mut i = 0;
107 while i < (len - 1) {
108 ops.append(&mut _double_line(
109 points[i].x,
110 points[i].y,
111 points[i + 1].x,
112 points[i + 1].y,
113 o,
114 false,
115 ));
116 i += 1;
117 }
118 if close {
119 ops.append(&mut _double_line(
120 points[len - 1].x,
121 points[len - 1].y,
122 points[0].x,
123 points[0].y,
124 o,
125 false,
126 ));
127 }
128 OpSet {
129 op_set_type: OpSetType::Path,
130 ops,
131 path: None,
132 size: None,
133 }
134 } else if len == 2 {
135 line(points[0].x, points[0].y, points[1].x, points[1].y, o)
136 } else {
137 OpSet {
138 op_set_type: OpSetType::Path,
139 ops: Vec::new(),
140 path: None,
141 size: None,
142 }
143 }
144}
145
146pub fn polygon<F: Float + Trig + FromPrimitive>(
147 points: &[Point2D<F>],
148 o: &mut Options,
149) -> OpSet<F> {
150 linear_path(points, true, o)
151}
152
153pub fn rectangle<F: Float + Trig + FromPrimitive>(
154 x: F,
155 y: F,
156 width: F,
157 height: F,
158 o: &mut Options,
159) -> OpSet<F> {
160 let points: Vec<Point2D<F>> = vec![
161 Point2D::new(x, y),
162 Point2D::new(x + width, y),
163 Point2D::new(x + width, y + height),
164 Point2D::new(x, y + height),
165 ];
166 polygon(&points, o)
167}
168
169pub fn bezier_quadratic<F: Float + Trig + FromPrimitive>(
170 start: Point2D<F>,
171 cp: Point2D<F>,
172 end: Point2D<F>,
173 o: &mut Options,
174) -> OpSet<F> {
175 let ops = _bezier_quadratic_to(cp.x, cp.y, end.x, end.y, &start, o);
176
177 OpSet {
178 op_set_type: OpSetType::Path,
179 ops,
180 path: None,
181 size: None,
182 }
183}
184
185pub fn bezier_cubic<F: Float + Trig + FromPrimitive>(
186 start: Point2D<F>,
187 cp1: Point2D<F>,
188 cp2: Point2D<F>,
189 end: Point2D<F>,
190 o: &mut Options,
191) -> OpSet<F> {
192 let ops = _bezier_to(cp1.x, cp1.y, cp2.x, cp2.y, end.x, end.y, &start, o);
193
194 OpSet {
195 op_set_type: OpSetType::Path,
196 ops,
197 path: None,
198 size: None,
199 }
200}
201
202pub fn curve<F: Float + Trig + FromPrimitive>(points: &[Point2D<F>], o: &mut Options) -> OpSet<F> {
203 let mut o1 = _curve_with_offset(
204 points,
205 _c::<F>(1.0) * _c(1.0 + o.roughness.unwrap_or(0.0) * 0.2),
206 o,
207 );
208 if !o.disable_multi_stroke.unwrap_or(false) {
209 let mut o2 = _curve_with_offset(
210 points,
211 _c::<F>(1.5) * _c(1.0 + o.roughness.unwrap_or(0.0) * 0.22),
212 &mut clone_options_alter_seed(o),
213 );
214 o1.append(&mut o2);
215 }
216 OpSet {
217 op_set_type: OpSetType::Path,
218 ops: o1,
219 path: None,
220 size: None,
221 }
222}
223
224pub fn ellipse<F: Float + Trig + FromPrimitive>(
225 x: F,
226 y: F,
227 width: F,
228 height: F,
229 o: &mut Options,
230) -> OpSet<F> {
231 let params = generate_ellipse_params(width, height, o);
232 ellipse_with_params(x, y, o, ¶ms).opset
233}
234
235pub fn generate_ellipse_params<F: Float + Trig + FromPrimitive>(
236 width: F,
237 height: F,
238 o: &mut Options,
239) -> EllipseParams<F> {
240 let psq: F = Float::sqrt(
241 _cc::<F>(std::f64::consts::PI * 2.0)
242 * Float::sqrt(
243 (Float::powi(width / _c(2.0), 2) + Float::powi(height / _c(2.0), 2)) / _c(2.0),
244 ),
245 );
246 let step_count: F = Float::ceil(Float::max(
247 _c(o.curve_step_count.unwrap_or(1.0)),
248 _c::<F>(o.curve_step_count.unwrap_or(1.0) / Float::sqrt(200.0)) * psq,
249 ));
250 let increment: F = _cc::<F>(std::f64::consts::PI * 2.0) / step_count;
251 let mut rx = Float::abs(width / _c(2.0));
252 let mut ry = Float::abs(height / _c(2.0));
253 let curve_fit_randomness: F = _c::<F>(1.0) - _c(o.curve_fitting.unwrap_or(0.0));
254 rx = rx + _offset_opt(rx * curve_fit_randomness, o, None);
255 ry = ry + _offset_opt(ry * curve_fit_randomness, o, None);
256 EllipseParams { increment, rx, ry }
257}
258
259pub fn ellipse_with_params<F: Float + Trig + FromPrimitive>(
260 x: F,
261 y: F,
262 o: &mut Options,
263 ellipse_params: &EllipseParams<F>,
264) -> EllipseResult<F> {
265 let ellipse_points = _compute_ellipse_points(
266 ellipse_params.increment,
267 x,
268 y,
269 ellipse_params.rx,
270 ellipse_params.ry,
271 _c(1.0),
272 ellipse_params.increment
273 * _offset(
274 _c(0.1),
275 _offset(_c::<F>(0.4), _c::<F>(1.0), o, None),
276 o,
277 None,
278 ),
279 o,
280 );
281 let ap1 = ellipse_points[0].clone();
282 let cp1 = ellipse_points[1].clone();
283 let mut o1 = _curve(&ap1, None, o);
284 if (!o.disable_multi_stroke.unwrap_or(false)) && (o.roughness.unwrap_or(0.0) != 0.0) {
285 let inner_ellipse_points = _compute_ellipse_points(
286 ellipse_params.increment,
287 x,
288 y,
289 ellipse_params.rx,
290 ellipse_params.ry,
291 _c::<F>(1.5),
292 _c::<F>(0.0),
293 o,
294 );
295 let ap2 = inner_ellipse_points[0].clone();
296 let _cp2 = inner_ellipse_points[1].clone();
297 let mut o2 = _curve(&ap2, None, o);
298 o1.append(&mut o2);
299 }
300 EllipseResult {
301 estimated_points: cp1,
302 opset: OpSet {
303 op_set_type: OpSetType::Path,
304 ops: o1,
305 size: None,
306 path: None,
307 },
308 }
309}
310
311#[allow(clippy::too_many_arguments)]
312pub fn arc<F: Float + Trig + FromPrimitive>(
313 x: F,
314 y: F,
315 width: F,
316 height: F,
317 start: F,
318 stop: F,
319 closed: bool,
320 rough_closure: bool,
321 o: &mut Options,
322) -> OpSet<F> {
323 let cx = x;
324 let cy = y;
325 let mut rx = Float::abs(width / _c(2.0));
326 let mut ry = Float::abs(height / _c(2.0));
327 rx = rx + _offset_opt(rx * _c(0.01), o, None);
328 ry = ry + _offset_opt(ry * _c(0.01), o, None);
329 let mut strt: F = start;
330 let mut stp: F = stop;
331 while strt < _c(0.0) {
332 strt = strt + _c(f32::PI() * 2.0);
333 stp = stp + _c(f32::PI() * 2.0);
334 }
335 if (stp - strt) > _c(f32::PI() * 2.0) {
336 strt = _c(0.0);
337 stp = _c(f32::PI() * 2.0);
338 }
339 let ellipse_inc: F = _c::<F>(f32::PI() * 2.0) / _c(o.curve_step_count.unwrap_or(1.0));
340 let arc_inc = Float::min(ellipse_inc / _c(2.0), (stp - strt) / _c(2.0));
341 let mut ops = _arc(arc_inc, cx, cy, rx, ry, strt, stp, _c(1.0), o);
342 if !o.disable_multi_stroke.unwrap_or(false) {
343 let mut o2 = _arc(arc_inc, cx, cy, rx, ry, strt, stp, _c(1.5), o);
344 ops.append(&mut o2);
345 }
346 if closed {
347 if rough_closure {
348 ops.append(&mut _double_line(
349 cx,
350 cy,
351 cx + rx * Float::cos(strt),
352 cy + ry * Float::sin(strt),
353 o,
354 false,
355 ));
356 ops.append(&mut _double_line(
357 cx,
358 cy,
359 cx + rx * Float::cos(stp),
360 cy + ry * Float::sin(stp),
361 o,
362 false,
363 ));
364 } else {
365 ops.push(Op {
366 op: OpType::LineTo,
367 data: vec![cx, cy],
368 });
369 ops.push(Op {
370 op: OpType::LineTo,
371 data: vec![cx + rx * Float::cos(strt), cy + ry * Float::sin(strt)],
372 });
373 }
374 }
375 OpSet {
376 op_set_type: OpSetType::Path,
377 ops,
378 path: None,
379 size: None,
380 }
381}
382
383pub fn solid_fill_polygon<F: Float + Trig + FromPrimitive>(
384 polygon_list: &Vec<Vec<Point2D<F>>>,
385 options: &mut Options,
386) -> OpSet<F> {
387 let mut ops = vec![];
388 for polygon in polygon_list {
389 if polygon.len() > 2 {
390 let rand_offset = _c(options.max_randomness_offset.unwrap_or(2.0));
391 polygon.iter().enumerate().for_each(|(ind, point)| {
392 if ind == 0 {
393 ops.push(Op {
394 op: OpType::Move,
395 data: vec![
396 point.x + _offset_opt(rand_offset, options, None),
397 point.y + _offset_opt(rand_offset, options, None),
398 ],
399 });
400 } else {
401 ops.push(Op {
402 op: OpType::LineTo,
403 data: vec![
404 point.x + _offset_opt(rand_offset, options, None),
405 point.y + _offset_opt(rand_offset, options, None),
406 ],
407 });
408 }
409 })
410 }
411 }
412 OpSet {
413 op_set_type: OpSetType::FillPath,
414 ops,
415 size: None,
416 path: None,
417 }
418}
419
420pub fn rand_offset<F: Float + Trig + FromPrimitive>(x: F, o: &mut Options) -> F {
421 _offset_opt(x, o, None)
422}
423
424pub fn rand_offset_with_range<F: Float + Trig + FromPrimitive>(
425 min: F,
426 max: F,
427 o: &mut Options,
428) -> F {
429 _offset(min, max, o, None)
430}
431
432pub fn double_line_fill_ops<F: Float + Trig + FromPrimitive>(
433 x1: F,
434 y1: F,
435 x2: F,
436 y2: F,
437 o: &mut Options,
438) -> Vec<Op<F>> {
439 _double_line(x1, y1, x2, y2, o, true)
440}
441
442fn clone_options_alter_seed(ops: &mut Options) -> Options {
443 let mut result: Options = ops.clone();
448 result.randomizer = None;
449 if let Some(seed) = ops.seed {
450 if seed != 0 {
451 result.seed = Some(seed + 1);
452 }
453 }
454 result
455}
456
457fn _offset<F: Float + Trig + FromPrimitive>(
458 min: F,
459 max: F,
460 ops: &mut Options,
461 roughness_gain: Option<F>,
462) -> F {
463 let rg: F = roughness_gain.unwrap_or_else(|| _c(1.0));
464 _c::<F>(ops.roughness.unwrap_or(1.0)) * rg * ((_cc::<F>(ops.random()) * (max - min)) + min)
465}
466
467fn _offset_opt<F: Float + Trig + FromPrimitive>(
468 x: F,
469 ops: &mut Options,
470 roughness_gain: Option<F>,
471) -> F {
472 _offset(-x, x, ops, roughness_gain)
473}
474
475fn _line<F: Float + Trig + FromPrimitive>(
476 x1: F,
477 y1: F,
478 x2: F,
479 y2: F,
480 o: &mut Options,
481 mover: bool,
482 overlay: bool,
483) -> Vec<Op<F>> {
484 let length_sq = (x1 - x2).powi(2) + (y1 - y2).powi(2);
485 let length = length_sq.sqrt();
486 let roughness_gain;
487 if length < _c(200.0_f32) {
488 roughness_gain = _c(1.0);
489 } else if length > _c(500.0) {
490 roughness_gain = _c(0.4);
491 } else {
492 roughness_gain = _c::<F>(-0.0016668) * length + _c(1.233334);
493 }
494
495 let mut offset = _c(o.max_randomness_offset.unwrap_or(2.0));
496 if (offset * offset * _c(100.0)) > length_sq {
497 offset = length / _c(10.0);
498 }
499 let half_offset = offset / _c(2.0);
500 let diverge_point = _c::<F>(0.2) + _cc::<F>(o.random()) * _c(0.2);
501 let mut mid_disp_x =
502 _c::<F>(o.bowing.unwrap_or(1.0)) * _c(o.max_randomness_offset.unwrap_or(2.0)) * (y2 - y1)
503 / _c(200.0);
504 let mut mid_disp_y =
505 _c::<F>(o.bowing.unwrap_or(1.0)) * _c(o.max_randomness_offset.unwrap_or(2.0)) * (x1 - x2)
506 / _c(200.0);
507 mid_disp_x = _offset_opt(mid_disp_x, o, Some(roughness_gain));
508 mid_disp_y = _offset_opt(mid_disp_y, o, Some(roughness_gain));
509 let mut ops: Vec<Op<F>> = Vec::new();
510
511 let preserve_vertices = o.preserve_vertices.unwrap_or(false);
512 if mover {
513 if overlay {
514 ops.push(Op {
515 op: OpType::Move,
516 data: vec![
517 x1 + if preserve_vertices {
518 _c(0.0)
519 } else {
520 _offset_opt(half_offset, o, Some(roughness_gain))
521 },
522 y1 + if preserve_vertices {
523 _c(0.0)
524 } else {
525 _offset_opt(half_offset, o, Some(roughness_gain))
526 },
527 ],
528 });
529 } else {
530 ops.push(Op {
531 op: OpType::Move,
532 data: vec![
533 x1 + if preserve_vertices {
534 _c(0.0)
535 } else {
536 _offset_opt(offset, o, Some(roughness_gain))
537 },
538 y1 + if preserve_vertices {
539 _c(0.0)
540 } else {
541 _offset_opt(offset, o, Some(roughness_gain))
542 },
543 ],
544 });
545 }
546 }
547 if overlay {
548 ops.push(Op {
549 op: OpType::BCurveTo,
550 data: vec![
551 mid_disp_x
552 + x1
553 + (x2 - x1) * diverge_point
554 + _offset_opt(half_offset, o, Some(roughness_gain)),
555 mid_disp_y
556 + y1
557 + (y2 - y1) * diverge_point
558 + _offset_opt(half_offset, o, Some(roughness_gain)),
559 mid_disp_x
560 + x1
561 + _c::<F>(2.0) * (x2 - x1) * diverge_point
562 + _offset_opt(half_offset, o, Some(roughness_gain)),
563 mid_disp_y
564 + y1
565 + _c::<F>(2.0) * (y2 - y1) * diverge_point
566 + _offset_opt(half_offset, o, Some(roughness_gain)),
567 x2 + if preserve_vertices {
568 _c(0.0)
569 } else {
570 _offset_opt(half_offset, o, Some(roughness_gain))
571 },
572 y2 + if preserve_vertices {
573 _c(0.0)
574 } else {
575 _offset_opt(half_offset, o, Some(roughness_gain))
576 },
577 ],
578 });
579 } else {
580 ops.push(Op {
581 op: OpType::BCurveTo,
582 data: vec![
583 mid_disp_x
584 + x1
585 + (x2 - x1) * diverge_point
586 + _offset_opt(offset, o, Some(roughness_gain)),
587 mid_disp_y
588 + y1
589 + (y2 - y1) * diverge_point
590 + _offset_opt(offset, o, Some(roughness_gain)),
591 mid_disp_x
592 + x1
593 + _c::<F>(2.0) * (x2 - x1) * diverge_point
594 + _offset_opt(offset, o, Some(roughness_gain)),
595 mid_disp_y
596 + y1
597 + _c::<F>(2.0) * (y2 - y1) * diverge_point
598 + _offset_opt(offset, o, Some(roughness_gain)),
599 x2 + if preserve_vertices {
600 _c(0.0)
601 } else {
602 _offset_opt(offset, o, Some(roughness_gain))
603 },
604 y2 + if preserve_vertices {
605 _c(0.0)
606 } else {
607 _offset_opt(offset, o, Some(roughness_gain))
608 },
609 ],
610 });
611 }
612 ops
613}
614
615pub(crate) fn _double_line<F: Float + Trig + FromPrimitive>(
616 x1: F,
617 y1: F,
618 x2: F,
619 y2: F,
620 o: &mut Options,
621 filling: bool,
622) -> Vec<Op<F>> {
623 let single_stroke = if filling {
624 o.disable_multi_stroke_fill.unwrap_or(false)
625 } else {
626 o.disable_multi_stroke.unwrap_or(false)
627 };
628 let mut o1 = _line(x1, y1, x2, y2, o, true, false);
629 if single_stroke {
630 o1
631 } else {
632 let mut o2 = _line(x1, y1, x2, y2, o, true, true);
633 o1.append(&mut o2);
634 o1
635 }
636}
637
638pub(crate) fn _curve<F: Float + Trig + FromPrimitive>(
639 points: &[Point2D<F>],
640 close_point: Option<Point2D<F>>,
641 o: &mut Options,
642) -> Vec<Op<F>> {
643 let len = points.len();
644 let mut ops: Vec<Op<F>> = vec![];
645 if len > 3 {
646 let mut b: [[F; 2]; 4] = [[_c(0.0); 2]; 4];
647 let s: F = _c::<F>(1.0) - _c(o.curve_tightness.unwrap_or(0.0));
648 ops.push(Op {
649 op: OpType::Move,
650 data: vec![points[1].x, points[1].y],
651 });
652 let mut i = 1;
653 while (i + 2) < len {
654 let cached_vert_array = points[i];
655 b[0] = [cached_vert_array.x, cached_vert_array.y];
656 b[1] = [
657 cached_vert_array.x + (s * points[i + 1].x - s * points[i - 1].x) / _c(6.0),
658 cached_vert_array.y + (s * points[i + 1].y - s * points[i - 1].y) / _c(6.0),
659 ];
660 b[2] = [
661 points[i + 1].x + (s * points[i].x - s * points[i + 2].x) / _c(6.0),
662 points[i + 1].y + (s * points[i].y - s * points[i + 2].y) / _c(6.0),
663 ];
664 b[3] = [points[i + 1].x, points[i + 1].y];
665 ops.push(Op {
666 op: OpType::BCurveTo,
667 data: vec![b[1][0], b[1][1], b[2][0], b[2][1], b[3][0], b[3][1]],
668 });
669 i += 1;
670 }
671 if let Some(cp) = close_point {
672 let ro = _c(o.max_randomness_offset.unwrap_or(2.0));
673 ops.push(Op {
674 op: OpType::LineTo,
675 data: vec![
676 cp.x + _offset_opt(ro, o, None),
677 cp.y + _offset_opt(ro, o, None),
678 ],
679 });
680 }
681 } else if len == 3 {
682 ops.push(Op {
683 op: OpType::Move,
684 data: vec![points[1].x, points[1].y],
685 });
686 ops.push(Op {
687 op: OpType::BCurveTo,
688 data: vec![
689 points[1].x,
690 points[1].y,
691 points[2].x,
692 points[2].y,
693 points[2].x,
694 points[2].y,
695 ],
696 });
697 } else if len == 2 {
698 ops.append(&mut _double_line(
699 points[0].x,
700 points[0].y,
701 points[1].x,
702 points[1].y,
703 o,
704 false,
705 ));
706 }
707 ops
708}
709
710fn _curve_with_offset<F: Float + Trig + FromPrimitive>(
711 points: &[Point2D<F>],
712 offset: F,
713 o: &mut Options,
714) -> Vec<Op<F>> {
715 let mut ps: Vec<Point2D<F>> = vec![
716 Point2D::new(
717 points[0].x + _offset_opt(offset, o, None),
718 points[0].y + _offset_opt(offset, o, None),
719 ),
720 Point2D::new(
721 points[0].x + _offset_opt(offset, o, None),
722 points[0].y + _offset_opt(offset, o, None),
723 ),
724 ];
725 let mut i = 1;
726 while i < points.len() {
727 ps.push(Point2D::new(
728 points[i].x + _offset_opt(offset, o, None),
729 points[i].y + _offset_opt(offset, o, None),
730 ));
731 if i == (points.len() - 1) {
732 ps.push(Point2D::new(
733 points[i].x + _offset_opt(offset, o, None),
734 points[i].y + _offset_opt(offset, o, None),
735 ));
736 }
737 i += 1;
738 }
739 _curve(&ps, None, o)
740}
741
742#[allow(clippy::too_many_arguments)]
743pub(crate) fn _compute_ellipse_points<F: Float + Trig + FromPrimitive>(
744 increment: F,
745 cx: F,
746 cy: F,
747 rx: F,
748 ry: F,
749 offset: F,
750 overlap: F,
751 o: &mut Options,
752) -> Vec<Vec<Point2D<F>>> {
753 let core_only = o.roughness.unwrap_or(0.0) == 0.0;
754 let mut core_points: Vec<Point2D<F>> = Vec::new();
755 let mut all_points: Vec<Point2D<F>> = Vec::new();
756
757 if core_only {
758 let increment_inner = increment / _c(4.0);
759 all_points.push(Point2D::new(
760 cx + rx * Float::cos(-increment_inner),
761 cy + ry * Float::sin(-increment_inner),
762 ));
763
764 let mut angle = _c(0.0);
765 while angle <= _cc::<F>(std::f64::consts::PI * 2.0) {
766 let p = Point2D::new(cx + rx * Float::cos(angle), cy + ry * Float::sin(angle));
767 core_points.push(p);
768 all_points.push(p);
769 angle = angle + increment_inner;
770 }
771 all_points.push(Point2D::new(
772 cx + rx * Float::cos(_c(0.0)),
773 cy + ry * Float::sin(_c(0.0)),
774 ));
775 all_points.push(Point2D::new(
776 cx + rx * Float::cos(increment_inner),
777 cy + ry * Float::sin(increment_inner),
778 ));
779 } else {
780 let rad_offset: F = _offset_opt::<F>(_c(0.5), o, None) - (_c::<F>(f32::PI()) / _c(2.0));
781 all_points.push(Point2D::new(
782 _offset_opt(offset, o, None)
783 + cx
784 + _c::<F>(0.9) * rx * Float::cos(rad_offset - increment),
785 _offset_opt(offset, o, None)
786 + cy
787 + _c::<F>(0.9) * ry * Float::sin(rad_offset - increment),
788 ));
789 let end_angle = _cc::<F>(std::f64::consts::PI * 2.0) + rad_offset - _c(0.01);
790 let mut angle = rad_offset;
791 while angle < end_angle {
792 let p = Point2D::new(
793 _offset_opt(offset, o, None) + cx + rx * Float::cos(angle),
794 _offset_opt(offset, o, None) + cy + ry * Float::sin(angle),
795 );
796 core_points.push(p);
797 all_points.push(p);
798 angle = angle + increment;
799 }
800
801 all_points.push(Point2D::new(
802 _offset_opt(offset, o, None)
803 + cx
804 + rx * Float::cos(
805 rad_offset + _cc::<F>(std::f64::consts::PI * 2.0) + overlap * _c(0.5),
806 ),
807 _offset_opt(offset, o, None)
808 + cy
809 + ry * Float::sin(
810 rad_offset + _cc::<F>(std::f64::consts::PI * 2.0) + overlap * _c(0.5),
811 ),
812 ));
813 all_points.push(Point2D::new(
814 _offset_opt(offset, o, None)
815 + cx
816 + _c::<F>(0.98) * rx * Float::cos(rad_offset + overlap),
817 _offset_opt(offset, o, None)
818 + cy
819 + _c::<F>(0.98) * ry * Float::sin(rad_offset + overlap),
820 ));
821 all_points.push(Point2D::new(
822 _offset_opt(offset, o, None)
823 + cx
824 + _c::<F>(0.9) * rx * Float::cos(rad_offset + overlap * _c(0.5)),
825 _offset_opt(offset, o, None)
826 + cy
827 + _c::<F>(0.9) * ry * Float::sin(rad_offset + overlap * _c(0.5)),
828 ));
829 }
830 vec![all_points, core_points]
831}
832
833#[allow(clippy::too_many_arguments)]
834fn _arc<F: Float + Trig + FromPrimitive>(
835 increment: F,
836 cx: F,
837 cy: F,
838 rx: F,
839 ry: F,
840 strt: F,
841 stp: F,
842 offset: F,
843 o: &mut Options,
844) -> Vec<Op<F>> {
845 let rad_offset = strt + _offset_opt(_c(0.1), o, None);
846 let mut points: Vec<Point2D<F>> = vec![Point2D::new(
847 _offset_opt(offset, o, None) + cx + _c::<F>(0.9) * rx * Float::cos(rad_offset - increment),
848 _offset_opt(offset, o, None) + cy + _c::<F>(0.9) * ry * Float::sin(rad_offset - increment),
849 )];
850 let mut angle = rad_offset;
851 while angle <= stp {
852 points.push(Point2D::new(
853 _offset_opt(offset, o, None) + cx + rx * Float::cos(angle),
854 _offset_opt(offset, o, None) + cy + ry * Float::sin(angle),
855 ));
856 angle = angle + increment;
857 }
858 points.push(Point2D::new(
859 cx + rx * Float::cos(stp),
860 cy + ry * Float::sin(stp),
861 ));
862 points.push(Point2D::new(
863 cx + rx * Float::cos(stp),
864 cy + ry * Float::sin(stp),
865 ));
866 _curve(&points, None, o)
867}
868
869fn _bezier_quadratic_to<F: Float + Trig + FromPrimitive>(
870 x1: F,
871 y1: F,
872 x: F,
873 y: F,
874 current: &Point2D<F>,
875 o: &mut Options,
876) -> Vec<Op<F>> {
877 let cubic = convert_bezier_quadratic_to_cubic(BezierQuadratic {
880 start: *current,
881 cp: Point2D::new(x1, y1),
882 end: Point2D::new(x, y),
883 });
884
885 _bezier_to(
886 cubic.cp1.x,
887 cubic.cp1.y,
888 cubic.cp2.x,
889 cubic.cp2.y,
890 cubic.end.x,
891 cubic.end.y,
892 &cubic.start,
893 o,
894 )
895}
896
897#[allow(clippy::too_many_arguments)]
898fn _bezier_to<F: Float + Trig + FromPrimitive>(
899 x1: F,
900 y1: F,
901 x2: F,
902 y2: F,
903 x: F,
904 y: F,
905 current: &Point2D<F>,
906 o: &mut Options,
907) -> Vec<Op<F>> {
908 let mut ops: Vec<Op<F>> = Vec::new();
909 let ros = [
910 _c(o.max_randomness_offset.unwrap_or(2.0)),
911 _c(o.max_randomness_offset.unwrap_or(2.0) + 0.3),
912 ];
913 let mut f: Point2D<F>;
914 let iterations = if o.disable_multi_stroke.unwrap_or(false) {
915 1
916 } else {
917 2
918 };
919 let preserve_vertices = o.preserve_vertices.unwrap_or(false);
920 let mut i = 0;
921 while i < iterations {
922 if i == 0 {
923 ops.push(Op {
924 op: OpType::Move,
925 data: vec![current.x, current.y],
926 });
927 } else {
928 ops.push(Op {
929 op: OpType::Move,
930 data: vec![
931 current.x
932 + (if preserve_vertices {
933 _c(0.0)
934 } else {
935 _offset_opt(ros[0], o, None)
936 }),
937 current.y
938 + (if preserve_vertices {
939 _c(0.0)
940 } else {
941 _offset_opt(ros[0], o, None)
942 }),
943 ],
944 });
945 }
946 f = if preserve_vertices {
947 Point2D::new(x, y)
948 } else {
949 Point2D::new(
950 x + _offset_opt(ros[i], o, None),
951 y + _offset_opt(ros[i], o, None),
952 )
953 };
954 ops.push(Op {
955 op: OpType::BCurveTo,
956 data: vec![
957 x1 + _offset_opt(ros[i], o, None),
958 y1 + _offset_opt(ros[i], o, None),
959 x2 + _offset_opt(ros[i], o, None),
960 y2 + _offset_opt(ros[i], o, None),
961 f.x,
962 f.y,
963 ],
964 });
965 i += 1;
966 }
967 ops
968}
969
970pub fn pattern_fill_polygons<F, P>(polygon_list: P, o: &mut Options) -> OpSet<F>
971where
972 F: Float + Trig + FromPrimitive,
973 P: BorrowMut<Vec<Vec<Point2D<F>>>>,
974{
975 let filler = if let Some(fill_style) = o.fill_style.as_ref() {
976 match fill_style {
977 FillStyle::Hachure => get_filler(ScanLineHachure),
978 FillStyle::Dashed => get_filler(DashedFiller),
979 FillStyle::Dots => get_filler(DotFiller),
980 FillStyle::CrossHatch => get_filler(HatchFiller),
981 FillStyle::ZigZag => get_filler(ZigZagFiller),
982 FillStyle::ZigZagLine => get_filler(ZigZagLineFiller),
983 _ => get_filler(ScanLineHachure),
984 }
985 } else {
986 get_filler(ScanLineHachure)
987 };
988 filler.fill_polygons(polygon_list, o)
989}
990
991pub fn pattern_fill_arc<F>(
992 x: F,
993 y: F,
994 width: F,
995 height: F,
996 start: F,
997 stop: F,
998 o: &mut Options,
999) -> OpSet<F>
1000where
1001 F: Float + FromPrimitive + Trig,
1002{
1003 let cx = x;
1004 let cy = y;
1005 let mut rx = F::abs(width / _c(2.0));
1006 let mut ry = F::abs(height / _c(2.0));
1007
1008 rx = rx + _offset_opt(rx * _c(0.01), o, None);
1009 ry = ry + _offset_opt(ry * _c(0.01), o, None);
1010
1011 let mut strt = start;
1012 let mut stp = stop;
1013 let two_pi = _c::<F>(f32::PI()) * _c::<F>(2.0);
1014
1015 while strt < _c(0.0) {
1016 strt = strt + two_pi;
1017 stp = stp + two_pi;
1018 }
1019
1020 if (stp - strt) > two_pi {
1021 strt = F::zero();
1022 stp = two_pi;
1023 }
1024
1025 let increment = (stp / strt) / o.curve_step_count.map(|a| _c(a)).unwrap_or_else(|| _c(1.0));
1026 let mut points: Vec<Point2D<F>> = vec![];
1027
1028 let mut angle = strt;
1029
1030 while angle <= stp {
1031 points.push(point2(
1032 cx + rx * Float::cos(angle),
1033 cy + ry * Float::sin(angle),
1034 ));
1035 angle = angle + increment;
1036 }
1037
1038 points.push(point2(cx + rx * Float::cos(stp), cy + ry * Float::sin(stp)));
1039 points.push(point2(cx, cy));
1040 pattern_fill_polygons(vec![points], o)
1041}
1042
1043pub fn svg_path<F>(path: String, o: &mut Options) -> OpSet<F>
1044where
1045 F: Float + FromPrimitive + Trig,
1046{
1047 let ops = vec![];
1048 let first = Point2D::new(_c::<F>(0.0), _c::<F>(0.0));
1049 let current = Point2D::new(_c::<F>(0.0), _c::<F>(0.0));
1050 let path_parser = PathParser::from(path.as_ref());
1051 let path_segments: Vec<PathSegment> = path_parser.flatten().collect();
1052 let normalized_segments = normalize(absolutize(path_segments.iter()));
1053
1054 opset_from_path(o, ops, first, current, normalized_segments)
1055}
1056
1057pub fn svg_segments<F>(path_segments: Vec<PathSegment>, o: &mut Options) -> OpSet<F>
1058where
1059 F: Float + FromPrimitive + Trig,
1060{
1061 let ops = vec![];
1062 let first = Point2D::new(_c::<F>(0.0), _c::<F>(0.0));
1063 let current = Point2D::new(_c::<F>(0.0), _c::<F>(0.0));
1064 let normalized_segments = normalize(absolutize(path_segments.iter()));
1065
1066 opset_from_path(o, ops, first, current, normalized_segments)
1067}
1068
1069pub fn svg_normalized_segments<F>(normalized_segments: &[PathSegment], o: &mut Options) -> OpSet<F>
1070where
1071 F: Float + FromPrimitive + Trig,
1072{
1073 let ops = vec![];
1074 let first = Point2D::new(_c::<F>(0.0), _c::<F>(0.0));
1075 let current = Point2D::new(_c::<F>(0.0), _c::<F>(0.0));
1076
1077 opset_from_path(o, ops, first, current, normalized_segments.iter().cloned())
1078}
1079
1080fn opset_from_path<F>(
1081 o: &mut Options,
1082 mut ops: Vec<Op<F>>,
1083 mut first: euclid::Point2D<F, euclid::UnknownUnit>,
1084 mut current: euclid::Point2D<F, euclid::UnknownUnit>,
1085 normalized_segments: impl Iterator<Item = PathSegment>,
1086) -> OpSet<F>
1087where
1088 F: Float + FromPrimitive + Trig,
1089{
1090 for segment in normalized_segments {
1091 match segment {
1092 PathSegment::MoveTo { abs: true, x, y } => {
1093 current = Point2D::new(_cc::<F>(x), _cc::<F>(y));
1097 first = Point2D::new(_cc::<F>(x), _cc::<F>(y));
1098 }
1099 PathSegment::LineTo { abs: true, x, y } => {
1100 ops.extend(_double_line(
1101 current.x,
1102 current.y,
1103 _cc::<F>(x),
1104 _cc::<F>(y),
1105 o,
1106 false,
1107 ));
1108 current = Point2D::new(_cc::<F>(x), _cc::<F>(y));
1109 }
1110 PathSegment::CurveTo {
1111 abs: true,
1112 x1,
1113 y1,
1114 x2,
1115 y2,
1116 x,
1117 y,
1118 } => {
1119 ops.extend(_bezier_to(
1120 _cc::<F>(x1),
1121 _cc::<F>(y1),
1122 _cc::<F>(x2),
1123 _cc::<F>(y2),
1124 _cc::<F>(x),
1125 _cc::<F>(y),
1126 ¤t,
1127 o,
1128 ));
1129 current = Point2D::new(_cc::<F>(x), _cc::<F>(y));
1130 }
1131 PathSegment::ClosePath { abs: true } => {
1132 ops.extend(_double_line(
1133 current.x, current.y, first.x, first.y, o, false,
1134 ));
1135 current = Point2D::new(first.x, first.y);
1136 }
1137 _ => panic!("Unexpected segment type"),
1138 }
1139 }
1140 OpSet {
1141 op_set_type: OpSetType::Path,
1142 ops,
1143 size: None,
1144 path: None,
1145 }
1146}
1147
1148#[cfg(test)]
1149mod test {
1150 use euclid::point2;
1151 use plotlib::page::Page;
1152 use plotlib::repr::Plot;
1153 use plotlib::style::{PointMarker, PointStyle};
1154 use plotlib::view::ContinuousView;
1155
1156 use super::{EllipseParams, _compute_ellipse_points, _curve};
1157 use crate::core::{Op, OpSet, OpSetType, OpType, Options, OptionsBuilder};
1158
1159 fn get_default_options() -> Options {
1160 OptionsBuilder::default()
1161 .seed(345_u64)
1162 .build()
1163 .expect("failed to build default options")
1164 }
1165
1166 #[test]
1167 fn linear_path() {
1168 let result = super::linear_path(
1169 &[point2(0.0f32, 0.0), point2(0.0, 0.1), point2(1.0, 1.0)],
1170 false,
1171 &mut get_default_options(),
1172 );
1173 assert_eq!(result.op_set_type, OpSetType::Path);
1174 assert_eq!(
1175 result,
1176 OpSet {
1177 op_set_type: OpSetType::Path,
1178 ops: vec![
1179 Op {
1180 op: OpType::Move,
1181 data: vec![-0.0012205532, 0.0027011754]
1182 },
1183 Op {
1184 op: OpType::BCurveTo,
1185 data: vec![
1186 0.007769434,
1187 0.026625521,
1188 -0.006868569,
1189 0.035775613,
1190 -0.008950782,
1191 0.09677874
1192 ]
1193 },
1194 Op {
1195 op: OpType::Move,
1196 data: vec![0.0010519032, -0.0035673995]
1197 },
1198 Op {
1199 op: OpType::BCurveTo,
1200 data: vec![
1201 -0.0034613428,
1202 0.040271826,
1203 -0.0024902155,
1204 0.074226834,
1205 -0.0011456441,
1206 0.09860738
1207 ]
1208 },
1209 Op {
1210 op: OpType::Move,
1211 data: vec![-0.123573944, 0.12996572]
1212 },
1213 Op {
1214 op: OpType::BCurveTo,
1215 data: vec![
1216 0.19195092, 0.3300887, 0.6037904, 0.64465916, 0.98244137, 1.0048801
1217 ]
1218 },
1219 Op {
1220 op: OpType::Move,
1221 data: vec![0.047007628, 0.116847344]
1222 },
1223 Op {
1224 op: OpType::BCurveTo,
1225 data: vec![
1226 0.37384683, 0.40432873, 0.84561193, 0.77220255, 1.0250582, 0.96798605
1227 ]
1228 }
1229 ],
1230 size: None,
1231 path: None
1232 }
1233 );
1234 }
1235
1236 #[test]
1237 #[ignore = "failing due to randomness"]
1238 fn ellipse_with_params() {
1239 let expected_estimated_points = vec![
1240 point2(0.6818724507954145, -0.24215675845215262),
1241 point2(1.3682071413206485, 0.7930465114686116),
1242 point2(1.9097816708676238, 0.7671100939304721),
1243 point2(0.8360414855920169, 1.5122198080140175),
1244 point2(0.531355187897985, 0.4738367335276372),
1245 point2(1.111026909625053, 1.3449538537307408),
1246 point2(1.1040092949849214, 1.801902725957649),
1247 point2(0.4258957275631308, 1.2442749714336163),
1248 point2(0.5661545950654607, 0.6328000056262721),
1249 ];
1250
1251 let result = super::ellipse_with_params(
1252 0.1,
1253 0.1,
1254 &mut get_default_options(),
1255 &EllipseParams {
1256 rx: 0.486848765998615,
1257 ry: 0.4755334706420514,
1258 increment: 0.6981317007977318,
1259 },
1260 );
1261
1262 assert_eq!(expected_estimated_points, result.estimated_points);
1263 }
1264
1265 #[test]
1266 #[ignore = "failing due to randommness"]
1267 fn compute_ellipse_points() {
1268 let expected = vec![
1269 vec![
1270 point2(1.0710641633603797, 0.6343339196221436),
1271 point2(0.9888360341310736, 0.539884571860436),
1272 point2(1.0423582717058324, 0.48447611636004245),
1273 point2(1.1323647757131408, 0.48734422393942145),
1274 point2(1.097114022520837, 0.5024772415343248),
1275 point2(1.1983573886194598, 0.6344444071433158),
1276 point2(1.2951674832143851, 0.641832264291391),
1277 point2(1.3536023670520665, 0.6251662974163592),
1278 point2(1.2548224121208582, 0.6352429012560402),
1279 point2(1.3489034470987185, 0.6012739292011288),
1280 point2(1.4213037554602923, 0.6261652440563298),
1281 point2(1.4743145534688815, 0.7882156278963534),
1282 point2(1.4700412486188879, 0.8875515790754055),
1283 point2(1.4460278644836544, 0.8456185823210882),
1284 point2(1.4868741833172523, 0.9079833740096543),
1285 point2(1.4920518492387598, 0.9095078637143422),
1286 point2(1.5595453417691338, 0.9901532598343071),
1287 point2(1.5936742539308373, 1.0213282325299586),
1288 point2(1.58058656655406, 1.17305000017827),
1289 point2(1.4480254616492774, 1.0928279018210438),
1290 point2(1.4539640114348549, 1.144388265648967),
1291 point2(1.3648317202407696, 1.2212937832283584),
1292 point2(1.4733929772805416, 1.2083669884937012),
1293 point2(1.3608398097214693, 1.3207579529041924),
1294 point2(1.2912648851735424, 1.4205716705529399),
1295 point2(1.2046625302840053, 1.3826569437709715),
1296 point2(1.2570442078920254, 1.3410441079145428),
1297 point2(1.1830529369693072, 1.3820810903226886),
1298 point2(1.167072937591176, 1.4466053111301487),
1299 point2(1.0852661499741054, 1.55951044347548),
1300 point2(1.0494466853794846, 1.5479828315241733),
1301 point2(1.0033271419673007, 1.468194659125039),
1302 point2(0.9484890618160645, 1.4530640355956308),
1303 point2(0.9973592789218273, 1.45324593604413),
1304 point2(0.97187677594751, 1.5815631933148016),
1305 point2(0.8144204755613362, 1.3782837410393232),
1306 point2(0.7950961543969257, 1.444409277208105),
1307 point2(0.8249520184490917, 1.3374139622566115),
1308 point2(0.6758412677442227, 1.334436082917169),
1309 point2(0.64368867956175, 1.3618188433767497),
1310 point2(0.5445160170270017, 1.2507819758003385),
1311 point2(0.5261266184295889, 1.290024044761643),
1312 point2(0.502690056479149, 1.236879918084129),
1313 point2(0.5280669233268998, 1.1091277406960698),
1314 point2(0.4827538350322879, 1.1436496314081661),
1315 point2(0.5883382268183734, 1.175168641400803),
1316 point2(0.44736030622371087, 1.018503357084688),
1317 point2(0.5448981202541112, 0.9143727174667883),
1318 point2(0.4317760080261111, 1.051488996664834),
1319 point2(0.5085207904485967, 0.9331170328373988),
1320 point2(0.6001478439304737, 0.8979301783503268),
1321 point2(0.4373488434812126, 0.723669324069054),
1322 point2(0.48379460068391017, 0.6896668054813503),
1323 point2(0.5802149727260961, 0.6326489019654757),
1324 point2(0.5318481024591232, 0.6672519961193484),
1325 point2(0.6267954168946062, 0.6264453502200538),
1326 point2(0.7244414827901777, 0.6742999823788176),
1327 point2(0.7409838872007461, 0.5515230198623486),
1328 point2(0.7461775341290393, 0.6232380086449496),
1329 point2(0.9055915299113261, 0.5326254191949538),
1330 point2(0.9510466807539406, 0.49366667559390653),
1331 point2(0.8116223593436764, 0.4695463357704083),
1332 point2(0.8528118040757474, 0.4635000250267341),
1333 point2(0.9141212396595003, 0.40460067972212826),
1334 point2(1.003267583900141, 0.5351889587671019),
1335 point2(1.0320189898300267, 0.6060923051759772),
1336 point2(1.0784925820514744, 0.5016457530039365),
1337 ],
1338 vec![
1339 point2(0.9888360341310736, 0.539884571860436),
1340 point2(1.0423582717058324, 0.48447611636004245),
1341 point2(1.1323647757131408, 0.48734422393942145),
1342 point2(1.097114022520837, 0.5024772415343248),
1343 point2(1.1983573886194598, 0.6344444071433158),
1344 point2(1.2951674832143851, 0.641832264291391),
1345 point2(1.3536023670520665, 0.6251662974163592),
1346 point2(1.2548224121208582, 0.6352429012560402),
1347 point2(1.3489034470987185, 0.6012739292011288),
1348 point2(1.4213037554602923, 0.6261652440563298),
1349 point2(1.4743145534688815, 0.7882156278963534),
1350 point2(1.4700412486188879, 0.8875515790754055),
1351 point2(1.4460278644836544, 0.8456185823210882),
1352 point2(1.4868741833172523, 0.9079833740096543),
1353 point2(1.4920518492387598, 0.9095078637143422),
1354 point2(1.5595453417691338, 0.9901532598343071),
1355 point2(1.5936742539308373, 1.0213282325299586),
1356 point2(1.58058656655406, 1.17305000017827),
1357 point2(1.4480254616492774, 1.0928279018210438),
1358 point2(1.4539640114348549, 1.144388265648967),
1359 point2(1.3648317202407696, 1.2212937832283584),
1360 point2(1.4733929772805416, 1.2083669884937012),
1361 point2(1.3608398097214693, 1.3207579529041924),
1362 point2(1.2912648851735424, 1.4205716705529399),
1363 point2(1.2046625302840053, 1.3826569437709715),
1364 point2(1.2570442078920254, 1.3410441079145428),
1365 point2(1.1830529369693072, 1.3820810903226886),
1366 point2(1.167072937591176, 1.4466053111301487),
1367 point2(1.0852661499741054, 1.55951044347548),
1368 point2(1.0494466853794846, 1.5479828315241733),
1369 point2(1.0033271419673007, 1.468194659125039),
1370 point2(0.9484890618160645, 1.4530640355956308),
1371 point2(0.9973592789218273, 1.45324593604413),
1372 point2(0.97187677594751, 1.5815631933148016),
1373 point2(0.8144204755613362, 1.3782837410393232),
1374 point2(0.7950961543969257, 1.444409277208105),
1375 point2(0.8249520184490917, 1.3374139622566115),
1376 point2(0.6758412677442227, 1.334436082917169),
1377 point2(0.64368867956175, 1.3618188433767497),
1378 point2(0.5445160170270017, 1.2507819758003385),
1379 point2(0.5261266184295889, 1.290024044761643),
1380 point2(0.502690056479149, 1.236879918084129),
1381 point2(0.5280669233268998, 1.1091277406960698),
1382 point2(0.4827538350322879, 1.1436496314081661),
1383 point2(0.5883382268183734, 1.175168641400803),
1384 point2(0.44736030622371087, 1.018503357084688),
1385 point2(0.5448981202541112, 0.9143727174667883),
1386 point2(0.4317760080261111, 1.051488996664834),
1387 point2(0.5085207904485967, 0.9331170328373988),
1388 point2(0.6001478439304737, 0.8979301783503268),
1389 point2(0.4373488434812126, 0.723669324069054),
1390 point2(0.48379460068391017, 0.6896668054813503),
1391 point2(0.5802149727260961, 0.6326489019654757),
1392 point2(0.5318481024591232, 0.6672519961193484),
1393 point2(0.6267954168946062, 0.6264453502200538),
1394 point2(0.7244414827901777, 0.6742999823788176),
1395 point2(0.7409838872007461, 0.5515230198623486),
1396 point2(0.7461775341290393, 0.6232380086449496),
1397 point2(0.9055915299113261, 0.5326254191949538),
1398 point2(0.9510466807539406, 0.49366667559390653),
1399 point2(0.8116223593436764, 0.4695463357704083),
1400 point2(0.8528118040757474, 0.4635000250267341),
1401 point2(0.9141212396595003, 0.40460067972212826),
1402 ],
1403 ];
1404 let result = _compute_ellipse_points(
1405 0.1,
1406 1.0,
1407 1.0,
1408 0.5,
1409 0.5,
1410 0.1,
1411 0.1,
1412 &mut get_default_options(),
1413 );
1414 assert_eq!(expected, result);
1415 }
1416
1417 #[test]
1418 fn curve() {
1419 let result = _curve(
1420 &[
1421 point2(0.0, 0.0),
1422 point2(1.0, 1.0),
1423 point2(2.0, 0.0),
1424 point2(-1.0, -1.0),
1425 ],
1426 None,
1427 &mut get_default_options(),
1428 );
1429 assert_eq!(result[0].op, OpType::Move);
1430 assert_eq!(result[0].data, vec![1.0, 1.0]);
1431
1432 assert_eq!(result[1].op, OpType::BCurveTo);
1433 assert_eq!(
1434 result[1].data,
1435 vec![
1436 1.3333333333333333,
1437 1.0,
1438 2.3333333333333335,
1439 0.3333333333333333,
1440 2.0,
1441 0.0
1442 ]
1443 );
1444 }
1445
1446 #[test]
1447 #[ignore = "utility to see results quickly"]
1448 fn plot_points() {
1449 let data = vec![
1450 (1.0559477995009565, 0.6021961777759488),
1451 (0.9925497905143945, 0.4436148523483838),
1452 (1.1783256257253407, 0.5143362336768694),
1453 (1.208490397628349, 0.5745944499427847),
1454 (1.2711903714514319, 0.5701901786816395),
1455 (1.1974231651740772, 0.5696505646227608),
1456 (1.266815053466919, 0.5450282815494873),
1457 (1.4283771417586615, 0.6382465720026044),
1458 (1.4154905334465357, 0.7109067381405771),
1459 (1.4333920313802389, 0.8059906260263232),
1460 (1.5094667274959321, 0.7265860541520335),
1461 (1.400692088449572, 0.7835751135014755),
1462 (1.3881602391283323, 0.7755163633824922),
1463 (1.570385206729917, 0.8510533444105508),
1464 (1.5493770357747365, 1.0250335113190738),
1465 (1.510651107806883, 1.0837232261571872),
1466 (1.4775536326276126, 1.016950646519272),
1467 (1.5472535904647446, 1.1025497737242922),
1468 (1.399983805334271, 1.1307557954537981),
1469 (1.3612945701680008, 1.2623693228823314),
1470 (1.3404043926945617, 1.1635099938248215),
1471 (1.361444072889848, 1.3669009350459007),
1472 (1.3856729774849246, 1.3334358041468137),
1473 (1.4238836270255022, 1.3470401143733706),
1474 (1.3117443672910145, 1.3007103720810664),
1475 (1.2951811386649095, 1.413842218695549),
1476 (1.1332155971266886, 1.3564586452873857),
1477 (1.2083097488252306, 1.5340221616808116),
1478 (1.0881580052193756, 1.4263268611969555),
1479 (1.035233163501938, 1.580914582858814),
1480 (1.0786021335616458, 1.4201023026826818),
1481 (1.0116161297926778, 1.4140491306394047),
1482 (0.8765318057053879, 1.4359492914939993),
1483 (0.9399561543054671, 1.5660782762309609),
1484 (0.8375472416599303, 1.525744002191411),
1485 (0.8138957025941598, 1.499526147458222),
1486 (0.6692225625276738, 1.4230050653539723),
1487 (0.6445821561240486, 1.3465046022062919),
1488 (0.7468382746164379, 1.3061904618040936),
1489 (0.5422183692127689, 1.4253173885030197),
1490 (0.6535141358551948, 1.3706502636385975),
1491 (0.5394132023778615, 1.3237938582067676),
1492 (0.5609544663499307, 1.1661260280518218),
1493 (0.5071032508159938, 1.1407886339852356),
1494 (0.5720800099397795, 1.0384692384541154),
1495 (0.5507046722809901, 0.9777594942139937),
1496 (0.5080449523990171, 0.9942577887966262),
1497 (0.5885628279692711, 0.9426486291554865),
1498 (0.4977542840222783, 0.9482898228608775),
1499 (0.5144216046077197, 0.902002627557736),
1500 (0.6326671537040239, 0.8415207219207479),
1501 (0.5737651049885282, 0.7955447719947131),
1502 (0.5017586112800467, 0.8016467388837818),
1503 (0.6016973900071679, 0.6327656807099842),
1504 (0.6618602604154518, 0.5506023666758844),
1505 (0.6324945491128473, 0.5460241979809777),
1506 (0.8125244142495132, 0.6530224612358858),
1507 (0.7983569626413481, 0.6411210503669331),
1508 (0.7582913526129964, 0.6190096172157633),
1509 (0.7799420253058733, 0.5328746976861746),
1510 (0.9418801906688571, 0.4601256410807209),
1511 (1.0420025580486114, 0.5992707449732568),
1512 (0.9427185990787657, 0.5878683460934829),
1513 (1.0816303653623174, 0.5537733879903082),
1514 (1.159556236737222, 0.501976527225239),
1515 (1.0528934849778917, 0.6258578810541852),
1516 (1.1241549892963243, 0.6265235243673886),
1517 ];
1518 let data2 = vec![
1519 (0.9925497905143945, 0.4436148523483838),
1520 (1.1783256257253407, 0.5143362336768694),
1521 (1.208490397628349, 0.5745944499427847),
1522 (1.2711903714514319, 0.5701901786816395),
1523 (1.1974231651740772, 0.5696505646227608),
1524 (1.266815053466919, 0.5450282815494873),
1525 (1.4283771417586615, 0.6382465720026044),
1526 (1.4154905334465357, 0.7109067381405771),
1527 (1.4333920313802389, 0.8059906260263232),
1528 (1.5094667274959321, 0.7265860541520335),
1529 (1.400692088449572, 0.7835751135014755),
1530 (1.3881602391283323, 0.7755163633824922),
1531 (1.570385206729917, 0.8510533444105508),
1532 (1.5493770357747365, 1.0250335113190738),
1533 (1.510651107806883, 1.0837232261571872),
1534 (1.4775536326276126, 1.016950646519272),
1535 (1.5472535904647446, 1.1025497737242922),
1536 (1.399983805334271, 1.1307557954537981),
1537 (1.3612945701680008, 1.2623693228823314),
1538 (1.3404043926945617, 1.1635099938248215),
1539 (1.361444072889848, 1.3669009350459007),
1540 (1.3856729774849246, 1.3334358041468137),
1541 (1.4238836270255022, 1.3470401143733706),
1542 (1.3117443672910145, 1.3007103720810664),
1543 (1.2951811386649095, 1.413842218695549),
1544 (1.1332155971266886, 1.3564586452873857),
1545 (1.2083097488252306, 1.5340221616808116),
1546 (1.0881580052193756, 1.4263268611969555),
1547 (1.035233163501938, 1.580914582858814),
1548 (1.0786021335616458, 1.4201023026826818),
1549 (1.0116161297926778, 1.4140491306394047),
1550 (0.8765318057053879, 1.4359492914939993),
1551 (0.9399561543054671, 1.5660782762309609),
1552 (0.8375472416599303, 1.525744002191411),
1553 (0.8138957025941598, 1.499526147458222),
1554 (0.6692225625276738, 1.4230050653539723),
1555 (0.6445821561240486, 1.3465046022062919),
1556 (0.7468382746164379, 1.3061904618040936),
1557 (0.5422183692127689, 1.4253173885030197),
1558 (0.6535141358551948, 1.3706502636385975),
1559 (0.5394132023778615, 1.3237938582067676),
1560 (0.5609544663499307, 1.1661260280518218),
1561 (0.5071032508159938, 1.1407886339852356),
1562 (0.5720800099397795, 1.0384692384541154),
1563 (0.5507046722809901, 0.9777594942139937),
1564 (0.5080449523990171, 0.9942577887966262),
1565 (0.5885628279692711, 0.9426486291554865),
1566 (0.4977542840222783, 0.9482898228608775),
1567 (0.5144216046077197, 0.902002627557736),
1568 (0.6326671537040239, 0.8415207219207479),
1569 (0.5737651049885282, 0.7955447719947131),
1570 (0.5017586112800467, 0.8016467388837818),
1571 (0.6016973900071679, 0.6327656807099842),
1572 (0.6618602604154518, 0.5506023666758844),
1573 (0.6324945491128473, 0.5460241979809777),
1574 (0.8125244142495132, 0.6530224612358858),
1575 (0.7983569626413481, 0.6411210503669331),
1576 (0.7582913526129964, 0.6190096172157633),
1577 (0.7799420253058733, 0.5328746976861746),
1578 (0.9418801906688571, 0.4601256410807209),
1579 (1.0420025580486114, 0.5992707449732568),
1580 (0.9427185990787657, 0.5878683460934829),
1581 (1.0816303653623174, 0.5537733879903082),
1582 ];
1583
1584 let s1: Plot = Plot::new(data).point_style(
1586 PointStyle::new()
1587 .marker(PointMarker::Square) .colour("#DD3355")
1589 .size(1.0),
1590 ); let s2: Plot = Plot::new(data2).point_style(
1594 PointStyle::new() .colour("#35C788")
1596 .size(1.0),
1597 ); let v = ContinuousView::new()
1601 .add(s1)
1602 .add(s2)
1603 .x_range(-5., 10.)
1604 .y_range(-2., 6.)
1605 .x_label("Some varying variable")
1606 .y_label("The response of something");
1607
1608 Page::single(&v).save("scatter.svg").unwrap();
1610 }
1611}