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