Dear Fltk programers:
I find a lot fl_graphics_driver in "fl_draw.H" but not in "fl_draw.cxx"
my current link version of fltk used to compile my chapter.12.3 program(of book
of Mr. Bjarne Stroustrup-"Programming-Principle and practice using c++" 4th
Ed.) is 1.3.x
(is that right one?)
I am in Ubuntu10.04,gcc/g++4.4.3
Is I missing any header files on my(or Mr. Stroustrup's) Graph.h or Graph.cpp?
---------------------------------------------------------
r...@eric-laptop:/home/eric/BStrou/usingC++4/code/Chapter12# make
g++ -o Graph Graph.o -lstdc++ -lbookgui -lfltk -lfltk_images -lX11 -ljpeg
/usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib/crt1.o: In function `_start':
(.text+0x18): undefined reference to `main'
Graph.o: In function `Graph_lib::Shape::draw() const':
Graph.cpp:(.text+0xac): undefined reference to `fl_graphics_driver'
Graph.cpp:(.text+0xc6): undefined reference to `fl_graphics_driver'
Graph.cpp:(.text+0xf1): undefined reference to `fl_graphics_driver'
Graph.cpp:(.text+0x102): undefined reference to `fl_graphics_driver'
Graph.o: In function `Graph_lib::Text::draw_lines() const':
Graph.cpp:(.text+0xd97): undefined reference to `fl_graphics_driver'
Graph.o:Graph.cpp:(.text+0xe0e): more undefined references to
`fl_graphics_driver' follow
Graph.o:(.rodata._ZTVN9Graph_lib9Bad_imageE[vtable for
Graph_lib::Bad_image]+0x14): undefined reference to
`Fl_Image::color_average(unsigned int, float)'
collect2: ld returned 1 exit status
make: *** [Graph] Error 1
---------------------------------------
------------Graph.h--------------------
//
// This is a GUI support code to the chapters 12-16 of the book
// "Programming -- Principles and Practice Using C++" by Bjarne Stroustrup
//
#ifndef GRAPH_GUARD
#define GRAPH_GUARD 1
#include <FL/fl_draw.H>
#include <FL/Fl_Image.H>
#include "Point.h"
#include "std_lib_facilities.h"
namespace Graph_lib {
// defense against ill-behaved Linux macros:
#undef major
#undef minor
//------------------------------------------------------------------------------
// Color is the type we use to represent color. We can use Color like this:
// grid.set_color(Color::red);
struct Color {
enum Color_type {
red=FL_RED,
blue=FL_BLUE,
green=FL_GREEN,
yellow=FL_YELLOW,
white=FL_WHITE,
black=FL_BLACK,
magenta=FL_MAGENTA,
cyan=FL_CYAN,
dark_red=FL_DARK_RED,
dark_green=FL_DARK_GREEN,
dark_yellow=FL_DARK_YELLOW,
dark_blue=FL_DARK_BLUE,
dark_magenta=FL_DARK_MAGENTA,
dark_cyan=FL_DARK_CYAN
};
enum Transparency { invisible = 0, visible=255 };
Color(Color_type cc) :c(Fl_Color(cc)), v(visible) { }
Color(Color_type cc, Transparency vv) :c(Fl_Color(cc)), v(vv) { }
Color(int cc) :c(Fl_Color(cc)), v(visible) { }
Color(Transparency vv) :c(Fl_Color()), v(vv) { } // default color
int as_int() const { return c; }
char visibility() const { return v; }
void set_visibility(Transparency vv) { v=vv; }
private:
char v; // invisible and visible for now
Fl_Color c;
};
//------------------------------------------------------------------------------
struct Line_style {
enum Line_style_type {
solid=FL_SOLID, // -------
dash=FL_DASH, // - - - -
dot=FL_DOT, // .......
dashdot=FL_DASHDOT, // - . - .
dashdotdot=FL_DASHDOTDOT, // -..-..
};
Line_style(Line_style_type ss) :s(ss), w(0) { }
Line_style(Line_style_type lst, int ww) :s(lst), w(ww) { }
Line_style(int ss) :s(ss), w(0) { }
int width() const { return w; }
int style() const { return s; }
private:
int s;
int w;
};
//------------------------------------------------------------------------------
class Font {
public:
enum Font_type {
helvetica=FL_HELVETICA,
helvetica_bold=FL_HELVETICA_BOLD,
helvetica_italic=FL_HELVETICA_ITALIC,
helvetica_bold_italic=FL_HELVETICA_BOLD_ITALIC,
courier=FL_COURIER,
courier_bold=FL_COURIER_BOLD,
courier_italic=FL_COURIER_ITALIC,
courier_bold_italic=FL_COURIER_BOLD_ITALIC,
times=FL_TIMES,
times_bold=FL_TIMES_BOLD,
times_italic=FL_TIMES_ITALIC,
times_bold_italic=FL_TIMES_BOLD_ITALIC,
symbol=FL_SYMBOL,
screen=FL_SCREEN,
screen_bold=FL_SCREEN_BOLD,
zapf_dingbats=FL_ZAPF_DINGBATS
};
Font(Font_type ff) :f(ff) { }
Font(int ff) :f(ff) { }
int as_int() const { return f; }
private:
int f;
};
//------------------------------------------------------------------------------
template<class T> class Vector_ref {
vector<T*> v;
vector<T*> owned;
public:
Vector_ref() {}
Vector_ref(T& a) { push_back(a); }
Vector_ref(T& a, T& b);
Vector_ref(T& a, T& b, T& c);
Vector_ref(T* a, T* b = 0, T* c = 0, T* d = 0)
{
if (a) push_back(a);
if (b) push_back(b);
if (c) push_back(c);
if (d) push_back(d);
}
~Vector_ref() { for (int i=0; i<owned.size(); ++i) delete owned[i]; }
void push_back(T& s) { v.push_back(&s); }
void push_back(T* p) { v.push_back(p); owned.push_back(p); }
T& operator[](int i) { return *v[i]; }
const T& operator[](int i) const { return *v[i]; }
int size() const { return v.size(); }
};
//------------------------------------------------------------------------------
typedef double Fct(double);
class Shape { // deals with color and style, and holds sequence of lines
public:
void draw() const; // deal with color and draw lines
virtual void move(int dx, int dy); // move the shape +=dx and +=dy
void set_color(Color col) { lcolor = col; }
Color color() const { return lcolor; }
void set_style(Line_style sty) { ls = sty; }
Line_style style() const { return ls; }
void set_fill_color(Color col) { fcolor = col; }
Color fill_color() const { return fcolor; }
Point point(int i) const { return points[i]; } // read only access to points
int number_of_points() const { return int(points.size()); }
virtual ~Shape() { }
protected:
Shape();
virtual void draw_lines() const; // draw the appropriate lines
void add(Point p); // add p to points
void set_point(int i,Point p); // points[i]=p;
private:
vector<Point> points; // not used by all shapes
Color lcolor; // color for lines and characters
Line_style ls;
Color fcolor; // fill color
Shape(const Shape&); // prevent copying
Shape& operator=(const Shape&);
};
//------------------------------------------------------------------------------
struct Function : Shape {
// the function parameters are not stored
Function(Fct f, double r1, double r2, Point orig,
int count = 100, double xscale = 25, double yscale = 25);
};
//------------------------------------------------------------------------------
struct Line : Shape { // a Line is a Shape defined by two Points
Line(Point p1, Point p2); // construct a line from two points
};
//------------------------------------------------------------------------------
struct Rectangle : Shape {
Rectangle(Point xy, int ww, int hh) : w(ww), h(hh)
{
add(xy);
if (h<=0 || w<=0) error("Bad rectangle: non-positive side");
}
Rectangle(Point x, Point y) : w(y.x-x.x), h(y.y-x.y)
{
add(x);
if (h<=0 || w<=0) error("Bad rectangle: non-positive width or height");
}
void draw_lines() const;
int height() const { return h; }
int width() const { return w; }
private:
int h; // height
int w; // width
};
//------------------------------------------------------------------------------
struct Open_polyline : Shape { // open sequence of lines
void add(Point p) { Shape::add(p); }
void draw_lines() const;
};
//------------------------------------------------------------------------------
struct Closed_polyline : Open_polyline { // closed sequence of lines
void draw_lines() const;
};
//------------------------------------------------------------------------------
struct Polygon : Closed_polyline { // closed sequence of non-intersecting
lines
void add(Point p);
void draw_lines() const;
};
//------------------------------------------------------------------------------
struct Lines : Shape { // related lines
void draw_lines() const;
void add(Point p1, Point p2); // add a line defined by two points
};
//------------------------------------------------------------------------------
struct Text : Shape {
// the point is the bottom left of the first letter
Text(Point x, const string& s) : lab(s), fnt(fl_font()), fnt_sz(fl_size())
{ add(x); }
void draw_lines() const;
void set_label(const string& s) { lab = s; }
string label() const { return lab; }
void set_font(Font f) { fnt = f; }
Font font() const { return Font(fnt); }
void set_font_size(int s) { fnt_sz = s; }
int font_size() const { return fnt_sz; }
private:
string lab; // label
Font fnt;
int fnt_sz;
};
//------------------------------------------------------------------------------
struct Axis : Shape {
enum Orientation { x, y, z };
Axis(Orientation d, Point xy, int length,
int number_of_notches=0, string label = "");
void draw_lines() const;
void move(int dx, int dy);
void set_color(Color c);
Text label;
Lines notches;
};
//------------------------------------------------------------------------------
struct Circle : Shape {
Circle(Point p, int rr); // center and radius
void draw_lines() const;
Point center() const ;
int radius() const { return r; }
void set_radius(int rr) { r=rr; }
private:
int r;
};
//------------------------------------------------------------------------------
struct Ellipse : Shape {
Ellipse(Point p, int w, int h) // center, min, and max distance from
center
: w(w), h(h)
{
add(Point(p.x-w,p.y-h));
}
void draw_lines() const;
Point center() const { return Point(point(0).x+w,point(0).y+h); }
Point focus1() const { return
Point(center().x+int(sqrt(double(w*w-h*h))),center().y); }
Point focus2() const { return
Point(center().x-int(sqrt(double(w*w-h*h))),center().y); }
void set_major(int ww) { w=ww; }
int major() const { return w; }
void set_minor(int hh) { h=hh; }
int minor() const { return h; }
private:
int w;
int h;
};
//------------------------------------------------------------------------------
struct Marked_polyline : Open_polyline {
Marked_polyline(const string& m) :mark(m) { }
void draw_lines() const;
private:
string mark;
};
//------------------------------------------------------------------------------
struct Marks : Marked_polyline {
Marks(const string& m) :Marked_polyline(m)
{
set_color(Color(Color::invisible));
}
};
//------------------------------------------------------------------------------
struct Mark : Marks {
Mark(Point xy, char c) : Marks(string(1,c))
{
add(xy);
}
};
//------------------------------------------------------------------------------
struct Suffix {
enum Encoding { none, jpg, gif };
};
Suffix::Encoding get_encoding(const string& s);
//------------------------------------------------------------------------------
struct Image : Shape {
Image(Point xy, string file_name, Suffix::Encoding e = Suffix::none);
~Image() { delete p; }
void draw_lines() const;
void set_mask(Point xy, int ww, int hh) { w=ww; h=hh; cx=xy.x; cy=xy.y; }
private:
int w,h; // define "masking box" within image relative to position (cx,cy)
int cx,cy;
Fl_Image* p;
Text fn;
};
//------------------------------------------------------------------------------
struct Bad_image : Fl_Image {
Bad_image(int h, int w) : Fl_Image(h,w,0) { }
void draw(int x,int y, int, int, int, int) { draw_empty(x,y); }
};
//------------------------------------------------------------------------------
} // of namespace Graph_lib
#endif
-------------------------------------------------------------
---------------this is Graph.cpp--------------------------
//
// This is a GUI support code to the chapters 12-16 of the book
// "Programming -- Principles and Practice Using C++" by Bjarne Stroustrup
//
#include <FL/Fl_GIF_Image.H>
#include <FL/Fl_JPEG_Image.H>
#include "Graph.h"
#include <cstdlib>
#include <cstring>
//------------------------------------------------------------------------------
namespace Graph_lib {
//------------------------------------------------------------------------------
Shape::Shape() :
lcolor(fl_color()), // default color for lines and characters
ls(0), // default style
fcolor(Color::invisible) // no fill
{}
//------------------------------------------------------------------------------
void Shape::add(Point p) // protected
{
points.push_back(p);
}
//------------------------------------------------------------------------------
void Shape::set_point(int i,Point p) // not used; not necessary so far
{
points[i] = p;
}
//------------------------------------------------------------------------------
void Shape::draw_lines() const
{
if (color().visibility() && 1<points.size()) // draw sole pixel?
for (unsigned int i=1; i<points.size(); ++i)
fl_line(points[i-1].x,points[i-1].y,points[i].x,points[i].y);
}
//------------------------------------------------------------------------------
void Shape::draw() const
{
Fl_Color oldc = fl_color();
// there is no good portable way of retrieving the current style
fl_color(lcolor.as_int()); // set color
fl_line_style(ls.style(),ls.width()); // set style
draw_lines();
fl_color(oldc); // reset color (to previous)
fl_line_style(0); // reset line style to default
}
//------------------------------------------------------------------------------
void Shape::move(int dx, int dy) // move the shape +=dx and +=dy
{
for (int i = 0; i<points.size(); ++i) {
points[i].x+=dx;
points[i].y+=dy;
}
}
//------------------------------------------------------------------------------
Line::Line(Point p1, Point p2) // construct a line from two points
{
add(p1); // add p1 to this shape
add(p2); // add p2 to this shape
}
//------------------------------------------------------------------------------
void Lines::add(Point p1, Point p2)
{
Shape::add(p1);
Shape::add(p2);
}
//------------------------------------------------------------------------------
// draw lines connecting pairs of points
void Lines::draw_lines() const
{
if (color().visibility())
for (int i=1; i<number_of_points(); i+=2)
fl_line(point(i-1).x,point(i-1).y,point(i).x,point(i).y);
}
//------------------------------------------------------------------------------
// does two lines (p1,p2) and (p3,p4) intersect?
// if se return the distance of the intersect point as distances from p1
inline pair<double,double> line_intersect(Point p1, Point p2, Point p3, Point
p4, bool& parallel)
{
double x1 = p1.x;
double x2 = p2.x;
double x3 = p3.x;
double x4 = p4.x;
double y1 = p1.y;
double y2 = p2.y;
double y3 = p3.y;
double y4 = p4.y;
double denom = ((y4 - y3)*(x2-x1) - (x4-x3)*(y2-y1));
if (denom == 0){
parallel= true;
return pair<double,double>(0,0);
}
parallel = false;
return pair<double,double>( ((x4-x3)*(y1-y3) - (y4-y3)*(x1-x3))/denom,
((x2-x1)*(y1-y3) - (y2-y1)*(x1-x3))/denom);
}
//------------------------------------------------------------------------------
//intersection between two line segments
//Returns true if the two segments intersect,
//in which case intersection is set to the point of intersection
bool line_segment_intersect(Point p1, Point p2, Point p3, Point p4, Point&
intersection){
bool parallel;
pair<double,double> u = line_intersect(p1,p2,p3,p4,parallel);
if (parallel || u.first < 0 || u.first > 1 || u.second < 0 || u.second > 1)
return false;
intersection.x = p1.x + u.first*(p2.x - p1.x);
intersection.y = p1.y + u.first*(p2.y - p1.y);
return true;
}
//------------------------------------------------------------------------------
void Polygon::add(Point p)
{
int np = number_of_points();
if (1<np) { // check that thenew line isn't parallel to the previous one
if (p==point(np-1)) error("polygon point equal to previous point");
bool parallel;
line_intersect(point(np-1),p,point(np-2),point(np-1),parallel);
if (parallel)
error("two polygon points lie in a straight line");
}
for (int i = 1; i<np-1; ++i) { // check that new segment doesn't
interset and old point
Point ignore(0,0);
if (line_segment_intersect(point(np-1),p,point(i-1),point(i),ignore))
error("intersect in polygon");
}
Closed_polyline::add(p);
}
//------------------------------------------------------------------------------
void Polygon::draw_lines() const
{
if (number_of_points() < 3) error("less than 3 points in a Polygon");
Closed_polyline::draw_lines();
}
//------------------------------------------------------------------------------
void Open_polyline::draw_lines() const
{
if (fill_color().visibility()) {
fl_color(fill_color().as_int());
fl_begin_complex_polygon();
for(int i=0; i<number_of_points(); ++i){
fl_vertex(point(i).x, point(i).y);
}
fl_end_complex_polygon();
fl_color(color().as_int()); // reset color
}
if (color().visibility())
Shape::draw_lines();
}
//------------------------------------------------------------------------------
void Closed_polyline::draw_lines() const
{
Open_polyline::draw_lines(); // first draw the "open poly line part"
// then draw closing line:
if (color().visibility())
fl_line(point(number_of_points()-1).x,
point(number_of_points()-1).y,
point(0).x,
point(0).y);
}
//------------------------------------------------------------------------------
void draw_mark(Point xy, char c)
{
static const int dx = 4;
static const int dy = 4;
string m(1,c);
fl_draw(m.c_str(),xy.x-dx,xy.y+dy);
}
//------------------------------------------------------------------------------
void Marked_polyline::draw_lines() const
{
Open_polyline::draw_lines();
for (int i=0; i<number_of_points(); ++i)
draw_mark(point(i),mark[i%mark.size()]);
}
//------------------------------------------------------------------------------
void Rectangle::draw_lines() const
{
if (fill_color().visibility()) { // fill
fl_color(fill_color().as_int());
fl_rectf(point(0).x,point(0).y,w,h);
}
if (color().visibility()) { // lines on top of fill
fl_color(color().as_int());
fl_rect(point(0).x,point(0).y,w,h);
}
}
//------------------------------------------------------------------------------
Circle::Circle(Point p, int rr) // center and radius
:r(rr)
{
add(Point(p.x-r,p.y-r)); // store top-left corner
}
//------------------------------------------------------------------------------
Point Circle::center() const
{
return Point(point(0).x+r, point(0).y+r);
}
//------------------------------------------------------------------------------
void Circle::draw_lines() const
{
if (color().visibility())
fl_arc(point(0).x,point(0).y,r+r,r+r,0,360);
}
//------------------------------------------------------------------------------
void Ellipse::draw_lines() const
{
if (color().visibility())
fl_arc(point(0).x,point(0).y,w+w,h+h,0,360);
}
//------------------------------------------------------------------------------
void Text::draw_lines() const
{
int ofnt = fl_font();
int osz = fl_size();
fl_font(fnt.as_int(),fnt_sz);
fl_draw(lab.c_str(),point(0).x,point(0).y);
fl_font(ofnt,osz);
}
//------------------------------------------------------------------------------
Axis::Axis(Orientation d, Point xy, int length, int n, string lab) :
label(Point(0,0),lab)
{
if (length<0) error("bad axis length");
switch (d){
case Axis::x:
{
Shape::add(xy); // axis line
Shape::add(Point(xy.x+length,xy.y));
if (1<n) { // add notches
int dist = length/n;
int x = xy.x+dist;
for (int i = 0; i<n; ++i) {
notches.add(Point(x,xy.y),Point(x,xy.y-5));
x += dist;
}
}
// label under the line
label.move(length/3,xy.y+20);
break;
}
case Axis::y:
{
Shape::add(xy); // a y-axis goes up
Shape::add(Point(xy.x,xy.y-length));
if (1<n) { // add notches
int dist = length/n;
int y = xy.y-dist;
for (int i = 0; i<n; ++i) {
notches.add(Point(xy.x,y),Point(xy.x+5,y));
y -= dist;
}
}
// label at top
label.move(xy.x-10,xy.y-length-10);
break;
}
case Axis::z:
error("z axis not implemented");
}
}
//------------------------------------------------------------------------------
void Axis::draw_lines() const
{
Shape::draw_lines();
notches.draw(); // the notches may have a different color from the line
label.draw(); // the label may have a different color from the line
}
//------------------------------------------------------------------------------
void Axis::set_color(Color c)
{
Shape::set_color(c);
notches.set_color(c);
label.set_color(c);
}
//------------------------------------------------------------------------------
void Axis::move(int dx, int dy)
{
Shape::move(dx,dy);
notches.move(dx,dy);
label.move(dx,dy);
}
//------------------------------------------------------------------------------
Function::Function(Fct f, double r1, double r2, Point xy,
int count, double xscale, double yscale)
// graph f(x) for x in [r1:r2) using count line segments with (0,0) displayed
at xy
// x coordinates are scaled by xscale and y coordinates scaled by yscale
{
if (r2-r1<=0) error("bad graphing range");
if (count <=0) error("non-positive graphing count");
double dist = (r2-r1)/count;
double r = r1;
for (int i = 0; i<count; ++i) {
add(Point(xy.x+int(r*xscale),xy.y-int(f(r)*yscale)));
r += dist;
}
}
//------------------------------------------------------------------------------
bool can_open(const string& s)
// check if a file named s exists and can be opened for reading
{
ifstream ff(s.c_str());
return ff;
}
//------------------------------------------------------------------------------
#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
Suffix::Encoding get_encoding(const string& s)
{
struct SuffixMap
{
const char* extension;
Suffix::Encoding suffix;
};
static SuffixMap smap[] = {
{".jpg", Suffix::jpg},
{".jpeg", Suffix::jpg},
{".gif", Suffix::gif},
};
for (int i = 0, n = ARRAY_SIZE(smap); i < n; i++)
{
int len = strlen(smap[i].extension);
if (s.length() >= len && s.substr(s.length()-len, len) ==
smap[i].extension)
return smap[i].suffix;
}
return Suffix::none;
}
//------------------------------------------------------------------------------
// somewhat over-elaborate constructor
// because errors related to image files can be such a pain to debug
Image::Image(Point xy, string s, Suffix::Encoding e)
:w(0), h(0), fn(xy,"")
{
add(xy);
if (!can_open(s)) { // can we open s?
fn.set_label("cannot open \""+s+'\"');
p = new Bad_image(30,20); // the "error image"
return;
}
if (e == Suffix::none) e = get_encoding(s);
switch(e) { // check if it is a known encoding
case Suffix::jpg:
p = new Fl_JPEG_Image(s.c_str());
break;
case Suffix::gif:
p = new Fl_GIF_Image(s.c_str());
break;
default: // Unsupported image encoding
fn.set_label("unsupported file type \""+s+'\"');
p = new Bad_image(30,20); // the "error image"
}
}
//------------------------------------------------------------------------------
void Image::draw_lines() const
{
if (fn.label()!="") fn.draw_lines();
if (w&&h)
p->draw(point(0).x,point(0).y,w,h,cx,cy);
else
p->draw(point(0).x,point(0).y);
}
//------------------------------------------------------------------------------
} // of namespace Graph_lib
----------------------------------------------------
so plz help, eric, [email protected], [email protected]
_______________________________________________
fltk mailing list
[email protected]
http://lists.easysw.com/mailman/listinfo/fltk