~freecad-community/freecad-extras/fasteners

« back to all changes in this revision

Viewing changes to PEMInserts.py

  • Committer: GitHub
  • Author(s): Shai Seger
  • Date: 2022-02-09 15:56:43 UTC
  • mfrom: (152.1.1)
  • Revision ID: git-v1:dfeb76eec3cec9c7a264eed2c399672cb6a0e1da
Merge pull request #125 from shaise/revert-123-fix_indent

Revert "Fix indentations"

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
#  
24
24
###################################################################################
25
25
 
26
 
import FreeCAD
27
 
import math
28
 
import os
 
26
from FreeCAD import Gui
29
27
from FreeCAD import Base
30
 
from FreeCAD import Gui
31
 
 
 
28
import FreeCAD, FreeCADGui, Part, os, math
32
29
__dir__ = os.path.dirname(__file__)
33
 
iconPath = os.path.join(__dir__, 'Icons')
 
30
iconPath = os.path.join( __dir__, 'Icons' )
34
31
 
35
32
import FastenerBase
36
33
from FastenerBase import FSBaseObject
37
 
import ScrewMaker
38
 
 
 
34
import ScrewMaker  
39
35
screwMaker = ScrewMaker.Instance()
40
36
 
41
37
tan30 = math.tan(math.radians(30))
46
42
CLSSizeCodes = ['00', '0', '1', '2']
47
43
CLSDiamCodes = ['Auto', 'M2', 'M2.5', 'M3', 'M3.5', 'M4', 'M5', 'M6', 'M8', 'M10', 'M12']
48
44
CLSPEMTable = {
49
 
    #         (00,   0,    1,    2   )  C,     E,     T,    d
50
 
    'M2': ((0, 0.77, 0.97, 1.38), 4.2, 6.35, 1.5, 1.6),
51
 
    'M2.5': ((0, 0.77, 0.97, 1.38), 4.2, 6.35, 1.5, 2.05),
52
 
    'M3': ((0, 0.77, 0.97, 1.38), 4.2, 6.35, 1.5, 2.5),
53
 
    'M3.5': ((0, 0.77, 0.97, 1.38), 4.73, 7.11, 1.5, 2.9),
54
 
    'M4': ((0, 0.77, 0.97, 1.38), 5.38, 7.87, 2.0, 3.3),
55
 
    'M5': ((0, 0.77, 0.97, 1.38), 6.33, 8.64, 2.0, 4.2),
56
 
    'M6': ((0.89, 1.15, 1.38, 2.21), 8.73, 11.18, 4.08, 5.0),
57
 
    'M8': ((0, 0, 1.38, 2.21), 10.47, 12.7, 5.47, 6.8),
58
 
    'M10': ((0, 0, 2.21, 3.05), 13.97, 17.35, 7.48, 8.5),
59
 
    'M12': ((0, 0, 3.05, 0), 16.95, 20.57, 8.5, 10.2)
60
 
}
 
45
#         (00,   0,    1,    2   )  C,     E,     T,    d
 
46
  'M2':  ((0,    0.77, 0.97, 1.38), 4.2,   6.35,  1.5,  1.6),
 
47
  'M2.5':((0,    0.77, 0.97, 1.38), 4.2,   6.35,  1.5,  2.05),
 
48
  'M3':  ((0,    0.77, 0.97, 1.38), 4.2,   6.35,  1.5,  2.5),
 
49
  'M3.5':((0,    0.77, 0.97, 1.38), 4.73,  7.11,  1.5,  2.9),
 
50
  'M4':  ((0,    0.77, 0.97, 1.38), 5.38,  7.87,  2.0,  3.3),
 
51
  'M5':  ((0,    0.77, 0.97, 1.38), 6.33,  8.64,  2.0,  4.2),
 
52
  'M6':  ((0.89, 1.15, 1.38, 2.21), 8.73,  11.18, 4.08, 5.0),
 
53
  'M8':  ((0,    0,    1.38, 2.21), 10.47, 12.7,  5.47, 6.8),
 
54
  'M10': ((0,    0,    2.21, 3.05), 13.97, 17.35, 7.48, 8.5),
 
55
  'M12': ((0,    0,    3.05, 0),    16.95, 20.57, 8.5,  10.2)
 
56
  }
61
57
 
62
58
 
63
59
def clMakeWire(do, di, a, c, e, t):
64
 
    do = do / 2
65
 
    di = di / 2
66
 
    ch1 = do - di
67
 
    ch2 = ch1 / 2
68
 
    if ch2 < 0.2:
69
 
        ch2 = 0.2
70
 
    c = c / 2
71
 
    e = e / 2
72
 
    c2 = (c + e) / 2
73
 
    sl = a / 20
74
 
    a2 = a / 2
75
 
 
76
 
    fm = FastenerBase.FSFaceMaker()
77
 
    fm.AddPoint(di, -a + ch1)
78
 
    fm.AddPoint(do, -a)
79
 
    fm.AddPoint(c, -a)
80
 
    fm.AddPoint(c, -a * 0.75, )
81
 
    fm.AddPoint(c - sl, -a2)
82
 
    fm.AddPoint(c2, -a2)
83
 
    fm.AddPoint(c2, 0)
84
 
    fm.AddPoint(e, 0)
85
 
    fm.AddPoint(e, t - ch2)
86
 
    fm.AddPoint(e - ch2, t)
87
 
    fm.AddPoint(do, t)
88
 
    fm.AddPoint(di, t - ch1)
89
 
    return fm.GetFace()
90
 
 
 
60
  do = do / 2
 
61
  di = di / 2
 
62
  ch1 = do - di
 
63
  ch2 = ch1 / 2
 
64
  if ch2 < 0.2:
 
65
    ch2 = 0.2
 
66
  c = c / 2
 
67
  e = e / 2
 
68
  c2 = (c + e) / 2
 
69
  sl = a / 20
 
70
  a2 = a / 2
 
71
  
 
72
  fm = FastenerBase.FSFaceMaker()
 
73
  fm.AddPoint(di, -a + ch1)
 
74
  fm.AddPoint(do, -a)
 
75
  fm.AddPoint(c, -a)
 
76
  fm.AddPoint(c, -a * 0.75,)
 
77
  fm.AddPoint(c - sl, -a2)
 
78
  fm.AddPoint(c2, -a2)
 
79
  fm.AddPoint(c2, 0)
 
80
  fm.AddPoint(e, 0)
 
81
  fm.AddPoint(e, t - ch2)
 
82
  fm.AddPoint(e - ch2, t)
 
83
  fm.AddPoint(do, t)
 
84
  fm.AddPoint(di, t - ch1) 
 
85
  return fm.GetFace()
91
86
 
92
87
def clMakePressNut(diam, code):
93
 
    if code not in CLSSizeCodes:
94
 
        return None
95
 
    i = CLSSizeCodes.index(code)
96
 
 
97
 
    if not (diam in CLSPEMTable):
98
 
        return None
99
 
 
100
 
    (key, shape) = FastenerBase.FSGetKey('PressNut', diam, code)
101
 
    if shape is not None:
102
 
        return shape
103
 
 
104
 
    ls, c, e, t, di = CLSPEMTable[diam]
105
 
    a = ls[i]
106
 
    if a == 0:
107
 
        return None
108
 
    do = FastenerBase.MToFloat(diam)
109
 
    f = clMakeWire(do, di, a, c, e, t)
110
 
    p = f.revolve(Base.Vector(0.0, 0.0, 0.0), Base.Vector(0.0, 0.0, 1.0), 360)
111
 
    FastenerBase.FSCache[key] = p
112
 
    return p
113
 
 
 
88
  if code not in CLSSizeCodes:
 
89
    return None
 
90
  i = CLSSizeCodes.index(code)
 
91
 
 
92
  if not(diam in CLSPEMTable):
 
93
    return None
 
94
  
 
95
  (key, shape) = FastenerBase.FSGetKey('PressNut', diam, code)
 
96
  if shape is not None:
 
97
    return shape
 
98
 
 
99
  ls, c, e, t, di = CLSPEMTable[diam]
 
100
  a = ls[i]
 
101
  if a == 0:
 
102
    return None
 
103
  do = FastenerBase.MToFloat(diam)
 
104
  f = clMakeWire(do, di, a, c, e, t)
 
105
  p = f.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)
 
106
  FastenerBase.FSCache[key] = p
 
107
  return p
114
108
 
115
109
def clFindClosest(diam, code):
116
 
    ''' Find closest standard screw to given parameters '''
117
 
    if code not in CLSSizeCodes:
118
 
        return '1'
119
 
    i = CLSSizeCodes.index(code)
120
 
    lens = CLSPEMTable[diam][0]
121
 
    if lens[i] != 0:
122
 
        return code
123
 
    min = 999
124
 
    max = len(CLSSizeCodes)
125
 
    j = 0
126
 
    for c in lens:
127
 
        if c != 0 and min == 999:
128
 
            min = j
129
 
        if c == 0 and min != 999:
130
 
            max = j - 1
131
 
            break
132
 
        j = j + 1
133
 
    if i < min:
134
 
        return CLSSizeCodes[min]
135
 
    # i is probably > max
136
 
    return CLSSizeCodes[max]
137
 
 
 
110
  ''' Find closest standard screw to given parameters '''
 
111
  if code not in CLSSizeCodes:
 
112
    return '1'
 
113
  i = CLSSizeCodes.index(code)
 
114
  lens = CLSPEMTable[diam][0]
 
115
  if lens[i] != 0:
 
116
    return code
 
117
  min = 999
 
118
  max = len(CLSSizeCodes)
 
119
  j = 0
 
120
  for c in lens:
 
121
    if c != 0 and min == 999:
 
122
      min = j
 
123
    if c == 0 and min != 999:
 
124
      max = j - 1
 
125
      break
 
126
    j = j + 1
 
127
  if i < min:
 
128
    return CLSSizeCodes[min]
 
129
  # i is probably > max
 
130
  return CLSSizeCodes[max]
 
131
      
138
132
 
139
133
# h = clMakePressNut('M5','1')
140
134
 
141
135
class FSPressNutObject(FSBaseObject):
142
 
    def __init__(self, obj, attachTo):
143
 
        '''"Add Press nut (self clinching) type fastener" '''
144
 
        FSBaseObject.__init__(self, obj, attachTo)
145
 
        self.itemText = "PressNut"
146
 
        # self.Proxy = obj.Name
147
 
 
148
 
        obj.addProperty("App::PropertyEnumeration", "tcode", "Parameters", "Thickness code").tcode = CLSSizeCodes
149
 
        obj.addProperty("App::PropertyEnumeration", "diameter", "Parameters", "Press nut thread diameter").diameter = CLSDiamCodes
150
 
        obj.invert = FastenerBase.FSLastInvert
151
 
        obj.tcode = '1'
152
 
        obj.Proxy = self
153
 
 
154
 
    def execute(self, fp):
155
 
        '''"Print a short message when doing a recomputation, this method is mandatory" '''
156
 
 
157
 
        try:
158
 
            baseobj = fp.baseObject[0]
159
 
            shape = baseobj.Shape.getElement(fp.baseObject[1][0])
160
 
        except:
161
 
            baseobj = None
162
 
            shape = None
163
 
        self.updateProps(fp)
164
 
        if not (hasattr(self, 'diameter')) or self.diameter != fp.diameter or self.tcode != fp.tcode:
165
 
            if fp.diameter == 'Auto':
166
 
                d = FastenerBase.FSAutoDiameterM(shape, CLSPEMTable, 1)
167
 
            else:
168
 
                d = fp.diameter
169
 
 
170
 
            l = clFindClosest(d, fp.tcode)
171
 
            if l != fp.tcode:
172
 
                fp.tcode = l
173
 
            if d != fp.diameter:
174
 
                fp.diameter = d
175
 
            s = clMakePressNut(d, l)
176
 
            self.diameter = fp.diameter
177
 
            self.tcode = fp.tcode
178
 
            FastenerBase.FSLastInvert = fp.invert
179
 
            fp.Label = fp.diameter + '-PressNut'
180
 
            fp.Shape = s
181
 
        else:
182
 
            FreeCAD.Console.PrintLog("Using cached object\n")
183
 
        if shape is not None:
184
 
            # feature = FreeCAD.ActiveDocument.getObject(self.Proxy)
185
 
            # fp.Placement = FreeCAD.Placement() # reset placement
186
 
            FastenerBase.FSMoveToObject(fp, shape, fp.invert, fp.offset.Value)
187
 
 
188
 
 
189
 
FastenerBase.FSClassIcons[FSPressNutObject] = 'PEMPressNut.svg'
190
 
 
 
136
  def __init__(self, obj, attachTo):
 
137
    '''"Add Press nut (self clinching) type fastener" '''
 
138
    FSBaseObject.__init__(self, obj, attachTo)
 
139
    self.itemText = "PressNut"
 
140
    #self.Proxy = obj.Name
 
141
    
 
142
    obj.addProperty("App::PropertyEnumeration","tcode","Parameters","Thickness code").tcode = CLSSizeCodes
 
143
    obj.addProperty("App::PropertyEnumeration","diameter","Parameters","Press nut thread diameter").diameter = CLSDiamCodes
 
144
    obj.invert = FastenerBase.FSLastInvert
 
145
    obj.tcode = '1'
 
146
    obj.Proxy = self
 
147
 
 
148
  def execute(self, fp):
 
149
    '''"Print a short message when doing a recomputation, this method is mandatory" '''
 
150
    
 
151
    try:
 
152
      baseobj = fp.baseObject[0]
 
153
      shape = baseobj.Shape.getElement(fp.baseObject[1][0])
 
154
    except:
 
155
      baseobj = None
 
156
      shape = None
 
157
    self.updateProps(fp)
 
158
    if not (hasattr(self, 'diameter')) or self.diameter != fp.diameter or self.tcode != fp.tcode:
 
159
      if fp.diameter == 'Auto':
 
160
        d = FastenerBase.FSAutoDiameterM(shape, CLSPEMTable, 1)
 
161
      else:
 
162
        d = fp.diameter
 
163
        
 
164
      l = clFindClosest(d, fp.tcode)
 
165
      if l != fp.tcode:
 
166
        fp.tcode = l
 
167
      if d != fp.diameter:
 
168
        fp.diameter = d
 
169
      s = clMakePressNut(d, l)
 
170
      self.diameter = fp.diameter
 
171
      self.tcode = fp.tcode
 
172
      FastenerBase.FSLastInvert = fp.invert
 
173
      fp.Label = fp.diameter + '-PressNut'
 
174
      fp.Shape = s
 
175
    else:
 
176
      FreeCAD.Console.PrintLog("Using cached object\n")
 
177
    if shape is not None:
 
178
      #feature = FreeCAD.ActiveDocument.getObject(self.Proxy)
 
179
      #fp.Placement = FreeCAD.Placement() # reset placement
 
180
      FastenerBase.FSMoveToObject(fp, shape, fp.invert, fp.offset.Value)
 
181
 
 
182
 
 
183
FastenerBase.FSClassIcons[FSPressNutObject] = 'PEMPressNut.svg'    
191
184
 
192
185
class FSPressnutCommand:
193
 
    """Add Preass-nut command"""
194
 
 
195
 
    def GetResources(self):
196
 
        icon = os.path.join(iconPath, 'PEMPressNut.svg')
197
 
        return {
198
 
            'Pixmap': icon,  # the name of a svg file available in the resources
199
 
            'MenuText': "Add Press-Nut",
200
 
            'ToolTip': "Add PEM Self Clinching Metric Nut"
201
 
        }
202
 
 
203
 
    def Activated(self):
204
 
        FastenerBase.FSGenerateObjects(FSPressNutObject, "PressNut")
205
 
        return
206
 
 
207
 
    def IsActive(self):
208
 
        return Gui.ActiveDocument is not None
209
 
 
 
186
  """Add Preass-nut command"""
 
187
 
 
188
  def GetResources(self):
 
189
    icon = os.path.join( iconPath , 'PEMPressNut.svg')
 
190
    return {'Pixmap'  : icon , # the name of a svg file available in the resources
 
191
            'MenuText': "Add Press-Nut" ,
 
192
            'ToolTip' : "Add PEM Self Clinching Metric Nut"}
 
193
 
 
194
  def Activated(self):
 
195
    FastenerBase.FSGenerateObjects(FSPressNutObject, "PressNut")
 
196
    return
 
197
   
 
198
  def IsActive(self):
 
199
    return Gui.ActiveDocument is not None
210
200
 
211
201
Gui.addCommand("FSPressNut", FSPressnutCommand())
212
202
FastenerBase.FSCommands.append("FSPressNut", "screws", "PEM Inserts")
213
203
 
 
204
 
214
205
###################################################################################
215
206
# PEM Self Clinching standoffs types: SO/SOS/SOA/SO4
216
 
SOLengths = {'3': 0, '4': 0, '6': 0, '8': 0, '10': 4, '12': 4, '14': 4, '16': 8, '18': 8, '20': 8, '22': 11, '25': 11}
217
 
# BSLengths = {'6':3.2, '8':4, '10':4, '12':5, '14':6.5, '16':6.5, '18':9.5, '20':9.5, '22':9.5, '25':9.5}
218
 
SODiameters = ['Auto', 'M3', '3.5M3', 'M3.5', 'M4', 'M5']
 
207
SOLengths = {'3':0, '4':0, '6':0, '8':0, '10':4, '12':4, '14':4, '16':8, '18':8, '20':8, '22':11, '25':11}
 
208
#BSLengths = {'6':3.2, '8':4, '10':4, '12':5, '14':6.5, '16':6.5, '18':9.5, '20':9.5, '22':9.5, '25':9.5}
 
209
SODiameters = ['Auto', 'M3', '3.5M3', 'M3.5', 'M4', 'M5' ]
219
210
SOPEMTable = {
220
 
    #          B,    C,    H,   d, Lmin, Lmax
221
 
    'M3': (3.2, 4.2, 4.8, 2.5, 3, 18),
222
 
    '3.5M3': (3.2, 5.39, 6.4, 2.5, 3, 25),
223
 
    'M3.5': (3.9, 5.39, 6.4, 2.9, 3, 25),
224
 
    'M4': (4.8, 7.12, 7.9, 3.3, 3, 25),
225
 
    'M5': (5.36, 7.12, 7.9, 4.2, 3, 25)
226
 
}
 
211
#          B,    C,    H,   d, Lmin, Lmax
 
212
  'M3':   (3.2,  4.2,  4.8, 2.5, 3, 18),
 
213
  '3.5M3':(3.2,  5.39, 6.4, 2.5, 3, 25),
 
214
  'M3.5': (3.9,  5.39, 6.4, 2.9, 3, 25),
 
215
  'M4':   (4.8,  7.12, 7.9, 3.3, 3, 25),
 
216
  'M5':   (5.36, 7.12, 7.9, 4.2, 3, 25)
 
217
  }
227
218
 
228
219
 
229
220
def soMakeFace(b, c, h, d, l):
230
 
    h10 = h / 10.0
231
 
    c12 = c / 12.5
232
 
    c20 = c / 20.0
233
 
    c40 = c / 40.0
234
 
    b = b / 2
235
 
    c = c / 2
236
 
    d = d / 2
237
 
    ch1 = b - d
238
 
    l1 = float(l)
239
 
    l2 = l1 - SOLengths[l]
240
 
    c1 = c - c40
241
 
    c2 = c - c20
242
 
    l3 = h10 * 2 + (c12 + c20) * 2
243
 
 
244
 
    fm = FastenerBase.FSFaceMaker()
245
 
    fm.AddPoint(b, 0)
246
 
    fm.AddPoint(d, -ch1)
247
 
    fm.AddPoint(d, -(l2 - ch1))
248
 
    fm.AddPoint(b, -l2)
249
 
    if (l1 - l2) > 0.01:
250
 
        fm.AddPoint(b, -l1)
251
 
    fm.AddPoint(c, -l1)
252
 
    if l3 < l1:
253
 
        fm.AddPoint(c, -l3)
254
 
        fm.AddPoint(c1, -l3)
255
 
        fm.AddPoint(c1, -(l3 - c20))
256
 
        fm.AddPoint(c, -(l3 - c20))
257
 
    fm.AddPoint(c, -(h10 * 2 + c12 + c20))
258
 
    fm.AddPoint(c1, -(h10 * 2 + c12 + c20))
259
 
    fm.AddPoint(c1, -(h10 * 2 + c12))
260
 
    fm.AddPoint(c, -(h10 * 2 + c12))
261
 
    fm.AddPoint(c, -h10 * 2)
262
 
    fm.AddPoint(c2, -h10 * 2)
263
 
    fm.AddPoint(c2, -h10)
264
 
    fm.AddPoint(h * 0.6, -h10)
265
 
    fm.AddPoint(h * 0.6, 0)
266
 
    return fm.GetFace()
267
 
 
 
221
  h10 = h / 10.0
 
222
  c12 = c / 12.5
 
223
  c20 = c / 20.0
 
224
  c40 = c / 40.0
 
225
  b = b / 2
 
226
  c = c / 2
 
227
  d = d / 2
 
228
  ch1 = b - d
 
229
  l1 = float(l)
 
230
  l2 = l1 - SOLengths[l]
 
231
  c1 = c - c40
 
232
  c2 = c - c20
 
233
  l3 = h10 * 2 + (c12 + c20) * 2
 
234
  
 
235
  fm = FastenerBase.FSFaceMaker()
 
236
  fm.AddPoint(b, 0)
 
237
  fm.AddPoint(d, -ch1)
 
238
  fm.AddPoint(d, -(l2 - ch1))
 
239
  fm.AddPoint(b, -l2)
 
240
  if (l1 - l2) > 0.01:
 
241
    fm.AddPoint(b, -l1)
 
242
  fm.AddPoint(c, -l1)
 
243
  if l3 < l1:
 
244
    fm.AddPoint(c, -l3)
 
245
    fm.AddPoint(c1, -l3)
 
246
    fm.AddPoint(c1, -(l3 - c20))
 
247
    fm.AddPoint(c, -(l3 - c20))
 
248
  fm.AddPoint(c, -(h10 * 2 + c12 + c20))
 
249
  fm.AddPoint(c1, -(h10 * 2 + c12 + c20))
 
250
  fm.AddPoint(c1, -(h10 * 2 + c12))
 
251
  fm.AddPoint(c, -(h10 * 2 + c12))
 
252
  fm.AddPoint(c, -h10 * 2)
 
253
  fm.AddPoint(c2, -h10 * 2)
 
254
  fm.AddPoint(c2, -h10)
 
255
  fm.AddPoint(h * 0.6, -h10)
 
256
  fm.AddPoint(h * 0.6, 0)
 
257
  return fm.GetFace()
268
258
 
269
259
def bsMakeFace(b, c, h, d, l):
270
 
    h10 = h / 10.0
271
 
    h102 = h10 + h10 / 2
272
 
    c12 = c / 12.5
273
 
    c20 = c / 20.0
274
 
    c40 = c / 40.0
275
 
    b = b / 2
276
 
    c = c / 2
277
 
    d = d / 2
278
 
    ch1 = b - d
279
 
    ch2 = d * tan30
280
 
    l1 = float(l)
281
 
    # l2 = l1 - SOLengths[l]
282
 
    c1 = c - c40
283
 
    c2 = c - c20
284
 
    l3 = h10 * 2 + (c12 + c20) * 2
285
 
 
286
 
    fm = FastenerBase.FSFaceMaker()
287
 
    fm.AddPoint(0, 0)
288
 
    fm.AddPoint(0, -h102)
289
 
    fm.AddPoint(d, -(h102 + ch2))
290
 
    fm.AddPoint(d, -(l1 - ch1))
291
 
    fm.AddPoint(b, -l1)
292
 
    fm.AddPoint(c, -l1)
293
 
    if l3 < l1:
294
 
        fm.AddPoint(c, -l3)
295
 
        fm.AddPoint(c1, -l3)
296
 
        fm.AddPoint(c1, -(l3 - c20))
297
 
        fm.AddPoint(c, -(l3 - c20))
298
 
    fm.AddPoint(c, -(h10 * 2 + c12 + c20))
299
 
    fm.AddPoint(c1, -(h10 * 2 + c12 + c20))
300
 
    fm.AddPoint(c1, -(h10 * 2 + c12))
301
 
    fm.AddPoint(c, -(h10 * 2 + c12))
302
 
    fm.AddPoint(c, -h10 * 2)
303
 
    fm.AddPoint(c2, -h10 * 2)
304
 
    fm.AddPoint(c2, -h10)
305
 
    fm.AddPoint(h * 0.6, -h10)
306
 
    fm.AddPoint(h * 0.6, 0)
307
 
    return fm.GetFace()
308
 
 
 
260
  h10 = h / 10.0
 
261
  h102 = h10 + h10 / 2
 
262
  c12 = c / 12.5
 
263
  c20 = c / 20.0
 
264
  c40 = c / 40.0
 
265
  b = b / 2
 
266
  c = c / 2
 
267
  d = d / 2
 
268
  ch1 = b - d
 
269
  ch2 = d * tan30
 
270
  l1 = float(l)
 
271
  #l2 = l1 - SOLengths[l]
 
272
  c1 = c - c40
 
273
  c2 = c - c20
 
274
  l3 = h10 * 2 + (c12 + c20) * 2
 
275
  
 
276
  fm = FastenerBase.FSFaceMaker()
 
277
  fm.AddPoint(0, 0)
 
278
  fm.AddPoint(0, -h102)
 
279
  fm.AddPoint(d, -(h102 + ch2))
 
280
  fm.AddPoint(d, -(l1 - ch1))
 
281
  fm.AddPoint(b, -l1)
 
282
  fm.AddPoint(c, -l1)
 
283
  if l3 < l1:
 
284
    fm.AddPoint(c, -l3)
 
285
    fm.AddPoint(c1, -l3)
 
286
    fm.AddPoint(c1, -(l3 - c20))
 
287
    fm.AddPoint(c, -(l3 - c20))
 
288
  fm.AddPoint(c, -(h10 * 2 + c12 + c20))
 
289
  fm.AddPoint(c1, -(h10 * 2 + c12 + c20))
 
290
  fm.AddPoint(c1, -(h10 * 2 + c12))
 
291
  fm.AddPoint(c, -(h10 * 2 + c12))
 
292
  fm.AddPoint(c, -h10 * 2)
 
293
  fm.AddPoint(c2, -h10 * 2)
 
294
  fm.AddPoint(c2, -h10)
 
295
  fm.AddPoint(h * 0.6, -h10)
 
296
  fm.AddPoint(h * 0.6, 0)
 
297
  return fm.GetFace()
309
298
 
310
299
def soMakeStandOff(diam, len, blind):
311
 
    if not (len in SOLengths):
312
 
        return None
313
 
    if not (diam in SOPEMTable):
314
 
        return None
315
 
 
316
 
    (key, shape) = FastenerBase.FSGetKey('StandOff', diam, len, blind)
317
 
    if shape is not None:
318
 
        return shape
319
 
 
320
 
    l = int(len)
321
 
    b, c, h, d, lmin, lmax = SOPEMTable[diam]
322
 
    if blind:
323
 
        lmin, lmax = (6, 25)
324
 
    if l < lmin or l > lmax:
325
 
        return None
326
 
 
327
 
    if blind:
328
 
        f = bsMakeFace(b, c, h, d, len)
329
 
    else:
330
 
        f = soMakeFace(b, c, h, d, len)
331
 
    p = f.revolve(Base.Vector(0.0, 0.0, 0.0), Base.Vector(0.0, 0.0, 1.0), 360)
332
 
    htool = screwMaker.makeHextool(h, 3, h * 2)
333
 
    htool.translate(Base.Vector(0.0, 0.0, -2.0))
334
 
    shape = p.cut(htool)
335
 
    FastenerBase.FSCache[key] = shape
 
300
  if not(len in SOLengths):
 
301
    return None
 
302
  if not(diam in SOPEMTable):
 
303
    return None
 
304
 
 
305
  (key, shape) = FastenerBase.FSGetKey('StandOff', diam, len, blind)
 
306
  if shape is not None:
336
307
    return shape
337
 
 
 
308
  
 
309
  l = int(len)
 
310
  b, c, h, d, lmin, lmax = SOPEMTable[diam]
 
311
  if blind:
 
312
    lmin, lmax = (6, 25)
 
313
  if l < lmin or l > lmax:
 
314
    return None
 
315
  
 
316
  if blind:
 
317
    f = bsMakeFace(b, c, h, d, len)
 
318
  else:
 
319
    f = soMakeFace(b, c, h, d, len)
 
320
  p = f.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)
 
321
  htool = screwMaker.makeHextool(h, 3, h * 2)
 
322
  htool.translate(Base.Vector(0.0,0.0,-2.0))
 
323
  shape = p.cut(htool)
 
324
  FastenerBase.FSCache[key] = shape
 
325
  return shape
338
326
 
339
327
def soFindClosest(diam, len):
340
 
    ''' Find closest standard screw to given parameters '''
341
 
    if not (diam in SOPEMTable):
342
 
        return None
343
 
    if float(len) > SOPEMTable[diam][5]:
344
 
        return str(SOPEMTable[diam][5])
345
 
    if float(len) < SOPEMTable[diam][4]:
346
 
        return str(SOPEMTable[diam][4])
347
 
    return len
348
 
 
349
 
 
 
328
  ''' Find closest standard screw to given parameters '''
 
329
  if not(diam in SOPEMTable):
 
330
    return None
 
331
  if float(len) > SOPEMTable[diam][5]:
 
332
    return str(SOPEMTable[diam][5])
 
333
  if float(len) < SOPEMTable[diam][4]:
 
334
    return str(SOPEMTable[diam][4])
 
335
  return len
 
336
 
350
337
def soGetAllLengths(diam, blind):
351
 
    if blind:
352
 
        lmin, lmax = (6, 25)
353
 
    else:
354
 
        b, c, h, d, lmin, lmax = SOPEMTable[diam]
355
 
    list = []
356
 
    for len in SOLengths:
357
 
        l = float(len)
358
 
        if l >= lmin and l <= lmax:
359
 
            list.append(len)
360
 
    try:  # py3
361
 
        import functools
362
 
        sorted(list, key=functools.cmp_to_key(FastenerBase.NumCompare))
363
 
    except:
364
 
        list.sort(cmp=FastenerBase.NumCompare)
365
 
    return list
366
 
 
 
338
  if blind:
 
339
    lmin, lmax = (6, 25)
 
340
  else:
 
341
    b, c, h, d, lmin, lmax = SOPEMTable[diam]
 
342
  list = []
 
343
  for len in SOLengths:
 
344
    l = float(len)
 
345
    if l >= lmin and l <= lmax:
 
346
      list.append(len)
 
347
  try:  # py3
 
348
    import functools
 
349
    sorted(list, key = functools.cmp_to_key(FastenerBase.NumCompare))
 
350
  except:
 
351
    list.sort(cmp = FastenerBase.NumCompare)
 
352
  return list
367
353
 
368
354
# h = clMakePressNut('M5','1')
369
355
 
370
356
class FSStandOffObject(FSBaseObject):
371
 
    def __init__(self, obj, attachTo):
372
 
        '''"Add StandOff (self clinching) type fastener" '''
373
 
        FSBaseObject.__init__(self, obj, attachTo)
374
 
        self.itemText = "StandOff"
375
 
        # self.Proxy = obj.Name
376
 
 
377
 
        obj.addProperty("App::PropertyEnumeration", "diameter", "Parameters", "Standoff thread diameter").diameter = SODiameters
378
 
        obj.addProperty("App::PropertyBool", "blind", "Parameters", "Blind Standoff type").blind = False
379
 
        obj.addProperty("App::PropertyEnumeration", "length", "Parameters", "Standoff length").length = soGetAllLengths(SODiameters[1], False)
380
 
        obj.invert = FastenerBase.FSLastInvert
381
 
        obj.Proxy = self
382
 
 
383
 
    def execute(self, fp):
384
 
        '''"Print a short message when doing a recomputation, this method is mandatory" '''
385
 
 
386
 
        try:
387
 
            baseobj = fp.baseObject[0]
388
 
            shape = baseobj.Shape.getElement(fp.baseObject[1][0])
389
 
        except:
390
 
            baseobj = None
391
 
            shape = None
392
 
        self.updateProps(fp)
393
 
        if not (hasattr(self,
394
 
                        'diameter')) or self.diameter != fp.diameter or self.length != fp.length or self.blind != fp.blind:
395
 
            diameterchange = False
396
 
            if not (hasattr(self, 'diameter')) or self.diameter != fp.diameter:
397
 
                diameterchange = True
398
 
            if fp.diameter == 'Auto':
399
 
                d = FastenerBase.FSAutoDiameterM(shape, SOPEMTable, 1)
400
 
                diameterchange = True
401
 
            else:
402
 
                d = fp.diameter
403
 
 
404
 
            blindchange = False
405
 
            if not (hasattr(self, 'blind')) or self.blind != fp.blind:
406
 
                blindchange = True
407
 
 
408
 
            l = soFindClosest(d, fp.length)
409
 
            if d != fp.diameter:
410
 
                diameterchange = True
411
 
                fp.diameter = d
412
 
 
413
 
            if l != fp.length or diameterchange or blindchange:
414
 
                if diameterchange or blindchange:
415
 
                    fp.length = soGetAllLengths(fp.diameter, fp.blind)
416
 
                fp.length = l
417
 
 
418
 
            s = soMakeStandOff(d, l, fp.blind)
419
 
            self.diameter = fp.diameter
420
 
            self.length = fp.length
421
 
            self.blind = fp.blind
422
 
            FastenerBase.FSLastInvert = fp.invert
423
 
            fp.Label = fp.diameter + 'x' + fp.length + '-Standoff'
424
 
            fp.Shape = s
425
 
        else:
426
 
            FreeCAD.Console.PrintLog("Using cached object\n")
427
 
        if shape is not None:
428
 
            # feature = FreeCAD.ActiveDocument.getObject(self.Proxy)
429
 
            # fp.Placement = FreeCAD.Placement() # reset placement
430
 
            FastenerBase.FSMoveToObject(fp, shape, fp.invert, fp.offset.Value)
431
 
 
432
 
 
433
 
FastenerBase.FSClassIcons[FSStandOffObject] = 'PEMTHStandoff.svg'
 
357
  def __init__(self, obj, attachTo):
 
358
    '''"Add StandOff (self clinching) type fastener" '''
 
359
    FSBaseObject.__init__(self, obj, attachTo)
 
360
    self.itemText = "StandOff"
 
361
    #self.Proxy = obj.Name
 
362
    
 
363
    obj.addProperty("App::PropertyEnumeration","diameter","Parameters","Standoff thread diameter").diameter = SODiameters
 
364
    obj.addProperty("App::PropertyBool", "blind", "Parameters", "Blind Standoff type").blind = False
 
365
    obj.addProperty("App::PropertyEnumeration","length","Parameters","Standoff length").length = soGetAllLengths(SODiameters[1], False)
 
366
    obj.invert = FastenerBase.FSLastInvert
 
367
    obj.Proxy = self
 
368
 
 
369
  def execute(self, fp):
 
370
    '''"Print a short message when doing a recomputation, this method is mandatory" '''
 
371
    
 
372
    try:
 
373
      baseobj = fp.baseObject[0]
 
374
      shape = baseobj.Shape.getElement(fp.baseObject[1][0])
 
375
    except:
 
376
      baseobj = None
 
377
      shape = None
 
378
    self.updateProps(fp)
 
379
    if not (hasattr(self, 'diameter')) or self.diameter != fp.diameter or self.length != fp.length or self.blind != fp.blind:
 
380
      diameterchange = False      
 
381
      if not (hasattr(self, 'diameter')) or self.diameter != fp.diameter:
 
382
        diameterchange = True      
 
383
      if fp.diameter == 'Auto':
 
384
        d = FastenerBase.FSAutoDiameterM(shape, SOPEMTable, 1)
 
385
        diameterchange = True      
 
386
      else:
 
387
        d = fp.diameter
 
388
        
 
389
      blindchange = False
 
390
      if not(hasattr(self, 'blind')) or self.blind != fp.blind:
 
391
        blindchange = True
 
392
        
 
393
      l = soFindClosest(d, fp.length)
 
394
      if d != fp.diameter:
 
395
        diameterchange = True      
 
396
        fp.diameter = d
 
397
 
 
398
      if l != fp.length or diameterchange or blindchange:
 
399
        if diameterchange or blindchange:
 
400
          fp.length = soGetAllLengths(fp.diameter, fp.blind)
 
401
        fp.length = l
 
402
               
 
403
      s = soMakeStandOff(d, l, fp.blind)
 
404
      self.diameter = fp.diameter
 
405
      self.length = fp.length
 
406
      self.blind = fp.blind
 
407
      FastenerBase.FSLastInvert = fp.invert
 
408
      fp.Label = fp.diameter + 'x' + fp.length + '-Standoff'
 
409
      fp.Shape = s
 
410
    else:
 
411
      FreeCAD.Console.PrintLog("Using cached object\n")
 
412
    if shape is not None:
 
413
      #feature = FreeCAD.ActiveDocument.getObject(self.Proxy)
 
414
      #fp.Placement = FreeCAD.Placement() # reset placement
 
415
      FastenerBase.FSMoveToObject(fp, shape, fp.invert, fp.offset.Value)
 
416
 
 
417
 
 
418
FastenerBase.FSClassIcons[FSStandOffObject] = 'PEMTHStandoff.svg'    
434
419
 
435
420
 
436
421
class FSStandOffCommand:
437
 
    """Add Standoff command"""
438
 
 
439
 
    def GetResources(self):
440
 
        icon = os.path.join(iconPath, 'PEMTHStandoff.svg')
441
 
        return {
442
 
            'Pixmap': icon,  # the name of a svg file available in the resources
443
 
            'MenuText': "Add Standoff",
444
 
            'ToolTip': "Add PEM Self Clinching Metric Standoff"
445
 
        }
446
 
 
447
 
    def Activated(self):
448
 
        FastenerBase.FSGenerateObjects(FSStandOffObject, "Standoff")
449
 
        return
450
 
 
451
 
    def IsActive(self):
452
 
        return Gui.ActiveDocument is not None
453
 
 
 
422
  """Add Standoff command"""
 
423
 
 
424
  def GetResources(self):
 
425
    icon = os.path.join( iconPath , 'PEMTHStandoff.svg')
 
426
    return {'Pixmap'  : icon , # the name of a svg file available in the resources
 
427
            'MenuText': "Add Standoff" ,
 
428
            'ToolTip' : "Add PEM Self Clinching Metric Standoff"}
 
429
 
 
430
  def Activated(self):
 
431
    FastenerBase.FSGenerateObjects(FSStandOffObject, "Standoff")
 
432
    return
 
433
   
 
434
  def IsActive(self):
 
435
    return Gui.ActiveDocument is not None
454
436
 
455
437
Gui.addCommand("FSStandOff", FSStandOffCommand())
456
438
FastenerBase.FSCommands.append("FSStandOff", "screws", "PEM Inserts")
458
440
###################################################################################
459
441
# PEM Self Clinching studs types: FH/FHS/FHA
460
442
FHLengths = ['6', '8', '10', '12', '15', '18', '20', '25', '30', '35']
461
 
# BSLengths = {'6':3.2, '8':4, '10':4, '12':5, '14':6.5, '16':6.5, '18':9.5, '20':9.5, '22':9.5, '25':9.5}
462
 
FHDiameters = ['Auto', 'M2.5', 'M3', 'M3.5', 'M4', 'M5', 'M6', 'M8']
 
443
#BSLengths = {'6':3.2, '8':4, '10':4, '12':5, '14':6.5, '16':6.5, '18':9.5, '20':9.5, '22':9.5, '25':9.5}
 
444
FHDiameters = ['Auto', 'M2.5', 'M3', 'M3.5', 'M4', 'M5', 'M6', 'M8' ]
463
445
FHPEMTable = {
464
 
    #          H,    S,    d, Lmin, Lmax
465
 
    'M2.5': (4.1, 1.95, 2.05, 6, 18),
466
 
    'M3': (4.6, 2.1, 2.5, 6, 25),
467
 
    'M3.5': (5.3, 2.25, 2.9, 6, 30),
468
 
    'M4': (5.9, 2.4, 3.3, 6, 35),
469
 
    'M5': (6.5, 2.7, 4.2, 8, 35),
470
 
    'M6': (8.2, 3.0, 5.0, 10, 35),
471
 
    'M8': (9.6, 3.7, 6.75, 12, 35)
472
 
}
473
 
 
 
446
#          H,    S,    d, Lmin, Lmax
 
447
  'M2.5': (4.1,  1.95, 2.05, 6,  18),
 
448
  'M3':   (4.6,  2.1,  2.5,  6,  25),
 
449
  'M3.5': (5.3,  2.25, 2.9,  6,  30),
 
450
  'M4':   (5.9,  2.4,  3.3,  6,  35),
 
451
  'M5':   (6.5,  2.7,  4.2,  8,  35),
 
452
  'M6':   (8.2,  3.0,  5.0,  10, 35),
 
453
  'M8':   (9.6,  3.7, 6.75, 12, 35)
 
454
  }
474
455
 
475
456
def fhMakeFace(m, h, d, l):
476
 
    h10 = h / 10.0
477
 
    h20 = h / 20.0
478
 
    m25 = m * 0.025
479
 
    hs = 0.8 + 0.125 * m
480
 
    he = 0.8 + 0.2 * m
481
 
    h = h / 2.0
482
 
    m = m / 2.0
483
 
    d = d / 2.0
484
 
    h85 = h * 0.85
485
 
    m9 = m * 0.9
486
 
    mr = m9 - m25 * (1.0 - cos30)
487
 
    ch1 = m - d
488
 
 
489
 
    fm = FastenerBase.FSFaceMaker()
490
 
    fm.AddPoint(0, 0)
491
 
    fm.AddPoint(h - h20, 0)
492
 
    fm.AddArc(h, - h20, h - h20, -h10)
493
 
    fm.AddPoint(h - h20, -(h10 + h20))
494
 
    fm.AddPoint(m, -(h10 + h20))
495
 
    fm.AddPoint(m, -hs)
496
 
    fm.AddPoint(m9, -(hs + m25))
497
 
    fm.AddArc(mr, -(hs + m25 * 1.5), m9, -(hs + m25 * 2))
498
 
    fm.AddPoint(m, -he)
499
 
    fm.AddPoint(m, -(l - ch1))
500
 
    fm.AddPoint(m - ch1, -l)
501
 
    fm.AddPoint(0, -l)
502
 
    return fm.GetFace()
503
 
 
 
457
  h10 = h / 10.0
 
458
  h20 = h / 20.0
 
459
  m25 = m * 0.025
 
460
  hs = 0.8 + 0.125 * m
 
461
  he = 0.8 + 0.2 * m
 
462
  h = h / 2.0
 
463
  m = m / 2.0
 
464
  d = d / 2.0
 
465
  h85 = h * 0.85
 
466
  m9 = m * 0.9
 
467
  mr = m9 - m25 * (1.0 - cos30)
 
468
  ch1 = m - d
 
469
  
 
470
  fm = FastenerBase.FSFaceMaker()
 
471
  fm.AddPoint(0, 0)
 
472
  fm.AddPoint(h - h20, 0)
 
473
  fm.AddArc(h, - h20, h - h20, -h10)
 
474
  fm.AddPoint(h - h20, -(h10 + h20))
 
475
  fm.AddPoint(m , -(h10 + h20))
 
476
  fm.AddPoint(m , -hs)
 
477
  fm.AddPoint(m9, -(hs + m25))
 
478
  fm.AddArc(mr, -(hs + m25 * 1.5), m9, -(hs + m25 * 2))
 
479
  fm.AddPoint(m, -he)
 
480
  fm.AddPoint(m, -(l - ch1))
 
481
  fm.AddPoint(m - ch1, -l)
 
482
  fm.AddPoint(0, -l)
 
483
  return fm.GetFace()
504
484
 
505
485
def fhMakeStud(diam, len):
506
 
    if not (len in FHLengths):
507
 
        return None
508
 
    if not (diam in FHPEMTable):
509
 
        return None
510
 
 
511
 
    key, shape = FastenerBase.FSGetKey('Stud', diam, len)
512
 
    if shape is not None:
513
 
        return shape
514
 
 
515
 
    l = int(len)
516
 
    m = FastenerBase.MToFloat(diam)
517
 
    h, s, d, lmin, lmax = FHPEMTable[diam]
518
 
    if l < lmin or l > lmax:
519
 
        return None
520
 
 
521
 
    f = fhMakeFace(m, h, d, l)
522
 
    p = f.revolve(Base.Vector(0.0, 0.0, 0.0), Base.Vector(0.0, 0.0, 1.0), 360)
523
 
    FastenerBase.FSCache[key] = p
524
 
    return p
 
486
  if not(len in FHLengths):
 
487
    return None
 
488
  if not(diam in FHPEMTable):
 
489
    return None
 
490
 
 
491
  key, shape = FastenerBase.FSGetKey('Stud', diam, len)
 
492
  if shape is not None:
 
493
    return shape
 
494
  
 
495
  l = int(len)
 
496
  m = FastenerBase.MToFloat(diam)
 
497
  h, s, d, lmin, lmax = FHPEMTable[diam]
 
498
  if l < lmin or l > lmax:
 
499
    return None
 
500
  
 
501
  f = fhMakeFace(m, h, d, l)
 
502
  p = f.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)
 
503
  FastenerBase.FSCache[key] = p
 
504
  return p
525
505
 
526
506
 
527
507
def fhFindClosest(diam, len):
528
 
    ''' Find closest standard screw to given parameters '''
529
 
    if not (diam in FHPEMTable):
530
 
        return None
531
 
    if float(len) > FHPEMTable[diam][4]:
532
 
        return str(FHPEMTable[diam][4])
533
 
    if float(len) < FHPEMTable[diam][3]:
534
 
        return str(FHPEMTable[diam][3])
535
 
    return len
 
508
  ''' Find closest standard screw to given parameters '''
 
509
  if not(diam in FHPEMTable):
 
510
    return None
 
511
  if float(len) > FHPEMTable[diam][4]:
 
512
    return str(FHPEMTable[diam][4])
 
513
  if float(len) < FHPEMTable[diam][3]:
 
514
    return str(FHPEMTable[diam][3])
 
515
  return len
536
516
 
537
517
 
538
518
def fhGetAllLengths(diam):
539
 
    h, s, d, lmin, lmax = FHPEMTable[diam]
540
 
    list = []
541
 
    for len in FHLengths:
542
 
        l = float(len)
543
 
        if l >= lmin and l <= lmax:
544
 
            list.append(len)
545
 
    try:  # py3
546
 
        import functools
547
 
        sorted(list, key=functools.cmp_to_key(FastenerBase.NumCompare))
548
 
    except:
549
 
        list.sort(cmp=FastenerBase.NumCompare)
550
 
    return list
551
 
 
552
 
 
 
519
  h, s, d, lmin, lmax = FHPEMTable[diam]
 
520
  list = []
 
521
  for len in FHLengths:
 
522
    l = float(len)
 
523
    if l >= lmin and l <= lmax:
 
524
      list.append(len)
 
525
  try:  # py3
 
526
    import functools
 
527
    sorted(list, key=functools.cmp_to_key(FastenerBase.NumCompare))
 
528
  except:
 
529
    list.sort(cmp=FastenerBase.NumCompare)
 
530
  return list
 
531
 
 
532
  
553
533
class FSStudObject(FSBaseObject):
554
 
    def __init__(self, obj, attachTo):
555
 
        '''"Add Stud (self clinching) type fastener" '''
556
 
        FSBaseObject.__init__(self, obj, attachTo)
557
 
        self.itemText = "Stud"
558
 
        # self.Proxy = obj.Name
559
 
 
560
 
        obj.addProperty("App::PropertyEnumeration", "diameter", "Parameters",
561
 
                        "Standoff thread diameter").diameter = FHDiameters
562
 
        obj.addProperty("App::PropertyEnumeration", "length", "Parameters", "Standoff length").length = fhGetAllLengths(
563
 
            FHDiameters[1])
564
 
        obj.invert = FastenerBase.FSLastInvert
565
 
        obj.Proxy = self
566
 
 
567
 
    def execute(self, fp):
568
 
        '''"Print a short message when doing a recomputation, this method is mandatory" '''
569
 
 
570
 
        try:
571
 
            baseobj = fp.baseObject[0]
572
 
            shape = baseobj.Shape.getElement(fp.baseObject[1][0])
573
 
        except:
574
 
            baseobj = None
575
 
            shape = None
576
 
        self.updateProps(fp)
577
 
        if not (hasattr(self, 'diameter')) or self.diameter != fp.diameter or self.length != fp.length:
578
 
            diameterchange = False
579
 
            if not (hasattr(self, 'diameter')) or self.diameter != fp.diameter:
580
 
                diameterchange = True
581
 
            if fp.diameter == 'Auto':
582
 
                d = FastenerBase.FSAutoDiameterM(shape, FHPEMTable, -1)
583
 
                diameterchange = True
584
 
            else:
585
 
                d = fp.diameter
586
 
 
587
 
            l = fhFindClosest(d, fp.length)
588
 
            if d != fp.diameter:
589
 
                diameterchange = True
590
 
                fp.diameter = d
591
 
 
592
 
            if l != fp.length or diameterchange:
593
 
                if diameterchange:
594
 
                    fp.length = fhGetAllLengths(fp.diameter)
595
 
                fp.length = l
596
 
 
597
 
            s = fhMakeStud(d, l)
598
 
            self.diameter = fp.diameter
599
 
            self.length = fp.length
600
 
            FastenerBase.FSLastInvert = fp.invert
601
 
            fp.Label = fp.diameter + 'x' + fp.length + '-Stud'
602
 
            fp.Shape = s
603
 
        else:
604
 
            FreeCAD.Console.PrintLog("Using cached object\n")
605
 
        if shape is not None:
606
 
            # feature = FreeCAD.ActiveDocument.getObject(self.Proxy)
607
 
            # fp.Placement = FreeCAD.Placement() # reset placement
608
 
            FastenerBase.FSMoveToObject(fp, shape, fp.invert, fp.offset.Value)
609
 
 
610
 
 
611
 
FastenerBase.FSClassIcons[FSStudObject] = 'PEMStud.svg'
 
534
  def __init__(self, obj, attachTo):
 
535
    '''"Add Stud (self clinching) type fastener" '''
 
536
    FSBaseObject.__init__(self, obj, attachTo)
 
537
    self.itemText = "Stud"
 
538
    #self.Proxy = obj.Name
 
539
    
 
540
    obj.addProperty("App::PropertyEnumeration","diameter","Parameters","Standoff thread diameter").diameter = FHDiameters
 
541
    obj.addProperty("App::PropertyEnumeration","length","Parameters","Standoff length").length = fhGetAllLengths(FHDiameters[1])
 
542
    obj.invert = FastenerBase.FSLastInvert
 
543
    obj.Proxy = self
 
544
 
 
545
  def execute(self, fp):
 
546
    '''"Print a short message when doing a recomputation, this method is mandatory" '''
 
547
    
 
548
    try:
 
549
      baseobj = fp.baseObject[0]
 
550
      shape = baseobj.Shape.getElement(fp.baseObject[1][0])
 
551
    except:
 
552
      baseobj = None
 
553
      shape = None
 
554
    self.updateProps(fp)
 
555
    if not (hasattr(self, 'diameter')) or self.diameter != fp.diameter or self.length != fp.length:
 
556
      diameterchange = False      
 
557
      if not (hasattr(self, 'diameter')) or self.diameter != fp.diameter:
 
558
        diameterchange = True      
 
559
      if fp.diameter == 'Auto':
 
560
        d = FastenerBase.FSAutoDiameterM(shape, FHPEMTable, -1)
 
561
        diameterchange = True      
 
562
      else:
 
563
        d = fp.diameter
 
564
        
 
565
      l = fhFindClosest(d, fp.length)
 
566
      if d != fp.diameter:
 
567
        diameterchange = True      
 
568
        fp.diameter = d
 
569
 
 
570
      if l != fp.length or diameterchange:
 
571
        if diameterchange:
 
572
          fp.length = fhGetAllLengths(fp.diameter)
 
573
        fp.length = l
 
574
               
 
575
      s = fhMakeStud(d, l)
 
576
      self.diameter = fp.diameter
 
577
      self.length = fp.length
 
578
      FastenerBase.FSLastInvert = fp.invert
 
579
      fp.Label = fp.diameter + 'x' + fp.length + '-Stud'
 
580
      fp.Shape = s
 
581
    else:
 
582
      FreeCAD.Console.PrintLog("Using cached object\n")
 
583
    if shape is not None:
 
584
      #feature = FreeCAD.ActiveDocument.getObject(self.Proxy)
 
585
      #fp.Placement = FreeCAD.Placement() # reset placement
 
586
      FastenerBase.FSMoveToObject(fp, shape, fp.invert, fp.offset.Value)
 
587
 
 
588
 
 
589
FastenerBase.FSClassIcons[FSStudObject] = 'PEMStud.svg'    
612
590
 
613
591
 
614
592
class FSStudCommand:
615
 
    """Add Standoff command"""
616
 
 
617
 
    def GetResources(self):
618
 
        icon = os.path.join(iconPath, 'PEMStud.svg')
619
 
        return {
620
 
            'Pixmap': icon,  # the name of a svg file available in the resources
621
 
            'MenuText': "Add Stud",
622
 
            'ToolTip': "Add PEM Self Clinching Metric Stud"
623
 
        }
624
 
 
625
 
    def Activated(self):
626
 
        FastenerBase.FSGenerateObjects(FSStudObject, "Stud")
627
 
        return
628
 
 
629
 
    def IsActive(self):
630
 
        return Gui.ActiveDocument is not None
631
 
 
 
593
  """Add Standoff command"""
 
594
 
 
595
  def GetResources(self):
 
596
    icon = os.path.join( iconPath , 'PEMStud.svg')
 
597
    return {'Pixmap'  : icon , # the name of a svg file available in the resources
 
598
            'MenuText': "Add Stud" ,
 
599
            'ToolTip' : "Add PEM Self Clinching Metric Stud"}
 
600
 
 
601
  def Activated(self):
 
602
    FastenerBase.FSGenerateObjects(FSStudObject, "Stud")
 
603
    return
 
604
   
 
605
  def IsActive(self):
 
606
    return Gui.ActiveDocument is not None
632
607
 
633
608
Gui.addCommand("FSStud", FSStudCommand())
634
609
FastenerBase.FSCommands.append("FSStud", "screws", "PEM Inserts")
643
618
FastenerBase.FSAddFastenerType("HeatSet", False)
644
619
FastenerBase.FSAddItemsToType("HeatSet", "HeatSet")
645
620
 
646
 
 
647
621
def FSPIGetAllDiameters(type):
648
 
    if type == "PressNut":
649
 
        diams = list(CLSDiamCodes)
650
 
    elif type == "StandOff":
651
 
        diams = list(SODiameters)
652
 
    elif type == "Stud":
653
 
        diams = list(FHDiameters)
654
 
    diams.pop(0)
655
 
    return diams
656
 
 
657
 
 
 
622
  if type == "PressNut":
 
623
    diams = list(CLSDiamCodes)
 
624
  elif type == "StandOff":
 
625
    diams = list(SODiameters)
 
626
  elif type == "Stud":
 
627
    diams = list(FHDiameters)
 
628
  diams.pop(0)
 
629
  return diams
 
630
  
658
631
def FSPIGetAllLengths(type, diam):
659
 
    # if type == "PressNut":
660
 
    #  return []
661
 
    if type == "StandOff":
662
 
        return soGetAllLengths(diam, False)
663
 
    elif type == "Stud":
664
 
        return fhGetAllLengths(diam)
665
 
    return []
 
632
  #if type == "PressNut":
 
633
  #  return []
 
634
  if type == "StandOff":
 
635
    return soGetAllLengths(diam, False)
 
636
  elif type == "Stud":
 
637
    return fhGetAllLengths(diam)
 
638
  return []
666
639
 
667
640
 
668
641
###################################################################################
669
642
# PCB standoffs / Wurth standard WA-SSTIE 
670
643
PSLengths = {
671
 
    'M2.5x5': ('5', '6', '7', '8', '9', '10', '12', '15', '17', '18', '20', '25', '30'),
672
 
    'M3x5': ('10', '15', '20', '25'),
673
 
    'M3x5.5': (
674
 
    '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '22', '23', '25', '27',
675
 
    '28', '30', '35', '40', '45', '50', '55', '60'),
676
 
    'M3x6': ('8', '10', '12', '15', '20', '25', '30', '35', '40'),
677
 
    'M4x7': ('5', '6', '8', '10', '12', '15', '20', '25', '30', '35', '40'),
678
 
    'M5x8': ('8', '10', '15', '20', '25', '30', '40', '50', '60', '70'),
679
 
    'M6x10': ('15', '20', '25', '30', '35', '40', '45', '50', '60')
 
644
  'M2.5x5': ('5', '6', '7', '8', '9', '10', '12', '15', '17', '18', '20', '25', '30'),
 
645
  'M3x5': ('10', '15', '20', '25'),
 
646
  'M3x5.5': ('5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '22', '23', '25', '27', '28', '30', '35', '40', '45', '50', '55', '60'),
 
647
  'M3x6': ('8', '10', '12', '15', '20', '25', '30', '35', '40'),
 
648
  'M4x7': ('5', '6', '8', '10', '12', '15', '20', '25', '30', '35', '40'),
 
649
  'M5x8': ('8', '10', '15', '20', '25', '30', '40', '50', '60', '70'),
 
650
  'M6x10': ('15', '20', '25', '30', '35', '40', '45', '50', '60')
680
651
}
681
 
PSDiameters = ['Auto', 'M2.5', 'M3', 'M4', 'M5', 'M6']
 
652
PSDiameters = ['Auto', 'M2.5', 'M3', 'M4', 'M5', 'M6' ]
682
653
PSMTable = {
683
 
    #          Tlo, id,   SW(s)
684
 
    'M2.5': (6, 2.05, ('5',)),
685
 
    'M3': (6, 2.5, ('5', '5.5', '6')),
686
 
    'M4': (8, 3.3, ('7',)),
687
 
    'M5': (10, 4.2, ('8',)),
688
 
    'M6': (10, 5, ('10',))
689
 
}
 
654
#          Tlo, id,   SW(s)
 
655
  'M2.5': (6,   2.05, ('5',)),
 
656
  'M3':   (6,   2.5,  ('5', '5.5', '6')),
 
657
  'M4':   (8,   3.3,  ('7',)),
 
658
  'M5':   (10,  4.2,  ('8',)),
 
659
  'M6':   (10,  5,    ('10',))
 
660
  }
690
661
 
691
662
 
692
663
def psMakeFace(m, sw, lo, l, id):
693
 
    l = float(l)
694
 
    id2 = id / 2.0
695
 
    sw2 = float(sw) / 2.0
696
 
    m2 = m / 2.0
697
 
    d2 = 0.95 * sw2 / cos30
698
 
    l1 = l - (d2 - sw2) / 2.0
699
 
    dd = m2 - id2
700
 
    lo1 = -0.6
701
 
    lo2 = lo1 - dd
702
 
    lo3 = dd - lo
703
 
    p = l - 10
704
 
    if p < 1:
705
 
        p = 1
706
 
    p1 = p + id2
707
 
 
708
 
    fm = FastenerBase.FSFaceMaker()
709
 
    fm.AddPoint(0, p)
710
 
    fm.AddPoint(id2, p1)
711
 
    fm.AddPoint(id2, l - dd)
712
 
    fm.AddPoint(id2 + dd, l)
713
 
    fm.AddPoint(sw2, l)
714
 
    fm.AddPoint(d2, l1)
715
 
    fm.AddPoint(d2, 0)
716
 
    fm.AddPoint(id2, 0)
717
 
    fm.AddPoint(id2, lo1)
718
 
    fm.AddPoint(m2, lo2)
719
 
    fm.AddPoint(m2, lo3)
720
 
    fm.AddPoint(id2, -lo)
721
 
    fm.AddPoint(0, -lo)
722
 
    return fm.GetFace()
723
 
 
 
664
  l = float(l)
 
665
  id2 = id / 2.0
 
666
  sw2 = float(sw) / 2.0
 
667
  m2 = m / 2.0
 
668
  d2 = 0.95 * sw2 / cos30
 
669
  l1 = l - (d2 - sw2) / 2.0
 
670
  dd = m2 - id2
 
671
  lo1 = -0.6
 
672
  lo2 = lo1 - dd
 
673
  lo3 = dd - lo
 
674
  p = l - 10
 
675
  if p < 1:
 
676
    p = 1
 
677
  p1 = p + id2
 
678
 
 
679
  fm = FastenerBase.FSFaceMaker()
 
680
  fm.AddPoint(0, p)
 
681
  fm.AddPoint(id2, p1)
 
682
  fm.AddPoint(id2, l - dd)
 
683
  fm.AddPoint(id2 + dd, l)
 
684
  fm.AddPoint(sw2, l)
 
685
  fm.AddPoint(d2, l1)
 
686
  fm.AddPoint(d2, 0)
 
687
  fm.AddPoint(id2, 0)
 
688
  fm.AddPoint(id2, lo1)
 
689
  fm.AddPoint(m2, lo2)
 
690
  fm.AddPoint(m2, lo3)
 
691
  fm.AddPoint(id2, -lo)
 
692
  fm.AddPoint(0, -lo)
 
693
  return fm.GetFace()
724
694
 
725
695
def psMakeStandOff(diam, len, width, screwlen):
726
 
    FreeCAD.Console.PrintLog("Making PCB standof" + diam + "x" + len + "x" + width + "x" + str(screwlen) + "\n")
727
 
    if not (diam in PSMTable):
728
 
        return None
729
 
    lenKey = diam + "x" + width
730
 
    if not (lenKey in PSLengths):
731
 
        return None
732
 
 
733
 
    (key, shape) = FastenerBase.FSGetKey('PcbStandOff', diam, width, len, screwlen)
734
 
    if shape is not None:
735
 
        return shape
736
 
 
737
 
    tlo, id, sw = PSMTable[diam]
738
 
 
739
 
    m = FastenerBase.MToFloat(diam)
740
 
    f = psMakeFace(m, width, screwlen, len, id)
741
 
    p = f.revolve(Base.Vector(0.0, 0.0, 0.0), Base.Vector(0.0, 0.0, 1.0), 360)
742
 
    w = float(width)
743
 
    l = float(len)
744
 
    htool = screwMaker.makeHextool(w, l + screwlen, w * 2)
745
 
    htool.translate(Base.Vector(0.0, 0.0, -screwlen - 0.1))
746
 
    shape = p.cut(htool)
747
 
    FastenerBase.FSCache[key] = shape
 
696
  FreeCAD.Console.PrintLog("Making PCB standof" + diam + "x" + len + "x" + width + "x" + str(screwlen) + "\n")
 
697
  if not(diam in PSMTable):
 
698
    return None
 
699
  lenKey = diam + "x" + width
 
700
  if not(lenKey in PSLengths):
 
701
    return None
 
702
 
 
703
  (key, shape) = FastenerBase.FSGetKey('PcbStandOff', diam, width, len, screwlen)
 
704
  if shape is not None:
748
705
    return shape
 
706
  
 
707
  tlo, id, sw = PSMTable[diam]
749
708
 
 
709
  m = FastenerBase.MToFloat(diam)
 
710
  f = psMakeFace(m, width, screwlen, len, id)
 
711
  p = f.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)
 
712
  w = float(width)
 
713
  l = float(len)
 
714
  htool = screwMaker.makeHextool(w, l + screwlen, w * 2)
 
715
  htool.translate(Base.Vector(0.0,0.0,-screwlen - 0.1))
 
716
  shape = p.cut(htool)
 
717
  FastenerBase.FSCache[key] = shape
 
718
  return shape
750
719
 
751
720
def psFindClosest(mtable, ltable, diam, width, len):
752
 
    ''' Find closest standard standoff to given parameters '''
753
 
    if not (diam in mtable):
754
 
        return None
755
 
    lenKey = diam + "x" + width
756
 
    if not (lenKey in ltable):
757
 
        return None
758
 
    lens = ltable[lenKey]
759
 
    for l in lens:
760
 
        if float(len) <= float(l):
761
 
            return l
762
 
    return lens[len(lens) - 1]
763
 
 
 
721
  ''' Find closest standard standoff to given parameters '''
 
722
  if not(diam in mtable):
 
723
    return None
 
724
  lenKey = diam + "x" + width
 
725
  if not(lenKey in ltable):
 
726
    return None
 
727
  lens = ltable[lenKey]
 
728
  for l in lens:
 
729
    if float(len) <= float(l):
 
730
      return l
 
731
  return lens[len(lens) - 1]
764
732
 
765
733
def psGetAllWidths(mtable, diam):
766
 
    if not (diam in mtable):
767
 
        return None
768
 
    list = mtable[diam][2]
769
 
    try:  # py3
770
 
        import functools
771
 
        sorted(list, key=functools.cmp_to_key(FastenerBase.NumCompare))
772
 
    except:
773
 
        list.sort(cmp=FastenerBase.NumCompare)
774
 
    return list
775
 
 
776
 
 
 
734
  if not(diam in mtable):
 
735
    return None
 
736
  list = mtable[diam][2]
 
737
  try:  # py3
 
738
    import functools
 
739
    sorted(list, key = functools.cmp_to_key(FastenerBase.NumCompare))
 
740
  except:
 
741
    list.sort(cmp = FastenerBase.NumCompare)
 
742
  return list
 
743
 
 
744
 
777
745
def psGetAllLengths(mtable, ltable, diam, width):
778
 
    if not (diam in mtable):
779
 
        return None
780
 
    if width not in mtable[diam][2]:
781
 
        width = mtable[diam][2][0]
782
 
    lenKey = diam + "x" + width
783
 
    if not (lenKey in ltable):
784
 
        return None
785
 
    list = []
786
 
    for len in ltable[lenKey]:
787
 
        list.append(len)
788
 
    try:  # py3
789
 
        import functools
790
 
        sorted(list, key=functools.cmp_to_key(FastenerBase.NumCompare))
791
 
    except:
792
 
        list.sort(cmp=FastenerBase.NumCompare)
793
 
    list.append("Custom")
794
 
    return list
795
 
 
 
746
  if not(diam in mtable):
 
747
    return None
 
748
  if width not in mtable[diam][2]:
 
749
    width = mtable[diam][2][0]
 
750
  lenKey = diam + "x" + width
 
751
  if not(lenKey in ltable):
 
752
    return None
 
753
  list = []
 
754
  for len in ltable[lenKey]:
 
755
    list.append(len)
 
756
  try:  # py3
 
757
    import functools
 
758
    sorted(list, key=functools.cmp_to_key(FastenerBase.NumCompare))
 
759
  except:
 
760
    list.sort(cmp=FastenerBase.NumCompare)
 
761
  list.append("Custom")
 
762
  return list
796
763
 
797
764
# h = clMakePressNut('M5','1')
798
765
 
799
766
class FSPcbStandOffObject(FSBaseObject):
800
 
    def __init__(self, obj, attachTo):
801
 
        '''"Add PCB StandOff type fastener" '''
802
 
        FSBaseObject.__init__(self, obj, attachTo)
803
 
        self.itemText = "PcbStandOff"
804
 
        # self.Proxy = obj.Name
805
 
 
806
 
        obj.addProperty("App::PropertyEnumeration", "diameter", "Parameters",
807
 
                        "Standoff thread diameter").diameter = PSDiameters
808
 
        widths = psGetAllWidths(PSMTable, PSDiameters[1])
809
 
        obj.addProperty("App::PropertyEnumeration", "width", "Parameters", "Standoff body width").width = widths
810
 
        self.VerifyMissingAttrs(obj, PSDiameters[1], widths[0])
811
 
        # obj.addProperty("App::PropertyEnumeration","length","Parameters","Standoff length").length = psGetAllLengths(PSMTable, PSLengths ,PSDiameters[1], widths[0])
812
 
        obj.invert = FastenerBase.FSLastInvert
813
 
        obj.Proxy = self
814
 
 
815
 
    def VerifyMissingAttrs(self, obj, diam, width):
816
 
        self.updateProps(obj)
817
 
        if not hasattr(obj, 'lengthCustom'):
818
 
            slens = psGetAllLengths(PSMTable, PSLengths, diam, width)
819
 
            if hasattr(obj, 'length'):
820
 
                origLen = obj.length
821
 
                obj.length = slens
822
 
                if origLen not in slens:
823
 
                    obj.length = slens[0]
824
 
                else:
825
 
                    obj.length = origLen
826
 
            else:
827
 
                obj.addProperty("App::PropertyEnumeration", "length", "Parameters", "Standoff length").length = slens
828
 
            obj.addProperty("App::PropertyLength", "lengthCustom", "Parameters", "Custom length").lengthCustom = slens[
829
 
                0]
830
 
        if not hasattr(obj, 'screwLength'):
831
 
            obj.addProperty("App::PropertyLength", "screwLength", "Parameters", "Thread length").screwLength = \
832
 
            PSMTable[diam][0]
833
 
 
834
 
    def ActiveLength(self, obj):
835
 
        if not hasattr(obj, 'length'):
836
 
            return '0'
837
 
        if obj.length == 'Custom':
838
 
            return str(float(obj.lengthCustom)).rstrip("0").rstrip('.')
839
 
        return obj.length
840
 
 
841
 
    def execute(self, fp):
842
 
        '''"Print a short message when doing a recomputation, this method is mandatory" '''
843
 
 
844
 
        try:
845
 
            baseobj = fp.baseObject[0]
846
 
            shape = baseobj.Shape.getElement(fp.baseObject[1][0])
847
 
        except:
848
 
            baseobj = None
849
 
            shape = None
850
 
 
851
 
        # for backward compatibility: add missing attribute if needed
852
 
        self.VerifyMissingAttrs(fp, fp.diameter, fp.width)
853
 
 
854
 
        diameterchange = not (hasattr(self, 'diameter')) or self.diameter != fp.diameter
855
 
        widthchange = not (hasattr(self, 'width')) or self.width != fp.width
856
 
        lengthchange = not (hasattr(self, 'length')) or self.length != fp.length
857
 
        cutstlenchange = not (hasattr(self, 'lengthCustom')) or self.lengthCustom != fp.lengthCustom
858
 
        screwlenchange = not (hasattr(self, 'screwLength')) or self.screwLength != fp.screwLength
859
 
        if diameterchange or widthchange or lengthchange or cutstlenchange or screwlenchange:
860
 
            if fp.diameter == 'Auto':
861
 
                d = FastenerBase.FSAutoDiameterM(shape, PSMTable, 1)
862
 
                diameterchange = True
863
 
            else:
864
 
                d = fp.diameter
865
 
 
866
 
            if d != fp.diameter:
867
 
                diameterchange = True
868
 
                fp.diameter = d
869
 
 
870
 
            if widthchange or diameterchange:
871
 
                widthchange = True
872
 
                if diameterchange:
873
 
                    allwidth = psGetAllWidths(PSMTable, d)
874
 
                    fp.width = allwidth
875
 
                    if len(allwidth) > 1:
876
 
                        fp.width = allwidth[1]
877
 
                    else:
878
 
                        fp.width = allwidth[0]
879
 
 
880
 
            if not lengthchange and hasattr(self, 'lengthCustom') and self.lengthCustom != fp.lengthCustom.Value:
881
 
                fp.length = 'Custom'
882
 
 
883
 
            if fp.length == 'Custom':
884
 
                l = str(float(fp.lengthCustom)).rstrip("0").rstrip('.')
885
 
            else:
886
 
                l = psFindClosest(PSMTable, PSLengths, d, fp.width, fp.length)
887
 
 
888
 
                if l != fp.length or diameterchange or widthchange:
889
 
                    if diameterchange or widthchange:
890
 
                        fp.length = psGetAllLengths(PSMTable, PSLengths, fp.diameter, fp.width)
891
 
                    fp.length = l
892
 
                fp.lengthCustom = l
893
 
 
894
 
            if diameterchange:
895
 
                fp.screwLength = PSMTable[fp.diameter][0]
896
 
            elif fp.screwLength < 2:
897
 
                fp.screwLength = 2
898
 
 
899
 
            s = psMakeStandOff(d, l, fp.width, float(fp.screwLength))
900
 
 
901
 
            self.diameter = fp.diameter
902
 
            self.length = fp.length
903
 
            self.width = fp.width
904
 
            self.lengthCustom = fp.lengthCustom.Value
905
 
            self.screwLength = fp.screwLength.Value
906
 
            FastenerBase.FSLastInvert = fp.invert
907
 
            fp.Label = fp.diameter + 'x' + fp.width + 'x' + l + '-Standoff'
908
 
            fp.Shape = s
 
767
  def __init__(self, obj, attachTo):
 
768
    '''"Add PCB StandOff type fastener" '''
 
769
    FSBaseObject.__init__(self, obj, attachTo)
 
770
    self.itemText = "PcbStandOff"
 
771
    #self.Proxy = obj.Name
 
772
    
 
773
    obj.addProperty("App::PropertyEnumeration","diameter","Parameters","Standoff thread diameter").diameter = PSDiameters
 
774
    widths = psGetAllWidths(PSMTable ,PSDiameters[1])
 
775
    obj.addProperty("App::PropertyEnumeration", "width", "Parameters", "Standoff body width").width = widths
 
776
    self.VerifyMissingAttrs(obj, PSDiameters[1], widths[0])
 
777
    #obj.addProperty("App::PropertyEnumeration","length","Parameters","Standoff length").length = psGetAllLengths(PSMTable, PSLengths ,PSDiameters[1], widths[0])
 
778
    obj.invert = FastenerBase.FSLastInvert
 
779
    obj.Proxy = self
 
780
 
 
781
  def VerifyMissingAttrs(self, obj, diam, width):
 
782
    self.updateProps(obj)
 
783
    if not hasattr(obj, 'lengthCustom'):
 
784
      slens = psGetAllLengths(PSMTable, PSLengths ,diam, width)
 
785
      if hasattr(obj, 'length'):
 
786
        origLen = obj.length
 
787
        obj.length = slens
 
788
        if origLen not in slens:
 
789
          obj.length = slens[0]
909
790
        else:
910
 
            FreeCAD.Console.PrintLog("Using cached object\n")
911
 
        if shape is not None:
912
 
            # feature = FreeCAD.ActiveDocument.getObject(self.Proxy)
913
 
            # fp.Placement = FreeCAD.Placement() # reset placement
914
 
            FastenerBase.FSMoveToObject(fp, shape, fp.invert, fp.offset.Value)
915
 
 
916
 
 
917
 
FastenerBase.FSClassIcons[FSPcbStandOffObject] = 'PCBStandoff.svg'
918
 
 
 
791
          obj.length = origLen
 
792
      else:
 
793
        obj.addProperty("App::PropertyEnumeration", "length", "Parameters", "Standoff length").length = slens
 
794
      obj.addProperty("App::PropertyLength", "lengthCustom", "Parameters", "Custom length").lengthCustom = slens[0]
 
795
    if not hasattr(obj, 'screwLength'):
 
796
      obj.addProperty("App::PropertyLength", "screwLength", "Parameters", "Thread length").screwLength = PSMTable[diam][0]
 
797
 
 
798
  def ActiveLength(self, obj):
 
799
    if not hasattr(obj,'length'):
 
800
      return '0'
 
801
    if obj.length == 'Custom':
 
802
      return str(float(obj.lengthCustom)).rstrip("0").rstrip('.')
 
803
    return obj.length
 
804
 
 
805
  def execute(self, fp):
 
806
    '''"Print a short message when doing a recomputation, this method is mandatory" '''
 
807
    
 
808
    try:
 
809
      baseobj = fp.baseObject[0]
 
810
      shape = baseobj.Shape.getElement(fp.baseObject[1][0])
 
811
    except:
 
812
      baseobj = None
 
813
      shape = None
 
814
  
 
815
    # for backward compatibility: add missing attribute if needed
 
816
    self.VerifyMissingAttrs(fp, fp.diameter, fp.width)
 
817
 
 
818
    diameterchange = not (hasattr(self, 'diameter')) or self.diameter != fp.diameter
 
819
    widthchange = not(hasattr(self, 'width')) or self.width != fp.width
 
820
    lengthchange = not(hasattr(self, 'length')) or self.length != fp.length
 
821
    cutstlenchange = not(hasattr(self, 'lengthCustom')) or self.lengthCustom != fp.lengthCustom
 
822
    screwlenchange = not(hasattr(self, 'screwLength')) or self.screwLength != fp.screwLength
 
823
    if diameterchange or widthchange or lengthchange or cutstlenchange or screwlenchange:
 
824
      if fp.diameter == 'Auto':
 
825
        d = FastenerBase.FSAutoDiameterM(shape, PSMTable, 1)
 
826
        diameterchange = True      
 
827
      else:
 
828
        d = fp.diameter
 
829
 
 
830
      if d != fp.diameter:
 
831
        diameterchange = True      
 
832
        fp.diameter = d
 
833
 
 
834
      if widthchange or diameterchange:
 
835
        widthchange = True
 
836
        if diameterchange:
 
837
          allwidth = psGetAllWidths(PSMTable, d)
 
838
          fp.width = allwidth
 
839
          if len(allwidth) > 1:
 
840
            fp.width = allwidth[1]
 
841
          else:
 
842
            fp.width = allwidth[0]
 
843
 
 
844
      if not lengthchange and hasattr(self,'lengthCustom') and self.lengthCustom != fp.lengthCustom.Value:
 
845
        fp.length = 'Custom'
 
846
 
 
847
      if fp.length == 'Custom':
 
848
        l = str(float(fp.lengthCustom)).rstrip("0").rstrip('.')
 
849
      else:
 
850
        l = psFindClosest(PSMTable, PSLengths ,d, fp.width, fp.length)
 
851
 
 
852
        if l != fp.length or diameterchange or widthchange:
 
853
          if diameterchange or widthchange:
 
854
            fp.length = psGetAllLengths(PSMTable, PSLengths ,fp.diameter, fp.width)
 
855
          fp.length = l
 
856
        fp.lengthCustom = l
 
857
        
 
858
      if diameterchange:
 
859
        fp.screwLength = PSMTable[fp.diameter][0]
 
860
      elif fp.screwLength < 2:
 
861
        fp.screwLength = 2
 
862
 
 
863
      s = psMakeStandOff(d, l, fp.width, float(fp.screwLength))
 
864
        
 
865
      self.diameter = fp.diameter
 
866
      self.length = fp.length
 
867
      self.width = fp.width
 
868
      self.lengthCustom = fp.lengthCustom.Value
 
869
      self.screwLength = fp.screwLength.Value
 
870
      FastenerBase.FSLastInvert = fp.invert
 
871
      fp.Label = fp.diameter + 'x' + fp.width + 'x' + l + '-Standoff'
 
872
      fp.Shape = s
 
873
    else:
 
874
      FreeCAD.Console.PrintLog("Using cached object\n")
 
875
    if shape is not None:
 
876
      #feature = FreeCAD.ActiveDocument.getObject(self.Proxy)
 
877
      #fp.Placement = FreeCAD.Placement() # reset placement
 
878
      FastenerBase.FSMoveToObject(fp, shape, fp.invert, fp.offset.Value)
 
879
 
 
880
 
 
881
FastenerBase.FSClassIcons[FSPcbStandOffObject] = 'PCBStandoff.svg'    
919
882
 
920
883
class FSPcbStandOffCommand:
921
 
    """Add PCB Standoff command"""
922
 
 
923
 
    def GetResources(self):
924
 
        icon = os.path.join(iconPath, 'PCBStandoff.svg')
925
 
        return {
926
 
            'Pixmap': icon,  # the name of a svg file available in the resources
927
 
            'MenuText': "Add PCB Standoff",
928
 
            'ToolTip': "Add PCB Metric Standoff"
929
 
        }
930
 
 
931
 
    def Activated(self):
932
 
        FastenerBase.FSGenerateObjects(FSPcbStandOffObject, "PcbStandoff")
933
 
        return
934
 
 
935
 
    def IsActive(self):
936
 
        return Gui.ActiveDocument is not None
937
 
 
 
884
  """Add PCB Standoff command"""
 
885
 
 
886
  def GetResources(self):
 
887
    icon = os.path.join( iconPath , 'PCBStandoff.svg')
 
888
    return {'Pixmap'  : icon , # the name of a svg file available in the resources
 
889
            'MenuText': "Add PCB Standoff" ,
 
890
            'ToolTip' : "Add PCB Metric Standoff"}
 
891
 
 
892
  def Activated(self):
 
893
    FastenerBase.FSGenerateObjects(FSPcbStandOffObject, "PcbStandoff")
 
894
    return
 
895
   
 
896
  def IsActive(self):
 
897
    return Gui.ActiveDocument is not None
938
898
 
939
899
Gui.addCommand("FSPcbStandOff", FSPcbStandOffCommand())
940
900
FastenerBase.FSCommands.append("FSPcbStandOff", "screws", "PEM Inserts")
942
902
###################################################################################
943
903
# PCB Spacers / Wurth standard WA-SSTII 
944
904
PSPLengths = {
945
 
    'M2.5x5': ('5', '10', '11', '12', '15', '17', '18', '20', '22'),
946
 
    'M3x5': ('5', '10', '15', '20'),
947
 
    'M3x5.5': (
948
 
    '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '25',
949
 
    '27', '30', '35', '40'),
950
 
    'M4x7': ('5', '8', '10', '12', '15', '20', '25', '30', '35', '40', '45', '50', '60', '70', '80'),
951
 
    'M5x8': ('10', '12', '15', '20', '25', '30', '35', '40', '50'),
952
 
    'M6x10': ('10', '15', '20', '25', '30', '35', '40', '45', '50', '60')
 
905
  'M2.5x5' : ('5', '10', '11', '12', '15', '17', '18', '20', '22'),
 
906
  'M3x5'   : ('5', '10', '15', '20'),
 
907
  'M3x5.5' : ('5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '25', '27', '30', '35', '40'),
 
908
  'M4x7'   : ('5', '8', '10', '12', '15', '20', '25', '30', '35', '40', '45', '50', '60', '70', '80'),
 
909
  'M5x8'   : ('10', '12', '15', '20', '25', '30', '35', '40', '50'),
 
910
  'M6x10'  : ('10', '15', '20', '25', '30', '35', '40', '45', '50', '60')
953
911
}
954
 
PSPDiameters = ['Auto', 'M2.5', 'M3', 'M4', 'M5', 'M6']
 
912
PSPDiameters = ['Auto', 'M2.5', 'M3', 'M4', 'M5', 'M6' ]
955
913
PSPMTable = {
956
 
    #          Th,   id,   SW(s)
957
 
    'M2.5': (18, 2.05, ('5',)),
958
 
    'M3': (20, 2.5, ('5', '5.5')),
959
 
    'M4': (20, 3.3, ('7',)),
960
 
    'M5': (20, 4.2, ('8',)),
961
 
    'M6': (20, 5, ('10',))
962
 
}
 
914
#          Th,   id,   SW(s)
 
915
  'M2.5': (18,   2.05, ('5',)),
 
916
  'M3':   (20,   2.5,  ('5', '5.5')),
 
917
  'M4':   (20,   3.3,  ('7',)),
 
918
  'M5':   (20,   4.2,  ('8',)),
 
919
  'M6':   (20,   5,    ('10',))
 
920
  }
963
921
 
964
922
 
965
923
def pspMakeFace(m, sw, l, id, th):
966
 
    l = float(l)
967
 
    id2 = id / 2.0
968
 
    sw2 = float(sw) / 2.0
969
 
    m2 = m / 2.0
970
 
    d2 = 0.95 * sw2 / cos30
971
 
    l1 = l - (d2 - sw2) / 2.0
972
 
    dd = m2 - id2
973
 
    p = 10
974
 
    if p + 0.5 > l / 2.0:
975
 
        p = l / 2.0 - 0.5
976
 
    p1 = p - id2
977
 
 
978
 
    fm = FastenerBase.FSFaceMaker()
979
 
    fm.AddPoint(id2, l - dd)
980
 
    fm.AddPoint(id2 + dd, l)
981
 
    fm.AddPoint(sw2, l)
982
 
    fm.AddPoint(d2, l1)
983
 
    fm.AddPoint(d2, dd)
984
 
    fm.AddPoint(sw2, 0)
985
 
    fm.AddPoint(id2 + dd, 0)
986
 
    fm.AddPoint(id2, dd)
987
 
    if l > th:
988
 
        # separate holes
989
 
        fm.AddPoint(id2, p1)
990
 
        fm.AddPoint(0, p)
991
 
        fm.AddPoint(0, l - p)
992
 
        fm.AddPoint(id2, l - p1)
993
 
    return fm.GetFace()
994
 
 
 
924
  l = float(l)
 
925
  id2 = id / 2.0
 
926
  sw2 = float(sw) / 2.0
 
927
  m2 = m / 2.0
 
928
  d2 = 0.95 * sw2 / cos30
 
929
  l1 = l - (d2 - sw2) / 2.0
 
930
  dd = m2 - id2
 
931
  p = 10
 
932
  if p + 0.5 > l / 2.0:
 
933
    p = l / 2.0 - 0.5
 
934
  p1 = p - id2
 
935
 
 
936
  fm = FastenerBase.FSFaceMaker()
 
937
  fm.AddPoint(id2, l - dd)
 
938
  fm.AddPoint(id2 + dd, l)
 
939
  fm.AddPoint(sw2, l)
 
940
  fm.AddPoint(d2, l1)
 
941
  fm.AddPoint(d2, dd)
 
942
  fm.AddPoint(sw2, 0)
 
943
  fm.AddPoint(id2 + dd, 0)
 
944
  fm.AddPoint(id2, dd)
 
945
  if l > th:
 
946
    # separate holes
 
947
    fm.AddPoint(id2, p1)
 
948
    fm.AddPoint(0, p)
 
949
    fm.AddPoint(0, l - p)
 
950
    fm.AddPoint(id2, l - p1)
 
951
  return fm.GetFace()
995
952
 
996
953
def pspMakeSpacer(diam, len, width):
997
 
    FreeCAD.Console.PrintLog("Making PCB spacer" + diam + "x" + len + "x" + width + "\n")
998
 
    if not (diam in PSPMTable):
999
 
        return None
1000
 
    lenKey = diam + "x" + width
1001
 
    if not (lenKey in PSPLengths):
1002
 
        return None
1003
 
 
1004
 
    (key, shape) = FastenerBase.FSGetKey('PcbSpacer', diam, width, len)
1005
 
    if shape is not None:
1006
 
        return shape
1007
 
 
1008
 
    th, id, sw = PSPMTable[diam]
1009
 
 
1010
 
    m = FastenerBase.MToFloat(diam)
1011
 
    f = pspMakeFace(m, width, len, id, th)
1012
 
    p = f.revolve(Base.Vector(0.0, 0.0, 0.0), Base.Vector(0.0, 0.0, 1.0), 360)
1013
 
    w = float(width)
1014
 
    l = float(len)
1015
 
    htool = screwMaker.makeHextool(w, l, w * 2)
1016
 
    htool.translate(Base.Vector(0.0, 0.0, - 0.1))
1017
 
    shape = p.cut(htool)
1018
 
    FastenerBase.FSCache[key] = shape
 
954
  FreeCAD.Console.PrintLog("Making PCB spacer" + diam + "x" + len + "x" + width + "\n")
 
955
  if not(diam in PSPMTable):
 
956
    return None
 
957
  lenKey = diam + "x" + width
 
958
  if not(lenKey in PSPLengths):
 
959
    return None
 
960
 
 
961
  (key, shape) = FastenerBase.FSGetKey('PcbSpacer', diam, width, len)
 
962
  if shape is not None:
1019
963
    return shape
 
964
  
 
965
  th, id, sw = PSPMTable[diam]
1020
966
 
 
967
  m = FastenerBase.MToFloat(diam)
 
968
  f = pspMakeFace(m, width, len, id, th)
 
969
  p = f.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)
 
970
  w = float(width)
 
971
  l = float(len)
 
972
  htool = screwMaker.makeHextool(w, l, w * 2)
 
973
  htool.translate(Base.Vector(0.0,0.0,- 0.1))
 
974
  shape = p.cut(htool)
 
975
  FastenerBase.FSCache[key] = shape
 
976
  return shape
1021
977
 
1022
978
# h = clMakePressNut('M5','1')
1023
979
 
1024
980
class FSPcbSpacerObject(FSBaseObject):
1025
 
    def __init__(self, obj, attachTo):
1026
 
        '''"Add PCB Spacer type fastener" '''
1027
 
        FSBaseObject.__init__(self, obj, attachTo)
1028
 
        self.itemText = "PcbSpacer"
1029
 
        # self.Proxy = obj.Name
1030
 
 
1031
 
        obj.addProperty("App::PropertyEnumeration", "diameter", "Parameters",
1032
 
                        "Standoff thread diameter").diameter = PSDiameters
1033
 
        widths = psGetAllWidths(PSPMTable, PSDiameters[1])
1034
 
        obj.addProperty("App::PropertyEnumeration", "width", "Parameters", "Standoff body width").width = widths
1035
 
        obj.addProperty("App::PropertyEnumeration", "length", "Parameters", "Standoff length").length = psGetAllLengths(
1036
 
            PSPMTable, PSPLengths, PSDiameters[1], widths[0])
1037
 
        obj.invert = FastenerBase.FSLastInvert
1038
 
        obj.Proxy = self
1039
 
 
1040
 
    def execute(self, fp):
1041
 
        '''"Print a short message when doing a recomputation, this method is mandatory" '''
1042
 
        try:
1043
 
            baseobj = fp.baseObject[0]
1044
 
            shape = baseobj.Shape.getElement(fp.baseObject[1][0])
1045
 
        except:
1046
 
            baseobj = None
1047
 
            shape = None
1048
 
        self.updateProps(fp)
1049
 
        if not hasattr(self, 'diameter') or self.diameter != fp.diameter or self.width != fp.width or self.length != fp.length:
1050
 
            diameterchange = False
1051
 
            if not (hasattr(self, 'diameter')) or self.diameter != fp.diameter:
1052
 
                diameterchange = True
1053
 
            if fp.diameter == 'Auto':
1054
 
                d = FastenerBase.FSAutoDiameterM(shape, PSMTable, 1)
1055
 
                diameterchange = True
1056
 
            else:
1057
 
                d = fp.diameter
1058
 
 
1059
 
            if d != fp.diameter:
1060
 
                diameterchange = True
1061
 
                fp.diameter = d
1062
 
 
1063
 
            widthchange = False
1064
 
            if diameterchange or not (hasattr(self, 'width')) or self.width != fp.width:
1065
 
                widthchange = True
1066
 
                if diameterchange:
1067
 
                    allwidth = psGetAllWidths(PSPMTable, d)
1068
 
                    fp.width = allwidth
1069
 
                    if len(allwidth) > 1:
1070
 
                        fp.width = allwidth[1]
1071
 
                    else:
1072
 
                        fp.width = allwidth[0]
1073
 
 
1074
 
            l = psFindClosest(PSPMTable, PSPLengths, d, fp.width, fp.length)
1075
 
 
1076
 
            if l != fp.length or diameterchange or widthchange:
1077
 
                if diameterchange or widthchange:
1078
 
                    fp.length = psGetAllLengths(PSPMTable, PSPLengths, fp.diameter, fp.width)
1079
 
                fp.length = l
1080
 
 
1081
 
            s = pspMakeSpacer(d, l, fp.width)
1082
 
 
1083
 
            self.diameter = fp.diameter
1084
 
            self.length = fp.length
1085
 
            self.width = fp.width
1086
 
            FastenerBase.FSLastInvert = fp.invert
1087
 
            fp.Label = fp.diameter + 'x' + fp.width + 'x' + fp.length + '-Spacer'
1088
 
            fp.Shape = s
1089
 
        else:
1090
 
            FreeCAD.Console.PrintLog("Using cached object\n")
1091
 
        if shape is not None:
1092
 
            # feature = FreeCAD.ActiveDocument.getObject(self.Proxy)
1093
 
            # fp.Placement = FreeCAD.Placement() # reset placement
1094
 
            FastenerBase.FSMoveToObject(fp, shape, fp.invert, fp.offset.Value)
1095
 
 
1096
 
 
1097
 
FastenerBase.FSClassIcons[FSPcbSpacerObject] = 'PCBSpacer.svg'
1098
 
 
 
981
  def __init__(self, obj, attachTo):
 
982
    '''"Add PCB Spacer type fastener" '''
 
983
    FSBaseObject.__init__(self, obj, attachTo)
 
984
    self.itemText = "PcbSpacer"
 
985
    #self.Proxy = obj.Name
 
986
    
 
987
    obj.addProperty("App::PropertyEnumeration","diameter","Parameters","Standoff thread diameter").diameter = PSDiameters
 
988
    widths = psGetAllWidths(PSPMTable ,PSDiameters[1])
 
989
    obj.addProperty("App::PropertyEnumeration", "width", "Parameters", "Standoff body width").width = widths
 
990
    obj.addProperty("App::PropertyEnumeration","length","Parameters","Standoff length").length = psGetAllLengths(PSPMTable, PSPLengths ,PSDiameters[1], widths[0])
 
991
    obj.invert = FastenerBase.FSLastInvert
 
992
    obj.Proxy = self
 
993
 
 
994
  def execute(self, fp):
 
995
    '''"Print a short message when doing a recomputation, this method is mandatory" '''
 
996
    try:
 
997
      baseobj = fp.baseObject[0]
 
998
      shape = baseobj.Shape.getElement(fp.baseObject[1][0])
 
999
    except:
 
1000
      baseobj = None
 
1001
      shape = None
 
1002
    self.updateProps(fp)
 
1003
    if not (hasattr(self, 'diameter')) or self.diameter != fp.diameter or self.width != fp.width or self.length != fp.length:
 
1004
      diameterchange = False      
 
1005
      if not (hasattr(self, 'diameter')) or self.diameter != fp.diameter:
 
1006
        diameterchange = True      
 
1007
      if fp.diameter == 'Auto':
 
1008
        d = FastenerBase.FSAutoDiameterM(shape, PSMTable, 1)
 
1009
        diameterchange = True      
 
1010
      else:
 
1011
        d = fp.diameter
 
1012
 
 
1013
      if d != fp.diameter:
 
1014
        diameterchange = True      
 
1015
        fp.diameter = d
 
1016
 
 
1017
      widthchange = False
 
1018
      if diameterchange or not(hasattr(self, 'width')) or self.width != fp.width:
 
1019
        widthchange = True
 
1020
        if diameterchange:
 
1021
          allwidth = psGetAllWidths(PSPMTable, d)
 
1022
          fp.width = allwidth
 
1023
          if len(allwidth) > 1:
 
1024
            fp.width = allwidth[1]
 
1025
          else:
 
1026
            fp.width = allwidth[0]
 
1027
 
 
1028
      l = psFindClosest(PSPMTable, PSPLengths ,d, fp.width, fp.length)
 
1029
 
 
1030
      if l != fp.length or diameterchange or widthchange:
 
1031
        if diameterchange or widthchange:
 
1032
          fp.length = psGetAllLengths(PSPMTable, PSPLengths, fp.diameter, fp.width)
 
1033
        fp.length = l
 
1034
 
 
1035
      s = pspMakeSpacer(d, l, fp.width)
 
1036
        
 
1037
      self.diameter = fp.diameter
 
1038
      self.length = fp.length
 
1039
      self.width = fp.width
 
1040
      FastenerBase.FSLastInvert = fp.invert
 
1041
      fp.Label = fp.diameter + 'x' + fp.width + 'x' + fp.length + '-Spacer'
 
1042
      fp.Shape = s
 
1043
    else:
 
1044
      FreeCAD.Console.PrintLog("Using cached object\n")
 
1045
    if shape is not None:
 
1046
      #feature = FreeCAD.ActiveDocument.getObject(self.Proxy)
 
1047
      #fp.Placement = FreeCAD.Placement() # reset placement
 
1048
      FastenerBase.FSMoveToObject(fp, shape, fp.invert, fp.offset.Value)
 
1049
 
 
1050
 
 
1051
FastenerBase.FSClassIcons[FSPcbSpacerObject] = 'PCBSpacer.svg'    
1099
1052
 
1100
1053
class FSPcbSpacerCommand:
1101
 
    """Add PCB Spacer command"""
1102
 
 
1103
 
    def GetResources(self):
1104
 
        icon = os.path.join(iconPath, 'PCBSpacer.svg')
1105
 
        return {
1106
 
            'Pixmap': icon,  # the name of a svg file available in the resources
1107
 
            'MenuText': "Add PCB Spacer",
1108
 
            'ToolTip': "Add PCB Metric Spacer"
1109
 
        }
1110
 
 
1111
 
    def Activated(self):
1112
 
        FastenerBase.FSGenerateObjects(FSPcbSpacerObject, "PcbSpacer")
1113
 
        return
1114
 
 
1115
 
    def IsActive(self):
1116
 
        return Gui.ActiveDocument is not None
1117
 
 
 
1054
  """Add PCB Spacer command"""
 
1055
 
 
1056
  def GetResources(self):
 
1057
    icon = os.path.join( iconPath , 'PCBSpacer.svg')
 
1058
    return {'Pixmap'  : icon , # the name of a svg file available in the resources
 
1059
            'MenuText': "Add PCB Spacer" ,
 
1060
            'ToolTip' : "Add PCB Metric Spacer"}
 
1061
 
 
1062
  def Activated(self):
 
1063
    FastenerBase.FSGenerateObjects(FSPcbSpacerObject, "PcbSpacer")
 
1064
    return
 
1065
   
 
1066
  def IsActive(self):
 
1067
    return Gui.ActiveDocument is not None
1118
1068
 
1119
1069
Gui.addCommand("FSPcbSpacer", FSPcbSpacerCommand())
1120
1070
FastenerBase.FSCommands.append("FSPcbSpacer", "screws", "PEM Inserts")
1122
1072
###################################################################################
1123
1073
# Heat Staked Threaded Insert types: IUT
1124
1074
 
1125
 
IUTDiamCodes = ['Auto', 'M2', 'M2.5', 'M3', 'M3.5', 'M4', 'M5', 'M6']
 
1075
IUTDiamCodes = ['Auto','M2', 'M2.5', 'M3', 'M3.5', 'M4', 'M5', 'M6']
1126
1076
 
1127
1077
IUTPEMTable = {
1128
 
    #            D,    A,    E,    C,   S1,   S2
1129
 
    'M2': (3.23, 4.00, 3.73, 3.07, 0.79, 0.79),
1130
 
    'M2.5': (4.00, 5.74, 4.55, 3.86, 0.79, 0.79),
1131
 
    'M3': (4.00, 5.74, 4.55, 3.86, 0.79, 0.79),
1132
 
    'M3.5': (4.80, 7.14, 5.33, 4.65, 0.79, 0.79),
1133
 
    'M4': (5.67, 8.15, 6.17, 5.51, 0.79, 0.79),
1134
 
    'M5': (6.43, 9.52, 6.93, 6.27, 1.17, 1.17),
1135
 
    'M6': (8.00, 12.7, 8.69, 7.87, 1.17, 1.58),
1136
 
}
1137
 
 
 
1078
#            D,    A,    E,    C,   S1,   S2
 
1079
  'M2':  (3.23, 4.00, 3.73, 3.07, 0.79, 0.79),
 
1080
  'M2.5':(4.00, 5.74, 4.55, 3.86, 0.79, 0.79),
 
1081
  'M3':  (4.00, 5.74, 4.55, 3.86, 0.79, 0.79),
 
1082
  'M3.5':(4.80, 7.14, 5.33, 4.65, 0.79, 0.79),
 
1083
  'M4':  (5.67, 8.15, 6.17, 5.51, 0.79, 0.79),
 
1084
  'M5':  (6.43, 9.52, 6.93, 6.27, 1.17, 1.17),
 
1085
  'M6':  (8.00, 12.7, 8.69, 7.87, 1.17, 1.58),
 
1086
  }
1138
1087
 
1139
1088
def iutMakeWire(D, a, E, C, s1, s2):
1140
 
    d = D / 2
1141
 
    e = E / 2
1142
 
    c = C / 2
1143
 
    ch = C / 6
1144
 
    k1 = (a - ch - s1 - s2) / 2
1145
 
    k2 = k1 + s1 + k1
1146
 
    sd = (e - d) / 2
1147
 
 
1148
 
    fm = FastenerBase.FSFaceMaker()
1149
 
    fm.AddPoint(d, 0)
1150
 
    fm.AddPoint(e, 0)
1151
 
    fm.AddPoint(e, -k1)
1152
 
    fm.AddPoint(e - sd, -k1)
1153
 
    fm.AddPoint(e - sd, -k1 - s1)
1154
 
    fm.AddPoint(e, -k1 - s1)
1155
 
    fm.AddPoint(e, -k2)
1156
 
    fm.AddPoint(e - sd, -k2)
1157
 
    fm.AddPoint(e - sd, -k2 - s2)
1158
 
    fm.AddPoint(c, -k2 - s2)
1159
 
    fm.AddPoint(c, -a)
1160
 
    fm.AddPoint(d, -a)
1161
 
    return fm.GetFace()
1162
 
 
 
1089
  d = D / 2
 
1090
  e = E / 2
 
1091
  c = C / 2
 
1092
  ch = C / 6
 
1093
  k1 = (a - ch - s1 - s2)/2
 
1094
  k2 = k1 + s1 + k1
 
1095
  sd = (e - d)/2
 
1096
  
 
1097
  fm = FastenerBase.FSFaceMaker()
 
1098
  fm.AddPoint(d, 0)
 
1099
  fm.AddPoint(e, 0)
 
1100
  fm.AddPoint(e, -k1)
 
1101
  fm.AddPoint(e - sd, -k1)
 
1102
  fm.AddPoint(e - sd, -k1 - s1)
 
1103
  fm.AddPoint(e, -k1 - s1)
 
1104
  fm.AddPoint(e, -k2)
 
1105
  fm.AddPoint(e - sd, -k2)
 
1106
  fm.AddPoint(e - sd, -k2 - s2)
 
1107
  fm.AddPoint(c, -k2 - s2)
 
1108
  fm.AddPoint(c, -a)
 
1109
  fm.AddPoint(d, -a)
 
1110
  return fm.GetFace()
1163
1111
 
1164
1112
def iutMakeHeatSet(diam):
1165
 
    if not (diam in IUTPEMTable):
1166
 
        return None
1167
 
 
1168
 
    (key, shape) = FastenerBase.FSGetKey('HeatSet', diam)
1169
 
    if shape is not None:
1170
 
        return shape
1171
 
 
1172
 
    D, A, E, C, s1, s2 = IUTPEMTable[diam]
1173
 
    D = FastenerBase.MToFloat(diam)
1174
 
    f = iutMakeWire(D, A, E, C, s1, s2)
1175
 
    p = f.revolve(Base.Vector(0.0, 0.0, 0.0), Base.Vector(0.0, 0.0, 1.0), 360)
1176
 
    FastenerBase.FSCache[key] = p
1177
 
    return p
1178
 
 
 
1113
  if not(diam in IUTPEMTable):
 
1114
    return None
 
1115
  
 
1116
  (key, shape) = FastenerBase.FSGetKey('HeatSet', diam)
 
1117
  if shape is not None:
 
1118
    return shape
 
1119
 
 
1120
  D, A, E, C, s1, s2 = IUTPEMTable[diam]
 
1121
  D = FastenerBase.MToFloat(diam)
 
1122
  f = iutMakeWire(D, A, E, C, s1, s2)
 
1123
  p = f.revolve(Base.Vector(0.0,0.0,0.0),Base.Vector(0.0,0.0,1.0),360)
 
1124
  FastenerBase.FSCache[key] = p
 
1125
  return p
1179
1126
 
1180
1127
def iutFindClosest(diam):
1181
 
    ''' Find closest standard screw to given parameters '''
1182
 
    i = IUTDiamCodes.index(diam)
1183
 
    lens = IUTPEMTable[diam][0]
1184
 
    min = 999
1185
 
    max = len(IUTDiamCodes)
1186
 
    j = 0
1187
 
    for c in lens:
1188
 
        if c != 0 and min == 999:
1189
 
            min = j
1190
 
        if c == 0 and min != 999:
1191
 
            max = j - 1
1192
 
            break
1193
 
        j = j + 1
1194
 
    if i < min:
1195
 
        return IUTDiamCodes[min]
1196
 
    return IUTDiamCodes[max]
1197
 
 
 
1128
  ''' Find closest standard screw to given parameters '''
 
1129
  i = IUTDiamCodes.index(diam)
 
1130
  lens = IUTPEMTable[diam][0]
 
1131
  min = 999
 
1132
  max = len(IUTDiamCodes)
 
1133
  j = 0
 
1134
  for c in lens:
 
1135
    if c != 0 and min == 999:
 
1136
      min = j
 
1137
    if c == 0 and min != 999:
 
1138
      max = j - 1
 
1139
      break
 
1140
    j = j + 1
 
1141
  if i < min:
 
1142
    return IUTDiamCodes[min]
 
1143
  return IUTDiamCodes[max]
1198
1144
 
1199
1145
class FSHeatSetObject(FSBaseObject):
1200
 
    def __init__(self, obj, attachTo):
1201
 
        '''"Add IUT[A/B/C] Heat Set Insert fastener" '''
1202
 
        FSBaseObject.__init__(self, obj, attachTo)
1203
 
        self.itemText = "HeatSet"
1204
 
 
1205
 
        obj.addProperty("App::PropertyEnumeration", "diameter", "Parameters",
1206
 
                        "Heat set thread diameter").diameter = IUTDiamCodes
1207
 
        obj.invert = FastenerBase.FSLastInvert
1208
 
        obj.Proxy = self
1209
 
 
1210
 
    def execute(self, fp):
1211
 
        '''"Print a short message when doing a recomputation, this method is mandatory" '''
1212
 
 
1213
 
        try:
1214
 
            baseobj = fp.baseObject[0]
1215
 
            shape = baseobj.Shape.getElement(fp.baseObject[1][0])
1216
 
        except:
1217
 
            baseobj = None
1218
 
            shape = None
1219
 
        self.updateProps(fp)
1220
 
        if not (hasattr(self, 'diameter')) or self.diameter != fp.diameter:
1221
 
            if fp.diameter == 'Auto':
1222
 
                d = FastenerBase.FSAutoDiameterM(shape, IUTPEMTable, 0)
1223
 
            else:
1224
 
                d = fp.diameter
1225
 
 
1226
 
            s = iutMakeHeatSet(d)
1227
 
            self.diameter = fp.diameter
1228
 
            FastenerBase.FSLastInvert = fp.invert
1229
 
            fp.Label = fp.diameter + '-HeatSet'
1230
 
            fp.Shape = s
1231
 
        else:
1232
 
            FreeCAD.Console.PrintLog("Using cached object\n")
1233
 
        if shape is not None:
1234
 
            FastenerBase.FSMoveToObject(fp, shape, fp.invert, fp.offset.Value)
1235
 
 
1236
 
 
1237
 
FastenerBase.FSClassIcons[FSHeatSetObject] = 'IUTHeatInsert.svg'
1238
 
 
 
1146
  def __init__(self, obj, attachTo):
 
1147
    '''"Add IUT[A/B/C] Heat Set Insert fastener" '''
 
1148
    FSBaseObject.__init__(self, obj, attachTo)
 
1149
    self.itemText = "HeatSet"
 
1150
    
 
1151
    obj.addProperty("App::PropertyEnumeration","diameter","Parameters","Heat set thread diameter").diameter = IUTDiamCodes
 
1152
    obj.invert = FastenerBase.FSLastInvert
 
1153
    obj.Proxy = self
 
1154
 
 
1155
  def execute(self, fp):
 
1156
    '''"Print a short message when doing a recomputation, this method is mandatory" '''
 
1157
    
 
1158
    try:
 
1159
      baseobj = fp.baseObject[0]
 
1160
      shape = baseobj.Shape.getElement(fp.baseObject[1][0])
 
1161
    except:
 
1162
      baseobj = None
 
1163
      shape = None
 
1164
    self.updateProps(fp)
 
1165
    if not (hasattr(self, 'diameter')) or self.diameter != fp.diameter:
 
1166
      if fp.diameter == 'Auto':
 
1167
        d = FastenerBase.FSAutoDiameterM(shape, IUTPEMTable, 0)
 
1168
      else:
 
1169
        d = fp.diameter
 
1170
        
 
1171
      s = iutMakeHeatSet(d)
 
1172
      self.diameter = fp.diameter
 
1173
      FastenerBase.FSLastInvert = fp.invert
 
1174
      fp.Label = fp.diameter + '-HeatSet'
 
1175
      fp.Shape = s
 
1176
    else:
 
1177
      FreeCAD.Console.PrintLog("Using cached object\n")
 
1178
    if shape is not None:
 
1179
      FastenerBase.FSMoveToObject(fp, shape, fp.invert, fp.offset.Value)
 
1180
 
 
1181
 
 
1182
FastenerBase.FSClassIcons[FSHeatSetObject] = 'IUTHeatInsert.svg'    
1239
1183
 
1240
1184
class FSHeatSetCommand:
1241
 
    """Add Heat Set Insert command"""
1242
 
 
1243
 
    def GetResources(self):
1244
 
        icon = os.path.join(iconPath, 'IUTHeatInsert.svg')
1245
 
        return {
1246
 
            'Pixmap': icon,  # the name of a svg file available in the resources
1247
 
            'MenuText': "Add Heatset Insert",
1248
 
            'ToolTip': "Add IUT[A/B/C] Heat Staked Metric Insert"
1249
 
        }
1250
 
 
1251
 
    def Activated(self):
1252
 
        FastenerBase.FSGenerateObjects(FSHeatSetObject, "HeatSet")
1253
 
        return
1254
 
 
1255
 
    def IsActive(self):
1256
 
        return Gui.ActiveDocument is not None
1257
 
 
 
1185
  """Add Heat Set Insert command"""
 
1186
 
 
1187
  def GetResources(self):
 
1188
    icon = os.path.join( iconPath , 'IUTHeatInsert.svg')
 
1189
    return {'Pixmap'  : icon , # the name of a svg file available in the resources
 
1190
            'MenuText': "Add Heatset Insert" ,
 
1191
            'ToolTip' : "Add IUT[A/B/C] Heat Staked Metric Insert"}
 
1192
 
 
1193
  def Activated(self):
 
1194
    FastenerBase.FSGenerateObjects(FSHeatSetObject, "HeatSet")
 
1195
    return
 
1196
   
 
1197
  def IsActive(self):
 
1198
    return Gui.ActiveDocument is not None
1258
1199
 
1259
1200
Gui.addCommand("FSHeatSet", FSHeatSetCommand())
1260
1201
FastenerBase.FSCommands.append("FSHeatSet", "screws", "PEM Inserts")