You are still not following my advice.
-
I clearly showed above that the selection check for edges is the first thing that should happen in the command method.
Ie, there is no point in subjecting the user to enter trim options if the command is going to have to exit because they’ve not selected any edge path(s).
And … re:
#Checking if edges exist in the selection - returns false if no edges are selected and closes program
… it’s too long (lines should be 80 characters of less,) and it doesn’t “close the program”, … it exits your command method which to the enduser appears as a command cancel.
(I’m also not fond of omitting a space after the#
and the beginning of a comment. (Readability) -
You’ve misplaced the creation of the
model
andselection
reference. (Ie, theif selection.empty? ||
… conditional will raise aNameError
exception as the referenceselection
is not yet defined until lower in your code.) -
I’ve told you repeatedly, that the results from calling
UI.inputbox
must be checked for a boolean falsity, as this means the user has canceled the inputbox. (Refer to previous topic threads.) -
I carefully explained above that the UI command procs are a snapshot and should be executed last. But you’ve pasted them in first, before even a method that the proc calls is even defined.
How could my post be a solution if you do not follow the advice ?
Endusers are not likely to be reading your code, and if this will be a commerical extension then you’ll probably encrypt all the .rb
files in your extension subfolder to .rbe
format. (This means endusers couldn’t read anything in the files anyway.)
Contact and support information would go in a help file and/or the unencrypted extension registrar script that goes one folder up in the “Plugins” folder. You could also put this in the extension object’s description field and the users could see it in the Extension Manager.
But most coders would put it html help files that are distributed along with your extension.
Back to the creation of the menu item command.
You are not running the program from the menu item. (SketchUp is the application program.)
Your code is executing just what the proc attached to the menu item does, which is a command (consisting of methods.)
The following will not work, as NONE of the following local reference objects have been created at the extension module level within the menu item command proc:
height, thickness, quarter_round, entities, trimdef, transgroup, edges
#Only loading UI object creation once
if !@loaded
plugins_menu = UI.menu("Plugins")
submenu = plugins_menu.add_submenu("ProTrim")
submenu.add_item("Create Base Trim") {create_base_trim(height, thickness, quarter_round, entities, trimdef, transgroup, edges)}
@loaded = true
end
Secondly, (again) please stop making us and yourself scroll horizontally to read code.
Blocks, literal Arrays and Hashes, and method argument lists can span multiple lines.
You put the opening delimiter on the first line, indent the internal lines, and put the non-indented closing delimiter on the last line.
calling_some_method(
height, thickness, quarter_round, entities, trimdef, transgroup, edges
)
# A literal array:
prompts = [
"Trim Height: ",
"Trim Thickness: ",
"Quarter Round: "
]
# A block
undo(model,"Nifty Command") {
# a bunch of statements or a long method call
}
I told you what kind of transformation you will need. It is actually 2 (or more) transformations multiplied together.
In this snippet … vector
is the equivalent of the global vector Y_AXIS
.
But is also a unit vector. SketchUp and it’s APIs use inches internally regardless of what the model’s display units are set to.
So your vector
used as a translational transform will result in something being moved 1 inch in the Y direction. This is not really what you need.
Your code will need to split the edges
array into path arrays, with the edges in start to end order.
Then for each path array, get the start vertex from the start edge, and get it’s point position, get the vector from ORIGIN
to this point and use that for the translational part of the transform …
paths.each |path| do
start_edge = path.first
point = start_edge.start.position
vector = ORIGIN.vector_to(point)
vt = Geom::Transformation.translation(vector)
# The followme tool needs the face to be perpendicular
# to the starting edge of the extrusion path.
path_vector = point.vector_to(start_edge.end.position)
# face_vector is probably one of the global axis vectors or it's reverse
face_vector = Y_AXIS
rt = Geom::Transformation.rotation(
ORIGIN,
Z_AXIS,
face_vector.angle_between(path_vector)
)
transgrp = rt * vt
extrude_base_trim(trimdef, transgrp, path)
end
Again, this is a simple example for a possibility. It assumes all trim paths will be perpendicular to the Z_AXIS (parallel to the ground plane,) which might not always be true. Some trim runs diagonally up along stairwells, and not all edges where ceiling meets walls are horizontal for crown molding trim.
Also the face_vector
is only known to you, as I don’t know in what plane you plan to draw your trim face profiles. If you draw them on the XY ground plane, then you’ll also need to rotate the instances 90 degrees to stand them up. So I’d suggest draw upon the XZ plane with the front face toward the screen. The front face’s normal vector pointing toward you, it’s reverse pointing in the Y_AXIS direction.
There may bee an issue with the vector.angle_between
method. It may not give angles greater than 180 degrees.
The other thing that I’ve left out is the determination of which side on the edge path to position the face group on. Your code will need to check the faces that adjoin the edge for their normal vector which would indicate a direction pointing inward toward the center of the room. (Ie, the reversed vector from the wall faces normals would point inside the wall.)
Yes, it is an exercise in iteration. I believe it has been covered here in the past.
Regardless if you can find the topic, you iterate through the edge objects until you find the ones that have a start or end vertex used only by one edge.
I’ll leave that as an exercise for you to solve.