1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
|
/*
* std_F.cc -- The std_F class definitions
*
* Last Change: September 23, 2007
*/
// Include only the headers we need; burdensome, but generally more
// efficient for larger projects with many dependencies.
#ifdef MINIMAL
#include "epix/affine.h"
#include "epix/Color.h"
#include "epix/curves.h"
#include "epix/pairs.h"
#include "epix/path.h"
#include "epix/state.h"
#include "epix/triples.h"
#else
#include "epix.h"
#endif
#include "epix/paint_style.h"
#include "std_F.h"
namespace ePiX {
// The constructor initializes the class data, ensuring objects are
// well-formed. For efficiency, we use "initialization" instead of
// assignment (the "=" operator); this way, data members get their
// actual values immediately. The constructor body is empty, since
// this class requires no further initialization.
// All class member function definitions must be qualified with the
// class name, here "std_F::"
std_F::std_F()
: m_loc(0,0), m_e1(1,0), m_e2(0,1),
m_fore(Black()), m_back(White()),
m_edge(Black()), m_edge_width(0.4) { }
// Apply the affine map af; return a reference to this object so
// calls can be daisy-chained. Note the efficiency of storing only
// the bare minimum data to specify an affine map rather than
// holding and manipulating the shape of an F.
std_F& std_F::map_by(const affine& af)
{
m_loc = af(m_loc); // affines map locations, so this works
m_e1 = af(m_e1);
m_e2 = af(m_e2);
return *this;
}
// Set the background and foreground colors. Arguments' names chosen
// to indicate their purpose.
std_F& std_F::backing(const Color& back)
{
m_back = back;
return *this;
}
std_F& std_F::fill(const Color& fore)
{
m_fore = fore;
return *this;
}
// Set outline parameters.
std_F& std_F::border(const Color& edge, double wid)
{
m_edge = edge;
m_edge_width = wid;
return *this;
}
// Draw in the active screen. Most of the "real work" is done here.
void std_F::draw() const
{
// Get global drawing state, so we can restore before returning.
// Not particularly elegant, but it's what we have to work with.
Color old_fill(the_paint_style().fill_color());
bool old_flag(the_paint_style().fill_flag());
Color old_line(the_paint_style().line_color());
length old_line_width(the_paint_style().line_width());
// now we can draw
const double r(1.0/6.0);
path F;
// pr converts coords in [0,1] x [0,1] to our coords
F .pt(pr(r, 0.75*r)).pt(pr(2*r, 0.75*r)).pt(pr(2*r, 2.25*r))
.pt(pr(4*r, 2.25*r)).pt(pr(4*r, 3.25*r)).pt(pr(2*r, 3.25*r))
.pt(pr(2*r, 4.25*r)).pt(pr(5*r, 4.25*r)).pt(pr(5*r, 5.25*r))
.pt(pr( r, 5.25*r));
F.close().fill();
// Set global drawing state. We have a member function named fill,
// so the call must be explicitly qualified with "ePiX::".
ePiX::fill(m_back);
ePiX::pen(m_edge, m_edge_width);
// Bounding parallelogram
ePiX::quad(pr(0,0), pr(1,0), pr(1,1), pr(0,1));
ePiX::fill(m_fore);
F.draw();
// Restore global fill state.
the_paint_style().fill_color(old_fill);
the_paint_style().fill_flag(old_flag);
the_paint_style().line_color(old_line);
the_paint_style().line_width(old_line_width);
}
// private; convert (x,y) to a location usable in path construction
// "Privacy" is enforced by the compiler from reading the header;
// the definition requires no special syntax.
P std_F::pr(double x, double y) const
{
pair loc((1 - x -y)*m_loc + x*m_e1 + y*m_e2);
return P(loc.x1(), loc.x2());
}
} // end of namespace
|