diff options
author | Fridrich Štrba <fridrich.strba@bluewin.ch> | 2013-07-09 23:06:59 +0200 |
---|---|---|
committer | Fridrich Štrba <fridrich.strba@bluewin.ch> | 2013-07-09 23:06:59 +0200 |
commit | 0e8734be3d3294454d3f6f8f9de282c31bdf28bf (patch) | |
tree | 334fa69d241ee3d620e07eb2f108f1b46099db70 | |
parent | 98f9d25aae4de36c75656935da2909d044344398 (diff) |
De-uglify a tiny bit the NURBS code
-rw-r--r-- | src/lib/VSDContentCollector.cpp | 268 | ||||
-rw-r--r-- | src/lib/VSDContentCollector.h | 12 |
2 files changed, 122 insertions, 158 deletions
diff --git a/src/lib/VSDContentCollector.cpp b/src/lib/VSDContentCollector.cpp index 4edffb3..2b0b29a 100644 --- a/src/lib/VSDContentCollector.cpp +++ b/src/lib/VSDContentCollector.cpp @@ -1311,192 +1311,155 @@ void libvisio::VSDContentCollector::collectArcTo(unsigned /* id */, unsigned lev } } -void libvisio::VSDContentCollector::_generateCubicBeziersFromNURBS(const std::vector<std::pair<double, double> > &controlPoints, - const std::vector<double> &knotVector) + +void libvisio::VSDContentCollector::_outputCubicBezierSegment(const std::vector<std::pair<double, double> > &points) { - if (controlPoints.empty() || knotVector.empty()) + if (points.size() < 4) return; - WPXPropertyList node; + node.insert("libwpg:path-action", "C"); + double x = points[1].first; + double y = points[1].second; + transformPoint(x, y); + node.insert("svg:x1", m_scale*x); + node.insert("svg:y1", m_scale*y); + x = points[2].first; + y = points[2].second; + transformPoint(x, y); + node.insert("svg:x2", m_scale*x); + node.insert("svg:y2", m_scale*y); + x = points[3].first; + y = points[3].second; + transformPoint(x, y); + node.insert("svg:x", m_scale*x); + node.insert("svg:y", m_scale*y); - /* Decomposition of a spline of 3rd degree into Bezier segments - * adapted from the algorithm DecomposeCurve (Les Piegl, Wayne Tiller: - * The NURBS Book, 2nd Edition, 1997 - */ - - unsigned m = controlPoints.size() + 4; - unsigned a = 3; - unsigned b = 4; - std::vector< std::pair<double, double> > Qw(4), NextQw(4); - unsigned i = 0; - for (; i <= 3; i++) - Qw[i] = controlPoints[i]; - while (b < m) - { - i = b; - while (b < m && knotVector[b+1] == knotVector[b]) - b++; - unsigned mult = b - i + 1; - if (mult < 3) - { - double numer = (double)(knotVector[b] - knotVector[a]); - unsigned j = 3; - std::map<unsigned, double> alphas; - for (; j >mult; j--) - alphas[j-mult-1] = numer/double(knotVector[a+j]-knotVector[a]); - unsigned r = 3 - mult; - for (j=1; j<=r; j++) - { - unsigned save = r - j; - unsigned s = mult+j; - for (unsigned k = 3; k>=s; k--) - { - double alpha = alphas[k-s]; - Qw[k].first = alpha*Qw[k].first + (1.0-alpha)*Qw[k-1].first; - Qw[k].second = alpha*Qw[k].second + (1.0-alpha)*Qw[k-1].second; - } - if (b < m) - { - NextQw[save].first = Qw[3].first; - NextQw[save].second = Qw[3].second; - } - } - } - // Pass the segment to the path + if (!m_noFill && !m_noShow) + m_currentFillGeometry.push_back(node); + if (!m_noLine && !m_noShow) + m_currentLineGeometry.push_back(node); +} - node.clear(); - node.insert("libwpg:path-action", "C"); - double x = Qw[1].first; - double y = Qw[1].second; - transformPoint(x, y); - node.insert("svg:x1", m_scale*x); - node.insert("svg:y1", m_scale*y); - x = Qw[2].first; - y = Qw[2].second; - transformPoint(x, y); - node.insert("svg:x2", m_scale*x); - node.insert("svg:y2", m_scale*y); - x = Qw[3].first; - y = Qw[3].second; - transformPoint(x, y); - node.insert("svg:x", m_scale*x); - node.insert("svg:y", m_scale*y); +void libvisio::VSDContentCollector::_outputQuadraticBezierSegment(const std::vector<std::pair<double, double> > &points) +{ + if (points.size() < 3) + return; + WPXPropertyList node; + node.insert("libwpg:path-action", "Q"); + double x = points[1].first; + double y = points[1].second; + transformPoint(x, y); + node.insert("svg:x1", m_scale*x); + node.insert("svg:y1", m_scale*y); + x = points[2].first; + y = points[2].second; + transformPoint(x, y); + node.insert("svg:x", m_scale*x); + node.insert("svg:y", m_scale*y); - if (!m_noFill && !m_noShow) - m_currentFillGeometry.push_back(node); - if (!m_noLine && !m_noShow) - m_currentLineGeometry.push_back(node); + if (!m_noFill && !m_noShow) + m_currentFillGeometry.push_back(node); + if (!m_noLine && !m_noShow) + m_currentLineGeometry.push_back(node); +} - std::swap(Qw, NextQw); +void libvisio::VSDContentCollector::_outputLinearBezierSegment(const std::vector<std::pair<double, double> > &points) +{ + if (points.size() < 2) + return; + WPXPropertyList node; + node.insert("libwpg:path-action", "L"); + double x = points[1].first; + double y = points[1].second; + transformPoint(x, y); + node.insert("svg:x", m_scale*x); + node.insert("svg:y", m_scale*y); - if (b < m) - { - for (i=3-mult; i <= 3; i++) - { - Qw[i].first = controlPoints[b-3+i].first; - Qw[i].second = controlPoints[b-3+i].second; - } - a = b; - b++; - } - } - m_originalX = controlPoints.back().first; - m_originalY = controlPoints.back().second; - m_x = controlPoints.back().first; - m_y = controlPoints.back().second; - transformPoint(m_x, m_y); + if (!m_noFill && !m_noShow) + m_currentFillGeometry.push_back(node); + if (!m_noLine && !m_noShow) + m_currentLineGeometry.push_back(node); } - -void libvisio::VSDContentCollector::_generateQuadraticBeziersFromNURBS(const std::vector<std::pair<double, double> > &controlPoints, - const std::vector<double> &knotVector) +void libvisio::VSDContentCollector::_generateBezierSegmentsFromNURBS(unsigned degree, + const std::vector<std::pair<double, double> > &controlPoints, const std::vector<double> &knotVector) { - if (controlPoints.empty() || knotVector.empty()) + if (controlPoints.empty() || knotVector.empty() || !degree) return; - WPXPropertyList node; - - /* Decomposition of a spline of 2nd degree into Bezier segments + /* Decomposition of a uniform spline of a given degree into Bezier segments * adapted from the algorithm DecomposeCurve (Les Piegl, Wayne Tiller: * The NURBS Book, 2nd Edition, 1997 */ - unsigned m = controlPoints.size() + 3; - unsigned a = 2; - unsigned b = 3; - std::vector< std::pair<double, double> > Qw(3), NextQw(3); + unsigned m = controlPoints.size() + degree + 1; + unsigned a = degree; + unsigned b = degree + 1; + std::vector< std::pair<double, double> > points(degree + 1), nextPoints(degree + 1); unsigned i = 0; - for (; i <= 2; i++) - Qw[i] = controlPoints[i]; + for (; i <= degree; i++) + points[i] = controlPoints[i]; while (b < m) { i = b; while (b < m && knotVector[b+1] == knotVector[b]) b++; unsigned mult = b - i + 1; - if (mult < 2) + if (mult < degree) { double numer = (double)(knotVector[b] - knotVector[a]); - unsigned j = 2; + unsigned j = degree; std::map<unsigned, double> alphas; for (; j >mult; j--) alphas[j-mult-1] = numer/double(knotVector[a+j]-knotVector[a]); - unsigned r = 2 - mult; + unsigned r = degree - mult; for (j=1; j<=r; j++) { unsigned save = r - j; unsigned s = mult+j; - for (unsigned k = 2; k>=s; k--) + for (unsigned k = degree; k>=s; k--) { double alpha = alphas[k-s]; - Qw[k].first = alpha*Qw[k].first + (1.0-alpha)*Qw[k-1].first; - Qw[k].second = alpha*Qw[k].second + (1.0-alpha)*Qw[k-1].second; + points[k].first = alpha*points[k].first + (1.0-alpha)*points[k-1].first; + points[k].second = alpha*points[k].second + (1.0-alpha)*points[k-1].second; } if (b < m) { - NextQw[save].first = Qw[2].first; - NextQw[save].second = Qw[2].second; + nextPoints[save].first = points[degree].first; + nextPoints[save].second = points[degree].second; } } } // Pass the segment to the path - node.clear(); - node.insert("libwpg:path-action", "Q"); - double x = Qw[1].first; - double y = Qw[1].second; - transformPoint(x, y); - node.insert("svg:x1", m_scale*x); - node.insert("svg:y1", m_scale*y); - x = Qw[2].first; - y = Qw[2].second; - transformPoint(x, y); - node.insert("svg:x", m_scale*x); - node.insert("svg:y", m_scale*y); - - if (!m_noFill && !m_noShow) - m_currentFillGeometry.push_back(node); - if (!m_noLine && !m_noShow) - m_currentLineGeometry.push_back(node); + switch (degree) + { + case 1: + _outputLinearBezierSegment(points); + break; + case 2: + _outputQuadraticBezierSegment(points); + break; + case 3: + _outputCubicBezierSegment(points); + break; + default: + break; + } - std::swap(Qw, NextQw); + std::swap(points, nextPoints); if (b < m) { - for (i=2-mult; i <= 2; i++) + for (i=degree-mult; i <= degree; i++) { - Qw[i].first = controlPoints[b-2+i].first; - Qw[i].second = controlPoints[b-2+i].second; + points[i].first = controlPoints[b-degree+i].first; + points[i].second = controlPoints[b-degree+i].second; } a = b; b++; } } - m_originalX = controlPoints.back().first; - m_originalY = controlPoints.back().second; - m_x = controlPoints.back().first; - m_y = controlPoints.back().second; - transformPoint(m_x, m_y); } #define VSD_NUM_POLYLINES_PER_NURBS 200 @@ -1534,22 +1497,20 @@ void libvisio::VSDContentCollector::_generatePolylineFromNURBS(unsigned degree, m_currentLineGeometry.push_back(node); } - m_originalX = controlPoints.back().first; - m_originalY = controlPoints.back().second; - m_x = controlPoints.back().first; - m_y = controlPoints.back().second; - transformPoint(m_x, m_y); + double x = controlPoints.back().first; + double y = controlPoints.back().second; + transformPoint(x, y); node.clear(); node.insert("libwpg:path-action", "L"); - node.insert("svg:x", m_scale*m_x); - node.insert("svg:y", m_scale*m_y); + node.insert("svg:x", m_scale*x); + node.insert("svg:y", m_scale*y); if (!m_noFill && !m_noShow) m_currentFillGeometry.push_back(node); if (!m_noLine && !m_noShow) m_currentLineGeometry.push_back(node); } -bool libvisio::VSDContentCollector::_areWeightsUniform(const std::vector<double> weights) const +bool libvisio::VSDContentCollector::_isUniform(const std::vector<double> weights) const { if (weights.empty()) return true; @@ -1574,13 +1535,6 @@ void libvisio::VSDContentCollector::collectNURBSTo(unsigned /* id */, unsigned l // Here, maybe we should just draw line to (x2,y2) return; - // Fill in end knots - while (knotVector.size() < (controlPoints.size() + degree + 3)) - { - double tmpBack = knotVector.back(); - knotVector.push_back(tmpBack); - } - // Convert control points to static co-ordinates for (std::vector<std::pair<double, double> >::iterator it = controlPoints.begin(); it != controlPoints.end(); ++it) @@ -1595,15 +1549,23 @@ void libvisio::VSDContentCollector::collectNURBSTo(unsigned /* id */, unsigned l controlPoints.push_back(std::pair<double,double>(x2, y2)); controlPoints.insert(controlPoints.begin(), std::pair<double, double>(m_originalX, m_originalY)); - if ((degree == 2 || degree == 3) && _areWeightsUniform(weights)) + // Fill in end knots + while (knotVector.size() < (controlPoints.size() + degree + 1)) { - if (degree == 2) - _generateQuadraticBeziersFromNURBS(controlPoints, knotVector); - else - _generateCubicBeziersFromNURBS(controlPoints, knotVector); + double tmpBack = knotVector.back(); + knotVector.push_back(tmpBack); } + + if (degree <= 3 && _isUniform(weights)) + _generateBezierSegmentsFromNURBS(degree, controlPoints, knotVector); else _generatePolylineFromNURBS(degree, controlPoints, knotVector, weights); + + m_originalX = controlPoints.back().first; + m_originalY = controlPoints.back().second; + m_x = controlPoints.back().first; + m_y = controlPoints.back().second; + transformPoint(m_x, m_y); } double libvisio::VSDContentCollector::_NURBSBasis(unsigned knot, unsigned degree, double point, const std::vector<double> &knotVector) diff --git a/src/lib/VSDContentCollector.h b/src/lib/VSDContentCollector.h index 0d1fd27..59e6614 100644 --- a/src/lib/VSDContentCollector.h +++ b/src/lib/VSDContentCollector.h @@ -220,13 +220,15 @@ private: bool parseFormatId( const char *formatString, unsigned short &result ); void _appendField(WPXString &text); - void _generateCubicBeziersFromNURBS(const std::vector<std::pair<double, double> > &controlPoints, - const std::vector<double> &knotVector); - void _generateQuadraticBeziersFromNURBS(const std::vector<std::pair<double, double> > &controlPoints, - const std::vector<double> &knotVector); + // NURBS processing functions + bool _isUniform(const std::vector<double> weights) const; void _generatePolylineFromNURBS(unsigned degree, const std::vector<std::pair<double, double> > &controlPoints, const std::vector<double> &knotVector, const std::vector<double> &weights); - bool _areWeightsUniform(const std::vector<double> weights) const; + void _generateBezierSegmentsFromNURBS(unsigned degree, const std::vector<std::pair<double, double> > &controlPoints, + const std::vector<double> &knotVector); + void _outputCubicBezierSegment(const std::vector<std::pair<double, double> > &points); + void _outputQuadraticBezierSegment(const std::vector<std::pair<double, double> > &points); + void _outputLinearBezierSegment(const std::vector<std::pair<double, double> > &points); bool m_isPageStarted; double m_pageWidth; |