7
7
//
8
8
9
9
#include " RoadNetwork.h"
10
- #include " Road.h"
11
10
#include " Lot.h"
12
-
13
11
#include " CinderCGAL.h"
12
+ #include " GeometryHelpers.h"
14
13
15
14
using namespace ci ;
15
+ using namespace std ;
16
16
17
17
void RoadNetwork::buildHighways ( const Options &options, CGAL::Polygon_set_2<ExactK> &paved )
18
18
{
19
- float roadWidth = 20.0 ;
20
-
21
- std::vector<CGAL::Polygon_2<ExactK>> roads;
19
+ vector<CGAL::Polygon_2<ExactK>> roads;
22
20
for ( uint i = 1 , size = mPoints .size (); i < size; i += 2 ) {
23
- roads.push_back ( polygonFrom<ExactK>( Road ( mPoints [i-1 ], mPoints [i], roadWidth ). outline ) );
21
+ roads.push_back ( roadOutline ( mPoints [i-1 ], mPoints [i], options. road . highwayWidth ) );
24
22
}
25
23
// It's more efficient for CGAL to insert all at once:
26
24
paved.join ( roads.begin (), roads.end () );
@@ -29,77 +27,91 @@ void RoadNetwork::buildHighways( const Options &options, CGAL::Polygon_set_2<Exa
29
27
// Add some secondary streets
30
28
void RoadNetwork::buildSideStreets ( const Options &options, CGAL::Polygon_set_2<ExactK> &paved )
31
29
{
32
- // TODO:
33
- // - make roadway orientation configurable
34
-
35
30
CGAL::Polygon_set_2<ExactK> unpaved;
36
- std:: list<CGAL::Polygon_with_holes_2<ExactK>> unpavedPwh;
31
+ list<CGAL::Polygon_with_holes_2<ExactK>> unpavedPwh;
37
32
38
33
// Find the unpaved chunks to break up with streets
39
34
unpaved.complement (paved);
40
- unpaved.polygons_with_holes ( std:: back_inserter ( unpavedPwh ) );
41
- for ( auto chunk = unpavedPwh. begin (); chunk != unpavedPwh. end (); ++chunk ) {
42
- if ( chunk-> is_unbounded () ) continue ;
35
+ unpaved.polygons_with_holes ( back_inserter ( unpavedPwh ) );
36
+ for ( auto chunk : unpavedPwh ) {
37
+ if ( chunk. is_unbounded () ) continue ;
43
38
44
- // TODO: this is begging to be moved into a function:
45
- // Create narrow roads to cover the bounding box
39
+ const std::vector<vec2> outlinePoints = polyLineFrom ( chunk. outer_boundary () ). getPoints ();
40
+ vector<CGAL::Polygon_2<ExactK>> roads;
46
41
47
- CGAL::Bbox_2 bounds = chunk->bbox ();
48
- std::vector<CGAL::Polygon_2<ExactK>> roads;
49
- for ( float y = bounds.ymin () + options.road .blockHeight ; y < bounds.ymax (); y += options.road .blockHeight ) {
50
- roads.push_back ( polygonFrom<ExactK>( Road ( vec2 ( bounds.xmin (), y ), vec2 ( bounds.xmax (), y ), options.road .sidestreetWidth ).outline ) );
42
+ // Create narrow roads to cover the bounding box
43
+ uint16_t angle = options.road .sidestreetAngle1 ;
44
+ vector<vec2> dividerPoints = computeDividers ( outlinePoints, angle * M_PI / 180.0 , options.road .blockHeight );
45
+ assert ( dividerPoints.size () % 2 == 0 );
46
+ for ( auto a = dividerPoints.cbegin (); a != dividerPoints.cend () ; ++a ) {
47
+ roads.push_back ( roadOutline ( *a, *( ++a ), options.road .sidestreetWidth ) );
51
48
}
52
- for ( float x = bounds.xmin () + options.road .blockWidth ; x < bounds.xmax (); x += options.road .blockWidth ) {
53
- roads.push_back ( polygonFrom<ExactK>( Road ( vec2 ( x, bounds.ymin () ), vec2 ( x, bounds.ymax () ), options.road .sidestreetWidth ).outline ) );
49
+
50
+ angle += options.road .sidestreetAngle2 ;
51
+ // TODO move duplicated logic to a function
52
+ dividerPoints = computeDividers ( outlinePoints, angle * M_PI / 180.0 , options.road .blockWidth );
53
+ assert ( dividerPoints.size () % 2 == 0 );
54
+ for ( auto a = dividerPoints.cbegin (); a != dividerPoints.cend () ; ++a ) {
55
+ roads.push_back ( roadOutline ( *a, *( ++a ), options.road .sidestreetWidth ) );
54
56
}
55
57
56
58
CGAL::Polygon_set_2<ExactK> newStreets;
57
- // It's more efficient for CGAL to insert all at once:
58
59
newStreets.join ( roads.begin (), roads.end () );
59
-
60
60
// Find the intersection of the streets and block
61
- newStreets.intersection ( *chunk );
62
-
61
+ newStreets.intersection ( chunk );
63
62
// Add those as new streets.
64
63
paved.join ( newStreets );
65
64
}
66
-
67
65
}
68
66
69
67
// Should probably be called build the rest... a bit of a code smell here.
70
68
void RoadNetwork::buildBlocks ( const Options &options )
71
69
{
72
70
CGAL::Polygon_set_2<ExactK> paved, unpaved;
73
- std:: list<CGAL::Polygon_with_holes_2<ExactK>> pavedShapes, unpavedShapes;
71
+ list<CGAL::Polygon_with_holes_2<ExactK>> pavedShapes, unpavedShapes;
74
72
75
73
buildHighways ( options, paved );
76
74
// TODO: Make this step optional
77
75
buildSideStreets ( options, paved );
78
76
79
77
// Get the expanded street network
80
- paved.polygons_with_holes ( std:: back_inserter ( pavedShapes ) );
81
- for ( auto it = pavedShapes. begin (); it != pavedShapes. end (); ++it ) {
82
- mShapes .push_back ( FlatShape ( * it ) );
78
+ paved.polygons_with_holes ( back_inserter ( pavedShapes ) );
79
+ for ( auto & it : pavedShapes ) {
80
+ mRoadShapes .push_back ( FlatShape ( it ) );
83
81
}
84
82
85
83
// Extract the final blocks
86
84
unpavedShapes.clear ();
87
85
unpaved.complement (paved);
88
- unpaved.polygons_with_holes ( std:: back_inserter ( unpavedShapes ) );
89
- for ( auto it = unpavedShapes. begin (); it != unpavedShapes. end (); ++it ) {
90
- if ( it-> is_unbounded () ) continue ;
86
+ unpaved.polygons_with_holes ( back_inserter ( unpavedShapes ) );
87
+ for ( auto & it : unpavedShapes ) {
88
+ if ( it. is_unbounded () ) continue ;
91
89
92
- mBlocks .push_back ( Block ( FlatShape ( * it ), ColorA ( 1.0 , 1.0 , 0.0 , 0.3 ) ) );
90
+ mBlocks .push_back ( Block ( FlatShape ( it ), ColorA ( 1.0 , 1.0 , 0.0 , 0.3 ) ) );
93
91
}
94
92
}
95
93
94
+ CGAL::Polygon_2<ExactK> RoadNetwork::roadOutline ( const ci::vec2 &a, const ci::vec2 &b, uint8_t width )
95
+ {
96
+ // It's much faster to do this math outside of CGAL.
97
+ ci::vec2 perpendicular = glm::normalize ( ci::vec2 ( b.y - a.y , -( b.x - a.x ) ) );
98
+ ci::vec2 offset = perpendicular * ci::vec2 ( width / 2.0 );
99
+
100
+ CGAL::Polygon_2<ExactK> results;
101
+ results.push_back ( pointFrom<ExactK>( b + offset ) );
102
+ results.push_back ( pointFrom<ExactK>( b - offset ) );
103
+ results.push_back ( pointFrom<ExactK>( a - offset ) );
104
+ results.push_back ( pointFrom<ExactK>( a + offset ) );
105
+ return results;
106
+ };
107
+
96
108
void RoadNetwork::layout ( const Options &options )
97
109
{
98
110
// Don't bother redoing the layout if we have an odd number of points.
99
111
if ( mPoints .size () % 2 == 1 ) return ;
100
112
101
113
mBlocks .clear ();
102
- mShapes .clear ();
114
+ mRoadShapes .clear ();
103
115
104
116
buildBlocks ( options );
105
117
@@ -112,7 +124,7 @@ void RoadNetwork::draw( const Options &options )
112
124
{
113
125
if ( options.drawRoads ) {
114
126
gl::color ( ColorA ( 0 .3f , 0 .3f , 0 .3f , 0 .4f ) );
115
- for ( auto &shape : mShapes ) {
127
+ for ( auto &shape : mRoadShapes ) {
116
128
gl::draw ( shape.mesh () );
117
129
}
118
130
}
0 commit comments