Merge pull request #8 from kenohori/cgal

More profiles (T, U, Z) and support for openings
This commit is contained in:
Ken Arroyo Ohori
2017-03-09 18:45:34 -06:00
committed by GitHub
5 changed files with 398 additions and 17 deletions
@@ -54,9 +54,15 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPlane* pln, cgal_plane_t&
IfcSchema::IfcAxis2Placement3D* l = pln->Position();
cgal_point_t o;
cgal_direction_t axis = Kernel::Vector_3(0,0,1);
cgal_direction_t refDirection;
IfcGeom::CgalKernel::convert(l->Location(),o);
bool hasRef = l->hasRefDirection();
if ( l->hasAxis() ) IfcGeom::CgalKernel::convert(l->Axis(),axis);
plane = Kernel::Plane_3(o, axis);
if ( hasRef ) IfcGeom::CgalKernel::convert(l->RefDirection(),refDirection);
cgal_plane_t ax3;
if ( hasRef ) ax3 = Kernel::Plane_3(o,o+axis,o+refDirection);
else ax3 = Kernel::Plane_3(o,axis);
plane = ax3;
// CACHE(IfcPlane,pln,plane)
return true;
}
@@ -63,6 +63,9 @@ FACE(IfcEllipseProfileDef);
FACE(IfcCShapeProfileDef);
FACE(IfcIShapeProfileDef);
FACE(IfcLShapeProfileDef);
FACE(IfcTShapeProfileDef);
FACE(IfcUShapeProfileDef);
FACE(IfcZShapeProfileDef);
WIRE(IfcEdgeLoop);
WIRE(IfcOrientedEdge);
@@ -655,3 +655,304 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcIShapeProfileDef* l, cgal_
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTShapeProfileDef* l, cgal_face_t& face) {
const bool doFlangeEdgeFillet = l->hasFlangeEdgeRadius();
const bool doWebEdgeFillet = l->hasWebEdgeRadius();
const bool doFillet = l->hasFilletRadius();
const bool hasFlangeSlope = l->hasFlangeSlope();
const bool hasWebSlope = l->hasWebSlope();
const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double x = l->FlangeWidth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double d1 = l->WebThickness() * getValue(GV_LENGTH_UNIT);
const double d2 = l->FlangeThickness() * getValue(GV_LENGTH_UNIT);
const double flangeSlope = hasFlangeSlope ? (l->FlangeSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;
const double webSlope = hasWebSlope ? (l->WebSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
double dy1 = 0.0f;
double dy2 = 0.0f;
double dx1 = 0.0f;
double dx2 = 0.0f;
double f1 = 0.0f;
double f2 = 0.0f;
double f3 = 0.0f;
if (doFillet) {
f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
}
if (doWebEdgeFillet) {
f2 = l->WebEdgeRadius() * getValue(GV_LENGTH_UNIT);
}
if (doFlangeEdgeFillet) {
f3 = l->FlangeEdgeRadius() * getValue(GV_LENGTH_UNIT);
}
double xx, xy;
if (hasFlangeSlope) {
dy1 = (x / 2. - d1) * tan(flangeSlope);
dy2 = x / 2. * tan(flangeSlope);
}
if (hasWebSlope) {
dx1 = (y - d2) * tan(webSlope);
dx2 = y * tan(webSlope);
}
if (hasWebSlope || hasFlangeSlope) {
const double x1s = d1/2. - dx2; const double y1s = -y;
const double x1e = d1/2. + dx1; const double y1e = y - d2;
const double x2s = x; const double y2s = y - d2 + dy2;
const double x2e = d1/2.; const double y2e = y - d2 - dy1;
const double a1 = y1e - y1s;
const double b1 = x1s - x1e;
const double c1 = a1*x1s + b1*y1s;
const double a2 = y2e - y2s;
const double b2 = x2s - x2e;
const double c2 = a2*x2s + b2*y2s;
const double det = a1*b2 - a2*b1;
if (ALMOST_THE_SAME(det, 0.)) {
Logger::Message(Logger::LOG_NOTICE, "Web and flange do not intersect for:",l->entity);
return false;
}
xx = (b2*c1 - b1*c2) / det;
xy = (a1*c2 - a2*c1) / det;
} else {
xx = d1 / 2;
xy = y - d2;
}
cgal_placement_t trsf2d;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
const int segments = 3;
face = cgal_face_t();
if (f2 == 0.0) {
face.outer.push_back(Kernel::Point_3(d1/2.-dx2, -y, 0.0));
} else {
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel::Point_3(d1/2.-dx2-f2+f2*cos(current_angle), -y+f2+f2*sin(current_angle), 0));
}
} if (f1 == 0.0) {
face.outer.push_back(Kernel::Point_3(xx, xy, 0.0));
} else {
for (int current_segment = segments; current_segment >= 0; --current_segment) {
double current_angle = 0.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel::Point_3(xx+f1+f1*cos(current_angle), xy-f1+f1*sin(current_angle), 0));
}
} if (f3 == 0.0) {
face.outer.push_back(Kernel::Point_3(x, y-d2+dy2, 0.0));
} else {
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel::Point_3(x-f3+f3*cos(current_angle), y-d2+dy2+f3+f3*sin(current_angle), 0));
}
} face.outer.push_back(Kernel::Point_3(x, y, 0.0));
face.outer.push_back(Kernel::Point_3(-x, y, 0.0));
if (f3 == 0.0) {
face.outer.push_back(Kernel::Point_3(-x, y-d2+dy2, 0.0));
} else {
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel::Point_3(-x+f3+f3*cos(current_angle), y-d2+dy2+f3+f3*sin(current_angle), 0));
}
} if (f1 == 0.0) {
face.outer.push_back(Kernel::Point_3(-xx, xy, 0.0));
} else {
for (int current_segment = segments; current_segment >= 0; --current_segment) {
double current_angle = current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel::Point_3(-xx-f1+f1*cos(current_angle), xy-f1+f1*sin(current_angle), 0));
}
} if (f2 == 0.0) {
face.outer.push_back(Kernel::Point_3(-d1/2.+dx2, -y, 0.0));
} else {
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel::Point_3(-d1/2.+dx2+f2+f2*cos(current_angle), -y+f2+f2*sin(current_angle), 0));
}
}
if (has_position) {
IfcGeom::CgalKernel::convert(l->Position(), trsf2d);
for (auto &vertex: face.outer) {
vertex = vertex.transform(trsf2d);
}
}
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcUShapeProfileDef* l, cgal_face_t& face) {
const bool doEdgeFillet = l->hasEdgeRadius();
const bool doFillet = l->hasFilletRadius();
const bool hasSlope = l->hasFlangeSlope();
const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double x = l->FlangeWidth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double d1 = l->WebThickness() * getValue(GV_LENGTH_UNIT);
const double d2 = l->FlangeThickness() * getValue(GV_LENGTH_UNIT);
const double slope = hasSlope ? (l->FlangeSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;
double dy1 = 0.0f;
double dy2 = 0.0f;
double f1 = 0.0f;
double f2 = 0.0f;
if (doFillet) {
f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
}
if (doEdgeFillet) {
f2 = l->EdgeRadius() * getValue(GV_LENGTH_UNIT);
}
if (hasSlope) {
dy1 = (x - d1) * tan(slope);
dy2 = x * tan(slope);
}
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
cgal_placement_t trsf2d;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
const int segments = 3;
face = cgal_face_t();
face.outer.push_back(Kernel::Point_3(-x, -y, 0.0));
face.outer.push_back(Kernel::Point_3(x, -y, 0.0));
if (f2 == 0.0) {
face.outer.push_back(Kernel::Point_3(x, -y+d2-dy2, 0.0));
} else {
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel::Point_3(x-f2+f2*cos(current_angle), -y+d2-dy2-f2+f2*sin(current_angle), 0));
}
} if (f1 == 0.0) {
face.outer.push_back(Kernel::Point_3(-x+d1, -y+d2+dy1, 0.0));
} else {
for (int current_segment = segments; current_segment >= 0; --current_segment) {
double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel::Point_3(-x+d1+f1+f1*cos(current_angle), -y+d2+dy1+f1+f1*sin(current_angle), 0));
}
} if (f1 == 0.0) {
face.outer.push_back(Kernel::Point_3(-x+d1, y-d2-dy1, 0.0));
} else {
for (int current_segment = segments; current_segment >= 0; --current_segment) {
double current_angle = 0.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel::Point_3(-x+d1+f1+f1*cos(current_angle), y-d2-dy1-f1+f1*sin(current_angle), 0));
}
} if (f2 == 0.0) {
face.outer.push_back(Kernel::Point_3(x,y-d2+dy2, 0.0));
} else {
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel::Point_3(x-f2+f2*cos(current_angle), y-d2+dy2+f2+f2*sin(current_angle), 0));
}
} face.outer.push_back(Kernel::Point_3(x,y, 0.0));
face.outer.push_back(Kernel::Point_3(-x,y, 0.0));
if (has_position) {
IfcGeom::CgalKernel::convert(l->Position(), trsf2d);
for (auto &vertex: face.outer) {
vertex = vertex.transform(trsf2d);
}
}
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcZShapeProfileDef* l, cgal_face_t& face) {
const double x = l->FlangeWidth() * getValue(GV_LENGTH_UNIT);
const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double dx = l->WebThickness() / 2.0f * getValue(GV_LENGTH_UNIT);
const double dy = l->FlangeThickness() * getValue(GV_LENGTH_UNIT);
bool doFillet = l->hasFilletRadius();
bool doEdgeFillet = l->hasEdgeRadius();
double f1 = 0.;
double f2 = 0.;
if ( doFillet ) {
f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
}
if ( doEdgeFillet ) {
f2 = l->EdgeRadius() * getValue(GV_LENGTH_UNIT);
}
if ( x == 0.0f || y == 0.0f || dx == 0.0f || dy == 0.0f ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
cgal_placement_t trsf2d;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
const int segments = 3;
face = cgal_face_t();
face.outer.push_back(Kernel::Point_3(-dx, -y, 0.0));
face.outer.push_back(Kernel::Point_3(x, -y, 0.0));
if (f2 == 0.0) {
face.outer.push_back(Kernel::Point_3(x, -y+dy, 0.0));
} else {
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel::Point_3(x-f2+f2*cos(current_angle), -y+dy-f2+f2*sin(current_angle), 0));
}
} if (f1 == 0.0) {
face.outer.push_back(Kernel::Point_3(dx, -y+dy, 0.0));
} else {
for (int current_segment = segments; current_segment >= 0; --current_segment) {
double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel::Point_3(dx+f1+f1*cos(current_angle), -y+dy+f1+f1*sin(current_angle), 0));
}
} face.outer.push_back(Kernel::Point_3(dx, y, 0.0));
face.outer.push_back(Kernel::Point_3(-x, y, 0.0));
if (f2 == 0.0) {
face.outer.push_back(Kernel::Point_3(-x, y-dy, 0.0));
} else {
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel::Point_3(-x+f2+f2*cos(current_angle), y-dy+f2+f2*sin(current_angle), 0));
}
} if (f1 == 0.0) {
face.outer.push_back(Kernel::Point_3(-dx, y-dy, 0.0));
} else {
for (int current_segment = segments; current_segment >= 0; --current_segment) {
double current_angle = current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel::Point_3(-dx-f1+f1*cos(current_angle), y-dy-f1+f1*sin(current_angle), 0));
}
}
if (has_position) {
IfcGeom::CgalKernel::convert(l->Position(), trsf2d);
for (auto &vertex: face.outer) {
vertex = vertex.transform(trsf2d);
}
}
return true;
}
+86 -15
View File
@@ -111,25 +111,24 @@ IfcGeom::NativeElement<double>* IfcGeom::CgalKernel::create_brep_for_representat
const std::string product_type = IfcSchema::Type::ToString(product->type());
ElementSettings element_settings(settings, getValue(GV_LENGTH_UNIT), product_type);
if (!settings.get(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS) && openings && openings->size()) {
Logger::Message(Logger::LOG_ERROR, "Not implemented opening subtractions");
}
if (settings.get(IteratorSettings::USE_WORLD_COORDS)) {
// TODO: OpenCascade code uses opened_shapes. Check why.
if (!settings.get(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS) && openings && openings->size()) {
IfcGeom::ConversionResults opened_shapes;
convert_openings(product,openings,shapes,trsf,opened_shapes);
if (settings.get(IteratorSettings::USE_WORLD_COORDS)) {
for ( IfcGeom::ConversionResults::iterator it = opened_shapes.begin(); it != opened_shapes.end(); ++ it ) {
it->prepend(new CgalPlacement(trsf));
}
trsf = cgal_placement_t();
}
shape = new IfcGeom::Representation::Native(element_settings, representation->entity->id(), opened_shapes);
} else if (settings.get(IteratorSettings::USE_WORLD_COORDS)) {
for ( IfcGeom::ConversionResults::iterator it = shapes.begin(); it != shapes.end(); ++ it ) {
it->prepend(new CgalPlacement(trsf));
}
trsf = Kernel::Aff_transformation_3();
shape = new IfcGeom::Representation::Native(element_settings, representation->entity->id(), shapes);
} else if (settings.get(IteratorSettings::USE_WORLD_COORDS)) {
for ( IfcGeom::ConversionResults::iterator it = shapes.begin(); it != shapes.end(); ++ it ) {
it->prepend(new CgalPlacement(trsf));
}
trsf = Kernel::Aff_transformation_3();
shape = new IfcGeom::Representation::Native(element_settings, representation->entity->id(), shapes);
trsf = cgal_placement_t();
shape = new IfcGeom::Representation::Native(element_settings, representation->entity->id(), shapes);
} else {
shape = new IfcGeom::Representation::Native(element_settings, representation->entity->id(), shapes);
shape = new IfcGeom::Representation::Native(element_settings, representation->entity->id(), shapes);
}
std::string context_string = "";
@@ -191,3 +190,75 @@ IfcGeom::NativeElement<double>* IfcGeom::CgalKernel::create_brep_for_processed_r
brep->geometry_pointer()
);
}
bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings,
const IfcGeom::ConversionResults& entity_shapes, const cgal_placement_t& entity_trsf, IfcGeom::ConversionResults& cut_shapes) {
std::list<cgal_shape_t> opening_shapelist;
for ( IfcSchema::IfcRelVoidsElement::list::it it = openings->begin(); it != openings->end(); ++ it ) {
IfcSchema::IfcRelVoidsElement* v = *it;
IfcSchema::IfcFeatureElementSubtraction* fes = v->RelatedOpeningElement();
if ( fes->is(IfcSchema::Type::IfcOpeningElement) ) {
if (!fes->hasRepresentation()) continue;
// Convert the IfcRepresentation of the IfcOpeningElement
cgal_placement_t opening_trsf;
if (fes->hasObjectPlacement()) {
try {
convert(fes->ObjectPlacement(),opening_trsf);
} catch (...) {}
}
// Move the opening into the coordinate system of the IfcProduct
opening_trsf = opening_trsf * entity_trsf.inverse();
IfcSchema::IfcProductRepresentation* prodrep = fes->Representation();
IfcSchema::IfcRepresentation::list::ptr reps = prodrep->Representations();
IfcGeom::ConversionResults opening_shapes;
for ( IfcSchema::IfcRepresentation::list::it it2 = reps->begin(); it2 != reps->end(); ++ it2 ) {
convert_shapes(*it2,opening_shapes);
}
for ( unsigned int i = 0; i < opening_shapes.size(); ++ i ) {
cgal_shape_t opening_shape(((CgalShape*)opening_shapes[i].Shape())->shape());
if (opening_shapes[i].Placement()) {
cgal_placement_t gtrsf = *(CgalPlacement*)opening_shapes[i].Placement();
gtrsf = gtrsf * opening_trsf;
opening_shape.transform(gtrsf);
} opening_shapelist.push_back(opening_shape);
}
}
}
// Iterate over the shapes of the IfcProduct
for ( IfcGeom::ConversionResults::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) {
const cgal_shape_t& entity_shape_unlocated(((CgalShape*)it3->Shape())->shape());
cgal_shape_t entity_shape(entity_shape_unlocated);
if (it3->Placement()) {
const cgal_placement_t& entity_shape_gtrsf = *(CgalPlacement*)it3->Placement();
entity_shape.transform(entity_shape_gtrsf);
}
cgal_shape_t brep_cut_result(entity_shape);
for (auto &opening: opening_shapelist) {
brep_cut_result -= opening;
}
if (brep_cut_result.is_valid()) {
cut_shapes.push_back(IfcGeom::ConversionResult(new CgalShape(brep_cut_result), &it3->Style()));
} else {
// Apparently processing the boolean operation failed or resulted in an invalid result
// in which case the original shape without the subtractions is returned instead
// we try convert the openings in the original way, one by one.
Logger::Message(Logger::LOG_WARNING, "Subtracting combined openings compound failed:", entity->entity);
return false;
}
}
return true;
}
+1 -1
View File
@@ -137,7 +137,7 @@ namespace IfcGeom {
void remove_duplicate_points_from_loop(cgal_wire_t& polygon, bool closed, double tol = -1.);
// bool convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const ConversionResults& entity_shapes, const gp_Trsf& entity_trsf, ConversionResults& cut_shapes);
bool convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const ConversionResults& entity_shapes, const cgal_placement_t& entity_trsf, ConversionResults& cut_shapes);
void purge_cache() {
// Rather hack-ish, but a stopgap solution to keep memory under control