// public-domain code by Darel Rex Finley, 2009
// See diagrams at http://alienryderflex.com/polygon_hatchline_fill
// This function returns NO if MAX_NODES is exceeded, in which case some
// of the stripes may have been drawn, but not all of them.
bool drawDiagonalStripes(long polygonCount, long *polygonCorners,
double **polygons, double spacing) {
#define MAX_NODES 1000
#define FAR_FAR_AWAY 999999999.
double spanMin= FAR_FAR_AWAY, theCos, theSin, nodeX[MAX_NODES] ;
double spanMax=-FAR_FAR_AWAY, x, y, a, b, newX, stripeY, swap ;
long i, j, k, spanStart, spanEnd, nodeCount, step ;
// Create a 45-degree angle for stripes.
theCos=sqrt(.5);
theSin=sqrt(.5);
// Loop to determine the span over which diagonal lines must be drawn.
for (i=0; i<polygonCount ; i++) {
for (j=0; j<polygonCorners[i]; j++) {
x=polygons[i][j*2 ];
y=polygons[i][j*2+1];
// Rotate the point, since the stripes may be at an angle.
y=y*theCos-x*theSin;
// Adjust the span.
if (spanMin>y) spanMin=y;
if (spanMax<y) spanMax=y; }}
// Turn the span into a discrete step range.
spanStart=(long) floor(spanMin/spacing)-1;
spanEnd =(long) floor(spanMax/spacing)+1;
// Loop to create all stripes.
for (step=spanStart; step<=spanEnd; step++) {
nodeCount=0; stripeY=spacing*(double) step;
// Loop to build a node list for one row of stripes.
for (i=0; i<polygonCount ; i++) {
k=polygonCorners[i]-1;
for (j=0; j<polygonCorners[i]; j++) {
a=polygons[i][k*2 ];
b=polygons[i][k*2+1];
x=polygons[i][j*2 ];
y=polygons[i][j*2+1];
// Rotate the points, since the stripes may be at an angle.
newX=a*theCos+b*theSin;
b =b*theCos-a*theSin; a=newX;
newX=x*theCos+y*theSin;
y =y*theCos-x*theSin; x=newX;
// Find the node, if any.
if (b<stripeY && y>=stripeY
|| y<stripeY && b>=stripeY) {
if (nodeCount>=MAX_NODES) return NO;
nodeX[nodeCount++]=a+(x-a)*(stripeY-b)/(y-b); }
k=j; }}
// Sort the node list.
i=0;
while (i<nodeCount-1) {
if (nodeX[i]<=nodeX[i+1]) i++;
else {
swap=nodeX[i]; nodeX[i]=nodeX[i+1]; nodeX[i+1]=swap; if (i) i--; }}
// Loop to draw one row of stripe segments.
for (i=0; i<nodeCount; i+=2) {
// Rotate the points back to their original coordinate system.
a=nodeX[i ]*theCos- stripeY*theSin;
b= stripeY*theCos+nodeX[i ]*theSin;
x=nodeX[i+1]*theCos- stripeY*theSin;
y= stripeY*theCos+nodeX[i+1]*theSin;
// Draw a single stripe segment.
drawLineSegmentABtoXY(a,b,x,y); }}
// Success.
return YES; }
|