/* * Copyright (c) 1987, 1988, 1989 Stanford University * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided * that the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Stanford not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. Stanford makes no representations about * the suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * STANFORD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Graphic base class implementation. */ #include #include #include #include #include #include /* * Static member allocation. */ Transformer* Graphic::identity; /* identity matrix */ bool Graphic::caching; /* state of bounding box caching */ GraphicToPainter* Graphic::painters; Painter* Graphic::p; Graphic& Graphic::operator = (Graphic& p) { SetColors(p.GetFgColor(), p.GetBgColor()); FillBg(p.BgFilled()); SetPattern(p.GetPattern()); SetBrush(p.GetBrush()); SetFont(p.GetFont()); if (p.t == nil) { Unref(t); t = nil; } else { if (t == nil) { t = new Transformer(p.t); } else { *t = *p.t; } } invalidateCaches(); return *this; } void Graphic::update (Graphic* gs) { p = painters->Find(gs); Transformer* t = p->GetTransformer(); if (t == nil) { if (gs->t != nil) { Transformer* newt = new Transformer(gs->t); p->SetTransformer(newt); Unref(newt); } } else { if (gs->t == nil) { *t = *identity; } else { *t = *gs->t; } } } void Graphic::getExtent (float&, float&, float&, float&, float&, Graphic*) { } void Graphic::cachingOn () { caching = true; } void Graphic::cachingOff () { caching = false; } void Graphic::transform (Coord& x, Coord& y, Graphic* g) { Transformer* t = (g == nil) ? GetTransformer() : g->GetTransformer(); if (t != nil) { t->Transform(x, y); } } void Graphic::transform (Coord x, Coord y, Coord& tx, Coord& ty, Graphic* g) { Transformer* t = (g == nil) ? GetTransformer() : g->GetTransformer(); if (t != nil) { t->Transform(x, y, tx, ty); } else { tx = x; ty = y; } } void Graphic::transform (float x, float y, float& tx, float& ty, Graphic* g) { Transformer* t = (g == nil) ? GetTransformer() : g->GetTransformer(); if (t != nil) { t->Transform(x, y, tx, ty); } else { tx = x; ty = y; } } void Graphic::transformList ( Coord x[], Coord y[], int n, Coord tx[], Coord ty[], Graphic* g ) { Transformer* t = (g == nil) ? GetTransformer() : g->GetTransformer(); if (t != nil) { t->TransformList(x, y, n, tx, ty); } else { CopyArray(x, y, n, tx, ty); } } void Graphic::transformRect ( float x0, float y0, float x1, float y1, float& nx0, float& ny0, float& nx1, float& ny1, Graphic* g ) { Transformer* t = (g == nil) ? GetTransformer() : g->GetTransformer(); nx0 = x0; ny0 = y0; nx1 = x1; ny1 = y1; if (t != nil) { t->TransformRect(nx0, ny0, nx1, ny1); } } void Graphic::invTransform (Coord& tx, Coord& ty, Graphic* g) { Transformer* t = (g == nil) ? GetTransformer() : g->GetTransformer(); if (t != nil) { t->InvTransform(tx, ty); } } void Graphic::invTransform ( Coord tx, Coord ty, Coord& x, Coord& y, Graphic* g ) { Transformer* t = (g == nil) ? GetTransformer() : g->GetTransformer(); if (t != nil) { t->InvTransform(tx, ty, x, y); } else { x = tx; y = ty; } } void Graphic::invTransform ( float tx, float ty, float& x, float& y, Graphic* g ) { Transformer* t = (g == nil) ? GetTransformer() : g->GetTransformer(); if (t != nil) { t->InvTransform(tx, ty, x, y); } else { x = tx; y = ty; } } void Graphic::invTransformList( Coord tx[], Coord ty[], int n, Coord x[], Coord y[], Graphic* g ) { Transformer* t = (g == nil) ? GetTransformer() : g->GetTransformer(); if (t != nil) { t->InvTransformList(tx, ty, n, x, y); } else { CopyArray(tx, ty, n, x, y); } } void Graphic::invTransformRect ( float x0, float y0, float x1, float y1, float& nx0, float& ny0, float& nx1, float& ny1, Graphic* g ) { Transformer* t = (g == nil) ? GetTransformer() : g->GetTransformer(); nx0 = x0; ny0 = y0; nx1 = x1; ny1 = y1; if (t != nil) { t->InvTransformRect(nx0, ny0, nx1, ny1); } } Graphic* Graphic::getRoot () { Graphic* cur, *parent = this; do { cur = parent; parent = cur->Parent(); } while (parent != nil); return cur; } void Graphic::totalGS (Graphic& gs) { Graphic* parent = Parent(); if (parent == nil) { concat(nil, this, &gs); } else { parent->totalGS(gs); concat(this, &gs, &gs); } } void Graphic::parentXform (Transformer& t) { Graphic* parent = Parent(); if (parent == nil) { t = *identity; } else { parent->TotalTransformation(t); } } void Graphic::TotalTransformation (Transformer& total) { Graphic* parent = Parent(); if (parent == nil) { concatTransformer(nil, t, &total); } else { parent->TotalTransformation(total); concatTransformer(t, &total, &total); } } void Graphic::setParent (Graphic* g, Graphic* parent) { if (!g->parent.Valid()) { // a graphic can have only one parent g->parent = Ref(parent); } } void Graphic::unsetParent (Graphic* g) { g->parent = (Graphic*)nil; g->invalidateCaches(); } bool Graphic::read (PFile* f) { int test; float a[6]; Ref dummy; /* dummy origin ref for backward compatibility */ bool ok = Persistent::read(f) && parent.Read(f) && dummy.Read(f) && f->Read(fillBg) && fg.Read(f) && bg.Read(f) && tag.Read(f) && f->Read(test); if (ok) { if (test != int(nil)) { ok = f->Read(a, 6); t = new Transformer(a[0], a[1], a[2], a[3], a[4], a[5]); } } return ok; } bool Graphic::write (PFile* f) { float a[6]; Ref dummy; /* dummy origin ref for backward compatibility */ bool ok = Persistent::write(f) && parent.Write(f) && dummy.Write(f) && f->Write(fillBg) && fg.Write(f) && bg.Write(f) && tag.Write(f) && f->Write(int(t)); if (ok && t != nil) { t->GetEntries(a[0], a[1], a[2], a[3], a[4], a[5]); ok = f->Write(a, 6); } return ok; } void Graphic::concatGS (Graphic* a, Graphic* b, Graphic* dest) { int fill; PColor* fg, *bg; PFont* font; PBrush* br; PPattern* pat; if (a == nil) { *dest = *b; return; } else if (b == nil) { *dest = *a; return; } if ((fill = b->BgFilled()) == UNDEF) { fill = a->BgFilled(); } dest->FillBg(fill); if ((fg = b->GetFgColor()) == nil) { fg = a->GetFgColor(); } if ((bg = b->GetBgColor()) == nil) { bg = a->GetBgColor(); } dest->SetColors(fg, bg); if ((pat = b->GetPattern()) == nil) { pat = a->GetPattern(); } dest->SetPattern(pat); if ((font = b->GetFont()) == nil) { font = a->GetFont(); } dest->SetFont(font); if ((br = b->GetBrush()) == nil) { br = a->GetBrush(); } dest->SetBrush(br); } void Graphic::concatTransformer ( Transformer* a, Transformer* b, Transformer* dest ) { if (a == nil) { *dest = (b == nil) ? *identity : *b; } else if (b == nil) { *dest = *a; } else { Transformer tmp(a); tmp.Postmultiply(b); *dest = tmp; } } void Graphic::concat (Graphic* a, Graphic* b, Graphic* dest) { Transformer* ta, *tb, *td; ta = (a == nil) ? nil : a->GetTransformer(); tb = (b == nil) ? nil : b->GetTransformer(); td = dest->GetTransformer(); if (td == nil) { td = new Transformer; dest->SetTransformer(td); Unref(td); } concatGS(a, b, dest); concatTransformer(ta, tb, td); } bool Graphic::extentCached () { return false; } void Graphic::uncacheExtent () { } void Graphic::uncacheChildren () { } void Graphic::uncacheParents () { Graphic* p; for (p = Parent(); p != nil && p->extentCached(); p = p->Parent()) { p->uncacheExtent(); } } void Graphic::invalidateCaches() { uncacheParents(); uncacheExtent(); uncacheChildren(); } void Graphic::getBox (Coord& x0, Coord& y0, Coord& x1, Coord& y1, Graphic* gs) { float left, bottom, right, top; getBounds(left, bottom, right, top, gs); x0 = Coord(left - 1); y0 = Coord(bottom - 1); x1 = Coord(right + 1); y1 = Coord(top + 1); } void Graphic::GetExtent (Extent& e) { FullGraphic gs; totalGS(gs); getExtent(e.left, e.bottom, e.cx, e.cy, e.tol, &gs); } void Graphic::GetBounds (float& x0, float& y0, float& x1, float& y1) { FullGraphic gs; totalGS(gs); getBounds(x0, y0, x1, y1, &gs); } void Graphic::GetBox (Coord& x0, Coord& y0, Coord& x1, Coord& y1) { float left, bottom, right, top; GetBounds(left, bottom, right, top); x0 = Coord(left - 1); y0 = Coord(bottom - 1); x1 = Coord(right + 1); y1 = Coord(top + 1); } bool Graphic::contains (PointObj& po, Graphic* gs) { BoxObj b; getBox(b, gs); return b.Contains(po); } bool Graphic::intersects (BoxObj& userb, Graphic* gs) { BoxObj b; getBox(b, gs); return b.Intersects(userb); } void Graphic::draw (Canvas*, Graphic*) { } void Graphic::erase (Canvas* c, Graphic* gs) { PColor* fg = gs->GetFgColor(); PColor* bg = gs->GetBgColor(); gs->SetColors(bg, bg); draw(c, gs); gs->SetColors(fg, bg); } void Graphic::drawClipped ( Canvas* c, Coord left, Coord bottom, Coord right, Coord top, Graphic* gs ) { BoxObj thisBox; BoxObj clipBox(left, bottom, right, top); getBox(thisBox, gs); if (clipBox.Intersects(thisBox)) { draw(c, gs); } } void Graphic::eraseClipped ( Canvas* c, Coord left, Coord bottom, Coord right, Coord top, Graphic* gs ) { BoxObj thisBox; BoxObj clipBox(left, bottom, right, top); getBox(thisBox, gs); if (clipBox.Intersects(thisBox)) { erase(c, gs); } } void Graphic::Draw (Canvas* c) { if (Parent() == nil) { draw(c, this); } else { FullGraphic gs; totalGS(gs); draw(c, &gs); } } void Graphic::Draw (Canvas* c, Coord l, Coord b, Coord r, Coord t) { if (Parent() == nil) { drawClipped(c, l, b, r, t, this); } else { FullGraphic gs; totalGS(gs); drawClipped(c, l, b, r, t, &gs); } } void Graphic::DrawClipped (Canvas* c, Coord l, Coord b, Coord r, Coord t) { painters->Clip(c, l, b, r, t); if (Parent() == nil) { drawClipped(c, l, b, r, t, this); } else { FullGraphic gs; totalGS(gs); drawClipped(c, l, b, r, t, &gs); } painters->NoClip(); } void Graphic::Erase (Canvas* c) { if (Parent() == nil) { erase(c, this); } else { FullGraphic gs; totalGS(gs); erase(c, &gs); } } void Graphic::Erase (Canvas* c, Coord l, Coord b, Coord r, Coord t) { if (Parent() == nil) { eraseClipped(c, l, b, r, t, this); } else { FullGraphic gs; totalGS(gs); eraseClipped(c, l, b, r, t, &gs); } } void Graphic::EraseClipped (Canvas* c, Coord l, Coord b, Coord r, Coord t) { painters->Clip(c, l, b, r, t); if (Parent() == nil) { eraseClipped(c, l, b, r, t, this); } else { FullGraphic gs; totalGS(gs); eraseClipped(c, l, b, r, t, &gs); } painters->NoClip(); } Persistent* Graphic::GetCluster () { if (parent.Valid()) { return Parent()->GetCluster(); } else { return this; } } static const int PAINTERS_SIZE = 100; ClassId Graphic::GetClassId () { return GRAPHIC; } bool Graphic::IsA (ClassId id) { return GRAPHIC == id || Persistent::IsA(id); } Graphic::Graphic (Graphic* gr) { parent = (Graphic*)nil; tag = (Persistent*)nil; t = nil; if (painters == nil) { painters = new GraphicToPainter(PAINTERS_SIZE); identity = new Transformer; cachingOn(); } if (gr == nil) { FillBg((unsigned int) UNDEF); SetColors(nil, nil); } else { FillBg(gr->BgFilled()); SetColors(gr->GetFgColor(), gr->GetBgColor()); if (gr->t != nil) { t = new Transformer(gr->t); } } } Graphic::~Graphic () { Unref(t); } void Graphic::GetCenter (float& x, float& y) { FullGraphic gs; float l, b, tol; totalGS(gs); getExtent(l, b, x, y, tol, &gs); } bool Graphic::Contains (PointObj& p) { if (Parent() == nil) { return contains(p, this); } else { FullGraphic gs; totalGS(gs); return contains(p, &gs); } } bool Graphic::Intersects (BoxObj& b) { if (Parent() == nil) { return intersects(b, this); } else { FullGraphic gs; totalGS(gs); return intersects(b, &gs); } } Graphic* Graphic::Copy () { return new Graphic(this); } void Graphic::FillBg (bool fbg) { fillBg = fbg; } int Graphic::BgFilled () { return fillBg; } void Graphic::SetColors (PColor* f, PColor* b) { fg = Ref(f); bg = Ref(b); } PColor* Graphic::GetFgColor () { return (PColor*) fg(); } PColor* Graphic::GetBgColor () { return (PColor*) bg(); } void Graphic::SetPattern (PPattern*) { } PPattern* Graphic::GetPattern () { return nil; } void Graphic::SetBrush (PBrush*) { } PBrush* Graphic::GetBrush() { return nil; } void Graphic::SetFont (PFont*) { } PFont* Graphic::GetFont () { return nil; } bool Graphic::HasChildren () { return false; } void Graphic::Translate (float dx, float dy) { if (dx != 0 || dy != 0) { if (t == nil) { t = new Transformer; } t->Translate(dx, dy); uncacheParents(); } } void Graphic::Scale (float sx, float sy, float cx, float cy) { float ncx, ncy; if (sx != 1 || sy != 1) { if (t == nil) { t = new Transformer; } Transformer parents; parentXform(parents); parents.InvTransform(cx, cy, ncx, ncy); if (ncx != 0 || ncy != 0) { t->Translate(-ncx, -ncy); t->Scale(sx, sy); t->Translate(ncx, ncy); } else { t->Scale(sx, sy); } uncacheParents(); } } void Graphic::Rotate (float angle, float cx, float cy) { float mag = (angle < 0) ? -angle : angle; float ncx, ncy; if ((mag - int(mag)) != 0 || int(mag)%360 != 0) { if (t == nil) { t = new Transformer; } Transformer parents; parentXform(parents); parents.InvTransform(cx, cy, ncx, ncy); if (ncx != 0 || ncy != 0) { t->Translate(-ncx, -ncy); t->Rotate(angle); t->Translate(ncx, ncy); } else { t->Rotate(angle); } uncacheParents(); } } void Graphic::SetTransformer (Transformer* t) { if (t != this->t) { Unref(this->t); if (t != nil) { t->Reference(); } this->t = t; uncacheParents(); } } void Graphic::Align (Alignment falign, Graphic* moved, Alignment malign) { float fx0, fy0, fx1, fy1, mx0, my0, mx1, my1, dx = 0, dy = 0; Transformer parents; GetBounds(fx0, fy0, fx1, fy1); moved->GetBounds(mx0, my0, mx1, my1); switch (falign) { case BottomLeft: case CenterLeft: case TopLeft: case Left: dx = fx0; break; case BottomCenter: case Center: case TopCenter: case HorizCenter: dx = (fx0 + fx1 + 1)/2; break; case BottomRight: case CenterRight: case TopRight: case Right: dx = fx1 + 1; break; } switch (falign) { case BottomLeft: case BottomCenter: case BottomRight: case Bottom: dy = fy0; break; case CenterLeft: case Center: case CenterRight: case VertCenter: dy = (fy0 + fy1 + 1)/2; break; case TopLeft: case TopCenter: case TopRight: case Top: dy = fy1 + 1; break; } switch (malign) { case BottomLeft: case CenterLeft: case TopLeft: case Left: dx -= mx0; break; case BottomCenter: case Center: case TopCenter: case HorizCenter: dx -= (mx0 + mx1 + 1)/2; break; case BottomRight: case CenterRight: case TopRight: case Right: dx -= (mx1 + 1); break; } switch (malign) { case BottomLeft: case BottomCenter: case BottomRight: case Bottom: dy -= my0; break; case CenterLeft: case Center: case CenterRight: case VertCenter: dy -= (my0 + my1 + 1)/2; break; case TopLeft: case TopCenter: case TopRight: case Top: dy -= (my1 + 1); break; } if (dx != 0 || dy != 0) { parentXform(parents); parents.InvTransform(0.0, 0.0, fx0, fy0); parents.InvTransform(dx, dy, mx0, my0); moved->Translate(mx0-fx0, my0-fy0); } } /*****************************************************************************/ bool FullGraphic::read (PFile* f) { return Graphic::read(f) && pat.Read(f) && brush.Read(f) && font.Read(f); } bool FullGraphic::write (PFile* f) { return Graphic::write(f) && pat.Write(f) && brush.Write(f) &&font.Write(f); } Graphic* FullGraphic::Copy () { return new FullGraphic(this); } ClassId FullGraphic::GetClassId () { return FULL_GRAPHIC; } bool FullGraphic::IsA (ClassId id) { return FULL_GRAPHIC == id || Graphic::IsA(id); } FullGraphic::FullGraphic (Graphic* gr) : Graphic(gr) { if (gr == nil) { SetPattern(nil); SetBrush(nil); SetFont(nil); } else { SetPattern(gr->GetPattern()); SetBrush(gr->GetBrush()); SetFont(gr->GetFont()); } } void FullGraphic::SetPattern (PPattern* p) { pat = Ref(p); } PPattern* FullGraphic::GetPattern () { return (PPattern*) pat(); } void FullGraphic::SetBrush (PBrush* brush) { if (this->brush != Ref(brush)) { this->brush = Ref(brush); invalidateCaches(); } } PBrush* FullGraphic::GetBrush () { return (PBrush*) brush(); } void FullGraphic::SetFont (PFont* font) { if (this->font != Ref(font)) { this->font = Ref(font); invalidateCaches(); } } PFont* FullGraphic::GetFont () { return (PFont*) font(); } Transformer* Graphic::GetTransformer () { return t; } Graphic* Graphic::Parent () { return (Graphic*) parent(); } void Graphic::SetTag (Ref r) { tag = r; } Ref Graphic::GetTag () { return tag; } void Graphic::GetBox (BoxObj& b) { GetBox(b.left, b.bottom, b.right, b.top); } void Graphic::getBox (BoxObj& b, Graphic* p) { getBox(b.left, b.bottom, b.right, b.top, p); } void Graphic::pText (Canvas* c, char* s, int n, Coord x, Coord y) { p->Text(c, s, n, x, y); } void Graphic::pPoint (Canvas* c, Coord x, Coord y) { p->Point(c, x, y); } void Graphic::pMultiPoint(Canvas* c, Coord x[], Coord y[], int n) { p->MultiPoint(c, x, y, n); } void Graphic::pLine(Canvas* c, Coord x1, Coord y1, Coord x2, Coord y2) { p->Line(c, x1, y1, x2, y2); } void Graphic::pRect(Canvas* c, Coord x1, Coord y1, Coord x2, Coord y2) { p->Rect(c, x1, y1, x2, y2); } void Graphic::pFillRect(Canvas* c,Coord x1,Coord y1, Coord x2,Coord y2){ p->FillRect(c, x1, y1, x2, y2); } void Graphic::pRasterRect(Canvas* c, Coord x, Coord y, Raster* r){ p->RasterRect(c, x, y, r); } void Graphic::pStencil(Canvas* c,Coord x,Coord y, Bitmap* i, Bitmap* m){ p->Stencil(c, x, y, i, m); } void Graphic::pCircle(Canvas* c, Coord x, Coord y, int r) { p->Circle(c, x, y, r); } void Graphic::pFillCircle(Canvas* c, Coord x, Coord y, int r) { p->FillCircle(c, x, y, r); } void Graphic::pEllipse(Canvas* c, Coord x, Coord y, int r1, int r2) { p->Ellipse(c, x, y, r1, r2); } void Graphic::pFillEllipse(Canvas* c, Coord x, Coord y, int r1, int r2){ p->FillEllipse(c, x, y, r1, r2); } void Graphic::pMultiLine(Canvas* c, Coord x[], Coord y[], int n) { p->MultiLine(c, x, y, n); } void Graphic::pPolygon(Canvas* c, Coord x[], Coord y[], int n) { p->Polygon(c, x, y, n); } void Graphic::pFillPolygon(Canvas* c, Coord x[], Coord y[], int n) { p->FillPolygon(c, x, y, n); } void Graphic::pBSpline(Canvas* c, Coord x[], Coord y[], int n) { p->BSpline(c, x, y, n); } void Graphic::pClosedBSpline(Canvas* c, Coord x[], Coord y[], int n) { p->ClosedBSpline(c, x, y, n); } void Graphic::pFillBSpline(Canvas* c, Coord x[], Coord y[], int n) { p->FillBSpline(c, x, y, n); } void Graphic::getBounds ( float& l, float& b, float& r, float& t, Graphic* gs ) { float tol; getExtent(l, b, r, t, tol, gs); r += r - l; t += t - b; l -= tol; b -= tol; r += tol; t += tol; } void Graphic::drawGraphic (Graphic* g, Canvas* c, Graphic* gs) { g->draw(c, gs); } void Graphic::eraseGraphic (Graphic* g, Canvas* c, Graphic* gs) { g->erase(c, gs); } void Graphic::drawClippedGraphic ( Graphic* g, Canvas* c, Coord l, Coord b, Coord r, Coord t, Graphic* gs ) { g->drawClipped(c, l, b, r, t, gs); } void Graphic::eraseClippedGraphic ( Graphic* g, Canvas* c, Coord l, Coord b, Coord r, Coord t, Graphic* gs ) { g->eraseClipped(c, l, b, r, t, gs); } void Graphic::getExtentGraphic ( Graphic* g, float& l, float& b, float& r, float& t, float& tol, Graphic* gs ) { g->getExtent(l, b, r, t, tol, gs); } bool Graphic::containsGraphic (Graphic* g, PointObj& p, Graphic* gs){ return g->contains(p, gs); } bool Graphic::intersectsGraphic (Graphic* g, BoxObj& b, Graphic* gs){ return g->intersects(b, gs); } bool Graphic::extentCachedGraphic (Graphic* g) { return g->extentCached(); } void Graphic::uncacheExtentGraphic (Graphic* g) { g->uncacheExtent(); } void Graphic::uncacheParentsGraphic (Graphic* g) { g->uncacheParents();} void Graphic::uncacheChildrenGraphic (Graphic* g) { g->uncacheChildren(); } void Graphic::invalidateCachesGraphic (Graphic* g) { g->invalidateCaches(); } void Graphic::concatGSGraphic ( Graphic* g, Graphic* a, Graphic* b, Graphic* d ) { g->concatGS(a, b, d); } void Graphic::concatTransformerGraphic ( Graphic* g, Transformer* a, Transformer* b, Transformer* dest ) { g->concatTransformer(a, b, dest); } void Graphic::concatGraphic ( Graphic* g, Graphic* a, Graphic* b, Graphic* d ) { g->concat(a, b, d); }