Sketcher: Symmetry tool rework.
This commit is contained in:
committed by
Yorik van Havre
parent
3aab822df3
commit
a8adc573f8
@@ -4227,105 +4227,298 @@ bool SketchObject::isCarbonCopyAllowed(App::Document* pDoc, App::DocumentObject*
|
||||
}
|
||||
|
||||
int SketchObject::addSymmetric(const std::vector<int>& geoIdList, int refGeoId,
|
||||
Sketcher::PointPos refPosId /*=Sketcher::PointPos::none*/)
|
||||
Sketcher::PointPos refPosId /*=Sketcher::PointPos::none*/,
|
||||
bool addSymmetryConstraints /*= false*/)
|
||||
{
|
||||
// no need to check input data validity as this is an sketchobject managed operation.
|
||||
Base::StateLocker lock(managedoperation, true);
|
||||
|
||||
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);
|
||||
|
||||
newgeoVals.reserve(geovals.size() + geoIdList.size());
|
||||
|
||||
int cgeoid = getHighestCurveIndex() + 1;
|
||||
|
||||
std::map<int, int> geoIdMap;
|
||||
std::map<int, bool> isStartEndInverted;
|
||||
|
||||
// Find out if reference is aligned with V or H axis,
|
||||
// if so we can keep Vertical and Horizontal constraints in the mirrored geometry.
|
||||
bool refIsLine = refPosId == Sketcher::PointPos::none;
|
||||
bool refIsAxisAligned = false;
|
||||
if (refGeoId == Sketcher::GeoEnum::VAxis || refGeoId == Sketcher::GeoEnum::HAxis) {
|
||||
if (refGeoId == Sketcher::GeoEnum::VAxis || refGeoId == Sketcher::GeoEnum::HAxis || !refIsLine) {
|
||||
refIsAxisAligned = true;
|
||||
}
|
||||
else {
|
||||
for (std::vector<Constraint*>::const_iterator it = constrvals.begin();
|
||||
it != constrvals.end();
|
||||
++it) {
|
||||
Constraint* constr = *(it);
|
||||
for (auto* constr : constrvals) {
|
||||
if (constr->First == refGeoId
|
||||
&& (constr->Type == Sketcher::Vertical || constr->Type == Sketcher::Horizontal))
|
||||
&& (constr->Type == Sketcher::Vertical || constr->Type == Sketcher::Horizontal)){
|
||||
refIsAxisAligned = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// reference is a line
|
||||
if (refPosId == Sketcher::PointPos::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;
|
||||
// add the geometry
|
||||
std::map<int, int> geoIdMap;
|
||||
std::map<int, bool> isStartEndInverted;
|
||||
std::vector<Part::Geometry*> newgeoVals(getInternalGeometry());
|
||||
std::vector<Part::Geometry*> symmetricVals = getSymmetric(geoIdList, geoIdMap, isStartEndInverted, refGeoId, refPosId);
|
||||
newgeoVals.insert(newgeoVals.end(), symmetricVals.begin(), symmetricVals.end());
|
||||
|
||||
// Block acceptGeometry in OnChanged to avoid unnecessary checks and updates
|
||||
{
|
||||
Base::StateLocker lock(internaltransaction, true);
|
||||
Geometry.setValues(std::move(newgeoVals));
|
||||
|
||||
|
||||
for (auto* constr : constrvals) {
|
||||
// we look in the map, because we might have skipped internal alignment geometry
|
||||
auto fit = geoIdMap.find(constr->First);
|
||||
|
||||
if (fit != geoIdMap.end()) {// if First of constraint is in geoIdList
|
||||
if (addSymmetryConstraints && constr->Type != Sketcher::InternalAlignment) {
|
||||
// if we are making symmetric constraints, then we don't want to copy all constraints
|
||||
continue;
|
||||
}
|
||||
|
||||
if (constr->Second == GeoEnum::GeoUndef /*&& constr->Third == GeoEnum::GeoUndef*/) {
|
||||
if (refIsAxisAligned) {
|
||||
// in this case we want to keep the Vertical, Horizontal constraints
|
||||
// DistanceX ,and DistanceY constraints should also be possible to keep in
|
||||
// this case, but keeping them causes segfault, not sure why.
|
||||
|
||||
if (constr->Type != Sketcher::DistanceX
|
||||
&& constr->Type != Sketcher::DistanceY) {
|
||||
Constraint* constNew = constr->copy();
|
||||
constNew->First = fit->second;
|
||||
newconstrVals.push_back(constNew);
|
||||
}
|
||||
}
|
||||
else if (constr->Type != Sketcher::DistanceX
|
||||
&& constr->Type != Sketcher::DistanceY
|
||||
&& constr->Type != Sketcher::Vertical
|
||||
&& constr->Type != Sketcher::Horizontal) {
|
||||
// this includes all non-directional single GeoId constraints, as radius,
|
||||
// diameter, weight,...
|
||||
|
||||
Constraint* constNew = constr->copy();
|
||||
constNew->First = fit->second;
|
||||
newconstrVals.push_back(constNew);
|
||||
}
|
||||
}
|
||||
else {// other geoids intervene in this constraint
|
||||
|
||||
auto sit = geoIdMap.find(constr->Second);
|
||||
|
||||
if (sit != geoIdMap.end()) {// Second is also in the list
|
||||
|
||||
if (constr->Third == GeoEnum::GeoUndef) {
|
||||
if (constr->Type == Sketcher::Coincident
|
||||
|| constr->Type == Sketcher::Perpendicular
|
||||
|| constr->Type == Sketcher::Parallel
|
||||
|| constr->Type == Sketcher::Tangent
|
||||
|| constr->Type == Sketcher::Distance
|
||||
|| constr->Type == Sketcher::Equal || constr->Type == Sketcher::Angle
|
||||
|| constr->Type == Sketcher::PointOnObject
|
||||
|| constr->Type == Sketcher::InternalAlignment) {
|
||||
Constraint* constNew = constr->copy();
|
||||
|
||||
constNew->First = fit->second;
|
||||
constNew->Second = sit->second;
|
||||
if (isStartEndInverted[constr->First]) {
|
||||
if (constr->FirstPos == Sketcher::PointPos::start)
|
||||
constNew->FirstPos = Sketcher::PointPos::end;
|
||||
else if (constr->FirstPos == Sketcher::PointPos::end)
|
||||
constNew->FirstPos = Sketcher::PointPos::start;
|
||||
}
|
||||
if (isStartEndInverted[constr->Second]) {
|
||||
if (constr->SecondPos == Sketcher::PointPos::start)
|
||||
constNew->SecondPos = Sketcher::PointPos::end;
|
||||
else if (constr->SecondPos == Sketcher::PointPos::end)
|
||||
constNew->SecondPos = Sketcher::PointPos::start;
|
||||
}
|
||||
|
||||
if (constNew->Type == Tangent || constNew->Type == Perpendicular)
|
||||
AutoLockTangencyAndPerpty(constNew, true);
|
||||
|
||||
if ((constr->Type == Sketcher::Angle)
|
||||
&& (refPosId == Sketcher::PointPos::none)) {
|
||||
constNew->setValue(-constr->getValue());
|
||||
}
|
||||
|
||||
newconstrVals.push_back(constNew);
|
||||
}
|
||||
}
|
||||
else {// three GeoIds intervene in constraint
|
||||
auto tit = geoIdMap.find(constr->Third);
|
||||
|
||||
if (tit != geoIdMap.end()) {// Third is also in the list
|
||||
Constraint* constNew = constr->copy();
|
||||
constNew->First = fit->second;
|
||||
constNew->Second = sit->second;
|
||||
constNew->Third = tit->second;
|
||||
if (isStartEndInverted[constr->First]) {
|
||||
if (constr->FirstPos == Sketcher::PointPos::start)
|
||||
constNew->FirstPos = Sketcher::PointPos::end;
|
||||
else if (constr->FirstPos == Sketcher::PointPos::end)
|
||||
constNew->FirstPos = Sketcher::PointPos::start;
|
||||
}
|
||||
if (isStartEndInverted[constr->Second]) {
|
||||
if (constr->SecondPos == Sketcher::PointPos::start)
|
||||
constNew->SecondPos = Sketcher::PointPos::end;
|
||||
else if (constr->SecondPos == Sketcher::PointPos::end)
|
||||
constNew->SecondPos = Sketcher::PointPos::start;
|
||||
}
|
||||
if (isStartEndInverted[constr->Third]) {
|
||||
if (constr->ThirdPos == Sketcher::PointPos::start)
|
||||
constNew->ThirdPos = Sketcher::PointPos::end;
|
||||
else if (constr->ThirdPos == Sketcher::PointPos::end)
|
||||
constNew->ThirdPos = Sketcher::PointPos::start;
|
||||
}
|
||||
newconstrVals.push_back(constNew);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Part::GeomLineSegment* refGeoLine = static_cast<const Part::GeomLineSegment*>(georef);
|
||||
if (addSymmetryConstraints) {
|
||||
auto createSymConstr = [&]
|
||||
(int first, int second, Sketcher::PointPos firstPos, Sketcher::PointPos secondPos) {
|
||||
auto symConstr = new Constraint();
|
||||
symConstr->Type = Symmetric;
|
||||
symConstr->First = first;
|
||||
symConstr->Second = second;
|
||||
symConstr->Third = refGeoId;
|
||||
symConstr->FirstPos = firstPos;
|
||||
symConstr->SecondPos = secondPos;
|
||||
symConstr->ThirdPos = refPosId;
|
||||
newconstrVals.push_back(symConstr);
|
||||
};
|
||||
auto createEqualityConstr = [&]
|
||||
(int first, int second) {
|
||||
auto symConstr = new Constraint();
|
||||
symConstr->Type = Equal;
|
||||
symConstr->First = first;
|
||||
symConstr->Second = second;
|
||||
newconstrVals.push_back(symConstr);
|
||||
};
|
||||
|
||||
for (auto geoIdPair : geoIdMap) {
|
||||
int geoId1 = geoIdPair.first;
|
||||
int geoId2 = geoIdPair.second;
|
||||
const Part::Geometry* geo = getGeometry(geoId1);
|
||||
|
||||
if (geo->is<Part::GeomLineSegment>()) {
|
||||
auto gf = GeometryFacade::getFacade(geo);
|
||||
if (!gf->isInternalAligned()) {
|
||||
// Note internal aligned lines (ellipse, parabola, hyperbola) are causing redundant constraint.
|
||||
createSymConstr(geoId1, geoId2, PointPos::start, isStartEndInverted[geoId1] ? PointPos::end : PointPos::start);
|
||||
createSymConstr(geoId1, geoId2, PointPos::end, isStartEndInverted[geoId1] ? PointPos::start : PointPos::end);
|
||||
}
|
||||
}
|
||||
else if (geo->is<Part::GeomCircle>() || geo->is<Part::GeomEllipse>()) {
|
||||
createEqualityConstr(geoId1, geoId2);
|
||||
createSymConstr(geoId1, geoId2, PointPos::mid, PointPos::mid);
|
||||
}
|
||||
else if (geo->is<Part::GeomArcOfCircle>()
|
||||
|| geo->is<Part::GeomArcOfEllipse>()
|
||||
|| geo->is<Part::GeomArcOfHyperbola>()
|
||||
|| geo->is<Part::GeomArcOfParabola>()) {
|
||||
createEqualityConstr(geoId1, geoId2);
|
||||
createSymConstr(geoId1, geoId2, PointPos::start, isStartEndInverted[geoId1] ? PointPos::end : PointPos::start);
|
||||
createSymConstr(geoId1, geoId2, PointPos::end, isStartEndInverted[geoId1] ? PointPos::start : PointPos::end);
|
||||
}
|
||||
else if (geo->is<Part::GeomPoint>()) {
|
||||
auto gf = GeometryFacade::getFacade(geo);
|
||||
if (!gf->isInternalAligned()) {
|
||||
createSymConstr(geoId1, geoId2, PointPos::start, PointPos::start);
|
||||
}
|
||||
}
|
||||
// Note bspline has symmetric by the internal aligned circles.
|
||||
}
|
||||
}
|
||||
|
||||
if (newconstrVals.size() > constrvals.size()){
|
||||
Constraints.setValues(std::move(newconstrVals));
|
||||
}
|
||||
}
|
||||
|
||||
// we delayed update, so trigger it now.
|
||||
// Update geometry indices and rebuild vertexindex now via onChanged, so that
|
||||
// ViewProvider::UpdateData is triggered.
|
||||
Geometry.touch();
|
||||
|
||||
return Geometry.getSize() - 1;
|
||||
}
|
||||
|
||||
|
||||
std::vector<Part::Geometry*> SketchObject::getSymmetric(const std::vector<int>& geoIdList,
|
||||
std::map<int, int>& geoIdMap,
|
||||
std::map<int, bool>& isStartEndInverted,
|
||||
int refGeoId,
|
||||
Sketcher::PointPos refPosId)
|
||||
{
|
||||
std::vector<Part::Geometry*> symmetricVals;
|
||||
bool refIsLine = refPosId == Sketcher::PointPos::none;
|
||||
int cgeoid = getHighestCurveIndex() + 1;
|
||||
|
||||
auto shouldCopyGeometry = [&](auto* geo, int geoId) -> bool {
|
||||
auto gf = GeometryFacade::getFacade(geo);
|
||||
if (gf->isInternalAligned()) {
|
||||
// only add if the corresponding geometry it defines is also in the list.
|
||||
int definedGeo = GeoEnum::GeoUndef;
|
||||
for (auto c : Constraints.getValues()) {
|
||||
if (c->Type == Sketcher::InternalAlignment && c->First == geoId) {
|
||||
definedGeo = c->Second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Return true if definedGeo is in geoIdList, false otherwise
|
||||
return std::find(geoIdList.begin(), geoIdList.end(), definedGeo) != geoIdList.end();
|
||||
}
|
||||
// Return true if not internal aligned, indicating it should always be copied
|
||||
return true;
|
||||
};
|
||||
|
||||
if (refIsLine) {
|
||||
const Part::Geometry* georef = getGeometry(refGeoId);
|
||||
if (!georef->is<Part::GeomLineSegment>()) {
|
||||
Base::Console().Error("Reference for symmetric is neither a point nor a line.\n");
|
||||
return {};
|
||||
}
|
||||
|
||||
auto* 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);
|
||||
for (auto geoId : geoIdList) {
|
||||
const Part::Geometry* geo = getGeometry(geoId);
|
||||
Part::Geometry* geosym;
|
||||
|
||||
auto gf = GeometryFacade::getFacade(geo);
|
||||
|
||||
if (gf->isInternalAligned()) {
|
||||
// only add this geometry if the corresponding geometry it defines is also in the
|
||||
// list.
|
||||
int definedGeo = GeoEnum::GeoUndef;
|
||||
|
||||
for (auto c : Constraints.getValues()) {
|
||||
if (c->Type == Sketcher::InternalAlignment && c->First == *it) {
|
||||
definedGeo = c->Second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (std::find(geoIdList.begin(), geoIdList.end(), definedGeo) != geoIdList.end())
|
||||
geosym = geo->copy();
|
||||
else {
|
||||
// we should not mirror internal alignment geometry, unless the element they
|
||||
// define is also mirrored
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
geosym = geo->copy();
|
||||
if (!shouldCopyGeometry(geo, geoId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
geosym = geo->copy();
|
||||
|
||||
// Handle Geometry
|
||||
if (geosym->is<Part::GeomLineSegment>()) {
|
||||
Part::GeomLineSegment* geosymline = static_cast<Part::GeomLineSegment*>(geosym);
|
||||
auto* 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));
|
||||
isStartEndInverted.insert(std::make_pair(geoId, false));
|
||||
}
|
||||
else if (geosym->is<Part::GeomCircle>()) {
|
||||
Part::GeomCircle* geosymcircle = static_cast<Part::GeomCircle*>(geosym);
|
||||
auto* 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));
|
||||
isStartEndInverted.insert(std::make_pair(geoId, false));
|
||||
}
|
||||
else if (geosym->is<Part::GeomArcOfCircle>()) {
|
||||
Part::GeomArcOfCircle* geoaoc = static_cast<Part::GeomArcOfCircle*>(geosym);
|
||||
auto* geoaoc = static_cast<Part::GeomArcOfCircle*>(geosym);
|
||||
Base::Vector3d sp = geoaoc->getStartPoint(true);
|
||||
Base::Vector3d ep = geoaoc->getEndPoint(true);
|
||||
Base::Vector3d cp = geoaoc->getCenter();
|
||||
@@ -4342,10 +4535,10 @@ int SketchObject::addSymmetric(const std::vector<int>& geoIdList, int refGeoId,
|
||||
|
||||
geoaoc->setCenter(scp);
|
||||
geoaoc->setRange(theta1, theta2, true);
|
||||
isStartEndInverted.insert(std::make_pair(*it, true));
|
||||
isStartEndInverted.insert(std::make_pair(geoId, true));
|
||||
}
|
||||
else if (geosym->is<Part::GeomEllipse>()) {
|
||||
Part::GeomEllipse* geosymellipse = static_cast<Part::GeomEllipse*>(geosym);
|
||||
auto* geosymellipse = static_cast<Part::GeomEllipse*>(geosym);
|
||||
Base::Vector3d cp = geosymellipse->getCenter();
|
||||
|
||||
Base::Vector3d majdir = geosymellipse->getMajorAxisDir();
|
||||
@@ -4362,10 +4555,10 @@ int SketchObject::addSymmetric(const std::vector<int>& geoIdList, int refGeoId,
|
||||
geosymellipse->setMajorAxisDir(sf1 - scp);
|
||||
|
||||
geosymellipse->setCenter(scp);
|
||||
isStartEndInverted.insert(std::make_pair(*it, false));
|
||||
isStartEndInverted.insert(std::make_pair(geoId, false));
|
||||
}
|
||||
else if (geosym->is<Part::GeomArcOfEllipse>()) {
|
||||
Part::GeomArcOfEllipse* geosymaoe = static_cast<Part::GeomArcOfEllipse*>(geosym);
|
||||
auto* geosymaoe = static_cast<Part::GeomArcOfEllipse*>(geosym);
|
||||
Base::Vector3d cp = geosymaoe->getCenter();
|
||||
|
||||
Base::Vector3d majdir = geosymaoe->getMajorAxisDir();
|
||||
@@ -4394,11 +4587,10 @@ int SketchObject::addSymmetric(const std::vector<int>& geoIdList, int refGeoId,
|
||||
}
|
||||
|
||||
geosymaoe->setRange(theta1, theta2, true);
|
||||
isStartEndInverted.insert(std::make_pair(*it, true));
|
||||
isStartEndInverted.insert(std::make_pair(geoId, true));
|
||||
}
|
||||
else if (geosym->is<Part::GeomArcOfHyperbola>()) {
|
||||
Part::GeomArcOfHyperbola* geosymaoe =
|
||||
static_cast<Part::GeomArcOfHyperbola*>(geosym);
|
||||
auto* geosymaoe = static_cast<Part::GeomArcOfHyperbola*>(geosym);
|
||||
Base::Vector3d cp = geosymaoe->getCenter();
|
||||
|
||||
Base::Vector3d majdir = geosymaoe->getMajorAxisDir();
|
||||
@@ -4423,10 +4615,10 @@ int SketchObject::addSymmetric(const std::vector<int>& geoIdList, int refGeoId,
|
||||
std::swap(theta1, theta2);
|
||||
|
||||
geosymaoe->setRange(theta1, theta2, true);
|
||||
isStartEndInverted.insert(std::make_pair(*it, true));
|
||||
isStartEndInverted.insert(std::make_pair(geoId, true));
|
||||
}
|
||||
else if (geosym->is<Part::GeomArcOfParabola>()) {
|
||||
Part::GeomArcOfParabola* geosymaoe = static_cast<Part::GeomArcOfParabola*>(geosym);
|
||||
auto* geosymaoe = static_cast<Part::GeomArcOfParabola*>(geosym);
|
||||
Base::Vector3d cp = geosymaoe->getCenter();
|
||||
|
||||
// double df= geosymaoe->getFocal();
|
||||
@@ -4447,45 +4639,41 @@ int SketchObject::addSymmetric(const std::vector<int>& geoIdList, int refGeoId,
|
||||
std::swap(theta1, theta2);
|
||||
|
||||
geosymaoe->setRange(theta1, theta2, true);
|
||||
isStartEndInverted.insert(std::make_pair(*it, true));
|
||||
isStartEndInverted.insert(std::make_pair(geoId, true));
|
||||
}
|
||||
else if (geosym->is<Part::GeomBSplineCurve>()) {
|
||||
Part::GeomBSplineCurve* geosymbsp = static_cast<Part::GeomBSplineCurve*>(geosym);
|
||||
auto* geosymbsp = static_cast<Part::GeomBSplineCurve*>(geosym);
|
||||
|
||||
std::vector<Base::Vector3d> poles = geosymbsp->getPoles();
|
||||
|
||||
for (std::vector<Base::Vector3d>::iterator jt = poles.begin(); jt != poles.end();
|
||||
++jt) {
|
||||
|
||||
(*jt) = (*jt)
|
||||
+ 2.0
|
||||
* ((*jt).Perpendicular(refGeoLine->getStartPoint(), vectline) - (*jt));
|
||||
for (auto& pole : poles) {
|
||||
pole = pole
|
||||
+ 2.0 * (pole.Perpendicular(refGeoLine->getStartPoint(), vectline) - pole);
|
||||
}
|
||||
|
||||
geosymbsp->setPoles(poles);
|
||||
|
||||
isStartEndInverted.insert(std::make_pair(*it, false));
|
||||
isStartEndInverted.insert(std::make_pair(geoId, false));
|
||||
}
|
||||
else if (geosym->is<Part::GeomPoint>()) {
|
||||
Part::GeomPoint* geosympoint = static_cast<Part::GeomPoint*>(geosym);
|
||||
auto* 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));
|
||||
isStartEndInverted.insert(std::make_pair(geoId, false));
|
||||
}
|
||||
else {
|
||||
Base::Console().Error("Unsupported Geometry!! Just copying it.\n");
|
||||
isStartEndInverted.insert(std::make_pair(*it, false));
|
||||
isStartEndInverted.insert(std::make_pair(geoId, false));
|
||||
}
|
||||
|
||||
newgeoVals.push_back(geosym);
|
||||
geoIdMap.insert(std::make_pair(*it, cgeoid));
|
||||
symmetricVals.push_back(geosym);
|
||||
geoIdMap.insert(std::make_pair(geoId, cgeoid));
|
||||
cgeoid++;
|
||||
}
|
||||
}
|
||||
else {// reference is a point
|
||||
refIsAxisAligned = true;
|
||||
Vector3d refpoint;
|
||||
const Part::Geometry* georef = getGeometry(refGeoId);
|
||||
|
||||
@@ -4496,160 +4684,43 @@ int SketchObject::addSymmetric(const std::vector<int>& geoIdList, int refGeoId,
|
||||
refpoint = Vector3d(0, 0, 0);
|
||||
}
|
||||
else {
|
||||
switch (refPosId) {
|
||||
case Sketcher::PointPos::start:
|
||||
if (georef->is<Part::GeomLineSegment>()) {
|
||||
const Part::GeomLineSegment* geosymline =
|
||||
static_cast<const Part::GeomLineSegment*>(georef);
|
||||
refpoint = geosymline->getStartPoint();
|
||||
}
|
||||
else if (georef->is<Part::GeomArcOfCircle>()) {
|
||||
const Part::GeomArcOfCircle* geoaoc =
|
||||
static_cast<const Part::GeomArcOfCircle*>(georef);
|
||||
refpoint = geoaoc->getStartPoint(true);
|
||||
}
|
||||
else if (georef->is<Part::GeomArcOfEllipse>()) {
|
||||
const Part::GeomArcOfEllipse* geosymaoe =
|
||||
static_cast<const Part::GeomArcOfEllipse*>(georef);
|
||||
refpoint = geosymaoe->getStartPoint(true);
|
||||
}
|
||||
else if (georef->is<Part::GeomArcOfHyperbola>()) {
|
||||
const Part::GeomArcOfHyperbola* geosymaoe =
|
||||
static_cast<const Part::GeomArcOfHyperbola*>(georef);
|
||||
refpoint = geosymaoe->getStartPoint(true);
|
||||
}
|
||||
else if (georef->is<Part::GeomArcOfParabola>()) {
|
||||
const Part::GeomArcOfParabola* geosymaoe =
|
||||
static_cast<const Part::GeomArcOfParabola*>(georef);
|
||||
refpoint = geosymaoe->getStartPoint(true);
|
||||
}
|
||||
else if (georef->is<Part::GeomBSplineCurve>()) {
|
||||
const Part::GeomBSplineCurve* geosymbsp =
|
||||
static_cast<const Part::GeomBSplineCurve*>(georef);
|
||||
refpoint = geosymbsp->getStartPoint();
|
||||
}
|
||||
break;
|
||||
case Sketcher::PointPos::end:
|
||||
if (georef->is<Part::GeomLineSegment>()) {
|
||||
const Part::GeomLineSegment* geosymline =
|
||||
static_cast<const Part::GeomLineSegment*>(georef);
|
||||
refpoint = geosymline->getEndPoint();
|
||||
}
|
||||
else if (georef->is<Part::GeomArcOfCircle>()) {
|
||||
const Part::GeomArcOfCircle* geoaoc =
|
||||
static_cast<const Part::GeomArcOfCircle*>(georef);
|
||||
refpoint = geoaoc->getEndPoint(true);
|
||||
}
|
||||
else if (georef->is<Part::GeomArcOfEllipse>()) {
|
||||
const Part::GeomArcOfEllipse* geosymaoe =
|
||||
static_cast<const Part::GeomArcOfEllipse*>(georef);
|
||||
refpoint = geosymaoe->getEndPoint(true);
|
||||
}
|
||||
else if (georef->is<Part::GeomArcOfHyperbola>()) {
|
||||
const Part::GeomArcOfHyperbola* geosymaoe =
|
||||
static_cast<const Part::GeomArcOfHyperbola*>(georef);
|
||||
refpoint = geosymaoe->getEndPoint(true);
|
||||
}
|
||||
else if (georef->is<Part::GeomArcOfParabola>()) {
|
||||
const Part::GeomArcOfParabola* geosymaoe =
|
||||
static_cast<const Part::GeomArcOfParabola*>(georef);
|
||||
refpoint = geosymaoe->getEndPoint(true);
|
||||
}
|
||||
else if (georef->is<Part::GeomBSplineCurve>()) {
|
||||
const Part::GeomBSplineCurve* geosymbsp =
|
||||
static_cast<const Part::GeomBSplineCurve*>(georef);
|
||||
refpoint = geosymbsp->getEndPoint();
|
||||
}
|
||||
break;
|
||||
case Sketcher::PointPos::mid:
|
||||
if (georef->is<Part::GeomCircle>()) {
|
||||
const Part::GeomCircle* geosymcircle =
|
||||
static_cast<const Part::GeomCircle*>(georef);
|
||||
refpoint = geosymcircle->getCenter();
|
||||
}
|
||||
else if (georef->is<Part::GeomArcOfCircle>()) {
|
||||
const Part::GeomArcOfCircle* geoaoc =
|
||||
static_cast<const Part::GeomArcOfCircle*>(georef);
|
||||
refpoint = geoaoc->getCenter();
|
||||
}
|
||||
else if (georef->is<Part::GeomEllipse>()) {
|
||||
const Part::GeomEllipse* geosymellipse =
|
||||
static_cast<const Part::GeomEllipse*>(georef);
|
||||
refpoint = geosymellipse->getCenter();
|
||||
}
|
||||
else if (georef->is<Part::GeomArcOfEllipse>()) {
|
||||
const Part::GeomArcOfEllipse* geosymaoe =
|
||||
static_cast<const Part::GeomArcOfEllipse*>(georef);
|
||||
refpoint = geosymaoe->getCenter();
|
||||
}
|
||||
else if (georef->is<Part::GeomArcOfHyperbola>()) {
|
||||
const Part::GeomArcOfHyperbola* geosymaoe =
|
||||
static_cast<const Part::GeomArcOfHyperbola*>(georef);
|
||||
refpoint = geosymaoe->getCenter();
|
||||
}
|
||||
else if (georef->is<Part::GeomArcOfParabola>()) {
|
||||
const Part::GeomArcOfParabola* geosymaoe =
|
||||
static_cast<const Part::GeomArcOfParabola*>(georef);
|
||||
refpoint = geosymaoe->getCenter();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Base::Console().Error("Wrong PointPosId.\n");
|
||||
return -1;
|
||||
if (refPosId == Sketcher::PointPos::none) {
|
||||
Base::Console().Error("Wrong PointPosId.\n");
|
||||
return {};
|
||||
}
|
||||
refpoint = getPoint(georef, refPosId);
|
||||
}
|
||||
|
||||
for (std::vector<int>::const_iterator it = geoIdList.begin(); it != geoIdList.end(); ++it) {
|
||||
const Part::Geometry* geo = getGeometry(*it);
|
||||
|
||||
for (auto geoId : geoIdList) {
|
||||
const Part::Geometry* geo = getGeometry(geoId);
|
||||
Part::Geometry* geosym;
|
||||
|
||||
auto gf = GeometryFacade::getFacade(geo);
|
||||
|
||||
if (gf->isInternalAligned()) {
|
||||
// only add this geometry if the corresponding geometry it defines is also in the
|
||||
// list.
|
||||
int definedGeo = GeoEnum::GeoUndef;
|
||||
|
||||
for (auto c : Constraints.getValues()) {
|
||||
if (c->Type == Sketcher::InternalAlignment && c->First == *it) {
|
||||
definedGeo = c->Second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (std::find(geoIdList.begin(), geoIdList.end(), definedGeo) != geoIdList.end())
|
||||
geosym = geo->copy();
|
||||
else {
|
||||
// we should not mirror internal alignment geometry, unless the element they
|
||||
// define is also mirrored
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
geosym = geo->copy();
|
||||
if (!shouldCopyGeometry(geo, geoId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
geosym = geo->copy();
|
||||
|
||||
// Handle Geometry
|
||||
if (geosym->is<Part::GeomLineSegment>()) {
|
||||
Part::GeomLineSegment* geosymline = static_cast<Part::GeomLineSegment*>(geosym);
|
||||
auto* 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));
|
||||
isStartEndInverted.insert(std::make_pair(geoId, false));
|
||||
}
|
||||
else if (geosym->is<Part::GeomCircle>()) {
|
||||
Part::GeomCircle* geosymcircle = static_cast<Part::GeomCircle*>(geosym);
|
||||
auto* 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));
|
||||
isStartEndInverted.insert(std::make_pair(geoId, false));
|
||||
}
|
||||
else if (geosym->is<Part::GeomArcOfCircle>()) {
|
||||
Part::GeomArcOfCircle* geoaoc = static_cast<Part::GeomArcOfCircle*>(geosym);
|
||||
auto* geoaoc = static_cast<Part::GeomArcOfCircle*>(geosym);
|
||||
Base::Vector3d sp = geoaoc->getStartPoint(true);
|
||||
Base::Vector3d ep = geoaoc->getEndPoint(true);
|
||||
Base::Vector3d cp = geoaoc->getCenter();
|
||||
@@ -4663,10 +4734,10 @@ int SketchObject::addSymmetric(const std::vector<int>& geoIdList, int refGeoId,
|
||||
|
||||
geoaoc->setCenter(scp);
|
||||
geoaoc->setRange(theta1, theta2, true);
|
||||
isStartEndInverted.insert(std::make_pair(*it, false));
|
||||
isStartEndInverted.insert(std::make_pair(geoId, false));
|
||||
}
|
||||
else if (geosym->is<Part::GeomEllipse>()) {
|
||||
Part::GeomEllipse* geosymellipse = static_cast<Part::GeomEllipse*>(geosym);
|
||||
auto* geosymellipse = static_cast<Part::GeomEllipse*>(geosym);
|
||||
Base::Vector3d cp = geosymellipse->getCenter();
|
||||
|
||||
Base::Vector3d majdir = geosymellipse->getMajorAxisDir();
|
||||
@@ -4681,10 +4752,10 @@ int SketchObject::addSymmetric(const std::vector<int>& geoIdList, int refGeoId,
|
||||
geosymellipse->setMajorAxisDir(sf1 - scp);
|
||||
|
||||
geosymellipse->setCenter(scp);
|
||||
isStartEndInverted.insert(std::make_pair(*it, false));
|
||||
isStartEndInverted.insert(std::make_pair(geoId, false));
|
||||
}
|
||||
else if (geosym->is<Part::GeomArcOfEllipse>()) {
|
||||
Part::GeomArcOfEllipse* geosymaoe = static_cast<Part::GeomArcOfEllipse*>(geosym);
|
||||
auto* geosymaoe = static_cast<Part::GeomArcOfEllipse*>(geosym);
|
||||
Base::Vector3d cp = geosymaoe->getCenter();
|
||||
|
||||
Base::Vector3d majdir = geosymaoe->getMajorAxisDir();
|
||||
@@ -4699,11 +4770,10 @@ int SketchObject::addSymmetric(const std::vector<int>& geoIdList, int refGeoId,
|
||||
geosymaoe->setMajorAxisDir(sf1 - scp);
|
||||
|
||||
geosymaoe->setCenter(scp);
|
||||
isStartEndInverted.insert(std::make_pair(*it, false));
|
||||
isStartEndInverted.insert(std::make_pair(geoId, false));
|
||||
}
|
||||
else if (geosym->is<Part::GeomArcOfHyperbola>()) {
|
||||
Part::GeomArcOfHyperbola* geosymaoe =
|
||||
static_cast<Part::GeomArcOfHyperbola*>(geosym);
|
||||
auto* geosymaoe = static_cast<Part::GeomArcOfHyperbola*>(geosym);
|
||||
Base::Vector3d cp = geosymaoe->getCenter();
|
||||
|
||||
Base::Vector3d majdir = geosymaoe->getMajorAxisDir();
|
||||
@@ -4718,10 +4788,10 @@ int SketchObject::addSymmetric(const std::vector<int>& geoIdList, int refGeoId,
|
||||
geosymaoe->setMajorAxisDir(sf1 - scp);
|
||||
|
||||
geosymaoe->setCenter(scp);
|
||||
isStartEndInverted.insert(std::make_pair(*it, false));
|
||||
isStartEndInverted.insert(std::make_pair(geoId, false));
|
||||
}
|
||||
else if (geosym->is<Part::GeomArcOfParabola>()) {
|
||||
Part::GeomArcOfParabola* geosymaoe = static_cast<Part::GeomArcOfParabola*>(geosym);
|
||||
auto* geosymaoe = static_cast<Part::GeomArcOfParabola*>(geosym);
|
||||
Base::Vector3d cp = geosymaoe->getCenter();
|
||||
|
||||
/*double df= geosymaoe->getFocal();*/
|
||||
@@ -4733,167 +4803,39 @@ int SketchObject::addSymmetric(const std::vector<int>& geoIdList, int refGeoId,
|
||||
geosymaoe->setXAxisDir(sf1 - scp);
|
||||
geosymaoe->setCenter(scp);
|
||||
|
||||
isStartEndInverted.insert(std::make_pair(*it, false));
|
||||
isStartEndInverted.insert(std::make_pair(geoId, false));
|
||||
}
|
||||
else if (geosym->is<Part::GeomBSplineCurve>()) {
|
||||
Part::GeomBSplineCurve* geosymbsp = static_cast<Part::GeomBSplineCurve*>(geosym);
|
||||
auto* geosymbsp = static_cast<Part::GeomBSplineCurve*>(geosym);
|
||||
|
||||
std::vector<Base::Vector3d> poles = geosymbsp->getPoles();
|
||||
|
||||
for (std::vector<Base::Vector3d>::iterator it = poles.begin(); it != poles.end();
|
||||
++it) {
|
||||
(*it) = (*it) + 2.0 * (refpoint - (*it));
|
||||
for (auto& pole : poles) {
|
||||
pole = pole + 2.0 * (refpoint - pole);
|
||||
}
|
||||
|
||||
geosymbsp->setPoles(poles);
|
||||
|
||||
// isStartEndInverted.insert(std::make_pair(*it, false));
|
||||
// isStartEndInverted.insert(std::make_pair(geoId, false));
|
||||
}
|
||||
else if (geosym->is<Part::GeomPoint>()) {
|
||||
Part::GeomPoint* geosympoint = static_cast<Part::GeomPoint*>(geosym);
|
||||
auto* 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));
|
||||
isStartEndInverted.insert(std::make_pair(geoId, false));
|
||||
}
|
||||
else {
|
||||
Base::Console().Error("Unsupported Geometry!! Just copying it.\n");
|
||||
isStartEndInverted.insert(std::make_pair(*it, false));
|
||||
isStartEndInverted.insert(std::make_pair(geoId, false));
|
||||
}
|
||||
|
||||
newgeoVals.push_back(geosym);
|
||||
geoIdMap.insert(std::make_pair(*it, cgeoid));
|
||||
symmetricVals.push_back(geosym);
|
||||
geoIdMap.insert(std::make_pair(geoId, cgeoid));
|
||||
cgeoid++;
|
||||
}
|
||||
}
|
||||
|
||||
// add the geometry
|
||||
|
||||
// Block acceptGeometry in OnChanged to avoid unnecessary checks and updates
|
||||
{
|
||||
Base::StateLocker lock(internaltransaction, true);
|
||||
Geometry.setValues(std::move(newgeoVals));
|
||||
|
||||
for (std::vector<Constraint*>::const_iterator it = constrvals.begin();
|
||||
it != constrvals.end();
|
||||
++it) {
|
||||
// we look in the map, because we might have skipped internal alignment geometry
|
||||
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 (refIsAxisAligned) {
|
||||
// in this case we want to keep the Vertical, Horizontal constraints
|
||||
// DistanceX ,and DistanceY constraints should also be possible to keep in
|
||||
// this case, but keeping them causes segfault, not sure why.
|
||||
|
||||
if ((*it)->Type != Sketcher::DistanceX
|
||||
&& (*it)->Type != Sketcher::DistanceY) {
|
||||
Constraint* constNew = (*it)->copy();
|
||||
constNew->First = fit->second;
|
||||
newconstrVals.push_back(constNew);
|
||||
}
|
||||
}
|
||||
else if ((*it)->Type != Sketcher::DistanceX
|
||||
&& (*it)->Type != Sketcher::DistanceY
|
||||
&& (*it)->Type != Sketcher::Vertical
|
||||
&& (*it)->Type != Sketcher::Horizontal) {
|
||||
// this includes all non-directional single GeoId constraints, as radius,
|
||||
// diameter, weight,...
|
||||
|
||||
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::Coincident
|
||||
|| (*it)->Type == Sketcher::Perpendicular
|
||||
|| (*it)->Type == Sketcher::Parallel
|
||||
|| (*it)->Type == Sketcher::Tangent
|
||||
|| (*it)->Type == Sketcher::Distance
|
||||
|| (*it)->Type == Sketcher::Equal || (*it)->Type == Sketcher::Angle
|
||||
|| (*it)->Type == Sketcher::PointOnObject
|
||||
|| (*it)->Type == Sketcher::InternalAlignment) {
|
||||
Constraint* constNew = (*it)->copy();
|
||||
|
||||
constNew->First = fit->second;
|
||||
constNew->Second = sit->second;
|
||||
if (isStartEndInverted[(*it)->First]) {
|
||||
if ((*it)->FirstPos == Sketcher::PointPos::start)
|
||||
constNew->FirstPos = Sketcher::PointPos::end;
|
||||
else if ((*it)->FirstPos == Sketcher::PointPos::end)
|
||||
constNew->FirstPos = Sketcher::PointPos::start;
|
||||
}
|
||||
if (isStartEndInverted[(*it)->Second]) {
|
||||
if ((*it)->SecondPos == Sketcher::PointPos::start)
|
||||
constNew->SecondPos = Sketcher::PointPos::end;
|
||||
else if ((*it)->SecondPos == Sketcher::PointPos::end)
|
||||
constNew->SecondPos = Sketcher::PointPos::start;
|
||||
}
|
||||
|
||||
if (constNew->Type == Tangent || constNew->Type == Perpendicular)
|
||||
AutoLockTangencyAndPerpty(constNew, true);
|
||||
|
||||
if (((*it)->Type == Sketcher::Angle)
|
||||
&& (refPosId == Sketcher::PointPos::none)) {
|
||||
constNew->setValue(-(*it)->getValue());
|
||||
}
|
||||
|
||||
newconstrVals.push_back(constNew);
|
||||
}
|
||||
}
|
||||
else {// three GeoIds intervene in constraint
|
||||
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;
|
||||
if (isStartEndInverted[(*it)->First]) {
|
||||
if ((*it)->FirstPos == Sketcher::PointPos::start)
|
||||
constNew->FirstPos = Sketcher::PointPos::end;
|
||||
else if ((*it)->FirstPos == Sketcher::PointPos::end)
|
||||
constNew->FirstPos = Sketcher::PointPos::start;
|
||||
}
|
||||
if (isStartEndInverted[(*it)->Second]) {
|
||||
if ((*it)->SecondPos == Sketcher::PointPos::start)
|
||||
constNew->SecondPos = Sketcher::PointPos::end;
|
||||
else if ((*it)->SecondPos == Sketcher::PointPos::end)
|
||||
constNew->SecondPos = Sketcher::PointPos::start;
|
||||
}
|
||||
if (isStartEndInverted[(*it)->Third]) {
|
||||
if ((*it)->ThirdPos == Sketcher::PointPos::start)
|
||||
constNew->ThirdPos = Sketcher::PointPos::end;
|
||||
else if ((*it)->ThirdPos == Sketcher::PointPos::end)
|
||||
constNew->ThirdPos = Sketcher::PointPos::start;
|
||||
}
|
||||
newconstrVals.push_back(constNew);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newconstrVals.size() > constrvals.size())
|
||||
Constraints.setValues(std::move(newconstrVals));
|
||||
}
|
||||
|
||||
// we delayed update, so trigger it now.
|
||||
// Update geometry indices and rebuild vertexindex now via onChanged, so that
|
||||
// ViewProvider::UpdateData is triggered.
|
||||
Geometry.touch();
|
||||
|
||||
return Geometry.getSize() - 1;
|
||||
return symmetricVals;
|
||||
}
|
||||
|
||||
int SketchObject::addCopy(const std::vector<int>& geoIdList, const Base::Vector3d& displacement,
|
||||
|
||||
Reference in New Issue
Block a user