Complex scripting/plugin - to create a component library
-
First:
Ok will give it another try to purge before importing however a few notes:
I used illustrator to create and process the dwgs as I can use actions and keybord shortcuts to simply process them all in minutes. I cannot do this in a cad program but I will try and make sure everything is exploded as much as possible before importing and try again.second: ok I can use lupas rename for simplicity - I did not know of this. That will speed things up! So now assume the only difference in file names is the extention.
I converted them to jpg from the tiff because i didnt see how they needed the transparency and wanted to compress them a bit. Do they need transparency if the geometry it is applied to is clipping the white off? I can make them .png if needed?
Not sure what this means:
When the .dwgs are imported they dont import the hatches (which are the faces) and I cannot see any way of making sure a vector keeps any sort of "faces" when imported into Sketchup. Therefore the contents of the imported .dwgs (and therefore components) are JUST edges, no faces. I am unsure of what your final peice of ruby script is doing?Thanks for the help TIG
This is amazing! -
To explain the most recent code snippet... in 'English'.
You have a component containing just lines [aka edges].
These form the outline[s] of the final form you desire.
We get the 'bounding-box' of these - we'll use some of its properties later
We add the equivalent image to the component's entities-collection [just as you might had you edited the component and then manually added an image]
We set the image's insertion point to just off the origin -1mm in x/y and size the image to be 2mm bigger that the outline's bounds width/height.
This way the image is slightly bigger than the outline.
We explode the image.
The geometry of the outline and the image merge.
The image's face is now split up by the outline's edges.
These faces automatically use the image as a new textured material of the same name.
We then look through the component's geometry an collect all edges that don't have two faces - that is the 'perimeter' edges of the original image rectangle.
We erase those.
The related edges also disappear.
The remaining edges are now the outline.
It doesn't erase faces inside 'holes' - e.g. donut forms...
You can either do these manually by editing the component SKP later, or add an extra algorithm to find edges with two faces [potential holes] and then look at those faces and erase only the face where the edge is part of the face's outer_loop - if it forms an inner_loop of the face then it's the 'donut' face NOT the 'hole'.The later parts of the earlier code stand - this rotates the geometry so it's then "standing up"...
-
Wow!
Excellent!
Sounds perfect!Would it be ok to consolodate this script so I can use it? And explain if I need to edit anything please? (Your an absolute genius!)
Could you include the last part you mentioned about erasing inner faces? interesting to see how well it would work. Sounds like it would work perfectly on the people but may have issues on trees where the face of the leaves dont attach to the body of the tree - but this is something we could look at later or ignore and just use transparent png files so it wouldnt matter too much if the faces were there. (obviously the shadows wouldn't be as accurate but not crucial when it gets so complex with leaves!)
p.s. once this library is complete I might as well upload it to the Google Warehouse for others to benefit! - the idea is to speed up the process of getting good images by minimizing the use of post-editing in photoshop
-
togos=[] d.entities.each{|e|togos << e if e.valid? and e.is_a?(Sketchup::Edge) and e.faces.length<2} d.entities.erase_entities(togos)
This removes the four outer perimeter edges.
Now for the holes...faces=[] d.entities.each{|e|faces << e if e.is_a?(Sketchup;;Face)} (faces.length-1).times{ for face in faces if face.valid? for edgeuse in face.outer_loop.edgeuses if not edgeuse.partners[0] ### outermost face faces = faces - [face] loops = face.loops for loop in loops for fac in faces if fac.valid? and (fac.outer_loop.edges - loop.edges) == [] faces = faces - [fac] fac.erase! if fac.valid? ### fac abutts kept face so it must be erased... end #if fac end #for fac end #for loop end #if outermost end #for edgeuse end #if valid end #for face }#times
This looks complicated, BUT it ensures you end up with all faces that ought to be faces, it will get confused if you have made two overlapping rectangles the overlap is regarded as a hole even if you expected it to be solid...
-
haha absolutely genius!
Would you be able to just consolodate this code into one script then so I could copy and paste it into the ruby console? Pretty please
-
Sorry... you try.
I do have real [paid] work to do too...
It's not that hard to take the bits and get a single working tool...
It'll be good experience -
Done
I think?` ### PURGE UNUSED COMPONENTS
Sketchup.active_model.definitions.purge_unusedSETUP LIST OF NAMES
model=Sketchup.active_model
defs=model.definitions
cnames=[]
defs.each{|d|cnames << d.name}
cnames.sort!f='P:\02 General\Resource Library\People\JPEG'
cnames.each{|name|
d=defs[name]
bb=Gem::Boundingbox.new
d.entities.each{|e|bb.add(e.bounds)}ADD IMAGE TEXTURES
img=d.entities.add_image(File.join(f, File.basename(f, ".*")+".jpg"), [-1.mm,-1.mm,0], bb.width+2.mm, bb.height+2.mm)
img.explode
togos=[]
d.entities.each{|e|togos << e if e.valid? and e.is_a?(Sketchup::Edge) and e.faces.length<2}
d.entities.erase_entities(togos)
d.entities.each{|e|e.reverse! if e.is_a?(Sketchup::Face) && e.normal!=Z_AXIS}STAND COMPONENT CONTENTS TO VERTICAL
tr=Geom::Transformation.rotation(ORIGIN, X_AXIS, -90.degrees)
d.entities.transform_entities(tr, d.entities.to_a)
}FACE ME
cnames.each{|name|
defs[name].save_as(File.join(f, File.basename(f, ".*")+".skp"))
}REMOVE OUTER EDGE LEFT FROM EXPLODED IMAGE
img.explode
togos=[]
d.entities.each{|e|togos << e if e.valid? and e.is_a?(Sketchup::Edge) and e.faces.length<2}
d.entities.erase_entities(togos)REMOVE HOLES
faces=[]
d.entities.each{|e|faces << e if e.is_a?(Sketchup::Face)}
(faces.length-1).times{
for face in faces
if face.valid?
for edgeuse in face.outer_loop.edgeuses
if not edgeuse.partners[0] ### outermost face
faces = faces - [face]
loops = face.loops
for loop in loops
for fac in faces
if fac.valid? and (fac.outer_loop.edges - loop.edges) == []
faces = faces - [fac]
fac.erase! if fac.valid?
### fac abutts kept face so it must be erased...
end #if fac
end #for fac
end #for loop
end #if outermost
end #for edgeuse
end #if valid
end #for face
}#times` -
Needs testing - but looks reasonably convincing...
Indent the various parts of the code to make it 'readable'...
[Get Notepad++ - recommended for code editing etc]
Put your code inside a module thus:module LukeR def self.importer() ### add your code here end end
Usage: in the Ruby Console type
LukeR.importer
+ <enter>Change its name[s] as desired...
Later you can add your own new methods too like
LukeR.discombobulator
-
Last couple of points.
Using jpeg images as textures allows the faces to display received shadows [provided the containing object is set to do so too].
Using png images means they don't take shadows at all - the advantage is that they can have a transparent background so small 'holes' will be 'see-through' even if the face has no corresponding small hole.The other issue is hiding the edges of the faces within the component.
This easily done by adding a block of code near the end of each definition's processing...
d.entities.each{|e|e.hidden=true if e.is_a?(Sketchup::Edge)}
Only the component's faces are visible.
If View > Hidden Geometry is set ON the edges display as 'dotted' lines -
Managed to use a batch action in illustrator to successfully ungroup/explode all the components so that issue is solved.
Just tried saving the file as a .rb in the plugins folder and got and error. I am really not sure what I sould really do? Does the file name matter?
module LukeR def self.importer() ### PURGE UNUSED COMPONENTS Sketchup.active_model.definitions.purge_unused ### SETUP LIST OF NAMES model=Sketchup.active_model defs=model.definitions cnames=[] defs.each{|d|cnames << d.name} cnames.sort! f='P;\02 General\Resource Library\People\JPEG' cnames.each{|name| d=defs[name] bb=Gem;;Boundingbox.new d.entities.each{|e|bb.add(e.bounds)} ### ADD IMAGE TEXTURES img=d.entities.add_image(File.join(f, File.basename(f, ".*")+".jpg"), [-1.mm,-1.mm,0], bb.width+2.mm, bb.height+2.mm) img.explode togos=[] d.entities.each{|e|togos << e if e.valid? and e.is_a?(Sketchup;;Edge) and e.faces.length<2} d.entities.erase_entities(togos) d.entities.each{|e|e.reverse! if e.is_a?(Sketchup;;Face) && e.normal!=Z_AXIS} ### STAND COMPONENT CONTENTS TO VERTICAL tr=Geom;;Transformation.rotation(ORIGIN, X_AXIS, -90.degrees) d.entities.transform_entities(tr, d.entities.to_a) } ### FACE ME cnames.each{|name| defs[name].save_as(File.join(f, File.basename(f, ".*")+".skp")) } ### REMOVE OUTER EDGE LEFT FROM EXPLODED IMAGE img.explode togos=[] d.entities.each{|e|togos << e if e.valid? and e.is_a?(Sketchup;;Edge) and e.faces.length<2} d.entities.erase_entities(togos) ### REMOVE HOLES faces=[] d.entities.each{|e|faces << e if e.is_a?(Sketchup;;Face)} (faces.length-1).times{ for face in faces if face.valid? for edgeuse in face.outer_loop.edgeuses if not edgeuse.partners[0] ### outermost face faces = faces - [face] loops = face.loops for loop in loops for fac in faces if fac.valid? and (fac.outer_loop.edges - loop.edges) == [] faces = faces - [fac] fac.erase! if fac.valid? ### fac abutts kept face so it must be erased... end #if fac end #for fac end #for loop end #if outermost end #for edgeuse end #if valid end #for face }#times end end
ERROR
LukeR.importer Error; #<NameError; C;/Program Files/Google/Google SketchUp 8/Plugins/component_import.rb;17;in `importer'; uninitialized constant LukeR;;Gem> C;/Program Files/Google/Google SketchUp 8/Plugins/component_import.rb;17 C;/Program Files/Google/Google SketchUp 8/Plugins/component_import.rb;15;in `each' C;/Program Files/Google/Google SketchUp 8/Plugins/component_import.rb;15;in `importer' (eval);0
Nearly there now!
Thanks again TIG -
Typo
bb=Gem::Boundingbox.new
should be
bb=Geom::Boundingbox.new
The error messages show what's wrong 'Gem' and the line number - here '17'...
-
Ahh thank you. Will try again.
I looked there and thought it was the double "::" that was the issue -
I got the same error:
LukeR.importer Error; #<NoMethodError; undefined method `new' for ;Boundingbox;Symbol> C;/Program Files/Google/Google SketchUp 8/Plugins/component_import.rb;17 C;/Program Files/Google/Google SketchUp 8/Plugins/component_import.rb;15;in `each' C;/Program Files/Google/Google SketchUp 8/Plugins/component_import.rb;15;in `importer' (eval);17
module LukeR def self.importer() ### PURGE UNUSED COMPONENTS Sketchup.active_model.definitions.purge_unused ### SETUP LIST OF NAMES model=Sketchup.active_model defs=model.definitions cnames=[] defs.each{|d|cnames << d.name} cnames.sort! f='P;\02 General\Resource Library\People\JPEG' cnames.each{|name| d=defs[name] bb=Geom;;Boundingbox.new d.entities.each{|e|bb.add(e.bounds)} ### ADD IMAGE TEXTURES img=d.entities.add_image(File.join(f, File.basename(f, ".*")+".jpg"), [-1.mm,-1.mm,0], bb.width+2.mm, bb.height+2.mm) img.explode togos=[] d.entities.each{|e|togos << e if e.valid? and e.is_a?(Sketchup;;Edge) and e.faces.length<2} d.entities.erase_entities(togos) d.entities.each{|e|e.reverse! if e.is_a?(Sketchup;;Face) && e.normal!=Z_AXIS} ### STAND COMPONENT CONTENTS TO VERTICAL tr=Geom;;Transformation.rotation(ORIGIN, X_AXIS, -90.degrees) d.entities.transform_entities(tr, d.entities.to_a) } ### FACE ME cnames.each{|name| defs[name].save_as(File.join(f, File.basename(f, ".*")+".skp")) } ### REMOVE OUTER EDGE LEFT FROM EXPLODED IMAGE img.explode togos=[] d.entities.each{|e|togos << e if e.valid? and e.is_a?(Sketchup;;Edge) and e.faces.length<2} d.entities.erase_entities(togos) ### REMOVE HOLES faces=[] d.entities.each{|e|faces << e if e.is_a?(Sketchup;;Face)} (faces.length-1).times{ for face in faces if face.valid? for edgeuse in face.outer_loop.edgeuses if not edgeuse.partners[0] ### outermost face faces = faces - [face] loops = face.loops for loop in loops for fac in faces if fac.valid? and (fac.outer_loop.edges - loop.edges) == [] faces = faces - [fac] fac.erase! if fac.valid? ### fac abutts kept face so it must be erased... end #if fac end #for fac end #for loop end #if outermost end #for edgeuse end #if valid end #for face }#times end end
-
If you read it although it's the same line of code it is ANOTHER error!
Another daft typo!
It should actually beBounding**B**ox
NOT
Boundingbox
So the line should be
bb=Geom::BoundingBox.new
I didn't spot that either...
Incidentally the double :: is used to show the
Module::Class
A . shows the method [def] thus:
Module::Class.method()
You can also have aModule.method()
Sketchup and its related modules, like Geom, have both classes/methods and methods...The 'o' was simply missed out of the 'Geom' module's name, causing the error...
When testing a script the line references in errors are very useful [Notepad++ will display line numbers under one of it's Settings...]
A , instead of a . [or vice versa], a missing ( or } etc, a simple spelling error etc, can mess everything up big time... But if you know the line you can usually find the error easily... -
Ah ok Thankyou, I didn't realise it was case sensitive on commands! Will try again
-
Can't work this one out:
LukeR.importer C;/Program Files/Google/Google SketchUp 8/Plugins/component_import.rb;21; warning; Could not create Image for P;/02 General/Resource Library/People/JPEG/JPEG.jpg Error; #<NoMethodError; undefined method `explode' for nil;NilClass> C;/Program Files/Google/Google SketchUp 8/Plugins/component_import.rb;22 C;/Program Files/Google/Google SketchUp 8/Plugins/component_import.rb;15;in `each' C;/Program Files/Google/Google SketchUp 8/Plugins/component_import.rb;15;in `importer' (eval);0
module LukeR def self.importer() ### PURGE UNUSED COMPONENTS Sketchup.active_model.definitions.purge_unused ### SETUP LIST OF NAMES model=Sketchup.active_model defs=model.definitions cnames=[] defs.each{|d|cnames << d.name} cnames.sort! f='P;\02 General\Resource Library\People\JPEG' cnames.each{|name| d=defs[name] bb=Geom;;BoundingBox.new d.entities.each{|e|bb.add(e.bounds)} ### ADD IMAGE TEXTURES img=d.entities.add_image(File.join(f, File.basename(f, ".*")+".jpg"), [-1.mm,-1.mm,0], bb.width+2.mm, bb.height+2.mm) img.explode togos=[] d.entities.each{|e|togos << e if e.valid? and e.is_a?(Sketchup;;Edge) and e.faces.length<2} d.entities.erase_entities(togos) d.entities.each{|e|e.reverse! if e.is_a?(Sketchup;;Face) && e.normal!=Z_AXIS} ### STAND COMPONENT CONTENTS TO VERTICAL tr=Geom;;Transformation.rotation(ORIGIN, X_AXIS, -90.degrees) d.entities.transform_entities(tr, d.entities.to_a) } ### FACE ME cnames.each{|name| defs[name].save_as(File.join(f, File.basename(f, ".*")+".skp")) } ### REMOVE OUTER EDGE LEFT FROM EXPLODED IMAGE img.explode togos=[] d.entities.each{|e|togos << e if e.valid? and e.is_a?(Sketchup;;Edge) and e.faces.length<2} d.entities.erase_entities(togos) ### REMOVE HOLES faces=[] d.entities.each{|e|faces << e if e.is_a?(Sketchup;;Face)} (faces.length-1).times{ for face in faces if face.valid? for edgeuse in face.outer_loop.edgeuses if not edgeuse.partners[0] ### outermost face faces = faces - [face] loops = face.loops for loop in loops for fac in faces if fac.valid? and (fac.outer_loop.edges - loop.edges) == [] faces = faces - [fac] fac.erase! if fac.valid? ### fac abutts kept face so it must be erased... end #if fac end #for fac end #for loop end #if outermost end #for edgeuse end #if valid end #for face }#times end end
-
It's because it's another typo !
Line#21 should read
img=d.entities.add_image(File.join(f, File.basename(**name**, ".*")+".jpg"), [-1.mm,-1.mm,0], bb.width+2.mm, bb.height+2.mm)
sorry... -
Got some more issues TIG
Its getting there!-
It was rotating them the wrong angle so I change "-90" to "90" - so this is solved.
-
The result is just one component left - dont know where everything else went
-
For the one component that is left the face me doesnt seem to be working
-
I don't think it likes the img.explode on line 39
LukeR.importer Error; #<NameError; undefined local variable or method `img' for LukeR;Module> C;/Program Files/Google/Google SketchUp 8/Plugins/component_import.rb;39 (eval);0
module LukeR def self.importer() ### PURGE UNUSED COMPONENTS Sketchup.active_model.definitions.purge_unused ### SETUP LIST OF NAMES model=Sketchup.active_model defs=model.definitions cnames=[] defs.each{|d|cnames << d.name} cnames.sort! f='P;\02 General\Resource Library\People\JPEG' cnames.each{|name| d=defs[name] bb=Geom;;BoundingBox.new d.entities.each{|e|bb.add(e.bounds)} ### ADD IMAGE TEXTURES img=d.entities.add_image(File.join(f, File.basename(name, ".*")+".jpg"), [-1.mm,-1.mm,0], bb.width+2.mm, bb.height+2.mm) img.explode togos=[] d.entities.each{|e|togos << e if e.valid? and e.is_a?(Sketchup;;Edge) and e.faces.length<2} d.entities.erase_entities(togos) d.entities.each{|e|e.reverse! if e.is_a?(Sketchup;;Face) && e.normal!=Z_AXIS} ### STAND COMPONENT CONTENTS TO VERTICAL tr=Geom;;Transformation.rotation(ORIGIN, X_AXIS, 90.degrees) d.entities.transform_entities(tr, d.entities.to_a) } ### FACE ME cnames.each{|name| defs[name].save_as(File.join(f, File.basename(f, ".*")+".skp")) } ### REMOVE OUTER EDGE LEFT FROM EXPLODED IMAGE img.explode togos=[] d.entities.each{|e|togos << e if e.valid? and e.is_a?(Sketchup;;Edge) and e.faces.length<2} d.entities.erase_entities(togos) ### REMOVE HOLES faces=[] d.entities.each{|e|faces << e if e.is_a?(Sketchup;;Face)} (faces.length-1).times{ for face in faces if face.valid? for edgeuse in face.outer_loop.edgeuses if not edgeuse.partners[0] ### outermost face faces = faces - [face] loops = face.loops for loop in loops for fac in faces if fac.valid? and (fac.outer_loop.edges - loop.edges) == [] faces = faces - [fac] fac.erase! if fac.valid? ### fac abutts kept face so it must be erased... end #if fac end #for fac end #for loop end #if outermost end #for edgeuse end #if valid end #for face }#times end end
-
-
I would have thought -90.degrees was the correct angle... but if +90 works use it
I'm not sure how you are adding the initial components - importing as dxf/dwg outline ?
Before you add the images to their matching components made from the CAD files... do you have one of every type of component in the model ?? Remember this code is just to add an image to each preexisting component with the same name...You have a spurious
img.explode
line of code at line#39 remove it: it must have got copied down from where it's used earlier... and I'd not noticed it before...There's currently no code to make each component a 'faceme' type...
If you want that, then in the block {} that's processing the definition 'd' add a line
d.behavior.always_face_camera=true
-
@unknownuser said:
I'm not sure how you are adding the initial components - importing as dxf/dwg outline ?
Before you add the images to their matching components made from the CAD files... do you have one of every type of component in the model ?? Remember this code is just to add an image to each preexisting component with the same name...The .dwg files are imported into sketchup pro. But I used a batch import command I found elsewhere and it seems to work well. It will import every .dwg file in a selected folder, it imports all of these files into the current model - I used a new file so theres nothing else in it (apart from the default 2d woman!, but she got deleted). Each .dwg file is made into a component with the same name as the .dwg file. - so this should all match up with the file names of the jpegs in P:\02 General\Resource Library\People\JPEG
I have also attached an image that should help show what the sketchup model is like.
These components are all just outlines with no faces. just lines.example:
0001 vyonyx_couple_001.jpg
goes with
0001 vyonyx_couple_001.dwgHope this helps.
@unknownuser said:
You have a spurious
img.explode
line of code at line#39 remove it: it must have got copied down from where it's used earlier... and I'd not noticed it before...Ok will delete it.
@unknownuser said:
There's currently no code to make each component a 'faceme' type...
If you want that, then in the block {} that's processing the definition 'd' add a line
d.behavior.always_face_camera=true
Sorry I dont understand this
Shall I copyd.behavior.always_face_camera=true
into the script? where does it go?If it helps I have also found that it is creating a file in "P:\02 General\Resource Library\People\JPEG" called "JPEG.skp" - this is empty though.
If something is trying to save the components as .skp files, dont worry about this as long as they are in the same model I can just save all the components in the model via the components window.
Heres the current code:
module LukeR def self.importer() ### PURGE UNUSED COMPONENTS Sketchup.active_model.definitions.purge_unused ### SETUP LIST OF NAMES model=Sketchup.active_model defs=model.definitions cnames=[] defs.each{|d|cnames << d.name} cnames.sort! f='P;\02 General\Resource Library\People\JPEG' cnames.each{|name| d=defs[name] bb=Geom;;BoundingBox.new d.entities.each{|e|bb.add(e.bounds)} ### ADD IMAGE TEXTURES img=d.entities.add_image(File.join(f, File.basename(name, ".*")+".jpg"), [-1.mm,-1.mm,0], bb.width+2.mm, bb.height+2.mm) img.explode togos=[] d.entities.each{|e|togos << e if e.valid? and e.is_a?(Sketchup;;Edge) and e.faces.length<2} d.entities.erase_entities(togos) d.entities.each{|e|e.reverse! if e.is_a?(Sketchup;;Face) && e.normal!=Z_AXIS} ### STAND COMPONENT CONTENTS TO VERTICAL tr=Geom;;Transformation.rotation(ORIGIN, X_AXIS, 90.degrees) d.entities.transform_entities(tr, d.entities.to_a) } ### FACE ME cnames.each{|name| defs[name].save_as(File.join(f, File.basename(f, ".*")+".skp")) } ### REMOVE OUTER EDGE LEFT FROM EXPLODED IMAGE togos=[] d.entities.each{|e|togos << e if e.valid? and e.is_a?(Sketchup;;Edge) and e.faces.length<2} d.entities.erase_entities(togos) ### REMOVE HOLES faces=[] d.entities.each{|e|faces << e if e.is_a?(Sketchup;;Face)} (faces.length-1).times{ for face in faces if face.valid? for edgeuse in face.outer_loop.edgeuses if not edgeuse.partners[0] ### outermost face faces = faces - [face] loops = face.loops for loop in loops for fac in faces if fac.valid? and (fac.outer_loop.edges - loop.edges) == [] faces = faces - [fac] fac.erase! if fac.valid? ### fac abutts kept face so it must be erased... end #if fac end #for fac end #for loop end #if outermost end #for edgeuse end #if valid end #for face }#times end end
Advertisement