Custom Shape
Change a Shape Using Edit Points
Consider a square. In PowerPoint, using edit points, you can
- move the square’s corner in or out
- specify the curvature for a corner or point
- add new points to the square
- manipulate points on the square, etc.
Essentially, you can perform the described tasks on any shape. Using edit points, you get to change a shape or create a new shape from an existing shape.
Shape Editing Tips
Before you start editing PowerPoint shapes through edit points, you might want to consider these points about shapes:
- A shape (or its path) can either be closed or open.
- When a shape is closed, it lacks a start or end point. When a shape is open, it has a beginning and end.
- All shapes consist of at least 2 anchor points linked to each other by lines
- A line is either straight or curved. Anchor points determine the nature of the line.
- Anchor points exist as corner points, straight points, or smooth points:
- A corner point is a point where 2 straight lines join at an angle.
- A smooth point is a point where 2 handles exist in a straight line and the line’s segments join in a smooth curve. In this case, all handles are separated from the anchor point by an equal distance.
- A straight point is a point where 2 handles exist in a straight line and that line’s line segments joins in a smooth curve. In this case, the handles don’t have to be separated from the anchor point by an equal distance.
- By moving or editing anchor points (which changes the angle of lines), you can change the way a shape looks.
To edit PowerPoint shapes through edit points, Aspose.Slides provides the GeometryPath class and IGeometryPath interface.
- A GeometryPath instance represents a geometry path of the IGeometryShape object.
- To retrieve the
GeometryPath
from theIGeometryShape
instance, you can use the IGeometryShape::GetGeometryPaths method. - To set the
GeometryPath
for a shape, you can use these methods: IGeometryShape::SetGeometryPath() for solid shapes and IGeometryShape::SetGeometryPaths() for composite shapes. - To add segments, you can use the methods under IGeometryPath.
- Using the IGeometryPath::set_Stroke() and IGeometryPath::set_FillMode() methods, you can set the appearance for a geometry path.
- Using the IGeometryPath::get_PathData() method, you can retrieve the geometry path of a
GeometryShape
as an array of path segments. - To access additional shape geometry customization options, you can convert GeometryPath to GraphicsPath
- Use GeometryPathToGraphicsPath and GraphicsPathToGeometryPath methods (from the ShapeUtil class) to convert GeometryPath to GraphicsPath back and forth.
Simple Editing Operations
This C++ code shows you how to
Add a line to the end of a path
void LineTo(PointF point);
void LineTo(float x, float y);
Add a line to a specified position on a path:
void LineTo(PointF point, uint32_t index);
void LineTo(float x, float y, uint32_t index);
Add a cubic Bezier curve at the end of a path:
void CubicBezierTo(PointF point1, PointF point2, PointF point3);
void CubicBezierTo(float x1, float y1, float x2, float y2, float x3, float y3);
Add a cubic Bezier curve to the specified position on a path:
void CubicBezierTo(PointF point1, PointF point2, PointF point3, uint32_t index);
void CubicBezierTo(float x1, float y1, float x2, float y2, float x3, float y3, uint32_t index);
Add a quadratic Bezier curve at the end of a path:
void QuadraticBezierTo(PointF point1, PointF point2);
void QuadraticBezierTo(float x1, float y1, float x2, float y2);
Add quadratic Bezier curve to a specified position on a path:
void QuadraticBezierTo(PointF point1, PointF point2, uint32_t index);
void QuadraticBezierTo(float x1, float y1, float x2, float y2, uint32_t index);
Append a given arc to a path:
void ArcTo(float width, float heigth, float startAngle, float sweepAngle);
Close the current figure of a path:
void CloseFigure();
Set the position for the next point:
void MoveTo(PointF point);
void MoveTo(float x, float y);
Remove the path segment at a given index:
void RemoveAt(int32_t index);
Add Custom Points to Shape
- Create an instance of the GeometryShape class and set the ShapeType.Rectangle type.
- Get an instance of the GeometryPath class from the shape.
- Add a new point between the two top points on the path.
- Add a new point between the two bottom points on the path.
- Apply the path to the shape.
This C++ code shows you how to add custom points to a shape:
SharedPtr<Presentation> pres = System::MakeObject<Presentation>();
SharedPtr<IShapeCollection> shapes = pres->get_Slides()->idx_get(0)->get_Shapes();
SharedPtr<GeometryShape> shape = System::ExplicitCast<GeometryShape>(shapes->AddAutoShape(ShapeType::Rectangle, 100.0f, 100.0f, 200.0f, 100.0f));
SharedPtr<IGeometryPath> geometryPath = shape->GetGeometryPaths()->idx_get(0);
geometryPath->LineTo(100.0f, 50.0f, 1);
geometryPath->LineTo(100.0f, 50.0f, 4);
shape->SetGeometryPath(geometryPath);
Remove Points From Shape
- Create an instance of GeometryShape class and set the ShapeType.Heart type.
- Get an instance of the GeometryPath class from the shape.
- Remove the segment for the path.
- Apply the path to the shape.
This C++ code shows you how to remove points from a shape:
SharedPtr<Presentation> pres = System::MakeObject<Presentation>();
SharedPtr<IShapeCollection> shapes = pres->get_Slides()->idx_get(0)->get_Shapes();
SharedPtr<GeometryShape> shape = System::ExplicitCast<GeometryShape>(shapes->AddAutoShape(ShapeType::Heart, 100.0f, 100.0f, 300.0f, 300.0f));
SharedPtr<IGeometryPath> path = shape->GetGeometryPaths()->idx_get(0);
path->RemoveAt(2);
shape->SetGeometryPath(path);
Create Custom Shape
- Calculate the points for the shape.
- Create an instance of the GeometryPath class.
- Fill the path with the points.
- Create an instance of the GeometryShape class.
- Apply the path to the shape.
This C++ code shows you how to create a custom shape:
SharedPtr<List<PointF>> points = System::MakeObject<List<PointF>>();
float R = 100.0f, r = 50.0f;
int32_t step = 72;
for (int32_t angle = -90; angle < 270; angle += step)
{
double radians = angle * (Math::PI / 180.f);
double x = outerRadius * Math::Cos(radians);
double y = outerRadius * Math::Sin(radians);
points->Add(PointF((float)x + outerRadius, (float)y + outerRadius));
radians = Math::PI * (angle + step / 2) / 180.0;
x = innerRadiusr * Math::Cos(radians);
y = innerRadiusr * Math::Sin(radians);
points->Add(PointF((float)x + outerRadius, (float)y + outerRadius));
}
SharedPtr<GeometryPath> starPath = System::MakeObject<GeometryPath>();
starPath->MoveTo(points->idx_get(0));
for (int32_t i = 1; i < points->get_Count(); i++)
{
starPath->LineTo(points->idx_get(i));
}
starPath->CloseFigure();
SharedPtr<Presentation> pres = System::MakeObject<Presentation>();
SharedPtr<IShapeCollection> shapes = pres->get_Slides()->idx_get(0)->get_Shapes();
SharedPtr<GeometryShape> shape = System::ExplicitCast<GeometryShape>(shapes->AddAutoShape(ShapeType::Rectangle, 100.0f, 100.0f, R * 2, R * 2));
shape->SetGeometryPath(starPath);
Create Composite Custom Shape
- Create an instance of the GeometryShape class.
- Create a first instance of the GeometryPath class.
- Create a second instance of the GeometryPath class.
- Apply the paths to the shape.
This C++ code shows you to create a composite custom shape:
SharedPtr<Presentation> pres = System::MakeObject<Presentation>();
SharedPtr<IShapeCollection> shapes = pres->get_Slides()->idx_get(0)->get_Shapes();
SharedPtr<GeometryShape> shape = System::ExplicitCast<GeometryShape>(shapes->AddAutoShape(ShapeType::Rectangle, 100.0f, 100.0f, 200.0f, 100.0f));
SharedPtr<IGeometryPath> geometryPath0 = System::MakeObject<GeometryPath>();
geometryPath0->MoveTo(0.0f, 0.0f);
geometryPath0->LineTo(shape->get_Width(), 0.0f);
geometryPath0->LineTo(shape->get_Width(), shape->get_Height() / 3);
geometryPath0->LineTo(0.0f, shape->get_Height() / 3);
geometryPath0->CloseFigure();
SharedPtr<IGeometryPath> geometryPath1 = System::MakeObject<GeometryPath>();
geometryPath1->MoveTo(0.0f, shape->get_Height() / 3 * 2);
geometryPath1->LineTo(shape->get_Width(), shape->get_Height() / 3 * 2);
geometryPath1->LineTo(shape->get_Width(), shape->get_Height());
geometryPath1->LineTo(0.0f, shape->get_Height());
geometryPath1->CloseFigure();
shape->SetGeometryPaths(System::MakeArray<SharedPtr<IGeometryPath>>({ geometryPath0, geometryPath1 }));
Create Custom Shape With Curved Corners
This C++ code shows you how to create a custom shape with curved corners (inwards);
float shapeX = 20.f;
float shapeY = 20.f;
float shapeWidth = 300.f;
float shapeHeight = 200.f;
float leftTopSize = 50.f;
float rightTopSize = 20.f;
float rightBottomSize = 40.f;
float leftBottomSize = 10.f;
auto presentation = System::MakeObject<Presentation>();
auto childShape = presentation->get_Slides()->idx_get(0)->get_Shapes()->AddAutoShape(ShapeType::Custom, shapeX, shapeY, shapeWidth, shapeHeight);
auto geometryPath = System::MakeObject<GeometryPath>();
PointF point1(leftTopSize, 0.0f);
PointF point2(shapeWidth - rightTopSize, 0.0f);
PointF point3(shapeWidth, shapeHeight - rightBottomSize);
PointF point4(leftBottomSize, shapeHeight);
PointF point5(0.0f, leftTopSize);
geometryPath->MoveTo(point1);
geometryPath->LineTo(point2);
geometryPath->ArcTo(rightTopSize, rightTopSize, 180.0f, -90.0f);
geometryPath->LineTo(point3);
geometryPath->ArcTo(rightBottomSize, rightBottomSize, -90.0f, -90.0f);
geometryPath->LineTo(point4);
geometryPath->ArcTo(leftBottomSize, leftBottomSize, 0.0f, -90.0f);
geometryPath->LineTo(point5);
geometryPath->ArcTo(leftTopSize, leftTopSize, 90.0f, -90.0f);
geometryPath->CloseFigure();
childShape->SetGeometryPath(geometryPath);
presentation->Save(u"output.pptx", SaveFormat::Pptx);
Find Out If a Shape Geometry Is Closed
A closed shape is defined as one where all its sides connect, forming a single boundary without gaps. Such a shape can be a simple geometric form or a complex custom outline. The following code example shows how to check if a shape geometry is closed:
bool IsGeometryClosed(SharedPtr<IGeometryShape> geometryShape)
{
bool isClosed = false;
for (auto&& geometryPath : geometryShape->GetGeometryPaths())
{
auto dataLength = geometryPath->get_PathData()->get_Length();
if (dataLength == 0)
continue;
auto lastSegment = geometryPath->get_PathData()[dataLength - 1];
isClosed = lastSegment->get_PathCommand() == PathCommandType::Close;
if (!isClosed)
return false;
}
return isClosed;
}
Convert GeometryPath to GraphicsPath
- Create an instance of the GeometryShape class.
- Create an instance of the GraphicsPath class of the System.Drawing.Drawing2D namespace.
- Convert the GraphicsPath instance to the GeometryPath instance using ShapeUtil.
- Apply the paths to the shape.
This C++ code—an implementation of the steps above—demonstrates the GeometryPath to GraphicsPath conversion process:
SharedPtr<Presentation> pres = System::MakeObject<Presentation>();
SharedPtr<IShapeCollection> shapes = pres->get_Slides()->idx_get(0)->get_Shapes();
SharedPtr<GeometryShape> shape = System::ExplicitCast<GeometryShape>(shapes->AddAutoShape(ShapeType::Rectangle, 100.0f, 100.0f, 300.0f, 100.0f));
SharedPtr<IGeometryPath> originalPath = shape->GetGeometryPaths()->idx_get(0);
originalPath->set_FillMode(PathFillModeType::None);
SharedPtr<Drawing2D::GraphicsPath> graphicsPath = System::MakeObject<Drawing2D::GraphicsPath>();
graphicsPath->AddString(u"Text in shape", System::MakeObject<FontFamily>(u"Arial"), 1, 40.0f, PointF(10.0f, 10.0f), StringFormat::get_GenericDefault());
SharedPtr<IGeometryPath> textPath = ShapeUtil::GraphicsPathToGeometryPath(graphicsPath);
textPath->set_FillMode(PathFillModeType::Normal);
shape->SetGeometryPaths(System::MakeArray<SharedPtr<IGeometryPath>>({ originalPath, textPath }));