Python code of Hole Feature
This commit is contained in:
parent
45ce3b7822
commit
0a743b27da
|
@ -71,3 +71,35 @@ INSTALL(
|
|||
DESTINATION
|
||||
Mod/PartDesign/WizardShaft
|
||||
)
|
||||
|
||||
SET(FeatureHole_SRCS
|
||||
FeatureHole/__init__.py
|
||||
FeatureHole/HoleGui.py
|
||||
FeatureHole/FeatureHole.py
|
||||
FeatureHole/TaskHole.py
|
||||
FeatureHole/ViewProviderHole.py
|
||||
FeatureHole/Standards.py
|
||||
FeatureHole/PartDesign_Hole.svg
|
||||
)
|
||||
SOURCE_GROUP("featurehole" FILES ${FeatureHole_SRCS})
|
||||
|
||||
SET(FeatureHole_UI
|
||||
FeatureHole/TaskHole.ui
|
||||
)
|
||||
|
||||
SET(all_featurehole_files ${FeatureHole_SRCS} ${FeatureHole_UI})
|
||||
|
||||
ADD_CUSTOM_TARGET(FeatureHole ALL
|
||||
SOURCES ${all_featurehole_files}
|
||||
)
|
||||
|
||||
SET(all_files ${all_featurehole_files})
|
||||
|
||||
fc_copy_sources(Mod/PartDesign "${CMAKE_BINARY_DIR}/Mod/PartDesign" ${all_files})
|
||||
|
||||
INSTALL(
|
||||
FILES
|
||||
${FeatureHole_SRCS}
|
||||
DESTINATION
|
||||
Mod/PartDesign/FeatureHole
|
||||
)
|
||||
|
|
483
src/Mod/PartDesign/FeatureHole/FeatureHole.py
Normal file
483
src/Mod/PartDesign/FeatureHole/FeatureHole.py
Normal file
|
@ -0,0 +1,483 @@
|
|||
#/******************************************************************************
|
||||
# * Copyright (c)2012 Jan Rheinlaender <jrheinlaender@users.sourceforge.net> *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
# * *
|
||||
# * This library is free software; you can redistribute it and/or *
|
||||
# * modify it under the terms of the GNU Library General Public *
|
||||
# * License as published by the Free Software Foundation; either *
|
||||
# * version 2 of the License, or (at your option) any later version. *
|
||||
# * *
|
||||
# * This library is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this library; see the file COPYING.LIB. If not, *
|
||||
# * write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
# * Suite 330, Boston, MA 02111-1307, USA *
|
||||
# * *
|
||||
# ******************************************************************************/
|
||||
|
||||
import FreeCAD, FreeCADGui
|
||||
import Part, Sketcher, PartDesignGui
|
||||
import math
|
||||
|
||||
def makeVector(point):
|
||||
if point.__class__ == FreeCAD.Vector:
|
||||
return point
|
||||
return FreeCAD.Vector(point.X, point.Y, point.Z)
|
||||
|
||||
class Hole():
|
||||
"Hole feature"
|
||||
App = FreeCAD
|
||||
Gui = FreeCADGui
|
||||
|
||||
def __init__(self, feature):
|
||||
self.feature = feature
|
||||
self.feature.addProperty("App::PropertyString","HoleType","Hole","Type of hole").HoleType="Depth"
|
||||
self.feature.addProperty("App::PropertyBool","Threaded","Hole","Threaded hole").Threaded=False
|
||||
self.feature.addProperty("App::PropertyBool","Counterbore","Hole","Counterbore hole").Counterbore=False
|
||||
self.feature.addProperty("App::PropertyBool","Countersink","Hole","Countersink hole").Countersink=False
|
||||
self.feature.addProperty("App::PropertyString","Norm","Hole","Name of norm").Norm="Custom"
|
||||
self.feature.addProperty("App::PropertyString","NormTolerance","Hole","Tolerance field of norm").NormTolerance="medium"
|
||||
self.feature.addProperty("App::PropertyLength","NormDiameter","Hole","Nominal diameter of hole").NormDiameter=4.0
|
||||
self.feature.addProperty("App::PropertyString", "ExtraNorm", "Hole", "Norm of bolt or washer used in hole").ExtraNorm="ISO 4762"
|
||||
self.feature.addProperty("App::PropertyString", "NormThread", "Hole", "Norm of thread").NormThread="DIN 13-1"
|
||||
self.feature.addProperty("App::PropertyString", "NormThreadFinish", "Hole", "Norm defining thread finish length").NormThreadFinish="DIN 76-2"
|
||||
self.feature.addProperty("App::PropertyLength","Diameter","Hole","Diameter of hole").Diameter=5.0
|
||||
self.feature.addProperty("App::PropertyLength","Depth","Hole","Depth of hole").Depth=8.0
|
||||
self.feature.addProperty("App::PropertyLength","CounterboreDiameter","Hole","Diameter of counterbore").CounterboreDiameter=10.0
|
||||
self.feature.addProperty("App::PropertyLength","CounterboreDepth","Hole","Depth of counterbore").CounterboreDepth=4.0
|
||||
self.feature.addProperty("App::PropertyLength","CountersinkAngle","Hole","Angle of countersink").CountersinkAngle=45.0;
|
||||
self.feature.addProperty("App::PropertyLength","ThreadLength","Hole","Length of thread").ThreadLength=5.0;
|
||||
self.feature.addProperty("App::PropertyString","PositionType","Hole","Type of position references").PositionType="Linear"
|
||||
self.feature.addProperty("App::PropertyLinkSub","Support","Hole","Support of hole feature").Support=None
|
||||
self.feature.addProperty("App::PropertyLink","HoleGroove","Hole","Revolution feature creating the hole").HoleGroove=None
|
||||
# Create new HoleGroove feature
|
||||
body = PartDesignGui.getActivePart()
|
||||
self.sketchaxis = self.feature.Document.addObject("PartDesign::Line", "HoleSketchAxis")
|
||||
body.addFeature(self.sketchaxis)
|
||||
self.Gui.ActiveDocument.hide(self.sketchaxis.Name)
|
||||
self.sketchplane = self.feature.Document.addObject("PartDesign::Plane", "HoleSketchPlane")
|
||||
self.sketchplane.References = (self.sketchaxis, "")
|
||||
body.addFeature(self.sketchplane)
|
||||
self.Gui.ActiveDocument.hide(self.sketchplane.Name)
|
||||
self.sketch = self.feature.Document.addObject("Sketcher::SketchObject","HoleSketch")
|
||||
self.sketch.Support = (self.sketchplane, ["front"])
|
||||
body.addFeature(self.sketch)
|
||||
self.Gui.ActiveDocument.hide(self.sketch.Name)
|
||||
feature.HoleGroove = feature.Document.addObject("PartDesign::Groove","HoleGroove")
|
||||
feature.HoleGroove.Angle = 360.0
|
||||
feature.HoleGroove.Sketch = self.sketch
|
||||
body.addFeature(feature.HoleGroove)
|
||||
self.Gui.ActiveDocument.hide(feature.HoleGroove.Name)
|
||||
self.feature.Proxy = self
|
||||
self.oldCounterbore = False
|
||||
self.oldCountersink = False
|
||||
|
||||
def execute(self, feature):
|
||||
if feature.Support != None:
|
||||
(support, element) = feature.Support
|
||||
feature.Placement = feature.HoleGroove.Placement
|
||||
shape = feature.HoleGroove.Shape.copy()
|
||||
shape.Placement = FreeCAD.Placement()
|
||||
feature.Shape = shape
|
||||
|
||||
self.Gui.ActiveDocument.hide(support.Name)
|
||||
# Copy display properties from support
|
||||
featview = feature.ViewObject
|
||||
suppview = support.ViewObject
|
||||
for p in suppview.PropertiesList:
|
||||
if not p in ["DisplayMode","BoundingBox","Proxy","RootNode","Visibility"]:
|
||||
if p in featview.PropertiesList:
|
||||
val = getattr(suppview,p)
|
||||
setattr(featview,p,val)
|
||||
if suppview.DisplayMode in featview.listDisplayModes():
|
||||
featview.DisplayMode = suppview.DisplayMode
|
||||
if hasattr(suppview,"DiffuseColor") and hasattr(featview,"DiffuseColor"):
|
||||
featview.DiffuseColor = suppview.DiffuseColor
|
||||
|
||||
def onChanged(self, fp, prop):
|
||||
#self.App.Console.PrintMessage("Change property: " + str(prop) + "\n")
|
||||
if fp == None or fp.Support == None:
|
||||
return
|
||||
|
||||
if (prop == "HoleType" or prop == "Threaded" or prop == "Counterbore" or prop == "Countersink"
|
||||
or prop == "Diameter" or prop == "Depth"
|
||||
or prop == "CounterboreDiameter" or prop == "CounterboreDepth"
|
||||
or prop == "CountersinkAngle"):
|
||||
self.executeSketchChanged(fp)
|
||||
fp.Document.recompute()
|
||||
elif prop == "Support":
|
||||
self.executePositionChanged(fp)
|
||||
fp.Document.recompute()
|
||||
|
||||
def executePositionChanged(self, fp):
|
||||
"Change the position of the hole"
|
||||
if fp.Support == None:
|
||||
return
|
||||
plane = self.feature.HoleGroove.Sketch.Support[0]
|
||||
# Get support (face)
|
||||
(support, elementList) = fp.Support
|
||||
face = eval("support.Shape." + elementList[0])
|
||||
refs = plane.References
|
||||
if len(refs) == 0:
|
||||
return
|
||||
|
||||
axis = plane.References[0][0]
|
||||
firstTime = (len(axis.References) == 0)
|
||||
if firstTime:
|
||||
# Try to guess some references (using arcs or lines of the outer wire of the support face)
|
||||
wire = face.OuterWire
|
||||
firstLine = None
|
||||
for e in wire.Edges:
|
||||
if type(e.Curve) == Part.Line:
|
||||
if firstLine == None:
|
||||
firstLine = e
|
||||
firstDirection = e.Curve.EndPoint - e.Curve.StartPoint
|
||||
else:
|
||||
if firstDirection == e.Curve.EndPoint - e.Curve.StartPoint or firstDirection == e.Curve.StartPoint - e.Curve.EndPoint:
|
||||
continue # Parallel edges
|
||||
allEdges = support.Shape.Edges
|
||||
firstLineIndex = -1
|
||||
secondLineIndex = -1
|
||||
for i in range(len(allEdges)):
|
||||
try:
|
||||
if type(allEdges[i].Curve) != Part.Line:
|
||||
continue
|
||||
if (allEdges[i].Curve.StartPoint == firstLine.Curve.StartPoint and allEdges[i].Curve.EndPoint == firstLine.Curve.EndPoint) or (allEdges[i].Curve.EndPoint == firstLine.Curve.StartPoint and allEdges[i].Curve.StartPoint == firstLine.Curve.EndPoint):
|
||||
firstLineIndex = i
|
||||
elif (allEdges[i].Curve.StartPoint == e.Curve.StartPoint and allEdges[i].Curve.EndPoint == e.Curve.EndPoint) or (allEdges[i].Curve.EndPoint == e.Curve.StartPoint and allEdges[i].Curve.StartPoint == e.Curve.EndPoint):
|
||||
secondLineIndex = i
|
||||
if (firstLineIndex > -1) and (secondLineIndex > -1):
|
||||
break
|
||||
except:
|
||||
# Unknown curvetype GeomAbs_OtherCurve
|
||||
continue
|
||||
axis.References = [(support, elementList[0]), (support, "Edge" + str(firstLineIndex+1)), (support, "Edge" + str(secondLineIndex+1))]
|
||||
axis.Offset = 1.0
|
||||
axis.Offset2 = 1.0
|
||||
self.feature.PositionType = "Linear"
|
||||
# Place the axis approximately in the center of the face
|
||||
#p = face.CenterOfMass
|
||||
#l1 = Part.Line(firstLine.Curve)
|
||||
#l2 = Part.Line(e.Curve)
|
||||
#axis.Offset = p.distanceToLine(l1.StartPoint, l1.EndPoint - l1.StartPoint)
|
||||
#axis.Offset2 = p.distanceToLine(l1.StartPoint, l2.EndPoint - l2.StartPoint)
|
||||
# TODO: Ensure that the hole is inside the face!
|
||||
break
|
||||
elif type(e.Curve) == Part.Circle:
|
||||
allEdges = support.Shape.Edges
|
||||
for i in range(len(allEdges)):
|
||||
try:
|
||||
if type(allEdges[i].Curve) != Part.Circle:
|
||||
continue
|
||||
c = allEdges[i].Curve
|
||||
if c.Center == e.Curve.Center and c.Axis == e.Curve.Axis and c.Radius == e.Curve.Radius:
|
||||
axis.References = [(support, "Edge" + str(i+1))]
|
||||
self.feature.PositionType = "Coaxial"
|
||||
break
|
||||
except:
|
||||
# Unknown curvetype
|
||||
continue
|
||||
elif type(e.Curve) == Part.ArcOfCircle:
|
||||
allEdges = support.Shape.Edges
|
||||
for i in range(len(allEdges)):
|
||||
try:
|
||||
if type(allEdges[i].Curve) != Part.ArcOfCircle:
|
||||
continue
|
||||
a = allEdges[i].Curve
|
||||
if a.Center == e.Curve.Center and a.Axis == e.Curve.Axis and a.Radius == e.Curve.Radius and a.FirstParameter == e.Curve.FirstParameter and a.LastParameter == e.Curve.LastParameter:
|
||||
axis.References = [(support, "Edge" + str(i+1))]
|
||||
self.feature.PositionType = "Coaxial"
|
||||
break
|
||||
except:
|
||||
continue
|
||||
break
|
||||
|
||||
# Grab a point from the wire of the support face
|
||||
axisbase = axis.Shape.Curve.StartPoint
|
||||
axisdir = axis.Shape.Curve.EndPoint - axisbase
|
||||
found = False
|
||||
if not firstTime and len(refs) > 1:
|
||||
# Try to keep the old point, to avoid the sketch plane jumping around
|
||||
(obj, sub) = refs[1]
|
||||
point = eval("support.Shape." + sub)
|
||||
if point.Point.distanceToLine(axisbase, axisdir) > 1E-10: # TODO: Precision::Confusion()
|
||||
found = True
|
||||
if not found:
|
||||
for p in face.OuterWire.Vertexes:
|
||||
if p.Point.distanceToLine(axisbase, axisdir) > 1E-10: # TODO: Precision::Confusion()
|
||||
point = p
|
||||
found = True
|
||||
break
|
||||
if not found:
|
||||
point = face.OuterWire.Vertexes[0] # Better this than nothing... and it can't actually happen, can it?
|
||||
|
||||
# Find the index of the point in the support shape
|
||||
allVertexes = support.Shape.Vertexes
|
||||
for v in range(len(allVertexes)):
|
||||
if allVertexes[v].Point == point.Point:
|
||||
# Use this point and the axis to define the sketch plane
|
||||
if len(refs) < 2:
|
||||
refs.append((support, "Vertex" + str(v+1)))
|
||||
else:
|
||||
refs[1] = (support, "Vertex" + str(v+1))
|
||||
break
|
||||
plane.References = refs
|
||||
if firstTime:
|
||||
fp.Document.recompute() # Update the Sketch Placement property
|
||||
self.executeSketchChanged(fp) # Build the sketch of the hole
|
||||
fp.Document.recompute()
|
||||
else:
|
||||
self.executeSketchChanged(fp) # Update the sketch of the hole
|
||||
self.setHoleDirection(fp)
|
||||
|
||||
def setHoleDirection(self, feature):
|
||||
# Make sure the hole goes into the material, not out of it
|
||||
sketch = feature.HoleGroove.Sketch
|
||||
axis = sketch.Support[0].References[0][0]
|
||||
axisbase = axis.Shape.Curve.StartPoint
|
||||
axisdir = axis.Shape.Curve.EndPoint - axisbase
|
||||
p1 = None
|
||||
p2 = None
|
||||
for v in sketch.Shape.Vertexes:
|
||||
# Find the two sketch vertices that are on the sketch axis
|
||||
if v.Point.distanceToLine(axisbase, axisdir) < 1E-10: # TODO: use Precision::Confusion()
|
||||
if p1 is None:
|
||||
p1 = v.Point
|
||||
else:
|
||||
p2 = v.Point
|
||||
break
|
||||
if p1 is not None and p2 is not None:
|
||||
(support, elementList) = feature.Support
|
||||
face = eval("support.Shape." + elementList[0])
|
||||
plane = face.Surface
|
||||
if type(plane) != Part.Plane:
|
||||
return
|
||||
# Find the vertex that is on the top of the hole
|
||||
if p1.distanceToPlane(plane.Position, plane.Axis) < 1E-10:
|
||||
top = p1
|
||||
dir = p2 - p1
|
||||
else:
|
||||
top = p2
|
||||
dir = p1 - p2
|
||||
if not support.Shape.isInside(top + dir.multiply(1E-8), 1E-10, False):
|
||||
# Toggle the angle
|
||||
angle = sketch.Constraints[12].Value
|
||||
if angle == math.pi:
|
||||
sketch.setDatum(12, 0.0)
|
||||
else:
|
||||
sketch.setDatum(12, math.pi)
|
||||
|
||||
def executeSketchChanged(self, fp):
|
||||
"Change the sketch shape of the hole"
|
||||
if self.feature.HoleGroove == None:
|
||||
return
|
||||
if fp.HoleType == "Thru":
|
||||
# TODO: Make this more stable
|
||||
length = 1E+4
|
||||
else:
|
||||
length = fp.Depth
|
||||
radius = fp.Diameter / 2.0
|
||||
|
||||
if fp.Counterbore:
|
||||
self.createOrUpdateCounterboreSketch(fp, length, radius)
|
||||
elif fp.Countersink:
|
||||
self.createOrUpdateCountersinkSketch(fp, length, radius)
|
||||
else:
|
||||
self.createOrUpdateStandardSketch(fp, length, radius)
|
||||
|
||||
def createOrUpdateStandardSketch(self, fp, depth, radius):
|
||||
(support, elements) = fp.Support
|
||||
if fp.HoleGroove.Sketch.GeometryCount == 0:
|
||||
#FreeCAD.Console.PrintMessage("Standard sketch\n")
|
||||
# New sketch
|
||||
sketch = fp.HoleGroove.Sketch
|
||||
axis = sketch.Support[0].References[0][0]
|
||||
# Geo -1,1 is the origin (Point)
|
||||
# Geo -1 is the X-axis
|
||||
# Geo -2 is the Y-axis
|
||||
# First external geometry is -3
|
||||
sketch.addExternal(axis.Name,"Line") # Geo -3: Datum axis
|
||||
sketch.addExternal(support.Name, elements[0]) # Geo -4: Support face
|
||||
# Note: Creating the sketch first with depth = 100.0 and then changing the constraint later seems to be more stable
|
||||
tempDepth = 100.0
|
||||
# Build the sketch
|
||||
sketch.addGeometry(Part.Line(self.App.Vector(10.0,50.0,0),self.App.Vector(10.0,-50.0,0))) # Geo0: Rotation axis
|
||||
sketch.toggleConstruction(0)
|
||||
sketch.addGeometry(Part.Line(self.App.Vector(10.0,-10.0,0),self.App.Vector(10.0,-30.0,0))) # Geo1: Vertical axis of hole
|
||||
sketch.addConstraint(Sketcher.Constraint('PointOnObject',1,1,0))# Datum0
|
||||
sketch.addConstraint(Sketcher.Constraint('PointOnObject',1,2,0))# Datum1
|
||||
sketch.addGeometry(Part.Line(self.App.Vector(10.0,-10.0,0),self.App.Vector(20.0,-10.0,0))) # Geo2: Top of hole
|
||||
sketch.addConstraint(Sketcher.Constraint('Coincident',1,1,2,1)) # Datum2
|
||||
sketch.addConstraint(Sketcher.Constraint('Perpendicular',2, 1)) # Datum3
|
||||
sketch.addGeometry(Part.Line(self.App.Vector(20.0,-10.0,0),self.App.Vector(20.0,-25.0,0))) # Geo3: Vertical mantle of hole
|
||||
sketch.addConstraint(Sketcher.Constraint('Coincident',2,2,3,1)) # temporary
|
||||
sketch.addConstraint(Sketcher.Constraint('Parallel',3, 1)) # Datum4
|
||||
sketch.addConstraint(Sketcher.Constraint('Distance',3,2,1, 10.0)) # Datum5: Radius
|
||||
sketch.addConstraint(Sketcher.Constraint('Distance',3,2,2, 15.0)) # Datum6: Depth
|
||||
sketch.addGeometry(Part.Line(self.App.Vector(10.0,-30.0,0),self.App.Vector(20.0,-25.0,0))) # Geo4: 118 degree tip angle
|
||||
sketch.addConstraint(Sketcher.Constraint('Coincident',4,1,1,2)) # Datum7
|
||||
sketch.addConstraint(Sketcher.Constraint('Coincident',4,2,3,2)) # Datum8
|
||||
# TODO: The tip angle of 118 degrees is for steel only. It should be taken from Part material data
|
||||
# (as soon as that is implemented)
|
||||
sketch.addConstraint(Sketcher.Constraint('Angle',4,1,1,2, 118.0/2.0 * math.pi / 180.0)) # Datum9
|
||||
# Locate at the intersection of the two external geometries
|
||||
sketch.addConstraint(Sketcher.Constraint('PointOnObject',1,1,-3))# Datum10
|
||||
sketch.addConstraint(Sketcher.Constraint('PointOnObject',1,1,-4))# Datum11
|
||||
sketch.addConstraint(Sketcher.Constraint('Angle',0,1,-3, 1, 0.0))# Datum12
|
||||
# This datum is specific for this holetype, so move it to the last position
|
||||
sketch.delConstraint(4)
|
||||
sketch.addConstraint(Sketcher.Constraint('Coincident',2,2,3,1)) # Datum13
|
||||
fp.HoleGroove.ReferenceAxis = (sketch,['Axis0'])
|
||||
if self.oldCounterbore == True:
|
||||
# Remove counterbore from existing sketch
|
||||
#FreeCAD.Console.PrintMessage("Counter to Standard sketch\n")
|
||||
sketch = fp.HoleGroove.Sketch
|
||||
sketch.delConstraint(19)
|
||||
sketch.delConstraint(18)
|
||||
sketch.delConstraint(17)
|
||||
sketch.delConstraint(16)
|
||||
sketch.delConstraint(15)
|
||||
sketch.delConstraint(14)
|
||||
sketch.delConstraint(13)
|
||||
sketch.delGeometry(6)
|
||||
sketch.delGeometry(5)
|
||||
sketch.addConstraint(Sketcher.Constraint('Coincident',2,2,3,1)) # Datum13
|
||||
elif self.oldCountersink == True:
|
||||
# Remove countersink from existing sketch
|
||||
#FreeCAD.Console.PrintMessage("Sink to Standard sketch\n")
|
||||
sketch = fp.HoleGroove.Sketch
|
||||
sketch.delConstraint(16)
|
||||
sketch.delConstraint(15)
|
||||
sketch.delConstraint(14)
|
||||
sketch.delConstraint(13)
|
||||
sketch.delGeometry(5)
|
||||
sketch.addConstraint(Sketcher.Constraint('Coincident',2,2,3,1)) # Datum13
|
||||
else:
|
||||
# Update existing standard sketch
|
||||
#FreeCAD.Console.PrintMessage("Update Standard sketch\n")
|
||||
sketch = fp.HoleGroove.Sketch
|
||||
sketch.setDatum(5, radius)
|
||||
sketch.setDatum(6, depth)
|
||||
if sketch.ExternalGeometry[1] != (support, elements[0]):
|
||||
# Update the external geometry references
|
||||
angle = sketch.Constraints[12].Value
|
||||
sketch.delConstraint(13)
|
||||
sketch.delConstraint(12)
|
||||
sketch.delConstraint(11)
|
||||
sketch.delExternal(1)
|
||||
sketch.addExternal(support.Name, elements[0]) # Geo -4: Support face
|
||||
sketch.addConstraint(Sketcher.Constraint('PointOnObject',1,1,-4))# Datum11
|
||||
sketch.addConstraint(Sketcher.Constraint('Angle',0,1,-3, 1, angle))# Datum12
|
||||
sketch.addConstraint(Sketcher.Constraint('Coincident',2,2,3,1)) # Datum13
|
||||
|
||||
self.setHoleDirection(fp)
|
||||
self.oldCounterbore = False
|
||||
self.oldCountersink = False
|
||||
|
||||
def createOrUpdateCounterboreSketch(self, fp, depth, radius):
|
||||
cradius = fp.CounterboreDiameter / 2.0
|
||||
cdepth = fp.CounterboreDepth
|
||||
(support, elements) = fp.Support
|
||||
|
||||
if self.oldCounterbore == True:
|
||||
# Update properties of existing counterbore sketch
|
||||
#FreeCAD.Console.PrintMessage("Update to Counterbore sketch\n")
|
||||
sketch = fp.HoleGroove.Sketch
|
||||
sketch.setDatum(5, radius)
|
||||
sketch.setDatum(6, depth)
|
||||
sketch.setDatum(13, cradius)
|
||||
sketch.setDatum(15, cdepth)
|
||||
if sketch.ExternalGeometry[1] != (support, elements[0]):
|
||||
# Update the external geometry references
|
||||
angle = sketch.Constraints[12].Value
|
||||
sketch.delConstraint(19)
|
||||
sketch.delConstraint(18)
|
||||
sketch.delConstraint(17)
|
||||
sketch.delConstraint(16)
|
||||
sketch.delConstraint(15)
|
||||
sketch.delConstraint(14)
|
||||
sketch.delConstraint(13)
|
||||
sketch.delConstraint(12)
|
||||
sketch.delConstraint(11)
|
||||
sketch.delExternal(1)
|
||||
sketch.addExternal(support.Name, elements[0]) # Geo -4: Support face
|
||||
sketch.addConstraint(Sketcher.Constraint('PointOnObject',1,1,-4))# Datum11
|
||||
sketch.addConstraint(Sketcher.Constraint('Angle',0,1,-3, 1, angle))# Datum12
|
||||
sketch.addConstraint(Sketcher.Constraint('Distance',2, cradius)) # Datum13
|
||||
sketch.addConstraint(Sketcher.Constraint('Coincident',2,2,5,1)) # Datum14
|
||||
sketch.addConstraint(Sketcher.Constraint('Distance',3, 1, 2, cdepth)) # Datum15
|
||||
sketch.addConstraint(Sketcher.Constraint('Parallel',5, 1)) # Datum16
|
||||
sketch.addConstraint(Sketcher.Constraint('Coincident',5,2,6,1)) # Datum17
|
||||
sketch.addConstraint(Sketcher.Constraint('Perpendicular',6, -3)) # Datum18
|
||||
sketch.addConstraint(Sketcher.Constraint('Coincident',6,2,3,1)) # Datum19
|
||||
else:
|
||||
# Change standard to counterbore in existing sketch
|
||||
#FreeCAD.Console.PrintMessage("Standard to Counterbore sketch\n")
|
||||
sketch = fp.HoleGroove.Sketch
|
||||
sketch.delConstraint(13)
|
||||
sketch.addConstraint(Sketcher.Constraint('Distance',2, cradius)) # Datum13
|
||||
p2 = sketch.Geometry[2].EndPoint
|
||||
sketch.addGeometry(Part.Line(p2,self.App.Vector(p2.x,p2.y-20.0,0))) # Geo5: Vertical mantle of counterbore
|
||||
sketch.addConstraint(Sketcher.Constraint('Coincident',2,2,5,1)) # Datum14
|
||||
sketch.addConstraint(Sketcher.Constraint('Distance',3, 1, 2, cdepth)) # Datum15
|
||||
sketch.addConstraint(Sketcher.Constraint('Parallel',5, 1)) # Datum16
|
||||
p3 = sketch.Geometry[3].StartPoint
|
||||
sketch.addGeometry(Part.Line(self.App.Vector(p2.x,p2.y-20.0, 0),p3)) # Geo6: bottom of counterbore
|
||||
sketch.addConstraint(Sketcher.Constraint('Coincident',5,2,6,1)) # Datum17
|
||||
sketch.addConstraint(Sketcher.Constraint('Perpendicular',6, -3)) # Datum18
|
||||
sketch.addConstraint(Sketcher.Constraint('Coincident',6,2,3,1)) # Datum19
|
||||
|
||||
self.setHoleDirection(fp)
|
||||
self.oldCounterbore = True
|
||||
self.oldCountersink = False
|
||||
|
||||
def createOrUpdateCountersinkSketch(self, fp, depth, radius):
|
||||
sradius = fp.CounterboreDiameter / 2.0
|
||||
sangle = fp.CountersinkAngle * math.pi / 180.0
|
||||
(support, elements) = fp.Support
|
||||
|
||||
if self.oldCountersink == True:
|
||||
# Update properties of existing countersink sketch
|
||||
#FreeCAD.Console.PrintMessage("Update to Countersink sketch\n")
|
||||
sketch = fp.HoleGroove.Sketch
|
||||
sketch.setDatum(5, radius)
|
||||
sketch.setDatum(6, depth)
|
||||
sketch.setDatum(13, sradius)
|
||||
sketch.setDatum(15, sangle)
|
||||
if sketch.ExternalGeometry[1] != (support, elements[0]):
|
||||
# Update the external geometry references
|
||||
angle = sketch.Constraints[12].Value
|
||||
sketch.delConstraint(16)
|
||||
sketch.delConstraint(15)
|
||||
sketch.delConstraint(14)
|
||||
sketch.delConstraint(13)
|
||||
sketch.delConstraint(12)
|
||||
sketch.delConstraint(11)
|
||||
sketch.delExternal(1)
|
||||
sketch.addExternal(support.Name, elements[0]) # Geo -4: Support face
|
||||
sketch.addConstraint(Sketcher.Constraint('PointOnObject',1,1,-4))# Datum11
|
||||
sketch.addConstraint(Sketcher.Constraint('Angle',0,1,-3, 1, angle))# Datum12
|
||||
sketch.addConstraint(Sketcher.Constraint('Distance',2, sradius)) # Datum13
|
||||
sketch.addConstraint(Sketcher.Constraint('Coincident',2,2,5,1)) # Datum14
|
||||
sketch.addConstraint(Sketcher.Constraint('Angle',5,2, 1,2, sangle)) # Datum15
|
||||
sketch.addConstraint(Sketcher.Constraint('Coincident',3,1,5,2)) # Datum16
|
||||
else:
|
||||
# Change standard to countersink in existing sketch
|
||||
#FreeCAD.Console.PrintMessage("Standard to Countersink sketch\n")
|
||||
sketch = fp.HoleGroove.Sketch
|
||||
sketch.delConstraint(13)
|
||||
sketch.addConstraint(Sketcher.Constraint('Distance',2, sradius)) # Datum13
|
||||
p2 = sketch.Geometry[2].EndPoint
|
||||
sketch.addGeometry(Part.Line(p2,self.App.Vector(p2.x,p2.y-20.0,0))) # Geo5: Chamfer of countersink
|
||||
sketch.addConstraint(Sketcher.Constraint('Coincident',2,2,5,1)) # Datum14
|
||||
sketch.addConstraint(Sketcher.Constraint('Angle',5,2, 1,2, sangle)) # Datum15
|
||||
sketch.addConstraint(Sketcher.Constraint('Coincident',3,1,5,2)) # Datum16
|
||||
|
||||
self.setHoleDirection(fp)
|
||||
self.oldCounterbore = False
|
||||
self.oldCountersink = True
|
92
src/Mod/PartDesign/FeatureHole/HoleGui.py
Normal file
92
src/Mod/PartDesign/FeatureHole/HoleGui.py
Normal file
|
@ -0,0 +1,92 @@
|
|||
#/******************************************************************************
|
||||
# * Copyright (c)2012 Jan Rheinlaender <jrheinlaender@users.sourceforge.net> *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
# * *
|
||||
# * This library is free software; you can redistribute it and/or *
|
||||
# * modify it under the terms of the GNU Library General Public *
|
||||
# * License as published by the Free Software Foundation; either *
|
||||
# * version 2 of the License, or (at your option) any later version. *
|
||||
# * *
|
||||
# * This library is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this library; see the file COPYING.LIB. If not, *
|
||||
# * write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
# * Suite 330, Boston, MA 02111-1307, USA *
|
||||
# * *
|
||||
# ******************************************************************************/
|
||||
|
||||
import FreeCAD, FreeCADGui
|
||||
import PartDesignGui
|
||||
from PyQt4 import QtCore, QtGui
|
||||
from TaskHole import TaskHole
|
||||
from FeatureHole import Hole
|
||||
from ViewProviderHole import ViewProviderHole
|
||||
|
||||
class HoleGui:
|
||||
def getMainWindow(self):
|
||||
"returns the main window"
|
||||
# using QtGui.qApp.activeWindow() isn't very reliable because if another
|
||||
# widget than the mainwindow is active (e.g. a dialog) the wrong widget is
|
||||
# returned
|
||||
toplevel = QtGui.qApp.topLevelWidgets()
|
||||
for i in toplevel:
|
||||
if i.metaObject().className() == "Gui::MainWindow":
|
||||
return i
|
||||
raise Exception("No main window found")
|
||||
|
||||
"Create a new hole feature"
|
||||
def Activated(self):
|
||||
# Get main window
|
||||
mw = self.getMainWindow()
|
||||
|
||||
# Get active document
|
||||
doc = FreeCAD.activeDocument()
|
||||
if doc == None:
|
||||
QtGui.QMessageBox.critical(mw, "No document", "A document must be open in order to create a hole feature")
|
||||
return
|
||||
|
||||
# Check for valid position selection
|
||||
selection = FreeCADGui.Selection.getSelectionEx()
|
||||
if len(selection) != 1:
|
||||
QtGui.QMessageBox.critical(mw, "No position defined", "Please select a face to create the hole feature on")
|
||||
return
|
||||
if selection[0].DocumentName != doc.Name:
|
||||
QtGui.QMessageBox.critical(mw, "Wrong document", "Please select a face in the active document")
|
||||
# Note: For some reason setting the Support property here breaks all sorts of things.
|
||||
# It is done in TaskHole.updateUI() instead
|
||||
|
||||
# Show feature preview
|
||||
body = PartDesignGui.getActivePart()
|
||||
if body == None:
|
||||
QtGui.QMessageBox.critical(mw, "No active body", "Please create a body or make a body active")
|
||||
|
||||
feature = doc.addObject("Part::FeaturePython","Hole")
|
||||
hole = Hole(feature)
|
||||
body.addFeature(feature)
|
||||
|
||||
ViewProviderHole(feature.ViewObject)
|
||||
feature.touch()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
# Fit view (remove after the testing phase)
|
||||
FreeCADGui.SendMsgToActiveView("ViewFit")
|
||||
|
||||
panel = TaskHole(feature)
|
||||
|
||||
FreeCADGui.Control.showDialog(panel)
|
||||
if panel.setupUi():
|
||||
FreeCADGui.Control.closeDialog(panel)
|
||||
return None
|
||||
return panel
|
||||
|
||||
def GetResources(self):
|
||||
IconPath = FreeCAD.ConfigGet("AppHomePath") + "Mod/PartDesign/FeatureHole/PartDesign_Hole.svg"
|
||||
MenuText = 'Create a hole feature'
|
||||
ToolTip = 'Create a hole feature'
|
||||
return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip}
|
||||
|
||||
FreeCADGui.addCommand('PartDesign_Hole', HoleGui())
|
646
src/Mod/PartDesign/FeatureHole/PartDesign_Hole.svg
Normal file
646
src/Mod/PartDesign/FeatureHole/PartDesign_Hole.svg
Normal file
|
@ -0,0 +1,646 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64px"
|
||||
height="64px"
|
||||
id="svg2816"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.3.1 r9886"
|
||||
sodipodi:docname="PartDesign_Hole3.svg"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||
inkscape:export-filename="/home/yorik/PartDesign_Pocket.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90">
|
||||
<defs
|
||||
id="defs2818">
|
||||
<linearGradient
|
||||
id="linearGradient4407">
|
||||
<stop
|
||||
id="stop4409"
|
||||
offset="0"
|
||||
style="stop-color:#001ccc;stop-opacity:0" />
|
||||
<stop
|
||||
id="stop4411"
|
||||
offset="1"
|
||||
style="stop-color:#00afff;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3669">
|
||||
<stop
|
||||
style="stop-color:#001ccc;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3671" />
|
||||
<stop
|
||||
style="stop-color:#00afff;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3673" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3602">
|
||||
<stop
|
||||
style="stop-color:#ff2600;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3604" />
|
||||
<stop
|
||||
style="stop-color:#ff5f00;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3606" />
|
||||
</linearGradient>
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 32 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="64 : 32 : 1"
|
||||
inkscape:persp3d-origin="32 : 21.333333 : 1"
|
||||
id="perspective2824" />
|
||||
<inkscape:perspective
|
||||
id="perspective3618"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3602-7"
|
||||
id="linearGradient3608-5"
|
||||
x1="3.909091"
|
||||
y1="14.363636"
|
||||
x2="24.81818"
|
||||
y2="14.363636"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
id="linearGradient3602-7">
|
||||
<stop
|
||||
style="stop-color:#c51900;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3604-1" />
|
||||
<stop
|
||||
style="stop-color:#ff5f00;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3606-3" />
|
||||
</linearGradient>
|
||||
<inkscape:perspective
|
||||
id="perspective3677"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3602-5"
|
||||
id="linearGradient3608-1"
|
||||
x1="3.909091"
|
||||
y1="14.363636"
|
||||
x2="24.81818"
|
||||
y2="14.363636"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
id="linearGradient3602-5">
|
||||
<stop
|
||||
style="stop-color:#c51900;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3604-9" />
|
||||
<stop
|
||||
style="stop-color:#ff5f00;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3606-9" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
y2="14.363636"
|
||||
x2="24.81818"
|
||||
y1="14.363636"
|
||||
x1="3.909091"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3686"
|
||||
xlink:href="#linearGradient3602-5"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective3717"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3602-58"
|
||||
id="linearGradient3608-8"
|
||||
x1="3.909091"
|
||||
y1="14.363636"
|
||||
x2="24.81818"
|
||||
y2="14.363636"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
id="linearGradient3602-58">
|
||||
<stop
|
||||
style="stop-color:#ff2600;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3604-2" />
|
||||
<stop
|
||||
style="stop-color:#840000;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3606-2" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
y2="14.363636"
|
||||
x2="24.81818"
|
||||
y1="14.363636"
|
||||
x1="3.909091"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3726"
|
||||
xlink:href="#linearGradient3602-58"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective4410"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective4944"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective4966"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective5009"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective5165"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective7581"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective7606"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective7638"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective7660"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective7704"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective7730"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective7762"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective7783"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective7843"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective7881"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective7932"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective2866"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective2878"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<linearGradient
|
||||
id="linearGradient3602-1">
|
||||
<stop
|
||||
style="stop-color:#ff2600;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3604-8" />
|
||||
<stop
|
||||
style="stop-color:#ff5f00;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3606-96" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3602-1"
|
||||
id="linearGradient2875"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="3.909091"
|
||||
y1="14.363636"
|
||||
x2="24.81818"
|
||||
y2="14.363636" />
|
||||
<inkscape:perspective
|
||||
id="perspective2885"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<linearGradient
|
||||
id="linearGradient3602-1-5">
|
||||
<stop
|
||||
style="stop-color:#ff2600;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3604-8-3" />
|
||||
<stop
|
||||
style="stop-color:#ff5f00;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3606-96-8" />
|
||||
</linearGradient>
|
||||
<inkscape:perspective
|
||||
id="perspective3720"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<linearGradient
|
||||
id="linearGradient3602-1-8">
|
||||
<stop
|
||||
style="stop-color:#ff2600;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3604-8-5" />
|
||||
<stop
|
||||
style="stop-color:#ff5f00;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3606-96-2" />
|
||||
</linearGradient>
|
||||
<inkscape:perspective
|
||||
id="perspective3822"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3849"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3879"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective2896"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective2925"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective2925-4"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3726"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3689"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<linearGradient
|
||||
id="linearGradient3669-2">
|
||||
<stop
|
||||
style="stop-color:#af7d00;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3671-7" />
|
||||
<stop
|
||||
style="stop-color:#ffed00;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3673-5" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientTransform="matrix(0.73872768,0,0,1.3536788,-2.25,-1.9999999)"
|
||||
y2="1.8468192"
|
||||
x2="48.259949"
|
||||
y1="33.61211"
|
||||
x1="34.290413"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3698"
|
||||
xlink:href="#linearGradient3669-2"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective3689-6"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<linearGradient
|
||||
id="linearGradient3669-22">
|
||||
<stop
|
||||
style="stop-color:#af7d00;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3671-8" />
|
||||
<stop
|
||||
style="stop-color:#ffed00;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3673-4" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientTransform="matrix(0.73872768,0,0,1.3536788,-2.25,-1.9999999)"
|
||||
y2="1.8468192"
|
||||
x2="48.259949"
|
||||
y1="33.61211"
|
||||
x1="34.290413"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3698-3"
|
||||
xlink:href="#linearGradient3669-22"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective3689-1"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<linearGradient
|
||||
id="linearGradient3669-0">
|
||||
<stop
|
||||
style="stop-color:#af7d00;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3671-9" />
|
||||
<stop
|
||||
style="stop-color:#ffed00;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3673-1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientTransform="matrix(0.73872768,0,0,1.3536788,-2.25,-1.9999999)"
|
||||
y2="1.8468192"
|
||||
x2="48.259949"
|
||||
y1="33.61211"
|
||||
x1="34.290413"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3698-9"
|
||||
xlink:href="#linearGradient3669-0"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3602-58-5"
|
||||
id="linearGradient4030-1"
|
||||
x1="42.239037"
|
||||
y1="23.095947"
|
||||
x2="36.44146"
|
||||
y2="21.198208"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
id="linearGradient3602-58-5">
|
||||
<stop
|
||||
style="stop-color:#d82b1e;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3604-2-5" />
|
||||
<stop
|
||||
style="stop-color:#840000;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3606-2-4" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3602-58-50"
|
||||
id="linearGradient4030-6"
|
||||
x1="42.239037"
|
||||
y1="23.095947"
|
||||
x2="36.44146"
|
||||
y2="21.198208"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
id="linearGradient3602-58-50">
|
||||
<stop
|
||||
style="stop-color:#d82b1e;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3604-2-8" />
|
||||
<stop
|
||||
style="stop-color:#840000;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3606-2-2" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3602-58"
|
||||
id="linearGradient4086"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.2297854,-0.03462374,-0.36744124,0.55635649,-6.3422889,4.2186912)"
|
||||
x1="73.638847"
|
||||
y1="24.203213"
|
||||
x2="40.176445"
|
||||
y2="14.684779" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3669-3"
|
||||
id="linearGradient4329-0"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.81731796,0,0,1.9288701,-2.7299862,-14.350362)"
|
||||
x1="78.740204"
|
||||
y1="21.910299"
|
||||
x2="70.337143"
|
||||
y2="24.084332" />
|
||||
<linearGradient
|
||||
id="linearGradient3669-3">
|
||||
<stop
|
||||
style="stop-color:#001ccc;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3671-2" />
|
||||
<stop
|
||||
style="stop-color:#00afff;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3673-2" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3669-22-5"
|
||||
id="linearGradient3675-0-5"
|
||||
x1="34.290413"
|
||||
y1="33.61211"
|
||||
x2="48.259949"
|
||||
y2="1.8468192"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.4976911,0,0,1.0526203,-3.6955244,-10.60101)" />
|
||||
<linearGradient
|
||||
id="linearGradient3669-22-5">
|
||||
<stop
|
||||
style="stop-color:#af7d00;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3671-8-3" />
|
||||
<stop
|
||||
style="stop-color:#ffed00;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3673-4-0" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="8.5762527"
|
||||
inkscape:cx="24.289382"
|
||||
inkscape:cy="23.529886"
|
||||
inkscape:current-layer="text3796"
|
||||
showgrid="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:window-width="1280"
|
||||
inkscape:window-height="964"
|
||||
inkscape:window-x="-2"
|
||||
inkscape:window-y="-3"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata2821">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<g
|
||||
transform="scale(0.73872768,1.3536788)"
|
||||
style="font-size:54.21519089000000236px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#ff2600;fill-opacity:1;stroke:#731200;font-family:Arial;-inkscape-font-specification:Arial;color:#000000;fill-rule:nonzero;stroke-width:2.19132471;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="text3796">
|
||||
<path
|
||||
style="fill:#006dff;fill-opacity:1;stroke:#00064a;stroke-width:2.511;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
d="M 35.875,1.46875 C 23.796955,8.5932992 13.671794,15.531702 1.59375,22.65625 L 1.5262142,35.512284 25.146178,57.487034 C 38.295836,48.256178 49.93017,40.983609 62.53125,32.661357 L 62.5,20.375 z M 34.21875,11 c 0.944286,-0.02471 1.856367,0.01824 2.71875,0.125 5.174304,0.640572 8.736535,3.725759 8.625,8.125 C 45.413784,25.115665 38.743677,31.129674 30.71875,32.625 22.69382,34.120324 16.351286,30.584395 16.5,24.71875 16.648714,18.853088 23.256323,12.807817 31.28125,11.3125 32.284366,11.125586 33.274464,11.024709 34.21875,11 z"
|
||||
transform="scale(1.3536788,0.73872768)"
|
||||
id="path4322"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccccsssssss" />
|
||||
<path
|
||||
style="fill:url(#linearGradient4086);fill-opacity:1;stroke:#ff2600;stroke-width:1.88300000000000001;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
d="M 47.422587,7.4666373 C 37.741692,7.3258328 25.165048,9.4019748 21.63491,15.803574 c -1.782129,3.231735 1.883355,8.564261 11.619402,8.710079 -1.470251,-1.63897 -1.850349,-3.829208 -0.09522,-5.653618 1.616533,-1.680347 4.876995,-4.337842 13.919647,-4.950527 4.265983,-0.289042 13.824866,0.839183 14.118979,2.693386 4.214064,-4.85183 -1.391358,-8.95614 -13.775129,-9.1362567 z"
|
||||
id="path4020"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="sscsscs" />
|
||||
<path
|
||||
style="font-size:54.21519089px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;color:#000000;fill:#000fb4;fill-opacity:1;fill-rule:nonzero;stroke:#00064a;stroke-width:2.51117516;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Arial;-inkscape-font-specification:Arial"
|
||||
d="m 34.56101,32.350098 c -0.0147,4.214125 -0.07684,4.086221 -0.3698,9.962925 17.800417,-6.819089 33.707407,-11.674718 50.765217,-17.822596 l -0.0423,-9.076272 c -20.77416,6.613084 -26.37193,8.571552 -50.353117,16.935943 z"
|
||||
id="path4322-5"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
style="fill:none;stroke:#00064a;stroke-width:2.51117516000000007;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;fill-opacity:1"
|
||||
d="M 2.1232553,17.121812 C 12.690909,21.90558 23.498028,27.192766 34.065684,31.976533 l -0.13172,10.175684"
|
||||
id="path3677"
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;stroke:#ff2600;stroke-width:2.6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
d="m 24.019815,32.984123 c 7.913576,0.167149 16.463578,-1.446885 21.454591,-11.426902"
|
||||
id="path4621"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="scale(1.3536788,0.73872768)"
|
||||
sodipodi:nodetypes="cc" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 23 KiB |
450
src/Mod/PartDesign/FeatureHole/Standards.py
Normal file
450
src/Mod/PartDesign/FeatureHole/Standards.py
Normal file
|
@ -0,0 +1,450 @@
|
|||
# -*- coding: iso-8859-15 -*-
|
||||
#/******************************************************************************
|
||||
# * Copyright (c)2012 Jan Rheinlaender <jrheinlaender@users.sourceforge.net> *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
# * *
|
||||
# * This library is free software; you can redistribute it and/or *
|
||||
# * modify it under the terms of the GNU Library General Public *
|
||||
# * License as published by the Free Software Foundation; either *
|
||||
# * version 2 of the License, or (at your option) any later version. *
|
||||
# * *
|
||||
# * This library is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this library; see the file COPYING.LIB. If not, *
|
||||
# * write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
# * Suite 330, Boston, MA 02111-1307, USA *
|
||||
# * *
|
||||
# ******************************************************************************/
|
||||
|
||||
import FreeCAD
|
||||
|
||||
"Standards for bore hole feature"
|
||||
sources = {
|
||||
"inet_arcor" : "http://home.arcor.de/maschinenelemente2-din/DIN%20EN%2020273_Durchgangsl%F6cher%20fuer%20Schrauben.PDF",
|
||||
"inet_duckma" : "http://www.duckma.de/mb14/SiteDocs/DIN%20Grundlagen%20Maschinenbau.pdf",
|
||||
"klein_14" : "Klein: Einführung in die DIN-Normen, 14. Auflage. Stuttgart, Teubner 2008"
|
||||
}
|
||||
|
||||
StandardYear = 0
|
||||
StandardTitle = 1
|
||||
StandardSource = 2
|
||||
StandardType = 3
|
||||
|
||||
standards = {
|
||||
# "Standard name" : ("Year", "Title", "Source", "Type")
|
||||
"DIN 13-1" : ("1999", "Metrisches ISO-Gewinde allgemeiner Anwendung (Auszug); Nennmaße für Regelgewinde", "klein_14", "thread"),
|
||||
"DIN 74-A" : ("2003", "Senkungen fur Senkschrauben, ausgenommen Senkschrauben mit Kopfen nach DIN EN 27721; Form A", "klein_14", "countersink"),
|
||||
"DIN 74-E" : ("2003", "Senkungen fur Senkschrauben, ausgenommen Senkschrauben mit Kopfen nach DIN EN 27721; Form E", "klein_14", "countersink"),
|
||||
"DIN 74-F" : ("2003", "Senkungen fur Senkschrauben, ausgenommen Senkschrauben mit Kopfen nach DIN EN 27721; Form F", "klein_14", "countersink"),
|
||||
"DIN 76-2" : ("1984", "Gewindeausläufe und Gewindefreistiche (Auszug); für Metrisches ISO-Gewinde nach DIN 13; Innengewinde (Gewindegrundlöcher)", "klein_14", "threaded"),
|
||||
"DIN 974-1" : ("1991", "Senkdurchmesser für Schrauben mit Zylinderkopf; Konstruktionsmaße (Auszug)", "klein_14", "counterbore"),
|
||||
"DIN 974-2" : ("1991", "Senkdurchmesser fur Sechskantschrauben und Sechskantmuttern; Konstruktionsmaße(Auszug)", "klein_14", "counterbore"),
|
||||
"ISO 273" : ("1979", "Fasteners; Clearance holes for bolts and screws", "inet_arcor", "through"),
|
||||
"ISO 15065" : ("2005", "Senkungen fur Senkschrauben mit Kopfform nach ISO 7721", "klein_14", "countersink")
|
||||
}
|
||||
|
||||
aliases = {
|
||||
"ISO 273" : ("ISO 273:1979", "EN 20273:1991", "DIN EN 20273:1992", "DIN ISO 273", "DIN ISO 273/09.79"),
|
||||
"ISO 15065" : ("ISO 15065:2005", "EN ISO 15065", "EN ISO 15065:2005", "DIN EN ISO 15065")
|
||||
}
|
||||
|
||||
standards_tolerance = ("fine", "medium", "coarse")
|
||||
|
||||
standards_through = {
|
||||
# "Standard name" : (Thread_dia : Hole_dia(Fine, Medium, Coarse))
|
||||
"ISO 273" : {
|
||||
1.0 : (1.1, 1.2, 1.3),
|
||||
1.2 : (1.3, 1.4, 1.5),
|
||||
1.4 : (1.5, 1.6, 1.8),
|
||||
1.6 : (1.7, 1.8, 2.0),
|
||||
1.8 : (2.0, 2.1, 2.2),
|
||||
2.0 : (2.2, 2.4, 2.6),
|
||||
2.5 : (2.7, 2.9, 3.1),
|
||||
3.0 : (3.2, 3.4, 3.6),
|
||||
3.5 : (3.7, 3.9, 4.2),
|
||||
4.0 : (4.3, 4.5, 4.8),
|
||||
4.5 : (4.8, 5.0, 5.3),
|
||||
5.0 : (5.3, 5.5, 5.8),
|
||||
6.0 : (6.4, 6.6, 7.0),
|
||||
7.0 : (7.4, 7.6, 8.0),
|
||||
8.0 : (8.4, 9.0, 10),
|
||||
10.0: (10.5, 11, 12),
|
||||
12.0: (13, 13.5, 14.5),
|
||||
14.0: (15, 15.5, 16.5),
|
||||
16.0: (17, 17.5, 18.5),
|
||||
18.0: (19, 20, 21),
|
||||
20.0: (21, 22, 24),
|
||||
22.0: (23, 24, 26),
|
||||
24.0: (25, 26, 28),
|
||||
27.0: (28, 30, 32),
|
||||
30.0: (31, 33, 35),
|
||||
33.0: (34, 36, 38),
|
||||
36.0: (37, 39, 42),
|
||||
39.0: (40, 42, 45),
|
||||
42.0: (43, 45, 48),
|
||||
45.0: (46, 48, 52),
|
||||
48.0: (50, 52, 56),
|
||||
52.0: (54, 56, 62),
|
||||
56.0: (58, 62, 66),
|
||||
60.0: (62, 66, 70),
|
||||
64.0: (66, 70, 74),
|
||||
68.0: (70, 74, 80),
|
||||
72.0: (74, 78, 82),
|
||||
76.0: (78, 82, 86),
|
||||
80.0: (82, 86, 91),
|
||||
85.0: (87, 91, 96),
|
||||
90.0: (93, 96, 101),
|
||||
95.0: (98, 101, 107),
|
||||
100.0: (104, 107, 112),
|
||||
105.0: (109, 112, 117),
|
||||
110.0: (114, 117, 121),
|
||||
115.0: (119, 122, 127),
|
||||
120.0: (124, 127, 132),
|
||||
125.0: (129, 132, 137),
|
||||
130.0: (134, 137, 144),
|
||||
140.0: (144, 147, 155),
|
||||
150.0: (155, 158, 165)
|
||||
}
|
||||
}
|
||||
|
||||
standards_counterbore = {
|
||||
# "Standard name" : {Thread_dia : counterboredia(row1, row2, row3, row4, row5, row6)}
|
||||
"DIN 974-1" : {
|
||||
1.0 : (2.2, None, None, None, None, None),
|
||||
1.2 : (2.5, None, None, None, None, None),
|
||||
1.4 : (3.0, None, None, None, None, None),
|
||||
1.6 : (3.5, 3.5, None, None, None, None),
|
||||
1.8 : (3.8, None, None, None, None, None),
|
||||
2.0 : (4.4, 5.0, None, 5.5, 6, 6),
|
||||
2.5 : (5.5, 6, None, 6, 7, 7),
|
||||
3.0 : (6.5, 7, 6.5, 7, 9, 8),
|
||||
3.5 : (6.5, 8, 6.5, 8, 9, 9),
|
||||
4.0 : (8, 9, 8, 9, 10, 10),
|
||||
5.0 : (10, 11, 10, 11, 13, 13),
|
||||
6.0 : (11, 13, 11, 13, 15, 15),
|
||||
8.0 : (15, 18, 15, 16, 18, 20),
|
||||
10.0 : (18, 24, 18, 20, 24, 24),
|
||||
12.0 : (20, None, 20, 24, 26, 33),
|
||||
14.0 : (24, None, 24, 26, 30, 40),
|
||||
16.0 : (26, None, 26, 30, 33, 43),
|
||||
18.0 : (30, None, 30, 33, 36, 46),
|
||||
20.0 : (33, None, 33, 36, 40, 48),
|
||||
22.0 : (36, None, 36, 40, 43, 54),
|
||||
24.0 : (40, None, 40, 43, 48, 58),
|
||||
27.0 : (46, None, 46, 46, 54, 63),
|
||||
30.0 : (50, None, 50, 54, 61, 73),
|
||||
33.0 : (54, None, 54, None, 63, None),
|
||||
36.0 : (58, None, 58, 63, 69, None),
|
||||
42.0 : (69, None, 69, 73, 82, None),
|
||||
48.0 : (78, None, 78, 82, 98, None),
|
||||
56.0 : (93, None, 93, 93, 112, None),
|
||||
64.0 : (107, None, 107, 107, 125, None),
|
||||
72.0 : (118, None, 118, 118, 132, None),
|
||||
80.0 : (132, None, 132, 132, 150, None),
|
||||
90.0 : (145, None, 145, 145, 170, None),
|
||||
100.0:(160, None, 160, 160, 182, None)
|
||||
},
|
||||
"DIN 974-2" : {
|
||||
3.0 : (11, 11, 9),
|
||||
4.0 : (13, 15, 10),
|
||||
5.0 : (15, 18, 11),
|
||||
6.0 : (18, 20, 13),
|
||||
8.0 : (24, 26, 18),
|
||||
10.0:(28, 33, 22),
|
||||
12.0:(33, 36, 26),
|
||||
14.0:(36, 43, 30),
|
||||
16.0:(40, 46, 33),
|
||||
18.0:(43, 50, 36),
|
||||
20.0:(46, 54, 40),
|
||||
22.0:(54, 61, 46),
|
||||
24.0:(58, 73, 48),
|
||||
27.0:(61, 76, 54),
|
||||
30.0:(73, 82, 61),
|
||||
33.0:(76, 89, 69),
|
||||
36.0:(82, 93, 73),
|
||||
39.0:(89, 98, 76),
|
||||
42.0:(98, 107, 82),
|
||||
45.0:(107, 112, 89)
|
||||
}
|
||||
}
|
||||
|
||||
standards_counterbore_through = {
|
||||
# Standard name : Through hole standard name
|
||||
"DIN 74-A" : "ISO 273",
|
||||
"DIN 74-E" : "ISO 273", # Note that the standards seems to allow tolerance class "fine" only
|
||||
"DIN 74-F" : "ISO 273",
|
||||
"DIN 974-1" : "ISO 273",
|
||||
"DIN 974-2" : "ISO 273",
|
||||
"ISO 15065" : "ISO 273"
|
||||
}
|
||||
|
||||
standards_counterbore_rows = {
|
||||
# Row index : ( extra standards e.g. bolt used or washer used )
|
||||
# Note that DIN 7980 has been cancelled, therefore row three should not be used any more
|
||||
"DIN 974-1" : {
|
||||
1 : ("ISO 1207", "ISO 4762", "DIN 6912", "DIN 7984"),
|
||||
2 : ("ISO 1580", "ISO 7045"),
|
||||
3 : ("DIN 7980", ""), # single value gives wrong iteration when collecting the standards
|
||||
4 : ("ISO 10673 type C", "DIN 6798", "DIN 6907"),
|
||||
5 : ("ISO 7089", "ISO 7090", "ISO 10673 type A"),
|
||||
6 : ("DIN 6796", "DIN 6908")
|
||||
},
|
||||
"DIN 974-2" : {
|
||||
1 : ("DIN 659", "DIN 896", "DIN 3112", "DIN 3124"),
|
||||
2 : ("DIN 838", "DIN 897", "DIN 3129"),
|
||||
3 : ("tight", "")
|
||||
}
|
||||
}
|
||||
|
||||
standards_counterbore_extradepth = {
|
||||
# max Thread diameter : extra depth
|
||||
1.4 : 0.2,
|
||||
6.0 : 0.4,
|
||||
20.0 : 0.6,
|
||||
27.0 : 0.8,
|
||||
100.0 : 1.0
|
||||
}
|
||||
|
||||
standards_countersink_dia = 0
|
||||
standards_countersink_angle = 1
|
||||
|
||||
standards_countersink = {
|
||||
# "Standard name" : {Thread_dia : (countersinkdia, head angle)}
|
||||
"DIN 74-A" : {
|
||||
1.6 : (3.7, 90.0),
|
||||
2.0 : (4.6, 90.0),
|
||||
2.5 : (5.7, 90.0),
|
||||
3.0 : (6.5, 90.0),
|
||||
3.5 : (7.6, 90.0),
|
||||
4.0 : (8.6, 90.0),
|
||||
4.5 : (9.5, 90.0),
|
||||
5.0 : (10.4, 90.0),
|
||||
5.5 : (11.4, 90.0),
|
||||
6.0 : (12.4, 90.0),
|
||||
7.0 : (14.4, 90.0),
|
||||
8.0 : (16.4, 90.0)
|
||||
},
|
||||
"DIN 74-E" : {
|
||||
10.0 : (19.0, 75.0),
|
||||
12.0 : (24.0, 75.0),
|
||||
16.0 : (31.0, 75.0),
|
||||
20.0 : (34.0, 60.0),
|
||||
22.0 : (37.0, 60.0),
|
||||
24.0 : (40.0, 60.0)
|
||||
},
|
||||
"DIN 74-F" : {
|
||||
3.0 : (6.94, 90.0),
|
||||
4.0 : (9.18, 90.0),
|
||||
5.0 : (11.47, 90.0),
|
||||
6.0 : (13.71, 90.0),
|
||||
8.0 : (18.25, 90.0),
|
||||
10.0 : (22.73, 90.0),
|
||||
12.0 : (27.21, 90.0),
|
||||
14.0 : (31.19, 90.0),
|
||||
16.0 : (33.39, 90.0),
|
||||
20.0 : (40.71, 90.0)
|
||||
},
|
||||
"ISO 15065" : {
|
||||
2.0 : (4.4, 90.0),
|
||||
3.0 : (6.3, 90.0),
|
||||
4.0 : (9.4, 90.0),
|
||||
5.0 : (0.4, 90.0),
|
||||
6.0 : (12.6, 90.0),
|
||||
8.0 : (17.3, 90.0),
|
||||
10.0 : (20.0, 90.0)
|
||||
}
|
||||
}
|
||||
|
||||
standards_threaded_types = ("normal", "short", "long")
|
||||
|
||||
standards_threaded = {
|
||||
# Standard name : { Tread pitch : threadFinish(normal, short, long) }
|
||||
"DIN 76-2" : {
|
||||
0.20 : (1.3, 0.8, 2.0),
|
||||
0.25 : (1.5, 1.0, 2.4),
|
||||
0.30 : (1.8, 1.2, 2.9),
|
||||
0.35 : (2.1, 1.3, 3.3),
|
||||
0.40 : (2.3, 1.5, 3.7),
|
||||
0.45 : (2.6, 1.6, 4.1),
|
||||
0.50 : (2.8, 1.8, 4.5),
|
||||
0.60 : (3.4, 2.1, 5.4),
|
||||
0.70 : (3.8, 2.4, 6.1),
|
||||
0.75 : (4.0 , 2.5, 6.4),
|
||||
0.80 : (4.2, 2.7, 6.8),
|
||||
1.00 : (5.1, 3.2, 8.2),
|
||||
1.25 : (6.2, 3.9, 10),
|
||||
1.5 : (7.3, 4.6, 11.6),
|
||||
1.75 : (8.3, 5.2, 13.3),
|
||||
2.0 : (9.3, 5.8, 14.8),
|
||||
2.5 : (11.2, 7.0, 17.9),
|
||||
3.0 : (13.1, 8.2, 21.0),
|
||||
3.5 : (15.2, 9.5, 24.3),
|
||||
4.0 : (16.8, 10.5, 26.9),
|
||||
4.5 : (18.4, 11.5, 29.4),
|
||||
5.0 : (20.8, 13.0, 33.3),
|
||||
5.5 : (22.4, 14.0, 35.8),
|
||||
6.0 : (24.0, 15, 38.4)
|
||||
}
|
||||
}
|
||||
|
||||
standards_threaded_thread = {
|
||||
# Standard name for thread attribute : standard name for thread }
|
||||
"DIN 76-2" : "DIN 13-1"
|
||||
}
|
||||
|
||||
standards_thread_pitch = 0
|
||||
standards_thread_flankdia = 1
|
||||
standards_thread_outercoredia = 2
|
||||
standards_thread_innercoredia = 3
|
||||
standards_thread_outerdepth = 4
|
||||
standards_thread_innerdepth = 5
|
||||
standards_thread_round = 6
|
||||
|
||||
standards_thread = {
|
||||
# Standard name : { Thread diameter : (pitch, flank diameter, core diameter, thread depth outer, thread depth inner, round) }
|
||||
# Note: This table only has the most common thread diameters
|
||||
"DIN 13-1" : {
|
||||
1.0 : (0.25, 0.838, 0.693, 0.729, 0.153, 0.135, 0.036),
|
||||
1.1 : (0.25, 0.938, 0.793, 0.829, 0.153, 0.135, 0.036),
|
||||
1.2 : (0.25, 1.038, 0.893, 0.929, 0.153, 0.135, 0.036),
|
||||
2.0 : (0.4, 1.740, 1.509, 1.567, 0.245, 0.217, 0.058),
|
||||
3.0 : (0.5, 2.675, 2.387, 2.459, 0.307, 0.271, 0.072),
|
||||
4.0 : (0.7, 3.545, 3.141, 3.242, 0.429, 0.379, 0.101 ),
|
||||
5.0 : (0.8, 4.480, 4.019, 4.134, 0.491, 0.433, 0.115),
|
||||
6.0 : (1.0, 5.350, 4.773, 4.917, 0.613, 0.541, 0.144),
|
||||
7.0 : (1.0, 6.350, 5.773, 5.917, 0.613, 0.541, 0.144),
|
||||
8.0 : (1.25, 7.188, 6.466, 6.647, 0.767, 0.677, 0.180),
|
||||
10.0 : (1.5, 9.026, 8.160, 8.376, 0.920, 0.812, 0.217),
|
||||
12.0 : (1.75, 10.863, 9.853, 10.106, 1.074, 0.947, 0.253),
|
||||
14.0 : (2.0, 12.701, 11.546, 11.835, 1.227, 1.083, 0.289),
|
||||
16.0 : (2.0, 14.701, 13.546, 13.835, 1.227, 1.083, 0.289),
|
||||
18.0 : (2.5, 16.376, 14.933, 15.294, 1.534, 1.353, 0.361),
|
||||
20.0 : (2.5, 18.376, 16.933, 17.294, 1.534, 1.353, 0.361),
|
||||
22.0 : (2.5, 20.376, 18.933, 19.294, 1.534, 1.353, 0.361),
|
||||
24.0 : (3.0, 22.051, 20.319, 20.752, 1.840, 1.624, 0.433),
|
||||
27.0 : (3.0, 25.051, 23.319, 23.752, 1.840, 1.624, 0.433),
|
||||
30.0 : (3.5, 27.727, 25.706, 26.211, 2.147, 1.894, 0.505),
|
||||
33.0 : (3.5, 30.727, 28.706, 29.211, 2.147, 1.894, 0.505),
|
||||
36.0 : (4.0, 33.402, 31.093, 31.670, 2.454, 2.165, 0.577),
|
||||
39.0 : (4.0, 36.402, 34.093, 34.670, 2.454, 2.165, 0.577),
|
||||
42.0 : (4.5 , 39.077, 36.479, 37.129, 2.760, 2.436, 0.650),
|
||||
45.0 : (4.5, 42.077, 39.479, 40.129, 2.760, 2.436, 0.650)
|
||||
}
|
||||
}
|
||||
|
||||
def getStandards(holetype):
|
||||
"Return the names of all available standards for the given hole type"
|
||||
result = []
|
||||
for key, value in standards.items():
|
||||
if value[StandardType] == holetype:
|
||||
result.append(key)
|
||||
|
||||
#FreeCAD.Console.PrintMessage("Number of matching standards: " + str(len(result)) + "\n")
|
||||
return sorted(result)
|
||||
|
||||
def getBaseDiameters(standard):
|
||||
"Return the base diameters of all holes defined in the given norm"
|
||||
if not standard in standards.keys():
|
||||
return []
|
||||
#FreeCAD.Console.PrintMessage("Getting diameters for " + standard + "\n")
|
||||
if standards[standard][StandardType] == "through":
|
||||
return standards_through[standard].keys()
|
||||
elif standards[standard][StandardType] == "counterbore":
|
||||
return standards_counterbore[standard].keys()
|
||||
elif standards[standard][StandardType] == "countersink":
|
||||
return standards_countersink[standard].keys()
|
||||
elif standards[standard][StandardType] == "thread":
|
||||
return standards_thread[standard].keys()
|
||||
return []
|
||||
|
||||
def getThroughHoleDia(standard, threadDia, tolerance = "medium"):
|
||||
if not standard in standards_through.keys():
|
||||
raise Exception("No such standard exists")
|
||||
values = standards_through[standard]
|
||||
if not threadDia in values:
|
||||
FreeCAD.Console.PrintMessage("Warning: Diameter %f is not in %s" % (threadDia, standard))
|
||||
return values[values.keys()[0]][standards_tolerance.index(tolerance)]
|
||||
return values[threadDia][standards_tolerance.index(tolerance)]
|
||||
|
||||
def getThroughHoleStandard(standard):
|
||||
if not standard in standards_counterbore_through.keys():
|
||||
raise Exception("No such standard exists")
|
||||
return standards_counterbore_through[standard]
|
||||
|
||||
def getCounterboreDia(standard, threadDia, extraStandard = ""):
|
||||
if not standard in standards_counterbore.keys():
|
||||
raise Exception("No such standard exists")
|
||||
values = standards_counterbore[standard]
|
||||
if not threadDia in values:
|
||||
FreeCAD.Console.PrintMessage("Warning: Diameter %f is not in %s" % (threadDia, standard))
|
||||
return values[values.keys()[0]][0]
|
||||
row = 1 # Use row 1 by default
|
||||
for r in standards_counterbore_rows[standard].keys():
|
||||
if extraStandard in standards_counterbore_rows[standard][r]:
|
||||
row = r
|
||||
break
|
||||
return values[threadDia][row-1]
|
||||
|
||||
def calcCounterboreDepth(standard, threadDia, standardBolt, standardsWashers = []):
|
||||
headHeight = getBoltHead(standardBolt)
|
||||
washerHeight = 0.0
|
||||
for standard in standardsWashers:
|
||||
washerHeight = washerHeight + getWasherHeight(standard)
|
||||
for maxThread in reverse(standards_counterbore_extradepth.keys()):
|
||||
if threadDia <= maxThread:
|
||||
extraDepth = standards_counterbore_extradepth[maxThread]
|
||||
return headHeight + washerHeight + extraDepth
|
||||
|
||||
def getRowStandards(standard):
|
||||
if not standard in standards_counterbore_rows.keys():
|
||||
raise Exception("No such standard exists")
|
||||
result = []
|
||||
rowdict = standards_counterbore_rows[standard]
|
||||
for stds in rowdict.values():
|
||||
for std in stds:
|
||||
if std != "":
|
||||
result.append(std)
|
||||
return result
|
||||
|
||||
def getCountersinkDia(standard, threadDia):
|
||||
if not standard in standards_countersink.keys():
|
||||
raise Exception("No such standard exists")
|
||||
values = standards_countersink[standard]
|
||||
if not threadDia in values:
|
||||
FreeCAD.Console.PrintMessage("Warning: Diameter %f is not in %s" % (threadDia, standard))
|
||||
return values[values.keys()[0]][standards_countersink_dia]
|
||||
return values[threadDia][standards_countersink_dia]
|
||||
|
||||
def getCountersinkAngle(standard, threadDia):
|
||||
if not standard in standards_countersink.keys():
|
||||
raise Exception("No such standard exists")
|
||||
values = standards_countersink[standard]
|
||||
if not threadDia in values:
|
||||
FreeCAD.Console.PrintMessage("Warning: Diameter %f is not in %s" % (threadDia, standard))
|
||||
return values[values.keys()[0]][standards_countersink_angle]
|
||||
return values[threadDia][standards_countersink_angle]
|
||||
|
||||
def getThreadCoreDiameter(standard, threadDia):
|
||||
if not standard in standards_thread.keys():
|
||||
raise Exception("No such standard exists")
|
||||
values = standards_thread[standard]
|
||||
if not threadDia in values:
|
||||
FreeCAD.Console.PrintMessage("Warning: Diameter %f is not in %s" % (threadDia, standard))
|
||||
return values[values.keys()[0]][standards_thread_innercoredia]
|
||||
return values[threadDia][standards_thread_innercoredia]
|
||||
|
||||
def getThreadFinishLength(standard, threadDia, length = "normal"):
|
||||
if not standard in standards_threaded.keys():
|
||||
raise Exception("No such standard exists")
|
||||
stdThread = standards_threaded_thread[standard]
|
||||
values = standards_thread[stdThread]
|
||||
if not threadDia in values:
|
||||
FreeCAD.Console.PrintMessage("Warning: Diameter %f is not in %s" % (threadDia, standard))
|
||||
return values[values.keys()[0]][standards_thread_pitch]
|
||||
pitch = values[threadDia][standards_thread_pitch]
|
||||
return standards_threaded[standard][pitch][standards_threaded_types.index(length)]
|
659
src/Mod/PartDesign/FeatureHole/TaskHole.py
Normal file
659
src/Mod/PartDesign/FeatureHole/TaskHole.py
Normal file
|
@ -0,0 +1,659 @@
|
|||
#/******************************************************************************
|
||||
# * Copyright (c)2012 Jan Rheinlaender <jrheinlaender@users.sourceforge.net> *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
# * *
|
||||
# * This library is free software; you can redistribute it and/or *
|
||||
# * modify it under the terms of the GNU Library General Public *
|
||||
# * License as published by the Free Software Foundation; either *
|
||||
# * version 2 of the License, or (at your option) any later version. *
|
||||
# * *
|
||||
# * This library is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this library; see the file COPYING.LIB. If not, *
|
||||
# * write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
# * Suite 330, Boston, MA 02111-1307, USA *
|
||||
# * *
|
||||
# ******************************************************************************/
|
||||
|
||||
import FreeCAD, FreeCADGui
|
||||
import Part, PartDesignGui
|
||||
from PyQt4 import QtCore, QtGui
|
||||
import Standards
|
||||
import os
|
||||
|
||||
class TaskHole:
|
||||
"Hole hole feature"
|
||||
types = ["Linear", "Coaxial"]
|
||||
typestr = ["Linear to two lines/planes", "Coaxial to a circle/cylinder"]
|
||||
|
||||
def __init__(self, feature):
|
||||
self.form = None
|
||||
self.extraStandards = []
|
||||
self.feature = feature
|
||||
p=os.path.realpath(__file__)
|
||||
p=os.path.dirname(p)
|
||||
self.ui = os.path.join(p, "TaskHole.ui")
|
||||
|
||||
def accept(self):
|
||||
self.feature.touch()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
FreeCADGui.ActiveDocument.resetEdit()
|
||||
return True
|
||||
|
||||
def reject(self):
|
||||
if (self.feature != None):
|
||||
self.hideFeature() # Show the support again
|
||||
document = self.feature.Document
|
||||
body = PartDesignGui.getActivePart()
|
||||
groove = self.feature.HoleGroove
|
||||
sketch = groove.Sketch
|
||||
plane = sketch.Support[0]
|
||||
axis = plane.References[0][0]
|
||||
body.removeFeature(self.feature)
|
||||
document.removeObject(self.feature.Name)
|
||||
body.removeFeature(groove)
|
||||
document.removeObject(groove.Name)
|
||||
body.removeFeature(sketch)
|
||||
try:
|
||||
document.removeObject(sketch.Name)
|
||||
except:
|
||||
pass # This always throws an exception: "Sketch support has been deleted" from SketchObject::execute()
|
||||
body.removeFeature(plane)
|
||||
document.removeObject(plane.Name)
|
||||
body.removeFeature(axis)
|
||||
document.removeObject(axis.Name)
|
||||
FreeCADGui.ActiveDocument.resetEdit()
|
||||
FreeCADGui.Control.closeDialog(self)
|
||||
return True
|
||||
|
||||
def isAllowedAlterDocument(self):
|
||||
return False
|
||||
|
||||
def isAllowedAlterView(self):
|
||||
return False
|
||||
|
||||
def isAllowedAlterSelection(self):
|
||||
return True
|
||||
|
||||
def getMainWindow(self):
|
||||
"returns the main window"
|
||||
# using QtGui.qApp.activeWindow() isn't very reliable because if another
|
||||
# widget than the mainwindow is active (e.g. a dialog) the wrong widget is
|
||||
# returned
|
||||
toplevel = QtGui.qApp.topLevelWidgets()
|
||||
for i in toplevel:
|
||||
if i.metaObject().className() == "Gui::MainWindow":
|
||||
return i
|
||||
raise Exception("No main window found")
|
||||
|
||||
def setupUi(self):
|
||||
mw = self.getMainWindow()
|
||||
form = mw.findChild(QtGui.QWidget, "TaskHole")
|
||||
if form == None:
|
||||
return
|
||||
form.tabWidget = form.findChild(QtGui.QTabWidget, "tabWidget")
|
||||
# Type
|
||||
form.tabType = form.tabWidget.findChild(QtGui.QWidget, "tab_type")
|
||||
form.buttonThru = form.tabType.findChild(QtGui.QRadioButton, "buttonThru")
|
||||
form.buttonDepth = form.tabType.findChild(QtGui.QRadioButton, "buttonDepth")
|
||||
form.checkThreaded = form.tabType.findChild(QtGui.QCheckBox, "checkThreaded")
|
||||
form.checkCounterbore = form.tabType.findChild(QtGui.QCheckBox, "checkCounterbore")
|
||||
form.checkCountersink = form.tabType.findChild(QtGui.QCheckBox, "checkCountersink")
|
||||
# Norm
|
||||
form.tabNorm = form.tabWidget.findChild(QtGui.QWidget, "tab_norm")
|
||||
form.checkCustom = form.tabNorm.findChild(QtGui.QCheckBox, "checkCustom")
|
||||
form.comboNorm = form.tabNorm.findChild(QtGui.QComboBox, "comboNorm")
|
||||
for std in Standards.getStandards("through"):
|
||||
form.comboNorm.addItem(std)
|
||||
form.comboTolerance = form.tabNorm.findChild(QtGui.QComboBox, "comboTolerance")
|
||||
for tol in Standards.standards_tolerance:
|
||||
form.comboTolerance.addItem(tol)
|
||||
form.comboNormDia = form.tabNorm.findChild(QtGui.QComboBox, "comboNormDia")
|
||||
form.comboNormBoltWasher = form.tabNorm.findChild(QtGui.QComboBox, "comboNormBoltWasher")
|
||||
# Thread
|
||||
form.tabThread = form.tabWidget.findChild(QtGui.QWidget, "tab_thread")
|
||||
form.comboThreadNorm = form.tabThread.findChild(QtGui.QComboBox, "comboThreadNorm")
|
||||
for std in Standards.getStandards("thread"):
|
||||
form.comboThreadNorm.addItem(std)
|
||||
form.comboThreadDia = form.tabThread.findChild(QtGui.QComboBox, "comboThreadDia")
|
||||
form.checkCustomThreadLength = form.tabThread.findChild(QtGui.QCheckBox, "checkCustomThreadLength")
|
||||
form.comboFinishNorm = form.tabThread.findChild(QtGui.QComboBox, "comboFinishNorm")
|
||||
for std in Standards.getStandards("threaded"):
|
||||
form.comboFinishNorm.addItem(std)
|
||||
# Data
|
||||
form.tabData = form.tabWidget.findChild(QtGui.QWidget, "tab_data")
|
||||
form.spinDiameter = form.tabData.findChild(QtGui.QDoubleSpinBox, "spinDiameter")
|
||||
form.spinDepth = form.tabData.findChild(QtGui.QDoubleSpinBox, "spinDepth")
|
||||
form.spinCounterboreDiameter = form.tabData.findChild(QtGui.QDoubleSpinBox, "spinCounterboreDiameter")
|
||||
form.spinCounterboreDepth = form.tabData.findChild(QtGui.QDoubleSpinBox, "spinCounterboreDepth")
|
||||
form.spinCountersinkAngle = form.tabData.findChild(QtGui.QDoubleSpinBox, "spinCountersinkAngle")
|
||||
form.spinThreadLength = form.tabData.findChild(QtGui.QDoubleSpinBox, "spinThreadLength")
|
||||
# Position
|
||||
form.tabPosition = form.tabWidget.findChild(QtGui.QWidget, "tab_position")
|
||||
form.comboType = form.tabPosition.findChild(QtGui.QComboBox, "comboType")
|
||||
for i in self.typestr:
|
||||
form.comboType.addItem(i)
|
||||
form.buttonSupport = form.tabPosition.findChild(QtGui.QPushButton, "buttonSupport")
|
||||
form.lineSupport = form.tabPosition.findChild(QtGui.QLineEdit, "lineSupport")
|
||||
form.buttonRef1 = form.tabPosition.findChild(QtGui.QPushButton, "buttonRef1")
|
||||
form.lineRef1 = form.tabPosition.findChild(QtGui.QLineEdit, "lineRef1")
|
||||
form.labelRef1 = form.tabPosition.findChild(QtGui.QLabel, "labelRef1")
|
||||
form.spinRef1 = form.tabPosition.findChild(QtGui.QDoubleSpinBox, "spinRef1")
|
||||
form.buttonRef2 = form.tabPosition.findChild(QtGui.QPushButton, "buttonRef2")
|
||||
form.lineRef2 = form.tabPosition.findChild(QtGui.QLineEdit, "lineRef2")
|
||||
form.labelRef2 = form.tabPosition.findChild(QtGui.QLabel, "labelRef2")
|
||||
form.spinRef2 = form.tabPosition.findChild(QtGui.QDoubleSpinBox, "spinRef2")
|
||||
self.form = form
|
||||
|
||||
# Connect Signals and Slots
|
||||
# Type
|
||||
self.form.buttonThru.toggled.connect(self.buttonThru)
|
||||
self.form.buttonDepth.toggled.connect(self.buttonDepth)
|
||||
self.form.checkThreaded.toggled.connect(self.checkThreaded)
|
||||
self.form.checkCounterbore.toggled.connect(self.checkCounterbore)
|
||||
self.form.checkCountersink.toggled.connect(self.checkCountersink)
|
||||
# Norm
|
||||
self.form.checkCustom.toggled.connect(self.checkCustom)
|
||||
self.form.comboNorm.currentIndexChanged.connect(self.comboNorm)
|
||||
self.form.comboTolerance.currentIndexChanged.connect(self.comboTolerance)
|
||||
self.form.comboNormDia.currentIndexChanged.connect(self.comboNormDia)
|
||||
self.form.comboNormBoltWasher.currentIndexChanged.connect(self.comboNormBoltWasher)
|
||||
# Thread
|
||||
self.form.comboThreadNorm.currentIndexChanged.connect(self.comboThreadNorm)
|
||||
self.form.comboThreadDia.currentIndexChanged.connect(self.comboThreadDia)
|
||||
self.form.checkCustomThreadLength.toggled.connect(self.checkCustomThreadLength)
|
||||
self.form.comboFinishNorm.currentIndexChanged.connect(self.comboFinishNorm)
|
||||
# Data
|
||||
self.form.spinDiameter.valueChanged.connect(self.spinDiameter)
|
||||
self.form.spinDepth.valueChanged.connect(self.spinDepth)
|
||||
self.form.spinCounterboreDiameter.valueChanged.connect(self.spinCounterboreDiameter)
|
||||
self.form.spinCounterboreDepth.valueChanged.connect(self.spinCounterboreDepth)
|
||||
self.form.spinCountersinkAngle.valueChanged.connect(self.spinCountersinkAngle)
|
||||
self.form.spinThreadLength.valueChanged.connect(self.spinThreadLength)
|
||||
# Position
|
||||
self.form.comboType.currentIndexChanged.connect(self.comboType)
|
||||
self.form.buttonSupport.clicked.connect(self.buttonSupport)
|
||||
self.form.buttonRef1.clicked.connect(self.buttonRef1)
|
||||
self.form.spinRef1.valueChanged.connect(self.spinRef1)
|
||||
self.form.buttonRef2.clicked.connect(self.buttonRef2)
|
||||
self.form.spinRef2.valueChanged.connect(self.spinRef2)
|
||||
|
||||
# Update the UI
|
||||
self.updateUI()
|
||||
|
||||
def getRefText(self, ref):
|
||||
(obj, element) = ref
|
||||
if isinstance(element, basestring):
|
||||
return obj.Name + ":" + element
|
||||
elif isinstance(element, list):
|
||||
return obj.Name + ":" + element[0]
|
||||
else:
|
||||
return obj.Name
|
||||
|
||||
def updateUI(self):
|
||||
# Type
|
||||
self.form.buttonThru.setChecked(self.feature.HoleType == "Thru")
|
||||
self.form.buttonDepth.setChecked(self.feature.HoleType == "Depth")
|
||||
self.form.checkThreaded.setChecked(self.feature.Threaded == True)
|
||||
self.form.checkCounterbore.setChecked(self.feature.Counterbore == True)
|
||||
self.form.checkCountersink.setChecked(self.feature.Countersink == True)
|
||||
# Norm
|
||||
if self.feature.Norm == "Custom":
|
||||
self.form.checkCustom.setChecked(True)
|
||||
self.form.comboNorm.setEnabled(False)
|
||||
self.form.comboTolerance.setEnabled(False)
|
||||
self.form.comboNormDia.setEnabled(False)
|
||||
self.form.comboNormBoltWasher.setEnabled(False)
|
||||
else:
|
||||
if self.feature.Counterbore == True:
|
||||
holetype = "counterbore"
|
||||
elif self.feature.Countersink == True:
|
||||
holetype = "countersink"
|
||||
elif self.feature.Threaded == True:
|
||||
holetype = "threaded"
|
||||
else:
|
||||
holetype = "through"
|
||||
self.form.comboNorm.setEnabled(True)
|
||||
self.form.comboTolerance.setEnabled(True)
|
||||
self.form.comboNormDia.setEnabled(True)
|
||||
if holetype == "counterbore":
|
||||
self.form.comboNormBoltWasher.setEnabled(True)
|
||||
else:
|
||||
self.form.comboNormBoltWasher.setEnabled(False)
|
||||
# comboNorm
|
||||
standards = Standards.getStandards(holetype)
|
||||
self.form.comboNorm.blockSignals(True)
|
||||
self.form.comboNorm.clear()
|
||||
for std in standards:
|
||||
self.form.comboNorm.addItem(std)
|
||||
if not self.feature.Norm in standards:
|
||||
self.feature.Norm = standards[0]
|
||||
else:
|
||||
self.form.comboNorm.setCurrentIndex(standards.index(self.feature.Norm))
|
||||
self.form.comboNorm.blockSignals(False)
|
||||
# comboTolerance
|
||||
self.form.comboTolerance.blockSignals(True)
|
||||
self.form.comboTolerance.setCurrentIndex(Standards.standards_tolerance.index(self.feature.NormTolerance))
|
||||
self.form.comboTolerance.blockSignals(False)
|
||||
# comboNormDia
|
||||
diameters = sorted(Standards.getBaseDiameters(self.feature.Norm))
|
||||
self.form.comboNormDia.blockSignals(True)
|
||||
self.form.comboNormDia.clear()
|
||||
for dia in diameters:
|
||||
self.form.comboNormDia.addItem("M%g" % dia)
|
||||
if self.feature.NormDiameter in diameters:
|
||||
self.form.comboNormDia.setCurrentIndex(diameters.index(self.feature.NormDiameter))
|
||||
self.form.comboNormDia.blockSignals(False)
|
||||
# comboNormBoltWasher
|
||||
if holetype == "counterbore":
|
||||
rowStandards = sorted(Standards.getRowStandards(self.feature.Norm))
|
||||
self.form.comboNormBoltWasher.blockSignals(True)
|
||||
self.form.comboNormBoltWasher.clear()
|
||||
for std in rowStandards:
|
||||
self.form.comboNormBoltWasher.addItem(std)
|
||||
if self.feature.ExtraNorm in rowStandards:
|
||||
self.form.comboNormBoltWasher.setCurrentIndex(rowStandards.index(self.feature.ExtraNorm))
|
||||
self.form.comboNormBoltWasher.blockSignals(False)
|
||||
# Dependent values
|
||||
if holetype == "through":
|
||||
self.feature.Diameter = Standards.getThroughHoleDia(self.feature.Norm, self.feature.NormDiameter, self.feature.NormTolerance)
|
||||
elif holetype == "counterbore":
|
||||
throughStandard = Standards.getThroughHoleStandard(self.feature.Norm)
|
||||
self.feature.Diameter = Standards.getThroughHoleDia(throughStandard, self.feature.NormDiameter, self.feature.NormTolerance)
|
||||
self.feature.CounterboreDiameter = Standards.getCounterboreDia(self.feature.Norm, self.feature.NormDiameter, self.feature.ExtraNorm)
|
||||
# TODO: Calculate counter bore depth from standard for bolt and washer(s)
|
||||
# Requires accessing all the norms for bolts
|
||||
# self.feature.CounterboreDepth = calcCounterboreDepth(...)
|
||||
elif holetype == "countersink":
|
||||
throughStandard = Standards.getThroughHoleStandard(self.feature.Norm)
|
||||
self.feature.Diameter = Standards.getThroughHoleDia(throughStandard, self.feature.NormDiameter, self.feature.NormTolerance)
|
||||
self.feature.CounterboreDiameter = Standards.getCountersinkDia(self.feature.Norm, self.feature.NormDiameter)
|
||||
self.feature.CountersinkAngle = Standards.getCountersinkAngle(self.feature.Norm, self.feature.NormDiameter) / 2.0
|
||||
# Thread
|
||||
if self.feature.Threaded == True:
|
||||
if not self.feature.Counterbore and not self.feature.Countersink:
|
||||
self.form.comboTolerance.setEnabled(False)
|
||||
else:
|
||||
self.form.tabNorm.setEnabled(True)
|
||||
self.form.comboTolerance.setEnabled(False)
|
||||
self.form.tabThread.setEnabled(True)
|
||||
self.form.comboThreadNorm.blockSignals(True)
|
||||
standards = Standards.getStandards("thread")
|
||||
if not self.feature.NormThread in standards:
|
||||
self.feature.NormThread = standards[0]
|
||||
else:
|
||||
self.form.comboThreadNorm.setCurrentIndex(standards.index(self.feature.NormThread))
|
||||
self.form.comboThreadNorm.blockSignals(False)
|
||||
threadDiameters = sorted(Standards.getBaseDiameters(self.feature.NormThread))
|
||||
self.form.comboThreadDia.blockSignals(True)
|
||||
self.form.comboThreadDia.clear()
|
||||
for dia in threadDiameters:
|
||||
self.form.comboThreadDia.addItem("M%g" % dia)
|
||||
if self.feature.NormDiameter in threadDiameters:
|
||||
self.form.comboThreadDia.setCurrentIndex(threadDiameters.index(self.feature.NormDiameter))
|
||||
self.form.comboThreadDia.blockSignals(False)
|
||||
if self.feature.NormThreadFinish == "Custom":
|
||||
self.form.checkCustomThreadLength.setChecked(True)
|
||||
self.form.comboFinishNorm.setEnabled(False)
|
||||
else:
|
||||
self.form.checkCustomThreadLength.setChecked(False)
|
||||
self.form.comboFinishNorm.setEnabled(True)
|
||||
self.form.comboFinishNorm.blockSignals(True)
|
||||
standards = Standards.getStandards("threaded")
|
||||
if not self.feature.NormThreadFinish in standards:
|
||||
self.feature.NormThreadFinish = standards[0]
|
||||
else:
|
||||
self.form.comboFinishNorm.setCurrentIndex(standards.index(self.feature.NormThreadFinish))
|
||||
self.form.comboFinishNorm.blockSignals(False)
|
||||
flength = Standards.getThreadFinishLength(self.feature.NormThreadFinish, self.feature.NormDiameter)
|
||||
tlength = self.feature.Depth - flength
|
||||
if tlength > 0:
|
||||
self.feature.ThreadLength = tlength # TODO: Warning message
|
||||
# Dependents
|
||||
self.feature.Diameter = Standards.getThreadCoreDiameter(self.feature.NormThread, self.feature.NormDiameter)
|
||||
else:
|
||||
self.form.tabThread.setEnabled(False)
|
||||
# Dependents
|
||||
self.form.spinDiameter.setEnabled(True)
|
||||
# Data
|
||||
self.form.spinDiameter.setValue(self.feature.Diameter)
|
||||
self.form.spinDepth.setValue(self.feature.Depth)
|
||||
if self.feature.HoleType == "Thru":
|
||||
self.form.spinDepth.setEnabled(False)
|
||||
else:
|
||||
self.form.spinDepth.setEnabled(True)
|
||||
if self.feature.Threaded == True:
|
||||
self.form.spinThreadLength.setEnabled(True)
|
||||
else:
|
||||
self.form.spinThreadLength.setEnabled(False)
|
||||
if self.feature.Counterbore == True:
|
||||
self.form.spinCounterboreDiameter.setEnabled(True)
|
||||
self.form.spinCounterboreDiameter.setValue(self.feature.CounterboreDiameter)
|
||||
self.form.spinCounterboreDepth.setEnabled(True)
|
||||
self.form.spinCounterboreDepth.setValue(self.feature.CounterboreDepth)
|
||||
self.form.spinCountersinkAngle.setEnabled(False)
|
||||
elif self.feature.Countersink == True:
|
||||
self.form.spinCounterboreDiameter.setEnabled(True)
|
||||
self.form.spinCounterboreDiameter.setValue(self.feature.CounterboreDiameter)
|
||||
self.form.spinCounterboreDepth.setEnabled(False)
|
||||
self.form.spinCountersinkAngle.setEnabled(True)
|
||||
self.form.spinCountersinkAngle.setValue(self.feature.CountersinkAngle)
|
||||
else:
|
||||
self.form.spinCounterboreDiameter.setEnabled(False)
|
||||
self.form.spinCounterboreDepth.setEnabled(False)
|
||||
self.form.spinCountersinkAngle.setEnabled(False)
|
||||
if self.feature.Norm == "Custom":
|
||||
self.form.spinDiameter.setEnabled(True)
|
||||
else:
|
||||
self.form.spinDiameter.setEnabled(False)
|
||||
if holetype == "counterbore":
|
||||
# Diameter is taken from Norm
|
||||
self.form.spinCounterboreDiameter.setEnabled(False)
|
||||
elif holetype == "countersink":
|
||||
# Values are taken from Norm
|
||||
self.form.spinCounterboreDiameter.setEnabled(False)
|
||||
self.form.spinCounterboreDepth.setEnabled(False)
|
||||
self.form.spinCountersinkAngle.setEnabled(False)
|
||||
if self.feature.Threaded == True:
|
||||
self.form.spinDiameter.setEnabled(False)
|
||||
if self.feature.NormThreadFinish != "Custom":
|
||||
self.form.spinThreadLength.setEnabled(False)
|
||||
self.form.spinThreadLength.setValue(self.feature.ThreadLength)
|
||||
# Position
|
||||
self.form.buttonSupport.setText("Face")
|
||||
if self.feature.Support == None:
|
||||
# First-time initialization
|
||||
selection = FreeCADGui.Selection.getSelectionEx()
|
||||
self.feature.Support = (selection[0].Object, selection[0].SubElementNames)
|
||||
self.form.lineSupport.setText(self.getRefText(self.feature.Support))
|
||||
if self.feature.PositionType == self.types[0]:
|
||||
# Linear
|
||||
self.form.buttonRef1.setText("Line/Plane")
|
||||
self.form.buttonRef1.setEnabled(True)
|
||||
self.form.buttonRef2.setText("Line/Plane")
|
||||
self.form.buttonRef2.setEnabled(True)
|
||||
self.form.lineRef1.setEnabled(True)
|
||||
self.form.lineRef2.setEnabled(True)
|
||||
self.form.labelRef1.setEnabled(True)
|
||||
self.form.labelRef1.setText("Distance")
|
||||
axis = self.feature.HoleGroove.Sketch.Support[0].References[0][0]
|
||||
if len(axis.References) > 0 and axis.References[0] != None:
|
||||
if (len(axis.References) == 3):
|
||||
self.form.lineRef1.setText(self.getRefText(axis.References[1]))
|
||||
else:
|
||||
self.form.lineRef1.setText(self.getRefText(axis.References[0]))
|
||||
self.form.spinRef1.setEnabled(True)
|
||||
self.form.spinRef1.setValue(axis.Offset)
|
||||
self.form.labelRef2.setEnabled(True)
|
||||
self.form.labelRef2.setText("Distance")
|
||||
if len(axis.References) > 1 and axis.References[1] != None:
|
||||
if (len(axis.References) == 3):
|
||||
self.form.lineRef2.setText(self.getRefText(axis.References[2]))
|
||||
else:
|
||||
self.form.lineRef2.setText(self.getRefText(axis.References[1]))
|
||||
self.form.spinRef2.setEnabled(True)
|
||||
self.form.spinRef2.setValue(axis.Offset2)
|
||||
elif self.feature.PositionType == self.types[1]:
|
||||
# Coaxial
|
||||
self.form.buttonRef1.setText("Circle/Cylinder")
|
||||
self.form.buttonRef1.setEnabled(True)
|
||||
self.form.buttonRef2.setEnabled(False)
|
||||
self.form.lineRef1.setEnabled(True)
|
||||
axis = self.feature.HoleGroove.Sketch.Support[0].References[0][0]
|
||||
if len(axis.References) > 0 and axis.References[0] != None:
|
||||
self.form.lineRef1.setText(self.getRefText(axis.References[0]))
|
||||
self.form.lineRef2.setEnabled(False)
|
||||
self.form.labelRef1.setEnabled(False)
|
||||
self.form.spinRef1.setEnabled(False)
|
||||
self.form.labelRef2.setEnabled(False)
|
||||
self.form.spinRef2.setEnabled(False)
|
||||
else:
|
||||
# Nothing else defined yet
|
||||
pass
|
||||
|
||||
def getStandardButtons(self):
|
||||
return int(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
|
||||
|
||||
def accept(self):
|
||||
return True
|
||||
|
||||
def buttonThru(self, toggle):
|
||||
if toggle == True:
|
||||
self.feature.HoleType = "Thru"
|
||||
|
||||
def buttonDepth(self, toggle):
|
||||
if toggle == True:
|
||||
self.feature.HoleType = "Depth"
|
||||
|
||||
def checkThreaded(self, checked):
|
||||
self.feature.Threaded = checked
|
||||
self.updateUI()
|
||||
|
||||
def checkCounterbore(self, checked):
|
||||
if checked == True:
|
||||
self.feature.Countersink = False
|
||||
self.feature.Counterbore = checked
|
||||
self.updateUI()
|
||||
|
||||
def checkCountersink(self, checked):
|
||||
if checked == True:
|
||||
self.feature.Counterbore = False
|
||||
self.feature.Countersink = checked
|
||||
self.updateUI()
|
||||
|
||||
def checkCustom(self, checked):
|
||||
if checked == True:
|
||||
self.feature.Norm = "Custom"
|
||||
else:
|
||||
self.feature.Norm = str(self.form.comboNorm.currentText())
|
||||
self.updateUI()
|
||||
|
||||
def comboNorm(self, index):
|
||||
self.feature.Norm = str(self.form.comboNorm.itemText(index))
|
||||
self.updateUI()
|
||||
|
||||
def comboTolerance(self, index):
|
||||
self.feature.NormTolerance = str(self.form.comboTolerance.itemText(index))
|
||||
self.updateUI()
|
||||
|
||||
def comboNormDia(self, index):
|
||||
diameter = str(self.form.comboNormDia.itemText(index))
|
||||
self.feature.NormDiameter = float(diameter[1:])
|
||||
self.updateUI()
|
||||
|
||||
def comboNormBoltWasher(self, index):
|
||||
self.feature.ExtraNorm = str(self.form.comboNormBoltWasher.itemText(index))
|
||||
self.updateUI()
|
||||
|
||||
def comboThreadNorm(self, index):
|
||||
self.feature.NormThread = str(self.form.comboThreadNorm.itemText(index))
|
||||
self.updateUI()
|
||||
|
||||
def comboThreadDia(self, index):
|
||||
diameter = str(self.form.comboThreadDia.itemText(index))
|
||||
self.feature.NormDiameter = float(diameter[1:])
|
||||
self.updateUI()
|
||||
|
||||
def checkCustomThreadLength(self, checked):
|
||||
if checked == True:
|
||||
self.feature.NormThreadFinish = "Custom"
|
||||
else:
|
||||
self.feature.NormThreadFinish = str(self.form.comboFinishNorm.currentText())
|
||||
self.updateUI()
|
||||
|
||||
def comboFinishNorm(self, index):
|
||||
self.feature.NormThreadFinish = str(self.form.comboFinishNorm.itemText(index))
|
||||
self.updateUI()
|
||||
|
||||
def spinDiameter(self, val):
|
||||
if (val > 0.0):
|
||||
self.feature.Diameter = val
|
||||
|
||||
def spinDepth(self, val):
|
||||
if (val > 0.0):
|
||||
self.feature.Depth = val
|
||||
self.updateUI() # required to update the thread length
|
||||
|
||||
def spinCounterboreDiameter(self, val):
|
||||
if (val > self.feature.Diameter):
|
||||
self.feature.CounterboreDiameter = val
|
||||
|
||||
def spinCounterboreDepth(self, val):
|
||||
if (val > 0.0):
|
||||
self.feature.CounterboreDepth = val
|
||||
|
||||
def spinCountersinkAngle(self, val):
|
||||
if (val > 0.0):
|
||||
self.feature.CountersinkAngle = val
|
||||
|
||||
def spinThreadLength(self, val):
|
||||
if (val > 0.0):
|
||||
self.feature.ThreadLength = val
|
||||
|
||||
def comboType(self, index):
|
||||
self.feature.PositionType = self.types[index]
|
||||
self.updateUI()
|
||||
|
||||
def addSelection(self, document, obj, element, position):
|
||||
#FreeCAD.Console.PrintMessage("AddSelection() for " + document + "." + obj + "." + element + "\n")
|
||||
# TODO: What is the position parameter?
|
||||
if document == self.feature.Document.Name:
|
||||
axis = self.feature.HoleGroove.Sketch.Support[0].References[0][0]
|
||||
refs = axis.References
|
||||
feature = eval("FreeCAD.getDocument('" + document + "')." + obj)
|
||||
shape = eval("feature.Shape." + element)
|
||||
if self.selectionMode == "Plane":
|
||||
if shape.Surface.__class__ != Part.Plane:
|
||||
FreeCAD.Console.PrintMessage("Selected face must be planar\n")
|
||||
return
|
||||
if self.feature.PositionType == self.types[0]:
|
||||
# The Hole support is also the first reference of the sketch axis in Linear mode with edges selected
|
||||
if len(refs) == 3:
|
||||
refs[0] = (feature, element)
|
||||
axis.References = refs
|
||||
self.feature.Support = (feature, [element])
|
||||
elif self.selectionMode == "LinearReference":
|
||||
if shape.ShapeType == "Edge":
|
||||
if shape.Curve.__class__ != Part.Line:
|
||||
FreeCAD.Console.PrintMessage("Selected edge must be linear\n")
|
||||
return
|
||||
if len(refs) > 1:
|
||||
refs[1] = (feature, element)
|
||||
else:
|
||||
refs.append((feature, element))
|
||||
elif shape.ShapeType == "Face":
|
||||
if shape.Surface.__class__ != Part.Plane:
|
||||
FreeCAD.Console.PrintMessage("Selected face must be planar\n")
|
||||
return
|
||||
if len(refs) > 0:
|
||||
if len(refs) > 2:
|
||||
refs = [(feature, element)]
|
||||
else:
|
||||
refs[0] = (feature, element)
|
||||
else:
|
||||
refs = [(feature, element)]
|
||||
else:
|
||||
FreeCAD.Console.PrintMessage("Wrong shape type selected\n")
|
||||
return
|
||||
axis.References = refs
|
||||
axis.Document.recompute()
|
||||
elif self.selectionMode == "LinearReference2":
|
||||
if shape.ShapeType == "Edge":
|
||||
if shape.Curve.__class__ != Part.Line:
|
||||
FreeCAD.Console.PrintMessage("Selected edge must be linear\n")
|
||||
return
|
||||
if len(refs) > 2:
|
||||
refs[2] = (feature, element)
|
||||
else:
|
||||
refs.append((feature, element))
|
||||
elif shape.ShapeType == "Face":
|
||||
if shape.Surface.__class__ != Part.Plane:
|
||||
FreeCAD.Console.PrintMessage("Selected face must be planar\n")
|
||||
return
|
||||
if len(refs) > 1:
|
||||
if len(refs) > 2:
|
||||
del refs[2]
|
||||
refs[1] = (feature, element)
|
||||
else:
|
||||
refs.append((feature, element))
|
||||
else:
|
||||
FreeCAD.Console.PrintMessage("Wrong shape type selected\n")
|
||||
return
|
||||
axis.References = refs
|
||||
axis.Document.recompute()
|
||||
elif self.selectionMode == "CircularReference":
|
||||
if shape.ShapeType == "Edge":
|
||||
if shape.Curve.__class__ != Part.Circle:
|
||||
FreeCAD.Console.PrintMessage("Selected edge must be arc or circle\n")
|
||||
return
|
||||
elif shape.ShapeType == "Face":
|
||||
if shape.Surface.__class__ != Part.Cylinder:
|
||||
FreeCAD.Console.PrintMessage("Selected face must be cylindrical\n")
|
||||
return
|
||||
else:
|
||||
FreeCAD.Console.PrintMessage("Wrong shape type selected\n")
|
||||
return
|
||||
refs = [(feature, element)]
|
||||
axis.References = refs
|
||||
axis.Document.recompute()
|
||||
else:
|
||||
FreeCAD.Console.PrintMessage("Unknown selection mode: " + self.selectionMode + "\n")
|
||||
self.selectionMode = ""
|
||||
return
|
||||
|
||||
FreeCADGui.Selection.removeObserver(self)
|
||||
FreeCADGui.Selection.clearSelection()
|
||||
FreeCADGui.Selection.removeSelectionGate()
|
||||
self.selectionMode = ""
|
||||
self.updateUI()
|
||||
self.showFeature()
|
||||
|
||||
def hideFeature(self):
|
||||
# Make sure selection takes place on support, not on hole feature
|
||||
if self.feature.Support != None:
|
||||
FreeCADGui.ActiveDocument.hide(self.feature.Name)
|
||||
(support, elements) = self.feature.Support
|
||||
FreeCADGui.ActiveDocument.show(support.Name)
|
||||
|
||||
def showFeature(self):
|
||||
if self.feature.Support != None:
|
||||
FreeCADGui.ActiveDocument.show(self.feature.Name)
|
||||
(support, elements) = self.feature.Support
|
||||
FreeCADGui.ActiveDocument.hide(support.Name)
|
||||
|
||||
def buttonSupport(self):
|
||||
FreeCADGui.Selection.addSelectionGate("SELECT Part::Feature SUBELEMENT Face COUNT 1")
|
||||
FreeCADGui.Selection.addObserver(self)
|
||||
# Currently support must be a planar face (but could also be a point or a construction plane in the future)
|
||||
self.selectionMode = "Plane"
|
||||
self.hideFeature()
|
||||
|
||||
def buttonRef1(self):
|
||||
FreeCADGui.Selection.addSelectionGate("SELECT Part::Feature SUBELEMENT Edge COUNT 1 SELECT Part::Feature SUBELEMENT Face COUNT 1")
|
||||
FreeCADGui.Selection.addObserver(self)
|
||||
if self.feature.PositionType == self.types[0]:
|
||||
self.selectionMode = "LinearReference"
|
||||
elif self.feature.PositionType == self.types[1]:
|
||||
self.selectionMode = "CircularReference"
|
||||
self.hideFeature()
|
||||
|
||||
def buttonRef2(self):
|
||||
FreeCADGui.Selection.addSelectionGate("SELECT Part::Feature SUBELEMENT Edge COUNT 1 SELECT Part::Feature SUBELEMENT Face COUNT 1")
|
||||
FreeCADGui.Selection.addObserver(self)
|
||||
self.selectionMode = "LinearReference2"
|
||||
self.hideFeature()
|
||||
|
||||
def spinRef1(self, val):
|
||||
axis = self.feature.HoleGroove.Sketch.Support[0].References[0][0]
|
||||
axis.Offset = val
|
||||
axis.Document.recompute()
|
||||
|
||||
def spinRef2(self, val):
|
||||
axis = self.feature.HoleGroove.Sketch.Support[0].References[0][0]
|
||||
axis.Offset2 = val
|
||||
axis.Document.recompute()
|
598
src/Mod/PartDesign/FeatureHole/TaskHole.ui
Normal file
598
src/Mod/PartDesign/FeatureHole/TaskHole.ui
Normal file
|
@ -0,0 +1,598 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TaskHole</class>
|
||||
<widget class="QWidget" name="TaskHole">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>327</width>
|
||||
<height>315</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab_position">
|
||||
<attribute name="title">
|
||||
<string>Position</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QComboBox" name="comboType"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonSupport">
|
||||
<property name="text">
|
||||
<string>Face</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineSupport"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonRef1">
|
||||
<property name="text">
|
||||
<string>Edge</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineRef1"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QLabel" name="labelRef1">
|
||||
<property name="text">
|
||||
<string>Distance</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="spinRef1">
|
||||
<property name="minimum">
|
||||
<double>-99999.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>99999.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>5.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonRef2">
|
||||
<property name="text">
|
||||
<string>Edge</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineRef2"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<widget class="QLabel" name="labelRef2">
|
||||
<property name="text">
|
||||
<string>Distance</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="spinRef2">
|
||||
<property name="minimum">
|
||||
<double>-99999.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>99999.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>5.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_type">
|
||||
<attribute name="title">
|
||||
<string>Type</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="buttonThru">
|
||||
<property name="text">
|
||||
<string>Through</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="buttonDepth">
|
||||
<property name="text">
|
||||
<string>Depth</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkThreaded">
|
||||
<property name="text">
|
||||
<string>Threaded</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkCountersink">
|
||||
<property name="text">
|
||||
<string>Countersink</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkCounterbore">
|
||||
<property name="text">
|
||||
<string>Counterbore</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_norm">
|
||||
<attribute name="title">
|
||||
<string>Hole norm</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkCustom">
|
||||
<property name="text">
|
||||
<string>Custom dimensions</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="comboNorm">
|
||||
<property name="editable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Tolerance</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="comboTolerance">
|
||||
<property name="editable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Diameter</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="comboNormDia">
|
||||
<property name="editable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_9">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Bolt/Washer</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="comboNormBoltWasher">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="editable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>125</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_thread">
|
||||
<attribute name="title">
|
||||
<string>Thread norm</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_10">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Thread norm</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="comboThreadNorm">
|
||||
<property name="editable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_12">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>Diameter</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="comboThreadDia">
|
||||
<property name="editable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_13">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkCustomThreadLength">
|
||||
<property name="text">
|
||||
<string> Custom thread length</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_6">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_11">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Finish depth</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="comboFinishNorm">
|
||||
<property name="editable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_7">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>81</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_data">
|
||||
<attribute name="title">
|
||||
<string>Data</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="layoutDiameter">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Diameter</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="spinDiameter">
|
||||
<property name="value">
|
||||
<double>8.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="layoutDepth">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Depth</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="spinDepth">
|
||||
<property name="value">
|
||||
<double>20.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="layoutDiameter_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Counterbore/sink dia</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="spinCounterboreDiameter">
|
||||
<property name="value">
|
||||
<double>15.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="layoutDepth_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Counterbore depth</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="spinCounterboreDepth">
|
||||
<property name="value">
|
||||
<double>7.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="layoutAngle">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Countersink angle</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="spinCountersinkAngle">
|
||||
<property name="value">
|
||||
<double>15.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="layoutDepth_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Thread length</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="spinThreadLength">
|
||||
<property name="value">
|
||||
<double>5.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>3</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
98
src/Mod/PartDesign/FeatureHole/ViewProviderHole.py
Normal file
98
src/Mod/PartDesign/FeatureHole/ViewProviderHole.py
Normal file
|
@ -0,0 +1,98 @@
|
|||
#/******************************************************************************
|
||||
# * Copyright (c)2012 Jan Rheinlaender <jrheinlaender@users.sourceforge.net> *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
# * *
|
||||
# * This library is free software; you can redistribute it and/or *
|
||||
# * modify it under the terms of the GNU Library General Public *
|
||||
# * License as published by the Free Software Foundation; either *
|
||||
# * version 2 of the License, or (at your option) any later version. *
|
||||
# * *
|
||||
# * This library is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this library; see the file COPYING.LIB. If not, *
|
||||
# * write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
# * Suite 330, Boston, MA 02111-1307, USA *
|
||||
# * *
|
||||
# ******************************************************************************/
|
||||
|
||||
import FreeCAD, FreeCADGui
|
||||
from TaskHole import TaskHole
|
||||
|
||||
class ViewProviderHole:
|
||||
def __init__(self, obj):
|
||||
''' Set this object to the proxy object of the actual view provider '''
|
||||
obj.Proxy = self
|
||||
self.Object = obj.Object
|
||||
|
||||
def attach(self, obj):
|
||||
''' Setup the scene sub-graph of the view provider, this method is mandatory '''
|
||||
return
|
||||
|
||||
def claimChildren(self):
|
||||
if self is None:
|
||||
return
|
||||
# The following statement leads to the error:
|
||||
# <unknown exception traceback><type 'exceptions.TypeError'>: PyCXX: Error creating object of type N2Py7SeqBaseINS_6ObjectEEE from None
|
||||
if not hasattr(self, "Object"):
|
||||
return
|
||||
|
||||
if self.Object != None:
|
||||
return [self.Object.HoleGroove, # the groove feature
|
||||
self.Object.HoleGroove.Sketch.Support[0], # the groove sketchplane (datum plane) feature
|
||||
self.Object.HoleGroove.Sketch.Support[0].References[0][0]] # the sketchplane first reference (datum line)
|
||||
|
||||
def updateData(self, fp, prop):
|
||||
''' If a property of the handled feature has changed we have the chance to handle this here '''
|
||||
return
|
||||
|
||||
def getDisplayModes(self,obj):
|
||||
''' Return a list of display modes. '''
|
||||
modes=[]
|
||||
return modes
|
||||
|
||||
def getDefaultDisplayMode(self):
|
||||
''' Return the name of the default display mode. It must be defined in getDisplayModes. '''
|
||||
return "Shaded"
|
||||
|
||||
def onChanged(self, vp, prop):
|
||||
''' Print the name of the property that has changed '''
|
||||
#FreeCAD.Console.PrintMessage("Change property: " + str(prop) + "\n")
|
||||
pass
|
||||
|
||||
def setEdit(self,vp,mode):
|
||||
FreeCAD.Console.PrintMessage("setEdit\n")
|
||||
panel = TaskHole(self.Object)
|
||||
|
||||
FreeCADGui.Control.showDialog(panel)
|
||||
if panel.setupUi():
|
||||
FreeCADGui.Control.closeDialog(panel)
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def unsetEdit(self,vp,mode):
|
||||
return
|
||||
|
||||
def getIcon(self):
|
||||
''' Return the icon in XMP format which will appear in the tree view. This method is optional
|
||||
and if not defined a default icon is shown.
|
||||
'''
|
||||
return ""
|
||||
|
||||
def __getstate__(self):
|
||||
''' When saving the document this object gets stored using Python's cPickle module.
|
||||
Since we have some un-pickable here -- the Coin stuff -- we must define this method
|
||||
to return a tuple of all pickable objects or None.
|
||||
'''
|
||||
return None
|
||||
|
||||
def __setstate__(self,state):
|
||||
''' When restoring the pickled object from document we have the chance to set some
|
||||
internals here. Since no data were pickled nothing needs to be done here.
|
||||
'''
|
||||
return None
|
30
src/Mod/PartDesign/FeatureHole/__init__.py
Normal file
30
src/Mod/PartDesign/FeatureHole/__init__.py
Normal file
|
@ -0,0 +1,30 @@
|
|||
"""
|
||||
Hole Feature
|
||||
"""
|
||||
|
||||
#/******************************************************************************
|
||||
# * Copyright (c)2012 Jan Rheinlaender <jrheinlaender@users.sourceforge.net> *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
# * *
|
||||
# * This library is free software; you can redistribute it and/or *
|
||||
# * modify it under the terms of the GNU Library General Public *
|
||||
# * License as published by the Free Software Foundation; either *
|
||||
# * version 2 of the License, or (at your option) any later version. *
|
||||
# * *
|
||||
# * This library is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this library; see the file COPYING.LIB. If not, *
|
||||
# * write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
# * Suite 330, Boston, MA 02111-1307, USA *
|
||||
# * *
|
||||
# ******************************************************************************/
|
||||
|
||||
# Empty file to treat the folder as a package
|
||||
# Initialize eric to do code completion for freecad libs
|
||||
# import sys
|
||||
# sys.path.append("/home/jan/freizeit/freecad-build-dbg/lib")
|
|
@ -649,7 +649,9 @@ Gui::MenuItem* Workbench::setupMenuBar() const
|
|||
// << "PartDesign_Scaled"
|
||||
<< "PartDesign_MultiTransform"
|
||||
<< "Separator"
|
||||
<< "PartDesign_Boolean";
|
||||
<< "PartDesign_Boolean"
|
||||
<< "Separator"
|
||||
<< "PartDesign_Hole";
|
||||
|
||||
// For 0.13 a couple of python packages like numpy, matplotlib and others
|
||||
// are not deployed with the installer on Windows. Thus, the WizardShaft is
|
||||
|
|
|
@ -42,6 +42,7 @@ class PartDesignWorkbench ( Workbench ):
|
|||
from WizardShaft import WizardShaft
|
||||
except ImportError:
|
||||
print "Wizard shaft module cannot be loaded"
|
||||
from FeatureHole import HoleGui
|
||||
import PartDesignGui
|
||||
import PartDesign
|
||||
try:
|
||||
|
|
72
src/Mod/PartDesign/InitGui.py.orig
Normal file
72
src/Mod/PartDesign/InitGui.py.orig
Normal file
|
@ -0,0 +1,72 @@
|
|||
# PartDesign gui init module
|
||||
# (c) 2003 Juergen Riegel
|
||||
#
|
||||
# Gathering all the information to start FreeCAD
|
||||
# This is the second one of three init scripts, the third one
|
||||
# runs when the gui is up
|
||||
|
||||
#***************************************************************************
|
||||
#* (c) Juergen Riegel (juergen.riegel@web.de) 2002 *
|
||||
#* *
|
||||
#* This file is part of the FreeCAD CAx development system. *
|
||||
#* *
|
||||
#* This program is free software; you can redistribute it and/or modify *
|
||||
#* it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
#* as published by the Free Software Foundation; either version 2 of *
|
||||
#* the License, or (at your option) any later version. *
|
||||
#* for detail see the LICENCE text file. *
|
||||
#* *
|
||||
#* FreeCAD is distributed in the hope that it will be useful, *
|
||||
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
#* GNU Lesser General Public License for more details. *
|
||||
#* *
|
||||
#* You should have received a copy of the GNU Library General Public *
|
||||
#* License along with FreeCAD; if not, write to the Free Software *
|
||||
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
#* USA *
|
||||
#* *
|
||||
#* Juergen Riegel 2002 *
|
||||
#***************************************************************************/
|
||||
|
||||
class PartDesignWorkbench ( Workbench ):
|
||||
"PartDesign workbench object"
|
||||
def __init__(self):
|
||||
self.__class__.Icon = FreeCAD.getResourceDir() + "Mod/PartDesign/Resources/icons/PartDesignWorkbench.svg"
|
||||
self.__class__.MenuText = "Part Design"
|
||||
self.__class__.ToolTip = "Part Design workbench"
|
||||
|
||||
<<<<<<< 64a1a440055b8a4359349b7abffe8956e78196db
|
||||
def Initialize(self):
|
||||
# load the module
|
||||
try:
|
||||
from WizardShaft import WizardShaft
|
||||
except ImportError:
|
||||
print "Wizard shaft module cannot be loaded"
|
||||
import PartDesignGui
|
||||
import PartDesign
|
||||
try:
|
||||
import InvoluteGearFeature
|
||||
except ImportError:
|
||||
print "Involute gear module cannot be loaded"
|
||||
def GetClassName(self):
|
||||
return "PartDesignGui::Workbench"
|
||||
=======
|
||||
def Initialize(self):
|
||||
# load the module
|
||||
try:
|
||||
from WizardShaft import WizardShaft
|
||||
except ImportError:
|
||||
print "Wizard shaft module cannot be loaded"
|
||||
from FeatureHole import HoleGui
|
||||
import PartDesignGui
|
||||
import PartDesign
|
||||
try:
|
||||
import InvoluteGearFeature
|
||||
except ImportError:
|
||||
print "Involute gear module cannot be loaded"
|
||||
def GetClassName(self):
|
||||
return "PartDesignGui::Workbench"
|
||||
>>>>>>> Python code of Hole Feature
|
||||
|
||||
Gui.addWorkbench(PartDesignWorkbench())
|
Loading…
Reference in New Issue
Block a user