Implement fillets and a couple of profiles

This commit is contained in:
Thomas Krijnen
2020-03-30 14:31:59 +02:00
parent 048ee84ae6
commit 3113976ee5
4 changed files with 234 additions and 23 deletions
@@ -565,12 +565,6 @@ namespace {
curve_creation_visitor_result_type operator()(const taxonomy::circle& c) {
const auto& m = c.matrix.components;
/*Eigen::IOFormat fmt;
std::stringstream ss;
ss << m.format(fmt) << std::endl;
ss << m.col(3).format(fmt);
auto s = ss.str();
std::wcout << s.c_str() << std::endl;*/
return result = Handle(Geom_Curve)(new Geom_Circle(gp_Ax2(convert_xyz2<gp_Pnt>(m.col(3)), convert_xyz2<gp_Dir>(m.col(2)), convert_xyz2<gp_Dir>(m.col(0))), c.radius));
}
@@ -609,17 +603,36 @@ namespace {
curve = approx.Curve();
}
const bool reversed = !((taxonomy::geom_item*)e.basis)->orientation.get_value_or(true);
const bool is_conic = e.basis->kind() == taxonomy::ELLIPSE || e.basis->kind() == taxonomy::CIRCLE;
// @todo, copy over logic from previous IfcTrimmedCurve handling
if (e.start.which() == 0) {
if (e.start.which() == 0) {
auto p1 = convert_xyz<gp_Pnt>(boost::get<taxonomy::point3>(e.start));
auto p2 = convert_xyz<gp_Pnt>(boost::get<taxonomy::point3>(e.end));
if (reversed) {
std::swap(p1, p2);
}
E = BRepBuilderAPI_MakeEdge(curve, p1, p2).Edge();
} else {
auto v1 = boost::get<double>(e.start);
auto v2 = boost::get<double>(e.end);
E = BRepBuilderAPI_MakeEdge(curve, v1, v2).Edge();
if (reversed) {
std::swap(v1, v2);
}
if (is_conic && ALMOST_THE_SAME(fmod(v2 - v1, M_PI*2.), 0.)) {
E = BRepBuilderAPI_MakeEdge(curve).Edge();
} else {
E = BRepBuilderAPI_MakeEdge(curve, v1, v2).Edge();
}
}
if (reversed) {
E.Reverse();
}
} else {
if (e.start.which() != 0) {
+207 -9
View File
@@ -17,6 +17,9 @@
* *
********************************************************************************/
#define _USE_MATH_DEFINES
#include <cmath>
#include "mapping.h"
#include "../../ifcparse/IfcLogger.h"
@@ -70,6 +73,8 @@ namespace {
loop_to_face_upgrade(taxonomy::item* item) {
taxonomy::loop* loop = dynamic_cast<taxonomy::loop*>(item);
if (loop) {
loop->external = true;
face_ = taxonomy::face();
face_->instance = loop->instance;
face_->matrix = loop->matrix;
@@ -1122,10 +1127,10 @@ namespace {
boost::optional<double> radius;
};
struct profile_point_with_neighbours {
std::array<double, 2> xy;
struct profile_point_with_edges {
Eigen::Vector2d xy;
boost::optional<double> radius;
profile_point* previous, *next;
taxonomy::edge *previous, *next;
};
taxonomy::loop* polygon_from_points(const std::vector<taxonomy::point3>& ps, bool external = true) {
@@ -1206,13 +1211,67 @@ namespace {
});
ps.push_back(ps.front());
return polygon_from_points(ps);
auto loop = polygon_from_points(ps);
std::vector<profile_point_with_edges> pps(points.size());
for (int b = 0; b < points.size(); ++b) {
int c = (b - 1) % points.size();
pps[b] = { Eigen::Vector2d(points[b].xy[0], points[b].xy[1]), points[b].radius, (taxonomy::edge*) loop->children[c], (taxonomy::edge*) loop->children[b]};
}
size_t i = pps.size();
while (i--) {
const auto& p = pps[i];
if (p.radius && *p.radius > 0.) {
// Position is a IfcAxis2Placement2D, so should remain 2d points
auto p0 = boost::get<taxonomy::point3>(p.previous->start).components.head<2>();
auto p1a = boost::get<taxonomy::point3>(p.previous->end).components.head<2>();
auto p2 = boost::get<taxonomy::point3>(p.next->end).components.head<2>();
auto p1b = boost::get<taxonomy::point3>(p.next->start).components.head<2>();
auto ba_ = p0 - p1a;
auto bc_ = p2 - p1b;
auto ba = ba_.normalized();
auto bc = bc_.normalized();
const double angle = std::acos(ba.dot(bc));
const double inset = *p.radius / std::tan(angle / 2.);
boost::get<taxonomy::point3>(p.previous->end).components.head<2>() += ba * inset;
boost::get<taxonomy::point3>(p.next->start).components.head<2>() += bc * inset;
auto e = new taxonomy::edge;
e->start = p.previous->end;
e->end = p.next->start;
auto ab = Eigen::Vector3d(-ba(1), +ba(0), 0.);
double sign = ab.head<2>().dot(bc) > 0 ? 1. : -1.;
auto O = boost::get<taxonomy::point3>(p.previous->end).components.head<3>() + ab * *p.radius * sign;
auto c = new taxonomy::circle;
c->matrix.components = Eigen::Affine3d(Eigen::Translation3d(O)).matrix();
c->radius = *p.radius;
e->basis = c;
c->orientation = sign == -1.;
loop->children.insert(std::find(loop->children.begin(), loop->children.end(), p.next), e);
}
};
return loop;
}
}
taxonomy::item* mapping::map_impl(const IfcSchema::IfcRectangleProfileDef* inst) {
const double x = inst->XDim() / 2.0f * length_unit_;
const double y = inst->YDim() / 2.0f * length_unit_;
boost::optional<double> radius;
if (inst->as<IfcSchema::IfcRoundedRectangleProfileDef>()) {
radius = inst->as<IfcSchema::IfcRoundedRectangleProfileDef>()->RoundingRadius() * length_unit_;
}
// @todo
const double precision_ = 1.e-5;
@@ -1223,10 +1282,150 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcRectangleProfileDef* inst)
}
return profile_helper(this, inst, {
{{-x, -y}},
{{+x, -y}},
{{+x, +y}},
{{-x, +y}},
{{-x, -y}, radius},
{{+x, -y}, radius},
{{+x, +y}, radius},
{{-x, +y}, radius},
});
}
taxonomy::item* mapping::map_impl(const IfcSchema::IfcRectangleHollowProfileDef* inst) {
const double x = inst->XDim() / 2.0f * length_unit_;
const double y = inst->YDim() / 2.0f * length_unit_;
const double d = inst->WallThickness() * length_unit_;
boost::optional<double> radius1, radius2;
if (inst->hasOuterFilletRadius()) {
radius1 = inst->OuterFilletRadius() * length_unit_;
}
if (inst->hasInnerFilletRadius()) {
radius2 = inst->InnerFilletRadius() * length_unit_;
}
// @todo
const double precision_ = 1.e-5;
if (x < precision_ || y < precision_) {
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", inst);
return nullptr;
}
auto outer_loop = profile_helper(this, inst, {
{{-x, -y}, radius1},
{{+x, -y}, radius1},
{{+x, +y}, radius1},
{{-x, +y}, radius1},
});
outer_loop->external = true;
auto inner_loop = profile_helper(this, inst, {
{{-x + d, -y + d}, radius2},
{{+x - d, -y + d}, radius2},
{{+x - d, +y - d}, radius2},
{{-x + d, +y - d}, radius2},
});
inner_loop->reverse();
inner_loop->external = false;
auto face = new taxonomy::face;
face->children = { outer_loop, inner_loop };
// @todo is this necessary;
std::swap(outer_loop->matrix, face->matrix);
inner_loop->matrix = outer_loop->matrix;
return face;
}
taxonomy::item* mapping::map_impl(const IfcSchema::IfcCircleProfileDef* inst) {
std::vector<double> radii = { inst->Radius() * length_unit_ };
if (inst->as<IfcSchema::IfcCircleHollowProfileDef>()) {
double t = inst->as<IfcSchema::IfcCircleHollowProfileDef>()->WallThickness() * length_unit_;
radii.push_back(radii.front() - t);
}
auto f = new taxonomy::face;
for (auto it = radii.begin(); it != radii.end(); ++it) {
const double r = *it;
const bool exterior = it == radii.begin();
auto c = new taxonomy::circle;
c->radius = r;
bool has_position = true;
#ifdef SCHEMA_IfcParameterizedProfileDef_Position_IS_OPTIONAL
has_position = inst->hasPosition();
#endif
if (has_position) {
taxonomy::matrix4 m = as<taxonomy::matrix4>(map(inst->Position()));
c->matrix = m.components;
}
auto e = new taxonomy::edge;
e->basis = c;
e->start = 0.;
e->end = 2 * M_PI;
auto l = new taxonomy::loop;
l->children = { e };
l->external = exterior;
f->children.push_back(l);
}
return f;
}
taxonomy::item* mapping::map_impl(const IfcSchema::IfcIShapeProfileDef* inst) {
const double x1 = inst->OverallWidth() / 2.0f * length_unit_;
const double y = inst->OverallDepth() / 2.0f * length_unit_;
const double d1 = inst->WebThickness() / 2.0f * length_unit_;
const double dy1 = inst->FlangeThickness() * length_unit_;
bool doFillet1 = inst->hasFilletRadius();
double f1 = 0.;
if (doFillet1) {
f1 = inst->FilletRadius() * length_unit_;
}
bool doFillet2 = doFillet1;
double x2 = x1, dy2 = dy1, f2 = f1;
if (inst->declaration().is(IfcSchema::IfcAsymmetricIShapeProfileDef::Class())) {
IfcSchema::IfcAsymmetricIShapeProfileDef* assym = (IfcSchema::IfcAsymmetricIShapeProfileDef*) inst;
x2 = assym->TopFlangeWidth() / 2. * length_unit_;
doFillet2 = assym->hasTopFlangeFilletRadius();
if (doFillet2) {
f2 = assym->TopFlangeFilletRadius() * length_unit_;
}
if (assym->hasTopFlangeThickness()) {
dy2 = assym->TopFlangeThickness() * length_unit_;
}
}
// @todo
const double precision_ = 1.e-5;
if (x1 < precision_ || x2 < precision_ || y < precision_ || d1 < precision_ || dy1 < precision_ || dy2 < precision_) {
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", inst);
return false;
}
return profile_helper(this, inst, {
{{-x1,-y}},
{{x1,-y}},
{{x1,-y + dy1}},
{{d1,-y + dy1}, f1},
{{d1,y - dy2}, f2},
{{x2,y - dy2}},
{{x2,y}},
{{-x2,y}},
{{-x2,y - dy2}},
{{-d1,y - dy2}, f2},
{{-d1,-y + dy1}, f1},
{{-x1,-y + dy1}}
});
}
@@ -1389,7 +1588,6 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcTrimmedCurve* inst) {
// @todo
const double precision_ = 1.e-5;
const double M_PI = 3.141592653;
trim_cartesian &= has_pnts[0] && has_pnts[1];
if (trim_cartesian) {
+5 -5
View File
@@ -74,19 +74,19 @@ BIND(IfcHalfSpaceSolid);
// IfcArbitraryProfileDefWithVoids included
BIND(IfcArbitraryClosedProfileDef);
// BIND(IfcRoundedRectangleProfileDef);
// BIND(IfcRectangleHollowProfileDef);
BIND(IfcRectangleHollowProfileDef);
// IfcRoundedRectangleProfileDef included
BIND(IfcRectangleProfileDef);
// BIND(IfcTrapeziumProfileDef)
// BIND(IfcCShapeProfileDef);
// IfcAsymmetricIShapeProfileDef included
// BIND(IfcIShapeProfileDef);
BIND(IfcIShapeProfileDef);
// BIND(IfcLShapeProfileDef);
// BIND(IfcTShapeProfileDef);
// BIND(IfcUShapeProfileDef);
// BIND(IfcZShapeProfileDef);
// BIND(IfcCircleHollowProfileDef);
// BIND(IfcCircleProfileDef);
// IfcCircleHollowProfileDef included
BIND(IfcCircleProfileDef);
// BIND(IfcEllipseProfileDef);
// BIND(IfcCenterLineProfileDef);
// BIND(IfcCompositeProfileDef);
+1 -1
View File
@@ -161,7 +161,7 @@ struct trimmed_curve : public curve {
trimmed_curve() : basis(nullptr), orientation(true) {}
virtual void reverse() {
std::swap(start, end);
// std::swap(start, end);
orientation = !orientation;
}
};