comp operation

Syntax

comp(component) { selector operator operations | selector operator operations ... }

Parameters

Description

The comp operation (component split) allows to divide a shape into its topological components, which are either faces, edges, face edges, vertices, groups, materials or holes. The components can be selected using either their index or a set of selectors. Group and material components satisfy a specific selection keyword if at least one geometric component (usually a face) satifies it. The selected components are transformed to a new shape and processed by a sequence of shape operations. Depending on the operator, either one shape is created for each individual selected component (":") ore one shape for the whole set of selected components ("=").

The selection parameters of a component split work in a excluding manner: if a parameter has selected a specific component, this component cannot be part of another selection (from left to right).

The local coordinate systems (pivot and scope) of the newly generated shapes are aligned according to the geometry's topology; the component split is one of the few shape operations which manipulate the pivot of a shape.

fIn the case of a face component split, the x-axis is directed as the first edge of the face and the z-axis points along the face normal. The pivot is positioned at the first vertex of the first edge of the face; the scope is the bounding box of the face, i.e. the z-dimension of the emerging shape's scope is set to zero. See an example.
eIn the case of an edge component split, the x-axes of the pivot and scope are along the edge and the z-axes points along the average of the neighboring face normals. The y- and z-dimension of the scope are set to zero and the x-dimension is the length of the edge. The pivot is positioned at one of the endpoints of the edge. The indexing of edges is as follows: Index 0 is the first edge of the first face, index 1 the second edge of the first face etc. Shared edges are skipped on second encounter. See an example.
feIn contrast to edges, face edges are considered separate for each face. Similarly, indexing is done firstly per face and secondly per edge, but shared edges are not skipped. Furthermore, contrary to edges, face edges have a unique direction determined by the orientation of the face they belong to. The x-axes of the pivot and the scope are directed in face orientation and the z-axes point out of the face orthogonally to the edge and the face normal. The pivot is positioned at the first vertex of the face edge. See an example.
vIn case of a vertex component split, the pivot is positioned at the vertex, the z-axes points along the average of the neighboring face normals and all scope dimensions are set to zero. See an example.

Comp shape attributes

Each generated shape has a number of comp shape attributes set. For more information see comp attribute.

Trim Planes

Additionally, for faces, the component split generates trim planes. Trim planes are placed along the shared edges of the new faces in a bisecting angle. The purpose of trim planes is twofold. On one side, trimming handles geometry intersections on the boundary of two neighboring faces, and on the other side, trimming is used to handle non-rectangular faces. The trim planes are applied using the insert operation, primitive operations, or the trim operation.

According to the direction of the shared edge, trim planes are classified into horizontal and vertical planes. They can be switched on or off by setting the trim attribute to true or false. By default, trimming is activated for vertical trim planes and deactivated for horizontal trim planes. Check the trim planes examples below.

Trim planes are only generated if the : operator is used!

Trim planes can be configured in the Procedural Runtime preferences.

Occluder shape

An occluder shape is automatically generated before the component split is applied. The occluder shape is made available for unlabeled occlusion queries.

Roof Edges

There is a number of selectors which are designed to classify typical roof edges:
eaveHorizontal border edges on the bottom of the roof. The edges are always oriented anti-clockwise around the original face.
hipInside edges connected to at least one eave edge. Hip edges are always oriented upwards, i.e. the ending point has larger y-coordinate than the starting point.
valleyInside edges where the two connected faces form a concavity. Valley edges are always oriented upwards, i.e. the ending point has larger y-coordinate than the starting point.
ridgeInside edges which are not hip or valley. Ridge edges are always oriented upwards, i.e. the ending point has larger y-coordinate than the starting point.

These selectors can only be applied on edge component splits!

The figure below shows a few examples.

Roof Edge Selectors

Street Selectors

Components adjacent to a street can be selected with the street.front selector, rear components can be selected with the street.back selector, and components in between front and back can be selected with the street.left and street.right selectors. street.side combines left and right components.

Street Selectors Street Selectors (many of them)
The picture above shows some examples for the street.xxx selectors.

These selectors depend on the availability of the streetWidth attribute map; see Auto-generated street width attributes. If the attribute is not available, component selection falls back to the object.xxx selectors.

Related

Examples

Facade Selection / Face Split Details


Facade selection a
Let us split the mass model of a building into the main facade and a number of side facades.
Note the orientation of the pivot (the annotated axes).


Facade selection b
Building -->	
   comp(f) { 
      front : color("#ff0000") Main. | 
      side  : color("#0000ff") Side. 
   }
   

Facade selection c
Each face is now the geometry of a new shape; the new shapes' scopes and pivots depend on the faces' orientation. The x-axis points along the first edge and the z-axis points along the face normal. The scope's z-dimension is zero.

Selectors 1: Quadrant-based


comp split selectors 1
Sphere -->
   comp(f) {
      top:    color("#0000ff") X. |	
      bottom: color("#ffff00") X. |	
      front:  color("#ff0000") X. | 
      back:   color("#ff00ff") X. |
      left:   color("#00ffff") X. |
      right:  color("#00ff00") X.	
   }
   
Selectors are demonstrated by using them to color the faces of a spherical geometry. The selection is relative to the local coordinate system (the shown scope).

Selectors 2: Angle to y-axis based


comp split selectors 2
Sphere -->
      comp(f) {
      horizontal: color("#0000ff") X. |	
      aslant:     color("#ff0000") X. | 
      vertical:   color("#ffff00") X. |	
      nutant:     color("#ff00ff") X. 
   }
	
Note the horizontal areas (blue) on the sphere's poles.

Logical selection expressions


comp_selExpr_1
Sphere --> comp(f) { top || front = X. }
	
Static selectors can be used in a logical selector expression. Here both the top and front faces are combined into a single shape.

comp_selExpr_2

Triangle -->
   comp(f) { geometry.area() > 1 && !inside : X. }
   
Here, only faces with a surface area greater than 1 and that are not inside are selected.

comp_selExpr_3

mySelectorFunc = 
    geometry.isOriented(top) || geometry.nVertices==3

Sphere -->
   comp(f) { mySelectorFunc : X. }
   
Here, a custom function is used to select the top faces and all faces with exactly 3 vertices.

Index-based Selection


Index selectors a
A mesh can also be disassembled into its components by addressing them directly by their index.
The indexing scheme is inherently encoded in the model itself!

Index selectors b
Tube -->
   comp(f) { 
      0 : X. | 
      2 : X. | 
      4 : X. 
   }
   
Here, only faces 0, 2 and 4 of the cylinder are selected.

Trim Planes


Trim Planes a
Start -->
   s(10,10,10)
   primitiveCube()
   comp(f) { 5 : X. }
	
At shared edges, trim planes (green) are inserted.

Trim Planes b
X -->
   s(15,'1, 2)
   center(xyz)
   primitiveCube()
	
Inserted geometry is cut with the trim planes.

Trim Planes c
Start -->
   s(10,10,10)
   primitiveCube()
   set(trim.horizontal, true)
   comp(f) { 5 : X. }
	
By default, horizontal trim planes are off. Enabling them before inserting the geometry gives a different result.

The Operator


Comp Operator :
            
            
            
Lot -->
   extrude(20)
   comp(f) { side : Sides. }
	

Using the ":" operator results in a new shape for each component selected by the selector.
In the example above, a shape is created for each side of the extruded geometry. Therefore, the Lot Shape has five successors (one for each side). Each successor shape has its pivot and scope set up differently.


Comp Operator :
            
            
            
Lot -->
   extrude(20)
   comp(f) { side = Sides. }
	

In contrast, using the "=" operator results in exactly one new shape for all component selected by the selector.
In the example above, one shape is created for all five sides of the extruded geometry. Thje new shape's geometry contains all five faces, and the pivot and scope are set up relative to the first selected face.

Border and Inside Selectors


Border Selector Initial Shape



The picture on the left shows the initial shape. It is a subdivided plane, consisting of a number of faces.


Border Selector Face Split
Init -->
   comp(f) { border : FBorder | inside : FInside  }
   
FBorder -->
   color("#ff0000")
	
FInside -->
   color("#00ff00")
	

The example selects the border and inside faces and colors them.


Border Selector Edge Split
Init-->
   comp(e) { border : EBorder | inside : EInside  }

EBorder --> s('1, 0.05, 0.05) t(0, '-0.5, 0)
            color("#ff0000") primitiveCube()
	
EInside --> s('1, 0.01, 0.01) t(0, '-0.5, 0)
            color("#00ff00") primitiveCube()
	

Here, there border and inside edges are selected and colored cubes are inserted.


Border Selector Vertex Split
            
Init -->
   comp(v) { border : VBorder | inside : VInside  }
   
VBorder --> s(0.05, 0.05, 0.05) t(-0.025, -0.025, -0.025)
            color("#ff0000") primitiveCube()
   
VInside --> s(0.05, 0.05, 0.05) t(-0.025, -0.025, -0.025)
            color("#00ff00") primitiveCube()
	

Finally, the border and inside vertices are used to insert colored cubes.

isTagged Selector


Comp isTagged Faces
Init --> envelope(normal,4, 0,45, 3,45, 2.5,50, 2,50)
         ShowEnvelopeAutoTags
         
ShowEnvelopeAutoTags -->
    comp(f) { isTagged("envelope.bottom")     : Blue 
            | isTagged("envelope.side.base")  : Yellow
            | isTagged("envelope.side.slope") : Orange
            | isTagged("envelope.side.inner") : Red
            | isTagged("envelope.top")        : Green } 
	
This example colors the face components based on the face tags applied by the envelope operation.


Comp isTagged Faces 2


Init --> envelope(normal,4, 0,45, 3,45, 2.5,50, 2,50)
         comp(f) { isTagged("envelope.side") : Yellow }
	

Here, the tag query "envelope.side" is used to select and color all base, slope and inner side faces at once.


Comp isTagged Edges


Init --> envelope(normal,4, 0,45, 3,45, 2.5,50, 2,50)
         comp(e) { isTagged("envelope.top") : Edge }
         
Edge --> s('1, 0.5, 0.5) center(yz)
         color("#09de1f") primitiveCube()
	

Here, the edges of the face tagged "envelope.top" are selected and colored cubes are inserted.

.


Comp isTagged Vertices


Init --> envelope(normal,4, 0,45, 3,45, 2.5,50, 2,50)
         comp(v) { isTagged("envelope.top") : Edge }
         
Edge --> s(0.5, 0.5, 0.5) center(xyz)
         color("#09de1f") primitiveSphere(8,6)
	

Here, the vertices of the face tagged "envelope.top" are selected and colored spheres are inserted.

By default, edges can be selected based on the tags of adjacent faces, while vertices can be selected based on the tags of adjacent faces and edges. However, to select faces based on the tags of their edges or vertices, the subcomponent parameter must be provided, as demonstrated in the section below.

Advanced Tag Selection


Comp isTagged With Subcomp1
            
Init --> envelope(normal,4, 0,45, 3,45, 2.5,50, 2,50)
         comp(f) { isTagged("envelope.bottom", e) 
            : ShowEnvelopeAutoTags }
	

By using the e subcomponent selector, all faces that share an edge with a face tagged "envelope.bottom" or have an edge tagged as such, are selected.

Note that the face tagged "envelope.bottom" (blue) is selected as well.


BComp isTagged With Subcomp2
            
Init --> envelope(normal,4, 0,45, 3,45, 2.5,50, 2,50)
         comp(f) { isTagged("envelope.bottom", e) &&
                   isTagged("envelope.side.slope") 
            : ShowEnvelopeAutoTags }
	

This example selects all slope faces that are edge-adjacent to the bottom face.


BComp isTagged With Subcomp2
            
Init --> envelope(normal,4, 0,45, 3,45, 2.5,50, 2,50)
         comp(e) { isTagged("envelope.bottom", v)
            : Edge }
            
Edge --> s('1, 0.5, 0.5) center(yz)
         color("#09de1f") primitiveCube()
	

This example selects all edges that share a vertex with the bottom face and inserts colored cubes.

Edge Split Details


Edge Split
	
Lot --> extrude(3) 
        comp(e) { all : primitiveCube() s('1, 0.25, 1) X. }
	

A building mass model is split into its edges, and the built-in cube model is inserted into each edge shape. The pivot of the new shape is positioned at one of the edge's vertices, and the alignment is as follows: the x-axis is parallel to the edge, the z-axis is the average of the neighboring face normals and the y-axis is normal to the two former ones. The scope has zero translation and rotation, and the sizes are (edge-length, 0, 0).


Edge Split
	
	
	
Lot --> extrude(3) 
        comp(fe) { all : primitiveCube() s('1, 0.25, 1) X. }
	

A split into face edges creates more components, for each face the edges are considered separately. Edges are oriented wrt. face orientations. The pivot is now set to the edge's start vertex and the x-axis points in face orientation, the z-axis is pointing out of the face orthogonally to the edge and the face normal.

Vertex Split Details


Edge Split
Lot -->
   extrude(10) 
   MassModel
   comp(v) { all : VShapes. }
	

A building mass model is split into its vertices.
The pivot of the new shape (the VShapes in the rule above) is set to the vertex position, and the alignment is as follows: the z-axis is the average of the neighboring face normals and the x- and y-axes are chosen such that they are all normal to each other.
The scope has zero translation, rotation and size.

Group Split Details


Group Split



Lot -->
   i("Orange_Tree.obj") 
   comp(g) { findFirst(geometry.materials,"Bark") : Trunk.
           | all = set(material.opacity, 0.2) Foliage. }
	

A tree model is split into its groups.

Material Split Details


Material Split



Lot -->
   i("Orange_Tree.obj") 
   comp(m) { findFirst(geometry.materials,"Foliage") : Oranges. 
           | findFirst(geometry.materials,"Bark")    : Trunk. }
	

A tree model is split into its materials. In this case groups and materials are the same.

Copyright ©2008-2023 Esri R&D Center Zurich. All rights reserved.