Close closes a (sub)path with a LineTo to the start of the path (the most recent MoveTo command). It also signals the path closes as opposed to being just a LineTo command, which can be significant for stroking purposes for example.
()
| 559 | |
| 560 | // Close closes a (sub)path with a LineTo to the start of the path (the most recent MoveTo command). It also signals the path closes as opposed to being just a LineTo command, which can be significant for stroking purposes for example. |
| 561 | func (p *Path) Close() { |
| 562 | if len(p.d) == 0 || p.d[len(p.d)-1] == CloseCmd { |
| 563 | // already closed or empty |
| 564 | return |
| 565 | } else if p.d[len(p.d)-1] == MoveToCmd { |
| 566 | // remove MoveTo + Close |
| 567 | p.d = p.d[:len(p.d)-cmdLen(MoveToCmd)] |
| 568 | return |
| 569 | } |
| 570 | |
| 571 | end := p.StartPos() |
| 572 | if p.d[len(p.d)-1] == LineToCmd && Equal(p.d[len(p.d)-3], end.X) && Equal(p.d[len(p.d)-2], end.Y) { |
| 573 | // replace LineTo by Close if equal (replace coordinates to ensure they match exactly) |
| 574 | p.d[len(p.d)-cmdLen(LineToCmd)] = CloseCmd |
| 575 | p.d[len(p.d)-3] = end.X |
| 576 | p.d[len(p.d)-2] = end.Y |
| 577 | p.d[len(p.d)-1] = CloseCmd |
| 578 | return |
| 579 | } else if p.d[len(p.d)-1] == LineToCmd { |
| 580 | // replace LineTo by Close if equidirectional extension |
| 581 | start := Point{p.d[len(p.d)-3], p.d[len(p.d)-2]} |
| 582 | prevStart := Point{} |
| 583 | if cmdLen(LineToCmd) < len(p.d) { |
| 584 | prevStart = Point{p.d[len(p.d)-cmdLen(LineToCmd)-3], p.d[len(p.d)-cmdLen(LineToCmd)-2]} |
| 585 | } |
| 586 | if Equal(end.Sub(start).AngleBetween(start.Sub(prevStart)), 0.0) { |
| 587 | p.d[len(p.d)-cmdLen(LineToCmd)] = CloseCmd |
| 588 | p.d[len(p.d)-3] = end.X |
| 589 | p.d[len(p.d)-2] = end.Y |
| 590 | p.d[len(p.d)-1] = CloseCmd |
| 591 | return |
| 592 | } |
| 593 | } |
| 594 | p.d = append(p.d, CloseCmd, end.X, end.Y, CloseCmd) |
| 595 | } |
| 596 | |
| 597 | // optimizeClose removes a superfluous first line segment in-place of a subpath. If both the first and last segment are line segments and are colinear, move the start of the path forward one segment |
| 598 | func (p *Path) optimizeClose() { |