diff --git a/build_geometry.cpp b/build_geometry.cpp index fe21616ff..bb160abd2 100644 --- a/build_geometry.cpp +++ b/build_geometry.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #if defined(__CYGWIN__) @@ -122,12 +123,30 @@ char *get_wkt_simple(osmNode *nodes, int count, int polygon) { } } +// helper method to add the WKT for a geometry to the +// global wkts list - used primarily for polygons. +void add_wkt(geom_ptr &geom, double area) { + WKTWriter wktw; + std::string wkt = wktw.write(geom.get()); + wkts.push_back(wkt); + areas.push_back(area); +} + +// helper method to add the WKT for a line built from a +// coordinate sequence to the global wkts list. +void add_wkt_line(GeometryFactory &gf, std::auto_ptr &segment) { + WKTWriter wktw; + geom_ptr geom = geom_ptr(gf.createLineString(segment.release())); + std::string wkt = wktw.write(geom.get()); + wkts.push_back(wkt); + areas.push_back(0); + segment.reset(gf.getCoordinateSequenceFactory()->create((size_t)0, (size_t)2)); +} size_t get_wkt_split(osmNode *nodes, int count, int polygon, double split_at) { GeometryFactory gf; std::auto_ptr coords(gf.getCoordinateSequenceFactory()->create((size_t)0, (size_t)2)); double area; - WKTWriter wktw; size_t wkt_size = 0; try @@ -152,10 +171,8 @@ size_t get_wkt_split(osmNode *nodes, int count, int polygon, double split_at) { } geom->normalize(); // Fix direction of ring area = geom->getArea(); - std::string wkt = wktw.write(geom.get()); - wkts.push_back(wkt); - areas.push_back(area); - wkt_size++; + add_wkt(geom, area); + } else { if (coords->getSize() < 2) return 0; @@ -165,21 +182,47 @@ size_t get_wkt_split(osmNode *nodes, int count, int polygon, double split_at) { segment = std::auto_ptr(gf.getCoordinateSequenceFactory()->create((size_t)0, (size_t)2)); segment->add(coords->getAt(0)); for(unsigned i=1; igetSize(); i++) { - segment->add(coords->getAt(i)); - distance += coords->getAt(i).distance(coords->getAt(i-1)); - if ((distance >= split_at) || (i == coords->getSize()-1)) { - geom = geom_ptr(gf.createLineString(segment.release())); - std::string wkt = wktw.write(geom.get()); - wkts.push_back(wkt); - areas.push_back(0); - wkt_size++; - distance=0; - segment = std::auto_ptr(gf.getCoordinateSequenceFactory()->create((size_t)0, (size_t)2)); - segment->add(coords->getAt(i)); + const Coordinate this_pt = coords->getAt(i); + const Coordinate prev_pt = coords->getAt(i-1); + const double delta = this_pt.distance(prev_pt); + // figure out if the addition of this point would take the total + // length of the line in `segment` over the `split_at` distance. + const size_t splits = std::floor((distance + delta) / split_at); + + if (splits > 0) { + // use the splitting distance to split the current segment up + // into as many parts as necessary to keep each part below + // the `split_at` distance. + for (size_t i = 0; i < splits; ++i) { + double frac = (double(i + 1) * split_at - distance) / delta; + const Coordinate interpolated(frac * (this_pt.x - prev_pt.x) + prev_pt.x, + frac * (this_pt.y - prev_pt.y) + prev_pt.y); + segment->add(interpolated); + add_wkt_line(gf, segment); + segment->add(interpolated); + } + // reset the distance based on the final splitting point for + // the next iteration. + distance = segment->getAt(0).distance(this_pt); + + } else { + // if not split then just push this point onto the sequence + // being saved up. + distance += delta; + } + + // always add this point + segment->add(this_pt); + + // on the last iteration, close out the line. + if (i == coords->getSize()-1) { + add_wkt_line(gf, segment); } } } + // ensure the number of wkts in the global list is accurate. + wkt_size = wkts.size(); } catch (std::bad_alloc) {