# Copyright 2005, @Last Software, Inc.

# Permission to use, copy, modify, and distribute this software for 
# any purpose and without fee is hereby granted, provided that the above
# copyright 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.
#-----------------------------------------------------------------------------

require 'sketchup.rb'

def simplyContours

    index = Sketchup.version.index(".")
    majorVersion =  Sketchup.version.slice(0..index)
    majorVersion = majorVersion.to_i

    if majorVersion<5
    
        UI.messagebox("This script will only run on SketchUp 5 or greater.")
        return
    
    end

    model = Sketchup.active_model
    
    #define everything as one undo operation
    model.start_operation "Simplify Contours"

    result = UI.inputbox ["Angle (deg)"], [10], "Simplify Angle"
    angle = (180-result[0])/57.296
    
    ss = Sketchup.active_model.selection

    #Get rid of any selected entities that are not edges
    remove = []

    ss.each do |entity|
    
        if !entity.kind_of?(Sketchup::Edge)
        
            remove.push(entity)
        
        end

    end

    ss.remove(remove)
    
    edges = []
    
    ss.each do |edge|
    
        edges.push(edge)
        
    end
    
    puts "Number Edges = " + ss.length.to_s
    
    parent = edges[0].parent.entities
    usedSet = Set.new
    contours = []
    
    edges.each do |edge|
    
        if !usedSet.include?(edge)
    
            orderedPoints = []
        
            curve = edge.curve
            
            if curve
            
                curve.vertices.each do |vert|
                
                    orderedPoints.push(vert.position)
                    
                end
                
                curve.edges.each do |edge|
                
                    usedSet.insert(edge)
                    
                end
                
                contours.push(orderedPoints)
        
            else
            
                #puts "using manual ordering"
                
                connectedEdges = edge.all_connected

                #remove all the non-edges
                for i in (0..connectedEdges.length-1)
                    if !connectedEdges[i].kind_of?(Sketchup::Edge)
                        connectedEdges[i] = nil
                    end
                end
                connectedEdges.compact!
                            
                bNoTVerts = true
                connectedEdges.each do |edge|
                
                    if edge.start.edges.length>2
                        bNoTVerts = false
                        break
                    end
                    
                    if edge.end.edges.length>2
                        bNoTVerts = false
                        break
                    end
                
                end
                
                if bNoTVerts
                
                    orderedPoints = OrderConnectedEdges(connectedEdges)
                
                end
                
                #mark all these edges as used
                connectedEdges.each do |edge|
                
                    usedSet.insert(edge)
                
                end
                
                if orderedPoints.length>1
                
                    contours.push(orderedPoints)
                    
                end
            
            end
            
        end
    
    end
        
    usedEdges = usedSet.to_a
    parent.erase_entities(usedEdges)
    
    count = 0
    contours.each do |contour|
    
        simpleContour = SimplifyCurve(contour, angle)
        parent.add_curve(simpleContour)
        count+=1
        tellPctComplete(count,contours.length) 
    
    end
    
    model.commit_operation

end

def SimplifyCurve(orderedPoints, angle)

    simplePoints = []

    simplePoints.push(orderedPoints[0])
    lastPoint = orderedPoints[0]
    
    for i in (1..orderedPoints.length-2)
    
        currentPoint = orderedPoints[i]
        nextPoint = orderedPoints[((1+i)%orderedPoints.length)]
    
        vec1 = lastPoint - currentPoint
        vec2 = nextPoint - currentPoint
    
        if (vec1.angle_between(vec2)>angle)
        
            #skip this vertex entirely
        
        else
        
            simplePoints.push(currentPoint)
            lastPoint = currentPoint 
        
        end
        
    end
    
    simplePoints.push(orderedPoints.last)

    return simplePoints
  
end

def OrderConnectedEdges(edges)

    #Scan through looking for an edge vertex that is only
    #connected to a single edge.  If non are found, then 
    #this is a closed loop
    orderedPoints = []
    
    if edges.length==1
        orderedPoints.push(edges[0].start.position)
        orderedPoints.push(edges[0].end.position)
        return orderedPoints
    end
    
    startVert = nil
    edges.each do |edge|
    
        if edge.start.edges.length==1
            startVert = edge.start
            break
        end

        if edge.end.edges.length==1
            startVert = edge.end
            break
        end

    end
    
    #closed Loop case
    if startVert==nil
        startVert = edges[0].start
    end

    orderedPoints.push(startVert.position)
    lastEdge = startVert.edges[0]
    currentVert = lastEdge.other_vertex(startVert)
    
    while (true)

        orderedPoints.push(currentVert.position)
        
        #find the next edge
        currentVert.edges.each do |edge|
        
            if edge!=lastEdge
                lastEdge = edge
                break
            end
            
        end
        
        #find the next vertex
        currentVert = lastEdge.other_vertex(currentVert)
        
        #push this on if this is our last point
        if currentVert.edges.length==1
            orderedPoints.push(currentVert.position)
            break
        end
        
        if currentVert==startVert
            orderedPoints.push(currentVert.position)
            break
        end
                
    end
    
    return orderedPoints

end

def tellPctComplete(iteration,total) 
    linechar = "-"                          # Set default line building character.
    progresschar = ">"                      # Set default moving indicator.
    pct = (iteration*100)/total             # Calculate percentage complete.
    pct = 1 if pct <= 0                     # round up to 1% if anything less than 1%.
    initial_block = linechar * 100          # Default progress bar line sequence.
    current_block = "|" << initial_block[0,pct-1] << progresschar << initial_block[pct,initial_block.length] << "|"
    Sketchup.set_status_text(current_block << "   " << (pct.to_s)<<"%.")
    return
end    # tellPctComplete


if( !$simplifyContoursLoaded )
    UI.menu("Plugins").add_item("Simplify Contours") { simplyContours }
    simplifyContoursLoaded = true
end
    
  
