Exemplo n.º 1
0
// ------------------------------------------------------------------------------------------------
void ConvertAxisPlacement(IfcMatrix4& out, const IfcAxis2Placement& in, ConversionData& conv)
{
	if(const IfcAxis2Placement3D* pl3 = in.ResolveSelectPtr<IfcAxis2Placement3D>(conv.db)) {
		ConvertAxisPlacement(out,*pl3);
	}
	else if(const IfcAxis2Placement2D* pl2 = in.ResolveSelectPtr<IfcAxis2Placement2D>(conv.db)) {
		ConvertAxisPlacement(out,*pl2);
	}
	else {
		IFCImporter::LogWarn("skipping unknown IfcAxis2Placement entity");
	}
}
Exemplo n.º 2
0
// 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,
    const IfcVector3& extrusionDir, TempMesh& result, ConversionData &conv, bool collect_openings)
{
    // Outline: 'curve' is now a list of vertex points forming the underlying profile, extrude along the given axis,
    // forming new triangles.
    const bool has_area = solid.SweptArea->ProfileType == "AREA" && curve.verts.size() > 2;
    if( solid.Depth < 1e-6 ) {
        if( has_area ) {
            result.Append(curve);
        }
        return;
    }

    result.verts.reserve(curve.verts.size()*(has_area ? 4 : 2));
    result.vertcnt.reserve(curve.verts.size() + 2);
    std::vector<IfcVector3> in = curve.verts;

    // First step: transform all vertices into the target coordinate space
    IfcMatrix4 trafo;
    ConvertAxisPlacement(trafo, solid.Position);

    IfcVector3 vmin, vmax;
    MinMaxChooser<IfcVector3>()(vmin, vmax);
    BOOST_FOREACH(IfcVector3& v, in) {
        v *= trafo;

        vmin = std::min(vmin, v);
        vmax = std::max(vmax, v);
    }
Exemplo n.º 3
0
// ------------------------------------------------------------------------------------------------
void ProcessParametrizedProfile(const IfcParameterizedProfileDef& def, TempMesh& meshout, ConversionData& conv)
{
	(void)conv;
	if(const IfcRectangleProfileDef* const cprofile = def.ToPtr<IfcRectangleProfileDef>()) {
		const IfcFloat x = cprofile->XDim*0.5f, y = cprofile->YDim*0.5f;

		meshout.verts.reserve(meshout.verts.size()+4);
		meshout.verts.push_back( IfcVector3( x, y, 0.f ));
		meshout.verts.push_back( IfcVector3(-x, y, 0.f ));
		meshout.verts.push_back( IfcVector3(-x,-y, 0.f ));
		meshout.verts.push_back( IfcVector3( x,-y, 0.f ));
		meshout.vertcnt.push_back(4);
	}
	else if( const IfcCircleProfileDef* const circle = def.ToPtr<IfcCircleProfileDef>()) {
		if( const IfcCircleHollowProfileDef* const hollow = def.ToPtr<IfcCircleHollowProfileDef>()) {
			// TODO
		}
		const size_t segments = 32;
		const IfcFloat delta = AI_MATH_TWO_PI_F/segments, radius = circle->Radius;

		meshout.verts.reserve(segments);

		IfcFloat angle = 0.f;
		for(size_t i = 0; i < segments; ++i, angle += delta) {
			meshout.verts.push_back( IfcVector3( cos(angle)*radius, sin(angle)*radius, 0.f ));
		}

		meshout.vertcnt.push_back(segments);
	}
	else if( const IfcIShapeProfileDef* const ishape = def.ToPtr<IfcIShapeProfileDef>()) {
		// construct simplified IBeam shape
		const IfcFloat offset = (ishape->OverallWidth - ishape->WebThickness) / 2;
		const IfcFloat inner_height = ishape->OverallDepth - ishape->FlangeThickness * 2;

		meshout.verts.reserve(12);
		meshout.verts.push_back(IfcVector3(0,0,0));
		meshout.verts.push_back(IfcVector3(0,ishape->FlangeThickness,0));
		meshout.verts.push_back(IfcVector3(offset,ishape->FlangeThickness,0));
		meshout.verts.push_back(IfcVector3(offset,ishape->FlangeThickness + inner_height,0));
		meshout.verts.push_back(IfcVector3(0,ishape->FlangeThickness + inner_height,0));
		meshout.verts.push_back(IfcVector3(0,ishape->OverallDepth,0));
		meshout.verts.push_back(IfcVector3(ishape->OverallWidth,ishape->OverallDepth,0));
		meshout.verts.push_back(IfcVector3(ishape->OverallWidth,ishape->FlangeThickness + inner_height,0));
		meshout.verts.push_back(IfcVector3(offset+ishape->WebThickness,ishape->FlangeThickness + inner_height,0));
		meshout.verts.push_back(IfcVector3(offset+ishape->WebThickness,ishape->FlangeThickness,0));
		meshout.verts.push_back(IfcVector3(ishape->OverallWidth,ishape->FlangeThickness,0));
		meshout.verts.push_back(IfcVector3(ishape->OverallWidth,0,0));

		meshout.vertcnt.push_back(12);
	}
	else {
		IFCImporter::LogWarn("skipping unknown IfcParameterizedProfileDef entity, type is " + def.GetClassName());
		return;
	}

	IfcMatrix4 trafo;
	ConvertAxisPlacement(trafo, *def.Position);
	meshout.Transform(trafo);
}
Exemplo n.º 4
0
// ------------------------------------------------------------------------------------------------
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; /*
	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;
	}

	result.verts.reserve(size*(has_area?4:2));
	result.vertcnt.reserve(meshout.vertcnt.size()+2);

	// First step: transform all vertices into the target coordinate space
	IfcMatrix4 trafo;
	ConvertAxisPlacement(trafo, solid.Position);

	IfcVector3 vmin, vmax;
	MinMaxChooser<IfcVector3>()(vmin, vmax);
	BOOST_FOREACH(IfcVector3& v,in) {
		v *= trafo;

		vmin = std::min(vmin, v);
		vmax = std::max(vmax, v);
	}
Exemplo n.º 5
0
// ------------------------------------------------------------------------------------------------
void ProcessParametrizedProfile(const IfcParameterizedProfileDef& def, TempMesh& meshout, ConversionData& conv)
{
	if(const IfcRectangleProfileDef* const cprofile = def.ToPtr<IfcRectangleProfileDef>()) {
		const IfcFloat x = cprofile->XDim*0.5f, y = cprofile->YDim*0.5f;

		meshout.verts.reserve(meshout.verts.size()+4);
		meshout.verts.push_back( IfcVector3( x, y, 0.f ));
		meshout.verts.push_back( IfcVector3(-x, y, 0.f ));
		meshout.verts.push_back( IfcVector3(-x,-y, 0.f ));
		meshout.verts.push_back( IfcVector3( x,-y, 0.f ));
		meshout.vertcnt.push_back(4);
	}
	else if( const IfcCircleProfileDef* const circle = def.ToPtr<IfcCircleProfileDef>()) {
		if( const IfcCircleHollowProfileDef* const hollow = def.ToPtr<IfcCircleHollowProfileDef>()) {
			// TODO
		}
		const size_t segments = 32;
		const IfcFloat delta = AI_MATH_TWO_PI_F/segments, radius = circle->Radius;

		meshout.verts.reserve(segments);

		IfcFloat angle = 0.f;
		for(size_t i = 0; i < segments; ++i, angle += delta) {
			meshout.verts.push_back( IfcVector3( ::cos(angle)*radius, ::sin(angle)*radius, 0.f ));
		}

		meshout.vertcnt.push_back(segments);
	}
	else {
		IFCImporter::LogWarn("skipping unknown IfcParameterizedProfileDef entity, type is " + def.GetClassName());
		return;
	}

	IfcMatrix4 trafo;
	ConvertAxisPlacement(trafo, *def.Position);
	meshout.Transform(trafo);
}
Exemplo n.º 6
0
// ------------------------------------------------------------------------------------------------
void ProcessRevolvedAreaSolid(const IfcRevolvedAreaSolid& solid, TempMesh& result, ConversionData& conv)
{
    TempMesh meshout;

    // first read the profile description
    if(!ProcessProfile(*solid.SweptArea,meshout,conv) || meshout.verts.size()<=1) {
        return;
    }

    IfcVector3 axis, pos;
    ConvertAxisPlacement(axis,pos,solid.Axis);

    IfcMatrix4 tb0,tb1;
    IfcMatrix4::Translation(pos,tb0);
    IfcMatrix4::Translation(-pos,tb1);

    const std::vector<IfcVector3>& in = meshout.verts;
    const size_t size=in.size();

    bool has_area = solid.SweptArea->ProfileType == "AREA" && size>2;
    const IfcFloat max_angle = solid.Angle*conv.angle_scale;
    if(std::fabs(max_angle) < 1e-3) {
        if(has_area) {
            result = meshout;
        }
        return;
    }

    const unsigned int cnt_segments = std::max(2u,static_cast<unsigned int>(16 * std::fabs(max_angle)/AI_MATH_HALF_PI_F));
    const IfcFloat delta = max_angle/cnt_segments;

    has_area = has_area && std::fabs(max_angle) < AI_MATH_TWO_PI_F*0.99;

    result.verts.reserve(size*((cnt_segments+1)*4+(has_area?2:0)));
    result.vertcnt.reserve(size*cnt_segments+2);

    IfcMatrix4 rot;
    rot = tb0 * IfcMatrix4::Rotation(delta,axis,rot) * tb1;

    size_t base = 0;
    std::vector<IfcVector3>& out = result.verts;

    // dummy data to simplify later processing
    for(size_t i = 0; i < size; ++i) {
        out.insert(out.end(),4,in[i]);
    }

    for(unsigned int seg = 0; seg < cnt_segments; ++seg) {
        for(size_t i = 0; i < size; ++i) {
            const size_t next = (i+1)%size;

            result.vertcnt.push_back(4);
            const IfcVector3& base_0 = out[base+i*4+3],base_1 = out[base+next*4+3];

            out.push_back(base_0);
            out.push_back(base_1);
            out.push_back(rot*base_1);
            out.push_back(rot*base_0);
        }
        base += size*4;
    }

    out.erase(out.begin(),out.begin()+size*4);

    if(has_area) {
        // leave the triangulation of the profile area to the ear cutting
        // implementation in aiProcess_Triangulate - for now we just
        // feed in two huge polygons.
        base -= size*8;
        for(size_t i = size; i--; ) {
            out.push_back(out[base+i*4+3]);
        }
        for(size_t i = 0; i < size; ++i ) {
            out.push_back(out[i*4]);
        }
        result.vertcnt.push_back(size);
        result.vertcnt.push_back(size);
    }

    IfcMatrix4 trafo;
    ConvertAxisPlacement(trafo, solid.Position);

    result.Transform(trafo);
    IFCImporter::LogDebug("generate mesh procedurally by radial extrusion (IfcRevolvedAreaSolid)");
}
Exemplo n.º 7
0
// ------------------------------------------------------------------------------------------------
void ProcessPolygonalBoundedBooleanHalfSpaceDifference(const IfcPolygonalBoundedHalfSpace* hs, TempMesh& result, 
													   const TempMesh& first_operand, 
													   ConversionData& conv)
{
	ai_assert(hs != NULL);

	const IfcPlane* const plane = hs->BaseSurface->ToPtr<IfcPlane>();
	if(!plane) {
		IFCImporter::LogError("expected IfcPlane as base surface for the IfcHalfSpaceSolid");
		return;
	}

	// extract plane base position vector and normal vector
	IfcVector3 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;
	}

	n.Normalize();

	// obtain the polygonal bounding volume
	boost::shared_ptr<TempMesh> profile = boost::shared_ptr<TempMesh>(new TempMesh());
	if(!ProcessCurve(hs->PolygonalBoundary, *profile.get(), conv)) {
		IFCImporter::LogError("expected valid polyline for boundary of boolean halfspace");
		return;
	}

	IfcMatrix4 proj_inv;
	ConvertAxisPlacement(proj_inv,hs->Position);

	// and map everything into a plane coordinate space so all intersection
	// tests can be done in 2D space.
	IfcMatrix4 proj = proj_inv;
	proj.Inverse();

	// clip the current contents of `meshout` against the plane we obtained from the second operand
	const std::vector<IfcVector3>& in = first_operand.verts;
	std::vector<IfcVector3>& outvert = result.verts;

	std::vector<unsigned int>::const_iterator begin = first_operand.vertcnt.begin(), 
		end = first_operand.vertcnt.end(), iit;

	outvert.reserve(in.size());
	result.vertcnt.reserve(first_operand.vertcnt.size());

	std::vector<size_t> intersected_boundary_segments;
	std::vector<IfcVector3> intersected_boundary_points;

	// TODO: the following algorithm doesn't handle all cases. 
	unsigned int vidx = 0;
	for(iit = begin; iit != end; vidx += *iit++) {
		if (!*iit) {
			continue;
		}

		unsigned int newcount = 0;
		bool was_outside_boundary = !PointInPoly(proj * in[vidx], profile->verts);

		// used any more?
		//size_t last_intersected_boundary_segment;
		IfcVector3 last_intersected_boundary_point;

		bool extra_point_flag = false;
		IfcVector3 extra_point;

		IfcVector3 enter_volume;
		bool entered_volume_flag = false;

		for(unsigned int i = 0; i < *iit; ++i) {
			// current segment: [i,i+1 mod size] or [*extra_point,i] if extra_point_flag is set
			const IfcVector3& e0 = extra_point_flag ? extra_point : in[vidx+i];
			const IfcVector3& e1 = extra_point_flag ? in[vidx+i] : in[vidx+(i+1)%*iit];

			// does the current segment intersect the polygonal boundary?
			const IfcVector3& e0_plane = proj * e0;
			const IfcVector3& e1_plane = proj * e1;

			intersected_boundary_segments.clear();
			intersected_boundary_points.clear();

			const bool is_outside_boundary = !PointInPoly(e1_plane, profile->verts);
			const bool is_boundary_intersection = is_outside_boundary != was_outside_boundary;
			
			IntersectsBoundaryProfile(e0_plane, e1_plane, profile->verts, 
				intersected_boundary_segments, 
				intersected_boundary_points);
		
			ai_assert(!is_boundary_intersection || !intersected_boundary_segments.empty());

			// does the current segment intersect the plane?
			// (no extra check if this is an extra point)
			IfcVector3 isectpos;
			const Intersect isect =  extra_point_flag ? Intersect_No : IntersectSegmentPlane(p,n,e0,e1,isectpos);

#ifdef _DEBUG
			if (isect == Intersect_Yes) {
				const IfcFloat f = fabs((isectpos - p)*n);
				ai_assert(f < 1e-5);
			}
#endif

			const bool is_white_side = (e0-p)*n >= -1e-6;

			// e0 on good side of plane? (i.e. we should keep all geometry on this side)
			if (is_white_side) {
				// but is there an intersection in e0-e1 and is e1 in the clipping
				// boundary? In this case, generate a line that only goes to the
				// intersection point.
				if (isect == Intersect_Yes  && !is_outside_boundary) {
					outvert.push_back(e0);
					++newcount;

					outvert.push_back(isectpos);
					++newcount;
					
					/*
					// this is, however, only a line that goes to the plane, but not
					// necessarily to the point where the bounding volume on the
					// black side of the plane is hit. So basically, we need another 
					// check for [isectpos-e1], which should yield an intersection
					// point.
					extra_point_flag = true;
					extra_point = isectpos;

					was_outside_boundary = true; 
					continue; */

					// [isectpos, enter_volume] potentially needs extra points.
					// For this, we determine the intersection point with the
					// bounding volume and project it onto the plane. 
					/*
					const IfcVector3& enter_volume_proj = proj * enter_volume;
					const IfcVector3& enter_isectpos = proj * isectpos;

					intersected_boundary_segments.clear();
					intersected_boundary_points.clear();

					IntersectsBoundaryProfile(enter_volume_proj, enter_isectpos, profile->verts, 
						intersected_boundary_segments, 
						intersected_boundary_points);

					if(!intersected_boundary_segments.empty()) {

						vec = vec + ((p - vec) * n) * n;
					}
					*/				

					//entered_volume_flag = true;
				}
				else {
					outvert.push_back(e0);
					++newcount;
				}
			}
			// e0 on bad side of plane, e1 on good (i.e. we should remove geometry on this side,
			// but only if it is within the bounding volume).
			else if (isect == Intersect_Yes) {
				// is e0 within the clipping volume? Insert the intersection point
				// of [e0,e1] and the plane instead of e0.
				if(was_outside_boundary) {
					outvert.push_back(e0);
				}
				else {
					if(entered_volume_flag) {
						const IfcVector3& fix_point = enter_volume + ((p - enter_volume) * n) * n;
						outvert.push_back(fix_point);
						++newcount;
					}

					outvert.push_back(isectpos);	
				}
				entered_volume_flag = false;
				++newcount;
			}
			else { // no intersection with plane or parallel; e0,e1 are on the bad side
			
				// did we just pass the boundary line to the poly bounding?
				if (is_boundary_intersection) {

					// and are now outside the clipping boundary?
					if (is_outside_boundary) {
						// in this case, get the point where the clipping boundary
						// was entered first. Then, get the point where the clipping
						// boundary volume was left! These two points with the plane
						// normal form another plane that intersects the clipping
						// volume. There are two ways to get from the first to the
						// second point along the intersection curve, try to pick the
						// one that lies within the current polygon.

						// TODO this approach doesn't handle all cases

						// ...

						IfcFloat d = 1e20;
						IfcVector3 vclosest;
						BOOST_FOREACH(const IfcVector3& v, intersected_boundary_points) {
							const IfcFloat dn = (v-e1_plane).SquareLength();
							if (dn < d) {
								d = dn;
								vclosest = v;
							}
						}

						vclosest = proj_inv * vclosest;
						if(entered_volume_flag) {
							const IfcVector3& fix_point = vclosest + ((p - vclosest) * n) * n;
							outvert.push_back(fix_point);
							++newcount;

							entered_volume_flag = false;
						}

						outvert.push_back(vclosest);
						++newcount;

						//outvert.push_back(e1);
						//++newcount;
					}
					else {
						entered_volume_flag = true;

						// we just entered the clipping boundary. Record the point
						// and the segment where we entered and also generate this point.
						//last_intersected_boundary_segment = intersected_boundary_segments.front();
						//last_intersected_boundary_point = intersected_boundary_points.front();

						outvert.push_back(e0);
						++newcount;

						IfcFloat d = 1e20;
						IfcVector3 vclosest;
						BOOST_FOREACH(const IfcVector3& v, intersected_boundary_points) {
							const IfcFloat dn = (v-e0_plane).SquareLength();
							if (dn < d) {
								d = dn;
								vclosest = v;
							}
						}

						enter_volume = proj_inv * vclosest;
						outvert.push_back(enter_volume);
						++newcount;
					}
				}				
				// if not, we just keep the vertex
				else if (is_outside_boundary) {
					outvert.push_back(e0);
					++newcount;

					entered_volume_flag = false;
				}
			}

			was_outside_boundary = is_outside_boundary;
			extra_point_flag = false;
		}