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"); }
App::DocumentObjectExecReturn *Thickness::execute(void) { // Base shape Part::TopoShape TopShape; try { TopShape = getBaseShape(); } catch (Base::Exception& e) { return new App::DocumentObjectExecReturn(e.what()); } TopTools_ListOfShape closingFaces; const std::vector<std::string>& subStrings = Base.getSubValues(); for (std::vector<std::string>::const_iterator it = subStrings.begin(); it != subStrings.end(); ++it) { TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(it->c_str())); closingFaces.Append(face); } bool reversed = Reversed.getValue(); double thickness = (reversed ? -1. : 1. )*Value.getValue(); double tol = Precision::Confusion(); short mode = (short)Mode.getValue(); short join = (short)Join.getValue(); //we do not offer tangent join type if(join == 1) join = 2; if (fabs(thickness) > 2*tol) this->Shape.setValue(getSolid(TopShape.makeThickSolid(closingFaces, thickness, tol, false, false, mode, join))); else this->Shape.setValue(getSolid(TopShape.getShape())); return App::DocumentObject::StdReturn; }
const bool Constraint::getCylinder(double &radius, double &height, Base::Vector3d& base, Base::Vector3d& axis) const { std::vector<App::DocumentObject*> Objects = References.getValues(); std::vector<std::string> SubElements = References.getSubValues(); if (Objects.empty()) return false; App::DocumentObject* obj = Objects[0]; Part::Feature* feat = static_cast<Part::Feature*>(obj); Part::TopoShape toposhape = feat->Shape.getShape(); if (toposhape.isNull()) return false; TopoDS_Shape sh = toposhape.getSubShape(SubElements[0].c_str()); TopoDS_Face face = TopoDS::Face(sh); BRepAdaptor_Surface surface(face); gp_Cylinder cyl = surface.Cylinder(); gp_Pnt start = surface.Value(surface.FirstUParameter(), surface.FirstVParameter()); gp_Pnt end = surface.Value(surface.FirstUParameter(), surface.LastVParameter()); height = start.Distance(end); radius = cyl.Radius(); gp_Pnt b = cyl.Location(); base = Base::Vector3d(b.X(), b.Y(), b.Z()); gp_Dir dir = cyl.Axis().Direction(); axis = Base::Vector3d(dir.X(), dir.Y(), dir.Z()); return true; }
void Pipe::buildPipePath(const Part::TopoShape& shape, const std::vector< std::string >& subedge, TopoDS_Shape& path) { if (!shape._Shape.IsNull()) { try { if (!subedge.empty()) { //if(SpineTangent.getValue()) //getContiniusEdges(shape, subedge); BRepBuilderAPI_MakeWire mkWire; for (std::vector<std::string>::const_iterator it = subedge.begin(); it != subedge.end(); ++it) { TopoDS_Shape subshape = shape.getSubShape(it->c_str()); mkWire.Add(TopoDS::Edge(subshape)); } path = mkWire.Wire(); } else if (shape._Shape.ShapeType() == TopAbs_EDGE) { path = shape._Shape; } else if (shape._Shape.ShapeType() == TopAbs_WIRE) { BRepBuilderAPI_MakeWire mkWire(TopoDS::Wire(shape._Shape)); path = mkWire.Wire(); } else if (shape._Shape.ShapeType() == TopAbs_COMPOUND) { TopoDS_Iterator it(shape._Shape); for (; it.More(); it.Next()) { if (it.Value().IsNull()) throw Base::Exception("In valid element in spine."); if ((it.Value().ShapeType() != TopAbs_EDGE) && (it.Value().ShapeType() != TopAbs_WIRE)) { throw Base::Exception("Element in spine is neither an edge nor a wire."); } } Handle(TopTools_HSequenceOfShape) hEdges = new TopTools_HSequenceOfShape(); Handle(TopTools_HSequenceOfShape) hWires = new TopTools_HSequenceOfShape(); for (TopExp_Explorer xp(shape._Shape, TopAbs_EDGE); xp.More(); xp.Next()) hEdges->Append(xp.Current()); ShapeAnalysis_FreeBounds::ConnectEdgesToWires(hEdges, Precision::Confusion(), Standard_True, hWires); int len = hWires->Length(); if (len != 1) throw Base::Exception("Spine is not connected."); path = hWires->Value(1); } else { throw Base::Exception("Spine is neither an edge nor a wire."); } } catch (Standard_Failure) { throw Base::Exception("Invalid spine."); } } }
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 ProfileBased::checkLineCrossesFace(const gp_Lin &line, const TopoDS_Face &face) { #if 1 BRepBuilderAPI_MakeEdge mkEdge(line); TopoDS_Wire wire = ShapeAnalysis::OuterWire(face); BRepExtrema_DistShapeShape distss(wire, mkEdge.Shape(), Precision::Confusion()); if (distss.IsDone()) { if (distss.Value() > Precision::Confusion()) return false; // build up map vertex->edge TopTools_IndexedDataMapOfShapeListOfShape vertex2Edge; TopExp::MapShapesAndAncestors(wire, TopAbs_VERTEX, TopAbs_EDGE, vertex2Edge); for (Standard_Integer i=1; i<= distss.NbSolution(); i++) { if (distss.PointOnShape1(i).Distance(distss.PointOnShape2(i)) > Precision::Confusion()) continue; BRepExtrema_SupportType type = distss.SupportTypeShape1(i); if (type == BRepExtrema_IsOnEdge) { TopoDS_Edge edge = TopoDS::Edge(distss.SupportOnShape1(i)); BRepAdaptor_Curve adapt(edge); // create a plane (pnt,dir) that goes through the intersection point and is built of // the vectors of the sketch normal and the rotation axis const gp_Dir& normal = BRepAdaptor_Surface(face).Plane().Axis().Direction(); gp_Dir dir = line.Direction().Crossed(normal); gp_Pnt pnt = distss.PointOnShape1(i); Standard_Real t; distss.ParOnEdgeS1(i, t); gp_Pnt p_eps1 = adapt.Value(std::max<double>(adapt.FirstParameter(), t-10*Precision::Confusion())); gp_Pnt p_eps2 = adapt.Value(std::min<double>(adapt.LastParameter(), t+10*Precision::Confusion())); // now check if we get a change in the sign of the distances Standard_Real dist_p_eps1_pnt = gp_Vec(p_eps1, pnt).Dot(gp_Vec(dir)); Standard_Real dist_p_eps2_pnt = gp_Vec(p_eps2, pnt).Dot(gp_Vec(dir)); // distance to the plane must be noticeable if (fabs(dist_p_eps1_pnt) > 5*Precision::Confusion() && fabs(dist_p_eps2_pnt) > 5*Precision::Confusion()) { if (dist_p_eps1_pnt * dist_p_eps2_pnt < 0) return true; } } else if (type == BRepExtrema_IsVertex) { // for a vertex check the two adjacent edges if there is a change of sign TopoDS_Vertex vertex = TopoDS::Vertex(distss.SupportOnShape1(i)); const TopTools_ListOfShape& edges = vertex2Edge.FindFromKey(vertex); if (edges.Extent() == 2) { // create a plane (pnt,dir) that goes through the intersection point and is built of // the vectors of the sketch normal and the rotation axis BRepAdaptor_Surface adapt(face); const gp_Dir& normal = adapt.Plane().Axis().Direction(); gp_Dir dir = line.Direction().Crossed(normal); gp_Pnt pnt = distss.PointOnShape1(i); // from the first edge get a point next to the intersection point const TopoDS_Edge& edge1 = TopoDS::Edge(edges.First()); BRepAdaptor_Curve adapt1(edge1); Standard_Real dist1 = adapt1.Value(adapt1.FirstParameter()).SquareDistance(pnt); Standard_Real dist2 = adapt1.Value(adapt1.LastParameter()).SquareDistance(pnt); gp_Pnt p_eps1; if (dist1 < dist2) p_eps1 = adapt1.Value(adapt1.FirstParameter() + 2*Precision::Confusion()); else p_eps1 = adapt1.Value(adapt1.LastParameter() - 2*Precision::Confusion()); // from the second edge get a point next to the intersection point const TopoDS_Edge& edge2 = TopoDS::Edge(edges.Last()); BRepAdaptor_Curve adapt2(edge2); Standard_Real dist3 = adapt2.Value(adapt2.FirstParameter()).SquareDistance(pnt); Standard_Real dist4 = adapt2.Value(adapt2.LastParameter()).SquareDistance(pnt); gp_Pnt p_eps2; if (dist3 < dist4) p_eps2 = adapt2.Value(adapt2.FirstParameter() + 2*Precision::Confusion()); else p_eps2 = adapt2.Value(adapt2.LastParameter() - 2*Precision::Confusion()); // now check if we get a change in the sign of the distances Standard_Real dist_p_eps1_pnt = gp_Vec(p_eps1, pnt).Dot(gp_Vec(dir)); Standard_Real dist_p_eps2_pnt = gp_Vec(p_eps2, pnt).Dot(gp_Vec(dir)); // distance to the plane must be noticeable if (fabs(dist_p_eps1_pnt) > Precision::Confusion() && fabs(dist_p_eps2_pnt) > Precision::Confusion()) { if (dist_p_eps1_pnt * dist_p_eps2_pnt < 0) return true; } } } } } return false; #else // This is not as easy as it looks, because a distance of zero might be OK if // the axis touches the sketchshape in in a linear edge or a vertex // Note: This algorithm does not catch cases where the sketchshape touches the // axis in two or more points // Note: And it only works on closed outer wires TopoDS_Wire outerWire = ShapeAnalysis::OuterWire(face); BRepBuilderAPI_MakeEdge mkEdge(line); if (!mkEdge.IsDone()) throw Base::RuntimeError("Revolve: Unexpected OCE failure"); BRepAdaptor_Curve axis(TopoDS::Edge(mkEdge.Shape())); TopExp_Explorer ex; int intersections = 0; std::vector<gp_Pnt> intersectionpoints; // Note: We need to look at every edge separately to catch coincident lines for (ex.Init(outerWire, TopAbs_EDGE); ex.More(); ex.Next()) { BRepAdaptor_Curve edge(TopoDS::Edge(ex.Current())); Extrema_ExtCC intersector(axis, edge); if (intersector.IsDone()) { for (int i = 1; i <= intersector.NbExt(); i++) { #if OCC_VERSION_HEX >= 0x060500 if (intersector.SquareDistance(i) < Precision::Confusion()) { #else if (intersector.Value(i) < Precision::Confusion()) { #endif if (intersector.IsParallel()) { // A line that is coincident with the axis produces three intersections // 1 with the line itself and 2 with the adjacent edges intersections -= 2; } else { Extrema_POnCurv p1, p2; intersector.Points(i, p1, p2); intersectionpoints.push_back(p1.Value()); intersections++; } } } } } // Note: We might check this inside the loop but then we have to rely on TopExp_Explorer // returning the wire's edges in adjacent order (because of the coincident line checking) if (intersections > 1) { // Check that we don't touch the sketchface just in two identical vertices if ((intersectionpoints.size() == 2) && (intersectionpoints[0].IsEqual(intersectionpoints[1], Precision::Confusion()))) return false; else return true; } return false; #endif } void ProfileBased::remapSupportShape(const TopoDS_Shape& newShape) { TopTools_IndexedMapOfShape faceMap; TopExp::MapShapes(newShape, TopAbs_FACE, faceMap); // here we must reset the placement otherwise the geometric matching doesn't work Part::TopoShape shape = this->Shape.getValue(); TopoDS_Shape sh = shape.getShape(); sh.Location(TopLoc_Location()); shape.setShape(sh); std::vector<App::DocumentObject*> refs = this->getInList(); for (std::vector<App::DocumentObject*>::iterator it = refs.begin(); it != refs.end(); ++it) { std::vector<App::Property*> props; (*it)->getPropertyList(props); for (std::vector<App::Property*>::iterator jt = props.begin(); jt != props.end(); ++jt) { if (!(*jt)->isDerivedFrom(App::PropertyLinkSub::getClassTypeId())) continue; App::PropertyLinkSub* link = static_cast<App::PropertyLinkSub*>(*jt); if (link->getValue() != this) continue; std::vector<std::string> subValues = link->getSubValues(); std::vector<std::string> newSubValues; for (std::vector<std::string>::iterator it = subValues.begin(); it != subValues.end(); ++it) { std::string shapetype; if (it->size() > 4 && it->substr(0,4) == "Face") { shapetype = "Face"; } else if (it->size() > 4 && it->substr(0,4) == "Edge") { shapetype = "Edge"; } else if (it->size() > 6 && it->substr(0,6) == "Vertex") { shapetype = "Vertex"; } else { newSubValues.push_back(*it); continue; } bool success = false; TopoDS_Shape element; try { element = shape.getSubShape(it->c_str()); } catch (Standard_Failure&) { // This shape doesn't even exist, so no chance to do some tests newSubValues.push_back(*it); continue; } try { // as very first test check if old face and new face are parallel planes TopoDS_Shape newElement = Part::TopoShape(newShape).getSubShape(it->c_str()); if (isParallelPlane(element, newElement)) { newSubValues.push_back(*it); success = true; } } catch (Standard_Failure&) { } // try an exact matching if (!success) { for (int i=1; i<faceMap.Extent(); i++) { if (isQuasiEqual(element, faceMap.FindKey(i))) { std::stringstream str; str << shapetype << i; newSubValues.push_back(str.str()); success = true; break; } } } // if an exact matching fails then try to compare only the geometries if (!success) { for (int i=1; i<faceMap.Extent(); i++) { if (isEqualGeometry(element, faceMap.FindKey(i))) { std::stringstream str; str << shapetype << i; newSubValues.push_back(str.str()); success = true; break; } } } // the new shape couldn't be found so keep the old sub-name if (!success) newSubValues.push_back(*it); } link->setValue(this, newSubValues); } } }
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; }
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; }