User:Renatorivo: Difference between revisions

From FreeCAD Documentation
(Macro Half Hull)
(Blanked the page)
Line 1: Line 1:
{{Code|code=
#
#
# Half Hull
#
#
################################

import FreeCAD
from FreeCAD import Base, Draft
import Part, PartGui, sys, math, collections
from collections import OrderedDict
from os.path import expanduser # default input directory
from PySide import QtGui, QtCore

# UI Class definitions

class ConfigParams:
"""carrier for the user selection parameters"""
def __init__(self):
self.result = None
self.cb1a = None
self.cb1b = None
self.cb1c = None
self.cb2a = None
self.cb2b = None
self.cb2c = None
self.cb3a = None
self.cb3b = None
self.cb3c = None
self.cb4a = None
self.rb4b = None
self.rb5b = None
self.skipAtBow = None
self.skipAtStern = None
self.deckWidth = None
self.deckThrow = None
self.coachhouseRise = None
self.coachhouseIncline = None
self.documentFileName = None

class GetConfigParams(QtGui.QDialog):
""""""
def __init__(self):
super(GetConfigParams, self).__init__()
self.initUI()
def initUI(self):
self.configParams = ConfigParams()
# set default return value
self.configParams.result = userCancelled
# set default values
skipAtBowDefault = str(2)
skipAtSternDefault = str(2)
deckWidthDefault = str(50)
deckThrowDefault = str(2)
coachhouseRiseDefault = str(50)
coachhouseInclineDefault = str(8)
# field descriptors
self.promptLbl = QtGui.QLabel("Please Choose Options:", self)
self.promptLbl.move(20, 20)
# checkboxes - define first so signals can be set up
self.cb1a = QtGui.QCheckBox("Starboard half-hull", self)
self.cb1b = QtGui.QCheckBox("Mounting plaque", self)
self.cb1c = QtGui.QCheckBox("Allow space for keel", self)
self.cb2a = QtGui.QCheckBox("Port half-hull", self)
self.cb2b = QtGui.QCheckBox("Mounting plaque", self)
self.cb2c = QtGui.QCheckBox("Allow space for keel", self)
self.cb3a = QtGui.QCheckBox("Complete hull", self)
self.cb3b = QtGui.QCheckBox("Bottle for complete hull", self)
self.cb3c = QtGui.QCheckBox("Allow space for keel", self)
self.rb4b = QtGui.QRadioButton("Bulkheads for flush deck",self)
self.rb5b = QtGui.QRadioButton("Bulkheads for coachhouse",self)
#
self.cb1a.clicked.connect(self.onCb1a)
self.cb1a.toggle() # set default value
self.cb1c.setEnabled(False)
#self.cb1a.stateChanged.connect(self.onCb1a)
self.cb1a.move(20,50)
#
self.cb1b.clicked.connect(self.onCb1b)
self.cb1b.move(250,50)
#
self.cb1c.clicked.connect(self.onCb1c)
self.cb1c.move(450,50)
#
self.cb2a.clicked.connect(self.onCb2a)
self.cb2b.setEnabled(False)
self.cb2c.setEnabled(False)
self.cb2a.move(20,80)
#
self.cb2b.clicked.connect(self.onCb2b)
self.cb2b.move(250,80)
#
self.cb2c.clicked.connect(self.onCb2c)
self.cb2c.move(450,80)
#
self.cb3a.clicked.connect(self.onCb3a)
self.cb3b.setEnabled(False)
self.cb3c.setEnabled(False)
self.cb3a.move(20,110)
#
self.cb3b.clicked.connect(self.onCb3b)
self.cb3b.move(250,110)
#
self.cb3c.clicked.connect(self.onCb3c)
self.cb3c.move(450,110)
#
self.cb4a = QtGui.QCheckBox("Bulkheads for complete hull", self)
self.cb4a.clicked.connect(self.onCb4a)
self.rb4b.setEnabled(False)
self.rb5b.setEnabled(False)
#self.hideCoachhouseFields(True) # grey out coachhouse fields
self.cb4a.move(20,140)
# radio buttons
self.rb4b.move(250,140)
self.rb4b.clicked.connect(self.onRb4b)
#
self.rb5b.move(250,170)
self.rb5b.clicked.connect(self.onRb5b)
#
self.skipAtBowLabel = QtGui.QLabel("Cross-sections to skip at bow:", self)
self.skipAtBowLabel.move(270, 200)
self.skipAtBow = 0
#
self.skipAtSternLabel = QtGui.QLabel("Cross-sections to skip at stern:", self)
self.skipAtSternLabel.move(270, 230)
self.skipAtStern = 0
#
self.deckWidthLabel = QtGui.QLabel("Deck Width:", self)
self.deckWidthLabel.move(270, 260)
self.deckWidth = QtGui.QLineEdit(self)
self.deckWidth.setInputMask("999")
self.deckWidth.setText(deckWidthDefault)
self.deckWidth.setFixedWidth(35)
self.deckWidth.move(493, 260)
#
self.deckThrowLabel = QtGui.QLabel("Deck throw:", self)
self.deckThrowLabel.move(270, 290)
self.deckThrow = QtGui.QLineEdit(self)
self.deckThrow.setInputMask("999")
self.deckThrow.setText(deckThrowDefault)
self.deckThrow.setFixedWidth(35)
self.deckThrow.move(493, 290)
#
self.coachhouseRiseLabel = QtGui.QLabel("Coachhouse Rise:", self)
self.coachhouseRiseLabel.move(270, 320)
self.coachhouseRise = QtGui.QLineEdit(self)
self.coachhouseRise.setInputMask("999")
self.coachhouseRise.setText(coachhouseRiseDefault)
self.coachhouseRise.setFixedWidth(35)
self.coachhouseRise.move(493, 320)
#
self.coachhouseInclineLabel = QtGui.QLabel("Coachhouse Incline:", self)
self.coachhouseInclineLabel.move(270, 350)
self.coachhouseIncline = QtGui.QLineEdit(self)
self.coachhouseIncline.setInputMask("999")
self.coachhouseIncline.setText(coachhouseInclineDefault)
self.coachhouseIncline.setFixedWidth(35)
self.coachhouseIncline.move(493, 350)
# set up lists for pop-ups
self.popupItemsB = OrderedDict([("2",""),("3",""),("4",""),("5",""),("6",""),("7",""),("8",""),("9",""),("10","")])
self.popupItemsS = OrderedDict([("1",""),("2",""),("3",""),("4",""),("5",""),("6",""),("7",""),("8",""),("9",""),("10","")])
# set up pop-up menu of bulkheads to skip bulkheads at bow
self.skipAtBowPop = QtGui.QComboBox(self)
self.skipAtBowPop.addItems(self.popupItemsB.keys())
self.skipAtBowPop.setCurrentIndex(self.popupItemsB.keys().index(skipAtBowDefault))
self.skipAtBow = skipAtBowDefault
self.skipAtBowPop.move(490, 200)
self.skipAtBowPop.activated[str].connect(self.onSkipBowActivated)
# set up pop-up menu of bulkheads to skip bulkheads at stern
self.skipAtSternPop = QtGui.QComboBox(self)
self.skipAtSternPop.addItems(self.popupItemsS.keys())
self.skipAtSternPop.setCurrentIndex(self.popupItemsS.keys().index(skipAtSternDefault))
self.skipAtStern = skipAtSternDefault
self.skipAtSternPop.move(490, 230)
self.skipAtSternPop.activated[str].connect(self.onSkipSternActivated)
# cancel button
cancelButton = QtGui.QPushButton('Cancel', self)
cancelButton.clicked.connect(self.onCancel)
cancelButton.move(260, 390)
# last used button
lastFileButton = QtGui.QPushButton('Re-use last file', self)
lastFileButton.clicked.connect(self.onLastFile)
lastFileButton.move(345, 390)
# OK button
sfButton = QtGui.QPushButton('Select File', self)
sfButton.clicked.connect(self.onSf)
sfButton.move(480, 390)
# define window xLoc,yLoc,xDim,yDim
self.setGeometry( 250, 250, 630, 445)
self.setWindowTitle("Macro Configuration")
self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
self.disableCoachhouseFields(True) # grey out coachhouse fields
self.show()
#
def onCb1a(self):
if self.cb1a.isChecked():
self.cb1b.setEnabled(True)
else:
self.cb1b.setEnabled(False)
self.cb1b.setChecked(False)
self.cb1c.setEnabled(False)
self.cb1c.setChecked(False)
def onCb1b(self):
if self.cb1b.isChecked():
self.cb1c.setEnabled(True)
else:
self.cb1c.setEnabled(False)
self.cb1c.setChecked(False)
def onCb1c(self):
pass
def onCb2a(self):
if self.cb2a.isChecked():
self.cb2b.setEnabled(True)
else:
self.cb2b.setEnabled(False)
self.cb2b.setChecked(False)
self.cb2c.setEnabled(False)
self.cb2c.setChecked(False)
def onCb2b(self):
if self.cb2b.isChecked():
self.cb2c.setEnabled(True)
else:
self.cb2c.setEnabled(False)
self.cb2c.setChecked(False)
def onCb2c(self):
pass
def onCb3a(self):
if self.cb3a.isChecked():
self.cb3b.setEnabled(True)
else:
self.cb3b.setEnabled(False)
self.cb3b.setChecked(False)
self.cb3c.setEnabled(False)
self.cb3c.setChecked(False)
def onCb3b(self):
if self.cb3b.isChecked():
self.cb3c.setEnabled(True)
else:
self.cb3c.setEnabled(False)
self.cb3c.setChecked(False)
def onCb3c(self):
pass
def onCb4a(self):
if self.cb4a.isChecked():
self.rb4b.setEnabled(True)
self.rb4b.setChecked(True)
self.rb5b.setEnabled(True)
self.rb5b.setChecked(False)
else:
self.rb4b.setChecked(False)
self.rb4b.setEnabled(False)
self.rb5b.setChecked(False)
self.rb5b.setEnabled(False)
self.disableCoachhouseFields(True)
def onRb4b(self):
if self.rb4b.isChecked():
self.disableCoachhouseFields(True)
else:
self.disableCoachhouseFields(False)
def onRb5b(self):
if self.rb5b.isChecked():
self.disableCoachhouseFields(False)
else:
self.disableCoachhouseFields(True)
def onSkipBowActivated(self, text):
self.skipAtBow = text
def onSkipSternActivated(self, text):
self.skipAtStern = text
def disableCoachhouseFields(self, aFlag):
# enable or disable coachhouse parameter fields
if aFlag:
self.skipAtBowLabel.setEnabled(False)
self.skipAtBowPop.setEnabled(False)
self.skipAtSternLabel.setEnabled(False)
self.skipAtSternPop.setEnabled(False)
self.deckWidthLabel.setEnabled(False)
self.deckWidth.setEnabled(False)
self.deckThrowLabel.setEnabled(False)
self.deckThrow.setEnabled(False)
self.coachhouseRiseLabel.setEnabled(False)
self.coachhouseRise.setEnabled(False)
self.coachhouseInclineLabel.setEnabled(False)
self.coachhouseIncline.setEnabled(False)
else:
self.skipAtBowLabel.setEnabled(True)
self.skipAtBowPop.setEnabled(True)
self.skipAtSternLabel.setEnabled(True)
self.skipAtSternPop.setEnabled(True)
self.deckWidthLabel.setEnabled(True)
self.deckWidth.setEnabled(True)
self.deckThrowLabel.setEnabled(True)
self.deckThrow.setEnabled(True)
self.coachhouseRiseLabel.setEnabled(True)
self.coachhouseRise.setEnabled(True)
self.coachhouseInclineLabel.setEnabled(True)
self.coachhouseIncline.setEnabled(True)
def onCancel(self):
self.configParams.result = userCancelled
self.close()
def transferConfigParams(self):
self.configParams.cb1a = self.cb1a.isChecked()
self.configParams.cb1b = self.cb1b.isChecked()
self.configParams.cb1c = self.cb1c.isChecked()
self.configParams.cb2a = self.cb2a.isChecked()
self.configParams.cb2b = self.cb2b.isChecked()
self.configParams.cb2c = self.cb2c.isChecked()
self.configParams.cb3a = self.cb3a.isChecked()
self.configParams.cb3b = self.cb3b.isChecked()
self.configParams.cb3c = self.cb3c.isChecked()
self.configParams.cb4a = self.cb4a.isChecked()
self.configParams.rb5b = self.rb5b.isChecked()
self.configParams.skipAtBow = self.skipAtBow
self.configParams.skipAtStern = self.skipAtStern
self.configParams.deckWidth = self.deckWidth
self.configParams.deckThrow = self.deckThrow
self.configParams.coachhouseRise = self.coachhouseRise
self.configParams.coachhouseIncline = self.coachhouseIncline
def onLastFile(self):
self.configParams.result = userLastFile
self.transferConfigParams()
self.close()
def onSf(self):
self.configParams.result = userOK
self.transferConfigParams()
self.close()

# Class definitions

class HullCrossSection:
"Holder of information pertaining to a cross section profile"
#persistentInstance = ""
#import copy
def __init__(self,aSketch):
self.sketch = aSketch
self.geometryCount = aSketch.GeometryCount
self.geometryS = None # geometry for starboard side
self.geometryP = None # geometry for port side
self.geometryC = None # geometry for complete hull (i.e. both halves as one)
self.label = aSketch.Label
# next 2 lines due to mysterious label morphing routine of FreeCAD
self.altLabel = self.label.replace(" ", "_")
self.altLabel = self.altLabel.replace("-", "_")
#
self.xPos = 0.0 # normalise sketch to axis
self.yPos = aSketch.Placement.Base.y
self.zPos = aSketch.Placement.Base.z
self.xMin = infinity # will hold min X value in Sketch
self.yMin = infinity # will hold min Y value in Sketch
self.xMax = infinityNegative # will hold max X value in Sketch
self.yMax = infinityNegative # will hold max Y value in Sketch
self.endPoint = None # will be the 'top' point on the polyline
self.key = int(self.yPos)
self.rotation = aSketch.Placement.Rotation
self.rotAngle = aSketch.Placement.Rotation.Angle
self.rotAxis = aSketch.Placement.Rotation.Axis
self.rotQ = aSketch.Placement.Rotation.Q
# following 4 statements seem necessary to pass the Rotation quad-value
self.rotQ1 = aSketch.Placement.Rotation.Q[0]
self.rotQ2 = aSketch.Placement.Rotation.Q[1]
self.rotQ3 = aSketch.Placement.Rotation.Q[2]
self.rotQ4 = aSketch.Placement.Rotation.Q[3]
# set flags for either stemline or transom or suspected transom cross-section
if eqRotation(self.rotation,yzPlane):
# if we have the stemline then wait to give it the foremost placement
FreeCAD.Console.PrintMessage("Stemline identified '" + self.label + "'\n")
self.stemlineFlag = True
else:
self.stemlineFlag = False
if eqRotation(self.rotation,xyPlane):
# if we have the transom then wait to give it the aftmost placement
FreeCAD.Console.PrintMessage("Transom identified '" + self.label + "'\n")
self.transomFlag = True
else:
self.transomFlag = False
if eqRotation(self.rotation,xzPlane):
# the most numerous sketches will be the cross-sections, so don't flag it
self.possibleTransomCS = False
else:
# it's not lying in any of the 3 planes so it's either an error
# or it could be an inclined cross-section for the transom
# (although there should only be one or none of these)
# flag it as such and sort it out later once all the other
# cross-sections are placed
if not (self.stemlineFlag or self.transomFlag):
FreeCAD.Console.PrintMessage("Possible Transom cross-section identified '" + self.label + "'\n")
self.possibleTransomCS = True
self.defineGeometries() # make S & P & C geometries from the geometry of the supplied Sketch
def defineGeometries(self):
# the supplied geometry is for the starboard side and is part of the user supplied Sketch
# - make a direct copy for the starboard half-hull
# - negate the X coordinates for the Port side
# - append a negated reversed copy to each starboard piece for the complete hull
self.geometryS = list()
self.geometryP = list()
self.geometryC = list()
#grab the endPoint which will be used for covering the half-hull model
epX = max(self.sketch.Geometry[-1].StartPoint.x, self.sketch.Geometry[-1].EndPoint.x)
epY = self.yPos
epZ = max(self.sketch.Geometry[-1].StartPoint.y, self.sketch.Geometry[-1].EndPoint.y)
self.endPoint = Base.Vector(epX,epY,epZ)
# first pass through segment of sketch is to determine the min and max X & Y values
for seg in self.sketch.Geometry:
# determine the minimum X & Y values
self.xMin = min(self.xMin, seg.StartPoint.x, seg.EndPoint.x)
self.yMin = min(self.yMin, seg.StartPoint.y, seg.EndPoint.y)
self.xMax = max(self.xMax, seg.StartPoint.x, seg.EndPoint.x)
self.yMax = max(self.yMax, seg.StartPoint.y, seg.EndPoint.y)
# second pass is to create the S, P and starboard side of the C geometries
for seg in self.sketch.Geometry:
# extract the X,Y,Z for start and end
segStartX = seg.StartPoint.x
segStartY = seg.StartPoint.y
segStartZ = seg.StartPoint.z
segEndX = seg.EndPoint.x
segEndY = seg.EndPoint.y
segEndZ = seg.EndPoint.z
absMinX = abs(self.xMin)
# normalise segments within drawing to X axis if not stemline
if not self.stemlineFlag:
if abs(segStartX) == absMinX:
if 0<absMinX<1:
segStartX = 0
elif absMinX >= 1:
FreeCAD.Console.PrintMessage("Move to Y axis of '" + self.label + "'\n")
if segStartX<0:
segStartX = segStartX + absMinX
elif segEndX>0:
segStartX = segStartX - absMinX
if abs(segEndX) == absMinX:
if 0<absMinX<1:
segEndX = 0
elif absMinX >= 1:
FreeCAD.Console.PrintMessage("Move to Y axis of '" + self.label + "'\n")
if segEndX<0:
segEndX = segEndX + absMinX
elif segEndX>0:
segEndX = segEndX - absMinX
# now create starboard, port, complete geometries
self.geometryS.append(Part.Line(
Base.Vector(segStartX, segStartY, segStartZ),
Base.Vector(segEndX, segEndY, segEndZ)))
if self.stemlineFlag:
# stemline is on the YZ axis and is common to both half-hulls
# so don't flip it's X coordinates
multiplicand = 1
else:
multiplicand = -1
self.geometryP.append(Part.Line(
Base.Vector(segStartX*multiplicand, segStartY, segStartZ),
Base.Vector(segEndX*multiplicand, segEndY, segEndZ)))
# starboard geometry is first half of complete hull geometry
self.geometryC.append(self.geometryS[-1])
# third pass is to create the Complete geometry so the segments have
# constant direction from starboard to port:
# 1) reverse segment order of starboard side
# 2 copy port side geometry
segCnt = len(self.sketch.Geometry)
completeGeometry = list()
for i in range(segCnt):
completeGeometry.append(self.reverseLineDirection(self.geometryS[segCnt-1-i]))
for i in range(segCnt):
completeGeometry.append(self.reverseLineDirection(self.geometryP[i]))
self.geometryC = completeGeometry
def reverseLineDirection(self,aLine):
return Part.Line(aLine.EndPoint, aLine.StartPoint)

# Function definitions

def createBottle(aKeelFlag):
# create a bottle around the hull
bottleRadius = 250
neckRadius = 75
bottleBottom = -1000
bottleTop = 400
neckBottom = 800
neckTop = 1150
corkHeight = 100
# get some dimensions for the plaque based on the size of the hull or half-hull
minusX = crossSections[-2].yPos * 1.1
plusX = (crossSections[0].yPos + crossSections[0].yMax) * 1.1
minusY = 0; plusY = 0
for cs in crossSections:
#minusY = max(minusY, abs(cs.yMin))
plusY = max(plusY, cs.yMax)
minusY = plusY * -0.75
plusY = plusY * 1.1
#print minusX, " ", plusX, " ", minusY, " ", plusY
bs0 = FreeCAD.ActiveDocument.addObject("Part::Vertex","Ring0")
bs0.Label='Ring0'
bs0.X=0.00
bs0.Y=bottleBottom*0.97
bs0.Z=0.00
bs0.Placement = Base.Placement( Base.Vector(0.00,0.00,0.00),
Base.Rotation(0.00,0.00,0.00,1.00))
bs0.ViewObject.Visibility=False
#
bs1 = FreeCAD.activeDocument().addObject('Sketcher::SketchObject','Ring1')
bs1.addGeometry(Part.Circle(Base.Vector(0,0,0), Base.Vector(0,0,1), bottleRadius))
bs1.Placement = FreeCAD.Placement(FreeCAD.Vector(0.0,bottleBottom,0.0),
FreeCAD.Rotation(-0.707107,0.0,0.0,-0.707107))
#
bs2 = FreeCAD.activeDocument().addObject('Sketcher::SketchObject','Ring2')
bs2.addGeometry(Part.Circle(Base.Vector(0,0,0), Base.Vector(0,0,1), bottleRadius))
bs2.Placement = FreeCAD.Placement(FreeCAD.Vector(0.0,bottleTop,0.0),
FreeCAD.Rotation(-0.707107,0.0,0.0,-0.707107))
#
bs3 = FreeCAD.activeDocument().addObject('Sketcher::SketchObject','Ring3')
bs3.addGeometry(Part.Circle(Base.Vector(0,0,0), Base.Vector(0,0,1), neckRadius))
bs3.Placement = FreeCAD.Placement(FreeCAD.Vector(0.0,neckBottom,0.0),
FreeCAD.Rotation(-0.707107,0.0,0.0,-0.707107))
#
bs4 = FreeCAD.activeDocument().addObject('Sketcher::SketchObject','Ring4')
bs4.addGeometry(Part.Circle(Base.Vector(0,0,0), Base.Vector(0,0,1), neckRadius))
bs4.Placement = FreeCAD.Placement(FreeCAD.Vector(0.0,neckTop,0.0),
FreeCAD.Rotation(-0.707107,0.0,0.0,-0.707107))
#
bot0 = FreeCAD.getDocument('hull_complete').addObject('Part::Loft','Loft0')
bot0.Sections=[bs0, bs1,]
bot0.Solid=False; bot0.Ruled=False; bot0.Closed=False
#
bot1 = FreeCAD.getDocument('hull_complete').addObject('Part::Loft','Loft1')
bot1.Sections=[bs1, bs2,]
bot1.Solid=False; bot1.Ruled=False; bot1.Closed=False
#
bot2 = FreeCAD.getDocument('hull_complete').addObject('Part::Loft','Loft2')
bot2.Sections=[bs2, bs3,]
bot2.Solid=False; bot2.Ruled=False; bot2.Closed=False
#
bot3 = FreeCAD.getDocument('hull_complete').addObject('Part::Loft','Loft3')
bot3.Sections=[bs3,bs4,]
bot3.Solid=False; bot3.Ruled=False; bot3.Closed=False
#
bottle = FreeCAD.activeDocument().addObject("Part::MultiFuse","Bottle")
bottle.Shapes = [bot0,bot1,bot2,bot3,]
bot1.ViewObject.Visibility=False
bot2.ViewObject.Visibility=False
bot3.ViewObject.Visibility=False
#bottle.ViewObject.ShapeColor=Gui.ActiveDocument.Loft1.ShapeColor
bottle.ViewObject.DisplayMode="Shaded"
bottle.ViewObject.Transparency=80
bottle.ViewObject.ShapeColor=(0.4, 0.8, 0.5, 0.0)
FreeCAD.ActiveDocument.recompute()
#
cork = FreeCAD.ActiveDocument.addObject("Part::Cylinder","Cylinder")
cork.Label = "Cork"
cork.Radius = neckRadius-1
cork.Height = corkHeight
cork.Placement = FreeCAD.Placement( FreeCAD.Vector(0.0,neckTop-(corkHeight/2),0.0),
FreeCAD.Rotation(FreeCAD.Vector(1,0,0),-90))
cork.ViewObject.ShapeColor=(0.78, 0.65, 0.35, 0.0)
cork.ViewObject.DisplayMode = "Shaded"
#
FreeCADGui.activeDocument().activeView().viewAxometric()
FreeCADGui.SendMsgToActiveView("ViewFit")
FreeCAD.ActiveDocument.recompute()

def createBulkheads(aDictionary):
userAction = None

docKey = findOpenDocumentName(outputWorkspaceB)
print docKey
if docKey!=None:
reply = QtGui.QMessageBox.question(None, "",
"The previous 'Bulkheads' output file is still open, close it",
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No)
if reply == QtGui.QMessageBox.Yes:
FreeCAD.closeDocument(outputWorkspaceB)
else:
userAction = userCancelled

if userAction!=userCancelled:
# bring in values from user dialogue
coachhouseFlag = aDictionary["coachhouseDeckBulkheadsFlag"]
forwardBulkheadsToSkip = aDictionary["forwardBulkheadsToSkip"]
aftBulkheadsToSkip = aDictionary["aftBulkheadsToSkip"]
deckWidth = aDictionary["deckWidth"]
deckThrow = aDictionary["deckThrow"]
coachhouseRise = aDictionary["coachhouseRise"]
coachhouseIncline = aDictionary["coachhouseIncline"]
# set up output workspaces
doc = FreeCAD.newDocument(outputWorkspaceB)
FreeCAD.setActiveDocument(outputWorkspaceB)
FreeCAD.ActiveDocument = FreeCAD.getDocument(outputWorkspaceB)
FreeCADGui.ActiveDocument = FreeCADGui.getDocument(outputWorkspaceB)
for i in range(forwardBulkheadsToSkip,len(crossSections)-aftBulkheadsToSkip):
# add new bulkhead
cs = crossSections[i]
newSketch = FreeCAD.activeDocument().addObject('Sketcher::SketchObject',cs.label)
#place bulkhead along keel
newSketch.Placement = FreeCAD.Placement(
FreeCAD.Vector(cs.xPos,cs.yPos,cs.zPos),
FreeCAD.Rotation(cs.rotQ1,cs.rotQ2,cs.rotQ3,cs.rotQ4))
# insert geometry segments from both half-hulls plus bulkhead into new Sketch
for seg in cs.geometryC:
newSketch.addGeometry(
Part.Line(FreeCAD.Vector(seg.StartPoint.x,
seg.StartPoint.y, 0),
FreeCAD.Vector(seg.EndPoint.x,
seg.EndPoint.y,0)))
FreeCAD.ActiveDocument.recompute()
xMin = cs.xMax * -1
if coachhouseFlag:
# user wants a coachhouse bulkhead
newSketch.addGeometry(
Part.Line( FreeCAD.Vector(xMin, cs.yMax, 0),
FreeCAD.Vector(xMin+deckWidth, cs.yMax+deckThrow, 0)))
FreeCAD.ActiveDocument.recompute()
newSketch.addGeometry(
Part.Line( FreeCAD.Vector(xMin+deckWidth, cs.yMax+deckThrow, 0),
FreeCAD.Vector(xMin+deckWidth+coachhouseIncline, cs.yMax+deckThrow+coachhouseRise, 0)))
FreeCAD.ActiveDocument.recompute()
#
newSketch.addGeometry(
Part.Line( FreeCAD.Vector(xMin+deckWidth+coachhouseIncline, cs.yMax+deckThrow+coachhouseRise, 0),
FreeCAD.Vector(cs.xMax-deckWidth-coachhouseIncline, cs.yMax+deckThrow+coachhouseRise, 0)))
FreeCAD.ActiveDocument.recompute()
# focus at about -800
#newSketch.addGeometry(
# Part.ArcOfCircle(Part.Circle(App.Vector(0.0,-190,0),App.Vector(0,0,1),240.0),1.078868,2.064096))
newSketch.addGeometry(
Part.Line( FreeCAD.Vector(cs.xMax-deckWidth-coachhouseIncline, cs.yMax+deckThrow+coachhouseRise, 0),
FreeCAD.Vector(cs.xMax-deckWidth, cs.yMax+deckThrow, 0)))
FreeCAD.ActiveDocument.recompute()
newSketch.addGeometry(
Part.Line( FreeCAD.Vector(cs.xMax-deckWidth, cs.yMax+deckThrow, 0),
FreeCAD.Vector(cs.xMax, cs.yMax, 0)))
else:
# generate bulkheads for flush deck
newSketch.addGeometry(
Part.Line( FreeCAD.Vector(xMin, cs.yMax, 0),
FreeCAD.Vector(cs.xMax, cs.yMax, 0)))
FreeCAD.ActiveDocument.recompute()
newPad = App.activeDocument().addObject("PartDesign::Pad","Bulkhead")
newPad.Sketch = newSketch
newPad.Length = 1.0
newPad.Sketch.ViewObject.hide()
FreeCAD.ActiveDocument.recompute()
FreeCADGui.SendMsgToActiveView("ViewFit")
FreeCADGui.activeDocument().activeView().viewAxometric()

def createPlaque(aSideFlag, aKeelFlag):
# create plaque to mount half-hull on
# get some dimensions for the plaque based on the size of the hull or half-hull
# note: the X & Y in this routine are to do with the XY of the plaque, not the Sketches
woodColour = (0.53, 0.42, 0.23, 0.0)
# find the overall max & min for X & Y
minusY = crossSections[1].yMin; plusY = crossSections[1].yMin
# get the plaque's Y min & max for the cross-sections (not the stemline or transom)
for i in range(1,len(crossSections)-1):
minusY = min(minusY, crossSections[i].yMin)
plusY = max(plusY, crossSections[i].yMax)
# now allow for the extent of the stemline
minusY = min(minusY, crossSections[0].yMin)
plusY = max(plusY, crossSections[0].yMax)
# get extent of aftmost cross-section and add what the transom sticks out
minusX = crossSections[-2].yPos + crossSections[-1].yMin - crossSections[-1].yMax
# get the placement of the stemline and add what the stemline extends forward
plusX = crossSections[0].yPos + crossSections[0].xMax
# some scaling factors to provide margin space around the half-hull
minusX = minusX * 1.1
plusX = plusX * 1.1
minusY = minusY * 1.5
plusY = plusY * 1.25

ps = FreeCAD.activeDocument().addObject('Sketcher::SketchObject','PlainPlaqueSketch')
ps.Placement = FreeCAD.Placement(FreeCAD.Vector(0.0,0.0,0.0),
FreeCAD.Rotation(0.5,0.5,0.5,0.5))
if aSideFlag==starboardSideFlag: ps.Placement.Base.x = -10
ps.addGeometry(Part.Line(FreeCAD.Vector(minusX,plusY,0),FreeCAD.Vector(plusX,plusY,0)))
ps.addGeometry(Part.Line(FreeCAD.Vector(plusX,plusY,0),FreeCAD.Vector(plusX,minusY,0)))
ps.addGeometry(Part.Line(FreeCAD.Vector(plusX,minusY,0),FreeCAD.Vector(minusX,minusY,0)))
ps.addGeometry(Part.Line(FreeCAD.Vector(minusX,minusY,0),FreeCAD.Vector(minusX,plusY,0)))
#
ps.addConstraint(Sketcher.Constraint('Coincident',0,2,1,1))
ps.addConstraint(Sketcher.Constraint('Coincident',1,2,2,1))
ps.addConstraint(Sketcher.Constraint('Coincident',2,2,3,1))
ps.addConstraint(Sketcher.Constraint('Coincident',3,2,0,1))
ps.addConstraint(Sketcher.Constraint('Horizontal',0))
ps.addConstraint(Sketcher.Constraint('Horizontal',2))
ps.addConstraint(Sketcher.Constraint('Vertical',1))
ps.addConstraint(Sketcher.Constraint('Vertical',3))
FreeCAD.ActiveDocument.recompute()
#
pad = FreeCAD.activeDocument().addObject("PartDesign::Pad","PlainPlaquePad")
pad.Sketch = ps
pad.Length = 10.0
pad.Sketch.ViewObject.hide()
pad.ViewObject.ShapeColor = woodColour
FreeCAD.ActiveDocument.recompute()
#
cyl1 = FreeCAD.ActiveDocument.addObject("Part::Cylinder","Cylinder1")
cyl1.Label = "Cylinder1"
cyl1.Radius = plusY/5
cyl1.Placement = FreeCAD.Placement(FreeCAD.Vector(0,plusX,plusY),
FreeCAD.Rotation(FreeCAD.Vector(0,1,0),90))
if aSideFlag==starboardSideFlag: cyl1.Placement.Base.x = -10
cut1 = FreeCAD.activeDocument().addObject("Part::Cut","Cut1")
cut1.Base = App.activeDocument().PlainPlaquePad
cut1.Tool = App.activeDocument().Cylinder1
cut1.ViewObject.ShapeColor = woodColour
FreeCAD.ActiveDocument.recompute()
#
cyl2 = FreeCAD.ActiveDocument.addObject("Part::Cylinder","Cylinder2")
cyl2.Label = "Cylinder2"
cyl2.Radius = plusY/5
cyl2.Placement = FreeCAD.Placement(FreeCAD.Vector(0,plusX,minusY),
FreeCAD.Rotation(FreeCAD.Vector(0,1,0),90))
if aSideFlag==starboardSideFlag: cyl2.Placement.Base.x = -10
cut2 = FreeCAD.activeDocument().addObject("Part::Cut","Cut2")
cut2.Base = App.activeDocument().Cut1
cut2.Tool = App.activeDocument().Cylinder2
cut2.ViewObject.ShapeColor = woodColour
FreeCAD.ActiveDocument.recompute()
#
cyl3 = FreeCAD.ActiveDocument.addObject("Part::Cylinder","Cylinder3")
cyl3.Label = "Cylinder3"
cyl3.Radius = plusY/5
cyl3.Placement = FreeCAD.Placement(FreeCAD.Vector(0,minusX,minusY),
FreeCAD.Rotation(FreeCAD.Vector(0,1,0),90))
if aSideFlag==starboardSideFlag: cyl3.Placement.Base.x = -10
cut3 = FreeCAD.activeDocument().addObject("Part::Cut","Cut3")
cut3.Base = App.activeDocument().Cut2
cut3.Tool = App.activeDocument().Cylinder3
cut3.ViewObject.ShapeColor = woodColour
FreeCAD.ActiveDocument.recompute()
#
cyl4 = FreeCAD.ActiveDocument.addObject("Part::Cylinder","Cylinder4")
cyl4.Label = "Cylinder4"
cyl4.Radius = plusY/5
cyl4.Placement = FreeCAD.Placement(FreeCAD.Vector(0,minusX,plusY),
FreeCAD.Rotation(FreeCAD.Vector(0,1,0),90))
if aSideFlag==starboardSideFlag: cyl4.Placement.Base.x = -10
cut4 = FreeCAD.activeDocument().addObject("Part::Cut","Cut4")
cut4.Base = App.activeDocument().Cut3
cut4.Tool = App.activeDocument().Cylinder4
cut4.ViewObject.ShapeColor = woodColour
FreeCAD.ActiveDocument.recompute()
#
cham = FreeCAD.ActiveDocument.addObject("Part::Chamfer","Plaque")
cham.Base = FreeCAD.ActiveDocument.Cut4
edges = []
if aSideFlag == starboardSideFlag:
edges.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))
edges.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))
else:
edges.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))
edges.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))
cham.Edges = edges
cham.Base.ViewObject.Visibility = False
cham.ViewObject.ShapeColor = woodColour

createPlaqueCover()
if aSideFlag == starboardSideFlag:
FreeCADGui.activeDocument().activeView().viewRight()
else:
FreeCADGui.activeDocument().activeView().viewLeft()
FreeCADGui.SendMsgToActiveView("ViewFit")
FreeCAD.ActiveDocument.recompute()

def createPlaqueCover():
# get upper bow point UBP
# get upper stern point USP
# get number of sections NS
# divide the line UBP-USP into NS pieces
#---
# for each sketch, get the top point TP
# make segments between each consecutive points
#---
# make RuledSurface between corresponding segments
FreeCAD.zot = crossSections
if len(crossSections)<5:
FreeCAD.Console.PrintMessage("Insufficient cross-sections for plaque cover")
else:
# the number of cross-section and therefore chines determines how many
# segments will be in the cover for the half-hull model
segmentCount = len(crossSections)-2
# determine endpoints for the line segments along the plaque
bowPoint = Base.Vector(0,
max(crossSections[0].geometryS[-1].StartPoint.x, crossSections[0].geometryS[-1].EndPoint.x),
max(crossSections[0].geometryS[-1].StartPoint.y, crossSections[0].geometryS[-1].EndPoint.y))
sternPoint = Base.Vector(0,
crossSections[-2].yPos,
max(crossSections[-2].geometryS[-1].StartPoint.y, crossSections[-2].geometryS[-1].EndPoint.y))
plaquePoints = [bowPoint, sternPoint]
lineAlongPlaqueToSplit = Part.Line(bowPoint,sternPoint)
lapSection = lineAlongPlaqueToSplit.length()/segmentCount

# build a list of the points that start/end the segments
pointList = []
pointList.append(lineAlongPlaqueToSplit.StartPoint)
print lineAlongPlaqueToSplit.StartPoint
for i in range(1, segmentCount):
pointList.append(lineAlongPlaqueToSplit.value((i)*lapSection))
print lineAlongPlaqueToSplit.value((i)*lapSection)
pointList.append(lineAlongPlaqueToSplit.EndPoint)
print lineAlongPlaqueToSplit.EndPoint
print
# iterate the list of points from the first segment to the last
# do stemline first as it is in the YZ plane (cross-sections are in the XZ plane)
a=FreeCAD.ActiveDocument.addObject('Part::Line', 'cs1k')
a.X1=0; a.Y1=pointList[0].y; a.Z1=pointList[0].z
a.X2=0; a.Y2=pointList[1].y; a.Z2=pointList[1].z
b=FreeCAD.ActiveDocument.addObject('Part::Line', 'cs1h')
# B1 wrong
b.X1=0; b.Y1=crossSections[0].endPoint.x; b.Z1=crossSections[0].endPoint.z
b.X2=crossSections[1].endPoint.x; b.Y2=crossSections[1].endPoint.y; b.Z2=crossSections[1].endPoint.z
FreeCAD.ActiveDocument.addObject('Part::RuledSurface', 'coverSeg1')
FreeCAD.ActiveDocument.ActiveObject.Curve1=(a,[''])
FreeCAD.ActiveDocument.ActiveObject.Curve2=(b,[''])
FreeCAD.ActiveDocument.recompute()
# now do cross=sections
for i in range(1, segmentCount):
a=FreeCAD.ActiveDocument.addObject('Part::Line', 'cs'+str(i+1)+'k')
a.X1=0; a.Y1=pointList[i].y; a.Z1=pointList[i].z
a.X2=0; a.Y2=pointList[i+1].y; a.Z2=pointList[i+1].z
b=FreeCAD.ActiveDocument.addObject('Part::Line', 'cs'+str(i+1)+'h')
b.X1=crossSections[i].endPoint.x; b.Y1=crossSections[i].endPoint.y; b.Z1=crossSections[i-1].endPoint.z
b.X2=crossSections[i+1].endPoint.x; b.Y2=crossSections[i+1].endPoint.y; b.Z2=crossSections[i].endPoint.z
FreeCAD.ActiveDocument.addObject('Part::RuledSurface', 'coverSeg'+str(i+1))
FreeCAD.ActiveDocument.ActiveObject.Curve1=(a,[''])
FreeCAD.ActiveDocument.ActiveObject.Curve2=(b,[''])
FreeCAD.ActiveDocument.recompute()
FreeCAD.ActiveDocument.recompute()

def displayChinePanels(crossSectionLabelA, crossSectionLabelB, aSideFlag):
# accept 2 sketch labels and generate a ruled surface between them
#print sketchLabelA
placeholder = "_"
csA = FreeCAD.ActiveDocument.getObjectsByLabel(crossSectionLabelA)[0]
csB = FreeCAD.ActiveDocument.getObjectsByLabel(crossSectionLabelB)[0]
labelA = csA.Label
labelB = csB.Label
lblA = labelA.split('_', 1)[0]
lblB = labelB.split('_', 1)[0]
if aSideFlag == portSideFlag:
sideText = " Port"
elif aSideFlag == starboardSideFlag:
sideText = " Starboard"
else:
sideText = ""
#print str(sketchLabelA) + " " + str(sketchLabelB)
FreeCAD.ActiveDocument.addObject('Part::RuledSurface', placeholder+lblA+placeholder+lblB+sideText)
csObjectA = FreeCAD.ActiveDocument.getObjectsByLabel(crossSectionLabelA)[0]
csObjectB = FreeCAD.ActiveDocument.getObjectsByLabel(crossSectionLabelB)[0]
#print "> " + str(sketchObjectA) + " " + str(sketchObjectB)
FreeCAD.ActiveDocument.ActiveObject.Curve1=(csObjectA,[''])
FreeCAD.ActiveDocument.ActiveObject.Curve2=(csObjectB,[''])

def displayCompleteHull():
userAction = None

docKey = findOpenDocumentName(outputWorkspaceC)
if docKey!=None:
reply = QtGui.QMessageBox.question(None, "",
"The previous 'Complete Hull' output file is still open, close it",
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No)
if reply == QtGui.QMessageBox.Yes:
FreeCAD.closeDocument(outputWorkspaceC)
else:
userAction = userCancelled

if userAction!=userCancelled:
doc = App.newDocument(outputWorkspaceC)
App.setActiveDocument(outputWorkspaceC)
App.ActiveDocument=App.getDocument(outputWorkspaceC)
docComplete = App.ActiveDocument
Gui.ActiveDocument=Gui.getDocument(outputWorkspaceC)
for cs in crossSections:
# add new Sketch object
newSketch = FreeCAD.activeDocument().addObject('Sketcher::SketchObject',cs.label)
newSketch.Placement = FreeCAD.Placement(
FreeCAD.Vector(cs.xPos,cs.yPos,cs.zPos),
FreeCAD.Rotation(cs.rotQ1,cs.rotQ2,cs.rotQ3,cs.rotQ4))
Gui.activeDocument().setEdit(cs.altLabel)
# insert geometry segments from both half-hulls into new Sketch
for seg in cs.geometryC:
newSketch.addGeometry(
Part.Line(FreeCAD.Vector(seg.StartPoint.x,
seg.StartPoint.y, 0),
FreeCAD.Vector(seg.EndPoint.x,
seg.EndPoint.y,0)))
Gui.getDocument(doc.Label).resetEdit()
#print obj.Name + " " + obj.Label
FreeCAD.cs = crossSections # debug statement
for i in range(0, len(crossSections)-1):
displayChinePanels(crossSections[i].altLabel,crossSections[i+1].altLabel, "C")
# now draw the bow sections going to the stemline
#displayChinePanels(crossSections[].altLabel,crossSections[i+1].altLabel, "C")
FreeCAD.activeDocument().recompute()
FreeCADGui.SendMsgToActiveView("ViewFit")
FreeCADGui.activeDocument().activeView().viewAxometric()

def displayHalfHull(aSideFlag):
userAction = None
# create output workspace for one side
if aSideFlag == starboardSideFlag:
query = "The previous 'Port Half-Hull' output file is still open, close it"
selectedOutputWorkspace = outputWorkspaceS
outputWorkspace = outputWorkspaceS
sideFlag = starboardSideFlag
else:
query = "The previous 'Starboard Half-Hull' output file is still open, close it"
selectedOutputWorkspace = outputWorkspaceP
outputWorkspace = outputWorkspaceP
sideFlag = portSideFlag

docKey = findOpenDocumentName(selectedOutputWorkspace)
if docKey==None:
doc = FreeCAD.newDocument(selectedOutputWorkspace)
else:
reply = QtGui.QMessageBox.question(None, "",
query,
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No)
if reply == QtGui.QMessageBox.Yes:
FreeCAD.closeDocument(selectedOutputWorkspace)
doc = FreeCAD.newDocument(selectedOutputWorkspace)
else:
userAction = userCancelled

if userAction!=userCancelled:
FreeCAD.setActiveDocument(outputWorkspace)
FreeCAD.ActiveDocument=FreeCAD.getDocument(outputWorkspace)
FreeCADGui.ActiveDocument=FreeCADGui.getDocument(outputWorkspace)
# place the segments in the document
for cs in crossSections:
# add new Sketch object
FreeCAD.activeDocument().addObject('Sketcher::SketchObject',cs.label)
newSketch = FreeCAD.ActiveDocument.getObject(cs.altLabel)
newSketch.Placement = FreeCAD.Placement(
FreeCAD.Vector(cs.xPos,cs.yPos,cs.zPos),
FreeCAD.Rotation(cs.rotQ1,cs.rotQ2,cs.rotQ3,cs.rotQ4))
Gui.activeDocument().setEdit(cs.altLabel)
# insert geometry segments into new Sketch
if sideFlag == "S":
geom = cs.geometryS
else:
geom = cs.geometryP
for seg in geom:
newSketch.addGeometry(
Part.Line(FreeCAD.Vector(seg.StartPoint.x,
seg.StartPoint.y, 0),
FreeCAD.Vector(seg.EndPoint.x,
seg.EndPoint.y,0)))
Gui.getDocument(doc.Label).resetEdit()
for i in range(0, len(crossSections)-1):
displayChinePanels(crossSections[i].altLabel,crossSections[i+1].altLabel, sideFlag)
FreeCAD.activeDocument().recompute()
FreeCADGui.SendMsgToActiveView("ViewFit")
FreeCADGui.activeDocument().activeView().viewAxometric()

def eqRotation(rotationA, rotationB, eps=0.0001):
"takes 2 Rotations and compares for equality"
eqFlag = True
for i in range(0, 4):
#print str(rotationA.Q[i]) + "#" + str(rotationB.Q[i])
if rotationA.Q[i] == 0:
if rotationB.Q[i] <> 0:
eqFlag = False
elif abs(abs(rotationA.Q[i])-abs(rotationB.Q[i]))/abs(rotationA.Q[i]) > eps:
eqFlag = False
return eqFlag

def resetSketchesVisibility():
# set Visibility on all Sketches to False
openWindows = list()
if starboardHHFlag:
openWindows.append(outputWorkspaceS)
if portHHFlag:
openWindows.append(outputWorkspaceP)
if completeHullFlag:
openWindows.append(outputWorkspaceC)
#if fullHullBulkheadsFlag:
#openWindows.append(outputWorkspaceB)

for ws in openWindows:
FreeCAD.setActiveDocument(ws)
FreeCAD.ActiveDocument=FreeCAD.getDocument(ws)
FreeCADGui.ActiveDocument=FreeCADGui.getDocument(ws)
for obj in FreeCAD.ActiveDocument.Objects:
if obj.TypeId == 'Sketcher::SketchObject':
vo = FreeCADGui.ActiveDocument.getObject(obj.Name)
vo.Visibility=False

def sortOutFilesAndDocuments():
global keepSourceOpenFlag
# this routine uses the following variables from the main handler:
# docSrc (returns)
# fileName (reads)
# keepSourceOpenFlag (global, writes)
# it determines if the 'user selected input document' is already open,
# if it is then is is made the ActiveDocument, otherwise it is
# Opened which also sets it to the ActiveDocument
if len(FreeCAD.listDocuments())==0:
# no documents open
return FreeCAD.open(fileName)
else:
# some document(s) open so check if 'user selected input document' is already open
"""docKey = None
for key in FreeCAD.listDocuments():
if FreeCAD.listDocuments()[key].FileName==fileName:
docKey = key"""
docKey = findOpenDocumentFileSpec(fileName)
if docKey==None:
# 'user selected input document' is not open
return FreeCAD.open(fileName)
else:
# 'user selected input document' is among open documents
# set the 'user selected input document' to the active document (in case it isn't)
FreeCAD.setActiveDocument(docKey)
# user started with 'user selected input document' open, so this flag will allow
# us to leave it open when we finish
keepSourceOpenFlag = True
return FreeCAD.ActiveDocument

def findOpenDocumentFileSpec(aDocumentFileSpec):
# check if supplied document is already open
# return document name or None
docKey = None
for key in FreeCAD.listDocuments():
if FreeCAD.listDocuments()[key].FileName==aDocumentFileSpec:
docKey = key
return docKey
def findOpenDocumentName(aDocumentName):
# check if supplied document is already open
# return document name or None
docKey = None
for key in FreeCAD.listDocuments():
if FreeCAD.listDocuments()[key].Name==aDocumentName:
docKey = key
return docKey
# Constant definitions
outputWorkspaceS = "hull_starboard"
outputWorkspaceP = "hull_port"
outputWorkspaceC = "hull_complete"
outputWorkspaceB = "bulkheads"
xyPlane = Base.Rotation(0.0, 0.0, 0.0, 1.0) # transom
xzPlane = Base.Rotation(0.7071067811865475, 0.0, 0.0, 0.7071067811865476) # cross section profile
yzPlane = Base.Rotation(0.5,0.5,0.5,0.5) # stemline
infinity = +99999999999999.9 # will hold min Y value in Sketch
infinityNegative = -99999999999999.9 # will hold max X value in Sketch
global starboardSideFlag, portSideFlag, userCancelled, userLastFile, userOK
starboardSideFlag = "S"
portSideFlag = "F"
completeSidesFlag = "C"
userCancelled = "Cancelled"
userLastFile = "Last File"
userOK = "OK"
defaultDir = FreeCAD.ConfigGet("UserHomePath")

# code ***********************************************************************************
allCrossSections = {}
crossSections = list()
docSrc = None
global keepSourceOpenFlag
keepSourceOpenFlag = False
starboardHHFlag = False; starboardHHPlaqueFlag = False; starboardHHPKeelFlag = False
portHHFlag = False; portHHPlaqueFlag = False; portHHPKeelFlag = False
completeHullFlag = False; completeHullBottleFlag = False; completeHullKeelFlag = False
bulkheadsFlag = False; flushDeckBulkheadsFlag = True; coachhouseDeckBulkheadsFlag = True

form = GetConfigParams()
form.exec_()
configParams = form.configParams

if configParams.result==userLastFile:
if hasattr(FreeCAD,"MacroHalfHullConfigParams"):
# global in FreeCAD exists so use the parameters stored there
#if type(FreeCAD.MacroHalfHullConfigParams)=='GetConfigParams':
configParams = FreeCAD.MacroHalfHullConfigParams
configParams.result = userLastFile
else:
# user requested to re-use last file but there isn't one
# so reset the choice to pick a file
configParams.result = userOK
if configParams.result != userCancelled:
# transfer results to control flags
starboardHHFlag = configParams.cb1a
starboardHHPlaqueFlag = configParams.cb1b
starboardHHPKeelFlag = configParams.cb1c
portHHFlag = configParams.cb2a
portHHPlaqueFlag = configParams.cb2b
portHHPKeelFlag = configParams.cb2c
completeHullFlag = configParams.cb3a
completeHullBottleFlag = configParams.cb3b
completeHullKeelFlag = configParams.cb3c
bulkheadsFlag = configParams.cb4a
# transfer bulkhead parameters
bulkheadParams = {}
bulkheadParams["coachhouseDeckBulkheadsFlag"] = configParams.rb5b
bulkheadParams["forwardBulkheadsToSkip"] = int(configParams.skipAtBow)
bulkheadParams["aftBulkheadsToSkip"] = int(configParams.skipAtStern)
bulkheadParams["deckWidth"] = float(configParams.deckWidth.text())
bulkheadParams["deckThrow"] = float(configParams.deckThrow.text())
bulkheadParams["coachhouseRise"] = float(configParams.coachhouseRise.text())
bulkheadParams["coachhouseIncline"] = float(configParams.coachhouseIncline.text())
defaultDir = expanduser("~")
defaultDir = "/Data Pool/Coding/FreeCAD/work items/hull mirroring/half-hull/"
if configParams.result==userOK:
# user wants to select file
fileName = QtGui.QFileDialog.getOpenFileName(dir=defaultDir, caption = "Select a 'Hull Profile' to Load", filter="*.FCStd")[0]
configParams.documentFileName = fileName
else:
# file is coming out of FreeCAD global
fileName = FreeCAD.MacroHalfHullConfigParams.documentFileName

if len(fileName) != 0:
docSrc = sortOutFilesAndDocuments()
# read all the objects, saving the Sketcher objects
for obj in FreeCAD.ActiveDocument.Objects:
if obj.TypeId == 'Sketcher::SketchObject':
# ignore anything except Sketches
newObj = HullCrossSection(obj)
if newObj.transomFlag:
# if we have the transom sketch then wait to give
# it a placement further aft than anything else
transomObject = newObj
elif newObj.stemlineFlag:
# if we have the stemline sketch then wait
# to give it the first placement
stemlineObject = newObj
stemlineSegmentCount = stemlineObject.sketch.GeometryCount
else:
# must be a regular cross section profile
# so add object to our collection
allCrossSections[newObj.key] = newObj
#maxY = max(maxY, newObj.yPos)

# discard sketches with wrong number of points
# i.e. cross-sections that have a different number
# of points than the stemline
for key, cs in allCrossSections.items():
if cs.geometryCount <> stemlineSegmentCount:
FreeCAD.Console.PrintMessage("Discard for wrong number of segments for '" + str(allCrossSections[key].label) + "'\n")
del allCrossSections[key]
# construct a list with cross sections in order from stemline to transom
crossSections.append(stemlineObject)
for sk in sorted(allCrossSections.keys(), reverse=True):
crossSections.append(allCrossSections[sk])
transomObject.zPos = crossSections[-1].zPos+crossSections[-1].yMax
crossSections.append(transomObject)

FreeCAD.cs = crossSections # debug statement
# now set the transom elevation at the top of the last cross-section
crossSections[-1].zPos = crossSections[-2].zPos + crossSections[-2].yMax
FreeCAD.cs = crossSections # debug statement

# depending on user flags, invoke appropriate modules
if starboardHHFlag: displayHalfHull(starboardSideFlag)
if starboardHHPlaqueFlag: createPlaque(starboardSideFlag, starboardHHPKeelFlag)
if portHHFlag: displayHalfHull(portSideFlag)
if portHHPlaqueFlag: createPlaque(portSideFlag, portHHPKeelFlag)
if completeHullFlag: displayCompleteHull()
if completeHullBottleFlag: createBottle(completeHullKeelFlag)
if bulkheadsFlag: createBulkheads(bulkheadParams)

# save Config Params to FreeCAD global in case user wants to use it next run
FreeCAD.MacroHalfHullConfigParams = configParams
if not keepSourceOpenFlag:
FreeCAD.closeDocument(docSrc.Name)
resetSketchesVisibility()
}}

Revision as of 08:58, 16 February 2015