void ControlPointEditorStroke::setLinearSpeedIn(int index, bool linear, bool updatePoints) { TStroke *stroke = getStroke(); if (!stroke || m_controlPoints.size() == 1) return; int pointIndex = m_controlPoints[index].m_pointIndex; if (pointIndex == 0) { if (isSelfLoop()) pointIndex = stroke->getControlPointCount() - 1; else return; } int precIndex = (index == 0 && isSelfLoop()) ? m_controlPoints.size() - 1 : index - 1; TThickPoint point = stroke->getControlPoint(pointIndex); TThickPoint precPoint = (pointIndex > 2) ? stroke->getControlPoint(pointIndex - 3) : TThickPoint(); if (linear) { TThickPoint p(point - precPoint); double n = norm(p); TThickPoint speedIn = (n != 0.0) ? (0.01 / n) * p : TThickPoint(0.001, 0.001, 0.0); m_controlPoints[index].m_speedIn = speedIn; } else { TThickPoint newPrec2 = (precPoint + point) * 0.5; TThickPoint speedIn = (point - newPrec2) * 0.5; m_controlPoints[index].m_speedIn = speedIn; } if (updatePoints) updateDependentPoint(index); }
void ControlPointEditorStroke::setLinearSpeedOut(int index, bool linear, bool updatePoints) { TStroke *stroke = getStroke(); if (!stroke || m_controlPoints.size() == 1) return; int cpCount = stroke->getControlPointCount(); int pointIndex = m_controlPoints[index].m_pointIndex; if (pointIndex == cpCount - 1) { if (isSelfLoop()) pointIndex = 0; else return; } int nextIndex = (index == m_controlPoints.size() - 1 && isSelfLoop()) ? 0 : index + 1; TThickPoint point = stroke->getControlPoint(pointIndex); TThickPoint nextPoint = (pointIndex < cpCount - 3) ? stroke->getControlPoint(pointIndex + 3) : TThickPoint(); if (linear) { TThickPoint p(nextPoint - point); double n = norm(p); TThickPoint speedOut = (n != 0.0) ? (0.01 / n) * p : TThickPoint(0.001, 0.001, 0.0); m_controlPoints[index].m_speedOut = speedOut; } else { TThickPoint newNext2 = (nextPoint + point) * 0.5; TThickPoint speedOut = (newNext2 - point) * 0.5; m_controlPoints[index].m_speedOut = speedOut; } if (updatePoints) updateDependentPoint(index); }
void ControlPointEditorStroke::moveSegment(int beforeIndex, int nextIndex, const TPointD &delta, const TPointD &pos) { TStroke *stroke = getStroke(); if (!stroke) return; int cpCount = getControlPointCount(); // Verifiche per il caso in cui lo stroke e' selfLoop if (isSelfLoop() && beforeIndex == 0 && nextIndex == cpCount - 1) std::swap(beforeIndex, nextIndex); int beforePointIndex = m_controlPoints[beforeIndex].m_pointIndex; int nextPointIndex = (isSelfLoop() && nextIndex == 0) ? stroke->getControlPointCount() - 1 : m_controlPoints[nextIndex].m_pointIndex; double w = stroke->getW(pos); double w0 = stroke->getParameterAtControlPoint(beforePointIndex); double w4 = stroke->getParameterAtControlPoint(nextPointIndex); if (w0 > w) return; assert(w0 <= w && w <= w4); double t = 1; double s = 1; if (isSpeedOutLinear(beforeIndex)) { m_controlPoints[beforeIndex].m_speedOut = (stroke->getControlPoint(nextPointIndex) - stroke->getControlPoint(beforePointIndex)) * 0.3; if (!isSpeedInLinear(beforeIndex)) m_controlPoints[beforeIndex].m_isCusp = true; } else if (!isSpeedOutLinear(beforeIndex) && !isSpeedInLinear(beforeIndex) && !isCusp(beforeIndex)) { t = 1 - fabs(w - w0) / fabs(w4 - w0); moveSingleControlPoint(beforeIndex, t * delta); t = 1 - t; } if (isSpeedInLinear(nextIndex)) { m_controlPoints[nextIndex].m_speedIn = (stroke->getControlPoint(nextPointIndex) - stroke->getControlPoint(beforePointIndex)) * 0.3; if (!isSpeedOutLinear(nextIndex)) m_controlPoints[nextIndex].m_isCusp = true; } else if (!isSpeedInLinear(nextIndex) && !isSpeedOutLinear(nextIndex) && !isCusp(nextIndex)) { s = 1 - fabs(w4 - w) / fabs(w4 - w0); moveSingleControlPoint(nextIndex, s * delta); s = 1 - s; } moveSpeedOut(beforeIndex, delta * s, 0); // updateDependentPoint(beforeIndex); moveSpeedIn(nextIndex, delta * t, 0); // updateDependentPoint(nextIndex); updatePoints(); }
TThickPoint TStrokeBenderDeformation::getDisplacementForControlPoint( const TStroke &s, UINT n) const { // potenziale exp^(-x^2) limitato tra // [-c_maxLenghtOfGaussian,c_maxLenghtOfGaussian] double strokeLengthAtParameter = s.getLengthAtControlPoint(n); double diff = strokeLengthAtParameter - m_startLength; if (m_vect) { double outVal = 0; if (fabs(diff) <= m_lengthOfDeformation && m_versus == INNER) { diff *= (1.0 / m_lengthOfDeformation) * c_maxLenghtOfGaussian; outVal = gaussianPotential(diff); } else if (m_versus == OUTER) { double valForGaussian = -c_maxLenghtOfGaussian + 2 * c_maxLenghtOfGaussian / m_lengthOfDeformation * strokeLengthAtParameter; outVal = 1.0 - gaussianPotential(valForGaussian); } TPointD cp = convert(s.getControlPoint(n)); TPointD p = cp; TRotation rot(*m_vect, outVal * rad2degree(m_angle)); p = rot * p; return TThickPoint(p - cp, 0.0); } return TThickPoint(); }
void setPoint(const TPointD &p) { TThickPoint point = m_stroke->getControlPoint(m_index); point.x = p.x; point.y = p.y; m_stroke->setControlPoint(m_index, point); }
TThickPoint ControlPointEditorStroke::getSpeedOutPoint(int index) const { TStroke *stroke = getStroke(); assert(stroke && 0 <= index && index < (int)m_controlPoints.size()); ControlPoint cp = m_controlPoints[index]; return stroke->getControlPoint(cp.m_pointIndex) + cp.m_speedOut; }
void ControlPointEditorStroke::resetControlPoints() { TStroke *stroke = getStroke(); if (!stroke) return; m_controlPoints.clear(); int i; int cpCount = stroke->getControlPointCount(); if (cpCount == 3) { const TThickQuadratic *chunk = stroke->getChunk(0); if (chunk->getP0() == chunk->getP1() && chunk->getP0() == chunk->getP2()) // E' un punto { m_controlPoints.push_back( ControlPoint(0, TPointD(0.0, 0.0), TPointD(0.0, 0.0), true)); return; } } for (i = 0; i < cpCount; i = i + 4) { TThickPoint speedIn, speedOut; bool isPickOut = false; TThickPoint p = stroke->getControlPoint(i); TThickPoint precP = stroke->getControlPoint(i - 1); TThickPoint nextP = stroke->getControlPoint(i + 1); if (0 < i && i < cpCount - 1) // calcola speedIn e speedOut { speedIn = p - precP; speedOut = nextP - p; } if (i == 0) // calcola solo lo speedOut { speedOut = nextP - p; if (isSelfLoop()) speedIn = p - stroke->getControlPoint(cpCount - 2); } if (i == cpCount - 1) // calcola solo lo speedIn speedIn = p - precP; if (i == cpCount - 1 && isSelfLoop()) break; // Se lo stroke e' selfLoop inserisco solo il primo dei due punti // coincidenti bool isCusp = ((i != 0 && i != cpCount - 1) || (isSelfLoop() && i == 0)) ? isCuspPoint(precP, p, nextP) : true; m_controlPoints.push_back(ControlPoint(i, speedIn, speedOut, isCusp)); } }
bool PinchTool::keyDown(int key, TUINT32 flags, const TPoint &pos) { m_deformation->reset(); #if 0 char c = (char)key; if(c == 'p' || c == 'P' ) { TVectorImageP vimage(getImage()); if(!vimage) return false; char fileName[] = {"c:\\toonz_input.sdd"}; ofstream out_file(fileName); if(!out_file) { cerr<<"Error on opening: "<<fileName<<endl; return false; } out_file<<"# VImage info\n"; out_file<<"# Number of stroke:\n"; const int max_number_of_strokes = vimage->getStrokeCount(); out_file<<max_number_of_strokes<<endl; int number_of_strokes = 0; const int cp_for_row=3; while( number_of_strokes<max_number_of_strokes) { TStroke* ref = vimage->getStroke(number_of_strokes); out_file<<endl; out_file<<"# Number of control points for stroke:\n"; const int max_number_of_cp = ref->getControlPointCount(); out_file<<max_number_of_cp <<endl; out_file<<"# Control Points:\n"; int number_of_cp=0; while( number_of_cp<max_number_of_cp ) { out_file<<ref->getControlPoint(number_of_cp)<<" "; if(!((number_of_cp+1)%cp_for_row)) // add a new line after ten points out_file<<endl; number_of_cp++; } out_file<<endl; number_of_strokes++; } } #endif return true; }
TThickPoint ControlPointEditorStroke::getPureDependentPoint(int index) const { TStroke *stroke = getStroke(); if (!stroke) return TThickPoint(); bool selfLoop = isSelfLoop(); int cpCount = selfLoop ? m_controlPoints.size() + 1 : m_controlPoints.size(); int nextIndex = (selfLoop && index == cpCount - 2) ? 0 : index + 1; int pointIndex = m_controlPoints[index].m_pointIndex; TThickPoint oldP(stroke->getControlPoint(pointIndex + 2)); TPointD oldSpeedOutP = stroke->getControlPoint(pointIndex + 1); TPointD oldSpeedInP = stroke->getControlPoint(pointIndex + 3); double dist = tdistance(oldSpeedOutP, oldSpeedInP); double t = (dist > 1e-4) ? tdistance(oldSpeedInP, convert(oldP)) / dist : 0.5; TPointD speedOutPoint(getSpeedOutPoint(index)); TPointD nextSpeedInPoint(getSpeedInPoint(nextIndex)); return TThickPoint((1 - t) * nextSpeedInPoint + t * speedOutPoint, oldP.thick); // return TThickPoint(0.5 * (speedOutPoint + nextSpeedInPoint), oldThick); }
TThickPoint TStrokePointDeformation::getDisplacementForControlPoint( const TStroke &stroke, UINT n) const { // riferimento ad un punto ciccione della stroke TPointD pntOfStroke(convert(stroke.getControlPoint(n))); double d = tdistance(pntOfStroke, m_imp->m_circleCenter); if (m_imp->m_vect) return m_imp->m_potential->value(d) * TThickPoint(*m_imp->m_vect, 0); else { double outVal = m_imp->m_potential->value(d); return TThickPoint(outVal, outVal, 0); } }
void ControlPointEditorStroke::getDependentPoints( int index, std::vector<std::pair<int, TThickPoint>> &points) const { TStroke *stroke = getStroke(); if (!stroke) return; int cpCount = m_controlPoints.size(); if (index == cpCount && isSelfLoop()) // strange, but was treated... index = 0; if (index == 0 && cpCount == 1) { // Single point case TStroke *stroke = getStroke(); TThickPoint pos(stroke->getControlPoint(m_controlPoints[0].m_pointIndex)); points.push_back(std::make_pair(1, pos)); points.push_back(std::make_pair(2, pos)); return; } int prev = prevIndex(index); if (prev >= 0) { int prevPointIndex = m_controlPoints[prev].m_pointIndex; if (isSpeedOutLinear(prev)) points.push_back( std::make_pair(prevPointIndex + 1, getSpeedOutPoint(prev))); points.push_back( std::make_pair(prevPointIndex + 2, getPureDependentPoint(prev))); points.push_back( std::make_pair(prevPointIndex + 3, getSpeedInPoint(index))); } int next = nextIndex(index); if (next >= 0) { int pointIndex = m_controlPoints[index].m_pointIndex; points.push_back(std::make_pair(pointIndex + 1, getSpeedOutPoint(index))); points.push_back( std::make_pair(pointIndex + 2, getPureDependentPoint(index))); if (isSpeedInLinear(next)) points.push_back(std::make_pair(pointIndex + 3, getSpeedInPoint(next))); } }
void ControlPointEditorStroke::moveSingleControlPoint(int index, const TPointD &delta) { TStroke *stroke = getStroke(); if (!stroke) return; int pointIndex = m_controlPoints[index].m_pointIndex; assert(stroke && 0 <= pointIndex && pointIndex < stroke->getControlPointCount()); bool selfLoop = isSelfLoop(); int cpCount = selfLoop ? m_controlPoints.size() + 1 : m_controlPoints.size(); TThickPoint p = stroke->getControlPoint(pointIndex); p = TThickPoint(p + delta, p.thick); stroke->setControlPoint(pointIndex, p); if (pointIndex == 0 && selfLoop) stroke->setControlPoint(stroke->getControlPointCount() - 1, p); // Directions must be recalculated in the linear cases if ((selfLoop || index > 0) && isSpeedInLinear(index)) { setLinearSpeedIn(index, true, false); // Furthermore, if the NEIGHBOUR point is linear, it has to be // recalculated too int prevIndex = (selfLoop && index == 0) ? cpCount - 2 : index - 1; if (m_controlPoints[prevIndex].m_isCusp && isSpeedOutLinear(prevIndex)) setLinearSpeedOut(prevIndex, true, false); } if ((selfLoop || index < cpCount - 1) && isSpeedOutLinear(index)) { setLinearSpeedOut(index, true, false); int nextIndex = (selfLoop && index == cpCount - 2) ? 0 : index + 1; if (m_controlPoints[nextIndex].m_isCusp && isSpeedInLinear(nextIndex)) setLinearSpeedIn(nextIndex, true, false); } }
ControlPointEditorStroke::PointType ControlPointEditorStroke::getPointTypeAt( const TPointD &pos, double &distance2, int &index) const { TStroke *stroke = getStroke(); if (!stroke) return NONE; double w = stroke->getW(pos); TPointD p = stroke->getPoint(w); double strokeDistance = tdistance2(p, pos); int precPointIndex = -1; double minPrecDistance = 0; double minDistance2 = distance2; index = -1; PointType type = NONE; int cpCount = m_controlPoints.size(); int i; for (i = 0; i < cpCount; i++) { ControlPoint cPoint = m_controlPoints[i]; TPointD point = stroke->getControlPoint(cPoint.m_pointIndex); double cpDistance2 = tdistance2(pos, point); double distanceIn2 = !isSpeedInLinear(i) ? tdistance2(pos, point - cPoint.m_speedIn) : cpDistance2 + 1; double distanceOut2 = !isSpeedOutLinear(i) ? tdistance2(pos, point + cPoint.m_speedOut) : cpDistance2 + 1; if (i == 0 && !isSelfLoop()) distanceIn2 = std::max(cpDistance2, distanceOut2) + 1; if (i == cpCount - 1 && !isSelfLoop()) distanceOut2 = std::max(cpDistance2, distanceIn2) + 1; if (cpDistance2 < distanceIn2 && cpDistance2 < distanceOut2 && (cpDistance2 < minDistance2 || index < 0)) { minDistance2 = cpDistance2; index = i; type = CONTROL_POINT; } else if (distanceIn2 < cpDistance2 && distanceIn2 < distanceOut2 && (distanceIn2 < minDistance2 || index < 0)) { minDistance2 = distanceIn2; index = i; type = SPEED_IN; } else if (distanceOut2 < cpDistance2 && distanceOut2 < distanceIn2 && (distanceOut2 < minDistance2 || index < 0)) { minDistance2 = distanceOut2; index = i; type = SPEED_OUT; } double cpw = stroke->getParameterAtControlPoint(m_controlPoints[i].m_pointIndex); if (w <= cpw) continue; double precDistance = w - cpw; if (precPointIndex < 0 || precDistance < minPrecDistance) { precPointIndex = i; minPrecDistance = precDistance; } } if (minDistance2 < distance2) distance2 = minDistance2; else if (strokeDistance > distance2) { distance2 = strokeDistance; index = -1; type = NONE; } else { distance2 = minPrecDistance; index = precPointIndex; type = SEGMENT; } return type; }
TPointD getPoint() const { return m_stroke->getControlPoint(m_index); }
int ControlPointEditorStroke::addControlPoint(const TPointD &pos) { TStroke *stroke = getStroke(); if (!stroke) return -1; double d = 0.01; int indexAtPos; int cpCount = stroke->getControlPointCount(); if (cpCount <= 3) // e' un unico chunk e in questo caso rappresenta un punto { getPointTypeAt(pos, d, indexAtPos); return indexAtPos; } double w = stroke->getW(pos); int pointIndex = stroke->getControlPointIndexAfterParameter(w); int i, index; for (i = 0; i < getControlPointCount(); i++) { // Cerco il ControlPoint corrispondente all'indice pointIndex. OSS.: // Effettuo il // controllo da zero a getControlPointCount()-1 per gestire il caso del // selfLoop if (pointIndex == m_controlPoints[i].m_pointIndex + 1 || pointIndex == m_controlPoints[i].m_pointIndex + 2 || pointIndex == m_controlPoints[i].m_pointIndex + 3 || pointIndex == m_controlPoints[i].m_pointIndex + 4) index = i; } ControlPoint precCp = m_controlPoints[index]; assert(precCp.m_pointIndex >= 0); std::vector<TThickPoint> points; for (i = 0; i < cpCount; i++) { if (i != precCp.m_pointIndex + 1 && i != precCp.m_pointIndex + 2 && i != precCp.m_pointIndex + 3) points.push_back(stroke->getControlPoint(i)); if (i == precCp.m_pointIndex + 2) { bool isBeforePointLinear = isSpeedOutLinear(index); int nextIndex = (isSelfLoop() && index == m_controlPoints.size() - 1) ? 0 : index + 1; bool isNextPointLinear = nextIndex < (int)m_controlPoints.size() && isSpeedInLinear(nextIndex); TThickPoint a0 = stroke->getControlPoint(precCp.m_pointIndex); TThickPoint a1 = stroke->getControlPoint(precCp.m_pointIndex + 1); TThickPoint a2 = stroke->getControlPoint(precCp.m_pointIndex + 2); TThickPoint a3 = stroke->getControlPoint(precCp.m_pointIndex + 3); TThickPoint a4 = stroke->getControlPoint(precCp.m_pointIndex + 4); double dist2 = tdistance2(pos, TPointD(a2)); TThickPoint d0, d1, d2, d3, d4, d5, d6; if (isBeforePointLinear && isNextPointLinear) { // Se sono entrambi i punti lineari inserisco un punto lineare d0 = a1; d3 = stroke->getThickPoint(w); d6 = a3; d2 = computeLinearPoint(d0, d3, 0.01, true); // SpeedIn d4 = computeLinearPoint(d3, d6, 0.01, false); // SpeedOut d1 = 0.5 * (d0 + d2); d5 = 0.5 * (d4 + d6); } else if (dist2 < 32) { // Sono molto vicino al punto che non viene visualizzato TThickPoint b0 = 0.5 * (a0 + a1); TThickPoint b1 = 0.5 * (a2 + a1); TThickPoint c0 = 0.5 * (b0 + b1); TThickPoint b2 = 0.5 * (a2 + a3); TThickPoint b3 = 0.5 * (a3 + a4); TThickPoint c1 = 0.5 * (b2 + b3); d0 = b0; d1 = c0; d2 = b1; d3 = a2; d4 = b2; d5 = c1; d6 = b3; } else { bool isInFirstChunk = true; if (pointIndex > precCp.m_pointIndex + 2) { // nel caso in cui sono nel secondo chunk scambio i punti a0 = a4; std::swap(a1, a3); isInFirstChunk = false; } double w0 = (isSelfLoop() && precCp.m_pointIndex + 4 == cpCount - 1 && !isInFirstChunk) ? 1 : stroke->getW(a0); double w1 = stroke->getW(a2); double t = (w - w0) / (w1 - w0); TThickPoint p = stroke->getThickPoint(w); TThickPoint b0 = TThickPoint((1 - t) * a0 + t * a1, (1 - t) * a0.thick + t * a1.thick); TThickPoint b1 = TThickPoint((1 - t) * a1 + t * a2, (1 - t) * a1.thick + t * a2.thick); TThickPoint c0 = TThickPoint(0.5 * a0 + 0.5 * b0, (1 - t) * a0.thick + t * b0.thick); TThickPoint c1 = TThickPoint(0.5 * b0 + 0.5 * p, (1 - t) * b0.thick + t * p.thick); TThickPoint c2 = TThickPoint(0.5 * c0 + 0.5 * c1, (1 - t) * c0.thick + t * c1.thick); d0 = (isInFirstChunk) ? c0 : a3; d1 = (isInFirstChunk) ? c2 : a2; d2 = (isInFirstChunk) ? c1 : b1; d3 = p; d4 = (isInFirstChunk) ? b1 : c1; d5 = (isInFirstChunk) ? a2 : c2; d6 = (isInFirstChunk) ? a3 : c0; } if (isBeforePointLinear && !isNextPointLinear) d1 = computeLinearPoint(d0, d2, 0.01, false); else if (isNextPointLinear && !isBeforePointLinear) d5 = computeLinearPoint(d4, d6, 0.01, true); points.push_back(d0); points.push_back(d1); points.push_back(d2); points.push_back(d3); points.push_back(d4); points.push_back(d5); points.push_back(d6); } } stroke->reshape(&points[0], points.size()); resetControlPoints(); getPointTypeAt(pos, d, indexAtPos); return indexAtPos; }
void leftButtonUp(const TPointD &, const TMouseEvent &) { if (!m_active) return; m_active = false; m_pointAtMouseDown = m_pointAtMove = TConsts::napd; TStroke *ref; TVectorImageP vi = TImageP(getImage(true)); if (!vi) return; QMutexLocker lock(vi->getMutex()); UINT i, j; for (i = 0; i < m_strokeHit.size(); ++i) { ref = m_strokeHit[i]; ref->enableComputeOfCaches(); ref->reduceControlPoints(getPixelSize() * ReduceControlPointCorrection, *(m_hitStrokeCorners[i])); // vi->validateRegionEdges(ref, false); } clearPointerContainer(m_hitStrokeCorners); m_hitStrokeCorners.clear(); UINT count = 0; for (i = 0; i < m_strokeToModify.size(); ++i) { // recupero la stroke collection MagnetTool::strokeCollection &sc = m_strokeToModify[i]; for (j = 0; j < sc.m_splittedToMove.size(); ++j) { ref = sc.m_splittedToMove[j]; ref->enableComputeOfCaches(); ref->reduceControlPoints(getPixelSize() * ReduceControlPointCorrection, *(m_strokeToModifyCorners[count++])); } // ricostruisco una stroke con quella data ref = merge(sc.m_splitted); if (sc.m_parent->isSelfLoop()) { int cpCount = ref->getControlPointCount(); TThickPoint p1 = ref->getControlPoint(0); TThickPoint p2 = ref->getControlPoint(cpCount - 1); TThickPoint midP = (p1 + p2) * 0.5; ref->setControlPoint(0, midP); ref->setControlPoint(cpCount - 1, midP); ref->setSelfLoop(true); } sc.m_parent->swapGeometry(*ref); delete ref; // elimino la curva temporanea clearPointerContainer(sc.m_splitted); // pulisco le stroke trovate con lo split sc.m_splittedToMove.clear(); // pulisco il contenitore ( le stroke // che erano contenute qua sono state // eliminate nella clearPointer.... } clearPointerContainer(m_strokeToModifyCorners); m_strokeToModifyCorners.clear(); for (i = 0; i < vi->getStrokeCount(); ++i) { ref = vi->getStroke(i); ref->invalidate(); } vi->notifyChangedStrokes(m_changedStrokes, m_oldStrokesArray); notifyImageChanged(); if (m_undo) TUndoManager::manager()->add(m_undo); m_undo = 0; clearPointerContainer(m_oldStrokesArray); m_oldStrokesArray.clear(); invalidate(); };
TThickPoint ControlPointEditorStroke::getControlPoint(int index) const { TStroke *stroke = getStroke(); assert(stroke && 0 <= index && index < (int)m_controlPoints.size()); return stroke->getControlPoint(m_controlPoints[index].m_pointIndex); }