Python code of Hole Feature

This commit is contained in:
jrheinlaender 2013-09-16 20:15:34 +02:00 committed by Stefan Tröger
parent 45ce3b7822
commit 0a743b27da
12 changed files with 3164 additions and 1 deletions

View File

@ -71,3 +71,35 @@ INSTALL(
DESTINATION
Mod/PartDesign/WizardShaft
)
SET(FeatureHole_SRCS
FeatureHole/__init__.py
FeatureHole/HoleGui.py
FeatureHole/FeatureHole.py
FeatureHole/TaskHole.py
FeatureHole/ViewProviderHole.py
FeatureHole/Standards.py
FeatureHole/PartDesign_Hole.svg
)
SOURCE_GROUP("featurehole" FILES ${FeatureHole_SRCS})
SET(FeatureHole_UI
FeatureHole/TaskHole.ui
)
SET(all_featurehole_files ${FeatureHole_SRCS} ${FeatureHole_UI})
ADD_CUSTOM_TARGET(FeatureHole ALL
SOURCES ${all_featurehole_files}
)
SET(all_files ${all_featurehole_files})
fc_copy_sources(Mod/PartDesign "${CMAKE_BINARY_DIR}/Mod/PartDesign" ${all_files})
INSTALL(
FILES
${FeatureHole_SRCS}
DESTINATION
Mod/PartDesign/FeatureHole
)

View File

@ -0,0 +1,483 @@
#/******************************************************************************
# * Copyright (c)2012 Jan Rheinlaender <jrheinlaender@users.sourceforge.net> *
# * *
# * 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 *
# * *
# ******************************************************************************/
import FreeCAD, FreeCADGui
import Part, Sketcher, PartDesignGui
import math
def makeVector(point):
if point.__class__ == FreeCAD.Vector:
return point
return FreeCAD.Vector(point.X, point.Y, point.Z)
class Hole():
"Hole feature"
App = FreeCAD
Gui = FreeCADGui
def __init__(self, feature):
self.feature = feature
self.feature.addProperty("App::PropertyString","HoleType","Hole","Type of hole").HoleType="Depth"
self.feature.addProperty("App::PropertyBool","Threaded","Hole","Threaded hole").Threaded=False
self.feature.addProperty("App::PropertyBool","Counterbore","Hole","Counterbore hole").Counterbore=False
self.feature.addProperty("App::PropertyBool","Countersink","Hole","Countersink hole").Countersink=False
self.feature.addProperty("App::PropertyString","Norm","Hole","Name of norm").Norm="Custom"
self.feature.addProperty("App::PropertyString","NormTolerance","Hole","Tolerance field of norm").NormTolerance="medium"
self.feature.addProperty("App::PropertyLength","NormDiameter","Hole","Nominal diameter of hole").NormDiameter=4.0
self.feature.addProperty("App::PropertyString", "ExtraNorm", "Hole", "Norm of bolt or washer used in hole").ExtraNorm="ISO 4762"
self.feature.addProperty("App::PropertyString", "NormThread", "Hole", "Norm of thread").NormThread="DIN 13-1"
self.feature.addProperty("App::PropertyString", "NormThreadFinish", "Hole", "Norm defining thread finish length").NormThreadFinish="DIN 76-2"
self.feature.addProperty("App::PropertyLength","Diameter","Hole","Diameter of hole").Diameter=5.0
self.feature.addProperty("App::PropertyLength","Depth","Hole","Depth of hole").Depth=8.0
self.feature.addProperty("App::PropertyLength","CounterboreDiameter","Hole","Diameter of counterbore").CounterboreDiameter=10.0
self.feature.addProperty("App::PropertyLength","CounterboreDepth","Hole","Depth of counterbore").CounterboreDepth=4.0
self.feature.addProperty("App::PropertyLength","CountersinkAngle","Hole","Angle of countersink").CountersinkAngle=45.0;
self.feature.addProperty("App::PropertyLength","ThreadLength","Hole","Length of thread").ThreadLength=5.0;
self.feature.addProperty("App::PropertyString","PositionType","Hole","Type of position references").PositionType="Linear"
self.feature.addProperty("App::PropertyLinkSub","Support","Hole","Support of hole feature").Support=None
self.feature.addProperty("App::PropertyLink","HoleGroove","Hole","Revolution feature creating the hole").HoleGroove=None
# Create new HoleGroove feature
body = PartDesignGui.getActivePart()
self.sketchaxis = self.feature.Document.addObject("PartDesign::Line", "HoleSketchAxis")
body.addFeature(self.sketchaxis)
self.Gui.ActiveDocument.hide(self.sketchaxis.Name)
self.sketchplane = self.feature.Document.addObject("PartDesign::Plane", "HoleSketchPlane")
self.sketchplane.References = (self.sketchaxis, "")
body.addFeature(self.sketchplane)
self.Gui.ActiveDocument.hide(self.sketchplane.Name)
self.sketch = self.feature.Document.addObject("Sketcher::SketchObject","HoleSketch")
self.sketch.Support = (self.sketchplane, ["front"])
body.addFeature(self.sketch)
self.Gui.ActiveDocument.hide(self.sketch.Name)
feature.HoleGroove = feature.Document.addObject("PartDesign::Groove","HoleGroove")
feature.HoleGroove.Angle = 360.0
feature.HoleGroove.Sketch = self.sketch
body.addFeature(feature.HoleGroove)
self.Gui.ActiveDocument.hide(feature.HoleGroove.Name)
self.feature.Proxy = self
self.oldCounterbore = False
self.oldCountersink = False
def execute(self, feature):
if feature.Support != None:
(support, element) = feature.Support
feature.Placement = feature.HoleGroove.Placement
shape = feature.HoleGroove.Shape.copy()
shape.Placement = FreeCAD.Placement()
feature.Shape = shape
self.Gui.ActiveDocument.hide(support.Name)
# Copy display properties from support
featview = feature.ViewObject
suppview = support.ViewObject
for p in suppview.PropertiesList:
if not p in ["DisplayMode","BoundingBox","Proxy","RootNode","Visibility"]:
if p in featview.PropertiesList:
val = getattr(suppview,p)
setattr(featview,p,val)
if suppview.DisplayMode in featview.listDisplayModes():
featview.DisplayMode = suppview.DisplayMode
if hasattr(suppview,"DiffuseColor") and hasattr(featview,"DiffuseColor"):
featview.DiffuseColor = suppview.DiffuseColor
def onChanged(self, fp, prop):
#self.App.Console.PrintMessage("Change property: " + str(prop) + "\n")
if fp == None or fp.Support == None:
return
if (prop == "HoleType" or prop == "Threaded" or prop == "Counterbore" or prop == "Countersink"
or prop == "Diameter" or prop == "Depth"
or prop == "CounterboreDiameter" or prop == "CounterboreDepth"
or prop == "CountersinkAngle"):
self.executeSketchChanged(fp)
fp.Document.recompute()
elif prop == "Support":
self.executePositionChanged(fp)
fp.Document.recompute()
def executePositionChanged(self, fp):
"Change the position of the hole"
if fp.Support == None:
return
plane = self.feature.HoleGroove.Sketch.Support[0]
# Get support (face)
(support, elementList) = fp.Support
face = eval("support.Shape." + elementList[0])
refs = plane.References
if len(refs) == 0:
return
axis = plane.References[0][0]
firstTime = (len(axis.References) == 0)
if firstTime:
# Try to guess some references (using arcs or lines of the outer wire of the support face)
wire = face.OuterWire
firstLine = None
for e in wire.Edges:
if type(e.Curve) == Part.Line:
if firstLine == None:
firstLine = e
firstDirection = e.Curve.EndPoint - e.Curve.StartPoint
else:
if firstDirection == e.Curve.EndPoint - e.Curve.StartPoint or firstDirection == e.Curve.StartPoint - e.Curve.EndPoint:
continue # Parallel edges
allEdges = support.Shape.Edges
firstLineIndex = -1
secondLineIndex = -1
for i in range(len(allEdges)):
try:
if type(allEdges[i].Curve) != Part.Line:
continue
if (allEdges[i].Curve.StartPoint == firstLine.Curve.StartPoint and allEdges[i].Curve.EndPoint == firstLine.Curve.EndPoint) or (allEdges[i].Curve.EndPoint == firstLine.Curve.StartPoint and allEdges[i].Curve.StartPoint == firstLine.Curve.EndPoint):
firstLineIndex = i
elif (allEdges[i].Curve.StartPoint == e.Curve.StartPoint and allEdges[i].Curve.EndPoint == e.Curve.EndPoint) or (allEdges[i].Curve.EndPoint == e.Curve.StartPoint and allEdges[i].Curve.StartPoint == e.Curve.EndPoint):
secondLineIndex = i
if (firstLineIndex > -1) and (secondLineIndex > -1):
break
except:
# Unknown curvetype GeomAbs_OtherCurve
continue
axis.References = [(support, elementList[0]), (support, "Edge" + str(firstLineIndex+1)), (support, "Edge" + str(secondLineIndex+1))]
axis.Offset = 1.0
axis.Offset2 = 1.0
self.feature.PositionType = "Linear"
# Place the axis approximately in the center of the face
#p = face.CenterOfMass
#l1 = Part.Line(firstLine.Curve)
#l2 = Part.Line(e.Curve)
#axis.Offset = p.distanceToLine(l1.StartPoint, l1.EndPoint - l1.StartPoint)
#axis.Offset2 = p.distanceToLine(l1.StartPoint, l2.EndPoint - l2.StartPoint)
# TODO: Ensure that the hole is inside the face!
break
elif type(e.Curve) == Part.Circle:
allEdges = support.Shape.Edges
for i in range(len(allEdges)):
try:
if type(allEdges[i].Curve) != Part.Circle:
continue
c = allEdges[i].Curve
if c.Center == e.Curve.Center and c.Axis == e.Curve.Axis and c.Radius == e.Curve.Radius:
axis.References = [(support, "Edge" + str(i+1))]
self.feature.PositionType = "Coaxial"
break
except:
# Unknown curvetype
continue
elif type(e.Curve) == Part.ArcOfCircle:
allEdges = support.Shape.Edges
for i in range(len(allEdges)):
try:
if type(allEdges[i].Curve) != Part.ArcOfCircle:
continue
a = allEdges[i].Curve
if a.Center == e.Curve.Center and a.Axis == e.Curve.Axis and a.Radius == e.Curve.Radius and a.FirstParameter == e.Curve.FirstParameter and a.LastParameter == e.Curve.LastParameter:
axis.References = [(support, "Edge" + str(i+1))]
self.feature.PositionType = "Coaxial"
break
except:
continue
break
# Grab a point from the wire of the support face
axisbase = axis.Shape.Curve.StartPoint
axisdir = axis.Shape.Curve.EndPoint - axisbase
found = False
if not firstTime and len(refs) > 1:
# Try to keep the old point, to avoid the sketch plane jumping around
(obj, sub) = refs[1]
point = eval("support.Shape." + sub)
if point.Point.distanceToLine(axisbase, axisdir) > 1E-10: # TODO: Precision::Confusion()
found = True
if not found:
for p in face.OuterWire.Vertexes:
if p.Point.distanceToLine(axisbase, axisdir) > 1E-10: # TODO: Precision::Confusion()
point = p
found = True
break
if not found:
point = face.OuterWire.Vertexes[0] # Better this than nothing... and it can't actually happen, can it?
# Find the index of the point in the support shape
allVertexes = support.Shape.Vertexes
for v in range(len(allVertexes)):
if allVertexes[v].Point == point.Point:
# Use this point and the axis to define the sketch plane
if len(refs) < 2:
refs.append((support, "Vertex" + str(v+1)))
else:
refs[1] = (support, "Vertex" + str(v+1))
break
plane.References = refs
if firstTime:
fp.Document.recompute() # Update the Sketch Placement property
self.executeSketchChanged(fp) # Build the sketch of the hole
fp.Document.recompute()
else:
self.executeSketchChanged(fp) # Update the sketch of the hole
self.setHoleDirection(fp)
def setHoleDirection(self, feature):
# Make sure the hole goes into the material, not out of it
sketch = feature.HoleGroove.Sketch
axis = sketch.Support[0].References[0][0]
axisbase = axis.Shape.Curve.StartPoint
axisdir = axis.Shape.Curve.EndPoint - axisbase
p1 = None
p2 = None
for v in sketch.Shape.Vertexes:
# Find the two sketch vertices that are on the sketch axis
if v.Point.distanceToLine(axisbase, axisdir) < 1E-10: # TODO: use Precision::Confusion()
if p1 is None:
p1 = v.Point
else:
p2 = v.Point
break
if p1 is not None and p2 is not None:
(support, elementList) = feature.Support
face = eval("support.Shape." + elementList[0])
plane = face.Surface
if type(plane) != Part.Plane:
return
# Find the vertex that is on the top of the hole
if p1.distanceToPlane(plane.Position, plane.Axis) < 1E-10:
top = p1
dir = p2 - p1
else:
top = p2
dir = p1 - p2
if not support.Shape.isInside(top + dir.multiply(1E-8), 1E-10, False):
# Toggle the angle
angle = sketch.Constraints[12].Value
if angle == math.pi:
sketch.setDatum(12, 0.0)
else:
sketch.setDatum(12, math.pi)
def executeSketchChanged(self, fp):
"Change the sketch shape of the hole"
if self.feature.HoleGroove == None:
return
if fp.HoleType == "Thru":
# TODO: Make this more stable
length = 1E+4
else:
length = fp.Depth
radius = fp.Diameter / 2.0
if fp.Counterbore:
self.createOrUpdateCounterboreSketch(fp, length, radius)
elif fp.Countersink:
self.createOrUpdateCountersinkSketch(fp, length, radius)
else:
self.createOrUpdateStandardSketch(fp, length, radius)
def createOrUpdateStandardSketch(self, fp, depth, radius):
(support, elements) = fp.Support
if fp.HoleGroove.Sketch.GeometryCount == 0:
#FreeCAD.Console.PrintMessage("Standard sketch\n")
# New sketch
sketch = fp.HoleGroove.Sketch
axis = sketch.Support[0].References[0][0]
# Geo -1,1 is the origin (Point)
# Geo -1 is the X-axis
# Geo -2 is the Y-axis
# First external geometry is -3
sketch.addExternal(axis.Name,"Line") # Geo -3: Datum axis
sketch.addExternal(support.Name, elements[0]) # Geo -4: Support face
# Note: Creating the sketch first with depth = 100.0 and then changing the constraint later seems to be more stable
tempDepth = 100.0
# Build the sketch
sketch.addGeometry(Part.Line(self.App.Vector(10.0,50.0,0),self.App.Vector(10.0,-50.0,0))) # Geo0: Rotation axis
sketch.toggleConstruction(0)
sketch.addGeometry(Part.Line(self.App.Vector(10.0,-10.0,0),self.App.Vector(10.0,-30.0,0))) # Geo1: Vertical axis of hole
sketch.addConstraint(Sketcher.Constraint('PointOnObject',1,1,0))# Datum0
sketch.addConstraint(Sketcher.Constraint('PointOnObject',1,2,0))# Datum1
sketch.addGeometry(Part.Line(self.App.Vector(10.0,-10.0,0),self.App.Vector(20.0,-10.0,0))) # Geo2: Top of hole
sketch.addConstraint(Sketcher.Constraint('Coincident',1,1,2,1)) # Datum2
sketch.addConstraint(Sketcher.Constraint('Perpendicular',2, 1)) # Datum3
sketch.addGeometry(Part.Line(self.App.Vector(20.0,-10.0,0),self.App.Vector(20.0,-25.0,0))) # Geo3: Vertical mantle of hole
sketch.addConstraint(Sketcher.Constraint('Coincident',2,2,3,1)) # temporary
sketch.addConstraint(Sketcher.Constraint('Parallel',3, 1)) # Datum4
sketch.addConstraint(Sketcher.Constraint('Distance',3,2,1, 10.0)) # Datum5: Radius
sketch.addConstraint(Sketcher.Constraint('Distance',3,2,2, 15.0)) # Datum6: Depth
sketch.addGeometry(Part.Line(self.App.Vector(10.0,-30.0,0),self.App.Vector(20.0,-25.0,0))) # Geo4: 118 degree tip angle
sketch.addConstraint(Sketcher.Constraint('Coincident',4,1,1,2)) # Datum7
sketch.addConstraint(Sketcher.Constraint('Coincident',4,2,3,2)) # Datum8
# TODO: The tip angle of 118 degrees is for steel only. It should be taken from Part material data
# (as soon as that is implemented)
sketch.addConstraint(Sketcher.Constraint('Angle',4,1,1,2, 118.0/2.0 * math.pi / 180.0)) # Datum9
# Locate at the intersection of the two external geometries
sketch.addConstraint(Sketcher.Constraint('PointOnObject',1,1,-3))# Datum10
sketch.addConstraint(Sketcher.Constraint('PointOnObject',1,1,-4))# Datum11
sketch.addConstraint(Sketcher.Constraint('Angle',0,1,-3, 1, 0.0))# Datum12
# This datum is specific for this holetype, so move it to the last position
sketch.delConstraint(4)
sketch.addConstraint(Sketcher.Constraint('Coincident',2,2,3,1)) # Datum13
fp.HoleGroove.ReferenceAxis = (sketch,['Axis0'])
if self.oldCounterbore == True:
# Remove counterbore from existing sketch
#FreeCAD.Console.PrintMessage("Counter to Standard sketch\n")
sketch = fp.HoleGroove.Sketch
sketch.delConstraint(19)
sketch.delConstraint(18)
sketch.delConstraint(17)
sketch.delConstraint(16)
sketch.delConstraint(15)
sketch.delConstraint(14)
sketch.delConstraint(13)
sketch.delGeometry(6)
sketch.delGeometry(5)
sketch.addConstraint(Sketcher.Constraint('Coincident',2,2,3,1)) # Datum13
elif self.oldCountersink == True:
# Remove countersink from existing sketch
#FreeCAD.Console.PrintMessage("Sink to Standard sketch\n")
sketch = fp.HoleGroove.Sketch
sketch.delConstraint(16)
sketch.delConstraint(15)
sketch.delConstraint(14)
sketch.delConstraint(13)
sketch.delGeometry(5)
sketch.addConstraint(Sketcher.Constraint('Coincident',2,2,3,1)) # Datum13
else:
# Update existing standard sketch
#FreeCAD.Console.PrintMessage("Update Standard sketch\n")
sketch = fp.HoleGroove.Sketch
sketch.setDatum(5, radius)
sketch.setDatum(6, depth)
if sketch.ExternalGeometry[1] != (support, elements[0]):
# Update the external geometry references
angle = sketch.Constraints[12].Value
sketch.delConstraint(13)
sketch.delConstraint(12)
sketch.delConstraint(11)
sketch.delExternal(1)
sketch.addExternal(support.Name, elements[0]) # Geo -4: Support face
sketch.addConstraint(Sketcher.Constraint('PointOnObject',1,1,-4))# Datum11
sketch.addConstraint(Sketcher.Constraint('Angle',0,1,-3, 1, angle))# Datum12
sketch.addConstraint(Sketcher.Constraint('Coincident',2,2,3,1)) # Datum13
self.setHoleDirection(fp)
self.oldCounterbore = False
self.oldCountersink = False
def createOrUpdateCounterboreSketch(self, fp, depth, radius):
cradius = fp.CounterboreDiameter / 2.0
cdepth = fp.CounterboreDepth
(support, elements) = fp.Support
if self.oldCounterbore == True:
# Update properties of existing counterbore sketch
#FreeCAD.Console.PrintMessage("Update to Counterbore sketch\n")
sketch = fp.HoleGroove.Sketch
sketch.setDatum(5, radius)
sketch.setDatum(6, depth)
sketch.setDatum(13, cradius)
sketch.setDatum(15, cdepth)
if sketch.ExternalGeometry[1] != (support, elements[0]):
# Update the external geometry references
angle = sketch.Constraints[12].Value
sketch.delConstraint(19)
sketch.delConstraint(18)
sketch.delConstraint(17)
sketch.delConstraint(16)
sketch.delConstraint(15)
sketch.delConstraint(14)
sketch.delConstraint(13)
sketch.delConstraint(12)
sketch.delConstraint(11)
sketch.delExternal(1)
sketch.addExternal(support.Name, elements[0]) # Geo -4: Support face
sketch.addConstraint(Sketcher.Constraint('PointOnObject',1,1,-4))# Datum11
sketch.addConstraint(Sketcher.Constraint('Angle',0,1,-3, 1, angle))# Datum12
sketch.addConstraint(Sketcher.Constraint('Distance',2, cradius)) # Datum13
sketch.addConstraint(Sketcher.Constraint('Coincident',2,2,5,1)) # Datum14
sketch.addConstraint(Sketcher.Constraint('Distance',3, 1, 2, cdepth)) # Datum15
sketch.addConstraint(Sketcher.Constraint('Parallel',5, 1)) # Datum16
sketch.addConstraint(Sketcher.Constraint('Coincident',5,2,6,1)) # Datum17
sketch.addConstraint(Sketcher.Constraint('Perpendicular',6, -3)) # Datum18
sketch.addConstraint(Sketcher.Constraint('Coincident',6,2,3,1)) # Datum19
else:
# Change standard to counterbore in existing sketch
#FreeCAD.Console.PrintMessage("Standard to Counterbore sketch\n")
sketch = fp.HoleGroove.Sketch
sketch.delConstraint(13)
sketch.addConstraint(Sketcher.Constraint('Distance',2, cradius)) # Datum13
p2 = sketch.Geometry[2].EndPoint
sketch.addGeometry(Part.Line(p2,self.App.Vector(p2.x,p2.y-20.0,0))) # Geo5: Vertical mantle of counterbore
sketch.addConstraint(Sketcher.Constraint('Coincident',2,2,5,1)) # Datum14
sketch.addConstraint(Sketcher.Constraint('Distance',3, 1, 2, cdepth)) # Datum15
sketch.addConstraint(Sketcher.Constraint('Parallel',5, 1)) # Datum16
p3 = sketch.Geometry[3].StartPoint
sketch.addGeometry(Part.Line(self.App.Vector(p2.x,p2.y-20.0, 0),p3)) # Geo6: bottom of counterbore
sketch.addConstraint(Sketcher.Constraint('Coincident',5,2,6,1)) # Datum17
sketch.addConstraint(Sketcher.Constraint('Perpendicular',6, -3)) # Datum18
sketch.addConstraint(Sketcher.Constraint('Coincident',6,2,3,1)) # Datum19
self.setHoleDirection(fp)
self.oldCounterbore = True
self.oldCountersink = False
def createOrUpdateCountersinkSketch(self, fp, depth, radius):
sradius = fp.CounterboreDiameter / 2.0
sangle = fp.CountersinkAngle * math.pi / 180.0
(support, elements) = fp.Support
if self.oldCountersink == True:
# Update properties of existing countersink sketch
#FreeCAD.Console.PrintMessage("Update to Countersink sketch\n")
sketch = fp.HoleGroove.Sketch
sketch.setDatum(5, radius)
sketch.setDatum(6, depth)
sketch.setDatum(13, sradius)
sketch.setDatum(15, sangle)
if sketch.ExternalGeometry[1] != (support, elements[0]):
# Update the external geometry references
angle = sketch.Constraints[12].Value
sketch.delConstraint(16)
sketch.delConstraint(15)
sketch.delConstraint(14)
sketch.delConstraint(13)
sketch.delConstraint(12)
sketch.delConstraint(11)
sketch.delExternal(1)
sketch.addExternal(support.Name, elements[0]) # Geo -4: Support face
sketch.addConstraint(Sketcher.Constraint('PointOnObject',1,1,-4))# Datum11
sketch.addConstraint(Sketcher.Constraint('Angle',0,1,-3, 1, angle))# Datum12
sketch.addConstraint(Sketcher.Constraint('Distance',2, sradius)) # Datum13
sketch.addConstraint(Sketcher.Constraint('Coincident',2,2,5,1)) # Datum14
sketch.addConstraint(Sketcher.Constraint('Angle',5,2, 1,2, sangle)) # Datum15
sketch.addConstraint(Sketcher.Constraint('Coincident',3,1,5,2)) # Datum16
else:
# Change standard to countersink in existing sketch
#FreeCAD.Console.PrintMessage("Standard to Countersink sketch\n")
sketch = fp.HoleGroove.Sketch
sketch.delConstraint(13)
sketch.addConstraint(Sketcher.Constraint('Distance',2, sradius)) # Datum13
p2 = sketch.Geometry[2].EndPoint
sketch.addGeometry(Part.Line(p2,self.App.Vector(p2.x,p2.y-20.0,0))) # Geo5: Chamfer of countersink
sketch.addConstraint(Sketcher.Constraint('Coincident',2,2,5,1)) # Datum14
sketch.addConstraint(Sketcher.Constraint('Angle',5,2, 1,2, sangle)) # Datum15
sketch.addConstraint(Sketcher.Constraint('Coincident',3,1,5,2)) # Datum16
self.setHoleDirection(fp)
self.oldCounterbore = False
self.oldCountersink = True

View File

@ -0,0 +1,92 @@
#/******************************************************************************
# * Copyright (c)2012 Jan Rheinlaender <jrheinlaender@users.sourceforge.net> *
# * *
# * 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 *
# * *
# ******************************************************************************/
import FreeCAD, FreeCADGui
import PartDesignGui
from PyQt4 import QtCore, QtGui
from TaskHole import TaskHole
from FeatureHole import Hole
from ViewProviderHole import ViewProviderHole
class HoleGui:
def getMainWindow(self):
"returns the main window"
# using QtGui.qApp.activeWindow() isn't very reliable because if another
# widget than the mainwindow is active (e.g. a dialog) the wrong widget is
# returned
toplevel = QtGui.qApp.topLevelWidgets()
for i in toplevel:
if i.metaObject().className() == "Gui::MainWindow":
return i
raise Exception("No main window found")
"Create a new hole feature"
def Activated(self):
# Get main window
mw = self.getMainWindow()
# Get active document
doc = FreeCAD.activeDocument()
if doc == None:
QtGui.QMessageBox.critical(mw, "No document", "A document must be open in order to create a hole feature")
return
# Check for valid position selection
selection = FreeCADGui.Selection.getSelectionEx()
if len(selection) != 1:
QtGui.QMessageBox.critical(mw, "No position defined", "Please select a face to create the hole feature on")
return
if selection[0].DocumentName != doc.Name:
QtGui.QMessageBox.critical(mw, "Wrong document", "Please select a face in the active document")
# Note: For some reason setting the Support property here breaks all sorts of things.
# It is done in TaskHole.updateUI() instead
# Show feature preview
body = PartDesignGui.getActivePart()
if body == None:
QtGui.QMessageBox.critical(mw, "No active body", "Please create a body or make a body active")
feature = doc.addObject("Part::FeaturePython","Hole")
hole = Hole(feature)
body.addFeature(feature)
ViewProviderHole(feature.ViewObject)
feature.touch()
FreeCAD.ActiveDocument.recompute()
# Fit view (remove after the testing phase)
FreeCADGui.SendMsgToActiveView("ViewFit")
panel = TaskHole(feature)
FreeCADGui.Control.showDialog(panel)
if panel.setupUi():
FreeCADGui.Control.closeDialog(panel)
return None
return panel
def GetResources(self):
IconPath = FreeCAD.ConfigGet("AppHomePath") + "Mod/PartDesign/FeatureHole/PartDesign_Hole.svg"
MenuText = 'Create a hole feature'
ToolTip = 'Create a hole feature'
return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip}
FreeCADGui.addCommand('PartDesign_Hole', HoleGui())

View File

@ -0,0 +1,646 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64px"
height="64px"
id="svg2816"
version="1.1"
inkscape:version="0.48.3.1 r9886"
sodipodi:docname="PartDesign_Hole3.svg"
sodipodi:version="0.32"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
inkscape:export-filename="/home/yorik/PartDesign_Pocket.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<defs
id="defs2818">
<linearGradient
id="linearGradient4407">
<stop
id="stop4409"
offset="0"
style="stop-color:#001ccc;stop-opacity:0" />
<stop
id="stop4411"
offset="1"
style="stop-color:#00afff;stop-opacity:1;" />
</linearGradient>
<linearGradient
id="linearGradient3669">
<stop
style="stop-color:#001ccc;stop-opacity:1;"
offset="0"
id="stop3671" />
<stop
style="stop-color:#00afff;stop-opacity:1;"
offset="1"
id="stop3673" />
</linearGradient>
<linearGradient
id="linearGradient3602">
<stop
style="stop-color:#ff2600;stop-opacity:1;"
offset="0"
id="stop3604" />
<stop
style="stop-color:#ff5f00;stop-opacity:1;"
offset="1"
id="stop3606" />
</linearGradient>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 32 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="64 : 32 : 1"
inkscape:persp3d-origin="32 : 21.333333 : 1"
id="perspective2824" />
<inkscape:perspective
id="perspective3618"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3602-7"
id="linearGradient3608-5"
x1="3.909091"
y1="14.363636"
x2="24.81818"
y2="14.363636"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient3602-7">
<stop
style="stop-color:#c51900;stop-opacity:1;"
offset="0"
id="stop3604-1" />
<stop
style="stop-color:#ff5f00;stop-opacity:1;"
offset="1"
id="stop3606-3" />
</linearGradient>
<inkscape:perspective
id="perspective3677"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3602-5"
id="linearGradient3608-1"
x1="3.909091"
y1="14.363636"
x2="24.81818"
y2="14.363636"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient3602-5">
<stop
style="stop-color:#c51900;stop-opacity:1;"
offset="0"
id="stop3604-9" />
<stop
style="stop-color:#ff5f00;stop-opacity:1;"
offset="1"
id="stop3606-9" />
</linearGradient>
<linearGradient
y2="14.363636"
x2="24.81818"
y1="14.363636"
x1="3.909091"
gradientUnits="userSpaceOnUse"
id="linearGradient3686"
xlink:href="#linearGradient3602-5"
inkscape:collect="always" />
<inkscape:perspective
id="perspective3717"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3602-58"
id="linearGradient3608-8"
x1="3.909091"
y1="14.363636"
x2="24.81818"
y2="14.363636"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient3602-58">
<stop
style="stop-color:#ff2600;stop-opacity:1;"
offset="0"
id="stop3604-2" />
<stop
style="stop-color:#840000;stop-opacity:1;"
offset="1"
id="stop3606-2" />
</linearGradient>
<linearGradient
y2="14.363636"
x2="24.81818"
y1="14.363636"
x1="3.909091"
gradientUnits="userSpaceOnUse"
id="linearGradient3726"
xlink:href="#linearGradient3602-58"
inkscape:collect="always" />
<inkscape:perspective
id="perspective4410"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4944"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4966"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective5009"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective5165"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective7581"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective7606"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective7638"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective7660"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective7704"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective7730"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective7762"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective7783"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective7843"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective7881"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective7932"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective2866"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective2878"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
id="linearGradient3602-1">
<stop
style="stop-color:#ff2600;stop-opacity:1;"
offset="0"
id="stop3604-8" />
<stop
style="stop-color:#ff5f00;stop-opacity:1;"
offset="1"
id="stop3606-96" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3602-1"
id="linearGradient2875"
gradientUnits="userSpaceOnUse"
x1="3.909091"
y1="14.363636"
x2="24.81818"
y2="14.363636" />
<inkscape:perspective
id="perspective2885"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
id="linearGradient3602-1-5">
<stop
style="stop-color:#ff2600;stop-opacity:1;"
offset="0"
id="stop3604-8-3" />
<stop
style="stop-color:#ff5f00;stop-opacity:1;"
offset="1"
id="stop3606-96-8" />
</linearGradient>
<inkscape:perspective
id="perspective3720"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
id="linearGradient3602-1-8">
<stop
style="stop-color:#ff2600;stop-opacity:1;"
offset="0"
id="stop3604-8-5" />
<stop
style="stop-color:#ff5f00;stop-opacity:1;"
offset="1"
id="stop3606-96-2" />
</linearGradient>
<inkscape:perspective
id="perspective3822"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3849"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3879"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective2896"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective2925"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective2925-4"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3726"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3689"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
id="linearGradient3669-2">
<stop
style="stop-color:#af7d00;stop-opacity:1;"
offset="0"
id="stop3671-7" />
<stop
style="stop-color:#ffed00;stop-opacity:1;"
offset="1"
id="stop3673-5" />
</linearGradient>
<linearGradient
gradientTransform="matrix(0.73872768,0,0,1.3536788,-2.25,-1.9999999)"
y2="1.8468192"
x2="48.259949"
y1="33.61211"
x1="34.290413"
gradientUnits="userSpaceOnUse"
id="linearGradient3698"
xlink:href="#linearGradient3669-2"
inkscape:collect="always" />
<inkscape:perspective
id="perspective3689-6"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
id="linearGradient3669-22">
<stop
style="stop-color:#af7d00;stop-opacity:1;"
offset="0"
id="stop3671-8" />
<stop
style="stop-color:#ffed00;stop-opacity:1;"
offset="1"
id="stop3673-4" />
</linearGradient>
<linearGradient
gradientTransform="matrix(0.73872768,0,0,1.3536788,-2.25,-1.9999999)"
y2="1.8468192"
x2="48.259949"
y1="33.61211"
x1="34.290413"
gradientUnits="userSpaceOnUse"
id="linearGradient3698-3"
xlink:href="#linearGradient3669-22"
inkscape:collect="always" />
<inkscape:perspective
id="perspective3689-1"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
id="linearGradient3669-0">
<stop
style="stop-color:#af7d00;stop-opacity:1;"
offset="0"
id="stop3671-9" />
<stop
style="stop-color:#ffed00;stop-opacity:1;"
offset="1"
id="stop3673-1" />
</linearGradient>
<linearGradient
gradientTransform="matrix(0.73872768,0,0,1.3536788,-2.25,-1.9999999)"
y2="1.8468192"
x2="48.259949"
y1="33.61211"
x1="34.290413"
gradientUnits="userSpaceOnUse"
id="linearGradient3698-9"
xlink:href="#linearGradient3669-0"
inkscape:collect="always" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3602-58-5"
id="linearGradient4030-1"
x1="42.239037"
y1="23.095947"
x2="36.44146"
y2="21.198208"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient3602-58-5">
<stop
style="stop-color:#d82b1e;stop-opacity:1;"
offset="0"
id="stop3604-2-5" />
<stop
style="stop-color:#840000;stop-opacity:1;"
offset="1"
id="stop3606-2-4" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3602-58-50"
id="linearGradient4030-6"
x1="42.239037"
y1="23.095947"
x2="36.44146"
y2="21.198208"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient3602-58-50">
<stop
style="stop-color:#d82b1e;stop-opacity:1;"
offset="0"
id="stop3604-2-8" />
<stop
style="stop-color:#840000;stop-opacity:1;"
offset="1"
id="stop3606-2-2" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3602-58"
id="linearGradient4086"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.2297854,-0.03462374,-0.36744124,0.55635649,-6.3422889,4.2186912)"
x1="73.638847"
y1="24.203213"
x2="40.176445"
y2="14.684779" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3669-3"
id="linearGradient4329-0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.81731796,0,0,1.9288701,-2.7299862,-14.350362)"
x1="78.740204"
y1="21.910299"
x2="70.337143"
y2="24.084332" />
<linearGradient
id="linearGradient3669-3">
<stop
style="stop-color:#001ccc;stop-opacity:1;"
offset="0"
id="stop3671-2" />
<stop
style="stop-color:#00afff;stop-opacity:1;"
offset="1"
id="stop3673-2" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3669-22-5"
id="linearGradient3675-0-5"
x1="34.290413"
y1="33.61211"
x2="48.259949"
y2="1.8468192"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.4976911,0,0,1.0526203,-3.6955244,-10.60101)" />
<linearGradient
id="linearGradient3669-22-5">
<stop
style="stop-color:#af7d00;stop-opacity:1;"
offset="0"
id="stop3671-8-3" />
<stop
style="stop-color:#ffed00;stop-opacity:1;"
offset="1"
id="stop3673-4-0" />
</linearGradient>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="8.5762527"
inkscape:cx="24.289382"
inkscape:cy="23.529886"
inkscape:current-layer="text3796"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="1280"
inkscape:window-height="964"
inkscape:window-x="-2"
inkscape:window-y="-3"
inkscape:window-maximized="1" />
<metadata
id="metadata2821">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<g
transform="scale(0.73872768,1.3536788)"
style="font-size:54.21519089000000236px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#ff2600;fill-opacity:1;stroke:#731200;font-family:Arial;-inkscape-font-specification:Arial;color:#000000;fill-rule:nonzero;stroke-width:2.19132471;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="text3796">
<path
style="fill:#006dff;fill-opacity:1;stroke:#00064a;stroke-width:2.511;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="M 35.875,1.46875 C 23.796955,8.5932992 13.671794,15.531702 1.59375,22.65625 L 1.5262142,35.512284 25.146178,57.487034 C 38.295836,48.256178 49.93017,40.983609 62.53125,32.661357 L 62.5,20.375 z M 34.21875,11 c 0.944286,-0.02471 1.856367,0.01824 2.71875,0.125 5.174304,0.640572 8.736535,3.725759 8.625,8.125 C 45.413784,25.115665 38.743677,31.129674 30.71875,32.625 22.69382,34.120324 16.351286,30.584395 16.5,24.71875 16.648714,18.853088 23.256323,12.807817 31.28125,11.3125 32.284366,11.125586 33.274464,11.024709 34.21875,11 z"
transform="scale(1.3536788,0.73872768)"
id="path4322"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccsssssss" />
<path
style="fill:url(#linearGradient4086);fill-opacity:1;stroke:#ff2600;stroke-width:1.88300000000000001;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
d="M 47.422587,7.4666373 C 37.741692,7.3258328 25.165048,9.4019748 21.63491,15.803574 c -1.782129,3.231735 1.883355,8.564261 11.619402,8.710079 -1.470251,-1.63897 -1.850349,-3.829208 -0.09522,-5.653618 1.616533,-1.680347 4.876995,-4.337842 13.919647,-4.950527 4.265983,-0.289042 13.824866,0.839183 14.118979,2.693386 4.214064,-4.85183 -1.391358,-8.95614 -13.775129,-9.1362567 z"
id="path4020"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sscsscs" />
<path
style="font-size:54.21519089px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;color:#000000;fill:#000fb4;fill-opacity:1;fill-rule:nonzero;stroke:#00064a;stroke-width:2.51117516;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Arial;-inkscape-font-specification:Arial"
d="m 34.56101,32.350098 c -0.0147,4.214125 -0.07684,4.086221 -0.3698,9.962925 17.800417,-6.819089 33.707407,-11.674718 50.765217,-17.822596 l -0.0423,-9.076272 c -20.77416,6.613084 -26.37193,8.571552 -50.353117,16.935943 z"
id="path4322-5"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="fill:none;stroke:#00064a;stroke-width:2.51117516000000007;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;fill-opacity:1"
d="M 2.1232553,17.121812 C 12.690909,21.90558 23.498028,27.192766 34.065684,31.976533 l -0.13172,10.175684"
id="path3677"
sodipodi:nodetypes="ccc"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#ff2600;stroke-width:2.6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 24.019815,32.984123 c 7.913576,0.167149 16.463578,-1.446885 21.454591,-11.426902"
id="path4621"
inkscape:connector-curvature="0"
transform="scale(1.3536788,0.73872768)"
sodipodi:nodetypes="cc" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 23 KiB

View File

@ -0,0 +1,450 @@
# -*- coding: iso-8859-15 -*-
#/******************************************************************************
# * Copyright (c)2012 Jan Rheinlaender <jrheinlaender@users.sourceforge.net> *
# * *
# * 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 *
# * *
# ******************************************************************************/
import FreeCAD
"Standards for bore hole feature"
sources = {
"inet_arcor" : "http://home.arcor.de/maschinenelemente2-din/DIN%20EN%2020273_Durchgangsl%F6cher%20fuer%20Schrauben.PDF",
"inet_duckma" : "http://www.duckma.de/mb14/SiteDocs/DIN%20Grundlagen%20Maschinenbau.pdf",
"klein_14" : "Klein: Einführung in die DIN-Normen, 14. Auflage. Stuttgart, Teubner 2008"
}
StandardYear = 0
StandardTitle = 1
StandardSource = 2
StandardType = 3
standards = {
# "Standard name" : ("Year", "Title", "Source", "Type")
"DIN 13-1" : ("1999", "Metrisches ISO-Gewinde allgemeiner Anwendung (Auszug); Nennmaße für Regelgewinde", "klein_14", "thread"),
"DIN 74-A" : ("2003", "Senkungen fur Senkschrauben, ausgenommen Senkschrauben mit Kopfen nach DIN EN 27721; Form A", "klein_14", "countersink"),
"DIN 74-E" : ("2003", "Senkungen fur Senkschrauben, ausgenommen Senkschrauben mit Kopfen nach DIN EN 27721; Form E", "klein_14", "countersink"),
"DIN 74-F" : ("2003", "Senkungen fur Senkschrauben, ausgenommen Senkschrauben mit Kopfen nach DIN EN 27721; Form F", "klein_14", "countersink"),
"DIN 76-2" : ("1984", "Gewindeausläufe und Gewindefreistiche (Auszug); für Metrisches ISO-Gewinde nach DIN 13; Innengewinde (Gewindegrundlöcher)", "klein_14", "threaded"),
"DIN 974-1" : ("1991", "Senkdurchmesser für Schrauben mit Zylinderkopf; Konstruktionsmaße (Auszug)", "klein_14", "counterbore"),
"DIN 974-2" : ("1991", "Senkdurchmesser fur Sechskantschrauben und Sechskantmuttern; Konstruktionsmaße(Auszug)", "klein_14", "counterbore"),
"ISO 273" : ("1979", "Fasteners; Clearance holes for bolts and screws", "inet_arcor", "through"),
"ISO 15065" : ("2005", "Senkungen fur Senkschrauben mit Kopfform nach ISO 7721", "klein_14", "countersink")
}
aliases = {
"ISO 273" : ("ISO 273:1979", "EN 20273:1991", "DIN EN 20273:1992", "DIN ISO 273", "DIN ISO 273/09.79"),
"ISO 15065" : ("ISO 15065:2005", "EN ISO 15065", "EN ISO 15065:2005", "DIN EN ISO 15065")
}
standards_tolerance = ("fine", "medium", "coarse")
standards_through = {
# "Standard name" : (Thread_dia : Hole_dia(Fine, Medium, Coarse))
"ISO 273" : {
1.0 : (1.1, 1.2, 1.3),
1.2 : (1.3, 1.4, 1.5),
1.4 : (1.5, 1.6, 1.8),
1.6 : (1.7, 1.8, 2.0),
1.8 : (2.0, 2.1, 2.2),
2.0 : (2.2, 2.4, 2.6),
2.5 : (2.7, 2.9, 3.1),
3.0 : (3.2, 3.4, 3.6),
3.5 : (3.7, 3.9, 4.2),
4.0 : (4.3, 4.5, 4.8),
4.5 : (4.8, 5.0, 5.3),
5.0 : (5.3, 5.5, 5.8),
6.0 : (6.4, 6.6, 7.0),
7.0 : (7.4, 7.6, 8.0),
8.0 : (8.4, 9.0, 10),
10.0: (10.5, 11, 12),
12.0: (13, 13.5, 14.5),
14.0: (15, 15.5, 16.5),
16.0: (17, 17.5, 18.5),
18.0: (19, 20, 21),
20.0: (21, 22, 24),
22.0: (23, 24, 26),
24.0: (25, 26, 28),
27.0: (28, 30, 32),
30.0: (31, 33, 35),
33.0: (34, 36, 38),
36.0: (37, 39, 42),
39.0: (40, 42, 45),
42.0: (43, 45, 48),
45.0: (46, 48, 52),
48.0: (50, 52, 56),
52.0: (54, 56, 62),
56.0: (58, 62, 66),
60.0: (62, 66, 70),
64.0: (66, 70, 74),
68.0: (70, 74, 80),
72.0: (74, 78, 82),
76.0: (78, 82, 86),
80.0: (82, 86, 91),
85.0: (87, 91, 96),
90.0: (93, 96, 101),
95.0: (98, 101, 107),
100.0: (104, 107, 112),
105.0: (109, 112, 117),
110.0: (114, 117, 121),
115.0: (119, 122, 127),
120.0: (124, 127, 132),
125.0: (129, 132, 137),
130.0: (134, 137, 144),
140.0: (144, 147, 155),
150.0: (155, 158, 165)
}
}
standards_counterbore = {
# "Standard name" : {Thread_dia : counterboredia(row1, row2, row3, row4, row5, row6)}
"DIN 974-1" : {
1.0 : (2.2, None, None, None, None, None),
1.2 : (2.5, None, None, None, None, None),
1.4 : (3.0, None, None, None, None, None),
1.6 : (3.5, 3.5, None, None, None, None),
1.8 : (3.8, None, None, None, None, None),
2.0 : (4.4, 5.0, None, 5.5, 6, 6),
2.5 : (5.5, 6, None, 6, 7, 7),
3.0 : (6.5, 7, 6.5, 7, 9, 8),
3.5 : (6.5, 8, 6.5, 8, 9, 9),
4.0 : (8, 9, 8, 9, 10, 10),
5.0 : (10, 11, 10, 11, 13, 13),
6.0 : (11, 13, 11, 13, 15, 15),
8.0 : (15, 18, 15, 16, 18, 20),
10.0 : (18, 24, 18, 20, 24, 24),
12.0 : (20, None, 20, 24, 26, 33),
14.0 : (24, None, 24, 26, 30, 40),
16.0 : (26, None, 26, 30, 33, 43),
18.0 : (30, None, 30, 33, 36, 46),
20.0 : (33, None, 33, 36, 40, 48),
22.0 : (36, None, 36, 40, 43, 54),
24.0 : (40, None, 40, 43, 48, 58),
27.0 : (46, None, 46, 46, 54, 63),
30.0 : (50, None, 50, 54, 61, 73),
33.0 : (54, None, 54, None, 63, None),
36.0 : (58, None, 58, 63, 69, None),
42.0 : (69, None, 69, 73, 82, None),
48.0 : (78, None, 78, 82, 98, None),
56.0 : (93, None, 93, 93, 112, None),
64.0 : (107, None, 107, 107, 125, None),
72.0 : (118, None, 118, 118, 132, None),
80.0 : (132, None, 132, 132, 150, None),
90.0 : (145, None, 145, 145, 170, None),
100.0:(160, None, 160, 160, 182, None)
},
"DIN 974-2" : {
3.0 : (11, 11, 9),
4.0 : (13, 15, 10),
5.0 : (15, 18, 11),
6.0 : (18, 20, 13),
8.0 : (24, 26, 18),
10.0:(28, 33, 22),
12.0:(33, 36, 26),
14.0:(36, 43, 30),
16.0:(40, 46, 33),
18.0:(43, 50, 36),
20.0:(46, 54, 40),
22.0:(54, 61, 46),
24.0:(58, 73, 48),
27.0:(61, 76, 54),
30.0:(73, 82, 61),
33.0:(76, 89, 69),
36.0:(82, 93, 73),
39.0:(89, 98, 76),
42.0:(98, 107, 82),
45.0:(107, 112, 89)
}
}
standards_counterbore_through = {
# Standard name : Through hole standard name
"DIN 74-A" : "ISO 273",
"DIN 74-E" : "ISO 273", # Note that the standards seems to allow tolerance class "fine" only
"DIN 74-F" : "ISO 273",
"DIN 974-1" : "ISO 273",
"DIN 974-2" : "ISO 273",
"ISO 15065" : "ISO 273"
}
standards_counterbore_rows = {
# Row index : ( extra standards e.g. bolt used or washer used )
# Note that DIN 7980 has been cancelled, therefore row three should not be used any more
"DIN 974-1" : {
1 : ("ISO 1207", "ISO 4762", "DIN 6912", "DIN 7984"),
2 : ("ISO 1580", "ISO 7045"),
3 : ("DIN 7980", ""), # single value gives wrong iteration when collecting the standards
4 : ("ISO 10673 type C", "DIN 6798", "DIN 6907"),
5 : ("ISO 7089", "ISO 7090", "ISO 10673 type A"),
6 : ("DIN 6796", "DIN 6908")
},
"DIN 974-2" : {
1 : ("DIN 659", "DIN 896", "DIN 3112", "DIN 3124"),
2 : ("DIN 838", "DIN 897", "DIN 3129"),
3 : ("tight", "")
}
}
standards_counterbore_extradepth = {
# max Thread diameter : extra depth
1.4 : 0.2,
6.0 : 0.4,
20.0 : 0.6,
27.0 : 0.8,
100.0 : 1.0
}
standards_countersink_dia = 0
standards_countersink_angle = 1
standards_countersink = {
# "Standard name" : {Thread_dia : (countersinkdia, head angle)}
"DIN 74-A" : {
1.6 : (3.7, 90.0),
2.0 : (4.6, 90.0),
2.5 : (5.7, 90.0),
3.0 : (6.5, 90.0),
3.5 : (7.6, 90.0),
4.0 : (8.6, 90.0),
4.5 : (9.5, 90.0),
5.0 : (10.4, 90.0),
5.5 : (11.4, 90.0),
6.0 : (12.4, 90.0),
7.0 : (14.4, 90.0),
8.0 : (16.4, 90.0)
},
"DIN 74-E" : {
10.0 : (19.0, 75.0),
12.0 : (24.0, 75.0),
16.0 : (31.0, 75.0),
20.0 : (34.0, 60.0),
22.0 : (37.0, 60.0),
24.0 : (40.0, 60.0)
},
"DIN 74-F" : {
3.0 : (6.94, 90.0),
4.0 : (9.18, 90.0),
5.0 : (11.47, 90.0),
6.0 : (13.71, 90.0),
8.0 : (18.25, 90.0),
10.0 : (22.73, 90.0),
12.0 : (27.21, 90.0),
14.0 : (31.19, 90.0),
16.0 : (33.39, 90.0),
20.0 : (40.71, 90.0)
},
"ISO 15065" : {
2.0 : (4.4, 90.0),
3.0 : (6.3, 90.0),
4.0 : (9.4, 90.0),
5.0 : (0.4, 90.0),
6.0 : (12.6, 90.0),
8.0 : (17.3, 90.0),
10.0 : (20.0, 90.0)
}
}
standards_threaded_types = ("normal", "short", "long")
standards_threaded = {
# Standard name : { Tread pitch : threadFinish(normal, short, long) }
"DIN 76-2" : {
0.20 : (1.3, 0.8, 2.0),
0.25 : (1.5, 1.0, 2.4),
0.30 : (1.8, 1.2, 2.9),
0.35 : (2.1, 1.3, 3.3),
0.40 : (2.3, 1.5, 3.7),
0.45 : (2.6, 1.6, 4.1),
0.50 : (2.8, 1.8, 4.5),
0.60 : (3.4, 2.1, 5.4),
0.70 : (3.8, 2.4, 6.1),
0.75 : (4.0 , 2.5, 6.4),
0.80 : (4.2, 2.7, 6.8),
1.00 : (5.1, 3.2, 8.2),
1.25 : (6.2, 3.9, 10),
1.5 : (7.3, 4.6, 11.6),
1.75 : (8.3, 5.2, 13.3),
2.0 : (9.3, 5.8, 14.8),
2.5 : (11.2, 7.0, 17.9),
3.0 : (13.1, 8.2, 21.0),
3.5 : (15.2, 9.5, 24.3),
4.0 : (16.8, 10.5, 26.9),
4.5 : (18.4, 11.5, 29.4),
5.0 : (20.8, 13.0, 33.3),
5.5 : (22.4, 14.0, 35.8),
6.0 : (24.0, 15, 38.4)
}
}
standards_threaded_thread = {
# Standard name for thread attribute : standard name for thread }
"DIN 76-2" : "DIN 13-1"
}
standards_thread_pitch = 0
standards_thread_flankdia = 1
standards_thread_outercoredia = 2
standards_thread_innercoredia = 3
standards_thread_outerdepth = 4
standards_thread_innerdepth = 5
standards_thread_round = 6
standards_thread = {
# Standard name : { Thread diameter : (pitch, flank diameter, core diameter, thread depth outer, thread depth inner, round) }
# Note: This table only has the most common thread diameters
"DIN 13-1" : {
1.0 : (0.25, 0.838, 0.693, 0.729, 0.153, 0.135, 0.036),
1.1 : (0.25, 0.938, 0.793, 0.829, 0.153, 0.135, 0.036),
1.2 : (0.25, 1.038, 0.893, 0.929, 0.153, 0.135, 0.036),
2.0 : (0.4, 1.740, 1.509, 1.567, 0.245, 0.217, 0.058),
3.0 : (0.5, 2.675, 2.387, 2.459, 0.307, 0.271, 0.072),
4.0 : (0.7, 3.545, 3.141, 3.242, 0.429, 0.379, 0.101 ),
5.0 : (0.8, 4.480, 4.019, 4.134, 0.491, 0.433, 0.115),
6.0 : (1.0, 5.350, 4.773, 4.917, 0.613, 0.541, 0.144),
7.0 : (1.0, 6.350, 5.773, 5.917, 0.613, 0.541, 0.144),
8.0 : (1.25, 7.188, 6.466, 6.647, 0.767, 0.677, 0.180),
10.0 : (1.5, 9.026, 8.160, 8.376, 0.920, 0.812, 0.217),
12.0 : (1.75, 10.863, 9.853, 10.106, 1.074, 0.947, 0.253),
14.0 : (2.0, 12.701, 11.546, 11.835, 1.227, 1.083, 0.289),
16.0 : (2.0, 14.701, 13.546, 13.835, 1.227, 1.083, 0.289),
18.0 : (2.5, 16.376, 14.933, 15.294, 1.534, 1.353, 0.361),
20.0 : (2.5, 18.376, 16.933, 17.294, 1.534, 1.353, 0.361),
22.0 : (2.5, 20.376, 18.933, 19.294, 1.534, 1.353, 0.361),
24.0 : (3.0, 22.051, 20.319, 20.752, 1.840, 1.624, 0.433),
27.0 : (3.0, 25.051, 23.319, 23.752, 1.840, 1.624, 0.433),
30.0 : (3.5, 27.727, 25.706, 26.211, 2.147, 1.894, 0.505),
33.0 : (3.5, 30.727, 28.706, 29.211, 2.147, 1.894, 0.505),
36.0 : (4.0, 33.402, 31.093, 31.670, 2.454, 2.165, 0.577),
39.0 : (4.0, 36.402, 34.093, 34.670, 2.454, 2.165, 0.577),
42.0 : (4.5 , 39.077, 36.479, 37.129, 2.760, 2.436, 0.650),
45.0 : (4.5, 42.077, 39.479, 40.129, 2.760, 2.436, 0.650)
}
}
def getStandards(holetype):
"Return the names of all available standards for the given hole type"
result = []
for key, value in standards.items():
if value[StandardType] == holetype:
result.append(key)
#FreeCAD.Console.PrintMessage("Number of matching standards: " + str(len(result)) + "\n")
return sorted(result)
def getBaseDiameters(standard):
"Return the base diameters of all holes defined in the given norm"
if not standard in standards.keys():
return []
#FreeCAD.Console.PrintMessage("Getting diameters for " + standard + "\n")
if standards[standard][StandardType] == "through":
return standards_through[standard].keys()
elif standards[standard][StandardType] == "counterbore":
return standards_counterbore[standard].keys()
elif standards[standard][StandardType] == "countersink":
return standards_countersink[standard].keys()
elif standards[standard][StandardType] == "thread":
return standards_thread[standard].keys()
return []
def getThroughHoleDia(standard, threadDia, tolerance = "medium"):
if not standard in standards_through.keys():
raise Exception("No such standard exists")
values = standards_through[standard]
if not threadDia in values:
FreeCAD.Console.PrintMessage("Warning: Diameter %f is not in %s" % (threadDia, standard))
return values[values.keys()[0]][standards_tolerance.index(tolerance)]
return values[threadDia][standards_tolerance.index(tolerance)]
def getThroughHoleStandard(standard):
if not standard in standards_counterbore_through.keys():
raise Exception("No such standard exists")
return standards_counterbore_through[standard]
def getCounterboreDia(standard, threadDia, extraStandard = ""):
if not standard in standards_counterbore.keys():
raise Exception("No such standard exists")
values = standards_counterbore[standard]
if not threadDia in values:
FreeCAD.Console.PrintMessage("Warning: Diameter %f is not in %s" % (threadDia, standard))
return values[values.keys()[0]][0]
row = 1 # Use row 1 by default
for r in standards_counterbore_rows[standard].keys():
if extraStandard in standards_counterbore_rows[standard][r]:
row = r
break
return values[threadDia][row-1]
def calcCounterboreDepth(standard, threadDia, standardBolt, standardsWashers = []):
headHeight = getBoltHead(standardBolt)
washerHeight = 0.0
for standard in standardsWashers:
washerHeight = washerHeight + getWasherHeight(standard)
for maxThread in reverse(standards_counterbore_extradepth.keys()):
if threadDia <= maxThread:
extraDepth = standards_counterbore_extradepth[maxThread]
return headHeight + washerHeight + extraDepth
def getRowStandards(standard):
if not standard in standards_counterbore_rows.keys():
raise Exception("No such standard exists")
result = []
rowdict = standards_counterbore_rows[standard]
for stds in rowdict.values():
for std in stds:
if std != "":
result.append(std)
return result
def getCountersinkDia(standard, threadDia):
if not standard in standards_countersink.keys():
raise Exception("No such standard exists")
values = standards_countersink[standard]
if not threadDia in values:
FreeCAD.Console.PrintMessage("Warning: Diameter %f is not in %s" % (threadDia, standard))
return values[values.keys()[0]][standards_countersink_dia]
return values[threadDia][standards_countersink_dia]
def getCountersinkAngle(standard, threadDia):
if not standard in standards_countersink.keys():
raise Exception("No such standard exists")
values = standards_countersink[standard]
if not threadDia in values:
FreeCAD.Console.PrintMessage("Warning: Diameter %f is not in %s" % (threadDia, standard))
return values[values.keys()[0]][standards_countersink_angle]
return values[threadDia][standards_countersink_angle]
def getThreadCoreDiameter(standard, threadDia):
if not standard in standards_thread.keys():
raise Exception("No such standard exists")
values = standards_thread[standard]
if not threadDia in values:
FreeCAD.Console.PrintMessage("Warning: Diameter %f is not in %s" % (threadDia, standard))
return values[values.keys()[0]][standards_thread_innercoredia]
return values[threadDia][standards_thread_innercoredia]
def getThreadFinishLength(standard, threadDia, length = "normal"):
if not standard in standards_threaded.keys():
raise Exception("No such standard exists")
stdThread = standards_threaded_thread[standard]
values = standards_thread[stdThread]
if not threadDia in values:
FreeCAD.Console.PrintMessage("Warning: Diameter %f is not in %s" % (threadDia, standard))
return values[values.keys()[0]][standards_thread_pitch]
pitch = values[threadDia][standards_thread_pitch]
return standards_threaded[standard][pitch][standards_threaded_types.index(length)]

View File

@ -0,0 +1,659 @@
#/******************************************************************************
# * Copyright (c)2012 Jan Rheinlaender <jrheinlaender@users.sourceforge.net> *
# * *
# * 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 *
# * *
# ******************************************************************************/
import FreeCAD, FreeCADGui
import Part, PartDesignGui
from PyQt4 import QtCore, QtGui
import Standards
import os
class TaskHole:
"Hole hole feature"
types = ["Linear", "Coaxial"]
typestr = ["Linear to two lines/planes", "Coaxial to a circle/cylinder"]
def __init__(self, feature):
self.form = None
self.extraStandards = []
self.feature = feature
p=os.path.realpath(__file__)
p=os.path.dirname(p)
self.ui = os.path.join(p, "TaskHole.ui")
def accept(self):
self.feature.touch()
FreeCAD.ActiveDocument.recompute()
FreeCADGui.ActiveDocument.resetEdit()
return True
def reject(self):
if (self.feature != None):
self.hideFeature() # Show the support again
document = self.feature.Document
body = PartDesignGui.getActivePart()
groove = self.feature.HoleGroove
sketch = groove.Sketch
plane = sketch.Support[0]
axis = plane.References[0][0]
body.removeFeature(self.feature)
document.removeObject(self.feature.Name)
body.removeFeature(groove)
document.removeObject(groove.Name)
body.removeFeature(sketch)
try:
document.removeObject(sketch.Name)
except:
pass # This always throws an exception: "Sketch support has been deleted" from SketchObject::execute()
body.removeFeature(plane)
document.removeObject(plane.Name)
body.removeFeature(axis)
document.removeObject(axis.Name)
FreeCADGui.ActiveDocument.resetEdit()
FreeCADGui.Control.closeDialog(self)
return True
def isAllowedAlterDocument(self):
return False
def isAllowedAlterView(self):
return False
def isAllowedAlterSelection(self):
return True
def getMainWindow(self):
"returns the main window"
# using QtGui.qApp.activeWindow() isn't very reliable because if another
# widget than the mainwindow is active (e.g. a dialog) the wrong widget is
# returned
toplevel = QtGui.qApp.topLevelWidgets()
for i in toplevel:
if i.metaObject().className() == "Gui::MainWindow":
return i
raise Exception("No main window found")
def setupUi(self):
mw = self.getMainWindow()
form = mw.findChild(QtGui.QWidget, "TaskHole")
if form == None:
return
form.tabWidget = form.findChild(QtGui.QTabWidget, "tabWidget")
# Type
form.tabType = form.tabWidget.findChild(QtGui.QWidget, "tab_type")
form.buttonThru = form.tabType.findChild(QtGui.QRadioButton, "buttonThru")
form.buttonDepth = form.tabType.findChild(QtGui.QRadioButton, "buttonDepth")
form.checkThreaded = form.tabType.findChild(QtGui.QCheckBox, "checkThreaded")
form.checkCounterbore = form.tabType.findChild(QtGui.QCheckBox, "checkCounterbore")
form.checkCountersink = form.tabType.findChild(QtGui.QCheckBox, "checkCountersink")
# Norm
form.tabNorm = form.tabWidget.findChild(QtGui.QWidget, "tab_norm")
form.checkCustom = form.tabNorm.findChild(QtGui.QCheckBox, "checkCustom")
form.comboNorm = form.tabNorm.findChild(QtGui.QComboBox, "comboNorm")
for std in Standards.getStandards("through"):
form.comboNorm.addItem(std)
form.comboTolerance = form.tabNorm.findChild(QtGui.QComboBox, "comboTolerance")
for tol in Standards.standards_tolerance:
form.comboTolerance.addItem(tol)
form.comboNormDia = form.tabNorm.findChild(QtGui.QComboBox, "comboNormDia")
form.comboNormBoltWasher = form.tabNorm.findChild(QtGui.QComboBox, "comboNormBoltWasher")
# Thread
form.tabThread = form.tabWidget.findChild(QtGui.QWidget, "tab_thread")
form.comboThreadNorm = form.tabThread.findChild(QtGui.QComboBox, "comboThreadNorm")
for std in Standards.getStandards("thread"):
form.comboThreadNorm.addItem(std)
form.comboThreadDia = form.tabThread.findChild(QtGui.QComboBox, "comboThreadDia")
form.checkCustomThreadLength = form.tabThread.findChild(QtGui.QCheckBox, "checkCustomThreadLength")
form.comboFinishNorm = form.tabThread.findChild(QtGui.QComboBox, "comboFinishNorm")
for std in Standards.getStandards("threaded"):
form.comboFinishNorm.addItem(std)
# Data
form.tabData = form.tabWidget.findChild(QtGui.QWidget, "tab_data")
form.spinDiameter = form.tabData.findChild(QtGui.QDoubleSpinBox, "spinDiameter")
form.spinDepth = form.tabData.findChild(QtGui.QDoubleSpinBox, "spinDepth")
form.spinCounterboreDiameter = form.tabData.findChild(QtGui.QDoubleSpinBox, "spinCounterboreDiameter")
form.spinCounterboreDepth = form.tabData.findChild(QtGui.QDoubleSpinBox, "spinCounterboreDepth")
form.spinCountersinkAngle = form.tabData.findChild(QtGui.QDoubleSpinBox, "spinCountersinkAngle")
form.spinThreadLength = form.tabData.findChild(QtGui.QDoubleSpinBox, "spinThreadLength")
# Position
form.tabPosition = form.tabWidget.findChild(QtGui.QWidget, "tab_position")
form.comboType = form.tabPosition.findChild(QtGui.QComboBox, "comboType")
for i in self.typestr:
form.comboType.addItem(i)
form.buttonSupport = form.tabPosition.findChild(QtGui.QPushButton, "buttonSupport")
form.lineSupport = form.tabPosition.findChild(QtGui.QLineEdit, "lineSupport")
form.buttonRef1 = form.tabPosition.findChild(QtGui.QPushButton, "buttonRef1")
form.lineRef1 = form.tabPosition.findChild(QtGui.QLineEdit, "lineRef1")
form.labelRef1 = form.tabPosition.findChild(QtGui.QLabel, "labelRef1")
form.spinRef1 = form.tabPosition.findChild(QtGui.QDoubleSpinBox, "spinRef1")
form.buttonRef2 = form.tabPosition.findChild(QtGui.QPushButton, "buttonRef2")
form.lineRef2 = form.tabPosition.findChild(QtGui.QLineEdit, "lineRef2")
form.labelRef2 = form.tabPosition.findChild(QtGui.QLabel, "labelRef2")
form.spinRef2 = form.tabPosition.findChild(QtGui.QDoubleSpinBox, "spinRef2")
self.form = form
# Connect Signals and Slots
# Type
self.form.buttonThru.toggled.connect(self.buttonThru)
self.form.buttonDepth.toggled.connect(self.buttonDepth)
self.form.checkThreaded.toggled.connect(self.checkThreaded)
self.form.checkCounterbore.toggled.connect(self.checkCounterbore)
self.form.checkCountersink.toggled.connect(self.checkCountersink)
# Norm
self.form.checkCustom.toggled.connect(self.checkCustom)
self.form.comboNorm.currentIndexChanged.connect(self.comboNorm)
self.form.comboTolerance.currentIndexChanged.connect(self.comboTolerance)
self.form.comboNormDia.currentIndexChanged.connect(self.comboNormDia)
self.form.comboNormBoltWasher.currentIndexChanged.connect(self.comboNormBoltWasher)
# Thread
self.form.comboThreadNorm.currentIndexChanged.connect(self.comboThreadNorm)
self.form.comboThreadDia.currentIndexChanged.connect(self.comboThreadDia)
self.form.checkCustomThreadLength.toggled.connect(self.checkCustomThreadLength)
self.form.comboFinishNorm.currentIndexChanged.connect(self.comboFinishNorm)
# Data
self.form.spinDiameter.valueChanged.connect(self.spinDiameter)
self.form.spinDepth.valueChanged.connect(self.spinDepth)
self.form.spinCounterboreDiameter.valueChanged.connect(self.spinCounterboreDiameter)
self.form.spinCounterboreDepth.valueChanged.connect(self.spinCounterboreDepth)
self.form.spinCountersinkAngle.valueChanged.connect(self.spinCountersinkAngle)
self.form.spinThreadLength.valueChanged.connect(self.spinThreadLength)
# Position
self.form.comboType.currentIndexChanged.connect(self.comboType)
self.form.buttonSupport.clicked.connect(self.buttonSupport)
self.form.buttonRef1.clicked.connect(self.buttonRef1)
self.form.spinRef1.valueChanged.connect(self.spinRef1)
self.form.buttonRef2.clicked.connect(self.buttonRef2)
self.form.spinRef2.valueChanged.connect(self.spinRef2)
# Update the UI
self.updateUI()
def getRefText(self, ref):
(obj, element) = ref
if isinstance(element, basestring):
return obj.Name + ":" + element
elif isinstance(element, list):
return obj.Name + ":" + element[0]
else:
return obj.Name
def updateUI(self):
# Type
self.form.buttonThru.setChecked(self.feature.HoleType == "Thru")
self.form.buttonDepth.setChecked(self.feature.HoleType == "Depth")
self.form.checkThreaded.setChecked(self.feature.Threaded == True)
self.form.checkCounterbore.setChecked(self.feature.Counterbore == True)
self.form.checkCountersink.setChecked(self.feature.Countersink == True)
# Norm
if self.feature.Norm == "Custom":
self.form.checkCustom.setChecked(True)
self.form.comboNorm.setEnabled(False)
self.form.comboTolerance.setEnabled(False)
self.form.comboNormDia.setEnabled(False)
self.form.comboNormBoltWasher.setEnabled(False)
else:
if self.feature.Counterbore == True:
holetype = "counterbore"
elif self.feature.Countersink == True:
holetype = "countersink"
elif self.feature.Threaded == True:
holetype = "threaded"
else:
holetype = "through"
self.form.comboNorm.setEnabled(True)
self.form.comboTolerance.setEnabled(True)
self.form.comboNormDia.setEnabled(True)
if holetype == "counterbore":
self.form.comboNormBoltWasher.setEnabled(True)
else:
self.form.comboNormBoltWasher.setEnabled(False)
# comboNorm
standards = Standards.getStandards(holetype)
self.form.comboNorm.blockSignals(True)
self.form.comboNorm.clear()
for std in standards:
self.form.comboNorm.addItem(std)
if not self.feature.Norm in standards:
self.feature.Norm = standards[0]
else:
self.form.comboNorm.setCurrentIndex(standards.index(self.feature.Norm))
self.form.comboNorm.blockSignals(False)
# comboTolerance
self.form.comboTolerance.blockSignals(True)
self.form.comboTolerance.setCurrentIndex(Standards.standards_tolerance.index(self.feature.NormTolerance))
self.form.comboTolerance.blockSignals(False)
# comboNormDia
diameters = sorted(Standards.getBaseDiameters(self.feature.Norm))
self.form.comboNormDia.blockSignals(True)
self.form.comboNormDia.clear()
for dia in diameters:
self.form.comboNormDia.addItem("M%g" % dia)
if self.feature.NormDiameter in diameters:
self.form.comboNormDia.setCurrentIndex(diameters.index(self.feature.NormDiameter))
self.form.comboNormDia.blockSignals(False)
# comboNormBoltWasher
if holetype == "counterbore":
rowStandards = sorted(Standards.getRowStandards(self.feature.Norm))
self.form.comboNormBoltWasher.blockSignals(True)
self.form.comboNormBoltWasher.clear()
for std in rowStandards:
self.form.comboNormBoltWasher.addItem(std)
if self.feature.ExtraNorm in rowStandards:
self.form.comboNormBoltWasher.setCurrentIndex(rowStandards.index(self.feature.ExtraNorm))
self.form.comboNormBoltWasher.blockSignals(False)
# Dependent values
if holetype == "through":
self.feature.Diameter = Standards.getThroughHoleDia(self.feature.Norm, self.feature.NormDiameter, self.feature.NormTolerance)
elif holetype == "counterbore":
throughStandard = Standards.getThroughHoleStandard(self.feature.Norm)
self.feature.Diameter = Standards.getThroughHoleDia(throughStandard, self.feature.NormDiameter, self.feature.NormTolerance)
self.feature.CounterboreDiameter = Standards.getCounterboreDia(self.feature.Norm, self.feature.NormDiameter, self.feature.ExtraNorm)
# TODO: Calculate counter bore depth from standard for bolt and washer(s)
# Requires accessing all the norms for bolts
# self.feature.CounterboreDepth = calcCounterboreDepth(...)
elif holetype == "countersink":
throughStandard = Standards.getThroughHoleStandard(self.feature.Norm)
self.feature.Diameter = Standards.getThroughHoleDia(throughStandard, self.feature.NormDiameter, self.feature.NormTolerance)
self.feature.CounterboreDiameter = Standards.getCountersinkDia(self.feature.Norm, self.feature.NormDiameter)
self.feature.CountersinkAngle = Standards.getCountersinkAngle(self.feature.Norm, self.feature.NormDiameter) / 2.0
# Thread
if self.feature.Threaded == True:
if not self.feature.Counterbore and not self.feature.Countersink:
self.form.comboTolerance.setEnabled(False)
else:
self.form.tabNorm.setEnabled(True)
self.form.comboTolerance.setEnabled(False)
self.form.tabThread.setEnabled(True)
self.form.comboThreadNorm.blockSignals(True)
standards = Standards.getStandards("thread")
if not self.feature.NormThread in standards:
self.feature.NormThread = standards[0]
else:
self.form.comboThreadNorm.setCurrentIndex(standards.index(self.feature.NormThread))
self.form.comboThreadNorm.blockSignals(False)
threadDiameters = sorted(Standards.getBaseDiameters(self.feature.NormThread))
self.form.comboThreadDia.blockSignals(True)
self.form.comboThreadDia.clear()
for dia in threadDiameters:
self.form.comboThreadDia.addItem("M%g" % dia)
if self.feature.NormDiameter in threadDiameters:
self.form.comboThreadDia.setCurrentIndex(threadDiameters.index(self.feature.NormDiameter))
self.form.comboThreadDia.blockSignals(False)
if self.feature.NormThreadFinish == "Custom":
self.form.checkCustomThreadLength.setChecked(True)
self.form.comboFinishNorm.setEnabled(False)
else:
self.form.checkCustomThreadLength.setChecked(False)
self.form.comboFinishNorm.setEnabled(True)
self.form.comboFinishNorm.blockSignals(True)
standards = Standards.getStandards("threaded")
if not self.feature.NormThreadFinish in standards:
self.feature.NormThreadFinish = standards[0]
else:
self.form.comboFinishNorm.setCurrentIndex(standards.index(self.feature.NormThreadFinish))
self.form.comboFinishNorm.blockSignals(False)
flength = Standards.getThreadFinishLength(self.feature.NormThreadFinish, self.feature.NormDiameter)
tlength = self.feature.Depth - flength
if tlength > 0:
self.feature.ThreadLength = tlength # TODO: Warning message
# Dependents
self.feature.Diameter = Standards.getThreadCoreDiameter(self.feature.NormThread, self.feature.NormDiameter)
else:
self.form.tabThread.setEnabled(False)
# Dependents
self.form.spinDiameter.setEnabled(True)
# Data
self.form.spinDiameter.setValue(self.feature.Diameter)
self.form.spinDepth.setValue(self.feature.Depth)
if self.feature.HoleType == "Thru":
self.form.spinDepth.setEnabled(False)
else:
self.form.spinDepth.setEnabled(True)
if self.feature.Threaded == True:
self.form.spinThreadLength.setEnabled(True)
else:
self.form.spinThreadLength.setEnabled(False)
if self.feature.Counterbore == True:
self.form.spinCounterboreDiameter.setEnabled(True)
self.form.spinCounterboreDiameter.setValue(self.feature.CounterboreDiameter)
self.form.spinCounterboreDepth.setEnabled(True)
self.form.spinCounterboreDepth.setValue(self.feature.CounterboreDepth)
self.form.spinCountersinkAngle.setEnabled(False)
elif self.feature.Countersink == True:
self.form.spinCounterboreDiameter.setEnabled(True)
self.form.spinCounterboreDiameter.setValue(self.feature.CounterboreDiameter)
self.form.spinCounterboreDepth.setEnabled(False)
self.form.spinCountersinkAngle.setEnabled(True)
self.form.spinCountersinkAngle.setValue(self.feature.CountersinkAngle)
else:
self.form.spinCounterboreDiameter.setEnabled(False)
self.form.spinCounterboreDepth.setEnabled(False)
self.form.spinCountersinkAngle.setEnabled(False)
if self.feature.Norm == "Custom":
self.form.spinDiameter.setEnabled(True)
else:
self.form.spinDiameter.setEnabled(False)
if holetype == "counterbore":
# Diameter is taken from Norm
self.form.spinCounterboreDiameter.setEnabled(False)
elif holetype == "countersink":
# Values are taken from Norm
self.form.spinCounterboreDiameter.setEnabled(False)
self.form.spinCounterboreDepth.setEnabled(False)
self.form.spinCountersinkAngle.setEnabled(False)
if self.feature.Threaded == True:
self.form.spinDiameter.setEnabled(False)
if self.feature.NormThreadFinish != "Custom":
self.form.spinThreadLength.setEnabled(False)
self.form.spinThreadLength.setValue(self.feature.ThreadLength)
# Position
self.form.buttonSupport.setText("Face")
if self.feature.Support == None:
# First-time initialization
selection = FreeCADGui.Selection.getSelectionEx()
self.feature.Support = (selection[0].Object, selection[0].SubElementNames)
self.form.lineSupport.setText(self.getRefText(self.feature.Support))
if self.feature.PositionType == self.types[0]:
# Linear
self.form.buttonRef1.setText("Line/Plane")
self.form.buttonRef1.setEnabled(True)
self.form.buttonRef2.setText("Line/Plane")
self.form.buttonRef2.setEnabled(True)
self.form.lineRef1.setEnabled(True)
self.form.lineRef2.setEnabled(True)
self.form.labelRef1.setEnabled(True)
self.form.labelRef1.setText("Distance")
axis = self.feature.HoleGroove.Sketch.Support[0].References[0][0]
if len(axis.References) > 0 and axis.References[0] != None:
if (len(axis.References) == 3):
self.form.lineRef1.setText(self.getRefText(axis.References[1]))
else:
self.form.lineRef1.setText(self.getRefText(axis.References[0]))
self.form.spinRef1.setEnabled(True)
self.form.spinRef1.setValue(axis.Offset)
self.form.labelRef2.setEnabled(True)
self.form.labelRef2.setText("Distance")
if len(axis.References) > 1 and axis.References[1] != None:
if (len(axis.References) == 3):
self.form.lineRef2.setText(self.getRefText(axis.References[2]))
else:
self.form.lineRef2.setText(self.getRefText(axis.References[1]))
self.form.spinRef2.setEnabled(True)
self.form.spinRef2.setValue(axis.Offset2)
elif self.feature.PositionType == self.types[1]:
# Coaxial
self.form.buttonRef1.setText("Circle/Cylinder")
self.form.buttonRef1.setEnabled(True)
self.form.buttonRef2.setEnabled(False)
self.form.lineRef1.setEnabled(True)
axis = self.feature.HoleGroove.Sketch.Support[0].References[0][0]
if len(axis.References) > 0 and axis.References[0] != None:
self.form.lineRef1.setText(self.getRefText(axis.References[0]))
self.form.lineRef2.setEnabled(False)
self.form.labelRef1.setEnabled(False)
self.form.spinRef1.setEnabled(False)
self.form.labelRef2.setEnabled(False)
self.form.spinRef2.setEnabled(False)
else:
# Nothing else defined yet
pass
def getStandardButtons(self):
return int(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
def accept(self):
return True
def buttonThru(self, toggle):
if toggle == True:
self.feature.HoleType = "Thru"
def buttonDepth(self, toggle):
if toggle == True:
self.feature.HoleType = "Depth"
def checkThreaded(self, checked):
self.feature.Threaded = checked
self.updateUI()
def checkCounterbore(self, checked):
if checked == True:
self.feature.Countersink = False
self.feature.Counterbore = checked
self.updateUI()
def checkCountersink(self, checked):
if checked == True:
self.feature.Counterbore = False
self.feature.Countersink = checked
self.updateUI()
def checkCustom(self, checked):
if checked == True:
self.feature.Norm = "Custom"
else:
self.feature.Norm = str(self.form.comboNorm.currentText())
self.updateUI()
def comboNorm(self, index):
self.feature.Norm = str(self.form.comboNorm.itemText(index))
self.updateUI()
def comboTolerance(self, index):
self.feature.NormTolerance = str(self.form.comboTolerance.itemText(index))
self.updateUI()
def comboNormDia(self, index):
diameter = str(self.form.comboNormDia.itemText(index))
self.feature.NormDiameter = float(diameter[1:])
self.updateUI()
def comboNormBoltWasher(self, index):
self.feature.ExtraNorm = str(self.form.comboNormBoltWasher.itemText(index))
self.updateUI()
def comboThreadNorm(self, index):
self.feature.NormThread = str(self.form.comboThreadNorm.itemText(index))
self.updateUI()
def comboThreadDia(self, index):
diameter = str(self.form.comboThreadDia.itemText(index))
self.feature.NormDiameter = float(diameter[1:])
self.updateUI()
def checkCustomThreadLength(self, checked):
if checked == True:
self.feature.NormThreadFinish = "Custom"
else:
self.feature.NormThreadFinish = str(self.form.comboFinishNorm.currentText())
self.updateUI()
def comboFinishNorm(self, index):
self.feature.NormThreadFinish = str(self.form.comboFinishNorm.itemText(index))
self.updateUI()
def spinDiameter(self, val):
if (val > 0.0):
self.feature.Diameter = val
def spinDepth(self, val):
if (val > 0.0):
self.feature.Depth = val
self.updateUI() # required to update the thread length
def spinCounterboreDiameter(self, val):
if (val > self.feature.Diameter):
self.feature.CounterboreDiameter = val
def spinCounterboreDepth(self, val):
if (val > 0.0):
self.feature.CounterboreDepth = val
def spinCountersinkAngle(self, val):
if (val > 0.0):
self.feature.CountersinkAngle = val
def spinThreadLength(self, val):
if (val > 0.0):
self.feature.ThreadLength = val
def comboType(self, index):
self.feature.PositionType = self.types[index]
self.updateUI()
def addSelection(self, document, obj, element, position):
#FreeCAD.Console.PrintMessage("AddSelection() for " + document + "." + obj + "." + element + "\n")
# TODO: What is the position parameter?
if document == self.feature.Document.Name:
axis = self.feature.HoleGroove.Sketch.Support[0].References[0][0]
refs = axis.References
feature = eval("FreeCAD.getDocument('" + document + "')." + obj)
shape = eval("feature.Shape." + element)
if self.selectionMode == "Plane":
if shape.Surface.__class__ != Part.Plane:
FreeCAD.Console.PrintMessage("Selected face must be planar\n")
return
if self.feature.PositionType == self.types[0]:
# The Hole support is also the first reference of the sketch axis in Linear mode with edges selected
if len(refs) == 3:
refs[0] = (feature, element)
axis.References = refs
self.feature.Support = (feature, [element])
elif self.selectionMode == "LinearReference":
if shape.ShapeType == "Edge":
if shape.Curve.__class__ != Part.Line:
FreeCAD.Console.PrintMessage("Selected edge must be linear\n")
return
if len(refs) > 1:
refs[1] = (feature, element)
else:
refs.append((feature, element))
elif shape.ShapeType == "Face":
if shape.Surface.__class__ != Part.Plane:
FreeCAD.Console.PrintMessage("Selected face must be planar\n")
return
if len(refs) > 0:
if len(refs) > 2:
refs = [(feature, element)]
else:
refs[0] = (feature, element)
else:
refs = [(feature, element)]
else:
FreeCAD.Console.PrintMessage("Wrong shape type selected\n")
return
axis.References = refs
axis.Document.recompute()
elif self.selectionMode == "LinearReference2":
if shape.ShapeType == "Edge":
if shape.Curve.__class__ != Part.Line:
FreeCAD.Console.PrintMessage("Selected edge must be linear\n")
return
if len(refs) > 2:
refs[2] = (feature, element)
else:
refs.append((feature, element))
elif shape.ShapeType == "Face":
if shape.Surface.__class__ != Part.Plane:
FreeCAD.Console.PrintMessage("Selected face must be planar\n")
return
if len(refs) > 1:
if len(refs) > 2:
del refs[2]
refs[1] = (feature, element)
else:
refs.append((feature, element))
else:
FreeCAD.Console.PrintMessage("Wrong shape type selected\n")
return
axis.References = refs
axis.Document.recompute()
elif self.selectionMode == "CircularReference":
if shape.ShapeType == "Edge":
if shape.Curve.__class__ != Part.Circle:
FreeCAD.Console.PrintMessage("Selected edge must be arc or circle\n")
return
elif shape.ShapeType == "Face":
if shape.Surface.__class__ != Part.Cylinder:
FreeCAD.Console.PrintMessage("Selected face must be cylindrical\n")
return
else:
FreeCAD.Console.PrintMessage("Wrong shape type selected\n")
return
refs = [(feature, element)]
axis.References = refs
axis.Document.recompute()
else:
FreeCAD.Console.PrintMessage("Unknown selection mode: " + self.selectionMode + "\n")
self.selectionMode = ""
return
FreeCADGui.Selection.removeObserver(self)
FreeCADGui.Selection.clearSelection()
FreeCADGui.Selection.removeSelectionGate()
self.selectionMode = ""
self.updateUI()
self.showFeature()
def hideFeature(self):
# Make sure selection takes place on support, not on hole feature
if self.feature.Support != None:
FreeCADGui.ActiveDocument.hide(self.feature.Name)
(support, elements) = self.feature.Support
FreeCADGui.ActiveDocument.show(support.Name)
def showFeature(self):
if self.feature.Support != None:
FreeCADGui.ActiveDocument.show(self.feature.Name)
(support, elements) = self.feature.Support
FreeCADGui.ActiveDocument.hide(support.Name)
def buttonSupport(self):
FreeCADGui.Selection.addSelectionGate("SELECT Part::Feature SUBELEMENT Face COUNT 1")
FreeCADGui.Selection.addObserver(self)
# Currently support must be a planar face (but could also be a point or a construction plane in the future)
self.selectionMode = "Plane"
self.hideFeature()
def buttonRef1(self):
FreeCADGui.Selection.addSelectionGate("SELECT Part::Feature SUBELEMENT Edge COUNT 1 SELECT Part::Feature SUBELEMENT Face COUNT 1")
FreeCADGui.Selection.addObserver(self)
if self.feature.PositionType == self.types[0]:
self.selectionMode = "LinearReference"
elif self.feature.PositionType == self.types[1]:
self.selectionMode = "CircularReference"
self.hideFeature()
def buttonRef2(self):
FreeCADGui.Selection.addSelectionGate("SELECT Part::Feature SUBELEMENT Edge COUNT 1 SELECT Part::Feature SUBELEMENT Face COUNT 1")
FreeCADGui.Selection.addObserver(self)
self.selectionMode = "LinearReference2"
self.hideFeature()
def spinRef1(self, val):
axis = self.feature.HoleGroove.Sketch.Support[0].References[0][0]
axis.Offset = val
axis.Document.recompute()
def spinRef2(self, val):
axis = self.feature.HoleGroove.Sketch.Support[0].References[0][0]
axis.Offset2 = val
axis.Document.recompute()

View File

@ -0,0 +1,598 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TaskHole</class>
<widget class="QWidget" name="TaskHole">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>327</width>
<height>315</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab_position">
<attribute name="title">
<string>Position</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QComboBox" name="comboType"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="buttonSupport">
<property name="text">
<string>Face</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineSupport"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="buttonRef1">
<property name="text">
<string>Edge</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineRef1"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLabel" name="labelRef1">
<property name="text">
<string>Distance</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="spinRef1">
<property name="minimum">
<double>-99999.000000000000000</double>
</property>
<property name="maximum">
<double>99999.000000000000000</double>
</property>
<property name="value">
<double>5.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QPushButton" name="buttonRef2">
<property name="text">
<string>Edge</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineRef2"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QLabel" name="labelRef2">
<property name="text">
<string>Distance</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="spinRef2">
<property name="minimum">
<double>-99999.000000000000000</double>
</property>
<property name="maximum">
<double>99999.000000000000000</double>
</property>
<property name="value">
<double>5.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_type">
<attribute name="title">
<string>Type</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QRadioButton" name="buttonThru">
<property name="text">
<string>Through</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="buttonDepth">
<property name="text">
<string>Depth</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="checkThreaded">
<property name="text">
<string>Threaded</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkCountersink">
<property name="text">
<string>Countersink</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkCounterbore">
<property name="text">
<string>Counterbore</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_norm">
<attribute name="title">
<string>Hole norm</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QCheckBox" name="checkCustom">
<property name="text">
<string>Custom dimensions</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboNorm">
<property name="editable">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_8">
<item>
<widget class="QLabel" name="label_7">
<property name="text">
<string>Tolerance</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboTolerance">
<property name="editable">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>Diameter</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboNormDia">
<property name="editable">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_9">
<item>
<widget class="QLabel" name="label_8">
<property name="text">
<string>Bolt/Washer</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboNormBoltWasher">
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="editable">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>125</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_thread">
<attribute name="title">
<string>Thread norm</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_10">
<item>
<widget class="QLabel" name="label_9">
<property name="text">
<string>Thread norm</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboThreadNorm">
<property name="editable">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_12">
<item>
<widget class="QLabel" name="label_12">
<property name="text">
<string>Diameter</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboThreadDia">
<property name="editable">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_13">
<item>
<widget class="QCheckBox" name="checkCustomThreadLength">
<property name="text">
<string> Custom thread length</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_11">
<item>
<widget class="QLabel" name="label_10">
<property name="text">
<string>Finish depth</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboFinishNorm">
<property name="editable">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_7">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>81</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_data">
<attribute name="title">
<string>Data</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="layoutDiameter">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Diameter</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="spinDiameter">
<property name="value">
<double>8.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="layoutDepth">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Depth</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="spinDepth">
<property name="value">
<double>20.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="layoutDiameter_2">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Counterbore/sink dia</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="spinCounterboreDiameter">
<property name="value">
<double>15.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="layoutDepth_2">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Counterbore depth</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="spinCounterboreDepth">
<property name="value">
<double>7.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="layoutAngle">
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>Countersink angle</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="spinCountersinkAngle">
<property name="value">
<double>15.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="layoutDepth_3">
<item>
<widget class="QLabel" name="label_11">
<property name="text">
<string>Thread length</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="spinThreadLength">
<property name="value">
<double>5.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>3</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,98 @@
#/******************************************************************************
# * Copyright (c)2012 Jan Rheinlaender <jrheinlaender@users.sourceforge.net> *
# * *
# * 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 *
# * *
# ******************************************************************************/
import FreeCAD, FreeCADGui
from TaskHole import TaskHole
class ViewProviderHole:
def __init__(self, obj):
''' Set this object to the proxy object of the actual view provider '''
obj.Proxy = self
self.Object = obj.Object
def attach(self, obj):
''' Setup the scene sub-graph of the view provider, this method is mandatory '''
return
def claimChildren(self):
if self is None:
return
# The following statement leads to the error:
# <unknown exception traceback><type 'exceptions.TypeError'>: PyCXX: Error creating object of type N2Py7SeqBaseINS_6ObjectEEE from None
if not hasattr(self, "Object"):
return
if self.Object != None:
return [self.Object.HoleGroove, # the groove feature
self.Object.HoleGroove.Sketch.Support[0], # the groove sketchplane (datum plane) feature
self.Object.HoleGroove.Sketch.Support[0].References[0][0]] # the sketchplane first reference (datum line)
def updateData(self, fp, prop):
''' If a property of the handled feature has changed we have the chance to handle this here '''
return
def getDisplayModes(self,obj):
''' Return a list of display modes. '''
modes=[]
return modes
def getDefaultDisplayMode(self):
''' Return the name of the default display mode. It must be defined in getDisplayModes. '''
return "Shaded"
def onChanged(self, vp, prop):
''' Print the name of the property that has changed '''
#FreeCAD.Console.PrintMessage("Change property: " + str(prop) + "\n")
pass
def setEdit(self,vp,mode):
FreeCAD.Console.PrintMessage("setEdit\n")
panel = TaskHole(self.Object)
FreeCADGui.Control.showDialog(panel)
if panel.setupUi():
FreeCADGui.Control.closeDialog(panel)
return True
return False
def unsetEdit(self,vp,mode):
return
def getIcon(self):
''' Return the icon in XMP format which will appear in the tree view. This method is optional
and if not defined a default icon is shown.
'''
return ""
def __getstate__(self):
''' When saving the document this object gets stored using Python's cPickle module.
Since we have some un-pickable here -- the Coin stuff -- we must define this method
to return a tuple of all pickable objects or None.
'''
return None
def __setstate__(self,state):
''' When restoring the pickled object from document we have the chance to set some
internals here. Since no data were pickled nothing needs to be done here.
'''
return None

View File

@ -0,0 +1,30 @@
"""
Hole Feature
"""
#/******************************************************************************
# * Copyright (c)2012 Jan Rheinlaender <jrheinlaender@users.sourceforge.net> *
# * *
# * 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 *
# * *
# ******************************************************************************/
# Empty file to treat the folder as a package
# Initialize eric to do code completion for freecad libs
# import sys
# sys.path.append("/home/jan/freizeit/freecad-build-dbg/lib")

View File

@ -649,7 +649,9 @@ Gui::MenuItem* Workbench::setupMenuBar() const
// << "PartDesign_Scaled"
<< "PartDesign_MultiTransform"
<< "Separator"
<< "PartDesign_Boolean";
<< "PartDesign_Boolean"
<< "Separator"
<< "PartDesign_Hole";
// For 0.13 a couple of python packages like numpy, matplotlib and others
// are not deployed with the installer on Windows. Thus, the WizardShaft is

View File

@ -42,6 +42,7 @@ class PartDesignWorkbench ( Workbench ):
from WizardShaft import WizardShaft
except ImportError:
print "Wizard shaft module cannot be loaded"
from FeatureHole import HoleGui
import PartDesignGui
import PartDesign
try:

View File

@ -0,0 +1,72 @@
# PartDesign gui init module
# (c) 2003 Juergen Riegel
#
# Gathering all the information to start FreeCAD
# This is the second one of three init scripts, the third one
# runs when the gui is up
#***************************************************************************
#* (c) Juergen Riegel (juergen.riegel@web.de) 2002 *
#* *
#* This file is part of the FreeCAD CAx development system. *
#* *
#* 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. *
#* *
#* FreeCAD 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 Lesser General Public License for more details. *
#* *
#* You should have received a copy of the GNU Library General Public *
#* License along with FreeCAD; if not, write to the Free Software *
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
#* USA *
#* *
#* Juergen Riegel 2002 *
#***************************************************************************/
class PartDesignWorkbench ( Workbench ):
"PartDesign workbench object"
def __init__(self):
self.__class__.Icon = FreeCAD.getResourceDir() + "Mod/PartDesign/Resources/icons/PartDesignWorkbench.svg"
self.__class__.MenuText = "Part Design"
self.__class__.ToolTip = "Part Design workbench"
<<<<<<< 64a1a440055b8a4359349b7abffe8956e78196db
def Initialize(self):
# load the module
try:
from WizardShaft import WizardShaft
except ImportError:
print "Wizard shaft module cannot be loaded"
import PartDesignGui
import PartDesign
try:
import InvoluteGearFeature
except ImportError:
print "Involute gear module cannot be loaded"
def GetClassName(self):
return "PartDesignGui::Workbench"
=======
def Initialize(self):
# load the module
try:
from WizardShaft import WizardShaft
except ImportError:
print "Wizard shaft module cannot be loaded"
from FeatureHole import HoleGui
import PartDesignGui
import PartDesign
try:
import InvoluteGearFeature
except ImportError:
print "Involute gear module cannot be loaded"
def GetClassName(self):
return "PartDesignGui::Workbench"
>>>>>>> Python code of Hole Feature
Gui.addWorkbench(PartDesignWorkbench())