aa51ee
aa51ee
aa51ee
// TnzTools includes
aa51ee
#include <tools replicator.h=""></tools>
aa51ee
#include <tools modifierclone.h="" modifiers=""></tools>
aa51ee
#include <tools assistants="" guidelineline.h=""></tools>
aa51ee
aa51ee
aa51ee
// TnzCore includes
aa51ee
#include <tgl.h></tgl.h>
aa51ee
aa51ee
aa51ee
//*****************************************************************************************
aa51ee
//    TReplicatorStar implementation
aa51ee
//*****************************************************************************************
aa51ee
aa51ee
class TReplicatorStar final : public TReplicator {
aa51ee
  Q_DECLARE_TR_FUNCTIONS(TReplicatorStar)
aa51ee
public:
aa51ee
  const TStringId m_idDiscreteAngle;
aa51ee
  const TStringId m_idMirror;
aa51ee
  const TStringId m_idCount;
aa51ee
aa51ee
protected:
aa51ee
  TAssistantPoint &m_center;
aa51ee
  TAssistantPoint &m_a;
aa51ee
aa51ee
public:
aa51ee
  TReplicatorStar(TMetaObject &object):
aa51ee
    TReplicator(object),
aa51ee
    m_idDiscreteAngle("discreteAngle"),
aa51ee
    m_idMirror("mirror"),
aa51ee
    m_idCount("count"),
aa51ee
    m_center( addPoint("center", TAssistantPoint::CircleCross) ),
aa51ee
    m_a     ( addPoint("a",      TAssistantPoint::Circle, TPointD(80, 0)) )
aa51ee
  {
aa51ee
    addProperty( new TBoolProperty(m_idDiscreteAngle.str(), getDiscreteAngle()) );
aa51ee
    addProperty( new TBoolProperty(m_idMirror.str(),        getMirror()) );
aa51ee
    addProperty( createCountProperty(m_idCount, getCount(), 2) );
aa51ee
  }
aa51ee
aa51ee
  
aa51ee
  static QString getLocalName()
aa51ee
    { return tr("Replicator Star"); }
aa51ee
aa51ee
    
aa51ee
  void updateTranslation() const override {
aa51ee
    TReplicator::updateTranslation();
aa51ee
    setTranslation(m_idDiscreteAngle, tr("Discrete Angle"));
aa51ee
    setTranslation(m_idMirror, tr("Mirror"));
aa51ee
    setTranslation(m_idCount, tr("Count"));
aa51ee
  }
aa51ee
aa51ee
  
aa51ee
  inline bool getDiscreteAngle() const
aa51ee
    { return data()[m_idDiscreteAngle].getBool(); }
aa51ee
  inline bool getMirror() const
aa51ee
    { return data()[m_idMirror].getBool(); }
aa51ee
  inline int getCount() const
aa51ee
    { return (int)data()[m_idCount].getDouble(); }
aa51ee
aa51ee
protected:
aa51ee
  inline void setCount(int x)
aa51ee
    { if (getCount() != (double)x) data()[m_idCount].setDouble((double)x); }
aa51ee
aa51ee
    
aa51ee
  void onSetDefaults() override {
aa51ee
    setCount(6);
aa51ee
    TReplicator::onSetDefaults();
aa51ee
  }
aa51ee
aa51ee
  
aa51ee
  void onFixData() override {
aa51ee
    TReplicator::onFixData();
aa51ee
    setCount( std::max(1, std::min(multiplierSoftLimit - 1, getCount())) );
aa51ee
  }
aa51ee
aa51ee
aa51ee
  TPointD fixA() const {
aa51ee
    TPointD a = m_a.position;
aa51ee
    
aa51ee
    if (getDiscreteAngle()) {
aa51ee
      TPointD d = a - m_center.position;
aa51ee
      double l = norm2(d);
aa51ee
      if (l > TConsts::epsilon*TConsts::epsilon) {
aa51ee
        l = sqrt(l);
aa51ee
        int count = getCount();
aa51ee
        if (count > 0) {
aa51ee
          double angle = atan2(d.y, d.x);
aa51ee
          angle = round(angle*2*count/M_PI)*M_PI/(2*count);
aa51ee
          a.x = cos(angle)*l + m_center.position.x;
aa51ee
          a.y = sin(angle)*l + m_center.position.y;
aa51ee
        }
aa51ee
      }
aa51ee
    }
aa51ee
    
aa51ee
    if (areAlmostEqual(a, m_center.position))
aa51ee
      a = m_center.position + TPointD(1, 0);
aa51ee
    
aa51ee
    return a;
aa51ee
  }
aa51ee
aa51ee
  
aa51ee
  void onMovePoint(TAssistantPoint &point, const TPointD &position) override {
aa51ee
    if (&point == &m_center)
aa51ee
      m_a.position += position - m_center.position;
aa51ee
    point.position = position;
aa51ee
  }
aa51ee
  
aa51ee
  
aa51ee
public:
aa51ee
  int getMultipler() const override
aa51ee
    { return getCount() + 1; }
aa51ee
  
aa51ee
  
370a7e
  void getPoints(const TAffine &toTool, PointList &points) const override {
370a7e
    points.reserve(points.size() * getMultipler());
370a7e
    int pointsCount = (int)points.size();
370a7e
    
370a7e
    int count = getCount();
370a7e
    bool mirror = getMirror();
370a7e
370a7e
    TPointD c = toTool*m_center.position;
370a7e
    TPointD x = toTool*fixA() - c;
370a7e
    TPointD y(-x.y, x.x);
370a7e
370a7e
    TAffine t1( x.x,  y.x, c.x,
370a7e
                x.y,  y.y, c.y );
370a7e
    TAffine t2( x.x, -y.x, c.x,
370a7e
                x.y, -y.y, c.y );
370a7e
    
370a7e
    TAffine t0 = t1.inv();
370a7e
    TRotation r(360.0/getCount());
370a7e
                          
370a7e
    for(int i = 0; i < count; ++i) {
370a7e
      if (i)
370a7e
        transformPoints(t1*t0, points, pointsCount);
370a7e
      if (mirror) {
370a7e
        transformPoints(t2*t0, points, pointsCount);
370a7e
        t2 *= r;
370a7e
      }
370a7e
      t1 *= r;
370a7e
    }
370a7e
  }
370a7e
  
370a7e
  
aa51ee
  void getModifiers(
aa51ee
    const TAffine &toTool,
aa51ee
    TInputModifier::List &outModifiers ) const override
aa51ee
  {
aa51ee
    int count = getCount();
aa51ee
    bool mirror = getMirror();
aa51ee
aa51ee
    TPointD c = toTool*m_center.position;
aa51ee
    TPointD x = toTool*fixA() - c;
aa51ee
    TPointD y(-x.y, x.x);
aa51ee
aa51ee
    TAffine t1( x.x,  y.x, c.x,
aa51ee
                x.y,  y.y, c.y );
aa51ee
    TAffine t2( x.x, -y.x, c.x,
aa51ee
                x.y, -y.y, c.y );
aa51ee
    
aa51ee
    TAffine t0 = t1.inv();
aa51ee
    TRotation r(360.0/getCount());
aa51ee
                          
aa51ee
    TModifierClone *modifier = new TModifierClone();
aa51ee
    for(int i = 0; i < count; ++i) {
aa51ee
      if (i)
aa51ee
        modifier->transforms.push_back(TTrackTransform(t1*t0));
aa51ee
      if (mirror) {
aa51ee
        modifier->transforms.push_back(TTrackTransform(t2*t0));
aa51ee
        t2 *= r;
aa51ee
      }
aa51ee
      t1 *= r;
aa51ee
    }
aa51ee
    
aa51ee
    outModifiers.push_back(modifier);
aa51ee
  }
aa51ee
aa51ee
  
aa51ee
  void draw(TToolViewer*, bool enabled) const override {
aa51ee
    double alpha = getDrawingAlpha(enabled);
aa51ee
    double gridAlpha = getDrawingGridAlpha();
aa51ee
    double pixelSize = sqrt(tglGetPixelSize2());
aa51ee
aa51ee
    int count = getCount();
aa51ee
    bool mirror = getMirror();
aa51ee
aa51ee
    TPointD c = m_center.position;
aa51ee
    TPointD a = fixA();
aa51ee
    TPointD d = normalize(a - c);
aa51ee
    
aa51ee
    double spacing = 10*pixelSize;
aa51ee
    double l = spacing*count/M_2PI;
aa51ee
    
aa51ee
    TPointD p0 = c + d*l;
aa51ee
    TPointD p1 = p0 + d;
aa51ee
    TRotation r(360.0/count);
aa51ee
    
aa51ee
    TAffine4 modelview, projection;
aa51ee
    glGetDoublev(GL_MODELVIEW_MATRIX, modelview.a);
aa51ee
    glGetDoublev(GL_PROJECTION_MATRIX, projection.a);
aa51ee
aa51ee
    TAffine matrix = (projection*modelview).get2d();
aa51ee
    TAffine matrixInv = matrix.inv();
aa51ee
    const TRectD oneBox(-1.0, -1.0, 1.0, 1.0);
aa51ee
    
aa51ee
    for(int i = 0; i < count; ++i) {
aa51ee
      TPointD pp0 = matrix*p0;
aa51ee
      TPointD pp1 = matrix*p1;
aa51ee
      if (TGuidelineLine::truncateRay(oneBox, pp0, pp1))
aa51ee
        drawSegment(matrixInv*pp0, matrixInv*pp1, pixelSize, i ? gridAlpha : alpha);
aa51ee
      p0 = r*(p0 - c) + c;
aa51ee
      p1 = r*(p1 - c) + c;
aa51ee
    }
aa51ee
    
aa51ee
    TPointD p = TPointD(-d.y, d.x);
aa51ee
    drawSegment( (mirror ? a+p*15 : a), a-p*15, pixelSize, alpha );
aa51ee
    
aa51ee
    drawSegment(c - d*10, c + d*10, pixelSize, alpha);
aa51ee
    drawSegment(c - p*10, c + p*10, pixelSize, alpha);
aa51ee
  }
aa51ee
};
aa51ee
aa51ee
aa51ee
//*****************************************************************************************
aa51ee
//    Registration
aa51ee
//*****************************************************************************************
aa51ee
aa51ee
static TAssistantTypeT<treplicatorstar> replicatorStar("replicatorStar");</treplicatorstar>