/******************************************************************************
 * $Id: ilihelper.cpp 17904 2009-10-26 19:22:46Z chaitanya $
 *
 * Project:  Interlis 1/2 Translator
 * Purpose:  Helper functions for Interlis reader
 * Author:   Pirmin Kalberer, Sourcepole AG
 *
 ******************************************************************************
 * Copyright (c) 2004, Pirmin Kalberer, Sourcepole AG
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 ****************************************************************************/


#include "ilihelper.h"


CPL_CVSID("$Id: ilihelper.cpp 17904 2009-10-26 19:22:46Z chaitanya $");


OGRPoint *getARCCenter(OGRPoint *ptStart, OGRPoint *ptArc, OGRPoint *ptEnd) {
  // FIXME precision
  double bx = ptStart->getX(); double by = ptStart->getY();
  double cx = ptArc->getX(); double cy = ptArc->getY();
  double dx = ptEnd->getX(); double dy = ptEnd->getY();
  double temp, bc, cd, det, x, y;

  temp = cx*cx+cy*cy;
  bc = (bx*bx + by*by - temp)/2.0;
  cd = (temp - dx*dx - dy*dy)/2.0;
  det = (bx-cx)*(cy-dy)-(cx-dx)*(by-cy);

  OGRPoint *center = new OGRPoint();

  if (fabs(det) < 1.0e-6) { // could not determin the determinante: too small
    return center;
  }
  det = 1/det;
  x = (bc*(cy-dy)-cd*(by-cy))*det;
  y = ((bx-cx)*cd-(cx-dx)*bc)*det;

  center->setX(x);
  center->setY(y);

  return center;
}

void interpolateArc(OGRLineString* line, OGRPoint *ptStart, OGRPoint *ptOnArc, OGRPoint *ptEnd, double arcIncr) {
  OGRPoint *center = getARCCenter(ptStart, ptOnArc, ptEnd);

  double cx = center->getX(); double cy = center->getY();
  double px = ptOnArc->getX(); double py = ptOnArc->getY();
  double r = sqrt((cx-px)*(cx-px)+(cy-py)*(cy-py));

  double myAlpha = 2.0*acos(1.0-0.002/r);
      
  if (myAlpha < arcIncr)  {
      arcIncr = myAlpha;
  }

  double a1 = atan2(ptStart->getY() - cy, ptStart->getX() - cx);
  double a2 = atan2(py - cy, px - cx);
  double a3 = atan2(ptEnd->getY() - cy, ptEnd->getX() - cx);

  double sweep;

  // Clockwise
  if(a1 > a2 && a2 > a3) {
    sweep = a3 - a1;
  }
  // Counter-clockwise
  else if(a1 < a2 && a2 < a3) {
    sweep = a3 - a1;
  }
  // Clockwise, wrap
  else if((a1 < a2 && a1 > a3) || (a2 < a3 && a1 > a3)) {
    sweep = a3 - a1 + 2*PI;
  }
  // Counter-clockwise, wrap
  else if((a1 > a2 && a1 < a3) || (a2 > a3 && a1 < a3)) {
    sweep = a3 - a1 - 2*PI;
  }
  else {
    sweep = 0.0;
  }

  int ptcount = ceil(fabs(sweep/arcIncr));

  if(sweep < 0) arcIncr *= -1.0;

  double angle = a1;

  for(int i = 0; i < ptcount - 1; i++) {
    angle += arcIncr;

    if(arcIncr > 0.0 && angle > PI) angle -= 2*PI;
    if(arcIncr < 0.0 && angle < -1*PI) angle -= 2*PI;

    double x = cx + r*cos(angle);
    double y = cy + r*sin(angle);
   
    line->addPoint(x, y, 0);

   
    if((angle < a2) && ((angle + arcIncr) > a2)) {
       line->addPoint(ptOnArc);
    }

    if((angle > a2) && ((angle + arcIncr) < a2)) {
       line->addPoint(ptOnArc);
    }
   
  }
  line->addPoint(ptEnd);
  delete center;
}

