/*****
* runlabel.in
*
* Runtime functions for label operations.
*
*****/
pen => primPen()
pair => primPair()
path => primPath()
picture* => primPicture()
transform => primTransform()
realarray* => realArray()
stringarray* => stringArray()
penarray* => penArray()
patharray* => pathArray()
patharray2* => pathArray2()
#include "picture.h"
#include "drawlabel.h"
#include "locate.h"
using namespace camp;
using namespace vm;
using namespace settings;
typedef array realarray;
typedef array stringarray;
typedef array penarray;
typedef array patharray;
typedef array patharray2;
using types::realArray;
using types::stringArray;
using types::penArray;
using types::pathArray;
using types::pathArray2;
void cannotread(const string& s)
{
ostringstream buf;
buf << "Cannot read from " << s;
error(buf);
}
void cannotwrite(const string& s)
{
ostringstream buf;
buf << "Cannot write to " << s;
error(buf);
}
pair readpair(stringstream& s, double hscale=1.0, double vscale=1.0)
{
double x,y;
s >> y;
s >> x;
return pair(hscale*x,vscale*y);
}
string ASYx="/ASYx {( ) print ASYX sub 12 string cvs print} bind def";
string ASYy="/ASYy {( ) print ASYY sub 12 string cvs print} bind def";
string pathforall="{(M) print ASYy ASYx} {(L) print ASYy ASYx} {(C) print ASYy ASYx ASYy ASYx ASYy ASYx} {(c) print} pathforall";
string currentpoint="print currentpoint ASYy ASYx ";
string ASYinit="/ASYX currentpoint pop def /ASYY currentpoint exch pop def ";
string ASY1="ASY1 {"+ASYinit+"/ASY1 false def} if ";
void endpath(std::ostream& ps)
{
ps << ASY1 << pathforall << " (M) " << currentpoint
<< "currentpoint newpath moveto} bind def" << endl;
}
void fillpath(std::ostream& ps)
{
ps << "/fill {closepath ";
endpath(ps);
}
void showpath(std::ostream& ps)
{
ps << ASYx << newl
<< ASYy << newl
<< "/ASY1 true def" << newl
<< "/stroke {strokepath ";
endpath(ps);
fillpath(ps);
}
array *readpath(const string& psname, bool keep,
double hscale=1.0, double vsign=1.0)
{
double vscale=vsign*hscale;
array *PP=new array(0);
char *oldPath=NULL;
string dir=stripFile(outname());
if(!dir.empty()) {
oldPath=getPath();
setPath(dir.c_str());
}
mem::vector<string> cmd;
cmd.push_back(getSetting<string>("gs"));
cmd.push_back("-q");
cmd.push_back("-dBATCH");
cmd.push_back("-P");
if(safe) cmd.push_back("-dSAFER");
#ifdef __MSDOS__
const string null="NUL";
#else
const string null="/dev/null";
#endif
string psdriver=getSetting<string>("psdriver");
cmd.push_back("-sDEVICE="+psdriver);
cmd.push_back("-sOutputFile="+null);
cmd.push_back(stripDir(psname));
iopipestream gs(cmd,"gs","Ghostscript");
while(gs.running()) {
stringstream buf;
string s=gs.readline();
if(s.empty()) break;
gs << newl;
// Workaround broken stringstream container in libc++.
#ifdef _LIBCPP_VERSION
for(string::iterator i=s.begin(); i != s.end(); ++i) {
if(isalpha(*i) && *i != 'e') {buf << " ";}
buf << *i;
}
#else
buf << s;
#endif
if(verbose > 2) cout << endl;
mem::vector<solvedKnot> nodes;
solvedKnot node;
bool active=false;
array *P=new array(0);
PP->push(P);
while(!buf.eof()) {
char c='>';
buf >> c;
if(c == '>') break;
switch(c) {
case 'M':
{
node.pre=node.point=readpair(buf,hscale,vscale);
node.straight=false;
break;
}
case 'L':
{
pair point=readpair(buf,hscale,vscale);
pair delta=(point-node.point)*third;
node.post=node.point+delta;
node.straight=true;
nodes.push_back(node);
active=true;
node.pre=point-delta;
node.point=point;
break;
}
case 'C':
{
pair point=readpair(buf,hscale,vscale);
pair pre=readpair(buf,hscale,vscale);
node.post=readpair(buf,hscale,vscale);
node.straight=false;
nodes.push_back(node);
active=true;
node.pre=pre;
node.point=point;
break;
}
case 'c':
{
if(active) {
if(node.point == nodes[0].point)
nodes[0].pre=node.pre;
else {
pair delta=(nodes[0].point-node.point)*third;
node.post=node.point+delta;
nodes[0].pre=nodes[0].point-delta;
node.straight=true;
nodes.push_back(node);
}
P->push(path(nodes,nodes.size(),true)); // Discard noncyclic paths
nodes.clear();
}
active=false;
node.straight=false;
break;
}
}
}
}
if(oldPath != NULL)
setPath(oldPath);
if(!keep)
unlink(psname.c_str());
return PP;
}
// Autogenerated routines:
void label(picture *f, string *s, string *size, transform t, pair position,
pair align, pen p)
{
f->append(new drawLabel(*s,*size,t,position,align,p));
}
bool labels(picture *f)
{
return f->havelabels();
}
realarray *texsize(string *s, pen p=CURRENTPEN)
{
texinit();
processDataStruct &pd=processData();
string texengine=getSetting<string>("tex");
setpen(pd.tex,texengine,p);
double width,height,depth;
texbounds(width,height,depth,pd.tex,*s);
array *t=new array(3);
(*t)[0]=width;
(*t)[1]=height;
(*t)[2]=depth;
return t;
}
patharray2 *_texpath(stringarray *s, penarray *p)
{
size_t n=checkArrays(s,p);
if(n == 0) return new array(0);
string prefix=cleanpath(outname());
string psname=auxname(prefix,"ps");
string texname=auxname(prefix,"tex");
string dviname=auxname(prefix,"dvi");
bbox b;
string texengine=getSetting<string>("tex");
bool xe=settings::xe(texengine) || settings::lua(texengine) ||
settings::context(texengine);
texfile tex(texname,b,true);
tex.miniprologue();
for(size_t i=0; i < n; ++i) {
tex.setfont(read<pen>(p,i));
if(i != 0) {
if(texengine == "context")
tex.verbatimline("}\\page\\hbox{%");
else if(texengine == "luatex" || texengine == "tex" ||
texengine == "pdftex")
tex.verbatimline("\\eject");
else
tex.verbatimline("\\newpage");
}
if(!xe) {
tex.verbatimline("\\special{ps:");
tex.verbatimline(ASYx);
tex.verbatimline(ASYy);
tex.verbatimline("/ASY1 true def");
tex.verbatimline("/show {"+ASY1+
"currentpoint newpath moveto false charpath "+pathforall+
"} bind def");
tex.verbatimline("/V {"+ASY1+"Ry neg Rx 4 copy 4 2 roll 2 copy 6 2 roll 2 copy (M) print ASYy ASYx (L) print ASYy add ASYx (L) print add ASYy add ASYx (L) print add ASYy ASYx (c) print} bind def}");
}
tex.verbatimline(read<string>(s,i)+"\\ %");
}
tex.epilogue(true);
tex.close();
int status=opentex(texname,prefix,!xe);
string pdfname,psname2;
bool keep=getSetting<bool>("keep");
if(!status) {
if(xe) {
string psdriver=getSetting<string>("psdriver");
pdfname=auxname(prefix,"pdf");
psname2=auxname(prefix+"_","ps");
if(!fs::exists(pdfname)) return new array(n);
std::ofstream ps(psname.c_str(),std::ios::binary);
if(!ps) cannotwrite(psname);
showpath(ps);
mem::vector<string> cmd;
cmd.push_back(getSetting<string>("gs"));
cmd.push_back("-q");
cmd.push_back("-dNoOutputFonts");
cmd.push_back("-dNOPAUSE");
cmd.push_back("-dBATCH");
if(safe) cmd.push_back("-dSAFER");
cmd.push_back("-sDEVICE="+psdriver);
cmd.push_back("-sOutputFile="+psname2);
cmd.push_back(pdfname);
status=System(cmd,0,true,"gs");
std::ifstream in(psname2.c_str());
ps << in.rdbuf();
ps.close();
} else {
if(!fs::exists(dviname)) return new array(n);
mem::vector<string> dcmd;
dcmd.push_back(getSetting<string>("dvips"));
dcmd.push_back("-R");
dcmd.push_back("-Pdownload35");
dcmd.push_back("-D600");
push_split(dcmd,getSetting<string>("dvipsOptions"));
if(verbose <= 2) dcmd.push_back("-q");
dcmd.push_back("-o"+psname);
dcmd.push_back(dviname);
status=System(dcmd,0,true,"dvips");
}
} else
error("texpath failed");
if(!keep) { // Delete temporary files.
unlink(texname.c_str());
if(!getSetting<bool>("keepaux"))
unlink(auxname(prefix,"aux").c_str());
unlink(auxname(prefix,"log").c_str());
unlink(xe ? pdfname.c_str() : dviname.c_str());
if(settings::context(texengine)) {
unlink(auxname(prefix,"top").c_str());
unlink(auxname(prefix,"tua").c_str());
unlink(auxname(prefix,"tuc").c_str());
unlink(auxname(prefix,"tui").c_str());
}
}
return xe ? readpath(psname,keep,0.1) : readpath(psname,keep,0.12,-1.0);
}
patharray2 *textpath(stringarray *s, penarray *p)
{
size_t n=checkArrays(s,p);
if(n == 0) return new array(0);
string prefix=cleanpath(outname());
string outputname=auxname(prefix,getSetting<string>("textoutformat"));
string textname=auxname(prefix,getSetting<string>("textextension"));
std::ofstream text(textname.c_str());
if(!text) cannotwrite(textname);
for(size_t i=0; i < n; ++i) {
text << getSetting<string>("textprologue") << newl
<< read<pen>(p,i).Font() << newl
<< read<string>(s,i) << newl
<< getSetting<string>("textepilogue") << endl;
}
text.close();
string psname=auxname(prefix,"ps");
std::ofstream ps(psname.c_str());
if(!ps) cannotwrite(psname);
showpath(ps);
mem::vector<string> cmd;
cmd.push_back(getSetting<string>("textcommand"));
push_split(cmd,getSetting<string>("textcommandOptions"));
cmd.push_back(textname);
iopipestream typesetter(cmd);
typesetter.block(true,false);
mem::vector<string> cmd2;
cmd2.push_back(getSetting<string>("gs"));
cmd2.push_back("-q");
cmd2.push_back("-dNoOutputFonts");
cmd2.push_back("-dNOPAUSE");
cmd2.push_back("-dBATCH");
cmd2.push_back("-P");
if(safe) cmd2.push_back("-dSAFER");
cmd2.push_back("-sDEVICE="+getSetting<string>("psdriver"));
cmd2.push_back("-sOutputFile=-");
cmd2.push_back("-");
iopipestream gs(cmd2,"gs","Ghostscript");
gs.block(false,false);
// TODO: Simplify by connecting the pipes directly.
for(;;) {
string out;
if(typesetter.isopen()) {
typesetter >> out;
if(!out.empty()) gs << out;
else if(!typesetter.running()) {
typesetter.pipeclose();
gs.eof();
}
}
string out2;
gs >> out2;
if(out2.empty() && !gs.running()) break;
ps << out2;
}
ps.close();
if(verbose > 2) cout << endl;
bool keep=getSetting<bool>("keep");
if(!keep) // Delete temporary files.
unlink(textname.c_str());
return readpath(psname,keep,0.1);
}
patharray *_strokepath(path g, pen p=CURRENTPEN)
{
array *P=new array(0);
if(g.size() == 0) return P;
string prefix=cleanpath(outname());
string psname=auxname(prefix,"ps");
bbox b;
psfile ps(psname,false);
ps.prologue(b);
ps.verbatimline(ASYx);
ps.verbatimline(ASYy);
ps.verbatimline("/stroke {"+ASYinit+pathforall+"} bind def");
ps.resetpen();
ps.setpen(p);
ps.write(g);
ps.strokepath();
ps.stroke(p);
ps.verbatimline("(M) "+currentpoint);
ps.epilogue();
ps.close();
array *a=readpath(psname,getSetting<bool>("keep"));
return a->size() > 0 ? read<array *>(a,0) : a;
}