Sketcher - Add new Split Edge action
This commit is contained in:
committed by
abdullahtahiriyo
parent
9209d35390
commit
a7d83b5e15
@@ -1647,7 +1647,7 @@ void SketchObject::transferFilletConstraints(int geoId1, PointPos posId1, int ge
|
||||
this->Constraints.setValues(std::move(newConstraints));
|
||||
}
|
||||
|
||||
int SketchObject::transferConstraints(int fromGeoId, PointPos fromPosId, int toGeoId, PointPos toPosId)
|
||||
int SketchObject::transferConstraints(int fromGeoId, PointPos fromPosId, int toGeoId, PointPos toPosId, bool tangencyHolds)
|
||||
{
|
||||
Base::StateLocker lock(managedoperation, true); // no need to check input data validity as this is an sketchobject managed operation.
|
||||
|
||||
@@ -1659,15 +1659,17 @@ int SketchObject::transferConstraints(int fromGeoId, PointPos fromPosId, int toG
|
||||
!(vals[i]->Second == toGeoId && vals[i]->SecondPos == toPosId) &&
|
||||
!(toGeoId < 0 && vals[i]->Second <0) ) {
|
||||
|
||||
// Nothing guarantees that a tangent can be freely transferred to another coincident point, as
|
||||
// the transfer destination edge most likely won't be intended to be tangent. However, if it is
|
||||
// an end to end point tangency, the user expects it to be substituted by a coincidence constraint.
|
||||
std::unique_ptr<Constraint> constNew(newVals[i]->clone());
|
||||
constNew->First = toGeoId;
|
||||
constNew->FirstPos = toPosId;
|
||||
|
||||
if(vals[i]->Type == Sketcher::Tangent || vals[i]->Type == Sketcher::Perpendicular){
|
||||
constNew->Type = Sketcher::Coincident;
|
||||
// If not explicitly confirmed, nothing guarantees that a tangent can be freely transferred to another coincident
|
||||
// point, as the transfer destination edge most likely won't be intended to be tangent. However, if it is
|
||||
// an end to end point tangency, the user expects it to be substituted by a coincidence constraint.
|
||||
if (vals[i]->Type == Sketcher::Tangent || vals[i]->Type == Sketcher::Perpendicular) {
|
||||
if (!tangencyHolds) {
|
||||
constNew->Type = Sketcher::Coincident;
|
||||
}
|
||||
}
|
||||
// With respect to angle constraints, if it is a DeepSOIC style angle constraint (segment+segment+point),
|
||||
// then no problem arises as the segments are PosId=none. In this case there is no call to this function.
|
||||
@@ -1690,11 +1692,13 @@ int SketchObject::transferConstraints(int fromGeoId, PointPos fromPosId, int toG
|
||||
std::unique_ptr<Constraint> constNew(newVals[i]->clone());
|
||||
constNew->Second = toGeoId;
|
||||
constNew->SecondPos = toPosId;
|
||||
// Nothing guarantees that a tangent can be freely transferred to another coincident point, as
|
||||
// the transfer destination edge most likely won't be intended to be tangent. However, if it is
|
||||
// If not explicitly confirmed, nothing guarantees that a tangent can be freely transferred to another coincident
|
||||
// point, as the transfer destination edge most likely won't be intended to be tangent. However, if it is
|
||||
// an end to end point tangency, the user expects it to be substituted by a coincidence constraint.
|
||||
if(vals[i]->Type == Sketcher::Tangent || vals[i]->Type == Sketcher::Perpendicular) {
|
||||
constNew->Type = Sketcher::Coincident;
|
||||
if (vals[i]->Type == Sketcher::Tangent || vals[i]->Type == Sketcher::Perpendicular) {
|
||||
if (!tangencyHolds) {
|
||||
constNew->Type = Sketcher::Coincident;
|
||||
}
|
||||
}
|
||||
else if(vals[i]->Type == Sketcher::Angle) {
|
||||
continue;
|
||||
@@ -1713,6 +1717,19 @@ int SketchObject::transferConstraints(int fromGeoId, PointPos fromPosId, int toG
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SketchObject::swapInvolvedGeometry(Constraint *constraint, int fromGeoId, int toGeoId)
|
||||
{
|
||||
if (constraint->First == fromGeoId) {
|
||||
constraint->First = toGeoId;
|
||||
}
|
||||
if (constraint->Second == fromGeoId) {
|
||||
constraint->Second = toGeoId;
|
||||
}
|
||||
if (constraint->Third == fromGeoId) {
|
||||
constraint->Third = toGeoId;
|
||||
}
|
||||
}
|
||||
|
||||
int SketchObject::fillet(int GeoId, PointPos PosId, double radius, bool trim, bool createCorner)
|
||||
{
|
||||
if (GeoId < 0 || GeoId > getHighestCurveIndex())
|
||||
@@ -2964,6 +2981,312 @@ int SketchObject::trim(int GeoId, const Base::Vector3d& point)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int SketchObject::split(int GeoId, const Base::Vector3d &point)
|
||||
{
|
||||
// No need to check input data validity as this is an sketchobject managed operation
|
||||
|
||||
Base::StateLocker lock(managedoperation, true);
|
||||
|
||||
if (GeoId < 0 || GeoId > getHighestCurveIndex()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const Part::Geometry *geo = getGeometry(GeoId);
|
||||
std::vector<Part::Geometry *> newGeometries;
|
||||
std::vector<int> newIds;
|
||||
std::vector<Constraint *> newConstraints;
|
||||
bool ok = false;
|
||||
|
||||
Base::Vector3d startPoint, endPoint, splitPoint;
|
||||
double radius, startAngle, endAngle, splitAngle;
|
||||
unsigned int longestPart = 0;
|
||||
|
||||
do {
|
||||
if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
|
||||
const Part::GeomLineSegment *lineSegm = static_cast<const Part::GeomLineSegment *>(geo);
|
||||
|
||||
startPoint = lineSegm->getStartPoint();
|
||||
endPoint = lineSegm->getEndPoint();
|
||||
splitPoint = point.Perpendicular(startPoint, endPoint - startPoint);
|
||||
if ((endPoint - splitPoint).Length() > (splitPoint - startPoint).Length()) {
|
||||
longestPart = 1;
|
||||
}
|
||||
|
||||
Part::GeomLineSegment *newLine = static_cast<Part::GeomLineSegment *>(lineSegm->copy());
|
||||
newGeometries.push_back(newLine);
|
||||
|
||||
newLine->setPoints(startPoint, splitPoint);
|
||||
int newId = addGeometry(newLine);
|
||||
if (newId < 0) {
|
||||
continue;
|
||||
}
|
||||
newIds.push_back(newId);
|
||||
setConstruction(newId, GeometryFacade::getConstruction(geo));
|
||||
|
||||
newLine = static_cast<Part::GeomLineSegment *>(lineSegm->copy());
|
||||
newGeometries.push_back(newLine);
|
||||
|
||||
newLine->setPoints(splitPoint, endPoint);
|
||||
newId = addGeometry(newLine);
|
||||
if (newId < 0) {
|
||||
continue;
|
||||
}
|
||||
newIds.push_back(newId);
|
||||
setConstruction(newId, GeometryFacade::getConstruction(geo));
|
||||
|
||||
Constraint *joint = new Constraint();
|
||||
joint->Type = Coincident;
|
||||
joint->First = newIds[0];
|
||||
joint->FirstPos = end;
|
||||
joint->Second = newIds[1];
|
||||
joint->SecondPos = start;
|
||||
newConstraints.push_back(joint);
|
||||
|
||||
transferConstraints(GeoId, start, newIds[0], start, true);
|
||||
transferConstraints(GeoId, end, newIds[1], end, true);
|
||||
ok = true;
|
||||
}
|
||||
else if (geo->getTypeId() == Part::GeomCircle::getClassTypeId()) {
|
||||
const Part::GeomCircle *circle = static_cast<const Part::GeomCircle *>(geo);
|
||||
|
||||
Base::Vector3d center(circle->getLocation());
|
||||
Base::Vector3d dir(point - center);
|
||||
radius = circle->getRadius();
|
||||
|
||||
splitAngle = atan2(dir.y, dir.x);
|
||||
startAngle = splitAngle;
|
||||
endAngle = splitAngle + M_PI*2.0;
|
||||
|
||||
splitPoint = Base::Vector3d(center.x + radius*cos(splitAngle), center.y + radius*sin(splitAngle));
|
||||
startPoint = splitPoint;
|
||||
endPoint = splitPoint;
|
||||
|
||||
Part::GeomArcOfCircle *arc = new Part::GeomArcOfCircle();
|
||||
newGeometries.push_back(arc);
|
||||
|
||||
arc->setLocation(center);
|
||||
arc->setRadius(radius);
|
||||
arc->setRange(startAngle, endAngle, false);
|
||||
int arcId = addGeometry(arc);
|
||||
if (arcId < 0) {
|
||||
continue;
|
||||
}
|
||||
newIds.push_back(arcId);
|
||||
setConstruction(arcId, GeometryFacade::getConstruction(geo));
|
||||
|
||||
transferConstraints(GeoId, mid, arcId, mid);
|
||||
ok = true;
|
||||
}
|
||||
else if (geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) {
|
||||
const Part::GeomArcOfCircle *arc = static_cast<const Part::GeomArcOfCircle *>(geo);
|
||||
|
||||
startPoint = arc->getStartPoint();
|
||||
endPoint = arc->getEndPoint();
|
||||
|
||||
Base::Vector3d center(arc->getLocation());
|
||||
radius = arc->getRadius();
|
||||
arc->getRange(startAngle, endAngle, false);
|
||||
|
||||
Base::Vector3d dir(point - center);
|
||||
splitAngle = atan2(dir.y, dir.x);
|
||||
if (splitAngle < startAngle) {
|
||||
splitAngle += M_PI*2.0;
|
||||
}
|
||||
if (endAngle - splitAngle > splitAngle - startAngle) {
|
||||
longestPart = 1;
|
||||
}
|
||||
|
||||
splitPoint = Base::Vector3d(center.x + radius*cos(splitAngle), center.y + radius*sin(splitAngle));
|
||||
startPoint = splitPoint;
|
||||
endPoint = splitPoint;
|
||||
|
||||
Part::GeomArcOfCircle *newArc = static_cast<Part::GeomArcOfCircle *>(arc->copy());
|
||||
newGeometries.push_back(newArc);
|
||||
|
||||
newArc->setRange(startAngle, splitAngle, false);
|
||||
int newId = addGeometry(newArc);
|
||||
if (newId < 0) {
|
||||
continue;
|
||||
}
|
||||
newIds.push_back(newId);
|
||||
setConstruction(newId, GeometryFacade::getConstruction(geo));
|
||||
|
||||
newArc = static_cast<Part::GeomArcOfCircle *>(arc->copy());
|
||||
newGeometries.push_back(newArc);
|
||||
|
||||
newArc->setRange(splitAngle, endAngle, false);
|
||||
newId = addGeometry(newArc);
|
||||
if (newId < 0) {
|
||||
continue;
|
||||
}
|
||||
newIds.push_back(newId);
|
||||
setConstruction(newId, GeometryFacade::getConstruction(geo));
|
||||
|
||||
Constraint *joint = new Constraint();
|
||||
joint->Type = Coincident;
|
||||
joint->First = newIds[0];
|
||||
joint->FirstPos = end;
|
||||
joint->Second = newIds[1];
|
||||
joint->SecondPos = start;
|
||||
newConstraints.push_back(joint);
|
||||
|
||||
joint = new Constraint();
|
||||
joint->Type = Coincident;
|
||||
joint->First = newIds[0];
|
||||
joint->FirstPos = mid;
|
||||
joint->Second = newIds[1];
|
||||
joint->SecondPos = mid;
|
||||
newConstraints.push_back(joint);
|
||||
|
||||
transferConstraints(GeoId, start, newIds[0], start, true);
|
||||
transferConstraints(GeoId, mid, newIds[0], mid);
|
||||
transferConstraints(GeoId, end, newIds[1], end, true);
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
while (false);
|
||||
|
||||
if (ok) {
|
||||
std::vector<int> oldConstraints;
|
||||
getAppliedConstraints(GeoId, oldConstraints);
|
||||
|
||||
for (unsigned int i = 0; i < oldConstraints.size(); ++i) {
|
||||
|
||||
Constraint *con = this->Constraints.getValues()[oldConstraints[i]];
|
||||
int conId = con->First;
|
||||
PointPos conPos = con->FirstPos;
|
||||
if (conId == GeoId) {
|
||||
conId = con->Second;
|
||||
conPos = con->SecondPos;
|
||||
}
|
||||
|
||||
bool transferToAll = false;
|
||||
switch (con->Type) {
|
||||
case Horizontal:
|
||||
case Vertical:
|
||||
case Parallel: {
|
||||
transferToAll = geo->getTypeId() == Part::GeomLineSegment::getClassTypeId();
|
||||
break;
|
||||
}
|
||||
case Tangent:
|
||||
case Perpendicular: {
|
||||
unsigned int initial = 0;
|
||||
unsigned int limit = newIds.size();
|
||||
|
||||
if (geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) {
|
||||
const Part::Geometry *conGeo = getGeometry(conId);
|
||||
if (conGeo && conGeo->isDerivedFrom(Part::GeomCurve::getClassTypeId())) {
|
||||
std::vector<std::pair<Base::Vector3d, Base::Vector3d>> intersections;
|
||||
bool intersects[2];
|
||||
|
||||
intersects[0] = static_cast<const Part::GeomCurve *>(newGeometries[0])->
|
||||
intersect(static_cast<const Part::GeomCurve *>(conGeo), intersections);
|
||||
intersects[1] = static_cast<const Part::GeomCurve *>(newGeometries[1])->
|
||||
intersect(static_cast<const Part::GeomCurve *>(conGeo), intersections);
|
||||
|
||||
initial = longestPart;
|
||||
if (intersects[0] != intersects[1]) {
|
||||
initial = intersects[1] ? 1 : 0;
|
||||
}
|
||||
limit = initial + 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int i = initial; i < limit; ++i) {
|
||||
Constraint *trans = con->copy();
|
||||
swapInvolvedGeometry(trans, GeoId, newIds[i]);
|
||||
newConstraints.push_back(trans);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Distance:
|
||||
case DistanceX:
|
||||
case DistanceY:
|
||||
case PointOnObject: {
|
||||
if (con->FirstPos == none && con->SecondPos == none) {
|
||||
Constraint *dist = con->copy();
|
||||
dist->First = newIds[0];
|
||||
dist->FirstPos = start;
|
||||
dist->Second = newIds[1];
|
||||
dist->SecondPos = end;
|
||||
newConstraints.push_back(dist);
|
||||
}
|
||||
else {
|
||||
Constraint *trans = con->copy();
|
||||
trans->First = conId;
|
||||
trans->FirstPos = conPos;
|
||||
trans->SecondPos = none;
|
||||
|
||||
Base::Vector3d conPoint(getPoint(conId, conPos));
|
||||
int targetId = newIds[0];
|
||||
|
||||
if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
|
||||
Base::Vector3d projPoint(conPoint.Perpendicular(startPoint, endPoint - startPoint));
|
||||
Base::Vector3d splitDir = splitPoint - startPoint;
|
||||
if ((projPoint - startPoint)*splitDir > splitDir*splitDir) {
|
||||
targetId = newIds[1];
|
||||
}
|
||||
}
|
||||
else if (geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) {
|
||||
Base::Vector3d conDir(conPoint - static_cast<const Part::GeomArcOfCircle *>(geo)->getLocation());
|
||||
double conAngle = atan2(conDir.y, conDir.x);
|
||||
if (conAngle < startAngle) {
|
||||
conAngle += M_PI*2.0;
|
||||
}
|
||||
if (conAngle > splitAngle) {
|
||||
targetId = newIds[1];
|
||||
}
|
||||
}
|
||||
trans->Second = targetId;
|
||||
|
||||
newConstraints.push_back(trans);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Radius:
|
||||
case Diameter:
|
||||
case Equal: {
|
||||
transferToAll = geo->getTypeId() == Part::GeomCircle::getClassTypeId()
|
||||
|| geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// Release other constraints
|
||||
break;
|
||||
}
|
||||
|
||||
if (transferToAll) {
|
||||
for (unsigned int i = 0; i < newIds.size(); ++i) {
|
||||
Constraint *trans = con->copy();
|
||||
swapInvolvedGeometry(trans, GeoId, newIds[i]);
|
||||
newConstraints.push_back(trans);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (noRecomputes) {
|
||||
solve();
|
||||
}
|
||||
|
||||
delConstraints(oldConstraints);
|
||||
addConstraints(newConstraints);
|
||||
}
|
||||
|
||||
for (std::vector<Part::Geometry *>::iterator it = newGeometries.begin(); it != newGeometries.end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
for (std::vector<Constraint *>::iterator it = newConstraints.begin(); it != newConstraints.end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
delGeometry(GeoId);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool SketchObject::isExternalAllowed(App::Document *pDoc, App::DocumentObject *pObj, eReasonList* rsn) const
|
||||
{
|
||||
if (rsn)
|
||||
@@ -6826,6 +7149,19 @@ bool SketchObject::arePointsCoincident(int GeoId1, PointPos PosId1,
|
||||
return false;
|
||||
}
|
||||
|
||||
void SketchObject::getAppliedConstraints(int GeoId, std::vector<int> &constraintList)
|
||||
{
|
||||
const std::vector<Constraint *> &constraints = this->Constraints.getValues();
|
||||
int i = 0;
|
||||
|
||||
for (std::vector<Constraint *>::const_iterator it = constraints.begin(); it != constraints.end(); ++it) {
|
||||
if ((*it)->First == GeoId || (*it)->Second == GeoId || (*it)->Third == GeoId) {
|
||||
constraintList.push_back(i);
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
void SketchObject::appendConflictMsg(const std::vector<int> &conflicting, std::string &msg)
|
||||
{
|
||||
appendConstraintsMsg(conflicting,
|
||||
|
||||
Reference in New Issue
Block a user