struct xobject *t1_Xform( register struct xobject *obj, /* object to transform */ register DOUBLE M[2][2]) /* transformation matrix */ { if (obj == NULL) return(NULL); if (obj->type == FONTTYPE) { register struct font *F = (struct font *) obj; F = UniqueFont(F); return((struct xobject*)F); } if (obj->type == PICTURETYPE) { /* In the case of a picture, we choose both to update the picture's transformation matrix and keep the handles up to date. */ register struct picture *P = (struct picture *) obj; register struct segment *handles; /* temporary path to transform handles */ P = UniquePicture(P); handles = PathSegment(LINETYPE, P->origin.x, P->origin.y); handles = Join(handles, PathSegment(LINETYPE, P->ending.x, P->ending.y) ); handles = (struct segment *)Xform((struct xobject *) handles, M); P->origin = handles->dest; P->ending = handles->link->dest; KillPath(handles); return((struct xobject *)P); } if (ISPATHTYPE(obj->type)) { struct XYspace pseudo; /* local temporary space */ PseudoSpace(&pseudo, M); return((struct xobject *) PathTransform((struct segment *)obj, &pseudo)); } if (obj->type == SPACETYPE) { register struct XYspace *S = (struct XYspace *) obj; /* replaced ISPERMANENT(S->flag) with S->references > 1 3-26-91 PNM */ if (S->references > 1) S = CopySpace(S); else S->ID = NEXTID; MatrixMultiply(S->tofract.normal, M, S->tofract.normal); /* * mark inverted matrix invalid: */ S->flag &= ~HASINVERSE(ON); FillOutFcns(S); return((struct xobject *) S); } return(ArgErr("Untransformable object", obj, obj)); }
void QuerySpace(struct XYspace *S, /* space asked about */ double *cxxP, double *cyxP, /* where to put answer */ double *cxyP, double *cyyP) { double M[2][2]; /* temp matrix to build user's answer */ if (S->type != SPACETYPE) { ArgErr("QuerySpace: not a space", S, NULL); return; } MatrixMultiply(S->tofract.normal, IDENTITY->tofract.inverse, M); *cxxP = M[0][0]; *cxyP = M[1][0]; *cyxP = M[0][1]; *cyyP = M[1][1]; }
/* :h3.KillPath() - Destroying a Path Destroying a path is simply a matter of freeing each segment in the linked list. Again, we let the experts handle text. */ void KillPath(struct segment *p) /* path to destroy */ { register struct segment *linkp; /* temp register holding next segment*/ /* return conditional based on reference count 3-26-91 PNM */ if ( (--(p->references) > 1) || ( (p->references == 1) && !ISPERMANENT(p->flag) ) ) return; while (p != NULL) { if (!ISPATHTYPE(p->type)) { ArgErr("KillPath: bad segment", p, NULL); return; } linkp = p->link; if (p->type == TEXTTYPE) KillText(p); else Free(p); p = linkp; } }