This point can be drawn from point A to B and extends from B with an absolute offset.pull/1/head
| @@ -0,0 +1,90 @@ | |||
| package point | |||
| import ( | |||
| "git.wtrh.nl/wouter/gopatterns/pkg/position" | |||
| "git.wtrh.nl/wouter/gopatterns/pkg/vector" | |||
| "github.com/tdewolff/canvas" | |||
| "math" | |||
| ) | |||
| // ExtendPoint defines a point on the line between two other points. | |||
| type ExtendPoint struct { | |||
| id ID | |||
| from Point | |||
| to Point | |||
| extend float64 | |||
| name string | |||
| draw bool | |||
| hide bool | |||
| } | |||
| // NewExtendPoint returns a new ExtendPoint relative to two other points from and to. | |||
| // The given offset defines where the new point is. | |||
| // With offset = 0 the new point is a from, offset = 0.5 results in a point exactly in the middle. | |||
| func NewExtendPoint(from, to Point, extend float64, id ID) *ExtendPoint { | |||
| return &ExtendPoint{ | |||
| id: id, | |||
| from: from, | |||
| to: to, | |||
| extend: extend, | |||
| name: string(id), | |||
| } | |||
| } | |||
| // Position calculates and returns the absolute [position.Position]. | |||
| func (b *ExtendPoint) Position() position.Position { | |||
| return position.Position{ | |||
| Vector: b.to.Vector().Add(b.extendedVector()), | |||
| Rotation: b.to.Vector().AngleBetween(b.to.Vector()) - math.Pi/2, | |||
| } | |||
| } | |||
| func (b *ExtendPoint) extendedVector() vector.Vector { | |||
| return b.to.Vector().Subtract(b.from.Vector()).Unit().Multiply(b.extend) | |||
| } | |||
| // Vector calculates and returns the absolute [vector.Vector]. | |||
| func (b *ExtendPoint) Vector() vector.Vector { | |||
| return b.Position().Vector | |||
| } | |||
| // Matrix calculates and returns the [canvas.Matrix] of a point. | |||
| func (b *ExtendPoint) Matrix() canvas.Matrix { | |||
| return b.to.Matrix().Translate(b.extendedVector().Values()). | |||
| Rotate((b.from.Vector().AngleBetween(b.to.Vector()) - math.Pi/2) * 180 / math.Pi) | |||
| } | |||
| // ID returns the point ID. | |||
| func (b *ExtendPoint) ID() ID { | |||
| return b.id | |||
| } | |||
| // Name returns the name of a point. | |||
| func (b *ExtendPoint) Name() string { | |||
| return b.name | |||
| } | |||
| // Draw returns if the point should be drawn. | |||
| func (b *ExtendPoint) Draw() bool { | |||
| return b.draw | |||
| } | |||
| // SetDraw indicates that the point should be drawn. | |||
| func (b *ExtendPoint) SetDraw() { | |||
| b.draw = true | |||
| } | |||
| // UnsetDraw indicates that the point should not be drawn. | |||
| func (b *ExtendPoint) UnsetDraw() { | |||
| b.draw = true | |||
| } | |||
| // Hide returns if the point must remain hidden. | |||
| func (b *ExtendPoint) Hide() bool { | |||
| return b.hide | |||
| } | |||
| // SetHide indicates that the must be hidden. | |||
| func (b *ExtendPoint) SetHide() { | |||
| b.hide = true | |||
| } | |||
| @@ -30,6 +30,7 @@ type Point struct { | |||
| RelativeTo *point.ID `yaml:"relativeTo,omitempty"` | |||
| Description string `yaml:"description"` | |||
| Between *BetweenPoint `yaml:"between"` | |||
| Extend *ExtendPoint `yaml:"extend"` | |||
| Hide bool `yaml:"hide"` | |||
| } | |||
| @@ -150,6 +151,11 @@ func (p Points) addSingleToPattern(id point.ID, pat *pattern.Pattern, depth int) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| case templatePoint.Extend != nil: | |||
| newPoint, err = p.createExtend(id, pat, depth) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| default: | |||
| x, y, r, err := templatePoint.Position.evaluate(pat.Parameters(), p.Functions(pat)) | |||
| if err != nil { | |||
| @@ -245,3 +251,39 @@ func (p Points) getOrCreate(id point.ID, pat *pattern.Pattern, depth int) (point | |||
| return createdPoint, nil | |||
| } | |||
| func (p Points) createExtend(id point.ID, pat *pattern.Pattern, depth int) (point.Point, error) { | |||
| newPoint, ok := p[id] | |||
| if !ok { | |||
| return nil, ErrPointNotFound | |||
| } | |||
| if newPoint.Extend.To == id || newPoint.Extend.From == id || depth > maxRecursionDepth { | |||
| return nil, ErrRelativePointRecursion | |||
| } | |||
| fromPoint, err := p.getOrCreate(newPoint.Extend.From, pat, depth) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| toPoint, err := p.getOrCreate(newPoint.Extend.To, pat, depth) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| params := pat.Parameters() | |||
| offset, err := newPoint.Extend.Offset.Evaluate(params, p.Functions(pat)) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| return point.NewExtendPoint(fromPoint, toPoint, offset, id), nil | |||
| } | |||
| type ExtendPoint struct { | |||
| From point.ID `yaml:"from"` | |||
| To point.ID `yaml:"to"` | |||
| Offset *Value `yaml:"offset"` | |||
| } | |||
| @@ -57,6 +57,15 @@ components: | |||
| $ref: '#/components/schemas/expression' | |||
| hide: | |||
| type: bool | |||
| extend: | |||
| type: object | |||
| properties: | |||
| from: | |||
| $ref: '#/components/schemas/pointID' | |||
| to: | |||
| $ref: '#/components/schemas/pointID' | |||
| offset: | |||
| $ref: '#/components/schemas/expression' | |||
| points: | |||
| type: object | |||
| @@ -67,11 +76,11 @@ components: | |||
| type: object | |||
| properties: | |||
| y: | |||
| type: string | |||
| $ref: '#/components/schemas/expression' | |||
| x: | |||
| type: string | |||
| $ref: '#/components/schemas/expression' | |||
| rotation: | |||
| type: string | |||
| $ref: '#/components/schemas/expression' | |||
| line: | |||
| type: object | |||
| @@ -95,8 +104,8 @@ components: | |||
| expression: | |||
| oneOf: | |||
| - type: integer | |||
| - type: number | |||
| - type: string | |||
| @@ -80,7 +80,7 @@ points: | |||
| between: | |||
| from: 16 | |||
| to: 18 | |||
| offset: 0.5 | |||
| absolute: 0.5 | |||
| 20: | |||
| position: | |||
| x: 20 | |||
| @@ -87,23 +87,16 @@ points: | |||
| position: | |||
| x: -rugbreedte/2 | |||
| relativeTo: H | |||
| Nrotated: | |||
| position: | |||
| rotation: AngleBetween("N","Q") | |||
| relativeTo: N | |||
| V: | |||
| position: | |||
| x: DistanceBetween("R","W")-10 | |||
| relativeTo: Nrotated | |||
| Rrotated: | |||
| position: | |||
| rotation: AngleBetween("R","T") | |||
| relativeTo: R | |||
| extend: | |||
| from: Q | |||
| to: N | |||
| offset: -(DistanceBetween("R","W") - 10) | |||
| W: | |||
| position: | |||
| x: DistanceBetween("R","T") + 20 | |||
| relativeTo: Rrotated | |||
| extend: | |||
| from: R | |||
| to: T | |||
| offset: 20 | |||
| panels: | |||
| basis: | |||