1/*!
2 * \file partitioned_tessellated_path.cpp
3 * \brief file partitioned_tessellated_path.cpp
4 *
5 * Copyright 2019 by Intel.
6 *
7 * Contact: kevin.rogovin@gmail.com
8 *
9 * This Source Code Form is subject to the
10 * terms of the Mozilla Public License, v. 2.0.
11 * If a copy of the MPL was not distributed with
12 * this file, You can obtain one at
13 * http://mozilla.org/MPL/2.0/.
14 *
15 * \author Kevin Rogovin <kevin.rogovin@gmail.com>
16 *
17 */
18
19#include <vector>
20#include <complex>
21#include <algorithm>
22
23#include <fastuidraw/tessellated_path.hpp>
24#include <fastuidraw/path.hpp>
25#include <fastuidraw/partitioned_tessellated_path.hpp>
26
27#include <private/util_private.hpp>
28#include <private/util_private_ostream.hpp>
29#include <private/bounding_box.hpp>
30#include <private/path_util_private.hpp>
31#include <private/clip.hpp>
32
33namespace
34{
35 enum
36 {
37 splitting_threshhold = 50,
38 max_recursion_depth = 10
39 };
40
41 class SubsetBuilder:fastuidraw::noncopyable
42 {
43 public:
44 typedef fastuidraw::TessellatedPath::segment segment;
45
46 class PerChain
47 {
48 public:
49 explicit
50 PerChain(unsigned int start):
51 m_range(start, start),
52 m_has_before_first(false)
53 {}
54
55 PerChain(unsigned int start,
56 const segment &before_first):
57 m_range(start, start),
58 m_before_first(before_first),
59 m_has_before_first(true)
60 {}
61
62 fastuidraw::range_type<unsigned int> m_range;
63 segment m_before_first;
64 bool m_has_before_first;
65 };
66
67 SubsetBuilder(void):
68 m_has_arcs(false)
69 {}
70
71 const segment*
72 add_segment(const segment &S)
73 {
74 FASTUIDRAWassert(!m_chains.empty());
75 m_segments.push_back(S);
76 m_has_arcs = m_has_arcs || (S.m_type == fastuidraw::TessellatedPath::arc_segment);
77 m_bbox.union_point(S.m_start_pt);
78 m_bbox.union_point(S.m_end_pt);
79 ++m_chains.back().m_range.m_end;
80
81 return &m_segments.back();
82 }
83
84 void
85 start_chain(const segment *before_chain)
86 {
87 if (before_chain)
88 {
89 m_chains.push_back(PerChain(m_segments.size(), *before_chain));
90 }
91 else
92 {
93 m_chains.push_back(PerChain(m_segments.size()));
94 }
95 }
96
97 void
98 process_chain(const fastuidraw::TessellatedPath::segment_chain &chain)
99 {
100 start_chain(chain.m_prev_to_start);
101 for (const auto &S : chain.m_segments)
102 {
103 add_segment(S);
104 }
105 }
106
107 void
108 process_chains(fastuidraw::c_array<const fastuidraw::TessellatedPath::segment_chain> chains)
109 {
110 for (const auto &a : chains)
111 {
112 process_chain(a);
113 }
114 }
115
116 void
117 process_caps(fastuidraw::c_array<const fastuidraw::TessellatedPath::cap> caps)
118 {
119 m_caps.reserve(m_caps.size() + caps.size());
120 for (const auto &C : caps)
121 {
122 m_caps.push_back(C);
123 }
124 }
125
126 void
127 process_joins(fastuidraw::c_array<const fastuidraw::TessellatedPath::join> joins)
128 {
129 m_joins.reserve(m_joins.size() + joins.size());
130 for (const auto &J : joins)
131 {
132 m_joins.push_back(J);
133 m_join_bbox.union_point(J.m_position);
134 }
135 }
136
137 fastuidraw::BoundingBox<float> m_bbox;
138 fastuidraw::BoundingBox<float> m_join_bbox;
139 std::vector<segment> m_segments;
140 std::vector<PerChain> m_chains;
141 std::vector<fastuidraw::TessellatedPath::join> m_joins;
142 std::vector<fastuidraw::TessellatedPath::cap> m_caps;
143 bool m_has_arcs;
144 };
145
146 class ScratchSpace
147 {
148 public:
149 std::vector<fastuidraw::vec3> m_adjusted_clip_eqs;
150 fastuidraw::c_array<const fastuidraw::vec2> m_clipped_rect;
151 fastuidraw::vecN<std::vector<fastuidraw::vec2>, 2> m_clip_scratch_vec2s;
152 };
153
154 class SubsetSelectionPrivate:fastuidraw::noncopyable
155 {
156 public:
157 // data from selection
158 fastuidraw::reference_counted_ptr<const fastuidraw::PartitionedTessellatedPath> m_source;
159 std::vector<unsigned int> m_subset_ids;
160 std::vector<unsigned int> m_join_subset_ids_backing;
161 fastuidraw::c_array<const unsigned int> m_join_subset_ids;
162
163 // work-room for selection
164 ScratchSpace m_scratch;
165 };
166
167 class SubsetPrivate:fastuidraw::noncopyable
168 {
169 public:
170 typedef fastuidraw::TessellatedPath::segment segment;
171 typedef fastuidraw::TessellatedPath::join join;
172 typedef fastuidraw::TessellatedPath::cap cap;
173 typedef fastuidraw::TessellatedPath::segment_chain segment_chain;
174
175 ~SubsetPrivate();
176
177 static
178 SubsetPrivate*
179 create(SubsetBuilder &builder,
180 std::vector<SubsetPrivate*> &out_values);
181
182 const fastuidraw::Rect&
183 bounding_box(void) const
184 {
185 return m_bounding_box.as_rect();
186 }
187
188 bool
189 has_children(void) const
190 {
191 return m_children[0] != nullptr;
192 }
193
194 SubsetPrivate*
195 child(unsigned int I)
196 {
197 return m_children[I];
198 }
199
200 unsigned int
201 ID(void) const
202 {
203 return m_ID;
204 }
205
206 fastuidraw::c_array<const segment_chain>
207 segment_chains(void) const
208 {
209 return fastuidraw::make_c_array(m_chains);
210 }
211
212 fastuidraw::c_array<const join>
213 joins(void) const
214 {
215 return fastuidraw::make_c_array(m_joins);
216 }
217
218 fastuidraw::c_array<const cap>
219 caps(void) const
220 {
221 return fastuidraw::make_c_array(m_caps);
222 }
223
224 void
225 select_subsets(bool miter_hunting,
226 ScratchSpace &scratch,
227 fastuidraw::c_array<const fastuidraw::vec3> clip_equations,
228 const fastuidraw::float3x3 &clip_matrix_local,
229 const fastuidraw::vec2 &one_pixel_width,
230 fastuidraw::c_array<const float> geometry_inflation,
231 std::vector<unsigned int> &dst);
232
233 private:
234 /* creation will steal the vector<> values of
235 * the passed SubsetBuilder
236 */
237 SubsetPrivate(int recursion_depth, SubsetBuilder &builder,
238 std::vector<SubsetPrivate*> &out_values);
239
240 void
241 make_children(int recursion_depth, std::vector<SubsetPrivate*> &out_values);
242
243 int
244 choose_splitting_coordinate(float &split_value);
245
246 static
247 void
248 process_chain(int splitting_coordinate, float splitting_value,
249 const segment_chain &chain,
250 SubsetBuilder *before_split, SubsetBuilder *after_split);
251
252 bool //returns true if this element is added.
253 select_subsets_implement(bool miter_hunting,
254 ScratchSpace &scratch,
255 float item_space_additional_room,
256 std::vector<unsigned int> &dst);
257
258 unsigned int m_ID;
259 fastuidraw::vecN<SubsetPrivate*, 2> m_children;
260 std::vector<segment> m_segments;
261 std::vector<segment_chain> m_chains;
262 std::vector<segment> m_prev_start_segments;
263 std::vector<join> m_joins;
264 std::vector<cap> m_caps;
265 fastuidraw::BoundingBox<float> m_bounding_box;
266 fastuidraw::BoundingBox<float> m_join_bounding_box;
267 };
268
269 class PartitionedTessellatedPathPrivate:fastuidraw::noncopyable
270 {
271 public:
272 explicit
273 PartitionedTessellatedPathPrivate(const fastuidraw::TessellatedPath &path);
274
275 PartitionedTessellatedPathPrivate(fastuidraw::c_array<const fastuidraw::TessellatedPath::segment_chain> chains,
276 fastuidraw::c_array<const fastuidraw::TessellatedPath::join> joins,
277 fastuidraw::c_array<const fastuidraw::TessellatedPath::cap> caps);
278
279 ~PartitionedTessellatedPathPrivate();
280
281 bool m_has_arcs;
282 SubsetPrivate *m_root_subset;
283 std::vector<SubsetPrivate*> m_subsets;
284 };
285}
286
287/////////////////////////////////////
288// SubsetPrivate methods
289SubsetPrivate*
290SubsetPrivate::
291create(SubsetBuilder &builder,
292 std::vector<SubsetPrivate*> &out_values)
293{
294 SubsetPrivate *root;
295
296 root = FASTUIDRAWnew SubsetPrivate(0, builder, out_values);
297 return root;
298}
299
300SubsetPrivate::
301SubsetPrivate(int recursion_depth, SubsetBuilder &builder,
302 std::vector<SubsetPrivate*> &out_values):
303 m_ID(out_values.size()),
304 m_children(nullptr, nullptr),
305 m_bounding_box(builder.m_bbox),
306 m_join_bounding_box(builder.m_join_bbox)
307{
308 out_values.push_back(this);
309 m_segments.swap(builder.m_segments);
310 m_joins.swap(builder.m_joins);
311 m_caps.swap(builder.m_caps);
312
313 /* reserve before hand so that addresses of
314 * values in m_prev_start_segments do not
315 * change.
316 */
317 m_chains.reserve(builder.m_chains.size());
318 m_prev_start_segments.reserve(builder.m_chains.size());
319
320 fastuidraw::c_array<const segment> segs(fastuidraw::make_c_array(m_segments));
321 for (const SubsetBuilder::PerChain &R : builder.m_chains)
322 {
323 fastuidraw::c_array<const segment> sub_segs;
324 sub_segs = segs.sub_array(R.m_range);
325 if (!sub_segs.empty())
326 {
327 segment_chain V;
328
329 if (R.m_has_before_first)
330 {
331 m_prev_start_segments.push_back(R.m_before_first);
332 V.m_prev_to_start = &m_prev_start_segments.back();
333 }
334 else
335 {
336 V.m_prev_to_start = nullptr;
337 }
338 V.m_segments = sub_segs;
339 m_chains.push_back(V);
340 }
341 }
342
343 if (m_segments.size() >= splitting_threshhold
344 && recursion_depth <= max_recursion_depth)
345 {
346 make_children(recursion_depth, out_values);
347 }
348}
349
350SubsetPrivate::
351~SubsetPrivate()
352{
353 if (m_children[0])
354 {
355 FASTUIDRAWassert(m_children[1]);
356
357 FASTUIDRAWdelete(m_children[0]);
358 FASTUIDRAWdelete(m_children[1]);
359 }
360}
361
362void
363SubsetPrivate::
364process_chain(int splitting_coordinate, float splitting_value,
365 const segment_chain &chain,
366 SubsetBuilder *before_split, SubsetBuilder *after_split)
367{
368 using namespace fastuidraw;
369
370 SubsetBuilder *last_added_to(nullptr);
371 const segment *prev_segment(chain.m_prev_to_start);
372
373 for (const segment &S : chain.m_segments)
374 {
375 enum TessellatedPath::split_t split;
376 segment before, after;
377
378 split = S.compute_split(splitting_value,
379 &before, &after,
380 splitting_coordinate);
381
382 switch (split)
383 {
384 case TessellatedPath::segment_completey_before_split:
385 {
386 if (last_added_to != before_split)
387 {
388 before_split->start_chain(prev_segment);
389 last_added_to = before_split;
390 }
391 prev_segment = before_split->add_segment(S);
392 }
393 break;
394
395 case TessellatedPath::segment_completey_after_split:
396 {
397 if (last_added_to != after_split)
398 {
399 after_split->start_chain(prev_segment);
400 last_added_to = after_split;
401 }
402 prev_segment = after_split->add_segment(S);
403 }
404 break;
405
406 case TessellatedPath::segment_split_start_before:
407 {
408 if (last_added_to != before_split)
409 {
410 before_split->start_chain(prev_segment);
411 }
412 prev_segment = before_split->add_segment(before);
413 after_split->start_chain(prev_segment);
414 prev_segment = after_split->add_segment(after);
415 last_added_to = after_split;
416 }
417 break;
418
419 case TessellatedPath::segment_split_start_after:
420 {
421 if (last_added_to != after_split)
422 {
423 after_split->start_chain(prev_segment);
424 }
425 prev_segment = after_split->add_segment(after);
426 before_split->start_chain(prev_segment);
427 prev_segment = before_split->add_segment(before);
428 last_added_to = before_split;
429 }
430 break;
431 } // switch
432
433 } //for (const segment &S : chain)
434}
435
436int
437SubsetPrivate::
438choose_splitting_coordinate(float &split_value)
439{
440 using namespace fastuidraw;
441
442 vecN<float, 2> split_values;
443 vecN<unsigned int, 2> split_counters(0, 0);
444 vecN<uvec2, 2> child_counters(uvec2(0, 0), uvec2(0, 0));
445 std::vector<float> qs;
446 unsigned int data_size(m_segments.size());
447
448 qs.reserve(m_segments.size());
449 /* For the most balanced split, we take the median
450 * of the start and end points of the segments.
451 */
452 for (int c = 0; c < 2; ++c)
453 {
454 qs.clear();
455 qs.push_back(m_bounding_box.min_point()[c]);
456 qs.push_back(m_bounding_box.max_point()[c]);
457 for(const segment &seg : m_segments)
458 {
459 qs.push_back(seg.m_start_pt[c]);
460 }
461 qs.push_back(m_segments.back().m_end_pt[c]);
462 std::sort(qs.begin(), qs.end());
463 split_values[c] = qs[qs.size() / 2];
464
465 for(const segment &seg : m_segments)
466 {
467 bool sA, sB;
468 sA = (seg.m_start_pt[c] < split_values[c]);
469 sB = (seg.m_end_pt[c] < split_values[c]);
470 if (sA != sB)
471 {
472 ++split_counters[c];
473 ++child_counters[c][0];
474 ++child_counters[c][1];
475 }
476 else
477 {
478 ++child_counters[c][sA];
479 }
480 }
481 }
482
483 /* choose the coordiante that splits the smallest number of edges */
484 int canidate;
485 canidate = (split_counters[0] < split_counters[1]) ? 0 : 1;
486
487 /* we require that both sides will have fewer edges
488 * than the parent size.
489 */
490 if (child_counters[canidate][0] < data_size
491 && child_counters[canidate][1] < data_size)
492 {
493 split_value = split_values[canidate];
494 return canidate;
495 }
496 else
497 {
498 return -1;
499 }
500}
501
502void
503SubsetPrivate::
504make_children(int recursion_depth, std::vector<SubsetPrivate*> &out_values)
505{
506 int splitting_coordinate(-1);
507 float splitting_value;
508
509 /* step 1: find a good splitting coordinate and splitting value */
510 splitting_coordinate = choose_splitting_coordinate(splitting_value);
511 if (splitting_coordinate == -1)
512 {
513 return;
514 }
515
516 /* step 2: split each chain */
517 SubsetBuilder before_split, after_split;
518
519 for (const auto &chain : m_chains)
520 {
521 process_chain(splitting_coordinate, splitting_value, chain,
522 &before_split, &after_split);
523 }
524
525 /* step 3: split the joins */
526 for (const auto &join : m_joins)
527 {
528 SubsetBuilder *dst;
529 if (join.m_position[splitting_coordinate] > splitting_value)
530 {
531 dst = &after_split;
532 }
533 else
534 {
535 dst = &before_split;
536 }
537 dst->m_joins.push_back(join);
538 dst->m_join_bbox.union_point(join.m_position);
539 }
540
541 /* step 4: split the caps */
542 for (const auto &cap : m_caps)
543 {
544 if (cap.m_position[splitting_coordinate] > splitting_value)
545 {
546 after_split.m_caps.push_back(cap);
547 }
548 else
549 {
550 before_split.m_caps.push_back(cap);
551 }
552 }
553
554 m_children[0]= FASTUIDRAWnew SubsetPrivate(recursion_depth + 1, before_split, out_values);
555 m_children[1]= FASTUIDRAWnew SubsetPrivate(recursion_depth + 1, after_split, out_values);
556}
557
558void
559SubsetPrivate::
560select_subsets(bool miter_hunting,
561 ScratchSpace &scratch,
562 fastuidraw::c_array<const fastuidraw::vec3> clip_equations,
563 const fastuidraw::float3x3 &clip_matrix_local,
564 const fastuidraw::vec2 &one_pixel_width,
565 fastuidraw::c_array<const float> geometry_inflation,
566 std::vector<unsigned int> &dst)
567{
568 using namespace fastuidraw;
569
570 float pixels_additional_room;
571 float item_space_additional_room;
572
573 if (miter_hunting)
574 {
575 pixels_additional_room = geometry_inflation[PathEnums::pixel_space_distance_miter_joins];
576 item_space_additional_room = geometry_inflation[PathEnums::item_space_distance_miter_joins];
577 }
578 else
579 {
580 pixels_additional_room = geometry_inflation[PathEnums::pixel_space_distance];
581 item_space_additional_room = geometry_inflation[PathEnums::item_space_distance];
582 }
583
584 scratch.m_adjusted_clip_eqs.resize(clip_equations.size());
585 for(unsigned int i = 0; i < clip_equations.size(); ++i)
586 {
587 vec3 c(clip_equations[i]);
588 float f;
589
590 /* make "w" larger by the named number of pixels. */
591 f = t_abs(c.x()) * one_pixel_width.x()
592 + t_abs(c.y()) * one_pixel_width.y();
593
594 c.z() += pixels_additional_room * f;
595
596 /* transform clip equations from clip coordinates to
597 * local coordinates.
598 */
599 scratch.m_adjusted_clip_eqs[i] = c * clip_matrix_local;
600 }
601
602 dst.clear();
603 select_subsets_implement(miter_hunting, scratch,
604 item_space_additional_room,
605 dst);
606}
607
608bool
609SubsetPrivate::
610select_subsets_implement(bool miter_hunting,
611 ScratchSpace &scratch,
612 float item_space_additional_room,
613 std::vector<unsigned int> &dst)
614{
615 using namespace fastuidraw;
616
617 if (miter_hunting)
618 {
619 if (m_join_bounding_box.empty())
620 {
621 return false;
622 }
623 }
624 else
625 {
626 if (m_bounding_box.empty())
627 {
628 return false;
629 }
630 }
631
632 /* clip the bounding box of this StrokedPathSubset */
633 vecN<vec2, 4> bb;
634 bool unclipped;
635
636 if (miter_hunting)
637 {
638 m_join_bounding_box.inflated_polygon(bb, item_space_additional_room);
639 }
640 else
641 {
642 m_bounding_box.inflated_polygon(bb, item_space_additional_room);
643 }
644 unclipped = detail::clip_against_planes(make_c_array(scratch.m_adjusted_clip_eqs),
645 bb, &scratch.m_clipped_rect,
646 scratch.m_clip_scratch_vec2s);
647
648 //completely clipped
649 if (scratch.m_clipped_rect.empty())
650 {
651 return false;
652 }
653
654 //completely unclipped.
655 if (unclipped || !has_children())
656 {
657 dst.push_back(m_ID);
658 return true;
659 }
660
661 FASTUIDRAWassert(m_children[0] != nullptr);
662 FASTUIDRAWassert(m_children[1] != nullptr);
663
664 bool r0, r1;
665
666 r0 = m_children[0]->select_subsets_implement(miter_hunting, scratch, item_space_additional_room, dst);
667 r1 = m_children[1]->select_subsets_implement(miter_hunting, scratch, item_space_additional_room, dst);
668
669 if (r0 && r1)
670 {
671 /* the last two elements added are m_children[0] and m_children[1];
672 * remove them and add this instead (if possible).
673 */
674 FASTUIDRAWassert(!dst.empty() && dst.back() == m_children[1]->m_ID);
675 dst.pop_back();
676
677 FASTUIDRAWassert(!dst.empty() && dst.back() == m_children[0]->m_ID);
678 dst.pop_back();
679
680 dst.push_back(m_ID);
681 return true;
682 }
683
684 return false;
685}
686
687////////////////////////////////////////////
688// PartitionedTessellatedPathPrivate methods
689PartitionedTessellatedPathPrivate::
690PartitionedTessellatedPathPrivate(const fastuidraw::TessellatedPath &P)
691{
692 SubsetBuilder builder;
693
694 builder.process_chains(P.segment_chain_data());
695 builder.process_joins(P.join_data());
696 builder.process_caps(P.cap_data());
697 m_has_arcs = builder.m_has_arcs;
698 m_root_subset = SubsetPrivate::create(builder, m_subsets);
699}
700
701PartitionedTessellatedPathPrivate::
702PartitionedTessellatedPathPrivate(fastuidraw::c_array<const fastuidraw::TessellatedPath::segment_chain> chains,
703 fastuidraw::c_array<const fastuidraw::TessellatedPath::join> joins,
704 fastuidraw::c_array<const fastuidraw::TessellatedPath::cap> caps)
705{
706 SubsetBuilder builder;
707
708 builder.process_chains(chains);
709 builder.process_caps(caps);
710 builder.process_joins(joins);
711 m_has_arcs = builder.m_has_arcs;
712 m_root_subset = SubsetPrivate::create(builder, m_subsets);
713}
714
715PartitionedTessellatedPathPrivate::
716~PartitionedTessellatedPathPrivate()
717{
718 FASTUIDRAWdelete(m_root_subset);
719}
720
721/////////////////////////////////////////////////////////////////
722// fastuidraw::PartitionedTessellatedPath::SubsetSelection methods
723fastuidraw::PartitionedTessellatedPath::SubsetSelection::
724SubsetSelection(void)
725{
726 m_d = FASTUIDRAWnew SubsetSelectionPrivate();
727}
728
729fastuidraw::PartitionedTessellatedPath::SubsetSelection::
730~SubsetSelection(void)
731{
732 SubsetSelectionPrivate *d;
733 d = static_cast<SubsetSelectionPrivate*>(m_d);
734 FASTUIDRAWdelete(d);
735 m_d = nullptr;
736}
737
738fastuidraw::c_array<const unsigned int>
739fastuidraw::PartitionedTessellatedPath::SubsetSelection::
740subset_ids(void) const
741{
742 SubsetSelectionPrivate *d;
743 d = static_cast<SubsetSelectionPrivate*>(m_d);
744 return make_c_array(d->m_subset_ids);
745}
746
747fastuidraw::c_array<const unsigned int>
748fastuidraw::PartitionedTessellatedPath::SubsetSelection::
749join_subset_ids(void) const
750{
751 SubsetSelectionPrivate *d;
752 d = static_cast<SubsetSelectionPrivate*>(m_d);
753 return d->m_join_subset_ids;
754}
755
756const fastuidraw::reference_counted_ptr<const fastuidraw::PartitionedTessellatedPath>&
757fastuidraw::PartitionedTessellatedPath::SubsetSelection::
758source(void) const
759{
760 SubsetSelectionPrivate *d;
761 d = static_cast<SubsetSelectionPrivate*>(m_d);
762 return d->m_source;
763}
764
765void
766fastuidraw::PartitionedTessellatedPath::SubsetSelection::
767clear(const reference_counted_ptr<const PartitionedTessellatedPath> &src)
768{
769 SubsetSelectionPrivate *d;
770 d = static_cast<SubsetSelectionPrivate*>(m_d);
771 d->m_source = src;
772 d->m_subset_ids.clear();
773 d->m_join_subset_ids_backing.clear();
774 d->m_join_subset_ids = c_array<const unsigned int>();
775}
776
777void
778fastuidraw::PartitionedTessellatedPath::SubsetSelection::
779apply_path_effect(const PathEffect &effect, PathEffect::Storage &dst) const
780{
781 if (!source())
782 {
783 return;
784 }
785
786 const PartitionedTessellatedPath &path(*source());
787 for (unsigned int id : subset_ids())
788 {
789 PartitionedTessellatedPath::Subset S(path.subset(id));
790 c_array<const segment_chain> segment_chains(S.segment_chains());
791 c_array<const TessellatedPath::cap> caps(S.caps());
792
793 effect.process_chains(segment_chains.begin(), segment_chains.end(), dst);
794 effect.process_caps(caps.begin(), caps.end(), dst);
795 }
796
797 for (unsigned int id : join_subset_ids())
798 {
799 PartitionedTessellatedPath::Subset S(path.subset(id));
800 c_array<const TessellatedPath::join> joins(S.joins());
801
802 effect.process_joins(joins.begin(), joins.end(), dst);
803 }
804}
805
806/////////////////////////////////
807// fastuidraw::PartitionedTessellatedPath::Subset methods
808fastuidraw::PartitionedTessellatedPath::Subset::
809Subset(void *d):
810 m_d(d)
811{
812}
813
814const fastuidraw::Rect&
815fastuidraw::PartitionedTessellatedPath::Subset::
816bounding_box(void) const
817{
818 SubsetPrivate *d;
819 d = static_cast<SubsetPrivate*>(m_d);
820 FASTUIDRAWassert(d);
821 return d->bounding_box();
822}
823
824fastuidraw::c_array<const fastuidraw::TessellatedPath::segment_chain>
825fastuidraw::PartitionedTessellatedPath::Subset::
826segment_chains(void) const
827{
828 SubsetPrivate *d;
829 d = static_cast<SubsetPrivate*>(m_d);
830 FASTUIDRAWassert(d);
831 return d->segment_chains();
832}
833
834bool
835fastuidraw::PartitionedTessellatedPath::Subset::
836has_children(void) const
837{
838 SubsetPrivate *d;
839 d = static_cast<SubsetPrivate*>(m_d);
840 FASTUIDRAWassert(d);
841 return d->has_children();
842}
843
844unsigned int
845fastuidraw::PartitionedTessellatedPath::Subset::
846ID(void) const
847{
848 SubsetPrivate *d;
849 d = static_cast<SubsetPrivate*>(m_d);
850 FASTUIDRAWassert(d);
851 return d->ID();
852}
853
854fastuidraw::vecN<fastuidraw::PartitionedTessellatedPath::Subset, 2>
855fastuidraw::PartitionedTessellatedPath::Subset::
856children(void) const
857{
858 SubsetPrivate *d, *p0(nullptr), *p1(nullptr);
859
860 d = static_cast<SubsetPrivate*>(m_d);
861 if (d && d->has_children())
862 {
863 p0 = d->child(0);
864 p1 = d->child(1);
865 }
866
867 Subset s0(p0), s1(p1);
868 return vecN<Subset, 2>(s0, s1);
869}
870
871fastuidraw::c_array<const fastuidraw::TessellatedPath::join>
872fastuidraw::PartitionedTessellatedPath::Subset::
873joins(void) const
874{
875 SubsetPrivate *d;
876 d = static_cast<SubsetPrivate*>(m_d);
877 FASTUIDRAWassert(d);
878 return d->joins();
879}
880
881fastuidraw::c_array<const fastuidraw::TessellatedPath::cap>
882fastuidraw::PartitionedTessellatedPath::Subset::
883caps(void) const
884{
885 SubsetPrivate *d;
886 d = static_cast<SubsetPrivate*>(m_d);
887 FASTUIDRAWassert(d);
888 return d->caps();
889}
890
891////////////////////////////////////////////
892// fastuidraw::PartitionedTessellatedPath methods
893fastuidraw::PartitionedTessellatedPath::
894PartitionedTessellatedPath(const TessellatedPath &path)
895{
896 m_d = FASTUIDRAWnew PartitionedTessellatedPathPrivate(path);
897}
898
899fastuidraw::PartitionedTessellatedPath::
900PartitionedTessellatedPath(c_array<const segment_chain> chains,
901 c_array<const join> joins,
902 c_array<const cap> caps)
903{
904 m_d = FASTUIDRAWnew PartitionedTessellatedPathPrivate(chains, joins, caps);
905}
906
907fastuidraw::PartitionedTessellatedPath::
908~PartitionedTessellatedPath()
909{
910 PartitionedTessellatedPathPrivate *d;
911 d = static_cast<PartitionedTessellatedPathPrivate*>(m_d);
912 FASTUIDRAWdelete(d);
913}
914
915bool
916fastuidraw::PartitionedTessellatedPath::
917has_arcs(void) const
918{
919 PartitionedTessellatedPathPrivate *d;
920 d = static_cast<PartitionedTessellatedPathPrivate*>(m_d);
921 return d->m_has_arcs;
922}
923
924unsigned int
925fastuidraw::PartitionedTessellatedPath::
926number_subsets(void) const
927{
928 PartitionedTessellatedPathPrivate *d;
929 d = static_cast<PartitionedTessellatedPathPrivate*>(m_d);
930 return d->m_subsets.size();
931}
932
933fastuidraw::PartitionedTessellatedPath::Subset
934fastuidraw::PartitionedTessellatedPath::
935subset(unsigned int I) const
936{
937 PartitionedTessellatedPathPrivate *d;
938 d = static_cast<PartitionedTessellatedPathPrivate*>(m_d);
939
940 FASTUIDRAWassert(I < d->m_subsets.size());
941 return Subset(d->m_subsets[I]);
942}
943
944fastuidraw::PartitionedTessellatedPath::Subset
945fastuidraw::PartitionedTessellatedPath::
946root_subset(void) const
947{
948 PartitionedTessellatedPathPrivate *d;
949 d = static_cast<PartitionedTessellatedPathPrivate*>(m_d);
950 return Subset(d->m_root_subset);
951}
952
953fastuidraw::c_array<const fastuidraw::TessellatedPath::join>
954fastuidraw::PartitionedTessellatedPath::
955joins(void) const
956{
957 PartitionedTessellatedPathPrivate *d;
958 d = static_cast<PartitionedTessellatedPathPrivate*>(m_d);
959 return d->m_root_subset->joins();
960}
961
962fastuidraw::c_array<const fastuidraw::TessellatedPath::cap>
963fastuidraw::PartitionedTessellatedPath::
964caps(void) const
965{
966 PartitionedTessellatedPathPrivate *d;
967 d = static_cast<PartitionedTessellatedPathPrivate*>(m_d);
968 return d->m_root_subset->caps();
969}
970
971void
972fastuidraw::PartitionedTessellatedPath::
973select_subsets(c_array<const vec3> clip_equations,
974 const float3x3 &clip_matrix_local,
975 const vec2 &one_pixel_width,
976 c_array<const float> geometry_inflation,
977 bool select_miter_joins,
978 SubsetSelection &dst) const
979{
980 PartitionedTessellatedPathPrivate *d;
981 d = static_cast<PartitionedTessellatedPathPrivate*>(m_d);
982
983 SubsetSelectionPrivate *dst_d;
984 dst_d = static_cast<SubsetSelectionPrivate*>(dst.m_d);
985
986 dst_d->m_source = this;
987 d->m_root_subset->select_subsets(false,
988 dst_d->m_scratch,
989 clip_equations,
990 clip_matrix_local,
991 one_pixel_width,
992 geometry_inflation,
993 dst_d->m_subset_ids);
994
995 if (select_miter_joins)
996 {
997 d->m_root_subset->select_subsets(true,
998 dst_d->m_scratch,
999 clip_equations,
1000 clip_matrix_local,
1001 one_pixel_width,
1002 geometry_inflation,
1003 dst_d->m_join_subset_ids_backing);
1004 dst_d->m_join_subset_ids = make_c_array(dst_d->m_join_subset_ids_backing);
1005 }
1006 else
1007 {
1008 dst_d->m_join_subset_ids = make_c_array(dst_d->m_subset_ids);
1009 }
1010}
1011