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 5958749b7a
commit 38256931af
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())