bool Edgecluster::IsValidEdge(const TopoDS_Edge& edge) { if ( edge.IsNull() ) return false; if ( BRep_Tool::Degenerated(edge) ) return false; BRepAdaptor_Curve bac(edge); Standard_Real fparam = bac.FirstParameter(); Standard_Real lparam = bac.LastParameter(); gp_Pnt fpoint = bac.Value(fparam); gp_Pnt lpoint = bac.Value(lparam); //do not test the distance first last in case of a full circle edge (fpoint == lastpoint) //if ( fpoint.IsEqual(lpoint,1e-5 ) ) // return false; gp_Pnt mpoint = bac.Value((fparam+lparam)*0.5); Standard_Real dist = mpoint.Distance(lpoint); if ( dist <= 1e-5 ) return false; dist = mpoint.Distance(fpoint); if ( dist <= 1e-5 ) return false; return true; }
bool SMESH_Algo::GetSortedNodesOnEdge(const SMESHDS_Mesh* theMesh, const TopoDS_Edge& theEdge, const bool ignoreMediumNodes, map< double, const SMDS_MeshNode* > & theNodes) { theNodes.clear(); if ( !theMesh || theEdge.IsNull() ) return false; SMESHDS_SubMesh * eSubMesh = theMesh->MeshElements( theEdge ); if ( !eSubMesh || !eSubMesh->GetElements()->more() ) return false; // edge is not meshed int nbNodes = 0; set < double > paramSet; if ( eSubMesh ) { // loop on nodes of an edge: sort them by param on edge SMDS_NodeIteratorPtr nIt = eSubMesh->GetNodes(); while ( nIt->more() ) { const SMDS_MeshNode* node = nIt->next(); if ( ignoreMediumNodes ) { SMDS_ElemIteratorPtr elemIt = node->GetInverseElementIterator(); if ( elemIt->more() && elemIt->next()->IsMediumNode( node )) continue; } const SMDS_PositionPtr& pos = node->GetPosition(); if ( pos->GetTypeOfPosition() != SMDS_TOP_EDGE ) return false; const SMDS_EdgePosition* epos = static_cast<const SMDS_EdgePosition*>(node->GetPosition().get()); theNodes.insert( make_pair( epos->GetUParameter(), node )); ++nbNodes; } } // add vertex nodes TopoDS_Vertex v1, v2; TopExp::Vertices(theEdge, v1, v2); const SMDS_MeshNode* n1 = VertexNode( v1, (SMESHDS_Mesh*) theMesh ); const SMDS_MeshNode* n2 = VertexNode( v2, (SMESHDS_Mesh*) theMesh ); Standard_Real f, l; BRep_Tool::Range(theEdge, f, l); if ( v1.Orientation() != TopAbs_FORWARD ) std::swap( f, l ); if ( n1 && ++nbNodes ) theNodes.insert( make_pair( f, n1 )); if ( n2 && ++nbNodes ) theNodes.insert( make_pair( l, n2 )); return theNodes.size() == nbNodes; }
bool SMESH_Algo::GetNodeParamOnEdge(const SMESHDS_Mesh* theMesh, const TopoDS_Edge& theEdge, vector< double > & theParams) { theParams.clear(); if ( !theMesh || theEdge.IsNull() ) return false; SMESHDS_SubMesh * eSubMesh = theMesh->MeshElements( theEdge ); if ( !eSubMesh || !eSubMesh->GetElements()->more() ) return false; // edge is not meshed //int nbEdgeNodes = 0; set < double > paramSet; if ( eSubMesh ) { // loop on nodes of an edge: sort them by param on edge SMDS_NodeIteratorPtr nIt = eSubMesh->GetNodes(); while ( nIt->more() ) { const SMDS_MeshNode* node = nIt->next(); const SMDS_PositionPtr& pos = node->GetPosition(); if ( pos->GetTypeOfPosition() != SMDS_TOP_EDGE ) return false; const SMDS_EdgePosition* epos = static_cast<const SMDS_EdgePosition*>(node->GetPosition().get()); if ( !paramSet.insert( epos->GetUParameter() ).second ) return false; // equal parameters } } // add vertex nodes params TopoDS_Vertex V1,V2; TopExp::Vertices( theEdge, V1, V2); if ( VertexNode( V1, theMesh ) && !paramSet.insert( BRep_Tool::Parameter(V1,theEdge) ).second ) return false; // there are equal parameters if ( VertexNode( V2, theMesh ) && !paramSet.insert( BRep_Tool::Parameter(V2,theEdge) ).second ) return false; // there are equal parameters // fill the vector theParams.resize( paramSet.size() ); set < double >::iterator par = paramSet.begin(); vector< double >::iterator vecPar = theParams.begin(); for ( ; par != paramSet.end(); ++par, ++vecPar ) *vecPar = *par; return theParams.size() > 1; }
void Edgecluster::Perform(const TopoDS_Edge& edge) { if ( edge.IsNull() ) return; TopoDS_Vertex V1,V2; TopExp::Vertices(edge,V1,V2); gp_Pnt P1 = BRep_Tool::Pnt(V1); gp_Pnt P2 = BRep_Tool::Pnt(V2); tEdgeVector emptyList; std::pair<tMapPntEdge::iterator,bool> iter = m_vertices.insert(tMapPntEdgePair(P1,emptyList)); iter.first->second.push_back(edge); iter = m_vertices.insert(tMapPntEdgePair(P2,emptyList)); iter.first->second.push_back(edge); }
StdMeshers_FaceSide * StdMeshers_CompositeSegment_1D::GetFaceSide(SMESH_Mesh& aMesh, const TopoDS_Edge& anEdge, const TopoDS_Face& aFace, const bool ignoreMeshed) { list< TopoDS_Edge > edges; edges.push_back( anEdge ); list <const SMESHDS_Hypothesis *> hypList; SMESH_Algo* theAlgo = aMesh.GetGen()->GetAlgo( aMesh, anEdge ); if ( theAlgo ) hypList = theAlgo->GetUsedHypothesis(aMesh, anEdge, false); for ( int forward = 0; forward < 2; ++forward ) { TopoDS_Edge eNext = nextC1Edge( anEdge, aMesh, forward ); while ( !eNext.IsNull() ) { if ( ignoreMeshed ) { // eNext must not have computed mesh if ( SMESHDS_SubMesh* sm = aMesh.GetMeshDS()->MeshElements(eNext) ) if ( sm->NbNodes() || sm->NbElements() ) break; } // eNext must have same hypotheses SMESH_Algo* algo = aMesh.GetGen()->GetAlgo( aMesh, eNext ); if ( !algo || string(theAlgo->GetName()) != algo->GetName() || hypList != algo->GetUsedHypothesis(aMesh, eNext, false)) break; if ( forward ) edges.push_back( eNext ); else edges.push_front( eNext ); eNext = nextC1Edge( eNext, aMesh, forward ); } } return new StdMeshers_FaceSide( aFace, edges, &aMesh, true, false ); }
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()); } }
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; }
void ProfileBased::getAxis(const App::DocumentObject *pcReferenceAxis, const std::vector<std::string> &subReferenceAxis, Base::Vector3d& base, Base::Vector3d& dir) { dir = Base::Vector3d(0,0,0); // If unchanged signals that no valid axis was found if (pcReferenceAxis == NULL) return; App::DocumentObject* profile = Profile.getValue(); gp_Pln sketchplane; if (profile->getTypeId().isDerivedFrom(Part::Part2DObject::getClassTypeId())) { Part::Part2DObject* sketch = getVerifiedSketch(); Base::Placement SketchPlm = sketch->Placement.getValue(); Base::Vector3d SketchVector = Base::Vector3d(0, 0, 1); Base::Rotation SketchOrientation = SketchPlm.getRotation(); SketchOrientation.multVec(SketchVector, SketchVector); Base::Vector3d SketchPos = SketchPlm.getPosition(); sketchplane = gp_Pln(gp_Pnt(SketchPos.x, SketchPos.y, SketchPos.z), gp_Dir(SketchVector.x, SketchVector.y, SketchVector.z)); if (pcReferenceAxis == profile) { bool hasValidAxis = false; Base::Axis axis; if (subReferenceAxis[0] == "V_Axis") { hasValidAxis = true; axis = sketch->getAxis(Part::Part2DObject::V_Axis); } else if (subReferenceAxis[0] == "H_Axis") { hasValidAxis = true; axis = sketch->getAxis(Part::Part2DObject::H_Axis); } else if (subReferenceAxis[0].size() > 4 && subReferenceAxis[0].substr(0, 4) == "Axis") { int AxId = std::atoi(subReferenceAxis[0].substr(4, 4000).c_str()); if (AxId >= 0 && AxId < sketch->getAxisCount()) { hasValidAxis = true; axis = sketch->getAxis(AxId); } } if (hasValidAxis) { axis *= SketchPlm; base = axis.getBase(); dir = axis.getDirection(); return; } //else - an edge of the sketch was selected as an axis } } else if (profile->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { Base::Placement SketchPlm = getVerifiedObject()->Placement.getValue(); Base::Vector3d SketchVector = getProfileNormal(); Base::Vector3d SketchPos = SketchPlm.getPosition(); sketchplane = gp_Pln(gp_Pnt(SketchPos.x, SketchPos.y, SketchPos.z), gp_Dir(SketchVector.x, SketchVector.y, SketchVector.z)); } // get reference axis if (pcReferenceAxis->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) { const PartDesign::Line* line = static_cast<const PartDesign::Line*>(pcReferenceAxis); base = line->getBasePoint(); dir = line->getDirection(); // Check that axis is perpendicular with sketch plane! if (sketchplane.Axis().Direction().IsParallel(gp_Dir(dir.x, dir.y, dir.z), Precision::Angular())) throw Base::ValueError("Rotation axis must not be perpendicular with the sketch plane"); return; } if (pcReferenceAxis->getTypeId().isDerivedFrom(App::Line::getClassTypeId())) { const App::Line* line = static_cast<const App::Line*>(pcReferenceAxis); base = Base::Vector3d(0,0,0); line->Placement.getValue().multVec(Base::Vector3d (1,0,0), dir); // Check that axis is perpendicular with sketch plane! if (sketchplane.Axis().Direction().IsParallel(gp_Dir(dir.x, dir.y, dir.z), Precision::Angular())) throw Base::ValueError("Rotation axis must not be perpendicular with the sketch plane"); return; } if (pcReferenceAxis->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { if (subReferenceAxis.empty()) throw Base::ValueError("No rotation axis reference specified"); const Part::Feature* refFeature = static_cast<const Part::Feature*>(pcReferenceAxis); Part::TopoShape refShape = refFeature->Shape.getShape(); TopoDS_Shape ref = refShape.getSubShape(subReferenceAxis[0].c_str()); if (ref.ShapeType() == TopAbs_EDGE) { TopoDS_Edge refEdge = TopoDS::Edge(ref); if (refEdge.IsNull()) throw Base::ValueError("Failed to extract rotation edge"); BRepAdaptor_Curve adapt(refEdge); if (adapt.GetType() != GeomAbs_Line) throw Base::TypeError("Rotation edge must be a straight line"); gp_Pnt b = adapt.Line().Location(); base = Base::Vector3d(b.X(), b.Y(), b.Z()); gp_Dir d = adapt.Line().Direction(); dir = Base::Vector3d(d.X(), d.Y(), d.Z()); // Check that axis is co-planar with sketch plane! // Check that axis is perpendicular with sketch plane! if (sketchplane.Axis().Direction().IsParallel(d, Precision::Angular())) throw Base::ValueError("Rotation axis must not be perpendicular with the sketch plane"); return; } else { throw Base::TypeError("Rotation reference must be an edge"); } } throw Base::TypeError("Rotation axis reference is invalid"); }
//============================================================================= 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(); }
const std::list<gp_Trsf> PolarPattern::getTransformations(const std::vector<App::DocumentObject*>) { float angle = Angle.getValue(); if (angle < Precision::Confusion()) throw Base::Exception("Pattern angle too small"); int occurrences = Occurrences.getValue(); if (occurrences < 2) throw Base::Exception("At least two occurrences required"); bool reversed = Reversed.getValue(); double offset; if (std::abs(angle - 360.0) < Precision::Confusion()) offset = Base::toRadians<double>(angle) / occurrences; // Because e.g. two occurrences in 360 degrees need to be 180 degrees apart else offset = Base::toRadians<double>(angle) / (occurrences - 1); App::DocumentObject* refObject = Axis.getValue(); if (refObject == NULL) throw Base::Exception("No axis reference specified"); if (!refObject->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) throw Base::Exception("Axis reference must be edge of a feature"); std::vector<std::string> subStrings = Axis.getSubValues(); if (subStrings.empty() || subStrings[0].empty()) throw Base::Exception("No axis reference specified"); gp_Pnt axbase; gp_Dir axdir; 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(); axbase = gp_Pnt(axis.getBase().x, axis.getBase().y, axis.getBase().z); axdir = gp_Dir(axis.getDirection().x, axis.getDirection().y, axis.getDirection().z); } else { 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_EDGE) { TopoDS_Edge refEdge = TopoDS::Edge(ref); if (refEdge.IsNull()) throw Base::Exception("Failed to extract axis edge"); BRepAdaptor_Curve adapt(refEdge); if (adapt.GetType() != GeomAbs_Line) throw Base::Exception("Axis edge must be a straight line"); axbase = adapt.Value(adapt.FirstParameter()); axdir = adapt.Line().Direction(); } else { throw Base::Exception("Axis reference must be an edge"); } } TopLoc_Location invObjLoc = this->getLocation().Inverted(); axbase.Transform(invObjLoc.Transformation()); axdir.Transform(invObjLoc.Transformation()); gp_Ax2 axis(axbase, axdir); if (reversed) axis.SetDirection(axis.Direction().Reversed()); // 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.SetRotation(axis.Axis(), i * offset); transformations.push_back(trans); } return transformations; }
//======================================================================= //function : Execute //purpose : //======================================================================= Standard_Integer GEOMImpl_Fillet1dDriver::Execute(TFunction_Logbook& log) const { if (Label().IsNull()) return 0; Handle(GEOM_Function) aFunction = GEOM_Function::GetFunction(Label()); GEOMImpl_IFillet1d aCI (aFunction); Handle(GEOM_Function) aRefShape = aCI.GetShape(); TopoDS_Shape aShape = aRefShape->GetValue(); if (aShape.IsNull()) return 0; if (aShape.ShapeType() != TopAbs_WIRE) Standard_ConstructionError::Raise("Wrong arguments: polyline as wire must be given"); TopoDS_Wire aWire = TopoDS::Wire(aShape); double rad = aCI.GetR(); if ( rad < Precision::Confusion()) return 0; // collect vertices for make fillet TopTools_ListOfShape aVertexList; TopTools_MapOfShape mapShape; int aLen = aCI.GetLength(); if ( aLen > 0 ) { for (int ind = 1; ind <= aLen; ind++) { TopoDS_Shape aShapeVertex; if (GEOMImpl_ILocalOperations::GetSubShape (aWire, aCI.GetVertex(ind), aShapeVertex)) if (mapShape.Add(aShapeVertex)) aVertexList.Append( aShapeVertex ); } } else { // get all vertices from wire TopExp_Explorer anExp( aWire, TopAbs_VERTEX ); for ( ; anExp.More(); anExp.Next() ) { if (mapShape.Add(anExp.Current())) aVertexList.Append( anExp.Current() ); } } if (aVertexList.IsEmpty()) Standard_ConstructionError::Raise("Invalid input no vertices to make fillet"); //INFO: this algorithm implemented in assumption that user can select both // vertices of some edges to make fillet. In this case we should remember // already modified initial edges to take care in next fillet step TopTools_DataMapOfShapeShape anEdgeToEdgeMap; //iterates on vertices, and make fillet on each couple of edges //collect result fillet edges in list TopTools_ListOfShape aListOfNewEdge; // remember relation between initial and modified map TopTools_IndexedDataMapOfShapeListOfShape aMapVToEdges; TopExp::MapShapesAndAncestors( aWire, TopAbs_VERTEX, TopAbs_EDGE, aMapVToEdges ); TopTools_ListIteratorOfListOfShape anIt( aVertexList ); for ( ; anIt.More(); anIt.Next() ) { TopoDS_Vertex aV = TopoDS::Vertex( anIt.Value() ); if ( aV.IsNull() || !aMapVToEdges.Contains( aV ) ) continue; const TopTools_ListOfShape& aVertexEdges = aMapVToEdges.FindFromKey( aV ); if ( aVertexEdges.Extent() != 2 ) continue; // no input data to make fillet TopoDS_Edge anEdge1 = TopoDS::Edge( aVertexEdges.First() ); TopoDS_Edge anEdge2 = TopoDS::Edge( aVertexEdges.Last() ); // check if initial edges already modified in previous fillet operation if ( anEdgeToEdgeMap.IsBound( anEdge1 ) ) anEdge1 = TopoDS::Edge(anEdgeToEdgeMap.Find( anEdge1 )); if ( anEdgeToEdgeMap.IsBound( anEdge2 ) ) anEdge2 = TopoDS::Edge(anEdgeToEdgeMap.Find( anEdge2 )); if ( anEdge1.IsNull() || anEdge2.IsNull() || anEdge1.IsSame( anEdge2 ) ) continue; //no input data to make fillet // create plane on 2 edges gp_Pln aPlane; if ( !takePlane(anEdge1, anEdge2, aV, aPlane) ) continue; // seems edges does not belong to same plane or parallel (fillet can not be build) GEOMImpl_Fillet1d aFilletAlgo(anEdge1, anEdge2, aPlane); if ( !aFilletAlgo.Perform(rad) ) continue; // can not create fillet with given radius // take fillet result in given vertex TopoDS_Edge aModifE1, aModifE2; TopoDS_Edge aNewE = aFilletAlgo.Result(BRep_Tool::Pnt(aV), aModifE1, aModifE2); if (aNewE.IsNull()) continue; // no result found // add new created edges and take modified edges aListOfNewEdge.Append( aNewE ); // check if face edges modified, // if yes, than map to original edges (from vertex-edges list), because edges can be modified before if (aModifE1.IsNull() || !anEdge1.IsSame( aModifE1 )) addEdgeRelation( anEdgeToEdgeMap, TopoDS::Edge(aVertexEdges.First()), aModifE1 ); if (aModifE2.IsNull() || !anEdge2.IsSame( aModifE2 )) addEdgeRelation( anEdgeToEdgeMap, TopoDS::Edge(aVertexEdges.Last()), aModifE2 ); } if ( anEdgeToEdgeMap.IsEmpty() && aListOfNewEdge.IsEmpty() ) { StdFail_NotDone::Raise("1D Fillet can't be computed on the given shape with the given radius"); return 0; } // create new wire instead of original for ( TopExp_Explorer anExp( aWire, TopAbs_EDGE ); anExp.More(); anExp.Next() ) { TopoDS_Shape anEdge = anExp.Current(); if ( !anEdgeToEdgeMap.IsBound( anEdge ) ) aListOfNewEdge.Append( anEdge ); else if (!anEdgeToEdgeMap.Find( anEdge ).IsNull()) aListOfNewEdge.Append( anEdgeToEdgeMap.Find( anEdge ) ); } GEOMImpl_IShapesOperations::SortShapes( aListOfNewEdge ); BRepBuilderAPI_MakeWire aWireTool; aWireTool.Add( aListOfNewEdge ); aWireTool.Build(); if (!aWireTool.IsDone()) return 0; aWire = aWireTool.Wire(); aFunction->SetValue(aWire); log.SetTouched(Label()); return 1; }
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; }
void Tesselate_Presentation::tesselateShape(const TopoDS_Shape& aShape) { // setResultTitle("Tesselate shape"); TCollection_AsciiString aText = ( "/////////////////////////////////////////////////////////////////" EOL "// Tesselate shape." EOL "/////////////////////////////////////////////////////////////////" EOL EOL ) ; Standard_Real aDeflection = DATA[myIndex][0]; Standard_Integer aNumOfFace = (Standard_Integer)DATA[myIndex][1]; Standard_Integer aNumOfEdge = (Standard_Integer)DATA[myIndex][2]; aText += "Standard_Real aDeflection;" EOL "// aDeflection = ... ;" EOL EOL "// removes all the triangulations of the faces ," EOL "//and all the polygons on the triangulations of the edges:" EOL "BRepTools::Clean(aShape);" EOL EOL "// adds a triangulation of the shape aShape with the deflection aDeflection:" EOL "BRepMesh::Mesh(aShape,aDeflection);" EOL EOL "TopExp_Explorer aExpFace,aExpEdge;" EOL "for(aExpFace.Init(aShape,TopAbs_FACE);aExpFace.More();aExpFace.Next())" EOL "{ " EOL " TopoDS_Face aFace = TopoDS::Face(aExpFace.Current());" EOL " TopLoc_Location aLocation;" EOL EOL " // takes the triangulation of the face aFace:" EOL " Handle_Poly_Triangulation aTr = BRep_Tool::Triangulation(aFace,aLocation);" EOL EOL " if(!aTr.IsNull()) // if this triangulation is not NULL" EOL " { " EOL " // takes the array of nodes for this triangulation:" EOL " const TColgp_Array1OfPnt& aNodes = aTr->Nodes();" EOL " // takes the array of triangles for this triangulation:" EOL " const Poly_Array1OfTriangle& triangles = aTr->Triangles();" EOL EOL " // create array of node points in absolute coordinate system" EOL " TColgp_Array1OfPnt aPoints(1, aNodes.Length());" EOL " for( Standard_Integer i = 1; i < aNodes.Length()+1; i++)" EOL " aPoints(i) = aNodes(i).Transformed(aLocation);" EOL EOL " // Takes the node points of each triangle of this triangulation." EOL " // takes a number of triangles:" EOL " Standard_Integer nnn = aTr->NbTriangles();" EOL " Standard_Integer nt,n1,n2,n3;" EOL " for( nt = 1 ; nt < nnn+1 ; nt++)" EOL " {" EOL " // takes the node indices of each triangle in n1,n2,n3:" EOL " triangles(nt).Get(n1,n2,n3);" EOL " // takes the node points:" EOL " gp_Pnt aPnt1 = aPoints(n1);" EOL " gp_Pnt aPnt2 = aPoints(n2);" EOL " gp_Pnt aPnt3 = aPoints(n3);" EOL " } " EOL EOL " // Takes the polygon associated to an edge." EOL " aExpEdge.Init(aFace,TopAbs_EDGE);" EOL " TopoDS_Edge aEdge;" EOL " // for example,working with the first edge:" EOL " if(aExpEdge.More())" EOL " aEdge = TopoDS::Edge(aExpEdge.Current());" EOL EOL " if(!aEdge.IsNull()) // if this edge is not NULL" EOL " {" EOL " // takes the polygon associated to the edge aEdge:" EOL " Handle_Poly_PolygonOnTriangulation aPol = " EOL " BRep_Tool::PolygonOnTriangulation(aEdge,aTr,aEdge.Location());" EOL EOL " if(!aPol.IsNull()) // if this polygon is not NULL" EOL " // takes the array of nodes for this polygon" EOL " // (indexes in the array of nodes for triangulation of theFace):" EOL " const TColStd_Array1OfInteger& aNodesOfPol = aPol->Nodes();" EOL " }" EOL " }" EOL "}" EOL EOL "//==================================================" EOL EOL ; aText += " Result with deflection = "; aText += TCollection_AsciiString(aDeflection); aText += " :" EOL; GetDocument()->PocessTextInDialog("Compute the triangulation on a shape", aText); // setResultText(aText.ToCString()); //========================================================================== BRepTools::Clean(aShape); BRepMesh::Mesh(aShape,aDeflection); BRep_Builder aBuilder,aBuild1,aBuild2; TopoDS_Compound aCompound,aComp1,aComp2; aBuilder.MakeCompound(aCompound); aBuild1.MakeCompound(aComp1); aBuild2.MakeCompound(aComp2); TopTools_SequenceOfShape aVertices; Standard_Integer aCount = 0; Standard_Integer aNumOfNodes = 0; Standard_Integer aNumOfTriangles = 0; Handle_AIS_InteractiveObject aShowEdge,aShowFace,aShowShape; TopExp_Explorer aExpFace,aExpEdge; for(aExpFace.Init(aShape,TopAbs_FACE);aExpFace.More();aExpFace.Next()) { aCount++; TopoDS_Face aFace = TopoDS::Face(aExpFace.Current()); TopLoc_Location aLocation; Handle_Poly_Triangulation aTr = BRep_Tool::Triangulation(aFace,aLocation); if(!aTr.IsNull()) { const TColgp_Array1OfPnt& aNodes = aTr->Nodes(); aNumOfNodes += aTr->NbNodes(); Standard_Integer aLower = aNodes.Lower(); Standard_Integer anUpper = aNodes.Upper(); const Poly_Array1OfTriangle& triangles = aTr->Triangles(); aNumOfTriangles += aTr->NbTriangles(); if(aCount == aNumOfFace) { Standard_Integer aNbOfNodesOfFace = aTr->NbNodes(); Standard_Integer aNbOfTrianglesOfFace = aTr->NbTriangles(); aExpEdge.Init(aFace,TopAbs_EDGE); TopoDS_Edge aEdge; for( Standard_Integer i = 0; aExpEdge.More() && i < aNumOfEdge ; aExpEdge.Next(), i++) aEdge = TopoDS::Edge(aExpEdge.Current()); if(!aEdge.IsNull()) { Handle_Poly_PolygonOnTriangulation aPol = BRep_Tool::PolygonOnTriangulation(aEdge,aTr,aEdge.Location()); if(!aPol.IsNull()) { const TColStd_Array1OfInteger& aNodesOfPol = aPol->Nodes(); Standard_Integer aNbOfNodesOfEdge = aPol->NbNodes(); aText += "Number of nodes of the edge = "; aText += TCollection_AsciiString(aNbOfNodesOfEdge) + EOL; aText += "Number of nodes of the face = "; aText += TCollection_AsciiString(aNbOfNodesOfFace) + EOL; aText += "Number of triangles of the face = "; aText += TCollection_AsciiString(aNbOfTrianglesOfFace) + EOL; GetDocument()->PocessTextInDialog("Compute the triangulation on a shape", aText); // setResultText(aText.ToCString()); Standard_Integer aLower = aNodesOfPol.Lower(), anUpper = aNodesOfPol.Upper(); for( int i = aLower; i < anUpper ; i++) { gp_Pnt aPnt1 = aNodes(aNodesOfPol(i)).Transformed(aLocation); gp_Pnt aPnt2 = aNodes(aNodesOfPol(i+1)).Transformed(aLocation); TopoDS_Vertex aVertex1 = BRepBuilderAPI_MakeVertex (aPnt1); TopoDS_Vertex aVertex2 = BRepBuilderAPI_MakeVertex (aPnt2); if(!aVertex1.IsNull() && !aVertex2.IsNull() && // if vertices are "alive" !BRep_Tool::Pnt(aVertex1).IsEqual( BRep_Tool::Pnt(aVertex2),Precision::Confusion())) // if they are different { aEdge = BRepBuilderAPI_MakeEdge (aVertex1,aVertex2); aBuild2.Add(aComp2,aVertex1); if(!aEdge.IsNull()) aBuild2.Add(aComp2,aEdge); if(i == anUpper-1) aBuild2.Add(aComp2,aVertex2); } } getAISContext()->EraseAll(); aShowShape = drawShape(aShape); if(WAIT_A_SECOND) return; aShowEdge = drawShape(aComp2,Quantity_NOC_GREEN); getAISContext()->Erase(aShowShape); if(WAIT_A_SECOND) return; } } } TopTools_DataMapOfIntegerShape aEdges; TopTools_SequenceOfShape aVertices; for( Standard_Integer i = 1; i < aNodes.Length()+1; i++) { gp_Pnt aPnt = aNodes(i).Transformed(aLocation); TopoDS_Vertex aVertex = BRepBuilderAPI_MakeVertex(aPnt); if(!aVertex.IsNull()) { aBuilder.Add(aCompound,aVertex); if(aCount == aNumOfFace ) aBuild1.Add(aComp1,aVertex); aVertices.Append(aVertex); } } Standard_Integer nnn = aTr->NbTriangles(); Standard_Integer nt,n1,n2,n3; for( nt = 1 ; nt < nnn+1 ; nt++) { triangles(nt).Get(n1,n2,n3); Standard_Integer key[3]; TopoDS_Vertex aV1,aV2; key[0] = _key(n1, n2); if(!aEdges.IsBound(key[0])) { aV1 = TopoDS::Vertex(aVertices(n1)); aV2 = TopoDS::Vertex(aVertices(n2)); if(!aV1.IsNull() && !aV2.IsNull() && !BRep_Tool::Pnt(aV1).IsEqual(BRep_Tool::Pnt(aV2),Precision::Confusion())) { TopoDS_Edge aEdge = BRepBuilderAPI_MakeEdge (aV1,aV2); if(!aEdge.IsNull()) { aEdges.Bind(key[0], aEdge); aBuilder.Add(aCompound,aEdges(key[0])); if(aCount == aNumOfFace) aBuild1.Add(aComp1,aEdges(key[0])); } } } key[1] = _key(n2,n3); if(!aEdges.IsBound(key[1])) { aV1 = TopoDS::Vertex(aVertices(n2)); aV2 = TopoDS::Vertex(aVertices(n3)); if(!aV1.IsNull() && !aV2.IsNull() && !BRep_Tool::Pnt(aV1).IsEqual(BRep_Tool::Pnt(aV2),Precision::Confusion())) { TopoDS_Edge aEdge = BRepBuilderAPI_MakeEdge (aV1,aV2); if(!aEdge.IsNull()) { aEdges.Bind(key[1],aEdge); aBuilder.Add(aCompound,aEdges(key[1])); if(aCount == aNumOfFace) aBuild1.Add(aComp1,aEdges(key[1])); } } } key[2] = _key(n3,n1); if(!aEdges.IsBound(key[2])) { aV1 = TopoDS::Vertex(aVertices(n3)); aV2 = TopoDS::Vertex(aVertices(n1)); if(!aV1.IsNull() && !aV2.IsNull() && !BRep_Tool::Pnt(aV1).IsEqual(BRep_Tool::Pnt(aV2),Precision::Confusion())) { TopoDS_Edge aEdge = BRepBuilderAPI_MakeEdge (aV1,aV2); if(!aEdge.IsNull()) { aEdges.Bind(key[2],aEdge); aBuilder.Add(aCompound,aEdges(key[2])); if(aCount == aNumOfFace) aBuild1.Add(aComp1,aEdges(key[2])); } } } } if(aCount == aNumOfFace) { aShowFace = drawShape(aComp1,Quantity_NOC_GREEN); getAISContext()->Erase(aShowEdge); } } else { aText += "Can't compute a triangulation on face "; aText += TCollection_AsciiString(aCount) + EOL; GetDocument()->PocessTextInDialog("Compute the triangulation on a shape", aText); // setResultText(aText.ToCString()); } } aText += "Number of nodes of the shape = "; aText += TCollection_AsciiString(aNumOfNodes) + EOL; aText += "Number of triangles of the shape = "; aText += TCollection_AsciiString(aNumOfTriangles) + EOL EOL; GetDocument()->PocessTextInDialog("Compute the triangulation on a shape", aText); // setResultText(aText.ToCString()); if(WAIT_A_SECOND) return; drawShape(aCompound,Quantity_NOC_GREEN); getAISContext()->Erase(aShowFace); }