diff --git a/src/Mod/Path/PathScripts/PathSimulatorGui.py b/src/Mod/Path/PathScripts/PathSimulatorGui.py index 428dcc394c..0045d5ed61 100644 --- a/src/Mod/Path/PathScripts/PathSimulatorGui.py +++ b/src/Mod/Path/PathScripts/PathSimulatorGui.py @@ -125,13 +125,21 @@ class PathSimulation: except Exception: self.tool = None - # if hasattr(self.operation, "ToolController"): - # self.tool = self.operation.ToolController.Tool if (self.tool is not None): - toolProf = self.CreateToolProfile(self.tool, Vector(0, 1, 0), Vector(0, 0, 0), float(self.tool.Diameter) / 2.0) - self.cutTool.Shape = Part.makeSolid(toolProf.revolve(Vector(0, 0, 0), Vector(0, 0, 1))) + if isinstance(self.tool, Path.Tool): + # handle legacy tools + toolProf = self.CreateToolProfile(self.tool, Vector(0, 1, 0), Vector(0, 0, 0), float(self.tool.Diameter) / 2.0) + self.cutTool.Shape = Part.makeSolid(toolProf.revolve(Vector(0, 0, 0), Vector(0, 0, 1))) + else: + # handle tool bits + self.cutTool.Shape = self.tool.Shape + + if not self.cutTool.Shape.isValid() or self.cutTool.Shape.isNull(): + self.EndSimulation() + raise RuntimeError("Path Simulation: Error in tool geometry - {}".format(self.tool.Name)) + self.cutTool.ViewObject.show() - self.voxSim.SetCurrentTool(self.tool) + self.voxSim.SetToolShape(self.cutTool.Shape, 0.05 * self.accuracy) self.icmd = 0 self.curpos = FreeCAD.Placement(self.initialPos, self.stdrot) # self.cutTool.Placement = FreeCAD.Placement(self.curpos, self.stdrot) diff --git a/src/Mod/Path/PathSimulator/App/PathSim.cpp b/src/Mod/Path/PathSimulator/App/PathSim.cpp index 64afa13f67..621efe5b99 100644 --- a/src/Mod/Path/PathSimulator/App/PathSim.cpp +++ b/src/Mod/Path/PathSimulator/App/PathSim.cpp @@ -33,7 +33,6 @@ #include #include "PathSim.h" -//#include "VolSim.h" using namespace Base; using namespace PathSimulator; @@ -54,69 +53,15 @@ PathSim::~PathSim() delete m_tool; } - void PathSim::BeginSimulation(Part::TopoShape * stock, float resolution) { Base::BoundBox3d bbox = stock->getBoundBox(); m_stock = new cStock(bbox.MinX, bbox.MinY, bbox.MinZ, bbox.LengthX(), bbox.LengthY(), bbox.LengthZ(), resolution); } -void PathSim::SetCurrentTool(Tool * tool) +void PathSim::SetToolShape(const TopoDS_Shape& toolShape, float resolution) { - cSimTool::Type tp = cSimTool::FLAT; - float angle = 180; - switch (tool->Type) - { - case Tool::BALLENDMILL: - tp = cSimTool::ROUND; - break; - - case Tool::CHAMFERMILL: - tp = cSimTool::CHAMFER; - angle = tool->CuttingEdgeAngle; - break; - - case Tool::UNDEFINED: - case Tool::DRILL: - tp = cSimTool::CHAMFER; - angle = tool->CuttingEdgeAngle; - if (angle > 180) - { - angle = 180; - } - break; - case Tool::CENTERDRILL: - tp = cSimTool::CHAMFER; - angle = tool->CuttingEdgeAngle; - if (angle > 180) - { - angle = 180; - } - break; - case Tool::COUNTERSINK: - case Tool::COUNTERBORE: - case Tool::REAMER: - case Tool::TAP: - case Tool::ENDMILL: - tp = cSimTool::FLAT; - angle = 180; - break; - case Tool::SLOTCUTTER: - case Tool::CORNERROUND: - case Tool::ENGRAVER: - tp = cSimTool::CHAMFER; - angle = tool->CuttingEdgeAngle; - if (angle > 180) - { - angle = 180; - } - break; - default: - tp = cSimTool::FLAT; - angle = 180; - break; - } - m_tool = new cSimTool(tp, tool->Diameter / 2.0, angle); + m_tool = new cSimTool(toolShape, resolution); } Base::Placement * PathSim::ApplyCommand(Base::Placement * pos, Command * cmd) diff --git a/src/Mod/Path/PathSimulator/App/PathSim.h b/src/Mod/Path/PathSimulator/App/PathSim.h index 5ad93dbb99..90be142766 100644 --- a/src/Mod/Path/PathSimulator/App/PathSim.h +++ b/src/Mod/Path/PathSimulator/App/PathSim.h @@ -31,7 +31,6 @@ #include #include #include -#include #include #include "VolSim.h" @@ -51,7 +50,7 @@ namespace PathSimulator ~PathSim(); void BeginSimulation(Part::TopoShape * stock, float resolution); - void SetCurrentTool(Tool * tool); + void SetToolShape(const TopoDS_Shape& toolShape, float resolution); Base::Placement * ApplyCommand(Base::Placement * pos, Command * cmd); public: diff --git a/src/Mod/Path/PathSimulator/App/PathSimPy.xml b/src/Mod/Path/PathSimulator/App/PathSimPy.xml index 1449f5b20e..7225318f21 100644 --- a/src/Mod/Path/PathSimulator/App/PathSimPy.xml +++ b/src/Mod/Path/PathSimulator/App/PathSimPy.xml @@ -23,12 +23,10 @@ Create a path simulator object\n Start a simulation process on a box shape stock with given resolution\n - + - - SetCurrentTool(tool):\n - Set the current Path Tool for the subsequent simulator operations.\n - + SetToolShape(shape):\n +Set the shape of the tool to be used for simulation\n diff --git a/src/Mod/Path/PathSimulator/App/PathSimPyImp.cpp b/src/Mod/Path/PathSimulator/App/PathSimPyImp.cpp index eaec6d454a..708cc4b9a1 100644 --- a/src/Mod/Path/PathSimulator/App/PathSimPyImp.cpp +++ b/src/Mod/Path/PathSimulator/App/PathSimPyImp.cpp @@ -69,13 +69,15 @@ PyObject* PathSimPy::BeginSimulation(PyObject * args, PyObject * kwds) return Py_None; } -PyObject* PathSimPy::SetCurrentTool(PyObject * args) +PyObject* PathSimPy::SetToolShape(PyObject * args) { - PyObject *pObjTool; - if (!PyArg_ParseTuple(args, "O!", &(Path::ToolPy::Type), &pObjTool)) + PyObject *pObjToolShape; + float resolution; + if (!PyArg_ParseTuple(args, "O!f", &(Part::TopoShapePy::Type), &pObjToolShape, &resolution)) return 0; PathSim *sim = getPathSimPtr(); - sim->SetCurrentTool(static_cast(pObjTool)->getToolPtr()); + const TopoDS_Shape& toolShape = static_cast(pObjToolShape)->getTopoShapePtr()->getShape(); + sim->SetToolShape(toolShape, resolution); Py_IncRef(Py_None); return Py_None; } diff --git a/src/Mod/Path/PathSimulator/App/VolSim.cpp b/src/Mod/Path/PathSimulator/App/VolSim.cpp index 2ba4450586..bc46e76b47 100644 --- a/src/Mod/Path/PathSimulator/App/VolSim.cpp +++ b/src/Mod/Path/PathSimulator/App/VolSim.cpp @@ -21,6 +21,11 @@ ***************************************************************************/ #include "PreCompiled.h" +#include + +#include +#include +#include #ifndef _PreComp_ # include @@ -712,41 +717,98 @@ void Point3D::UpdateCmd(Path::Command & cmd) //************************************************************************************************************ // Simulation tool //************************************************************************************************************ -float cSimTool::GetToolProfileAt(float pos) // pos is -1..1 location along the radius of the tool (0 is center) -{ - switch (type) - { - case FLAT: - return 0; +cSimTool::cSimTool(const TopoDS_Shape& toolShape, float res){ - case CHAMFER: - { - if (pos < 0) return -chamRatio * pos; - return chamRatio * pos; + BRepCheck_Analyzer aChecker(toolShape); + bool shapeIsValid = aChecker.IsValid() ? true : false; + + if(!shapeIsValid){ + throw Base::RuntimeError("Path Simulation: Error in tool geometry"); } - case ROUND: - pos *= radius; - return radius - sqrt(dradius - pos * pos); - break; + Bnd_Box boundBox; + BRepBndLib::Add(toolShape, boundBox); + + boundBox.SetGap(0.0); + Standard_Real xMin, yMin, zMin, xMax, yMax, zMax; + boundBox.Get(xMin, yMin, zMin, xMax, yMax, zMax); + radius = (xMax - xMin) / 2; + length = zMax - zMin; + + Base::Vector3d pnt; + pnt.x = 0; + pnt.y = 0; + pnt.z = 0; + + int radValue = (int)(radius / res) + 1; + + // Measure the performance of the profile extraction + //auto start = std::chrono::high_resolution_clock::now(); + + for (int x = 0; x < radValue; x++) + { + // find the face of the tool by checking z points accross the + // radius to see if the point is inside the shape + pnt.x = x * res; + bool inside = isInside(toolShape, pnt, res); + + // move down until the point is outside the shape + while(inside && std::abs(pnt.z) < length ){ + pnt.z -= res; + inside = isInside(toolShape, pnt, res); + } + + // move up until the point is first inside the shape and record the position + while (!inside && pnt.z < length) + { + pnt.z += res; + inside = isInside(toolShape, pnt, res); + + if (inside){ + toolShapePoint shapePoint; + shapePoint.radiusPos = pnt.x; + shapePoint.heightPos = pnt.z; + m_toolShape.push_back(shapePoint); + break; + } + } } - return 0; + + // Report the performance of the profile extraction + //auto stop = std::chrono::high_resolution_clock::now(); + //auto duration = std::chrono::duration_cast(stop - start); + //Base::Console().Log("cSimTool::cSimTool - Tool Profile Extraction Took: %i ms\n", duration.count() / 1000); + } -void cSimTool::InitTool() // pos is 0..1 location along the radius of the tool +float cSimTool::GetToolProfileAt(float pos) // pos is -1..1 location along the radius of the tool (0 is center) { - switch (type) - { - case CHAMFER: - chamRatio = radius * tan((90.0 - tipAngle / 2) * 3.1415926535 / 180); - break; + try{ + float radPos = std::abs(pos) * radius; + toolShapePoint test; test.radiusPos = radPos; + auto it = std::lower_bound(m_toolShape.begin(), m_toolShape.end(), test, toolShapePoint::less_than()); + return it->heightPos; + }catch(...){ + return 0; + } +} - case ROUND: - dradius = radius * radius; - break; +bool cSimTool::isInside(const TopoDS_Shape& toolShape, Base::Vector3d pnt, float res) +{ + bool checkFace = true; + TopAbs_State stateIn = TopAbs_IN; - case FLAT: - break; + try { + BRepClass3d_SolidClassifier solidClassifier(toolShape); + gp_Pnt vertex = gp_Pnt(pnt.x, pnt.y, pnt.z); + solidClassifier.Perform(vertex, res); + bool inside = (solidClassifier.State() == stateIn); + if (checkFace && solidClassifier.IsOnAFace()){ + inside = true; + } + return inside; + }catch (...) { + return false; } } diff --git a/src/Mod/Path/PathSimulator/App/VolSim.h b/src/Mod/Path/PathSimulator/App/VolSim.h index 39fb371adf..0487db7eb2 100644 --- a/src/Mod/Path/PathSimulator/App/VolSim.h +++ b/src/Mod/Path/PathSimulator/App/VolSim.h @@ -34,6 +34,18 @@ #define SIM_TESSEL_TOP 1 #define SIM_TESSEL_BOT 2 #define SIM_WALK_RES 0.6 // step size in pixel units (to make sure all pixels in the path are visited) + +struct toolShapePoint { + float radiusPos; + float heightPos; + + struct less_than{ + bool operator()(const toolShapePoint &a, const toolShapePoint &b){ + return a.radiusPos < b.radiusPos; + } + }; +}; + struct Point3D { Point3D() : x(0), y(0), z(0), sina(0), cosa(0) {} @@ -88,22 +100,15 @@ struct cLineSegment class cSimTool { public: - enum Type { - FLAT = 0, - CHAMFER, - ROUND - }; - cSimTool() : type(FLAT), radius(0), tipAngle(0), dradius(0), chamRatio(0) {} - cSimTool(Type t, float rad, float tipang = 180) : type(t), radius(rad), tipAngle(tipang) { InitTool(); } + cSimTool(const TopoDS_Shape& toolShape, float res); ~cSimTool() {} - void InitTool(); - Type type; - float radius; - float tipAngle; - float dradius; - float chamRatio; float GetToolProfileAt(float pos); + bool isInside(const TopoDS_Shape& toolShape, Base::Vector3d pnt, float res); + + std::vector< toolShapePoint > m_toolShape; + float radius; + float length; }; template @@ -131,7 +136,6 @@ private: int height; }; - class cStock { public: