|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T p
Length: 17489 (0x4451) Types: TextFile Names: »pathlist.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki └─⟦526ad3590⟧ »EUUGD11/gnu-31mar87/X.V10.R4.tar.Z« └─⟦2109abc41⟧ └─⟦this⟧ »./X.V10R4/libibm/libsrc/pathlist.c«
#ifndef lint static char *rcsid_pathlist_c = "$Header: pathlist.c,v 10.1 86/11/19 10:43:18 jg Exp $"; #endif lint /* pathlist.c - Coverter for vertex list * * PathListConverter Convert a list of vertices * into absolute striaght lines * Spline Generates a series of line segments * that make up a smooth curve * Matrix Utility rtn used by Spline to interpolate * points along the curve * * Author: * Scott Bates * Brown University * IRIS, Box 1946 * Providence, RI 02912 * * * Copyright (c) 1986 Brown University * * Permission to use, copy, modify and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided * that the above copyright notice appear in all copies, and that both * that copyright notice and this permission notice appear in supporting * documentation, and that the name of Brown University not be used in * advertising or publicity pertaining to distribution of the software * without specific, written prior permission. Brown University makes no * representations about the suitability of this software for any purpose. * It is provided "as-is" without express or implied warranty. */ #include "private.h" #include "pathlist.h" /* * Convert vertex list */ PathListConverter(verts, vertcount, xbase, ybase, newverts, newvertcount, type) register Vertex *verts; int vertcount; short xbase, ybase; Vertex **newverts; int *newvertcount; int type; { register Vertex *ThisVertex = verts; register Vertex *LastVertex; register Vertex *NewVerts; register Segment *CurrentSegment; register i, j; int VertexCount; int VertexIndex = 0; int SegmentIndex = 0; int CurvedSegments = 0; int MaxSegments = INITIAL_SEGMENTS; int TotalVertexCount = vertcount; #ifdef TRACE_X fprintf (stderr, "In PathListConverter\n"); fflush (stderr); #endif TRACE_X /* * Perform initial allocation of segment table */ CurrentSegment = SegmentTable = (Segment *)malloc(MaxSegments * sizeof(Segment)); if(SegmentTable == NULL) { return(NULL); } /* * Prime first segment table entry */ ThisVertex->x += xbase; ThisVertex->y += ybase; CurrentSegment->Index = 0; CurrentSegment->Count = 1; switch(ThisVertex->flags & VERTEX_TYPE_MASK) { case(LINE): /* First segment is a line */ CurrentSegment->Type = LINE_SEGMENT; break; case(START_CLOSED_CURVE): /* First segment is a closed curve */ CurrentSegment->Type = CLOSED_CURVE_SEGMENT; CurvedSegments++; break; default: /* First segment is a line */ /* * turn off bogus flags and make this first segment a line */ ThisVertex->flags &= ~(START_CLOSED_CURVE | END_CLOSED_CURVE); CurrentSegment->Type = LINE_SEGMENT; } /* * Convert remaining vertices to absolute coordinates and * divide them up into there appropriate segemnts. */ do { if(++VertexIndex < vertcount) { /* * Move on to next vertex and save current vertex */ LastVertex = ThisVertex++; } else { /* * Conversion has completed. If the last segment was a * curved segment verify it before exiting loop. */ if(CurrentSegment->Type == CLOSED_CURVE_SEGMENT && ((ThisVertex->flags & VERTEX_TYPE_MASK) != END_CLOSED_CURVE || CurrentSegment->Count < 3)) { return(NULL); } else if(CurrentSegment->Type == OPEN_CURVE_SEGMENT && CurrentSegment->Count < 3) { return(NULL); } break; } /* * Make Vertex an absolute coordinate */ if(ThisVertex->flags & VertexRelative) { ThisVertex->x += LastVertex->x; ThisVertex->y += LastVertex->y; } else { ThisVertex->x += xbase; ThisVertex->y += ybase; } /* * If this is the last vertex turn off any bogus flags * before processing it */ if((VertexIndex + 1) == vertcount && CurrentSegment->Type != CLOSED_CURVE_SEGMENT) { ThisVertex->flags &= ~(END_CLOSED_CURVE); } /* * add this vertex to the current segement or start a new one. */ switch(ThisVertex->flags & VERTEX_TYPE_MASK) { case(LINE): /* This vertex is a LINE */ switch(LastVertex->flags & VERTEX_TYPE_MASK) { case(LINE): /* Last vertex was a LINE */ /* * Add this vertex to the current segment */ CurrentSegment->Count++; break; case(CURVE): /* Last vertex was a CURVE */ /* * If the current segment type is a closed curve * convert it to an open curve segment. */ if(CurrentSegment->Type == CLOSED_CURVE_SEGMENT) { CurrentSegment->Type = OPEN_CURVE_SEGMENT; if(CurrentSegment->Index > 0) { CurrentSegment->Index--; CurrentSegment->Count++; } } if(++CurrentSegment->Count < 3) { return(NULL); } case(END_CLOSED_CURVE): /* Last vertex was a END_CLOSED_CURVE */ /* * Start a line segment */ StartNewSegment(LINE_SEGMENT, VertexIndex, 1); break; case(START_CLOSED_CURVE): /* Last vertex was start closed curve */ /* * Convert the current segment to a line segment */ CurrentSegment->Type = LINE_SEGMENT; CurrentSegment->Count++; CurvedSegments--; } break; case(CURVE): /* This vertex was a curve */ switch(LastVertex->flags & VERTEX_TYPE_MASK) { case(LINE): /* Last vertex was a line or */ case(END_CLOSED_CURVE): /* end closed curve */ /* * Start an open curve segment */ StartNewSegment(OPEN_CURVE_SEGMENT, VertexIndex - 1, 2); CurvedSegments++; break; case(CURVE): /* Last vertex was a curve or start */ case(START_CLOSED_CURVE): /* closed curve */ /* * Add this vertex to current segment */ CurrentSegment->Count++; } break; case(START_CLOSED_CURVE): /* This vertex is start closed curve */ switch(LastVertex->flags & VERTEX_TYPE_MASK) { case(CURVE): /* Last vertex was a curve */ /* If the current segment type is a closed curve * convert it to a open curve segment. Then start * a closed curve segment using this vertex. */ if(CurrentSegment->Type == CLOSED_CURVE_SEGMENT) { CurrentSegment->Type = OPEN_CURVE_SEGMENT; if(CurrentSegment->Index > 0) { CurrentSegment->Index--; CurrentSegment->Count++; } } if(++CurrentSegment->Count < 3) { return(NULL); } case(LINE): /* Last vertex was a line or */ case(END_CLOSED_CURVE): /* end closed curve */ /* * Start closed curve segemnt */ StartNewSegment(CLOSED_CURVE_SEGMENT, VertexIndex, 1); CurvedSegments++; break; case(START_CLOSED_CURVE): /* Last vertex was start closed curve */ /* * Indicate to caller that there was a * path list error. */ return(NULL); } break; case(END_CLOSED_CURVE): /* This vertex is end closed curve */ /* * Add this vertex to the current segment */ ++CurrentSegment->Count; /* * Last vertex was a curve */ if((LastVertex->flags & VERTEX_TYPE_MASK) == CURVE) { /* * Vaild vertex count of curved segment */ if(CurrentSegment->Count < 3) { return(NULL); } /* * If the current segment is a closed segment * validate that the last vertex of the segment * equals the first. */ if(CurrentSegment->Type == CLOSED_CURVE_SEGMENT) { if(verts[CurrentSegment->Index].x != verts[VertexIndex].x || verts[CurrentSegment->Index].y != verts[VertexIndex].y) { return(NULL); } } else { /* * Start a line segment using this vertex */ StartNewSegment(LINE_SEGMENT, VertexIndex, 1); } } break; default: /* * Indicate to caller that there was a * path list error. */ return(NULL); } } while(1); /* * If there are curved segments in this path list * then perform the required setup and call the spline * rtn . */ SplineUsed = 0; if(CurvedSegments) { Vertex *Vertex_A; Vertex *Vertex_B; Vertex *Vertex_C; Vertex *Vertex_D; int Count; /* * Initial allocating of the spline vertex buffer */ SplineVertexIndex = 0; MaxSplineVerts = INITIAL_SPLINE_VERTS; SplineVertexBuffer = (Vertex *)malloc(MaxSplineVerts * sizeof(Vertex)); if(SplineVertexBuffer == NULL) { return(NULL); } SplineUsed++; /* * Loop thru all the path list segments looking * for all open and closed curve segments. */ for(i = 0; i <= SegmentIndex; i++) { switch((CurrentSegment = &SegmentTable[i])->Type) { case(LINE_SEGMENT): /* * Ignore line segments */ continue; case(OPEN_CURVE_SEGMENT): /* * Generate a series of line segments * that represent the open curve defined * by this segment. */ Count = 0; Vertex_A = &verts[CurrentSegment->Index + CurrentSegment->Count - 1]; Vertex_B = &verts[CurrentSegment->Index]; Vertex_C = Vertex_B + 1; Vertex_D = Vertex_C + 1; CurrentSegment->Index = SplineVertexIndex; j = CurrentSegment->Count - 2; while(1) { Count += Spline(Vertex_A, Vertex_B, Vertex_C, Vertex_D); if(--j == 0) { break; } Vertex_A = Vertex_B; Vertex_B = Vertex_C; Vertex_C = Vertex_D++; } break; case(CLOSED_CURVE_SEGMENT): /* * Generate a series of line segments * that represent the closed curve defined * by this segment. */ Count = 0; LastVertex = &verts[CurrentSegment->Index + 1]; Vertex_A = &verts[CurrentSegment->Index + CurrentSegment->Count - 2]; Vertex_B = &verts[CurrentSegment->Index]; CurrentSegment->Index = SplineVertexIndex; Vertex_C = Vertex_B + 1; Vertex_D = Vertex_C; j = CurrentSegment->Count - 2; while(j--) { Vertex_D++; Count += Spline(Vertex_A, Vertex_B, Vertex_C, Vertex_D); Vertex_A = Vertex_B; Vertex_B = Vertex_C; Vertex_C = Vertex_D; } Vertex_D = LastVertex; Count += Spline(Vertex_A, Vertex_B, Vertex_C, Vertex_D); } /* * Adjust the current segment count and * increase the total vertex to reflect * the new points generated by the spline rtn. */ CurrentSegment->Count = Count; TotalVertexCount += Count; /* * If there are no more curved segments exit early */ if(--CurvedSegments == 0) { break; } } } /* * Allocate space for new vertex list */ NewVerts = *newverts = (Vertex *)malloc((TotalVertexCount << 1) * sizeof(Vertex)); if(NewVerts == NULL) { return(NULL); } /* * Loop thru coordinate list */ for(VertexCount = 0, i = 0; i <= SegmentIndex; i++) { /* * If this segment is a line segment get verts from original * vertex list else use the spline vertex list. */ if((CurrentSegment = &SegmentTable[i])->Type == LINE_SEGMENT) { ThisVertex = &verts[CurrentSegment->Index]; } else { ThisVertex = &SplineVertexBuffer[CurrentSegment->Index]; } /* * Get segment vertex count */ j = CurrentSegment->Count; /* * Convert path list to fill format */ if(type == FILL_PATH_LIST) { do { /* * Something to draw ? */ if(ThisVertex->flags & VertexDontDraw) { /* * Indicate start of closed polygon */ ThisVertex->flags |= START_OF_CLOSED_POLY; /* * Increment vertex pointers */ LastVertex = ThisVertex++; /* * Continue processing of current segment */ continue; } /* * If this vertex is not a dup save the * line segment represented by the last * vertex and this one in NewVerts. * If it is a dup ignore this vertex. */ if(ThisVertex->x != LastVertex->x || ThisVertex->y != LastVertex->y) { /* * Save start and end points of * visible line */ *NewVerts++ = *LastVertex; *NewVerts++ = *ThisVertex; /* * Increment vertex count */ VertexCount += 2; /* * Increment vertex pointers */ LastVertex = ThisVertex++; } else { /* * Ignore this vertex */ ThisVertex++; } }while(--j); } else { do { /* * Something to draw ? */ if(ThisVertex->flags & VertexDontDraw) { /* * Increment vertex pointers */ LastVertex = ThisVertex++; /* * Continue processing current segment */ continue; } if(ThisVertex->x != LastVertex->x || ThisVertex->y != LastVertex->y) { /* * Save start and end points of * visible line */ *NewVerts++ = *LastVertex; *NewVerts = *ThisVertex; /* * Shorten line by one point if * "VertexDrawLastPoint" flag is off */ if(!(ThisVertex->flags & VertexDrawLastPoint)) { int DeltaX, DeltaY; int SignX = 0, SignY = 0; if((DeltaX = ThisVertex->x - LastVertex->x) < 0) { SignX = -1; DeltaX = -DeltaX; } if((DeltaY = ThisVertex->y - LastVertex->y) < 0) { SignY = -1; DeltaY = -DeltaY; } if (DeltaX > DeltaY) { SignX < 0 ? NewVerts->x++ : NewVerts->x--; if ((DeltaX >> 1) <= DeltaY) { SignY < 0 ? NewVerts->y++ : NewVerts->y--; } } else if (DeltaX < DeltaY ) { SignY < 0 ? NewVerts->y++ : NewVerts->y--; if ((DeltaY >> 1) <= DeltaX) { SignX < 0 ? NewVerts->x++ : NewVerts->x--; } } else { if (DeltaX > 0) { SignX < 0 ? NewVerts->x++ : NewVerts->x--; SignY < 0 ? NewVerts->y++ : NewVerts->y--; } else { /* * Line now has a length of zero * so we skip this one. Back up the * buffer pointer and move on to the * next vertex */ NewVerts--; /* * Increment vertex pointers */ LastVertex = ThisVertex++; continue; } } } /* * Advance buffer pointer */ NewVerts++; /* * Increment vertex count */ VertexCount += 2; /* * Increment vertex pointers */ LastVertex = ThisVertex++; } else { /* * Ignore this vertex */ ThisVertex++; } } while(--j); } } /* * Save final vertex count and free any resources used * during path list conversion. */ *newvertcount = VertexCount; free((caddr_t)SegmentTable); if(SplineUsed) { free((caddr_t)SplineVertexBuffer); } return(1); } /* * Generate a series of points that will form * a curve between Vertex_B and Vertex_C. */ static Spline(Vertex_A, Vertex_B, Vertex_C, Vertex_D) register Vertex *Vertex_A; register Vertex *Vertex_B; register Vertex *Vertex_C; register Vertex *Vertex_D; { register Vertex *Verts = &SplineVertexBuffer[SplineVertexIndex]; register i; int nls = 1; int Delta_X, Delta_Y; long Matrix(); #ifdef TRACE_X fprintf (stderr, "In Spline\n"); fflush (stderr); #endif TRACE_X GrowSplineVertexBuffer(Verts, 2); *Verts++ = *Vertex_B; SplineVertexIndex++; if((Vertex_C->flags & VertexDontDraw) == 0) { /* * Compute how many points to generate * based on the largest delta change in either * the X or Y direction. This number represents * the maximum number of points to be generated * and may be reduced by an increasing amount * as the change (delta) gets larger. This allows * us to generate fewer points and therefore * improve performace and still generate * quality smooth curve. */ if((Delta_X = Vertex_C->x - Vertex_B->x) < 0) { Delta_X = -Delta_X; } if((Delta_Y = Vertex_C->y - Vertex_B->y) < 0) { Delta_Y = -Delta_Y; } if(Delta_X > Delta_Y) { if(Delta_X > 64) { nls = Delta_X >> 3; } else if(Delta_X > 32) { nls = Delta_X >> 2; } else if(Delta_X > 16) { nls = Delta_X >> 1; } else { nls = Delta_X; } } else { if(Delta_Y > 64) { nls = Delta_Y >> 3; } else if(Delta_Y > 32) { nls = Delta_Y >> 2; } else if(Delta_Y > 16) { nls = Delta_Y >> 1; } else { nls = Delta_Y; } } /* * Generate the actual points */ if(nls) { GrowSplineVertexBuffer(Verts, nls); for(i = 1; i < nls; i++, Verts++) { Verts->x = Matrix((long)Vertex_A->x, (long)Vertex_B->x, (long)Vertex_C->x, (long)Vertex_D->x, nls, i); Verts->y = Matrix((long)Vertex_A->y, (long)Vertex_B->y, (long)Vertex_C->y, (long)Vertex_D->y, nls, i); Verts->flags = Vertex_C->flags & VertexDrawLastPoint; } SplineVertexIndex += nls; } else { nls = 1; SplineVertexIndex++; } } else { SplineVertexIndex++; } *Verts = *Vertex_C; /* * Return the number of points generated */ return(nls + 1); } /* * This rtn performs the matrix math require to interpolate a * point on the curve represented by a, b, c, and d. The generated * point will be between points b and c. */ static long Matrix(a, b, c, d, nls, i) register long a, b, c, d; register nls; int i; { register long p = SHIFT_LEFT_16(-a + b - c + d); #ifdef TRACE_X fprintf (stderr, "In Matrix\n"); fflush (stderr); #endif TRACE_X p = PERCENT_16(p, i, nls) + SHIFT_LEFT_16((a << 1) - (b << 1) + c - d); p = PERCENT_16(p, i, nls) + SHIFT_LEFT_16(-a + c); return(ROUND_16(PERCENT_16(p, i, nls) + SHIFT_LEFT_16(b))); }