-
Notifications
You must be signed in to change notification settings - Fork 0
/
StreetGraph.h
177 lines (144 loc) · 6.19 KB
/
StreetGraph.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#ifndef STREETGRAPH_H
#define STREETGRAPH_H
#include <QObject>
#include <QPointF>
#include <QSize>
#include <QMap>
#include "TensorField.h"
struct Node;
enum RoadType {
Principal,
Secondary
};
// Structure to store a road
struct Road {
int ID;
QVector<QPointF> segments;
int nodeID1;
int nodeID2;
RoadType type;
float straightLength;
float pathLength;
};
// Structure to store an intersection (node)
struct Node {
int ID;
QPointF position;
QVector<int> connectedNodeIDs;
QVector<int> connectedRoadIDs;
};
// Convenience typedefs
typedef QMap<int,Node>::iterator NodeMapIterator;
typedef QMap<int,Road>::iterator RoadMapIterator;
class StreetGraph : public QObject
{
Q_OBJECT
public:
// Construct a StreetGraph object within limits passed
explicit StreetGraph(QPointF bottomLeft, QPointF topRight, TensorField * field, float distSeparation, QObject *parent = 0);
// Create a random seed list
void createRandomSeedList(int numberOfSeeds, bool append);
// Create a random seed list that respect a certain density
void createDensityConstrainedSeedList(int numberOfSeeds, bool append);
// Create a list of seeds spread in a grid pattern on the region
int createGridSeedList(double separationDistance, bool append);
// Create a list of seeds following the method asked by the user in the UI
void generateSeedListWithUIMethod();
// Returns wether the point is too close from one of the existing seeds
bool pointRespectSeedSeparationDistance(QPointF point, float separationDistance);
// Compute the major hyperstreamlines from the stored tensor field
void computeMajorHyperstreamlines(bool clearStorage);
// Compute the street graph from the stored tensor field
void computeStreetGraph(bool clearStorage);
void computeStreetGraph2(bool clearStorage);
void computeStreetGraph3(bool clearStorage);
// 1 : doesn't check for segments being too long. Doesn't replant seeds
// 2 : Checks for segments being too long. Replants seeds
// 3 : Seeds grow in both directions
// Grow a road until it leaves the field, is too long, or other stopping condition
Node& growRoad(Road& road, Node& startNode, bool growInMajorDirection, bool growInOppositeDirection, bool useExceedLenStopCond);
// Grow a road and connects it to the first road it crosses
Node& growRoadAndConnect(Road& road, Node& startNode, bool growInMajorDirection, bool growInOppositeDirection, bool useExceedLenStopCond);
// Draw an image with major hyperstreamlines
QPixmap drawStreetGraph(bool showNodes, bool showSeeds);
// Draw the road network using the painter
void drawRoads(QPainter& painter, QSize imageSize);
// Clear the stored street graph (Nodes, Roads)
// Warning: Doesn't clear the seed list
void clearStoredStreetGraph();
// Set the tensor field to compute street graph from
void setTensorField(TensorField * field) {mTensorField = field;}
signals:
// Fired when a new image is drawn
void newStreetGraphImage(QPixmap);
public slots:
// Main function : compute and draw the street graph
void generateStreetGraph();
// Change method to initialize seeds
void changeSeedInitMethod(int index) {mSeedInitMethod = index;}
// Set the variable for drawing nodes or not
void setDrawNodes(bool drawNodes);
// Set the density variable
void setSeparationDistance(double separationDistance);
private:
// 1st condition: Reaching boundary
bool boundaryStoppingCondition(QPointF nextPosition);
// 2nd condition: Reaching a degenerate point
bool degeneratePointStoppingCondition(int i, int j);
// 3rd condition: Returning to origin
bool loopStoppingCondition(QPointF nextPosition, const QVector<QPointF> &segments);
// 4th condition: Exceeding user-defined max length
bool exceedingLengthStoppingCondition(const QVector<QPointF>& segments);
// 5th condition: Too close to other hyperstreamline
bool exceedingDensityStoppingCondition();
// Check if road is meeting another one. Find the closest point of the met road
bool meetsAnotherRoad(Road &road, int &intersectedRoadID, int &closestPointID, float minDistance);
// Check if road is meeting another one. Find the intersection of the two meeting road.
// The intersection isn't necessarily a point of the met road, unlike in meetsAnotherRoad().
bool meetsAnotherRoadAndFindIntersection(int roadID, QPointF nextPosition, int &intersectedRoadID,
int &closestPointID, QPointF &intersectionPoint);
// Tensor field
TensorField * mTensorField;
// Container for nodes
QMap<int,Node> mNodes;
// Container for roads
QMap<int,Road> mRoads;
// Container for seeds
QVector<QPointF> mSeeds;
// Height and width of the region
QSizeF mRegionSize;
// Coordinates of the bottom left point
QPointF mBottomLeft;
// Coordinates of the top right point
QPointF mTopRight;
// Last IDs for Nodes and Roads
int mLastNodeID;
int mLastRoadID;
// Distance for road density
float mSeparationDistance;
// Watermap
QImage mWatermap;
// Method to use for seed initialization
int mSeedInitMethod;
// Holds if nodes should be drawn in the street graph image
bool mDrawNodes;
};
// Overloads writing Road to std stream
std::ostream& operator<<(std::ostream& out, const Road r);
// Overloads writing Node to std stream
std::ostream& operator<<(std::ostream& out, const Node n);
// Overloads writing QPointF to std stream
std::ostream& operator<<(std::ostream& out, const QPointF p);
// Compute the length of a road
float computePathLength(const QVector<QPointF>& segments);
// Compute the length between the 2 endpoints of a road
float computeStraightLength(const QVector<QPointF>& segments);
// Compute det(AB, AM) which determines if M is in, on the left,
// or on the right of AB
float detPointLine(QPointF A, QPointF B, QPointF M);
// Compute determinant of V1 and V2 (2x2 matrix)
float det2D(QPointF V1, QPointF V2);
// Find the intersection point between segments AB and CD.
// If there isn't, a null QPointF is returned
QPointF computeIntersectionPoint(QPointF A, QPointF B, QPointF C, QPointF D);
#endif // STREETGRAPH_H