summaryrefslogtreecommitdiff
path: root/Build/source/utils/asymptote/drawlabel.cc
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/utils/asymptote/drawlabel.cc')
-rw-r--r--Build/source/utils/asymptote/drawlabel.cc310
1 files changed, 310 insertions, 0 deletions
diff --git a/Build/source/utils/asymptote/drawlabel.cc b/Build/source/utils/asymptote/drawlabel.cc
new file mode 100644
index 00000000000..b6f0590ae1c
--- /dev/null
+++ b/Build/source/utils/asymptote/drawlabel.cc
@@ -0,0 +1,310 @@
+/*****
+ * drawlabel.cc
+ * John Bowman 2003/04/07
+ *
+ * Add a label to a picture.
+ *****/
+
+#include <sstream>
+
+#include "drawlabel.h"
+#include "settings.h"
+#include "util.h"
+#include "lexical.h"
+
+using namespace settings;
+
+namespace camp {
+
+string texready=string("(Please type a command or say `\\end')\n*");
+pen drawElement::lastpen;
+
+void drawLabel::labelwarning(const char *action)
+{
+ cerr << "warning: label \"" << label
+ << "\" " << action << " to avoid overwriting" << endl;
+}
+
+int drawLabel::wait(iopipestream &tex, const char *s, const char **abort,
+ bool ignore)
+{
+ int rc=tex.wait(s,abort);
+ if(rc > 0) {
+ if(fataltex[rc-1]) {
+ tex.pipeclose();
+ ignore=false;
+ } else {
+ tex << "\n";
+ tex.wait(s,abort);
+ tex << "\n";
+ tex.wait(s,abort);
+ }
+ if(!ignore) {
+ string s=tex.message();
+ tex.shred();
+ reportError(s);
+ }
+ }
+ tex.shred();
+ return rc;
+}
+
+bool drawLabel::texbounds(iopipestream& tex, string& s, const char **abort,
+ bool warn)
+{
+ string texbuf;
+ tex << "\\setbox\\ASYbox=\\hbox{" << stripblanklines(s) << "}\n\n";
+ int rc=wait(tex,texready.c_str(),abort,getSetting<bool>("inlinetex"));
+ if(rc) {
+ tex << "\\show 0\n";
+ tex.wait("\n*");
+ if(warn) {
+ if(getSetting<bool>("debug")) {
+ ostringstream buf;
+ buf << "Cannot determine size of label \"" << s << "\"";
+ reportWarning(buf);
+ }
+ return false;
+ }
+ return false;
+ }
+
+ tex << "\\showthe\\wd\\ASYbox\n";
+ tex >> texbuf;
+
+ string cannotread="Cannot read label ";
+ if(texbuf[0] == '>' && texbuf[1] == ' ')
+ try {
+ width=lexical::cast<double>(texbuf.c_str()+2,true)*tex2ps;
+ } catch(lexical::bad_cast&) {
+ reportError(cannotread+"width");
+ }
+ else reportError(cannotread+"width");
+ tex << "\n";
+ wait(tex,"\n*",abort);
+
+ tex << "\\showthe\\ht\\ASYbox\n";
+ tex >> texbuf;
+ if(texbuf[0] == '>' && texbuf[1] == ' ')
+ try {
+ height=lexical::cast<double>(texbuf.c_str()+2,true)*tex2ps;
+ } catch(lexical::bad_cast&) {
+ reportError(cannotread+"height");
+ }
+ else reportError(cannotread+"height");
+ tex << "\n";
+ wait(tex,"\n*",abort);
+
+ tex << "\\showthe\\dp\\ASYbox\n";
+ tex >> texbuf;
+ if(texbuf[0] == '>' && texbuf[1] == ' ')
+ try {
+ depth=lexical::cast<double>(texbuf.c_str()+2,true)*tex2ps;
+ } catch(lexical::bad_cast&) {
+ reportError(cannotread+"depth");
+ }
+ else reportError(cannotread+"depth");
+ tex << "\n";
+ wait(tex,"\n*",abort);
+
+ return true;
+}
+
+inline double urand()
+{
+ static const double factor=2.0/RAND_MAX;
+ return rand()*factor-1.0;
+}
+
+void drawLabel::getbounds(iopipestream& tex, const string& texengine)
+{
+ if(havebounds) return;
+ havebounds=true;
+
+ const char **abort=texabort(texengine);
+ bool Latex=latex(texengine);
+
+ if(Latex) {
+ if(setlatexfont(tex,pentype,lastpen))
+ wait(tex,"\n*",abort);
+ }
+ if(settexfont(tex,pentype,lastpen,Latex))
+ wait(tex,"\n*",abort);
+
+ lastpen=pentype;
+
+ bool nullsize=size.empty();
+ if(!texbounds(tex,label,abort,nullsize) && !nullsize)
+ texbounds(tex,size,abort,false);
+ enabled=true;
+
+ Align=inverse(T)*align;
+ double scale0=max(fabs(Align.getx()),fabs(Align.gety()));
+ if(scale0) Align *= 0.5/scale0;
+ Align -= pair(0.5,0.5);
+ double Depth=(pentype.Baseline() == NOBASEALIGN) ? depth :
+ -depth*Align.gety();
+ texAlign=Align;
+ const double vertical=height+depth;
+ if(Depth > 0) texAlign += pair(0.0,Depth/vertical);
+ Align.scale(width,vertical);
+ Align += pair(0.0,Depth-depth);
+ Align=T*Align;
+}
+
+void drawLabel::bounds(bbox& b, iopipestream& tex, boxvector& labelbounds,
+ bboxlist&)
+{
+ string texengine=getSetting<string>("tex");
+ if(texengine == "none") {b += position; return;}
+
+ getbounds(tex,texengine);
+
+ // alignment point
+ pair p=position+Align;
+ const double vertical=height+depth;
+ const double fuzz=pentype.size()*0.1+0.3;
+ pair A=p+T*pair(-fuzz,-fuzz);
+ pair B=p+T*pair(-fuzz,vertical+fuzz);
+ pair C=p+T*pair(width+fuzz,vertical+fuzz);
+ pair D=p+T*pair(width+fuzz,-fuzz);
+
+ if(pentype.Overwrite() != ALLOW && label != "") {
+ size_t n=labelbounds.size();
+ box Box=box(A,B,C,D);
+ for(size_t i=0; i < n; i++) {
+ if(labelbounds[i].intersect(Box)) {
+ switch(pentype.Overwrite()) {
+ case SUPPRESS:
+ labelwarning("suppressed");
+ case SUPPRESSQUIET:
+ suppress=true;
+ return;
+ case MOVE:
+ labelwarning("moved");
+ default:
+ break;
+ }
+
+ pair Align=(align == pair(0,0)) ? unit(pair(urand(),urand())) :
+ unit(align);
+ double s=0.1*pentype.size();
+ double dx=0, dy=0;
+ if(Align.getx() > 0.1) dx=labelbounds[i].xmax()-Box.xmin()+s;
+ if(Align.getx() < -0.1) dx=labelbounds[i].xmin()-Box.xmax()-s;
+ if(Align.gety() > 0.1) dy=labelbounds[i].ymax()-Box.ymin()+s;
+ if(Align.gety() < -0.1) dy=labelbounds[i].ymin()-Box.ymax()-s;
+ pair offset=pair(dx,dy);
+ position += offset;
+ A += offset;
+ B += offset;
+ C += offset;
+ D += offset;
+ Box=box(A,B,C,D);
+ i=0;
+ }
+ }
+ labelbounds.resize(n+1);
+ labelbounds[n]=Box;
+ }
+
+ Box=bbox();
+ Box += A;
+ Box += B;
+ Box += C;
+ Box += D;
+
+ b += Box;
+}
+
+void drawLabel::checkbounds()
+{
+ if(!havebounds)
+ reportError("drawLabel::write called before bounds");
+}
+
+bool drawLabel::write(texfile *out, const bbox&)
+{
+ checkbounds();
+ if(suppress || pentype.invisible() || !enabled) return true;
+ out->setpen(pentype);
+ out->put(label,T,position,texAlign);
+ return true;
+}
+
+drawElement *drawLabel::transformed(const transform& t)
+{
+ return new drawLabel(label,size,t*T,t*position,
+ length(align)*unit(shiftless(t)*align),pentype);
+}
+
+void drawLabelPath::bounds(bbox& b, iopipestream& tex, boxvector&, bboxlist&)
+{
+ string texengine=getSetting<string>("tex");
+ if(texengine == "none") {b += position; return;}
+
+ getbounds(tex,texengine);
+ double L=p.arclength();
+
+ double s1,s2;
+ if(justify == "l") {
+ s1=0.0;
+ s2=width;
+ } else if(justify == "r") {
+ s1=L-width;
+ s2=L;
+ } else {
+ double s=0.5*L;
+ double h=0.5*width;
+ s1=s-h;
+ s2=s+h;
+ }
+
+ double Sx=shift.getx();
+ double Sy=shift.gety();
+ s1 += Sx;
+ s2 += Sx;
+
+ if(width > L || (!p.cyclic() && (s1 < 0 || s2 > L))) {
+ ostringstream buf;
+ buf << "Cannot fit label \"" << label << "\" to path";
+ reportError(buf);
+ }
+
+ path q=p.subpath(p.arctime(s1),p.arctime(s2));
+
+ b += q.bounds(Sy,Sy+height);
+ Box=b;
+}
+
+bool drawLabelPath::write(texfile *out, const bbox&)
+{
+ bbox b=Box;
+ double Hoffset=getSetting<bool>("inlinetex") ? b.right : b.left;
+ b.shift(pair(-Hoffset,-b.bottom));
+
+ checkbounds();
+ if(drawLabel::pentype.invisible()) return true;
+ out->setpen(drawLabel::pentype);
+ out->verbatimline("\\psset{unit=1pt}%");
+ out->verbatim("\\pstextpath[");
+ out->verbatim(justify);
+ out->verbatim("]");
+ out->writepair(shift);
+ out->verbatim("{\\pstVerb{");
+ out->beginraw();
+ writeshiftedpath(out);
+ out->endraw();
+ out->verbatim("}}{");
+ out->verbatim(label);
+ out->verbatimline("}");
+ return true;
+}
+
+drawElement *drawLabelPath::transformed(const transform& t)
+{
+ return new drawLabelPath(label,size,transpath(t),justify,shift,
+ transpen(t));
+}
+
+} //namespace camp