0% found this document useful (0 votes)
2 views3 pages

SVG Reader: Path and Transform Handling

Uploaded by

dat28102006
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views3 pages

SVG Reader: Path and Transform Handling

Uploaded by

dat28102006
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

SVG Reader – Case 2 (Path + Transform + ViewBox + Zoom/Pan/Rotate)

Mục tiêu: Mở rộng Case 1 để hỗ trợ <path> với các lệnh M/L/H/V/C/Q/Z (subset),
hỗ trợ transform (translate/scale/rotate), parse viewBox và fit-to-window, tương tác
zoom/pan/rotate.

1) Bổ sung lớp SvgPath

class SvgPath : public SvgElement {


public:
mutable std::unique_ptr<Gdiplus::GraphicsPath> cache;
std::wstring d;

void buildPath() const {


if (cache) return;
cache = std::make_unique<Gdiplus::GraphicsPath>();
size_t i = 0;
auto skipws = [&](void){ while(i<[Link]() && iswspace(d[i])) ++i; };
auto readNum = [&](double& out)->bool{
skipws(); std::wstring s;
while(i<[Link]() && (iswdigit(d[i]) || d[i]==L'.' || d[i]==L'-' ||
d[i]==L'+')) s += d[i++];
if([Link]()) return false;
out = std::stod(s); return true;
};

double x=0,y=0, sx=0, sy=0;


while(i < [Link]()) {
skipws();
if (i>=[Link]()) break;
wchar_t cmd = d[i++];
if (cmd == 'M' || cmd == 'm') {
double nx, ny; if(readNum(nx) && readNum(ny)){
if (cmd=='m') { x += nx; y += ny; } else { x = nx; y =
ny; }
cache->StartFigure();
cache->AddLine((Gdiplus::REAL)x,(Gdiplus::REAL)y,
(Gdiplus::REAL)x,(Gdiplus::REAL)y);
sx = x; sy = y;
}
} else if (cmd == 'L' || cmd == 'l') {
double nx, ny; if(readNum(nx) && readNum(ny)){
if (cmd=='l') { nx += x; ny += y; }
cache->AddLine((Gdiplus::REAL)x,(Gdiplus::REAL)y,
(Gdiplus::REAL)nx,(Gdiplus::REAL)ny);
x = nx; y = ny;
}
} else if (cmd == 'Z' || cmd == 'z') {
cache->CloseFigure();
x = sx; y = sy;
} else {
// TODO: H/V/C/Q
}
}
}

void render(Gdiplus::Graphics& g, const RenderContext& ctx) const override


{
buildPath();
Gdiplus::Matrix old; [Link](&old);
Gdiplus::Matrix m = old; [Link](&transform);
[Link](&m);
Gdiplus::SolidBrush fb(toGdiColor(fill));
Gdiplus::Pen sp(toGdiColor(stroke), strokeWidth);
if (cache) {
[Link](&fb, [Link]());
[Link](&sp, [Link]());
}
[Link](&old);
}
};

2) Transform & kế thừa style

struct TransformUtil {
static void applyTranslate(Gdiplus::Matrix& m, float tx, float ty)
{ [Link](tx, ty, Gdiplus::MatrixOrderAppend); }
static void applyScale(Gdiplus::Matrix& m, float sx, float sy){ [Link](sx,
sy, Gdiplus::MatrixOrderAppend); }
static void applyRotate(Gdiplus::Matrix& m, float deg){ [Link](deg,
Gdiplus::MatrixOrderAppend); }
};

3) ViewBox & Fit-to-Window

void computeFitMatrix(Gdiplus::Matrix& world, float cw, float ch, float vx,


float vy, float vw, float vh){
float sx = cw / vw, sy = ch / vh;
float s = (sx < sy) ? sx : sy;
[Link]();
[Link]((cw - s*vw)*0.5f, (ch - s*vh)*0.5f,
Gdiplus::MatrixOrderAppend);
[Link](s, s, Gdiplus::MatrixOrderAppend);
[Link](-vx, -vy, Gdiplus::MatrixOrderAppend);
}
4) Tương tác: Zoom/Pan/Rotate

// WndProc: xửlý WM_MOUSEWHEEL, WM_LBUTTONDOWN, WM_MOUSEMOVE, WM_KEYDOWN


(R/Shift+R).

You might also like