=begin
###
Copyright 2011-2015, TIG (c)
Permission to use, copy, modify, and distribute this software for any 
purpose, and currently without fee, is hereby granted, provided that  
this text and the above copyright (c) notice appear in all copies.
This software is provided "as is" and without any express or implied 
warranties, including, without limitation, the implied warranties of 
merchantability and fitness for a particular purpose.
###
Name: dropverts.rb
###
Menu: 'Plugins' > 'Drop Vertices...' > 
'To Nearest Object'
'To Nearest Below'
'To Nearest Above'
'To Nearest+Z=?'
'To Lowest'
'To Highest'
'To Middle'
'To Average'
'To Z=?'
'To Z=%'
###
Usage:

Preselect the edges where you want vertices to 'adjust', choose tool...

'To Nearest Object' means all of the edges' vertices will 'drop' on to 
the 'objects' below them, OR 'lift' to the 'objects' above them if there 
was nothing below, or to Z=0 if there is nothing above/below.

'To Nearest Below' means all of the edges' vertices will 'drop' on to 
the next 'object' below them, or to Z=0 if there is nothing below.

'To Nearest Above' means all of the edges' vertices will 'lift' up to 
the next 'object' above them, or to Z=0 if there is nothing above.

'To Nearest+Z=?' means you enter the default drop Z value in a dialog 
and it then does the equivalent of 'To Nearest Object' BUT stops at 
the specified Z value [rather than Z=0] is nothing is above/below.

'To Lowest' means all of the edges' vertices will 'drop' to match the 
Z value of the lowest selected vertex.

'To Highest' means all of the edges' vertices will 'lift' to match the 
Z value of the highest selected vertex.

'To Middle' means all of the edges' vertices will 'adjust' to match the 
mid Z value between the highest and lowest selected vertices.

'To Average' means all of the edges' vertices will 'adjust' to match the 
average Z value of all of the selected vertices; this is not necessarily 
the same as 'To Middle' as a disproportionate number of low vertices 
in the selection will reduce the average but not affect the mid value.

'To Z=?' means a dialog asks for the Z value; enter a number to use 
current-units e.g. 123 might be 123" or 123mm depending on the model's 
current units; to use something other than the current units suffix the 
number thus '123mm' to use 123mm when your units might be in 'meters':
the vertices will all adjust to that specified Z value: default Z=0.

'To Z=%' means that a dialog asks for the % [Percentage]; enter a 
value: the default is 100 which means 'no change': entering a smaller 
value, say 50, will adjust each selected vertex to be 50% its height 
above the lowest selected vertex [i.e. the mesh is 'deflated']; entering 
a higher value, say 150, will adjust each selected vertex to be 150% 
its height above the lowest selected vertex [i.e. the mesh is 
'inflated']; entering 0 will completely 'flatten' the mesh to the level 
of the lowest selected vertex [equivalent to using 'To Lowest']; 
entering negative values will 'flip' the mesh - so -100 will invert it, 
-50 will invert it and deflate it, and -150 will invert it and inflate 
it.

###
Donations: PayPal.com to info @ revitrev.org
###
Version:
1.0 20110806 First issue.
1.1 20110807 Nearest-Below/-Above, Middle/Average and Z=% options added.
1.2 20110807 Nearest+Z=? option added.
1.3 20110810 Glitch with Lowest/Highest/Middle fixed.
2.0 20150422 Glitches with dropping curves resolved.
###
=end
###
require 'sketchup.rb'
###
module TIG
###
def self.dropverts(z=nil,dn=nil,up=nil,pe=nil)
  ###
  z=z.to_s.to_l if z ###to units
  zN=true
  if ! up && ! dn
    zN=false
    up=true
	dn=true
  end
  ###
  model=Sketchup.active_model
  ents=model.active_entities
  ss=model.selection
  verts=[]
  ss.grep(Sketchup::Edge).each{|e|
    e.explode_curve if e.curve
	verts << e.vertices
  }
  ss.clear
  unless verts[0]
    UI.messagebox("Pre-Select Edges!")
    return nil
  end
  verts.flatten!
  verts.uniq!
  if pe ### percentage
    pe=1.0-(pe.to_f/100.0)
    z=verts[0].position.z
    verts.each{|v|z=v.position.z if v.position.z < z}
  end
  vxs=[]
  vts=[]
  verts.each{|v|
    vxs << v
    pv=v.position
    if z
      if ! pe
        if zN ### z passed but also 'to nearest'
          rayt=model.raytest(pv, Z_AXIS.reverse)
          if rayt
            pt=rayt[0]
          else
            rayt=model.raytest(pv, Z_AXIS)
            if rayt
              pt=rayt[0]
            else
              pt=pv.clone
              pt.z=z if z
              pt.z=0 if ! z
            end
          end
        else ### there's no zN - so z=z
          pt=pv.clone
          pt.z=z if z
          pt.z=0 if ! z
        end
      else ### we'll apply the percentage
        pt=pv.offset(Z_AXIS.reverse, (pv.z - z)*pe)
      end
    elsif dn
      rayt=model.raytest(pv, Z_AXIS.reverse)
      if rayt
        pt=rayt[0]
      elsif up
        rayt=model.raytest(pv, Z_AXIS)
        if rayt
          pt=rayt[0]
        else
          pt=pv.clone
          pt.z=z if z
          pt.z=0 if ! z
        end
      else   
        pt=pv.clone
        pt.z=z if z
        pt.z=0 if ! z
      end
    elsif up
      rayt=model.raytest(pv, Z_AXIS)
      if rayt
        pt=rayt[0]
      else
        pt=pv.clone
        pt.z=z if z
        pt.z=0 if ! z
      end
    else###no z
      pt=pv.clone
      pt.z=z if z ### unlikely!
      pt.z=0 if ! z
    end#if
    vts << pv.vector_to(pt)
  }
  begin
    model.start_operation("TIG.dropverts", true)
  rescue
    model.start_operation("TIG.dropverts")
  end
    ents.transform_by_vectors(vxs,vts)
    return vxs ### returns array of vertices processed
  model.commit_operation
end
###
def self.dropverts_lowest()
  model=Sketchup.active_model
  ss=model.selection
  verts=[]
  ss.grep(Sketchup::Edge).each{|e| verts << e.vertices }
  unless verts[0]
    UI.messagebox("Pre-Select Edges!")
    return nil
  end
  verts.flatten!
  verts.uniq!
  z=verts[0].position.z
  verts.each{|v|z=v.position.z if v.position.z < z}
  TIG.dropverts(z,nil,nil,nil)
end
###
def self.dropverts_highest()
  model=Sketchup.active_model
  ss=model.selection
  verts=[]
  ss.grep(Sketchup::Edge).each{|e| verts << e.vertices }
  unless verts[0]
    UI.messagebox("Pre-Select Edges!")
    return nil
  end
  verts.flatten!
  verts.uniq!
  z=verts[0].position.z
  verts.each{|v|z=v.position.z if v.position.z > z}
  TIG.dropverts(z,nil,nil,nil)
end
###
def self.dropverts_middle()
  model=Sketchup.active_model
  ss=model.selection
  verts=[]
  ss.grep(Sketchup::Edge).each{|e| verts << e.vertices }
  unless verts[0]
    UI.messagebox("Pre-Select Edges!")
    return nil
  end
  verts.flatten!
  verts.uniq!
  zz=verts[0].position.z
  zzz=verts[0].position.z
  verts.each{|v|
     zz=v.position.z if v.position.z > zz
    zzz=v.position.z if v.position.z < zzz
  }
  z=(zz-((zz-zzz)/2.0)).to_s+'"'
  TIG.dropverts(z,nil,nil,nil)
end
###
def self.dropverts_average()
  model=Sketchup.active_model
  ss=model.selection
  verts=[]
  ss.grep(Sketchup::Edge).each{|e| verts << e.vertices }
  unless verts[0]
    UI.messagebox("Pre-Select Edges!")
    return nil
  end
  verts.flatten!
  verts.uniq!
  zz=0.0
  verts.each{|v|zz = zz+v.position.z}
  z = (zz/(verts.length.to_f)).to_s+'"'
  TIG.dropverts(z,nil,nil,nil)
end
###
def self.dropverts_dialog()
  model=Sketchup.active_model
  ss=model.selection
  verts=[]
  ss.grep(Sketchup::Edge).each{|e| verts << e.vertices }
  unless verts[0]
    UI.messagebox("Pre-Select Edges!")
    return nil
  end
  @dropvertsZ="0" unless @dropvertsZ
  results=UI.inputbox(["To Z=?"],[@dropvertsZ],"Drop Vertices ?")
  return nil unless results
  @dropvertsZ=results[0]
  TIG.dropverts(@dropvertsZ,nil,nil,nil)
end
###
def self.dropverts_nearestZ()
  model=Sketchup.active_model
  ss=model.selection
  verts=[]
  ss.grep(Sketchup::Edge).each{|e| verts << e.vertices } 
  unless verts[0]
    UI.messagebox("Pre-Select Edges!")
    return nil
  end
  @dropvertsZ="0" unless @dropvertsZ
  results=UI.inputbox(["To Z=?"],[@dropvertsZ],"Drop Vertices [Nearest+]")
  return nil unless results
  @dropvertsZ=results[0]
  TIG.dropverts(@dropvertsZ,true,true,nil)
end
###
def self.dropverts_percentage()
  model=Sketchup.active_model
  ss=model.selection
  verts=[]
  ss.grep(Sketchup::Edge).each{|e| verts << e.vertices }
  unless verts[0]
    UI.messagebox("Pre-Select Edges!")
    return nil
  end
  @dropvertsP=100.0 unless @dropvertsP
  results=UI.inputbox(["To Z=%"],[@dropvertsP],"Drop Vertices [%]")
  return nil unless results
  @dropvertsP=results[0]
  TIG.dropverts(nil,nil,nil,@dropvertsP)
end
### menu
unless file_loaded?(__FILE__)
  menu=UI.menu("Plugins").add_submenu("Drop Vertices...")
  menu.add_item("To Nearest Object"){TIG.dropverts(nil,true,true,nil)}
  menu.add_item("To Nearest Below"){TIG.dropverts(nil,true,nil,nil)}
  menu.add_item("To Nearest Above"){TIG.dropverts(nil,nil,true,nil)}
  menu.add_item("To Nearest+Z=?"){TIG.dropverts_nearestZ()}
  menu.add_item("To Lowest"){TIG.dropverts_lowest()}
  menu.add_item("To Highest"){TIG.dropverts_highest()}
  menu.add_item("To Middle"){TIG.dropverts_middle()}
  menu.add_item("To Average"){TIG.dropverts_average()}
  menu.add_item("To Z=?"){TIG.dropverts_dialog()}
  menu.add_item("To Z=%"){TIG.dropverts_percentage()}
  file_loaded(__FILE__)
end
###
end#module
