Select to view content in your preferred language

Fitting a rectangle with a given depth into another shape.

1193
8
06-29-2023 03:39 AM
MattOlsen
Occasional Contributor

Hi all. 

I'm trying to create a rule that places houses of a specified depth and width around the perimeter of a Lot.

The lots are usually not rectangular, and I'm trying to create clusters of houses to maximise efficiency.

What I've tried so far is using the splitAndSetback operation, which carves the boundary into segments. Good so far. Other than houses, some of the buildings need to be perimeter blocks which wrap around the corners, so this operation is very useful.

MattOlsen_2-1688035093448.png

 

I'm then trying to use the innerRectangle function to create a rectangle, that I can then split into individual shapes that will become the houses. 

Unfortunately, sometimes the innerRectangle is narrower than the depth I need for the houses - see shape on the left.

MattOlsen_0-1688034900684.png

 

Can anyone think of a way to alternate way to fit a rectangle with a fixed depth into these shapes, as pictured below in green? 

MattOlsen_1-1688034943687.png

 

Any help much appreciated.

 

0 Kudos
8 Replies
MattOlsen
Occasional Contributor

MattOlsen_0-1688035627810.png


For reference, the end goal is something similar to this.

 

0 Kudos
plfontes
Regular Contributor

Hi,

I had a similar challenge in a project so I ended up placing the buildings as fixed objects with the correct sizes using the 'i' operation. Thus, regardless of the shape of the InnerRectangle, the building kept its size.


Screenshot 2023-06-29 132947.png

 

I had 3 typologies, for the left, right and middle position. I also added scope controls for tunning the position and rotation.

Here's the CGA code:

/**	
 * File:    Townhouses.cga
 * Created: 24 May 2023 13:17:26 GMT
 * Author:  PFontes
 */

version "2022.1"

@Enum("Lawn 1", "Lawn 2") @Order(3)
attr grassType = "Lawn 1"
@Order(4)
attr xTextureSize = 5
@Order(5)
attr zTextureSize = 5

@Range(min=-180, max=180, restricted=true)
attr rotateScope = 90

@Range(min=-10, max=10, restricted=false)
attr scopeTranslateX = 0
@Range(min=-10, max=10, restricted=false)
attr scopeTranslateY = 0
@Range(min=-10, max=10, restricted=false)
attr scopeTranslateZ = 0

@Enum("Left", "Right", "Centre")
attr villaType = "Centre"

@Enum("uvtest", "white")
attr textureType = "uvtest"

Lot -->
    innerRectangle(scope) { shape: GrassTexture Insert | remainder: GrassTexture}

InsertVilla -->
	case villaType == "Left":
		i("Townhouses/Townhouse Semi Left.dae", yUp, keepSizeAndPosition) 
		center(xz) 
		projectUV(0) 
		softenNormals(0) 
		comp(f){horizontal: GenericTexture | all: GenericTexture}
	case villaType == "Right":
		i("Townhouses/Townhouse Semi Right.dae", yUp, keepSizeAndPosition) 
		center(xz) projectUV(0) 
		softenNormals(0) 
		comp(f){horizontal: GenericTexture | all: GenericTexture}
	else:
		i("Townhouses/Townhouse.dae", yUp, keepSizeAndPosition) 
		center(xz) 
		softenNormals(0) 
		comp(f){horizontal: GenericTexture | all: GenericTexture}

Insert -->
		rotateScope(0, rotateScope, 0)
		t(scopeTranslateX, scopeTranslateY, scopeTranslateZ)
		alignScopeToAxes(y)
		InsertVilla

GenericTexture -->
	case textureType == "uvtest":
		texture("/ESRI.lib/assets/General/uvtest.png")
		setupProjection(0, scope.xy, 1, 1, 0, 0, 1)
		projectUV(0)
	else: White.
		
 GrassTexture -->
    case grassType== "Lawn 1":
		setupProjection(0, scope.xz, xTextureSize, zTextureSize)
		texture("assets/Lawn 1.jpg")
		projectUV(0)
	else:
		setupProjection(0, scope.xz, xTextureSize, zTextureSize)
		texture("assets/Lawn 2.jpg")
		projectUV(0)

 Hope this helps.

0 Kudos
MattOlsen
Occasional Contributor

Thanks @plfontes - the way you've centred the assets is useful. How are you carving up the original Lot into the individual houses (I can't see this in the CGA) - is that with the in-built subdivision types for the Block?

0 Kudos
plfontes
Regular Contributor

Hi,

The plot shapes were imported from GIS. Not done in CE.
But this rule would have worked the same way if the subdivision was done in CE, although probably less precise.

0 Kudos
MattOlsen
Occasional Contributor

Thank you - sounds like we have a slightly different situation in that I need to generate the plot shapes inside of CE. 

To simplify the original question - I need to fit a rectangle / box of a given depth into another shape - the width should be as long as can fit in that shape.

Any ideas? 

0 Kudos
plfontes
Regular Contributor

One way I can think is to use the offset subdivision to have this level of control over the shape of the plots. But from looking at your images, seems that you have already used it. Another option would be not to use shape subdivision but use the split() operation and fix the size of the split on X and Z axis.

For example, this test rule I created while ago for filling a grid of 9x9m cell size within any given plot using split() instead of subdividing the initial block.

/**
 * File:    grid_test.cga
 * Created: 25 Sep 2022 07:40:38 GMT
 * Author:  PFontes
 */

version "2019.1"

attr gridCellSize = 9
attr setbackAll = 0
@Enum("Global", "Local")
attr alignment = "Global"

@StartRule
Lot -->
	setback(setbackAll){all: NIL | remainder: Parcel}
	
Parcel -->
	case alignment == "Global" :
		alignScopeToAxes(world.xyz)
		split(x){gridCellSize: mirrorScope(false,true,false) set(scope.tz, 5) split(z){gridCellSize: A}*}*
	else :
		alignScopeToGeometry(yUp, any, longest)
		split(x){gridCellSize: mirrorScope(true,false,true) set(scope.tz, -setbackAll) split(z){gridCellSize: A}*}*
	
A -->
	innerRectangle(scope){shape: label("Bldg") B | remainder: NIL}
	
B -->
	case geometry.area <= 60 : NIL
	else: extrude(rand(3,6))

 

Check if any of this can help you. 

0 Kudos
MattOlsen
Occasional Contributor

Thanks @plfontes - appreciate all of your input. I haven't been able to do exactly what I wanted, but using some of your code I've got something close.

 

MattOlsen_0-1688483509121.png

 

plfontes
Regular Contributor

Glad to be of help

0 Kudos