- IFC: initial implementation of boolean clipping (simple kind of CSG). Currently only supports clipping against unbounded planes.
git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@999 67173fc5-114c-0410-ac8e-9d2fd5bffc1fpull/1/head
parent
f64f0446db
commit
ee64441305
|
@ -1097,16 +1097,116 @@ void ProcessSweptAreaSolid(const IFC::IfcSweptAreaSolid& swept, TempMesh& meshou
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ProcessBoolean(const IFC::IfcBooleanResult& boolean, TempMesh& meshout, ConversionData& conv)
|
enum Intersect {
|
||||||
|
Intersect_No,
|
||||||
|
Intersect_LiesOnPlane,
|
||||||
|
Intersect_Yes
|
||||||
|
};
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
Intersect IntersectSegmentPlane(const aiVector3D& p,const aiVector3D& n, const aiVector3D& e0, const aiVector3D& e1, aiVector3D& out)
|
||||||
|
{
|
||||||
|
const aiVector3D pdelta = e0 - p, seg = e1-e0;
|
||||||
|
const float dotOne = n*seg, dotTwo = -(n*pdelta);
|
||||||
|
|
||||||
|
if (fabs(dotOne) < 1e-6) {
|
||||||
|
return fabs(dotTwo) < 1e-6f ? Intersect_LiesOnPlane : Intersect_No;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float t = dotTwo/dotOne;
|
||||||
|
// t must be in [0..1] if the intersection point is within the given segment
|
||||||
|
if (t > 1.f || t < 0.f) {
|
||||||
|
return Intersect_No;
|
||||||
|
}
|
||||||
|
out = e0+t*seg;
|
||||||
|
return Intersect_Yes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
void ProcessBoolean(const IFC::IfcBooleanResult& boolean, TempMesh& result, ConversionData& conv)
|
||||||
{
|
{
|
||||||
if(const IFC::IfcBooleanClippingResult* const clip = boolean.ToPtr<IFC::IfcBooleanClippingResult>()) {
|
if(const IFC::IfcBooleanClippingResult* const clip = boolean.ToPtr<IFC::IfcBooleanClippingResult>()) {
|
||||||
|
if(clip->Operator != "DIFFERENCE") {
|
||||||
|
IFCImporter::LogWarn("encountered unsupported boolean operator: " + (std::string)clip->Operator);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TempMesh meshout;
|
||||||
|
const IFC::IfcHalfSpaceSolid* const hs = clip->SecondOperand->ResolveSelectPtr<IFC::IfcHalfSpaceSolid>(conv.db);
|
||||||
|
if(!hs) {
|
||||||
|
IFCImporter::LogError("expected IfcHalfSpaceSolid as second clipping operand");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const IFC::IfcPlane* const plane = hs->BaseSurface->ToPtr<IFC::IfcPlane>();
|
||||||
|
if(!plane) {
|
||||||
|
IFCImporter::LogError("expected IfcPlane as base surface for the IfcHalfSpaceSolid");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(const IFC::IfcBooleanResult* const op0 = clip->FirstOperand->ResolveSelectPtr<IFC::IfcBooleanResult>(conv.db)) {
|
if(const IFC::IfcBooleanResult* const op0 = clip->FirstOperand->ResolveSelectPtr<IFC::IfcBooleanResult>(conv.db)) {
|
||||||
ProcessBoolean(*op0,meshout,conv);
|
ProcessBoolean(*op0,meshout,conv);
|
||||||
}
|
}
|
||||||
else if (const IFC::IfcSweptAreaSolid* const swept = clip->FirstOperand->ResolveSelectPtr<IFC::IfcSweptAreaSolid>(conv.db)) {
|
else if (const IFC::IfcSweptAreaSolid* const swept = clip->FirstOperand->ResolveSelectPtr<IFC::IfcSweptAreaSolid>(conv.db)) {
|
||||||
ProcessSweptAreaSolid(*swept,meshout,conv);
|
ProcessSweptAreaSolid(*swept,meshout,conv);
|
||||||
// XXX
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
IFCImporter::LogError("expected IfcSweptAreaSolid or IfcBooleanResult as first clipping operand");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract plane base position vector and normal vector
|
||||||
|
aiVector3D p,n(0.f,0.f,1.f);
|
||||||
|
if (plane->Position->Axis) {
|
||||||
|
ConvertDirection(n,plane->Position->Axis.Get());
|
||||||
|
}
|
||||||
|
ConvertCartesianPoint(p,plane->Position->Location);
|
||||||
|
|
||||||
|
if(!IsTrue(hs->AgreementFlag)) {
|
||||||
|
n *= -1.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clip the current contents of `meshout` against the plane we obtained from the second operand
|
||||||
|
const std::vector<aiVector3D>& in = meshout.verts;
|
||||||
|
std::vector<aiVector3D>& outvert = result.verts;
|
||||||
|
std::vector<unsigned int>::const_iterator outer_polygon = meshout.vertcnt.end(), begin=meshout.vertcnt.begin(), iit;
|
||||||
|
|
||||||
|
unsigned int vidx = 0;
|
||||||
|
for(iit = begin; iit != meshout.vertcnt.end(); vidx += *iit++) {
|
||||||
|
|
||||||
|
unsigned int newcount = 0;
|
||||||
|
for(unsigned int i = 0; i < *iit; ++i) {
|
||||||
|
const aiVector3D& e0 = in[vidx+i], e1 = in[vidx+(i+1)%*iit];
|
||||||
|
|
||||||
|
// does the next segment intersect the plane?
|
||||||
|
aiVector3D isectpos;
|
||||||
|
const Intersect isect = IntersectSegmentPlane(p,n,e0,e1,isectpos);
|
||||||
|
if (isect == Intersect_No || isect == Intersect_LiesOnPlane) {
|
||||||
|
if ( (e0-p).Normalize()*n > 0 ) {
|
||||||
|
outvert.push_back(e0);
|
||||||
|
++newcount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (isect == Intersect_Yes) {
|
||||||
|
if ( (e0-p).Normalize()*n > 0 ) {
|
||||||
|
// e0 is on the right side, so keep it
|
||||||
|
outvert.push_back(e0);
|
||||||
|
outvert.push_back(isectpos);
|
||||||
|
newcount += 2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// e0 is on the wrong side, so drop it and keep e1 instead
|
||||||
|
outvert.push_back(isectpos);
|
||||||
|
++newcount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(newcount) {
|
||||||
|
result.vertcnt.push_back(newcount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IFCImporter::LogDebug("generating CSG geometry by plane clipping (IfcBooleanClippingResult)");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
IFCImporter::LogWarn("skipping unknown IfcBooleanResult entity, type is " + boolean.GetClassName());
|
IFCImporter::LogWarn("skipping unknown IfcBooleanResult entity, type is " + boolean.GetClassName());
|
||||||
|
|
|
@ -1278,8 +1278,7 @@ template <> size_t GenericFill<IfcRectangularPyramid>(const DB& db, const LIST&
|
||||||
template <> size_t GenericFill<IfcSurface>(const DB& db, const LIST& params, IfcSurface* in)
|
template <> size_t GenericFill<IfcSurface>(const DB& db, const LIST& params, IfcSurface* in)
|
||||||
{
|
{
|
||||||
size_t base = GenericFill(db,params,static_cast<IfcGeometricRepresentationItem*>(in));
|
size_t base = GenericFill(db,params,static_cast<IfcGeometricRepresentationItem*>(in));
|
||||||
// this data structure is not used yet, so there is no code generated to fill its members
|
if (params.GetSize() < 0) { throw STEP::TypeError("expected 0 arguments to IfcSurface"); } return base;
|
||||||
return base;
|
|
||||||
}
|
}
|
||||||
// -----------------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------------
|
||||||
template <> size_t GenericFill<IfcBoundedSurface>(const DB& db, const LIST& params, IfcBoundedSurface* in)
|
template <> size_t GenericFill<IfcBoundedSurface>(const DB& db, const LIST& params, IfcBoundedSurface* in)
|
||||||
|
@ -1312,7 +1311,18 @@ template <> size_t GenericFill<IfcRelationship>(const DB& db, const LIST& params
|
||||||
template <> size_t GenericFill<IfcHalfSpaceSolid>(const DB& db, const LIST& params, IfcHalfSpaceSolid* in)
|
template <> size_t GenericFill<IfcHalfSpaceSolid>(const DB& db, const LIST& params, IfcHalfSpaceSolid* in)
|
||||||
{
|
{
|
||||||
size_t base = GenericFill(db,params,static_cast<IfcGeometricRepresentationItem*>(in));
|
size_t base = GenericFill(db,params,static_cast<IfcGeometricRepresentationItem*>(in));
|
||||||
// this data structure is not used yet, so there is no code generated to fill its members
|
if (params.GetSize() < 2) { throw STEP::TypeError("expected 2 arguments to IfcHalfSpaceSolid"); } do { // convert the 'BaseSurface' argument
|
||||||
|
const DataType* arg = params[base++];
|
||||||
|
if (dynamic_cast<const ISDERIVED*>(&*arg)) { in->ObjectHelper<Assimp::IFC::IfcHalfSpaceSolid,2>::aux_is_derived[0]=true; break; }
|
||||||
|
try { GenericConvert( in->BaseSurface, *arg, db ); break; }
|
||||||
|
catch (const TypeError& t) { throw TypeError(t.what() + std::string(" - expected argument 0 to IfcHalfSpaceSolid to be a `IfcSurface`")); }
|
||||||
|
} while(0);
|
||||||
|
do { // convert the 'AgreementFlag' argument
|
||||||
|
const DataType* arg = params[base++];
|
||||||
|
if (dynamic_cast<const ISDERIVED*>(&*arg)) { in->ObjectHelper<Assimp::IFC::IfcHalfSpaceSolid,2>::aux_is_derived[1]=true; break; }
|
||||||
|
try { GenericConvert( in->AgreementFlag, *arg, db ); break; }
|
||||||
|
catch (const TypeError& t) { throw TypeError(t.what() + std::string(" - expected argument 1 to IfcHalfSpaceSolid to be a `BOOLEAN`")); }
|
||||||
|
} while(0);
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
// -----------------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------------
|
||||||
|
@ -1557,15 +1567,19 @@ template <> size_t GenericFill<IfcCircle>(const DB& db, const LIST& params, IfcC
|
||||||
template <> size_t GenericFill<IfcElementarySurface>(const DB& db, const LIST& params, IfcElementarySurface* in)
|
template <> size_t GenericFill<IfcElementarySurface>(const DB& db, const LIST& params, IfcElementarySurface* in)
|
||||||
{
|
{
|
||||||
size_t base = GenericFill(db,params,static_cast<IfcSurface*>(in));
|
size_t base = GenericFill(db,params,static_cast<IfcSurface*>(in));
|
||||||
// this data structure is not used yet, so there is no code generated to fill its members
|
if (params.GetSize() < 1) { throw STEP::TypeError("expected 1 arguments to IfcElementarySurface"); } do { // convert the 'Position' argument
|
||||||
|
const DataType* arg = params[base++];
|
||||||
|
if (dynamic_cast<const ISDERIVED*>(&*arg)) { in->ObjectHelper<Assimp::IFC::IfcElementarySurface,1>::aux_is_derived[0]=true; break; }
|
||||||
|
try { GenericConvert( in->Position, *arg, db ); break; }
|
||||||
|
catch (const TypeError& t) { throw TypeError(t.what() + std::string(" - expected argument 0 to IfcElementarySurface to be a `IfcAxis2Placement3D`")); }
|
||||||
|
} while(0);
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
// -----------------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------------
|
||||||
template <> size_t GenericFill<IfcPlane>(const DB& db, const LIST& params, IfcPlane* in)
|
template <> size_t GenericFill<IfcPlane>(const DB& db, const LIST& params, IfcPlane* in)
|
||||||
{
|
{
|
||||||
size_t base = GenericFill(db,params,static_cast<IfcElementarySurface*>(in));
|
size_t base = GenericFill(db,params,static_cast<IfcElementarySurface*>(in));
|
||||||
// this data structure is not used yet, so there is no code generated to fill its members
|
if (params.GetSize() < 1) { throw STEP::TypeError("expected 1 arguments to IfcPlane"); } return base;
|
||||||
return base;
|
|
||||||
}
|
}
|
||||||
// -----------------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------------
|
||||||
template <> size_t GenericFill<IfcCostSchedule>(const DB& db, const LIST& params, IfcCostSchedule* in)
|
template <> size_t GenericFill<IfcCostSchedule>(const DB& db, const LIST& params, IfcCostSchedule* in)
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
# code generator. Also, the names of all used entities need to be present
|
# code generator. Also, the names of all used entities need to be present
|
||||||
# in the source code for this to work.
|
# in the source code for this to work.
|
||||||
|
|
||||||
|
IfcPlane
|
||||||
|
IfcHalfSpaceSolid
|
||||||
IfcAxis1Placement
|
IfcAxis1Placement
|
||||||
IfcMeasureWithUnit
|
IfcMeasureWithUnit
|
||||||
IfcConversionBasedUnit
|
IfcConversionBasedUnit
|
||||||
|
|
Loading…
Reference in New Issue