V10/cmd/picasso/xform.c
/* Copyright (c) 1988 AT&T */
/* All Rights Reserved */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
/* The copyright notice above does not evidence any */
/* actual or intended publication of such source code. */
/* @(#)picasso:xform.c 1.0 */
#include "picasso.h"
#include "y.tab.h"
#include <math.h>
/* shorthand for a 3x3 affine matrix applied as follows:
*
* C(x, y) = |x y 1| | C[0] C[1] 0 |
* | C[2] C[3] 0 |
* | C[4] C[5] 1 |
*
* = (C[0]x+C[2]y+C[4], C[1]x+C[3]y+C[5])
*/
matmult (A, B) /* A <- A * B; A is an object transformation */
valtype A[6]; /* or cur_xform updated by a new transform. */
double B[6];
{
register double p;
p = A[0].f * B[0] + A[1].f * B[2];
A[1].f = A[0].f * B[1] + A[1].f * B[3];
A[0].f = p;
p = A[2].f * B[0] + A[3].f * B[2];
A[3].f = A[2].f * B[1] + A[3].f * B[3];
A[2].f = p;
p = A[4].f * B[0] + A[5].f * B[2] + B[4];
A[5].f = A[4].f * B[1] + A[5].f * B[3] + B[5];
A[4].f = p;
}
matmult2 (A, B) /* same, but updates a double array; this is */
double A[6]; /* done only in going up the block hierarchy. */
valtype B[6];
{
register double p;
p = A[0] * B[0].f + A[1] * B[2].f;
A[1] = A[0] * B[1].f + A[1] * B[3].f;
A[0] = p;
p = A[2] * B[0].f + A[3] * B[2].f;
A[3] = A[2] * B[1].f + A[3] * B[3].f;
A[2] = p;
p = A[4] * B[0].f + A[5] * B[2].f + B[4].f;
A[5] = A[4] * B[1].f + A[5] * B[3].f + B[5].f;
A[4] = p;
}
mat_inverse(Ainv, A)
double Ainv[6];
float A[6];
{
double det, det_1;
det = A[0] * A[3] - A[1] * A[2];
if (det == 0.0) {
Ainv[0] = Ainv[3] = 1.0;
Ainv[1] = Ainv[2] = 0.0;
Ainv[4] = Ainv[5] = 0.0;
return;
}
det_1 = 1.0 / det;
Ainv[0] = A[3] * det_1;
Ainv[1] = - A[1] * det_1;
Ainv[2] = - A[2] * det_1;
Ainv[3] = A[0] * det_1;
Ainv[4] = (A[2] * A[5] - A[3] * A[4]) * det_1;
Ainv[5] = (A[1] * A[4] - A[0] * A[5]) * det_1;
}
double T[6];
compose (p) /* accumulate xforms over block hierarchy */
obj *p;
{
if (p == NULL || p->o_type > TEXT) {
T[0] = T[3] = 1;
T[1] = T[2] =
T[4] = T[5] = 0;
if (p == NULL)
return;
}
else {
T[0] = p->o_mxx; T[1] = p->o_myx;
T[2] = p->o_mxy; T[3] = p->o_myy;
T[4] = p->o_mxt; T[5] = p->o_myt;
}
while ((p = p->o_parent) != NULL)
if (p->o_type <= TEXT)
if (p->o_mxx != 1 || p->o_mxy != 0 || p->o_mxt != 0
|| p->o_myx != 0 || p->o_myy != 1 || p->o_myt != 0)
matmult2(T, p->o_xform);
}
get_matrix(M0, M1, M2, M3)
double *M0, *M1, *M2, *M3;
{
*M0 = T[0]; *M1 = T[1]; *M2 = T[2]; *M3 = T[3];
}
double Xformx (p, flag, x, y)
obj *p;
int flag;
double x, y;
{
if (flag)
compose(p);
return x*T[0] + y*T[2] + T[4];
}
double Xformy (p, flag, x, y)
obj *p;
int flag;
double x, y;
{
if (flag)
compose(p);
return x*T[1] + y*T[3] + T[5];
}
double Linx (p, flag, x, y) /* linear component, only */
obj *p;
int flag;
double x, y;
{
if (flag)
compose(p);
return T[0]*x + T[2]*y;
}
double Liny (p, flag, x, y)
obj *p;
int flag;
double x, y;
{
if (flag)
compose(p);
return T[1]*x + T[3]*y;
}
apply (p, M, d) /* apply matrix M (determinant d) to object p */
obj *p;
double *M, d;
{
float bnd[4];
if (p->o_type == PLACE) {
matmult (cur_xform, M);
if (d != 1)
checkscale(sqrt(d));
}
else if (p->o_type <= TEXT) {
matmult (p->o_xform, M);
get_bounds(p, bnd, 0);
track_bounds(bnd[0], bnd[1], bnd[2], bnd[3]);
redo_gbox = 1;
}
}
translate (p, x, y) /* the easy case of applying a transformation */
obj *p;
double x, y;
{
float bnd[4];
int i;
if (p->o_type == PLACE) {
cur_xform[4].f += x;
cur_xform[5].f += y;
}
else if (p->o_type <= TEXT) {
if (p->o_type == BLOCK || p->o_mxx != 1 || p->o_myy != 1
|| p->o_mxy != 0 || p->o_myx != 0
|| p->o_mxt != 0 || p->o_myt != 0) {
p->o_mxt += x;
p->o_myt += y;
}
else { /* no existing transformation, move center */
/* DBK: probably should also test to make sure
there is no higher level transformation?? */
p->o_x += x;
p->o_y += y;
switch (p->o_type) {
case LINE:
case ARROW:
case SPLINE:
for (i = 0; i <= p->o_val[N_VAL+3].f; i++) {
p->o_val[N_VAL+4+i+i].f += x;
p->o_val[N_VAL+5+i+i].f += y;
}
break;
case ARC:
case SECTOR:
p->o_val[N_VAL+2].f += x;
p->o_val[N_VAL+3].f += y;
p->o_val[N_VAL+4].f += x;
p->o_val[N_VAL+5].f += y;
break;
}
}
get_bounds(p, bnd, 0);
track_bounds(bnd[0], bnd[1], bnd[2], bnd[3]);
redo_gbox = 1;
}
}
xlate (p, q)
obj *p, *q;
{
translate (p, q->o_x, q->o_y);
}
xlate_to (p, q) /* destination given in absolute coordinates */
obj *p, *q;
{
translate (p, q->o_x - p->o_x, q->o_y - p->o_y);
}
static double picscale = 1.0;
rescale (v) /* implicit scaling from user's "scale = v" statement */
double v; /* rather unintuitively, this is like "scale O 1/v". */
{
picscale = v;
}
scale_pic() /* for PIC compatibility--called at end of parse */
{
double sc;
obj *o;
int i;
float bnd[4];
if (picscale == 0.0)
picscale = 1.0;
if (picscale == 1.0)
return;
sc = 1.0 / picscale;
for (o = objhead; o != objtail; o = o->o_next) {
if (o->o_type == PLACE || o->o_type == TEXT ||
o->o_type == MOVE) {
o->o_x *= sc;
o->o_y *= sc;
/* NOTE!! may need to adjust center offset of text */
}
else if (o->o_type < TEXT) { /* PIC couldn't scale text */
for (i = 0; i < 6; i++)
o->o_xform[i].f *= sc;
}
if (o->o_type == BLOCK) /* skip the contents */
o = o->o_val[N_VAL].o;
}
/* make arrowheads large to compensate for later shrinkage */
for (o = objhead; o != objtail; o = o->o_next) {
if ((o->o_type == LINE || o->o_type == SPLINE ||
o->o_type == ARROW) && (o->o_attr & HEAD12) != 0) {
o->o_val[N_VAL+1].f *= picscale;
o->o_val[N_VAL+2].f *= picscale;
}
if (o->o_type == ARC && (o->o_attr & HEAD12) != 0) {
o->o_val[N_VAL+8].f *= picscale;
o->o_val[N_VAL+9].f *= picscale;
}
}
picscale = 1.0;
Gbox[2] = Gbox[3] = -(Gbox[0] = Gbox[1] = 32767);
for (o = objhead->o_next; o != objtail; o = o->o_next) {
get_bounds(o, bnd, 1);
track_bounds (bnd[0], bnd[1], bnd[2], bnd[3]);
if (o->o_type == BLOCK)
o = o->o_val[N_VAL].o;
}
#if 0
cur_xform[0].f /= v;
cur_xform[1].f /= v;
cur_xform[2].f /= v;
cur_xform[3].f /= v;
checkscale(v);
#endif
}
scale (p, n, q)
obj *p, *q;
int n;
{
register double det;
double M[6];
M[0] = exprlist[nexpr-n];
M[3] = (n == 1 ? M[0] : exprlist[nexpr-n+1]);
nexpr = 0;
if ((det = M[0] * M[3]) == 0.0) {
yyerror("can't scale by 0 factor");
return;
}
M[1] = M[2] = M[4] = M[5] = 0.;
if (q != NULL) {
M[4] = (1 - M[0]) * Xformx(q,1,q->o_x,q->o_y);
M[5] = (1 - M[3]) * Xformy(q,0,q->o_x,q->o_y);
}
apply(p, M, det);
}
olpscaleobj (p, sx, sy, cx, cy)
obj *p;
double sx, sy; /* scale factor in x and y directions */
double cx, cy; /* center for scaling in real (inches) units */
{
register double det;
double M[6];
M[0] = sx;
M[3] = sy;
if ((det = M[0] * M[3]) == 0.0) {
yyerror("can't scale by 0 factor");
return;
}
M[1] = M[2] = 0.0;
M[4] = cx * (1. - sx);
M[5] = cy * (1. - sy);
apply(p, M, det);
}
rotate (p, phi, q)
obj *p, *q;
double phi; /* in radians */
{
register double x, y;
double M[6];
M[3] = M[0] = Cos(phi);
M[2] = -(M[1] = Sin(phi));
if (q == NULL)
M[4] = M[5] = 0;
else {
x = Xformx(q, 1, q->o_x, q->o_y);
y = Xformy(q, 0, q->o_x, q->o_y);
M[4] = (1 - M[0]) * x + M[1] * y;
M[5] = (1 - M[0]) * y - M[1] * x;
}
apply(p, M, 1);
}
void
rotate_point(x, y, angle, cx, cy, pointx, pointy)
double x, y;
double angle; /* in radians */
double cx, cy; /* center for rotation in screen units. */
double *pointx, *pointy; /* rotated point to be passed back */
{
double tempx, tempy;
tempx = x - cx;
tempy = y - cy;
*pointx = (tempx * cos(angle)) - (tempy* sin(angle)) + cx;
*pointy = (tempx * sin(angle)) + (tempy* cos(angle)) + cy;
}
void
olprotateobj (p, angle, cx, cy)
obj *p;
double angle; /* in radians */
double cx, cy; /* center for rotation in real (inches) units. */
{
double M[6];
M[3] = M[0] = cos(angle);
M[2] = -(M[1] = sin(angle));
M[4] = (1 - M[0]) * cx + M[1] * cy;
M[5] = (1 - M[0]) * cy - M[1] * cx;
apply(p, M, 1);
}
xform (p, n)
obj *p;
int n;
{
register double det;
double M[6];
int i;
for (i = 0; i < n; ++i)
M[i] = exprlist[i];
while (i < 6)
M[i++] = 0;
nexpr = 0;
if ((det = M[0]*M[3] - M[1]*M[2]) == 0)
yyerror ("singular transformation matrix");
else
apply(p, M, det);
}
reflect (p, q)
obj *p, *q;
{
float bnd[4];
double phi, c, s, x0, y0, x1, y1, M[6];
int axial;
if (q == NULL)
axial = x0 = x0 = x1 = y1 = 0;
else
switch (q->o_type) {
case ARC:
case ARROW:
case LINE:
case SPLINE: whatpos(q, START, bnd, bnd+1);
whatpos(q, END, bnd+2, bnd+3);
x0 = Xformx(q, 1, bnd[0], bnd[1]);
y0 = Xformy(q, 0, bnd[0], bnd[1]);
x1 = Xformx(q, 0, bnd[2], bnd[3]);
y1 = Xformy(q, 0, bnd[2], bnd[3]);
if (axial = (x0 != x1 || y0 != y1))
break;
/* fall through to default case; i.e., use */
/* center, for closed lines. otherwise, use */
/* closest point to p along q as start of q */
#if 0 /*MS: The next few lines never get used */
S = (y1-y0)/(x1-x0); /* slope of the line */
B = y0 - S*x0; /* intercept term. */
s = -1/S; /* perpendicular slope*/
x = Xformx(p, 1, p->o_x, p->o_y);
y = Xformy(p, 0, p->o_x, p->o_y);
b = y - s*x;
x0 = (b - B)/(S - s); y0 = S*x0 + B;
#endif
default:
x0 = Xformx(q, 1, q->o_x, q->o_y);
y0 = Xformy(q, 0, q->o_x, q->o_y);
axial = 0;
}
if (!axial) {
M[0] = M[3] = -1;
M[1] = M[2] = 0;
M[4] = 2 * x0;
M[5] = 2 * y0;
}
else {
if (x1 == x0 || y1 == y0) { /* note: not both */
s = 0;
c = (x1 == x0 ? -1 : 1);
}
else if (fabs(x1-x0) == fabs(y1-y0)) {
c = 0;
s = (x1-x0 == y1-y0 ? 1 : -1);
}
else {
c = cos(phi = 2 * atan2(y1-y0, x1-x0));
s = sin(phi);
}
M[1] = M[2] = s;
M[3] = -(M[0] = c);
M[4] = x0*(1-c) - y0*s;
M[5] = y0*(1+c) - x0*s;
}
apply(p, M, 1);
}
olpreflectobj (p, x0, y0, x1, y1)
obj *p;
double x0, y0, x1, y1;
{
double phi, c, s, M[6];
int axial;
if (x0 != x1 || y0 != y1)
axial = 1;
else axial = 0;
if (!axial) {
M[0] = M[3] = -1;
M[1] = M[2] = 0;
M[4] = 2 * x0;
M[5] = 2 * y0;
}
else {
if (x1 == x0 || y1 == y0) { /* note: not both */
s = 0;
c = (x1 == x0 ? -1 : 1);
}
else if (fabs(x1-x0) == fabs(y1-y0)) {
c = 0;
s = (x1-x0 == y1-y0 ? 1 : -1);
}
else {
c = cos(phi = 2 * atan2(y1-y0, x1-x0));
s = sin(phi);
}
M[1] = M[2] = s;
M[3] = -(M[0] = c);
M[4] = x0*(1-c) - y0*s;
M[5] = y0*(1+c) - x0*s;
}
apply(p, M, 1);
}