Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions AddConstraints_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package dlineate

import (
"math"
"math/big"
"testing"

"github.com/marcuswu/dlineate/utils"
Expand All @@ -28,13 +29,13 @@ func TestAddAngleConstraint(t *testing.T) {

assert.NotNil(t, c1, "AngleConstraint should be created")
assert.Nil(t, err, "AngleConstraint should be created")
assert.Equal(t, (40/180.0)*math.Pi, c1.constraints[0].Value, "Angle constraint is 40 degrees")
assert.Equal(t, 0, utils.StandardBigFloatCompare(big.NewFloat((40/180.0)*math.Pi), &c1.constraints[0].Value), "Angle constraint is 40 degrees")

c1, err = s.AddAngleConstraint(l1, l2, 40, true)

assert.NotNil(t, c1, "AngleConstraint should be created")
assert.Nil(t, err, "AngleConstraint should be created")
assert.Equal(t, (140/180.0)*math.Pi, c1.constraints[0].Value, "Angle constraint is 140 degrees")
assert.Equal(t, 0, utils.StandardBigFloatCompare(big.NewFloat((140/180.0)*math.Pi), &c1.constraints[0].Value), "Angle constraint is 140 degrees")
}

func TestAddCoincidentConstraint(t *testing.T) {
Expand Down
19 changes: 15 additions & 4 deletions AngleConstraint.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package dlineate
import (
"errors"
"math"
"math/big"

ic "github.com/marcuswu/dlineate/internal/constraint"
"github.com/marcuswu/dlineate/utils"
)

func AngleConstraint(p1 *Element, p2 *Element) *Constraint {
Expand All @@ -26,15 +28,24 @@ func (s *Sketch) AddAngleConstraint(p1 *Element, p2 *Element, v float64, useSupp
return nil, errors.New("incorrect element types for angle constraint")
}

radians := v / 180 * math.Pi
radiansAlt := math.Pi - math.Abs(radians)
var halfCir, pi, angle, radians, radiansAlt, t big.Float
halfCir.SetPrec(utils.FloatPrecision).SetFloat64(180)
pi.SetPrec(utils.FloatPrecision).SetFloat64(math.Pi)
angle.SetPrec(utils.FloatPrecision).SetFloat64(v)

// radians := v / 180 * math.Pi
radians.SetPrec(utils.FloatPrecision).Quo(&angle, &halfCir)
radians.Mul(&radians, &pi)
// radiansAlt := math.Pi - math.Abs(radians)
t.SetPrec(utils.FloatPrecision).Abs(&radians)
radiansAlt.Sub(&pi, &t)

if useSupplementary {
// if useSupplementary || math.Abs(math.Abs(currentAngle)-math.Abs(radiansAlt)) < math.Abs(math.Abs(currentAngle)-math.Abs(radians)) {
radians = radiansAlt
radians.Set(&radiansAlt)
}

constraint := s.sketch.AddConstraint(ic.Angle, p1.element, p2.element, radians)
constraint := s.sketch.AddConstraint(ic.Angle, p1.element, p2.element, &radians)
p1.constraints = append(p1.constraints, constraint)
p2.constraints = append(p2.constraints, constraint)
c.constraints = append(c.constraints, constraint)
Expand Down
19 changes: 13 additions & 6 deletions DistanceConstraint.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package dlineate

import (
"math/big"

ic "github.com/marcuswu/dlineate/internal/constraint"
"github.com/marcuswu/dlineate/utils"
)
Expand All @@ -18,13 +20,15 @@ func DistanceConstraint(p1 *Element, p2 *Element) *Constraint {
}

func (s *Sketch) addDistanceConstraint(p1 *Element, p2 *Element, v float64) *ic.Constraint {
var value big.Float
value.SetPrec(utils.FloatPrecision).SetFloat64(v)
switch p1.elementType {
case Point:
if p2.elementType != Point {
return s.addDistanceConstraint(p2, p1, v)
}

return s.sketch.AddConstraint(ic.Distance, p1.element, p2.element, v)
return s.sketch.AddConstraint(ic.Distance, p1.element, p2.element, &value)
case Circle:
if p2 == nil {
// If p2 is nil, we're setting the circle radius
Expand All @@ -44,14 +48,14 @@ func (s *Sketch) addDistanceConstraint(p1 *Element, p2 *Element, v float64) *ic.
p1.children[0].element.GetID(),
p1.children[1].element.GetID(),
)
return s.sketch.AddConstraint(ic.Distance, p1.children[0].element, p1.children[1].element, v)
return s.sketch.AddConstraint(ic.Distance, p1.children[0].element, p1.children[1].element, &value)
}
isCircle := p2.elementType == Circle
isArc := p2.elementType == Arc
if isArc || isCircle {
return s.addDistanceConstraint(p2, p1, v)
}
return s.sketch.AddConstraint(ic.Distance, p1.element, p2.element, v)
return s.sketch.AddConstraint(ic.Distance, p1.element, p2.element, &value)
case Arc:
if p2 == nil {
// Add a constraint to pkg/Sketch (not translatable to internal solver)
Expand Down Expand Up @@ -115,20 +119,23 @@ func (s *Sketch) resolveCurveDistance(e1 *Element, e2 *Element, c *Constraint) b
utils.Logger.Debug().
Float64("center x", e1.values[0]).
Float64("center y", e1.values[1]).
Float64("radius", eRadius).
Str("radius", eRadius.String()).
Msg("Resolved curve radius")
var constraint *ic.Constraint = nil
if e2 != nil {
e1Element := e1.element
if e1.elementType == Circle {
e1Element = e1.Center().element
}
constraint = s.sketch.AddConstraint(ic.Distance, e1Element, e2.element, eRadius+c.dataValue)
var dv big.Float
dv.SetPrec(utils.FloatPrecision).SetFloat64(c.dataValue)
dv.Add(&dv, eRadius)
constraint = s.sketch.AddConstraint(ic.Distance, e1Element, e2.element, &dv)
utils.Logger.Debug().
Uint("constraint id", constraint.GetID()).
Uint("element 1", constraint.Element1).
Uint("element 2", constraint.Element2).
Float64("value", constraint.Value).
Str("value", constraint.Value.String()).
Msg("Resolved curve radius")
}
utils.Logger.Debug().
Expand Down
90 changes: 60 additions & 30 deletions Element.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"math"
"math/big"
"strings"

c "github.com/marcuswu/dlineate/internal/constraint"
Expand Down Expand Up @@ -72,20 +73,20 @@ func (e *Element) valuesFromSketch(s *Sketch) error {
switch e.elementType {
case Point:
p := e.element.AsPoint()
e.values[0] = p.GetX()
e.values[1] = p.GetY()
e.values[0], _ = p.GetX().Float64()
e.values[1], _ = p.GetY().Float64()
case Axis:
p := e.element.AsLine()
e.values[0] = p.GetA()
e.values[1] = p.GetB()
e.values[2] = p.GetC()
e.values[0], _ = p.GetA().Float64()
e.values[1], _ = p.GetB().Float64()
e.values[2], _ = p.GetC().Float64()
case Line:
p1 := e.children[0].element.AsPoint()
p2 := e.children[1].element.AsPoint()
e.values[0] = p1.GetX()
e.values[1] = p1.GetY()
e.values[2] = p2.GetX()
e.values[3] = p2.GetY()
e.values[0], _ = p1.GetX().Float64()
e.values[1], _ = p1.GetY().Float64()
e.values[2], _ = p2.GetX().Float64()
e.values[3], _ = p2.GetY().Float64()
case Circle:
/*
Circle radius is determined either by
Expand All @@ -94,8 +95,8 @@ func (e *Element) valuesFromSketch(s *Sketch) error {
*/
var err error = nil
c := e.children[0].element.AsPoint()
e.values[0] = c.GetX()
e.values[1] = c.GetY()
e.values[0], _ = c.GetX().Float64()
e.values[1], _ = c.GetY().Float64()
// find distance constraint on e
constraint, err := s.findConstraint(Distance, e)
if err != nil {
Expand All @@ -112,12 +113,12 @@ func (e *Element) valuesFromSketch(s *Sketch) error {
center := e.children[0].element.AsPoint()
start := e.children[1].element.AsPoint()
end := e.children[2].element.AsPoint()
e.values[0] = center.GetX()
e.values[1] = center.GetY()
e.values[2] = start.GetX()
e.values[3] = start.GetY()
e.values[4] = end.GetX()
e.values[5] = end.GetY()
e.values[0], _ = center.GetX().Float64()
e.values[1], _ = center.GetY().Float64()
e.values[2], _ = start.GetX().Float64()
e.values[3], _ = start.GetY().Float64()
e.values[4], _ = end.GetX().Float64()
e.values[5], _ = end.GetY().Float64()
}
e.valuePass = s.passes

Expand All @@ -138,7 +139,8 @@ func (e *Element) getCircleRadius(s *Sketch, c *Constraint) (float64, error) {
other, _ = s.sketch.GetElement(constraint.Element2)
}

return other.DistanceTo(e.children[0].element.AsPoint()), nil
dist, _ := other.DistanceTo(e.children[0].element.AsPoint()).Float64()
return dist, nil
}

return 0, errors.New("Constraint type for circle radius must be Distance or Coincident")
Expand Down Expand Up @@ -364,17 +366,28 @@ func (e *Element) PointVerticalFrom(x, y float64) (float64, float64, bool) {
log.Debug().Msg("element is not castable to Line")
return 0, 0, false
}
start := l.NearestPoint(0, 0)
start := l.NearestPoint(big.NewFloat(0), big.NewFloat(0))
var t1 big.Float
var newY float64
if utils.StandardFloatCompare(-l.GetA(), 0) == 0 {
t1.Neg(l.GetA())
if utils.StandardBigFloatCompare(&t1, big.NewFloat(0)) == 0 {
if l.GetB().Cmp(big.NewFloat(0)) == 0 {
// a and b shouldn't both be 0
return 0, 0, false
}
// horizontal line
newY = -l.GetC() / l.GetB()
} else if utils.StandardFloatCompare(l.GetB(), 0) == 0 {
c, _ := l.GetC().Float64()
b, _ := l.GetB().Float64()
newY = -c / b
} else if utils.StandardBigFloatCompare(l.GetB(), big.NewFloat(0)) == 0 {
log.Debug().Msg("incorrect slope")
return 0, 0, false // if our element is already a vertical line, a vertical distance constraint makes no sense
} else {
slope := l.GetSlope()
newY = (slope * (x - start.X)) + start.Y
// newY = (slope * (x - start.X)) + start.Y
slope, _ := l.GetSlope().Float64()
startX, _ := start.X.Float64()
startY, _ := start.Y.Float64()
newY = (slope * (x - startX)) + startY
}
return x, newY, true
}
Expand All @@ -387,20 +400,37 @@ func (e *Element) PointHorizontalFrom(x, y float64) (float64, float64, bool) {
if l == nil {
return 0, 0, false
}
start := l.NearestPoint(0, 0)
var zero, t1 big.Float
zero.SetFloat64(0)
start := l.NearestPoint(&zero, &zero)
var newX float64
if utils.StandardFloatCompare(-l.GetA(), 0) == 0 {
t1.Neg(l.GetA())
if utils.StandardBigFloatCompare(&t1, &zero) == 0 {
return 0, 0, false // if our element is already a vertical line, a vertical distance constraint makes no sense
} else if utils.StandardFloatCompare(l.GetB(), 0) == 0 {
} else if utils.StandardBigFloatCompare(l.GetB(), &zero) == 0 {
// vertical line
newX = -l.GetC() / l.GetA()
c, _ := l.GetC().Float64()
a, _ := l.GetA().Float64()
newX = -c / a
} else {
slope := l.GetSlope()
newX = ((y - start.Y) / slope) + start.X
slope, _ := l.GetSlope().Float64()
startX, _ := start.X.Float64()
startY, _ := start.Y.Float64()
newX = ((y - startY) / slope) + startX
}
return newX, y, true
}

func (e *Element) DistanceBetweenPoints(other *Element) float64 {
if e.elementType != Point || other.elementType != Point {
return math.NaN()
}
p := e.element.AsPoint()
o := other.element.AsPoint()
dist, _ := p.DistanceTo(o).Float64()
return dist
}

func (e *Element) String() string {
values := make([]string, len(e.values))
for i, value := range e.values {
Expand Down
27 changes: 14 additions & 13 deletions Element_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dlineate

import (
"math/big"
"testing"

"github.com/marcuswu/dlineate/internal/constraint"
Expand All @@ -27,12 +28,12 @@ func TestElementTypeString(t *testing.T) {
func TestValuesFromSketch(t *testing.T) {
s := NewSketch()
arc := s.AddArc(0, 0, 1, 1, 2, 2)
arc.children[0].element.AsPoint().X = 1
arc.children[0].element.AsPoint().Y = 2
arc.children[1].element.AsPoint().X = 3
arc.children[1].element.AsPoint().Y = 4
arc.children[2].element.AsPoint().X = 5
arc.children[2].element.AsPoint().Y = 6
arc.children[0].element.AsPoint().X.SetFloat64(1)
arc.children[0].element.AsPoint().Y.SetFloat64(2)
arc.children[1].element.AsPoint().X.SetFloat64(3)
arc.children[1].element.AsPoint().Y.SetFloat64(4)
arc.children[2].element.AsPoint().X.SetFloat64(5)
arc.children[2].element.AsPoint().Y.SetFloat64(6)

s.XAxis.valuesFromSketch(s)
assert.Equal(t, 0.0, s.XAxis.values[0])
Expand Down Expand Up @@ -64,7 +65,7 @@ func TestGetCircleRadius(t *testing.T) {

c = s.AddCircle(1, 0, 2)
c3 := s.AddCoincidentConstraint(c, o)
c3.constraints = append(c3.constraints, s.sketch.AddConstraint(constraint.Distance, c.Center().element, o.element, 1.0))
c3.constraints = append(c3.constraints, s.sketch.AddConstraint(constraint.Distance, c.Center().element, o.element, big.NewFloat(1.0)))
dist, err = c.getCircleRadius(s, c3)
assert.Nil(t, err, "Should have no error looking for a circle")
assert.Equal(t, 1.0, dist, "Should find circle distance")
Expand All @@ -73,12 +74,12 @@ func TestGetCircleRadius(t *testing.T) {
func TestGetValues(t *testing.T) {
s := NewSketch()
arc := s.AddArc(0, 0, 1, 1, 2, 2)
arc.children[0].element.AsPoint().X = 1
arc.children[0].element.AsPoint().Y = 2
arc.children[1].element.AsPoint().X = 3
arc.children[1].element.AsPoint().Y = 4
arc.children[2].element.AsPoint().X = 5
arc.children[2].element.AsPoint().Y = 6
arc.children[0].element.AsPoint().X.SetFloat64(1)
arc.children[0].element.AsPoint().Y.SetFloat64(2)
arc.children[1].element.AsPoint().X.SetFloat64(3)
arc.children[1].element.AsPoint().Y.SetFloat64(4)
arc.children[2].element.AsPoint().X.SetFloat64(5)
arc.children[2].element.AsPoint().Y.SetFloat64(6)

values := arc.Values()
assert.Equal(t, 0.0, values[0])
Expand Down
Loading