166af2
166af2
166af2
// TnzTools includes
d9135c
#include "assistantline.h"
d5090c
166af2
166af2
166af2
//*****************************************************************************************
166af2
//    TAssistantLine implementation
166af2
//*****************************************************************************************
166af2
166af2
d9135c
TAssistantLine::TAssistantLine(TMetaObject &object):
d9135c
  TAssistant(object),
d9135c
  m_idRestricktA("restrictA"),
d9135c
  m_idRestricktB("restrictB"),
d9135c
  m_idParallel("parallel"),
d9135c
  m_idGrid("grid"),
d9135c
  m_idPerspective("perspective"),
d9135c
  m_a( addPoint("a", TAssistantPoint::CircleCross) ),
d9135c
  m_b( addPoint("b", TAssistantPoint::Circle, TPointD(100.0, 0.0)) ),
d9135c
  m_grid0( addPoint("grid0",  TAssistantPoint::CircleDoubleDots, TPointD(  0.0,-50.0)) ),
d9135c
  m_grid1( addPoint("grid1",  TAssistantPoint::CircleDots,       TPointD( 25.0,-75.0)) )
d9135c
{
d9135c
  addProperty( new TBoolProperty(m_idRestricktA.str(), getRestrictA()) );
d9135c
  addProperty( new TBoolProperty(m_idRestricktB.str(), getRestrictB()) );
d9135c
  addProperty( new TBoolProperty(m_idParallel.str(), getParallel()) );
d9135c
  addProperty( new TBoolProperty(m_idGrid.str(), getGrid()) );
d9135c
  addProperty( new TBoolProperty(m_idPerspective.str(), getPerspective()) );
d9135c
}
d9135c
d9135c
d9135c
QString TAssistantLine::getLocalName()
d9135c
  { return tr("Line"); }
d9135c
d9135c
d9135c
void TAssistantLine::updateTranslation() const {
d9135c
  TAssistant::updateTranslation();
d9135c
  setTranslation(m_idRestricktA, tr("Restrict A"));
d9135c
  setTranslation(m_idRestricktB, tr("Restrict B"));
d9135c
  setTranslation(m_idParallel, tr("Parallel"));
d9135c
  setTranslation(m_idGrid, tr("Grid"));
d9135c
  setTranslation(m_idPerspective, tr("Perspective"));
d9135c
}
d9135c
d9135c
d9135c
void TAssistantLine::onDataChanged(const TVariant &value) {
d9135c
  TAssistant::onDataChanged(value);
d9135c
  m_grid0.visible = getGrid()
d9135c
                  || (getParallel() && (getRestrictA() || getRestrictB()));
d9135c
  m_grid1.visible = getGrid();
d9135c
}
d9135c
d9135c
d9135c
void TAssistantLine::fixGrid(const TPointD &prevA, const TPointD &prevB) {
d9135c
  TPointD dx0 = prevB - prevA;
d9135c
  TPointD dx1 = m_b.position - m_a.position;
d9135c
  double l0 = norm2(dx0);
d9135c
  double l1 = norm2(dx1);
d9135c
  if (!( l0 > TConsts::epsilon*TConsts::epsilon
d9135c
     &&  l1 > TConsts::epsilon*TConsts::epsilon )) return;
d9135c
  dx0 *= 1/sqrt(l0);
d9135c
  dx1 *= 1/sqrt(l1);
d9135c
  TPointD dy0(-dx0.y, dx0.x);
d9135c
  TPointD dy1(-dx1.y, dx1.x);
d9135c
d9135c
  if (getParallel()) {
166af2
    TPointD g1 = m_grid1.position - m_grid0.position;
d9135c
    m_grid1.position = m_grid0.position + g1*dx0*dx1 + g1*dy0*dy1;
d9135c
  } else {
d9135c
    TPointD g0 = m_grid0.position - prevA;
d9135c
    TPointD g1 = m_grid1.position - prevA;
d9135c
    m_grid0.position = m_a.position + g0*dx0*dx1 + g0*dy0*dy1;
d9135c
    m_grid1.position = m_a.position + g1*dx0*dx1 + g1*dy0*dy1;
166af2
  }
d9135c
}
d9135c
d9135c
d9135c
void TAssistantLine::onMovePoint(TAssistantPoint &point, const TPointD &position) {
d9135c
  TPointD prevA = m_a.position;
d9135c
  TPointD prevB = m_b.position;
d9135c
  point.position = position;
de8863
  if (&point == &m_a)
de8863
    m_b.position += m_a.position - prevA;
d9135c
  if (&point != &m_grid1)
d9135c
    fixGrid(prevA, prevB);
d9135c
}
d9135c
d9135c
d9135c
void TAssistantLine::getGuidelines(
d9135c
  const TPointD &position,
d9135c
  const TAffine &toTool,
d9135c
  TGuidelineList &outGuidelines ) const
d9135c
{
d9135c
  bool restrictA = getRestrictA();
d9135c
  bool restrictB = getRestrictB();
d9135c
  bool parallel = getParallel();
d9135c
  bool perspective = getPerspective();
d9135c
d9135c
  TPointD a = toTool*m_a.position;
d9135c
  TPointD b = toTool*m_b.position;
d9135c
  TPointD ab = b - a;
d9135c
  double abLen2 = norm2(ab);
d9135c
  if (abLen2 < TConsts::epsilon*TConsts::epsilon) return;
d9135c
d9135c
  if (parallel) {
d9135c
    TPointD abp = rotate90(ab);
d9135c
    TPointD ag = toTool*m_grid0.position - a;
d9135c
    double k = abp*ag;
d9135c
    if (fabs(k) <= TConsts::epsilon) {
d9135c
      if (restrictA || restrictB) return;
d9135c
      a = position;
d9135c
    } else {
d9135c
      k = (abp*(position - a))/k;
d9135c
      a = a + ag*k;
166af2
    }
d9135c
    if (perspective && (restrictA || restrictB))
d9135c
      ab = ab*k;
d9135c
    b = a + ab;
166af2
  }
166af2
d9135c
  if (restrictA && restrictB)
d9135c
    outGuidelines.push_back(TGuidelineP(
d9135c
      new TGuidelineLine(
d9135c
        getEnabled(), getMagnetism(), a,  b )));
d9135c
  else if (restrictA)
d9135c
    outGuidelines.push_back(TGuidelineP(
d9135c
      new TGuidelineRay(
d9135c
        getEnabled(), getMagnetism(), a,  b )));
d9135c
  else if (restrictB)
d9135c
    outGuidelines.push_back(TGuidelineP(
d9135c
      new TGuidelineRay(
d9135c
        getEnabled(), getMagnetism(), b,  a ))); // b first
d9135c
  else
d9135c
    outGuidelines.push_back(TGuidelineP(
d9135c
      new TGuidelineInfiniteLine(
d9135c
        getEnabled(), getMagnetism(), a,  b )));
d9135c
}
d9135c
d9135c
d9135c
void TAssistantLine::drawRuler(
d9135c
  const TPointD &a,
d9135c
  const TPointD &b,
d9135c
  const TPointD &grid0,
d9135c
  const TPointD &grid1,
d9135c
  const TPointD *perspectiveBase,
d9135c
  double alpha )
d9135c
{
d9135c
  double pixelSize = sqrt(tglGetPixelSize2());
d9135c
  double minStep = (perspectiveBase ? 5 : 10)*pixelSize;
d9135c
d9135c
  TPointD direction = b - a;
d9135c
  double l2 = norm2(direction);
d9135c
  if (l2 <= TConsts::epsilon*TConsts::epsilon) return;
d9135c
  double dirLen = sqrt(l2);
d9135c
  TPointD dirProj = direction*(1.0/l2);
d9135c
  TPointD normal = TPointD(-direction.y, direction.x)*(1.0/dirLen);
d9135c
d9135c
  double xg0 = dirProj*(grid0 - a);
d9135c
  double xg1 = dirProj*(grid1 - a);
d9135c
d9135c
  if (perspectiveBase) {
d9135c
    // draw perspective
d9135c
    double xa0 = dirProj*(*perspectiveBase - a);
d9135c
    double w, i0, i1;
d9135c
    if (!calcPerspectiveStep(minStep/dirLen, 0, 1, xa0, xg0, xg1, w, i0, i1)) return;
d9135c
    for(double i = i0; i < i1; i += 1) {
d9135c
      double x = xa0 + 1/(i*w + 1);
d9135c
      drawMark(a + direction*x, normal, pixelSize, alpha);
166af2
    }
d9135c
  } else {
d9135c
    // draw linear
d9135c
    double dx = fabs(xg1 - xg0);
d9135c
    if (dx*dirLen < minStep) return;
d9135c
    for(double x = xg0 - floor(xg0/dx)*dx; x < 1.0; x += dx)
d9135c
      drawMark(a + direction*x, normal, pixelSize, alpha);
d9135c
  }
d9135c
}
d9135c
d9135c
d9135c
void TAssistantLine::drawLine(
d9135c
  const TAffine &matrix,
d9135c
  const TAffine &matrixInv,
d9135c
  double pixelSize,
d9135c
  const TPointD &a,
d9135c
  const TPointD &b,
d9135c
  bool restrictA,
d9135c
  bool restrictB,
d9135c
  double alpha )
d9135c
{
d9135c
  const TRectD oneBox(-1.0, -1.0, 1.0, 1.0);
d9135c
  TPointD aa = matrix*a;
d9135c
  TPointD bb = matrix*b;
d9135c
  if ( restrictA && restrictB ? TGuidelineLineBase::truncateLine(oneBox, aa, bb)
d9135c
      : restrictA             ? TGuidelineLineBase::truncateRay (oneBox, aa, bb)
d9135c
      : restrictB             ? TGuidelineLineBase::truncateRay (oneBox, bb, aa) // aa first
d9135c
      :                 TGuidelineLineBase::truncateInfiniteLine(oneBox, aa, bb) )
d9135c
        drawSegment(matrixInv*aa, matrixInv*bb, pixelSize, alpha);
d9135c
}
d9135c
d9135c
d9135c
void TAssistantLine::drawGrid(
d9135c
  const TPointD &a,
d9135c
  const TPointD &b,
d9135c
  const TPointD &grid0,
d9135c
  const TPointD &grid1,
d9135c
  bool restrictA,
d9135c
  bool restrictB,
d9135c
  bool perspective,
d9135c
  double alpha )
d9135c
{
d9135c
  TAffine4 modelview, projection;
d9135c
  glGetDoublev(GL_MODELVIEW_MATRIX, modelview.a);
d9135c
  glGetDoublev(GL_PROJECTION_MATRIX, projection.a);
d9135c
  TAffine matrix = (projection*modelview).get2d();
d9135c
  TAffine matrixInv = matrix.inv();
d9135c
  double pixelSize = sqrt(tglGetPixelSize2());
d9135c
  double minStep = (perspective ? 2.5 : 10)*pixelSize;
d9135c
d9135c
  TPointD ab = b - a;
d9135c
  double abLen2 = norm2(ab);
d9135c
  if (abLen2 < TConsts::epsilon*TConsts::epsilon) return;
d9135c
  double abLen = sqrt(abLen2);
d9135c
d9135c
  TPointD abp = rotate90(ab);
d9135c
  TPointD ag = grid0 - a;
d9135c
  if (fabs(abp*ag) <= TConsts::epsilon) {
d9135c
    if (restrictA || restrictB) return;
d9135c
    ag = abp;
d9135c
  }
d9135c
  double agLen2 = norm2(ag);
d9135c
  if (agLen2 < TConsts::epsilon*TConsts::epsilon) return;
d9135c
  double abpAgK = 1.0/(abp*ag);
d9135c
  TPointD abpAgProj = abp*abpAgK;
d9135c
d9135c
  // draw restriction lines
d9135c
  if (perspective) {
d9135c
    if (restrictA) drawLine(matrix, matrixInv, pixelSize, a, a + ag, false, false, alpha);
d9135c
    if (restrictB) drawLine(matrix, matrixInv, pixelSize, a, a + ag + ab, false, false, alpha);
d9135c
    // horizon
d9135c
    if (!restrictA) drawLine(matrix, matrixInv, pixelSize, a - ab, a, restrictA, restrictB, alpha); else
d9135c
    if (!restrictB) drawLine(matrix, matrixInv, pixelSize, a, a + ab, restrictA, restrictB, alpha);
d9135c
  } else {
d9135c
    if (restrictA) drawLine(matrix, matrixInv, pixelSize, a, a + ag, false, false, alpha);
d9135c
    if (restrictB) drawLine(matrix, matrixInv, pixelSize, b, b + ag, false, false, alpha);
166af2
  }
166af2
d9135c
  double minStepX = fabs(minStep*abLen*abpAgK);
d9135c
  if (minStepX <= TConsts::epsilon) return;
d9135c
d9135c
  // calculate bounds
d9135c
  const TRectD oneBox(-1.0, -1.0, 1.0, 1.0);
d9135c
  TPointD corners[4] = {
d9135c
    TPointD(oneBox.x0, oneBox.y0),
d9135c
    TPointD(oneBox.x0, oneBox.y1),
d9135c
    TPointD(oneBox.x1, oneBox.y0),
d9135c
    TPointD(oneBox.x1, oneBox.y1) };
d9135c
  double minX = 0.0, maxX = 0.0;
d9135c
  for(int i = 0; i < 4; ++i) {
d9135c
    double x = abpAgProj * (matrixInv*corners[i] - a);
d9135c
    if (i == 0 || x < minX) minX = x;
d9135c
    if (i == 0 || x > maxX) maxX = x;
166af2
  }
d9135c
  if (maxX <= minX) return;
166af2
d9135c
  double x0 = abpAgProj*(grid0 - a);
d9135c
  double x1 = abpAgProj*(grid1 - a);
166af2
d9135c
  if (perspective) {
d9135c
    double w, i0, i1;
d9135c
    minStepX /= 2;
d9135c
    
d9135c
    if (!calcPerspectiveStep(minStepX, minX, maxX, 0, x0, x1, w, i0, i1)) return;
d9135c
    double abk = 1.0/fabs(x0);
d9135c
    for(double i = i0; i < i1; i += 1) {
d9135c
      double x = 1/(i*w + 1);
d9135c
      
d9135c
      double curStep = fabs(w*x*x);
d9135c
      double curAlpha = (curStep - minStepX)/minStepX;
d9135c
      if (curAlpha < 0) continue;
d9135c
      if (curAlpha > 1) curAlpha = 1;
d9135c
      
d9135c
      TPointD ca = a + ag*x;
d9135c
      TPointD cb = ca + ab*(abk*x);
d9135c
      drawLine(matrix, matrixInv, pixelSize, ca, cb, restrictA, restrictB, alpha*curAlpha);
166af2
    }
d9135c
  } else {
d9135c
    double dx = fabs(x1 - x0);
d9135c
    if (dx < minStepX) return;
d9135c
    for(double x = x0 + ceil((minX - x0)/dx)*dx; x < maxX; x += dx) {
d9135c
      TPointD ca = a + ag*x;
d9135c
      drawLine(matrix, matrixInv, pixelSize, ca, ca + ab, restrictA, restrictB, alpha);
166af2
    }
d9135c
  }
d9135c
}
d9135c
d9135c
d9135c
void TAssistantLine::draw(TToolViewer*, bool enabled) const {
d9135c
  double alpha = getDrawingAlpha(enabled);
d9135c
  bool restrictA = getRestrictA();
d9135c
  bool restrictB = getRestrictB();
d9135c
  bool parallel = getParallel();
d9135c
  bool grid = getGrid();
d9135c
  bool perspective = getPerspective();
d9135c
d9135c
  // common data about viewport
d9135c
  const TRectD oneBox(-1.0, -1.0, 1.0, 1.0);
d9135c
  TAffine4 modelview, projection;
d9135c
  glGetDoublev(GL_MODELVIEW_MATRIX, modelview.a);
d9135c
  glGetDoublev(GL_PROJECTION_MATRIX, projection.a);
d9135c
  TAffine matrix = (projection*modelview).get2d();
d9135c
  TAffine matrixInv = matrix.inv();
d9135c
  double pixelSize = sqrt(tglGetPixelSize2());
d9135c
d9135c
  // calculate range
d9135c
  TPointD aa = matrix*m_a.position;
d9135c
  TPointD bb = matrix*m_b.position;
d9135c
  bool success = false;
d9135c
  if (restrictA && restrictB)
d9135c
    success = TGuidelineLineBase::truncateLine(oneBox, aa, bb);
d9135c
  else if (restrictA)
d9135c
    success = TGuidelineLineBase::truncateRay(oneBox, aa, bb);
d9135c
  else if (restrictB)
d9135c
    success = TGuidelineLineBase::truncateRay(oneBox, bb, aa);
d9135c
  else
d9135c
    success = TGuidelineLineBase::truncateInfiniteLine(oneBox, aa, bb);
d9135c
d9135c
  if (!success) {
d9135c
    // line is out of screen, bud grid still can be visible
d9135c
    if (grid && getParallel())
d9135c
        drawGrid(
d9135c
          m_a.position,
d9135c
          m_b.position,
d9135c
          m_grid0.position,
d9135c
          m_grid1.position,
d9135c
          restrictA,
d9135c
          restrictB,
d9135c
          perspective,
d9135c
          getDrawingGridAlpha() );
d9135c
    return;
d9135c
  }
d9135c
  
d9135c
  TPointD a = matrixInv*aa;
d9135c
  TPointD b = matrixInv*bb;
d9135c
d9135c
  // draw line
d9135c
  drawSegment(a, b, pixelSize, alpha);
d9135c
d9135c
  // draw restriction marks
d9135c
  if (restrictA || (!parallel && grid && perspective))
d9135c
    drawDot(m_a.position);
d9135c
  if (restrictB)
d9135c
    drawDot(m_b.position);
d9135c
d9135c
  if (grid) {
d9135c
    if (getParallel()) {
d9135c
      drawGrid(
d9135c
        m_a.position,
d9135c
        m_b.position,
d9135c
        m_grid0.position,
d9135c
        m_grid1.position,
d9135c
        restrictA,
d9135c
        restrictB,
d9135c
        perspective,
d9135c
        getDrawingGridAlpha() );
166af2
    } else {
d9135c
      drawRuler(
d9135c
        a, b, m_grid0.position, m_grid1.position,
d9135c
        perspective ? &m_a.position : nullptr, getDrawingAlpha() );
166af2
    }
166af2
  }
d9135c
}
166af2
166af2
166af2
166af2
//*****************************************************************************************
166af2
//    Registration
166af2
//*****************************************************************************************
166af2
166af2
static TAssistantTypeT<tassistantline> assistantLine("assistantLine");</tassistantline>