diff --git a/src/Base/Vector3D.cpp b/src/Base/Vector3D.cpp index 0d0729013f..a5d34a7259 100644 --- a/src/Base/Vector3D.cpp +++ b/src/Base/Vector3D.cpp @@ -192,6 +192,26 @@ Vector3<_Precision> Vector3<_Precision>::Cross(const Vector3<_Precision>& rcVct) return cVctRes; } +template +bool Vector3<_Precision>::IsOnLine (const Vector3<_Precision>& startVct, const Vector3<_Precision>& endVct) const +{ + Vector3<_Precision> vectorAB = endVct - startVct; + Vector3<_Precision> vectorAC = *this - startVct; + Vector3<_Precision> crossproduct = vectorAB.Cross(vectorAC); + _Precision dotproduct = vectorAB.Dot(vectorAC); + + if (crossproduct.Length() > traits_type::epsilon()) + return false; + + if (dotproduct < 0) + return false; + + if (dotproduct > vectorAB.Length() * vectorAB.Length()) + return false; + + return true; +} + template bool Vector3<_Precision>::operator != (const Vector3<_Precision>& rcVct) const { diff --git a/src/Base/Vector3D.h b/src/Base/Vector3D.h index 4b0f4a414d..b0f7e2ebbb 100644 --- a/src/Base/Vector3D.h +++ b/src/Base/Vector3D.h @@ -133,6 +133,9 @@ public: bool operator == (const Vector3<_Precision>& rcVct) const; //@} + /// Check if Vector is on a line + bool IsOnLine (const Vector3<_Precision>& startVct, const Vector3<_Precision>& endVct) const; + /** @name Modification */ //@{ void ScaleX (_Precision f); diff --git a/src/Base/VectorPy.xml b/src/Base/VectorPy.xml index 517eff03fd..2f5a8486f0 100644 --- a/src/Base/VectorPy.xml +++ b/src/Base/VectorPy.xml @@ -74,6 +74,13 @@ + + + isOnLine(Vector, Vector) + checks if Vector is on a line + + + getAngle(Vector) diff --git a/src/Base/VectorPyImp.cpp b/src/Base/VectorPyImp.cpp index 712315dcb1..96328aab97 100644 --- a/src/Base/VectorPyImp.cpp +++ b/src/Base/VectorPyImp.cpp @@ -435,6 +435,32 @@ PyObject* VectorPy::cross(PyObject *args) return new VectorPy(v); } +PyObject* VectorPy::isOnLine(PyObject *args) +{ + PyObject *start, *end; + if (!PyArg_ParseTuple(args, "OO",&start, &end)) + return 0; + if (!PyObject_TypeCheck(start, &(VectorPy::Type))) { + PyErr_SetString(PyExc_TypeError, "First arg must be Vector"); + return 0; + } + if (!PyObject_TypeCheck(end, &(VectorPy::Type))) { + PyErr_SetString(PyExc_TypeError, "Second arg must be Vector"); + return 0; + } + + VectorPy* start_vec = static_cast(start); + VectorPy* end_vec = static_cast(end); + + VectorPy::PointerType this_ptr = reinterpret_cast(_pcTwinPointer); + VectorPy::PointerType start_ptr = reinterpret_cast(start_vec->_pcTwinPointer); + VectorPy::PointerType end_ptr = reinterpret_cast(end_vec->_pcTwinPointer); + + Py::Boolean result = this_ptr->IsOnLine(*start_ptr, *end_ptr); + + return Py::new_reference_to(result); +} + PyObject* VectorPy::getAngle(PyObject *args) { PyObject *obj; diff --git a/src/Mod/Path/PathScripts/PathSurface.py b/src/Mod/Path/PathScripts/PathSurface.py index df07fe881e..792928a4ba 100644 --- a/src/Mod/Path/PathScripts/PathSurface.py +++ b/src/Mod/Path/PathScripts/PathSurface.py @@ -365,6 +365,9 @@ class ObjectSurface(PathOp.ObjectOp): def opExecute(self, obj): '''opExecute(obj) ... process surface operation''' PathLog.track() + import cProfile + pr = cProfile.Profile() + pr.enable() self.modelSTLs = list() self.safeSTLs = list() @@ -530,7 +533,7 @@ class ObjectSurface(PathOp.ObjectOp): PathLog.info('Working on Model.Group[{}]: {}'.format(m, Mdl.Label)) # make stock-model-voidShapes STL model for avoidance detection on transitions self._makeSafeSTL(JOB, obj, m, FACES[m], VOIDS[m]) - time.sleep(0.2) + #time.sleep(0.2) # Process model/faces - OCL objects must be ready CMDS.extend(self._processCutAreas(JOB, obj, m, FACES[m], VOIDS[m])) @@ -603,6 +606,8 @@ class ObjectSurface(PathOp.ObjectOp): del self.deflection execTime = time.time() - startTime + pr.disable() + pr.dump_stats("/mnt/files/profile.cprof") PathLog.info('Operation time: {} sec.'.format(execTime)) return True @@ -1008,7 +1013,7 @@ class ObjectSurface(PathOp.ObjectOp): except Exception as eee: PathLog.error(str(eee)) cont = False - time.sleep(0.2) + #time.sleep(0.2) if cont: csFaceShape = self._getShapeSlice(baseEnv) @@ -1486,7 +1491,7 @@ class ObjectSurface(PathOp.ObjectOp): fuseShapes.append(adjStckWst) else: PathLog.warning('Path transitions might not avoid the model. Verify paths.') - time.sleep(0.3) + #time.sleep(0.3) else: # If boundbox is Job.Stock, add hidden pad under stock as base plate @@ -1523,7 +1528,7 @@ class ObjectSurface(PathOp.ObjectOp): LinearDeflection=obj.LinearDeflection.Value, AngularDeflection=obj.AngularDeflection.Value, Relative=False) - time.sleep(0.2) + #time.sleep(0.2) stl = ocl.STLSurf() for f in meshFuse.Facets: p = f.Points[0] @@ -2003,7 +2008,7 @@ class ObjectSurface(PathOp.ObjectOp): for v in range(1, lenOS): nxt = OS[v + 1] if optimize is True: - iPOL = self.isPointOnLine(prev, nxt, pnt) + iPOL = prev.isOnLine(nxt, pnt) if iPOL is True: pnt = nxt else: @@ -2057,7 +2062,7 @@ class ObjectSurface(PathOp.ObjectOp): ep = FreeCAD.Vector(v2[0], v2[1], 0.0) # end point cp = FreeCAD.Vector(v1[0], v1[1], 0.0) # check point (first / middle point) - iC = self.isPointOnLine(sp, ep, cp) + iC = sp.isOnLine(ep, cp) if iC is True: inLine.append('BRK') chkGap = True @@ -2163,7 +2168,7 @@ class ObjectSurface(PathOp.ObjectOp): cp = FreeCAD.Vector(v1[0], v1[1], 0.0) # check point (start point of segment) ep = FreeCAD.Vector(v2[0], v2[1], 0.0) # end point - iC = self.isPointOnLine(sp, ep, cp) + iC = sp.isOnLine(ep, cp) if iC is True: inLine.append('BRK') chkGap = True @@ -2452,7 +2457,7 @@ class ObjectSurface(PathOp.ObjectOp): return ARCS def _planarDropCutScan(self, pdc, A, B): - PNTS = list() + #PNTS = list() (x1, y1) = A (x2, y2) = B path = ocl.Path() # create an empty path object @@ -2463,8 +2468,9 @@ class ObjectSurface(PathOp.ObjectOp): pdc.setPath(path) pdc.run() # run dropcutter algorithm on path CLP = pdc.getCLPoints() - for p in CLP: - PNTS.append(FreeCAD.Vector(p.x, p.y, p.z)) + PNTS = [FreeCAD.Vector(p.x, p.y, p.z) for p in CLP] + #for p in CLP: + # PNTS.append(FreeCAD.Vector(p.x, p.y, p.z)) return PNTS # pdc.getCLPoints() def _planarCircularDropCutScan(self, pdc, Arc, cMode): @@ -2601,7 +2607,7 @@ class ObjectSurface(PathOp.ObjectOp): # Process point if optimize is True: - iPOL = self.isPointOnLine(prev, nxt, pnt) + iPOL = prev.isOnLine(nxt, pnt) if iPOL is True: onLine = True else: @@ -2893,7 +2899,7 @@ class ObjectSurface(PathOp.ObjectOp): # Process point if prcs is True: if optimize is True: - iPOL = self.isPointOnLine(prev, nxt, pnt) + iPOL = prev.isOnLine(nxt, pnt) if iPOL is True: onLine = True else: @@ -3308,7 +3314,7 @@ class ObjectSurface(PathOp.ObjectOp): prevDepth = layDep lCnt += 1 # increment layer count PathLog.debug("--Layer " + str(lCnt) + ": " + str(len(advances)) + " OCL scans and gcode in " + str(time.time() - t_before) + " s") - time.sleep(0.2) + #time.sleep(0.2) # Eol return commands @@ -3467,7 +3473,7 @@ class ObjectSurface(PathOp.ObjectOp): self.holdPoint = ocl.Point(float("inf"), float("inf"), float("inf")) if self.onHold is False: - if not optimize or not self.isPointOnLine(FreeCAD.Vector(prev.x, prev.y, prev.z), FreeCAD.Vector(nxt.x, nxt.y, nxt.z), FreeCAD.Vector(pnt.x, pnt.y, pnt.z)): + if not optimize or not FreeCAD.Vector(prev.x, prev.y, prev.z).isOnLine(FreeCAD.Vector(nxt.x, nxt.y, nxt.z), FreeCAD.Vector(pnt.x, pnt.y, pnt.z)): output.append(Path.Command('G1', {'X': pnt.x, 'Y': pnt.y, 'Z': pnt.z, 'F': self.horizFeed})) # elif i == lastCLP: # output.append(Path.Command('G1', {'X': pnt.x, 'Y': pnt.y, 'Z': pnt.z, 'F': self.horizFeed})) @@ -3588,7 +3594,7 @@ class ObjectSurface(PathOp.ObjectOp): else: optimize = False - if not optimize or not self.isPointOnLine(FreeCAD.Vector(prev.x, prev.y, prev.z), FreeCAD.Vector(nxt.x, nxt.y, nxt.z), FreeCAD.Vector(pnt.x, pnt.y, pnt.z)): + if not optimize or not FreeCAD.Vector(prev.x, prev.y, prev.z).isOnLine(FreeCAD.Vector(nxt.x, nxt.y, nxt.z), FreeCAD.Vector(pnt.x, pnt.y, pnt.z)): output.append(Path.Command('G1', {'X': pnt.x, 'Y': pnt.y, 'F': self.horizFeed})) # Rotate point data @@ -3606,26 +3612,6 @@ class ObjectSurface(PathOp.ObjectOp): return output - # Support functions for both dropcutter and waterline operations - def isPointOnLine(self, strtPnt, endPnt, pointP): - '''isPointOnLine(strtPnt, endPnt, pointP) ... Determine if a given point is on the line defined by start and end points.''' - tolerance = 1e-6 - vectorAB = endPnt - strtPnt - vectorAC = pointP - strtPnt - crossproduct = vectorAB.cross(vectorAC) - dotproduct = vectorAB.dot(vectorAC) - - if crossproduct.Length > tolerance: - return False - - if dotproduct < 0: - return False - - if dotproduct > vectorAB.Length * vectorAB.Length: - return False - - return True - def holdStopCmds(self, obj, zMax, pd, p2, txt): '''holdStopCmds(obj, zMax, pd, p2, txt) ... Gcode commands to be executed at beginning of hold.''' cmds = [] @@ -3754,10 +3740,11 @@ class ObjectSurface(PathOp.ObjectOp): A = (p1.x, p1.y) B = (p2.x, p2.y) LINE = self._planarDropCutScan(pdc, A, B) - zMax = LINE[0].z - for p in LINE: - if p.z > zMax: - zMax = p.z + zMax = max([obj.z for obj in LINE]) + #zMax = LINE[0].z + #for p in LINE: + # if p.z > zMax: + # zMax = p.z if minDep is not None: if zMax < minDep: zMax = minDep