User:Renatorivo: Difference between revisions
Renatorivo (talk | contribs) (Macro Half Hull) |
Renatorivo (talk | contribs) (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() |
|||
}} |