Hi,
How to test if a face will be valid ?
for exemple: Sketchup.active_model.entities.add_face([85633.68524760043, -156720.70957342573, 16041.781177255041], [93548.54067123163, -164726.37168133756, 9652.44358096269], [93889.10645925412, -165070.6724738833, 9377.661310890353])
This code will not add face because the triangle is to long. Is it a easyway to test if the triangle will be valid before to create it ?
face = Sketchup.active_model.entities.add_face([85633.68524760043, -156720.70957342573, 16041.781177255041], [93548.54067123163, -164726.37168133756, 9652.44358096269], [93889.10645925412, -165070.6724738833, 9377.661310890353])
puts face
# if it is nil then it failed to add the face,
# otherwise it succeeded and it will be a Sketchup::Face
since when face is nil, puts will emit a blank line that is very easy to miss.
But in any case that misses the center of the OP’s question, which is to somehow test the points before invoking add_face. And in the end that may be the wrong idea. It would likely take only a minimally smaller amount of time to run some test vs to try add_face and detect when it fails.
The #inspect method merely formats a developer friendly string representation of the object. Printing nil to the console prints an empty line but printing nil.inspect prints “nil” (without quotes) which is easier to see.
Typically inspect is not used in the actual extension, just when testing. In the the actual extension the value’s truthiness is tested directly (or the #nil? method is used as Dan shows).
Actually it is puts that is mainly used for debugging or error logging during development and then removed or commented out for the production version. By default, puts invokes the to_s method on any object that isn’t already a string, and for nil to_s generates nothing, not even a space. Explicitly using inspect causes visible output.
Not that I know of - though of course formatting the string for output is part of the I/O overhead as well as sending the string to the Ruby Console (which itself involves another round of formatting).
My script grep the faces of the model and projected them on a plane into a new group.
I scaleup on all point, create the projected face and scaledown the result.
My script work on all model since 2 years but this week we found a bug on a specific model.
The entire ruby quite too long so I simplified it and add manually the face in the script with the value of the model that cause trouble.
@model = Sketchup.active_model
blueVector = Geom::Vector3d.new 0,1,1
initial_points = [[856.3368524760043,-1567.2070957342573,160.41777885028986],
[935.4854067123163,-1647.2637168133756,96.5243973571191],
[938.8910645925412,-1650.7067247388331,93.77667705045559]] # normally this points are grep from the model
face = @model.entities.add_face initial_points
projection_plan = [Geom::Point3d.new(856.4238828783741,-1621.8729329954144,115.20644543635315), Geom::Vector3d.new(-0.0225928, -0.637181, 0.770383)] # normally the projection plan is compute from the model.
scalecoef = 100.0
group = face.parent.entities.add_group
group.name = "projected_face A"
scaleUp = Geom::Transformation.scaling scalecoef
scaleDown = Geom::Transformation.scaling (1.0 / scalecoef )
holes_loop = []
newpts = []
if face
holes_loop += (face.loops - [face.outer_loop])
pts = face.outer_loop.vertices
pts.each{|vertex|
pt = vertex
newpoint = Geom.intersect_line_plane([pt,blueVector], projection_plan)
newpts.push(newpoint.transform scaleUp) if newpoint
}
newpts.uniq!
if newpts.length > 2
puts newpts.inspect
puts "grou befor face:#{group.valid?}"
new_face = group.entities.add_face newpts
puts "group after face:#{group.valid?}"
end
end
Error: #<ArgumentError: Points are not planar>
<main>:35:in `add_face'
<main>:35:in `<main>'
SketchUp:1:in `eval'
The result in the console is "Points are not planar’ because point are quite aligned.
When I execute my real script this error is not display but the puts “group after face:#{group.valid?}” return a false, the group have been erase and that cause trouble later in the script.
I can check if the point are colinear, … but I looking for a method to know if an array of points is good enouth to create a face without create an error.
Not really sure but in this case ang was 1.0128153852026937e-05 radians and dist was 3.473275mm. So something greater than that. It is certainly possible that the distance between the points and/or the distance of the points to the model origin will effect the minimum
Ok thanks ! i will take 2 inches, waiting to compute properly the compactness.
Maybe 2 additional questions:
→ why script return an error where it should return a nil as describe by TIG
→ Why in my entire script it doesn’t return an error but delete silently the group ? ( is it due to @model.start_operation, true and @model.commit ?)
Three points usually add a face - as they’ll at least be coplanar !
But if not the result is nil.
But if there are more not three points, and some are not coplanar then it will throw an error.
Therefore using a begin…rescue…end block is needed to trap for those error cases, and take the various actions that you need in each case…
While TIG was suggesting the begin rescue end blocks, I was doing just that to your code. I found that the initial add_face was not the problem but the new_face was.
@model = Sketchup.active_model
blueVector = Geom::Vector3d.new 0,1,1
initial_points = [[856.3368524760043,-1567.2070957342573,160.41777885028986],
[935.4854067123163,-1647.2637168133756,96.5243973571191],
[938.8910645925412,-1650.7067247388331,93.77667705045559]] # normally this points are grep from the model
begin #<-- trap error
face = @model.entities.add_face initial_points
projection_plan = [Geom::Point3d.new(856.4238828783741,-1621.8729329954144,115.20644543635315), Geom::Vector3d.new(-0.0225928, -0.637181, 0.770383)] # normally the projection plan is compute from the model.
scalecoef = 100.0
group = face.parent.entities.add_group
group.name = "projected_face A"
scaleUp = Geom::Transformation.scaling scalecoef
scaleDown = Geom::Transformation.scaling (1.0 / scalecoef )
holes_loop = []
newpts = []
if face
holes_loop += (face.loops - [face.outer_loop])
pts = face.outer_loop.vertices
pts.each{|vertex|
pt = vertex
newpoint = Geom.intersect_line_plane([pt,blueVector], projection_plan)
newpts.push(newpoint.transform scaleUp) if newpoint
}
newpts.uniq!
if newpts.length > 2
puts newpts.inspect
puts "group before face:#{group.valid?}"
begin
new_face = group.entities.add_face newpts
puts "group after face:#{group.valid?}"
rescue
puts "error creating new_face"
end
end
end
rescue
puts "error creating initial face"
end