Adaptagrams
planarise.h
1 /*
2  * vim: ts=4 sw=4 et tw=0 wm=0
3  *
4  * libdialect - A library for computing DiAlEcT layouts:
5  * D = Decompose/Distribute
6  * A = Arrange
7  * E = Expand/Emend
8  * T = Transform
9  *
10  * Copyright (C) 2018 Monash University
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public
14  * License as published by the Free Software Foundation; either
15  * version 2.1 of the License, or (at your option) any later version.
16  * See the file LICENSE.LGPL distributed with the 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): Steve Kieffer <http://skieffer.info>
23 */
24 
25 #ifndef DIALECT_PLANARISE_H
26 #define DIALECT_PLANARISE_H
27 
28 #include <vector>
29 #include <utility>
30 
31 #include "libvpsc/rectangle.h"
32 
33 #include "libdialect/commontypes.h"
34 #include "libdialect/constraints.h"
35 
36 namespace dialect {
37 
38 struct Event;
39 
41 struct EdgeSegment {
42 
46  EdgeSegment(Node_SP node1, Node_SP node2);
47 
50  void setNewClosingNode(Node_SP u);
51 
54  std::pair<Event*, Event*> getEvents(void);
55 
58  void addSep(SepMatrix &m) const;
59 
63  double constCoord;
65  double lowerBound;
67  double upperBound;
69  Node_SP openingNode;
71  Node_SP closingNode;
72 
73 };
74 
75 enum class EventType {
76  // Note: It is actually important that they be in this order:
77  CLOSE, SUSTAIN, OPEN
78  // (See CompareActiveEvents function.)
79 };
80 
81 struct Event {
82 
84  Event(EdgeSegment *seg, Node_SP endpt, EventType type);
85 
88  Event(double varCoord, Node_SP node, EventType type);
89 
90  Node_SP getNode(void) { return endpt; }
91 
92  EdgeSegment *seg;
93  Node_SP endpt;
94  double constCoord;
95  double varCoord;
96  EventType type;
97  Event *companion;
98  double x(void);
99  double y(void);
100 };
101 
111 bool CompareActiveEvents(Event *a, Event *b);
112 
113 typedef std::vector<EdgeSegment*> EdgeSegments;
114 typedef std::vector<Event*> Events;
115 typedef std::vector<Nodes> NodeGroups;
116 
117 struct OrthoPlanariserOptions {
123  bool generateConstraints = true;
124 };
125 
131 public:
137  OrthoPlanariser(const Graph_SP &G) : m_givenGraph(G) {}
138 
139  /* Memory model:
140  *
141  * Many objects are allocated in the lifecycle of an OrthoPlanariser, but
142  * cleaning up is nevertheless quite simple.
143  *
144  * Among the three Graphs -- given, overlap-free, and planar -- the first
145  * and the last are the client's responsibility, since those are this object's
146  * input and output. The overlap-free graph is an intermediate workspace and
147  * should be destroyed, and it will be destroyed automatically, since all the
148  * allocated objects of which it is made -- Nodes, Edges, and the Graph itself --
149  * are managed solely by shared pointers.
150  *
151  * Apart from Graphs, Nodes, and Edges, we allocate EdgeSegments and Events.
152  *
153  * Events are always cleaned up before even exiting those methods that use them
154  * (namely computeNodeGroups and computeCrossings).
155  *
156  * In every place where an EdgeSegment is allocated (there are only two placed:
157  * buildSegments, and computeCrossings), a pointer is pushed into m_edgeSegments.
158  * Pointers are removed from that vector in only one place: the
159  * deleteSegments method; and here of course, it comes only after deleting those
160  * EdgeSegments to which they pointed. Therefore calling deleteSegments is all
161  * that is needed to free all EdgeSegments ever allocated. Since that is called
162  * at the end of the planarise method, there is nothing for the destructor to do.
163  */
164  ~OrthoPlanariser(void) {}
165 
167  void setOpts(const OrthoPlanariserOptions &opts) { m_opts = opts; }
168 
171  Graph_SP planarise(void) {
172  // There are two steps.
173  // (1) First we construct an overlap-free graph based on the given one.
174  // In this graph, there are no edge-overlaps, but there may still be edge-crossings.
175  removeEdgeOverlaps();
176  // (2) Then we construct a planar graph based on the overlap-free one.
177  // Here we remove any edge-crossings.
178  removeEdgeCrossings();
179  // There are some allocated EdgeSegment objects left over afterward.
180  // Clean them up now, since they are no longer needed.
181  deleteSegments();
182  // The planar graph is the result we produce for the client.
183  return m_planarGraph;
184  }
185 
186 private:
187 
194  void removeEdgeOverlaps(void);
200  void removeEdgeCrossings(void);
203  void buildSegments(Graph_SP G);
205  void deleteSegments(void);
213  NodeGroups computeNodeGroups(EdgeSegments segs);
222  Nodes computeCrossings(void);
223 
224  OrthoPlanariserOptions m_opts;
225 
226  EdgeSegments m_edgeSegments;
227 
228  Graph_SP m_givenGraph;
229  Graph_SP m_overlapFreeGraph;
230  Graph_SP m_planarGraph;
231 };
232 
233 
234 } // namespace dialect
235 
236 #endif // DIALECT_PLANARISE_H
void setOpts(const OrthoPlanariserOptions &opts)
Set the options.
Definition: planarise.h:167
OrthoPlanariser(const Graph_SP &G)
Standard constructor.
Definition: planarise.h:137
Node_SP openingNode
The node that sits at the end where the lower bound on the variable coordinate occurs: ...
Definition: planarise.h:69
double upperBound
The upper bound on the coordinate that does change:
Definition: planarise.h:67
bool CompareActiveEvents(Event *a, Event *b)
Definition: planarise.cpp:268
Represents an axis-aligned segment of an orthogonal connector route.
Definition: planarise.h:41
Graph_SP planarise(void)
Compute a planarisation of the given Graph.
Definition: planarise.h:171
double lowerBound
The lower bound on the coordinate that does change:
Definition: planarise.h:65
libdialect: A library for computing human-like orthogonal network (DiAlEcT) layouts.
Definition: cola.h:44
Definition: planarise.h:130
std::pair< Event *, Event * > getEvents(void)
Generate the two Events, in order, representing the opening and closing of this segment.
Definition: planarise.cpp:90
EdgeSegment(Node_SP node1, Node_SP node2)
Standard constructor.
Definition: planarise.cpp:48
Node_SP closingNode
The node that sits at the end where the upper bound on the variable coordinate occurs: ...
Definition: planarise.h:71
double constCoord
The value of the coordinate that does not change:
Definition: planarise.h:63
Dim
Indicates the x- or y-dimension.
Definition: rectangle.h:41
void setNewClosingNode(Node_SP u)
Substitute a new Node as the closing node of the segment. This is useful during our scan line process...
Definition: planarise.cpp:84
vpsc::Dim orientation
The orientation of the segment (horizontal or vertical):
Definition: planarise.h:61
void addSep(SepMatrix &m) const
Update a SepMatrix with a constraint requiring this segment to remain aligned and at least its curren...
Definition: planarise.cpp:98