SketchUcation Plugin Store

 

 

basics - creating components and pushpull direction

basics - creating components and pushpull direction

Postby troypiggo » Wed Jul 18, 2012 4:39 am

Very new to Ruby scripting, so please excuse potentially dumb questions.

I'm trying to write a script to draw timber stud walls. At the moment I'm just trying to get the basics working - bottom plate, stud, top plate as components. Later I'll copy the studs at certain spacings along the length of wall, add nogging, allow custom input dimensions etc, and maybe add features for windows/doors etc with jamb studs, lintels and so on.

Below is the code where I'm at for now. It works, kind of, in that it draws a bottom plate, a stud, and top plate.

1. But the top plate is being drawn in the wrong/opposite direction to the bottom plate, even though the code is almost identical. See image below. Any ideas why? If I make the bottom plate and stud components as they're created, would that stop this behaviour?

2. That leads to my next stumbling block. I'm at a total loss on how to create a component from each element. I'm reading through the API and "Automatic Sketchup" PDF, but it still eludes me.

3. In future, instead of hard coding the dimensions, I'd obviously like to be able to select an edge or face, click my studwall icon, up pops a window where you can type in the relevant dimensions/properties etc, and it gets drawn as components (dynamic?) that can be edited later if needed. For now, how can I use a selected edge to use for the wall start and finish points?

4. Any other comments/tips/critique you can think of?

Code: Select all
## draw a stud wall                                                             
# Basics first - bottom plate, studs, top plate
# later look into windows, jamb studs etc

# retrieve the current active model and selection
model = Sketchup.active_model
entities = model.entities
selection = model.selection

# wall overall length and height (outside faces of end studs, bottom of bottom
# plate to top of top plate)
## need to make this use the selection length
wallLength = 2000.mm
wallHeight = 2400.mm

# bottom plates
btmPlLength = wallLength
btmPlDepth = 45.mm
btmPlWidth = 90.mm
btmPlNo = 1

# top plate dimensions
topPlLength = wallLength
topPlDepth = 45.mm
topPlWidth = 90.mm
topPlNo = 1

# stud dimensions
studDepth = 90.mm
studWidth = 45.mm
studLength = wallHeight-(btmPlNo*btmPlDepth)-(topPlNo*topPlDepth)

# stud alignment
studOffset = 0.mm
studSpacingMax = 450.mm

# find the selected edge

# create bottom plate and make a component
btmPlCorners = []
btmPlCorners[0] = [0.mm,0.mm,0.mm]
btmPlCorners[1] = [0.mm,0.mm,btmPlDepth]
btmPlCorners[2] = [btmPlWidth,0.mm,btmPlDepth]
btmPlCorners[3] = [btmPlWidth,0.mm,0.mm]
btmPlSection = entities.add_face btmPlCorners
btmPlSection.pushpull wallLength

# create stud component
studCorners = []
studCorners[0] = [0.mm,0.mm,btmPlDepth*btmPlNo]
studCorners[1] = [0.mm,studWidth,btmPlDepth*btmPlNo]
studCorners[2] = [studDepth,studWidth,btmPlDepth*btmPlNo]
studCorners[3] = [studDepth,0.mm,btmPlDepth*btmPlNo]
studSection = entities.add_face studCorners
studSection.pushpull (wallHeight-btmPlDepth*btmPlNo-topPlDepth*topPlNo)

# copy array of studs

# create top plate face and push
topPlCorners = []
topPlCorners[0] = [0.mm,0.mm,wallHeight-topPlDepth*topPlNo]
topPlCorners[1] = [0.mm,0.mm,wallHeight-topPlDepth*topPlNo+topPlDepth]
topPlCorners[2] = [topPlWidth,0.mm,wallHeight-topPlDepth*topPlNo+topPlDepth]
topPlCorners[3] = [topPlWidth,0.mm,wallHeight-topPlDepth*topPlNo]
topPlSection = entities.add_face topPlCorners
topPlSection.pushpull wallLength
Please, register (free) to access all the attachments on the forums.
This is not my signature. I type it at the end of every message for quality control.
troypiggo
 
Posts: 58
Joined: Mon Jun 25, 2012 2:49 am
Location: Brisbane, AUSTRALIA
Name: troypiggo
Operating system: Windows
SketchUp version: 2013
License type: Pro
SketchUp use: engineering and mechanical design
Level of SketchUp: Beginner

Re: basics - creating components and pushpull direction

Postby troypiggo » Wed Jul 18, 2012 8:57 am

Just further to the above, thought I'd try to use selections to make components as you would with the mouse. For a single box (ie the bottom plate) there are 18 entities. I assume this is 12 edges and 6 faces. What's the easiest way to select all of those and make them a component?

And once that is a component and I add more entities (eg the stud), what's the best way to distinguish the new entities from the ones in that first component to make a new one?

Am I barking up the wrong tree here?
This is not my signature. I type it at the end of every message for quality control.
troypiggo
 
Posts: 58
Joined: Mon Jun 25, 2012 2:49 am
Location: Brisbane, AUSTRALIA
Name: troypiggo
Operating system: Windows
SketchUp version: 2013
License type: Pro
SketchUp use: engineering and mechanical design
Level of SketchUp: Beginner

Re: basics - creating components and pushpull direction

Postby TIG » Wed Jul 18, 2012 9:30 am

When a flat face is made on the ground 'manually' it always faces down, irrespective of the direction its edges were added to the model. However, when z!=0 the order of the creation of its edges affects a flat face.normal...
It's the same doing it in code.
If you make a flat face at z=0 it will always have face.normal as [0,0,-1].
The direction [clockwise/counter-clockwise] of the edges will affect the flat face-normal otherwise.

When you pushpull in code the distance is always in the direction of the face.normal.
Using a -distance makes the extrusion in the other direction.
So what your code can do is check a flat face.normal and if face.normal.z<0 you know it's facing down or >0 it's facing up, or ==0 it's vertical... and you can adjust the distance to be +ve/-ve to suit...

Incidentally another way to make rectangular timber plates, studs etc is to make a 1" cube component [defn], then add it using inst=entities.add_instance(defn, tr) where 'tr' is the point in 3d that it'll be inserted - tr=Geom::Transformation.new(point) - and then use another transformation ts=Geom::Transformation.scaling(point, x, y, z); inst.transform!(ts)
Where x/y/z are the three dimensions of the piece of timber.
That way you have a series of correctly sized pieces from the one original...
TIG
User avatar
TIG
Global Moderator
 
Posts: 14310
Joined: Mon Nov 12, 2007 7:24 pm
Location: Northumbria UK
Name: TIG
Operating system: Windows
SketchUp version: 2013
License type: Pro
SketchUp use: architecture
Level of SketchUp: Advanced

Re: basics - creating components and pushpull direction

Postby troypiggo » Wed Jul 18, 2012 11:51 am

Thanks TIG! That has certainly set me off on the right track. I like the unit cube idea. Have implemented that.
This is not my signature. I type it at the end of every message for quality control.
troypiggo
 
Posts: 58
Joined: Mon Jun 25, 2012 2:49 am
Location: Brisbane, AUSTRALIA
Name: troypiggo
Operating system: Windows
SketchUp version: 2013
License type: Pro
SketchUp use: engineering and mechanical design
Level of SketchUp: Beginner

Re: basics - creating components and pushpull direction

Postby troypiggo » Mon Jul 23, 2012 8:35 am

Still having some trouble, sorry. I have completely rearranged the way I started out to (try to) make use of classes, modules, methods etc. Seem to have gone backwards.

My intention is to have a 1x1x1 "unit_block" component, then when I want to draw a new piece of timber, do as TIG suggested and transform it accordingly. Timber is going to be a class and it will create the block of appropriately sized timber, then BottomPlate is a subclass of it and will also handle orientations and positions in the wall.

Here's where I'm at:

Code: Select all
Class Timber

  # Timber properties:
  attr_accessor :depth, :width, :length

  def initialize(depth, width, length)
    @depth = depth
    @width = width
    @length = length
  end # initialize

  def draw
   
    model = Sketchup.active_model
    ents = model.entities
    def_list = model.definitions
   
    unit_block = def_list.add "unit_block"
    unit_block.description = "This is a 1x1x1 block to use as a building block"
    def_ents = unit_block.entities
    base = def_ents.add_face [0,0,0], [0,1,0], [1,1,0], [1,0,0]
    base.reverse! if base.normal.z < 0
    base.pushpull 1

    inst = ents.add_instance unit_block, [0, 0, 0]                             
 
    ts = Geom::Transformation.scaling(@depth,@width,@length)
    timber = inst.transform!(ts)

  end # draw

end # class Timber


I can't for the life of me see where this is wrong. I think I can't see the forest for the trees.

It's giving errors and not drawing an appropriately sized piece of timber when I call

Code: Select all
t.new 1, 2, 3


or

Code: Select all
t.draw


Sorry for the noob questions.
This is not my signature. I type it at the end of every message for quality control.
troypiggo
 
Posts: 58
Joined: Mon Jun 25, 2012 2:49 am
Location: Brisbane, AUSTRALIA
Name: troypiggo
Operating system: Windows
SketchUp version: 2013
License type: Pro
SketchUp use: engineering and mechanical design
Level of SketchUp: Beginner

Re: basics - creating components and pushpull direction

Postby TIG » Mon Jul 23, 2012 10:00 am

The 'draw' method is special method used by the Tool class to draw temporary graphics - rubber-banding lines etc - it is automatically invoked if the script is launched as a tool - it expects 'view' as an argument - see the Tool class API...
You need to make your def called named perhaps 'make_cube()', not 'draw'.
It will do nothing unless you 'call' it with Timber.new(1,2,3).
So for example in the initialize() end the code with self.make_cube()

Next...
Every time you run your [fixed] script in the same Model it will add a new cube component definition... incrementing its name from 'unit_block' to 'unit_block#1' etc, you probably don't want that.
So to make it once if it doesn't exist use...
unit_block=def_list.add("unit_block") unless unit_block=def_list["unit_block"]
This makes a reference to one if it exists, otherwise it adds it too...

There are several ways of 'scaling' - see the Transformation API...
Your current transformation scales about [0,0,0] which might be what you expect, but you can also specify the anchor-point and limit scaling to certain axes etc...
TIG
User avatar
TIG
Global Moderator
 
Posts: 14310
Joined: Mon Nov 12, 2007 7:24 pm
Location: Northumbria UK
Name: TIG
Operating system: Windows
SketchUp version: 2013
License type: Pro
SketchUp use: architecture
Level of SketchUp: Advanced

Re: basics - creating components and pushpull direction

Postby troypiggo » Mon Jul 23, 2012 1:32 pm

Thanks TIG. It works the first time I run it, but the second time I get the error:

> sw = StudWall.new
Error: #<TypeError: /Library/Application Support/Google SketchUp 8/SketchUp/Plugins/set.rb:58:in `add_instance': reference to deleted ComponentDefinition>
/Library/Application Support/Google SketchUp 8/SketchUp/Plugins/set.rb:58
/Library/Application Support/Google SketchUp 8/SketchUp/Plugins/set.rb:58:in `initialize'
/Library/Application Support/Google SketchUp 8/SketchUp/Plugins/set.rb:102:in `new'
/Library/Application Support/Google SketchUp 8/SketchUp/Plugins/set.rb:102:in `initialize'
(eval):58:in `new'
(eval):58



Code: Select all
class Timber                                                                   

  # Timber properties:
  attr_accessor :depth, :width, :length

  def initialize(depth, width, length)

    @depth = depth
    @width = width
    @length = length

    model = Sketchup.active_model
    ents = model.entities
    def_list = model.definitions
   
    unit_block = def_list.add "unit_block" unless \
      unit_block = def_list["unit_block"]
    unit_block.description = "This is a 1x1x1 block to use as a building block"
    def_ents = unit_block.entities
    base = def_ents.add_face [0,0,0], [0,1,0], [1,1,0], [1,0,0]
    base.reverse! if base.normal.z < 0
    base.pushpull 1

    inst = ents.add_instance unit_block, [0, 0, 0]
    ts = Geom::Transformation.scaling(@length,@width,@depth)
    block = inst.transform!(ts)

  end # initialize

end # class Timber

class StudWall

  def initialize                                                               

    # input the wall dimensions
    prompts = [ "Wall Height", "Wall Length", \
                "Btm Pl Depth", "Btm Pl Width", \
                "Stud Depth", "Stud Width", "Stud Max Spacing", \
                "Top Pl Depth", "Top Pl Width" \
              ]
    defaults = [ "2400", "1000", \
                 "45", "90", \
                 "90", "45", "600", \
                 "45", "90" \
               ]
    results = inputbox prompts, defaults, "Stud Wall Properties"

    # assign the input to variables
    wH = results[0].to_f.mm; wL = results[1].to_f.mm
    bPD = results[2].to_f.mm; bPW = results[3].to_f.mm
    sD = results[4].to_f.mm; sW = results[5].to_f.mm
      sMxSp = results[6].to_f.mm
    tPD = results[6].to_f.mm; tPW = results[7].to_f.mm

    bPL = wL; tPL = wL
    bPNo = 1; tPNo = 1

    sL = wH-(bPNo*bPD)-(tPNo*tPD)

    # create bottom plate

    btmPl = Timber.new (bPD,bPW,bPL)

    # create single stud
#    pt = Geom::Point3d.new 0,0,bPD
#    tr = Geom::Transformation.new pt
#    ts = Geom::Transformation.scaling(pt,sD,sW,sL)

#    stud = Timber.new (sD,sW,sL)

    # duplicate studs

    # insert nogging

    # create top plate
#    pt = Geom::Point3d.new 0,0,bPD+sL

    # duplicate studs

    # insert nogging

    # create top plate
#    pt = Geom::Point3d.new 0,0,bPD+sL
#    tr = Geom::Transformation.new pt
#    ts = Geom::Transformation.scaling(pt,tPW,tPL,tPD)
#    tP = entities.add_instance unit_cube, tr
#    tP.transform!(ts)

  end # initialize
   
end # class StudWall
This is not my signature. I type it at the end of every message for quality control.
troypiggo
 
Posts: 58
Joined: Mon Jun 25, 2012 2:49 am
Location: Brisbane, AUSTRALIA
Name: troypiggo
Operating system: Windows
SketchUp version: 2013
License type: Pro
SketchUp use: engineering and mechanical design
Level of SketchUp: Beginner

Re: basics - creating components and pushpull direction

Postby TIG » Mon Jul 23, 2012 1:54 pm

Getting there...

When you make a new definition add geometry to it immediately.
Empty definitions/groups don't survive in code...

Try something like:
Code: Select all
unless unit_block=def_list["unit_block"]
  unit_block=def_list.add("unit_block")
  ### add geometry to unit_block.entities
  ### add description to unit_block.description
  ### etc
end
### now add instance, knowing the definition exists and has geometry
which might be clearer?
You don't need to add geometry to the component if it already exists !

Another tip - use
Timber.new(bPD,bPW,bPL)
not
Timber.new (bPD,bPW,bPL)
don't leaves a space in front of the arguments' ()
TIG
User avatar
TIG
Global Moderator
 
Posts: 14310
Joined: Mon Nov 12, 2007 7:24 pm
Location: Northumbria UK
Name: TIG
Operating system: Windows
SketchUp version: 2013
License type: Pro
SketchUp use: architecture
Level of SketchUp: Advanced

SketchUcation One-Liner Adverts

by Ad Machine » 5 minutes ago

Vertex Tools for SketchUp. Take control over each vertex with this vertex editor for SketchUp.

Premium Members get 20% discount!

Ad Machine
Robot
 
Posts: 2012


Return to Developers' Forum

Who is online

Users browsing this forum: g_wilson, KevOrr, MSN Bot, OSN58, Salandora, slbaumgartner, Whaat and 4 guests