[PD] Remove unused old hole feature implementation

Has been disabled for 7 years a there's an existing newer implementation
This commit is contained in:
Adrian Insaurralde Avalos
2023-10-18 12:09:13 +02:00
committed by wwmayer
parent 3b0720c2b2
commit 3fe4cdd977
9 changed files with 0 additions and 3069 deletions
-17
View File
@@ -201,20 +201,3 @@ if(BUILD_FEM)
Mod/PartDesign/WizardShaft
)
endif(BUILD_FEM)
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})
@@ -1,483 +0,0 @@
#/******************************************************************************
# * Copyright (c) 2012 Jan Rheinländer <[email protected]> *
# * *
# * 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 = FreeCADGui.activeView().getActiveObject("pdbody")
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 is not 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 is None or fp.Support is 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 is 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.LineSegment:
if firstLine is 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.LineSegment:
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 Exception:
# 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.LineSegment(firstLine.Curve)
#l2 = Part.LineSegment(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 is 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,"LineSegment") # 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.LineSegment(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.LineSegment(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.LineSegment(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.LineSegment(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.LineSegment(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.LineSegment(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.LineSegment(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.LineSegment(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
-88
View File
@@ -1,88 +0,0 @@
#/******************************************************************************
# * Copyright (c) 2012 Jan Rheinländer <[email protected]> *
# * *
# * 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 PySide 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.QApplication.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.QApplication.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 is 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")
return
# 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 = FreeCADGui.activeView().getActiveObject("pdbody");
if body is None:
QtGui.QMessageBox.critical(mw, "No active body", "Please create a body or make a body active")
return
feature = doc.addObject("Part::FeaturePython","Hole")
hole = Hole(feature)
body.addFeature(feature)
vp = ViewProviderHole(feature.ViewObject)
feature.touch()
FreeCAD.ActiveDocument.recompute()
# Fit view (remove after the testing phase)
FreeCADGui.SendMsgToActiveView("ViewFit")
vp.setEdit(vp, 1)
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())
@@ -1,646 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 23 KiB

-450
View File
@@ -1,450 +0,0 @@
# -*- coding: iso-8859-15 -*-
#/******************************************************************************
# * Copyright (c) 2012 Jan Rheinländer <[email protected]> *
# * *
# * 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:
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:
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:
raise Exception("No such standard exists")
return standards_counterbore_through[standard]
def getCounterboreDia(standard, threadDia, extraStandard = ""):
if not standard in standards_counterbore:
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:
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:
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:
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:
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:
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)]
-660
View File
@@ -1,660 +0,0 @@
#/******************************************************************************
# * Copyright (c) 2012 Jan Rheinländer <[email protected]> *
# * *
# * 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 PySide 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 is not None):
self.hideFeature() # Show the support again
document = self.feature.Document
body = FreeCADGui.activeView().getActiveObject("pdbody");
groove = self.feature.HoleGroove
sketch = groove.Sketch
plane = sketch.Support[0]
axis = plane.References[0][0]
body.removeObject(self.feature)
document.removeObject(self.feature.Name)
body.removeObject(groove)
document.removeObject(groove.Name)
body.removeObject(sketch)
try:
document.removeObject(sketch.Name)
except Exception:
pass # This always throws an exception: "Sketch support has been deleted" from SketchObject::execute()
body.removeObject(plane)
document.removeObject(plane.Name)
body.removeObject(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.QApplication.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.QApplication.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 is 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()
return True
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 is 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] is not 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] is not 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] is not 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.LineSegment:
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.LineSegment:
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 is not None:
FreeCADGui.ActiveDocument.hide(self.feature.Name)
(support, elements) = self.feature.Support
FreeCADGui.ActiveDocument.show(support.Name)
def showFeature(self):
if self.feature.Support is not 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()
-598
View File
@@ -1,598 +0,0 @@
<?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 notr="true">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>
@@ -1,97 +0,0 @@
#/******************************************************************************
# * Copyright (c) 2012 Jan Rheinländer <[email protected]> *
# * *
# * 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 is not 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):
panel = TaskHole(self.Object)
FreeCADGui.Control.showDialog(panel)
if not panel.setupUi():
FreeCADGui.Control.closeDialog(panel)
return False
return True
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
@@ -1,30 +0,0 @@
"""
Hole Feature
"""
#/******************************************************************************
# * Copyright (c) 2012 Jan Rheinländer <[email protected]> *
# * *
# * 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")