/* XX != AB */ static int lattXXtoAB(double *dstParm, int srcLatt, const double *srcParm) { double AA[2], BB[2], area, theta, radi, scl; int ret = 0; switch(srcLatt) { case rvaLattPRA: /* PRA -> AB */ area = AIR_ABS(srcParm[2]); theta = AIR_AFFINE(0, srcParm[0], 1, AIR_PI/2, AIR_PI/3); radi = srcParm[1]; ELL_2V_SET(AA, 1.0, 0.0); ELL_2V_SET(BB, radi*cos(theta), radi*sin(theta)); /* area from AA and BB is BB[1], but need to scale these to get to requested area */ scl = sqrt(area/BB[1]); ELL_4V_SET(dstParm, scl*AA[0], scl*AA[1], scl*BB[0], scl*BB[1]); break; case rvaLattAB: /* UVW -> AB */ ELL_4V_SET(dstParm, srcParm[2], 0.0, srcParm[0], srcParm[1]); break; case rvaLattXY: /* XY -> AB */ ELL_4V_SET(dstParm, 1.0, 0.0, srcParm[0], srcParm[1]); break; default: ret = 1; break; /* unimplemented */ } return ret; }
void wheelArrow(wheelPS *wps, double x0, double y0, double x1, double y1, double alen, double awidth) { double len, dir[2], perp[2]; dir[0] = x0 - x1; dir[1] = y0 - y1; ELL_2V_NORM(dir, dir, len); ELL_2V_SET(perp, -dir[1], dir[0]); fprintf(wps->file, "%g %g M\n", WPS_X(x0), WPS_Y(y0)); fprintf(wps->file, "%g %g L S\n", WPS_X(x1 + alen*dir[0]/2), WPS_Y(y1 + alen*dir[1]/2)); if (alen && awidth) { if (len < alen) { awidth *= len/alen; alen = len; } fprintf(wps->file, "%g %g M\n", WPS_X(x1 + alen*dir[0] + awidth*perp[0]), WPS_Y(y1 + alen*dir[1] + awidth*perp[1])); fprintf(wps->file, "%g %g L\n", WPS_X(x1), WPS_Y(y1)); fprintf(wps->file, "%g %g L CP F\n", WPS_X(x1 + alen*dir[0] - awidth*perp[0]), WPS_Y(y1 + alen*dir[1] - awidth*perp[1])); } return; }
/* XX != AB */ static int lattABtoXX(int dstLatt, double *dstParm, const double *srcParm) { double AA[2], BB[2], theta, phase, radi, area, len; int ret = 0; /* we have to reduce the DOF, which always starts with the same loss of orientation information */ ELL_2V_COPY(AA, srcParm + 0); ELL_2V_COPY(BB, srcParm + 2); getToPosY(AA, BB); switch(dstLatt) { case rvaLattPRA: /* AB -> PRA (loss off orientation) */ theta = atan2(BB[1], BB[0]); phase = AIR_AFFINE(AIR_PI/2, theta, AIR_PI/3, 0.0, 1.0); radi = _rvaLen2(BB)/_rvaLen2(AA); area = _rvaLen2(AA)*BB[1]; ELL_3V_SET(dstParm, phase, radi, area); break; case rvaLattUVW: /* AB -> UVW (loss of orientation) */ ELL_3V_SET(dstParm, BB[0], BB[1], AA[0]); break; case rvaLattXY: /* AB -> XY (loss of orientation and scale) */ len = _rvaLen2(AA); ELL_2V_SET(dstParm, BB[0]/len, BB[1]/len); break; default: ret = 1; break; /* unimplemented */ } return ret; }
/* ******** limnCameraPathMake ** ** uses limnSplines to do camera paths based on key-frames ** ** output: cameras at all "numFrames" frames are set in the ** PRE-ALLOCATED array of output cameras, "cam". ** ** input: ** keycam: array of keyframe cameras ** time: times associated with the key frames ** ---> both of these arrays are length "numKeys" <--- ** trackWhat: takes values from the limnCameraPathTrack* enum ** quatType: spline to control camera orientations. This is needed for ** tracking at or from, but not needed for limnCameraPathTrackBoth. ** This is the only limnSplineTypeSpec* argument that can be NULL. ** posType: spline to control whichever of from, at, and up are needed for ** the given style of tracking. ** distType: spline to control neer, faar, dist: positions of near clipping, ** far clipping, and image plane, as well as the ** distance between from and at (which is used if not doing ** limnCameraPathTrackBoth) ** viewType: spline to control fov (and aspect, if you're crazy) ** ** NOTE: The "atRelative", "orthographic", and "rightHanded" fields ** are copied from keycam[0] into all output cam[i], but you still need ** to correctly set them for all keycam[i] for limnCameraUpdate to work ** as expected. Also, for the sake of simplicity, this function only works ** with fov and aspect, instead of {u,v}Range, and hence both "fov" and ** "aspect" need to set in *all* the keycams, even if neither of them ** ever changes! */ int limnCameraPathMake(limnCamera *cam, int numFrames, limnCamera *keycam, double *time, int numKeys, int trackWhat, limnSplineTypeSpec *quatType, limnSplineTypeSpec *posType, limnSplineTypeSpec *distType, limnSplineTypeSpec *viewType) { static const char me[]="limnCameraPathMake"; char which[AIR_STRLEN_MED]; airArray *mop; Nrrd *nquat, *nfrom, *natpt, *nupvc, *ndist, *nfova, *ntime, *nsample; double fratVec[3], *quat, *from, *atpt, *upvc, *dist, *fova, W2V[9], N[3], fratDist; limnSpline *timeSpline, *quatSpline, *fromSpline, *atptSpline, *upvcSpline, *distSpline, *fovaSpline; limnSplineTypeSpec *timeType; int ii, E; if (!( cam && keycam && time && posType && distType && viewType )) { biffAddf(LIMN, "%s: got NULL pointer", me); return 1; } if (!( AIR_IN_OP(limnCameraPathTrackUnknown, trackWhat, limnCameraPathTrackLast) )) { biffAddf(LIMN, "%s: trackWhat %d not in valid range [%d,%d]", me, trackWhat, limnCameraPathTrackUnknown+1, limnCameraPathTrackLast-1); return 1; } if (limnCameraPathTrackBoth != trackWhat && !quatType) { biffAddf(LIMN, "%s: need the quaternion limnSplineTypeSpec if not " "doing trackBoth", me); return 1; } /* create and allocate nrrds. For the time being, we're allocating more different nrrds, and filling their contents, than we need to-- nquat is not needed if we're doing limnCameraPathTrackBoth, for example. However, we do make an effort to only do the spline evaluation on the things we actually need to know. */ mop = airMopNew(); airMopAdd(mop, nquat = nrrdNew(), (airMopper)nrrdNuke, airMopAlways); airMopAdd(mop, nfrom = nrrdNew(), (airMopper)nrrdNuke, airMopAlways); airMopAdd(mop, natpt = nrrdNew(), (airMopper)nrrdNuke, airMopAlways); airMopAdd(mop, nupvc = nrrdNew(), (airMopper)nrrdNuke, airMopAlways); airMopAdd(mop, ndist = nrrdNew(), (airMopper)nrrdNuke, airMopAlways); airMopAdd(mop, nfova = nrrdNew(), (airMopper)nrrdNuke, airMopAlways); airMopAdd(mop, ntime = nrrdNew(), (airMopper)nrrdNix, airMopAlways); if (nrrdWrap_va(ntime, time, nrrdTypeDouble, 1, AIR_CAST(size_t, numKeys))) { biffMovef(LIMN, NRRD, "%s: trouble wrapping time values", me); airMopError(mop); return 1; } airMopAdd(mop, nsample = nrrdNew(), (airMopper)nrrdNuke, airMopAlways); timeType = limnSplineTypeSpecNew(limnSplineTypeTimeWarp); airMopAdd(mop, timeType, (airMopper)limnSplineTypeSpecNix, airMopAlways); if (nrrdMaybeAlloc_va(nquat, nrrdTypeDouble, 2, AIR_CAST(size_t, 4), AIR_CAST(size_t, numKeys)) || nrrdMaybeAlloc_va(nfrom, nrrdTypeDouble, 2, AIR_CAST(size_t, 3), AIR_CAST(size_t, numKeys)) || nrrdMaybeAlloc_va(natpt, nrrdTypeDouble, 2, AIR_CAST(size_t, 3), AIR_CAST(size_t, numKeys)) || nrrdMaybeAlloc_va(nupvc, nrrdTypeDouble, 2, AIR_CAST(size_t, 3), AIR_CAST(size_t, numKeys)) || nrrdMaybeAlloc_va(ndist, nrrdTypeDouble, 2, AIR_CAST(size_t, 4), AIR_CAST(size_t, numKeys)) || nrrdMaybeAlloc_va(nfova, nrrdTypeDouble, 2, AIR_CAST(size_t, 2), AIR_CAST(size_t, numKeys))) { biffMovef(LIMN, NRRD, "%s: couldn't allocate buffer nrrds", me); airMopError(mop); return 1; } quat = (double*)(nquat->data); from = (double*)(nfrom->data); atpt = (double*)(natpt->data); upvc = (double*)(nupvc->data); dist = (double*)(ndist->data); fova = (double*)(nfova->data); /* check cameras, and put camera information into nrrds */ for (ii=0; ii<numKeys; ii++) { if (limnCameraUpdate(keycam + ii)) { biffAddf(LIMN, "%s: trouble with camera at keyframe %d\n", me, ii); airMopError(mop); return 1; } if (!( AIR_EXISTS(keycam[ii].fov) && AIR_EXISTS(keycam[ii].aspect) )) { biffAddf(LIMN, "%s: fov, aspect not both defined on keyframe %d", me, ii); airMopError(mop); return 1; } ell_4m_to_q_d(quat + 4*ii, keycam[ii].W2V); if (ii) { if (0 > ELL_4V_DOT(quat + 4*ii, quat + 4*(ii-1))) { ELL_4V_SCALE(quat + 4*ii, -1, quat + 4*ii); } } ELL_3V_COPY(from + 3*ii, keycam[ii].from); ELL_3V_COPY(atpt + 3*ii, keycam[ii].at); ELL_3V_COPY(upvc + 3*ii, keycam[ii].up); ELL_3V_SUB(fratVec, keycam[ii].from, keycam[ii].at); fratDist = ELL_3V_LEN(fratVec); ELL_4V_SET(dist + 4*ii, fratDist, keycam[ii].neer, keycam[ii].dist, keycam[ii].faar); ELL_2V_SET(fova + 2*ii, keycam[ii].fov, keycam[ii].aspect); } /* create splines from nrrds */ if (!( (strcpy(which, "quaternion"), quatSpline = limnSplineCleverNew(nquat, limnSplineInfoQuaternion, quatType)) && (strcpy(which, "from point"), fromSpline = limnSplineCleverNew(nfrom, limnSplineInfo3Vector, posType)) && (strcpy(which, "at point"), atptSpline = limnSplineCleverNew(natpt, limnSplineInfo3Vector, posType)) && (strcpy(which, "up vector"), upvcSpline = limnSplineCleverNew(nupvc, limnSplineInfo3Vector, posType)) && (strcpy(which, "plane distances"), distSpline = limnSplineCleverNew(ndist, limnSplineInfo4Vector, distType)) && (strcpy(which, "field-of-view"), fovaSpline = limnSplineCleverNew(nfova, limnSplineInfo2Vector, viewType)) && (strcpy(which, "time warp"), timeSpline = limnSplineCleverNew(ntime, limnSplineInfoScalar, timeType)) )) { biffAddf(LIMN, "%s: trouble creating %s spline", me, which); airMopError(mop); return 1; } airMopAdd(mop, quatSpline, (airMopper)limnSplineNix, airMopAlways); airMopAdd(mop, fromSpline, (airMopper)limnSplineNix, airMopAlways); airMopAdd(mop, atptSpline, (airMopper)limnSplineNix, airMopAlways); airMopAdd(mop, upvcSpline, (airMopper)limnSplineNix, airMopAlways); airMopAdd(mop, distSpline, (airMopper)limnSplineNix, airMopAlways); airMopAdd(mop, fovaSpline, (airMopper)limnSplineNix, airMopAlways); airMopAdd(mop, timeSpline, (airMopper)limnSplineNix, airMopAlways); /* evaluate splines */ E = AIR_FALSE; if (!E) E |= limnSplineSample(nsample, timeSpline, limnSplineMinT(timeSpline), numFrames, limnSplineMaxT(timeSpline)); quat = NULL; from = NULL; atpt = NULL; upvc = NULL; switch(trackWhat) { case limnCameraPathTrackAt: if (!E) E |= limnSplineNrrdEvaluate(natpt, atptSpline, nsample); if (!E) atpt = (double*)(natpt->data); if (!E) E |= limnSplineNrrdEvaluate(nquat, quatSpline, nsample); if (!E) quat = (double*)(nquat->data); break; case limnCameraPathTrackFrom: if (!E) E |= limnSplineNrrdEvaluate(nfrom, fromSpline, nsample); if (!E) from = (double*)(nfrom->data); if (!E) E |= limnSplineNrrdEvaluate(nquat, quatSpline, nsample); if (!E) quat = (double*)(nquat->data); break; case limnCameraPathTrackBoth: if (!E) E |= limnSplineNrrdEvaluate(nfrom, fromSpline, nsample); if (!E) from = (double*)(nfrom->data); if (!E) E |= limnSplineNrrdEvaluate(natpt, atptSpline, nsample); if (!E) atpt = (double*)(natpt->data); if (!E) E |= limnSplineNrrdEvaluate(nupvc, upvcSpline, nsample); if (!E) upvc = (double*)(nupvc->data); break; } dist = NULL; if (!E) E |= limnSplineNrrdEvaluate(ndist, distSpline, nsample); if (!E) dist = (double*)(ndist->data); fova = NULL; if (!E) E |= limnSplineNrrdEvaluate(nfova, fovaSpline, nsample); if (!E) fova = (double*)(nfova->data); if (E) { biffAddf(LIMN, "%s: trouble evaluating splines", me); airMopError(mop); return 1; } /* copy information from nrrds back into cameras */ for (ii=0; ii<numFrames; ii++) { cam[ii].atRelative = keycam[0].atRelative; cam[ii].orthographic = keycam[0].orthographic; cam[ii].rightHanded = keycam[0].rightHanded; if (limnCameraPathTrackBoth == trackWhat) { ELL_3V_COPY(cam[ii].from, from + 3*ii); ELL_3V_COPY(cam[ii].at, atpt + 3*ii); ELL_3V_COPY(cam[ii].up, upvc + 3*ii); } else { fratDist = (dist + 4*ii)[0]; ell_q_to_3m_d(W2V, quat + 4*ii); ELL_3MV_ROW1_GET(cam[ii].up, W2V); if (cam[ii].rightHanded) { ELL_3V_SCALE(cam[ii].up, -1, cam[ii].up); } ELL_3MV_ROW2_GET(N, W2V); if (limnCameraPathTrackFrom == trackWhat) { ELL_3V_COPY(cam[ii].from, from + 3*ii); ELL_3V_SCALE_ADD2(cam[ii].at, 1.0, cam[ii].from, fratDist, N); } else { ELL_3V_COPY(cam[ii].at, atpt + 3*ii); ELL_3V_SCALE_ADD2(cam[ii].from, 1.0, cam[ii].at, -fratDist, N); } } cam[ii].neer = (dist + 4*ii)[1]; cam[ii].dist = (dist + 4*ii)[2]; cam[ii].faar = (dist + 4*ii)[3]; cam[ii].fov = (fova + 2*ii)[0]; cam[ii].aspect = (fova + 2*ii)[1]; if (limnCameraUpdate(cam + ii)) { biffAddf(LIMN, "%s: trouble with output camera %d\n", me, ii); airMopError(mop); return 1; } } airMopOkay(mop); return 0; }