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
Solved! Go to Solution.
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
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
Thank you Chris. Very useful
This is super helpful. Thank you very much!
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!
Hmm it worked perfectly for me...I just added in color and transparency
Can you explain me how to do it please?
I just applied the rule to planar sections in stairwells of my floor space.
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
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
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