Skip to content

Commit 807e2b3

Browse files
committed
Got the road angles configurable and kept the math fast
1 parent 2532708 commit 807e2b3

File tree

8 files changed

+68
-80
lines changed

8 files changed

+68
-80
lines changed

SEEME.png

-12.5 KB
Loading

include/Options.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@
1111
#include "cinder/gl/GlslProg.h"
1212

1313
struct RoadOptions {
14-
float highwayWidth = 20;
15-
float sidestreetWidth = 10;
16-
float sidestreetAngle = 0;
17-
float blockHeight = 200;
18-
float blockWidth = 100;
14+
uint8_t highwayWidth = 20;
15+
uint8_t sidestreetWidth = 10;
16+
int16_t sidestreetAngle1 = 0; // -180 - +180 degrees
17+
int16_t sidestreetAngle2 = 90; // -90 - +90 degrees
18+
uint16_t blockHeight = 200;
19+
uint16_t blockWidth = 100;
1920
};
2021

2122
struct BlockOptions {

include/Road.h

Lines changed: 0 additions & 30 deletions
This file was deleted.

include/RoadNetwork.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ class RoadNetwork {
4141
void buildSideStreets( const Options &options, CGAL::Polygon_set_2<ExactK> &paved );
4242
void buildBlocks( const Options &options );
4343

44+
CGAL::Polygon_2<ExactK> roadOutline( const ci::vec2 &a, const ci::vec2 &b, uint8_t width = 10 );
45+
4446
std::vector<ci::vec2> mPoints;
4547
std::vector<Block> mBlocks;
46-
std::vector<FlatShape> mShapes;
48+
std::vector<FlatShape> mRoadShapes;
4749
};

src/CityscapeApp.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,7 @@ void CityscapeApp::buildSky()
8383

8484
void CityscapeApp::setup()
8585
{
86-
mParams = params::InterfaceGl::create( "App parameters", ivec2( 180, 300 ) );
87-
// mParams->maximize( false );
86+
mParams = params::InterfaceGl::create( "App parameters", ivec2( 350, 700 ) );
8887

8988
resize();
9089

src/RoadNetwork.cpp

Lines changed: 48 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,18 @@
77
//
88

99
#include "RoadNetwork.h"
10-
#include "Road.h"
1110
#include "Lot.h"
12-
1311
#include "CinderCGAL.h"
12+
#include "GeometryHelpers.h"
1413

1514
using namespace ci;
15+
using namespace std;
1616

1717
void RoadNetwork::buildHighways( const Options &options, CGAL::Polygon_set_2<ExactK> &paved )
1818
{
19-
float roadWidth = 20.0;
20-
21-
std::vector<CGAL::Polygon_2<ExactK>> roads;
19+
vector<CGAL::Polygon_2<ExactK>> roads;
2220
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 ) );
2422
}
2523
// It's more efficient for CGAL to insert all at once:
2624
paved.join( roads.begin(), roads.end() );
@@ -29,77 +27,91 @@ void RoadNetwork::buildHighways( const Options &options, CGAL::Polygon_set_2<Exa
2927
// Add some secondary streets
3028
void RoadNetwork::buildSideStreets( const Options &options, CGAL::Polygon_set_2<ExactK> &paved )
3129
{
32-
// TODO:
33-
// - make roadway orientation configurable
34-
3530
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;
3732

3833
// Find the unpaved chunks to break up with streets
3934
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;
4338

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;
4641

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) );
5148
}
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) );
5456
}
5557

5658
CGAL::Polygon_set_2<ExactK> newStreets;
57-
// It's more efficient for CGAL to insert all at once:
5859
newStreets.join( roads.begin(), roads.end() );
59-
6060
// Find the intersection of the streets and block
61-
newStreets.intersection( *chunk );
62-
61+
newStreets.intersection( chunk );
6362
// Add those as new streets.
6463
paved.join( newStreets );
6564
}
66-
6765
}
6866

6967
// Should probably be called build the rest... a bit of a code smell here.
7068
void RoadNetwork::buildBlocks( const Options &options )
7169
{
7270
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;
7472

7573
buildHighways( options, paved );
7674
// TODO: Make this step optional
7775
buildSideStreets( options, paved );
7876

7977
// 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 ) );
8381
}
8482

8583
// Extract the final blocks
8684
unpavedShapes.clear();
8785
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;
9189

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 ) ) );
9391
}
9492
}
9593

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+
96108
void RoadNetwork::layout( const Options &options )
97109
{
98110
// Don't bother redoing the layout if we have an odd number of points.
99111
if ( mPoints.size() % 2 == 1 ) return;
100112

101113
mBlocks.clear();
102-
mShapes.clear();
114+
mRoadShapes.clear();
103115

104116
buildBlocks( options );
105117

@@ -112,7 +124,7 @@ void RoadNetwork::draw( const Options &options )
112124
{
113125
if ( options.drawRoads ) {
114126
gl::color( ColorA( 0.3f, 0.3f, 0.3f, 0.4f ) );
115-
for ( auto &shape : mShapes ) {
127+
for ( auto &shape : mRoadShapes ) {
116128
gl::draw( shape.mesh() );
117129
}
118130
}

xcode/CityMode.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,16 @@ void CityMode::addParams( ci::params::InterfaceGlRef params) {
1313

1414
// TODO: Don't redo layout on every change, set a timer to update every half
1515
// second or so.
16-
// params->addParam( "highwayWidth", &mOptions.road.highwayWidth )
17-
// .min( 10 ).max( 50 ).step( 1 ).updateFn( std::bind( &CityMode::layout, this ) );
18-
// params->addParam( "sidestreetWidth", &mOptions.road.sidestreetWidth )
19-
// .min( 10 ).max( 50 ).step( 1 ).updateFn( std::bind( &CityMode::layout, this ) );
16+
params->addParam( "highwayWidth", &mOptions.road.highwayWidth )
17+
.min( 10 ).max( 50 ).step( 1 ).updateFn( std::bind( &CityMode::layout, this ) );
18+
params->addParam( "sidestreetWidth", &mOptions.road.sidestreetWidth )
19+
.min( 10 ).max( 50 ).step( 1 ).updateFn( std::bind( &CityMode::layout, this ) );
20+
params->addParam( "highwayWidth", &mOptions.road.highwayWidth )
21+
.min( 10 ).max( 50 ).step( 1 ).updateFn( std::bind( &CityMode::layout, this ) );
22+
params->addParam( "sidestreetAngle1", &mOptions.road.sidestreetAngle1 )
23+
.min( -180 ).max( 180 ).step( 5 ).updateFn( std::bind( &CityMode::layout, this ) );
24+
params->addParam( "sidestreetAngle2", &mOptions.road.sidestreetAngle2 )
25+
.min( -90 ).max( 90 ).step( 15 ).updateFn( std::bind( &CityMode::layout, this ) );
2026
params->addParam( "blockWidth", &mOptions.road.blockWidth ).step( 5 )
2127
.min( 15 ).max( 400 ).updateFn( std::bind( &CityMode::layout, this ) );
2228
params->addParam( "blockHeight", &mOptions.road.blockHeight ).step( 5 )

xcode/Cityscape.xcodeproj/project.pbxproj

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@
103103
5FEFD9D81A92FB450093F109 /* Block.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Block.h; path = ../include/Block.h; sourceTree = "<group>"; };
104104
5FEFD9D91A92FB450093F109 /* Building.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Building.h; sourceTree = "<group>"; };
105105
5FEFD9DA1A92FB450093F109 /* Lot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Lot.h; path = ../include/Lot.h; sourceTree = "<group>"; };
106-
5FEFD9DB1A92FB450093F109 /* Road.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Road.h; path = ../include/Road.h; sourceTree = "<group>"; };
107106
87F1E1C66EC543B1852B8B39 /* Cityscape_Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Cityscape_Prefix.pch; path = ../xcode/Cityscape_Prefix.pch; sourceTree = "<group>"; };
108107
8D1107320486CEB800E47090 /* Cityscape.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Cityscape.app; sourceTree = BUILT_PRODUCTS_DIR; };
109108
ACB4D9448A764F68A540CED0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@@ -223,7 +222,6 @@
223222
5FA88B2B1C48B866008C1A4A /* CityMode.h */,
224223
5FA88B2E1C48B95F008C1A4A /* BlockMode.h */,
225224
5FA88B2F1C48B9A6008C1A4A /* BuildingMode.h */,
226-
5FEFD9DB1A92FB450093F109 /* Road.h */,
227225
498D89CB1B1C027300A962B5 /* RoadNetwork.h */,
228226
5FEFD9D81A92FB450093F109 /* Block.h */,
229227
5FEFD9DA1A92FB450093F109 /* Lot.h */,

0 commit comments

Comments
 (0)