[Sketcher] Refactor SketchObject::addCopy()

if and for rearrangement for readability.
This commit is contained in:
Ajinkya Dahale
2024-08-02 23:46:36 +05:30
parent 6a3bbc195d
commit f008424ef5

View File

@@ -4939,9 +4939,15 @@ std::vector<Part::Geometry*> SketchObject::getSymmetric(const std::vector<int>&
return symmetricVals;
}
int SketchObject::addCopy(const std::vector<int>& geoIdList, const Base::Vector3d& displacement,
bool moveonly , bool clone , int csize , int rsize , bool constraindisplacement ,
double perpscale )
// clang-format on
int SketchObject::addCopy(const std::vector<int>& geoIdList,
const Base::Vector3d& displacement,
bool moveonly,
bool clone,
int csize,
int rsize,
bool constraindisplacement,
double perpscale)
{
// no need to check input data validity as this is an sketchobject managed operation.
Base::StateLocker lock(managedoperation, true);
@@ -4958,9 +4964,10 @@ int SketchObject::addCopy(const std::vector<int>& geoIdList, const Base::Vector3
std::vector<int> newgeoIdList(geoIdList);
if (newgeoIdList.empty()) {// default option to operate on all the geometry
for (int i = 0; i < int(geovals.size()); i++)
if (newgeoIdList.empty()) { // default option to operate on all the geometry
for (int i = 0; i < int(geovals.size()); i++) {
newgeoIdList.push_back(i);
}
}
int cgeoid = getHighestCurveIndex() + 1;
@@ -4984,478 +4991,494 @@ int SketchObject::addCopy(const std::vector<int>& geoIdList, const Base::Vector3
int x, y;
for (y = 0; y < rsize; y++) {
for (x = 0; x < csize; x++) {
// the reference for constraining array elements is the first valid point of the first
// element
if (x == 0 && y == 0) {
const Part::Geometry* geo = getGeometry(*(newgeoIdList.begin()));
auto makeCopyAtRowColumn = [&](int x, int y) {
// the reference for constraining array elements is the first valid point of the first
// element
if (x == 0 && y == 0) {
const Part::Geometry* geo = getGeometry(*(newgeoIdList.begin()));
auto gf = GeometryFacade::getFacade(geo);
auto gf = GeometryFacade::getFacade(geo);
if (gf->isInternalAligned() && !moveonly) {
// only add this geometry if the corresponding geometry it defines is also in
// the list.
int definedGeo = GeoEnum::GeoUndef;
if (gf->isInternalAligned() && !moveonly) {
// only add this geometry if the corresponding geometry it defines is also in
// the list.
for (auto c : Constraints.getValues()) {
if (c->Type == Sketcher::InternalAlignment
&& c->First == *(newgeoIdList.begin())) {
definedGeo = c->Second;
break;
}
}
auto constrIt = std::ranges::find_if(constrvals, [&newgeoIdList](auto c) {
return (c->Type == Sketcher::InternalAlignment
&& c->First == *(newgeoIdList.begin()));
});
if (std::ranges::find(newgeoIdList, definedGeo) == newgeoIdList.end()) {
// the first element setting the reference is an internal alignment
// geometry, wherein the geometry it defines is not part of the copy
// operation.
THROWM(Base::ValueError,
"A move/copy/array operation on an internal alignment geometry is "
"only possible together with the geometry it defines.")
}
int definedGeo =
(constrIt != constrvals.end()) ? (*constrIt)->Second : GeoEnum::GeoUndef;
if (std::ranges::find(newgeoIdList, definedGeo) == newgeoIdList.end()) {
// the first element setting the reference is an internal alignment
// geometry, wherein the geometry it defines is not part of the copy
// operation.
THROWM(Base::ValueError,
"A move/copy/array operation on an internal alignment geometry is "
"only possible together with the geometry it defines.");
}
}
refgeoid = *(newgeoIdList.begin());
currentrowfirstgeoid = refgeoid;
iterfirstgeoid = refgeoid;
if (geo->is<Part::GeomCircle>()
|| geo->is<Part::GeomEllipse>()) {
refposId = Sketcher::PointPos::mid;
}
else
refposId = Sketcher::PointPos::start;
continue;// the first element is already in place
refgeoid = *(newgeoIdList.begin());
currentrowfirstgeoid = refgeoid;
iterfirstgeoid = refgeoid;
if (geo->is<Part::GeomCircle>() || geo->is<Part::GeomEllipse>()) {
refposId = Sketcher::PointPos::mid;
}
else {
prevfirstgeoid = iterfirstgeoid;
iterfirstgeoid = cgeoid;
if (x == 0) {// if first element of second row
prevrowstartfirstgeoid = currentrowfirstgeoid;
currentrowfirstgeoid = cgeoid;
}
refposId = Sketcher::PointPos::start;
}
int index = 0;
for (std::vector<int>::const_iterator it = newgeoIdList.begin();
it != newgeoIdList.end();
++it, index++) {
const Part::Geometry* geo = getGeometry(*it);
return; // the first element is already in place
}
Part::Geometry* geocopy;
prevfirstgeoid = iterfirstgeoid;
auto gf = GeometryFacade::getFacade(geo);
iterfirstgeoid = cgeoid;
if (gf->isInternalAligned() && !moveonly) {
// only add this geometry if the corresponding geometry it defines is also in
// the list.
int definedGeo = GeoEnum::GeoUndef;
if (x == 0) { // if first element of second row
prevrowstartfirstgeoid = currentrowfirstgeoid;
currentrowfirstgeoid = cgeoid;
}
for (auto c : Constraints.getValues()) {
if (c->Type == Sketcher::InternalAlignment && c->First == *it) {
definedGeo = c->Second;
break;
}
}
int index = 0;
for (auto it = newgeoIdList.cbegin(); it != newgeoIdList.cend(); ++it, ++index) {
const Part::Geometry* geo = getGeometry(*it);
if (std::ranges::find(newgeoIdList, definedGeo)
== newgeoIdList.end()) {
// we should not copy internal alignment geometry, unless the element they
// define is also mirrored
continue;
}
Part::Geometry* geocopy;
auto gf = GeometryFacade::getFacade(geo);
if (gf->isInternalAligned() && !moveonly) {
// only add this geometry if the corresponding geometry it defines is also in
// the list.
int definedGeo = GeoEnum::GeoUndef;
auto constrIt = std::ranges::find_if(constrvals, [&it](auto c) {
return (c->Type == Sketcher::InternalAlignment && c->First == *it);
});
if (constrIt != constrvals.end()) {
definedGeo = (*constrIt)->Second;
}
// We have already cloned all geometry and constraints, we only need a copy if not
// moving
if (!moveonly) {
geocopy = geo->copy();
generateId(geocopy);
} else
geocopy = newgeoVals[*it];
// Handle Geometry
if (geocopy->is<Part::GeomLineSegment>()) {
Part::GeomLineSegment* geosymline =
static_cast<Part::GeomLineSegment*>(geocopy);
Base::Vector3d ep = geosymline->getEndPoint();
Base::Vector3d ssp = geosymline->getStartPoint() + double(x) * displacement
+ double(y) * perpendicularDisplacement;
geosymline->setPoints(
ssp, ep + double(x) * displacement + double(y) * perpendicularDisplacement);
if (it == newgeoIdList.begin())
iterfirstpoint = ssp;
}
else if (geocopy->is<Part::GeomCircle>()) {
auto* geosymcircle = static_cast<Part::GeomCircle*>(geocopy);
Base::Vector3d cp = geosymcircle->getCenter();
Base::Vector3d scp =
cp + double(x) * displacement + double(y) * perpendicularDisplacement;
geosymcircle->setCenter(scp);
if (it == newgeoIdList.begin())
iterfirstpoint = scp;
}
else if (geocopy->is<Part::GeomArcOfCircle>()) {
auto* geoaoc = static_cast<Part::GeomArcOfCircle*>(geocopy);
Base::Vector3d cp = geoaoc->getCenter();
Base::Vector3d scp =
cp + double(x) * displacement + double(y) * perpendicularDisplacement;
geoaoc->setCenter(scp);
if (it == newgeoIdList.begin())
iterfirstpoint = geoaoc->getStartPoint(true);
}
else if (geocopy->is<Part::GeomEllipse>()) {
auto* geosymellipse = static_cast<Part::GeomEllipse*>(geocopy);
Base::Vector3d cp = geosymellipse->getCenter();
Base::Vector3d scp =
cp + double(x) * displacement + double(y) * perpendicularDisplacement;
geosymellipse->setCenter(scp);
if (it == newgeoIdList.begin())
iterfirstpoint = scp;
}
else if (geocopy->is<Part::GeomArcOfEllipse>()) {
auto* geoaoe = static_cast<Part::GeomArcOfEllipse*>(geocopy);
Base::Vector3d cp = geoaoe->getCenter();
Base::Vector3d scp =
cp + double(x) * displacement + double(y) * perpendicularDisplacement;
geoaoe->setCenter(scp);
if (it == newgeoIdList.begin())
iterfirstpoint = geoaoe->getStartPoint(true);
}
else if (geocopy->is<Part::GeomArcOfHyperbola>()) {
Part::GeomArcOfHyperbola* geoaoe =
static_cast<Part::GeomArcOfHyperbola*>(geocopy);
Base::Vector3d cp = geoaoe->getCenter();
Base::Vector3d scp =
cp + double(x) * displacement + double(y) * perpendicularDisplacement;
geoaoe->setCenter(scp);
if (it == newgeoIdList.begin())
iterfirstpoint = geoaoe->getStartPoint(true);
}
else if (geocopy->is<Part::GeomArcOfParabola>()) {
Part::GeomArcOfParabola* geoaoe =
static_cast<Part::GeomArcOfParabola*>(geocopy);
Base::Vector3d cp = geoaoe->getCenter();
Base::Vector3d scp =
cp + double(x) * displacement + double(y) * perpendicularDisplacement;
geoaoe->setCenter(scp);
if (it == newgeoIdList.begin())
iterfirstpoint = geoaoe->getStartPoint(true);
}
else if (geocopy->is<Part::GeomBSplineCurve>()) {
auto* geobsp = static_cast<Part::GeomBSplineCurve*>(geocopy);
std::vector<Base::Vector3d> poles = geobsp->getPoles();
for (std::vector<Base::Vector3d>::iterator jt = poles.begin();
jt != poles.end();
++jt) {
(*jt) = (*jt) + double(x) * displacement
+ double(y) * perpendicularDisplacement;
}
geobsp->setPoles(poles);
if (it == newgeoIdList.begin())
iterfirstpoint = geobsp->getStartPoint();
}
else if (geocopy->is<Part::GeomPoint>()) {
auto* geopoint = static_cast<Part::GeomPoint*>(geocopy);
Base::Vector3d cp = geopoint->getPoint();
Base::Vector3d scp =
cp + double(x) * displacement + double(y) * perpendicularDisplacement;
geopoint->setPoint(scp);
if (it == newgeoIdList.begin())
iterfirstpoint = scp;
}
else {
Base::Console().error("Unsupported Geometry!! Just skipping it.\n");
if (std::ranges::find(newgeoIdList, definedGeo) == newgeoIdList.end()) {
// we should not copy internal alignment geometry, unless the element they
// define is also mirrored
continue;
}
if (!moveonly) {// we are copying
newgeoVals.push_back(geocopy);
geoIdMap.insert(std::make_pair(*it, cgeoid));
cgeoid++;
}
}
// We have already cloned all geometry and constraints, we only need a copy if not
// moving
if (!moveonly) {
// handle geometry constraints
for (std::vector<Constraint*>::const_iterator it = constrvals.begin();
it != constrvals.end();
++it) {
auto fit = geoIdMap.find((*it)->First);
if (fit != geoIdMap.end()) {// if First of constraint is in geoIdList
if ((*it)->Second
== GeoEnum::GeoUndef /*&& (*it)->Third == GeoEnum::GeoUndef*/) {
if (((*it)->Type != Sketcher::DistanceX
&& (*it)->Type != Sketcher::DistanceY)
|| (*it)->FirstPos == Sketcher::PointPos::none) {
// if it is not a point locking DistanceX/Y
if (((*it)->Type == Sketcher::DistanceX
|| (*it)->Type == Sketcher::DistanceY
|| (*it)->Type == Sketcher::Distance
|| (*it)->Type == Sketcher::Diameter
|| (*it)->Type == Sketcher::Weight
|| (*it)->Type == Sketcher::Radius)
&& clone) {
// Distances on a single Element are mapped to equality
// constraints in clone mode
Constraint* constNew = (*it)->copy();
constNew->Type = Sketcher::Equal;
constNew->isDriving = true;
// first is already (*it->First)
constNew->Second = fit->second;
newconstrVals.push_back(constNew);
}
else if ((*it)->Type == Sketcher::Angle && clone) {
if (getGeometry((*it)->First)->is<Part::GeomLineSegment>()) {
// Angles on a single Element are mapped to parallel
// constraints in clone mode
Constraint* constNew = (*it)->copy();
constNew->Type = Sketcher::Parallel;
constNew->isDriving = true;
// first is already (*it->First)
constNew->Second = fit->second;
newconstrVals.push_back(constNew);
}
}
else {
Constraint* constNew = (*it)->copy();
constNew->First = fit->second;
newconstrVals.push_back(constNew);
}
}
}
else {// other geoids intervene in this constraint
auto sit = geoIdMap.find((*it)->Second);
if (sit != geoIdMap.end()) {// Second is also in the list
if ((*it)->Third == GeoEnum::GeoUndef) {
if (((*it)->Type == Sketcher::DistanceX
|| (*it)->Type == Sketcher::DistanceY
|| (*it)->Type == Sketcher::Distance)
&& ((*it)->First == (*it)->Second) && clone) {
// Distances on a two Elements, which must be points of the
// same line are mapped to equality constraints in clone
// mode
Constraint* constNew = (*it)->copy();
constNew->Type = Sketcher::Equal;
constNew->isDriving = true;
constNew->FirstPos = Sketcher::PointPos::none;
// first is already (*it->First)
constNew->Second = fit->second;
constNew->SecondPos = Sketcher::PointPos::none;
newconstrVals.push_back(constNew);
}
else {// this includes InternalAlignment constraints
Constraint* constNew = (*it)->copy();
constNew->First = fit->second;
constNew->Second = sit->second;
newconstrVals.push_back(constNew);
}
}
else {
auto tit = geoIdMap.find((*it)->Third);
if (tit != geoIdMap.end()) {// Third is also in the list
Constraint* constNew = (*it)->copy();
constNew->First = fit->second;
constNew->Second = sit->second;
constNew->Third = tit->second;
newconstrVals.push_back(constNew);
}
}
}
}
}
}
// handle inter-geometry constraints
if (constraindisplacement) {
// add a construction line
Part::GeomLineSegment* constrline = new Part::GeomLineSegment();
// position of the reference point
Base::Vector3d sp = getPoint(refgeoid, refposId)
+ ((x == 0) ? (double(x) * displacement
+ double(y - 1) * perpendicularDisplacement)
: (double(x - 1) * displacement
+ double(y) * perpendicularDisplacement));
// position of the current instance corresponding point
Base::Vector3d ep = iterfirstpoint;
constrline->setPoints(sp, ep);
GeometryFacade::setConstruction(constrline, true);
generateId(constrline);
newgeoVals.push_back(constrline);
Constraint* constNew;
if (x == 0) {// first element of a row
// add coincidents for construction line
constNew = new Constraint();
constNew->Type = Sketcher::Coincident;
constNew->First = prevrowstartfirstgeoid;
constNew->FirstPos = refposId;
constNew->Second = cgeoid;
constNew->SecondPos = Sketcher::PointPos::start;
newconstrVals.push_back(constNew);
constNew = new Constraint();
constNew->Type = Sketcher::Coincident;
constNew->First = iterfirstgeoid;
constNew->FirstPos = refposId;
constNew->Second = cgeoid;
constNew->SecondPos = Sketcher::PointPos::end;
newconstrVals.push_back(constNew);
// it is the first added element of this row in the perpendicular to
// displacementvector direction
if (y == 1) {
rowrefgeoid = cgeoid;
cgeoid++;
// add length (or equal if perpscale==1) and perpendicular
if (perpscale == 1.0) {
constNew = new Constraint();
constNew->Type = Sketcher::Equal;
constNew->First = rowrefgeoid;
constNew->FirstPos = Sketcher::PointPos::none;
constNew->Second = colrefgeoid;
constNew->SecondPos = Sketcher::PointPos::none;
newconstrVals.push_back(constNew);
}
else {
constNew = new Constraint();
constNew->Type = Sketcher::Distance;
constNew->First = rowrefgeoid;
constNew->FirstPos = Sketcher::PointPos::none;
constNew->setValue(perpendicularDisplacement.Length());
newconstrVals.push_back(constNew);
}
constNew = new Constraint();
constNew->Type = Sketcher::Perpendicular;
constNew->First = rowrefgeoid;
constNew->FirstPos = Sketcher::PointPos::none;
constNew->Second = colrefgeoid;
constNew->SecondPos = Sketcher::PointPos::none;
newconstrVals.push_back(constNew);
}
else {// it is just one more element in the col direction
cgeoid++;
// all other first rowers get an equality and perpendicular constraint
constNew = new Constraint();
constNew->Type = Sketcher::Equal;
constNew->First = rowrefgeoid;
constNew->FirstPos = Sketcher::PointPos::none;
constNew->Second = cgeoid - 1;
constNew->SecondPos = Sketcher::PointPos::none;
newconstrVals.push_back(constNew);
constNew = new Constraint();
constNew->Type = Sketcher::Perpendicular;
constNew->First = cgeoid - 1;
constNew->FirstPos = Sketcher::PointPos::none;
constNew->Second = colrefgeoid;
constNew->SecondPos = Sketcher::PointPos::none;
newconstrVals.push_back(constNew);
}
}
else {// any element not being the first element of a row
// add coincidents for construction line
constNew = new Constraint();
constNew->Type = Sketcher::Coincident;
constNew->First = prevfirstgeoid;
constNew->FirstPos = refposId;
constNew->Second = cgeoid;
constNew->SecondPos = Sketcher::PointPos::start;
newconstrVals.push_back(constNew);
constNew = new Constraint();
constNew->Type = Sketcher::Coincident;
constNew->First = iterfirstgeoid;
constNew->FirstPos = refposId;
constNew->Second = cgeoid;
constNew->SecondPos = Sketcher::PointPos::end;
newconstrVals.push_back(constNew);
if (y == 0 && x == 1) {// first element of the first row
colrefgeoid = cgeoid;
cgeoid++;
// add length and Angle
constNew = new Constraint();
constNew->Type = Sketcher::Distance;
constNew->First = colrefgeoid;
constNew->FirstPos = Sketcher::PointPos::none;
constNew->setValue(displacement.Length());
newconstrVals.push_back(constNew);
constNew = new Constraint();
constNew->Type = Sketcher::Angle;
constNew->First = colrefgeoid;
constNew->FirstPos = Sketcher::PointPos::none;
constNew->setValue(atan2(displacement.y, displacement.x));
newconstrVals.push_back(constNew);
}
else {// any other element
cgeoid++;
// all other elements get an equality and parallel constraint
constNew = new Constraint();
constNew->Type = Sketcher::Equal;
constNew->First = colrefgeoid;
constNew->FirstPos = Sketcher::PointPos::none;
constNew->Second = cgeoid - 1;
constNew->SecondPos = Sketcher::PointPos::none;
newconstrVals.push_back(constNew);
constNew = new Constraint();
constNew->Type = Sketcher::Parallel;
constNew->First = cgeoid - 1;
constNew->FirstPos = Sketcher::PointPos::none;
constNew->Second = colrefgeoid;
constNew->SecondPos = Sketcher::PointPos::none;
newconstrVals.push_back(constNew);
}
}
}
// after each creation reset map so that the key-value is univoque (only for
// operations other than move)
geoIdMap.clear();
geocopy = geo->copy();
generateId(geocopy);
}
else {
geocopy = newgeoVals[*it];
}
// Handle Geometry
if (geocopy->is<Part::GeomLineSegment>()) {
auto* geosymline = static_cast<Part::GeomLineSegment*>(geocopy);
Base::Vector3d ep = geosymline->getEndPoint();
Base::Vector3d ssp = geosymline->getStartPoint() + double(x) * displacement
+ double(y) * perpendicularDisplacement;
geosymline->setPoints(ssp,
ep + double(x) * displacement
+ double(y) * perpendicularDisplacement);
if (it == newgeoIdList.begin()) {
iterfirstpoint = ssp;
}
}
else if (geocopy->is<Part::GeomCircle>()) {
auto* geosymcircle = static_cast<Part::GeomCircle*>(geocopy);
Base::Vector3d cp = geosymcircle->getCenter();
Base::Vector3d scp =
cp + double(x) * displacement + double(y) * perpendicularDisplacement;
geosymcircle->setCenter(scp);
if (it == newgeoIdList.begin()) {
iterfirstpoint = scp;
}
}
else if (geocopy->is<Part::GeomArcOfCircle>()) {
auto* geoaoc = static_cast<Part::GeomArcOfCircle*>(geocopy);
Base::Vector3d cp = geoaoc->getCenter();
Base::Vector3d scp =
cp + double(x) * displacement + double(y) * perpendicularDisplacement;
geoaoc->setCenter(scp);
if (it == newgeoIdList.begin()) {
iterfirstpoint = geoaoc->getStartPoint(true);
}
}
else if (geocopy->is<Part::GeomEllipse>()) {
auto* geosymellipse = static_cast<Part::GeomEllipse*>(geocopy);
Base::Vector3d cp = geosymellipse->getCenter();
Base::Vector3d scp =
cp + double(x) * displacement + double(y) * perpendicularDisplacement;
geosymellipse->setCenter(scp);
if (it == newgeoIdList.begin()) {
iterfirstpoint = scp;
}
}
else if (geocopy->is<Part::GeomArcOfEllipse>()) {
auto* geoaoe = static_cast<Part::GeomArcOfEllipse*>(geocopy);
Base::Vector3d cp = geoaoe->getCenter();
Base::Vector3d scp =
cp + double(x) * displacement + double(y) * perpendicularDisplacement;
geoaoe->setCenter(scp);
if (it == newgeoIdList.begin()) {
iterfirstpoint = geoaoe->getStartPoint(true);
}
}
else if (geocopy->is<Part::GeomArcOfHyperbola>()) {
auto* geoaoe = static_cast<Part::GeomArcOfHyperbola*>(geocopy);
Base::Vector3d cp = geoaoe->getCenter();
Base::Vector3d scp =
cp + double(x) * displacement + double(y) * perpendicularDisplacement;
geoaoe->setCenter(scp);
if (it == newgeoIdList.begin()) {
iterfirstpoint = geoaoe->getStartPoint(true);
}
}
else if (geocopy->is<Part::GeomArcOfParabola>()) {
auto* geoaoe = static_cast<Part::GeomArcOfParabola*>(geocopy);
Base::Vector3d cp = geoaoe->getCenter();
Base::Vector3d scp =
cp + double(x) * displacement + double(y) * perpendicularDisplacement;
geoaoe->setCenter(scp);
if (it == newgeoIdList.begin()) {
iterfirstpoint = geoaoe->getStartPoint(true);
}
}
else if (geocopy->is<Part::GeomBSplineCurve>()) {
auto* geobsp = static_cast<Part::GeomBSplineCurve*>(geocopy);
std::vector<Base::Vector3d> poles = geobsp->getPoles();
for (std::vector<Base::Vector3d>::iterator jt = poles.begin(); jt != poles.end();
++jt) {
(*jt) =
(*jt) + double(x) * displacement + double(y) * perpendicularDisplacement;
}
geobsp->setPoles(poles);
if (it == newgeoIdList.begin()) {
iterfirstpoint = geobsp->getStartPoint();
}
}
else if (geocopy->is<Part::GeomPoint>()) {
Part::GeomPoint* geopoint = static_cast<Part::GeomPoint*>(geocopy);
Base::Vector3d cp = geopoint->getPoint();
Base::Vector3d scp =
cp + double(x) * displacement + double(y) * perpendicularDisplacement;
geopoint->setPoint(scp);
if (it == newgeoIdList.begin()) {
iterfirstpoint = scp;
}
}
else {
Base::Console().error("Unsupported Geometry!! Just skipping it.\n");
continue;
}
if (!moveonly) { // we are copying
newgeoVals.push_back(geocopy);
geoIdMap.insert(std::make_pair(*it, cgeoid));
cgeoid++;
}
}
if (moveonly) {
return;
}
// handle geometry constraints
for (const auto& constr : constrvals) {
auto fit = geoIdMap.find(constr->First);
if (fit == geoIdMap.end()) {
continue;
}
// First of constraint is in geoIdList
if (constr->Second == GeoEnum::GeoUndef /*&& constr->Third == GeoEnum::GeoUndef*/) {
if ((constr->Type == Sketcher::DistanceX || constr->Type == Sketcher::DistanceY)
&& constr->FirstPos != Sketcher::PointPos::none) {
continue;
}
// if it is not a point locking DistanceX/Y
if ((constr->Type == Sketcher::DistanceX || constr->Type == Sketcher::DistanceY
|| constr->Type == Sketcher::Distance || constr->Type == Sketcher::Diameter
|| constr->Type == Sketcher::Weight || constr->Type == Sketcher::Radius)
&& clone) {
// Distances on a single Element are mapped to equality
// constraints in clone mode
Constraint* constNew = constr->copy();
constNew->Type = Sketcher::Equal;
constNew->isDriving = true;
// first is already (constr->First)
constNew->Second = fit->second;
newconstrVals.push_back(constNew);
continue;
}
if (!(constr->Type == Sketcher::Angle && clone)) {
Constraint* constNew = constr->copy();
constNew->First = fit->second;
newconstrVals.push_back(constNew);
continue;
}
if (getGeometry(constr->First)->is<Part::GeomLineSegment>()) {
// Angles on a single Element are mapped to parallel
// constraints in clone mode
Constraint* constNew = constr->copy();
constNew->Type = Sketcher::Parallel;
constNew->isDriving = true;
// first is already (constr->First)
constNew->Second = fit->second;
newconstrVals.push_back(constNew);
}
continue;
}
// other geoids intervene in this constraint
auto sit = geoIdMap.find(constr->Second);
if (sit == geoIdMap.end()) {
continue;
}
// Second is also in the list
if (constr->Third == GeoEnum::GeoUndef) {
if ((constr->Type == Sketcher::DistanceX || constr->Type == Sketcher::DistanceY
|| constr->Type == Sketcher::Distance)
&& (constr->First == constr->Second) && clone) {
// Distances on a two Elements, which must be points of the
// same line are mapped to equality constraints in clone
// mode
Constraint* constNew = constr->copy();
constNew->Type = Sketcher::Equal;
constNew->isDriving = true;
constNew->FirstPos = Sketcher::PointPos::none;
// first is already (constr->First)
constNew->Second = fit->second;
constNew->SecondPos = Sketcher::PointPos::none;
newconstrVals.push_back(constNew);
continue;
}
// remaining, this includes InternalAlignment constraints
Constraint* constNew = constr->copy();
constNew->First = fit->second;
constNew->Second = sit->second;
newconstrVals.push_back(constNew);
continue;
}
auto tit = geoIdMap.find(constr->Third);
if (tit != geoIdMap.end()) {
continue;
}
// Third is also in the list
Constraint* constNew = constr->copy();
constNew->First = fit->second;
constNew->Second = sit->second;
constNew->Third = tit->second;
newconstrVals.push_back(constNew);
}
// handle inter-geometry constraints
if (!constraindisplacement) {
// after each creation reset map so that the key-value is univoque (only for
// operations other than move)
geoIdMap.clear();
}
// add a construction line
Part::GeomLineSegment* constrline = new Part::GeomLineSegment();
// position of the reference point
Base::Vector3d sp = getPoint(refgeoid, refposId)
+ ((x == 0) ? (double(x) * displacement + double(y - 1) * perpendicularDisplacement)
: (double(x - 1) * displacement + double(y) * perpendicularDisplacement));
// position of the current instance corresponding point
Base::Vector3d ep = iterfirstpoint;
constrline->setPoints(sp, ep);
GeometryFacade::setConstruction(constrline, true);
generateId(constrline);
newgeoVals.push_back(constrline);
Constraint* constNew;
if (x == 0) {
// first element of a row
// add coincidents for construction line
constNew = new Constraint();
constNew->Type = Sketcher::Coincident;
constNew->First = prevrowstartfirstgeoid;
constNew->FirstPos = refposId;
constNew->Second = cgeoid;
constNew->SecondPos = Sketcher::PointPos::start;
newconstrVals.push_back(constNew);
constNew = new Constraint();
constNew->Type = Sketcher::Coincident;
constNew->First = iterfirstgeoid;
constNew->FirstPos = refposId;
constNew->Second = cgeoid;
constNew->SecondPos = Sketcher::PointPos::end;
newconstrVals.push_back(constNew);
// it is the first added element of this row in the perpendicular to
// displacementvector direction
if (y == 1) {
rowrefgeoid = cgeoid;
cgeoid++;
// add length (or equal if perpscale==1) and perpendicular
if (perpscale == 1.0) {
constNew = new Constraint();
constNew->Type = Sketcher::Equal;
constNew->First = rowrefgeoid;
constNew->FirstPos = Sketcher::PointPos::none;
constNew->Second = colrefgeoid;
constNew->SecondPos = Sketcher::PointPos::none;
newconstrVals.push_back(constNew);
}
else {
constNew = new Constraint();
constNew->Type = Sketcher::Distance;
constNew->First = rowrefgeoid;
constNew->FirstPos = Sketcher::PointPos::none;
constNew->setValue(perpendicularDisplacement.Length());
newconstrVals.push_back(constNew);
}
constNew = new Constraint();
constNew->Type = Sketcher::Perpendicular;
constNew->First = rowrefgeoid;
constNew->FirstPos = Sketcher::PointPos::none;
constNew->Second = colrefgeoid;
constNew->SecondPos = Sketcher::PointPos::none;
newconstrVals.push_back(constNew);
}
else {
// it is just one more element in the col direction
cgeoid++;
// all other first rowers get an equality and perpendicular constraint
constNew = new Constraint();
constNew->Type = Sketcher::Equal;
constNew->First = rowrefgeoid;
constNew->FirstPos = Sketcher::PointPos::none;
constNew->Second = cgeoid - 1;
constNew->SecondPos = Sketcher::PointPos::none;
newconstrVals.push_back(constNew);
constNew = new Constraint();
constNew->Type = Sketcher::Perpendicular;
constNew->First = cgeoid - 1;
constNew->FirstPos = Sketcher::PointPos::none;
constNew->Second = colrefgeoid;
constNew->SecondPos = Sketcher::PointPos::none;
newconstrVals.push_back(constNew);
}
}
else {
// any element not being the first element of a row
// add coincidents for construction line
constNew = new Constraint();
constNew->Type = Sketcher::Coincident;
constNew->First = prevfirstgeoid;
constNew->FirstPos = refposId;
constNew->Second = cgeoid;
constNew->SecondPos = Sketcher::PointPos::start;
newconstrVals.push_back(constNew);
constNew = new Constraint();
constNew->Type = Sketcher::Coincident;
constNew->First = iterfirstgeoid;
constNew->FirstPos = refposId;
constNew->Second = cgeoid;
constNew->SecondPos = Sketcher::PointPos::end;
newconstrVals.push_back(constNew);
if (y == 0 && x == 1) {
// first element of the first row
colrefgeoid = cgeoid;
cgeoid++;
// add length and Angle
constNew = new Constraint();
constNew->Type = Sketcher::Distance;
constNew->First = colrefgeoid;
constNew->FirstPos = Sketcher::PointPos::none;
constNew->setValue(displacement.Length());
newconstrVals.push_back(constNew);
constNew = new Constraint();
constNew->Type = Sketcher::Angle;
constNew->First = colrefgeoid;
constNew->FirstPos = Sketcher::PointPos::none;
constNew->setValue(atan2(displacement.y, displacement.x));
newconstrVals.push_back(constNew);
}
else {
// any other element
cgeoid++;
// all other elements get an equality and parallel constraint
constNew = new Constraint();
constNew->Type = Sketcher::Equal;
constNew->First = colrefgeoid;
constNew->FirstPos = Sketcher::PointPos::none;
constNew->Second = cgeoid - 1;
constNew->SecondPos = Sketcher::PointPos::none;
newconstrVals.push_back(constNew);
constNew = new Constraint();
constNew->Type = Sketcher::Parallel;
constNew->First = cgeoid - 1;
constNew->FirstPos = Sketcher::PointPos::none;
constNew->Second = colrefgeoid;
constNew->SecondPos = Sketcher::PointPos::none;
newconstrVals.push_back(constNew);
}
}
// after each creation reset map so that the key-value is univoque (only for
// operations other than move)
geoIdMap.clear();
};
for (y = 0; y < rsize; y++) {
for (x = 0; x < csize; x++) {
makeCopyAtRowColumn(x, y);
}
}
@@ -5464,8 +5487,9 @@ int SketchObject::addCopy(const std::vector<int>& geoIdList, const Base::Vector3
Base::StateLocker preventUpdate(internaltransaction, true);
Geometry.setValues(std::move(newgeoVals));
if (newconstrVals.size() > constrvals.size())
if (newconstrVals.size() > constrvals.size()) {
Constraints.setValues(std::move(newconstrVals));
}
}
// we inhibited update, so we trigger it now
@@ -5475,6 +5499,7 @@ int SketchObject::addCopy(const std::vector<int>& geoIdList, const Base::Vector3
return Geometry.getSize() - 1;
}
// clang-format off
int SketchObject::removeAxesAlignment(const std::vector<int>& geoIdList)
{