void GeometryGroup::Draw (cairo_t *cr) { Transform *transform = GetTransform (); cairo_matrix_t saved; cairo_get_matrix (cr, &saved); if (transform) { cairo_matrix_t matrix; transform->GetTransform (&matrix); cairo_transform (cr, &matrix); } GeometryCollection *children = GetChildren (); Geometry *geometry; // GeometryGroup is used for Clip (as a Geometry) so Fill (normally setting the fill rule) is never called cairo_set_fill_rule (cr, convert_fill_rule (GetFillRule ())); int children_count = children->GetCount (); for (int i = 0; i < children_count; i++) { geometry = children->GetValueAt (i)->AsGeometry (); geometry->Draw (cr); } cairo_set_matrix (cr, &saved); }
std::auto_ptr<Geometry> collect( const Geometry& ga, const Geometry& gb ) { if ( ga.geometryTypeId() == gb.geometryTypeId() ) { if ( ga.geometryTypeId() == TYPE_POINT ) { MultiPoint *mp = new MultiPoint; mp->addGeometry( ga ); mp->addGeometry( gb ); return std::auto_ptr<Geometry>(mp); } else if ( ga.geometryTypeId() == TYPE_LINESTRING ) { MultiLineString *mls = new MultiLineString(); mls->addGeometry(ga); mls->addGeometry(gb); return std::auto_ptr<Geometry>( mls ); } else if ( ga.geometryTypeId() == TYPE_POLYGON ) { MultiPolygon *mp = new MultiPolygon(); mp->addGeometry(ga); mp->addGeometry(gb); return std::auto_ptr<Geometry>( mp ); } else if ( ga.geometryTypeId() == TYPE_SOLID ) { MultiSolid *mp = new MultiSolid(); mp->addGeometry(ga); mp->addGeometry(gb); return std::auto_ptr<Geometry>( mp ); } } // else GeometryCollection* coll = new GeometryCollection(); coll->addGeometry(ga); coll->addGeometry(gb); return std::auto_ptr<Geometry>( coll ); }
optional<GeometryCollection> offsetLine(const GeometryCollection& rings, const double offset) { if (offset == 0) return {}; GeometryCollection newRings; Point<double> zero(0, 0); for (const auto& ring : rings) { newRings.emplace_back(); auto& newRing = newRings.back(); for (auto i = ring.begin(); i != ring.end(); i++) { auto& p = *i; Point<double> aToB = i == ring.begin() ? zero : util::perp(util::unit(convertPoint<double>(p - *(i - 1)))); Point<double> bToC = i + 1 == ring.end() ? zero : util::perp(util::unit(convertPoint<double>(*(i + 1) - p))); Point<double> extrude = util::unit(aToB + bToC); const double cosHalfAngle = extrude.x * bToC.x + extrude.y * bToC.y; extrude *= (1.0 / cosHalfAngle); newRing.push_back(convertPoint<int16_t>(extrude * offset) + p); } } return newRings; }
/** * Tiles the geometry up until all the cells have less than given number of points. */ void downsizeGeometry(Geometry* geometry, const SpatialReference* featureSRS, unsigned int maxPoints, GeometryCollection& out) { // If the geometyr is greater than the maximum number of points, we need to tile it up further. if (geometry->size() > maxPoints) { OE_NOTICE << "Downsizing geometry of size " << geometry->size() << std::endl; // Tile the geometry. GeometryCollection tmp; tileGeometry(geometry, featureSRS, 2, 2, tmp ); for (unsigned int i = 0; i < tmp.size(); i++) { Geometry* g = tmp[i].get(); // If the generated geometry still has too many points, continue to downsample it recursively. if (g->size() > maxPoints) { // We pass "out" as the destination here since downsizeGeometry will only append tiles that are less than the max size. downsizeGeometry( g, featureSRS, maxPoints, out ); } else { // Append the geometry to the output list. out.push_back( g ); } } } else { // The geometry is valid, so add it to the output list. out.push_back( geometry ); } }
GeometryCollection* GeometryEditor::editGeometryCollection(const GeometryCollection *collection, GeometryEditorOperation *operation) { GeometryCollection *newCollection = (GeometryCollection*) operation->edit(collection,factory); vector<Geometry*> *geometries = new vector<Geometry*>(); for (int i = 0; i < newCollection->getNumGeometries(); i++) { Geometry *geometry = edit(newCollection->getGeometryN(i), operation); if (geometry->isEmpty()) { delete geometry; continue; } geometries->push_back(geometry); } if (typeid(*newCollection)==typeid(MultiPoint)) { delete newCollection; return factory->createMultiPoint(geometries); } else if (typeid(*newCollection)==typeid(MultiLineString)) { delete newCollection; return factory->createMultiLineString(geometries); } else if (typeid(*newCollection)==typeid(MultiPolygon)) { delete newCollection; return factory->createMultiPolygon(geometries); } else { delete newCollection; return factory->createGeometryCollection(geometries); } }
optional<GeometryCollection> FeatureIndex::translateQueryGeometry( const GeometryCollection& queryGeometry, const std::array<float, 2>& translate, const TranslateAnchorType anchorType, const float bearing, const float pixelsToTileUnits) { if (translate[0] == 0 && translate[1] == 0) return {}; GeometryCoordinate translateVec(translate[0] * pixelsToTileUnits, translate[1] * pixelsToTileUnits); if (anchorType == TranslateAnchorType::Viewport) { translateVec = util::rotate(translateVec, -bearing); } GeometryCollection translated; for (auto& ring : queryGeometry) { translated.emplace_back(); auto& translatedRing = translated.back(); for (auto& p : ring) { translatedRing.push_back(p - translateVec); } } return translated; }
void ForceValidityVisitor::visit( GeometryCollection& g ) { g.forceValidityFlag( valid_ ); for ( size_t i = 0; i < g.numGeometries(); i++ ) { g.geometryN( i ).accept( *this ); } }
void triangulatePolygon3D( const GeometryCollection& g, TriangulatedSurface& triangulatedSurface ) { for ( size_t i = 0; i < g.numGeometries(); i++ ) { triangulatePolygon3D( g.geometryN( i ), triangulatedSurface ); } }
void limitHoles(GeometryCollection& polygon, uint32_t maxHoles) { if (polygon.size() > 1 + maxHoles) { std::nth_element(polygon.begin() + 1, polygon.begin() + 1 + maxHoles, polygon.end(), [] (const auto& a, const auto& b) { return signedArea(a) > signedArea(b); }); polygon.resize(1 + maxHoles); } }
GeometryCollection operator()(const mapbox::geometry::multi_line_string<int16_t>& geom) const { GeometryCollection collection; collection.reserve(geom.size()); for (const auto& ring : geom) { GeometryCoordinates coordinates; coordinates.reserve(ring.size()); for (const auto& point : ring) { coordinates.emplace_back(point); } collection.push_back(std::move(coordinates)); } return collection; }
GeometryCollection operator()(const mapbox::geometry::multi_polygon<int16_t>& geom) const { GeometryCollection collection; for (auto& polygon : geom) { for (auto& ring : polygon) { GeometryCoordinates coordinates; coordinates.reserve(ring.size()); for (auto& point : ring) { coordinates.emplace_back(point); } collection.push_back(std::move(coordinates)); } } return collection; }
void WktWriter::write( const GeometryCollection & g ) { _s << "GEOMETRYCOLLECTION" ; if ( g.isEmpty() ){ _s << " EMPTY" ; return ; } _s << "(" ; for ( size_t i = 0 ; i < g.numGeometries(); i++ ){ if ( i != 0 ) _s << ","; write( g.geometryN(i) ); } _s << ")" ; }
Rect GeometryGroup::ComputePathBounds () { GeometryCollection *children = GetChildren (); Rect bounds = Rect (0.0, 0.0, 0.0, 0.0); Geometry *geometry; int children_count = children->GetCount (); for (int i = 0; i < children_count; i++) { geometry = children->GetValueAt (i)->AsGeometry (); bounds = bounds.Union (geometry->GetBounds (), true); } //g_warning ("GeometryGroup::ComputeBounds - x %g y %g w %g h %g", bounds.x, bounds.y, bounds.w, bounds.h); return bounds; }
static void processPolynodeBranch(ClipperLib::PolyNode* polynode, GeometryCollection& rings) { // Exterior ring. rings.push_back(fromClipperPath(polynode->Contour)); assert(signedArea(rings.back()) > 0); // Interior rings. for (auto * ring : polynode->Childs) { rings.push_back(fromClipperPath(ring->Contour)); assert(signedArea(rings.back()) < 0); } // PolyNodes may be nested in the case of a polygon inside a hole. for (auto * ring : polynode->Childs) { for (auto * subRing : ring->Childs) { processPolynodeBranch(subRing, rings); } } }
GeometryCollection clipLines(const GeometryCollection &lines, const int16_t x1, const int16_t y1, const int16_t x2, const int16_t y2) { GeometryCollection clippedLines; for (auto& line : lines) { if (line.empty()) continue; auto end = line.end() - 1; for (auto it = line.begin(); it != end; it++) { GeometryCoordinate p0 = *(it); GeometryCoordinate p1 = *(it + 1); if (p0.x < x1 && p1.x < x1) { continue; } else if (p0.x < x1) { p0 = { x1, static_cast<int16_t>(::round(p0.y + (p1.y - p0.y) * ((float)(x1 - p0.x) / (p1.x - p0.x)))) }; } else if (p1.x < x1) { p1 = { x1, static_cast<int16_t>(::round(p0.y + (p1.y - p0.y) * ((float)(x1 - p0.x) / (p1.x - p0.x)))) }; } if (p0.y < y1 && p1.y < y1) { continue; } else if (p0.y < y1) { p0 = { static_cast<int16_t>(::round(p0.x + (p1.x - p0.x) * ((float)(y1 - p0.y) / (p1.y - p0.y)))), y1 }; } else if (p1.y < y1) { p1 = { static_cast<int16_t>(::round(p0.x + (p1.x - p0.x) * ((float)(y1 - p0.y) / (p1.y - p0.y)))), y1 }; } if (p0.x >= x2 && p1.x >= x2) { continue; } else if (p0.x >= x2) { p0 = { x2, static_cast<int16_t>(::round(p0.y + (p1.y - p0.y) * ((float)(x2 - p0.x) / (p1.x - p0.x)))) }; } else if (p1.x >= x2) { p1 = { x2, static_cast<int16_t>(::round(p0.y + (p1.y - p0.y) * ((float)(x2 - p0.x) / (p1.x - p0.x)))) }; } if (p0.y >= y2 && p1.y >= y2) { continue; } else if (p0.y >= y2) { p0 = { static_cast<int16_t>(::round(p0.x + (p1.x - p0.x) * ((float)(y2 - p0.y) / (p1.y - p0.y)))), y2 }; } else if (p1.y >= y2) { p1 = { static_cast<int16_t>(::round(p0.x + (p1.x - p0.x) * ((float)(y2 - p0.y) / (p1.y - p0.y)))), y2 }; } if (clippedLines.empty() || (!clippedLines.back().empty() && !(p0 == clippedLines.back().back()))) { clippedLines.emplace_back(); clippedLines.back().push_back(p0); } clippedLines.back().push_back(p1); } } return clippedLines; }
/** * Tiles the Geometry into the given number of columns and rows */ void tileGeometry(Geometry* geometry, const SpatialReference* featureSRS, unsigned int numCols, unsigned int numRows, GeometryCollection& out) { // Clear the output list. out.clear(); Bounds b = geometry->getBounds(); double tw = b.width() / (double)numCols; double th = b.height() / (double)numRows; // Get the average Z, since GEOS will set teh Z of new verts to that of the cropping polygon, // which is stupid but that's how it is. double z = 0.0; for(unsigned i=0; i<geometry->size(); ++i) z += geometry->at(i).z(); z /= geometry->size(); osg::ref_ptr<Polygon> poly = new Polygon; poly->resize( 4 ); for(int x=0; x<(int)numCols; ++x) { for(int y=0; y<(int)numRows; ++y) { (*poly)[0].set( b.xMin() + tw*(double)x, b.yMin() + th*(double)y, z ); (*poly)[1].set( b.xMin() + tw*(double)(x+1), b.yMin() + th*(double)y, z ); (*poly)[2].set( b.xMin() + tw*(double)(x+1), b.yMin() + th*(double)(y+1), z ); (*poly)[3].set( b.xMin() + tw*(double)x, b.yMin() + th*(double)(y+1), z ); osg::ref_ptr<Geometry> ringTile; if ( geometry->crop(poly.get(), ringTile) ) { // Use an iterator since crop could return a multi-polygon GeometryIterator gi( ringTile.get(), false ); while( gi.hasMore() ) { Geometry* geom = gi.next(); out.push_back( geom ); } } } } }
GeometryCollection VectorTileFeature::getGeometries() const { uint8_t cmd = 1; uint32_t length = 0; int32_t x = 0; int32_t y = 0; const float scale = float(util::EXTENT) / layer.extent; GeometryCollection lines; lines.emplace_back(); GeometryCoordinates* line = &lines.back(); auto g_itr = geometry_iter.begin(); while (g_itr != geometry_iter.end()) { if (length == 0) { uint32_t cmd_length = static_cast<uint32_t>(*g_itr++); cmd = cmd_length & 0x7; length = cmd_length >> 3; } --length; if (cmd == 1 || cmd == 2) { x += protozero::decode_zigzag32(static_cast<uint32_t>(*g_itr++)); y += protozero::decode_zigzag32(static_cast<uint32_t>(*g_itr++)); if (cmd == 1 && !line->empty()) { // moveTo lines.emplace_back(); line = &lines.back(); } line->emplace_back(::round(x * scale), ::round(y * scale)); } else if (cmd == 7) { // closePolygon if (!line->empty()) { line->push_back((*line)[0]); } } else { throw std::runtime_error("unknown command"); } }
GeometryCollection VectorTileFeature::getGeometries() const { pbf data(geometry_pbf); uint8_t cmd = 1; uint32_t length = 0; int32_t x = 0; int32_t y = 0; GeometryCollection lines; lines.emplace_back(); GeometryCoordinates* line = &lines.back(); while (data.data < data.end) { if (length == 0) { uint32_t cmd_length = data.varint(); cmd = cmd_length & 0x7; length = cmd_length >> 3; } --length; if (cmd == 1 || cmd == 2) { x += data.svarint(); y += data.svarint(); if (cmd == 1 && !line->empty()) { // moveTo lines.emplace_back(); line = &lines.back(); } line->emplace_back(x, y); } else if (cmd == 7) { // closePolygon if (!line->empty()) { line->push_back((*line)[0]); } } else { throw std::runtime_error("unknown command"); } }
void WKBWriter::writeGeometryCollection(const GeometryCollection &g, int wkbtype) { writeByteOrder(); writeGeometryType(wkbtype, g.getSRID()); writeSRID(g.getSRID()); int ngeoms = g.getNumGeometries(); writeInt(ngeoms); assert(outStream); for (int i=0; i<ngeoms; i++) { const Geometry* elem = g.getGeometryN(i); assert(elem); write(*elem, *outStream); } }
std::vector<GeometryCollection> classifyRings(const GeometryCollection& rings) { std::vector<GeometryCollection> polygons; std::size_t len = rings.size(); if (len <= 1) { polygons.push_back(rings); return polygons; } GeometryCollection polygon; int8_t ccw = 0; for (std::size_t i = 0; i < len; i++) { double area = signedArea(rings[i]); if (area == 0) continue; if (ccw == 0) ccw = (area < 0 ? -1 : 1); if (ccw == (area < 0 ? -1 : 1) && !polygon.empty()) { polygons.push_back(polygon); polygon.clear(); } polygon.push_back(rings[i]); } if (!polygon.empty()) polygons.push_back(polygon); return polygons; }
void WKBWriter::writeGeometryCollection(const GeometryCollection& g, int wkbtype) { writeByteOrder(); writeGeometryType(wkbtype, g.getSRID()); writeSRID(g.getSRID()); auto ngeoms = g.getNumGeometries(); writeInt(static_cast<int>(ngeoms)); auto orig_includeSRID = includeSRID; includeSRID = false; assert(outStream); for(std::size_t i = 0; i < ngeoms; i++) { const Geometry* elem = g.getGeometryN(i); assert(elem); write(*elem, *outStream); } includeSRID = orig_includeSRID; }
void GetPointsVisitor::visit( const GeometryCollection& g ) { for ( size_t i = 0; i < g.numGeometries(); i++ ) { g.geometryN( i ).accept( *this ); } }
void BuildGeometryFilter::tileAndBuildPolygon(Geometry* ring, const SpatialReference* featureSRS, const SpatialReference* mapSRS, bool makeECEF, bool tessellate, osg::Geometry* osgGeom, const osg::Matrixd &world2local) { #define MAX_POINTS_PER_CROP_TILE 1024 #define TARGET_TILE_SIZE_EXTENT_DEGREES 5.0 // Tile the incoming polygon if necessary GeometryCollection tiles; prepareForTesselation( ring, featureSRS, TARGET_TILE_SIZE_EXTENT_DEGREES, MAX_POINTS_PER_CROP_TILE, tiles); osg::ref_ptr<osg::Geode> geode = new osg::Geode; // Process each ring independently for (int ringIndex = 0; ringIndex < tiles.size(); ringIndex++) { Ring* geom = dynamic_cast< Ring*>(tiles[ringIndex].get()); if (geom) { // temporary target geometry for this cell: osg::ref_ptr<osg::Geometry> temp = new osg::Geometry(); temp->setVertexArray( new osg::Vec3Array() ); // establish a local plane for this cell based on its centroid: GeoPoint cellCenter(featureSRS, geom->getBounds().center()); cellCenter.transform(mapSRS, cellCenter); osg::Matrix world2cell; cellCenter.createWorldToLocal( world2cell ); // build the localized polygon: buildPolygon(geom, featureSRS, mapSRS, makeECEF, tessellate, temp.get(), world2cell); // if successful, transform the verts back into our master LTP: if ( temp->getNumPrimitiveSets() > 0 ) { // Tesselate the polygon while the coordinates are still in the LTP if (tesselateGeometry( temp.get() )) { osg::Vec3Array* verts = static_cast<osg::Vec3Array*>(temp->getVertexArray()); if ( verts->getNumElements() > 0 ) { // Convert the coordinates back to the master LTP. // This is ok, but you will probably run into precision errors if the tile size is very large. osg::Matrix cell2world; cell2world.invert( world2cell ); osg::Matrix cell2local = cell2world * world2local; // pre-multiply to avoid precision loss for(int i=0; i<verts->size(); ++i) { (*verts)[i] = (*verts)[i] * cell2local; } geode->addDrawable(temp.get()); } } } } } // The geode is going to contain all of our polygons now, so merge them into one. osgUtil::Optimizer optimizer; osgUtil::Optimizer::MergeGeometryVisitor mgv; // We only want one Geometry, so don't limit the number of vertices. mgv.setTargetMaximumNumberOfVertices(UINT_MAX); mgv.apply( *geode.get() ); // and copy them into the output geometry. if ( geode->getNumDrawables() > 0 ) { // If we have more than one drawable after the MergeGeometryVisitor ran, we have a problem so // dump out some info to help debug. if (geode->getNumDrawables() != 1) { OE_WARN << LC << "MergeGeometryVisitor failed to merge geometries into a single one. Num drawables " << geode->getNumDrawables() << std::endl; for (unsigned int i = 0; i < geode->getNumDrawables(); i++) { osg::Geometry* g = geode->getDrawable(i)->asGeometry(); if (g) { osg::Vec3Array* verts = dynamic_cast<osg::Vec3Array*>(g->getVertexArray()); OE_WARN << "Geometry " << i << " has " << verts->size() << " verts" << std::endl; OE_WARN << "Geometry " << i << " has " << g->getNumPrimitiveSets() << " primitive sets" << std::endl; for (unsigned int j = 0; j < g->getNumPrimitiveSets(); j++) { osg::PrimitiveSet* ps = g->getPrimitiveSet(j); OE_WARN << "PrimitiveSet " << j << ps->className() << std::endl; } } } } osgGeom->setVertexArray( geode->getDrawable(0)->asGeometry()->getVertexArray() ); osgGeom->setPrimitiveSetList( geode->getDrawable(0)->asGeometry()->getPrimitiveSetList() ); } osgUtil::SmoothingVisitor::smooth( *osgGeom ); }
/** * Prepares a geometry into a grid if it is too big geospatially to have a sensible local tangent plane * We will also tile the geometry if it just has too many points to speed up the tesselator. */ void prepareForTesselation(Geometry* geometry, const SpatialReference* featureSRS, double targetTileSizeDeg, unsigned int maxPointsPerTile, GeometryCollection& out) { // Clear the output list. GeometryCollection tiles; unsigned int count = geometry->size(); unsigned int tx = 1; unsigned int ty = 1; // Tile the geometry if it's geospatial size is too large to have a sensible local tangent plane. GeoExtent featureExtentDeg = GeoExtent(featureSRS, geometry->getBounds()).transform(SpatialReference::create("wgs84")); // Tile based on the extent if ( featureExtentDeg.width() > targetTileSizeDeg || featureExtentDeg.height() > targetTileSizeDeg) { // Determine the tile size based on the extent. tx = ceil( featureExtentDeg.width() / targetTileSizeDeg ); ty = ceil (featureExtentDeg.height() / targetTileSizeDeg ); } else if (count > maxPointsPerTile) { // Determine the size based on the number of points. unsigned numTiles = ((double)count / (double)maxPointsPerTile) + 1u; tx = ceil(sqrt((double)numTiles)); ty = tx; } if (tx == 1 && ty == 1) { // The geometry doesn't need modified so just add it to the list. tiles.push_back( geometry ); } else { tileGeometry( geometry, featureSRS, tx, ty, tiles ); } out.clear(); #if 1 // Just copy the output tiles to the output. std::copy(tiles.begin(), tiles.end(), std::back_inserter(out)); #else // Calling this code will recursively subdivide the cells based on the number of points they have. // This works but it will produces a non-regular grid which doesn't render well in geocentric // due to the curvature of the earth so we disable it for now. // // Reduce the size of the tiles if needed. for (unsigned int i = 0; i < tiles.size(); i++) { if (tiles[i]->size() > maxPointsPerTile) { GeometryCollection tmp; downsizeGeometry(tiles[i].get(), featureSRS, maxPointsPerTile, tmp); std::copy(tmp.begin(), tmp.end(), std::back_inserter(out)); } else { out.push_back( tiles[i].get() ); } } #endif }
int parse_wkt(const char * wkt, struct osmNode *** xnodes, int ** xcount, int * polygon) { GeometryFactory gf; WKTReader reader(&gf); std::string wkt_string(wkt); Geometry * geometry; const Geometry * subgeometry; GeometryCollection * gc; CoordinateSequence * coords; size_t num_geometries; size_t i; *polygon = 0; try { geometry = reader.read(wkt_string); switch (geometry->getGeometryTypeId()) { // Single geometries case GEOS_POLYGON: // Drop through case GEOS_LINEARRING: *polygon = 1; // Drop through case GEOS_POINT: // Drop through case GEOS_LINESTRING: *xnodes = (struct osmNode **) malloc(2 * sizeof(struct osmNode *)); *xcount = (int *) malloc(sizeof(int)); coords = geometry->getCoordinates(); (*xcount)[0] = coords2nodes(coords, &((*xnodes)[0])); (*xnodes)[1] = NULL; delete coords; break; // Geometry collections case GEOS_MULTIPOLYGON: *polygon = 1; // Drop through case GEOS_MULTIPOINT: // Drop through case GEOS_MULTILINESTRING: gc = dynamic_cast<GeometryCollection *>(geometry);; num_geometries = gc->getNumGeometries(); *xnodes = (struct osmNode **) malloc((num_geometries + 1) * sizeof(struct osmNode *)); *xcount = (int *) malloc(num_geometries * sizeof(int)); for (i = 0; i < num_geometries; i++) { subgeometry = gc->getGeometryN(i); coords = subgeometry->getCoordinates(); (*xcount)[i] = coords2nodes(coords, &((*xnodes)[i])); delete coords; } (*xnodes)[i] = NULL; break; default: std::cerr << std::endl << "unexpected object type while processing PostGIS data" << std::endl; delete geometry; return -1; } delete geometry; } catch (...) { std::cerr << std::endl << "Exception caught parsing PostGIS data" << std::endl; return -1; } return 0; }
void ShapeAnnotationImpl::updateTile(const TileID& tileID, AnnotationTile& tile) { static const double baseTolerance = 4; if (!shapeTiler) { const uint64_t maxAmountOfTiles = 1 << maxZoom; const double tolerance = baseTolerance / (maxAmountOfTiles * GeometryTileFeature::defaultExtent); geojsonvt::ProjectedRings rings; std::vector<geojsonvt::LonLat> points; for (size_t i = 0; i < shape.segments[0].size(); ++i) { // first segment for now (no holes) const double constrainedLatitude = util::clamp(shape.segments[0][i].latitude, -util::LATITUDE_MAX, util::LATITUDE_MAX); points.push_back(geojsonvt::LonLat(shape.segments[0][i].longitude, constrainedLatitude)); } if (type == geojsonvt::ProjectedFeatureType::Polygon && (points.front().lon != points.back().lon || points.front().lat != points.back().lat)) { points.push_back(geojsonvt::LonLat(points.front().lon, points.front().lat)); } auto ring = geojsonvt::Convert::projectRing(points, tolerance); rings.push_back(ring); std::vector<geojsonvt::ProjectedFeature> features; features.push_back(geojsonvt::Convert::create(geojsonvt::Tags(), type, rings)); mapbox::geojsonvt::Options options; options.maxZoom = maxZoom; options.buffer = 255u; options.extent = util::EXTENT; options.tolerance = baseTolerance; shapeTiler = std::make_unique<mapbox::geojsonvt::GeoJSONVT>(features, options); } const auto& shapeTile = shapeTiler->getTile(tileID.sourceZ, tileID.x, tileID.y); if (!shapeTile) return; AnnotationTileLayer& layer = *tile.layers.emplace(layerID, std::make_unique<AnnotationTileLayer>()).first->second; for (auto& shapeFeature : shapeTile.features) { FeatureType featureType = FeatureType::Unknown; if (shapeFeature.type == geojsonvt::TileFeatureType::LineString) { featureType = FeatureType::LineString; } else if (shapeFeature.type == geojsonvt::TileFeatureType::Polygon) { featureType = FeatureType::Polygon; } assert(featureType != FeatureType::Unknown); GeometryCollection renderGeometry; for (auto& shapeRing : shapeFeature.tileGeometry.get<geojsonvt::TileRings>()) { GeometryCoordinates renderLine; for (auto& shapePoint : shapeRing) { renderLine.emplace_back(shapePoint.x, shapePoint.y); } renderGeometry.push_back(renderLine); } layer.features.emplace_back( std::make_shared<AnnotationTileFeature>(featureType, renderGeometry)); } }
inline GeometryCollectionBaseType::const_iterator range_end(const GeometryCollection& gc) {return gc.end();}
void ShapeAnnotationImpl::updateTile(const TileID& tileID, AnnotationTile& tile) { static const double baseTolerance = 3; static const uint16_t extent = 4096; if (!shapeTiler) { const uint64_t maxAmountOfTiles = 1 << maxZoom; const double tolerance = baseTolerance / (maxAmountOfTiles * extent); ProjectedGeometryContainer rings; std::vector<LonLat> points; for (size_t i = 0; i < shape.segments[0].size(); ++i) { // first segment for now (no holes) const double constraintedLatitude = ::fmin(::fmax(shape.segments[0][i].latitude, -util::LATITUDE_MAX), util::LATITUDE_MAX); points.push_back(LonLat(shape.segments[0][i].longitude, constraintedLatitude)); } if (type == ProjectedFeatureType::Polygon && (points.front().lon != points.back().lon || points.front().lat != points.back().lat)) { points.push_back(LonLat(points.front().lon, points.front().lat)); } ProjectedGeometryContainer ring = Convert::project(points, tolerance); rings.members.push_back(ring); std::vector<ProjectedFeature> features; features.push_back(Convert::create(Tags(), type, rings)); shapeTiler = std::make_unique<mapbox::util::geojsonvt::GeoJSONVT>(features, maxZoom, 4, 100, 10); } const auto& shapeTile = shapeTiler->getTile(tileID.z, tileID.x, tileID.y); if (!shapeTile) return; AnnotationTileLayer& layer = *tile.layers.emplace(layerID, std::make_unique<AnnotationTileLayer>()).first->second; for (auto& shapeFeature : shapeTile.features) { FeatureType featureType = FeatureType::Unknown; if (shapeFeature.type == TileFeatureType::LineString) { featureType = FeatureType::LineString; } else if (shapeFeature.type == TileFeatureType::Polygon) { featureType = FeatureType::Polygon; } assert(featureType != FeatureType::Unknown); GeometryCollection renderGeometry; for (auto& shapeGeometry : shapeFeature.tileGeometry) { std::vector<Coordinate> renderLine; auto& shapeRing = shapeGeometry.get<TileRing>(); for (auto& shapePoint : shapeRing.points) { renderLine.emplace_back(shapePoint.x, shapePoint.y); } renderGeometry.push_back(renderLine); } layer.features.emplace_back( std::make_shared<AnnotationTileFeature>(featureType, renderGeometry)); } }
void BoundaryVisitor::visit( const GeometryCollection& g ) { BOOST_THROW_EXCEPTION( Exception( ( boost::format( "unsupported type %1% in boundary operation" ) % g.geometryType() ).str() ) ); }
inline GeometryCollectionBaseType::const_iterator range_begin(const GeometryCollection& gc) {return gc.begin();}