Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix collapse bugs with non-manifold geometry #5

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions lib/mittsu/mesh_analysis/winged_edge.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,13 @@ def other_vertex(index)
end

def reattach_vertex!(from:, to:)
was = self.clone
if @start == from
@start = to
elsif @finish == from
@finish = to
end
raise ArgumentError.new("was #{was.inspect}, now: #{inspect}") if degenerate?
end

def reattach_edge!(from:, to:)
Expand All @@ -49,6 +51,7 @@ def reattach_edge!(from:, to:)
elsif @ccw_right == from
@ccw_right = to
end
raise ArgumentError.new(self.inspect) if degenerate?
end

def coincident_at(edge)
Expand Down Expand Up @@ -107,16 +110,20 @@ def stitch!(edge)
return nil unless face && edge.coincident_at(edge)
# Flip incoming edge if it's not pointing the same way
edge = edge.flip unless same_direction?(edge)
raise ArgumentError if edge.degenerate? || degenerate? || !same_direction?(edge)
# Stitch left side of other edge if our left face is the shared one, or vice versa
puts face
if face == @left
@cw_left = edge.cw_left
@ccw_left = edge.ccw_left
@left = edge.left
raise ArgumentError.new(self.inspect) if degenerate?
return @left
else
@cw_right = edge.cw_right
@ccw_right = edge.ccw_right
@right = edge.right
raise ArgumentError.new(self.inspect) if degenerate?
return @right
end
end
Expand Down
25 changes: 24 additions & 1 deletion lib/mittsu/mesh_analysis/winged_edge_geometry.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ def flatten!
next if face.nil?
e0 = edge(face[:edge])
next if e0.nil?
puts "error accessing edge #{face[:edge]} for face #{face[:face]}" if e0.nil?
if e0.left == face[:face]
Mittsu::Face3.new(e0.start, e0.finish, edge(e0.ccw_left)&.other_vertex(e0.finish)) if e0.start && e0.finish && edge(e0.ccw_left)&.other_vertex(e0.finish)
elsif e0.right == face[:face]
Expand All @@ -76,6 +77,7 @@ def between(v1, v2)
end

def indexes_between(v1, v2)
puts "between #{v1} and #{v2}"
find_edge_indexes(from: v1, to: v2) + find_edge_indexes(from: v2, to: v1)
end

Expand All @@ -86,7 +88,18 @@ def edge(index)
def manifold?
@edges.all? do |e|
return true if e.nil?
e.complete? &&
raise "edge #{e.index} is incomplete" unless e.complete?
raise "edge #{e.index} is degenerate" if e.degenerate?
raise "edge #{e.index} is duplicated" if indexes_between(e.start, e.finish).count > 1
raise "edge #{e.index} references missing start vertex #{e.start}" if @vertices[e.start].nil?
raise "edge #{e.index} references missing finish vertex #{e.finish}" if @vertices[e.finish].nil?
raise "edge #{e.index} references missing left face #{e.left}" if @face_indices[e.left].nil?
raise "edge #{e.index} references missing right face #{e.right}" if @face_indices[e.right].nil?
raise "edge #{e.index} references missing cw left edge #{e.cw_left}" if @edges[e.cw_left].nil?
raise "edge #{e.index} references missing ccw left edge #{e.ccw_left}" if @edges[e.ccw_left].nil?
raise "edge #{e.index} references missing cw right edge #{e.cw_right}" if @edges[e.cw_right].nil?
raise "edge #{e.index} references missing ccw right edge #{e.ccw_right}" if @edges[e.ccw_right].nil?
ok = e.complete? &&
!e.degenerate? &&
indexes_between(e.start, e.finish).count <= 1 &&
!@vertices[e.start].nil? &&
Expand All @@ -97,6 +110,8 @@ def manifold?
!@edges[e.ccw_left].nil? &&
!@edges[e.cw_right].nil? &&
!@edges[e.ccw_right].nil?
puts " -- #{e.inspect}" unless ok
ok
end
end

Expand All @@ -116,8 +131,10 @@ def split(vertex:, left:, right:, displacement:, flatten: true)
# and merging everything onto the start vertex instead.
# If the result would be degenerate in some way, the mesh is unchanged
def collapse(index, flatten: true)
puts "collapsing edge #{index}"
# find the edge
e0 = edge(index)
puts e0.inspect
return if e0.nil?

# Move vertices to new position
Expand All @@ -135,6 +152,7 @@ def collapse(index, flatten: true)
ccw_left = @edges[e0.ccw_left]
if cw_left && ccw_left
face = cw_left.stitch!(ccw_left)
raise ArgumentError.new("tried to stitch #{ccw_left.inspect} into #{cwl.inspect} and got #{cw_left.inspect}") if cw_left.degenerate?
@edges[cw_left.index] = cw_left
@face_indices[face] = {face: face, edge: cw_left.index} if face
end
Expand All @@ -144,6 +162,7 @@ def collapse(index, flatten: true)
ccw_right = ccwr = @edges[e0.ccw_right]
if cw_right && ccw_right
face = ccw_right.stitch!(cw_right)
raise ArgumentError.new("tried to stitch #{cw_right.inspect} into #{ccwr.inspect} and got #{ccw_right.inspect}") if ccw_right.degenerate?
@edges[ccw_right.index] = ccw_right
@face_indices[face] = {face: face, edge: ccw_right.index} if face
end
Expand All @@ -158,6 +177,9 @@ def collapse(index, flatten: true)

# Reattach edges to remove old indexes
# This could be much more efficient by walking round the wings
puts "reattaching: left #{ccw_left&.index} -> #{cw_left&.index}"
puts "reattaching: right #{cw_right&.index} -> #{ccw_right&.index}"
puts "reattaching: finish #{e0.finish} -> #{e0.start}"
@face_indices.each do |f|
next if f.nil?
f[:edge] = cw_left&.index if f[:edge] == ccw_left&.index
Expand All @@ -171,6 +193,7 @@ def collapse(index, flatten: true)
end

# Prepare for rendering
raise "SHIT" unless manifold?
flatten! if flatten
# Return split parameters required to invert operation
# [vertex, left_vertex, right_vertex, displacement]
Expand Down
Loading