Sketcher: Text tool - review changes

This commit is contained in:
paddle
2026-03-10 07:22:25 +01:00
committed by Benjamin Nauck
parent fed11359d9
commit 320bd61156
28 changed files with 1831 additions and 248 deletions
+63 -36
View File
@@ -105,6 +105,7 @@
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_HArray1OfBoolean.hxx>
#include <TopExp_Explorer.hxx>
#include <ShapeFix_Wire.hxx>
#if OCC_VERSION_HEX < 0x070600
# include <GeomAdaptor_HSurface.hxx>
@@ -7344,6 +7345,7 @@ struct FTDC_Ctx
std::vector<TopoDS_Wire> Wires;
std::vector<TopoDS_Edge> Edges;
FT_Vector LastVert;
FT_Vector StartVert;
Handle(Geom_Surface) surf;
};
@@ -7360,6 +7362,11 @@ TopoDS_Wire edgesToWire(std::vector<TopoDS_Edge>& Edges)
if (mkWire.IsDone()) {
TopoDS_Wire wire = mkWire.Wire();
BRepLib::BuildCurves3d(wire);
// Ensure the wire is topologically closed and valid
ShapeFix_Wire sfw;
sfw.Load(wire);
sfw.FixClosed();
wire = sfw.Wire();
return wire;
}
else {
@@ -7367,18 +7374,37 @@ TopoDS_Wire edgesToWire(std::vector<TopoDS_Edge>& Edges)
return TopoDS_Wire();
}
}
// Helper to close the current contour if needed and flush to Wires list
void flushContour(FTDC_Ctx* dc)
{
if (dc->Edges.empty()) {
return;
}
// Check if the contour is geometrically closed.
// If not, add a closing segment from LastVert to StartVert.
gp_Pnt2d pStart(dc->StartVert.x, dc->StartVert.y);
gp_Pnt2d pEnd(dc->LastVert.x, dc->LastVert.y);
if (!pStart.IsEqual(pEnd, Precision::Confusion())) {
Handle(Geom2d_TrimmedCurve) lseg = GCE2d_MakeSegment(pEnd, pStart);
TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(lseg, dc->surf);
dc->Edges.push_back(edge);
}
TopoDS_Wire newWire = edgesToWire(dc->Edges);
if (!newWire.IsNull()) {
dc->Wires.push_back(newWire);
}
dc->Edges.clear();
}
// FT Decompose callbacks
int move_cb(const FT_Vector* pt, void* p)
{
FTDC_Ctx* dc = static_cast<FTDC_Ctx*>(p);
if (!dc->Edges.empty()) {
TopoDS_Wire newWire = edgesToWire(dc->Edges);
if (!newWire.IsNull()) {
dc->Wires.push_back(newWire);
}
dc->Edges.clear();
}
flushContour(dc);
dc->StartVert = *pt;
dc->LastVert = *pt;
return 0;
}
@@ -7622,12 +7648,19 @@ std::vector<TopoDS_Shape> makeTextWires(
return allWires;
}
FT_Set_Char_Size(ftFace, 0, 48 * 64 * 10, 0, 0);
double scaleFactor = (height / static_cast<double>(ftFace->height)) / 10.0;
// Use the font's native units for maximum precision
double unitsPerEM = static_cast<double>(ftFace->units_per_EM);
if (unitsPerEM < 1.0) {
unitsPerEM = 2048.0; // Fallback
}
// We want a nominal height of 1.0 for the base shapes
double scaleFactor = (height / unitsPerEM);
FT_Outline_Funcs ftCallbacks = {move_cb, line_cb, quad_cb, cubic_cb, 0, 0};
FT_UInt ftLoadFlags = FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP;
FT_UInt ftLoadFlags = FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP;
double penPos = 0.0;
double currentTracking = 0.0;
FT_ULong prevCharcode = 0;
std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> converter;
@@ -7635,13 +7668,6 @@ std::vector<TopoDS_Shape> makeTextWires(
for (size_t i = 0; i < wide_text.length(); ++i) {
FT_ULong charcode = wide_text[i];
if (charcode == ' ') {
if (FT_Load_Char(ftFace, charcode, ftLoadFlags) == 0) {
penPos += ftFace->glyph->advance.x;
}
prevCharcode = charcode;
continue;
}
if (FT_Load_Char(ftFace, charcode, ftLoadFlags) != 0) {
continue;
@@ -7653,37 +7679,38 @@ std::vector<TopoDS_Shape> makeTextWires(
ftFace,
FT_Get_Char_Index(ftFace, prevCharcode),
FT_Get_Char_Index(ftFace, charcode),
FT_KERNING_DEFAULT,
FT_KERNING_UNSCALED,
&kern
);
penPos += kern.x;
}
FTDC_Ctx ctx;
ctx.surf = new Geom_Plane(gp::Origin(), gp::DZ());
FT_Outline_Decompose(&ftFace->glyph->outline, &ftCallbacks, &ctx);
if (ftFace->glyph->format == FT_GLYPH_FORMAT_OUTLINE
&& ftFace->glyph->outline.n_contours > 0) {
FTDC_Ctx ctx;
ctx.surf = new Geom_Plane(gp::Origin(), gp::DZ());
FT_Outline_Decompose(&ftFace->glyph->outline, &ftCallbacks, &ctx);
if (!ctx.Edges.empty()) {
TopoDS_Wire lastWire = edgesToWire(ctx.Edges);
if (!lastWire.IsNull()) {
ctx.Wires.push_back(lastWire);
}
}
flushContour(&ctx);
gp_Trsf charTransform;
charTransform.SetScale(gp::Origin(), scaleFactor);
gp_Vec translation(penPos * scaleFactor + i * tracking, 0.0, 0.0);
charTransform.SetTranslationPart(translation);
if (!ctx.Wires.empty()) {
gp_Trsf charTransform;
charTransform.SetScale(gp::Origin(), scaleFactor);
gp_Vec translation(penPos * scaleFactor + currentTracking, 0.0, 0.0);
charTransform.SetTranslationPart(translation);
for (const auto& wire : ctx.Wires) {
BRepBuilderAPI_Transform performer(charTransform);
performer.Perform(wire, true); // true = create a copy
if (performer.IsDone()) {
allWires.push_back(performer.Shape());
for (const auto& wire : ctx.Wires) {
BRepBuilderAPI_Transform performer(charTransform);
performer.Perform(wire, true); // true = create a copy
if (performer.IsDone()) {
allWires.push_back(performer.Shape());
}
}
}
}
penPos += ftFace->glyph->advance.x;
currentTracking += tracking;
prevCharcode = charcode;
}
+4
View File
@@ -1,4 +1,8 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
include_directories(
SYSTEM
${CMAKE_SOURCE_DIR}/src/3rdParty/json/single_include/nlohmann/
)
add_library(Sketcher SHARED)
+98 -13
View File
@@ -31,6 +31,8 @@
#include <string>
#include <vector>
#include "json.hpp"
#include <fmt/ranges.h>
#include <Base/Reader.h>
@@ -88,9 +90,9 @@ Constraint* Constraint::copy() const
temp->isInVirtualSpace = this->isInVirtualSpace;
temp->isVisible = this->isVisible;
temp->isActive = this->isActive;
temp->isTextHeight = this->isTextHeight;
temp->elements = this->elements;
// Do not copy tag, otherwise it is considered a clone, and a "rename" by the expression engine.
temp->MetaData = this->MetaData;
#if SKETCHER_CONSTRAINT_USE_LEGACY_ELEMENTS
temp->First = this->First;
@@ -150,12 +152,10 @@ unsigned int Constraint::getMemSize() const
void Constraint::Save(Writer& writer) const
{
std::string encodeName = encodeAttribute(Name);
std::string encodeText = encodeAttribute(Text);
std::string encodeFont = encodeAttribute(Font);
std::string encodeMetaData = encodeAttribute(MetaData);
writer.Stream() << writer.ind() << "<Constrain "
<< "Name=\"" << encodeName << "\" "
<< "Text=\"" << encodeText << "\" "
<< "Font=\"" << encodeFont << "\" "
<< "MetaData=\"" << encodeMetaData << "\" "
<< "Type=\"" << (int)Type << "\" ";
if (this->Type == InternalAlignment) {
writer.Stream() << "InternalAlignmentType=\"" << (int)AlignmentType << "\" "
@@ -167,8 +167,7 @@ void Constraint::Save(Writer& writer) const
<< "IsDriving=\"" << (int)isDriving << "\" "
<< "IsInVirtualSpace=\"" << (int)isInVirtualSpace << "\" "
<< "IsVisible=\"" << (int)isVisible << "\" "
<< "IsActive=\"" << (int)isActive << "\" "
<< "IsTextHeight=\"" << (int)isTextHeight << "\" ";
<< "IsActive=\"" << (int)isActive << "\" ";
// Save elements
{
@@ -201,8 +200,7 @@ void Constraint::Restore(XMLReader& reader)
{
reader.readElement("Constrain");
Name = reader.getAttribute<const char*>("Name");
Text = reader.hasAttribute("Text") ? reader.getAttribute<const char*>("Text") : "";
Font = reader.hasAttribute("Font") ? reader.getAttribute<const char*>("Font") : "";
MetaData = reader.hasAttribute("MetaData") ? reader.getAttribute<const char*>("MetaData") : "";
Type = reader.getAttribute<ConstraintType>("Type");
Value = reader.getAttribute<double>("Value");
@@ -242,10 +240,6 @@ void Constraint::Restore(XMLReader& reader)
isActive = reader.getAttribute<bool>("IsActive");
}
if (reader.hasAttribute("IsTextHeight")) {
isTextHeight = reader.getAttribute<bool>("IsTextHeight");
}
if (reader.hasAttribute("ElementIds") && reader.hasAttribute("ElementPositions")) {
auto splitAndClean = [](std::string_view input) {
const char delimiter = ' ';
@@ -600,3 +594,94 @@ void Constraint::truncateElements(size_t newSize)
elements.resize(newSize);
}
}
std::string Constraint::getText() const
{
if (MetaData.empty()) {
return {};
}
try {
auto j = nlohmann::json::parse(MetaData);
if (j.contains("text")) {
return j["text"].get<std::string>();
}
}
catch (...) {
// Handle JSON parsing errors or type mismatches silently
}
return {};
}
void Constraint::setText(const std::string& text)
{
nlohmann::json j;
if (!MetaData.empty()) {
try {
j = nlohmann::json::parse(MetaData);
}
catch (...) {
}
}
j["text"] = text;
MetaData = j.dump();
}
std::string Constraint::getFont() const
{
if (MetaData.empty()) {
return {};
}
try {
auto j = nlohmann::json::parse(MetaData);
if (j.contains("font")) {
return j["font"].get<std::string>();
}
}
catch (...) {
}
return {};
}
void Constraint::setFont(const std::string& font)
{
nlohmann::json j;
if (!MetaData.empty()) {
try {
j = nlohmann::json::parse(MetaData);
}
catch (...) {
}
}
j["font"] = font;
MetaData = j.dump();
}
bool Constraint::getIsTextHeight() const
{
if (MetaData.empty()) {
return true; // Default value
}
try {
auto j = nlohmann::json::parse(MetaData);
if (j.contains("isTextHeight")) {
return j["isTextHeight"].get<bool>();
}
}
catch (...) {
}
return true; // Default value
}
void Constraint::setIsTextHeight(bool isHeight)
{
nlohmann::json j;
if (!MetaData.empty()) {
try {
j = nlohmann::json::parse(MetaData);
}
catch (...) {
}
}
j["isTextHeight"] = isHeight;
MetaData = j.dump();
}
+8 -3
View File
@@ -216,8 +216,7 @@ public:
ConstraintType Type {None};
InternalAlignmentType AlignmentType {Undef};
std::string Name;
std::string Text;
std::string Font;
std::string MetaData;
float LabelDistance {10.F};
float LabelPosition {0.F};
bool isDriving {true};
@@ -228,7 +227,6 @@ public:
bool isVisible {true};
bool isActive {true};
bool isTextHeight {true};
GeoElementId getElement(size_t index) const;
void setElement(size_t index, GeoElementId element);
@@ -246,6 +244,13 @@ public:
void swapElements(int index1, int index2);
bool ensureElementExists(int index);
std::string getText() const;
void setText(const std::string& text);
std::string getFont() const;
void setFont(const std::string& font);
bool getIsTextHeight() const;
void setIsTextHeight(bool val);
#ifdef SKETCHER_CONSTRAINT_USE_LEGACY_ELEMENTS
// Deprecated, use getElement/setElement instead
int First {GeoEnum::GeoUndef};
+6 -4
View File
@@ -120,6 +120,8 @@ int ConstraintPy::PyInit(PyObject* args, PyObject* /*kwd*/)
return false; // Failure
}
constr_ptr->truncateElements(0);
for (Py_ssize_t i = 0; i < list_size; i += 2) {
PyObject* py_geoId_obj = PyList_GetItem(list, i);
PyObject* py_posId_obj = PyList_GetItem(list, i + 1);
@@ -177,15 +179,15 @@ int ConstraintPy::PyInit(PyObject* args, PyObject* /*kwd*/)
}
// Set the specific members for the Text constraint
constraint->Text = text_str;
constraint->Font = font_str;
constraint->setText(text_str);
constraint->setFont(font_str);
// Check and set the optional boolean
if (py_is_height && PyBool_Check(py_is_height)) {
constraint->isTextHeight = (py_is_height == Py_True);
constraint->setIsTextHeight(py_is_height == Py_True);
}
else {
constraint->isTextHeight = true;
constraint->setIsTextHeight(true);
}
return 0; // Success!
+15 -13
View File
@@ -198,12 +198,12 @@ int Sketch::setUpSketch(
clear();
// The geometries that are in groups are going to be ignored by the solver.
std::set<int> slaveGeoIds;
std::set<int> inGroupGeoIds;
for (const auto& c : ConstraintList) {
if (c->Type == Group || c->Type == Text) {
// Start from index 1, as 0 is the frame.
for (int i = 1; c->hasElement(i); ++i) {
slaveGeoIds.insert(c->getGeoId(i));
inGroupGeoIds.insert(c->getGeoId(i));
}
}
}
@@ -259,7 +259,7 @@ int Sketch::setUpSketch(
buildInternalAlignmentGeometryMap(ConstraintList);
addGeometry(intGeoList, onlyBlockedGeometry, slaveGeoIds);
addGeometry(intGeoList, onlyBlockedGeometry, inGroupGeoIds);
int extStart = Geoms.size();
addGeometry(extGeoList, true);
int extEnd = Geoms.size() - 1;
@@ -277,9 +277,8 @@ int Sketch::setUpSketch(
continue;
}
bool hasSlaveReference = false;
for (int j = 0; c->hasElement(j); ++j) {
if (slaveGeoIds.count(c->getGeoId(j))) {
if (inGroupGeoIds.count(c->getGeoId(j))) {
unenforceableConstraints[i] = true;
break;
}
@@ -762,7 +761,7 @@ int Sketch::addGeometry(const std::vector<Part::Geometry*>& geos, bool fixed)
int Sketch::addGeometry(
const std::vector<Part::Geometry*>& geos,
const std::vector<bool>& blockedGeometry,
const std::set<int>& slaveGeoIds
const std::set<int>& inGroupGeoIds
)
{
assert(geos.size() == blockedGeometry.size());
@@ -777,8 +776,8 @@ int Sketch::addGeometry(
++it, ++bit, ++geoIdCounter) {
// Check if the current geometry is in group.
bool isSlave = slaveGeoIds.count(geoIdCounter);
if (isSlave) {
bool isInGroup = inGroupGeoIds.count(geoIdCounter);
if (isInGroup) {
GeoDef def;
def.geo = (*it)->clone();
Geoms.push_back(def);
@@ -1909,6 +1908,7 @@ int Sketch::checkGeoId(int geoId) const
geoId += Geoms.size(); // convert negative external-geometry index to index into Geoms
}
if (!(geoId >= 0 && geoId < int(Geoms.size()))) {
Base::Console().warning("geoId %d Geoms.size %d\n", geoId, int(Geoms.size()));
throw Base::IndexError("Sketch::checkGeoId. GeoId index out range.");
}
return geoId;
@@ -5665,18 +5665,20 @@ void Sketch::applyGroupTransformations()
T2[2][3] = postSolveFrame.startPoint.z;
// 5. Combine the matrices in the correct order: T_final = T2 * R * S * T1
// The * operator is overloaded for matrix multiplication.
Base::Matrix4D transform = T2 * R * S * T1;
// --- Loop through slave elements and apply the transform ---
// --- Loop through grouped elements and apply the transform ---
for (int i = 1; c->hasElement(i); ++i) {
int slaveGeoId = c->getGeoId(i);
int groupedGeoId = c->getGeoId(i);
if (groupedGeoId == GeoEnum::GeoUndef) {
continue;
}
// Get the slave's current (pre-solve) state
Part::Geometry* slaveGeo = Geoms[checkGeoId(slaveGeoId)].geo;
Part::Geometry* groupedGeo = Geoms[checkGeoId(groupedGeoId)].geo;
// Apply the calculated transformation
slaveGeo->transform(transform);
groupedGeo->transform(transform);
}
}
+1 -1
View File
@@ -91,7 +91,7 @@ public:
int addGeometry(
const std::vector<Part::Geometry*>& geos,
const std::vector<bool>& blockedGeometry,
const std::set<int>& slaveGeoIds
const std::set<int>& inGroupGeoIds
);
/// get boolean list indicating whether the geometry is to be blocked or not
void getBlockedGeometry(
+60 -32
View File
@@ -906,7 +906,7 @@ double SketchObject::getDatum(int ConstrId) const
return this->Constraints[ConstrId]->getValue();
}
int SketchObject::setTextAndFont(int ConstrId, std::string& newText, std::string& newFont)
int SketchObject::setTextAndFont(int ConstrId, std::string& newText, std::string& newFont, bool isConstruction)
{
; // no need to check input data validity as this is an sketchobject managed operation.
Base::StateLocker lock(managedoperation, true);
@@ -921,32 +921,39 @@ int SketchObject::setTextAndFont(int ConstrId, std::string& newText, std::string
}
auto* constr = vals[ConstrId];
if (constr->Type != Text || !constr->hasElement(1)) {
if (constr->Type != Text || !constr->hasElement(0)) {
return -1;
}
// First we replace the old geometries by the new text.
const bool isHeight = constr->isTextHeight;
const std::string oldText = constr->Text;
const std::string oldFont = constr->Font;
const bool isHeight = constr->getIsTextHeight();
const std::string oldText = constr->getText();
const std::string oldFont = constr->getFont();
int handleGeoId = constr->getGeoId(0);
int firstTextGeoId = constr->getGeoId(1);
bool hasExistingText = firstTextGeoId != GeoEnum::GeoUndef;
bool handleLast = handleGeoId > firstTextGeoId;
// Check if text is construction or normal geos
auto* geo1 = getGeometry(firstTextGeoId);
bool isConstruction = GeometryFacade::getConstruction(geo1);
if (hasExistingText) {
// Check if text is construction or normal geos
auto* geo1 = getGeometry(firstTextGeoId);
isConstruction = GeometryFacade::getConstruction(geo1);
// Delete all the old text geos. Not the handle!
std::vector<int> geoIdsToDelete;
for (int i = 1; constr->hasElement(i); ++i) {
geoIdsToDelete.push_back(constr->getGeoId(i));
if (handleLast) {
--handleGeoId; // handle line is added after all text geos.
// Delete all the old text geos. Not the handle!
std::vector<int> geoIdsToDelete;
for (int i = 1; constr->hasElement(i); ++i) {
if (constr->getGeoId(i) == GeoEnum::GeoUndef) {
continue;
}
geoIdsToDelete.push_back(constr->getGeoId(i));
if (handleLast) {
--handleGeoId; // handle line is added after all text geos.
}
}
delGeometries(geoIdsToDelete);
}
delGeometries(geoIdsToDelete);
auto* line = dynamic_cast<const Part::GeomLineSegment*>(getGeometry(handleGeoId));
if (!line) {
return -1;
@@ -960,11 +967,6 @@ int SketchObject::setTextAndFont(int ConstrId, std::string& newText, std::string
line->getStartPoint(),
line->getEndPoint(),
isHeight);
if (isConstruction) {
for (size_t i = 0; i < newGeos.size(); ++i) {
Sketcher::GeometryFacade::setConstruction(newGeos[i].get(), isConstruction);
}
}
// Add the geometries to sketch
int lastGeoid = getHighestCurveIndex();
@@ -984,26 +986,32 @@ int SketchObject::setTextAndFont(int ConstrId, std::string& newText, std::string
newGeos.clear();
addGeometry(newGeosRawPtrs);
// Create a new constraint to replace the one that was deleted.
int newLastGeoid = getHighestCurveIndex();
constr = new Constraint();
constr->Type = Text;
constr->truncateElements(0); // remove the First/Second/Third that are created automatically
constr->addElement(GeoElementId(handleGeoId));
// If there was text geos, they were deleted, which deleted the text constraint.
// In this case create a new constraint to replace it.
if (hasExistingText) {
constr = new Constraint();
constr->Type = Text;
constr->truncateElements(0); // remove the First/Second/Third that are created automatically
constr->addElement(GeoElementId(handleGeoId));
}
for (int i = lastGeoid + 1; i <= newLastGeoid; ++i) {
constr->addElement(GeoElementId(i));
}
constr->Text = newText;
constr->Font = newFont;
constr->isTextHeight = isHeight;
constr->setText(newText);
constr->setFont(newFont);
constr->setIsTextHeight(isHeight);
addConstraint(constr);
if (hasExistingText) {
addConstraint(constr);
}
int err = solve();
if (err) {
constr->Text = oldText;
constr->Font = oldFont;
constr->setText(oldText);
constr->setFont(oldFont);
}
return err;
@@ -1109,6 +1117,26 @@ int SketchObject::getActive(int ConstrId, bool& isactive)
return 0;
}
bool SketchObject::isConstraintActiveInSketch(const Sketcher::Constraint* cstr) const
{
// If the constraint is deactivated then it's over
if (!cstr || !cstr->isActive) {
return false;
}
if (cstr->Type == Group || cstr->Type == Text) {
return true;
}
// If the constraint is not deactivated, it could still constraint something in a group
for (int j = 0; cstr->hasElement(j); ++j) {
if (isInGroup(cstr->getGeoId(j), false)) {
return false;
}
}
return true;
}
int SketchObject::toggleActive(int ConstrId)
{
// no need to check input data validity as this is an sketchobject managed operation.
@@ -10215,10 +10243,10 @@ bool SketchObject::evaluateConstraint(const Constraint* constraint) const
case Equal:
case PointOnObject:
case Angle:
case Text:
break;
case Tangent:
case Group:
case Text:
requireSecond = true;
break;
case Symmetric:
+8 -1
View File
@@ -354,7 +354,12 @@ public:
/// get the datum of a Distance or Angle constraint
double getDatum(int ConstrId) const;
/// set the text and font of a text constraint
int setTextAndFont(int ConstrId, std::string& newText, std::string& newFont);
int setTextAndFont(
int ConstrId,
std::string& newText,
std::string& newFont,
bool isConstruction = false
);
/// set the driving status of this constraint and solve
int setDriving(int ConstrId, bool isdriving);
/// get the driving status of this constraint
@@ -369,6 +374,8 @@ public:
int setActive(int ConstrId, bool isactive);
/// get the driving status of this constraint
int getActive(int ConstrId, bool& isactive);
// Return true if the constraint is active, includes checking if it's not in a group
bool isConstraintActiveInSketch(const Sketcher::Constraint* cstr) const;
/// toggle the driving status of this constraint
int toggleActive(int ConstrId);
+6 -4
View File
@@ -762,17 +762,19 @@ PyObject* SketchObjectPy::setTextAndFont(PyObject* args, PyObject* kwd)
char* textStr;
char* fontStr;
char* constrName = nullptr;
PyObject* isConstrObj = Py_False; // Default to null (parameter not provided)
// Try to parse (int, str, str)
if (PyArg_ParseTuple(args, "iss", &constrIndex, &textStr, &fontStr)) {
// This format is valid, proceed.
// "iss|O" means: int, string, string, | optional Object
if (!PyArg_ParseTuple(args, "iss|O!", &constrIndex, &textStr, &fontStr, &PyBool_Type, &isConstrObj)) {
return nullptr;
}
std::string text(textStr);
std::string font(fontStr);
// Call the C++ implementation
int err = this->getSketchObjectPtr()->setTextAndFont(constrIndex, text, font);
int err = this->getSketchObjectPtr()
->setTextAndFont(constrIndex, text, font, Base::asBoolean(isConstrObj));
// Handle errors returned from the C++ function
if (err) {
+1 -3
View File
@@ -10535,7 +10535,6 @@ void CmdSketcherConstrainGroup::activated(int iMsg)
getSelection().clearSelection();
}
namespace {
/**
* @brief Escapes a string for safe embedding within a single-quoted Python string literal.
*
@@ -10544,7 +10543,7 @@ namespace {
* @param input The raw string to escape.
* @return A new string with special characters escaped.
*/
std::string escapeForPython(const std::string& input)
std::string SketcherGui::escapeForPython(const std::string& input)
{
std::string result;
// Pre-allocating can be a small optimization if strings are long
@@ -10561,7 +10560,6 @@ std::string escapeForPython(const std::string& input)
}
return result;
}
} // anonymous namespace
bool SketcherGui::addListConstraint(Sketcher::SketchObject* Obj,
std::vector<Sketcher::GeoElementId>& elts,
+1 -2
View File
@@ -137,7 +137,7 @@ void doEndpointToEdgeTangency(
/// notifications
void notifyConstraintSubstitutions(const QString& message);
std::string escapeForPython(const std::string& input);
bool addListConstraint(
Sketcher::SketchObject* Obj,
std::vector<Sketcher::GeoElementId>& elts,
@@ -148,5 +148,4 @@ bool addListConstraint(
const std::string& text = "",
const std::string& font = ""
);
} // namespace SketcherGui
+14 -14
View File
@@ -54,20 +54,20 @@ enum class FilterValue
Equality = 9,
Symmetric = 10,
Block = 11,
Group = 12,
Text = 13,
InternalAlignment = 14,
Datums = 15,
HorizontalDistance = 16,
VerticalDistance = 17,
Distance = 18,
Radius = 19,
Weight = 20,
Diameter = 21,
Angle = 22,
SnellsLaw = 23,
Named = 24,
NonDriving = 25,
InternalAlignment = 12,
Datums = 13,
HorizontalDistance = 14,
VerticalDistance = 15,
Distance = 16,
Radius = 17,
Weight = 18,
Diameter = 19,
Angle = 20,
SnellsLaw = 21,
Named = 22,
NonDriving = 23,
Group = 24,
Text = 25,
NumFilterValue // SpecialFilterValue shall start at the same index as this
};
+40 -24
View File
@@ -128,29 +128,53 @@ private:
void executeCommands() override
{
try {
int firstCurve = getHighestCurveIndex() + 1;
createShape(false);
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Add sketch Text"));
commandAddShapeGeometryAndConstraints();
// Add the Handle Line
Gui::cmdAppObjectArgs(
getSketchObject(),
"addGeometry(Part.LineSegment(App.Vector(%f, %f,0), App.Vector(%f, %f,0)), True)",
startPoint.x,
startPoint.y,
endPoint.x,
endPoint.y
);
handleId = getHighestCurveIndex();
handleId = getHighestCurveIndex() + 1; // line is not added yet
std::vector<Sketcher::GeoElementId> elts;
for (int i = firstCurve; i < handleId; ++i) {
elts.push_back(GeoElementId(i));
}
std::string escText = escapeForPython(text);
std::string escFont = escapeForPython(font);
bool isHeight = constructionMethod() == ConstructionMethod::Height;
if (!addListConstraint(getSketchObject(), elts, "Text", startPoint, endPoint, isHeight, text, font)) {
Gui::Command::abortCommand();
return;
}
const char* constrBoolStr = isConstructionMode() ? "True" : "False";
// Add the 'Text' Constraint (Empty)
// We initialize the constraint containing ONLY the handle (element 0).
// We do not add the text geometry manually to avoid floating-point precision loss
// associated with Python serialization.
Gui::cmdAppObjectArgs(
getSketchObject(),
"addConstraint(Sketcher.Constraint('Text', [%d, 0], '%s', '%s', %s))",
handleId,
escText.c_str(),
escFont.c_str(),
isHeight ? "True" : "False"
);
// Generate Text Geometry by calling setTextAndFont on the new constraint.
// This triggers the C++ logic to generate the exact geometry and insert it
// into the sketch, ensuring closed wires and perfect precision.
Gui::cmdAppObjectArgs(
getSketchObject(),
"setTextAndFont(len(App.ActiveDocument.getObject('%s').Constraints)-1, '%s', '%s', "
"%s)",
getSketchObject()->getNameInDocument(),
escText.c_str(),
escFont.c_str(),
constrBoolStr
);
Gui::Command::commitCommand();
}
catch (const Base::Exception&) {
catch (const Base::Exception& e) {
Gui::NotifyError(
sketchgui,
QT_TRANSLATE_NOOP("Notifications", "Error"),
@@ -158,14 +182,6 @@ private:
);
Gui::Command::abortCommand();
THROWM(
Base::RuntimeError,
QT_TRANSLATE_NOOP(
"Notifications",
"Tool execution aborted"
) "\n"
) // This prevents constraints from being
// applied on non existing geometry
}
}
@@ -1879,12 +1879,16 @@ void EditModeConstraintCoinManager::updateConstraintColor(
}
}
else {
bool isActive = ViewProviderSketchCoinAttorney::isConstraintActiveInSketch(
viewProvider,
constraint
);
if (hasDatumLabel) {
SoDatumLabel* l = static_cast<SoDatumLabel*>(
s->getChild(static_cast<int>(ConstraintNodePosition::DatumLabelIndex))
);
l->textColor = constraint->isActive
l->textColor = isActive
? ViewProviderSketchCoinAttorney::constraintHasExpression(viewProvider, i)
? drawingParameters.ExprBasedConstrDimColor
: (constraint->isDriving ? drawingParameters.ConstrDimColor
@@ -1892,7 +1896,7 @@ void EditModeConstraintCoinManager::updateConstraintColor(
: drawingParameters.DeactivatedConstrDimColor;
}
else if (hasMaterial) {
m->diffuseColor = constraint->isActive
m->diffuseColor = isActive
? (constraint->isDriving ? drawingParameters.ConstrDimColor
: drawingParameters.NonDrivingConstrDimColor)
: drawingParameters.DeactivatedConstrDimColor;
@@ -1968,7 +1972,8 @@ void EditModeConstraintCoinManager::rebuildConstraintNodes(
// every constrained visual node gets its own material for preselection and selection
SoMaterial* mat = new SoMaterial;
mat->ref();
mat->diffuseColor = (*it)->isActive
bool isActive = ViewProviderSketchCoinAttorney::isConstraintActiveInSketch(viewProvider, *it);
mat->diffuseColor = isActive
? ((*it)->isDriving ? drawingParameters.ConstrDimColor
: drawingParameters.NonDrivingConstrDimColor)
: drawingParameters.DeactivatedConstrDimColor;
@@ -1986,7 +1991,7 @@ void EditModeConstraintCoinManager::rebuildConstraintNodes(
SoDatumLabel* text = new SoDatumLabel();
text->norm.setValue(norm);
text->string = "";
text->textColor = (*it)->isActive
text->textColor = isActive
? ((*it)->isDriving ? drawingParameters.ConstrDimColor
: drawingParameters.NonDrivingConstrDimColor)
: drawingParameters.DeactivatedConstrDimColor;
@@ -2970,6 +2975,10 @@ QColor EditModeConstraintCoinManager::constrColor(int constraintId)
};
const auto constraints = ViewProviderSketchCoinAttorney::getConstraints(viewProvider);
bool isActive = ViewProviderSketchCoinAttorney::isConstraintActiveInSketch(
viewProvider,
constraints[constraintId]
);
if (ViewProviderSketchCoinAttorney::isConstraintPreselected(viewProvider, constraintId)) {
return toQColor(drawingParameters.PreselectColor);
@@ -2977,7 +2986,7 @@ QColor EditModeConstraintCoinManager::constrColor(int constraintId)
else if (ViewProviderSketchCoinAttorney::isConstraintSelected(viewProvider, constraintId)) {
return toQColor(drawingParameters.SelectColor);
}
else if (!constraints[constraintId]->isActive) {
else if (!isActive) {
return toQColor(drawingParameters.DeactivatedConstrDimColor);
}
else if (!constraints[constraintId]->isDriving) {
+5 -3
View File
@@ -45,15 +45,17 @@ EditTextDialog::EditTextDialog(ViewProviderSketch* viewProvider, int constraintI
{
ui->setupUi(this);
ui->comboBox_font->setMaxVisibleItems(20);
const Sketcher::SketchObject* sketch = sketchView->getSketchObject();
const Sketcher::Constraint* constraint = sketch->Constraints[constrIndex];
// Initialize Text
ui->lineEdit_text->setText(QString::fromStdString(constraint->Text));
ui->lineEdit_text->setText(QString::fromStdString(constraint->getText()));
// Initialize Font
populateFontList();
QString currentFontName = findFontNameFromPath(QString::fromStdString(constraint->Font));
QString currentFontName = findFontNameFromPath(QString::fromStdString(constraint->getFont()));
if (!currentFontName.isEmpty()) {
ui->comboBox_font->setCurrentText(currentFontName);
}
@@ -89,7 +91,7 @@ void EditTextDialog::on_buttonBox_accepted()
const Sketcher::Constraint* constraint = sketch->Constraints[constrIndex];
// Check if anything changed
if (newText == constraint->Text && newFontPath == constraint->Font) {
if (newText == constraint->getText() && newFontPath == constraint->getFont()) {
return; // Nothing to do
}
@@ -93,6 +93,8 @@
<file>icons/elements/Sketcher_Element_Line_Edge.svg</file>
<file>icons/elements/Sketcher_Element_Line_EndPoint.svg</file>
<file>icons/elements/Sketcher_Element_Line_StartingPoint.svg</file>
<file>icons/elements/Sketcher_Element_Text_EndPoint.svg</file>
<file>icons/elements/Sketcher_Element_Text_StartPoint.svg</file>
<file>icons/elements/Sketcher_Element_Parabolic_Arc_Centre_Point.svg</file>
<file>icons/elements/Sketcher_Element_Parabolic_Arc_Edge.svg</file>
<file>icons/elements/Sketcher_Element_Parabolic_Arc_End_Point.svg</file>
@@ -6,8 +6,8 @@
height="64px"
id="svg2816"
version="1.1"
sodipodi:docname="Sketcher_ToggleConstraint.svg"
inkscape:version="1.4 (86a8ad7, 2024-10-11)"
sodipodi:docname="Constraint_Group.svg"
inkscape:version="1.4.2 (f4327f4, 2025-05-13)"
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"
@@ -25,9 +25,9 @@
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="14.948679"
inkscape:cx="39.836295"
inkscape:cy="23.11241"
inkscape:zoom="2.6425781"
inkscape:cx="79.467851"
inkscape:cy="69.818183"
inkscape:window-width="3840"
inkscape:window-height="1571"
inkscape:window-x="-9"
@@ -419,25 +419,111 @@
</cc:Work>
</rdf:RDF>
</metadata>
<rect
y="11.795785"
x="11.795785"
height="40.408428"
width="40.408428"
id="rect3107"
style="fill:none;stroke:#280000;stroke-width:8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.5;stroke-dasharray:none;stroke-opacity:1" />
<rect
y="11.795785"
x="11.795785"
height="40.408428"
width="40.408428"
id="rect3107-3"
style="fill:none;stroke:#cc0000;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.5;stroke-dasharray:none;stroke-opacity:1" />
<rect
y="10.448837"
x="10.448837"
height="43.102325"
width="43.102325"
id="rect3107-6"
style="fill:none;stroke:#ef2929;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.5;stroke-dasharray:none;stroke-opacity:1" />
<g
id="g6"
transform="translate(-4.2813147,13.579795)">
<path
style="baseline-shift:baseline;display:inline;overflow:visible;fill:#cc0000;fill-opacity:1;stroke:#280000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;enable-background:accumulate;stop-color:#000000"
d="M 10.691188,-10.079592 A 2.7002703,2.7002703 0 0 0 7.990017,-7.3784198 V 4.1625958 a 2.7000003,2.7000003 0 0 0 2.701171,2.6992188 2.7000003,2.7000003 0 0 0 2.699219,-2.6992188 v -8.8417969 h 8.179688 a 2.7000003,2.7000003 0 0 0 2.699218,-2.6992187 2.7000003,2.7000003 0 0 0 -2.699218,-2.7011722 z"
id="path5" />
<path
style="fill:none;fill-opacity:1;stroke:#ef2929;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="M 9.8336448,4.6826881 V -8.2281518 H 22.108977"
id="path6" />
</g>
<g
id="g6-8"
transform="rotate(90,27.48765,22.71893)">
<path
style="baseline-shift:baseline;display:inline;overflow:visible;fill:#cc0000;fill-opacity:1;stroke:#280000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;enable-background:accumulate;stop-color:#000000"
d="M 10.691188,-10.079592 A 2.7002703,2.7002703 0 0 0 7.990017,-7.3784198 V 4.1625958 a 2.7000003,2.7000003 0 0 0 2.701171,2.6992188 2.7000003,2.7000003 0 0 0 2.699219,-2.6992188 v -8.8417969 h 8.179688 a 2.7000003,2.7000003 0 0 0 2.699218,-2.6992187 2.7000003,2.7000003 0 0 0 -2.699218,-2.7011722 z"
id="path5-8" />
<path
style="fill:none;fill-opacity:1;stroke:#ef2929;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="M 9.8336448,4.6826881 V -8.2281518 H 22.108977"
id="path6-2" />
</g>
<g
id="g6-8-5"
transform="rotate(180,34.21529,25.143605)">
<path
style="baseline-shift:baseline;display:inline;overflow:visible;fill:#cc0000;fill-opacity:1;stroke:#280000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;enable-background:accumulate;stop-color:#000000"
d="M 10.691188,-10.079592 A 2.7002703,2.7002703 0 0 0 7.990017,-7.3784198 V 4.1625958 a 2.7000003,2.7000003 0 0 0 2.701171,2.6992188 2.7000003,2.7000003 0 0 0 2.699219,-2.6992188 v -8.8417969 h 8.179688 a 2.7000003,2.7000003 0 0 0 2.699218,-2.6992187 2.7000003,2.7000003 0 0 0 -2.699218,-2.7011722 z"
id="path5-8-1" />
<path
style="fill:none;fill-opacity:1;stroke:#ef2929;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="M 9.8336448,4.6826881 V -8.2281518 H 22.108977"
id="path6-2-7" />
</g>
<g
id="g6-8-52"
transform="rotate(-90,40.965184,27.49795)">
<path
style="baseline-shift:baseline;display:inline;overflow:visible;fill:#cc0000;fill-opacity:1;stroke:#280000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;enable-background:accumulate;stop-color:#000000"
d="M 10.691188,-10.079592 A 2.7002703,2.7002703 0 0 0 7.990017,-7.3784198 V 4.1625958 a 2.7000003,2.7000003 0 0 0 2.701171,2.6992188 2.7000003,2.7000003 0 0 0 2.699219,-2.6992188 v -8.8417969 h 8.179688 a 2.7000003,2.7000003 0 0 0 2.699218,-2.6992187 2.7000003,2.7000003 0 0 0 -2.699218,-2.7011722 z"
id="path5-8-7" />
<path
style="fill:none;fill-opacity:1;stroke:#ef2929;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="M 9.8336448,4.6826881 V -8.2281518 H 22.108977"
id="path6-2-6" />
</g>
<g
id="g1942"
transform="matrix(0.56082348,0.00382887,-0.00382887,0.56082348,-30.824178,24.889141)">
<g
id="g1639">
<path
style="fill:none;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
d="m 85.705652,39.254404 36.510728,0.03213 -0.0643,-36.0755714"
id="path3042" />
<g
id="g5444"
transform="matrix(0.12582856,0,0,0.13656888,-116.075,-78.506633)">
<rect
style="fill:none;fill-opacity:1;stroke:#2e3436;stroke-width:61.1235;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect3579"
width="320.34793"
height="290.3475"
x="1581.9229"
y="577.53864"
ry="72.587051" />
<rect
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:15.2809;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect3579-9-4"
width="334.35117"
height="306.85471"
x="1574.9211"
y="569.28497"
ry="76.713875" />
<rect
style="fill:none;fill-opacity:1;stroke:#d3d7cf;stroke-width:15.2809;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect3579-9"
width="308.51923"
height="283.05432"
x="1587.837"
y="581.18518"
ry="70.763763" />
</g>
</g>
<g
id="g1893"
transform="matrix(0.92702216,0,0,0.92702216,60.747574,-46.780667)">
<path
style="fill:none;stroke:#2e3436;stroke-width:7.99999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.9;stroke-dasharray:none;stroke-opacity:1"
id="path3064"
d="m 87.99875,70.15496 -24,12.819254 L 40.058512,69.793468 40.118273,43.793467 64.118272,30.974213 88.058511,44.15496 Z" />
<path
style="fill:none;stroke:#d3d7cf;stroke-width:4.00001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.9;stroke-dasharray:none;stroke-opacity:1"
id="path3064-3"
d="m 87.99875,70.15496 -24,12.819254 L 40.058512,69.793468 40.118273,43.793467 64.118272,30.974213 88.058511,44.15496 Z" />
<path
style="fill:none;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.9;stroke-opacity:1"
d="m 39.058511,70.286516 0.06225,-27 25,-13.312301 24.93775,13.687698"
id="path3064-3-6" />
<path
style="fill:none;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.9;stroke-opacity:1"
d="m 87.058511,44.648008 -0.05727,25 -23,12.326206 -22.94273,-12.673794"
id="path3064-3-6-7" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 18 KiB

@@ -7,12 +7,34 @@
id="svg2869"
version="1.1"
viewBox="0 0 64 64"
sodipodi:docname="Constraint_Text.svg"
inkscape:version="1.4.2 (f4327f4, 2025-05-13)"
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="namedview1"
pagecolor="#50505000"
bordercolor="#eeeeeeff"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#505050ff"
inkscape:zoom="5.2851563"
inkscape:cx="12.487805"
inkscape:cy="43.612712"
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
@@ -187,6 +209,26 @@
offset="1"
style="stop-color:#a40000;stop-opacity:1" />
</linearGradient>
<linearGradient
gradientTransform="matrix(0.1649204,0,0,0.1649204,-632.71718,-223.01448)"
y2="1734.2576"
x2="4157.8677"
y1="1473.5258"
x1="4115.4229"
gradientUnits="userSpaceOnUse"
id="linearGradient3009-2"
xlink:href="#linearGradient3010-2" />
<linearGradient
id="linearGradient3010-2">
<stop
id="stop3012-1"
offset="0"
style="stop-color:#d3d7cf;stop-opacity:1;" />
<stop
id="stop3014-6"
offset="1"
style="stop-color:#d3d7cf;stop-opacity:1;" />
</linearGradient>
</defs>
<metadata
id="metadata2874">
@@ -218,76 +260,71 @@
</rdf:RDF>
</metadata>
<g
id="layer4">
id="g2"
transform="translate(-2.1206965,1.6845105)">
<g
id="g1"
style="display:inline"
transform="translate(-44,13)">
id="g6"
transform="translate(-2.0747215,12.048077)">
<path
style="fill:none;stroke:#151819;stroke-width:8;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
d="M 10,32 H 32"
id="path1" />
style="baseline-shift:baseline;display:inline;overflow:visible;fill:#cc0000;fill-opacity:1;stroke:#280000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;enable-background:accumulate;stop-color:#000000"
d="M 10.691188,-10.079592 A 2.7002703,2.7002703 0 0 0 7.990017,-7.3784198 V 4.1625958 a 2.7000003,2.7000003 0 0 0 2.701171,2.6992188 2.7000003,2.7000003 0 0 0 2.699219,-2.6992188 v -8.8417969 h 8.179688 a 2.7000003,2.7000003 0 0 0 2.699218,-2.6992187 2.7000003,2.7000003 0 0 0 -2.699218,-2.7011722 z"
id="path5" />
<path
style="display:inline;fill:none;stroke:#d3d7cf;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;paint-order:markers fill stroke"
d="M 10,32 H 32"
id="path1-7" />
<path
style="display:inline;fill:none;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
d="M 10,31 H 32"
id="path1-7-0" />
style="fill:none;fill-opacity:1;stroke:#ef2929;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="M 9.8336448,4.6826881 V -8.2281518 H 22.108977"
id="path6-23" />
</g>
<g
id="g8"
style="display:inline"
transform="translate(-44,27)">
id="g6-8"
transform="rotate(90,29.356805,23.056368)">
<path
style="fill:none;stroke:#091425;stroke-width:8;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
d="M 10,32 H 32"
id="path6" />
style="baseline-shift:baseline;display:inline;overflow:visible;fill:#cc0000;fill-opacity:1;stroke:#280000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;enable-background:accumulate;stop-color:#000000"
d="M 10.691188,-10.079592 A 2.7002703,2.7002703 0 0 0 7.990017,-7.3784198 V 4.1625958 a 2.7000003,2.7000003 0 0 0 2.701171,2.6992188 2.7000003,2.7000003 0 0 0 2.699219,-2.6992188 v -8.8417969 h 8.179688 a 2.7000003,2.7000003 0 0 0 2.699218,-2.6992187 2.7000003,2.7000003 0 0 0 -2.699218,-2.7011722 z"
id="path5-8" />
<path
style="display:inline;fill:none;stroke:#3465a4;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;paint-order:markers fill stroke"
d="M 10,32 H 32"
id="path7" />
<path
style="display:inline;fill:none;stroke:#729fcf;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
d="M 10,31 H 32"
id="path8" />
style="fill:none;fill-opacity:1;stroke:#ef2929;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="M 9.8336448,4.6826881 V -8.2281518 H 22.108977"
id="path6-2" />
</g>
<g
transform="matrix(0.77869459,0,0,0.77869445,3.548264,36.597628)"
id="g3797-9-5-5"
style="stroke-width:1.2842">
id="g6-8-5"
transform="rotate(180,35.318587,24.377746)">
<path
style="fill:none;stroke:#2e0000;stroke-width:2.56841;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path4250-71-6-6"
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" />
style="baseline-shift:baseline;display:inline;overflow:visible;fill:#cc0000;fill-opacity:1;stroke:#280000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;enable-background:accumulate;stop-color:#000000"
d="M 10.691188,-10.079592 A 2.7002703,2.7002703 0 0 0 7.990017,-7.3784198 V 4.1625958 a 2.7000003,2.7000003 0 0 0 2.701171,2.6992188 2.7000003,2.7000003 0 0 0 2.699219,-2.6992188 v -8.8417969 h 8.179688 a 2.7000003,2.7000003 0 0 0 2.699218,-2.6992187 2.7000003,2.7000003 0 0 0 -2.699218,-2.7011722 z"
id="path5-8-1" />
<path
style="fill:url(#linearGradient9);fill-opacity:1;stroke:#ef2929;stroke-width:2.56842;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path4250-7-3-2-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" />
style="fill:none;fill-opacity:1;stroke:#ef2929;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="M 9.8336448,4.6826881 V -8.2281518 H 22.108977"
id="path6-2-7" />
</g>
<g
id="g6-8-52"
transform="rotate(-90,41.302622,25.628794)">
<path
style="baseline-shift:baseline;display:inline;overflow:visible;fill:#cc0000;fill-opacity:1;stroke:#280000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;enable-background:accumulate;stop-color:#000000"
d="M 10.691188,-10.079592 A 2.7002703,2.7002703 0 0 0 7.990017,-7.3784198 V 4.1625958 a 2.7000003,2.7000003 0 0 0 2.701171,2.6992188 2.7000003,2.7000003 0 0 0 2.699219,-2.6992188 v -8.8417969 h 8.179688 a 2.7000003,2.7000003 0 0 0 2.699218,-2.6992187 2.7000003,2.7000003 0 0 0 -2.699218,-2.7011722 z"
id="path5-8-7" />
<path
style="fill:none;fill-opacity:1;stroke:#ef2929;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="M 9.8336448,4.6826881 V -8.2281518 H 22.108977"
id="path6-2-6" />
</g>
</g>
<g
id="layer3"
style="display:inline">
<g
id="layer1">
<g
id="g3491"
transform="matrix(0.1649204,0,0,0.1649204,-643.71716,-232.01446)">
<path
id="text2714"
d="m 4163.931,1667.5588 h -109.1436 l -33.4751,40.7475 c -3.5156,5.2084 -2.3852,4.766 -2.9061,7.7608 0,6.0635 3.9239,9.9135 12.1271,12.127 v 12.1271 h -97.0165 v -12.1271 c 5.4688,-1.0416 14.9354,-3.4593 18.1906,-6.0635 3.2552,-2.6042 6.0635,-6.0635 12.1271,-12.1271 l 139.4611,-200.0965 c 4.4269,-6.5102 5.2821,-8.2206 6.0636,-12.1271 1.3019,-5.9893 0.9676,-9.5226 -6.0636,-12.127 v -12.1271 h 97.0165 v 12.1271 c -12.127,0 -17.1492,0.595 -18.1906,6.0635 -0.7814,3.7763 -0.6531,6.3037 0.9097,11.1211 l 60.3514,205.4688 c 2.6039,8.724 2.8333,10.5692 5.4378,13.8243 2.6038,3.1251 6.9183,5.0219 12.1271,6.0635 v 12.1271 h -97.0165 v -12.1271 c 8.984,-1.4322 10.8247,-5.4864 12.127,-12.127 0.5207,-2.7344 1.5623,-6.7885 0,-12.1271 l -12.127,-36.3812 m 0,-36.3812 -24.2542,-97.0165 -72.7623,97.0165 h 97.0165"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:40px;font-family:'Copperplate Gothic Bold';-inkscape-font-specification:'Copperplate Gothic Bold, Bold';fill:url(#linearGradient3009);fill-opacity:1;stroke:#2e0000;stroke-width:12.1271;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
id="text2714-1"
d="m 4171.6736,1655.4317 h -122.0514 l -36.1634,43.7572 c -8.9781,11.6058 -6.5744,17.6706 -7.5981,18.9453 0,5.6501 9.2106,8.5485 16.6543,10.6111 l 1.2403,-0.1379 -78.1114,-0.4134 -3.7208,2.894 c 4.9624,-0.9706 23.3368,-5.4284 26.2906,-7.855 2.9538,-2.4267 7.4313,-8.4063 12.2445,-15.4346 l 117.1771,-168.125 c 4.017,-6.0664 15.8176,-22.4055 19.0072,-28.5262 3.3863,-5.5809 9.1466,-22.5163 2.7664,-24.9431 l -10.1979,-0.5513 h 85.1396 l -13.0918,-0.6889 c -11.004,0 -10.7379,5.2398 -11.5452,9.233 -0.7089,3.5189 0.6477,7.8032 2.0659,12.2922 l 55.59,189.1168 c 2.3628,8.1291 2.4331,9.7107 3.832,14.9489 3.6029,9.9401 1.3166,12.3967 6.043,13.3673 l 17.6394,4.272 h -84.8894 l 12.5404,-6.2013 c 4.9827,-8.914 5.1626,-6.4905 6.3444,-12.6783 0.4724,-2.548 -2.579,-12.6647 -3.9966,-17.6393 l -12.9335,-35.4166 m 4.4614,-18.4109 -33.3601,-122.5662 -89.8152,122.4284 122.0295,0.024"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:40px;font-family:'Copperplate Gothic Bold';-inkscape-font-specification:'Copperplate Gothic Bold, Bold';fill:none;stroke:#ef2929;stroke-width:12.1271;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
id="text2714-7"
d="m 4163.931,1667.5588 h -109.1436 l -33.4751,40.7475 c -3.5156,5.2084 -2.3852,4.766 -2.9061,7.7608 0,6.0635 3.9239,9.9135 12.1271,12.127 v 12.1271 h -97.0165 v -12.1271 c 5.4688,-1.0416 14.9354,-3.4593 18.1906,-6.0635 3.2552,-2.6042 6.0635,-6.0635 12.1271,-12.1271 l 139.4611,-200.0965 c 4.4269,-6.5102 5.2821,-8.2206 6.0636,-12.1271 1.3019,-5.9893 0.9676,-9.5226 -6.0636,-12.127 v -12.1271 h 97.0165 v 12.1271 c -12.127,0 -17.1492,0.595 -18.1906,6.0635 -0.7814,3.7763 -0.6531,6.3037 0.9097,11.1211 l 60.3514,205.4688 c 2.6039,8.724 2.8333,10.5692 5.4378,13.8243 2.6038,3.1251 6.9183,5.0219 12.1271,6.0635 v 12.1271 h -97.0165 v -12.1271 c 8.984,-1.4322 10.8247,-5.4864 12.127,-12.127 0.5206,-2.7344 1.5623,-6.7885 0,-12.1271 l -12.127,-36.3812 m 0,-36.3812 -24.2542,-97.0165 -72.7623,97.0165 h 97.0165"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:40px;font-family:'Copperplate Gothic Bold';-inkscape-font-specification:'Copperplate Gothic Bold, Bold';fill:none;stroke:#280000;stroke-width:12.1271;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</g>
id="g3"
transform="matrix(0.67985712,0,0,0.67985712,3.8942753,5.1844051)">
<path
id="text2714"
d="M 52.000007,50.000005 H 34.000001 l -5.520727,6.720094 c -0.579794,0.858972 -0.393368,0.786011 -0.479275,1.279915 0,0.999994 0.647131,1.634938 2.000006,1.999989 v 2.000006 h -16 v -2.000006 c 0.901917,-0.171781 2.463152,-0.570509 3.000001,-0.999995 0.536849,-0.429485 0.999995,-0.999994 2.000006,-2.000006 L 41.999993,24.000007 c 0.730086,-1.073664 0.871126,-1.355744 1.000011,-2.000006 0.21471,-0.987758 0.159577,-1.570471 -1.000011,-1.999989 v -2.000007 h 16 v 2.000007 c -1.99999,0 -2.828253,0.09813 -3.000001,0.999994 -0.128869,0.622789 -0.10771,1.039609 0.150028,1.834097 l 9.953177,33.885996 c 0.429436,1.438766 0.467269,1.743077 0.896804,2.279909 0.42942,0.515393 1.140969,0.828214 2.000006,0.999995 v 2.000006 h -16 v -2.000006 c 1.481645,-0.236199 1.785214,-0.904819 1.99999,-1.999989 0.08587,-0.450959 0.257655,-1.119563 0,-2.000007 l -1.99999,-6.000002 m 0,-6.000002 -4.000012,-16 -11.999988,16 h 16"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:40px;font-family:'Copperplate Gothic Bold';-inkscape-font-specification:'Copperplate Gothic Bold, Bold';fill:url(#linearGradient3009-2);fill-opacity:1;stroke:#2e0000;stroke-width:2.00001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
id="text2714-1"
d="M 53.27692,47.999999 H 33.148154 l -5.964082,7.216455 c -1.480672,1.914033 -1.084253,2.914242 -1.253082,3.124467 0,0.931816 1.519016,1.409822 2.746634,1.749986 l 0.204551,-0.02274 -12.882164,-0.06818 -0.613636,0.477279 c 0.818401,-0.160071 3.848715,-0.895254 4.335857,-1.295449 0.487142,-0.400213 1.225573,-1.386371 2.019368,-2.545481 L 41.066494,28.909094 c 0.662485,-1.000473 2.608645,-3.695124 3.134675,-4.704552 0.55847,-0.920405 1.508461,-3.713398 0.456236,-4.113626 l -1.681842,-0.09092 H 57.01682 l -2.159105,-0.113615 c -1.814784,0 -1.770899,0.86415 -1.904039,1.52271 -0.116912,0.580339 0.106819,1.286907 0.340709,2.027235 l 9.167925,31.189218 c 0.389674,1.340655 0.401268,1.601493 0.631975,2.465379 0.594192,1.639325 0.217134,2.044469 0.996614,2.20454 l 2.909097,0.70454 H 53.000002 l 2.068168,-1.022721 c 0.821749,-1.4701 0.851418,-1.070415 1.046321,-2.09091 0.07791,-0.420217 -0.42533,-2.088667 -0.659121,-2.90908 l -2.132998,-5.84092 m 0.735776,-3.036333 -5.501761,-20.213667 -14.812359,20.190941 20.125154,0.004"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:40px;font-family:'Copperplate Gothic Bold';-inkscape-font-specification:'Copperplate Gothic Bold, Bold';fill:none;stroke:#ffffff;stroke-width:2.00001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
id="text2714-7"
d="M 52.000007,50.000005 H 34.000001 l -5.520727,6.720094 c -0.579794,0.858972 -0.393368,0.786011 -0.479275,1.279915 0,0.999994 0.647131,1.634938 2.000006,1.999989 v 2.000006 h -16 v -2.000006 c 0.901917,-0.171781 2.463152,-0.570509 3.000001,-0.999995 0.536849,-0.429485 0.999995,-0.999994 2.000006,-2.000006 L 41.999993,24.000007 c 0.730086,-1.073664 0.871126,-1.355744 1.000011,-2.000006 0.21471,-0.987758 0.159577,-1.570471 -1.000011,-1.999989 v -2.000007 h 16 v 2.000007 c -1.99999,0 -2.828253,0.09813 -3.000001,0.999994 -0.128869,0.622789 -0.10771,1.039609 0.150028,1.834097 l 9.953177,33.885996 c 0.429436,1.438766 0.467269,1.743077 0.896804,2.279909 0.42942,0.515393 1.140969,0.828214 2.000006,0.999995 v 2.000006 h -16 v -2.000006 c 1.481645,-0.236199 1.785214,-0.904819 1.99999,-1.999989 0.08586,-0.450959 0.257655,-1.119563 0,-2.000007 l -1.99999,-6.000002 m 0,-6.000002 -4.000012,-16 -11.999988,16 h 16"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:40px;font-family:'Copperplate Gothic Bold';-inkscape-font-specification:'Copperplate Gothic Bold, Bold';fill:none;stroke:#280000;stroke-width:2.00001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 15 KiB

@@ -0,0 +1,587 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="64"
height="64"
id="svg2869"
version="1.1"
viewBox="0 0 64 64"
sodipodi:docname="Sketcher_Element_Text_EndPoint.svg"
inkscape:version="1.4.2 (f4327f4, 2025-05-13)"
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="namedview1"
pagecolor="#50505000"
bordercolor="#eeeeeeff"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#505050ff"
inkscape:zoom="3.7371698"
inkscape:cx="88.302115"
inkscape:cy="-27.962336"
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="linearGradient34">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop33" />
<stop
style="stop-color:#d3d7cf;stop-opacity:1;"
offset="1"
id="stop34" />
</linearGradient>
<linearGradient
id="linearGradient32">
<stop
style="stop-color:#d3d7cf;stop-opacity:1;"
offset="0"
id="stop31" />
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="1"
id="stop32" />
</linearGradient>
<linearGradient
id="linearGradient17">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop16" />
<stop
style="stop-color:#ffffff;stop-opacity:0"
offset="1"
id="stop17" />
</linearGradient>
<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)" />
<radialGradient
xlink:href="#linearGradient3809"
id="radialGradient3815"
cx="225.93762"
cy="91.956673"
fx="225.93762"
fy="91.956673"
r="22"
gradientTransform="matrix(-1.4090915,3.8636359,-0.97565325,-0.35582669,437.08461,-816.22007)"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient3809">
<stop
style="stop-color:#729fcf;stop-opacity:1"
offset="0"
id="stop3811" />
<stop
style="stop-color:#204a87;stop-opacity:1"
offset="1"
id="stop3813" />
</linearGradient>
<linearGradient
y2="5"
x2="-22"
y1="18"
x1="-18"
gradientUnits="userSpaceOnUse"
id="linearGradient3444"
xlink:href="#linearGradient3836-9-3"
gradientTransform="matrix(0.90206746,0,0,0.90216902,-1.9060863,1.1084289)" />
<linearGradient
y2="5"
x2="-22"
y1="18"
x1="-18"
gradientUnits="userSpaceOnUse"
id="linearGradient3857"
xlink:href="#linearGradient3836-9-3"
gradientTransform="matrix(0.89262616,0,0,0.89258466,72.894067,1.2176306)" />
<linearGradient
y2="5"
x2="-22"
y1="18"
x1="-18"
gradientTransform="matrix(0.93724177,0,0,0.93725692,-1.2227671,0.70650014)"
gradientUnits="userSpaceOnUse"
id="linearGradient3148"
xlink:href="#linearGradient3836-9-3" />
<linearGradient
xlink:href="#linearGradient17"
id="linearGradient3898"
x1="37.429146"
y1="41.590584"
x2="24.483221"
y2="4.9104676"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient3892">
<stop
style="stop-color:#bdd2e9;stop-opacity:1;"
offset="0"
id="stop3894" />
<stop
style="stop-color:#ffffff;stop-opacity:0"
offset="1"
id="stop3896" />
</linearGradient>
<linearGradient
xlink:href="#linearGradient3892"
id="linearGradient3856"
x1="22.84341"
y1="4.8241611"
x2="30.783579"
y2="28.644661"
gradientUnits="userSpaceOnUse" />
<radialGradient
r="22"
fy="91.956673"
fx="225.93762"
cy="91.956673"
cx="225.93762"
gradientTransform="matrix(-1.7064667,4.6731721,-1.1815555,-0.43038201,776.9032,-933.08315)"
gradientUnits="userSpaceOnUse"
id="radialGradient3163"
xlink:href="#linearGradient3809" />
<linearGradient
xlink:href="#linearGradient4104"
id="linearGradient4110"
x1="-23.070524"
y1="18.383886"
x2="-24.194258"
y2="6.534451"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient4104">
<stop
style="stop-color:#d3d7cf;stop-opacity:1"
offset="0"
id="stop4106" />
<stop
style="stop-color:#ffffff;stop-opacity:1"
offset="1"
id="stop4108" />
</linearGradient>
<linearGradient
xlink:href="#linearGradient4096"
id="linearGradient4102"
x1="-24.035076"
y1="16.85112"
x2="-23.821426"
y2="7.2881389"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient4096">
<stop
style="stop-color:#ffffff;stop-opacity:1"
offset="0"
id="stop4098" />
<stop
style="stop-color:#d3d7cf;stop-opacity:1"
offset="1"
id="stop4100" />
</linearGradient>
<linearGradient
xlink:href="#linearGradient3836-9-3"
id="linearGradient4216"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.71430595,0,0,0.71426219,259.5032,71.709694)"
x1="-18"
y1="18"
x2="-22"
y2="5" />
<radialGradient
r="22"
fy="91.956673"
fx="225.93762"
cy="91.956673"
cx="225.93762"
gradientTransform="matrix(-1.7064667,4.6731721,-1.1815555,-0.43038201,776.9032,-933.08315)"
gradientUnits="userSpaceOnUse"
id="radialGradient3163-9"
xlink:href="#linearGradient3809" />
<linearGradient
xlink:href="#linearGradient4104"
id="linearGradient4347"
x1="-21.31983"
y1="18.008659"
x2="-24.907471"
y2="6.9377007"
gradientUnits="userSpaceOnUse" />
<linearGradient
xlink:href="#linearGradient4096"
id="linearGradient4339"
x1="-21.141161"
y1="17.489555"
x2="-24.733845"
y2="7.0083036"
gradientUnits="userSpaceOnUse" />
<linearGradient
y2="5"
x2="-22"
y1="18"
x1="-18"
gradientTransform="matrix(0.65313239,0,0,0.65304994,258.31758,72.40809)"
gradientUnits="userSpaceOnUse"
id="linearGradient4235-2"
xlink:href="#linearGradient3836-9-3" />
<linearGradient
xlink:href="#linearGradient3836-9-3"
id="linearGradient3801-1-3-7"
gradientUnits="userSpaceOnUse"
x1="-18"
y1="18"
x2="-22"
y2="5" />
<linearGradient
xlink:href="#linearGradient32"
id="linearGradient3901"
gradientUnits="userSpaceOnUse"
x1="30.202745"
y1="56.729507"
x2="35.013981"
y2="19.843365"
gradientTransform="matrix(0.62354045,-0.62354046,0.62354039,0.62354042,-12.205772,28.459494)" />
<linearGradient
xlink:href="#linearGradient34"
id="linearGradient3903"
gradientUnits="userSpaceOnUse"
x1="29.993565"
y1="54.846851"
x2="36.094769"
y2="20.854424"
gradientTransform="matrix(0.57365718,-0.57365723,0.57365712,0.57365719,-8.6693108,28.742734)" />
<linearGradient
y2="5"
x2="-22"
y1="18"
x1="-18"
gradientUnits="userSpaceOnUse"
id="linearGradient3922"
xlink:href="#linearGradient3836-9-3"
gradientTransform="matrix(0.85221122,0,0,0.85228409,-2.8500258,1.6945624)" />
<linearGradient
y2="5"
x2="-22"
y1="18"
x1="-18"
gradientUnits="userSpaceOnUse"
id="linearGradient3096"
xlink:href="#linearGradient3836-9-3" />
<linearGradient
xlink:href="#linearGradient3836-9-3"
id="linearGradient3801-7"
gradientUnits="userSpaceOnUse"
x1="-18"
y1="18"
x2="-22"
y2="5"
gradientTransform="translate(-90,-5.9999999)" />
<linearGradient
y2="5"
x2="-22"
y1="18"
x1="-18"
gradientUnits="userSpaceOnUse"
id="linearGradient3082-3-8"
xlink:href="#linearGradient3836-9-3" />
<linearGradient
xlink:href="#linearGradient3836-9-3"
id="linearGradient3801-1"
gradientUnits="userSpaceOnUse"
x1="-18"
y1="18"
x2="-22"
y2="5" />
<linearGradient
xlink:href="#linearGradient3836-9-3"
id="linearGradient3801-1-3-7-3"
gradientUnits="userSpaceOnUse"
x1="-18"
y1="18"
x2="-22"
y2="5" />
<linearGradient
xlink:href="#linearGradient3836-9-3"
id="linearGradient3801-1-3-7-3-0"
gradientUnits="userSpaceOnUse"
x1="-18"
y1="18"
x2="-22"
y2="5" />
<linearGradient
y2="5"
x2="-22"
y1="18"
x1="-18"
gradientUnits="userSpaceOnUse"
id="linearGradient3203"
xlink:href="#linearGradient3836-9-3" />
<linearGradient
xlink:href="#linearGradient3836-9-3"
id="linearGradient47"
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="#linearGradient3836-9-3"
id="linearGradient49"
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="#linearGradient3836-9-3"
id="linearGradient3801-1-3-0"
gradientUnits="userSpaceOnUse"
x1="-18"
y1="18"
x2="-22"
y2="5" />
<linearGradient
xlink:href="#linearGradient2"
id="linearGradient6"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.82607043,0,0,0.82533448,-4.0098079,1.346708)"
x1="-18"
y1="18"
x2="-22"
y2="5" />
<linearGradient
id="linearGradient2">
<stop
style="stop-color:#73d216;stop-opacity:1;"
offset="0"
id="stop1" />
<stop
style="stop-color:#8ae234;stop-opacity:1;"
offset="1"
id="stop2" />
</linearGradient>
<linearGradient
gradientTransform="matrix(0.1649204,0,0,0.1649204,-641.71718,-230.01448)"
y2="1734.2576"
x2="4157.8677"
y1="1473.5258"
x1="4115.4229"
gradientUnits="userSpaceOnUse"
id="linearGradient3009"
xlink:href="#linearGradient3010" />
<linearGradient
id="linearGradient3010">
<stop
id="stop3012"
offset="0"
style="stop-color:#d3d7cf;stop-opacity:1;" />
<stop
id="stop3014"
offset="1"
style="stop-color:#d3d7cf;stop-opacity:1;" />
</linearGradient>
</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>
<g
id="g1"
transform="translate(-5.05e-6,-3.000006)">
<path
id="text2714"
d="M 43.000006,43.000004 H 25 l -5.520727,6.720094 c -0.579794,0.858972 -0.393368,0.786011 -0.479275,1.279915 0,0.999994 0.647131,1.634938 2.000006,1.999989 v 2.000006 H 5.0000041 V 53.000002 C 5.9019207,52.828221 7.4631562,52.429493 8.0000051,52.000007 8.536854,51.570522 8.9999999,51.000013 10.000011,50.000001 L 32.999992,17.000006 C 33.730078,15.926342 33.871118,15.644262 34.000003,15 c 0.21471,-0.987758 0.159577,-1.570471 -1.000011,-1.999989 v -2.000007 h 16 v 2.000007 c -1.99999,0 -2.828253,0.09813 -3.000001,0.999994 -0.128869,0.622789 -0.10771,1.039609 0.150028,1.834097 l 9.953177,33.885996 c 0.429436,1.438766 0.467269,1.743077 0.896804,2.279909 0.42942,0.515393 1.140969,0.828214 2.000006,0.999995 v 2.000006 h -16 v -2.000006 c 1.481645,-0.236199 1.785214,-0.904819 1.99999,-1.999989 0.08587,-0.450959 0.257655,-1.119563 0,-2.000007 l -1.99999,-6.000002 m 0,-6.000002 -4.000012,-16 -11.999988,16 h 16"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:40px;font-family:'Copperplate Gothic Bold';-inkscape-font-specification:'Copperplate Gothic Bold, Bold';fill:url(#linearGradient3009);fill-opacity:1;stroke:#2e0000;stroke-width:2.00001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
id="text2714-1"
d="M 44.276919,40.999998 H 24.148153 l -5.964082,7.216455 c -1.480672,1.914033 -1.084253,2.914242 -1.253082,3.124467 0,0.931816 1.519016,1.409822 2.746634,1.749986 l 0.204551,-0.02274 -12.8821638,-0.06818 -0.6136358,0.477279 c 0.818401,-0.160071 3.8487146,-0.895254 4.3358566,-1.295449 0.487142,-0.400213 1.225573,-1.386371 2.019368,-2.545481 L 32.066493,21.909093 c 0.662485,-1.000473 2.608645,-3.695124 3.134675,-4.704552 0.55847,-0.920405 1.508461,-3.713398 0.456236,-4.113626 l -1.681842,-0.09092 H 48.016819 L 45.857714,12.88638 c -1.814784,0 -1.770899,0.86415 -1.904039,1.52271 -0.116912,0.580339 0.106819,1.286907 0.340709,2.027235 l 9.167925,31.189218 c 0.389674,1.340655 0.401268,1.601493 0.631975,2.465379 0.594192,1.639325 0.217134,2.044469 0.996614,2.20454 l 2.909097,0.70454 H 44.000001 l 2.068168,-1.022721 c 0.821749,-1.4701 0.851418,-1.070415 1.046321,-2.09091 0.07791,-0.420217 -0.42533,-2.088667 -0.659121,-2.90908 l -2.132998,-5.84092 m 0.735776,-3.036333 -5.501761,-20.213667 -14.812359,20.190941 20.125154,0.004"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:40px;font-family:'Copperplate Gothic Bold';-inkscape-font-specification:'Copperplate Gothic Bold, Bold';fill:none;stroke:#ffffff;stroke-width:2.00001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
id="text2714-7"
d="M 43.000006,43.000004 H 25 l -5.520727,6.720094 c -0.579794,0.858972 -0.393368,0.786011 -0.479275,1.279915 0,0.999994 0.647131,1.634938 2.000006,1.999989 v 2.000006 H 5.0000041 V 53.000002 C 5.9019207,52.828221 7.4631562,52.429493 8.0000051,52.000007 8.536854,51.570522 8.9999999,51.000013 10.000011,50.000001 L 32.999992,17.000006 C 33.730078,15.926342 33.871118,15.644262 34.000003,15 c 0.21471,-0.987758 0.159577,-1.570471 -1.000011,-1.999989 v -2.000007 h 16 v 2.000007 c -1.99999,0 -2.828253,0.09813 -3.000001,0.999994 -0.128869,0.622789 -0.10771,1.039609 0.150028,1.834097 l 9.953177,33.885996 c 0.429436,1.438766 0.467269,1.743077 0.896804,2.279909 0.42942,0.515393 1.140969,0.828214 2.000006,0.999995 v 2.000006 h -16 v -2.000006 c 1.481645,-0.236199 1.785214,-0.904819 1.99999,-1.999989 0.08586,-0.450959 0.257655,-1.119563 0,-2.000007 l -1.99999,-6.000002 m 0,-6.000002 -4.000012,-16 -11.999988,16 h 16"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:40px;font-family:'Copperplate Gothic Bold';-inkscape-font-specification:'Copperplate Gothic Bold, Bold';fill:none;stroke:#280000;stroke-width:2.00001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
<g
id="layer1-5"
transform="rotate(-135,42.659784,41.549307)">
<path
style="fill:#3465a4;stroke:#091425;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 24.393399,44.849229 20.150758,40.60659 54.091883,6.6654658 l 4.24264,4.2426392 z"
id="path3061-2"
sodipodi:nodetypes="ccccc" />
<path
style="fill:none;stroke:#729fcf;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 22.487284,41.09849 54.583793,9.0019854"
id="path3063-7"
sodipodi:nodetypes="cc" />
</g>
<g
transform="matrix(-0.55062023,-0.55062023,0.55062013,-0.55062013,-8.8460455,50.079206)"
id="g47-6"
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="path46-1"
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(#linearGradient47);fill-opacity:1;stroke:#ef2929;stroke-width:2.56842;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path47-4"
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.55062023,0.55062023,-0.55062013,-0.55062013,50.287573,71.929186)"
id="g6"
style="display:inline;stroke-width:1.2842">
<path
style="fill:none;stroke:#162c02;stroke-width:2.56841;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path5"
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(#linearGradient6);fill-opacity:1;stroke:#8ae234;stroke-width:2.56842;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path6-7"
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: 21 KiB

@@ -0,0 +1,597 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="64"
height="64"
id="svg2869"
version="1.1"
viewBox="0 0 64 64"
sodipodi:docname="Sketcher_Element_Text_StartPoint.svg"
inkscape:version="1.4.2 (f4327f4, 2025-05-13)"
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="namedview1"
pagecolor="#50505000"
bordercolor="#eeeeeeff"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#505050ff"
inkscape:zoom="10.570313"
inkscape:cx="35.476718"
inkscape:cy="26.725795"
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="linearGradient34">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop33" />
<stop
style="stop-color:#d3d7cf;stop-opacity:1;"
offset="1"
id="stop34" />
</linearGradient>
<linearGradient
id="linearGradient32">
<stop
style="stop-color:#d3d7cf;stop-opacity:1;"
offset="0"
id="stop31" />
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="1"
id="stop32" />
</linearGradient>
<linearGradient
id="linearGradient17">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop16" />
<stop
style="stop-color:#ffffff;stop-opacity:0"
offset="1"
id="stop17" />
</linearGradient>
<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)" />
<radialGradient
xlink:href="#linearGradient3809"
id="radialGradient3815"
cx="225.93762"
cy="91.956673"
fx="225.93762"
fy="91.956673"
r="22"
gradientTransform="matrix(-1.4090915,3.8636359,-0.97565325,-0.35582669,437.08461,-816.22007)"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient3809">
<stop
style="stop-color:#729fcf;stop-opacity:1"
offset="0"
id="stop3811" />
<stop
style="stop-color:#204a87;stop-opacity:1"
offset="1"
id="stop3813" />
</linearGradient>
<linearGradient
y2="5"
x2="-22"
y1="18"
x1="-18"
gradientUnits="userSpaceOnUse"
id="linearGradient3444"
xlink:href="#linearGradient3836-9-3"
gradientTransform="matrix(0.90206746,0,0,0.90216902,-1.9060863,1.1084289)" />
<linearGradient
y2="5"
x2="-22"
y1="18"
x1="-18"
gradientUnits="userSpaceOnUse"
id="linearGradient3857"
xlink:href="#linearGradient3836-9-3"
gradientTransform="matrix(0.89262616,0,0,0.89258466,72.894067,1.2176306)" />
<linearGradient
y2="5"
x2="-22"
y1="18"
x1="-18"
gradientTransform="matrix(0.93724177,0,0,0.93725692,-1.2227671,0.70650014)"
gradientUnits="userSpaceOnUse"
id="linearGradient3148"
xlink:href="#linearGradient3836-9-3" />
<linearGradient
xlink:href="#linearGradient17"
id="linearGradient3898"
x1="37.429146"
y1="41.590584"
x2="24.483221"
y2="4.9104676"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient3892">
<stop
style="stop-color:#bdd2e9;stop-opacity:1;"
offset="0"
id="stop3894" />
<stop
style="stop-color:#ffffff;stop-opacity:0"
offset="1"
id="stop3896" />
</linearGradient>
<linearGradient
xlink:href="#linearGradient3892"
id="linearGradient3856"
x1="22.84341"
y1="4.8241611"
x2="30.783579"
y2="28.644661"
gradientUnits="userSpaceOnUse" />
<radialGradient
r="22"
fy="91.956673"
fx="225.93762"
cy="91.956673"
cx="225.93762"
gradientTransform="matrix(-1.7064667,4.6731721,-1.1815555,-0.43038201,776.9032,-933.08315)"
gradientUnits="userSpaceOnUse"
id="radialGradient3163"
xlink:href="#linearGradient3809" />
<linearGradient
xlink:href="#linearGradient4104"
id="linearGradient4110"
x1="-23.070524"
y1="18.383886"
x2="-24.194258"
y2="6.534451"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient4104">
<stop
style="stop-color:#d3d7cf;stop-opacity:1"
offset="0"
id="stop4106" />
<stop
style="stop-color:#ffffff;stop-opacity:1"
offset="1"
id="stop4108" />
</linearGradient>
<linearGradient
xlink:href="#linearGradient4096"
id="linearGradient4102"
x1="-24.035076"
y1="16.85112"
x2="-23.821426"
y2="7.2881389"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient4096">
<stop
style="stop-color:#ffffff;stop-opacity:1"
offset="0"
id="stop4098" />
<stop
style="stop-color:#d3d7cf;stop-opacity:1"
offset="1"
id="stop4100" />
</linearGradient>
<linearGradient
xlink:href="#linearGradient3836-9-3"
id="linearGradient4216"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.71430595,0,0,0.71426219,259.5032,71.709694)"
x1="-18"
y1="18"
x2="-22"
y2="5" />
<radialGradient
r="22"
fy="91.956673"
fx="225.93762"
cy="91.956673"
cx="225.93762"
gradientTransform="matrix(-1.7064667,4.6731721,-1.1815555,-0.43038201,776.9032,-933.08315)"
gradientUnits="userSpaceOnUse"
id="radialGradient3163-9"
xlink:href="#linearGradient3809" />
<linearGradient
xlink:href="#linearGradient4104"
id="linearGradient4347"
x1="-21.31983"
y1="18.008659"
x2="-24.907471"
y2="6.9377007"
gradientUnits="userSpaceOnUse" />
<linearGradient
xlink:href="#linearGradient4096"
id="linearGradient4339"
x1="-21.141161"
y1="17.489555"
x2="-24.733845"
y2="7.0083036"
gradientUnits="userSpaceOnUse" />
<linearGradient
y2="5"
x2="-22"
y1="18"
x1="-18"
gradientTransform="matrix(0.65313239,0,0,0.65304994,258.31758,72.40809)"
gradientUnits="userSpaceOnUse"
id="linearGradient4235-2"
xlink:href="#linearGradient3836-9-3" />
<linearGradient
xlink:href="#linearGradient3836-9-3"
id="linearGradient3801-1-3-7"
gradientUnits="userSpaceOnUse"
x1="-18"
y1="18"
x2="-22"
y2="5" />
<linearGradient
xlink:href="#linearGradient32"
id="linearGradient3901"
gradientUnits="userSpaceOnUse"
x1="30.202745"
y1="56.729507"
x2="35.013981"
y2="19.843365"
gradientTransform="matrix(0.62354045,-0.62354046,0.62354039,0.62354042,-12.205772,28.459494)" />
<linearGradient
xlink:href="#linearGradient34"
id="linearGradient3903"
gradientUnits="userSpaceOnUse"
x1="29.993565"
y1="54.846851"
x2="36.094769"
y2="20.854424"
gradientTransform="matrix(0.57365718,-0.57365723,0.57365712,0.57365719,-8.6693108,28.742734)" />
<linearGradient
y2="5"
x2="-22"
y1="18"
x1="-18"
gradientUnits="userSpaceOnUse"
id="linearGradient3922"
xlink:href="#linearGradient3836-9-3"
gradientTransform="matrix(0.85221122,0,0,0.85228409,-2.8500258,1.6945624)" />
<linearGradient
y2="5"
x2="-22"
y1="18"
x1="-18"
gradientUnits="userSpaceOnUse"
id="linearGradient3096"
xlink:href="#linearGradient3836-9-3" />
<linearGradient
xlink:href="#linearGradient3836-9-3"
id="linearGradient3801-7"
gradientUnits="userSpaceOnUse"
x1="-18"
y1="18"
x2="-22"
y2="5"
gradientTransform="translate(-90,-5.9999999)" />
<linearGradient
y2="5"
x2="-22"
y1="18"
x1="-18"
gradientUnits="userSpaceOnUse"
id="linearGradient3082-3-8"
xlink:href="#linearGradient3836-9-3" />
<linearGradient
xlink:href="#linearGradient3836-9-3"
id="linearGradient3801-1"
gradientUnits="userSpaceOnUse"
x1="-18"
y1="18"
x2="-22"
y2="5" />
<linearGradient
xlink:href="#linearGradient3836-9-3"
id="linearGradient3801-1-3-7-3"
gradientUnits="userSpaceOnUse"
x1="-18"
y1="18"
x2="-22"
y2="5" />
<linearGradient
xlink:href="#linearGradient3836-9-3"
id="linearGradient3801-1-3-7-3-0"
gradientUnits="userSpaceOnUse"
x1="-18"
y1="18"
x2="-22"
y2="5" />
<linearGradient
y2="5"
x2="-22"
y1="18"
x1="-18"
gradientUnits="userSpaceOnUse"
id="linearGradient3203"
xlink:href="#linearGradient3836-9-3" />
<linearGradient
xlink:href="#linearGradient3836-9-3"
id="linearGradient47"
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="#linearGradient3836-9-3"
id="linearGradient49"
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="#linearGradient3836-9-3"
id="linearGradient3801-1-3-0"
gradientUnits="userSpaceOnUse"
x1="-18"
y1="18"
x2="-22"
y2="5" />
<linearGradient
xlink:href="#linearGradient2"
id="linearGradient6"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.82607043,0,0,0.82533448,-4.0098079,1.346708)"
x1="-18"
y1="18"
x2="-22"
y2="5" />
<linearGradient
id="linearGradient2">
<stop
style="stop-color:#73d216;stop-opacity:1;"
offset="0"
id="stop1" />
<stop
style="stop-color:#8ae234;stop-opacity:1;"
offset="1"
id="stop2" />
</linearGradient>
<linearGradient
gradientTransform="matrix(0.1649204,0,0,0.1649204,-641.71718,-230.01448)"
y2="1734.2576"
x2="4157.8677"
y1="1473.5258"
x1="4115.4229"
gradientUnits="userSpaceOnUse"
id="linearGradient3009"
xlink:href="#linearGradient3010" />
<linearGradient
id="linearGradient3010">
<stop
id="stop3012"
offset="0"
style="stop-color:#d3d7cf;stop-opacity:1;" />
<stop
id="stop3014"
offset="1"
style="stop-color:#d3d7cf;stop-opacity:1;" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3836-9-3"
id="linearGradient1"
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>
<g
id="g1"
transform="translate(-5.05e-6,-3.000006)">
<path
id="text2714"
d="M 43.000006,43.000004 H 25 l -5.520727,6.720094 c -0.579794,0.858972 -0.393368,0.786011 -0.479275,1.279915 0,0.999994 0.647131,1.634938 2.000006,1.999989 v 2.000006 H 5.0000041 V 53.000002 C 5.9019207,52.828221 7.4631562,52.429493 8.0000051,52.000007 8.536854,51.570522 8.9999999,51.000013 10.000011,50.000001 L 32.999992,17.000006 C 33.730078,15.926342 33.871118,15.644262 34.000003,15 c 0.21471,-0.987758 0.159577,-1.570471 -1.000011,-1.999989 v -2.000007 h 16 v 2.000007 c -1.99999,0 -2.828253,0.09813 -3.000001,0.999994 -0.128869,0.622789 -0.10771,1.039609 0.150028,1.834097 l 9.953177,33.885996 c 0.429436,1.438766 0.467269,1.743077 0.896804,2.279909 0.42942,0.515393 1.140969,0.828214 2.000006,0.999995 v 2.000006 h -16 v -2.000006 c 1.481645,-0.236199 1.785214,-0.904819 1.99999,-1.999989 0.08587,-0.450959 0.257655,-1.119563 0,-2.000007 l -1.99999,-6.000002 m 0,-6.000002 -4.000012,-16 -11.999988,16 h 16"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:40px;font-family:'Copperplate Gothic Bold';-inkscape-font-specification:'Copperplate Gothic Bold, Bold';fill:url(#linearGradient3009);fill-opacity:1;stroke:#2e0000;stroke-width:2.00001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
id="text2714-1"
d="M 44.276919,40.999998 H 24.148153 l -5.964082,7.216455 c -1.480672,1.914033 -1.084253,2.914242 -1.253082,3.124467 0,0.931816 1.519016,1.409822 2.746634,1.749986 l 0.204551,-0.02274 -12.8821638,-0.06818 -0.6136358,0.477279 c 0.818401,-0.160071 3.8487146,-0.895254 4.3358566,-1.295449 0.487142,-0.400213 1.225573,-1.386371 2.019368,-2.545481 L 32.066493,21.909093 c 0.662485,-1.000473 2.608645,-3.695124 3.134675,-4.704552 0.55847,-0.920405 1.508461,-3.713398 0.456236,-4.113626 l -1.681842,-0.09092 H 48.016819 L 45.857714,12.88638 c -1.814784,0 -1.770899,0.86415 -1.904039,1.52271 -0.116912,0.580339 0.106819,1.286907 0.340709,2.027235 l 9.167925,31.189218 c 0.389674,1.340655 0.401268,1.601493 0.631975,2.465379 0.594192,1.639325 0.217134,2.044469 0.996614,2.20454 l 2.909097,0.70454 H 44.000001 l 2.068168,-1.022721 c 0.821749,-1.4701 0.851418,-1.070415 1.046321,-2.09091 0.07791,-0.420217 -0.42533,-2.088667 -0.659121,-2.90908 l -2.132998,-5.84092 m 0.735776,-3.036333 -5.501761,-20.213667 -14.812359,20.190941 20.125154,0.004"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:40px;font-family:'Copperplate Gothic Bold';-inkscape-font-specification:'Copperplate Gothic Bold, Bold';fill:none;stroke:#ffffff;stroke-width:2.00001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
id="text2714-7"
d="M 43.000006,43.000004 H 25 l -5.520727,6.720094 c -0.579794,0.858972 -0.393368,0.786011 -0.479275,1.279915 0,0.999994 0.647131,1.634938 2.000006,1.999989 v 2.000006 H 5.0000041 V 53.000002 C 5.9019207,52.828221 7.4631562,52.429493 8.0000051,52.000007 8.536854,51.570522 8.9999999,51.000013 10.000011,50.000001 L 32.999992,17.000006 C 33.730078,15.926342 33.871118,15.644262 34.000003,15 c 0.21471,-0.987758 0.159577,-1.570471 -1.000011,-1.999989 v -2.000007 h 16 v 2.000007 c -1.99999,0 -2.828253,0.09813 -3.000001,0.999994 -0.128869,0.622789 -0.10771,1.039609 0.150028,1.834097 l 9.953177,33.885996 c 0.429436,1.438766 0.467269,1.743077 0.896804,2.279909 0.42942,0.515393 1.140969,0.828214 2.000006,0.999995 v 2.000006 h -16 v -2.000006 c 1.481645,-0.236199 1.785214,-0.904819 1.99999,-1.999989 0.08586,-0.450959 0.257655,-1.119563 0,-2.000007 l -1.99999,-6.000002 m 0,-6.000002 -4.000012,-16 -11.999988,16 h 16"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:40px;font-family:'Copperplate Gothic Bold';-inkscape-font-specification:'Copperplate Gothic Bold, Bold';fill:none;stroke:#280000;stroke-width:2.00001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
<g
id="layer1-5"
transform="rotate(45,-1.3443654,28.861417)">
<path
style="fill:#3465a4;stroke:#091425;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 24.393399,44.849229 20.150758,40.60659 54.091883,6.6654658 l 4.24264,4.2426392 z"
id="path3061-2"
sodipodi:nodetypes="ccccc" />
<path
style="fill:none;stroke:#729fcf;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 22.487284,41.09849 54.583793,9.0019854"
id="path3063-7"
sodipodi:nodetypes="cc" />
</g>
<g
transform="matrix(0.55062023,0.55062023,-0.55062013,0.55062013,72.305403,60.418843)"
id="g47-6"
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="path46-1"
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(#linearGradient1);fill-opacity:1;stroke:#ef2929;stroke-width:2.56842;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path47-4"
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.55062023,-0.55062023,0.55062013,0.55062013,13.171784,38.568863)"
id="g6"
style="display:inline;stroke-width:1.2842">
<path
style="fill:none;stroke:#162c02;stroke-width:2.56841;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path5"
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(#linearGradient6);fill-opacity:1;stroke:#8ae234;stroke-width:2.56842;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path6-7"
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: 21 KiB

@@ -56,6 +56,10 @@ SketcherToolDefaultWidget::SketcherToolDefaultWidget(QWidget* parent)
{
ui->setupUi(this);
ui->comboBox1->setMaxVisibleItems(25);
ui->comboBox2->setMaxVisibleItems(25);
ui->comboBox3->setMaxVisibleItems(25);
// connecting the needed signals
setupConnections();
@@ -352,7 +352,7 @@ public:
auto selicon = [this](const Sketcher::Constraint* constr,
const QIcon& normal,
const QIcon& driven) -> QIcon {
if (!constr->isActive) {
if (!sketch->isConstraintActiveInSketch(constr)) {
QIcon darkIcon;
int w = listWidget()->style()->pixelMetric(QStyle::PM_ListViewIconSize);
darkIcon.addPixmap(normal.pixmap(w, w, QIcon::Disabled, QIcon::Off),
@@ -1708,6 +1708,10 @@ bool TaskSketcherConstraints::isConstraintFiltered(QListWidgetItem* item)
ConstraintItem* it = static_cast<ConstraintItem*>(item);
const Sketcher::Constraint* constraint = vals[it->ConstraintNbr];
// Text constraint is hidden from the list widget.
if (constraint->Type == Sketcher::Text) {
return true;
}
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/Mod/Sketcher");
+65 -6
View File
@@ -204,7 +204,8 @@ public:
Base::Type geometryType,
GeometryState state,
const QString& lab,
ViewProviderSketch* sketchView
ViewProviderSketch* sketchView,
bool isTextHandle = false
)
: ElementNbr(elementnr)
, StartingVertex(startingVertex)
@@ -219,6 +220,7 @@ public:
, clickedOn(SubElementType::none)
, hovered(SubElementType::none)
, rightClicked(false)
, isTextHandle(isTextHandle)
, label(lab)
, sketchView(sketchView)
{
@@ -319,6 +321,7 @@ public:
SubElementType clickedOn;
SubElementType hovered;
bool rightClicked;
bool isTextHandle;
QString label;
@@ -377,11 +380,12 @@ public:
static const QIcon&
getIcon(Base::Type type, Sketcher::PointPos pos,
ElementItem::GeometryState icontype = ElementItem::GeometryState::Normal)
ElementItem::GeometryState icontype = ElementItem::GeometryState::Normal,
bool isTextHandle = false)
{
static ElementWidgetIcons elementicons;
return elementicons.getIconImpl(type, pos, icontype);
return elementicons.getIconImpl(type, pos, icontype, isTextHandle);
}
private:
@@ -505,11 +509,34 @@ private:
{Sketcher::PointPos::none,
getMultIcon("Sketcher_Element_SelectionTypeInvalid")},
}));
// Text Handle Icons
textIcons[Sketcher::PointPos::none] = Gui::BitmapFactory().iconFromTheme("Sketcher_CreateText");
textIcons[Sketcher::PointPos::start] = Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Text_StartPoint");
textIcons[Sketcher::PointPos::end] = Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Text_EndPoint");
}
const QIcon& getIconImpl(Base::Type type, Sketcher::PointPos pos,
ElementItem::GeometryState icontype)
ElementItem::GeometryState icontype,
bool isTextHandle)
{
if (isTextHandle) {
auto it = textIcons.find(pos);
if (it != textIcons.end()) {
return it->second;
}
// Fallback for Midpoint or other positions: use normal line icon without blue filter
if (type == Part::GeomLineSegment::getClassTypeId()) {
auto typekey = icons.find(type);
if (typekey != icons.end()) {
auto poskey = typekey->second.find(pos);
if (poskey != typekey->second.end()) {
// Return the 'Normal' variant (index 0) to avoid blue construction color
return std::get<0>(poskey->second);
}
}
}
}
auto typekey = icons.find(type);
@@ -585,6 +612,7 @@ private:
private:
std::map<Base::Type, std::map<Sketcher::PointPos, std::tuple<QIcon, QIcon, QIcon, QIcon>>>
icons;
std::map<Sketcher::PointPos, QIcon> textIcons;
};
ElementView::ElementView(QWidget* parent)
@@ -720,6 +748,14 @@ void ElementView::contextMenuEvent(QContextMenuEvent* event)
QMenu menu;
QList<QListWidgetItem*> items = selectedItems();
if (items.size() == 1) {
ElementItem* item = static_cast<ElementItem*>(items.first());
if (item->isTextHandle) {
menu.addSeparator();
menu.addAction(tr("Convert to geometries"), this, SLOT(doConvertToGeometries()));
}
}
// NOTE: If extending this context menu, be sure to add the items to the translation block at
// the top of this file
@@ -944,6 +980,25 @@ ElementItem* ElementView::itemFromIndex(const QModelIndex& index)
return static_cast<ElementItem*>(QListWidget::itemFromIndex(index));
}
void ElementView::doConvertToGeometries()
{
QList<QListWidgetItem*> items = selectedItems();
if (items.isEmpty())
return;
ElementItem* item = static_cast<ElementItem*>(items.first());
if (!item->isTextHandle)
return;
int geoId = item->ElementNbr;
Sketcher::SketchObject* sketch = item->getSketchObject();
// Deleting the handle geometry will automatically remove the Text constraint
// (turning it to None), leaving the generated text geometries intact.
Gui::Selection().clearSelection();
sketch->delGeometry(geoId);
}
// clang-format on
/* ElementItem delegate ---------------------------------------------------- */
ElementItemDelegate::ElementItemDelegate(ElementView* parent)
@@ -1038,7 +1093,8 @@ void ElementItemDelegate::drawSubControl(
auto isHovered = rect.contains(mousePos);
auto drawSelectIcon = [&](Sketcher::PointPos pos) {
auto icon = ElementWidgetIcons::getIcon(item->GeometryType, pos, item->State);
auto icon
= ElementWidgetIcons::getIcon(item->GeometryType, pos, item->State, item->isTextHandle);
auto isOptionSelected = option.state & QStyle::State_Selected;
auto isOptionHovered = option.state & QStyle::State_MouseOver;
@@ -1977,6 +2033,7 @@ void TaskSketcherElements::slotElementsChanged()
QString label;
// This is a regular geometry. Get its type name.
QString baseName;
bool isTextHandle = false;
if (type == Part::GeomPoint::getClassTypeId()) {
baseName = tr("Point");
}
@@ -1990,6 +2047,7 @@ void TaskSketcherElements::slotElementsChanged()
}
else {
baseName = tr("Text");
isTextHandle = true;
}
}
else {
@@ -2043,7 +2101,8 @@ void TaskSketcherElements::slotElementsChanged()
type,
state,
label,
sketchView);
sketchView,
isTextHandle);
ui->listWidgetElements->addItem(itemN);
@@ -85,6 +85,7 @@ protected Q_SLOTS:
void doSymmetricConstraint();
void doBlockConstraint();
void doGroupConstraint();
void doConvertToGeometries();
void doLockConstraint();
void doHorizontalConstraint();
@@ -4464,6 +4464,11 @@ Sketcher::Constraint* ViewProviderSketch::getConstraint(int constid) const
return nullptr;
}
bool ViewProviderSketch::isConstraintActiveInSketch(const Sketcher::Constraint* cstr) const
{
return getSketchObject()->isConstraintActiveInSketch(cstr);
}
const GeoList ViewProviderSketch::getGeoList() const
{
const std::vector<Part::Geometry*> tempGeo =
@@ -888,6 +888,9 @@ private:
/// or null if it doesn't exist.
Sketcher::Constraint* getConstraint(int constid) const;
// Return true if the constraint is active, includes checking if it's not in a group
bool isConstraintActiveInSketch(const Sketcher::Constraint* cstr) const;
// gets the list of geometry of the sketchobject or of the solver instance
const GeoList getGeoList() const;
@@ -85,6 +85,10 @@ class ViewProviderSketchCoinAttorney
private:
static inline bool constraintHasExpression(const ViewProviderSketch& vp, int constrid);
static inline const std::vector<Sketcher::Constraint*> getConstraints(const ViewProviderSketch& vp);
static inline bool isConstraintActiveInSketch(
const ViewProviderSketch& vp,
const Sketcher::Constraint* cstr
);
static inline const GeoList getGeoList(const ViewProviderSketch& vp);
static inline const GeoListFacade getGeoListFacade(const ViewProviderSketch& vp);
static inline Base::Placement getEditingPlacement(const ViewProviderSketch& vp);
@@ -144,6 +148,14 @@ inline const std::vector<Sketcher::Constraint*> ViewProviderSketchCoinAttorney::
return vp.getConstraints();
}
inline bool ViewProviderSketchCoinAttorney::isConstraintActiveInSketch(
const ViewProviderSketch& vp,
const Sketcher::Constraint* cstr
)
{
return vp.isConstraintActiveInSketch(cstr);
}
inline const GeoList ViewProviderSketchCoinAttorney::getGeoList(const ViewProviderSketch& vp)
{
return vp.getGeoList();