ultimatepp/uppsrc/Painter/PainterPath.cpp

140 lines
2.8 KiB
C++

#include "Painter.h"
namespace Upp {
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);
Pointf t, t1, t2;
auto ReadDouble = [&] {
while(p.Char(','));
return p.IsDouble2() ? p.ReadDouble() : 0;
};
auto ReadPointP = [&](Pointf current, bool rel) {
Pointf t;
t.x = ReadDouble();
t.y = ReadDouble();
if(rel)
t += current;
return t;
};
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(IsDouble()) {
current = ReadPoint();
Line(current);
}
done = true;
break;
case 'Z':
Close();
done = true;
break;
case 'H':
while(IsDouble()) {
current.x = p.ReadDouble() + rel * current.x;
Line(current);
done = true;
}
break;
case 'V':
while(IsDouble()) {
current.y = p.ReadDouble() + rel * current.y;
Line(current);
done = true;
}
break;
case 'C':
while(IsDouble()) {
t1 = ReadPoint();
t2 = ReadPoint();
current = ReadPoint();
Cubic(t1, t2, current);
done = true;
}
break;
case 'S':
while(IsDouble()) {
Pointf now = current;
t2 = ReadPoint();
current = ReadPoint();
if(previousCmd != 'C' && previousCmd != 'S')
Cubic(now, t2, current);
else
Cubic(t2, current);
while(p.Char(','));
done = true;
}
break;
case 'Q':
while(IsDouble()) {
t1 = ReadPoint();
current = ReadPoint();
Quadratic(t1, current);
done = true;
}
break;
case 'T':
while(IsDouble()) {
Pointf now = current;
current = ReadPoint();
if(previousCmd != 'Q' && previousCmd != 'T')
Quadratic(now, current);
else
Quadratic(current);
done = true;
}
break;
case 'A':
while(IsDouble()) {
t1 = ReadPointP(Pointf(0, 0), false);
double xangle = ReadDouble();
auto ReadBool = [&] {
while(p.Char(','));
if(p.Char('1')) return true;
p.Char('0');
return false;
};
bool large = ReadBool();
bool sweep = ReadBool();
current = ReadPoint();
SvgArc(t1, xangle * M_PI / 180.0, large, sweep, current);
done = true;
}
break;
default:
if(!done)
Move(0, 0); // to clear previous path
return *this;
}
previousCmd = ToUpper(c);
}
if(!done)
Move(0, 0); // to clear previous path
return *this;
}
Painter& Painter::Path(const char *path)
{
try {
CParser p(path);
Path(p);
}
catch(CParser::Error) {}
return *this;
}
}