Skip to content

Commit

Permalink
First attempt at taxonomy::implicit_item
Browse files Browse the repository at this point in the history
  • Loading branch information
aothms committed Sep 29, 2023
1 parent d50dcad commit b51b451
Show file tree
Hide file tree
Showing 7 changed files with 259 additions and 55 deletions.
2 changes: 2 additions & 0 deletions src/ifcgeom/AbstractKernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ namespace ifcopenshell { namespace geometry { namespace kernels {
virtual bool convert_impl(const taxonomy::surface_curve_sweep::ptr, IfcGeom::ConversionResults&) { throw std::runtime_error("Not implemented"); }
virtual bool convert_impl(const taxonomy::loft::ptr, IfcGeom::ConversionResults&) { throw std::runtime_error("Not implemented"); }
virtual bool convert_impl(const taxonomy::collection::ptr, IfcGeom::ConversionResults&);
virtual bool convert_impl(const taxonomy::piecewise_function::ptr item, IfcGeom::ConversionResults& cs) { return convert(item->evaluate(), cs); }


/*
virtual void set_offset(const std::array<double, 3> &p_offset);
Expand Down
23 changes: 17 additions & 6 deletions src/ifcgeom/mapping/IfcCompositeCurve.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ using namespace ifcopenshell::geometry;

taxonomy::ptr mapping::map_impl(const IfcSchema::IfcCompositeCurve* inst) {
auto loop = taxonomy::make<taxonomy::loop>();
auto pwf = taxonomy::make<taxonomy::piecewise_function>();

#ifdef SCHEMA_HAS_IfcSegment
// 4x3
Expand Down Expand Up @@ -66,18 +67,28 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcCompositeCurve* inst) {
}
#ifdef SCHEMA_HAS_IfcCurveSegment
else if (segment->as<IfcSchema::IfcCurveSegment>()) {
// @todo check that we don't get a mixture of implicit and explicit definitions
auto crv = map(segment->as<IfcSchema::IfcCurveSegment>());
for (auto& s : taxonomy::cast<taxonomy::loop>(crv)->children) {
loop->children.push_back(s);
if (crv->kind() == taxonomy::LOOP) {
for (auto& s : taxonomy::cast<taxonomy::loop>(crv)->children) {
loop->children.push_back(s);
}
} else if (crv->kind() == taxonomy::PIECEWISE_FUNCTION) {
auto seg = taxonomy::cast<taxonomy::piecewise_function>(crv);
pwf->spans.insert(pwf->spans.end(), seg->spans.begin(), seg->spans.end());
}
}
#endif
}

aggregate_of_instance::ptr profile = inst->data().getInverse(&IfcSchema::IfcProfileDef::Class(), -1);
const bool force_close = profile && profile->size() > 0;
loop->closed = force_close;
return loop;
if (pwf->spans.empty()) {
aggregate_of_instance::ptr profile = inst->data().getInverse(&IfcSchema::IfcProfileDef::Class(), -1);
const bool force_close = profile && profile->size() > 0;
loop->closed = force_close;
return loop;
} else {
return pwf;
}
}

/*
Expand Down
143 changes: 98 additions & 45 deletions src/ifcgeom/mapping/IfcCurveSegment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,32 +27,11 @@ using namespace ifcopenshell::geometry;

#include <boost/mpl/vector.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/math/quadrature/trapezoidal.hpp>

// @todo use std::numbers::pi when upgrading to C++ 20
#define PI 3.1415926535897932384626433832795


namespace
{
// trapezoid rule integration
// @todo is there a well established math library we can use instead of
// creating our own integrator?
double integrate(double a, double b, unsigned n, std::function<double(double)> fn)
{
double area = 0;
double h = (b - a) / n;
for (auto i = 1; i <= n; i++)
{
auto x1 = a + h * (i - 1);
auto x2 = a + h * i;
auto f1 = fn(x1);
auto f2 = fn(x2);
area += h * (f1 + f2) / 2.0;
}
return area;
}
}

typedef boost::mpl::vector<
IfcSchema::IfcLine
#ifdef SCHEMA_HAS_IfcClothoid
Expand All @@ -65,19 +44,25 @@ typedef boost::mpl::vector<
, IfcSchema::IfcCircle
> curve_seg_types;

enum segment_type_t {
ST_HORIZONTAL, ST_VERTICAL, ST_CANT
};

class curve_segment_evaluator {
private:
double length_unit_;
double start_;
double length_;
segment_type_t segment_type_;
IfcSchema::IfcCurve* curve_;

std::optional<std::function<Eigen::Vector3d(double)>> eval_;
std::optional<std::function<Eigen::VectorXd(double)>> eval_;

public:
// First constructor, takes parameters from IfcCurveSegment
curve_segment_evaluator(double length_unit, IfcSchema::IfcCurve* curve, IfcSchema::IfcCurveMeasureSelect* st, IfcSchema::IfcCurveMeasureSelect* le)
curve_segment_evaluator(double length_unit, segment_type_t segment_type, IfcSchema::IfcCurve* curve, IfcSchema::IfcCurveMeasureSelect* st, IfcSchema::IfcCurveMeasureSelect* le)
: length_unit_(length_unit)
, segment_type_(segment_type)
, curve_(curve)
{
// @todo in IFC4X3_ADD2 this needs to be length measure
Expand Down Expand Up @@ -146,7 +131,7 @@ class curve_segment_evaluator {
// // transform point into clothoid's coodinate system
// auto x = xl * cos(theta) - yl * sin(theta) + Cx;
// auto y = xl * sin(theta) + yl * cos(theta) + Cy;
// return Eigen::Vector3d(x, y, 0.0);
// return Eigen::VectorXd(x, y, 0.0);
// };
// }
//#endif
Expand Down Expand Up @@ -185,21 +170,26 @@ class curve_segment_evaluator {
auto Cy = C->as<IfcSchema::IfcCartesianPoint>()->Coordinates()[1];

eval_ = [L, Cx, Cy, theta, signX, fnX, signY, fnY](double u) {
using boost::math::quadrature::trapezoidal;

// integration limits, integrate from a to b
// from 8.9.3.19.1, integration limits are 0.0 to u where u is a normalized parameter
auto a = 0.0;
auto b = fabs(u / L);

auto n = 10; // use 10 steps in the numeric integration
// @todo where to plug this in?
// auto n = 10; // use 10 steps in the numeric integration

auto xl = signX(u)*integrate(a, b, n, fnX);
auto yl = signY(u)*integrate(a, b, n, fnY);
auto xl = signX(u)*trapezoidal(fnX, a, b);
auto yl = signY(u)*trapezoidal(fnY, a, b);

// transform point into clothoid's coodinate system
auto x = xl * cos(theta) - yl * sin(theta) + Cx;
auto y = xl * sin(theta) + yl * cos(theta) + Cy;
return Eigen::Vector3d(x, y, 0.0);
};
Eigen::VectorXd vec(3);
vec << x, y, 0.0;
return vec;
};
}

// Clothoid using numerical integration
Expand Down Expand Up @@ -290,8 +280,10 @@ class curve_segment_evaluator {
// transform point into circle's coodinate system
auto x = xl * cos(theta) - yl * sin(theta) + Cx;
auto y = xl * sin(theta) + yl * cos(theta) + Cy;
return Eigen::Vector3d(x, y, 0.0);
};
Eigen::VectorXd vec;
vec << x, y, 0.0;
return vec;
};
}

void operator()(IfcSchema::IfcPolyline* pl)
Expand Down Expand Up @@ -361,8 +353,10 @@ class curve_segment_evaluator {

auto [u_start, u_end, compare] = iter->first;
auto [x,y] = (iter->second)(u - u_start); // (u - u_start) is distance from start of this segment of the polyline
return Eigen::Vector3d(x, y, 0);
};
Eigen::VectorXd vec;
vec << x, y, 0;
return vec;
};
}

void operator()(IfcSchema::IfcLine* l) {
Expand All @@ -376,11 +370,27 @@ class curve_segment_evaluator {
auto dx = dr[0] / m;
auto dy = dr[1] / m;

eval_ = [px, py, dx, dy](double u) {
auto x = px + u * dx;
auto y = py + u * dy;
return Eigen::Vector3d(x, y, 0);
if (segment_type_ == ST_HORIZONTAL) {

eval_ = [px, py, dx, dy](double u) {
auto x = px + u * dx;
auto y = py + u * dy;
Eigen::VectorXd vec;
vec << x, y, 0;
return vec;
};

} else if (segment_type_ == ST_VERTICAL) {

eval_ = [px, py, dx, dy](double u) {
// @todo this can't be correct
auto z = u * dy;
Eigen::VectorXd vec;
vec << z;
return vec;
};

}
}

// Take the boost::type value from mpl::for_each and test it against our curve instance
Expand All @@ -392,7 +402,7 @@ class curve_segment_evaluator {
}

// Then, with function populated based on IfcCurve subtype, we can evaluate to points
Eigen::Vector3d operator()(double u) {
Eigen::VectorXd operator()(double u) {
if (eval_) {
return (*eval_)((u + start_) * length_unit_);
} else {
Expand All @@ -403,23 +413,65 @@ class curve_segment_evaluator {
double length() const {
return length_;
}

const std::optional<std::function<Eigen::VectorXd(double)>>& evaluation_function() const {
return eval_;
}
};

taxonomy::ptr mapping::map_impl(const IfcSchema::IfcCurveSegment* inst) {
// @todo fixed number of segments or fixed interval?
// @todo placement
// @todo figure out what to do with the zero length segments at the end of compound curves

static int NUM_SEGMENTS = 64;
curve_segment_evaluator cse(length_unit_, inst->ParentCurve(), inst->SegmentStart(), inst->SegmentLength());
boost::mpl::for_each<curve_seg_types, boost::type<boost::mpl::_>>(std::ref(cse));
bool is_horizontal = false;
bool is_vertical = false;
bool is_cant = false;

std::vector<taxonomy::point3::ptr> polygon;
{
aggregate_of_instance::ptr segment_owners = inst->data().getInverse(&IfcSchema::IfcCompositeCurve::Class(), 0);
if (segment_owners) {
for (auto& cc : *segment_owners) {
if (cc->as<IfcSchema::IfcSegmentedReferenceCurve>()) {
is_cant = true;
} else if (cc->as<IfcSchema::IfcGradientCurve>()) {
is_vertical = true;
} else {
is_horizontal = true;
}
}
}
}

if ((is_horizontal + is_vertical + is_cant) != 1) {
// We have to choose the correct functor based on usage. We can't
// support multiple, because we don't know the caller at this point.
return nullptr;
}

auto segment_type = is_horizontal ? ST_HORIZONTAL : is_vertical ? ST_VERTICAL : ST_CANT;

curve_segment_evaluator cse(length_unit_, segment_type, inst->ParentCurve(), inst->SegmentStart(), inst->SegmentLength());
boost::mpl::for_each<curve_seg_types, boost::type<boost::mpl::_>>(std::ref(cse));

auto fn = *cse.evaluation_function();
auto length = cse.length();

This comment has been minimized.

Copy link
@RickBrice

RickBrice Oct 2, 2023

Contributor

I think this needs to be

auto length = fabs(cse.length());

Length can be a negative value.


// @todo - for some reason this isn't working, the matrix gets all messed up
//const auto& transformation_matrix = taxonomy::cast<taxonomy::matrix4>(map(inst->Placement()))->ccomponents();
auto transformation_matrix = taxonomy::cast<taxonomy::matrix4>(map(inst->Placement()))->ccomponents();

auto fn_transformed = [fn, transformation_matrix](double u) {
return transformation_matrix * fn(u);
};

// @todo it might be suboptimal that we no longer have the spans now
auto pwf = taxonomy::make<taxonomy::piecewise_function>();
pwf->spans.push_back({ length, fn_transformed });
return pwf;

/*
static int NUM_SEGMENTS = 64;
std::vector<taxonomy::point3::ptr> polygon;
auto length = cse.length();
if (0.001 < fabs(length))
{
Expand All @@ -433,6 +485,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcCurveSegment* inst) {
}
return polygon_from_points(polygon);
*/
}

#endif
76 changes: 76 additions & 0 deletions src/ifcgeom/mapping/IfcGradientCurve.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/

#include "mapping.h"
#define mapping POSTFIX_SCHEMA(mapping)
using namespace ifcopenshell::geometry;

#ifdef SCHEMA_HAS_IfcGradientCurve

taxonomy::ptr mapping::map_impl(const IfcSchema::IfcGradientCurve* inst) {
auto horizontal = taxonomy::cast<taxonomy::piecewise_function>(map(inst->BaseCurve()));
auto vertical = taxonomy::make<taxonomy::piecewise_function>();

auto segments = inst->Segments();

for (auto& segment : *segments) {
if (segment->as<IfcSchema::IfcCurveSegment>()) {
// @todo check that we don't get a mixture of implicit and explicit definitions
auto crv = map(segment->as<IfcSchema::IfcCurveSegment>());
if (crv->kind() == taxonomy::PIECEWISE_FUNCTION) {
auto seg = taxonomy::cast<taxonomy::piecewise_function>(crv);
vertical->spans.insert(vertical->spans.end(), seg->spans.begin(), seg->spans.end());
} else {
Logger::Error("Unsupported");
return nullptr;
}
} else {
Logger::Error("Unsupported");
return nullptr;
}
}

// @todo does this really make sense?
auto composition = [horizontal, vertical](double u) {
auto xy = horizontal->evaluate(u);
auto z = vertical->evaluate(u);
Eigen::VectorXd vec(3);
vec << xy(0), xy(1), z(0);
return vec;
};

// @todo where do we get the startdistalong from @civilx64's code?
std::array<taxonomy::piecewise_function::ptr, 2> both = { horizontal , vertical };
double min_length = std::numeric_limits<double>::infinity();
for (auto i = 0; i < 2; ++i) {
double l = 0;
for (auto& s : both[i]->spans) {
l += s.first;
}
if (l < min_length) {
min_length = l;
}
}

auto pwf = taxonomy::make<taxonomy::piecewise_function>();
pwf->spans.push_back({ min_length, composition });
return pwf;
}

#endif
5 changes: 4 additions & 1 deletion src/ifcgeom/mapping/mapping.i
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ BIND(IfcEdge);
BIND(IfcEdgeLoop);
BIND(IfcPolyline);
BIND(IfcPolyLoop);
#ifdef SCHEMA_HAS_IfcGradientCurve
BIND(IfcGradientCurve);
#endif
BIND(IfcCompositeCurve);
BIND(IfcTrimmedCurve);
BIND(IfcArbitraryOpenProfileDef);
Expand Down Expand Up @@ -150,4 +153,4 @@ BIND(IfcStyledItem); // -> style

#ifdef SCHEMA_HAS_IfcCurveSegment
BIND(IfcCurveSegment);
#endif
#endif

0 comments on commit b51b451

Please sign in to comment.