-
Notifications
You must be signed in to change notification settings - Fork 110
/
geometry.go
105 lines (92 loc) · 3.32 KB
/
geometry.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package spatialmath
import (
"encoding/json"
"github.com/golang/geo/r3"
commonpb "go.viam.com/rdk/proto/api/common/v1"
)
// GeometryCreator provides a common way to instantiate Geometries.
type GeometryCreator interface {
NewGeometry(Pose) Geometry
json.Marshaler
}
// Geometry is an entry point with which to access all types of collision geometries.
type Geometry interface {
Pose() Pose
Vertices() []r3.Vector
AlmostEqual(Geometry) bool
Transform(Pose) Geometry
ToProtobuf() *commonpb.Geometry
CollidesWith(Geometry) (bool, error)
DistanceFrom(Geometry) (float64, error)
EncompassedBy(Geometry) (bool, error)
}
// GeometryConfig specifies the format of geometries specified through the configuration file.
type GeometryConfig struct {
Type string `json:"type"`
// parameters used for defining a box's rectangular cross section
X float64 `json:"x"`
Y float64 `json:"y"`
Z float64 `json:"z"`
// parameters used for defining a sphere, its radius
R float64 `json:"r"`
// define an offset to position the geometry
TranslationOffset TranslationConfig `json:"translation"`
OrientationOffset OrientationConfig `json:"orientation"`
}
// NewGeometryConfig creates a config for a Geometry from an offset Pose.
func NewGeometryConfig(offset Pose) (*GeometryConfig, error) {
o := offset.Orientation()
translationConfig := NewTranslationConfig(Compose(NewPoseFromOrientation(r3.Vector{}, OrientationInverse(o)), offset).Point())
orientationConfig, err := NewOrientationConfig(o.AxisAngles())
if err != nil {
return nil, err
}
return &GeometryConfig{
TranslationOffset: *translationConfig,
OrientationOffset: *orientationConfig,
}, nil
}
// ParseConfig converts a GeometryConfig into the correct GeometryCreator type, as specified in its Type field.
func (config *GeometryConfig) ParseConfig() (GeometryCreator, error) {
// determine offset to use
orientation, err := config.OrientationOffset.ParseConfig()
if err != nil {
return nil, err
}
offset := Compose(NewPoseFromOrientation(r3.Vector{}, orientation), NewPoseFromPoint(config.TranslationOffset.ParseConfig()))
// build GeometryCreator depending on specified type
switch config.Type {
case "box":
return NewBoxCreator(r3.Vector{X: config.X, Y: config.Y, Z: config.Z}, offset)
case "sphere":
return NewSphereCreator(config.R, offset)
case "point":
return NewPointCreator(offset), nil
case "":
// no type specified, iterate through supported types and try to infer intent
creator, err := NewBoxCreator(r3.Vector{X: config.X, Y: config.Y, Z: config.Z}, offset)
if err == nil {
return creator, nil
}
creator, err = NewSphereCreator(config.R, offset)
if err == nil {
return creator, nil
}
// never try to infer point geometry if nothing is specified
}
return nil, newGeometryTypeUnsupportedError(config.Type)
}
// NewGeometryFromProto instatiates a new Geometry from a protobuf Geometry message.
func NewGeometryFromProto(geometry *commonpb.Geometry) (Geometry, error) {
pose := NewPoseFromProtobuf(geometry.Center)
if box := geometry.GetBox().GetDimsMm(); box != nil {
return NewBox(pose, r3.Vector{X: box.X, Y: box.Y, Z: box.Z})
}
if sphere := geometry.GetSphere(); sphere != nil {
if sphere.RadiusMm == 0 {
return NewPoint(pose.Point()), nil
}
return NewSphere(pose.Point(), sphere.RadiusMm)
}
return nil, newGeometryTypeUnsupportedError("")
}