sketchucation logo sketchucation
    • Login
    ℹ️ Licensed Extensions | FredoBatch, ElevationProfile, FredoSketch, LayOps, MatSim and Pic2Shape will require license from Sept 1st More Info

    Request for help in developing a new Tool

    Scheduled Pinned Locked Moved Plugins
    12 Posts 4 Posters 571 Views 4 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • J Offline
      johnwmcc
      last edited by

      Many thanks for responding.

      The Ruby API docs say there should be two parameters to the view.draw_text method - point and text:
      point: A Point3d object.
      text: The text string to draw.

      Unfortunately, your suggestion doesn't work, though I can see why it should.

      Re-read the API docs for view.draw_text. Finally spotted that it says:

      View.draw_text
      This method is used to draw text on the screen.
      This method is usually invoked within the draw method of a tool.

      In my previous almost-working tool, I had the code in both places - the onMouseMove, AND in the draw_geometry method. When I put it in the draw method here, and drawgets called, it works. DOH!

      (Note to self: RTFM more carefully!)

      1 Reply Last reply Reply Quote 0
      • D Offline
        driven
        last edited by

        @johnwmcc said:

        ...This method is usually invoked within the draw method of a tool.

        It should say This method is ONLY WORKS when invoked within the draw method of a tool.

        I have many a doh! moments with it...

        john

        learn from the mistakes of others, you may not live long enough to make them all yourself...

        1 Reply Last reply Reply Quote 0
        • J Offline
          johnwmcc
          last edited by

          I'm making progress on this, but I've run into another question.

          At one point, I need to find the angle between a vector in the X-Y (red/green) plane and the X_AXIS.

          I calculate

          
          # Calculate a vector (vec3) which is the projection of a face.normal onto the red/green plane
             vec3 = Geom;;Vector3d.new [face.normal.x, face.normal.y, 0]
             rotate3 = X_AXIS.angle_between vec3 
          
          

          Perhaps naively, I had expected the value of rotate3 to change sign if the direction of vec3 is rotated past the X_AXIS from (say) [1,-1,0] (-45 degrees) through [1,0,0] (0 degrees) to [1,1,0] +45 degrees.

          But it doesn't. rotate 3 is always positive.

          Is this because in the general case, the angle between two arbitrary vectors doesn't have a 'sense of direction'?

          So do I have to distinguish cases where face.normal.y may be positive or negative?

          Doing that with an IF statement works.

          But is there a more elegant way of calculating this angle, WITH a sign attached?

          1 Reply Last reply Reply Quote 0
          • sdmitchS Offline
            sdmitch
            last edited by

            @johnwmcc said:

            I'm making progress on this, but I've run into another question.

            At one point, I need to find the angle between a vector in the X-Y (red/green) plane and the X_AXIS.

            I calculate

            
            > # Calculate a vector (vec3) which is the projection of a face.normal onto the red/green plane
            >    vec3 = Geom;;Vector3d.new [face.normal.x, face.normal.y, 0]
            >    rotate3 = X_AXIS.angle_between vec3 
            > 
            

            Perhaps naively, I had expected the value of rotate3 to change sign if the direction of vec3 is rotated past the X_AXIS from (say) [1,-1,0] (-45 degrees) through [1,0,0] (0 degrees) to [1,1,0] +45 degrees.
            But it doesn't. rotate 3 is always positive.

            the angle will always be positive and between 0 and 180 degrees

            Is this because in the general case, the angle between two arbitrary vectors doesn't have a 'sense of direction'?

            So do I have to distinguish cases where face.normal.y may be positive or negative?
            Yes
            Doing that with an IF statement works.

            But is there a more elegant way of calculating this angle, WITH a sign attached?
            No I don't think so.

            Nothing is worthless, it can always be used as a bad example.

            http://sdmitch.blogspot.com/

            1 Reply Last reply Reply Quote 0
            • TIGT Offline
              TIG Moderator
              last edited by

              Use vectorC = vectorA.cross(vectorB)
              Substituting the vec3 [the 'flat-vector' you've just made] and the X_AXIS for vectorA & vectorB as appropriate***.
              if vectorC == face.normal then the angle is positive; if it is not - i.e. it's ==face.normal.reverse then the angle is negative. I think you should just get a +/-ve Z value difference ?

              ***The order you substitute the two vectors in the 'cross' affects the resultant vectorC...
              Do some tests to work out which way is which...

              TIG

              1 Reply Last reply Reply Quote 0
              • J Offline
                johnwmcc
                last edited by

                Thanks again, TIG.

                1 Reply Last reply Reply Quote 0
                • J Offline
                  johnwmcc
                  last edited by

                  I thought I'd just got to a working version of this tool, when I discovered a bug in my code that I don't understand, and wonder if anyone can help me figure it out.

                  I have drawn (using my Draw Framing tool) a component representing a rectangular piece of wood, at an arbitrary angle (though it can also happen at orthogonal angles).

                  I pick a point on its face from which to start drawing another component, but I find that the reported face.normal vector is along the green axis, not normal to the face.

                  The image may help to visualize it. The magenta rectangle is generated by the draw_geometry method of my tool, which also draws the face normal along what will become the @long_axis of the about-to-be-created component.

                  Shows calculated face.normal visibly NOT normal to the top face of the component

                  But as you can see in the drawing, instead of being normal to the face, the @long_axis is parallel to the green axis. (By the way, the 3x2 cursor text is the nominal size in inches of the cross section of the component about to be drawn, in case you were wondering.)

                  The code which finds the face normal is derived from the sample ruby CLineTool:

                  
                  @ip1.pick view, x, y
                  if( @ip1.valid? )
                  ... other code...
                  ## Detect if pick point is on a face, and if so, orient long axis normal to it
                  #   unless axis is locked
                  if @ip.face 
                     f = @ip.face
                     puts  "Face picked; normal is \n"
                     puts f.normal.inspect
                     if @@axis_lock == NO_LOCK # axis not locked
                       @long_axis = f.normal
                       puts "@long_axis = " + @long_axis.inspect
                  
                  

                  This outputs in the Ruby console :

                  
                  Face picked; normal is 
                  Vector3d(0, 1, 0)
                  @long_axis = Vector3d(0, 1, 0)
                  
                  

                  The code which draws the feedback geometry is:

                  
                  # Display long axis as visual feedback
                    view.line_width = 2; view.line_stipple = ""
                    view.set_color_from_line(pt1 - @long_axis, pt1 + @long_axis)
                    view.draw_line(@first_pick.position, @first_pick.position + @long_axis) 
                    ...
                    view.drawing_color = "magenta" 
                    view.draw_polyline(@profile_points)
                  
                  

                  I find that if I open the component for editing, and copy and paste its top face into the World coordinate system, the face.normal IS normal to this face, which is in the red-blue plane, not at the angle it appears as the top surface of the component.

                  I'm sure this is because I've originally drawn the far end face of the visible component in the r-g plane (as @profile_points0, which got transformed into @profile_points in the feedback view.draw.polyline above), then did the same transforms on the component face -- rotated it about two different axes and translated it -- then push-pulled it along (its) long_axis to generate the component shown.

                  Yet (as you can see from the blue highlighted bounding box) the previous component axes are in line with its faces.

                  In case it helps, I also attach the complete tool draw_framing.rb file.

                  Any clues as to how to fix this would be most welcome. Until I discovered this 'bug' in my code, I thought I was nearing v1.0 of my code!

                  So how do I reset the axes of the original face and the component which it becomes, to get a component drawn whose faces AREN'T weirdly distorted internally so as to throw off the apparent face.normal?

                  I found (before I recoded it this way) that if I first made a group, then a component instance, it didn't have this problem, but its component axes were along world axes, not tightly around the shape of a non-orthogonal component. That is easy to fix manually with a Change Axes command, but there isn't an API function to do the same, afaik.

                  If anyone knows how to do that, I could revert to that method of creating the component instance.

                  For example, would it help to explode the component in code, then re-group it and make component?

                  Or can anyone suggest an alternative approach altogether?

                  Thanks in advance for any advice I could follow, to work round this.


                  Code that generates this odd component

                  1 Reply Last reply Reply Quote 0
                  • D Offline
                    driven
                    last edited by

                    can you utilise

                    face.bounds.center.normal
                    

                    where face is the 'new' face???

                    thinking out loud...
                    john

                    learn from the mistakes of others, you may not live long enough to make them all yourself...

                    1 Reply Last reply Reply Quote 0
                    • J Offline
                      johnwmcc
                      last edited by

                      Thanks for the suggestion. Unfortunately, it reports just the same normal as face.normal - off at an angle from the face, but along one axis to which the face is NOT normal geometrically!

                      I shall look again at the sequence of inserting and transforming the face into the component definition - I'm now pretty sure that the problem lies in the create_geometry method, where I draw the face, insert it into a component definition, then transform it to the required position. Doing that is somehow seriously distorting where the component thinks its face normals point - not normal to the physical face!

                      1 Reply Last reply Reply Quote 0
                      • sdmitchS Offline
                        sdmitch
                        last edited by

                        @johnwmcc said:

                        Thanks for the suggestion. Unfortunately, it reports just the same normal as face.normal - off at an angle from the face, but along one axis to which the face is NOT normal geometrically!

                        I shall look again at the sequence of inserting and transforming the face into the component definition - I'm now pretty sure that the problem lies in the create_geometry method, where I draw the face, insert it into a component definition, then transform it to the required position. Doing that is somehow seriously distorting where the component thinks its face normals point - not normal to the physical face!

                        If you are picking a face in a component or group, the normal will need to be transformed.

                        @ip1.pick view, x, y
                        if( @ip1.valid? )
                        ... other code...
                        ## Detect if pick point is on a face, and if so, orient long axis normal to it
                        #   unless axis is locked
                        if @ip.face 
                           f = @ip.face
                           puts  "Face picked; normal is \n"
                        #######
                           n = @ip.face.normal; t = @ip.transformation; n.transform! t
                        #######
                           puts f.normal.inspect; n.inspect
                           
                           if @@axis_lock == NO_LOCK # axis not locked
                             @long_axis = f.normal
                             puts "@long_axis = " + @long_axis.inspect
                        

                        Nothing is worthless, it can always be used as a bad example.

                        http://sdmitch.blogspot.com/

                        1 Reply Last reply Reply Quote 0
                        • 1 / 1
                        • First post
                          Last post
                        Buy SketchPlus
                        Buy SUbD
                        Buy WrapR
                        Buy eBook
                        Buy Modelur
                        Buy Vertex Tools
                        Buy SketchCuisine
                        Buy FormFonts

                        Advertisement