Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ test: \
test_attribute_store \
test_config_validator \
test_deque_map \
test_geom \
test_helpers \
test_options_parser \
test_pbf_reader \
Expand Down Expand Up @@ -196,6 +197,11 @@ test_deque_map: \
test/deque_map.test.o
$(CXX) $(CXXFLAGS) -o test.deque_map $^ $(INC) $(LIB) $(LDFLAGS) && ./test.deque_map

test_geom: \
src/geom.o \
test/geom.test.o
$(CXX) $(CXXFLAGS) -o test.geom $^ $(INC) $(LIB) $(LDFLAGS) && ./test.geom

test_helpers: \
src/helpers.o \
src/external/libdeflate/lib/adler32.o \
Expand Down
10 changes: 8 additions & 2 deletions include/geom.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,10 @@ void make_valid(MultiPolygon &mp);
// Attempt to repair an invalid areal geometry in place: dissolve-based
// make_valid first (preserves area), then a zero-width buffer as a last
// resort. Returns true if mp is valid afterwards; on failure mp is left as the
// best-effort input so callers never regress.
bool repair_multi_polygon(MultiPolygon &mp, bool knownInvalid = false);
// best-effort input so callers never regress. If wholeValid is given, it is set
// to true only if mp as a whole is known to pass geom::is_valid afterwards (a true
// result alone can leave individually valid polygons that overlap each other).
bool repair_multi_polygon(MultiPolygon &mp, bool knownInvalid = false, bool *wholeValid = nullptr);

void union_many(std::vector<MultiPolygon> &mps);

Expand All @@ -91,6 +93,10 @@ char bit_code(Point const &p, Box const &bbox);
// fast_clip returns true if the geometry was modified (false means identity).
bool fast_clip(Ring &points, Box const &bbox);
bool fast_clip(MultiPolygon &mp, Box const &bbox);
// Exact clip of a valid multipolygon to bbox that keeps it valid (fast_clip can
// leave zero-width bridges along the box edge). Returns false if it could not
// clip robustly; `out` is then unspecified and the caller must use geom::intersection.
bool rect_clip(const MultiPolygon &mp, Box const &bbox, MultiPolygon &out);

// Cheap conservative validity tests, run before geom::is_valid. They return
// true only when the geometry is certainly valid (is_valid would return true
Expand Down
3 changes: 2 additions & 1 deletion include/osm_mem_tiles.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ class OsmMemTiles : public TileDataSource {
// CorrectGeometry found them Valid (or Reversed: valid after reversing the ring)
// on the same lon/latp coordinates.
bool polygonKnownValid(NodeID objectID) const override {
return objectID >= OSM_THRESHOLD && (IS_WAY(objectID) || IS_WAY_REV(objectID));
if (objectID < OSM_THRESHOLD) return TileDataSource::polygonKnownValid(objectID);
return IS_WAY(objectID) || IS_WAY_REV(objectID);
}

const NodeStore& nodeStore;
Expand Down
12 changes: 10 additions & 2 deletions include/tile_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,8 @@ class TileDataSource {
std::vector<linestring_store_t> linestringStores;
std::vector<multi_linestring_store_t> multilinestringStores;
std::vector<multi_polygon_store_t> multipolygonStores;
// Per multipolygonStores entry: stored geometry is known to pass geom::is_valid
std::vector<std::vector<bool>> multipolygonValid;

ClipCache<MultiPolygon> multiPolygonClipCache;
ClipCache<MultiLinestring> multiLinestringClipCache;
Expand Down Expand Up @@ -359,6 +361,7 @@ class TileDataSource {
pointStores[0].push_back(Point(0,0));
linestringStores[0].push_back(linestring_t());
multipolygonStores[0].push_back(multi_polygon_t());
multipolygonValid[0].push_back(false);
multilinestringStores[0].push_back(multi_linestring_t());
}
void reportSize() const;
Expand All @@ -380,7 +383,11 @@ class TileDataSource {
virtual void populateMultiPolygon(MultiPolygon& dst, NodeID objectID);
// True if the polygon populateMultiPolygon returns for objectID is known to
// have passed geom::is_valid on exactly the same coordinates.
virtual bool polygonKnownValid(NodeID objectID) const { return false; }
virtual bool polygonKnownValid(NodeID objectID) const {
const auto& valid = multipolygonValid[getShard(objectID)];
const auto offset = getId(objectID);
return offset < valid.size() && valid[offset];
}

unsigned int getIndexZoom() const { return indexZoom; }
inline size_t getId(NodeID id) const {
Expand Down Expand Up @@ -415,7 +422,8 @@ class TileDataSource {
return shard.at(offset);
}

NodeID storeMultiPolygon(const MultiPolygon& src);
// knownValid: src has passed geom::is_valid (see polygonKnownValid)
NodeID storeMultiPolygon(const MultiPolygon& src, bool knownValid = false);

multi_polygon_t const &retrieveMultiPolygon(NodeID id) const {
const auto& shardId = getShard(id);
Expand Down
Loading
Loading