Skip to content

Commit

Permalink
Introduce SelfContainedGeometry type to simplify interface.
Browse files Browse the repository at this point in the history
  • Loading branch information
josephbirkner committed Nov 11, 2024
1 parent 0b2c4e4 commit 5dbf63e
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 31 deletions.
2 changes: 1 addition & 1 deletion libs/model/include/mapget/model/feature.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class Feature : public simfil::MandatoryDerivedModelNodeBase<TileFeatureLayer>
*/
model_ptr<GeometryCollection> geom();
[[nodiscard]] model_ptr<GeometryCollection> geomOrNull() const;
[[nodiscard]] model_ptr<Geometry> firstGeometry() const;
[[nodiscard]] SelfContainedGeometry firstGeometry() const;

/**
* Get this feature's Attribute layers. The non-const version adds a
Expand Down
16 changes: 16 additions & 0 deletions libs/model/include/mapget/model/geometry.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,16 @@ enum class GeomType: uint8_t {
Mesh // Collection of triangles
};

/**
* Small interface container type which may be used
* to pass around geometry data.
*/
struct SelfContainedGeometry
{
std::vector<Point> points_;
GeomType geomType_ = GeomType::Points;
};

/**
* Geometry object, which stores a point collection, a line-string,
* or a triangle mesh.
Expand Down Expand Up @@ -80,6 +90,12 @@ class Geometry final : public simfil::MandatoryDerivedModelNodeBase<TileFeatureL
template <typename LambdaType, class ModelType = TileFeatureLayer>
bool forEachPoint(LambdaType const& callback) const;

/**
* Turn the points and type from this geometry into a self-contained
* struct which can be passed around.
*/
[[nodiscard]] SelfContainedGeometry toSelfContained() const;

protected:
[[nodiscard]] ValueType type() const override;
[[nodiscard]] ModelNode::Ptr at(int64_t) const override;
Expand Down
2 changes: 1 addition & 1 deletion libs/model/include/mapget/model/validity.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ class Validity : public simfil::ProceduralObject<6, Validity, TileFeatureLayer>
* - A vector containing a single point, if the validity resolved to a point geometry.
* - A vector containing more than one point, if the validity resolved to a poly-line.
*/
std::vector<Point> computeGeometry(model_ptr<GeometryCollection> const& geometryCollection, std::string* error=nullptr) const;
SelfContainedGeometry computeGeometry(model_ptr<GeometryCollection> const& geometryCollection, std::string* error=nullptr) const;

protected:
/** Actual per-validity data that is stored in the model's attributes-column. */
Expand Down
6 changes: 4 additions & 2 deletions libs/model/src/feature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ bool Feature::forEachRelation(std::function<bool(const model_ptr<Relation>&)> co
return true;
}

model_ptr<Geometry> Feature::firstGeometry() const
SelfContainedGeometry Feature::firstGeometry() const
{
model_ptr<Geometry> result;
if (auto geometryCollection = geomOrNull()) {
Expand All @@ -307,7 +307,9 @@ model_ptr<Geometry> Feature::firstGeometry() const
return false;
});
}
return result;
if (result)
return result->toSelfContained();
return {};
}

std::optional<std::vector<model_ptr<Relation>>>
Expand Down
30 changes: 27 additions & 3 deletions libs/model/src/geometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,18 @@ Geometry::Geometry(Data* data, ModelConstPtr pool_, ModelNodeAddress a)
storage_ = &model().vertexBufferStorage();
}

SelfContainedGeometry Geometry::toSelfContained() const
{
SelfContainedGeometry result{{}, geomType()};
result.points_.reserve(numPoints());
forEachPoint([&result](auto&& pt)
{
result.points_.emplace_back(pt);
return true;
});
return result;
}

ValueType Geometry::type() const {
return ValueType::Object;
}
Expand All @@ -124,11 +136,13 @@ ModelNode::Ptr Geometry::at(int64_t i) const {
return get(StringPool::TypeStr);
if (i == 1)
return get(StringPool::CoordinatesStr);
if (i == 2)
return get(StringPool::NameStr);
throw std::out_of_range("geom: Out of range.");
}

uint32_t Geometry::size() const {
return 2 + (geomData_->sourceDataReferences_ ? 1 : 0);
return 3 + (geomData_->sourceDataReferences_ ? 1 : 0);
}

ModelNode::Ptr Geometry::get(const StringId& f) const {
Expand Down Expand Up @@ -156,6 +170,14 @@ ModelNode::Ptr Geometry::get(const StringId& f) const {
model_, ModelNodeAddress{TileFeatureLayer::ColumnId::PointBuffers, addr_.index()});
}
}
if (f == StringPool::NameStr) {
auto resolvedString = model().strings()->resolve(geomData_->geomName_);
return model_ptr<ValueNode>::make(
resolvedString ?
*resolvedString :
std::string_view("<Could not resolve geometry name>"),
model_);
}
return {};
}

Expand All @@ -167,6 +189,7 @@ StringId Geometry::keyAt(int64_t i) const {
}
if (i == 0) return StringPool::TypeStr;
if (i == 1) return StringPool::CoordinatesStr;
if (i == 2) return StringPool::NameStr;
throw std::out_of_range("geom: Out of range.");
}

Expand Down Expand Up @@ -213,8 +236,9 @@ GeomType Geometry::geomType() const {

bool Geometry::iterate(const IterCallback& cb) const
{
if (!cb(*at(0))) return false;
if (!cb(*at(1))) return false;
for (auto i = 0; i < size(); ++i) {
if (!cb(*at(i))) return false;
}
return true;
}

Expand Down
30 changes: 10 additions & 20 deletions libs/model/src/validity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -365,21 +365,15 @@ model_ptr<Geometry> Validity::simpleGeometry() const
return model().resolveGeometry(*ModelNode::Ptr::make(model_, std::get<ModelNodeAddress>(data_->geomDescr_)));
}

std::vector<Point> Validity::computeGeometry(
SelfContainedGeometry Validity::computeGeometry(
const model_ptr<GeometryCollection>& geometryCollection,
std::string* error) const
{
if (data_->geomDescrType_ == SimpleGeometry) {
// Return the self-contained geometry points.
auto simpleGeom = simpleGeometry();
assert(simpleGeom);
std::vector<Point> result;
result.reserve(simpleGeom->numPoints());
simpleGeom->forEachPoint([&result](auto&& point){
result.emplace_back(point);
return true;
});
return result;
return simpleGeom->toSelfContained();
}

// Find a geometry with a matching name.
Expand All @@ -403,13 +397,7 @@ std::vector<Point> Validity::computeGeometry(
// No geometry description from the attribute - just return the whole
// geometry from the collection.
if (data_->geomDescrType_ == NoGeometry) {
std::vector<Point> result;
result.reserve(geometry->numPoints());
geometry->forEachPoint([&result](auto&& point){
result.emplace_back(point);
return true;
});
return result;
return geometry->toSelfContained();
}

// Now we have OffsetPointValidity or OffsetRangeValidity
Expand All @@ -434,7 +422,8 @@ std::vector<Point> Validity::computeGeometry(

// Handle GeoPosOffset (a range of the geometry line, bound by two positions).
if (offsetType == GeoPosOffset) {
return geometryFromPositionBound(geometry, startPoint, endPoint);
auto points = geometryFromPositionBound(geometry, startPoint, endPoint);
return {points, points.size() > 1 ? GeomType::Line : GeomType::Points};
}

// Handle BufferOffset (a range of the goemetry bound by two indices).
Expand All @@ -461,11 +450,11 @@ std::vector<Point> Validity::computeGeometry(
std::swap(startPointIndex, endPointIndex);
}

std::vector<Point> result;
std::vector<Point> points;
for (auto pointIndex = startPointIndex; pointIndex <= endPointIndex; ++pointIndex) {
result.emplace_back(geometry->pointAt(pointIndex));
points.emplace_back(geometry->pointAt(pointIndex));
}
return result;
return {points, points.size() > 1 ? GeomType::Line : GeomType::Points};
}

// Handle RelativeLengthOffset (a percentage range of the geometry).
Expand All @@ -480,7 +469,8 @@ std::vector<Point> Validity::computeGeometry(

// Handle MetricLengthOffset (a length range of the geometry in meters).
if (offsetType == MetricLengthOffset || offsetType == RelativeLengthOffset) {
return geometryFromLengthBound(geometry, startPoint.x, endPoint ? std::optional<double>(endPoint->x) : std::optional<double>());
auto points = geometryFromLengthBound(geometry, startPoint.x, endPoint ? std::optional<double>(endPoint->x) : std::optional<double>());
return {points, points.size() > 1 ? GeomType::Line : GeomType::Points};
}

if (error) {
Expand Down
8 changes: 4 additions & 4 deletions test/unit/test-model-geometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -418,11 +418,11 @@ TEST_CASE("Attribute Validity", "[validity]") {
DYNAMIC_SECTION(fmt::format("Validity Index #{}", validityIndex))
{
auto wgsPoints = validity.computeGeometry(geometryCollection);
log().info("Points #{}: {}", validityIndex, nlohmann::json(wgsPoints).dump());
log().info("Points #{}: {}", validityIndex, nlohmann::json(wgsPoints.points_).dump());
auto const& expectedWgsPoints = expectedGeometry[validityIndex];
REQUIRE(wgsPoints.size() == expectedWgsPoints.size());
for (auto pointIndex = 0; pointIndex < wgsPoints.size(); ++pointIndex) {
auto const& computedPoint = wgsPoints[pointIndex];
REQUIRE(wgsPoints.points_.size() == expectedWgsPoints.size());
for (auto pointIndex = 0; pointIndex < wgsPoints.points_.size(); ++pointIndex) {
auto const& computedPoint = wgsPoints.points_[pointIndex];
auto const& expectedPoint = expectedWgsPoints[pointIndex];
using namespace Catch::Matchers;
REQUIRE_THAT(computedPoint.x, WithinRel(expectedPoint.x));
Expand Down

0 comments on commit 5dbf63e

Please sign in to comment.