Skip to content

Commit 45fbb09

Browse files
committed
dcel, beginning of naive emst, half way done with convex dt
1 parent 04215ca commit 45fbb09

File tree

9 files changed

+918
-242
lines changed

9 files changed

+918
-242
lines changed

.idea/workspace.xml

Lines changed: 403 additions & 240 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/main/java/convex_dt/ConvexDT.java

Lines changed: 336 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,336 @@
1+
package convex_dt;
2+
3+
import dcel.HalfEdge;
4+
import kds.KDSPoint;
5+
import static convex_dt.Utils.*; // not very nice, but it's to avoid having to write Utils.<func> everywhere
6+
import static convex_dt.ConvexShape.*;
7+
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
8+
9+
import java.util.ArrayList;
10+
11+
/**
12+
* Created by cvium on 29-11-2016.
13+
*/
14+
public class ConvexDT {
15+
private HalfEdge base;
16+
private HalfEdge lcand;
17+
private HalfEdge rcand;
18+
private ConvexShape shape;
19+
private ArrayList<KDSPoint> points;
20+
21+
public ConvexDT() {
22+
}
23+
24+
public ConvexDT(ArrayList<KDSPoint> points, ConvexShape shape) {
25+
throw new NotImplementedException();
26+
}
27+
28+
public HalfEdge computeSmallDelaunay(ArrayList<KDSPoint> points) {
29+
throw new NotImplementedException();
30+
}
31+
32+
public HalfEdge findLowerSupport(HalfEdge left, HalfEdge right) {
33+
if (lowerThan(left.getOrigin(), right.getOrigin())) {
34+
while (shape.inInfCircle(rNext(right).getOrigin(), left.getOrigin(), right.getOrigin()) ==
35+
infCircleEnum.INSIDE && lessThan(rNext(right).getOrigin(), right.getOrigin())) {
36+
right = rNext(right);
37+
}
38+
if (shape.inInfCircle(right.getDestination(), left.getOrigin(), right.getOrigin()) == infCircleEnum.INSIDE) {
39+
right = rPrev(right);
40+
} else if (shape.inInfCircle(left.getDestination(), left.getOrigin(), right.getOrigin()) == infCircleEnum.INSIDE) {
41+
left = rPrev(left);
42+
} else {
43+
return connect(right.getTwin(), oPrev(left));
44+
}
45+
} else {
46+
// TODO ????
47+
throw new NotImplementedException();
48+
}
49+
50+
// TODO ??????
51+
return connect(right, left);
52+
}
53+
54+
public void makeBundle(HalfEdge edge) {
55+
if (edge != lNext(lNext(lNext(edge)))) {
56+
if (lNext(edge).isBridge()) delete(lNext(edge));
57+
if (dNext(edge).isBridge()) delete(dNext(edge));
58+
connect(edge, lPrev(edge)).markBridge();
59+
}
60+
}
61+
62+
public HalfEdge unBundle(HalfEdge edge) {
63+
HalfEdge fixed, moving, returnEdge, junk;
64+
if (onLine(oNext(edge).getDestination(), edge.getOrigin(), edge.getDestination())) {
65+
fixed = oPrev(edge);
66+
moving = lNext(lNext(edge));
67+
returnEdge = oNext(edge);
68+
} else {
69+
fixed = lNext(edge);
70+
moving = lNext(oPrev(edge));
71+
returnEdge = oPrev(edge);
72+
}
73+
74+
while (fixed != moving) {
75+
junk = connect(fixed, moving);
76+
moving = lNext(moving);
77+
}
78+
79+
return returnEdge;
80+
}
81+
82+
public void unBundleAll(HalfEdge edge) {
83+
HalfEdge current;
84+
for (int direction = 1; direction <= 2; ++direction) {
85+
current = oNext(edge);
86+
while (current != edge) {
87+
if (current.isBridge()) current = unBundle(current);
88+
else current = oNext(current);
89+
}
90+
edge = edge.getTwin();
91+
}
92+
}
93+
94+
public HalfEdge produceONext(HalfEdge edge) {
95+
if (lNext(edge).isBridge()) {
96+
delete(lNext(edge));
97+
makeBundle(connect(lNext(edge), edge).getTwin());
98+
} else if (oNext(edge).isBridge()) {
99+
delete(oNext(edge));
100+
makeBundle(oPrev(connect(edge, lPrev(edge))));
101+
}
102+
return oNext(edge);
103+
}
104+
105+
public HalfEdge produceOPrev(HalfEdge edge) {
106+
if (lPrev(edge).isBridge()) {
107+
delete(lPrev(edge));
108+
makeBundle(connect(lPrev(edge), edge).getTwin());
109+
} else if (oPrev(edge).isBridge()) {
110+
delete(oPrev(edge));
111+
makeBundle(oNext(connect(edge, lNext(edge))));
112+
}
113+
return oPrev(edge);
114+
}
115+
116+
public HalfEdge connect(HalfEdge a, HalfEdge b) {
117+
// TODO: does this work?
118+
HalfEdge newEdge = new HalfEdge(a.getDestination(), b.getOrigin());
119+
a.setNext(newEdge);
120+
b.setPrev(newEdge);
121+
// hackish way to create the twin
122+
newEdge.getTwin();
123+
return newEdge;
124+
}
125+
126+
public void delete(HalfEdge e) {
127+
// remove e from its prev and next edges, TODO: IS THAT ENOUGH?
128+
e.getPrev().setNext(null);
129+
e.getNext().setPrev(null);
130+
// have to remove the twin as well
131+
e.getTwin().getPrev().setNext(null);
132+
e.getTwin().getNext().setPrev(null);
133+
}
134+
135+
public HalfEdge connectLeft() {
136+
unBundleAll(lcand);
137+
// \__ Base is directed from right to left, so base dest must be connected to lcand's origin
138+
return connect(base.getTwin(), lcand.getTwin());
139+
}
140+
141+
public HalfEdge connectRight() {
142+
unBundleAll(rcand);
143+
// TODO: should this be reversed? THINK NOT
144+
// __/ Base is directed from left to right, so base dest must be connected to rcand's origin
145+
return connect(base.getTwin(), rcand.getTwin());
146+
}
147+
148+
public HalfEdge computeLcand() {
149+
HalfEdge current = null, top = null, t = null;
150+
lcand = rPrev(base);
151+
152+
if (shape.inInfCircle(lcand.getDestination(), base.getOrigin(), base.getDestination()) == infCircleEnum.BEFORE) {
153+
lcand = produceONext(lcand);
154+
while (shape.inInfCircle(lcand.getDestination(), base.getOrigin(), base.getDestination()) == infCircleEnum.BEFORE) {
155+
delete(oPrev(lcand));
156+
lcand = produceONext(lcand);
157+
}
158+
if (isValid(lcand)) delete(oPrev(lcand));
159+
else lcand = oPrev(lcand);
160+
}
161+
162+
if (isValid(lcand)) {
163+
current = oNext(lcand);
164+
top = lcand;
165+
166+
switch(shape.inCircle(lcand.getOrigin(), lcand.getDestination(), base.getOrigin(), current.getDestination())) {
167+
case INSIDE:
168+
if (current.isBridge() || rPrev(current).isBridge()) {
169+
current = produceONext(oPrev(current));
170+
}
171+
if (leftOf(current.getDestination(), lcand.getOrigin(), lcand.getDestination())) {
172+
if (rPrev(current) != dPrev(lcand))
173+
makeBundle(connect(lcand, current.getTwin()).getTwin());
174+
if (current != oNext(lcand))
175+
makeBundle(lNext(connect(lPrev(lcand), current.getTwin())));
176+
t = produceONext(lcand);
177+
delete(lcand);
178+
lcand = t;
179+
current = oNext(lcand);
180+
top = lcand;
181+
} else {
182+
// We have lcand
183+
break;
184+
//return lcand;
185+
}
186+
break;
187+
case ONBEFORE:
188+
if (leftOf(current.getDestination(), current.getOrigin(), lcand.getDestination())) {
189+
current = rPrev(current);
190+
} else{
191+
return lcand;
192+
}
193+
break;
194+
case ONAFTER:
195+
top = dNext(top);
196+
t = current;
197+
current = oNext(current);
198+
delete(current);
199+
break;
200+
default:
201+
//return lcand;
202+
break;
203+
}
204+
} else {
205+
System.out.println("lcand not valid???");
206+
}
207+
208+
// TODO top shouldn't be null I think
209+
//assert top != null;
210+
//assert current != null;
211+
212+
if (top != lcand) {
213+
makeBundle(lNext(connect(top, lcand)));
214+
top = oNext(lcand);
215+
}
216+
if (oPrev(current) != top) {
217+
makeBundle(oPrev(connect(top, oPrev(current))));
218+
}
219+
return lcand;
220+
}
221+
222+
public HalfEdge computeRcand() {
223+
HalfEdge current = null, top = null, t = null;
224+
// TODO ?
225+
HalfEdge base_twin = base.getTwin();
226+
rcand = lNext(base_twin);
227+
228+
if (shape.inInfCircle(rcand.getDestination(), base_twin.getOrigin(), base_twin.getDestination()) == infCircleEnum.BEFORE) {
229+
rcand = produceOPrev(rcand);
230+
while (shape.inInfCircle(rcand.getDestination(), base_twin.getOrigin(), base_twin.getDestination()) == infCircleEnum.BEFORE) {
231+
delete(oNext(rcand));
232+
rcand = produceOPrev(rcand);
233+
}
234+
if (isValid(rcand)) delete(oNext(rcand));
235+
else rcand = oNext(rcand);
236+
}
237+
238+
if (isValid(rcand)) {
239+
current = oPrev(rcand);
240+
top = rcand;
241+
switch(shape.inCircle(rcand.getOrigin(), rcand.getDestination(), base_twin.getOrigin(), current.getDestination())) {
242+
case INSIDE:
243+
if (current.isBridge() || lNext(current).isBridge()) {
244+
current = produceOPrev(lNext(current));
245+
}
246+
if (leftOf(current.getDestination(), rcand.getOrigin(), rcand.getDestination())) {
247+
if (lNext(current) != rcand) {
248+
249+
}
250+
}
251+
break;
252+
case ONBEFORE:
253+
break;
254+
case ONAFTER:
255+
break;
256+
default:
257+
// we have rcand
258+
break;
259+
260+
}
261+
262+
}
263+
264+
265+
throw new NotImplementedException();
266+
}
267+
268+
public HalfEdge delaunay(ArrayList<KDSPoint> points) {
269+
if (points.size() < 4) return computeSmallDelaunay(points);
270+
else {
271+
int split = (int) Math.floor(points.size() / 2);
272+
273+
ArrayList<KDSPoint>left = (ArrayList<KDSPoint>) points.subList(0, split);
274+
ArrayList<KDSPoint> right = (ArrayList<KDSPoint>) points.subList(split + 1, points.size());
275+
276+
HalfEdge lleft = delaunay(left);
277+
HalfEdge lright = delaunay(right);
278+
279+
base = findLowerSupport(lleft, lright);
280+
boolean leftLower = lowerThan(lleft.getOrigin(), lright.getOrigin());
281+
HalfEdge lower;
282+
if (leftLower) {
283+
if (lleft.getOrigin() == base.getDestination()) lower = base.getTwin();
284+
else lower = lleft;
285+
} else {
286+
lower = rNext(lright);
287+
}
288+
289+
lcand = computeLcand();
290+
rcand = computeRcand();
291+
292+
if (isValid(lcand) && isValid(rcand)) {
293+
switch(shape.inCircle(base.getOrigin(), base.getDestination(), lcand.getDestination(), rcand.getDestination())) {
294+
case INSIDE:
295+
base = connectRight();
296+
break;
297+
case ON:
298+
case ONBEFORE:
299+
case ONAFTER:
300+
if (rightOf(rcand.getDestination(), lcand.getOrigin(), lcand.getDestination())) {
301+
base = connectRight();
302+
} else {
303+
base = connectLeft();
304+
}
305+
break;
306+
default:
307+
base = connectLeft();
308+
}
309+
}
310+
else if (isValid(lcand)) base = connectLeft();
311+
else if (isValid(rcand)) base = connectRight();
312+
else if (shape.inInfCircle(rcand.getDestination(), base.getOrigin(), base.getDestination()) == infCircleEnum.AFTER) {
313+
while (shape.inInfCircle(lcand.getDestination(), lcand.getOrigin(), rcand.getDestination()) == infCircleEnum.INSIDE) {
314+
lcand = rPrev(lcand);
315+
}
316+
base = connect(rcand, oPrev(lcand));
317+
delete(rcand);
318+
}
319+
else if (shape.inInfCircle(rcand.getDestination(), base.getOrigin(), base.getDestination()) == infCircleEnum.AFTER) {
320+
while (shape.inInfCircle(rcand.getDestination(), lcand.getDestination(), rcand.getOrigin()) == infCircleEnum.INSIDE) {
321+
rcand = lNext(rcand);
322+
}
323+
base = connect(lPrev(rcand), lcand.getTwin());
324+
delete(lcand);
325+
}
326+
327+
if (!leftLower) lower = rPrev(lower);
328+
329+
return lower;
330+
}
331+
}
332+
333+
public boolean isValid(HalfEdge e) {
334+
return shape.inInfCircle(e.getDestination(), base.getOrigin(), base.getDestination()) == infCircleEnum.INSIDE;
335+
}
336+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package convex_dt;
2+
3+
import kds.KDSPoint;
4+
5+
/**
6+
* Created by cvium on 03-12-2016.
7+
*/
8+
public interface ConvexShape {
9+
circleEnum inCircle(KDSPoint a, KDSPoint b, KDSPoint c, KDSPoint d);
10+
11+
/**
12+
* Predicate test to determine where point a lies wrt. to the infinite circle with b and c on the boundary.
13+
*
14+
* @param a The query point
15+
* @param b First point on the boundary of the infinite circle
16+
* @param c The second point on the boundary of the infinite circle
17+
* @return inside, outside, before, after
18+
*/
19+
infCircleEnum inInfCircle(KDSPoint a, KDSPoint b, KDSPoint c);
20+
enum infCircleEnum {
21+
INSIDE, OUTSIDE, BEFORE, AFTER
22+
}
23+
enum circleEnum {
24+
INSIDE, OUTSIDE, ONBEFORE, ONAFTER, ON
25+
}
26+
}

src/main/java/convex_dt/Pie.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package convex_dt;
2+
3+
import kds.KDSPoint;
4+
5+
/**
6+
* Created by cvium on 03-12-2016.
7+
*/
8+
public class Pie implements ConvexShape {
9+
public Pie() {
10+
}
11+
12+
@Override
13+
public circleEnum inCircle(KDSPoint a, KDSPoint b, KDSPoint c, KDSPoint d) {
14+
return null;
15+
}
16+
17+
@Override
18+
public infCircleEnum inInfCircle(KDSPoint a, KDSPoint b, KDSPoint c) {
19+
return null;
20+
}
21+
}

0 commit comments

Comments
 (0)