Complex scripting/plugin - to create a component library
-
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
-
You have got some of your coding steps in a tangle...
I'll fix it and post a working [hopefully] version soonest...Incidentally, you don't need to open SketchUp with 'the 2d-woman' etc.
You can delete her, Model Info > Statistics > Purge Unused...
Then set other values exactly as desired - Units, number of dp's, no-snapping, no-unit-suffix, Text font/size, Dimension defaults etc.
Then under File > Save as Template. Under Preferences set that as your default template, thereafter every time you open a new SKP it will be empty and have the exact settings you prefer... -
Ok Thank you!!!!!!!!
~~I have used sketchup for 5 years and never bothered to change the default style!
Thanks ~~
CHANGED! -
Here it is:
I can't try it because I have no paired dwg/image sets...### Usage; Ruby Console type LukeR.importer require('sketchup.rb') module LukeR def self.importer() model=Sketchup.active_model defs=model.definitions ### PURGE UNUSED COMPONENTS [NOT NEEDED IF YOU DO IT MANUALLY FIRST] #defs.purge_unused ### SETUP LIST OF NAMES etc cnames=[] defs.each{|d|cnames << d.name if File.extname(d.name).downcase == '.dwg'} cnames.sort! fj='P;\02 General\Resource Library\People\JPEG' ### for images ff='P;\02 General\Resource Library\People' ### for saved SKPs cnames.each{|name| puts name ### SET UP defn etc 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(fj, File.basename(name, ".*")+".jpg"), [-1.mm,-1.mm,0], bb.width+2.mm, bb.height+2.mm) img.explode ### REMOVE img's UNWANTED PERIMETER 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) ### ENSURE FACES ARE 'UP' d.entities.each{|e|e.reverse! if e.is_a?(Sketchup;;Face) && e.normal!=Z_AXIS} ### STAND COMPONENT'S CONTENTS TO BE VERTICAL tr=Geom;;Transformation.rotation(ORIGIN, X_AXIS, 90.degrees) d.entities.transform_entities(tr, d.entities.to_a) ### MAKE IT A FACE-ME COMPONENT d.behavior.always_face_camera=true ### REMOVE ANY '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 ### FINALLY... SAVE IT INTO 'PEOPLE' AS A' SKP' d.save_as(File.join(ff, File.basename(name, ".*")+".skp")) }#names end#def end#module
-
SO MUCH BETTER!
Ok its getting there!
Its not working fully.
I have deleted parts of the script and tried it again at various stages.
I think the deleting the img edges after exploding isnt working. I think the newly created face needs to be intersected with the rest of the outline (found that the whole rectangle is one face and currently ignores the outline).Can we add an intersect just after ### ADD IMAGE TEXTURES?
-
The
img.explode
ought to auto-intersect the image's face and the rest of the edges [I assume that the component 'outline' consists of just edges ??]
However, as you suggest... the following code inserted immediately after the 'img.explode' line of code, should ensure proper intersection, if it's possible...
t=Geom::Transformation.new() d.entities.intersect_with(false, t, d.entities, t, true, d.entities.to_a)
Things that might stop this being always effective are:
that the outline edges are not quite coplanar and therefore don't split the newly added image face:
the outline contains edges that are tiny in length, and thereby the Sketchup intersect method fails as both ends are deemed to be coincident and therefore the edge is not recognized and therefore no full loop is made as needed to hold a face...
If that's the case we can try to 'heal' tiny edges... but let's first see how the current fix-up ideas work... -
Yeah the components are just faces after being importer as dwg.
I tried just to add the textures them intersect them individually and that worked hence the suggestion of an intersect.
So that should work!But I did this and got an error:
LukeR.importer 0001 vyonyx_couple_001.dwg Error; #<NoMethodError; undefined method `transformation' for Geom;Module> C;/Program Files/Google/Google SketchUp 8/Plugins/component_import.rb;32 C;/Program Files/Google/Google SketchUp 8/Plugins/component_import.rb;20;in `each' C;/Program Files/Google/Google SketchUp 8/Plugins/component_import.rb;20;in `importer' (eval);0
I obviously put them in wrong! Sorry
UPDATE: My guess is it needs a capital T on transformation
testing now### Usage; Ruby Console type LukeR.importer require('sketchup.rb') module LukeR def self.importer() model=Sketchup.active_model defs=model.definitions ### PURGE UNUSED COMPONENTS [NOT NEEDED IF YOU DO IT MANUALLY FIRST] #defs.purge_unused ### SETUP LIST OF NAMES etc cnames=[] defs.each{|d|cnames << d.name if File.extname(d.name).downcase == '.dwg'} cnames.sort! fj='P;\02 General\Resource Library\People\JPEG' ### for images ff='P;\02 General\Resource Library\People\Sketchup People' ### for saved SKPs cnames.each{|name| puts name ### SET UP defn etc 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(fj, File.basename(name, ".*")+".jpg"), [-1.mm,-1.mm,0], bb.width+2.mm, bb.height+2.mm) img.explode t=Geom;;transformation.new() d.entities.intersect_with(false, t, d.entities, t, true, d.entities.to_a) ### REMOVE img's UNWANTED PERIMETER 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) ### ENSURE FACES ARE 'UP' d.entities.each{|e|e.reverse! if e.is_a?(Sketchup;;Face) && e.normal!=Z_AXIS} ### STAND COMPONENT'S CONTENTS TO BE VERTICAL tr=Geom;;Transformation.rotation(ORIGIN, X_AXIS, 90.degrees) d.entities.transform_entities(tr, d.entities.to_a) ### MAKE IT A FACE-ME COMPONENT d.behavior.always_face_camera=true ### REMOVE OUTER EDGES 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 ANY '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 ### FINALLY... SAVE IT INTO 'PEOPLE' AS A' SKP' d.save_as(File.join(ff, File.basename(name, ".*")+".skp")) }#names end#def end#module
It didnt do that before I added the intersect command
-
You are right it needs to be
t=Geom::**T**ransformation.new()
-
WOW!
))))))))))
Ok So a few things, very nearly perfect now!
I have attached an image showing a new model which i dropped approx 50 people into (in less than a minute )))))))Issues:
1 - I believe some of the jpegs need cutting out better as some have tiny artifacts where they should be transparent. This is causing the bounding box of the outline and the jpeg of some images to be off. I will look into a quick way of doing this i photoshop. (They have all been trimmed but not sure how to batch trim/crop/remove the artifacts and images when all the image sizes are different etc... Might go to the photoshop forums for this.)2 - I removed some of the script to try and correct it as it was not working before. It seems to delete everything so all the skp files are empty. I thought this was the removing holes script but I beleive it to be either: "### REMOVE img's UNWANTED PERIMETER", "### REMOVE OUTER EDGES LEFT FROM EXPLODED IMAGE" or "### REMOVE ANY 'HOLES'"
Further testing is needed to determine the culprite of the mass deleting issue.
HOWEVER (dont ask me why, I will look into it though)
All the components have successfully saved as perfect components with the exception of off centered jpeg textures - issue one as above. Something deleted the img borders but not sure what!-
Would be useful to get better thumbnails of the components. As they are currently shown in the component library window as the original dwg outlines - needs updating? (see attached image)
-
The odd few are out of scale for example groups of people and people sitting down. This is not an issue as they are just odd ones and will be scaled down manually after
### Usage; Ruby Console type LukeR.importer require('sketchup.rb') module LukeR def self.importer() model=Sketchup.active_model defs=model.definitions ### PURGE UNUSED COMPONENTS [NOT NEEDED IF YOU DO IT MANUALLY FIRST] #defs.purge_unused ### SETUP LIST OF NAMES etc cnames=[] defs.each{|d|cnames << d.name if File.extname(d.name).downcase == '.dwg'} cnames.sort! fj='P;\02 General\Resource Library\People\JPEG' ### for images ff='P;\02 General\Resource Library\Sketchup People' ### for saved SKPs cnames.each{|name| puts name ### SET UP defn etc 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(fj, File.basename(name, ".*")+".jpg"), [-1.mm,-1.mm,0], bb.width+2.mm, bb.height+2.mm) img.explode t=Geom;;Transformation.new() d.entities.intersect_with(false, t, d.entities, t, true, d.entities.to_a) ### ENSURE FACES ARE 'UP' d.entities.each{|e|e.reverse! if e.is_a?(Sketchup;;Face) && e.normal!=Z_AXIS} ### STAND COMPONENT'S CONTENTS TO BE VERTICAL tr=Geom;;Transformation.rotation(ORIGIN, X_AXIS, 90.degrees) d.entities.transform_entities(tr, d.entities.to_a) ### MAKE IT A FACE-ME COMPONENT d.behavior.always_face_camera=true ### FINALLY... SAVE IT INTO 'PEOPLE' AS A' SKP' d.save_as(File.join(ff, File.basename(name, ".*")+".skp")) }#names end#def end#module
This code worked:
-
-
I noticed you aren't 'hiding edges' anywhere...
In this code
d.entities.each{|e|e.reverse! if e.is_a?(Sketchup::Face) && e.normal!=Z_AXIS}
adjust it to read like this
d.entities.each{|e|e.reverse! if e.is_a?(Sketchup::Face) && e.normal!=Z_AXIS**; e.hidden=true if e.is_a?(Sketchup::Edge)**}
This saves iterating everything another time, to optimize speed...Using a PNG image with a transparent background avoids the 'white-fringe' issues of poorly trimmed JPG images. It also allows potential holes to remain 'see-through', although the cutout's shadows won't then match, and PNG textured materials on faces never 'receive shadows' either...
You should also add...
**d.refresh_thumbnail**
to get an updated thumbnail image ?
Insert it just before the line that saves the SKP externally...
d.save_as(...)
Hope this helps...
-
I'm not sure I want to hide edges. Will have a think about that one!
Mainly because I can always turn edges off on the style for the whole model.
I will ask a collegue what they would prefer to do but nice to have the code there if he wants them hidden so thanks again! - I quite like the option of having them as silhuettes as well for more concept images (change style to hidden line)I will add the refresh thumbnail, cheers!
I'm trying to think if I need them to receive shadows or not! - i dont think it matters, in which case I will probably change to png images. However it will solve half the issue; fill the white with transparency. But it wont get rid of the small artifacts so there will still be lots of images with off axis images. - a photoshop issue. But yeah I think your right, use pngs!
-
As an alternative to hiding edges, Is it easy to move the edges to another layer to allow easy on/off of them? Just a thought.
-
hidn=model.layers.add("HIDN-LINE")### or whatever name you like! d.entities.each{|e|e.reverse! if e.is_a?(Sketchup::Face) && e.normal!=Z_AXIS; e.layer=hidn if e.is_a?(Sketchup::Edge)}
-
So just to confirm is this right:
Will this keep the lines visible? I would like it to save the component with the lines as visible then hide the layer is needed. The name should probably be "People Outlines"Also while were at it is might be good to have the components on they're own layer "People"
is this right?
I haven't added anything to move the component default layer though.hidn=model.layers.add("People Outlines")### or whatever name you like! d.entities.each{|e|e.reverse! if e.is_a?(Sketchup;;Face) && e.normal!=Z_AXIS; e.layer=hidn if e.is_a?(Sketchup;;Edge)}
-
The layer 'hidn' is visible by default.
You can name a layer whatever you like!
I don't recommend that you put the 'faces' on another layer.
Let the user decide how to layer their own model. With the face on Layer0 inside the component it assumes the instance's current layer anyway - that way you can then have two separate sets of 'people' assigned to different layers and switch between them...
BUT if you really insist it's simple enough...hidn=model.layers.add("People Outlines")### or whatever name you like! peep=model.layers.add("People Images")### or whatever name you like! d.entities.each{|e|e.reverse! if e.is_a?(Sketchup;;Face) && e.normal!=Z_AXIS; e.layer=hidn if e.is_a?(Sketchup;;Edge); e.layer=peep if e.is_a?(Sketchup;;Face);}
-
ABSOLUTELY BRILLIANT!
This is SO good now!
LONG STORY SHORT I THINK YOU'VE DONE IT!comments (some for me )/
1 - deleted a duplicate (it was in the scrit twice!) of the img perimeter deleting - this caused everything to be deleted (a page back) ("### REMOVE img's UNWANTED PERIMETER", "### REMOVE OUTER EDGES LEFT FROM EXPLODED IMAGE")2 - I will need to sort out the images with small artifacts causing off axis
3 - I am yet to try the hole deleting part but its not causing any issues on people - doing the trees tomorrow so will try then!
4 - The layers work perfectly - will have a think whether to leave as default layer or change to People. Thinking of leaving as default as you said.
5 - Changed to png which works much cleaner
6 - Thumbnail refresh works well
Advertisement