850a0b
850a0b
850a0b
// TnzTools includes
850a0b
#include <tools replicator.h=""></tools>
850a0b
#include <tools modifierclone.h="" modifiers=""></tools>
850a0b
850a0b
850a0b
// TnzCore includes
850a0b
#include <tgl.h></tgl.h>
850a0b
850a0b
850a0b
//*****************************************************************************************
850a0b
//    TReplicatorGrid implementation
850a0b
//*****************************************************************************************
850a0b
850a0b
class TReplicatorGrid final : public TReplicator {
850a0b
  Q_DECLARE_TR_FUNCTIONS(TReplicatorAffine)
850a0b
public:
850a0b
  const TStringId m_idFixAngle;
850a0b
  const TStringId m_idFixSkew;
850a0b
  const TStringId m_idMirrorA;
850a0b
  const TStringId m_idMirrorB;
850a0b
  const TStringId m_idCountA;
850a0b
  const TStringId m_idCountAInv;
850a0b
  const TStringId m_idCountB;
850a0b
  const TStringId m_idCountBInv;
850a0b
850a0b
protected:
850a0b
  TAssistantPoint &m_center;
850a0b
  TAssistantPoint &m_a;
850a0b
  TAssistantPoint &m_b;
850a0b
850a0b
public:
850a0b
  TReplicatorGrid(TMetaObject &object):
850a0b
    TReplicator(object),
850a0b
    m_idFixAngle("fixAngle"),
850a0b
    m_idFixSkew("fixSkew"),
850a0b
    m_idMirrorA("mirrorA"),
850a0b
    m_idMirrorB("mirrorB"),
850a0b
    m_idCountA("countA"),
850a0b
    m_idCountAInv("countAInv"),
850a0b
    m_idCountB("countB"),
850a0b
    m_idCountBInv("countBInv"),
850a0b
    m_center( addPoint("center", TAssistantPoint::CircleCross) ),
850a0b
    m_a     ( addPoint("a",      TAssistantPoint::CircleFill, TPointD(80,   0)) ),
850a0b
    m_b     ( addPoint("b",      TAssistantPoint::Circle,     TPointD( 0, -80)) )
850a0b
  {
850a0b
    addProperty( new TBoolProperty(m_idFixAngle.str(),  getFixAngle()) );
850a0b
    addProperty( new TBoolProperty(m_idFixSkew.str(),   getFixSkew()) );
850a0b
    addProperty( new TBoolProperty(m_idMirrorA.str(),   getMirrorA()) );
850a0b
    addProperty( new TBoolProperty(m_idMirrorB.str(),   getMirrorB()) );
850a0b
    addProperty( createCountProperty(m_idCountA, getCountA(), 1) );
850a0b
    addProperty( createCountProperty(m_idCountAInv, getCountAInv(), 0) );
850a0b
    addProperty( createCountProperty(m_idCountB, getCountB(), 1) );
850a0b
    addProperty( createCountProperty(m_idCountBInv, getCountBInv(), 0) );
850a0b
  }
850a0b
850a0b
  
850a0b
  static QString getLocalName()
850a0b
    { return tr("Replicator Grid"); }
850a0b
850a0b
    
850a0b
  void updateTranslation() const override {
850a0b
    TReplicator::updateTranslation();
850a0b
    setTranslation(m_idFixAngle, tr("Fix Angle"));
850a0b
    setTranslation(m_idFixSkew, tr("Fix Skew"));
850a0b
    setTranslation(m_idMirrorA, tr("Mirror A"));
850a0b
    setTranslation(m_idMirrorB, tr("Mirror B"));
850a0b
    setTranslation(m_idCountA, tr("Count A"));
850a0b
    setTranslation(m_idCountAInv, tr("Inv. Count A"));
850a0b
    setTranslation(m_idCountB, tr("Count B"));
850a0b
    setTranslation(m_idCountBInv, tr("Inv. Count B"));
850a0b
  }
850a0b
850a0b
  
850a0b
  inline bool getFixAngle() const
850a0b
    { return data()[m_idFixAngle].getBool(); }
850a0b
  inline bool getFixSkew() const
850a0b
    { return data()[m_idFixSkew].getBool(); }
850a0b
  inline bool getMirrorA() const
850a0b
    { return data()[m_idMirrorA].getBool(); }
850a0b
  inline bool getMirrorB() const
850a0b
    { return data()[m_idMirrorB].getBool(); }
850a0b
  inline int getCountA() const
850a0b
    { return (int)data()[m_idCountA].getDouble(); }
850a0b
  inline int getCountAInv() const
850a0b
    { return (int)data()[m_idCountAInv].getDouble(); }
850a0b
  inline int getCountB() const
850a0b
    { return (int)data()[m_idCountB].getDouble(); }
850a0b
  inline int getCountBInv() const
850a0b
    { return (int)data()[m_idCountBInv].getDouble(); }
850a0b
850a0b
protected:
850a0b
  inline void setCountA(int x)
850a0b
    { if (getCountA() != (double)x) data()[m_idCountA].setDouble((double)x); }
850a0b
  inline void setCountAInv(int x)
850a0b
    { if (getCountAInv() != (double)x) data()[m_idCountAInv].setDouble((double)x); }
850a0b
  inline void setCountB(int x)
850a0b
    { if (getCountB() != (double)x) data()[m_idCountB].setDouble((double)x); }
850a0b
  inline void setCountBInv(int x)
850a0b
    { if (getCountBInv() != (double)x) data()[m_idCountBInv].setDouble((double)x); }
850a0b
850a0b
    
850a0b
  void onSetDefaults() override {
850a0b
    setCountA(4);
850a0b
    setCountB(4);
850a0b
    TReplicator::onSetDefaults();
850a0b
  }
850a0b
850a0b
  
850a0b
  void onFixData() override {
850a0b
    TReplicator::onFixData();
850a0b
    setCountA( std::max(1, std::min(multiplierSoftLimit, getCountA())) );
850a0b
    setCountAInv( std::max(0, std::min(multiplierSoftLimit, getCountAInv())) );
850a0b
    setCountB( std::max(1, std::min(multiplierSoftLimit, getCountB())) );
850a0b
    setCountBInv( std::max(0, std::min(multiplierSoftLimit, getCountBInv())) );
850a0b
  }
850a0b
850a0b
850a0b
  void onFixPoints() override {
850a0b
    TPointD &c = m_center.position;
850a0b
    TPointD &a = m_a.position;
850a0b
    TPointD &b = m_b.position;
850a0b
850a0b
    if (getFixAngle()) {
850a0b
      double la = tdistance(a, c);
850a0b
      double lb = tdistance(b, c);
850a0b
      a = TPointD(a.x < c.x ? -la : la, 0) + c;
850a0b
      b = TPointD(0, b.y < c.y ? -lb : lb) + c;
850a0b
    } else
850a0b
    if (getFixSkew()) {
850a0b
      TPointD da = a - c;
850a0b
      double la = norm2(da);
850a0b
      if (la > TConsts::epsilon*TConsts::epsilon) {
850a0b
        TPointD db = b - c;
850a0b
        TPointD pa(-da.y, da.x);
850a0b
        double l = pa*db/la;
850a0b
        b = pa*l + c;
850a0b
      }
850a0b
    }
850a0b
  }
850a0b
  
850a0b
  
850a0b
  void onMovePoint(TAssistantPoint &point, const TPointD &position) override {
850a0b
    TPointD pc = m_center.position;
850a0b
    point.position = position;
850a0b
    if (&point == &m_center) {
850a0b
      TPointD d = m_center.position - pc;
850a0b
      m_a.position += d;
850a0b
      m_b.position += d;
850a0b
    } else {
850a0b
      onFixPoints();
850a0b
    }
850a0b
  }
850a0b
  
850a0b
  
850a0b
  void onDataFieldChanged(const TStringId &name, const TVariant &value) override {
850a0b
    TReplicator::onDataFieldChanged(name, value);
850a0b
    if ( name == m_idFixAngle
850a0b
      || name == m_idFixSkew )
850a0b
        fixPoints();
850a0b
  }
850a0b
850a0b
  
850a0b
  static bool makeMirror(TAffine &mirror, const TPointD &c, const TPointD &x) {
850a0b
    if (!(norm2(x) > TConsts::epsilon*TConsts::epsilon))
850a0b
      return false;
850a0b
    TPointD y(-x.y, x.x);
850a0b
    TAffine t0( x.x,  y.x, c.x,
850a0b
                x.y,  y.y, c.y );
850a0b
    TAffine t1( x.x, -y.x, c.x,
850a0b
                x.y, -y.y, c.y );
850a0b
    mirror = t1*t0.inv();
850a0b
    return true;
850a0b
  }
850a0b
  
850a0b
  
850a0b
public:
850a0b
  int getMultipler() const override {
850a0b
    return (getCountA() + getCountAInv())
850a0b
         * (getCountB() + getCountBInv())
850a0b
         * (getMirrorA() ? 2 : 1)
850a0b
         * (getMirrorB() ? 2 : 1);    
850a0b
  }
850a0b
  
850a0b
  
850a0b
  void getModifiers(
850a0b
    const TAffine &toTool,
850a0b
    TInputModifier::List &outModifiers ) const override
850a0b
  {
850a0b
    TPointD c = toTool*m_center.position;
850a0b
    TPointD da = toTool*m_a.position - c;
850a0b
    TPointD db = toTool*m_b.position - c;
850a0b
    
850a0b
    TAffine ma, mb;
850a0b
    
850a0b
    bool mirrorA = getMirrorA() && makeMirror(ma, c, da);
850a0b
    bool mirrorB = getMirrorB() && makeMirror(ma, c, db);
850a0b
850a0b
    int a1 = getCountA();
850a0b
    int b1 = getCountB();
850a0b
    int a0 = -getCountAInv();
850a0b
    int b0 = -getCountBInv();
850a0b
    
850a0b
    TModifierClone *modifier = new TModifierClone();
850a0b
    for(int ib = b0; ib < b1; ++ib)
850a0b
    for(int ia = a0; ia < a1; ++ia) {
850a0b
      TPointD o = da*ia + db*ib;
850a0b
      if (ia || ib)
850a0b
        modifier->transforms.push_back(TTrackTransform(
850a0b
          TAffine( 1, 0, o.x,
850a0b
                   0, 1, o.y ) ));
850a0b
      if (mirrorA)
850a0b
        modifier->transforms.push_back(TTrackTransform(
850a0b
          TAffine( ma.a11, ma.a12, ma.a13 + o.x,
850a0b
                   ma.a21, ma.a22, ma.a23 + o.y ) ));
850a0b
      if (mirrorB)
850a0b
        modifier->transforms.push_back(TTrackTransform(
850a0b
          TAffine( mb.a11, mb.a12, mb.a13 + o.x,
850a0b
                   mb.a21, mb.a22, mb.a23 + o.y ) ));
850a0b
    }
850a0b
    outModifiers.push_back(modifier);
850a0b
  }
850a0b
850a0b
  
850a0b
  void draw(TToolViewer*, bool enabled) const override {
850a0b
    double alpha = getDrawingAlpha(enabled);
850a0b
    double pixelSize = sqrt(tglGetPixelSize2());
850a0b
850a0b
    TPointD c = m_center.position;
850a0b
    TPointD a = m_a.position;
850a0b
    TPointD b = m_b.position;
850a0b
    TPointD da = a - c;
850a0b
    TPointD db = b - c;
850a0b
850a0b
    int a1 = getCountA();
850a0b
    int b1 = getCountB();
850a0b
    int a0 = -getCountAInv();
850a0b
    int b0 = -getCountBInv();
850a0b
    
850a0b
    bool mirrorA = getMirrorA();
850a0b
    bool mirrorB = getMirrorB();
850a0b
    
850a0b
    // draw base
850a0b
    drawSegment(c, a, pixelSize, alpha);
850a0b
    drawSegment(c, b, pixelSize, alpha);
850a0b
    
850a0b
    // draw clones
850a0b
    for(int ib = b0; ib < b1; ++ib)
850a0b
    for(int ia = a0; ia < a1; ++ia) {
850a0b
      TPointD o = c + da*ia + db*ib;
850a0b
      if (ia || ib) {
850a0b
        drawSegment(o, o + da*0.2, pixelSize, alpha);
850a0b
        drawSegment(o, o + db*0.2, pixelSize, alpha);
850a0b
      }
850a0b
      if (mirrorA) drawSegment(o, o - da*0.2, pixelSize, alpha);
850a0b
      if (mirrorB) drawSegment(o, o - db*0.2, pixelSize, alpha);
850a0b
    }
850a0b
  }
850a0b
};
850a0b
850a0b
850a0b
//*****************************************************************************************
850a0b
//    Registration
850a0b
//*****************************************************************************************
850a0b
850a0b
static TAssistantTypeT<treplicatorgrid> replicatorGrid("replicatorGrid");</treplicatorgrid>