summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFridrich Štrba <fridrich.strba@bluewin.ch>2013-07-09 23:06:59 +0200
committerFridrich Štrba <fridrich.strba@bluewin.ch>2013-07-09 23:06:59 +0200
commit0e8734be3d3294454d3f6f8f9de282c31bdf28bf (patch)
tree334fa69d241ee3d620e07eb2f108f1b46099db70
parent98f9d25aae4de36c75656935da2909d044344398 (diff)
De-uglify a tiny bit the NURBS code
-rw-r--r--src/lib/VSDContentCollector.cpp268
-rw-r--r--src/lib/VSDContentCollector.h12
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;