Showing posts with label ruby. Show all posts
Showing posts with label ruby. Show all posts

Monday, March 2, 2009

Ruby Vector2D

A 2D Vector for Ruby. This is for the Koch snowflake and future 2D examples. Feel free to let me know how I can improve it, or where I can find a good third-party implementation.

Writing geometry classes has been one of my biggest frustrations because of the different implementations, or lack thereof, in the various graphics packages. As a result of this, my first instinct when picking up a new framework is figuring out what geometry is supported and the operations that are available.

A good geometry class for points, vectors, lines, shapes, etc., can save you a lot of headache trying to remember how to do a certain geometrical operation, and focus instead on putting these operations together.


# Use this so glVertex works.
require 'opengl'

class Vector
attr_accessor :x, :y;

def initialize(x,y)
self.x = x
self.y = y
end

def gl_vertex
GL::Vertex2f(x,y)
end

def normal
Vector.new(-@y,@x)
end

def normalize
before_length = length
return if before_length == 0
@x /= before_length
@y /= before_length
end

def length
return Math.sqrt(@x*@x + @y*@y)
end

def reverse
@x = -@x
@y = -@y
end

def add_vector(v)
@x += v.x
@y += v.y
end

def sub_vector(v)
@x -= v.x
@y -= v.y
end

def multiply(scalar)
@x *= scalar
@y *= scalar
end

def divide(scalar)
@x = @x / (1.0 * scalar)
@y = @y / (1.0 * scalar)
end

def Vector.copy(p)
return Vector.new(p.x,p.y)
end

def Vector.between(p1,p2)
between = Vector.new(p2.x,p2.y)
between.sub_vector(p1)
return between
end

def to_s
"#{x}, #{y}"
end

def Vector.midpoint(p1, p2)
midpoint = Vector.new(p1.x,p1.y)
midpoint.add_vector(p2)
midpoint.divide(2.0)
return midpoint
end
end

Koch Snowflake



What is is?

Wolfram's Koch Snowflake.

The Recipe

  1. Take a line.
  2. Divide into three parts.
  3. Take the middle part and create an equilateral triangle bump from it.
  4. Repeat steps using each of the lines from the new shape.

Visually

To make the Koch snowflake, you start with three lines that make an equilateral triangle.







Ruby Version



# A vector implementation I made
require 'vector.rb'

class Koch
# Creates a Koch line from point p1 to point p2
def initialize(p1,p2)
@points = [p1,p2]
end


# Creates the next step in the fractal
def step
p1 = @points.shift
new_array = [p1]

# For all points in the shape,
# divide the line from next p1
# to next p2.
while(@points.length > 0)
p2 = @points.shift

third = Vector.between(p1,p2)
third.multiply(0.333)
two_third = Vector.between(p1,p2)
two_third.multiply(0.666)

# Adds p1 to the delta between p1 and p2 to
# get the actual 1/3 and 2/3 way points.
third.add_vector(p1)
two_third.add_vector(p1)

# Creates bump roughly equivalent to an equilateral triangle
# This is the key line here: the midpoint is moved along the normal
# (perpendicular line) of the line. If you do Vector.between(two_third,third)
# the normal points the opposite way and the bump will be backwards.
top = Vector.midpoint(third,two_third)
top.add_vector(Vector.between(third,two_third).normal)

# Adds the subdivisions into the point array.
new_array << third << top << two_third << p2

# Moves to the next point
p1 = p2
end

@points = new_array
end


def gl_paint
GL.Begin(GL::LINE_STRIP)
for p in @points
GL.Vertex2f(p.x,p.y)
end
GL.End
end
end

Thursday, February 5, 2009

Radial Space Filling Tree


I've been continuing work with my color wheel using radial space filling trees, inspired in part because of DocBurst. I've modified the original source code to allow multiple levels of rings, though only three are seen here (the center circle is considered a segment, but I set it to the background color). Children sectors in the ring are constrained to the angle bounds of its parent.

Further steps include click detection on segments based to select different segments, and extracting a child segment to form a new color wheel.

Wednesday, February 4, 2009

Rings of Color




I've been thinking of making a color wheel for playing around with color palettes. This is an initial concept that I came up where sectors display colors. To actually get the ring effect I painted all of the colors as pies, and then filled the center of the circle containing the color pies with the background color.



Adding more colors creates more sections of the ring and the spacers prevent them from getting too close together. Future steps are to add a feature to generate shades of a color at given steps from a certain hue based upon saturation or brightness. Adding and saving of color palettes and exporting as Qt style sheets would also be useful.

Creating and editing colors is done using the already provided QColorDialog. Unfortunately, it doesn't provide as many options as the Java Swing Color Chooser, but it gets the job done for now.

Tuesday, February 3, 2009

Porting QT between C++ and Ruby

I have an assignment due next week for a graphics class I'm taking and I have given the ability to use whatever language or windowing libraries I want, provided they are portable. The only condition is that we are required to use OpenGL. Well, I wrote the project initially using C with GLUT, and then after realizing that my C code is really sketch, and ported it to a more familiar environment C++/Qt.

OpenGL with Qt is not really a much different animal than with GLUT, but it seems like OpenGL integrates better with the interface in Qt. I'd like to also try out OpenGL with FxRuby and WxWidgets to get a better idea of how to work with both traditional GUI interfaces while adding OpenGL effects to the mix. The OpenGL page for Ruby has a lot of helpful tips.

Tuesday, January 27, 2009

Write once, debug everywhere.

Java was initially heralded as the "Write once, run anywhere" language, and with its Swing GUI library this would end all programmers frustrations of porting code. Right? Of course this myth didn't last two long as there are a lot of undocumented hacks necessary to get our programs to play nicely on different systems. I remember one hack specifically from Game Programming in Java regarding an additional method call to the event queue to properly process events on Linux.

And of course I've run into this again on Windows with QtRuby. Something in several of my examples which use Qt::Timer (QTimer) for stepping simulations and repaints work fine on Linux, but not at all on Windows. Since I use Linux exclusively this isn't a critical issue right now, but I'm going to have to look into it if I plan to distribute any of my programs on Windows.