Add code for SvgState, MoveTo, LineTo, CurveTo, ClosePath

pull/170/head
James Ball 2023-01-23 22:40:55 +00:00
rodzic f0e99440fc
commit 60b80b7812
17 zmienionych plików z 360 dodań i 0 usunięć

Wyświetl plik

@ -31,6 +31,11 @@ void Vector2::translate(double x, double y) {
this->y += y;
}
void Vector2::reflectRelativeToVector(double x, double y) {
this->x += 2.0 * (x - this->x);
this->y += 2.0 * (y - this->y);
}
double Vector2::length() {
return 0.0;
}

Wyświetl plik

@ -12,6 +12,7 @@ public:
void rotate(double theta);
void scale(double x, double y);
void translate(double x, double y);
void reflectRelativeToVector(double x, double y);
double length();
double x, y;

Wyświetl plik

@ -0,0 +1,19 @@
#include "ClosePath.h"
#include "../shape/Line.h"
std::vector<std::unique_ptr<Shape>> ClosePath::absolute(SvgState& state, std::vector<float>& args) {
return parseClosePath(state, args);
}
std::vector<std::unique_ptr<Shape>> ClosePath::relative(SvgState& state, std::vector<float>& args) {
return parseClosePath(state, args);
}
std::vector<std::unique_ptr<Shape>> ClosePath::parseClosePath(SvgState& state, std::vector<float>& args) {
auto shapes = std::vector<std::unique_ptr<Shape>>();
if (state.currPoint.x != state.initialPoint.x || state.currPoint.y != state.initialPoint.y) {
state.currPoint = state.initialPoint;
shapes.push_back(std::make_unique<Line>(state.currPoint.x, state.currPoint.y, state.initialPoint.x, state.initialPoint.y));
}
return shapes;
}

Wyświetl plik

@ -0,0 +1,12 @@
#pragma once
#include <vector>
#include "../shape/Shape.h"
#include "SvgState.h"
class ClosePath {
public:
static std::vector<std::unique_ptr<Shape>> absolute(SvgState& state, std::vector<float>& args);
static std::vector<std::unique_ptr<Shape>> relative(SvgState& state, std::vector<float>& args);
private:
static std::vector<std::unique_ptr<Shape>> parseClosePath(SvgState& state, std::vector<float>& args);
};

Wyświetl plik

@ -0,0 +1,103 @@
#include "CurveTo.h"
#include "../shape/CubicBezierCurve.h"
#include "../shape/QuadraticBezierCurve.h"
std::vector<std::unique_ptr<Shape>> CurveTo::absolute(SvgState& state, std::vector<float>& args) {
return parseCurveTo(state, args, true, true, false);
}
std::vector<std::unique_ptr<Shape>> CurveTo::relative(SvgState& state, std::vector<float>& args) {
return parseCurveTo(state, args, false, true, false);
}
std::vector<std::unique_ptr<Shape>> CurveTo::smoothAbsolute(SvgState& state, std::vector<float>& args) {
return parseCurveTo(state, args, true, true, true);
}
std::vector<std::unique_ptr<Shape>> CurveTo::smoothRelative(SvgState& state, std::vector<float>& args) {
return parseCurveTo(state, args, false, true, true);
}
std::vector<std::unique_ptr<Shape>> CurveTo::quarticAbsolute(SvgState& state, std::vector<float>& args) {
return parseCurveTo(state, args, true, false, false);
}
std::vector<std::unique_ptr<Shape>> CurveTo::quarticRelative(SvgState& state, std::vector<float>& args) {
return parseCurveTo(state, args, false, false, false);
}
std::vector<std::unique_ptr<Shape>> CurveTo::quarticSmoothAbsolute(SvgState& state, std::vector<float>& args) {
return parseCurveTo(state, args, true, false, true);
}
std::vector<std::unique_ptr<Shape>> CurveTo::quarticSmoothRelative(SvgState& state, std::vector<float>& args) {
return parseCurveTo(state, args, false, false, true);
}
// Parses curveto commands (C, c, S, s, Q, q, T, and t commands)
// isCubic should be true for parsing C, c, S, and s commands
// isCubic should be false for parsing Q, q, T, and t commands
// isSmooth should be true for parsing S, s, T, and t commands
// isSmooth should be false for parsing C, c, Q, and q commands
std::vector<std::unique_ptr<Shape>> CurveTo::parseCurveTo(SvgState& state, std::vector<float>& args, bool isAbsolute, bool isCubic, bool isSmooth) {
int expectedArgs = isCubic ? 4 : 2;
if (!isSmooth) {
expectedArgs += 2;
}
if (args.size() % expectedArgs != 0 || args.size() < expectedArgs) {
return {};
}
auto curves = std::vector<std::unique_ptr<Shape>>();
for (int i = 0; i < args.size(); i += expectedArgs) {
Vector2 controlPoint1;
Vector2 controlPoint2;
if (isSmooth) {
if (isCubic) {
if (!state.prevCubicControlPoint.has_value()) {
controlPoint1 = state.currPoint;
} else {
controlPoint1 = state.prevCubicControlPoint.value();
controlPoint1.reflectRelativeToVector(state.currPoint.x, state.currPoint.y);
}
} else {
if (!state.prevQuadraticControlPoint.has_value()) {
controlPoint1 = state.currPoint;
} else {
controlPoint1 = state.prevQuadraticControlPoint.value();
controlPoint1.reflectRelativeToVector(state.currPoint.x, state.currPoint.y);
}
}
} else {
controlPoint1 = Vector2(args[i], args[i + 1]);
}
if (isCubic) {
controlPoint2 = Vector2(args[i + 2], args[i + 3]);
}
Vector2 newPoint(args[i + expectedArgs - 2], args[i + expectedArgs - 1]);
if (!isAbsolute) {
controlPoint1.translate(state.currPoint.x, state.currPoint.y);
controlPoint2.translate(state.currPoint.x, state.currPoint.y);
newPoint.translate(state.currPoint.x, state.currPoint.y);
}
if (isCubic) {
curves.push_back(std::make_unique<CubicBezierCurve>(state.currPoint.x, state.currPoint.y, controlPoint1.x, controlPoint1.y, controlPoint2.x, controlPoint2.y, newPoint.x, newPoint.y));
state.currPoint = newPoint;
state.prevCubicControlPoint = controlPoint2;
} else {
curves.push_back(std::make_unique<QuadraticBezierCurve>(state.currPoint.x, state.currPoint.y, controlPoint1.x, controlPoint1.y, newPoint.x, newPoint.y));
state.currPoint = newPoint;
state.prevQuadraticControlPoint = controlPoint1;
}
}
return curves;
}

Wyświetl plik

@ -0,0 +1,18 @@
#pragma once
#include <vector>
#include "../shape/Shape.h"
#include "SvgState.h"
class CurveTo {
public:
static std::vector<std::unique_ptr<Shape>> absolute(SvgState& state, std::vector<float>& args);
static std::vector<std::unique_ptr<Shape>> relative(SvgState& state, std::vector<float>& args);
static std::vector<std::unique_ptr<Shape>> smoothAbsolute(SvgState& state, std::vector<float>& args);
static std::vector<std::unique_ptr<Shape>> smoothRelative(SvgState& state, std::vector<float>& args);
static std::vector<std::unique_ptr<Shape>> quarticAbsolute(SvgState& state, std::vector<float>& args);
static std::vector<std::unique_ptr<Shape>> quarticRelative(SvgState& state, std::vector<float>& args);
static std::vector<std::unique_ptr<Shape>> quarticSmoothAbsolute(SvgState& state, std::vector<float>& args);
static std::vector<std::unique_ptr<Shape>> quarticSmoothRelative(SvgState& state, std::vector<float>& args);
private:
static std::vector<std::unique_ptr<Shape>> parseCurveTo(SvgState& state, std::vector<float>& args, bool isAbsolute, bool isCubic, bool isSmooth);
};

Wyświetl plik

@ -0,0 +1,13 @@
#include "EllipticalArcTo.h"
std::vector<std::unique_ptr<Shape>> EllipticalArcTo::absolute(SvgState& state, std::vector<float>& args) {
return std::vector<std::unique_ptr<Shape>>();
}
std::vector<std::unique_ptr<Shape>> EllipticalArcTo::relative(SvgState& state, std::vector<float>& args) {
return std::vector<std::unique_ptr<Shape>>();
}
std::vector<std::unique_ptr<Shape>> EllipticalArcTo::parseEllipticalArc(SvgState& state, std::vector<float>& args, bool isAbsolute) {
return std::vector<std::unique_ptr<Shape>>();
}

Wyświetl plik

@ -0,0 +1,12 @@
#pragma once
#include <vector>
#include "../shape/Shape.h"
#include "SvgState.h"
class EllipticalArcTo {
public:
static std::vector<std::unique_ptr<Shape>> absolute(SvgState& state, std::vector<float>& args);
static std::vector<std::unique_ptr<Shape>> relative(SvgState& state, std::vector<float>& args);
private:
static std::vector<std::unique_ptr<Shape>> parseEllipticalArc(SvgState& state, std::vector<float>& args, bool isAbsolute);
};

Wyświetl plik

@ -0,0 +1,74 @@
#include "LineTo.h"
#include "../shape/Line.h"
std::vector<std::unique_ptr<Shape>> LineTo::absolute(SvgState& state, std::vector<float>& args) {
return parseLineTo(state, args, true, true, true);
}
std::vector<std::unique_ptr<Shape>> LineTo::relative(SvgState& state, std::vector<float>& args) {
return parseLineTo(state, args, false, true, true);
}
std::vector<std::unique_ptr<Shape>> LineTo::horizontalAbsolute(SvgState& state, std::vector<float>& args) {
return parseLineTo(state, args, true, true, false);
}
std::vector<std::unique_ptr<Shape>> LineTo::horizontalRelative(SvgState& state, std::vector<float>& args) {
return parseLineTo(state, args, false, true, false);
}
std::vector<std::unique_ptr<Shape>> LineTo::verticalAbsolute(SvgState& state, std::vector<float>& args) {
return parseLineTo(state, args, true, false, true);
}
std::vector<std::unique_ptr<Shape>> LineTo::verticalRelative(SvgState& state, std::vector<float>& args) {
return parseLineTo(state, args, false, false, true);
}
// Parses lineto commands (L, l, H, h, V, and v commands)
// isHorizontal and isVertical should be true for parsing L and l commands
// Only isHorizontal should be true for parsing H and h commands
// Only isVertical should be true for parsing V and v commands
std::vector<std::unique_ptr<Shape>> LineTo::parseLineTo(SvgState& state, std::vector<float>& args, bool isAbsolute, bool isHorizontal, bool isVertical) {
int expectedArgs = isHorizontal && isVertical ? 2 : 1;
if (args.size() % expectedArgs != 0 || args.size() < expectedArgs) {
return {};
}
auto lines = std::vector<std::unique_ptr<Shape>>();
for (int i = 0; i < args.size(); i += expectedArgs) {
Vector2 newPoint;
if (expectedArgs == 1) {
newPoint = Vector2(args[i], args[i]);
} else {
newPoint = Vector2(args[i], args[i + 1]);
}
if (isHorizontal && !isVertical) {
if (isAbsolute) {
newPoint.y = state.currPoint.y;
} else {
newPoint.y = 0;
}
} else if (isVertical && !isHorizontal) {
if (isAbsolute) {
newPoint.x = state.currPoint.x;
} else {
newPoint.x = 0;
}
}
if (!isAbsolute) {
newPoint.translate(state.currPoint.x, state.currPoint.y);
}
lines.push_back(std::make_unique<Line>(state.currPoint.x, state.currPoint.y, newPoint.x, newPoint.y));
state.currPoint = newPoint;
}
return lines;
}

Wyświetl plik

@ -0,0 +1,16 @@
#pragma once
#include <vector>
#include "../shape/Shape.h"
#include "SvgState.h"
class LineTo {
public:
static std::vector<std::unique_ptr<Shape>> absolute(SvgState& state, std::vector<float>& args);
static std::vector<std::unique_ptr<Shape>> relative(SvgState& state, std::vector<float>& args);
static std::vector<std::unique_ptr<Shape>> horizontalAbsolute(SvgState& state, std::vector<float>& args);
static std::vector<std::unique_ptr<Shape>> horizontalRelative(SvgState& state, std::vector<float>& args);
static std::vector<std::unique_ptr<Shape>> verticalAbsolute(SvgState& state, std::vector<float>& args);
static std::vector<std::unique_ptr<Shape>> verticalRelative(SvgState& state, std::vector<float>& args);
private:
static std::vector<std::unique_ptr<Shape>> parseLineTo(SvgState& state, std::vector<float>& args, bool isAbsolute, bool isHorizontal, bool isVertical);
};

Wyświetl plik

@ -0,0 +1,36 @@
#include "MoveTo.h"
#include "LineTo.h"
std::vector<std::unique_ptr<Shape>> MoveTo::absolute(SvgState& state, std::vector<float>& args) {
return parseMoveTo(state, args, true);
}
std::vector<std::unique_ptr<Shape>> MoveTo::relative(SvgState& state, std::vector<float>& args) {
return parseMoveTo(state, args, false);
}
std::vector<std::unique_ptr<Shape>> MoveTo::parseMoveTo(SvgState& state, std::vector<float>& args, bool isAbsolute) {
if (args.size() % 2 != 0 || args.size() < 2) {
return {};
}
Vector2 vec(args[0], args[1]);
if (isAbsolute) {
state.currPoint = vec;
state.initialPoint = state.currPoint;
if (args.size() > 2) {
std::vector<float> newArgs = std::vector<float>(args.begin() + 2, args.end());
return LineTo::absolute(state, newArgs);
}
} else {
state.currPoint.translate(vec.x, vec.y);
state.initialPoint = state.currPoint;
if (args.size() > 2) {
std::vector<float> newArgs = std::vector<float>(args.begin() + 2, args.end());
return LineTo::relative(state, newArgs);
}
}
return {};
}

Wyświetl plik

@ -0,0 +1,12 @@
#pragma once
#include <vector>
#include "../shape/Shape.h"
#include "SvgState.h"
class MoveTo {
public:
static std::vector<std::unique_ptr<Shape>> absolute(SvgState& state, std::vector<float>& args);
static std::vector<std::unique_ptr<Shape>> relative(SvgState& state, std::vector<float>& args);
private:
static std::vector<std::unique_ptr<Shape>> parseMoveTo(SvgState& state, std::vector<float>& args, bool isAbsolute);
};

Wyświetl plik

@ -0,0 +1 @@
#include "SvgState.h"

Wyświetl plik

@ -0,0 +1,9 @@
#pragma once
#include "../shape/Vector2.h"
struct {
Vector2 currPoint;
Vector2 initialPoint;
Vector2 prevCubicControlPoint;
Vector2 prevQuadraticControlPoint;
};

Wyświetl plik

@ -0,0 +1 @@
#include "SvgState.h"

Wyświetl plik

@ -0,0 +1,10 @@
#pragma once
#include "../shape/Vector2.h"
#include <optional>
struct SvgState {
Vector2 currPoint;
Vector2 initialPoint;
std::optional<Vector2> prevCubicControlPoint;
std::optional<Vector2> prevQuadraticControlPoint;
};

Wyświetl plik

@ -7,6 +7,24 @@
cppLanguageStandard="20" projectLineFeed="&#10;" headerPath="./include">
<MAINGROUP id="j5Ge2T" name="osci-render">
<GROUP id="{75439074-E50C-362F-1EDF-8B4BE9011259}" name="Source">
<GROUP id="{56A27063-1FE7-31C3-8263-98389240A8CB}" name="svg">
<FILE id="FVWkba" name="ClosePath.cpp" compile="1" resource="0" file="Source/svg/ClosePath.cpp"/>
<FILE id="pJz3ek" name="ClosePath.h" compile="0" resource="0" file="Source/svg/ClosePath.h"/>
<FILE id="PS8Qfk" name="CurveTo.cpp" compile="1" resource="0" file="Source/svg/CurveTo.cpp"/>
<FILE id="Sjh7ne" name="CurveTo.h" compile="0" resource="0" file="Source/svg/CurveTo.h"/>
<FILE id="DQJJdr" name="EllipticalArcTo.cpp" compile="1" resource="0"
file="Source/svg/EllipticalArcTo.cpp"/>
<FILE id="iVMpEw" name="EllipticalArcTo.h" compile="0" resource="0"
file="Source/svg/EllipticalArcTo.h"/>
<FILE id="DSmqNL" name="LineTo.cpp" compile="1" resource="0" file="Source/svg/LineTo.cpp"/>
<FILE id="fjo7Oy" name="LineTo.h" compile="0" resource="0" file="Source/svg/LineTo.h"/>
<FILE id="c2y2ap" name="MoveTo.cpp" compile="1" resource="0" file="Source/svg/MoveTo.cpp"/>
<FILE id="SfIJEj" name="MoveTo.h" compile="0" resource="0" file="Source/svg/MoveTo.h"/>
<FILE id="cTec1H" name="SvgParser.cpp" compile="1" resource="0" file="Source/svg/SvgParser.cpp"/>
<FILE id="gvkrDH" name="SvgParser.h" compile="0" resource="0" file="Source/svg/SvgParser.h"/>
<FILE id="OvloZU" name="SvgState.cpp" compile="1" resource="0" file="Source/svg/SvgState.cpp"/>
<FILE id="GCBO9x" name="SvgState.h" compile="0" resource="0" file="Source/svg/SvgState.h"/>
</GROUP>
<GROUP id="{2A41BAF3-5E83-B018-5668-39D89ABFA00C}" name="chinese_postman">
<FILE id="LcDpwe" name="BinaryHeap.cpp" compile="1" resource="0" file="Source/chinese_postman/BinaryHeap.cpp"/>
<FILE id="UYdaXR" name="BinaryHeap.h" compile="0" resource="0" file="Source/chinese_postman/BinaryHeap.h"/>