#pragma once
#ifndef CONTROLPOINT_SELECTION_INCLUDED
#define CONTROLPOINT_SELECTION_INCLUDED
#include "toonzqt/selection.h"
#include "tool.h"
#include "tstroke.h"
#include "tcurves.h"
//=============================================================================
// ControlPointEditorStroke
//-----------------------------------------------------------------------------
/*!La classe ControlPointEditorStroke effettua tutte le operazioni matematiche sullo Stroke */
class ControlPointEditorStroke
{
private:
//!Punti di controllo comprensivi di SpeedIn e SpeenOut
class ControlPoint
{
public:
int m_indexPoint;
TPointD m_speedIn;
TPointD m_speedOut;
bool m_isCusp;
ControlPoint(int i, TPointD speedIn, TPointD speedOut, bool isCusp = true)
: m_indexPoint(i), m_speedIn(speedIn), m_speedOut(speedOut), m_isCusp(isCusp) {}
ControlPoint()
{
}
};
vector<ControlPoint> m_controlPoints;
TStroke *m_stroke;
int m_strokeIndex;
/*! Viene riempito il vettore \b m_controlPoints scegliendo da \b m_stroke soltanto
i punti di controllo nelle posizioni pari.
*/
void updateControlPoints();
//! Viene settato il valore \b p.m_isCusp osservando lo SpeedIn e SpeedOut del punto.
void setCusp(ControlPoint &p);
void setSpeedIn(ControlPoint &cp, const TPointD &p)
{
cp.m_speedIn = m_stroke->getControlPoint(cp.m_indexPoint) - p;
}
void setSpeedOut(ControlPoint &cp, const TPointD &p)
{
cp.m_speedOut = p - m_stroke->getControlPoint(cp.m_indexPoint);
}
/*! Inserisce un punto nel chunk di lunghezza maggiore selezionato tra quelli compresi
tra il chunk \b indexA e \b indexB.
*/
void insertPoint(int indexA, int indexB);
/*! Verifica che in \b m_stroke tra due cuspidi sia sempre presente un numero pari
di Chunk: in caso contrario richiama la \b insertPoint;
*/
void adjustChunkParity();
//! Sposta il punto di controllo \b index di un fattore delta
void moveSingleControlPoint(int indexPoint, const TPointD &delta);
/*! Sposta i punti di controllo precedenti al punto \b index di un fattore delta.
Se \b moveSpeed==true e' usato per movimento degli speed, altrimenti per
movimento dei punti di controllo.
*/
void movePrecControlPoints(int indexPoint, const TPointD &delta, bool moveSpeed);
/*! Sposta i punti di controllo successivi al punto \b index di un fattore delta.
Se \b moveSpeed==true e' usato per movimento degli speed, altrimenti per
movimento dei punti di controllo.
*/
void moveNextControlPoints(int indexPoint, const TPointD &delta, bool moveSpeed);
public:
ControlPointEditorStroke()
: m_stroke(0), m_strokeIndex(-1) {}
/*!Viene modificato lo stroke in modo tale che tra due cuspidi esista sempre un
numero pari di chunk.
ATTENZIONE: poiche' puo' aggiungere punti di controllo allo stroke, e' bene richiamare
tale funzione solo quando e' necessario.
*/
void setStroke(TStroke *stroke, int strokeIndex);
void setStrokeIndex(int strokeIndex) { m_strokeIndex = strokeIndex; }
int getStrokeIndex() { return m_strokeIndex; }
TThickPoint getControlPoint(int index) const
{
assert(m_stroke && 0 <= index && index < (int)m_controlPoints.size());
return m_stroke->getControlPoint(m_controlPoints[index].m_indexPoint);
}
TThickPoint getSpeedIn(int index) const
{
assert(m_stroke && 0 <= index && index < (int)m_controlPoints.size());
return m_controlPoints[index].m_speedIn;
}
TThickPoint getSpeedOut(int index) const
{
assert(m_stroke && 0 <= index && index < (int)m_controlPoints.size());
return m_controlPoints[index].m_speedOut;
}
int getControlPointCount() const
{
return m_controlPoints.size();
}
//! Ritorna \b true se il punto index e' una cuspide.
bool getIsCusp(int index) const
{
assert(m_stroke && 0 <= index && index < (int)getControlPointCount());
return m_controlPoints[index].m_isCusp;
}
//!Viene settato il valore \b m_isCusp del punto index-esimo a \b isCusp.
void linkUnlinkSpeeds(int index, bool isCusp)
{
m_controlPoints[index].m_isCusp = isCusp;
}
/*! Sposta il ControlPoint \b index di un fattore delta con continuita',
cioe' spostando anche i punti di controllo adiacenti se necessario.*/
void moveControlPoint(int index, const TPointD &delta);
//! Cancella il punto di controllo \b point.
void deleteControlPoint(int index);
/*! Aggiunge il punto di controllo \b point.
Ritorna l'indice del punto di controllo appena inserito.*/
int addControlPoint(const TPointD &pos);
/*! Ritorna l'indice del cp piu' vicino al punto pos.
distance2 riceve il valore del quadrato della distanza
se la ControlPointEditorStroke e' vuota ritorna -1.*/
int getClosestControlPoint(const TPointD &pos, double &distance2) const;
//! Ritorna true sse e' definita una curva e se pos e' abbastanza vicino alla curva
bool isCloseTo(const TPointD &pos, double pixelSize) const;
/*! Ritorna l'indice del cp il cui bilancino e' piu' vicino al punto pos.
\b minDistance2 riceve il valore del quadrato della distanza
se la ControlPointEditorStroke e' vuota ritorna -1. \b isIn e' true se il bilancino cliccato
corrisponde allo SpeedIn.*/
int getClosestSpeed(const TPointD &pos, double &minDistance2, bool &isIn) const;
/*! Sposta il bilancino del punto \b index di un fattore delta. \b isIn deve essere
true se si vuole spostare lo SpeedIn.*/
void moveSpeed(int index, const TPointD &delta, bool isIn, double pixelSize);
/*! Se isLinear e' true setta a "0" il valore dello speedIn e il valore dello speedOut;
altrimenti li setta ad un valore di default. Ritorna vero se almeno un punto e' ststo modificato.*/
bool setLinear(int index, bool isLinear);
void setLinearSpeedIn(int index);
void setLinearSpeedOut(int index);
bool isSpeedInLinear(int index);
bool isSpeedOutLinear(int index);
bool isSelfLoop()
{
return m_stroke->isSelfLoop();
}
};
//=============================================================================
// ControlPointSelection
//-----------------------------------------------------------------------------
class ControlPointSelection : public QObject, public TSelection
{
Q_OBJECT
private:
std::set<int> m_selectedPoints;
ControlPointEditorStroke *m_controlPointEditorStroke;
public:
ControlPointSelection() : m_controlPointEditorStroke(0) {}
void setControlPointEditorStroke(ControlPointEditorStroke *controlPointEditorStroke)
{
m_controlPointEditorStroke = controlPointEditorStroke;
}
bool isEmpty() const { return m_selectedPoints.empty(); }
void selectNone() { m_selectedPoints.clear(); }
bool isSelected(int index) const;
void select(int index);
void unselect(int index);
void deleteControlPoints();
void addMenuItems(QMenu *menu);
void enableCommands();
protected slots:
void setLinear();
void setUnlinear();
};
#endif //CONTROLPOINT_SELECTION_INCLUDED