Continuing the discussion from LineTool example:
Thatâs because vertices is an Array of Vertex objects. You need to look back in the code to see where it is created and populated to realize this. Then if you look at the API docs for Vertex, you will see that it has a position method that returns a Point3d.
to_s is a basic Ruby method that tells an object to return a printable string representation of itself.
Your problem is again following the basic Ruby code. First look at the Entities class docs to see what add_face does (it creates and returns a Face object). Then look at the Face class docs to see what the vertices method does (it creates and returns an Array of Vertex objects). Now look at Vertex and you are on your way!
Canât help you with that one - I have never heard of it (so far as I know it is neither standard Ruby nor SketchUp API, so if it exists it must have been defined somewhere in the code you are running).
Bottom line: it appears you need to study Ruby somewhat more to become better familiar with the language and syntax. Then worry about the SketchUp Ruby examples. They are indeed impenetrable if you donât understand Ruby!
No, but the LanguageHandlerâs square bracket method is documented, which does the same. You gave the .
, but what is in front of the dot is the object which responds to this method (in object oriented programming methods are not global, but owned by classes). You look at the class of what object it is (LanguageHandler) and then look at the methods of that class. If you write a script for your own, you probably wonât need it, unless you want to build a localized and translated software package.
Not everything you see on the internet is also good to use (especially the example contains global variables and the camelCase methods contradicting ruby style). The mentioned method may not be officially deprecated, but the fact itâs not mentioned anymore lets us consider it not a public API method, that means developers can not rely on its continuous existence or behavior and therefore shouldnât use it.
Yes but my point is that I can only look up in hindsight -so if I see, as in this case:
pent.vertices[0].position.to_s
I can look up vertices , position and to_s
But I can not look up vertices and then follow thru with possible uses because i have no information about what could follow it. That means that I have to know something of position and to_s first (or at least as in this case see them written in some code) before I can see that they can modify vertices.
-Sorry if I am confused or not clear.
Just seem to me that a thorough description of vertices would include position and all other applicable methods. I suppose that I may be wrong though. Maybe there are so many possible methods that act on vertices that it is not practical to list them.
Yes, it would just be convenient if I did not have to page back and forth -and as a newb and I would like to see the actual return to help me understand for example what a vertex object is.
Getstring, fileloaded? seems like a few others are common in the SU_examples scripts
That is most definitely true. I like learning by doing though but in this case I jumped way too far out ahead of myself. To paraphrase TopGun my coding was writing checks that my brain could not cash (or something like that)
You only need to worry about Getstring etc if you invoke a Langhandler and you have translations for the strings used in you codeâs prompts etcâŚ
One thing to get your head around is the difference between Vertex3d and Point3d.
Edges have Vertices [2]
Faces have Vertices [3 or more]
Faces have at least one Loop.
Loops have Vertices.
and so onâŚ
A Vertex has a position, which is called a Point.
To complicate matters a three point array [x,y,z] will often be acceptable as defining a Point.
In many methods you can substitute Vertices for Points - e.g. adding a face from an array of vertices.
You can easily convert your vertices into points using .position
.
You cannot directly compare Vertices, as they are separate entities, you can compare Points for equivalence, you can only compare point-arrays for being âthe sameâ.
In terms of âtransformationsâ⌠you can transform a point directly using:
point.transform!(transformation)
This also applies to âcontainersâ like group and component-instanceâŚ
But for raw geometry [edges, faces] and vertices you must use:
entities.transform_entities(transformation, array_of_entities)
or similar entities.transform⌠methods [note that this method also works on other âcontainerâ entities, but not with point3d ]
Hmm. thanks TIG I ws just wondering how to add two 3dpoints together
thanks Aerilius
I found getstring would allow an input box to accept metric or imperial units and actually did not know it was some variation of LanguageHandler -it did not mention this ability.
Create the input box
prompts = [$exStrings.GetString("Width"), $exStrings.GetString("Depth"),
$exStrings.GetString("Height")]
values = [4.feet, 4.feet, 4.feet]
results = inputbox prompts, values, $exStrings.GetString(âCubeâ)
The LanguageHandler
class and itâs []
instance method (alias GetString
,) has nothing to do with the conversion of numerics between model units.
Also be aware that only strings that are IN the âstringsâ file loaded by the LanguageHandler::new
constructor call can be successfully looked up. If the string is not in the file, the English argument is echoed back.
(In other words: LanguageHandler
is a dumb class, and a simple wrapper around a Hash
instance, whose members are loaded from a file.)
This unit conversion functionality is built-into the UI.inputbox
features.
See Thomas Thomassenâs blog article:
Dealing with Units in SketchUp
Ahh, thanks DanRathbun,
So it looks like it was the fact that the input box was being fed unit information in the value default that actually allowed it to accept metric and had nothing to do with getstring.
-another example of incomplete information in the reference material.
Specifically if you feed the defaults Length
class objects, theyâll get properly returned in the result array.
Read up on the Numeric
class additions by the API. The feet
instance method is one of them that converts and returns a Length
object.
I do not understand why basic mouse functions are being handled in ruby.
I can see why users need the ability to override behavior but the performance of linetool.rb is noticeably worse than the system pencil.
FredoTools DrawAlong works better but is still laggy
Is there a better way to handle mouse functions?
Seems like I should just be able to send the system mouse point and clicks to my tool.
The Tool class covers all aspects of handling mouse location, clicking, button/key-presses, typed input etc etcâŚ
http://www.sketchup.com/intl/en/developer/docs/ourdoc/tool
There are additional pick-helpers, temporary graphics drawing methods etc, tooâŚ
You last sentence makes little sense ??
Your tool when properly coded and set up gets its own data on the system mouse and more besides ?
Many of us have successfully used the APIâs Tool toolset in many plugin-toolsâŚ
I am not questioning whether or not Ruby provides the tools to handle mouse functions because the answer to that is obvious. Well maybe i am confused then because it seems to me that it uses ruby.
That is what most of this code is:
Copyright 2012, Trimble Navigation Limited
This software is provided as an example of using the Ruby interface
to SketchUp.
Permission to use, copy, modify, and distribute this software for
any purpose and without fee is hereby granted, provided that the above
copyright notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
-----------------------------------------------------------------------------
require 'sketchup.rb'
-----------------------------------------------------------------------------
module Sketchup::Examples
To create a new tool in Ruby, you must define a new class that implements
the methods for the events that you want to respond to. You do not have
to implement methods for every possible event that a Tool can respond to.
Once you have defined a tool class, you select that tool by creating an
instance of it and passing it to Sketchup.active_model.select_tool
This implementation of a tool tries to be pretty complete to show all
of the kinds of things that you can do in a tool. This makes it a little
complicated. You should also look at the TrackMouseTool defined in
utilities.rb for an example of a simpler tool.
This example shows the implementation of a simple line tool. This tool
is similar to the Pencil tool in SketchUp, but it create construction lines
rather than edges
class LineTool
This is the standard Ruby initialize method that is called when you create
a new object.
def initialize
@ip1 = nil
@ip2 = nil
@xdown = 0
@ydown = 0
end
The activate method is called by SketchUp when the tool is first selected.
it is a good place to put most of your initialization
def activate
The Sketchup::InputPoint class is used to get 3D points from screen
positions. It uses the SketchUp inferencing code.
In this tool, we will have two points for the end points of the line.
@ip1 = Sketchup::InputPoint.new
@ip2 = Sketchup::InputPoint.new
@ip = Sketchup::InputPoint.new
@drawn = false
This sets the label for the VCB
Sketchup::set_status_text $exStrings.GetString("Length"), SB_VCB_LABEL
self.reset(nil)
end
deactivate is called when the tool is deactivated because
a different tool was selected
def deactivate(view)
view.invalidate if @drawn
end
The onMouseMove method is called whenever the user moves the mouse.
because it is called so often, it is important to try to make it efficient.
In a lot of tools, your main interaction will occur in this method.
def onMouseMove(flags, x, y, view)
if( @state == 0 )
We are getting the first end of the line. Call the pick method
on the InputPoint to get a 3D position from the 2D screen position
that is passed as an argument to this method.
@ip.pick view, x, y
if( @ip != @ip1 )
if the point has changed from the last one we got, then
see if we need to display the point. We need to display it
if it has a display representation or if the previous point
was displayed. The invalidate method on the view is used
to tell the view that something has changed so that you need
to refresh the view.
view.invalidate if( @ip.display? or @ip1.display? )
@ip1.copy! @ip
set the tooltip that should be displayed to this point
view.tooltip = @ip1.tooltip
end
else
Getting the second end of the line
If you pass in another InputPoint on the pick method of InputPoint
it uses that second point to do additional inferencing such as
parallel to an axis.
@ip2.pick view, x, y, @ip1
view.tooltip = @ip2.tooltip if( @ip2.valid? )
view.invalidate
Update the length displayed in the VCB
if( @ip2.valid? )
length = @ip1.position.distance(@ip2.position)
Sketchup::set_status_text length.to_s, SB_VCB_VALUE
end
Check to see if the mouse was moved far enough to create a line.
This is used so that you can create a line by either dragging
or doing click-move-click
if( (x-@xdown).abs > 10 || (y-@ydown).abs > 10 )
@dragging = true
end
end
end
The onLButtonDOwn method is called when the user presses the left mouse button.
def onLButtonDown(flags, x, y, view)
When the user clicks the first time, we switch to getting the
second point. When they click a second time we create the line
if( @state == 0 )
@ip1.pick view, x, y
if( @ip1.valid? )
@state = 1
Sketchup::set_status_text $exStrings.GetString("Select second end"), SB_PROMPT
@xdown = x
@ydown = y
end
else
# create the line on the second click
if( @ip2.valid? )
self.create_geometry(@ip1.position, @ip2.position,view)
self.reset(view)
end
end
Clear any inference lock
view.lock_inference
end
# The onLButtonUp method is called when the user releases the left mouse button.
def onLButtonUp(flags, x, y, view)
If we are doing a drag, then create the line on the mouse up event
if( @dragging && @ip2.valid? )
self.create_geometry(@ip1.position, @ip2.position,view)
self.reset(view)
end
end
onKeyDown is called when the user presses a key on the keyboard.
We are checking it here to see if the user pressed the shift key
so that we can do inference locking
def onKeyDown(key, repeat, flags, view)
if( key == CONSTRAIN_MODIFIER_KEY && repeat == 1 )
@shift_down_time = Time.now
if we already have an inference lock, then unlock it
if( view.inference_locked? )
calling lock_inference with no arguments actually unlocks
view.lock_inference
elsif( @state == 0 && @ip1.valid? )
view.lock_inference @ip1
elsif( @state == 1 && @ip2.valid? )
view.lock_inference @ip2, @ip1
end
end
end
onKeyUp is called when the user releases the key
We use this to unlock the inference
If the user holds down the shift key for more than 1/2 second, then we
unlock the inference on the release. Otherwise, the user presses shift
once to lock and a second time to unlock.
def onKeyUp(key, repeat, flags, view)
if( key == CONSTRAIN_MODIFIER_KEY &&
view.inference_locked? &&
(Time.now - @shift_down_time) > 0.5 )
view.lock_inference
end
end
onUserText is called when the user enters something into the VCB
In this implementation, we create a line of the entered length if
the user types a length while selecting the second point
def onUserText(text, view)
We only accept input when the state is 1 (i.e. getting the second point)
This could be enhanced to also modify the last line created if a length
is entered after creating a line.
return if not @state == 1
return if not @ip2.valid?
The user may type in something that we can't parse as a length
so we set up some exception handling to trap that
begin
value = text.to_l
rescue
Error parsing the text
UI.beep
puts "Cannot convert #{text} to a Length"
value = nil
Sketchup::set_status_text "", SB_VCB_VALUE
end
return if !value
Compute the direction and the second point
pt1 = @ip1.position
vec = @ip2.position - pt1
if( vec.length == 0.0 )
UI.beep
return
end
vec.length = value
pt2 = pt1 + vec
Create a line
self.create_geometry(pt1, pt2, view)
self.reset(view)
end
The draw method is called whenever the view is refreshed. It lets the
tool draw any temporary geometry that it needs to.
def draw(view)
if( @ip1.valid? )
if( @ip1.display? )
@ip1.draw(view)
@drawn = true
end
if( @ip2.valid? )
@ip2.draw(view) if( @ip2.display? )
The set_color_from_line method determines what color
to use to draw a line based on its direction. For example
red, green or blue.
view.set_color_from_line(@ip1, @ip2)
self.draw_geometry(@ip1.position, @ip2.position, view)
@drawn = true
end
end
end
onCancel is called when the user hits the escape key
def onCancel(flag, view)
self.reset(view)
end
The following methods are not directly called from SketchUp. They are
internal methods that are used to support the other methods in this class.
Reset the tool back to its initial state
def reset(view)
# This variable keeps track of which point we are currently getting
@state = 0
# clear the InputPoints
@ip1.clear
@ip2.clear
Most of this code simply replaces or duplicates code that has already been done at the system level. And if you run the the program you can tell that it is ruby. Even Fredoâs better written DrawAlong tool lags.
But perhaps my understanding of programming is seriously deficient because I do not see why I need to do all this in ruby when it is already done at the system level where it runs more efficiently.
FYI, Ruby is an interpreter. All interpreters are slow, compared to compiled code.
But like all interpreters, they themselves need to be programmed in some manner. Ruby is implemented in C/C++.
SketchUpâs interface to Ruby is likewise. SketchUpâs Ruby API is 99% implemented in compiled C/C++.
So if you do not care for Ruby,⌠you can write and compile your extensions in C/C++. And make direct system calls using system libraries, if you know how. The drawback is that you need to understand both OSX and Windows system functions, and have code that accommodates each. (Ruby and SketchUp API functions already do this platform accommodation for Ruby extensions.) Another issue is that two binaries need to be compiled for Windows, a 32-bit and 64-bit. (A Ruby extension, usually, need not worry about platform bitness.)
So, in end it is you that must choose your poison.
Yeah I am already over my head with Ruby -much less C++
I guess that answers the question though -no access to the more efficient mouse which is too bad because it is a real resource hog.
Thanks all.
It may not be the actual mouse calls. Iâve done some debugging in the past that showed as you move the mouse around, (ie as a tool instance is waiting for user input,) SketchUpâs UI redraw function is firing. It is redrawing all the toolbar buttons, and calling each buttons validation proc (to know whether to draw it pressed, unpressed, or grayed out.) Some coders write slow code that has complex boolean expressions in these procs, which added together slow things down. So the more toolbars that are open, the slower things can seem. If the Outliner window is open again it will slow things down, the more objects are in the model, the time to update the outline tree. The more other tool windows that are open, the more UI there is to refresh on each cycle.
Yes, they mention in the comments that it is important to make the code efficient.
-I just wish the example provided worked well and displayed best practices. No telling how long it will take me to figure out what is going on there.
This should get you started, until I can re-organize and update my Newbieâs Guide and Ruby Reference lists.
Tutorials (do in this order)
Ruby in Twenty Minutes
[url]https://www.ruby-lang.org/en/documentation/quickstart/[/url]
Ruby Userâs Guide by Prof. Mark Slagell
[url]http://www.rubyist.net/~slagell/ruby/[/url]
Introduction to Ruby
[url]http://ruby-doc.org/docs/Tutorial/[/url]
Online Books
Programming Ruby: The Pragmatic Programmerâs Guide by Dave Thomas
The 'ol âPick Axeâ book. It is a must read. (There are newer editions available.)
[url]http://phrogz.net/ProgrammingRuby/frameset.html[/url]
Learn to Program by Chris Pine
[url]https://pine.fm/LearnToProgram/[/url]
Mr. Neighborlyâs Humble Little Ruby Book
[url]http://www.humblelittlerubybook.com/[/url]
Downloadable
The Little Book Of Ruby by Huw Collingbourne
[url]http://www.sapphiresteel.com/IMG/pdf/LittleBookOfRuby.pdf[/url]
The Book Of Ruby by Huw Collingbourne
[url]http://www.sapphiresteel.com/IMG/zip/book-of-ruby.zip[/url]
And there is also the only book on SketchUp and Ruby: âAutomatic SketchUpâ by Matthew Scarpino.
Available for free download in searchable PDF here:
http://www.crai.archi.fr/rld/pdf/Automatic_SketchUp.pdf
Also on Amazon for $249(???) in paperback but why would you do that?
⌠which is the LAST book a newbie should ever read ! (It has serious issues with best practices.)
Since I might be following those worst practices, please enlighten me.