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:
Abdullah Tahiri 2015-07-16 05:00:00 +02:00 committed by wmayer
parent fbc6ed5c77
commit 359e9a5d78
6 changed files with 640 additions and 2 deletions

View File

@ -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())

View File

@ -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

View File

@ -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>

View File

@ -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;

View File

@ -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());
}

View File

@ -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>