Merge branch 'master' into bugfix/path-invalid-base-geometry-robustness

This commit is contained in:
mlampert
2021-02-14 11:19:07 -08:00
committed by GitHub
14 changed files with 323 additions and 133 deletions

View File

@@ -73,7 +73,7 @@ class OrthoArray(gui_base.GuiCommandBase):
We add callbacks that connect the 3D view with
the widgets of the task panel.
"""
_log("GuiCommand: {}".format(_self.command_name))
_log("GuiCommand: {}".format(self.command_name))
#_msg("{}".format(16*"-"))
#_msg("GuiCommand: {}".format(self.command_name))

View File

@@ -297,7 +297,7 @@ class TaskPanelCircularArray:
"App.ActiveDocument.recompute()"]
# We commit the command list through the parent command
self.source_command.commit(translate("draft","Circular array", _cmd_list))
self.source_command.commit(translate("draft","Circular array"), _cmd_list)
def get_distances(self):
"""Get the distance parameters from the widgets."""

View File

@@ -1497,6 +1497,30 @@ void MeshObject::validateIndices()
this->_segments.clear();
}
bool MeshObject::hasInvalidNeighbourhood() const
{
MeshCore::MeshEvalNeighbourhood eval(_kernel);
return !eval.Evaluate();
}
bool MeshObject::hasPointsOutOfRange() const
{
MeshCore::MeshEvalRangePoint eval(_kernel);
return !eval.Evaluate();
}
bool MeshObject::hasFacetsOutOfRange() const
{
MeshCore::MeshEvalRangeFacet eval(_kernel);
return !eval.Evaluate();
}
bool MeshObject::hasCorruptedFacets() const
{
MeshCore::MeshEvalCorruptedFacets eval(_kernel);
return !eval.Evaluate();
}
void MeshObject::validateDeformations(float fMaxAngle, float fEps)
{
unsigned long count = _kernel.CountFacets();

View File

@@ -283,6 +283,10 @@ public:
void removeDuplicatedPoints();
void removeDuplicatedFacets();
bool hasNonManifolds() const;
bool hasInvalidNeighbourhood() const;
bool hasPointsOutOfRange() const;
bool hasFacetsOutOfRange() const;
bool hasCorruptedFacets() const;
void removeNonManifolds();
void removeNonManifoldPoints();
bool hasSelfIntersections() const;

View File

@@ -229,7 +229,7 @@ for c in mesh.getSeparatecomponents():
<UserDocu>Check if the mesh has non-manifolds</UserDocu>
</Documentation>
</Methode>
<Methode Name="removeNonManifolds">
<Methode Name="removeNonManifolds">
<Documentation>
<UserDocu>Remove non-manifolds</UserDocu>
</Documentation>
@@ -284,7 +284,27 @@ for c in mesh.getSeparatecomponents():
<UserDocu>Remove points with invalid coordinates (NaN)</UserDocu>
</Documentation>
</Methode>
<Methode Name="countComponents" Const="true">
<Methode Name="hasInvalidNeighbourhood" Const="true">
<Documentation>
<UserDocu>Check if the mesh has invalid neighbourhood indices</UserDocu>
</Documentation>
</Methode>
<Methode Name="hasPointsOutOfRange" Const="true">
<Documentation>
<UserDocu>Check if the mesh has point indices that are out of range</UserDocu>
</Documentation>
</Methode>
<Methode Name="hasFacetsOutOfRange" Const="true">
<Documentation>
<UserDocu>Check if the mesh has facet indices that are out of range</UserDocu>
</Documentation>
</Methode>
<Methode Name="hasCorruptedFacets" Const="true">
<Documentation>
<UserDocu>Check if the mesh has corrupted facets</UserDocu>
</Documentation>
</Methode>
<Methode Name="countComponents" Const="true">
<Documentation>
<UserDocu>Get the number of topologic independent areas</UserDocu>
</Documentation>

View File

@@ -972,6 +972,38 @@ PyObject* MeshPy::hasNonManifolds(PyObject *args)
return Py_BuildValue("O", (ok ? Py_True : Py_False));
}
PyObject* MeshPy::hasInvalidNeighbourhood(PyObject *args)
{
if (!PyArg_ParseTuple(args, ""))
return NULL;
bool ok = getMeshObjectPtr()->hasInvalidNeighbourhood();
return Py_BuildValue("O", (ok ? Py_True : Py_False));
}
PyObject* MeshPy::hasPointsOutOfRange(PyObject *args)
{
if (!PyArg_ParseTuple(args, ""))
return NULL;
bool ok = getMeshObjectPtr()->hasPointsOutOfRange();
return Py_BuildValue("O", (ok ? Py_True : Py_False));
}
PyObject* MeshPy::hasFacetsOutOfRange(PyObject *args)
{
if (!PyArg_ParseTuple(args, ""))
return NULL;
bool ok = getMeshObjectPtr()->hasFacetsOutOfRange();
return Py_BuildValue("O", (ok ? Py_True : Py_False));
}
PyObject* MeshPy::hasCorruptedFacets(PyObject *args)
{
if (!PyArg_ParseTuple(args, ""))
return NULL;
bool ok = getMeshObjectPtr()->hasFacetsOutOfRange();
return Py_BuildValue("O", (ok ? Py_True : Py_False));
}
PyObject* MeshPy::removeNonManifolds(PyObject *args)
{
if (!PyArg_ParseTuple(args, ""))

View File

@@ -19,120 +19,224 @@ except Exception:
class MeshTopoTestCases(unittest.TestCase):
def setUp(self):
# set up a planar face with 18 triangles
self.planarMesh = []
for x in range(3):
for y in range(3):
self.planarMesh.append( [0.0 + x, 0.0 + y,0.0000] )
self.planarMesh.append( [1.0 + x, 1.0 + y,0.0000] )
self.planarMesh.append( [0.0 + x, 1.0 + y,0.0000] )
self.planarMesh.append( [0.0 + x, 0.0 + y,0.0000] )
self.planarMesh.append( [1.0 + x, 0.0 + y,0.0000] )
self.planarMesh.append( [1.0 + x, 1.0 + y,0.0000] )
def setUp(self):
# set up a planar face with 18 triangles
self.planarMesh = []
for x in range(3):
for y in range(3):
self.planarMesh.append( [0.0 + x, 0.0 + y,0.0000] )
self.planarMesh.append( [1.0 + x, 1.0 + y,0.0000] )
self.planarMesh.append( [0.0 + x, 1.0 + y,0.0000] )
self.planarMesh.append( [0.0 + x, 0.0 + y,0.0000] )
self.planarMesh.append( [1.0 + x, 0.0 + y,0.0000] )
self.planarMesh.append( [1.0 + x, 1.0 + y,0.0000] )
def testCollapseFacetsSingle(self):
for i in range(18):
planarMeshObject = Mesh.Mesh(self.planarMesh)
planarMeshObject.collapseFacets([i])
def testCollapseFacetsSingle(self):
for i in range(18):
planarMeshObject = Mesh.Mesh(self.planarMesh)
planarMeshObject.collapseFacets([i])
def testCollapseFacetsMultible(self):
planarMeshObject = Mesh.Mesh(self.planarMesh)
planarMeshObject.collapseFacets(range(7))
def testCollapseFacetsMultible(self):
planarMeshObject = Mesh.Mesh(self.planarMesh)
planarMeshObject.collapseFacets(range(7))
def testCollapseFacetsAll(self):
planarMeshObject = Mesh.Mesh(self.planarMesh)
planarMeshObject.collapseFacets(range(18))
def testCollapseFacetsAll(self):
planarMeshObject = Mesh.Mesh(self.planarMesh)
planarMeshObject.collapseFacets(range(18))
class MeshSplitTestCases(unittest.TestCase):
def setUp(self):
self.mesh = Mesh.createBox(1.0, 1.0, 1.0)
def testSplitFacetOnOneEdge(self):
p1 = self.mesh.Points[0].Vector
p2 = self.mesh.Points[1].Vector
p3 = self.mesh.Points[2].Vector
self.mesh.splitFacet(0, p1, (p2 + p3) / 2)
self.assertFalse(self.mesh.hasNonManifolds())
self.assertFalse(self.mesh.hasInvalidNeighbourhood())
self.assertFalse(self.mesh.hasPointsOutOfRange())
self.assertFalse(self.mesh.hasFacetsOutOfRange())
self.assertFalse(self.mesh.hasCorruptedFacets())
self.assertTrue(self.mesh.isSolid())
def testSplitFacetOnTwoEdges_21(self):
p1 = self.mesh.Points[0].Vector
p2 = self.mesh.Points[1].Vector
p3 = self.mesh.Points[2].Vector
self.mesh.splitFacet(0, (p1 + p3) / 2, (p2 + p3) / 2)
self.assertFalse(self.mesh.hasNonManifolds())
self.assertFalse(self.mesh.hasInvalidNeighbourhood())
self.assertFalse(self.mesh.hasPointsOutOfRange())
self.assertFalse(self.mesh.hasFacetsOutOfRange())
self.assertFalse(self.mesh.hasCorruptedFacets())
self.assertTrue(self.mesh.isSolid())
def testSplitFacetOnTwoEdges_12(self):
p1 = self.mesh.Points[0].Vector
p2 = self.mesh.Points[1].Vector
p3 = self.mesh.Points[2].Vector
self.mesh.splitFacet(0, (p2 + p3) / 2, (p1 + p3) / 2)
self.assertFalse(self.mesh.hasNonManifolds())
self.assertFalse(self.mesh.hasInvalidNeighbourhood())
self.assertFalse(self.mesh.hasPointsOutOfRange())
self.assertFalse(self.mesh.hasFacetsOutOfRange())
self.assertFalse(self.mesh.hasCorruptedFacets())
self.assertTrue(self.mesh.isSolid())
def testSplitFacetOnTwoEdges_01(self):
p1 = self.mesh.Points[0].Vector
p2 = self.mesh.Points[1].Vector
p3 = self.mesh.Points[2].Vector
self.mesh.splitFacet(0, (p1 + p2) / 2, (p2 + p3) / 2)
self.assertFalse(self.mesh.hasNonManifolds())
self.assertFalse(self.mesh.hasInvalidNeighbourhood())
self.assertFalse(self.mesh.hasPointsOutOfRange())
self.assertFalse(self.mesh.hasFacetsOutOfRange())
self.assertFalse(self.mesh.hasCorruptedFacets())
self.assertTrue(self.mesh.isSolid())
def testSplitFacetOnTwoEdges_10(self):
p1 = self.mesh.Points[0].Vector
p2 = self.mesh.Points[1].Vector
p3 = self.mesh.Points[2].Vector
self.mesh.splitFacet(0, (p2 + p3) / 2, (p1 + p2) / 2)
self.assertFalse(self.mesh.hasNonManifolds())
self.assertFalse(self.mesh.hasInvalidNeighbourhood())
self.assertFalse(self.mesh.hasPointsOutOfRange())
self.assertFalse(self.mesh.hasFacetsOutOfRange())
self.assertFalse(self.mesh.hasCorruptedFacets())
self.assertTrue(self.mesh.isSolid())
def testSplitFacetOnTwoEdges_02(self):
p1 = self.mesh.Points[0].Vector
p2 = self.mesh.Points[1].Vector
p3 = self.mesh.Points[2].Vector
self.mesh.splitFacet(0, (p1 + p2) / 2, (p1 + p3) / 2)
self.assertFalse(self.mesh.hasNonManifolds())
self.assertFalse(self.mesh.hasInvalidNeighbourhood())
self.assertFalse(self.mesh.hasPointsOutOfRange())
self.assertFalse(self.mesh.hasFacetsOutOfRange())
self.assertFalse(self.mesh.hasCorruptedFacets())
self.assertTrue(self.mesh.isSolid())
def testSplitFacetOnTwoEdges_20(self):
p1 = self.mesh.Points[0].Vector
p2 = self.mesh.Points[1].Vector
p3 = self.mesh.Points[2].Vector
self.mesh.splitFacet(0, (p1 + p3) / 2, (p1 + p2) / 2)
self.assertFalse(self.mesh.hasNonManifolds())
self.assertFalse(self.mesh.hasInvalidNeighbourhood())
self.assertFalse(self.mesh.hasPointsOutOfRange())
self.assertFalse(self.mesh.hasFacetsOutOfRange())
self.assertFalse(self.mesh.hasCorruptedFacets())
self.assertTrue(self.mesh.isSolid())
def testSplitFacetOnTwoEdges_5teps(self):
Vec3d = FreeCAD.Vector
for i in range(5):
f = self.mesh.Facets[0]
p1 = Vec3d(f.Points[0])
p2 = Vec3d(f.Points[1])
p3 = Vec3d(f.Points[2])
self.mesh.splitFacet(0, (p1 + p3) / 2, (p2 + p3) / 2)
self.assertFalse(self.mesh.hasNonManifolds())
self.assertFalse(self.mesh.hasInvalidNeighbourhood())
self.assertFalse(self.mesh.hasPointsOutOfRange())
self.assertFalse(self.mesh.hasFacetsOutOfRange())
self.assertFalse(self.mesh.hasCorruptedFacets())
self.assertTrue(self.mesh.isSolid())
class MeshGeoTestCases(unittest.TestCase):
def setUp(self):
# set up a planar face with 2 triangles
self.planarMesh = []
def setUp(self):
# set up a planar face with 2 triangles
self.planarMesh = []
def testIntersection(self):
self.planarMesh.append( [0.9961,1.5413,4.3943] )
self.planarMesh.append( [9.4796,10.024,-3.0937] )
self.planarMesh.append( [1.4308,11.3841,2.6829] )
self.planarMesh.append( [2.6493,2.2536,3.0679] )
self.planarMesh.append( [13.1126,0.4857,-4.4417] )
self.planarMesh.append( [10.2410,8.9040,-3.5002] )
planarMeshObject = Mesh.Mesh(self.planarMesh)
f1 = planarMeshObject.Facets[0]
f2 = planarMeshObject.Facets[1]
res=f1.intersect(f2)
self.failUnless(len(res) == 0)
def testIntersection(self):
self.planarMesh.append( [0.9961,1.5413,4.3943] )
self.planarMesh.append( [9.4796,10.024,-3.0937] )
self.planarMesh.append( [1.4308,11.3841,2.6829] )
self.planarMesh.append( [2.6493,2.2536,3.0679] )
self.planarMesh.append( [13.1126,0.4857,-4.4417] )
self.planarMesh.append( [10.2410,8.9040,-3.5002] )
planarMeshObject = Mesh.Mesh(self.planarMesh)
f1 = planarMeshObject.Facets[0]
f2 = planarMeshObject.Facets[1]
res=f1.intersect(f2)
self.failUnless(len(res) == 0)
def testIntersection2(self):
self.planarMesh.append( [-16.097176,-29.891157,15.987688] )
self.planarMesh.append( [-16.176304,-29.859991,15.947966] )
self.planarMesh.append( [-16.071451,-29.900553,15.912505] )
self.planarMesh.append( [-16.092241,-29.893408,16.020439] )
self.planarMesh.append( [-16.007210,-29.926180,15.967641] )
self.planarMesh.append( [-16.064457,-29.904951,16.090832] )
planarMeshObject = Mesh.Mesh(self.planarMesh)
f1 = planarMeshObject.Facets[0]
f2 = planarMeshObject.Facets[1]
# does definitely NOT intersect
res=f1.intersect(f2)
self.failUnless(len(res) == 0)
def testIntersection2(self):
self.planarMesh.append( [-16.097176,-29.891157,15.987688] )
self.planarMesh.append( [-16.176304,-29.859991,15.947966] )
self.planarMesh.append( [-16.071451,-29.900553,15.912505] )
self.planarMesh.append( [-16.092241,-29.893408,16.020439] )
self.planarMesh.append( [-16.007210,-29.926180,15.967641] )
self.planarMesh.append( [-16.064457,-29.904951,16.090832] )
planarMeshObject = Mesh.Mesh(self.planarMesh)
f1 = planarMeshObject.Facets[0]
f2 = planarMeshObject.Facets[1]
# does definitely NOT intersect
res=f1.intersect(f2)
self.failUnless(len(res) == 0)
class PivyTestCases(unittest.TestCase):
def setUp(self):
# set up a planar face with 2 triangles
self.planarMesh = []
FreeCAD.newDocument("MeshTest")
def setUp(self):
# set up a planar face with 2 triangles
self.planarMesh = []
FreeCAD.newDocument("MeshTest")
def testRayPick(self):
if not FreeCAD.GuiUp:
return
self.planarMesh.append( [-16.097176,-29.891157,15.987688] )
self.planarMesh.append( [-16.176304,-29.859991,15.947966] )
self.planarMesh.append( [-16.071451,-29.900553,15.912505] )
self.planarMesh.append( [-16.092241,-29.893408,16.020439] )
self.planarMesh.append( [-16.007210,-29.926180,15.967641] )
self.planarMesh.append( [-16.064457,-29.904951,16.090832] )
planarMeshObject = Mesh.Mesh(self.planarMesh)
def testRayPick(self):
if not FreeCAD.GuiUp:
return
self.planarMesh.append( [-16.097176,-29.891157,15.987688] )
self.planarMesh.append( [-16.176304,-29.859991,15.947966] )
self.planarMesh.append( [-16.071451,-29.900553,15.912505] )
self.planarMesh.append( [-16.092241,-29.893408,16.020439] )
self.planarMesh.append( [-16.007210,-29.926180,15.967641] )
self.planarMesh.append( [-16.064457,-29.904951,16.090832] )
planarMeshObject = Mesh.Mesh(self.planarMesh)
from pivy import coin; import FreeCADGui
Mesh.show(planarMeshObject)
view=FreeCADGui.ActiveDocument.ActiveView.getViewer()
rp=coin.SoRayPickAction(view.getSoRenderManager().getViewportRegion())
rp.setRay(coin.SbVec3f(-16.05,16.0,16.0),coin.SbVec3f(0,-1,0))
rp.apply(view.getSoRenderManager().getSceneGraph())
pp=rp.getPickedPoint()
self.failUnless(pp != None)
det=pp.getDetail()
self.failUnless(det.getTypeId() == coin.SoFaceDetail.getClassTypeId())
det=coin.cast(det,str(det.getTypeId().getName()))
self.failUnless(det.getFaceIndex() == 1)
from pivy import coin; import FreeCADGui
Mesh.show(planarMeshObject)
view=FreeCADGui.ActiveDocument.ActiveView.getViewer()
rp=coin.SoRayPickAction(view.getSoRenderManager().getViewportRegion())
rp.setRay(coin.SbVec3f(-16.05,16.0,16.0),coin.SbVec3f(0,-1,0))
rp.apply(view.getSoRenderManager().getSceneGraph())
pp=rp.getPickedPoint()
self.failUnless(pp != None)
det=pp.getDetail()
self.failUnless(det.getTypeId() == coin.SoFaceDetail.getClassTypeId())
det=coin.cast(det,str(det.getTypeId().getName()))
self.failUnless(det.getFaceIndex() == 1)
def testPrimitiveCount(self):
if not FreeCAD.GuiUp:
return
self.planarMesh.append( [-16.097176,-29.891157,15.987688] )
self.planarMesh.append( [-16.176304,-29.859991,15.947966] )
self.planarMesh.append( [-16.071451,-29.900553,15.912505] )
self.planarMesh.append( [-16.092241,-29.893408,16.020439] )
self.planarMesh.append( [-16.007210,-29.926180,15.967641] )
self.planarMesh.append( [-16.064457,-29.904951,16.090832] )
planarMeshObject = Mesh.Mesh(self.planarMesh)
def testPrimitiveCount(self):
if not FreeCAD.GuiUp:
return
self.planarMesh.append( [-16.097176,-29.891157,15.987688] )
self.planarMesh.append( [-16.176304,-29.859991,15.947966] )
self.planarMesh.append( [-16.071451,-29.900553,15.912505] )
self.planarMesh.append( [-16.092241,-29.893408,16.020439] )
self.planarMesh.append( [-16.007210,-29.926180,15.967641] )
self.planarMesh.append( [-16.064457,-29.904951,16.090832] )
planarMeshObject = Mesh.Mesh(self.planarMesh)
from pivy import coin; import FreeCADGui
Mesh.show(planarMeshObject)
view=FreeCADGui.ActiveDocument.ActiveView
view.setAxisCross(False)
pc=coin.SoGetPrimitiveCountAction()
pc.apply(view.getSceneGraph())
self.failUnless(pc.getTriangleCount() == 2)
#self.failUnless(pc.getPointCount() == 6)
from pivy import coin; import FreeCADGui
Mesh.show(planarMeshObject)
view=FreeCADGui.ActiveDocument.ActiveView
view.setAxisCross(False)
pc=coin.SoGetPrimitiveCountAction()
pc.apply(view.getSceneGraph())
self.failUnless(pc.getTriangleCount() == 2)
#self.failUnless(pc.getPointCount() == 6)
def tearDown(self):
#closing doc
FreeCAD.closeDocument("MeshTest")
def tearDown(self):
#closing doc
FreeCAD.closeDocument("MeshTest")
# Threads

View File

@@ -74,7 +74,7 @@
namespace Part {
const App::PropertyQuantityConstraint::Constraints apexRange = {0.0,90.0,0.1};
const App::PropertyQuantityConstraint::Constraints apexRange = {-90.0,90.0,0.1};
const App::PropertyQuantityConstraint::Constraints torusRangeV = {-180.0,180.0,1.0};
const App::PropertyQuantityConstraint::Constraints angleRangeU = {0.0,360.0,1.0};
const App::PropertyQuantityConstraint::Constraints angleRangeV = {-90.0,90.0,1.0};
@@ -801,7 +801,7 @@ Helix::Helix(void)
Height.setConstraints(&quantityRange);
ADD_PROPERTY_TYPE(Radius,(1.0),"Helix",App::Prop_None,"The radius of the helix");
Radius.setConstraints(&quantityRange);
ADD_PROPERTY_TYPE(Angle,(0.0),"Helix",App::Prop_None,"If angle is > 0 a conical otherwise a cylindircal surface is used");
ADD_PROPERTY_TYPE(Angle,(0.0),"Helix",App::Prop_None,"If angle is != 0 a conical otherwise a cylindircal surface is used");
Angle.setConstraints(&apexRange);
ADD_PROPERTY_TYPE(LocalCoord,(long(0)),"Coordinate System",App::Prop_None,"Orientation of the local coordinate system of the helix");
LocalCoord.setEnums(LocalCSEnums);

View File

@@ -261,7 +261,7 @@ DlgPrimitives::DlgPrimitives(QWidget* parent, Part::Primitive* feature)
ui->helixPitch->setRange(0, INT_MAX);
ui->helixHeight->setRange(0, INT_MAX);
ui->helixRadius->setRange(0, INT_MAX);
ui->helixAngle->setRange(0, 90);
ui->helixAngle->setRange(-90, 90);
// circle
ui->circleRadius->setRange(0, INT_MAX);
ui->circleAngle0->setRange(0, 360);
@@ -560,7 +560,7 @@ DlgPrimitives::DlgPrimitives(QWidget* parent, Part::Primitive* feature)
}
}
/*
/*
* Destroys the object and frees any allocated resources
*/
DlgPrimitives::~DlgPrimitives()
@@ -1937,7 +1937,7 @@ TaskPrimitives::~TaskPrimitives()
}
QDialogButtonBox::StandardButtons TaskPrimitives::getStandardButtons() const
{
{
return QDialogButtonBox::Close|
QDialogButtonBox::Ok;
}

View File

@@ -515,7 +515,7 @@ class ObjectSlot(PathOp.ObjectOp):
(p1, p2) = pnts
begExt = obj.ExtendPathStart.Value
endExt = obj.ExtendPathEnd.Value
# invert endExt, begExt args to apply extentions to correct ends
# invert endExt, begExt args to apply extensions to correct ends
# XY geom is postitive CCW; Gcode postitive CW
pnts = self._extendArcSlot(p1, p2, self.arcCenter, endExt, begExt)
@@ -925,7 +925,7 @@ class ObjectSlot(PathOp.ObjectOp):
# Check that all Z values are equal (isRoughly same)
if (abs(z1 - z2) > tolrnc or
abs(z1 - z3) > tolrnc ):
# abs(z2 - z3) > tolrnc): 3rd test reduntant.
# abs(z2 - z3) > tolrnc): 3rd test redundant.
return False
return True
@@ -1230,8 +1230,8 @@ class ObjectSlot(PathOp.ObjectOp):
# Convert extension to radians; make a generic chord ( line ) on XY plane from the x axis
# rotate and shift into place so it has same vertices as the required arc extention
# adjust rotation angle to provide +ve or -ve extention as needed
# rotate and shift into place so it has same vertices as the required arc extension
# adjust rotation angle to provide +ve or -ve extension as needed
origin = FreeCAD.Vector(0.0, 0.0, 0.0)
if begExt:
ExtRadians = abs(begExt / self.newRadius)

View File

@@ -31,6 +31,7 @@
# include <BRepAdaptor_Curve.hxx>
# include <Precision.hxx>
# include <QDebug>
# include <QGraphicsScene>
# include <QGraphicsSceneMouseEvent>
# include <QPainter>
@@ -48,7 +49,6 @@
#include <Base/Exception.h>
#include <Base/Parameter.h>
#include <Gui/Command.h>
#include <Gui/Control.h>
#include <Gui/Tools.h>
#include <string>
@@ -74,7 +74,6 @@
#include "QGIViewDimension.h"
#include "QGVPage.h"
#include "MDIViewPage.h"
#include "TaskBalloon.h"
//TODO: hide the Qt coord system (+y down).
@@ -140,8 +139,11 @@ void QGIBalloonLabel::mouseMoveEvent(QGraphicsSceneMouseEvent * event)
void QGIBalloonLabel::mouseReleaseEvent(QGraphicsSceneMouseEvent * event)
{
if(scene() && this == scene()->mouseGrabberItem()) {
Q_EMIT dragFinished();
if (QLineF(event->screenPos(), event->buttonDownScreenPos(Qt::LeftButton))
.length() > 0) {
if (scene() && this == scene()->mouseGrabberItem()) {
Q_EMIT dragFinished();
}
}
m_ctrl = false;
m_drag = false;
@@ -152,13 +154,17 @@ void QGIBalloonLabel::mouseDoubleClickEvent(QGraphicsSceneMouseEvent * event)
{
QGIViewBalloon* qgivBalloon = dynamic_cast<QGIViewBalloon*>(parentItem());
if (qgivBalloon == nullptr) {
qWarning() << "QGIBalloonLabel::mouseDoubleClickEvent: No parent item";
return;
}
auto ViewProvider = static_cast<ViewProviderBalloon*>(qgivBalloon->getViewProvider(qgivBalloon->getViewObject()));
auto ViewProvider = dynamic_cast<ViewProviderBalloon*>(qgivBalloon->getViewProvider(qgivBalloon->getViewObject()));
if (ViewProvider == nullptr) {
qWarning() << "QGIBalloonLabel::mouseDoubleClickEvent: No valid view provider";
return;
}
Gui::Control().showDialog(new TaskDlgBalloon(qgivBalloon, ViewProvider));
ViewProvider->startDefaultEditMode();
QGraphicsItem::mouseDoubleClickEvent(event);
}
@@ -482,7 +488,7 @@ void QGIViewBalloon::balloonLabelDragged(bool ctrl)
m_saveOffset = dvb->getOriginOffset();
}
}
double scale = 1.0;
DrawView* balloonParent = getSourceView();
if (balloonParent != nullptr) {
@@ -499,7 +505,7 @@ void QGIViewBalloon::balloonLabelDragged(bool ctrl)
if (ctrl) {
Base::Vector3d pos(x, -y, 0.0);
Base::Vector3d newOrg = pos - m_saveOffset;
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.OriginX = %f",
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.OriginX = %f",
dvb->getNameInDocument(), newOrg.x);
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.OriginY = %f",
dvb->getNameInDocument(), newOrg.y);

View File

@@ -36,6 +36,8 @@
# include <BRepAdaptor_Curve.hxx>
# include <Precision.hxx>
# include <QApplication>
# include <QDebug>
# include <QGraphicsScene>
# include <QGraphicsSceneMouseEvent>
# include <QPainter>
@@ -52,7 +54,6 @@
#include <Base/Parameter.h>
#include <Base/UnitsApi.h>
#include <Gui/Command.h>
#include <Gui/Control.h>
#include <Mod/Part/App/PartFeature.h>
@@ -76,7 +77,6 @@
#include "QGIViewDimension.h"
#include "ViewProviderDimension.h"
#include "DrawGuiUtil.h"
#include "TaskDimension.h"
#define NORMAL 0
#define PRE 1
@@ -149,10 +149,7 @@ void QGIDatumLabel::mousePressEvent(QGraphicsSceneMouseEvent * event)
m_ctrl = true;
}
if(scene() && this == scene()->mouseGrabberItem()) {
Q_EMIT dragFinished();
}
QGraphicsItem::mousePressEvent(event);
QGraphicsItem::mousePressEvent(event);
}
void QGIDatumLabel::mouseMoveEvent(QGraphicsSceneMouseEvent * event)
@@ -164,8 +161,11 @@ void QGIDatumLabel::mouseReleaseEvent(QGraphicsSceneMouseEvent * event)
{
// Base::Console().Message("QGIDL::mouseReleaseEvent()\n");
m_ctrl = false;
if(scene() && this == scene()->mouseGrabberItem()) {
Q_EMIT dragFinished();
if (QLineF(event->screenPos(), event->buttonDownScreenPos(Qt::LeftButton))
.length() > 0) {
if (scene() && this == scene()->mouseGrabberItem()) {
Q_EMIT dragFinished();
}
}
QGraphicsItem::mouseReleaseEvent(event);
@@ -175,13 +175,17 @@ void QGIDatumLabel::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event)
{
QGIViewDimension* qgivDimension = dynamic_cast<QGIViewDimension*>(parentItem());
if (qgivDimension == nullptr) {
qWarning() << "QGIDatumLabel::mouseDoubleClickEvent: No parent item";
return;
}
auto ViewProvider = static_cast<ViewProviderDimension*>(qgivDimension->getViewProvider(qgivDimension->getViewObject()));
auto ViewProvider = dynamic_cast<ViewProviderDimension*>(qgivDimension->getViewProvider(qgivDimension->getViewObject()));
if (ViewProvider == nullptr) {
qWarning() << "QGIDatumLabel::mouseDoubleClickEvent: No valid view provider";
return;
}
Gui::Control().showDialog(new TaskDlgDimension(qgivDimension, ViewProvider));
ViewProvider->startDefaultEditMode();
QGraphicsItem::mouseDoubleClickEvent(event);
}

View File

@@ -63,14 +63,12 @@ public:
virtual void unsetEdit(int ModNum);
virtual bool doubleClicked(void);
virtual bool canDelete(App::DocumentObject* obj) const;
void startDefaultEditMode();
virtual TechDraw::DrawViewBalloon* getViewObject() const;
protected:
virtual void handleChangedPropertyType(Base::XMLReader &reader, const char *TypeName, App::Property * prop);
private:
void startDefaultEditMode();
};
} // namespace TechDrawGui

View File

@@ -76,6 +76,7 @@ public:
virtual bool setEdit(int ModNum);
virtual void unsetEdit(int ModNum);
virtual bool doubleClicked(void);
void startDefaultEditMode();
virtual TechDraw::DrawViewDimension* getViewObject() const;
@@ -89,9 +90,6 @@ public:
protected:
virtual void handleChangedPropertyType(Base::XMLReader &reader, const char *TypeName, App::Property * prop);
private:
void startDefaultEditMode();
private:
static const char *StandardAndStyleEnums[];
static const char *RenderingExtentEnums[];