diff --git a/pkg/pattern/point/extend_point.go b/pkg/pattern/point/extend_point.go new file mode 100644 index 0000000..9a172e1 --- /dev/null +++ b/pkg/pattern/point/extend_point.go @@ -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 +} diff --git a/pkg/pattern/template/point.go b/pkg/pattern/template/point.go index 552c0bb..8fb50e2 100644 --- a/pkg/pattern/template/point.go +++ b/pkg/pattern/template/point.go @@ -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"` +} diff --git a/spec/template.yaml b/spec/pattern.yaml similarity index 82% rename from spec/template.yaml rename to spec/pattern.yaml index 6b705d4..feb676a 100644 --- a/spec/template.yaml +++ b/spec/pattern.yaml @@ -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 - diff --git a/templates/basic_trouser_block.yaml b/templates/basic_trouser_block.yaml index a58a06b..018781e 100644 --- a/templates/basic_trouser_block.yaml +++ b/templates/basic_trouser_block.yaml @@ -80,7 +80,7 @@ points: between: from: 16 to: 18 - offset: 0.5 + absolute: 0.5 20: position: x: 20 diff --git a/templates/basis_grondpatroon_heren.yaml b/templates/basis_grondpatroon_heren.yaml index 2092b57..7078d76 100644 --- a/templates/basis_grondpatroon_heren.yaml +++ b/templates/basis_grondpatroon_heren.yaml @@ -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: