Create simple stairs with CGA

3720
10
Jump to solution
11-03-2015 10:29 AM
TessOldemeyer
Occasional Contributor

What is the best route to take in order to connect building floors using stairs as in the ESRI Campus example web scene (http://www.arcgis.com/apps/CEWebViewer/viewer.html?3dWebScene=9c0e319bfaff4d33a0fe2da97c2c3fd7 )? I am unsure of how to best approach this....

I currently have floor layers that have attributes distinguishing stairwells. My floors have been added from file geodatabases and the height offset has been manually set while aligning to terrain.

Any advice or suggestions would be super helpful! Thanks!

Tess

0 Kudos
1 Solution

Accepted Solutions
by Anonymous User
Not applicable

Attached is a rule that makes stairs. It was used in the Atlanta airport demo at UC 2015, so there may be some code that was specific to how that was setup. You'll have to study it some. I wrote it, but I don't remember exactly how the directional logic works. You'll have to figure that part out through experimentation.

Chris

View solution in original post

10 Replies
by Anonymous User
Not applicable

Attached is a rule that makes stairs. It was used in the Atlanta airport demo at UC 2015, so there may be some code that was specific to how that was setup. You'll have to study it some. I wrote it, but I don't remember exactly how the directional logic works. You'll have to figure that part out through experimentation.

Chris

ValerioBozzo
New Contributor III

Thank you Chris. Very useful

0 Kudos
TessOldemeyer
Occasional Contributor

This is super helpful. Thank you very much!

0 Kudos
ValerioBozzo
New Contributor III

Please, someone can explain how to use it? I tried to apply to shape object but it doesn't work!

I tried to apply to a sloped street, but nothing. Please, help me, I need to transform a sloped street to a flight of steps!

0 Kudos
TessOldemeyer
Occasional Contributor

Hmm it worked perfectly for me...I just added in color and transparency

0 Kudos
ValerioBozzo
New Contributor III

Can you explain me how to do it please?

0 Kudos
TessOldemeyer
Occasional Contributor

I just applied the rule to planar sections in stairwells of my floor space.

Stairs.JPG

Here is the rule:

version "2015.1"

attr StairColor="#8b8682"

attr StairTransparency= 0.3

attr LandingColor="#8b8682"

attr LandingTransparency= 0.3

attr landingWidth = 1.2

attr stairDepth = 0.3

attr landingSlabThickness = 0.2

attr stairThickness = landingSlabThickness

@Range("CW","CCW")

attr TransitionDirection = "CW"

attr TransitionHeight = uFeet(13)

const transitionHeight = meters(TransitionHeight)

attr TransitionOrientation = 0 # Using North=0, CW compass, East=90

@Group("Units",6)

@Order(1)

@Range("Feet","Meters")

attr units = "Feet"

unitScale = case units == "Feet": 3.28084 else: 1

const halfFloorHeight = transitionHeight / 2

@StartRule

StairMaster -->

  # Make flat and aligned to world Y axis.

  alignScopeToAxes(y)

  s('1,0,'1)

  # Remove extra vertices.

  cleanupGeometry(all,0.5)

  # Get the inner rectangle, since original shapes might be out of square.

  innerRect

  # Align X axis on longer side.

  # XX Will need to add rotation code.

  PutScopeXGoingLongways

PutScopeXGoingLongways -->

  case scope.sz > scope.sx:

  rotateScope(0,90,0)

  OrientationCheck

  else:

  OrientationCheck

OrientationCheck -->

  # Tilt up end and check which side the landing is oriented, based on the shape.

  rotate(rel,scope,0,0,90)

  set(InitialLandingSide, compassDirection)

  #print("compassDirection"+compassDirection)

  #print("TransitionOrientation "+TransitionOrientation)

  rotate(rel,scope,0,0,-90)

  FlipDirectionMaybe

@Hidden

attr InitialLandingSide = ""

compassDirection =

  case geometry.isOriented(world.north): "N"

  case geometry.isOriented(world.east): "E"

  case geometry.isOriented(world.south): "S"

  case geometry.isOriented(world.west): "W"

  else: "X"

FlipDirectionMaybe -->

  case InitialLandingSide == "N":

  case TransitionOrientation == 0:

  Make270Stairs

  case TransitionOrientation == 180:

  rotateScope(0,180,0)

  Make270Stairs

  else:

  print("Error in TransitionOrientation attribute.")

  color(1,0,0) Error.

  case InitialLandingSide == "S":

  case TransitionOrientation == 180:

  Make270Stairs

  case TransitionOrientation == 0:

  rotateScope(0,180,0)

  Make270Stairs

  else:

  print("Error in TransitionOrientation attribute.")

  color(1,0,0) Error.

  case InitialLandingSide == "E":

  case TransitionOrientation == 90:

  Make270Stairs

  case TransitionOrientation == 270:

  rotateScope(0,180,0)

  Make270Stairs

  else:

  print("Error in TransitionOrientation attribute.")

  color(1,0,0) Error.

  case InitialLandingSide == "W":

  case TransitionOrientation == 270:

  Make270Stairs

  case TransitionOrientation == 90:

  rotateScope(0,180,0)

  Make270Stairs

  else:

  print("Error in TransitionOrientation attribute.")

  color(1,0,0) Error.

  else:

  print("Error in TransitionOrientation attribute - compass error.")

  print("InitialLandingSide = " + InitialLandingSide)

  color(1,0,0) Error.

Make270Stairs -->

  split(x) {

  landingWidth: LandingLowerAndUpper |

  ~1: TwoStraightRuns |

  landingWidth: LandingMiddle

  }

LandingLowerAndUpper -->

  Landing

  t(0,transitionHeight,0)

  Landing

LandingMiddle -->

  t(0,halfFloorHeight,0)

  Landing

Landing -->

  extrude(-landingSlabThickness)

  color(LandingColor)

  set(material.opacity, 1-LandingTransparency)

@Hidden

attr runLength = 0

TwoStraightRuns -->

  set(runLength, scope.sx)

  DJScratchDirection

DJScratchDirection -->

  case TransitionDirection == "CW":

  split(z){'0.5: FirstRun | '0.5: SecondRun }

  else:

  split(z){'0.5: SecondRun | '0.5: FirstRun }

FirstRun -->

  StraightRun

SecondRun --> NIL

  rotateScope(0,180,0)

  t(0, halfFloorHeight, 0)

  StraightRun

StraightRun -->

  split(x){adjustedStairDepth: Stair}*

Stair -->

  t(0,stairRise * (split.index + 1),0)

  extrude(-stairThickness)

  color(StairColor)

  set(material.opacity, 1-StairTransparency)

adjustedStairDepth = runLength / stairCount  

stairCount = rint(runLength / stairDepth)

stairRise = halfFloorHeight / (stairCount + 1)

#################################################################

# Include this in the rule anywhere. Bottom of rule probably.

meters(valueInEitherFeetOrMeters) =

  case units == "Feet": valueInEitherFeetOrMeters * 0.3048

  else: valueInEitherFeetOrMeters

# Allows CGA author to specify defaults in feet, rather than meters times scale.

uFeet(valueInFeet) =

  case units == "Feet": valueInFeet

  else: valueInFeet * 0.3048

uMeters(valueInMeters) =

  case units == "Feet": valueInMeters * 3.28084

  else: valueInMeters 

0 Kudos
by Anonymous User
Not applicable

I'm sorry Valerio, the rule is not intended for sloped streets. It runs on flat rectangular shapes. You can adjust the slope in the Inspector for the rule.

Chris

TessOldemeyer
Occasional Contributor

I have combined the stairs rule with a floor plan rule in hopes of  being able to use the 'floor plan' portion except in the case where the room type is specified as a stairwell in the attributes. The rule works for either the stairs or the floor plan, but I cannot get both to generate at once. CityEngine has automatically assumed two start rules for the rule file (AddOutline and StairMaster). AddOutline is associated with coloring the floors and generating walls and StairMaster (surprise surprise) is for the stairs. When AddOutline is specified as the start rule, the areas where RM_TYPE=STAIR are left empty. When StairMaster is used as the start rule, the stairs are generated but nothing else.

How can I get the floor plan and stair shapes to generate simultaneously?

Thanks again for all of your help!


Tess

Here is the rule I have so far:

version "2015.1"

#attr Fill_Color = "#FFF80"

attr Outline_Color = "#000000"

@Range(0,1)

attr Transparency = 0.1

attr BorderThickness = 0.2

attr Extrude_Height = 1

attr DV_LTR = ""   # This will connect to your object attribute from the GDB.

AddOutline -->

  offset( -BorderThickness)

  comp(f){border: BorderColor | inside: FillColor}

BorderColor -->

  color(Outline_Color)

  set(material.opacity, 1-Transparency)

  extrude( Extrude_Height)

FillColor -->

     color(getColorFromOrg(DV_LTR)) # This calls the function below using attribute.

  set(material.opacity, 1-Transparency)

  # Expand this function using orgs, with colors in "hex color" format:

  getColorFromOrg(DV_LTR)=

     case DV_LTR == "A" : "#baff1e"

     case DV_LTR == "B" : "#0b5394"

     case DV_LTR == "C" : "#0000ff"

     case DV_LTR == "D" : "#c62104"

     case DV_LTR == "E" : "#ddf1ff"

     else: "#000000"

    

attr RM_TYPE = ""

attr StairColor="#8b8682"

attr StairTransparency= 0.3

attr LandingColor="#8b8682"

attr LandingTransparency= 0.3

attr landingWidth = 1.2

attr stairDepth = 0.3

attr landingSlabThickness = 0.2

attr stairThickness = landingSlabThickness

@Range("CW","CCW")

attr TransitionDirection = "CW"

attr TransitionHeight = uFeet(13)

const transitionHeight = meters(TransitionHeight)

attr TransitionOrientation = 0 # Using North=0, CW compass, East=90

@Group("Units",6)

@Order(1)

@Range("Feet","Meters")

attr units = "Feet"

unitScale = case units == "Feet": 3.28084 else: 1

const halfFloorHeight = transitionHeight / 2

StairMaster -->

  case RM_TYPE == "STAIR":

  # Make flat and aligned to world Y axis.

  alignScopeToAxes(y)

  s('1,0,'1)

  # Remove extra vertices.

  cleanupGeometry(all,0.5)

  # Get the inner rectangle, since original shapes might be out of square.

  innerRect

  # Align X axis on longer side.

  # XX Will need to add rotation code.

  PutScopeXGoingLongways

  else: NIL

PutScopeXGoingLongways -->

  case RM_TYPE == "STAIR":

  case scope.sz > scope.sx:

  rotateScope(0,90,0)

  OrientationCheck

  else:

  OrientationCheck

  else: NIL

OrientationCheck -->

  case RM_TYPE == "STAIR":

  # Tilt up end and check which side the landing is oriented, based on the shape.

  rotate(rel,scope,0,0,90)

  set(InitialLandingSide, compassDirection)

  #print("compassDirection"+compassDirection)

  #print("TransitionOrientation "+TransitionOrientation)

  rotate(rel,scope,0,0,-90)

  FlipDirectionMaybe

  else: NIL

  @Hidden

  attr InitialLandingSide = ""

  compassDirection =

  case geometry.isOriented(world.north): "N"

  case geometry.isOriented(world.east): "E"

  case geometry.isOriented(world.south): "S"

  case geometry.isOriented(world.west): "W"

  else: "X"

FlipDirectionMaybe -->

  case RM_TYPE == "STAIR":

  case InitialLandingSide == "N":

  case TransitionOrientation == 0:

  Make270Stairs

  case TransitionOrientation == 180:

  rotateScope(0,180,0)

  Make270Stairs

  else:

  print("Error in TransitionOrientation attribute.")

  color(1,0,0) Error.

  case InitialLandingSide == "S":

  case TransitionOrientation == 180:

  Make270Stairs

  case TransitionOrientation == 0:

  rotateScope(0,180,0)

  Make270Stairs

  else:

  print("Error in TransitionOrientation attribute.")

  color(1,0,0) Error.

  case InitialLandingSide == "E":

  case TransitionOrientation == 90:

  Make270Stairs

  case TransitionOrientation == 270:

  rotateScope(0,180,0)

  Make270Stairs

  else:

  print("Error in TransitionOrientation attribute.")

  color(1,0,0) Error.

  case InitialLandingSide == "W":

  case TransitionOrientation == 270:

  Make270Stairs

  case TransitionOrientation == 90:

  rotateScope(0,180,0)

  Make270Stairs

  else:

  print("Error in TransitionOrientation attribute.")

  color(1,0,0) Error.

  else:

  print("Error in TransitionOrientation attribute - compass error.")

  print("InitialLandingSide = " + InitialLandingSide)

  color(1,0,0) Error.

  else:NIL

Make270Stairs -->

  case RM_TYPE == "STAIR":

  split(x) {

  landingWidth: LandingLowerAndUpper |

  ~1: TwoStraightRuns |

  landingWidth: LandingMiddle

  }

  else:NIL

LandingLowerAndUpper -->

  case RM_TYPE == "STAIR":

  Landing

  t(0,transitionHeight,0)

  Landing

  else:NIL

LandingMiddle -->

  case RM_TYPE == "STAIR":

  t(0,halfFloorHeight,0)

  Landing

  else:NIL

Landing -->

  case RM_TYPE == "STAIR":

  extrude(-landingSlabThickness)

  color(LandingColor)

  set(material.opacity, 1-LandingTransparency)

  else:NIL

  @Hidden

  attr runLength = 0

TwoStraightRuns -->

  case RM_TYPE == "STAIR":

  set(runLength, scope.sx)

  DJScratchDirection

  else:NIL

DJScratchDirection -->

  case RM_TYPE == "STAIR":

  case TransitionDirection == "CW":

  split(z){'0.5: FirstRun | '0.5: SecondRun }

  else:

  split(z){'0.5: SecondRun | '0.5: FirstRun }

  else:NIL

FirstRun -->

  case RM_TYPE == "STAIR":

  StraightRun

  else:NIL

SecondRun --> NIL

  #case RM_TYPE == "STAIR":

  rotateScope(0,180,0)

  t(0, halfFloorHeight, 0)

  StraightRun

  #else: NIL

StraightRun -->

  case RM_TYPE == "STAIR":

  split(x){adjustedStairDepth: Stair}*

  else: NIL

Stair -->

  case RM_TYPE == "STAIR":

  t(0,stairRise * (split.index + 1),0)

  extrude(-stairThickness)

  color(StairColor)

  set(material.opacity, 1-StairTransparency)

  else: NIL

  adjustedStairDepth = runLength / stairCount  

  stairCount = rint(runLength / stairDepth)

  stairRise = halfFloorHeight / (stairCount + 1)

  #################################################################

  # Include this in the rule anywhere. Bottom of rule probably.

  meters(valueInEitherFeetOrMeters) =

  case units == "Feet": valueInEitherFeetOrMeters * 0.3048

  else: valueInEitherFeetOrMeters

  # Allows CGA author to specify defaults in feet, rather than meters times scale.

  uFeet(valueInFeet) =

  case units == "Feet": valueInFeet

  else: valueInFeet * 0.3048

  uMeters(valueInMeters) =

  case units == "Feet": valueInMeters * 3.28084

  else: valueInMeters 

0 Kudos