Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a061681

Browse files
committed
Speed improvements for path simplification algorithm.
svn path=/trunk/matplotlib/; revision=4885
1 parent 696420e commit a061681

2 files changed

Lines changed: 50 additions & 60 deletions

File tree

src/_backend_agg.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ bool should_snap(Path& path, const agg::trans_affine& trans) {
370370

371371
template<class Path>
372372
bool should_simplify(Path& path) {
373-
return !path.has_curves() && path.total_vertices() > 5;
373+
return !path.has_curves() && path.total_vertices() >= 128;
374374
}
375375

376376
Py::Object
@@ -803,10 +803,7 @@ void RendererAgg::_draw_path(path_t& path, bool has_clippath,
803803
if (gc.linewidth != 0.0) {
804804
double linewidth = gc.linewidth;
805805
if (!gc.isaa) {
806-
if (linewidth < 0.5)
807-
linewidth = 0.5;
808-
else
809-
linewidth = round(linewidth);
806+
linewidth = (linewidth < 0.5) ? 0.5 : round(linewidth);
810807
}
811808
if (gc.dashes.size() == 0) {
812809
stroke_t stroke(path);

src/agg_py_path_iterator.h

Lines changed: 48 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ class PathIterator
2424

2525
m_vertices = (PyArrayObject*)PyArray_FromObject
2626
(vertices_obj.ptr(), PyArray_DOUBLE, 2, 2);
27-
if (!m_vertices || PyArray_NDIM(m_vertices) != 2 || PyArray_DIM(m_vertices, 1) != 2)
27+
if (!m_vertices ||
28+
PyArray_NDIM(m_vertices) != 2 ||
29+
PyArray_DIM(m_vertices, 1) != 2)
2830
throw Py::ValueError("Invalid vertices array.");
2931

3032
if (codes_obj.ptr() != Py_None)
@@ -116,7 +118,7 @@ class SimplifyPath
116118
SimplifyPath(VertexSource& source, bool quantize, bool simplify,
117119
double width = 0.0, double height = 0.0) :
118120
m_source(&source), m_quantize(quantize), m_simplify(simplify),
119-
m_width(width), m_height(height),
121+
m_width(width), m_height(height), m_queue_read(0), m_queue_write(0),
120122
m_moveto(true), m_lastx(0.0), m_lasty(0.0), m_clipped(false),
121123
m_do_clipping(width > 0.0 && height > 0.0),
122124
m_origdx(0.0), m_origdy(0.0),
@@ -177,19 +179,21 @@ class SimplifyPath
177179
// will be popped from the queue in subsequent calls. The following
178180
// block will empty the queue before proceeding to the main loop below.
179181
// -- Michael Droettboom
180-
if (m_queue.size())
182+
if (m_queue_read < m_queue_write)
181183
{
182-
const item& front = m_queue.front();
184+
const item& front = m_queue[m_queue_read++];
183185
unsigned cmd = front.cmd;
184186
*x = front.x;
185187
*y = front.y;
186-
m_queue.pop();
187188
#if DEBUG_SIMPLIFY
188189
printf((cmd == agg::path_cmd_move_to) ? "|" : "-");
189190
#endif
190191
return cmd;
191192
}
192193

194+
m_queue_read = 0;
195+
m_queue_write = 0;
196+
193197
// If the queue is now empty, and the path was fully consumed
194198
// in the last call to the main loop, return agg::path_cmd_stop to
195199
// signal that there are no more points to emit.
@@ -200,8 +204,8 @@ class SimplifyPath
200204
return agg::path_cmd_stop;
201205
}
202206

203-
// The main simplification loop. The point is consume only as many
204-
// points as necessary until some have been added to the outbound
207+
// The main simplification loop. The point is to consume only as many
208+
// points as necessary until something has been added to the outbound
205209
// queue, not to run through the entire path in one go. This
206210
// eliminates the need to allocate and fill an entire additional path
207211
// array on each draw.
@@ -241,10 +245,10 @@ class SimplifyPath
241245
//skip any lines that are outside the drawing area. Note: More lines
242246
//could be clipped, but a more involved calculation would be needed
243247
if (m_do_clipping &&
244-
((*x < -1 && m_lastx < -1) ||
245-
(*x > m_width + 1 && m_lastx > m_width + 1) ||
246-
(*y < -1 && m_lasty < -1) ||
247-
(*y > m_height + 1 && m_lasty > m_height + 1)))
248+
((*x < -1.0 && m_lastx < -1.0) ||
249+
(*x > m_width + 1.0 && m_lastx > m_width + 1.0) ||
250+
(*y < -1.0 && m_lasty < -1.0) ||
251+
(*y > m_height + 1.0 && m_lasty > m_height + 1.0)))
248252
{
249253
m_lastx = *x;
250254
m_lasty = *y;
@@ -264,31 +268,24 @@ class SimplifyPath
264268
{
265269
if (m_clipped)
266270
{
267-
m_queue.push(item(agg::path_cmd_move_to, m_lastx, m_lasty));
271+
m_queue[m_queue_write++].set(agg::path_cmd_move_to, m_lastx, m_lasty);
268272
m_clipped = false;
269273
}
270274

271275
m_origdx = *x - m_lastx;
272276
m_origdy = *y - m_lasty;
273-
m_origdNorm2 = m_origdx*m_origdx + m_origdy+m_origdy;
277+
m_origdNorm2 = m_origdx*m_origdx + m_origdy*m_origdy;
274278

275279
//set all the variables to reflect this new orig vecor
276280
m_dnorm2Max = m_origdNorm2;
277-
m_dnorm2Min = 0;
281+
m_dnorm2Min = 0.0;
278282
m_haveMin = false;
279283
m_lastMax = true;
280284

281-
m_maxX = *x;
282-
m_maxY = *y;
283-
m_minX = m_lastx;
284-
m_minY = m_lasty;
285-
286-
m_lastWrittenX = m_lastx;
287-
m_lastWrittenY = m_lasty;
288-
289-
// set the last point seen
290-
m_lastx = *x;
291-
m_lasty = *y;
285+
m_lastx = m_maxX = *x;
286+
m_lasty = m_maxY = *y;
287+
m_lastWrittenX = m_minX = m_lastx;
288+
m_lastWrittenY = m_minY = m_lasty;
292289
#if DEBUG_SIMPLIFY
293290
m_skipped++;
294291
#endif
@@ -313,7 +310,6 @@ class SimplifyPath
313310
// get the para vector ( = (o.v)o/(o.o))
314311
double paradx = totdot*m_origdx/m_origdNorm2;
315312
double parady = totdot*m_origdy/m_origdNorm2;
316-
double paradNorm2 = paradx*paradx + parady*parady;
317313

318314
// get the perp vector ( = v - para)
319315
double perpdx = totdx - paradx;
@@ -330,6 +326,8 @@ class SimplifyPath
330326
//direction. If anti-p, test if it is the longest in the
331327
//opposite direction (the min of our final line)
332328

329+
double paradNorm2 = paradx*paradx + parady*parady;
330+
333331
m_lastMax = false;
334332
if (totdot >= 0)
335333
{
@@ -368,49 +366,39 @@ class SimplifyPath
368366
//direction we are drawing in, move back to we start drawing from
369367
//back there.
370368
if (m_haveMin)
371-
m_queue.push(item(agg::path_cmd_line_to, m_minX, m_minY));
372-
m_queue.push(item(agg::path_cmd_line_to, m_maxX, m_maxY));
369+
m_queue[m_queue_write++].set(agg::path_cmd_move_to, m_minX, m_minY);
370+
m_queue[m_queue_write++].set(agg::path_cmd_line_to, m_maxX, m_maxY);
373371

374372
//if we clipped some segments between this line and the next line
375373
//we are starting, we also need to move to the last point.
376374
if (m_clipped)
377-
{
378-
m_queue.push(item(agg::path_cmd_move_to, m_lastx, m_lasty));
379-
}
375+
m_queue[m_queue_write++].set(agg::path_cmd_move_to, m_lastx, m_lasty);
380376
else if (!m_lastMax)
381-
{
382377
//if the last line was not the longest line, then move back to
383378
//the end point of the last line in the sequence. Only do this
384379
//if not clipped, since in that case lastx,lasty is not part of
385380
//the line just drawn.
386381

387382
//Would be move_to if not for the artifacts
388-
m_queue.push(item(agg::path_cmd_line_to, m_lastx, m_lasty));
389-
}
383+
m_queue[m_queue_write++].set(agg::path_cmd_line_to, m_lastx, m_lasty);
390384

391385
//now reset all the variables to get ready for the next line
392386
m_origdx = *x - m_lastx;
393387
m_origdy = *y - m_lasty;
394388
m_origdNorm2 = m_origdx*m_origdx + m_origdy*m_origdy;
395389

396390
m_dnorm2Max = m_origdNorm2;
397-
m_dnorm2Min = 0;
391+
m_dnorm2Min = 0.0;
398392
m_haveMin = false;
399393
m_lastMax = true;
400-
m_maxX = *x;
401-
m_maxY = *y;
402-
m_minX = m_lastx;
403-
m_minY = m_lasty;
404-
405-
m_lastWrittenX = m_lastx;
406-
m_lastWrittenY = m_lasty;
394+
m_lastx = m_maxX = *x;
395+
m_lasty = m_maxY = *y;
396+
m_lastWrittenX = m_minX = m_lastx;
397+
m_lastWrittenY = m_minY = m_lasty;
407398

408399
m_clipped = false;
409-
410-
m_lastx = *x;
411-
m_lasty = *y;
412400
#if DEBUG_SIMPLIFY
413-
m_pushed += m_queue.size();
401+
m_pushed += m_queue_write - m_queue_read;
414402
#endif
415403
break;
416404
}
@@ -423,21 +411,20 @@ class SimplifyPath
423411
if (m_origdNorm2 != 0)
424412
{
425413
if (m_haveMin)
426-
m_queue.push(item(agg::path_cmd_line_to, m_minX, m_minY));
427-
m_queue.push(item(agg::path_cmd_line_to, m_maxX, m_maxY));
414+
m_queue[m_queue_write++].set(agg::path_cmd_line_to, m_minX, m_minY);
415+
m_queue[m_queue_write++].set(agg::path_cmd_line_to, m_maxX, m_maxY);
428416
}
429417
m_done = true;
430418
}
431419

432420
// Return the first item in the queue, if any, otherwise
433421
// indicate that we're done.
434-
if (m_queue.size())
422+
if (m_queue_read < m_queue_write)
435423
{
436-
const item& front = m_queue.front();
424+
const item& front = m_queue[m_queue_read++];
437425
unsigned cmd = front.cmd;
438426
*x = front.x;
439427
*y = front.y;
440-
m_queue.pop();
441428
#if DEBUG_SIMPLIFY
442429
printf((cmd == agg::path_cmd_move_to) ? "|" : "-");
443430
#endif
@@ -460,14 +447,20 @@ class SimplifyPath
460447

461448
struct item
462449
{
463-
item(unsigned cmd_, const double& x_, double& y_) :
464-
cmd(cmd_), x(x_), y(y_) {}
450+
item() {}
451+
inline void set(const unsigned cmd_, const double& x_, const double& y_) {
452+
cmd = cmd_;
453+
x = x_;
454+
y = y_;
455+
}
465456
unsigned cmd;
466457
double x;
467458
double y;
468459
};
469-
typedef std::queue<item> ItemQueue;
470-
ItemQueue m_queue;
460+
int m_queue_read;
461+
int m_queue_write;
462+
item m_queue[6];
463+
471464
bool m_moveto;
472465
double m_lastx, m_lasty;
473466
bool m_clipped;

0 commit comments

Comments
 (0)