• Login
sketchucation logo sketchucation
  • Login
πŸ€‘ SketchPlus 1.3 | 44 Tools for $15 until June 20th Buy Now

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.
  • G Offline
    Garry K
    last edited by 31 Oct 2013, 22:24

    I've been looking for a method to transform an array of Point3d objects. It appears that the array.transform is for a simple array of 3 numbers representing x,y and z.

    I know you can transform many entities or a group or a polygon mesh.

    I've added a bunch of points into a polygon mesh and transformed them but I get similar performance by transforming a point at a time.

    It would certainly be nice to transform in place an array of points.

    1 Reply Last reply Reply Quote 0
    • C Offline
      Chris Fullmer
      last edited by 1 Nov 2013, 02:31

      Try these two options:

      entiites.transform_entities
      entities.transform_by_vectors

      http://www.sketchup.com/intl/en/developer/docs/ourdoc/entities.php#transform_entities
      http://www.sketchup.com/intl/en/developer/docs/ourdoc/entities.php#transform_entities

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

      1 Reply Last reply Reply Quote 0
      • G Offline
        Garry K
        last edited by 1 Nov 2013, 06:23

        Sorry Chris - doesn't work.

        It appears that the reason is my point3d objects are not in the model - so they are not considered entities. If I put them in the model then this works - but I loose all the speed benefits that I currently have just by putting them in the model and manipulating them there.

        What I am doing is transforming points and then adding them to a PolygonMesh. Currently I am transforming the points 1 at a time.

        1 Reply Last reply Reply Quote 0
        • J Offline
          jolran
          last edited by 1 Nov 2013, 08:17

          Garry, we seam both to have a fascination of Points currently πŸ˜„

          I'm trying to find out the optimal way to transform Points "en mass" too.

          Can one really Group Point3d objects? Don't Think so..

          
          
          arrayofpoints2 = arrayofpoints1.collect{|p| p.offset(vec) }
          
          

          This seams to work when you don't want to alter the original Points Array.

          I'm wondering if creating a dup of the original array and perform edit in Place(offset!) is faster. You mention that also, btw.
          It might not be as easy as Array.dup... Might not work with Point3d objects..

          I started to fiddle around with the polygonmesh object. Yes it's convenient that one can transform the meshobject as whole. But found the polygons and Points methods a bit difficult for traversing Points, since for ex the polygon method returns indexes and not arrays of Points. I'm sure there's a reason for that I'm not aware off, but I had to add Another loop in the loop to reach the correct Points. And that is expensive.

          Keep posted. Interesting subject.

          1 Reply Last reply Reply Quote 0
          • G Offline
            Garry K
            last edited by 1 Nov 2013, 09:00

            I've had the best results so far doing this:
            profile.each { |val| mesh.add_point( val.transform( t ) ) }

            What was interesting is I didn't have to change my code that creates triangle or quad polygons. Instead I changed the array to hold indexes instead of points. For the handrail profiles I simply keep 2 arrays that contain indexes. The length of the array exactly corresponds to the number of points for the handrail profile.

            For this project I can guarantee that the points are all unique. So I don't have to store all the indexes since I already know what they are. For the first handrail segment I have one array containing 53 integers (indexes) 1..53 and the second array contains 53 integers 54..106. The array's simplified logic as I could make use of [-1] which wraps around and completes the face.

            It might be cheaper to dispense with the 2 arrays and do the math. But it isn't as obvious and I'd have to handle the wrap as a separate condition.

            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.

            1 Reply Last reply Reply Quote 0
            • A Offline
              AdamB
              last edited by 1 Nov 2013, 09:23

              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.

              Developer of LightUp Click for website

              1 Reply Last reply Reply Quote 0
              • T Offline
                TIG Moderator
                last edited by 1 Nov 2013, 11:46

                The two entities transform methods will affect instances/groups, faces, edges and vertices, but NOT points.
                Points have their own methods .transform(trans) and .transform!(trans). and .offset(vector) and .offset!(vector) [you can use an optional second argument for 'distance' if the 'vector' is not the required length]
                If you have some points that need simple offsets by a fixed vector then iterating them with offset! will do, but if you want to do a rotate/scale etc then you need an appropriate transformation...

                If you clarifies what you have and what you want to end up with then more precise help might be available...

                TIG

                1 Reply Last reply Reply Quote 0
                • J Offline
                  jolran
                  last edited by 1 Nov 2013, 12:03

                  TIG.
                  I think this thread is related.
                  http://sketchucation.com/forums/viewtopic.php?f=180&t=54786

                  Actually the topic title describes the question quite good..

                  1 Reply Last reply Reply Quote 0
                  • J Offline
                    jolran
                    last edited by 1 Nov 2013, 14:14

                    @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 1 Nov 2013, 14:52

                      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
                      • C Offline
                        Chris Fullmer
                        last edited by 1 Nov 2013, 16:08

                        @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 1 Nov 2013, 16:28

                          @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 1 Nov 2013, 17:44

                            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 1 Nov 2013, 18:58

                              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 1 Nov 2013, 19:40

                                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 2 Nov 2013, 04:31

                                  @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
                                  • J Offline
                                    jolran
                                    last edited by 2 Nov 2013, 08:26

                                    @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
                                    • J Offline
                                      jolran
                                      last edited by 2 Nov 2013, 10:24

                                      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 2 Nov 2013, 12:14

                                        What about a benchmark for a hash?

                                        1 Reply Last reply Reply Quote 0
                                        • J Offline
                                          jolran
                                          last edited by 2 Nov 2013, 12:42

                                          
                                          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
                                          • 1
                                          • 2
                                          • 1 / 2
                                          1 / 2
                                          • First post
                                            1/27
                                            Last post
                                          Buy SketchPlus
                                          Buy SUbD
                                          Buy WrapR
                                          Buy eBook
                                          Buy Modelur
                                          Buy Vertex Tools
                                          Buy SketchCuisine
                                          Buy FormFonts

                                          Advertisement