=begin 
(Originally 2009 (c) CPhillips* then (c) TIG** THEN (c) ThomThom 
Script: triangulateFaces.rb
Code Usage:   triangulateFace(face)*
Result: it triangulates a face... all Texture UVs are kept.
Plugin Usage: triangulateFaces(faces_array)**
Result: it triangulates faces in a selection...
v1.0
First Release: Def Code 'mesh' idea by CPhillips*, 
retained back_materials added by TIG [failed] ###, 
Plugin parts by TIG**. 20090729
v1.1
Rewritten entirely by TIG... THEN completely corrected by Thomthom (TT)!
It now retains all Texture mapping successfully. 20091203
v1.2 20101120
Any 4-sided triangles now intersected and split into two!
=end
###
require 'sketchup.rb'
###
def triangulateFace(face)
 ### if already a triangle leave alone...
 if face.vertices[3]
  mesh=face.mesh(3)
  ents=face.parent.entities
  mat=face.material
  bac=face.back_material
   # (TT) # Instead of sampling vertices we sample points of the face's plane.
   # This is because we need four points, and some times a face only has three vertices.
   # And we also get the wrong result if any of the first four vertices are co-linear.
   samples = []
   samples << face.vertices[0].position             # 0,0 | Origin
   samples << samples[0].offset(face.normal.axes.x) # 1,0 | Offset Origin in X
   samples << samples[0].offset(face.normal.axes.y) # 0,1 | Offset Origin in Y
   samples << samples[1].offset(face.normal.axes.y) # 1,1 | Offset X in Y
   ### get uvs
   tw=Sketchup.create_texture_writer
   # (TT)
   uv_helper=face.get_UVHelper(true,true,tw) # (TT) Only need one UV Helper
   xyz = []
   uv_f = []
   uv_b = []
   samples.each { |position|
      # XYZ 3D coordinates
      xyz << position
      # UV 2D coordinates
      # Front
      uvq = uv_helper.get_front_UVQ(position)
      uv_f << flattenUVQ(uvq)
      # Back
      uvq = uv_helper.get_back_UVQ(position)
      uv_b << flattenUVQ(uvq)
   }
  ###
  grp=ents.add_group
  grp.entities.fill_from_mesh(mesh, true, 0)
  # (TT) Adds the mesh without soft/smooth edges. (and faster)
  grp.entities.to_a.each{|e|
    next unless e.class==Sketchup::Face
    if mat # (TT) # Position texture.
      pts = []
      (0..3).each { |i|
         pts << xyz[i]
         pts << uv_f[i]
      }
        e.position_material(mat,pts, true)
    end#if
    if bac # (TT) # Position texture.
      pts = []
      (0..3).each { |i|
         pts << xyz[i]
         pts << uv_b[i]
      }
       e.position_material(bac, pts, false)
    end#if
  }
  ### force intersection of all triangles so if any 4 sided they are fixed.
  grp.entities.intersect_with(true, grp.transformation, grp.entities, grp.transformation, true, grp.entities.to_a)
  ### fix 4 sided triangles...
  grp.entities.to_a.each{|e|
    next unless e.class==Sketchup::Face
    verts=e.vertices
    if verts.length > 3
      verts.each{|v|
           (verts-[v]).each{|vv|
                grp.entities.add_line(v.position, vv.position)
            }
        }
    end#if
  }
  face.erase! if face.valid?
  grp.explode if grp.valid?
 end#if
end#def
# Get UV coordinates from UVQ matrix. (TT)
def flattenUVQ(uvq)
  return Geom::Point3d.new(uvq.x / uvq.z, uvq.y / uvq.z, 1.0)
end
###
### Main Code for Plugin (c) TIG----------------------------------------
def triangulateFaces(faces_array)
  model=Sketchup.active_model
  model.start_operation("Triangulate Faces")
  msg="Triangulating"
  tick=0
  faces_array.each{|e|
    if e.kind_of?(Sketchup::Face)and e.edges.length>=4
      Sketchup::set_status_text(msg,SB_PROMPT)
      triangulateFace(e)
      msg=msg+". "
      tick+=1
    end#if
  }
  Sketchup::set_status_text("",SB_PROMPT)
  model.commit_operation
  return nil
end#def
###
### Menu ###------------------------------------------------------------
if not file_loaded?(File.basename(__FILE__))
  UI.menu("Plugins").add_item("Triangulate Faces in Selection"){triangulateFaces(Sketchup.active_model.selection.to_a);Sketchup.active_model.selection.clear}
end#if
file_loaded(File.basename(__FILE__))
###
