[TD]corrupt dim reference detect and correct
This commit is contained in:
@@ -87,6 +87,7 @@ using Import::ImpExpDxfWrite;
|
||||
using TechDraw::ProjectionAlgos;
|
||||
|
||||
using namespace std;
|
||||
using namespace Part;
|
||||
|
||||
namespace TechDraw {
|
||||
|
||||
@@ -271,7 +272,7 @@ private:
|
||||
}
|
||||
else {
|
||||
for (auto& w : sortedWires) {
|
||||
PyObject* wire = new TopoShapeWirePy(new TopoShape(w));
|
||||
PyObject* wire = new TopoShapeWirePy(new Part::TopoShape(w));
|
||||
result.append(Py::asObject(wire));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ set(TechDrawLIBS
|
||||
Part
|
||||
Spreadsheet
|
||||
Import
|
||||
PartDesign
|
||||
)
|
||||
|
||||
if(FREECAD_QT_MAJOR_VERSION EQUAL 5)
|
||||
@@ -114,6 +115,8 @@ SET(Draw_SRCS
|
||||
DimensionReferences.h
|
||||
DimensionFormatter.cpp
|
||||
DimensionFormatter.h
|
||||
GeometryMatcher.cpp
|
||||
GeometryMatcher.h
|
||||
DrawViewBalloon.cpp
|
||||
DrawViewBalloon.h
|
||||
DrawViewSection.cpp
|
||||
|
||||
@@ -53,10 +53,8 @@ void pointPair::move(Base::Vector3d offset)
|
||||
// project the points onto the dvp's paper plane. Points are still in R3 coords.
|
||||
void pointPair::project(DrawViewPart* dvp)
|
||||
{
|
||||
Base::Vector3d normal = DrawUtil::toVector3d(dvp->getProjectionCS().Direction());
|
||||
Base::Vector3d stdOrigin(0.0, 0.0, 0.0);
|
||||
m_first = m_first.ProjectToPlane(stdOrigin, normal) * dvp->getScale();
|
||||
m_second = m_second.ProjectToPlane(stdOrigin, normal) * dvp->getScale();
|
||||
m_first = dvp->projectPoint(m_first) * dvp->getScale();
|
||||
m_second = dvp->projectPoint(m_second) * dvp->getScale();
|
||||
}
|
||||
|
||||
// map the points onto the dvp's XY coordinate system
|
||||
@@ -111,10 +109,8 @@ void anglePoints::move(Base::Vector3d offset)
|
||||
// project the points onto the dvp's paper plane. Points are still in R3 coords.
|
||||
void anglePoints::project(DrawViewPart* dvp)
|
||||
{
|
||||
Base::Vector3d normal = DrawUtil::toVector3d(dvp->getProjectionCS().Direction());
|
||||
Base::Vector3d stdOrigin(0.0, 0.0, 0.0);
|
||||
m_ends.project(dvp);
|
||||
m_vertex = m_vertex.ProjectToPlane(stdOrigin, normal) * dvp->getScale();
|
||||
m_vertex = dvp->projectPoint(m_vertex) * dvp->getScale();
|
||||
}
|
||||
|
||||
// map the points onto the dvp's XY coordinate system
|
||||
@@ -187,14 +183,12 @@ void arcPoints::move(Base::Vector3d offset)
|
||||
void arcPoints::project(DrawViewPart* dvp)
|
||||
{
|
||||
radius = radius * dvp->getScale();
|
||||
Base::Vector3d normal = DrawUtil::toVector3d(dvp->getProjectionCS().Direction());
|
||||
Base::Vector3d stdOrigin(0.0, 0.0, 0.0);
|
||||
center = center.ProjectToPlane(stdOrigin, normal) * dvp->getScale();
|
||||
onCurve.first(onCurve.first().ProjectToPlane(stdOrigin, normal) * dvp->getScale());
|
||||
onCurve.second(onCurve.second().ProjectToPlane(stdOrigin, normal) * dvp->getScale());
|
||||
arcEnds.first(arcEnds.first().ProjectToPlane(stdOrigin, normal) * dvp->getScale());
|
||||
arcEnds.second(arcEnds.second().ProjectToPlane(stdOrigin, normal) * dvp->getScale());
|
||||
midArc = midArc.ProjectToPlane(stdOrigin, normal) * dvp->getScale();
|
||||
center = dvp->projectPoint(center) * dvp->getScale();
|
||||
onCurve.first(dvp->projectPoint(onCurve.first()) * dvp->getScale());
|
||||
onCurve.second(dvp->projectPoint(onCurve.second()) * dvp->getScale());
|
||||
arcEnds.first(dvp->projectPoint(arcEnds.first()) * dvp->getScale());
|
||||
arcEnds.second(dvp->projectPoint(arcEnds.second()) * dvp->getScale());
|
||||
midArc = dvp->projectPoint(midArc) * dvp->getScale();
|
||||
}
|
||||
|
||||
void arcPoints::mapToPage(DrawViewPart* dvp)
|
||||
|
||||
@@ -25,18 +25,29 @@
|
||||
# include <TopoDS_Shape.hxx>
|
||||
#endif
|
||||
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <BRepAdaptor_Curve.hxx>
|
||||
#include <BRepBuilderAPI_MakeVertex.hxx>
|
||||
#include <TopExp.hxx>
|
||||
|
||||
#include <App/GeoFeature.h>
|
||||
#include <Base/Console.h>
|
||||
#include <Mod/Part/App/TopoShape.h>
|
||||
#include <Mod/PartDesign/App/Body.h>
|
||||
#include <Mod/PartDesign/App/Feature.h>
|
||||
|
||||
#include "DimensionReferences.h"
|
||||
#include "DrawUtil.h"
|
||||
#include "DrawViewPart.h"
|
||||
#include "GeometryObject.h"
|
||||
|
||||
|
||||
using namespace TechDraw;
|
||||
using DU = DrawUtil;
|
||||
|
||||
TopoDS_Shape ReferenceEntry::getGeometry() const
|
||||
{
|
||||
// Base::Console().Message("RE::getGeometry()\n");
|
||||
if ( getObject()->isDerivedFrom(TechDraw::DrawViewPart::getClassTypeId()) ) {
|
||||
TechDraw::DrawViewPart* dvp = static_cast<TechDraw::DrawViewPart*>(getObject());
|
||||
std::string gType = geomType();
|
||||
@@ -50,6 +61,7 @@ TopoDS_Shape ReferenceEntry::getGeometry() const
|
||||
auto fgeom = dvp->getFace(getSubName());
|
||||
return fgeom->toOccFace();
|
||||
}
|
||||
//Base::Console().Message("RE::getGeometry - returns null shape! - gType: %s\n", gType.c_str());
|
||||
return TopoDS_Shape();
|
||||
}
|
||||
|
||||
@@ -62,6 +74,7 @@ TopoDS_Shape ReferenceEntry::getGeometry() const
|
||||
if (getSubName().empty()) {
|
||||
return shape.getShape();
|
||||
}
|
||||
// TODO: what happens if the subelement is no longer present?
|
||||
return shape.getSubShape(getSubName().c_str());
|
||||
}
|
||||
|
||||
@@ -78,6 +91,58 @@ std::string ReferenceEntry::getSubName(bool longForm) const
|
||||
return workingSubName;
|
||||
}
|
||||
|
||||
App::DocumentObject* ReferenceEntry::getObject() const
|
||||
{
|
||||
// For PartDesign objects, when the reference is created from a selection,
|
||||
// the SelectionObject is a Feature within the Body.
|
||||
PartDesign::Body* pdBody = PartDesign::Body::findBodyOf(m_object);
|
||||
if (pdBody && pdBody->Tip.getValue()) {
|
||||
return pdBody->Tip.getValue();
|
||||
}
|
||||
return m_object;
|
||||
}
|
||||
|
||||
Part::TopoShape ReferenceEntry::asTopoShape()
|
||||
{
|
||||
// Base::Console().Message("RE::asTopoShape()\n");
|
||||
TopoDS_Shape geom = getGeometry();
|
||||
|
||||
if (geom.ShapeType() == TopAbs_VERTEX) {
|
||||
TopoDS_Vertex vert = TopoDS::Vertex(geom);
|
||||
return asTopoShapeVertex(vert);
|
||||
} else if (geom.ShapeType() == TopAbs_EDGE) {
|
||||
TopoDS_Edge edge = TopoDS::Edge(geom);
|
||||
return asTopoShapeEdge(edge);
|
||||
} else {
|
||||
throw Base::RuntimeError("Dimension Reference has unsupported geometry");
|
||||
}
|
||||
return Part::TopoShape();
|
||||
}
|
||||
|
||||
Part::TopoShape ReferenceEntry::asTopoShapeVertex(TopoDS_Vertex vert)
|
||||
{
|
||||
Base::Vector3d point = DU::toVector3d(BRep_Tool::Pnt(vert));
|
||||
if (!is3d()) {
|
||||
TechDraw::DrawViewPart* dvp = static_cast<TechDraw::DrawViewPart*>(getObject());
|
||||
point = point / dvp->getScale();
|
||||
}
|
||||
BRepBuilderAPI_MakeVertex mkVert(DU::togp_Pnt(point));
|
||||
return Part::TopoShape(mkVert.Vertex());
|
||||
}
|
||||
|
||||
Part::TopoShape ReferenceEntry::asTopoShapeEdge(TopoDS_Edge edge)
|
||||
{
|
||||
// Base::Console().Message("RE::asTopoShapeEdge()\n");
|
||||
TopoDS_Edge unscaledEdge = edge;
|
||||
if (!is3d()) {
|
||||
// 2d reference - projected and scaled. scale might have changed, so we need to unscale
|
||||
TechDraw::DrawViewPart* dvp = static_cast<TechDraw::DrawViewPart*>(getObject());
|
||||
TopoDS_Shape unscaledShape = TechDraw::scaleShape(edge, 1.0 / dvp->getScale());
|
||||
unscaledEdge = TopoDS::Edge(unscaledShape);
|
||||
}
|
||||
return Part::TopoShape(unscaledEdge);
|
||||
}
|
||||
|
||||
std::string ReferenceEntry::geomType() const
|
||||
{
|
||||
return DrawUtil::getGeomTypeFromName(getSubName());
|
||||
@@ -87,3 +152,12 @@ bool ReferenceEntry::isWholeObject() const
|
||||
{
|
||||
return getSubName().empty();
|
||||
}
|
||||
|
||||
bool ReferenceEntry::is3d() const
|
||||
{
|
||||
if ( getObject()->isDerivedFrom(TechDraw::DrawViewPart::getClassTypeId()) ) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,13 +29,21 @@
|
||||
#include <vector>
|
||||
|
||||
#include <TopoDS_Shape.hxx>
|
||||
#include <TopoDS_Edge.hxx>
|
||||
#include <TopoDS_Vertex.hxx>
|
||||
|
||||
#include <Mod/Part/App/TopoShape.h>
|
||||
|
||||
namespace App
|
||||
{
|
||||
class DocumentObject;
|
||||
}
|
||||
|
||||
namespace Part
|
||||
{
|
||||
class TopoShape;
|
||||
}
|
||||
|
||||
namespace TechDraw
|
||||
{
|
||||
|
||||
@@ -53,7 +61,7 @@ public:
|
||||
}
|
||||
~ReferenceEntry() = default;
|
||||
|
||||
App::DocumentObject* getObject() const { return m_object; }
|
||||
App::DocumentObject* getObject() const;
|
||||
void setObject(App::DocumentObject* docObj) { m_object = docObj; }
|
||||
std::string getSubName(bool longForm = false) const;
|
||||
void setSubName(std::string subName) { m_subName = subName; }
|
||||
@@ -61,8 +69,13 @@ public:
|
||||
std::string geomType() const;
|
||||
bool isWholeObject() const;
|
||||
|
||||
Part::TopoShape asTopoShape();
|
||||
Part::TopoShape asTopoShapeVertex(TopoDS_Vertex vert);
|
||||
Part::TopoShape asTopoShapeEdge(TopoDS_Edge edge);
|
||||
|
||||
bool is3d() const;
|
||||
|
||||
private:
|
||||
bool is3d();
|
||||
App::DocumentObject* m_object;
|
||||
std::string m_subName;
|
||||
};
|
||||
|
||||
@@ -55,7 +55,11 @@
|
||||
#include <Base/Quantity.h>
|
||||
#include <Base/Tools.h>
|
||||
#include <Base/UnitsApi.h>
|
||||
|
||||
#include <Mod/Measure/App/Measurement.h>
|
||||
#include <Mod/Part/App/Geometry.h>
|
||||
#include <Mod/Part/App/TopoShape.h>
|
||||
|
||||
#include <Mod/TechDraw/App/DrawViewDimensionPy.h> // generated from DrawViewDimensionPy.xml
|
||||
|
||||
#include "DrawViewDimension.h"
|
||||
@@ -63,10 +67,12 @@
|
||||
#include "DrawUtil.h"
|
||||
#include "DrawViewPart.h"
|
||||
#include "Geometry.h"
|
||||
#include "GeometryMatcher.h"
|
||||
#include "Preferences.h"
|
||||
|
||||
|
||||
using namespace TechDraw;
|
||||
using namespace Part;
|
||||
using DU = DrawUtil;
|
||||
|
||||
//===========================================================================
|
||||
// DrawViewDimension
|
||||
@@ -135,6 +141,9 @@ DrawViewDimension::DrawViewDimension()
|
||||
ADD_PROPERTY_TYPE(LineAngle, (0.0), "Override", App::Prop_Output, "Dimension line angle");
|
||||
ADD_PROPERTY_TYPE(ExtensionAngle, (0.0), "Override", App::Prop_Output, "Extension line angle");
|
||||
|
||||
ADD_PROPERTY_TYPE(SavedGeometry, () ,"References",(App::PropertyType)(App::Prop_None),"Reference Geometry");
|
||||
SavedGeometry.setOrderRelevant(true);
|
||||
|
||||
// hide the DrawView properties that don't apply to Dimensions
|
||||
ScaleType.setStatus(App::Property::ReadOnly, true);
|
||||
ScaleType.setStatus(App::Property::Hidden, true);
|
||||
@@ -158,7 +167,8 @@ DrawViewDimension::DrawViewDimension()
|
||||
resetAngular();
|
||||
resetArc();
|
||||
m_hasGeometry = false;
|
||||
m_formatter = new DimensionFormatter(this);
|
||||
m_matcher = new GeometryMatcher(this);
|
||||
m_referencesCorrect = true;
|
||||
}
|
||||
|
||||
DrawViewDimension::~DrawViewDimension()
|
||||
@@ -166,6 +176,7 @@ DrawViewDimension::~DrawViewDimension()
|
||||
delete measurement;
|
||||
measurement = nullptr;
|
||||
delete m_formatter;
|
||||
delete m_matcher;
|
||||
}
|
||||
|
||||
void DrawViewDimension::resetLinear()
|
||||
@@ -208,14 +219,19 @@ void DrawViewDimension::onChanged(const App::Property* prop)
|
||||
return;
|
||||
}
|
||||
|
||||
if (prop == &References3D) {//have to rebuild the Measurement object
|
||||
clear3DMeasurements(); //Measurement object
|
||||
if (prop == &References2D) {
|
||||
updateSavedGeometry();
|
||||
} else if (prop == &References3D) {
|
||||
// remove the old measurement object
|
||||
clear3DMeasurements();
|
||||
if (!(References3D.getValues()).empty()) {
|
||||
// rebuild the Measurement object
|
||||
setAll3DMeasurement();
|
||||
}
|
||||
else if (MeasureType.isValue("True")) {//empty 3dRefs, but True
|
||||
MeasureType.touch(); //run MeasureType logic for this case
|
||||
}
|
||||
updateSavedGeometry();
|
||||
return;
|
||||
}
|
||||
else if (prop == &Type) {//why??
|
||||
@@ -370,37 +386,26 @@ short DrawViewDimension::mustExecute() const
|
||||
|
||||
App::DocumentObjectExecReturn* DrawViewDimension::execute()
|
||||
{
|
||||
// Base::Console().Message("DVD::execute() - %s\n", getNameInDocument());
|
||||
if (!keepUpdated()) {
|
||||
// Base::Console().Message("DVD::execute() - %s\n", getNameInDocument());
|
||||
if (!okToProceed()) {
|
||||
return App::DocumentObject::StdReturn;
|
||||
}
|
||||
DrawViewPart* dvp = getViewPart();
|
||||
if (!dvp)
|
||||
return App::DocumentObject::StdReturn;
|
||||
|
||||
if (!has2DReferences() && !has3DReferences()) {
|
||||
//no references, can't do anything
|
||||
return App::DocumentObject::StdReturn;
|
||||
}
|
||||
|
||||
if (!getViewPart()->hasGeometry()) {
|
||||
//can't do anything until Source has geometry
|
||||
return App::DocumentObject::StdReturn;
|
||||
}
|
||||
|
||||
if (References3D.getValues().empty() && !checkReferences2D()) {
|
||||
Base::Console().Warning("DVD::execute - %s has invalid 2D References\n",
|
||||
getNameInDocument());
|
||||
return App::DocumentObject::StdReturn;
|
||||
}
|
||||
|
||||
//we have either or both valid References3D and References2D
|
||||
ReferenceVector references = getEffectiveReferences();
|
||||
|
||||
resetLinear();
|
||||
resetAngular();
|
||||
resetArc();
|
||||
|
||||
m_referencesCorrect = compareSavedGeometry();
|
||||
if (!m_referencesCorrect) {
|
||||
m_referencesCorrect = fixExactMatch();
|
||||
if (!m_referencesCorrect) {
|
||||
handleNoExactMatch();
|
||||
}
|
||||
}
|
||||
|
||||
//we have either or both valid References3D and References2D
|
||||
ReferenceVector references = getEffectiveReferences();
|
||||
|
||||
if (Type.isValue("Distance") || Type.isValue("DistanceX") || Type.isValue("DistanceY")) {
|
||||
if (getRefType() == oneEdge) {
|
||||
m_linearPoints = getPointsOneEdge(references);
|
||||
@@ -443,6 +448,35 @@ App::DocumentObjectExecReturn* DrawViewDimension::execute()
|
||||
return DrawView::execute();
|
||||
}
|
||||
|
||||
// true if we have enough information to execute, false otherwise
|
||||
bool DrawViewDimension::okToProceed()
|
||||
{
|
||||
if (!keepUpdated()) {
|
||||
return false;
|
||||
}
|
||||
DrawViewPart* dvp = getViewPart();
|
||||
if (!dvp)
|
||||
return false;
|
||||
|
||||
if (!has2DReferences() && !has3DReferences()) {
|
||||
//no references, can't do anything
|
||||
return App::DocumentObject::StdReturn;
|
||||
}
|
||||
|
||||
if (!getViewPart()->hasGeometry()) {
|
||||
//can't do anything until Source has geometry
|
||||
return false;
|
||||
}
|
||||
|
||||
if (References3D.getValues().empty() && !checkReferences2D()) {
|
||||
Base::Console().Warning("DVD::execute - %s has invalid 2D References\n",
|
||||
getNameInDocument());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////TODO: schema not report their multiValue status
|
||||
bool DrawViewDimension::isMultiValueSchema() const { return m_formatter->isMultiValueSchema(); }
|
||||
|
||||
@@ -615,7 +649,6 @@ pointPair DrawViewDimension::getPointsOneEdge(ReferenceVector references)
|
||||
pts.move(getViewPart()->getOriginalCentroid());
|
||||
pts.project(getViewPart());
|
||||
pts.mapToPage(getViewPart());
|
||||
pts.invertY();
|
||||
return pts;
|
||||
}
|
||||
|
||||
@@ -650,7 +683,6 @@ pointPair DrawViewDimension::getPointsTwoEdges(ReferenceVector references)
|
||||
pts.move(getViewPart()->getOriginalCentroid());
|
||||
pts.project(getViewPart());
|
||||
pts.mapToPage(getViewPart());
|
||||
pts.invertY();
|
||||
return pts;
|
||||
}
|
||||
|
||||
@@ -690,7 +722,6 @@ pointPair DrawViewDimension::getPointsTwoVerts(ReferenceVector references)
|
||||
pts.move(getViewPart()->getOriginalCentroid());
|
||||
pts.project(getViewPart());
|
||||
pts.mapToPage(getViewPart());
|
||||
pts.invertY();
|
||||
return pts;
|
||||
}
|
||||
|
||||
@@ -731,7 +762,6 @@ pointPair DrawViewDimension::getPointsEdgeVert(ReferenceVector references)
|
||||
pts.move(getViewPart()->getOriginalCentroid());
|
||||
pts.project(getViewPart());
|
||||
pts.mapToPage(getViewPart());
|
||||
pts.invertY();
|
||||
return pts;
|
||||
}
|
||||
|
||||
@@ -762,7 +792,6 @@ arcPoints DrawViewDimension::getArcParameters(ReferenceVector references)
|
||||
pts.move(getViewPart()->getOriginalCentroid());
|
||||
pts.project(getViewPart());
|
||||
pts.mapToPage(getViewPart());
|
||||
pts.invertY();
|
||||
return pts;
|
||||
}
|
||||
|
||||
@@ -1089,7 +1118,6 @@ anglePoints DrawViewDimension::getAnglePointsTwoEdges(ReferenceVector references
|
||||
pts.move(getViewPart()->getOriginalCentroid());
|
||||
pts.project(getViewPart());
|
||||
pts.mapToPage(getViewPart());
|
||||
pts.invertY();
|
||||
return pts;
|
||||
}
|
||||
|
||||
@@ -1137,7 +1165,6 @@ anglePoints DrawViewDimension::getAnglePointsThreeVerts(ReferenceVector referenc
|
||||
pts.move(getViewPart()->getOriginalCentroid());
|
||||
pts.project(getViewPart());
|
||||
pts.mapToPage(getViewPart());
|
||||
pts.invertY();
|
||||
return pts;
|
||||
}
|
||||
|
||||
@@ -1206,6 +1233,21 @@ ReferenceVector DrawViewDimension::getReferences3d() const
|
||||
return refs3d;
|
||||
}
|
||||
|
||||
void DrawViewDimension::replaceReferenceSubElement2d(int iRef, std::string newSubelement)
|
||||
{
|
||||
// Base::Console().Message("DVD::replaceReferenceSubElement2d(%d, %s)\n", iRef, newSubelement.c_str());
|
||||
ReferenceVector refs = getReferences2d();
|
||||
refs.at(iRef).setSubName(newSubelement);
|
||||
setReferences2d(refs);
|
||||
}
|
||||
|
||||
void DrawViewDimension::replaceReferenceSubElement3d(int iRef, std::string newSubelement)
|
||||
{
|
||||
ReferenceVector refs = getReferences3d();
|
||||
refs.at(iRef).setSubName(newSubelement);
|
||||
setReferences3d(refs);
|
||||
}
|
||||
|
||||
//what configuration of references do we have - Vertex-Vertex, Edge-Vertex, Edge, ...
|
||||
int DrawViewDimension::getRefType() const
|
||||
{
|
||||
@@ -1313,6 +1355,275 @@ bool DrawViewDimension::checkReferences2D() const
|
||||
return true;
|
||||
}
|
||||
|
||||
void DrawViewDimension::updateSavedGeometry()
|
||||
{
|
||||
// Base::Console().Message("DVD::updateSavedGeometry() - %s - savedGeometry: %d\n",
|
||||
// getNameInDocument(), SavedGeometry.getValues().size());
|
||||
ReferenceVector references = getEffectiveReferences();
|
||||
std::vector<TopoShape> newGeometry;
|
||||
const std::vector<TopoShape> oldGeometry = SavedGeometry.getValues();
|
||||
//need to clean up old geometry objects here?
|
||||
|
||||
for (auto& entry : references) {
|
||||
if (entry.getSubName().empty()) {
|
||||
// view only reference has no geometry.
|
||||
continue;
|
||||
}
|
||||
newGeometry.push_back(entry.asTopoShape());
|
||||
// Base::Console().Message("DVD::updateSavedGeometry - entry.isNull: %d\n", entry.asTopoShape().isNull());
|
||||
}
|
||||
if (newGeometry.empty()) {
|
||||
//clear out the old SavedGeometry
|
||||
SavedGeometry.clear();
|
||||
} else {
|
||||
SavedGeometry.setValues(newGeometry);
|
||||
}
|
||||
}
|
||||
|
||||
// routines related to detecting that references no longer point to the same geometry as
|
||||
// when they were created.
|
||||
// returns true if the saved geometry is the same as the current reference geometry
|
||||
// returns false if the saved geometry is different from the the current reference geometry
|
||||
bool DrawViewDimension::compareSavedGeometry()
|
||||
{
|
||||
// Base::Console().Message("DVD::compareSavedGeometry() - isRestoring: %d\n", isRestoring());
|
||||
const std::vector<TopoShape> savedGeometry = SavedGeometry.getValues();
|
||||
if (savedGeometry.empty()) {
|
||||
// no saved geometry, so we have nothing to compare, so we don't know if there has been a change
|
||||
return true;
|
||||
}
|
||||
|
||||
ReferenceVector references = getEffectiveReferences();
|
||||
std::vector<Part::TopoShape> referenceGeometry;
|
||||
for (auto& entry : references) {
|
||||
referenceGeometry.push_back(entry.asTopoShape());
|
||||
}
|
||||
if (savedGeometry.size() != referenceGeometry.size()) {
|
||||
// Base::Console().Message("DVD::compareSavedGeometry - geometry sizes have changed\n");
|
||||
return false;
|
||||
}
|
||||
int geometryCount = savedGeometry.size();
|
||||
int iGeom = 0;
|
||||
for ( ; iGeom < geometryCount; iGeom++) {
|
||||
if (savedGeometry.at(iGeom).getTypeId() != referenceGeometry.at(iGeom).getTypeId()) {
|
||||
// Base::Console().Message("DVD::compareSavedGeometry - saved geometry (%d) has different type\n", iGeom);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//saved and reference geometry have same count and types
|
||||
for (iGeom = 0; iGeom < geometryCount; iGeom++) {
|
||||
Part::TopoShape temp = savedGeometry.at(iGeom);
|
||||
if (!m_matcher->compareGeometry(temp, referenceGeometry.at(iGeom)) ) {
|
||||
// Base::Console().Message("DVD::compareSavedGeometry - saved geometry (%d) does not match current geometry\n", iGeom);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//free the reference geometry?
|
||||
return true;
|
||||
}
|
||||
|
||||
// deal with the situation where references do not point to the same geometry as
|
||||
// when they were created.
|
||||
bool DrawViewDimension::fixExactMatch()
|
||||
{
|
||||
// Base::Console().Message("DVD::fixExactMatch() - reference geometry has changed\n");
|
||||
if (!Preferences::autoCorrectDimRefs()) {
|
||||
return false;
|
||||
}
|
||||
ReferenceVector references = getEffectiveReferences();
|
||||
std::vector< std::pair<int, std::string> > refsToFix2d;
|
||||
std::vector< std::pair<int, std::string> > refsToFix3d;
|
||||
bool success(true);
|
||||
int referenceCount = references.size();
|
||||
int iRef = 0;
|
||||
for ( ; iRef < referenceCount; iRef++) {
|
||||
std::string newReference("");
|
||||
TopoDS_Shape geomShape = references.at(iRef).getGeometry();
|
||||
if (references.at(iRef).is3d()) {
|
||||
if (geomShape.ShapeType() == TopAbs_VERTEX) {
|
||||
newReference = recoverChangedVertex3d(iRef);
|
||||
} else {
|
||||
newReference = recoverChangedEdge3d(iRef);
|
||||
}
|
||||
if (!newReference.empty()) {
|
||||
std::pair<int, std::string> toFix(iRef, newReference);
|
||||
refsToFix3d.push_back(toFix);
|
||||
} else {
|
||||
Base::Console().Warning("%s - no exact match for changed 3d reference: %d\n", getNameInDocument(), iRef);
|
||||
success = false;
|
||||
}
|
||||
} else {
|
||||
if (geomShape.ShapeType() == TopAbs_VERTEX) {
|
||||
newReference = recoverChangedVertex2d(iRef);
|
||||
} else {
|
||||
newReference = recoverChangedEdge2d(iRef);
|
||||
}
|
||||
if (!newReference.empty()) {
|
||||
std::pair<int, std::string> toFix(iRef, newReference);
|
||||
refsToFix2d.push_back(toFix);
|
||||
} else {
|
||||
Base::Console().Warning("%s - no exact match for changed 2d reference: %d\n", getNameInDocument(), iRef);
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& fix : refsToFix2d) {
|
||||
replaceReferenceSubElement2d(fix.first, fix.second);
|
||||
}
|
||||
for (auto& fix : refsToFix3d) {
|
||||
replaceReferenceSubElement3d(fix.first, fix.second);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
// deal with situation where the current geometry does not match the saved geometry,
|
||||
// but we did not find an exact match in the geometry pile
|
||||
void DrawViewDimension::handleNoExactMatch()
|
||||
{
|
||||
// Base::Console().Message("DVD::handleNoExactMatch()\n");
|
||||
Base::Console().Message("%s - trying to match changed geometry - stage 2\n", getNameInDocument());
|
||||
// this is where we insert the clever logic to determine that the changed geometry
|
||||
// actually still represents the "front top left" edge.
|
||||
updateSavedGeometry();
|
||||
m_referencesCorrect = true;
|
||||
}
|
||||
|
||||
//find an edge in the view that matches the reference entry's type and characteristics
|
||||
std::string DrawViewDimension::recoverChangedEdge2d(int iReference)
|
||||
{
|
||||
// Base::Console().Message("DVD::recoverChangedEdge2d(ref: %d)\n", iReference);
|
||||
double scale = getViewPart()->getScale();
|
||||
Part::TopoShape savedGeometryItem = SavedGeometry.getValues().at(iReference);
|
||||
std::vector<TechDraw::BaseGeomPtr> gEdges = getViewPart()->getEdgeGeometry();
|
||||
int iEdge = 0;
|
||||
for (auto& edge : gEdges) {
|
||||
Part::TopoShape temp = edge->asTopoShape(scale);
|
||||
if (savedGeometryItem.getTypeId() != temp.getTypeId()) {
|
||||
// if the typeIds don't match, we can not compare the geometry
|
||||
// Base::Console().Message("DVD::recoverChangedEdge2d - types do not match\n");
|
||||
iEdge++;
|
||||
continue;
|
||||
}
|
||||
bool isSame = m_matcher->compareGeometry(savedGeometryItem, temp);
|
||||
// Base::Console().Message("DVD::recoverChangedEdge2d - iEdge: %d isSame: %d\n", iEdge, isSame);
|
||||
if (isSame) {
|
||||
return std::string("Edge") + std::to_string(iEdge);
|
||||
}
|
||||
iEdge++;
|
||||
}
|
||||
return std::string("");
|
||||
}
|
||||
|
||||
std::string DrawViewDimension::recoverChangedVertex2d(int iReference)
|
||||
{
|
||||
// Base::Console().Message("DVD::recoverChangedVertex2d(%d)\n", iReference);
|
||||
double scale = getViewPart()->getScale();
|
||||
Part::TopoShape savedGeometryItem = SavedGeometry.getValues().at(iReference);
|
||||
std::vector<TechDraw::VertexPtr> gVertexAll = getViewPart()->getVertexGeometry();
|
||||
int iVertex = 0;
|
||||
for (auto& vert : gVertexAll) {
|
||||
Part::TopoShape temp = vert->asTopoShape(scale);
|
||||
bool isSame = m_matcher->compareGeometry(savedGeometryItem, temp);
|
||||
if (isSame) {
|
||||
return std::string("Vertex") + std::to_string(iVertex);
|
||||
}
|
||||
iVertex++;
|
||||
}
|
||||
return std::string("");
|
||||
}
|
||||
|
||||
std::string DrawViewDimension::recoverChangedEdge3d(int iReference)
|
||||
{
|
||||
// Base::Console().Message("DVD::recoverChangedEdge3d(%d)\n", iReference);
|
||||
Part::TopoShape savedGeometryItem = SavedGeometry.getValues().at(iReference);
|
||||
ReferenceVector references = getEffectiveReferences();
|
||||
App::DocumentObject* searchObject = references.at(iReference).getObject();
|
||||
Part::TopoShape shape = Part::Feature::getTopoShape(searchObject);
|
||||
App::GeoFeature* geoFeat = dynamic_cast<App::GeoFeature*>(searchObject);
|
||||
//does a feature in a body get the body's globalPlacement??
|
||||
if (geoFeat) {
|
||||
shape.setPlacement(geoFeat->globalPlacement());
|
||||
}
|
||||
//TODO: these TopoShapes will have to be released when we are finished with them
|
||||
std::vector<TopoShape> edgesAll = getEdges(shape);
|
||||
int iEdge = 1; //note that edge numbering starts at 1!
|
||||
for (auto& edge : edgesAll) {
|
||||
bool isSame = m_matcher->compareGeometry(savedGeometryItem, edge);
|
||||
if (isSame) {
|
||||
return std::string("Edge") + std::to_string(iEdge);
|
||||
}
|
||||
iEdge++;
|
||||
}
|
||||
return std::string("");
|
||||
}
|
||||
|
||||
// based on Part::TopoShapePyImp::getShapes. Produces a vector of unique edges within the shape
|
||||
std::vector<TopoShape> DrawViewDimension::getEdges(const TopoShape& inShape)
|
||||
{
|
||||
std::vector<TopoShape> ret;
|
||||
TopTools_IndexedMapOfShape M;
|
||||
TopExp_Explorer Ex(inShape.getShape(), TopAbs_EDGE);
|
||||
while (Ex.More()) {
|
||||
M.Add(Ex.Current());
|
||||
Ex.Next();
|
||||
}
|
||||
|
||||
for (Standard_Integer k = 1; k <= M.Extent(); k++) {
|
||||
const TopoDS_Shape& shape = M(k);
|
||||
ret.push_back(TopoShape(shape));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// as recoverChangedVertex2d, but 3d references do not need to be unscaled
|
||||
std::string DrawViewDimension::recoverChangedVertex3d(int iReference)
|
||||
{
|
||||
// Base::Console().Message("DVD::recoverChangedVertex3d(%d)\n", iReference);
|
||||
Part::TopoShape savedGeometryItem = SavedGeometry.getValues().at(iReference);
|
||||
ReferenceVector references = getEffectiveReferences();
|
||||
App::DocumentObject* searchObject = references.at(iReference).getObject();
|
||||
Part::TopoShape shape = Part::Feature::getTopoShape(searchObject);
|
||||
App::GeoFeature* geoFeat = dynamic_cast<App::GeoFeature*>(searchObject);
|
||||
if (geoFeat) {
|
||||
shape.setPlacement(geoFeat->globalPlacement());
|
||||
}
|
||||
|
||||
//TODO: these TopoShapes will have to be released when we are finished with them
|
||||
std::vector<TopoShape> vertsAll = getVertexes(shape);
|
||||
int iVert = 1; //note that vertex numbering starts at 1!
|
||||
for (auto& vert : vertsAll) {
|
||||
bool isSame = m_matcher->compareGeometry(savedGeometryItem, vert);
|
||||
if (isSame) {
|
||||
return std::string("Vertex") + std::to_string(iVert);
|
||||
}
|
||||
iVert++;
|
||||
}
|
||||
return std::string("");
|
||||
}
|
||||
|
||||
// based on Part::TopoShapePyImp::getShapes
|
||||
std::vector<TopoShape> DrawViewDimension::getVertexes(const TopoShape& inShape)
|
||||
{
|
||||
std::vector<TopoShape> ret;
|
||||
TopTools_IndexedMapOfShape M;
|
||||
TopExp_Explorer Ex(inShape.getShape(), TopAbs_VERTEX);
|
||||
while (Ex.More()) {
|
||||
M.Add(Ex.Current());
|
||||
Ex.Next();
|
||||
}
|
||||
|
||||
for (Standard_Integer k = 1; k <= M.Extent(); k++) {
|
||||
const TopoDS_Shape& shape = M(k);
|
||||
ret.push_back(TopoShape(shape));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
pointPair DrawViewDimension::closestPoints(TopoDS_Shape s1, TopoDS_Shape s2) const
|
||||
{
|
||||
pointPair result;
|
||||
@@ -1334,6 +1645,7 @@ pointPair DrawViewDimension::closestPoints(TopoDS_Shape s1, TopoDS_Shape s2) con
|
||||
//set the reference property from a reference vector
|
||||
void DrawViewDimension::setReferences2d(ReferenceVector refs)
|
||||
{
|
||||
// Base::Console().Message("DVD::setReferences2d(%d)\n", refs.size());
|
||||
std::vector<App::DocumentObject*> objects;
|
||||
std::vector<std::string> subNames;
|
||||
if (objects.size() != subNames.size()) {
|
||||
@@ -1351,6 +1663,11 @@ void DrawViewDimension::setReferences2d(ReferenceVector refs)
|
||||
//set the reference property from a reference vector
|
||||
void DrawViewDimension::setReferences3d(ReferenceVector refs)
|
||||
{
|
||||
if (refs.empty() && !References3D.getValues().empty()) {
|
||||
//clear the property of any old links
|
||||
References3D.setValue(nullptr, nullptr);
|
||||
return;
|
||||
}
|
||||
std::vector<App::DocumentObject*> objects;
|
||||
std::vector<std::string> subNames;
|
||||
if (objects.size() != subNames.size()) {
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
|
||||
#include <App/DocumentObject.h>
|
||||
#include <Base/UnitsApi.h>
|
||||
#include <Mod/Part/App/PropertyTopoShapeList.h>
|
||||
|
||||
#include <Mod/TechDraw/TechDrawGlobal.h>
|
||||
|
||||
#include "DimensionGeometry.h"
|
||||
@@ -35,7 +37,6 @@
|
||||
#include "DrawView.h"
|
||||
#include "DrawViewPart.h"
|
||||
|
||||
|
||||
class TopoDS_Shape;
|
||||
|
||||
namespace Measure {
|
||||
@@ -45,6 +46,7 @@ namespace TechDraw
|
||||
{
|
||||
class DrawViewPart;
|
||||
class DimensionFormatter;
|
||||
class GeometryMatcher;
|
||||
|
||||
class TechDrawExport DrawViewDimension : public TechDraw::DrawView
|
||||
{
|
||||
@@ -88,6 +90,8 @@ enum DimensionType {
|
||||
App::PropertyAngle LineAngle;
|
||||
App::PropertyAngle ExtensionAngle;
|
||||
|
||||
Part::PropertyTopoShapeList SavedGeometry;
|
||||
|
||||
enum RefType{
|
||||
invalidRef,
|
||||
oneEdge,
|
||||
@@ -157,6 +161,7 @@ enum DimensionType {
|
||||
bool useDecimals() const;
|
||||
bool isExtentDim() const;
|
||||
virtual ReferenceVector getEffectiveReferences() const;
|
||||
bool goodReferenceGeometry() const { return m_referencesCorrect; }
|
||||
|
||||
protected:
|
||||
void handleChangedPropertyType(Base::XMLReader &, const char * , App::Property * ) override;
|
||||
@@ -177,7 +182,6 @@ protected:
|
||||
virtual anglePoints getAnglePointsTwoEdges(ReferenceVector references);
|
||||
virtual anglePoints getAnglePointsThreeVerts(ReferenceVector references);
|
||||
|
||||
protected:
|
||||
Measure::Measurement *measurement;
|
||||
double dist2Segs(Base::Vector3d s1,
|
||||
Base::Vector3d e1,
|
||||
@@ -190,6 +194,21 @@ protected:
|
||||
void resetAngular();
|
||||
void resetArc();
|
||||
|
||||
bool okToProceed();
|
||||
void updateSavedGeometry();
|
||||
bool compareSavedGeometry();
|
||||
bool fixExactMatch();
|
||||
void handleNoExactMatch();
|
||||
std::string recoverChangedEdge2d(int iReference);
|
||||
std::string recoverChangedEdge3d(int iReference);
|
||||
std::string recoverChangedVertex2d(int iReference);
|
||||
std::string recoverChangedVertex3d(int iReference);
|
||||
void replaceReferenceSubElement2d(int iRef, std::string newSubelement);
|
||||
void replaceReferenceSubElement3d(int iRef, std::string newSubelement);
|
||||
|
||||
std::vector<Part::TopoShape> getEdges(const Part::TopoShape& inShape);
|
||||
std::vector<Part::TopoShape> getVertexes(const Part::TopoShape& inShape);
|
||||
|
||||
private:
|
||||
static const char* TypeEnums[];
|
||||
static const char* MeasureTypeEnums[];
|
||||
@@ -203,6 +222,9 @@ private:
|
||||
|
||||
friend class DimensionFormatter;
|
||||
DimensionFormatter* m_formatter;
|
||||
GeometryMatcher* m_matcher;
|
||||
|
||||
bool m_referencesCorrect;
|
||||
};
|
||||
|
||||
} //namespace TechDraw
|
||||
|
||||
@@ -1336,9 +1336,8 @@ Base::Vector3d DrawViewPart::getXDirection() const
|
||||
Base::Vector3d dir = Direction.getValue(); //make a sensible default
|
||||
Base::Vector3d org(0.0, 0.0, 0.0);
|
||||
result = getLegacyX(org, dir);
|
||||
}
|
||||
else {
|
||||
result = propVal;//normal case. XDirection is set.
|
||||
} else {
|
||||
result = propVal; //normal case. XDirection is set.
|
||||
}
|
||||
}
|
||||
else { //no Property. can this happen?
|
||||
|
||||
@@ -74,13 +74,18 @@
|
||||
#include <Base/Reader.h>
|
||||
#include <Base/Writer.h>
|
||||
|
||||
#include <Mod/Part/App/Geometry.h>
|
||||
#include <Mod/Part/App/TopoShape.h>
|
||||
|
||||
#include "Geometry.h"
|
||||
#include "GeometryObject.h"
|
||||
#include "DrawUtil.h"
|
||||
|
||||
|
||||
using namespace TechDraw;
|
||||
using namespace Part;
|
||||
using namespace std;
|
||||
using DU = DrawUtil;
|
||||
|
||||
#if OCC_VERSION_HEX >= 0x070600
|
||||
using BRepAdaptor_HCurve = BRepAdaptor_Curve;
|
||||
@@ -704,6 +709,14 @@ void BaseGeom::intersectionCC(TechDraw::BaseGeomPtr geom1,
|
||||
}
|
||||
}
|
||||
|
||||
TopoShape BaseGeom::asTopoShape(double scale)
|
||||
{
|
||||
// Base::Console().Message("BG::asTopoShape(%.3f) - dump: %s\n", scale, dump().c_str());
|
||||
TopoDS_Shape unscaledShape = TechDraw::scaleShape(getOCCEdge(), 1.0 / scale);
|
||||
TopoDS_Edge unscaledEdge = TopoDS::Edge(unscaledShape);
|
||||
return unscaledEdge;
|
||||
}
|
||||
|
||||
Ellipse::Ellipse(const TopoDS_Edge &e)
|
||||
{
|
||||
geomType = ELLIPSE;
|
||||
@@ -1496,6 +1509,14 @@ void Vertex::dump(const char* title)
|
||||
cosmeticTag.c_str());
|
||||
}
|
||||
|
||||
TopoShape Vertex::asTopoShape(double scale)
|
||||
{
|
||||
Base::Vector3d point = DU::toVector3d(BRep_Tool::Pnt(getOCCVertex()));
|
||||
point = point / scale;
|
||||
BRepBuilderAPI_MakeVertex mkVert(DU::togp_Pnt(point));
|
||||
return TopoShape(mkVert.Vertex());
|
||||
}
|
||||
|
||||
|
||||
/*static*/
|
||||
BaseGeomPtrVector GeometryUtils::chainGeoms(BaseGeomPtrVector geoms)
|
||||
|
||||
@@ -36,6 +36,9 @@
|
||||
#include <TopoDS_Vertex.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
|
||||
namespace Part {
|
||||
class TopoShape;
|
||||
}
|
||||
|
||||
namespace TechDraw {
|
||||
|
||||
@@ -142,6 +145,7 @@ class TechDrawExport BaseGeom : public std::enable_shared_from_this<BaseGeom>
|
||||
void sourceIndex(int si) { m_sourceIndex = si; }
|
||||
std::string getCosmeticTag() { return cosmeticTag; }
|
||||
void setCosmeticTag(std::string t) { cosmeticTag = t; }
|
||||
Part::TopoShape asTopoShape(double scale);
|
||||
|
||||
protected:
|
||||
void createNewTag();
|
||||
@@ -377,6 +381,8 @@ class TechDrawExport Vertex
|
||||
bool isReference() { return m_reference; }
|
||||
void isReference(bool state) { m_reference = state; }
|
||||
|
||||
Part::TopoShape asTopoShape(double scale);
|
||||
|
||||
protected:
|
||||
//Uniqueness
|
||||
void createNewTag();
|
||||
|
||||
262
src/Mod/TechDraw/App/GeometryMatcher.cpp
Normal file
262
src/Mod/TechDraw/App/GeometryMatcher.cpp
Normal file
@@ -0,0 +1,262 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 WandererFan <wandererfan@gmail.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 *
|
||||
* *
|
||||
***************************************************************************/
|
||||
// a class to handle changes to dimension reference geometry
|
||||
|
||||
// detects changes in reference geometry (2d & 3d) that would invalidate a dimension
|
||||
// identifies replacement view/model geometry
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#endif
|
||||
|
||||
#include <BRepAdaptor_Curve.hxx>
|
||||
#include <BRepLProp_CLProps.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <gp_Circ.hxx>
|
||||
#include <gp_Elips.hxx>
|
||||
#include <TopExp.hxx>
|
||||
#include <TopoDS_Edge.hxx>
|
||||
#include <TopoDS_Shape.hxx>
|
||||
#include <TopoDS_Vertex.hxx>
|
||||
|
||||
#include <Base/Console.h>
|
||||
#include <Base/Tools.h>
|
||||
|
||||
#include <Mod/Part/App/TopoShape.h>
|
||||
|
||||
#include "GeometryMatcher.h"
|
||||
#include "DrawUtil.h"
|
||||
|
||||
using namespace TechDraw;
|
||||
using DU = DrawUtil;
|
||||
|
||||
// a set of routines for comparing geometry for equality.
|
||||
|
||||
bool GeometryMatcher::compareGeometry(Part::TopoShape shape1, Part::TopoShape shape2)
|
||||
{
|
||||
// Base::Console().Message("GM::compareGeometry()\n");
|
||||
if (shape1.isNull() || shape2.isNull()) {
|
||||
Base::Console().Message("GM::compareGeometry - one or more shapes are null\n");
|
||||
}
|
||||
TopoDS_Shape geom1 = shape1.getShape();
|
||||
TopoDS_Shape geom2 = shape2.getShape();
|
||||
if (geom1.ShapeType() == TopAbs_VERTEX) {
|
||||
return comparePoints(geom1, geom2);
|
||||
}
|
||||
if (geom1.ShapeType() == TopAbs_EDGE) {
|
||||
return compareEdges(geom1, geom2);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GeometryMatcher::comparePoints(TopoDS_Shape shape1, TopoDS_Shape shape2)
|
||||
{
|
||||
// Base::Console().Message("GM::comparePoints()\n");
|
||||
if (shape1.ShapeType() != TopAbs_VERTEX ||
|
||||
shape2.ShapeType() != TopAbs_VERTEX) {
|
||||
// can not compare these shapes
|
||||
return false;
|
||||
}
|
||||
auto vert1 = TopoDS::Vertex(shape1);
|
||||
Base::Vector3d point1 = DU::toVector3d(BRep_Tool::Pnt(vert1));
|
||||
auto vert2 = TopoDS::Vertex(shape2);
|
||||
Base::Vector3d point2 = DU::toVector3d(BRep_Tool::Pnt(vert2));
|
||||
if (point1.IsEqual(point2, EWTOLERANCE)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GeometryMatcher::compareEdges(TopoDS_Shape shape1, TopoDS_Shape shape2)
|
||||
{
|
||||
// Base::Console().Message("GM::compareEdges()\n");
|
||||
if (shape1.ShapeType() != TopAbs_EDGE ||
|
||||
shape2.ShapeType() != TopAbs_EDGE) {
|
||||
// can not compare these shapes
|
||||
// Base::Console().Message("GM::compareEdges - shape is not an edge\n");
|
||||
return false;
|
||||
}
|
||||
TopoDS_Edge edge1 = TopoDS::Edge(shape1);
|
||||
TopoDS_Edge edge2 = TopoDS::Edge(shape2);
|
||||
BRepAdaptor_Curve adapt1(edge1);
|
||||
BRepAdaptor_Curve adapt2(edge2);
|
||||
|
||||
if (adapt1.GetType() == GeomAbs_Line &&
|
||||
adapt2.GetType() == GeomAbs_Line) {
|
||||
return compareLines(edge1, edge2);
|
||||
}
|
||||
|
||||
if (adapt1.GetType() == GeomAbs_Circle &&
|
||||
adapt2.GetType() == GeomAbs_Circle) {
|
||||
if (adapt1.IsClosed() && adapt2.IsClosed()) {
|
||||
return compareCircles(edge1, edge2);
|
||||
} else {
|
||||
return compareCircleArcs(edge1, edge2);
|
||||
}
|
||||
}
|
||||
|
||||
if (adapt1.GetType() == GeomAbs_Ellipse &&
|
||||
adapt2.GetType() == GeomAbs_Ellipse) {
|
||||
if (adapt1.IsClosed() && adapt2.IsClosed()) {
|
||||
return compareEllipses(edge1, edge2);
|
||||
} else {
|
||||
return compareEllipseArcs(edge1, edge2);
|
||||
}
|
||||
}
|
||||
|
||||
if (adapt1.GetType() == GeomAbs_BSplineCurve &&
|
||||
adapt2.GetType() == GeomAbs_BSplineCurve) {
|
||||
return compareBSplines(edge1, edge2);
|
||||
}
|
||||
|
||||
// if we reach this point, we have dissimilar geometry types
|
||||
return compareDifferent(edge1, edge2);
|
||||
}
|
||||
|
||||
bool GeometryMatcher::compareLines(TopoDS_Edge edge1, TopoDS_Edge edge2)
|
||||
{
|
||||
// Base::Console().Message("GM::compareLines()\n");
|
||||
auto start1 = DU::toVector3d(BRep_Tool::Pnt(TopExp::FirstVertex(edge1)));
|
||||
auto end1 = DU::toVector3d(BRep_Tool::Pnt(TopExp::LastVertex(edge1)));
|
||||
auto start2 = DU::toVector3d(BRep_Tool::Pnt(TopExp::FirstVertex(edge2)));
|
||||
auto end2 = DU::toVector3d(BRep_Tool::Pnt(TopExp::LastVertex(edge2)));
|
||||
if (start1.IsEqual(start2, EWTOLERANCE) &&
|
||||
end1.IsEqual(end2, EWTOLERANCE)) {
|
||||
//exact match
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GeometryMatcher::compareCircles(TopoDS_Edge edge1, TopoDS_Edge edge2)
|
||||
{
|
||||
// Base::Console().Message("GM::compareCircles()\n");
|
||||
BRepAdaptor_Curve adapt1(edge1);
|
||||
BRepAdaptor_Curve adapt2(edge2);
|
||||
gp_Circ circle1 = adapt1.Circle();
|
||||
gp_Circ circle2 = adapt2.Circle();
|
||||
double radius1 = circle1.Radius();
|
||||
double radius2 = circle2.Radius();
|
||||
auto center1 = DU::toVector3d(circle1.Location());
|
||||
auto center2 = DU::toVector3d(circle2.Location());
|
||||
if (DU::fpCompare(radius1, radius2, EWTOLERANCE) &&
|
||||
center1.IsEqual(center2, EWTOLERANCE)) {
|
||||
//exact match
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GeometryMatcher::compareEllipses(TopoDS_Edge edge1, TopoDS_Edge edge2)
|
||||
{
|
||||
BRepAdaptor_Curve adapt1(edge1);
|
||||
BRepAdaptor_Curve adapt2(edge2);
|
||||
gp_Elips ellipse1 = adapt1.Ellipse();
|
||||
gp_Elips ellipse2 = adapt2.Ellipse();
|
||||
double major1 = ellipse1.MajorRadius();
|
||||
double minor1 = ellipse1.MinorRadius();
|
||||
double major2 = ellipse2.MajorRadius();
|
||||
double minor2 = ellipse2.MinorRadius();
|
||||
auto center1 = DU::toVector3d(ellipse1.Location());
|
||||
auto center2 = DU::toVector3d(ellipse2.Location());
|
||||
if (DU::fpCompare(major1, major2, EWTOLERANCE) &&
|
||||
DU::fpCompare(minor1, minor2, EWTOLERANCE) &&
|
||||
center1.IsEqual(center2, EWTOLERANCE)) {
|
||||
// exact match
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// for our purposes, only circles masquerading as bsplines are of interest
|
||||
bool GeometryMatcher::compareBSplines(TopoDS_Edge edge1, TopoDS_Edge edge2)
|
||||
{
|
||||
BRepAdaptor_Curve adapt1(edge1);
|
||||
BRepAdaptor_Curve adapt2(edge2);
|
||||
bool isArc1(false);
|
||||
bool isArc2(false);
|
||||
TopoDS_Edge circleEdge1;
|
||||
TopoDS_Edge circleEdge2;
|
||||
try {
|
||||
circleEdge1 = GeometryUtils::asCircle(edge1, isArc1);
|
||||
circleEdge2 = GeometryUtils::asCircle(edge2, isArc1);
|
||||
}
|
||||
catch (Base::RuntimeError& e) {
|
||||
Base::Console().Error("GeometryMatcher failed to make circles from splines\n");
|
||||
return false;
|
||||
}
|
||||
if (!isArc1 && !isArc2) {
|
||||
// full circles
|
||||
return compareCircles(circleEdge1, circleEdge2);
|
||||
}
|
||||
if (isArc1 && isArc2) {
|
||||
// circular arcs
|
||||
return compareCircleArcs(circleEdge1, circleEdge2);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// this is a weak comparison. we should also check center & radius?
|
||||
bool GeometryMatcher::compareCircleArcs(TopoDS_Edge edge1, TopoDS_Edge edge2)
|
||||
{
|
||||
return compareEndPoints(edge1, edge2);
|
||||
}
|
||||
|
||||
bool GeometryMatcher::compareEllipseArcs(TopoDS_Edge edge1, TopoDS_Edge edge2)
|
||||
{
|
||||
return compareEndPoints(edge1, edge2);
|
||||
}
|
||||
|
||||
// this is where we would try to match a bspline against a line or a circle.
|
||||
// not sure how successful this would be. For now, we just say it doesn't match
|
||||
bool GeometryMatcher::compareDifferent(TopoDS_Edge edge1, TopoDS_Edge edge2)
|
||||
{
|
||||
BRepAdaptor_Curve adapt1(edge1);
|
||||
BRepAdaptor_Curve adapt2(edge2);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GeometryMatcher::compareEndPoints(TopoDS_Edge edge1, TopoDS_Edge edge2)
|
||||
{
|
||||
BRepAdaptor_Curve adapt1(edge1);
|
||||
BRepAdaptor_Curve adapt2(edge2);
|
||||
double pFirst1 = adapt1.FirstParameter();
|
||||
double pLast1 = adapt1.LastParameter();
|
||||
BRepLProp_CLProps props1(adapt1, pFirst1, 0, Precision::Confusion());
|
||||
auto begin1 = DU::toVector3d(props1.Value());
|
||||
props1.SetParameter(pLast1);
|
||||
auto end1 = DU::toVector3d(props1.Value());
|
||||
double pFirst2 = adapt2.FirstParameter();
|
||||
double pLast2 = adapt2.LastParameter();
|
||||
BRepLProp_CLProps props2(adapt2, pFirst2, 0, Precision::Confusion());
|
||||
auto begin2 = DU::toVector3d(props2.Value());
|
||||
props2.SetParameter(pLast2);
|
||||
auto end2 = DU::toVector3d(props2.Value());
|
||||
|
||||
if (begin1.IsEqual(begin2, EWTOLERANCE) &&
|
||||
end1.IsEqual(end2, EWTOLERANCE)) {
|
||||
//exact match
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
64
src/Mod/TechDraw/App/GeometryMatcher.h
Normal file
64
src/Mod/TechDraw/App/GeometryMatcher.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 WandererFan <wandererfan@gmail.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 *
|
||||
* *
|
||||
***************************************************************************/
|
||||
// a class to handle changes to dimension reference geometry
|
||||
|
||||
#ifndef GEOMETRYMATCHER_H
|
||||
#define GEOMETRYMATCHER_H
|
||||
|
||||
#include <Mod/TechDraw/TechDrawGlobal.h>
|
||||
|
||||
#include <DrawViewDimension.h>
|
||||
|
||||
namespace Part
|
||||
{
|
||||
class TopoShape;
|
||||
}
|
||||
|
||||
namespace TechDraw {
|
||||
|
||||
class TechDrawExport GeometryMatcher {
|
||||
public:
|
||||
GeometryMatcher() {}
|
||||
GeometryMatcher(DrawViewDimension* dim) { m_dimension = dim; }
|
||||
~GeometryMatcher() = default;
|
||||
|
||||
bool compareGeometry(Part::TopoShape geom1, Part::TopoShape geom2);
|
||||
bool comparePoints(TopoDS_Shape shape1, TopoDS_Shape shape2);
|
||||
bool compareEdges(TopoDS_Shape shape1, TopoDS_Shape shape2);
|
||||
|
||||
bool compareLines(TopoDS_Edge edge1, TopoDS_Edge edge2);
|
||||
bool compareCircles(TopoDS_Edge edge1, TopoDS_Edge edge2);
|
||||
bool compareEllipses(TopoDS_Edge edge1, TopoDS_Edge edge2);
|
||||
bool compareBSplines(TopoDS_Edge edge1, TopoDS_Edge edge2);
|
||||
bool compareDifferent(TopoDS_Edge edge1, TopoDS_Edge edge2);
|
||||
bool compareCircleArcs(TopoDS_Edge edge1, TopoDS_Edge edge2);
|
||||
bool compareEllipseArcs(TopoDS_Edge edge1, TopoDS_Edge edge2);
|
||||
|
||||
private:
|
||||
bool compareEndPoints(TopoDS_Edge edge1, TopoDS_Edge edge2);
|
||||
|
||||
DrawViewDimension* m_dimension;
|
||||
};
|
||||
|
||||
} //end namespace TechDraw
|
||||
#endif
|
||||
|
||||
@@ -1044,11 +1044,9 @@ void CmdTechDrawBalloon::activated(int iMsg)
|
||||
{
|
||||
Q_UNUSED(iMsg);
|
||||
bool result = _checkSelectionBalloon(this, 1);
|
||||
if (!result)
|
||||
if (!result) {
|
||||
return;
|
||||
// result = _checkDrawViewPartBalloon(this);
|
||||
// if (!result)
|
||||
// return;
|
||||
}
|
||||
|
||||
std::vector<Gui::SelectionObject> selection = getSelection().getSelectionEx();
|
||||
|
||||
@@ -1085,7 +1083,8 @@ bool CmdTechDrawBalloon::isActive()
|
||||
{
|
||||
bool havePage = DrawGuiUtil::needPage(this);
|
||||
bool haveView = DrawGuiUtil::needView(this, false);
|
||||
return (havePage && haveView);
|
||||
bool taskInProgress = Gui::Control().activeDialog();
|
||||
return (havePage && haveView && !taskInProgress);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
||||
@@ -536,6 +536,7 @@ void QGIView::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, Q
|
||||
QRectF QGIView::customChildrenBoundingRect() const
|
||||
{
|
||||
QList<QGraphicsItem*> children = childItems();
|
||||
// exceptions not to be included in determining the frame rectangle
|
||||
int dimItemType = QGraphicsItem::UserType + 106; // TODO: Get magic number from include by name
|
||||
int borderItemType = QGraphicsItem::UserType + 136; // TODO: Magic number warning
|
||||
int labelItemType = QGraphicsItem::UserType + 135; // TODO: Magic number warning
|
||||
@@ -563,7 +564,6 @@ QRectF QGIView::customChildrenBoundingRect() const
|
||||
(child->type() != centerMarkItemType)) {
|
||||
QRectF childRect = mapFromItem(child, child->boundingRect()).boundingRect();
|
||||
result = result.united(childRect);
|
||||
//result = result.united((*it)->boundingRect());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
#include "QGIArrow.h"
|
||||
#include "QGIDimLines.h"
|
||||
#include "QGIVertex.h"
|
||||
#include "QGCustomSvg.h"
|
||||
#include "ViewProviderDimension.h"
|
||||
#include "ZVALUE.h"
|
||||
|
||||
@@ -512,6 +513,12 @@ QGIViewDimension::QGIViewDimension() : dvDimension(nullptr), hasHover(false), m_
|
||||
setZValue(ZVALUE::DIMENSION);//note: this won't paint dimensions over another View if it stacks
|
||||
//above this Dimension's parent view. need Layers?
|
||||
hideFrame();
|
||||
|
||||
m_refFlag = new QGCustomSvg();
|
||||
m_refFlag->setParentItem(this);
|
||||
m_refFlag->load(QString::fromUtf8(":/icons/TechDraw_RefError.svg"));
|
||||
m_refFlag->setZValue(ZVALUE::LOCK);
|
||||
m_refFlag->hide();
|
||||
}
|
||||
|
||||
QVariant QGIViewDimension::itemChange(GraphicsItemChange change, const QVariant& value)
|
||||
@@ -637,6 +644,14 @@ void QGIViewDimension::updateView(bool update)
|
||||
updateDim();
|
||||
}
|
||||
|
||||
if (dim->goodReferenceGeometry()) {
|
||||
m_refFlag->hide();
|
||||
} else {
|
||||
// m_refFlag->setPos(datumLabel->pos());
|
||||
m_refFlag->centerAt(datumLabel->pos() + datumLabel->boundingRect().center());
|
||||
m_refFlag->show();
|
||||
}
|
||||
|
||||
draw();
|
||||
}
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ class QGCustomText;
|
||||
class QGIArrow;
|
||||
class QGIDimLines;
|
||||
class QGIViewDimension;
|
||||
class QGCustomSvg;
|
||||
class ViewProviderDimension;
|
||||
|
||||
class QGIDatumLabel : public QGraphicsObject
|
||||
@@ -134,6 +135,7 @@ private:
|
||||
QGCustomText* m_tolTextOver;
|
||||
QGCustomText* m_tolTextUnder;
|
||||
QGCustomText* m_unitText;
|
||||
QGCustomText* m_referenceFlag;
|
||||
QColor m_colNormal;
|
||||
bool m_ctrl;
|
||||
|
||||
@@ -303,6 +305,9 @@ private:
|
||||
QGIArrow* aHead1;
|
||||
QGIArrow* aHead2;
|
||||
double m_lineWidth;
|
||||
|
||||
QGCustomSvg* m_refFlag;
|
||||
|
||||
};
|
||||
|
||||
} // namespace MDIViewPageGui
|
||||
|
||||
Reference in New Issue
Block a user