Sketcher: Intersection externals

This commit is contained in:
PaddleStroke
2024-11-08 10:57:18 +01:00
committed by WandererFan
parent f3c79302c4
commit 0e5e071d72
12 changed files with 1309 additions and 168 deletions

View File

@@ -141,6 +141,11 @@ SketchObject::SketchObject()
"Sketch",
(App::PropertyType)(App::Prop_None | App::Prop_ReadOnly),
"Sketch external geometry");
ADD_PROPERTY_TYPE(ExternalTypes,
({}),
"Sketch",
(App::PropertyType)(App::Prop_None | App::Prop_Hidden),
"Sketch external geometry type: 0 = projection, 1 = intersection, 2 = both.");
ADD_PROPERTY_TYPE(FullyConstrained,
(false),
"Sketch",
@@ -7721,8 +7726,12 @@ int SketchObject::addExternal(App::DocumentObject *Obj, const char* SubName, boo
}
// get the actual lists of the externals
std::vector<long> Types = ExternalTypes.getValues();
std::vector<DocumentObject*> Objects = ExternalGeometry.getValues();
std::vector<std::string> SubElements = ExternalGeometry.getSubValues();
if (Types.size() != Objects.size()) {
Types.resize(Objects.size(), 0);
}
const std::vector<DocumentObject*> originalObjects = Objects;
const std::vector<std::string> originalSubElements = SubElements;
@@ -7734,21 +7743,35 @@ int SketchObject::addExternal(App::DocumentObject *Obj, const char* SubName, boo
return -1;
}
bool add = true;
for (size_t i = 0; i < Objects.size(); ++i) {
if (Objects[i] == Obj && std::string(SubName) == SubElements[i]) {
Base::Console().Error("Link to %s already exists in this sketch.\n", SubName);
return -1;
if (Types[i] == (int)ExtType::Both
|| (Types[i] == (int)ExtType::Projection && !intersection)
|| (Types[i] == (int)ExtType::Intersection && intersection)) {
Base::Console().Error("Link to %s already exists in this sketch.\n", SubName);
return -1;
}
// Case where projections are already there when adding intersections.
add = false;
Types[i] = (int)ExtType::Both;
}
}
if (add) {
// add the new ones
Objects.push_back(Obj);
SubElements.emplace_back(SubName);
Types.push_back((int)(intersection ? ExtType::Intersection : ExtType::Projection));
if (intersection) {}
// add the new ones
Objects.push_back(Obj);
SubElements.emplace_back(SubName);
// set the Link list.
ExternalGeometry.setValues(Objects, SubElements);
}
ExternalTypes.setValues(Types);
// set the Link list.
ExternalGeometry.setValues(Objects, SubElements);
try {
rebuildExternalGeometry(defining, intersection);
ExternalToAdd ext{ Obj, std::string(SubName), defining, intersection };
rebuildExternalGeometry(ext);
}
catch (const Base::Exception& e) {
Base::Console().Error("%s\n", e.what());
@@ -8731,6 +8754,8 @@ void processEdge(const TopoDS_Edge& edge,
}
else if (curve.GetType() == GeomAbs_Ellipse) {
gp_Pnt P1 = curve.Value(curve.FirstParameter());
gp_Pnt P2 = curve.Value(curve.LastParameter());
gp_Elips elipsOrig = curve.Ellipse();
gp_Elips elipsDest;
gp_Pnt origCenter = elipsOrig.Location();
@@ -8792,11 +8817,22 @@ void processEdge(const TopoDS_Edge& edge,
// projection is a circle
if ((RDest - rDest) < (double)Precision::Confusion()) {
Handle(Geom_Circle) curve = new Geom_Circle(destCurveAx2, 0.5 * (rDest + RDest));
auto* circle = new Part::GeomCircle();
circle->setHandle(curve);
GeometryFacade::setConstruction(circle, true);
geos.emplace_back(circle);
Handle(Geom_Circle) curve2 = new Geom_Circle(destCurveAx2, 0.5 * (rDest + RDest));
if (P1.SquareDistance(P2) < Precision::Confusion()) {
auto* circle = new Part::GeomCircle();
circle->setHandle(curve2);
GeometryFacade::setConstruction(circle, true);
geos.emplace_back(circle);
}
else {
auto* arc = new Part::GeomArcOfCircle();
Handle(Geom_TrimmedCurve) tCurve = new Geom_TrimmedCurve(curve2,
curve.FirstParameter(),
curve.LastParameter());
arc->setHandle(tCurve);
GeometryFacade::setConstruction(arc, true);
geos.emplace_back(arc);
}
}
else {
if (sketchPlane.Position().Direction().IsNormal(
@@ -8818,11 +8854,23 @@ void processEdge(const TopoDS_Edge& edge,
elipsDest.SetMinorRadius(destAxisMinor.Magnitude());
Handle(Geom_Ellipse) curve = new Geom_Ellipse(elipsDest);
auto* ellipse = new Part::GeomEllipse();
ellipse->setHandle(curve);
GeometryFacade::setConstruction(ellipse, true);
geos.emplace_back(ellipse);
if (P1.SquareDistance(P2) < Precision::Confusion()) {
Handle(Geom_Ellipse) curve = new Geom_Ellipse(elipsDest);
auto* ellipse = new Part::GeomEllipse();
ellipse->setHandle(curve);
GeometryFacade::setConstruction(ellipse, true);
geos.emplace_back(ellipse);
}
else {
auto* aoe = new Part::GeomArcOfEllipse();
Handle(Geom_Curve) curve2 = new Geom_Ellipse(elipsDest);
Handle(Geom_TrimmedCurve) tCurve = new Geom_TrimmedCurve(curve2,
curve.FirstParameter(),
curve.LastParameter());
aoe->setHandle(tCurve);
GeometryFacade::setConstruction(aoe, true);
geos.emplace_back(aoe);
}
}
}
}
@@ -8929,15 +8977,19 @@ std::vector<TopoDS_Shape> projectShape(const TopoDS_Shape& inShape, const gp_Ax3
}
}
void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection)
void SketchObject::rebuildExternalGeometry(std::optional<ExternalToAdd> extToAdd)
{
Base::StateLocker lock(managedoperation, true); // no need to check input data validity as this is an sketchobject managed operation.
// get the actual lists of the externals
auto Types = ExternalTypes.getValues();
auto Objects = ExternalGeometry.getValues();
auto SubElements = ExternalGeometry.getSubValues();
assert(externalGeoRef.size() == Objects.size());
auto keys = externalGeoRef;
if (Types.size() != Objects.size()) {
Types.resize(Objects.size(), 0);
}
// re-check for any missing geometry element. The code here has a side
// effect that the linked external geometry will continue to work even if
@@ -9007,169 +9059,211 @@ void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection)
const std::string &SubElement=SubElements[i];
const std::string &key = keys[i];
bool beingCreated = false;
if (extToAdd) {
beingCreated = extToAdd->obj == Obj && extToAdd->subname == SubElement;
}
bool projection = Types[i] == (int)ExtType::Projection || Types[i] == (int)ExtType::Both;
bool intersection = Types[i] == (int)ExtType::Intersection || Types[i] == (int)ExtType::Both;
// Skip frozen geometries
bool frozen = false;
bool sync = false;
bool intersection = addIntersection && (i+1 == (int)Objects.size());
for(auto id : externalGeoRefMap[key]) {
auto it = externalGeoMap.find(id);
if(it != externalGeoMap.end()) {
auto egf = ExternalGeometryFacade::getFacade(ExternalGeo[it->second]);
if(egf->testFlag(ExternalGeometryExtension::Frozen))
if(egf->testFlag(ExternalGeometryExtension::Frozen)) {
frozen = true;
if(egf->testFlag(ExternalGeometryExtension::Sync))
}
if (egf->testFlag(ExternalGeometryExtension::Sync)) {
sync = true;
}
}
}
if(frozen && !sync) {
refSet.insert(std::move(key));
continue;
}
if(!Obj || !Obj->getNameInDocument())
if (!Obj || !Obj->getNameInDocument()) {
continue;
}
std::vector<std::unique_ptr<Part::Geometry> > geos;
try {
TopoDS_Shape refSubShape;
auto importVertex = [&](const TopoDS_Shape& refSubShape) {
gp_Pnt P = BRep_Tool::Pnt(TopoDS::Vertex(refSubShape));
GeomAPI_ProjectPointOnSurf proj(P, gPlane);
P = proj.NearestPoint();
Base::Vector3d p(P.X(), P.Y(), P.Z());
invPlm.multVec(p, p);
if (Obj->isDerivedFrom<Part::Datum>()) {
auto* datum = static_cast<const Part::Datum*>(Obj);
refSubShape = datum->getShape();
}
else if (Obj->isDerivedFrom<Part::Feature>()) {
try {
Part::GeomPoint* point = new Part::GeomPoint(p);
GeometryFacade::setConstruction(point, true);
geos.emplace_back(point);
};
try {
TopoDS_Shape refSubShape;
if (Obj->isDerivedFrom<Part::Datum>()) {
auto* datum = static_cast<const Part::Datum*>(Obj);
refSubShape = datum->getShape();
}
else if (Obj->isDerivedFrom<Part::Feature>()) {
auto* refObj = static_cast<const Part::Feature*>(Obj);
const Part::TopoShape& refShape = refObj->Shape.getShape();
refSubShape = refShape.getSubShape(SubElement.c_str());
}
catch (Standard_Failure& e) {
throw Base::CADKernelError(e.GetMessageString());
else if (Obj->isDerivedFrom<App::Plane>()) {
auto* pl = static_cast<const App::Plane*>(Obj);
Base::Placement plm = pl->Placement.getValue();
Base::Vector3d base = plm.getPosition();
Base::Rotation rot = plm.getRotation();
Base::Vector3d normal(0, 0, 1);
rot.multVec(normal, normal);
gp_Pln plane(gp_Pnt(base.x, base.y, base.z), gp_Dir(normal.x, normal.y, normal.z));
BRepBuilderAPI_MakeFace fBuilder(plane);
if (!fBuilder.IsDone())
throw Base::RuntimeError(
"Sketcher: addExternal(): Failed to build face from App::Plane");
TopoDS_Face f = TopoDS::Face(fBuilder.Shape());
refSubShape = f;
}
else {
throw Base::TypeError(
"Datum feature type is not yet supported as external geometry for a sketch");
}
}
else if (Obj->isDerivedFrom<App::Plane>()) {
auto* pl = static_cast<const App::Plane*>(Obj);
Base::Placement plm = pl->Placement.getValue();
Base::Vector3d base = plm.getPosition();
Base::Rotation rot = plm.getRotation();
Base::Vector3d normal(0, 0, 1);
rot.multVec(normal, normal);
gp_Pln plane(gp_Pnt(base.x, base.y, base.z), gp_Dir(normal.x, normal.y, normal.z));
BRepBuilderAPI_MakeFace fBuilder(plane);
if (!fBuilder.IsDone())
throw Base::RuntimeError(
"Sketcher: addExternal(): Failed to build face from App::Plane");
TopoDS_Face f = TopoDS::Face(fBuilder.Shape());
refSubShape = f;
}
else {
throw Base::TypeError(
"Datum feature type is not yet supported as external geometry for a sketch");
}
if (projection) {
switch (refSubShape.ShapeType()) {
case TopAbs_FACE: {
const TopoDS_Face& face = TopoDS::Face(refSubShape);
BRepAdaptor_Surface surface(face);
if (surface.GetType() == GeomAbs_Plane) {
// Check that the plane is perpendicular to the sketch plane
Geom_Plane plane = surface.Plane();
gp_Dir dnormal = plane.Axis().Direction();
gp_Dir snormal = sketchPlane.Axis().Direction();
switch (refSubShape.ShapeType()) {
case TopAbs_FACE: {
const TopoDS_Face& face = TopoDS::Face(refSubShape);
BRepAdaptor_Surface surface(face);
if (surface.GetType() == GeomAbs_Plane) {
// Check that the plane is perpendicular to the sketch plane
Geom_Plane plane = surface.Plane();
gp_Dir dnormal = plane.Axis().Direction();
gp_Dir snormal = sketchPlane.Axis().Direction();
// Extract all edges from the face
TopExp_Explorer edgeExp;
for (edgeExp.Init(face, TopAbs_EDGE); edgeExp.More(); edgeExp.Next()) {
TopoDS_Edge edge = TopoDS::Edge(edgeExp.Current());
// Process each edge
processEdge(edge, geos, gPlane, invPlm, mov, sketchPlane, invRot, sketchAx3, aProjFace);
}
// Extract all edges from the face
TopExp_Explorer edgeExp;
for (edgeExp.Init(face, TopAbs_EDGE); edgeExp.More(); edgeExp.Next()) {
TopoDS_Edge edge = TopoDS::Edge(edgeExp.Current());
// Process each edge
processEdge(edge, geos, gPlane, invPlm, mov, sketchPlane, invRot, sketchAx3, aProjFace);
}
if (fabs(dnormal.Angle(snormal) - M_PI_2) < Precision::Confusion()) {
// The face is normal to the sketch plane
// We don't want to keep the projection of all the edges of the face.
// We need a single line that goes from min to max of all the projections.
bool initialized = false;
Base::Vector3d start, end;
// Lambda to determine if a point should replace start or end
auto updateExtremes = [&](const Base::Vector3d& point) {
if ((point - start).Length() < (point - end).Length()) {
// `point` is closer to `start` than `end`, check if it's further out than `start`
if ((point - end).Length() > (end - start).Length()) {
start = point;
if (fabs(dnormal.Angle(snormal) - M_PI_2) < Precision::Confusion()) {
// The face is normal to the sketch plane
// We don't want to keep the projection of all the edges of the face.
// We need a single line that goes from min to max of all the projections.
bool initialized = false;
Base::Vector3d start, end;
// Lambda to determine if a point should replace start or end
auto updateExtremes = [&](const Base::Vector3d& point) {
if ((point - start).Length() < (point - end).Length()) {
// `point` is closer to `start` than `end`, check if it's further out than `start`
if ((point - end).Length() > (end - start).Length()) {
start = point;
}
}
else {
// `point` is closer to `end`, check if it's further out than `end`
if ((point - start).Length() > (end - start).Length()) {
end = point;
}
}
};
for (auto& geo : geos) {
auto* line = dynamic_cast<Part::GeomLineSegment*>(geo.get());
if (!line) {
// The face being normal to the sketch, we should have
// only lines. This is just a fail-safe in case there's a
// straight bspline or something like this.
continue;
}
if (!initialized) {
start = line->getStartPoint();
end = line->getEndPoint();
initialized = true;
continue;
}
updateExtremes(line->getStartPoint());
updateExtremes(line->getEndPoint());
}
if (initialized) {
auto* unifiedLine = new Part::GeomLineSegment();
unifiedLine->setPoints(start, end);
geos.clear(); // Clear other segments
geos.emplace_back(unifiedLine);
}
else {
// `point` is closer to `end`, check if it's further out than `end`
if ((point - start).Length() > (end - start).Length()) {
end = point;
// In case we have not initialized, perhaps the projections were
// only straight bsplines.
// Then we use the old method that will give a line with 20000 length:
// Get vector that is normal to both sketch plane normal and plane normal.
// This is the line's direction
gp_Dir lnormal = dnormal.Crossed(snormal);
BRepBuilderAPI_MakeEdge builder(gp_Lin(plane.Location(), lnormal));
builder.Build();
if (builder.IsDone()) {
const TopoDS_Edge& edge = TopoDS::Edge(builder.Shape());
BRepAdaptor_Curve curve(edge);
if (curve.GetType() == GeomAbs_Line) {
geos.emplace_back(projectLine(curve, gPlane, invPlm));
}
}
}
};
for (auto& geo : geos) {
auto* line = dynamic_cast<Part::GeomLineSegment*>(geo.get());
if (!line) {
continue; // we should have only lines
}
if (!initialized) {
start = line->getStartPoint();
end = line->getEndPoint();
initialized = true;
continue;
}
updateExtremes(line->getStartPoint());
updateExtremes(line->getEndPoint());
}
auto* unifiedLine = new Part::GeomLineSegment();
unifiedLine->setPoints(start, end);
geos.clear(); // Clear other segments
geos.emplace_back(unifiedLine);
}
}
else {
std::vector<TopoDS_Shape> res = projectShape(face, sketchAx3);
for (auto& resShape : res) {
TopExp_Explorer explorer(resShape, TopAbs_EDGE);
while (explorer.More()) {
TopoDS_Edge projEdge = TopoDS::Edge(explorer.Current());
processEdge2(projEdge, geos);
explorer.Next();
}
}
else {
std::vector<TopoDS_Shape> res = projectShape(face, sketchAx3);
for (auto& resShape : res) {
TopExp_Explorer explorer(resShape, TopAbs_EDGE);
while (explorer.More()) {
TopoDS_Edge projEdge = TopoDS::Edge(explorer.Current());
processEdge2(projEdge, geos);
explorer.Next();
}
}
}
} break;
case TopAbs_EDGE: {
const TopoDS_Edge& edge = TopoDS::Edge(refSubShape);
processEdge(edge, geos, gPlane, invPlm, mov, sketchPlane, invRot, sketchAx3, aProjFace);
} break;
case TopAbs_VERTEX: {
importVertex(refSubShape);
} break;
default:
throw Base::TypeError("Unknown type of geometry");
break;
}
if (beingCreated && !extToAdd->intersection) {
// We are adding the projections, so we need to initialize those
for (auto& geo : geos) {
auto egf = ExternalGeometryFacade::getFacade(geo.get());
egf->setFlag(ExternalGeometryExtension::Defining, extToAdd->defining);
}
}
} break;
case TopAbs_EDGE: {
const TopoDS_Edge& edge = TopoDS::Edge(refSubShape);
processEdge(edge, geos, gPlane, invPlm, mov, sketchPlane, invRot, sketchAx3, aProjFace);
} break;
case TopAbs_VERTEX: {
gp_Pnt P = BRep_Tool::Pnt(TopoDS::Vertex(refSubShape));
GeomAPI_ProjectPointOnSurf proj(P, gPlane);
P = proj.NearestPoint();
Base::Vector3d p(P.X(), P.Y(), P.Z());
invPlm.multVec(p, p);
auto* point = new Part::GeomPoint(p);
GeometryFacade::setConstruction(point, true);
geos.emplace_back(point);
} break;
default:
throw Base::TypeError("Unknown type of geometry");
break;
}
int projSize = geos.size();
if (intersection && (refSubShape.ShapeType() == TopAbs_EDGE
|| refSubShape.ShapeType() == TopAbs_FACE))
{
if (intersection) {
FCBRepAlgoAPI_Section maker(refSubShape, sketchPlane);
maker.Approximation(Standard_True);
if (!maker.IsDone())
FC_THROWM(Base::CADKernelError,"Failed to get intersection");
FC_THROWM(Base::CADKernelError, "Failed to get intersection");
Part::TopoShape intersectionShape(maker.Shape());
auto edges = intersectionShape.getSubTopoShapes(TopAbs_EDGE);
for (const auto& s : edges) {
TopoDS_Edge edge = TopoDS::Edge(s.getShape());
processEdge(edge, geos, gPlane, invPlm, mov, sketchPlane, invRot, sketchAx3, aProjFace);
}
// Section of some face (e.g. sphere) produce more than one arcs
// from the same circle. So we try to fit the arcs with a single
// circle/arc.
@@ -9190,6 +9284,17 @@ void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection)
}
}
}
for (const auto& s : intersectionShape.getSubShapes(TopAbs_VERTEX, TopAbs_EDGE)) {
importVertex(s);
}
if (beingCreated && extToAdd->intersection) {
// We are adding the projections, so we need to initialize those
for (size_t i = projSize; i < geos.size(); ++i) {
auto egf = ExternalGeometryFacade::getFacade(geos[i].get());
egf->setFlag(ExternalGeometryExtension::Defining, extToAdd->defining);
}
}
}
} catch (Base::Exception &e) {
@@ -9209,25 +9314,18 @@ void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection)
<< getFullName() << ": " << key << std::endl << "Unknown exception");
continue;
}
if(geos.empty())
if (geos.empty()) {
continue;
}
if(!refSet.emplace(key).second) {
FC_WARN("Duplicated external reference in " << getFullName() << ": " << key);
continue;
}
if (intersection) {
for(auto &geo : geos) {
auto egf = ExternalGeometryFacade::getFacade(geo.get());
egf->setFlag(ExternalGeometryExtension::Defining, defining);
}
} else if (defining && i+1==(int)Objects.size()) {
for(auto &geo : geos)
ExternalGeometryFacade::getFacade(geo.get())->setFlag(
ExternalGeometryExtension::Defining);
}
for(auto &geo : geos)
for (auto& geo : geos) {
ExternalGeometryFacade::getFacade(geo.get())->setRef(key);
}
newGeos.push_back(std::move(geos));
}
@@ -9308,8 +9406,9 @@ void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection)
solverNeedsUpdate=true;
Constraints.acceptGeometry(getCompleteGeometry());
if(hasError && this->isRecomputing())
if (hasError && this->isRecomputing()) {
throw Base::RuntimeError("Missing external geometry reference");
}
}
void SketchObject::fixExternalGeometry(const std::vector<int> &geoIds) {

View File

@@ -46,6 +46,20 @@ namespace Sketcher
class SketchAnalysis;
struct ExternalToAdd
{
App::DocumentObject* obj;
std::string subname;
bool defining;
bool intersection;
};
enum class ExtType
{
Projection,
Intersection,
Both
};
class SketcherExport SketchObject: public Part::Part2DObject
{
typedef Part::Part2DObject inherited;
@@ -68,6 +82,7 @@ public:
Part ::PropertyGeometryList Geometry;
Sketcher::PropertyConstraintList Constraints;
App ::PropertyLinkSubList ExternalGeometry;
App::PropertyIntegerList ExternalTypes;
App ::PropertyLinkListHidden Exports;
Part ::PropertyGeometryList ExternalGeo;
App ::PropertyBool FullyConstrained;
@@ -231,7 +246,9 @@ public:
return ExternalGeo.getValues();
}
/// rebuilds external geometry (projection onto the sketch plane)
void rebuildExternalGeometry(bool defining = false, bool intersection = false);
// It uses std::optional because this function is actually used to both recompute external
// geometries but also to add new external geometries. Ideally this should be refactored.
void rebuildExternalGeometry(std::optional<ExternalToAdd> extToAdd = std::nullopt);
/// returns the number of external Geometry entities
int getExternalGeometryCount() const
{

View File

@@ -253,12 +253,14 @@ carbonCopy(objName:str, asConstruction=True)
<UserDocu>
Add a link to an external geometry.
addExternal(objName:str, subName:str)
addExternal(objName:str, subName:str, bool:defining, bool:intersection)
Args:
objName: The name of the document object to reference.
subName: The name of the sub-element of the object's shape to link as
"external geometry".
defining: Should the external edges be defining or construction?
intersection: Should the external edges be projections or intersections?
</UserDocu>
</Documentation>
</Methode>

View File

@@ -557,19 +557,35 @@ PyObject* SketchObjectPy::addExternal(PyObject* args)
{
char* ObjectName;
char* SubName;
PyObject* defining; // this is an optional argument default false
PyObject* defining; // this is an optional argument default false
PyObject* intersection; // this is an optional argument default false
bool isDefining;
if (!PyArg_ParseTuple(args, "ssO!", &ObjectName, &SubName, &PyBool_Type, &defining)) {
PyErr_Clear();
if (!PyArg_ParseTuple(args, "ss", &ObjectName, &SubName)) {
return nullptr;
bool isIntersection;
if (!PyArg_ParseTuple(args,
"ssO!O!",
&ObjectName,
&SubName,
&PyBool_Type,
&defining,
&PyBool_Type,
&intersection)) {
if (!PyArg_ParseTuple(args, "ssO!", &ObjectName, &SubName, &PyBool_Type, &defining)) {
PyErr_Clear();
if (!PyArg_ParseTuple(args, "ss", &ObjectName, &SubName)) {
return nullptr;
}
else {
isDefining = false;
}
}
else {
isDefining = false;
isDefining = Base::asBoolean(defining);
}
isIntersection = false;
}
else {
isDefining = Base::asBoolean(defining);
isIntersection = Base::asBoolean(intersection);
}
// get the target object for the external link
@@ -590,7 +606,7 @@ PyObject* SketchObjectPy::addExternal(PyObject* args)
}
// add the external
if (skObj->addExternal(Obj, SubName, isDefining) < 0) {
if (skObj->addExternal(Obj, SubName, isDefining, isIntersection) < 0) {
std::stringstream str;
str << "Not able to add external shape element " << SubName;
PyErr_SetString(PyExc_ValueError, str.str().c_str());

View File

@@ -115,7 +115,9 @@ CmdSketcherToggleConstruction::CmdSketcherToggleConstruction()
rcCmdMgr.addCommandMode("ToggleConstruction", "Sketcher_CreatePeriodicBSplineByInterpolation");
rcCmdMgr.addCommandMode("ToggleConstruction", "Sketcher_CompCreateBSpline");
rcCmdMgr.addCommandMode("ToggleConstruction", "Sketcher_CarbonCopy");
rcCmdMgr.addCommandMode("ToggleConstruction", "Sketcher_CompExternal");
rcCmdMgr.addCommandMode("ToggleConstruction", "Sketcher_External");
rcCmdMgr.addCommandMode("ToggleConstruction", "Sketcher_Intersection");
rcCmdMgr.addCommandMode("ToggleConstruction", "Sketcher_ToggleConstruction");
}

View File

@@ -1434,7 +1434,63 @@ public:
}
};
// ======================================================================================
// Group for external tools =============================================
class CmdSketcherCompExternal: public Gui::GroupCommand
{
public:
CmdSketcherCompExternal()
: GroupCommand("Sketcher_CompExternal")
{
sAppModule = "Sketcher";
sGroup = "Sketcher";
sMenuText = QT_TR_NOOP("Create external");
sToolTipText = QT_TR_NOOP("Create external edges linked to external geometries.");
sWhatsThis = "Sketcher_CompExternal";
sStatusTip = sToolTipText;
eType = ForEdit;
setCheckable(false);
addCommand("Sketcher_External");
addCommand("Sketcher_Intersection");
}
void updateAction(int mode) override
{
Gui::ActionGroup* pcAction = qobject_cast<Gui::ActionGroup*>(getAction());
if (!pcAction) {
return;
}
QList<QAction*> al = pcAction->actions();
int index = pcAction->property("defaultAction").toInt();
switch (static_cast<GeometryCreationMode>(mode)) {
case GeometryCreationMode::Normal:
al[0]->setIcon(Gui::BitmapFactory().iconFromTheme("Sketcher_External"));
al[1]->setIcon(Gui::BitmapFactory().iconFromTheme("Sketcher_Intersection"));
getAction()->setIcon(al[index]->icon());
break;
case GeometryCreationMode::Construction:
al[0]->setIcon(Gui::BitmapFactory().iconFromTheme("Sketcher_External_Constr"));
al[1]->setIcon(Gui::BitmapFactory().iconFromTheme("Sketcher_Intersection_Constr"));
getAction()->setIcon(al[index]->icon());
break;
}
}
const char* className() const override
{
return "CmdSketcherCompExternal";
}
bool isActive() override
{
return isCommandActive(getActiveGuiDocument());
}
};
// Externals - Projection ==================================================================
DEF_STD_CMD_AU(CmdSketcherExternal)
@@ -1443,8 +1499,10 @@ CmdSketcherExternal::CmdSketcherExternal()
{
sAppModule = "Sketcher";
sGroup = "Sketcher";
sMenuText = QT_TR_NOOP("Create external geometry");
sToolTipText = QT_TR_NOOP("Create an edge linked to an external geometry");
sMenuText = QT_TR_NOOP("Create external projection geometry");
sToolTipText = QT_TR_NOOP("Create the projection edges of an external geometry.\n"
"External edges can be either defining or construction geometries.\n"
"You can use the toggle construction tool.");
sWhatsThis = "Sketcher_External";
sStatusTip = sToolTipText;
sPixmap = "Sketcher_External";
@@ -1465,6 +1523,39 @@ bool CmdSketcherExternal::isActive()
return isCommandActive(getActiveGuiDocument());
}
// Externals - Intersection ==================================================================
DEF_STD_CMD_AU(CmdSketcherIntersection)
CmdSketcherIntersection::CmdSketcherIntersection()
: Command("Sketcher_Intersection")
{
sAppModule = "Sketcher";
sGroup = "Sketcher";
sMenuText = QT_TR_NOOP("Create external intersection geometry");
sToolTipText =
QT_TR_NOOP("Create the intersection edges of an external geometry with the sketch plane.\n"
"External edges can be either defining or construction geometries.\n"
"You can use the toggle construction tool.");
sWhatsThis = "Sketcher_Intersection";
sStatusTip = sToolTipText;
sPixmap = "Sketcher_Intersection";
sAccel = "G, I";
eType = ForEdit;
}
CONSTRUCTION_UPDATE_ACTION(CmdSketcherIntersection, "Sketcher_Intersection")
void CmdSketcherIntersection::activated(int iMsg)
{
ActivateHandler(getActiveGuiDocument(), std::make_unique<DrawSketchHandlerExternal>(true));
}
bool CmdSketcherIntersection::isActive(void)
{
return isCommandActive(getActiveGuiDocument());
}
// ======================================================================================
DEF_STD_CMD_AU(CmdSketcherCarbonCopy)
@@ -2069,6 +2160,8 @@ void CreateSketcherCommandsCreateGeo()
rcCmdMgr.addCommand(new CmdSketcherSplit());
rcCmdMgr.addCommand(new CmdSketcherCompCurveEdition());
rcCmdMgr.addCommand(new CmdSketcherExternal());
rcCmdMgr.addCommand(new CmdSketcherIntersection());
rcCmdMgr.addCommand(new CmdSketcherCompExternal());
rcCmdMgr.addCommand(new CmdSketcherCarbonCopy());
rcCmdMgr.addCommand(new CmdSketcherCompLine());
}

View File

@@ -116,7 +116,9 @@ public:
class DrawSketchHandlerExternal: public DrawSketchHandler
{
public:
DrawSketchHandlerExternal() = default;
DrawSketchHandlerExternal(bool intersection = false)
: intersection(intersection)
{}
~DrawSketchHandlerExternal() override
{
Gui::Selection().rmvSelectionGate();
@@ -163,10 +165,11 @@ public:
Gui::Command::openCommand(
QT_TRANSLATE_NOOP("Command", "Add external geometry"));
Gui::cmdAppObjectArgs(sketchgui->getObject(),
"addExternal(\"%s\",\"%s\", %s)",
"addExternal(\"%s\",\"%s\", %s, %s)",
msg.pObjectName,
msg.pSubName,
isConstructionMode() ? "False" : "True");
isConstructionMode() ? "False" : "True",
intersection ? "True" : "False");
Gui::Command::commitCommand();
@@ -214,6 +217,10 @@ private:
QString getCrosshairCursorSVGName() const override
{
if (intersection) {
return QString::fromLatin1("Sketcher_Pointer_External_Intersection");
}
return QString::fromLatin1("Sketcher_Pointer_External");
}
@@ -222,6 +229,8 @@ private:
Q_UNUSED(sketchgui);
setAxisPickStyle(true);
}
bool intersection;
};

View File

@@ -200,6 +200,8 @@
<file>icons/geometry/Sketcher_Extend.svg</file>
<file>icons/geometry/Sketcher_External.svg</file>
<file>icons/geometry/Sketcher_External_Constr.svg</file>
<file>icons/geometry/Sketcher_Intersection.svg</file>
<file>icons/geometry/Sketcher_Intersection_Constr.svg</file>
<file>icons/geometry/Sketcher_Split.svg</file>
<file>icons/geometry/Sketcher_ToggleConstruction.svg</file>
<file>icons/geometry/Sketcher_ToggleConstruction_Constr.svg</file>
@@ -251,6 +253,7 @@
<file>icons/pointers/Sketcher_Pointer_Create_Symmetry.svg</file>
<file>icons/pointers/Sketcher_Pointer_Extension.svg</file>
<file>icons/pointers/Sketcher_Pointer_External.svg</file>
<file>icons/pointers/Sketcher_Pointer_External_Intersection.svg</file>
<file>icons/pointers/Sketcher_Pointer_Heptagon.svg</file>
<file>icons/pointers/Sketcher_Pointer_Hexagon.svg</file>
<file>icons/pointers/Sketcher_Pointer_InsertKnot.svg</file>

View File

@@ -0,0 +1,399 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="64"
height="64"
id="svg2869"
version="1.1"
viewBox="0 0 64 64"
sodipodi:docname="Sketcher_Intersection.svg"
inkscape:version="1.1-beta1 (77e7b44db3, 2021-03-28)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<sodipodi:namedview
id="namedview71"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
objecttolerance="10.0"
gridtolerance="10.0"
guidetolerance="10.0"
inkscape:pageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="2.9414063"
inkscape:cx="-202.45418"
inkscape:cy="55.245684"
inkscape:window-width="3840"
inkscape:window-height="1571"
inkscape:window-x="-9"
inkscape:window-y="-9"
inkscape:window-maximized="1"
inkscape:current-layer="svg2869" />
<defs
id="defs2871">
<linearGradient
id="linearGradient5">
<stop
style="stop-color:#ef2929;stop-opacity:1;"
offset="0"
id="stop19" />
<stop
style="stop-color:#ef2929;stop-opacity:0;"
offset="1"
id="stop20" />
</linearGradient>
<linearGradient
id="swatch18">
<stop
style="stop-color:#ef2929;stop-opacity:1;"
offset="0"
id="stop18" />
</linearGradient>
<linearGradient
id="swatch15">
<stop
style="stop-color:#3d0000;stop-opacity:1;"
offset="0"
id="stop15" />
</linearGradient>
<linearGradient
id="linearGradient5-1">
<stop
style="stop-color:#ef2929;stop-opacity:1;"
offset="0"
id="stop5" />
<stop
style="stop-color:#ef2929;stop-opacity:0;"
offset="1"
id="stop6" />
</linearGradient>
<linearGradient
id="linearGradient3836-9">
<stop
style="stop-color:#a40000;stop-opacity:1"
offset="0"
id="stop3838-8" />
<stop
style="stop-color:#ef2929;stop-opacity:1"
offset="1"
id="stop3840-1" />
</linearGradient>
<linearGradient
id="linearGradient3836-9-3">
<stop
style="stop-color:#a40000;stop-opacity:1"
offset="0"
id="stop3838-8-5" />
<stop
style="stop-color:#ef2929;stop-opacity:1"
offset="1"
id="stop3840-1-6" />
</linearGradient>
<linearGradient
y2="5"
x2="-22"
y1="18"
x1="-18"
gradientUnits="userSpaceOnUse"
id="linearGradient3082"
xlink:href="#linearGradient3836-9-3" />
<linearGradient
id="linearGradient3836-9-7">
<stop
style="stop-color:#a40000;stop-opacity:1"
offset="0"
id="stop3838-8-0" />
<stop
style="stop-color:#ef2929;stop-opacity:1"
offset="1"
id="stop3840-1-9" />
</linearGradient>
<linearGradient
y2="5"
x2="-22"
y1="18"
x1="-18"
gradientUnits="userSpaceOnUse"
id="linearGradient3082-3"
xlink:href="#linearGradient3836-9-7" />
<linearGradient
xlink:href="#linearGradient3836-9-3"
id="linearGradient3801-1-3"
gradientUnits="userSpaceOnUse"
x1="-18"
y1="18"
x2="-22"
y2="5"
gradientTransform="matrix(0.76342439,0,0,0.75750425,-4.596389,2.7525637)" />
<linearGradient
xlink:href="#linearGradient3836-9-3"
id="linearGradient3801-1-3-2"
gradientUnits="userSpaceOnUse"
x1="-18"
y1="18"
x2="-22"
y2="5"
gradientTransform="matrix(0.84956703,0,0,0.84301394,-2.927337,1.7790378)" />
<linearGradient
xlink:href="#linearGradient3836-9-3"
id="linearGradient34"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.82607043,0,0,0.82533448,-4.0098079,1.346708)"
x1="-18"
y1="18"
x2="-22"
y2="5" />
<linearGradient
xlink:href="#linearGradient3838"
id="linearGradient3844"
x1="36"
y1="1039.3622"
x2="32"
y2="1003.3622"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(2.0563921e-6,-988.36218)" />
<linearGradient
id="linearGradient3838">
<stop
style="stop-color:#d3d7cf;stop-opacity:1;"
offset="0"
id="stop3840" />
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="1"
id="stop3842" />
</linearGradient>
<linearGradient
xlink:href="#linearGradient3830"
id="linearGradient3836"
x1="36"
y1="1037.3622"
x2="32"
y2="1005.3622"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(2.0563921e-6,-988.36218)" />
<linearGradient
id="linearGradient3830">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop3832" />
<stop
style="stop-color:#d3d7cf;stop-opacity:1;"
offset="1"
id="stop3834" />
</linearGradient>
<linearGradient
x1="10.504496"
y1="16.48678"
x2="5.9349072"
y2="1.6356685"
id="linearGradient-1"
gradientTransform="scale(0.99999018,1.0000098)"
gradientUnits="userSpaceOnUse">
<stop
stop-color="#A40000"
offset="0%"
id="stop6-9" />
<stop
stop-color="#EF2929"
offset="100%"
id="stop8" />
</linearGradient>
<linearGradient
xlink:href="#linearGradient3815"
id="linearGradient3856"
gradientUnits="userSpaceOnUse"
x1="80"
y1="58"
x2="79"
y2="42"
gradientTransform="matrix(-0.00939458,-1.2882215,1.6774889,-0.00721454,-1.7046467,126.12227)" />
<linearGradient
id="linearGradient3815">
<stop
style="stop-color:#3465a4;stop-opacity:1"
offset="0"
id="stop3817" />
<stop
style="stop-color:#729fcf;stop-opacity:1"
offset="1"
id="stop3819" />
</linearGradient>
<linearGradient
xlink:href="#linearGradient3841"
id="linearGradient3858"
gradientUnits="userSpaceOnUse"
x1="109"
y1="51"
x2="105"
y2="38"
gradientTransform="translate(-16.823373,6.2895086)" />
<linearGradient
id="linearGradient3841">
<stop
style="stop-color:#204a87;stop-opacity:1"
offset="0"
id="stop3843" />
<stop
style="stop-color:#3465a4;stop-opacity:1"
offset="1"
id="stop3845" />
</linearGradient>
<linearGradient
y2="5"
x2="-22"
y1="18"
x1="-18"
gradientTransform="matrix(0.77114848,0,0,0.77113937,-4.4090973,2.5859051)"
gradientUnits="userSpaceOnUse"
id="linearGradient3898"
xlink:href="#linearGradient3836-9-3" />
<linearGradient
xlink:href="#linearGradient3815"
id="linearGradient3978"
gradientUnits="userSpaceOnUse"
x1="-15"
y1="37"
x2="-19"
y2="37"
gradientTransform="rotate(15,69.468151,244.38323)" />
<linearGradient
xlink:href="#linearGradient3836-9-3"
id="linearGradient25"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.82607043,0,0,0.82533448,-4.0098079,1.346708)"
x1="-18"
y1="18"
x2="-22"
y2="5" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3815"
id="linearGradient3748"
x1="21.865803"
y1="14.823394"
x2="59.167919"
y2="14.823394"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-5.3545817,7.6494024)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3815"
id="linearGradient3783"
gradientUnits="userSpaceOnUse"
gradientTransform="rotate(180,37.057105,31.362549)"
x1="59.092896"
y1="15.588334"
x2="21.260881"
y2="15.673326" />
<linearGradient
xlink:href="#linearGradient3836-9"
id="linearGradient25-8"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.82607043,0,0,0.82533448,-4.0098079,1.346708)"
x1="-18"
y1="18"
x2="-22"
y2="5" />
</defs>
<metadata
id="metadata2874">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:creator>
<cc:Agent>
<dc:title>[maxwxyz]</dc:title>
</cc:Agent>
</dc:creator>
<dc:relation>https://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
<dc:publisher>
<cc:Agent>
<dc:title>FreeCAD</dc:title>
</cc:Agent>
</dc:publisher>
<dc:identifier>FreeCAD/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_CreateArc.svg</dc:identifier>
<dc:rights>
<cc:Agent>
<dc:title>FreeCAD LGPL2+</dc:title>
</cc:Agent>
</dc:rights>
<dc:date>2023-12-19</dc:date>
</cc:Work>
</rdf:RDF>
</metadata>
<path
style="fill:url(#linearGradient3783);fill-opacity:1;stroke:#0b1521;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 51.250996,35.357237 49.496052,59.704648 15.946284,59.848939 17.508632,35.017264"
id="path3606-0" />
<path
style="fill:none;stroke:#729fcf;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 49.178749,35.190901 47.632004,57.712779 18.067528,57.86373 19.505976,35.059761"
id="path4286-5"
sodipodi:nodetypes="cccc" />
<path
id="path3027"
d="M 1.5850321,44.532846 24.798304,24.100465 61.939537,28.186942 38.726265,48.619323 Z"
style="fill:#d21919;fill-opacity:0.36831275;stroke:#d21919;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:url(#linearGradient3748);fill-opacity:1;stroke:#0b1521;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 17.508632,35.017264 19.263576,10.669853 52.813344,10.525562 51.250996,35.357237"
id="path3606" />
<path
style="fill:none;stroke:#729fcf;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 19.505976,35.059761 1.62696,-22.472403 29.282936,0.05622 -1.154486,22.652497"
id="path4286"
sodipodi:nodetypes="cccc" />
<path
style="fill:none;stroke:#151819;stroke-width:8;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 18.462151,34.4834 32.788845,0.873837"
id="path3921"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#d3d7cf;stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 18.462151,34.4834 32.788845,0.873837"
id="path3921-4"
sodipodi:nodetypes="cc" />
<path
style="display:inline;fill:none;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 18.15845,33.483274 33.405046,0.873838"
id="path11"
sodipodi:nodetypes="cc" />
<g
transform="matrix(0.52286042,0,0,0.52286032,62.255136,29.78816)"
id="g25"
style="stroke-width:1.2842">
<path
style="fill:none;stroke:#2e0000;stroke-width:2.56841;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path24"
d="M -26.310778,5.3580033 A 8.3519646,8.3515832 0.02039876 1 1 -13.623399,16.222662 8.3519646,8.3515832 0.02039876 1 1 -26.310778,5.3580033 Z" />
<path
style="fill:url(#linearGradient25);fill-opacity:1;stroke:#ef2929;stroke-width:2.56842;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path25"
d="m -24.358888,7.0362241 a 5.782493,5.7773415 0 1 1 8.784093,7.5158349 5.782493,5.7773415 0 0 1 -8.784093,-7.5158349 z" />
</g>
<g
transform="matrix(0.52286042,0,0,0.52286032,27.608659,28.950461)"
id="g25-7"
style="stroke-width:1.2842">
<path
style="fill:none;stroke:#2e0000;stroke-width:2.56841;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path24-7"
d="M -26.310778,5.3580033 A 8.3519646,8.3515832 0.02039876 1 1 -13.623399,16.222662 8.3519646,8.3515832 0.02039876 1 1 -26.310778,5.3580033 Z" />
<path
style="fill:url(#linearGradient25-8);fill-opacity:1;stroke:#ef2929;stroke-width:2.56842;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path25-2"
d="m -24.358888,7.0362241 a 5.782493,5.7773415 0 1 1 8.784093,7.5158349 5.782493,5.7773415 0 0 1 -8.784093,-7.5158349 z" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -0,0 +1,399 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="64"
height="64"
id="svg2869"
version="1.1"
viewBox="0 0 64 64"
sodipodi:docname="Sketcher_Intersection_Constr.svg"
inkscape:version="1.1-beta1 (77e7b44db3, 2021-03-28)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<sodipodi:namedview
id="namedview71"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
objecttolerance="10.0"
gridtolerance="10.0"
guidetolerance="10.0"
inkscape:pageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="8.3195534"
inkscape:cx="45.134635"
inkscape:cy="32.633963"
inkscape:window-width="3840"
inkscape:window-height="1571"
inkscape:window-x="-9"
inkscape:window-y="-9"
inkscape:window-maximized="1"
inkscape:current-layer="svg2869" />
<defs
id="defs2871">
<linearGradient
id="linearGradient5">
<stop
style="stop-color:#ef2929;stop-opacity:1;"
offset="0"
id="stop19" />
<stop
style="stop-color:#ef2929;stop-opacity:0;"
offset="1"
id="stop20" />
</linearGradient>
<linearGradient
id="swatch18">
<stop
style="stop-color:#ef2929;stop-opacity:1;"
offset="0"
id="stop18" />
</linearGradient>
<linearGradient
id="swatch15">
<stop
style="stop-color:#3d0000;stop-opacity:1;"
offset="0"
id="stop15" />
</linearGradient>
<linearGradient
id="linearGradient5-1">
<stop
style="stop-color:#ef2929;stop-opacity:1;"
offset="0"
id="stop5" />
<stop
style="stop-color:#ef2929;stop-opacity:0;"
offset="1"
id="stop6" />
</linearGradient>
<linearGradient
id="linearGradient3836-9">
<stop
style="stop-color:#a40000;stop-opacity:1"
offset="0"
id="stop3838-8" />
<stop
style="stop-color:#ef2929;stop-opacity:1"
offset="1"
id="stop3840-1" />
</linearGradient>
<linearGradient
id="linearGradient3836-9-3">
<stop
style="stop-color:#a40000;stop-opacity:1"
offset="0"
id="stop3838-8-5" />
<stop
style="stop-color:#ef2929;stop-opacity:1"
offset="1"
id="stop3840-1-6" />
</linearGradient>
<linearGradient
y2="5"
x2="-22"
y1="18"
x1="-18"
gradientUnits="userSpaceOnUse"
id="linearGradient3082"
xlink:href="#linearGradient3836-9-3" />
<linearGradient
id="linearGradient3836-9-7">
<stop
style="stop-color:#a40000;stop-opacity:1"
offset="0"
id="stop3838-8-0" />
<stop
style="stop-color:#ef2929;stop-opacity:1"
offset="1"
id="stop3840-1-9" />
</linearGradient>
<linearGradient
y2="5"
x2="-22"
y1="18"
x1="-18"
gradientUnits="userSpaceOnUse"
id="linearGradient3082-3"
xlink:href="#linearGradient3836-9-7" />
<linearGradient
xlink:href="#linearGradient3836-9-3"
id="linearGradient3801-1-3"
gradientUnits="userSpaceOnUse"
x1="-18"
y1="18"
x2="-22"
y2="5"
gradientTransform="matrix(0.76342439,0,0,0.75750425,-4.596389,2.7525637)" />
<linearGradient
xlink:href="#linearGradient3836-9-3"
id="linearGradient3801-1-3-2"
gradientUnits="userSpaceOnUse"
x1="-18"
y1="18"
x2="-22"
y2="5"
gradientTransform="matrix(0.84956703,0,0,0.84301394,-2.927337,1.7790378)" />
<linearGradient
xlink:href="#linearGradient3836-9-3"
id="linearGradient34"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.82607043,0,0,0.82533448,-4.0098079,1.346708)"
x1="-18"
y1="18"
x2="-22"
y2="5" />
<linearGradient
xlink:href="#linearGradient3838"
id="linearGradient3844"
x1="36"
y1="1039.3622"
x2="32"
y2="1003.3622"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(2.0563921e-6,-988.36218)" />
<linearGradient
id="linearGradient3838">
<stop
style="stop-color:#d3d7cf;stop-opacity:1;"
offset="0"
id="stop3840" />
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="1"
id="stop3842" />
</linearGradient>
<linearGradient
xlink:href="#linearGradient3830"
id="linearGradient3836"
x1="36"
y1="1037.3622"
x2="32"
y2="1005.3622"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(2.0563921e-6,-988.36218)" />
<linearGradient
id="linearGradient3830">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop3832" />
<stop
style="stop-color:#d3d7cf;stop-opacity:1;"
offset="1"
id="stop3834" />
</linearGradient>
<linearGradient
x1="10.504496"
y1="16.48678"
x2="5.9349072"
y2="1.6356685"
id="linearGradient-1"
gradientTransform="scale(0.99999018,1.0000098)"
gradientUnits="userSpaceOnUse">
<stop
stop-color="#A40000"
offset="0%"
id="stop6-9" />
<stop
stop-color="#EF2929"
offset="100%"
id="stop8" />
</linearGradient>
<linearGradient
xlink:href="#linearGradient3815"
id="linearGradient3856"
gradientUnits="userSpaceOnUse"
x1="80"
y1="58"
x2="79"
y2="42"
gradientTransform="matrix(-0.00939458,-1.2882215,1.6774889,-0.00721454,-1.7046467,126.12227)" />
<linearGradient
id="linearGradient3815">
<stop
style="stop-color:#3465a4;stop-opacity:1"
offset="0"
id="stop3817" />
<stop
style="stop-color:#729fcf;stop-opacity:1"
offset="1"
id="stop3819" />
</linearGradient>
<linearGradient
xlink:href="#linearGradient3841"
id="linearGradient3858"
gradientUnits="userSpaceOnUse"
x1="109"
y1="51"
x2="105"
y2="38"
gradientTransform="translate(-16.823373,6.2895086)" />
<linearGradient
id="linearGradient3841">
<stop
style="stop-color:#204a87;stop-opacity:1"
offset="0"
id="stop3843" />
<stop
style="stop-color:#3465a4;stop-opacity:1"
offset="1"
id="stop3845" />
</linearGradient>
<linearGradient
y2="5"
x2="-22"
y1="18"
x1="-18"
gradientTransform="matrix(0.77114848,0,0,0.77113937,-4.4090973,2.5859051)"
gradientUnits="userSpaceOnUse"
id="linearGradient3898"
xlink:href="#linearGradient3836-9-3" />
<linearGradient
xlink:href="#linearGradient3815"
id="linearGradient3978"
gradientUnits="userSpaceOnUse"
x1="-15"
y1="37"
x2="-19"
y2="37"
gradientTransform="rotate(15,69.468151,244.38323)" />
<linearGradient
xlink:href="#linearGradient3836-9-3"
id="linearGradient25"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.82607043,0,0,0.82533448,-4.0098079,1.346708)"
x1="-18"
y1="18"
x2="-22"
y2="5" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3815"
id="linearGradient3748"
x1="21.865803"
y1="14.823394"
x2="59.167919"
y2="14.823394"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-5.3545817,7.6494024)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3815"
id="linearGradient3783"
gradientUnits="userSpaceOnUse"
gradientTransform="rotate(180,37.057105,31.362549)"
x1="59.092896"
y1="15.588334"
x2="21.260881"
y2="15.673326" />
<linearGradient
xlink:href="#linearGradient3836-9"
id="linearGradient25-8"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.82607043,0,0,0.82533448,-4.0098079,1.346708)"
x1="-18"
y1="18"
x2="-22"
y2="5" />
</defs>
<metadata
id="metadata2874">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:creator>
<cc:Agent>
<dc:title>[maxwxyz]</dc:title>
</cc:Agent>
</dc:creator>
<dc:relation>https://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
<dc:publisher>
<cc:Agent>
<dc:title>FreeCAD</dc:title>
</cc:Agent>
</dc:publisher>
<dc:identifier>FreeCAD/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_CreateArc.svg</dc:identifier>
<dc:rights>
<cc:Agent>
<dc:title>FreeCAD LGPL2+</dc:title>
</cc:Agent>
</dc:rights>
<dc:date>2023-12-19</dc:date>
</cc:Work>
</rdf:RDF>
</metadata>
<path
style="fill:url(#linearGradient3783);fill-opacity:1;stroke:#0b1521;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 51.250996,35.357237 49.496052,59.704648 15.946284,59.848939 17.508632,35.017264"
id="path3606-0" />
<path
style="fill:none;stroke:#729fcf;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 49.178749,35.190901 47.632004,57.712779 18.067528,57.86373 19.505976,35.059761"
id="path4286-5"
sodipodi:nodetypes="cccc" />
<path
id="path3027"
d="M 1.5850321,44.532846 24.798304,24.100465 61.939537,28.186942 38.726265,48.619323 Z"
style="fill:#d21919;fill-opacity:0.36831275;stroke:#d21919;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:url(#linearGradient3748);fill-opacity:1;stroke:#0b1521;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 17.508632,35.017264 19.263576,10.669853 52.813344,10.525562 51.250996,35.357237"
id="path3606" />
<path
style="fill:none;stroke:#729fcf;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 19.505976,35.059761 1.62696,-22.472403 29.282936,0.05622 -1.154486,22.652497"
id="path4286"
sodipodi:nodetypes="cccc" />
<path
style="fill:none;stroke:#0b1521;stroke-width:8;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 18.462151,34.4834 32.788845,0.873837"
id="path3921"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#3465a4;stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 18.462151,34.4834 32.788845,0.873837"
id="path3921-4"
sodipodi:nodetypes="cc" />
<path
style="display:inline;fill:none;stroke:#729fcf;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 18.15845,33.483274 33.405046,0.873838"
id="path11"
sodipodi:nodetypes="cc" />
<g
transform="matrix(0.52286042,0,0,0.52286032,62.255136,29.78816)"
id="g25"
style="stroke-width:1.2842">
<path
style="fill:none;stroke:#2e0000;stroke-width:2.56841;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path24"
d="M -26.310778,5.3580033 A 8.3519646,8.3515832 0.02039876 1 1 -13.623399,16.222662 8.3519646,8.3515832 0.02039876 1 1 -26.310778,5.3580033 Z" />
<path
style="fill:url(#linearGradient25);fill-opacity:1;stroke:#ef2929;stroke-width:2.56842;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path25"
d="m -24.358888,7.0362241 a 5.782493,5.7773415 0 1 1 8.784093,7.5158349 5.782493,5.7773415 0 0 1 -8.784093,-7.5158349 z" />
</g>
<g
transform="matrix(0.52286042,0,0,0.52286032,27.608659,28.950461)"
id="g25-7"
style="stroke-width:1.2842">
<path
style="fill:none;stroke:#2e0000;stroke-width:2.56841;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path24-7"
d="M -26.310778,5.3580033 A 8.3519646,8.3515832 0.02039876 1 1 -13.623399,16.222662 8.3519646,8.3515832 0.02039876 1 1 -26.310778,5.3580033 Z" />
<path
style="fill:url(#linearGradient25-8);fill-opacity:1;stroke:#ef2929;stroke-width:2.56842;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path25-2"
d="m -24.358888,7.0362241 a 5.782493,5.7773415 0 1 1 8.784093,7.5158349 5.782493,5.7773415 0 0 1 -8.784093,-7.5158349 z" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
id="svg12"
width="64"
height="64"
version="1.1"
sodipodi:docname="Sketcher_Pointer_External_Intersection.svg"
inkscape:version="1.1-beta1 (77e7b44db3, 2021-03-28)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="8"
inkscape:cx="12.3125"
inkscape:cy="38.5625"
inkscape:window-width="1920"
inkscape:window-height="1057"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg12"
objecttolerance="10.0"
gridtolerance="10.0"
guidetolerance="10.0"
inkscape:pageshadow="0"
showgrid="false" />
<metadata
id="metadata18">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs16">
<inkscape:path-effect
effect="dashed_stroke"
id="path-effect1"
is_visible="true"
lpeversion="1"
numberdashes="4"
holefactor="0"
splitsegments="true"
halfextreme="true"
unifysegment="false"
message="Add &lt;b&gt;&quot;Fill Between Many LPE&quot;&lt;/b&gt; to add fill." />
</defs>
<path
id="path6161"
style="fill:none;stroke:#d60000;stroke-width:2;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 61.303538,37.170339 H 21.900546 L 5.8602162,55.892161 H 47.78452 L 61.303538,37.170339 v 0"
sodipodi:nodetypes="cccccc" />
<g
id="g1290"
transform="translate(-10.625,20.75)">
<path
style="fill:#a76635;stroke:#cc0000;stroke-width:2;stroke-dasharray:none;stroke-dashoffset:0"
d="m 33.483443,25.311263 h 24"
id="path1" />
<circle
cx="33.483452"
cy="25.311251"
id="circle4755"
style="fill:none;stroke:#cc0000;stroke-width:2"
r="4" />
<circle
cx="57.483452"
cy="25.311251"
id="circle4755-2"
style="fill:none;stroke:#cc0000;stroke-width:2"
r="4" />
</g>
<g
style="stroke:#ffffff;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:miter"
id="crosshair">
<path
id="path9"
d="m16,3v9m0,8v9m-13-13h9m8,0h9" />
</g>
<path
id="path6161-0"
style="fill:none;stroke:#d60000;stroke-width:2;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 23.764089,24.398641 -2.125,37.652992 24.721822,0.16533 1.375,-37.924304 -23.971822,0.105982"
sodipodi:nodetypes="ccccc" />
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@@ -538,6 +538,7 @@ inline void SketcherAddWorkbenchTools<Gui::MenuItem>(Gui::MenuItem& consaccel)
SketcherAddWorkspaceFillets(consaccel);
SketcherAddWorkspaceCurveEdition(consaccel);
consaccel << "Sketcher_External"
<< "Sketcher_Intersection"
<< "Sketcher_CarbonCopy"
<< "Separator"
<< "Sketcher_SelectOrigin"
@@ -564,7 +565,7 @@ inline void SketcherAddWorkbenchTools<Gui::ToolBarItem>(Gui::ToolBarItem& consac
{
SketcherAddWorkspaceFillets(consaccel);
SketcherAddWorkspaceCurveEdition(consaccel);
consaccel << "Sketcher_External"
consaccel << "Sketcher_CompExternal"
<< "Sketcher_CarbonCopy"
<< "Separator"
<< "Sketcher_Translate"