POST
|
Hi Matt, Thanks for your help. I was having trouble with the Python export (reporting) module so I ended up writing a script that uses Gauss' polygon area formula/shoelace formula to batch calculate the area of polygons. It uses the ce.getVertices function to retrieve the unstructured vertices list from a polygon [x1, y1, z1, x2, y2, z2,... xN, yN, zN] and converts it to the format [[x1, z1], [x2, z2],...[xN, zN]]. The polygon area is then saved as an object attribute to the original shape. _____________________________________________________________________________________________ '''
Created on 2017-08-03
@author: bcbd
SELECT ANY NUMBER OF 2D POLYGONS AND HIT F9
RETURNS THE CALCULATED AREA OF THE POLYGON, STORED AS AN OBJECT ATTRIBUTE
'''
from scripting import *
# get a CityEngine instance
ce = CE()
def toShape():
shapes = ce.getObjectsFrom(ce.selection, ce.isShape)
for shape in shapes:
ce.setRuleFile(ce.selection(), 'calculateParcelArea.cga') # assign CGA rule calcParcelArea
ce.setStartRule(ce.selection(), 'Lot')
ce.generateModels(ce.selection())
parcelArea = toParcelArea()
ce.setAttribute(shape, 'parcelArea', parcelArea)
def toParcelArea():
parcels = ce.getObjectsFrom(ce.selection, ce.isShape)
for parcel in parcels:
#TO CALCULATE PARCEL AREA
XYZ_coords = ce.getPosition(parcel) # GETS THE CENTROID COORDINATES FOR EACH PARCEL
vertices = ce.getVertices(parcel) #retrieve unstructured list with coordinates of vertices
verticesRestructured = restructureList(vertices)
parcelArea = polygonArea(verticesRestructured)
ce.setAttribute(parcel, 'parcelArea', parcelArea)
def restructureList(vertices):
results = [] #create empty list to store restructured list [[x1,z1],[x2,z2],[x3,z3]]
print "Unstructured list in format: [x1,y1,z1,x2,y2,z2,x3,y3,z3...xN,yN,zN]"
print vertices
i = 0 #initialize counter for first while loop
j = 0 #initialize counter for second while loop
coord_XZ = [] #create empty coord pair list to store each coord pair [x1,z1]
while i < len(vertices): # while the counter is less than the length of the unstructured list
while j <= 2: #while the counter is less than equal to 2 (for unstructured X, Y, and Z coordinates
coord_XZ.append(vertices) #adds the value from unstructured list to coord pair list
i = i + 1
j = j + 1
j = 0
del coord_XZ[1] #removes the Y (height) coordinate from the vertex
results.append(coord_XZ) #appends X,Y coordinates for one vertex
coord_XZ = [] #RESET COORD LIST TO NULL doesnt work
#print "------" #reset
print "Restructured list in format: [[x1,z1], [x2,z2], [x3,z3]...[xN,zN]]"
print results
print "-----------------"
print "The area of the polygon is: "
print polygonArea(results)
print "-----------------"
return results
def polygonArea(corners): #GAUSSIAN POLYGON AREA FUNCTION
n = len(corners) # of corners
area = 0.0
for i in range(n):
j = (i + 1) % n
area += corners[0] * corners [1]
area -= corners [0] * corners[1]
area = abs(area) / 2.0
return area
if __name__ == '__main__':
toParcelArea()
pass
... View more
08-03-2017
03:09 PM
|
0
|
0
|
3312
|
POST
|
Hey Matt, I understand the Python will make things more complex but I believe it will be necessary to automate many parts of my project. I’m interested in using CityEngine to model scenarios in two ways. Firstly, what metrics we can be reported from building form, such a FAR, passive and active zones, and thermal shape factor. Secondly, how can metrics be used to generate form, such as setting FAR and having CityEngine produce a variety of building forms that would suit the FAR condition. So far the most successful and flexible example that I’ve come across is your tutorial “GFA & FAR Calculations with CityEngine” on Youtube: https://www.youtube.com/watch?v=gnefAyqUQVE&t=2503s&index=3&list=PL34n_T3uZ_mMzFk4aV7Lo6EgxoQGZEcSg Around 33:15 in the tutorial you made a new parcel polygon beneath your building, applied calcArea.cga, and manually added the parcel area printed to the console as a new object attribute. At 37:15 you mention that “object attributes cannot be set directly with CGA” and that a Python script might be used to keep the value up-to-date. I’ll be working with hundreds of parcels so I want to write a Python script. From what I understand I need to use a Python exporting (reporting) script to report parcel area values, automate the creation of a new object attribute (parcelArea) for each parcel shape and assign parcelArea from the reported value. Is this correct? Thanks, Brendan
... View more
08-01-2017
05:10 PM
|
0
|
1
|
3312
|
POST
|
Hi Matt, I've written a CGA rule that allows the user to control the splitting of a block into a series of shapes. Once the final subblock units have been set I've used a python script to convert them to static parcels. One problem I'm having is saving the area of each of these areas as an object attribute in the newly created shapes (for subsequent FAR calculations). Once they are static shapes I need to manually remove some excess shapes (there are extra subblock areas created for each rectangle in the block, including the block itself). Finally, I've tried writing an Export (Reporting) Python module that creates a new object attribute for each subblock unit and assigns the area to that attribute. Any advice you can provide is greatly appreciated! Brendan _______________________________________________________________________________________ CGA rule for controlled subdivision of a block: /** * File: subblock.cga * Created: 20 Jul 2017 18:58:27 GMT * Author: bcbd */ version "2017.0" import Zoning : "Zoning.cga" @hidden attr myZoning = "" attr zoningResidentialArea = 0 attr zoningCommercialArea = 0 attr zoningInstitutitonalArea = 0 attr zoningMixed_UseArea = 0 attr zoningIndustrialArea = 0 @Group("Initial Block: First Split", 1) attr A_B_Split = false attr rotate_AB = false @Range(0,200) attr A_Depth = 20 @Range("Residential", "Commercial", "Institutional", "Mixed_Use", "Industrial") attr zoningA = "Residential" @Range("Residential", "Commercial", "Institutional", "Mixed_Use", "Industrial") attr zoningB = "Residential" @Group("A: Second Split", 3) attr A1_A2_Split = false attr rotate_ZoneA = false @Range(0,100) attr A2_Width = 20 attr A3_Split = false @Range(0,100) attr A3_Width = 20 @Range("Residential", "Commercial", "Institutional", "Mixed_Use", "Industrial") attr zoningA1 = "Residential" @Range("Residential", "Commercial", "Institutional", "Mixed_Use", "Industrial") attr zoningA2 = "Residential" @Range("Residential", "Commercial", "Institutional", "Mixed_Use", "Industrial") attr zoningA3 = "Residential" @Group("B: Second Split", 4) attr B1_B2_Split = false attr rotate_ZoneB = false @Range(0,100) attr B2_Width = 20 attr B3_Split = false @Range(0,100) attr B3_Width = 20 @Range("Residential", "Commercial", "Institutional", "Mixed_Use", "Industrial") attr zoningB1 = "Residential" @Range("Residential", "Commercial", "Institutional", "Mixed_Use", "Industrial") attr zoningB2 = "Residential" @Range("Residential", "Commercial", "Institutional", "Mixed_Use", "Industrial") attr zoningB3 = "Residential" ////////////////////////// BEGINNING OF SPLIT @StartRule block --> case A_B_Split == true : case rotate_AB == false : split(x) {A_Depth : zoneA | ~1 : zoneB} Reporting NIL /////////////////// else : split(z) {A_Depth : zoneA | ~1 : zoneB} Reporting /////////////////// NIL else : colorPicker(zoningA) Reporting /////////////////// NIL zoneA --> case A1_A2_Split == true && A3_Split == false : case rotate_ZoneA == false : split(x) {A2_Width : zoneA1 | ~1 : zoneA2} Reporting /////////////////// NIL else : split(z) {A2_Width : zoneA1 | ~1 : zoneA2} Reporting /////////////////// NIL case A1_A2_Split == true && A3_Split == true : case rotate_ZoneA == false : split(x) {A2_Width : zoneA1 | ~1 : zoneA2 | A3_Width : zoneA3} Reporting /////////////////// NIL else : split(z) {A2_Width : zoneA1 | ~1 : zoneA2 | A3_Width : zoneA3} Reporting /////////////////// NIL else : colorPicker(zoningA) Reporting /////////////////// NIL zoneB --> case B1_B2_Split == true && B3_Split == false : case rotate_ZoneB == false : split(x) {B2_Width : zoneB1 | ~1 : zoneB2} Reporting /////////////////// NIL else : split(z) {B2_Width : zoneB1 | ~1 : zoneB2} Reporting /////////////////// NIL case B1_B2_Split == true && B3_Split == true : case rotate_ZoneB == false : split(x) {B2_Width : zoneB1 | ~1 : zoneB2 | B3_Width : zoneB3} Reporting /////////////////// NIL else : split(z) {B2_Width : zoneB1 | ~1 : zoneB2 | B3_Width : zoneB3} Reporting /////////////////// NIL else : colorPicker(zoningB) Reporting /////////////////// NIL #ZONE A zoneA1 --> colorPicker(zoningA1) zoneA2 --> colorPicker(zoningA2) zoneA3 --> colorPicker(zoningA3) #ZONE B zoneB1 --> colorPicker(zoningB1) zoneB2 --> colorPicker(zoningB2) zoneB3 --> colorPicker(zoningB3) colorPicker(zoningType)--> case zoningType == "Residential" : Zoning.Residential label("Residential") set(myZoning, "Residential") //set(zoningResidentialArea, geometry.area) print(myZoning + " Area: " + geometry.area) case zoningType == "Commercial" : Zoning.Commercial set(myZoning, "Commercial") label("Commercial") //set(zoningCommercialArea, geometry.area) print(myZoning + " Area: " + geometry.area) case zoningType == "Institutional" : Zoning.Institutional label("Institutional") set(myZoning, "Institutional") //set(zoningInstitutitonalArea, geometry.area) print(myZoning + " Area: " + geometry.area) case zoningType == "Mixed_Use" : Zoning.Mixed_Use label("Mixed_Use") set(myZoning, "Mixed_Use") //set(zoningMixed_UseArea, geometry.area) print(myZoning + " Area: " + geometry.area) case zoningType == "Industrial" : Zoning.Industrial label("Industrial") set(myZoning, "Industrial") //set(zoningIndustrialArea, geometry.area) print(myZoning + " Area: " + geometry.area) else : NIL Reporting --> report("Area_Residential", zoningResidentialArea) report("Area_Commercial", zoningCommercialArea) report("Area_Institutional", zoningInstitutitonalArea) report("Area.Mixed_Use", zoningMixed_UseArea) report("Area.Industrial", zoningIndustrialArea) _______________________________________________________________________________________ Script to convert selected block into static subblock fragments: ''' Created on 2017-07-26 @author: bcbd ''' from scripting import * # get a CityEngine instance ce = CE() def convertModelsToShapes(): models = ce.selection() shapes = ce.convertModelsToShapes(models) newShapes = ce.separateFaces(shapes) #cleanupSettings = CleanupShapesSettings() #LIST ALL CLEANUP SETTINGS TO BE APPLIED #cleanupSettings.setRemoveCoplanarEdges(True) #DOES THIS EVEN WORK? #cleanedShapes = ce.cleanupShapes(newShapes,cleanupSettings) #print "new shape converted from model: "+ce.getName(newShapes[0]) def subblockSelection(): shapes = ce.getObjectsFrom(ce.scene, ce.isShape) if __name__ == '__main__': convertModelsToShapes() pass _______________________________________________________________________________________ Once excess subblock units are removed (currently manual): Script to calculate parcel area: attr parcelArea_Calc = geometry.area Lot --> set(parcelArea_Calc, geometry.area) report("Parcel_Area", parcelArea_Calc) print("Parcel Area: " + parcelArea_Calc) color(0.2,0.2,0.2) #color orange if CGA rule is complete _______________________________________________________________________________________ Script to generate new object attributes (parcel area) for each subblock unit. Not yet complete. ''' Created on 2017-07-27 @author: bcbd ''' from scripting import * # Get a CityEngine instance ce = CE() REPORT = "" def initExport(exportContextOID): global REPORT REPORT = "Name,parcelArea\n" parcelArea() # Called for each shape after generation. def finishModel(exportContextOID, shapeOID, modelOID): shape = Shape(shapeOID) model = Model(modelOID) global REPORT i = 0 totalArea = 0.0 reports = model.getReports() if 'Parcel_Area' in reports.keys(): for area in reports['Parcel_Area']: #totalArea +=area i+=1 REPORT += "%s,%d\n" % (ce.getName(shape), area) #ce.addAttributeLayer(model, 'parcelArea', area) else : REPORT += "%s,%d\n" % (model, 0) def finishExport(exportContextOID): filename = ce.toFSPath("models/"+"/reportdata.txt") FILE = open(filename, "w") FILE.write(REPORT) FILE.close() ''' if(model.getReports().has_key('Parcel_Area')): l = len(model.getReports()['Parcel_Area']) for i in range(0,l): parcelArea = model.getReports()['Parcel_Area'] l = ce.addAttributeLayer('Parcel_Area') ce.setAttribute(shape, "/ce/rule/Parcel_Area", parcelArea) # Called after all shapes are generated. def finishExport(exportContextOID): ctx = ScriptExportModelSettings(exportContextOID) parcelArea() ''' def parcelArea(): objects = ce.getObjectsFrom(ce.selection, ce.isShape) for o in objects: ce.setRuleFile(ce.selection(), 'calculateParcelArea.cga') # assign CGA rule calcParcelArea ce.setStartRule(ce.selection(), 'Lot') ce.generateModels(ce.selection())
... View more
07-28-2017
01:55 PM
|
0
|
3
|
3312
|
POST
|
I am trying to write a python script that will create a new object attribute containing the parcel area for any number of parcels I’ve selected in the scene. I know I need to use Export (Reporting) python script to fetch the value of a rule attribute. Proposed method: Select the desired parcels in the scene Run a python script that assigns the CGA rule “calculateParcelArea.cga” to each of the parcels, generates the models using “calculateParcelArea.cga”, and reports the area in the Parcel_Area row, under the sum column. The python script then fetches the reports for each of the parcels, creates a new object attribute named ‘parcelArea’ for each parcel, and assigns the reported value. So far I’ve written a regular python (Module: Main) script that assigns the “calculateParcelArea.cga” to the selected parcels, generates the models with areas saved to rule attribute ‘parcelArea_Calc’, and reports the value. I’m having difficulty with the Export (Reporting) python module. Can someone help me make sense of this? How do I bring the existing script into the Export (Reporting) python module to complete the task? Thanks! Python script and CGA rule below: _____________________________________________________________________________________ ''' Created on 2017-07-26 @author: bcbd ''' from scripting import * # get a CityEngine instance ce = CE() def parcelArea(): shapes = ce.getObjectsFrom(ce.selection, ce.isShape) for shape in shapes: ce.setRuleFile(ce.selection(), 'calculateParcelArea.cga') # assign CGA rule calcParcelArea ce.setStartRule(ce.selection(), 'Lot') ce.generateModels(ce.selection()) if __name__ == '__main__': parcelArea() pass _____________________________________________________________________________________ /** * File: calculateParcelArea.cga */ version “2017.0” attr parcelArea_Calc = geometry.area Lot --> report("Parcel_Area", parcelArea_Calc) print("Parcel_Area: " + parcelArea_Calc) _____________________________________________________________________________________
... View more
07-27-2017
12:18 PM
|
0
|
7
|
3244
|
POST
|
I'm running into an issue where the block subdivision types in CityEngine does not seem to have the functionality I need for my current project. I'm looking to write a rule that allows for greater control in the parceling stage. I need to be able to create a controlled mosaic of zoning types within a block and have a unique parceling for each of those different zoning types. I currently have a CGA rule that allows me to split the block in two (A and B) and then have additional splits within A and B and the ability to rotate the orientation of A and B. Each of the subblock areas can then be assigned a zoning type (color as placeholders in the images). Once I'm at this stage I cannot select individual parcels, unlike those created using one of the existing subdivision types. Additionally, the polygons I've created are not aware of street edges and do not have the option to Set First Edge. After assigning a zoning type the subblock area should be divided into parcels according to specific zoning parameters (minimum & maximum lot widths, setbacks, etc) as drawn in image 4. The other option I'm considering is using roads with widths of 0m to subdivide the whole block into several CityEngine blocks so that I can preserve the Set First Edge function. I'd like to avoid this option if possible as I want to have dynamic sliders that would allow users configure subblock zoning dimensions.
... View more
07-20-2017
04:06 PM
|
0
|
8
|
4914
|
POST
|
The closest thing I've found for FAR as a generator of form is this tutorial here by Matt Buehler: GFA & FAR Calculations with CityEngine - YouTube
... View more
07-20-2017
03:20 PM
|
0
|
5
|
1466
|
Online Status |
Offline
|
Date Last Visited |
11-11-2020
02:23 AM
|