- IFC reader regenerated from schema to include IfcArbitraryProfileDefWithVoids

- implemented IfcArbitraryProfileDefWithVoids to fix solar panel covers in test\models-nonbsd\IFC\rac_basic_sample_project.ifc
- warning: another dirty hack on top of dirty hacks - one day all these CSG implementations will blow up in our faces. Mark my words.
pull/533/head
ulf 2015-04-13 16:01:33 +02:00
parent b5e3e18bf0
commit 806d3ac8e1
6 changed files with 17607 additions and 8011 deletions

View File

@ -522,43 +522,23 @@ IfcMatrix3 DerivePlaneCoordinateSpace(const TempMesh& curmesh, bool& ok, IfcVect
return m; return m;
} }
// Extrudes the given polygon along the direction, converts it into an opening or applies all openings as necessary.
// ------------------------------------------------------------------------------------------------ void ProcessExtrudedArea(const IfcExtrudedAreaSolid& solid, const TempMesh& curve,
void ProcessExtrudedAreaSolid(const IfcExtrudedAreaSolid& solid, TempMesh& result, const IfcVector3& extrusionDir, TempMesh& result, ConversionData &conv, bool collect_openings)
ConversionData& conv, bool collect_openings)
{ {
TempMesh meshout; // Outline: 'curve' is now a list of vertex points forming the underlying profile, extrude along the given axis,
// forming new triangles.
// First read the profile description const bool has_area = solid.SweptArea->ProfileType == "AREA" && curve.verts.size() > 2;
if(!ProcessProfile(*solid.SweptArea,meshout,conv) || meshout.verts.size()<=1) { if( solid.Depth < 1e-6 ) {
return; if( has_area ) {
} result.Append(curve);
IfcVector3 dir;
ConvertDirection(dir,solid.ExtrudedDirection);
dir *= solid.Depth; /*
if(conv.collect_openings && !conv.apply_openings) {
dir *= 1000.0;
} */
// Outline: assuming that `meshout.verts` is now a list of vertex points forming
// the underlying profile, extrude along the given axis, forming new
// triangles.
std::vector<IfcVector3>& in = meshout.verts;
const size_t size=in.size();
const bool has_area = solid.SweptArea->ProfileType == "AREA" && size>2;
if(solid.Depth < 1e-6) {
if(has_area) {
result = meshout;
} }
return; return;
} }
result.verts.reserve(size*(has_area?4:2)); result.verts.reserve(curve.verts.size()*(has_area ? 4 : 2));
result.vertcnt.reserve(meshout.vertcnt.size()+2); result.vertcnt.reserve(curve.verts.size() + 2);
std::vector<IfcVector3> in = curve.verts;
// First step: transform all vertices into the target coordinate space // First step: transform all vertices into the target coordinate space
IfcMatrix4 trafo; IfcMatrix4 trafo;
@ -566,7 +546,7 @@ void ProcessExtrudedAreaSolid(const IfcExtrudedAreaSolid& solid, TempMesh& resul
IfcVector3 vmin, vmax; IfcVector3 vmin, vmax;
MinMaxChooser<IfcVector3>()(vmin, vmax); MinMaxChooser<IfcVector3>()(vmin, vmax);
BOOST_FOREACH(IfcVector3& v,in) { BOOST_FOREACH(IfcVector3& v, in) {
v *= trafo; v *= trafo;
vmin = std::min(vmin, v); vmin = std::min(vmin, v);
@ -575,93 +555,91 @@ void ProcessExtrudedAreaSolid(const IfcExtrudedAreaSolid& solid, TempMesh& resul
vmax -= vmin; vmax -= vmin;
const IfcFloat diag = vmax.Length(); const IfcFloat diag = vmax.Length();
IfcVector3 dir = IfcMatrix3(trafo) * extrusionDir;
IfcVector3 min = in[0];
dir *= IfcMatrix3(trafo);
// reverse profile polygon if it's winded in the wrong direction in relation to the extrusion direction // reverse profile polygon if it's winded in the wrong direction in relation to the extrusion direction
IfcVector3 profileNormal = TempMesh::ComputePolygonNormal( in.data(), in.size()); IfcVector3 profileNormal = TempMesh::ComputePolygonNormal(in.data(), in.size());
if( profileNormal * dir < 0.0 ) if( profileNormal * dir < 0.0 )
std::reverse( in.begin(), in.end()); std::reverse(in.begin(), in.end());
std::vector<IfcVector3> nors; std::vector<IfcVector3> nors;
const bool openings = !!conv.apply_openings && conv.apply_openings->size(); const bool openings = !!conv.apply_openings && conv.apply_openings->size();
// Compute the normal vectors for all opening polygons as a prerequisite // Compute the normal vectors for all opening polygons as a prerequisite
// to TryAddOpenings_Poly2Tri() // to TryAddOpenings_Poly2Tri()
// XXX this belongs into the aforementioned function // XXX this belongs into the aforementioned function
if (openings) { if( openings ) {
if (!conv.settings.useCustomTriangulation) { if( !conv.settings.useCustomTriangulation ) {
// it is essential to apply the openings in the correct spatial order. The direction // it is essential to apply the openings in the correct spatial order. The direction
// doesn't matter, but we would screw up if we started with e.g. a door in between // doesn't matter, but we would screw up if we started with e.g. a door in between
// two windows. // two windows.
std::sort(conv.apply_openings->begin(),conv.apply_openings->end(), std::sort(conv.apply_openings->begin(), conv.apply_openings->end(), TempOpening::DistanceSorter(in[0]));
TempOpening::DistanceSorter(min));
} }
nors.reserve(conv.apply_openings->size()); nors.reserve(conv.apply_openings->size());
BOOST_FOREACH(TempOpening& t,*conv.apply_openings) { BOOST_FOREACH(TempOpening& t, *conv.apply_openings) {
TempMesh& bounds = *t.profileMesh.get(); TempMesh& bounds = *t.profileMesh.get();
if (bounds.verts.size() <= 2) { if( bounds.verts.size() <= 2 ) {
nors.push_back(IfcVector3()); nors.push_back(IfcVector3());
continue; continue;
} }
nors.push_back(((bounds.verts[2]-bounds.verts[0])^(bounds.verts[1]-bounds.verts[0]) ).Normalize()); nors.push_back(((bounds.verts[2] - bounds.verts[0]) ^ (bounds.verts[1] - bounds.verts[0])).Normalize());
} }
} }
TempMesh temp; TempMesh temp;
TempMesh& curmesh = openings ? temp : result; TempMesh& curmesh = openings ? temp : result;
std::vector<IfcVector3>& out = curmesh.verts; std::vector<IfcVector3>& out = curmesh.verts;
size_t sides_with_openings = 0; size_t sides_with_openings = 0;
for(size_t i = 0; i < size; ++i) { for( size_t i = 0; i < in.size(); ++i ) {
const size_t next = (i+1)%size; const size_t next = (i + 1) % in.size();
curmesh.vertcnt.push_back(4); curmesh.vertcnt.push_back(4);
out.push_back(in[i]); out.push_back(in[i]);
out.push_back(in[next]); out.push_back(in[next]);
out.push_back(in[next]+dir); out.push_back(in[next] + dir);
out.push_back(in[i]+dir); out.push_back(in[i] + dir);
if(openings) { if( openings ) {
if((in[i]-in[next]).Length() > diag * 0.1 && GenerateOpenings(*conv.apply_openings,nors,temp,true, true, dir)) { if( (in[i] - in[next]).Length() > diag * 0.1 && GenerateOpenings(*conv.apply_openings, nors, temp, true, true, dir) ) {
++sides_with_openings; ++sides_with_openings;
} }
result.Append(temp); result.Append(temp);
temp.Clear(); temp.Clear();
} }
} }
if(openings) { if( openings ) {
BOOST_FOREACH(TempOpening& opening, *conv.apply_openings) { BOOST_FOREACH(TempOpening& opening, *conv.apply_openings) {
if (!opening.wallPoints.empty()) { if( !opening.wallPoints.empty() ) {
IFCImporter::LogError("failed to generate all window caps"); IFCImporter::LogError("failed to generate all window caps");
} }
opening.wallPoints.clear(); opening.wallPoints.clear();
} }
} }
size_t sides_with_v_openings = 0;
if(has_area) {
for(size_t n = 0; n < 2; ++n) { size_t sides_with_v_openings = 0;
if( has_area ) {
for( size_t n = 0; n < 2; ++n ) {
if( n > 0 ) { if( n > 0 ) {
for(size_t i = 0; i < size; ++i ) for( size_t i = 0; i < in.size(); ++i )
out.push_back(in[i]+dir); out.push_back(in[i] + dir);
} else { }
for(size_t i = size; i--; ) else {
for( size_t i = in.size(); i--; )
out.push_back(in[i]); out.push_back(in[i]);
} }
curmesh.vertcnt.push_back(size); curmesh.vertcnt.push_back(in.size());
if(openings && size > 2) { if( openings && in.size() > 2 ) {
if(GenerateOpenings(*conv.apply_openings,nors,temp,true, true, dir)) { if( GenerateOpenings(*conv.apply_openings, nors, temp, true, true, dir) ) {
++sides_with_v_openings; ++sides_with_v_openings;
} }
@ -671,7 +649,7 @@ void ProcessExtrudedAreaSolid(const IfcExtrudedAreaSolid& solid, TempMesh& resul
} }
} }
if(openings && ((sides_with_openings == 1 && sides_with_openings) || (sides_with_v_openings == 2 && sides_with_v_openings))) { if( openings && ((sides_with_openings == 1 && sides_with_openings) || (sides_with_v_openings == 2 && sides_with_v_openings)) ) {
IFCImporter::LogWarn("failed to resolve all openings, presumably their topology is not supported by Assimp"); IFCImporter::LogWarn("failed to resolve all openings, presumably their topology is not supported by Assimp");
} }
@ -679,17 +657,58 @@ void ProcessExtrudedAreaSolid(const IfcExtrudedAreaSolid& solid, TempMesh& resul
// If this is an opening element, store both the extruded mesh and the 2D profile mesh // If this is an opening element, store both the extruded mesh and the 2D profile mesh
// it was created from. Return an empty mesh to the caller. // it was created from. Return an empty mesh to the caller.
if(collect_openings && !result.IsEmpty()) { if( collect_openings && !result.IsEmpty() ) {
ai_assert(conv.collect_openings); ai_assert(conv.collect_openings);
boost::shared_ptr<TempMesh> profile = boost::shared_ptr<TempMesh>(new TempMesh()); boost::shared_ptr<TempMesh> profile = boost::shared_ptr<TempMesh>(new TempMesh());
profile->Swap(result); profile->Swap(result);
boost::shared_ptr<TempMesh> profile2D = boost::shared_ptr<TempMesh>(new TempMesh()); boost::shared_ptr<TempMesh> profile2D = boost::shared_ptr<TempMesh>(new TempMesh());
profile2D->Swap(meshout); profile2D->verts.insert(profile2D->verts.end(), in.begin(), in.end());
conv.collect_openings->push_back(TempOpening(&solid,dir,profile, profile2D)); profile2D->vertcnt.push_back(in.size());
conv.collect_openings->push_back(TempOpening(&solid, dir, profile, profile2D));
ai_assert(result.IsEmpty()); ai_assert(result.IsEmpty());
} }
}
// ------------------------------------------------------------------------------------------------
void ProcessExtrudedAreaSolid(const IfcExtrudedAreaSolid& solid, TempMesh& result,
ConversionData& conv, bool collect_openings)
{
TempMesh meshout;
// First read the profile description.
if(!ProcessProfile(*solid.SweptArea,meshout,conv) || meshout.verts.size()<=1) {
return;
}
IfcVector3 dir;
ConvertDirection(dir,solid.ExtrudedDirection);
dir *= solid.Depth;
// Some profiles bring their own holes, for which we need to provide a container. This all is somewhat backwards,
// and there's still so many corner cases uncovered - we really need a generic solution to all of this hole carving.
std::vector<TempOpening> fisherPriceMyFirstOpenings;
std::vector<TempOpening>* oldApplyOpenings = conv.apply_openings;
if( const IfcArbitraryProfileDefWithVoids* const cprofile = solid.SweptArea->ToPtr<IfcArbitraryProfileDefWithVoids>() ) {
if( !cprofile->InnerCurves.empty() ) {
// read all inner curves and extrude them to form proper openings.
std::vector<TempOpening>* oldCollectOpenings = conv.collect_openings;
conv.collect_openings = &fisherPriceMyFirstOpenings;
BOOST_FOREACH(const IfcCurve* curve, cprofile->InnerCurves) {
TempMesh curveMesh, tempMesh;
ProcessCurve(*curve, curveMesh, conv);
ProcessExtrudedArea(solid, curveMesh, dir, tempMesh, conv, true);
}
// and then apply those to the geometry we're about to generate
conv.apply_openings = conv.collect_openings;
conv.collect_openings = oldCollectOpenings;
}
}
ProcessExtrudedArea(solid, meshout, dir, result, conv, collect_openings);
conv.apply_openings = oldApplyOpenings;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -784,7 +803,7 @@ bool ProcessGeometricItem(const IfcRepresentationItem& geo, unsigned int matid,
meshtmp->RemoveDegenerates(); meshtmp->RemoveDegenerates();
if(fix_orientation) { if(fix_orientation) {
meshtmp->FixupFaceOrientation(); // meshtmp->FixupFaceOrientation();
} }
aiMesh* const mesh = meshtmp->ToMesh(); aiMesh* const mesh = meshtmp->ToMesh();

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -271,6 +271,7 @@ IfcFloat ConvertSIPrefix(const std::string& prefix);
// IFCProfile.cpp // IFCProfile.cpp
bool ProcessProfile(const IfcProfileDef& prof, TempMesh& meshout, ConversionData& conv); bool ProcessProfile(const IfcProfileDef& prof, TempMesh& meshout, ConversionData& conv);
bool ProcessCurve(const IfcCurve& curve, TempMesh& meshout, ConversionData& conv);
// IFCMaterial.cpp // IFCMaterial.cpp
unsigned int ProcessMaterials(uint64_t id, unsigned int prevMatId, ConversionData& conv, bool forceDefaultMat); unsigned int ProcessMaterials(uint64_t id, unsigned int prevMatId, ConversionData& conv, bool forceDefaultMat);

View File

@ -1,16 +1,17 @@
# ============================================================================== # ==============================================================================
# List of IFC structures needed by Assimp # List of IFC structures needed by Assimp
# ============================================================================== # ==============================================================================
# use genentitylist.sh to update this list # use genentitylist.sh to update this list
# This machine-generated list is not complete, it lacks many intermediate # This machine-generated list is not complete, it lacks many intermediate
# classes in the inheritance hierarchy. Those are magically augmented by the # classes in the inheritance hierarchy. Those are magically augmented by the
# 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.
IfcAnnotation IfcAnnotation
IfcArbitraryClosedProfileDef IfcArbitraryClosedProfileDef
IfcArbitraryOpenProfileDef IfcArbitraryOpenProfileDef
IfcArbitraryProfileDefWithVoids
IfcAxis1Placement IfcAxis1Placement
IfcAxis2Placement IfcAxis2Placement
IfcAxis2Placement2D IfcAxis2Placement2D

File diff suppressed because it is too large Load Diff