bool SMESH_MesherHelper::GetNodeUVneedInFaceNode(const TopoDS_Face& F) const { if ( F.IsNull() ) return !mySeamShapeIds.empty(); if ( !F.IsNull() && !myShape.IsNull() && myShape.IsSame( F )) return !mySeamShapeIds.empty(); Handle(Geom_Surface) aSurface = BRep_Tool::Surface( F ); if ( !aSurface.IsNull() ) return ( aSurface->IsUPeriodic() || aSurface->IsVPeriodic() ); return false; }
// TODO: This code is taken from and duplicates code in Part2DObject::positionBySupport() // Note: We cannot return a reference, because it will become Null. // Not clear where, because we check for IsNull() here, but as soon as it is passed out of // this method, it becomes null! const TopoDS_Face SketchBased::getSupportFace() const { const App::PropertyLinkSub& Support = static_cast<Part::Part2DObject*>(Sketch.getValue())->Support; Part::Feature *part = static_cast<Part::Feature*>(Support.getValue()); if (!part || !part->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) throw Base::Exception("Sketch has no support shape"); const std::vector<std::string> &sub = Support.getSubValues(); assert(sub.size()==1); // get the selected sub shape (a Face) const Part::TopoShape &shape = part->Shape.getShape(); if (shape._Shape.IsNull()) throw Base::Exception("Sketch support shape is empty!"); TopoDS_Shape sh = shape.getSubShape(sub[0].c_str()); if (sh.IsNull()) throw Base::Exception("Null shape in SketchBased::getSupportFace()!"); const TopoDS_Face face = TopoDS::Face(sh); if (face.IsNull()) throw Base::Exception("Null face in SketchBased::getSupportFace()!"); BRepAdaptor_Surface adapt(face); if (adapt.GetType() != GeomAbs_Plane) throw Base::Exception("No planar face in SketchBased::getSupportFace()!"); return face; }
gp_Dir GetFaceNormalAtUV(const TopoDS_Face &face, double u, double v, gp_Pnt *pos){ if(face.IsNull()) return gp_Dir(0, 0, 1); try { Handle(Geom_Surface) surf=BRep_Tool::Surface(face); // get surface properties GeomLProp_SLProps props(surf, u, v, 1, 0.01); // get surface normal if(!props.IsNormalDefined())return gp_Dir(0, 0, 1); gp_Dir norm=props.Normal(); // check orientation if(pos)*pos = props.Value(); if(face.Orientation()==TopAbs_REVERSED) norm.Reverse(); return norm; } catch (Standard_Failure) { Handle_Standard_Failure e = Standard_Failure::Caught(); wxMessageBox(wxString(_("Error in GetFaceNormalAtUV")) + _T(": ") + Ctt(e->GetMessageString())); return gp_Dir(0, 0, 1); } catch (const char* str) { wxMessageBox(wxString(_("Error in GetFaceNormalAtUV")) + _T(": ") + Ctt(str)); return gp_Dir(0, 0, 1); } catch (...) { wxMessageBox(_("Error in GetFaceNormalAtUV")); return gp_Dir(0, 0, 1); } }
void PointOnFacesProjector::prepare(const TopoDS_Shape& faces) { d->clear(); // Build the UB tree for binary search of points internal::UBTreeOfNodeIndicesFiller_t ubTreeFiller(d->m_ubTree, Standard_False); for (TopExp_Explorer exp(faces, TopAbs_FACE); exp.More(); exp.Next()) { const TopoDS_Face face = TopoDS::Face(exp.Current()); if (!face.IsNull()) { TopLoc_Location loc; const Handle_Poly_Triangulation& triangulation = BRep_Tool::Triangulation(face, loc); if (!triangulation.IsNull()) { d->insertMapping(triangulation, face); const gp_Trsf& trsf = loc.Transformation(); const TColgp_Array1OfPnt& nodes = triangulation->Nodes(); for (int i = nodes.Lower(); i <= nodes.Upper(); ++i) { const gp_Pnt iNode(nodes(i).Transformed(trsf)); Bnd_Box ibb; ibb.Set(iNode); ubTreeFiller.Add(std::make_pair(i, triangulation), ibb); } } } } ubTreeFiller.Fill(); }
void ProfileBased::getUpToFaceFromLinkSub(TopoDS_Face& upToFace, const App::PropertyLinkSub& refFace) { App::DocumentObject* ref = refFace.getValue(); std::vector<std::string> subStrings = refFace.getSubValues(); if (ref == NULL) throw Base::ValueError("SketchBased: Up to face: No face selected"); if (ref->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { upToFace = TopoDS::Face(makeShapeFromPlane(ref)); return; } else if (ref->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { Part::Datum* datum = static_cast<Part::Datum*>(ref); upToFace = TopoDS::Face(datum->getShape()); return; } if (!ref->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) throw Base::TypeError("SketchBased: Up to face: Must be face of a feature"); Part::TopoShape baseShape = static_cast<Part::Feature*>(ref)->Shape.getShape(); if (subStrings.empty() || subStrings[0].empty()) throw Base::ValueError("SketchBased: Up to face: No face selected"); // TODO: Check for multiple UpToFaces? upToFace = TopoDS::Face(baseShape.getSubShape(subStrings[0].c_str())); if (upToFace.IsNull()) throw Base::ValueError("SketchBased: Up to face: Failed to extract face"); }
// Note: We cannot return a reference, because it will become Null. // Not clear where, because we check for IsNull() here, but as soon as it is passed out of // this method, it becomes null! const TopoDS_Face ProfileBased::getSupportFace() const { const Part::Part2DObject* sketch = getVerifiedSketch(); if (sketch->MapMode.getValue() == Attacher::mmFlatFace && sketch->Support.getValue()) { const auto &Support = sketch->Support; App::DocumentObject* ref = Support.getValue(); Part::Feature *part = static_cast<Part::Feature*>(ref); if (part && part->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { const std::vector<std::string> &sub = Support.getSubValues(); assert(sub.size()==1); if (sub.at(0) == "") { // This seems to happen when sketch is on a datum plane return TopoDS::Face(Feature::makeShapeFromPlane(sketch)); } // get the selected sub shape (a Face) const Part::TopoShape &shape = part->Shape.getShape(); if (shape.getShape().IsNull()) throw Base::ValueError("Sketch support shape is empty!"); TopoDS_Shape sh = shape.getSubShape(sub[0].c_str()); if (sh.IsNull()) throw Base::ValueError("Null shape in SketchBased::getSupportFace()!"); const TopoDS_Face face = TopoDS::Face(sh); if (face.IsNull()) throw Base::ValueError("Null face in SketchBased::getSupportFace()!"); BRepAdaptor_Surface adapt(face); if (adapt.GetType() != GeomAbs_Plane) throw Base::TypeError("No planar face in SketchBased::getSupportFace()!"); return face; } } return TopoDS::Face(Feature::makeShapeFromPlane(sketch)); }
TopoDS_Face FaceTypedCylinder::buildFace(const FaceVectorType &faces) const { std::vector<EdgeVectorType> boundaries; boundarySplit(faces, boundaries); static TopoDS_Face dummy; if (boundaries.size() < 1) return dummy; //take one face and remove all the wires. TopoDS_Face workFace = faces.at(0); ShapeBuild_ReShape reshaper; TopExp_Explorer it; for (it.Init(workFace, TopAbs_WIRE); it.More(); it.Next()) reshaper.Remove(it.Current()); workFace = TopoDS::Face(reshaper.Apply(workFace)); if (workFace.IsNull()) return TopoDS_Face(); ShapeFix_Face faceFixer(workFace); //makes wires std::vector<EdgeVectorType>::iterator boundaryIt; for (boundaryIt = boundaries.begin(); boundaryIt != boundaries.end(); ++boundaryIt) { BRepLib_MakeWire wireMaker; EdgeVectorType::iterator it; for (it = (*boundaryIt).begin(); it != (*boundaryIt).end(); ++it) wireMaker.Add(*it); if (wireMaker.Error() != BRepLib_WireDone) continue; faceFixer.Add(wireMaker.Wire()); } if (faceFixer.Perform() > ShapeExtend_DONE5) return TopoDS_Face(); faceFixer.FixOrientation(); if (faceFixer.Perform() > ShapeExtend_DONE5) return TopoDS_Face(); return faceFixer.Face(); }
const std::list<gp_Trsf> LinearPattern::getTransformations(const std::vector<App::DocumentObject*>) { std::string stdDirection = StdDirection.getValue(); float distance = Length.getValue(); if (distance < Precision::Confusion()) throw Base::Exception("Pattern length too small"); int occurrences = Occurrences.getValue(); if (occurrences < 2) throw Base::Exception("At least two occurrences required"); bool reversed = Reversed.getValue(); gp_Dir dir; double offset = distance / (occurrences - 1); if (!stdDirection.empty()) { // Note: The placement code commented out below had the defect of working always on the // absolute X,Y,Z direction, not on the relative coordinate system of the Body feature. // It requires positionBySupport() to be called in Transformed::Execute() AFTER // the call to getTransformations() // New code thanks to logari81 if (stdDirection == "X") { //dir = Base::Axis(Base::Vector3d(0,0,0), Base::Vector3d(1,0,0)); dir = gp_Dir(1,0,0); } else if (stdDirection == "Y") { //dir = Base::Axis(Base::Vector3d(0,0,0), Base::Vector3d(0,1,0)); dir = gp_Dir(0,1,0); } else if(stdDirection == "Z") { //dir = Base::Axis(Base::Vector3d(0,0,0), Base::Vector3d(0,0,1)); dir = gp_Dir(0,0,1); } else { throw Base::Exception("Invalid direction (must be X, Y or Z)"); } } else { App::DocumentObject* refObject = Direction.getValue(); if (refObject == NULL) throw Base::Exception("No direction specified"); if (!refObject->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) throw Base::Exception("Direction reference must be edge or face of a feature"); std::vector<std::string> subStrings = Direction.getSubValues(); if (subStrings.empty() || subStrings[0].empty()) throw Base::Exception("No direction reference specified"); Part::Feature* refFeature = static_cast<Part::Feature*>(refObject); Part::TopoShape refShape = refFeature->Shape.getShape(); TopoDS_Shape ref = refShape.getSubShape(subStrings[0].c_str()); if (ref.ShapeType() == TopAbs_FACE) { TopoDS_Face refFace = TopoDS::Face(ref); if (refFace.IsNull()) throw Base::Exception("Failed to extract direction plane"); BRepAdaptor_Surface adapt(refFace); if (adapt.GetType() != GeomAbs_Plane) throw Base::Exception("Direction face must be planar"); dir = adapt.Plane().Axis().Direction(); //gp_Dir d = adapt.Plane().Axis().Direction(); //dir = Base::Axis(Base::Vector3d(0,0,0), Base::Vector3d(d.X(), d.Y(), d.Z())); } else if (ref.ShapeType() == TopAbs_EDGE) { TopoDS_Edge refEdge = TopoDS::Edge(ref); if (refEdge.IsNull()) throw Base::Exception("Failed to extract direction edge"); BRepAdaptor_Curve adapt(refEdge); if (adapt.GetType() != GeomAbs_Line) throw Base::Exception("Direction edge must be a straight line"); //gp_Dir d = adapt.Line().Direction(); //dir = Base::Axis(Base::Vector3d(0,0,0), Base::Vector3d(d.X(), d.Y(), d.Z())); dir = adapt.Line().Direction(); } else { throw Base::Exception("Direction reference must be edge or face"); } TopLoc_Location invObjLoc = this->getLocation().Inverted(); dir.Transform(invObjLoc.Transformation()); } // get the support placement // TODO: Check for NULL pointer /*Part::Feature* supportFeature = static_cast<Part::Feature*>(originals.front()); if (supportFeature == NULL) throw Base::Exception("Cannot work on invalid support shape"); Base::Placement supportPlacement = supportFeature->Placement.getValue(); dir *= supportPlacement; gp_Vec direction(dir.getDirection().x, dir.getDirection().y, dir.getDirection().z);*/ gp_Vec direction(dir.X(), dir.Y(), dir.Z()); if (reversed) direction.Reverse(); // Note: The original feature is NOT included in the list of transformations! Therefore // we start with occurrence number 1, not number 0 std::list<gp_Trsf> transformations; gp_Trsf trans; transformations.push_back(trans); // identity transformation for (int i = 1; i < occurrences; i++) { trans.SetTranslation(direction * i * offset); transformations.push_back(trans); } return transformations; }
//============================================================================= bool NETGENPlugin_Mesher::Compute() { #ifdef WNT netgen::MeshingParameters& mparams = netgen::GlobalMeshingParameters(); #else netgen::MeshingParameters& mparams = netgen::mparam; #endif MESSAGE("Compute with:\n" " max size = " << mparams.maxh << "\n" " segments per edge = " << mparams.segmentsperedge); MESSAGE("\n" " growth rate = " << mparams.grading << "\n" " elements per radius = " << mparams.curvaturesafety << "\n" " second order = " << mparams.secondorder << "\n" " quad allowed = " << mparams.quad); SMESH_ComputeErrorPtr error = SMESH_ComputeError::New(); nglib::Ng_Init(); // ------------------------- // Prepare OCC geometry // ------------------------- netgen::OCCGeometry occgeo; list< SMESH_subMesh* > meshedSM; PrepareOCCgeometry( occgeo, _shape, *_mesh, &meshedSM ); // ------------------------- // Generate the mesh // ------------------------- netgen::Mesh *ngMesh = NULL; SMESH_Comment comment; int err = 0; int nbInitNod = 0; int nbInitSeg = 0; int nbInitFac = 0; // vector of nodes in which node index == netgen ID vector< SMDS_MeshNode* > nodeVec; try { // ---------------- // compute 1D mesh // ---------------- // pass 1D simple parameters to NETGEN if ( _simpleHyp ) { if ( int nbSeg = _simpleHyp->GetNumberOfSegments() ) { // nb of segments mparams.segmentsperedge = nbSeg + 0.1; mparams.maxh = occgeo.boundingbox.Diam(); mparams.grading = 0.01; } else { // segment length mparams.segmentsperedge = 1; mparams.maxh = _simpleHyp->GetLocalLength(); } } // let netgen create ngMesh and calculate element size on not meshed shapes char *optstr = 0; int startWith = netgen::MESHCONST_ANALYSE; int endWith = netgen::MESHCONST_ANALYSE; err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr); if (err) comment << "Error in netgen::OCCGenerateMesh() at MESHCONST_ANALYSE step"; // fill ngMesh with nodes and elements of computed submeshes err = ! fillNgMesh(occgeo, *ngMesh, nodeVec, meshedSM); nbInitNod = ngMesh->GetNP(); nbInitSeg = ngMesh->GetNSeg(); nbInitFac = ngMesh->GetNSE(); // compute mesh if (!err) { startWith = endWith = netgen::MESHCONST_MESHEDGES; err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr); if (err) comment << "Error in netgen::OCCGenerateMesh() at 1D mesh generation"; } // --------------------- // compute surface mesh // --------------------- if (!err) { // pass 2D simple parameters to NETGEN if ( _simpleHyp ) { if ( double area = _simpleHyp->GetMaxElementArea() ) { // face area mparams.maxh = sqrt(2. * area/sqrt(3.0)); mparams.grading = 0.4; // moderate size growth } else { // length from edges double length = 0; TopTools_MapOfShape tmpMap; for ( TopExp_Explorer exp( _shape, TopAbs_EDGE ); exp.More(); exp.Next() ) if( tmpMap.Add(exp.Current()) ) length += SMESH_Algo::EdgeLength( TopoDS::Edge( exp.Current() )); if ( ngMesh->GetNSeg() ) { // we have to multiply length by 2 since for each TopoDS_Edge there // are double set of NETGEN edges or, in other words, we have to // divide ngMesh->GetNSeg() on 2. mparams.maxh = 2*length / ngMesh->GetNSeg(); } else mparams.maxh = 1000; mparams.grading = 0.2; // slow size growth } mparams.maxh = min( mparams.maxh, occgeo.boundingbox.Diam()/2 ); ngMesh->SetGlobalH (mparams.maxh); netgen::Box<3> bb = occgeo.GetBoundingBox(); bb.Increase (bb.Diam()/20); ngMesh->SetLocalH (bb.PMin(), bb.PMax(), mparams.grading); } // let netgen compute 2D mesh startWith = netgen::MESHCONST_MESHSURFACE; endWith = _optimize ? netgen::MESHCONST_OPTSURFACE : netgen::MESHCONST_MESHSURFACE; err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr); if (err) comment << "Error in netgen::OCCGenerateMesh() at surface mesh generation"; } // --------------------- // generate volume mesh // --------------------- if (!err && _isVolume) { // add ng face descriptors of meshed faces std::map< int, std::pair<int,int> >::iterator fId_soIds = _faceDescriptors.begin(); for ( ; fId_soIds != _faceDescriptors.end(); ++fId_soIds ) { int faceID = fId_soIds->first; int solidID1 = fId_soIds->second.first; int solidID2 = fId_soIds->second.second; ngMesh->AddFaceDescriptor (netgen::FaceDescriptor(faceID, solidID1, solidID2, 0)); } // pass 3D simple parameters to NETGEN const NETGENPlugin_SimpleHypothesis_3D* simple3d = dynamic_cast< const NETGENPlugin_SimpleHypothesis_3D* > ( _simpleHyp ); if ( simple3d ) { if ( double vol = simple3d->GetMaxElementVolume() ) { // max volume mparams.maxh = pow( 72, 1/6. ) * pow( vol, 1/3. ); mparams.maxh = min( mparams.maxh, occgeo.boundingbox.Diam()/2 ); } else { // length from faces mparams.maxh = ngMesh->AverageH(); } // netgen::ARRAY<double> maxhdom; // maxhdom.SetSize (occgeo.NrSolids()); // maxhdom = mparams.maxh; // ngMesh->SetMaxHDomain (maxhdom); ngMesh->SetGlobalH (mparams.maxh); mparams.grading = 0.4; ngMesh->CalcLocalH(); } // let netgen compute 3D mesh startWith = netgen::MESHCONST_MESHVOLUME; endWith = _optimize ? netgen::MESHCONST_OPTVOLUME : netgen::MESHCONST_MESHVOLUME; err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr); if (err) comment << "Error in netgen::OCCGenerateMesh()"; } if (!err && mparams.secondorder > 0) { netgen::OCCRefinementSurfaces ref (occgeo); ref.MakeSecondOrder (*ngMesh); } } catch (netgen::NgException exc) { error->myName = err = COMPERR_ALGO_FAILED; comment << exc.What(); } int nbNod = ngMesh->GetNP(); int nbSeg = ngMesh->GetNSeg(); int nbFac = ngMesh->GetNSE(); int nbVol = ngMesh->GetNE(); MESSAGE((err ? "Mesh Generation failure" : "End of Mesh Generation") << ", nb nodes: " << nbNod << ", nb segments: " << nbSeg << ", nb faces: " << nbFac << ", nb volumes: " << nbVol); // ----------------------------------------------------------- // Feed back the SMESHDS with the generated Nodes and Elements // ----------------------------------------------------------- SMESHDS_Mesh* meshDS = _mesh->GetMeshDS(); bool isOK = ( !err && (_isVolume ? (nbVol > 0) : (nbFac > 0)) ); if ( true /*isOK*/ ) // get whatever built { // map of nodes assigned to submeshes NCollection_Map<int> pindMap; // create and insert nodes into nodeVec nodeVec.resize( nbNod + 1 ); int i; for (i = nbInitNod+1; i <= nbNod /*&& isOK*/; ++i ) { const netgen::MeshPoint& ngPoint = ngMesh->Point(i); SMDS_MeshNode* node = NULL; bool newNodeOnVertex = false; TopoDS_Vertex aVert; if (i-nbInitNod <= occgeo.vmap.Extent()) { // point on vertex aVert = TopoDS::Vertex(occgeo.vmap(i-nbInitNod)); SMESHDS_SubMesh * submesh = meshDS->MeshElements(aVert); if (submesh) { SMDS_NodeIteratorPtr it = submesh->GetNodes(); if (it->more()) { node = const_cast<SMDS_MeshNode*> (it->next()); pindMap.Add(i); } } if (!node) newNodeOnVertex = true; } if (!node) node = meshDS->AddNode(ngPoint.X(), ngPoint.Y(), ngPoint.Z()); if (!node) { MESSAGE("Cannot create a mesh node"); if ( !comment.size() ) comment << "Cannot create a mesh node"; nbSeg = nbFac = nbVol = isOK = 0; break; } nodeVec.at(i) = node; if (newNodeOnVertex) { // point on vertex meshDS->SetNodeOnVertex(node, aVert); pindMap.Add(i); } } // create mesh segments along geometric edges NCollection_Map<Link> linkMap; for (i = nbInitSeg+1; i <= nbSeg/* && isOK*/; ++i ) { const netgen::Segment& seg = ngMesh->LineSegment(i); Link link(seg.p1, seg.p2); if (linkMap.Contains(link)) continue; linkMap.Add(link); TopoDS_Edge aEdge; int pinds[3] = { seg.p1, seg.p2, seg.pmid }; int nbp = 0; double param2 = 0; for (int j=0; j < 3; ++j) { int pind = pinds[j]; if (pind <= 0) continue; ++nbp; double param; if (j < 2) { if (aEdge.IsNull()) { int aGeomEdgeInd = seg.epgeominfo[j].edgenr; if (aGeomEdgeInd > 0 && aGeomEdgeInd <= occgeo.emap.Extent()) aEdge = TopoDS::Edge(occgeo.emap(aGeomEdgeInd)); } param = seg.epgeominfo[j].dist; param2 += param; } else param = param2 * 0.5; if (pind <= nbInitNod || pindMap.Contains(pind)) continue; if (!aEdge.IsNull()) { meshDS->SetNodeOnEdge(nodeVec.at(pind), aEdge, param); pindMap.Add(pind); } } SMDS_MeshEdge* edge; if (nbp < 3) // second order ? edge = meshDS->AddEdge(nodeVec.at(pinds[0]), nodeVec.at(pinds[1])); else edge = meshDS->AddEdge(nodeVec.at(pinds[0]), nodeVec.at(pinds[1]), nodeVec.at(pinds[2])); if (!edge) { if ( !comment.size() ) comment << "Cannot create a mesh edge"; MESSAGE("Cannot create a mesh edge"); nbSeg = nbFac = nbVol = isOK = 0; break; } if (!aEdge.IsNull()) meshDS->SetMeshElementOnShape(edge, aEdge); } // create mesh faces along geometric faces for (i = nbInitFac+1; i <= nbFac/* && isOK*/; ++i ) { const netgen::Element2d& elem = ngMesh->SurfaceElement(i); int aGeomFaceInd = elem.GetIndex(); TopoDS_Face aFace; if (aGeomFaceInd > 0 && aGeomFaceInd <= occgeo.fmap.Extent()) aFace = TopoDS::Face(occgeo.fmap(aGeomFaceInd)); vector<SMDS_MeshNode*> nodes; for (int j=1; j <= elem.GetNP(); ++j) { int pind = elem.PNum(j); SMDS_MeshNode* node = nodeVec.at(pind); nodes.push_back(node); if (pind <= nbInitNod || pindMap.Contains(pind)) continue; if (!aFace.IsNull()) { const netgen::PointGeomInfo& pgi = elem.GeomInfoPi(j); meshDS->SetNodeOnFace(node, aFace, pgi.u, pgi.v); pindMap.Add(pind); } } SMDS_MeshFace* face = NULL; switch (elem.GetType()) { case netgen::TRIG: face = meshDS->AddFace(nodes[0],nodes[1],nodes[2]); break; case netgen::QUAD: face = meshDS->AddFace(nodes[0],nodes[1],nodes[2],nodes[3]); break; case netgen::TRIG6: face = meshDS->AddFace(nodes[0],nodes[1],nodes[2],nodes[5],nodes[3],nodes[4]); break; case netgen::QUAD8: face = meshDS->AddFace(nodes[0],nodes[1],nodes[2],nodes[3], nodes[4],nodes[7],nodes[5],nodes[6]); break; default: MESSAGE("NETGEN created a face of unexpected type, ignoring"); continue; } if (!face) { if ( !comment.size() ) comment << "Cannot create a mesh face"; MESSAGE("Cannot create a mesh face"); nbSeg = nbFac = nbVol = isOK = 0; break; } if (!aFace.IsNull()) meshDS->SetMeshElementOnShape(face, aFace); } // create tetrahedra for (i = 1; i <= nbVol/* && isOK*/; ++i) { const netgen::Element& elem = ngMesh->VolumeElement(i); int aSolidInd = elem.GetIndex(); TopoDS_Solid aSolid; if (aSolidInd > 0 && aSolidInd <= occgeo.somap.Extent()) aSolid = TopoDS::Solid(occgeo.somap(aSolidInd)); vector<SMDS_MeshNode*> nodes; for (int j=1; j <= elem.GetNP(); ++j) { int pind = elem.PNum(j); SMDS_MeshNode* node = nodeVec.at(pind); nodes.push_back(node); if (pind <= nbInitNod || pindMap.Contains(pind)) continue; if (!aSolid.IsNull()) { // point in solid meshDS->SetNodeInVolume(node, aSolid); pindMap.Add(pind); } } SMDS_MeshVolume* vol = NULL; switch (elem.GetType()) { case netgen::TET: vol = meshDS->AddVolume(nodes[0],nodes[1],nodes[2],nodes[3]); break; case netgen::TET10: vol = meshDS->AddVolume(nodes[0],nodes[1],nodes[2],nodes[3], nodes[4],nodes[7],nodes[5],nodes[6],nodes[8],nodes[9]); break; default: MESSAGE("NETGEN created a volume of unexpected type, ignoring"); continue; } if (!vol) { if ( !comment.size() ) comment << "Cannot create a mesh volume"; MESSAGE("Cannot create a mesh volume"); nbSeg = nbFac = nbVol = isOK = 0; break; } if (!aSolid.IsNull()) meshDS->SetMeshElementOnShape(vol, aSolid); } } if ( error->IsOK() && ( !isOK || comment.size() > 0 )) error->myName = COMPERR_ALGO_FAILED; if ( !comment.empty() ) error->myComment = comment; // set bad compute error to subshapes of all failed subshapes shapes if ( !error->IsOK() && err ) { for (int i = 1; i <= occgeo.fmap.Extent(); i++) { int status = occgeo.facemeshstatus[i-1]; if (status == 1 ) continue; if ( SMESH_subMesh* sm = _mesh->GetSubMeshContaining( occgeo.fmap( i ))) { SMESH_ComputeErrorPtr& smError = sm->GetComputeError(); if ( !smError || smError->IsOK() ) { if ( status == -1 ) smError.reset( new SMESH_ComputeError( error->myName, error->myComment )); else smError.reset( new SMESH_ComputeError( COMPERR_ALGO_FAILED, "Ignored" )); } } } } nglib::Ng_DeleteMesh((nglib::Ng_Mesh*)ngMesh); nglib::Ng_Exit(); RemoveTmpFiles(); return error->IsOK(); }
void ShapeGeometryBuilder::edgeConstruct(const TopoDS_Edge &edgeIn) { TopoDS_Face face = TopoDS::Face(edgeToFace.FindFromKey(edgeIn).First()); if (face.IsNull()) throw std::runtime_error("face is null in edge construction"); TopLoc_Location location; Handle(Poly_Triangulation) triangulation; triangulation = BRep_Tool::Triangulation(face, location); const Handle(Poly_PolygonOnTriangulation) &segments = BRep_Tool::PolygonOnTriangulation(edgeIn, triangulation, location); if (segments.IsNull()) throw std::runtime_error("edge triangulation is null in edge construction"); gp_Trsf transformation; bool identity = true; if(!location.IsIdentity()) { identity = false; transformation = location.Transformation(); } const TColStd_Array1OfInteger& indexes = segments->Nodes(); const TColgp_Array1OfPnt& nodes = triangulation->Nodes(); osg::Vec3Array *vertices = dynamic_cast<osg::Vec3Array *>(edgeGeometry->getVertexArray()); osg::Vec4Array *colors = dynamic_cast<osg::Vec4Array *>(edgeGeometry->getColorArray()); osg::ref_ptr<osg::DrawElementsUInt> indices = new osg::DrawElementsUInt (GL_LINE_STRIP, indexes.Length()); osg::BoundingSphere bSphere; for (int index(indexes.Lower()); index < indexes.Upper() + 1; ++index) { gp_Pnt point = nodes(indexes(index)); if(!identity) point.Transform(transformation); vertices->push_back(osg::Vec3(point.X(), point.Y(), point.Z())); colors->push_back(edgeGeometry->getColor()); (*indices)[index - 1] = vertices->size() - 1; if (!bSphere.valid()) //for first one. { bSphere.center() = vertices->back(); bSphere.radius() = 0.0; } else bSphere.expandBy(vertices->back()); } edgeGeometry->addPrimitiveSet(indices.get()); boost::uuids::uuid id = seerShape->findShapeIdRecord(edgeIn).id; std::size_t lastPrimitiveIndex = edgeGeometry->getNumPrimitiveSets() - 1; if (!idPSetWrapperEdge->hasId(id)) { IdPSetRecord record; record.id = id; record.primitiveSetIndex = lastPrimitiveIndex; record.bSphere = bSphere; idPSetWrapperEdge->idPSetContainer.insert(record); } else //ensure that edges have the same primitive index between lod calls. //asserts here prior to having lod implemented is probably duplicate ids //for different geometry. assert(lastPrimitiveIndex == idPSetWrapperEdge->findPSetFromId(id)); }
App::DocumentObjectExecReturn *DrawViewSection::execute(void) { App::DocumentObject* link = Source.getValue(); App::DocumentObject* base = BaseView.getValue(); if (!link || !base) { Base::Console().Log("INFO - DVS::execute - No Source or Link - creation?\n"); return DrawView::execute(); } if (!link->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) return new App::DocumentObjectExecReturn("Source object is not a Part object"); if (!base->getTypeId().isDerivedFrom(TechDraw::DrawViewPart::getClassTypeId())) return new App::DocumentObjectExecReturn("BaseView object is not a DrawViewPart object"); //Base::Console().Message("TRACE - DVS::execute() - %s/%s\n",getNameInDocument(),Label.getValue()); const Part::TopoShape &partTopo = static_cast<Part::Feature*>(link)->Shape.getShape(); if (partTopo.getShape().IsNull()) return new App::DocumentObjectExecReturn("Linked shape object is empty"); (void) DrawView::execute(); //make sure Scale is up to date gp_Pln pln = getSectionPlane(); gp_Dir gpNormal = pln.Axis().Direction(); Base::Vector3d orgPnt = SectionOrigin.getValue(); Base::BoundBox3d bb = partTopo.getBoundBox(); if(!isReallyInBox(orgPnt, bb)) { Base::Console().Warning("DVS: Section Plane doesn't intersect part in %s\n",getNameInDocument()); Base::Console().Warning("DVS: Using center of bounding box.\n"); orgPnt = bb.GetCenter(); SectionOrigin.setValue(orgPnt); } // Make the extrusion face double dMax = bb.CalcDiagonalLength(); BRepBuilderAPI_MakeFace mkFace(pln, -dMax,dMax,-dMax,dMax); TopoDS_Face aProjFace = mkFace.Face(); if(aProjFace.IsNull()) return new App::DocumentObjectExecReturn("DrawViewSection - Projected face is NULL"); gp_Vec extrudeDir = dMax * gp_Vec(gpNormal); TopoDS_Shape prism = BRepPrimAPI_MakePrism(aProjFace, extrudeDir, false, true).Shape(); // We need to copy the shape to not modify the BRepstructure BRepBuilderAPI_Copy BuilderCopy(partTopo.getShape()); TopoDS_Shape myShape = BuilderCopy.Shape(); BRepAlgoAPI_Cut mkCut(myShape, prism); if (!mkCut.IsDone()) return new App::DocumentObjectExecReturn("Section cut has failed"); TopoDS_Shape rawShape = mkCut.Shape(); Bnd_Box testBox; BRepBndLib::Add(rawShape, testBox); testBox.SetGap(0.0); if (testBox.IsVoid()) { //prism & input don't intersect. rawShape is garbage, don't bother. Base::Console().Log("INFO - DVS::execute - prism & input don't intersect\n"); return DrawView::execute(); } gp_Pnt inputCenter; try { inputCenter = TechDrawGeometry::findCentroid(rawShape, Direction.getValue()); TopoDS_Shape mirroredShape = TechDrawGeometry::mirrorShape(rawShape, inputCenter, Scale.getValue()); geometryObject = buildGeometryObject(mirroredShape,inputCenter); //this is original shape after cut by section prism #if MOD_TECHDRAW_HANDLE_FACES extractFaces(); #endif //#if MOD_TECHDRAW_HANDLE_FACES } catch (Standard_Failure) { Handle_Standard_Failure e1 = Standard_Failure::Caught(); Base::Console().Log("LOG - DVS::execute - base shape failed for %s - %s **\n",getNameInDocument(),e1->GetMessageString()); return new App::DocumentObjectExecReturn(e1->GetMessageString()); } try { TopoDS_Compound sectionCompound = findSectionPlaneIntersections(rawShape); TopoDS_Shape mirroredSection = TechDrawGeometry::mirrorShape(sectionCompound, inputCenter, Scale.getValue()); TopoDS_Compound newFaces; BRep_Builder builder; builder.MakeCompound(newFaces); TopExp_Explorer expl(mirroredSection, TopAbs_FACE); for (; expl.More(); expl.Next()) { const TopoDS_Face& face = TopoDS::Face(expl.Current()); TopoDS_Face pFace = projectFace(face, inputCenter, Direction.getValue()); if (!pFace.IsNull()) { builder.Add(newFaces,pFace); } } sectionFaces = newFaces; } catch (Standard_Failure) { Handle_Standard_Failure e2 = Standard_Failure::Caught(); Base::Console().Log("LOG - DVS::execute - failed building section faces for %s - %s **\n",getNameInDocument(),e2->GetMessageString()); return new App::DocumentObjectExecReturn(e2->GetMessageString()); } return App::DocumentObject::StdReturn; }
bool FaceUniter::process() { if (workShell.IsNull()) return false; modifiedShapes.clear(); deletedShapes.clear(); typeObjects.push_back(&getPlaneObject()); typeObjects.push_back(&getCylinderObject()); //add more face types. ModelRefine::FaceTypeSplitter splitter; splitter.addShell(workShell); std::vector<FaceTypedBase *>::iterator typeIt; for(typeIt = typeObjects.begin(); typeIt != typeObjects.end(); ++typeIt) splitter.registerType((*typeIt)->getType()); splitter.split(); ModelRefine::FaceVectorType facesToRemove; ModelRefine::FaceVectorType facesToSew; ModelRefine::FaceAdjacencySplitter adjacencySplitter(workShell); for(typeIt = typeObjects.begin(); typeIt != typeObjects.end(); ++typeIt) { ModelRefine::FaceVectorType typedFaces = splitter.getTypedFaceVector((*typeIt)->getType()); ModelRefine::FaceEqualitySplitter equalitySplitter; equalitySplitter.split(typedFaces, *typeIt); for (std::size_t indexEquality(0); indexEquality < equalitySplitter.getGroupCount(); ++indexEquality) { adjacencySplitter.split(equalitySplitter.getGroup(indexEquality)); // std::cout << " adjacency group count: " << adjacencySplitter.getGroupCount() << std::endl; for (std::size_t adjacentIndex(0); adjacentIndex < adjacencySplitter.getGroupCount(); ++adjacentIndex) { // std::cout << " face count is: " << adjacencySplitter.getGroup(adjacentIndex).size() << std::endl; TopoDS_Face newFace = (*typeIt)->buildFace(adjacencySplitter.getGroup(adjacentIndex)); if (!newFace.IsNull()) { facesToSew.push_back(newFace); if (facesToRemove.capacity() <= facesToRemove.size() + adjacencySplitter.getGroup(adjacentIndex).size()) facesToRemove.reserve(facesToRemove.size() + adjacencySplitter.getGroup(adjacentIndex).size()); FaceVectorType temp = adjacencySplitter.getGroup(adjacentIndex); facesToRemove.insert(facesToRemove.end(), temp.begin(), temp.end()); // the first shape will be marked as modified, i.e. replaced by newFace, all others are marked as deleted if (!temp.empty()) { modifiedShapes.push_back(std::make_pair(temp.front(), newFace)); deletedShapes.insert(deletedShapes.end(), temp.begin()+1, temp.end()); } } } } } if (facesToSew.size() > 0) { modifiedSignal = true; workShell = ModelRefine::removeFaces(workShell, facesToRemove); TopExp_Explorer xp; bool emptyShell = true; for (xp.Init(workShell, TopAbs_FACE); xp.More(); xp.Next()) { emptyShell = false; break; } if (!emptyShell || facesToSew.size() > 1) { BRepBuilderAPI_Sewing sew; sew.Add(workShell); FaceVectorType::iterator sewIt; for(sewIt = facesToSew.begin(); sewIt != facesToSew.end(); ++sewIt) sew.Add(*sewIt); sew.Perform(); workShell = TopoDS::Shell(sew.SewedShape()); // update the list of modifications for (std::vector<ShapePairType>::iterator it = modifiedShapes.begin(); it != modifiedShapes.end(); ++it) { if (sew.IsModified(it->second)) { it->second = sew.Modified(it->second); break; } } } else { // workShell has no more faces and we add exactly one face BRep_Builder builder; builder.MakeShell(workShell); FaceVectorType::iterator sewIt; for(sewIt = facesToSew.begin(); sewIt != facesToSew.end(); ++sewIt) builder.Add(workShell, *sewIt); } BRepLib_FuseEdges edgeFuse(workShell, Standard_True); TopTools_DataMapOfShapeShape affectedFaces; edgeFuse.Faces(affectedFaces); TopTools_DataMapIteratorOfDataMapOfShapeShape mapIt; for (mapIt.Initialize(affectedFaces); mapIt.More(); mapIt.Next()) { ShapeFix_Face faceFixer(TopoDS::Face(mapIt.Value())); faceFixer.Perform(); } workShell = TopoDS::Shell(edgeFuse.Shape()); // update the list of modifications TopTools_DataMapOfShapeShape faceMap; edgeFuse.Faces(faceMap); for (std::vector<ShapePairType>::iterator it = modifiedShapes.begin(); it != modifiedShapes.end(); ++it) { if (faceMap.IsBound(it->second)) { const TopoDS_Shape& value = faceMap.Find(it->second); if (!value.IsSame(it->second)) it->second = value; } } } return true; }
App::DocumentObjectExecReturn *Pocket::execute(void) { // Handle legacy features, these typically have Type set to 3 (previously NULL, now UpToFace), // empty FaceName (because it didn't exist) and a value for Length if (std::string(Type.getValueAsString()) == "UpToFace" && (UpToFace.getValue() == NULL && Length.getValue() > Precision::Confusion())) Type.setValue("Length"); // Validate parameters double L = Length.getValue(); if ((std::string(Type.getValueAsString()) == "Length") && (L < Precision::Confusion())) return new App::DocumentObjectExecReturn("Pocket: Length of pocket too small"); Part::Feature* obj = 0; TopoDS_Face face; try { obj = getVerifiedObject(); face = getVerifiedFace(); } catch (const Base::Exception& e) { return new App::DocumentObjectExecReturn(e.what()); } // if the Base property has a valid shape, fuse the prism into it TopoDS_Shape base; try { base = getBaseShape(); } catch (const Base::Exception&) { return new App::DocumentObjectExecReturn("No sketch support and no base shape: Please tell me where to remove the material of the pocket!"); } // get the Sketch plane Base::Placement SketchPos = obj->Placement.getValue(); Base::Vector3d SketchVector = getProfileNormal(); // turn around for pockets SketchVector *= -1; try { this->positionByPrevious(); TopLoc_Location invObjLoc = this->getLocation().Inverted(); base.Move(invObjLoc); gp_Dir dir(SketchVector.x,SketchVector.y,SketchVector.z); dir.Transform(invObjLoc.Transformation()); if (face.IsNull()) return new App::DocumentObjectExecReturn("Pocket: Creating a face from sketch failed"); face.Move(invObjLoc); std::string method(Type.getValueAsString()); if (method == "UpToFirst" || method == "UpToFace") { if (base.IsNull()) return new App::DocumentObjectExecReturn("Pocket: Extruding up to a face is only possible if the sketch is located on a face"); // Note: This will return an unlimited planar face if support is a datum plane TopoDS_Face supportface = getSupportFace(); supportface.Move(invObjLoc); if (Reversed.getValue()) dir.Reverse(); // Find a valid face or datum plane to extrude up to TopoDS_Face upToFace; if (method == "UpToFace") { getUpToFaceFromLinkSub(upToFace, UpToFace); upToFace.Move(invObjLoc); } getUpToFace(upToFace, base, supportface, face, method, dir, Offset.getValue()); // BRepFeat_MakePrism(..., 2, 1) in combination with PerForm(upToFace) is buggy when the // prism that is being created is contained completely inside the base solid // In this case the resulting shape is empty. This is not a problem for the Pad or Pocket itself // but it leads to an invalid SubShape // The bug only occurs when the upToFace is limited (by a wire), not for unlimited upToFace. But // other problems occur with unlimited concave upToFace so it is not an option to always unlimit upToFace // Check supportface for limits, otherwise Perform() throws an exception TopExp_Explorer Ex(supportface,TopAbs_WIRE); if (!Ex.More()) supportface = TopoDS_Face(); BRepFeat_MakePrism PrismMaker; PrismMaker.Init(base, face, supportface, dir, 0, 1); PrismMaker.Perform(upToFace); if (!PrismMaker.IsDone()) return new App::DocumentObjectExecReturn("Pocket: Up to face: Could not extrude the sketch!"); TopoDS_Shape prism = PrismMaker.Shape(); // And the really expensive way to get the SubShape... BRepAlgoAPI_Cut mkCut(base, prism); if (!mkCut.IsDone()) return new App::DocumentObjectExecReturn("Pocket: Up to face: Could not get SubShape!"); // FIXME: In some cases this affects the Shape property: It is set to the same shape as the SubShape!!!! TopoDS_Shape result = refineShapeIfActive(mkCut.Shape()); this->AddSubShape.setValue(result); this->Shape.setValue(prism); } else { TopoDS_Shape prism; generatePrism(prism, face, method, dir, L, 0.0, Midplane.getValue(), Reversed.getValue()); if (prism.IsNull()) return new App::DocumentObjectExecReturn("Pocket: Resulting shape is empty"); // set the subtractive shape property for later usage in e.g. pattern prism = refineShapeIfActive(prism); this->AddSubShape.setValue(prism); // Cut the SubShape out of the base feature BRepAlgoAPI_Cut mkCut(base, prism); if (!mkCut.IsDone()) return new App::DocumentObjectExecReturn("Pocket: Cut out of base feature failed"); TopoDS_Shape result = mkCut.Shape(); // we have to get the solids (fuse sometimes creates compounds) TopoDS_Shape solRes = this->getSolid(result); if (solRes.IsNull()) return new App::DocumentObjectExecReturn("Pocket: Resulting shape is not a solid"); solRes = refineShapeIfActive(solRes); remapSupportShape(solRes); this->Shape.setValue(solRes); } return App::DocumentObject::StdReturn; } catch (Standard_Failure) { Handle_Standard_Failure e = Standard_Failure::Caught(); if (std::string(e->GetMessageString()) == "TopoDS::Face" && (std::string(Type.getValueAsString()) == "UpToFirst" || std::string(Type.getValueAsString()) == "UpToFace")) return new App::DocumentObjectExecReturn("Could not create face from sketch.\n" "Intersecting sketch entities or multiple faces in a sketch are not allowed " "for making a pocket up to a face."); else return new App::DocumentObjectExecReturn(e->GetMessageString()); } catch (Base::Exception& e) { return new App::DocumentObjectExecReturn(e.what()); } }
App::DocumentObjectExecReturn *Draft::execute(void) { // Get parameters // Base shape Part::TopoShape TopShape; try { TopShape = getBaseShape(); } catch (Base::Exception& e) { return new App::DocumentObjectExecReturn(e.what()); } // Faces where draft should be applied // Note: Cannot be const reference currently because of BRepOffsetAPI_DraftAngle::Remove() bug, see below std::vector<std::string> SubVals = Base.getSubValuesStartsWith("Face"); if (SubVals.size() == 0) return new App::DocumentObjectExecReturn("No faces specified"); // Draft angle double angle = Angle.getValue() / 180.0 * M_PI; // Pull direction gp_Dir pullDirection; App::DocumentObject* refDirection = PullDirection.getValue(); if (refDirection != NULL) { if (refDirection->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) { PartDesign::Line* line = static_cast<PartDesign::Line*>(refDirection); Base::Vector3d d = line->getDirection(); pullDirection = gp_Dir(d.x, d.y, d.z); } else if (refDirection->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { std::vector<std::string> subStrings = PullDirection.getSubValues(); if (subStrings.empty() || subStrings[0].empty()) throw Base::Exception("No pull direction reference specified"); Part::Feature* refFeature = static_cast<Part::Feature*>(refDirection); Part::TopoShape refShape = refFeature->Shape.getShape(); TopoDS_Shape ref = refShape.getSubShape(subStrings[0].c_str()); if (ref.ShapeType() == TopAbs_EDGE) { TopoDS_Edge refEdge = TopoDS::Edge(ref); if (refEdge.IsNull()) throw Base::Exception("Failed to extract pull direction reference edge"); BRepAdaptor_Curve adapt(refEdge); if (adapt.GetType() != GeomAbs_Line) throw Base::Exception("Pull direction reference edge must be linear"); pullDirection = adapt.Line().Direction(); } else { throw Base::Exception("Pull direction reference must be an edge or a datum line"); } } else { throw Base::Exception("Pull direction reference must be an edge of a feature or a datum line"); } TopLoc_Location invObjLoc = this->getLocation().Inverted(); pullDirection.Transform(invObjLoc.Transformation()); } // Neutral plane gp_Pln neutralPlane; App::DocumentObject* refPlane = NeutralPlane.getValue(); if (refPlane == NULL) { // Try to guess a neutral plane from the first selected face // Get edges of first selected face TopoDS_Shape face = TopShape.getSubShape(SubVals[0].c_str()); TopTools_IndexedMapOfShape mapOfEdges; TopExp::MapShapes(face, TopAbs_EDGE, mapOfEdges); bool found = false; for (int i = 1; i <= mapOfEdges.Extent(); i++) { // Note: What happens if mapOfEdges(i) is the degenerated edge of a cone? // But in that case the draft is not possible anyway! BRepAdaptor_Curve c(TopoDS::Edge(mapOfEdges(i))); gp_Pnt p1 = c.Value(c.FirstParameter()); gp_Pnt p2 = c.Value(c.LastParameter()); if (c.IsClosed()) { // Edge is a circle or a circular arc (other types are not allowed for drafting) neutralPlane = gp_Pln(p1, c.Circle().Axis().Direction()); found = true; break; } else { // Edge is linear // Find midpoint of edge and create auxiliary plane through midpoint normal to edge gp_Pnt pm = c.Value((c.FirstParameter() + c.LastParameter()) / 2.0); Handle(Geom_Plane) aux = new Geom_Plane(pm, gp_Dir(p2.X() - p1.X(), p2.Y() - p1.Y(), p2.Z() - p1.Z())); // Intersect plane with face. Is there no easier way? BRepAdaptor_Surface adapt(TopoDS::Face(face), Standard_False); Handle(Geom_Surface) sf = adapt.Surface().Surface(); GeomAPI_IntSS intersector(aux, sf, Precision::Confusion()); if (!intersector.IsDone()) continue; Handle(Geom_Curve) icurve = intersector.Line(1); if (!icurve->IsKind(STANDARD_TYPE(Geom_Line))) continue; // TODO: How to extract the line from icurve without creating an edge first? TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(icurve); BRepAdaptor_Curve c(edge); neutralPlane = gp_Pln(pm, c.Line().Direction()); found = true; break; } } if (!found) throw Base::Exception("No neutral plane specified and none can be guessed"); } else { if (refPlane->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { PartDesign::Plane* plane = static_cast<PartDesign::Plane*>(refPlane); Base::Vector3d b = plane->getBasePoint(); Base::Vector3d n = plane->getNormal(); neutralPlane = gp_Pln(gp_Pnt(b.x, b.y, b.z), gp_Dir(n.x, n.y, n.z)); } else if (refPlane->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { neutralPlane = Feature::makePlnFromPlane(refPlane); } else if (refPlane->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { std::vector<std::string> subStrings = NeutralPlane.getSubValues(); if (subStrings.empty() || subStrings[0].empty()) throw Base::Exception("No neutral plane reference specified"); Part::Feature* refFeature = static_cast<Part::Feature*>(refPlane); Part::TopoShape refShape = refFeature->Shape.getShape(); TopoDS_Shape ref = refShape.getSubShape(subStrings[0].c_str()); if (ref.ShapeType() == TopAbs_FACE) { TopoDS_Face refFace = TopoDS::Face(ref); if (refFace.IsNull()) throw Base::Exception("Failed to extract neutral plane reference face"); BRepAdaptor_Surface adapt(refFace); if (adapt.GetType() != GeomAbs_Plane) throw Base::Exception("Neutral plane reference face must be planar"); neutralPlane = adapt.Plane(); } else if (ref.ShapeType() == TopAbs_EDGE) { if (refDirection != NULL) { // Create neutral plane through edge normal to pull direction TopoDS_Edge refEdge = TopoDS::Edge(ref); if (refEdge.IsNull()) throw Base::Exception("Failed to extract neutral plane reference edge"); BRepAdaptor_Curve c(refEdge); if (c.GetType() != GeomAbs_Line) throw Base::Exception("Neutral plane reference edge must be linear"); double a = c.Line().Angle(gp_Lin(c.Value(c.FirstParameter()), pullDirection)); if (std::fabs(a - M_PI_2) > Precision::Confusion()) throw Base::Exception("Neutral plane reference edge must be normal to pull direction"); neutralPlane = gp_Pln(c.Value(c.FirstParameter()), pullDirection); } else { throw Base::Exception("Neutral plane reference can only be an edge if pull direction is defined"); } } else { throw Base::Exception("Neutral plane reference must be a face"); } } else { throw Base::Exception("Neutral plane reference must be face of a feature or a datum plane"); } TopLoc_Location invObjLoc = this->getLocation().Inverted(); neutralPlane.Transform(invObjLoc.Transformation()); } if (refDirection == NULL) { // Choose pull direction normal to neutral plane pullDirection = neutralPlane.Axis().Direction(); } // Reversed pull direction bool reversed = Reversed.getValue(); if (reversed) angle *= -1.0; this->positionByBaseFeature(); // create an untransformed copy of the base shape Part::TopoShape baseShape(TopShape); baseShape.setTransform(Base::Matrix4D()); try { BRepOffsetAPI_DraftAngle mkDraft; // Note: // LocOpe_SplitDrafts can split a face with a wire and apply draft to both parts // Not clear though whether the face must have free boundaries // LocOpe_DPrism can create a stand-alone draft prism. The sketch can only have a single // wire, though. // BRepFeat_MakeDPrism requires a support for the operation but will probably support multiple // wires in the sketch bool success; do { success = true; mkDraft.Init(baseShape.getShape()); for (std::vector<std::string>::iterator it=SubVals.begin(); it != SubVals.end(); ++it) { TopoDS_Face face = TopoDS::Face(baseShape.getSubShape(it->c_str())); // TODO: What is the flag for? mkDraft.Add(face, pullDirection, angle, neutralPlane); if (!mkDraft.AddDone()) { // Note: the function ProblematicShape returns the face on which the error occurred // Note: mkDraft.Remove() stumbles on a bug in Draft_Modification::Remove() and is // therefore unusable. See http://forum.freecadweb.org/viewtopic.php?f=10&t=3209&start=10#p25341 // The only solution is to discard mkDraft and start over without the current face // mkDraft.Remove(face); Base::Console().Error("Adding face failed on %s. Omitted\n", it->c_str()); success = false; SubVals.erase(it); break; } } } while (!success); mkDraft.Build(); if (!mkDraft.IsDone()) return new App::DocumentObjectExecReturn("Failed to create draft"); TopoDS_Shape shape = mkDraft.Shape(); if (shape.IsNull()) return new App::DocumentObjectExecReturn("Resulting shape is null"); this->Shape.setValue(getSolid(shape)); return App::DocumentObject::StdReturn; } catch (Standard_Failure) { Handle(Standard_Failure) e = Standard_Failure::Caught(); return new App::DocumentObjectExecReturn(e->GetMessageString()); } }
bool FaceUniter::process() { if (workShell.IsNull()) return false; modifiedShapes.clear(); deletedShapes.clear(); typeObjects.push_back(&getPlaneObject()); typeObjects.push_back(&getCylinderObject()); //add more face types. ModelRefine::FaceTypeSplitter splitter; splitter.addShell(workShell); std::vector<FaceTypedBase *>::iterator typeIt; for(typeIt = typeObjects.begin(); typeIt != typeObjects.end(); ++typeIt) splitter.registerType((*typeIt)->getType()); splitter.split(); ModelRefine::FaceVectorType facesToRemove; ModelRefine::FaceVectorType facesToSew; ModelRefine::FaceAdjacencySplitter adjacencySplitter(workShell); for(typeIt = typeObjects.begin(); typeIt != typeObjects.end(); ++typeIt) { ModelRefine::FaceVectorType typedFaces = splitter.getTypedFaceVector((*typeIt)->getType()); ModelRefine::FaceEqualitySplitter equalitySplitter; equalitySplitter.split(typedFaces, *typeIt); for (std::size_t indexEquality(0); indexEquality < equalitySplitter.getGroupCount(); ++indexEquality) { adjacencySplitter.split(equalitySplitter.getGroup(indexEquality)); // std::cout << " adjacency group count: " << adjacencySplitter.getGroupCount() << std::endl; for (std::size_t adjacentIndex(0); adjacentIndex < adjacencySplitter.getGroupCount(); ++adjacentIndex) { // std::cout << " face count is: " << adjacencySplitter.getGroup(adjacentIndex).size() << std::endl; TopoDS_Face newFace = (*typeIt)->buildFace(adjacencySplitter.getGroup(adjacentIndex)); if (!newFace.IsNull()) { facesToSew.push_back(newFace); if (facesToRemove.capacity() <= facesToRemove.size() + adjacencySplitter.getGroup(adjacentIndex).size()) facesToRemove.reserve(facesToRemove.size() + adjacencySplitter.getGroup(adjacentIndex).size()); FaceVectorType temp = adjacencySplitter.getGroup(adjacentIndex); facesToRemove.insert(facesToRemove.end(), temp.begin(), temp.end()); // the first shape will be marked as modified, i.e. replaced by newFace, all others are marked as deleted // jrheinlaender: IMHO this is not correct because references to the deleted faces will be broken, whereas they should // be replaced by references to the new face. To achieve this all shapes should be marked as // modified, producing one single new face. This is the inverse behaviour to faces that are split e.g. // by a boolean cut, where one old shape is marked as modified, producing multiple new shapes if (!temp.empty()) { for (FaceVectorType::iterator f = temp.begin(); f != temp.end(); ++f) modifiedShapes.push_back(std::make_pair(*f, newFace)); } } } } } if (facesToSew.size() > 0) { modifiedSignal = true; workShell = ModelRefine::removeFaces(workShell, facesToRemove); TopExp_Explorer xp; bool emptyShell = true; for (xp.Init(workShell, TopAbs_FACE); xp.More(); xp.Next()) { emptyShell = false; break; } if (!emptyShell || facesToSew.size() > 1) { BRepBuilderAPI_Sewing sew; sew.Add(workShell); FaceVectorType::iterator sewIt; for(sewIt = facesToSew.begin(); sewIt != facesToSew.end(); ++sewIt) sew.Add(*sewIt); sew.Perform(); try { workShell = TopoDS::Shell(sew.SewedShape()); } catch (Standard_Failure) { return false; } // update the list of modifications for (std::vector<ShapePairType>::iterator it = modifiedShapes.begin(); it != modifiedShapes.end(); ++it) { if (sew.IsModified(it->second)) { it->second = sew.Modified(it->second); break; } } } else { // workShell has no more faces and we add exactly one face BRep_Builder builder; builder.MakeShell(workShell); FaceVectorType::iterator sewIt; for(sewIt = facesToSew.begin(); sewIt != facesToSew.end(); ++sewIt) builder.Add(workShell, *sewIt); } BRepLib_FuseEdges edgeFuse(workShell); // TODO: change this version after occ fix. Freecad Mantis 1450 #if OCC_VERSION_HEX <= 0x070000 TopTools_IndexedMapOfShape map; collectConicEdges(workShell, map); edgeFuse.AvoidEdges(map); #endif TopTools_DataMapOfShapeShape affectedFaces; edgeFuse.Faces(affectedFaces); TopTools_DataMapIteratorOfDataMapOfShapeShape mapIt; for (mapIt.Initialize(affectedFaces); mapIt.More(); mapIt.Next()) { ShapeFix_Face faceFixer(TopoDS::Face(mapIt.Value())); faceFixer.Perform(); } workShell = TopoDS::Shell(edgeFuse.Shape()); // update the list of modifications TopTools_DataMapOfShapeShape faceMap; edgeFuse.Faces(faceMap); for (mapIt.Initialize(faceMap); mapIt.More(); mapIt.Next()) { bool isModifiedFace = false; for (std::vector<ShapePairType>::iterator it = modifiedShapes.begin(); it != modifiedShapes.end(); ++it) { if (mapIt.Key().IsSame(it->second)) { // Note: IsEqual() for some reason does not work it->second = mapIt.Value(); isModifiedFace = true; } } if (!isModifiedFace) { // Catch faces that were not united but whose boundary was changed (probably because // several adjacent faces were united) // See https://sourceforge.net/apps/mantisbt/free-cad/view.php?id=873 modifiedShapes.push_back(std::make_pair(mapIt.Key(), mapIt.Value())); } } // Handle edges that were fused. See https://sourceforge.net/apps/mantisbt/free-cad/view.php?id=873 TopTools_DataMapOfIntegerListOfShape oldEdges; TopTools_DataMapOfIntegerShape newEdges; edgeFuse.Edges(oldEdges); edgeFuse.ResultEdges(newEdges); TopTools_DataMapIteratorOfDataMapOfIntegerListOfShape edgeMapIt; for (edgeMapIt.Initialize(oldEdges); edgeMapIt.More(); edgeMapIt.Next()) { const TopTools_ListOfShape& edges = edgeMapIt.Value(); int idx = edgeMapIt.Key(); TopTools_ListIteratorOfListOfShape edgeIt; for (edgeIt.Initialize(edges); edgeIt.More(); edgeIt.Next()) { modifiedShapes.push_back(std::make_pair(edgeIt.Value(), newEdges(idx))); } // TODO: Handle vertices that have disappeared in the fusion of the edges } } return true; }
void BuildShapeMesh(osg::Geode *geode, const TopoDS_Shape &shape, const osg::Vec4 &color, double deflection) { bool bSetNormal = true; osg::ref_ptr<deprecated_osg::Geometry> triGeom = new deprecated_osg::Geometry(); osg::ref_ptr<osg::Vec3Array> theVertices = new osg::Vec3Array(); osg::ref_ptr<osg::Vec3Array> theNormals = new osg::Vec3Array(); BRepMesh::Mesh(shape, deflection); TopExp_Explorer faceExplorer; for (faceExplorer.Init(shape, TopAbs_FACE); faceExplorer.More(); faceExplorer.Next()) { TopLoc_Location theLocation; TopoDS_Face theFace = TopoDS::Face(faceExplorer.Current()); if (theFace.IsNull()) continue; const Handle_Poly_Triangulation &theTriangulation = BRep_Tool::Triangulation(theFace, theLocation); BRepLProp_SLProps theProp(BRepAdaptor_Surface(theFace), 1, Precision::Confusion()); Standard_Integer nTriangles = theTriangulation->NbTriangles(); for (Standard_Integer i = 1; i <= nTriangles; i++) { const Poly_Triangle& theTriangle = theTriangulation->Triangles().Value(i); gp_Pnt theVertex1 = theTriangulation->Nodes().Value(theTriangle(1)); gp_Pnt theVertex2 = theTriangulation->Nodes().Value(theTriangle(2)); gp_Pnt theVertex3 = theTriangulation->Nodes().Value(theTriangle(3)); const gp_Pnt2d &theUV1 = theTriangulation->UVNodes().Value(theTriangle(1)); const gp_Pnt2d &theUV2 = theTriangulation->UVNodes().Value(theTriangle(2)); const gp_Pnt2d &theUV3 = theTriangulation->UVNodes().Value(theTriangle(3)); theVertex1.Transform(theLocation.Transformation()); theVertex2.Transform(theLocation.Transformation()); theVertex3.Transform(theLocation.Transformation()); // find the normal for the triangle mesh. gp_Vec V12(theVertex1, theVertex2); gp_Vec V13(theVertex1, theVertex3); gp_Vec theNormal = V12 ^ V13; gp_Vec theNormal1 = theNormal; gp_Vec theNormal2 = theNormal; gp_Vec theNormal3 = theNormal; if (theNormal.Magnitude() > Precision::Confusion()) { theNormal.Normalize(); theNormal1.Normalize(); theNormal2.Normalize(); theNormal3.Normalize(); } theProp.SetParameters(theUV1.X(), theUV1.Y()); if (theProp.IsNormalDefined()) { theNormal1 = theProp.Normal(); } theProp.SetParameters(theUV2.X(), theUV2.Y()); if (theProp.IsNormalDefined()) { theNormal2 = theProp.Normal(); } theProp.SetParameters(theUV3.X(), theUV3.Y()); if (theProp.IsNormalDefined()) { theNormal3 = theProp.Normal(); } if (theFace.Orientation() == TopAbs_REVERSED) { theNormal.Reverse(); theNormal1.Reverse(); theNormal2.Reverse(); theNormal3.Reverse(); } theVertices->push_back(osg::Vec3(theVertex1.X(), theVertex1.Y(), theVertex1.Z())); theVertices->push_back(osg::Vec3(theVertex2.X(), theVertex2.Y(), theVertex2.Z())); theVertices->push_back(osg::Vec3(theVertex3.X(), theVertex3.Y(), theVertex3.Z())); if (bSetNormal) { theNormals->push_back(osg::Vec3(theNormal1.X(), theNormal1.Y(), theNormal1.Z())); theNormals->push_back(osg::Vec3(theNormal2.X(), theNormal2.Y(), theNormal2.Z())); theNormals->push_back(osg::Vec3(theNormal3.X(), theNormal3.Y(), theNormal3.Z())); } else { theNormals->push_back(osg::Vec3(theNormal.X(), theNormal.Y(), theNormal.Z())); theNormals->push_back(osg::Vec3(theNormal.X(), theNormal.Y(), theNormal.Z())); theNormals->push_back(osg::Vec3(theNormal.X(), theNormal.Y(), theNormal.Z())); } } } triGeom->setVertexArray(theVertices.get()); triGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, 0, theVertices->size())); triGeom->setNormalArray(theNormals); triGeom->setNormalBinding(deprecated_osg::Geometry::BIND_PER_VERTEX); osg::ref_ptr<osg::Vec4Array> colArr = new osg::Vec4Array(); colArr->push_back(color); triGeom->setColorArray(colArr, osg::Array::BIND_OVERALL); geode->addDrawable(triGeom); }
const std::list<gp_Trsf> LinearPattern::getTransformations(const std::vector<App::DocumentObject*>) { double distance = Length.getValue(); if (distance < Precision::Confusion()) throw Base::Exception("Pattern length too small"); int occurrences = Occurrences.getValue(); if (occurrences < 2) throw Base::Exception("At least two occurrences required"); bool reversed = Reversed.getValue(); double offset = distance / (occurrences - 1); App::DocumentObject* refObject = Direction.getValue(); if (refObject == NULL) throw Base::Exception("No direction reference specified"); std::vector<std::string> subStrings = Direction.getSubValues(); if (subStrings.empty()) throw Base::Exception("No direction reference specified"); gp_Dir dir; if (refObject->getTypeId().isDerivedFrom(Part::Part2DObject::getClassTypeId())) { Part::Part2DObject* refSketch = static_cast<Part::Part2DObject*>(refObject); Base::Axis axis; if (subStrings[0] == "H_Axis") axis = refSketch->getAxis(Part::Part2DObject::H_Axis); else if (subStrings[0] == "V_Axis") axis = refSketch->getAxis(Part::Part2DObject::V_Axis); else if (subStrings[0] == "N_Axis") axis = refSketch->getAxis(Part::Part2DObject::N_Axis); else if (subStrings[0].size() > 4 && subStrings[0].substr(0,4) == "Axis") { int AxId = std::atoi(subStrings[0].substr(4,4000).c_str()); if (AxId >= 0 && AxId < refSketch->getAxisCount()) axis = refSketch->getAxis(AxId); } axis *= refSketch->Placement.getValue(); dir = gp_Dir(axis.getDirection().x, axis.getDirection().y, axis.getDirection().z); } else if (refObject->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { PartDesign::Plane* plane = static_cast<PartDesign::Plane*>(refObject); Base::Vector3d d = plane->getNormal(); dir = gp_Dir(d.x, d.y, d.z); } else if (refObject->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) { PartDesign::Line* line = static_cast<PartDesign::Line*>(refObject); Base::Vector3d d = line->getDirection(); dir = gp_Dir(d.x, d.y, d.z); } else if (refObject->getTypeId().isDerivedFrom(App::Line::getClassTypeId())) { App::Line* line = static_cast<App::Line*>(refObject); Base::Rotation rot = line->Placement.getValue().getRotation(); Base::Vector3d d(1,0,0); rot.multVec(d, d); dir = gp_Dir(d.x, d.y, d.z); } else if (refObject->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { if (subStrings[0].empty()) throw Base::Exception("No direction reference specified"); Part::Feature* refFeature = static_cast<Part::Feature*>(refObject); Part::TopoShape refShape = refFeature->Shape.getShape(); TopoDS_Shape ref = refShape.getSubShape(subStrings[0].c_str()); if (ref.ShapeType() == TopAbs_FACE) { TopoDS_Face refFace = TopoDS::Face(ref); if (refFace.IsNull()) throw Base::Exception("Failed to extract direction plane"); BRepAdaptor_Surface adapt(refFace); if (adapt.GetType() != GeomAbs_Plane) throw Base::Exception("Direction face must be planar"); dir = adapt.Plane().Axis().Direction(); } else if (ref.ShapeType() == TopAbs_EDGE) { TopoDS_Edge refEdge = TopoDS::Edge(ref); if (refEdge.IsNull()) throw Base::Exception("Failed to extract direction edge"); BRepAdaptor_Curve adapt(refEdge); if (adapt.GetType() != GeomAbs_Line) throw Base::Exception("Direction edge must be a straight line"); dir = adapt.Line().Direction(); } else { throw Base::Exception("Direction reference must be edge or face"); } } else { throw Base::Exception("Direction reference must be edge/face of a feature or a datum line/plane"); } TopLoc_Location invObjLoc = this->getLocation().Inverted(); dir.Transform(invObjLoc.Transformation()); gp_Vec direction(dir.X(), dir.Y(), dir.Z()); if (reversed) direction.Reverse(); // Note: The original feature is NOT included in the list of transformations! Therefore // we start with occurrence number 1, not number 0 std::list<gp_Trsf> transformations; gp_Trsf trans; transformations.push_back(trans); // identity transformation for (int i = 1; i < occurrences; i++) { trans.SetTranslation(direction * i * offset); transformations.push_back(trans); } return transformations; }
bool NETGENPlugin_NETGEN_2D_ONLY::Evaluate(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape, MapShapeNbElems& aResMap) { TopoDS_Face F = TopoDS::Face(aShape); if(F.IsNull()) return false; // collect info from edges int nb0d = 0, nb1d = 0; bool IsQuadratic = false; bool IsFirst = true; double fullLen = 0.0; TopTools_MapOfShape tmpMap; for (TopExp_Explorer exp(F, TopAbs_EDGE); exp.More(); exp.Next()) { TopoDS_Edge E = TopoDS::Edge(exp.Current()); if( tmpMap.Contains(E) ) continue; tmpMap.Add(E); SMESH_subMesh *aSubMesh = aMesh.GetSubMesh(exp.Current()); MapShapeNbElemsItr anIt = aResMap.find(aSubMesh); if( anIt==aResMap.end() ) { SMESH_subMesh *sm = aMesh.GetSubMesh(F); SMESH_ComputeErrorPtr& smError = sm->GetComputeError(); smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated",this)); return false; } std::vector<int> aVec = (*anIt).second; nb0d += aVec[SMDSEntity_Node]; nb1d += Max(aVec[SMDSEntity_Edge],aVec[SMDSEntity_Quad_Edge]); double aLen = SMESH_Algo::EdgeLength(E); fullLen += aLen; if(IsFirst) { IsQuadratic = (aVec[SMDSEntity_Quad_Edge] > aVec[SMDSEntity_Edge]); IsFirst = false; } } tmpMap.Clear(); // compute edge length double ELen = 0; if (_hypLengthFromEdges || (!_hypLengthFromEdges && !_hypMaxElementArea)) { if ( nb1d > 0 ) ELen = fullLen / nb1d; } if ( _hypMaxElementArea ) { double maxArea = _hypMaxElementArea->GetMaxArea(); ELen = sqrt(2. * maxArea/sqrt(3.0)); } GProp_GProps G; BRepGProp::SurfaceProperties(F,G); double anArea = G.Mass(); const int hugeNb = numeric_limits<int>::max()/10; if ( anArea / hugeNb > ELen*ELen ) { SMESH_subMesh *sm = aMesh.GetSubMesh(F); SMESH_ComputeErrorPtr& smError = sm->GetComputeError(); smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated.\nToo small element length",this)); return false; } int nbFaces = (int) ( anArea / ( ELen*ELen*sqrt(3.) / 4 ) ); int nbNodes = (int) ( ( nbFaces*3 - (nb1d-1)*2 ) / 6 + 1 ); std::vector<int> aVec(SMDSEntity_Last); for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aVec[i]=0; if( IsQuadratic ) { aVec[SMDSEntity_Node] = nbNodes; aVec[SMDSEntity_Quad_Triangle] = nbFaces; } else { aVec[SMDSEntity_Node] = nbNodes; aVec[SMDSEntity_Triangle] = nbFaces; } SMESH_subMesh *sm = aMesh.GetSubMesh(F); aResMap.insert(std::make_pair(sm,aVec)); return true; }
StdMeshers_FaceSide::StdMeshers_FaceSide(const TopoDS_Face& theFace, list<TopoDS_Edge>& theEdges, SMESH_Mesh* theMesh, const bool theIsForward, const bool theIgnoreMediumNodes) { int nbEdges = theEdges.size(); myEdge.resize( nbEdges ); myC2d.resize( nbEdges ); myFirst.resize( nbEdges ); myLast.resize( nbEdges ); myNormPar.resize( nbEdges ); myLength = 0; myNbPonits = myNbSegments = 0; myMesh = theMesh; myMissingVertexNodes = false; myIgnoreMediumNodes = theIgnoreMediumNodes; if ( nbEdges == 0 ) return; SMESHDS_Mesh* meshDS = theMesh->GetMeshDS(); vector<double> len( nbEdges ); int nbDegen = 0; list<TopoDS_Edge>::iterator edge = theEdges.begin(); for ( int index = 0; edge != theEdges.end(); ++index, ++edge ) { int i = theIsForward ? index : nbEdges - index - 1; len[i] = SMESH_Algo::EdgeLength( *edge ); if ( len[i] < DBL_MIN ) nbDegen++; myLength += len[i]; myEdge[i] = *edge; if ( !theIsForward ) myEdge[i].Reverse(); if ( theFace.IsNull() ) BRep_Tool::Range( *edge, myFirst[i], myLast[i] ); else myC2d[i] = BRep_Tool::CurveOnSurface( *edge, theFace, myFirst[i], myLast[i] ); if ( myEdge[i].Orientation() == TopAbs_REVERSED ) std::swap( myFirst[i], myLast[i] ); if ( SMESHDS_SubMesh* sm = meshDS->MeshElements( *edge )) { int nbN = sm->NbNodes(); if ( theIgnoreMediumNodes ) { SMDS_ElemIteratorPtr elemIt = sm->GetElements(); if ( elemIt->more() && elemIt->next()->IsQuadratic() ) nbN -= sm->NbElements(); } myNbPonits += nbN; myNbSegments += sm->NbElements(); } if ( SMESH_Algo::VertexNode( TopExp::FirstVertex( *edge, 1), meshDS )) myNbPonits += 1; // for the first end else myMissingVertexNodes = true; } if ( SMESH_Algo::VertexNode( TopExp::LastVertex( theEdges.back(), 1), meshDS )) myNbPonits++; // for the last end else myMissingVertexNodes = true; if ( nbEdges > 1 && myLength > DBL_MIN ) { const double degenNormLen = 1.e-5; double totLength = myLength; if ( nbDegen ) totLength += myLength * degenNormLen * nbDegen; double prevNormPar = 0; for ( int i = 0; i < nbEdges; ++i ) { if ( len[ i ] < DBL_MIN ) len[ i ] = myLength * degenNormLen; myNormPar[ i ] = prevNormPar + len[i]/totLength; prevNormPar = myNormPar[ i ]; } } myNormPar[nbEdges-1] = 1.; //dump(); }
bool SMESH_Algo::IsReversedSubMesh (const TopoDS_Face& theFace, SMESHDS_Mesh* theMeshDS) { if ( theFace.IsNull() || !theMeshDS ) return false; // find out orientation of a meshed face int faceID = theMeshDS->ShapeToIndex( theFace ); TopoDS_Shape aMeshedFace = theMeshDS->IndexToShape( faceID ); bool isReversed = ( theFace.Orientation() != aMeshedFace.Orientation() ); const SMESHDS_SubMesh * aSubMeshDSFace = theMeshDS->MeshElements( faceID ); if ( !aSubMeshDSFace ) return isReversed; // find element with node located on face and get its normal const SMDS_FacePosition* facePos = 0; int vertexID = 0; gp_Pnt nPnt[3]; gp_Vec Ne; bool normalOK = false; SMDS_ElemIteratorPtr iteratorElem = aSubMeshDSFace->GetElements(); while ( iteratorElem->more() ) // loop on elements on theFace { const SMDS_MeshElement* elem = iteratorElem->next(); if ( elem && elem->NbNodes() > 2 ) { SMDS_ElemIteratorPtr nodesIt = elem->nodesIterator(); const SMDS_FacePosition* fPos = 0; int i = 0, vID = 0; while ( nodesIt->more() ) { // loop on nodes const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode *>(nodesIt->next()); if ( i == 3 ) i = 2; nPnt[ i++ ].SetCoord( node->X(), node->Y(), node->Z() ); // check position const SMDS_PositionPtr& pos = node->GetPosition(); if ( !pos ) continue; if ( pos->GetTypeOfPosition() == SMDS_TOP_FACE ) { fPos = dynamic_cast< const SMDS_FacePosition* >( pos.get() ); } else if ( pos->GetTypeOfPosition() == SMDS_TOP_VERTEX ) { vID = pos->GetShapeId(); } } if ( fPos || ( !normalOK && vID )) { // compute normal gp_Vec v01( nPnt[0], nPnt[1] ), v02( nPnt[0], nPnt[2] ); if ( v01.SquareMagnitude() > RealSmall() && v02.SquareMagnitude() > RealSmall() ) { Ne = v01 ^ v02; normalOK = ( Ne.SquareMagnitude() > RealSmall() ); } // we need position on theFace or at least on vertex if ( normalOK ) { vertexID = vID; if ((facePos = fPos)) break; } } } } if ( !normalOK ) return isReversed; // node position on face double u,v; if ( facePos ) { u = facePos->GetUParameter(); v = facePos->GetVParameter(); } else if ( vertexID ) { TopoDS_Shape V = theMeshDS->IndexToShape( vertexID ); if ( V.IsNull() || V.ShapeType() != TopAbs_VERTEX ) return isReversed; gp_Pnt2d uv = BRep_Tool::Parameters( TopoDS::Vertex( V ), theFace ); u = uv.X(); v = uv.Y(); } else { return isReversed; } // face normal at node position TopLoc_Location loc; Handle(Geom_Surface) surf = BRep_Tool::Surface( theFace, loc ); if ( surf.IsNull() || surf->Continuity() < GeomAbs_C1 ) return isReversed; gp_Vec d1u, d1v; surf->D1( u, v, nPnt[0], d1u, d1v ); gp_Vec Nf = (d1u ^ d1v).Transformed( loc ); if ( theFace.Orientation() == TopAbs_REVERSED ) Nf.Reverse(); return Ne * Nf < 0.; }
App::DocumentObjectExecReturn *DrawViewDetail::execute(void) { if (!keepUpdated()) { return App::DocumentObject::StdReturn; } App::DocumentObject* baseObj = BaseView.getValue(); if (!baseObj) { Base::Console().Log("INFO - DVD::execute - No BaseView - creation?\n"); return DrawView::execute(); } DrawViewPart* dvp = nullptr; if (!baseObj->getTypeId().isDerivedFrom(TechDraw::DrawViewPart::getClassTypeId())) { return new App::DocumentObjectExecReturn("BaseView object is not a DrawViewPart object"); } else { dvp = static_cast<DrawViewPart*>(baseObj); } TopoDS_Shape shape = dvp->getSourceShapeFused(); if (shape.IsNull()) { return new App::DocumentObjectExecReturn("DVD - Linked shape object is invalid"); } Base::Vector3d anchor = AnchorPoint.getValue(); //this is a 2D point (in unrotated coords) Base::Vector3d dirDetail = dvp->Direction.getValue(); double shapeRotate = dvp->Rotation.getValue(); //degrees CW? if (dvp->isDerivedFrom(TechDraw::DrawProjGroupItem::getClassTypeId())) { DrawProjGroupItem* dpgi= static_cast<TechDraw::DrawProjGroupItem*>(dvp); shapeRotate += dpgi->getRotateAngle() * 180.0/M_PI; // to degrees from radians } double radius = getFudgeRadius(); double scale = getScale(); BRepBuilderAPI_Copy BuilderCopy(shape); TopoDS_Shape myShape = BuilderCopy.Shape(); //rotate the copied shape to match orientation of BaseView and center it on origin gp_Pnt gpCenter = TechDrawGeometry::findCentroid(myShape, //centre of unrotated shape dirDetail); Base::Vector3d shapeCenter = Base::Vector3d(gpCenter.X(),gpCenter.Y(),gpCenter.Z()); gp_Ax2 viewAxis = getViewAxis(shapeCenter, dirDetail, false); myShape = TechDrawGeometry::rotateShape(myShape, //rotate to match Base shape viewAxis, -shapeRotate); myShape = TechDrawGeometry::moveShape(myShape, //centre on origin -shapeCenter); gpCenter = TechDrawGeometry::findCentroid(myShape, dirDetail); shapeCenter = Base::Vector3d(gpCenter.X(),gpCenter.Y(),gpCenter.Z()); Bnd_Box bbxSource; bbxSource.SetGap(0.0); BRepBndLib::Add(myShape, bbxSource); double diag = sqrt(bbxSource.SquareExtent()); Base::Vector3d extentFar,extentNear; extentFar = shapeCenter + dirDetail * diag; extentNear = shapeCenter + dirDetail * diag * -1.0; anchor = Base::Vector3d(anchor.x,anchor.y, 0.0); viewAxis = getViewAxis(shapeCenter, dirDetail, false); //change view axis to (0,0,0) Base::Vector3d offsetCenter3D = DrawUtil::toR3(viewAxis, anchor); //displacement in R3 Base::Vector3d stdZ(0.0,0.0,1.0); if (DrawUtil::checkParallel(dirDetail,stdZ)) { extentNear = extentNear + offsetCenter3D; } else { extentNear = extentNear - offsetCenter3D; } gp_Pnt gpnt(extentNear.x,extentNear.y,extentNear.z); gp_Dir gdir(dirDetail.x,dirDetail.y,dirDetail.z); gp_Pln gpln(gpnt,gdir); double hideToolRadius = radius * 1.0; BRepBuilderAPI_MakeFace mkFace(gpln, -hideToolRadius,hideToolRadius,-hideToolRadius,hideToolRadius); TopoDS_Face aProjFace = mkFace.Face(); if(aProjFace.IsNull()) { return new App::DocumentObjectExecReturn("DrawViewDetail - Projected face is NULL"); } Base::Vector3d extrudeVec = dirDetail* (extentFar-extentNear).Length(); gp_Vec extrudeDir(extrudeVec.x,extrudeVec.y,extrudeVec.z); TopoDS_Shape tool = BRepPrimAPI_MakePrism(aProjFace, extrudeDir, false, true).Shape(); BRepAlgoAPI_Common mkCommon(myShape,tool); if (!mkCommon.IsDone()) { Base::Console().Log("DVD::execute - mkCommon not done\n"); return new App::DocumentObjectExecReturn("DVD::execute - mkCommon not done"); } if (mkCommon.Shape().IsNull()) { Base::Console().Log("DVD::execute - mkCommon.Shape is Null\n"); return new App::DocumentObjectExecReturn("DVD::execute - mkCommon.Shape is Null"); } //Did we get a solid? TopExp_Explorer xp; xp.Init(mkCommon.Shape(),TopAbs_SOLID); if (!(xp.More() == Standard_True)) { Base::Console().Warning("DVD::execute - mkCommon.Shape is not a solid!\n"); } TopoDS_Shape detail = mkCommon.Shape(); Bnd_Box testBox; testBox.SetGap(0.0); BRepBndLib::Add(detail, testBox); if (testBox.IsVoid()) { Base::Console().Message("DrawViewDetail - detail area contains no geometry\n"); return new App::DocumentObjectExecReturn("DVDetail - detail area contains no geometry"); } //for debugging show compound instead of common // BRep_Builder builder; // TopoDS_Compound Comp; // builder.MakeCompound(Comp); // builder.Add(Comp, tool); // builder.Add(Comp, myShape); gp_Pnt inputCenter; try { inputCenter = TechDrawGeometry::findCentroid(tool, Direction.getValue()); TopoDS_Shape mirroredShape = TechDrawGeometry::mirrorShape(detail, inputCenter, scale); viewAxis = getViewAxis(Base::Vector3d(inputCenter.X(),inputCenter.Y(),inputCenter.Z()),Direction.getValue()); if (!DrawUtil::fpCompare(Rotation.getValue(),0.0)) { mirroredShape = TechDrawGeometry::rotateShape(mirroredShape, viewAxis, Rotation.getValue()); //degrees cw? } geometryObject = buildGeometryObject(mirroredShape,viewAxis); geometryObject->pruneVertexGeom(Base::Vector3d(0.0,0.0,0.0),Radius.getValue() * scale); //remove vertices beyond clipradius #if MOD_TECHDRAW_HANDLE_FACES if (handleFaces()) { try { extractFaces(); } catch (Standard_Failure& e4) { Base::Console().Log("LOG - DVD::execute - extractFaces failed for %s - %s **\n",getNameInDocument(),e4.GetMessageString()); return new App::DocumentObjectExecReturn(e4.GetMessageString()); } } #endif //#if MOD_TECHDRAW_HANDLE_FACES } catch (Standard_Failure& e1) { Base::Console().Message("LOG - DVD::execute - failed to create detail %s - %s **\n",getNameInDocument(),e1.GetMessageString()); return new App::DocumentObjectExecReturn(e1.GetMessageString()); } requestPaint(); dvp->requestPaint(); return App::DocumentObject::StdReturn; }