Sketcher: New Feature: Symmetric tool
===================================== Creates geometry symmetric to the selected one with respect to the last selected point or line. It does not support the following constraints: - Angle - Horiz/vertical distance - SnellLaw Horizontal and Vertical (directional) dimensions removed from the the copying process when created on a single edge (by picking one edge instead of two points), i.e. Constraint involving only one GeoId at "First".
This commit is contained in:
parent
fbc6ed5c77
commit
359e9a5d78
|
@ -50,6 +50,7 @@
|
|||
#include <Base/Reader.h>
|
||||
#include <Base/Tools.h>
|
||||
#include <Base/Console.h>
|
||||
#include <Base/Vector3D.h>
|
||||
|
||||
#include <Mod/Part/App/Geometry.h>
|
||||
|
||||
|
@ -1613,6 +1614,397 @@ int SketchObject::trim(int GeoId, const Base::Vector3d& point)
|
|||
return -1;
|
||||
}
|
||||
|
||||
int SketchObject::addSymmetric(const std::vector<int> &geoIdList, int refGeoId, Sketcher::PointPos refPosId/*=Sketcher::none*/)
|
||||
{
|
||||
const std::vector< Part::Geometry * > &geovals = getInternalGeometry();
|
||||
std::vector< Part::Geometry * > newgeoVals(geovals);
|
||||
|
||||
const std::vector< Constraint * > &constrvals = this->Constraints.getValues();
|
||||
std::vector< Constraint * > newconstrVals(constrvals);
|
||||
|
||||
int cgeoid = getHighestCurveIndex()+1;
|
||||
|
||||
std::map<int, int> geoIdMap;
|
||||
std::map<int, bool> isStartEndInverted;
|
||||
|
||||
// reference is a line
|
||||
if(refPosId == Sketcher::none)
|
||||
{
|
||||
const Part::Geometry *georef = getGeometry(refGeoId);
|
||||
if(georef->getTypeId() != Part::GeomLineSegment::getClassTypeId()) {
|
||||
Base::Console().Error("Reference for symmetric is neither a point nor a line.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const Part::GeomLineSegment *refGeoLine = static_cast<const Part::GeomLineSegment *>(georef);
|
||||
//line
|
||||
Base::Vector3d refstart = refGeoLine->getStartPoint();
|
||||
Base::Vector3d vectline = refGeoLine->getEndPoint()-refstart;
|
||||
|
||||
for (std::vector<int>::const_iterator it = geoIdList.begin(); it != geoIdList.end(); ++it) {
|
||||
const Part::Geometry *geo = getGeometry(*it);
|
||||
Part::Geometry *geosym = geo->clone();
|
||||
|
||||
// Handle Geometry
|
||||
if(geosym->getTypeId() == Part::GeomLineSegment::getClassTypeId()){
|
||||
Part::GeomLineSegment *geosymline = static_cast<Part::GeomLineSegment *>(geosym);
|
||||
Base::Vector3d sp = geosymline->getStartPoint();
|
||||
Base::Vector3d ep = geosymline->getEndPoint();
|
||||
|
||||
|
||||
geosymline->setPoints(sp+2.0*(sp.Perpendicular(refGeoLine->getStartPoint(),vectline)-sp),
|
||||
ep+2.0*(ep.Perpendicular(refGeoLine->getStartPoint(),vectline)-ep));
|
||||
isStartEndInverted.insert(std::make_pair(*it, false));
|
||||
}
|
||||
else if(geosym->getTypeId() == Part::GeomCircle::getClassTypeId()){
|
||||
Part::GeomCircle *geosymcircle = static_cast<Part::GeomCircle *>(geosym);
|
||||
Base::Vector3d cp = geosymcircle->getCenter();
|
||||
|
||||
geosymcircle->setCenter(cp+2.0*(cp.Perpendicular(refGeoLine->getStartPoint(),vectline)-cp));
|
||||
isStartEndInverted.insert(std::make_pair(*it, false));
|
||||
}
|
||||
else if(geosym->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()){
|
||||
Part::GeomArcOfCircle *geoaoc = static_cast<Part::GeomArcOfCircle *>(geosym);
|
||||
Base::Vector3d sp = geoaoc->getStartPoint(true);
|
||||
Base::Vector3d ep = geoaoc->getEndPoint(true);
|
||||
Base::Vector3d cp = geoaoc->getCenter();
|
||||
|
||||
Base::Vector3d ssp = sp+2.0*(sp.Perpendicular(refGeoLine->getStartPoint(),vectline)-sp);
|
||||
Base::Vector3d sep = ep+2.0*(ep.Perpendicular(refGeoLine->getStartPoint(),vectline)-ep);
|
||||
Base::Vector3d scp = cp+2.0*(cp.Perpendicular(refGeoLine->getStartPoint(),vectline)-cp);
|
||||
|
||||
double theta1 = Base::fmod(atan2(sep.y - scp.y, sep.x - scp.x), 2.f*M_PI);
|
||||
double theta2 = Base::fmod(atan2(ssp.y - scp.y, ssp.x - scp.x), 2.f*M_PI);
|
||||
|
||||
geoaoc->setCenter(scp);
|
||||
geoaoc->setRange(theta1,theta2,true);
|
||||
isStartEndInverted.insert(std::make_pair(*it, true));
|
||||
}
|
||||
else if(geosym->getTypeId() == Part::GeomEllipse::getClassTypeId()){
|
||||
Part::GeomEllipse *geosymellipse = static_cast<Part::GeomEllipse *>(geosym);
|
||||
Base::Vector3d cp = geosymellipse->getCenter();
|
||||
|
||||
Base::Vector3d majdir = geosymellipse->getMajorAxisDir();
|
||||
double majord=geosymellipse->getMajorRadius();
|
||||
double minord=geosymellipse->getMinorRadius();
|
||||
double df= sqrt(majord*majord-minord*minord);
|
||||
Base::Vector3d f1 = cp + df * majdir;
|
||||
|
||||
Base::Vector3d sf1 = f1+2.0*(f1.Perpendicular(refGeoLine->getStartPoint(),vectline)-f1);
|
||||
Base::Vector3d scp = cp+2.0*(cp.Perpendicular(refGeoLine->getStartPoint(),vectline)-cp);
|
||||
|
||||
geosymellipse->setMajorAxisDir(sf1-scp);
|
||||
|
||||
geosymellipse->setCenter(scp);
|
||||
isStartEndInverted.insert(std::make_pair(*it, false));
|
||||
}
|
||||
else if(geosym->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()){
|
||||
Part::GeomArcOfEllipse *geosymaoe = static_cast<Part::GeomArcOfEllipse *>(geosym);
|
||||
Base::Vector3d cp = geosymaoe->getCenter();
|
||||
Base::Vector3d sp = geosymaoe->getStartPoint(true);
|
||||
Base::Vector3d ep = geosymaoe->getEndPoint(true);
|
||||
|
||||
Base::Vector3d majdir = geosymaoe->getMajorAxisDir();
|
||||
double majord=geosymaoe->getMajorRadius();
|
||||
double minord=geosymaoe->getMinorRadius();
|
||||
double df= sqrt(majord*majord-minord*minord);
|
||||
Base::Vector3d f1 = cp + df * majdir;
|
||||
|
||||
Base::Vector3d sf1 = f1+2.0*(f1.Perpendicular(refGeoLine->getStartPoint(),vectline)-f1);
|
||||
Base::Vector3d scp = cp+2.0*(cp.Perpendicular(refGeoLine->getStartPoint(),vectline)-cp);
|
||||
Base::Vector3d ssp = sp+2.0*(sp.Perpendicular(refGeoLine->getStartPoint(),vectline)-sp);
|
||||
Base::Vector3d sep = ep+2.0*(ep.Perpendicular(refGeoLine->getStartPoint(),vectline)-ep);
|
||||
|
||||
geosymaoe->setMajorAxisDir(sf1-scp);
|
||||
|
||||
geosymaoe->setCenter(scp);
|
||||
|
||||
double theta1,theta2;
|
||||
geosymaoe->closestParameter(sep,theta1);
|
||||
geosymaoe->closestParameter(ssp,theta2);
|
||||
|
||||
geosymaoe->setRange(theta1,theta2,true);
|
||||
isStartEndInverted.insert(std::make_pair(*it, true));
|
||||
}
|
||||
else if(geosym->getTypeId() == Part::GeomPoint::getClassTypeId()){
|
||||
Part::GeomPoint *geosympoint = static_cast<Part::GeomPoint *>(geosym);
|
||||
Base::Vector3d cp = geosympoint->getPoint();
|
||||
|
||||
geosympoint->setPoint(cp+2.0*(cp.Perpendicular(refGeoLine->getStartPoint(),vectline)-cp));
|
||||
isStartEndInverted.insert(std::make_pair(*it, false));
|
||||
}
|
||||
else {
|
||||
Base::Console().Error("Unsupported Geometry!! Just copying it.\n");
|
||||
isStartEndInverted.insert(std::make_pair(*it, false));
|
||||
}
|
||||
|
||||
newgeoVals.push_back(geosym);
|
||||
geoIdMap.insert(std::make_pair(*it, cgeoid));
|
||||
cgeoid++;
|
||||
}
|
||||
|
||||
}
|
||||
else //reference is a point
|
||||
{
|
||||
Vector3d refpoint;
|
||||
const Part::Geometry *georef = getGeometry(refGeoId);
|
||||
|
||||
if (georef->getTypeId() == Part::GeomPoint::getClassTypeId()) {
|
||||
refpoint = static_cast<const Part::GeomPoint *>(georef)->getPoint();
|
||||
}
|
||||
else if ( refGeoId == -1 && refPosId == Sketcher::start) {
|
||||
refpoint = Vector3d(0,0,0);
|
||||
}
|
||||
else {
|
||||
switch(refPosId){
|
||||
case Sketcher::start:
|
||||
if(georef->getTypeId() == Part::GeomLineSegment::getClassTypeId()){
|
||||
const Part::GeomLineSegment *geosymline = static_cast<const Part::GeomLineSegment *>(georef);
|
||||
refpoint = geosymline->getStartPoint();
|
||||
}
|
||||
else if(georef->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()){
|
||||
const Part::GeomArcOfCircle *geoaoc = static_cast<const Part::GeomArcOfCircle *>(georef);
|
||||
refpoint = geoaoc->getStartPoint(true);
|
||||
}
|
||||
else if(georef->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()){
|
||||
const Part::GeomArcOfEllipse *geosymaoe = static_cast<const Part::GeomArcOfEllipse *>(georef);
|
||||
refpoint = geosymaoe->getStartPoint(true);
|
||||
}
|
||||
break;
|
||||
case Sketcher::end:
|
||||
if(georef->getTypeId() == Part::GeomLineSegment::getClassTypeId()){
|
||||
const Part::GeomLineSegment *geosymline = static_cast<const Part::GeomLineSegment *>(georef);
|
||||
refpoint = geosymline->getEndPoint();
|
||||
}
|
||||
else if(georef->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()){
|
||||
const Part::GeomArcOfCircle *geoaoc = static_cast<const Part::GeomArcOfCircle *>(georef);
|
||||
refpoint = geoaoc->getEndPoint(true);
|
||||
}
|
||||
else if(georef->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()){
|
||||
const Part::GeomArcOfEllipse *geosymaoe = static_cast<const Part::GeomArcOfEllipse *>(georef);
|
||||
refpoint = geosymaoe->getEndPoint(true);
|
||||
}
|
||||
break;
|
||||
case Sketcher::mid:
|
||||
if(georef->getTypeId() == Part::GeomCircle::getClassTypeId()){
|
||||
const Part::GeomCircle *geosymcircle = static_cast<const Part::GeomCircle *>(georef);
|
||||
refpoint = geosymcircle->getCenter();
|
||||
}
|
||||
else if(georef->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()){
|
||||
const Part::GeomArcOfCircle *geoaoc = static_cast<const Part::GeomArcOfCircle *>(georef);
|
||||
refpoint = geoaoc->getCenter();
|
||||
}
|
||||
else if(georef->getTypeId() == Part::GeomEllipse::getClassTypeId()){
|
||||
const Part::GeomEllipse *geosymellipse = static_cast<const Part::GeomEllipse *>(georef);
|
||||
refpoint = geosymellipse->getCenter();
|
||||
}
|
||||
else if(georef->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()){
|
||||
const Part::GeomArcOfEllipse *geosymaoe = static_cast<const Part::GeomArcOfEllipse *>(georef);
|
||||
refpoint = geosymaoe->getCenter();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Base::Console().Error("Wrong PointPosId.\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
for (std::vector<int>::const_iterator it = geoIdList.begin(); it != geoIdList.end(); ++it) {
|
||||
const Part::Geometry *geo = getGeometry(*it);
|
||||
Part::Geometry *geosym = geo->clone();
|
||||
|
||||
// Handle Geometry
|
||||
if(geosym->getTypeId() == Part::GeomLineSegment::getClassTypeId()){
|
||||
Part::GeomLineSegment *geosymline = static_cast<Part::GeomLineSegment *>(geosym);
|
||||
Base::Vector3d sp = geosymline->getStartPoint();
|
||||
Base::Vector3d ep = geosymline->getEndPoint();
|
||||
Base::Vector3d ssp = sp + 2.0*(refpoint-sp);
|
||||
Base::Vector3d sep = ep + 2.0*(refpoint-ep);
|
||||
|
||||
geosymline->setPoints(ssp, sep);
|
||||
isStartEndInverted.insert(std::make_pair(*it, false));
|
||||
}
|
||||
else if(geosym->getTypeId() == Part::GeomCircle::getClassTypeId()){
|
||||
Part::GeomCircle *geosymcircle = static_cast<Part::GeomCircle *>(geosym);
|
||||
Base::Vector3d cp = geosymcircle->getCenter();
|
||||
|
||||
geosymcircle->setCenter(cp + 2.0*(refpoint-cp));
|
||||
isStartEndInverted.insert(std::make_pair(*it, false));
|
||||
}
|
||||
else if(geosym->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()){
|
||||
Part::GeomArcOfCircle *geoaoc = static_cast<Part::GeomArcOfCircle *>(geosym);
|
||||
Base::Vector3d sp = geoaoc->getStartPoint(true);
|
||||
Base::Vector3d ep = geoaoc->getEndPoint(true);
|
||||
Base::Vector3d cp = geoaoc->getCenter();
|
||||
|
||||
Base::Vector3d ssp = sp + 2.0*(refpoint-sp);
|
||||
Base::Vector3d sep = ep + 2.0*(refpoint-ep);
|
||||
Base::Vector3d scp = cp + 2.0*(refpoint-cp);
|
||||
|
||||
double theta1 = Base::fmod(atan2(ssp.y - scp.y, ssp.x - scp.x), 2.f*M_PI);
|
||||
double theta2 = Base::fmod(atan2(sep.y - scp.y, sep.x - scp.x), 2.f*M_PI);
|
||||
|
||||
geoaoc->setCenter(scp);
|
||||
geoaoc->setRange(theta1,theta2,true);
|
||||
isStartEndInverted.insert(std::make_pair(*it, false));
|
||||
}
|
||||
else if(geosym->getTypeId() == Part::GeomEllipse::getClassTypeId()){
|
||||
Part::GeomEllipse *geosymellipse = static_cast<Part::GeomEllipse *>(geosym);
|
||||
Base::Vector3d cp = geosymellipse->getCenter();
|
||||
|
||||
Base::Vector3d majdir = geosymellipse->getMajorAxisDir();
|
||||
double majord=geosymellipse->getMajorRadius();
|
||||
double minord=geosymellipse->getMinorRadius();
|
||||
double df= sqrt(majord*majord-minord*minord);
|
||||
Base::Vector3d f1 = cp + df * majdir;
|
||||
|
||||
Base::Vector3d sf1 = f1 + 2.0*(refpoint-f1);
|
||||
Base::Vector3d scp = cp + 2.0*(refpoint-cp);
|
||||
|
||||
geosymellipse->setMajorAxisDir(sf1-scp);
|
||||
|
||||
geosymellipse->setCenter(scp);
|
||||
isStartEndInverted.insert(std::make_pair(*it, false));
|
||||
}
|
||||
else if(geosym->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()){
|
||||
Part::GeomArcOfEllipse *geosymaoe = static_cast<Part::GeomArcOfEllipse *>(geosym);
|
||||
Base::Vector3d cp = geosymaoe->getCenter();
|
||||
Base::Vector3d sp = geosymaoe->getStartPoint(true);
|
||||
Base::Vector3d ep = geosymaoe->getEndPoint(true);
|
||||
|
||||
Base::Vector3d majdir = geosymaoe->getMajorAxisDir();
|
||||
double majord=geosymaoe->getMajorRadius();
|
||||
double minord=geosymaoe->getMinorRadius();
|
||||
double df= sqrt(majord*majord-minord*minord);
|
||||
Base::Vector3d f1 = cp + df * majdir;
|
||||
|
||||
Base::Vector3d sf1 = f1 + 2.0*(refpoint-f1);
|
||||
Base::Vector3d scp = cp + 2.0*(refpoint-cp);
|
||||
Base::Vector3d ssp = sp + 2.0*(refpoint-sp);
|
||||
Base::Vector3d sep = ep + 2.0*(refpoint-ep);
|
||||
|
||||
geosymaoe->setMajorAxisDir(sf1-scp);
|
||||
|
||||
geosymaoe->setCenter(scp);
|
||||
|
||||
double theta1,theta2;
|
||||
geosymaoe->closestParameter(ssp,theta1);
|
||||
geosymaoe->closestParameter(sep,theta2);
|
||||
|
||||
geosymaoe->setRange(theta1,theta2,true);
|
||||
isStartEndInverted.insert(std::make_pair(*it, false));
|
||||
}
|
||||
else if(geosym->getTypeId() == Part::GeomPoint::getClassTypeId()){
|
||||
Part::GeomPoint *geosympoint = static_cast<Part::GeomPoint *>(geosym);
|
||||
Base::Vector3d cp = geosympoint->getPoint();
|
||||
|
||||
geosympoint->setPoint(cp + 2.0*(refpoint-cp));
|
||||
isStartEndInverted.insert(std::make_pair(*it, false));
|
||||
}
|
||||
else {
|
||||
Base::Console().Error("Unsupported Geometry!! Just copying it.\n");
|
||||
isStartEndInverted.insert(std::make_pair(*it, false));
|
||||
}
|
||||
|
||||
newgeoVals.push_back(geosym);
|
||||
geoIdMap.insert(std::make_pair(*it, cgeoid));
|
||||
cgeoid++;
|
||||
}
|
||||
}
|
||||
|
||||
for (std::vector<Constraint *>::const_iterator it = constrvals.begin(); it != constrvals.end(); ++it) {
|
||||
|
||||
std::vector<int>::const_iterator fit=std::find(geoIdList.begin(), geoIdList.end(), (*it)->First);
|
||||
|
||||
if(fit != geoIdList.end()) { // if First of constraint is in geoIdList
|
||||
|
||||
if( (*it)->Second == Constraint::GeoUndef /*&& (*it)->Third == Constraint::GeoUndef*/) {
|
||||
if((*it)->Type != Sketcher::DistanceX &&
|
||||
(*it)->Type != Sketcher::DistanceY) {
|
||||
|
||||
Constraint *constNew = (*it)->clone();
|
||||
constNew->First = geoIdMap[(*it)->First];
|
||||
newconstrVals.push_back(constNew);
|
||||
}
|
||||
}
|
||||
else { // other geoids intervene in this constraint
|
||||
|
||||
std::vector<int>::const_iterator sit=std::find(geoIdList.begin(), geoIdList.end(), (*it)->Second);
|
||||
|
||||
if(sit != geoIdList.end()) { // Second is also in the list
|
||||
|
||||
if( (*it)->Third == Constraint::GeoUndef ) {
|
||||
if((*it)->Type == Sketcher::Coincident ||
|
||||
(*it)->Type == Sketcher::Perpendicular ||
|
||||
(*it)->Type == Sketcher::Parallel ||
|
||||
(*it)->Type == Sketcher::Tangent ||
|
||||
(*it)->Type == Sketcher::Distance ||
|
||||
(*it)->Type == Sketcher::Equal ||
|
||||
(*it)->Type == Sketcher::Radius ||
|
||||
(*it)->Type == Sketcher::PointOnObject ){
|
||||
Constraint *constNew = (*it)->clone();
|
||||
constNew->First = geoIdMap[(*it)->First];
|
||||
constNew->Second = geoIdMap[(*it)->Second];
|
||||
if(isStartEndInverted[(*it)->First]){
|
||||
if((*it)->FirstPos == Sketcher::start)
|
||||
constNew->FirstPos = Sketcher::end;
|
||||
else if((*it)->FirstPos == Sketcher::end)
|
||||
constNew->FirstPos = Sketcher::start;
|
||||
}
|
||||
if(isStartEndInverted[(*it)->Second]){
|
||||
if((*it)->SecondPos == Sketcher::start)
|
||||
constNew->SecondPos = Sketcher::end;
|
||||
else if((*it)->SecondPos == Sketcher::end)
|
||||
constNew->SecondPos = Sketcher::start;
|
||||
}
|
||||
newconstrVals.push_back(constNew);
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::vector<int>::const_iterator tit=std::find(geoIdList.begin(), geoIdList.end(), (*it)->Third);
|
||||
|
||||
if(tit != geoIdList.end()) { // Third is also in the list
|
||||
Constraint *constNew = (*it)->clone();
|
||||
constNew->First = geoIdMap[(*it)->First];
|
||||
constNew->Second = geoIdMap[(*it)->Second];
|
||||
constNew->Third = geoIdMap[(*it)->Third];
|
||||
if(isStartEndInverted[(*it)->First]){
|
||||
if((*it)->FirstPos == Sketcher::start)
|
||||
constNew->FirstPos = Sketcher::end;
|
||||
else if((*it)->FirstPos == Sketcher::end)
|
||||
constNew->FirstPos = Sketcher::start;
|
||||
}
|
||||
if(isStartEndInverted[(*it)->Second]){
|
||||
if((*it)->SecondPos == Sketcher::start)
|
||||
constNew->SecondPos = Sketcher::end;
|
||||
else if((*it)->SecondPos == Sketcher::end)
|
||||
constNew->SecondPos = Sketcher::start;
|
||||
}
|
||||
if(isStartEndInverted[(*it)->Third]){
|
||||
if((*it)->ThirdPos == Sketcher::start)
|
||||
constNew->ThirdPos = Sketcher::end;
|
||||
else if((*it)->ThirdPos == Sketcher::end)
|
||||
constNew->ThirdPos = Sketcher::start;
|
||||
}
|
||||
newconstrVals.push_back(constNew);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Geometry.setValues(newgeoVals);
|
||||
Constraints.acceptGeometry(getCompleteGeometry());
|
||||
rebuildVertexIndex();
|
||||
|
||||
if( newconstrVals.size() > constrvals.size() )
|
||||
Constraints.setValues(newconstrVals);
|
||||
|
||||
return Geometry.getSize()-1;
|
||||
}
|
||||
|
||||
|
||||
int SketchObject::ExposeInternalGeometry(int GeoId)
|
||||
{
|
||||
if (GeoId < 0 || GeoId > getHighestCurveIndex())
|
||||
|
|
|
@ -150,6 +150,8 @@ public:
|
|||
|
||||
/// trim a curve
|
||||
int trim(int geoId, const Base::Vector3d& point);
|
||||
/// adds symmetric geometric elements with respect to the refGeoId (line or point)
|
||||
int addSymmetric(const std::vector<int> &geoIdList, int refGeoId, Sketcher::PointPos refPosId=Sketcher::none);
|
||||
/// Exposes all internal geometry of an object supporting internal geometry
|
||||
/*!
|
||||
* \return -1 on error
|
||||
|
|
|
@ -132,6 +132,11 @@
|
|||
<UserDocu>trim a curve with a given id at a given reference point</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="addSymmetric">
|
||||
<Documentation>
|
||||
<UserDocu>add a symmetric geometric objects to the sketch with respect to a reference point or line</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="ExposeInternalGeometry">
|
||||
<Documentation>
|
||||
<UserDocu>Exposes all internal geometry of an object supporting internal geometry</UserDocu>
|
||||
|
|
|
@ -754,6 +754,44 @@ PyObject* SketchObjectPy::trim(PyObject *args)
|
|||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* SketchObjectPy::addSymmetric(PyObject *args)
|
||||
{
|
||||
PyObject *pcObj;
|
||||
int refGeoId;
|
||||
int refPosId = Sketcher::none;
|
||||
if (!PyArg_ParseTuple(args, "Oi|i", &pcObj, &refGeoId, &refPosId))
|
||||
return 0;
|
||||
|
||||
if (PyObject_TypeCheck(pcObj, &(PyList_Type)) ||
|
||||
PyObject_TypeCheck(pcObj, &(PyTuple_Type))) {
|
||||
std::vector<int> geoIdList;
|
||||
Py::Sequence list(pcObj);
|
||||
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
|
||||
if (PyInt_Check((*it).ptr()))
|
||||
geoIdList.push_back(PyInt_AsLong((*it).ptr()));
|
||||
}
|
||||
|
||||
int ret = this->getSketchObjectPtr()->addSymmetric(geoIdList,refGeoId,(Sketcher::PointPos) refPosId) + 1;
|
||||
|
||||
if(ret == -1)
|
||||
throw Py::TypeError("Symmetric operation unsuccessful!");
|
||||
|
||||
std::size_t numGeo = geoIdList.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 list of GeoIds, not ");
|
||||
error += pcObj->ob_type->tp_name;
|
||||
throw Py::TypeError(error);
|
||||
}
|
||||
|
||||
|
||||
PyObject* SketchObjectPy::calculateAngleViaPoint(PyObject *args)
|
||||
{
|
||||
int GeoId1=0, GeoId2=0;
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
# include <Precision.hxx>
|
||||
#endif
|
||||
|
||||
#include <Base/Console.h>
|
||||
#include <App/Application.h>
|
||||
#include <Gui/Application.h>
|
||||
#include <Gui/Document.h>
|
||||
|
@ -971,6 +972,203 @@ bool CmdSketcherRestoreInternalAlignmentGeometry::isActive(void)
|
|||
return isSketcherAcceleratorActive( getActiveGuiDocument(), true );
|
||||
}
|
||||
|
||||
DEF_STD_CMD_A(CmdSketcherSymmetry);
|
||||
|
||||
CmdSketcherSymmetry::CmdSketcherSymmetry()
|
||||
:Command("Sketcher_Symmetry")
|
||||
{
|
||||
sAppModule = "Sketcher";
|
||||
sGroup = QT_TR_NOOP("Sketcher");
|
||||
sMenuText = QT_TR_NOOP("Symmetry");
|
||||
sToolTipText = QT_TR_NOOP("Creates symmetric geometry with respect to the last selected line or point");
|
||||
sWhatsThis = sToolTipText;
|
||||
sStatusTip = sToolTipText;
|
||||
sPixmap = "Sketcher_Symmetry";
|
||||
sAccel = "";
|
||||
eType = ForEdit;
|
||||
}
|
||||
|
||||
void CmdSketcherSymmetry::activated(int iMsg)
|
||||
{
|
||||
// get the selection
|
||||
std::vector<Gui::SelectionObject> selection = getSelection().getSelectionEx();
|
||||
Sketcher::SketchObject* Obj = dynamic_cast<Sketcher::SketchObject*>(selection[0].getObject());
|
||||
|
||||
// only one sketch with its subelements are allowed to be selected
|
||||
if (selection.size() != 1) {
|
||||
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
|
||||
QObject::tr("Select elements from a single sketch."));
|
||||
return;
|
||||
}
|
||||
|
||||
// get the needed lists and objects
|
||||
const std::vector<std::string> &SubNames = selection[0].getSubNames();
|
||||
const std::vector< Sketcher::Constraint * > &vals = Obj->Constraints.getValues();
|
||||
|
||||
std::string doc_name = Obj->getDocument()->getName();
|
||||
std::string obj_name = Obj->getNameInDocument();
|
||||
std::stringstream ss;
|
||||
|
||||
getSelection().clearSelection();
|
||||
|
||||
int nelements = SubNames.size();
|
||||
|
||||
int LastGeoId;
|
||||
Sketcher::PointPos LastPointPos = Sketcher::none;
|
||||
const Part::Geometry *LastGeo;
|
||||
typedef enum { invalid = -1, line = 0, point = 1 } GeoType;
|
||||
|
||||
GeoType lastgeotype = invalid;
|
||||
|
||||
// create python command with list of elements
|
||||
std::stringstream stream;
|
||||
int geoids = 0;
|
||||
|
||||
for (std::vector<std::string>::const_iterator it=SubNames.begin(); it != SubNames.end(); ++it) {
|
||||
// only handle non-external edges
|
||||
if ((it->size() > 4 && it->substr(0,4) == "Edge") ||
|
||||
(it->size() > 12 && it->substr(0,12) == "ExternalEdge")) {
|
||||
|
||||
if(it->substr(0,4) == "Edge") {
|
||||
LastGeoId = std::atoi(it->substr(4,4000).c_str()) - 1;
|
||||
LastPointPos = Sketcher::none;
|
||||
}
|
||||
else {
|
||||
LastGeoId = -std::atoi(it->substr(12,4000).c_str()) - 2;
|
||||
LastPointPos = Sketcher::none;
|
||||
}
|
||||
|
||||
// reference can be external or non-external
|
||||
LastGeo = Obj->getGeometry(LastGeoId);
|
||||
// Only for supported types
|
||||
if(LastGeo->getTypeId() == Part::GeomLineSegment::getClassTypeId())
|
||||
lastgeotype = line;
|
||||
else
|
||||
lastgeotype = invalid;
|
||||
|
||||
// lines to make symmetric (only non-external)
|
||||
if(LastGeoId>=0) {
|
||||
geoids++;
|
||||
stream << LastGeoId << ",";
|
||||
}
|
||||
}
|
||||
else if(it->size() > 6 && it->substr(0,6) == "Vertex"){
|
||||
// only if it is a GeomPoint
|
||||
int VtId = std::atoi(it->substr(6,4000).c_str()) - 1;
|
||||
int GeoId;
|
||||
Sketcher::PointPos PosId;
|
||||
Obj->getGeoVertexIndex(VtId, GeoId, PosId);
|
||||
if (Obj->getGeometry(GeoId)->getTypeId() == Part::GeomPoint::getClassTypeId()) {
|
||||
LastGeoId = GeoId;
|
||||
LastPointPos = Sketcher::start;
|
||||
lastgeotype = point;
|
||||
|
||||
// points to make symmetric
|
||||
if(LastGeoId>=0) {
|
||||
geoids++;
|
||||
stream << LastGeoId << ",";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool lastvertexoraxis=false;
|
||||
// check if last selected element is a Vertex, not being a GeomPoint
|
||||
if(SubNames.rbegin()->size() > 6 && SubNames.rbegin()->substr(0,6) == "Vertex"){
|
||||
int VtId = std::atoi(SubNames.rbegin()->substr(6,4000).c_str()) - 1;
|
||||
int GeoId;
|
||||
Sketcher::PointPos PosId;
|
||||
Obj->getGeoVertexIndex(VtId, GeoId, PosId);
|
||||
if (Obj->getGeometry(GeoId)->getTypeId() != Part::GeomPoint::getClassTypeId()) {
|
||||
LastGeoId = GeoId;
|
||||
LastPointPos = PosId;
|
||||
lastgeotype = point;
|
||||
lastvertexoraxis=true;
|
||||
}
|
||||
}
|
||||
// check if last selected element is horizontal axis
|
||||
else if(SubNames.rbegin()->size() == 6 && SubNames.rbegin()->substr(0,6) == "H_Axis"){
|
||||
LastGeoId = -1;
|
||||
LastPointPos = Sketcher::none;
|
||||
lastgeotype = line;
|
||||
lastvertexoraxis=true;
|
||||
}
|
||||
// check if last selected element is vertical axis
|
||||
else if(SubNames.rbegin()->size() == 6 && SubNames.rbegin()->substr(0,6) == "V_Axis"){
|
||||
LastGeoId = -2;
|
||||
LastPointPos = Sketcher::none;
|
||||
lastgeotype = line;
|
||||
lastvertexoraxis=true;
|
||||
}
|
||||
// check if last selected element is the root point
|
||||
else if(SubNames.rbegin()->size() == 9 && SubNames.rbegin()->substr(0,9) == "RootPoint"){
|
||||
LastGeoId = -1;
|
||||
LastPointPos = Sketcher::start;
|
||||
lastgeotype = point;
|
||||
lastvertexoraxis=true;
|
||||
}
|
||||
|
||||
if ( geoids < 2 || (geoids<1 && LastGeoId<0) || (geoids<1 && lastvertexoraxis) ) {
|
||||
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
|
||||
QObject::tr("A symmetric construction requires at least two geometric elements, the last geometric element being the reference for the symmetry construction."));
|
||||
return;
|
||||
}
|
||||
|
||||
if ( lastgeotype == invalid ) {
|
||||
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
|
||||
QObject::tr("The last element must be a point or a line serving as reference for the symmetry construction."));
|
||||
return;
|
||||
}
|
||||
|
||||
std::string geoIdList = stream.str();
|
||||
|
||||
// missing cases:
|
||||
// 1- Last element is an edge, and is V or H axis
|
||||
// 2- Last element is a point GeomPoint
|
||||
// 3- Last element is a point (Vertex)
|
||||
|
||||
if(LastGeoId>=0 && !lastvertexoraxis) {
|
||||
// if LastGeoId was added remove the last element
|
||||
int index = geoIdList.rfind(',');
|
||||
index = geoIdList.rfind(',',index-1);
|
||||
geoIdList.resize(index);
|
||||
}
|
||||
else {
|
||||
int index = geoIdList.rfind(',');
|
||||
geoIdList.resize(index);
|
||||
}
|
||||
|
||||
geoIdList.insert(0,1,'[');
|
||||
geoIdList.append(1,']');
|
||||
|
||||
Gui::Command::openCommand("Create Symmetric geometry");
|
||||
|
||||
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher");
|
||||
bool autoRecompute = hGrp->GetBool("AutoRecompute",false);
|
||||
|
||||
try{
|
||||
Gui::Command::doCommand(
|
||||
Gui::Command::Doc, "App.ActiveDocument.%s.addSymmetric(%s,%d,%d)",
|
||||
Obj->getNameInDocument(), geoIdList.c_str(), LastGeoId, LastPointPos
|
||||
);
|
||||
|
||||
Gui::Command::commitCommand();
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
Base::Console().Error("%s\n", e.what());
|
||||
Gui::Command::abortCommand();
|
||||
}
|
||||
|
||||
if(autoRecompute)
|
||||
Gui::Command::updateActive();
|
||||
else
|
||||
Obj->solve();
|
||||
}
|
||||
|
||||
bool CmdSketcherSymmetry::isActive(void)
|
||||
{
|
||||
return isSketcherAcceleratorActive( getActiveGuiDocument(), true );
|
||||
}
|
||||
|
||||
void CreateSketcherCommandsConstraintAccel(void)
|
||||
{
|
||||
|
@ -986,4 +1184,5 @@ void CreateSketcherCommandsConstraintAccel(void)
|
|||
rcCmdMgr.addCommand(new CmdSketcherSelectConflictingConstraints());
|
||||
rcCmdMgr.addCommand(new CmdSketcherSelectElementsAssociatedWithConstraints());
|
||||
rcCmdMgr.addCommand(new CmdSketcherRestoreInternalAlignmentGeometry());
|
||||
rcCmdMgr.addCommand(new CmdSketcherSymmetry());
|
||||
}
|
||||
|
|
|
@ -245,14 +245,16 @@ inline void SketcherAddWorkbenchTools<Gui::MenuItem>(Gui::MenuItem& consaccel){
|
|||
<< "Sketcher_SelectRedundantConstraints"
|
||||
<< "Sketcher_SelectConflictingConstraints"
|
||||
<< "Sketcher_SelectElementsAssociatedWithConstraints"
|
||||
<< "Sketcher_RestoreInternalAlignmentGeometry";
|
||||
<< "Sketcher_RestoreInternalAlignmentGeometry"
|
||||
<< "Sketcher_Symmetry";
|
||||
}
|
||||
template <>
|
||||
inline void SketcherAddWorkbenchTools<Gui::ToolBarItem>(Gui::ToolBarItem& consaccel){
|
||||
consaccel << "Sketcher_CloseShape"
|
||||
<< "Sketcher_ConnectLines"
|
||||
<< "Sketcher_SelectConstraints"
|
||||
<< "Sketcher_RestoreInternalAlignmentGeometry";
|
||||
<< "Sketcher_RestoreInternalAlignmentGeometry"
|
||||
<< "Sketcher_Symmetry";
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
|
Loading…
Reference in New Issue
Block a user