View.draw examples using GL_LINES for multiple lines at a time

In one tool I made I’m doing something like this:

def onMouseMove(flags, x, y, view)
    @ip.pick(view, x, y)
    if @ip.valid?
        @ipx, @ipy = x,y

def draw(view)
    offset_x = 10
    offset_y = 10
    pts = []
    pts << [@ipx,@ipy + offset_y]
    pts << [@ipx+ offset_x,@ipy + offset_y]
    pts << [@ipx+ offset_x,@ipy]
    pts << [@ipx,@ipy]
    view.draw2d GL_QUADS, pts

Its some lines I copied from a more complex tool so I haven’t tested these actual lines in this order. It should work though.

Edit2 - note: this code doesn’t draw anything in 3d. It draws a rectangle perpendicular to the screen and attached to the mouse.

My related question: How using ruby could I create a tool that gives real time feedback similar to the native SU Move tool? With that tool, for example, a selected group and all its drawing elements (including materials and even shadows) move as you move the cursor.

Implemented in Ruby, the performance of such a tool would probably be unacceptable.

Perhaps in many cases.
But I can’t even try because there don’t seem to be API methods to do it.

The only appropriate method in such a Tool would probably be the ‘move’ method. Performance aside, there is no reason you couldn’t have an instance follow the mouse using ‘move’.

The only I’ve tried this in the past, using the API call:


It cannot easily be used inside a tool, because it changes the active tool (so your tool will be deactivated.)

See this thread where you should have posted your question, instead of hijacking this topic:

Thank you all for your response, I am making progress.

In the end what i am trying to achieve is an array of points relative to @pt1 (Inputpoint1) and the same array of points relative to @pt2(location of cursor before 2nd click)

but i need the array of points to stay on a plane perpendicular to the vector, that @pt1 and @pt2 create, as i am moving the cursor to determine the direction i want to draw the geometry.

I have a tool that is working really well with creating the geometry, i am just trying to spice it up with the temporary graphical outline that view.draw method enables us to do.

So far profile builder is the only extension i have seen apply what i am trying to accomplish. here is a screenshot of the tool in use.

@bckwdsmn: In a prototype tool I did something like you want to achieve here. In short:

  1. make an array of the edges of the geometry you want to draw. In my tool the source was a component and I just iterated though all its edges and put them into an array.

  2. calculate the normal / detect the plane you want to draw on. Is Z always up or do you want to draw on angular faces as well?

  3. calculate the transformation. I used Geom::Transformation.axes because the drawing plane could be everything. You need to calculate a vector from pt1 to pt2. You need the plane / normal. With the vector and the plane/normal you can calculate the rest.

  4. apply the transformation on the vertices of each edge (from 1) and put the resulting points into a point array. I iterated through the edges and for each edge I iterated though its vertices and for each position of a vertex I applied the transformation (point 3) and put the result into the point array,

  5. use the point array (point 4) in the view.draw(GL_LINES, points)

I hope this helps.

I’m not interested in recreating the move tool, I was just using it as an example of feedback that would include materials and therefore give some solidity to an otherwise wireframe appearance.
So let me ask again: For the problem posed here by bckwdsmn, how can faces (with materials) be included in the kind of feedback he desires as the position of the cursor changes to stretch the proposed object?

Barry, he never asked about materials or faces which are not supported for view drawing within a tool.

I know he didn’t. I was asking,as I said, “a related question”.
So now I finally know the answer.
Has it ever been suggested? It would seem to me to have great benefits.

I’m getting so close! i have all the lines working and drawing right. i must not understand the method Geom::Transformation.axes because no matter how many times i try to apply the transformation to each point. the drawing goes all over the place.

it seems to work ‘best’ at the model ORIGIN, (still not working right) but once my first input point is off the origin it draws the shape outline a good distance away from my cursor.

But without attempting to apply the transformation to each point it works pretty well. other than they all stay on the XZ plane.

is there anyone who can elaborate on the Transformation.axes method?

here is basically what i’m working with to get a 10 x 10 square. i can not seem to figure out how to apply the right transformation to each array of points to keep them on the plane perpendicular to the vector created by the 1st input point and the cursor location

def draw_geometry(pt1, pt2)
  vec = pt2 - pt1
  plane = [pt1, vec]

  trans1 = Geom::Transformation.axes pt1, vec.axes[0], vec.axes[1], vec.axes[1] #set the transformation origin at the 1st input point location
  trans2 = Geom::Transformation.axes pt2, vec2.axes[0], vec2.axes[1], vec.axes[1] #set the transformation origin at 2nd input location

  ip1points = [ #points in reference to 1st input point
    a1 =[0] + 5, pt1[1], pt1[2]),
    a2 =[0] + 5, pt1[1], pt1[2] + 10),
    a3 =[0] - 5, pt1[1], pt1[2] + 10),
    a4 =[0] - 5, pt1[1], pt1[2])

  ip2points = [ #points in reference to 2nd inputpoint
    b1 =[0] + 5, pt2[1], pt2[2]),
    b2 =[0] + 5, pt2[1], pt2[2] + 10),
    b3 =[0] - 5, pt2[1], pt2[2] + 10),
    b4 =[0] - 5, pt2[1], pt2[2])

  ip1points.each {|p| p.transform! trans1} #apply the transformation to the 1st set of points
  ip2points.each {|p| p.transform! trans2} #apply the transformation to the 2nd set of points

  all_points =

  all_points.push pt1, pt2, a1, a2, a2, a3, a3, a4, a4, a1, b1, b2, b2, b3, b3, b4, b4, b1 #add the input points and both ends outline points in the right sequence

  view.line_width = 1
  view.draw(GL_LINES, all_points)

Yes i want to draw on angular faces as well.and i’m getting there, i dont have a background much in mathematics so matrices and transformations have seemed to be one of the bigger hurdles for me to grasp. but i’m learning![quote=“maxB, post:19, topic:31599”]
apply the transformation on the vertices of each edge (from 1) and put the resulting points into a point array. I iterated through the edges and for each edge I iterated though its vertices and for each position of a vertex I applied the transformation (point 3) and put the result into the point array,

How are you applying the transformation to each vertex? i’m not asking how to iterate through them, but properly applying them. I must be misunderstanding the transformation to each. i suspect its with the 3 vectors that the method takes as arguments.

I see several problems in your test code. I made a small example myself. Its more easy if you have the complete code. Have a look at it and it should help you changing your code.

Note: I’m just a amateur coder. Proper educated coders might/will have some suggestions for adjustment.
Note2: Its just some rough code. Lots of checks need to be put into it to function well without any warnings (for instance: detect length of @vx when @ip1 and @ip2 are overlapping, etc)

Save the code to a ruby file and find it in your extensions named Ghost. It should look like in the pic.

####Ghost example
require 'sketchup.rb'
module MB
class MB::Ghost
    def initialize
        @vx = 1,0,0
        @vy = 0,1,0
        @vz = 0,0,1        
        @picked_points = 0
        @ip =
        @ip1 =
        @ip2 =
        @pts_arr = [[0,0,0],[10,0,0],[10,10,0],[0,10,0],[0,0,10],[10,0,10],[10,10,10],[0,10,10],[0,0,0],[0,10,0],[0,10,10],[0,0,10]]
    def onMouseMove(flags, x, y, view)
        case @picked_points
        when 0
            @ip.pick(view, x, y)
            if @ip.valid? && @ip != @ip1
        when 1
            @ip.pick(view, x, y, @ip1)
            if @ip.valid? && @ip != @ip2
        when 2
            @ip.pick(view, x, y, @ip2)
        if @picked_points > 0
            @vx = @ip1.position.vector_to @ip2.position
            @vy = @vx.axes[0]
            @vz = @vx.axes[1]
        @trans = Geom::Transformation.axes @ip1.position, @vx, @vy, @vz

    def onLButtonDown(flags, x, y, view)        
    case @picked_points
        when 0
                @picked_points = 1
        when 1
                @picked_points = 2
    def draw(view)
        pts =[]
        @pts_arr.each{|p| pts << p.transform(@trans)}
        view.drawing_color = "orange"
        view.line_width = 2
end #class

unless file_loaded?( __FILE__ )
    m = 'Extensions' )

file_loaded( __FILE__ )
end #module

Any progress on this one?

I made a quick translation of the line tool with the code of maxB. Just to see of you can make a followme from a simple box.

But when you use it you only see the orange lines at ip1.position and it rotates with the mouse. But how can you let a simple box follow the line from ip1 to ip2. Thats the part i can’t seem to figure out.

Test line.rb (5.9 KB)

Haven’t tested your code but my code above does exactly what you want. One corner is at ip1, the second is at ip2. One edge of the box is on that line.
Maybe you’re asking: ‘how can you attach a simple box to the mouse to have it follow you everywhere with a fixed orientation?’ My code already does that too when you just started it.

Maybe you can clarify?

Yes u tried your code and it greates the box. But then the box shape must follow the line untill the second point, like profile builder does. I think it’s the same thing bckwdsmn is looking for.

Still not clear. what would following the line from p1 to p2 do the box? You mean stretch the box?

If so; you have to dynamically adjust the points in the pts_array OR apply a transformation-scale as well to @trans.

I’m very short on time at the moment so can’t help you now adjusting the code. With these suggestions though, you hopefully know where to look further.

Oke clear,

Going to look for it but last question. How can you apply a transformation scale to @trans

When you do that i get the error: Error: #<ArgumentError: Cannot convert argument to Sketchup::Point3d


You can multiply transformations. So if you have a scaling transformation @ts as well (see below) you could apply that in my code above by doing


Without proper context it’s very hard to find out why you have that error. For instance this works fine:

pt = [100,200,300]
@ts = Geom::Transformation.scaling 10