• Login
sketchucation logo sketchucation
  • Login
ℹ️ GoFundMe | Our friend Gus Robatto needs some help in a challenging time Learn More

Raytest Alternative?

Scheduled Pinned Locked Moved Developers' Forum
7 Posts 2 Posters 449 Views
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.
  • A Offline
    ArjunaMeridian
    last edited by 11 Oct 2011, 17:46

    I'm using code to iterate through a series of faces, taking each center point, and testing each individually using raytest to see if the face is "visible" to another far away test point, given the other geometry present in the model (ie, if the ray "hits" something else, it isn't visible).

    It works great EXCEPT that it is excruciatingly slow, especially when there are many faces and/or test points.

    Is there a better way?

    Here's a snippet:

    def self.test_points(face)
             center = face.bounds.center
             normal = face.normal
             counter = 1
             0.upto(test_points.length-1) {|s|
             ray = [center,test_points[s]]
             item = @model.raytest(ray,false)
             #puts item         
             if item == nil
                sv = center.vector_to test_points[s]
                an = normal.angle_between sv
                counter += Math.cos(an)
             end
    
    1 Reply Last reply Reply Quote 0
    • T Offline
      TIG Moderator
      last edited by 11 Oct 2011, 19:38

      I don't fully follow your code πŸ˜’
      You suddenly seem to recall the 'test_points' method from within itself to no affect ?
      Where does the 'test_points' come from that you use - it is used as an array BUT you also have a method with the same name that is passed a (face)... πŸ˜•
      If you are declaring an array of 'test_points' then name it '@test_points' and use that - because the reference is loss across methods without the @ !!
      You also seem to be passing points as vectors in the raytest πŸ˜• πŸ˜•
      And when the test fails incrementing a counter by an[gle] that unused elsewhere anyway πŸ˜• πŸ˜• πŸ˜•

      TIG

      1 Reply Last reply Reply Quote 0
      • A Offline
        ArjunaMeridian
        last edited by 11 Oct 2011, 20:00

        You're absolutely correct...I pulled the code out of context of a longer section of code, re-(mis-)labeled a few things, all in an effort to minimize the reading required by anyone attempting to help me out, since RAYTEST seems to be the crux of the problem (I think).

        In case you care to read my entire code, it is below, though I've added a big comment block with #RAYTEST SECTION# if you want to skip to that.

        The test point array is '@suns'

        Thank you for trying to help me

        module MC_sun_tools
           @model = Sketchup.active_model
           @ents = @model.entities
           @sel = @model.selection
        
        
        
           def MC_sun_tools.generate_suns
        
             
             # Initialize some variables
        
             tz = -5.0  
             altitude = 1000.m #We'll generate points 1km away
        
              @suns = [] # An array to hold our "suns"
        
              si = @model.shadow_info
        
              ct = si["ShadowTime"]   #the class of ct is Time
        
              yr = ct.year
              mon = 9 #ct.month
              day = ct.day
        
              # The points we add will be part of a new group
        
              #my_verts = @sel[0].vertices
        
              new_ent = @ents.add_group
              new_ent.name = "{mon}-{day}"
        
              0.upto(24*4-1) {|hour|
                 t = Time.local(yr, mon, day, hour/4, (hour.to_f/4 % 1)*60)
                 si['ShadowTime'] = t
                 v = si["SunDirection"]
                 v.length = altitude
                 pt = ORIGIN + v
                 new_ent.entities.add_cpoint(pt)
                 new_ent.entities.add_text(((hour/4-tz) % 24).to_i.to_s, pt)
                 @suns << pt #if pt.is_a? Sketchup;;Point3d
              }
          end
        
           def MC_sun_tools.get_faces
               my_faces = []
                  @sel.each {|e|
                     if e.is_a? Sketchup;;Face
                     my_faces << e
                  end
               }
               my_faces.each {|e|
                   MC_sun_tools.test_suns(e)
               }
               puts my_faces.length
           end
        ######################################################
        #########RAYTEST SECTION##############################
           
           def MC_sun_tools.test_suns(face)
              center = face.bounds.center
              normal = face.normal
              face.material= @color_hash[1]
              counter = 1
              0.upto(@suns.length-1) {|s|
                 ray = [center,@suns[s]]
                 item = @model.raytest(ray,false)
                 #puts item         
                 if item == nil
                    sun_vector = center.vector_to @suns[s]
                    an = normal.angle_between sun_vector
                    counter = counter + Math.cos(an)*0.8
                    #puts cos(an)     
                    #@ents.add_cline(center, @suns[s])
                    
                 end
                 
              }
              face.material = @color_hash[[counter.to_i, 25].min]
           end
        ########################################################
        
        @color_hash = [[0, 0, 180], 
        [0, 30, 180], 
        [0, 60, 180], 
        [0, 90, 180], 
        [0, 120, 180], 
        [0, 150, 180], 
        [0, 180, 180], 
        [0, 180, 150], 
        [0, 180, 120], 
        [0, 180, 90], 
        [0, 180, 60], 
        [0, 180, 30], 
        [0, 180, 0], 
        [30, 180, 0], 
        [60, 180, 0], 
        [90, 180, 0], 
        [120, 180, 0], 
        [150, 180, 0], 
        [180, 180, 0], 
        [180, 150, 0], 
        [180, 120, 0], 
        [180, 90, 0], 
        [180, 60, 0], 
        [180, 30, 0], 
        [180, 0, 0]] 
        
        end
        
        plug_menu = UI.menu("Plugins")
        plug_menu.add_item("Generate Suns") {MC_sun_tools.generate_suns}
        plug_menu.add_item("Test Suns") {MC_sun_tools.test_suns}
        plug_menu.add_item("Get Faces") {MC_sun_tools.get_faces}
        
        1 Reply Last reply Reply Quote 0
        • T Offline
          TIG Moderator
          last edited by 11 Oct 2011, 20:10

          Why do you mess with si["SunDirection"] ?
          Why not pass that as a vector to the @suns array...
          Messing on adding it to the ORIGIN etc just causes me confusion ?
          I deduce you are testing sun-angles across time and seeing if a face's center can see the sun...
          I don't think you need to make it quite so convoluted...

          TIG

          1 Reply Last reply Reply Quote 0
          • A Offline
            ArjunaMeridian
            last edited by 12 Oct 2011, 13:58

            You're right about what the code is attempting to do, and no doubt it needs to be cleaned up and modularized a bit. To answer your question: I call si["SunDirection"] when generating the @sun array because the Point3ds (generated from vectors about ORIGIN) will depend on the geolocation and date of the model. Hence, Colorado's suns will differ from London's.

            Regardless, the ShadowInfo calls within the sun array routine aren't the time constraint within the code-- RayTest seems to be the culprit. Given the profusion of rendering programs which are undoubtedly doing MANY more collision calculations, I'm wondering if there's an obvious, less computationally expensive substitute to calling RayTest.

            1 Reply Last reply Reply Quote 0
            • T Offline
              TIG Moderator
              last edited by 12 Oct 2011, 14:25

              It seems to work fast enough for me ?

              Also remember that the sun's vector is the same irrespective of where you 'place it' ?
              Setting it's length to 1km does nothing to it when you use it in the raytest - I realize you want it for the 'sun location...
              Adding it .to_a to the ORIGIN returns a point.

              A simple raytest is
              model.raytest([point,vector])
              So for any 'point' you pass to the raytest using the sun_direction vector [unaltered] will return 'nil' if it hits nothing or a two element array otherwise - which in your case you can just ignore.

              I assume your code should then 'color' faces depending on if their center fails the raytest and its angle towards the sun...

              The raytesting itself should be relatively quick - how many faces are you testing ?

              TIG

              1 Reply Last reply Reply Quote 0
              • A Offline
                ArjunaMeridian
                last edited by 12 Oct 2011, 15:16

                Well I hadn't thought of the sun vector that way, but that is great advice-- should certainly speed things up, a little at least.

                As for the number of faces...I'd like to take a surface and run it with arbitrary granularity; so, thousands. Running my code as it stands for 1000 faces takes on the order of 15 minutes to run.

                Making the change you suggested now...

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

                Advertisement