[TD]Refactor LTNP correction code for Dimensions

- additional geometry types

- add method to handle line like bsplines

- handle deleted ref body feature

- add test for empty savedGeometry

- add switch for matcher/LTNP on/off
This commit is contained in:
wmayer
2024-02-20 14:43:02 +01:00
committed by WandererFan
parent 1bc62cf113
commit 48ff9ad3a1
16 changed files with 1507 additions and 674 deletions

View File

@@ -106,6 +106,8 @@ SET(Draw_SRCS
DimensionFormatter.h
GeometryMatcher.cpp
GeometryMatcher.h
DimensionAutoCorrect.cpp
DimensionAutoCorrect.h
DrawViewBalloon.cpp
DrawViewBalloon.h
DrawViewSection.cpp

View File

@@ -0,0 +1,596 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/***************************************************************************
* 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 validate and correct dimension references
// the dimension reference auto correct algo:
//
// when a dimension is created, the shape of each reference is saved, so in addition
// to the dimensionedObject + subElement reference, we also keep a Part::TopoShape copy
// of the reference.
//
// when we later use that dimension, we check its references as follows:
// for each reference:
// // auto correct phase 1
// if ref.currentGeometry == ref.savedGeometry:
// // the reference points to the same geometry as before, so we
// // so we consider this to be correct. same geometry, same index case.
// continue
// else:
// // search all the source shapes for a subelement with the exact same
// // geometry. same geometry, different index case.
// newRef = searchForExactSameGeometry(ref) // geometry matcher
// if newRef:
// // substitute the reference we just found in place of the old
// // reference
// replace(ref, newRef)
// else:
// // auto correct phase 2
// // we don't have any geometry that is identical to our saved geometry.
// // finding a match now becomes guess work. we have to find the most
// // similar geometry (with at least some level of same-ness) and use
// // that to rebuild our reference.
// // we do not have a good algo for searchForMostSimilarGeometry() yet.
// newRef = searchForMostSimilarGeometry(ref) // geometry guesser
// if newRef:
// replace(ref, newRef)
// else:
// //we can't fix this
#include "PreCompiled.h"
#ifndef _PreComp_
#endif
#include <TopoDS_Shape.hxx>
#include <App/Document.h>
#include <Base/Console.h>
#include <Base/Tools.h>
#include <Mod/Part/App/TopoShape.h>
#include "GeometryMatcher.h"
#include "DimensionReferences.h"
#include "DimensionGeometry.h"
#include "DimensionAutoCorrect.h"
#include "DrawUtil.h"
#include "Preferences.h"
using namespace TechDraw;
using DU = DrawUtil;
//! true if references point to valid geometry and the valid geometry matches the
//! corresponding saved geometry. this method does not correct anything, it just
//! verifies if the references point to the same geometry as when the reference
//! was created.
bool DimensionAutoCorrect::referencesHaveValidGeometry(std::vector<bool>& referenceState) const
{
// Base::Console().Message("DAC::referencesHaveValidGeometry()\n");
ReferenceVector refsAll = getDimension()->getEffectiveReferences();
const std::vector<Part::TopoShape> savedGeometry = getDimension()->SavedGeometry.getValues();
if (savedGeometry.empty() || savedGeometry.size() != refsAll.size()) {
// this must be an old document without savedGeometry property. We can not
// validate the references in this case so we hope they are valid.
referenceState = std::vector<bool>(refsAll.size(), true);
return true;
}
bool result {true};
size_t iRef {0};
for (auto& entry : refsAll) {
if (entry.hasGeometry()) {
// entry points to something, is it the correct geom?
if (isMatchingGeometry(entry, savedGeometry.at(iRef))) {
referenceState.emplace_back(true);
}
else {
result = false;
referenceState.emplace_back(false);
}
}
else {
result = false;
referenceState.emplace_back(false);
}
}
return result;
}
//! try to correct references that point to non-existent geometry or when the saved
//! geometry does not match the current geometry the reference points to.
//! referenceState is the output of a previous use of referencesHaveValidGeometry.
bool DimensionAutoCorrect::autocorrectReferences(std::vector<bool>& referenceState,
ReferenceVector& repairedRefs) const
{
// Base::Console().Message("DAC::autocorrectReferences()\n");
if (!Preferences::autoCorrectDimRefs()) {
return false;
}
bool result {true};
ReferenceVector refsAll = getDimension()->getEffectiveReferences();
const std::vector<Part::TopoShape> savedGeometry = getDimension()->SavedGeometry.getValues();
if (savedGeometry.empty() || savedGeometry.size() != refsAll.size()) {
// this must be an old document without savedGeometry property. We can not
// validate the references in this case.
return false;
}
std::vector<Part::TopoShape> referenceGeometry;
for (auto& entry : refsAll) {
if (entry.hasGeometry()) {
referenceGeometry.push_back(entry.asTopoShape());
}
else {
referenceGeometry.push_back(Part::TopoShape());
}
}
size_t iRef {0};
for (const auto& state : referenceState) {
if (state) {
// ref points to valid geometry that matches saved geometry
referenceState.at(iRef) = true;
repairedRefs.push_back(refsAll.at(iRef));
iRef++;
continue;
}
Part::TopoShape temp = savedGeometry.at(iRef);
if (temp.isNull()) {
result = false;
referenceState.at(iRef) = false;
repairedRefs.push_back(refsAll.at(iRef));
iRef++;
// we could exit here instead of checking all the refs?
continue;
}
// this ref does not point to valid geometry or
// the geometry it points to does not match the saved geometry
ReferenceEntry fixedRef = refsAll.at(iRef);
// first, look for an exact match to the saved geometry
bool success = fix1GeomExact(fixedRef, savedGeometry.at(iRef).getShape());
if (success) {
// we did find a match
referenceState.at(iRef) = true;
repairedRefs.push_back(fixedRef);
iRef++;
continue;
}
// we did not find an exact match, so check for an Similar match
success = fix1GeomSimilar(fixedRef, savedGeometry.at(iRef).getShape());
if (success) {
// we did find an Similar match
referenceState.at(iRef) = true;
repairedRefs.push_back(fixedRef);
iRef++;
continue;
}
// we did not find an Similar match the geometry
result = false;
referenceState.at(iRef) = false;
repairedRefs.push_back(fixedRef);
iRef++;
// we could exit here
}
return result;
}
//! fix a single reference with an exact match to geomToFix
bool DimensionAutoCorrect::fix1GeomExact(ReferenceEntry& refToFix, TopoDS_Shape geomToFix) const
{
// Base::Console().Message("DAC::fix1GeomExact()\n");
ReferenceEntry fixedRef = refToFix;
Part::TopoShape topoShapeToFix(geomToFix);
bool success {false};
if (refToFix.is3d()) {
if (!refToFix.getObject() && m_3dObjectCache.empty()) {
return false;
}
if (geomToFix.ShapeType() == TopAbs_VERTEX) {
success = findExactVertex3d(refToFix, topoShapeToFix);
}
else {
success = findExactEdge3d(refToFix, topoShapeToFix);
}
}
else {
if (geomToFix.ShapeType() == TopAbs_VERTEX) {
success = findExactVertex2d(refToFix, topoShapeToFix);
}
else {
success = findExactEdge2d(refToFix, topoShapeToFix);
}
}
return success;
}
//! fix a single reference with an Similar match to geomToFix
bool DimensionAutoCorrect::fix1GeomSimilar(ReferenceEntry& refToFix, TopoDS_Shape geomToFix) const
{
// Base::Console().Message("DAC::fix1GeomSimilar()\n");
Part::TopoShape topoShapeToFix(geomToFix);
bool success {false};
if (refToFix.is3d()) {
if (!refToFix.getObject() && m_3dObjectCache.empty()) {
// can't fix this. nothing to compare.
return false;
}
if (geomToFix.ShapeType() == TopAbs_VERTEX) {
success = findSimilarVertex3d(refToFix, topoShapeToFix);
}
else {
success = findSimilarEdge3d(refToFix, topoShapeToFix);
}
}
else {
if (geomToFix.ShapeType() == TopAbs_VERTEX) {
success = findSimilarVertex2d(refToFix, topoShapeToFix);
}
else {
success = findSimilarEdge2d(refToFix, topoShapeToFix);
}
}
return success;
}
//! search the view for a 2d vertex that is the same as the saved reference geometry
//! and return a reference pointing to the matching vertex
bool DimensionAutoCorrect::findExactVertex2d(ReferenceEntry& refToFix,
Part::TopoShape refGeom) const
{
// Base::Console().Message("DAC::findExactVertex2d()\n");
getMatcher()->setPointTolerance(EWTOLERANCE);
auto refObj = refToFix.getObject();
auto refDvp = dynamic_cast<TechDraw::DrawViewPart*>(refObj);
if (refDvp) {
ReferenceEntry fixedRef = searchViewForVert(refDvp, refGeom);
if (fixedRef.getObject()) {
refToFix = fixedRef;
return true;
}
}
// no match
return false;
}
//! search the view for a 2d edge that is the same as the saved reference geometry
//! and return a reference pointing to the matching edge.
bool DimensionAutoCorrect::findExactEdge2d(ReferenceEntry& refToFix, Part::TopoShape refGeom) const
{
// Base::Console().Message("DAC::findExactEdge2d()\n");
double scale = getDimension()->getViewPart()->getScale();
BaseGeomPtrVector gEdgeAll = getDimension()->getViewPart()->getEdgeGeometry();
int iEdge {0};
for (auto& edge : gEdgeAll) {
Part::TopoShape temp = edge->asTopoShape(scale);
bool isSame = getMatcher()->compareGeometry(refGeom, temp);
if (isSame) {
refToFix.setSubName(std::string("Edge") + std::to_string(iEdge));
return true;
}
iEdge++;
}
// no match, return the input reference
return false;
}
//! search the model for a 3d vertex that is the same as the saved reference geometry
//! and return a reference pointing to the matching vertex
bool DimensionAutoCorrect::findExactVertex3d(ReferenceEntry& refToFix,
Part::TopoShape refGeom) const
{
// Base::Console().Message("DAC::findExactVertex3d()\n");
getMatcher()->setPointTolerance(EWTOLERANCE);
// try the referenced object
auto refObj = refToFix.getObject();
if (refObj) {
ReferenceEntry fixedRef = searchObjForVert(refObj, refGeom);
if (fixedRef.getObject()) {
refToFix = fixedRef;
return true;
}
}
// not match in refObj (or no refObj!)
for (auto& objectName : m_3dObjectCache) {
auto object3d = getDimension()->getDocument()->getObject(objectName.c_str());
ReferenceEntry fixedRef = searchObjForVert(object3d, refGeom);
if (fixedRef.getObject()) {
refToFix = fixedRef;
return true;
}
}
return false;
}
//! search the model for a 3d edge that is the same as the saved reference geometry
//! and return a reference pointing to the matching edge.
bool DimensionAutoCorrect::findExactEdge3d(ReferenceEntry& refToFix, Part::TopoShape refGeom) const
{
// Base::Console().Message("DAC::findExactEdge3d() - cache: %d\n", m_3dObjectCache.size());
// first, try to find a match in the referenced object
auto refObj = refToFix.getObject();
if (refObj) {
ReferenceEntry fixedRef = searchObjForEdge(refObj, refGeom);
if (fixedRef.getObject()) {
refToFix = fixedRef;
return true;
}
}
// no match in refObj, so now search the cached objects
for (auto& objectName : m_3dObjectCache) {
auto object3d = getDimension()->getDocument()->getObject(objectName.c_str());
auto shape3d = Part::Feature::getShape(object3d);
auto edgesAll = getDimension()->getEdges(shape3d);
size_t iEdge {1};
for (auto& edge : edgesAll) {
if (getMatcher()->compareGeometry(edge, refGeom)) {
// found a match!
refToFix.setObjectName(objectName);
refToFix.setObject(object3d);
refToFix.setSubName(std::string("Edge") + std::to_string(iEdge));
return true;
}
iEdge++;
}
}
return false;
}
//! search the view for a vertex that is within a tolerance of the saved reference geometry
//! and return a reference pointing to the matching vertex
bool DimensionAutoCorrect::findSimilarVertex2d(ReferenceEntry& refToFix,
Part::TopoShape refGeom) const
{
// Base::Console().Message("DAC::findSimilarVertex2d()\n");
(void)refToFix;
(void)refGeom;
Base::Console().Message("DAC::findSimilarVertex2d is not implemented yet\n");
return false;
}
//! search the view for a 2d edge that is similar to the saved reference geometry
//! and return a reference pointing to the similar edge.
bool DimensionAutoCorrect::findSimilarEdge2d(ReferenceEntry& refToFix,
Part::TopoShape refGeom) const
{
// Base::Console().Message("DAC::findSimilarEdge2d()\n");
(void)refToFix;
(void)refGeom;
Base::Console().Message("DAC::findSimilarEdge2d is not implemented yet\n");
return false;
}
//! search the referenced 3d object and the object cache for a vertex that is within
//! a tolerance of the saved reference geometry and return a reference pointing
//! to the matching vertex
bool DimensionAutoCorrect::findSimilarVertex3d(ReferenceEntry& refToFix,
Part::TopoShape refGeom) const
{
// Base::Console().Message("DAC::findSimilarVertex3d()\n");
(void)refToFix;
(void)refGeom;
Base::Console().Message("DAC::findSimilarVertex3d is not implemented yet\n");
return false;
}
//! search the referenced 3d object and the object cache for an edge that is
//! similar to the saved reference geometry and return a reference pointing
//! to the similar edge
bool DimensionAutoCorrect::findSimilarEdge3d(ReferenceEntry& refToFix,
Part::TopoShape refGeom) const
{
// Base::Console().Message("DAC::findSimilarEdge3d(%s)\n", refToFix.getObjectName().c_str());
(void)refToFix;
(void)refGeom;
Base::Console().Message("DAC::findSimilarEdge3d is not implemented yet\n");
return false;
}
//! compare the geometry pointed to by a reference to the corresponding saved geometry
bool DimensionAutoCorrect::isMatchingGeometry(ReferenceEntry ref,
Part::TopoShape savedGeometry) const
{
Part::TopoShape temp = ref.asTopoShape();
if (temp.isNull()) {
// this shouldn't happen as we already know that this ref points to valid geometry
return false;
}
if (getMatcher()->compareGeometry(temp, savedGeometry)) {
// reference still points to the same geometry
return true;
}
return false;
}
//! search obj (3d object with a shape) for a match to refVertex. This is always
//! an exact match for phase 1 (GeometryMatcher), but in phase 2 (GeometryGuesser)
//! a similar match will be allowed.
ReferenceEntry DimensionAutoCorrect::searchObjForVert(App::DocumentObject* obj,
Part::TopoShape refVertex,
bool exact) const
{
(void)exact;
auto shape3d = Part::Feature::getShape(obj);
if (shape3d.IsNull()) {
// how to handle this?
return {};
}
auto vertsAll = getDimension()->getVertexes(shape3d);
size_t iVert {1};
for (auto& vert : vertsAll) {
bool isSame = getMatcher()->compareGeometry(refVertex, vert);
if (isSame) {
auto newSubname = std::string("Vertex") + std::to_string(iVert);
return {obj, newSubname, getDimension()->getDocument()};
}
iVert++;
}
return {};
}
//! search View (2d part display) for a match to refVertex. This can be an
//! exact or Similar match depending on the setting of exact.
ReferenceEntry DimensionAutoCorrect::searchViewForVert(DrawViewPart* obj,
Part::TopoShape refVertex,
bool exact) const
{
(void)exact;
double scale = getDimension()->getViewPart()->getScale();
std::vector<TechDraw::VertexPtr> gVertexAll =
getDimension()->getViewPart()->getVertexGeometry();
getMatcher()->setPointTolerance(EWTOLERANCE);
int iVertex = 0;
for (auto& vert : gVertexAll) {
Part::TopoShape temp = vert->asTopoShape(scale);
bool isSame = getMatcher()->compareGeometry(refVertex, temp);
if (isSame) {
auto newSubname = std::string("Vertex") + std::to_string(iVertex);
return {obj, newSubname, getDimension()->getDocument()};
}
iVertex++;
}
return {};
}
//! search View (2d part display) for an exact match to refEdge.
ReferenceEntry DimensionAutoCorrect::searchViewForExactEdge(DrawViewPart* obj,
Part::TopoShape refEdge) const
{
// Base::Console().Message("DAC::searchViewForExactEdge()\n");
double scale = getDimension()->getViewPart()->getScale();
auto gEdgeAll = getDimension()->getViewPart()->getEdgeGeometry();
int iEdge {0};
for (auto& edge : gEdgeAll) {
Part::TopoShape temp = edge->asTopoShape(scale);
bool isSame = getMatcher()->compareGeometry(refEdge, temp);
if (isSame) {
auto newSubname = std::string("Edge") + std::to_string(iEdge);
return {obj, newSubname, getDimension()->getDocument()};
}
iEdge++;
}
return {};
}
//! search View (2d part display) for an edge that is similar to refEdge
ReferenceEntry DimensionAutoCorrect::searchViewForSimilarEdge(DrawViewPart* obj,
Part::TopoShape refEdge) const
{
// Base::Console().Message("DAC::searchViewForSimilarEdge()\n");
(void)obj;
(void)refEdge;
Base::Console().Message("DAC::searchViewForSimilarEdge is not implemented yet\n");
return {};
}
//! search model for for a 3d edge that is a match to refEdge
//! note that only the exact match is implemented in phase 1
ReferenceEntry DimensionAutoCorrect::searchObjForEdge(App::DocumentObject* obj,
Part::TopoShape refEdge,
bool exact) const
{
// Base::Console().Message("DAC::searchObjForEdge(%s)\n", obj->Label.getValue());
(void)exact;
auto shape3d = Part::Feature::getShape(obj);
if (shape3d.IsNull()) {
// how to handle this?
// Base::Console().Message("DAC::searchObjForEdge - object shape is null\n");
return {};
}
auto edgesAll = getDimension()->getEdges(shape3d);
size_t iEdge {1};
for (auto& edge : edgesAll) {
bool isSame = getMatcher()->compareGeometry(refEdge, edge);
if (isSame) {
auto newSubname = std::string("Edge") + std::to_string(iEdge);
return {obj, newSubname, getDimension()->getDocument()};
}
iEdge++;
}
return {};
}
//! rebuild 3d references from saved geometry. returns true is all references
//! have been repaired
bool DimensionAutoCorrect::fixBrokenReferences(ReferenceVector& fixedReferences) const
{
// Base::Console().Message("DAC::fixBrokenReferences()\n");
bool success {true};
const std::vector<Part::TopoShape> savedGeometry = getDimension()->SavedGeometry.getValues();
int iGeom {0};
for (auto& geom : savedGeometry) {
if (fixedReferences.at(iGeom).hasGeometry()) {
iGeom++;
continue;
}
//
TopoDS_Shape geomShape = geom.getShape();
for (auto& objectName : m_3dObjectCache) {
auto object3d = getDimension()->getDocument()->getObject(objectName.c_str());
if (!object3d) {
// cached object has been deleted
continue;
}
// TODO: do we need to check for Similar matches here too?
ReferenceEntry newRef;
if (geomShape.ShapeType() == TopAbs_VERTEX) {
newRef = searchObjForVert(object3d, geomShape);
fixedReferences.at(iGeom) = newRef;
}
else {
newRef = searchObjForEdge(object3d, geomShape);
fixedReferences.at(iGeom) = newRef;
}
fixedReferences.at(iGeom) = newRef;
if (!newRef.getObject()) {
success = false;
}
}
}
return success;
}
GeometryMatcher* DimensionAutoCorrect::getMatcher() const
{
return getDimension()->getMatcher();
}

View File

@@ -0,0 +1,101 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/***************************************************************************
* 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 validate and correct dimension references
#ifndef DIMAUTOCORRECT_H
#define DIMAUTOCORRECT_H
#include <Mod/TechDraw/TechDrawGlobal.h>
#include <DrawViewDimension.h>
namespace Part
{
class TopoShape;
}
namespace TechDraw
{
class GeometryMatcher;
class TechDrawExport DimensionAutoCorrect
{
public:
DimensionAutoCorrect()
{}
explicit DimensionAutoCorrect(DrawViewDimension* dim)
{
m_dimension = dim;
}
~DimensionAutoCorrect() = default;
bool referencesHaveValidGeometry(std::vector<bool>& referenceState) const;
bool autocorrectReferences(std::vector<bool>& referenceState,
ReferenceVector& repairedRefs) const;
void set3dObjectCache(std::set<std::string> cache)
{
m_3dObjectCache = cache;
}
bool fixBrokenReferences(ReferenceVector& fixedReferences) const;
private:
bool fix1GeomExact(ReferenceEntry& refToFix, TopoDS_Shape geomToFix) const;
bool fix1GeomSimilar(ReferenceEntry& refToFix, TopoDS_Shape geomToFix) const;
bool findExactVertex2d(ReferenceEntry& refToFix, Part::TopoShape refGeom) const;
bool findExactEdge2d(ReferenceEntry& refToFix, Part::TopoShape refGeom) const;
bool findExactVertex3d(ReferenceEntry& refToFix, Part::TopoShape refGeom) const;
bool findExactEdge3d(ReferenceEntry& refToFix, Part::TopoShape refGeom) const;
bool findSimilarVertex2d(ReferenceEntry& refToFix, Part::TopoShape refGeom) const;
bool findSimilarEdge2d(ReferenceEntry& refToFix, Part::TopoShape refGeom) const;
bool findSimilarVertex3d(ReferenceEntry& refToFix, Part::TopoShape refGeom) const;
bool findSimilarEdge3d(ReferenceEntry& refToFix, Part::TopoShape refGeom) const;
ReferenceEntry
searchObjForVert(App::DocumentObject* obj, Part::TopoShape refVertex, bool exact = true) const;
ReferenceEntry
searchViewForVert(DrawViewPart* obj, Part::TopoShape refVertex, bool exact = true) const;
ReferenceEntry
searchObjForEdge(App::DocumentObject* obj, Part::TopoShape refEdge, bool exact = true) const;
ReferenceEntry searchViewForExactEdge(DrawViewPart* obj, Part::TopoShape refEdge) const;
ReferenceEntry searchViewForSimilarEdge(DrawViewPart* obj, Part::TopoShape refEdge) const;
bool isMatchingGeometry(ReferenceEntry ref, Part::TopoShape savedGeometry) const;
DrawViewDimension* getDimension() const
{
return m_dimension;
}
GeometryMatcher* getMatcher() const;
DrawViewDimension* m_dimension;
std::set<std::string> m_3dObjectCache;
};
} // end namespace TechDraw
#endif

View File

@@ -31,6 +31,8 @@
#include <TopExp.hxx>
#include <App/GeoFeature.h>
#include <App/DocumentObject.h>
#include <App/Document.h>
#include <Base/Console.h>
#include <Mod/Part/App/TopoShape.h>
#include <Mod/PartDesign/App/Body.h>
@@ -44,16 +46,65 @@
using namespace TechDraw;
using DU = DrawUtil;
ReferenceEntry::ReferenceEntry( App::DocumentObject* docObject, std::string subName, App::Document* document)
{
setObject(docObject);
setSubName(subName);
setDocument(document);
if (docObject) {
setObjectName(docObject->getNameInDocument());
if (document == nullptr) {
setDocument(docObject->getDocument());
}
}
}
ReferenceEntry::ReferenceEntry(const ReferenceEntry& other)
{
setObject(other.getObject());
setSubName(other.getSubName());
setObjectName(other.getObjectName());
setDocument(other.getDocument());
}
ReferenceEntry& ReferenceEntry::operator=(const ReferenceEntry& otherRef)
{
setObject(otherRef.getObject());
setSubName(otherRef.getSubName());
setObjectName(otherRef.getObjectName());
setDocument(otherRef.getDocument());
return *this;
}
TopoDS_Shape ReferenceEntry::getGeometry() const
{
// Base::Console().Message("RE::getGeometry() - obj: %s sub: %s\n",
// getObject()->getNameInDocument(), getSubName());
// Base::Console().Message("RE::getGeometry() - objectName: %s sub: **%s**\n",
// getObjectName(), getSubName());
// first, make sure the object has not been deleted!
App::DocumentObject* obj = getDocument()->getObject(getObjectName().c_str());
if (!obj) {
Base::Console().Message("RE::getGeometry - %s no longer exists!\n", getObjectName().c_str());
return {};
}
if (getSubName().empty()) {
Base::Console().Message("RE::getGeometry - Reference has no subelement!\n");
return {};
}
if ( getObject()->isDerivedFrom(TechDraw::DrawViewPart::getClassTypeId()) ) {
// Base::Console().Message("RE::getGeometry - getting 2d geometry\n");
std::string gType;
try {
auto dvp = static_cast<TechDraw::DrawViewPart*>(getObject());
gType = geomType();
if (gType == "Vertex") {
// getVertex throws on not found, but we want to return null
// shape
auto vgeom = dvp->getVertex(getSubName());
return vgeom->getOCCVertex();
}
@@ -67,11 +118,12 @@ TopoDS_Shape ReferenceEntry::getGeometry() const
}
}
catch (...) {
// Base::Console().Message("RE::getGeometry - no shape for dimension reference - gType: %s\n", gType.c_str());
Base::Console().Message("RE::getGeometry - no shape for dimension 2d reference - gType: **%s**\n", gType.c_str());
return {};
}
}
// Base::Console().Message("RE::getGeometry - getting 2d geometry\n");
Part::TopoShape shape = Part::Feature::getTopoShape(getObject());
auto geoFeat = dynamic_cast<App::GeoFeature*>(getObject());
if (geoFeat) {
@@ -100,13 +152,15 @@ std::string ReferenceEntry::getSubName(bool longForm) const
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();
if (!getDocument()) {
return nullptr;
}
return m_object;
App::DocumentObject* obj = getDocument()->getObject(getObjectName().c_str());
if (!obj) {
return nullptr;
}
return obj;
}
Part::TopoShape ReferenceEntry::asTopoShape() const
@@ -114,7 +168,9 @@ Part::TopoShape ReferenceEntry::asTopoShape() const
// Base::Console().Message("RE::asTopoShape()\n");
TopoDS_Shape geom = getGeometry();
if (geom.IsNull()) {
throw Base::RuntimeError("Dimension Reference has null geometry");
// throw Base::RuntimeError("Dimension Reference has null geometry");
Base::Console().Message("RE::asTopoShape - reference geometry is null\n");
return {};
}
if (geom.ShapeType() == TopAbs_VERTEX) {
TopoDS_Vertex vert = TopoDS::Vertex(geom);
@@ -153,6 +209,7 @@ Part::TopoShape ReferenceEntry::asTopoShapeEdge(TopoDS_Edge &edge) const
std::string ReferenceEntry::geomType() const
{
// Base::Console().Message("RE::geomType() - subName: **%s**\n", getSubName().c_str());
return DrawUtil::getGeomTypeFromName(getSubName());
}
@@ -163,15 +220,61 @@ bool ReferenceEntry::isWholeObject() const
bool ReferenceEntry::is3d() const
{
return !getObject()->isDerivedFrom(TechDraw::DrawViewPart::getClassTypeId());
}
//! check if this reference has valid geometry
bool ReferenceEntry::isValid() const
{
TopoDS_Shape geom = getGeometry();
if (geom.IsNull()) {
if (getObject() &&
getObject()->isDerivedFrom(TechDraw::DrawViewPart::getClassTypeId()) &&
!getSubName().empty()) {
// this is a well formed 2d reference
return false;
}
if (getObject() &&
getObject()->isDerivedFrom(TechDraw::DrawViewPart::getClassTypeId()) &&
getSubName().empty()) {
// this is a broken 3d reference, so it should be treated as 3d
return true;
}
// either we have no object or we have an object and it is a 3d object
return true;
}
//! check if this reference has valid geometry in the model
bool ReferenceEntry::hasGeometry() const
{
// Base::Console().Message("RE::hasGeometry()\n");
if (!getObject()) {
return false;
}
if ( getObject()->isDerivedFrom(TechDraw::DrawViewPart::getClassTypeId()) ) {
// 2d reference
auto dvp = static_cast<TechDraw::DrawViewPart*>(getObject());
if (getSubName().empty()) {
return false;
}
int geomNumber = DU::getIndexFromName(getSubName());
std::string gType = geomType();
if (gType == "Vertex") {
auto vert = dvp->getProjVertexByIndex(geomNumber);
if (vert) {
return true;
}
} else if (gType == "Edge") {
auto edge = dvp->getGeomByIndex(geomNumber);
if (edge) {
return true;
}
}
// if we ever have dimensions for faces, add something here.
return false;
}
// 3d reference
auto shape = Part::Feature::getTopoShape(getObject());
auto subShape = shape.getSubShape(getSubName().c_str());
if (!subShape.IsNull()) {
return true;
}
return false;
}

View File

@@ -37,6 +37,7 @@
namespace App
{
class DocumentObject;
class Document;
}
namespace Part
@@ -51,34 +52,39 @@ namespace TechDraw
class TechDrawExport ReferenceEntry
{
public:
ReferenceEntry( App::DocumentObject* docObject, std::string subName ) {
setObject(docObject);
setSubName(subName);
}
ReferenceEntry(const ReferenceEntry& other) {
setObject(other.getObject());
setSubName(other.getSubName());
}
ReferenceEntry() {};
ReferenceEntry( App::DocumentObject* docObject, std::string subName, App::Document* document = nullptr);
ReferenceEntry(const ReferenceEntry& other);
~ReferenceEntry() = default;
ReferenceEntry& operator= (const ReferenceEntry& otherRef);
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; }
std::string getObjectName() const { return m_objectName; }
void setObjectName(std::string name) { m_objectName = name; }
App::Document* getDocument() const { return m_document; }
void setDocument(App::Document* document) { m_document = document; }
TopoDS_Shape getGeometry() const;
std::string geomType() const;
bool isWholeObject() const;
Part::TopoShape asTopoShape() const;
bool is3d() const;
bool hasGeometry() const;
private:
Part::TopoShape asTopoShapeVertex(TopoDS_Vertex &vert) const;
Part::TopoShape asTopoShapeEdge(TopoDS_Edge& edge) const;
bool is3d() const;
bool isValid() const;
private:
App::DocumentObject* m_object;
std::string m_subName;
App::DocumentObject* m_object{nullptr};
std::string m_subName{""};
std::string m_objectName{""};
App::Document* m_document{nullptr};
};
using ReferenceVector = std::vector<ReferenceEntry>;

File diff suppressed because it is too large Load Diff

View File

@@ -23,8 +23,6 @@
#ifndef TechDraw_DrawViewDimension_h_
#define TechDraw_DrawViewDimension_h_
#include <tuple>
#include <App/DocumentObject.h>
#include <Base/UnitsApi.h>
#include <Mod/Part/App/PropertyTopoShapeList.h>
@@ -39,7 +37,8 @@
class TopoDS_Shape;
namespace Measure {
namespace Measure
{
class Measurement;
}
namespace TechDraw
@@ -47,60 +46,63 @@ namespace TechDraw
class DrawViewPart;
class DimensionFormatter;
class GeometryMatcher;
class DimensionAutoCorrect;
class TechDrawExport DrawViewDimension : public TechDraw::DrawView
class TechDrawExport DrawViewDimension: public TechDraw::DrawView
{
PROPERTY_HEADER_WITH_OVERRIDE(TechDraw::DrawViewDimension);
public:
// keep this enum synchronized with TypeEnums
enum DimensionType {
Distance,
DistanceX,
DistanceY,
DistanceZ,
Radius,
Diameter,
Angle,
Angle3Pt
};
// keep this enum synchronized with TypeEnums
enum DimensionType
{
Distance,
DistanceX,
DistanceY,
DistanceZ,
Radius,
Diameter,
Angle,
Angle3Pt
};
/// Constructor
DrawViewDimension();
~DrawViewDimension() override;
App::PropertyEnumeration MeasureType; //True/Projected
App::PropertyLinkSubList References2D; //Points to Projection SubFeatures
App::PropertyLinkSubList References3D; //Points to 3D Geometry SubFeatures
App::PropertyEnumeration Type; //DistanceX, DistanceY, Diameter, etc.
App::PropertyEnumeration MeasureType; // True/Projected
App::PropertyLinkSubList References2D; // Points to Projection SubFeatures
App::PropertyLinkSubList References3D; // Points to 3D Geometry SubFeatures
App::PropertyEnumeration Type; // DistanceX, DistanceY, Diameter, etc.
App::PropertyBool TheoreticalExact;
App::PropertyBool Inverted;
App::PropertyString FormatSpec;
App::PropertyString FormatSpecOverTolerance;
App::PropertyString FormatSpecUnderTolerance;
App::PropertyBool Arbitrary;
App::PropertyBool ArbitraryTolerances;
App::PropertyBool EqualTolerance;
App::PropertyBool TheoreticalExact;
App::PropertyBool Inverted;
App::PropertyString FormatSpec;
App::PropertyString FormatSpecOverTolerance;
App::PropertyString FormatSpecUnderTolerance;
App::PropertyBool Arbitrary;
App::PropertyBool ArbitraryTolerances;
App::PropertyBool EqualTolerance;
App::PropertyQuantityConstraint OverTolerance;
App::PropertyQuantityConstraint UnderTolerance;
App::PropertyBool AngleOverride;
App::PropertyAngle LineAngle;
App::PropertyAngle ExtensionAngle;
App::PropertyBool AngleOverride;
App::PropertyAngle LineAngle;
App::PropertyAngle ExtensionAngle;
Part::PropertyTopoShapeList SavedGeometry;
Part::PropertyTopoShapeList SavedGeometry;
App::PropertyVectorList BoxCorners;
enum RefType{
invalidRef,
oneEdge,
twoEdge,
twoVertex,
vertexEdge,
threeVertex,
extent
};
enum RefType
{
invalidRef,
oneEdge,
twoEdge,
twoVertex,
vertexEdge,
threeVertex,
extent
};
short mustExecute() const override;
@@ -108,23 +110,20 @@ enum DimensionType {
virtual bool has3DReferences() const;
bool hasOverUnderTolerance() const;
/** @name methods override Feature */
//@{
/// recalculate the Feature
App::DocumentObjectExecReturn *execute() override;
//@}
App::DocumentObjectExecReturn* execute() override;
/// returns the type name of the ViewProvider
const char* getViewProviderName() const override {
const char* getViewProviderName() const override
{
return "TechDrawGui::ViewProviderDimension";
}
//return PyObject as DrawViewDimensionPy
PyObject *getPyObject() override;
// return PyObject as DrawViewDimensionPy
PyObject* getPyObject() override;
virtual std::string getFormattedToleranceValue(int partial);
virtual std::pair<std::string, std::string> getFormattedToleranceValues(int partial = 0);
virtual std::string getFormattedDimensionValue(int partial = 0);
virtual std::string formatValue(qreal value, QString qFormatSpec, int partial = 0, bool isDim = true);
virtual std::string
formatValue(qreal value, QString qFormatSpec, int partial = 0, bool isDim = true);
virtual bool haveTolerance();
@@ -132,24 +131,51 @@ enum DimensionType {
QStringList getPrefixSuffixSpec(QString fSpec);
virtual DrawViewPart* getViewPart() const;
QRectF getRect() const override { return {0, 0, 1, 1}; } //pretend dimensions always fit!
virtual int getRefType() const; //Vertex-Vertex, Edge, Edge-Edge
static int getRefTypeSubElements(const std::vector<std::string> &); //Vertex-Vertex, Edge, Edge-Edge
QRectF getRect() const override
{
return {0, 0, 1, 1};
} // pretend dimensions always fit!
virtual int getRefType() const; // Vertex-Vertex, Edge, Edge-Edge
static int
getRefTypeSubElements(const std::vector<std::string>&); // Vertex-Vertex, Edge, Edge-Edge
void setReferences2d(ReferenceVector refs);
void setReferences3d(ReferenceVector refs);
ReferenceVector getReferences2d() const;
ReferenceVector getReferences3d() const;
bool hasGoodReferences() const
{
return m_referencesCorrect;
}
void setAll3DMeasurement();
void clear3DMeasurements();
virtual bool checkReferences2D() const;
virtual pointPair getLinearPoints() const {return m_linearPoints; }
virtual void setLinearPoints(Base::Vector3d point0, Base::Vector3d point1) { m_linearPoints.first(point0);
m_linearPoints.second(point1); };
virtual void setLinearPoints(pointPair newPair) { m_linearPoints = newPair; }
arcPoints getArcPoints() {return m_arcPoints; }
anglePoints getAnglePoints() {return m_anglePoints; }
bool hasBroken3dReferences() const;
virtual pointPair getLinearPoints() const
{
return m_linearPoints;
}
virtual void setLinearPoints(Base::Vector3d point0, Base::Vector3d point1)
{
m_linearPoints.first(point0);
m_linearPoints.second(point1);
};
virtual void setLinearPoints(pointPair newPair)
{
m_linearPoints = newPair;
}
arcPoints getArcPoints()
{
return m_arcPoints;
}
anglePoints getAnglePoints()
{
return m_anglePoints;
}
bool leaderIntersectsArc(Base::Vector3d s, Base::Vector3d pointOnCircle);
bool isMultiValueSchema() const;
@@ -161,10 +187,27 @@ enum DimensionType {
bool useDecimals() const;
bool isExtentDim() const;
virtual ReferenceVector getEffectiveReferences() const;
bool goodReferenceGeometry() const { return m_referencesCorrect; }
GeometryMatcher* getMatcher() const
{
return m_matcher;
}
DimensionAutoCorrect* getCorrector() const
{
return m_corrector;
}
// these should probably be static as they don't use the dimension at all
std::vector<Part::TopoShape> getEdges(const Part::TopoShape& inShape);
std::vector<Part::TopoShape> getVertexes(const Part::TopoShape& inShape);
// autocorrect support methods
void saveFeatureBox();
Base::BoundBox3d getSavedBox();
Base::BoundBox3d getFeatureBox();
protected:
void handleChangedPropertyType(Base::XMLReader &, const char * , App::Property * ) override;
void handleChangedPropertyType(Base::XMLReader&, const char*, App::Property*) override;
void Restore(Base::XMLReader& reader) override;
void onChanged(const App::Property* prop) override;
void onDocumentRestored() override;
@@ -182,13 +225,10 @@ protected:
virtual anglePoints getAnglePointsTwoEdges(ReferenceVector references);
virtual anglePoints getAnglePointsThreeVerts(ReferenceVector references);
Measure::Measurement *measurement;
double dist2Segs(Base::Vector3d s1,
Base::Vector3d e1,
Base::Vector3d s2,
Base::Vector3d e2) const;
pointPair closestPoints(TopoDS_Shape s1,
TopoDS_Shape s2) const;
Measure::Measurement* measurement;
double
dist2Segs(Base::Vector3d s1, Base::Vector3d e1, Base::Vector3d s2, Base::Vector3d e2) const;
pointPair closestPoints(TopoDS_Shape s1, TopoDS_Shape s2) const;
void resetLinear();
void resetAngular();
@@ -196,36 +236,27 @@ protected:
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[];
void dumpRefs2D(const char* text) const;
//Dimension "geometry"
pointPair m_linearPoints;
pointPair m_arrowPositions;
arcPoints m_arcPoints;
// Dimension "geometry"
pointPair m_linearPoints;
pointPair m_arrowPositions;
arcPoints m_arcPoints;
anglePoints m_anglePoints;
bool m_hasGeometry;
bool m_hasGeometry;
friend class DimensionFormatter;
DimensionFormatter* m_formatter;
GeometryMatcher* m_matcher;
DimensionAutoCorrect* m_corrector;
bool m_referencesCorrect;
bool m_referencesCorrect {false};
std::set<std::string> m_3dObjectCache;
};
} //namespace TechDraw
} // namespace TechDraw
#endif

View File

@@ -862,7 +862,7 @@ TechDraw::VertexPtr DrawViewPart::getProjVertexByIndex(int idx) const
return nullptr;
}
if ((unsigned)idx >= geoms.size()) {
Base::Console().Error("DVP::getProjVertexByIndex(%d) - invalid index\n", idx);
Base::Console().Error("DVP::getProjVertexByIndex(%d) - invalid index - size: %d\n", idx);
return nullptr;
}
return geoms.at(idx);

View File

@@ -1716,3 +1716,21 @@ bool GeometryUtils::isLine(TopoDS_Edge occEdge)
}
return false;
}
//! make a line Edge from BSpline Edge
TopoDS_Edge GeometryUtils::asLine(TopoDS_Edge occEdge)
{
BRepAdaptor_Curve c(occEdge);
// find the two ends
Handle(Geom_Curve) curve = c.Curve().Curve();
double first = c.FirstParameter();
double last = c.LastParameter();
gp_Pnt start = c.Value(first);
gp_Pnt end = c.Value(last);
TopoDS_Edge result = BRepBuilderAPI_MakeEdge(start, end);
return result;
}

View File

@@ -446,6 +446,8 @@ class TechDrawExport GeometryUtils
static bool getCircleParms(TopoDS_Edge occEdge, double& radius, Base::Vector3d& center, bool& isArc);
static TopoDS_Edge asCircle(TopoDS_Edge occEdge, bool& arc);
static bool isLine(TopoDS_Edge occEdge);
static TopoDS_Edge asLine(TopoDS_Edge occEdge);
};
} //end namespace TechDraw

View File

@@ -45,23 +45,29 @@
#include "GeometryMatcher.h"
#include "DrawUtil.h"
#include "Preferences.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)
bool GeometryMatcher::compareGeometry(Part::TopoShape shape1, Part::TopoShape shape2)
{
// Base::Console().Message("GM::compareGeometry()\n");
// Base::Console().Message("GM::compareGeometry()\n");
if (!Preferences::useExactMatchOnDims()) {
return false;
}
if (shape1.isNull() || shape2.isNull()) {
// Base::Console().Message("GM::compareGeometry - one or more TopoShapes are null\n");
// Base::Console().Message("GM::compareGeometry - one or more TopoShapes are
// null\n");
return false;
}
TopoDS_Shape geom1 = shape1.getShape();
TopoDS_Shape geom2 = shape2.getShape();
if (geom1.IsNull() || geom2.IsNull()) {
// Base::Console().Message("GM::compareGeometry - one or more TopoDS_Shapes are null\n");
// Base::Console().Message("GM::compareGeometry - one or more TopoDS_Shapes are
// null\n");
return false;
}
@@ -74,11 +80,11 @@ bool GeometryMatcher::compareGeometry(Part::TopoShape shape1, Part::TopoShape s
return false;
}
bool GeometryMatcher::comparePoints(TopoDS_Shape &shape1, TopoDS_Shape &shape2)
bool GeometryMatcher::comparePoints(TopoDS_Shape& shape1, TopoDS_Shape& shape2)
{
// Base::Console().Message("GM::comparePoints()\n");
if (shape1.ShapeType() != TopAbs_VERTEX ||
shape2.ShapeType() != TopAbs_VERTEX) {
// Base::Console().Message("GM::comparePoints()\n");
if (shape1.ShapeType() != TopAbs_VERTEX || shape2.ShapeType() != TopAbs_VERTEX) {
// can not compare these shapes
return false;
}
@@ -92,50 +98,47 @@ bool GeometryMatcher::comparePoints(TopoDS_Shape &shape1, TopoDS_Shape &shape2)
return false;
}
bool GeometryMatcher::compareEdges(TopoDS_Shape &shape1, TopoDS_Shape &shape2)
bool GeometryMatcher::compareEdges(TopoDS_Shape& shape1, TopoDS_Shape& shape2)
{
// Base::Console().Message("GM::compareEdges()\n");
if (shape1.ShapeType() != TopAbs_EDGE ||
shape2.ShapeType() != TopAbs_EDGE) {
// 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");
// 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);
if (edge1.IsNull() || edge2.IsNull()) {
// Base::Console().Message("GM::compareEdges - an input edge is null\n");
if (edge1.IsNull() || edge2.IsNull()) {
// Base::Console().Message("GM::compareEdges - an input edge is null\n");
return false;
}
BRepAdaptor_Curve adapt1(edge1);
BRepAdaptor_Curve adapt2(edge2);
if (adapt1.GetType() == GeomAbs_Line &&
adapt2.GetType() == GeomAbs_Line) {
if (adapt1.GetType() == GeomAbs_Line && adapt2.GetType() == GeomAbs_Line) {
return compareLines(edge1, edge2);
}
if (adapt1.GetType() == GeomAbs_Circle &&
adapt2.GetType() == GeomAbs_Circle) {
if (adapt1.GetType() == GeomAbs_Circle && adapt2.GetType() == GeomAbs_Circle) {
if (adapt1.IsClosed() && adapt2.IsClosed()) {
return compareCircles(edge1, edge2);
} else {
}
else {
return compareCircleArcs(edge1, edge2);
}
}
if (adapt1.GetType() == GeomAbs_Ellipse &&
adapt2.GetType() == GeomAbs_Ellipse) {
if (adapt1.GetType() == GeomAbs_Ellipse && adapt2.GetType() == GeomAbs_Ellipse) {
if (adapt1.IsClosed() && adapt2.IsClosed()) {
return compareEllipses(edge1, edge2);
} else {
}
else {
return compareEllipseArcs(edge1, edge2);
}
}
if (adapt1.GetType() == GeomAbs_BSplineCurve &&
adapt2.GetType() == GeomAbs_BSplineCurve) {
if (adapt1.GetType() == GeomAbs_BSplineCurve && adapt2.GetType() == GeomAbs_BSplineCurve) {
return compareBSplines(edge1, edge2);
}
@@ -143,33 +146,32 @@ bool GeometryMatcher::compareEdges(TopoDS_Shape &shape1, TopoDS_Shape &shape2)
return compareDifferent(edge1, edge2);
}
bool GeometryMatcher::compareLines(TopoDS_Edge &edge1, TopoDS_Edge &edge2)
bool GeometryMatcher::compareLines(TopoDS_Edge& edge1, TopoDS_Edge& edge2)
{
// Base::Console().Message("GM::compareLines()\n");
// Base::Console().Message("GM::compareLines()\n");
// how does the edge that was NOT null in compareEdges become null here?
// should not happen, but does!
if (edge1.IsNull() || edge2.IsNull()) {
// Base::Console().Message("GM::compareLine - an input edge is null\n");
// Base::Console().Message("GM::compareLine - an input edge is null\n");
return false;
}
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
if (start1.IsEqual(start2, EWTOLERANCE) && end1.IsEqual(end2, EWTOLERANCE)) {
// exact match
return true;
}
return false;
}
bool GeometryMatcher::compareCircles(TopoDS_Edge &edge1, TopoDS_Edge &edge2)
bool GeometryMatcher::compareCircles(TopoDS_Edge& edge1, TopoDS_Edge& edge2)
{
// Base::Console().Message("GM::compareCircles()\n");
// Base::Console().Message("GM::compareCircles()\n");
// how does the edge that was NOT null in compareEdges become null here?
if (edge1.IsNull() || edge2.IsNull()) {
// Base::Console().Message("GM::compareCircles - an input edge is null\n");
// Base::Console().Message("GM::compareCircles - an input edge is null\n");
return false;
}
@@ -181,19 +183,18 @@ bool GeometryMatcher::compareCircles(TopoDS_Edge &edge1, TopoDS_Edge &edge2)
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
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)
bool GeometryMatcher::compareEllipses(TopoDS_Edge& edge1, TopoDS_Edge& edge2)
{
// how does the edge that was NOT null in compareEdges become null here?
if (edge1.IsNull() || edge2.IsNull()) {
// Base::Console().Message("GM::compareEllipses - an input edge is null\n");
// Base::Console().Message("GM::compareEllipses - an input edge is null\n");
return false;
}
@@ -207,19 +208,18 @@ bool GeometryMatcher::compareEllipses(TopoDS_Edge &edge1, TopoDS_Edge &edge2)
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)) {
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 lines or circles masquerading as bsplines are of interest
bool GeometryMatcher::compareBSplines(TopoDS_Edge &edge1, TopoDS_Edge &edge2)
bool GeometryMatcher::compareBSplines(TopoDS_Edge& edge1, TopoDS_Edge& edge2)
{
// Base::Console().Message("GM::compareBSplines()\n");
// Base::Console().Message("GM::compareBSplines()\n");
// how does the edge that was NOT null in compareEdges become null here?
if (edge1.IsNull() || edge2.IsNull()) {
Base::Console().Message("GM::compareBSplines - an input edge is null\n");
@@ -258,31 +258,31 @@ bool GeometryMatcher::compareBSplines(TopoDS_Edge &edge1, TopoDS_Edge &edge2)
}
// this is a weak comparison. we should also check center & radius?
bool GeometryMatcher::compareCircleArcs(TopoDS_Edge &edge1, TopoDS_Edge &edge2)
bool GeometryMatcher::compareCircleArcs(TopoDS_Edge& edge1, TopoDS_Edge& edge2)
{
return compareEndPoints(edge1, edge2);
}
bool GeometryMatcher::compareEllipseArcs(TopoDS_Edge &edge1, TopoDS_Edge &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)
bool GeometryMatcher::compareDifferent(TopoDS_Edge& edge1, TopoDS_Edge& edge2)
{
// Base::Console().Message("GM::compareDifferent()\n");
// Base::Console().Message("GM::compareDifferent()\n");
BRepAdaptor_Curve adapt1(edge1);
BRepAdaptor_Curve adapt2(edge2);
return false;
}
bool GeometryMatcher::compareEndPoints(TopoDS_Edge &edge1, TopoDS_Edge &edge2)
bool GeometryMatcher::compareEndPoints(TopoDS_Edge& edge1, TopoDS_Edge& edge2)
{
// how does the edge that was NOT null in compareEdges become null here?
if (edge1.IsNull() || edge2.IsNull()) {
// Base::Console().Message("GM::compareLine - an input edge is null\n");
// Base::Console().Message("GM::compareLine - an input edge is null\n");
return false;
}
@@ -301,9 +301,8 @@ bool GeometryMatcher::compareEndPoints(TopoDS_Edge &edge1, TopoDS_Edge &edge2)
props2.SetParameter(pLast2);
auto end2 = DU::toVector3d(props2.Value());
if (begin1.IsEqual(begin2, EWTOLERANCE) &&
end1.IsEqual(end2, EWTOLERANCE)) {
//exact match
if (begin1.IsEqual(begin2, EWTOLERANCE) && end1.IsEqual(end2, EWTOLERANCE)) {
// exact match
return true;
}
return false;

View File

@@ -33,17 +33,23 @@ namespace Part
class TopoShape;
}
namespace TechDraw {
namespace TechDraw
{
class TechDrawExport GeometryMatcher {
class TechDrawExport GeometryMatcher
{
public:
GeometryMatcher() {}
explicit GeometryMatcher(DrawViewDimension* dim) { m_dimension = dim; }
GeometryMatcher()
{}
explicit 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 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);
@@ -53,12 +59,21 @@ public:
bool compareCircleArcs(TopoDS_Edge& edge1, TopoDS_Edge& edge2);
bool compareEllipseArcs(TopoDS_Edge& edge1, TopoDS_Edge& edge2);
double getPointTolerance() const
{
return m_pointTolerance;
}
void setPointTolerance(double tol)
{
m_pointTolerance = tol;
}
private:
bool compareEndPoints(TopoDS_Edge& edge1, TopoDS_Edge& edge2);
DrawViewDimension* m_dimension;
double m_pointTolerance {EWTOLERANCE};
};
} //end namespace TechDraw
} // end namespace TechDraw
#endif

View File

@@ -527,3 +527,13 @@ int Preferences::sectionLineConvention()
{
return getPreferenceGroup("Standards")->GetInt("SectionLineStandard", 1);
}
//! true if the GeometryMatcher should be used in correcting Dimension references
bool Preferences::useExactMatchOnDims()
{
return getPreferenceGroup("Dimensions")->GetBool("UseMatcher", true);
}

View File

@@ -126,6 +126,8 @@ public:
static std::string currentElementDefFile();
static int sectionLineConvention();
static bool useExactMatchOnDims();
};

View File

@@ -24,7 +24,6 @@
#include <QApplication>
#include <QFileInfo>
#include <QMessageBox>
#include <sstream>
#include <vector>
#endif
@@ -75,7 +74,7 @@
#include "TaskProjection.h"
#include "TaskSectionView.h"
#include "ViewProviderPage.h"
#include "ViewProviderViewPart.h"
#include "ViewProviderDrawingView.h"
void execSimpleSection(Gui::Command* cmd);
void execComplexSection(Gui::Command* cmd);

View File

@@ -630,10 +630,9 @@ void QGIViewDimension::updateView(bool update)
updateDim();
}
if (dim->goodReferenceGeometry()) {
if (dim->hasGoodReferences()) {
m_refFlag->hide();
} else {
// m_refFlag->setPos(datumLabel->pos());
m_refFlag->centerAt(datumLabel->pos() + datumLabel->boundingRect().center());
m_refFlag->show();
}