In this tutorial, we will generate slices from a 3d model and arrange them next to each other in one layer. This approach will work with any three-dimensional object; here we use a cone. The slices result from an intersection of the model with an array of planes. The generated section curves could be used for plotting or a CNC router.

## Grasshopper

#### 1

##### Define initial geometric object

To start, we need a shape and in the following we will use a cone to illustrate
the procedure. Thus, we place a ConeInputs Base (B) Base plane Radius (R) Radius at cone base Length (L) Cone height Outputs Cone (C) Resulting cone Tip (T) Tip of cone `10`

to the radius **R** and length **L**. By attaching an ExtrudeInputs Base (B) Profile curve or surface Direction (D) Extrusion direction Outputs Extrusion (E) Extrusion result **D** of the extrusion is given by a Unit ZInputs Factor (F) Unit multiplication Outputs Unit vector (V) World {z} vector *material thickness* of `-1`

. A Bounding BoxInputs Content (C) Geometry to contain Plane (P) BoundingBox orientation plane Outputs Box (B) Aligned bounding box in world coordinates Box (B) Bounding box in orientation plane coordinates ^{}Inputs Content (C) Geometry to contain Plane (P) BoundingBox orientation plane Outputs Box (B) Aligned bounding box in world coordinates Box (B) Bounding box in orientation plane coordinates *Union Box* selected. This will wrap all objects in a single box.^{}By default, the Bounding BoxInputs Content (C) Geometry to contain Plane (P) BoundingBox orientation plane Outputs Box (B) Aligned bounding box in world coordinates Box (B) Bounding box in orientation plane coordinates *Union Box* selected. This will wrap all objects in a single box.
To change the orientation of the *bounding box* (and so the direction of the
slices), we could provide a plane at input **P**.

#### 2

##### Generate section planes

To define section planes, we need an array of points that serve as origins for
the planes. To find these points, we use Evaluate BoxInputs Box (B) Base box U parameter (U) {u} parameter (values between 0.0 and 1.0 are inside the box) V parameter (V) {v} parameter (values between 0.0 and 1.0 are inside the box) W parameter (W) {w} parameter (values between 0.0 and 1.0 are inside the box) Outputs Plane (Pl) Plane at {uvw} coordinate Point (Pt) Point at {uvw} coordinate Include (I) True if point is inside or on box **U** and **V**. The parameters have to be normalized
(between *0* and *1*).

The component RangeInputs Domain (D) Domain of numeric range Steps (N) Number of steps Outputs Range (R) Range of numbers **N** values within the domain
**D**. By default, the domain is `0 To 1`

and `10`

ascending values are created.
This is good enough for this exercise, but we need to use Cull IndexInputs List (L) List to cull Indices (I) Culling indices Wrap (W) Wrap indices to list range Outputs List (L) Culled list *0*) and last value (*-1*), which are the faces of the
box. Then we connect the output of *Range* to the inputs **U** and **V** of
*Evaluate Box*. This will give us the desired origin points at output **Pt** and
we can connect a YZ PlaneInputs Origin (O) Origin of plane Outputs Plane (P) World YZ plane Inputs Origin (O) Origin of plane Outputs Plane (P) World XZ plane

#### 3

##### Compute section curves

While working with a Grasshopper algorithm, we have to ensure the data
structures match the planed operation. In this case, we need a data treeInputs Branch {0;0} ({0;0}) Data to entwine Branch {0;1} ({0;1}) Data to entwine Branch {0;2} ({0;2}) Data to entwine Outputs Result (R) Entwined result

Next, we place a Brep | PlaneInputs Brep (B) Base Brep Plane (P) Section plane Outputs Curves (C) Section curves Points (P) Section points **C** we find
the curves that are created by solving the intersection event. But, each curve
is in a separate branch and we need Trim TreeInputs Tree (T) Data tree to flatten Depth (D) Number of outermost branches to merge Outputs Tree (T) Trimmed data tree

#### 4

##### Get dimensions for arranging the curves in a plane

In the second half of this tutorial, we will arrange the slices in a single
plane and next to each other, thus preparing them to be plotted on a sheet of
paper. For this, we need coordinates for each slice that prevent overlapping of
section curves. To get the dimensions, we use Plane Through ShapeInputs Plane (P) Surface plane Shape (S) Shape to exceed Inflate (I) Boundary inflation amount Outputs Surface (S) Resulting planar surface **P** for each curve **S**. ^{}Inputs Plane (P) Surface plane Shape (S) Shape to exceed Inflate (I) Boundary inflation amount Outputs Surface (S) Resulting planar surface Inputs Content (C) Geometry to contain Plane (P) BoundingBox orientation plane Outputs Box (B) Aligned bounding box in world coordinates Box (B) Bounding box in orientation plane coordinates ^{}The component Plane Through ShapeInputs Plane (P) Surface plane Shape (S) Shape to exceed Inflate (I) Boundary inflation amount Outputs Surface (S) Resulting planar surface Inputs Content (C) Geometry to contain Plane (P) BoundingBox orientation plane Outputs Box (B) Aligned bounding box in world coordinates Box (B) Bounding box in orientation plane coordinates Inputs Surface (S) Surface to measure Outputs U dimension (U) Approximate dimension in U direction V dimension (V) Approximate dimension in V direction

#### 5

##### Find coordinates in x-direction

As stated, the coordinates for each slice on our base place depend on the
dimensions of the section curves. Here, we would like to have two rows of
section profiles, separated for each slicing direction. In x-direction we will
place the curves from the same set and their distance is given by the height of
each slice. The heights are obtained from output **V** of DimensionsInputs Surface (S) Surface to measure Outputs U dimension (U) Approximate dimension in U direction V dimension (V) Approximate dimension in V direction

The list of x-coordinates ought to start at *0*, but currently starts with the
first height. Therefore, we use Shift ListInputs List (L) List to shift Shift (S) Shift offset Wrap (W) Wrap values Outputs List (L) Shifted list `-1`

. Then we use Replace ItemsInputs List (L) List to modify Item (I) Items to replace with. If no items are supplied, nulls will be inserted. Indices (i) Replacement index for each item Wrap (W) If true, indices will be wrapped Outputs List (L) List with replaced values *0*) in the
list with `0`

.

The component Mass AdditionInputs Input (I) Input values for mass addition. Outputs Result (R) Result of mass addition Partial Results (Pr) List of partial results **Pr**. This is what we will use for
the x-coordinates.

#### 6

##### Find coordinates in y-direction

For the coordinates in y-direction, we will use a different approach, because
here we will just have two rows, one for each set of curves. The distance of the
rows is given by the largest width in the first set. The widths can be found at
output **U** of DimensionsInputs Surface (S) Surface to measure Outputs U dimension (U) Approximate dimension in U direction V dimension (V) Approximate dimension in V direction Inputs Data (D) Data to explode Outputs Branch 0 (-) All data inside the branch at index: 0 Branch 1 (-) All data inside the branch at index: 1 **{0,0}**, which is also the first row of section curves.

To find the largest width, we use Sort ListInputs Keys (K) List of sortable keys Values A (A) Optional list of values to sort synchronously Outputs Keys (K) Sorted keys Values A (A) Synchronous values in A Inputs List (L) Base list Index (i) Item index Wrap (W) Wrap index to list bounds Outputs Item (i) Item at {i'} *Reverse* its input **L** to find the largest value. This will become
the y-coordinate for the second row. The first row starts at `0`

and we use EntwineInputs Branch {0;0} ({0;0}) Data to entwine Branch {0;1} ({0;1}) Data to entwine Branch {0;2} ({0;2}) Data to entwine Outputs Result (R) Entwined result

#### 7

##### Arrange slices in a plane

After calculating the coordinates for each slice, we arrange them all in a
single plane. To convert the coordinates to actual points, we will use Construct PointInputs X coordinate (X) {x} coordinate Y coordinate (Y) {y} coordinate Z coordinate (Z) {z} coordinate Outputs Point (Pt) Point coordinate **X** and **Y** with the results
from the previous two steps.

To place the section curves at their coordinates, we use OrientInputs Geometry (G) Base geometry Source (A) Initial plane Target (B) Final plane Outputs Geometry (G) Reoriented geometry Transform (X) Transformation data **G** takes the geometric objects (our curves), input **A** the reference
planes (result of *Plane Through Shape*) and input **B** the target planes
(generated by connecting our coordinates).

The result of this tutorial could now be plotted or fabricated with a CNC machine

## Test your skills

In the tutorial above, there was **one** geometric object to be sliced. Usually,
we have more than one and now it’s your turn to tweak the algorithm so that it
can handle several geometric objects. The section profiles on the base plane
should contain all curves from one section. To keep it simple, let’s add a
sphere to the tip of the cone.

### Connect the sphere

To include the sphere, we connect it
to input **C** of Bounding BoxInputs Content (C) Geometry to contain Plane (P) BoundingBox orientation plane Outputs Box (B) Aligned bounding box in world coordinates Box (B) Bounding box in orientation plane coordinates **B** of the component
Brep | PlaneInputs Brep (B) Base Brep Plane (P) Section plane Outputs Curves (C) Section curves Points (P) Section points

### Fix data structure

To change the data handling, we
right-click the component Bounding BoxInputs Content (C) Geometry to contain Plane (P) BoundingBox orientation plane Outputs Box (B) Aligned bounding box in world coordinates Box (B) Bounding box in orientation plane coordinates *Union
Box*. This will create one box around all objects and not wrap each object with
its own box.

Also, we have *graft* input **P** of Brep | PlaneInputs Brep (B) Base Brep Plane (P) Section plane Outputs Curves (C) Section curves Points (P) Section points **B** will be matched
with every plane. This change will lead to an error: the component is displayed
in red and states “Intersection failed”. But, this result is correct and could
have been expected; the radius of the sphere is not large enough for it to have
an intersection event with all the planes. We can ignore this *error*.

In the Rhino viewport, we can see that the arrangement on one layer is not yet
working as expected. This is caused by the changed data structure; Plane Through ShapeInputs Plane (P) Surface plane Shape (S) Shape to exceed Inflate (I) Boundary inflation amount Outputs Surface (S) Resulting planar surface

### Capture the items in a single plane

The problem is that
Plane Through ShapeInputs Plane (P) Surface plane Shape (S) Shape to exceed Inflate (I) Boundary inflation amount Outputs Surface (S) Resulting planar surface Inputs Brep (B) Base Brep Plane (P) Section plane Outputs Curves (C) Section curves Points (P) Section points Inputs Tree (T) Data tree to flatten Depth (D) Number of outermost branches to merge Outputs Tree (T) Trimmed data tree *Plane Through Shape* creates a bounding rectangle for each item, but
this is not what we want. Instead, we need a bounding rectangle both around
items.

The *Plane Through Shape* component has no option for this and we use another
Bounding BoxInputs Content (C) Geometry to contain Plane (P) BoundingBox orientation plane Outputs Box (B) Aligned bounding box in world coordinates Box (B) Bounding box in orientation plane coordinates *Union Box* selected. This way, we get
flat boxes with no height. We have to reduce them by a branch level with Trim TreeInputs Tree (T) Data tree to flatten Depth (D) Number of outermost branches to merge Outputs Tree (T) Trimmed data tree Inputs Plane (P) Surface plane Shape (S) Shape to exceed Inflate (I) Boundary inflation amount Outputs Surface (S) Resulting planar surface ^{}*Bounding Box* to *Plane Through Shape*,
which is kind of an unnecessary repetition, we could have also extracted the
right face from the box. But, more component would be needed.^{}Instead of connecting the results from *Bounding Box* to *Plane Through Shape*,
which is kind of an unnecessary repetition, we could have also extracted the
right face from the box. But, more component would be needed.

As we can see, we still need to adjust OrientInputs Geometry (G) Base geometry Source (A) Initial plane Target (B) Final plane Outputs Geometry (G) Reoriented geometry Transform (X) Transformation data *grafing* inputs **A** and **B**. Done.