Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
connector.cpp
Go to the documentation of this file.
1/*
2 * vim: ts=4 sw=4 et tw=0 wm=0
3 *
4 * libavoid - Fast, Incremental, Object-avoiding Line Router
5 *
6 * Copyright (C) 2004-2014 Monash University
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 * See the file LICENSE.LGPL distributed with the library.
13 *
14 * Licensees holding a valid commercial license may use this file in
15 * accordance with the commercial license agreement provided with the
16 * library.
17 *
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 *
22 * Author(s): Michael Wybrow
23*/
24
25
26#include <cstring>
27#include <cfloat>
28#include <cmath>
29#include <cstdlib>
30#include <algorithm>
31#include <queue>
32#include <limits>
33
34#include "libavoid/connector.h"
35#include "libavoid/connend.h"
36#include "libavoid/router.h"
37#include "libavoid/visibility.h"
38#include "libavoid/debug.h"
39#include "libavoid/assertions.h"
40#include "libavoid/junction.h"
41#include "libavoid/makepath.h"
43
44
45namespace Avoid {
46
47
48ConnRef::ConnRef(Router *router, const unsigned int id)
49 : m_router(router),
50 m_type(router->validConnType()),
51 m_reroute_flag_ptr(nullptr),
52 m_needs_reroute_flag(true),
53 m_false_path(false),
54 m_needs_repaint(false),
55 m_active(false),
56 m_hate_crossings(false),
57 m_has_fixed_route(false),
58 m_route_dist(0),
59 m_src_vert(nullptr),
60 m_dst_vert(nullptr),
61 m_start_vert(nullptr),
62 m_callback_func(nullptr),
63 m_connector(nullptr),
64 m_src_connend(nullptr),
65 m_dst_connend(nullptr)
66{
67 COLA_ASSERT(m_router != nullptr);
68 m_id = m_router->assignId(id);
69
70 // TODO: Store endpoints and details.
71 m_route.clear();
72
74}
75
76
77ConnRef::ConnRef(Router *router, const ConnEnd& src, const ConnEnd& dst,
78 const unsigned int id)
79 : m_router(router),
80 m_type(router->validConnType()),
81 m_reroute_flag_ptr(nullptr),
82 m_needs_reroute_flag(true),
83 m_false_path(false),
84 m_needs_repaint(false),
85 m_active(false),
86 m_hate_crossings(false),
87 m_has_fixed_route(false),
88 m_route_dist(0),
89 m_src_vert(nullptr),
90 m_dst_vert(nullptr),
91 m_callback_func(nullptr),
92 m_connector(nullptr),
93 m_src_connend(nullptr),
94 m_dst_connend(nullptr)
95{
96 COLA_ASSERT(m_router != nullptr);
97 m_id = m_router->assignId(id);
98 m_route.clear();
99
100 // Set endpoint values.
102
104}
105
106
108{
109 COLA_ASSERT(m_router);
110
112 {
113 err_printf("ERROR: ConnRef::~ConnRef() shouldn't be called directly.\n");
114 err_printf(" It is owned by the router. Call Router::deleteConnector() instead.\n");
115 abort();
116 }
117
119
121
122 freeRoutes();
123
124 if (m_src_vert)
125 {
128 delete m_src_vert;
129 m_src_vert = nullptr;
130 }
131 if (m_src_connend)
132 {
135 delete m_src_connend;
136 m_src_connend = nullptr;
137 }
138
139 if (m_dst_vert)
140 {
143 delete m_dst_vert;
144 m_dst_vert = nullptr;
145 }
146 if (m_dst_connend)
147 {
150 delete m_dst_connend;
151 m_dst_connend = nullptr;
152 }
153
154 // Clear checkpoint vertices.
155 for (size_t i = 0; i < m_checkpoint_vertices.size(); ++i)
156 {
157 m_checkpoint_vertices[i]->removeFromGraph(true);
159 delete m_checkpoint_vertices[i];
160 }
161 m_checkpoint_vertices.clear();
162
163 if (m_active)
164 {
165 makeInactive();
166 }
167}
168
169
171{
172 return m_type;
173}
174
175
177{
178 type = m_router->validConnType(type);
179 if (m_type != type)
180 {
181 m_type = type;
182
184
186 }
187}
188
189
190std::vector<Checkpoint> ConnRef::routingCheckpoints(void) const
191{
192 return m_checkpoints;
193}
194
195
196void ConnRef::setRoutingCheckpoints(const std::vector<Checkpoint>& checkpoints)
197{
198 m_checkpoints = checkpoints;
199
200 // Clear previous checkpoint vertices.
201 for (size_t i = 0; i < m_checkpoint_vertices.size(); ++i)
202 {
203 m_checkpoint_vertices[i]->removeFromGraph(true);
205 delete m_checkpoint_vertices[i];
206 }
207 m_checkpoint_vertices.clear();
208
209 for (size_t i = 0; i < m_checkpoints.size(); ++i)
210 {
211 VertID ptID(m_id, 2 + i,
213 VertInf *vertex = new VertInf(m_router, ptID, m_checkpoints[i].point);
214 vertex->visDirections = ConnDirAll;
215
216 m_checkpoint_vertices.push_back(vertex);
217 }
219 {
220 for (size_t i = 0; i < m_checkpoints.size(); ++i)
221 {
222 vertexVisibility(m_checkpoint_vertices[i], nullptr, true, true);
223 }
224 }
225}
226
227
228void ConnRef::common_updateEndPoint(const unsigned int type, ConnEnd connEnd)
229{
230 const Point& point = connEnd.position();
231 //db_printf("common_updateEndPoint(%d,(pid=%d,vn=%d,(%f,%f)))\n",
232 // type,point.id,point.vn,point.x,point.y);
233 COLA_ASSERT((type == (unsigned int) VertID::src) ||
234 (type == (unsigned int) VertID::tar));
235
236 // The connEnd is a copy of a ConnEnd that will get disconnected,
237 // so don't leave it looking like it is still connected.
238 connEnd.m_conn_ref = nullptr;
239
240 if (!m_active)
241 {
242 makeActive();
243 }
244
245 VertInf *altered = nullptr;
246
248 if (connEnd.isPinConnection())
249 {
250 properties |= VertID::PROP_DummyPinHelper;
251 }
252 VertID ptID(m_id, type, properties);
253 if (type == (unsigned int) VertID::src)
254 {
255 if (m_src_vert)
256 {
257 m_src_vert->Reset(ptID, point);
258 }
259 else
260 {
261 m_src_vert = new VertInf(m_router, ptID, point);
262 }
264
265 if (m_src_connend)
266 {
269 delete m_src_connend;
270 m_src_connend = nullptr;
271 }
272 if (connEnd.isPinConnection())
273 {
274 m_src_connend = new ConnEnd(connEnd);
275 m_src_connend->connect(this);
276 // Don't need this to have visibility since we won't
277 // be connecting to it.
279 }
280
281 altered = m_src_vert;
282 }
283 else // if (type == (unsigned int) VertID::tar)
284 {
285 if (m_dst_vert)
286 {
287 m_dst_vert->Reset(ptID, point);
288 }
289 else
290 {
291 m_dst_vert = new VertInf(m_router, ptID, point);
292 }
294
295 if (m_dst_connend)
296 {
299 delete m_dst_connend;
300 m_dst_connend = nullptr;
301 }
302 if (connEnd.isPinConnection())
303 {
304 m_dst_connend = new ConnEnd(connEnd);
305 m_dst_connend->connect(this);
306 // Don't need this to have visibility since we won't
307 // be connecting to it.
309 }
310
311 altered = m_dst_vert;
312 }
313
314 // XXX: Seems to be faster to just remove the edges and recreate
315 bool isConn = true;
316 altered->removeFromGraph(isConn);
317
320}
321
322
323void ConnRef::setEndpoints(const ConnEnd& srcPoint, const ConnEnd& dstPoint)
324{
325 m_router->modifyConnector(this, VertID::src, srcPoint);
326 m_router->modifyConnector(this, VertID::tar, dstPoint);
327}
328
329
330void ConnRef::setEndpoint(const unsigned int type, const ConnEnd& connEnd)
331{
332 m_router->modifyConnector(this, type, connEnd);
333}
334
335
337{
338 m_router->modifyConnector(this, VertID::src, srcPoint);
339}
340
341
343{
344 m_router->modifyConnector(this, VertID::tar, dstPoint);
345}
346
347
348// Given the start or end vertex of a connector, returns the ConnEnd that
349// can be used to reproduce that endpoint. This is used for hyperedge routing.
350//
352 ConnEnd& connEnd) const
353{
354 if (vertex == nullptr)
355 {
356 err_printf("Warning: In ConnRef::getConnEndForEndpointVertex():\n"
357 " ConnEnd for connector %d is uninitialised. It may have been\n"
358 " set but Router::processTrancaction has not yet been called.\n",
359 (int) id());
360 return false;
361 }
362
363 if (vertex == m_src_vert)
364 {
365 if (m_src_connend)
366 {
367 connEnd = *m_src_connend;
368 }
369 else
370 {
373 }
374 return true;
375 }
376 else if (vertex == m_dst_vert)
377 {
378 if (m_dst_connend)
379 {
380 connEnd = *m_dst_connend;
381 }
382 else
383 {
386 }
387 return true;
388 }
389 return false;
390}
391
392
393void ConnRef::updateEndPoint(const unsigned int type, const ConnEnd& connEnd)
394{
395 common_updateEndPoint(type, connEnd);
396
398 {
399 // Don't need to continue and compute visibility if route is fixed.
400 return;
401 }
402
404 {
405 bool knownNew = true;
406 bool genContains = true;
407 if (type == (unsigned int) VertID::src)
408 {
409 bool dummySrc = m_src_connend && m_src_connend->isPinConnection();
410 if (!dummySrc)
411 {
412 // Only generate visibility if not attached to a pin.
413 vertexVisibility(m_src_vert, m_dst_vert, knownNew, genContains);
414 }
415 }
416 else
417 {
418 bool dummyDst = m_dst_connend && m_dst_connend->isPinConnection();
419 if (!dummyDst)
420 {
421 // Only generate visibility if not attached to a pin.
422 vertexVisibility(m_dst_vert, m_src_vert, knownNew, genContains);
423 }
424 }
425 }
426}
427
428
429void ConnRef::outputCode(FILE *fp) const
430{
431 fprintf(fp, " // connRef%u\n", id());
432 fprintf(fp, " connRef = new ConnRef(router, %u);\n", id());
433 if (m_src_connend)
434 {
435 m_src_connend->outputCode(fp, "src");
436 fprintf(fp, " connRef->setSourceEndpoint(srcPt);\n");
437 }
438 else if (src())
439 {
440 fprintf(fp, " srcPt = ConnEnd(Point(%" PREC "g, %" PREC "g), %u);\n",
441 src()->point.x, src()->point.y, src()->visDirections);
442 fprintf(fp, " connRef->setSourceEndpoint(srcPt);\n");
443 }
444 if (m_dst_connend)
445 {
446 m_dst_connend->outputCode(fp, "dst");
447 fprintf(fp, " connRef->setDestEndpoint(dstPt);\n");
448 }
449 else if (dst())
450 {
451 fprintf(fp, " dstPt = ConnEnd(Point(%" PREC "g, %" PREC "g), %u);\n",
452 dst()->point.x, dst()->point.y, dst()->visDirections);
453 fprintf(fp, " connRef->setDestEndpoint(dstPt);\n");
454 }
455 fprintf(fp, " connRef->setRoutingType((ConnType)%u);\n", routingType());
456
458 {
459 PolyLine currRoute = route();
460 fprintf(fp, " newRoute._id = %u;\n", id());
461 fprintf(fp, " newRoute.ps.resize(%d);\n", (int)currRoute.size());
462 for (size_t i = 0; i < currRoute.size(); ++i)
463 {
464 fprintf(fp, " newRoute.ps[%d] = Point(%" PREC "g, %" PREC "g);\n",
465 (int) i, currRoute.ps[i].x, currRoute.ps[i].y);
466 fprintf(fp, " newRoute.ps[%d].id = %u;\n",
467 (int) i, currRoute.ps[i].id);
468 fprintf(fp, " newRoute.ps[%d].vn = %u;\n",
469 (int) i, currRoute.ps[i].vn);
470 }
471 fprintf(fp, " connRef->setFixedRoute(newRoute);\n");
472 }
473
474 if (!m_checkpoints.empty())
475 {
476 fprintf(fp, " std::vector<Checkpoint> checkpoints%u(%d);\n", id(),
477 (int) m_checkpoints.size());
478 for (size_t cInd = 0; cInd < m_checkpoints.size(); ++cInd)
479 {
480 fprintf(fp, " checkpoints%u[%d] = Checkpoint(Point("
481 "%" PREC "g, %" PREC "g), (ConnDirFlags) %d, "
482 "(ConnDirFlags) %d);\n", id(), (int) cInd,
483 m_checkpoints[cInd].point.x, m_checkpoints[cInd].point.y,
484 m_checkpoints[cInd].arrivalDirections,
485 m_checkpoints[cInd].departureDirections);
486 }
487 fprintf(fp, " connRef->setRoutingCheckpoints(checkpoints%u);\n",
488 id());
489 }
490 fprintf(fp, "\n");
491}
492
493
494std::pair<Obstacle *, Obstacle *> ConnRef::endpointAnchors(void) const
495{
496 std::pair<Obstacle *, Obstacle *> anchors;
497 anchors.first = nullptr;
498 anchors.second = nullptr;
499
500 if (m_src_connend)
501 {
502 anchors.first = m_src_connend->m_anchor_obj;
503 }
504 if (m_dst_connend)
505 {
506 anchors.second = m_dst_connend->m_anchor_obj;
507 }
508 return anchors;
509}
510
511std::pair<ConnEnd, ConnEnd> ConnRef::endpointConnEnds(void) const
512{
513 std::pair<ConnEnd, ConnEnd> endpoints;
514 getConnEndForEndpointVertex(m_src_vert, endpoints.first);
515 getConnEndForEndpointVertex(m_dst_vert, endpoints.second);
516 return endpoints;
517}
518
519bool ConnRef::setEndpoint(const unsigned int type, const VertID& pointID,
520 Point *pointSuggestion)
521{
522 VertInf *vInf = m_router->vertices.getVertexByID(pointID);
523 if (vInf == nullptr)
524 {
525 return false;
526 }
527 Point& point = vInf->point;
528 if (pointSuggestion)
529 {
530 if (euclideanDist(point, *pointSuggestion) > 0.5)
531 {
532 return false;
533 }
534 }
535
536 common_updateEndPoint(type, point);
537
538 // Give this visibility just to the point it is over.
539 EdgeInf *edge = new EdgeInf(
540 (type == VertID::src) ? m_src_vert : m_dst_vert, vInf);
541 // XXX: We should be able to set this to zero, but can't due to
542 // assumptions elsewhere in the code.
543 edge->setDist(0.001);
544
546 return true;
547}
548
549
551{
552 COLA_ASSERT(!m_active);
553
554 // Add to connRefs list.
555 m_connrefs_pos = m_router->connRefs.insert(m_router->connRefs.begin(), this);
556 m_active = true;
557}
558
559
561{
562 if (m_src_connend)
563 {
565 }
566 if (m_dst_connend)
567 {
569 }
570}
571
572
574{
575 COLA_ASSERT(m_active);
576
577 // Remove from connRefs list.
579 m_active = false;
580}
581
582
584{
585 m_route.clear();
587}
588
589
590const PolyLine& ConnRef::route(void) const
591{
592 return m_route;
593}
594
595
597{
598 return m_route;
599}
600
601
602void ConnRef::set_route(const PolyLine& route)
603{
604 if (&m_display_route == &route)
605 {
606 db_printf("Error:\tTrying to update libavoid route with itself.\n");
607 return;
608 }
610
611 //_display_route.clear();
612}
613
615{
616 COLA_ASSERT(m_route.size() >= 2);
617 m_has_fixed_route = true;
619}
620
622{
623 if (route.size() >= 2)
624 {
625 // Set endpoints based on the fixed route incase the
626 // fixed route is later cleared.
627 setEndpoints(route.ps[0], route.ps[route.size() - 1]);
628 }
629 m_has_fixed_route = true;
630 m_route = route;
633}
634
636{
637 return m_has_fixed_route;
638}
639
646
648{
650 {
651 // No displayRoute is set. Simplify the current route to get it.
653 }
654 return m_display_route;
655}
656
657
659{
660 double (*dist)(const Point& a, const Point& b) =
662
663 m_route_dist = 0;
664 for (size_t i = 1; i < m_route.size(); ++i)
665 {
666 m_route_dist += dist(m_route.at(i), m_route.at(i - 1));
667 }
668}
669
670
671bool ConnRef::needsRepaint(void) const
672{
673 return m_needs_repaint;
674}
675
676
677unsigned int ConnRef::id(void) const
678{
679 return m_id;
680}
681
682
684{
686
687 midpoint.x = (a.x + b.x) / 2.0;
688 midpoint.y = (a.y + b.y) / 2.0;
689
690 return midpoint;
691}
692
693
694std::pair<JunctionRef *, ConnRef *> ConnRef::splitAtSegment(
695 const size_t segmentN)
696{
697 ConnRef *newConn = nullptr;
698 JunctionRef *newJunction = nullptr;
699
700 if (m_display_route.size() > segmentN)
701 {
702 // Position the junction at the midpoint of the desired segment.
703 Point junctionPos = midpoint(m_display_route.at(segmentN - 1),
704 m_display_route.at(segmentN));
705
706 // Create the new junction.
707 newJunction = new JunctionRef(router(), junctionPos);
708 router()->addJunction(newJunction);
709 newJunction->preferOrthogonalDimension(
710 (m_display_route.at(segmentN - 1).x ==
711 m_display_route.at(segmentN).x) ? YDIM : XDIM);
712
713 // Create a new connection routing from the junction to the original
714 // connector's endpoint.
715 ConnEnd newConnSrc = ConnEnd(newJunction);
716 ConnEnd newConnDst = *m_dst_connend;
717 newConn = new ConnRef(router(), newConnSrc, newConnDst);
718
719 // Reroute the endpoint of the original connector to attach to the
720 // new junction.
721 ConnEnd oldConnDst = ConnEnd(newJunction);
722 this->setDestEndpoint(oldConnDst);
723 }
724
725 return std::make_pair(newJunction, newConn);
726}
727
728
730{
731 return m_src_vert;
732}
733
734
736{
737 return m_dst_vert;
738}
739
740
742{
743 return m_start_vert;
744}
745
746
748{
749 return m_active;
750}
751
752
759
760
762{
763 if (m_src_vert)
764 {
766 }
767
768 if (m_dst_vert)
769 {
771 }
772}
773
774
775void ConnRef::setCallback(void (*cb)(void *), void *ptr)
776{
777 m_callback_func = cb;
778 m_connector = ptr;
779}
780
781
783{
784 if (m_callback_func)
785 {
787 }
788}
789
790
792{
794}
795
796
798{
799 return m_router;
800}
801
802
803// Validates a bend point on a path to check it does not form a zigzag corner.
804// a, b, c are consecutive points on the path. d and e are b's neighbours,
805// forming the shape corner d-b-e.
806//
807bool validateBendPoint(VertInf *aInf, VertInf *bInf, VertInf *cInf)
808{
809 if (bInf->id.isConnectionPin() || bInf->id.isConnCheckpoint())
810 {
811 // We shouldn't check connection pins or checkpoints.
812 return true;
813 }
814 bool bendOkay = true;
815
816 if ((aInf == nullptr) || (cInf == nullptr))
817 {
818 // Not a bendpoint, i.e., the end of the connector, so don't test.
819 return bendOkay;
820 }
821
822 COLA_ASSERT(bInf != nullptr);
823 VertInf *dInf = bInf->shPrev;
824 VertInf *eInf = bInf->shNext;
825 COLA_ASSERT(dInf != nullptr);
826 COLA_ASSERT(eInf != nullptr);
827
828 Point& a = aInf->point;
829 Point& b = bInf->point;
830 Point& c = cInf->point;
831 Point& d = dInf->point;
832 Point& e = eInf->point;
833
834 if ((a == b) || (b == c))
835 {
836 return bendOkay;
837 }
838
839#ifdef PATHDEBUG
840 db_printf("a=(%g, %g)\n", a.x, a.y);
841 db_printf("b=(%g, %g)\n", b.x, b.y);
842 db_printf("c=(%g, %g)\n", c.x, c.y);
843 db_printf("d=(%g, %g)\n", d.x, d.y);
844 db_printf("e=(%g, %g)\n", e.x, e.y);
845#endif
846 // Check angle:
847 int abc = vecDir(a, b, c);
848#ifdef PATHDEBUG
849 db_printf("(abc == %d) ", abc);
850#endif
851
852 if (abc == 0)
853 {
854 // The three consecutive point on the path are in a line.
855 // There should always be an equally short path that skips this
856 // bend point, but this check is used during rubber-band routing
857 // so we allow this case.
858 bendOkay = true;
859 }
860 else // (abc != 0)
861 {
862 COLA_ASSERT(vecDir(d, b, e) > 0);
863 int abe = vecDir(a, b, e);
864 int abd = vecDir(a, b, d);
865 int bce = vecDir(b, c, e);
866 int bcd = vecDir(b, c, d);
867#ifdef PATHDEBUG
868 db_printf("&& (abe == %d) && (abd == %d) &&\n(bce == %d) && (bcd == %d)",
869 abe, abd, bce, bcd);
870#endif
871
872 bendOkay = false;
873 if (abe > 0)
874 {
875 if ((abc > 0) && (abd >= 0) && (bce >= 0))
876 {
877 bendOkay = true;
878 }
879 }
880 else if (abd < 0)
881 {
882 if ((abc < 0) && (abe <= 0) && (bcd <= 0))
883 {
884 bendOkay = true;
885 }
886 }
887 }
888#ifdef PATHDEBUG
889 db_printf("\n");
890#endif
891 return bendOkay;
892}
893
894
895std::pair<bool, bool> ConnRef::assignConnectionPinVisibility(const bool connect)
896{
897 // XXX This is kind of a hack for connection pins. Probably we want to
898 // not use m_src_vert and m_dst_vert. For the moment we will clear
899 // their visibility and give them visibility to the pins.
900 bool dummySrc = m_src_connend && m_src_connend->isPinConnection();
901 if (dummySrc)
902 {
904 if (connect)
905 {
907 }
908 }
909 bool dummyDst = m_dst_connend && m_dst_connend->isPinConnection();
910 if (dummyDst)
911 {
913 if (connect)
914 {
916 }
917 }
918
919 return std::make_pair(dummySrc, dummyDst);
920}
921
922
924{
925 // XXX Currently rubber-band routing only works when dragging the
926 // destination point of a connector, but not the source. The code
927 // needs to be reworked to work in both directions.
928
930 {
931 // This connector is up to date.
932 return false;
933 }
934
935 if (!m_dst_vert || !m_src_vert)
936 {
937 // Connector is not fully initialised.
938 return false;
939 }
940
941 //COLA_ASSERT(_srcVert->point != _dstVert->point);
942
943 m_false_path = false;
944 m_needs_reroute_flag = false;
945
947
948 // Some connectors may attach to connection pins, which means they route
949 // to the closest of multiple pins on a shape. How we handle this is to
950 // add a dummy vertex as the source or target vertex. This is then given
951 // visibility to each of the possible pins and tiny distance. Here we
952 // assign this visibility by adding edges to the visibility graph that we
953 // later remove.
954 std::pair<bool, bool> isDummyAtEnd = assignConnectionPinVisibility(true);
955
956
957 if (m_router->RubberBandRouting && route().size() > 0)
958 {
959 if (isDummyAtEnd.first)
960 {
961 //ShapeConnectionPin *activePin = m_src_connend->active
962 Point firstPoint = m_src_vert->point;
963 firstPoint.id = m_src_vert->id.objID;
964 firstPoint.vn = m_src_vert->id.vn;
965 PolyLine& existingRoute = routeRef();
966 existingRoute.ps.insert(existingRoute.ps.begin(), 1, firstPoint);
967 }
968 }
969
970 std::vector<Point> path;
971 std::vector<VertInf *> vertices;
972 if (m_checkpoints.empty())
973 {
974 generateStandardPath(path, vertices);
975 }
976 else
977 {
978 generateCheckpointsPath(path, vertices);
979 }
980
981 COLA_ASSERT(vertices.size() >= 2);
982 COLA_ASSERT(vertices[0] == src());
983 COLA_ASSERT(vertices[vertices.size() - 1] == dst());
984 COLA_ASSERT(m_reroute_flag_ptr != nullptr);
985
986 for (size_t i = 1; i < vertices.size(); ++i)
987 {
989 {
990 // TODO: Again, we could know this edge without searching.
991 EdgeInf *edge = EdgeInf::existingEdge(vertices[i - 1], vertices[i]);
992 if (edge) {
994 }
995 }
996 else
997 {
998 m_false_path = true;
999 }
1000
1001 VertInf *vertex = vertices[i];
1002 if (vertex->pathNext &&
1003 (vertex->pathNext->point == vertex->point))
1004 {
1005 if (!(vertex->pathNext->id.isConnPt()) && !(vertex->id.isConnPt()))
1006 {
1007 // Check for consecutive points on opposite
1008 // corners of two touching shapes.
1009 COLA_ASSERT(abs(vertex->pathNext->id.vn - vertex->id.vn) != 2);
1010 }
1011 }
1012 }
1013
1014 // Get rid of dummy ShapeConnectionPin bridging points at beginning
1015 // and end of path.
1016 std::vector<Point> clippedPath;
1017 std::vector<Point>::iterator pathBegin = path.begin();
1018 std::vector<Point>::iterator pathEnd = path.end();
1019 if (path.size() > 2 && isDummyAtEnd.first)
1020 {
1021 ++pathBegin;
1022 m_src_connend->usePinVertex(vertices[1]);
1023 }
1024 if (path.size() > 2 && isDummyAtEnd.second)
1025 {
1026 --pathEnd;
1027 m_dst_connend->usePinVertex(vertices[vertices.size() - 2]);
1028 }
1029 clippedPath.insert(clippedPath.end(), pathBegin, pathEnd);
1030
1031 // Clear visibility edges added for connection pins dummy vertices.
1033
1034 freeRoutes();
1035 PolyLine& output_route = m_route;
1036 output_route.ps = clippedPath;
1037
1038#ifdef PATHDEBUG
1039 db_printf("Output route:\n");
1040 for (size_t i = 0; i < output_route.ps.size(); ++i)
1041 {
1042 db_printf("[%d,%d] %g, %g ", output_route.ps[i].id,
1043 output_route.ps[i].vn, output_route.ps[i].x,
1044 output_route.ps[i].y);
1045 }
1046 db_printf("\n\n");
1047#endif
1048
1049#ifdef DEBUGHANDLER
1050 if (m_router->debugHandler())
1051 {
1052 m_router->debugHandler()->updateConnectorRoute(this, -1, -1);
1053 }
1054#endif
1055
1056 return true;
1057}
1058
1059void ConnRef::generateCheckpointsPath(std::vector<Point>& path,
1060 std::vector<VertInf *>& vertices)
1061{
1062 std::vector<VertInf *> checkpoints = m_checkpoint_vertices;
1063 checkpoints.insert(checkpoints.begin(), src());
1064 checkpoints.push_back(dst());
1065
1066 path.clear();
1067 vertices.clear();
1068 path.push_back(src()->point);
1069 vertices.push_back(src());
1070
1071 size_t lastSuccessfulIndex = 0;
1072 for (size_t i = 1; i < checkpoints.size(); ++i)
1073 {
1074 VertInf *start = checkpoints[lastSuccessfulIndex];
1075 VertInf *end = checkpoints[i];
1076
1077 // Handle checkpoint directions by disabling some visibility edges.
1078 if (lastSuccessfulIndex > 0)
1079 {
1080 Checkpoint& srcCP = m_checkpoints[lastSuccessfulIndex - 1];
1081 if (srcCP.departureDirections != ConnDirAll)
1082 {
1084 }
1085 }
1086 if ((i + 1) < checkpoints.size())
1087 {
1088 Checkpoint& dstCP = m_checkpoints[i - 1];
1089 if (dstCP.arrivalDirections != ConnDirAll)
1090 {
1091 end->setVisibleDirections(dstCP.arrivalDirections);
1092 }
1093 }
1094
1095 AStarPath aStar;
1096 // Route the connector
1097 aStar.search(this, start, end, nullptr);
1098
1099 // Restore changes made for checkpoint visibility directions.
1100 if (lastSuccessfulIndex > 0)
1101 {
1103 }
1104 if ((i + 1) < checkpoints.size())
1105 {
1106 end->setVisibleDirections(ConnDirAll);
1107 }
1108
1109 // Process the path.
1110 int pathlen = end->pathLeadsBackTo(start);
1111 if (pathlen >= 2)
1112 {
1113 size_t prev_path_size = path.size();
1114 path.resize(prev_path_size + (pathlen - 1));
1115 vertices.resize(prev_path_size + (pathlen - 1));
1116 VertInf *vertInf = end;
1117 for (size_t index = path.size() - 1; index >= prev_path_size;
1118 --index)
1119 {
1120 path[index] = vertInf->point;
1121 if (vertInf->id.isConnPt())
1122 {
1123 path[index].id = m_id;
1124 path[index].vn = kUnassignedVertexNumber;
1125 }
1126 else
1127 {
1128 path[index].id = vertInf->id.objID;
1129 path[index].vn = vertInf->id.vn;
1130 }
1131 vertices[index] = vertInf;
1132 vertInf = vertInf->pathNext;
1133 }
1134 lastSuccessfulIndex = i;
1135 }
1136 else if (i + 1 == checkpoints.size())
1137 {
1138 // There is no valid path.
1139 db_printf("Warning: Path not found...\n");
1140 m_needs_reroute_flag = true;
1141
1142 path.push_back(dst()->point);
1143 vertices.push_back(dst());
1144
1145 COLA_ASSERT(path.size() >= 2);
1146 }
1147 else
1148 {
1149 err_printf("Warning: skipping checkpoint for connector "
1150 "%d at (%g, %g).\n", (int) id(),
1151 checkpoints[i]->point.x, checkpoints[i]->point.y);
1152 fflush(stderr);
1153 }
1154 }
1155 // Use topbit to differentiate between start and end point of connector.
1156 // They need unique IDs for nudging.
1157 unsigned int topbit = ((unsigned int) 1) << 31;
1158 path[path.size() - 1].id = m_id | topbit;
1159 path[path.size() - 1].vn = kUnassignedVertexNumber;
1160}
1161
1162
1163void ConnRef::generateStandardPath(std::vector<Point>& path,
1164 std::vector<VertInf *>& vertices)
1165{
1166 VertInf *tar = m_dst_vert;
1167 size_t existingPathStart = 0;
1168 const PolyLine& currRoute = route();
1170 {
1171 COLA_ASSERT(m_router->IgnoreRegions == true);
1172
1173#ifdef PATHDEBUG
1174 db_printf("\n");
1175 src()->id.db_print();
1176 db_printf(": %g, %g\n", src()->point.x, src()->point.y);
1177 tar->id.db_print();
1178 db_printf(": %g, %g\n", tar->point.x, tar->point.y);
1179 for (size_t i = 0; i < currRoute.ps.size(); ++i)
1180 {
1181 db_printf("%g, %g ", currRoute.ps[i].x, currRoute.ps[i].y);
1182 }
1183 db_printf("\n");
1184#endif
1185 if (currRoute.size() > 2)
1186 {
1187 if (m_src_vert->point == currRoute.ps[0])
1188 {
1189 existingPathStart = currRoute.size() - 2;
1190 COLA_ASSERT(existingPathStart != 0);
1191 const Point& pnt = currRoute.at(existingPathStart);
1192 VertID vID(pnt.id, pnt.vn);
1193
1195 COLA_ASSERT(m_start_vert);
1196 }
1197 }
1198 }
1199 //db_printf("GO\n");
1200 //db_printf("src: %X strt: %X dst: %X\n", (int) m_src_vert, (int) m_start_vert, (int) m_dst_vert);
1201 unsigned int pathlen = 0;
1202 while (pathlen == 0)
1203 {
1204 AStarPath aStar;
1205 aStar.search(this, src(), dst(), start());
1206 pathlen = dst()->pathLeadsBackTo(src());
1207 if (pathlen < 2)
1208 {
1209 if (existingPathStart == 0)
1210 {
1211 break;
1212 }
1213#ifdef PATHDEBUG
1214 db_printf("BACK\n");
1215#endif
1216 existingPathStart--;
1217 const Point& pnt = currRoute.at(existingPathStart);
1218 VertIDProps props = (existingPathStart > 0) ? 0 :
1220 VertID vID(pnt.id, pnt.vn, props);
1221
1223 COLA_ASSERT(m_start_vert);
1224 }
1225 else if (m_router->RubberBandRouting)
1226 {
1227 // found.
1228 bool unwind = false;
1229
1230#ifdef PATHDEBUG
1231 db_printf("\n\n\nSTART:\n\n");
1232#endif
1233 VertInf *prior = nullptr;
1234 for (VertInf *curr = tar; curr != m_start_vert->pathNext;
1235 curr = curr->pathNext)
1236 {
1237 if (!validateBendPoint(curr->pathNext, curr, prior))
1238 {
1239 unwind = true;
1240 break;
1241 }
1242 prior = curr;
1243 }
1244 if (unwind)
1245 {
1246#ifdef PATHDEBUG
1247 db_printf("BACK II\n");
1248#endif
1249 if (existingPathStart == 0)
1250 {
1251 break;
1252 }
1253 existingPathStart--;
1254 const Point& pnt = currRoute.at(existingPathStart);
1255 VertIDProps props = (existingPathStart > 0) ? 0 :
1257 VertID vID(pnt.id, pnt.vn, props);
1258
1260 COLA_ASSERT(m_start_vert);
1261
1262 pathlen = 0;
1263 }
1264 }
1265 }
1266
1267 if (pathlen < 2)
1268 {
1269 // There is no valid path.
1270 db_printf("Warning: Path not found...\n");
1271 m_needs_reroute_flag = true;
1272 pathlen = 2;
1273 tar->pathNext = m_src_vert;
1275 {
1276 // TODO: Could we know this edge already?
1277 //EdgeInf *edge = EdgeInf::existingEdge(m_src_vert, tar);
1278 //COLA_ASSERT(edge != nullptr);
1279 //edge->addCycleBlocker();
1280 }
1281 }
1282 path.resize(pathlen);
1283 vertices.resize(pathlen);
1284
1285 unsigned int j = pathlen - 1;
1286 for (VertInf *i = tar; i != m_src_vert; i = i->pathNext)
1287 {
1288 path[j] = i->point;
1289 vertices[j] = i;
1290 path[j].id = i->id.objID;
1291 path[j].vn = i->id.vn;
1292
1293 j--;
1294 }
1295 vertices[0] = m_src_vert;
1296 path[0] = m_src_vert->point;
1297 path[0].id = m_src_vert->id.objID;
1298 path[0].vn =m_src_vert->id.vn;
1299}
1300
1301
1303{
1304 m_hate_crossings = value;
1305}
1306
1307
1309{
1310 return m_hate_crossings;
1311}
1312
1313
1314std::vector<Point> ConnRef::possibleDstPinPoints(void) const
1315{
1316 std::vector<Point> points;
1317 if (m_dst_connend)
1318 {
1319 points = m_dst_connend->possiblePinPoints();
1320 }
1321 return points;
1322}
1323
1324
1326{
1327 // We have sorted neither list initially.
1328 for (size_t dim = 0; dim < 2; ++dim)
1329 {
1330 sorted[dim] = false;
1331 }
1332}
1333
1334
1336{
1337}
1338
1339
1341{
1342 // Sort if not already sorted.
1343 if (sorted[dim] == false)
1344 {
1345 sort(dim);
1346 }
1347 return sortedConnVector[dim];
1348}
1349
1350
1351int PtOrder::positionFor(const size_t dim, const ConnRef *conn)
1352{
1353 // Sort if not already sorted.
1354 if (sorted[dim] == false)
1355 {
1356 sort(dim);
1357 }
1358
1359 // Just return position from the sorted list.
1360 size_t i = 0;
1361 for ( ; i < sortedConnVector[dim].size(); ++i)
1362 {
1363 if (sortedConnVector[dim][i].second == conn)
1364 {
1365 return (int) i;
1366 }
1367 }
1368 return -1;
1369}
1370
1371
1372size_t PtOrder::insertPoint(const size_t dim, const PtConnPtrPair& pointPair)
1373{
1374 // Is this connector bendpoint already inserted?
1375 size_t i = 0;
1376 for ( ; i < nodes[dim].size(); ++i)
1377 {
1378 if (nodes[dim][i].second == pointPair.second)
1379 {
1380 return i;
1381 }
1382 }
1383 // Not found, insert.
1384 nodes[dim].push_back(pointPair);
1385 return nodes[dim].size() - 1;
1386}
1387
1388void PtOrder::addPoints(const size_t dim, const PtConnPtrPair& arg1,
1389 const PtConnPtrPair& arg2)
1390{
1391 // Add points, but not ordering information.
1392 insertPoint(dim, arg1);
1393 insertPoint(dim, arg2);
1394}
1395
1396
1397void PtOrder::addOrderedPoints(const size_t dim, const PtConnPtrPair& innerArg,
1398 const PtConnPtrPair& outerArg, bool swapped)
1399{
1400 PtConnPtrPair inner = (swapped) ? outerArg : innerArg;
1401 PtConnPtrPair outer = (swapped) ? innerArg : outerArg;
1402 COLA_ASSERT(inner != outer);
1403
1404 // Add points.
1405 size_t innerIndex = insertPoint(dim, inner);
1406 size_t outerIndex = insertPoint(dim, outer);
1407
1408 // And edge for ordering information.
1409 links[dim].push_back(std::make_pair(outerIndex, innerIndex));
1410}
1411
1412
1413void PtOrder::sort(const size_t dim)
1414{
1415 // This is just a topological sort of the points using the edges info.
1416
1417 sorted[dim] = true;
1418
1419 size_t n = nodes[dim].size();
1420
1421 // Build an adjacency matrix for easy lookup.
1422 std::vector<std::vector<bool> > adjacencyMatrix(n);
1423 for (size_t i = 0; i < n; ++i)
1424 {
1425 adjacencyMatrix[i].assign(n, false);
1426 }
1427 std::vector<int> incomingDegree(n);
1428 std::queue<size_t> queue;
1429
1430 // Populate the dependency matrix.
1431 for (NodeIndexPairLinkList::iterator it = links[dim].begin();
1432 it != links[dim].end(); ++it)
1433 {
1434 adjacencyMatrix[it->first][it->second] = true;
1435 }
1436
1437 // Build incoming degree lookup structure, and add nodes with no
1438 // incoming edges to queue.
1439 for (size_t i = 0; i < n; ++i)
1440 {
1441 int degree = 0;
1442
1443 for (size_t j = 0; j < n; ++j)
1444 {
1445 if (adjacencyMatrix[j][i])
1446 {
1447 degree++;
1448 }
1449 }
1450 incomingDegree[i] = degree;
1451
1452 if (degree == 0)
1453 {
1454 queue.push(i);
1455 }
1456 }
1457
1458 while (queue.empty() == false)
1459 {
1460 size_t k = queue.front();
1461 assert(k < nodes[dim].size());
1462 queue.pop();
1463
1464 // Insert node k into the sorted list
1465 sortedConnVector[dim].push_back(nodes[dim][k]);
1466
1467 // Remove all edges leaving node k:
1468 for (size_t i = 0; i < n; ++i)
1469 {
1470 if (adjacencyMatrix[k][i])
1471 {
1472 adjacencyMatrix[k][i] = false;
1473 incomingDegree[i]--;
1474
1475 if (incomingDegree[i] == 0)
1476 {
1477 queue.push(i);
1478 }
1479 }
1480 }
1481 }
1482}
1483
1484
1485// Returns a vertex number representing a point on the line between
1486// two shape corners, represented by p0 and p1.
1487//
1488static int midVertexNumber(const Point& p0, const Point& p1, const Point& c)
1489{
1490 if (c.vn != kUnassignedVertexNumber)
1491 {
1492 // The split point is a shape corner, so doesn't need its
1493 // vertex number adjusting.
1494 return c.vn;
1495 }
1496 if ((p0.vn >= 4) && (p0.vn < kUnassignedVertexNumber))
1497 {
1498 // The point next to this has the correct nudging direction,
1499 // so use that.
1500 return p0.vn;
1501 }
1502 if ((p1.vn >= 4) && (p1.vn < kUnassignedVertexNumber))
1503 {
1504 // The point next to this has the correct nudging direction,
1505 // so use that.
1506 return p1.vn;
1507 }
1508 if ((p0.vn < 4) && (p1.vn < 4))
1509 {
1510 if (p0.vn != p1.vn)
1511 {
1512 return p0.vn;
1513 }
1514 // Splitting between two ordinary shape corners.
1515 int vn_mid = std::min(p0.vn, p1.vn);
1516 if ((std::max(p0.vn, p1.vn) == 3) && (vn_mid == 0))
1517 {
1518 vn_mid = 3; // Next vn is effectively 4.
1519 }
1520 return vn_mid + 4;
1521 }
1522 COLA_ASSERT((p0.x == p1.x) || (p0.y == p1.y));
1523 if (p0.vn != kUnassignedVertexNumber)
1524 {
1525 if (p0.x == p1.x)
1526 {
1527 if ((p0.vn == 2) || (p0.vn == 3))
1528 {
1529 return 6;
1530 }
1531 return 4;
1532 }
1533 else
1534 {
1535 if ((p0.vn == 0) || (p0.vn == 3))
1536 {
1537 return 7;
1538 }
1539 return 5;
1540 }
1541 }
1542 else if (p1.vn != kUnassignedVertexNumber)
1543 {
1544 if (p0.x == p1.x)
1545 {
1546 if ((p1.vn == 2) || (p1.vn == 3))
1547 {
1548 return 6;
1549 }
1550 return 4;
1551 }
1552 else
1553 {
1554 if ((p1.vn == 0) || (p1.vn == 3))
1555 {
1556 return 7;
1557 }
1558 return 5;
1559 }
1560 }
1561
1562 // Shouldn't both be new (kUnassignedVertexNumber) points.
1563 db_printf("midVertexNumber(): p0.vn and p1.vn both = "
1564 "kUnassignedVertexNumber\n");
1565 db_printf("p0.vn %d p1.vn %d\n", p0.vn, p1.vn);
1567}
1568
1569
1570// Break up overlapping parallel segments that are not the same edge in
1571// the visibility graph, i.e., where one segment is a subsegment of another.
1572void splitBranchingSegments(Avoid::Polygon& poly, bool polyIsConn,
1573 Avoid::Polygon& conn, const double tolerance)
1574{
1575 for (std::vector<Avoid::Point>::iterator i = conn.ps.begin();
1576 i != conn.ps.end(); ++i)
1577 {
1578 if (i == conn.ps.begin())
1579 {
1580 // Skip the first point.
1581 // There are points-1 segments in a connector.
1582 continue;
1583 }
1584
1585 for (std::vector<Avoid::Point>::iterator j = poly.ps.begin();
1586 j != poly.ps.end(); )
1587 {
1588 if (polyIsConn && (j == poly.ps.begin()))
1589 {
1590 // Skip the first point.
1591 // There are points-1 segments in a connector.
1592 ++j;
1593 continue;
1594 }
1595 Point& c0 = *(i - 1);
1596 Point& c1 = *i;
1597
1598 Point& p0 = (j == poly.ps.begin()) ? poly.ps.back() : *(j - 1);
1599 Point& p1 = *j;
1600
1601 // Check the first point of the first segment.
1602 if (((i - 1) == conn.ps.begin()) &&
1603 pointOnLine(p0, p1, c0, tolerance))
1604 {
1605 //db_printf("add to poly %g %g\n", c0.x, c0.y);
1606
1607 c0.vn = midVertexNumber(p0, p1, c0);
1608 j = poly.ps.insert(j, c0);
1609 if (j != poly.ps.begin())
1610 {
1611 --j;
1612 }
1613 continue;
1614 }
1615 // And the second point of every segment.
1616 if (pointOnLine(p0, p1, c1, tolerance))
1617 {
1618 //db_printf("add to poly %g %g\n", c1.x, c1.y);
1619
1620 c1.vn = midVertexNumber(p0, p1, c1);
1621 j = poly.ps.insert(j, c1);
1622 if (j != poly.ps.begin())
1623 {
1624 --j;
1625 }
1626 continue;
1627 }
1628
1629 // Check the first point of the first segment.
1630 if (polyIsConn && ((j - 1) == poly.ps.begin()) &&
1631 pointOnLine(c0, c1, p0, tolerance))
1632 {
1633 //db_printf("add to conn %g %g\n", p0.x, p0.y);
1634
1635 p0.vn = midVertexNumber(c0, c1, p0);
1636 i = conn.ps.insert(i, p0);
1637 continue;
1638 }
1639 // And the second point of every segment.
1640 if (pointOnLine(c0, c1, p1, tolerance))
1641 {
1642 //db_printf("add to conn %g %g\n", p1.x, p1.y);
1643
1644 p1.vn = midVertexNumber(c0, c1, p1);
1645 i = conn.ps.insert(i, p1);
1646 }
1647 ++j;
1648 }
1649 }
1650}
1651
1652
1653static int segDir(const Point& p1, const Point& p2)
1654{
1655 int result = 1;
1656 if (p1.x == p2.x)
1657 {
1658 if (p2.y > p1.y)
1659 {
1660 result = -1;
1661 }
1662 }
1663 else if (p1.y == p2.y)
1664 {
1665 if (p2.x < p1.x)
1666 {
1667 result = -1;
1668 }
1669 }
1670 return result;
1671}
1672
1673
1674static bool posInlineWithConnEndSegs(const double pos, const size_t dim,
1675 const Avoid::Polygon& poly, const Avoid::Polygon& conn)
1676{
1677 size_t pLast = poly.size() - 1;
1678 size_t cLast = conn.size() - 1;
1679 if ((
1680 // Is inline with the beginning of the "poly" line
1681 ((pos == poly.ps[0][dim]) && (pos == poly.ps[1][dim])) ||
1682 // Is inline with the end of the "poly" line
1683 ((pos == poly.ps[pLast][dim]) && (pos == poly.ps[pLast - 1][dim]))
1684 ) && (
1685 // Is inline with the beginning of the "conn" line
1686 ((pos == conn.ps[0][dim]) && (pos == conn.ps[1][dim])) ||
1687 // Is inline with the end of the "conn" line
1688 ((pos == conn.ps[cLast][dim]) && (pos == conn.ps[cLast - 1][dim]))
1689 ))
1690 {
1691 return true;
1692 }
1693 return false;
1694}
1695
1697 Avoid::Polygon& conn, ConnRef *polyConnRef, ConnRef *connConnRef)
1698 : poly(poly),
1699 polyIsConn(polyIsConn),
1700 conn(conn),
1701 checkForBranchingSegments(false),
1702 polyConnRef(polyConnRef),
1703 connConnRef(connConnRef),
1704 crossingPoints(nullptr),
1705 pointOrders(nullptr),
1706 sharedPaths(nullptr)
1707{
1708}
1709
1717
1718
1719// Computes the *shared* length of these two shared paths.
1720//
1721static double pathLength(Avoid::Point **c_path, Avoid::Point **p_path,
1722 size_t size)
1723{
1724 double length = 0;
1725
1726 for (unsigned int ind = 1; ind < size; ++ind)
1727 {
1728 if ( (*(c_path[ind - 1]) == *(p_path[ind - 1])) &&
1729 (*(c_path[ind]) == *(p_path[ind])) )
1730 {
1731 // This segment is shared by both paths.
1732 //
1733 // This function will only be used for orthogonal paths, so we
1734 // can use Manhattan distance here since it will be faster to
1735 // compute.
1736 length += manhattanDist(*(c_path[ind - 1]), *(c_path[ind]));
1737 }
1738 }
1739
1740 return length;
1741}
1742
1743// Works out if the segment conn[cIndex-1]--conn[cIndex] really crosses poly.
1744// This does not not count non-crossing shared paths as crossings.
1745// poly can be either a connector (polyIsConn = true) or a cluster
1746// boundary (polyIsConn = false).
1747//
1748void ConnectorCrossings::countForSegment(size_t cIndex, const bool finalSegment)
1749{
1750 clear();
1751
1752 bool polyIsOrthogonal = (polyConnRef &&
1754 bool connIsOrthogonal = (connConnRef &&
1756
1757 // Fixed routes will not have segment breaks at possible crossings.
1758 bool polyIsFixed = (polyConnRef && polyConnRef->hasFixedRoute());
1759 bool connIsFixed = (connConnRef && connConnRef->hasFixedRoute());
1760
1761 // We need to split apart connectors at potential crossing points if
1762 // either has a fixed route or it is a polyline connector. This is not
1763 // needed for orthogonal connectors where crossings occur at vertices
1764 // in visibility graph and on the raw connector routes.
1765 if (checkForBranchingSegments || polyIsFixed || connIsFixed ||
1766 !polyIsOrthogonal || !connIsOrthogonal)
1767 {
1768 double epsilon = std::numeric_limits<double>::epsilon();
1769 size_t conn_pn = conn.size();
1770 // XXX When doing the pointOnLine test we allow the points to be
1771 // slightly non-collinear. This addresses a problem with clustered
1772 // routing where connectors could otherwise route cheaply through
1773 // shape corners that were not quite on the cluster boundary, but
1774 // reported to be on there by the line segment intersection code,
1775 // which I suspect is not numerically accurate enough. This occurred
1776 // for points that only differed by about 10^-12 in the y-dimension.
1777 double tolerance = (!polyIsConn) ? epsilon : 0.0;
1779 // cIndex is going to be the last, so take into account added points.
1780 cIndex += (conn.size() - conn_pn);
1781 }
1782 COLA_ASSERT(cIndex >= 1);
1783 COLA_ASSERT(cIndex < conn.size());
1784
1785 size_t poly_size = poly.size();
1786
1787 Avoid::Point& a1 = conn.ps[cIndex - 1];
1788 Avoid::Point& a2 = conn.ps[cIndex];
1789 //db_printf("a1: %g %g\n", a1.x, a1.y);
1790 //db_printf("a2: %g %g\n", a2.x, a2.y);
1791
1792 // Allocate arrays for computing shared paths.
1793 // Don't use dynamic array due to portablity issues.
1794 size_t max_path_size = std::min(poly_size, conn.size());
1795 Avoid::Point **c_path = new Avoid::Point*[max_path_size];
1796 Avoid::Point **p_path = new Avoid::Point*[max_path_size];
1797 size_t size = 0;
1798
1799 for (size_t j = ((polyIsConn) ? 1 : 0); j < poly_size; ++j)
1800 {
1801 Avoid::Point& b1 = poly.ps[(j - 1 + poly_size) % poly_size];
1802 Avoid::Point& b2 = poly.ps[j];
1803 //db_printf("b1: %g %g\n", b1.x, b1.y);
1804 //db_printf("b2: %g %g\n", b2.x, b2.y);
1805
1806 size = 0;
1807
1808 bool converging = false;
1809
1810 const bool a1_eq_b1 = (a1 == b1);
1811 const bool a2_eq_b1 = (a2 == b1);
1812 const bool a2_eq_b2 = (a2 == b2);
1813 const bool a1_eq_b2 = (a1 == b2);
1814
1815 if ( (a1_eq_b1 && a2_eq_b2) ||
1816 (a2_eq_b1 && a1_eq_b2) )
1817 {
1818 if (finalSegment)
1819 {
1820 converging = true;
1821 }
1822 else
1823 {
1824 // Route along same segment: no penalty. We detect
1825 // crossovers when we see the segments diverge.
1826 continue;
1827 }
1828 }
1829 else if (a2_eq_b1 || a2_eq_b2 || a1_eq_b2)
1830 {
1831 // Each crossing that is at a vertex in the
1832 // visibility graph gets noticed four times.
1833 // We ignore three of these cases.
1834 // This also catches the case of a shared path,
1835 // but this is one that terminates at a common
1836 // endpoint, so we don't care about it.
1837 continue;
1838 }
1839
1840 if (a1_eq_b1 || converging)
1841 {
1842 if (!converging)
1843 {
1844 if (polyIsConn && (j == 1))
1845 {
1846 // Can't be the end of a shared path or crossing path
1847 // since the common point is the first point of the
1848 // connector path. This is not a shared path at all.
1849 continue;
1850 }
1851
1852 Avoid::Point& b0 = poly.ps[(j - 2 + poly_size) % poly_size];
1853 // The segments share an endpoint -- a1==b1.
1854 if (a2 == b0)
1855 {
1856 // a2 is not a split, continue.
1857 continue;
1858 }
1859 }
1860
1861 // If here and not converging, then we know that a2 != b2
1862 // And a2 and its pair in b are a split.
1863 COLA_ASSERT(converging || !a2_eq_b2);
1864
1865 bool shared_path = false;
1866
1867 // Initial values here don't matter. They are only used after
1868 // being set to sensible values, but we set them to stop a MSVC
1869 // warning.
1870 bool p_dir_back;
1871 int p_dir = 0;
1872 int trace_c = 0;
1873 int trace_p = 0;
1874
1875 if (converging)
1876 {
1877 // Determine direction we have to look through
1878 // the points of connector b.
1879 p_dir_back = a2_eq_b2 ? true : false;
1880 p_dir = p_dir_back ? -1 : 1;
1881 trace_c = (int) cIndex;
1882 trace_p = (int) j;
1883 if (!p_dir_back)
1884 {
1885 if (finalSegment)
1886 {
1887 trace_p--;
1888 }
1889 else
1890 {
1891 trace_c--;
1892 }
1893 }
1894
1895 shared_path = true;
1896 }
1897 else if (cIndex >= 2)
1898 {
1899 Avoid::Point& b0 = poly.ps[(j - 2 + poly_size) % poly_size];
1900 Avoid::Point& a0 = conn.ps[cIndex - 2];
1901
1902 //db_printf("a0: %g %g\n", a0.x, a0.y);
1903 //db_printf("b0: %g %g\n", b0.x, b0.y);
1904
1905 if ((a0 == b2) || (a0 == b0))
1906 {
1907 // Determine direction we have to look through
1908 // the points of connector b.
1909 p_dir_back = (a0 == b0) ? true : false;
1910 p_dir = p_dir_back ? -1 : 1;
1911 trace_c = (int) cIndex;
1912 trace_p = (int) (p_dir_back ? j : j - 2);
1913
1914 shared_path = true;
1915 }
1916 }
1917
1918 if (shared_path)
1919 {
1921 // Shouldn't be here if p_dir is still equal to zero.
1922 COLA_ASSERT(p_dir != 0);
1923
1924 // Build the shared path, including the diverging points at
1925 // each end if the connector does not end at a common point.
1926 while ( (trace_c >= 0) && (!polyIsConn ||
1927 ((trace_p >= 0) && (trace_p < (int) poly_size))) )
1928 {
1929 // If poly is a cluster boundary, then it is a closed
1930 // poly-line and so it wraps around.
1931 size_t index_p = (size_t)
1932 ((trace_p + (2 * poly_size)) % poly_size);
1933 size_t index_c = (size_t) trace_c;
1934 c_path[size] = &conn.ps[index_c];
1935 p_path[size] = &poly.ps[index_p];
1936 ++size;
1937 if ((size > 1) && (conn.ps[index_c] != poly.ps[index_p]))
1938 {
1939 // Points don't match, so break out of loop.
1940 break;
1941 }
1942 trace_c--;
1943 trace_p += p_dir;
1944 }
1945
1946 // Are there diverging points at the ends of the shared path.
1947 bool front_same = (*(c_path[0]) == *(p_path[0]));
1948 bool back_same = (*(c_path[size - 1]) == *(p_path[size - 1]));
1949
1950 // Determine if the shared path originates at a junction.
1951 bool terminatesAtJunction = false;
1952 if (polyConnRef && connConnRef && (front_same || back_same))
1953 {
1954 // To do this we find the two ConnEnds at the common
1955 // end of the shared path. Then check if they are
1956 // attached to a junction and it is the same one.
1957 std::pair<ConnEnd, ConnEnd> connEnds =
1959 JunctionRef *connJunction = nullptr;
1960
1961 std::pair<ConnEnd, ConnEnd> polyEnds =
1963 JunctionRef *polyJunction = nullptr;
1964
1965 // The front of the c_path corresponds to destination
1966 // of the connector.
1967 connJunction = (front_same) ? connEnds.second.junction() :
1968 connEnds.first.junction();
1969 bool use_first = back_same;
1970 if (p_dir_back)
1971 {
1972 // Reversed, so use opposite.
1973 use_first = !use_first;
1974 }
1975 // The front of the p_path corresponds to destination
1976 // of the connector.
1977 polyJunction = (use_first) ? polyEnds.second.junction() :
1978 polyEnds.first.junction();
1979
1980 terminatesAtJunction = (connJunction &&
1981 (connJunction == polyJunction));
1982 }
1983
1984 if (sharedPaths)
1985 {
1986 // Store a copy of the shared path
1987 size_t start = (front_same) ? 0 : 1;
1988 size_t limit = size - ((back_same) ? 0 : 1);
1989
1990 PointList sPath(limit - start);
1991 for (size_t i = start; i < limit; ++i)
1992 {
1993 sPath[i - start] = *(c_path[i]);
1994 }
1995 sharedPaths->push_back(sPath);
1996 }
1997
1998 // Check to see if these share a fixed segment.
1999 if (polyIsOrthogonal && connIsOrthogonal)
2000 {
2001 size_t startPt = (front_same) ? 0 : 1;
2002 size_t endPt = size - ((back_same) ? 1 : 2);
2003 for (size_t dim = 0; dim < 2; ++dim)
2004 {
2005 if ((*c_path[startPt])[dim] == (*c_path[endPt])[dim])
2006 {
2007 double pos = (*c_path[startPt])[dim];
2008 // See if this is inline with either the start
2009 // or end point of both connectors. We don't
2010 // count them as crossing if they originate at a
2011 // junction and are part of the same hyperedge.
2012 if ( ((pos == poly.ps[0][dim]) ||
2013 (pos == poly.ps[poly_size - 1][dim])) &&
2014 ((pos == conn.ps[0][dim]) ||
2015 (pos == conn.ps[cIndex][dim])) &&
2016 (terminatesAtJunction == false))
2017 {
2019 }
2020 }
2021 }
2022
2023 if (!front_same && !back_same)
2024 {
2025 // Find overlapping segments that are constrained by
2026 // the fact that both the adjoining segments are fixed
2027 // in the other dimension, i.e.,
2028 //
2029 // X------++---X
2030 // ||
2031 // ||
2032 // X---++------X
2033 //
2034 // In the example above, altDim is X, and dim is Y.
2035 //
2036
2037 // For each dimension...
2038 for (size_t dim = 0; dim < 2; ++dim)
2039 {
2040 size_t end = size - 1;
2041 size_t altDim = (dim + 1) % 2;
2042 // If segment is in this dimension...
2043 if ((*c_path[1])[altDim] == (*c_path[end - 1])[altDim])
2044 {
2045 double posBeg = (*c_path[1])[dim];
2046 double posEnd = (*c_path[end - 1])[dim];
2047 // If both segment ends diverge at right-angles...
2048 if ( (posBeg == (*c_path[0])[dim]) &&
2049 (posBeg == (*p_path[0])[dim]) &&
2050 (posEnd == (*c_path[end])[dim]) &&
2051 (posEnd == (*p_path[end])[dim]) )
2052 {
2053 // and these segments are inline with the conn and path ends themselves...
2054 if (posInlineWithConnEndSegs(posBeg, dim,
2055 conn, poly) &&
2056 posInlineWithConnEndSegs(posEnd, dim,
2057 conn, poly))
2058 {
2059 // If all endpoints branch at right angles,
2060 // then penalise this since it is a segment
2061 // will will not be able to nudge apart
2062 // without introducing fixed segment
2063 // crossings.
2064 crossingFlags |=
2066 }
2067 }
2068 }
2069 }
2070 }
2071
2072#if 0
2073 // XXX: What is this code for? It is pretty much
2074 // incomprehensible and also causes one of the test
2075 // cases to fail.
2076 //
2077 if (!front_same && !back_same)
2078 {
2079 for (size_t dim = 0; dim < 2; ++dim)
2080 {
2081 size_t altDim = (dim + 1) % 2;
2082 if ((*c_path[1])[altDim] == (*c_path[1])[altDim])
2083 {
2084 size_t n = c_path.size();
2085 double yPosB = (*c_path[1])[dim];
2086 if ( (yPosB == (*c_path[0])[dim]) &&
2087 (yPosB == (*p_path[0])[dim]) )
2088 {
2089 crossingFlags |=
2091 }
2092
2093 double yPosE = (*c_path[n - 2])[dim];
2094 if ( (yPosE == (*c_path[n - 1])[dim]) &&
2095 (yPosE == (*p_path[n - 1])[dim]) )
2096 {
2097 crossingFlags |=
2099 }
2100 }
2101 }
2102 }
2103#endif
2104 }
2105
2106 // {start,end}CornerSide specifies which side of conn the
2107 // poly path enters and leaves.
2108 int startCornerSide = 1;
2109 int endCornerSide = 1;
2110
2111 bool reversed = false;
2112 if (!front_same)
2113 {
2114 // If there is a divergence at the beginning,
2115 // then order the shared path based on this.
2116 startCornerSide = Avoid::cornerSide(*c_path[0], *c_path[1],
2117 *c_path[2], *p_path[0]);
2118 }
2119 if (!back_same)
2120 {
2121 // If there is a divergence at the end of the path,
2122 // then order the shared path based on this.
2123 endCornerSide = Avoid::cornerSide(*c_path[size - 3],
2124 *c_path[size - 2], *c_path[size - 1],
2125 *p_path[size - 1]);
2126 }
2127 else
2128 {
2129 endCornerSide = startCornerSide;
2130 }
2131 if (front_same)
2132 {
2133 startCornerSide = endCornerSide;
2134 }
2135
2136 if (endCornerSide != startCornerSide)
2137 {
2138 // Mark that the shared path crosses.
2139 //db_printf("shared path crosses.\n");
2140 crossingCount += 1;
2141 if (crossingPoints)
2142 {
2143 crossingPoints->insert(*c_path[1]);
2144 }
2145 }
2146
2147 if (front_same || back_same)
2148 {
2150
2151 // Reduce the cost of paths that stay straight after
2152 // the split, and make this length available so that the
2153 // paths can be ordered during the improveCrossings()
2154 // step and the straight (usually better) paths will be
2155 // left alone while the router attempts to find better
2156 // paths for the others.
2157 double straightModifier = 200;
2159 pathLength(c_path, p_path, size);
2160 if (back_same && (size > 2))
2161 {
2162 if (vecDir(*p_path[0], *p_path[1], *p_path[2]) == 0)
2163 {
2164 firstSharedPathAtEndLength -= straightModifier;
2165 }
2166
2167 if (vecDir(*c_path[0], *c_path[1], *c_path[2]) == 0)
2168 {
2169 secondSharedPathAtEndLength -= straightModifier;
2170 }
2171 }
2172 else if (front_same && (size > 2))
2173 {
2174 if (vecDir(*p_path[size - 3], *p_path[size - 2],
2175 *p_path[size - 1]) == 0)
2176 {
2177 firstSharedPathAtEndLength -= straightModifier;
2178 }
2179
2180 if (vecDir(*c_path[size - 3], *c_path[size - 2],
2181 *c_path[size - 1]) == 0)
2182 {
2183 secondSharedPathAtEndLength -= straightModifier;
2184 }
2185 }
2186 }
2187 else if (polyIsOrthogonal && connIsOrthogonal)
2188 {
2189 int cStartDir = vecDir(*c_path[0], *c_path[1], *c_path[2]);
2190 int pStartDir = vecDir(*p_path[0], *p_path[1], *p_path[2]);
2191 if ((cStartDir != 0) && (cStartDir == -pStartDir))
2192 {
2193 // The start segments diverge at 180 degrees to each
2194 // other. So order based on not introducing overlap
2195 // of the diverging segments when these are nudged
2196 // apart.
2197 startCornerSide = -cStartDir;
2198 }
2199 else
2200 {
2201 int cEndDir = vecDir(*c_path[size - 3],
2202 *c_path[size - 2], *c_path[size - 1]);
2203 int pEndDir = vecDir(*p_path[size - 3],
2204 *p_path[size - 2], *p_path[size - 1]);
2205 if ((cEndDir != 0) && (cEndDir == -pEndDir))
2206 {
2207 // The end segments diverge at 180 degrees to
2208 // each other. So order based on not introducing
2209 // overlap of the diverging segments when these
2210 // are nudged apart.
2211 startCornerSide = -cEndDir;
2212 }
2213 }
2214 }
2215
2216#if 0
2217 int prevTurnDir = 0;
2218 if (pointOrders)
2219 {
2220 // Return the ordering for the shared path.
2221 COLA_ASSERT(c_path.size() > 0 || back_same);
2222 size_t adj_size = (c_path.size() - ((back_same) ? 0 : 1));
2223 for (size_t i = (front_same) ? 0 : 1; i < adj_size; ++i)
2224 {
2225 Avoid::Point& an = *(c_path[i]);
2226 Avoid::Point& bn = *(p_path[i]);
2227 int currTurnDir = ((i > 0) && (i < (adj_size - 1))) ?
2228 vecDir(*c_path[i - 1], an,
2229 *c_path[i + 1]) : 0;
2230 VertID vID(an.id, true, an.vn);
2231 if ( (currTurnDir == (-1 * prevTurnDir)) &&
2232 (currTurnDir != 0) && (prevTurnDir != 0) )
2233 {
2234 // The connector turns the opposite way around
2235 // this shape as the previous bend on the path,
2236 // so reverse the order so that the inner path
2237 // become the outer path and vice versa.
2238 reversed = !reversed;
2239 }
2240 bool orderSwapped = (*pointOrders)[an].addOrderedPoints(
2241 &bn, &an, reversed);
2242 if (orderSwapped)
2243 {
2244 // Reverse the order for later points.
2245 reversed = !reversed;
2246 }
2247 prevTurnDir = currTurnDir;
2248 }
2249 }
2250#endif
2251 if (pointOrders)
2252 {
2253 reversed = false;
2254 size_t startPt = (front_same) ? 0 : 1;
2255
2256 // Orthogonal should always have at least one segment.
2257 COLA_ASSERT(size > (startPt + 1));
2258
2259 if (startCornerSide > 0)
2260 {
2261 reversed = !reversed;
2262 }
2263
2264 int prevDir = 0;
2265 // Return the ordering for the shared path.
2266 COLA_ASSERT(size > 0 || back_same);
2267 size_t adj_size = (size - ((back_same) ? 0 : 1));
2268 for (size_t i = startPt; i < adj_size; ++i)
2269 {
2270 Avoid::Point& an = *(c_path[i]);
2271 Avoid::Point& bn = *(p_path[i]);
2272 COLA_ASSERT(an == bn);
2273
2274 if (i > startPt)
2275 {
2276 Avoid::Point& ap = *(c_path[i - 1]);
2277 Avoid::Point& bp = *(p_path[i - 1]);
2278
2279 int thisDir = segDir(ap, an);
2280 if (prevDir == 0)
2281 {
2282 if (thisDir > 0)
2283 {
2284 reversed = !reversed;
2285 }
2286 }
2287 else if (thisDir != prevDir)
2288 {
2289 reversed = !reversed;
2290 }
2291
2292 int orientation = (ap.x == an.x) ? 0 : 1;
2293 //printf("prevOri %d\n", prevOrientation);
2294 //printf("1: %X, %X\n", (int) &(bn), (int) &(an));
2295 (*pointOrders)[an].addOrderedPoints(
2296 orientation,
2297 std::make_pair(&bn, polyConnRef),
2298 std::make_pair(&an, connConnRef),
2299 reversed);
2300 COLA_ASSERT(ap == bp);
2301 //printf("2: %X, %X\n", (int) &bp, (int) &ap);
2302 (*pointOrders)[ap].addOrderedPoints(
2303 orientation,
2304 std::make_pair(&bp, polyConnRef),
2305 std::make_pair(&ap, connConnRef),
2306 reversed);
2307 prevDir = thisDir;
2308 }
2309 }
2310 }
2311#if 0
2312 int ymod = -1;
2313 if ((id.vn == 1) || (id.vn == 2))
2314 {
2315 // bottom.
2316 ymod = +1;
2317 }
2318
2319 int xmod = -1;
2320 if ((id.vn == 0) || (id.vn == 1))
2321 {
2322 // right.
2323 xmod = +1;
2324 }
2325 if(id.vn > 3)
2326 {
2327 xmod = ymod = 0;
2328 if (id.vn == 4)
2329 {
2330 // right.
2331 xmod = +1;
2332 }
2333 else if (id.vn == 5)
2334 {
2335 // bottom.
2336 ymod = +1;
2337 }
2338 else if (id.vn == 6)
2339 {
2340 // left.
2341 xmod = -1;
2342 }
2343 else if (id.vn == 7)
2344 {
2345 // top.
2346 ymod = -1;
2347 }
2348 }
2349#endif
2350
2352 }
2353 else if (cIndex >= 2)
2354 {
2355 // The connectors cross or touch at this point.
2356 //db_printf("Cross or touch at point... \n");
2357
2358 // Crossing shouldn't be at an endpoint.
2359 COLA_ASSERT(cIndex >= 2);
2360 COLA_ASSERT(!polyIsConn || (j >= 2));
2361
2362 Avoid::Point& b0 = poly.ps[(j - 2 + poly_size) % poly_size];
2363 Avoid::Point& a0 = conn.ps[cIndex - 2];
2364
2365 int side1 = Avoid::cornerSide(a0, a1, a2, b0);
2366 int side2 = Avoid::cornerSide(a0, a1, a2, b2);
2367 if (side1 != side2)
2368 {
2369 // The connectors cross at this point.
2370 //db_printf("cross.\n");
2371 crossingCount += 1;
2372 if (crossingPoints)
2373 {
2374 crossingPoints->insert(a1);
2375 }
2376 }
2377
2379 if (pointOrders)
2380 {
2381 if (polyIsOrthogonal && connIsOrthogonal)
2382 {
2383 // Orthogonal case:
2384 // Just order based on which comes from the left and
2385 // top in each dimension because this can only be two
2386 // L-shaped segments touching at the bend.
2387 bool reversedX = ((a0.x < a1.x) || (a2.x < a1.x));
2388 bool reversedY = ((a0.y < a1.y) || (a2.y < a1.y));
2389 // XXX: Why do we need to invert the reversed values
2390 // here? Are they wrong for orthogonal points
2391 // in the other places?
2392 (*pointOrders)[b1].addOrderedPoints(0,
2393 std::make_pair(&b1, polyConnRef),
2394 std::make_pair(&a1, connConnRef),
2395 !reversedX);
2396 (*pointOrders)[b1].addOrderedPoints(1,
2397 std::make_pair(&b1, polyConnRef),
2398 std::make_pair(&a1, connConnRef),
2399 !reversedY);
2400 }
2401#if 0
2402// Unused code.
2403 else
2404 {
2405 int turnDirA = vecDir(a0, a1, a2);
2406 int turnDirB = vecDir(b0, b1, b2);
2407 bool reversed = (side1 != -turnDirA);
2408 if (side1 != side2)
2409 {
2410 // Interesting case where a connector routes round
2411 // the edge of a shape and intersects a connector
2412 // which is connected to a port on the edge of the
2413 // shape.
2414 if (turnDirA == 0)
2415 {
2416 // We'll make B the outer by preference,
2417 // because the points of A are collinear.
2418 reversed = false;
2419 }
2420 else if (turnDirB == 0)
2421 {
2422 reversed = true;
2423 }
2424 // TODO COLA_ASSERT((turnDirB != 0) ||
2425 // (turnDirA != 0));
2426 }
2427 VertID vID(b1.id, b1.vn);
2428 //(*pointOrders)[b1].addOrderedPoints(&b1, &a1, reversed);
2429 }
2430#endif
2431 }
2432 }
2433 }
2434 else
2435 {
2436 if ( polyIsOrthogonal && connIsOrthogonal)
2437 {
2438 // All crossings in orthogonal connectors will be at a
2439 // vertex in the visibility graph, so we need not bother
2440 // doing normal line intersection.
2441 continue;
2442 }
2443
2444 // No endpoint is shared between these two line segments,
2445 // so just calculate normal segment intersection.
2446
2447 Point cPt;
2448 int intersectResult = Avoid::segmentIntersectPoint(
2449 a1, a2, b1, b2, &(cPt.x), &(cPt.y));
2450
2451 if (intersectResult == Avoid::DO_INTERSECT)
2452 {
2453 if (!polyIsConn &&
2454 ((a1 == cPt) || (a2 == cPt) || (b1 == cPt) || (b2 == cPt)))
2455 {
2456 // XXX: This shouldn't actually happen, because these
2457 // points should be added as bends to each line by
2458 // splitBranchingSegments(). Thus, lets ignore them.
2459 COLA_ASSERT(a1 != cPt);
2460 COLA_ASSERT(a2 != cPt);
2461 COLA_ASSERT(b1 != cPt);
2462 COLA_ASSERT(b2 != cPt);
2463 continue;
2464 }
2465 //db_printf("crossing lines:\n");
2466 //db_printf("cPt: %g %g\n", cPt.x, cPt.y);
2467 crossingCount += 1;
2468 if (crossingPoints)
2469 {
2470 crossingPoints->insert(cPt);
2471 }
2472 }
2473 }
2474 }
2475 //db_printf("crossingcount %d %d\n", crossingCount, crossingFlags);
2476
2477 // Free shared path memory.
2478 delete[] c_path;
2479 delete[] p_path;
2480}
2481
2482
2483//============================================================================
2484
2485}
2486
2487
static SPStyleProp const props[]
Lookup dictionary for attributes/properties.
void search(ConnRef *lineRef, VertInf *src, VertInf *tar, VertInf *start)
Definition makepath.cpp:922
A checkpoint is a point that the route for a particular connector must visit.
Definition connector.h:69
ConnDirFlags departureDirections
Definition connector.h:111
ConnDirFlags arrivalDirections
Definition connector.h:110
The ConnEnd class represents different possible endpoints for connectors.
Definition connend.h:111
std::vector< Point > possiblePinPoints(void) const
Definition connend.cpp:214
const Point position(void) const
Returns the position of this connector endpoint.
Definition connend.cpp:120
void freeActivePin(void)
Definition connend.cpp:226
void usePinVertex(VertInf *pinVert)
Definition connend.cpp:195
ConnRef * m_conn_ref
Definition connend.h:255
bool isPinConnection(void) const
Definition connend.cpp:169
ConnDirFlags directions(void) const
Returns the directions in which this connector endpoint should be given visibility.
Definition connend.cpp:137
void outputCode(FILE *fp, const char *srcDst) const
Definition connend.cpp:411
void disconnect(const bool shapeDeleted=false)
Definition connend.cpp:249
Obstacle * m_anchor_obj
Definition connend.h:254
void connect(ConnRef *conn)
Definition connend.cpp:237
void assignPinVisibilityTo(VertInf *dummyConnectionVert, VertInf *targetVert)
Definition connend.cpp:274
The ConnRef class represents a connector object.
Definition connector.h:132
void unInitialise(void)
void outputCode(FILE *fp) const
unsigned int id(void) const
Returns the ID of this connector.
void freeActivePins(void)
const PolyLine & route(void) const
Returns a reference to the current raw "debug" route for the connector.
std::vector< Point > possibleDstPinPoints(void) const
ConnType m_type
Definition connector.h:445
void makeInactive(void)
VertInf * dst(void) const
ConnType routingType(void) const
Returns the type of routing performed for this connector.
bool m_needs_repaint
Definition connector.h:449
ConnRef(Router *router, const unsigned int id=0)
Constructs a connector with no endpoints specified.
Definition connector.cpp:48
void removeFromGraph(void)
std::pair< JunctionRef *, ConnRef * > splitAtSegment(const size_t segmentN)
Splits a connector in the centre of the segmentNth segment and creates a junction point there as well...
std::vector< Checkpoint > routingCheckpoints(void) const
Returns the current set of routing checkpoints for this connector.
void setFixedRoute(const PolyLine &route)
Sets a fixed user-specified route for this connector.
std::vector< VertInf * > m_checkpoint_vertices
Definition connector.h:466
bool m_needs_reroute_flag
Definition connector.h:447
unsigned int m_id
Definition connector.h:444
VertInf * m_dst_vert
Definition connector.h:459
bool doesHateCrossings(void) const
void setSourceEndpoint(const ConnEnd &srcPoint)
Sets just a new source endpoint for this connector.
VertInf * m_start_vert
Definition connector.h:460
bool m_hate_crossings
Definition connector.h:452
void setEndpoint(const unsigned int type, const ConnEnd &connEnd)
PolyLine m_route
Definition connector.h:454
bool hasFixedRoute(void) const
Returns whether the connector route is marked as fixed.
std::vector< Checkpoint > m_checkpoints
Definition connector.h:465
void makePathInvalid(void)
bool generatePath(void)
VertInf * m_src_vert
Definition connector.h:458
bool needsRepaint(void) const
Returns an indication of whether this connector has a new route and thus needs to be repainted.
ConnRefList::iterator m_connrefs_pos
Definition connector.h:457
void performCallback(void)
void setHateCrossings(bool value)
void calcRouteDist(void)
std::pair< Obstacle *, Obstacle * > endpointAnchors(void) const
void setDestEndpoint(const ConnEnd &dstPoint)
Sets just a new destination endpoint for this connector.
void common_updateEndPoint(const unsigned int type, ConnEnd connEnd)
void setRoutingCheckpoints(const std::vector< Checkpoint > &checkpoints)
Allows the user to specify a set of checkpoints that this connector will route via.
void clearFixedRoute(void)
Returns the connector to being automatically routed if it was marked as fixed.
void setCallback(void(*cb)(void *), void *ptr)
Sets a callback function that will called to indicate that the connector needs rerouting.
bool isInitialised(void) const
VertInf * start(void)
Polygon m_display_route
Definition connector.h:455
bool m_has_fixed_route
Definition connector.h:453
PolyLine & routeRef(void)
void setFixedExistingRoute(void)
Sets a fixed existing route for this connector.
VertInf * src(void) const
PolyLine & displayRoute(void)
Returns a reference to the current display version of the route for the connector.
friend class JunctionRef
Definition connector.h:417
std::pair< ConnEnd, ConnEnd > endpointConnEnds(void) const
Returns ConnEnds specifying what this connector is attached to.
~ConnRef()
Connector reference destuctor.
friend class ConnEnd
Definition connector.h:416
Router * m_router
Definition connector.h:443
Router * router(void) const
Returns a pointer to the router scene this connector is in.
void makeActive(void)
void setRoutingType(ConnType type)
Sets the type of routing to be performed for this connector.
void(* m_callback_func)(void *)
Definition connector.h:461
void * m_connector
Definition connector.h:462
void generateCheckpointsPath(std::vector< Point > &path, std::vector< VertInf * > &vertices)
ConnEnd * m_dst_connend
Definition connector.h:464
void setEndpoints(const ConnEnd &srcPoint, const ConnEnd &dstPoint)
Sets both a new source and destination endpoint for this connector.
bool * m_reroute_flag_ptr
Definition connector.h:446
void generateStandardPath(std::vector< Point > &path, std::vector< VertInf * > &vertices)
bool getConnEndForEndpointVertex(VertInf *vertex, ConnEnd &connEnd) const
void freeRoutes(void)
double m_route_dist
Definition connector.h:456
ConnEnd * m_src_connend
Definition connector.h:463
void set_route(const PolyLine &route)
void updateEndPoint(const unsigned int type, const ConnEnd &connEnd)
std::pair< bool, bool > assignConnectionPinVisibility(const bool connect)
bool * addConn(ConnRef *conn)
Definition router.cpp:3097
void removeConn(ConnRef *conn)
Definition router.cpp:3103
Avoid::Polygon & poly
Definition connector.h:521
unsigned int crossingFlags
Definition connector.h:529
ConnectorCrossings(Avoid::Polygon &poly, bool polyIsConn, Avoid::Polygon &conn, ConnRef *polyConnRef=nullptr, ConnRef *connConnRef=nullptr)
Avoid::Polygon & conn
Definition connector.h:523
void countForSegment(size_t cIndex, const bool finalSegment)
SharedPathList * sharedPaths
Definition connector.h:532
unsigned int crossingCount
Definition connector.h:528
virtual void updateConnectorRoute(ConnRef *conn, int index1, int index2)
void addConn(bool *flag)
Definition graph.cpp:329
void setDist(double dist)
Definition graph.cpp:259
static EdgeInf * existingEdge(VertInf *i, VertInf *j)
Definition graph.cpp:622
The JunctionRef class represents a fixed or free-floating point that connectors can be attached to.
Definition junction.h:58
void preferOrthogonalDimension(const size_t dim)
Definition junction.cpp:96
The Point class defines a point in the plane.
Definition geomtypes.h:53
unsigned short vn
The vertex number associated with this point.
Definition geomtypes.h:113
double y
The y position.
Definition geomtypes.h:109
double x
The x position.
Definition geomtypes.h:107
unsigned int id
The ID associated with this point.
Definition geomtypes.h:111
A dynamic Polygon, to which points can be easily added and removed.
Definition geomtypes.h:208
Polygon simplify(void) const
Returns a simplified Polyline, where all collinear line segments have been collapsed down into single...
size_t size(void) const
Returns the number of points in this polygon.
bool empty(void) const
Returns true if this polygon is empty.
std::vector< Point > ps
A vector of the points that make up the Polygon.
Definition geomtypes.h:285
void clear(void)
Resets this to the empty polygon.
const Point & at(size_t index) const
Returns a specific point in the polygon.
void sort(const size_t dim)
void addPoints(const size_t dim, const PtConnPtrPair &arg1, const PtConnPtrPair &arg2)
size_t insertPoint(const size_t dim, const PtConnPtrPair &point)
int positionFor(const size_t dim, const ConnRef *conn)
PointRepVector sortedConnVector[2]
Definition connector.h:494
NodeIndexPairLinkList links[2]
Definition connector.h:493
PointRepVector sortedPoints(const size_t dim)
bool sorted[2]
Definition connector.h:491
PointRepVector nodes[2]
Definition connector.h:492
void addOrderedPoints(const size_t dim, const PtConnPtrPair &innerArg, const PtConnPtrPair &outerArg, bool swapped)
The Router class represents a libavoid router instance.
Definition router.h:386
unsigned int assignId(const unsigned int suggestedId)
Definition router.cpp:807
bool InvisibilityGrph
Definition router.h:418
void addJunction(JunctionRef *junction)
Definition router.cpp:659
VertInfList vertices
Definition router.h:408
void modifyConnector(ConnRef *conn)
Definition router.cpp:202
DebugHandler * debugHandler(void) const
Definition router.cpp:153
ConnType validConnType(const ConnType select=ConnType_None) const
Definition router.cpp:1969
void setStaticGraphInvalidated(const bool invalidated)
Definition router.cpp:403
void registerSettingsChange(void)
Definition router.cpp:2066
ConnRerouteFlagDelegate m_conn_reroute_flags
Definition router.h:860
ConnRefList connRefs
Definition router.h:402
bool processTransaction(void)
Finishes the current transaction and processes all the queued object changes efficiently.
Definition router.cpp:640
bool m_allows_polyline_routing
Definition router.h:870
bool m_currently_calling_destructors
Definition router.h:856
bool RubberBandRouting
Definition router.h:424
void removeObjectFromQueuedActions(const void *object)
Definition router.cpp:238
bool IgnoreRegions
Definition router.h:416
static const unsigned short tar
Definition vertices.h:60
static const VertIDProps PROP_DummyPinHelper
Definition vertices.h:66
static const VertIDProps PROP_ConnCheckpoint
Definition vertices.h:65
static const unsigned short src
Definition vertices.h:59
void db_print(void) const
Definition vertices.cpp:132
unsigned short vn
Definition vertices.h:55
bool isConnPt(void) const
Definition vertices.h:87
bool isConnCheckpoint(void) const
Definition vertices.h:95
bool isConnectionPin(void) const
Definition vertices.h:91
unsigned int objID
Definition vertices.h:54
static const VertIDProps PROP_ConnPoint
Definition vertices.h:62
VertInf * getVertexByID(const VertID &id)
Definition vertices.cpp:660
VertInf * removeVertex(VertInf *vert)
Definition vertices.cpp:557
VertInf * shNext
Definition vertices.h:148
VertInf * pathNext
Definition vertices.h:155
void setVisibleDirections(const ConnDirFlags directions)
Definition vertices.cpp:320
ConnDirFlags visDirections
Definition vertices.h:166
void removeFromGraph(const bool isConnVert=true)
Definition vertices.cpp:228
VertInf * shPrev
Definition vertices.h:147
unsigned int pathLeadsBackTo(const VertInf *start) const
Definition vertices.cpp:357
void Reset(const VertID &vid, const Point &vpoint)
Definition vertices.cpp:204
double inner(valarray< double > const &x, valarray< double > const &y)
Contains the interface for the ConnRef class.
Contains the interface for the ConnEnd class.
Css & result
Geom::IntPoint size
double c[8][4]
Contains the interface for the JunctionRef class.
Geom::Point start
Geom::Point end
libavoid: Object-avoiding orthogonal and polyline connector routing library.
const unsigned int CROSSING_NONE
Definition connector.h:501
void db_printf(const char *fmt,...)
Definition debug.h:53
double manhattanDist(const Point &a, const Point &b)
Definition geometry.cpp:302
int segmentIntersectPoint(const Point &a1, const Point &a2, const Point &b1, const Point &b2, double *x, double *y)
Definition geometry.cpp:476
bool validateBendPoint(VertInf *aInf, VertInf *bInf, VertInf *cInf)
static const int DO_INTERSECT
Definition geometry.h:117
Point midpoint(Point a, Point b)
ConnType
Describes the type of routing that is performed for each connector.
Definition connector.h:53
@ ConnType_Orthogonal
The connector path will be a shortest-path orthogonal poly-line (only vertical and horizontal line se...
Definition connector.h:61
@ ConnType_PolyLine
The connector path will be a shortest-path poly-line that routes around obstacles.
Definition connector.h:57
static double pathLength(Avoid::Point **c_path, Avoid::Point **p_path, size_t size)
static const unsigned short kUnassignedVertexNumber
Constant value representing an unassigned vertex number.
Definition geomtypes.h:120
std::pair< Point *, ConnRef * > PtConnPtrPair
Definition connector.h:470
static const size_t XDIM
Definition geomtypes.h:42
const unsigned int CROSSING_SHARES_PATH_AT_END
Definition connector.h:504
static int midVertexNumber(const Point &p0, const Point &p1, const Point &c)
void vertexVisibility(VertInf *point, VertInf *partner, bool knownNew, const bool gen_contains)
const unsigned int CROSSING_SHARES_PATH
Definition connector.h:503
static int segDir(const Point &p1, const Point &p2)
double euclideanDist(const Point &a, const Point &b)
Definition geometry.cpp:292
unsigned short VertIDProps
Definition vertices.h:48
static int vecDir(const Point &a, const Point &b, const Point &c, const double maybeZero=0.0)
Definition geometry.h:79
const unsigned int CROSSING_SHARES_FIXED_SEGMENT
Definition connector.h:505
std::vector< Avoid::Point > PointList
Definition connector.h:509
void err_printf(const char *fmt,...)
Definition debug.h:78
const unsigned int CROSSING_TOUCHES
Definition connector.h:502
static const size_t YDIM
Definition geomtypes.h:43
@ ConnDirNone
Definition connend.h:63
@ ConnDirAll
This option, provided for convenience, specifies the point should be given visibility to all four sid...
Definition connend.h:79
std::vector< PtConnPtrPair > PointRepVector
Definition connector.h:472
bool pointOnLine(const Point &a, const Point &b, const Point &c, const double tolerance)
Definition geometry.cpp:105
int cornerSide(const Point &c1, const Point &c2, const Point &c3, const Point &p)
Definition geometry.cpp:261
void splitBranchingSegments(Avoid::Polygon &poly, bool polyIsConn, Avoid::Polygon &conn, const double tolerance)
static bool posInlineWithConnEndSegs(const double pos, const size_t dim, const Avoid::Polygon &poly, const Avoid::Polygon &conn)
double dist(const Point &a, const Point &b)
Definition geometry.cpp:310
Contains the interface for the Router class.
size_t degree
int index