osci-render/Source/svg/SvgParser.cpp

124 wiersze
4.3 KiB
C++

#include "SvgParser.h"
#include "../shape/Line.h"
#include "../shape/QuadraticBezierCurve.h"
#include "../shape/CubicBezierCurve.h" // Add missing include
SvgParser::SvgParser(juce::String svgFile) {
auto doc = juce::XmlDocument::parse(svgFile);
if (doc != nullptr) {
std::unique_ptr<juce::Drawable> svg = juce::Drawable::createFromSVG(*doc);
juce::DrawableComposite* composite = dynamic_cast<juce::DrawableComposite*>(svg.get());
if (composite != nullptr) {
auto contentArea = composite->getContentArea();
auto path = svg->getOutlineAsPath();
// Apply translation to center the path
path.applyTransform(juce::AffineTransform::translation(-contentArea.getX(), -contentArea.getY()));
// Instead of separate scaling for width and height, just get the path as is
pathToShapes(path, shapes, true); // Enable normalization
Shape::removeOutOfBounds(shapes);
return;
}
}
juce::MessageManager::callAsync([this] {
juce::AlertWindow::showMessageBoxAsync(juce::AlertWindow::AlertIconType::WarningIcon, "Error", "The SVG could not be loaded.");
});
// draw an X to indicate an error.
shapes.push_back(std::make_unique<Line>(-0.5, -0.5, 0.5, 0.5));
shapes.push_back(std::make_unique<Line>(-0.5, 0.5, 0.5, -0.5));
}
SvgParser::~SvgParser() {}
void SvgParser::pathToShapes(juce::Path& path, std::vector<std::unique_ptr<Shape>>& shapes, bool normalise) {
juce::Path::Iterator pathIterator(path);
double x = 0;
double y = 0;
double startX = 0;
double startY = 0;
while (pathIterator.next()) {
auto type = pathIterator.elementType;
switch (type) {
case juce::Path::Iterator::PathElementType::startNewSubPath:
x = pathIterator.x1;
y = pathIterator.y1;
startX = x;
startY = y;
break;
case juce::Path::Iterator::PathElementType::lineTo:
shapes.push_back(std::make_unique<Line>(x, -y, pathIterator.x1, -pathIterator.y1));
x = pathIterator.x1;
y = pathIterator.y1;
break;
case juce::Path::Iterator::PathElementType::quadraticTo:
shapes.push_back(std::make_unique<QuadraticBezierCurve>(x, -y, pathIterator.x1, -pathIterator.y1, pathIterator.x2, -pathIterator.y2));
x = pathIterator.x2;
y = pathIterator.y2;
break;
case juce::Path::Iterator::PathElementType::cubicTo:
shapes.push_back(std::make_unique<CubicBezierCurve>(x, -y, pathIterator.x1, -pathIterator.y1, pathIterator.x2, -pathIterator.y2, pathIterator.x3, -pathIterator.y3));
x = pathIterator.x3;
y = pathIterator.y3;
break;
case juce::Path::Iterator::PathElementType::closePath:
shapes.push_back(std::make_unique<Line>(x, -y, startX, -startY));
x = startX;
y = startY;
break;
}
}
// Normalize shapes if requested and if there are shapes to normalize
if (normalise && !shapes.empty()) {
// Find the bounding box of all shapes
double minX = std::numeric_limits<double>::max();
double minY = std::numeric_limits<double>::max();
double maxX = std::numeric_limits<double>::lowest();
double maxY = std::numeric_limits<double>::lowest();
for (const auto& shape : shapes) {
auto start = shape->nextVector(0);
minX = std::min(minX, start.x);
minY = std::min(minY, start.y);
maxX = std::max(maxX, start.x);
maxY = std::max(maxY, start.y);
auto end = shape->nextVector(1);
minX = std::min(minX, end.x);
minY = std::min(minY, end.y);
maxX = std::max(maxX, end.x);
maxY = std::max(maxY, end.y);
}
// Calculate center of all shapes
double centerX = (minX + maxX) / 2.0;
double centerY = (minY + maxY) / 2.0;
// Calculate uniform scale factor based on the maximum dimension
double width = maxX - minX;
double height = maxY - minY;
double scaleFactor = 1.8 / std::max(width, height); // Scale to fit within -1 to 1
// Apply translation and scaling to all shapes
for (auto& shape : shapes) {
// First center, then scale
shape->translate(-centerX, -centerY, 0);
shape->scale(scaleFactor, scaleFactor, 1);
}
}
}
std::vector<std::unique_ptr<Shape>> SvgParser::draw() {
// clone with deep copy
std::vector<std::unique_ptr<Shape>> tempShapes = std::vector<std::unique_ptr<Shape>>();
for (auto& shape : shapes) {
tempShapes.push_back(shape->clone());
}
return tempShapes;
}