Original User: Daniel.OShaughnessy1) Yes, each block is 1 OBJ file2) Not from Rhino (they always get triangulated). You can avoid the triangulation by using 3d Max instead, but a quick test of that reveals the same problem[ATTACH=CONFIG]15876[/ATTACH]3) OK4) Here is the code (sorry it's kind of long). The model import is in the InsertModel rule, while the splitting occurs between Mass and Floors@Group("Model",0) @Order(1)
attr Model_file = "my.obj"
@Group("Model",0) @Order(2) @Range("Scale to Parcel Size","Scale to Parcel and Set Height","Set Height","Do not scale (model in realworld dimensions)")
attr Model_Size = "Scale to Parcel and Set Height"
@Group("Model",0) @Order(3)
attr Model_Height = 50
@Group("Model",0) @Order(4) @Range("0","90","180","270")
attr Model_Rotation = 0
@Group("Lot Attributes",1)
attr distanceStreet = 0   // Lot setback
@Hidden
attr Block_Area = 0
Block -->
 set(Block_Area,geometry.area)   //PM: We have to store this value to calculate the FAR below
 report("Block Area",Block_Area)  //PM: Plus we write it out for the report
 offset(distanceStreet)
 comp(f) {inside: alignScopeToAxes InsertModel | border: O}
 
InsertModel -->
 // examples of different insert 'modes'
 case Model_Size == "Scale to Parcel Size":
  i(Model_file) // the insert operation fits in the model automatically and scales the height accordingly
  r(scopeCenter, 0, Model_Rotation, 0)
  Mass
 case Model_Size == "Scale to Parcel and Set Height":
  s('1,Model_Height,'1) 
  i(Model_file) 
  r(scopeCenter, 0, Model_Rotation, 0)
  Mass
 case Model_Size == "Set Target Height":
  s(0,Model_Height,0) center(xz)  // in case only height is set..
  i(Model_file)      // ..the insert operation scales the width and depth according to the given height
  r(scopeCenter, 0, Model_Rotation, 0)
  Mass
 else:
  s(0,0,0) center(xyz)  // in case size is 0..
  r(scopeCenter, 0, Model_Rotation, 0)
  i(Model_file)     // ..the insert operation uses the realworld dimensions
  Mass
 
##############################################
# REST IS THE SAME AS IN THE PREVIOUS CGA FILE 
#  
@Group("Land Use Control",5) @Order(1) @Range("Residential","Commercial","Mixed-Use","Industrial", "Retail","Government","Cultural","Education","Hotel") //PM: @Range annotation creates drop-down
attr Land_Use = 10%: "Residential" 50%: "Commercial" 30%: "Mixed-Use" else: "Industrial" //PM: These attribute is usually controlled by image map
  
@Group("Building Attributes") @Order(2)
attr retailheight = 5 
@Group("Building Attributes") @Order(1)
attr floorheight = 4 
@Group("Visualization") @Range("Mass_white","Mass_color","Floors","MassAndFloors")
attr vizMode = "MassAndFloors"
@Group("Land Use Control") @Order(5) @Description("% of commercial floors in a mixed-use residential building")
attr mixedUsePercentage = 0.4 //PM: New attribute
@Group("Building Attributes")
attr getNumberOfRetailFloors =
 case Land_Use == "Residential" : 0
 case Land_Use == "Industrial" : 0
 case Land_Use == "Education" : 0
 case Land_Use == "Cultural"  : 0
 case Land_Use == "Commercial" : 1
 case Land_Use == "Mixed-Use" : 1
 else       : floor(rand(1))
getColor(myLandUse) =
 case myLandUse == "Commercial" : "#DD7300"
 case myLandUse == "Retail"  : "#D63200"
 case myLandUse == "Residential" : "#FFD255"
 case myLandUse == "Industrial" : "#720000"
 case myLandUse == "Government" : "#1887B2"
 case myLandUse == "Cultural" : "#46B8E6"
 case myLandUse == "Education" : "#8D7CC1"
 case myLandUse == "Hotel"  : "#D8ABC8"
 else       : "#888888"
calcNumberOfFloors =
 rint(scope.sy/floorheight)
//PM: handles mixed use and adds retail floors 
Mass -->
 case Land_Use == "Mixed-Use":
  split(y){ retailheight * getNumberOfRetailFloors: Floors("Retail") 
    | floorheight * mixedUsePercentage*calcNumberOfFloors : Floors("Commercial")
    | ~1: Floors("Residential") }
  MassViz(Land_Use)
 else:
  split(y){ retailheight * getNumberOfRetailFloors: Floors("Retail") 
    | ~1: Floors(Land_Use) }
  MassViz(Land_Use)
  
  
// PM: sets the color according the landuse-parameter and splits them in single floors using a repeat split 
Floors(myLandUse) -->
 color(getColor(myLandUse))
 split(y){ ~floorheight: comp(f){ bottom: FloorArea(myLandUse) } }*
 
 
FloorArea(myLandUse) -->
 reverseNormals
 report("GFA."+myLandUse,geometry.area)  //PM: the default staticts show the sum, so we just have to call it for each floor 
 report("FAR",geometry.area/Block_Area) //PM: same here (we just do the division for each floor instead for the whole sum at the end)
 FloorViz(myLandUse)
 
O -->
 color("#A7BC2B")
##############################################
# Visualization
#
MassViz(myLandUse) --> //DOS: the idea is to have viz modes similar to those in the reporting tutorial
 case vizMode == "Mass_white" : Mass. //DOS: solid white mass
 case vizMode == "Mass_color" :    //DOS: mass colored by land use
  color(getColor(myLandUse)) Mass. 
 case vizMode == "MassAndFloors" :  //DOS: transparent mass with floors
  set(material.color.a, 0.2) Mass.
 else: NIL   //DOS: if set to "Floors" there should be no mass shown at all, only floors
FloorViz(myLandUse) -->
 case vizMode == "Mass_white" || vizMode == "Mass_color" : NIL
 else:
  color(getColor(myLandUse)) Floors.