home *** CD-ROM | disk | FTP | other *** search
- // C++ file for base display classes
- // copyright 1992 Pittsburgh Supercomputing Center
- // these will only be called if the actual display used doesn't have its own
- #include <math.h>
- #include "cgm.h"
- #ifdef __MSDOS__
- #include "cgmdisp.h"
- #else
- #include "cgmdisplay.h"
- #endif
- #include "hload1.h"
- // error call
- extern void myError(const char *inMsg, const char *inMsg2=NULL,
- int severity=1);
- ////
- // angle
- ////
- const double angle::tanMax = 1e10; // maximum tangent value
- #ifdef macintosh
- #pragma segment DIS1
- #endif
- ////
- // hershey font stuff
- ////
- // hershey character
- ////
- const int hersheyChar::maxOffset = sizeof(hf_array);
- hersheyChar::hersheyChar(const genText *inText, int charNo, int fontNo)
- {
- static const vdcPts *usePos = NULL;
- int offset, i;
- next = NULL;
- contents = NULL;
- if (!inText || (charNo > inText->size())) return; // safety check
- ////
- if (fontNo >= NO_HF) fontNo = 0; // existing font
- int wantChar = inText->contents()[charNo]; // character we want
- if ((wantChar < 0) || (wantChar >= MAX_HCHARS) ||
- ((offset = h_array[fontNo][wantChar]) < 0) ||
- (offset > maxOffset)) return; // no legal character
- // if (hf_array[offset] < 0) return; // no such character in this font
- float charSize = inText->info()->height() / 24; // 24 pixel square
- // do we have any rotation ?
- angle upVec(1, 0), baseVec(0, 1);
- if (inText->info()->orientation()) {
- upVec = angle(inText->info()->orientation()->y(0),
- inText->info()->orientation()->x(0));
- baseVec = angle(inText->info()->orientation()->y(1),
- inText->info()->orientation()->x(1));
- }
- ////
- // now we know we have some points
- if (inText->pos()) usePos = inText->pos(); // may be appended
- if (!usePos) return; // no where to put it
- // figure out the shifts
- unsigned char *hPtr = hf_array + offset;
- float temp1 = charSize * (128 - (int) hPtr[0]);
- float temp2 = charSize * ((int) hPtr[1] - 128);
- myShift1 = temp1 * baseVec.cos();
- myShift2 = temp2 * baseVec.cos();
- myShiftY1 = temp1 * baseVec.sin();
- myShiftY2 = temp2 * baseVec.sin();
- myHeight = myDepth = 0;
- // step over widths
- hPtr +=2;
- // prepare for loop
- int noPts = 0;
- float fx, fy;
- do {
- if (!hPtr[2*noPts] && (!hPtr[2*noPts+1] || (hPtr[2*noPts+1] == 128))) {
- // pen coming up or end of character description
- if (noPts) { // some to do
- if (usePos->type()) { // real vdc's
- float *newFloat = new float[noPts * 2];
- for (i=0; i<noPts; ++i) {
- fx = hPtr[2*i];
- fx -= 128;
- fx *= charSize;
- fy = - (int) hPtr[2*i+1];
- fy += 140; // + 12 for bottom of box
- fy *= charSize;
- if (fy > myHeight) myHeight = fy;
- if (-fy > myDepth) myDepth = -fy;
- newFloat[2*i] = fx * baseVec.cos() + fy * upVec.cos();
- newFloat[2*i+1] = fy * upVec.sin() + fx * baseVec.sin();
- }
- addPts(new vdcPts(newFloat, noPts));
- } else { // integer vdc's
- int *newInt = new int[noPts * 2];
- for (i=0; i<noPts; ++i) {
- fx = hPtr[2*i];
- fx -= 128;
- fx *= charSize;
- fy = - (int) hPtr[2*i+1];
- fy += 140; // + 12 for bottom of box
- fy *= charSize;
- if (fy > myHeight) myHeight = fy;
- if (-fy > myDepth) myDepth = -fy;
- newInt[2*i] = (int) (fx * baseVec.cos() + fy * upVec.cos());
- newInt[2*i+1] = (int) (fy * upVec.sin() + fx * baseVec.sin());
- }
- addPts(new vdcPts(newInt, noPts));
- }
- }
- if (hPtr[2*noPts+1]) { // more to come
- hPtr += noPts * 2 + 2; // step over description
- noPts = 0; // start fresh
- } else break; // last polyline
- } else ++noPts; // normal point
- } while ((hPtr + noPts * 2) <= (hf_array + maxOffset)); // in legal position
- }
- ////
- // destructor
- ////
- hersheyChar::~hersheyChar()
- {
- vdcPts *myPtr, *nextPtr;
- for (myPtr = contents; myPtr; myPtr = nextPtr) {
- nextPtr = myPtr->next;
- delete myPtr;
- }
- }
- ////
- // scale the character
- ////
- void hersheyChar::scale(float factor)
- {
- myShift1 *= factor;
- myShift2 *= factor;
- myShiftY1 *= factor;
- myShiftY2 *= factor;
- myHeight *= factor;
- myDepth *= factor;
- for (vdcPts *myPtr = contents; myPtr; myPtr = myPtr->next)
- myPtr->scale(factor);
- }
- ////
- // add some pts to a single character
- ////
- void hersheyChar::addPts(vdcPts *inPts)
- {
- if (!contents) contents = inPts;
- else {
- for (vdcPts *myPtr=contents; myPtr->next; myPtr = myPtr->next);
- myPtr->next = inPts;
- }
- }
- ////
- // display the character
- ////
- int hersheyChar::display(baseDisplay *inDisplay)
- {
- int ret = 1;
- for (vdcPts *myPtr=contents; myPtr; myPtr=myPtr->next) {
- ret = ret && inDisplay->polyline(myPtr);
- }
- return ret;
- }
- ////
- // shift the character
- ////
- void hersheyChar::shift(float &xShift, float &yShift)
- {
- for (vdcPts *myPtr=contents; myPtr; myPtr=myPtr->next) {
- myPtr->shift(xShift, yShift);
- }
- }
- ////
- // hershey string
- ////
- hersheyString::hersheyString(const genText *inText) // constructor
- {
- static float xStart, yStart;
- contents = NULL;
- myHeight = myDepth = 0;
- ////
- // create all of the characters
- for (int i=0; i<inText->size(); ++i)
- addChar(new hersheyChar(inText, i));
- ////
- if (inText->pos()) { // may be appended text
- xStart = inText->pos()->x(0);
- yStart = inText->pos()->y(0);
- }
- // is this restricted text ?
- const vdc *inW, *inH;
- if ((inW = inText->width()) && (inH = inText->height())) {
- float inWidth = inW->f();
- float inHeight = inH->f();
- float h = height();
- float d = depth();
- float w = width();
- if (inText->info()) w *= inText->info()->expan();
- if (d > 0) h += d;
- if (h && w) {
- float xHScale = inWidth / w;
- float yHScale = inHeight / h;
- float useHScale = (xHScale < yHScale) ? xHScale : yHScale;
- scale(useHScale); // scale the string
- if (d > 0) yStart += d * useHScale;
- }
- }
- // float yStart1 = yStart;
- // now take care of positioning
- float trueWidth = width(); // figure out true width of string
- if (inText->info()) trueWidth *= inText->info()->expan();
- ////
- if (inText->info()->align()) {
- switch(inText->info()->align()->h()) {
- case 0:
- case 1: break; // ok
- case 2: xStart -= 0.5 * trueWidth; break;
- case 3: xStart -= trueWidth; break;
- case 4: break; // fix later
- }
- switch(inText->info()->align()->v()) {
- case 0: break; // ok
- case 1: yStart -= height(); break;
- case 2: yStart -= 0.9 * height(); break;
- case 3: yStart -= 0.5 * height(); break;
- case 4: yStart -= 0.1 * height(); break;
- case 5: break;
- case 6 : break; // fix later
- }
- }
- switch(inText->info()->path()) {
- case 0:
- right(inText, xStart, yStart); break;
- case 1:
- left(inText, xStart, yStart); break;
- case 2:
- up(inText, xStart, yStart); break;
- case 3:
- down(inText, xStart, yStart); break;
- }
- }
- ////
- // string width
- ////
- float hersheyString::width()
- {
- float w=0;
- for (hersheyChar *p=contents; p; p=p->next) w += p->width();
- return w;
- }
- ////
- // scale the string
- ////
- void hersheyString::scale(float factor)
- {
- myHeight *= factor;
- myDepth *= factor;
- for (hersheyChar *p=contents; p; p=p->next) p->scale(factor);
- }
- ////
- // destructor
- ////
- hersheyString::~hersheyString()
- {
- hersheyChar *myPtr, *nextPtr;
- for (myPtr = contents; myPtr; myPtr = nextPtr) {
- nextPtr = myPtr->next;
- delete myPtr;
- }
- }
- ////
- // write out to the right
- ////
- void hersheyString::right(const genText *inText, float &xStart, float &yStart)
- {
- angle upVec(1, 0), baseVec(0, 1);
- float expand = 1;
- if (inText->info()->orientation()) {
- upVec = angle(inText->info()->orientation()->y(0),
- inText->info()->orientation()->x(0));
- baseVec = angle(inText->info()->orientation()->y(1),
- inText->info()->orientation()->x(1));
- if (upVec.size()) expand = baseVec.size() / upVec.size();
- }
- expand *= inText->info()->expan();
- for (hersheyChar *myPtr=contents; myPtr; myPtr=myPtr->next) {
- xStart += myPtr->shift1() * expand;
- yStart += myPtr->shiftY1();
- myPtr->shift(xStart, yStart);
- xStart += myPtr->shift2() * expand;
- yStart += myPtr->shiftY2();
- }
- }
- ////
- // write out to the left
- ////
- void hersheyString::left(const genText *inText, float &xStart, float &yStart)
- {
- angle upVec(1, 0), baseVec(0, 1);
- float expand = 1;
- if (inText->info()->orientation()) {
- upVec = angle(inText->info()->orientation()->y(0),
- inText->info()->orientation()->x(0));
- baseVec = angle(inText->info()->orientation()->y(1),
- inText->info()->orientation()->x(1));
- if (upVec.size()) expand = baseVec.size() / upVec.size();
- }
- expand *= inText->info()->expan();
- for (hersheyChar *myPtr=contents; myPtr; myPtr=myPtr->next) {
- xStart -= myPtr->shift2() * expand;
- yStart -= myPtr->shiftY2();
- myPtr->shift(xStart, yStart);
- xStart -= myPtr->shift1() * expand;
- yStart -= myPtr->shiftY1();
- }
- }
- ////
- // write up
- ////
- void hersheyString::up(const genText *inText, float &xStart, float &yStart)
- {
- float x, expand = 1;
- angle upVec(1, 0), baseVec(0, 1);
- if (inText->info()->orientation()) {
- upVec = angle(inText->info()->orientation()->y(0),
- inText->info()->orientation()->x(0));
- baseVec = angle(inText->info()->orientation()->y(1),
- inText->info()->orientation()->x(1));
- if (upVec.size()) expand = baseVec.size() / upVec.size();
- }
- expand *= inText->info()->expan();
- for (hersheyChar *myPtr=contents; myPtr; myPtr=myPtr->next) {
- x = xStart + myPtr->shift1() * expand;
- myPtr->shift(x, yStart);
- yStart += myPtr->height() * upVec.sin();
- xStart += myPtr->height() * upVec.cos();
- }
- }
- ////
- // write down
- ////
- void hersheyString::down(const genText *inText, float &xStart, float &yStart)
- {
- float x, expand = 1;
- angle upVec(1, 0), baseVec(0, 1);
- if (inText->info()->orientation()) {
- upVec = angle(inText->info()->orientation()->y(0),
- inText->info()->orientation()->x(0));
- baseVec = angle(inText->info()->orientation()->y(1),
- inText->info()->orientation()->x(1));
- if (upVec.size()) expand = baseVec.size() / upVec.size();
- }
- expand *= inText->info()->expan();
- for (hersheyChar *myPtr=contents; myPtr; myPtr=myPtr->next) {
- x = xStart + myPtr->shift1() * expand;
- myPtr->shift(x, yStart);
- yStart -= myPtr->height() * upVec.sin();
- xStart -= myPtr->height() * upVec.cos();
- }
- }
- void hersheyString::addChar(hersheyChar *inChar)
- {
- if (!contents) contents = inChar;
- else {
- for (hersheyChar *myPtr = contents; myPtr->next; myPtr = myPtr->next);
- myPtr->next = inChar;
- if (inChar->height() > myHeight) myHeight = inChar->height();
- if (inChar->depth() > myDepth) myDepth = inChar->depth();
- }
- }
- int hersheyString::display(baseDisplay *inDisplay)
- {
- int ret = 1;
- for (hersheyChar *myPtr=contents; myPtr; myPtr=myPtr->next)
- ret = ret && myPtr->display(inDisplay);
- return ret;
- }
- #ifdef macintosh
- #pragma segment DIS2
- #endif
- ////
- // base display
- // constructor
- ////
- baseDisplay::baseDisplay()
- {
- myPxlExtent = NULL;
- }
- ////
- // graphical primitives
- ////
- // disjoint polyline
- ////
- int baseDisplay::disPolyline(const vdcPts *inPts) // emulate with a polyline
- // we do the disjoint polyline 2 pairs of points at a time
- {
- int i, j, ret = 1;
- vdcPts *myPts = NULL;
-
- if (inPts->type()) { // real vdc's
- float *newFloat = new float[4];
- myPts = new vdcPts(newFloat, 2);
-
- for (i=0; (i<inPts->no()) && ret; i +=2) {
- for (j=0; j<4; ++j) newFloat[j] = inPts->f(2*i+j);
- ret = ret && polyline(myPts);
- }
- } else { // integer VDC's
- int *newInt = new int[4];
- myPts = new vdcPts(newInt, 2);
-
- for (i=0; (i<inPts->no()) && ret; i +=2) {
- for (j=0; j<4; ++j) newInt[j] = inPts->i(2*i+j);
- ret = ret && polyline(myPts);
- }
- }
- delete myPts; // clean up
- return ret;
- }
- ////
- // polymarker
- ////
- int baseDisplay::polymarker(const vdcPts *inPts) // emulate with disjoint polyline
- {
- int ret = 1, i, j;
- float *newFloat;
- int *newInt;
- vdcPts *myPts = NULL;
- float defSize = 0.01 * vdcHeight; // default size
- float markerSize; // marker size we shall use
-
- // simple descriptions of the markers as vectors, normalised to unit size
- // note that we call circle routine for a circle (number 4)
- const int noMarkers = 6; // for convenience; 4 + circle, 0 is a dummy
- // points in descriptions
- static const int noPoints[noMarkers] = {0, 2, 4, 6, 0, 4};
- // position of descriptions
- static const int offsets[noMarkers] = {0, 0, 2, 6, 12, 12};
- // descriptions
- static float markers[32] = {
- 0.0, 0.0, 0.0, 0.0, // dot
- 0.0, 0.5, 0.0, -0.5, 0.5, 0.0, -0.5, 0.0, // plus
- 0.0, 0.5, 0.0, -0.5, 0.25, 0.433, -0.25, -0.433,
- -0.25, 0.433, 0.25, -0.433, // asterisk
- 0.354, 0.354, -0.354, -0.354,
- -0.354, 0.354, 0.354, -0.354}; // cross
-
- ////
- // figure out the size we shall use,
- if (myMarkerSize) { // been told a size
- markerSize = myMarkerSize->type() ? // relative size required
- myMarkerSize->f() * defSize // else
- : myMarkerSize->v()->f(); // absolute size
- } else markerSize = defSize; // default
-
- if (myMarkerType == 4) { // use a circle
- vdc *radius = NULL;
- if (inPts->type()) { // real vdc's
- newFloat = new float[2];
- radius = new vdc((float) (markerSize/2));
- myPts = new vdcPts(newFloat, 1);
- for (i=0; i<inPts->no() && ret; ++i) {
- newFloat[0] = inPts->fx(i);
- newFloat[1] = inPts->fy(i);
- ret = ret && circle(myPts, radius, 1);
- }
- } else { // integer vdc's
- newInt = new int[2];
- radius = new vdc((int) (markerSize/2));
- myPts = new vdcPts(newInt, 1);
- for (i=0; i<inPts->no() && ret; ++i) {
- newInt[0] = inPts->ix(i);
- newInt[1] = inPts->iy(i);
- ret = ret && circle(myPts, radius, 1);
- }
- }
- delete myPts;
- delete radius;
- return ret;
- } else if ((myMarkerType > 0) && (myMarkerType < 6)) {
- ////
- // use disjoint polyline
- float *floatPtr = markers + 2 * offsets[myMarkerType];
-
- if (inPts->type()) { // real vdc's
- newFloat = new float[2 * noPoints[myMarkerType]];
- myPts = new vdcPts(newFloat, noPoints[myMarkerType]);
- for (i=0; i<inPts->no() && ret; ++i) {
- for (j=0; j<noPoints[myMarkerType]; ++j) {
- newFloat[2*j] = inPts->fx(i) + markerSize * floatPtr[2*j];
- newFloat[2*j+1] = inPts->fy(i) + markerSize * floatPtr[2*j+1];
- }
- ret = ret && disPolyline(myPts);
- }
- } else { // integer VDC's
- newInt = new int[2 * noPoints[myMarkerType]];
- myPts = new vdcPts(newInt, noPoints[myMarkerType]);
- for (i=0; i<inPts->no() && ret; ++i) {
- for (j=0; j<noPoints[myMarkerType]; ++j) {
- newInt[2*j] = inPts->ix(i) + (int) (markerSize * floatPtr[2*j]);
- newInt[2*j+1] = inPts->iy(i) + (int) (markerSize * floatPtr[2*j+1]);
- }
- ret = ret && disPolyline(myPts);
- }
- }
- delete myPts;
- } // disjoint polyline emulation
- return ret;
- }
- #ifdef macintosh
- #pragma segment DIS3
- #endif
- ////
- // text, emulate
- ////
- int baseDisplay::text(const genText *inText)
- {
- hersheyString *myString = new hersheyString(inText);
- int ret = myString->display(this);
- delete myString;
- return ret;
- }
- ////
- // polygon
- ////
- int baseDisplay::polygon(const vdcPts *inPts) // emulate with a polyline
- {
- int i, ret;
- vdcPts *myPts;
- if (inPts->type()) { // real vdc's
- float *newFloat = new float[2 * (inPts->no() + 1)];
- for (i=0; i<2 * inPts->no(); ++i) newFloat[i] = inPts->f(i);
- newFloat[i++] = inPts->fx(0); // complete polygon
- newFloat[i++] = inPts->fy(0);
- myPts = new vdcPts(newFloat, inPts->no() + 1);
- } else {
- int *newInt = new int[2 * (inPts->no() + 1)];
- for (i=0; i<2 * inPts->no(); ++i) newInt[i] = inPts->i(i);
- newInt[i++] = inPts->ix(0); // complete polygon
- newInt[i++] = inPts->iy(0);
- myPts = new vdcPts(newInt, inPts->no() + 1);
- }
- ret = polyline(myPts);
- delete myPts;
- return ret;
- }
- ////
- // polygon set, emulate with a polygon
- ////
- int baseDisplay::polygonSet(const vdcPts *inPts, const int*)
- {
- return polygon(inPts);
- }
- ////
- // cell array
- ////
- int baseDisplay::cells(const cellArray *inCarray) // emulate with a polygon
- {
- int ret = (inCarray && inCarray->corners()) ?
- rectangle(inCarray->corners()) : 1;
- return ret;
- }
- ////
- // rectangle
- ////
- int baseDisplay::rectangle(const vdcPts *inPts) // emulate with a polygon
- {
- const int noIndices = 8;
- static const int permute[noIndices] = {0, 1, 0, 3, 2, 3, 2, 1};
- if (!inPts || (inPts->no() < 2)) {
- myError("too few points in a rectangle");
- return 1;
- }
- int ret, i;
- vdcPts *myPts;
- if (inPts->type()) { // real vdc's
- float *newFloat = new float[noIndices];
- for (i=0; i<noIndices; ++i) newFloat[i] = inPts->f(permute[i]);
- myPts = new vdcPts(newFloat, noIndices / 2);
- } else {
- int *newInt = new int[8];
- for (i=0; i<noIndices; ++i) newInt[i] = inPts->i(permute[i]);
- myPts = new vdcPts(newInt, 4);
- }
- ret = polygon(myPts);
- delete myPts;
- return ret;
- }
- ////
- // circle
- ////
- int baseDisplay::circle(const vdcPts *centre, const vdc *radius, int lineOnly)
- {
- ////
- // get the beginning and ending angles
- angle theta0(-0.0001, -1); // -pi - epsilon
- angle theta1(0.0001, -1); // -pi + epsilon
- // get a new set of points from our emulation routine
- vdcPts *myPts = getArc(centre, radius, &theta0, &theta1, 1);
- int ret = (lineOnly) ? polyline(myPts) : polygon(myPts);
- delete myPts;
- return ret;
- }
- ////
- // basic elliptical arc routine, defaults to circles
- // i.e., if r2 == NULL and rotation == 0 will get a circle
- ////
- vdcPts *baseDisplay::getArc(const vdcPts *centre, const vdc *radius,
- const angle *theta0, const angle *theta1,
- int closeType, const vdc *r2,
- const angle *rotation)
- {
- // draw a circular arc from theta0 to theta1
- // if closeType == 0 then we add a final point at the centre
- // if closeType == 1 then we add a final point duplicating the first
- int i;
- vdcPts *myPts;
- #ifdef __MSDOS__
- int totalPts = 5000; // maximum no of points
- #else
- int totalPts = 10000; // maximum no of points
- #endif
- int noPts = (closeType >= 0) ? totalPts - 1 : totalPts;
- ////
- // need the rotation angle, may be null
- double crot = (rotation) ? rotation->cos() : 1;
- double srot = (rotation) ? rotation->sin() : 0;
- ////
- // get the starting angle, theta0 - rotation, and finishing angle
- angle theta = (rotation) ? *theta0 - *rotation : *theta0;
- angle end = (rotation) ? *theta1 - *rotation : *theta1;
- ////
- // now figure out a reasonable stepping angle
- angle dtheta(1.0 / (1.0 + getSize(radius)), 1);
- ////
- // get the radii, etc.
- float fx, fy;
- if (centre->type()) { // real
- fx = centre->fx(0);
- fy = centre->fy(0);
- } else {
- fx = centre->ix(0);
- fy = centre->iy(0);
- }
- float fa = radius->f(); // first radius
- float fb = (r2) ? r2->f() : fa; // second radius
- // note that we make sure coincident start and end -> full circle
- if (centre->type()) { // real
- float *newFloat = new float[totalPts * 2];
- for (i=0; (i<noPts) &&
- !(end.within(theta, theta + dtheta) && (i>1)); ++i) {
- newFloat[2*i] = fx + fa * theta.cos() * crot -
- fb * theta.sin() * srot;
- newFloat[2*i+1] = fy + fb * theta.sin() * crot +
- fa * theta.cos() * srot;
- theta +=dtheta;
- }
- if (closeType == 0) { // add point at centre
- newFloat[2*i] = fx;
- newFloat[2*i+1] = fy;
- ++i;
- } else if (closeType == 1) { // close with a chord
- newFloat[2*i] = newFloat[0];
- newFloat[2*i+1] = newFloat[1];
- ++i;
- }
- myPts = new vdcPts(newFloat, i);
- } else { // integer
- int *newInt = new int[totalPts * 2];
- for (i=0; (i<noPts) &&
- !(end.within(theta, theta + dtheta) && (i>1)); ++i) {
- newInt[2*i] = (int) (fx + fa * theta.cos() * crot -
- fb * theta.sin() * srot);
- newInt[2*i+1] = (int) (fy + fb * theta.sin() * crot +
- fa * theta.cos() * srot);
- theta +=dtheta;
- }
- if (closeType == 0) { // add point at centre
- newInt[2*i] = (int) fx;
- newInt[2*i+1] = (int) fy;
- ++i;
- } else if (closeType == 1) { // close with a chord
- newInt[2*i] = newInt[0];
- newInt[2*i+1] = newInt[1];
- ++i;
- }
- myPts = new vdcPts(newInt, i);
- }
- return myPts;
- }
- ////
- // circular arc, 3 points, may close
- // emulate with a polygon or polyline
- // closeType == -1 => no closure
- // closeType == 0 => pie
- // closeType == 1 => chord
- ////
- int baseDisplay::arc3Pt(const vdcPts *inPts, int closeType)
- {
- // handy macro
- #define SQ(in) ((double) (in) * (in))
- float *c = new float[2];
- int ret = 1;
- if (inPts->no() < 3) return ret; // something strange
- ////
- // first figure out centre, radius and 2 angles from 3 points
- // make sure they're not co-linear
- float t1 = ((inPts->x(2) - inPts->x(0)) * (inPts->y(1) - inPts->y(0)) -
- (inPts->x(1) - inPts->x(0)) * (inPts->y(2) - inPts->y(0))) * 2;
- if (t1 == 0) return ret; // co-linear
- ////
- // more temporary variables
- float t2 = inPts->x2(1) - inPts->x2(0) + inPts->y2(1) - inPts->y2(0);
- float t3 = inPts->x2(2) - inPts->x2(0) + inPts->y2(2) - inPts->y2(0);
- ////
- // now get the center coordinates, x and y
- c[0] = ((inPts->y(2) - inPts->y(0)) * t2 -
- (inPts->y(1) - inPts->y(0)) * t3) / t1;
- c[1] = ((inPts->x(2) - inPts->x(0)) * t2 -
- (inPts->x(1) - inPts->x(0)) * t3) / t1;
- ////
- // now the radius
- float r = sqrt(SQ(inPts->x(0) - c[0]) + SQ(inPts->y(0) - c[1]));
- ////
- // now the angles
- angle theta0(inPts->y(0) - c[1], inPts->x(0) - c[0]);
- angle theta1(inPts->y(1) - c[1], inPts->x(1) - c[0]);
- angle theta2(inPts->y(2) - c[1], inPts->x(2) - c[0]);
- ////
- // we need to include the middle point between the start and end
- angle *start, *end;
- if (theta1.within(theta0, theta2)) {
- start = &theta0;
- end = &theta2;
- } else {
- start = &theta2;
- end = &theta0;
- }
- ////
- // prepare for the call to the arc routine
- vdcPts centre(c);
- vdc radius(r);
- ////
- // make the call
- vdcPts *myPts = getArc(¢re, &radius, start, end, closeType);
- ret = (closeType >= 0) ? polygon(myPts) : polyline(myPts);
- delete myPts;
- ////
- // all done
- return ret;
- }
- ////
- // circular arc, center, 2 vectors, radius, may close
- // emulate with a polygon or polyline
- ////
- int baseDisplay::arcCtr(const vdcPts *inPts, vdc *radius, int closeType)
- {
- int ret = 1;
- if (inPts->no() < 3) return ret; // something strange
- ////
- // first figure out 2 angles from info
- angle theta0(inPts->y(1), inPts->x(1));
- angle theta1(inPts->y(2), inPts->x(2));
- ////
- // now get the emulated points
- vdcPts *myPts = getArc(inPts, radius, &theta0, &theta1, closeType);
- ret = (closeType >= 0) ? polygon(myPts) : polyline(myPts);
- delete myPts;
- ////
- // all done
- return ret;
- }
- #ifdef macintosh
- #pragma segment DIS4
- #endif
- ////
- // ellipse, 3 pts (centre and 2 CDP's)
- // emulate with a polygon
- ////
- int baseDisplay::ellipse(const vdcPts *inPts)
- {
- if (inPts->no() < 3) return 1; // something strange
- vdc *radius1, *radius2;
-
- // get the 2 radii
- float r1 = sqrt(SQ(inPts->x(1) - inPts->x(0)) +
- SQ(inPts->y(1) - inPts->y(0)));
- float r2 = sqrt(SQ(inPts->x(2) - inPts->x(0)) +
- SQ(inPts->y(2) - inPts->y(0)));
- ////
- // get the beginning and ending angles
- angle theta0(-0.001, -1); // -pi - epsilon
- angle theta1(0.001, -1); // -pi + epsilon
- // figure out the angle of rotation
- angle rotation(inPts->y(1) - inPts->y(0), inPts->x(1) - inPts->x(0));
-
- if (inPts->type()) { // real vdc's
- radius1 = new vdc(r1);
- radius2 = new vdc(r2);
- } else { // integer
- radius1 = new vdc((int) r1);
- radius2 = new vdc((int) r2);
- }
- // get a new set of points from our emulation routine
- vdcPts *myPts = getArc(inPts, radius1, &theta0, &theta1,
- -1, radius2, &rotation);
- int ret = polygon(myPts); // do a polygon
- delete myPts;
- delete radius1;
- delete radius2;
- return ret;
- }
- ////
- // elliptical arc, 5 pts plus close type
- // emulate with a polygon or polyline
- ////
- int baseDisplay::ellipArc(const vdcPts *inPts, int closeType)
- {
- if (inPts->no() < 5) return 1; // something strange
- vdc *radius1, *radius2;
-
- // get the 2 radii
- float r1 = sqrt(SQ(inPts->x(1) - inPts->x(0)) +
- SQ(inPts->y(1) - inPts->y(0)));
- float r2 = sqrt(SQ(inPts->x(2) - inPts->x(0)) +
- SQ(inPts->y(2) - inPts->y(0)));
- ////
- // figure out the angle of rotation
- angle rotation(inPts->y(1) - inPts->y(0), inPts->x(1) - inPts->x(0));
- ////
- // get the starting and ending angles
- angle theta0(inPts->y(3), inPts->x(3));
- angle theta1(inPts->y(4), inPts->x(4));
-
- if (inPts->type()) { // real vdc's
- radius1 = new vdc(r1);
- radius2 = new vdc(r2);
- } else { // integer
- radius1 = new vdc((int) r1);
- radius2 = new vdc((int) r2);
- }
- // get a new set of points from our emulation routine
- vdcPts *myPts = getArc(inPts, radius1, &theta0, &theta1,
- closeType, radius2, &rotation);
- int ret = (closeType >= 0) ? polygon(myPts) : polyline(myPts);
- delete myPts;
- delete radius1;
- delete radius2;
- return ret;
- }
- ////
- // function called at beginning of each new picture
- ///
- void baseDisplay::newPic()
- {
- //
- // reset defaults
- // control elements
- //
- myTrans = 1;
- myClipRect = NULL;
- myClip = 0; // fix later
- // attributes
- myLineIndex = 1;
- myLineType = 1;
- myLineWidth = NULL;
- myMarkerIndex = 1;
- myMarkerType = 3;
- myMarkerSize = NULL;
- myTextIndex = 1;
- myFontIndex = 1;
- myTextPrec = 0;
- myCharExpan = 1.0;
- myCharSpace = 0;
- myCharHeight = NULL;
- myCharOri = NULL;
- myTextPath = 0;
- myTextAlign = NULL;
- myEdgeIndex = 1;
- myEdgeType = 1;
- myEdgeWidth = NULL;
- myCharSetIndex = 1;
- myAltCharSetIndex = 1;
- myFillIndex = 1;
- myIntStyle = 0;
- myHatchIndex = 1;
- myPatIndex = 1;
- myEdgeVis = 0;
- myFillRefPt = NULL;
- }
- ////
- // function called at beginning of each new picture body
- ///
- void baseDisplay::newPicBody(float inWidth, float inHeight,
- float xOff, float yOff)
- {
- // store the vdc extent
- vdcWidth = inWidth;
- vdcHeight = inHeight;
- // get the extent of the output device
- devWidth = pxlExtent()->width();
- devHeight = pxlExtent()->height();
- // how much do we have to scale ? (take care of non-square pixels later)
- xScale = devWidth / vdcWidth;
- yScale = devHeight / vdcHeight;
- // use the smaller scale (largest enclosed rectangle)
- useScale = (yScale < xScale) ? yScale : xScale;
- // get the offsets
- useOff[0] = pxlExtent()->x(0);
- useOff[1] = pxlExtent()->y(0);
- // need to keep these separate for inverting devices
- useOff[2] = xOff * useScale;
- useOff[3] = yOff * useScale;
- }
- ////
- // get scaled points into integer form
- ////
- int baseDisplay::getPts(const vdcPts *inPts, int* &outPtr, int close)
- {
- int i;
-
- // get the memory
- outPtr = close ? new int[inPts->no() * 2 + 2] : new int[inPts->no() * 2];
-
- // move over the scaled points
- if (inPts->type()) { // real vdc's
- if (invert()) { // need to invert the picture
- for (i=0; i<inPts->no(); ++i) {
- outPtr[2*i] = (int) (useOff[0] + useOff[2] + useScale * inPts->fx(i));
- outPtr[2*i+1] = (int) (devHeight + useOff[3]
- - useOff[1] - useScale * inPts->fy(i));
- }
- } else { // normal picture
- for (i=0; i<2*inPts->no(); ++i)
- outPtr[i] = (int) (useOff[i % 2] + useOff[2 + (i % 2)]
- + useScale * inPts->f(i));
- }
- } else { // integer VDC's
- if (invert()) { // need to invert the picture
- for (i=0; i<inPts->no(); ++i) {
- outPtr[2*i] = (int) (useOff[0] + useOff[2] + useScale * inPts->ix(i));
- outPtr[2*i+1] = (int) (devHeight - useOff[1]
- + useOff[3] - useScale * inPts->iy(i));
- }
- } else { // normal picture
- for (i=0; i<2*inPts->no(); ++i)
- outPtr[i] = (int) (useOff[i % 2] + + useOff[2 + (i % 2)]
- + useScale * inPts->i(i));
- }
- }
- if (close) { // want to close the path
- outPtr[2 * inPts->no()] = outPtr[0];
- outPtr[2 * inPts->no() + 1] = outPtr[1];
- }
- return 1;
- }
- ////
- // get scaled points into float form
- ////
- int baseDisplay::getPts(const vdcPts *inPts, float* &outPtr, int close)
- {
- int i;
- // get the memory
- outPtr = close ? new float[inPts->no() * 2 + 2] : new float[inPts->no() * 2];
-
- // move over the scaled points
- if (inPts->type()) { // real vdc's
- if (invert()) { // need to invert the picture
- for (i=0; i<inPts->no(); ++i) {
- outPtr[2*i] = useOff[0] + useOff[2] + useScale * inPts->fx(i);
- outPtr[2*i+1] = devHeight - useOff[1] + useOff[3]
- - useScale * inPts->fy(i);
- }
- } else { // normal picture
- for (i=0; i<2*inPts->no(); ++i)
- outPtr[i] = useOff[i % 2] + useOff[2 + (i % 2)]
- + useScale * inPts->f(i);
- }
- } else { // integer VDC's
- if (invert()) { // need to invert the picture
- for (i=0; i<inPts->no(); ++i) {
- outPtr[2*i] = useOff[0] + useOff[2] + useScale * inPts->ix(i);
- outPtr[2*i+1] = devHeight - useOff[1] + useOff[3]
- - useScale * inPts->iy(i);
- }
- } else { // normal picture
- for (i=0; i<2*inPts->no(); ++i)
- outPtr[i] = useOff[i % 2] + useOff[2 + (i % 2)]
- + useScale * inPts->i(i);
- }
- }
- if (close) { // want to close the path
- outPtr[2 * inPts->no()] = outPtr[0];
- outPtr[2 * inPts->no() + 1] = outPtr[1];
- }
- return 1;
- }
- ////
- // get scaled points into short form
- ////
- int baseDisplay::getPts(const vdcPts *inPts, short* &outPtr, int close)
- {
- int i;
- // get the memory
- outPtr = (close) ? new short[inPts->no() * 2 + 2]
- : new short[inPts->no() * 2];
- // move over the scaled points
- if (inPts->type()) { // real vdc's
- if (invert()) { // need to invert the picture
- for (i=0; i<inPts->no(); ++i) {
- outPtr[2*i] = (short) (useOff[0] + useOff[2] +
- useScale * inPts->fx(i));
- outPtr[2*i+1] = (short)(devHeight - useOff[1] + useOff[3]
- -useScale * inPts->fy(i));
- }
- } else { // normal picture
- for (i=0; i<2*inPts->no(); ++i)
- outPtr[i] = (short) (useOff[i % 2] + useOff[2 + (i % 2)]
- + useScale * inPts->f(i));
- }
- } else { // integer VDC's
- if (invert()) { // need to invert the picture
- for (i=0; i<inPts->no(); ++i) {
- outPtr[2*i] = (short) (useOff[0] + useOff[2] +
- useScale * inPts->ix(i));
- outPtr[2*i+1] = (short)(devHeight - useOff[1] + useOff[3]
- - useScale * inPts->iy(i));
- }
- } else { // normal picture
- for (i=0; i<2*inPts->no(); ++i)
- outPtr[i] = (short) (useOff[i % 2] + useOff[2 + (i % 2)]
- + useScale * inPts->i(i));
- }
- }
- if (close) { // want to close the path
- outPtr[2 * inPts->no()] = outPtr[0];
- outPtr[2 * inPts->no() + 1] = outPtr[1];
- }
- return 1;
- }
- ////
- // attributes
- ////
- void baseDisplay::colrs(const colrTable*) // colour table test implementation
- {
- // fprintf(stderr, "colour table set\n");
- }
-