Intersecting Hollow Objects using intersect_with
-
You are making it more complicated than it needs to be.
Instead of slicing a plane through the object and producing some edges, and then having to do complicated checks to see what is to be erased and then what faces need creating on the cut plane etc.... why not use the 'solid' tools available to you in the API as a Pro users?
Now you have anobject_group
[that is a 'solid'], and you want to 'chop' a piece off it - so you make anothertemp_group
including the plane on the cut-line which is bigger than the object_group [as you are already doing for theintersect_with
].
Now offset that plane-face's 4 corners vertically down until they are all below theobject_group.bounds.min.z
.
You now have a distorted 'box' in outline astemp_group
.
Add faces to its edges so it becomes another solid form with 6 faces in all.There are various methods available to Pro users that can cut/combine/trim 'solids'.
In this case you'd want to use 'subtract
'.
Thus:
result_group = object_group.subtract(temp_group)
The result is a group that's still a 'solid' with faces added on the 'cut' plane etc...
Note that the 'result_group
' is a new group - the original 'object_group
' and 'temp_group
' no longer exist after the operation, so before doing the operation you will need to get references to thereference/name/layer/material/attribute_dictionaries
[if any] for the 'object_group
' and then reapply them to the new 'result_group
'... Thus to the user it will look as if you have cut a piece off the original 'object_group
' but actually the operation results in the destruction of the two solids used and the new solid that results has been reconfigured to match the original object in every way except it has modified geometry...See the API for 'group' and the various 'solid' tools it lists...
-
That sounds better... I ruled out boolean tools because I knew a face cannot be made into a solid group.
Wouldn't it be nice if SketchUp DID allow solid trimming with a face. We could specify the "trim direction" which is the direction to remove geometry. (In this case the -z direction.)
-
Thanks TIG,
I will definitely give that a go. I'll have to start up my work computer to give it a try though. I use the "free" version on a mac at home and the Pro windows version on my work laptop.Dan your thoughts are exactly where I wanted to go with being able to pick a direction for the cut. I envisioned a future user prompt to pick a side. I still think I could make it look like a plane being cut using TIG's described method by creating the geometry after the pick. But as a tool it would only be usable on a Pro machine it sounds.
I thought using the array comparisons would be a quick check of the entities created, but actually it didn't work out well because it looks as though Sketchup "redraws" entities like lines and faces when the intersect_with happens even if it's basically the same location. That's why I started down the checking edges, then checking vertices, etc.
-
@dan rathbun said:
That sounds better... I ruled out boolean tools because I knew a face cannot be made into a solid group.
Wouldn't it be nice if SketchUp DID allow solid trimming with a face. We could specify the "trim direction" which is the direction to remove geometry. (In this case the -z direction.)
Try this http://sketchucation.com/forums/viewtopic.php?p=433723#p433723 -
Thanks for the plugins, TIG! Those are awesome starting points for me. I will need to modify them so that they work for any plane that is non-orthogonal to the orgin. But I think that's just a matter of creating a "plane" through code and not choosing it like the plugin. Thanks again!
-
My plugins do cut on any plane that is defined by any three non-co-linear points: these don't need to be orthogonal, drawing a temp-grouped face, WorkPlane or even some guidelines to snap onto will define the plane for you...
To hard-code it you simply need to define the three points used in @pts...
Because a face has a plane and you can project a point onto a plane it's relatively straightforward to use an existing face to derive the plane, and thereby the points - you just need to project any point onto the face.plane (to be @pts[0]) then offset that original point 1.0 in the X and re-project for @pts[1], then 1.0 in the Y and re-project for @pts[2]... You'll need 'a trap' to ensure that the face isn't in an orientation that gives coincident/co-linear points for some projections - for example a face with a normal parallel to the X_AXIS will make @pts[1]==@pts[0] when it projects back onto the plane !
A simple way is to convert the projected points into arrays [point.to_a] as you save them into @pts, and also to project more than you'll need - e.g. @pts[3] as Z 1.0, then doing a @pts.uniq! should leave you with at least three points that are on the plane and not co-linear or the same points... Use @pts[0..2] to be sure of a good set... -
Thanks TIG. I am still working on this and will post my results.
On a side note:
I tried to create a function in the module I wrapped everything in and it won't load in Sketchup but works fine outside of the function block.
ex.module PMA_INT_TEST ..code here to create geometry end #of module
load PMA_INT_TEST.rb into Sketchup works fine
then I changed:
module PMA_INT_TEST create_geometry() def create_geometry() exact same..code here to create geometry end end #of module
load PMA_INT_TEST.rb into Sketchup get:
Error: #<NoMethodError: undefined method `create_geometry' for PMA_INT_TEST:Module> -
- You have two issues.
(1) The obvious. As the interpreter reads the module definition (for the first time,) it encounters a call to a method that is not yet defined, so the module's private method
method_missing()
is called passing the unknown method name in as a symbol.Your module has no local override of this error handler, so Ruby passes the call on up the inheritance chain, superclass by superclass. When it finds a root handler, the error is handled. In this case the default from class
Module
just raises aNoMethodError
exception.The exception's message is what you see, which should have also told you the error originated on line 2.
If not.. at the console you can get a reference to the last exception instance object, via the global$!
, and it's backtrace via the global$@
.So the general rule, is to define all your static objects first, usually in this order: constants, class/module @@variables, nested class or module defintions, class methods / module functions (grouping private and public together,) instance methods (grouping private and public together,) and finally "Run Once" init code that runs the first time the module or class is loaded.
"Run Once" init code is usually within a conditional block, such as:
` unless file_loaded?(File.basename(FILE))add menu items only once in here
end # Run Once`
If you have code that always runs each time you reload the module, then put it at the very end.
Keep in mind that the Ruby keywords
module
andclass
mean "open for editing (and create first if needed.)"(2) The not so obvious quirk of instance methods inside modules.
Instance methods inside modules are allowed for a specific purpose. And that is so the module can be used as a "mixin" library module, to
include
orextend
other module or class definitions.You are not creating a "mixin" module, but you would still like to have internal methods that can be called like instance methods with no parent qualification.
The answer is a trick called an anonymous singleton proxy class.
Proxy class objects are associated with a proxy object, are opened for definition with the syntax:
` class << proxy_objectend`
In the case of a custom module instance, the proxy object association is to the module it
self
.SO... within a module, define instance methods as you would inside a normal class definition, but instead put them inside a proxy class definition block (grouping private and public together.)
module PMA_INT_TEST require("sketchup.rb") # Constants here; THISFILE = "#{self.name};#{File.basename(__FILE__)}" # Module Variables here class << self # instance variables here public def use_my_tool() # call an internal method end private def create_geometry() # code here to create geometry end end # proxy class # RUN ONCE unless file_loaded?(THISFILE) # create menus and menuitems, # populate a toolbar, etc. file_loaded(THISFILE) # adds to $loaded_files array end # ALWAYS RUN WHEN LOADED CODE here end #of module
The global methods
file_loaded()
andfile_loaded?()
are defined in "Tools/sketchup.rb" so that file must berequire
'd if you use them. (Do not specify the "Tools" dir as it is already one of the members of the [ruby:1ngdxd24]$LOAD_PATH[/ruby:1ngdxd24] array that is used byrequire
.) -
Well I've been using the "solid" tools for the last few days and it is a whole lot easier than what I was trying before. It would be nice to find a non-Pro version, for home use. The following is my test_code. I will re-write using Dan's previous post as a guide. It's a little over my head at this moment and I'm still trying to completly understand it.
module PMA_INT_TEST require('sketchup.rb') l = 1.50 w = 1.50 t = 0.078 h = 20 model = Sketchup.active_model ents = model.entities #Just test geometry pt1 = [0,0,0] pt2 = [l,0,0] pt3 = [l,w,0] pt4 = [0,w,0] object_group = ents.add_group() object_group.name = "OBJECT GROUP" cpt = object_group.entities.add_cpoint(ORIGIN) face1 = object_group.entities.add_face pt1,pt2,pt3,pt4 cpt.erase! pt1 = [0+t,0+t,0] pt2 = [l-t,0+t,0] pt3 = [l-t,w-t,0] pt4 = [0+t,w-t,0] face2 = object_group.entities.add_face pt1,pt2,pt3,pt4 face2.erase! face1.reverse! face1.pushpull h #Creating Test Cutgroup1 cut_group1 = ents.add_group() cpt = cut_group1.entities.add_cpoint(ORIGIN) pt1 = [0,0,0] pt2 = [l,0,0] pt3 = [l,w,0] pt4 = [0,w,0] face3 = cut_group1.entities.add_face pt1,pt2,pt3,pt4 face3.reverse! face3.pushpull h t1 = Geom;;Transformation.translation [0,0,10] ts1 = Geom;;Transformation.scaling [l/2,w/2,0], 10 tr1 = Geom;;Transformation.rotation [0, 0, 0], [1, 0, 0], 10.degrees cut_group1.transform! tr1 * t1 * ts1 cut_group1.name = "CUT GROUP1" cpt.erase! #Creating Test Cutgroup2 cut_group2 = ents.add_group() cpt = cut_group2.entities.add_cpoint(ORIGIN) pt1 = [0,0,0] pt2 = [l,0,0] pt3 = [l,w,0] pt4 = [0,w,0] face4 = cut_group2.entities.add_face pt1,pt2,pt3,pt4 face4.pushpull h t2 = Geom;;Transformation.translation [0,0,1] tr2 = Geom;;Transformation.rotation [0, 0, 0], [1, 0, 0], -10.degrees cut_group2.transform! tr2 * t2 * ts1 cut_group2.name = "CUT GROUP2" cpt.erase! #Create "NEW" group from cut group and from object group UI.messagebox("CUTTING") cut_group = cut_group1.subtract(object_group) cut_group = cut_group2.subtract(cut_group) cut_group.name = "NEW NAME" end #of module PMA_INT_TEST
-
There's BoolTools http://www.Smustard.com, for just $10...
There's also Oscarlok's Boolean ODCoolean toolset, in the Plugins Index, which is free... http://sketchucation.com/forums/viewtopic.php?p=112055#p112055
These both replicate several of the solid tools in Free that are available only in Pro...
Advertisement