Monkey Patching Vec3D
Re-Opening Vec3D to add rotation funtionality
Whilst translating toxiclibs
example for JRubyArt I came across this mesh doodle sketch, that I realised I could make work just using my Vec2D and Vec3D classes (and avoid using the toxicilibs
library). I just needed to add some rotation functionality to my Vec3D class as follows (and to use a struct for Face):-
# After a toxiclibs "MeshDoodle" sketch by Karsten Schmidt
# Adapted to use JRubyArt Vec2D and Vec3D classes by Martin Prout
# Note: The extension Vec3D class to support rotations and use of a Struct
# for triangle 'mesh' Face. Also use of AppRenderer for Vec3D => vertex
attr_reader :prev, :p, :q, :rotation, :faces, :pos, :weight, :renderer
Face = Struct.new(:a, :b, :c)
Vec3D.class_eval do # re-open the Vec3D class to add rotation functionality
def rotate_y(theta)
co = Math.cos(theta)
si = Math.sin(theta)
xx = co * x - si * z
self.z = si * x + co * z
self.x = xx
self
end
def rotate_x(theta)
co = Math.cos(theta)
si = Math.sin(theta)
zz = co * z - si * y
self.y = si * z + co * y
self.z = zz
self
end
end
def settings
size(600, 600, P3D)
end
def setup
sketch_title 'Ribbon Doodle'
@renderer = AppRender.new(self)
@weight = 0
@prev = Vec3D.new
@p = Vec3D.new
@q = Vec3D.new
@rotation = Vec2D.new
@faces = []
end
def draw
background(0)
lights
translate(width / 2, height / 2, 0)
rotate_x(rotation.x)
rotate_y(rotation.y)
no_stroke
begin_shape(TRIANGLES)
# iterate over all faces/triangles of the 'mesh'
faces.each do |f|
# create vertices for each corner point
f.a.to_vertex(renderer)
f.b.to_vertex(renderer)
f.c.to_vertex(renderer)
end
end_shape
# update rotation
@rotation += Vec2D.new(0.014, 0.0237)
end
def mouse_moved
# get 3D rotated mouse position
@pos = Vec3D.new(mouse_x - width / 2, mouse_y - height / 2, 0)
pos.rotate_x(rotation.x)
pos.rotate_y(rotation.y)
# use distance to previous point as target stroke weight
@weight += (sqrt(pos.dist(prev)) * 2 - weight) * 0.1
# define offset points for the triangle strip
a = pos + Vec3D.new(0, 0, weight)
b = pos + Vec3D.new(0, 0, -weight)
# add 2 faces to the mesh
faces << Face.new(p, b, q)
faces << Face.new(p, a, b)
# store current points for next iteration
@prev = pos
@p = a
@q = b
end