I’ve been struggling for the past week trying to work out how to fix orphaned edges (see images) in the models that I’ve been given to work with. I’m not having any problem selecting the edges that need to be fixed (I modified an outer loop method that ThomThom provided in another post). What I am struggling with is how to match/join them together. I’ve had a bit of success with Entities::transform_by_vectors but its hit and miss as the orphaned edge counts are rarely the same. And the transform_by_vectors method doesn’t seem to join/merge vertices that are the same (they appear to be, but they are not).
These should be ArcCurve objects. They should inherit Curve#move_vetices.
They will need to be made to have the same number of vertices (and edges) so the one with more would need to have it’s last vertex moved to the previous to eliminate the extra edge.
Looking at the last image there are tiny faces that we would hope will get cleaned up. (But this may be wishful thinking.)
The models I work with are imported from a solid modeling application (SolidEdge) which is the problem. The faces are imported as strips and there are a lot of inconsistencies in edge counts where the strips meet. Many of the models are long and cylindrical and the longer the strips get, the lower the edge count for the circumference gets, making the edge problem worse yet.
I use Sketchup for technical illustration and many of the images are closeups and I just can’t publish them looking that way. Often I find it easier to just remodel, but that takes a lot of time. So, I’m trying to write a plugin that could help me fix these issues without having to remodel.
I’ve attached a sample. Note that these models are imported at 1000x scale to help with the issue of Sketchup dropping small faces. I’m not sure it this is still an issue, just the way I managed that problem when I created importer many years ago (Sketchup 8).
Yes, when I use the Entities::transform_by_vectors method, they just overlap. I’m ok if that is the best that can be done, but I would prefer if the vertex points would merge rather than overlapped.
I’m aiming to do something semi-automated. Maybe, after a while of semi-automating it, a fully automated solution may become more obvious. It may be that it should be done in the importer, as at that point the strips are separate and may be more suitable to modify before connecting them. Don’t know yet.
If I may ask, Solid Edge will export in STL file format which can then be imported directly into Sketchup, are you transferring the data through some other file format that is causing these problems?
I thought that importing an STL file might give me some clues on how to fix the problem, but it appears my importer (top image) does a much better job importing than the Sketchup STL importer (bottom image) or maybe it’s the SolidEdge exporter?
Here’s the thing, If I create a chamfered hole in an axle with the Solid Edge tools ( first image) and transfer that design to Sketchup via an STL file I’ll get a nice solid object ( second image ) with all of the faces neatly arranged ( third image ). Perhaps you can send me the Solid Edge file and we’ll determine what is actually in the file. It might contain be a mesh that was imported from some earlier CAD program.
I’ve got some logic in Vertex Tools to force-merge vertices. The gist is that I create a temp group with edges that has one end at each position I want to merge. I then transform (by vectors) each edge to be zero length long and then explode the temp gorup. That will trigger SketchUp to perform some merge-checks. I’ll see if I can dig up a snippet for that.
Can you verify which importer the bottom is please? Is it the old Ruby STL importer, or the newer native STL importer? Also what import settings are used? (Looks like a case of too small faces)
I was considering an exploded temp group approach. I have used that method before when creating geometry for threads. A snippet of your approach would be helpful. Thanks.
I used the native STL importer in SketchUp 2020. I did try the importer again this morning. The unit of measurement was set to millimeters. I changed it to meters and the result was much better. But the problem of bad edges remains.
# Heal geometry
# (i) When vertices are merged into one point it one end up with zero size
# faces and edges. These produce a messy mesh and cause errors to be
# reported when Su validates the model.
#
# If one draw a dummy edge with SU's native edge tool it heals the
# geometry. But if one does the same with the Ruby API it doesn't.
#
# Thanks to Gulcan Ocali from Tgi3D for suggesting a workaround where
# the edge is created in a dummy group - then exploded. This appear to
# make SU heal the geometry. The dummy edge is turned into a zero length
# edge before exploding so it's automatically cleaned up when the group
# is exploded.
#
# @see http://forums.sketchucation.com/viewtopic.php?f=180&t=35470#p312814
#
# This does however feel too much like a dirty hack. Would be nice to
# know how to correctly do this.
#
# (?) Turn into a reusable method accepting an array of vertices to heal.
#
# (?) Is it necessary to also do the same to soft-selected vertices?
#
# @param [Sketchup::Entities] entities
# @param [Geom::Point3d] point
#
# @return [Nil]
def self.heal_vertex(entities, point)
point = point.position if point.is_a?(Sketchup::Vertex)
temp_group = entities.add_group
temp_edge = temp_group.entities.add_line(point, point.offset(Z_AXIS))
temp_group.entities.transform_by_vectors([temp_edge.end], [Z_AXIS.reverse])
temp_group.explode
nil
end
# Performance test: HealVertices.skp (15299 Vertices)
#
# Original healing method (calls heal_vertex)
#
# Healing took: 75.799s
# Healing took: 79.11s
# Healing took: 81.0s
#
#
# Bulk healing method
#
# Healing took: 23.9s
# Healing took: 23.92s
# Healing took: 24.04s
#
#
# While the new one is nearly three times faster, it appear to some times not
# heal every face. It's in any case still faster to run the bulk method twice
# in case the first operation didn't heal 100% than to run the original
# method.
#
# @param [Sketchup::Entities] entities
# @param [Array<Geom::Point3d>] points
#
# @return [Nil]
def self.heal_vertices(entities, points)
# Ensure we internally have an array.
if points.is_a?(Enumerable)
stack = points.dup # Duplicate container since it might be modified.
else
stack = [points]
end
# Ensure we have Point3d objects.
stack.map! { |point|
if point.is_a?(Sketchup::Vertex)
point.position
else
point
end
}
# Heal vertices.
# Create a temp group with a set of zero length edges for each vertex -
# when exploded will trigger SketchUp's internal healing function.
temp_group = entities.add_group
# Avoid adding an edge for two vertices at the same position. That might
# leave stray edges.
edges = Set.new
offset_reverse = Z_AXIS.reverse
vertices = []
vectors = []
stack.each { |point|
temp_edge = temp_group.entities.add_line(point, point.offset(Z_AXIS))
next if edges.include?(temp_edge)
vertices << temp_edge.end
vectors << offset_reverse
edges << temp_edge
}
temp_group.entities.transform_by_vectors(vertices, vectors)
temp_group.explode
stack.size
end
# Tries to heal all zero length edges in the given set of entities. This
# should also heal zero size faces since they are bound by zero length edges.
#
# @param [Sketchup::Entities] entities
#
# @return [Nil]
def self.heal_entities(entities)
return if entities.length == 0
parent = entities.first.parent
entities.each { |entity|
next unless entity.is_a?(Sketchup::Edge)
if entity.length == 0
self.heal_vertex(parent, entity.start)
end
}
nil
end