Apologies in advance for my noobie questions! I’m getting a
little lost in the Ruby API and could do with some pointers.
A bit of background: Pretty much all of my work in SU
involves importing a DXF and pulling into a ‘standard thickness’. Taking a PCB
outline from my PCB package and turning it into a 3d model.
Using this as a model for my Ruby script I will add the API
methods.
File>Import DXF
UI.openpanel- toobtain DXF location
Model.import- to import the DXF
UI.inputbox- to obtain PCB thickness
Select outline Tools>Utilities>Create Face
Edge.find_faces – to createface. This was mentioned in this thread. How do I select an edge of the DXF? How should I Handle the DXF import?
Select All Edit>Intersect Faces>With Selection
Not sure what to do here! Help!
Select and Delete nested faces
I guess a loop is needed here using Face.area to
find the face area and then delete all the smallest faces and leave only the
largest? How do I find and select the nested faces?
Select remaining face Pull to 1.6mm
Face.pushpull to pull to thickness. Thickness taken from point 1
Save (to be imported into and assembly)
Further to this adding a PNG as a texture to the top and bottom using UI.openpanel and Model.import would be very useful!
Is this approach reasonable? Please give me some pointers to head me in the correct direction!
I have attached my coding efforts so far. AKDXF.rb (305 Bytes)
And a sample DXF. Nest.dxf (6.9 KB)
require 'sketchup.rb'
UI.menu("Extensions").add_item("AK PCB Tool"){
SKETCHUP_CONSOLE.show
ak_PCBTool #method call
}
#The pcb tool method
def ak_PCBTool
# Vars for model
mod = Sketchup.active_model
ents = mod.active_entities
# generate an open file dialog and store location in 'dxfLocation'
# Only allow DXF import
dxfLocation=UI.openpanel("Import PCB DXF", "", "DXF|*.dxf||") #cancel button not handled yet! todo
#Generate user input box to get pcb thickness store in pcbInput array
#akPrompts store name for imputbox array
akPrompts = ["PCB Thickness"]
#akDefaults store default value array .mm to give dimension to the array element
akDefaults = [1.6.mm]
pcbInput = UI.inputbox(akPrompts,akDefaults,"PCB Thickness") #cancel button not handled yet! todo
#Take array element and store in var 'pcbThickness'
pcbThickness = pcbInput.at(0)
#improt dxf
mod.import dxfLocation,false
#find_face on all edges
ents.each{|ent|
if ent.typename == "Edge"
#pcbEdges << ent
ent.find_faces#this approach is brute force and not effiecnt but ensures all faces are found
puts ent #verbose debug
end
}
#Create and populate an array of pcb faces.
pcbFaces = []
ents.each{|ent|
if ent.typename=="Face"
pcbFaces << ent
puts ent #verbose debug
end
}
puts "pcb faces:"
puts pcbFaces.length #verbose debug
#if there is one pcb face pull to pcbthickness
if pcbFaces.length == 1
pcbFace=pcbFaces[0]
pcb=pcbFace.pushpull pcbThickness*-1# assumes pcb faces the same direction if pcb is ever pulled -ve to z this will need recoding to detect and correct
end
end
So…
I can import my dxf, add faces to the imported edges and if I have a single face pull it to pcb thickness.
If I have more than one face I’m lost. How do I find the faces surrounded by a face? I guess I can then use face,erase!.
My first idea was to use face.area to find the smallest areas and erase them. the trouble with this is there is no guarantee that the smallest faces are the ones I want to erase.
Yes. I did have a look. I have probably misunderstood the thread. I will give it another look.
I see how that is better. noted and added.
I have not given materials much though yet. I plan to add .png to the top and bottom face in the future.
Is adding a material worth doing if I will be adding png textures later?
Not sure it will fit your workflow, but this is a function that I use to do something very similar. Notice that it works only if the holes are all internal.
a group of faces (faces to be cut). In your case this would be the face generated by the outerloop
an array of ‘tools’. This is an array of solid groups. In your case a tool would be generated by pushpulling the internal faces.
This is the code:
def self.cut_surfaces(tools, surface_group) #log
#puts 'BEFORE INTERSECTION'
#puts 'All entities in group'
#puts surface_group.entities.each{|e| p e}
#surface.entities.select{|e| e.is_a?(Sketchup::Face)}.each{|e| p e.to_s}
orig_surfaces = surface_group.entities.select{|s| s.is_a?(Sketchup::Face)}
tools.each do |t|
arrays = t.entities.intersect_with false, t.transformation, surface_group.entities, surface_group.transformation, false, surface_group
end
#puts 'AFTER INTERSECTION'
#puts 'All surfaces in group'
#surface_group.entities.grep(Sketchup::Face).each{|e| p e.to_s}
del = surface_group.entities.grep(Sketchup::Face).select{|e| !orig_surfaces.include?(e)}
#puts 'Surfaces to be deleted'
#del.each{|e| p e}
del.each do |e|
surface_group.entities.erase_entities(e)
end
return true
end
I have my script working quite well. I thought i would share my code here.
require 'sketchup.rb'
UI.menu("Extensions").add_item("AK PCB Tool 1.1"){
SKETCHUP_CONSOLE.show
ak_PCBTool
}
#The pcb tool method
def ak_PCBTool
# Vars for model
mod = Sketchup.active_model
ents = mod.active_entities
pcbview = Sketchup.active_model.active_view
# generate an open file dialog and store location in 'dxfLocation'
dxfLocation=UI.openpanel("Import PCB DXF", "", "DXF|*.dxf||")
if dxfLocation == nil
puts "cancelled at DXF in!"
else
#Generate user input box to get pcb thickness store in pcbInput array
#akPrompts store name for imputbox array
akPrompts = ["PCB Thickness"]
#akDefaults store default value array .mm to give dimension to the array element
akDefaults = ['1.6.mm'.to_l]
pcbInput = UI.inputbox(akPrompts,akDefaults,"PCB Thickness")
#Take array element and store in var 'pcbThickness'
if pcbInput == false
puts "cancelled at Thickness!"
else
pcbThickness = pcbInput.at(0)
#improt dxf
mod.import dxfLocation,false
#find_face on all edges
totNumEdges=0
pcbEdges=[]
ents.each{|ent|
if ent.typename == "Edge"
pcbEdges<<ent
end
}
totNumEdges=pcbEdges.length
puts "Total number of edges: " + totNumEdges.to_s
faceCount=0
while pcbEdges.length>0 do
faceCount=faceCount+1
anEdge=pcbEdges.at(0)
connectedE=anEdge.all_connected
anEdge.find_faces
pcbEdges=pcbEdges-connectedE
puts "face " + faceCount.to_s + " found"
end
#Create and populate an array of pcb faces.
pcbFaces = []
ents.each{|ent|
if ent.typename=="Face"
pcbFaces << ent
end
}
puts "pcb faces: " + pcbFaces.length.to_s #verbose debug
puts "Removing inner faces and pull to thickness"
faceCount=0
pcbFaces.each{|face|
faceCount=faceCount+1
faceEdges=face.edges
if faceEdges.length==totNumEdges
face.pushpull pcbThickness*-1
puts "Face " + faceCount.to_s + " is the PCB face. Pulled to Thickness"
else
face.erase!
puts "Face " + faceCount.to_s + " is a void. Face erased"
end
}
pcbview.zoom_extents
puts "Done, you can now close the Ruby Console "
end
end
end
This is perhaps not the best method but it has saved alot of time already.