/*****
* drawfill.h
* Andy Hammerlindl 2002/06/06
*
* Stores a cyclic path that will outline a filled shape in a picture.
*****/
#ifndef DRAWFILL_H
#define DRAWFILL_H
#include "drawelement.h"
#include "path.h"
namespace camp {
class drawFill : public drawSuperPathPenBase {
protected:
bool stroke;
public:
void noncyclic() {
reportError("non-cyclic path cannot be filled");
}
drawFill(const vm::array& src, bool stroke, pen pentype,
const string& key="") :
drawElement(key), drawSuperPathPenBase(src,pentype), stroke(stroke) {
if(!stroke && !cyclic()) noncyclic();
}
bool svg() {return true;}
// dvisvgm doesn't yet support SVG patterns.
bool svgpng() {return pentype.fillpattern() != "";}
virtual ~drawFill() {}
virtual bool draw(psfile *out);
virtual void palette(psfile *out) {
penSave(out);
penTranslate(out);
}
virtual void fill(psfile *out) {
out->setpen(pentype);
if(stroke) out->strokepath();
out->fill(pentype);
penRestore(out);
};
drawElement *transformed(const transform& t);
};
class drawShade : public drawFill {
public:
drawShade(const vm::array& src, bool stroke, pen pentype,
const string& key="")
: drawFill(src,stroke,pentype,key) {}
void bounds(bbox& b, iopipestream& iopipe, boxvector& vbox,
bboxlist& bboxstack) {
if(stroke) strokebounds(b);
else drawSuperPathPenBase::bounds(b,iopipe,vbox,bboxstack);
}
bool pdf() {
return settings::pdf(settings::getSetting<string>("tex"));
}
// Shading in SVG is incomplete and not supported at all by dvisvgm --pdf.
bool svgpng() {return true;}
virtual void beginshade(psfile *out)=0;
virtual void shade(psfile *out)=0;
bool draw(psfile *out) {
if(pentype.invisible() || empty()) return true;
palette(out);
beginshade(out);
writeclippath(out);
if(stroke) strokepath(out);
out->endpsclip(pentype.Fillrule());
shade(out);
out->grestore();
return true;
}
};
class drawLatticeShade : public drawShade {
protected:
vm::array pens;
const transform T;
public:
drawLatticeShade(const vm::array& src, bool stroke,
pen pentype, const vm::array& pens,
const camp::transform& T=identity, const string& key="")
: drawShade(src,stroke,pentype,key), pens(pens), T(T) {}
void palette(psfile *out) {
out->gsave();
}
void beginshade(psfile *out) {
out->beginlatticeshade(pens,bpath);
}
void shade(psfile *out) {
bbox b;
for(size_t i=0; i < size; i++) {
path p=vm::read<path>(P,i).transformed(inverse(T));
if(stroke)
drawPathPenBase::strokebounds(b,p);
else
b += p.bounds();
}
out->latticeshade(pens,T*matrix(b.Min(),b.Max()));
}
drawElement *transformed(const transform& t);
};
class drawAxialShade : public drawShade {
protected:
pair a;
bool extenda;
pen penb;
pair b;
bool extendb;
ColorSpace colorspace;
public:
drawAxialShade(const vm::array& src, bool stroke,
pen pentype, pair a, bool extenda, pen penb, pair b,
bool extendb, const string& key="")
: drawShade(src,stroke,pentype,key), a(a), extenda(extenda),
penb(penb), b(b), extendb(extendb) {}
bool svgpng() {return !extenda || !extendb || pdf();}
void palette(psfile *out);
void beginshade(psfile *out) {
out->begingradientshade(true,colorspace,pentype,a,0,penb,b,0);
}
void shade(psfile *out) {
out->gradientshade(true,colorspace,pentype,a,0,extenda,penb,b,0,extendb);
}
drawElement *transformed(const transform& t);
};
class drawRadialShade : public drawAxialShade {
protected:
double ra;
double rb;
public:
drawRadialShade(const vm::array& src, bool stroke,
pen pentype, pair a, double ra, bool extenda, pen penb,
pair b, double rb, bool extendb, const string& key="")
: drawAxialShade(src,stroke,pentype,a,extenda,penb,b,
extendb,key), ra(ra), rb(rb) {}
bool svgpng() {return a != b || ra > 0.0 || !extenda || !extendb || pdf();}
void beginshade(psfile *out) {
out->begingradientshade(false,colorspace,pentype,a,ra,penb,b,rb);
}
void shade(psfile *out) {
out->gradientshade(false,colorspace,pentype,a,ra,extenda,penb,b,rb,extendb);
}
drawElement *transformed(const transform& t);
};
class drawGouraudShade : public drawShade {
protected:
vm::array pens,vertices,edges;
public:
drawGouraudShade(const vm::array& src, bool stroke,
pen pentype, const vm::array& pens,
const vm::array& vertices, const vm::array& edges,
const string& key="")
: drawElement(key), drawShade(src,stroke,pentype,key), pens(pens),
vertices(vertices), edges(edges) {}
bool svgpng() {return settings::xasy || !settings::getSetting<bool>("svgemulation") || pdf();}
void palette(psfile *out) {
out->gsave();
}
void beginshade(psfile *out) {
out->begingouraudshade(pens,vertices,edges);
}
void shade(psfile *out) {
out->gouraudshade(pentype,pens,vertices,edges);
}
drawElement *transformed(const transform& t);
};
class drawTensorShade : public drawShade {
protected:
vm::array pens,boundaries,z;
public:
drawTensorShade(const vm::array& src, bool stroke,
pen pentype, const vm::array& pens,
const vm::array& boundaries, const vm::array& z,
const string& key="") :
drawShade(src,stroke,pentype,key), pens(pens), boundaries(boundaries),
z(z) {
}
void palette(psfile *out) {
out->gsave();
}
void beginshade(psfile *out) {}
void shade(psfile *out) {
out->tensorshade(pentype,pens,boundaries,z);
}
drawElement *transformed(const transform& t);
};
class drawFunctionShade : public drawFill {
protected:
string shader;
public:
drawFunctionShade(const vm::array& src, bool stroke,
pen pentype, const string& shader, const string& key="")
: drawFill(src,stroke,pentype,key), shader(shader) {
string texengine=settings::getSetting<string>("tex");
if(!settings::pdf(texengine))
reportError("functionshade is not implemented for the '"+texengine+
"' tex engine");
}
virtual ~drawFunctionShade() {}
bool draw(psfile *out) {return false;}
bool write(texfile *, const bbox&);
bool islabel() {return true;}
drawElement *transformed(const transform& t);
};
}
#endif