/**********************************************************************
 * $Id: InteriorPointLine.cpp 1820 2006-09-06 16:54:23Z mloskot $
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.refractions.net
 *
 * Copyright (C) 2005-2006 Refractions Research Inc.
 * Copyright (C) 2001-2002 Vivid Solutions Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation. 
 * See the COPYING file for more information.
 *
 **********************************************************************
 *
 **********************************************************************/

#include <geos/algorithm/InteriorPointLine.h>
#include <geos/geom/Coordinate.h>
#include <geos/geom/Geometry.h>
#include <geos/geom/GeometryCollection.h>
#include <geos/geom/LineString.h>
#include <geos/geom/CoordinateSequence.h>

#ifndef GEOS_DEBUG
#define GEOS_DEBUG 0
#endif

#ifdef GEOS_DEBUG
#include <iostream>
#endif

using namespace geos::geom;

namespace geos {
namespace algorithm { // geos.algorithm

InteriorPointLine::InteriorPointLine(Geometry *g)
{
	minDistance=DoubleInfinity;
	hasInterior=false;
	if ( g->getCentroid(centroid) )
	{
#if GEOS_DEBUG
		std::cerr << "Centroid: " << centroid << std::endl;
#endif
		addInterior(g);
		if (!hasInterior) addEndpoints(g);
	}
}

InteriorPointLine::~InteriorPointLine()
{
}

/* private
 *
 * Tests the interior vertices (if any)
 * defined by a linear Geometry for the best inside point.
 * If a Geometry is not of dimension 1 it is not tested.
 * @param geom the geometry to add
 */
void
InteriorPointLine::addInterior(const Geometry *geom)
{
	const LineString *ls = dynamic_cast<const LineString*>(geom);
	if ( ls ) {
		addInterior(ls->getCoordinatesRO());
		return;
	}

	const GeometryCollection *gc = dynamic_cast<const GeometryCollection*>(geom);
	if ( gc )
	{
		for(unsigned int i=0, n=gc->getNumGeometries(); i<n; i++) {
			addInterior(gc->getGeometryN(i));
		}
	}
}

void
InteriorPointLine::addInterior(const CoordinateSequence *pts)
{
	unsigned int n=pts->getSize()-1;
	for(unsigned int i=1; i<n; ++i)
	{
		add(pts->getAt(i));
	}
}

/* private
 *
 * Tests the endpoint vertices
 * defined by a linear Geometry for the best inside point.
 * If a Geometry is not of dimension 1 it is not tested.
 * @param geom the geometry to add
 */
void
InteriorPointLine::addEndpoints(const Geometry *geom)
{
	const LineString *ls = dynamic_cast<const LineString*>(geom);
	if ( ls ) {
		addEndpoints(ls->getCoordinatesRO());
		return;
	}

	const GeometryCollection *gc = dynamic_cast<const GeometryCollection*>(geom);
	if ( gc )
	{
		for(unsigned int i=0, n=gc->getNumGeometries(); i<n; i++) {
			addEndpoints(gc->getGeometryN(i));
		}
	}
}

void
InteriorPointLine::addEndpoints(const CoordinateSequence *pts)
{
	add(pts->getAt(0));
	add(pts->getAt(pts->getSize()-1));
}

/*private*/
void
InteriorPointLine::add(const Coordinate& point)
{

	double dist=point.distance(centroid);
#if GEOS_DEBUG
	std::cerr << "point " << point << " dist " << dist << ", minDistance " << minDistance << std::endl;
#endif
	if (!hasInterior || dist<minDistance) {
		interiorPoint=point;
#if GEOS_DEBUG
		std::cerr << " is new InteriorPoint" << std::endl;
#endif
		minDistance=dist;
		hasInterior=true;
	}
}

bool
InteriorPointLine::getInteriorPoint(Coordinate& ret) const
{
	if ( ! hasInterior ) return false;
	ret=interiorPoint;
	return true;
}

} // namespace geos.algorithm
} // namespace geos

/**********************************************************************
 * $Log$
 * Revision 1.18  2006/03/21 11:12:23  strk
 * Cleanups: headers inclusion and Log section
 *
 * Revision 1.17  2006/03/09 16:46:45  strk
 * geos::geom namespace definition, first pass at headers split
 **********************************************************************/

