Personalizar Formas de Apresentação em C++
Visão geral
Este artigo explica como personalizar formas de apresentação no Aspose.Slides editando a geometria da forma por meio de pontos de edição e caminhos de geometria. Ele mostra como trabalhar com GeometryPath e IGeometryPath para modificar formas existentes, realizar operações básicas de edição de caminho, adicionar ou remover pontos e aplicar a geometria atualizada de volta a uma forma.
Também demonstra como criar formas personalizadas e compostas, construir formas com cantos curvos e determinar se a geometria de uma forma está fechada.
Alterar uma Forma Usando Pontos de Edição
No PowerPoint, você pode usar Pontos de Edição para modificar um quadrado:
- Mover um canto para dentro ou para fora.
- Ajustar a curvatura em um ponto.
- Adicionar novos pontos.
A edição de pontos permite modificar o contorno de uma forma ou usar uma forma existente como base para uma nova.
Dicas de Edição de Forma

Ao editar formas do PowerPoint, tenha em mente estes conceitos:
- Uma forma (ou seu caminho) pode ser fechada ou aberta.
- O caminho de uma forma consiste em pontos âncora conectados por segmentos.
- Um segmento pode ser reto ou curvo. Pontos âncora e alças de controle determinam sua forma.
- Pontos âncora existem como pontos de canto, pontos retos ou pontos suaves:
- Em um ponto de canto, os segmentos adjacentes podem se encontrar em um ângulo.
- Em um ponto suave, as duas alças de controle ficam alinhadas e à mesma distância do ponto âncora.
- Em um ponto reto, as duas alças de controle ficam alinhadas, mas podem ter distâncias diferentes do ponto âncora.
- Mover pontos âncora ou ajustar suas alças altera o contorno da forma.
Para editar formas do PowerPoint por meio de pontos de edição, Aspose.Slides fornece a classe GeometryPath e a interface IGeometryPath.
- Uma instância de GeometryPath representa o caminho de geometria do objeto IGeometryShape.
- Para obter o GeometryPath a partir da instância IGeometryShape, você pode usar o método IGeometryShape::GetGeometryPaths.
- Para definir o GeometryPath de uma forma, você pode usar estes métodos: IGeometryShape::SetGeometryPath para formas com um único caminho e IGeometryShape::SetGeometryPaths para formas com múltiplos caminhos.
- Para adicionar segmentos, você pode usar os métodos sob IGeometryPath.
- Usando os métodos IGeometryPath::set_Stroke e IGeometryPath::set_FillMode, você pode definir a aparência de um caminho de geometria.
- Usando o método IGeometryPath::get_PathData, você pode obter o caminho de geometria de um GeometryShape como um array de segmentos de caminho.
Operações Simples de Edição
Use os métodos a seguir para editar um caminho de geometria. Sobrecargas que aceitam um índice inserem um segmento naquela posição baseada em zero no array de segmentos do caminho.
| Operação | Método |
|---|---|
| Anexar ou inserir uma linha reta. | GeometryPath::LineTo |
| Anexar ou inserir uma curva Bézier cúbica com dois pontos de controle e um ponto final. | GeometryPath::CubicBezierTo |
| Anexar ou inserir uma curva Bézier quadrática com um ponto de controle e um ponto final. | GeometryPath::QuadraticBezierTo |
| Anexar um arco elíptico com as dimensões e ângulos especificados em graus. | GeometryPath::ArcTo |
| Fechar a figura atual conectando seu ponto final ao ponto inicial. | GeometryPath::CloseFigure |
| Definir o ponto inicial de uma figura. | GeometryPath::MoveTo |
| Remover um segmento em um índice baseado em zero. | GeometryPath::RemoveAt |
Adicionar Pontos Personalizados a uma Forma
Este exemplo insere dois pontos em uma forma retangular usando GeometryPath::LineTo e aplica o caminho editado com IGeometryShape::SetGeometryPath. As coordenadas são locais à forma: ambos os novos pontos estão no centro, a 100 pontos da esquerda e 50 pontos do topo. Os índices de segmento 1 e 4 os posicionam nas bordas superior e inferior, puxando essas bordas para dentro.
#include <DOM/IAutoShape.h>
#include <DOM/IGeometryPath.h>
#include <DOM/IShapeCollection.h>
#include <DOM/ISlide.h>
#include <DOM/ISlideCollection.h>
#include <DOM/Presentation.h>
#include <DOM/ShapeType.h>
#include <system/smart_ptr.h>
using namespace Aspose::Slides;
using namespace System;
auto presentation = System::MakeObject<Presentation>();
auto slide = presentation->get_Slide(0);
auto shape = slide->get_Shapes()->AddAutoShape(ShapeType::Rectangle, 100.0f, 100.0f, 200.0f, 100.0f);
auto geometryPath = shape->GetGeometryPaths()->idx_get(0);
geometryPath->LineTo(100.0f, 50.0f, 1);
geometryPath->LineTo(100.0f, 50.0f, 4);
shape->SetGeometryPath(geometryPath);

Remover Pontos de uma Forma
Este exemplo altera o contorno de um coração removendo o segmento no índice baseado em zero 2 com GeometryPath::RemoveAt. Aplicar o caminho modificado com IGeometryShape::SetGeometryPath atualiza o contorno da forma.
#include <DOM/IAutoShape.h>
#include <DOM/IGeometryPath.h>
#include <DOM/IShapeCollection.h>
#include <DOM/ISlide.h>
#include <DOM/ISlideCollection.h>
#include <DOM/Presentation.h>
#include <DOM/ShapeType.h>
#include <system/smart_ptr.h>
using namespace Aspose::Slides;
using namespace System;
auto presentation = System::MakeObject<Presentation>();
auto slide = presentation->get_Slide(0);
auto shape = slide->get_Shapes()->AddAutoShape(ShapeType::Heart, 100.0f, 100.0f, 300.0f, 300.0f);
auto path = shape->GetGeometryPaths()->idx_get(0);
path->RemoveAt(2);
shape->SetGeometryPath(path);

Criar uma Forma Personalizada
Este exemplo constrói uma estrela de cinco pontas com GeometryPath. Raios externos e internos alternados de 100 e 50 pontos definem as pontas e as reentrâncias; um passo de 72 graus distribui uniformemente as cinco pontas. O caminho é fechado com GeometryPath::CloseFigure e aplicado a uma forma retangular usando IGeometryShape::SetGeometryPath, substituindo seu contorno.
#include <DOM/GeometryPath.h>
#include <DOM/IAutoShape.h>
#include <DOM/IShapeCollection.h>
#include <DOM/ISlide.h>
#include <DOM/ISlideCollection.h>
#include <DOM/Presentation.h>
#include <DOM/ShapeType.h>
#include <drawing/point_f.h>
#include <system/collections/list.h>
#include <system/math.h>
#include <system/smart_ptr.h>
using namespace Aspose::Slides;
using namespace System;
using namespace System::Collections::Generic;
using namespace System::Drawing;
auto points = System::MakeObject<List<PointF>>();
auto outerRadius = 100.0f;
auto innerRadius = 50.0f;
auto angleStep = 72;
for (auto angle = -90; angle < 270; angle += angleStep)
{
auto radians = angle * (Math::PI / 180.f);
auto x = outerRadius * Math::Cos(radians);
auto y = outerRadius * Math::Sin(radians);
points->Add(PointF((float)x + outerRadius, (float)y + outerRadius));
radians = Math::PI * (angle + angleStep / 2) / 180.0;
x = innerRadius * Math::Cos(radians);
y = innerRadius * Math::Sin(radians);
points->Add(PointF((float)x + outerRadius, (float)y + outerRadius));
}
auto starPath = System::MakeObject<GeometryPath>();
starPath->MoveTo(points->idx_get(0));
for (auto i = 1; i < points->get_Count(); i++)
{
starPath->LineTo(points->idx_get(i));
}
starPath->CloseFigure();
auto presentation = System::MakeObject<Presentation>();
auto slide = presentation->get_Slide(0);
auto shape = slide->get_Shapes()->AddAutoShape(ShapeType::Rectangle, 100.0f, 100.0f, outerRadius * 2, outerRadius * 2);
shape->SetGeometryPath(starPath);

Criar uma Forma Personalizada Composta
Este exemplo define dois GeometryPath fechados para os terços superior e inferior de uma forma. Aplicar ambos os caminhos com IGeometryShape::SetGeometryPaths cria uma única forma composta com um espaço atravessando seu terço central.
#include <DOM/GeometryPath.h>
#include <DOM/IAutoShape.h>
#include <DOM/IGeometryPath.h>
#include <DOM/IShapeCollection.h>
#include <DOM/ISlide.h>
#include <DOM/ISlideCollection.h>
#include <DOM/Presentation.h>
#include <DOM/ShapeType.h>
#include <system/smart_ptr.h>
using namespace Aspose::Slides;
using namespace System;
auto presentation = System::MakeObject<Presentation>();
auto slide = presentation->get_Slide(0);
auto shape = slide->get_Shapes()->AddAutoShape(ShapeType::Rectangle, 100.0f, 100.0f, 200.0f, 100.0f);
auto topPath = System::MakeObject<GeometryPath>();
topPath->MoveTo(0.0f, 0.0f);
topPath->LineTo(shape->get_Width(), 0.0f);
topPath->LineTo(shape->get_Width(), shape->get_Height() / 3);
topPath->LineTo(0.0f, shape->get_Height() / 3);
topPath->CloseFigure();
auto bottomPath = System::MakeObject<GeometryPath>();
bottomPath->MoveTo(0.0f, shape->get_Height() / 3 * 2);
bottomPath->LineTo(shape->get_Width(), shape->get_Height() / 3 * 2);
bottomPath->LineTo(shape->get_Width(), shape->get_Height());
bottomPath->LineTo(0.0f, shape->get_Height());
bottomPath->CloseFigure();
auto paths = System::MakeArray<SharedPtr<IGeometryPath>>({ topPath, bottomPath });
shape->SetGeometryPaths(paths);

Criar uma Forma Personalizada com Cantos Curvos
Este exemplo combina segmentos retos com GeometryPath::ArcTo para criar uma forma com cantos curvos para dentro. Cada tamanho de canto define a largura e a altura do arco em pontos, e o arco de -90 graus desenha um quarto de elipse no sentido anti‑horário. O caminho concluído é aplicado com IGeometryShape::SetGeometryPath, e a apresentação é salva no formato PPTX.
#include <DOM/GeometryPath.h>
#include <DOM/IAutoShape.h>
#include <DOM/IShapeCollection.h>
#include <DOM/ISlide.h>
#include <DOM/ISlideCollection.h>
#include <DOM/Presentation.h>
#include <DOM/ShapeType.h>
#include <Export/SaveFormat.h>
#include <drawing/point_f.h>
using namespace Aspose::Slides;
using namespace Aspose::Slides::Export;
using namespace System::Drawing;
auto shapeX = 20.f;
auto shapeY = 20.f;
auto shapeWidth = 300.f;
auto shapeHeight = 200.f;
auto leftTopSize = 50.f;
auto rightTopSize = 20.f;
auto rightBottomSize = 40.f;
auto leftBottomSize = 10.f;
auto presentation = System::MakeObject<Presentation>();
auto slide = presentation->get_Slide(0);
auto shape = slide->get_Shapes()->AddAutoShape(ShapeType::Custom, shapeX, shapeY, shapeWidth, shapeHeight);
auto topLeft = PointF(leftTopSize, 0.0f);
auto topRight = PointF(shapeWidth - rightTopSize, 0.0f);
auto rightBottom = PointF(shapeWidth, shapeHeight - rightBottomSize);
auto bottomLeft = PointF(leftBottomSize, shapeHeight);
auto leftTop = PointF(0.0f, leftTopSize);
auto geometryPath = System::MakeObject<GeometryPath>();
geometryPath->MoveTo(topLeft);
geometryPath->LineTo(topRight);
geometryPath->ArcTo(rightTopSize, rightTopSize, 180.0f, -90.0f);
geometryPath->LineTo(rightBottom);
geometryPath->ArcTo(rightBottomSize, rightBottomSize, -90.0f, -90.0f);
geometryPath->LineTo(bottomLeft);
geometryPath->ArcTo(leftBottomSize, leftBottomSize, 0.0f, -90.0f);
geometryPath->LineTo(leftTop);
geometryPath->ArcTo(leftTopSize, leftTopSize, 90.0f, -90.0f);
geometryPath->CloseFigure();
shape->SetGeometryPath(geometryPath);
presentation->Save(u"output.pptx", SaveFormat::Pptx);
Descobrir se a Geometria de uma Forma está Fechada
O ajudante a seguir verifica se cada caminho de geometria não vazio termina com um segmento de fechamento. Ele lê IGeometryPath::get_PathData e compara o comando do segmento final IPathSegment::get_PathCommand com PathCommandType::Close. Retorna false quando não há caminhos não vazios. Essa verificação analisa o comando final de cada caminho; não inspeciona cada sub‑figura dentro de um caminho. O exemplo imprime True para um retângulo.
#include <DOM/Presentation.h>
#include <DOM/ISlide.h>
#include <DOM/IShapeCollection.h>
#include <DOM/IAutoShape.h>
#include <DOM/IGeometryShape.h>
#include <DOM/IGeometryPath.h>
#include <DOM/ShapeType.h>
#include <system/array.h>
#include <system/smart_ptr.h>
#include <system/console.h>
#include <DOM/IPathSegment.h>
#include <DOM/PathCommandType.h>
using namespace Aspose::Slides;
using namespace System;
auto isGeometryClosed = [](SharedPtr<IGeometryShape> geometryShape)
{
auto hasNonemptyPath = false;
for (auto&& geometryPath : geometryShape->GetGeometryPaths())
{
auto segments = geometryPath->get_PathData();
if (segments->get_Length() == 0)
{
continue;
}
hasNonemptyPath = true;
auto lastSegment = segments->idx_get(segments->get_Length() - 1);
if (lastSegment->get_PathCommand() != PathCommandType::Close)
{
return false;
}
}
return hasNonemptyPath;
};
auto presentation = MakeObject<Presentation>();
auto slide = presentation->get_Slide(0);
auto shape = slide->get_Shapes()->AddAutoShape(ShapeType::Rectangle, 100, 100, 200, 100);
Console::WriteLine(isGeometryClosed(shape));
Extrair e Inspecionar Elementos de Forma
Use IGeometryShape::CreateShapeElements para inspecionar uma forma existente como elementos contendo pontos de caminho e tipos de ponto. Converta cada IShapeElement retornado para ShapeElement a fim de ler os arrays retornados por get_PathPoints e get_PathTypes. Essa representação é útil para análise de contorno ou para passar a geometria a ferramentas de desenho customizadas.
O exemplo abre uma apresentação, encontra a primeira forma de geometria diretamente no primeiro slide e imprime seus segmentos de caminho. Use uma apresentação contendo uma forma com segmentos retos e curvos para ver ambos os tipos de saída. Ele não procura dentro de grupos.
#include <DOM/Presentation.h>
#include <DOM/ISlide.h>
#include <DOM/IShapeCollection.h>
#include <DOM/IAutoShape.h>
#include <DOM/IGeometryShape.h>
#include <DOM/IGeometryPath.h>
#include <DOM/ShapeType.h>
#include <system/array.h>
#include <system/smart_ptr.h>
#include <system/console.h>
#include <DOM/IShapeElement.h>
#include <DOM/ShapeElement.h>
using namespace Aspose::Slides;
using namespace System;
auto presentation = MakeObject<Presentation>(u"input.pptx");
auto slide = presentation->get_Slide(0);
SharedPtr<IGeometryShape> shape;
for (auto&& candidate : slide->get_Shapes())
{
shape = AsCast<IGeometryShape>(candidate);
if (shape != nullptr)
{
break;
}
}
if (shape == nullptr)
{
Console::WriteLine(u"No geometry shape found on the first slide.");
return;
}
for (auto&& element : shape->CreateShapeElements())
{
auto shapeElement = ExplicitCast<ShapeElement>(element);
auto points = shapeElement->get_PathPoints();
auto types = shapeElement->get_PathTypes();
Console::WriteLine(u"Shape element:");
for (auto i = 0; i < points->get_Length(); i++)
{
auto pointType = types[i] & 0x07; // Mantém o tipo de segmento, excluindo flags.
switch (pointType)
{
case 0:
Console::WriteLine(u"Start figure at {0}", points[i]);
break;
case 1:
Console::WriteLine(u"Line to {0}", points[i]);
break;
case 3:
Console::WriteLine(u"Cubic Bezier: controls {0}, {1}; end {2}", points[i], points[i + 1], points[i + 2]);
i += 2; // Consome ambos os pontos de controle e o ponto final.
break;
}
if ((types[i] & 0x80) != 0)
{
Console::WriteLine(u"Close subpath back to its starting point.");
}
}
}
Os arrays correspondem por índice: points[i] é um ponto e types[i] descreve seu papel. O tipo 0 inicia uma figura, e o tipo 1 desenha uma linha do ponto anterior para o ponto atual. Um segmento Bézier cúbico começa no ponto final anterior e usa três entradas consecutivas do tipo 3: dois pontos de controle seguidos do novo ponto final. O laço consome essas três entradas juntas e verifica o ponto final para fechamento.
Os tipos de ponto também contêm flags. Mascarar com 0x07 identifica o tipo de segmento, e testar 0x80 separadamente detecta um subcaminho fechado. Por exemplo, 129 (0x81) significa um ponto final de linha que fecha um subcaminho, e 131 (0x83) significa um ponto final Bézier que fecha um subcaminho. Comparar o valor bruto apenas com 1 ou 3 perderia esses casos. Outras flags, como traço (0x10) e marcador (0x20), não alteram o tipo base do segmento.
Coordenadas e transformações. Os pontos são medidos em pontos (1/72 polegada), com X aumentando para a direita e Y aumentando para baixo. Para uma forma não agrupada, as coordenadas extraídas já incluem a posição retornada por get_X e get_Y e refletem sua largura e altura atuais. Por exemplo, um retângulo não rotacionado em (100, 200) com tamanho 120 × 80 tem limites de contorno (100, 200)–(220, 280). Não adicione a posição da forma novamente. Subtraia seu X e Y para obter coordenadas relativas ao seu quadro não rotacionado.
Os pontos extraídos não aplicam a rotação definida por set_Rotation nem os reflexos horizontal e vertical. Para reproduzir o contorno exibido, aplique essas transformações ao redor do centro da forma. Para formas agrupadas, também considere o mapeamento de coordenadas do grupo e as transformações; não presuma que os pontos extraídos sejam as coordenadas finais renderizadas no slide nem aplique uma translação ou escala duas vezes se já estiver refletida no quadro do filho.
Inspeção versus edição. Os arrays extraídos descrevem o contorno; alterá‑los não atualiza a forma original. Use esta abordagem quando sua análise ou código de desenho precisar dos arrays de ponto/tipo. Use GetGeometryPaths quando precisar dos comandos de geometria no sistema de coordenadas local da forma ou quiser editar sua geometria. Aplique os caminhos editados via SetGeometryPath ou SetGeometryPaths.
Converter GeometryPath para GraphicsPath
A API pública atual do Aspose.Slides for C++ não expõe conversões entre caminhos de geometria e caminhos gráficos. Para inspecionar um contorno, use elementos de forma como descrito acima. Para editar uma forma, use caminhos de geometria e aplique os caminhos atualizados à forma.
Perguntas Frequentes
O que acontecerá com o preenchimento e o contorno após substituir a geometria?
O estilo permanece na forma; apenas o contorno muda. O preenchimento e o contorno são aplicados automaticamente à nova geometria.
Como girar corretamente uma forma personalizada juntamente com sua geometria?
Use o método set_Rotation da forma; a geometria gira com a forma porque está vinculada ao próprio sistema de coordenadas da forma.
Posso converter uma forma personalizada em uma imagem para “travar” o resultado?
Sim. Exporte a área da slide ou a própria forma para um formato raster; isso simplifica trabalhos posteriores com geometrias complexas.