[Plugin] Another g-code export
-
Uli, thank you for this. Very interesting stuff. Makes me want to build a CNC router which I don't have room for in my shop.
-
If you're interested in open source projects you might want to check out the STL project from SketchUp. There's talks about GCode as well once we've polished up STL Import/Export. Suggestion has been made that the project could be extended to GCode eventually to provide a complete package for fabbing and such. https://github.com/SketchUp/sketchup-stl/issues/40
-
I had a look at the source code of the plugins on the page you linked to. I noticed you said they where for personal use - but since you posted the link here on this forum I'll provide some notes about writing plugin in general ensuring that they don't clash with anything else.
I noticed you have several methods that's not inside a module or class. These ends up being added to the Kernel class, which is included in Object which then again means they'll get inherited by every other class around.
Because of that it's recommended that you wrap your whole plugin in a module - isolating your plugin from the rest of the environment.I also noticed that you have several methods starting with capital letters - which is not the Ruby convention. Anything starting with capital letters in Ruby are constants.
And I also advice against using global variables. If you wrap your code in a module when you can use an instance variable inside that module instead.
More info:
http://www.thomthom.net/thoughts/2012/01/golden-rules-of-sketchup-plugin-development/ -
Hi!
Thanks for your hints:
If these are all things that I've made "bad", then I'm happy.I'm a software developer, but ruby is not my primary environment (which is C++ in embedded environments): In fact, I just tried to find out how to get the things working. After all, it wasn't that hard, and I really like the object-model that I can access with ruby. And Ruby really is a funny language and simple to use:
The G-Code Exporter was written while I was waiting for "pycam" working on an exported STL file from Sketchup...I hope the gcode-export code is better than the attribute code: At least it is using a class, but you can see my learning curve when you read it from end upwards to the beginning: The first lines (=at the end of the file) were written without knowing how to declare anything, and later I just copied them from one script to the next. They did (and do) their job... The attribute thing was just a quick hack to make it usable.
It better should use a input box for example.The capital letter thing is a thing I didn't know at all. Thanks for that. In the end, I still don't know ruby at all: I had to search google how to write a while loop
Global variables are bad, you are right. I hope the @xxx variables are members of the class?So we come to a question:
What is the best initialization and "let a instance of class do the work" example that I should follow? For example, this extension thing seems to be the way to go, but it did not work as I expected.At least for the G-Code Exporter I expect to continue to work on it the next time a bit more, so all hints are welcome. In fact, I'm not a G-Code expert at all, but I got it that far to get my work done.
For the question about working on open source projects: If I would have time... But I will have a look at it.
And yes, I posted it here to get comments: About the code, what it is doing and how it could be improved.
Thank you for that,
Uli
-
@utessel said:
So we come to a question:
What is the best initialization and "let a instance of class do the work" example that I should follow?I'm not quite sure what you refer to here. In regard to wrapping it into a namespace? In which case, if you don't have an actual object to do the work (where you'd use a class) just use a module to wrap everything in.
I have a feeling I might have completely failed that answer...
-
@thomthom said:
I have a feeling I might have completely failed that answer...
Partially ...
Because you had one answer on your page
The "Hello World example that “plays nice”" is already a good start: I didn't know about modules (in ruby)!
At least, this is a change that is so easy to follow and improves the scripts already.I like the way plugins can installed now and like to have a checkbox to disable them:
But the script itself has to support this: There is this "SketchupExtension" thing: How would your "hello world" example look with that? Register was easy, but disable did not work. At least not immediately, so I didn't spend time on it. -
With extensions you need two files. One that lies directly in the Plugins folder, one that is located in a subfolder.
Example:
SketchUp/Plugins/myplugin.rb
<span class="syntaxdefault"><br />require </span><span class="syntaxstring">'sketchup.rb'<br /></span><span class="syntaxdefault">require </span><span class="syntaxstring">'extensions.rb'<br /><br /></span><span class="syntaxdefault">module NN_MyOwnUniqueNamespace<br /> <br /> </span><span class="syntaxcomment">### CONSTANTS ### ----------------------------------------------------------<br /></span><span class="syntaxdefault"> PLUGIN_NAME </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> </span><span class="syntaxstring">'Super Plugin'</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">freeze<br /> PLUGIN_VERSION </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> </span><span class="syntaxstring">'1.0.0'</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">freeze<br /> <br /> ROOT_PATH </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> File</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">dirname</span><span class="syntaxkeyword">(</span><span class="syntaxdefault"> File</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">expand_path</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">__FILE__</span><span class="syntaxkeyword">)</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">).</span><span class="syntaxdefault">freeze<br /> PATH </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> File</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">join</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">ROOT_PATH</span><span class="syntaxkeyword">,</span><span class="syntaxdefault"> </span><span class="syntaxstring">'MySuperPlugin'</span><span class="syntaxkeyword">).</span><span class="syntaxdefault">freeze<br /> <br /> </span><span class="syntaxcomment">### EXTENSION ### ----------------------------------------------------------<br /></span><span class="syntaxdefault"> PROXY_LOADER </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> File</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">join</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">PATH</span><span class="syntaxkeyword">,</span><span class="syntaxdefault"> </span><span class="syntaxstring">'core.rb'</span><span class="syntaxkeyword">).</span><span class="syntaxdefault">freeze<br /> <br /> ex </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> SketchupExtension</span><span class="syntaxkeyword">.new(</span><span class="syntaxdefault"> PLUGIN_NAME</span><span class="syntaxkeyword">,</span><span class="syntaxdefault"> PROXY_LOADER </span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault"> ex</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">description </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> </span><span class="syntaxstring">"Lorem ipsum dolor sit amet."<br /></span><span class="syntaxdefault"> ex</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">version </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> PLUGIN_VERSION<br /> ex</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">copyright </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> </span><span class="syntaxstring">'John Doe © 2010-2012'<br /></span><span class="syntaxdefault"> ex</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">creator </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> </span><span class="syntaxstring">'John Doe (johndoe@example.com)'<br /></span><span class="syntaxdefault"> Sketchup</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">register_extension</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">ex</span><span class="syntaxkeyword">,</span><span class="syntaxdefault"> true</span><span class="syntaxkeyword">)<br /><br /></span><span class="syntaxdefault">end </span><span class="syntaxcomment"># module<br /> </span><span class="syntaxdefault"></span>
SketchUp/Plugins/MySuperPlugin/core.rb
<span class="syntaxdefault"><br />require </span><span class="syntaxstring">'sketchup.rb'<br /></span><span class="syntaxdefault"> <br />module NN_MyOwnUniqueNamespace<br /> <br /> unless file_loaded</span><span class="syntaxkeyword">?(</span><span class="syntaxdefault"> __FILE__ </span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault"> menu </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> UI</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">menu</span><span class="syntaxkeyword">(</span><span class="syntaxdefault"> </span><span class="syntaxstring">'Plugins'</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault"> menu</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">add_item</span><span class="syntaxkeyword">(</span><span class="syntaxdefault"> </span><span class="syntaxstring">'Hello World'</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">)</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">{</span><span class="syntaxdefault"> self</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">hello_world </span><span class="syntaxkeyword">}<br /></span><span class="syntaxdefault"> end<br /> <br /> </span><span class="syntaxcomment"># Use instance variables inside modules instead of global variables.<br /></span><span class="syntaxdefault"> </span><span class="syntaxkeyword">@</span><span class="syntaxdefault">my_variable </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> </span><span class="syntaxstring">'Hi there! ;)'<br /></span><span class="syntaxdefault"> <br /> def self</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">hello_world<br /> puts </span><span class="syntaxkeyword">@</span><span class="syntaxdefault">my_variable<br /> end<br /> <br /> file_loaded</span><span class="syntaxkeyword">(</span><span class="syntaxdefault"> __FILE__ </span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault"> <br />end </span><span class="syntaxcomment"># module<br /></span><span class="syntaxdefault"></span>
That's roughly the typical pattern I use.
-
Cool, thanks...
Learned a lot:
.freeze has something to do make a string really constant I expect. Will read ruby docu for that.
The filename you give to the extension is the the one that is loaded (or not, when disabled): To use the subfolder is required so that the script is not loaded automatically! This was one thing I didn't undertand how this should work. Might have been to obvious? In the end, very simple but effective solutionIn combination with .rbz files the typical user doesn't need to know anything about scripts anymore: Just select the downloaded file and install, and disable if you don't want it. Nice improvement! (Ok, no real uninstall yet...)
Of course I will do this to my scripts! -
@utessel said:
.freeze has something to do make a string really constant I expect. Will read ruby docu for that.
Correct. Ruby will let you redefine a constant - but output a warning. Freezing it ensures you don't inadvertently modify it with methods like
.chop!
etc.@utessel said:
The filename you give to the extension is the the one that is loaded (or not, when disabled):
Correct.
@utessel said:
To use the subfolder is required so that the script is not loaded automatically!
Yes. For large plugins, even the ones doesn't use SketchupExtension I use sub-folders so I can split each class and module in the project into separate files. Also when you need extra support files, such as for WebDialogs or translations.
Speaking of WebDialogs, I recommend you look at this thread if you should use that class. It's one of the items in the API that has a few inconsistencies and cotcha's.
http://sketchucation.com/forums/viewtopic.php?f=180&t=23445And should you feel tempted to use Observers (try to keep them to a minimum and avoid modifying the model on their events) you might want to refer to this chart for know issues etc: http://www.thomthom.net/software/sketchup/observers/
@utessel said:
In combination with .rbz files the typical user doesn't need to know anything about scripts anymore: Just select the downloaded file and install, and disable if you don't want it.
RBZ is supported only by SketchUp 8. Before that plugins usually came in RB or ZIp packages (if they had multiple files). I made a simple utility to assist in this process, as it is one of the most frequently asked questions. http://sketchucation.com/forums/viewtopic.php?f=323&t=42315#p375454
@utessel said:
(Ok, no real uninstall yet...)
Yea, uninstall would be nice. In combination with a repository - like an app store.
-
@thomthom said:
Suggestion has been made that the project could be extended to GCode eventually to provide a complete package for fabbing and such. https://github.com/SketchUp/sketchup-stl/issues/40
Hmm, in fact my export code is one step towards that already.
I can imagine it can also be useful for 3D Printer. I still don't have one, but the time will come Adding a printing head to my milling machine?
What is missing to use the generated files on Machines like Mendel? Or is this completely nonsense?Anyway:
What really is missing are scripts that generate these paths now:
For example, generate paths "on" faces, typically all in the same Z-Position.
This is not too complex, a bit more is to make them loop-free and to connect one layer with the next.But for this I had an idea, as I had the problem already:
Imagine you have a line from top down to a circle, and then further down.
Sketchup will connect the circle and the line. Now what path do you want?
At that vertex of the connection I have four edges. Continue straight is not useful here as you will miss the circle.
Now my idea: An attribute that tells (stores) the expected direction!
If two edges are marked with the same "walk this way" value, then the path is clear.
For my example: The edge from top to circle gets an "A", and the right edge here (of the circle) also gets an "A". The left edge (other side, still on the circle) gets a "B", and the line going down also get the "B". Now the path is well defined and doesn't have problems with interesections. Ok, to select the two edges on a circle is tricky, but it was just an example.If now someone could tell me how to select and edge within a group (within a group...), then I (aehm, the script of course) could show directly where a problem with the current date exists.
When the path is generated by a script it is obviously easy to set attributes like this.Ah, and another thing I'm thinking about:
Imagine you have a script that fills a face with lines: But where to start? Where to continue from one layer to the next? One idea is: You draw a line to start the path and where you want to go down. Then you select the face(s!) together with that line, right click and say "fill..." (or so). Now that script has a starting point, and can ask some questions (only material XY, distance from line to line, etc.) and then it fills the face with lines.
This doesn't work well with groups (and the lines should be in their own group), so the idea is not finished yet.Maybe someone has different ideas how to solve these problems (Continue-here on crosses, filling faces with lines)?
Thanks,
Uli
-
I just gave Noel Warren a nudge to this thread. Maybe he's some input.
-
@utessel said:
If now someone could tell me how to select and edge within a group (within a group...), then I (aehm, the script of course) could show directly where a problem with the current date exists.
When the path is generated by a script it is obviously easy to set attributes like this.As long as you have a reference to an entity you can add it to the selection:
Sketchup.active_model.selection.add(edge)
But! SketchUp isn't expecting the have entities selected which doesn't belong to the current context. If it's for the purpose of debugging I'd not worry too much.
But if it's something to display to the end user you probably want to use a Tool to draw on the viewport. Something like what Solid Inspector does - it checks a mesh for errors and highlights it. http://sketchucation.com/forums/viewtopic.php?f=323&t=30504#p267832
-
For the "how to find the way through a labyrinth of edges":
The attribute idea might work, but a bit better (also for the example) is to use two distinct attributes: Entry and Exit.Any other idea how to tell the script which edge to use next at a "multi-edge" vertex?
Advertisement