/*
* Copyright (c) 2016 Metron, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Metron, Inc. nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL METRON, INC. BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.metsci.glimpse.charts.shoreline;
import java.util.ArrayList;
import java.util.List;
/**
* @author hogye
*/
public class LandSegmentFactory
{
private final LandBox box;
public LandSegmentFactory( LandBox box )
{
this.box = box;
}
/**
* The returned LandSegment may have land on the wrong side. It is up
* to the calling code to detect this and correct for it.
*/
public LandSegment newLandSegment( List<LandVertex> vertices )
{
LandVertex start = vertices.get( 0 );
LandVertex end = vertices.get( vertices.size( ) - 1 );
if ( start.equals( end ) ) return LandSegment.newFillableSegment( vertices );
Edge startEdge = Edge.NONE;
if ( start.lat >= box.northLat )
startEdge = Edge.NORTH;
else if ( start.lat <= box.southLat )
startEdge = Edge.SOUTH;
else if ( start.lon >= box.eastLon )
startEdge = Edge.EAST;
else if ( start.lon <= box.westLon ) startEdge = Edge.WEST;
Edge endEdge = Edge.NONE;
if ( end.lat >= box.northLat )
endEdge = Edge.NORTH;
else if ( end.lat <= box.southLat )
endEdge = Edge.SOUTH;
else if ( end.lon >= box.eastLon )
endEdge = Edge.EAST;
else if ( end.lon <= box.westLon ) endEdge = Edge.WEST;
if ( startEdge == Edge.NONE || endEdge == Edge.NONE ) return LandSegment.newUnfillableSegment( vertices );
List<LandVertex> ghostVertices = new ArrayList<LandVertex>( );
if ( startEdge.isSame( endEdge ) )
{
// No ghost vertices needed
}
else if ( startEdge.isOpposite( endEdge ) )
{
switch ( startEdge )
{
case NORTH:
case SOUTH:
ghostVertices.add( new LandVertex( end.lat, box.eastLon ) );
ghostVertices.add( new LandVertex( start.lat, box.eastLon ) );
break;
case EAST:
case WEST:
ghostVertices.add( new LandVertex( box.northLat, end.lon ) );
ghostVertices.add( new LandVertex( box.northLat, start.lon ) );
break;
case NONE:
}
}
else if ( startEdge.isAdjacent( endEdge ) )
{
switch ( startEdge )
{
case NORTH:
case SOUTH:
ghostVertices.add( new LandVertex( start.lat, end.lon ) );
break;
case EAST:
case WEST:
ghostVertices.add( new LandVertex( end.lat, start.lon ) );
break;
case NONE:
}
}
return LandSegment.newFillableSegment( vertices, ghostVertices );
}
private static enum Edge
{
NONE, EAST, WEST, NORTH, SOUTH;
public boolean isSame( Edge edge )
{
return ( this != NONE && this == edge );
}
public boolean isOpposite( Edge edge )
{
switch ( this )
{
case EAST:
return edge == WEST;
case WEST:
return edge == EAST;
case NORTH:
return edge == SOUTH;
case SOUTH:
return edge == NORTH;
default:
return false;
}
}
public boolean isAdjacent( Edge edge )
{
switch ( this )
{
case EAST:
return edge == NORTH || edge == SOUTH;
case WEST:
return edge == NORTH || edge == SOUTH;
case NORTH:
return edge == EAST || edge == WEST;
case SOUTH:
return edge == EAST || edge == WEST;
default:
return false;
}
}
}
}