展開図を作るスクリプト
久しぶりの投稿です。YouTubeで投稿していたVectorworksの展開図を作るスクリプトのサンプルです。
サンプルなのでエラーとか出る可能性があります。通り芯はレコードの設定を手動で行う必要があります。仕上げのオブジェクトはvso(VectorScriptObject)なのでスクリプトの他の設定が必要で今回は省いています。
通り芯とレコードの設定
通り芯を認識するためにレコードの設定が必要です。
レコード名:通り芯
レコードフィールド名:通し番号(テキストタイプ)
レコード値に記号として入力
展開図作成後
スクリプト
実際はまとまっていないですが、一区切りとして。ご質問があればコメントください。
import vs
import math
def elvDialog():#ダイアログの設定
kOK = 1
kCANCEL = 2
kSETUPDIALOG = 12255
def create_dialog():
dialog = vs.CreateLayout('選択した多角形から展開図を作成します', False, 'OK', 'キャンセル')
vs.CreateStaticText( dialog, 5, '展開図の向きを選んでください。', 40 )
vs.SetFirstLayoutItem( dialog, 5 )
vs.CreateRadioButton(dialog, 10, '両方')
vs.SetBelowItem(dialog, 5,10,5,2)
vs.CreateRadioButton(dialog, 20, '内側')
vs.SetRightItem(dialog, 10, 20, 0, 0)
vs.CreateRadioButton(dialog, 30, '外側')
vs.SetRightItem(dialog, 20, 30, 0, 0)
vs.CreateStaticText( dialog, 40, '壁の高さ:', 10 )
vs.SetBelowItem(dialog, 10,40,3,2)
vs.CreateEditReal(dialog, 45, 1, 3000, 16)
vs.SetRightItem(dialog, 40,45,0,0)
vs.CreateStaticText( dialog, 50, '巾木高さ:', 10 )
vs.SetBelowItem(dialog, 40,50,0,0)
vs.CreateEditReal(dialog, 55, 1, 100, 16)
vs.SetRightItem(dialog, 50,55,0,0)
vs.CreateDesignLayerPullDownMenu(dialog, 60, 20)
vs.SetBelowItem(dialog, 50,60,0,5)
return dialog
def dialog_handler(item,data):
if item == kOK:
elvDialog.both = vs.GetBooleanItem(dialog, 10)
elvDialog.inside = vs.GetBooleanItem(dialog, 20)
elvDialog.outside = vs.GetBooleanItem(dialog, 30)
elvDialog.boo , elvDialog.wallH = vs.GetEditReal(dialog, 45, 1)
elvDialog.boo , elvDialog.habakiH = vs.GetEditReal(dialog, 55, 1)
elvDialog.outIndex , elvDialog.outText = vs.GetSelectedChoiceInfo(dialog, 60, 0)
elif item == kCANCEL:
pass
elif item == kSETUPDIALOG:
vs.SetBooleanItem(dialog, 10, False)
vs.SetBooleanItem(dialog, 20, True) #普通
vs.SetBooleanItem(dialog, 30, False)
return item
dialog = create_dialog()
result = False
elvDialog.both = False
elvDialog.inside = False
elvDialog.outside = False
elvDialog.wallH = 2700
elvDialog.habakiH = 100
elvDialog.outIndex = 0
elvDialog.outText = ''
if vs.RunLayoutDialog( dialog, dialog_handler ) == kOK:
result = True
return result , elvDialog.both , elvDialog.inside , elvDialog.outside , elvDialog.wallH , elvDialog.habakiH , elvDialog.outIndex , elvDialog.outText
def setElvRecord(field):
vs.SetRecord(vs.LNewObj(), '展開')
vs.SetRField(vs.LNewObj(), '展開', field ,True)
def getPioRecord(hand,fieldNo):
hrecdef = vs.GetParametricRecord(hand)
recname = vs.GetName(hrecdef)
hrec = vs.GetObject(recname)
fld = vs.GetFldName(hrec,fieldNo)
word = vs.GetRField(hand, recname, fld)
return word
def dimAdjust(hand):
vs.SetObjectVariableBoolean(hand, 7, True)
vs.SetObjectVariableBoolean(hand, 8, True)
vs.SetObjectVariableReal(hand, 43, 5)
vs.SetObjectVariableInt(hand, 1235, 1)
vs.ResetObject(hand)
def createPoly(pList):
vs.BeginPoly()
for p in pList:
vs.AddPoint(p)
vs.EndPoly()
def getAttr(hand):
attrDict = {}
fillType = vs.GetObjectVariableInt(hand, 696)
boo , fillName = vs.GetVectorFill(hand)
fillpat = vs.GetFPat(hand)
attrDict['タイプ'] = fillType
attrDict['パターン'] = fillpat
attrDict['リソース'] = boo
if boo == False:
fillName = None
attrDict['名前'] = fillName
red,green,blue = vs.GetFillFore(hand)
color = vs.RGBToColorIndex(red, green, blue)
attrDict['面前RGB'] = [red,green,blue]
attrDict['面前色'] = color
red,green,blue = vs.GetFillBack(hand)
color = vs.RGBToColorIndex(red, green, blue)
attrDict['面後RGB'] = [red,green,blue]
attrDict['面後色'] = color
boo,penOpa,fillOpa = vs.GetOpacityN(hand)
attrDict['面透明'] = fillOpa
red,green,blue = vs.GetPenFore(hand)
color = vs.RGBToColorIndex(red, green, blue)
attrDict['線RGB'] = [red,green,blue]
attrDict['線色'] = color
attrDict['線透明'] = penOpa
lineWide = vs.GetLW(hand)
lineStyle = vs.GetLSN(hand)
attrDict['線幅'] = lineWide
attrDict['ラインタイプ'] = lineStyle
return attrDict
def getDirection(hand):
num = vs.GetVertNum(hand)
pList = []
pxList = []
pyList = []
for i in range(1,num+1):
p = vs.GetPolyPt(hand, (i))
pList.append(p)
pxList.append(p[0])
pyList.append(p[1])
rightNo = pxList.index(min(pxList))
leftNo = pxList.index(max(pxList))
topNo = pyList.index(max(pyList))
bottomNo = pyList.index(min(pyList))
if rightNo == num -1:
v = (pxList[0] - pxList[rightNo-1]),(pyList[0] - pyList[rightNo-1])
else:
v = (pxList[rightNo+1] - pxList[rightNo-1]),(pyList[rightNo+1] - pyList[rightNo-1])
if v[1] > 0:
direction = 'clock'
else:
direction = 'unclock'
pList.reverse()
return direction , pList
def createMark(x,y,mark,angle):
scale = vs.GetLScale(vs.ActLayer())
a = 15 * scale
vs.BeginGroup()
vs.PushAttrs()
vs.BeginPoly()
vs.AddPoint(x-(3*scale),y+a)
vs.AddPoint(x,y-(4*scale)+a)
vs.AddPoint(x+(3*scale),y+a)
vs.AddPoint(x-(3*scale),y+a)
vs.EndPoly()
vs.SetFillBack(vs.LNewObj(), 65535)
vs.ArcByCenter(x, y+a, (2*scale), 0, 360)
vs.MoveTo(x,y+a)
vs.TextSize(6)
vs.TextJust(2)
vs.TextVerticalAlign(3)
vs.CreateText(mark)
vs.PopAttrs()
vs.EndGroup()
p = x,y
vs.HRotate(vs.LNewObj(),p,(angle + 180))
def getElvdata(roomH,bango):#通り芯と仕上げの場所をゲットする
def callbackCore(coreH):
p3 = vs.GetSegPt1(coreH)
p4 = vs.GetSegPt2(coreH)
parallel,boo,crossPt = vs.LineLineIntersection(p1, p2, p3, p4)
if boo == True:
core = vs.GetRField(coreH, '通り芯', '通し番号')
coreDist = round(vs.Distance(crossPt[0],crossPt[1],p1[0],p1[1]),2)
dict[core] = coreDist
vs.Locus(crossPt)
def callbackFinish(finishH):
#p1,p2 は展開図のベースのライン
finishDict = getAttr(finishH)
finishSt = vs.GetSegPt2(finishH)
finishEd = vs.GetSegPt1(finishH)
booSt = vs.PtOnLine(finishSt , p1, p2, 0.1)
booEd = vs.PtOnLine(finishEd , p1, p2, 0.1)
v1 = (p2[0]-p1[0],p2[1]-p1[1],0)
v2 = (finishSt[0]-finishEd[0],finishSt[1]-finishEd[1],0)
if (booSt == True) and (booEd == True) and (vs.AngBVec(v1, v2)) == 180 :
finishDict['記号'] = vs.GetRField(finishH, '仕上げ情報', '記号')
finishDict['仕上げ'] = vs.GetRField(finishH, '仕上げ情報', '仕上げ')
finishDict['品番・仕様'] = vs.GetRField(finishH, '仕上げ情報', '品番・仕様')
finishDict['メーカー'] = vs.GetRField(finishH, '仕上げ情報', 'メーカー')
finishDict['下地'] = vs.GetRField(finishH, '仕上げ情報', '下地')
finishDict['始点'] = round(vs.Distance(finishSt[0],finishSt[1],p1[0],p1[1]),2)
finishDict['終点'] = round(vs.Distance(finishEd[0],finishEd[1],p1[0],p1[1]),2)
finishList.append(finishDict)
if vs.GetTypeN(roomH) == 2:
num = 1
p1 = vs.GetSegPt1(roomH)
p2 = vs.GetSegPt2(roomH)
vs.MoveTo(p1)
vs.LineTo(p2)
hand = vs.LNewObj()
vs.SetRecord(hand, '展開図')
vs.SetRField(hand, '展開図', '名前',('展開図' + chr(64 + int(bango))))
#vs.AlrtDialog(str(p1))
else:
num = vs.GetVertNum(roomH)
#直線を引いて、展開図のレコードを作る
for i in range(1,num+1):
p1 = vs.GetPolyPt(roomH, (i))
p2 = vs.GetPolyPt(roomH, (i+1))
if i == num:
p2 = vs.GetPolyPt(roomH,1)
vs.MoveTo(p1)
vs.LineTo(p2)
hand = vs.LNewObj()
vs.SetRecord(hand, '展開図')
vs.SetRField(hand, '展開図', '名前',('展開図' + chr(64 + int(bango))))
bango += 1
vs.DSelectAll()
countElv = int(vs.Count("((R IN ['展開図']))"))
if countElv != 0:
vs.SelectObj("(R IN ['展開図'])")
elvList = []
dict = {}
finishList = []
elvdata = {}
elvH = vs.FSActLayer()
for elv in range(countElv):
p1 = vs.GetSegPt1(elvH)
p2 = vs.GetSegPt2(elvH)
#名前
name = vs.GetRField(elvH, '展開図', '名前')
elvdata['名前'] = name
#壁の長さ
dist = vs.Distance(p2[0],p2[1],p1[0],p1[1])
elvdata['壁長'] = dist
#展開図の壁の高さを取得
#展開図の巾木の高さを取得
#仕上げ
countFinish = vs.Count( "(PON='#finishLine')")
finishList = []
if countFinish !=0:
vs.ForEachObject(callbackFinish, "(PON='#finishLine')")
elvdata['仕上げ'] = finishList
finishList = []
#通り芯との交点を把握
countCore = vs.Count("((R IN ['通り芯']) & (T=LINE))")
if countCore != 0:
vs.ForEachObject(callbackCore, "((R IN ['通り芯']) & (T=LINE))")
elvdata['通り芯'] = dict
dict = {}
elvList.append(elvdata)
elvdata = {}
#凡例
angle = vs.HAngle(elvH)
createMark((p1[0]+p2[0])/2,(p1[1]+p2[1])/2,name.replace('展開図',''),angle)
setElvRecord('記号')
elvH = vs.NextSObj(elvH)
vs.DSelectAll()
vs.SelectObj("(R IN ['展開図'])")
vs.DeleteObjs()
return elvList , bango
def createElv(elvList,wallH,habakiH,lscale):
def textNoSet(coreNo):
vs.PushAttrs()
vs.TextJust(2)
vs.TextVerticalAlign(5)
vs.BeginGroup()
vs.CreateText(str(coreNo))
p1,p2 = vs.GetBBox(vs.LNewObj())
center = vs.HCenter(vs.LNewObj())
rad = vs.Distance(center[0], center[1], p1[0], p1[1])
vs.ArcByCenter(center[0], center[1],rad, 0, 360)
vs.SetFPat(vs.LNewObj(), 0)
vs.EndGroup()
vs.PopAttrs()
vs.PushAttrs()
def createAnno(hand):#handは四角形
vs.PushAttrs()
vs.FillPat(0)
layerScale = vs.GetLScale(vs.ActLayer())
hAng = 60
length = 20 * layerScale
centerP = vs.HCenter(hand)
uuid = vs.GetObjectUuid(hand)
heigh = vs.HHeight(hand) * 0.35
objectHand = vs.CreateCustomObjectN('#Leader',centerP,hAng,False)
vs.SetRField(objectHand, '#Leader','LineLength', length)
vs.SetRField(objectHand, '#Leader','target', str(uuid))
word = vs.GetRField(hand,'仕上げ情報','仕上げ')
if vs.GetRField(hand,'仕上げ情報','品番・仕様') != '':
word = vs.GetRField(hand,'仕上げ情報','仕上げ') + '(' + vs.GetRField(hand,'仕上げ情報','品番・仕様') + ')'
vs.SetRField(objectHand, '#Leader','finishName', str(word))
word = vs.GetRField(hand,'仕上げ情報','下地')
vs.SetRField(objectHand, '#Leader','baseName', str(word))
vs.HMove(objectHand, 0, heigh)
vs.ResetObject(objectHand)
vs.PopAttrs()
def callbackGetPt(hand):
p1,p2 = vs.GetBBox(hand)
ptxList.append(int(p2[0]))
ptyList.append(int(p2[1]))
vs.PushAttrs()
vs.TextJust(1)
vs.TextVerticalAlign(1)
vs.TextSize(8)
paperTop = 20 * lscale
paperBot = 20 * lscale
paperLeft = 30 * lscale
paperRight = 30 * lscale
pPaperSt,pPaperEd = vs.GetDrawingSizeRect()
paperVert = abs(pPaperEd[1]-pPaperSt[1])
limitX = abs(pPaperEd[0] - pPaperSt[0]) - (paperLeft + paperRight)
limitY = abs(pPaperEd[1] - pPaperSt[1]) - (paperTop + paperBot)
totalX = 0
high = wallH
countFlame = int(vs.Count("((R IN ['展開図枠']))"))
if countFlame != 0:
ptxList = []
ptyList = []
vs.ForEachObject(callbackGetPt,"(R IN ['展開図枠'])")
pyMin = min(ptyList) - (20 * lscale)
nowVert = abs(pyMin - pPaperSt[1])
div , mod = nowVert // paperVert , nowVert % paperVert #商 , 余り
pElvSt = (pPaperSt[0] + (paperLeft) , pyMin - (lscale * 10) )
paperCount = div + 1
totalY = high + mod
if totalY > limitY:
pElvSt = (pPaperSt[0] + (paperLeft) , pPaperSt[1] - (paperTop) - (paperCount * paperVert))
paperCount += 1
totalY = (high)
#-----------------------------
else:
pElvSt = (pPaperSt[0] + (paperLeft) , pPaperSt[1] - (paperTop) )
paperCount = 1
totalY = high
for index,elvdata in enumerate(elvList):
#展開図の情報
name = elvdata['名前']
wide = elvdata['壁長']
core = elvdata['通り芯']
finishList = elvdata['仕上げ']
#high = wallH + habakiH
flameX = wide + (lscale * 40)
flameY = high + (lscale * 50)
# 展開図を書く位置
totalX += flameX
if (totalX > limitX) and index !=0 :
totalY += flameY
totalX = wide
pElvSt = (pPaperSt[0] + (paperLeft) , pElvSt[1] - (high + (lscale * 50)))
if totalY > limitY:
pElvSt = (pPaperSt[0] + (paperLeft) , pPaperSt[1] - (paperTop) - (paperCount * paperVert))
paperCount += 1
totalY = (high)
# 展開図の名前を書く
pName = (pElvSt[0],pElvSt[1])
vs.MoveTo(pName)
vs.CreateText(str(name))
pBox1,pBox2 = vs.GetBBox(vs.LNewObj())
setElvRecord('名前')
vs.Rect(pBox1,pBox2)
vs.SetFPat(vs.LNewObj(), 0)
setElvRecord('名前')
# 展開図の枠を書く
pFlameSt = (pElvSt[0] , pElvSt[1] - (20 * lscale))
pFlameEd = (pElvSt[0] + wide , pFlameSt[1] - high)
vs.Rect(pFlameSt,pFlameEd)
vs.SetName(vs.LNewObj(), name)
vs.SetRecord(vs.LNewObj(), '展開図枠')
vs.SetRField(vs.LNewObj(), '展開図枠', '番号',(name.replace('展開図', '')))
setElvRecord('枠')
# 展開図の寸法を書く
pFlameDimSt = (pFlameSt[0] , pFlameSt[1]-high)
pFlameDimEd = (pFlameEd[0] , pFlameEd[1])
vs.LinearDim(pFlameDimSt, pFlameDimEd , -20 * (lscale) , 0 , 1, 1, -100) # 横寸法
dimAdjust(vs.LNewObj())
setElvRecord('寸法')
vs.LinearDim(pFlameSt, pFlameDimSt , -10 * (lscale) , 1 , 1, 1, -100) # 縦寸法
dimAdjust(vs.LNewObj())
setElvRecord('寸法')
pWallDim = (pFlameSt[0],pFlameDimSt[1] + habakiH)
vs.LinearDim(pFlameSt, pWallDim , -5 * (lscale) , 1 , 1, 1, -100) # 壁高さ
dimAdjust(vs.LNewObj())
setElvRecord('寸法')
vs.LinearDim(pWallDim, pFlameDimSt , -5 * (lscale) , 1 , 1, 1, -100) # 壁高さ
dimAdjust(vs.LNewObj())
setElvRecord('寸法')
# 展開図の仕上げを書く
pFinishSt = pElvSt
for finishDict in finishList:
pFinishSt = (pFlameSt[0] + finishDict['始点'] , pFlameSt[1])
pFinishEd = ( (pFinishSt[0] + (finishDict['終点']-finishDict['始点']) , pFinishSt[1] - wallH) )
vs.Rect(pFinishSt , pFinishEd)
vs.SetRecord(vs.LNewObj(), '仕上げ情報')
vs.SetRField(vs.LNewObj(), '仕上げ情報', '記号',finishDict['記号'] )
vs.SetRField(vs.LNewObj(), '仕上げ情報', '仕上げ',finishDict['仕上げ'])
vs.SetRField(vs.LNewObj(), '仕上げ情報', '品番・仕様',finishDict['品番・仕様'])
vs.SetRField(vs.LNewObj(), '仕上げ情報', 'メーカー',finishDict['メーカー'])
vs.SetRField(vs.LNewObj(), '仕上げ情報', '下地',finishDict['下地'] )
vs.SetOpacityN(vs.LNewObj(), finishDict['線透明'], finishDict['面透明'])
if finishDict['リソース'] == True:
result = vs.Name2Index(finishDict['名前'])
vs.SetObjectVariableLongInt (vs.LNewObj(),695,result * -1)
else:
if finishDict['タイプ'] == 1:
vs.SetFPat(vs.LNewObj(), 0)
elif finishDict['タイプ'] == 2:
vs.SetFPat(vs.LNewObj(), 1)
vs.SetFillBack(vs.LNewObj(), finishDict['面後色'])
elif finishDict['タイプ'] == 3:
vs.SetFPat(vs.LNewObj(),finishDict['パターン'])
vs.SetFillFore(vs.LNewObj(), finishDict['面前色'])
vs.SetFillBack(vs.LNewObj(), finishDict['面後色'])
setElvRecord('壁')
# 仕上げの注釈を書く
createAnno(vs.LNewObj())
setElvRecord('注釈')
# 仕上げの寸法を書く
pFinishDimSt = (pFinishSt[0],pFinishSt[1]-high)
pFinishDimEd = (pFinishEd[0],pFinishSt[1]-high)
vs.LinearDim(pFinishDimSt, pFinishDimEd , -8 * (lscale) , 0 , 1, 1, -100)
dimAdjust(vs.LNewObj())
setElvRecord('寸法')
pFinishSt = (pFinishSt[0] + finishDict['終点'] , pFinishSt[1])
coreDistList = []
# 展開図の通り芯を書く
for coreNo,coreDist in core.items():
pCoreSt = (pFlameSt[0] + coreDist,pFlameSt[1] + (10*lscale))
pCoreEd = (pFlameSt[0] + coreDist,pFlameSt[1] - high - (10*lscale))
vs.MoveTo(pCoreSt[0],pCoreSt[1])
textNoSet(coreNo)
setElvRecord('通り芯')
vs.LineTo(pCoreEd[0],pCoreEd[1])
setElvRecord('通り芯')
coreDistList.append(coreDist)
coreDistList.append(wide)
coreDistList.sort()
pCoreDimSt = (pFlameSt[0],pFlameSt[1]- high)
coreBefore = 0
# 通り芯の寸法を書く
for coreDist in coreDistList:
pCoreDimEd = (pCoreDimSt[0] + coreDist - coreBefore ,pCoreDimSt[1])
vs.LinearDim(pCoreDimSt, pCoreDimEd , -15 * (lscale) , 0 , 1, 1, -100)
dimAdjust(vs.LNewObj())
setElvRecord('寸法')
pCoreDimSt = pCoreDimEd
coreBefore = coreDist
pHabakiSt = (pElvSt[0] , pFlameEd[1] + habakiH)
pHabakiEd = (pElvSt[0] + wide , pFlameEd[1])
vs.Rect(pHabakiSt,pHabakiEd)
setElvRecord('巾木')
pElvSt = (pElvSt[0]+ wide + (lscale * 30) , pElvSt[1])
vs.DSelectAll()
vs.PopAttrs()
result , both , inside , outside , wallH, habakiH ,outIndex , outText = elvDialog()
vs.NewField('展開','枠','False',2,0)
vs.NewField('展開','名前','False',2,0)
vs.NewField('展開','壁','False',2,0)
vs.NewField('展開','巾木','False',2,0)
vs.NewField('展開','注釈','False',2,0)
vs.NewField('展開','寸法','False',2,0)
vs.NewField('展開','記号','False',2,0)
vs.NewField('展開','通り芯','False',2,0)
vs.NewField('展開図','名前','',4,0)
vs.NewField('展開図枠','番号','',4,0)
if result == False:
pass
else:
selCount = int(vs.Count("((V) & (SEL=TRUE))"))
selH = vs.FSActLayer()
targetList = []
for id in range(selCount):
uuid = vs.GetObjectUuid(selH)
targetList.append(uuid)
selH = vs.NextSObj(selH)
delList = []
baseList = []
for uuid in targetList: # 選択図形のタイプを選択
selH = vs.GetObjectByUuid(uuid)
if vs.GetTypeN(selH) == 3 or vs.GetTypeN(selH) == 5:
if vs.GetTypeN(selH) == 3: #四角形を変換
selH = vs.ConvertToPolygon(selH,0)
delUuid = vs.GetObjectUuid(selH)
delList.append(delUuid)
else:
pass
direction , pList = getDirection(selH)
if ((outside == True) and (direction =='clock')) or (inside == True) and (direction =='unclock'):
createPoly(pList)
selH = vs.LNewObj()
delUuid = vs.GetObjectUuid(selH)
delList.append(delUuid)
baseUuid = vs.GetObjectUuid(selH)
baseList.append(baseUuid)
if both == True:
createPoly(pList)
delUuid = vs.GetObjectUuid(vs.LNewObj())
delList.append(delUuid)
baseUuid = vs.GetObjectUuid(vs.LNewObj())
baseList.append(baseUuid)
elif vs.GetTypeN(selH) == 2:
baseUuid = vs.GetObjectUuid(selH)
baseList.append(baseUuid)
else:
pass
elvList = []
countFlame = int(vs.Count("((R IN ['展開図枠']))"))
bango = countFlame + 1
for id in baseList:
hand = vs.GetObjectByUuid(id)
elvList1,bango = getElvdata(hand,bango)
elvList = elvList + elvList1
if outIndex != 0:
vs.Layer(str(outText))
lscale = vs.GetLScale(vs.ActLayer())
createElv(elvList,wallH,habakiH,lscale)
for id in delList:
hand = vs.GetObjectByUuid(id)
vs.DelObject(hand)
vs.ReDraw()
vs.AlrtDialog('展開図を作成しました。' + vs.Chr(13) + '展開図の向きを確認ください。' )