diff --git a/src/Mod/Draft/Resources/Draft.qrc b/src/Mod/Draft/Resources/Draft.qrc
index f914187b7f..e403999a49 100644
--- a/src/Mod/Draft/Resources/Draft.qrc
+++ b/src/Mod/Draft/Resources/Draft.qrc
@@ -105,6 +105,7 @@
icons/Snap_Perpendicular.svg
icons/Snap_Special.svg
icons/Snap_WorkingPlane.svg
+ icons/Draft_NewLayer.svg
patterns/aluminium.svg
patterns/brick01.svg
patterns/concrete.svg
diff --git a/src/Mod/Draft/Resources/icons/Draft_NewLayer.svg b/src/Mod/Draft/Resources/icons/Draft_NewLayer.svg
new file mode 100644
index 0000000000..eb0fa91ea4
--- /dev/null
+++ b/src/Mod/Draft/Resources/icons/Draft_NewLayer.svg
@@ -0,0 +1,720 @@
+
+
diff --git a/src/Mod/Draft/draftfunctions/svg.py b/src/Mod/Draft/draftfunctions/svg.py
index e8f68fd604..02c13031d5 100644
--- a/src/Mod/Draft/draftfunctions/svg.py
+++ b/src/Mod/Draft/draftfunctions/svg.py
@@ -478,7 +478,12 @@ def get_svg(obj,
else:
stroke = utils.get_rgb(color)
elif App.GuiUp:
- if hasattr(obj, "ViewObject"):
+ # find print color
+ pc = get_print_color(obj)
+ if pc:
+ stroke = utils.get_rgb(pc)
+ # get line color
+ elif hasattr(obj, "ViewObject"):
if hasattr(obj.ViewObject, "LineColor"):
stroke = utils.get_rgb(obj.ViewObject.LineColor)
elif hasattr(obj.ViewObject, "TextColor"):
@@ -918,6 +923,17 @@ def get_svg(obj,
return svg
+def get_print_color(obj):
+ """returns the print color of the parent layer, if available"""
+ for parent in obj.InListRecursive:
+ if (hasattr(parent,"ViewObject")
+ and hasattr(parent.ViewObject,"UsePrintColor")
+ and parent.ViewObject.UsePrintColor):
+ if hasattr(parent.ViewObject,"LinePrintColor"):
+ return parent.ViewObject.LinePrintColor
+ return None
+
+
def getSVG(obj,
scale=1, linewidth=0.35, fontsize=12,
fillstyle="shape color", direction=None,
diff --git a/src/Mod/Draft/draftguitools/gui_groups.py b/src/Mod/Draft/draftguitools/gui_groups.py
index 305eb6ae52..d580ce4e68 100644
--- a/src/Mod/Draft/draftguitools/gui_groups.py
+++ b/src/Mod/Draft/draftguitools/gui_groups.py
@@ -73,7 +73,7 @@ class AddToGroup(gui_base.GuiCommandNeedsSelection):
d = {'Pixmap': 'Draft_AddToGroup',
'MenuText': QT_TRANSLATE_NOOP("Draft_AddToGroup",
- "Move to group"),
+ "Move to group")+"...",
'ToolTip': QT_TRANSLATE_NOOP("Draft_AddToGroup",
_tooltip)}
return d
diff --git a/src/Mod/Draft/draftguitools/gui_setstyle.py b/src/Mod/Draft/draftguitools/gui_setstyle.py
index cf2a8ebd18..5dcd6a923c 100644
--- a/src/Mod/Draft/draftguitools/gui_setstyle.py
+++ b/src/Mod/Draft/draftguitools/gui_setstyle.py
@@ -125,18 +125,25 @@ class Draft_SetStyle_TaskPanel:
if "DrawStyle" in vobj.PropertiesList:
vobj.DrawStyle = ["Solid","Dashed","Dotted","Dashdot"][self.form.DrawStyle.currentIndex()]
if "DisplayMode" in vobj.PropertiesList:
- try:
- vobj.DisplayMode = ["Flat Lines","Wireframe","Shaded","points"][self.form.DisplayMode.currentIndex()]
- except:
- pass
+ dmodes = ["Flat Lines","Wireframe","Shaded","Points"]
+ dm = dmodes[self.form.DisplayMode.currentIndex()]
+ if hasattr(vobj,"Proxy") and hasattr(vobj.Proxy,"getDisplayModes"):
+ dmodes = vobj.Proxy.getDisplayModes(vobj)
+ if dm in dmodes:
+ try:
+ vobj.DisplayMode = dm
+ except:
+ pass
if "ShapeColor" in vobj.PropertiesList:
vobj.ShapeColor = self.form.ShapeColor.property("color").rgb()<<8
if "Transparency" in vobj.PropertiesList:
vobj.Transparency = self.form.Transparency.value()
if "FontName" in vobj.PropertiesList:
- vobj.TextFont = self.form.TextFont.currentFont().family()
+ vobj.FontName = self.form.TextFont.currentFont().family()
if "TextSize" in vobj.PropertiesList:
vobj.TextSize = FreeCAD.Units.Quantity(self.form.TextSize.text()).Value
+ if "FontSize" in vobj.PropertiesList:
+ vobj.FontSize = FreeCAD.Units.Quantity(self.form.TextSize.text()).Value
if "TextColor" in vobj.PropertiesList:
vobj.TextColor = self.form.TextColor.property("color").rgb()<<8
if "ArrowType" in vobj.PropertiesList:
diff --git a/src/Mod/Draft/draftviewproviders/view_layer.py b/src/Mod/Draft/draftviewproviders/view_layer.py
index 740cb77a83..897380827a 100644
--- a/src/Mod/Draft/draftviewproviders/view_layer.py
+++ b/src/Mod/Draft/draftviewproviders/view_layer.py
@@ -80,6 +80,17 @@ class ViewProviderLayer:
_tip)
vobj.OverrideShapeColorChildren = True
+ if "UsePrintColor" not in properties:
+ _tip = QT_TRANSLATE_NOOP("App::Property",
+ "If it is true, the print color "
+ "will be used when objects in this "
+ "layer are placed on a TechDraw page")
+ vobj.addProperty("App::PropertyBool",
+ "UsePrintColor",
+ "Print",
+ _tip)
+
+
def set_visual_properties(self, vobj, properties):
"""Set visual properties only if they don't already exist."""
view_group = App.ParamGet("User parameter:BaseApp/Preferences/View")
@@ -145,6 +156,16 @@ class ViewProviderLayer:
_tip)
vobj.Transparency = 0
+ if "LinePrintColor" not in properties:
+ _tip = QT_TRANSLATE_NOOP("App::Property",
+ "The line color of the objects "
+ "contained within this layer, "
+ "when used on a TechDraw page")
+ vobj.addProperty("App::PropertyColor",
+ "LinePrintColor",
+ "Print",
+ _tip)
+
def getIcon(self):
"""Return the path to the icon used by the viewprovider.
@@ -382,6 +403,11 @@ class ViewProviderLayerContainer:
menu)
action1.triggered.connect(self.merge_by_name)
menu.addAction(action1)
+ action2 = QtGui.QAction(QtGui.QIcon(":/icons/Draft_NewLayer.svg"),
+ translate("Draft", "Add new layer"),
+ menu)
+ action2.triggered.connect(self.add_layer)
+ menu.addAction(action2)
def merge_by_name(self):
"""Merge the layers that have the same name."""
@@ -442,6 +468,12 @@ class ViewProviderLayerContainer:
_msg("InList not empty. "
"Unable to delete layer: " + layer.Label)
+ def add_layer(self):
+ """Creates a new layer"""
+ import Draft
+ Draft.make_layer()
+ App.ActiveDocument.recompute()
+
def __getstate__(self):
"""Return a tuple of objects to save or None."""
return None
diff --git a/src/Mod/Path/CMakeLists.txt b/src/Mod/Path/CMakeLists.txt
index b25189233a..db02b58762 100644
--- a/src/Mod/Path/CMakeLists.txt
+++ b/src/Mod/Path/CMakeLists.txt
@@ -204,6 +204,7 @@ SET(PathTests_SRCS
PathTests/TestPathToolController.py
PathTests/TestPathTooltable.py
PathTests/TestPathUtil.py
+ PathTests/TestPathVcarve.py
PathTests/TestPathVoronoi.py
PathTests/boxtest.fcstd
PathTests/test_centroid_00.ngc
diff --git a/src/Mod/Path/PathScripts/PathGeom.py b/src/Mod/Path/PathScripts/PathGeom.py
index 1b6c67848d..69f116f594 100644
--- a/src/Mod/Path/PathScripts/PathGeom.py
+++ b/src/Mod/Path/PathScripts/PathGeom.py
@@ -222,7 +222,7 @@ def speedBetweenPoints(p0, p1, hSpeed, vSpeed):
pitch = pitch + 1
while pitch > 1:
pitch = pitch - 1
- print(" pitch = %g %g (%.2f, %.2f, %.2f) -> %.2f" % (pitch, math.atan2(xy(d).Length, d.z), d.x, d.y, d.z, xy(d).Length))
+ PathLog.debug(" pitch = %g %g (%.2f, %.2f, %.2f) -> %.2f" % (pitch, math.atan2(xy(d).Length, d.z), d.x, d.y, d.z, xy(d).Length))
speed = vSpeed + pitch * (hSpeed - vSpeed)
if speed > hSpeed and speed > vSpeed:
return max(hSpeed, vSpeed)
diff --git a/src/Mod/Path/PathScripts/PathOp.py b/src/Mod/Path/PathScripts/PathOp.py
index 0a16a1361c..ee1cde01dc 100644
--- a/src/Mod/Path/PathScripts/PathOp.py
+++ b/src/Mod/Path/PathScripts/PathOp.py
@@ -524,6 +524,10 @@ class ObjectOp(object):
result = self.opExecute(obj) # pylint: disable=assignment-from-no-return
+ if self.commandlist and (FeatureHeights & self.opFeatures(obj)):
+ # Let's finish by rapid to clearance...just for safety
+ self.commandlist.append(Path.Command("G0", {"Z": obj.ClearanceHeight.Value}))
+
path = Path.Path(self.commandlist)
obj.Path = path
obj.CycleTime = self.getCycleTimeEstimate(obj)
diff --git a/src/Mod/Path/PathScripts/PathThreadMillingGui.py b/src/Mod/Path/PathScripts/PathThreadMillingGui.py
index 66acac9387..fab21692a7 100644
--- a/src/Mod/Path/PathScripts/PathThreadMillingGui.py
+++ b/src/Mod/Path/PathScripts/PathThreadMillingGui.py
@@ -203,7 +203,7 @@ class TaskPanelOpPage(PathCircularHoleBaseGui.TaskPanelOpPage):
Command = PathOpGui.SetupOperation('Thread Milling',
PathThreadMilling.Create,
TaskPanelOpPage,
- 'Path-ThreadMilling',
+ 'Path_ThreadMilling',
QtCore.QT_TRANSLATE_NOOP("PathThreadMilling", "Thread Milling"),
QtCore.QT_TRANSLATE_NOOP("PathThreadMilling", "Creates a Path Thread Milling operation from features of a base object"),
PathThreadMilling.SetupProperties)
diff --git a/src/Mod/Path/PathScripts/PathToolBitLibraryGui.py b/src/Mod/Path/PathScripts/PathToolBitLibraryGui.py
index b7b41c4fb3..33e8fb8e39 100644
--- a/src/Mod/Path/PathScripts/PathToolBitLibraryGui.py
+++ b/src/Mod/Path/PathScripts/PathToolBitLibraryGui.py
@@ -334,7 +334,7 @@ class ToolBitSelector(object):
tools = self.selectedOrAllTools()
for tool in tools:
- tc = PathToolControllerGui.Create(tool[1].Label, tool[1], tool[0])
+ tc = PathToolControllerGui.Create("TC: {}".format(tool[1].Label), tool[1], tool[0])
job.Proxy.addToolController(tc)
FreeCAD.ActiveDocument.recompute()
diff --git a/src/Mod/Path/PathScripts/PathToolController.py b/src/Mod/Path/PathScripts/PathToolController.py
index 45e468500f..199d5cdf22 100644
--- a/src/Mod/Path/PathScripts/PathToolController.py
+++ b/src/Mod/Path/PathScripts/PathToolController.py
@@ -225,13 +225,13 @@ class ToolController:
obj.addProperty("App::PropertyLink", "Tool", "Base", QtCore.QT_TRANSLATE_NOOP("PathToolController", "The tool used by this controller"))
-def Create(name='Default Tool', tool=None, toolNumber=1, assignViewProvider=True):
+def Create(name='TC: Default Tool', tool=None, toolNumber=1, assignViewProvider=True):
legacyTool = PathPreferences.toolsReallyUseLegacyTools() if tool is None else isinstance(tool, Path.Tool)
PathLog.track(tool, toolNumber, legacyTool)
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)
- obj.Label = "TC: {}".format(name)
+ obj.Label = name
obj.Proxy = ToolController(obj, legacyTool)
if FreeCAD.GuiUp and assignViewProvider:
diff --git a/src/Mod/Path/PathScripts/PathVcarve.py b/src/Mod/Path/PathScripts/PathVcarve.py
index 00e812392f..dd713923d6 100644
--- a/src/Mod/Path/PathScripts/PathVcarve.py
+++ b/src/Mod/Path/PathScripts/PathVcarve.py
@@ -157,6 +157,45 @@ def _sortVoronoiWires(wires, start=FreeCAD.Vector(0, 0, 0)):
return result
+class _Geometry(object):
+ '''POD class so the limits only have to be calculated once.'''
+
+ def __init__(self, zStart, zStop, zScale):
+ self.start = zStart
+ self.stop = zStop
+ self.scale = zScale
+
+ @classmethod
+ def FromTool(cls, tool, zStart, zFinal):
+ rMax = float(tool.Diameter) / 2.0
+ rMin = float(tool.TipDiameter) / 2.0
+ toolangle = math.tan(math.radians(tool.CuttingEdgeAngle.Value / 2.0))
+ zScale = 1.0 / toolangle
+ zStop = zStart - rMax * zScale
+ zOff = rMin * zScale
+
+ return _Geometry(zStart + zOff, max(zStop + zOff, zFinal), zScale)
+
+ @classmethod
+ def FromObj(cls, obj, model):
+ zStart = model.Shape.BoundBox.ZMax
+ finalDepth = obj.FinalDepth.Value
+
+ return cls.FromTool(obj.ToolController.Tool, zStart, finalDepth)
+
+def _calculate_depth(MIC, geom):
+ # given a maximum inscribed circle (MIC) and tool angle,
+ # return depth of cut relative to zStart.
+ depth = geom.start - round(MIC / geom.scale, 4)
+ PathLog.debug('zStart value: {} depth: {}'.format(geom.start, depth))
+
+ return max(depth, geom.stop)
+
+def _getPartEdge(edge, depths):
+ dist = edge.getDistances()
+ zBegin = _calculate_depth(dist[0], depths)
+ zEnd = _calculate_depth(dist[1], depths)
+ return edge.toShape(zBegin, zEnd)
class ObjectVcarve(PathEngraveBase.ObjectOp):
'''Proxy class for Vcarve operation.'''
@@ -197,42 +236,10 @@ class ObjectVcarve(PathEngraveBase.ObjectOp):
# upgrade ...
self.setupAdditionalProperties(obj)
- def _calculate_depth(self, MIC, zStart, zStop, zScale, finaldepth):
- # given a maximum inscribed circle (MIC) and tool angle,
- # return depth of cut relative to zStart.
- depth = zStart - round(MIC / zScale, 4)
- PathLog.debug('zStart value: {} depth: {}'.format(zStart, depth))
-
- # Never go below the operation final depth.
- zStop = zStop if zStop > finaldepth else finaldepth
-
- return depth if depth > zStop else zStop
-
- def _getPartEdge(self, edge, zStart, zStop, zScale, finaldepth):
- dist = edge.getDistances()
- return edge.toShape(self._calculate_depth(dist[0],
- zStart,
- zStop,
- zScale,
- finaldepth),
- self._calculate_depth(dist[1],
- zStart,
- zStop,
- zScale,
- finaldepth))
-
- def _getPartEdges(self, obj, vWire):
- # pre-calculate the depth limits - pre-mature optimisation ;)
- r = float(obj.ToolController.Tool.Diameter) / 2
- toolangle = obj.ToolController.Tool.CuttingEdgeAngle
- zStart = self.model[0].Shape.BoundBox.ZMin
- zStop = zStart - r / math.tan(math.radians(toolangle/2))
- zScale = 1.0 / math.tan(math.radians(toolangle / 2))
- finaldepth = obj.FinalDepth.Value
-
+ def _getPartEdges(self, obj, vWire, geom):
edges = []
for e in vWire:
- edges.append(self._getPartEdge(e, zStart, zStop, zScale, finaldepth))
+ edges.append(_getPartEdge(e, geom))
return edges
def buildPathMedial(self, obj, Faces):
@@ -253,14 +260,12 @@ class ObjectVcarve(PathEngraveBase.ObjectOp):
path.append(Path.Command("G0 Z{}".format(obj.SafeHeight.Value)))
e = edges[0]
p = e.valueAt(e.FirstParameter)
- path.append(Path.Command("G0 X{} Y{} Z{}".format(p.x, p.y,
- obj.SafeHeight.Value)))
- c = Path.Command("G1 X{} Y{} Z{} F{}".format(p.x, p.y, p.z,
- obj.ToolController.HorizFeed.Value))
- path.append(c)
+ path.append(Path.Command("G0 X{} Y{} Z{}".format(p.x, p.y, obj.SafeHeight.Value)))
+ hSpeed = obj.ToolController.HorizFeed.Value
+ vSpeed = obj.ToolController.VertFeed.Value
+ path.append(Path.Command("G1 X{} Y{} Z{} F{}".format(p.x, p.y, p.z, vSpeed)))
for e in edges:
- path.extend(PathGeom.cmdsForEdge(e,
- hSpeed=obj.ToolController.HorizFeed.Value))
+ path.extend(PathGeom.cmdsForEdge(e, hSpeed=hSpeed, vSpeed=vSpeed))
return path
@@ -290,10 +295,12 @@ class ObjectVcarve(PathEngraveBase.ObjectOp):
if _sorting == 'global':
voronoiWires = _sortVoronoiWires(voronoiWires)
+ geom = _Geometry.FromObj(obj, self.model[0])
+
pathlist = []
pathlist.append(Path.Command("(starting)"))
for w in voronoiWires:
- pWire = self._getPartEdges(obj, w)
+ pWire = self._getPartEdges(obj, w, geom)
if pWire:
wires.append(pWire)
pathlist.extend(cutWire(pWire))
@@ -355,6 +362,9 @@ operation will produce no output.'))
else:
obj.OpFinalDepth = -0.1
+ def isToolSupported(self, obj, tool):
+ '''isToolSupported(obj, tool) ... returns True if v-carve op can work with tool.'''
+ return hasattr(tool, 'Diameter') and hasattr(tool, 'CuttingEdgeAngle') and hasattr(tool, 'TipDiameter')
def SetupProperties():
return ["Discretize"]
diff --git a/src/Mod/Path/PathTests/TestPathVcarve.py b/src/Mod/Path/PathTests/TestPathVcarve.py
new file mode 100644
index 0000000000..686cc4ddff
--- /dev/null
+++ b/src/Mod/Path/PathTests/TestPathVcarve.py
@@ -0,0 +1,114 @@
+# -*- coding: utf-8 -*-
+
+# ***************************************************************************
+# * *
+# * Copyright (c) 2020 sliptonic *
+# * *
+# * This program is free software; you can redistribute it and/or modify *
+# * it under the terms of the GNU Lesser General Public License (LGPL) *
+# * as published by the Free Software Foundation; either version 2 of *
+# * the License, or (at your option) any later version. *
+# * for detail see the LICENCE text file. *
+# * *
+# * This program 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 program; if not, write to the Free Software *
+# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
+# * USA *
+# * *
+# ***************************************************************************
+
+import FreeCAD
+import PathScripts.PathGeom as PathGeom
+import PathScripts.PathToolBit as PathToolBit
+import PathScripts.PathVcarve as PathVcarve
+import math
+
+from PathTests.PathTestUtils import PathTestBase
+
+class VbitTool(object):
+ '''Faked out vcarve tool'''
+
+ def __init__(self, dia, angle, tipDia):
+ self.Diameter = FreeCAD.Units.Quantity(dia, FreeCAD.Units.Length)
+ self.CuttingEdgeAngle = FreeCAD.Units.Quantity(angle, FreeCAD.Units.Angle)
+ self.TipDiameter = FreeCAD.Units.Quantity(tipDia, FreeCAD.Units.Length)
+
+Scale45 = 2.414214
+Scale60 = math.sqrt(3)
+
+class TestPathVcarve(PathTestBase):
+ '''Test Vcarve milling basics.'''
+
+ def test00(self):
+ '''Verify 90 deg depth calculation'''
+ tool = VbitTool(10, 90, 0)
+ geom = PathVcarve._Geometry.FromTool(tool, 0, -10)
+ self.assertRoughly(geom.start, 0)
+ self.assertRoughly(geom.stop, -5)
+ self.assertRoughly(geom.scale, 1)
+
+ def test01(self):
+ '''Verify 90 deg depth limit'''
+ tool = VbitTool(10, 90, 0)
+ geom = PathVcarve._Geometry.FromTool(tool, 0, -3)
+ self.assertRoughly(geom.start, 0)
+ self.assertRoughly(geom.stop, -3)
+ self.assertRoughly(geom.scale, 1)
+
+ def test02(self):
+ '''Verify 60 deg depth calculation'''
+ tool = VbitTool(10, 60, 0)
+ geom = PathVcarve._Geometry.FromTool(tool, 0, -10)
+ self.assertRoughly(geom.start, 0)
+ self.assertRoughly(geom.stop, -5 * Scale60)
+ self.assertRoughly(geom.scale, Scale60)
+
+ def test03(self):
+ '''Verify 60 deg depth limit'''
+ tool = VbitTool(10, 60, 0)
+ geom = PathVcarve._Geometry.FromTool(tool, 0, -3)
+ self.assertRoughly(geom.start, 0)
+ self.assertRoughly(geom.stop, -3)
+ self.assertRoughly(geom.scale, Scale60)
+
+ def test10(self):
+ '''Verify 90 deg with tip dia depth calculation'''
+ tool = VbitTool(10, 90, 2)
+ geom = PathVcarve._Geometry.FromTool(tool, 0, -10)
+ # in order for the width to be correct the height needs to be shifted
+ self.assertRoughly(geom.start, 1)
+ self.assertRoughly(geom.stop, -4)
+ self.assertRoughly(geom.scale, 1)
+
+ def test11(self):
+ '''Verify 90 deg with tip dia depth limit calculation'''
+ tool = VbitTool(10, 90, 2)
+ geom = PathVcarve._Geometry.FromTool(tool, 0, -3)
+ # in order for the width to be correct the height needs to be shifted
+ self.assertRoughly(geom.start, 1)
+ self.assertRoughly(geom.stop, -3)
+ self.assertRoughly(geom.scale, 1)
+
+ def test12(self):
+ '''Verify 45 deg with tip dia depth calculation'''
+ tool = VbitTool(10, 45, 2)
+ geom = PathVcarve._Geometry.FromTool(tool, 0, -10)
+ # in order for the width to be correct the height needs to be shifted
+ self.assertRoughly(geom.start, Scale45)
+ self.assertRoughly(geom.stop, -4 * Scale45)
+ self.assertRoughly(geom.scale, Scale45)
+
+ def test13(self):
+ '''Verify 45 deg with tip dia depth limit calculation'''
+ tool = VbitTool(10, 45, 2)
+ geom = PathVcarve._Geometry.FromTool(tool, 0, -3)
+ # in order for the width to be correct the height needs to be shifted
+ self.assertRoughly(geom.start, Scale45)
+ self.assertRoughly(geom.stop, -3)
+ self.assertRoughly(geom.scale, Scale45)
+
diff --git a/src/Mod/Path/TestPathApp.py b/src/Mod/Path/TestPathApp.py
index 623bf180ee..0adebedfc6 100644
--- a/src/Mod/Path/TestPathApp.py
+++ b/src/Mod/Path/TestPathApp.py
@@ -42,6 +42,7 @@ from PathTests.TestPathDeburr import TestPathDeburr
from PathTests.TestPathHelix import TestPathHelix
from PathTests.TestPathVoronoi import TestPathVoronoi
from PathTests.TestPathThreadMilling import TestPathThreadMilling
+from PathTests.TestPathVcarve import TestPathVcarve
# dummy usage to get flake8 and lgtm quiet
False if TestApp.__name__ else True
@@ -64,4 +65,5 @@ False if TestPathPreferences.__name__ else True
False if TestPathToolBit.__name__ else True
False if TestPathVoronoi.__name__ else True
False if TestPathThreadMilling.__name__ else True
+False if TestPathVcarve.__name__ else True
diff --git a/src/Mod/Path/Tools/Bit/60degree_Vbit.fctb b/src/Mod/Path/Tools/Bit/60degree_Vbit.fctb
index 715361ec34..69d181d4a3 100644
--- a/src/Mod/Path/Tools/Bit/60degree_Vbit.fctb
+++ b/src/Mod/Path/Tools/Bit/60degree_Vbit.fctb
@@ -5,10 +5,10 @@
"parameter": {
"CuttingEdgeAngle": "60.0000 \u00b0",
"Diameter": "10.0000 mm",
- "FlatHeight": "1.0000 mm",
- "FlatRadius": "0.5000 mm",
+ "CuttingEdgeHeight": "1.0000 mm",
+ "TipDiameter": "1.0000 mm",
"Length": "20.0000 mm",
"ShankDiameter": "5.0000 mm"
},
"attribute": {}
-}
\ No newline at end of file
+}
diff --git a/src/Mod/Path/Tools/Shape/ballend.fcstd b/src/Mod/Path/Tools/Shape/ballend.fcstd
index 79cbd68605..c3c5ee8b25 100644
Binary files a/src/Mod/Path/Tools/Shape/ballend.fcstd and b/src/Mod/Path/Tools/Shape/ballend.fcstd differ
diff --git a/src/Mod/Path/Tools/Shape/bullnose.fcstd b/src/Mod/Path/Tools/Shape/bullnose.fcstd
index c2f7240b72..c35ae78d81 100644
Binary files a/src/Mod/Path/Tools/Shape/bullnose.fcstd and b/src/Mod/Path/Tools/Shape/bullnose.fcstd differ
diff --git a/src/Mod/Path/Tools/Shape/chamfer.fcstd b/src/Mod/Path/Tools/Shape/chamfer.fcstd
index e56a1359d4..3470b4a3c6 100644
Binary files a/src/Mod/Path/Tools/Shape/chamfer.fcstd and b/src/Mod/Path/Tools/Shape/chamfer.fcstd differ
diff --git a/src/Mod/Path/Tools/Shape/endmill.fcstd b/src/Mod/Path/Tools/Shape/endmill.fcstd
index 8e258621ba..98888db1e3 100644
Binary files a/src/Mod/Path/Tools/Shape/endmill.fcstd and b/src/Mod/Path/Tools/Shape/endmill.fcstd differ
diff --git a/src/Mod/Path/Tools/Shape/thread-mill.fcstd b/src/Mod/Path/Tools/Shape/thread-mill.fcstd
index ba9294fe6f..d97e56241f 100644
Binary files a/src/Mod/Path/Tools/Shape/thread-mill.fcstd and b/src/Mod/Path/Tools/Shape/thread-mill.fcstd differ
diff --git a/src/Mod/Path/Tools/Shape/v-bit.fcstd b/src/Mod/Path/Tools/Shape/v-bit.fcstd
index 5d35188c81..3168e5fe8d 100644
Binary files a/src/Mod/Path/Tools/Shape/v-bit.fcstd and b/src/Mod/Path/Tools/Shape/v-bit.fcstd differ