#ifndef GRAPH_GUARD
#define GRAPH_GUARD 1
#include "Point.h"
#include <FL/Fl.H>
#include <FL/fl_draw.H>
#include <iostream>
#include <stdio.h>
#include <vector>
#include <cmath> // コメントアウトになっていた
using std::string; using std::initializer_list;
using std::vector; using std::cout;
// このエラー関数が存在していなかった
void error (const char* message) ;
namespace Graph_lib {
#undef major
#undef minor
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) { }
int as_int() const { return c; }
char visibility() const { return v; }
void set_visibility(Transparency vv) { v=vv; }
private:
unsigned char v;
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, 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 {
protected:
Shape() { }
Shape(initializer_list<Point> lst){ } // initializer_listを設定していなかった
void add(Point p){ points.push_back(p); }
void set_point(int i, Point p) { points[i] = p; }
public:
void draw() const;
protected:
virtual void draw_lines() const;
public:
virtual void move(int dx, int 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]; }
int number_of_points() const { return int(points.size()); }
virtual ~Shape() { }
Shape(const Shape&) = delete;
Shape& operator=(const Shape&) = delete;
private:
vector<Point> points;
Color lcolor {static_cast<int>(fl_color())}; // 型が合わないので変換
Line_style ls {0};
Color fcolor {Color::invisible};
};
struct Function : Shape {
Function(Fct f, double r1, double r2, Point orig, int count = 100, double xscale = 25, double yscale = 25);
};
struct Fill {
Fill() :no_fill(true), fcolor(0) { }
Fill(Color c) :no_fill(false), fcolor(c) { }
void set_fill_color(Color col) { fcolor = col; }
Color fill_color() { return fcolor; }
protected:
bool no_fill;
Color fcolor;
};
struct Line : Shape {
Line(Point p1, Point p2) { add(p1); add(p2); }
};
struct Rectangle : Shape {
Rectangle(Point xy, int ww, int hh) :w{ ww }, h{ hh }
{
if (h<=0 || w<=0) error("Bad rectangle: non-positive side"); // error関数がないのでエラー
add(xy);
}
Rectangle(Point x, Point y) :w{ y.x - x.x }, h{ y.y - x.y }
{
if (h<=0 || w<=0) error("Bad rectangle: first point is not top left");
add(x);
}
void draw_lines() const;
int height() const { return h; }
int width() const { return w; }
private:
int h;
int w;
// Color fcolor; // fill color; 0 means "no fill"
};
bool intersect(Point p1, Point p2, Point p3, Point p4);
struct Open_polyline : Shape {
using Shape::Shape;
void add(Point p) { Shape::add(p); }
void draw_lines() const;
};
struct Closed_polyline : Open_polyline {
using Open_polyline::Open_polyline;
void draw_lines() const;
// void add(Point p) { Shape::add(p); }
};
struct Polygon : Closed_polyline {
using Closed_polyline::Closed_polyline;
void add(Point p);
void draw_lines() const;
};
struct Lines : Shape {
Lines() {}
Lines(initializer_list<Point> lst) : Shape{lst} { if (lst.size() % 2) error("odd number of points for Lines"); }
void draw_lines() const;
void add(Point p1, Point p2) { Shape::add(p1); Shape::add(p2); }
};
struct Text : Shape {
Text(Point x, const string& s) : lab{ s } { 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{ fl_font() };
int fnt_sz{ (14<fl_size()) ? fl_size() : 14 };
};
struct Axis : Shape {
enum Orientation { x, y, z };
Axis(Orientation d, Point xy, int length, int nummber_of_notches=0, string label = "");
void draw_lines() const;
void move(int dx, int dy);
void set_color(Color c);
Text label;
Lines notches;
// Orientation orin;
// int notches;
};
struct Circle : Shape {
Circle(Point p, int rr)
:r{ rr } {
add(Point{ p.x - r, p.y - r });
}
void draw_lines() const;
Point center() const { return { point(0).x + r, point(0).y + r }; }
void set_radius(int rr) { r=rr; }
int radius() const { return r; }
private:
int r;
};
struct Ellipse : Shape {
Ellipse(Point p, int ww, int hh)
:w{ ww }, h{ hh } {
add(Point{ p.x - ww, p.y - hh });
}
void draw_lines() const;
Point center() const { return{ point(0).x + w, point(0).y + h }; }
Point focus1() const { return{ center().x + int(sqrt(double(w*w - h*h))), center().y }; }
Point focus2() const { return{ 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 Mark : Text {
static const int dw = 4;
static const int dh = 4;
Mark(Point xy, char c) : Text(Point(xy.x-dw, xy.y+dh),string(1,c)) {}
};
*/
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 Marks : Shape {
Marks(char m) : mark(string(1,m)) { }
void add(Point p) { Shape::add(p); }
void draw_lines() const;
private:
string mark;
};
*/
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); }
};
struct Suffix {
enum Encoding { none, jpg, gif, bmp };
};
Suffix::Encoding get_encoding(const string& s);
struct Image : Shape {
Image(Point xy, string s, 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; }
void move(int dx,int dy) { Shape::move(dx,dy); p->draw(point(0).x,point(0).y); }
private:
int w,h,cx,cy;
Fl_Image* p;
Text fn;
};
}
#endif
#include "Graph.h"
#include <map>
#include <fstream>
#include <FL/Fl_JPEG_Image.H>
#include <FL/Fl_GIF_Image.H>
using std::pair; using std::ifstream;
void error (const char* message) {
cout << message << "¥n" ;
exit(1);
}
namespace Graph_lib {
void Shape::draw_lines() const
{
if (color().visibility() && 1<points.size())
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();
fl_color(lcolor.as_int());
fl_line_style(ls.style(),ls.width());
draw_lines();
fl_color(oldc);
fl_line_style(0);
}
// pairの設定がなかった
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);
}
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) {
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) {
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();
if (color().visibility())
fl_line(point(number_of_points()-1).x,point(number_of_points()-1).y,point(0).x,point(0).y);
}
void Shape::move(int dx, int dy)
{
for (unsigned int i = 0; i<points.size(); ++i) {
points[i].x+=dx;
points[i].y+=dy;
}
}
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);
}
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);
}
Function::Function(Fct f, double r1, double r2, Point xy, int count, double xscale, double 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;
}
}
void Rectangle::draw_lines() const
{
if (fill_color().visibility()) {
fl_color(fill_color().as_int());
fl_rectf(point(0).x,point(0).y,w,h);
fl_color(color().as_int());
}
if (color().visibility()) {
fl_color(color().as_int());
fl_rect(point(0).x,point(0).y,w,h);
}
}
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);
Shape::add(Point(xy.x+length,xy.y));
if (1<n) {
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.move(length/3,xy.y+20);
break;
}
case Axis::y:
{ Shape::add(xy);
Shape::add(Point(xy.x,xy.y-length));
if (1<n) {
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.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();
label.draw();
}
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);
}
void Circle::draw_lines() const
{
if (fill_color().visibility()) {
fl_color(fill_color().as_int());
fl_pie(point(0).x,point(0).y,r+r-1,r+r-1,0,360);
fl_color(color().as_int());
}
if (color().visibility()) {
fl_color(color().as_int());
fl_arc(point(0).x,point(0).y,r+r,r+r,0,360);
}
}
void Ellipse::draw_lines() const
{
if (fill_color().visibility()) {
fl_color(fill_color().as_int());
fl_pie(point(0).x,point(0).y,w+w-1,h+h-1,0,360);
fl_color(color().as_int());
}
if (color().visibility()) {
fl_color(color().as_int());
fl_arc(point(0).x,point(0).y,w+w,h+h,0,360);
}
}
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 Marks::draw_lines() const
{
for (int i=0; i<number_of_points(); ++i)
fl_draw(mark.c_str(),point(i).x-4,point(i).y+4);
}
*/
std::map<string,Suffix::Encoding> suffix_map;
int init_suffix_map()
{
suffix_map["jpg"] = Suffix::jpg;
suffix_map["JPG"] = Suffix::jpg;
suffix_map["jpeg"] = Suffix::jpg;
suffix_map["JPEG"] = Suffix::jpg;
suffix_map["gif"] = Suffix::gif;
suffix_map["GIF"] = Suffix::gif;
suffix_map["bmp"] = Suffix::bmp;
suffix_map["BMP"] = Suffix::bmp;
return 0;
}
Suffix::Encoding get_encoding(const string& s)
{
static int x = init_suffix_map();
string::const_iterator p = find(s.begin(),s.end(),'.');
if (p==s.end()) return Suffix::none;
string suf(p+1,s.end());
return suffix_map[suf];
}
// この関数ではffが戻り値になっていたのでエラー
bool can_open(const string& s)
{
ofstream ff(s.c_str());
if (ff){
return 1;
} else {
return 0;
}
}
Image::Image(Point xy, string s, Suffix::Encoding e)
:w(0), h(0), fn(xy,"")
{
add(xy);
if (!can_open(s)) {
fn.set_label("cannot open \""+s+'\"');
p = new Bad_image(30,20);
return;
}
if (e == Suffix::none) e = get_encoding(s);
switch(e) {
case Suffix::jpg:
p = new Fl_JPEG_Image(s.c_str());
break;
case Suffix::gif:
p = new Fl_GIF_Image(s.c_str());
break;
// case Suffix::bmp:
// p = new Fl_BMP_Image(s.c_str());
// break;
default:
fn.set_label("unsupported file type \""+s+'\"');
p = new Bad_image(30,20);
}
}
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);
}
}