• Login
sketchucation logo sketchucation
  • Login
๐Ÿ”Œ Quick Selection | Try Didier Bur's reworked classic extension that supercharges selections in SketchUp Download

Transform face to a known plane

Scheduled Pinned Locked Moved Developers' Forum
15 Posts 5 Posters 1.7k Views 5 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 9 Dec 2015, 22:44

    I have a face that can be on any plane. I need to transform it so that it is on a specific plane. Does anyone know how to do this.

    In most cases the specific plane will be flat on the ground.

    1 Reply Last reply Reply Quote 0
    • J Offline
      jolran
      last edited by 9 Dec 2015, 23:41

      The "specific plane" ? I assume you mean the modeling plane where the face is located to start with ?

      It says in the API

      Geom::Transformation.new(origin, zaxis)

      Don't remember if it was this one I used..
      Try: origin, a Point on the plane and zaxis should then be the plane normal.

      Edit: Be aware though that it's not really a reliable method since only providing 1 vector and not a frame. Sketchup does some thinking and comparing to decide what is supposed to become X and Y axis. So if rotation is important you have to do some extra work..

      Oh and you have to reset translation to ORIGIN before moving it to the face. I guess you could use a vector instead. Anyhew...
      If you have a plane and not a face. The plane is an Array[3] with Point and normal.

      
      ents = Sketchup.active_model.entities
      face = Sketchup.active_model.selection.grep(Sketchup;;Face)[0]
      gp = Sketchup.active_model.selection.grep(Sketchup;;Group)[0]
      	
      normal = face.normal
      c = face.bounds.center
      tr1 = Geom;;Transformation.new(c,normal)
      #reset to ORIGIN
      gpc = gp.bounds.center
      tr = Geom;;Transformation.new([-gpc[0],-gpc[1],-gpc[2]], Z_AXIS)
      
      gp.transform!(tr1*tr)
      
      1 Reply Last reply Reply Quote 0
      • G Offline
        Garry K
        last edited by 10 Dec 2015, 00:36

        The face can be rotated on both x and y axis.

        The key part is that rourke has centroid code but it only works on a face that is parallel to the ground.

        What I want to do is transform the points of the face to ground plane, calculate the centroid and then transform the centroid back so it lays on the original face.

        1 Reply Last reply Reply Quote 0
        • S Offline
          sdmitch
          last edited by 10 Dec 2015, 01:42

          @garry k said:

          What I want to do is transform the points of the face to ground plane, calculate the centroid and then transform the centroid back so it lays on the original face.

          Not sure where I found this code but it will calculate the centriod of xyz pts.

          def calc_centroid(f)
           tx=0.0;ty=0.0;tz=0.0;
           p=f.outer_loop.vertices.collect{|v|v.position}
           p.each{|v| tx+=v.x;ty+=v.y;tz+=v.z}
           ax=tx/p.length;ay=ty/p.length;az=tz/p.length
           c=Geom;;Point3d.new(ax,ay,az);#ent.add_cpoint(c)
           area = 0.0;cx = 0.0;cy = 0.0;cz = 0.0;
           for i in 0...p.length
            areat = (p[i].distance(p[i-1])*(c.distance_to_line([p[i],p[i].vector_to(p[i-1])])))/2.0
            area = area + areat;
            cx = cx + areat * ( p[i].x + p[i-1].x + c.x ) / 3.0;
            cy = cy + areat * ( p[i].y + p[i-1].y + c.y ) / 3.0;
            cz = cz + areat * ( p[i].z + p[i-1].z + c.z ) / 3.0;
           end
           cx = cx / area;cy = cy / area;cz = cz / area;
           Geom;;Point3d.new(cx,cy,cz)
          end
          
          
          

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

          http://sdmitch.blogspot.com/

          1 Reply Last reply Reply Quote 0
          • G Offline
            Garry K
            last edited by 10 Dec 2015, 02:45

            Thanks sdmitch

            This indeed produces a centroid on a face.

            I also need to transform the face to ground level. The reason is I will need to do some panel optimization. So I need the shapes on ground level.

            1 Reply Last reply Reply Quote 0
            • J Offline
              jolran
              last edited by 10 Dec 2015, 06:27

              Ok missed the the key part in the first post....

              It might be difficult to find a general solution if you want the correct X or Y rotation flat at the ground from a reversed face transformation ? Don't know if anyone found a simple solution to that unless digging in at entity level and comparing angles.
              For a simple rectangle face it might be solvable, but a complex polygon how do you tell which edge or vertice to use for alignment ? It's easier to do with parametric Surface and derivatives ๐Ÿ˜‰

              An alternative might be to use Vector3d.axes, where you form your own axes with the face.normal as Z-axis and use those with your Formulas. Might remove the need to move the face to Origin. Same problem with alignment though but when creating a tempgroup for a faceclone ( you can't move the original ๐Ÿ˜„ )its Z-axis is not pointing in the face normal direction, so there is quite some work to make the boundingbox aligned so the face is flat on the ground when reversing transformations..

              1 Reply Last reply Reply Quote 0
              • C Offline
                CAUL
                last edited by 10 Dec 2015, 07:55

                @garry k said:

                I have a face that can be on any plane. I need to transform it so that it is on a specific plane. Does anyone know how to do this.

                In most cases the specific plane will be flat on the ground.

                I think the code below works:

                
                module AlignToNormal
                
                  def self.get_alignment_matrix(face_normal, p, plane_normal)
                    return Geom;;Transformation.new if (plane_normal.dot(face_normal)- 1).abs < 0.00000001   
                    cv = face_normal.cross(plane_normal)
                    a = face_normal.angle_between(plane_normal)
                    return Geom;;Transformation.rotation(p, cv, a)
                  end
                  
                  def self.get_centroid(f)
                    c = Geom;;Point3d.new(0, 0, 0)
                    f.outer_loop.vertices.map { |v| v.position }.each { |p| 
                      c.x += p.x ; c.y += p.y; c.z += p.z
                    }
                    div = f.outer_loop.vertices.length
                    c.x = c.x / div; c.y = c.y / div; c.z = c.z / div;
                    return c
                  end
                
                  def self.main
                    mod = Sketchup.active_model
                    ent = mod.entities
                    sel = mod.selection
                    
                    f = sel.grep(Sketchup;;Face)[0]
                    centroid = get_centroid(f)
                    m = get_alignment_matrix(f.normal, centroid, Geom;;Vector3d.new(1, 1, 1).normalize!)
                    ent.transform_entities(m, f)
                  end
                  
                  main
                end
                
                
                
                1 Reply Last reply Reply Quote 0
                • J Offline
                  jolran
                  last edited by 10 Dec 2015, 08:17

                  That's nice but..

                  @unknownuser said:

                  I also need to transform the face to ground level. The reason is I will need to do some panel optimization. So I need the shapes on ground level.

                  I gather this information as he actually DO want the face to the ground to do something with it there. Maybe I'm wrong this time as well.

                  Edit, sorry missed the part in the code where one can edit the plane. Your code seams to work for the purpose of getting the plane correct!

                  1 Reply Last reply Reply Quote 0
                  • C Offline
                    CAUL
                    last edited by 10 Dec 2015, 10:56

                    @jolran said:

                    I gather this information as he actually DO want the face to the ground to do something with it there. Maybe I'm wrong this time as well.

                    You can concatenate transformations with multplication:

                    
                    align = get_alignment_matrix(face_normal, centroid, plane_normal)
                    translate = Geom;;Transformation.translation(to_point - centroid)
                    align_and_translate = translate * align
                    ent.transform_entities(align_and_translate, f)
                    
                    
                    1 Reply Last reply Reply Quote 0
                    • G Offline
                      Garry K
                      last edited by 11 Dec 2015, 05:11

                      Thanks guys - I've adjusted Caul's code and I can now get everything working the way I want.

                      1 Reply Last reply Reply Quote 0
                      • G Offline
                        Garry K
                        last edited by 11 Dec 2015, 12:08

                        The plane is rotated from the ground plane on all axis.

                        1 Reply Last reply Reply Quote 0
                        • F Offline
                          fredo6
                          last edited by 12 Dec 2015, 16:15

                          Usually, you achieve this with Geom::Transformation.axes.

                          In your case, assuming the face is at top level of the model:

                          
                          tr_axe_inv = Geom;;Transformation.axes(face.vertices[0].position, *(face.normal.axes)).inverse
                          
                          

                          tr_axe_inv is the transformation to be used for the projection.

                          Fredo

                          1 Reply Last reply Reply Quote 0
                          • G Offline
                            Garry K
                            last edited by 12 Dec 2015, 21:17

                            Thanks Fredo,

                            Seems like there is always something new to learn !!

                            1 Reply Last reply Reply Quote 0
                            • F Offline
                              fredo6
                              last edited by 13 Dec 2015, 10:36

                              This projects the face on the XY plane, with vertex 0 at Origin.

                              If you wish to project to another plane, say with [pt2, normal2], use an additional direct Axe transformation.

                              Fredo

                              1 Reply Last reply Reply Quote 0
                              • C Offline
                                CAUL
                                last edited by 13 Dec 2015, 15:27

                                @fredo6 said:

                                
                                > tr_axe_inv = Geom;;Transformation.axes(face.vertices[0].position, *(face.normal.axes)).inverse
                                > 
                                

                                Neat! Just saved fifteen lines of code in a script...

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

                                Advertisement