/*
 * PiAnoS (Picture Annotation System), A fingerprint examiner training tool
 * Copyright (C) 2011-2021 University of Lausanne, Switzerland
 * https://ips-labs.unil.ch/pianos
 * 
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any
 * later version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see http://www.gnu.org/licenses/.
 */

/**
 * @constructor
 */
function Pianos4Annotation()
{
}
Pianos4Annotation._s_ids = 1;
Pianos4Annotation._s_pairIds = 1;

// ----------------------------
// Minutia
// ----------------------------

/**
 * @constructor
 */
function Pianos4Minutia( type, pos, angle )
{
    assert( type == 'bifurcation' || type == 'ridge_ending' || type == 'center' || type == 'difference' || type == 'unknown' || type == 'unknown2' || type == "live" );
    assert( angle >= -180.0 && angle <= 180.0 );
    
    this.id = Pianos4Annotation._s_ids++;
    this.type = type;
    this.pos = pos;
    this.angle = angle;
    this.live = ( type === "live" );
}

// ----------------------------
// TPS Anchor
// ----------------------------

/**
 * @constructor
 */
function Pianos4TPSAnchore( type, origin, pos )
{
    this.id = Pianos4Annotation._s_ids++;
    this.type = type;
    this.pos = pos;
    this.origin = origin;
}

function Pianos4TPSLines( type, from, to )
{
    this.id = Pianos4Annotation._s_ids++;
    this.type = type;
    this.from = from;
    this.to = to;
}

// ----------------------------
// Ridge
// ----------------------------

/**
 * @constructor
 */
function Pianos4Ridge( points, color, width, opacity )
{
    var myID = null;
    if( !$.isArray( points ) )
    {
        var p = points; // points is in fact a javascript object, which contains
                        // only the data
        // and which we are converting into a Pianos4Ridge object
        assert( 'id' in p && 'color' in p && 'width' in p && 'opacity' in p );
        
        myID = parseInt( p.id );
        points = p.points;
        color = p.color;
        width = p.width;
        opacity = p.opacity;
    }
    
    assert( points.length >= 2 );
    // if (color.length != 7)
    // var breakme = 0;
    assert( color.length == 7 );
    assert( width > 0.0 );
    assert( opacity >= 0.0 && opacity <= 1.0 );
    
    this.id = myID ? myID : Pianos4Annotation._s_ids++;
    this.points = points;
    this.color = color;
    this.width = width;
    this.opacity = opacity;
}

// ----------------------------
// Area
// ----------------------------

/**
 * @constructor
 */
function Pianos4Area( points, color, type, value, holes )
{
    assert( points.length >= 2 );
    assert( color.length == 7 );
    
    this.id = Pianos4Annotation._s_ids++;
    this.points = points;
    this.color = color;
    
    if( typeof ( type ) != 'undefined' )
        this.type = type;
    
    if( typeof ( value ) != 'undefined' )
        this.value = value;
    
    if( typeof ( holes ) != 'undefined' )
        this.holes = holes;
}

Pianos4Area.getPolygonSurface = function( points )
{
    // Use the Surveyor's formula [1] to calculate the area of the polygon
    // [1]: http://www.maa.org/pubs/Calc_articles/ma063.pdf
    assert( points.length >= 3 );
    var p, q;
    var area = 0.0;
    var to = points.length;
    var last = points.length - 1;
    for( var i = 0; i < to; ++i )
    {
        if( i == last )
        {
            p = points[ i ];
            q = points[ 0 ];
        } else
        {
            p = points[ i ];
            q = points[ i + 1 ];
        }
        var det = p[ 0 ] * q[ 1 ] - q[ 0 ] * p[ 1 ];
        area += det;
    }
    // The sign of the result depends on the ordering of the vertices
    // (CCW or CW). Since we have no way of enforcing CCW (actually,
    // CW since or Y axis is reversed - but anyway, we can't enforce one
    // or the other) we just take the absolute value of the result, which
    // is negative if CCW (should be negative if CW if the Y axis was up)
    // and positive if CW.
    return Math.abs( area );
}

Pianos4Area.getSurface = function( area )
{
    var hull = Pianos4Area.getPolygonSurface( area.points );
    var holes = 0.0;
    if( 'holes' in area )
    {
        for( var i in area.holes )
            holes += Pianos4Area.getPolygonSurface( area.holes[ i ] );
    }
    assert( holes <= hull );
    return hull - holes;
}

// ----------------------------
// Comment
// ----------------------------

/**
 * @constructor
 */
function Pianos4Comment( content, color, pos, boxpos )
{
    assert( color.length == 7 );
    
    this.id = Pianos4Annotation._s_ids++;
    this.content = content;
    this.color = color;
    this.pos = pos;
    this.boxpos = boxpos;
}
