App::DocumentObjectExecReturn *Helix::execute(void) { try { Standard_Real myPitch = Pitch.getValue(); Standard_Real myHeight = Height.getValue(); Standard_Real myRadius = Radius.getValue(); Standard_Real myAngle = Angle.getValue(); Standard_Boolean myLocalCS = LocalCoord.getValue() ? Standard_True : Standard_False; //Standard_Boolean myStyle = Style.getValue() ? Standard_True : Standard_False; TopoShape helix; // work around for OCC bug #23314 (FC #0954) // the exact conditions for failure are unknown. building the helix 1 turn at a time // seems to always work. this->Shape.setValue(helix.makeLongHelix(myPitch, myHeight, myRadius, myAngle, myLocalCS)); // if (myHeight / myPitch > 50.0) // this->Shape.setValue(helix.makeLongHelix(myPitch, myHeight, myRadius, myAngle, myLocalCS)); // else // this->Shape.setValue(helix.makeHelix(myPitch, myHeight, myRadius, myAngle, myLocalCS, myStyle)); } catch (Standard_Failure& e) { return new App::DocumentObjectExecReturn(e.GetMessageString()); } return Primitive::execute(); }
App::DocumentObjectExecReturn *Loft::execute(void) { if (Sections.getSize() == 0) return new App::DocumentObjectExecReturn("No sections linked."); try { TopTools_ListOfShape profiles; const std::vector<App::DocumentObject*>& shapes = Sections.getValues(); std::vector<App::DocumentObject*>::const_iterator it; for (it = shapes.begin(); it != shapes.end(); ++it) { if (!(*it)->isDerivedFrom(Part::Feature::getClassTypeId())) return new App::DocumentObjectExecReturn("Linked object is not a shape."); TopoDS_Shape shape = static_cast<Part::Feature*>(*it)->Shape.getValue(); if (shape.IsNull()) return new App::DocumentObjectExecReturn("Linked shape is invalid."); // Extract first element of a compound if (shape.ShapeType() == TopAbs_COMPOUND) { TopoDS_Iterator it(shape); for (; it.More(); it.Next()) { if (!it.Value().IsNull()) { shape = it.Value(); break; } } } if (shape.ShapeType() == TopAbs_FACE) { TopoDS_Wire faceouterWire = ShapeAnalysis::OuterWire(TopoDS::Face(shape)); profiles.Append(faceouterWire); } else if (shape.ShapeType() == TopAbs_WIRE) { BRepBuilderAPI_MakeWire mkWire(TopoDS::Wire(shape)); profiles.Append(mkWire.Wire()); } else if (shape.ShapeType() == TopAbs_EDGE) { BRepBuilderAPI_MakeWire mkWire(TopoDS::Edge(shape)); profiles.Append(mkWire.Wire()); } else if (shape.ShapeType() == TopAbs_VERTEX) { profiles.Append(shape); } else { return new App::DocumentObjectExecReturn("Linked shape is not a vertex, edge, wire nor face."); } } Standard_Boolean isSolid = Solid.getValue() ? Standard_True : Standard_False; Standard_Boolean isRuled = Ruled.getValue() ? Standard_True : Standard_False; Standard_Boolean isClosed = Closed.getValue() ? Standard_True : Standard_False; TopoShape myShape; this->Shape.setValue(myShape.makeLoft(profiles, isSolid, isRuled,isClosed)); return App::DocumentObject::StdReturn; } catch (Standard_Failure) { Handle_Standard_Failure e = Standard_Failure::Caught(); return new App::DocumentObjectExecReturn(e->GetMessageString()); } }
void PropertyPartShape::RestoreDocFile(Base::Reader &reader) { Base::FileInfo brep(reader.getFileName()); if (brep.hasExtension("bin")) { TopoShape shape; shape.importBinary(reader); setValue(shape); } else { bool direct = App::GetApplication().GetParameterGroupByPath ("User parameter:BaseApp/Preferences/Mod/Part/General")->GetBool("DirectAccess", true); if (!direct) { BRep_Builder builder; // create a temporary file and copy the content from the zip stream Base::FileInfo fi(App::Application::getTempFileName()); // read in the ASCII file and write back to the file stream Base::ofstream file(fi, std::ios::out | std::ios::binary); unsigned long ulSize = 0; if (reader) { std::streambuf* buf = file.rdbuf(); reader >> buf; file.flush(); ulSize = buf->pubseekoff(0, std::ios::cur, std::ios::in); } file.close(); // Read the shape from the temp file, if the file is empty the stored shape was already empty. // If it's still empty after reading the (non-empty) file there must occurred an error. TopoDS_Shape shape; if (ulSize > 0) { if (!BRepTools::Read(shape, (Standard_CString)fi.filePath().c_str(), builder)) { // Note: Do NOT throw an exception here because if the tmp. created file could // not be read it's NOT an indication for an invalid input stream 'reader'. // We only print an error message but continue reading the next files from the // stream... App::PropertyContainer* father = this->getContainer(); if (father && father->isDerivedFrom(App::DocumentObject::getClassTypeId())) { App::DocumentObject* obj = static_cast<App::DocumentObject*>(father); Base::Console().Error("BRep file '%s' with shape of '%s' seems to be empty\n", fi.filePath().c_str(),obj->Label.getValue()); } else { Base::Console().Warning("Loaded BRep file '%s' seems to be empty\n", fi.filePath().c_str()); } } } // delete the temp file fi.deleteFile(); setValue(shape); } else {
App::DocumentObjectExecReturn *Helix::execute(void) { try { Standard_Real myPitch = Pitch.getValue(); Standard_Real myHeight = Height.getValue(); Standard_Real myRadius = Radius.getValue(); Standard_Real myAngle = Angle.getValue(); Standard_Boolean myLocalCS = LocalCoord.getValue() ? Standard_True : Standard_False; Standard_Boolean myStyle = Style.getValue() ? Standard_True : Standard_False; TopoShape helix; this->Shape.setValue(helix.makeHelix(myPitch, myHeight, myRadius, myAngle, myLocalCS, myStyle)); } catch (Standard_Failure) { Handle_Standard_Failure e = Standard_Failure::Caught(); return new App::DocumentObjectExecReturn(e->GetMessageString()); } return App::DocumentObject::StdReturn; }
void PropertyPartShape::SaveDocFile (Base::Writer &writer) const { // If the shape is empty we simply store nothing. The file size will be 0 which // can be checked when reading in the data. if (_Shape.getShape().IsNull()) return; TopoDS_Shape myShape = _Shape.getShape(); if (writer.getMode("BinaryBrep")) { TopoShape shape; shape.setShape(myShape); shape.exportBinary(writer.Stream()); } else { bool direct = App::GetApplication().GetParameterGroupByPath ("User parameter:BaseApp/Preferences/Mod/Part/General")->GetBool("DirectAccess", true); if (!direct) { // create a temporary file and copy the content to the zip stream // once the tmp. filename is known use always the same because otherwise // we may run into some problems on the Linux platform static Base::FileInfo fi(App::Application::getTempFileName()); if (!BRepTools_Write(myShape,(Standard_CString)fi.filePath().c_str())) { // Note: Do NOT throw an exception here because if the tmp. file could // not be created we should not abort. // We only print an error message but continue writing the next files to the // stream... App::PropertyContainer* father = this->getContainer(); if (father && father->isDerivedFrom(App::DocumentObject::getClassTypeId())) { App::DocumentObject* obj = static_cast<App::DocumentObject*>(father); Base::Console().Error("Shape of '%s' cannot be written to BRep file '%s'\n", obj->Label.getValue(),fi.filePath().c_str()); } else { Base::Console().Error("Cannot save BRep file '%s'\n", fi.filePath().c_str()); } std::stringstream ss; ss << "Cannot save BRep file '" << fi.filePath() << "'"; writer.addError(ss.str()); } Base::ifstream file(fi, std::ios::in | std::ios::binary); if (file) { //unsigned long ulSize = 0; std::streambuf* buf = file.rdbuf(); //if (buf) { // unsigned long ulCurr; // ulCurr = buf->pubseekoff(0, std::ios::cur, std::ios::in); // ulSize = buf->pubseekoff(0, std::ios::end, std::ios::in); // buf->pubseekoff(ulCurr, std::ios::beg, std::ios::in); //} // read in the ASCII file and write back to the stream //std::strstreambuf sbuf(ulSize); //file >> &sbuf; //writer.Stream() << &sbuf; writer.Stream() << buf; } file.close(); // remove temp file fi.deleteFile(); } else { BRepTools_Write(myShape, writer.Stream()); } } }
TopoShape Extrusion::extrudeShape(const TopoShape source, Extrusion::ExtrusionParameters params) { TopoDS_Shape result; gp_Vec vec = gp_Vec(params.dir).Multiplied(params.lengthFwd+params.lengthRev);//total vector of extrusion if (std::fabs(params.taperAngleFwd) >= Precision::Angular() || std::fabs(params.taperAngleRev) >= Precision::Angular() ) { //Tapered extrusion! #if defined(__GNUC__) && defined (FC_OS_LINUX) Base::SignalException se; #endif TopoDS_Shape myShape = source.getShape(); if (myShape.IsNull()) Standard_Failure::Raise("Cannot extrude empty shape"); // #0000910: Circles Extrude Only Surfaces, thus use BRepBuilderAPI_Copy myShape = BRepBuilderAPI_Copy(myShape).Shape(); std::list<TopoDS_Shape> drafts; makeDraft(params, myShape, drafts); if (drafts.empty()) { Standard_Failure::Raise("Drafting shape failed"); } else if (drafts.size() == 1) { result = drafts.front(); } else { TopoDS_Compound comp; BRep_Builder builder; builder.MakeCompound(comp); for (std::list<TopoDS_Shape>::iterator it = drafts.begin(); it != drafts.end(); ++it) builder.Add(comp, *it); result = comp; } } else { //Regular (non-tapered) extrusion! TopoDS_Shape myShape = source.getShape(); if (myShape.IsNull()) Standard_Failure::Raise("Cannot extrude empty shape"); // #0000910: Circles Extrude Only Surfaces, thus use BRepBuilderAPI_Copy myShape = BRepBuilderAPI_Copy(myShape).Shape(); //apply reverse part of extrusion by shifting the source shape if (fabs(params.lengthRev)>Precision::Confusion() ){ gp_Trsf mov; mov.SetTranslation(gp_Vec(params.dir)*(-params.lengthRev)); TopLoc_Location loc(mov); myShape.Move(loc); } //make faces from wires if (params.solid) { //test if we need to make faces from wires. If there are faces - we don't. TopExp_Explorer xp(myShape, TopAbs_FACE); if (xp.More()){ //source shape has faces. Just extrude as-is. } else { std::unique_ptr<FaceMaker> mkFace = FaceMaker::ConstructFromType(params.faceMakerClass.c_str()); if (myShape.ShapeType() == TopAbs_COMPOUND) mkFace->useCompound(TopoDS::Compound(myShape)); else mkFace->addShape(myShape); mkFace->Build(); myShape = mkFace->Shape(); } } //extrude! BRepPrimAPI_MakePrism mkPrism(myShape, vec); result = mkPrism.Shape(); } if (result.IsNull()) throw Base::Exception("Result of extrusion is null shape."); return TopoShape(result); }
// constructor method int TopoShapeVertexPy::PyInit(PyObject* args, PyObject* /*kwd*/) { double x=0.0,y=0.0,z=0.0; PyObject *object; bool success = false; if (PyArg_ParseTuple(args, "|ddd", &x,&y,&z)) { // do nothing here success = true; } if (!success) { PyErr_Clear(); // set by PyArg_ParseTuple() if (PyArg_ParseTuple(args,"O!",&(Base::VectorPy::Type), &object)) { // Note: must be static_cast, not reinterpret_cast Base::Vector3d* ptr = static_cast<Base::VectorPy*>(object)->getVectorPtr(); x = ptr->x; y = ptr->y; z = ptr->z; success = true; } } if (!success) { PyErr_Clear(); // set by PyArg_ParseTuple() if (PyArg_ParseTuple(args,"O!",&(PyTuple_Type), &object)) { try { Py::Tuple tuple(object); x = Py::Float(tuple.getItem(0)); y = Py::Float(tuple.getItem(1)); z = Py::Float(tuple.getItem(2)); success = true; } catch (const Py::Exception&) { return -1; } } } if (!success) { PyErr_Clear(); // set by PyArg_ParseTuple() if (PyArg_ParseTuple(args,"O!",&(PointPy::Type), &object)) { Handle_Geom_CartesianPoint this_point = Handle_Geom_CartesianPoint::DownCast (static_cast<PointPy*>(object)->getGeomPointPtr()->handle()); gp_Pnt pnt = this_point->Pnt(); x = pnt.X(); y = pnt.Y(); z = pnt.Z(); success = true; } } if (!success) { PyErr_Clear(); // set by PyArg_ParseTuple() if (PyArg_ParseTuple(args,"O!",&(Part::TopoShapePy::Type), &object)) { TopoShape* ptr = static_cast<TopoShapePy*>(object)->getTopoShapePtr(); TopoDS_Shape shape = ptr->getShape(); if (!shape.IsNull() && shape.ShapeType() == TopAbs_VERTEX) { TopoShapeVertexPy::PointerType vert = reinterpret_cast<TopoShapeVertexPy::PointerType>(_pcTwinPointer); vert->setShape(ptr->getShape()); return 0; } } } if (!success) { PyErr_SetString(PyExc_TypeError, "Either three floats, tuple, vector or vertex expected"); return -1; } TopoShapeVertexPy::PointerType ptr = reinterpret_cast<TopoShapeVertexPy::PointerType>(_pcTwinPointer); BRepBuilderAPI_MakeVertex aBuilder(gp_Pnt(x,y,z)); TopoDS_Shape s = aBuilder.Vertex(); ptr->setShape(s); return 0; }
TopoShape DuplicateCylinderFilletBug(){ TopoDS_Shape Box = BRepPrimAPI_MakeBox(10., 10., 10.); TopoDS_Shape Cylinder = BRepPrimAPI_MakeCylinder(2., 10.); // in FreeCAD, every operation first creates a blank TopoShape and then adds the // TopoDS_Shape to it TopoShape BoxShape, CylShape, FusedShape; // The current FreeCAD source will directly set TopoShape._Shape from all kinds of // places in the code. I have added a TopoShape::setShape method so that we can have // some control over this. Note that this method is overloaded a few times BoxShape.setShape(Box, "Primitive Box"); CylShape.setShape(Cylinder, "Primitive Cylinder"); // As of now, I don't see the TopoShape fuse being used. rather, the fuse is done // outside and then stored to the TopoShape BRepAlgoAPI_Fuse mkFuse(Box, Cylinder); // in my current implementation, I send the FIRST TopoShape from the Fuse operation to // the setShape, and copy it's _TopoNamer FusedShape.setShape(BoxShape, mkFuse); // Now let's select an edge, then fillet it TopoDS_Shape BaseShape = mkFuse.Shape(); // Finaly, 'Select' the edge std::string selectionLabel = FusedShape.selectEdge(3); std::cout << "Selected Edge Node = " << selectionLabel << std::endl; // Write out the current-state of things //FusedShape.OCCDeepDump(); FusedShape.WriteTNamingNode("0:1:1", "01_Selected", true); FusedShape.WriteTNamingNode("0:2", "02_BaseBox", false); FusedShape.WriteTNamingNode("0:3", "03_BaseCyl", false); FusedShape.WriteTNamingNode("0:4", "04_FusedShape", false); // Fillet the selected edge TopoDS_Edge RecoveredEdge = FusedShape.getSelectedEdge(selectionLabel); BRepFilletAPI_MakeFillet mkFillet(FusedShape.getShape()); mkFillet.Add(2., 2., RecoveredEdge); mkFillet.Build(); // Record the Fillet Operation TopoShape FilletedShape;// = mkFillet.Shape(); FilletedShape.setShape(FusedShape, mkFillet); // write out the latest node FusedShape.WriteTNamingNode("0:5", "05_FilletedShape", false); //-------------------------------------------------------------------------------- //-------------------------------------------------------------------------------- // FUSE DONE, ABOUT TO RESIZE THE CYLINDER //-------------------------------------------------------------------------------- //-------------------------------------------------------------------------------- // resize the cylinder. I believe FreeCAD just creates a whole new cylinder TopoDS_Shape Cylinder2 = BRepPrimAPI_MakeCylinder(2., 15.); TopoShape NewCylShape; NewCylShape.setShape(Cylinder2); // Now the FreeCAD algorithms figure out that Fuse and Fillet need to be re-run // First, re-do Fuse TopoShape ReFusedShape; BRepAlgoAPI_Fuse mkFuse2(BoxShape.getShape(), NewCylShape.getShape()); ReFusedShape.setShape(BoxShape, mkFuse2); BRepFilletAPI_MakeFillet mkFillet2(ReFusedShape.getShape()); // grab the selected edge from our tree to re-fillet TopoDS_Edge RecoveredEdge2 = ReFusedShape.getSelectedEdge(selectionLabel); // now re-do fillet mkFillet2.Add(2., 2., RecoveredEdge); mkFillet2.Build(); // Record the Fillet Operation TopoShape ReFilletedShape;// = mkFillet2.Shape(); ReFilletedShape.setShape(ReFusedShape, mkFillet2); // Write out some more shapes FusedShape.WriteTNamingNode("0:6", "06_PartOfFusionMaybe", false); FusedShape.WriteTNamingNode("0:7", "07_ReFusion", false); FusedShape.WriteTNamingNode("0:8", "08_ReFillet", false); return FusedShape; }
TopoShape SimpleBoxWithNaming(){ // We'll do this like freecad, first create TopoDS_Shape const TopoDS_Shape& Box = BRepPrimAPI_MakeBox(10., 10., 10.); // create Base Shape that gets passed to FilletFeature TopoShape BaseShape(Box); //std::clog << "Dumping deep TDF tree\n"; //std::clog << BaseShape.DeepDeepDumpTopoHistory(); // create blank TopoShape in FilletFeature and add Base Shape TopoShape BoxShape; BoxShape.addShape(Box); // Finaly, 'Select' the edge std::cout << "Trying to select the first time" << std::endl; std::string selectionLabel = BoxShape.selectEdge(3); //std::cout << "Trying to select a second time" << std::endl; //std::string selectionLabel2 = BoxShape.selectEdge(3); //std::clog << "Dumping tree" << std::endl; //std::clog << BoxShape.DumpTopoHistory(); //std::clog << "|____________________|" << std::endl; // And fillet the box std::clog << "Running makeTopoShape" << std::endl; BoxShape.makeTopoShapeFillet(2., 2., selectionLabel); //std::clog << "-------------------------" << std::endl; std::clog << "------------ REBUILDING ----------" << std::endl; //std::clog << "-------------------------" << std::endl; // make box taller const TopoDS_Shape& Box2 = BRepPrimAPI_MakeBox(10., 20., 20.); BoxShape.modifyShape("0:2", Box2); std::clog << BoxShape.DumpTopoHistory(); // try re-building the box TopoDS_Edge recoveredEdge = TopoDS::Edge(BoxShape.getSelectedEdge(selectionLabel)); //TopoDS_Shape recoveredBase = BoxShape.getSelectedBaseShape(selectionLabel); //TopoDS_Shape recoveredBase = BoxShape.getNodeShape("0:4"); TopoDS_Shape recoveredBase = BoxShape.getTipShape(); //if (recoveredBase.IsNull()){ //std::cout << "BaseShape is NULL....\n"; //} //else{ //std::cout << "BaseShape is not NULL!!!!\n"; //} //if (recoveredEdge.IsNull()){ //std::cout << "recoveredEdge is Nul..." << std::endl; //} //else{ //std::cout << "recoveredEdge is NOT NULL!!!!" << std::endl; //} TopTools_IndexedMapOfShape edges; TopExp::MapShapes(recoveredBase, TopAbs_EDGE, edges); if (edges.Contains(recoveredEdge)){ std::cout << "Yes the Edge is in the box...\n"; } else{ std::cout << "No, the Edge is not in the Box...\n"; } //BoxShape.makeTopoShapeFillet(2., 2., selectionLabel); return BoxShape; }
App::DocumentObjectExecReturn *Loft::execute(void) { if (Sections.getSize() == 0) return new App::DocumentObjectExecReturn("No sections linked."); try { TopTools_ListOfShape profiles; const std::vector<App::DocumentObject*>& shapes = Sections.getValues(); std::vector<App::DocumentObject*>::const_iterator it; for (it = shapes.begin(); it != shapes.end(); ++it) { if (!(*it)->isDerivedFrom(Part::Feature::getClassTypeId())) return new App::DocumentObjectExecReturn("Linked object is not a shape."); TopoDS_Shape shape = static_cast<Part::Feature*>(*it)->Shape.getValue(); if (shape.IsNull()) return new App::DocumentObjectExecReturn("Linked shape is invalid."); // Allow compounds with a single face, wire or vertex or // if there are only edges building one wire if (shape.ShapeType() == TopAbs_COMPOUND) { Handle(TopTools_HSequenceOfShape) hEdges = new TopTools_HSequenceOfShape(); Handle(TopTools_HSequenceOfShape) hWires = new TopTools_HSequenceOfShape(); TopoDS_Iterator it(shape); int numChilds=0; TopoDS_Shape child; for (; it.More(); it.Next(), numChilds++) { if (!it.Value().IsNull()) { child = it.Value(); if (child.ShapeType() == TopAbs_EDGE) { hEdges->Append(child); } } } // a single child if (numChilds == 1) { shape = child; } // or all children are edges else if (hEdges->Length() == numChilds) { ShapeAnalysis_FreeBounds::ConnectEdgesToWires(hEdges, Precision::Confusion(), Standard_False, hWires); if (hWires->Length() == 1) shape = hWires->Value(1); } } if (shape.ShapeType() == TopAbs_FACE) { TopoDS_Wire faceouterWire = ShapeAnalysis::OuterWire(TopoDS::Face(shape)); profiles.Append(faceouterWire); } else if (shape.ShapeType() == TopAbs_WIRE) { BRepBuilderAPI_MakeWire mkWire(TopoDS::Wire(shape)); profiles.Append(mkWire.Wire()); } else if (shape.ShapeType() == TopAbs_EDGE) { BRepBuilderAPI_MakeWire mkWire(TopoDS::Edge(shape)); profiles.Append(mkWire.Wire()); } else if (shape.ShapeType() == TopAbs_VERTEX) { profiles.Append(shape); } else { return new App::DocumentObjectExecReturn("Linked shape is not a vertex, edge, wire nor face."); } } Standard_Boolean isSolid = Solid.getValue() ? Standard_True : Standard_False; Standard_Boolean isRuled = Ruled.getValue() ? Standard_True : Standard_False; Standard_Boolean isClosed = Closed.getValue() ? Standard_True : Standard_False; int degMax = MaxDegree.getValue(); TopoShape myShape; this->Shape.setValue(myShape.makeLoft(profiles, isSolid, isRuled, isClosed, degMax)); return App::DocumentObject::StdReturn; } catch (Standard_Failure& e) { return new App::DocumentObjectExecReturn(e.GetMessageString()); } }
// constructor method int TopoShapeEdgePy::PyInit(PyObject* args, PyObject* /*kwd*/) { PyObject *pcObj, *pcObj2; double first=DBL_MAX, last=DBL_MAX; if (PyArg_ParseTuple(args, "O!|dd", &(Part::GeometryPy::Type), &pcObj, &first, &last)) { Geometry* geom = static_cast<GeometryPy*>(pcObj)->getGeometryPtr(); Handle(Geom_Curve) curve = Handle(Geom_Curve)::DownCast(geom->handle()); if (curve.IsNull()) { PyErr_SetString(PartExceptionOCCError, "geometry is not a curve type"); return -1; } if (first==DBL_MAX) first = curve->FirstParameter(); if (last==DBL_MAX) last = curve->LastParameter(); try { BRepBuilderAPI_MakeEdge mkEdge(curve, first, last); getTopoShapePtr()->setShape(mkEdge.Edge()); return 0; } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return -1; } } PyErr_Clear(); if (PyArg_ParseTuple(args, "O!", &(Part::TopoShapePy::Type), &pcObj)) { TopoShape* shape = static_cast<TopoShapePy*>(pcObj)->getTopoShapePtr(); if (shape && !shape->getShape().IsNull() && shape->getShape().ShapeType() == TopAbs_EDGE) { this->getTopoShapePtr()->setShape(shape->getShape()); return 0; } else { PyErr_SetString(PyExc_TypeError, "Shape is not an edge"); return -1; } } PyErr_Clear(); if (PyArg_ParseTuple(args, "O!O!", &(Part::TopoShapeVertexPy::Type), &pcObj, &(Part::TopoShapeVertexPy::Type), &pcObj2)) { TopoShape* shape1 = static_cast<TopoShapePy*>(pcObj)->getTopoShapePtr(); TopoShape* shape2 = static_cast<TopoShapePy*>(pcObj2)->getTopoShapePtr(); const TopoDS_Vertex& v1 = TopoDS::Vertex(shape1->getShape()); const TopoDS_Vertex& v2 = TopoDS::Vertex(shape2->getShape()); try { BRepBuilderAPI_MakeEdge mkEdge(v1, v2); getTopoShapePtr()->setShape(mkEdge.Edge()); return 0; } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return -1; } } PyErr_SetString(PartExceptionOCCError, "Curve or shape expected"); return -1; }