Přizpůsobení tvarů prezentací v C++

Přehled

Tento článek vysvětluje, jak přizpůsobit tvary prezentací v Aspose.Slides úpravou geometrie tvaru pomocí editačních bodů a geometrických cest. Ukazuje, jak pracovat s GeometryPath a IGeometryPath k úpravě existujících tvarů, provádění základních operací úpravy cesty, přidávání nebo odstraňování bodů a aplikaci aktualizované geometrie zpět na tvar.

Také demonstruje, jak vytvořit vlastní a složené tvary, sestavit tvary s zakřivenými rohy a určit, zda je geometrie tvaru uzavřená.

Změna tvaru pomocí editačních bodů

V PowerPointu můžete použít Edit Points k úpravě čtverce:

  • Posunout roh dovnitř nebo ven.
  • Upravit zakřivení v bodě.
  • Přidat nové body.

Úprava bodů vám umožní měnit obrys tvaru nebo použít existující tvar jako základ pro nový.

Tipy pro úpravu tvarů

overview_image

Při úpravě tvarů v PowerPointu mějte na paměti následující pojmy:

  • Tvar (nebo jeho cesta) může být buď uzavřený, nebo otevřený.
  • Cesta tvaru se skládá z kotevních bodů spojených segmenty.
  • Segment může být přímý nebo zakřivený. Kotevní body a ovládací úchyty určují jeho tvar.
  • Kotevní body existují jako rohové body, přímé body nebo hladké body:
    • V rohovém bodě se sousední segmenty mohou setkat pod úhlem.
    • V hladkém bodě jsou oba ovládací úchyty zarovnané a stejně vzdálené od kotevního bodu.
    • V přímém bodě jsou oba ovládací úchyty zarovnané, ale mohou mít různou vzdálenost od kotevního bodu.
  • Posun kotevních bodů nebo úprava jejich úchytů mění obrys tvaru.

Pro úpravu tvarů PowerPointu pomocí editačních bodů poskytuje Aspose.Slides třídu GeometryPath a rozhraní IGeometryPath.

Jednoduché operace úpravy

Použijte následující metody k úpravě geometrické cesty. Přetížení, která přijímají index, vloží segment na tuto nulovou pozici v poli segmentů cesty.

Operace Metoda
Přidat nebo vložit přímou čáru. GeometryPath::LineTo
Přidat nebo vložit kubické Bézierovo zakřivení se dvěma ovládacími body a koncovým bodem. GeometryPath::CubicBezierTo
Přidat nebo vložit kvadratické Bézierovo zakřivení s jedním ovládacím bodem a koncovým bodem. GeometryPath::QuadraticBezierTo
Přidat eliptický oblouk se zadanými rozměry a úhly ve stupních. GeometryPath::ArcTo
Uzavřít aktuální figuru propojením jejího koncového bodu s počátečním bodem. GeometryPath::CloseFigure
Nastavit počáteční bod figury. GeometryPath::MoveTo
Odstranit segment na nulovém indexu. GeometryPath::RemoveAt

Přidání vlastních bodů do tvaru

Tento příklad vloží dva body do obdélníkového tvaru pomocí GeometryPath::LineTo a použije upravenou cestu pomocí IGeometryShape::SetGeometryPath. Souřadnice jsou lokální k tvaru: oba nové body jsou ve středu, 100 bodů od levého okraje a 50 bodů od horního okraje. Indexy segmentů 1 a 4 je umístí na horní a dolní hranu a stáhnou tyto hrany dovnitř.

#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

Odstranění bodů z tvaru

Tento příklad mění obrys ve tvaru srdce odstraněním segmentu na nulovém indexu 2 pomocí GeometryPath::RemoveAt. Použití upravené cesty pomocí IGeometryShape::SetGeometryPath aktualizuje konturu tvaru.

#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

Vytvoření vlastního tvaru

Tento příklad vytvoří pětihrotou hvězdu pomocí GeometryPath. Střídavé vnější a vnitřní poloměry 100 a 50 bodů definují špičky a zapouzdření; krok 72 stupňů rovnoměrně rozmístí pět špiček. Cesta je uzavřena pomocí GeometryPath::CloseFigure a aplikována na obdélníkový tvar pomocí IGeometryShape::SetGeometryPath, čímž nahradí jeho obrys.

#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

Vytvoření složeného vlastního tvaru

Tento příklad definuje dva uzavřené objekty GeometryPath pro horní a dolní třetinu tvaru. Použití obou cest pomocí IGeometryShape::SetGeometryPaths vytvoří jediný složený tvar s prohlášením uprostřed jeho střední třetiny.

#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

Vytvoření vlastního tvaru se zakřivenými rohy

Tento příklad kombinuje přímé segmenty s GeometryPath::ArcTo k vytvoření tvaru se zakřivenými rohy dovnitř. Každá velikost rohu nastavuje šířku a výšku oblouku v bodech a natočení -90 stupňů kreslí proti směru hodinových ručiček čtvrtkruh elipsy. Dokončená cesta je aplikována pomocí IGeometryShape::SetGeometryPath a prezentace je uložena ve formátu 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);

Zjištění, zda je geometrie tvaru uzavřená

Následující pomocná funkce kontroluje, zda každý neprázdný geometrický cest končí uzavíracím segmentem. Čte IGeometryPath::get_PathData a porovnává poslední segmentů IPathSegment::get_PathCommand s PathCommandType::Close. Vrací false, když neexistují neprázdné cesty. Tato kontrola zkoumá poslední příkaz každé cesty; neprohledává každou podfiguru uvnitř cesty. Příklad vypisuje True pro obdélník.

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

Extrahování a inspekce prvků tvaru

Použijte IGeometryShape::CreateShapeElements k inspekci existujícího tvaru jako prvků obsahujících body cesty a typy bodů. Přetypujte každý vrácený IShapeElement na ShapeElement a přečtěte pole vrácená metodami get_PathPoints a get_PathTypes. Toto znázornění je užitečné pro analýzu obrysu nebo předání geometrie nástrojům pro vlastní kreslení.

Příklad otevře prezentaci, najde první geometrický tvar přímo na první snímku a vypíše jeho segmenty cesty. Použijte prezentaci obsahující tvar s přímými i zakřivenými segmenty, abyste viděli oba typy výstupu. Nepřechází do skupin.

#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; // Uchovat typ segmentu, vyjma příznaků.
        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; // Consume both control points and the endpoint.
                break;
        }
        if ((types[i] & 0x80) != 0)
        {
            Console::WriteLine(u"Close subpath back to its starting point.");
        }
    }
}

Pole jsou podle indexu spárována: points[i] je bod a types[i] popisuje jeho roli. Typ 0 začíná figuru a typ 1 kreslí úsečku od předchozího bodu k aktuálnímu bodu. Kubický Bézierův segment začíná předchozím koncovým bodem a používá tři po sobě jdoucí položky typu 3: dva ovládací body a nový koncový bod. Smyčka konzumuje těchto tři položky najednou a kontroluje koncový bod pro uzavření.

Typy bodů také obsahují příznaky. Maskujte 0x07 pro určení typu segmentu a testujte 0x80 samostatně pro detekci uzavřené podcesty. Například 129 (0x81) znamená koncový bod úsečky, který uzavře podcestu, a 131 (0x83) znamená Bézierův koncový bod, který uzavře podcestu. Pouze porovnání surové hodnoty s 1 nebo 3 by tyto případy minulo. Další příznaky, jako pomlčka (0x10) a značka (0x20), nemění základní typ segmentu.

Souřadnice a transformace. Body jsou měřeny v bodech (1/72 palce), přičemž X roste doprava a Y dolů. Pro neztvořený tvar již extrahované souřadnice zahrnují pozici vrácenou metodami get_X a get_Y a odrážejí jeho aktuální šířku a výšku. Například neotočený obdélník v (100, 200) se šířkou 120 × 80 má obrysové limity (100, 200)–(220, 280). Nepřidávejte pozici tvaru znovu. Odečtěte jeho X a Y pro získání souřadnic relativních k jeho neotočenému rámci.

Extrahované body neaplikují rotaci nastavenou pomocí set_Rotation ani horizontální a vertikální převrácení. Pro reprodukci zobrazeného obrysu aplikujte tyto transformace kolem středu tvaru. Pro seskupené tvary také zohledněte mapování souřadnic skupiny a transformace; nepředpokládejte, že extrahované body jsou konečné vykreslené souřadnice snímku, ani neaplikujte posun nebo měřítko dvakrát, pokud už jsou zahrnuty ve rámci potomka.

Inspekce versus úprava. Extrahovaná pole popisují obrys; jejich změna neaktualizuje původní tvar. Zvolte tento přístup, když vaše analytické nebo kreslicí kódy vyžadují pole bodů/typů. Použijte GetGeometryPaths když potřebujete geometrické příkazy v lokálním souřadnicovém systému tvaru nebo chcete upravit jeho geometriku. Použijte upravené cesty prostřednictvím SetGeometryPath nebo SetGeometryPaths.

Převod GeometryPath na GraphicsPath

Veřejné API Aspose.Slides pro C++ aktuálně neumožňuje převody mezi geometrickými cestami a grafickými cestami. K inspekci obrysu použijte prvky tvaru, jak je popsáno výše. K úpravě tvaru použijte geometrické cesty a aplikujte aktualizované cesty na tvar.

Často kladené otázky

Co se stane s výplní a obrysem po nahrazení geometrie?

Styl zůstává u tvaru; mění se pouze obrys. Výplň a obrys jsou automaticky aplikovány na novou geometrii.

Jak správně otočit vlastní tvar spolu s jeho geometrií?

Použijte metodu set_Rotation tvaru; geometrie se otáčí spolu s tvarem, protože je svázána s lokálním souřadnicovým systémem tvaru.

Mohu převést vlastní tvar na obrázek, abych „uzamkl“ výsledek?

Ano. Exportujte požadovanou slide nebo samotný shape do rastrového formátu; to zjednoduší další práci s komplikovanými geometriemi.