1 /*
2 * Copyright (C) 2010-2011 Dmitry Marakasov
3 *
4 * This file is part of glosm.
5 *
6 * glosm is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * glosm is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with glosm. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <glosm/GeometryGenerator.hh>
21
22 #include <glosm/OsmDatasource.hh>
23 #include <glosm/Geometry.hh>
24 #include <glosm/GeometryOperations.hh>
25 #include <glosm/geomath.h>
26
27 #include <list>
28 #include <cstdlib>
29 #include <cstdio>
30
31 typedef std::list<Vector2i> VertexList;
32 typedef std::vector<Vector2i> VertexVector;
33
CreateLines(Geometry & geom,const VertexVector & vertices,int z,const OsmDatasource::Way &)34 static void CreateLines(Geometry& geom, const VertexVector& vertices, int z, const OsmDatasource::Way& /*unused*/) {
35 for (unsigned int i = 1; i < vertices.size(); ++i)
36 geom.AddLine(Vector3i(vertices[i-1], z), Vector3i(vertices[i], z));
37 }
38
CreateVerticalLines(Geometry & geom,const VertexVector & vertices,int minz,int maxz,const OsmDatasource::Way & way)39 static void CreateVerticalLines(Geometry& geom, const VertexVector& vertices, int minz, int maxz, const OsmDatasource::Way& way) {
40 for (unsigned int i = way.Closed ? 1 : 0; i < vertices.size(); ++i)
41 geom.AddLine(Vector3i(vertices[i], minz), Vector3i(vertices[i], maxz));
42 }
43
CreateSmartVerticalLines(Geometry & geom,const VertexVector & vertices,int minz,int maxz,float minslope,const OsmDatasource::Way & way)44 static void CreateSmartVerticalLines(Geometry& geom, const VertexVector& vertices, int minz, int maxz, float minslope, const OsmDatasource::Way& way) {
45 double cosminslope = cos(minslope/180.0*M_PI);
46
47 if (vertices.size() < 2)
48 return CreateVerticalLines(geom, vertices, minz, maxz, way);
49
50 if (way.Closed) {
51 for (unsigned int i = 0; i < vertices.size() - 1; ++i) {
52 Vector3d to_prev = ToLocalMetric(vertices[i == 0 ? vertices.size() - 2 : i - 1], vertices[i]).Normalized();
53 Vector3d to_next = ToLocalMetric(vertices[i + 1], vertices[i]).Normalized();
54
55 if (fabs(to_prev.DotProduct(to_next)) < cosminslope)
56 geom.AddLine(Vector3i(vertices[i], minz), Vector3i(vertices[i], maxz));
57 }
58 } else {
59 for (unsigned int i = 1; i < vertices.size() - 1; ++i) {
60 Vector3d to_prev = ToLocalMetric(vertices[i - 1], vertices[i]).Normalized();
61 Vector3d to_next = ToLocalMetric(vertices[i + 1], vertices[i]).Normalized();
62
63 if (fabs(to_prev.DotProduct(to_next)) < cosminslope)
64 geom.AddLine(Vector3i(vertices[i], minz), Vector3i(vertices[i], maxz));
65 }
66 geom.AddLine(Vector3i(vertices.front(), minz), Vector3i(vertices.front(), maxz));
67 geom.AddLine(Vector3i(vertices.back(), minz), Vector3i(vertices.back(), maxz));
68 }
69 }
70
CreateWalls(Geometry & geom,const VertexVector & vertices,int minz,int maxz,const OsmDatasource::Way &)71 static void CreateWalls(Geometry& geom, const VertexVector& vertices, int minz, int maxz, const OsmDatasource::Way& /*unused*/) {
72 for (unsigned int i = 1; i < vertices.size(); ++i)
73 geom.AddQuad(Vector3i(vertices[i-1], minz), Vector3i(vertices[i-1], maxz), Vector3i(vertices[i], maxz), Vector3i(vertices[i], minz));
74 }
75
CreateWall(Geometry & geom,const VertexVector & vertices,int minz,int maxz,const OsmDatasource::Way &)76 static void CreateWall(Geometry& geom, const VertexVector& vertices, int minz, int maxz, const OsmDatasource::Way& /*unused*/) {
77 for (unsigned int i = 1; i < vertices.size(); ++i) {
78 geom.AddQuad(Vector3i(vertices[i-1], minz), Vector3i(vertices[i-1], maxz), Vector3i(vertices[i], maxz), Vector3i(vertices[i], minz));
79 geom.AddQuad(Vector3i(vertices[i-1], maxz), Vector3i(vertices[i-1], minz), Vector3i(vertices[i], minz), Vector3i(vertices[i], maxz));
80 }
81 }
82
CreateArea(Geometry & geom,const VertexVector & vertices,bool revorder,int z,const OsmDatasource::Way & way)83 static void CreateArea(Geometry& geom, const VertexVector& vertices, bool revorder, int z, const OsmDatasource::Way& way) {
84 if (vertices.size() < 3 || !way.Closed)
85 return;
86
87 VertexList vert;
88 for (VertexVector::const_iterator i = vertices.begin(); i != vertices.end(); ++i)
89 vert.push_back(*i);
90 vert.pop_back();
91
92 VertexList::iterator i0, i1, i2, o;
93 i0 = vert.begin();
94
95 /* quick & dirty triangulation for roofs
96 * this should be rewritten to support sprips and/or fans,
97 * and there should be no possibility of infinite loop,
98 * as well as this iteration counter
99 */
100 int iters = 1000;
101 while (vert.size() >= 3) {
102 if (++(i1 = i0) == vert.end())
103 i1 = vert.begin();
104 if (++(i2 = i1) == vert.end())
105 i2 = vert.begin();
106
107 osmlong_t area = 0;
108 area += (osmlong_t)i0->x*(osmlong_t)i1->y - (osmlong_t)i0->y*(osmlong_t)i1->x;
109 area += (osmlong_t)i1->x*(osmlong_t)i2->y - (osmlong_t)i1->y*(osmlong_t)i2->x;
110 area += (osmlong_t)i2->x*(osmlong_t)i0->y - (osmlong_t)i2->y*(osmlong_t)i0->x;
111
112 bool ok = true;
113 o = i2;
114 while (1) {
115 if (++o == vert.end())
116 o = vert.begin();
117
118 if (o == i0)
119 break;
120
121 if (Vector2l(*o).IsInTriangle(*i0, *i1, *i2)) {
122 ok = false;
123 break;
124 }
125 }
126
127 if ((area < 0) && ok) {
128 if (revorder)
129 geom.AddTriangle(Vector3i(*i0, z), Vector3i(*i1, z), Vector3i(*i2, z));
130 else
131 geom.AddTriangle(Vector3i(*i0, z), Vector3i(*i2, z), Vector3i(*i1, z));
132
133 vert.erase(i1);
134 }
135
136 if (++i0 == vert.end())
137 i0 = vert.begin();
138
139 if (--iters == 0) {
140 /* FIXME: add way ID here, lacks interface to datasource */
141 fprintf(stderr, "warning: triangulation failed: giving up on %d/%d points\n", vert.size(), vertices.size());
142 return;
143 }
144 }
145 }
146
CreateRoof(Geometry & geom,const VertexVector & vertices,int z,const OsmDatasource::Way & way)147 static void CreateRoof(Geometry& geom, const VertexVector& vertices, int z, const OsmDatasource::Way& way) {
148 float slope = 30.0;
149 bool along = true;
150
151 OsmDatasource::TagsMap::const_iterator shape, tag;
152
153 if ((tag = way.Tags.find("building:roof:angle")) != way.Tags.end())
154 slope = strtof(tag->second.c_str(), NULL);
155 if ((tag = way.Tags.find("building:roof:orientation")) != way.Tags.end() && tag->second == "across")
156 along = false;
157
158 std::vector<Vector3i> vert;
159 vert.reserve(vertices.size());
160 for (VertexVector::const_iterator i = vertices.begin(); i != vertices.end(); ++i)
161 vert.push_back(Vector3i(*i, z));
162
163 if (vert.size() > 3 && way.Closed &&
164 (shape = way.Tags.find("building:roof:shape")) != way.Tags.end() &&
165 (shape->second == "pyramidal" || shape->second == "conical")
166 ) {
167 /* calculate center */
168 Vector3l center;
169 for (unsigned int i = 0; i < vert.size() - 1; i++)
170 center += Vector3i(vert[i]);
171 center /= vert.size() - 1;
172
173 /* calculate mean face length */
174 float facelength = 0.0;
175 for (unsigned int i = 0; i < vert.size() - 1; i++)
176 facelength += (ToLocalMetric(vert[i], center)/2.0 + ToLocalMetric(vert[i+1], center)/2.0).Length();
177 facelength /= vert.size() - 1;
178
179 center.z += (tan(slope/180.0*M_PI) * facelength) * GEOM_UNITSINMETER;
180
181 for (unsigned int i = 0; i < vert.size() - 1; i++) {
182 geom.AddTriangle(vert[i], center, vert[i+1]);
183 geom.AddLine(vert[i], center);
184 }
185 return;
186 }
187
188 /* only 4-vert buildings are supported for other types, yet */
189 if (vert.size() == 5 && way.Closed && (shape = way.Tags.find("building:roof:shape")) != way.Tags.end()) {
190 float length1 = ToLocalMetric(vert[0], vert[1]).Length();
191 float length2 = ToLocalMetric(vert[1], vert[2]).Length();
192
193 if (shape->second == "pyramidal") {
194 Vector3i center = ((Vector3l)vert[0] + (Vector3l)vert[1] + (Vector3l)vert[2] + (Vector3l)vert[3]) / 4;
195 center.z += (tan(slope/180.0*M_PI) * std::min(length1, length2) * 0.5) * GEOM_UNITSINMETER;
196
197 for (int i = 0; i < 4; i++) {
198 geom.AddTriangle(vert[i], center, vert[i+1]);
199 geom.AddLine(vert[i], center);
200 }
201 return;
202 } else if (shape->second == "pitched") {
203 if (!!(length1 < length2) ^ !along) {
204 osmint_t height = (tan(slope/180.0*M_PI) * length1 * 0.5) * GEOM_UNITSINMETER;
205
206 Vector3i center1 = ((Vector3l)vert[0] + (Vector3l)vert[1])/2;
207 Vector3i center2 = ((Vector3l)vert[2] + (Vector3l)vert[3])/2;
208
209 center1.z += height;
210 center2.z += height;
211
212 geom.AddTriangle(vert[0], center1, vert[1]);
213 geom.AddTriangle(vert[2], center2, vert[3]);
214 geom.AddQuad(vert[2], vert[1], center1, center2);
215 geom.AddQuad(vert[0], vert[3], center2, center1);
216
217 geom.AddLine(vert[0], center1); geom.AddLine(center1, vert[1]);
218 geom.AddLine(vert[2], center2); geom.AddLine(center2, vert[3]);
219 geom.AddLine(center1, center2);
220 } else {
221 osmint_t height = (tan(slope/180.0*M_PI) * length2 * 0.5) * GEOM_UNITSINMETER;
222
223 Vector3i center1 = ((Vector3l)vert[1] + (Vector3l)vert[2])/2;
224 Vector3i center2 = ((Vector3l)vert[0] + (Vector3l)vert[3])/2;
225
226 center1.z += height;
227 center2.z += height;
228
229 geom.AddTriangle(vert[1], center1, vert[2]);
230 geom.AddTriangle(vert[3], center2, vert[0]);
231 geom.AddQuad(vert[1], vert[0], center2, center1);
232 geom.AddQuad(vert[3], vert[2], center1, center2);
233
234 geom.AddLine(vert[1], center1); geom.AddLine(center1, vert[2]);
235 geom.AddLine(vert[3], center2); geom.AddLine(center2, vert[0]);
236 geom.AddLine(center1, center2);
237 }
238 return;
239 } else if (shape->second == "hipped") {
240 if (length1 < length2) {
241 osmint_t height = (tan(slope/180.0*M_PI) * length1 * 0.5) * GEOM_UNITSINMETER;
242
243 Vector3i center1 = ((Vector3l)vert[0] + (Vector3l)vert[1])/2;
244 Vector3i center2 = ((Vector3l)vert[2] + (Vector3l)vert[3])/2;
245
246 Vector3i delta = FromLocalMetric(ToLocalMetric(center2, center1).Normalized() * ToLocalMetric(vert[0], center1).Length(), center1) - center1;
247
248 center1 += delta;
249 center2 -= delta;
250
251 center1.z += height;
252 center2.z += height;
253
254 geom.AddTriangle(vert[0], center1, vert[1]);
255 geom.AddTriangle(vert[2], center2, vert[3]);
256 geom.AddQuad(vert[2], vert[1], center1, center2);
257 geom.AddQuad(vert[0], vert[3], center2, center1);
258
259 geom.AddLine(vert[0], center1); geom.AddLine(center1, vert[1]);
260 geom.AddLine(vert[2], center2); geom.AddLine(center2, vert[3]);
261 geom.AddLine(center1, center2);
262 } else {
263 osmint_t height = (tan(slope/180.0*M_PI) * length2 * 0.5) * GEOM_UNITSINMETER;
264
265 Vector3i center1 = ((Vector3l)vert[1] + (Vector3l)vert[2])/2;
266 Vector3i center2 = ((Vector3l)vert[0] + (Vector3l)vert[3])/2;
267
268 Vector3i delta = FromLocalMetric(ToLocalMetric(center2, center1).Normalized() * ToLocalMetric(vert[1], center1).Length(), center1) - center1;
269
270 center1 += delta;
271 center2 -= delta;
272
273 center1.z += height;
274 center2.z += height;
275
276 geom.AddTriangle(vert[1], center1, vert[2]);
277 geom.AddTriangle(vert[3], center2, vert[0]);
278 geom.AddQuad(vert[1], vert[0], center2, center1);
279 geom.AddQuad(vert[3], vert[2], center1, center2);
280
281 geom.AddLine(vert[1], center1); geom.AddLine(center1, vert[2]);
282 geom.AddLine(vert[3], center2); geom.AddLine(center2, vert[0]);
283 geom.AddLine(center1, center2);
284 }
285 return;
286 } else if (shape->second == "crosspitched") {
287 int height = (tan(slope/180.0*M_PI) * std::min(length1, length2) * 0.5) * GEOM_UNITSINMETER;
288
289 Vector3i center = ((Vector3l)vert[0] + (Vector3l)vert[1] + (Vector3l)vert[2] + (Vector3l)vert[3]) / 4;
290 center.z += height;
291
292 for (int i = 0; i < 4; ++i) {
293 Vector3i sidecenter = ((Vector3l)vert[i] + (Vector3l)vert[i+1]) / 2;
294 sidecenter.z += height;
295
296 geom.AddTriangle(vert[i], center, sidecenter);
297 geom.AddTriangle(center, vert[i+1], sidecenter);
298 geom.AddTriangle(vert[i+1], vert[i], sidecenter);
299
300 geom.AddLine(sidecenter, center);
301 geom.AddLine(sidecenter, vert[i]);
302 geom.AddLine(sidecenter, vert[i+1]);
303 geom.AddLine(vert[i], center);
304 }
305 return;
306 }
307 }
308
309 /* fallback - flat roof */
310 return CreateArea(geom, vertices, false, z, way);
311 }
312
CreateRoad(Geometry & geom,const VertexVector & vertices,float width,const OsmDatasource::Way &)313 static void CreateRoad(Geometry& geom, const VertexVector& vertices, float width, const OsmDatasource::Way& /*unused*/) {
314 if (vertices.size() < 2)
315 return;
316
317 VertexVector::const_iterator prev = vertices.end();
318 VertexVector::const_iterator next;
319 Vector2i prev_points[2];
320 Vector2i new_points[2];
321 for (VertexVector::const_iterator i = vertices.begin(); i != vertices.end(); i++) {
322 ++(next = i);
323
324 Vector3d to_prev, to_next;
325
326 if (next != vertices.end()) {
327 to_next = ToLocalMetric(*next, *i).Normalized();
328 if (prev != vertices.end())
329 to_prev = ToLocalMetric(*prev, *i).Normalized();
330 else
331 to_prev = -to_next;
332 } else {
333 to_prev = ToLocalMetric(*prev, *i).Normalized();
334 to_next = -to_prev;
335 }
336
337 Vector3d normside = to_next.CrossProduct(Vector3d(0.0, 0.0, 1.0));
338 Vector3d side = normside * width / 2.0;
339
340 Vector3d bisect = to_prev + to_next;
341 double cosangle = to_next.DotProduct(to_prev);
342
343 if (cosangle > 0.99) {
344 /* FIXME: add way ID here, lacks interface to datasource */
345 fprintf(stderr, "warning: too sharp road turn (cos=%f), likely data error\n", cosangle);
346 prev = i;
347 continue;
348 }
349
350 if (bisect.Length() < 0.001) { /* constant == sin(alpha/2), where alpha is minimal angle to consider joint non-straight */
351 /* almost straight segment, just use normals */
352 new_points[0] = FromLocalMetric(-side, *i);
353 new_points[1] = FromLocalMetric(side, *i);
354 } else {
355 bisect = bisect.Normalized() * (width / 2.0) / sin(acos(cosangle) / 2.0);
356
357 if (bisect.Normalized().DotProduct(normside) < 0.0) {
358 new_points[0] = FromLocalMetric(bisect, *i);
359 new_points[1] = FromLocalMetric(-bisect, *i);
360 } else {
361 new_points[0] = FromLocalMetric(-bisect, *i);
362 new_points[1] = FromLocalMetric(bisect, *i);
363 }
364 }
365
366 if (prev != vertices.end())
367 geom.AddQuad(prev_points[0], prev_points[1], new_points[1], new_points[0]);
368
369 prev_points[0] = new_points[0];
370 prev_points[1] = new_points[1];
371
372 prev = i;
373 }
374 }
375
GetMaxHeight(const OsmDatasource::Way & way)376 static float GetMaxHeight(const OsmDatasource::Way& way) {
377 OsmDatasource::TagsMap::const_iterator building, tag;
378
379 if ((tag = way.Tags.find("building:part:height")) != way.Tags.end()) {
380 /* building:part:height is topmost precedence (hack for Ostankino tower) */
381 return strtof(tag->second.c_str(), NULL);
382 } else if ((tag = way.Tags.find("height")) != way.Tags.end()) {
383 /* explicit height - topmost precedence in all other cases */
384 return strtof(tag->second.c_str(), NULL);
385 } else if ((tag = way.Tags.find("building:levels")) != way.Tags.end()) {
386 /* count level heights as 3 meters */
387 int levels = strtol(tag->second.c_str(), NULL, 10);
388 float h = 3.0 * levels;
389
390 /* also add 1 meter for basement for short buildings
391 * (except for garages which doesn't have one) - should work
392 * well in rural areas */
393 if (levels == 1 && (building = way.Tags.find("building")) != way.Tags.end() && building->second != "garages" && building->second != "garage")
394 h += 1.0;
395
396 return h;
397 }
398
399 return 0.0;
400 }
401
GetMinHeight(const OsmDatasource::Way & way)402 static float GetMinHeight(const OsmDatasource::Way& way) {
403 OsmDatasource::TagsMap::const_iterator building, tag, tag1;
404
405 if ((tag = way.Tags.find("min_height")) != way.Tags.end()) {
406 /* explicit height - topmost precedence in all other cases */
407 return strtof(tag->second.c_str(), NULL);
408 } else if ((tag = way.Tags.find("building:min_level")) != way.Tags.end() || (tag = way.Tags.find("building:skipped_levels")) != way.Tags.end()) {
409 /* count level heights as 3 meters */
410 float h = 3.0 * strtol(tag->second.c_str(), NULL, 10);
411
412 /* in building:min_level scheme, levels are counted from zero, which may be fixed by building:ground_level... */
413 if (tag->first == "building:min_level" && (tag1 = way.Tags.find("building:ground_level")) != way.Tags.end())
414 h -= 3.0 * strtol(tag1->second.c_str(), NULL, 10);
415 /* ...while in my proposal (building:skipped_levels) everythng just works */
416
417 return h;
418 }
419
420 return 0.0;
421 }
422
GetHighwayLanes(const std::string & highway,const OsmDatasource::Way & way)423 static int GetHighwayLanes(const std::string& highway, const OsmDatasource::Way& way) {
424 OsmDatasource::TagsMap::const_iterator tag;
425
426 /* explicitely tagged lanes have top */
427 if ((tag = way.Tags.find("lanes")) != way.Tags.end())
428 return strtol(tag->second.c_str(), NULL, 10);
429
430 bool oneway = false;
431 if ((tag = way.Tags.find("oneway")) != way.Tags.end() && tag->second != "no")
432 oneway = true;
433
434 /* motorway assumes one-way */
435 if (highway == "motorway" || highway == "motorway_link")
436 oneway = true;
437
438 if (highway == "service" || highway == "track") {
439 return 1;
440 } else if (highway == "residential") {
441 return 2;
442 } else {
443 return oneway ? 2 : 4;
444 }
445 }
446
GetHighwayWidth(const std::string & highway,const OsmDatasource::Way & way)447 static float GetHighwayWidth(const std::string& highway, const OsmDatasource::Way& way) {
448 OsmDatasource::TagsMap::const_iterator tag;
449
450 /* explicitely tagged lanes have top */
451 if ((tag = way.Tags.find("width")) != way.Tags.end())
452 return strtof(tag->second.c_str(), NULL);
453
454 if (highway == "path") {
455 return 0.5f;
456 } else if (highway == "footway" || highway == "steps") {
457 return 2.0f;
458 } else if (highway == "pedestrian") {
459 return 3.0f;
460 } else {
461 return GetHighwayLanes(highway, way) * 3.5f; /* likely 4 is closer to truth */
462 }
463 }
464
WayDispatcher(Geometry & geom,const OsmDatasource & datasource,int flags,const OsmDatasource::Way & way)465 static void WayDispatcher(Geometry& geom, const OsmDatasource& datasource, int flags, const OsmDatasource::Way& way) {
466 osmint_t minz = GetMinHeight(way) * GEOM_UNITSINMETER;
467 osmint_t maxz = GetMaxHeight(way) * GEOM_UNITSINMETER;
468
469 if (minz < 0)
470 minz = 0;
471 if (maxz < minz) {
472 fprintf(stderr, "warning: max height < min height for object\n");
473 maxz = minz = 0;
474 }
475
476 OsmDatasource::TagsMap::const_iterator t;
477
478 VertexVector vertices;
479 vertices.reserve(way.Nodes.size());
480
481 if (way.Clockwise)
482 for (OsmDatasource::Way::NodesList::const_iterator n = way.Nodes.begin(); n != way.Nodes.end(); ++n)
483 vertices.push_back(datasource.GetNode(*n).Pos);
484 else
485 for (OsmDatasource::Way::NodesList::const_reverse_iterator n = way.Nodes.rbegin(); n != way.Nodes.rend(); ++n)
486 vertices.push_back(datasource.GetNode(*n).Pos);
487
488 /* dispatch */
489 if ((way.Tags.find("building") != way.Tags.end() || way.Tags.find("building:part") != way.Tags.end()) && minz != maxz) {
490 if (flags & GeometryDatasource::DETAIL) {
491 CreateWalls(geom, vertices, minz, maxz, way);
492 CreateRoof(geom, vertices, maxz, way);
493
494 CreateLines(geom, vertices, minz, way);
495 CreateLines(geom, vertices, maxz, way);
496 CreateSmartVerticalLines(geom, vertices, minz, maxz, 5.0, way);
497
498 if (minz > 1) {
499 CreateArea(geom, vertices, true, minz, way);
500 CreateLines(geom, vertices, minz, way);
501 }
502 }
503 } else if ((t = way.Tags.find("man_made")) != way.Tags.end() && (t->second == "tower" || t->second == "chimney") && minz != maxz) {
504 if (flags & GeometryDatasource::DETAIL) {
505 CreateWalls(geom, vertices, minz, maxz, way);
506 CreateArea(geom, vertices, false, maxz, way);
507
508 CreateLines(geom, vertices, minz, way);
509 CreateLines(geom, vertices, maxz, way);
510 CreateSmartVerticalLines(geom, vertices, minz, maxz, 5.0, way);
511 }
512 } else if (way.Tags.find("barrier") != way.Tags.end()) {
513 if (flags & GeometryDatasource::DETAIL) {
514 if (maxz == minz)
515 maxz += 2 * GEOM_UNITSINMETER;
516 CreateWall(geom, vertices, minz, maxz, way);
517
518 CreateLines(geom, vertices, minz, way);
519 CreateLines(geom, vertices, maxz, way);
520 CreateVerticalLines(geom, vertices, minz, maxz, way);
521 }
522 } else if ((t = way.Tags.find("highway")) != way.Tags.end()) {
523 if (flags & GeometryDatasource::DETAIL) {
524 OsmDatasource::TagsMap::const_iterator t1;
525
526 if ((t1 = way.Tags.find("area")) != way.Tags.end() && t1->second != "no") {
527 /* area */
528 CreateArea(geom, vertices, false, 0, way);
529 } else {
530 CreateRoad(geom, vertices, GetHighwayWidth(t->second, way), way);
531 }
532 } else if ((flags & GeometryDatasource::GROUND) && (
533 t->second == "motorway" || t->second == "motorway_link" ||
534 t->second == "trunk" || t->second == "trunk_link" ||
535 t->second == "primary" || t->second == "primary_link" ||
536 t->second == "secondary" || t->second == "secondary_link" ||
537 t->second == "tertiary")) {
538 CreateLines(geom, vertices, minz, way);
539 }
540 } else if ((t = way.Tags.find("railway")) != way.Tags.end() && (t->second == "rail")) {
541 if (flags & GeometryDatasource::DETAIL) {
542 CreateLines(geom, vertices, minz, way);
543 } else if (flags & GeometryDatasource::GROUND) {
544 if (t->second == "rail")
545 CreateLines(geom, vertices, minz, way);
546 }
547 } else if ((t = way.Tags.find("boundary")) != way.Tags.end() && (t->second == "administrative")) {
548 if (flags & GeometryDatasource::GROUND)
549 CreateLines(geom, vertices, minz, way);
550 } else if ((t = way.Tags.find("waterway")) != way.Tags.end()) {
551 if (flags & GeometryDatasource::GROUND)
552 CreateLines(geom, vertices, minz, way);
553 } else if ((t = way.Tags.find("natural")) != way.Tags.end()) {
554 if (flags & GeometryDatasource::GROUND)
555 CreateLines(geom, vertices, minz, way);
556 } else if ((t = way.Tags.find("landuse")) != way.Tags.end()) {
557 if (flags & GeometryDatasource::GROUND)
558 CreateLines(geom, vertices, minz, way);
559 } else {
560 if (flags & GeometryDatasource::DETAIL)
561 CreateLines(geom, vertices, minz, way);
562 }
563 }
564
GeometryGenerator(const OsmDatasource & datasource)565 GeometryGenerator::GeometryGenerator(const OsmDatasource& datasource) : datasource_(datasource) {
566 }
567
GetGeometry(Geometry & geom,const BBoxi & bbox,int flags) const568 void GeometryGenerator::GetGeometry(Geometry& geom, const BBoxi& bbox, int flags) const {
569 std::vector<OsmDatasource::Way> ways;
570
571 /* safe bbox is a bit wider than requested one to be sure
572 * all ways are included, even those which have width */
573 float extra_width = 24.0; /* still may be not sufficient, e.g. very wide roads */
574 BBoxi safe_bbox = BBoxi(
575 FromLocalMetric(-Vector2d(extra_width, extra_width), bbox.GetBottomLeft()),
576 FromLocalMetric(Vector2d(extra_width, extra_width), bbox.GetTopRight())
577 );
578 datasource_.GetWays(ways, safe_bbox);
579
580 Geometry temp;
581
582 for (std::vector<OsmDatasource::Way>::const_iterator w = ways.begin(); w != ways.end(); ++w)
583 WayDispatcher(temp, datasource_, flags, *w);
584
585 geom.AppendCropped(temp, bbox);
586 }
587
GetCenter() const588 Vector2i GeometryGenerator::GetCenter() const {
589 return datasource_.GetCenter();
590 }
591
GetBBox() const592 BBoxi GeometryGenerator::GetBBox() const {
593 return datasource_.GetBBox();
594 }
595