Jump to content

Scripting Massing Models


Recommended Posts

I found my error but can't see how to delete this topic

 

My eventual goal is to build a set of massing models based on polygons with records for height etc. 

I can't see anything in the help files for the massing model custom object so what I have so far is based on exporting a script from a file with massing models in it. It looks like I should be able to change the fields for number of floors and height etc based on the records once I have got it to build massing models.

So far what I have runs and creates massing models but they don't show on screen or export, I can select them and see their properties  but there is clearly something very wrong with them.  

 

vs.SelectObj("T=GROUP")
vs.Ungroup()
def gone(h1):
    vs.ConvertToPolygon(h1, 0)
    
vs.ForEachObject(gone, "T=POLYLINE" ) #loop for all the polylines and convert them to polygons
def extrudebuildings(h):#Extrude buidlings based on records
        vs.CreateCustomObjectPath('Massing Model', h, none)
        h2 = vs.LNewObj()  # get handle to new symbol instance
        vs.Record(vs.LNewObj(),'Massing Model');
        vs.SetRField(vs.LNewObj(),'Massing Model','2Ddisplay','Roof');
        vs.SetRField(vs.LNewObj(),'Massing Model','Height','6.096');
        vs.SetRField(vs.LNewObj(),'Massing Model','NumFloors','2');
        vs.SetRField(vs.LNewObj(),'Massing Model','WallMatl','');
        vs.SetRField(vs.LNewObj(),'Massing Model','Custom Roof','False');
        vs.SetRField(vs.LNewObj(),'Massing Model','Overhang','0.3048');
        vs.SetRField(vs.LNewObj(),'Massing Model','RoofThk','0.3048');
        vs.SetRField(vs.LNewObj(),'Massing Model','RoofMatl','');
        vs.SetRField(vs.LNewObj(),'Massing Model','DrawPitchedRoof','False');
        vs.SetRField(vs.LNewObj(),'Massing Model','EaveStyle','Square');
        vs.SetRField(vs.LNewObj(),'Massing Model','RoofPitch','35');
        vs.SetRField(vs.LNewObj(),'Massing Model','DrawFloorLevels','True');
        vs.SetRField(vs.LNewObj(),'Massing Model','FloorThk','0.3048');
        vs.SetRField(vs.LNewObj(),'Massing Model','Use Site Modifiers','False');
        vs.SetRField(vs.LNewObj(),'Massing Model','Use Fence','True');
        vs.SetRField(vs.LNewObj(),'Massing Model','Fence offset','0.0254');
        vs.SetRField(vs.LNewObj(),'Massing Model','Use Shadow','False');
vs.ForEachObject(extrudebuildings, "T=POLY" ) #loop for all the polygons 

 

Edited by Sloader
Link to comment

Here is a version that kind of works.

CreateCustomObjectPath is expecting the handles to two polygons, one for the walls, one for the roof overhang. I did not both to try and figure out which is which.

 

The Massing Model record is automatically part of the object created by the CreateCustomObjectPath command so you don't want to try and attach it with the vs.Record line.

 

In your script you will want to replace all the vs.LNewObj calls in the SetRField functions with h2 so you don't recalculate the object every time.

 

Be careful of the units you are running in. In a document set to Feet and Inches, the constant values in the SetRField functions are interpreted as Inches, so the model is very short. In millimeters it might be even worse.

 

Set the values properly by reading the records attached to your polygons and you should be good.  Be careful, the polygons are "incorporated" into the massing model. I don't know if the originals become part of the massing model or that data is used to create a new object inside the massing model, but if a new object is created you may loose you records. Even if you don't lose them, you will lose easy access to them as you will have to enter the Profile Group or the Path group to see the original object and read or change the record.

 

You probably want to make a copy of the original poly with record attached and pass that to the CCOP procedure instead of passing the original.

 

HTH

 

vs.SelectObj("T=GROUP")
vs.Ungroup()

def gone(h1):
    vs.ConvertToPolygon(h1, 0)
    
vs.ForEachObject(gone, "T=POLYLINE" ) #loop for all the polylines and convert them to polygons

def extrudebuildings(h):#Extrude buidlings based on record
        pts_h1 = h
        pts_h2 = vs.OffsetPolyClosed(h, 12, 'False')
        vs.CreateCustomObjectPath('Massing Model', h, pts_h2)
        h2 = vs.LNewObj()  # get handle to new symbol instance
		#   vs.Record(vs.LNewObj(),'Massing Model');
        vs.SetRField(vs.LNewObj(),'Massing Model','2Ddisplay','Roof');
        vs.SetRField(vs.LNewObj(),'Massing Model','Height','6.096');
        vs.SetRField(vs.LNewObj(),'Massing Model','NumFloors','2');
        vs.SetRField(vs.LNewObj(),'Massing Model','WallMatl','');
        vs.SetRField(vs.LNewObj(),'Massing Model','Custom Roof','False');
        vs.SetRField(vs.LNewObj(),'Massing Model','Overhang','0.3048');
        vs.SetRField(vs.LNewObj(),'Massing Model','RoofThk','0.3048');
        vs.SetRField(vs.LNewObj(),'Massing Model','RoofMatl','');
        vs.SetRField(vs.LNewObj(),'Massing Model','DrawPitchedRoof','False');
        vs.SetRField(vs.LNewObj(),'Massing Model','EaveStyle','Square');
        vs.SetRField(vs.LNewObj(),'Massing Model','RoofPitch','35');
        vs.SetRField(vs.LNewObj(),'Massing Model','DrawFloorLevels','True');
        vs.SetRField(vs.LNewObj(),'Massing Model','FloorThk','0.3048');
        vs.SetRField(vs.LNewObj(),'Massing Model','Use Site Modifiers','False');
        vs.SetRField(vs.LNewObj(),'Massing Model','Use Fence','True');
        vs.SetRField(vs.LNewObj(),'Massing Model','Fence offset','0.0254');
        vs.SetRField(vs.LNewObj(),'Massing Model','Use Shadow','False');
        
vs.ForEachObject(extrudebuildings, "T=POLY" ) #loop for all the polygons 

 

Link to comment

Script below is cleaned up a bit. 

It now works with heights from my records and I have got GIS to do some guessing about which lines are too complex for a pitched roof in addition to cleaning up angles near 0 or 90. 

There will still be many polylines that are too complex so it would be good to suppress the failure messages so I don't have to sit and hold the return key whilst it runs, this would also mean I can relax the inputs on which polylines it tries to add a pitched roof to.

 

 

storeyht=3

vs.SelectObj("T=GROUP")
vs.Ungroup()
def gone(h1):
	vs.ConvertToPolygon(h1, 0)
	
vs.ForEachObject(gone, "T=POLYLINE" ) #loop for all the polylines and convert them to polygons

def extrudebuildings(h):#make massing model buidlings based on records
		RecName=vs.GetName(vs.GetRecord(h,1))
		Pitched=vs.GetRField(h, RecName,'PITCHED')#Get pitched boolean from record	
		AOD=vs.GetRField(h, RecName,'TM_mean')#Get AOD height from record
		TM=eval(vs.GetRField(h, RecName,'TM_mean'))#convert AOD height to number
		SM=eval(vs.GetRField(h, RecName,'SM_max'))#Get max surface height as number
		BHT=SM-TM
		Storeys = ((SM-TM)-2)/storeyht
		Floors = vs.Round(Storeys)
		vs.CreateCustomObjectPath('Massing Model', h, None)
		h2 = vs.LNewObj()  # get handle to new massing model
		vs.SetRField(h2,'Massing Model','2Ddisplay','Roof')
		vs.SetRField(h2,'Massing Model','Height',BHT)
		vs.SetRField(h2,'Massing Model','NumFloors',Floors)
		vs.SetRField(h2,'Massing Model','WallMatl','')
		vs.SetRField(h2,'Massing Model','Custom Roof','False')
		vs.SetRField(h2,'Massing Model','Overhang','0.3')
		vs.SetRField(h2,'Massing Model','RoofThk','0.3')
		vs.SetRField(h2,'Massing Model','RoofMatl','')
		vs.SetRField(h2,'Massing Model','DrawPitchedRoof',Pitched)
		vs.SetRField(h2,'Massing Model','EaveStyle','Square')
		vs.SetRField(h2,'Massing Model','RoofPitch','35')
		vs.SetRField(h2,'Massing Model','DrawFloorLevels','True')
		vs.SetRField(h2,'Massing Model','FloorThk','0.3')
		vs.SetRField(h2,'Massing Model','Use Site Modifiers','False')
		vs.SetRField(h2,'Massing Model','Use Fence','True')
		vs.SetRField(h2,'Massing Model','Fence offset','0.02')
		vs.SetRField(h2,'Massing Model','Use Shadow','False')
		vs.Move3DObj(h2, 0, 0, AOD)	
vs.ForEachObject(extrudebuildings, "T=POLY" ) #loop for all the polygons 

 

Link to comment

I don't think there is a way to suppress the error messages, so your best best is to try and "calculate" which polys are too complex and skip them until you can be present. Or try running the Simplify Polys command from the Modify:Drafting Aids... menu to get something reasonable.

Link to comment
On 3/29/2022 at 1:06 PM, Sloader said:

it would be good to suppress the failure messages

Hello
Does it maybe work if you do something like this:

try:
	vs.SetRField(h2,'Massing Model','2Ddisplay','Roof')
	#your code

except:
	pass
	#or do someting like taggging the object as "too complexe" or do another function


Alternatively you can put something heavy on your enter key, while script is running.
 

  • Like 1
  • Laugh 1
Link to comment

The try / except approach looks ideal - When I get time I'll try setting the roof to pitched (True) and false if it fails

The something heavy on the key option was explored E7 S7 of the Simpsons which clearly demonstrates some of the drawbacks of this approach

computer-drinking.gif

  • Laugh 1
Link to comment

@DomC The "Try Except" approach works nicely so I have managed to get VW to do what I want and learnt something new in Python. 

I am still using the "Pitched" attribute from GIS so I can prevent buildings above or below a certain size from having pitched roofs but I should now be able to relax the restriction on how complex a roof I let it try and make pitched. 

 

		try:
			vs.SetRField(h2,'Massing Model','DrawPitchedRoof',Pitched)
		except:
			pass	

 

MassingModels.jpg

  • Like 1
Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...