Apply style to edges


#1

Hi I am looking for a way to apply a style to a geometry exactly the same way round corner does, I wanna keep the inner edges hidden smoothed and the rest of the edges visible unsmoothed, any ideas?

Def Add_Polygon.rb (2.6 KB)


#2

you have a unorthodox way of creating the object, so I played around to see how I could achieve your desired result…

I would not normally add the first face this way, but this shows one way of finding the edges and applying :soft

pts_bottom=[[-1.69267, 1.96424, 0], [-1.85607, 1.85607, 0], [-1.96424, 1.69267, 0], [-2, 1.5, 0], [-2, -1.5, 0],
[-1.96424, -1.69267, 0], [-1.85607, -1.85607, 0], [-1.69267, -1.96424, 0], [-1.5, -2, 0], [1.5, -2, 0],
[1.69267, -1.96424, 0], [1.85607, -1.85607, 0], [1.96424, -1.69267, 0], [2, -1.5, 0], [2, 1.5, 0],
[1.96424, 1.69267, 0], [1.85607, 1.85607, 0], [1.69267, 1.96424, 0], [1.5, 2, 0], [-1.5, 2, 0]]
mesh2 = Geom::PolygonMesh.new
polygon_index = mesh2.add_polygon(pts_bottom)

Sketchup.active_model.entities.add_faces_from_mesh(mesh2)

face = Sketchup.active_model.entities[-1]
face.pushpull(5)

Sketchup.active_model.entities.grep(Sketchup::Edge) do |edge|
  next unless edge.length == 5
  edge.soft = true if  edge.faces[0].normal.dot(edge.faces[1].normal).abs < 0.98
end

john


#3

YES!, thank you john, this is what I was looking for…


#4

Hi I am back, I try to make a simpler shape, cant seem to understand how to do it, why my angle the angle is allways 0?, cant use follow me command because this is a small part of something bigger, cant seem to understand faces.length, the side edges should be connected to only 2 faces?

Def Add_Polygon v2.rb (1.6 KB)


#5

your :sides method produces 27 faces instead of 6…

john


#6

27 faces total ok, but if i am iterating through every edge, and faces.length trows diferent values

edges.each {|edge|
faces=edge.faces
if faces.length==2

also why angle is always = 0

ang0=faces[0].normal
ang1=faces[1].normal
angle=ang0.angle_between(ang1)


#7

heres a different approach with additional code so you can ‘watch’ what happens…

@faces = []
@edges = []

@ents  = Sketchup.active_model.entities
@bot_points2 = [[0.46424, -0.19267, 0], [0.35607, -0.35607, 0], [0.19267, -0.46424, 0], [0, -0.5, 0], [0, 0, 0], [0.5, 0, 0], [0.46424, -0.19267, 0]]
@top_points2 = [[0.46424, -0.19267, 1], [0.35607, -0.35607, 1], [0.19267, -0.46424, 1], [0, -0.5, 1], [0, 0, 1], [0.5, 0, 1], [0.46424, -0.19267, 1]]


def bottom_cap
  pts_bottom = @bot_points2
  face = @ents.add_face(pts_bottom)
  # face.reverse!
  @faces << face
end

def top_cap
  pts_top = @top_points2
  face = @ents.add_face(pts_top)
  face.reverse!
  @faces << face
end

def side_edges
  joining_edge_pts = @bot_points2.zip(@top_points2)
  joining_edge_pts.flatten.each_slice(3).to_a.each_slice(2).to_a
  joining_edge_pts.each{|pair| @ents.add_line(pair)}
end

def missing_faces
  ents=Sketchup.active_model.entities
  edges = ents.grep(Sketchup::Edge)
  edges.each {|edge|
    @edges << edge
    next unless edge.faces.empty?
    edge.find_faces
  }
end

def soften_edges
  @edges.each { |edge|
    faces = edge.faces
    next if faces.map{|face| @faces.include?(face)}.include?(true)
    next if faces.map{|face| face.area < 0.2}.include?(false)
    edge.soft=true
    edge.smooth=true
  }
end

model = Sketchup.active_model
sel   = model.selection
view  = model.active_view

sel.clear unless sel.empty?

model.start_operation('slowly')
  bottom_cap
  sleep 0.5
  view.refresh
  top_cap
  sleep 0.5
  view.refresh
  side_edges
  sleep 0.5
  view.refresh
  missing_faces
  sleep 0.5
  view.refresh
  soften_edges
model.commit_operation

john


#8

John I am gonna be honest with you, you blew my mind with that sleep command!! didnt know about it, ok i’ve been testing your code, and it seem you rely on face.area to determine what edge to smooth, but when we grow bigger you face a problem, the points you have now will be ramdon generated acording to shapes made by the user or library, so question 1: should we look for faces closed to each other with the same area? in that way we dont rely on a “fixed” value? question 2: why your object edges are welded somehow and mine are not?Def Add_Polygon v2.rb (6.1 KB)

PS: Thanks for the Help!!!


#9

your Geom::PolygonMesh code is creating to many faces, it is breaking the face finding, edge smoothing, etc…

which is why I changed that method, added the missing faces method and changed the order each is is called…

face.area was just something else you can look, you can pre-calulate from the input, but I just measured it for a quick demo…


#10

I’m joining this party kind of late, but looking at your original code I saw a couple of serious issues.

  • In your sides method, on each pass through the loop you add a polygon to the mesh using add_polygon and then you also invoke add_faces_from_mesh. So, the first pass adds a polygon to the mesh and then a face from that mesh. The second pass adds a second polygon to the same mesh and then adds two faces based on the mesh: a duplicate of the original plus the added one. And so on, increasing the number of duplicates on each pass. The result is a large load of duplicate faces that make the subsequent analysis fail, as almost none of the edges border just two faces! You should move the add_faces_from_mesh outside the end of the loop and let it make faces from all the polygons at once.

  • In soften_edges, you seem to misunderstand how a dot product works (or perhaps have a typo). Since the normal vector to a face is a unit vector, the dot product between two of them is between 1 and -1 (dot = |a|*|b|*cos(angle)). Here |a| == |b| == 1 and -1 < cos < 1! So, the first test fails because the dot magnitude will never be > 1. This might be a typo where you meant <1? The second test is also not likely to pass very often because you are dealing with finite precision computer arithmetic. It is not likely that a calculated abs of a dot product will exactly equal 1, even if the two faces are coplanar. You need to test to within a tolerance, or better, use the Ruby API’s Vector3d#parallel? method which already uses a tolerance.

That said, I’m not clear what edges you expected to soften and smooth, as your sample has no faces that are coplanar.


#11

@slbaumgartner, I believe this is the desired outcome…

desired

def bottom_cap
  pts_bottom = @bot_points
  face = @ents.add_face(pts_bottom)
  #face.reverse!
  @faces << face
end

def top_cap
  pts_top = @top_points
  face = @ents.add_face(pts_top)
  #face.reverse!
  @faces << face
end

def side_edges
  joining_edge_pts = @bot_points.zip(@top_points)
  joining_edge_pts.flatten.each_slice(3).to_a.each_slice(2).to_a
  joining_edge_pts.each{|pair| @ents.add_line(pair)}
end

def missing_faces
  ents=Sketchup.active_model.entities
  edges = ents.grep(Sketchup::Edge)
  edges.each {|edge|
    @edges << edge
    next unless edge.faces.empty?
    edge.find_faces
    @area << edge.faces[0].area
  }
end

def soften_edges
  avg = @area.sum/@area.size
  @edges.each { |edge|
    faces = edge.faces
    next if faces.map{|face| @faces.include?(face)}.include?(true)
    next if faces.map{|face| face.area < avg}.include?(false)
    edge.soft=true
    edge.smooth=true
  }
end

model = Sketchup.active_model
sel   = model.selection
view  = model.active_view

sel.clear unless sel.empty?

model.start_operation('slowly')
  
  @area = []
  @faces = []
  @edges = []
  bottom_cap
  sleep 0.5
  view.refresh
  top_cap
  sleep 0.5
  view.refresh
  side_edges
  sleep 0.5
  view.refresh
  missing_faces
  sleep 0.5
  view.refresh
  soften_edges
model.commit_operation

#12

I’m curious why after having drawn the bottom cap you don’t just #pushpull it to create the other cap and all the side edges and faces in one go? Why create elaborate code to do something built into the Ruby API?


#13

Yea, if the corners were drawn as Arc entities they should have their edges soft+smooth automatically. You could then traverse the vertical edges of the start/end of each curve and turn off soft+smooth.


#14

Illustrating @tt_su’s point and mine (I drew the bottom manually since that part of the code isn’t the key idea).

pushpull


#15

Oh, there isn’t even any need to manually unsmooth the edges connected to the curve corners…
…ah, I suppose the whole loop would have had to be a Curve for all extruded edges to appear smooth.


#16

Yes, same as pushpull does in the GUI. Pushpull leaves an unsmoothed edge wherever there is a join between two separate things in the face’s loop. One has to weld the loop into a Curve to get it to smooth everything.


#17

@tt_su, @slbaumgartner Hi, the whole idea is to have a shape made by user or library, read the outerloop of the shape, and then make a path, square/round/whetever to make aluminium/pvc windows with a specific profile, pushpull or followme will be limited if a want to have a texture (correct me if im wrong). Well lets say I have a pvc with wood texture. The whole idea is to move points around whetever i need them to be, maybe my approach is wrong, should i read the profile, get outerloop, make a path then follow me?

@slbaumgartner, yes thanks now my Polymesh works in a perfect way, of course I took it out of the loop.

@john_drivenupthewall, your new approach seem perfect except for the small first object, the 90 degrees faces are smoothed and they should not be, maybe an if about it will fix it, another thing i noticed is that my Polymesh works on the large objects but fails on the small one, i get a nill somewhere soften_edges, no edges?
Def Add_Polygon v2.rb (6.2 KB)

PS: thanks everybody, awesome input, im learning a lot over here, and that makes happy…


#18

I don’t understand what you mean by that, nor why your and John’s approaches don’t have the same issue? Please explain. Texture is something you apply to faces in the API. The way you created those faces is irrelevant.

That’s how I would do it…


#19

it’s using Sketchup.active_model.entities so it’s only meant to run on one item at a time…

if you want to test three items you need to make sure you reference the correct entities…

john


#20

the main change is in soften edges…

def soften_edges
  @edges.flatten.each do |edge|
    # the only important faces
    faces = edge.faces
    # conditionals
    next if faces.length == 1 ||                                   # this needed for v2
    faces[0].normal.angle_between(faces[1].normal).radians >= 45  ||   # degree could change
    faces[0].area.round(1) != faces[1].area.round(1)           # different approx sizes
    # set both true
    edge.soft = edge.smooth = true
  end
  @edges = []
end

after modifying your code…

  # we need to know the existing faces
  orig_faces = @ents.grep(Sketchup::Face)
  # then make new faces
  @ents.add_faces_from_mesh(mesh, Geom::PolygonMesh::NO_SMOOTH_OR_HIDE)
  # find the new by checking again and minus the originals
  faces = (@ents.grep(Sketchup::Face) - orig_faces)
  # only collect relevent edges
  faces.each { |f| @edges << f.edges }

I commented and formatted your script …

edit: fixed a typo and removed the .rb file as you have it now…