- IFC: slight optimization, take less memory.
# IFC: try to make normals point outwards, if possible. # IFC: implement recursive polygon merging, but leave it disabled since it seems to fail on very complicated polygons with multiple, nested boundaries. git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@1007 67173fc5-114c-0410-ac8e-9d2fd5bffc1fpull/1/head
parent
f522143909
commit
78b44c3aed
|
@ -333,8 +333,13 @@ void IFCImporter::InternReadFile( const std::string& pFile,
|
||||||
EXPRESS::ConversionSchema schema;
|
EXPRESS::ConversionSchema schema;
|
||||||
IFC::GetSchema(schema);
|
IFC::GetSchema(schema);
|
||||||
|
|
||||||
|
// tell the reader which entity types to track with special care
|
||||||
|
static const char* const types_to_track[] = {
|
||||||
|
"ifcsite", "ifcbuilding", "ifcproject"
|
||||||
|
};
|
||||||
|
|
||||||
// feed the IFC schema into the reader and pre-parse all lines
|
// feed the IFC schema into the reader and pre-parse all lines
|
||||||
STEP::ReadFile(*db, schema);
|
STEP::ReadFile(*db, schema, types_to_track);
|
||||||
|
|
||||||
const STEP::LazyObject* proj = db->GetObject("ifcproject");
|
const STEP::LazyObject* proj = db->GetObject("ifcproject");
|
||||||
if (!proj) {
|
if (!proj) {
|
||||||
|
@ -731,6 +736,116 @@ bool ProcessPolyloop(const IFC::IfcPolyLoop& loop, TempMesh& meshout, Conversion
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
void FixupFaceOrientation(TempMesh& result)
|
||||||
|
{
|
||||||
|
aiVector3D vavg;
|
||||||
|
BOOST_FOREACH(aiVector3D& v, result.verts) {
|
||||||
|
vavg += v;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fix face orientation - try at least.
|
||||||
|
vavg /= static_cast<float>( result.verts.size() );
|
||||||
|
|
||||||
|
size_t c = 0;
|
||||||
|
BOOST_FOREACH(unsigned int cnt, result.vertcnt) {
|
||||||
|
if (cnt>2){
|
||||||
|
const aiVector3D& thisvert = result.verts[c];
|
||||||
|
const aiVector3D normal((thisvert-result.verts[c+1])^(thisvert-result.verts[c+2]));
|
||||||
|
if (normal*(thisvert-vavg) < 0) {
|
||||||
|
std::reverse(result.verts.begin()+c,result.verts.begin()+cnt+c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c += cnt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
void RecursiveMergeBoundaries(TempMesh& final_result, const TempMesh& in, const TempMesh& boundary, std::vector<aiVector3D>& normals, const aiVector3D& nor_boundary)
|
||||||
|
{
|
||||||
|
ai_assert(in.vertcnt.size() >= 1);
|
||||||
|
ai_assert(boundary.vertcnt.size() == 1);
|
||||||
|
std::vector<unsigned int>::const_iterator end = in.vertcnt.end(), begin=in.vertcnt.begin(), iit, best_iit;
|
||||||
|
|
||||||
|
TempMesh out;
|
||||||
|
|
||||||
|
// iterate through all other bounds and find the one for which the shortest connection
|
||||||
|
// to the outer boundary is actually the shortest possible.
|
||||||
|
size_t vidx = 0, best_vidx_start = 0;
|
||||||
|
size_t best_ofs, best_outer = boundary.verts.size();
|
||||||
|
float best_dist = 1e10;
|
||||||
|
for(std::vector<unsigned int>::const_iterator iit = begin; iit != end; vidx += *iit++) {
|
||||||
|
|
||||||
|
for(size_t vofs = 0; vofs < *iit; ++vofs) {
|
||||||
|
const aiVector3D& v = in.verts[vidx+vofs];
|
||||||
|
|
||||||
|
for(size_t outer = 0; outer < boundary.verts.size(); ++outer) {
|
||||||
|
const aiVector3D& o = boundary.verts[outer];
|
||||||
|
const float d = (o-v).SquareLength();
|
||||||
|
|
||||||
|
if (d < best_dist) {
|
||||||
|
best_dist = d;
|
||||||
|
best_ofs = vofs;
|
||||||
|
best_outer = outer;
|
||||||
|
best_iit = iit;
|
||||||
|
best_vidx_start = vidx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ai_assert(best_outer != boundary.verts.size());
|
||||||
|
|
||||||
|
// now that we collected all vertex connections to be added, build the output polygon
|
||||||
|
size_t cnt = boundary.verts.size();
|
||||||
|
for(size_t outer = 0; outer < boundary.verts.size(); ++outer) {
|
||||||
|
const aiVector3D& o = boundary.verts[outer];
|
||||||
|
out.verts.push_back(o);
|
||||||
|
|
||||||
|
if (outer == best_outer) {
|
||||||
|
for(size_t i = best_ofs; i < *best_iit; ++i) {
|
||||||
|
out.verts.push_back(in.verts[best_vidx_start + i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// we need the first vertex of the inner polygon twice as we return to the
|
||||||
|
// outer loop through the very same connection through which we got there.
|
||||||
|
for(size_t i = 0; i <= best_ofs; ++i) {
|
||||||
|
out.verts.push_back(in.verts[best_vidx_start + i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// reverse face winding if the normal of the sub-polygon points in the
|
||||||
|
// same direction as the normal of the outer polygonal boundary
|
||||||
|
if (normals[std::distance(begin,best_iit)] * nor_boundary > 0) {
|
||||||
|
std::reverse(out.verts.rbegin(),out.verts.rbegin()+*best_iit+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// also append a copy of the initial insertion point to be able to continue the outer polygon
|
||||||
|
out.verts.push_back(o);
|
||||||
|
cnt += *best_iit+2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.vertcnt.push_back(cnt);
|
||||||
|
|
||||||
|
if (in.vertcnt.size() > 1) {
|
||||||
|
// Recursively apply the same algorithm if there are more boundaries to merge. The
|
||||||
|
// current implementation is relatively inefficient, though.
|
||||||
|
|
||||||
|
TempMesh temp;
|
||||||
|
|
||||||
|
// drop the boundary that we just processed
|
||||||
|
const size_t dist = std::distance(begin, best_iit);
|
||||||
|
TempMesh remaining = in;
|
||||||
|
remaining.vertcnt.erase(remaining.vertcnt.begin() + dist);
|
||||||
|
remaining.verts.erase(remaining.verts.begin()+best_ofs,remaining.verts.begin()+best_ofs+*best_iit);
|
||||||
|
|
||||||
|
normals.erase(normals.begin() + dist);
|
||||||
|
RecursiveMergeBoundaries(temp,remaining,out,normals,nor_boundary);
|
||||||
|
|
||||||
|
final_result.Append(temp);
|
||||||
|
}
|
||||||
|
else final_result.Append(out);
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Note: meshout may be modified even though the merged polygon is copied to `result`!
|
// Note: meshout may be modified even though the merged polygon is copied to `result`!
|
||||||
void MergePolygonBoundaries(TempMesh& result, TempMesh& meshout, size_t master_bounds = -1)
|
void MergePolygonBoundaries(TempMesh& result, TempMesh& meshout, size_t master_bounds = -1)
|
||||||
|
@ -754,7 +869,6 @@ void MergePolygonBoundaries(TempMesh& result, TempMesh& meshout, size_t master_b
|
||||||
result.verts.reserve(meshout.verts.size()+meshout.vertcnt.size()*2+result.verts.size());
|
result.verts.reserve(meshout.verts.size()+meshout.vertcnt.size()*2+result.verts.size());
|
||||||
size_t outer_polygon_start = 0;
|
size_t outer_polygon_start = 0;
|
||||||
|
|
||||||
|
|
||||||
// compute proper normals for all polygons
|
// compute proper normals for all polygons
|
||||||
size_t max_vcount = 0;
|
size_t max_vcount = 0;
|
||||||
std::vector<unsigned int>::iterator outer_polygon = meshout.vertcnt.end(), begin=meshout.vertcnt.begin(), end=outer_polygon, iit;
|
std::vector<unsigned int>::iterator outer_polygon = meshout.vertcnt.end(), begin=meshout.vertcnt.begin(), end=outer_polygon, iit;
|
||||||
|
@ -767,6 +881,8 @@ void MergePolygonBoundaries(TempMesh& result, TempMesh& meshout, size_t master_b
|
||||||
std::vector<aiVector3D> normals;
|
std::vector<aiVector3D> normals;
|
||||||
normals.reserve( meshout.vertcnt.size() );
|
normals.reserve( meshout.vertcnt.size() );
|
||||||
|
|
||||||
|
// `NewellNormal()` currently has a relatively strange interface and need to
|
||||||
|
// re-structure things a bit to meet them.
|
||||||
size_t vidx = 0;
|
size_t vidx = 0;
|
||||||
for(iit = begin; iit != meshout.vertcnt.end(); vidx += *iit++) {
|
for(iit = begin; iit != meshout.vertcnt.end(); vidx += *iit++) {
|
||||||
for(size_t vofs = 0, cnt = 0; vofs < *iit; ++vofs) {
|
for(size_t vofs = 0, cnt = 0; vofs < *iit; ++vofs) {
|
||||||
|
@ -784,7 +900,7 @@ void MergePolygonBoundaries(TempMesh& result, TempMesh& meshout, size_t master_b
|
||||||
NewellNormal<4,4,4>(normals.back(),*iit,&temp[0],&temp[1],&temp[2]);
|
NewellNormal<4,4,4>(normals.back(),*iit,&temp[0],&temp[1],&temp[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// see if one of the polygons is a IfcFaceOuterBound - treats this as the outer boundary.
|
// see if one of the polygons is a IfcFaceOuterBound (in which case master_bounds is not `-1`).
|
||||||
// sadly we can't rely on it, the docs say 'At most one of the bounds shall be of the type IfcFaceOuterBound'
|
// sadly we can't rely on it, the docs say 'At most one of the bounds shall be of the type IfcFaceOuterBound'
|
||||||
if (master_bounds != -1) {
|
if (master_bounds != -1) {
|
||||||
outer_polygon = begin + master_bounds;
|
outer_polygon = begin + master_bounds;
|
||||||
|
@ -844,10 +960,7 @@ next_loop:
|
||||||
const size_t start = (v-o).SquareLength() > (vnext-o).SquareLength() ? vofs : next;
|
const size_t start = (v-o).SquareLength() > (vnext-o).SquareLength() ? vofs : next;
|
||||||
std::vector<aiVector3D>::iterator inbase = in.begin()+vidx, it = std::copy(inbase+start, inbase+*iit,tmp.begin());
|
std::vector<aiVector3D>::iterator inbase = in.begin()+vidx, it = std::copy(inbase+start, inbase+*iit,tmp.begin());
|
||||||
std::copy(inbase, inbase+start,it);
|
std::copy(inbase, inbase+start,it);
|
||||||
|
|
||||||
//if(start == next) {
|
|
||||||
std::reverse(tmp.begin(),tmp.end());
|
std::reverse(tmp.begin(),tmp.end());
|
||||||
//}
|
|
||||||
|
|
||||||
in.insert(in.begin()+outer_polygon_start+(outer+1)%*outer_polygon,tmp.begin(),tmp.end());
|
in.insert(in.begin()+outer_polygon_start+(outer+1)%*outer_polygon,tmp.begin(),tmp.end());
|
||||||
vidx += outer_polygon_start<vidx ? *iit : 0;
|
vidx += outer_polygon_start<vidx ? *iit : 0;
|
||||||
|
@ -865,86 +978,36 @@ next_loop:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef boost::tuple<std::vector<unsigned int>::iterator, unsigned int, unsigned int> InsertionPoint;
|
// extract the outer boundary and move it to a separate mesh
|
||||||
std::vector< std::vector<InsertionPoint> > insertions(*outer_polygon, std::vector<InsertionPoint>());
|
TempMesh boundary;
|
||||||
|
boundary.vertcnt.resize(1,*outer_polygon);
|
||||||
|
boundary.verts.resize(*outer_polygon);
|
||||||
|
|
||||||
// iterate through all other polyloops and find points in the outer polyloop that are close
|
std::vector<aiVector3D>::iterator b = in.begin()+outer_polygon_start;
|
||||||
vidx = 0;
|
std::copy(b,b+*outer_polygon,boundary.verts.begin());
|
||||||
for(iit = begin; iit != end; vidx += *iit++) {
|
in.erase(b,b+*outer_polygon);
|
||||||
if (iit == outer_polygon || !*iit) {
|
|
||||||
continue;
|
std::vector<aiVector3D>::iterator norit = normals.begin()+std::distance(meshout.vertcnt.begin(),outer_polygon);
|
||||||
|
const aiVector3D nor_boundary = *norit;
|
||||||
|
normals.erase(norit);
|
||||||
|
meshout.vertcnt.erase(outer_polygon);
|
||||||
|
|
||||||
|
// keep merging the closest inner boundary with the outer boundary until no more boundaries are left
|
||||||
|
RecursiveMergeBoundaries(result,meshout,boundary,normals,nor_boundary);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t best_ofs,best_outer = *outer_polygon;
|
|
||||||
float best_dist = 1e10;
|
|
||||||
for(size_t vofs = 0; vofs < *iit; ++vofs) {
|
|
||||||
const aiVector3D& v = in[vidx+vofs];
|
|
||||||
|
|
||||||
for(size_t outer = 0; outer < *outer_polygon; ++outer) {
|
|
||||||
const aiVector3D& o = in[outer_polygon_start+outer];
|
|
||||||
const float d = (o-v).SquareLength();
|
|
||||||
|
|
||||||
if (d < best_dist) {
|
|
||||||
best_dist = d;
|
|
||||||
best_ofs = vofs;
|
|
||||||
best_outer = outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ai_assert(best_outer != *outer_polygon);
|
|
||||||
|
|
||||||
// we will later insert a hidden connection line right after the closest point in the outer polygon
|
|
||||||
insertions[best_outer].push_back(boost::make_tuple(iit,vidx,best_ofs));
|
|
||||||
}
|
|
||||||
|
|
||||||
// now that we collected all vertex connections to be added, build the output polygon
|
|
||||||
size_t cnt = *outer_polygon;
|
|
||||||
for(size_t outer = 0; outer < *outer_polygon; ++outer) {
|
|
||||||
const aiVector3D& o = meshout.verts[outer_polygon_start+outer];
|
|
||||||
result.verts.push_back(o);
|
|
||||||
|
|
||||||
const std::vector<InsertionPoint>& insvec = insertions[outer];
|
|
||||||
BOOST_FOREACH(const InsertionPoint& ins,insvec) {
|
|
||||||
if (!*ins.get<0>()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(size_t i = ins.get<2>(); i < *ins.get<0>(); ++i) {
|
|
||||||
result.verts.push_back(in[ins.get<1>() + i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// we need the first vertex of the inner polygon twice as we return to the
|
|
||||||
// outer loop through the very same connection through which we got there.
|
|
||||||
for(size_t i = 0; i <= ins.get<2>(); ++i) {
|
|
||||||
result.verts.push_back(in[ins.get<1>() + i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// reverse face winding if the normal of the sub-polygon points in the
|
|
||||||
// same direction as the normal of the outer polygonal boundary
|
|
||||||
if (normals[std::distance(begin,ins.get<0>())] * normals[std::distance(begin,outer_polygon)] > 0) {
|
|
||||||
std::reverse(result.verts.rbegin(),result.verts.rbegin()+*ins.get<0>()+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// also append a copy of the initial insertion point to be able to continue the outer polygon
|
|
||||||
result.verts.push_back(o);
|
|
||||||
cnt += *ins.get<0>()+2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result.vertcnt.push_back(cnt);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ProcessConnectedFaceSet(const IFC::IfcConnectedFaceSet& fset, TempMesh& result, ConversionData& conv)
|
void ProcessConnectedFaceSet(const IFC::IfcConnectedFaceSet& fset, TempMesh& result, ConversionData& conv)
|
||||||
{
|
{
|
||||||
BOOST_FOREACH(const IFC::IfcFace& face, fset.CfsFaces) {
|
BOOST_FOREACH(const IFC::IfcFace& face, fset.CfsFaces) {
|
||||||
TempMesh meshout;
|
|
||||||
|
|
||||||
size_t ob = -1, cnt = 0;
|
size_t ob = -1, cnt = 0;
|
||||||
|
//TempMesh meshout;
|
||||||
BOOST_FOREACH(const IFC::IfcFaceBound& bound, face.Bounds) {
|
BOOST_FOREACH(const IFC::IfcFaceBound& bound, face.Bounds) {
|
||||||
|
|
||||||
|
// XXX implement proper merging for polygonal loops
|
||||||
if(const IFC::IfcPolyLoop* const polyloop = bound.Bound->ToPtr<IFC::IfcPolyLoop>()) {
|
if(const IFC::IfcPolyLoop* const polyloop = bound.Bound->ToPtr<IFC::IfcPolyLoop>()) {
|
||||||
if(ProcessPolyloop(*polyloop, meshout, conv)) {
|
if(ProcessPolyloop(*polyloop, result,conv)) {
|
||||||
if(bound.ToPtr<IFC::IfcFaceOuterBound>()) {
|
if(bound.ToPtr<IFC::IfcFaceOuterBound>()) {
|
||||||
ob = cnt;
|
ob = cnt;
|
||||||
}
|
}
|
||||||
|
@ -956,18 +1019,19 @@ void ProcessConnectedFaceSet(const IFC::IfcConnectedFaceSet& fset, TempMesh& res
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!IsTrue(bound.Orientation)) {
|
/*if(!IsTrue(bound.Orientation)) {
|
||||||
size_t c = 0;
|
size_t c = 0;
|
||||||
BOOST_FOREACH(unsigned int& i, meshout.vertcnt) {
|
BOOST_FOREACH(unsigned int& i, meshout.vertcnt) {
|
||||||
std::reverse(meshout.verts.begin() + cnt,meshout.verts.begin() + cnt + c);
|
std::reverse(meshout.verts.begin() + cnt,meshout.verts.begin() + cnt + c);
|
||||||
cnt += c;
|
cnt += c;
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MergePolygonBoundaries(result,meshout,ob);
|
//MergePolygonBoundaries(result,meshout,ob);
|
||||||
}
|
}
|
||||||
|
FixupFaceOrientation(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -1068,30 +1132,6 @@ bool ProcessProfile(const IFC::IfcProfileDef& prof, TempMesh& meshout, Conversio
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
void FixupFaceOrientation(TempMesh& result)
|
|
||||||
{
|
|
||||||
aiVector3D vavg;
|
|
||||||
BOOST_FOREACH(aiVector3D& v, result.verts) {
|
|
||||||
vavg += v;
|
|
||||||
}
|
|
||||||
|
|
||||||
// fix face orientation - try at least.
|
|
||||||
vavg /= static_cast<float>( result.verts.size() );
|
|
||||||
|
|
||||||
size_t c = 0;
|
|
||||||
BOOST_FOREACH(unsigned int cnt, result.vertcnt) {
|
|
||||||
if (cnt>2){
|
|
||||||
const aiVector3D& thisvert = result.verts[c];
|
|
||||||
const aiVector3D normal((thisvert-result.verts[c+1])^(thisvert-result.verts[c+2]));
|
|
||||||
if (normal*(thisvert-vavg) < 0) {
|
|
||||||
std::reverse(result.verts.begin()+c,result.verts.begin()+cnt+c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c += cnt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ProcessRevolvedAreaSolid(const IFC::IfcRevolvedAreaSolid& solid, TempMesh& result, ConversionData& conv)
|
void ProcessRevolvedAreaSolid(const IFC::IfcRevolvedAreaSolid& solid, TempMesh& result, ConversionData& conv)
|
||||||
{
|
{
|
||||||
|
@ -1271,7 +1311,7 @@ aiVector2D ProjectPositionVectorOntoPlane(const aiVector3D& x, const ProjectionI
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void TriangulatePart(const aiVector2D& pmin, const aiVector2D& pmax, XYSortedField& field, const std::vector< BoundingBox >& bbs,
|
void QuadrifyPart(const aiVector2D& pmin, const aiVector2D& pmax, XYSortedField& field, const std::vector< BoundingBox >& bbs,
|
||||||
std::vector<aiVector2D>& out)
|
std::vector<aiVector2D>& out)
|
||||||
{
|
{
|
||||||
if (!(pmin.x-pmax.x) || !(pmin.y-pmax.y)) {
|
if (!(pmin.x-pmax.x) || !(pmin.y-pmax.y)) {
|
||||||
|
@ -1323,7 +1363,7 @@ void TriangulatePart(const aiVector2D& pmin, const aiVector2D& pmax, XYSortedFie
|
||||||
const float ys = std::max(bb.first.y,pmin.y), ye = std::min(bb.second.y,pmax.y);
|
const float ys = std::max(bb.first.y,pmin.y), ye = std::min(bb.second.y,pmax.y);
|
||||||
if (ys - ylast) {
|
if (ys - ylast) {
|
||||||
// Divide et impera!
|
// Divide et impera!
|
||||||
TriangulatePart( aiVector2D(xs,ylast), aiVector2D(xe,ys) ,field,bbs,out);
|
QuadrifyPart( aiVector2D(xs,ylast), aiVector2D(xe,ys) ,field,bbs,out);
|
||||||
}
|
}
|
||||||
|
|
||||||
// the following are the window vertices
|
// the following are the window vertices
|
||||||
|
@ -1349,12 +1389,12 @@ void TriangulatePart(const aiVector2D& pmin, const aiVector2D& pmax, XYSortedFie
|
||||||
}
|
}
|
||||||
if (ylast < pmax.y) {
|
if (ylast < pmax.y) {
|
||||||
// Divide et impera!
|
// Divide et impera!
|
||||||
TriangulatePart( aiVector2D(xs,ylast), aiVector2D(xe,pmax.y) ,field,bbs,out);
|
QuadrifyPart( aiVector2D(xs,ylast), aiVector2D(xe,pmax.y) ,field,bbs,out);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Divide et impera! - now for the whole rest
|
// Divide et impera! - now for the whole rest
|
||||||
if (pmax.x-xe) {
|
if (pmax.x-xe) {
|
||||||
TriangulatePart(aiVector2D(xe,pmin.y), pmax ,field,bbs,out);
|
QuadrifyPart(aiVector2D(xe,pmin.y), pmax ,field,bbs,out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1581,7 +1621,7 @@ bool TryAddOpenings_Triangulate(const std::vector<TempOpening>& openings,const s
|
||||||
|
|
||||||
std::vector<aiVector2D> outflat;
|
std::vector<aiVector2D> outflat;
|
||||||
outflat.reserve(openings.size()*4);
|
outflat.reserve(openings.size()*4);
|
||||||
TriangulatePart(aiVector2D(0.f,0.f),aiVector2D(1.f,1.f),field,bbs,outflat);
|
QuadrifyPart(aiVector2D(0.f,0.f),aiVector2D(1.f,1.f),field,bbs,outflat);
|
||||||
ai_assert(!(outflat.size() % 4));
|
ai_assert(!(outflat.size() % 4));
|
||||||
|
|
||||||
//FixOuterBoundaries(outflat,contour_flat);
|
//FixOuterBoundaries(outflat,contour_flat);
|
||||||
|
@ -1652,12 +1692,14 @@ void ProcessExtrudedAreaSolid(const IFC::IfcExtrudedAreaSolid& solid, TempMesh&
|
||||||
|
|
||||||
// compute the normal vectors for all opening polygons
|
// compute the normal vectors for all opening polygons
|
||||||
if (conv.apply_openings) {
|
if (conv.apply_openings) {
|
||||||
|
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(),DistanceSorter(min));
|
std::sort(conv.apply_openings->begin(),conv.apply_openings->end(),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();
|
||||||
|
|
||||||
|
@ -2387,8 +2429,9 @@ aiNode* ProcessSpatialStructure(aiNode* parent, const IFC::IfcProduct& el, Conve
|
||||||
if(!conv.collect_openings) {
|
if(!conv.collect_openings) {
|
||||||
conv.apply_openings = &openings;
|
conv.apply_openings = &openings;
|
||||||
}
|
}
|
||||||
ProcessProductRepresentation(el,nd.get(),subnodes,conv);
|
|
||||||
|
|
||||||
|
|
||||||
|
ProcessProductRepresentation(el,nd.get(),subnodes,conv);
|
||||||
conv.apply_openings = conv.collect_openings = NULL;
|
conv.apply_openings = conv.collect_openings = NULL;
|
||||||
|
|
||||||
if (subnodes.size()) {
|
if (subnodes.size()) {
|
||||||
|
@ -2414,19 +2457,22 @@ void ProcessSpatialStructures(ConversionData& conv)
|
||||||
// process all products in the file. it is reasonable to assume that a
|
// process all products in the file. it is reasonable to assume that a
|
||||||
// file that is relevant for us contains at least a site or a building.
|
// file that is relevant for us contains at least a site or a building.
|
||||||
const STEP::DB::ObjectMapByType& map = conv.db.GetObjectsByType();
|
const STEP::DB::ObjectMapByType& map = conv.db.GetObjectsByType();
|
||||||
STEP::DB::ObjectMapRange range = map.equal_range("ifcsite");
|
|
||||||
|
|
||||||
if (range.first == map.end()) {
|
ai_assert(map.find("ifcsite") != map.end());
|
||||||
range = map.equal_range("ifcbuilding");
|
const STEP::DB::ObjectSet* range = &map.find("ifcsite")->second;
|
||||||
if (range.first == map.end()) {
|
|
||||||
// no site, no building - try all ids. this will take ages, but it should rarely happen.
|
if (range->empty()) {
|
||||||
range = STEP::DB::ObjectMapRange(map.begin(),map.end());
|
ai_assert(map.find("ifcbuilding") != map.end());
|
||||||
|
range = &map.find("ifcbuilding")->second;
|
||||||
|
if (range->empty()) {
|
||||||
|
// no site, no building - fail;
|
||||||
|
IFCImporter::ThrowException("no root element found (expected IfcBuilding or preferably IfcSite)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for(;range.first != range.second; ++range.first) {
|
BOOST_FOREACH(const STEP::LazyObject* lz, *range) {
|
||||||
const IFC::IfcSpatialStructureElement* const prod = (*range.first).second->ToPtr<IFC::IfcSpatialStructureElement>();
|
const IFC::IfcSpatialStructureElement* const prod = lz->ToPtr<IFC::IfcSpatialStructureElement>();
|
||||||
if(!prod) {
|
if(!prod) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -2454,7 +2500,7 @@ void ProcessSpatialStructures(ConversionData& conv)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
IFCImporter::ThrowException("Failed to determine primary site element");
|
IFCImporter::ThrowException("failed to determine primary site element");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -804,7 +804,7 @@ namespace STEP {
|
||||||
class DB
|
class DB
|
||||||
{
|
{
|
||||||
friend DB* ReadFileHeader(boost::shared_ptr<IOStream> stream);
|
friend DB* ReadFileHeader(boost::shared_ptr<IOStream> stream);
|
||||||
friend void ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme);
|
friend void ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme,const char* const* arr, size_t len);
|
||||||
friend class LazyObject;
|
friend class LazyObject;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -812,12 +812,12 @@ namespace STEP {
|
||||||
// objects indexed by ID
|
// objects indexed by ID
|
||||||
typedef std::map<uint64_t,boost::shared_ptr<const LazyObject> > ObjectMap;
|
typedef std::map<uint64_t,boost::shared_ptr<const LazyObject> > ObjectMap;
|
||||||
|
|
||||||
// objects indexed by their declarative type
|
// objects indexed by their declarative type, but only for those that we truly want
|
||||||
typedef std::step_unordered_multimap<std::string, const LazyObject* > ObjectMapByType;
|
typedef std::set< const LazyObject*> ObjectSet;
|
||||||
typedef std::pair<ObjectMapByType::const_iterator,ObjectMapByType::const_iterator> ObjectMapRange;
|
typedef std::map<std::string, ObjectSet > ObjectMapByType;
|
||||||
|
|
||||||
// references - for each object id the ids of all objects which reference it
|
// references - for each object id the ids of all objects which reference it
|
||||||
typedef std::multimap<uint64_t, uint64_t > RefMap;
|
typedef std::step_unordered_multimap<uint64_t, uint64_t > RefMap;
|
||||||
typedef std::pair<RefMap::const_iterator,RefMap::const_iterator> RefMapRange;
|
typedef std::pair<RefMap::const_iterator,RefMap::const_iterator> RefMapRange;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -872,8 +872,8 @@ namespace STEP {
|
||||||
// get an arbitrary object out of the soup with the only restriction being its type.
|
// get an arbitrary object out of the soup with the only restriction being its type.
|
||||||
const LazyObject* GetObject(const std::string& type) const {
|
const LazyObject* GetObject(const std::string& type) const {
|
||||||
const ObjectMapByType::const_iterator it = objects_bytype.find(type);
|
const ObjectMapByType::const_iterator it = objects_bytype.find(type);
|
||||||
if (it != objects_bytype.end()) {
|
if (it != objects_bytype.end() && (*it).second.size()) {
|
||||||
return (*it).second;
|
return *(*it).second.begin();
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -919,13 +919,24 @@ namespace STEP {
|
||||||
|
|
||||||
void InternInsert(boost::shared_ptr<const LazyObject> lz) {
|
void InternInsert(boost::shared_ptr<const LazyObject> lz) {
|
||||||
objects[lz->id] = lz;
|
objects[lz->id] = lz;
|
||||||
objects_bytype.insert(std::make_pair(lz->type,lz.get()));
|
|
||||||
|
const ObjectMapByType::iterator it = objects_bytype.find( lz->type );
|
||||||
|
if (it != objects_bytype.end()) {
|
||||||
|
(*it).second.insert(lz.get());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetSchema(const EXPRESS::ConversionSchema& _schema) {
|
void SetSchema(const EXPRESS::ConversionSchema& _schema) {
|
||||||
schema = &_schema;
|
schema = &_schema;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SetTypesToTrack(const char* const* types, size_t N) {
|
||||||
|
for(size_t i = 0; i < N;++i) {
|
||||||
|
objects_bytype[types[i]] = ObjectSet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
HeaderInfo& GetHeader() {
|
HeaderInfo& GetHeader() {
|
||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,9 +161,10 @@ STEP::DB* STEP::ReadFileHeader(boost::shared_ptr<IOStream> stream)
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void STEP::ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme)
|
void STEP::ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme,const char* const* arr, size_t len)
|
||||||
{
|
{
|
||||||
db.SetSchema(scheme);
|
db.SetSchema(scheme);
|
||||||
|
db.SetTypesToTrack(arr,len);
|
||||||
|
|
||||||
const DB::ObjectMap& map = db.GetObjects();
|
const DB::ObjectMap& map = db.GetObjects();
|
||||||
LineSplitter& splitter = db.GetSplitter();
|
LineSplitter& splitter = db.GetSplitter();
|
||||||
|
|
|
@ -56,7 +56,11 @@ namespace STEP {
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
// 2) read the actual file contents using a user-supplied set of
|
// 2) read the actual file contents using a user-supplied set of
|
||||||
// conversion functions to interpret the data.
|
// conversion functions to interpret the data.
|
||||||
void ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme);
|
void ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme, const char* const* arr, size_t len);
|
||||||
|
template <size_t N> inline void ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme, const char* const (&arr)[N]) {
|
||||||
|
return ReadFile(db,scheme,arr,N);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // ! STEP
|
} // ! STEP
|
||||||
} // ! Assimp
|
} // ! Assimp
|
||||||
|
|
Loading…
Reference in New Issue