|
3 | 3 | import ProGAL.geom2d.viewer.J2DScene;
|
4 | 4 | import kds.KDSPoint;
|
5 | 5 |
|
| 6 | +import java.awt.*; |
6 | 7 | import java.util.ArrayList;
|
7 | 8 |
|
| 9 | +import static convex_dt.Utils.isCCW; |
| 10 | +import static convex_dt.Utils.leftOf; |
| 11 | +import static convex_dt.Utils.rightOf; |
8 | 12 | import static java.lang.Thread.sleep;
|
9 | 13 |
|
10 | 14 | /**
|
@@ -49,76 +53,184 @@ public HalfEdge createEdge() {
|
49 | 53 | public HalfEdge connect(HalfEdge a, HalfEdge b) {
|
50 | 54 | HalfEdge c = new HalfEdge(a.getDestination(), b.getOrigin());
|
51 | 55 | HalfEdge c_twin = new HalfEdge(b.getOrigin(), a.getDestination());
|
| 56 | + c.setTwin(c_twin); |
| 57 | + c_twin.setTwin(c); |
52 | 58 | edges.add(c);
|
53 | 59 | edges.add(c_twin);
|
54 | 60 |
|
55 |
| - // add prev and next |
56 |
| - c.setPrev(a); |
57 |
| - c.setNext(b); |
| 61 | + // Handling a |
58 | 62 |
|
59 |
| - c.setTwin(c_twin); |
60 |
| - c_twin.setTwin(c); |
61 |
| - // remove the face because we'll most likely get 2 new ones |
62 |
| - faces.remove(a.getFace()); |
63 |
| - // create two new faces |
64 |
| - Face c_face = createFace(c); |
65 |
| - Face c_twin_face = createFace(c_twin); |
66 |
| - c.setFace(c_face); |
67 |
| - c_twin.setFace(c_twin_face); |
68 |
| - // connect the twin |
69 |
| - if (a.getNext() != null) { |
70 |
| - c_twin.setNext(a.getNext()); |
71 |
| - a.getNext().setPrev(c_twin); |
72 |
| - } else if (c.getPrev() != null){ |
73 |
| - c_twin.setNext(c.getPrev().getTwin()); |
74 |
| - c.getPrev().getTwin().setPrev(c_twin); |
| 63 | + // case 1: a has no next -> not much to do |
| 64 | + if (a.getNext() == null) { |
| 65 | + a.setNext(c); |
| 66 | + a.getTwin().setPrev(c_twin); |
| 67 | + |
| 68 | + c.setPrev(a); |
| 69 | + c_twin.setNext(a.getTwin()); |
| 70 | + |
| 71 | + // update face |
| 72 | + c.setFace(a.getFace()); |
| 73 | + c_twin.setFace(a.getTwin().getFace()); |
| 74 | + } |
| 75 | + // case 2: a has a next -> locate the proper incident edges to pre/append c |
| 76 | + else if (a.getNext() != null) { |
| 77 | + // use a.twin to make it simpler. likewise, use c_twin |
| 78 | + // means we have to start from a.twin and not a.twin.next |
| 79 | + HalfEdge tmp = a.getTwin(); |
| 80 | + HalfEdge ccw = tmp; |
| 81 | + boolean foundCCW = false; |
| 82 | + |
| 83 | + // stop if the next edge is a.twin |
| 84 | + do { |
| 85 | + boolean edgeIsCCW = isCCW(c_twin, tmp); |
| 86 | + if (foundCCW && !edgeIsCCW) break; |
| 87 | + else if (edgeIsCCW) { |
| 88 | + foundCCW = true; |
| 89 | + // break if the new edge is to the right of our previous ccw edge |
| 90 | + if (rightOf(ccw.getOrigin(), ccw.getDestination(), tmp.getDestination())) break; |
| 91 | + ccw = tmp; |
| 92 | + } |
| 93 | + |
| 94 | + // have to break because we're using do-while |
| 95 | + if (tmp.getTwin().getNext() == null) break; |
| 96 | + tmp = tmp.getTwin().getNext(); |
| 97 | + } while (tmp != a.getTwin()); |
| 98 | + |
| 99 | + tmp = a.getTwin(); |
| 100 | + HalfEdge cw = null; |
| 101 | + boolean foundCW = false; |
| 102 | + |
| 103 | + // stop if the next edge is a.twin.prev, since we handle a.twin in the while loop |
| 104 | + do { |
| 105 | + boolean edgeIsCW = !isCCW(c_twin, tmp); |
| 106 | + if (foundCW && !edgeIsCW) break; |
| 107 | + else if (edgeIsCW) { |
| 108 | + foundCW = true; |
| 109 | + // break if the new edge is to the left of our previous cw edge |
| 110 | + if (cw != null && leftOf(cw.getOrigin(), cw.getDestination(), tmp.getDestination())) break; |
| 111 | + cw = tmp; |
| 112 | + } |
| 113 | + |
| 114 | + // have to break because we're using do-while |
| 115 | + if (tmp.getTwin().getNext() == null) break; |
| 116 | + tmp = tmp.getTwin().getNext(); |
| 117 | + } while (tmp != a.getTwin()); |
| 118 | + |
| 119 | + assert cw != null; |
| 120 | + assert ccw != null; |
| 121 | + // handle cw - set proper faces later |
| 122 | + c.setPrev(cw.getTwin()); |
| 123 | + cw.getTwin().setNext(c); |
| 124 | + |
| 125 | + // handle ccw - set proper faces later |
| 126 | + c_twin.setNext(ccw); |
| 127 | + ccw.setPrev(c_twin); |
75 | 128 | }
|
76 |
| - if (b.getPrev() != null) { |
77 |
| - c_twin.setPrev(b.getPrev()); |
78 |
| - b.getPrev().setNext(c_twin); |
79 |
| - } else if (c.getNext() != null){ |
80 |
| - c_twin.setPrev(c.getNext().getTwin()); |
81 |
| - c.getNext().getTwin().setNext(c_twin); |
| 129 | + |
| 130 | + // Handling b |
| 131 | + |
| 132 | + // case 1: b has no prev -> c can be tacked on easily |
| 133 | + if (b.getPrev() == null) { |
| 134 | + b.setPrev(c); |
| 135 | + b.getTwin().setNext(c_twin); |
| 136 | + |
| 137 | + c.setNext(b); |
| 138 | + c_twin.setPrev(b.getTwin()); |
| 139 | + c.setFace(b.getFace()); // c shares the same face as b |
| 140 | + c_twin.setFace(b.getTwin().getFace()); // c twin shares same face with b twin |
82 | 141 | }
|
83 |
| - // update a and b's prev/next |
84 |
| - a.setNext(c); |
85 |
| - b.setPrev(c); |
86 |
| - // set faces |
87 |
| - HalfEdge tmp = c.getNext(); |
88 |
| - int direction = 1; // 1 == next |
89 |
| - while (true) { |
90 |
| - if (tmp == c) break; |
91 |
| - if (tmp == null && direction == 1) { |
92 |
| - // this means the face is not closed, so we have to start over |
93 |
| - direction = 0; |
94 |
| - tmp = c.getPrev(); |
95 |
| - if (tmp == null) break; |
96 |
| - } else if (tmp == null) { |
97 |
| - break; |
| 142 | + // case 2: b has a prev -> we need to locate the edges CCW and CW from c if they exist |
| 143 | + else if (b.getPrev() != null) { |
| 144 | + HalfEdge tmp = b; |
| 145 | + HalfEdge ccw = tmp; |
| 146 | + boolean foundCCW = false; |
| 147 | + // locate CCW edge by looking at incident edges |
| 148 | + do { |
| 149 | + boolean edgeIsCCW = isCCW(c, tmp); |
| 150 | + if (foundCCW && !edgeIsCCW) { |
| 151 | + // we found the CCW edge |
| 152 | + break; |
| 153 | + } else if (edgeIsCCW) { |
| 154 | + foundCCW = true; |
| 155 | + // break if the new edge is to the right of our previous ccw edge |
| 156 | + if (rightOf(ccw.getOrigin(), ccw.getDestination(), tmp.getDestination())) break; |
| 157 | + ccw = tmp; |
| 158 | + } |
| 159 | + // have to break because we're using do-while |
| 160 | + if (tmp.getTwin().getNext() == null) break; |
| 161 | + tmp = tmp.getTwin().getNext(); |
98 | 162 | }
|
99 |
| - tmp.setFace(c_face); |
100 |
| - tmp = direction == 1 ? tmp.getNext() : tmp.getPrev(); |
| 163 | + while (tmp != null && tmp.getTwin().getNext() != null && tmp != b); |
| 164 | + |
| 165 | + tmp = b; |
| 166 | + HalfEdge cw = tmp; |
| 167 | + boolean foundCW = false; |
| 168 | + // locate CW edge by looking at incident edges |
| 169 | + do { |
| 170 | + boolean edgeIsCW = !isCCW(c, tmp); |
| 171 | + if (foundCW && !edgeIsCW) { |
| 172 | + // we found the CW edge |
| 173 | + break; |
| 174 | + } else if (edgeIsCW) { |
| 175 | + foundCW = true; |
| 176 | + // break if the new edge is to the left of our previous ccw edge |
| 177 | + if (leftOf(cw.getOrigin(), cw.getDestination(), tmp.getDestination())) break; |
| 178 | + cw = tmp; |
| 179 | + } |
| 180 | + // have to break because we're using do-while |
| 181 | + if (tmp.getPrev() == null) break; |
| 182 | + tmp = tmp.getPrev().getTwin(); |
| 183 | + } while (tmp != null && tmp.getPrev() != null && tmp != b); |
| 184 | + assert ccw != null; |
| 185 | + assert cw != null; |
| 186 | + |
| 187 | + // handle ccw - set proper faces later |
| 188 | + c.setNext(ccw); |
| 189 | + ccw.setPrev(c); |
| 190 | + |
| 191 | + // handle cw - set proper faces later |
| 192 | + c_twin.setPrev(cw.getTwin()); |
| 193 | + cw.getTwin().setNext(c_twin); |
101 | 194 | }
|
102 | 195 |
|
103 |
| - tmp = c_twin.getNext(); |
104 |
| - direction = 1; // 1 == next |
105 |
| - while (true) { |
106 |
| - if (tmp == c_twin) break; |
107 |
| - if (tmp == null && direction == 1) { |
108 |
| - // this means the face is not closed, so we have to start over |
109 |
| - direction = 0; |
110 |
| - tmp = c_twin.getPrev(); |
111 |
| - if (tmp == null) break; |
112 |
| - } else if (tmp == null) { |
113 |
| - break; |
| 196 | + // only update faces if we created a new one |
| 197 | + if (a.getNext() != null || b.getPrev() != null) { |
| 198 | + // handle faces by traversing the edges and updating the face |
| 199 | + Face c_face = createFace(c); |
| 200 | + c.setFace(c_face); |
| 201 | + HalfEdge tmp = c.getNext(); |
| 202 | + while (tmp != null && tmp != c) { |
| 203 | + tmp.setFace(c_face); |
| 204 | + tmp = tmp.getNext(); |
| 205 | + } |
| 206 | + |
| 207 | + Face c_twin_face = createFace(c_twin); |
| 208 | + c_twin.setFace(c_twin_face); |
| 209 | + tmp = c_twin.getNext(); |
| 210 | + while (tmp != null && tmp != c_twin) { |
| 211 | + tmp.draw(scene, 0, Color.CYAN); |
| 212 | + scene.repaint(); |
| 213 | + tmp.setFace(c_twin_face); |
| 214 | + tmp = tmp.getNext(); |
114 | 215 | }
|
115 |
| - tmp.setFace(c_twin_face); |
116 |
| - tmp = direction == 1 ? tmp.getNext() : tmp.getPrev(); |
117 | 216 | }
|
118 | 217 |
|
119 |
| - //scene.removeAllShapes(); |
120 |
| - c_face.draw(scene); |
| 218 | + c.getFace().draw(scene); |
121 | 219 | scene.repaint();
|
| 220 | + /*try { |
| 221 | + scene.removeAllShapes(); |
| 222 | + scene.repaint(); |
| 223 | + c.getFace().draw(scene); |
| 224 | + scene.repaint(); |
| 225 | + sleep(5000); |
| 226 | +
|
| 227 | + scene.removeAllShapes(); |
| 228 | + scene.repaint(); |
| 229 | + sleep(1000); |
| 230 | + c_twin.getFace().draw(scene); |
| 231 | + scene.repaint(); |
| 232 | + sleep(5000); |
| 233 | + } catch (Exception e) {}*/ |
122 | 234 | //scene.removeAllShapes();
|
123 | 235 | return c;
|
124 | 236 | }
|
|
0 commit comments