[TD]Cosmetic function overhaul (#14216)
* [TD]Cosmetic geometry and tools update - all cosmetics to store geometry in same form - all cosmetics to survive scaling and rotation - extension functions to survive scaling and rotation * [TD]overhaul leader point storage and editing - add py routine makeLeader(points) * [TD]add leader conversion utility * [TD]Set Leader RotateWithView default to true * [TD]fix intersection vertex position * [TD]add CosmeticEdge::makeLineFromCanonicalPoints * [TD]fix 2 Extension tools - positioning in DrawCosmeticCircle - mishandling of points in execLineParallelPerpendicular * [TD]Remove duplicate constexpr * [TD]fix 2x Cosmetic arc tools * [TD]refactor LineFormat out of Cosmetic * [TD]move cosmetic appearance settings to LineFormat * [TD]remove 2 unused methods * [TD]apply format to blue line & circle tools * [TD]fix ballon arrowhead does not rotate with view * [TD]fix CosmeticCircle3Points * [TD]allow multiple cosmetic object deletions * [TD]fix extend/shorten centerline
This commit is contained in:
@@ -149,5 +149,7 @@ PyMOD_INIT_FUNC(TechDraw)
|
||||
TechDraw::DrawWeldSymbolPython::init();
|
||||
TechDraw::DrawBrokenViewPython::init();
|
||||
|
||||
TechDraw::LineFormat::initCurrentLineFormat();
|
||||
|
||||
PyMOD_Return(mod);
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
#include "ProjectionAlgos.h"
|
||||
#include "TechDrawExport.h"
|
||||
#include "CosmeticVertexPy.h"
|
||||
|
||||
#include "DrawLeaderLinePy.h"
|
||||
|
||||
namespace TechDraw {
|
||||
//module level static C++ functions go here
|
||||
@@ -191,6 +191,9 @@ public:
|
||||
add_varargs_method("makeCanonicalPoint", &Module::makeCanonicalPoint,
|
||||
"makeCanonicalPoint(DrawViewPart, Vector3d) - Returns the unscaled, unrotated version of the input point)"
|
||||
);
|
||||
add_varargs_method("makeLeader", &Module::makeLeader,
|
||||
"makeLeader(parent - DrawViewPart, points - [Vector], startSymbol - int, endSymbol - int) - Creates a leader line attached to parent. Points are in page coordinates with (0, 0) at lowerleft.s"
|
||||
);
|
||||
initialize("This is a module for making drawings"); // register with Python
|
||||
}
|
||||
~Module() override {}
|
||||
@@ -1286,6 +1289,42 @@ private:
|
||||
cPoint = CosmeticVertex::makeCanonicalPoint(dvp, cPoint, unscale);
|
||||
return Py::asObject(new Base::VectorPy(cPoint));
|
||||
}
|
||||
|
||||
Py::Object makeLeader(const Py::Tuple& args)
|
||||
{
|
||||
PyObject* pDvp(nullptr);
|
||||
PyObject* pPointList(nullptr);
|
||||
int iStartSymbol = 0;
|
||||
int iEndSymbol = 0;
|
||||
TechDraw::DrawViewPart* dvp = nullptr;
|
||||
|
||||
if (!PyArg_ParseTuple(args.ptr(), "OO!|ii", &pDvp, &(PyList_Type), &pPointList, &iStartSymbol, &iEndSymbol)) {
|
||||
throw Py::TypeError("expected (DrawViewPart, listofpoints, startsymbolindex, endsymbolindex");
|
||||
}
|
||||
if (PyObject_TypeCheck(pDvp, &(TechDraw::DrawViewPartPy::Type))) {
|
||||
App::DocumentObject* obj = static_cast<App::DocumentObjectPy*>(pDvp)->getDocumentObjectPtr();
|
||||
dvp = static_cast<TechDraw::DrawViewPart*>(obj);
|
||||
}
|
||||
|
||||
std::vector<Base::Vector3d> pointList;
|
||||
try {
|
||||
Py::Sequence list(pPointList);
|
||||
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
|
||||
if (PyObject_TypeCheck((*it).ptr(), &(Base::VectorPy::Type))) {
|
||||
Base::Vector3d temp = static_cast<Base::VectorPy*>((*it).ptr())->value();
|
||||
pointList.push_back(temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Standard_Failure& e) {
|
||||
throw Py::Exception(Part::PartExceptionOCCError, e.GetMessageString());
|
||||
}
|
||||
auto newLeader = DrawLeaderLine::makeLeader(dvp, pointList, iStartSymbol, iEndSymbol);
|
||||
|
||||
// return the new leader as DrawLeaderPy
|
||||
return Py::asObject(new DrawLeaderLinePy(newLeader));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
PyObject* initModule()
|
||||
|
||||
@@ -174,6 +174,8 @@ SET(TechDraw_SRCS
|
||||
XMLQuery.h
|
||||
LineGenerator.cpp
|
||||
LineGenerator.h
|
||||
LineFormat.cpp
|
||||
LineFormat.h
|
||||
)
|
||||
|
||||
SET(Geometry_SRCS
|
||||
|
||||
@@ -885,10 +885,10 @@ void CenterLine::Save(Base::Writer &writer) const
|
||||
|
||||
// style is deprecated in favour of line number, but we still save and restore it
|
||||
// to avoid problems with old documents.
|
||||
writer.Stream() << writer.ind() << "<Style value=\"" << m_format.m_style << "\"/>" << std::endl;
|
||||
writer.Stream() << writer.ind() << "<Weight value=\"" << m_format.m_weight << "\"/>" << std::endl;
|
||||
writer.Stream() << writer.ind() << "<Color value=\"" << m_format.m_color.asHexString() << "\"/>" << std::endl;
|
||||
const char v = m_format.m_visible?'1':'0';
|
||||
writer.Stream() << writer.ind() << "<Style value=\"" << m_format.getStyle() << "\"/>" << std::endl;
|
||||
writer.Stream() << writer.ind() << "<Weight value=\"" << m_format.getWidth() << "\"/>" << std::endl;
|
||||
writer.Stream() << writer.ind() << "<Color value=\"" << m_format.getColor().asHexString() << "\"/>" << std::endl;
|
||||
const char v = m_format.getVisible() ? '1' : '0';
|
||||
writer.Stream() << writer.ind() << "<Visible value=\"" << v << "\"/>" << std::endl;
|
||||
|
||||
//stored geometry
|
||||
@@ -984,14 +984,16 @@ void CenterLine::Restore(Base::XMLReader &reader)
|
||||
// style is deprecated in favour of line number, but we still save and restore it
|
||||
// to avoid problems with old documents.
|
||||
reader.readElement("Style");
|
||||
m_format.m_style = reader.getAttributeAsInteger("value");
|
||||
m_format.setStyle(reader.getAttributeAsInteger("value"));
|
||||
reader.readElement("Weight");
|
||||
m_format.m_weight = reader.getAttributeAsFloat("value");
|
||||
m_format.setWidth(reader.getAttributeAsFloat("value"));
|
||||
reader.readElement("Color");
|
||||
std::string temp = reader.getAttribute("value");
|
||||
m_format.m_color.fromHexString(temp);
|
||||
std::string tempHex = reader.getAttribute("value");
|
||||
App::Color tempColor;
|
||||
tempColor.fromHexString(tempHex);
|
||||
m_format.setColor(tempColor);
|
||||
reader.readElement("Visible");
|
||||
m_format.m_visible = (int)reader.getAttributeAsInteger("value")==0?false:true;
|
||||
m_format.setVisible( (int)reader.getAttributeAsInteger("value")==0 ? false : true);
|
||||
|
||||
//stored geometry
|
||||
reader.readElement("GeometryType");
|
||||
|
||||
@@ -115,10 +115,10 @@ Py::Dict CenterLinePy::getFormat() const
|
||||
TechDraw::LineFormat* format= &(this->getCenterLinePtr()->m_format);
|
||||
Py::Dict dict;
|
||||
|
||||
dict.setItem("style", Py::Long(format->m_style));
|
||||
dict.setItem("weight", Py::Float(format->m_weight));
|
||||
dict.setItem("color", Py::Tuple(DrawUtil::colorToPyTuple(format->m_color), true));
|
||||
dict.setItem("visible", Py::Boolean(format->m_visible));
|
||||
dict.setItem("style", Py::Long(format->getStyle()));
|
||||
dict.setItem("weight", Py::Float(format->getWidth()));
|
||||
dict.setItem("color", Py::Tuple(DrawUtil::colorToPyTuple(format->getColor()), true));
|
||||
dict.setItem("visible", Py::Boolean(format->getVisible()));
|
||||
|
||||
return dict;
|
||||
}
|
||||
@@ -138,10 +138,10 @@ void CenterLinePy::setFormat(Py::Dict arg)
|
||||
}
|
||||
|
||||
TechDraw::LineFormat* format = &(this->getCenterLinePtr()->m_format);
|
||||
format->m_style = style;
|
||||
format->m_weight = weight;
|
||||
format->m_color = DrawUtil::pyTupleToColor(pColor);
|
||||
format->m_visible = Base::asBoolean(visible);
|
||||
format->setStyle(style);
|
||||
format->setWidth(weight);
|
||||
format->setColor(DrawUtil::pyTupleToColor(pColor));
|
||||
format->setVisible(Base::asBoolean(visible));
|
||||
}
|
||||
|
||||
Py::String CenterLinePy::getTag() const
|
||||
|
||||
@@ -37,11 +37,8 @@
|
||||
#include "DrawUtil.h"
|
||||
#include "DrawViewPart.h"
|
||||
#include "GeometryObject.h"
|
||||
#include "LineGroup.h"
|
||||
#include "LineGenerator.h"
|
||||
#include "Preferences.h"
|
||||
|
||||
|
||||
using namespace TechDraw;
|
||||
using namespace std;
|
||||
using DU = DrawUtil;
|
||||
@@ -50,67 +47,11 @@ using DU = DrawUtil;
|
||||
#define COSMETICEDGE 1
|
||||
#define CENTERLINE 2
|
||||
|
||||
LineFormat::LineFormat()
|
||||
{
|
||||
m_style = getDefEdgeStyle();
|
||||
m_weight = getDefEdgeWidth();
|
||||
m_color= getDefEdgeColor();
|
||||
m_visible = true;
|
||||
m_lineNumber = LineGenerator::fromQtStyle((Qt::PenStyle)m_style);
|
||||
}
|
||||
|
||||
LineFormat::LineFormat(const int style,
|
||||
const double weight,
|
||||
const App::Color& color,
|
||||
const bool visible) :
|
||||
m_style(style),
|
||||
m_weight(weight),
|
||||
m_color(color),
|
||||
m_visible(visible),
|
||||
m_lineNumber(LineGenerator::fromQtStyle((Qt::PenStyle)m_style))
|
||||
{
|
||||
}
|
||||
|
||||
void LineFormat::dump(const char* title)
|
||||
{
|
||||
Base::Console().Message("LF::dump - %s \n", title);
|
||||
Base::Console().Message("LF::dump - %s \n", toString().c_str());
|
||||
}
|
||||
|
||||
std::string LineFormat::toString() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << m_style << ", " <<
|
||||
m_weight << ", " <<
|
||||
m_color.asHexString() << ", " <<
|
||||
m_visible;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
//static preference getters.
|
||||
double LineFormat::getDefEdgeWidth()
|
||||
{
|
||||
return TechDraw::LineGroup::getDefaultWidth("Graphic");
|
||||
}
|
||||
|
||||
App::Color LineFormat::getDefEdgeColor()
|
||||
{
|
||||
return Preferences::normalColor();
|
||||
}
|
||||
|
||||
int LineFormat::getDefEdgeStyle()
|
||||
{
|
||||
return Preferences::getPreferenceGroup("Decorations")->GetInt("CenterLineStyle", 2); //dashed
|
||||
}
|
||||
|
||||
//******************************************
|
||||
|
||||
TYPESYSTEM_SOURCE(TechDraw::CosmeticEdge, Base::Persistence)
|
||||
|
||||
//note this ctor has no occEdge or first/last point for geometry!
|
||||
CosmeticEdge::CosmeticEdge()
|
||||
{
|
||||
// Base::Console().Message("CE::CE()\n");
|
||||
permaRadius = 0.0;
|
||||
m_geometry = std::make_shared<TechDraw::BaseGeom> ();
|
||||
initialize();
|
||||
@@ -118,7 +59,6 @@ CosmeticEdge::CosmeticEdge()
|
||||
|
||||
CosmeticEdge::CosmeticEdge(const CosmeticEdge* ce)
|
||||
{
|
||||
// Base::Console().Message("CE::CE(ce)\n");
|
||||
TechDraw::BaseGeomPtr newGeom = ce->m_geometry->copy();
|
||||
//these endpoints are already YInverted
|
||||
permaStart = ce->permaStart;
|
||||
@@ -130,13 +70,12 @@ CosmeticEdge::CosmeticEdge(const CosmeticEdge* ce)
|
||||
}
|
||||
|
||||
CosmeticEdge::CosmeticEdge(const Base::Vector3d& pt1, const Base::Vector3d& pt2) :
|
||||
// 🠓 returns TopoDS_Edge
|
||||
CosmeticEdge::CosmeticEdge(TopoDS_EdgeFromVectors(pt1, pt2))
|
||||
CosmeticEdge::CosmeticEdge(TopoDS_EdgeFromVectors(pt1, pt2))
|
||||
{
|
||||
}
|
||||
|
||||
// 🠓 returns TechDraw::BaseGeomPtr
|
||||
CosmeticEdge::CosmeticEdge(const TopoDS_Edge& e) : CosmeticEdge(TechDraw::BaseGeom::baseFactory(e))
|
||||
CosmeticEdge::CosmeticEdge(const TopoDS_Edge& e) :
|
||||
CosmeticEdge(TechDraw::BaseGeom::baseFactory(e))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -153,6 +92,15 @@ CosmeticEdge::CosmeticEdge(const TechDraw::BaseGeomPtr g)
|
||||
permaStart = circ->center;
|
||||
permaEnd = circ->center;
|
||||
permaRadius = circ->radius;
|
||||
if (g->getGeomType() == TechDraw::GeomType::ARCOFCIRCLE) {
|
||||
TechDraw::AOCPtr aoc = std::static_pointer_cast<TechDraw::AOC>(circ);
|
||||
aoc->clockwiseAngle(g->clockwiseAngle());
|
||||
aoc->startPnt = g->getStartPoint();
|
||||
aoc->startAngle = g->getStartAngle();
|
||||
aoc->endPnt = g->getEndPoint();
|
||||
aoc->endAngle = g->getEndAngle();
|
||||
// aoc->largeArc = g->largeArc;
|
||||
}
|
||||
}
|
||||
initialize();
|
||||
}
|
||||
@@ -173,15 +121,10 @@ void CosmeticEdge::initialize()
|
||||
m_geometry->setCosmeticTag(getTagAsString());
|
||||
}
|
||||
|
||||
// TODO: not sure that this method should be doing the inversion. CV for example
|
||||
// accepts input point as is. The caller should have figured out the correct points.
|
||||
TopoDS_Edge CosmeticEdge::TopoDS_EdgeFromVectors(const Base::Vector3d& pt1, const Base::Vector3d& pt2)
|
||||
{
|
||||
// Base::Console().Message("CE::CE(p1, p2)\n");
|
||||
Base::Vector3d p1 = DrawUtil::invertY(pt1);
|
||||
Base::Vector3d p2 = DrawUtil::invertY(pt2);
|
||||
gp_Pnt gp1(p1.x, p1.y, p1.z);
|
||||
gp_Pnt gp2(p2.x, p2.y, p2.z);
|
||||
gp_Pnt gp1(pt1.x, pt1.y, pt1.z);
|
||||
gp_Pnt gp2(pt2.x, pt2.y, pt2.z);
|
||||
return BRepBuilderAPI_MakeEdge(gp1, gp2);
|
||||
}
|
||||
|
||||
@@ -202,7 +145,7 @@ TechDraw::BaseGeomPtr CosmeticEdge::scaledGeometry(const double scale)
|
||||
TechDraw::BaseGeomPtr CosmeticEdge::scaledAndRotatedGeometry(const double scale, const double rotDegrees)
|
||||
{
|
||||
TopoDS_Edge e = m_geometry->getOCCEdge();
|
||||
// TopoDS_Shape s = TechDraw::scaleShape(e, scale);
|
||||
bool saveCW = m_geometry->clockwiseAngle();
|
||||
// Mirror shape in Y and scale
|
||||
TopoDS_Shape s = ShapeUtils::mirrorShape(e, gp_Pnt(0.0, 0.0, 0.0), scale);
|
||||
// rotate using OXYZ as the coordinate system
|
||||
@@ -215,11 +158,11 @@ TechDraw::BaseGeomPtr CosmeticEdge::scaledAndRotatedGeometry(const double scale,
|
||||
newGeom->setCosmetic(true);
|
||||
newGeom->source(COSMETICEDGE);
|
||||
newGeom->setCosmeticTag(getTagAsString());
|
||||
newGeom->clockwiseAngle(saveCW);
|
||||
return newGeom;
|
||||
}
|
||||
|
||||
//! makes an unscaled, unrotated line from two scaled & rotated end points. If points is Gui space coordinates,
|
||||
//! they should be inverted (DU::invertY) before calling this method.
|
||||
//! makes an unscaled, unrotated line from two scaled & rotated end points.
|
||||
//! the result of this method should be used in addCosmeticEdge().
|
||||
TechDraw::BaseGeomPtr CosmeticEdge::makeCanonicalLine(DrawViewPart* dvp, Base::Vector3d start, Base::Vector3d end)
|
||||
{
|
||||
@@ -228,7 +171,16 @@ TechDraw::BaseGeomPtr CosmeticEdge::makeCanonicalLine(DrawViewPart* dvp, Base::V
|
||||
gp_Pnt gStart = DU::togp_Pnt(cStart);
|
||||
gp_Pnt gEnd = DU::togp_Pnt(cEnd);
|
||||
TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(gStart, gEnd);
|
||||
return TechDraw::BaseGeom::baseFactory(edge)->inverted();
|
||||
return TechDraw::BaseGeom::baseFactory(edge);
|
||||
}
|
||||
|
||||
//! makes an unscaled, unrotated line from two canonical points.
|
||||
TechDraw::BaseGeomPtr CosmeticEdge::makeLineFromCanonicalPoints(Base::Vector3d start, Base::Vector3d end)
|
||||
{
|
||||
gp_Pnt gStart = DU::togp_Pnt(start);
|
||||
gp_Pnt gEnd = DU::togp_Pnt(end);
|
||||
TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(gStart, gEnd);
|
||||
return TechDraw::BaseGeom::baseFactory(edge);
|
||||
}
|
||||
|
||||
std::string CosmeticEdge::toString() const
|
||||
@@ -261,10 +213,10 @@ void CosmeticEdge::Save(Base::Writer &writer) const
|
||||
{
|
||||
// TODO: this should be using m_format->Save(writer) instead of saving the individual
|
||||
// fields.
|
||||
writer.Stream() << writer.ind() << "<Style value=\"" << m_format.m_style << "\"/>" << endl;
|
||||
writer.Stream() << writer.ind() << "<Weight value=\"" << m_format.m_weight << "\"/>" << endl;
|
||||
writer.Stream() << writer.ind() << "<Color value=\"" << m_format.m_color.asHexString() << "\"/>" << endl;
|
||||
const char v = m_format.m_visible?'1':'0';
|
||||
writer.Stream() << writer.ind() << "<Style value=\"" << m_format.getStyle() << "\"/>" << endl;
|
||||
writer.Stream() << writer.ind() << "<Weight value=\"" << m_format.getWidth() << "\"/>" << endl;
|
||||
writer.Stream() << writer.ind() << "<Color value=\"" << m_format.getColor().asHexString() << "\"/>" << endl;
|
||||
const char v = m_format.getVisible() ? '1' : '0';
|
||||
writer.Stream() << writer.ind() << "<Visible value=\"" << v << "\"/>" << endl;
|
||||
|
||||
writer.Stream() << writer.ind() << "<GeometryType value=\"" << m_geometry->getGeomType() <<"\"/>" << endl;
|
||||
@@ -292,14 +244,16 @@ void CosmeticEdge::Restore(Base::XMLReader &reader)
|
||||
}
|
||||
// Base::Console().Message("CE::Restore - reading elements\n");
|
||||
reader.readElement("Style");
|
||||
m_format.m_style = reader.getAttributeAsInteger("value");
|
||||
m_format.setStyle(reader.getAttributeAsInteger("value"));
|
||||
reader.readElement("Weight");
|
||||
m_format.m_weight = reader.getAttributeAsFloat("value");
|
||||
m_format.setWidth(reader.getAttributeAsFloat("value"));
|
||||
reader.readElement("Color");
|
||||
std::string temp = reader.getAttribute("value");
|
||||
m_format.m_color.fromHexString(temp);
|
||||
std::string tempHex = reader.getAttribute("value");
|
||||
App::Color tempColor;
|
||||
tempColor.fromHexString(tempHex);
|
||||
m_format.setColor(tempColor);
|
||||
reader.readElement("Visible");
|
||||
m_format.m_visible = reader.getAttributeAsInteger("value") != 0;
|
||||
m_format.setVisible(reader.getAttributeAsInteger("value") != 0);
|
||||
|
||||
reader.readElement("GeometryType");
|
||||
TechDraw::GeomType gType = static_cast<TechDraw::GeomType>(reader.getAttributeAsInteger("value"));
|
||||
@@ -378,20 +332,12 @@ void CosmeticEdge::assignTag(const TechDraw::CosmeticEdge* ce)
|
||||
throw Base::TypeError("CosmeticEdge tag can not be assigned as types do not match.");
|
||||
}
|
||||
|
||||
CosmeticEdge* CosmeticEdge::copy() const
|
||||
{
|
||||
// Base::Console().Message("CE::copy()\n");
|
||||
CosmeticEdge* newCE = new CosmeticEdge();
|
||||
TechDraw::BaseGeomPtr newGeom = m_geometry->copy();
|
||||
newCE->m_geometry = newGeom;
|
||||
newCE->m_format = m_format;
|
||||
return newCE;
|
||||
}
|
||||
|
||||
CosmeticEdge* CosmeticEdge::clone() const
|
||||
{
|
||||
// Base::Console().Message("CE::clone()\n");
|
||||
CosmeticEdge* cpy = this->copy();
|
||||
Base::Console().Message("CE::clone()\n");
|
||||
CosmeticEdge* cpy = new CosmeticEdge();
|
||||
cpy->m_geometry = m_geometry->copy();
|
||||
cpy->m_format = m_format;
|
||||
cpy->tag = this->tag;
|
||||
return cpy;
|
||||
}
|
||||
@@ -412,10 +358,10 @@ TYPESYSTEM_SOURCE(TechDraw::GeomFormat, Base::Persistence)
|
||||
GeomFormat::GeomFormat() :
|
||||
m_geomIndex(-1)
|
||||
{
|
||||
m_format.m_style = LineFormat::getDefEdgeStyle();
|
||||
m_format.m_weight = LineFormat::getDefEdgeWidth();
|
||||
m_format.m_color = LineFormat::getDefEdgeColor();
|
||||
m_format.m_visible = true;
|
||||
m_format.setStyle(LineFormat::getDefEdgeStyle());
|
||||
m_format.setWidth(LineFormat::getDefEdgeWidth());
|
||||
m_format.setColor(LineFormat::getDefEdgeColor());
|
||||
m_format.setVisible(true);
|
||||
m_format.setLineNumber(LineFormat::InvalidLine);
|
||||
|
||||
createNewTag();
|
||||
@@ -424,10 +370,10 @@ GeomFormat::GeomFormat() :
|
||||
GeomFormat::GeomFormat(const GeomFormat* gf)
|
||||
{
|
||||
m_geomIndex = gf->m_geomIndex;
|
||||
m_format.m_style = gf->m_format.m_style;
|
||||
m_format.m_weight = gf->m_format.m_weight;
|
||||
m_format.m_color = gf->m_format.m_color;
|
||||
m_format.m_visible = gf->m_format.m_visible;
|
||||
m_format.setStyle(gf->m_format.getStyle());
|
||||
m_format.setWidth(gf->m_format.getWidth());
|
||||
m_format.setColor(gf->m_format.getColor());
|
||||
m_format.setVisible(gf->m_format.getVisible());
|
||||
m_format.setLineNumber(gf->m_format.getLineNumber());
|
||||
|
||||
createNewTag();
|
||||
@@ -437,10 +383,10 @@ GeomFormat::GeomFormat(const int idx,
|
||||
const TechDraw::LineFormat& fmt) :
|
||||
m_geomIndex(idx)
|
||||
{
|
||||
m_format.m_style = fmt.m_style;
|
||||
m_format.m_weight = fmt.m_weight;
|
||||
m_format.m_color = fmt.m_color;
|
||||
m_format.m_visible = fmt.m_visible;
|
||||
m_format.setStyle(fmt.getStyle());
|
||||
m_format.setWidth(fmt.getWidth());
|
||||
m_format.setColor(fmt.getColor());
|
||||
m_format.setVisible(fmt.getVisible());
|
||||
m_format.setLineNumber(fmt.getLineNumber());
|
||||
|
||||
createNewTag();
|
||||
@@ -472,13 +418,13 @@ unsigned int GeomFormat::getMemSize () const
|
||||
|
||||
void GeomFormat::Save(Base::Writer &writer) const
|
||||
{
|
||||
const char v = m_format.m_visible?'1':'0';
|
||||
const char v = m_format.getVisible() ? '1' : '0';
|
||||
writer.Stream() << writer.ind() << "<GeomIndex value=\"" << m_geomIndex << "\"/>" << endl;
|
||||
// style is deprecated in favour of line number, but we still save and restore it
|
||||
// to avoid problems with old documents.
|
||||
writer.Stream() << writer.ind() << "<Style value=\"" << m_format.m_style << "\"/>" << endl;
|
||||
writer.Stream() << writer.ind() << "<Weight value=\"" << m_format.m_weight << "\"/>" << endl;
|
||||
writer.Stream() << writer.ind() << "<Color value=\"" << m_format.m_color.asHexString() << "\"/>" << endl;
|
||||
writer.Stream() << writer.ind() << "<Style value=\"" << m_format.getStyle() << "\"/>" << endl;
|
||||
writer.Stream() << writer.ind() << "<Weight value=\"" << m_format.getWidth() << "\"/>" << endl;
|
||||
writer.Stream() << writer.ind() << "<Color value=\"" << m_format.getColor().asHexString() << "\"/>" << endl;
|
||||
writer.Stream() << writer.ind() << "<Visible value=\"" << v << "\"/>" << endl;
|
||||
writer.Stream() << writer.ind() << "<LineNumber value=\"" << m_format.getLineNumber() << "\"/>" << endl;
|
||||
}
|
||||
@@ -496,14 +442,16 @@ void GeomFormat::Restore(Base::XMLReader &reader)
|
||||
// style is deprecated in favour of line number, but we still save and restore it
|
||||
// to avoid problems with old documents.
|
||||
reader.readElement("Style");
|
||||
m_format.m_style = reader.getAttributeAsInteger("value");
|
||||
m_format.setStyle(reader.getAttributeAsInteger("value"));
|
||||
reader.readElement("Weight");
|
||||
m_format.m_weight = reader.getAttributeAsFloat("value");
|
||||
m_format.setWidth(reader.getAttributeAsFloat("value"));
|
||||
reader.readElement("Color");
|
||||
std::string temp = reader.getAttribute("value");
|
||||
m_format.m_color.fromHexString(temp);
|
||||
std::string tempHex = reader.getAttribute("value");
|
||||
App::Color tempColor;
|
||||
tempColor.fromHexString(tempHex);
|
||||
m_format.setColor(tempColor);
|
||||
reader.readElement("Visible");
|
||||
m_format.m_visible = (int)reader.getAttributeAsInteger("value")==0?false:true;
|
||||
m_format.setVisible((int)reader.getAttributeAsInteger("value") == 0 ? false : true);
|
||||
// older documents may not have the LineNumber element, so we need to check the
|
||||
// next entry. if it is a start element, then we check if it is a start element
|
||||
// for LineNumber.
|
||||
@@ -566,10 +514,10 @@ GeomFormat* GeomFormat::copy() const
|
||||
{
|
||||
GeomFormat* newFmt = new GeomFormat();
|
||||
newFmt->m_geomIndex = m_geomIndex;
|
||||
newFmt->m_format.m_style = m_format.m_style;
|
||||
newFmt->m_format.m_weight = m_format.m_weight;
|
||||
newFmt->m_format.m_color = m_format.m_color;
|
||||
newFmt->m_format.m_visible = m_format.m_visible;
|
||||
newFmt->m_format.setStyle(m_format.getStyle());
|
||||
newFmt->m_format.setWidth(m_format.getWidth());
|
||||
newFmt->m_format.setColor(m_format.getColor());
|
||||
newFmt->m_format.setVisible(m_format.getVisible());
|
||||
newFmt->m_format.setLineNumber(m_format.getLineNumber());
|
||||
return newFmt;
|
||||
}
|
||||
|
||||
@@ -31,54 +31,13 @@
|
||||
#include <Base/Vector3D.h>
|
||||
|
||||
#include "Geometry.h"
|
||||
|
||||
#include "LineFormat.h"
|
||||
|
||||
class TopoDS_Edge;
|
||||
|
||||
namespace TechDraw {
|
||||
class DrawViewPart;
|
||||
|
||||
|
||||
//general purpose line format specifier
|
||||
class TechDrawExport LineFormat
|
||||
{
|
||||
public:
|
||||
static constexpr size_t InvalidLine{0};
|
||||
|
||||
LineFormat();
|
||||
LineFormat(const int style,
|
||||
const double weight,
|
||||
const App::Color& color,
|
||||
const bool visible);
|
||||
~LineFormat() = default;
|
||||
|
||||
int getStyle() const { return m_style; }
|
||||
void setStyle(int style) { m_style = style; }
|
||||
double getWidth() const { return m_weight; }
|
||||
void setWidth(double width) {m_weight = width; }
|
||||
App::Color getColor() const { return m_color; }
|
||||
void setColor(App::Color color) { m_color = color; }
|
||||
QColor getQColor() const { return m_color.asValue<QColor>(); }
|
||||
void setQColor(QColor qColor) { m_color.set(qColor.redF(), qColor.greenF(), qColor.blueF(), 1.0 - qColor.alphaF()); }
|
||||
bool getVisible() const { return m_visible; }
|
||||
void setVisible(bool viz) { m_visible = viz; }
|
||||
int getLineNumber() const { return m_lineNumber; }
|
||||
void setLineNumber(int number) { m_lineNumber = number; }
|
||||
|
||||
int m_style;
|
||||
double m_weight;
|
||||
App::Color m_color;
|
||||
bool m_visible;
|
||||
int m_lineNumber {1};
|
||||
|
||||
static double getDefEdgeWidth();
|
||||
static App::Color getDefEdgeColor();
|
||||
static int getDefEdgeStyle();
|
||||
|
||||
void dump(const char* title);
|
||||
std::string toString() const;
|
||||
};
|
||||
|
||||
//********** CosmeticEdge ******************************************************
|
||||
|
||||
class TechDrawExport CosmeticEdge : public Base::Persistence, public TechDraw::BaseGeom
|
||||
@@ -99,6 +58,11 @@ public:
|
||||
TechDraw::BaseGeomPtr scaledAndRotatedGeometry(const double scale, const double rotDegrees);
|
||||
|
||||
static TechDraw::BaseGeomPtr makeCanonicalLine(DrawViewPart* dvp, Base::Vector3d start, Base::Vector3d end);
|
||||
static TechDraw::BaseGeomPtr makeLineFromCanonicalPoints(Base::Vector3d start, Base::Vector3d end);
|
||||
|
||||
LineFormat format() const { return m_format; }
|
||||
void setFormat(LineFormat newFormat) { m_format = newFormat; }
|
||||
|
||||
std::string toString() const override;
|
||||
void dump(const char* title) const;
|
||||
|
||||
@@ -108,7 +72,6 @@ public:
|
||||
void Restore(Base::XMLReader &/*reader*/) override;
|
||||
|
||||
PyObject *getPyObject() override;
|
||||
CosmeticEdge* copy() const;
|
||||
CosmeticEdge* clone() const;
|
||||
|
||||
Base::Vector3d permaStart; //persistent unscaled start/end points in View coords
|
||||
|
||||
@@ -15,16 +15,6 @@
|
||||
<Author Licence="LGPL" Name="WandererFan" EMail="wandererfan@gmail.com" />
|
||||
<UserDocu>CosmeticEdge specifies an extra (cosmetic) edge in Views</UserDocu>
|
||||
</Documentation>
|
||||
<Methode Name="clone" Const="true">
|
||||
<Documentation>
|
||||
<UserDocu>Create a clone of this CosmeticEdge</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="copy" Const="true">
|
||||
<Documentation>
|
||||
<UserDocu>Create a copy of this CosmeticEdge</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Attribute Name="Tag" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Gives the tag of the CosmeticEdge as string.</UserDocu>
|
||||
|
||||
@@ -62,59 +62,59 @@ int CosmeticEdgePy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
|
||||
}
|
||||
|
||||
//From Part::GeometryPy.cpp
|
||||
PyObject* CosmeticEdgePy::clone(PyObject *args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
return nullptr;
|
||||
// PyObject* CosmeticEdgePy::clone(PyObject *args)
|
||||
// {
|
||||
// if (!PyArg_ParseTuple(args, ""))
|
||||
// return nullptr;
|
||||
|
||||
TechDraw::CosmeticEdge* geom = this->getCosmeticEdgePtr();
|
||||
PyTypeObject* type = this->GetType();
|
||||
PyObject* cpy = nullptr;
|
||||
// let the type object decide
|
||||
if (type->tp_new)
|
||||
cpy = type->tp_new(type, this, nullptr);
|
||||
if (!cpy) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "failed to create clone of CosmeticEdge");
|
||||
return nullptr;
|
||||
}
|
||||
// TechDraw::CosmeticEdge* geom = this->getCosmeticEdgePtr();
|
||||
// PyTypeObject* type = this->GetType();
|
||||
// PyObject* cpy = nullptr;
|
||||
// // let the type object decide
|
||||
// if (type->tp_new)
|
||||
// cpy = type->tp_new(type, this, nullptr);
|
||||
// if (!cpy) {
|
||||
// PyErr_SetString(PyExc_RuntimeError, "failed to create clone of CosmeticEdge");
|
||||
// return nullptr;
|
||||
// }
|
||||
|
||||
TechDraw::CosmeticEdgePy* geompy = static_cast<TechDraw::CosmeticEdgePy*>(cpy);
|
||||
// the PyMake function must have created the corresponding instance of the 'CosmeticEdge' subclass
|
||||
// so delete it now to avoid a memory leak
|
||||
if (geompy->_pcTwinPointer) {
|
||||
TechDraw::CosmeticEdge* clone = static_cast<TechDraw::CosmeticEdge*>(geompy->_pcTwinPointer);
|
||||
delete clone;
|
||||
}
|
||||
geompy->_pcTwinPointer = geom->clone();
|
||||
return cpy;
|
||||
}
|
||||
// TechDraw::CosmeticEdgePy* geompy = static_cast<TechDraw::CosmeticEdgePy*>(cpy);
|
||||
// // the PyMake function must have created the corresponding instance of the 'CosmeticEdge' subclass
|
||||
// // so delete it now to avoid a memory leak
|
||||
// if (geompy->_pcTwinPointer) {
|
||||
// TechDraw::CosmeticEdge* clone = static_cast<TechDraw::CosmeticEdge*>(geompy->_pcTwinPointer);
|
||||
// delete clone;
|
||||
// }
|
||||
// geompy->_pcTwinPointer = geom->clone();
|
||||
// return cpy;
|
||||
// }
|
||||
|
||||
PyObject* CosmeticEdgePy::copy(PyObject *args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
return nullptr;
|
||||
// PyObject* CosmeticEdgePy::copy(PyObject *args)
|
||||
// {
|
||||
// if (!PyArg_ParseTuple(args, ""))
|
||||
// return nullptr;
|
||||
|
||||
TechDraw::CosmeticEdge* geom = this->getCosmeticEdgePtr();
|
||||
PyTypeObject* type = this->GetType();
|
||||
PyObject* cpy = nullptr;
|
||||
// let the type object decide
|
||||
if (type->tp_new)
|
||||
cpy = type->tp_new(type, this, nullptr);
|
||||
if (!cpy) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "failed to create copy of CosmeticEdge");
|
||||
return nullptr;
|
||||
}
|
||||
// TechDraw::CosmeticEdge* ce = this->getCosmeticEdgePtr();
|
||||
// PyTypeObject* type = this->GetType();
|
||||
// PyObject* cpy = nullptr;
|
||||
// // let the type object decide
|
||||
// if (type->tp_new)
|
||||
// cpy = type->tp_new(type, this, nullptr);
|
||||
// if (!cpy) {
|
||||
// PyErr_SetString(PyExc_RuntimeError, "failed to create copy of CosmeticEdge");
|
||||
// return nullptr;
|
||||
// }
|
||||
|
||||
TechDraw::CosmeticEdgePy* geompy = static_cast<TechDraw::CosmeticEdgePy*>(cpy);
|
||||
// the PyMake function must have created the corresponding instance of the 'CosmeticEdge' subclass
|
||||
// so delete it now to avoid a memory leak
|
||||
if (geompy->_pcTwinPointer) {
|
||||
TechDraw::CosmeticEdge* copy = static_cast<TechDraw::CosmeticEdge*>(geompy->_pcTwinPointer);
|
||||
delete copy;
|
||||
}
|
||||
geompy->_pcTwinPointer = geom->copy();
|
||||
return cpy;
|
||||
}
|
||||
// TechDraw::CosmeticEdgePy* geompy = static_cast<TechDraw::CosmeticEdgePy*>(cpy);
|
||||
// // the PyMake function must have created the corresponding instance of the 'CosmeticEdge' subclass
|
||||
// // so delete it now to avoid a memory leak
|
||||
// if (geompy->_pcTwinPointer) {
|
||||
// TechDraw::CosmeticEdge* copy = static_cast<TechDraw::CosmeticEdge*>(geompy->_pcTwinPointer);
|
||||
// delete copy;
|
||||
// }
|
||||
// geompy->_pcTwinPointer = ce->copy();
|
||||
// return cpy;
|
||||
// }
|
||||
|
||||
void CosmeticEdgePy::setFormat(Py::Dict arg)
|
||||
{
|
||||
@@ -131,10 +131,10 @@ void CosmeticEdgePy::setFormat(Py::Dict arg)
|
||||
}
|
||||
|
||||
TechDraw::LineFormat* format = &(this->getCosmeticEdgePtr()->m_format);
|
||||
format->m_style = style;
|
||||
format->m_weight = weight;
|
||||
format->m_color = DrawUtil::pyTupleToColor(pColor);
|
||||
format->m_visible = Base::asBoolean(visible);
|
||||
format->setStyle(style);
|
||||
format->setWidth(weight);
|
||||
format->setColor(DrawUtil::pyTupleToColor(pColor));
|
||||
format->setVisible(Base::asBoolean(visible));
|
||||
}
|
||||
|
||||
Py::Dict CosmeticEdgePy::getFormat() const
|
||||
@@ -142,10 +142,10 @@ Py::Dict CosmeticEdgePy::getFormat() const
|
||||
TechDraw::LineFormat* format= &(this->getCosmeticEdgePtr()->m_format);
|
||||
Py::Dict dict;
|
||||
|
||||
dict.setItem("style", Py::Long(format->m_style));
|
||||
dict.setItem("weight", Py::Float(format->m_weight));
|
||||
dict.setItem("color", Py::Tuple(DrawUtil::colorToPyTuple(format->m_color), true));
|
||||
dict.setItem("visible", Py::Boolean(format->m_visible));
|
||||
dict.setItem("style", Py::Long(format->getStyle()));
|
||||
dict.setItem("weight", Py::Float(format->getWidth()));
|
||||
dict.setItem("color", Py::Tuple(DrawUtil::colorToPyTuple(format->getColor()), true));
|
||||
dict.setItem("visible", Py::Boolean(format->getVisible()));
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
@@ -62,6 +62,35 @@ TechDraw::DrawViewPart* CosmeticExtension::getOwner()
|
||||
return static_cast<TechDraw::DrawViewPart*>(getExtendedObject());
|
||||
}
|
||||
|
||||
//! remove cosmetic elements for a list of subelement names
|
||||
void CosmeticExtension::deleteCosmeticElements(std::vector<std::string> removables)
|
||||
{
|
||||
// Base::Console().Message("CEx::deleteCosmeticElements(%d removables)\n", removables.size());
|
||||
for (auto& name : removables) {
|
||||
if (DU::getGeomTypeFromName(name) == "Vertex" &&
|
||||
DU::isCosmeticVertex(getOwner(), name)) {
|
||||
CosmeticVertex* vert = getCosmeticVertexBySelection(name);
|
||||
removeCosmeticVertex(vert->getTagAsString());
|
||||
continue;
|
||||
}
|
||||
if (DU::getGeomTypeFromName(name) == "Edge" &&
|
||||
( DU::isCosmeticEdge(getOwner(), name) ||
|
||||
DU::isCenterLine(getOwner(), name) ) ) {
|
||||
CosmeticEdge* edge = getCosmeticEdgeBySelection(name);
|
||||
if (edge) {
|
||||
// if not edge, something has gone very wrong!
|
||||
removeCosmeticEdge(edge->getTagAsString());
|
||||
continue;
|
||||
}
|
||||
CenterLine* line = getCenterLineBySelection(name);
|
||||
if (line) {
|
||||
removeCenterLine(line->getTagAsString());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
//CosmeticVertex x, y are stored as unscaled, but mirrored (inverted Y) values.
|
||||
//if you are creating a CV based on calculations of scaled geometry, you need to
|
||||
@@ -161,13 +190,18 @@ int CosmeticExtension::getCVIndex(const std::string& tag)
|
||||
}
|
||||
|
||||
/// adds a cosmetic vertex to the property list. does not add to display geometry until dvp executes.
|
||||
/// returns unique CV id
|
||||
std::string CosmeticExtension::addCosmeticVertex(const Base::Vector3d& pos)
|
||||
/// returns unique CV id. if the pos parameter is in real world coordinates, then invert should be true
|
||||
/// (the default). if pos is in TD geometry or scene coordinates, then it is already inverted, and
|
||||
/// invert should be set to false.
|
||||
std::string CosmeticExtension::addCosmeticVertex(const Base::Vector3d& pos, bool invert)
|
||||
{
|
||||
// Base::Console().Message("CEx::addCosmeticVertex(%s)\n",
|
||||
// DrawUtil::formatVector(pos).c_str());
|
||||
std::vector<CosmeticVertex*> verts = CosmeticVertexes.getValues();
|
||||
Base::Vector3d tempPos = DrawUtil::invertY(pos);
|
||||
Base::Vector3d tempPos = pos;
|
||||
if (invert) {
|
||||
tempPos = DrawUtil::invertY(pos);
|
||||
}
|
||||
TechDraw::CosmeticVertex* cv = new TechDraw::CosmeticVertex(tempPos);
|
||||
verts.push_back(cv);
|
||||
CosmeticVertexes.setValues(verts);
|
||||
@@ -393,6 +427,8 @@ void CosmeticExtension::removeCosmeticEdge(const std::string& delTag)
|
||||
/// remove the cosmetic edges with the given tags from the list property
|
||||
void CosmeticExtension::removeCosmeticEdge(const std::vector<std::string>& delTags)
|
||||
{
|
||||
// Base::Console().Message("DVP::removeCE(%d tages)\n", delTags.size());
|
||||
std::vector<CosmeticEdge*> cEdges = CosmeticEdges.getValues();
|
||||
for (auto& t: delTags) {
|
||||
removeCosmeticEdge(t);
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ public:
|
||||
virtual CosmeticVertex* getCosmeticVertex(const std::string& tag) const;
|
||||
virtual int add1CVToGV(const std::string& tag);
|
||||
virtual int getCVIndex(const std::string& tag);
|
||||
virtual std::string addCosmeticVertex(const Base::Vector3d& pos);
|
||||
virtual std::string addCosmeticVertex(const Base::Vector3d& pos, bool invert = true);
|
||||
virtual void addCosmeticVertexesToGeom();
|
||||
virtual void clearCosmeticVertexes();
|
||||
virtual void refreshCVGeoms();
|
||||
@@ -95,6 +95,8 @@ public:
|
||||
virtual void removeGeomFormat(const std::string& tag);
|
||||
virtual void clearGeomFormats();
|
||||
|
||||
void deleteCosmeticElements(std::vector<std::string> removables);
|
||||
|
||||
TechDraw::DrawViewPart* getOwner();
|
||||
|
||||
PyObject* getExtensionPyObject() override;
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
//! CosmeticVertex point is stored in unscaled, unrotated form
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#include <boost/uuid/uuid_generators.hpp>
|
||||
@@ -46,14 +48,9 @@ TYPESYSTEM_SOURCE(TechDraw::CosmeticVertex, Base::Persistence)
|
||||
|
||||
CosmeticVertex::CosmeticVertex() : TechDraw::Vertex()
|
||||
{
|
||||
point(Base::Vector3d(0.0, 0.0, 0.0));
|
||||
permaPoint = Base::Vector3d(0.0, 0.0, 0.0);
|
||||
linkGeom = -1;
|
||||
color = Preferences::vertexColor();
|
||||
size = Preferences::vertexScale() *
|
||||
LineGroup::getDefaultWidth("Thin");
|
||||
style = 1;
|
||||
visible = true;
|
||||
hlrVisible = true;
|
||||
cosmetic = true;
|
||||
|
||||
@@ -76,7 +73,6 @@ CosmeticVertex::CosmeticVertex(const TechDraw::CosmeticVertex* cv) : TechDraw::V
|
||||
|
||||
CosmeticVertex::CosmeticVertex(const Base::Vector3d& loc) : TechDraw::Vertex(loc)
|
||||
{
|
||||
// Base::Console().Message("CV::CV(%s)\n", DU::formatVector(loc).c_str());
|
||||
permaPoint = loc;
|
||||
linkGeom = -1;
|
||||
color = Preferences::vertexColor();
|
||||
@@ -93,21 +89,17 @@ CosmeticVertex::CosmeticVertex(const Base::Vector3d& loc) : TechDraw::Vertex(loc
|
||||
|
||||
void CosmeticVertex::move(const Base::Vector3d& newPos)
|
||||
{
|
||||
permaPoint = newPos;
|
||||
point(newPos);
|
||||
}
|
||||
|
||||
void CosmeticVertex::moveRelative(const Base::Vector3d& movement)
|
||||
{
|
||||
permaPoint += movement;
|
||||
point( point() += movement);
|
||||
}
|
||||
|
||||
std::string CosmeticVertex::toString() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << permaPoint.x << ", " <<
|
||||
permaPoint.y << ", " <<
|
||||
permaPoint.z << ", " <<
|
||||
" / ";
|
||||
ss << point().x << ", " <<
|
||||
point().y << ", " <<
|
||||
point().z << ", " <<
|
||||
@@ -181,13 +173,15 @@ Base::Vector3d CosmeticVertex::scaled(const double factor)
|
||||
return permaPoint * factor;
|
||||
}
|
||||
|
||||
//! returns a transformed version of our coordinates (permaPoint)
|
||||
Base::Vector3d CosmeticVertex::rotatedAndScaled(const double scale, const double rotDegrees)
|
||||
{
|
||||
Base::Vector3d scaledPoint = scaled(scale);
|
||||
if (rotDegrees != 0.0) {
|
||||
// invert the Y coordinate so the rotation math works out
|
||||
// the stored point is inverted
|
||||
scaledPoint = DU::invertY(scaledPoint);
|
||||
scaledPoint.RotateZ(rotDegrees * M_PI / 180.0);
|
||||
scaledPoint.RotateZ(rotDegrees * M_PI / DegreesHalfCircle);
|
||||
scaledPoint = DU::invertY(scaledPoint);
|
||||
}
|
||||
return scaledPoint;
|
||||
@@ -198,13 +192,12 @@ Base::Vector3d CosmeticVertex::rotatedAndScaled(const double scale, const double
|
||||
//! inverted back on return.
|
||||
Base::Vector3d CosmeticVertex::makeCanonicalPoint(DrawViewPart* dvp, Base::Vector3d point, bool unscale)
|
||||
{
|
||||
// Base::Console().Message("CV::makeCanonicalPoint(%s)\n", DU::formatVector(point).c_str());
|
||||
double rotDeg = dvp->Rotation.getValue();
|
||||
|
||||
Base::Vector3d result = point;
|
||||
if (rotDeg != 0.0) {
|
||||
// unrotate the point
|
||||
double rotRad = rotDeg * M_PI / 180.0;
|
||||
double rotRad = rotDeg * M_PI / DegreesHalfCircle;
|
||||
// we always rotate around the origin.
|
||||
result.RotateZ(-rotRad);
|
||||
}
|
||||
@@ -219,6 +212,16 @@ Base::Vector3d CosmeticVertex::makeCanonicalPoint(DrawViewPart* dvp, Base::Vecto
|
||||
return result;
|
||||
}
|
||||
|
||||
//! a version of makeCanonicalPoint that accepts and returns an invertedPoint.
|
||||
Base::Vector3d CosmeticVertex::makeCanonicalPointInverted(DrawViewPart* dvp, Base::Vector3d invertedPoint, bool unscale)
|
||||
{
|
||||
Base::Vector3d result = makeCanonicalPoint(dvp,
|
||||
DU::invertY(invertedPoint),
|
||||
unscale);
|
||||
return DU::invertY(result);
|
||||
}
|
||||
|
||||
|
||||
boost::uuids::uuid CosmeticVertex::getTag() const
|
||||
{
|
||||
return tag;
|
||||
|
||||
@@ -47,6 +47,8 @@ public:
|
||||
CosmeticVertex(const Base::Vector3d& loc);
|
||||
~CosmeticVertex() override = default;
|
||||
|
||||
Base::Vector3d point() const { return permaPoint; };
|
||||
void point(Base::Vector3d newPoint) { permaPoint = newPoint; }
|
||||
void move(const Base::Vector3d& newPos);
|
||||
void moveRelative(const Base::Vector3d& movement);
|
||||
|
||||
@@ -56,6 +58,7 @@ public:
|
||||
Base::Vector3d rotatedAndScaled(const double scale, const double rotDegrees);
|
||||
|
||||
static Base::Vector3d makeCanonicalPoint(DrawViewPart* dvp, Base::Vector3d point, bool unscale = true);
|
||||
static Base::Vector3d makeCanonicalPointInverted(DrawViewPart* dvp, Base::Vector3d invertedPoint, bool unscale = true);
|
||||
static bool restoreCosmetic();
|
||||
|
||||
// Persistence implementer ---------------------
|
||||
@@ -67,13 +70,13 @@ public:
|
||||
CosmeticVertex* copy() const;
|
||||
CosmeticVertex* clone() const;
|
||||
|
||||
Base::Vector3d permaPoint; //permanent, unscaled value
|
||||
int linkGeom; //connection to corresponding "geom" Vertex (fragile - index based!)
|
||||
Base::Vector3d permaPoint{Base::Vector3d()}; //permanent, unscaled value
|
||||
int linkGeom{-1}; //connection to corresponding "geom" Vertex (fragile - index based!)
|
||||
//better to do reverse search for CosmeticTag in vertex geometry
|
||||
App::Color color;
|
||||
double size;
|
||||
int style;
|
||||
bool visible; //base class vertex also has visible property
|
||||
App::Color color{App::Color()};
|
||||
double size{1.0};
|
||||
int style{1};
|
||||
bool visible{true}; //base class vertex also has visible property
|
||||
|
||||
boost::uuids::uuid getTag() const;
|
||||
std::string getTagAsString() const override;
|
||||
|
||||
@@ -20,19 +20,29 @@
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
//! DrawLeaderLine - a class for storing leader line attributes and providing methods to apply transformations on leader geometry.
|
||||
//! Waypoints are to be stored as displacements from the first Waypoint in printed page coordinates (mm, conventional
|
||||
//! X and Y axes, (0, 0) at lower left). The first Waypoint is set to (0,0) after the displacements are calculated.
|
||||
//! The leader's X,Y position is relative to the parent's origin. The X,Y position is unrotated and unscaled.
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#include <App/Document.h>
|
||||
#include <Base/Console.h>
|
||||
#include <Base/Parameter.h>
|
||||
|
||||
#include "DrawViewPart.h"
|
||||
#include "DrawPage.h"
|
||||
#include "DrawLeaderLine.h"
|
||||
#include "DrawLeaderLinePy.h" // generated from DrawLeaderLinePy.xml
|
||||
#include "ArrowPropEnum.h"
|
||||
#include "DrawView.h"
|
||||
#include "Preferences.h"
|
||||
#include "DrawUtil.h"
|
||||
|
||||
|
||||
using namespace TechDraw;
|
||||
using DU = DrawUtil;
|
||||
|
||||
//===========================================================================
|
||||
// DrawLeaderLine - Base class for drawing leader based features
|
||||
@@ -66,26 +76,26 @@ DrawLeaderLine::DrawLeaderLine()
|
||||
{
|
||||
static const char *group = "Leader";
|
||||
|
||||
constexpr long int FilledArrow{0l};
|
||||
constexpr long int NoEnd{7l};
|
||||
|
||||
ADD_PROPERTY_TYPE(LeaderParent, (nullptr), group, (App::PropertyType)(App::Prop_None),
|
||||
"View to which this leader is attached");
|
||||
LeaderParent.setScope(App::LinkScope::Global);
|
||||
ADD_PROPERTY_TYPE(WayPoints, (Base::Vector3d()) ,group, App::Prop_None,
|
||||
"Intermediate points for Leader line");
|
||||
|
||||
// EndType.setEnums(ArrowTypeEnums);
|
||||
// ADD_PROPERTY(EndType, (prefEnd()));
|
||||
|
||||
StartSymbol.setEnums(ArrowPropEnum::ArrowTypeEnums);
|
||||
ADD_PROPERTY(StartSymbol, (0l)); //filled arrow
|
||||
ADD_PROPERTY(StartSymbol, (FilledArrow)); //filled arrow
|
||||
|
||||
// ADD_PROPERTY_TYPE(StartSymbol, (0), group, App::Prop_None, "Symbol (arrowhead) for start of line");
|
||||
EndSymbol.setEnums(ArrowPropEnum::ArrowTypeEnums);
|
||||
ADD_PROPERTY(EndSymbol, (7l)); //no symbol
|
||||
// ADD_PROPERTY_TYPE(EndSymbol, (0), group, App::Prop_None, "Symbol (arrowhead) for end of line");
|
||||
|
||||
ADD_PROPERTY(EndSymbol, (NoEnd)); //no symbol
|
||||
|
||||
ADD_PROPERTY_TYPE(Scalable ,(false), group, App::Prop_None, "Scale line with LeaderParent");
|
||||
ADD_PROPERTY_TYPE(AutoHorizontal ,(getDefAuto()), group, App::Prop_None, "Forces last line segment to be horizontal");
|
||||
ADD_PROPERTY_TYPE(RotatesWithParent ,(true), group, App::Prop_None,
|
||||
"If true, leader rotates around parent. If false, only first segment of leader changes with parent rotation.");
|
||||
|
||||
|
||||
//hide the DrawView properties that don't apply to Leader
|
||||
ScaleType.setStatus(App::Property::ReadOnly, true);
|
||||
@@ -108,12 +118,16 @@ void DrawLeaderLine::onChanged(const App::Property* prop)
|
||||
short DrawLeaderLine::mustExecute() const
|
||||
{
|
||||
if (!isRestoring() && LeaderParent.isTouched()) {
|
||||
return true; // Property changed
|
||||
return 1; // Property changed
|
||||
}
|
||||
|
||||
const App::DocumentObject* docObj = getBaseObject();
|
||||
if (docObj && docObj->isTouched()) {
|
||||
return true; // Object property points to is touched
|
||||
return 1; // Object property points to is touched
|
||||
}
|
||||
|
||||
if (WayPoints.isTouched()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return DrawView::mustExecute();
|
||||
@@ -121,11 +135,13 @@ short DrawLeaderLine::mustExecute() const
|
||||
|
||||
App::DocumentObjectExecReturn *DrawLeaderLine::execute()
|
||||
{
|
||||
// Base::Console().Message("DLL::execute()\n");
|
||||
// Base::Console().Message("DLL::execute()\n");
|
||||
if (!keepUpdated()) {
|
||||
return App::DocumentObject::StdReturn;
|
||||
}
|
||||
adjustLastSegment();
|
||||
|
||||
// is horizLastSegment something that should be done only at draw time?
|
||||
horizLastSegment();
|
||||
overrideKeepUpdated(false);
|
||||
return DrawView::execute();
|
||||
}
|
||||
@@ -137,7 +153,7 @@ DrawView* DrawLeaderLine::getBaseView() const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DrawView* cast = dynamic_cast<DrawView*>(baseObj);
|
||||
auto cast = dynamic_cast<DrawView*>(baseObj);
|
||||
return cast;
|
||||
}
|
||||
|
||||
@@ -155,8 +171,6 @@ bool DrawLeaderLine::keepUpdated()
|
||||
return view->keepUpdated();
|
||||
}
|
||||
|
||||
//need separate getParentScale()???
|
||||
|
||||
double DrawLeaderLine::getBaseScale() const
|
||||
{
|
||||
// Base::Console().Message("DLL::getBaseScale()\n");
|
||||
@@ -174,11 +188,7 @@ double DrawLeaderLine::getScale() const
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
DrawView* parent = getBaseView();
|
||||
if (!parent) {
|
||||
return 1.0;
|
||||
}
|
||||
return parent->getScale();
|
||||
return getBaseScale();
|
||||
}
|
||||
|
||||
Base::Vector3d DrawLeaderLine::getAttachPoint()
|
||||
@@ -190,23 +200,37 @@ Base::Vector3d DrawLeaderLine::getAttachPoint()
|
||||
);
|
||||
}
|
||||
|
||||
void DrawLeaderLine::adjustLastSegment()
|
||||
//! unit agnostic conversion of last segment to horizontal. need to do this at drawing time otherwise
|
||||
//! we just realign the canonical form.
|
||||
void DrawLeaderLine::horizLastSegment()
|
||||
{
|
||||
// Base::Console().Message("DLL::adjustLastSegment()\n");
|
||||
bool adjust = AutoHorizontal.getValue();
|
||||
std::vector<Base::Vector3d> wp = WayPoints.getValues();
|
||||
if (adjust && wp.size() > 1) {
|
||||
int iLast = wp.size() - 1;
|
||||
int iPen = wp.size() - 2;
|
||||
// Base::Console().Message("DLL::horizLastSegment() - auto: %d\n", AutoHorizontal.getValue());
|
||||
bool adjust = AutoHorizontal.getValue();
|
||||
if (!adjust) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto temp = horizLastSegment(WayPoints.getValues());
|
||||
WayPoints.setValues(temp);
|
||||
}
|
||||
|
||||
std::vector<Base::Vector3d> DrawLeaderLine::horizLastSegment(const std::vector<Base::Vector3d>& inDeltas)
|
||||
{
|
||||
// Base::Console().Message("DLL::horizLastSegment(in: %d)\n", inDeltas.size());
|
||||
|
||||
std::vector<Base::Vector3d> wp = inDeltas;
|
||||
if (wp.size() > 1) {
|
||||
size_t iLast = wp.size() - 1;
|
||||
size_t iPen = wp.size() - 2;
|
||||
Base::Vector3d last = wp.at(iLast);
|
||||
Base::Vector3d penUlt = wp.at(iPen);
|
||||
last.y = penUlt.y;
|
||||
wp.at(iLast) = last;
|
||||
}
|
||||
WayPoints.setValues(wp);
|
||||
return wp;
|
||||
}
|
||||
|
||||
//middle of last line segment
|
||||
//! returns the mid point of last segment. used by leader decorators like weld symbol.
|
||||
Base::Vector3d DrawLeaderLine::getTileOrigin() const
|
||||
{
|
||||
std::vector<Base::Vector3d> wp = WayPoints.getValues();
|
||||
@@ -215,17 +239,17 @@ Base::Vector3d DrawLeaderLine::getTileOrigin() const
|
||||
Base::Vector3d second = wp.rbegin()[1];
|
||||
return (last + second) / 2.0;
|
||||
}
|
||||
|
||||
|
||||
Base::Console().Warning("DLL::getTileOrigin - no waypoints\n");
|
||||
return Base::Vector3d();
|
||||
}
|
||||
|
||||
//start of last line segment
|
||||
//! returns start of last line segment
|
||||
Base::Vector3d DrawLeaderLine::getKinkPoint() const
|
||||
{
|
||||
std::vector<Base::Vector3d> wp = WayPoints.getValues();
|
||||
if (wp.size() > 1) {
|
||||
return wp.rbegin()[1]; // Second
|
||||
return wp.rbegin()[1]; // second point from end
|
||||
}
|
||||
|
||||
Base::Console().Warning("DLL::getKinkPoint - no waypoints\n");
|
||||
@@ -239,12 +263,180 @@ Base::Vector3d DrawLeaderLine::getTailPoint() const
|
||||
if (!wp.empty()) {
|
||||
return wp.rbegin()[0]; // Last
|
||||
}
|
||||
|
||||
|
||||
Base::Console().Warning("DLL::getTailPoint - no waypoints\n");
|
||||
return Base::Vector3d();
|
||||
}
|
||||
|
||||
|
||||
//! create a new leader feature from parameters. Used by python method makeLeader.
|
||||
//! pagePoints are in mm from bottom left of page.
|
||||
DrawLeaderLine* DrawLeaderLine::makeLeader(DrawViewPart* parent, std::vector<Base::Vector3d> pagePoints, int iStartSymbol, int iEndSymbol)
|
||||
{
|
||||
// Base::Console().Message("DLL::makeLeader(%s, %d, %d, %d)\n", parent->getNameInDocument(), pagePoints.size(), iStartSymbol, iEndSymbol);
|
||||
if (pagePoints.size() < 2) {
|
||||
Base::Console().Message("DLL::makeLeader - not enough pagePoints\n");
|
||||
return {};
|
||||
}
|
||||
|
||||
// this is +/- the same code as in TaskLeaderLine::createLeaderFeature()
|
||||
const std::string objectName{"LeaderLine"};
|
||||
const std::string leaderType = "TechDraw::DrawLeaderLine";
|
||||
std::string leaderName = parent->getDocument()->getUniqueObjectName(objectName.c_str());
|
||||
std::string pageName = parent->findParentPage()->getNameInDocument();
|
||||
std::string parentName = parent->getNameInDocument();
|
||||
|
||||
Base::Interpreter().runStringArg("App.activeDocument().addObject('%s', '%s')",
|
||||
leaderType.c_str(), leaderName.c_str());
|
||||
Base::Interpreter().runStringArg("App.activeDocument().%s.translateLabel('DrawLeaderLine', 'LeaderLine', '%s')",
|
||||
leaderName.c_str(), leaderName.c_str());
|
||||
Base::Interpreter().runStringArg("App.activeDocument().%s.addView(App.activeDocument().%s)",
|
||||
pageName.c_str(), leaderName.c_str());
|
||||
Base::Interpreter().runStringArg("App.activeDocument().%s.LeaderParent = App.activeDocument().%s",
|
||||
leaderName.c_str(), parentName.c_str());
|
||||
// we assume here that the caller will handle AutoHorizontal, Scalable and Rotatable as required
|
||||
|
||||
|
||||
App::DocumentObject* obj = parent->getDocument()->getObject(leaderName.c_str());
|
||||
if (!obj || !obj->isDerivedFrom(TechDraw::DrawLeaderLine::getClassTypeId())) {
|
||||
throw Base::RuntimeError("DrawLeaderLine::makeLeader - new object not found");
|
||||
}
|
||||
|
||||
// set leader x,y position
|
||||
auto leaderFeature = static_cast<TechDraw::DrawLeaderLine*>(obj);
|
||||
Base::Vector3d parentPagePos{ parent->X.getValue(), parent->Y.getValue(), 0.0};
|
||||
Base::Vector3d leaderPagePos = pagePoints.front() - parentPagePos;
|
||||
bool force = true; // update position even though leaders default to locked.
|
||||
leaderFeature->setPosition(leaderPagePos.x, leaderPagePos.y, force);
|
||||
|
||||
// page positions to deltas
|
||||
std::vector<Base::Vector3d> pageDeltas;
|
||||
for (auto& point : pagePoints) {
|
||||
auto temp = point - pagePoints.front();
|
||||
pageDeltas.emplace_back(temp);
|
||||
}
|
||||
|
||||
// deltas to unscaled, unrotated form
|
||||
auto leaderPoints = leaderFeature->makeCanonicalPoints(pageDeltas);
|
||||
// invert the canonical points
|
||||
std::vector<Base::Vector3d> inverted;
|
||||
inverted.reserve(leaderPoints.size());
|
||||
for (auto& point : leaderPoints) {
|
||||
inverted.push_back(DU::invertY(point));
|
||||
}
|
||||
leaderFeature->WayPoints.setValues(inverted);
|
||||
|
||||
leaderFeature->StartSymbol.setValue(iStartSymbol);
|
||||
leaderFeature->EndSymbol.setValue(iEndSymbol);
|
||||
|
||||
parent->touch();
|
||||
|
||||
return leaderFeature;
|
||||
}
|
||||
|
||||
//! return scaled and rotated copies of the WayPoints (page position deltas from 1st point)
|
||||
//! used by QGILL.
|
||||
std::vector<Base::Vector3d> DrawLeaderLine::getScaledAndRotatedPoints(bool doScale, bool doRotate) const
|
||||
{
|
||||
// Base::Console().Message("DLL::getScaledAndRotatedPoints(%d, %d)\n", doScale, doRotate);
|
||||
auto dvp = getBaseView();
|
||||
if (!dvp) {
|
||||
// document is restoring?
|
||||
// Base::Console().Message("DLL::getScaledAndRotatedPoints - no DV\n");
|
||||
return {};
|
||||
}
|
||||
|
||||
double scale{1.0};
|
||||
if (Scalable.getValue() && doScale) {
|
||||
scale = dvp->getScale();
|
||||
}
|
||||
|
||||
double rotationRad{0.0};
|
||||
if (doRotate) {
|
||||
rotationRad = dvp->Rotation.getValue() * M_PI / DegreesHalfCircle;
|
||||
}
|
||||
|
||||
std::vector<Base::Vector3d> pointsAll = WayPoints.getValues();
|
||||
std::vector<Base::Vector3d> result;
|
||||
for (auto& point : pointsAll) {
|
||||
Base::Vector3d newPoint = DU::invertY(point * scale);
|
||||
if (rotationRad != 0.0) {
|
||||
// the waypoints use conventional coords
|
||||
newPoint.RotateZ(rotationRad);
|
||||
}
|
||||
result.push_back(DU::invertY(newPoint));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//! return unscaled and unrotated versions of the input points. input is expected to in mm (Rez::appX()),
|
||||
//! and conventional Y axis (+ up)
|
||||
//! used by QGILL.
|
||||
std::vector<Base::Vector3d>
|
||||
DrawLeaderLine::makeCanonicalPoints(const std::vector<Base::Vector3d>& inPoints,
|
||||
bool doScale,
|
||||
bool doRotate) const
|
||||
{
|
||||
// Base::Console().Message("DLL::makeCanonicalPoints(%d, %d, %d)\n", inPoints.size(), doScale, doRotate);
|
||||
auto dvp = getBaseView();
|
||||
|
||||
double scale{1.0};
|
||||
if (Scalable.getValue() && doScale) {
|
||||
scale = dvp->getScale();
|
||||
}
|
||||
|
||||
double rotationRad{0.0};
|
||||
if (doRotate) {
|
||||
rotationRad = - dvp->Rotation.getValue() * M_PI / DegreesHalfCircle;
|
||||
}
|
||||
|
||||
std::vector<Base::Vector3d> result;
|
||||
for (auto& point : inPoints) {
|
||||
Base::Vector3d newPoint = point / scale;
|
||||
if (rotationRad != 0.0) {
|
||||
newPoint.RotateZ(rotationRad);
|
||||
}
|
||||
result.push_back(newPoint);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//! as makeCanonicalPoints, but accepts and returns inverted points
|
||||
std::vector<Base::Vector3d>
|
||||
DrawLeaderLine::makeCanonicalPointsInverted(const std::vector<Base::Vector3d>& inPoints,
|
||||
bool doScale,
|
||||
bool doRotate) const
|
||||
{
|
||||
std::vector<Base::Vector3d> conventionalPoints;
|
||||
conventionalPoints.reserve(inPoints.size());
|
||||
for (auto& point : inPoints) {
|
||||
conventionalPoints.push_back(DU::invertY(point));
|
||||
}
|
||||
auto conventionalCanon = makeCanonicalPoints(inPoints, doScale, doRotate);
|
||||
std::vector<Base::Vector3d> invertedPoints;
|
||||
invertedPoints.reserve(inPoints.size());
|
||||
for (auto& point : conventionalCanon) {
|
||||
invertedPoints.push_back(DU::invertY(point));
|
||||
}
|
||||
return invertedPoints;
|
||||
}
|
||||
|
||||
//! returns true if parent exists. if parent is a DVP it must have geometry.
|
||||
bool DrawLeaderLine::isParentReady() const
|
||||
{
|
||||
TechDraw::DrawView* parent = getBaseView();
|
||||
auto dvp = dynamic_cast<TechDraw::DrawViewPart*>(parent);
|
||||
if (!parent || (dvp && !dvp->hasGeometry())) {
|
||||
// still restoring or
|
||||
// we are attached to a dvp that has no geometry, so don't bother trying to draw yet
|
||||
Base::Console().Message("DLL:: - no parent or geometry\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DrawLeaderLine::getDefAuto() const
|
||||
{
|
||||
return Preferences::getPreferenceGroup("LeaderLine")->GetBool("AutoHorizontal", true);
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
|
||||
namespace TechDraw
|
||||
{
|
||||
class DrawViewPart;
|
||||
|
||||
class TechDrawExport DrawLeaderLine : public TechDraw::DrawView
|
||||
{
|
||||
@@ -47,14 +48,13 @@ public:
|
||||
App::PropertyEnumeration StartSymbol;
|
||||
App::PropertyEnumeration EndSymbol;
|
||||
|
||||
/* App::PropertyInteger StartSymbol; //see Gui/QGIArrow for values*/
|
||||
/* App::PropertyInteger EndSymbol;*/
|
||||
|
||||
App::PropertyBool Scalable;
|
||||
App::PropertyBool AutoHorizontal;
|
||||
App::PropertyBool RotatesWithParent;
|
||||
|
||||
short mustExecute() const override;
|
||||
App::DocumentObjectExecReturn *execute() override;
|
||||
App::PropertyLink *getOwnerProperty() override { return &LeaderParent; }
|
||||
|
||||
const char* getViewProviderName() const override {
|
||||
return "TechDrawGui::ViewProviderLeader";
|
||||
@@ -65,18 +65,29 @@ public:
|
||||
Base::Vector3d getAttachPoint();
|
||||
DrawView* getBaseView() const;
|
||||
virtual App::DocumentObject* getBaseObject() const;
|
||||
App::PropertyLink *getOwnerProperty() override { return &LeaderParent; }
|
||||
|
||||
bool keepUpdated() override;
|
||||
double getScale() const override;
|
||||
double getBaseScale() const;
|
||||
void adjustLastSegment();
|
||||
void horizLastSegment();
|
||||
static std::vector<Base::Vector3d> horizLastSegment(const std::vector<Base::Vector3d>& inDeltas);
|
||||
bool getDefAuto() const;
|
||||
|
||||
Base::Vector3d getTileOrigin() const;
|
||||
Base::Vector3d getKinkPoint() const;
|
||||
Base::Vector3d getTailPoint() const;
|
||||
|
||||
static DrawLeaderLine* makeLeader(DrawViewPart* parent, std::vector<Base::Vector3d> points, int iStartSymbol = 0, int iEndSymbol = 0);
|
||||
std::vector<Base::Vector3d> getScaledAndRotatedPoints(bool doScale = true, bool doRotate = true) const;
|
||||
std::vector<Base::Vector3d> makeCanonicalPoints(const std::vector<Base::Vector3d>& inPoints,
|
||||
bool doScale = true,
|
||||
bool doRotate = true) const;
|
||||
std::vector<Base::Vector3d> makeCanonicalPointsInverted(const std::vector<Base::Vector3d>& inPoints,
|
||||
bool doScale = true,
|
||||
bool doRotate = true) const;
|
||||
|
||||
bool isParentReady() const;
|
||||
|
||||
protected:
|
||||
void onChanged(const App::Property* prop) override;
|
||||
|
||||
|
||||
@@ -52,6 +52,8 @@
|
||||
#define M_2PI ((M_PI)*2.0)
|
||||
#endif
|
||||
|
||||
constexpr double DegreesHalfCircle{180.0};
|
||||
|
||||
#define VERTEXTOLERANCE (2.0 * Precision::Confusion())
|
||||
#define VECTORTOLERANCE (Precision::Confusion())
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
|
||||
|
||||
using namespace TechDraw;
|
||||
|
||||
using DU = DrawUtil;
|
||||
// returns a string which represents the object e.g. when printed in python
|
||||
std::string DrawViewPartPy::representation() const
|
||||
{
|
||||
@@ -229,6 +229,7 @@ PyObject* DrawViewPartPy::makeCosmeticVertex(PyObject *args)
|
||||
return PyUnicode_FromString(id.c_str()); //return tag for new CV
|
||||
}
|
||||
|
||||
//! make a cosmetic vertex from a 3d point
|
||||
PyObject* DrawViewPartPy::makeCosmeticVertex3d(PyObject *args)
|
||||
{
|
||||
PyObject* pPnt1 = nullptr;
|
||||
@@ -239,9 +240,12 @@ PyObject* DrawViewPartPy::makeCosmeticVertex3d(PyObject *args)
|
||||
DrawViewPart* dvp = getDrawViewPartPtr();
|
||||
Base::Vector3d pnt1 = static_cast<Base::VectorPy*>(pPnt1)->value();
|
||||
Base::Vector3d centroid = dvp->getOriginalCentroid();
|
||||
// center the point
|
||||
pnt1 = pnt1 - centroid;
|
||||
Base::Vector3d projected = DrawUtil::invertY(dvp->projectPoint(pnt1));
|
||||
projected = CosmeticVertex::makeCanonicalPoint(dvp, projected);
|
||||
// project but do not invert
|
||||
Base::Vector3d projected = dvp->projectPoint(pnt1);
|
||||
// this is a real world point, it is not scaled or rotated, so so it is in canonical form
|
||||
// add and invert the point.
|
||||
std::string id = dvp->addCosmeticVertex(projected);
|
||||
//int link =
|
||||
dvp->add1CVToGV(id);
|
||||
@@ -341,6 +345,8 @@ PyObject* DrawViewPartPy::removeCosmeticVertex(PyObject *args)
|
||||
|
||||
PyObject* DrawViewPartPy::makeCosmeticLine(PyObject *args)
|
||||
{
|
||||
// the input points are expected to use conventional coordinates (Y up) and need to be inverted
|
||||
// before building the line
|
||||
PyObject* pPnt1 = nullptr;
|
||||
PyObject* pPnt2 = nullptr;
|
||||
int style = LineFormat::getDefEdgeStyle();
|
||||
@@ -358,12 +364,12 @@ PyObject* DrawViewPartPy::makeCosmeticLine(PyObject *args)
|
||||
DrawViewPart* dvp = getDrawViewPartPtr();
|
||||
Base::Vector3d pnt1 = static_cast<Base::VectorPy*>(pPnt1)->value();
|
||||
Base::Vector3d pnt2 = static_cast<Base::VectorPy*>(pPnt2)->value();
|
||||
std::string newTag = dvp->addCosmeticEdge(pnt1, pnt2);
|
||||
std::string newTag = dvp->addCosmeticEdge(DU::invertY(pnt1), DU::invertY(pnt2));
|
||||
TechDraw::CosmeticEdge* ce = dvp->getCosmeticEdge(newTag);
|
||||
if (ce) {
|
||||
ce->m_format.m_style = style;
|
||||
ce->m_format.m_weight = weight;
|
||||
ce->m_format.m_color = pColor ? DrawUtil::pyTupleToColor(pColor) : defCol;
|
||||
ce->m_format.setStyle(style);
|
||||
ce->m_format.setWidth(weight);
|
||||
ce->m_format.setColor(pColor ? DrawUtil::pyTupleToColor(pColor) : defCol);
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_RuntimeError, "DVPPI:makeCosmeticLine - line creation failed");
|
||||
@@ -378,6 +384,7 @@ PyObject* DrawViewPartPy::makeCosmeticLine(PyObject *args)
|
||||
|
||||
PyObject* DrawViewPartPy::makeCosmeticLine3D(PyObject *args)
|
||||
{
|
||||
// input points are expected to be conventional 3d points
|
||||
PyObject* pPnt1 = nullptr;
|
||||
PyObject* pPnt2 = nullptr;
|
||||
int style = LineFormat::getDefEdgeStyle();
|
||||
@@ -397,18 +404,18 @@ PyObject* DrawViewPartPy::makeCosmeticLine3D(PyObject *args)
|
||||
|
||||
Base::Vector3d pnt1 = static_cast<Base::VectorPy*>(pPnt1)->value();
|
||||
pnt1 = pnt1 - centroid;
|
||||
pnt1 = DrawUtil::invertY(dvp->projectPoint(pnt1));
|
||||
pnt1 = dvp->projectPoint(pnt1);
|
||||
|
||||
Base::Vector3d pnt2 = static_cast<Base::VectorPy*>(pPnt2)->value();
|
||||
pnt2 = pnt2 - centroid;
|
||||
pnt2 = DrawUtil::invertY(dvp->projectPoint(pnt2));
|
||||
pnt2 = dvp->projectPoint(pnt2);
|
||||
|
||||
std::string newTag = dvp->addCosmeticEdge(pnt1, pnt2);
|
||||
TechDraw::CosmeticEdge* ce = dvp->getCosmeticEdge(newTag);
|
||||
if (ce) {
|
||||
ce->m_format.m_style = style;
|
||||
ce->m_format.m_weight = weight;
|
||||
ce->m_format.m_color = pColor ? DrawUtil::pyTupleToColor(pColor) : defCol;
|
||||
ce->m_format.setStyle(style);
|
||||
ce->m_format.setWidth(weight);
|
||||
ce->m_format.setColor(pColor ? DrawUtil::pyTupleToColor(pColor) : defCol);
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_RuntimeError, "DVPPI:makeCosmeticLine - line creation failed");
|
||||
@@ -444,9 +451,9 @@ PyObject* DrawViewPartPy::makeCosmeticCircle(PyObject *args)
|
||||
TechDraw::CosmeticEdge* ce = dvp->getCosmeticEdge(newTag);
|
||||
if (ce) {
|
||||
ce->permaRadius = radius;
|
||||
ce->m_format.m_style = style;
|
||||
ce->m_format.m_weight = weight;
|
||||
ce->m_format.m_color = pColor ? DrawUtil::pyTupleToColor(pColor) : defCol;
|
||||
ce->m_format.setStyle(style);
|
||||
ce->m_format.setWidth(weight);
|
||||
ce->m_format.setColor(pColor ? DrawUtil::pyTupleToColor(pColor) : defCol);
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_RuntimeError, "DVPPI:makeCosmeticCircle - circle creation failed");
|
||||
@@ -484,12 +491,12 @@ PyObject* DrawViewPartPy::makeCosmeticCircleArc(PyObject *args)
|
||||
TechDraw::CosmeticEdge* ce = dvp->getCosmeticEdge(newTag);
|
||||
if (ce) {
|
||||
ce->permaRadius = radius;
|
||||
ce->m_format.m_style = style;
|
||||
ce->m_format.m_weight = weight;
|
||||
ce->m_format.setStyle(style);
|
||||
ce->m_format.setWidth(weight);
|
||||
if (!pColor)
|
||||
ce->m_format.m_color = defCol;
|
||||
ce->m_format.setColor(defCol);
|
||||
else
|
||||
ce->m_format.m_color = DrawUtil::pyTupleToColor(pColor);
|
||||
ce->m_format.setColor(DrawUtil::pyTupleToColor(pColor));
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_RuntimeError, "DVPPI:makeCosmeticCircleArc - arc creation failed");
|
||||
@@ -529,9 +536,9 @@ PyObject* DrawViewPartPy::makeCosmeticCircle3d(PyObject *args)
|
||||
TechDraw::CosmeticEdge* ce = dvp->getCosmeticEdge(newTag);
|
||||
if (ce) {
|
||||
ce->permaRadius = radius;
|
||||
ce->m_format.m_style = style;
|
||||
ce->m_format.m_weight = weight;
|
||||
ce->m_format.m_color = pColor ? DrawUtil::pyTupleToColor(pColor) : defCol;
|
||||
ce->m_format.setStyle(style);
|
||||
ce->m_format.setWidth(weight);
|
||||
ce->m_format.setColor(pColor ? DrawUtil::pyTupleToColor(pColor) : defCol);
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_RuntimeError, "DVPPI:makeCosmeticCircle - circle creation failed");
|
||||
@@ -572,12 +579,12 @@ PyObject* DrawViewPartPy::makeCosmeticCircleArc3d(PyObject *args)
|
||||
TechDraw::CosmeticEdge* ce = dvp->getCosmeticEdge(newTag);
|
||||
if (ce) {
|
||||
ce->permaRadius = radius;
|
||||
ce->m_format.m_style = style;
|
||||
ce->m_format.m_weight = weight;
|
||||
ce->m_format.setStyle(style);
|
||||
ce->m_format.setWidth(weight);
|
||||
if (!pColor)
|
||||
ce->m_format.m_color = defCol;
|
||||
ce->m_format.setColor(defCol);
|
||||
else
|
||||
ce->m_format.m_color = DrawUtil::pyTupleToColor(pColor);
|
||||
ce->m_format.setColor(DrawUtil::pyTupleToColor(pColor));
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_RuntimeError, "DVPPI:makeCosmeticCircleArc - arc creation failed");
|
||||
@@ -763,10 +770,10 @@ PyObject* DrawViewPartPy::formatGeometricEdge(PyObject *args)
|
||||
DrawViewPart* dvp = getDrawViewPartPtr();
|
||||
TechDraw::GeomFormat* gf = dvp->getGeomFormatBySelection(idx);
|
||||
if (gf) {
|
||||
gf->m_format.m_style = style;
|
||||
gf->m_format.m_color = color;
|
||||
gf->m_format.m_weight = weight;
|
||||
gf->m_format.m_visible = visible;
|
||||
gf->m_format.setStyle(style);
|
||||
gf->m_format.setColor(color);
|
||||
gf->m_format.setWidth(weight);
|
||||
gf->m_format.setVisible(visible);
|
||||
}
|
||||
else {
|
||||
TechDraw::LineFormat fmt(style, weight, color, visible);
|
||||
|
||||
@@ -621,7 +621,7 @@ std::vector<Base::Vector3d> BaseGeom::intersection(TechDraw::BaseGeomPtr geom2)
|
||||
TopExp_Explorer explorer(sectionShape, TopAbs_VERTEX);
|
||||
while (explorer.More()) {
|
||||
Base::Vector3d pt(DrawUtil::toVector3d(BRep_Tool::Pnt(TopoDS::Vertex(explorer.Current()))));
|
||||
interPoints.push_back(DrawUtil::invertY(pt));
|
||||
interPoints.push_back(pt);
|
||||
explorer.Next();
|
||||
}
|
||||
}
|
||||
@@ -802,16 +802,20 @@ AOC::AOC(const TopoDS_Edge &e) : Circle(e)
|
||||
gp_Vec v1(m, s); //vector mid to start
|
||||
gp_Vec v2(m, ePt); //vector mid to end
|
||||
gp_Vec v3(0, 0, 1); //stdZ
|
||||
|
||||
// this is the wrong determination of cw/ccw. needs to be determined by edge.
|
||||
double a = v3.DotCross(v1, v2); //error if v1 = v2?
|
||||
|
||||
startAngle = fmod(f, 2.0*M_PI);
|
||||
endAngle = fmod(l, 2.0*M_PI);
|
||||
|
||||
|
||||
cw = (a < 0) ? true: false;
|
||||
largeArc = (fabs(l-f) > M_PI) ? true : false;
|
||||
|
||||
startPnt = Base::Vector3d(s.X(), s.Y(), s.Z());
|
||||
endPnt = Base::Vector3d(ePt.X(), ePt.Y(), s.Z());
|
||||
midPnt = Base::Vector3d(m.X(), m.Y(), s.Z());
|
||||
startPnt = DU::toVector3d(s);
|
||||
endPnt = DU::toVector3d(ePt);
|
||||
midPnt = DU::toVector3d(m);
|
||||
if (e.Orientation() == TopAbs_REVERSED) {
|
||||
reversed = true;
|
||||
}
|
||||
@@ -845,6 +849,11 @@ AOC::AOC(Base::Vector3d c, double r, double sAng, double eAng) : Circle()
|
||||
gp_Vec v1(m, s); //vector mid to start
|
||||
gp_Vec v2(m, ePt); //vector mid to end
|
||||
gp_Vec v3(0, 0, 1); //stdZ
|
||||
|
||||
// this is a bit of an arcane method of determining if v2 is clockwise from v1 or counter clockwise from v1.
|
||||
// The v1 x v2 points up if v2 is ccw from v1 and points down if v2 is cw from v1. Taking (v1 x v2) * stdZ
|
||||
// gives 1 for parallel with stdZ (v2 is ccw from v1) or -1 for antiparallel with stdZ (v2 is clockwise from v1).
|
||||
// this cw flag is a problem. we should just declare that arcs are always ccw and flip the start and end angles.
|
||||
double a = v3.DotCross(v1, v2); //error if v1 = v2?
|
||||
|
||||
startAngle = fmod(f, 2.0*M_PI);
|
||||
@@ -852,9 +861,9 @@ AOC::AOC(Base::Vector3d c, double r, double sAng, double eAng) : Circle()
|
||||
cw = (a < 0) ? true: false;
|
||||
largeArc = (fabs(l-f) > M_PI) ? true : false;
|
||||
|
||||
startPnt = Base::Vector3d(s.X(), s.Y(), s.Z());
|
||||
endPnt = Base::Vector3d(ePt.X(), ePt.Y(), s.Z());
|
||||
midPnt = Base::Vector3d(m.X(), m.Y(), s.Z());
|
||||
startPnt = DU::toVector3d(s);
|
||||
endPnt = DU::toVector3d(ePt);
|
||||
midPnt = DU::toVector3d(m);
|
||||
if (edge.Orientation() == TopAbs_REVERSED) {
|
||||
reversed = true;
|
||||
}
|
||||
@@ -890,6 +899,22 @@ bool AOC::isOnArc(Base::Vector3d p)
|
||||
return false;
|
||||
}
|
||||
|
||||
BaseGeomPtr AOC::copy()
|
||||
{
|
||||
auto base = BaseGeom::copy();
|
||||
TechDraw::CirclePtr circle = std::static_pointer_cast<TechDraw::Circle>(base);
|
||||
TechDraw::AOCPtr aoc = std::static_pointer_cast<TechDraw::AOC>(circle);
|
||||
if (aoc) {
|
||||
aoc->clockwiseAngle(clockwiseAngle());
|
||||
aoc->startPnt = startPnt;
|
||||
aoc->startAngle = startAngle;
|
||||
aoc->endPnt = endPnt;
|
||||
aoc->endAngle = endAngle;
|
||||
aoc->largeArc = largeArc;
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
double AOC::distToArc(Base::Vector3d p)
|
||||
{
|
||||
return minDist(p);
|
||||
|
||||
@@ -113,7 +113,7 @@ class TechDrawExport BaseGeom : public std::enable_shared_from_this<BaseGeom>
|
||||
static bool validateEdge(TopoDS_Edge edge);
|
||||
static TopoDS_Edge completeEdge(const TopoDS_Edge &edge);
|
||||
bool closed();
|
||||
BaseGeomPtr copy();
|
||||
virtual BaseGeomPtr copy();
|
||||
std::string dump();
|
||||
virtual std::string toString() const;
|
||||
std::vector<Base::Vector3d> intersection(TechDraw::BaseGeomPtr geom2);
|
||||
@@ -241,6 +241,7 @@ class TechDrawExport AOC: public Circle
|
||||
~AOC() override = default;
|
||||
|
||||
public:
|
||||
BaseGeomPtr copy() override;
|
||||
double getStartAngle() override { return startAngle; }
|
||||
double getEndAngle() override { return endAngle; }
|
||||
bool clockwiseAngle() override { return cw; }
|
||||
|
||||
@@ -624,14 +624,13 @@ void GeometryObject::addEdge(TechDraw::BaseGeomPtr bg) { edgeGeom.push_back(bg);
|
||||
//adds a new GeomVert surrogate for CV
|
||||
//returns GeomVert selection index ("Vertex3")
|
||||
// insertGeomForCV(cv)
|
||||
// is this ever used?
|
||||
int GeometryObject::addCosmeticVertex(CosmeticVertex* cv)
|
||||
{
|
||||
// Base::Console().Message("GO::addCosmeticVertex(%X)\n", cv);
|
||||
double scale = m_parent->getScale();
|
||||
Base::Vector3d pos = cv->scaled(scale);
|
||||
TechDraw::VertexPtr v(std::make_shared<TechDraw::Vertex>(pos.x, pos.y));
|
||||
v->setCosmetic(true);
|
||||
// v->setCosmeticLink = -1;//obs??
|
||||
v->setCosmeticTag(cv->getTagAsString());
|
||||
v->setHlrVisible(true);
|
||||
int idx = vertexGeom.size();
|
||||
@@ -643,7 +642,6 @@ int GeometryObject::addCosmeticVertex(CosmeticVertex* cv)
|
||||
//should probably be called addVertex since not connect to CV by tag
|
||||
int GeometryObject::addCosmeticVertex(Base::Vector3d pos)
|
||||
{
|
||||
Base::Console().Message("GO::addCosmeticVertex() 1 - deprec?\n");
|
||||
TechDraw::VertexPtr v(std::make_shared<TechDraw::Vertex>(pos.x, pos.y));
|
||||
v->setCosmetic(true);
|
||||
v->setCosmeticTag("tbi");//not connected to CV
|
||||
@@ -655,7 +653,6 @@ int GeometryObject::addCosmeticVertex(Base::Vector3d pos)
|
||||
|
||||
int GeometryObject::addCosmeticVertex(Base::Vector3d pos, std::string tagString)
|
||||
{
|
||||
// Base::Console().Message("GO::addCosmeticVertex() 2\n");
|
||||
TechDraw::VertexPtr v(std::make_shared<TechDraw::Vertex>(pos.x, pos.y));
|
||||
v->setCosmetic(true);
|
||||
v->setCosmeticTag(tagString);//connected to CV
|
||||
|
||||
117
src/Mod/TechDraw/App/LineFormat.cpp
Normal file
117
src/Mod/TechDraw/App/LineFormat.cpp
Normal file
@@ -0,0 +1,117 @@
|
||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 wandererfan <wandererfan at gmail dot com> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#endif
|
||||
|
||||
#include "LineGroup.h"
|
||||
#include "LineGenerator.h"
|
||||
#include "Preferences.h"
|
||||
|
||||
#include "LineFormat.h"
|
||||
|
||||
using namespace TechDraw;
|
||||
|
||||
//! general purpose line format specifier
|
||||
|
||||
LineFormat::LineFormat()
|
||||
{
|
||||
m_style = getDefEdgeStyle();
|
||||
m_weight = getDefEdgeWidth();
|
||||
m_color= getDefEdgeColor();
|
||||
m_visible = true;
|
||||
m_lineNumber = LineGenerator::fromQtStyle((Qt::PenStyle)m_style);
|
||||
}
|
||||
|
||||
// static loader of default format
|
||||
void LineFormat::initCurrentLineFormat()
|
||||
{
|
||||
getCurrentLineFormat().setStyle(getDefEdgeStyle());
|
||||
getCurrentLineFormat().setWidth(getDefEdgeWidth());
|
||||
getCurrentLineFormat().setColor(getDefEdgeColor());
|
||||
getCurrentLineFormat().setVisible(true);
|
||||
getCurrentLineFormat().setLineNumber(LineGenerator::fromQtStyle((Qt::PenStyle)getCurrentLineFormat().getStyle()));
|
||||
}
|
||||
|
||||
LineFormat& LineFormat::getCurrentLineFormat()
|
||||
{
|
||||
static TechDraw::LineFormat currentLineFormat;
|
||||
return currentLineFormat;
|
||||
}
|
||||
|
||||
void LineFormat::setCurrentLineFormat(LineFormat& newFormat)
|
||||
{
|
||||
getCurrentLineFormat().setStyle(newFormat.getStyle());
|
||||
getCurrentLineFormat().setWidth(newFormat.getWidth());
|
||||
getCurrentLineFormat().setColor(newFormat.getColor());
|
||||
getCurrentLineFormat().setVisible(newFormat.getVisible());
|
||||
getCurrentLineFormat().setLineNumber(newFormat.getLineNumber());
|
||||
}
|
||||
|
||||
LineFormat::LineFormat(const int style,
|
||||
const double weight,
|
||||
const App::Color& color,
|
||||
const bool visible) :
|
||||
m_style(style),
|
||||
m_weight(weight),
|
||||
m_color(color),
|
||||
m_visible(visible),
|
||||
m_lineNumber(LineGenerator::fromQtStyle((Qt::PenStyle)m_style))
|
||||
{
|
||||
}
|
||||
|
||||
void LineFormat::dump(const char* title)
|
||||
{
|
||||
Base::Console().Message("LF::dump - %s \n", title);
|
||||
Base::Console().Message("LF::dump - %s \n", toString().c_str());
|
||||
}
|
||||
|
||||
std::string LineFormat::toString() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << m_style << ", " <<
|
||||
m_weight << ", " <<
|
||||
m_color.asHexString() << ", " <<
|
||||
m_visible;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
//static preference getters.
|
||||
double LineFormat::getDefEdgeWidth()
|
||||
{
|
||||
return TechDraw::LineGroup::getDefaultWidth("Graphic");
|
||||
}
|
||||
|
||||
App::Color LineFormat::getDefEdgeColor()
|
||||
{
|
||||
return Preferences::normalColor();
|
||||
}
|
||||
|
||||
int LineFormat::getDefEdgeStyle()
|
||||
{
|
||||
return Preferences::getPreferenceGroup("Decorations")->GetInt("CenterLineStyle", 2); //dashed
|
||||
}
|
||||
|
||||
|
||||
96
src/Mod/TechDraw/App/LineFormat.h
Normal file
96
src/Mod/TechDraw/App/LineFormat.h
Normal file
@@ -0,0 +1,96 @@
|
||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 wandererfan <wandererfan at gmail dot com> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TECHDRAW_LINEFORMAT_H
|
||||
#define TECHDRAW_LINEFORMAT_H
|
||||
|
||||
#include <Mod/TechDraw/TechDrawGlobal.h>
|
||||
|
||||
#include <QColor>
|
||||
|
||||
#include <App/Color.h>
|
||||
|
||||
|
||||
namespace TechDraw {
|
||||
|
||||
//! general purpose line format specifier
|
||||
class TechDrawExport LineFormat
|
||||
{
|
||||
public:
|
||||
static constexpr size_t InvalidLine{0};
|
||||
|
||||
LineFormat();
|
||||
LineFormat(const int style,
|
||||
const double weight,
|
||||
const App::Color& color,
|
||||
const bool visible,
|
||||
const int lineNumber);
|
||||
// TODO: phase out the old 4 parameter constructor
|
||||
LineFormat(const int style,
|
||||
const double weight,
|
||||
const App::Color& color,
|
||||
const bool visible);
|
||||
~LineFormat() = default;
|
||||
|
||||
// style was used to specify QPen styles. line number (from LineGenerator) should be used now.
|
||||
int getStyle() const { return m_style; }
|
||||
void setStyle(int style) { m_style = style; }
|
||||
|
||||
double getWidth() const { return m_weight; }
|
||||
void setWidth(double width) {m_weight = width; }
|
||||
|
||||
App::Color getColor() const { return m_color; }
|
||||
void setColor(App::Color color) { m_color = color; }
|
||||
QColor getQColor() const { return m_color.asValue<QColor>(); }
|
||||
void setQColor(QColor qColor) { m_color.set(qColor.redF(), qColor.greenF(), qColor.blueF(), 1.0 - qColor.alphaF()); }
|
||||
|
||||
bool getVisible() const { return m_visible; }
|
||||
void setVisible(bool viz) { m_visible = viz; }
|
||||
|
||||
int getLineNumber() const { return m_lineNumber; }
|
||||
void setLineNumber(int number) { m_lineNumber = number; }
|
||||
|
||||
static double getDefEdgeWidth();
|
||||
static App::Color getDefEdgeColor();
|
||||
static int getDefEdgeStyle();
|
||||
|
||||
void dump(const char* title);
|
||||
std::string toString() const;
|
||||
|
||||
static void initCurrentLineFormat();
|
||||
static LineFormat& getCurrentLineFormat();
|
||||
static void setCurrentLineFormat(LineFormat& newformat);
|
||||
|
||||
private:
|
||||
int m_style;
|
||||
double m_weight;
|
||||
App::Color m_color;
|
||||
bool m_visible;
|
||||
int m_lineNumber {1};
|
||||
};
|
||||
|
||||
} //end namespace TechDraw
|
||||
|
||||
#endif //TECHDRAW_LINEFORMAT_H
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
|
||||
#include <Mod/TechDraw/TechDrawGlobal.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace TechDraw
|
||||
|
||||
Reference in New Issue
Block a user