FreeCAD-macros
1197 строк · 46.4 Кб
1#
2#
3# Half Hull
4# (c) piffpoof 2015
5#
6################################
7
8import FreeCAD
9from FreeCAD import Base, Draft
10import Part, PartGui, sys, math, collections
11from collections import OrderedDict
12from os.path import expanduser # default input directory
13from PySide import QtGui, QtCore
14
15# UI Class definitions
16global ConfigParams
17global GetConfigParams
18global OrderedDict
19
20class ConfigParams:
21"""carrier for the user selection parameters"""
22def __init__(self):
23self.result = None
24self.cb1a = None
25self.cb1b = None
26self.cb1c = None
27self.cb2a = None
28self.cb2b = None
29self.cb2c = None
30self.cb3a = None
31self.cb3b = None
32self.cb3c = None
33self.cb4a = None
34self.rb4b = None
35self.rb5b = None
36self.skipAtBow = None
37self.skipAtStern = None
38self.deckWidth = None
39self.deckThrow = None
40self.coachhouseRise = None
41self.coachhouseIncline = None
42self.documentFileName = None
43
44class GetConfigParams(QtGui.QDialog):
45""""""
46def __init__(self):
47super(GetConfigParams, self).__init__()
48self.initUI()
49def initUI(self):
50self.configParams = ConfigParams()
51# set default return value
52self.configParams.result = userCancelled
53# set default values
54skipAtBowDefault = str(2)
55skipAtSternDefault = str(2)
56deckWidthDefault = str(50)
57deckThrowDefault = str(2)
58coachhouseRiseDefault = str(50)
59coachhouseInclineDefault = str(8)
60# field descriptors
61self.promptLbl = QtGui.QLabel("Please Choose Options:", self)
62self.promptLbl.move(20, 20)
63# checkboxes - define first so signals can be set up
64self.cb1a = QtGui.QCheckBox("Starboard half-hull", self)
65self.cb1b = QtGui.QCheckBox("Mounting plaque", self)
66self.cb1c = QtGui.QCheckBox("Allow space for keel", self)
67self.cb2a = QtGui.QCheckBox("Port half-hull", self)
68self.cb2b = QtGui.QCheckBox("Mounting plaque", self)
69self.cb2c = QtGui.QCheckBox("Allow space for keel", self)
70self.cb3a = QtGui.QCheckBox("Complete hull", self)
71self.cb3b = QtGui.QCheckBox("Bottle for complete hull", self)
72self.cb3c = QtGui.QCheckBox("Allow space for keel", self)
73self.rb4b = QtGui.QRadioButton("Bulkheads for flush deck",self)
74self.rb5b = QtGui.QRadioButton("Bulkheads for coachhouse",self)
75#
76self.cb1a.clicked.connect(self.onCb1a)
77self.cb1a.toggle() # set default value
78self.cb1c.setEnabled(False)
79#self.cb1a.stateChanged.connect(self.onCb1a)
80self.cb1a.move(20,50)
81#
82self.cb1b.clicked.connect(self.onCb1b)
83self.cb1b.move(250,50)
84#
85self.cb1c.clicked.connect(self.onCb1c)
86self.cb1c.move(450,50)
87#
88self.cb2a.clicked.connect(self.onCb2a)
89self.cb2b.setEnabled(False)
90self.cb2c.setEnabled(False)
91self.cb2a.move(20,80)
92#
93self.cb2b.clicked.connect(self.onCb2b)
94self.cb2b.move(250,80)
95#
96self.cb2c.clicked.connect(self.onCb2c)
97self.cb2c.move(450,80)
98#
99self.cb3a.clicked.connect(self.onCb3a)
100self.cb3b.setEnabled(False)
101self.cb3c.setEnabled(False)
102self.cb3a.move(20,110)
103#
104self.cb3b.clicked.connect(self.onCb3b)
105self.cb3b.move(250,110)
106#
107self.cb3c.clicked.connect(self.onCb3c)
108self.cb3c.move(450,110)
109#
110self.cb4a = QtGui.QCheckBox("Bulkheads for complete hull", self)
111self.cb4a.clicked.connect(self.onCb4a)
112self.rb4b.setEnabled(False)
113self.rb5b.setEnabled(False)
114#self.hideCoachhouseFields(True) # grey out coachhouse fields
115self.cb4a.move(20,140)
116# radio buttons
117self.rb4b.move(250,140)
118self.rb4b.clicked.connect(self.onRb4b)
119#
120self.rb5b.move(250,170)
121self.rb5b.clicked.connect(self.onRb5b)
122#
123self.skipAtBowLabel = QtGui.QLabel("Cross-sections to skip at bow:", self)
124self.skipAtBowLabel.move(270, 200)
125self.skipAtBow = 0
126#
127self.skipAtSternLabel = QtGui.QLabel("Cross-sections to skip at stern:", self)
128self.skipAtSternLabel.move(270, 230)
129self.skipAtStern = 0
130#
131self.deckWidthLabel = QtGui.QLabel("Deck Width:", self)
132self.deckWidthLabel.move(270, 260)
133self.deckWidth = QtGui.QLineEdit(self)
134self.deckWidth.setInputMask("999")
135self.deckWidth.setText(deckWidthDefault)
136self.deckWidth.setFixedWidth(35)
137self.deckWidth.move(493, 260)
138#
139self.deckThrowLabel = QtGui.QLabel("Deck throw:", self)
140self.deckThrowLabel.move(270, 290)
141self.deckThrow = QtGui.QLineEdit(self)
142self.deckThrow.setInputMask("999")
143self.deckThrow.setText(deckThrowDefault)
144self.deckThrow.setFixedWidth(35)
145self.deckThrow.move(493, 290)
146#
147self.coachhouseRiseLabel = QtGui.QLabel("Coachhouse Rise:", self)
148self.coachhouseRiseLabel.move(270, 320)
149self.coachhouseRise = QtGui.QLineEdit(self)
150self.coachhouseRise.setInputMask("999")
151self.coachhouseRise.setText(coachhouseRiseDefault)
152self.coachhouseRise.setFixedWidth(35)
153self.coachhouseRise.move(493, 320)
154#
155self.coachhouseInclineLabel = QtGui.QLabel("Coachhouse Incline:", self)
156self.coachhouseInclineLabel.move(270, 350)
157self.coachhouseIncline = QtGui.QLineEdit(self)
158self.coachhouseIncline.setInputMask("999")
159self.coachhouseIncline.setText(coachhouseInclineDefault)
160self.coachhouseIncline.setFixedWidth(35)
161self.coachhouseIncline.move(493, 350)
162# set up lists for pop-ups
163self.popupItemsB = OrderedDict([("2",""),("3",""),("4",""),("5",""),("6",""),("7",""),("8",""),("9",""),("10","")])
164self.popupItemsS = OrderedDict([("1",""),("2",""),("3",""),("4",""),("5",""),("6",""),("7",""),("8",""),("9",""),("10","")])
165# set up pop-up menu of bulkheads to skip bulkheads at bow
166self.skipAtBowPop = QtGui.QComboBox(self)
167self.skipAtBowPop.addItems(self.popupItemsB.keys())
168self.skipAtBowPop.setCurrentIndex(self.popupItemsB.keys().index(skipAtBowDefault))
169self.skipAtBow = skipAtBowDefault
170self.skipAtBowPop.move(490, 200)
171self.skipAtBowPop.activated[str].connect(self.onSkipBowActivated)
172# set up pop-up menu of bulkheads to skip bulkheads at stern
173self.skipAtSternPop = QtGui.QComboBox(self)
174self.skipAtSternPop.addItems(self.popupItemsS.keys())
175self.skipAtSternPop.setCurrentIndex(self.popupItemsS.keys().index(skipAtSternDefault))
176self.skipAtStern = skipAtSternDefault
177self.skipAtSternPop.move(490, 230)
178self.skipAtSternPop.activated[str].connect(self.onSkipSternActivated)
179# cancel button
180cancelButton = QtGui.QPushButton('Cancel', self)
181cancelButton.clicked.connect(self.onCancel)
182cancelButton.move(260, 390)
183# last used button
184lastFileButton = QtGui.QPushButton('Re-use last file', self)
185lastFileButton.clicked.connect(self.onLastFile)
186lastFileButton.move(345, 390)
187# OK button
188sfButton = QtGui.QPushButton('Select File', self)
189sfButton.clicked.connect(self.onSf)
190sfButton.move(480, 390)
191# define window xLoc,yLoc,xDim,yDim
192self.setGeometry( 250, 250, 630, 445)
193self.setWindowTitle("Macro Configuration")
194self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
195self.disableCoachhouseFields(True) # grey out coachhouse fields
196self.show()
197#
198def onCb1a(self):
199if self.cb1a.isChecked():
200self.cb1b.setEnabled(True)
201else:
202self.cb1b.setEnabled(False)
203self.cb1b.setChecked(False)
204self.cb1c.setEnabled(False)
205self.cb1c.setChecked(False)
206def onCb1b(self):
207if self.cb1b.isChecked():
208self.cb1c.setEnabled(True)
209else:
210self.cb1c.setEnabled(False)
211self.cb1c.setChecked(False)
212def onCb1c(self):
213pass
214def onCb2a(self):
215if self.cb2a.isChecked():
216self.cb2b.setEnabled(True)
217else:
218self.cb2b.setEnabled(False)
219self.cb2b.setChecked(False)
220self.cb2c.setEnabled(False)
221self.cb2c.setChecked(False)
222def onCb2b(self):
223if self.cb2b.isChecked():
224self.cb2c.setEnabled(True)
225else:
226self.cb2c.setEnabled(False)
227self.cb2c.setChecked(False)
228def onCb2c(self):
229pass
230def onCb3a(self):
231if self.cb3a.isChecked():
232self.cb3b.setEnabled(True)
233else:
234self.cb3b.setEnabled(False)
235self.cb3b.setChecked(False)
236self.cb3c.setEnabled(False)
237self.cb3c.setChecked(False)
238def onCb3b(self):
239if self.cb3b.isChecked():
240self.cb3c.setEnabled(True)
241else:
242self.cb3c.setEnabled(False)
243self.cb3c.setChecked(False)
244def onCb3c(self):
245pass
246def onCb4a(self):
247if self.cb4a.isChecked():
248self.rb4b.setEnabled(True)
249self.rb4b.setChecked(True)
250self.rb5b.setEnabled(True)
251self.rb5b.setChecked(False)
252else:
253self.rb4b.setChecked(False)
254self.rb4b.setEnabled(False)
255self.rb5b.setChecked(False)
256self.rb5b.setEnabled(False)
257self.disableCoachhouseFields(True)
258def onRb4b(self):
259if self.rb4b.isChecked():
260self.disableCoachhouseFields(True)
261else:
262self.disableCoachhouseFields(False)
263def onRb5b(self):
264if self.rb5b.isChecked():
265self.disableCoachhouseFields(False)
266else:
267self.disableCoachhouseFields(True)
268def onSkipBowActivated(self, text):
269self.skipAtBow = text
270def onSkipSternActivated(self, text):
271self.skipAtStern = text
272def disableCoachhouseFields(self, aFlag):
273# enable or disable coachhouse parameter fields
274if aFlag:
275self.skipAtBowLabel.setEnabled(False)
276self.skipAtBowPop.setEnabled(False)
277self.skipAtSternLabel.setEnabled(False)
278self.skipAtSternPop.setEnabled(False)
279self.deckWidthLabel.setEnabled(False)
280self.deckWidth.setEnabled(False)
281self.deckThrowLabel.setEnabled(False)
282self.deckThrow.setEnabled(False)
283self.coachhouseRiseLabel.setEnabled(False)
284self.coachhouseRise.setEnabled(False)
285self.coachhouseInclineLabel.setEnabled(False)
286self.coachhouseIncline.setEnabled(False)
287else:
288self.skipAtBowLabel.setEnabled(True)
289self.skipAtBowPop.setEnabled(True)
290self.skipAtSternLabel.setEnabled(True)
291self.skipAtSternPop.setEnabled(True)
292self.deckWidthLabel.setEnabled(True)
293self.deckWidth.setEnabled(True)
294self.deckThrowLabel.setEnabled(True)
295self.deckThrow.setEnabled(True)
296self.coachhouseRiseLabel.setEnabled(True)
297self.coachhouseRise.setEnabled(True)
298self.coachhouseInclineLabel.setEnabled(True)
299self.coachhouseIncline.setEnabled(True)
300def onCancel(self):
301self.configParams.result = userCancelled
302self.close()
303def transferConfigParams(self):
304self.configParams.cb1a = self.cb1a.isChecked()
305self.configParams.cb1b = self.cb1b.isChecked()
306self.configParams.cb1c = self.cb1c.isChecked()
307self.configParams.cb2a = self.cb2a.isChecked()
308self.configParams.cb2b = self.cb2b.isChecked()
309self.configParams.cb2c = self.cb2c.isChecked()
310self.configParams.cb3a = self.cb3a.isChecked()
311self.configParams.cb3b = self.cb3b.isChecked()
312self.configParams.cb3c = self.cb3c.isChecked()
313self.configParams.cb4a = self.cb4a.isChecked()
314self.configParams.rb5b = self.rb5b.isChecked()
315self.configParams.skipAtBow = self.skipAtBow
316self.configParams.skipAtStern = self.skipAtStern
317self.configParams.deckWidth = self.deckWidth
318self.configParams.deckThrow = self.deckThrow
319self.configParams.coachhouseRise = self.coachhouseRise
320self.configParams.coachhouseIncline = self.coachhouseIncline
321def onLastFile(self):
322self.configParams.result = userLastFile
323self.transferConfigParams()
324self.close()
325def onSf(self):
326self.configParams.result = userOK
327self.transferConfigParams()
328self.close()
329
330# Class definitions
331
332class HullCrossSection:
333"Holder of information pertaining to a cross section profile"
334#persistentInstance = ""
335#import copy
336def __init__(self,aSketch):
337self.sketch = aSketch
338self.geometryCount = aSketch.GeometryCount
339self.geometryS = None # geometry for starboard side
340self.geometryP = None # geometry for port side
341self.geometryC = None # geometry for complete hull (i.e. both halves as one)
342self.label = aSketch.Label
343# next 2 lines due to mysterious label morphing routine of FreeCAD
344self.altLabel = self.label.replace(" ", "_")
345self.altLabel = self.altLabel.replace("-", "_")
346#
347self.xPos = 0.0 # normalise sketch to axis
348self.yPos = aSketch.Placement.Base.y
349self.zPos = aSketch.Placement.Base.z
350self.xMin = infinity # will hold min X value in Sketch
351self.yMin = infinity # will hold min Y value in Sketch
352self.xMax = infinityNegative # will hold max X value in Sketch
353self.yMax = infinityNegative # will hold max Y value in Sketch
354self.endPoint = None # will be the 'top' point on the polyline
355self.key = int(self.yPos)
356self.rotation = aSketch.Placement.Rotation
357self.rotAngle = aSketch.Placement.Rotation.Angle
358self.rotAxis = aSketch.Placement.Rotation.Axis
359self.rotQ = aSketch.Placement.Rotation.Q
360# following 4 statements seem necessary to pass the Rotation quad-value
361self.rotQ1 = aSketch.Placement.Rotation.Q[0]
362self.rotQ2 = aSketch.Placement.Rotation.Q[1]
363self.rotQ3 = aSketch.Placement.Rotation.Q[2]
364self.rotQ4 = aSketch.Placement.Rotation.Q[3]
365# set flags for either stemline or transom or suspected transom cross-section
366if eqRotation(self.rotation,yzPlane):
367# if we have the stemline then wait to give it the foremost placement
368FreeCAD.Console.PrintMessage("Stemline identified '" + self.label + "'\n")
369self.stemlineFlag = True
370else:
371self.stemlineFlag = False
372if eqRotation(self.rotation,xyPlane):
373# if we have the transom then wait to give it the aftmost placement
374FreeCAD.Console.PrintMessage("Transom identified '" + self.label + "'\n")
375self.transomFlag = True
376else:
377self.transomFlag = False
378if eqRotation(self.rotation,xzPlane):
379# the most numerous sketches will be the cross-sections, so don't flag it
380self.possibleTransomCS = False
381else:
382# it's not lying in any of the 3 planes so it's either an error
383# or it could be an inclined cross-section for the transom
384# (although there should only be one or none of these)
385# flag it as such and sort it out later once all the other
386# cross-sections are placed
387if not (self.stemlineFlag or self.transomFlag):
388FreeCAD.Console.PrintMessage("Possible Transom cross-section identified '" + self.label + "'\n")
389self.possibleTransomCS = True
390self.defineGeometries() # make S & P & C geometries from the geometry of the supplied Sketch
391
392def defineGeometries(self):
393# the supplied geometry is for the starboard side and is part of the user supplied Sketch
394# - make a direct copy for the starboard half-hull
395# - negate the X coordinates for the Port side
396# - append a negated reversed copy to each starboard piece for the complete hull
397self.geometryS = list()
398self.geometryP = list()
399self.geometryC = list()
400#grab the endPoint which will be used for covering the half-hull model
401epX = max(self.sketch.Geometry[-1].StartPoint.x, self.sketch.Geometry[-1].EndPoint.x)
402epY = self.yPos
403epZ = max(self.sketch.Geometry[-1].StartPoint.y, self.sketch.Geometry[-1].EndPoint.y)
404self.endPoint = Base.Vector(epX,epY,epZ)
405# first pass through segment of sketch is to determine the min and max X & Y values
406for seg in self.sketch.Geometry:
407# determine the minimum X & Y values
408self.xMin = min(self.xMin, seg.StartPoint.x, seg.EndPoint.x)
409self.yMin = min(self.yMin, seg.StartPoint.y, seg.EndPoint.y)
410self.xMax = max(self.xMax, seg.StartPoint.x, seg.EndPoint.x)
411self.yMax = max(self.yMax, seg.StartPoint.y, seg.EndPoint.y)
412# second pass is to create the S, P and starboard side of the C geometries
413for seg in self.sketch.Geometry:
414# extract the X,Y,Z for start and end
415segStartX = seg.StartPoint.x
416segStartY = seg.StartPoint.y
417segStartZ = seg.StartPoint.z
418segEndX = seg.EndPoint.x
419segEndY = seg.EndPoint.y
420segEndZ = seg.EndPoint.z
421absMinX = abs(self.xMin)
422# normalise segments within drawing to X axis if not stemline
423if not self.stemlineFlag:
424if abs(segStartX) == absMinX:
425if 0<absMinX<1:
426segStartX = 0
427elif absMinX >= 1:
428FreeCAD.Console.PrintMessage("Move to Y axis of '" + self.label + "'\n")
429if segStartX<0:
430segStartX = segStartX + absMinX
431elif segEndX>0:
432segStartX = segStartX - absMinX
433if abs(segEndX) == absMinX:
434if 0<absMinX<1:
435segEndX = 0
436elif absMinX >= 1:
437FreeCAD.Console.PrintMessage("Move to Y axis of '" + self.label + "'\n")
438if segEndX<0:
439segEndX = segEndX + absMinX
440elif segEndX>0:
441segEndX = segEndX - absMinX
442# now create starboard, port, complete geometries
443self.geometryS.append(Part.Line(
444Base.Vector(segStartX, segStartY, segStartZ),
445Base.Vector(segEndX, segEndY, segEndZ)))
446if self.stemlineFlag:
447# stemline is on the YZ axis and is common to both half-hulls
448# so don't flip it's X coordinates
449multiplicand = 1
450else:
451multiplicand = -1
452self.geometryP.append(Part.Line(
453Base.Vector(segStartX*multiplicand, segStartY, segStartZ),
454Base.Vector(segEndX*multiplicand, segEndY, segEndZ)))
455# starboard geometry is first half of complete hull geometry
456self.geometryC.append(self.geometryS[-1])
457# third pass is to create the Complete geometry so the segments have
458# constant direction from starboard to port:
459# 1) reverse segment order of starboard side
460# 2 copy port side geometry
461segCnt = len(self.sketch.Geometry)
462completeGeometry = list()
463for i in range(segCnt):
464completeGeometry.append(self.reverseLineDirection(self.geometryS[segCnt-1-i]))
465for i in range(segCnt):
466completeGeometry.append(self.reverseLineDirection(self.geometryP[i]))
467self.geometryC = completeGeometry
468
469def reverseLineDirection(self,aLine):
470return Part.Line(aLine.EndPoint, aLine.StartPoint)
471
472# Function definitions
473
474def createBottle(aKeelFlag):
475# create a bottle around the hull
476bottleRadius = 250
477neckRadius = 75
478bottleBottom = -1000
479bottleTop = 400
480neckBottom = 800
481neckTop = 1150
482corkHeight = 100
483# get some dimensions for the plaque based on the size of the hull or half-hull
484minusX = crossSections[-2].yPos * 1.1
485plusX = (crossSections[0].yPos + crossSections[0].yMax) * 1.1
486minusY = 0; plusY = 0
487for cs in crossSections:
488#minusY = max(minusY, abs(cs.yMin))
489plusY = max(plusY, cs.yMax)
490minusY = plusY * -0.75
491plusY = plusY * 1.1
492#print minusX, " ", plusX, " ", minusY, " ", plusY
493
494bs0 = FreeCAD.ActiveDocument.addObject("Part::Vertex","Ring0")
495bs0.Label='Ring0'
496bs0.X=0.00
497bs0.Y=bottleBottom*0.97
498bs0.Z=0.00
499bs0.Placement = Base.Placement( Base.Vector(0.00,0.00,0.00),
500Base.Rotation(0.00,0.00,0.00,1.00))
501bs0.ViewObject.Visibility=False
502#
503bs1 = FreeCAD.activeDocument().addObject('Sketcher::SketchObject','Ring1')
504bs1.addGeometry(Part.Circle(Base.Vector(0,0,0), Base.Vector(0,0,1), bottleRadius))
505bs1.Placement = FreeCAD.Placement(FreeCAD.Vector(0.0,bottleBottom,0.0),
506FreeCAD.Rotation(-0.707107,0.0,0.0,-0.707107))
507#
508bs2 = FreeCAD.activeDocument().addObject('Sketcher::SketchObject','Ring2')
509bs2.addGeometry(Part.Circle(Base.Vector(0,0,0), Base.Vector(0,0,1), bottleRadius))
510bs2.Placement = FreeCAD.Placement(FreeCAD.Vector(0.0,bottleTop,0.0),
511FreeCAD.Rotation(-0.707107,0.0,0.0,-0.707107))
512#
513bs3 = FreeCAD.activeDocument().addObject('Sketcher::SketchObject','Ring3')
514bs3.addGeometry(Part.Circle(Base.Vector(0,0,0), Base.Vector(0,0,1), neckRadius))
515bs3.Placement = FreeCAD.Placement(FreeCAD.Vector(0.0,neckBottom,0.0),
516FreeCAD.Rotation(-0.707107,0.0,0.0,-0.707107))
517#
518bs4 = FreeCAD.activeDocument().addObject('Sketcher::SketchObject','Ring4')
519bs4.addGeometry(Part.Circle(Base.Vector(0,0,0), Base.Vector(0,0,1), neckRadius))
520bs4.Placement = FreeCAD.Placement(FreeCAD.Vector(0.0,neckTop,0.0),
521FreeCAD.Rotation(-0.707107,0.0,0.0,-0.707107))
522#
523bot0 = FreeCAD.getDocument('hull_complete').addObject('Part::Loft','Loft0')
524bot0.Sections=[bs0, bs1,]
525bot0.Solid=False; bot0.Ruled=False; bot0.Closed=False
526#
527bot1 = FreeCAD.getDocument('hull_complete').addObject('Part::Loft','Loft1')
528bot1.Sections=[bs1, bs2,]
529bot1.Solid=False; bot1.Ruled=False; bot1.Closed=False
530#
531bot2 = FreeCAD.getDocument('hull_complete').addObject('Part::Loft','Loft2')
532bot2.Sections=[bs2, bs3,]
533bot2.Solid=False; bot2.Ruled=False; bot2.Closed=False
534#
535bot3 = FreeCAD.getDocument('hull_complete').addObject('Part::Loft','Loft3')
536bot3.Sections=[bs3,bs4,]
537bot3.Solid=False; bot3.Ruled=False; bot3.Closed=False
538#
539bottle = FreeCAD.activeDocument().addObject("Part::MultiFuse","Bottle")
540bottle.Shapes = [bot0,bot1,bot2,bot3,]
541bot1.ViewObject.Visibility=False
542bot2.ViewObject.Visibility=False
543bot3.ViewObject.Visibility=False
544#bottle.ViewObject.ShapeColor=Gui.ActiveDocument.Loft1.ShapeColor
545bottle.ViewObject.DisplayMode="Shaded"
546bottle.ViewObject.Transparency=80
547bottle.ViewObject.ShapeColor=(0.4, 0.8, 0.5, 0.0)
548FreeCAD.ActiveDocument.recompute()
549#
550cork = FreeCAD.ActiveDocument.addObject("Part::Cylinder","Cylinder")
551cork.Label = "Cork"
552cork.Radius = neckRadius-1
553cork.Height = corkHeight
554cork.Placement = FreeCAD.Placement( FreeCAD.Vector(0.0,neckTop-(corkHeight/2),0.0),
555FreeCAD.Rotation(FreeCAD.Vector(1,0,0),-90))
556cork.ViewObject.ShapeColor=(0.78, 0.65, 0.35, 0.0)
557cork.ViewObject.DisplayMode = "Shaded"
558#
559FreeCADGui.activeDocument().activeView().viewAxometric()
560FreeCADGui.SendMsgToActiveView("ViewFit")
561FreeCAD.ActiveDocument.recompute()
562
563def createBulkheads(aDictionary):
564userAction = None
565
566docKey = findOpenDocumentName(outputWorkspaceB)
567print docKey
568if docKey!=None:
569reply = QtGui.QMessageBox.question(None, "",
570"The previous 'Bulkheads' output file is still open, close it",
571QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No)
572if reply == QtGui.QMessageBox.Yes:
573FreeCAD.closeDocument(outputWorkspaceB)
574else:
575userAction = userCancelled
576
577if userAction!=userCancelled:
578# bring in values from user dialogue
579coachhouseFlag = aDictionary["coachhouseDeckBulkheadsFlag"]
580forwardBulkheadsToSkip = aDictionary["forwardBulkheadsToSkip"]
581aftBulkheadsToSkip = aDictionary["aftBulkheadsToSkip"]
582deckWidth = aDictionary["deckWidth"]
583deckThrow = aDictionary["deckThrow"]
584coachhouseRise = aDictionary["coachhouseRise"]
585coachhouseIncline = aDictionary["coachhouseIncline"]
586# set up output workspaces
587doc = FreeCAD.newDocument(outputWorkspaceB)
588FreeCAD.setActiveDocument(outputWorkspaceB)
589FreeCAD.ActiveDocument = FreeCAD.getDocument(outputWorkspaceB)
590FreeCADGui.ActiveDocument = FreeCADGui.getDocument(outputWorkspaceB)
591
592for i in range(forwardBulkheadsToSkip,len(crossSections)-aftBulkheadsToSkip):
593# add new bulkhead
594cs = crossSections[i]
595newSketch = FreeCAD.activeDocument().addObject('Sketcher::SketchObject',cs.label)
596#place bulkhead along keel
597newSketch.Placement = FreeCAD.Placement(
598FreeCAD.Vector(cs.xPos,cs.yPos,cs.zPos),
599FreeCAD.Rotation(cs.rotQ1,cs.rotQ2,cs.rotQ3,cs.rotQ4))
600# insert geometry segments from both half-hulls plus bulkhead into new Sketch
601for seg in cs.geometryC:
602newSketch.addGeometry(
603Part.Line(FreeCAD.Vector(seg.StartPoint.x,
604seg.StartPoint.y, 0),
605FreeCAD.Vector(seg.EndPoint.x,
606seg.EndPoint.y,0)))
607FreeCAD.ActiveDocument.recompute()
608xMin = cs.xMax * -1
609if coachhouseFlag:
610# user wants a coachhouse bulkhead
611newSketch.addGeometry(
612Part.Line( FreeCAD.Vector(xMin, cs.yMax, 0),
613FreeCAD.Vector(xMin+deckWidth, cs.yMax+deckThrow, 0)))
614FreeCAD.ActiveDocument.recompute()
615newSketch.addGeometry(
616Part.Line( FreeCAD.Vector(xMin+deckWidth, cs.yMax+deckThrow, 0),
617FreeCAD.Vector(xMin+deckWidth+coachhouseIncline, cs.yMax+deckThrow+coachhouseRise, 0)))
618FreeCAD.ActiveDocument.recompute()
619#
620newSketch.addGeometry(
621Part.Line( FreeCAD.Vector(xMin+deckWidth+coachhouseIncline, cs.yMax+deckThrow+coachhouseRise, 0),
622FreeCAD.Vector(cs.xMax-deckWidth-coachhouseIncline, cs.yMax+deckThrow+coachhouseRise, 0)))
623FreeCAD.ActiveDocument.recompute()
624# focus at about -800
625#newSketch.addGeometry(
626# Part.ArcOfCircle(Part.Circle(App.Vector(0.0,-190,0),App.Vector(0,0,1),240.0),1.078868,2.064096))
627newSketch.addGeometry(
628Part.Line( FreeCAD.Vector(cs.xMax-deckWidth-coachhouseIncline, cs.yMax+deckThrow+coachhouseRise, 0),
629FreeCAD.Vector(cs.xMax-deckWidth, cs.yMax+deckThrow, 0)))
630FreeCAD.ActiveDocument.recompute()
631newSketch.addGeometry(
632Part.Line( FreeCAD.Vector(cs.xMax-deckWidth, cs.yMax+deckThrow, 0),
633FreeCAD.Vector(cs.xMax, cs.yMax, 0)))
634else:
635# generate bulkheads for flush deck
636newSketch.addGeometry(
637Part.Line( FreeCAD.Vector(xMin, cs.yMax, 0),
638FreeCAD.Vector(cs.xMax, cs.yMax, 0)))
639FreeCAD.ActiveDocument.recompute()
640
641newPad = App.activeDocument().addObject("PartDesign::Pad","Bulkhead")
642newPad.Sketch = newSketch
643newPad.Length = 1.0
644newPad.Sketch.ViewObject.hide()
645FreeCAD.ActiveDocument.recompute()
646
647FreeCADGui.SendMsgToActiveView("ViewFit")
648FreeCADGui.activeDocument().activeView().viewAxometric()
649
650def createPlaque(aSideFlag, aKeelFlag):
651# create plaque to mount half-hull on
652# get some dimensions for the plaque based on the size of the hull or half-hull
653# note: the X & Y in this routine are to do with the XY of the plaque, not the Sketches
654woodColour = (0.53, 0.42, 0.23, 0.0)
655# find the overall max & min for X & Y
656minusY = crossSections[1].yMin; plusY = crossSections[1].yMin
657# get the plaque's Y min & max for the cross-sections (not the stemline or transom)
658for i in range(1,len(crossSections)-1):
659minusY = min(minusY, crossSections[i].yMin)
660plusY = max(plusY, crossSections[i].yMax)
661# now allow for the extent of the stemline
662minusY = min(minusY, crossSections[0].yMin)
663plusY = max(plusY, crossSections[0].yMax)
664# get extent of aftmost cross-section and add what the transom sticks out
665minusX = crossSections[-2].yPos + crossSections[-1].yMin - crossSections[-1].yMax
666# get the placement of the stemline and add what the stemline extends forward
667plusX = crossSections[0].yPos + crossSections[0].xMax
668# some scaling factors to provide margin space around the half-hull
669minusX = minusX * 1.1
670plusX = plusX * 1.1
671minusY = minusY * 1.5
672plusY = plusY * 1.25
673
674ps = FreeCAD.activeDocument().addObject('Sketcher::SketchObject','PlainPlaqueSketch')
675ps.Placement = FreeCAD.Placement(FreeCAD.Vector(0.0,0.0,0.0),
676FreeCAD.Rotation(0.5,0.5,0.5,0.5))
677if aSideFlag==starboardSideFlag: ps.Placement.Base.x = -10
678ps.addGeometry(Part.Line(FreeCAD.Vector(minusX,plusY,0),FreeCAD.Vector(plusX,plusY,0)))
679ps.addGeometry(Part.Line(FreeCAD.Vector(plusX,plusY,0),FreeCAD.Vector(plusX,minusY,0)))
680ps.addGeometry(Part.Line(FreeCAD.Vector(plusX,minusY,0),FreeCAD.Vector(minusX,minusY,0)))
681ps.addGeometry(Part.Line(FreeCAD.Vector(minusX,minusY,0),FreeCAD.Vector(minusX,plusY,0)))
682#
683ps.addConstraint(Sketcher.Constraint('Coincident',0,2,1,1))
684ps.addConstraint(Sketcher.Constraint('Coincident',1,2,2,1))
685ps.addConstraint(Sketcher.Constraint('Coincident',2,2,3,1))
686ps.addConstraint(Sketcher.Constraint('Coincident',3,2,0,1))
687ps.addConstraint(Sketcher.Constraint('Horizontal',0))
688ps.addConstraint(Sketcher.Constraint('Horizontal',2))
689ps.addConstraint(Sketcher.Constraint('Vertical',1))
690ps.addConstraint(Sketcher.Constraint('Vertical',3))
691FreeCAD.ActiveDocument.recompute()
692#
693pad = FreeCAD.activeDocument().addObject("PartDesign::Pad","PlainPlaquePad")
694pad.Sketch = ps
695pad.Length = 10.0
696pad.Sketch.ViewObject.hide()
697pad.ViewObject.ShapeColor = woodColour
698FreeCAD.ActiveDocument.recompute()
699#
700cyl1 = FreeCAD.ActiveDocument.addObject("Part::Cylinder","Cylinder1")
701cyl1.Label = "Cylinder1"
702cyl1.Radius = plusY/5
703cyl1.Placement = FreeCAD.Placement(FreeCAD.Vector(0,plusX,plusY),
704FreeCAD.Rotation(FreeCAD.Vector(0,1,0),90))
705if aSideFlag==starboardSideFlag: cyl1.Placement.Base.x = -10
706cut1 = FreeCAD.activeDocument().addObject("Part::Cut","Cut1")
707cut1.Base = App.activeDocument().PlainPlaquePad
708cut1.Tool = App.activeDocument().Cylinder1
709cut1.ViewObject.ShapeColor = woodColour
710FreeCAD.ActiveDocument.recompute()
711#
712cyl2 = FreeCAD.ActiveDocument.addObject("Part::Cylinder","Cylinder2")
713cyl2.Label = "Cylinder2"
714cyl2.Radius = plusY/5
715cyl2.Placement = FreeCAD.Placement(FreeCAD.Vector(0,plusX,minusY),
716FreeCAD.Rotation(FreeCAD.Vector(0,1,0),90))
717if aSideFlag==starboardSideFlag: cyl2.Placement.Base.x = -10
718cut2 = FreeCAD.activeDocument().addObject("Part::Cut","Cut2")
719cut2.Base = App.activeDocument().Cut1
720cut2.Tool = App.activeDocument().Cylinder2
721cut2.ViewObject.ShapeColor = woodColour
722FreeCAD.ActiveDocument.recompute()
723#
724cyl3 = FreeCAD.ActiveDocument.addObject("Part::Cylinder","Cylinder3")
725cyl3.Label = "Cylinder3"
726cyl3.Radius = plusY/5
727cyl3.Placement = FreeCAD.Placement(FreeCAD.Vector(0,minusX,minusY),
728FreeCAD.Rotation(FreeCAD.Vector(0,1,0),90))
729if aSideFlag==starboardSideFlag: cyl3.Placement.Base.x = -10
730cut3 = FreeCAD.activeDocument().addObject("Part::Cut","Cut3")
731cut3.Base = App.activeDocument().Cut2
732cut3.Tool = App.activeDocument().Cylinder3
733cut3.ViewObject.ShapeColor = woodColour
734FreeCAD.ActiveDocument.recompute()
735#
736cyl4 = FreeCAD.ActiveDocument.addObject("Part::Cylinder","Cylinder4")
737cyl4.Label = "Cylinder4"
738cyl4.Radius = plusY/5
739cyl4.Placement = FreeCAD.Placement(FreeCAD.Vector(0,minusX,plusY),
740FreeCAD.Rotation(FreeCAD.Vector(0,1,0),90))
741if aSideFlag==starboardSideFlag: cyl4.Placement.Base.x = -10
742cut4 = FreeCAD.activeDocument().addObject("Part::Cut","Cut4")
743cut4.Base = App.activeDocument().Cut3
744cut4.Tool = App.activeDocument().Cylinder4
745cut4.ViewObject.ShapeColor = woodColour
746FreeCAD.ActiveDocument.recompute()
747#
748cham = FreeCAD.ActiveDocument.addObject("Part::Chamfer","Plaque")
749cham.Base = FreeCAD.ActiveDocument.Cut4
750edges = []
751if aSideFlag == starboardSideFlag:
752edges.append((3,3.00,3.00)); edges.append((13,3.00,3.00)); edges.append((14,3.00,3.00)); edges.append((15,3.00,3.00))
753edges.append((16,3.00,3.00)); edges.append((17,3.00,3.00)); edges.append((18,3.00,3.00)); edges.append((19,3.00,3.00))
754else:
755edges.append((1,3.00,3.00)); edges.append((5,3.00,3.00)); edges.append((6,3.00,3.00)); edges.append((7,3.00,3.00))
756edges.append((8,3.00,3.00)); edges.append((9,3.00,3.00)); edges.append((10,3.00,3.00)); edges.append((11,3.00,3.00))
757cham.Edges = edges
758cham.Base.ViewObject.Visibility = False
759cham.ViewObject.ShapeColor = woodColour
760
761createPlaqueCover()
762
763if aSideFlag == starboardSideFlag:
764FreeCADGui.activeDocument().activeView().viewRight()
765else:
766FreeCADGui.activeDocument().activeView().viewLeft()
767FreeCADGui.SendMsgToActiveView("ViewFit")
768FreeCAD.ActiveDocument.recompute()
769
770def createPlaqueCover():
771# get upper bow point UBP
772# get upper stern point USP
773# get number of sections NS
774# divide the line UBP-USP into NS pieces
775#---
776# for each sketch, get the top point TP
777# make segments between each consecutive points
778#---
779# make RuledSurface between corresponding segments
780
781if len(crossSections)<5:
782FreeCAD.Console.PrintMessage("Insufficient cross-sections for plaque cover")
783else:
784# the number of cross-section and therefore chines determines how many
785# segments will be in the cover for the half-hull model
786segmentCount = len(crossSections)-2
787# determine endpoints for the line segments along the plaque
788bowPoint = Base.Vector(0,
789max(crossSections[0].geometryS[-1].StartPoint.x, crossSections[0].geometryS[-1].EndPoint.x),
790max(crossSections[0].geometryS[-1].StartPoint.y, crossSections[0].geometryS[-1].EndPoint.y))
791sternPoint = Base.Vector(0,
792crossSections[-2].yPos,
793max(crossSections[-2].geometryS[-1].StartPoint.y, crossSections[-2].geometryS[-1].EndPoint.y))
794plaquePoints = [bowPoint, sternPoint]
795lineAlongPlaqueToSplit = Part.Line(bowPoint,sternPoint)
796lapSection = lineAlongPlaqueToSplit.length()/segmentCount
797
798# build a list of the points that start/end the segments
799pointList = []
800pointList.append(lineAlongPlaqueToSplit.StartPoint)
801print lineAlongPlaqueToSplit.StartPoint
802for i in range(1, segmentCount):
803pointList.append(lineAlongPlaqueToSplit.value((i)*lapSection))
804print lineAlongPlaqueToSplit.value((i)*lapSection)
805pointList.append(lineAlongPlaqueToSplit.EndPoint)
806print lineAlongPlaqueToSplit.EndPoint
807808# iterate the list of points from the first segment to the last
809# do stemline first as it is in the YZ plane (cross-sections are in the XZ plane)
810a=FreeCAD.ActiveDocument.addObject('Part::Line', 'cs1k')
811a.X1=0; a.Y1=pointList[0].y; a.Z1=pointList[0].z
812a.X2=0; a.Y2=pointList[1].y; a.Z2=pointList[1].z
813b=FreeCAD.ActiveDocument.addObject('Part::Line', 'cs1h')
814# B1 wrong
815b.X1=0; b.Y1=crossSections[0].endPoint.x; b.Z1=crossSections[0].endPoint.z
816b.X2=crossSections[1].endPoint.x; b.Y2=crossSections[1].endPoint.y; b.Z2=crossSections[1].endPoint.z
817FreeCAD.ActiveDocument.addObject('Part::RuledSurface', 'coverSeg1')
818FreeCAD.ActiveDocument.ActiveObject.Curve1=(a,[''])
819FreeCAD.ActiveDocument.ActiveObject.Curve2=(b,[''])
820FreeCAD.ActiveDocument.recompute()
821# now do cross=sections
822for i in range(1, segmentCount):
823a=FreeCAD.ActiveDocument.addObject('Part::Line', 'cs'+str(i+1)+'k')
824a.X1=0; a.Y1=pointList[i].y; a.Z1=pointList[i].z
825a.X2=0; a.Y2=pointList[i+1].y; a.Z2=pointList[i+1].z
826b=FreeCAD.ActiveDocument.addObject('Part::Line', 'cs'+str(i+1)+'h')
827b.X1=crossSections[i].endPoint.x; b.Y1=crossSections[i].endPoint.y; b.Z1=crossSections[i-1].endPoint.z
828b.X2=crossSections[i+1].endPoint.x; b.Y2=crossSections[i+1].endPoint.y; b.Z2=crossSections[i].endPoint.z
829FreeCAD.ActiveDocument.addObject('Part::RuledSurface', 'coverSeg'+str(i+1))
830FreeCAD.ActiveDocument.ActiveObject.Curve1=(a,[''])
831FreeCAD.ActiveDocument.ActiveObject.Curve2=(b,[''])
832FreeCAD.ActiveDocument.recompute()
833
834FreeCAD.ActiveDocument.recompute()
835
836def displayChinePanels(crossSectionLabelA, crossSectionLabelB, aSideFlag):
837# accept 2 sketch labels and generate a ruled surface between them
838#print sketchLabelA
839placeholder = "_"
840csA = FreeCAD.ActiveDocument.getObjectsByLabel(crossSectionLabelA)[0]
841csB = FreeCAD.ActiveDocument.getObjectsByLabel(crossSectionLabelB)[0]
842labelA = csA.Label
843labelB = csB.Label
844lblA = labelA.split('_', 1)[0]
845lblB = labelB.split('_', 1)[0]
846if aSideFlag == portSideFlag:
847sideText = " Port"
848elif aSideFlag == starboardSideFlag:
849sideText = " Starboard"
850else:
851sideText = ""
852#print str(sketchLabelA) + " " + str(sketchLabelB)
853FreeCAD.ActiveDocument.addObject('Part::RuledSurface', placeholder+lblA+placeholder+lblB+sideText)
854csObjectA = FreeCAD.ActiveDocument.getObjectsByLabel(crossSectionLabelA)[0]
855csObjectB = FreeCAD.ActiveDocument.getObjectsByLabel(crossSectionLabelB)[0]
856#print "> " + str(sketchObjectA) + " " + str(sketchObjectB)
857FreeCAD.ActiveDocument.ActiveObject.Curve1=(csObjectA,[''])
858FreeCAD.ActiveDocument.ActiveObject.Curve2=(csObjectB,[''])
859
860def displayCompleteHull():
861userAction = None
862
863docKey = findOpenDocumentName(outputWorkspaceC)
864if docKey!=None:
865reply = QtGui.QMessageBox.question(None, "",
866"The previous 'Complete Hull' output file is still open, close it",
867QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No)
868if reply == QtGui.QMessageBox.Yes:
869FreeCAD.closeDocument(outputWorkspaceC)
870else:
871userAction = userCancelled
872
873if userAction!=userCancelled:
874doc = App.newDocument(outputWorkspaceC)
875App.setActiveDocument(outputWorkspaceC)
876App.ActiveDocument=App.getDocument(outputWorkspaceC)
877docComplete = App.ActiveDocument
878Gui.ActiveDocument=Gui.getDocument(outputWorkspaceC)
879
880for cs in crossSections:
881# add new Sketch object
882newSketch = FreeCAD.activeDocument().addObject('Sketcher::SketchObject',cs.label)
883newSketch.Placement = FreeCAD.Placement(
884FreeCAD.Vector(cs.xPos,cs.yPos,cs.zPos),
885FreeCAD.Rotation(cs.rotQ1,cs.rotQ2,cs.rotQ3,cs.rotQ4))
886Gui.activeDocument().setEdit(cs.altLabel)
887# insert geometry segments from both half-hulls into new Sketch
888for seg in cs.geometryC:
889newSketch.addGeometry(
890Part.Line(FreeCAD.Vector(seg.StartPoint.x,
891seg.StartPoint.y, 0),
892FreeCAD.Vector(seg.EndPoint.x,
893seg.EndPoint.y,0)))
894Gui.getDocument(doc.Label).resetEdit()
895#print obj.Name + " " + obj.Label
896
897FreeCAD.cs = crossSections # debug statement
898for i in range(0, len(crossSections)-1):
899displayChinePanels(crossSections[i].altLabel,crossSections[i+1].altLabel, "C")
900# now draw the bow sections going to the stemline
901#displayChinePanels(crossSections[].altLabel,crossSections[i+1].altLabel, "C")
902FreeCAD.activeDocument().recompute()
903FreeCADGui.SendMsgToActiveView("ViewFit")
904FreeCADGui.activeDocument().activeView().viewAxometric()
905
906def displayHalfHull(aSideFlag):
907userAction = None
908# create output workspace for one side
909if aSideFlag == starboardSideFlag:
910query = "The previous 'Port Half-Hull' output file is still open, close it"
911selectedOutputWorkspace = outputWorkspaceS
912outputWorkspace = outputWorkspaceS
913sideFlag = starboardSideFlag
914else:
915query = "The previous 'Starboard Half-Hull' output file is still open, close it"
916selectedOutputWorkspace = outputWorkspaceP
917outputWorkspace = outputWorkspaceP
918sideFlag = portSideFlag
919
920docKey = findOpenDocumentName(selectedOutputWorkspace)
921if docKey==None:
922doc = FreeCAD.newDocument(selectedOutputWorkspace)
923else:
924reply = QtGui.QMessageBox.question(None, "",
925query,
926QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No)
927if reply == QtGui.QMessageBox.Yes:
928FreeCAD.closeDocument(selectedOutputWorkspace)
929doc = FreeCAD.newDocument(selectedOutputWorkspace)
930else:
931userAction = userCancelled
932
933if userAction!=userCancelled:
934FreeCAD.setActiveDocument(outputWorkspace)
935FreeCAD.ActiveDocument=FreeCAD.getDocument(outputWorkspace)
936FreeCADGui.ActiveDocument=FreeCADGui.getDocument(outputWorkspace)
937
938# place the segments in the document
939for cs in crossSections:
940# add new Sketch object
941FreeCAD.activeDocument().addObject('Sketcher::SketchObject',cs.label)
942newSketch = FreeCAD.ActiveDocument.getObject(cs.altLabel)
943newSketch.Placement = FreeCAD.Placement(
944FreeCAD.Vector(cs.xPos,cs.yPos,cs.zPos),
945FreeCAD.Rotation(cs.rotQ1,cs.rotQ2,cs.rotQ3,cs.rotQ4))
946Gui.activeDocument().setEdit(cs.altLabel)
947# insert geometry segments into new Sketch
948if sideFlag == "S":
949geom = cs.geometryS
950else:
951geom = cs.geometryP
952for seg in geom:
953newSketch.addGeometry(
954Part.Line(FreeCAD.Vector(seg.StartPoint.x,
955seg.StartPoint.y, 0),
956FreeCAD.Vector(seg.EndPoint.x,
957seg.EndPoint.y,0)))
958Gui.getDocument(doc.Label).resetEdit()
959
960for i in range(0, len(crossSections)-1):
961displayChinePanels(crossSections[i].altLabel,crossSections[i+1].altLabel, sideFlag)
962
963FreeCAD.activeDocument().recompute()
964FreeCADGui.SendMsgToActiveView("ViewFit")
965FreeCADGui.activeDocument().activeView().viewAxometric()
966
967def eqRotation(rotationA, rotationB, eps=0.0001):
968"takes 2 Rotations and compares for equality"
969eqFlag = True
970for i in range(0, 4):
971#print str(rotationA.Q[i]) + "#" + str(rotationB.Q[i])
972if rotationA.Q[i] == 0:
973if rotationB.Q[i] <> 0:
974eqFlag = False
975elif abs(abs(rotationA.Q[i])-abs(rotationB.Q[i]))/abs(rotationA.Q[i]) > eps:
976eqFlag = False
977return eqFlag
978
979def resetSketchesVisibility():
980# set Visibility on all Sketches to False
981openWindows = list()
982if starboardHHFlag:
983openWindows.append(outputWorkspaceS)
984if portHHFlag:
985openWindows.append(outputWorkspaceP)
986if completeHullFlag:
987openWindows.append(outputWorkspaceC)
988#if fullHullBulkheadsFlag:
989#openWindows.append(outputWorkspaceB)
990
991for ws in openWindows:
992FreeCAD.setActiveDocument(ws)
993FreeCAD.ActiveDocument=FreeCAD.getDocument(ws)
994FreeCADGui.ActiveDocument=FreeCADGui.getDocument(ws)
995for obj in FreeCAD.ActiveDocument.Objects:
996if obj.TypeId == 'Sketcher::SketchObject':
997vo = FreeCADGui.ActiveDocument.getObject(obj.Name)
998vo.Visibility=False
999
1000def sortOutFilesAndDocuments():
1001global keepSourceOpenFlag
1002# this routine uses the following variables from the main handler:
1003# docSrc (returns)
1004# fileName (reads)
1005# keepSourceOpenFlag (global, writes)
1006# it determines if the 'user selected input document' is already open,
1007# if it is then it is made the ActiveDocument, otherwise it is
1008# Opened which also sets it to the ActiveDocument
1009if len(FreeCAD.listDocuments())==0:
1010# no documents open
1011return FreeCAD.open(fileName)
1012else:
1013# some document(s) open so check if 'user selected input document' is already open
1014"""docKey = None
1015for key in FreeCAD.listDocuments():
1016if FreeCAD.listDocuments()[key].FileName==fileName:
1017docKey = key"""
1018docKey = findOpenDocumentFileSpec(fileName)
1019if docKey==None:
1020# 'user selected input document' is not open
1021return FreeCAD.open(fileName)
1022else:
1023# 'user selected input document' is among open documents
1024# set the 'user selected input document' to the active document (in case it isn't)
1025FreeCAD.setActiveDocument(docKey)
1026# user started with 'user selected input document' open, so this flag will allow
1027# us to leave it open when we finish
1028keepSourceOpenFlag = True
1029return FreeCAD.ActiveDocument
1030
1031def findOpenDocumentFileSpec(aDocumentFileSpec):
1032# check if supplied document is already open
1033# return document name or None
1034docKey = None
1035for key in FreeCAD.listDocuments():
1036if FreeCAD.listDocuments()[key].FileName==aDocumentFileSpec:
1037docKey = key
1038return docKey
1039
1040def findOpenDocumentName(aDocumentName):
1041# check if supplied document is already open
1042# return document name or None
1043docKey = None
1044for key in FreeCAD.listDocuments():
1045if FreeCAD.listDocuments()[key].Name==aDocumentName:
1046docKey = key
1047return docKey
1048
1049# Constant definitions
1050outputWorkspaceS = "hull_starboard"
1051outputWorkspaceP = "hull_port"
1052outputWorkspaceC = "hull_complete"
1053outputWorkspaceB = "bulkheads"
1054xyPlane = Base.Rotation(0.0, 0.0, 0.0, 1.0) # transom
1055xzPlane = Base.Rotation(0.7071067811865475, 0.0, 0.0, 0.7071067811865476) # cross section profile
1056yzPlane = Base.Rotation(0.5,0.5,0.5,0.5) # stemline
1057infinity = +99999999999999.9 # will hold min Y value in Sketch
1058infinityNegative = -99999999999999.9 # will hold max X value in Sketch
1059global starboardSideFlag, portSideFlag, userCancelled, userLastFile, userOK
1060starboardSideFlag = "S"
1061portSideFlag = "F"
1062completeSidesFlag = "C"
1063userCancelled = "Cancelled"
1064userLastFile = "Last File"
1065userOK = "OK"
1066defaultDir = FreeCAD.ConfigGet("UserHomePath")
1067
1068# code ***********************************************************************************
1069allCrossSections = {}
1070crossSections = list()
1071docSrc = None
1072global keepSourceOpenFlag
1073keepSourceOpenFlag = False
1074starboardHHFlag = False; starboardHHPlaqueFlag = False; starboardHHPKeelFlag = False
1075portHHFlag = False; portHHPlaqueFlag = False; portHHPKeelFlag = False
1076completeHullFlag = False; completeHullBottleFlag = False; completeHullKeelFlag = False
1077bulkheadsFlag = False; flushDeckBulkheadsFlag = True; coachhouseDeckBulkheadsFlag = True
1078
1079form = GetConfigParams()
1080form.exec_()
1081configParams = form.configParams
1082
1083if configParams.result==userLastFile:
1084if hasattr(FreeCAD,"MacroHalfHullConfigParams"):
1085# global in FreeCAD exists so use the parameters stored there
1086#if type(FreeCAD.MacroHalfHullConfigParams)=='GetConfigParams':
1087configParams = FreeCAD.MacroHalfHullConfigParams
1088configParams.result = userLastFile
1089else:
1090# user requested to re-use last file but there isn't one
1091# so reset the choice to pick a file
1092configParams.result = userOK
1093
1094if configParams.result != userCancelled:
1095# transfer results to control flags
1096starboardHHFlag = configParams.cb1a
1097starboardHHPlaqueFlag = configParams.cb1b
1098starboardHHPKeelFlag = configParams.cb1c
1099portHHFlag = configParams.cb2a
1100portHHPlaqueFlag = configParams.cb2b
1101portHHPKeelFlag = configParams.cb2c
1102completeHullFlag = configParams.cb3a
1103completeHullBottleFlag = configParams.cb3b
1104completeHullKeelFlag = configParams.cb3c
1105bulkheadsFlag = configParams.cb4a
1106# transfer bulkhead parameters
1107bulkheadParams = {}
1108bulkheadParams["coachhouseDeckBulkheadsFlag"] = configParams.rb5b
1109bulkheadParams["forwardBulkheadsToSkip"] = int(configParams.skipAtBow)
1110bulkheadParams["aftBulkheadsToSkip"] = int(configParams.skipAtStern)
1111bulkheadParams["deckWidth"] = float(configParams.deckWidth.text())
1112bulkheadParams["deckThrow"] = float(configParams.deckThrow.text())
1113bulkheadParams["coachhouseRise"] = float(configParams.coachhouseRise.text())
1114bulkheadParams["coachhouseIncline"] = float(configParams.coachhouseIncline.text())
1115
1116defaultDir = expanduser("~")
1117defaultDir = "/Data Pool/Coding/FreeCAD/work items/hull mirroring/half-hull/"
1118if configParams.result==userOK:
1119# user wants to select file
1120fileName = QtGui.QFileDialog.getOpenFileName(dir=defaultDir, caption = "Select a 'Hull Profile' to Load", filter="*.FCStd")[0]
1121configParams.documentFileName = fileName
1122else:
1123# file is coming out of FreeCAD global
1124fileName = FreeCAD.MacroHalfHullConfigParams.documentFileName
1125
1126if len(fileName) != 0:
1127docSrc = sortOutFilesAndDocuments()
1128# read all the objects, saving the Sketcher objects
1129for obj in FreeCAD.ActiveDocument.Objects:
1130if obj.TypeId == 'Sketcher::SketchObject':
1131# ignore anything except Sketches
1132newObj = HullCrossSection(obj)
1133if newObj.transomFlag:
1134# if we have the transom sketch then wait to give
1135# it a placement further aft than anything else
1136transomObject = newObj
1137elif newObj.stemlineFlag:
1138# if we have the stemline sketch then wait
1139# to give it the first placement
1140stemlineObject = newObj
1141stemlineSegmentCount = stemlineObject.sketch.GeometryCount
1142else:
1143# must be a regular cross section profile
1144# so add object to our collection
1145allCrossSections[newObj.key] = newObj
1146#maxY = max(maxY, newObj.yPos)
1147
1148# discard sketches with wrong number of points
1149# i.e. cross-sections that have a different number
1150# of points than the stemline
1151for key, cs in allCrossSections.items():
1152if cs.geometryCount <> stemlineSegmentCount:
1153FreeCAD.Console.PrintMessage("Discard for wrong number of segments for '" + str(allCrossSections[key].label) + "'\n")
1154del allCrossSections[key]
1155
1156# construct a list with cross sections in order from stemline to transom
1157crossSections.append(stemlineObject)
1158for sk in sorted(allCrossSections.keys(), reverse=True):
1159crossSections.append(allCrossSections[sk])
1160transomObject.zPos = crossSections[-1].zPos+crossSections[-1].yMax
1161crossSections.append(transomObject)
1162
1163FreeCAD.cs = crossSections # debug statement
1164
1165# now set the transom elevation at the top of the last cross-section
1166crossSections[-1].zPos = crossSections[-2].zPos + crossSections[-2].yMax
1167
1168FreeCAD.cs = crossSections # debug statement
1169
1170# depending on user flags, invoke appropriate modules
1171if starboardHHFlag: displayHalfHull(starboardSideFlag)
1172if starboardHHPlaqueFlag: createPlaque(starboardSideFlag, starboardHHPKeelFlag)
1173if portHHFlag: displayHalfHull(portSideFlag)
1174if portHHPlaqueFlag: createPlaque(portSideFlag, portHHPKeelFlag)
1175if completeHullFlag: displayCompleteHull()
1176if completeHullBottleFlag: createBottle(completeHullKeelFlag)
1177if bulkheadsFlag: createBulkheads(bulkheadParams)
1178
1179# save Config Params to FreeCAD global in case user wants to use it next run
1180FreeCAD.MacroHalfHullConfigParams = configParams
1181
1182if not keepSourceOpenFlag:
1183FreeCAD.closeDocument(docSrc.Name)
1184resetSketchesVisibility()
1185#
1186#OS: Mac OS X
1187#Word size: 64-bit
1188#Version: 0.14.3703 (Git)
1189#Branch: releases/FreeCAD-0-14
1190#Hash: c6edd47334a3e6f209e493773093db2b9b4f0e40
1191#Python version: 2.7.5
1192#Qt version: 4.8.6
1193#Coin version: 3.1.3
1194#SoQt version: 1.5.0
1195#OCC version: 6.7.0
1196#
1197#and so the macro ends...
1198