replace replaces path segments by their respective functions, each returning the path that will replace the segment or nil if no replacement is to be performed. The line function will take the start and end points. The bezier function will take the start point, control point 1 and 2, and the end poi
( line func(Point, Point) *Path, quad func(Point, Point, Point) *Path, cube func(Point, Point, Point, Point) *Path, arc func(Point, float64, float64, float64, bool, bool, Point) *Path, )
| 1479 | |
| 1480 | // replace replaces path segments by their respective functions, each returning the path that will replace the segment or nil if no replacement is to be performed. The line function will take the start and end points. The bezier function will take the start point, control point 1 and 2, and the end point (i.e. a cubic Bézier, quadratic Béziers will be implicitly converted to cubic ones). The arc function will take a start point, the major and minor radii, the radial rotation counter clockwise, the large and sweep booleans, and the end point. The replacing path will replace the path segment without any checks, you need to make sure the be moved so that its start point connects with the last end point of the base path before the replacement. If the end point of the replacing path is different that the end point of what is replaced, the path that follows will be displaced. |
| 1481 | func (p *Path) replace( |
| 1482 | line func(Point, Point) *Path, |
| 1483 | quad func(Point, Point, Point) *Path, |
| 1484 | cube func(Point, Point, Point, Point) *Path, |
| 1485 | arc func(Point, float64, float64, float64, bool, bool, Point) *Path, |
| 1486 | ) *Path { |
| 1487 | copied := false |
| 1488 | var start, end Point |
| 1489 | for i := 0; i < len(p.d); { |
| 1490 | var q *Path |
| 1491 | cmd := p.d[i] |
| 1492 | switch cmd { |
| 1493 | case LineToCmd, CloseCmd: |
| 1494 | if line != nil { |
| 1495 | end = Point{p.d[i+1], p.d[i+2]} |
| 1496 | q = line(start, end) |
| 1497 | if cmd == CloseCmd { |
| 1498 | q.Close() |
| 1499 | } |
| 1500 | } |
| 1501 | case QuadToCmd: |
| 1502 | if quad != nil { |
| 1503 | cp := Point{p.d[i+1], p.d[i+2]} |
| 1504 | end = Point{p.d[i+3], p.d[i+4]} |
| 1505 | q = quad(start, cp, end) |
| 1506 | } |
| 1507 | case CubeToCmd: |
| 1508 | if cube != nil { |
| 1509 | cp1 := Point{p.d[i+1], p.d[i+2]} |
| 1510 | cp2 := Point{p.d[i+3], p.d[i+4]} |
| 1511 | end = Point{p.d[i+5], p.d[i+6]} |
| 1512 | q = cube(start, cp1, cp2, end) |
| 1513 | } |
| 1514 | case ArcToCmd: |
| 1515 | if arc != nil { |
| 1516 | rx, ry, phi := p.d[i+1], p.d[i+2], p.d[i+3] |
| 1517 | large, sweep := toArcFlags(p.d[i+4]) |
| 1518 | end = Point{p.d[i+5], p.d[i+6]} |
| 1519 | q = arc(start, rx, ry, phi, large, sweep, end) |
| 1520 | } |
| 1521 | } |
| 1522 | |
| 1523 | if q != nil { |
| 1524 | if !copied { |
| 1525 | p = p.Copy() |
| 1526 | copied = true |
| 1527 | } |
| 1528 | |
| 1529 | r := &Path{append([]float64{MoveToCmd, end.X, end.Y, MoveToCmd}, p.d[i+cmdLen(cmd):]...)} |
| 1530 | |
| 1531 | p.d = p.d[: i : i+cmdLen(cmd)] // make sure not to overwrite the rest of the path |
| 1532 | p = p.Join(q) |
| 1533 | if cmd != CloseCmd { |
| 1534 | p.LineTo(end.X, end.Y) |
| 1535 | } |
| 1536 | |
| 1537 | i = len(p.d) |
| 1538 | p = p.Join(r) // join the rest of the base path |