diff --git a/src/Gui/PreferencePackTemplates/Shortcuts.cfg b/src/Gui/PreferencePackTemplates/Shortcuts.cfg
index 48572b9e34..c82e3fd307 100644
--- a/src/Gui/PreferencePackTemplates/Shortcuts.cfg
+++ b/src/Gui/PreferencePackTemplates/Shortcuts.cfg
@@ -548,7 +548,7 @@
G, B, P
G, B, O
G, Y
- G, F, P
+ G, F, C
G, M
G, R
G, V
diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp
index 8312902534..ecb6c9abe6 100644
--- a/src/Mod/Sketcher/App/SketchObject.cpp
+++ b/src/Mod/Sketcher/App/SketchObject.cpp
@@ -2065,7 +2065,7 @@ int SketchObject::transferConstraints(int fromGeoId, PointPos fromPosId, int toG
return 0;
}
-int SketchObject::fillet(int GeoId, PointPos PosId, double radius, bool trim, bool createCorner)
+int SketchObject::fillet(int GeoId, PointPos PosId, double radius, bool trim, bool createCorner, bool chamfer)
{
if (GeoId < 0 || GeoId > getHighestCurveIndex())
return -1;
@@ -2081,12 +2081,12 @@ int SketchObject::fillet(int GeoId, PointPos PosId, double radius, bool trim, bo
const Part::Geometry* geo2 = getGeometry(GeoIdList[1]);
if (geo1->is()
&& geo2->is()) {
- const Part::GeomLineSegment* lineSeg1 = static_cast(geo1);
- const Part::GeomLineSegment* lineSeg2 = static_cast(geo2);
+ auto* lineSeg1 = static_cast(geo1);
+ auto* lineSeg2 = static_cast(geo2);
Base::Vector3d midPnt1 = (lineSeg1->getStartPoint() + lineSeg1->getEndPoint()) / 2;
Base::Vector3d midPnt2 = (lineSeg2->getStartPoint() + lineSeg2->getEndPoint()) / 2;
- return fillet(GeoIdList[0], GeoIdList[1], midPnt1, midPnt2, radius, trim, createCorner);
+ return fillet(GeoIdList[0], GeoIdList[1], midPnt1, midPnt2, radius, trim, createCorner, chamfer);
}
}
@@ -2094,11 +2094,11 @@ int SketchObject::fillet(int GeoId, PointPos PosId, double radius, bool trim, bo
}
int SketchObject::fillet(int GeoId1, int GeoId2, const Base::Vector3d& refPnt1,
- const Base::Vector3d& refPnt2, double radius, bool trim, bool createCorner)
+ const Base::Vector3d& refPnt2, double radius, bool trim, bool createCorner, bool chamfer)
{
- if (GeoId1 < 0 || GeoId1 > getHighestCurveIndex() || GeoId2 < 0
- || GeoId2 > getHighestCurveIndex())
+ if (GeoId1 < 0 || GeoId1 > getHighestCurveIndex() || GeoId2 < 0 || GeoId2 > getHighestCurveIndex()) {
return -1;
+ }
// If either of the two input lines are locked, don't try to trim since it won't work anyway
const Part::Geometry* geo1 = getGeometry(GeoId1);
@@ -2107,14 +2107,19 @@ int SketchObject::fillet(int GeoId1, int GeoId2, const Base::Vector3d& refPnt1,
trim = false;
}
- if (geo1->is()
- && geo2->is()) {
- const Part::GeomLineSegment* lineSeg1 = static_cast(geo1);
- const Part::GeomLineSegment* lineSeg2 = static_cast(geo2);
+ Base::Vector3d p1, p2;
+ PointPos PosId1 = PointPos::none;
+ PointPos PosId2 = PointPos::none;
+ int filletId;
+
+ if (geo1->is() && geo2->is()) {
+ auto* lineSeg1 = static_cast(geo1);
+ auto* lineSeg2 = static_cast(geo2);
Base::Vector3d filletCenter;
- if (!Part::findFilletCenter(lineSeg1, lineSeg2, radius, refPnt1, refPnt2, filletCenter))
+ if (!Part::findFilletCenter(lineSeg1, lineSeg2, radius, refPnt1, refPnt2, filletCenter)) {
return -1;
+ }
Base::Vector3d dir1 = lineSeg1->getEndPoint() - lineSeg1->getStartPoint();
Base::Vector3d dir2 = lineSeg2->getEndPoint() - lineSeg2->getStartPoint();
@@ -2123,27 +2128,27 @@ int SketchObject::fillet(int GeoId1, int GeoId2, const Base::Vector3d& refPnt1,
Base::Vector3d intersection, dist1, dist2;
// create arc from known parameters and lines
- int filletId;
std::unique_ptr arc(
Part::createFilletGeometry(lineSeg1, lineSeg2, filletCenter, radius));
- if (!arc)
+ if (!arc) {
return -1;
+ }
// calculate intersection and distances before we invalidate lineSeg1 and lineSeg2
if (!find2DLinesIntersection(lineSeg1, lineSeg2, intersection)) {
return -1;
}
+ p1 = arc->getStartPoint();
+ p2 = arc->getEndPoint();
+
dist1.ProjectToLine(arc->getStartPoint(/*emulateCCW=*/true) - intersection, dir1);
dist2.ProjectToLine(arc->getStartPoint(/*emulateCCW=*/true) - intersection, dir2);
- Part::Geometry* newgeo = arc.get();
- filletId = addGeometry(newgeo);
+ filletId = addGeometry(arc.get());
if (trim) {
- PointPos PosId1 =
- (filletCenter - intersection) * dir1 > 0 ? PointPos::start : PointPos::end;
- PointPos PosId2 =
- (filletCenter - intersection) * dir2 > 0 ? PointPos::start : PointPos::end;
+ PosId1 = (filletCenter - intersection) * dir1 > 0 ? PointPos::start : PointPos::end;
+ PosId2 = (filletCenter - intersection) * dir2 > 0 ? PointPos::start : PointPos::end;
if (createCorner) {
transferFilletConstraints(GeoId1, PosId1, GeoId2, PosId2);
@@ -2182,16 +2187,8 @@ int SketchObject::fillet(int GeoId1, int GeoId2, const Base::Vector3d& refPnt1,
addConstraint(std::move(tangent1));
addConstraint(std::move(tangent2));
}
-
- // if we do not have a recompute after the geometry creation, the sketch must be solved to
- // update the DoF of the solver
- if (noRecomputes)
- solve();
-
- return 0;
}
- else if (geo1->isDerivedFrom()
- && geo2->isDerivedFrom()) {
+ else if (geo1->isDerivedFrom() && geo2->isDerivedFrom()) {
auto distancetorefpoints =
[](Base::Vector3d ip1, Base::Vector3d ip2, Base::Vector3d ref1, Base::Vector3d ref2) {
@@ -2284,40 +2281,35 @@ int SketchObject::fillet(int GeoId1, int GeoId2, const Base::Vector3d& refPnt1,
// look for coincident constraints between curves, take the coincident closest to the
// refpoints
- Sketcher::PointPos curve1PosId = Sketcher::PointPos::none;
- Sketcher::PointPos curve2PosId = Sketcher::PointPos::none;
-
double dist = INFINITY;
const std::vector& constraints = this->Constraints.getValues();
- for (std::vector::const_iterator it = constraints.begin();
- it != constraints.end();
- ++it) {
- if ((*it)->Type == Sketcher::Coincident || (*it)->Type == Sketcher::Perpendicular
- || (*it)->Type == Sketcher::Tangent) {
- if ((*it)->First == GeoId1 && (*it)->Second == GeoId2
- && (*it)->FirstPos != Sketcher::PointPos::none
- && (*it)->SecondPos != Sketcher::PointPos::none) {
- Base::Vector3d tmpp1 = getPoint((*it)->First, (*it)->FirstPos);
- Base::Vector3d tmpp2 = getPoint((*it)->Second, (*it)->SecondPos);
+ for (auto& constr : constraints) {
+ if (constr->Type == Sketcher::Coincident || constr->Type == Sketcher::Perpendicular
+ || constr->Type == Sketcher::Tangent) {
+ if (constr->First == GeoId1 && constr->Second == GeoId2
+ && constr->FirstPos != PointPos::none
+ && constr->SecondPos != PointPos::none) {
+ Base::Vector3d tmpp1 = getPoint(constr->First, constr->FirstPos);
+ Base::Vector3d tmpp2 = getPoint(constr->Second, constr->SecondPos);
double tmpdist = distancetorefpoints(tmpp1, tmpp2, refPnt1, refPnt2);
if (tmpdist < dist) {
- curve1PosId = (*it)->FirstPos;
- curve2PosId = (*it)->SecondPos;
+ PosId1 = constr->FirstPos;
+ PosId2 = constr->SecondPos;
dist = tmpdist;
interpoints = std::make_pair(tmpp1, tmpp2);
}
}
- else if ((*it)->First == GeoId2 && (*it)->Second == GeoId1
- && (*it)->FirstPos != Sketcher::PointPos::none
- && (*it)->SecondPos != Sketcher::PointPos::none) {
- Base::Vector3d tmpp2 = getPoint((*it)->First, (*it)->FirstPos);
- Base::Vector3d tmpp1 = getPoint((*it)->Second, (*it)->SecondPos);
+ else if (constr->First == GeoId2 && constr->Second == GeoId1
+ && constr->FirstPos != PointPos::none
+ && constr->SecondPos != PointPos::none) {
+ Base::Vector3d tmpp2 = getPoint(constr->First, constr->FirstPos);
+ Base::Vector3d tmpp1 = getPoint(constr->Second, constr->SecondPos);
double tmpdist = distancetorefpoints(tmpp1, tmpp2, refPnt1, refPnt2);
if (tmpdist < dist) {
- curve2PosId = (*it)->FirstPos;
- curve1PosId = (*it)->SecondPos;
+ PosId2 = constr->FirstPos;
+ PosId1 = constr->SecondPos;
dist = tmpdist;
interpoints = std::make_pair(tmpp1, tmpp2);
}
@@ -2325,15 +2317,13 @@ int SketchObject::fillet(int GeoId1, int GeoId2, const Base::Vector3d& refPnt1,
}
}
- if (curve1PosId == Sketcher::PointPos::none) {
+ if (PosId1 == PointPos::none) {
// no coincident was found, try basis curve intersection if GeomTrimmedCurve
- if (geo1->isDerivedFrom(Part::GeomTrimmedCurve::getClassTypeId())
- && geo2->isDerivedFrom(Part::GeomTrimmedCurve::getClassTypeId())) {
+ if (geo1->isDerivedFrom()
+ && geo2->isDerivedFrom()) {
- const Part::GeomTrimmedCurve* tcurve1 =
- static_cast(geo1);
- const Part::GeomTrimmedCurve* tcurve2 =
- static_cast(geo2);
+ auto* tcurve1 =static_cast(geo1);
+ auto* tcurve2 = static_cast(geo2);
try {
if (!tcurve1->intersectBasisCurves(tcurve2, points))
@@ -2350,11 +2340,13 @@ int SketchObject::fillet(int GeoId1, int GeoId2, const Base::Vector3d& refPnt1,
int res = selectintersection(points, interpoints, refPnt1, refPnt2);
- if (res != 0)
+ if (res != 0) {
return res;
+ }
}
- else
+ else {
return -1;// not a GeomTrimmedCurve and no coincident point.
+ }
}
// Now that we know where the curves intersect, get the parameters in the curves of those
@@ -2363,8 +2355,9 @@ int SketchObject::fillet(int GeoId1, int GeoId2, const Base::Vector3d& refPnt1,
double intparam2;
try {
- if (!curve1->closestParameter(interpoints.first, intparam1))
+ if (!curve1->closestParameter(interpoints.first, intparam1)) {
return -1;
+ }
}
catch (Base::CADKernelError& e) {
e.ReportException();
@@ -2374,8 +2367,9 @@ int SketchObject::fillet(int GeoId1, int GeoId2, const Base::Vector3d& refPnt1,
}
try {
- if (!curve2->closestParameter(interpoints.second, intparam2))
+ if (!curve2->closestParameter(interpoints.second, intparam2)) {
return -1;
+ }
}
catch (Base::CADKernelError& e) {
e.ReportException();
@@ -2439,8 +2433,7 @@ int SketchObject::fillet(int GeoId1, int GeoId2, const Base::Vector3d& refPnt1,
/ det,
0);
- radius =
- ((refp1 - normalintersect).Length() + (refp2 - normalintersect).Length()) / 2;
+ radius = ((refp1 - normalintersect).Length() + (refp2 - normalintersect).Length()) / 2;
}
catch (const Base::Exception&) {
radius = ref21.Length();// fall-back to simplest estimation.
@@ -2543,8 +2536,9 @@ int SketchObject::fillet(int GeoId1, int GeoId2, const Base::Vector3d& refPnt1,
int res = selectintersection(offsetintersectionpoints, filletcenterpoint, refPnt1, refPnt2);
- if (res != 0)
+ if (res != 0) {
return res;
+ }
#ifdef DEBUG
Base::Console().Log(
@@ -2555,8 +2549,9 @@ int SketchObject::fillet(int GeoId1, int GeoId2, const Base::Vector3d& refPnt1,
double refoparam2;
try {
- if (!curve1->closestParameter(filletcenterpoint.first, refoparam1))
+ if (!curve1->closestParameter(filletcenterpoint.first, refoparam1)) {
return -1;
+ }
}
catch (Base::CADKernelError& e) {
e.ReportException();
@@ -2564,8 +2559,9 @@ int SketchObject::fillet(int GeoId1, int GeoId2, const Base::Vector3d& refPnt1,
}
try {
- if (!curve2->closestParameter(filletcenterpoint.second, refoparam2))
+ if (!curve2->closestParameter(filletcenterpoint.second, refoparam2)) {
return -1;
+ }
}
catch (Base::CADKernelError& e) {
e.ReportException();
@@ -2599,25 +2595,29 @@ int SketchObject::fillet(int GeoId1, int GeoId2, const Base::Vector3d& refPnt1,
endAngle = startAngle + range;
- if (endAngle < startAngle)
+ if (endAngle < startAngle) {
std::swap(startAngle, endAngle);
+ }
- if (endAngle > 2 * M_PI)
+ if (endAngle > 2 * M_PI) {
endAngle -= 2 * M_PI;
+ }
- if (startAngle < 0)
+ if (startAngle < 0) {
endAngle += 2 * M_PI;
+ }
// Create Arc Segment
- Part::GeomArcOfCircle* arc = new Part::GeomArcOfCircle();
+ auto* arc = new Part::GeomArcOfCircle();
arc->setRadius(radDir1.Length());
arc->setCenter(filletcenterpoint.first);
arc->setRange(startAngle, endAngle, /*emulateCCWXY=*/true);
+ p1 = arc->getStartPoint();
+ p2 = arc->getEndPoint();
+
// add arc to sketch geometry
- int filletId;
- Part::Geometry* newgeo = arc;
- filletId = addGeometry(newgeo);
+ filletId = addGeometry(arc);
if (filletId < 0) {
delete arc;
return -1;
@@ -2639,27 +2639,27 @@ int SketchObject::fillet(int GeoId1, int GeoId2, const Base::Vector3d& refPnt1,
// b) we used the basis curve intersection
- if (curve1PosId == Sketcher::PointPos::none) {
- curve1PosId = selectend(intparam1, refoparam1, spc1);
- curve2PosId = selectend(intparam2, refoparam2, spc2);
+ if (PosId1 == Sketcher::PointPos::none) {
+ PosId1 = selectend(intparam1, refoparam1, spc1);
+ PosId2 = selectend(intparam2, refoparam2, spc2);
}
- delConstraintOnPoint(GeoId1, curve1PosId, false);
- delConstraintOnPoint(GeoId2, curve2PosId, false);
+ delConstraintOnPoint(GeoId1, PosId1, false);
+ delConstraintOnPoint(GeoId2, PosId2, false);
- Sketcher::Constraint* tangent1 = new Sketcher::Constraint();
- Sketcher::Constraint* tangent2 = new Sketcher::Constraint();
+ auto* tangent1 = new Sketcher::Constraint();
+ auto* tangent2 = new Sketcher::Constraint();
tangent1->Type = Sketcher::Tangent;
tangent1->First = GeoId1;
- tangent1->FirstPos = curve1PosId;
+ tangent1->FirstPos = PosId1;
tangent1->Second = filletId;
tangent2->Type = Sketcher::Tangent;
tangent2->First = GeoId2;
- tangent2->FirstPos = curve2PosId;
+ tangent2->FirstPos = PosId2;
tangent2->Second = filletId;
double dist1 = (refp1 - arc->getStartPoint(true)).Length();
@@ -2670,14 +2670,14 @@ int SketchObject::fillet(int GeoId1, int GeoId2, const Base::Vector3d& refPnt1,
if (dist1 < dist2) {
tangent1->SecondPos = PointPos::start;
tangent2->SecondPos = PointPos::end;
- movePoint(GeoId1, curve1PosId, arc->getStartPoint(true), false, true);
- movePoint(GeoId2, curve2PosId, arc->getEndPoint(true), false, true);
+ movePoint(GeoId1, PosId1, arc->getStartPoint(true), false, true);
+ movePoint(GeoId2, PosId2, arc->getEndPoint(true), false, true);
}
else {
tangent1->SecondPos = PointPos::end;
tangent2->SecondPos = PointPos::start;
- movePoint(GeoId1, curve1PosId, arc->getEndPoint(true), false, true);
- movePoint(GeoId2, curve2PosId, arc->getStartPoint(true), false, true);
+ movePoint(GeoId1, PosId1, arc->getEndPoint(true), false, true);
+ movePoint(GeoId2, PosId2, arc->getStartPoint(true), false, true);
}
addConstraint(tangent1);
@@ -2692,15 +2692,53 @@ int SketchObject::fillet(int GeoId1, int GeoId2, const Base::Vector3d& refPnt1,
#ifdef DEBUG
Base::Console().Log("\n\nEND OF FILLET DEBUG\n\n");
#endif
-
- // if we do not have a recompute after the geometry creation, the sketch must be solved to
- // update the DoF of the solver
- if (noRecomputes)
- solve();
-
- return 0;
}
- return -1;
+ else {
+ return -1;
+ }
+
+ if (chamfer) {
+ auto line = std::make_unique();
+ line->setPoints(p1, p2);
+ int lineGeoId = addGeometry(line.get());
+
+ auto coinc1 = std::make_unique();
+ auto coinc2 = std::make_unique();
+
+ coinc1->Type = Sketcher::Coincident;
+ coinc1->First = lineGeoId;
+ coinc1->FirstPos = PointPos::start;
+
+ coinc2->Type = Sketcher::Coincident;
+ coinc2->First = lineGeoId;
+ coinc2->FirstPos = PointPos::end;
+
+ if (trim) {
+ coinc1->Second = GeoId1;
+ coinc1->SecondPos = PosId1;
+ coinc2->Second = GeoId2;
+ coinc2->SecondPos = PosId2;
+ }
+ else {
+ coinc1->Second = filletId;
+ coinc1->SecondPos = PointPos::start;
+ coinc2->Second = filletId;
+ coinc2->SecondPos = PointPos::end;
+ }
+
+ addConstraint(std::move(coinc1));
+ addConstraint(std::move(coinc2));
+
+ setConstruction(filletId, true);
+ }
+
+ // if we do not have a recompute after the geometry creation, the sketch must be solved to
+ // update the DoF of the solver
+ if (noRecomputes) {
+ solve();
+ }
+
+ return 0;
}
int SketchObject::extend(int GeoId, double increment, PointPos endpoint)
diff --git a/src/Mod/Sketcher/App/SketchObject.h b/src/Mod/Sketcher/App/SketchObject.h
index d0f3b99ba1..5d748bdadb 100644
--- a/src/Mod/Sketcher/App/SketchObject.h
+++ b/src/Mod/Sketcher/App/SketchObject.h
@@ -323,8 +323,12 @@ public:
\param createCorner - keep geoId/pos as a Point and keep as many constraints as possible
\retval - 0 on success, -1 on failure
*/
- int
- fillet(int geoId, PointPos pos, double radius, bool trim = true, bool preserveCorner = false);
+ int fillet(int geoId,
+ PointPos pos,
+ double radius,
+ bool trim = true,
+ bool preserveCorner = false,
+ bool chamfer = false);
/*!
\brief More general form of fillet
\param geoId1, geoId2 - geoId for two lines (which don't necessarily have to coincide)
@@ -340,7 +344,8 @@ public:
const Base::Vector3d& refPnt2,
double radius,
bool trim = true,
- bool createCorner = false);
+ bool createCorner = false,
+ bool chamfer = false);
/// trim a curve
int trim(int geoId, const Base::Vector3d& point);
diff --git a/src/Mod/Sketcher/App/SketchObjectPyImp.cpp b/src/Mod/Sketcher/App/SketchObjectPyImp.cpp
index 631e90b8f8..54d2eac944 100644
--- a/src/Mod/Sketcher/App/SketchObjectPyImp.cpp
+++ b/src/Mod/Sketcher/App/SketchObjectPyImp.cpp
@@ -1196,11 +1196,12 @@ PyObject* SketchObjectPy::fillet(PyObject* args)
int geoId1, geoId2, posId1;
int trim = true;
PyObject* createCorner = Py_False;
+ PyObject* chamfer = Py_False;
double radius;
// Two Lines, radius
if (PyArg_ParseTuple(args,
- "iiO!O!d|iO!",
+ "iiO!O!d|iO!O!",
&geoId1,
&geoId2,
&(Base::VectorPy::Type),
@@ -1210,15 +1211,23 @@ PyObject* SketchObjectPy::fillet(PyObject* args)
&radius,
&trim,
&PyBool_Type,
- &createCorner)) {
+ &createCorner,
+ &PyBool_Type,
+ &chamfer)) {
// The i for &trim should probably have been a bool like &createCorner, but we'll leave it
// an int for backward compatibility (and because python will accept a bool there anyway)
Base::Vector3d v1 = static_cast(pcObj1)->value();
Base::Vector3d v2 = static_cast(pcObj2)->value();
- if (this->getSketchObjectPtr()
- ->fillet(geoId1, geoId2, v1, v2, radius, trim, Base::asBoolean(createCorner))) {
+ if (this->getSketchObjectPtr()->fillet(geoId1,
+ geoId2,
+ v1,
+ v2,
+ radius,
+ trim,
+ Base::asBoolean(createCorner),
+ Base::asBoolean(chamfer))) {
std::stringstream str;
str << "Not able to fillet curves with ids : (" << geoId1 << ", " << geoId2
<< ") and points (" << v1.x << ", " << v1.y << ", " << v1.z << ") & "
@@ -1232,18 +1241,21 @@ PyObject* SketchObjectPy::fillet(PyObject* args)
PyErr_Clear();
// Point, radius
if (PyArg_ParseTuple(args,
- "iid|iO!",
+ "iid|iO!O!",
&geoId1,
&posId1,
&radius,
&trim,
&PyBool_Type,
- &createCorner)) {
+ &createCorner,
+ &PyBool_Type,
+ &chamfer)) {
if (this->getSketchObjectPtr()->fillet(geoId1,
static_cast(posId1),
radius,
trim,
- Base::asBoolean(createCorner))) {
+ Base::asBoolean(createCorner),
+ Base::asBoolean(chamfer))) {
std::stringstream str;
str << "Not able to fillet point with ( geoId: " << geoId1 << ", PointPos: " << posId1
<< " )";
diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp
index 5d5fb442d6..2b66c0874d 100644
--- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp
+++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp
@@ -1431,8 +1431,9 @@ CmdSketcherCreateFillet::CmdSketcherCreateFillet()
void CmdSketcherCreateFillet::activated(int iMsg)
{
Q_UNUSED(iMsg);
- ActivateHandler(getActiveGuiDocument(),
- new DrawSketchHandlerFillet(DrawSketchHandlerFillet::SimpleFillet));
+ ActivateHandler(
+ getActiveGuiDocument(),
+ new DrawSketchHandlerFillet(ConstructionMethods::FilletConstructionMethod::Fillet));
}
bool CmdSketcherCreateFillet::isActive()
@@ -1442,149 +1443,62 @@ bool CmdSketcherCreateFillet::isActive()
// ======================================================================================
-DEF_STD_CMD_A(CmdSketcherCreatePointFillet)
+DEF_STD_CMD_A(CmdSketcherCreateChamfer)
-CmdSketcherCreatePointFillet::CmdSketcherCreatePointFillet()
- : Command("Sketcher_CreatePointFillet")
+CmdSketcherCreateChamfer::CmdSketcherCreateChamfer()
+ : Command("Sketcher_CreateChamfer")
{
sAppModule = "Sketcher";
sGroup = "Sketcher";
- sMenuText = QT_TR_NOOP("Create corner-preserving fillet");
- sToolTipText = QT_TR_NOOP("Fillet that preserves intersection point and most constraints");
- sWhatsThis = "Sketcher_CreatePointFillet";
+ sMenuText = QT_TR_NOOP("Create chamfer");
+ sToolTipText = QT_TR_NOOP("Create a chamfer between two lines or at a coincident point");
+ sWhatsThis = "Sketcher_CreateChamfer";
sStatusTip = sToolTipText;
- sPixmap = "Sketcher_CreatePointFillet";
- sAccel = "G, F, P";
+ sPixmap = "Sketcher_CreateChamfer";
+ sAccel = "G, F, C";
eType = ForEdit;
}
-void CmdSketcherCreatePointFillet::activated(int iMsg)
+void CmdSketcherCreateChamfer::activated(int iMsg)
{
Q_UNUSED(iMsg);
ActivateHandler(
getActiveGuiDocument(),
- new DrawSketchHandlerFillet(DrawSketchHandlerFillet::ConstraintPreservingFillet));
+ new DrawSketchHandlerFillet(ConstructionMethods::FilletConstructionMethod::Chamfer));
}
-bool CmdSketcherCreatePointFillet::isActive()
+bool CmdSketcherCreateChamfer::isActive()
{
return isCommandActive(getActiveGuiDocument());
}
-/// @brief Macro that declares a new sketcher command class 'CmdSketcherCompCreateFillets'
-DEF_STD_CMD_ACLU(CmdSketcherCompCreateFillets)
-/**
- * @brief ctor
- */
-CmdSketcherCompCreateFillets::CmdSketcherCompCreateFillets()
- : Command("Sketcher_CompCreateFillets")
+class CmdSketcherCompCreateFillets: public Gui::GroupCommand
{
- sAppModule = "Sketcher";
- sGroup = "Sketcher";
- sMenuText = QT_TR_NOOP("Create fillet");
- sToolTipText = QT_TR_NOOP("Create a fillet between two lines");
- sWhatsThis = "Sketcher_CompCreateFillets";
- sStatusTip = sToolTipText;
- eType = ForEdit;
-}
+public:
+ CmdSketcherCompCreateFillets()
+ : GroupCommand("Sketcher_CompCreateFillets")
+ {
+ sAppModule = "Sketcher";
+ sGroup = "Sketcher";
+ sMenuText = QT_TR_NOOP("Create fillet or chamfer");
+ sToolTipText = QT_TR_NOOP("Create a fillet or chamfer between two lines");
+ sWhatsThis = "Sketcher_CompCreateFillets";
+ sStatusTip = sToolTipText;
+ eType = ForEdit;
-/**
- * @brief Instantiates the fillet handler when the fillet command activated
- * @param int iMsg
- */
-void CmdSketcherCompCreateFillets::activated(int iMsg)
-{
- if (iMsg == 0) {
- ActivateHandler(getActiveGuiDocument(),
- new DrawSketchHandlerFillet(DrawSketchHandlerFillet::SimpleFillet));
- }
- else if (iMsg == 1) {
- ActivateHandler(
- getActiveGuiDocument(),
- new DrawSketchHandlerFillet(DrawSketchHandlerFillet::ConstraintPreservingFillet));
- }
- else {
- return;
+ setCheckable(false);
+
+ addCommand("Sketcher_CreateFillet");
+ addCommand("Sketcher_CreateChamfer");
}
- // Since the default icon is reset when enabling/disabling the command we have
- // to explicitly set the icon of the used command.
- Gui::ActionGroup* pcAction = qobject_cast(_pcAction);
- QList a = pcAction->actions();
-
- assert(iMsg < a.size());
- pcAction->setIcon(a[iMsg]->icon());
-}
-
-Gui::Action* CmdSketcherCompCreateFillets::createAction()
-{
- Gui::ActionGroup* pcAction = new Gui::ActionGroup(this, Gui::getMainWindow());
- pcAction->setDropDownMenu(true);
- applyCommandData(this->className(), pcAction);
-
- QAction* oldFillet = pcAction->addAction(QString());
- oldFillet->setIcon(Gui::BitmapFactory().iconFromTheme("Sketcher_CreateFillet"));
-
- QAction* pointFillet = pcAction->addAction(QString());
- pointFillet->setIcon(Gui::BitmapFactory().iconFromTheme("Sketcher_CreatePointFillet"));
-
- _pcAction = pcAction;
- languageChange();
-
- pcAction->setIcon(Gui::BitmapFactory().iconFromTheme("Sketcher_CreatePointFillet"));
- int defaultId = 1;
- pcAction->setProperty("defaultAction", QVariant(defaultId));
-
- return pcAction;
-}
-
-void CmdSketcherCompCreateFillets::updateAction(int mode)
-{
- Q_UNUSED(mode);
- Gui::ActionGroup* pcAction = qobject_cast(getAction());
- if (!pcAction) {
- return;
+ const char* className() const override
+ {
+ return "CmdSketcherCompCreateFillets";
}
+};
- QList a = pcAction->actions();
- int index = pcAction->property("defaultAction").toInt();
- a[0]->setIcon(Gui::BitmapFactory().iconFromTheme("Sketcher_CreateFillet"));
- a[1]->setIcon(Gui::BitmapFactory().iconFromTheme("Sketcher_CreatePointFillet"));
- getAction()->setIcon(a[index]->icon());
-}
-
-void CmdSketcherCompCreateFillets::languageChange()
-{
- Command::languageChange();
-
- if (!_pcAction) {
- return;
- }
- Gui::ActionGroup* pcAction = qobject_cast(_pcAction);
- QList a = pcAction->actions();
-
- QAction* oldFillet = a[0];
- oldFillet->setText(QApplication::translate("CmdSketcherCompCreateFillets", "Sketch fillet"));
- oldFillet->setToolTip(
- QApplication::translate("Sketcher_CreateFillet", "Creates a radius between two lines"));
- oldFillet->setStatusTip(
- QApplication::translate("Sketcher_CreateFillet", "Creates a radius between two lines"));
- QAction* pointFillet = a[1];
- pointFillet->setText(
- QApplication::translate("CmdSketcherCompCreateFillets", "Corner-preserving sketch fillet"));
- pointFillet->setToolTip(
- QApplication::translate("Sketcher_CreatePointFillet",
- "Fillet that preserves constraints and intersection point"));
- pointFillet->setStatusTip(
- QApplication::translate("Sketcher_CreatePointFillet",
- "Fillet that preserves constraints and intersection point"));
-}
-
-bool CmdSketcherCompCreateFillets::isActive()
-{
- return isCommandActive(getActiveGuiDocument());
-}
// ======================================================================================
@@ -2323,9 +2237,9 @@ void CreateSketcherCommandsCreateGeo()
rcCmdMgr.addCommand(new CmdSketcherCreateSlot());
rcCmdMgr.addCommand(new CmdSketcherCreateArcSlot());
rcCmdMgr.addCommand(new CmdSketcherCompSlot());
- rcCmdMgr.addCommand(new CmdSketcherCompCreateFillets());
rcCmdMgr.addCommand(new CmdSketcherCreateFillet());
- rcCmdMgr.addCommand(new CmdSketcherCreatePointFillet());
+ rcCmdMgr.addCommand(new CmdSketcherCreateChamfer());
+ rcCmdMgr.addCommand(new CmdSketcherCompCreateFillets());
// rcCmdMgr.addCommand(new CmdSketcherCreateText());
// rcCmdMgr.addCommand(new CmdSketcherCreateDraftLine());
rcCmdMgr.addCommand(new CmdSketcherTrimming());
diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerFillet.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerFillet.h
index b6c5aa1366..0fd4e12442 100644
--- a/src/Mod/Sketcher/Gui/DrawSketchHandlerFillet.h
+++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerFillet.h
@@ -35,6 +35,8 @@
#include "Utils.h"
#include "ViewProviderSketch.h"
+using namespace Sketcher;
+
namespace SketcherGui
{
@@ -86,80 +88,106 @@ public:
};
-class DrawSketchHandlerFillet: public DrawSketchHandler
-{
-public:
- enum FilletType
- {
- SimpleFillet,
- ConstraintPreservingFillet
- };
+class DrawSketchHandlerFillet;
- explicit DrawSketchHandlerFillet(FilletType filletType)
- : filletType(filletType)
- , Mode(STATUS_SEEK_First)
- , firstCurve(0)
+namespace ConstructionMethods
+{
+
+enum class FilletConstructionMethod
+{
+ Fillet,
+ Chamfer,
+ End // Must be the last one
+};
+
+}
+
+using DSHFilletController =
+ DrawSketchDefaultWidgetController, // NOLINT
+ /*WidgetParametersT =*/WidgetParameters<0, 0>, // NOLINT
+ /*WidgetCheckboxesT =*/WidgetCheckboxes<1, 1>, // NOLINT
+ /*WidgetComboboxesT =*/WidgetComboboxes<1, 1>, // NOLINT
+ ConstructionMethods::FilletConstructionMethod,
+ /*bool PFirstComboboxIsConstructionMethod =*/true>;
+
+using DSHFilletControllerBase = DSHFilletController::ControllerBase;
+
+using DrawSketchHandlerFilletBase = DrawSketchControllableHandler;
+
+class DrawSketchHandlerFillet: public DrawSketchHandlerFilletBase
+{
+ friend DSHFilletController;
+ friend DSHFilletControllerBase;
+
+public:
+ explicit DrawSketchHandlerFillet(ConstructionMethod constrMethod = ConstructionMethod::Fillet)
+ : DrawSketchHandlerFilletBase(constrMethod)
+ , preserveCorner(true)
+ , vtId(-1)
+ , geoId1(GeoEnum::GeoUndef)
+ , geoId2(GeoEnum::GeoUndef)
{}
~DrawSketchHandlerFillet() override
{
Gui::Selection().rmvSelectionGate();
}
- enum SelectMode
+private:
+ void updateDataAndDrawToPosition(Base::Vector2d onSketchPos) override
{
- STATUS_SEEK_First,
- STATUS_SEEK_Second
- };
-
- void mouseMove(Base::Vector2d onSketchPos) override
- {
- Q_UNUSED(onSketchPos);
+ switch (state()) {
+ case SelectMode::SeekFirst: {
+ vtId = getPreselectPoint();
+ geoId1 = getPreselectCurve();
+ firstPos = onSketchPos;
+ } break;
+ case SelectMode::SeekSecond: {
+ geoId2 = getPreselectCurve();
+ secondPos = onSketchPos;
+ } break;
+ default:
+ break;
+ }
}
- bool pressButton(Base::Vector2d onSketchPos) override
+ void executeCommands() override
{
- Q_UNUSED(onSketchPos);
- return true;
- }
+ SketchObject* obj = sketchgui->getSketchObject();
- bool releaseButton(Base::Vector2d onSketchPos) override
- {
bool construction = false;
- int VtId = getPreselectPoint();
- if (Mode == STATUS_SEEK_First && VtId != -1) {
+ bool isChamfer = constructionMethod() == ConstructionMethod::Chamfer;
+
+ if (vtId != -1) {
int GeoId;
- Sketcher::PointPos PosId = Sketcher::PointPos::none;
- sketchgui->getSketchObject()->getGeoVertexIndex(VtId, GeoId, PosId);
- const Part::Geometry* geom = sketchgui->getSketchObject()->getGeometry(GeoId);
- if (geom->is()
- && (PosId == Sketcher::PointPos::start || PosId == Sketcher::PointPos::end)) {
+ PointPos PosId = PointPos::none;
+ obj->getGeoVertexIndex(vtId, GeoId, PosId);
+ const Part::Geometry* geom = obj->getGeometry(GeoId);
+ if (isLineSegment(*geom) && (PosId == PointPos::start || PosId == PointPos::end)) {
// guess fillet radius
double radius = -1;
std::vector GeoIdList;
std::vector PosIdList;
- sketchgui->getSketchObject()->getDirectlyCoincidentPoints(GeoId,
- PosId,
- GeoIdList,
- PosIdList);
+ obj->getDirectlyCoincidentPoints(GeoId, PosId, GeoIdList, PosIdList);
if (GeoIdList.size() == 2 && GeoIdList[0] >= 0 && GeoIdList[1] >= 0) {
- const Part::Geometry* geom1 =
- sketchgui->getSketchObject()->getGeometry(GeoIdList[0]);
- const Part::Geometry* geom2 =
- sketchgui->getSketchObject()->getGeometry(GeoIdList[1]);
- construction = Sketcher::GeometryFacade::getConstruction(geom1)
- && Sketcher::GeometryFacade::getConstruction(geom2);
- if (geom1->is() && geom2->is()) {
- const Part::GeomLineSegment* lineSeg1 =
- static_cast(geom1);
- const Part::GeomLineSegment* lineSeg2 =
- static_cast(geom2);
- Base::Vector3d dir1 = lineSeg1->getEndPoint() - lineSeg1->getStartPoint();
- Base::Vector3d dir2 = lineSeg2->getEndPoint() - lineSeg2->getStartPoint();
- if (PosIdList[0] == Sketcher::PointPos::end) {
+ const Part::Geometry* geo1 = obj->getGeometry(GeoIdList[0]);
+ const Part::Geometry* geo2 = obj->getGeometry(GeoIdList[1]);
+
+ construction = GeometryFacade::getConstruction(geo1)
+ && GeometryFacade::getConstruction(geo2);
+
+ if (isLineSegment(*geo1) && isLineSegment(*geo2)) {
+ auto* line1 = static_cast(geo1);
+ auto* line2 = static_cast(geo2);
+ Base::Vector3d dir1 = line1->getEndPoint() - line1->getStartPoint();
+ Base::Vector3d dir2 = line2->getEndPoint() - line2->getStartPoint();
+ if (PosIdList[0] == PointPos::end) {
dir1 *= -1;
}
- if (PosIdList[1] == Sketcher::PointPos::end) {
+ if (PosIdList[1] == PointPos::end) {
dir2 *= -1;
}
double l1 = dir1.Length();
@@ -169,55 +197,197 @@ public:
}
}
if (radius < 0) {
- return false;
+ return;
}
- int currentgeoid = getHighestCurveIndex();
+ int filletGeoId = getHighestCurveIndex() + (isChamfer ? 2 : 1);
// create fillet at point
try {
- bool pointFillet = (filletType == 1);
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Create fillet"));
- Gui::cmdAppObjectArgs(sketchgui->getObject(),
- "fillet(%d,%d,%f,%s,%s)",
+ Gui::cmdAppObjectArgs(obj,
+ "fillet(%d,%d,%f,%s,%s,%s)",
GeoId,
static_cast(PosId),
radius,
"True",
- pointFillet ? "True" : "False");
+ preserveCorner ? "True" : "False",
+ isChamfer ? "True" : "False");
if (construction) {
- Gui::cmdAppObjectArgs(sketchgui->getObject(),
- "toggleConstruction(%d) ",
- currentgeoid + 1);
+ Gui::cmdAppObjectArgs(obj, "toggleConstruction(%d) ", filletGeoId);
}
Gui::Command::commitCommand();
}
catch (const Base::Exception& e) {
Gui::NotifyUserError(
- sketchgui->getObject(),
+ obj,
QT_TRANSLATE_NOOP("Notifications", "Failed to create fillet"),
e.what());
Gui::Command::abortCommand();
}
- tryAutoRecomputeIfNotSolve(
- static_cast(sketchgui->getObject()));
+ tryAutoRecomputeIfNotSolve(obj);
}
- return true;
}
- int GeoId = getPreselectCurve();
- if (GeoId > -1) {
- const Part::Geometry* geom = sketchgui->getSketchObject()->getGeometry(GeoId);
- if (geom->isDerivedFrom()) {
- if (Mode == STATUS_SEEK_First) {
- firstCurve = GeoId;
- firstPos = onSketchPos;
- Mode = STATUS_SEEK_Second;
- // add the line to the selection
+ else {
+ Base::Vector3d refPnt1(firstPos.x, firstPos.y, 0.f);
+ Base::Vector3d refPnt2(secondPos.x, secondPos.y, 0.f);
+
+ const Part::Geometry* geo1 = obj->getGeometry(geoId1);
+ const Part::Geometry* geo2 = obj->getGeometry(geoId2);
+
+ construction =
+ GeometryFacade::getConstruction(geo1) && GeometryFacade::getConstruction(geo2);
+
+ double radius = 0;
+
+ if (isLineSegment(*geo1) && isLineSegment(*geo2)) {
+ // guess fillet radius
+ auto* line1 = static_cast(geo1);
+ auto* line2 = static_cast(geo2);
+
+ radius = Part::suggestFilletRadius(line1, line2, refPnt1, refPnt2);
+ if (radius < 0) {
+ return;
+ }
+ }
+
+ int filletGeoId = getHighestCurveIndex() + (isChamfer ? 2 : 1);
+
+ // create fillet between lines
+ try {
+ Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Create fillet"));
+ Gui::cmdAppObjectArgs(
+ obj,
+ "fillet(%d,%d,App.Vector(%f,%f,0),App.Vector(%f,%f,0),%f,%s,%s,%s)",
+ geoId1,
+ geoId2,
+ firstPos.x,
+ firstPos.y,
+ secondPos.x,
+ secondPos.y,
+ radius,
+ "True",
+ preserveCorner ? "True" : "False",
+ isChamfer ? "True" : "False");
+ Gui::Command::commitCommand();
+ }
+ catch (const Base::CADKernelError& e) {
+ if (e.getTranslatable()) {
+ Gui::TranslatedUserError(sketchgui,
+ QObject::tr("CAD Kernel Error"),
+ QObject::tr(e.getMessage().c_str()));
+ }
+ Gui::Selection().clearSelection();
+ Gui::Command::abortCommand();
+ }
+ catch (const Base::ValueError& e) {
+ Gui::TranslatedUserError(sketchgui,
+ QObject::tr("Value Error"),
+ QObject::tr(e.getMessage().c_str()));
+ Gui::Selection().clearSelection();
+ Gui::Command::abortCommand();
+ }
+
+ tryAutoRecompute(obj);
+
+ if (construction) {
+ Gui::cmdAppObjectArgs(obj, "toggleConstruction(%d) ", filletGeoId);
+ }
+
+
+ Gui::Selection().clearSelection();
+ }
+ }
+
+ std::string getToolName() const override
+ {
+ return "DSH_Fillet";
+ }
+
+ QString getCrosshairCursorSVGName() const override
+ {
+ Gui::Selection().rmvSelectionGate();
+ Gui::Selection().addSelectionGate(new FilletSelection(sketchgui->getObject()));
+
+ if (constructionMethod() == DrawSketchHandlerFillet::ConstructionMethod::Fillet) {
+ if (preserveCorner) {
+ return QString::fromLatin1("Sketcher_Pointer_Create_PointFillet");
+ }
+ else {
+ return QString::fromLatin1("Sketcher_Pointer_Create_Fillet");
+ }
+ }
+ else {
+ if (preserveCorner) {
+ return QString::fromLatin1("Sketcher_Pointer_Create_PointChamfer");
+ }
+ else {
+ return QString::fromLatin1("Sketcher_Pointer_Create_Chamfer");
+ }
+ }
+ }
+
+ std::unique_ptr createWidget() const override
+ {
+ return std::make_unique();
+ }
+
+ bool isWidgetVisible() const override
+ {
+ return true;
+ };
+
+ QPixmap getToolIcon() const override
+ {
+ return Gui::BitmapFactory().pixmap("Sketcher_CreateFillet");
+ }
+
+ QString getToolWidgetText() const override
+ {
+ return QString(QObject::tr("Fillet/Chamfer parameters"));
+ }
+
+ bool canGoToNextMode() override
+ {
+ if (state() == SelectMode::SeekFirst) {
+ if (vtId != -1) {
+ return true;
+ }
+ if (geoId1 >= 0) {
+ const Part::Geometry* geo = sketchgui->getSketchObject()->getGeometry(geoId1);
+ if (geo->isDerivedFrom()) {
+ return true;
+ }
+ }
+ }
+
+ if (state() == SelectMode::SeekSecond) {
+ if (geoId2 >= 0) {
+ const Part::Geometry* geo = sketchgui->getSketchObject()->getGeometry(geoId2);
+ if (geo->isDerivedFrom()) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ void onButtonPressed(Base::Vector2d onSketchPos) override
+ {
+ this->updateDataAndDrawToPosition(onSketchPos);
+ if (canGoToNextMode()) {
+ if (state() == SelectMode::SeekFirst) {
+ if (vtId != -1) {
+ setState(SelectMode::End);
+ }
+ else {
+ // add the edge to the selection
std::stringstream ss;
- ss << "Edge" << firstCurve + 1;
+ ss << "Edge" << geoId1 + 1;
Gui::Selection().addSelection(
sketchgui->getSketchObject()->getDocument()->getName(),
sketchgui->getSketchObject()->getNameInDocument(),
@@ -225,128 +395,66 @@ public:
onSketchPos.x,
onSketchPos.y,
0.f);
- }
- else if (Mode == STATUS_SEEK_Second) {
- int secondCurve = GeoId;
- Base::Vector2d secondPos = onSketchPos;
-
- Base::Vector3d refPnt1(firstPos.x, firstPos.y, 0.f);
- Base::Vector3d refPnt2(secondPos.x, secondPos.y, 0.f);
-
- const Part::Geometry* geom1 =
- sketchgui->getSketchObject()->getGeometry(firstCurve);
-
- double radius = 0;
-
- if (geom->is() && geom1->is()) {
- // guess fillet radius
- const Part::GeomLineSegment* lineSeg1 =
- static_cast(
- sketchgui->getSketchObject()->getGeometry(firstCurve));
- const Part::GeomLineSegment* lineSeg2 =
- static_cast(
- sketchgui->getSketchObject()->getGeometry(secondCurve));
-
- radius = Part::suggestFilletRadius(lineSeg1, lineSeg2, refPnt1, refPnt2);
- if (radius < 0) {
- return false;
- }
-
- construction = Sketcher::GeometryFacade::getConstruction(lineSeg1)
- && Sketcher::GeometryFacade::getConstruction(lineSeg2);
- }
- else { // other supported curves
- const Part::Geometry* geo1 = static_cast(
- sketchgui->getSketchObject()->getGeometry(firstCurve));
- const Part::Geometry* geo2 = static_cast(
- sketchgui->getSketchObject()->getGeometry(secondCurve));
-
- construction = Sketcher::GeometryFacade::getConstruction(geo1)
- && Sketcher::GeometryFacade::getConstruction(geo2);
- }
-
-
- int currentgeoid = getHighestCurveIndex();
-
- // create fillet between lines
- try {
- bool pointFillet = (filletType == 1);
- Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Create fillet"));
- Gui::cmdAppObjectArgs(
- sketchgui->getObject(),
- "fillet(%d,%d,App.Vector(%f,%f,0),App.Vector(%f,%f,0),%f,%s,%s)",
- firstCurve,
- secondCurve,
- firstPos.x,
- firstPos.y,
- secondPos.x,
- secondPos.y,
- radius,
- "True",
- pointFillet ? "True" : "False");
- Gui::Command::commitCommand();
- }
- catch (const Base::CADKernelError& e) {
- if (e.getTranslatable()) {
- Gui::TranslatedUserError(sketchgui,
- QObject::tr("CAD Kernel Error"),
- QObject::tr(e.getMessage().c_str()));
- }
- Gui::Selection().clearSelection();
- Gui::Command::abortCommand();
- Mode = STATUS_SEEK_First;
- }
- catch (const Base::ValueError& e) {
- Gui::TranslatedUserError(sketchgui,
- QObject::tr("Value Error"),
- QObject::tr(e.getMessage().c_str()));
- Gui::Selection().clearSelection();
- Gui::Command::abortCommand();
- Mode = STATUS_SEEK_First;
- }
-
- tryAutoRecompute(static_cast(sketchgui->getObject()));
-
- if (construction) {
- Gui::cmdAppObjectArgs(sketchgui->getObject(),
- "toggleConstruction(%d) ",
- currentgeoid + 1);
- }
-
-
- Gui::Selection().clearSelection();
- Mode = STATUS_SEEK_First;
+ moveToNextMode();
}
}
+ else {
+ moveToNextMode();
+ }
}
-
- if (VtId < 0 && GeoId < 0) { // exit the fillet tool if the user clicked on empty space
- sketchgui
- ->purgeHandler(); // no code after this line, Handler get deleted in ViewProvider
- }
-
- return true;
}
+
private:
- QString getCrosshairCursorSVGName() const override
- {
- Gui::Selection().rmvSelectionGate();
- Gui::Selection().addSelectionGate(new FilletSelection(sketchgui->getObject()));
- if (filletType == SimpleFillet) {
- return QString::fromLatin1("Sketcher_Pointer_Create_Fillet");
- }
- else {
- return QString::fromLatin1("Sketcher_Pointer_Create_PointFillet");
- }
+ bool preserveCorner;
+ int vtId, geoId1, geoId2;
+ Base::Vector2d firstPos, secondPos;
+};
+
+template<>
+void DSHFilletController::configureToolWidget()
+{
+ if (!init) { // Code to be executed only upon initialisation
+ QStringList names = {QStringLiteral("Fillet"), QStringLiteral("Chamfer")};
+ toolWidget->setComboboxElements(WCombobox::FirstCombo, names);
+
+ toolWidget->setComboboxItemIcon(
+ WCombobox::FirstCombo,
+ 0,
+ Gui::BitmapFactory().iconFromTheme("Sketcher_CreateFillet"));
+ toolWidget->setComboboxItemIcon(
+ WCombobox::FirstCombo,
+ 1,
+ Gui::BitmapFactory().iconFromTheme("Sketcher_CreateChamfer"));
+
+ toolWidget->setCheckboxLabel(
+ WCheckbox::FirstBox,
+ QApplication::translate("TaskSketcherTool_c1_fillet", "Preserve corner (U)"));
+ toolWidget->setCheckboxToolTip(
+ WCheckbox::FirstBox,
+ QApplication::translate("TaskSketcherTool_c1_fillet",
+ "Preserves intersection point and most constraints"));
+
+ toolWidget->setCheckboxIcon(
+ WCheckbox::FirstBox,
+ Gui::BitmapFactory().iconFromTheme("Sketcher_CreatePointFillet"));
+ }
+ syncCheckboxToHandler(WCheckbox::FirstBox, handler->preserveCorner);
+}
+
+template<>
+void DSHFilletController::adaptDrawingToCheckboxChange(int checkboxindex, bool value)
+{
+ Q_UNUSED(checkboxindex);
+
+ switch (checkboxindex) {
+ case WCheckbox::FirstBox:
+ handler->preserveCorner = value;
+ break;
}
-protected:
- int filletType;
- SelectMode Mode;
- int firstCurve;
- Base::Vector2d firstPos;
-};
+ handler->updateCursor();
+}
} // namespace SketcherGui
diff --git a/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc b/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc
index 936b246e64..6572d92280 100644
--- a/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc
+++ b/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc
@@ -139,6 +139,7 @@
icons/geometry/Sketcher_CreateBSplineByInterpolation_Constr.svg
icons/geometry/Sketcher_Create_Periodic_BSplineByInterpolation.svg
icons/geometry/Sketcher_Create_Periodic_BSplineByInterpolation_Constr.svg
+ icons/geometry/Sketcher_CreateChamfer.svg
icons/geometry/Sketcher_CreateCircle.svg
icons/geometry/Sketcher_CreateCircle_Constr.svg
icons/geometry/Sketcher_CreateEllipse_3points.svg
@@ -229,6 +230,7 @@
icons/pointers/Sketcher_Pointer_Create_BSpline.svg
icons/pointers/Sketcher_Pointer_Create_BSplineByInterpolation.svg
icons/pointers/Sketcher_Pointer_Create_Circle.svg
+ icons/pointers/Sketcher_Pointer_Create_Chamfer.svg
icons/pointers/Sketcher_Pointer_Create_EllipseByCenter.svg
icons/pointers/Sketcher_Pointer_Create_Ellipse_3points.svg
icons/pointers/Sketcher_Pointer_Create_Fillet.svg
@@ -238,6 +240,7 @@
icons/pointers/Sketcher_Pointer_Create_Periodic_BSpline.svg
icons/pointers/Sketcher_Pointer_Create_Periodic_BSplineByInterpolation.svg
icons/pointers/Sketcher_Pointer_Create_Point.svg
+ icons/pointers/Sketcher_Pointer_Create_PointChamfer.svg
icons/pointers/Sketcher_Pointer_Create_PointFillet.svg
icons/pointers/Sketcher_Pointer_Create_Translate.svg
icons/pointers/Sketcher_Pointer_Create_Offset.svg
diff --git a/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateChamfer.svg b/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateChamfer.svg
new file mode 100644
index 0000000000..d2032be3c9
--- /dev/null
+++ b/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateChamfer.svg
@@ -0,0 +1,537 @@
+
+
diff --git a/src/Mod/Sketcher/Gui/Resources/icons/pointers/Sketcher_Pointer_Create_Chamfer.svg b/src/Mod/Sketcher/Gui/Resources/icons/pointers/Sketcher_Pointer_Create_Chamfer.svg
new file mode 100644
index 0000000000..6ed3ce1ce3
--- /dev/null
+++ b/src/Mod/Sketcher/Gui/Resources/icons/pointers/Sketcher_Pointer_Create_Chamfer.svg
@@ -0,0 +1,159 @@
+
+
diff --git a/src/Mod/Sketcher/Gui/Resources/icons/pointers/Sketcher_Pointer_Create_PointChamfer.svg b/src/Mod/Sketcher/Gui/Resources/icons/pointers/Sketcher_Pointer_Create_PointChamfer.svg
new file mode 100644
index 0000000000..6f1587fb76
--- /dev/null
+++ b/src/Mod/Sketcher/Gui/Resources/icons/pointers/Sketcher_Pointer_Create_PointChamfer.svg
@@ -0,0 +1,145 @@
+
+
diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp
index 09e656f69f..8bcacb0dcf 100644
--- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp
+++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp
@@ -4161,7 +4161,8 @@ void ViewProviderSketch::generateContextMenu()
<< "Separator"
<< "Sketcher_ToggleConstruction"
<< "Separator"
- << "Sketcher_CreatePointFillet"
+ << "Sketcher_CreateFillet"
+ << "Sketcher_CreateChamfer"
<< "Sketcher_Trimming"
<< "Sketcher_Extend"
<< "Separator"
diff --git a/src/Mod/Sketcher/Gui/Workbench.cpp b/src/Mod/Sketcher/Gui/Workbench.cpp
index e507189983..7ef3c44373 100644
--- a/src/Mod/Sketcher/Gui/Workbench.cpp
+++ b/src/Mod/Sketcher/Gui/Workbench.cpp
@@ -375,8 +375,8 @@ void SketcherAddWorkspaceFillets(T& geom);
template<>
inline void SketcherAddWorkspaceFillets(Gui::MenuItem& geom)
{
- geom << "Sketcher_CreatePointFillet"
- << "Sketcher_CreateFillet";
+ geom << "Sketcher_CreateFillet"
+ << "Sketcher_CreateChamfer";
}
template<>