Skip to content

Commit 21cfd03

Browse files
authored
Merge pull request #5362 from IfcOpenShell/fix-ifccircle-ifcellipse-processing
Fix error processing IfcCircle/IfcEllipse #5352
2 parents 51211dc + 1697e49 commit 21cfd03

7 files changed

Lines changed: 304 additions & 134 deletions

File tree

src/ifcgeom/AbstractKernel.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,15 @@ bool ifcopenshell::geometry::kernels::AbstractKernel::convert(const taxonomy::pt
3030
try {
3131
return dispatch_conversion<0>::dispatch(this, item->kind(), item, results);
3232
} catch (std::exception& e) {
33-
Logger::Error(e, item->instance);
34-
return false;
33+
std::string prev_exception = std::string(e.what());
34+
try {
35+
return dispatch_with_upgrade<0>::dispatch(this, item, results);
36+
} catch (std::exception& e) {
37+
Logger::Error(prev_exception + " Conversion for upgraded element failed with: " + std::string(e.what()), item->instance);
38+
return false;
39+
} catch (...) {
40+
return false;
41+
}
3542
} catch (...) {
3643
// @todo we can't log OCCT exceptions here, can we do some reraising to solve this?
3744
return false;

src/ifcgeom/AbstractKernel.h

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ namespace {
8686
struct dispatch_conversion {
8787
static bool dispatch(ifcopenshell::geometry::kernels::AbstractKernel* kernel, ifcopenshell::geometry::taxonomy::kinds item_kind, const ifcopenshell::geometry::taxonomy::ptr item, IfcGeom::ConversionResults& results) {
8888
if (N == item_kind) {
89-
auto concrete_item = ifcopenshell::geometry::taxonomy::template cast<ifcopenshell::geometry::taxonomy::type_by_kind::type<N>>(item);
89+
auto concrete_item = std::static_pointer_cast<ifcopenshell::geometry::taxonomy::type_by_kind::type<N>>(item);
9090
return kernel->convert_impl(concrete_item, results);
9191
} else {
9292
return dispatch_conversion<N + 1>::dispatch(kernel, item_kind, item, results);
@@ -102,6 +102,26 @@ namespace {
102102
}
103103
};
104104

105+
template <size_t N>
106+
struct dispatch_with_upgrade {
107+
static bool dispatch(ifcopenshell::geometry::kernels::AbstractKernel* kernel, const ifcopenshell::geometry::taxonomy::ptr item, IfcGeom::ConversionResults& results) {
108+
auto concrete_item = ifcopenshell::geometry::taxonomy::template dcast<ifcopenshell::geometry::taxonomy::upgrades::type<N>>(item);
109+
if (concrete_item) {
110+
return kernel->convert_impl(concrete_item, results);
111+
} else {
112+
return dispatch_with_upgrade<N + 1>::dispatch(kernel, item, results);
113+
}
114+
}
115+
};
116+
117+
template <>
118+
struct dispatch_with_upgrade<ifcopenshell::geometry::taxonomy::upgrades::max> {
119+
static bool dispatch(ifcopenshell::geometry::kernels::AbstractKernel*, const ifcopenshell::geometry::taxonomy::ptr item, IfcGeom::ConversionResults&) {
120+
Logger::Error("No conversion with upgrade for " + std::to_string(item->kind()));
121+
return false;
122+
}
123+
};
124+
105125
template <class T, class Tuple>
106126
struct TupleTypeIndex;
107127

src/ifcgeom/mapping/IfcCircle.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,6 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcCircle* inst) {
3434
auto c = taxonomy::make<taxonomy::circle>();
3535
c->radius = r;
3636
c->matrix = taxonomy::cast<taxonomy::matrix4>(map(placement));
37+
3738
return c;
3839
}

src/ifcgeom/taxonomy.cpp

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,3 +594,160 @@ void ifcopenshell::geometry::taxonomy::extrusion::print(std::ostream& o, int ind
594594
direction->print(o, indent + 4);
595595
basis->print(o, indent + 4);
596596
}
597+
598+
boost::optional<face::ptr> ifcopenshell::geometry::taxonomy::loop_to_face_upgrade_impl(ptr item) {
599+
boost::optional<face::ptr> face_;
600+
auto loop_ = dcast<loop>(item);
601+
if (loop_) {
602+
loop_->external = true;
603+
604+
face_ = make<face>();
605+
(*face_)->instance = loop_->instance;
606+
(*face_)->matrix = loop_->matrix;
607+
(*face_)->children = { clone(loop_) };
608+
}
609+
return face_;
610+
}
611+
612+
boost::optional<edge::ptr> ifcopenshell::geometry::taxonomy::curve_to_edge_upgrade_impl(ptr item) {
613+
boost::optional<edge::ptr> edge_;
614+
auto circle_ = dcast<circle>(item);
615+
auto ellipse_ = dcast<ellipse>(item);
616+
auto line_ = dcast<line>(item);
617+
auto bspline_curve_ = dcast<bspline_curve>(item);
618+
if (circle_ || ellipse_ || line_ || bspline_curve_) {
619+
edge_ = make<edge>();
620+
if (circle_) {
621+
(*edge_)->basis = circle_;
622+
(*edge_)->instance = circle_->instance;
623+
} else if (ellipse_) {
624+
(*edge_)->basis = ellipse_;
625+
(*edge_)->instance = ellipse_->instance;
626+
} else if (line_) {
627+
(*edge_)->basis = line_;
628+
(*edge_)->instance = line_->instance;
629+
} else if (bspline_curve_) {
630+
(*edge_)->basis = bspline_curve_;
631+
(*edge_)->instance = bspline_curve_->instance;
632+
}
633+
634+
if (circle_ || ellipse_) {
635+
// @todo
636+
(*edge_)->start = 0.;
637+
(*edge_)->end = 2 * boost::math::constants::pi<double>();
638+
}
639+
}
640+
return edge_;
641+
}
642+
643+
boost::optional<loop::ptr> ifcopenshell::geometry::taxonomy::curve_to_loop_upgrade_impl(ptr item) {
644+
boost::optional<loop::ptr> loop_;
645+
auto circle_ = dcast<circle>(item);
646+
auto ellipse_ = dcast<ellipse>(item);
647+
auto line_ = dcast<line>(item);
648+
auto bspline_curve_ = dcast<bspline_curve>(item);
649+
if (circle_ || ellipse_ || line_ || bspline_curve_) {
650+
auto edge_ = make<edge>();
651+
if (circle_) {
652+
edge_->basis = circle_;
653+
} else if (ellipse_) {
654+
edge_->basis = ellipse_;
655+
} else if (line_) {
656+
edge_->basis = line_;
657+
} else if (bspline_curve_) {
658+
edge_->basis = bspline_curve_;
659+
}
660+
661+
if (circle_ || ellipse_) {
662+
// @todo
663+
edge_->start = 0.;
664+
edge_->end = 2 * boost::math::constants::pi<double>();
665+
}
666+
667+
loop_ = make<loop>();
668+
(*loop_)->children.push_back(edge_);
669+
}
670+
return loop_;
671+
}
672+
673+
boost::optional<loop::ptr> ifcopenshell::geometry::taxonomy::edge_to_loop_upgrade_impl(ptr item) {
674+
boost::optional<loop::ptr> loop_;
675+
auto edge_ = dcast<edge>(item);
676+
if (edge_) {
677+
loop_ = make<loop>();
678+
(*loop_)->children.push_back(edge_);
679+
}
680+
return loop_;
681+
}
682+
683+
boost::optional<face::ptr> ifcopenshell::geometry::taxonomy::curve_to_face_upgrade_impl(ptr item) {
684+
boost::optional<face::ptr> face_;
685+
auto circle_ = dcast<circle>(item);
686+
auto ellipse_ = dcast<ellipse>(item);
687+
auto line_ = dcast<line>(item);
688+
auto bspline_curve_ = dcast<bspline_curve>(item);
689+
690+
if (circle_ || ellipse_ || line_ || bspline_curve_) {
691+
auto edge_ = make<edge>();
692+
if (circle_) {
693+
edge_->basis = circle_;
694+
} else if (ellipse_) {
695+
edge_->basis = ellipse_;
696+
} else if (line_) {
697+
edge_->basis = line_;
698+
} else if (bspline_curve_) {
699+
edge_->basis = bspline_curve_;
700+
}
701+
702+
if (circle_ || ellipse_) {
703+
// @todo
704+
edge_->start = 0.;
705+
edge_->end = 2 * boost::math::constants::pi<double>();
706+
}
707+
708+
auto loop_ = make<loop>();
709+
loop_->children.push_back(edge_);
710+
711+
face_ = make<face>();
712+
(*face_)->instance = loop_->instance;
713+
(*face_)->matrix = loop_->matrix;
714+
(*face_)->children = { clone(loop_) };
715+
}
716+
return face_;
717+
}
718+
719+
720+
boost::optional<piecewise_function::ptr> ifcopenshell::geometry::taxonomy::loop_to_piecewise_function_upgrade_impl(ptr item) {
721+
boost::optional<piecewise_function::ptr> pwf_;
722+
auto loop_ = dcast<loop>(item);
723+
if (loop_) {
724+
if (loop_->pwf.is_initialized()) {
725+
pwf_ = loop_->pwf;
726+
} else {
727+
piecewise_function::spans_t spans;
728+
spans.reserve(loop_->children.size());
729+
for (auto& edge_ : loop_->children) {
730+
// the edge could be an arc or trimmed circle in the case of IfcIndexPolyCurve - support for this isn't implemented yet
731+
if (edge_->basis) {
732+
Logger::Message(Logger::Severity::LOG_NOTICE, "Shape of basis curve ignored - edge is treated as a straight line edge");
733+
}
734+
735+
const auto& s = boost::get<point3::ptr>(edge_->start)->ccomponents();
736+
const auto& e = boost::get<point3::ptr>(edge_->end)->ccomponents();
737+
Eigen::Vector3d v = e - s;
738+
auto l = v.norm(); // the norm of a vector is a measure of its length
739+
v.normalize(); // normalize the vector so that it is a unit direction vector
740+
std::function<Eigen::Matrix4d(double)> fn = [s, v](double u) {
741+
Eigen::Vector3d o(s + u * v), axis(0, 0, 1), refDirection(v);
742+
auto Y = axis.cross(refDirection).normalized();
743+
axis = refDirection.cross(Y).normalized();
744+
return make<matrix4>(o, axis, refDirection)->components();
745+
};
746+
spans.emplace_back(l, fn);
747+
}
748+
pwf_ = make<piecewise_function>(0.0,spans);
749+
loop_->pwf = pwf_;
750+
}
751+
}
752+
return pwf_;
753+
}

0 commit comments

Comments
 (0)