Transform transforms the path by the given transformation matrix. It modifies the path in-place.
(m Matrix)
| 1265 | |
| 1266 | // Transform transforms the path by the given transformation matrix. It modifies the path in-place. |
| 1267 | func (p *Path) Transform(m Matrix) *Path { |
| 1268 | _, _, _, xscale, yscale, _ := m.Decompose() |
| 1269 | for i := 0; i < len(p.d); { |
| 1270 | cmd := p.d[i] |
| 1271 | switch cmd { |
| 1272 | case MoveToCmd, LineToCmd, CloseCmd: |
| 1273 | end := m.Dot(Point{p.d[i+1], p.d[i+2]}) |
| 1274 | p.d[i+1] = end.X |
| 1275 | p.d[i+2] = end.Y |
| 1276 | case QuadToCmd: |
| 1277 | cp := m.Dot(Point{p.d[i+1], p.d[i+2]}) |
| 1278 | end := m.Dot(Point{p.d[i+3], p.d[i+4]}) |
| 1279 | p.d[i+1] = cp.X |
| 1280 | p.d[i+2] = cp.Y |
| 1281 | p.d[i+3] = end.X |
| 1282 | p.d[i+4] = end.Y |
| 1283 | case CubeToCmd: |
| 1284 | cp1 := m.Dot(Point{p.d[i+1], p.d[i+2]}) |
| 1285 | cp2 := m.Dot(Point{p.d[i+3], p.d[i+4]}) |
| 1286 | end := m.Dot(Point{p.d[i+5], p.d[i+6]}) |
| 1287 | p.d[i+1] = cp1.X |
| 1288 | p.d[i+2] = cp1.Y |
| 1289 | p.d[i+3] = cp2.X |
| 1290 | p.d[i+4] = cp2.Y |
| 1291 | p.d[i+5] = end.X |
| 1292 | p.d[i+6] = end.Y |
| 1293 | case ArcToCmd: |
| 1294 | rx := p.d[i+1] |
| 1295 | ry := p.d[i+2] |
| 1296 | phi := p.d[i+3] |
| 1297 | large, sweep := toArcFlags(p.d[i+4]) |
| 1298 | end := Point{p.d[i+5], p.d[i+6]} |
| 1299 | |
| 1300 | // For ellipses written as the conic section equation in matrix form, we have: |
| 1301 | // [x, y] E [x; y] = 0, with E = [1/rx^2, 0; 0, 1/ry^2] |
| 1302 | // For our transformed ellipse we have [x', y'] = T [x, y], with T the affine |
| 1303 | // transformation matrix so that |
| 1304 | // (T^-1 [x'; y'])^T E (T^-1 [x'; y'] = 0 => [x', y'] T^(-T) E T^(-1) [x'; y'] = 0 |
| 1305 | // We define Q = T^(-1,T) E T^(-1) the new ellipse equation which is typically rotated |
| 1306 | // from the x-axis. That's why we find the eigenvalues and eigenvectors (the new |
| 1307 | // direction and length of the major and minor axes). |
| 1308 | T := m.Rotate(phi * 180.0 / math.Pi) |
| 1309 | invT := T.Inv() |
| 1310 | Q := Identity.Scale(1.0/rx/rx, 1.0/ry/ry) |
| 1311 | Q = invT.T().Mul(Q).Mul(invT) |
| 1312 | |
| 1313 | lambda1, lambda2, v1, v2 := Q.Eigen() |
| 1314 | rx = 1 / math.Sqrt(lambda1) |
| 1315 | ry = 1 / math.Sqrt(lambda2) |
| 1316 | phi = v1.Angle() |
| 1317 | if rx < ry { |
| 1318 | rx, ry = ry, rx |
| 1319 | phi = v2.Angle() |
| 1320 | } |
| 1321 | phi = angleNorm(phi) |
| 1322 | if math.Pi <= phi { // phi is canonical within 0 <= phi < 180 |
| 1323 | phi -= math.Pi |
| 1324 | } |
no test coverage detected