da847a
da847a
da847a
// TnzTools includes
da847a
#include <tools replicator.h=""></tools>
da847a
#include <tools modifierclone.h="" modifiers=""></tools>
da847a
da847a
da847a
// TnzCore includes
da847a
#include <tgl.h></tgl.h>
da847a
da847a
da847a
//*****************************************************************************************
da847a
//    TReplicatorAffine implementation
da847a
//*****************************************************************************************
da847a
da847a
class TReplicatorAffine final : public TReplicator {
da847a
  Q_DECLARE_TR_FUNCTIONS(TReplicatorAffine)
da847a
public:
da847a
  const TStringId m_idFixScale;
da847a
  const TStringId m_idFixAspect;
da847a
  const TStringId m_idFixAngle;
da847a
  const TStringId m_idFixSkew;
da847a
  const TStringId m_idCount;
da847a
  const TStringId m_idCountInv;
da847a
  const TStringId m_idPressure;
da847a
da847a
protected:
da847a
  TAssistantPoint &m_center0;
da847a
  TAssistantPoint &m_a0;
da847a
  TAssistantPoint &m_b0;
da847a
  TAssistantPoint &m_center1;
da847a
  TAssistantPoint &m_a1;
da847a
  TAssistantPoint &m_b1;
da847a
da847a
public:
da847a
  TReplicatorAffine(TMetaObject &object):
da847a
    TReplicator(object),
da847a
    m_idFixScale("fixScale"),
da847a
    m_idFixAspect("fixAspect"),
da847a
    m_idFixAngle("fixAngle"),
da847a
    m_idFixSkew("fixSkew"),
da847a
    m_idCount("count"),
da847a
    m_idCountInv("countInv"),
da847a
    m_idPressure("pressure"),
da847a
    m_center0( addPoint("center0", TAssistantPoint::CircleCross) ),
da847a
    m_a0     ( addPoint("a0",      TAssistantPoint::CircleFill, TPointD(40,  0)) ),
da847a
    m_b0     ( addPoint("b0",      TAssistantPoint::Circle,     TPointD( 0, 40)) ),
da847a
    m_center1( addPoint("center1", TAssistantPoint::Circle,     TPointD(50,  0)) ),
da847a
    m_a1     ( addPoint("a1",      TAssistantPoint::CircleFill, TPointD(90,  0)) ),
da847a
    m_b1     ( addPoint("b1",      TAssistantPoint::Circle,     TPointD(50, 40)) )
da847a
  {
da847a
    addProperty( new TBoolProperty(m_idFixScale.str(),  getFixScale()) );
da847a
    addProperty( new TBoolProperty(m_idFixAspect.str(), getFixAspect()) );
da847a
    addProperty( new TBoolProperty(m_idFixAngle.str(),  getFixAngle()) );
da847a
    addProperty( new TBoolProperty(m_idFixSkew.str(),   getFixSkew()) );
da847a
    addProperty( createCountProperty(m_idCount, getCount(), 0) );
da847a
    addProperty( createCountProperty(m_idCountInv, getCountInv(), 0) );
da847a
    addProperty( new TDoubleProperty(m_idPressure.str(), 0.0, 2.0, getPressure()) );
da847a
  }
da847a
da847a
  
da847a
  static QString getLocalName()
da847a
    { return tr("Replicator Affine"); }
da847a
da847a
    
da847a
  void updateTranslation() const override {
da847a
    TReplicator::updateTranslation();
da847a
    setTranslation(m_idFixScale, tr("Fix Scale"));
da847a
    setTranslation(m_idFixAspect, tr("Fix Aspect"));
da847a
    setTranslation(m_idFixAngle, tr("Fix Angle"));
da847a
    setTranslation(m_idFixSkew, tr("Fix Skew"));
da847a
    setTranslation(m_idCount, tr("Count"));
da847a
    setTranslation(m_idCountInv, tr("Inv. Count"));
da847a
    setTranslation(m_idPressure, tr("Pressure"));
da847a
  }
da847a
da847a
  
da847a
  inline bool getFixScale() const
da847a
    { return data()[m_idFixScale].getBool(); }
da847a
  inline bool getFixAspect() const
da847a
    { return data()[m_idFixAspect].getBool(); }
da847a
  inline bool getFixAngle() const
da847a
    { return data()[m_idFixAngle].getBool(); }
da847a
  inline bool getFixSkew() const
da847a
    { return data()[m_idFixSkew].getBool(); }
da847a
  inline int getCount() const
da847a
    { return (int)data()[m_idCount].getDouble(); }
da847a
  inline int getCountInv() const
da847a
    { return (int)data()[m_idCountInv].getDouble(); }
da847a
  inline double getPressure() const
da847a
    { return data()[m_idPressure].getDouble(); }
da847a
da847a
protected:
da847a
  inline void setCount(int x)
da847a
    { if (getCount() != (double)x) data()[m_idCount].setDouble((double)x); }
da847a
  inline void setCountInv(int x)
da847a
    { if (getCountInv() != (double)x) data()[m_idCountInv].setDouble((double)x); }
da847a
  inline void setPressure(double x)
da847a
    { if (getPressure() != x) data()[m_idPressure].setDouble(x); }
da847a
da847a
    
da847a
  void onSetDefaults() override {
da847a
    setCount(1);
da847a
    setPressure(1);
da847a
    TReplicator::onSetDefaults();
da847a
  }
da847a
da847a
  
da847a
  void onFixData() override {
da847a
    TReplicator::onFixData();
da847a
    setCount( std::max(0, std::min(multiplierSoftLimit - 1, getCount())) );
da847a
    setCountInv( std::max(0, std::min(multiplierSoftLimit - 1, getCountInv())) );
da847a
    setPressure( std::max(0.0, std::min(2.0, getPressure())) );
da847a
  }
da847a
da847a
da847a
  TAffine getAffine(const TAffine &toTool = TAffine()) const {
da847a
    TPointD c, x, y;
da847a
    c = toTool*m_center0.position;
da847a
    x = toTool*m_a0.position - c;
da847a
    y = toTool*m_b0.position - c;
da847a
    TAffine t0( x.x, y.x, c.x,
da847a
                x.y, y.y, c.y );
da847a
    c = toTool*m_center1.position;
da847a
    x = toTool*m_a1.position - c;
da847a
    y = toTool*m_b1.position - c;
da847a
    TAffine t1( x.x, y.x, c.x,
da847a
                x.y, y.y, c.y );
da847a
    return t1*t0.inv();
da847a
  }
da847a
  
da847a
  
da847a
  bool isMirror() const {
da847a
    TPointD da0 = m_a0.position - m_center0.position;
da847a
    TPointD db0 = m_b0.position - m_center0.position;
da847a
    TPointD pa0(-da0.y, da0.x);
da847a
da847a
    TPointD da1 = m_a1.position - m_center1.position;
da847a
    TPointD db1 = m_b1.position - m_center1.position;
da847a
    TPointD pa1(-da1.y, da0.x);
da847a
    
da847a
    return (pa0*db0 < 0) != (pa1*db1 < 0);
da847a
  }
da847a
  
da847a
da847a
  void doFixPoints(int mirror) {
da847a
    TPointD &c0 = m_center0.position;
da847a
    TPointD &a0 = m_a0.position;
da847a
    TPointD &b0 = m_b0.position;
da847a
    
da847a
    TPointD &c1 = m_center1.position;
da847a
    TPointD &a1 = m_a1.position;
da847a
    TPointD &b1 = m_b1.position;
da847a
da847a
    if (getFixScale()) {
da847a
      double la0 = tdistance(a0, c0);
da847a
      double lb0 = tdistance(b0, c0);
da847a
      double la1 = tdistance(a1, c1);
da847a
      double lb1 = tdistance(b1, c1);
da847a
      a1 = la1 > TConsts::epsilon
da847a
         ? (a1 - c1)*(la0/la1) + c1
da847a
         : a0 - c0 + c1;
da847a
      b1 = lb1 > TConsts::epsilon
da847a
         ? (b1 - c1)*(lb0/lb1) + c1
da847a
         : b0 - c0 + c1;
da847a
    } else
da847a
    if (getFixAspect()) {
da847a
      double la0 = tdistance(a0, c0);
da847a
      double lb0 = tdistance(b0, c0);
da847a
      double la1 = tdistance(a1, c1);
da847a
      double lb1 = tdistance(b1, c1);
da847a
      if (la0 > TConsts::epsilon)
da847a
        b1 = lb1 > TConsts::epsilon
da847a
           ? (b1 - c1)*(lb0/lb1*la1/la0) + c1
da847a
           : (b0 - c0)*(la1/la0) + c1;
da847a
    }
da847a
da847a
    if (getFixAngle()) {
da847a
      double la0 = tdistance(a0, c0);
da847a
      double lb0 = tdistance(b0, c0);
da847a
      double la1 = tdistance(a1, c1);
da847a
      double lb1 = tdistance(b1, c1);
da847a
      if (la0 > TConsts::epsilon)
da847a
        a1 = (a0 - c0)*(la1/la0) + c1;
da847a
      if (lb0 > TConsts::epsilon)
da847a
        b1 = (b0 - c0)*(lb1/lb0) + c1;
da847a
    } else
da847a
    if (getFixSkew()) {
da847a
      TPointD da0 = a0 - c0;
da847a
      TPointD pa0(-da0.y, da0.x);
da847a
      double x = (b0 - c0)*da0;
da847a
      double y = (b0 - c0)*pa0;
da847a
        
da847a
      TPointD da1 = a1 - c1;
da847a
      TPointD db1 = b1 - c1;
da847a
      TPointD pa1(-da1.y, da1.x);
da847a
      if (mirror) y *= mirror; else      
da847a
        if ((pa1*db1 < 0) != (y < 0)) y = -y;
da847a
      
da847a
      TPointD p = da1*x + pa1*y;
da847a
      double l = norm2(p);
da847a
      if (l > TConsts::epsilon*TConsts::epsilon)
da847a
        b1 = p*sqrt(norm2(db1)/l) + c1;
da847a
    }
da847a
  }
da847a
da847a
  
da847a
  void onFixPoints() override {
da847a
    doFixPoints(0);
da847a
  }
da847a
  
da847a
  
da847a
  void onMovePoint(TAssistantPoint &point, const TPointD &position) override {
da847a
    TPointD pc0 = m_center0.position;
da847a
    TPointD pc1 = m_center1.position;
da847a
    int mirror = &point == &m_b1 ? 0 : (isMirror() ? -1 : 1);
da847a
    point.position = position;
da847a
    if (&point == &m_center0) {
da847a
      TPointD d = m_center0.position - pc0;
da847a
      m_a0.position += d;
da847a
      m_b0.position += d;
da847a
      m_a1.position += d;
da847a
      m_b1.position += d;
da847a
      m_center1.position += d;
da847a
    } else
da847a
    if (&point == &m_center1) {
da847a
      TPointD d = m_center1.position - pc1;
da847a
      m_a1.position += d;
da847a
      m_b1.position += d;
da847a
    }
da847a
    doFixPoints(mirror);
da847a
  }
da847a
  
da847a
  
da847a
  void onDataFieldChanged(const TStringId &name, const TVariant &value) override {
da847a
    TReplicator::onDataFieldChanged(name, value);
da847a
    if ( name == m_idFixScale
da847a
      || name == m_idFixAspect
da847a
      || name == m_idFixAngle
da847a
      || name == m_idFixSkew )
da847a
        fixPoints();
da847a
  }
da847a
da847a
public:
da847a
  int getMultipler() const override
da847a
    { return getCount() + 1; }
da847a
  
da847a
  
da847a
  void getPoints(const TAffine &toTool, PointList &points) const override {
da847a
    points.reserve(points.size() * getMultipler());
da847a
    int pointsCount = (int)points.size();
da847a
da847a
    TAffine aff = getAffine(toTool);
da847a
    struct {
da847a
      int count;
da847a
      TAffine aff;
da847a
    } t[] = {
da847a
      { getCount(), aff },
da847a
      { getCountInv(), aff.inv() } };
da847a
da847a
    for(int i = 0; i < 2; ++i) {
da847a
      TAffine a;
da847a
      for(int j = 0; j < t[i].count; ++j) {
da847a
        a = t[i].aff * a;
da847a
        transformPoints(a, points, pointsCount);
da847a
      }
da847a
    }
da847a
  }
da847a
  
da847a
  
da847a
  void getModifiers(
da847a
    const TAffine &toTool,
da847a
    TInputModifier::List &outModifiers ) const override
da847a
  {
da847a
    TAffine aff = getAffine(toTool);
da847a
    double pressure = getPressure();
da847a
    double pressureInv = fabs(pressure) > TConsts::epsilon ? 1/pressure : 0;
da847a
    
da847a
    struct {
da847a
      int count;
da847a
      TAffine aff;
da847a
      double pressure;
da847a
    } t[] = {
da847a
      { getCount(), aff, pressure },
da847a
      { getCountInv(), aff.inv(), pressureInv },
da847a
    };
da847a
da847a
    TModifierClone *modifier = new TModifierClone();
da847a
    for(int i = 0; i < 2; ++i) {
da847a
      TTrackTransform tt;
da847a
      for(int j = 0; j < t[i].count; ++j) {
da847a
        tt.transform = t[i].aff * tt.transform;
da847a
        tt.tiltTransform = TTrackTransform::makeTiltTransform(tt.transform);
da847a
        tt.pressureScale *= t[i].pressure;
da847a
        modifier->transforms.push_back(tt);
da847a
      }
da847a
    }
da847a
    
da847a
    outModifiers.push_back(modifier);
da847a
  }
da847a
da847a
  
da847a
  void draw(TToolViewer*, bool enabled) const override {
da847a
    double alpha = getDrawingAlpha(enabled);
da847a
    double gridAlpha = getDrawingGridAlpha();
da847a
    double pixelSize = sqrt(tglGetPixelSize2());
da847a
da847a
    TPointD c = m_center0.position;
da847a
    TPointD a = m_a0.position;
da847a
    TPointD b = m_b0.position;
da847a
    TAffine aff = getAffine();
da847a
da847a
    // draw base
da847a
    drawSegment(c, a, pixelSize, alpha);
da847a
    drawSegment(c, b, pixelSize, alpha);
da847a
    
da847a
    // draw clones
da847a
    TAffine t;
da847a
    for(int i = getCount(); i > 0; --i) {
da847a
      t = aff * t;
da847a
      drawSegment(t*c, t*a, pixelSize, gridAlpha);
da847a
      drawSegment(t*c, t*b, pixelSize, gridAlpha);
da847a
    }
da847a
    
da847a
    // draw inverted clones
da847a
    t = TAffine();
da847a
    aff = aff.inv();
da847a
    for(int i = getCountInv(); i > 0; --i) {
da847a
      t = aff * t;
da847a
      drawSegment(t*c, t*a, pixelSize, gridAlpha);
da847a
      drawSegment(t*c, t*b, pixelSize, gridAlpha);
da847a
    }
da847a
  }
da847a
};
da847a
da847a
da847a
//*****************************************************************************************
da847a
//    Registration
da847a
//*****************************************************************************************
da847a
da847a
static TAssistantTypeT<treplicatoraffine> replicatorAffine("replicatorAffine");</treplicatoraffine>