diff --git a/examples/SVGView/SVGView.upp b/examples/SVGView/SVGView.upp index 14006e534..003a1f557 100644 --- a/examples/SVGView/SVGView.upp +++ b/examples/SVGView/SVGView.upp @@ -10,6 +10,7 @@ uses file main.cpp, SVG readonly separator, + svg\biplane.svg, svg\altum_angelfish_01.svg, svg\brown_fish_01.svg, svg\matrix.svg, diff --git a/examples/SVGView/main.cpp b/examples/SVGView/main.cpp index e95dc5030..74ae77941 100644 --- a/examples/SVGView/main.cpp +++ b/examples/SVGView/main.cpp @@ -121,7 +121,7 @@ SvgView::SvgView() Sizeable().Zoomable(); - AddFrame(splitter.Left(files, 200)); + AddFrame(splitter.Left(files, DPI(200))); dir = GetDataFile("svg"); } diff --git a/examples/SVGView/svg/biplane.svg b/examples/SVGView/svg/biplane.svg new file mode 100644 index 000000000..5b43e8839 --- /dev/null +++ b/examples/SVGView/svg/biplane.svg @@ -0,0 +1,298 @@ + + + Free 3D Biplane Model SVG Files for Laser Cutting + + + + + + + templatesarea.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Free 3D Biplane Model SVG Files for Laser Cutting + Get your free laser-cut SVG files for crafting an impressive wooden plane. + + + templatesarea.com + + + + + templatesarea.com + + + + + https://www.templatesarea.com/license-agreement/ + + + 2025.03.17 + + + + + + + + + + + + diff --git a/uppsrc/Painter/PainterPath.cpp b/uppsrc/Painter/PainterPath.cpp index c8d4d32ff..73a7b9915 100644 --- a/uppsrc/Painter/PainterPath.cpp +++ b/uppsrc/Painter/PainterPath.cpp @@ -6,7 +6,9 @@ Painter& Painter::Path(CParser& p) { Pointf current(0, 0); bool done = false; + int previousCmd = 0; while(!p.IsEof()) { + while(p.Char(',')); int c = p.GetChar(); p.Spaces(); bool rel = IsLower(c); @@ -23,13 +25,14 @@ Painter& Painter::Path(CParser& p) t += current; return t; }; - auto ReadPoint = [&]() { return ReadPointP(current, rel); }; + auto ReadPoint = [&] { return ReadPointP(current, rel); }; + auto IsDouble = [&] { while(p.Char(',')) {} return p.IsDouble2(); }; switch(ToUpper(c)) { case 'M': current = ReadPoint(); Move(current); case 'L': - while(p.IsDouble2()) { + while(IsDouble()) { current = ReadPoint(); Line(current); } @@ -40,21 +43,21 @@ Painter& Painter::Path(CParser& p) done = true; break; case 'H': - while(p.IsDouble2()) { + while(IsDouble()) { current.x = p.ReadDouble() + rel * current.x; Line(current); done = true; } break; case 'V': - while(p.IsDouble2()) { + while(IsDouble()) { current.y = p.ReadDouble() + rel * current.y; Line(current); done = true; } break; case 'C': - while(p.IsDouble2()) { + while(IsDouble()) { t1 = ReadPoint(); t2 = ReadPoint(); current = ReadPoint(); @@ -63,15 +66,20 @@ Painter& Painter::Path(CParser& p) } break; case 'S': - while(p.IsDouble2()) { + while(IsDouble()) { + Pointf now = current; t2 = ReadPoint(); current = ReadPoint(); - Cubic(t2, current); + if(previousCmd != 'C' && previousCmd != 'S') + Cubic(now, t2, current); + else + Cubic(t2, current); + while(p.Char(',')); done = true; } break; case 'Q': - while(p.IsDouble2()) { + while(IsDouble()) { t1 = ReadPoint(); current = ReadPoint(); Quadratic(t1, current); @@ -79,14 +87,18 @@ Painter& Painter::Path(CParser& p) } break; case 'T': - while(p.IsDouble2()) { + while(IsDouble()) { + Pointf now = current; current = ReadPoint(); - Quadratic(current); + if(previousCmd != 'Q' && previousCmd != 'T') + Quadratic(now, current); + else + Quadratic(current); done = true; } break; case 'A': - while(p.IsDouble2()) { + while(IsDouble()) { t1 = ReadPointP(Pointf(0, 0), false); double xangle = ReadDouble(); auto ReadBool = [&] { @@ -107,6 +119,8 @@ Painter& Painter::Path(CParser& p) Move(0, 0); // to clear previous path return *this; } + + previousCmd = ToUpper(c); } if(!done) Move(0, 0); // to clear previous path diff --git a/uppsrc/Painter/SvgParser.cpp b/uppsrc/Painter/SvgParser.cpp index d1353a640..9ef38df37 100644 --- a/uppsrc/Painter/SvgParser.cpp +++ b/uppsrc/Painter/SvgParser.cpp @@ -84,7 +84,7 @@ void SvgParser::DoGradient(int gi, bool stroke) r = r / sz; } Xform2D m; - + if(g.radial) { m.x.x = r.x; m.x.y = 0; @@ -356,6 +356,27 @@ void SvgParser::Element(const XmlNode& n, int depth, bool dosymbols) else if(m.IsTag("radialGradient")) ParseGradient(m, true); + else if(m.IsTag("style")) { + String text = m.GatherText(); + try { + CParser p(text); + while(!p.IsEof()) { + if(p.Char('.') && p.IsId()) { + String id = p.ReadIdh(); + if(p.Char('{')) { + const char *b = p.GetPtr(); + while(!p.IsChar('}') && !p.IsEof()) + p.SkipTerm(); + classes.Add(id, String(b, p.GetPtr())); + } + p.Char('}'); + } + else + p.SkipTerm(); + } + } + catch(CParser::Error) {} + } } else if(n.IsTag("linearGradient")) @@ -488,7 +509,7 @@ void SvgParser::Element(const XmlNode& n, int depth, bool dosymbols) CParser p(text); while(!p.IsEof()) { if(p.Char('.') && p.IsId()) { - String id = p.ReadId(); + String id = p.ReadIdh(); if(p.Char('{')) { const char *b = p.GetPtr(); while(!p.IsChar('}') && !p.IsEof()) @@ -633,4 +654,4 @@ Rectf GetSVGPathBoundingBox(const char *path) return p.Get(); } -} +} \ No newline at end of file