3a19fe
3a19fe
3a19fe
// TnzTools includes
3a19fe
#include <tools assistant.h=""></tools>
3a19fe
#include <tools assistants="" guidelineline.h=""></tools>
3a19fe
3a19fe
#include "assistantline.h"
3a19fe
#include "assistantvanishingpoint.h"
3a19fe
3a19fe
// TnzCore includes
3a19fe
#include <tgl.h></tgl.h>
3a19fe
3a19fe
3a19fe
//*****************************************************************************************
3a19fe
//    TAssistantPerspective implementation
3a19fe
//*****************************************************************************************
3a19fe
3a19fe
class TAssistantPerspective final : public TAssistant {
3a19fe
  Q_DECLARE_TR_FUNCTIONS(TAssistantPerspective)
3a19fe
public:
3a19fe
  const TStringId m_idParallelX;
3a19fe
  const TStringId m_idParallelY;
3a19fe
  const TStringId m_idParallelZ;
3a19fe
  const TStringId m_idGridXY;
3a19fe
  const TStringId m_idGridYZ;
3a19fe
  const TStringId m_idGridZX;
3a19fe
3a19fe
protected:
3a19fe
  TAssistantPoint &m_o;
3a19fe
  TAssistantPoint &m_x;
3a19fe
  TAssistantPoint &m_y;
3a19fe
  TAssistantPoint &m_z;
3a19fe
  TAssistantPoint &m_xy;
3a19fe
  TAssistantPoint &m_yz;
3a19fe
  TAssistantPoint &m_zx;
3a19fe
  TAssistantPoint &m_vx;
3a19fe
  TAssistantPoint &m_vy;
3a19fe
  TAssistantPoint &m_vz;
3a19fe
  
3a19fe
public:
3a19fe
  TAssistantPerspective(TMetaObject &object):
3a19fe
    TAssistant(object),
3a19fe
    m_idParallelX("parallelX"),
3a19fe
    m_idParallelY("parallelY"),
3a19fe
    m_idParallelZ("parallelZ"),
3a19fe
    m_idGridXY("gridXY"),
3a19fe
    m_idGridYZ("gridYZ"),
3a19fe
    m_idGridZX("gridZX"),
3a19fe
    m_o    ( addPoint("o",     TAssistantPoint::CircleCross)                           ),
3a19fe
    m_x    ( addPoint("x",     TAssistantPoint::CircleFill,       TPointD(  50,   0 )) ),
3a19fe
    m_y    ( addPoint("y",     TAssistantPoint::CircleFill,       TPointD(   0,  50 )) ),
3a19fe
    m_z    ( addPoint("z",     TAssistantPoint::CircleFill,       TPointD(  25, -25 )) ),
3a19fe
    m_xy   ( addPoint("xy",    TAssistantPoint::Circle,           TPointD(  50,  50 )) ),
3a19fe
    m_yz   ( addPoint("yz",    TAssistantPoint::Circle,           TPointD(  25,  25 )) ),
3a19fe
    m_zx   ( addPoint("zx",    TAssistantPoint::Circle,           TPointD(  75, -25 )) ),
3a19fe
    m_vx   ( addPoint("vx",    TAssistantPoint::Circle)                                ),
3a19fe
    m_vy   ( addPoint("vy",    TAssistantPoint::Circle)                                ),
3a19fe
    m_vz   ( addPoint("vz",    TAssistantPoint::Circle)                                )
3a19fe
  {
3a19fe
    addProperty( new TBoolProperty(m_idParallelX.str(), getParallelX()) );
3a19fe
    addProperty( new TBoolProperty(m_idParallelY.str(), getParallelY()) );
3a19fe
    addProperty( new TBoolProperty(m_idParallelZ.str(), getParallelZ()) );
3a19fe
    addProperty( new TBoolProperty(m_idGridXY.str(), getGridXY()) );
3a19fe
    addProperty( new TBoolProperty(m_idGridYZ.str(), getGridYZ()) );
3a19fe
    addProperty( new TBoolProperty(m_idGridZX.str(), getGridZX()) );
3a19fe
  }
3a19fe
3a19fe
3a19fe
  static QString getLocalName()
3a19fe
    { return tr("Perspective"); }
3a19fe
3a19fe
3a19fe
  void updateTranslation() const override {
3a19fe
    TAssistant::updateTranslation();
3a19fe
    setTranslation(m_idParallelX, tr("Parallel X"));
3a19fe
    setTranslation(m_idParallelY, tr("Parallel Y"));
3a19fe
    setTranslation(m_idParallelZ, tr("Parallel Z"));
3a19fe
    setTranslation(m_idGridXY, tr("Grid XY"));
3a19fe
    setTranslation(m_idGridYZ, tr("Grid YZ"));
3a19fe
    setTranslation(m_idGridZX, tr("Grid ZX"));
3a19fe
  }
3a19fe
3a19fe
3a19fe
  inline bool getParallelX() const
3a19fe
    { return data()[m_idParallelX].getBool(); }
3a19fe
  inline bool getParallelY() const
3a19fe
    { return data()[m_idParallelY].getBool(); }
3a19fe
  inline bool getParallelZ() const
3a19fe
    { return data()[m_idParallelZ].getBool(); }
3a19fe
  inline bool getGridXY() const
3a19fe
    { return data()[m_idGridXY].getBool(); }
3a19fe
  inline bool getGridYZ() const
3a19fe
    { return data()[m_idGridYZ].getBool(); }
3a19fe
  inline bool getGridZX() const
3a19fe
    { return data()[m_idGridZX].getBool(); }
3a19fe
3a19fe
  void onDataChanged(const TVariant &value) override {
3a19fe
    TAssistant::onDataChanged(value);
3a19fe
    m_xy.visible = !getParallelX() || !getParallelY();
3a19fe
    m_yz.visible = !getParallelY() || !getParallelZ();
3a19fe
    m_zx.visible = !getParallelZ() || !getParallelX();
3a19fe
    fixPoints();
3a19fe
  }
3a19fe
3a19fe
3a19fe
private:
3a19fe
  void fixAxisPoint(
3a19fe
    TPointD &a,
3a19fe
    const TAssistantPoint &v,
3a19fe
    const TPointD &oldV ) const
3a19fe
  {
3a19fe
    const TPointD &o = m_o.position;
3a19fe
    if (!v.visible)
3a19fe
      { a = o + v.position; return; }
3a19fe
    
3a19fe
    TPointD dv = v.position - o;
3a19fe
    TPointD oldDv = oldV - o;
3a19fe
    double l = norm2(oldDv);
3a19fe
    double ln = norm2(dv);
3a19fe
    if (!(l > TConsts::epsilon) || !(ln > TConsts::epsilon))
3a19fe
      return;
3a19fe
    
3a19fe
    double d = (a - o)*oldDv;
3a19fe
    a = o + dv*(d/l);
3a19fe
  }
3a19fe
  
3a19fe
3a19fe
  inline void fixAxisPoint(
3a19fe
    TAssistantPoint &a,
3a19fe
    const TAssistantPoint &v,
3a19fe
    const TPointD &oldV ) const
3a19fe
      { fixAxisPoint(a.position, v, oldV); }
3a19fe
3a19fe
  
3a19fe
  void fixVanishingPoint(
3a19fe
    TAssistantPoint &v,
3a19fe
    const TPointD &a,
3a19fe
    const TPointD &oldA ) const
3a19fe
  {
3a19fe
    const TPointD &o = m_o.position;
3a19fe
    TPointD da = a - o;
3a19fe
    if (!v.visible)
3a19fe
      { v.position = da; return; }
3a19fe
    
3a19fe
    TPointD oldDa = oldA - o;
3a19fe
    double l = norm2(oldDa);
3a19fe
    double ln = norm2(da);
3a19fe
    if (!(l > TConsts::epsilon) || !(ln > TConsts::epsilon))
3a19fe
      return;
3a19fe
    
3a19fe
    double d = (v.position - o)*oldDa;
3a19fe
    v.position = o + da*(d/l);
3a19fe
  }
3a19fe
  
3a19fe
3a19fe
  inline void fixVanishingPoint(
3a19fe
    TAssistantPoint &v,
3a19fe
    const TAssistantPoint &a,
3a19fe
    const TPointD &oldA ) const
3a19fe
      { fixVanishingPoint(v, a.position, oldA); }
3a19fe
3a19fe
3a19fe
  void fixVanishingPoint(
3a19fe
    TAssistantPoint &v,
3a19fe
    const TPointD &a0,
3a19fe
    const TPointD &a1,
3a19fe
    const TPointD &b0,
3a19fe
    const TPointD &b1 ) const
3a19fe
  {
3a19fe
    TPointD da = a1 - a0;
3a19fe
    TPointD db = b1 - b0;
3a19fe
    const TPointD ab = b0 - a0;
3a19fe
    double k = db.x*da.y - db.y*da.x;
3a19fe
3a19fe
    if ( (&v == &m_vx && getParallelX())
3a19fe
      || (&v == &m_vy && getParallelY())
3a19fe
      || (&v == &m_vz && getParallelZ()) )
3a19fe
        k = 0;
3a19fe
    
3a19fe
    if (fabs(k) > TConsts::epsilon) {
3a19fe
      double lb = (da.x*ab.y - da.y*ab.x)/k;
3a19fe
      v.position.x = lb*db.x + b0.x;
3a19fe
      v.position.y = lb*db.y + b0.y;
3a19fe
      v.visible = true;
3a19fe
    } else {
3a19fe
      v.position = da;
3a19fe
      v.visible = false;
3a19fe
    }
3a19fe
  }
3a19fe
3a19fe
3a19fe
  inline void fixVanishingPoint(
3a19fe
    TAssistantPoint &v,
3a19fe
    const TAssistantPoint &a0,
3a19fe
    const TAssistantPoint &a1,
3a19fe
    const TAssistantPoint &b0,
3a19fe
    const TAssistantPoint &b1 ) const
3a19fe
      { fixVanishingPoint(v, a0.position, a1.position, b0.position, b1.position); }
3a19fe
3a19fe
  
3a19fe
  static bool lineCross(
3a19fe
    TPointD &p,
3a19fe
    const TPointD &a,
3a19fe
    const TPointD &b,
3a19fe
    const TPointD &da,
3a19fe
    const TPointD &db )
3a19fe
  {
3a19fe
    double d = da.x*db.y - da.y*db.x;
3a19fe
    if (!(fabs(d) > TConsts::epsilon))
3a19fe
      return false;
3a19fe
    d = 1/d;
3a19fe
    p = TPointD(
3a19fe
      (a.y*db.x + b.x*db.y)*da.x - (a.x*da.y + b.y*da.x)*db.x,
3a19fe
      (a.y*da.x + b.x*da.y)*db.y - (a.x*db.y + b.y*db.x)*da.y )*d;
3a19fe
    return true;
3a19fe
  }
3a19fe
  
3a19fe
3a19fe
  void fixSidePoint(
3a19fe
    TPointD &p,
3a19fe
    const TPointD &a, // pass 'a' and 'b' by copy
3a19fe
    const TPointD &b, 
3a19fe
    const TAssistantPoint &va,
3a19fe
    const TAssistantPoint &vb ) const
3a19fe
  {
3a19fe
    
3a19fe
    TPointD da = va.visible ? va.position - a : va.position;
3a19fe
    TPointD db = vb.visible ? vb.position - b : vb.position;
3a19fe
    lineCross(p, a, b, da, db);
3a19fe
  }
3a19fe
3a19fe
3a19fe
  inline void fixSidePoint(
3a19fe
    TAssistantPoint &p,
3a19fe
    const TAssistantPoint &a,
3a19fe
    const TAssistantPoint &b,
3a19fe
    const TAssistantPoint &va,
3a19fe
    const TAssistantPoint &vb ) const
3a19fe
  { fixSidePoint(p.position, a.position, b.position, va, vb); }
3a19fe
3a19fe
3a19fe
  void fixSidePoints() {
3a19fe
    fixSidePoint(m_xy, m_x, m_y, m_vy, m_vx);
3a19fe
    fixSidePoint(m_yz, m_y, m_z, m_vz, m_vy);
3a19fe
    fixSidePoint(m_zx, m_z, m_x, m_vx, m_vz);
3a19fe
  }
3a19fe
3a19fe
  
3a19fe
  void addGuideline(
3a19fe
    const TPointD &position,
3a19fe
    const TAffine &toTool,
3a19fe
    const TAssistantPoint &v,
3a19fe
    TGuidelineList &outGuidelines ) const
3a19fe
  {
3a19fe
    if (v.visible) {
3a19fe
      TPointD p = toTool * v.position;
3a19fe
      if (tdistance2(p, position) > 4*TConsts::epsilon*TConsts::epsilon)
3a19fe
        outGuidelines.push_back(
3a19fe
          new TGuidelineRay(
3a19fe
            getEnabled(),
3a19fe
            getMagnetism(),
3a19fe
            p,
3a19fe
            position ));
3a19fe
    } else {
3a19fe
      TPointD d = toTool.transformDirection(v.position);
3a19fe
      if (norm2(d) > 4*TConsts::epsilon*TConsts::epsilon)
3a19fe
        outGuidelines.push_back(
3a19fe
          new TGuidelineInfiniteLine(
3a19fe
            getEnabled(),
3a19fe
            getMagnetism(),
3a19fe
            position,
3a19fe
            position + d ));
3a19fe
    }
3a19fe
  }
3a19fe
      
3a19fe
public:
3a19fe
  void onFixPoints() override {
3a19fe
    fixVanishingPoint(m_vx, m_o, m_x, m_y, m_xy);
3a19fe
    fixVanishingPoint(m_vy, m_o, m_y, m_x, m_xy);
3a19fe
    fixVanishingPoint(m_vz, m_o, m_z, m_x, m_zx);
3a19fe
    fixSidePoints();
3a19fe
  }
3a19fe
3a19fe
  void onMovePoint(TAssistantPoint &point, const TPointD &position) override {
3a19fe
    if (!point.visible)
3a19fe
      return;
3a19fe
3a19fe
    TPointD old = point.position;
3a19fe
    point.position = position;
3a19fe
    
3a19fe
    if (&point == &m_o) {
3a19fe
      TPointD d = m_o.position - old;
3a19fe
      m_x.position  += d;
3a19fe
      m_y.position  += d;
3a19fe
      m_z.position  += d;
3a19fe
      m_xy.position += d;
3a19fe
      m_yz.position += d;
3a19fe
      m_zx.position += d;
3a19fe
      if (m_vx.visible) m_vx.position += d;
3a19fe
      if (m_vy.visible) m_vy.position += d;
3a19fe
      if (m_vz.visible) m_vz.position += d;
3a19fe
    } else
3a19fe
    if (&point == &m_x) {
3a19fe
      fixVanishingPoint(m_vx, m_x, old);
3a19fe
      fixSidePoints();
3a19fe
    } else
3a19fe
    if (&point == &m_y) {
3a19fe
      fixVanishingPoint(m_vy, m_y, old);
3a19fe
      fixSidePoints();
3a19fe
    } else
3a19fe
    if (&point == &m_z) {
3a19fe
      fixVanishingPoint(m_vz, m_z, old);
3a19fe
      fixSidePoints();
3a19fe
    } else
3a19fe
    if (&point == &m_xy) {
3a19fe
      fixVanishingPoint(m_vx, m_o, m_x, m_y, m_xy);
3a19fe
      fixVanishingPoint(m_vy, m_o, m_y, m_x, m_xy);
3a19fe
      fixSidePoints();
3a19fe
    } else
3a19fe
    if (&point == &m_yz) {
3a19fe
      fixVanishingPoint(m_vy, m_o, m_y, m_z, m_yz);
3a19fe
      fixVanishingPoint(m_vz, m_o, m_z, m_y, m_yz);
3a19fe
      fixSidePoints();
3a19fe
    } else
3a19fe
    if (&point == &m_zx) {
3a19fe
      fixVanishingPoint(m_vz, m_o, m_z, m_x, m_zx);
3a19fe
      fixVanishingPoint(m_vx, m_o, m_x, m_z, m_zx);
3a19fe
      fixSidePoints();
3a19fe
    } else
3a19fe
    if (&point == &m_vx) {
3a19fe
      fixAxisPoint(m_x, m_vx, old);
3a19fe
      fixSidePoints();
3a19fe
    } else
3a19fe
    if (&point == &m_vy) {
3a19fe
      fixAxisPoint(m_y, m_vy, old);
3a19fe
      fixSidePoints();
3a19fe
    } else
3a19fe
    if (&point == &m_vz) {
3a19fe
      fixAxisPoint(m_z, m_vz, old);
3a19fe
      fixSidePoints();
3a19fe
    }
3a19fe
  }
3a19fe
3a19fe
  void getGuidelines(
3a19fe
    const TPointD &position,
3a19fe
    const TAffine &toTool,
3a19fe
    TGuidelineList &outGuidelines ) const override
3a19fe
  {
3a19fe
    addGuideline(position, toTool, m_vx, outGuidelines);
3a19fe
    addGuideline(position, toTool, m_vy, outGuidelines);
3a19fe
    addGuideline(position, toTool, m_vz, outGuidelines);
3a19fe
  }
3a19fe
3a19fe
  void drawGrid(
3a19fe
    const TAssistantPoint &vx,
3a19fe
    const TAssistantPoint &vy,
3a19fe
    const TPointD &y ) const
3a19fe
  {
3a19fe
    double alpha = getDrawingGridAlpha();
3a19fe
    const TPointD &o = m_o.position;
3a19fe
    
3a19fe
    if (!vx.visible && !vy.visible) {
3a19fe
      TAssistantLine::drawGrid(
3a19fe
        o, o + vx.position, o, y, false, false, false, alpha );
3a19fe
      return;
3a19fe
    }
3a19fe
    
3a19fe
    if (!vx.visible) {
3a19fe
      TAssistantLine::drawGrid(
3a19fe
        vy.position, vy.position + vx.position, o, y, false, false, true, alpha );
3a19fe
      return;
3a19fe
    }
3a19fe
    
3a19fe
    TPointD p = y;
3a19fe
    if (vy.visible) {
3a19fe
      const TPointD &a = vx.position;
3a19fe
      const TPointD &b = o;
3a19fe
      const TPointD da = y - a;
3a19fe
      const TPointD db = vy.position - vx.position;
3a19fe
      lineCross(p, a, b, da, db);
3a19fe
    }
3a19fe
    
3a19fe
    TAssistantVanishingPoint::drawPerspectiveGrid(vx.position, o, p, alpha);
3a19fe
  }
3a19fe
  
3a19fe
  void drawVanishingPoint(const TAssistantPoint &v, double pixelSize, double alpha) const {
3a19fe
    if (!v.visible)
3a19fe
      return;
3a19fe
    const TPointD &p = v.position;
3a19fe
    TPointD dx(20.0*pixelSize, 0.0);
3a19fe
    TPointD dy(0.0, 10.0*pixelSize);
3a19fe
    drawSegment(p-dx-dy, p+dx+dy, pixelSize, alpha);
3a19fe
    drawSegment(p-dx+dy, p+dx-dy, pixelSize, alpha);
3a19fe
  }
3a19fe
3a19fe
  void draw(TToolViewer*, bool enabled) const override {
3a19fe
    double pixelSize = sqrt(tglGetPixelSize2());
3a19fe
    double alpha = getDrawingAlpha(enabled);
3a19fe
    drawVanishingPoint(m_vx, pixelSize, alpha);
3a19fe
    drawVanishingPoint(m_vy, pixelSize, alpha);
3a19fe
    drawVanishingPoint(m_vz, pixelSize, alpha);
3a19fe
    if (getGridXY()) {
3a19fe
      drawGrid(m_vx, m_vy, m_y.position);
3a19fe
      drawGrid(m_vy, m_vx, m_x.position);
3a19fe
    }
3a19fe
    if (getGridYZ()) {
3a19fe
      drawGrid(m_vy, m_vz, m_z.position);
3a19fe
      drawGrid(m_vz, m_vy, m_y.position);
3a19fe
    }
3a19fe
    if (getGridZX()) {
3a19fe
      drawGrid(m_vz, m_vx, m_x.position);
3a19fe
      drawGrid(m_vx, m_vz, m_z.position);
3a19fe
    }
3a19fe
  }
3a19fe
3a19fe
  void drawEdit(TToolViewer *viewer) const override {
3a19fe
    double pixelSize = sqrt(tglGetPixelSize2());
3a19fe
    TPointD xyz;
3a19fe
    fixSidePoint(xyz, m_xy.position, m_zx.position, m_vz, m_vy);
3a19fe
    drawSegment(xyz, m_xy.position, pixelSize);
3a19fe
    drawSegment(xyz, m_yz.position, pixelSize);
3a19fe
    drawSegment(xyz, m_zx.position, pixelSize);
3a19fe
    drawSegment(m_xy.position, m_x.position, pixelSize);
3a19fe
    drawSegment(m_xy.position, m_y.position, pixelSize);
3a19fe
    drawSegment(m_yz.position, m_y.position, pixelSize);
3a19fe
    drawSegment(m_yz.position, m_z.position, pixelSize);
3a19fe
    drawSegment(m_zx.position, m_z.position, pixelSize);
3a19fe
    drawSegment(m_zx.position, m_x.position, pixelSize);
3a19fe
    drawSegment(m_o.position, m_x.position, pixelSize);
3a19fe
    drawSegment(m_o.position, m_y.position, pixelSize);
3a19fe
    drawSegment(m_o.position, m_z.position, pixelSize);
3a19fe
    TAssistant::drawEdit(viewer);
3a19fe
  }
3a19fe
};
3a19fe
3a19fe
3a19fe
//*****************************************************************************************
3a19fe
//    Registration
3a19fe
//*****************************************************************************************
3a19fe
3a19fe
static TAssistantTypeT<tassistantperspective> assistantPerspective("assistantPerspective");</tassistantperspective>