1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.math3.geometry.euclidean.twod;
18
19 import java.util.ArrayList;
20 import java.util.Iterator;
21
22 import org.apache.commons.math3.exception.MathIllegalArgumentException;
23 import org.apache.commons.math3.exception.util.LocalizedFormats;
24 import org.apache.commons.math3.geometry.Point;
25 import org.apache.commons.math3.geometry.euclidean.oned.IntervalsSet;
26 import org.apache.commons.math3.geometry.partitioning.Region;
27 import org.apache.commons.math3.geometry.partitioning.RegionFactory;
28 import org.apache.commons.math3.geometry.partitioning.SubHyperplane;
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 class NestedLoops {
48
49
50 private Vector2D[] loop;
51
52
53 private ArrayList<NestedLoops> surrounded;
54
55
56 private Region<Euclidean2D> polygon;
57
58
59 private boolean originalIsClockwise;
60
61
62 private final double tolerance;
63
64
65
66
67
68
69
70
71
72 public NestedLoops(final double tolerance) {
73 this.surrounded = new ArrayList<NestedLoops>();
74 this.tolerance = tolerance;
75 }
76
77
78
79
80
81
82
83
84 private NestedLoops(final Vector2D[] loop, final double tolerance)
85 throws MathIllegalArgumentException {
86
87 if (loop[0] == null) {
88 throw new MathIllegalArgumentException(LocalizedFormats.OUTLINE_BOUNDARY_LOOP_OPEN);
89 }
90
91 this.loop = loop;
92 this.surrounded = new ArrayList<NestedLoops>();
93 this.tolerance = tolerance;
94
95
96 final ArrayList<SubHyperplane<Euclidean2D>> edges = new ArrayList<SubHyperplane<Euclidean2D>>();
97 Vector2D current = loop[loop.length - 1];
98 for (int i = 0; i < loop.length; ++i) {
99 final Vector2D previous = current;
100 current = loop[i];
101 final Line line = new Line(previous, current, tolerance);
102 final IntervalsSet region =
103 new IntervalsSet(line.toSubSpace((Point<Euclidean2D>) previous).getX(),
104 line.toSubSpace((Point<Euclidean2D>) current).getX(),
105 tolerance);
106 edges.add(new SubLine(line, region));
107 }
108 polygon = new PolygonsSet(edges, tolerance);
109
110
111 if (Double.isInfinite(polygon.getSize())) {
112 polygon = new RegionFactory<Euclidean2D>().getComplement(polygon);
113 originalIsClockwise = false;
114 } else {
115 originalIsClockwise = true;
116 }
117
118 }
119
120
121
122
123
124
125 public void add(final Vector2D[] bLoop) throws MathIllegalArgumentException {
126 add(new NestedLoops(bLoop, tolerance));
127 }
128
129
130
131
132
133
134 private void add(final NestedLoops node) throws MathIllegalArgumentException {
135
136
137 for (final NestedLoops child : surrounded) {
138 if (child.polygon.contains(node.polygon)) {
139 child.add(node);
140 return;
141 }
142 }
143
144
145 for (final Iterator<NestedLoops> iterator = surrounded.iterator(); iterator.hasNext();) {
146 final NestedLoops child = iterator.next();
147 if (node.polygon.contains(child.polygon)) {
148 node.surrounded.add(child);
149 iterator.remove();
150 }
151 }
152
153
154 RegionFactory<Euclidean2D> factory = new RegionFactory<Euclidean2D>();
155 for (final NestedLoops child : surrounded) {
156 if (!factory.intersection(node.polygon, child.polygon).isEmpty()) {
157 throw new MathIllegalArgumentException(LocalizedFormats.CROSSING_BOUNDARY_LOOPS);
158 }
159 }
160
161 surrounded.add(node);
162
163 }
164
165
166
167
168
169
170 public void correctOrientation() {
171 for (NestedLoops child : surrounded) {
172 child.setClockWise(true);
173 }
174 }
175
176
177
178
179
180 private void setClockWise(final boolean clockwise) {
181
182 if (originalIsClockwise ^ clockwise) {
183
184 int min = -1;
185 int max = loop.length;
186 while (++min < --max) {
187 final Vector2D tmp = loop[min];
188 loop[min] = loop[max];
189 loop[max] = tmp;
190 }
191 }
192
193
194 for (final NestedLoops child : surrounded) {
195 child.setClockWise(!clockwise);
196 }
197
198 }
199
200 }