Initial MoonModel implementation
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module MoonModel
|
||||
class Mesh
|
||||
attr_reader :name, :vertices, :triangles, :material
|
||||
|
||||
def initialize(name:, material: nil)
|
||||
@name = name
|
||||
@material = material
|
||||
@vertices = []
|
||||
@triangles = []
|
||||
end
|
||||
|
||||
def vertex(point)
|
||||
@vertices << point.map(&:to_f)
|
||||
@vertices.length - 1
|
||||
end
|
||||
|
||||
def triangle(a, b, c)
|
||||
@triangles << [a, b, c]
|
||||
end
|
||||
|
||||
def quad(a, b, c, d, flip: false)
|
||||
flip ? (triangle(a, c, b); triangle(a, d, c)) : (triangle(a, b, c); triangle(a, c, d))
|
||||
end
|
||||
|
||||
def add_box(center, size)
|
||||
cx, cy, cz = center
|
||||
sx, sy, sz = size.map { |v| v / 2.0 }
|
||||
ids = [[-sx,-sy,-sz],[sx,-sy,-sz],[sx,sy,-sz],[-sx,sy,-sz],[-sx,-sy,sz],[sx,-sy,sz],[sx,sy,sz],[-sx,sy,sz]].map do |x,y,z|
|
||||
vertex([cx+x, cy+y, cz+z])
|
||||
end
|
||||
quad(ids[0], ids[3], ids[2], ids[1]); quad(ids[4], ids[5], ids[6], ids[7])
|
||||
quad(ids[0], ids[1], ids[5], ids[4]); quad(ids[1], ids[2], ids[6], ids[5])
|
||||
quad(ids[2], ids[3], ids[7], ids[6]); quad(ids[3], ids[0], ids[4], ids[7])
|
||||
end
|
||||
|
||||
def add_tapered_box(center, length, width_a, width_b, height)
|
||||
cx, cy, cz = center
|
||||
x0 = cx - length / 2.0; x1 = cx + length / 2.0
|
||||
z0 = cz - height / 2.0; z1 = cz + height / 2.0
|
||||
ids = [[x0,cy-width_a/2,z0],[x0,cy+width_a/2,z0],[x1,cy+width_b/2,z0],[x1,cy-width_b/2,z0],
|
||||
[x0,cy-width_a/2,z1],[x0,cy+width_a/2,z1],[x1,cy+width_b/2,z1],[x1,cy-width_b/2,z1]].map { |p| vertex(p) }
|
||||
quad(ids[0],ids[3],ids[2],ids[1]); quad(ids[4],ids[5],ids[6],ids[7])
|
||||
quad(ids[0],ids[1],ids[5],ids[4]); quad(ids[1],ids[2],ids[6],ids[5])
|
||||
quad(ids[2],ids[3],ids[7],ids[6]); quad(ids[3],ids[0],ids[4],ids[7])
|
||||
end
|
||||
|
||||
def add_cylinder(center, radius, height, segments: 24)
|
||||
cx, cy, cz = center
|
||||
bottom = segments.times.map { |i| a = i * 2*Math::PI/segments; vertex([cx+radius*Math.cos(a), cy+radius*Math.sin(a), cz-height/2]) }
|
||||
top = segments.times.map { |i| a = i * 2*Math::PI/segments; vertex([cx+radius*Math.cos(a), cy+radius*Math.sin(a), cz+height/2]) }
|
||||
cb = vertex([cx,cy,cz-height/2]); ct = vertex([cx,cy,cz+height/2])
|
||||
segments.times do |i|
|
||||
j = (i+1)%segments
|
||||
triangle(cb,bottom[j],bottom[i]); triangle(ct,top[i],top[j]); quad(bottom[i],bottom[j],top[j],top[i])
|
||||
end
|
||||
end
|
||||
|
||||
def add_annular_cylinder(center, inner_radius, outer_radius, z0, z1, segments: 32)
|
||||
cx, cy = center
|
||||
oi=[]; oo=[]; ti=[]; to=[]
|
||||
segments.times do |i|
|
||||
a=i*2*Math::PI/segments
|
||||
oi << vertex([cx+inner_radius*Math.cos(a),cy+inner_radius*Math.sin(a),z0])
|
||||
oo << vertex([cx+outer_radius*Math.cos(a),cy+outer_radius*Math.sin(a),z0])
|
||||
ti << vertex([cx+inner_radius*Math.cos(a),cy+inner_radius*Math.sin(a),z1])
|
||||
to << vertex([cx+outer_radius*Math.cos(a),cy+outer_radius*Math.sin(a),z1])
|
||||
end
|
||||
segments.times do |i|
|
||||
j=(i+1)%segments
|
||||
quad(oo[i],oo[j],to[j],to[i]); quad(oi[i],ti[i],ti[j],oi[j])
|
||||
quad(oi[i],oi[j],oo[j],oo[i]); quad(ti[i],to[i],to[j],ti[j])
|
||||
end
|
||||
end
|
||||
|
||||
def add_tri_prism(outer, inner)
|
||||
o = outer.map { |p| vertex(p) }
|
||||
i = inner.map { |p| vertex(p) }
|
||||
triangle(o[0], o[1], o[2]); triangle(i[0], i[2], i[1])
|
||||
3.times { |n| quad(o[n], o[(n + 1) % 3], i[(n + 1) % 3], i[n]) }
|
||||
end
|
||||
|
||||
def transform
|
||||
vertices.map! { |point| yield(point) }
|
||||
self
|
||||
end
|
||||
|
||||
def bounds
|
||||
axes = vertices.transpose
|
||||
axes.map { |axis| [axis.min || 0.0, axis.max || 0.0] }
|
||||
end
|
||||
|
||||
def valid?
|
||||
!vertices.empty? && triangles.all? { |tri| tri.uniq.length == 3 && tri.all? { |i| i.between?(0, vertices.length - 1) } }
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user