Ivan Mahonin 9a49d4
Ivan Mahonin 9a49d4
Ivan Mahonin d5090c
#include <tools/assistants/guidelineellipse.h>
Ivan Mahonin 9a49d4
Ivan Mahonin 9a49d4
// TnzCore includes
Ivan Mahonin 9a49d4
#include "tgl.h"
Ivan Mahonin 9a49d4
Ivan Mahonin 9a49d4
Ivan Mahonin 9a49d4
//*****************************************************************************************
Ivan Mahonin 9a49d4
//    TGuidelineEllipse implementation
Ivan Mahonin 9a49d4
//*****************************************************************************************
Ivan Mahonin 9a49d4
Ivan Mahonin 9a49d4
TGuidelineEllipse::TGuidelineEllipse(
Ivan Mahonin 9a49d4
  bool enabled,
Ivan Mahonin 9a49d4
  double magnetism,
Ivan Mahonin 9a49d4
  TAffine matrix
Ivan Mahonin 9a49d4
):
Ivan Mahonin 9a49d4
  TGuideline(enabled, magnetism),
Ivan Mahonin 9a49d4
  matrix(matrix),
Ivan Mahonin 9a49d4
  matrixInv(matrix.inv()) { }
Ivan Mahonin 9a49d4
Ivan Mahonin 9a49d4
Ivan Mahonin 9a49d4
TGuidelineEllipse::TGuidelineEllipse(
Ivan Mahonin 9a49d4
  bool enabled,
Ivan Mahonin 9a49d4
  double magnetism,
Ivan Mahonin 9a49d4
  TAffine matrix,
Ivan Mahonin 9a49d4
  TAffine matrixInv
Ivan Mahonin 9a49d4
):
Ivan Mahonin 9a49d4
  TGuideline(enabled, magnetism),
Ivan Mahonin 9a49d4
  matrix(matrix),
Ivan Mahonin 9a49d4
  matrixInv(matrixInv) { }
Ivan Mahonin 9a49d4
Ivan Mahonin 9a49d4
Ivan Mahonin 9a49d4
TTrackPoint
Ivan Mahonin 9a49d4
TGuidelineEllipse::transformPoint(const TTrackPoint &point) const
Ivan Mahonin 9a49d4
{
Ivan Mahonin 9a49d4
  TTrackPoint p = point;
Ivan Mahonin 9a49d4
  TPointD pp = matrixInv*p.position;
Ivan Mahonin 9a49d4
  double l2 = norm2(pp);
Ivan Mahonin 9a49d4
  if (l2 > TConsts::epsilon*TConsts::epsilon)
Ivan Mahonin 9a49d4
    p.position = matrix*(pp*(1.0/sqrt(l2)));
Ivan Mahonin 9a49d4
  return p;
Ivan Mahonin 9a49d4
}
Ivan Mahonin 9a49d4
Ivan Mahonin 9a49d4
Ivan Mahonin 9a49d4
bool
Ivan Mahonin 9a49d4
TGuidelineEllipse::truncateEllipse(
Ivan Mahonin 9a49d4
  TAngleRangeSet &ranges,
Ivan Mahonin 9a49d4
  const TAffine &ellipseMatrixInv,
Ivan Mahonin 9a49d4
  const TRectD &bounds )
Ivan Mahonin 9a49d4
{
Ivan Mahonin 9a49d4
  if (ranges.isEmpty()) return false;
Ivan Mahonin 9a49d4
  if (bounds.isEmpty()) { ranges.clear(); return false; }
Ivan Mahonin 9a49d4
Ivan Mahonin 9a49d4
  TPointD o  = ellipseMatrixInv*bounds.getP00();
Ivan Mahonin 9a49d4
  TPointD dx = ellipseMatrixInv.transformDirection(TPointD(bounds.getLx(), 0.0));
Ivan Mahonin 9a49d4
  TPointD dy = ellipseMatrixInv.transformDirection(TPointD(0.0, bounds.getLy()));
Ivan Mahonin 9a49d4
  double lx2 = norm2(dx);
Ivan Mahonin 9a49d4
  double ly2 = norm2(dy);
Ivan Mahonin 9a49d4
  if ( lx2 < TConsts::epsilon*TConsts::epsilon
Ivan Mahonin 9a49d4
    || ly2 < TConsts::epsilon*TConsts::epsilon )
Ivan Mahonin 9a49d4
      { ranges.clear(); return false; }
Ivan Mahonin 9a49d4
  TPointD nx = rotate90(dx)*(1.0/sqrt(lx2));
Ivan Mahonin 9a49d4
  TPointD ny = rotate90(dy)*(1.0/sqrt(ly2));
Ivan Mahonin 9a49d4
Ivan Mahonin 9a49d4
  TAngleI ax = TAngleRangeSet::fromDouble(atan(dx));
Ivan Mahonin 9a49d4
  TAngleI ay = TAngleRangeSet::fromDouble(atan(dy));
Ivan Mahonin 9a49d4
Ivan Mahonin 9a49d4
  double sign = nx*dy;
Ivan Mahonin 9a49d4
  if (fabs(sign) <= TConsts::epsilon)
Ivan Mahonin 9a49d4
    { ranges.clear(); return false; }
Ivan Mahonin 9a49d4
Ivan Mahonin 9a49d4
  if (sign < 0.0) {
Ivan Mahonin 9a49d4
    nx = -nx; ny = -ny;
Ivan Mahonin 9a49d4
    ax ^= TAngleRangeSet::half;
Ivan Mahonin 9a49d4
    ay ^= TAngleRangeSet::half;
Ivan Mahonin 9a49d4
  }
Ivan Mahonin 9a49d4
Ivan Mahonin 9a49d4
  TAngleI angles[] = {
Ivan Mahonin 9a49d4
    ax,
Ivan Mahonin 9a49d4
    ax^TAngleRangeSet::half,
Ivan Mahonin 9a49d4
    ay,
Ivan Mahonin 9a49d4
    ay^TAngleRangeSet::half };
Ivan Mahonin 9a49d4
Ivan Mahonin 9a49d4
  double heights[] = {
Ivan Mahonin 9a49d4
    o*nx,
Ivan Mahonin 9a49d4
    -((o+dx+dy)*nx),
Ivan Mahonin 9a49d4
    (o+dx)*ny,
Ivan Mahonin 9a49d4
    -((o+dy)*ny) };
Ivan Mahonin 9a49d4
Ivan Mahonin 9a49d4
  for(int i = 0; i < 4; ++i) {
Ivan Mahonin 9a49d4
    double h = heights[i];
Ivan Mahonin 9a49d4
    if (heights[i] <= TConsts::epsilon - 1.0)
Ivan Mahonin 9a49d4
      continue;
Ivan Mahonin 9a49d4
    if (h >= 1.0 - TConsts::epsilon)
Ivan Mahonin 9a49d4
      { ranges.clear(); return false; }
Ivan Mahonin 9a49d4
    TAngleI a = TAngleRangeSet::fromDouble(asin(h));
Ivan Mahonin 9a49d4
    TAngleI da = angles[i];
Ivan Mahonin 9a49d4
    ranges.subtract(da - a, (da + a)^TAngleRangeSet::half );
Ivan Mahonin 9a49d4
    if (ranges.isEmpty()) return false;
Ivan Mahonin 9a49d4
  }
Ivan Mahonin 9a49d4
Ivan Mahonin 9a49d4
  return true;
Ivan Mahonin 9a49d4
}
Ivan Mahonin 9a49d4
Ivan Mahonin 9a49d4
Ivan Mahonin 9a49d4
int
Ivan Mahonin 9a49d4
TGuidelineEllipse::calcSegmentsCount(const TAffine &ellipseMatrix, double pixelSize) {
Ivan Mahonin 9a49d4
  const TAffine &em = ellipseMatrix;
Ivan Mahonin 9a49d4
  const int min = 4, max = 1000;
Ivan Mahonin 9a49d4
  double r = sqrt(0.5*(norm2(TPointD(em.a11, em.a21)) + norm2(TPointD(em.a12, em.a22))));
Ivan Mahonin 9a49d4
  double h = 0.5*pixelSize/r;
Ivan Mahonin 9a49d4
  if (h <= TConsts::epsilon) return max;
Ivan Mahonin 9a49d4
  if (h >= 1.0 - TConsts::epsilon) return min;
Ivan Mahonin 9a49d4
  double segments = round(M_2PI/acos(1.0 - h));
Ivan Mahonin 9a49d4
  return segments <= (double)min ? min
Ivan Mahonin 9a49d4
       : segments >= (double)max ? max
Ivan Mahonin 9a49d4
       : (int)segments;
Ivan Mahonin 9a49d4
}
Ivan Mahonin 9a49d4
Ivan Mahonin 9a49d4
Ivan Mahonin 9a49d4
void
Ivan Mahonin 9a49d4
TGuidelineEllipse::draw(bool active, bool enabled) const {
Ivan Mahonin 9a49d4
  TAffine4 modelview, projection;
Ivan Mahonin 9a49d4
  glGetDoublev(GL_MODELVIEW_MATRIX, modelview.a);
Ivan Mahonin 9a49d4
  glGetDoublev(GL_PROJECTION_MATRIX, projection.a);
Ivan Mahonin 9a49d4
  TAffine screenMatrix = (projection*modelview).get2d();
Ivan Mahonin 9a49d4
  TAffine screenMatrixInv = screenMatrix.inv();
Ivan Mahonin 9a49d4
  double pixelSize = sqrt(tglGetPixelSize2());
Ivan Mahonin 9a49d4
Ivan Mahonin 9a49d4
  const TRectD oneBox(-1.0, -1.0, 1.0, 1.0);
Ivan Mahonin 9a49d4
  TAngleRangeSet ranges(true);
Ivan Mahonin 9a49d4
  if (!truncateEllipse(ranges, matrixInv*screenMatrixInv, oneBox))
Ivan Mahonin 9a49d4
      return;
Ivan Mahonin 9a49d4
Ivan Mahonin 9a49d4
  int segments = calcSegmentsCount(matrix, pixelSize);
Ivan Mahonin 9a49d4
  double da = M_2PI/segments;
Ivan Mahonin 9a49d4
  double s = sin(da);
Ivan Mahonin 9a49d4
  double c = cos(da);
Ivan Mahonin 9a49d4
Ivan Mahonin 9a49d4
  for(TAngleRangeSet::Iterator i(ranges); i; ++i) {
Ivan Mahonin 9a49d4
    double a0 = i.d0();
Ivan Mahonin 9a49d4
    double a1 = i.d1greater();
Ivan Mahonin 9a49d4
    TPointD r(cos(a0), sin(a0));
Ivan Mahonin 9a49d4
    TPointD p0 = matrix*r;
Ivan Mahonin 9a49d4
    int cnt = (int)floor((a1 - a0)/da);
Ivan Mahonin 9a49d4
    for(int j = 0; j < cnt; ++j) {
Ivan Mahonin 9a49d4
      r = TPointD(r.x*c - r.y*s, r.y*c + r.x*s);
Ivan Mahonin 9a49d4
      TPointD p1 = matrix*r;
Ivan Mahonin 9a49d4
      drawSegment(p0, p1, pixelSize, active, enabled);
Ivan Mahonin 9a49d4
      p0 = p1;
Ivan Mahonin 9a49d4
    }
Ivan Mahonin 9a49d4
    drawSegment(p0, matrix*TPointD(cos(a1), sin(a1)), pixelSize, active, enabled);
Ivan Mahonin 9a49d4
  }
Ivan Mahonin 9a49d4
}
Ivan Mahonin 9a49d4