Anpassa presentationsformer i C++

Översikt

Denna artikel förklarar hur man anpassar presentationsformer i Aspose.Slides genom att redigera formgeometri med hjälp av redigeringspunkter och geometriska banor. Den visar hur man arbetar med GeometryPath och IGeometryPath för att modifiera befintliga former, utföra grundläggande banredigeringsoperationer, lägga till eller ta bort punkter och applicera uppdaterad geometri tillbaka på en form.

Den visar också hur man skapar anpassade och sammansatta former, bygger former med kurvade hörn och bestämmer om en formgeometri är sluten.

Ändra en form med redigeringspunkter

  • Flytta ett hörn inåt eller utåt.
  • Justera krökningen vid en punkt.
  • Lägg till nya punkter.

Att redigera punkter låter dig modifiera en forms kontur eller använda en befintlig form som grund för en ny.

Tips för formredigering

overview_image

När du redigerar PowerPoint-former, håll dessa koncept i åtanke:

  • En form (eller dess bana) kan antingen vara sluten eller öppen.
  • En forms bana består av ankarnpunkter som är sammankopplade med segment.
  • Ett segment kan vara rakt eller kurvat. Ankarnpunkter och kontrollhandtag bestämmer dess form.
  • Ankarnpunkter finns som hörnpunkter, raka punkter eller mjuka punkter:
    • Vid en hörnpunkt kan intilliggande segment mötas i en vinkel.
    • Vid en mjuk punkt är de två kontrollhandtagen i linje och lika långt från ankarnpunkten.
    • Vid en rak punkt är de två kontrollhandtagen i linje men kan ha olika avstånd från ankarnpunkten.
  • Att flytta ankarnpunkter eller justera deras handtag förändrar formens kontur.

För att redigera PowerPoint-former genom redigeringspunkter tillhandahåller Aspose.Slides klassen GeometryPath och gränssnittet IGeometryPath.

Enkla redigeringsoperationer

Använd följande metoder för att redigera en geometrisk bana. Överlagringar som accepterar ett index infogar ett segment på den nollbaserade positionen i banans segmentarray.

Operation Metod
Lägg till eller infoga en rak linje. GeometryPath::LineTo
Lägg till eller infoga en kubisk Bézier-kurva med två kontrollpunkter och en slutpunkt. GeometryPath::CubicBezierTo
Lägg till eller infoga en kvadratisk Bézier-kurva med en kontrollpunkt och en slutpunkt. GeometryPath::QuadraticBezierTo
Lägg till en elliptisk båge med angivna dimensioner och vinklar i grader. GeometryPath::ArcTo
Stäng den aktuella figuren genom att ansluta dess slutpunkt till startpunkten. GeometryPath::CloseFigure
Sätt startpunkten för en figur. GeometryPath::MoveTo
Ta bort ett segment på ett nollbaserat index. GeometryPath::RemoveAt

Lägg till anpassade punkter i en form

Detta exempel inför två punkter i en rektangulär form med hjälp av GeometryPath::LineTo och applicerar den redigerade banan med IGeometryShape::SetGeometryPath. Koordinaterna är lokala för formen: båda nya punkterna ligger i dess centrum, 100 punkter från vänster och 50 punkter från toppen. Segmentindex 1 och 4 placerar dem på de övre och nedre kanterna och drar dessa kanter inåt.

#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);

example1_image

Ta bort punkter från en form

Detta exempel ändrar en hjärtformad kontur genom att ta bort segmentet på nollbaserat index 2 med GeometryPath::RemoveAt. Att applicera den modifierade banan med IGeometryShape::SetGeometryPath uppdaterar formens kontur.

#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);

example2_image

Skapa en anpassad form

Detta exempel bygger en femspetsig stjärna med GeometryPath. Växlande yttre och inre radier på 100 respektive 50 punkter definierar spetsarna och fördjupningarna; ett steg på 72 grader placerar de fem spetsarna jämnt. Banan stängs med GeometryPath::CloseFigure och appliceras på en rektangulär form med IGeometryShape::SetGeometryPath, vilket ersätter dess kontur.

#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);

example3_image

Skapa en sammansatt anpassad form

Detta exempel definierar två stängda GeometryPath‑objekt för den övre och nedre tredjedelen av en form. Att applicera båda banorna med IGeometryShape::SetGeometryPaths skapar en enda sammansatt form med ett glapp över dess mellersta tredjedel.

#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(shape->get_Height() / 3 * 2, 0.0f);
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);

example4_image

Skapa en anpassad form med kurvade hörn

Detta exempel kombinerar raka segment med GeometryPath::ArcTo för att skapa en form med inåtriktade kurvade hörn. Varje hörnstorlek sätter bågens bredd och höjd i punkter, och -90‑gradssvepet ritar en moturs kvartselipse. Den färdiga banan appliceras med IGeometryShape::SetGeometryPath och presentationen sparas i PPTX-format.

#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);

Ta reda på om en formgeometri är sluten

Följande hjälpfunktion kontrollerar om varje icke‑tom geometrisk bana slutar med ett avslutande segment. Den läser IGeometryPath::get_PathData och jämför den sista segmentets IPathSegment::get_PathCommand med PathCommandType::Close. Den returnerar false när det inte finns några icke‑tomma banor. Detta kontrollerar det sista kommandot för varje bana; den inspekterar inte varje subfigur i en bana. Exemplet skriver ut True för en rektangel.

#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));

Extrahera och inspektera formelement

Använd IGeometryShape::CreateShapeElements för att inspektera en befintlig form som element som innehåller banpunkter och punkttyper. Kast varje returnerad IShapeElement till ShapeElement för att läsa arrayerna som returneras av get_PathPoints och get_PathTypes. Denna representation är användbar för kontur‑analys eller för att överföra geometri till anpassade ritverktyg.

Exemplet öppnar en presentation, hittar den första geometriska formen direkt på den första bilden och skriver ut dess bansegment. Använd en presentation som innehåller en form med raka och kurvade segment för att se båda typer av utskrift. Den söker inte inuti grupper.

#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; // Behåll segmenttypen, exklusive flaggor.
        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; // Förbrukar båda kontrollpunkterna och slutpunkten.
                break;
        }
        if ((types[i] & 0x80) != 0)
        {
            Console::WriteLine(u"Close subpath back to its starting point.");
        }
    }
}

Arrayerna motsvarar varandra efter index: points[i] är en punkt och types[i] beskriver dess roll. Typ 0 startar en figur, och typ 1 ritar en linje från föregående punkt till den aktuella. Ett kubiskt Bézier‑segment startar vid föregående slutpunkt och använder tre på varandra följande typ‑3‑poster: två kontrollpunkter följda av den nya slutpunkten. Loopen konsumerar dessa tre poster tillsammans och kontrollerar slutpunkten för slutförande.

Punkttyper innehåller också flaggor. Maskera med 0x07 för att identifiera segmenttypen, och testa 0x80 separat för att upptäcka en sluten underbana. Till exempel betyder 129 (0x81) en linjeändpunkt som stänger en underbana, och 131 (0x83) betyder en Bézier‑ändpunkt som stänger en sådan. Att endast jämföra det råa värdet med 1 eller 3 skulle missa dessa fall. Andra flaggor, såsom streck (0x10) och markör (0x20), förändrar inte grundsegmenttypen.

Koordinater och transformationer. Punkter mäts i punkter (1/72 tum), med X som ökar åt höger och Y som ökar nedåt. För en icke‑grupperad form inkluderar de extraherade koordinaterna redan positionen som returneras av get_X och get_Y och återspeglar dess aktuella bredd och höjd. Till exempel har en orotated rektangel på (100, 200) med storlek 120 × 80 konturgränserna (100, 200)–(220, 280). Lägg inte till formens position igen. Subtrahera dess X och Y för att få koordinater relativt dess orotated ram.

De extraherade punkterna tillämpar inte rotationen som ställts in via set_Rotation eller horisontella och vertikala speglingar. För att reproducera den visade konturen, applicera dessa transformationer runt formens centrum. För grupperade former, ta också hänsyn till gruppens koordinatmappning och transformationer; anta inte att de extraherade punkterna är de slutgiltiga renderade bildpunkterna eller applicera en translation eller skala två gånger om den redan är reflekterad i barnets ram.

Inspektion kontra redigering. Extraherade arrayer beskriver konturen; att ändra dem uppdaterar inte den ursprungliga formen. Välj detta tillvägagångssätt när din analys‑ eller ritkod behöver punkt‑/typ‑arrayer. Använd GetGeometryPaths när du behöver geometriska kommandon i formens lokala koordinatsystem eller vill redigera dess geometri. Applicera redigerade banor via SetGeometryPath eller SetGeometryPaths.

Konvertera GeometryPath till GraphicsPath

Det nuvarande offentliga API:t för Aspose.Slides för C++ exponerar inte konverteringar mellan geometriska banor och grafikbanor. För att inspektera en kontur, använd formelement som beskrivits ovan. För att redigera en form, använd geometriska banor och applicera de uppdaterade banorna på formen.

FAQ

Vad händer med fyllning och kontur efter att geometrin har ersatts?

Stilen förblir på formen; endast konturen ändras. Fyllning och kontur appliceras automatiskt på den nya geometrin.

Hur roterar jag korrekt en anpassad form tillsammans med dess geometri?

Använd formens set_Rotation‑metod; geometrin roterar med formen eftersom den är bunden till formens eget koordinatsystem.

Kan jag konvertera en anpassad form till en bild för att “låsa” resultatet?

Ja. Exportera det önskade bild‑området eller själva form till ett rasterformat; detta förenklar vidare arbete med komplexa geometrier.