I’ve already noted that the API cannot set any text font characteristics.
Today I discovered that adding text attached with a leader ignores the preferences text font bold setting. (So called “screen text” does follow the bold setting.) Same situation if user adds the text.
My extension has one function to label a selected face with text at its centroid, and erase any previous text for that face.
To find the previous text I iterate through the active entities, and for each do text.point and face.classify_point to see which text(s) to delete.
However if there are any “screen” texts, they have no point so text.point gives nil, which crashes face.classify_point. So I have to test for nil point first.
The result is this ruby fragment below. First draw a face on XY plane and add some text (some on it and some not), then select the face. Running it deletes some of the text on the face but not all of them. If you rerun It deletes some more. Something is breaking the for loop but I can’t figure out what it is:
mod = Sketchup.active_model # Open model
ent = mod.active_entities # All entities in context
sel = mod.selection # Current selection
selface = sel[0]
for element in ent
puts element
if element.class == Sketchup::Text
textitem = element
textitem.point
if textitem.point != nil
textpoint = textitem.point
puts textitem.text + "is at " + textpoint.to_s
result = selface.classify_point(textpoint)
puts result.to_s + " classify"
if result == Sketchup::Face::PointInside then textitem.erase! end
end
end
end
Never erase or otherwise delete an item from an Entities collection while you are iterating over that collection! This will cause seemingly random “fenceposting” errors in which the iteration quits without covering the entire collection. Instead, get an independent Array of references by Entities.to_a and iterate over that. A flat array will not fencepost.
Also, screen text is fastened to the screen not the model so it does not have any of the attributes that would tie it to model coordinates. That’s why it returns nil for #point. It would be much better if there were separate derived classes in the Ruby API for screen and leader text.
“Fenceposting” is a general effect in a great many of the multi-element storage techniques used in computer programming, not just Ruby and not just the SketchUp API. In effect, the issue is like the cliche of sawing off the limb you are sitting on. The data structure loses its place.
grok (Stranger in a Strange Land). grep is an old-time UNIX command with a typically cryptic name Reportedly it comes from the ed editor command to display all occurrences of a regular expression in a file:
g = global
re = regular expression
p = print
Globally search a REgular expression and Print == GREP
Or something like that…
It’s a quick way of extracting ‘types’ from a collection.
It works on Arrays AND Collections like Entities and Selection.
If you pipe the results through a select{} it’s faster that having several steps.
I just used it here to avoid changing the entities AND of course collected the items ‘to-go’ and erased them in one pass, which is also quicker…
I went with the following because I could understand it;
deltextarr = Array.new
for textitem in ent
if textitem.class == Sketchup::Text
textpoint = textitem.point
if textpoint != nil
result = selface.classify_point(textpoint)
if result == Sketchup::Face::PointInside then ans = deltextarr << textitem end
end
end
end
if deltextarr.length > 0
ent.erase_entities deltextarr
end
Sorry about the typo.
As Steve said I typed that up quickly and got the array and entity references reversed in the << [push] !
I’ve corrected the original code in an Edit…
With the GREP method you can erase the items as you go without worry because the GREP has already made an array from a sub-set of the entities-collection.
Erasing one at a time is slightly slower that the collect-into-a-togos-array, then erase all togos ‘in one foul swoop’.
But unless you have a considerable number to erase you are unlikely to perceive the time saved difference in the methods…
No Bugsplat. It causes a Ruby error that stops the script.
Just by chance, I happened to have a screen text among active elements.
Otherwise I would never have found the problem.