From 1ddaa7bdf04344661fa4d9339ee85f49cbbf3ad9 Mon Sep 17 00:00:00 2001 From: ian Date: Mon, 21 Sep 1998 19:49:36 +0000 Subject: [PATCH] Initial checkin - found in davenant:~ian/chiark/things/moebius --- .depend | 10 ++++ Makefile | 18 ++++++ dualx11.cc | 79 ++++++++++++++++++++++++++ dualx11.hh | 27 +++++++++ fit | 1 + graphics.cc | 112 +++++++++++++++++++++++++++++++++++++ graphics.hh | 40 +++++++++++++ ins | 8 +++ library.cc | 50 +++++++++++++++++ library.hh | 72 ++++++++++++++++++++++++ main.cc | 152 ++++++++++++++++++++++++++++++++++++++++++++++++++ main.cc% | 19 +++++++ moebius.cc | 76 +++++++++++++++++++++++++ moebius.hh | 56 +++++++++++++++++++ output.hh | 17 ++++++ parameter.cc | 27 +++++++++ parameter.hh | 53 ++++++++++++++++++ postscript.cc | 47 ++++++++++++++++ postscript.hh | 17 ++++++ transforms.cc | 81 +++++++++++++++++++++++++++ transforms.hh | 91 ++++++++++++++++++++++++++++++ x11.cc | 46 +++++++++++++++ x11.hh | 26 +++++++++ 23 files changed, 1125 insertions(+) create mode 100644 .depend create mode 100644 Makefile create mode 100644 dualx11.cc create mode 100644 dualx11.hh create mode 100644 fit create mode 100644 graphics.cc create mode 100644 graphics.hh create mode 100644 ins create mode 100644 library.cc create mode 100644 library.hh create mode 100644 main.cc create mode 100644 main.cc% create mode 100644 moebius.cc create mode 100644 moebius.hh create mode 100644 output.hh create mode 100644 parameter.cc create mode 100644 parameter.hh create mode 100644 postscript.cc create mode 100644 postscript.hh create mode 100644 transforms.cc create mode 100644 transforms.hh create mode 100644 x11.cc create mode 100644 x11.hh diff --git a/.depend b/.depend new file mode 100644 index 0000000..bda22ed --- /dev/null +++ b/.depend @@ -0,0 +1,10 @@ +dualx11.o : dualx11.cc dualx11.hh output.hh library.hh parameter.hh +graphics.o : graphics.cc library.hh graphics.hh output.hh +library.o : library.cc library.hh transforms.hh +main.o : main.cc output.hh library.hh x11.hh dualx11.hh postscript.hh moebius.hh \ + transforms.hh graphics.hh parameter.hh +moebius.o : moebius.cc library.hh moebius.hh +parameter.o : parameter.cc parameter.hh +postscript.o : postscript.cc postscript.hh output.hh library.hh +transforms.o : transforms.cc transforms.hh library.hh +x11.o : x11.cc x11.hh output.hh library.hh diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..80111df --- /dev/null +++ b/Makefile @@ -0,0 +1,18 @@ +C++FLAGS= -Wall -O2 +CPPFLAGS= -I/usr/include +LDFLAGS= +LIBS= + +OBJS= dualx11.o x11.o main.o parameter.o graphics.o library.o \ + transforms.o postscript.o moebius.o + +a.out: $(OBJS) + $(LINK.cc) -o a.out $(OBJS) -lm -L/usr/X11R6/lib -lX11 -lg++ + +depend: + $(C++) $(CPPFLAGS) -E -MM *.cc >.depend + +clean: + rm -f $(OBJS) a.out + +include .depend diff --git a/dualx11.cc b/dualx11.cc new file mode 100644 index 0000000..4bfc39c --- /dev/null +++ b/dualx11.cc @@ -0,0 +1,79 @@ +/* + * X11 functions + */ + +#include "dualx11.hh" +#include "parameter.hh" + +DualX11Output::DualX11Output() { + display= XOpenDisplay(0); + Colormap cmap= DefaultColormap(display,DefaultScreen(display)); + + XAllocColorCells(display,cmap, + False, // contig + planemasks, + 2, // nplanes + &pixelbase, + 1); // ncolors + XColor colours[4], *cp= colours; + for (int i=0; i<2; i++) + for (int j=0; j<2; j++, cp++) { + cp->pixel= pixelbase + (i? planemasks[0] :0) + (j? planemasks[1] :0); + cp->red= i?65535:0; cp->green= j?/*65535*/32000:0; cp->blue= 0; + cp->flags= DoRed|DoGreen|DoBlue; + } + XStoreColors(display,cmap,colours,4); + + window= XCreateSimpleWindow(display, + DefaultRootWindow(display), + 0,0, 500,500, 0,0, pixelbase); + + XGCValues gcvalues; + for (i=0; i<2; i++) { + gcvalues.plane_mask= planemasks[i]; + // First, the fabric + gcvalues.function= GXclear; + fabric[i]= XCreateGC(display,window, + GCFunction|GCPlaneMask, + &gcvalues); + // Then, the mesh + gcvalues.function= GXset; + mesh[i]= XCreateGC(display,window, + GCFunction|GCPlaneMask, + &gcvalues); + } + XSelectInput(display,window,0); + XMapWindow(display,window); + XFlush(display); +} + +void DualX11Output::startimage() { + XClearWindow(display,window); +} + +void DualX11Output::endimage() { + XFlush(display); +} + +DualX11Output::~DualX11Output() { + XCloseDisplay(display); +} + +void DualX11Output::drawcell(const Point* list, int n) { + static Parameter eyeseparation("eyesep", + "Distance from projection eye to origin", + 0.3, .1, 0., 100.); + for (int i=0; i<2; i++) { + Point::seteyex(eyeseparation*(i-0.5)); + XPoint xp[n+1]; + for (int j=0; j +#include + +#include "output.hh" + +struct DualX11Output : Output { + DualX11Output(); + ~DualX11Output(); + void drawcell(const Point*, int); + void startimage(); + void endimage(); +private: + Display *display; + Window window; + GC fabric[2]; + GC mesh[2]; + unsigned long planemasks[2], pixelbase; +}; + +#endif diff --git a/fit b/fit new file mode 100644 index 0000000..f7bd11a --- /dev/null +++ b/fit @@ -0,0 +1 @@ +epsffit -c -s 50 450 550 750 t diff --git a/graphics.cc b/graphics.cc new file mode 100644 index 0000000..5fdfb25 --- /dev/null +++ b/graphics.cc @@ -0,0 +1,112 @@ +/* + * Graphics library + */ + +#include + +#include +#include +#include +#include + +#include "library.hh" +#include "graphics.hh" +#include "output.hh" + +static int checkneededline(Onscreen a, Onscreen b) { + double xd= a.x - b.x; + double yd= a.y - b.y; + int n= (int)ceil(sqrt(xd*xd+yd*yd)*100.0); + return n>0 ? n : 1; +} + +void Cell::display(Output& o) { + int nn[4]; + int totalnn= 0; + for (int i=0; i<4; i++) { + nn[i]= checkneededline(p[i],p[(i+1)&3]); + totalnn+= nn[i]; + } + Point *array= new Point[totalnn]; + Point *inarrayp= array; + for (i=0; i<4; i++) { + for (int a=0; aindex(); + for (int fragment= used-1; + fragment >= 0 && index < fragments[fragment]->entries[0].index; + fragment--); + if (fragment < 0) { + Fragment *nf= insertfragment(0); + nf->used= 1; + nf->entries[0].index= index; + nf->entries[0].cell= it; + return; + } + for (int entry= 0; + entry < fragments[fragment]->used && + index > fragments[fragment]->entries[entry].index; + entry++); + if (fragments[fragment]->used >= fragmentsize) { + Fragment *nf= insertfragment(fragment+1); + nf->used= fragmentsize>>1; + fragments[fragment]->used -= nf->used; + memcpy(nf->entries, + fragments[fragment]->entries + fragments[fragment]->used, + nf->used*sizeof(Entry)); + if (entry >= fragments[fragment]->used) { + entry-= fragments[fragment]->used; + fragment++; + } + } + memmove(fragments[fragment]->entries + entry+1, + fragments[fragment]->entries + entry, + sizeof(Entry) * (fragments[fragment]->used - entry)); + fragments[fragment]->entries[entry].index= index; + fragments[fragment]->entries[entry].cell= it; + fragments[fragment]->used++; +} + +SortedCellList::~SortedCellList() { + for (int fragment=0; fragmentused; entry++) { + delete fragments[fragment]->entries[entry].cell; + } + delete fragments[fragment]; + } + free(fragments); +} + +void SortedCellList::display(Output& o) { + o.startimage(); + for (int fragment=0; fragmentused; entry++) { + if (Point::indexvisible(fragments[fragment]->entries[entry].index)) { + fragments[fragment]->entries[entry].cell->display(o); + } + } + } + o.endimage(); +} diff --git a/graphics.hh b/graphics.hh new file mode 100644 index 0000000..bf7c3d2 --- /dev/null +++ b/graphics.hh @@ -0,0 +1,40 @@ +/* + * Graphics library + */ + +#ifndef GRAPHICS_HH +#define GRAPHICS_HH + +#include "library.hh" +#include "output.hh" + +class Cell { + void display(Output& o); + friend class SortedCellList; +public: + Point p[4]; + double index() { return p[0].index(); } +}; + +#define fragmentsize 10 +class SortedCellList { + struct Entry { + double index; + Cell *cell; + }; + struct Fragment { + int used; + Entry entries[fragmentsize]; + }; + Fragment **fragments; + int size,used; + + Fragment *insertfragment(int at); +public: + SortedCellList() { fragments=0; size=used=0; } + ~SortedCellList(); + void insert(Cell*); + void display(Output& o); +}; + +#endif diff --git a/ins b/ins new file mode 100644 index 0000000..70ba461 --- /dev/null +++ b/ins @@ -0,0 +1,8 @@ +tear=1 +twist=-1 +theta=1.57 +bulge=1.5 +sheary=3 +un=20 +tn=35 +x11 diff --git a/library.cc b/library.cc new file mode 100644 index 0000000..60f8446 --- /dev/null +++ b/library.cc @@ -0,0 +1,50 @@ +/* + * Points library + */ + +#include + +#include "library.hh" +#include "transforms.hh" + +double Point::planedistance= 1.0; +double Point::eyedistance= 1.0; +double Point::cutoffdistance= 10.0; +double Point::eyex= 0.0; + +TransformList Point::usertransforms; +TransformList Point::povtransform; + +Point TransformList::operator()(Point it) { + for (int i=0; i= size) { + size+=5; size<<=1; + a= (Transform**)realloc(a,sizeof(Transform*)*size); + if (!a) { perror("realloc"); exit(1); } + } + a[used++]= it; +} + +void TransformList::clearcontents() { + for (int i=0; i + +/* + * Coordinate system: + * + * Y | + * | + * | + * /-------- X + * / + * / + * Z (coming out of the monitor) + */ + +struct Onscreen { + double x, y; + Onscreen(){}; + Onscreen(double ix, double iy) { x=ix; y=iy; } +}; + +class Point; + +class Transform { +public: + virtual Point operator()(Point)= 0; +}; + +class TransformList { + Transform **a; + int size,used; + void clearcontents(); + public: + TransformList() { size=used=0; a=0; } + ~TransformList() { clearcontents(); free(a); } + void reset() { clearcontents(); used=0; } + Point operator()(Point); + void append(Transform*); +}; + +class Point { + static TransformList usertransforms; + static TransformList povtransform; + static double planedistance, eyedistance, cutoffdistance, eyex; + double xyz[3]; +public: + Point(){} + Point(double x, double y, double z) { xyz[0]=x; xyz[1]=y; xyz[2]=z; } + Point operator+(Point r) { return Point(xyz[0]+r[0], xyz[1]+r[1], xyz[2]+r[2]); } + Point operator*(double f) { return Point(xyz[0]*f, xyz[1]*f, xyz[2]*f); } + double& operator[](int i) { return xyz[i]; } + + operator Onscreen() const; + Point transformed() const { return povtransform(usertransforms(*this)); } + double index() const { return transformed()[2]; } + + static int indexvisible(double index) { return index < cutoffdistance; } + static void appendtransform(Transform *t) { usertransforms.append(t); } + static void cleartransform() { usertransforms.reset(); } + static void setobserver(double theta, double eta=0.0, + double planedist=1.0, double eyedist=1.0, + double cutoff=10.0); + static void seteyex(double n) { eyex=n; } +}; + +#endif diff --git a/main.cc b/main.cc new file mode 100644 index 0000000..7007194 --- /dev/null +++ b/main.cc @@ -0,0 +1,152 @@ +/* + * Moebius main program. + */ + +#include +#include +#include +#include +#include + +#include "output.hh" +#include "x11.hh" +#include "dualx11.hh" +#include "postscript.hh" +#include "library.hh" +#include "moebius.hh" +#include "transforms.hh" +#include "graphics.hh" +#include "parameter.hh" + +Parameter tn("tn", "Number of sections around `strip'", 30, 1, 1, 500); +Parameter un("un", "Number of sections across `strip'", 15, 1, 1, 500); +Parameter theta("theta", "Angle of model rotation", + /*-PI/2.*/0, PI/8., -PI*2., PI*2.); +Parameter eta("eta", "Angle of model elevation", 0., PI/8., -PI*2., PI*2.); +Parameter planedistance("plane", "Distance from projection plane to origin", + 4., .25, 0., 100.); +Parameter eyedistance("eye", "Distance from projection eye to origin", + 1.5, .25, 0., 100.); +Parameter cutoffdistance("cutoff", "Distance from projection cutoff to origin", + 10., .25, -10., 100.); +Parameter width("width", "Width of the `strip' before transformation", + .4, .1, 0., 1.); +Parameter thickness("thick", "Thickness of the `pancake'", 1., .1, 0., 1.); +Parameter bottomportion("bp", "Proportion in the bottom half", + .7, .1, 0., 1.); +//Parameter tear("tear", "Angle factor in tear-open", 0/*1.1*/, .1, -5., 5.); +//Parameter teary("teary", "Axis y coord in tear-open", 1.3, .1, -10., 10.); +//Parameter twist("twist", "Angle per length in twist", 0/*.8*/, .25, -5., 5.); +//Parameter twisty("twisty", "Axis y coord in twist", .85, .1, -10., 10.); +//Parameter bulge("bulge", "Amount of bulge", 0/*1.*/, .25, -15., 15.); +//Parameter bulgesd("bulgesd", "S.D. of bulge", 1., .2, .000001, 20.); +//Parameter bulgey("bulgey", "Axis y coord in bulge", .85, .1, -10., 10.); +//Parameter shearx("shearx", "Amount of shear (x)", 0., .1, -15., 15.); +//Parameter sheary("sheary", "Amount of shear (y)", 0/*1.*/, .1, -15., 15.); +//Parameter shearsdx("shearsdx", "S.D. of shear (x)", .5, .1, -15., 15.); +//Parameter shearsdy("shearsdy", "S.D. of shear (y)", .5, .1, -15., 15.); +//Parameter shearey("shearey", "Centre of shear (y)", 1.3, .1, -10., 10.); + +SortedCellList *list=0; +X11Output *x11= 0; +DualX11Output *dualx11= 0; + +void generate() { + if (list) delete list; + // MoebiusStrip strip(width); + MoebiusEnfoldment strip(thickness,bottomportion); + list= new SortedCellList; + double t0= 0.0; + for (int ti=0; tip[0]= strip.middlepoint(t0,u0); +//fprintf(stderr,"t %7.4f u %7.4f %7.4f,%7.4f,%7.4f\n", +// t0,u0, cell->p[0][0], cell->p[0][1], cell->p[0][2]); + cell->p[1]= strip.middlepoint(t0,u1); + cell->p[2]= strip.middlepoint(t1,u1); + cell->p[3]= strip.middlepoint(t1,u0); + list->insert(cell); + u0= u1; + } + t0= t1; + } +} + +int main(int argc, char **argv) { + char buf[100]; + + for (;;) { + Point::setobserver(theta,eta,planedistance,eyedistance,cutoffdistance); + Point::cleartransform(); +// if (tear != 0.0) Point::appendtransform(new TearOpenTransform(tear,teary)); +// if (twist != 0.0) Point::appendtransform(new TwistTransform(twist,twisty)); +// if (bulge != 0.0) Point::appendtransform(new BulgeTransform(bulge,bulgesd,bulgey)); +// if (shearx != 0.0 || sheary != 0.0) +// Point::appendtransform(new ShearTransform(Point(0.0,shearey,0.0), +// Point(shearx,sheary,0.0), +// Point(shearsdx,shearsdy,1e20))); + generate(); + if (x11) list->display(*x11); + if (dualx11) list->display(*dualx11); + for (;;) { + cin.get(buf,100,'\n'); + char c; + if (!cin.get(c) || c!='\n') { + cerr << "error reading command input, giving up\n"; + exit(1); + } + char *equals= strchr(buf,'='); + if (equals) { + *equals++= 0; + AnyParameter *param= AnyParameter::find(buf); + if (param) { + *param= atof(equals); + break; + } else { + cerr << "parameter `" << buf << "' not found\n"; + } + } else if (!strncmp(buf,"postscript ",11)) { + const char *filename= buf+11; + ofstream file(filename); + if (file) { + PostScriptOutput psout(file); + list->display(psout); + } else { + cerr << "Failed to open `" << filename << "'\n"; + continue; + } + cerr << "PostScript written to `" << filename <<"'\n"; + } else if (!strcmp(buf,"x11")) { + if (x11) { + delete x11; + x11= 0; + } else { + x11= new X11Output; + } + break; + } else if (!strcmp(buf,"dualx11")) { + if (dualx11) { + delete dualx11; + dualx11= 0; + } else { + dualx11= new DualX11Output; + } + break; + } else if (!strcmp(buf,"quit")) { + exit(0); + } else if (!strcmp(buf,"list")) { + AnyParameter::list(); + } else if (!*buf) { + break; + } else { + cerr << "command not understood\n"; + } + } + } +} + diff --git a/main.cc% b/main.cc% new file mode 100644 index 0000000..8324362 --- /dev/null +++ b/main.cc% @@ -0,0 +1,19 @@ +/* + * Moebius main program. + */ + +#include + +#include "output.hh" +#include "library.hh" +#include "graphics.hh" +#include "moebius.hh" + +Moebius strip; +PostScriptOutput output; + +int main() { + for (double t=-PI*2.0; t<= PI*2.0; t+=0.1) { + output.drawedgeline(strip.edgepoint(t), strip.edgepoint(t+0.1)); + } +} diff --git a/moebius.cc b/moebius.cc new file mode 100644 index 0000000..d68f4af --- /dev/null +++ b/moebius.cc @@ -0,0 +1,76 @@ +/* + * Equation for a Moebius strip + */ + +#include +#include + +#include "library.hh" +#include "moebius.hh" + +Point MoebiusStrip::edgepoint(double t) { + double theta= (t-0.5)*4.0*PI; + double r= 1.0 - halfgap*(1.0 - sin(theta/2.0)); + return Point(r*sin(theta), + -r*cos(theta), + halfbreadth*cos(theta/2.0)); +} + +Point MoebiusStrip::middlepoint(double t, double u) { + return edgepoint(t*0.5)*u + edgepoint((t+1)*0.5)*(1.0-u); +} + +class Bezier { + double e,f,g,h; +public: + Bezier(double x0, double x1, double dx0, double dx1); + double operator()(double t) { return h + t*(g + t*(f + t*e)); } + void debug(); +}; + +Bezier::Bezier(double x0, double x1, double dx0, double dx1) { +// e= 2*x0 - 2*x1 + dx0 + dx1; +// f= x1 - dx0 - x0 - e; + h= x0; + g= dx0; + e= g + 2*h + dx1 - 2*x1; + f= x1 - e - g - h; +} + +void Bezier::debug() { + fprintf(stderr,"bz e %7.4f f %7.4f g %7.4f h %7.4f\n",e,f,g,h); +} + +// The first end is at [sin(theta/2),-cos(theta/2),0] +// The second end is at [-theta/pi,0,sin(theta)] +// The first end is oriented towards [0,cos(theta),sin(theta)] +// The second end is oriented towards [0,-1,0] + +Point MoebiusEnfoldment::edgepoint(double t) { + double theta= t*2.0*PI; + return Point(sin(theta),cos(theta),0); +} + +Point MoebiusEnfoldment::middlepoint(double t, double u) { + if (t > bottomportion) { + t -= bottomportion; + t /= (1.0 - bottomportion); + double sizehere= sqrt(1-t*t); + return Point((u*2.0-1.0) * sizehere, + t, + sizehere * thickness * sin(u*2.0*PI)); + } else { + t /= bottomportion; + double theta= (.5-u)*2*PI; + Bezier bx(sin(theta*.5), -theta/PI, 0, 0); + double ypushiness= (1-cos(theta))*2.5+1; +// double fudge= (PI*sin(theta*.5)*cos(theta*.5))*(.5-u)*(.5-u)*4; + double fudge= (.5-u)*(.5-u)*4*cos(theta*.5); + Bezier by(-cos(theta*.5), 0, + cos(theta)*ypushiness + fudge*ypushiness, + ypushiness); +//by.debug(); + Bezier bz(0, sin(theta), sin(theta), 0); + return Point( bx(t), by(t), thickness * bz(t) ); + } +} diff --git a/moebius.hh b/moebius.hh new file mode 100644 index 0000000..e834d3b --- /dev/null +++ b/moebius.hh @@ -0,0 +1,56 @@ +/* + * Moebius strip + */ + +#ifndef MOEBIUS_HH +#define MOEBIUS_HH + +class Surface { +public: + // t and u vary from 0 to 1.0 + virtual Point middlepoint(double t, double u) =0; +}; + +class Edge { +public: + // t varies from 0 to 1.0 + virtual Point edgepoint(double t) =0; +}; + +class Moebius : public Surface, Edge { +public: + virtual Point edgepoint(double t) =0; + virtual Point middlepoint(double t, double u) =0; +}; + +class MoebiusStrip : public Moebius { + // Strip is `lying' in the XY plane. The crossing is at the + // maximal Y value, where the edge which has X*Z positive + // has smaller Y at the point where X=Z=0 than the `other' edge, + // which has X*Z negative. The flat part of the strip + // is at minimal Y value. Here one edge has Z positive and + // the other Z negative. + // X and Y range from -1.0 to 1.0; + // Z ranges from -halfbreadth to +halfbreadth. + double halfgap; // 1/2 the width of the strip at the crossing point + double halfbreadth; // 1/2 the width of the strip at the flat part +public: + MoebiusStrip() { halfgap= 0.15; halfbreadth= 0.15; } + MoebiusStrip(double b) { halfgap= halfbreadth= b/2.0; } + MoebiusStrip(double hg, double hb) { halfgap= hg/2.0; halfbreadth= hb/2.0; } + + Point edgepoint(double t); + Point middlepoint(double t, double u); +}; + +class MoebiusEnfoldment : public Moebius { + double thickness; + double bottomportion; +public: + MoebiusEnfoldment(double t=.35, double bp=.5) { thickness= t; bottomportion= bp; } + + Point edgepoint(double t); + Point middlepoint(double t, double u); +}; + +#endif diff --git a/output.hh b/output.hh new file mode 100644 index 0000000..92cc33b --- /dev/null +++ b/output.hh @@ -0,0 +1,17 @@ +/* + * Output functions + */ + +#ifndef OUTPUT_HH +#define OUTPUT_HH + +#include "library.hh" + +struct Output { + virtual ~Output(){}; + virtual void drawcell(const Point*, int) =0; + virtual void startimage(){}; + virtual void endimage(){}; +}; + +#endif diff --git a/parameter.cc b/parameter.cc new file mode 100644 index 0000000..0eb6df6 --- /dev/null +++ b/parameter.cc @@ -0,0 +1,27 @@ +/* + * Parameters library + */ + +#include "parameter.hh" + +AnyParameter::AnyParameter(const char *n, const char *d) { + name= n; description= d; + next= first; + first= this; +} + +AnyParameter* AnyParameter::find(const char *n) { + for (AnyParameter* search= first; + search && strcmp(search->name,n); + search= search->next); + return search; +} + +void AnyParameter::list() { + for (AnyParameter* search= first; + search; + search= search->next) + search->rangecheck(); +} + +AnyParameter* AnyParameter::first= 0; diff --git a/parameter.hh b/parameter.hh new file mode 100644 index 0000000..07b0137 --- /dev/null +++ b/parameter.hh @@ -0,0 +1,53 @@ +/* + * Parameters library + */ + +#ifndef PARAMETER_HH +#define PARAMETER_HH + +#include + +class AnyParameter { + AnyParameter *next; + static AnyParameter *first; +protected: + const char *name; + const char *description; + virtual void rangecheck() =0; +public: + AnyParameter(const char *n, const char *d); + virtual void operator ++() =0; + virtual void operator --() =0; + virtual void operator =(double) =0; + static AnyParameter *find(const char *n); + static void list(); +}; + +template class Parameter : AnyParameter { + T value, delta, min, max; + void rangecheck(); +public: + Parameter(const char *n, const char *d, T i, T de, T mi, T ma); + operator T (){ return value; } + void operator ++(){ value+= delta; rangecheck(); } + void operator --(){ value-= delta; rangecheck(); } + void operator =(double v) { value= (T)v; rangecheck(); } +}; + +template Parameter::Parameter + (const char *n, const char *d, T i, T de, T mi, T ma) +: AnyParameter(n,d) { + value=i; delta=de; min=mi; max=ma; +} + +template void Parameter::rangecheck() { + cerr << name << " "; + if (valuemax) { + value= max; cerr << "overflowed; "; + } + cerr << "set to " << value << "\n"; +} + +#endif diff --git a/postscript.cc b/postscript.cc new file mode 100644 index 0000000..3fbe4e7 --- /dev/null +++ b/postscript.cc @@ -0,0 +1,47 @@ +/* + * PostScript output + */ + +#include +#include "postscript.hh" + +PostScriptOutput::PostScriptOutput(ofstream& f) +: file(f) { + + file << + "%!PS-Adobe-2.0 EPSF-2.0\n" + "%%Creator: moebius\n" + "%%BoundingBox: -500 -500 500 500\n" + "%%Pages: 1\n" + "%%DocumentFonts: \n" + "%%EndComments\n" + " 1 setlinecap 1 setlinejoin 0.002 setlinewidth\n" + " 500 500 scale\n" + "%%EndProlog\n" + "%%Page: 1 0\n" + " save\n"; +} + +PostScriptOutput::~PostScriptOutput() { + file << + " restore\n" + "%%Trailer\n" + "%%EOF\n"; +} + +void PostScriptOutput::drawcell(const Point* list, int n) { + Onscreen p[4]; + for (int i=0; i<4; i++) p[i]= Onscreen(list[i]); + docell(p,n,"1 setgray fill"); + docell(p,n,"0 setgray stroke"); +} + +void PostScriptOutput::docell(const Onscreen* list, int n, const char *what) { + file << " newpath\n"; + file << " " << list->x << " " << list->y << " moveto\n"; + list++; + for (int i=1; ix << " " << list->y << " lineto\n"; + } + file << " closepath " << what << "\n"; +} diff --git a/postscript.hh b/postscript.hh new file mode 100644 index 0000000..d385513 --- /dev/null +++ b/postscript.hh @@ -0,0 +1,17 @@ +/* + * PostScript output + */ + +#include + +#include "output.hh" + +struct PostScriptOutput : Output { + PostScriptOutput(ofstream&); + ~PostScriptOutput(); + void drawcell(const Point*, int); +private: + ofstream& file; + void docell(const Onscreen*, int, const char* what); + void preamble(); +}; diff --git a/transforms.cc b/transforms.cc new file mode 100644 index 0000000..d5b6cd6 --- /dev/null +++ b/transforms.cc @@ -0,0 +1,81 @@ +/* + * Transformations + */ + +#include +#include + +#include "transforms.hh" + +RotationTransform::RotationTransform(double theta) { + s= sin(theta); c= cos(theta); +} + +Point XZRotationTransform::operator()(Point in) { + return Point(in[0]*c + in[2]*s, + in[1], + in[2]*c - in[0]*s); +} + +Point YZRotationTransform::operator()(Point in) { + return Point(in[0], + in[1]*c + in[2]*s, + in[2]*c - in[1]*s); +} + +TearOpenTransform::TearOpenTransform(double amt, double apy) { + factor= pow(10.0,amt); + apexy= apy; +} + +Point TearOpenTransform::operator()(Point in) { + double w= apexy - in[1]; + double r= sqrt(in[2]*in[2] + w*w); + double theta= r>0.0 ? factor*atan2(in[2],w) : 0.0; + double ny= apexy - r*cos(theta); + double nz= r*sin(theta); + return Point(in[0],ny,nz); +} + +BulgeTransform::BulgeTransform(double amt, double stddev, double apy) { + amount=amt; apexy=apy; + variance= stddev*stddev; +} + +Point BulgeTransform::operator()(Point in) { + double w= in[1] - apexy; + double r2= w*w + in[2]*in[2]; + double nror= 1.0 + amount*exp(-r2/variance); + double ny= w*nror + apexy; + return Point(in[0],ny,in[2]); +} + +Point ShearTransform::operator()(Point in) { + double dx= (in[0] - epicentre[0]) / deviation[0]; + double dy= (in[1] - epicentre[1]) / deviation[1]; + double dz= (in[2] - epicentre[2]) / deviation[2]; + double r2= dx*dx + dy*dy + dz*dz; + double amount= exp(-r2); + return in + magnitude*amount; +} + +Point TwistTransform::operator()(Point in) { + double w= in[1] - apexy; + double theta= factor*in[2]; + double c= cos(theta), s= sin(theta); + double nx= in[0]*c - w*s; + double ny= w*c + in[0]*s + apexy; + return Point(nx,ny,in[2]); +} + +Point MagicTransform::operator()(Point in) { + double nz= in[2]*zfactor; + double r= sqrt(in[0]*in[0] + in[1]*in[1]); + double nx= xfactor * (r - xkonstant); + double nr= yoffset + yfactor*in[1]; + double ny2= nr*nr- nz*nz; +//fprintf(stderr,"M %7.4f,%7.4f,%7.4f r=%7.4f nx=%7.4f nz=%7.4f nr=%7.4f ny2=%7.4f\n", +// in[0],in[1],in[2], r,nx,nz,nr,ny2); + double ny= sqrt(ny2); + return Point(nx,ny,nz); +} diff --git a/transforms.hh b/transforms.hh new file mode 100644 index 0000000..e398d27 --- /dev/null +++ b/transforms.hh @@ -0,0 +1,91 @@ +/* + * Transformations + */ + +#ifndef TRANSFORMS_HH +#define TRANSFORMS_HH + +#include "library.hh" + +class RotationTransform: public Transform { +protected: + double s,c; +public: + RotationTransform(double theta); +}; + +class XZRotationTransform : public RotationTransform { + /* + * Y | + * | <\ (positive theta) + * | / + * /-------- X + * / + * Z / \---> + */ +public: + XZRotationTransform(double theta) : RotationTransform(theta) { } + Point operator()(Point); +}; + +class YZRotationTransform : public RotationTransform { + /* + * Y | _ + * |/ \ (positive theta) + * ^ | V + * | /-------- X + * \/ + * Z / + */ +public: + YZRotationTransform(double theta) : RotationTransform(theta) { } + Point operator()(Point); +}; + +class TearOpenTransform : public Transform { + double factor; + double apexy; +public: + TearOpenTransform(double amt, double apy=1.3); + Point operator()(Point in); +}; + +class BulgeTransform : public Transform { + double amount; + double variance; + double apexy; +public: + BulgeTransform(double amt, double stddev, double apy=1.1); + Point operator()(Point in); +}; + +class TwistTransform : public Transform { + double factor; + double apexy; +public: + TwistTransform(double amt, double apy=1.2) { factor=amt; apexy=apy; } + Point operator()(Point in); +}; + +class ShearTransform : public Transform { + Point epicentre; + Point magnitude; + Point deviation; +public: + ShearTransform(Point ec, Point mag, Point dev) { + epicentre=ec; magnitude=mag; deviation=dev; + } + Point operator()(Point in); +}; + +class MagicTransform : public Transform { + double xkonstant, xfactor, yoffset, yfactor, zfactor; +public: + MagicTransform(double xk, double xf, double zf, + double yfudge=0.25, double yo=0.5, double yf=-0.5) { + xkonstant=xk; xfactor=xf; yoffset=yo+yfudge; yfactor=yf; zfactor=zf; + } + Point operator()(Point in); +}; + +#endif diff --git a/x11.cc b/x11.cc new file mode 100644 index 0000000..b724594 --- /dev/null +++ b/x11.cc @@ -0,0 +1,46 @@ +/* + * X11 functions + */ + + +#include "x11.hh" + +X11Output::X11Output() { + XGCValues gcvalues; + display= XOpenDisplay(0); + window= XCreateSimpleWindow(display, + DefaultRootWindow(display), + 0,0, 500,500, 0,0,0); + gcvalues.background= 0; + fabric= XCreateGC(display,window,GCBackground,&gcvalues); + gcvalues.foreground= 1; + gcvalues.background= 1; + mesh= XCreateGC(display,window,GCForeground|GCBackground,&gcvalues); + XSelectInput(display,window,0); + XMapWindow(display,window); + XFlush(display); +} + +void X11Output::startimage() { + XClearWindow(display,window); +} + +void X11Output::endimage() { + XFlush(display); +} + +X11Output::~X11Output() { + XCloseDisplay(display); +} + +void X11Output::drawcell(const Point* list, int n) { + XPoint xp[n+1]; + for (int i=0; i +#include + +#include "output.hh" + +struct X11Output : Output { + X11Output(); + ~X11Output(); + void drawcell(const Point*, int); + void startimage(); + void endimage(); +private: + Display *display; + Window window; + GC fabric; + GC mesh; +}; + +#endif -- 2.30.2