PyObject* GeometryPy::copy(PyObject *args) { if (!PyArg_ParseTuple(args, "")) return NULL; Part::Geometry* geom = this->getGeometryPtr(); PyTypeObject* type = this->GetType(); PyObject* cpy = 0; // let the type object decide if (type->tp_new) cpy = type->tp_new(type, this, 0); if (!cpy) { PyErr_SetString(PyExc_TypeError, "failed to create copy of geometry"); return 0; } Part::GeometryPy* geompy = static_cast<Part::GeometryPy*>(cpy); // the PyMake function must have created the corresponding instance of the 'Geometry' subclass // so delete it now to avoid a memory leak if (geompy->_pcTwinPointer) { Part::Geometry* clone = static_cast<Part::Geometry*>(geompy->_pcTwinPointer); delete clone; } geompy->_pcTwinPointer = geom->copy(); return cpy; }
void SketcherValidation::on_findReversed_clicked() { std::vector<Base::Vector3d> points; const std::vector<Part::Geometry *>& geom = sketch->getExternalGeometry(); for (std::size_t i=0; i<geom.size(); i++) { Part::Geometry* g = geom[i]; //only arcs of circles need to be repaired. Arcs of ellipse were so broken there should be nothing to repair from. if (g->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { const Part::GeomArcOfCircle *segm = static_cast<const Part::GeomArcOfCircle*>(g); if (segm->isReversed()) { points.push_back(segm->getStartPoint(/*emulateCCW=*/true)); points.push_back(segm->getEndPoint(/*emulateCCW=*/true)); } } } hidePoints(); if(points.size()>0){ int nc = sketch->port_reversedExternalArcs(/*justAnalyze=*/true); showPoints(points); if(nc>0){ QMessageBox::warning(this, tr("Reversed external geometry"), tr("%1 reversed external-geometry arcs were found. Their endpoints are" " encircled in 3d view.\n\n" "%2 constraints are linking to the endpoints. The constraints have" " been listed in Report view (menu View -> Views -> Report view).\n\n" "Click \"Swap endpoints in constraints\" button to reassign endpoints." " Do this only once to sketches created in FreeCAD older than v0.15.???" ).arg(points.size()/2).arg(nc) ); ui->swapReversed->setEnabled(true); } else { QMessageBox::warning(this, tr("Reversed external geometry"), tr("%1 reversed external-geometry arcs were found. Their endpoints are " "encircled in 3d view.\n\n" "However, no constraints linking to the endpoints were found.").arg(points.size()/2)); ui->swapReversed->setEnabled(false); } } else { QMessageBox::warning(this, tr("Reversed external geometry"), tr("No reversed external-geometry arcs were found.")); } }
PyObject* SketchObjectPy::addGeometry(PyObject *args) { PyObject *pcObj; PyObject* construction; // this is an optional argument default false bool isConstruction; if (!PyArg_ParseTuple(args, "OO!", &pcObj, &PyBool_Type, &construction)) { PyErr_Clear(); if (!PyArg_ParseTuple(args, "O", &pcObj)) return 0; else isConstruction=false; } else { isConstruction = PyObject_IsTrue(construction) ? true : false; } if (PyObject_TypeCheck(pcObj, &(Part::GeometryPy::Type))) { Part::Geometry *geo = static_cast<Part::GeometryPy*>(pcObj)->getGeometryPtr(); int ret; // An arc created with Part.Arc will be converted into a Part.ArcOfCircle if (geo->getTypeId() == Part::GeomTrimmedCurve::getClassTypeId()) { Handle_Geom_TrimmedCurve trim = Handle_Geom_TrimmedCurve::DownCast(geo->handle()); Handle_Geom_Circle circle = Handle_Geom_Circle::DownCast(trim->BasisCurve()); Handle_Geom_Ellipse ellipse = Handle_Geom_Ellipse::DownCast(trim->BasisCurve()); if (!circle.IsNull()) { // create the definition struct for that geom Part::GeomArcOfCircle aoc; aoc.setHandle(trim); ret = this->getSketchObjectPtr()->addGeometry(&aoc,isConstruction); } else if (!ellipse.IsNull()) { // create the definition struct for that geom Part::GeomArcOfEllipse aoe; aoe.setHandle(trim); ret = this->getSketchObjectPtr()->addGeometry(&aoe,isConstruction); } else { std::stringstream str; str << "Unsupported geometry type: " << geo->getTypeId().getName(); PyErr_SetString(PyExc_TypeError, str.str().c_str()); return 0; } } else if (geo->getTypeId() == Part::GeomPoint::getClassTypeId() || geo->getTypeId() == Part::GeomCircle::getClassTypeId() || geo->getTypeId() == Part::GeomEllipse::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() || geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { ret = this->getSketchObjectPtr()->addGeometry(geo,isConstruction); } else { std::stringstream str; str << "Unsupported geometry type: " << geo->getTypeId().getName(); PyErr_SetString(PyExc_TypeError, str.str().c_str()); return 0; } return Py::new_reference_to(Py::Int(ret)); } else if (PyObject_TypeCheck(pcObj, &(PyList_Type)) || PyObject_TypeCheck(pcObj, &(PyTuple_Type))) { std::vector<Part::Geometry *> geoList; std::vector<boost::shared_ptr <Part::Geometry> > tmpList; Py::Sequence list(pcObj); for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { if (PyObject_TypeCheck((*it).ptr(), &(Part::GeometryPy::Type))) { Part::Geometry *geo = static_cast<Part::GeometryPy*>((*it).ptr())->getGeometryPtr(); // An arc created with Part.Arc will be converted into a Part.ArcOfCircle if (geo->getTypeId() == Part::GeomTrimmedCurve::getClassTypeId()) { Handle_Geom_TrimmedCurve trim = Handle_Geom_TrimmedCurve::DownCast(geo->handle()); Handle_Geom_Circle circle = Handle_Geom_Circle::DownCast(trim->BasisCurve()); Handle_Geom_Ellipse ellipse = Handle_Geom_Ellipse::DownCast(trim->BasisCurve()); if (!circle.IsNull()) { // create the definition struct for that geom boost::shared_ptr<Part::GeomArcOfCircle> aoc(new Part::GeomArcOfCircle()); aoc->setHandle(trim); geoList.push_back(aoc.get()); tmpList.push_back(aoc); } else if (!ellipse.IsNull()) { // create the definition struct for that geom boost::shared_ptr<Part::GeomArcOfEllipse> aoe(new Part::GeomArcOfEllipse()); aoe->setHandle(trim); geoList.push_back(aoe.get()); tmpList.push_back(aoe); } else { std::stringstream str; str << "Unsupported geometry type: " << geo->getTypeId().getName(); PyErr_SetString(PyExc_TypeError, str.str().c_str()); return 0; } } else if (geo->getTypeId() == Part::GeomPoint::getClassTypeId() || geo->getTypeId() == Part::GeomCircle::getClassTypeId() || geo->getTypeId() == Part::GeomEllipse::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() || geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { geoList.push_back(geo); } else { std::stringstream str; str << "Unsupported geometry type: " << geo->getTypeId().getName(); PyErr_SetString(PyExc_TypeError, str.str().c_str()); return 0; } } } int ret = this->getSketchObjectPtr()->addGeometry(geoList,isConstruction) + 1; std::size_t numGeo = geoList.size(); Py::Tuple tuple(numGeo); for (std::size_t i=0; i<numGeo; ++i) { int geoId = ret - int(numGeo - i); tuple.setItem(i, Py::Int(geoId)); } return Py::new_reference_to(tuple); } std::string error = std::string("type must be 'Geometry' or list of 'Geometry', not "); error += pcObj->ob_type->tp_name; throw Py::TypeError(error); }
void SketcherValidation::on_findButton_clicked() { std::vector<VertexIds> vertexIds; const std::vector<Part::Geometry *>& geom = sketch->getInternalGeometry(); for (std::size_t i=0; i<geom.size(); i++) { Part::Geometry* g = geom[i]; if (g->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { const Part::GeomLineSegment *segm = static_cast<const Part::GeomLineSegment*>(g); VertexIds id; id.GeoId = (int)i; id.PosId = Sketcher::start; id.v = segm->getStartPoint(); vertexIds.push_back(id); id.GeoId = (int)i; id.PosId = Sketcher::end; id.v = segm->getEndPoint(); vertexIds.push_back(id); } else if (g->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { const Part::GeomArcOfCircle *segm = static_cast<const Part::GeomArcOfCircle*>(g); VertexIds id; id.GeoId = (int)i; id.PosId = Sketcher::start; id.v = segm->getStartPoint(/*emulateCCW=*/true); vertexIds.push_back(id); id.GeoId = (int)i; id.PosId = Sketcher::end; id.v = segm->getEndPoint(/*emulateCCW=*/true); vertexIds.push_back(id); } else if (g->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) { const Part::GeomArcOfEllipse *segm = static_cast<const Part::GeomArcOfEllipse*>(g); VertexIds id; id.GeoId = (int)i; id.PosId = Sketcher::start; id.v = segm->getStartPoint(/*emulateCCW=*/true); vertexIds.push_back(id); id.GeoId = (int)i; id.PosId = Sketcher::end; id.v = segm->getEndPoint(/*emulateCCW=*/true); vertexIds.push_back(id); } else if (g->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId()) { const Part::GeomArcOfHyperbola *segm = static_cast<const Part::GeomArcOfHyperbola*>(g); VertexIds id; id.GeoId = (int)i; id.PosId = Sketcher::start; id.v = segm->getStartPoint(); vertexIds.push_back(id); id.GeoId = (int)i; id.PosId = Sketcher::end; id.v = segm->getEndPoint(); vertexIds.push_back(id); } else if (g->getTypeId() == Part::GeomArcOfParabola::getClassTypeId()) { const Part::GeomArcOfParabola *segm = dynamic_cast<const Part::GeomArcOfParabola*>(g); VertexIds id; id.GeoId = (int)i; id.PosId = Sketcher::start; id.v = segm->getStartPoint(); vertexIds.push_back(id); id.GeoId = (int)i; id.PosId = Sketcher::end; id.v = segm->getEndPoint(); vertexIds.push_back(id); } } std::set<ConstraintIds, Constraint_Less> coincidences; double prec = Precision::Confusion(); QVariant v = ui->comboBoxTolerance->itemData(ui->comboBoxTolerance->currentIndex()); if (v.isValid()) prec = v.toDouble(); else prec = QLocale::system().toDouble(ui->comboBoxTolerance->currentText()); std::sort(vertexIds.begin(), vertexIds.end(), Vertex_Less(prec)); std::vector<VertexIds>::iterator vt = vertexIds.begin(); Vertex_EqualTo pred(prec); while (vt < vertexIds.end()) { // get first item whose adjacent element has the same vertex coordinates vt = std::adjacent_find(vt, vertexIds.end(), pred); if (vt < vertexIds.end()) { std::vector<VertexIds>::iterator vn; for (vn = vt+1; vn != vertexIds.end(); ++vn) { if (pred(*vt,*vn)) { ConstraintIds id; id.v = vt->v; id.First = vt->GeoId; id.FirstPos = vt->PosId; id.Second = vn->GeoId; id.SecondPos = vn->PosId; coincidences.insert(id); } else { break; } } vt = vn; } } std::vector<Sketcher::Constraint*> constraint = sketch->Constraints.getValues(); for (std::vector<Sketcher::Constraint*>::iterator it = constraint.begin(); it != constraint.end(); ++it) { if ((*it)->Type == Sketcher::Coincident) { ConstraintIds id; id.First = (*it)->First; id.FirstPos = (*it)->FirstPos; id.Second = (*it)->Second; id.SecondPos = (*it)->SecondPos; std::set<ConstraintIds, Constraint_Less>::iterator pos = coincidences.find(id); if (pos != coincidences.end()) { coincidences.erase(pos); } } } this->vertexConstraints.clear(); this->vertexConstraints.reserve(coincidences.size()); std::vector<Base::Vector3d> points; points.reserve(coincidences.size()); for (std::set<ConstraintIds, Constraint_Less>::iterator it = coincidences.begin(); it != coincidences.end(); ++it) { this->vertexConstraints.push_back(*it); points.push_back(it->v); } hidePoints(); if (this->vertexConstraints.empty()) { QMessageBox::information(this, tr("No missing coincidences"), tr("No missing coincidences found")); ui->fixButton->setEnabled(false); } else { showPoints(points); QMessageBox::warning(this, tr("Missing coincidences"), tr("%1 missing coincidences found").arg(this->vertexConstraints.size())); ui->fixButton->setEnabled(true); } }
void SketcherValidation::on_findButton_clicked() { std::vector<VertexIds> vertexIds; const std::vector<Part::Geometry *>& geom = sketch->getInternalGeometry(); for (std::size_t i=0; i<geom.size(); i++) { Part::Geometry* g = geom[i]; if(g->Construction && ui->checkBoxIgnoreConstruction->isChecked()) continue; if (g->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { const Part::GeomLineSegment *segm = static_cast<const Part::GeomLineSegment*>(g); VertexIds id; id.GeoId = (int)i; id.PosId = Sketcher::start; id.v = segm->getStartPoint(); vertexIds.push_back(id); id.GeoId = (int)i; id.PosId = Sketcher::end; id.v = segm->getEndPoint(); vertexIds.push_back(id); } else if (g->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { const Part::GeomArcOfCircle *segm = static_cast<const Part::GeomArcOfCircle*>(g); VertexIds id; id.GeoId = (int)i; id.PosId = Sketcher::start; id.v = segm->getStartPoint(/*emulateCCW=*/true); vertexIds.push_back(id); id.GeoId = (int)i; id.PosId = Sketcher::end; id.v = segm->getEndPoint(/*emulateCCW=*/true); vertexIds.push_back(id); } else if (g->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) { const Part::GeomArcOfEllipse *segm = static_cast<const Part::GeomArcOfEllipse*>(g); VertexIds id; id.GeoId = (int)i; id.PosId = Sketcher::start; id.v = segm->getStartPoint(/*emulateCCW=*/true); vertexIds.push_back(id); id.GeoId = (int)i; id.PosId = Sketcher::end; id.v = segm->getEndPoint(/*emulateCCW=*/true); vertexIds.push_back(id); } else if (g->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId()) { const Part::GeomArcOfHyperbola *segm = static_cast<const Part::GeomArcOfHyperbola*>(g); VertexIds id; id.GeoId = (int)i; id.PosId = Sketcher::start; id.v = segm->getStartPoint(); vertexIds.push_back(id); id.GeoId = (int)i; id.PosId = Sketcher::end; id.v = segm->getEndPoint(); vertexIds.push_back(id); } else if (g->getTypeId() == Part::GeomArcOfParabola::getClassTypeId()) { const Part::GeomArcOfParabola *segm = static_cast<const Part::GeomArcOfParabola*>(g); VertexIds id; id.GeoId = (int)i; id.PosId = Sketcher::start; id.v = segm->getStartPoint(); vertexIds.push_back(id); id.GeoId = (int)i; id.PosId = Sketcher::end; id.v = segm->getEndPoint(); vertexIds.push_back(id); } else if (g->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()) { const Part::GeomBSplineCurve *segm = static_cast<const Part::GeomBSplineCurve*>(g); VertexIds id; id.GeoId = (int)i; id.PosId = Sketcher::start; id.v = segm->getStartPoint(); vertexIds.push_back(id); id.GeoId = (int)i; id.PosId = Sketcher::end; id.v = segm->getEndPoint(); vertexIds.push_back(id); } } double prec = Precision::Confusion(); QVariant v = ui->comboBoxTolerance->itemData(ui->comboBoxTolerance->currentIndex()); if (v.isValid()) prec = v.toDouble(); else prec = QLocale::system().toDouble(ui->comboBoxTolerance->currentText()); std::sort(vertexIds.begin(), vertexIds.end(), Vertex_Less(prec)); std::vector<VertexIds>::iterator vt = vertexIds.begin(); Vertex_EqualTo pred(prec); std::list<ConstraintIds> coincidences; // Make a list of constraint we expect for coincident vertexes while (vt < vertexIds.end()) { // get first item whose adjacent element has the same vertex coordinates vt = std::adjacent_find(vt, vertexIds.end(), pred); if (vt < vertexIds.end()) { std::vector<VertexIds>::iterator vn; for (vn = vt+1; vn != vertexIds.end(); ++vn) { if (pred(*vt,*vn)) { ConstraintIds id; id.v = vt->v; id.First = vt->GeoId; id.FirstPos = vt->PosId; id.Second = vn->GeoId; id.SecondPos = vn->PosId; coincidences.push_back(id); } else { break; } } vt = vn; } } // Go through the available 'Coincident', 'Tangent' or 'Perpendicular' constraints // and check which of them is forcing two vertexes to be coincident. // If there is none but two vertexes can be considered equal a coincident constraint is missing. std::vector<Sketcher::Constraint*> constraint = sketch->Constraints.getValues(); for (std::vector<Sketcher::Constraint*>::iterator it = constraint.begin(); it != constraint.end(); ++it) { if ((*it)->Type == Sketcher::Coincident || (*it)->Type == Sketcher::Tangent || (*it)->Type == Sketcher::Perpendicular) { ConstraintIds id; id.First = (*it)->First; id.FirstPos = (*it)->FirstPos; id.Second = (*it)->Second; id.SecondPos = (*it)->SecondPos; std::list<ConstraintIds>::iterator pos = std::find_if (coincidences.begin(), coincidences.end(), Constraint_Equal(id)); if (pos != coincidences.end()) { coincidences.erase(pos); } } } this->vertexConstraints.clear(); this->vertexConstraints.reserve(coincidences.size()); std::vector<Base::Vector3d> points; points.reserve(coincidences.size()); for (std::list<ConstraintIds>::iterator it = coincidences.begin(); it != coincidences.end(); ++it) { this->vertexConstraints.push_back(*it); points.push_back(it->v); } hidePoints(); if (this->vertexConstraints.empty()) { QMessageBox::information(this, tr("No missing coincidences"), tr("No missing coincidences found")); ui->fixButton->setEnabled(false); } else { showPoints(points); QMessageBox::warning(this, tr("Missing coincidences"), tr("%1 missing coincidences found").arg(this->vertexConstraints.size())); ui->fixButton->setEnabled(true); } }