Diagram for .NET / User's Guide / Document Object Model / Models / Shapes / Composite Shapes

Composite Shapes

Composite shapes are shapes, which aggregate multiple primitive models. Composite shapes are represented by the NCompositeShape class, which derives from the NShape class. You can use any primitive model(s) to represent the geometry of a composite shape. That is why composite shapes are often used for custom shapes. Composite shapes are by default treated as 2D shapes.

 Aggregated Primitives
The primitives, which a composite shape aggregates are stored in an instance of the NPrimitiveModelCollection class, which can be obtained from the Primitives property. In this way the geometry of a composite shape can be represented by arbitrary paths and texts.
 Creating a custom shape

The following example shows how to create the following custom shape:

C#
Copy Code
NCompositeShape shape = new NCompositeShape();

// create the cup as a polygon path
NPolygonPath cup = new NPolygonPath(new NPointF[]{new NPointF(45, 268), new NPointF(63, 331), new NPointF(121, 331), new NPointF(140, 268)});
shape.Primitives.AddChild(cup);

// create the cup hangle as a closed curve path
NClosedCurvePath handle = new NClosedCurvePath(new NPointF[]{new NPointF(175, 295), new NPointF(171, 278), new NPointF(140, 283), new NPointF(170, 290), new NPointF(128, 323)}, 1);
NStyle.SetFillStyle(handle, new NColorFillStyle(Color.LightSalmon));
shape.Primitives.AddChild(handle);

// create the steam as a custom filled path
GraphicsPath path = new GraphicsPath();
path.AddBeziers(new PointF[]{new PointF(92, 258), new PointF(53, 163), new PointF(145, 160), new PointF(86, 50), new PointF(138, 194), new PointF(45, 145), new PointF(92, 258)});
path.CloseAllFigures();

NCustomPath steam = new NCustomPath(path, PathType.ClosedFigure);
NStyle.SetFillStyle(steam, new NColorFillStyle(Color.FromArgb(50, 122, 122, 122)));
shape.Primitives.AddChild(steam);

// update the shape model bounds to fit the primitives it contains
shape.UpdateModelBounds();

// create the shape ports
shape.CreateShapeElements(ShapeElementsMask.Ports);

// create dynamic port anchored to the cup center
NDynamicPort dynamicPort = new NDynamicPort(cup.UniqueId, ContentAlignment.MiddleCenter, DynamicPortGlueMode.GlueToContour);
shape.Ports.AddChild(dynamicPort);

// create rotated bounds port anchored to the middle right side of the handle
NRotatedBoundsPort rotatedBoundsPort = new NRotatedBoundsPort(handle.UniqueId, ContentAlignment.MiddleRight);
shape.Ports.AddChild(rotatedBoundsPort);

// apply style to the shape
shape.Style.FillStyle = new NColorFillStyle(Color.LightCoral);
Visual Basic
Copy Code
Dim shape As New NCompositeShape

' create the cup as a polygon path
Dim cup As NPolygonPath = New NPolygonPath(New NPointF() {New NPointF(45, 268), New NPointF(63, 331), New NPointF(121, 331), New NPointF(140, 268)})
shape.Primitives.AddChild(cup)

' create the cup hangle as a closed curve path
Dim handle As NClosedCurvePath = New NClosedCurvePath(New NPointF() {New NPointF(175, 295), New NPointF(171, 278), New NPointF(140, 283), New NPointF(170, 290), New NPointF(128, 323)}, 1)
NStyle.SetFillStyle(handle, New NColorFillStyle(Color.LightSalmon))
shape.Primitives.AddChild(Handle)

' create the steam as a custom filled path
Dim path As New GraphicsPath
path.AddBeziers(New PointF() {New PointF(92, 258), New PointF(53, 163), New PointF(145, 160), New PointF(86, 50), New PointF(138, 194), New PointF(45, 145), New PointF(92, 258)})
path.CloseAllFigures()

Dim steam As New NCustomPath(path, PathType.ClosedFigure)
NStyle.SetFillStyle(steam, New NColorFillStyle(Color.FromArgb(50, 122, 122, 122)))
shape.Primitives.AddChild(steam)

' update the shape model bounds to fit the primitives it contains
shape.UpdateModelBounds()

' create the shape ports
shape.CreateShapeElements(ShapeElementsMask.Ports)

' create dynamic port anchored to the cup center
Dim dynamicPort As New NDynamicPort(cup.UniqueId, ContentAlignment.MiddleCenter, DynamicPortGlueMode.GlueToContour)
shape.Ports.AddChild(dynamicPort)

' create rotated bounds port anchored to the middle right side of the handle
Dim rotatedBoundsPort As New NRotatedBoundsPort(Handle.UniqueId, ContentAlignment.MiddleRight)
shape.Ports.AddChild(rotatedBoundsPort)

' apply style to the shape
shape.Style.FillStyle = New NColorFillStyle(Color.LightCoral)

The coffee cup shape consist of three parts: cup, handle and steam. They are represented by three different types of primitives.

It is important to remember that you must call the UpdateModelBounds method of the composite shape once you have finished adding primitives to it. This is necessary in order for the shape to adopt the bounds of the primitives it contains (see Models for more information about aggregate models bounds).

 Composition

Composition is the process of creating of a new composite shape, which contains clonings of all the primitives contained in other shapes. This operation is primary used for the creation of a custom shape from a set of primitive shapes, but you can generally compose any set of shape - including other composite shapes. 

This operation is implemented by the NBatchCompose class - the implementation internally calls the Compose method of each shape.

Composition preserves the scene transformation of the original primitives. The cloned primitives adopt the style of the shapes, which contained the original primitives. The composed shapes must have a compose permission.

 Decomposition
Decomposition is the process of creating of a primitive shape for each primitive model aggregated by a set of shapes. For example decomposing the coffee cup shape will create three shapes: one polygon shape, one closed curve path shape and one composite shape with a single custom path primitive (note that the there is currently no primitive shape, which can aggregate a single custom path).

This operation is  implemented by the NBatchDecompose class - the implementation internally calls the Decompose method of each shape.

It is the primitive models, not the shapes, which determine what type of shape must be created. That is why each primitive model is responsible for overriding the CreateShape method declared in the NPrimitiveModel class.

Decomposition preserves the scene transformation of the primitives. If there is a local style applied to a primitive model it will be applied to the created shape. The decomposed shapes must have a decompose permission.
 Related Examples
Windows Forms: Document Object Model - Shapes - Custom Shapes
See Also