void drvIDRAW::print_coords() { unsigned int pathelts = numberOfElementsInPath(); bool closed; // True if shape is closed bool curved; // True if shape is curved const Point *firstpoint; // First and last points in shape const Point *lastpoint; unsigned int totalpoints; // Total number of points in shape const Point dummypoint(-123.456f, -789.101112f); // Used to help eliminate duplicates unsigned int i, j; // First, try to figure out what type of shape we have closed = false; curved = false; for (i = 0; i < pathelts; i++) { if (pathElement(i).getType() == curveto) curved = true; else if (pathElement(i).getType() == closepath) closed = true; } const Point **pointlist = new const Point *[pathelts * 3]; // List of points // Allocate a conservative amount assert(pointlist != NIL); firstpoint = NIL; lastpoint = &dummypoint; totalpoints = 0; for (i = 0; i < pathelts; i++) { const basedrawingelement & pelt = pathElement(i); if ((pelt.getType() == moveto || pelt.getType() == lineto) && !(pelt.getPoint(0) == *lastpoint)) lastpoint = pointlist[totalpoints++] = &pelt.getPoint(0); else if (pelt.getType() == curveto) for (j = 0; j < 3; j++) lastpoint = pointlist[totalpoints++] = &pelt.getPoint(j); } if (totalpoints) { firstpoint = pointlist[0]; if (firstpoint->x_ == lastpoint->x_ && firstpoint->y_ == lastpoint->y_) closed = true; // Find points on the curve for curved lines if (curved) { const unsigned int pt_per_cp = 5; // PostScript points per control point const unsigned int min_innerpoints = 2; // Minimum # of points to add unsigned int innerpoints; // Number of points to add unsigned int newtotalpoints = 0; // Number of points in curve // ASSUMPTION: Curve is moveto+curveto+curveto+curveto+... // List of points on curve const Point **newpointlist = new const Point *[pathelts * 3000 / pt_per_cp]; // Allocate a conservative amount assert(newpointlist != NIL); for (i = 0; i < totalpoints - 3; i += 3) { const float x0 = pointlist[i]->x_; const float y0 = pointlist[i]->y_; const float x1 = pointlist[i + 1]->x_; const float y1 = pointlist[i + 1]->y_; const float x2 = pointlist[i + 2]->x_; const float y2 = pointlist[i + 2]->y_; const float x3 = pointlist[i + 3]->x_; const float y3 = pointlist[i + 3]->y_; const float cx = (x1 - x0) * 3; const float cy = (y1 - y0) * 3; const float bx = (x2 - x1) * 3 - cx; const float by = (y2 - y1) * 3 - cy; const float ax = x3 - x0 - cx - bx; const float ay = y3 - y0 - cy - by; // Longer lines get more control points innerpoints =(unsigned int) ( pythagoras((y1 - y0),(x1 - x0) ) + pythagoras((y2 - y1),(x2 - x1) ) + pythagoras((y3 - y2),(x3 - x2) ) ) / pt_per_cp; if (innerpoints < min_innerpoints) innerpoints = min_innerpoints; // Add points to the list ADDPOINT(x0, y0); for (j = 1; j <= innerpoints; j++) { const float t = (float) j / (float) innerpoints; const float newx = (((ax * t) + bx) * t + cx) * t + x0; const float newy = (((ay * t) + by) * t + cy) * t + y0; ADDPOINT(newx, newy); } ADDPOINT(x3, y3); } delete[]pointlist; pointlist = newpointlist; totalpoints = newtotalpoints; } // Straight lines, not closed if (!closed && !curved) { if (totalpoints == 2) { // Special case for single line print_header("Line"); outf << "%I" << endl; outf << iscale(firstpoint->x_) << ' ' << iscale(firstpoint->y_) << ' '; outf << iscale(lastpoint->x_) << ' ' << iscale(lastpoint->y_) << ' '; outf << "Line" << endl; outf << "%I 1" << endl; outf << "End" << endl << endl; } else { // Otherwise, output a multiline print_header("MLine"); // (Should have a special case for Rect) outf << "%I " << totalpoints << endl; for (i = 0; i < totalpoints; i++) { outf << iscale(pointlist[i]->x_) << ' '; outf << iscale(pointlist[i]->y_) << endl; } outf << totalpoints << " MLine" << endl; outf << "%I 1" << endl; outf << "End" << endl << endl; } } // Straight lines, closed */ if (closed && !curved) { unsigned int numpoints; numpoints = totalpoints == 1 ? 1 : totalpoints - 1; print_header("Poly"); // Output a polygon outf << "%I " << numpoints << endl; for (i = 0; i < numpoints; i++) { outf << iscale(pointlist[i]->x_) << ' '; outf << iscale(pointlist[i]->y_) << endl; } outf << numpoints << " Poly" << endl; outf << "End" << endl << endl; } // Curved lines, not closed if (!closed && curved) { print_header("BSpl"); // Output a B-spline outf << "%I " << totalpoints << endl; for (i = 0; i < totalpoints; i++) { outf << iscale(pointlist[i]->x_) << ' '; outf << iscale(pointlist[i]->y_) << endl; } outf << totalpoints << " BSpl" << endl; outf << "%I 1" << endl; outf << "End" << endl << endl; } // Curved lines, closed if (closed && curved) { unsigned int numpoints; numpoints = totalpoints == 1 ? 1 : totalpoints - 1; print_header("CBSpl"); // Output a closed B-spline outf << "%I " << numpoints << endl; for (i = 0; i < numpoints; i++) { outf << iscale(pointlist[i]->x_) << ' '; outf << iscale(pointlist[i]->y_) << endl; } outf << numpoints << " CBSpl" << endl; outf << "End" << endl << endl; } if (curved) { // // in this case we have created the pointlist newly with Points on the heap // if (pointlist) for (unsigned int pindex = 0; pindex < totalpoints; pindex++) { //cout << "pindex / totalpoints " << pindex << " " << totalpoints << " " << pointlist[pindex]->x_ << " " << pointlist[pindex]->y_ << " " << pointlist[pindex]<< endl; #if defined (_MSC_VER) && (_MSC_VER < 1100) // MSVC < 6 needs cast here delete (Point *) (pointlist[pindex]); #else delete (pointlist[pindex]); #endif } } } delete[]pointlist; }
PyObject* compute_path_bbox( PyObject* self, PyObject* args ) { PyObject* pobj; PyObject* plist = NULL; PyObject* cacheobj = NULL; int i; int size; PyObject* item; int cset = 0; // is there a current point? double sx, sy; // start of subpath double cx, cy; // current point double c[8]; int j, k; double *xy; int empty = 1; double minx, maxx, miny, maxy; if ( !PyArg_ParseTuple( args, "O", &pobj ) ) return NULL; cacheobj = PyObject_GetAttrString( pobj, "_bbox" ); if ( cacheobj && cacheobj != Py_None ) { Py_INCREF( cacheobj ); } else { plist = PyObject_GetAttrString( pobj, "raw" ); if ( plist == NULL || !PyList_Check( plist ) ) { Py_XDECREF( plist ); PyErr_SetString( DrawError, "bad path object" ); return NULL; } size = PyList_Size( plist ); for ( i = 0; i < size; ++i ) { item = PyList_GetItem( plist, i ); #define ADDPOINT(x,y) {if(empty){empty=0;minx=maxx=(x);miny=maxy=(y);}else{ if((x)<minx)minx=(x);else if((x)>maxx)maxx=(x); if((y)<miny)miny=(y);else if((y)>maxy)maxy=(y);}} switch( PyInt_AsLong( PyList_GetItem( item, 0 ) ) ) { case S_CLOSE: ADDPOINT( sx, sy ); cset = 0; break; case S_MOVE: sx = cx = PyFloat_AsDouble( PyList_GetItem( item, 1 ) ); sy = cy = PyFloat_AsDouble( PyList_GetItem( item, 2 ) ); cset = 1; break; case S_LINE: ADDPOINT( cx, cy ); cx = PyFloat_AsDouble( PyList_GetItem( item, 1 ) ); cy = PyFloat_AsDouble( PyList_GetItem( item, 2 ) ); ADDPOINT( cx, cy ); break; case S_CURVE: c[0] = cx; c[1] = cy; for ( j = 0; j < 6; ++j ) c[j+2] = PyFloat_AsDouble( PyList_GetItem( item, j+1 ) ); cx = c[6]; cy = c[7]; xy = bezier_points( &k, 4, c, 0.001, 0 ); for ( j = 0; j < k; ++j ) ADDPOINT( xy[j*2], xy[j*2+1] ); break; case S_QCURVE: c[0] = cx; c[1] = cy; for ( j = 0; j < 4; ++j ) c[j+2] = PyFloat_AsDouble( PyList_GetItem( item, j+1 ) ); cx = c[4]; cy = c[5]; xy = bezier_points( &k, 3, c, 0.001, 0 ); for ( j = 0; j < k; ++j ) ADDPOINT( xy[j*2], xy[j*2+1] ); break; } } cacheobj = Py_BuildValue( "dddd", minx, miny, maxx, maxy ); PyObject_SetAttrString( pobj, "_bbox", cacheobj ); } Py_XDECREF( plist ); Py_INCREF( Py_None ); return cacheobj; }