21 #include <unordered_map> 23 #include "PriorityQueue.h" 25 #include "Beachline.h" 43 class FortuneAlgorithm
67 for (
auto i = std::size_t(0); i < mDiagram.getNbSites(); ++i)
68 mEvents.push(std::make_unique<Event<T>>(mDiagram.getSite(i)));
71 while (!mEvents.isEmpty())
73 auto event = mEvents.pop();
74 mBeachlineY =
event->y;
75 if (event->type == Event<T>::Type::Site)
76 handleSiteEvent(event.get());
78 handleCircleEvent(event.get());
99 for (
const auto& vertex : mDiagram.getVertices())
101 box.
left = std::min(vertex.point.x, box.
left);
103 box.
right = std::max(vertex.point.x, box.
right);
104 box.
top = std::max(vertex.point.y, box.
top);
107 auto linkedVertices = std::list<LinkedVertex>();
108 auto vertices = VerticeOnFrontierContainer(mDiagram.getNbSites());
109 if (!mBeachline.isEmpty())
111 auto arc = mBeachline.getLeftmostArc();
112 while (!mBeachline.isNil(arc->next))
114 success = boundEdge(box, arc, arc->next, linkedVertices, vertices) && success;
119 for (
auto& kv : vertices)
120 success = addCorners(box, linkedVertices, kv.second) && success;
122 for (
auto& kv : vertices)
123 joinHalfEdges(kv.first, kv.second);
137 return std::move(mDiagram);
142 Beachline<T> mBeachline;
143 PriorityQueue<Event<T>> mEvents;
148 void handleSiteEvent(Event<T>* event)
150 auto site =
event->site;
152 if (mBeachline.isEmpty())
154 mBeachline.setRoot(mBeachline.createArc(site));
158 auto arcToBreak = mBeachline.locateArcAbove(site->point, mBeachlineY);
159 deleteEvent(arcToBreak);
161 auto middleArc = breakArc(arcToBreak, site);
162 auto leftArc = middleArc->prev;
163 auto rightArc = middleArc->next;
165 addEdge(leftArc, middleArc);
166 middleArc->rightHalfEdge = middleArc->leftHalfEdge;
167 rightArc->leftHalfEdge = leftArc->rightHalfEdge;
170 if (!mBeachline.isNil(leftArc->prev))
171 addEvent(leftArc->prev, leftArc, middleArc);
173 if (!mBeachline.isNil(rightArc->next))
174 addEvent(middleArc, rightArc, rightArc->next);
177 void handleCircleEvent(Event<T>* event)
179 auto point =
event->point;
180 auto arc =
event->arc;
182 auto vertex = mDiagram.createVertex(point);
184 auto leftArc = arc->prev;
185 auto rightArc = arc->next;
186 deleteEvent(leftArc);
187 deleteEvent(rightArc);
189 removeArc(arc, vertex);
192 if (!mBeachline.isNil(leftArc->prev))
193 addEvent(leftArc->prev, leftArc, rightArc);
195 if (!mBeachline.isNil(rightArc->next))
196 addEvent(leftArc, rightArc, rightArc->next);
204 auto middleArc = mBeachline.createArc(site);
205 auto leftArc = mBeachline.createArc(arc->site, Arc<T>::Side::Left);
206 leftArc->leftHalfEdge = arc->leftHalfEdge;
207 auto rightArc = mBeachline.createArc(arc->site, Arc<T>::Side::Right);
208 rightArc->rightHalfEdge = arc->rightHalfEdge;
210 mBeachline.replace(arc, middleArc);
211 mBeachline.insertBefore(middleArc, leftArc);
212 mBeachline.insertAfter(middleArc, rightArc);
222 setDestination(arc->prev, arc, vertex);
223 setDestination(arc, arc->next, vertex);
225 arc->leftHalfEdge->next = arc->rightHalfEdge;
226 arc->rightHalfEdge->prev = arc->leftHalfEdge;
228 mBeachline.remove(arc);
230 auto prevHalfEdge = arc->prev->rightHalfEdge;
231 auto nextHalfEdge = arc->next->leftHalfEdge;
232 addEdge(arc->prev, arc->next);
233 setOrigin(arc->prev, arc->next, vertex);
234 setPrevHalfEdge(arc->prev->rightHalfEdge, prevHalfEdge);
235 setPrevHalfEdge(nextHalfEdge, arc->next->leftHalfEdge);
242 bool isMovingRight(
const Arc<T>* left,
const Arc<T>* right)
const 244 return left->site->point.y < right->site->point.y;
247 T getInitialX(
const Arc<T>* left,
const Arc<T>* right,
bool movingRight)
const 249 return movingRight ? left->site->point.x : right->site->point.x;
254 void addEdge(Arc<T>* left, Arc<T>* right)
257 left->rightHalfEdge = mDiagram.createHalfEdge(left->site->face);
258 right->leftHalfEdge = mDiagram.createHalfEdge(right->site->face);
260 left->rightHalfEdge->twin = right->leftHalfEdge;
261 right->leftHalfEdge->twin = left->rightHalfEdge;
266 left->rightHalfEdge->destination = vertex;
267 right->leftHalfEdge->origin = vertex;
272 left->rightHalfEdge->origin = vertex;
273 right->leftHalfEdge->destination = vertex;
284 void addEvent(Arc<T>* left, Arc<T>* middle, Arc<T>* right)
287 auto convergencePoint = computeConvergencePoint(left->site->point, middle->site->point, right->site->point, y);
289 if (!almostLower(y, mBeachlineY))
294 auto leftBreakpointMovingRight = isMovingRight(left, middle);
295 auto rightBreakpointMovingRight = isMovingRight(middle, right);
296 auto leftInitialX = getInitialX(left, middle, leftBreakpointMovingRight);
297 auto rightInitialX = getInitialX(middle, right, rightBreakpointMovingRight);
298 if (!(!leftBreakpointMovingRight && rightBreakpointMovingRight) &&
299 ((leftBreakpointMovingRight && almostLower(leftInitialX, convergencePoint.x)) ||
300 (!leftBreakpointMovingRight && almostGreater(leftInitialX, convergencePoint.x))) &&
301 ((rightBreakpointMovingRight && almostLower(rightInitialX, convergencePoint.x)) ||
302 (!rightBreakpointMovingRight && almostGreater(rightInitialX, convergencePoint.x))))
304 auto event = std::make_unique<Event<T>>(y, convergencePoint, middle);
305 middle->event =
event.get();
306 mEvents.push(std::move(event));
310 void deleteEvent(Arc<T>* arc)
312 if (arc->event !=
nullptr)
314 mEvents.remove(arc->event->index);
315 arc->event =
nullptr;
321 auto v1 = (point1 - point2).getOrthogonal();
322 auto v2 = (point2 - point3).getOrthogonal();
323 auto delta =
static_cast<T
>(0.5) * (point3 - point1);
324 auto denom = v1.getDet(v2);
326 if (almostZero(denom))
329 y = std::numeric_limits<T>::infinity();
333 auto t = delta.
getDet(v2) / denom;
334 auto center =
static_cast<T
>(0.5) * (point1 + point2) + t * v1;
349 using VerticeOnFrontierContainer = std::unordered_map<std::size_t, std::array<LinkedVertex*, 8>>;
351 bool boundEdge(
const Box<T>& box, Arc<T>* leftArc, Arc<T>* rightArc, std::list<LinkedVertex>& linkedVertices,
352 VerticeOnFrontierContainer& vertices)
356 auto direction = (leftArc->site->point - rightArc->site->point).getOrthogonal();
357 auto origin = (leftArc->site->point + rightArc->site->point) * static_cast<T>(0.5);
359 auto intersection = box.getFirstIntersection(origin, direction);
361 auto vertex = mDiagram.createVertex(intersection.point);
362 setDestination(leftArc, rightArc, vertex);
364 if (vertices.find(leftArc->site->index) == vertices.end())
365 vertices[leftArc->site->index].fill(
nullptr);
366 if (vertices.find(rightArc->site->index) == vertices.end())
367 vertices[rightArc->site->index].fill(
nullptr);
369 success = vertices[leftArc->site->index][2 *
static_cast<int>(intersection.side) + 1] ==
nullptr && success;
370 success = vertices[rightArc->site->index][2 *
static_cast<int>(intersection.side)] ==
nullptr && success;
372 linkedVertices.emplace_back(LinkedVertex{
nullptr, vertex, leftArc->rightHalfEdge});
373 vertices[leftArc->site->index][2 *
static_cast<int>(intersection.side) + 1] = &linkedVertices.back();
374 linkedVertices.emplace_back(LinkedVertex{rightArc->leftHalfEdge, vertex,
nullptr});
375 vertices[rightArc->site->index][2 *
static_cast<int>(intersection.side)] = &linkedVertices.back();
380 bool addCorners(
const Box<T>& box, std::list<LinkedVertex>& linkedVertices, std::array<LinkedVertex*, 8>& cellVertices)
384 for (
auto i = std::size_t(0); i < 5; ++i)
387 auto nextSide = (side + 1) % 4;
389 if (cellVertices[2 * side] ==
nullptr && cellVertices[2 * side + 1] !=
nullptr)
391 auto prevSide = (side + 3) % 4;
392 auto corner = mDiagram.createCorner(box,
static_cast<typename Box<T>::Side
>(side));
393 linkedVertices.emplace_back(LinkedVertex{
nullptr, corner,
nullptr});
395 success = cellVertices[2 * prevSide + 1] ==
nullptr && success;
397 cellVertices[2 * prevSide + 1] = &linkedVertices.back();
398 cellVertices[2 * side] = &linkedVertices.back();
401 else if (cellVertices[2 * side] !=
nullptr && cellVertices[2 * side + 1] ==
nullptr)
403 auto corner = mDiagram.createCorner(box,
static_cast<typename Box<T>::Side
>(nextSide));
404 linkedVertices.emplace_back(LinkedVertex{
nullptr, corner,
nullptr});
406 success = cellVertices[2 * nextSide] ==
nullptr && success;
408 cellVertices[2 * side + 1] = &linkedVertices.back();
409 cellVertices[2 * nextSide] = &linkedVertices.back();
416 void joinHalfEdges(std::size_t i, std::array<LinkedVertex*, 8>& cellVertices)
418 for (
auto side = std::size_t(0); side < 4; ++side)
423 if (cellVertices[2 * side] !=
nullptr)
426 auto halfEdge = mDiagram.createHalfEdge(mDiagram.
getFace(i));
427 halfEdge->origin = cellVertices[2 * side]->vertex;
428 halfEdge->destination = cellVertices[2 * side + 1]->vertex;
429 cellVertices[2 * side]->nextHalfEdge = halfEdge;
430 halfEdge->prev = cellVertices[2 * side]->prevHalfEdge;
431 if (cellVertices[2 * side]->prevHalfEdge !=
nullptr)
432 cellVertices[2 * side]->prevHalfEdge->next = halfEdge;
433 cellVertices[2 * side + 1]->prevHalfEdge = halfEdge;
434 halfEdge->next = cellVertices[2 * side + 1]->nextHalfEdge;
435 if (cellVertices[2 * side + 1]->nextHalfEdge !=
nullptr)
436 cellVertices[2 * side + 1]->nextHalfEdge->prev = halfEdge;
Data structure representing a partitioning of the space.
bool bound(Box< T > box)
Bound the Voronoi diagram.
Class representing a box.
Class representing a 2D vector.
FortuneAlgorithm(std::vector< Vector2< T >> points)
Constructor of FortuneAlgorithm.
T getDistance(const Vector2< T > &other) const
Compute the euclidean distance of this point to another point.
void construct()
Execute Fortune's algorithm to construct the diagram.
T getDet(const Vector2< T > &other) const
Compute the determinant with another vector.
const Face * getFace(std::size_t i) const
Get a face.
Point associated with a face of the partitioning.
Diagram< T > getDiagram()
Return the constructed diagram.