Class: Geometry::Transformation

Inherits:
Object
  • Object
show all
Defined in:
lib/geometry/transformation.rb,
lib/geometry/transformation/composition.rb

Overview

Transformation represents a relationship between two coordinate frames.

To create a pure translation relationship:

translate = Geometry::Transformation.new(:translate => Point[4, 2])

To create a transformation with an origin and an X-axis aligned with the parent coordinate system’s Y-axis (the Y and Z axes will be chosen arbitrarily):

translate = Geometry::Transformation.new(:origin => [4, 2], :x => [0,1,0])

To create a transformation with an origin, an X-axis aligned with the parent coordinate system’s Y-axis, and a Y-axis aligned with the parent coordinate system’s X-axis:

translate = Geometry::Transformation.new(:origin => [4, 2], :x => [0,1,0], :y => [1,0,0])

Defined Under Namespace

Classes: Composition

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ Transformation

Returns a new instance of Transformation.

Parameters:

  • options (Hash)

    a customizable set of options

Raises:

  • (ArgumentError)


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
# File 'lib/geometry/transformation.rb', line 49

def initialize(*args)
    options, args = args.partition {|a| a.is_a? Hash}
    translate, rotate, scale = args
    options = options.reduce({}, :merge)

    @dimensions = options[:dimensions] || nil

    rotation_options = options.select {|key, value| [:angle, :x, :y, :z].include? key }
    @rotation = options[:rotate] || rotate || ((rotation_options.size > 0) ? Geometry::Rotation.new(rotation_options) : nil)
    @scale = options[:scale] || scale

    case options.count {|k,v| [:move, :origin, :translate].include? k }
	when 0
	    @translation = translate
	when 1
	    @translation = (options[:translate] ||= options.delete(:move) || options.delete(:origin))
	else
	    raise ArgumentError, "Too many translation parameters in #{options}"
    end

    raise ArgumentError, "Bad translation" if @translation.is_a? Hash
    @translation = Point[*@translation]
    if @translation
	@translation = nil if @translation.all? {|v| v == 0}
	raise ArgumentError, ":translate must be a Point or a Vector" if @translation and not @translation.is_a?(Vector)
    end

    if @dimensions
	biggest = [@translation, @scale].select {|a| a}.map {|a| a.size}.max

	if biggest and (biggest != 0) and (((biggest != @dimensions)) or (@rotation and (@rotation.dimensions != biggest)))
	    raise ArgumentError, "Dimensionality mismatch"
	end
    end
end

Instance Attribute Details

#dimensionsObject (readonly)

Returns the value of attribute dimensions.



26
27
28
# File 'lib/geometry/transformation.rb', line 26

def dimensions
  @dimensions
end

#rotationObject (readonly)

Returns the value of attribute rotation.



27
28
29
# File 'lib/geometry/transformation.rb', line 27

def rotation
  @rotation
end

#scaleObject (readonly)

Returns the value of attribute scale.



28
29
30
# File 'lib/geometry/transformation.rb', line 28

def scale
  @scale
end

#translationObject (readonly)

Returns the value of attribute translation.



29
30
31
# File 'lib/geometry/transformation.rb', line 29

def translation
  @translation
end

#x_axisObject (readonly)

Returns the value of attribute x_axis.



31
32
33
# File 'lib/geometry/transformation.rb', line 31

def x_axis
  @x_axis
end

#y_axisObject (readonly)

Returns the value of attribute y_axis.



31
32
33
# File 'lib/geometry/transformation.rb', line 31

def y_axis
  @y_axis
end

#z_axisObject (readonly)

Returns the value of attribute z_axis.



31
32
33
# File 'lib/geometry/transformation.rb', line 31

def z_axis
  @z_axis
end

Instance Method Details

#+(other) ⇒ Object

Compose the current Geometry::Transformation with another one



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/geometry/transformation.rb', line 116

def +(other)
    return self.clone unless other

    case other
	when Array, Vector
	    if @translation
		Transformation.new(@translation+other, @rotation, @scale)
	    else
		Transformation.new(other, @rotation, @scale)
	    end
	when Composition
	    Composition.new(self, *other.transformations)
	when Transformation
	    if @rotation || other.rotation
		Composition.new(self, other)
	    else
		translation = @translation ? (@translation + other.translation) : other.translation
		Transformation.new(translation, @rotation, @scale)
	    end
    end
end

#-(other) ⇒ Object



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/geometry/transformation.rb', line 138

def -(other)
    return self.clone unless other

    case other
	when Array, Vector
	    if @translation
		Transformation.new(@translation-other, @rotation, @scale)
	    else
		Transformation.new(other.map {|e| -e}, @rotation, @scale)
	    end
	when Transformation
	    if @rotation
		rotation = other.rotation ? (@rotation - other.rotation) : @rotation
	    elsif other.rotation
		rotation = -other.rotation
	    else
		rotation = nil
	    end

	    translation = @translation ? (@translation - other.translation) : -other.translation

	    Transformation.new(translation, rotation, @scale)
    end
end

#eql?(other) ⇒ Boolean Also known as: ==

Returns:

  • (Boolean)


103
104
105
106
107
108
109
110
111
112
# File 'lib/geometry/transformation.rb', line 103

def eql?(other)
    return false unless other
    return true if !self.dimensions && !other.dimensions && !self.rotation && !other.rotation && !self.translation && !other.translation && !self.scale && !other.scale
    return false if !(self.dimensions && other.dimensions) && !(self.rotation && other.rotation) && !(self.translation && other.translation) && !(self.scale && other.scale)

    ((self.dimensions && other.dimensions && self.dimensions.eql?(other.dimensions)) || !(self.dimensions && other.dimensions)) &&
    ((self.rotation && other.rotation && self.rotation.eql?(other.rotation)) || !(self.rotation && other.rotation)) &&
    ((self.scale && other.scale && self.scale.eql?(other.scale)) || !(self.scale && other.rotation)) &&
    ((self.translation && other.translation && self.translation.eql?(other.translation)) || !(self.scale && other.rotation))
end

#has_rotation?Boolean

!@attribute [r] has_rotation?

@return [Bool] true if the transformation has any rotation components

Returns:

  • (Boolean)


94
95
96
# File 'lib/geometry/transformation.rb', line 94

def has_rotation?
    !!@rotation
end

#identity?Boolean

Returns true if the Geometry::Transformation is the identity transformation

Returns:

  • (Boolean)


99
100
101
# File 'lib/geometry/transformation.rb', line 99

def identity?
    !(@rotation || @scale || @translation)
end

#initialize_clone(source) ⇒ Object



85
86
87
88
89
90
# File 'lib/geometry/transformation.rb', line 85

def initialize_clone(source)
    super
    @rotation = @rotation.clone if @rotation
    @scale = @scale.clone if @scale
    @translation = @translation.clone if @translation
end

#transform(point) ⇒ Point

Transform and return a new Point. Rotation is applied before translation.

Parameters:

  • point (Point)

    the Point to transform into the parent coordinate frame

Returns:



166
167
168
169
# File 'lib/geometry/transformation.rb', line 166

def transform(point)
    point = @rotation.transform(point) if @rotation
    @translation ? (@translation + point) : point
end