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