void SipccSdpAttributeList::LoadDirection(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder) { SdpDirectionAttribute::Direction dir; ConvertDirection(sdp_get_media_direction(sdp, level, 0), &dir); SetAttribute(new SdpDirectionAttribute(dir)); }
// ------------------------------------------------------------------------------------------------ void ConvertAxisPlacement(IfcVector3& axis, IfcVector3& pos, const IfcAxis1Placement& in) { ConvertCartesianPoint(pos,in.Location); if (in.Axis) { ConvertDirection(axis,in.Axis.Get()); } else { axis = IfcVector3(0.f,0.f,1.f); } }
// ------------------------------------------------------------------------------------------------ void ConvertTransformOperator(IfcMatrix4& out, const IfcCartesianTransformationOperator& op) { IfcVector3 loc; ConvertCartesianPoint(loc,op.LocalOrigin); IfcVector3 x(1.f,0.f,0.f),y(0.f,1.f,0.f),z(0.f,0.f,1.f); if (op.Axis1) { ConvertDirection(x,*op.Axis1.Get()); } if (op.Axis2) { ConvertDirection(y,*op.Axis2.Get()); } if (const IfcCartesianTransformationOperator3D* op2 = op.ToPtr<IfcCartesianTransformationOperator3D>()) { if(op2->Axis3) { ConvertDirection(z,*op2->Axis3.Get()); } } IfcMatrix4 locm; IfcMatrix4::Translation(loc,locm); AssignMatrixAxes(out,x,y,z); IfcVector3 vscale; if (const IfcCartesianTransformationOperator3DnonUniform* nuni = op.ToPtr<IfcCartesianTransformationOperator3DnonUniform>()) { vscale.x = nuni->Scale?op.Scale.Get():1.f; vscale.y = nuni->Scale2?nuni->Scale2.Get():1.f; vscale.z = nuni->Scale3?nuni->Scale3.Get():1.f; } else { const IfcFloat sc = op.Scale?op.Scale.Get():1.f; vscale = IfcVector3(sc,sc,sc); } IfcMatrix4 s; IfcMatrix4::Scaling(vscale,s); out = locm * out * s; }
// ------------------------------------------------------------------------------------------------ void ConvertAxisPlacement(IfcMatrix4& out, const IfcAxis2Placement3D& in) { IfcVector3 loc; ConvertCartesianPoint(loc,in.Location); IfcVector3 z(0.f,0.f,1.f),r(1.f,0.f,0.f),x; if (in.Axis) { ConvertDirection(z,*in.Axis.Get()); } if (in.RefDirection) { ConvertDirection(r,*in.RefDirection.Get()); } IfcVector3 v = r.Normalize(); IfcVector3 tmpx = z * (v*z); x = (v-tmpx).Normalize(); IfcVector3 y = (z^x); IfcMatrix4::Translation(loc,out); AssignMatrixAxes(out,x,y,z); }
// ------------------------------------------------------------------------------------------------ void ConvertAxisPlacement(IfcMatrix4& out, const IfcAxis2Placement2D& in) { IfcVector3 loc; ConvertCartesianPoint(loc,in.Location); IfcVector3 x(1.f,0.f,0.f); if (in.RefDirection) { ConvertDirection(x,*in.RefDirection.Get()); } const IfcVector3 y = IfcVector3(x.y,-x.x,0.f); IfcMatrix4::Translation(loc,out); AssignMatrixAxes(out,x,y,IfcVector3(0.f,0.f,1.f)); }
// ------------------------------------------------------------------------------------------------ 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); }
void SipccSdpAttributeList::LoadExtmap(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder) { auto extmaps = MakeUnique<SdpExtmapAttributeList>(); for (uint16_t i = 1; i < UINT16_MAX; ++i) { sdp_attr_t* attr = sdp_find_attr(sdp, level, 0, SDP_ATTR_EXTMAP, i); if (!attr) { break; } sdp_extmap_t* extmap = &(attr->attr.extmap); SdpDirectionAttribute::Direction dir = SdpDirectionAttribute::kSendrecv; if (extmap->media_direction_specified) { ConvertDirection(extmap->media_direction, &dir); } extmaps->PushEntry(extmap->id, dir, extmap->media_direction_specified, extmap->uri, extmap->extension_attributes); } if (!extmaps->mExtmaps.empty()) { if (!AtSessionLevel() && mSessionLevel->HasAttribute(SdpAttribute::kExtmapAttribute)) { uint32_t lineNumber = sdp_attr_line_number(sdp, SDP_ATTR_EXTMAP, level, 0, 1); errorHolder.AddParseError( lineNumber, "extmap attributes in both session and media level"); } SetAttribute(extmaps.release()); } }
// ------------------------------------------------------------------------------------------------ void ConvertVector(IfcVector3& out, const IfcVector& in) { ConvertDirection(out,in.Orientation); out *= in.Magnitude; }
// ------------------------------------------------------------------------------------------------ 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; }