home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / IDIOMS.ZIP / APPA.C < prev    next >
C/C++ Source or Header  |  1991-12-04  |  16KB  |  530 lines

  1. /* Copyright (c) 1992 by AT&T Bell Laboratories. */
  2. /* Advanced C++ Programming Styles and Idioms */
  3. /* James O. Coplien */
  4. /* All rights reserved. */
  5.  
  6. #include <math.h>
  7. // #include <X11/X.h>
  8.  
  9. typedef long Display, Window, GContext;
  10.  
  11. /*
  12.  * File Shapes.h
  13.  * Author:  J. O. Coplien
  14.  *
  15.  * This header file contains declarations for classes used in
  16.  * a demonstration Shape library.  Many member functions are
  17.  * defined herein as inlines.
  18.  */
  19.  
  20. /*-----------------------------------------------------------*/
  21. /* class Angle is an angle in degrees or radians.  It is a   */
  22. /* class so that it can be easily ported to systems using    */
  23. /* either degrees or radians, and also so arithmetic         */
  24. /* precision(float, double, or int) can be changed.          */
  25. /*-----------------------------------------------------------*/
  26.  
  27. class Angle {
  28. friend double cos(Angle);
  29. friend double sin(Angle);
  30. public:
  31.     Angle(double d)       { radians = d; }
  32.     Angle ()              { radians = 0; }
  33.     Angle(const Angle& a) { radians = a.radians; }
  34.     inline Angle &operator=(const Angle& a) {
  35.         radians = a.radians;
  36.         return *this;
  37.     }
  38.     Angle operator+(const Angle&) const;
  39. private:
  40.     double    radians;
  41. };
  42.  
  43. /*-----------------------------------------------------------*/
  44. /* class Coordinate describes a point on the Cartesian plane.*/
  45. /*   It can be in micrometers, pixels, inches, or any other  */
  46. /* convenient units and scale.                               */
  47. /*-----------------------------------------------------------*/
  48.  
  49. class Coordinate {
  50. public:
  51.     inline long x() const       { return x_rep; }
  52.     inline long y() const       { return y_rep; }
  53.     Coordinate    &operator=(Coordinate &c) {
  54.         x_rep = c.x_rep;
  55.         y_rep = c.y_rep;
  56.         return *this;
  57.     }
  58.     Coordinate(long x, long y) {
  59.         x_rep = x; y_rep = y;
  60.     }
  61.     Coordinate(const Coordinate &c) {
  62.         x_rep = c.x_rep;
  63.         y_rep = c.y_rep;
  64.     }
  65.     Coordinate()        { x_rep = y_rep = 0;}
  66.     ~Coordinate()       { }
  67.  
  68.     void rotateAbout(Coordinate,Angle);
  69. private:
  70.     long x_rep, y_rep;
  71. };
  72.  
  73.  
  74. /*-----------------------------------------------------------*/
  75. /* These functions overload the normal trig functions,       */
  76. /* arranging so that they can be called with Angle as an     */
  77. /* argument.  Since overloading cannot be done on the basis  */
  78. /* of return value--only on the basis of argument            */
  79. /* type--the trig function atan, which needs to be able      */
  80. /* to return an object of type Angle, cannot be overloaded   */
  81. /* and must be made a whole new function.                    */
  82. /*-----------------------------------------------------------*/
  83.  
  84. inline double cos(Angle a)      { return ::cos(a.radians); }
  85. inline double sin(Angle a)      { return ::sin(a.radians); }
  86. inline Angle Angleatan(double t) {
  87.     Angle a(::atan(t)); return a;
  88. }
  89.  
  90. /*-----------------------------------------------------------*/
  91. /* Class Color encapsulated the implementation of color      */
  92. /* encoding for the graphics package being used; its         */
  93. /* internals can be accessed just by low-level interface     */
  94. /* routines, while high-level routines deal at a more general*/
  95. /* level.  This makes porting possible across a wide variety */
  96. /* of machines.                                              */
  97. /* Flashing is an attribute of color.  The commonly used     */
  98. /* constants Black and White are predeclared as constant     */
  99. /* global color objects.                                     */
  100. /*-----------------------------------------------------------*/
  101.  
  102. enum Flash { FlashBlack, FlashWhite, FlashOff };
  103.  
  104. class Color {
  105. public:
  106.     inline    double    red()         { return red_rep;  }
  107.     inline    double    green()       { return green_rep;  }
  108.     inline    double    blue()        { return blue_rep;  }
  109.             Color(double r=0.0, double g=0.0,
  110.                   double b=0.0, Flash f=FlashOff) {
  111.         red_rep = r;
  112.         green_rep = g;
  113.       blue_rep = b;
  114.         flashing = f;
  115.     }
  116.     inline    Color&    operator=(const Color& c) {
  117.         red_rep = c.red_rep;
  118.         green_rep=c.green_rep;
  119.         blue_rep = c.blue_rep;
  120.         return *this;
  121.     }
  122.             ~Color()        { }
  123. private:
  124.     double    red_rep, green_rep, blue_rep;
  125.     Flash    flashing;
  126. };
  127.  
  128. const Color Black, White = Color(1.0, 1.0, 1.0);
  129.  
  130. /*-----------------------------------------------------------*/
  131. /* Shape is the base class for all of the graphical shapes.  */
  132. /* It defines the signature (operations) possible on a shape,*/
  133. /* and also provides the actual implementation of operators  */
  134. /* common to all shapes (like move, common to all with some  */
  135. /* exceptions).                                              */
  136. /*-----------------------------------------------------------*/
  137.  
  138. class Shape { 
  139. public:
  140.     // rotate about center
  141.     virtual    void    rotate(Angle a)        { } 
  142.     virtual    void    move(Coordinate xy) {
  143.         erase(); center_val=xy; draw();
  144.     }
  145.     virtual    void    draw()  = 0;     // renderer
  146.     virtual    void    erase() {
  147.         color = Black; draw();
  148.     }
  149.  
  150.     virtual    void    redraw() {
  151.         erase(); draw();
  152.     }
  153.     Shape();
  154.     virtual   ~Shape();
  155.     virtual   Coordinate origin() const  { return center_val; }
  156.     virtual   Coordinate center() const  { return center_val; }
  157.     inline    Shape   *next() const   { return next_pointer; }
  158.     inline    Shape   *prev() const   { return prev_pointer; }
  159.     inline    void    insert(Shape* i) {
  160.         i->next_pointer= this;
  161.         i->prev_pointer=prev_pointer;
  162.         prev_pointer->next_pointer=i;
  163.         prev_pointer = i;
  164.     }
  165.     inline    void    append(Shape* i)    {
  166.                           i->next_pointer=next();
  167.                           i->prev_pointer = this;
  168.                           next_pointer->prev_pointer=i;
  169.                           next_pointer = i;
  170.                         }
  171. protected:
  172.  
  173.     /*
  174.      * These are protected instead of private so they can be
  175.      * accessed by routines in the derived classes
  176.      */
  177.  
  178.     Coordinate    center_val;    // nominal center
  179.     Color        color;        // shape's color
  180.  
  181.     /*
  182.      * These class static variables are used by the underlying
  183.      * window package (e.g., X) for general graphics setup.
  184.     */
  185.  
  186.     static        Display        display;
  187.     static        Window        window;
  188.     static        GContext        gc;
  189.  
  190. private:
  191.     Shape        *next_pointer;   // pointer to next in list
  192.     Shape        *prev_pointer;   // pointer to previous in list
  193. };
  194.  
  195. /*-----------------------------------------------------------*/
  196. /* Line is a special shape, since it is usually the          */
  197. /* rendering component of all other shapes. It alone among   */
  198. /* shapes has a rotateAbout member function which is used as */
  199. /* the primitive for rotating other shapes.  The rotate      */
  200. /* operation is a degenerate form of rotateAbout. The center */
  201. /* is defined as the average of the endpoints; the origin is  */
  202. /* the first endpoint.                                       */
  203. /*-----------------------------------------------------------*/
  204.  
  205. class Line : public Shape {
  206. public:
  207.     void    rotate(Angle a)    { rotateAbout(center(),a); }
  208.     void    rotateAbout(Coordinate,Angle);
  209.     void    draw();
  210.     inline Line &operator=(const Line &l) {
  211.          p=Coordinate(l.p); q=Coordinate(l.q); return *this;
  212.     }
  213.     Line(Coordinate,Coordinate);
  214.     Line(Line& l) {
  215.         p = l.p; q = l.q;
  216.         center_val = l.center_val;
  217.     }
  218.     Line()            { p = Coordinate(0,0);
  219.                       q = Coordinate(0,0); }
  220.    ~Line()            { erase(); }
  221.     inline  Coordinate      e() const   { return q; }
  222.     inline  Coordinate origin() const   { return p; }
  223. private:
  224.     Coordinate    p, q;            // line endpoints
  225. };
  226.  
  227. /*-----------------------------------------------------------*/
  228. /* Rect is made up of four lines. Origin is upper-left hand  */
  229. /* corner, and is established from the constructor's first   */
  230. /* parameter. Center is geometric center, as expected.  The  */
  231. /* operation erase is inherited from Shape. Reps are         */
  232. /* protected instead of private so that subclass Square can  */
  233. /*  use them.                                                */
  234. /*-----------------------------------------------------------*/
  235.  
  236. class Rect : public Shape {
  237. public:
  238.     void        rotate(Angle);
  239.     void        draw();
  240.     void        move(Coordinate);
  241.             //upper left corner, x size, y size
  242.             Rect(Coordinate,long,long);
  243.             ~Rect()            { erase(); }
  244.     inline    Coordinate    origin() const { return l1.origin(); }
  245. protected:
  246.     Line        l1, l2, l3, l4;
  247. };
  248.  
  249. /*-----------------------------------------------------------*/
  250. /* Ellipse's center is geometric center; origin is center.   */
  251. /* Ellipse is unimplemented.                                 */
  252. /*-----------------------------------------------------------*/
  253.  
  254. class Ellipse : public Shape {
  255. public:
  256.     void        rotate(Angle);
  257.     void        draw();
  258.             // center, major axis, minor axis
  259.             Ellipse(Coordinate,long,long);
  260.             ~Ellipse()        { erase(); }
  261. protected:
  262.     long        major, minor;
  263. };
  264.  
  265. /*-----------------------------------------------------------*/
  266. /* A triangle is made up of three lines.  Its center is      */
  267. /* calculated as the average of all points.                  */
  268. /*-----------------------------------------------------------*/
  269.  
  270. class Triangle : public Shape {
  271. public:
  272.     void        rotate(Angle);
  273.     void        draw();
  274.     void        move(Coordinate);
  275.             Triangle(Coordinate,Coordinate,Coordinate);
  276.             ~Triangle()        { erase(); }
  277. private:
  278.     Line        l1, l2, l3;
  279. };
  280.  
  281. /*-----------------------------------------------------------*/
  282. /* A square is just a degenerate rectangle.  All member      */
  283. /* functions are inherited from Rect; only the constructor   */
  284. /* is customized, and it does nothing but call Rect's        */
  285. /*  constructor.                                             */
  286. /*-----------------------------------------------------------*/
  287.  
  288. class Square : public Rect {
  289. public:
  290.             Square(Coordinate ctr, long x):
  291.                 Rect(ctr, x, x)         { }
  292. };
  293.  
  294. /*-----------------------------------------------------------*/
  295. /*                                                           */
  296. /* File Shapes.c, containing Shape code for example program  */
  297. /*                                                           */
  298. /*-----------------------------------------------------------*/
  299.  
  300.  
  301. extern "C" {
  302.     extern void doXInitialization(Shape&);
  303.     // extern void
  304.       // XDrawLine(Display, Window, GContext, int, int, int, int);
  305. }
  306.  
  307. /*
  308.  * CLASS ANGLE
  309.  */
  310.  
  311. Angle
  312. Angle::operator+(const Angle& angle) const {
  313.     Angle retval = angle;
  314.     retval.radians += radians;
  315.     return retval;
  316. }
  317.  
  318. /*
  319.  * CLASS COORDINATE
  320.  */
  321.  
  322. void
  323. Coordinate::rotateAbout(Coordinate pivot, Angle angle)
  324. {
  325.     long xdistance = pivot.x()-x(), ydistance = pivot.y()-y();
  326.     long xdistsquared = xdistance * xdistance,
  327.         ydistsquared = ydistance * ydistance;
  328.     double r = ::sqrt( xdistsquared + ydistsquared );
  329.     Angle newangle = angle +
  330.                 Angleatan(double(ydistance)/double(xdistance));
  331.     x_rep = pivot.x() + long(r * ::cos(newangle));
  332.     y_rep = pivot.y() + long(r * ::sin(newangle));
  333. }
  334.  
  335. /*
  336.  * CLASS SHAPE
  337.  */
  338.  
  339. /* flag for underlying graphics package */
  340.  
  341. static int X_initialized = 0;
  342.  
  343. Shape::Shape() {
  344.     center_val = Coordinate(0,0);
  345.     next_pointer=prev_pointer=0;
  346.     color = White;
  347.     if( !X_initialized) {
  348.         doXInitialization(*this);
  349.         X_initialized = 1;
  350.     }
  351. }
  352.  
  353. /*
  354.  * CLASS LINE
  355.  */
  356.  
  357. void
  358. Line::rotateAbout(Coordinate c, Angle angle) {
  359.     erase();
  360.     p.rotateAbout(c, angle);
  361.     q.rotateAbout(c, angle);
  362.     draw();
  363. }
  364.  
  365. void
  366. Line::draw() {
  367.     if (p.x()-q.x() && p.y()-q.y()) {
  368. //        XDrawLine(display, window, gc, p.x(),
  369. //                                         p.y(), q.x(), q.y());
  370.     }
  371. }
  372.  
  373. Line::Line(Coordinate p1, Coordinate p2) {
  374.     p = p1; q = p2;
  375.     center_val = Coordinate((p.x()+q.x())/2, (p.y()+q.y())/2);
  376.     color = Color(White);
  377.     draw();
  378. }
  379.  
  380. /*
  381.  * CLASS RECTANGLE
  382.  */
  383.  
  384. void
  385. Rect::rotate(Angle angle) {
  386.     erase();
  387.     l1.rotateAbout(center(), angle);
  388.     l2.rotateAbout(center(), angle);
  389.     l3.rotateAbout(center(), angle);
  390.     l4.rotateAbout(center(), angle);
  391.     draw();
  392. }
  393.  
  394. void
  395. Rect::draw() {
  396.     l1.draw();
  397.     l2.draw();
  398.     l3.draw();
  399.     l4.draw();
  400. }
  401.  
  402. void
  403. Rect::move(Coordinate c) {
  404.     /*
  405.      * Argument is center.  Move center there; find out how far
  406.      * center moved and displace all points by the same amount.
  407.      */
  408.  
  409.     erase();
  410.     long xmoved = c.x() - center().x();
  411.     long ymoved = c.y() - center().y();
  412.     center_val = c;
  413.     l1 = Line(Coordinate(l1.origin().x()+xmoved,
  414.                                       l1.origin().y()+ymoved),
  415.             Coordinate(l1.e().x()+xmoved,l1.e().y()+ymoved) );
  416.     l2 = Line(Coordinate(l2.origin().x()+xmoved,
  417.                                       l2.origin().y()+ymoved),
  418.             Coordinate(l2.e().x()+xmoved,l2.e().y()+ymoved) );
  419.     l3 = Line(Coordinate(l3.origin().x()+xmoved,
  420.                                       l3.origin().y()+ymoved),
  421.             Coordinate(l3.e().x()+xmoved,l3.e().y()+ymoved) );
  422.     l4 = Line(Coordinate(l4.origin().x()+xmoved,
  423.                                       l4.origin().y()+ymoved),
  424.             Coordinate(l4.e().x()+xmoved,l4.e().y()+ymoved) );
  425.     draw();
  426. }
  427.  
  428. Rect::Rect(Coordinate topLeft, long xsize, long ysize) {
  429.     Coordinate    a(topLeft);
  430.     Coordinate    b(a.x()+xsize, a.y());
  431.     Coordinate    c(a.x(),a.y()+ysize);
  432.     Coordinate    d(b.x(),c.y());
  433.     l1 = Line(a,b);
  434.     l2 = Line(b,c);
  435.     l3 = Line(c,d);
  436.     l4 = Line(d,a);
  437.     center_val = Coordinate((l1.origin().x()+l2.e().x())/2,
  438.                     (l4.origin().y()+l4.e().y())/2);
  439.     draw();
  440. }
  441.  
  442. /*
  443.  * CLASS TRIANGLE
  444.  */
  445.  
  446. void
  447. Triangle::rotate(Angle angle) {
  448.     erase();
  449.     l1.rotateAbout(center(), angle);
  450.     l2.rotateAbout(center(), angle);
  451.     l3.rotateAbout(center(), angle);
  452.     draw();
  453. }
  454.  
  455. void
  456. Triangle::move(Coordinate c) {
  457.     /*
  458.      * Argument is center.  Move center there; find out how far
  459.      * center moved and displace all points by the same amount.
  460.      */
  461.  
  462.     erase();
  463.     long xmoved = c.x() - center().x();
  464.     long ymoved = c.y() - center().y();
  465.     center_val = c;
  466.     l1 = Line(Coordinate(l1.origin().x()+xmoved,
  467.                                     l1.origin().y()+ymoved),
  468.             Coordinate(l1.e().x()+xmoved,l1.e().y()+ymoved) );
  469.     l2 = Line(Coordinate(l2.origin().x()+xmoved,
  470.                                     l2.origin().y()+ymoved),
  471.             Coordinate(l2.e().x()+xmoved,l2.e().y()+ymoved) );
  472.     l3 = Line(Coordinate(l3.origin().x()+xmoved,
  473.                                     l3.origin().y()+ymoved),
  474.             Coordinate(l3.e().x()+xmoved,l3.e().y()+ymoved) );
  475.     draw();
  476. }
  477.  
  478. void
  479. Triangle::draw() {
  480.     l1.draw(); l2.draw(); l3.draw();
  481. }
  482.  
  483. Triangle::Triangle(Coordinate a, Coordinate b, Coordinate c) {
  484.     l1 = Line(a,b);  l2 = Line(b,c);  l3 = Line(c,a);
  485.     center_val =
  486.                Coordinate((l1.e().x()+l2.e().x()+l3.e().x())/3,
  487.                         (l1.e().y()+l2.e().y()+l3.e().y())/3);
  488.     draw();
  489. }
  490.  
  491. /*-----------------------------------------------------------*/
  492. /* File main.c -- Driver program for Shapes example          */
  493. /*-----------------------------------------------------------*/
  494.  
  495. const int XSIZE = 800;
  496. const int YSIZE = 1024;
  497.  
  498. void
  499. rotateList(Shape *s, Angle a)
  500. {
  501.     for (Shape *f = s;  f;  f = f->next())
  502.         f->rotate(a);
  503. }
  504.  
  505. int
  506. main()
  507. {
  508.     Coordinate origin (0,0);
  509.  
  510.     /*
  511.      * windowBorder is not only the frame for the screen,
  512.      * but also serves as list head for the list of shapes
  513.      */
  514.  
  515.     Rect windowBorder(origin, XSIZE, YSIZE);
  516.  
  517.     Shape * t = new Triangle(
  518.         Coordinate(100, 100),
  519.         Coordinate(200, 200),
  520.         Coordinate(300, 100)
  521.     );
  522.     windowBorder.append(t);
  523.  
  524. //    Shape * c = new Circle(Coordinate(500,652), 150);
  525. //    t->insert(c);
  526.  
  527.     rotateList(&windowBorder, 90.0);
  528.     return 0;
  529. }
  530.