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

    Transforming an array of points

    Scheduled Pinned Locked Moved Developers' Forum
    27 Posts 7 Posters 531 Views 7 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.
    • jolranJ Offline
      jolran
      last edited by

      @unknownuser said:

      You probably already know this, but you can traverse the points this way:
      pt = mesh.point_at( index )
      You can then store your indexes in an array or hash and work with them instead.

      Yes I know, but In my case I desired an Array of Point-arrays(polygon) from mesh simply from Calling mesh.polygons. This still mean I'll have to recollect the Points from the returning indexes, unless I'm misstaken. Maybe one can chain methods I don't know.
      Havent tried that hard yet..

      @unknownuser said:

      If you're applying the same transform to all the points, generally you'd be better off both in performance and accuracy with changing the container entity's transform rather than changing the Points themselves.

      So there is a way to group Point3d objects ? Or are you referring to the Mesh.transform ?

      1 Reply Last reply Reply Quote 0
      • G Offline
        Garry K
        last edited by

        Tig,

        What I have are the points that describe the handrail profile (the face at the bottom of the picture). The picture is only for clarification. None of this is actually in the model at this time.

        I keep the points that are in the bottom face and apply a transformation that rotates and moves a copy of the original points. These points are then added into the PolygonMesh.

        In this case there are 53 points that describe the handrail profile (could be any profile).
        And there are going to be 39 filled in segments.

        Currently I am applying this transform to each point:

        t = Geom::Transformation.new( [ 0, 0, i * rise_per ] ) *
        Geom::Transformation.rotation( [0, 0, 0], Z_AXIS, ( i * deg ).degrees )

        profile.each { |val| mesh.add_point( val.transform( t ) ) }

        This example puts 2120 points into the mesh 40 * 53 = 2120

        I have tried adding the first profile into a second polygon mesh so that I can apply a bulk transform. It works - but the entire operation is much slower than just transforming one point at a time.

        All I am trying to do is see if there is a faster way than I am doing - or if this is "as good as it gets"

        Hopefully this is sufficient clarification.


        Handrail Profile

        1 Reply Last reply Reply Quote 0
        • Chris FullmerC Offline
          Chris Fullmer
          last edited by

          @tig said:

          The two entities transform methods will affect instances/groups, faces, edges and vertices, but NOT points.

          Wow, its beena while since I used those methods, apparently I had forgotten that. I guess I'm transforming vertices in my script then.

          Sorry for the bad advice 😳 😆

          Lately you've been tan, suspicious for the winter.
          All my Plugins I've written

          1 Reply Last reply Reply Quote 0
          • tt_suT Offline
            tt_su
            last edited by

            @garry k said:

            Currently I am applying this transform to each point:

            t = Geom::Transformation.new( [ 0, 0, i * rise_per ] ) *
            Geom::Transformation.rotation( [0, 0, 0], Z_AXIS, ( i * deg ).degrees )

            profile.each { |val| mesh.add_point( val.transform( t ) ) }

            What if you use PolygonMesh.transform! ?

            <span class="syntaxdefault"><br /></span><span class="syntaxcomment">#&nbsp;Use&nbsp;for&nbsp;in&nbsp;loop&nbsp;at&nbsp;that&nbsp;doesn't&nbsp;create&nbsp;new&nbsp;local&nbsp;object&nbsp;per&nbsp;iteration.<br />#&nbsp;Creating&nbsp;objects&nbsp;in&nbsp;Ruby&nbsp;is&nbsp;slow&nbsp;-&nbsp;so&nbsp;try&nbsp;to&nbsp;reuse&nbsp;them.<br /></span><span class="syntaxkeyword">for&nbsp;</span><span class="syntaxdefault">point&nbsp;in&nbsp;profile<br />&nbsp;&nbsp;mesh</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">add_point</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">point</span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault">end<br /><br />t&nbsp;</span><span class="syntaxkeyword">=&nbsp;</span><span class="syntaxdefault">Geom</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Transformation</span><span class="syntaxkeyword">.new(&nbsp;[&nbsp;</span><span class="syntaxdefault">0</span><span class="syntaxkeyword">,&nbsp;</span><span class="syntaxdefault">0</span><span class="syntaxkeyword">,&nbsp;</span><span class="syntaxdefault">i&nbsp;</span><span class="syntaxkeyword">*&nbsp;</span><span class="syntaxdefault">rise_per&nbsp;</span><span class="syntaxkeyword">]&nbsp;)&nbsp;*<br /></span><span class="syntaxdefault">Geom</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Transformation</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">rotation</span><span class="syntaxkeyword">(&nbsp;[</span><span class="syntaxdefault">0</span><span class="syntaxkeyword">,&nbsp;</span><span class="syntaxdefault">0</span><span class="syntaxkeyword">,&nbsp;</span><span class="syntaxdefault">0</span><span class="syntaxkeyword">],&nbsp;</span><span class="syntaxdefault">Z_AXIS</span><span class="syntaxkeyword">,&nbsp;(&nbsp;</span><span class="syntaxdefault">i&nbsp;</span><span class="syntaxkeyword">*&nbsp;</span><span class="syntaxdefault">deg&nbsp;</span><span class="syntaxkeyword">).</span><span class="syntaxdefault">degrees&nbsp;</span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault">mesh</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">transform</span><span class="syntaxkeyword">!(&nbsp;</span><span class="syntaxdefault">t&nbsp;</span><span class="syntaxkeyword">)<br />&nbsp;</span><span class="syntaxdefault"></span>
            

            Then you should be able to do bulk transformation of the points by doing iterative transformation for each profile step. I've never tested the performance for that - but generally the fewer operations the faster.

            1 Reply Last reply Reply Quote 0
            • G Offline
              Garry K
              last edited by

              I just tried your suggestion of using an incremental transform as opposed to a differential transform ( point by point from profile )

              I change my timing so that it avoids the start up code which is the same for both strategies and I also avoided the smoothing algorithm on the entity after fill_from_mesh.

              I performed the benchmarks 12 times for each strategy and threw out the highest and the lowest.

              This resulted in a 3% improvement using the incremental transform over the point by point transform.

              Incremental 0.1043
              0.129
              0.107
              0.106
              0.106
              0.106
              0.105
              0.104
              0.104
              0.104
              0.104
              0.097
              0.095

              Differential 0.1077
              0.131
              0.112
              0.111
              0.109
              0.109
              0.108
              0.108
              0.107
              0.106
              0.104
              0.103
              0.101

              I would still be in favor of the differential as the incremental will be prone to a slight fp (floating point) shift. It may not be noticeable with only 40 segments - but then neither is 3/1000 of a second!!

              I did change the "profile.each" to a "for pt in profile" and that hardly made a difference.

              So bottom line is that the bulk transform of points using a mesh is slightly faster - however it is more complex and most likely requires more memory. But it is certainly something to consider as a viable option in some circumstances!

              1 Reply Last reply Reply Quote 0
              • tt_suT Offline
                tt_su
                last edited by

                The data set you currently work with is probably so small that you won't gain that much. But I'd think as the data set increases you'd see bigger and bigger differences.

                1 Reply Last reply Reply Quote 0
                • G Offline
                  Garry K
                  last edited by

                  That is why I suggested it would be a viable option in some circumstances.

                  I think that we gain performance in the actual transform but may loose it accessing the points in the mesh.

                  If there was a bulk operation to move points from one mesh to another without invoking the built in check - then you would probably benefit even on a smaller data set.

                  1 Reply Last reply Reply Quote 0
                  • Dan RathbunD Offline
                    Dan Rathbun
                    last edited by

                    @jolran said:

                    So there is a way to group Point3d objects ?

                    Yes there is. Create a Geom::BoundingBox object and add points to it.

                    However I do not see a transform method that applies to bounding boxes.

                    😞

                    I'm not here much anymore.

                    1 Reply Last reply Reply Quote 0
                    • jolranJ Offline
                      jolran
                      last edited by

                      @unknownuser said:

                      Yes there is. Create a Geom::BoundingBox object and add points to it.
                      However I do not see a transform method that applies to bounding boxes

                      ☀ Forgot about that one. Will be useful, even if not in this case.

                      @unknownuser said:

                      I think that we gain performance in the actual transform but may loose it accessing the points in the mesh.

                      If polygonmesh.polygons returned arrays of Points that woulden't be the case.

                      Have you tried recollecting points to a new Array and Transform! them in place ?
                      Array.Dup does not work with Point3D objects 😞
                      As far as I know one have to recollect points into new Array. Comes with a timecost of course..

                      1 Reply Last reply Reply Quote 0
                      • jolranJ Offline
                        jolran
                        last edited by

                        Ok. Did some tests and it seams like Polygonmesh transform scales quite well.

                        Note this test may not be constructed optimaly, I'm still green. But still quite interesting to see how fast polygonMesh transforms many Points.
                        The test might provide different result if arrays are flattended, but I need to keep the polygon/Points hierarchy.

                        Edit: I saw that newlist actually don't keep the hierarchy So the result would probably be slower. Can't really Output the result in ruby consol 😉

                        # Square Polygon
                        pts = [
                          Geom;;Point3d.new(-5,-5,0),
                          Geom;;Point3d.new(5,-5,0),
                          Geom;;Point3d.new(5,5,0),
                          Geom;;Point3d.new(-5,5,0)
                        ]
                        
                        vec = [10,0,0]
                        tr = Geom;;Transformation.new( vec )
                        
                        # Create som polygons for testing..
                        polys = {}
                        vec2 = vec.clone
                        for i in 0...50
                          polys[i] = pts.collect{|pt| pt.offset(vec2) }
                          vec2.offset!([15,10,0])
                        end
                        
                        # Mesh
                        msh = Geom;;PolygonMesh.new
                        for k,v in polys
                          msh.add_polygon(v)
                        end
                        
                        # Array of points
                        polygonials = polys.values
                        puts "total nr Point3dObjects; #{polygonials.flatten.length}"
                        
                        #group = Sketchup.active_model.active_entities.add_group
                        #group.entities.fill_from_mesh(msh, true, 12)
                        
                        #Tests On My computer Gave;
                        #PolygonMesh Transforms; 0.03
                        #Array Transforms; 1.052
                        #Array Transforms And Collect; 2.335
                        
                        start = Time.now
                        10000.times {
                            msh.transform!(tr)
                        }
                        puts "PolygonMesh Transforms; #{Time.now - start}"
                        
                        
                        start = Time.now
                        10000.times {
                        for list in polygonials
                          for p in list do p.transform!(tr) end
                        end
                        }
                        puts "Array Transforms; #{Time.now - start}"
                        
                        start = Time.now
                        newlist = []
                        10000.times {
                        for list in polygonials
                          newlist << list.collect{|p| p.transform(tr) }
                        end
                        }
                        puts "Array Transforms And Collect; #{Time.now - start}"
                        
                        1 Reply Last reply Reply Quote 0
                        • G Offline
                          Garry K
                          last edited by

                          What about a benchmark for a hash?

                          1 Reply Last reply Reply Quote 0
                          • jolranJ Offline
                            jolran
                            last edited by

                            
                            start = Time.now
                            10000.times {
                            for key,val in polys
                              for p in val do p.transform!(tr) end
                            end
                            }
                            puts "Nested Hash Transforms; #{Time.now - start}" # => 1.274
                            
                            
                            

                            It is a Hash? If I don't nest the Hash the "polygon-Points" relation will be impossible to retrieve afterwards:
                            Hash = { 0 => [pt,pt,pt,pt] etc }

                            Do you mean 1 layer Hash structure { key => pointd3d etc } ?

                            There may off course be better structures for this, I'm all ears.

                            Edit: I tried running each test separately muting the other timers with following result:

                            PolygonMesh Transforms: 0.047
                            Nested Hash Transforms: 1.191
                            Array Transforms: 1.066
                            Array Transforms And Collect: 2.328

                            Maybe I'm confusing the matter... And I haven't outputed the resulting mesh(which would stall Sketchup) so there is a matter of knowing if the resulting Mesh is qualified as well.

                            1 Reply Last reply Reply Quote 0
                            • jolranJ Offline
                              jolran
                              last edited by

                              Ah you mean put result in Hash ?

                              start = Time.now
                              newHash = {}
                              10000.times {
                              for i in 0...polygonials.length
                                newHash[i] = polygonials[i].collect{|p| p.transform(tr) }
                              end
                              }
                              puts "HASH Transforms And Collect; #{Time.now - start}"
                              

                              =>2.381

                              1 Reply Last reply Reply Quote 0
                              • G Offline
                                Garry K
                                last edited by

                                You could render the mesh after the timers to maintain benchmark validity.

                                Have you tried traversing your polygons?
                                mesh.polygon_points_at( index )
                                Shouldn't this give you the same results as an outer_loop on a face?
                                The question I would have is although you can get the points for each polygon - Is there a way to tie in a reference to the faces in the model once you have rendered the mesh?
                                I would hope that the entities in the group immediately after a fill_from_mesh would be in mesh polygon index order. So there should be a 1 to 1 relationship.

                                I haven't played with hashes yet - so my question is probably confusing to you. Although I've programmed for many years and also played with CAD for many years I've only logged 3 or so months with Sketchup since I got serious about it (guess I caught the Sketchup virus).

                                1 Reply Last reply Reply Quote 0
                                • jolranJ Offline
                                  jolran
                                  last edited by

                                  @unknownuser said:

                                  You could render the mesh after the timers to maintain benchmark validity.

                                  Yeah, for those tests that edit in Place. Otherwise it would be too intense for Sketchup.

                                  @unknownuser said:

                                  The question I would have is although you can get the points for each polygon - Is there a way to tie in a reference to the faces in the model once you have rendered the mesh?

                                  I'm just moving Points in this code. I reckon you'd have to recollect faces afterwards
                                  and do some boolean tests. There's normal_at which could be used for ex.
                                  It all depends on (referring to your other question) if face order == polygon index order. I should test that as well unless someone else already knows..

                                  I'm pretty new to programming, so there can be lots of holes in the logic of my tests.
                                  But what better way to learn than trying to solve a problem, right?

                                  Hashes in Ruby are supposed to have much faster lookup than arrays. I think that's what Thomthom tried to point out earlier.

                                  1 Reply Last reply Reply Quote 0
                                  • tt_suT Offline
                                    tt_su
                                    last edited by

                                    @garry k said:

                                    I think that we gain performance in the actual transform but may loose it accessing the points in the mesh.

                                    Geom::PolygonMesh.points? http://www.sketchup.com/intl/en/developer/docs/ourdoc/polygonmesh.php#points

                                    1 Reply Last reply Reply Quote 0
                                    • G Offline
                                      Garry K
                                      last edited by

                                      Sorry - bad terminology. I was talking read and write access.
                                      the only write access we have is mesh.add_point.
                                      I'm still thinking as a C / C++ programmer.

                                      1 Reply Last reply Reply Quote 0
                                      • tt_suT Offline
                                        tt_su
                                        last edited by

                                        @garry k said:

                                        Sorry - bad terminology. I was talking read and write access.
                                        the only write access we have is mesh.add_point.

                                        PolygonMesh.set_point
                                        http://www.sketchup.com/intl/en/developer/docs/ourdoc/polygonmesh.php#set_point

                                        1 Reply Last reply Reply Quote 0
                                        • jolranJ Offline
                                          jolran
                                          last edited by

                                          Yet Another test 👊

                                          Don't know how reliable this test is but it appears face get appended in the same order as indexed in Polygonmesh. But Polygonmesh Count indexes starting at 1.

                                          Edit: Updated for adding c_point in polygonmesh index as well. But wonder how hidden edges affect the Index ordering..

                                          The API says:

                                          @unknownuser said:

                                          The negative values should not be used as an index for point_at, take the positive value of the index value in the polygon array

                                          Perhaps hidden edges will only happend if mesh is constructed from a collection of Sketchup::Face's. Not relevant in this case.
                                          In that case maybe use index.abs or perhaps double negation: index = index<0 ? -index : index

                                          ents = Sketchup.active_model.active_entities
                                          
                                          def centerpoints(f)
                                            cx = (f[0].x + f[1].x + f[2].x + f[3].x)/4
                                            cy = (f[0].y + f[1].y + f[2].y + f[3].y)/4
                                            cz = (f[0].z + f[1].z + f[2].z + f[3].z)/4
                                            return Geom;;Point3d.new(cx, cy, cz)
                                          end
                                          
                                          
                                          face1 = [ 
                                            Geom;;Point3d.new(-5,-5,0), Geom;;Point3d.new(5,-5,0),
                                            Geom;;Point3d.new(5,5,0), Geom;;Point3d.new(-5,5,0) 
                                          ]
                                          
                                          #create points for 4 faces
                                          faceHash = {}
                                          for i in (0...4) 
                                             faceHash[i] = face1
                                             face1 = face1.collect{|pt| pt.offset([20,0,0])}
                                          end
                                          
                                          #get refference to the center of "face"#3 Before appending to mesh.
                                          
                                          fC = centerpoints(faceHash[2])
                                          ents.add_cpoint(fC)
                                          
                                          # Bit strange to loop hash this way, but they get ordered.
                                          msh = Geom;;PolygonMesh.new
                                          for n in (0...faceHash.length)
                                            msh.add_polygon(faceHash[n])
                                          end
                                          
                                          #Test PolygonMesh index. How does hidden edges affect indexes for this ?
                                          # +1 index for polygons in Mesh. 2 c_points should get added at same spot
                                          meshface3 = msh.polygon_points_at(2+1)
                                          mc = centerpoints(meshface3)
                                          ents.add_cpoint(mc)
                                          
                                          
                                          group = ents.add_group
                                          group.entities.add_faces_from_mesh(msh)
                                          faces = group.entities.grep(Sketchup;;Face)
                                          
                                          #Red material to face 3
                                          faces[2].material = "red"
                                          
                                          
                                          
                                          1 Reply Last reply Reply Quote 0
                                          • 1
                                          • 2
                                          • 1 / 2
                                          • First post
                                            Last post
                                          Buy SketchPlus
                                          Buy SUbD
                                          Buy WrapR
                                          Buy eBook
                                          Buy Modelur
                                          Buy Vertex Tools
                                          Buy SketchCuisine
                                          Buy FormFonts

                                          Advertisement