Select to view content in your preferred language

Balcony design for the corner of the building

2551
5
06-24-2020 06:58 AM
nazaninyosefi
Emerging Contributor

hello everyone

I want to design a balcony for the corners of the building like the picture below.( by cga rule in cityengine) . But I don't know how to do it, can anyone help. very thanks

this building has galss balcony in corner

0 Kudos
5 Replies
NicolaiSteinø
Regular Contributor

Hi Nazanin,

Basically what you should do is three things:

  1. Model your parapet in CityEngine as plain shapes with segments corresponding to your railing element.
  2. Model the railing element in a conventional 3D modeler (i.e. SketchUp) and export it in a format known to CityEngine (i.e. .dae).
  3. Replace your plain shape segments with the modelled railing element.

Try using the code below. Note that the primitive cube inserted in line 28 makes sure that your railing element will trim at the corner (see close-up).

Nic 

/**
 * File:    railing_rule.cga
 * Created: 30 Jun 2020 19:41:21 GMT
 * Author:  nicolaisteino
 */

version "2020.0"

attr length = 4
attr height = 1.2
attr width = 4
attr railingDepth = 0.05

Lot -->
 primitiveCube(length,height,width)
 comp(f)
 { front : Side
 | right : Side
 }

Side -->
 split(x)
 { ~1 : Segment
 }*

Segment -->
 t(0,0,-railingDepth)
 primitiveCube(scope.sx,scope.sy,railingDepth)
 i("railing.dae")‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

CherylLau
Esri Regular Contributor

Nicolai Steinø‌'s post above is excellent.  That is a great way to make the railing.

In comparison, the code I will add is not a very nice solution, and it has limitations.  However, in addition to creating a nice railing, you might also want to know how to create the corner balcony that indents inward such that you have an L shaped balcony.  Here is one solution that breaks up the balcony into two pieces (which is why it is not an ideal solution).

The code splits each facade into tiles.  Just to test the concept, balconies are put in each corner and on a small number of random facade tiles in the middle.  Then, to test if a tile should make a corner balcony, the tiles are extruded backwards to see if they intersect other extruded tiles.  (Note: The code doesn't actually do an extrude here but instead uses a cube.)  The screenshot shows how the corner balconies are made in two parts.  The green part is created by the facade tile which comes from the last tile in the row, and the yellow part is created by the facade tile which comes from the first tile in the row.  So, the last tile in the row creates a shortened balcony, and the first tile in the row creates the full width balcony.

Limitations:  This only works for 90 degree corners.  I only considered rectangular shapes just to illustrate the principle, so this won't work for concave regions.  Furthermore, this might cause some ugly, short railing pieces (since the railing is broken into two pieces) when using Nicolai Steinø‌'s method above to create railings.  Like I said, not ideal.  Maybe someone has another solution.

/*
This rule creates corner balconies that go inwards.
First tiles in a row create a balcony which is the full width of the tile.
Last tiles in a row create a balcony which is shortened by the balcony width.
*/

const height = 12
const floor_height = 4
const tile_width = 4
const balcony_width = 1
const balcony_height = 1
const extrudedTile_label = "Extruded_Tile"
		
Lot -->
	extrude(height)
	comp(f) { side: Facade | top: Roof. }
	
Facade -->
	split(y) { ~floor_height: split(x) { ~tile_width: Tile(split.index) }* }*
	
Tile(xInd) -->
	case xInd==0:
		TileWithBalcony(true, false)
	case xInd==split.total-1:
		TileWithBalcony(false, true)
	case p(0.2):
		TileWithBalcony(false, false)
	else:
		Wall.
		
TileWithBalcony(isFirst, isLast) -->
	s('1, '1, 0.4*tile_width)
	primitiveCube
	t(0, 0, '-1)
	label(extrudedTile_label)
	TestOcclusion(isFirst, isLast)
	
TestOcclusion(isFirst, isLast) -->
	case overlaps(intra, extrudedTile_label):
		CreateBalcony(isFirst, isLast, true)
	else:
		CreateBalcony(isFirst, isLast, false)
		
CreateBalcony(isFirst, isLast, hasCornerBalcony) -->
	case isFirst && hasCornerBalcony:
		color(1,1,0)
		t(0, 0, scope.sz-balcony_width)
		s('1, '1, balcony_width)
		comp(f) { front: s('1, balcony_height, '1) BalconyRailing.
				| left: s('1, balcony_height, '1) BalconyRailing.
				| back: s(scope.sx-balcony_width,'1,'1) Wall.
				| top: NIL
				| all: Wall. }
	case isLast && hasCornerBalcony:
		color(0,1,0)
		t(0, 0, scope.sz-balcony_width)
		s(scope.sx-balcony_width, '1, balcony_width)
		comp(f) { front: s('1, balcony_height, '1) BalconyRailing.
				| right: NIL
				| top: NIL
				| all: Wall. }
	else:
		t(0, 0, scope.sz-balcony_width)
		s('1, '1, balcony_width)
		comp(f) { front: s('1, balcony_height, '1) BalconyRailing.
				| top: NIL
				| all: Wall. }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
0 Kudos
NicolaiSteinø
Regular Contributor

Combining Cheryl's approach and mine, the script now works for oblique corners as well. Passing on the vertical split index makes it possible to omit balconies at the ground floor. Cheryl's random balconies along the facade have been omitted to avoid unwanted results in the case of two neighboring balconies, as this approach produces balcony side walls. The code does work along the facade as well though. You may use a modulus/remainder query (%) to make sure that random balconies do not occur in neighboring tiles. For detailing, I added thickness to the balcony decks and a setback for the railing.

attr parapetH = 1.2
attr balconyD = 1.2
attr deckH = 0.15
attr railingDepth = 0.03
attr railingSetback = 0.03
attr segmentW = 1
attr bldgH = floorNumber*floorH
attr floorNumber = 4
attr floorH = 3
attr tileW = 4
          
Lot -->
 extrude(bldgH)
 comp(f)
 { side: Facade
 | top: Roof.
 }

Facade -->
 split(y)
     { ~floorH : Floor(split.index, split.total)
     }*
     
Floor(siy,sty) -->
 split(x)
     { ~tileW : Tile(siy,sty,split.index, split.total)
     }*

Tile(siy,sty,six,stx) -->
 case six==0 || six==stx-1 :
 Balcony Parapet(siy,sty)
 else :
 Wall.

Balcony -->
 t(0,0,-balconyD/2)
 primitiveCube(scope.sx,scope.sy,balconyD)
 comp(f)
 { bottom : NIL
 | top : rotateScope(90,0,0) Deck
 | front : NIL
 | all : reverseNormals() Wall.
 }

Deck -->
 t(0,-deckH,0)
 extrude(deckH)

Parapet(siy,sty) -->
 case siy > 0 :
 t(0,0,-railingDepth-railingSetback)
 trim()
 split(y) { parapetH : Side | ~1 : NIL }
 else :
 NIL
 
Side -->
 split(x)
 { ~segmentW : Segment
 }*

Segment -->
 t(0,0,-railingDepth)
 s(scope.sx,scope.sy,railingDepth)
 i("railing.dae")‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

CherylLau
Esri Regular Contributor

Yes!  Nicolai Steinø‌'s second post is the way to do it.  I forgot about trimming in my post, but Nicolai Steinø‌'s post has it.  Use the vertical trim planes created by the comp on the mass model in order to make nice corners.

0 Kudos
nazaninyosefi
Emerging Contributor

Hi dear Nicolai. Thank you for your guidance.Dear Carl, Thank you for your replay

0 Kudos