📄 paths.c
字号:
switch (p->type) { case LINETYPE: case MOVETYPE: break; case CONICTYPE: {/*The logic of this is that the new M point (stored relative to the newbeginning) is (M - C). However, C ("dest") has already been reversedSo, we add "dest" instead of subtracting it:*/ register struct conicsegment *cp = (struct conicsegment *) p; cp->M.x += p->dest.x; cp->M.y += p->dest.y; } break; case BEZIERTYPE: { register struct beziersegment *bp = (struct beziersegment *) p; bp->B.x += p->dest.x; bp->B.y += p->dest.y; bp->C.x += p->dest.x; bp->C.y += p->dest.y; } break; case HINTTYPE: { register struct hintsegment *hp = (struct hintsegment *) p; hp->ref.x = -hp->ref.x; hp->ref.y = -hp->ref.y; } break; default: abort("Reverse: bad path segment", 23); }/*We need to reverse the order of segments too, so we break this segmentoff of the input path, and tack it on the front of the growing pathin 'r':*/ nextp = p->link; p->link = NULL; p->last = p; if (r != NULL) CONCAT(p,r); /* leaves result in 'p'... not what we want */ r = p; p = nextp; /* advance to next segment in input path */ } while (p != NULL); if (wasclosed) r = ClosePath(r); return(r);} /*:h4.DropSubPath() - Drops the First Sub-Path Off a Path This subroutine returns the remaining sub-path(s). While doing so, itbreaks the input path after the first sub-path so that a pointer tothe original path now contains the first sub-path only.*/ static struct segment *DropSubPath(p0) register struct segment *p0; /* original path */{ register struct segment *p; /* returned remainder here */ for (p = p0; p->link != NULL; p = p->link) { if (p->link->type == MOVETYPE) break; } return(SplitPath(p0, p));} static struct segment *SplitPath(anchor, before) register struct segment *anchor; register struct segment *before;{ register struct segment *r; if (before == anchor->last) return(NULL); r = before->link; r->last = anchor->last; anchor->last = before; before->link = NULL; return(r);} /*:h3.ReverseSubPaths() - Reverse the Direction of Sub-paths Within a Path This user operator reverses the sub-paths in a path, but leaves the'move' segments unchanged. It builds on top of the subroutinesalready established.*/ struct segment *ReverseSubPaths(p) register struct segment *p; /* input path */{ register struct segment *r; /* reversed path will be created here */ register struct segment *nextp; /* temporary variable used in loop */ int wasclosed; /* flag; subpath was closed */ register struct segment *nomove; /* the part of sub-path without move segment */ struct fractpoint delta; IfTrace1((MustTraceCalls),"ReverseSubPaths(%p)\n", p); if (p == NULL) return(NULL); ARGCHECK(!ISPATHANCHOR(p), "ReverseSubPaths: invalid path", p, NULL, (0), struct segment *); if (p->type == TEXTTYPE) p = CoerceText(p); if (p->type != MOVETYPE) p = JoinSegment(NULL, MOVETYPE, 0, 0, p); p = UniquePath(p); r = NULL; for (; p != NULL;) { nextp = DropSubPath(p); wasclosed = ISCLOSED(p->flag); if (wasclosed) UnClose(p); nomove = SplitPath(p, p); r = Join(r, p); PathDelta(nomove, &delta); nomove = ReverseSubPath(nomove); p->dest.x += delta.x; p->dest.y += delta.y; if (nextp != NULL) { nextp->dest.x += delta.x; nextp->dest.y += delta.y; } if (wasclosed) { nomove = ClosePath(nomove); nextp->dest.x -= delta.x; nextp->dest.y -= delta.y; } r = Join(r, nomove); p = nextp; } return(r);} static int UnClose(p0) register struct segment *p0;{ register struct segment *p; for (p=p0; p->link->link != NULL; p=p->link) { ; } if (!LASTCLOSED(p->link->flag)) abort("UnClose: no LASTCLOSED", 24); Free(SplitPath(p0, p)); p0->flag &= ~ISCLOSED(ON); return(0); } /*:h2.Transforming and Putting Handles on Paths :h3.PathTransform() - Transform a Path Transforming a path involves transforming all the points. In orderthat closed paths do not become "unclosed" when their relativepositions are slightly changed due to loss of arithmetic precision,all point transformations are in absolute coordinates. (It might be better to reset the "absolute" coordinates every time amove segment is encountered. This would mean that we could accumulateerror from subpath to subpath, but we would be less likely to makethe "big error" where our fixed point arithmetic "wraps". However, Ithink I'll keep it this way until something happens to convince meotherwise.) The transform is described as a "space", that way we can use ourold friend the "iconvert" function, which should be very efficient.*/ struct segment *PathTransform(p0, S) register struct segment *p0; /* path to transform */ register struct XYspace *S; /* pseudo space to transform in */{ register struct segment *p; /* to loop through path with */ register fractpel newx,newy; /* current transformed position in path */ register fractpel oldx,oldy; /* current untransformed position in path */ register fractpel savex,savey; /* save path delta x,y */ p0 = UniquePath(p0); newx = newy = oldx = oldy = 0; for (p=p0; p != NULL; p=p->link) { savex = p->dest.x; savey = p->dest.y; (*S->iconvert)(&p->dest, S, p->dest.x + oldx, p->dest.y + oldy); p->dest.x -= newx; p->dest.y -= newy; switch (p->type) { case LINETYPE: case MOVETYPE: break; case CONICTYPE: { register struct conicsegment *cp = (struct conicsegment *) p; (*S->iconvert)(&cp->M, S, cp->M.x + oldx, cp->M.y + oldy); cp->M.x -= newx; cp->M.y -= newy; /* * Note roundness doesn't change... linear transform */ break; } case BEZIERTYPE: { register struct beziersegment *bp = (struct beziersegment *) p; (*S->iconvert)(&bp->B, S, bp->B.x + oldx, bp->B.y + oldy); bp->B.x -= newx; bp->B.y -= newy; (*S->iconvert)(&bp->C, S, bp->C.x + oldx, bp->C.y + oldy); bp->C.x -= newx; bp->C.y -= newy; break; } case HINTTYPE: { register struct hintsegment *hp = (struct hintsegment *) p; (*S->iconvert)(&hp->ref, S, hp->ref.x + oldx, hp->ref.y + oldy); hp->ref.x -= newx; hp->ref.y -= newy; (*S->iconvert)(&hp->width, S, hp->width.x, hp->width.y); /* Note: width is not relative to origin */ break; } case TEXTTYPE: { XformText(p,S); break; } default: IfTrace1(TRUE,"path = %p\n", p); abort("PathTransform: invalid segment", 25); } oldx += savex; oldy += savey; newx += p->dest.x; newy += p->dest.y; } return(p0);} /*:h3.PathDelta() - Return a Path's Ending Point*/ void PathDelta(p, pt) register struct segment *p; /* input path */ register struct fractpoint *pt; /* pointer to x,y to set */{ struct fractpoint mypoint; /* I pass this to TextDelta */ register fractpel x,y; /* working variables for path current point */ for (x=y=0; p != NULL; p=p->link) { x += p->dest.x; y += p->dest.y; if (p->type == TEXTTYPE) { TextDelta(p, &mypoint); x += mypoint.x; y += mypoint.y; } } pt->x = x; pt->y = y;} /*:h3.BoundingBox() - Produce a Bounding Box Path This function is called by image code, when we know the size of theimage in pels, and need to get a bounding box path that surrounds it.The starting/ending handle is in the lower right hand corner.*/struct segment *BoundingBox(h, w) register pel h,w; /* size of box */{ register struct segment *path; path = PathSegment(LINETYPE, -TOFRACTPEL(w), 0); path = JoinSegment(NULL, LINETYPE, 0, -TOFRACTPEL(h), path); path = JoinSegment(NULL, LINETYPE, TOFRACTPEL(w), 0, path); path = ClosePath(path); return(path);} /*:h2.Querying Locations and Paths :h3.QueryLoc() - Return the X,Y of a Locition*/ void QueryLoc(P, S, xP, yP) register struct segment *P; /* location to query, not consumed */ register struct XYspace *S; /* XY space to return coordinates in */ register DOUBLE *xP,*yP; /* coordinates returned here */{ IfTrace4((MustTraceCalls),"QueryLoc(P=%p, S=%p, (%f, %f))\n", P, S, *xP, *yP); if (!ISLOCATION(P)) { ArgErr("QueryLoc: first arg not a location", P, NULL); return; } if (S->type != SPACETYPE) { ArgErr("QueryLoc: second arg not a space", S, NULL); return; } UnConvert(S, &P->dest, xP, yP);}/*:h3.QueryPath() - Find Out the Type of Segment at the Head of a Path This is a very simple routine that looks at the first segment of apath and tells the caller what it is, as well as returning the controlpoint(s) of the path segment. Different path segments have differentnumber of control points. If the caller knows that the segment isa move segment, for example, he only needs to pass pointers to returnone control point.*/ void QueryPath(path, typeP, Bp, Cp, Dp, fP) register struct segment *path; /* path to check */ register int *typeP; /* return the type of path here */ register struct segment **Bp; /* return location of first point */ register struct segment **Cp; /* return location of second point */ register struct segment **Dp; /* return location of third point */ register DOUBLE *fP; /* return Conic sharpness */{ register int coerced = FALSE; /* did I coerce a text path? */ IfTrace3((MustTraceCalls), "QueryPath(%p, %p, %p, ...)\n", path, typeP, Bp); if (path == NULL) { *typeP = -1; return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -