Created
February 25, 2014 04:02
-
-
Save silverhammermba/9202455 to your computer and use it in GitHub Desktop.
Mobius Ring Generator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# generate OBJ of Mobius wedding band | |
require 'matrix' | |
if ARGV.size != 6 | |
STDERR.puts "usage: #$0 SIDES RADIUS SAMPLES STRETCH TURNS CURVE" | |
exit 1 | |
end | |
# sides: sides of mobius prism | |
# radius: radius of ring (prism is fixed at unit radius) | |
# samples: number of steps in the rotation around the band | |
# stretch: how much to squish the shape perpendicular to the axis of rotation | |
# turns: number of turns made, e.g. 0 for normal prism, 1 for normal mobius band | |
# curve: curvature approximated by normals e.g. 0 for prism, 1 for cylinder | |
$sides = ARGV[0].to_i | |
$radius = ARGV[1].to_f | |
$samples = ARGV[2].to_i | |
$stretch = ARGV[3].to_f | |
$turns = ARGV[4].to_i | |
$curve = ARGV[5].to_f | |
def rotate_y rad | |
Matrix[[Math.cos(rad), 0, -Math.sin(rad)], [0, 1, 0], [Math.sin(rad), 0, Math.cos(rad)]].transpose | |
end | |
def rotate_z rad | |
Matrix[[Math.cos(rad), Math.sin(rad), 0], [-Math.sin(rad), Math.cos(rad), 0], [0, 0, 1]].transpose | |
end | |
normals = [] | |
samples = $samples.times.map do |sample| | |
rotz = rotate_z((2 * Math::PI * sample) / $samples) | |
# normals for this sample | |
norms = [] | |
samp = $sides.times.map do |side| | |
[-1, 1].each do |dir| | |
norm = Vector[1, 0, 0] | |
# rotate norm according to current side, current direction, desired curvature, and current sample | |
norm = rotate_y((2 * Math::PI * side) / $sides + (Math::PI * dir * (1 - $curve)) / $sides + (2 * Math::PI * sample * $turns) / ($sides * $samples)) * norm | |
# scale by inverse transpose and renormalize | |
norm = Vector[norm[0] / $stretch, norm[1], norm[2]].normalize | |
# rotate to sample position | |
norm = rotz * norm | |
# format | |
norms << norm.to_a.map { |f| f.round(6) } | |
end | |
point = Vector[1, 0, 0] | |
# rotate point about Y according to current side and current sample | |
point = rotate_y((2 * Math::PI * side) / $sides + (2 * Math::PI * sample * $turns) / ($sides * $samples)) * point | |
# scale by X | |
point = Vector[point[0] * $stretch, point[1], point[2]] | |
# translate by radius | |
point = point + Vector[$radius, 0, 0] | |
# rotate to sample position | |
point = rotz * point | |
# format | |
point.to_a.map { |f| f.round(6) } | |
end | |
normals << norms | |
samp | |
end | |
# output samples | |
samples.each do |sample| | |
sample.each do |point| | |
puts "v #{point.join(' ')}" | |
end | |
end | |
# output normals | |
normals.each do |norms| | |
norms.each do |normal| | |
puts "vn #{normal.join(' ')}" | |
end | |
end | |
# get normal index from sample, vertex, direction | |
def v2n s, v, d | |
# offset of normals + 2 norms per side + negative dir first | |
$samples * $sides + 1 + s * $sides * 2 + v * 2 + (d > 0 ? 1 : 0) | |
end | |
# output faces (last connection is different) | |
(0...($samples - 1)).each do |i| | |
i1 = (i + 1) % $samples | |
samples[i].each_with_index do |point, j| | |
j1 = (j + 1) % $sides | |
puts "f #{i * $sides + j + 1}//#{v2n(i, j, 1)} #{i1 * $sides + j1 + 1}//#{v2n(i1, j1, -1)} #{i1 * $sides + j + 1}//#{v2n(i1, j, 1)}" | |
puts "f #{i * $sides + j + 1}//#{v2n(i, j, 1)} #{i * $sides + j1 + 1}//#{v2n(i, j1, -1)} #{i1 * $sides + j1 + 1}//#{v2n(i1, j1, -1)}" | |
end | |
end | |
# output last faces | |
k = ($samples - 1) * $sides | |
$sides.times do |j| | |
cj = (j - $turns) % $sides | |
nj = (j + 1) % $sides | |
puts "f #{k + cj + 1}//#{v2n($samples - 1, cj, 1)} #{nj + 1}//#{v2n(0, nj, -1)} #{j + 1}//#{v2n(0, j, 1)}" | |
puts "f #{k + cj + 1}//#{v2n($samples - 1, cj, 1)} #{k + (j - $turns + 1) % $sides + 1}//#{v2n($samples - 1, (j - $turns + 1) % $sides, -1)} #{nj + 1}//#{v2n(0, nj, -1)}" | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment