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


#1

Can anyone point me to examples, other than the API, for using the view.draw method to draw an outline of the geometry that will be created. It is simple enough to do a line from one point to another, but i’m looking to get it to work with a shape, from InputPoint1 to iInputPoint2.

so if i am going to draw an extruded triangle or square and my 2 Input Points determine the length and direction, i’m trying to learn how to dynamically show the outline of the shape as i am moving the mouse around to determine the 2nd InputPoint.

i’ve searched and searched through the documentation and forums and sketchucation, even tried studying source code of other extensions that sort of do this, but they all relate to drawing one line from A to B.

i imagine it might be pretty complex to do this, since the points would need to be constantly doing transformations on the plane perpendicular to the vector of InputPoint1 and InputPoint2 and relative to those points

  def draw(view)
    if( @ip1.valid? )
      if( @ip1.display? )
        @ip1.draw(view)
        @drawn = true
      end
      if( @ip2.valid? )
        points = [@ip1, @ip2]
        @ip2.draw(view) if( @ip2.display? )
        view.set_color_from_line(@ip1, @ip2)
        view.line_width = 5
        view.draw(GL_LINES, points)
        @drawn = true
      end
    end
  end

This is what i have so far with just creating the simple line, and the geometry is created after the 2nd click. so does anyone know of some more complex examples of the view.draw_lines method that i can study for doing shape outlines? any suggestions or direction would be very helpful, thanks


#2

FYI, (or any reader) the View.draw methods only work within a Ruby Tool class instance, when it is the active tool.

Yes,… the SketchUp Development Team’s Examples extension, has a file named “linetool.rb” which shows how to mimic the native LineTool, by creating a Ruby Tool class, and then at the bottom of the file, defining a subclass of that named (CylTool I think,) to override certain methods to create cylinders. The cylinder tool dynamically draws a circle on the viewport between the first and second clicks.

Again, yes,… many of the SketchUp Development Team’s extensions on their EW store page, are unscrambled (unencrypted) code examples.

…etc., see the SketchUp Development Team EW Store page for more example extensions.
(The exceptions are the small set of distributed extensions that come with SketchUp. Ie, Trimble Connect, Dynamic Components, Sandbox Tools, etc.)

The code repositories (for Community projects) are here: https://github.com/SketchUp


#3

I can offer some code that used to work in SU 2014, and which partially works in later versions.

See attached file. It may not run well, but at least it shows what (was) working code to partially emulate a pushpull operation on a rectangle using view.draw.

Search within the attached .rb file for view.draw - there are several examples.draw_framing_v0.7.2 pushpull draw working.rb.zip (13.1 KB)

Here’s a relevant extract

# -------------------------------------------------------------------------------
    when 2 # Cross-section drawn, waiting for drag or click to pushpull to length
      # @frame_length was defined in onMouseMove @state == 2
      # Define translation to move profile outline along @apparent_normal by @frame_length
      @vec6 = @first_pick.position.vector_to @first_pick.position.offset(@apparent_normal, @frame_length)
      ## Copy profile along @apparent_normal
      @tf6 = Geom::Transformation.translation(@vec6)

      @profile_points.each_index {|i| @profile_points4[i] = @profile_points[i].transform @tf6}
      
      view.line_width = 3
      view.drawing_color = "magenta" 
      view.draw_polyline(@profile_points)
      view.draw_polyline(@profile_points4)
      @profile_points.each_index {|i| view.draw_line(@profile_points[i], @profile_points4[i])}
      #view.draw_points @first_pick.position.offset(@apparent_normal, @frame_length), 8, 1, "magenta"
    end # case @state

#4

And here’s an installable rbz file of a slightly later version - try it.

jwm_draw_framing_v0.7.6.5.rbz (25.9 KB)

The plugin is one I have used, though not recently, to help me when drawing scenery based on standard (UK) softwood timber sizes.

After installation (at least in SU 2014) it will appear on the Draw menu as Timber Frame. With the tool active, R-click to select the timber size, then click the mouse L-button to choose the start point. Move mouse around the start point to choose relative orientation and axis, then click a second time to draw the cross-section. A pop up will appear asking you to name the component - change the name as you wish. Then drag to create a piece of ‘timber’ of the specified size, and length defined by a third mouse pick.

The bit that doesn’t work very well is moving the mouse round the first pick point to specify orientation.

But it does have a couple of examples of drawing simple shapes of more than one line in view.draw.

I wish I’d been able to get it to work better. May try again, after leaving it alone for a couple of years.


#5

Here’s an example from one of my unpublished plugins:

SB_diagonal_beam.rbz (14.0 KB)


#6

You’re almost there with your code snippet. The only thing to do is to add the coordinates of the other points of the shape you want to draw to the pointarray:

points = [@ip1, @ip2, p3, p4, p5, p6]


#7

Hi,

I’m also looking for this solution.

But if we go back to the simple line tool and you have a simple box that you want to draw as a polyline that follows the line.
How do you set that up:

	@pts = []
                    @pts[0] = [0, 0, 0]
                    @pts[1] = [0, 40.mm, 0]
                    @pts[2] = [0, 40.mm, 40.mm]
                    @pts[3] = [0, 0, 40.mm]
                        
                          view.line_width = 3
                          view.drawing_color = "magenta" 
                          view.draw_polyline(@pts)  

But the box don’t follow the line from ip1 to ip2


#8

Because you have no reference to @ip1 and @ip2 in your @pts array


#9

Thanks,

I know that but if i add an array like maxB said the box doens’t follow the line from ip1 to ip2?

Or i’m missing something :slight_smile:


#10

If you want to draw more than 1 line, you build a point array just like I said. These points though must be related to the cursor position IF you want the view.draw(GL_LINES, points) to draw something related to the cursor. So in your case, you would add the coordinates from your array to the @ip (current position of the cursor).

Note: view.draw_polyline(@pts) is something different. I have never used that one before so I can’t really say if its outcome is the same as view.draw(GL_LINES, points)


#11

Something like this:

                                point = Geom::Point3d.new(@ip1.position)                              
                          
                                po = []
                                po[0] = point +[0, 0, 0]
                                po[1] = point +[0, 40.mm, 0]
                                po[2] = point +[0, 40.mm, 40.mm]
                                po[3] = point +[0, 0, 40.mm]
                        
                          view.draw_polyline(po) 

You get the following result but is doens’t move over the line also not in the right direction.


#12

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
    end
    view.invalidate
end

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
end

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.


#13

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.


#14

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


#15

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


#16

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’.


#17

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

Sketchup::Model.html#place_component()

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:


#18

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.


#19

@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.


#20

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?