[TD]fix location of CV on rotated views

This commit is contained in:
wandererfan
2023-12-22 11:12:10 -05:00
committed by WandererFan
parent 2fe19267df
commit e6517089df
12 changed files with 155 additions and 69 deletions

View File

@@ -71,6 +71,7 @@
#include "GeometryObject.h"
#include "ProjectionAlgos.h"
#include "TechDrawExport.h"
#include "CosmeticVertexPy.h"
namespace TechDraw {
@@ -185,7 +186,10 @@ public:
);
add_varargs_method("build3dCurves", &Module::build3dCurves,
"TopoShape = build3dCurves(TopoShape) -- convert the edges to a 3D curve\n"
"which is useful for shapes obtained Part.HLRBRep.Algo"
"which is useful for shapes obtained Part.HLRBRep.Algo"
);
add_varargs_method("makeCanonicalPoint", &Module::makeCanonicalPoint,
"makeCanonicalPoint(DrawViewPart, Vector3d) - Returns the unscaled, unrotated version of the input point)"
);
initialize("This is a module for making drawings"); // register with Python
}
@@ -1234,14 +1238,14 @@ private:
PyObject *pcObjShape(nullptr);
if (!PyArg_ParseTuple(args.ptr(), "O!",
&(TopoShapePy::Type), &pcObjShape))
&(TopoShapePy::Type), &pcObjShape))
throw Py::Exception();
TopoShapePy* pShape = static_cast<TopoShapePy*>(pcObjShape);
SVGOutput output;
Py::String result(output.exportEdges(pShape->getTopoShapePtr()->getShape()));
SVGOutput output;
Py::String result(output.exportEdges(pShape->getTopoShapePtr()->getShape()));
return result;
return result;
}
Py::Object build3dCurves(const Py::Tuple& args)
@@ -1249,15 +1253,34 @@ private:
PyObject *pcObjShape(nullptr);
if (!PyArg_ParseTuple(args.ptr(), "O!",
&(TopoShapePy::Type), &pcObjShape))
&(TopoShapePy::Type), &pcObjShape))
throw Py::Exception();
TopoShapePy* pShape = static_cast<TopoShapePy*>(pcObjShape);
const TopoShape& nShape =
TechDraw::build3dCurves(pShape->getTopoShapePtr()->getShape());
return Py::Object(new TopoShapePy(new TopoShape(nShape)));
const TopoShape& nShape =
TechDraw::build3dCurves(pShape->getTopoShapePtr()->getShape());
return Py::Object(new TopoShapePy(new TopoShape(nShape)));
}
Py::Object makeCanonicalPoint(const Py::Tuple& args)
{
PyObject* pyDocObj{nullptr};
PyObject* pyPointIn{nullptr};
PyObject *pyUnscale{Py_True};
if (!PyArg_ParseTuple(args.ptr(), "O!O!|O", &(TechDraw::DrawViewPartPy::Type), &pyDocObj,
&(Base::VectorPy::Type), &pyPointIn, &pyUnscale)) {
return Py::None();
}
bool unscale = pyUnscale == Py_True ? true : false;
DrawViewPartPy* pyDvp = static_cast<TechDraw::DrawViewPartPy*>(pyDocObj);
DrawViewPart* dvp = pyDvp->getDrawViewPartPtr();
Base::Vector3d cPoint = static_cast<Base::VectorPy*>(pyPointIn)->value();
cPoint = CosmeticVertex::makeCanonicalPoint(dvp, cPoint, unscale);
return Py::asObject(new Base::VectorPy(cPoint));
}
};
PyObject* initModule()

View File

@@ -44,6 +44,7 @@
using namespace TechDraw;
using namespace std;
using DU = DrawUtil;
#define GEOMETRYEDGE 0
#define COSMETICEDGE 1
@@ -215,6 +216,19 @@ TechDraw::BaseGeomPtr CosmeticEdge::scaledAndRotatedGeometry(const double scale,
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.
//! the result of this method should be used in addCosmeticEdge().
TechDraw::BaseGeomPtr CosmeticEdge::makeCanonicalLine(DrawViewPart* dvp, Base::Vector3d start, Base::Vector3d end)
{
Base::Vector3d cStart = CosmeticVertex::makeCanonicalPoint(dvp, start);
Base::Vector3d cEnd = CosmeticVertex::makeCanonicalPoint(dvp, end);
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();
}
std::string CosmeticEdge::toString() const
{
std::stringstream ss;

View File

@@ -85,6 +85,7 @@ public:
TechDraw::BaseGeomPtr scaledGeometry(const double scale);
TechDraw::BaseGeomPtr scaledAndRotatedGeometry(const double scale, const double rotDegrees);
static TechDraw::BaseGeomPtr makeCanonicalLine(DrawViewPart* dvp, Base::Vector3d start, Base::Vector3d end);
std::string toString() const override;
void dump(const char* title) const;

View File

@@ -36,6 +36,7 @@
#include "LineGroup.h"
#include "Preferences.h"
#include "DrawUtil.h"
#include "DrawViewPart.h"
using namespace TechDraw;
using namespace std;
@@ -192,6 +193,32 @@ Base::Vector3d CosmeticVertex::rotatedAndScaled(const double scale, const double
return scaledPoint;
}
//! converts a point into its unscaled, unrotated form. If point is Gui space coordinates,
//! it should be inverted (DU::invertY) before calling this method, and the result should be
//! inverted 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;
// we always rotate around the origin.
result.RotateZ(-rotRad);
}
if (unscale) {
// unrotated point is scaled and we need to unscale it (the normal situation)
double scale = dvp->getScale();
return result / scale;
}
// return the unrotated version of input point without unscaling
return result;
}
boost::uuids::uuid CosmeticVertex::getTag() const
{
return tag;

View File

@@ -55,6 +55,7 @@ public:
Base::Vector3d scaled(const double factor);
Base::Vector3d rotatedAndScaled(const double scale, const double rotDegrees);
static Base::Vector3d makeCanonicalPoint(DrawViewPart* dvp, Base::Vector3d point, bool unscale = true);
static bool restoreCosmetic();
// Persistence implementer ---------------------

View File

@@ -402,11 +402,14 @@ DrawDimHelper::makeDistDim(DrawViewPart* dvp, std::string dimType,
std::vector<TechDraw::VertexPtr> gVerts = dvp->getVertexGeometry();
// invert the point so the math works correctly
Base::Vector3d cleanMin = DrawUtil::invertY(inMin);
cleanMin = CosmeticVertex::makeCanonicalPoint(dvp, cleanMin);
std::string tag1 = dvp->addCosmeticVertex(cleanMin);
int iGV1 = dvp->add1CVToGV(tag1);
Base::Vector3d cleanMax = DrawUtil::invertY(inMax);
cleanMax = CosmeticVertex::makeCanonicalPoint(dvp, cleanMax);
std::string tag2 = dvp->addCosmeticVertex(cleanMax);
int iGV2 = dvp->add1CVToGV(tag2);

View File

@@ -168,7 +168,6 @@ PyObject* DrawViewPartPy::makeCosmeticVertex(PyObject *args)
}
DrawViewPart* dvp = getDrawViewPartPtr();
std::string dvpName = dvp->getNameInDocument();
Base::Vector3d pnt1 = static_cast<Base::VectorPy*>(pPnt1)->value();
std::string id = dvp->addCosmeticVertex(pnt1);
//int link =
@@ -190,7 +189,7 @@ PyObject* DrawViewPartPy::makeCosmeticVertex3d(PyObject *args)
Base::Vector3d centroid = dvp->getOriginalCentroid();
pnt1 = pnt1 - centroid;
Base::Vector3d projected = DrawUtil::invertY(dvp->projectPoint(pnt1));
projected = CosmeticVertex::makeCanonicalPoint(dvp, projected);
std::string id = dvp->addCosmeticVertex(projected);
//int link =
dvp->add1CVToGV(id);

View File

@@ -340,13 +340,14 @@ void execMidpoints(Gui::Command* cmd)
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Add Midpoint Vertices"));
const TechDraw::BaseGeomPtrVector edges = dvp->getEdgeGeometry();
double scale = dvp->getScale();
for (auto& s: selectedEdges) {
int GeoId(TechDraw::DrawUtil::getIndexFromName(s));
TechDraw::BaseGeomPtr geom = edges.at(GeoId);
Base::Vector3d mid = geom->getMidPoint();
// invert the point so the math works correctly
mid = DrawUtil::invertY(mid);
dvp->addCosmeticVertex(mid / scale);
mid = CosmeticVertex::makeCanonicalPoint(dvp, mid);
dvp->addCosmeticVertex(mid);
}
Gui::Command::commitCommand();
@@ -366,15 +367,16 @@ void execQuadrants(Gui::Command* cmd)
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Add Quadrant Vertices"));
const TechDraw::BaseGeomPtrVector edges = dvp->getEdgeGeometry();
double scale = dvp->getScale();
for (auto& s: selectedEdges) {
int GeoId(TechDraw::DrawUtil::getIndexFromName(s));
TechDraw::BaseGeomPtr geom = edges.at(GeoId);
std::vector<Base::Vector3d> quads = geom->getQuads();
for (auto& q: quads) {
Base::Vector3d iq = DrawUtil::invertY(q);
dvp->addCosmeticVertex(iq / scale);
}
std::vector<Base::Vector3d> quads = geom->getQuads();
for (auto& q: quads) {
// invert the point so the math works correctly
Base::Vector3d iq = DrawUtil::invertY(q);
iq = CosmeticVertex::makeCanonicalPoint(dvp, iq);
dvp->addCosmeticVertex(iq);
}
}
Gui::Command::commitCommand();

View File

@@ -1349,7 +1349,8 @@ void execCreateObliqueChainDimension(Gui::Command* cmd) {
nextPoint.y = -nextPoint.y;
oldVertex.point.y = -oldVertex.point.y;
if ((oldVertex.point - nextPoint).Length() > 0.01) {
std::string vertTag = objFeat->addCosmeticVertex(nextPoint / scale);
Base::Vector3d cvPoint = CosmeticVertex::makeCanonicalPoint(objFeat, nextPoint);
std::string vertTag = objFeat->addCosmeticVertex(cvPoint);
int vertNumber = objFeat->add1CVToGV(vertTag);
std::stringstream ss;
ss << "Vertex" << vertNumber;
@@ -1703,7 +1704,8 @@ void execCreateObliqueCoordDimension(Gui::Command* cmd) {
nextPoint.y = -nextPoint.y;
oldVertex.point.y = -oldVertex.point.y;
if ((oldVertex.point - nextPoint).Length() > 0.01) {
std::string vertTag = objFeat->addCosmeticVertex(nextPoint / scale);
Base::Vector3d cvPoint = CosmeticVertex::makeCanonicalPoint(objFeat, nextPoint);
std::string vertTag = objFeat->addCosmeticVertex(cvPoint);
int vertNumber = objFeat->add1CVToGV(vertTag);
std::stringstream ss;
ss << "Vertex" << vertNumber;
@@ -2180,10 +2182,12 @@ void CmdTechDrawExtensionCreateLengthArc::activated(int iMsg) {
endPt.y = -endPt.y;
std::stringstream startName, endName, formatSpec;
double scale = objFeat->getScale();
std::string startVertTag = objFeat->addCosmeticVertex(startPt / scale);
Base::Vector3d cvPoint = CosmeticVertex::makeCanonicalPoint(objFeat, startPt);
std::string startVertTag = objFeat->addCosmeticVertex(cvPoint);
int startVertNumber = objFeat->add1CVToGV(startVertTag);
startName << "Vertex" << startVertNumber;
std::string endVertTag = objFeat->addCosmeticVertex(endPt / scale);
cvPoint = CosmeticVertex::makeCanonicalPoint(objFeat, endPt);
std::string endVertTag = objFeat->addCosmeticVertex(cvPoint);
int endVertNumber = objFeat->add1CVToGV(endVertTag);
endName << "Vertex" << endVertNumber;
TechDraw::DrawViewDimension* dim;

View File

@@ -843,11 +843,15 @@ void CmdTechDrawExtensionVertexAtIntersection::activated(int iMsg)
int GeoId2 = TechDraw::DrawUtil::getIndexFromName(SubNames[1]);
TechDraw::BaseGeomPtr geom2 = objFeat->getGeomByIndex(GeoId2);
double scale = objFeat->getScale();
// double scale = objFeat->getScale();
std::vector<Base::Vector3d> interPoints = geom1->intersection(geom2);
for (auto pt : interPoints) {
std::string ptId = objFeat->addCosmeticVertex(pt/scale);
objFeat->add1CVToGV(ptId);
// std::string ptId = objFeat->addCosmeticVertex(pt/scale);
// objFeat->add1CVToGV(ptId);
// invert the point so the math works correctly
Base::Vector3d temp = DrawUtil::invertY(pt);
temp = CosmeticVertex::makeCanonicalPoint(objFeat, temp);
objFeat->addCosmeticVertex(temp);
}
}
}
@@ -1193,33 +1197,41 @@ void execLineParallelPerpendicular(Gui::Command* cmd, bool isParallel)
if (SubNames.size() >= 2) {
std::string GeoType1 = TechDraw::DrawUtil::getGeomTypeFromName(SubNames[0]);
std::string GeoType2 = TechDraw::DrawUtil::getGeomTypeFromName(SubNames[1]);
int EdgeId;
int VertId;
if (GeoType1 == "Edge" && GeoType2 == "Vertex") {
double scale = objFeat->getScale();
int GeoId1 = TechDraw::DrawUtil::getIndexFromName(SubNames[0]);
TechDraw::BaseGeomPtr geom1 = objFeat->getGeomByIndex(GeoId1);
int GeoId2 = TechDraw::DrawUtil::getIndexFromName(SubNames[1]);
TechDraw::GenericPtr lineGen = std::static_pointer_cast<TechDraw::Generic>(geom1);
Base::Vector3d lineStart = lineGen->points.at(0);
Base::Vector3d lineEnd = lineGen->points.at(1);
TechDraw::VertexPtr vert = objFeat->getProjVertexByIndex(GeoId2);
Base::Vector3d vertexPoint(vert->point().x, vert->point().y, 0.0);
Base::Vector3d halfVector = (lineEnd - lineStart) / 2.0;
if (!isParallel) {
float dummy = halfVector.x;
halfVector.x = -halfVector.y;
halfVector.y = dummy;
}
Base::Vector3d startPoint = vertexPoint + halfVector;
Base::Vector3d endPoint = vertexPoint - halfVector;
startPoint.y = -startPoint.y;
endPoint.y = -endPoint.y;
std::string lineTag = objFeat->addCosmeticEdge(startPoint / scale, endPoint / scale);
TechDraw::CosmeticEdge* lineEdge = objFeat->getCosmeticEdge(lineTag);
_setLineAttributes(lineEdge);
objFeat->refreshCEGeoms();
objFeat->requestPaint();
cmd->getSelection().clearSelection();
EdgeId = TechDraw::DrawUtil::getIndexFromName(SubNames[0]);
VertId = TechDraw::DrawUtil::getIndexFromName(SubNames[1]);
} else if (GeoType2 == "Edge" && GeoType1 == "Vertex") {
EdgeId = TechDraw::DrawUtil::getIndexFromName(SubNames[1]);
VertId = TechDraw::DrawUtil::getIndexFromName(SubNames[0]);
} else {
// we don't have an edge + vertex as selection
return;
}
TechDraw::BaseGeomPtr geom1 = objFeat->getGeomByIndex(EdgeId);
TechDraw::GenericPtr lineGen = std::static_pointer_cast<TechDraw::Generic>(geom1);
Base::Vector3d lineStart = lineGen->points.at(0);
Base::Vector3d lineEnd = lineGen->points.at(1);
TechDraw::VertexPtr vert = objFeat->getProjVertexByIndex(VertId);
Base::Vector3d vertexPoint(vert->point().x, vert->point().y, 0.0);
Base::Vector3d halfVector = (lineEnd - lineStart) / 2.0;
if (!isParallel) {
float dummy = halfVector.x;
halfVector.x = -halfVector.y;
halfVector.y = dummy;
}
Base::Vector3d startPoint = vertexPoint + halfVector;
Base::Vector3d endPoint = vertexPoint - halfVector;
startPoint.y = -startPoint.y;
endPoint.y = -endPoint.y;
TechDraw::BaseGeomPtr cLine = CosmeticEdge::makeCanonicalLine(objFeat, startPoint, endPoint);
std::string lineTag = objFeat->addCosmeticEdge(cLine);
TechDraw::CosmeticEdge* lineEdge = objFeat->getCosmeticEdge(lineTag);
_setLineAttributes(lineEdge);
objFeat->refreshCEGeoms();
objFeat->requestPaint();
cmd->getSelection().clearSelection();
}
Gui::Command::commitCommand();
}

View File

@@ -137,7 +137,8 @@ void TaskCosVertex::addCosVertex(QPointF qPos)
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Add Cosmetic Vertex"));
// Base::Console().Message("TCV::addCosVertex(%s)\n", TechDraw::DrawUtil::formatVector(qPos).c_str());
Base::Vector3d pos(qPos.x(), -qPos.y());
Base::Vector3d pos = DU::invertY(DU::toVector3d(qPos));
pos = CosmeticVertex::makeCanonicalPoint(m_baseFeat, pos);
// int idx =
(void) m_baseFeat->addCosmeticVertex(pos);
m_baseFeat->requestPaint();
@@ -215,7 +216,6 @@ void TaskCosVertex::onTrackerFinished(std::vector<QPointF> pts, QGIView* qgParen
QPointF dragEnd = pts.front(); //scene pos of mouse click
double scale = m_baseFeat->getScale();
double x = Rez::guiX(m_baseFeat->X.getValue());
double y = Rez::guiX(m_baseFeat->Y.getValue());
@@ -235,19 +235,13 @@ void TaskCosVertex::onTrackerFinished(std::vector<QPointF> pts, QGIView* qgParen
QPointF basePosScene(x, -y); //base position in scene coords
QPointF displace = dragEnd - basePosScene;
QPointF scenePosCV = displace / scale;
QPointF scenePosCV = displace;
// if the base view is rotated, we need to unrotate it before saving
double rotDeg = m_baseFeat->Rotation.getValue();
if (rotDeg != 0.0) {
// Invert Y value so the math works.
Base::Vector3d posToRotate = DU::invertY(DU::toVector3d(scenePosCV));
double rotRad = rotDeg * M_PI / 180.0;
// we always rotate around the origin.
posToRotate.RotateZ(-rotRad);
// now put Y value back to display form
scenePosCV = DU::toQPointF(DU::invertY(posToRotate));
}
// Invert Y value so the math works.
Base::Vector3d posToRotate = DU::invertY(DU::toVector3d(scenePosCV));
posToRotate = CosmeticVertex::makeCanonicalPoint(m_baseFeat, posToRotate);
// now put Y value back to display form
scenePosCV = DU::toQPointF(DU::invertY(posToRotate));
m_savePoint = Rez::appX(scenePosCV);
updateUi();

View File

@@ -28,6 +28,7 @@ __date__ = "2023/12/04"
import FreeCAD as App
import FreeCADGui as Gui
import TechDraw
from functools import partial
@@ -47,12 +48,17 @@ class TaskAddOffsetVertex():
def accept(self):
'''slot: OK pressed'''
point = self.vertex.Point
point = self.vertex.Point # this is unscaled and inverted, but is also rotated.
# unrotate point. Note that since this is already unscaled, we need to set the
# third parameter to False to avoid an extra descaling.
point = TechDraw.makeCanonicalPoint(self.view, point, False);
xOffset = self.form.dSpinBoxX.value()
yOffset = self.form.dSpinBoxY.value()
offset = App.Vector(xOffset,yOffset,0)
offset = App.Vector(xOffset,yOffset,0) # the offset is applied to the canonical
# point. it is an unscaled, unrotated,
# uninverted relative value.
self.view.makeCosmeticVertex(point+offset)
Gui.Control.closeDialog()
def reject(self):
return True
return True