pax_global_header00006660000000000000000000000064126543460250014521gustar00rootroot0000000000000052 comment=12d4161bd25c0eda0d95a37437ba774b04a1eacb asymptote-2.37/000077500000000000000000000000001265434602500135015ustar00rootroot00000000000000asymptote-2.37/.gitignore000066400000000000000000000023421265434602500154720ustar00rootroot00000000000000### Compiled source *.o *.d *.d.* ### Compressed packages and Garbage Collector gc-* *.tar.gz *.tgz libatomic* ### Binaries asy xasy ### Version info *version.* revision.* /GUI/xasyVersion.py ### Runtime objects run*.cc run*.h ### Generated files newDrawing.asy /Makefile /doc/Makefile /doc/png/Makefile /doc/FAQ/asy-faq.* !/doc/FAQ/asy-faq.bfnn *.png *.gif *.pnm *.jpg *.prc *.svg *.roff /doc/png/*.html GUI/*.pyc /.wisdom /allsymbols.h /asy-keywords.el /asy.list /autom4te.cache/ /builtin.symbols.h /camp.output /camp.tab.cc /camp.tab.h /config.h /config.h.in /config.status /configure /doc/asy-latex.i* /doc/asy.1 /glrender.d.54461 /gsl.symbols.h /keywords.cc /lex.yy.cc /opsymbols.h /types.symbols.h *.dSYM ### TeX-related ## Core latex/pdflatex auxiliary files: *_.tex *+[0-9]*.tex *.aux *.lof *.log *.lot *.fls *.out *.toc *.tuc ## Intermediate documents: *.dvi *-converted-to.* # these rules might exclude image files for figures etc. *.ps *.eps *.pdf *.pre *.m9 *-[0-9].* /doc/**/asymptote.* !/doc/asymptote.texi /doc/options .asy_* ## Bibliography auxiliary files (bibtex/biblatex/biber): *.bbl *.bcf *.blg *-blx.aux *-blx.bib *.brf *.run.xml ### Data files *.obj *.dat *.pdb1 ### Debugging files core.* ### Backups *~ \#* .\#* asymptote-2.37/BUGS000066400000000000000000000003771265434602500141730ustar00rootroot00000000000000If you find a bug in Asymptote, please check (if possible) whether the bug is still present in the latest git developmental code before submitting a bug report. New bugs can be submitted using the Bug Tracking System at http://asymptote.sourceforge.net/ asymptote-2.37/Delaunay.cc000066400000000000000000000134111265434602500155520ustar00rootroot00000000000000// Robust version of Gilles Dumoulin's C++ port of Paul Bourke's // triangulation code available from // http://astronomy.swin.edu.au/~pbourke/papers/triangulate // Used with permission of Paul Bourke. // Segmentation fault and numerical robustness improvements by John C. Bowman #include #include "Delaunay.h" #include "predicates.h" inline double max(double a, double b) { return (a > b) ? a : b; } int XYZCompare(const void *v1, const void *v2) { double x1=((XYZ*)v1)->p[0]; double x2=((XYZ*)v2)->p[0]; if(x1 < x2) return(-1); else if(x1 > x2) return(1); else return(0); } inline double hypot2(double *x) { return x[0]*x[0]+x[1]*x[1]; } /////////////////////////////////////////////////////////////////////////////// // Triangulate(): // Triangulation subroutine // Takes as input NV vertices in array pxyz // Returned is a list of ntri triangular faces in the array v // These triangles are arranged in a consistent clockwise order. // The triangle array v should be allocated to 4 * nv // The vertex array pxyz must be big enough to hold 3 additional points. // By default, the array pxyz is automatically presorted and postsorted. /////////////////////////////////////////////////////////////////////////////// Int Triangulate(Int nv, XYZ pxyz[], ITRIANGLE v[], Int &ntri, bool presort, bool postsort) { Int emax = 200; if(presort) qsort(pxyz,nv,sizeof(XYZ),XYZCompare); else postsort=false; /* Allocate memory for the completeness list, flag for each triangle */ Int trimax = 4 * nv; Int *complete = new Int[trimax]; /* Allocate memory for the edge list */ IEDGE *edges = new IEDGE[emax]; /* Find the maximum and minimum vertex bounds. This is to allow calculation of the bounding triangle */ double xmin = pxyz[0].p[0]; double ymin = pxyz[0].p[1]; double xmax = xmin; double ymax = ymin; for(Int i = 1; i < nv; i++) { XYZ *pxyzi=pxyz+i; double x=pxyzi->p[0]; double y=pxyzi->p[1]; if (x < xmin) xmin = x; if (x > xmax) xmax = x; if (y < ymin) ymin = y; if (y > ymax) ymax = y; } double dx = xmax - xmin; double dy = ymax - ymin; /* Set up the supertriangle. This is a triangle which encompasses all the sample points. The supertriangle coordinates are added to the end of the vertex list. The supertriangle is the first triangle in the triangle list. */ static const double margin=0.01; double xmargin=margin*dx; double ymargin=margin*dy; pxyz[nv+0].p[0] = xmin-xmargin; pxyz[nv+0].p[1] = ymin-ymargin; pxyz[nv+1].p[0] = xmin-xmargin; pxyz[nv+1].p[1] = ymax+ymargin+dx; pxyz[nv+2].p[0] = xmax+xmargin+dy; pxyz[nv+2].p[1] = ymin-ymargin; v->p1 = nv; v->p2 = nv+1; v->p3 = nv+2; complete[0] = false; ntri = 1; /* Include each point one at a time into the existing mesh */ for(Int i = 0; i < nv; i++) { Int nedge = 0; double *d=pxyz[i].p; /* Set up the edge buffer. If the point d lies inside the circumcircle then the three edges of that triangle are added to the edge buffer and that triangle is removed. */ for(Int j = 0; j < ntri; j++) { if(complete[j]) continue; ITRIANGLE *vj=v+j; double *a=pxyz[vj->p1].p; double *b=pxyz[vj->p2].p; double *c=pxyz[vj->p3].p; if(incircle(a,b,c,d) <= 0.0) { // Point d is inside or on circumcircle /* Check that we haven't exceeded the edge list size */ if(nedge + 3 >= emax) { emax += 100; IEDGE *p_EdgeTemp = new IEDGE[emax]; for (Int i = 0; i < nedge; i++) { p_EdgeTemp[i] = edges[i]; } delete[] edges; edges = p_EdgeTemp; } ITRIANGLE *vj=v+j; Int p1=vj->p1; Int p2=vj->p2; Int p3=vj->p3; edges[nedge].p1 = p1; edges[nedge].p2 = p2; edges[++nedge].p1 = p2; edges[nedge].p2 = p3; edges[++nedge].p1 = p3; edges[nedge].p2 = p1; ++nedge; ntri--; v[j] = v[ntri]; complete[j] = complete[ntri]; j--; } else { double A=hypot2(a); double B=hypot2(b); double C=hypot2(c); double a0=orient2d(a,b,c); // Is d[0] > xc+r for circumcircle abc of radius r about (xc,yc)? if(d[0]*a0 < 0.5*orient2d(A,a[1],B,b[1],C,c[1])) complete[j]= incircle(a[0]*a0,a[1]*a0,b[0]*a0,b[1]*a0,c[0]*a0,c[1]*a0, d[0]*a0,0.5*orient2d(a[0],A,b[0],B,c[0],C)) > 0.0; } } /* Tag multiple edges Note: if all triangles are specified anticlockwise then all interior edges are opposite pointing in direction. */ for(Int j = 0; j < nedge - 1; j++) { for(Int k = j + 1; k < nedge; k++) { if((edges[j].p1 == edges[k].p2) && (edges[j].p2 == edges[k].p1)) { edges[j].p1 = -1; edges[j].p2 = -1; edges[k].p1 = -1; edges[k].p2 = -1; } } } /* Form new triangles for the current point Skipping over any tagged edges. All edges are arranged in clockwise order. */ for(Int j = 0; j < nedge; j++) { if(edges[j].p1 < 0 || edges[j].p2 < 0) continue; v[ntri].p1 = edges[j].p1; v[ntri].p2 = edges[j].p2; v[ntri].p3 = i; complete[ntri] = false; ntri++; assert(ntri < trimax); } } /* Remove triangles with supertriangle vertices These are triangles which have a vertex number greater than nv */ for(Int i = 0; i < ntri; i++) { ITRIANGLE *vi=v+i; if(vi->p1 >= nv || vi->p2 >= nv || vi->p3 >= nv) { ntri--; *vi = v[ntri]; i--; } } delete[] edges; delete[] complete; if(postsort) { for(Int i = 0; i < ntri; i++) { ITRIANGLE *vi=v+i; vi->p1=pxyz[vi->p1].i; vi->p2=pxyz[vi->p2].i; vi->p3=pxyz[vi->p3].i; } } return 0; } asymptote-2.37/Delaunay.h000066400000000000000000000006001265434602500154100ustar00rootroot00000000000000#ifndef DELAUNAY_H #define DELAUNAY_H #include #include #include #include #include "common.h" struct ITRIANGLE{ Int p1, p2, p3; }; struct IEDGE{ Int p1, p2; }; struct XYZ{ double p[2]; // {x,y} Int i; }; Int Triangulate(Int nv, XYZ pxyz[], ITRIANGLE v[], Int &ntri, bool presort=true, bool postsort=true); #endif asymptote-2.37/EnvVarUpdate.nsh000077500000000000000000000246101265434602500165650ustar00rootroot00000000000000/** * EnvVarUpdate.nsh * : Environmental Variables: append, prepend, and remove entries * * WARNING: If you use StrFunc.nsh header then include it before this file * with all required definitions. This is to avoid conflicts * * Usage: * ${EnvVarUpdate} "ResultVar" "EnvVarName" "Action" "RegLoc" "PathString" * * Credits: * Version 1.0 * * Cal Turney (turnec2) * * Amir Szekely (KiCHiK) and e-circ for developing the forerunners of this * function: AddToPath, un.RemoveFromPath, AddToEnvVar, un.RemoveFromEnvVar, * WriteEnvStr, and un.DeleteEnvStr * * Diego Pedroso (deguix) for StrTok * * Kevin English (kenglish_hi) for StrContains * * Hendri Adriaens (Smile2Me), Diego Pedroso (deguix), and Dan Fuhry * (dandaman32) for StrReplace * * Version 1.1 (compatibility with StrFunc.nsh) * * techtonik * * http://nsis.sourceforge.net/Environmental_Variables:_append%2C_prepend%2C_and_remove_entries * */ !ifndef ENVVARUPDATE_FUNCTION !define ENVVARUPDATE_FUNCTION !verbose push !verbose 3 !include "LogicLib.nsh" !include "WinMessages.NSH" !include "StrFunc.nsh" ; ---- Fix for conflict if StrFunc.nsh is already includes in main file ----------------------- !macro _IncludeStrFunction StrFuncName !ifndef ${StrFuncName}_INCLUDED ${${StrFuncName}} !endif !ifndef Un${StrFuncName}_INCLUDED ${Un${StrFuncName}} !endif !define un.${StrFuncName} "${Un${StrFuncName}}" !macroend !insertmacro _IncludeStrFunction StrTok !insertmacro _IncludeStrFunction StrStr !insertmacro _IncludeStrFunction StrRep ; ---------------------------------- Macro Definitions ---------------------------------------- !macro _EnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString Push "${EnvVarName}" Push "${Action}" Push "${RegLoc}" Push "${PathString}" Call EnvVarUpdate Pop "${ResultVar}" !macroend !define EnvVarUpdate '!insertmacro "_EnvVarUpdateConstructor"' !macro _unEnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString Push "${EnvVarName}" Push "${Action}" Push "${RegLoc}" Push "${PathString}" Call un.EnvVarUpdate Pop "${ResultVar}" !macroend !define un.EnvVarUpdate '!insertmacro "_unEnvVarUpdateConstructor"' ; ---------------------------------- Macro Definitions end------------------------------------- ;----------------------------------- EnvVarUpdate start---------------------------------------- !define hklm_all_users 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' !define hkcu_current_user 'HKCU "Environment"' !macro EnvVarUpdate UN Function ${UN}EnvVarUpdate Push $0 Exch 4 Exch $1 Exch 3 Exch $2 Exch 2 Exch $3 Exch Exch $4 Push $5 Push $6 Push $7 Push $8 Push $9 Push $R0 /* After this point: ------------------------- $0 = ResultVar (returned) $1 = EnvVarName (input) $2 = Action (input) $3 = RegLoc (input) $4 = PathString (input) $5 = Orig EnvVar (read from registry) $6 = Len of $0 (temp) $7 = tempstr1 (temp) $8 = Entry counter (temp) $9 = tempstr2 (temp) $R0 = tempChar (temp) */ ; Step 1: Read contents of EnvVarName from RegLoc ; ; Check for empty EnvVarName ${If} $1 == "" SetErrors DetailPrint "ERROR: EnvVarName is blank" Goto EnvVarUpdate_Restore_Vars ${EndIf} ; Check for valid Action ${If} $2 != "A" ${AndIf} $2 != "P" ${AndIf} $2 != "R" SetErrors DetailPrint "ERROR: Invalid Action - must be A, P, or R" Goto EnvVarUpdate_Restore_Vars ${EndIf} ${If} $3 == HKLM ReadRegStr $5 ${hklm_all_users} $1 ; Get EnvVarName from all users into $5 ${ElseIf} $3 == HKCU ReadRegStr $5 ${hkcu_current_user} $1 ; Read EnvVarName from current user into $5 ${Else} SetErrors DetailPrint 'ERROR: Action is [$3] but must be "HKLM" or HKCU"' Goto EnvVarUpdate_Restore_Vars ${EndIf} ; Check for empty PathString ${If} $4 == "" SetErrors DetailPrint "ERROR: PathString is blank" Goto EnvVarUpdate_Restore_Vars ${EndIf} ; Make sure we've got some work to do ${If} $5 == "" ${AndIf} $2 == "R" SetErrors DetailPrint "$1 is empty - Nothing to remove" Goto EnvVarUpdate_Restore_Vars ${EndIf} ; Step 2: Scrub EnvVar ; StrCpy $0 $5 ; Copy the contents to $0 ; Remove spaces around semicolons (NOTE: spaces before the 1st entry or ; after the last one are not removed here but instead in Step 3) ${If} $0 != "" ; If EnvVar is not empty ... ${Do} ${${UN}StrStr} $7 $0 " ;" ${If} $7 == "" ${ExitDo} ${EndIf} ${${UN}StrRep} $0 $0 " ;" ";" ; Remove ';' ${Loop} ${Do} ${${UN}StrStr} $7 $0 "; " ${If} $7 == "" ${ExitDo} ${EndIf} ${${UN}StrRep} $0 $0 "; " ";" ; Remove ';' ${Loop} ${Do} ${${UN}StrStr} $7 $0 ";;" ${If} $7 == "" ${ExitDo} ${EndIf} ${${UN}StrRep} $0 $0 ";;" ";" ${Loop} ; Remove a leading or trailing semicolon from EnvVar StrCpy $7 $0 1 0 ${If} $7 == ";" StrCpy $0 $0 "" 1 ; Change ';' to '' ${EndIf} StrLen $6 $0 IntOp $6 $6 - 1 StrCpy $7 $0 1 $6 ${If} $7 == ";" StrCpy $0 $0 $6 ; Change ';' to '' ${EndIf} ; DetailPrint "Scrubbed $1: [$0]" ; Uncomment to debug ${EndIf} /* Step 3. Remove all instances of the target path/string (even if "A" or "P") $6 = bool flag (1 = found and removed PathString) $7 = a string (e.g. path) delimited by semicolon(s) $8 = entry counter starting at 0 $9 = copy of $0 $R0 = tempChar */ ${If} $5 != "" ; If EnvVar is not empty ... StrCpy $9 $0 StrCpy $0 "" StrCpy $8 0 StrCpy $6 0 ${Do} ${${UN}StrTok} $7 $9 ";" $8 "0" ; $7 = next entry, $8 = entry counter ${If} $7 == "" ; If we've run out of entries, ${ExitDo} ; were done ${EndIf} ; ; Remove leading and trailing spaces from this entry (critical step for Action=Remove) ${Do} StrCpy $R0 $7 1 ${If} $R0 != " " ${ExitDo} ${EndIf} StrCpy $7 $7 "" 1 ; Remove leading space ${Loop} ${Do} StrCpy $R0 $7 1 -1 ${If} $R0 != " " ${ExitDo} ${EndIf} StrCpy $7 $7 -1 ; Remove trailing space ${Loop} ${If} $7 == $4 ; If string matches, remove it by not appending it StrCpy $6 1 ; Set 'found' flag ${ElseIf} $7 != $4 ; If string does NOT match ${AndIf} $0 == "" ; and the 1st string being added to $0, StrCpy $0 $7 ; copy it to $0 without a prepended semicolon ${ElseIf} $7 != $4 ; If string does NOT match ${AndIf} $0 != "" ; and this is NOT the 1st string to be added to $0, StrCpy $0 $0;$7 ; append path to $0 with a prepended semicolon ${EndIf} ; IntOp $8 $8 + 1 ; Bump counter ${Loop} ; Check for duplicates until we run out of paths ${EndIf} ; Step 4: Perform the requested Action ; ${If} $2 != "R" ; If Append or Prepend ${If} $6 == 1 ; And if we found the target DetailPrint "Target is already present in $1. It will be removed and" ${EndIf} ${If} $0 == "" ; If EnvVar is (now) empty StrCpy $0 $4 ; just copy PathString to EnvVar ${If} $6 == 0 ; If found flag is either 0 ${OrIf} $6 == "" ; or blank (if EnvVarName is empty) DetailPrint "$1 was empty and has been updated with the target" ${EndIf} ${ElseIf} $2 == "A" ; If Append (and EnvVar is not empty), StrCpy $0 $0;$4 ; append PathString ${If} $6 == 1 DetailPrint "appended to $1" ${Else} DetailPrint "Target was appended to $1" ${EndIf} ${Else} ; If Prepend (and EnvVar is not empty), StrCpy $0 $4;$0 ; prepend PathString ${If} $6 == 1 DetailPrint "prepended to $1" ${Else} DetailPrint "Target was prepended to $1" ${EndIf} ${EndIf} ${Else} ; If Action = Remove ${If} $6 == 1 ; and we found the target DetailPrint "Target was found and removed from $1" ${Else} DetailPrint "Target was NOT found in $1 (nothing to remove)" ${EndIf} ${If} $0 == "" DetailPrint "$1 is now empty" ${EndIf} ${EndIf} ; Step 5: Update the registry at RegLoc with the updated EnvVar and announce the change ; ClearErrors ${If} $3 == HKLM WriteRegExpandStr ${hklm_all_users} $1 $0 ; Write it in all users section ${ElseIf} $3 == HKCU WriteRegExpandStr ${hkcu_current_user} $1 $0 ; Write it to current user section ${EndIf} IfErrors 0 +4 MessageBox MB_OK|MB_ICONEXCLAMATION "Could not write updated $1 to $3" DetailPrint "Could not write updated $1 to $3" Goto EnvVarUpdate_Restore_Vars ; "Export" our change SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 EnvVarUpdate_Restore_Vars: ; ; Restore the user's variables and return ResultVar Pop $R0 Pop $9 Pop $8 Pop $7 Pop $6 Pop $5 Pop $4 Pop $3 Pop $2 Pop $1 Push $0 ; Push my $0 (ResultVar) Exch Pop $0 ; Restore his $0 FunctionEnd !macroend ; EnvVarUpdate UN !insertmacro EnvVarUpdate "" !insertmacro EnvVarUpdate "un." ;----------------------------------- EnvVarUpdate end---------------------------------------- !verbose pop !endif asymptote-2.37/GUI/000077500000000000000000000000001265434602500141255ustar00rootroot00000000000000asymptote-2.37/GUI/CubicBezier.py000077500000000000000000000071211265434602500166710ustar00rootroot00000000000000#!/usr/bin/env python ########################################################################### # # Convert a Bezier curve to a polyline # # Once Tk supports "RawCurves" this will not be needed. # # # Author: Orest Shardt # Created: June 29, 2007 # ########################################################################### import math def norm(vector): """Return the norm of a vector""" return math.sqrt(vector[0]**2+vector[1]**2) def splitLine(end0,end1,t): """Split a line at the distance t, with t in (0,1)""" return (end0[0]+t*(end1[0]-end0[0]),end0[1]+t*(end1[1]-end0[1])) def splitBezier(node0,control0,control1,node1,t): """Find the nodes and control points for the segments of a Bezier curve split at t""" a = splitLine(node0,control0,t) b = splitLine(control0,control1,t) c = splitLine(control1,node1,t) d = splitLine(a,b,t) e = splitLine(b,c,t) f = splitLine(d,e,t)#this is the point on the curve at t return ([node0,a,d,f],[f,e,c,node1]) def BezierWidth(node0,control0,control1,node1): """Compute the distance of the control points from the node-node axis""" deltax = node1[0] - node0[0] deltay = node1[1] - node0[1] length = norm((deltax,deltay)) if length == 0: y1 = control0[1]-node0[1] y2 = control1[1]-node0[1] else: cosine = deltax/length sine = deltay/length y1 = cosine*(control0[1]-node0[1])-sine*(control0[0]-node0[0]) y2 = cosine*(control1[1]-node0[1])-sine*(control1[0]-node0[0]) if y1*y2 >= 0: #same sign return max(abs(y1),abs(y2)) else: #opposite sign return abs(y1)+abs(y2) #If the above algorithm fails, this one will work, but it is far from elegant #def computeIntermediates(steps,node0,control0,control1,node1): #pointList = [] #for a in range(0,100,100/steps)+[100]: #t = a/100.0 #t1 = 1-t #x = node0[0]*t1**3+3*control0[0]*t*t1**2+3*control1[0]*t**2*t1+node1[0]*t**3 #y = node0[1]*t1**3+3*control0[1]*t*t1**2+3*control1[1]*t**2*t1+node1[1]*t**3 #pointList.append((x,y)) #return pointList #def makeBezier(steps,node0,control0,control1,node1): #if len(node0)!=2 or len(control0)!=2 or len(control1)!=2 or len(node1)!=2: #return -1 #else: #return [node0]+computeIntermediates(steps,node0,control0,control1,node1)+[node1] def makeBezierIntermediates(node0,control0,control1,node1,epsilon): """Find the points, excluding node0, to be used as the line segment endpoints""" if(BezierWidth(node0,control0,control1,node1) <= epsilon): return [node1] else: splitUp = splitBezier(node0,control0,control1,node1,0.5) return makeBezierIntermediates(*splitUp[0]+[epsilon])+makeBezierIntermediates(*splitUp[1]+[epsilon]) def makeBezier(node0,control0,control1,node1,epsilon=1): """Return the vertices to be used in the polyline representation of a Bezier curve""" return [node0]+makeBezierIntermediates(node0,control0,control1,node1,epsilon) if __name__ == '__main__': pointList = makeBezier((-80,0),(-150,40),(150,120),(80,0),0.5) from timeit import Timer t = Timer('makeBezier((-80,0),(-40,-40),(40,120),(80,0),1)','from __main__ import makeBezier') print pointList print len(pointList) iterations = 1000 time = t.timeit(iterations) print "%d iterations took %f seconds (%f ms for each)."%(iterations,time,1000.0*time/iterations) points = [] for point in pointList: points.append(point[0]) points.append(-point[1]) from Tkinter import * root = Tk() canv = Canvas(root,scrollregion=(-100,-100,100,100)) canv.pack() canv.create_line(points) for point in pointList: canv.create_oval(point[0],-point[1],point[0],-point[1],fill='red',outline='red') root.mainloop() asymptote-2.37/GUI/UndoRedoStack.py000077500000000000000000000056501265434602500172150ustar00rootroot00000000000000#!/usr/bin/env python ########################################################################### # # UndoRedoStack implements the usual undo/redo capabilities of a GUI # # Author: Orest Shardt # Created: July 23, 2007 # ########################################################################### class action: def __init__(self,act,inv): self.act = act self.inv = inv def undo(self): #print "Undo:",self self.inv() def redo(self): #print "Redo:",self self.act() def __str__(self): return "A generic action" class beginActionGroup: pass class endActionGroup: pass class actionStack: def __init__(self): self.clear() def add(self,action): self.undoStack.append(action) #print "Added",action self.redoStack = [] def undo(self): if len(self.undoStack) > 0: op = self.undoStack.pop() if op is beginActionGroup: level = 1 self.redoStack.append(endActionGroup) while level > 0: op=self.undoStack.pop() if op is endActionGroup: level -= 1 self.redoStack.append(beginActionGroup) elif op is beginActionGroup: level += 1 self.redoStack.append(endActionGroup) else: op.undo() self.redoStack.append(op) elif op is endActionGroup: raise Exception,"endActionGroup without previous beginActionGroup" else: self.redoStack.append(op) op.undo() #print "undid",op else: pass #print "nothing to undo" def redo(self): if len(self.redoStack) > 0: op = self.redoStack.pop() if op is beginActionGroup: level = 1 self.undoStack.append(endActionGroup) while level > 0: op = self.redoStack.pop() if op is endActionGroup: level -= 1 self.undoStack.append(beginActionGroup) elif op is beginActionGroup: level += 1 self.undoStack.append(endActionGroup) else: op.redo() self.undoStack.append(op) elif op is endActionGroup: raise Exception,"endActionGroup without previous beginActionGroup" else: self.undoStack.append(op) op.redo() #print "redid",op else: pass #print "nothing to redo" def setCommitLevel(self): self.commitLevel = len(self.undoStack) def changesMade(self): if len(self.undoStack) != self.commitLevel: return True else: return False def clear(self): self.redoStack = [] self.undoStack = [] self.commitLevel = 0 if __name__=='__main__': import sys def opq(): print "action1" def unopq(): print "inverse1" q = action(opq,unopq) w = action(lambda:sys.stdout.write("action2\n"),lambda:sys.stdout.write("inverse2\n")) e = action(lambda:sys.stdout.write("action3\n"),lambda:sys.stdout.write("inverse3\n")) s = actionStack() s.add(q) s.add(w) s.add(e) asymptote-2.37/GUI/xasy.py000077500000000000000000000015151265434602500154700ustar00rootroot00000000000000#!/usr/bin/env python ########################################################################### # # xasy implements a graphical interface for Asymptote. # # # Author: Orest Shardt # Created: June 29, 2007 # ############################################################################ import getopt,sys,signal from Tkinter import * import xasyMainWin signal.signal(signal.SIGINT,signal.SIG_IGN) root = Tk() mag = 1.0 try: opts,args = getopt.getopt(sys.argv[1:],"x:") if(len(opts)>=1): mag = float(opts[0][1]) except: print "Invalid arguments." print "Usage: xasy.py [-x magnification] [filename]" sys.exit(1) if(mag <= 0.0): print "Magnification must be positive." sys.exit(1) if(len(args)>=1): app = xasyMainWin.xasyMainWin(root,args[0],mag) else: app = xasyMainWin.xasyMainWin(root,magnification=mag) root.mainloop() asymptote-2.37/GUI/xasy2asy.py000077500000000000000000000616121265434602500162730ustar00rootroot00000000000000#!/usr/bin/env python ########################################################################### # # xasy2asy provides a Python interface to Asymptote # # # Author: Orest Shardt # Created: June 29, 2007 # ########################################################################### import sys,os,signal,threading from subprocess import * from string import * import xasyOptions import Queue from Tkinter import * from tempfile import mkdtemp # PIL support is now mandatory due to rotations try: from PIL import ImageTk from PIL import Image except: pass import CubicBezier quickAsyFailed = True global AsyTempDir console=None def startQuickAsy(): global quickAsy global quickAsyFailed global AsyTempDir global fout,fin if quickAsyRunning(): return try: fout.close() quickAsy.wait() except: pass try: quickAsyFailed = False if os.name == "nt": AsyTempDir=mkdtemp(prefix="asy_", dir="./") else: AsyTempDir=mkdtemp(prefix="asy_")+os.sep if sys.platform[:3] == 'win': quickAsy=Popen([xasyOptions.options['asyPath'],"-noV","-multiline","-q", "-o"+AsyTempDir,"-inpipe=0","-outpipe=2"],stdin=PIPE,stderr=PIPE) fout=quickAsy.stdin fin=quickAsy.stderr else: (rx,wx) = os.pipe() (ra,wa) = os.pipe() quickAsy=Popen([xasyOptions.options['asyPath'],"-noV","-multiline","-q", "-o"+AsyTempDir,"-inpipe="+str(rx),"-outpipe="+str(wa)]) fout=os.fdopen(wx,'w') fin=os.fdopen(ra,'r') if quickAsy.returncode != None: quickAsyFailed = True except: quickAsyFailed = True def stopQuickAsy(): if quickAsyRunning(): fout.write("exit;\n"); def getAsyTempDir(): return AsyTempDir def quickAsyRunning(): if quickAsyFailed or quickAsy.returncode != None: return False else: return True def asyExecute(command): if not quickAsyRunning(): startQuickAsy() fout.write(command) def closeConsole(event): global console console = None def consoleOutput(line): global console global ctl if console == None: ctl=Toplevel() ctl.title("Asymptote Console") ctl.bind("",closeConsole) yscrollbar=Scrollbar(ctl) yscrollbar.pack(side=RIGHT,fill=Y) console=Text(ctl,yscrollcommand=yscrollbar.set) console.pack() yscrollbar.config(command=console.yview) console.insert(END,line) ctl.lift() class asyTransform: """A python implementation of an asy transform""" def __init__(self,initTuple,delete=False): """Initialize the transform with a 6 entry tuple""" if type(initTuple) == type((0,)) and len(initTuple) == 6: self.t = initTuple self.x,self.y,self.xx,self.xy,self.yx,self.yy = initTuple self.deleted = delete else: raise Exception,"Illegal initializer for asyTransform" def getCode(self): """Obtain the asy code that represents this transform""" if self.deleted: return str(self.t) + ", false" else: return str(self.t) def scale(self,s): return asyTransform((0,0,s,0,0,s))*self def __str__(self): """Equivalent functionality to getCode(). It allows the expression str(asyTransform) to be meaningful.""" return self.getCode() def __mul__(self,other): """Define multiplication of transforms as composition.""" if type(other)==type((0,)): if len(other) == 6: return self*asyTransform(other) elif len(other) == 2: return ((self.t[0]+self.t[2]*other[0]+self.t[3]*other[1]),(self.t[1]+self.t[4]*other[0]+self.t[5]*other[1])) else: raise Exception, "Illegal multiplier of %s"%str(type(other)) elif isinstance(other,asyTransform): result = asyTransform((0,0,0,0,0,0)) result.x = self.x+self.xx*other.x+self.xy*other.y result.y = self.y+self.yx*other.x+self.yy*other.y result.xx = self.xx*other.xx+self.xy*other.yx result.xy = self.xx*other.xy+self.xy*other.yy result.yx = self.yx*other.xx+self.yy*other.yx result.yy = self.yx*other.xy+self.yy*other.yy result.t = (result.x,result.y,result.xx,result.xy,result.yx,result.yy) return result else: raise Exception, "Illegal multiplier of %s"%str(type(other)) def identity(): return asyTransform((0,0,1,0,0,1)) class asyObj: """A base class for asy objects: an item represented by asymptote code.""" def __init__(self): """Initialize the object""" self.asyCode = "" def updateCode(self,mag=1.0): """Update the object's code: should be overriden.""" pass def getCode(self): """Return the code describing the object""" self.updateCode() return self.asyCode class asyPen(asyObj): """A python wrapper for an asymptote pen""" def __init__(self,color=(0,0,0),width=0.5,options=""): """Initialize the pen""" asyObj.__init__(self) self.options=options self.width=width self.setColor(color) self.updateCode() if options != "": self.computeColor() def updateCode(self,mag=1.0): """Generate the pen's code""" self.asyCode = "rgb(%g,%g,%g)"%self.color+"+"+str(self.width) if len(self.options) > 0: self.asyCode += "+"+self.options def setWidth(self,newWidth): """Set the pen's width""" self.width=newWidth self.updateCode() def setColor(self,color): """Set the pen's color""" if type(color) == type((1,)) and len(color) == 3: self.color = color else: self.color = "(0,0,0)" self.updateCode() def computeColor(self): """Find out the color of an arbitrary asymptote pen.""" fout.write("pen p="+self.getCode()+';\n') fout.write("file fout=output(mode='pipe');\n") fout.write("write(fout,colorspace(p),newl);\n") fout.write("write(fout,colors(p));\n") fout.write("flush(fout);\n") fout.flush() colorspace = fin.readline() if colorspace.find("cmyk") != -1: lines = fin.readline()+fin.readline()+fin.readline()+fin.readline() parts = lines.split() c,m,y,k = eval(parts[0]),eval(parts[1]),eval(parts[2]),eval(parts[3]) k = 1-k r,g,b = ((1-c)*k,(1-m)*k,(1-y)*k) elif colorspace.find("rgb") != -1: lines = fin.readline()+fin.readline()+fin.readline() parts = lines.split() r,g,b = eval(parts[0]),eval(parts[1]),eval(parts[2]) elif colorspace.find("gray") != -1: lines = fin.readline() parts = lines.split() r = g = b = eval(parts[0]) self.color = (r,g,b) def tkColor(self): """Return the tk version of the pen's color""" self.computeColor() r,g,b = self.color r,g,b = int(256*r),int(256*g),int(256*b) if r == 256: r = 255 if g == 256: g = 255 if b == 256: b = 255 r,g,b = map(hex,(r,g,b)) r,g,b = r[2:],g[2:],b[2:] if len(r) < 2: r += '0' if len(g) < 2: g += '0' if len(b) < 2: b += '0' return'#'+r+g+b class asyPath(asyObj): """A python wrapper for an asymptote path""" def __init__(self): """Initialize the path to be an empty path: a path with no nodes, control points, or links.""" asyObj.__init__(self) self.nodeSet = [] self.linkSet = [] self.controlSet = [] self.computed = False def initFromNodeList(self,nodeSet,linkSet): """Initialize the path from a set of nodes and link types, "--", "..", or "::" """ if len(nodeSet)>0: self.nodeSet = nodeSet[:] self.linkSet = linkSet[:] self.computed = False def initFromControls(self,nodeSet,controlSet): """Initialize the path from nodes and control points""" self.controlSet = controlSet[:] self.nodeSet = nodeSet[:] self.computed = True def makeNodeStr(self,node): """Represent a node as a string""" if node == 'cycle': return node else: return "("+str(node[0])+","+str(node[1])+")" def updateCode(self,mag=1.0): """Generate the code describing the path""" if not self.computed: count = 0 #this string concatenation could be optimised self.asyCode = self.makeNodeStr(self.nodeSet[0]) for node in self.nodeSet[1:]: self.asyCode += self.linkSet[count]+self.makeNodeStr(node) count += 1 else: count = 0 #this string concatenation could be optimised self.asyCode = self.makeNodeStr(self.nodeSet[0]) for node in self.nodeSet[1:]: self.asyCode += "..controls" self.asyCode += self.makeNodeStr(self.controlSet[count][0]) self.asyCode += "and" self.asyCode += self.makeNodeStr(self.controlSet[count][1]) self.asyCode += ".." + self.makeNodeStr(node) + "\n" count += 1 def getNode(self,index): """Return the requested node""" return self.nodeSet[index] def getLink(self,index): """Return the requested link""" return self.linkSet[index] def setNode(self,index,newNode): """Set a node to a new position""" self.nodeSet[index] = newNode def moveNode(self,index,offset): """Translate a node""" if self.nodeSet[index] != "cycle": self.nodeSet[index] = (self.nodeSet[index][0]+offset[0],self.nodeSet[1]+offset[1]) def setLink(self,index,ltype): """Change the specified link""" self.linkSet[index] = ltype def addNode(self,point,ltype): """Add a node to the end of a path""" self.nodeSet.append(point) if len(self.nodeSet) != 1: self.linkSet.append(ltype) if self.computed: self.computeControls() def insertNode(self,index,point,ltype=".."): """Insert a node, and its corresponding link, at the given index""" self.nodeSet.insert(index,point) self.linkSet.insert(index,ltype) if self.computed: self.computeControls() def setControl(self,index,position): """Set a control point to a new position""" self.controlSet[index] = position def moveControl(self,index,offset): """Translate a control point""" self.controlSet[index] = (self.controlSet[index][0]+offset[0],self.controlSet[index][1]+offset[1]) def computeControls(self): """Evaluate the code of the path to obtain its control points""" fout.write("file fout=output(mode='pipe');\n") fout.write("path p="+self.getCode()+';\n') fout.write("write(fout,length(p),newl);\n") fout.write("write(fout,unstraighten(p),endl);\n") fout.flush() lengthStr = fin.readline() pathSegments = eval(lengthStr.split()[-1]) pathStrLines = [] for i in range(pathSegments+1): line=fin.readline() line=line.replace("\n","") pathStrLines.append(line) oneLiner = "".join(split(join(pathStrLines))) splitList = oneLiner.split("..") nodes = [a for a in splitList if a.find("controls")==-1] self.nodeSet = [] for a in nodes: if a == 'cycle': self.nodeSet.append(a) else: self.nodeSet.append(eval(a)) controls = [a.replace("controls","").split("and") for a in splitList if a.find("controls") != -1] self.controlSet = [[eval(a[0]),eval(a[1])] for a in controls] self.computed = True class asyLabel(asyObj): """A python wrapper for an asy label""" def __init__(self,text="",location=(0,0),pen=asyPen()): """Initialize the label with the given test, location, and pen""" asyObj.__init__(self) self.text = text self.location = location self.pen = pen def updateCode(self,mag=1.0): """Generate the code describing the label""" self.asyCode = "Label(\""+self.text+"\","+str((self.location[0],self.location[1]))+","+self.pen.getCode()+",align=SE)" def setText(self,text): """Set the label's text""" self.text = text self.updateCode() def setPen(self,pen): """Set the label's pen""" self.pen = pen self.updateCode() def moveTo(self,newl): """Translate the label's location""" self.location = newl class asyImage: """A structure containing an image and its format, bbox, and IDTag""" def __init__(self,image,format,bbox): self.image = image self.format = format self.bbox = bbox self.IDTag = None class xasyItem: """A base class for items in the xasy GUI""" def __init__(self,canvas=None): """Initialize the item to an empty item""" self.transform = [identity()] self.asyCode = "" self.imageList = [] self.IDTag = None self.asyfied = False self.onCanvas = canvas def updateCode(self,mag=1.0): """Update the item's code: to be overriden""" pass def getCode(self): """Return the code describing the item""" self.updateCode() return self.asyCode def handleImageReception(self,file,format,bbox,count): """Receive an image from an asy deconstruction. It replaces the default in asyProcess.""" image = Image.open(file) self.imageList.append(asyImage(image,format,bbox)) if self.onCanvas != None: self.imageList[-1].itk = ImageTk.PhotoImage(image) self.imageList[-1].originalImage = image.copy() self.imageList[-1].originalImage.theta = 0.0 self.imageList[-1].originalImage.bbox = bbox if count >= len(self.transform) or self.transform[count].deleted == False: self.imageList[-1].IDTag = self.onCanvas.create_image(bbox[0],-bbox[3],anchor=NW,tags=("image"),image=self.imageList[-1].itk) self.onCanvas.update() def asyfy(self,mag=1.0): self.removeFromCanvas() self.imageList = [] self.imageHandleQueue = Queue.Queue() worker = threading.Thread(target=self.asyfyThread,args=(mag,)) worker.start() item = self.imageHandleQueue.get() if console != None: console.delete(1.0,END) while item != (None,) and item[0] != "ERROR": if(item[0] == "OUTPUT"): consoleOutput(item[1]) else: self.handleImageReception(*item) try: os.remove(item[0]) except: pass item = self.imageHandleQueue.get() #self.imageHandleQueue.task_done() worker.join() def asyfyThread(self,mag=1.0): """Convert the item to a list of images by deconstructing this item's code""" fout.write("reset;\n") fout.write("initXasyMode();\n") fout.write("atexit(null);\n") global console for line in self.getCode().splitlines(): fout.write(line+"\n"); fout.write("deconstruct(%f);\n"%mag) fout.flush() format = "png" maxargs = int(split(fin.readline())[0]) boxes=[] batch=0 n=0 text = fin.readline() template=AsyTempDir+"%d_%d.%s" def render(): for i in range(len(boxes)): l,b,r,t = [float(a) for a in split(boxes[i])] name=template%(batch,i+1,format) self.imageHandleQueue.put((name,format,(l,b,r,t),i)) while text != "Done\n" and text != "Error\n": boxes.append(text) text = fin.readline() n += 1 if n >= maxargs: render() boxes=[] batch += 1 n=0 if text == "Error\n": self.imageHandleQueue.put(("ERROR",fin.readline())) else: render() self.imageHandleQueue.put((None,)) self.asyfied = True def drawOnCanvas(self,canvas,mag,forceAddition=False): pass def removeFromCanvas(self): pass class xasyDrawnItem(xasyItem): """A base class for GUI items was drawn by the user. It combines a path, a pen, and a transform.""" def __init__(self,path,pen = asyPen(),transform = identity()): """Initialize the item with a path, pen, and transform""" xasyItem.__init__(self) self.path = path self.pen = pen self.transform = [transform] def appendPoint(self,point,link=None): """Append a point to the path. If the path is cyclic, add this point before the 'cycle' node.""" if self.path.nodeSet[-1] == 'cycle': self.path.nodeSet[-1] = point self.path.nodeSet.append('cycle') else: self.path.nodeSet.append(point) self.path.computed = False if len(self.path.nodeSet) > 1 and link != None: self.path.linkSet.append(link) def clearTransform(self): """Reset the item's transform""" self.transform = [identity()] def removeLastPoint(self): """Remove the last point in the path. If the path is cyclic, remove the node before the 'cycle' node.""" if self.path.nodeSet[-1] == 'cycle': del self.path.nodeSet[-2] else: del self.path.nodeSet[-1] del self.path.linkSet[-1] self.path.computed = False def setLastPoint(self,point): """Modify the last point in the path. If the path is cyclic, modify the node before the 'cycle' node.""" if self.path.nodeSet[-1] == 'cycle': self.path.nodeSet[-2] = point else: self.path.nodeSet[-1] = point self.path.computed = False class xasyShape(xasyDrawnItem): """An outlined shape drawn on the GUI""" def __init__(self,path,pen=asyPen(),transform=identity()): """Initialize the shape with a path, pen, and transform""" xasyDrawnItem.__init__(self,path,pen,transform) def updateCode(self,mag=1.0): """Generate the code to describe this shape""" self.asyCode = "xformStack.push("+self.transform[0].getCode()+");\n" self.asyCode += "draw("+self.path.getCode()+","+self.pen.getCode()+");" def removeFromCanvas(self,canvas): """Remove the shape's depiction from a tk canvas""" if self.IDTag != None: canvas.delete(self.IDTag) def drawOnCanvas(self,canvas,mag,asyFy=False,forceAddition=False): """Add this shape to a tk canvas""" if not asyFy: if self.IDTag == None or forceAddition: #add ourselves to the canvas self.path.computeControls() self.IDTag = canvas.create_line(0,0,0,0,tags=("drawn","xasyShape"),fill=self.pen.tkColor(),width=self.pen.width*mag) self.drawOnCanvas(canvas,mag) else: self.path.computeControls() pointSet = [] previousNode = self.path.nodeSet[0] nodeCount = 0 if len(self.path.nodeSet) == 0: pointSet = [0,0,0,0] elif len(self.path.nodeSet) == 1: if self.path.nodeSet[-1] != 'cycle': p = self.transform[0]*(self.path.nodeSet[0][0],self.path.nodeSet[0][1]) pointSet = [p[0],-p[1],p[0],-p[1],p[0],-p[1]] else: pointSet = [0,0,0,0] else: for node in self.path.nodeSet[1:]: if node == 'cycle': node = self.path.nodeSet[0] transform = self.transform[0].scale(mag) points = CubicBezier.makeBezier(transform*previousNode,transform*self.path.controlSet[nodeCount][0],transform*self.path.controlSet[nodeCount][1],transform*node) for point in points: pointSet += [point[0],-point[1]] nodeCount += 1 previousNode = node canvas.coords(self.IDTag,*pointSet) canvas.itemconfigure(self.IDTag,fill=self.pen.tkColor(),width=self.pen.width*mag) else: #first asyfy then add an image list pass def __str__(self): """Create a string describing this shape""" return "xasyShape code:%s"%("\n\t".join(self.getCode().splitlines())) class xasyFilledShape(xasyShape): """A filled shape drawn on the GUI""" def __init__(self,path,pen=asyPen(),transform=identity()): """Initialize this shape with a path, pen, and transform""" if path.nodeSet[-1] != 'cycle': raise Exception,"Filled paths must be cyclic" xasyShape.__init__(self,path,pen,transform) def updateCode(self,mag=1.0): """Generate the code describing this shape""" self.asyCode = "xformStack.push("+self.transform[0].getCode()+");\n" self.asyCode += "fill("+self.path.getCode()+","+self.pen.getCode()+");" def removeFromCanvas(self,canvas): """Remove this shape's depiction from a tk canvas""" if self.IDTag != None: canvas.delete(self.IDTag) def drawOnCanvas(self,canvas,mag,asyFy=False,forceAddition=False): """Add this shape to a tk canvas""" if not asyFy: if self.IDTag == None or forceAddition: #add ourselves to the canvas self.path.computeControls() self.IDTag = canvas.create_polygon(0,0,0,0,0,0,tags=("drawn","xasyFilledShape"),fill=self.pen.tkColor(),outline=self.pen.tkColor(),width=1*mag) self.drawOnCanvas(canvas,mag) else: self.path.computeControls() pointSet = [] previousNode = self.path.nodeSet[0] nodeCount = 0 if len(self.path.nodeSet) == 0: pointSet = [0,0,0,0,0,0] elif len(self.path.nodeSet) == 1: if self.path.nodeSet[-1] != 'cycle': p = self.transform[0]*(self.path.nodeSet[0][0],self.path.nodeSet[0][1]) pointSet = [p[0],-p[1],p[0],-p[1],p[0],-p[1]] else: pointSet = [0,0,0,0,0,0] elif len(self.path.nodeSet) == 2: if self.path.nodeSet[-1] != 'cycle': p = self.transform[0].scale(mag)*(self.path.nodeSet[0][0],self.path.nodeSet[0][1]) p2 = self.transform[0].scale(mag)*(self.path.nodeSet[1][0],self.path.nodeSet[1][1]) pointSet = [p[0],-p[1],p2[0],-p2[1],p[0],-p[1]] else: pointSet = [0,0,0,0,0,0] else: for node in self.path.nodeSet[1:]: if node == 'cycle': node = self.path.nodeSet[0] transform = self.transform[0].scale(mag) points = CubicBezier.makeBezier(transform*previousNode,transform*self.path.controlSet[nodeCount][0],transform*self.path.controlSet[nodeCount][1],transform*node) for point in points: pointSet += [point[0],-point[1]] nodeCount += 1 previousNode = node canvas.coords(self.IDTag,*pointSet) canvas.itemconfigure(self.IDTag,fill=self.pen.tkColor(),outline=self.pen.tkColor(),width=1*mag) else: #first asyfy then add an image list pass def __str__(self): """Return a string describing this shape""" return "xasyFilledShape code:%s"%("\n\t".join(self.getCode().splitlines())) class xasyText(xasyItem): """Text created by the GUI""" def __init__(self,text,location,pen=asyPen(),transform=identity()): """Initialize this item with text, a location, pen, and transform""" xasyItem.__init__(self) self.label=asyLabel(text,location,pen) self.transform = [transform] self.onCanvas = None def updateCode(self,mag=1.0): """Generate the code describing this object""" self.asyCode = "xformStack.push("+self.transform[0].getCode()+");\n" self.asyCode += "label("+self.label.getCode()+");" def removeFromCanvas(self): """Removes the label's images from a tk canvas""" if self.onCanvas == None: return for image in self.imageList: if image.IDTag != None: self.onCanvas.delete(image.IDTag) def drawOnCanvas(self,canvas,mag,asyFy=True,forceAddition=False): """Adds the label's images to a tk canvas""" if self.onCanvas == None: self.onCanvas = canvas elif self.onCanvas != canvas: raise Exception,"Error: item cannot be added to more than one canvas" self.asyfy(mag) def __str__(self): return "xasyText code:%s"%("\n\t".join(self.getCode().splitlines())) class xasyScript(xasyItem): """A set of images create from asymptote code. It is always deconstructed.""" def __init__(self,canvas,script="",transforms=[]): """Initialize this script item""" xasyItem.__init__(self,canvas) self.transform = transforms[:] self.script = script def clearTransform(self): """Reset the transforms for each of the deconstructed images""" self.transform = [identity() for im in self.imageList] def updateCode(self,mag=1.0): """Generate the code describing this script""" self.asyCode = ""; if len(self.transform) > 0: self.asyCode = "xformStack.add(" isFirst = True count = 0 for xform in self.transform: if not isFirst: self.asyCode+=",\n" self.asyCode += "indexedTransform(%d,%s)"%(count,str(xform)) isFirst = False count += 1 self.asyCode += ");\n" self.asyCode += "startScript(); {\n" self.asyCode += self.script.replace("\t"," ") self.asyCode = self.asyCode.rstrip() self.asyCode += "\n} endScript();\n" def setScript(self,script): """Sets the content of the script item.""" self.script = script self.updateCode() def removeFromCanvas(self): """Removes the script's images from a tk canvas""" if self.onCanvas == None: return for image in self.imageList: if image.IDTag != None: self.onCanvas.delete(image.IDTag) def asyfy(self,mag): """Generate the list of images described by this object and adjust the length of the transform list.""" xasyItem.asyfy(self,mag) while len(self.imageList) > len(self.transform): self.transform.append(identity()) while len(self.imageList) < len(self.transform): self.transform.pop() self.updateCode() def drawOnCanvas(self,canvas,mag,asyFy=True,forceAddition=False): """Adds the script's images to a tk canvas""" if self.onCanvas == None: self.onCanvas = canvas elif self.onCanvas != canvas: raise Exception,"Error: item cannot be added to more than one canvas" self.asyfy(mag) def __str__(self): """Return a string describing this script""" retVal = "xasyScript\n\tTransforms:\n" for xform in self.transform: retVal += "\t"+str(xform)+"\n" retVal += "\tCode Ommitted" return retVal if __name__=='__main__': root = Tk() t=xasyText("test",(0,0)) t.asyfy() asymptote-2.37/GUI/xasyActions.py000077500000000000000000000335731265434602500170220ustar00rootroot00000000000000#!/usr/bin/env python ########################################################################### # # xasyActions implements the possible actions and their inverses # for the undo/redo stack in xasy # # Author: Orest Shardt # Created: July 23, 2007 # ########################################################################### import math import UndoRedoStack import xasy2asy from Tkinter import * class translationAction(UndoRedoStack.action): def __init__(self,owner,itemList,indexList,translation): self.translation = translation self.owner = owner self.itemList = itemList self.indexList = indexList UndoRedoStack.action.__init__(self,self.transF,self.unTransF) def transF(self): mag = self.owner.magnification for i in range(len(self.itemList)): for index in self.indexList[i]: self.owner.translateSomething(-1,(self.translation[0]/mag,self.translation[1]/mag),self.itemList[i],index) if index==None: index = 0 try: self.owner.mainCanvas.move(self.itemList[i].imageList[index].IDTag,self.translation[0]*mag,-self.translation[1]*mag) except: self.owner.mainCanvas.move(self.itemList[i].IDTag,self.translation[0]*mag,-self.translation[1]*mag) self.owner.updateSelection() self.owner.updateCanvasSize() def unTransF(self): mag = self.owner.magnification for i in range(len(self.itemList)): for index in self.indexList[i]: self.owner.translateSomething(-1,(-self.translation[0]/mag,-self.translation[1]/mag),self.itemList[i],index) try: self.owner.mainCanvas.move(self.itemList[i].imageList[index].IDTag,-self.translation[0]*mag,self.translation[1]*mag) except: self.owner.mainCanvas.move(self.itemList[i].IDTag,-self.translation[0]*mag,self.translation[1]*mag) self.owner.updateSelection() self.owner.updateCanvasSize() def __str__(self): return "Translation of "+str(self.itemList)+str(self.indexList)+" by "+str(self.translation) class rotationAction(UndoRedoStack.action): def __init__(self,owner,itemList,indexList,angle,origin): self.owner = owner self.itemList = itemList self.indexList = indexList self.angle = angle self.origin = origin UndoRedoStack.action.__init__(self,self.rotF,self.unRotF) def rotF(self): for i in range(len(self.itemList)): for index in self.indexList[i]: self.owner.rotateSomething(-1,self.angle,self.origin,self.itemList[i],index) for item in self.itemList: item.drawOnCanvas(self.owner.mainCanvas,self.owner.magnification) self.owner.bindItemEvents(item) self.owner.updateSelection() self.owner.updateCanvasSize() def unRotF(self): for i in range(len(self.itemList)): for index in self.indexList[i]: self.owner.rotateSomething(-1,-self.angle,self.origin,self.itemList[i],index) for item in self.itemList: item.drawOnCanvas(self.owner.mainCanvas,self.owner.magnification) self.owner.bindItemEvents(item) self.owner.updateSelection() self.owner.updateCanvasSize() def __str__(self): return "Rotation of "+str(self.itemList)+str(self.indexList)+" by "+"%.3f"%(self.angle*180.0/math.pi)+" about "+str(self.origin) class addLabelAction(UndoRedoStack.action): def __init__(self,owner,label): self.owner = owner self.label = label UndoRedoStack.action.__init__(self,self.addF,self.unAddF) def addF(self): self.owner.addItemToFile(self.label) self.label.drawOnCanvas(self.owner.mainCanvas,self.owner.magnification) self.owner.bindItemEvents(self.label) def unAddF(self): self.label.removeFromCanvas() del self.owner.fileItems[-1] self.owner.propList.delete(0) self.owner.clearSelection() def __str__(self): return "Addition of a label" class deleteLabelAction(UndoRedoStack.action): def __init__(self,owner,label,index): self.owner = owner self.label = label self.index = index UndoRedoStack.action.__init__(self,self.delF,self.unDelF) def delF(self): self.owner.fileItems[self.index].removeFromCanvas() self.owner.propList.delete(len(self.owner.fileItems)-self.index-1) del self.owner.fileItems[self.index] def unDelF(self): self.owner.fileItems.insert(self.index,self.label) self.owner.fileItems[self.index].drawOnCanvas(self.owner.mainCanvas,self.owner.magnification) self.owner.propList.insert(len(self.owner.fileItems)-self.index-1,self.owner.describeItem(self.label)) self.owner.bindItemEvents(self.label) def __str__(self): return "Deletion of a label" class editLabelTextAction(UndoRedoStack.action): def __init__(self,owner,label,newText,oldText): self.owner = owner self.label = label self.newText = newText self.oldText = oldText UndoRedoStack.action.__init__(self,self.modT,self.unModT) def modT(self): self.label.label.setText(self.newText) self.label.drawOnCanvas(self.owner.mainCanvas,self.owner.magnification) self.owner.bindItemEvents(self.label) def unModT(self): self.label.label.setText(self.oldText) self.label.drawOnCanvas(self.owner.mainCanvas,self.owner.magnification) self.owner.bindItemEvents(self.label) def __str__(self): return "Editing a label's text" class editLabelPenAction(UndoRedoStack.action): def __init__(self,owner,oldPen,newPen,index): self.owner = owner self.newPen = newPen self.oldPen = oldPen self.index = index UndoRedoStack.action.__init__(self,self.editF,self.unEditF) def editF(self): self.owner.fileItems[self.index].removeFromCanvas() self.owner.fileItems[self.index].label.pen = self.newPen self.owner.fileItems[self.index].drawOnCanvas(self.owner.mainCanvas,self.owner.magnification) self.owner.bindItemEvents(self.owner.fileItems[self.index]) def unEditF(self): self.owner.fileItems[self.index].removeFromCanvas() self.owner.fileItems[self.index].label.pen = self.oldPen self.owner.fileItems[self.index].drawOnCanvas(self.owner.mainCanvas,self.owner.magnification) self.owner.bindItemEvents(self.owner.fileItems[self.index]) def __str__(self): return "Changing a label's pen" class addScriptAction(UndoRedoStack.action): def __init__(self,owner,script): self.owner = owner self.script = script UndoRedoStack.action.__init__(self,self.addF,self.unAddF) def addF(self): self.owner.addItemToFile(self.script) self.script.drawOnCanvas(self.owner.mainCanvas,self.owner.magnification) self.owner.bindItemEvents(self.script) def unAddF(self): self.script.removeFromCanvas() del self.owner.fileItems[-1] self.owner.propList.delete(0) self.owner.clearSelection() def __str__(self): return "Addition of a script" class deleteScriptAction(UndoRedoStack.action): def __init__(self,owner,script,index): self.owner = owner self.script = script self.index = index UndoRedoStack.action.__init__(self,self.delF,self.unDelF) def delF(self): self.owner.fileItems[self.index].removeFromCanvas() self.owner.propList.delete(len(self.owner.fileItems)-self.index-1) del self.owner.fileItems[self.index] def unDelF(self): self.owner.fileItems.insert(self.index,self.script) self.owner.fileItems[self.index].drawOnCanvas(self.owner.mainCanvas,self.owner.magnification) self.owner.propList.insert(len(self.owner.fileItems)-self.index-1,self.owner.describeItem(self.script)) self.owner.bindItemEvents(self.script) def __str__(self): return "Deletion of a script" class deleteScriptItemAction(UndoRedoStack.action): def __init__(self,owner,script,indices,oldTransforms): self.owner = owner self.script = script self.indices = indices[:] UndoRedoStack.action.__init__(self,self.delI,self.unDelI) def delI(self): for index in self.indices: self.script.transform[index].deleted = True self.owner.mainCanvas.delete(self.script.imageList[index].IDTag) def unDelI(self): for i in range(len(self.indices)): index = self.indices[i] self.script.transform[index].deleted = False bbox = self.script.imageList[index].originalImage.bbox self.script.imageList[index].IDTag = self.owner.mainCanvas.create_image(bbox[0],-bbox[3],anchor=NW,tags=("image"),image=self.script.imageList[index].itk) self.owner.bindEvents(self.script.imageList[index].IDTag) self.owner.resetStacking() def __str__(self): return "Deletion of item "+str(self.indices)+" in "+str(self.script) class editScriptAction(UndoRedoStack.action): def __init__(self,owner,script,newText,oldText): self.owner = owner self.script = script self.newText = newText self.oldText = oldText UndoRedoStack.action.__init__(self,self.modS,self.unModS) def modS(self): self.script.setScript(self.newText) self.script.drawOnCanvas(self.owner.mainCanvas,self.owner.magnification) self.owner.bindItemEvents(self.script) def unModS(self): self.script.setScript(self.oldText) self.script.drawOnCanvas(self.owner.mainCanvas,self.owner.magnification) self.owner.bindItemEvents(self.script) def __str__(self): return "Modification of a script" class clearItemTransformsAction(UndoRedoStack.action): def __init__(self,owner,item,oldTransforms): self.owner = owner self.item = item self.oldTransforms = oldTransforms UndoRedoStack.action.__init__(self,self.clearF,self.unClearF) def clearF(self): for i in range(len(self.oldTransforms)): self.item.transform[i] = xasy2asy.identity() self.item.drawOnCanvas(self.owner.mainCanvas,self.owner.magnification) def unClearF(self): for i in range(len(self.oldTransforms)): self.item.transform[i] = self.oldTransforms[i] self.item.drawOnCanvas(self.owner.mainCanvas,self.owner.magnification) def __str__(self): return "Clear the transforms of "+str(self.item)+" from "+str(self.oldTransforms) class itemRaiseAction(UndoRedoStack.action): def __init__(self,owner,items,oldPositions): self.owner = owner self.items = items[:] self.oldPositions = oldPositions[:] UndoRedoStack.action.__init__(self,self.raiseI,self.unRaiseI) def raiseI(self): for item in self.items: self.owner.raiseSomething(item) def unRaiseI(self): length = len(self.owner.fileItems) indices = self.oldPositions[:] indices = [length-i-1 for i in indices] indices.reverse() for index in indices: for i in range(index): self.owner.raiseSomething(self.owner.fileItems[length-index-1]) def __str__(self): return "Raise items "+str(self.items)+" from positions "+str(self.oldPositions) class itemLowerAction(UndoRedoStack.action): def __init__(self,owner,items,oldPositions): self.owner = owner self.items = items[:] self.oldPositions = oldPositions[:] UndoRedoStack.action.__init__(self,self.lowerI,self.unLowerI) def lowerI(self): for item in self.items: self.owner.lowerSomething(item) def unLowerI(self): indices = self.oldPositions[:] indices.reverse() for index in indices: for i in range(index): self.owner.lowerSomething(self.owner.fileItems[index]) def __str__(self): return "Lower items "+str(self.items)+" from positions "+str(self.oldPositions) class addDrawnItemAction(UndoRedoStack.action): def __init__(self,owner,item): self.owner = owner self.item = item UndoRedoStack.action.__init__(self,self.drawF,self.unDrawF) def drawF(self): self.owner.addItemToFile(self.item) self.item.drawOnCanvas(self.owner.mainCanvas,self.owner.magnification,forceAddition=True) self.owner.bindItemEvents(self.item) def unDrawF(self): self.item.removeFromCanvas(self.owner.mainCanvas) del self.owner.fileItems[-1] self.owner.propList.delete(0) self.owner.clearSelection() def __str__(self): return "Drawing of an item" class deleteDrawnItemAction(UndoRedoStack.action): def __init__(self,owner,item,index): self.owner = owner self.item = item self.index = index UndoRedoStack.action.__init__(self,self.delF,self.unDelF) def delF(self): self.owner.fileItems[self.index].removeFromCanvas(self.owner.mainCanvas) self.owner.propList.delete(len(self.owner.fileItems)-self.index-1) del self.owner.fileItems[self.index] def unDelF(self): self.owner.fileItems.insert(self.index,self.item) self.owner.fileItems[self.index].drawOnCanvas(self.owner.mainCanvas,self.owner.magnification,forceAddition=True) self.owner.propList.insert(len(self.owner.fileItems)-self.index-1,self.owner.describeItem(self.item)) self.owner.bindItemEvents(self.item) def __str__(self): return "Deletion of a drawn item" class editDrawnItemAction(UndoRedoStack.action): def __init__(self,owner,oldItem,newItem,index): self.owner = owner self.oldItem = oldItem self.newItem = newItem self.index = index UndoRedoStack.action.__init__(self,self.editF,self.unEditF) def editF(self): self.owner.fileItems[self.index].removeFromCanvas(self.owner.mainCanvas) self.owner.fileItems[self.index].path = self.newItem.path self.owner.fileItems[self.index].pen = self.newItem.pen self.owner.fileItems[self.index].transform = self.newItem.transform self.owner.fileItems[self.index].IDTag = self.newItem.IDTag self.owner.fileItems[self.index].drawOnCanvas(self.owner.mainCanvas,self.owner.magnification,forceAddition=True) self.owner.bindItemEvents(self.owner.fileItems[self.index]) def unEditF(self): self.owner.fileItems[self.index].removeFromCanvas(self.owner.mainCanvas) self.owner.fileItems[self.index].path = self.oldItem.path self.owner.fileItems[self.index].pen = self.oldItem.pen self.owner.fileItems[self.index].transform = self.oldItem.transform self.owner.fileItems[self.index].IDTag = self.oldItem.IDTag self.owner.fileItems[self.index].drawOnCanvas(self.owner.mainCanvas,self.owner.magnification,forceAddition=True) self.owner.bindItemEvents(self.owner.fileItems[self.index]) def __str__(self): return "Modification of a drawn item" asymptote-2.37/GUI/xasyBezierEditor.py000077500000000000000000000200671265434602500200030ustar00rootroot00000000000000#!/usr/bin/env python ########################################################################### # # xasyBezierEditor implements the ability to graphically edit the location # of the nodes and control points of a bezier curve. # # # Author: Orest Shardt # Created: June 29, 2007 # ########################################################################### from Tkinter import * import math from CubicBezier import * import xasy2asy class node: def __init__(self,precontrol,node,postcontrol,uid,isTied = True): self.node = node self.precontrol = precontrol self.postcontrol = postcontrol self.isTied = isTied self.uid = uid self.nodeID = self.precontrolID = self.prelineID = self.postcontrolID = self.postlineID = None def shiftNode(self,delta): self.node = (self.node[0]+delta[0],self.node[1]+delta[1]) if self.precontrol != None: self.precontrol = (self.precontrol[0]+delta[0],self.precontrol[1]+delta[1]) if self.postcontrol != None: self.postcontrol = (self.postcontrol[0]+delta[0],self.postcontrol[1]+delta[1]) def shiftPrecontrol(self,delta): self.precontrol = (self.precontrol[0]+delta[0],self.precontrol[1]+delta[1]) if self.isTied and self.postcontrol != None: self.rotatePostControl(self.precontrol) def shiftPostcontrol(self,delta): self.postcontrol = (self.postcontrol[0]+delta[0],self.postcontrol[1]+delta[1]) if self.isTied and self.precontrol != None: self.rotatePrecontrol(self.postcontrol) def rotatePrecontrol(self,after): vx,vy = after[0]-self.node[0],after[1]-self.node[1] l = norm((vx,vy)) if l == 0: return m = norm((self.precontrol[0]-self.node[0],self.precontrol[1]-self.node[1])) vx = -m*vx/l vy = -m*vy/l self.precontrol = self.node[0]+vx,self.node[1]+vy def rotatePostControl(self,after): vx,vy = after[0]-self.node[0],after[1]-self.node[1] l = norm((vx,vy)) if l == 0: return m = norm((self.postcontrol[0]-self.node[0],self.postcontrol[1]-self.node[1])) vx = -m*vx/l vy = -m*vy/l self.postcontrol = self.node[0]+vx,self.node[1]+vy def draw(self,canvas): width = 3 if self.precontrol != None: if self.prelineID == None: self.prelineID = canvas.create_line(self.precontrol[0],-self.precontrol[1],self.node[0],-self.node[1],tags=("preline",self.uid)) else: canvas.coords(self.prelineID,self.precontrol[0],-self.precontrol[1],self.node[0],-self.node[1]) if self.precontrolID == None: self.precontrolID = canvas.create_oval(self.precontrol[0]-width,-self.precontrol[1]-width,self.precontrol[0]+width,-self.precontrol[1]+width, fill="red",outline="black",tags=("precontrol",self.uid)) else: canvas.coords(self.precontrolID,self.precontrol[0]-width,-self.precontrol[1]-width,self.precontrol[0]+width,-self.precontrol[1]+width) if self.postcontrol != None: if self.postlineID == None: self.postlineID = canvas.create_line(self.postcontrol[0],-self.postcontrol[1],self.node[0],-self.node[1],tags=("postline",self.uid)) else: canvas.coords(self.postlineID,self.postcontrol[0],-self.postcontrol[1],self.node[0],-self.node[1]) if self.postcontrolID == None: self.postcontrolID = canvas.create_oval(self.postcontrol[0]-width,-self.postcontrol[1]-width,self.postcontrol[0]+width,-self.postcontrol[1]+width, fill="red",outline="black",tags=("postcontrol",self.uid)) else: canvas.coords(self.postcontrolID,self.postcontrol[0]-width,-self.postcontrol[1]-width,self.postcontrol[0]+width,-self.postcontrol[1]+width) if self.isTied: color = "blue" else: color = "green" if self.nodeID == None: self.nodeID = canvas.create_oval(self.node[0]-width,-self.node[1]-width,self.node[0]+width,-self.node[1]+width, fill=color,outline="black",tags=("node",self.uid)) else: canvas.coords(self.nodeID,self.node[0]-width,-self.node[1]-width,self.node[0]+width,-self.node[1]+width) canvas.itemconfigure(self.nodeID,fill=color) class xasyBezierEditor: def __init__(self,parent,shape,canvas): self.parent = parent self.shape = shape self.transform = self.shape.transform[0] self.path = self.shape.path self.canvas = canvas self.modified = False self.path.computeControls() isCyclic = self.path.nodeSet[-1] == 'cycle' segments = len(self.path.controlSet) self.nodeList = [] for i in range(segments): if i == 0: node0 = self.transform*self.path.nodeSet[i] control = self.transform*self.path.controlSet[i][0] self.nodeList.append(node(None,node0,control,len(self.nodeList))) else: node0 = self.transform*self.path.nodeSet[i] precontrol = self.transform*self.path.controlSet[i-1][1] postcontrol = self.transform*self.path.controlSet[i][0] self.nodeList.append(node(precontrol,node0,postcontrol,len(self.nodeList))) if not isCyclic: node0 = self.transform*self.path.nodeSet[-1] precontrol = self.transform*self.path.controlSet[-1][1] self.nodeList.append(node(precontrol,node0,None,len(self.nodeList))) else: self.nodeList[0].precontrol = self.transform*self.path.controlSet[-1][1] self.showControls() self.bindNodeEvents() self.bindControlEvents() def showControls(self): for n in self.nodeList: n.draw(self.canvas) self.bindNodeEvents() self.bindControlEvents() self.parent.updateCanvasSize() def bindNodeEvents(self): self.canvas.tag_bind("node","",self.nodeDrag) self.canvas.tag_bind("node","",self.buttonDown) self.canvas.tag_bind("node","",self.toggleNode) def unbindNodeEvents(self): self.canvas.tag_unbind("node","") self.canvas.tag_unbind("node","") self.canvas.tag_unbind("node","") def bindControlEvents(self): self.canvas.tag_bind("precontrol || postcontrol","",self.controlDrag) self.canvas.tag_bind("precontrol || postcontrol","",self.buttonDown) def unbindControlEvents(self): self.canvas.tag_unbind("precontrol || postcontrol","") self.canvas.tag_unbind("precontrol || postcontrol","") def buttonDown(self,event): self.parent.freeMouseDown = False self.startx,self.starty = event.x,event.y def toggleNode(self,event): self.parent.freeMouseDown = False tags = self.canvas.gettags(CURRENT) obj = tags[0] uid = int(tags[1]) self.nodeList[uid].isTied = not self.nodeList[uid].isTied self.showControls() def nodeDrag(self,event): self.parent.freeMouseDown = False deltax = event.x-self.startx deltay = event.y-self.starty tags = self.canvas.gettags(CURRENT) obj = tags[0] uid = int(tags[1]) self.nodeList[uid].shiftNode((deltax,-deltay)) self.startx,self.starty = event.x,event.y self.applyChanges() self.showControls() self.shape.drawOnCanvas(self.canvas,self.parent.magnification) def controlDrag(self,event): self.parent.freeMouseDown = False deltax = event.x-self.startx deltay = event.y-self.starty tags = self.canvas.gettags(CURRENT) obj = tags[0] uid = int(tags[1]) if obj == "precontrol": self.nodeList[uid].shiftPrecontrol((deltax,-deltay)) elif obj == "postcontrol": self.nodeList[uid].shiftPostcontrol((deltax,-deltay)) self.startx,self.starty = event.x,event.y self.applyChanges() self.showControls() self.shape.drawOnCanvas(self.canvas,self.parent.magnification) def applyChanges(self): self.modified = True self.shape.transform[0] = xasy2asy.asyTransform((0,0,1,0,0,1)) for i in range(len(self.nodeList)): self.path.nodeSet[i] = self.nodeList[i].node if self.nodeList[i].postcontrol != None: self.path.controlSet[i][0] = self.nodeList[i].postcontrol if self.nodeList[i].precontrol != None: self.path.controlSet[i-1][1] = self.nodeList[i].precontrol def endEdit(self): self.unbindNodeEvents() self.unbindControlEvents() self.canvas.delete("node || precontrol || postcontrol || preline || postline") asymptote-2.37/GUI/xasyCodeEditor.py000077500000000000000000000023331265434602500174310ustar00rootroot00000000000000#!/usr/bin/env python ########################################################################### # # xasyCodeEditor implements a simple text editor for Asymptote scripts in # xasy. # # # Author: Orest Shardt # Created: June 29, 2007 # ############################################################################ from subprocess import call from tempfile import mkstemp from os import remove from os import fdopen from os import path from string import split import xasyOptions def getText(text=""): """Launch the external editor""" temp = mkstemp() tempf = fdopen(temp[0],"w") tempf.write(text) tempf.close() try: cmdpath,cmd = path.split(path.expandvars(xasyOptions.options['externalEditor'])) split_cmd = split(cmd) cmdpart = [path.join(cmdpath,split_cmd[0])] argpart = split_cmd[1:]+[temp[1]] arglist = cmdpart+argpart call(arglist) except Exception as e: raise Exception('Error launching external editor.') try: tempf = open(temp[1],"r") text = tempf.read() tempf.close() remove(temp[1]) except Exception as e: raise Exception('Error reading from external editor.') return text if __name__ == '__main__': #run a test print getText("Here is some text to edit") asymptote-2.37/GUI/xasyColorPicker.py000077500000000000000000000163111265434602500176250ustar00rootroot00000000000000#!/usr/bin/env python ########################################################################### # # xasyColorPicker implements a dialog that allows a user to choose a color # from those already defined in Asymptote or a custom RGB color. # # # Author: Orest Shardt # Created: June 29, 2007 # ############################################################################ from Tkinter import * import tkColorChooser asyColors = { "black":(0,0,0), "white":(1,1,1), "gray":(0.5,0.5,0.5), "red":(1,0,0), "green":(0,1,0), "blue":(0,0,1), "cmyk":(1,1,1), "Cyan":(0,1,1), "Magenta":(1,0,1), "Yellow":(1,1,0), "Black":(0,0,0), "cyan":(0,1,1), "magenta":(1,0,1), "yellow":(1,1,0), "palered":(1,0.75,0.75), "palegreen":(0.75,1,0.75), "paleblue":(0.75,0.75,1), "palecyan":(0.75,1,1), "palemagenta":(1,0.75,1), "paleyellow":(1,1,0.75), "palegray":(0.95,0.95,0.95), "lightred":(1,0.5,0.5), "lightgreen":(0.5,1,0.5), "lightblue":(0.5,0.5,1), "lightcyan":(0.5,1,1), "lightmagenta":(1,0.5,1), "lightyellow":(1,1,0.5), "lightgray":(0.9,0.9,0.9), "mediumred":(1,0.25,0.25), "mediumgreen":(0.25,1,0.25), "mediumblue":(0.25,0.25,1), "mediumcyan":(0.25,1,1), "mediummagenta":(1,0.25,1), "mediumyellow":(1,1,0.25), "mediumgray":(0.75,0.75,0.75), "heavyred":(0.75,0,0), "heavygreen":(0,0.75,0), "heavyblue":(0,0,0.75), "heavycyan":(0,0.75,0.75), "heavymagenta":(0.75,0,0.75), "lightolive":(0.75,0.75,0), "heavygray":(0.25,0.25,0.25), "deepred":(0.5,0,0), "deepgreen":(0,0.5,0), "deepblue":(0,0,0.5), "deepcyan":(0,0.5,0.5), "deepmagenta":(0.5,0,0.5), "olive":(0.5,0.5,0), "deepgray":(0.1,0.1,0.1), "darkred":(0.25,0,0), "darkgreen":(0,0.25,0), "darkblue":(0,0,0.25), "darkcyan":(0,0.25,0.25), "darkmagenta":(0.25,0,0.25), "darkolive":(0.25,0.25,0), "darkgray":(0.05,0.05,0.05), "orange":(1,0.5,0), "fuchsia":(1,0,0.5), "chartreuse":(0.5,1,0), "springgreen":(0,1,0.5), "purple":(0.5,0,1), "royalblue":(0,0.5,1) } colorLayout = [['palered', 'lightred', 'mediumred', 'red', 'heavyred', 'deepred', 'darkred', 'palegreen', 'lightgreen', 'mediumgreen', 'green', 'heavygreen', 'deepgreen', 'darkgreen', 'paleblue', 'lightblue', 'mediumblue', 'blue', 'heavyblue', 'deepblue', 'darkblue'], ['palecyan', 'lightcyan', 'heavycyan', 'deepcyan', 'darkcyan', 'palemagenta', 'lightmagenta', 'mediummagenta', 'magenta', 'heavymagenta', 'deepmagenta', 'darkmagenta', 'yellow', 'lightyellow', 'mediumyellow', 'yellow', 'lightolive', 'olive', 'darkolive', 'palegray', 'lightgray', 'mediumgray', 'gray', 'heavygray', 'deepgray', 'darkgray'], ['black', 'white', 'orange', 'fuchsia', 'chartreuse', 'springgreen', 'purple', 'royalblue', 'Cyan', 'Magenta', 'Yellow', 'Black']] def makeRGBfromTkColor(tkColor): """Convert a Tk color of the form #rrggbb to an asy rgb color""" r = int('0x'+tkColor[1:3],16) g = int('0x'+tkColor[3:5],16) b = int('0x'+tkColor[5:7],16) r /= 255.0 g /= 255.0 b /= 255.0 return (r,g,b) def RGBreal255((r,g,b)): """Convert an RGB color from 0-1 to 0-255""" a,b,c = (256*r,256*g,256*b) if a == 256: a = 255 if b == 256: b = 255 if c == 256: c = 255 return map(int,(a,b,c)) def RGB255hex((r,g,b)): """Make a color in the form #rrggbb in hex from r,g,b in 0-255""" rs,gs,bs = map(hex,(r,g,b)) rs,gs,bs = rs[2:],gs[2:],bs[2:] if len(rs) < 2: rs += '0' if len(gs) < 2: gs += '0' if len(bs) < 2: bs += '0' return '#'+rs+gs+bs class xasyColorDlg(Toplevel): """A dialog for choosing an asymptote color. It displays the usual asy presets and allows custom rgb colors""" def __init__(self,master=None,color=(0,0,0)): Toplevel.__init__(self,master,width=500,height=500) self.resizable(False,False) self.parent = master self.title("Color Picker") self.transient(master) self.focus_set() self.wait_visibility() self.grab_set() self.color = self.oldColor = color cwidth = 120 rheight = 20 self.pframe=Frame(self,bd=0) self.pframe.rowconfigure(0,weight=1) self.pframe.columnconfigure(0,weight=1) Label(self.pframe,text="Color Presets").grid(row=0,column=0) self.colScroll = Scrollbar(self.pframe,orient=VERTICAL) self.colorList = Canvas(self.pframe, width=cwidth*len(colorLayout), scrollregion=(0,0,20+cwidth*len(colorLayout),20+rheight*max([len(i) for i in colorLayout])),yscrollcommand=self.colScroll.set,relief=FLAT) self.colScroll.config(command=self.colorList.yview) self.colScroll.grid(row=1,column=1,sticky=N+S) self.colorList.grid(row=1,column=0,sticky=W) ccount = 0 for column in colorLayout: rcount = 0 for name in column: self.colorList.create_rectangle(10+cwidth*ccount,10+rheight*rcount,cwidth*ccount+25,rheight*rcount+25,tags=(name,"preset"),fill=RGB255hex(RGBreal255(asyColors[name]))) self.colorList.create_text(cwidth*ccount+30,10+rheight*rcount,text=name,anchor=NW,tags=(name,"preset"),fill="black",activefill=RGB255hex(RGBreal255(asyColors[name]))) rcount += 1 ccount += 1 self.colorList.tag_bind("preset","",self.setColorEvt) Button(self,text="Custom color...",command=self.getCustom).grid(row=2,column=0,sticky=W,padx=5,pady=5) self.colDisp = Canvas(self,width=200,height=20,background=RGB255hex(RGBreal255(self.color)),relief=SUNKEN, bd=3) self.colDisp.grid(row=2,column=1,columnspan=2) self.rowconfigure(3,minsize=10) self.columnconfigure(0,weight=1) self.columnconfigure(1,weight=1) self.columnconfigure(2,weight=1) Button(self,text="OK",default=ACTIVE,command=self.destroy).grid(row=4,column=1,sticky=E+W,padx=5,pady=5) Button(self,text="Cancel",command=self.cancel).grid(row=4,column=2,sticky=E+W,padx=5,pady=5) self.pframe.grid(row=1,column=0,columnspan=3,padx=10,pady=10) self.bind("",self.closeUp) self.setColor(color) def closeUp(self,event): """Close the dialog forcibly""" self.destroy() def getCustom(self): """Request a custom RGB color using a tkColorChooser""" result=tkColorChooser.askcolor(initialcolor=RGB255hex(RGBreal255(self.color)),title="Custom Color",parent=self) if result != (None,None): self.setColor((result[0][0]/255.0,result[0][1]/255.0,result[0][2]/255.0)) def cancel(self): """Respond to the user pressing cancel""" self.color = self.oldColor self.destroy() def setColor(self,color): """Save the color and update the color display""" self.color = color self.colDisp.configure(background=RGB255hex(RGBreal255(self.color))) def setColorEvt(self,event): """Respond to the user clicking a color from the palette""" self.setColor(asyColors[self.colorList.gettags(CURRENT)[0]]) def getColor(self,initialColor=(0,0,0)): """Use this method to prompt for a color. It returns the new color or the old color if the user cancelled the operation. e.g: print xasyColorDlg(Tk()).getColor((1,1,0)) """ self.setColor(initialColor) self.oldColor = initialColor self.wait_window(self) return self.color if __name__ == '__main__': root = Tk() Button(root,text="Pick Color",command=lambda:xasyColorDlg(root).getColor()).pack() root.mainloop() asymptote-2.37/GUI/xasyExample.asy000066400000000000000000000032461265434602500171500ustar00rootroot00000000000000initXasyMode(); // This file was generated by xasy. It may be edited manually, however, a strict // syntax must be followed. It is advised that manually scripted items be added // in the form of a script either by using xasy or by mimicking the format of an // xasy-generated script item. // Please consult the documentation or the examples provided for details. xformStack.add(indexedTransform(0,(0, 0, 1, 0, 0, 1)), indexedTransform(1,(0, 0, 1, 0, 0, 1)), indexedTransform(2,(0, 0, 1, 0, 0, 1)), indexedTransform(3,(0, 0, 1, 0, 0, 1)), indexedTransform(4,(0, 0, 1, 0, 0, 1)), indexedTransform(5,(0, 0, 1, 0, 0, 1)), indexedTransform(6,(0, 0, 1, 0, 0, 1)), indexedTransform(7,(0, 0, 1, 0, 0, 1)), indexedTransform(8,(0, 0, 1, 0, 0, 1)), indexedTransform(9,(0, 0, 1, 0, 0, 1)), indexedTransform(10,(0, 0, 1, 0, 0, 1)), indexedTransform(11,(0, 0, 1, 0, 0, 1)), indexedTransform(12,(0, 0, 1, 0, 0, 1))); startScript(); { size(0,150); pen colour1=red; pen colour2=green; pair z0=(0,0); pair z1=(-1,0); pair z2=(1,0); real r=1.5; guide c1=circle(z1,r); guide c2=circle(z2,r); fill(c1,colour1); fill(c2,colour2); picture intersection; fill(intersection,c1,colour1+colour2); clip(intersection,c2); add(intersection); draw(c1); draw(c2); label("$A$",z1); label("$B$",z2); pair z=(0,-2); real m=3; margin BigMargin=Margin(0,m*dot(unit(z1-z),unit(z0-z))); draw(Label("$A\cap B$",0),conj(z)--z0,Arrow,BigMargin); draw(Label("$A\cup B$",0),z--z0,Arrow,BigMargin); draw(z--z1,Arrow,Margin(0,m)); draw(z--z2,Arrow,Margin(0,m)); } endScript(); xformStack.push((-28.0, 7.0, 1, 0, 0, 1)); label(Label("A Venn Diagram",(-79.0, 91.0),rgb(0,0,0)+0.5,align=SE)); // This is the end of the file exitXasyMode(); asymptote-2.37/GUI/xasyFile.py000077500000000000000000000225151265434602500162730ustar00rootroot00000000000000#!/usr/bin/env python ########################################################################### # # xasyFile implements the loading, parsing, and saving of an xasy file. # # # Author: Orest Shardt # Created: June 29, 2007 # ############################################################################ from string import * from xasy2asy import * import re class xasyParseError(Exception): """A parsing error""" pass class xasyFileError(Exception): """An i/o error or other error not related to parsing""" pass def parseFile(inFile): """Parse a file returning a list of xasyItems""" lines = inFile.read() lines = lines.splitlines() #lines = [line for line in lines.splitlines() if not line.startswith("//")] result = [] if lines[0] != "initXasyMode();": raise xasyFileError,"Invalid file format: First line must be \"initXasyMode();\"" lines.pop(0) lineCount = 2 lineNum = len(lines) while lineNum > 0: line = lines[0] lines.pop(0) if not line.isspace() and len(line)>0: try: #print "Line %d: %s"%(lineCount,line), lineResult = parseLine(line.strip(),lines) except: raise xasyParseError,"Parsing error: line %d in %s\n%s"%(lineCount,inFile.name,line) if lineResult != None: result.append(lineResult) #print "\tproduced: %s"%str(lineResult) lineCount += lineNum-len(lines) lineNum = len(lines) return result transformPrefix = "xformStack" scriptPrefix = "startScript(); {" scriptSuffix = "} endScript();" def extractScript(lines): """Find the code belonging to a script item""" theScript = "" line = lines.pop(0) level = 1 while level > 0: check = line.lstrip() while check.endswith(scriptSuffix): level -= 1 line = line[:len(line)-len(scriptSuffix)] check = line.lstrip() if check.startswith(scriptPrefix): level += 1 theScript += line + "\n" if level > 0: line = lines.pop(0) global pendingTransformsD ts = pendingTransformsD[:] pendingTransformsD = [] return xasyScript(None,script=theScript,transforms=ts[:]) pendingTransforms = [] pendingTransformsD = [] def addTransform(index,t,active=1): """Place a transform in the list of transforms, expanding the list as needed""" while len(pendingTransformsD) < index+1: pendingTransformsD.append(identity()) deleted = int(active==0) pendingTransformsD[index]=asyTransform(t,deleted) def parseIndexedTransforms(args): """Parse a list of indexedTransforms, adding them to the current list of transforms""" global pendingTransformsD pendingTransformsD = [] args = args.replace("indexedTransform","") false = 0 tList = [eval(a) for a in ")?(".join(args.split("),(")).split("?")] for a in tList: addTransform(*a) def parseTransformExpression(line): """Parse statements related to the xformStack Syntax: xformStack.push(transform) e.g.: xformStack.push((0,0,1,0,0,1)); //the identity xformStack.add(indexedTransform(index,transform)[,...]) e.g.: xformStack.add(indexedTransform(1,(0,0,1,0,0,1)); """ global pendingTransforms stackCmd = line[len(transformPrefix)+1:line.find("(")] if line[-2:] != ");": raise xasyParseError,"Invalid syntax" args = line[line.find("(")+1:-2] if stackCmd == "push": t = asyTransform(eval(args)) pendingTransforms.append(t) elif stackCmd == "add": parseIndexedTransforms(args) else: raise xasyParseError,"Invalid transform stack command." return None def parseLabel(line): """Parse an asy Label statement, returning an xasyText item""" if not (line.startswith("Label(") and line.endswith(",align=SE)")): raise xasyParseError,"Invalid syntax" args = line[6:-1] loc2 = args.rfind(",align=SE") loc1 = args.rfind(",",0,loc2-1) loc = args.rfind(",(",0,loc1-1) if loc < 2: raise xasyParseError,"Invalid syntax" text = args[1:loc-1] location = eval(args[loc+1:args.find("),",loc)+1]) pen = args[loc:loc2] pen = pen[pen.find(",")+1:] pen = pen[pen.find(",")+1:] pen = pen[pen.find(",")+1:] global pendingTransforms return xasyText(text,location,parsePen(pen),pendingTransforms.pop()) def parseLabelCommand(line): """Parse a label command returning an xasyText object Syntax: label(Label(text,location,pen,align=SE)); e.g.: label(Label("Hello world!",(0,0),rgb(0,0,0)+0.5,align=SE)); """ if line[-2:] != ");": raise xasyParseError,"Invalid syntax" arguments = line[6:-2] return parseLabel(arguments) def parseDrawCommand(line): """Parse a draw command returning an xasyShape object Syntax: draw(path,pen); e.g.: draw((0,0)..controls(0.33,0.33)and(0.66,0.66)..(1,1),rgb(1,0,1)+1.5); """ if line[-2:] != ");": raise xasyParseError,"Invalid syntax" args = line[5:-2] loc = args.rfind(",rgb") path = args[:loc] pen = args[loc+1:] global pendingTransforms return xasyShape(parsePathExpression(path),parsePen(pen),pendingTransforms.pop()) def parseFillCommand(line): """Parse a fill command returning an xasyFilledShape object Syntax: fill(cyclic path,pen); e.g.: fill((0,0)..controls(0.33,0.33)and(0.66,0.66)..(1,1)..controls(0.66,0)and(0.33,0)..cycle,rgb(1,0,1)+1.5); """ if line[-2:] != ");": raise xasyParseError,"Invalid syntax" args = line[5:-2] loc = args.rfind(",rgb") path = args[:loc] pen = args[loc+1:] global pendingTransforms return xasyFilledShape(parsePathExpression(path),parsePen(pen),pendingTransforms.pop()) def parsePen(pen): """Parse a pen expression returning an asyPen Syntax: color+width[+options] e.g.: rgb(0,0,0)+1.5+evenodd e.g.: rgb(0,1,0)+1.23 """ try: tokens = pen.split("+") color = eval(tokens[0][3:]) width = float(tokens[1]) if len(tokens)>2: options = "+".join(tokens[2:]) else: options = "" return asyPen(color,width,options) except: raise xasyParseError,"Invalid pen" def parsePathExpression(expr): """Parse an asy path returning an asyPath()""" result = asyPath() expr = "".join(expr.split()) #print expr if expr.find("controls") != -1: #parse a path with control points tokens = expr.split("..") nodes = [a for a in tokens if not a.startswith("controls")] for a in range(len(nodes)): if nodes[a] != "cycle": nodes[a] = eval(nodes[a]) controls = [map(eval,a.replace("controls","").split("and")) for a in tokens if a.startswith("controls")] result.initFromControls(nodes, controls) else: #parse a path without control points tokens = re.split(r"(::|--|\.\.)",expr) linkSet = re.findall("::|--|\.\.",expr) nodeSet = [a for a in tokens if not re.match(r"::|--|\.\.",a)] #print nodeSet for a in range(len(nodeSet)): if nodeSet[a] != "cycle": nodeSet[a] = eval(nodeSet[a]) #print nodeSet result.initFromNodeList(nodeSet, linkSet) return result def takeUntilSemicolon(line,lines): """Read and concatenate lines until the collected lines end with a semicolon""" data = line while not data.endswith(";"): newline = lines.pop(0) data += newline return data def parseLine(line,lines): """Parse a line of the file""" if len(line)==0 or line.isspace() or line.startswith("//"): return None elif line.startswith(scriptPrefix): return extractScript(lines) elif line.startswith(transformPrefix): return parseTransformExpression(takeUntilSemicolon(line,lines)) elif line.startswith("label("): return parseLabelCommand(takeUntilSemicolon(line,lines)) elif line.startswith("draw("): return parseDrawCommand(takeUntilSemicolon(line,lines)) elif line.startswith("fill("): return parseFillCommand(takeUntilSemicolon(line,lines)) elif line.startswith("exitXasyMode();"): return None raise Exception,"Could not parse the line" fileHeader = """initXasyMode(); // This file was generated by xasy. It may be edited manually, however, a strict // syntax must be followed. It is advised that manually scripted items be added // in the form of a script either by using xasy or by mimicking the format of an // xasy-generated script item. // Please consult the documentation or the examples provided for details. """ fileFooter = """// This is the end of the file exitXasyMode(); """ def saveFile(file,xasyItems): """Write a list of xasyItems to a file""" file.write(fileHeader) for item in xasyItems: file.write(item.getCode()+"\n\n") file.write(fileFooter) if __name__ == '__main__': root = Tk() try: name = raw_input("enter file name (\"../../xasyTest.asy\"):") if name == '': name = "../../xasyTest.asy" f = open(name,"rt") except: print "Could not open file." asy.quit() sys.exit(1) fileItems = [] try: fileItems = parseFile(f) res = map(str,fileItems) print "----------------------------------" print "Objects in %s"%f.name print "----------------------------------" for a in res: print a print "----------------------------------" print "successful parse" f.close() except: f.close() print "parse failed" raise print "making a file" f = open("testfile.asy","wt") saveFile(f,fileItems) f.close() root.configure(width=500,height=500) root.title("Results") canv = Canvas(root,width=500,height=500) canv.pack() for i in fileItems[1].imageList: canv.create_image(250+i.bbox[0],250-i.bbox[3],anchor = NW, image=i.image) Button(root,image=i.image).pack(side=LEFT) root.mainloop() asymptote-2.37/GUI/xasyGUIIcons.py000077500000000000000000000113421265434602500170300ustar00rootroot00000000000000#!/usr/bin/env python ################################################################## # This file stores the icons used by the xasy GUI # # About images and base64 # # Suppose you have image.gif and want to create a base64 # string. This can be accomplished using: # # import base64 # base64.encodestring(open("image.gif","rb").read()) # # The resulting output, including the enclosing single quotes, # is the base64 encoding of the image and can be used in the # dictionary below. # # # Suppose you have a base64 string, b64str, and want to create # an image. This can be accomplished using: # # import base64 # open("image.gif","w").write(base64.decodestring(b64str)) # # # Author: Orest Shardt # Created: June 29, 2007 # ################################################################## import base64 import os #toolbar icon image data in base64 eliminates need to worry about files #these are the base64 encodings of the content of the directory xasy3Imgs iconB64 = { 'lower': 'R0lGODlhGAAYAPEBAAAAAP///8zMzAAAACH5BAEAAAIALAAAAAAYABgAAAItlI+py+0Po5yUgosz\nrrybK2giqADed6LHKCZm+p7xx2Zuqsqr95KcJpv9cJUCADs=\n', 'rotate': 'R0lGODlhGAAYAPAAAAAAAAAAACH5BAEAAAEALAAAAAAYABgAAAI7jI8JkO231mux1mkistL1zX0Q\ng2Fi6aGmurKp+8KKrJB0Zt+nzOQw6XPZgqjczuQ7eohKEDKoUYWIgQIAOw==\n', 'raise': 'R0lGODlhGAAYAPEBAAAAAP///8zMzAAAACH5BAEAAAIALAAAAAAYABgAAAIwlI+pywgND3ixzVvZ\nNDSn3nlKKH7fhaZmObKtk8Yh6dKlLcfC5vZ1jvIJh8SikVUAADs=\n', 'fillPoly': 'R0lGODlhGAAYAPEAAAAAAIOBgwAAAAAAACH5BAEAAAIALAAAAAAYABgAAAJGlI+py+0PEYgNBDCp\nDPxqY3UcRoViRzrmKWbLyqIMHI9vHbsbfuoHjfOBcrlbT0ATIo+gldKpMD1lL8vUo5oqS9vS5wsp\nAAA7\n', 'move': 'R0lGODlhGAAYAIABAAAAAP///yH5BAEAAAEALAAAAAAYABgAAAI4jI+py+0I3gNUNhqtwlVD7m3h\nkoVdUJ4MaKTYysVymbDoYcM4Tmv9eAO2cp6YEKUavY5BpvMZKgAAOw==\n', 'drawBezi': 'R0lGODlhGAAYAPEBAAAAAP///6usrQAAACH5BAEAAAIALAAAAAAYABgAAAI6lI+py+0AnYRUKhox\nsFvUFDXdM4LWUaKnEaorhqSX1noPmMquWJukzpr0YitRcfE5oobFpPIJjUoZBQA7\n', 'vertiMove': 'R0lGODlhGAAYAIABAAAAAP///yH5BAEAAAEALAAAAAAYABgAAAIsjI+py+0I3gNUNhqtwlVD7m3h\nko2QmZRooKKt+Y5xOFtc7dwrtrLd3gsKTQUAOw==\n', 'horizMove': 'R0lGODlhGAAYAIABAAAAAP///yH5BAEAAAEALAAAAAAYABgAAAIljI+py+0Po5y02oshAGu/7Skg\n143mSYpgGTYt8mbyTNf2jedWAQA7\n', 'fillEllip': 'R0lGODlhGAAYAPECAAAAAIOBg////6usrSH5BAEAAAMALAAAAAAYABgAAAJAnI+py+0PowS0gkmD\n3qE6wIXctYDi2SkmepLGyrYHHIcuXW93Lr+86BrgakHfrzjjIRGVFgVjWUqm1Kr1ijUUAAA7\n', 'text': 'R0lGODlhGAAYAIABAAAAAP///yH5BAEAAAEALAAAAAAYABgAAAI+jI+py+0Po5x0AgSu1SZvHnhS\nBnpio5Ukt2Idm3bysYrnddLwy+czH0rhFDkbTigj6UzKl68CjUqn1Ko1UAAAOw==\n', 'drawPoly': 'R0lGODlhGAAYAPAAAAAAAAAAACH5BAEAAAEALAAAAAAYABgAAAI4jI+py+0PEYhtgkmlzgFL/4DJ\nFULiVi4ns66smrUxrMj1fdqHR+60kfPdgCwLzbWTIU1LE+cJKQAAOw==\n', 'drawLines': 'R0lGODlhGAAYAPEBAAAAAP///6usrQAAACH5BAEAAAIALAAAAAAYABgAAAI3lI+py+0AnYRAPmoZ\njvlwX3Vh8j2XUIIWNXoZS3ZoO8soSK+4fRuYnQPyFEHhcHecFV+ppDNRAAA7\n', 'drawShape': 'R0lGODlhGAAYAPAAAAAAAAAAACH5BAEAAAEALAAAAAAYABgAAAI5jI+pywffIjQzIrCwdXnTplmh\nMoKmKIHVeZXp5cFcPH+0HbjbqKN17OoxgrTeKiOkPHjH3fIGjS4KADs=\n', 'drawEllip': 'R0lGODlhGAAYAPEBAAAAAP///6usrQAAACH5BAEAAAIALAAAAAAYABgAAAIylI+py+0PowS0gklX\ndRd29XmgdIQh+Z1TSSJpyxpqZMLqzOB4sgsbmKFZgrCi8YhMNgoAOw==\n', 'select': 'R0lGODlhGAAYAPIDAAAAAICAgMDAwP///6usrQAAAAAAAAAAACH5BAEAAAQALAAAAAAYABgAAANH\nSLrc/mvA6YCkGIiLIQhb54Gh2HwkZxKo4KoiSpam7L6rfdNZ4M+C3I+0Ush8wSLKCFIyPsnisyld\nAD7VabR6DWSt37BYmgAAOw==\n', 'fillShape': 'R0lGODlhGAAYAPEAAAAAAIOBgwAAAAAAACH5BAEAAAIALAAAAAAYABgAAAJHlI+pywff4gsUxgSo\nrhflzXXCB4YXWQIiCqpnubnLw8KyU8Omket77wvcgD4ZUTcMIj3KlOLYejY1N8/R0qChaCIrtgsO\nRwoAOw==\n', 'asy': 'R0lGODlhGAAYAIABAP8AAAAAACH5BAEKAAEALAIAAwAUABIAAAImjI+py+0AHINy0ZouNjBurmGd\nt40fFT4j2aydGqaBq8jvxH46UwAAOw==\n' } def createGIF(key): """Create a gif file from the data in the iconB64 list of icons""" if key not in iconB64.keys(): print "Error: %s not found in icon list."%key print "Available icons:",iconB64.keys() else: print "Generating %s.gif"%key open("%s.gif"%key,"w").write(base64.decodestring(iconB64[key])) def createGIFs(): """Create the files for all the icons in iconB64""" for name in iconB64.keys(): createGIF(name) def createStrFromGif(gifFile): """Create the base64 representation of a file""" return base64.encodestring(gifFile.read()) if __name__=='__main__': print "Testing the xasyGUIIcons module." print "Generating all the GIFs:" createGIFs() print "Checking consistency of all icons in iconB64" allpassed = True for icon in iconB64.keys(): print ("Checking %s"%icon), if createStrFromGif(open("%s.gif"%icon,"rb")) == iconB64[icon]: print "\tPassed." else: print "\tFailed." allpassed= False if allpassed: print "All files succeeded." s = raw_input("Delete generated files? (y/n)") if s == "y": for name in iconB64.keys(): print "Deleting %s.gif"%name, os.unlink(name+".gif") print "\tdone" print "Done" asymptote-2.37/GUI/xasyMainWin.py000077500000000000000000002104371265434602500167600ustar00rootroot00000000000000#!/usr/bin/env python ########################################################################### # # xasyMainWin implements the functionality of the GUI. It depends on # xasy2asy for its interaction with Asymptote. # # # Author: Orest Shardt # Created: June 29, 2007 # ########################################################################### import os from string import * import subprocess import math import copy from Tkinter import * import tkMessageBox import tkFileDialog import tkSimpleDialog import threading import time from xasyVersion import xasyVersion import xasyCodeEditor from xasy2asy import * import xasyFile import xasyOptions import xasyOptionsDialog import CubicBezier from xasyBezierEditor import xasyBezierEditor from xasyGUIIcons import iconB64 from xasyColorPicker import * from UndoRedoStack import * from xasyActions import * import string try: from PIL import ImageTk from PIL import Image PILAvailable = True except: PILAvailable = False class xasyMainWin: def __init__(self,master,file=None,magnification=1.0): self.opLock = threading.Lock() self.parent = master self.magnification = magnification self.previousZoom = self.magnification self.magList = [0.1,0.25,1.0/3,0.5,1,2,3,4,5,10] self.bindGlobalEvents() self.createWidgets() self.resetGUI() if sys.platform[:3] == "win": site="http://effbot.org/downloads/PIL-1.1.7.win32-py2.7.exe" else: site="http://effbot.org/downloads/Imaging-1.1.7.tar.gz" if not PILAvailable: tkMessageBox.showerror("Failed Dependencies","An error occurred loading the required PIL library. Please install "+site) self.parent.destroy() sys.exit(1) if file != None: self.loadFile(file) self.parent.after(100,self.tickHandler) def testOrAcquireLock(self): val = self.opLock.acquire(False) if val: self.closeDisplayLock() return val def acquireLock(self): self.closeDisplayLock() self.opLock.acquire() def releaseLock(self): self.opLock.release() self.openDisplayLock() def tickHandler(self): self.tickCount += 1 self.mainCanvas.itemconfigure("outlineBox",dashoffset=self.tickCount%9) self.parent.after(100,self.tickHandler) def closeDisplayLock(self): self.status.config(text="Busy") self.parent.update_idletasks() def openDisplayLock(self): self.status.config(text="Ready") def bindGlobalEvents(self): #global bindings self.parent.bind_all("",lambda q:self.editUndoCmd())# z -> no shift self.parent.bind_all("",lambda q:self.editRedoCmd())# Z -> with shift self.parent.bind_all("",lambda q:self.fileOpenCmd()) self.parent.bind_all("",lambda q:self.fileNewCmd()) self.parent.bind_all("",lambda q:self.fileSaveCmd()) self.parent.bind_all("",lambda q:self.fileExitCmd()) self.parent.bind_all("",lambda q:self.helpHelpCmd()) def unbindGlobalEvents(self): #global bindings self.parent.unbind("") self.parent.unbind("") self.parent.unbind("") self.parent.unbind("") self.parent.unbind("") self.parent.unbind("") self.parent.unbind("") def createWidgets(self): #first some configuration self.parent.geometry("800x600") self.parent.title("Xasy") self.parent.resizable(True,True) #try to capture the closing of the window #find a better way to do this since the widgets may #already be destroyed when this is called self.parent.protocol("WM_DELETE_WINDOW",self.canQuit) #the main menu self.mainMenu = Menu(self.parent) self.parent.config(menu=self.mainMenu) #the file menu self.fileMenu = Menu(self.mainMenu,tearoff=0) self.fileMenu.add_command(label="New",command=self.fileNewCmd,accelerator="Ctrl+N",underline=0) self.fileMenu.add_command(label="Open",command=self.fileOpenCmd,accelerator="Ctrl+O",underline=0) self.fileMenu.add_separator() self.fileMenu.add_command(label="Save",command=self.fileSaveCmd,accelerator="Ctrl+S",underline=0) self.fileMenu.add_command(label="Save As",command=self.fileSaveAsCmd,underline=5) self.fileMenu.add_separator() #an export menu self.exportMenu = Menu(self.fileMenu,tearoff=0) self.exportMenu.add_command(label="EPS...",command=self.exportEPS,underline=0) self.exportMenu.add_command(label="PDF...",command=self.exportPDF,underline=0) self.exportMenu.add_command(label="GIF...",command=self.exportGIF,underline=0) self.exportMenu.add_command(label="PNG...",command=self.exportPNG,underline=1) self.exportMenu.add_command(label="SVG...",command=self.exportSVG,underline=0) self.fileMenu.add_cascade(label="Export",menu=self.exportMenu,underline=1) self.fileMenu.add_separator() self.fileMenu.add_command(label="Quit",command=self.fileExitCmd,accelerator="Ctrl+Q",underline=0) self.mainMenu.add_cascade(label="File",menu=self.fileMenu,underline=0) #the edit menu self.editMenu = Menu(self.mainMenu,tearoff=0) self.editMenu.add_command(label="Undo",command=self.editUndoCmd,accelerator="Ctrl+Z",underline=0) self.editMenu.add_command(label="Redo",command=self.editRedoCmd,accelerator="Shift+Ctrl+Z",underline=0) self.mainMenu.add_cascade(label="Edit",menu=self.editMenu,underline=0) #the tools menu self.toolsMenu = Menu(self.mainMenu,tearoff=0) self.mainMenu.add_cascade(label="Tools",menu=self.toolsMenu,underline=0) #the options menu self.optionsMenu = Menu(self.toolsMenu,tearoff=0) self.toolsMenu.add_cascade(label="Options",menu=self.optionsMenu,underline=0) self.optionsMenu.add_command(label="Edit...",command=self.editOptions,underline=0) self.optionsMenu.add_command(label="Reset defaults",command=self.resetOptions,underline=6) #the help menu self.helpMenu = Menu(self.mainMenu,tearoff=0) self.helpMenu.add_command(label="Help",command=self.helpHelpCmd,state=DISABLED,accelerator="F1",underline=0) self.helpMenu.add_command(label="Asymptote Documentation",command=self.helpAsyDocCmd,underline=10) self.helpMenu.add_separator() self.helpMenu.add_command(label="About xasy",command=self.helpAboutCmd,underline=0) self.mainMenu.add_cascade(label="Help",menu=self.helpMenu,underline=0) #status bar self.statusBar = Frame(self.parent,relief=FLAT) self.magVal = DoubleVar() self.magVal.set(round(100*self.magnification,1)) self.magVal.trace('w',self.zoomViewCmd) zoomList = self.magList if self.magnification not in zoomList: zoomList.append(self.magnification) zoomList.sort() zoomList = [round(100*i,1) for i in zoomList] self.zoomMenu = OptionMenu(self.statusBar,self.magVal,*zoomList) self.zoomMenu.pack(side=RIGHT) Label(self.statusBar,text="Zoom:",anchor=E,width=7).pack(side=RIGHT) self.coords = Label(self.statusBar,text="(0,0)",relief=SUNKEN,anchor=W) self.coords.pack(side=RIGHT,anchor=S) self.status = Label(self.statusBar,text="Ready",relief=SUNKEN,anchor=W) self.status.pack(side=RIGHT,fill=X,expand=1,anchor=SW) self.statusBar.pack(side=BOTTOM,fill=X) #toolbar for transformation, drawing, and adjustment commands self.toolBar = Frame(self.parent,relief=FLAT,borderwidth=3) #let's load some images self.toolIcons = {} for x in iconB64.keys(): self.toolIcons[x] = PhotoImage(data=iconB64[x]) self.transformLbl = Label(self.toolBar,text="",anchor=W) self.transformLbl.grid(row=0,column=0,columnspan=2,sticky=W) self.toolSelectButton = Button(self.toolBar,command=self.toolSelectCmd,image=self.toolIcons["select"]) self.toolSelectButton.grid(row=1,column=0,sticky=N+S+E+W) self.toolMoveButton = Button(self.toolBar,command=self.toolMoveCmd,image=self.toolIcons["move"]) self.toolMoveButton.grid(row=2,column=0,sticky=N+S+E+W) self.toolRotateButton = Button(self.toolBar,command=self.toolRotateCmd,image=self.toolIcons["rotate"]) self.toolRotateButton.grid(row=2,column=1,sticky=N+S+E+W) self.toolVertiMoveButton = Button(self.toolBar,command=self.toolVertiMoveCmd,image=self.toolIcons["vertiMove"]) self.toolVertiMoveButton.grid(row=3,column=0,sticky=N+S+E+W) self.toolHorizMoveButton = Button(self.toolBar,command=self.toolHorizMoveCmd,image=self.toolIcons["horizMove"]) self.toolHorizMoveButton.grid(row=3,column=1,sticky=N+S+E+W) self.drawLbl = Label(self.toolBar,text="",anchor=W) self.drawLbl.grid(row=4,column=0,columnspan=2,sticky=W) self.toolDrawLinesButton = Button(self.toolBar,command=self.toolDrawLinesCmd,image=self.toolIcons["drawLines"]) self.toolDrawLinesButton.grid(row=5,column=0,sticky=N+S+E+W) self.toolDrawBeziButton = Button(self.toolBar,command=self.toolDrawBeziCmd,image=self.toolIcons["drawBezi"]) self.toolDrawBeziButton.grid(row=5,column=1,sticky=N+S+E+W) self.toolDrawPolyButton = Button(self.toolBar,command=self.toolDrawPolyCmd,image=self.toolIcons["drawPoly"]) self.toolDrawPolyButton.grid(row=6,column=0,sticky=N+S+E+W) self.toolFillPolyButton = Button(self.toolBar,command=self.toolFillPolyCmd,image=self.toolIcons["fillPoly"]) self.toolFillPolyButton.grid(row=6,column=1,sticky=N+S+E+W) self.toolDrawEllipButton = Button(self.toolBar,command=self.toolDrawEllipCmd,image=self.toolIcons["drawEllip"],state=DISABLED,relief=FLAT) #self.toolDrawEllipButton.grid(row=7,column=0,sticky=N+S+E+W) self.toolFillEllipButton = Button(self.toolBar,command=self.toolFillEllipCmd,image=self.toolIcons["fillEllip"],state=DISABLED,relief=FLAT) #self.toolFillEllipButton.grid(row=7,column=1,sticky=N+S+E+W) self.toolDrawShapeButton = Button(self.toolBar,command=self.toolDrawShapeCmd,image=self.toolIcons["drawShape"]) self.toolDrawShapeButton.grid(row=8,column=0,sticky=N+S+E+W) self.toolFillShapeButton = Button(self.toolBar,command=self.toolFillShapeCmd,image=self.toolIcons["fillShape"]) self.toolFillShapeButton.grid(row=8,column=1,sticky=N+S+E+W) self.toolTextButton = Button(self.toolBar,command=self.toolTextCmd,image=self.toolIcons["text"]) self.toolTextButton.grid(row=9,column=0,sticky=N+S+E+W) self.toolAsyButton = Button(self.toolBar,command=self.toolAsyCmd,image=self.toolIcons["asy"]) self.toolAsyButton.grid(row=9,column=1,sticky=N+S+E+W) self.adjLbl = Label(self.toolBar,text="",anchor=W) self.adjLbl.grid(row=10,column=0,columnspan=2,sticky=W) self.toolRaiseButton = Button(self.toolBar,command=self.toolRaiseCmd,image=self.toolIcons["raise"]) self.toolRaiseButton.grid(row=11,column=0,sticky=N+S+E+W) self.toolLowerButton = Button(self.toolBar,command=self.toolLowerCmd,image=self.toolIcons["lower"]) self.toolLowerButton.grid(row=11,column=1,sticky=N+S+E+W) self.toolBar.pack(side=LEFT,anchor=NW) #documentation for the tool bar buttons self.toolDocs = { self.toolSelectButton : "Click an item to select it. Control-Click will select/deselect additional items. Use mouse scroller (or Up/Down keys) to raise/lower highlighted items.", self.toolMoveButton : "Drag a selected item.", self.toolHorizMoveButton : "Drag a selected item. Only horizontal translation will be applied.", self.toolVertiMoveButton : "Drag a selected item. Only vertical translation will be applied.", self.toolRotateButton : "Drag a selected item to rotate it.", self.toolDrawLinesButton : "Click to draw line segments. Double click to place last point.", self.toolDrawBeziButton : "Click to place points. Double click to place last point.", self.toolDrawPolyButton : "Click to place vertices. Double click to place last point.", self.toolFillPolyButton : "Click to place vertices. Double click to place last point.", self.toolDrawEllipButton : "(UNIMPLEMENTED)Click to place center. Move mouse to achieve correct shape and double click.", self.toolFillEllipButton : "(UNIMPLEMENTED)Click to place center. Move mouse to achieve correct shape and double click.", self.toolDrawShapeButton : "Click to place points. Double click to place last point.", self.toolFillShapeButton : "Click to place points. Double click to place last point.", self.toolTextButton : "Click location of top left label position and enter text in dialog.", self.toolRaiseButton : "Raise selected items to top.", self.toolLowerButton : "Lower selected items to bottom.", self.toolAsyButton : "Insert/Edit Asymptote code." } #Current pen settings self.optionsBar = Frame(self.parent,height=100,relief=FLAT,borderwidth=3) self.penDisp = Canvas(self.optionsBar,width=100,height=25,bg="white",relief=SUNKEN,borderwidth=3) self.penDisp.grid(row=0,column=0,padx=3,pady=3) self.penDisp.create_line(10,25,30,10,60,20,80,10,smooth=True,tags="penDisp") self.penDisp.create_text(100,30,text="x1",tags="penMag",anchor=SE,font=("times","8")) self.penColButton = Button(self.optionsBar,text="Color...",width=5,command=self.setPenColCmd,relief=FLAT) self.penColButton.grid(row=0,column=1,padx=3,pady=3) Label(self.optionsBar,text="Width",anchor=E).grid(row=0,column=2) self.penWidthEntry = Entry(self.optionsBar,width=5) self.penWidthEntry.bind("",self.penWidthChanged) self.penWidthEntry.bind("",self.applyPenWidthEvt) self.penWidthEntry.bind("",self.applyPenWidthEvt) self.penWidthEntry.grid(row=0,column=3) Label(self.optionsBar,text="Options",anchor=E).grid(row=0,column=4) self.penOptEntry = Entry(self.optionsBar) self.penOptEntry.bind("",self.applyPenOptEvt) self.penOptEntry.bind("",self.applyPenOptEvt) self.penOptEntry.grid(row=0,column=5) self.optionsBar.pack(side=BOTTOM,anchor=NW) #a paned window for the canvas and propert explorer self.windowPane = PanedWindow(self.parent) #a property explorer self.propFrame = Frame(self.parent) self.propFrame.rowconfigure(1,weight=1) self.propFrame.columnconfigure(0,weight=1) Label(self.propFrame,text="Item List").grid(row=0,column=0,columnspan=2) self.itemScroll = Scrollbar(self.propFrame,orient=VERTICAL) self.propList = Listbox(self.propFrame, yscrollcommand=self.itemScroll.set) self.itemScroll.config(command=self.propList.yview) self.itemScroll.grid(row=1,column=1,sticky=N+S) self.propList.grid(row=1,column=0,sticky=N+S+E+W) self.propList.bind("",self.propSelect) self.propList.bind("",self.itemPropMenuPopup) #the canvas's frame self.canvFrame = Frame(self.parent,relief=FLAT,borderwidth=0) self.canvFrame.rowconfigure(0,weight=1) self.canvFrame.columnconfigure(0,weight=1) self.canvVScroll = Scrollbar(self.canvFrame,orient=VERTICAL) self.canvHScroll = Scrollbar(self.canvFrame,orient=HORIZONTAL) self.canvHScroll.grid(row=1,column=0,sticky=E+W) self.canvVScroll.grid(row=0,column=1,sticky=N+S) #add the frames to the window pane self.windowPane.pack(side=RIGHT,fill=BOTH,expand=True) self.windowPane.add(self.canvFrame) self.windowPane.add(self.propFrame) self.windowPane.paneconfigure(self.propFrame,minsize=50,sticky=N+S+E+W) self.windowPane.bind("",self.togglePaneEvt) #the highly important canvas! self.mainCanvas = Canvas(self.canvFrame,relief=SUNKEN,background="white",borderwidth=3, highlightthickness=0,closeenough=1.0,yscrollcommand=self.canvVScroll.set, xscrollcommand=self.canvHScroll.set) self.mainCanvas.grid(row=0,column=0,sticky=N+S+E+W) self.canvVScroll.config(command=self.mainCanvas.yview) self.canvHScroll.config(command=self.mainCanvas.xview) self.mainCanvas.bind("",self.canvMotion) self.mainCanvas.bind("",self.canvLeftDown) self.mainCanvas.bind("",self.endDraw) self.mainCanvas.bind("",self.canvLeftUp) self.mainCanvas.bind("",self.canvDrag) self.mainCanvas.bind("",self.canvEnter) self.mainCanvas.bind("",self.canvLeave) self.mainCanvas.bind("",self.itemDelete) #self.mainCanvas.bind("",self.canvRightDown) #self.mainCanvas.bind("",self.canvRightUp) self.mainCanvas.bind("",self.itemRaise) self.mainCanvas.bind("",self.itemLower) self.mainCanvas.bind("",self.itemRaise) self.mainCanvas.bind("",self.itemLower) self.mainCanvas.bind("",self.configEvt) def foregroundPenColor(self,hex): hex = hex[1:] rgb = max(hex[0:2], hex[2:4], hex[4:6]) if(rgb >= "80"): return "black" else: return "white" def resetGUI(self): #set up the main window self.filename = None self.fileToOpen = None self.retitle() #set up the paned window self.paneVisible = True #setup the pen entries self.pendingPenWidthChange = None self.pendingPenOptChange = None #load one-time configs xasyOptions.load() self.tkPenColor = xasyOptions.options['defPenColor'] self.penColor = makeRGBfromTkColor(self.tkPenColor) self.penColButton.config(activebackground=self.tkPenColor, activeforeground=self.foregroundPenColor(self.tkPenColor)) self.penWidth = xasyOptions.options['defPenWidth'] self.penWidthEntry.select_range(0,END) self.penWidthEntry.delete(0,END) self.penWidthEntry.insert(END,str(self.penWidth)) self.penOptions = xasyOptions.options['defPenOptions'] self.penOptEntry.select_range(0,END) self.penOptEntry.delete(0,END) self.penOptEntry.insert(END,str(self.penOptions)) self.showCurrentPen() #load modifiable configs self.applyOptions() #set up editing self.editor = None #set up drawing self.pathInProgress = asyPath() self.currentIDTag = -1 self.inDrawingMode = False self.freeMouseDown = True self.dragSelecting = False self.itemsBeingRotated = [] self.inRotatingMode = False #set up the toolbar try: self.updateSelectedButton(self.toolSelectButton) except: self.selectedButton = self.toolSelectButton self.updateSelectedButton(self.toolSelectButton) #set up the canvas self.mainCanvas.delete(ALL) self.mainCanvas.create_rectangle(0,0,0,0,tags="outlineBox",width=0,outline="#801111",dash=(3,6)) self.backColor = "white" #in future, load this from an options file. Or, should this really be an option? self.mainCanvas.configure(background=self.backColor) #set up the xasy item list self.fileItems = [] self.propList.delete(0,END) self.updateCanvasSize() #setup timer self.tickCount = 0 #setup undo/redo! self.undoRedoStack = actionStack() self.amDragging = False def retitle(self): if self.filename == None: self.parent.title("Xasy - New File") else: name = os.path.abspath(self.filename) name = os.path.basename(name) self.parent.title("Xasy - %s"%name) def applyOptions(self): self.gridcolor = xasyOptions.options['gridColor'] self.tickcolor = xasyOptions.options['tickColor'] self.axiscolor = xasyOptions.options['axesColor'] self.gridVisible = xasyOptions.options['showGrid'] self.gridxspace = xasyOptions.options['gridX'] self.gridyspace = xasyOptions.options['gridY'] self.axesVisible = xasyOptions.options['showAxes'] self.axisxspace = xasyOptions.options['axisX'] self.axisyspace = xasyOptions.options['axisY'] self.updateCanvasSize() #test the asyProcess startQuickAsy() if not quickAsyRunning(): if tkMessageBox.askyesno("Xasy Error","Asymptote could not be executed.\r\nTry to find Asymptote automatically?"): xasyOptions.setAsyPathFromWindowsRegistry() xasyOptions.save() startQuickAsy() while not quickAsyRunning(): if tkMessageBox.askyesno("Xasy Error","Asymptote could not be executed.\r\nEdit settings?"): xasyOptionsDialog.xasyOptionsDlg(self.parent) xasyOptions.save() startQuickAsy() else: self.parent.destroy() sys.exit(1) def drawGrid(self): self.mainCanvas.delete("grid") if not self.gridVisible: return left,top,right,bottom = map(int,self.mainCanvas.cget("scrollregion").split()) gridyspace = int(self.magnification*self.gridyspace) gridxspace = int(self.magnification*self.gridxspace) if gridxspace >= 3 and gridyspace >= 3: for i in range(0,right,gridxspace): self.mainCanvas.create_line(i,top,i,bottom,tags=("grid","vertical"),fill=self.gridcolor) for i in range(-gridxspace,left,-gridxspace): self.mainCanvas.create_line(i,top,i,bottom,tags=("grid","vertical"),fill=self.gridcolor) for i in range(-gridyspace,top,-gridyspace): self.mainCanvas.create_line(left,i,right,i,tags=("grid","horizontal"),fill=self.gridcolor) for i in range(0,bottom,gridyspace): self.mainCanvas.create_line(left,i,right,i,tags=("grid","horizontal"),fill=self.gridcolor) self.mainCanvas.tag_lower("grid") def drawAxes(self): self.mainCanvas.delete("axes") if not self.axesVisible: return left,top,right,bottom = map(int,self.mainCanvas.cget("scrollregion").split()) self.mainCanvas.create_line(0,top,0,bottom,tags=("axes","yaxis"),fill=self.axiscolor) self.mainCanvas.create_line(left,0,right,0,tags=("axes","xaxis"),fill=self.axiscolor) axisxspace = int(self.magnification*self.axisxspace) axisyspace = int(self.magnification*self.axisyspace) if axisxspace >= 3 and axisyspace >= 3: for i in range(axisxspace,right,axisxspace): self.mainCanvas.create_line(i,-5,i,5,tags=("axes","xaxis-ticks"),fill=self.tickcolor) for i in range(-axisxspace,left,-axisxspace): self.mainCanvas.create_line(i,-5,i,5,tags=("axes","xaxis-ticks"),fill=self.tickcolor) for i in range(-axisyspace,top,-axisyspace): self.mainCanvas.create_line(-5,i,5,i,tags=("axes","yaxis-ticks"),fill=self.tickcolor) for i in range(axisyspace,bottom,axisyspace): self.mainCanvas.create_line(-5,i,5,i,tags=("axes","yaxis-ticks"),fill=self.tickcolor) self.mainCanvas.tag_lower("axes") def updateCanvasSize(self,left=-200,top=-200,right=200,bottom=200): self.parent.update_idletasks() bbox = self.mainCanvas.bbox("drawn || image || node || precontrol || postcontrol") if bbox == None: bbox = (0,0,0,0) #(topleft, bottomright) left = min(bbox[0],left) top = min(bbox[1],top) right = max(bbox[2],right) bottom = max(bbox[3],bottom) w,h = self.mainCanvas.winfo_width(),self.mainCanvas.winfo_height() if right-left < w: extraw = w-(right-left) right += extraw/2 left -= extraw/2 if bottom-top < h: extrah = h-(bottom-top) bottom += extrah/2 top -= extrah/2 self.mainCanvas.config(scrollregion=(left,top,right,bottom)) #self.mainCanvas.xview(MOVETO,float(split(self.mainCanvas["scrollregion"])[0])) #self.mainCanvas.yview(MOVETO,float(split(self.mainCanvas["scrollregion"])[1])) #self.mainCanvas.xview(MOVETO,(left+right)/2) #self.mainCanvas.yview(MOVETO,(top+bottom)/2) self.drawAxes() self.drawGrid() def bindEvents(self,tagorID): if tagorID == None: return self.mainCanvas.tag_bind(tagorID,"",self.itemToggleSelect) self.mainCanvas.tag_bind(tagorID,"",self.itemSelect) self.mainCanvas.tag_bind(tagorID,"",self.itemMouseUp) self.mainCanvas.tag_bind(tagorID,"",self.itemEditEvt) self.mainCanvas.tag_bind(tagorID,"",self.itemDrag) self.mainCanvas.tag_bind(tagorID,"",self.itemDelete) self.mainCanvas.tag_bind(tagorID,"",self.itemHighlight) self.mainCanvas.tag_bind(tagorID,"",self.itemCanvasMenuPopup) def bindItemEvents(self,item): if item == None: return if isinstance(item,xasyScript) or isinstance(item,xasyText): for image in item.imageList: self.bindEvents(image.IDTag) else: self.bindEvents(item.IDTag) def canQuit(self,force=False): #print "Quitting" if not force and not self.testOrAcquireLock(): return try: self.releaseLock() except: pass if self.undoRedoStack.changesMade(): result = tkMessageBox._show("xasy","File has been modified.\nSave changes?",icon=tkMessageBox.QUESTION,type=tkMessageBox.YESNOCANCEL) if str(result) == tkMessageBox.CANCEL: return elif result == tkMessageBox.YES: self.fileSaveCmd() try: os.rmdir(getAsyTempDir()) except: pass stopQuickAsy() self.parent.destroy() def openFile(self,name): if(not self.testOrAcquireLock()): return self.releaseLock() #release the lock for loadFile self.resetGUI() self.loadFile(name) def loadFile(self,name): self.status.config(text="Loading "+name) self.filename = os.path.abspath(name) startQuickAsy() self.retitle() try: try: f = open(self.filename,'rt') except: if self.filename[-4:] == ".asy": raise else: f = open(self.filename+".asy",'rt') self.filename += ".asy" self.retitle() self.fileItems = xasyFile.parseFile(f) f.close() except IOError: tkMessageBox.showerror("File Opening Failed.","File could not be opened.") self.fileItems = [] except: self.fileItems = [] self.autoMakeScript = True if self.autoMakeScript or tkMessageBox.askyesno("Error Opening File", "File was not recognized as an xasy file.\nLoad as a script item?"): try: item = xasyScript(self.mainCanvas) f.seek(0) item.setScript(f.read()) self.addItemToFile(item) except: tkMessageBox.showerror("File Opening Failed.","Could not load as a script item.") self.fileItems = [] self.populateCanvasWithItems() self.populatePropertyList() self.updateCanvasSize() def populateCanvasWithItems(self): if(not self.testOrAcquireLock()): return self.mainCanvas.delete("drawn || image") self.itemCount = 0 for item in self.fileItems: item.drawOnCanvas(self.mainCanvas,self.magnification,forceAddition=True) self.bindItemEvents(item) self.releaseLock() def propListCountItem(self,item): plist = self.propList.get(0,END) count = 1 for text in plist: if text.startswith(item): count += 1 return count def describeItem(self,item): if isinstance(item,xasyScript): return "Code Module "+str(self.propListCountItem("Code Module")) elif isinstance(item,xasyText): return "Text Label "+str(self.propListCountItem("Text Label")) elif isinstance(item,xasyFilledShape): return "Filled Shape "+str(self.propListCountItem("Filled Shape")) elif isinstance(item,xasyShape): return "Outline "+str(self.propListCountItem("Outline")) else: return "If this happened, the program is corrupt!" def populatePropertyList(self): self.propList.delete(0,END) for item in self.fileItems: self.propList.insert(0,self.describeItem(item)) def saveFile(self,name): if(not self.testOrAcquireLock()): return f = open(name,"wt") xasyFile.saveFile(f,self.fileItems) f.close() self.undoRedoStack.setCommitLevel() self.retitle() self.releaseLock() #menu commands def fileNewCmd(self): if(not self.testOrAcquireLock()): return self.releaseLock() #print "Create New File" if self.undoRedoStack.changesMade(): result = tkMessageBox._show("xasy","File has been modified.\nSave changes?",icon=tkMessageBox.QUESTION,type=tkMessageBox.YESNOCANCEL) if str(result) == tkMessageBox.CANCEL: return elif result == tkMessageBox.YES: self.fileSaveCmd() self.resetGUI() def fileOpenCmd(self): if(not self.testOrAcquireLock()): return self.releaseLock() #print "Open a file" if self.undoRedoStack.changesMade(): result = tkMessageBox._show("xasy","File has been modified.\nSave changes?",icon=tkMessageBox.QUESTION,type=tkMessageBox.YESNOCANCEL) if str(result) == tkMessageBox.CANCEL: return elif result == tkMessageBox.YES: self.fileSaveCmd() filename=tkFileDialog.askopenfilename(filetypes=[("asy files","*.asy"),("All files","*")],title="Open File",parent=self.parent) if type(filename) != type((0,)) and filename != None and filename != '': self.filename = filename self.openFile(self.filename) def fileSaveCmd(self): #print "Save current file" if(not self.testOrAcquireLock()): return self.releaseLock() if self.filename == None: filename=tkFileDialog.asksaveasfilename(defaultextension=".asy",filetypes=[("asy files","*.asy")],initialfile="newDrawing.asy",parent=self.parent,title="Save File") if type(filename) != type((0,)) and filename != None and filename != '': self.filename = filename if self.filename != None: self.saveFile(self.filename) def fileSaveAsCmd(self): if(not self.testOrAcquireLock()): return self.releaseLock() #print "Save current file as" filename=tkFileDialog.asksaveasfilename(defaultextension=".asy",filetypes=[("asy files","*.asy")],initialfile="newDrawing.asy",parent=self.parent,title="Save File") if type(filename) != type((0,)) and filename != None and filename != '': self.filename = filename self.saveFile(self.filename) #export the file def exportEPS(self): self.exportFile(self.filename,"eps") def exportPDF(self): self.exportFile(self.filename,"pdf") def exportGIF(self): self.exportFile(self.filename,"gif") def exportPNG(self): self.exportFile(self.filename,"png") def exportSVG(self): self.exportFile(self.filename,"svg") def exportFile(self,inFile, outFormat): if(not self.testOrAcquireLock()): return self.releaseLock() if inFile == None: if tkMessageBox.askyesno("xasy","File has not been saved.\nSave?"): self.fileSaveAsCmd() inFile = self.filename else: return elif self.undoRedoStack.changesMade(): choice = tkMessageBox._show("xasy","File has been modified.\nOnly saved changes can be exported.\nDo you want to save changes?",icon=tkMessageBox.QUESTION,type=tkMessageBox.YESNOCANCEL) choice = str(choice) if choice != tkMessageBox.YES: return else: self.fileSaveCmd() name = os.path.splitext(os.path.basename(self.filename))[0]+'.'+outFormat outfilename = tkFileDialog.asksaveasfilename(defaultextension = '.'+outFormat,filetypes=[(outFormat+" files","*."+outFormat)],initialfile=name,parent=self.parent,title="Choose output file") if type(outfilename)==type((0,)) or not outfilename or outfilename == '': return fullname = os.path.abspath(outfilename) outName = os.path.basename(outfilename) command=[xasyOptions.options['asyPath'],"-f"+outFormat,"-o"+fullname,inFile] saver = subprocess.Popen(command,stdin=PIPE,stdout=PIPE,stderr=PIPE) saver.wait() if saver.returncode != 0: tkMessageBox.showerror("Export Error","Export Error:\n"+saver.stdout.read()+saver.stderr.read()) self.status.config(text="Error exporting file") else: self.status.config(text="File exported successfully") def fileExitCmd(self): #print "Exit xasy" self.canQuit() def editUndoCmd(self): if not self.editor == None: return if(not self.testOrAcquireLock()): return self.undoOperation() self.releaseLock() def editRedoCmd(self): if not self.editor == None: return if(not self.testOrAcquireLock()): return self.redoOperation() self.releaseLock() def helpHelpCmd(self): print "Get help on xasy" def helpAsyDocCmd(self): #print "Open documentation about Asymptote" asyExecute("help;\n") def helpAboutCmd(self): tkMessageBox.showinfo("About xasy","A graphical interface for Asymptote "+xasyVersion) def updateSelectedButton(self,newB): if(not self.testOrAcquireLock()): return self.releaseLock() #disable switching modes during an incomplete drawing operation if self.inDrawingMode: return self.selectedButton.config(relief = RAISED) if newB == self.toolSelectButton or self.selectedButton == self.toolSelectButton: self.mainCanvas.delete("highlightBox") if self.editor != None: self.editor.endEdit() if self.editor.modified: self.undoRedoStack.add(editDrawnItemAction(self,self.itemBeingEdited,copy.deepcopy(self.editor.shape),self.fileItems.index(self.editor.shape))) if newB not in (self.toolSelectButton,self.toolMoveButton,self.toolHorizMoveButton,self.toolVertiMoveButton,self.toolRotateButton): self.clearSelection() self.selectedButton = newB self.selectedButton.config(relief = SUNKEN) self.status.config(text=self.toolDocs[newB]) #toolbar commands def toolSelectCmd(self): self.updateSelectedButton(self.toolSelectButton) def toolMoveCmd(self): self.updateSelectedButton(self.toolMoveButton) def toolRotateCmd(self): self.updateSelectedButton(self.toolRotateButton) def toolVertiMoveCmd(self): self.updateSelectedButton(self.toolVertiMoveButton) def toolHorizMoveCmd(self): self.updateSelectedButton(self.toolHorizMoveButton) def toolDrawLinesCmd(self): self.updateSelectedButton(self.toolDrawLinesButton) def toolDrawBeziCmd(self): self.updateSelectedButton(self.toolDrawBeziButton) def toolDrawPolyCmd(self): self.updateSelectedButton(self.toolDrawPolyButton) def toolFillPolyCmd(self): self.updateSelectedButton(self.toolFillPolyButton) def toolDrawEllipCmd(self): self.updateSelectedButton(self.toolDrawEllipButton) def toolFillEllipCmd(self): self.updateSelectedButton(self.toolFillEllipButton) def toolDrawShapeCmd(self): self.updateSelectedButton(self.toolDrawShapeButton) def toolFillShapeCmd(self): self.updateSelectedButton(self.toolFillShapeButton) def toolTextCmd(self): self.updateSelectedButton(self.toolTextButton) def toolAsyCmd(self): # ignore the command if we are too busy to process it if not self.testOrAcquireLock(): return self.updateSelectedButton(self.toolSelectButton) self.clearSelection() self.clearHighlight() self.unbindGlobalEvents() try: self.getNewText("// enter your code here") except Exception, e: tkMessageBox.showerror('xasy Error',e.message) else: self.addItemToFile(xasyScript(self.mainCanvas)) text = self.newText self.undoRedoStack.add(addScriptAction(self,self.fileItems[-1])) self.fileItems[-1].setScript(text) self.fileItems[-1].drawOnCanvas(self.mainCanvas,self.magnification) self.bindItemEvents(self.fileItems[-1]) self.bindGlobalEvents() self.releaseLock() def toolRaiseCmd(self): if(not self.testOrAcquireLock()): return self.releaseLock() if not self.inDrawingMode and self.editor == None: itemList = [] indexList = [] for ID in self.mainCanvas.find_withtag("selectedItem"): item = self.findItem(ID) if item not in itemList: itemList.append(item) indexList.append(self.fileItems.index(item)) self.raiseSomething(item) self.undoRedoStack.add(itemRaiseAction(self,itemList,indexList)) def toolLowerCmd(self): if(not self.testOrAcquireLock()): return self.releaseLock() if not self.inDrawingMode and self.editor == None: itemList = [] indexList = [] for ID in self.mainCanvas.find_withtag("selectedItem"): item = self.findItem(ID) if item not in itemList: itemList.append(item) indexList.append(self.fileItems.index(item)) self.lowerSomething(item) self.undoRedoStack.add(itemLowerAction(self,itemList,indexList)) def itemRaise(self,event): self.mainCanvas.tag_raise(CURRENT) def itemLower(self,event): self.mainCanvas.tag_lower(CURRENT) #options bar commands def setPenColCmd(self): if not self.testOrAcquireLock(): return old = self.penColor self.penColor = xasyColorDlg(self.parent).getColor(self.penColor) if self.penColor != old: self.tkPenColor = RGB255hex(RGBreal255(self.penColor)) self.penColButton.config(activebackground=self.tkPenColor, activeforeground=self.foregroundPenColor(self.tkPenColor)) self.showCurrentPen() self.releaseLock() def clearSelection(self): self.hideSelectionBox() self.mainCanvas.dtag("selectedItem","selectedItem") def hideSelectionBox(self): self.mainCanvas.itemconfigure("outlineBox",width=1,outline=self.backColor) self.mainCanvas.tag_lower("outlineBox") self.mainCanvas.coords("outlineBox",self.mainCanvas.bbox(ALL)) def showSelectionBox(self): self.mainCanvas.itemconfigure("outlineBox",width=2,outline="#801111") self.mainCanvas.tag_raise("outlineBox") def setSelection(self,what): self.mainCanvas.addtag_withtag("selectedItem",what) self.updateSelection() if self.selectedButton == self.toolSelectButton and len(self.mainCanvas.find_withtag("selectedItem")) > 0: self.updateSelectedButton(self.toolMoveButton) def unSelect(self,what): self.mainCanvas.dtag(what,"selectedItem") self.updateSelection() def updateSelection(self): self.clearHighlight() theBbox = self.mainCanvas.bbox("selectedItem") if theBbox != None: theBbox = (theBbox[0]-2,theBbox[1]-2,theBbox[2]+2,theBbox[3]+2) self.mainCanvas.coords("outlineBox",theBbox) self.showSelectionBox() else: self.clearSelection() #event handlers def updateZoom(self): self.zoomMenu.config(state=DISABLED) self.magnification = self.magVal.get()/100.0 if self.magnification != self.previousZoom: self.populateCanvasWithItems() self.updateCanvasSize() self.updateSelection() self.drawAxes() self.drawGrid() self.previousZoom = self.magnification self.zoomMenu.config(state=NORMAL) def zoomViewCmd(self,*args): magnification = self.magVal.get()/100.0 self.updateZoom(); def selectItem(self,item): self.clearSelection() if isinstance(item,xasyScript) or isinstance(item,xasyText): for image in item.imageList: self.setSelection(image.IDTag) else: self.setSelection(item.IDTag) def propSelect(self,event): items = map(int, self.propList.curselection()) if len(items)>0: try: self.selectItem(self.fileItems[len(self.fileItems)-items[0]-1]) except: raise def findItem(self,ID): for item in self.fileItems: if isinstance(item,xasyScript) or isinstance(item,xasyText): for image in item.imageList: if image.IDTag == ID: return item else: if item.IDTag == ID: return item raise Exception,"Illegal operation: Item with matching ID could not be found." def findItemImageIndex(self,item,ID): count = 0 for image in item.imageList: if image.IDTag == ID: return count else: count += 1 raise Exception,"Illegal operation: Image with matching ID could not be found." return None def raiseSomething(self,item,force=False): if self.fileItems[-1] != item or force: index = len(self.fileItems)-self.fileItems.index(item)-1 text = self.propList.get(index) self.propList.delete(index) self.propList.insert(0,text) for i in range(self.fileItems.index(item),len(self.fileItems)-1): self.fileItems[i] = self.fileItems[i+1] self.fileItems[-1] = item if isinstance(item,xasyScript) or isinstance(item,xasyText): for im in item.imageList: if im.IDTag != None: self.mainCanvas.tag_raise(im.IDTag) else: if item.IDTag != None: self.mainCanvas.tag_raise(item.IDTag) def lowerSomething(self,item): if self.fileItems[0] != item: index = len(self.fileItems)-self.fileItems.index(item)-1 text = self.propList.get(index) self.propList.delete(index) self.propList.insert(END,text) indices = range(self.fileItems.index(item)) indices.reverse() for i in indices: self.fileItems[i+1] = self.fileItems[i] self.fileItems[0] = item if isinstance(item,xasyScript) or isinstance(item,xasyText): item.imageList.reverse() for im in item.imageList: if im.IDTag != None: self.mainCanvas.tag_lower(im.IDTag) item.imageList.reverse() else: if item.IDTag != None: self.mainCanvas.tag_lower(item.IDTag) self.mainCanvas.tag_lower("axes || grid") def translateSomething(self,ID,translation,specificItem=None,specificIndex=None): transform = asyTransform((translation[0],translation[1],1,0,0,1)) if ID == -1: item = specificItem else: item = self.findItem(ID) if isinstance(item,xasyText) or isinstance(item,xasyScript): if ID == -1: index = specificIndex else: index = self.findItemImageIndex(item,ID) try: original = item.transform[index] except: original = identity() item.transform[index] = transform*original bbox = item.imageList[index].originalImage.bbox item.imageList[index].originalImage.bbox = bbox[0]+translation[0],bbox[1]+translation[1],bbox[2]+translation[0],bbox[3]+translation[1] else: item.transform = [transform*item.transform[0]] def makeRotationMatrix(self,theta,origin): rotMat = (math.cos(theta),-math.sin(theta),math.sin(theta),math.cos(theta)) shift = asyTransform((0,0,1-rotMat[0],-rotMat[1],-rotMat[2],1-rotMat[3]))*origin return asyTransform((shift[0],shift[1],rotMat[0],rotMat[1],rotMat[2],rotMat[3])) def rotateSomething(self,ID,theta,origin,specificItem=None,specificIndex=None): #print "Rotating by",theta*180.0/math.pi,"around",origin rotMat = self.makeRotationMatrix(theta,(origin[0]/self.magnification,origin[1]/self.magnification)) #print rotMat if ID == -1: item = specificItem else: item = self.findItem(ID) if isinstance(item,xasyText) or isinstance(item,xasyScript): #transform the image if ID == -1: index = specificIndex else: index = self.findItemImageIndex(item,ID) try: original = item.transform[index] except: original = identity() oldBbox = item.imageList[index].originalImage.bbox oldBbox = (oldBbox[0],-oldBbox[1],oldBbox[2],-oldBbox[3]) item.transform[index] = rotMat*item.transform[index] item.transform[index] = rotMat*original item.imageList[index].originalImage.theta += theta item.imageList[index].image = item.imageList[index].originalImage.rotate(item.imageList[index].originalImage.theta*180.0/math.pi,expand=True,resample=Image.BICUBIC) item.imageList[index].itk = ImageTk.PhotoImage(item.imageList[index].image) self.mainCanvas.itemconfigure(ID,image=item.imageList[index].itk) #the image has been rotated in place #now, compensate for any resizing and shift to the correct location # # p0 --- p1 p1 # | | ---> / \ # p2 --- p3 p0 p3 # \ / # p2 # rotMat2 = self.makeRotationMatrix(item.imageList[index].originalImage.theta,origin) p0 = rotMat2*(oldBbox[0],-oldBbox[3])#switch to usual coordinates p1 = rotMat2*(oldBbox[2],-oldBbox[3]) p2 = rotMat2*(oldBbox[0],-oldBbox[1]) p3 = rotMat2*(oldBbox[2],-oldBbox[1]) newTopLeft = (min(p0[0],p1[0],p2[0],p3[0]),-max(p0[1],p1[1],p2[1],p3[1]))#switch back to screen coords shift = (newTopLeft[0]-oldBbox[0],newTopLeft[1]-oldBbox[3]) #print theta*180.0/math.pi,origin,oldBbox,newTopLeft,shift #print item.imageList[index].originalImage.size #print item.imageList[index].image.size #print self.mainCanvas.coords(ID,oldBbox[0]+shift[0],oldBbox[3]+shift[1]) else: #transform each point of the object xform = rotMat*item.transform[0] item.transform = [identity()] for i in range(len(item.path.nodeSet)): if item.path.nodeSet[i] != 'cycle': item.path.nodeSet[i] = xform*item.path.nodeSet[i] for i in range(len(item.path.controlSet)): item.path.controlSet[i][0] = xform*item.path.controlSet[i][0] item.path.controlSet[i][1] = xform*item.path.controlSet[i][1] item.drawOnCanvas(self.mainCanvas,self.magnification) def deleteItem(self,item): if isinstance(item,xasyScript) or isinstance(item,xasyText): if isinstance(item,xasyScript): self.undoRedoStack.add(deleteScriptAction(self,item,self.fileItems.index(item))) else: self.undoRedoStack.add(deleteLabelAction(self,item,self.fileItems.index(item))) for image in item.imageList: self.mainCanvas.delete(image.IDTag) else: if isinstance(item,xasyDrawnItem): self.undoRedoStack.add(deleteDrawnItemAction(self,item,self.fileItems.index(item))) self.mainCanvas.delete(item.IDTag) self.fileItems.remove(item) self.populatePropertyList() self.clearSelection() def deleteSomething(self,ID): self.clearSelection() self.clearHighlight() if self.editor != None: self.editor.endEdit() if self.editor.modified: self.undoRedoStack.add(editDrawnItemAction(self,self.itemBeingEdited,copy.deepcopy(self.editor.shape),self.fileItems.index(self.editor.shape))) item = self.findItem(ID) #save an event on the undoredo stack if isinstance(item,xasyScript): index = self.findItemImageIndex(item,ID) item.transform[index].deleted = True else: if isinstance(item,xasyText): self.undoRedoStack.add(deleteLabelAction(self,item,self.fileItems.index(item))) elif isinstance(item,xasyDrawnItem): self.undoRedoStack.add(deleteDrawnItemAction(self,item,self.fileItems.index(item))) self.fileItems.remove(item) self.mainCanvas.delete(ID) self.populatePropertyList() def scriptEditThread(self,oldText): try: self.newText = xasyCodeEditor.getText(oldText) except: self.newText = -1 def getNewText(self,oldText): editThread = threading.Thread(target=self.scriptEditThread,args=(oldText,)) editThread.start() while editThread.isAlive(): time.sleep(0.05) self.parent.update() editThread.join() if type(self.newText)==type(-1): self.newText = '' raise Exception('Error launching external editor. Please check xasy options.') def itemEdit(self,item): # are we too busy? if not self.testOrAcquireLock(): return self.updateSelectedButton(self.toolSelectButton) if isinstance(item,xasyScript): self.unbindGlobalEvents() oldText = item.script try: self.getNewText(oldText) except Exception,e: tkMessageBox.showerror('xasy Error',e.message) else: if self.newText != oldText: self.undoRedoStack.add(editScriptAction(self,item,self.newText,oldText)) item.setScript(self.newText) item.drawOnCanvas(self.mainCanvas,self.magnification) self.bindItemEvents(item) self.bindGlobalEvents() elif isinstance(item,xasyText): theText = tkSimpleDialog.askstring(title="Xasy - Text",prompt="Enter text to display:",initialvalue=item.label.text,parent=self.parent) if theText != None and theText != "": self.undoRedoStack.add(editLabelTextAction(self,item,theText,item.label.text)) item.label.text = theText item.drawOnCanvas(self.mainCanvas,self.magnification) self.bindItemEvents(item) elif isinstance(item,xasyShape): self.clearSelection() self.clearHighlight() self.itemBeingEdited = copy.deepcopy(item) self.editor = xasyBezierEditor(self,item,self.mainCanvas) self.updateSelection() self.releaseLock() def itemEditEvt(self,event): if not self.inDrawingMode: ID = self.mainCanvas.find_withtag(CURRENT)[0] item = self.findItem(ID) self.itemEdit(item) def itemDrag(self,event): x0,y0 = self.mainCanvas.canvasx(event.x),self.mainCanvas.canvasy(event.y) x = x0/self.magnification y = y0/self.magnification if self.selectedButton not in [self.toolMoveButton,self.toolVertiMoveButton,self.toolHorizMoveButton]: return if "selectedItem" in self.mainCanvas.gettags(CURRENT): self.amDragging = True for ID in self.mainCanvas.find_withtag("selectedItem"): transform = identity() if self.selectedButton == self.toolMoveButton: translation = (x0-self.dragStartx,-(y0-self.dragStarty)) elif self.selectedButton == self.toolVertiMoveButton: translation = (0,-(y0-self.dragStarty)) elif self.selectedButton == self.toolHorizMoveButton: translation = (x0-self.dragStartx,0) self.translateSomething(ID,(translation[0]/self.magnification,translation[1]/self.magnification)) self.mainCanvas.move(ID,translation[0],-translation[1]) self.updateSelection() self.updateCanvasSize() self.distanceDragged = (self.distanceDragged[0]+translation[0],self.distanceDragged[1]-translation[1]) self.dragStartx,self.dragStarty = x0,y0 def itemMouseUp(self,event): self.freeMouseDown = True if self.amDragging: IDList = self.mainCanvas.find_withtag("selectedItem") itemList = [] indexList = [] for ID in IDList: item = self.findItem(ID) if item not in itemList: itemList.append(item) try: indexList.append([self.findItemImageIndex(item,ID)]) except: indexList.append([None]) else: indexList[itemList.index(item)].append(self.findItemImageIndex(item,ID)) self.undoRedoStack.add(translationAction(self,itemList,indexList,(self.distanceDragged[0],-self.distanceDragged[1]))) self.amDragging = False def itemSelect(self,event): x0,y0 = self.mainCanvas.canvasx(event.x),self.mainCanvas.canvasy(event.y) x = x0/self.magnification y = y0/self.magnification self.dragStartx,self.dragStarty = x0,y0 self.distanceDragged = (0,0) if self.selectedButton in [self.toolSelectButton,self.toolMoveButton,self.toolVertiMoveButton,self.toolHorizMoveButton,self.toolRotateButton]: self.freeMouseDown = False if self.selectedButton == self.toolSelectButton or (len(self.mainCanvas.find_withtag("selectedItem"))<=1 and self.selectedButton in [self.toolMoveButton,self.toolVertiMoveButton,self.toolHorizMoveButton,self.toolRotateButton]): self.clearSelection() self.setSelection(CURRENT) def itemToggleSelect(self,event): #print "control click" x0,y0 = self.mainCanvas.canvasx(event.x),self.mainCanvas.canvasy(event.y) x = x0/self.magnification y = y0/self.magnification if self.selectedButton in [self.toolSelectButton,self.toolMoveButton,self.toolVertiMoveButton,self.toolHorizMoveButton,self.toolRotateButton]: self.freeMouseDown = False self.dragStartx,self.dragStarty = x0,y0 if "selectedItem" in self.mainCanvas.gettags(CURRENT): self.unSelect(CURRENT) else: self.setSelection(CURRENT) def itemDelete(self,event): if(not self.testOrAcquireLock()): return itemList = [] self.undoRedoStack.add(endActionGroup) for ID in self.mainCanvas.find_withtag("selectedItem"): item = self.findItem(ID) if isinstance(item,xasyScript): index = self.findItemImageIndex(item,ID) if item not in itemList: itemList.append([item,[index],[item.transform[index]]]) else: x = None for i in itemList: if i[0] == item: x = i x[1].append(index) x[2].append(item.transform[index]) self.deleteSomething(ID) for entry in itemList: self.undoRedoStack.add(deleteScriptItemAction(self,entry[0],entry[1],entry[2])) self.undoRedoStack.add(beginActionGroup) self.clearSelection() self.releaseLock() def itemMotion(self,event): pass def itemHighlight(self,event): if self.selectedButton in [self.toolSelectButton] and self.editor == None: box = self.mainCanvas.bbox(CURRENT) box = (box[0]-2,box[1]-2,box[2]+2,box[3]+2) if len(self.mainCanvas.find_withtag("highlightBox"))==0: self.mainCanvas.create_rectangle(box,tags="highlightBox",width=2,outline="red") else: self.mainCanvas.tag_raise("highlightBox") self.mainCanvas.coords("highlightBox",*box) self.mainCanvas.tag_bind("highlightBox","",self.itemUnHighlight) def itemUnHighlight(self,event): self.clearHighlight() def clearHighlight(self): self.mainCanvas.delete("highlightBox") def itemLeftDown(self,event): pass def itemLeftUp(self,event): pass def itemRightDown(self,event): pass def itemRightUp(self,event): pass def canvMotion(self,event): self.coords.config( text="(%.3f,%.3f)"%(self.mainCanvas.canvasx(event.x)/self.magnification,-self.mainCanvas.canvasy(event.y)/self.magnification) ) def addItemToFile(self,item): self.fileItems.append(item) self.propList.insert(0,self.describeItem(item)) self.updateCanvasSize() def startDraw(self,event): # don't start if we can't finish if not self.testOrAcquireLock() and not self.inDrawingMode: return x0,y0 = self.mainCanvas.canvasx(event.x),self.mainCanvas.canvasy(event.y) x = x0/self.magnification y = y0/self.magnification #self.mainCanvas.create_oval(x,y,x,y,width=5) if self.selectedButton == self.toolDrawEllipButton: pass elif self.selectedButton == self.toolFillEllipButton: pass elif self.selectedButton == self.toolTextButton: theText = tkSimpleDialog.askstring(title="Xasy - Text",prompt="Enter text to display:",initialvalue="",parent=self.parent) if theText != None and theText != "": theItem = xasyText(theText,(x,-y),asyPen(self.penColor,self.penWidth,self.penOptions)) theItem.drawOnCanvas(self.mainCanvas,self.magnification) self.bindItemEvents(theItem) self.addItemToFile(theItem) self.undoRedoStack.add(addLabelAction(self,theItem)) self.releaseLock() self.updateSelectedButton(self.toolSelectButton) elif self.selectedButton in [self.toolDrawLinesButton,self.toolDrawBeziButton,self.toolDrawPolyButton,self.toolDrawShapeButton,self.toolFillPolyButton,self.toolFillShapeButton]: self.inDrawingMode = True try: if len(self.itemBeingDrawn.path.nodeSet) == 0: raise Exception else: if self.selectedButton in [self.toolDrawLinesButton,self.toolDrawPolyButton,self.toolFillPolyButton]: self.itemBeingDrawn.appendPoint((x,-y),'--') else:#drawBezi,drawShape,fillShape self.itemBeingDrawn.appendPoint((x,-y),'..') except: path = asyPath() if self.selectedButton == self.toolDrawLinesButton: path.initFromNodeList([(x,-y),(x,-y)],['--']) elif self.selectedButton == self.toolDrawBeziButton: path.initFromNodeList([(x,-y),(x,-y)],['..']) elif self.selectedButton == self.toolDrawPolyButton or self.selectedButton == self.toolFillPolyButton: path.initFromNodeList([(x,-y),(x,-y),'cycle'],['--','--']) elif self.selectedButton == self.toolDrawShapeButton or self.selectedButton == self.toolFillShapeButton: path.initFromNodeList([(x,-y),(x,-y),'cycle'],['..','..']) if self.selectedButton in [self.toolDrawLinesButton,self.toolDrawBeziButton,self.toolDrawPolyButton,self.toolDrawShapeButton]: self.itemBeingDrawn = xasyShape(path,pen=asyPen(self.penColor,self.penWidth,self.penOptions)) else: if self.penOptions.find("fillrule") != -1 or self.penOptions.find("evenodd") != -1 or self.penOptions.find("zerowinding") != -1: options = self.penOptions else: options = "evenodd" self.itemBeingDrawn = xasyFilledShape(path,pen=asyPen(self.penColor,self.penWidth,options)) self.itemBeingDrawn.drawOnCanvas(self.mainCanvas,self.magnification) self.bindItemEvents(self.itemBeingDrawn) self.mainCanvas.bind("",self.extendDraw) def extendDraw(self,event): x0,y0 = self.mainCanvas.canvasx(event.x),self.mainCanvas.canvasy(event.y) x = x0/self.magnification y = y0/self.magnification tags = self.mainCanvas.gettags("itemBeingDrawn") self.itemBeingDrawn.setLastPoint((x,-y)) self.itemBeingDrawn.drawOnCanvas(self.mainCanvas,self.magnification) self.canvMotion(event) def endDraw(self,event): if not self.inDrawingMode or self.itemBeingDrawn == None: return x0,y0 = self.mainCanvas.canvasx(event.x),self.mainCanvas.canvasy(event.y) x = x0/self.magnification y = y0/self.magnification #if self.selectedButton in [self.toolDrawLinesButton,self.toolDrawPolyButton,self.toolFillPolyButton]: #self.itemBeingDrawn.appendPoint((x,-y),'--') #else: #self.itemBeingDrawn.appendPoint((x,-y),'..') #only needed for certain key bindings when startDraw is triggered right before an endDraw #e.g.: single click: startDraw, double click: endDraw self.itemBeingDrawn.removeLastPoint() self.itemBeingDrawn.setLastPoint((x,-y)) self.itemBeingDrawn.drawOnCanvas(self.mainCanvas,self.magnification) self.addItemToFile(self.itemBeingDrawn) self.undoRedoStack.add(addDrawnItemAction(self,self.itemBeingDrawn)) self.itemBeingDrawn = None self.mainCanvas.dtag("itemBeingDrawn","itemBeingDrawn") self.mainCanvas.bind("",self.canvMotion) self.inDrawingMode = False self.releaseLock() def canvLeftDown(self,event): #print "Left Mouse Down" self.selectDragStart = (self.mainCanvas.canvasx(event.x),self.mainCanvas.canvasy(event.y)) theBbox = self.mainCanvas.bbox("selectedItem") if theBbox != None: self.selectBboxMidpoint = (theBbox[0]+theBbox[2])/2.0,-(theBbox[1]+theBbox[3])/2.0 if self.freeMouseDown and self.editor != None: self.editor.endEdit() if self.editor.modified: self.undoRedoStack.add(editDrawnItemAction(self,self.itemBeingEdited,copy.deepcopy(self.editor.shape),self.fileItems.index(self.editor.shape))) self.editor = None elif self.selectedButton in (self.toolSelectButton,self.toolMoveButton,self.toolVertiMoveButton,self.toolHorizMoveButton,self.toolRotateButton): if self.freeMouseDown: self.clearSelection() self.dragSelecting = False else: self.startDraw(event) def canvLeftUp(self,event): #print "Left Mouse Up" # if we're busy, ignore it if not self.testOrAcquireLock(): return self.freeMouseDown = True if self.inRotatingMode: for item in self.itemsBeingRotated: item.drawOnCanvas(self.mainCanvas,self.magnification) self.bindItemEvents(item) self.updateSelection() self.itemsBeingRotated = [] self.inRotatingMode = False if self.dragSelecting: self.hideSelectionBox() self.dragSelecting = False self.mainCanvas.addtag_enclosed("enclosed",self.selectDragStart[0],self.selectDragStart[1],self.mainCanvas.canvasx(event.x),self.mainCanvas.canvasy(event.y)) for item in self.mainCanvas.find_withtag("enclosed"): tags = self.mainCanvas.gettags(item) if "drawn" not in tags and "image" not in tags: self.mainCanvas.dtag(item,"enclosed") self.mainCanvas.addtag_withtag("selectedItem","enclosed") self.mainCanvas.dtag("enclosed","enclosed") if self.selectedButton == self.toolSelectButton and len(self.mainCanvas.find_withtag("selectedItem")) > 0: self.updateSelectedButton(self.toolMoveButton) self.updateSelection() self.releaseLock() def canvDrag(self,event): x0,y0 = self.mainCanvas.canvasx(event.x),self.mainCanvas.canvasy(event.y) x = x0/self.magnification y = y0/self.magnification if self.selectedButton == self.toolSelectButton and self.editor == None: self.mainCanvas.coords("outlineBox",self.selectDragStart[0],self.selectDragStart[1],x0,y0) self.showSelectionBox() self.dragSelecting = True elif self.selectedButton == self.toolRotateButton and self.editor == None: bbox = self.mainCanvas.bbox("selectedItem") if bbox != None: p1 = self.selectDragStart[0]-self.selectBboxMidpoint[0],-self.selectDragStart[1]-self.selectBboxMidpoint[1] mp1 = math.sqrt(p1[0]**2+p1[1]**2) p2 = x0-self.selectBboxMidpoint[0],-y0-self.selectBboxMidpoint[1] mp2 = math.sqrt(p2[0]**2+p2[1]**2) if mp1 != 0: t1 = math.acos(p1[0]/mp1) if p1[1] < 0: t1 *= -1 else: t1 = 0 if mp2 != 0: t2 = math.acos(p2[0]/mp2) if p2[1] < 0: t2 *= -1 else: t2 = 0 theta = t2-t1 self.selectDragStart = x0,y0 self.itemsBeingRotated = [] for ID in self.mainCanvas.find_withtag("selectedItem"): self.rotateSomething(ID,theta,self.selectBboxMidpoint) item = self.findItem(ID) if not item in self.itemsBeingRotated: self.itemsBeingRotated.append(item) self.updateSelection() self.updateCanvasSize() if not self.inRotatingMode: self.currentRotationAngle = theta IDList = self.mainCanvas.find_withtag("selectedItem") itemList = [] indexList = [] for ID in IDList: item = self.findItem(ID) if item not in itemList: itemList.append(item) try: indexList.append([self.findItemImageIndex(item,ID)]) except: indexList.append([None]) else: indexList[itemList.index(item)].append(self.findItemImageIndex(item,ID)) self.undoRedoStack.add(rotationAction(self,itemList,indexList,self.currentRotationAngle,self.selectBboxMidpoint)) self.inRotatingMode = True else: self.currentRotationAngle += theta self.undoRedoStack.undoStack[-1].angle = self.currentRotationAngle def canvEnter(self,event): self.freeMouseDown = True event.widget.focus_set() def canvLeave(self,event): self.freeMouseDown = False def canvRightDown(self,event): pass #print "Right Mouse Down" def canvRightUp(self,event): pass #print "Right Mouse Up" def configEvt(self,event): self.updateCanvasSize() self.sizePane() def sizePane(self): width = self.windowPane.winfo_width()-10 cwidth = min(int(0.87*self.windowPane.winfo_width()),width-75) if self.paneVisible: self.windowPane.paneconfigure(self.canvFrame,minsize=cwidth) else: self.windowPane.paneconfigure(self.canvFrame,minsize=width) self.windowPane.paneconfigure(self.propFrame,minsize=75) def togglePaneEvt(self,event): self.paneVisible = not self.paneVisible self.sizePane() def popupDelete(self): self.deleteItem(self.itemPopupMenu.item) def popupEdit(self): self.itemEdit(self.itemPopupMenu.item) def popupViewCode(self): tkMessageBox.showinfo("Item Code",self.itemPopupMenu.item.getCode()) def popupClearTransform(self): self.undoRedoStack.add(clearItemTransformsAction(self,self.itemPopupMenu.item,copy.deepcopy(self.itemPopupMenu.item.transform))) if isinstance(self.itemPopupMenu.item,xasyScript) or isinstance(self.itemPopupMenu.item,xasyText): for i in range(len(self.itemPopupMenu.item.transform)): self.itemPopupMenu.item.transform[i] = identity() else: self.itemPopupMenu.item.transform = [identity()] self.popupRedrawItem() def popupRedrawItem(self): if not self.testOrAcquireLock(): return self.clearSelection() self.clearHighlight() self.itemPopupMenu.item.drawOnCanvas(self.mainCanvas,self.magnification) self.bindItemEvents(self.itemPopupMenu.item) self.updateCanvasSize() self.releaseLock() def hidePopupMenu(self): try: self.itemPopupMenu.unpost() except: pass def itemMenuPopup(self,parent,item,x,y): self.hidePopupMenu() self.itemPopupMenu = Menu(parent,tearoff=False) self.itemPopupMenu.add_command(label="Edit",command=self.popupEdit) self.itemPopupMenu.add_command(label="Clear Transforms",command=self.popupClearTransform) self.itemPopupMenu.add_command(label="Redraw",command=self.popupRedrawItem) self.itemPopupMenu.add_command(label="View code",command=self.popupViewCode) self.itemPopupMenu.add_separator() self.itemPopupMenu.add_command(label="Delete",command=self.popupDelete) self.itemPopupMenu.item = item #self.itemPopupMenu.bind("",lambda a:self.itemPopupMenu.unpost()) #self.itemPopupMenu.bind("",lambda a:self.itemPopupMenu.unpost()) self.itemPopupMenu.post(x,y) def itemPropMenuPopup(self,event): try: item = self.fileItems[len(self.fileItems)-int(self.propList.curselection()[0])-1] self.itemMenuPopup(self.propList,item,event.x_root,event.y_root) except: pass def itemCanvasMenuPopup(self,event): if self.selectedButton in (self.toolSelectButton,self.toolMoveButton,self.toolVertiMoveButton,self.toolHorizMoveButton,self.toolRotateButton): try: item = self.findItem(self.mainCanvas.find_withtag(CURRENT)[0]) except: item = None if item != None: self.itemMenuPopup(self.mainCanvas,item,event.x_root,event.y_root) def editOptions(self): if(not self.testOrAcquireLock()): return self.releaseLock() xasyOptionsDialog.xasyOptionsDlg(self.parent) self.applyOptions() def resetOptions(self): xasyOptions.setDefaults() self.applyOptions() def applyPenWidth(self): self.pendingPenWidthChange = None if self.validatePenWidth(): old = self.penWidth self.penWidth = float(self.penWidthEntry.get()) if old != self.penWidth: self.showCurrentPen() def validatePenWidth(self): text = self.penWidthEntry.get() try: width = float(text) if width <= 0: return False else: return True except: return False def showCurrentPen(self): mag = 1 width = self.penWidth while width > 10: width /= 2 mag *= 2 self.penDisp.itemconfigure("penDisp",width=width,fill=self.tkPenColor) self.penDisp.itemconfigure("penMag",text="x%d"%mag) #apply the new pen to any selected items IDs = self.mainCanvas.find_withtag("selectedItem") madeAChange = False for ID in IDs: item = self.findItem(ID) if not isinstance(item,xasyScript): if not madeAChange: self.undoRedoStack.add(endActionGroup) madeAChange = True if isinstance(item,xasyText): temp = item.label.pen item.label.pen = asyPen(self.penColor,self.penWidth,self.penOptions) item.drawOnCanvas(self.mainCanvas,self.magnification) self.bindItemEvents(item) self.setSelection(item.imageList[0].IDTag) self.undoRedoStack.add(editLabelPenAction(self,temp,asyPen(self.penColor,self.penWidth,self.penOptions),self.fileItems.index(item))) else: temp = copy.deepcopy(item) item.pen = asyPen(self.penColor,self.penWidth,self.penOptions) item.drawOnCanvas(self.mainCanvas,self.magnification) self.undoRedoStack.add(editDrawnItemAction(self,temp,copy.deepcopy(item),self.fileItems.index(item))) if madeAChange: self.undoRedoStack.add(beginActionGroup) def applyPenWidthEvt(self,event): if not self.testOrAcquireLock(): return self.applyPenWidth() self.releaseLock() def penWidthChanged(self,event): if self.pendingPenWidthChange is not None: self.penWidthEntry.after_cancel(self.pendingPenWidthChange) self.pendingPenWidthChange = self.penWidthEntry.after(1000,self.applyPenWidth) def applyPenOptEvt(self,event): if not self.testOrAcquireLock(): return self.applyPenOpt() self.releaseLock() def validatePenOpt(self): try: penTest = asyPen(self.penColor,self.penWidth,self.penOptEntry.get()) return True except: self.penOptEntry.select_range(0,END) self.penOptEntry.delete(0,END) self.penOptEntry.insert(END,"Invalid Pen Options") self.penOptEntry.after(5000,self.clearInvalidOptEntry) self.penOptions = "" return False def clearInvalidOptEntry(self): self.penOptEntry.select_range(0,END) self.penOptEntry.delete(0,END) def applyPenOpt(self): if self.validatePenOpt(): old = self.penOptions self.penOptions = self.penOptEntry.get() if old != self.penOptions: self.showCurrentPen() def undoOperation(self): self.undoRedoStack.undo() def redoOperation(self): self.undoRedoStack.redo() def resetStacking(self): for item in self.fileItems: self.raiseSomething(item,force=True) asymptote-2.37/GUI/xasyOptions.py000077500000000000000000000062231265434602500170450ustar00rootroot00000000000000#!/usr/bin/env python ########################################################################### # # xasyOptions provides a mechanism for storing and restoring a user's # preferences. # # # Author: Orest Shardt # Created: June 29, 2007 # ########################################################################### import pickle import sys,os import errno defaultOptions = { 'asyPath':'asy', 'showDebug':False, 'showGrid':False, 'gridX':10, 'gridY':10, 'gridColor':'#eeeeee', 'showAxes':True, 'axisX':10, 'axisY':10, 'axesColor':'#cccccc', 'tickColor':'#eeeeee', 'defPenOptions':'', 'defPenColor':'#000000', 'defPenWidth':1.0, 'externalEditor':'' } if sys.platform[:3] == "win": defaultOptions['externalEditor'] = "%PROGRAMFILES%\Windows NT\Accessories\wordpad.exe" else: defaultOptions['externalEditor'] = "emacs" options = defaultOptions.copy() def settingsFileLocation(): folder = "" try: folder = os.path.expanduser("~/.asy/") except: pass return os.path.normcase(os.path.join(folder,"xasy.conf")) def setAsyPathFromWindowsRegistry(): try: import _winreg as registry #test both registry locations try: key = registry.OpenKey(registry.HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\Asymptote") options['asyPath'] = registry.QueryValueEx(key,"Path")[0]+"\\asy.exe" registry.CloseKey(key) except: key = registry.OpenKey(registry.HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Asymptote") options['asyPath'] = registry.QueryValueEx(key,"InstallLocation")[0]+"\\asy.exe" registry.CloseKey(key) except: #looks like asy is not installed or this isn't Windows pass def setDefaults(): global options options = defaultOptions.copy() if sys.platform[:3] == 'win': #for windows, wince, win32, etc setAsyPathFromWindowsRegistry() save() def load(): global options fileName = settingsFileLocation() if not os.path.exists(fileName): #make folder thedir = os.path.dirname(fileName) if not os.path.exists(thedir): try: os.makedirs(thedir) except: raise Exception,"Could not create configuration folder" if not os.path.isdir(thedir): raise Exception,"Configuration folder path does not point to a folder" setDefaults() try: f = open(fileName,"rb") newOptions = pickle.load(f) for key in options.keys(): if type(newOptions[key]) != type(options[key]): raise Exception,"Bad type for entry in xasy settings" options = newOptions except: setDefaults() def save(): global options fileName = settingsFileLocation() try: f = open(fileName,"wb") pickle.dump(options,f) f.close() except: raise Exception,"Error saving preferences" load() if __name__=='__main__': print settingsFileLocation() print "Current content" load() print "Setting defaults" setDefaults() save() load() options['showAxes'] = options['showGrid'] = False save() print "Set to False" load() options['showAxes'] = options['showGrid'] = True save() print "Set to True" load() print options asymptote-2.37/GUI/xasyOptionsDialog.py000077500000000000000000000211551265434602500201660ustar00rootroot00000000000000#!/usr/bin/env python ########################################################################### # # xasyOptionsDialog implements a dialog window to allow users to edit # their preferences and specify program options # # # Author: Orest Shardt # Created: June 29, 2007 # ########################################################################### from Tkinter import * import xasyOptions import tkSimpleDialog import xasyColorPicker import tkMessageBox import tkFileDialog import tkColorChooser import os import sys class xasyOptionsDlg(tkSimpleDialog.Dialog): """A dialog to interact with users about their preferred settings""" def __init__(self,master=None): tkSimpleDialog.Dialog.__init__(self,master,"xasy Options") def body(self,master): optFrame = Frame(master) optFrame.grid(row=0,column=0,sticky=N+S+E+W) asyGrp = LabelFrame(optFrame,text="Asymptote",padx=5,pady=5) asyGrp.grid(row=0,column=0,sticky=E+W) asyGrp.rowconfigure(0,weight=1) asyGrp.rowconfigure(1,weight=1) asyGrp.columnconfigure(0,weight=1) asyGrp.columnconfigure(0,weight=2) Label(asyGrp,text="Command").grid(row=0,column=0,sticky=W) self.ap = Entry(asyGrp) self.ap.insert(END,xasyOptions.options['asyPath']) self.ap.grid(row=0,column=1,sticky=E+W) Button(asyGrp,text="...",command=self.findAsyPath).grid(row=0,column=2,sticky=E+W) self.showDebug = BooleanVar() self.showDebug.set(xasyOptions.options['showDebug']) self.sd = Checkbutton(asyGrp,text="Show debugging info in console",var=self.showDebug) self.sd.grid(row=1,column=0,columnspan=2,sticky=W) editGrp = LabelFrame(optFrame,text="External Editor",padx=5,pady=5) editGrp.grid(row=1,column=0,sticky=E+W) editGrp.rowconfigure(0,weight=1) editGrp.rowconfigure(1,weight=1) editGrp.columnconfigure(0,weight=1) editGrp.columnconfigure(0,weight=2) Label(editGrp,text="Program").grid(row=0,column=0,sticky=W) self.ee = Entry(editGrp) self.ee.insert(END,xasyOptions.options['externalEditor']) self.ee.grid(row=0,column=1,sticky=E+W) Button(editGrp,text="...",command=self.findEEPath).grid(row=0,column=2,sticky=E+W) penGrp = LabelFrame(optFrame,text="Default Pen",padx=5,pady=5) penGrp.grid(row=2,column=0,sticky=E+W) penGrp.rowconfigure(0,weight=1) penGrp.rowconfigure(1,weight=1) penGrp.rowconfigure(2,weight=1) penGrp.columnconfigure(1,weight=1) Label(penGrp,text="Color").grid(row=0,column=0,sticky=E) self.pc = xasyOptions.options['defPenColor'] Button(penGrp,text="Change",command=self.changePenColor).grid(row=0,column=1,sticky=W) Label(penGrp,text="Width").grid(row=1,column=0,sticky=E) self.pw = Entry(penGrp) self.pw.insert(END,str(xasyOptions.options['defPenWidth'])) self.pw.grid(row=1,column=1,sticky=E+W) Label(penGrp,text="Options").grid(row=2,column=0,sticky=E) self.po = Entry(penGrp) self.po.insert(END,xasyOptions.options['defPenOptions']) self.po.grid(row=2,column=1,sticky=E+W) dispGrp = LabelFrame(optFrame,text="Display Options",padx=5,pady=5) dispGrp.grid(row=3,column=0,sticky=E+W) dispGrp.rowconfigure(0,weight=1) dispGrp.rowconfigure(1,weight=1) dispGrp.rowconfigure(2,weight=1) dispGrp.rowconfigure(3,weight=1) dispGrp.columnconfigure(0,weight=1) dispGrp.columnconfigure(1,weight=1) dispGrp.columnconfigure(2,weight=1) self.showAxes = BooleanVar() self.showAxes.set(xasyOptions.options['showAxes']) self.sa = Checkbutton(dispGrp,text="Show Axes",var=self.showAxes) self.sa.grid(row=0,column=0,sticky=W) self.ac = xasyOptions.options['axesColor'] Button(dispGrp,text="Color...",command=self.changeAxesColor).grid(row=1,column=0) Label(dispGrp,text="x").grid(row=0,column=1,padx=5,sticky=E) self.axs = Entry(dispGrp,width=6) self.axs.insert(END,xasyOptions.options['axisX']) self.axs.grid(row=0,column=2,sticky=W+E) Label(dispGrp,text="y").grid(row=1,column=1,padx=5,sticky=E) self.ays = Entry(dispGrp,width=6) self.ays.insert(END,xasyOptions.options['axisY']) self.ays.grid(row=1,column=2,sticky=W+E) self.showGrid = BooleanVar() self.showGrid.set(xasyOptions.options['showGrid']) self.sg = Checkbutton(dispGrp,text="Show Grid",var=self.showGrid) self.sg.grid(row=4,column=0,sticky=W) self.gc = xasyOptions.options['gridColor'] Button(dispGrp,text="Color...",command=self.changeGridColor).grid(row=3,column=0) Label(dispGrp,text="x").grid(row=2,column=1,padx=5,sticky=E) self.gxs = Entry(dispGrp,width=6) self.gxs.insert(END,xasyOptions.options['gridX']) self.gxs.grid(row=2,column=2,sticky=W+E) Label(dispGrp,text="y").grid(row=3,column=1,padx=5,sticky=E) self.gys = Entry(dispGrp,width=6) self.gys.insert(END,xasyOptions.options['gridY']) self.gys.grid(row=3,column=2,sticky=W+E) def findEEPath(self): if sys.platform[:3] == 'win': #for windows, wince, win32, etc file=tkFileDialog.askopenfile(filetypes=[("Programs","*.exe"),("All files","*")],title="Choose External Editor",parent=self) else: file=tkFileDialog.askopenfile(filetypes=[("All files","*")],title="Choose External Editor",parent=self) if file != None: name = os.path.abspath(file.name) file.close() self.ee.delete(0,END) self.ee.insert(END,name) self.validate() def findAsyPath(self): if sys.platform[:3] == 'win': #for windows, wince, win32, etc file=tkFileDialog.askopenfile(filetypes=[("Programs","*.exe"),("All files","*")],title="Find Asymptote Executable",parent=self) else: file=tkFileDialog.askopenfile(filetypes=[("All files","*")],title="Find Asymptote Executable",parent=self) if file != None: name = os.path.abspath(file.name) file.close() self.ap.delete(0,END) self.ap.insert(END,name) self.validate() def getAColor(self,color): result = xasyColorPicker.xasyColorDlg(self).getColor(xasyColorPicker.makeRGBfromTkColor(color)) return xasyColorPicker.RGB255hex(xasyColorPicker.RGBreal255(result)) def changeAxesColor(self): self.ac = self.getAColor(self.ac) def changeGridColor(self): self.gc = self.getAColor(self.gc) def changePenColor(self): self.pc = self.getAColor(self.pc) def apply(self): xasyOptions.options['externalEditor'] = self.ee.get() xasyOptions.options['asyPath'] = self.ap.get() xasyOptions.options['showDebug'] = bool(self.showDebug.get()) xasyOptions.options['defPenColor'] = self.pc xasyOptions.options['defPenWidth'] = float(self.pw.get()) xasyOptions.options['defPenOptions'] = self.po.get() xasyOptions.options['showAxes'] = bool(self.showAxes.get()) xasyOptions.options['axesColor'] = self.ac xasyOptions.options['tickColor'] = self.ac xasyOptions.options['axisX'] = int(self.axs.get()) xasyOptions.options['axisY'] = int(self.ays.get()) xasyOptions.options['showGrid'] = bool(self.showGrid.get()) xasyOptions.options['gridColor'] = self.gc xasyOptions.options['gridX'] = int(self.gxs.get()) xasyOptions.options['gridY'] = int(self.gys.get()) xasyOptions.save() def validateAColor(self,color): hexdigits = '0123456789abcdef' if len(self.pc) != 7 or self.pc[0] != '#' or sum([1 for a in self.pc[1:] if a in hexdigits]) != 6: return False else: return True def validate(self): """Validate the data entered into the dialog""" #validate the color hexdigits = '0123456789abcdef' if not self.validateAColor(self.pc): tkMessageBox.showerror("xasy Options","Invalid pen color.\r\n"+self.pc,parent=self) return False #validate the width try: test = float(self.pw.get()) except: tkMessageBox.showerror("xasy Options","Pen width must be a number.",parent=self) return False #validate the options #nothing to do #validate the axis spacing try: test = int(self.axs.get()) test = int(self.ays.get()) except: tkMessageBox.showerror("xasy Options","Axes' x- and y-spacing must be numbers.",parent=self) return False #validate the grid spacing try: test = int(self.gxs.get()) test = int(self.gys.get()) except: tkMessageBox.showerror("xasy Options","Grid's x- and y-spacing must be numbers.",parent=self) return False if not self.validateAColor(self.ac): tkMessageBox.showerror("xasy Options","Invalid axis color.\r\n"+self.ac,parent=self) return False if not self.validateAColor(self.gc): tkMessageBox.showerror("xasy Options","Invalid grid color.\r\n"+self.gc,parent=self) return False return True if __name__ == '__main__': root = Tk() xasyOptions.load() d = xasyOptionsDlg(root) print d.result asymptote-2.37/INSTALL000066400000000000000000000243151265434602500145370ustar00rootroot00000000000000Compiling Asymptote from a Source Release ========================================= To compile and install Asymptote version x.xx from a source release: gunzip asymptote-x.xx.src.tgz tar -xf asymptote-x.xx.src.tar cd asymptote-x.xx ./configure make all make install The last command requires root privileges. To install without root privileges you should change the first line to ./configure --prefix=$HOME/asymptote If you get errors from a broken texinfo or pdftex installation, simply put http://asymptote.sourceforge.net/asymptote.pdf in the doc directory and repeat the commands make all and make install. For a list of configure options, type configure --help See also the generic configure instructions below. Compiling Asymptote from Git Developmental Source Code ============================================================= To compile from Git developmental source code: git clone http://github.com/vectorgraphics/asymptote cd asymptote ./autogen.sh ./configure make all make install Optional packages: * Fast Fourier Transform library http://www.fftw.org/ Version requirement >= 3.0 * The GNU Scientific Library for numerical analysis: http://www.gnu.org/software/gsl/ ***************************************** Generic Configure Instructions (advanced) ***************************************** The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves the results of its tests to speed up reconfiguring. (Caching is disabled by default to prevent problems with accidental use of stale cache files.) If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If you are using the cache, and at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create `configure' by a program called `autoconf'. You only need `configure.ac' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. Run `./configure --help' for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not support the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' installs the package's commands under `/usr/local/bin', include files under `/usr/local/include', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PREFIX'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you pass the option `--exec-prefix=PREFIX' to `configure', the package uses PREFIX as the prefix for installing programs and libraries. Documentation and other data files still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=DIR' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the option `--target=TYPE' to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE'. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc causes the specified `gcc' to be used as the C compiler (unless it is overridden in the site shell script). Here is a another example: /bin/bash ./configure CONFIG_SHELL=/bin/bash Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent configuration-related scripts to be executed by `/bin/bash'. `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of the options to `configure', and exit. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `configure' also accepts some other options. Run `configure --help' for more details. asymptote-2.37/LICENSE000066400000000000000000001045131265434602500145120ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . asymptote-2.37/LICENSE.LESSER000066400000000000000000000167271265434602500155170ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. asymptote-2.37/Makefile.in000066400000000000000000000231731265434602500155540ustar00rootroot00000000000000# @configure_input@ ARCH = unix POLL = poll GCVERSION = @GCVERSION@ GC = gc-$(GCVERSION) LIBATOMIC = libatomic_ops-$(GCVERSION) GCOPTIONS = @GCOPTIONS@ GCLIB = @GCLIB@ GCPPLIB = @GCPPLIB@ GCLIBS = $(GCPPLIB) $(GCLIB) LFLAGS = @LDFLAGS@ LIBS = $(LFLAGS) @PTHREAD_LIBS@ @LIBS@ $(GCLIBS) DOSLIBS = $(subst -lncurses, -ltermcap, $(LIBS)) -s -static PERL = perl # Libraries needed to make asymptote.so. # We have to remove OpenGL, threading, GC, etc from this. SHAREDLIBS = $(filter-out -lGL -lGLU -lglut -pthread $(GCLIBS), $(LIBS)) vpath %.cc prc CAMP = camperror path drawpath drawlabel picture psfile texfile util settings \ guide flatguide knot drawfill path3 drawpath3 drawsurface \ beziertriangle pen pipestream RUNTIME_FILES = runtime runbacktrace runpicture runlabel runhistory runarray \ runfile runsystem runpair runtriple runpath runpath3d runstring \ runmath # Files to be scanned for pre-translated symbols defined by SYM(name). SYMBOL_FILES = types builtin gsl $(RUNTIME_FILES) PRC = PRCbitStream oPRCFile PRCdouble writePRC COREFILES = $(CAMP) $(SYMBOL_FILES) env genv stm dec errormsg \ callable name symbol entry exp newexp stack camp.tab lex.yy \ access virtualfieldaccess absyn record interact fileio \ fftw++asy simpson coder coenv impdatum \ @getopt@ locate parser program application varinit fundec refaccess \ envcompleter process constructor array Delaunay predicates \ $(PRC) glrender tr arcball algebra3 quaternion FILES = $(COREFILES) main DIST = camp.tab.h camp.tab.cc lex.yy.cc runtime.cc keywords.cc \ asy-keywords.el $(RUNTIME_FILES:=.cc) $(RUNTIME_FILES:=.h) asy.list \ allsymbols.h opsymbols.h $(SYMBOL_FILES:=.symbols.h) NAME = asy XNAME = x$(NAME) CLEAN = camp.output base/version.asy doc/version.texi \ GUI/xasyVersion.py $(XNAME) doc/asy-latex.pdf EXTRA = asy-mode.el asy-init.el asy.vim asy_filetype.vim asy-kate.sh \ asymptote.py reload.js nopapersize.ps EXEXTRA = piicon.eps *.views *.dat *.bib DOCEXTRA = *.asy *.csv *.dat latexusage.tex externalprc.tex pixel.pdf KEYWORDS = base $(ASYMPTOTE_SITEDIR) LATEXFILES = asymptote.sty asycolors.sty ocg.sty latexmkrc CONTEXTFILES = colo-asy.tex ASY = ./asy -dir base -config "" -render=0 DEFS = @DEFS@ @OPTIONS@ @PTHREAD_CFLAGS@ -DFFTWPP_SINGLE_THREAD CFLAGS = @CXXFLAGS@ @CFLAGS@ OPTS = $(DEFS) @CPPFLAGS@ $(CFLAGS) INCL = -I. @INCL@ # Options for compiling the object files for the shared library. # gc has to be configured with the option --disable-threads in order to make a # shared library that doesn't seg fault. For now, just disable gc in the # shared library. SHAREDOPTS = $(filter-out -DUSEGC, $(DEFS)) $(CFLAGS) -fPIC -DFOR_SHARED CXX = @CXX@ -Wall CC = @CC@ -Wall MAKEDEPEND = $(OPTS) -O0 -M -DDEPEND BISON = bison LEX = @LEX@ prefix = @prefix@ exec_prefix = @exec_prefix@ datarootdir = @datarootdir@ bindir = $(DESTDIR)@bindir@ mandir = $(DESTDIR)@mandir@ infodir = $(DESTDIR)@infodir@ datadir = $(DESTDIR)@datadir@ asydir = $(datadir)/asymptote GUIdir = $(asydir)/GUI docdir = $(DESTDIR)@docdir@ exampledir = $(docdir)/examples animationsdir = $(exampledir)/animations latexdir = $(DESTDIR)@latexdir@ contextdir = $(DESTDIR)@contextdir@ INSTALL = @INSTALL@ REVISION = "const char *REVISION=" last = $(shell cat revision.cc | sed -e 's/.*\"\(.*\)\";/\\1/') usinggit = $(shell if test -d ".git"; then echo yes; fi) ifeq ($(usinggit),yes) revision = $(shell LC_ALL="C" git describe | sed -e 's/-g.*//') else revision = $(shell grep AC_INIT configure.ac | cut -s -d[ -f3 | cut -s -d] -f1) endif export prefix docdir exampledir mandir infodir INSTALL MAKE DESTDIR TEXI2DVI asy: version if test -n "$(MSDOS)"; then \ $(CXX) $(OPTS) -o $(NAME) $(FILES:=.o) revision.o asy.o $(DOSLIBS); \ else \ ln -sf GUI/xasy.py $(XNAME); \ $(CXX) $(OPTS) -o $(NAME) $(FILES:=.o) revision.o $(LIBS); \ fi version: $(GCLIB) $(FILES:=.o) if test ! -e revision.cc -o "$(revision)" != "$(last)"; then \ echo $(REVISION)\"$(revision)\"\; > revision.cc; \ fi $(CXX) $(OPTS) $(INCL) -o revision.o -c revision.cc; echo string VERSION=\"$(revision)\"\; > base/version.asy echo @set VERSION $(revision) > doc/version.texi echo @set Datadir @datadir@ >> doc/version.texi echo "#!/usr/bin/env python" > GUI/xasyVersion.py echo xasyVersion = \"$(revision)\" >> GUI/xasyVersion.py if test -n "$(MSDOS)"; then \ cat asy.rc | sed -e "s/ASYMPTOTE_VERSION/$(revision)/" | \ windres -o asy.o; \ fi asymptote.so: $(COREFILES:=.pic.o) $(CXX) $(OPTS) -shared -o asymptote.so revision.o $(COREFILES:=.pic.o) $(SHAREDLIBS) all: asy sty man faq asy-keywords.el $(GCLIB): $(GC).tar.gz gunzip -c $(GC).tar.gz > $(GC).tar tar -xf $(GC).tar rm -f $(GC).tar if test -r $(LIBATOMIC).tar.gz; then \ gunzip -c $(LIBATOMIC).tar.gz > $(LIBATOMIC).tar; \ tar -xf $(LIBATOMIC).tar; \ rm -f $(LIBATOMIC).tar; \ mv $(LIBATOMIC) $(GC)/libatomic_ops; \ fi if test "$(GC)" = "gc-7.0"; then \ cd $(GC)/include/private && \ patch < ../../../patches/gc-7.0nomem.patch; \ fi if test "$(GC)" = "gc-7.2b"; then \ mv gc-7.2 gc-7.2b; \ fi if test "$(GC)" = "gc-7.2c"; then \ mv gc-7.2 gc-7.2c; \ fi if test "$(GC)" = "gc-7.2d"; then \ mv gc-7.2 gc-7.2d; \ fi cd $(GC) && \ ./configure $(GCOPTIONS); \ $(MAKE) check $(GCPPLIB): $(GCLIB) sty: cd doc && $(MAKE) asy-latex.pdf dvi: asy sty cd doc && $(MAKE) dvi html: asy sty cd doc && $(MAKE) doc man: asy sty cd doc && $(MAKE) man faq: asy sty cd doc && $(MAKE) faq $(RUNTIME_FILES:=.cc): %.cc: runtime.pl opsymbols.h runtimebase.in %.in $(PERL) ./runtime.pl $(@:.cc=) $(SYMBOL_FILES:=.symbols.h): %.symbols.h: findsym.pl %.cc $(CXX) -E -DNOSYM $(OPTS) $(INCL) $(@:.symbols.h=.cc) | \ $(PERL) ./findsym.pl $@ - $(SYMBOL_FILES:=.o): %.o: %.symbols.h allsymbols.h: findsym.pl $(SYMBOL_FILES:=.cc) $(CXX) -E -DNOSYM $(OPTS) $(INCL) $(SYMBOL_FILES:=.cc) | \ $(PERL) ./findsym.pl $@ - symbol.o: opsymbols.h allsymbols.h camp.tab.cc: camp.y $(BISON) -dvt -b camp camp.y && mv camp.tab.c camp.tab.cc camp.tab.h: camp.tab.cc lex.yy.cc: camp.l $(LEX) -d -olex.yy.cc camp.l lex.yy.d: $(GCLIB) lex.yy.cc camp.tab.h keywords.cc: keywords.pl camp.l process.cc $(PERL) ./keywords.pl opsymbols.h: opsymbols.pl camp.l $(PERL) ./opsymbols.pl envcompleter.d: keywords.cc asy-keywords.el: asy @echo Creating $@; $(ASY) -l > asy.list ls $(addsuffix /*.asy,$(KEYWORDS)) | grep -v plain\* | \ grep -v three_\* | grep -v featpost3D | xargs $(ASY) -l >> asy.list $(PERL) ./asy-list.pl asy.list $(revision) install: asy-keywords.el install-texhash install-man install-all: install install-html install-texhash: install-asy -if test -z "$(DESTDIR)"; then \ texhash; \ fi install-asy: asy sty ${INSTALL} -d $(bindir) $(asydir) $(GUIdir) $(exampledir) \ $(animationsdir) -${INSTALL} -d $(latexdir) -${INSTALL} -d $(contextdir) ${INSTALL} -p -m 755 $(NAME) $(bindir) ${INSTALL} -p -m 644 base/*.asy $(addprefix base/,$(EXTRA)) \ asy-keywords.el $(asydir) ${INSTALL} -p -m 755 GUI/*.py $(GUIdir) ln -sf @datadir@/asymptote/GUI/xasy.py $(bindir)/$(XNAME) ${INSTALL} -p -m 644 examples/*.asy $(addprefix examples/,$(EXEXTRA)) \ doc/extra/*.asy $(addprefix doc/,$(DOCEXTRA)) $(exampledir) ${INSTALL} -p -m 644 examples/animations/*.asy \ examples/animations/inlinemovie.tex \ examples/animations/inlinemovie3.tex $(animationsdir) -${INSTALL} -p -m 644 $(addprefix doc/,$(LATEXFILES)) $(latexdir) -${INSTALL} -p -m 644 $(addprefix doc/,$(CONTEXTFILES)) $(contextdir) install-html: html cd doc && $(MAKE) install-all install-man: man cd doc && $(MAKE) install install-prebuilt: install-asy cd doc && $(MAKE) install-prebuilt uninstall: uninstall-all uninstall-all: uninstall-man uninstall-asy uninstall-docdir uninstall-asy: -cd $(animationsdir) && rm -f *.asy *.tex -rmdir $(animationsdir) -cd $(exampledir) && rm -f $(EXEXTRA) $(DOCEXTRA) -rmdir $(exampledir) -cd $(GUIdir) && rm -f *.py -rmdir $(GUIdir) -cd $(asydir) && rm -f asy-keywords.el *.asy $(EXTRA) -rmdir $(asydir) -cd $(latexdir) && rm -f $(LATEXFILES) -rmdir $(latexdir) -cd $(contextdir) && rm -f $(CONTEXTFILES) -rmdir $(contextdir) -cd $(bindir) && rm -f $(NAME) $(XNAME) uninstall-man: cd doc && $(MAKE) uninstall uninstall-docdir: -rmdir $(docdir) clean: FORCE -rm -f asy asymptote.so *.pic.o *.o *.d *mon.out $(CLEAN) gc-clean: FORCE clean -if test -d $(GC); then \ $(MAKE) -C $(GC) clean; \ fi cleaner: FORCE clean -if test -d $(GC); then \ rm -rf $(GC); \ fi -rm -f Makefile config.h config.log config.status errors.temp cd doc && $(MAKE) clean cd tests && $(MAKE) distclean distclean: FORCE cleaner cd doc && $(MAKE) distclean cleanest: FORCE maintainer-clean maintainer-clean: FORCE distclean -rm -f configure config.h.in $(DIST) -rm -rf autom4te.cache check: asy FORCE ./wce $(MAKE) -C tests check-all: asy FORCE ./wce $(MAKE) -C tests all .SUFFIXES: .c .cc .o .d .cc.o: $(CXX) $(OPTS) $(INCL) -o $@ -c $< .cc.d: @echo Creating $@; \ rm -f $@; \ ${CXX} $(MAKEDEPEND) $(INCL) $(MDOPTS) $< > $@.$$$$ 2>/dev/null && \ sed 's,\($*\)\.o[ :]*,\1.o \1.pic.o $@ : ,g' < $@.$$$$ > $@; \ rm -f $@.$$$$ .c.d: @echo Creating $@; \ rm -f $@; \ ${CC} $(MAKEDEPEND) $(INCL) $(MDOPTS) $< > $@.$$$$ 2>/dev/null && \ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ rm -f $@.$$$$ # Compile for the shared library. OpenGL must be disabled as it causes # crashes inside a shared library. %.pic.o: %.cc $(CXX) $(SHAREDOPTS) $(INCL) -o $@ -c $< ifeq (,$(findstring clean,${MAKECMDGOALS})) -include $(FILES:=.d) endif FORCE: configure: configure.ac autoheader && autoconf Makefile: Makefile.in config.status ./config.status config.status: configure ./config.status --recheck asymptote-2.37/README000066400000000000000000000050751265434602500143700ustar00rootroot00000000000000 ASYMPTOTE Copyright 2004-15 Andy Hammerlindl, John Bowman, and Tom Prince Asymptote is a powerful descriptive vector graphics language for technical drawing, inspired by MetaPost but with an improved C++-like syntax. Asymptote provides for figures the same high-quality level of typesetting that LaTeX does for scientific text. Installation instructions, documentation, binaries, and source code are available at: http://asymptote.sourceforge.net Bugs/Patches/Feature Requests can be submitted using the Bug/Patch/Feature Tracking Systems at http://sourceforge.net/projects/asymptote/. Questions and comments should be sent to the Asymptote Forum: http://sourceforge.net/p/asymptote/discussion/409349 All source files in the Asymptote project, unless explicitly noted otherwise, are released under version 3 (or later) of the GNU Lesser General Public License (see the files LICENSE.LESSER and LICENSE in the top-level source directory). ======================================================================== This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ======================================================================== Note that the MSWindows executable version of Asymptote can only be released under the GNU General Public License (GPL) as it is linked against the GNU Scientific Library, GNU Readline library, and other GPL libraries. This version of Asymptote also ships with the dll libraries noted below. The source code for the 2.0.2 cygwin1.dll is available under the GPL license: http://cygwin.com/snapshots/x86/cygwin-src-20150430.tar.xz The source code for freeglut.dll is available under the X-Consortium license: http://prdownloads.sourceforge.net/freeglut/freeglut-2.6.0.tar.gz The source code for glu32.dll is available from ftp://ftp.freedesktop.org/pub/mesa/7.6/MesaLib-7.6.tar.bz2 and patched as detailed here: http://old.nabble.com/Error-building-MesaLib-7.6-onto-Win32-with-Microsoft-Visual-Studio-2005-and-2008-td25990977.html asymptote-2.37/TODO000066400000000000000000000023211265434602500141670ustar00rootroot00000000000000Andy: add keyword-only arguments Andy: Arbitrary depth copying of arrays. Andy: Investigate bbox error in uofa-talk Shadowing slide Andy: change label in coder to a class not an Int Andy: look at label alignment in rotvenn Andy: possible optimizations: eliminate frame copying in picture.add(picture pic, ...) varpush+popcall --> varcall? fieldpush+popcall --> fieldcall? overloaded::simplify copies straight guide which references a subset of a pair vector. Is it cheaper to import a bltin module than to call base_venv again? varpush+pop --> no op varsave+pop --> one op closure+pushfunc+varsave+pop --> savefunc stack::popWithoutReturningValue look at position information saved in program, maybe save separately formal::addOps calls trans only hash first 3 or 4 args of signature rm transToType from varinitArg::trans change camp.y to flag arglists with named args Andy: testing in errortest.asy for packing versus casting, default argument ambiguities, and whatever else you can think of Andy: operator tuple, to let people define their own tuples Andy: Decide if we should change vm::error to em in application.cc John or Andy: Add unit test for AddOps. asymptote-2.37/absyn.cc000066400000000000000000000007301265434602500151240ustar00rootroot00000000000000/**** * absyn.cc * Tom Prince 2004/05/12 * * Utility functions for syntax trees. *****/ #include "absyn.h" #include "coenv.h" namespace absyntax { void absyn::markPos(trans::coenv& e) { e.c.markPos(getPos()); } absyn::~absyn() {} void prettyindent(ostream &out, Int indent) { for (Int i = 0; i < indent; i++) out << " "; } void prettyname(ostream &out, string name, Int indent) { prettyindent(out,indent); out << name << "\n"; } } // namespace absyntax asymptote-2.37/absyn.h000066400000000000000000000020061265434602500147640ustar00rootroot00000000000000/**** * absyn.h * Andy Hammerlindl 2002/07/14 * * Defines the basic types of abstract syntax objects using forward * class declarations. *****/ #ifndef ABSYN_H #define ABSYN_H #include "common.h" #include "errormsg.h" // For position // Forward declaration for markPos. namespace trans { class coenv; } namespace absyntax { class absyn : public gc { protected: const position pos; void markPos(trans::coenv& c); public: absyn(position pos) : pos(pos) {} virtual ~absyn(); position getPos() const { return pos; } virtual void prettyprint(ostream &out, Int indent) = 0; private: // Non-copyable void operator=(const absyn&); absyn(const absyn&); }; void prettyindent(ostream &out, Int indent); void prettyname(ostream &out, string name, Int indent); class name; class ty; class varinit; class exp; class runnable; class stm; class dec; class block; typedef block file; // This is the abstract syntax tree of a file, assigned to when running // yyparse. extern file *root; } #endif asymptote-2.37/access.cc000066400000000000000000000063551265434602500152620ustar00rootroot00000000000000/***** * access.cc * Andy Hammerlindl 2003/12/03 * Describes an "access," a representation of where a variable will be * stored at runtime, so that read, write, and call instructions can be * made. *****/ #include "access.h" #include "frame.h" #include "coder.h" #include "callable.h" using vm::item; namespace trans { /* access */ access::~access() {} /* identAccess */ void identAccess::encode(action act, position pos, coder& e) { if (act != CALL) { access::encode(act, pos, e); } // else - do nothing } /* bltinAccess */ static void bltinError(position pos) { em.error(pos); em << "built-in functions cannot be modified"; } void bltinAccess::encode(action act, position pos, coder &e) { switch (act) { case READ: e.encode(inst::constpush,(item)(vm::callable*)new vm::bfunc(f)); break; case WRITE: bltinError(pos); break; case CALL: e.encode(inst::builtin, f); break; } } void bltinAccess::encode(action act, position pos, coder &e, frame *) { e.encode(inst::pop); encode(act, pos, e); } /* callableAccess */ void callableAccess::encode(action act, position pos, coder &e) { switch (act) { case READ: e.encode(inst::constpush, (item)f); break; case WRITE: bltinError(pos); break; case CALL: this->encode(READ, pos, e); e.encode(inst::popcall); break; } } void callableAccess::encode(action act, position pos, coder &e, frame *) { e.encode(inst::pop); encode(act, pos, e); } /* frameAccess */ void frameAccess::encode(action act, position pos, coder &e) { if (act == READ) { if (!e.encode(f)) { em.compiler(pos); em << "encoding frame out of context"; } } else access::encode(act, pos, e); } void frameAccess::encode(action act, position pos, coder &e, frame *top) { if (act == READ) { if (!e.encode(f, top)) { em.compiler(pos); em << "encoding frame out of context"; } } else access::encode(act, pos, e, top); } /* localAccess */ static void frameError(position pos) { // A local variable is being used when its frame is not active. em.error(pos); em << "static use of dynamic variable"; } void localAccess::encode(action act, position pos, coder &e) { // Get the active frame of the virtual machine. frame *active = e.getFrame(); if (level == active) { e.encode(act == WRITE ? inst::varsave : inst::varpush, offset); } else if (e.encode(level)) { e.encode(act == WRITE ? inst::fieldsave : inst::fieldpush, offset); } else { frameError(pos); } if (act == CALL) e.encode(inst::popcall); } void localAccess::encode(action act, position pos, coder &e, frame *top) { if (e.encode(level,top)) { e.encode(act == WRITE ? inst::fieldsave : inst::fieldpush, offset); if (act == CALL) e.encode(inst::popcall); } else { frameError(pos); } } void qualifiedAccess::encode(action act, position pos, coder &e) { qualifier->encode(READ, pos, e); field->encode(act, pos, e, qualifierLevel); } void qualifiedAccess::encode(action act, position pos, coder &e, frame *top) { qualifier->encode(READ, pos, e, top); field->encode(act, pos, e, qualifierLevel); } } // namespace trans asymptote-2.37/access.h000066400000000000000000000056401265434602500151200ustar00rootroot00000000000000/***** * access.h * Andy Hammerlindl 2003/12/03 * * Describes an "access," a representation of where a variable will be * stored at runtime, so that read, write, and call instructions can be * made. *****/ #ifndef ACCESS_H #define ACCESS_H #include #include "errormsg.h" #include "item.h" #include "vm.h" namespace vm { struct callable; } namespace trans { class frame; class coder; enum action { READ, WRITE, CALL }; // These serves as the base class for the accesses. class access : public gc { protected: // Generic compiler access error - if the compiler functions properly, // none of these should be reachable by the user. void error(position pos) { em.compiler(pos); em << "invalid use of access"; } public: virtual ~access() = 0; // Encode a read/write/call of the access when nothing is on the stack. virtual void encode(action, position pos, coder &) { error(pos); } // Encode a read/write/call of the access when the frame "top" is on top // of the stack. virtual void encode(action, position pos, coder &, frame *) { error(pos); } }; // This class represents identity conversions in casting. class identAccess : public access { virtual void encode(action act, position, coder&); }; // Represents a function that is implemented by a built-in C++ function. class bltinAccess : public access { vm::bltin f; public: bltinAccess(vm::bltin f) : f(f) {} void encode(action act, position pos, coder &e); void encode(action act, position pos, coder &e, frame *); }; // Similar to bltinAccess, but works for any callable. class callableAccess : public access { vm::callable *f; public: callableAccess(vm::callable *f) : f(f) {} void encode(action act, position pos, coder &e); void encode(action act, position pos, coder &e, frame *); }; // An access that puts a frame on the top of the stack. class frameAccess : public access { frame *f; public: frameAccess(frame *f) : f(f) {} void encode(action act, position pos, coder &e); void encode(action act, position pos, coder &e, frame *top); }; // Represents the access of a local variable. class localAccess : public access { Int offset; frame *level; public: localAccess(Int offset, frame *level) : offset(offset), level(level) {} void encode(action act, position pos, coder &e); void encode(action act, position pos, coder &e, frame *top); }; class qualifiedAccess : public access { // The location and frame of the record. access *qualifier; frame *qualifierLevel; // The location of the field relative to the record. access *field; public: qualifiedAccess(access *qualifier, frame *qualifierLevel, access *field) : qualifier(qualifier), qualifierLevel(qualifierLevel), field(field) {} void encode(action act, position pos, coder &e); void encode(action act, position pos, coder &e, frame *top); }; } // namespace trans #endif // ACCESS_H asymptote-2.37/algebra3.cc000066400000000000000000001045621265434602500155000ustar00rootroot00000000000000/* algebra3.cpp, algebra3.h - C++ Vector and Matrix Algebra routines GLUI User Interface Toolkit (LGPL) Copyright (c) 1998 Paul Rademacher WWW: http://sourceforge.net/projects/glui/ Forums: http://sourceforge.net/forum/?group_id=92496 This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /************************************************************************** There are three vector classes and two matrix classes: vec2, vec3, vec4, mat3, and mat4. All the standard arithmetic operations are defined, with '*' for dot product of two vectors and multiplication of two matrices, and '^' for cross product of two vectors. Additional functions include length(), normalize(), homogenize for vectors, and print(), set(), apply() for all classes. There is a function transpose() for matrices, but note that it does not actually change the matrix, When multiplied with a matrix, a vector is treated as a row vector if it precedes the matrix (v*M), and as a column vector if it follows the matrix (M*v). Matrices are stored in row-major form. A vector of one dimension (2d, 3d, or 4d) can be cast to a vector of a higher or lower dimension. If casting to a higher dimension, the new component is set by default to 1.0, unless a value is specified: vec3 a(1.0, 2.0, 3.0 ); vec4 b( a, 4.0 ); // now b == {1.0, 2.0, 3.0, 4.0}; When casting to a lower dimension, the vector is homogenized in the lower dimension. E.g., if a 4d {X,Y,Z,W} is cast to 3d, the resulting vector is {X/W, Y/W, Z/W}. It is up to the user to insure the fourth component is not zero before casting. There are also the following function for building matrices: identity2D(), translation2D(), rotation2D(), scaling2D(), identity3D(), translation3D(), rotation3D(), rotation3Drad(), scaling3D(), perspective3D() --------------------------------------------------------------------- Author: Jean-Francois DOUEg Revised: Paul Rademacher Version 3.2 - Feb 1998 Revised: Nigel Stewart (GLUI Code Cleaning) **************************************************************************/ #include "algebra3.h" #include static const double radians=std::acos(-1)/180.0; #ifdef VEC_ERROR_FATAL #ifndef VEC_ERROR #define VEC_ERROR(E) { printf( "VERROR %s\n", E ); exit(1); } #endif #else #ifndef VEC_ERROR #define VEC_ERROR(E) { printf( "VERROR %s\n", E ); } #endif #endif /**************************************************************** * * * vec2 Member functions * * * ****************************************************************/ /******************** vec2 CONSTRUCTORS ********************/ vec2::vec2() { n[VX] = n[VY] = 0.0; } vec2::vec2(float x, float y) { n[VX] = x; n[VY] = y; } vec2::vec2(const vec2 &v) { n[VX] = v.n[VX]; n[VY] = v.n[VY]; } vec2::vec2(const vec3 &v) // it is up to caller to avoid divide-by-zero { n[VX] = v.n[VX]/v.n[VZ]; n[VY] = v.n[VY]/v.n[VZ]; } vec2::vec2(const vec3 &v, int dropAxis) { switch (dropAxis) { case VX: n[VX] = v.n[VY]; n[VY] = v.n[VZ]; break; case VY: n[VX] = v.n[VX]; n[VY] = v.n[VZ]; break; default: n[VX] = v.n[VX]; n[VY] = v.n[VY]; break; } } /******************** vec2 ASSIGNMENT OPERATORS ******************/ vec2 & vec2::operator=(const vec2 &v) { n[VX] = v.n[VX]; n[VY] = v.n[VY]; return *this; } vec2 & vec2::operator+=(const vec2 &v) { n[VX] += v.n[VX]; n[VY] += v.n[VY]; return *this; } vec2 & vec2::operator-=(const vec2 &v) { n[VX] -= v.n[VX]; n[VY] -= v.n[VY]; return *this; } vec2 &vec2::operator*=(float d) { n[VX] *= d; n[VY] *= d; return *this; } vec2 &vec2::operator/=(float d) { float d_inv = 1.0f/d; n[VX] *= d_inv; n[VY] *= d_inv; return *this; } float &vec2::operator[](int i) { if (i < VX || i > VY) //VEC_ERROR("vec2 [] operator: illegal access; index = " << i << '\n') VEC_ERROR("vec2 [] operator: illegal access" ); return n[i]; } const float &vec2::operator[](int i) const { if (i < VX || i > VY) //VEC_ERROR("vec2 [] operator: illegal access; index = " << i << '\n') VEC_ERROR("vec2 [] operator: illegal access" ); return n[i]; } /******************** vec2 SPECIAL FUNCTIONS ********************/ float vec2::length() const { return (float) sqrt(length2()); } float vec2::length2() const { return n[VX]*n[VX] + n[VY]*n[VY]; } vec2 &vec2::normalize() // it is up to caller to avoid divide-by-zero { *this /= length(); return *this; } vec2 &vec2::apply(V_FCT_PTR fct) { n[VX] = (*fct)(n[VX]); n[VY] = (*fct)(n[VY]); return *this; } void vec2::set( float x, float y ) { n[VX] = x; n[VY] = y; } /******************** vec2 FRIENDS *****************************/ vec2 operator-(const vec2 &a) { return vec2(-a.n[VX],-a.n[VY]); } vec2 operator+(const vec2 &a, const vec2& b) { return vec2(a.n[VX]+b.n[VX], a.n[VY]+b.n[VY]); } vec2 operator-(const vec2 &a, const vec2& b) { return vec2(a.n[VX]-b.n[VX], a.n[VY]-b.n[VY]); } vec2 operator*(const vec2 &a, float d) { return vec2(d*a.n[VX], d*a.n[VY]); } vec2 operator*(float d, const vec2 &a) { return a*d; } vec2 operator*(const mat3 &a, const vec2 &v) { vec3 av; av.n[VX] = a.v[0].n[VX]*v.n[VX] + a.v[0].n[VY]*v.n[VY] + a.v[0].n[VZ]; av.n[VY] = a.v[1].n[VX]*v.n[VX] + a.v[1].n[VY]*v.n[VY] + a.v[1].n[VZ]; av.n[VZ] = a.v[2].n[VX]*v.n[VX] + a.v[2].n[VY]*v.n[VY] + a.v[2].n[VZ]; return av; } vec2 operator*(const vec2 &v, const mat3 &a) { return a.transpose() * v; } vec3 operator*(const mat3 &a, const vec3 &v) { vec3 av; av.n[VX] = a.v[0].n[VX]*v.n[VX] + a.v[0].n[VY]*v.n[VY] + a.v[0].n[VZ]*v.n[VZ]; av.n[VY] = a.v[1].n[VX]*v.n[VX] + a.v[1].n[VY]*v.n[VY] + a.v[1].n[VZ]*v.n[VZ]; av.n[VZ] = a.v[2].n[VX]*v.n[VX] + a.v[2].n[VY]*v.n[VY] + a.v[2].n[VZ]*v.n[VZ]; return av; } vec3 operator*(const vec3 &v, const mat3 &a) { return a.transpose() * v; } float operator*(const vec2 &a, const vec2 &b) { return a.n[VX]*b.n[VX] + a.n[VY]*b.n[VY]; } vec2 operator/(const vec2 &a, float d) { float d_inv = 1.0f/d; return vec2(a.n[VX]*d_inv, a.n[VY]*d_inv); } vec3 operator^(const vec2 &a, const vec2 &b) { return vec3(0.0, 0.0, a.n[VX] * b.n[VY] - b.n[VX] * a.n[VY]); } int operator==(const vec2 &a, const vec2 &b) { return (a.n[VX] == b.n[VX]) && (a.n[VY] == b.n[VY]); } int operator!=(const vec2 &a, const vec2 &b) { return !(a == b); } /*ostream& operator << (ostream& s, vec2& v) { return s << "| " << v.n[VX] << ' ' << v.n[VY] << " |"; } */ /*istream& operator >> (istream& s, vec2& v) { vec2 v_tmp; char c = ' '; while (isspace(c)) s >> c; // The vectors can be formatted either as x y or | x y | if (c == '|') { s >> v_tmp[VX] >> v_tmp[VY]; while (s >> c && isspace(c)) ; if (c != '|') ;//s.set(_bad); } else { s.putback(c); s >> v_tmp[VX] >> v_tmp[VY]; } if (s) v = v_tmp; return s; } */ void swap(vec2 &a, vec2 &b) { vec2 tmp(a); a = b; b = tmp; } vec2 min_vec(const vec2 &a, const vec2 &b) { return vec2(MIN(a.n[VX], b.n[VX]), MIN(a.n[VY], b.n[VY])); } vec2 max_vec(const vec2 &a, const vec2 &b) { return vec2(MAX(a.n[VX], b.n[VX]), MAX(a.n[VY], b.n[VY])); } vec2 prod(const vec2 &a, const vec2 &b) { return vec2(a.n[VX] * b.n[VX], a.n[VY] * b.n[VY]); } /**************************************************************** * * * vec3 Member functions * * * ****************************************************************/ // CONSTRUCTORS vec3::vec3() { n[VX] = n[VY] = n[VZ] = 0.0; } vec3::vec3(float x, float y, float z) { n[VX] = x; n[VY] = y; n[VZ] = z; } vec3::vec3(const vec3 &v) { n[VX] = v.n[VX]; n[VY] = v.n[VY]; n[VZ] = v.n[VZ]; } vec3::vec3(const vec2 &v) { n[VX] = v.n[VX]; n[VY] = v.n[VY]; n[VZ] = 1.0; } vec3::vec3(const vec2 &v, float d) { n[VX] = v.n[VX]; n[VY] = v.n[VY]; n[VZ] = d; } vec3::vec3(const vec4 &v) // it is up to caller to avoid divide-by-zero { n[VX] = v.n[VX] / v.n[VW]; n[VY] = v.n[VY] / v.n[VW]; n[VZ] = v.n[VZ] / v.n[VW]; } vec3::vec3(const vec4 &v, int dropAxis) { switch (dropAxis) { case VX: n[VX] = v.n[VY]; n[VY] = v.n[VZ]; n[VZ] = v.n[VW]; break; case VY: n[VX] = v.n[VX]; n[VY] = v.n[VZ]; n[VZ] = v.n[VW]; break; case VZ: n[VX] = v.n[VX]; n[VY] = v.n[VY]; n[VZ] = v.n[VW]; break; default: n[VX] = v.n[VX]; n[VY] = v.n[VY]; n[VZ] = v.n[VZ]; break; } } // ASSIGNMENT OPERATORS vec3 &vec3::operator=(const vec3 &v) { n[VX] = v.n[VX]; n[VY] = v.n[VY]; n[VZ] = v.n[VZ]; return *this; } vec3 &vec3::operator+=(const vec3 &v) { n[VX] += v.n[VX]; n[VY] += v.n[VY]; n[VZ] += v.n[VZ]; return *this; } vec3 &vec3::operator-=(const vec3& v) { n[VX] -= v.n[VX]; n[VY] -= v.n[VY]; n[VZ] -= v.n[VZ]; return *this; } vec3 &vec3::operator*=(float d) { n[VX] *= d; n[VY] *= d; n[VZ] *= d; return *this; } vec3 &vec3::operator/=(float d) { float d_inv = 1.0f/d; n[VX] *= d_inv; n[VY] *= d_inv; n[VZ] *= d_inv; return *this; } float &vec3::operator[](int i) { if (i < VX || i > VZ) //VEC_ERROR("vec3 [] operator: illegal access; index = " << i << '\n') VEC_ERROR("vec3 [] operator: illegal access" ); return n[i]; } const float &vec3::operator[](int i) const { if (i < VX || i > VZ) //VEC_ERROR("vec3 [] operator: illegal access; index = " << i << '\n') VEC_ERROR("vec3 [] operator: illegal access" ); return n[i]; } // SPECIAL FUNCTIONS float vec3::length() const { return (float) sqrt(length2()); } float vec3::length2() const { return n[VX]*n[VX] + n[VY]*n[VY] + n[VZ]*n[VZ]; } vec3 &vec3::normalize() // it is up to caller to avoid divide-by-zero { *this /= length(); return *this; } vec3 &vec3::homogenize(void) // it is up to caller to avoid divide-by-zero { n[VX] /= n[VZ]; n[VY] /= n[VZ]; n[VZ] = 1.0; return *this; } vec3 &vec3::apply(V_FCT_PTR fct) { n[VX] = (*fct)(n[VX]); n[VY] = (*fct)(n[VY]); n[VZ] = (*fct)(n[VZ]); return *this; } void vec3::set(float x, float y, float z) // set vector { n[VX] = x; n[VY] = y; n[VZ] = z; } void vec3::print(FILE *file, const char *name) const // print vector to a file { fprintf( file, "%s: <%f, %f, %f>\n", name, n[VX], n[VY], n[VZ] ); } // FRIENDS vec3 operator-(const vec3 &a) { return vec3(-a.n[VX],-a.n[VY],-a.n[VZ]); } vec3 operator+(const vec3 &a, const vec3 &b) { return vec3(a.n[VX]+ b.n[VX], a.n[VY] + b.n[VY], a.n[VZ] + b.n[VZ]); } vec3 operator-(const vec3 &a, const vec3 &b) { return vec3(a.n[VX]-b.n[VX], a.n[VY]-b.n[VY], a.n[VZ]-b.n[VZ]); } vec3 operator*(const vec3 &a, float d) { return vec3(d*a.n[VX], d*a.n[VY], d*a.n[VZ]); } vec3 operator*(float d, const vec3 &a) { return a*d; } vec3 operator*(const mat4 &a, const vec3 &v) { return a*vec4(v); } vec3 operator*(const vec3 &v, mat4 &a) { return a.transpose()*v; } float operator*(const vec3 &a, const vec3 &b) { return a.n[VX]*b.n[VX] + a.n[VY]*b.n[VY] + a.n[VZ]*b.n[VZ]; } vec3 operator/(const vec3 &a, float d) { float d_inv = 1.0f/d; return vec3(a.n[VX]*d_inv, a.n[VY]*d_inv, a.n[VZ]*d_inv); } vec3 operator^(const vec3 &a, const vec3 &b) { return vec3(a.n[VY]*b.n[VZ] - a.n[VZ]*b.n[VY], a.n[VZ]*b.n[VX] - a.n[VX]*b.n[VZ], a.n[VX]*b.n[VY] - a.n[VY]*b.n[VX]); } int operator==(const vec3 &a, const vec3 &b) { return (a.n[VX] == b.n[VX]) && (a.n[VY] == b.n[VY]) && (a.n[VZ] == b.n[VZ]); } int operator!=(const vec3 &a, const vec3 &b) { return !(a == b); } /*ostream& operator << (ostream& s, vec3& v) { return s << "| " << v.n[VX] << ' ' << v.n[VY] << ' ' << v.n[VZ] << " |"; } istream& operator >> (istream& s, vec3& v) { vec3 v_tmp; char c = ' '; while (isspace(c)) s >> c; // The vectors can be formatted either as x y z or | x y z | if (c == '|') { s >> v_tmp[VX] >> v_tmp[VY] >> v_tmp[VZ]; while (s >> c && isspace(c)) ; if (c != '|') ;//s.set(_bad); } else { s.putback(c); s >> v_tmp[VX] >> v_tmp[VY] >> v_tmp[VZ]; } if (s) v = v_tmp; return s; } */ void swap(vec3 &a, vec3 &b) { vec3 tmp(a); a = b; b = tmp; } vec3 min_vec(const vec3 &a, const vec3 &b) { return vec3( MIN(a.n[VX], b.n[VX]), MIN(a.n[VY], b.n[VY]), MIN(a.n[VZ], b.n[VZ])); } vec3 max_vec(const vec3 &a, const vec3 &b) { return vec3( MAX(a.n[VX], b.n[VX]), MAX(a.n[VY], b.n[VY]), MAX(a.n[VZ], b.n[VZ])); } vec3 prod(const vec3 &a, const vec3 &b) { return vec3(a.n[VX]*b.n[VX], a.n[VY]*b.n[VY], a.n[VZ]*b.n[VZ]); } /**************************************************************** * * * vec4 Member functions * * * ****************************************************************/ // CONSTRUCTORS vec4::vec4() { n[VX] = n[VY] = n[VZ] = 0.0; n[VW] = 1.0; } vec4::vec4(float x, float y, float z, float w) { n[VX] = x; n[VY] = y; n[VZ] = z; n[VW] = w; } vec4::vec4(const vec4 &v) { n[VX] = v.n[VX]; n[VY] = v.n[VY]; n[VZ] = v.n[VZ]; n[VW] = v.n[VW]; } vec4::vec4(const vec3 &v) { n[VX] = v.n[VX]; n[VY] = v.n[VY]; n[VZ] = v.n[VZ]; n[VW] = 1.0; } vec4::vec4(const vec3 &v, float d) { n[VX] = v.n[VX]; n[VY] = v.n[VY]; n[VZ] = v.n[VZ]; n[VW] = d; } // ASSIGNMENT OPERATORS vec4 &vec4::operator=(const vec4 &v) { n[VX] = v.n[VX]; n[VY] = v.n[VY]; n[VZ] = v.n[VZ]; n[VW] = v.n[VW]; return *this; } vec4 &vec4::operator+=(const vec4 &v) { n[VX] += v.n[VX]; n[VY] += v.n[VY]; n[VZ] += v.n[VZ]; n[VW] += v.n[VW]; return *this; } vec4 &vec4::operator-=(const vec4 &v) { n[VX] -= v.n[VX]; n[VY] -= v.n[VY]; n[VZ] -= v.n[VZ]; n[VW] -= v.n[VW]; return *this; } vec4 &vec4::operator*=(float d) { n[VX] *= d; n[VY] *= d; n[VZ] *= d; n[VW] *= d; return *this; } vec4 &vec4::operator/=(float d) { float d_inv = 1.0f/d; n[VX] *= d_inv; n[VY] *= d_inv; n[VZ] *= d_inv; n[VW] *= d_inv; return *this; } float &vec4::operator[](int i) { if (i < VX || i > VW) //VEC_ERROR("vec4 [] operator: illegal access; index = " << i << '\n') VEC_ERROR("vec4 [] operator: illegal access" ); return n[i]; } const float &vec4::operator[](int i) const { if (i < VX || i > VW) //VEC_ERROR("vec4 [] operator: illegal access; index = " << i << '\n') VEC_ERROR("vec4 [] operator: illegal access" ); return n[i]; } // SPECIAL FUNCTIONS float vec4::length() const { return (float) sqrt(length2()); } float vec4::length2() const { return n[VX]*n[VX] + n[VY]*n[VY] + n[VZ]*n[VZ] + n[VW]*n[VW]; } vec4 &vec4::normalize() // it is up to caller to avoid divide-by-zero { *this /= length(); return *this; } vec4 &vec4::homogenize() // it is up to caller to avoid divide-by-zero { n[VX] /= n[VW]; n[VY] /= n[VW]; n[VZ] /= n[VW]; n[VW] = 1.0; return *this; } vec4 &vec4::apply(V_FCT_PTR fct) { n[VX] = (*fct)(n[VX]); n[VY] = (*fct)(n[VY]); n[VZ] = (*fct)(n[VZ]); n[VW] = (*fct)(n[VW]); return *this; } void vec4::print(FILE *file, const char *name) const // print vector to a file { fprintf( file, "%s: <%f, %f, %f, %f>\n", name, n[VX], n[VY], n[VZ], n[VW]); } void vec4::set(float x, float y, float z, float a) { n[0] = x; n[1] = y; n[2] = z; n[3] = a; } // FRIENDS vec4 operator-(const vec4 &a) { return vec4(-a.n[VX],-a.n[VY],-a.n[VZ],-a.n[VW]); } vec4 operator+(const vec4 &a, const vec4 &b) { return vec4( a.n[VX] + b.n[VX], a.n[VY] + b.n[VY], a.n[VZ] + b.n[VZ], a.n[VW] + b.n[VW]); } vec4 operator-(const vec4 &a, const vec4 &b) { return vec4( a.n[VX] - b.n[VX], a.n[VY] - b.n[VY], a.n[VZ] - b.n[VZ], a.n[VW] - b.n[VW]); } vec4 operator*(const vec4 &a, float d) { return vec4(d*a.n[VX], d*a.n[VY], d*a.n[VZ], d*a.n[VW]); } vec4 operator*(float d, const vec4 &a) { return a*d; } vec4 operator*(const mat4 &a, const vec4 &v) { #define ROWCOL(i) \ a.v[i].n[0]*v.n[VX] + \ a.v[i].n[1]*v.n[VY] + \ a.v[i].n[2]*v.n[VZ] + \ a.v[i].n[3]*v.n[VW] return vec4(ROWCOL(0), ROWCOL(1), ROWCOL(2), ROWCOL(3)); #undef ROWCOL } vec4 operator*(const vec4 &v, const mat4 &a) { return a.transpose()*v; } float operator*(const vec4 &a, const vec4 &b) { return a.n[VX]*b.n[VX] + a.n[VY]*b.n[VY] + a.n[VZ]*b.n[VZ] + a.n[VW]*b.n[VW]; } vec4 operator/(const vec4 &a, float d) { float d_inv = 1.0f/d; return vec4( a.n[VX]*d_inv, a.n[VY]*d_inv, a.n[VZ]*d_inv, a.n[VW]*d_inv); } int operator==(const vec4 &a, const vec4 &b) { return (a.n[VX] == b.n[VX]) && (a.n[VY] == b.n[VY]) && (a.n[VZ] == b.n[VZ]) && (a.n[VW] == b.n[VW]); } int operator!=(const vec4 &a, const vec4 &b) { return !(a == b); } /*ostream& operator << (ostream& s, vec4& v) { return s << "| " << v.n[VX] << ' ' << v.n[VY] << ' ' << v.n[VZ] << ' ' << v.n[VW] << " |"; } istream& operator >> (istream& s, vec4& v) { vec4 v_tmp; char c = ' '; while (isspace(c)) s >> c; // The vectors can be formatted either as x y z w or | x y z w | if (c == '|') { s >> v_tmp[VX] >> v_tmp[VY] >> v_tmp[VZ] >> v_tmp[VW]; while (s >> c && isspace(c)) ; if (c != '|') ;//s.set(_bad); } else { s.putback(c); s >> v_tmp[VX] >> v_tmp[VY] >> v_tmp[VZ] >> v_tmp[VW]; } if (s) v = v_tmp; return s; } */ void swap(vec4 &a, vec4 &b) { vec4 tmp(a); a = b; b = tmp; } vec4 min_vec(const vec4 &a, const vec4 &b) { return vec4( MIN(a.n[VX], b.n[VX]), MIN(a.n[VY], b.n[VY]), MIN(a.n[VZ], b.n[VZ]), MIN(a.n[VW], b.n[VW])); } vec4 max_vec(const vec4 &a, const vec4 &b) { return vec4( MAX(a.n[VX], b.n[VX]), MAX(a.n[VY], b.n[VY]), MAX(a.n[VZ], b.n[VZ]), MAX(a.n[VW], b.n[VW])); } vec4 prod(const vec4 &a, const vec4 &b) { return vec4( a.n[VX] * b.n[VX], a.n[VY] * b.n[VY], a.n[VZ] * b.n[VZ], a.n[VW] * b.n[VW]); } /**************************************************************** * * * mat3 member functions * * * ****************************************************************/ // CONSTRUCTORS mat3::mat3() { *this = identity2D(); } mat3::mat3(const vec3 &v0, const vec3 &v1, const vec3 &v2) { set(v0, v1, v2); } mat3::mat3(const mat3 &m) { v[0] = m.v[0]; v[1] = m.v[1]; v[2] = m.v[2]; } // ASSIGNMENT OPERATORS mat3 &mat3::operator=(const mat3 &m) { v[0] = m.v[0]; v[1] = m.v[1]; v[2] = m.v[2]; return *this; } mat3 &mat3::operator+=(const mat3& m) { v[0] += m.v[0]; v[1] += m.v[1]; v[2] += m.v[2]; return *this; } mat3 &mat3::operator-=(const mat3& m) { v[0] -= m.v[0]; v[1] -= m.v[1]; v[2] -= m.v[2]; return *this; } mat3 &mat3::operator*=(float d) { v[0] *= d; v[1] *= d; v[2] *= d; return *this; } mat3 &mat3::operator/=(float d) { v[0] /= d; v[1] /= d; v[2] /= d; return *this; } vec3 &mat3::operator[](int i) { if (i < VX || i > VZ) //VEC_ERROR("mat3 [] operator: illegal access; index = " << i << '\n') VEC_ERROR("mat3 [] operator: illegal access" ); return v[i]; } const vec3 &mat3::operator[](int i) const { if (i < VX || i > VZ) //VEC_ERROR("mat3 [] operator: illegal access; index = " << i << '\n') VEC_ERROR("mat3 [] operator: illegal access" ); return v[i]; } void mat3::set(const vec3 &v0, const vec3 &v1, const vec3 &v2) { v[0] = v0; v[1] = v1; v[2] = v2; } // SPECIAL FUNCTIONS mat3 mat3::transpose() const { return mat3( vec3(v[0][0], v[1][0], v[2][0]), vec3(v[0][1], v[1][1], v[2][1]), vec3(v[0][2], v[1][2], v[2][2])); } mat3 mat3::inverse() const // Gauss-Jordan elimination with partial pivoting { mat3 a(*this); // As a evolves from original mat into identity mat3 b(identity2D()); // b evolves from identity into inverse(a) int i, j, i1; // Loop over cols of a from left to right, eliminating above and below diag for (j=0; j<3; j++) // Find largest pivot in column j among rows j..2 { i1 = j; // Row with largest pivot candidate for (i=j+1; i<3; i++) if (fabs(a.v[i].n[j]) > fabs(a.v[i1].n[j])) i1 = i; // Swap rows i1 and j in a and b to put pivot on diagonal swap(a.v[i1], a.v[j]); swap(b.v[i1], b.v[j]); // Scale row j to have a unit diagonal if (a.v[j].n[j]==0.) VEC_ERROR("mat3::inverse: singular matrix; can't invert\n"); b.v[j] /= a.v[j].n[j]; a.v[j] /= a.v[j].n[j]; // Eliminate off-diagonal elems in col j of a, doing identical ops to b for (i=0; i<3; i++) if (i!=j) { b.v[i] -= a.v[i].n[j]*b.v[j]; a.v[i] -= a.v[i].n[j]*a.v[j]; } } return b; } mat3 &mat3::apply(V_FCT_PTR fct) { v[VX].apply(fct); v[VY].apply(fct); v[VZ].apply(fct); return *this; } // FRIENDS mat3 operator-(const mat3 &a) { return mat3(-a.v[0], -a.v[1], -a.v[2]); } mat3 operator+(const mat3 &a, const mat3 &b) { return mat3(a.v[0]+b.v[0], a.v[1]+b.v[1], a.v[2]+b.v[2]); } mat3 operator-(const mat3 &a, const mat3 &b) { return mat3(a.v[0]-b.v[0], a.v[1]-b.v[1], a.v[2]-b.v[2]); } mat3 operator*(const mat3 &a, const mat3 &b) { #define ROWCOL(i, j) \ a.v[i].n[0]*b.v[0][j] + a.v[i].n[1]*b.v[1][j] + a.v[i].n[2]*b.v[2][j] return mat3( vec3(ROWCOL(0,0), ROWCOL(0,1), ROWCOL(0,2)), vec3(ROWCOL(1,0), ROWCOL(1,1), ROWCOL(1,2)), vec3(ROWCOL(2,0), ROWCOL(2,1), ROWCOL(2,2))); #undef ROWCOL } mat3 operator*(const mat3 &a, float d) { return mat3(a.v[0]*d, a.v[1]*d, a.v[2]*d); } mat3 operator*(float d, const mat3 &a) { return a*d; } mat3 operator/(const mat3 &a, float d) { return mat3(a.v[0]/d, a.v[1]/d, a.v[2]/d); } int operator==(const mat3 &a, const mat3 &b) { return (a.v[0] == b.v[0]) && (a.v[1] == b.v[1]) && (a.v[2] == b.v[2]); } int operator!=(const mat3 &a, const mat3 &b) { return !(a == b); } /*ostream& operator << (ostream& s, mat3& m) { return s << m.v[VX] << '\n' << m.v[VY] << '\n' << m.v[VZ]; } istream& operator >> (istream& s, mat3& m) { mat3 m_tmp; s >> m_tmp[VX] >> m_tmp[VY] >> m_tmp[VZ]; if (s) m = m_tmp; return s; } */ void swap(mat3 &a, mat3 &b) { mat3 tmp(a); a = b; b = tmp; } void mat3::print(FILE *file, const char *name) const { int i, j; fprintf( stderr, "%s:\n", name ); for( i = 0; i < 3; i++ ) { fprintf( stderr, " " ); for( j = 0; j < 3; j++ ) { fprintf( stderr, "%f ", v[i][j] ); } fprintf( stderr, "\n" ); } } /**************************************************************** * * * mat4 member functions * * * ****************************************************************/ // CONSTRUCTORS mat4::mat4() { *this = identity3D(); } mat4::mat4(const vec4& v0, const vec4& v1, const vec4& v2, const vec4& v3) { v[0] = v0; v[1] = v1; v[2] = v2; v[3] = v3; } mat4::mat4(const mat4 &m) { v[0] = m.v[0]; v[1] = m.v[1]; v[2] = m.v[2]; v[3] = m.v[3]; } mat4::mat4( float a00, float a01, float a02, float a03, float a10, float a11, float a12, float a13, float a20, float a21, float a22, float a23, float a30, float a31, float a32, float a33 ) { v[0][0] = a00; v[0][1] = a01; v[0][2] = a02; v[0][3] = a03; v[1][0] = a10; v[1][1] = a11; v[1][2] = a12; v[1][3] = a13; v[2][0] = a20; v[2][1] = a21; v[2][2] = a22; v[2][3] = a23; v[3][0] = a30; v[3][1] = a31; v[3][2] = a32; v[3][3] = a33; } // ASSIGNMENT OPERATORS mat4 &mat4::operator=(const mat4 &m) { v[0] = m.v[0]; v[1] = m.v[1]; v[2] = m.v[2]; v[3] = m.v[3]; return *this; } mat4 &mat4::operator+=(const mat4 &m) { v[0] += m.v[0]; v[1] += m.v[1]; v[2] += m.v[2]; v[3] += m.v[3]; return *this; } mat4 &mat4::operator-=(const mat4 &m) { v[0] -= m.v[0]; v[1] -= m.v[1]; v[2] -= m.v[2]; v[3] -= m.v[3]; return *this; } mat4 &mat4::operator*=(float d) { v[0] *= d; v[1] *= d; v[2] *= d; v[3] *= d; return *this; } mat4 &mat4::operator/=(float d) { v[0] /= d; v[1] /= d; v[2] /= d; v[3] /= d; return *this; } vec4 &mat4::operator[](int i) { if (i < VX || i > VW) //VEC_ERROR("mat4 [] operator: illegal access; index = " << i << '\n') VEC_ERROR("mat4 [] operator: illegal access" ); return v[i]; } const vec4 &mat4::operator[](int i) const { if (i < VX || i > VW) //VEC_ERROR("mat4 [] operator: illegal access; index = " << i << '\n') VEC_ERROR("mat4 [] operator: illegal access" ); return v[i]; } // SPECIAL FUNCTIONS; mat4 mat4::transpose() const { return mat4( vec4(v[0][0], v[1][0], v[2][0], v[3][0]), vec4(v[0][1], v[1][1], v[2][1], v[3][1]), vec4(v[0][2], v[1][2], v[2][2], v[3][2]), vec4(v[0][3], v[1][3], v[2][3], v[3][3])); } mat4 mat4::inverse() const // Gauss-Jordan elimination with partial pivoting { mat4 a(*this); // As a evolves from original mat into identity mat4 b(identity3D()); // b evolves from identity into inverse(a) int i, j, i1; // Loop over cols of a from left to right, eliminating above and below diag for (j=0; j<4; j++) // Find largest pivot in column j among rows j..3 { i1 = j; // Row with largest pivot candidate for (i=j+1; i<4; i++) if (fabs(a.v[i].n[j]) > fabs(a.v[i1].n[j])) i1 = i; // Swap rows i1 and j in a and b to put pivot on diagonal swap(a.v[i1], a.v[j]); swap(b.v[i1], b.v[j]); // Scale row j to have a unit diagonal if (a.v[j].n[j]==0.) VEC_ERROR("mat4::inverse: singular matrix; can't invert\n"); b.v[j] /= a.v[j].n[j]; a.v[j] /= a.v[j].n[j]; // Eliminate off-diagonal elems in col j of a, doing identical ops to b for (i=0; i<4; i++) if (i!=j) { b.v[i] -= a.v[i].n[j]*b.v[j]; a.v[i] -= a.v[i].n[j]*a.v[j]; } } return b; } mat4 &mat4::apply(V_FCT_PTR fct) { v[VX].apply(fct); v[VY].apply(fct); v[VZ].apply(fct); v[VW].apply(fct); return *this; } void mat4::print(FILE *file, const char *name) const { int i, j; fprintf( stderr, "%s:\n", name ); for( i = 0; i < 4; i++ ) { fprintf( stderr, " " ); for( j = 0; j < 4; j++ ) { fprintf( stderr, "%f ", v[i][j] ); } fprintf( stderr, "\n" ); } } void mat4::swap_rows(int i, int j) { vec4 t; t = v[i]; v[i] = v[j]; v[j] = t; } void mat4::swap_cols(int i, int j) { float t; int k; for (k=0; k<4; k++) { t = v[k][i]; v[k][i] = v[k][j]; v[k][j] = t; } } // FRIENDS mat4 operator-(const mat4 &a) { return mat4(-a.v[0],-a.v[1],-a.v[2],-a.v[3]); } mat4 operator+(const mat4 &a, const mat4 &b) { return mat4( a.v[0] + b.v[0], a.v[1] + b.v[1], a.v[2] + b.v[2], a.v[3] + b.v[3]); } mat4 operator-(const mat4 &a, const mat4 &b) { return mat4( a.v[0] - b.v[0], a.v[1] - b.v[1], a.v[2] - b.v[2], a.v[3] - b.v[3]); } mat4 operator*(const mat4 &a, const mat4 &b) { #define ROWCOL(i, j) \ a.v[i].n[0]*b.v[0][j] + \ a.v[i].n[1]*b.v[1][j] + \ a.v[i].n[2]*b.v[2][j] + \ a.v[i].n[3]*b.v[3][j] return mat4( vec4(ROWCOL(0,0), ROWCOL(0,1), ROWCOL(0,2), ROWCOL(0,3)), vec4(ROWCOL(1,0), ROWCOL(1,1), ROWCOL(1,2), ROWCOL(1,3)), vec4(ROWCOL(2,0), ROWCOL(2,1), ROWCOL(2,2), ROWCOL(2,3)), vec4(ROWCOL(3,0), ROWCOL(3,1), ROWCOL(3,2), ROWCOL(3,3)) ); #undef ROWCOL } mat4 operator*(const mat4 &a, float d) { return mat4(a.v[0]*d, a.v[1]*d, a.v[2]*d, a.v[3]*d); } mat4 operator*(float d, const mat4 &a) { return a*d; } mat4 operator/(const mat4 &a, float d) { return mat4(a.v[0]/d, a.v[1]/d, a.v[2]/d, a.v[3]/d); } int operator==(const mat4 &a, const mat4 &b) { return (a.v[0] == b.v[0]) && (a.v[1] == b.v[1]) && (a.v[2] == b.v[2]) && (a.v[3] == b.v[3]); } int operator!=(const mat4 &a, const mat4 &b) { return !(a == b); } /*ostream& operator << (ostream& s, mat4& m) { return s << m.v[VX] << '\n' << m.v[VY] << '\n' << m.v[VZ] << '\n' << m.v[VW]; } istream& operator >> (istream& s, mat4& m) { mat4 m_tmp; s >> m_tmp[VX] >> m_tmp[VY] >> m_tmp[VZ] >> m_tmp[VW]; if (s) m = m_tmp; return s; } */ void swap(mat4 &a, mat4 &b) { mat4 tmp(a); a = b; b = tmp; } /**************************************************************** * * * 2D functions and 3D functions * * * ****************************************************************/ mat3 identity2D() { return mat3( vec3(1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, 0.0, 1.0)); } mat3 translation2D(const vec2 &v) { return mat3( vec3(1.0, 0.0, v[VX]), vec3(0.0, 1.0, v[VY]), vec3(0.0, 0.0, 1.0)); } mat3 rotation2D(const vec2 &Center, float angleDeg) { float angleRad = (float) (angleDeg * radians); float c = (float) cos(angleRad); float s = (float) sin(angleRad); return mat3( vec3(c, -s, Center[VX] * (1.0f-c) + Center[VY] * s), vec3(s, c, Center[VY] * (1.0f-c) - Center[VX] * s), vec3(0.0, 0.0, 1.0)); } mat3 scaling2D(const vec2 &scaleVector) { return mat3( vec3(scaleVector[VX], 0.0, 0.0), vec3(0.0, scaleVector[VY], 0.0), vec3(0.0, 0.0, 1.0)); } mat4 identity3D() { return mat4( vec4(1.0, 0.0, 0.0, 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); } mat4 translation3D(const vec3 &v) { return mat4( vec4(1.0, 0.0, 0.0, v[VX]), vec4(0.0, 1.0, 0.0, v[VY]), vec4(0.0, 0.0, 1.0, v[VZ]), vec4(0.0, 0.0, 0.0, 1.0)); } mat4 rotation3D(const vec3 &Axis, float angleDeg) { float angleRad = (float) (angleDeg * radians); float c = (float) cos(angleRad); float s = (float) sin(angleRad); float t = 1.0f - c; vec3 axis(Axis); axis.normalize(); return mat4( vec4(t * axis[VX] * axis[VX] + c, t * axis[VX] * axis[VY] - s * axis[VZ], t * axis[VX] * axis[VZ] + s * axis[VY], 0.0), vec4(t * axis[VX] * axis[VY] + s * axis[VZ], t * axis[VY] * axis[VY] + c, t * axis[VY] * axis[VZ] - s * axis[VX], 0.0), vec4(t * axis[VX] * axis[VZ] - s * axis[VY], t * axis[VY] * axis[VZ] + s * axis[VX], t * axis[VZ] * axis[VZ] + c, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); } mat4 rotation3Drad(const vec3 &Axis, float angleRad) { float c = (float) cos(angleRad); float s = (float) sin(angleRad); float t = 1.0f - c; vec3 axis(Axis); axis.normalize(); return mat4( vec4(t * axis[VX] * axis[VX] + c, t * axis[VX] * axis[VY] - s * axis[VZ], t * axis[VX] * axis[VZ] + s * axis[VY], 0.0), vec4(t * axis[VX] * axis[VY] + s * axis[VZ], t * axis[VY] * axis[VY] + c, t * axis[VY] * axis[VZ] - s * axis[VX], 0.0), vec4(t * axis[VX] * axis[VZ] - s * axis[VY], t * axis[VY] * axis[VZ] + s * axis[VX], t * axis[VZ] * axis[VZ] + c, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); } mat4 scaling3D(const vec3 &scaleVector) { return mat4( vec4(scaleVector[VX], 0.0, 0.0, 0.0), vec4(0.0, scaleVector[VY], 0.0, 0.0), vec4(0.0, 0.0, scaleVector[VZ], 0.0), vec4(0.0, 0.0, 0.0, 1.0)); } mat4 perspective3D(float d) { return mat4( vec4(1.0f, 0.0f, 0.0f, 0.0f), vec4(0.0f, 1.0f, 0.0f, 0.0f), vec4(0.0f, 0.0f, 1.0f, 0.0f), vec4(0.0f, 0.0f, 1.0f/d, 0.0f)); } asymptote-2.37/algebra3.h000066400000000000000000000461031265434602500153360ustar00rootroot00000000000000/* algebra3.cc, algebra3.h - C++ Vector and Matrix Algebra routines GLUI User Interface Toolkit (LGPL) Copyright (c) 1998 Paul Rademacher WWW: http://sourceforge.net/projects/glui/ Forums: http://sourceforge.net/forum/?group_id=92496 This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /************************************************************************** There are three vector classes and two matrix classes: vec2, vec3, vec4, mat3, and mat4. All the standard arithmetic operations are defined, with '*' for dot product of two vectors and multiplication of two matrices, and '^' for cross product of two vectors. Additional functions include length(), normalize(), homogenize for vectors, and print(), set(), apply() for all classes. There is a function transpose() for matrices, but note that it does not actually change the matrix, When multiplied with a matrix, a vector is treated as a row vector if it precedes the matrix (v*M), and as a column vector if it follows the matrix (M*v). Matrices are stored in row-major form. A vector of one dimension (2d, 3d, or 4d) can be cast to a vector of a higher or lower dimension. If casting to a higher dimension, the new component is set by default to 1.0, unless a value is specified: vec3 a(1.0, 2.0, 3.0 ); vec4 b( a, 4.0 ); // now b == {1.0, 2.0, 3.0, 4.0}; When casting to a lower dimension, the vector is homogenized in the lower dimension. E.g., if a 4d {X,Y,Z,W} is cast to 3d, the resulting vector is {X/W, Y/W, Z/W}. It is up to the user to insure the fourth component is not zero before casting. There are also the following function for building matrices: identity2D(), translation2D(), rotation2D(), scaling2D(), identity3D(), translation3D(), rotation3D(), rotation3Drad(), scaling3D(), perspective3D() NOTE: When compiling for Windows, include this file first, to avoid certain name conflicts --------------------------------------------------------------------- Author: Jean-Francois DOUEg Revised: Paul Rademacher Version 3.2 - Feb 1998 Revised: Nigel Stewart (GLUI Code Cleaning) **************************************************************************/ #ifndef GLUI_ALGEBRA3_H #define GLUI_ALGEBRA3_H #include #include #include #ifndef MAX #define MAX(a,b) ((a)>(b) ? (a) : (b)) #define MIN(a,b) ((a)<(b) ? (a) : (b)) #endif #define FUDGE .00001 // this line defines a new type: pointer to a function which returns a // float and takes as argument a float typedef float (*V_FCT_PTR)(float); class vec2; class vec3; class vec4; class mat3; class mat4; enum axes {VX, VY, VZ, VW}; /* enum planes {PA, PB, PC, PD}; enum colors {RED, GREEN, BLUE, ALPHA}; enum phong {KA, KD, KS, ES}; */ /**************************************************************** * * * 2D Vector * * * ****************************************************************/ class vec2 { friend class vec3; protected: float n[2]; public: // Constructors vec2(); vec2(float x, float y); vec2(const vec2 &v); // copy constructor vec2(const vec3 &v); // cast v3 to v2 vec2(const vec3 &v, int dropAxis); // cast v3 to v2 // Assignment operators vec2 &operator = (const vec2 &v); // assignment of a vec2 vec2 &operator += (const vec2 &v); // incrementation by a vec2 vec2 &operator -= (const vec2 &v); // decrementation by a vec2 vec2 &operator *= (float d); // multiplication by a constant vec2 &operator /= (float d); // division by a constant // special functions float length() const; // length of a vec2 float length2() const; // squared length of a vec2 vec2 &normalize(); // normalize a vec2 vec2 &apply(V_FCT_PTR fct); // apply a func. to each component void set(float x, float y); // set vector float &operator [] (int i); // indexing const float &operator [] (int i) const; // indexing // friends friend vec2 operator - (const vec2 &v); // -v1 friend vec2 operator + (const vec2 &a, const vec2 &b); // v1 + v2 friend vec2 operator - (const vec2 &a, const vec2 &b); // v1 - v2 friend vec2 operator * (const vec2 &a, float d); // v1 * 3.0 friend vec2 operator * (float d, const vec2 &a); // 3.0 * v1 friend vec2 operator * (const mat3 &a, const vec2 &v); // M . v friend vec2 operator * (const vec2 &v, const mat3 &a); // v . M friend float operator * (const vec2 &a, const vec2 &b); // dot product friend vec2 operator / (const vec2 &a, float d); // v1 / 3.0 friend vec3 operator ^ (const vec2 &a, const vec2 &b); // cross product friend int operator == (const vec2 &a, const vec2 &b); // v1 == v2 ? friend int operator != (const vec2 &a, const vec2 &b); // v1 != v2 ? //friend ostream& operator << (ostream& s, vec2& v); // output to stream //friend istream& operator >> (istream& s, vec2& v); // input from strm. friend void swap(vec2 &a, vec2 &b); // swap v1 & v2 friend vec2 min_vec(const vec2 &a, const vec2 &b); // min(v1, v2) friend vec2 max_vec(const vec2 &a, const vec2 &b); // max(v1, v2) friend vec2 prod (const vec2 &a, const vec2 &b); // term by term * }; /**************************************************************** * * * 3D Vector * * * ****************************************************************/ class vec3 { friend class vec2; friend class vec4; friend class mat3; protected: float n[3]; public: // Constructors vec3(); vec3(float x, float y, float z); vec3(const vec3 &v); // copy constructor vec3(const vec2 &v); // cast v2 to v3 vec3(const vec2 &v, float d); // cast v2 to v3 vec3(const vec4 &v); // cast v4 to v3 vec3(const vec4 &v, int dropAxis); // cast v4 to v3 // Assignment operators vec3 &operator = (const vec3 &v); // assignment of a vec3 vec3 &operator += (const vec3 &v); // incrementation by a vec3 vec3 &operator -= (const vec3 &v); // decrementation by a vec3 vec3 &operator *= (float d); // multiplication by a constant vec3 &operator /= (float d); // division by a constant // special functions float length() const; // length of a vec3 float length2() const; // squared length of a vec3 vec3& normalize(); // normalize a vec3 vec3& homogenize(); // homogenize (div by Z) vec3& apply(V_FCT_PTR fct); // apply a func. to each component void set(float x, float y, float z); // set vector void print(FILE *file, const char *name) const; // print vector to a file float &operator [] (int i); // indexing const float &operator [] (int i) const; // indexing // friends friend vec3 operator - (const vec3 &v); // -v1 friend vec3 operator + (const vec3 &a, const vec3 &b); // v1 + v2 friend vec3 operator - (const vec3 &a, const vec3 &b); // v1 - v2 friend vec3 operator * (const vec3 &a, float d); // v1 * 3.0 friend vec3 operator * (float d, const vec3 &a); // 3.0 * v1 friend vec3 operator * (const mat4 &a, const vec3 &v); // M . v friend vec3 operator * (const vec3 &v, const mat4 &a); // v . M friend float operator * (const vec3 &a, const vec3 &b); // dot product friend vec3 operator / (const vec3 &a, float d); // v1 / 3.0 friend vec3 operator ^ (const vec3 &a, const vec3 &b); // cross product friend int operator == (const vec3 &a, const vec3 &b); // v1 == v2 ? friend int operator != (const vec3 &a, const vec3 &b); // v1 != v2 ? //friend ostream& operator << (ostream& s, vec3& v); // output to stream //friend istream& operator >> (istream& s, vec3& v); // input from strm. friend void swap(vec3 &a, vec3 &b); // swap v1 & v2 friend vec3 min_vec(const vec3 &a, const vec3 &b); // min(v1, v2) friend vec3 max_vec(const vec3 &a, const vec3 &b); // max(v1, v2) friend vec3 prod(const vec3 &a, const vec3 &b); // term by term * // necessary friend declarations friend vec2 operator * (const mat3 &a, const vec2 &v); // linear transform friend vec3 operator * (const mat3 &a, const vec3 &v); // linear transform friend mat3 operator * (const mat3 &a, const mat3 &b); // matrix 3 product }; /**************************************************************** * * * 4D Vector * * * ****************************************************************/ class vec4 { friend class vec3; friend class mat4; protected: float n[4]; public: // Constructors vec4(); vec4(float x, float y, float z, float w); vec4(const vec4 &v); // copy constructor vec4(const vec3 &v); // cast vec3 to vec4 vec4(const vec3 &v, float d); // cast vec3 to vec4 // Assignment operators vec4 &operator = (const vec4 &v); // assignment of a vec4 vec4 &operator += (const vec4 &v); // incrementation by a vec4 vec4 &operator -= (const vec4 &v); // decrementation by a vec4 vec4 &operator *= (float d); // multiplication by a constant vec4 &operator /= (float d); // division by a constant // special functions float length() const; // length of a vec4 float length2() const; // squared length of a vec4 vec4 &normalize(); // normalize a vec4 vec4 &apply(V_FCT_PTR fct); // apply a func. to each component vec4 &homogenize(); void print(FILE *file, const char *name) const; // print vector to a file void set(float x, float y, float z, float a); float &operator [] (int i); // indexing const float &operator [] (int i) const; // indexing // friends friend vec4 operator - (const vec4 &v); // -v1 friend vec4 operator + (const vec4 &a, const vec4 &b); // v1 + v2 friend vec4 operator - (const vec4 &a, const vec4 &b); // v1 - v2 friend vec4 operator * (const vec4 &a, float d); // v1 * 3.0 friend vec4 operator * (float d, const vec4 &a); // 3.0 * v1 friend vec4 operator * (const mat4 &a, const vec4 &v); // M . v friend vec4 operator * (const vec4 &v, const mat4 &a); // v . M friend float operator * (const vec4 &a, const vec4 &b); // dot product friend vec4 operator / (const vec4 &a, float d); // v1 / 3.0 friend int operator == (const vec4 &a, const vec4 &b); // v1 == v2 ? friend int operator != (const vec4 &a, const vec4 &b); // v1 != v2 ? //friend ostream& operator << (ostream& s, vec4& v); // output to stream //friend istream& operator >> (istream& s, vec4& v); // input from strm. friend void swap(vec4 &a, vec4 &b); // swap v1 & v2 friend vec4 min_vec(const vec4 &a, const vec4 &b); // min(v1, v2) friend vec4 max_vec(const vec4 &a, const vec4 &b); // max(v1, v2) friend vec4 prod (const vec4 &a, const vec4 &b); // term by term * // necessary friend declarations friend vec3 operator * (const mat4 &a, const vec3 &v); // linear transform friend mat4 operator * (const mat4 &a, const mat4 &b); // matrix 4 product }; /**************************************************************** * * * 3x3 Matrix * * * ****************************************************************/ class mat3 { protected: vec3 v[3]; public: // Constructors mat3(); mat3(const vec3 &v0, const vec3 &v1, const vec3 &v2); mat3(const mat3 &m); // Assignment operators mat3 &operator = (const mat3 &m); // assignment of a mat3 mat3 &operator += (const mat3 &m); // incrementation by a mat3 mat3 &operator -= (const mat3 &m); // decrementation by a mat3 mat3 &operator *= (float d); // multiplication by a constant mat3 &operator /= (float d); // division by a constant // special functions mat3 transpose() const; // transpose mat3 inverse() const; // inverse mat3 &apply(V_FCT_PTR fct); // apply a func. to each element void print(FILE *file, const char *name ) const; // print matrix to a file void set(const vec3 &v0, const vec3 &v1, const vec3 &v2); vec3 &operator [] (int i); // indexing const vec3 &operator [] (int i) const; // indexing // friends friend mat3 operator - (const mat3 &a); // -m1 friend mat3 operator + (const mat3 &a, const mat3 &b); // m1 + m2 friend mat3 operator - (const mat3 &a, const mat3 &b); // m1 - m2 friend mat3 operator * (const mat3 &a, const mat3 &b); // m1 * m2 friend mat3 operator * (const mat3 &a, float d); // m1 * 3.0 friend mat3 operator * (float d, const mat3 &a); // 3.0 * m1 friend mat3 operator / (const mat3 &a, float d); // m1 / 3.0 friend int operator == (const mat3 &a, const mat3 &b); // m1 == m2 ? friend int operator != (const mat3 &a, const mat3 &b); // m1 != m2 ? //friend ostream& operator << (ostream& s, mat3& m); // output to stream //friend istream& operator >> (istream& s, mat3& m); // input from strm. friend void swap(mat3 &a, mat3 &b); // swap m1 & m2 // necessary friend declarations friend vec3 operator * (const mat3 &a, const vec3 &v); // linear transform friend vec2 operator * (const mat3 &a, const vec2 &v); // linear transform }; /**************************************************************** * * * 4x4 Matrix * * * ****************************************************************/ class mat4 { protected: vec4 v[4]; public: // Constructors mat4(); mat4(const vec4 &v0, const vec4 &v1, const vec4 &v2, const vec4 &v3); mat4(const mat4 &m); mat4(float a00, float a01, float a02, float a03, float a10, float a11, float a12, float a13, float a20, float a21, float a22, float a23, float a30, float a31, float a32, float a33 ); // Assignment operators mat4 &operator = (const mat4 &m); // assignment of a mat4 mat4 &operator += (const mat4 &m); // incrementation by a mat4 mat4 &operator -= (const mat4 &m); // decrementation by a mat4 mat4 &operator *= (float d); // multiplication by a constant mat4 &operator /= (float d); // division by a constant // special functions mat4 transpose() const; // transpose mat4 inverse() const; // inverse mat4 &apply(V_FCT_PTR fct); // apply a func. to each element void print(FILE *file, const char *name) const; // print matrix to a file vec4 &operator [] (int i); // indexing const vec4 &operator [] (int i) const; // indexing void swap_rows(int i, int j); // swap rows i and j void swap_cols(int i, int j); // swap cols i and j // friends friend mat4 operator - (const mat4 &a); // -m1 friend mat4 operator + (const mat4 &a, const mat4 &b); // m1 + m2 friend mat4 operator - (const mat4 &a, const mat4 &b); // m1 - m2 friend mat4 operator * (const mat4 &a, const mat4 &b); // m1 * m2 friend mat4 operator * (const mat4 &a, float d); // m1 * 4.0 friend mat4 operator * (float d, const mat4 &a); // 4.0 * m1 friend mat4 operator / (const mat4 &a, float d); // m1 / 3.0 friend int operator == (const mat4 &a, const mat4 &b); // m1 == m2 ? friend int operator != (const mat4 &a, const mat4 &b); // m1 != m2 ? //friend ostream& operator << (ostream& s, mat4& m); // output to stream //friend istream& operator >> (istream& s, mat4& m); // input from strm. friend void swap(mat4 &a, mat4 &b); // swap m1 & m2 // necessary friend declarations friend vec4 operator * (const mat4 &a, const vec4 &v); // linear transform //friend vec4 operator * (const vec4& v, const mat4& a); // linear transform friend vec3 operator * (const mat4 &a, const vec3 &v); // linear transform friend vec3 operator * (const vec3 &v, const mat4 &a); // linear transform }; /**************************************************************** * * * 2D functions and 3D functions * * * ****************************************************************/ mat3 identity2D (); // identity 2D mat3 translation2D(const vec2 &v); // translation 2D mat3 rotation2D (const vec2 &Center, float angleDeg); // rotation 2D mat3 scaling2D (const vec2 &scaleVector); // scaling 2D mat4 identity3D (); // identity 3D mat4 translation3D(const vec3 &v); // translation 3D mat4 rotation3D (const vec3 &Axis, float angleDeg); // rotation 3D mat4 rotation3Drad(const vec3 &Axis, float angleRad); // rotation 3D mat4 scaling3D (const vec3 &scaleVector); // scaling 3D mat4 perspective3D(float d); // perspective 3D vec3 operator * (const vec3 &v, const mat3 &a); vec2 operator * (const vec2 &v, const mat3 &a); vec3 operator * (const vec3 &v, const mat4 &a); vec4 operator * (const vec4 &v, const mat4 &a); #endif asymptote-2.37/align.h000066400000000000000000000043461265434602500147530ustar00rootroot00000000000000#ifndef __align_h__ #define __align_h__ 1 #ifndef HAVE_POSIX_MEMALIGN #ifdef __GLIBC_PREREQ #if __GLIBC_PREREQ(2,3) #define HAVE_POSIX_MEMALIGN #endif #else #ifdef _POSIX_SOURCE #define HAVE_POSIX_MEMALIGN #endif #endif #endif #ifdef __Array_h__ namespace Array { static const array1 NULL1; static const array2 NULL2; static const array3 NULL3; } #else #ifdef HAVE_POSIX_MEMALIGN #ifdef _AIX extern "C" int posix_memalign(void **memptr, size_t alignment, size_t size); #endif #else namespace Array { // Adapted from FFTW aligned malloc/free. Assumes that malloc is at least // sizeof(void*)-aligned. Allocated memory must be freed with free0. inline int posix_memalign0(void **memptr, size_t alignment, size_t size) { if(alignment % sizeof (void *) != 0 || (alignment & (alignment - 1)) != 0) return EINVAL; void *p0=malloc(size+alignment); if(!p0) return ENOMEM; void *p=(void *)(((size_t) p0+alignment)&~(alignment-1)); *((void **) p-1)=p0; *memptr=p; return 0; } inline void free0(void *p) { if(p) free(*((void **) p-1)); } } #endif namespace Array { template inline void newAlign(T *&v, size_t len, size_t align) { void *mem=NULL; const char *invalid="Invalid alignment requested"; const char *nomem="Memory limits exceeded"; #ifdef HAVE_POSIX_MEMALIGN int rc=posix_memalign(&mem,align,len*sizeof(T)); #else int rc=posix_memalign0(&mem,align,len*sizeof(T)); #endif if(rc == EINVAL) std::cerr << invalid << std::endl; if(rc == ENOMEM) std::cerr << nomem << std::endl; v=(T *) mem; for(size_t i=0; i < len; i++) new(v+i) T; } template inline void deleteAlign(T *v, size_t len) { for(size_t i=len; i-- > 0;) v[i].~T(); #ifdef HAVE_POSIX_MEMALIGN free(v); #else free0(v); #endif } } #endif namespace utils { inline unsigned int ceilquotient(unsigned int a, unsigned int b) { return (a+b-1)/b; } inline Complex *ComplexAlign(size_t size) { Complex *v; Array::newAlign(v,size,sizeof(Complex)); return v; } inline double *doubleAlign(size_t size) { double *v; Array::newAlign(v,size,sizeof(Complex)); return v; } template inline void deleteAlign(T *p) { #ifdef HAVE_POSIX_MEMALIGN free(p); #else Array::free0(p); #endif } } #endif asymptote-2.37/angle.h000066400000000000000000000014441265434602500147430ustar00rootroot00000000000000/***** * angle.h * Andy Hammerlindl 2004/04/29 * * For degree to radian conversion and visa versa. *****/ #ifndef ANGLE_H #define ANGLE_H #include #include "camperror.h" namespace camp { const double PI=acos(-1.0); const double Cpiby180=PI/180.0; const double C180bypi=180.0/PI; inline double radians(double theta) { return theta*Cpiby180; } inline double degrees(double theta) { return theta*C180bypi; } // Wrapper for atan2 with sensible (lexical) argument order and (0,0) check inline double angle(double x, double y) { if(x == 0.0 && y == 0.0) reportError("taking angle of (0,0)"); return atan2(y,x); } // Return an angle in the interval [0,360). inline double principalBranch(double deg) { if(deg < 0) deg += 360; return deg; } } //namespace camp #endif asymptote-2.37/application.cc000066400000000000000000000441461265434602500163240ustar00rootroot00000000000000/***** * application.cc * Andy Hammerlindl 2005/05/20 * * An application is a matching of arguments in a call expression to formal * parameters of a function. Since the language allows default arguments, * keyword arguments, rest arguments, and anything else we think of, this * is not a simple mapping. *****/ #include "application.h" #include "exp.h" #include "coenv.h" #include "runtime.h" #include "runarray.h" using namespace types; using absyntax::varinit; using absyntax::arrayinit; using absyntax::arglist; namespace trans { // Lower scores are better. Packed is added onto the other qualifiers so // we may score both exact and casted packed arguments. const score FAIL=0, EXACT=1, CAST=2; const score PACKED=2; bool castable(env &e, formal& target, formal& source) { return target.Explicit ? equivalent(target.t,source.t) : e.castable(target.t,source.t, symbol::castsym); } score castScore(env &e, formal& target, formal& source) { return equivalent(target.t,source.t) ? EXACT : (!target.Explicit && e.fastCastable(target.t,source.t)) ? CAST : FAIL; } void restArg::transMaker(coenv &e, Int size, bool rest) { // Push the number of cells and call the array maker. e.c.encode(inst::intpush, size); e.c.encode(inst::builtin, rest ? run::newAppendedArray : run::newInitializedArray); } void restArg::trans(coenv &e, temp_vector &temps) { // Push the values on the stack. for (mem::list::iterator p = inits.begin(); p != inits.end(); ++p) (*p)->trans(e, temps); if (rest) rest->trans(e, temps); transMaker(e, (Int)inits.size(), (bool)rest); } class maximizer { app_list l; // Tests if x is as good (or better) an application as y. bool asgood(application *x, application *y) { // Matches to open signatures are always worse than matches to normal // signatures. if (x->sig->isOpen) return y->sig->isOpen; else if (y->sig->isOpen) return true; assert (x->scores.size() == y->scores.size()); // Test if each score in x is no higher than the corresponding score in // y. return std::equal(x->scores.begin(), x->scores.end(), y->scores.begin(), std::less_equal()); } bool better(application *x, application *y) { return asgood(x,y) && !asgood(y,x); } // Add an application that has already been determined to be maximal. // Remove any other applications that are now not maximal because of its // addition. void addMaximal(application *x) { app_list::iterator y=l.begin(); while (y!=l.end()) if (better(x,*y)) y=l.erase(y); else ++y; l.push_front(x); } // Tests if x is maximal. bool maximal(application *x) { for (app_list::iterator y=l.begin(); y!=l.end(); ++y) if (better(*y,x)) return false; return true; } public: maximizer() {} void add(application *x) { if (maximal(x)) addMaximal(x); } app_list result() { return l; } }; ty *restCellType(signature *sig) { formal& f=sig->getRest(); if (f.t) { array *a=dynamic_cast(f.t); if (a) return a->celltype; } return 0; } void application::initRest() { formal& f=sig->getRest(); if (f.t) { ty *ct = restCellType(sig); if (!ct) vm::error("formal rest argument must be an array"); rf=formal(ct, symbol::nullsym, false, f.Explicit); } if (f.t || sig->isOpen) { rest=new restArg(); } } //const Int REST=-1; const Int NOMATCH=-2; Int application::find(symbol name) { formal_vector &f=sig->formals; for (size_t i=index; iadd(seq.addArg(a, rf.t, evalIndex)); scores.push_back(s+PACKED); return true; } } return false; } bool application::matchAtSpot(size_t spot, env &e, formal &source, varinit *a, size_t evalIndex) { formal &target=sig->getFormal(spot); score s=castScore(e, target, source); if (s == FAIL) return false; else if (sig->formalIsKeywordOnly(spot) && source.name == symbol::nullsym) return false; else { // The argument matches. args[spot]=seq.addArg(a, target.t, evalIndex); if (spot==index) advanceIndex(); scores.push_back(s); return true; } } bool application::matchArgument(env &e, formal &source, varinit *a, size_t evalIndex) { assert(!source.name); if (index==args.size()) // Try to pack into the rest array. return matchArgumentToRest(e, source, a, evalIndex); else // Match here, or failing that use a default and try to match at the next // spot. return matchAtSpot(index, e, source, a, evalIndex) || (matchDefault() && matchArgument(e, source, a, evalIndex)); } bool application::matchNamedArgument(env &e, formal &source, varinit *a, size_t evalIndex) { assert(source.name); Int spot=find(source.name); return spot!=NOMATCH && matchAtSpot(spot, e, source, a, evalIndex); } bool application::complete() { if (index==args.size()) return true; else if (matchDefault()) return complete(); else return false; } bool application::matchRest(env &e, formal &source, varinit *a, size_t evalIndex) { // First make sure all non-rest arguments are matched (matching to defaults // if necessary). if (complete()) // Match rest to rest. if (rest) { formal &target=sig->getRest(); score s=castScore(e, target, source); if (s!=FAIL) { rest->addRest(seq.addArg(a, target.t, evalIndex)); scores.push_back(s); return true; } } return false; } // When the argument should be evaluated, possibly adjusting for a rest // argument which occurs before named arguments. size_t adjustIndex(size_t i, size_t ri) { return i < ri ? i : i+1; } bool application::matchSignature(env &e, types::signature *source, arglist &al) { formal_vector &f=source->formals; #if 0 cout << "num args: " << f.size() << endl; cout << "num keyword-only: " << sig->numKeywordOnly << endl; #endif size_t ri = al.rest.val ? al.restPosition : f.size(); // First, match all of the named (non-rest) arguments. for (size_t i=0; ihasRest()) if (!matchRest(e, source->getRest(), al.rest.val, ri)) return false; // Fill in any remaining arguments with their defaults. return complete(); } bool application::matchOpen(env &e, signature *source, arglist &al) { assert(rest); // Pack all given parameters into the rest argument. formal_vector &f=source->formals; for (size_t i = 0; i < f.size(); ++i) if (al[i].name) // Named arguments are not handled by open signatures. return false; else rest->add(seq.addArg(al[i].val, f[i].t, i)); if (source->hasRest()) rest->addRest(new varinitArg(al.rest.val, source->getRest().t)); return true; } application *application::match(env &e, function *t, signature *source, arglist &al) { assert(t->kind==ty_function); application *app=new application(t); bool success = t->getSignature()->isOpen ? app->matchOpen(e, source, al) : app->matchSignature(e, source, al); //cout << "MATCH " << success << endl; return success ? app : 0; } void application::transArgs(coenv &e) { temp_vector temps; for(arg_vector::iterator a=args.begin(); a != args.end(); ++a) (*a)->trans(e,temps); if (rest) rest->trans(e,temps); } bool application::exact() { if (sig->isOpen) return false; for (score_vector::iterator p = scores.begin(); p != scores.end(); ++p) if (*p != EXACT) return false; return true; } bool application::halfExact() { if (sig->isOpen) return false; if (scores.size() != 2) return false; if (scores[0] == EXACT && scores[1] == CAST) return true; if (scores[0] == CAST && scores[1] == EXACT) return true; return false; } // True if any of the formals have names. bool namedFormals(signature *sig) { formal_vector& formals = sig->formals; size_t n = formals.size(); for (size_t i = 0; i < n; ++i) { if (formals[i].name) return true; } return false; } // Tests if arguments in the source signature can be matched to the formals // in the target signature with no casting or packing. // This allows overloaded args, but not named args. bool exactMightMatch(signature *target, signature *source) { // Open signatures never exactly match. if (target->isOpen) return false; #if 0 assert(!namedFormals(source)); #endif formal_vector& formals = target->formals; formal_vector& args = source->formals; // Sizes of the two lists. size_t fn = formals.size(), an = args.size(); // Indices for the two lists. size_t fi = 0, ai = 0; while (fi < fn && ai < an) { if (equivalent(formals[fi].t, args[ai].t)) { // Arguments match, move to the next. ++fi; ++ai; } else if (formals[fi].defval) { // Match formal to default value. ++fi; } else { // Failed to match formal. return false; } } assert(fi == fn || ai == an); // Packing array arguments into the rest formal is inexact. Do not allow it // here. if (ai < an) return false; assert(ai == an); // Match any remaining formal to defaults. while (fi < fn) if (formals[fi].defval) { // Match formal to default value. ++fi; } else { // Failed to match formal. return false; } // Non-rest arguments have matched. assert(fi == fn && ai == an); // Try to match the rest argument if given. if (source->hasRest()) { if (!target->hasRest()) return false; if (!equivalent(source->getRest().t, target->getRest().t)) return false; } // All arguments have matched. return true; } // Tries to match applications without casting. If an application matches // here, we need not attempt to match others with the slower, more general // techniques. app_list exactMultimatch(env &e, types::overloaded *o, types::signature *source, arglist &al) { assert(source); app_list l; // This can't handle named arguments. if (namedFormals(source)) return l; /* empty */ for (ty_vector::iterator t=o->sub.begin(); t!=o->sub.end(); ++t) { if ((*t)->kind != ty_function) continue; function *ft = (function *)*t; // First we run a test to see if all arguments could be exactly matched. // If this returns false, no such match is possible. // If it returns true, an exact match may or may not be possible. if (!exactMightMatch(ft->getSignature(), source)) continue; application *a=application::match(e, ft, source, al); // Consider calling // void f(A a=new A, int y) // with // f(3) // This matches exactly if there is no implicit cast from int to A. // Otherwise, it does not match. // Thus, there is no way to know if the // match truly is exact without looking at the environment. // In such a case, exactMightMatch() must return true, but there is no // exact match. Such false positives are eliminated here. // // Consider calling // void f(int x, real y=0.0, int z=0) // with // f(1,2) // exactMightMatch() will return true, matching 1 to x and 2 to z, but the // application::match will give an inexact match of 1 to x to 2 to y, due // to the cast from int to real. Therefore, we must test for exactness // even after matching. if (a && a->exact()) l.push_back(a); } //cout << "EXACTMATCH " << (!l.empty()) << endl; return l; } bool halfExactMightMatch(env &e, signature *target, types::ty *t1, types::ty *t2) { formal_vector& formals = target->formals; if (formals.size() < 2) return false; if (formals.size() > 2) { // We should probably abort the whole matching in this case. For now, // return true and let the usual matching handle it. return true; } assert(formals[0].t); assert(formals[1].t); // These casting tests if successful will be repeated again by // application::match. It would be nice to avoid this somehow, but the // additional complexity is probably not worth the minor speed improvement. if (equivalent(formals[0].t, t1)) return e.fastCastable(formals[1].t, t2); else return equivalent(formals[1].t, t2) && e.fastCastable(formals[0].t, t1); } // Most common after exact matches are cases such as // 2 + 3.4 (int, real) --> (real, real) // that is, binary operations where one of the operands matches exactly and the // other does not. This function searches for these so-called "half-exact" // matches. This should only be called after exactMultimatch has failed. app_list halfExactMultimatch(env &e, types::overloaded *o, types::signature *source, arglist &al) { assert(source); app_list l; // Half exact is only in the case of two arguments. formal_vector& formals = source->formals; if (formals.size() != 2 || source->hasRest()) return l; /* empty */ // This can't handle named arguments. if (namedFormals(source)) return l; /* empty */ // Alias the two argument types. types::ty *t1 = formals[0].t; types::ty *t2 = formals[1].t; assert(t1); assert(t2); for (ty_vector::iterator t=o->sub.begin(); t!=o->sub.end(); ++t) { if ((*t)->kind != ty_function) continue; function *ft = (function *)*t; #if 1 if (!halfExactMightMatch(e, ft->getSignature(), t1, t2)) continue; #endif application *a=application::match(e, ft, source, al); #if 1 if (a && a->halfExact()) l.push_back(a); #endif } return l; } // Simple check if there are too many arguments to match the candidate // function. // A "tooFewArgs" variant was also implemented at some point, but did // not give any speed-up. bool tooManyArgs(types::signature *target, types::signature *source) { return source->getNumFormals() > target->getNumFormals() && !target->hasRest(); } // The full overloading resolution system, which handles casting of arguments, // packing into rest arguments, named arguments, etc. app_list inexactMultimatch(env &e, types::overloaded *o, types::signature *source, arglist &al) { assert(source); app_list l; #define DEBUG_GETAPP 0 #if DEBUG_GETAPP //cout << "source: " << *source << endl; //cout << "ARGS: " << source->getNumFormals() << endl; bool perfect=false; bool exact=false; bool halfExact=false; #endif for(ty_vector::iterator t=o->sub.begin(); t!=o->sub.end(); ++t) { if ((*t)->kind==ty_function) { #if DEBUG_GETAPP function *ft = dynamic_cast(*t); signature *target = ft->getSignature(); if (equivalent(target, source)) perfect = true; #endif // Check if there are two many arguments to match. if (tooManyArgs((*t)->getSignature(), source)) continue; application *a=application::match(e, (function *)(*t), source, al); if (a) l.push_back(a); #if DEBUG_GETAPP if (a && !namedFormals(source)) { assert(a->exact() == exactlyMatchable(ft->getSignature(), source)); if (a->halfExact() && !namedFormals(source)) { assert(halfExactMightMatch(e, target, source->getFormal(0).t, source->getFormal(1).t)); } } if (a && a->exact()) exact = true; if (a && a->halfExact()) halfExact = true; #endif } } #if DEBUG_GETAPP cout << (perfect ? "PERFECT" : exact ? "EXACT" : halfExact ? "HALFEXACT" : "IMPERFECT") << endl; #endif if (l.size() > 1) { // Return the most specific candidates. maximizer m; for (app_list::iterator x=l.begin(); x!=l.end(); ++x) { assert(*x); m.add(*x); } return m.result(); } else return l; } enum testExactType { TEST_EXACT, DONT_TEST_EXACT, }; // Sanity check for multimatch optimizations. void sameApplications(app_list a, app_list b, testExactType te) { assert(a.size() == b.size()); if (te == TEST_EXACT) { for (app_list::iterator i = a.begin(); i != a.end(); ++i) { if (!(*i)->exact()) { cout << *(*i)->getType() << endl; } assert((*i)->exact()); } for (app_list::iterator i = b.begin(); i != b.end(); ++i) assert((*i)->exact()); } if (a.size() == 1) assert(equivalent(a.front()->getType(), b.front()->getType())); } app_list multimatch(env &e, types::overloaded *o, types::signature *source, arglist &al) { app_list a = exactMultimatch(e, o, source, al); if (!a.empty()) { #if DEBUG_CACHE // Make sure that exactMultimatch and the fallback return the same // application(s). sameApplications(a, inexactMultimatch(e, o, source, al), TEST_EXACT); #endif return a; } a = halfExactMultimatch(e, o, source, al); if (!a.empty()) { #if DEBUG_CACHE sameApplications(a, inexactMultimatch(e, o, source, al), DONT_TEST_EXACT); #endif return a; } // Slow but most general method. return inexactMultimatch(e, o, source, al); } } // namespace trans asymptote-2.37/application.h000066400000000000000000000216061265434602500161620ustar00rootroot00000000000000/***** * application.h * Andy Hammerlindl 2005/05/20 * * An application is a matching of arguments in a call expression to formal * parameters of a function. Since the language allows default arguments, * keyword arguments, rest arguments, and anything else we think of, this * is not a simple mapping. *****/ #ifndef APPLICATION_H #define APPLICATION_H #include "common.h" #include "types.h" #include "coenv.h" #include "exp.h" // Defined in runtime.in: namespace run { void pushDefault(vm::stack *Stack); } using absyntax::arglist; using absyntax::varinit; using absyntax::arrayinit; using absyntax::tempExp; // This is mid-way between trans and absyntax. namespace trans { typedef Int score; typedef mem::vector score_vector; // This is used during the translation of arguments to store temporary // expressions for arguments that need to be translated for side-effects at a // certain point but used later on. The invariant maintained is that if the // vector has n elements, then the side-effects for the first n arguments have // been translated. Null is pushed onto the vector to indicate that the // expression was evaluated directly onto the stack, without the use of a // temporary. typedef mem::vector temp_vector; struct arg : public gc { types::ty *t; arg(types::ty *t) : t(t) {} virtual ~arg() {} virtual void trans(coenv &e, temp_vector &) = 0; }; struct varinitArg : public arg { varinit *v; varinitArg(varinit *v, types::ty *t) : arg(t), v(v) {} virtual void trans(coenv &e, temp_vector &) { // Open signatures can match overloaded variables, but there is no way to // translate the result, so report an error. if (t->kind == types::ty_overloaded) { em.error(v->getPos()); em << "overloaded argument in function call"; } else v->transToType(e, t); } }; // Pushes a default argument token on the stack as a placeholder for the // argument. struct defaultArg : public arg { defaultArg(types::ty *t) : arg(t) {} virtual void trans(coenv &e, temp_vector &) { //e.c.encode(inst::builtin, run::pushDefault); e.c.encode(inst::push_default); } }; // Handles translation of all the arguments matched to the rest formal. // NOTE: This code duplicates a lot of arrayinit. struct restArg : public gc { mem::list inits; arg *rest; public: restArg() : rest(0) {} virtual ~restArg() {} // Encodes the instructions to make an array from size elements on the stack. static void transMaker(coenv &e, Int size, bool rest); void trans(coenv &e, temp_vector &temps); void add(arg *init) { inits.push_back(init); } void addRest(arg *init) { rest=init; } }; // This class generates sequenced args, args whose side-effects occur in order // according to their index, regardless of the order they are called. This is // used to ensure left-to-right order of evaluation of keyword arguments, even // if they are given out of the order specified in the declaration. class sequencer { struct sequencedArg : public varinitArg { sequencer &parent; size_t i; sequencedArg(varinit *v, types::ty *t, sequencer &parent, size_t i) : varinitArg(v, t), parent(parent), i(i) {} void trans(coenv &e, temp_vector &temps) { parent.trans(e, i, temps); } }; typedef mem::vector sa_vector; sa_vector args; // Makes a temporary for the next argument in the sequence. void alias(coenv &e, temp_vector &temps) { size_t n=temps.size(); assert(n < args.size()); sequencedArg *sa=args[n]; assert(sa); temps.push_back(new tempExp(e, sa->v, sa->t)); } // Get in a state to translate the i-th argument, aliasing any arguments that // occur before it in the sequence. void advance(coenv &e, size_t i, temp_vector &temps) { while (temps.size() < i) alias(e,temps); } void trans(coenv &e, size_t i, temp_vector &temps) { if (i < temps.size()) { // Already translated, use the alias. assert(temps[i]); temps[i]->trans(e); } else { // Alias earlier args if necessary. advance(e, i, temps); // Translate using the base method. args[i]->varinitArg::trans(e,temps); // Push null to indicate the argument has been translated. temps.push_back(0); } } public: arg *addArg(varinit *v, types::ty *t, size_t i) { if (args.size() <= i) args.resize(i+1); return args[i]=new sequencedArg(v, t, *this, i); } }; class application : public gc { types::signature *sig; types::function *t; // Sequencer to ensure given arguments are evaluated in the proper order. // Use of this sequencer means that transArgs can only be called once. sequencer seq; typedef mem::vector arg_vector; arg_vector args; restArg *rest; // Target formal to match with arguments to be packed into the rest array. types::formal rf; // During the matching of arguments to an application, this stores the index // of the first unmatched formal. size_t index; // To resolve which is the best application in case of multiple matches of // overloaded functions, a score is kept for every source argument matched, // and an application with higher-scoring matches is chosen. score_vector scores; void initRest(); application(types::signature *sig) : sig(sig), t(0), args(sig->formals.size()), rest(0), rf(0), index(0) { assert(sig); initRest(); } application(types::function *t) : sig(t->getSignature()), t(t), args(sig->formals.size()), rest(0), rf(0), index(0) { assert(sig); initRest(); } types::formal &getTarget() { return sig->getFormal(index); } // Move the index forward one, then keep going until we're at an unmatched // argument. void advanceIndex() { do { ++index; } while (index < args.size() && args[index]!=0); } // Finds the first unmatched formal of the given name, returning the index. // The rest formal is not tested. This function returns FAIL if no formals // match. Int find(symbol name); // Match the formal at index to its default argument (if it has one). bool matchDefault(); // Match the argument to the formal indexed by spot. bool matchAtSpot(size_t spot, env &e, types::formal &source, varinit *a, size_t evalIndex); // Match the argument to be packed into the rest array, if possible. bool matchArgumentToRest(env &e, types::formal& source, varinit *a, size_t evalIndex); // Matches the argument to a formal in the target signature (possibly causing // other formals in the target to be matched to default values), and updates // the matchpoint accordingly. bool matchArgument(env &e, types::formal& source, varinit *a, size_t evalIndex); // Match an argument bound to a name, as in f(index=7). bool matchNamedArgument(env &e, types::formal& source, varinit *a, size_t evalIndex); // After all source formals have been matched, checks if the match is // complete (filling in final default values if necessary). bool complete(); // Match a rest argument in the calling expression. bool matchRest(env &e, types::formal& f, varinit *a, size_t evalIndex); // Match the argument represented in signature to the target signature. On // success, all of the arguments in args will be properly set up. bool matchSignature(env &e, types::signature *source, arglist &al); // Match a signature which is open, meaning that any sequence of arguments is // matched. bool matchOpen(env &e, signature *source, arglist &al); friend class maximizer; public: // Attempt to build an application given the target signature and the source // signature (representing the given arguments). Return 0 if they cannot be // matched. static application *match(env &e, types::function *t, types::signature *source, arglist &al); // Translate the arguments so they appear in order on the stack in // preparation for a call. void transArgs(coenv &e); types::function *getType() { return t; } // This returns true in the special case that the arguments matched without // casting or packing into the rest formal. bool exact(); // The next best thing (score-wise) to an exact match. This returns true if // there are two arguments, one of which is cast and one is matched exactly // and neither are packed into the rest argument. bool halfExact(); }; typedef mem::list app_list; // Given an overloaded list of types, determines which type to call. If none // are applicable, returns an empty vector, if there is ambiguity, several will // be returned. app_list multimatch(env &e, types::overloaded *o, types::signature *source, arglist &al); } // namespace trans #endif asymptote-2.37/arcball.cc000066400000000000000000000130321265434602500154070ustar00rootroot00000000000000/********************************************************************** arcball.cc -------------------------------------------------- GLUI User Interface Toolkit (LGPL) Copyright (c) 1998 Paul Rademacher Feb 1998, Paul Rademacher (rademach@cs.unc.edu) Oct 2003, Nigel Stewart - GLUI Code Cleaning WWW: http://sourceforge.net/projects/glui/ Forums: http://sourceforge.net/forum/?group_id=92496 This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA **********************************************************************/ #include "arcball.h" #include /**************************************** Arcball::Arcball() ****/ /* Default (void) constructor for Arcball */ Arcball::Arcball() { rot_ptr = &rot; init(); } /**************************************** Arcball::Arcball() ****/ /* Takes as argument a mat4 to use instead of the internal rot */ Arcball::Arcball(mat4 *mtx) { rot_ptr = mtx; } /**************************************** Arcball::Arcball() ****/ /* A constructor that accepts the screen center and arcball radius*/ Arcball::Arcball(const vec2 &_center, float _radius) { rot_ptr = &rot; init(); set_params(_center, _radius); } /************************************** Arcball::set_params() ****/ void Arcball::set_params(const vec2 &_center, float _radius) { center = _center; radius = _radius; } /*************************************** Arcball::init() **********/ void Arcball::init() { center.set( 0.0, 0.0 ); radius = 1.0; q_now = quat_identity(); *rot_ptr = identity3D(); q_increment = quat_identity(); rot_increment = identity3D(); is_mouse_down = false; is_spinning = false; damp_factor = 0.0; zero_increment = true; } /*********************************** Arcball::mouse_to_sphere() ****/ vec3 Arcball::mouse_to_sphere(const vec2 &p) { float mag; vec2 v2 = (p - center) / radius; vec3 v3( v2[0], v2[1], 0.0 ); mag = v2*v2; if ( mag > 1.0 ) v3.normalize(); else v3[VZ] = (float) sqrt( 1.0 - mag ); /* Now we add constraints - X takes precedence over Y */ if ( constraint_x ) { v3 = constrain_vector( v3, vec3( 1.0, 0.0, 0.0 )); } else if ( constraint_y ) { v3 = constrain_vector( v3, vec3( 0.0, 1.0, 0.0 )); } return v3; } /************************************ Arcball::constrain_vector() ****/ vec3 Arcball::constrain_vector(const vec3 &vector, const vec3 &axis) { return (vector-(vector*axis)*axis).normalize(); } /************************************ Arcball::mouse_down() **********/ void Arcball::mouse_down(int x, int y) { down_pt.set( (float)x, (float) y ); is_mouse_down = true; q_increment = quat_identity(); rot_increment = identity3D(); zero_increment = true; } /************************************ Arcball::mouse_up() **********/ void Arcball::mouse_up() { q_now = q_drag * q_now; is_mouse_down = false; } /********************************** Arcball::mouse_motion() **********/ void Arcball::mouse_motion(int x, int y, int shift, int ctrl, int alt) { /* Set the X constraint if CONTROL key is pressed, Y if ALT key */ set_constraints( ctrl != 0, alt != 0 ); vec2 new_pt( (float)x, (float) y ); vec3 v0 = mouse_to_sphere( down_pt ); vec3 v1 = mouse_to_sphere( new_pt ); vec3 cross = v0^v1; q_drag.set( cross, v0 * v1 ); // *rot_ptr = (q_drag * q_now).to_mat4(); mat4 temp = q_drag.to_mat4(); *rot_ptr = *rot_ptr * temp; down_pt = new_pt; /* We keep a copy of the current incremental rotation (= q_drag) */ q_increment = q_drag; rot_increment = q_increment.to_mat4(); set_constraints(false, false); if ( q_increment.s < .999999 ) { is_spinning = true; zero_increment = false; } else { is_spinning = false; zero_increment = true; } } /********************************** Arcball::mouse_motion() **********/ void Arcball::mouse_motion(int x, int y) { mouse_motion(x, y, 0, 0, 0); } /***************************** Arcball::set_constraints() **********/ void Arcball::set_constraints(bool _constraint_x, bool _constraint_y) { constraint_x = _constraint_x; constraint_y = _constraint_y; } /***************************** Arcball::idle() *********************/ void Arcball::idle() { if (is_mouse_down) { is_spinning = false; zero_increment = true; } if (damp_factor < 1.0f) q_increment.scale_angle(1.0f - damp_factor); rot_increment = q_increment.to_mat4(); if (q_increment.s >= .999999f) { is_spinning = false; zero_increment = true; } } /************************ Arcball::set_damping() *********************/ void Arcball::set_damping(float d) { damp_factor = d; } asymptote-2.37/arcball.h000066400000000000000000000064251265434602500152610ustar00rootroot00000000000000/********************************************************************** arcball.h GLUI User Interface Toolkit (LGPL) Copyright (c) 1998 Paul Rademacher Feb 1998, Paul Rademacher (rademach@cs.unc.edu) Oct 2003, Nigel Stewart - GLUI Code Cleaning WWW: http://sourceforge.net/projects/glui/ Forums: http://sourceforge.net/forum/?group_id=92496 This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA --------------------------------------------------------------------- A C++ class that implements the Arcball, as described by Ken Shoemake in Graphics Gems IV. This class takes as input mouse events (mouse down, mouse drag, mouse up), and creates the appropriate quaternions and 4x4 matrices to represent the rotation given by the mouse. This class is used as follows: - initialize [either in the constructor or with set_params()], the center position (x,y) of the arcball on the screen, and the radius - on mouse down, call mouse_down(x,y) with the mouse position - as the mouse is dragged, repeatedly call mouse_motion() with the current x and y positions. One can optionally pass in the current state of the SHIFT, ALT, and CONTROL keys (passing zero if keys are not pressed, non-zero otherwise), which constrains the rotation to certain axes (X for CONTROL, Y for ALT). - when the mouse button is released, call mouse_up() Axis constraints can also be explicitly set with the set_constraints() function. The current rotation is stored in the 4x4 float matrix 'rot'. It is also stored in the quaternion 'q_now'. **********************************************************************/ #ifndef GLUI_ARCBALL_H #define GLUI_ARCBALL_H #include "algebra3.h" #include "quaternion.h" class Arcball { public: Arcball(); Arcball(mat4 *mtx); Arcball(const vec2 ¢er, float radius); void set_damping(float d); void idle(); void mouse_down(int x, int y); void mouse_up(); void mouse_motion(int x, int y, int shift, int ctrl, int alt); void mouse_motion(int x, int y); void set_constraints(bool constrain_x, bool constrain_y); void set_params(const vec2 ¢er, float radius); void init(); vec3 constrain_vector(const vec3 &vector, const vec3 &axis); vec3 mouse_to_sphere(const vec2 &p); //public: int is_mouse_down; /* true for down, false for up */ int is_spinning; quat q_now, q_down, q_drag, q_increment; vec2 down_pt; mat4 rot, rot_increment; mat4 *rot_ptr; bool constraint_x, constraint_y; vec2 center; float radius, damp_factor; int zero_increment; }; #endif asymptote-2.37/array.cc000066400000000000000000000110201265434602500151200ustar00rootroot00000000000000/***** * array.cc * Andy Hammerlindl 2008/01/26 * * Array type used by virtual machine. *****/ #include "array.h" #include "mod.h" namespace vm { inline void checkBackSlice(Int left, Int right) { if (right < left) // There isn't a clear behaviour for slices of the form A[5:2], so we don't // allow them. (Atleast, not until we can figure out what the behaviour // should be.) vm::error("slice ends before it begins"); } inline size_t sliceIndex(Int in, size_t len) { if (in < 0) // The Python behaviour here would simply be // in += len; // but this is inconsistent with Asymptote issuing an error for A[-1] if A // is a non-cyclic array, so we also issue an error here. vm::error("invalid negative index in slice of non-cyclic array"); if (in < 0) return 0; size_t index = (size_t)in; return index < len ? index : len; } array *array::slice(Int left, Int right) { checkBackSlice(left, right); if (left == right) return new array(); size_t length=size(); if (length == 0) return new array(); if (cycle) { size_t resultLength = (size_t)(right - left); array *result = new array(resultLength); size_t i = (size_t)imod(left, length), ri = 0; while (ri < resultLength) { (*result)[ri] = (*this)[i]; ++ri; ++i; if (i >= length) i -= length; } return result; } else { // Non-cyclic size_t l = sliceIndex(left, length); size_t r = sliceIndex(right, length); size_t resultLength = r - l; array *result = new array(resultLength); std::copy(this->begin()+l, this->begin()+r, result->begin()); return result; } } void array::setNonBridgingSlice(size_t l, size_t r, mem::vector *a) { assert(0 <= l); assert(l <= r); size_t asize=a->size(); if (asize == r-l) { // In place std::copy(a->begin(), a->end(), this->begin()+l); } else if (asize < r-l) { // Shrinking std::copy(a->begin(), a->end(), this->begin()+l); this->erase(this->begin()+l+a->size(), this->begin()+r); } else { // Expanding // NOTE: As a speed optimization, we could check capacity() to see if the // array can fit the new entries, and build the new array from scratch // (using swap()) if a new allocation is necessary. std::copy(a->begin(), a->begin()+r-l, this->begin()+l); this->insert(this->begin()+r, a->begin()+r-l, a->end()); } } void array::setBridgingSlice(size_t l, size_t r, mem::vector *a) { size_t len=this->size(); assert(r<=l); assert(r+len-l == a->size()); std::copy(a->begin(), a->begin()+(len-l), this->begin()+l); std::copy(a->begin()+(len-l), a->end(), this->begin()); } void array::setSlice(Int left, Int right, array *a) { checkBackSlice(left, right); // If we are slicing an array into itself, slice in a copy instead, to ensure // the proper result. mem::vector *v = (a == this) ? new mem::vector(*a) : a; size_t length=size(); if (cycle) { if (right == left) { // Notice that assigning to the slice A[A.length:A.length] is the same as // assigning to the slice A[0:0] for a cyclic array. size_t l = (size_t)imod(left, length); setNonBridgingSlice(l, l, v); } else { if (left + (Int) length < right) vm::error("assigning to cyclic slice with repeated entries"); size_t l = (size_t)imod(left, length); // Set r to length instead of zero, so that slices that go to the end of // the array are properly treated as non-bridging. size_t r = (size_t)imod(right, length); if (r == 0) r = length; if (l < r) setNonBridgingSlice(l, r, v); else { if (r + length - l == v->size()) setBridgingSlice(l, r, v); else vm::error("assignment to cyclic slice is not well defined"); } } } else { size_t l=sliceIndex(left, length); size_t r=sliceIndex(right, length); setNonBridgingSlice(l, r, v); } } item copyItemToDepth(item i, size_t depth) { if (depth == 0) return i; else return get(i)->copyToDepth(depth); } array *array::copyToDepth(size_t depth) { if (depth == 0) { return this; } else { size_t n=this->size(); array *a=new array(n); a->cycle = this->cycle; for (size_t i=0; i(n), cycle(false) { for (size_t k=0; k { bool cycle; void setNonBridgingSlice(size_t l, size_t r, mem::vector *a); void setBridgingSlice(size_t l, size_t r, mem::vector *a); public: array() : cycle(false) {} array(size_t n) : mem::vector(n), cycle(false) {} array(size_t n, item i, size_t depth); void push(item i) { push_back(i); } item pop() { item i=back(); pop_back(); return i; } template T read(size_t i) const { return get((*this)[i]); } array *slice(Int left, Int right); void setSlice(Int left, Int right, array *a); void cyclic(bool b) { cycle=b; } bool cyclic() const { return cycle; } array *copyToDepth(size_t depth); }; template inline T read(const array *a, size_t i) { return a->array::read(i); } template inline T read(const array &a, size_t i) { return a.array::read(i); } inline size_t checkArray(const vm::array *a) { if(a == 0) vm::error("dereference of null array"); return a->size(); } inline void checkEqual(size_t i, size_t j) { if(i == j) return; ostringstream buf; buf << "operation attempted on arrays of different lengths: " << i << " != " << j; vm::error(buf); } inline size_t checkArrays(const vm::array *a, const vm::array *b) { size_t asize=checkArray(a); size_t bsize=checkArray(b); checkEqual(asize,bsize); return asize; } // Copies an item to a depth d. If d == 0 then the item is just returned // without copying, otherwise, the array and its subarrays are copied to // depth d. item copyItemToDepth(item i, size_t depth); } // namespace vm #endif // ARRAY_H asymptote-2.37/arrayop.h000066400000000000000000000327201265434602500153330ustar00rootroot00000000000000/***** * arrayop * John Bowman * * Array operations *****/ #ifndef ARRAYOP_H #define ARRAYOP_H #include "util.h" #include "stack.h" #include "array.h" #include "types.h" #include "fileio.h" #include "callable.h" #include "mathop.h" namespace run { using vm::pop; using vm::read; using vm::array; using camp::tab; vm::array *copyArray(vm::array *a); vm::array *copyArray2(vm::array *a); template class op> void arrayOp(vm::stack *s) { U b=pop(s); array *a=pop(s); size_t size=checkArray(a); array *c=new array(size); for(size_t i=0; i < size; i++) (*c)[i]=op()(read(a,i),b,i); s->push(c); } template class op> void opArray(vm::stack *s) { array *a=pop(s); T b=pop(s); size_t size=checkArray(a); array *c=new array(size); for(size_t i=0; i < size; i++) (*c)[i]=op()(b,read(a,i),i); s->push(c); } template class op> void arrayArrayOp(vm::stack *s) { array *b=pop(s); array *a=pop(s); size_t size=checkArrays(a,b); array *c=new array(size); for(size_t i=0; i < size; i++) (*c)[i]=op()(read(a,i),read(b,i),i); s->push(c); } template void sumArray(vm::stack *s) { array *a=pop(s); size_t size=checkArray(a); T sum=0; for(size_t i=0; i < size; i++) sum += read(a,i); s->push(sum); } extern const char *arrayempty; template class op> void binopArray(vm::stack *s) { array *a=pop(s); size_t size=checkArray(a); if(size == 0) vm::error(arrayempty); T m=read(a,0); for(size_t i=1; i < size; i++) m=op()(m,read(a,i)); s->push(m); } template class op> void binopArray2(vm::stack *s) { array *a=pop(s); size_t size=checkArray(a); bool empty=true; T m=0; for(size_t i=0; i < size; i++) { array *ai=read(a,i); size_t aisize=checkArray(ai); if(aisize) { if(empty) { m=read(ai,0); empty=false; } for(size_t j=0; j < aisize; j++) m=op()(m,read(ai,j)); } } if(empty) vm::error(arrayempty); s->push(m); } template class op> void binopArray3(vm::stack *s) { array *a=pop(s); size_t size=checkArray(a); bool empty=true; T m=0; for(size_t i=0; i < size; i++) { array *ai=read(a,i); size_t aisize=checkArray(ai); for(size_t j=0; j < aisize; j++) { array *aij=read(ai,j); size_t aijsize=checkArray(aij); if(aijsize) { if(empty) { m=read(aij,0); empty=false; } for(size_t k=0; k < aijsize; k++) { m=op()(m,read(aij,k)); } } } } if(empty) vm::error(arrayempty); s->push(m); } template class op> void array2Op(vm::stack *s) { U b=pop(s); array *a=pop(s); size_t size=checkArray(a); array *c=new array(size); for(size_t i=0; i < size; ++i) { array *ai=read(a,i); size_t aisize=checkArray(ai); array *ci=new array(aisize); (*c)[i]=ci; for(size_t j=0; j < aisize; j++) (*ci)[j]=op()(read(ai,j),b,0); } s->push(c); } template class op> void opArray2(vm::stack *s) { array *a=pop(s); T b=pop(s); size_t size=checkArray(a); array *c=new array(size); for(size_t i=0; i < size; ++i) { array *ai=read(a,i); size_t aisize=checkArray(ai); array *ci=new array(aisize); (*c)[i]=ci; for(size_t j=0; j < aisize; j++) (*ci)[j]=op()(read(ai,j),b,0); } s->push(c); } template class op> void array2Array2Op(vm::stack *s) { array *b=pop(s); array *a=pop(s); size_t size=checkArrays(a,b); array *c=new array(size); for(size_t i=0; i < size; ++i) { array *ai=read(a,i); array *bi=read(b,i); size_t aisize=checkArrays(ai,bi); array *ci=new array(aisize); (*c)[i]=ci; for(size_t j=0; j < aisize; j++) (*ci)[j]=op()(read(ai,j),read(bi,j),0); } s->push(c); } template bool Array2Equals(vm::stack *s) { array *b=pop(s); array *a=pop(s); size_t n=checkArray(a); if(n != checkArray(b)) return false; if(n == 0) return true; size_t n0=checkArray(read(a,0)); if(n0 != checkArray(read(b,0))) return false; for(size_t i=0; i < n; ++i) { array *ai=read(a,i); array *bi=read(b,i); for(size_t j=0; j < n0; ++j) { if(read(ai,j) != read(bi,j)) return false; } } return true; } template void array2Equals(vm::stack *s) { s->push(Array2Equals(s)); } template void array2NotEquals(vm::stack *s) { s->push(!Array2Equals(s)); } template void diagonal(vm::stack *s) { array *a=pop(s); size_t n=checkArray(a); array *c=new array(n); for(size_t i=0; i < n; ++i) { array *ci=new array(n); (*c)[i]=ci; for(size_t j=0; j < i; ++j) (*ci)[j]=T(); (*ci)[i]=read(a,i); for(size_t j=i+1; j < n; ++j) (*ci)[j]=T(); } s->push(c); } template struct compare { bool operator() (const vm::item& a, const vm::item& b) { return vm::get(a) < vm::get(b); } }; template void sortArray(vm::stack *s) { array *c=copyArray(pop(s)); sort(c->begin(),c->end(),compare()); s->push(c); } template struct compare2 { bool operator() (const vm::item& A, const vm::item& B) { array *a=vm::get(A); array *b=vm::get(B); size_t size=a->size(); if(size != b->size()) return false; for(size_t j=0; j < size; j++) { if(read(a,j) < read(b,j)) return true; if(read(a,j) > read(b,j)) return false; } return false; } }; // Sort the rows of a 2-dimensional array by the first column, breaking // ties with successively higher columns. template void sortArray2(vm::stack *s) { array *c=copyArray(pop(s)); stable_sort(c->begin(),c->end(),compare2()); s->push(c); } // Search a sorted ordered array a of n elements for key, returning the index i // if a[i] <= key < a[i+1], -1 if key is less than all elements of a, or // n-1 if key is greater than or equal to the last element of a. template void searchArray(vm::stack *s) { T key=pop(s); array *a=pop(s); size_t size= a->size(); if(size == 0 || key < read(a,0)) {s->push(-1); return;} size_t u=size-1; if(key >= read(a,u)) {s->push((Int) u); return;} size_t l=0; while (l < u) { size_t i=(l+u)/2; if(key < read(a,i)) u=i; else if(key < read(a,i+1)) {s->push((Int) i); return;} else l=i+1; } s->push(0); } extern string emptystring; void writestring(vm::stack *s); template void write(vm::stack *s) { array *a=pop(s); vm::callable *suffix=pop(s,NULL); T first=pop(s); string S=pop(s,emptystring); vm::item it=pop(s); bool defaultfile=isdefault(it); camp::file *f=defaultfile ? &camp::Stdout : vm::get(it); size_t size=checkArray(a); if(!f->isOpen()) return; if(S != "") f->write(S); f->write(first); for(size_t i=0; i < size; ++i) { f->write(tab); f->write(read(a,i)); } if(f->text()) { if(suffix) { s->push(f); suffix->call(s); } else if(defaultfile) { try { f->writeline(); } catch (quit&) { } } } } template void writeArray(vm::stack *s) { array *A=pop(s); array *a=pop(s); string S=pop(s,emptystring); vm::item it=pop(s); bool defaultfile=isdefault(it); camp::file *f=defaultfile ? &camp::Stdout : vm::get(it); size_t asize=checkArray(a); size_t Asize=checkArray(A); if(f->Standard()) interact::lines=0; else if(!f->isOpen()) return; try { if(S != "") {f->write(S); f->writeline();} size_t i=0; bool cont=true; while(cont) { cont=false; bool first=true; if(i < asize) { vm::item& I=(*a)[i]; if(defaultfile) cout << i << ":\t"; if(!I.empty()) f->write(vm::get(I)); cont=true; first=false; } unsigned count=0; for(size_t j=0; j < Asize; ++j) { array *Aj=read(A,j); size_t Ajsize=checkArray(Aj); if(i < Ajsize) { if(f->text()) { if(first && defaultfile) cout << i << ":\t"; for(unsigned k=0; k <= count; ++k) f->write(tab); count=0; } vm::item& I=(*Aj)[i]; if(!I.empty()) f->write(vm::get(I)); cont=true; first=false; } else count++; } ++i; if(cont && f->text()) f->writeline(); } } catch (quit&) { } f->flush(); } template void writeArray2(vm::stack *s) { array *a=pop(s); camp::file *f=pop(s,&camp::Stdout); size_t size=checkArray(a); if(f->Standard()) interact::lines=0; else if(!f->isOpen()) return; try { for(size_t i=0; i < size; i++) { vm::item& I=(*a)[i]; if(!I.empty()) { array *ai=vm::get(I); size_t aisize=checkArray(ai); for(size_t j=0; j < aisize; j++) { if(j > 0 && f->text()) f->write(tab); vm::item& I=(*ai)[j]; if(!I.empty()) f->write(vm::get(I)); } } if(f->text()) f->writeline(); } } catch (quit&) { } f->flush(); } template void writeArray3(vm::stack *s) { array *a=pop(s); camp::file *f=pop(s,&camp::Stdout); size_t size=checkArray(a); if(f->Standard()) interact::lines=0; else if(!f->isOpen()) return; try { for(size_t i=0; i < size;) { vm::item& I=(*a)[i]; if(!I.empty()) { array *ai=vm::get(I); size_t aisize=checkArray(ai); for(size_t j=0; j < aisize; j++) { vm::item& I=(*ai)[j]; if(!I.empty()) { array *aij=vm::get(I); size_t aijsize=checkArray(aij); for(size_t k=0; k < aijsize; k++) { if(k > 0 && f->text()) f->write(tab); vm::item& I=(*aij)[k]; if(!I.empty()) f->write(vm::get(I)); } } if(f->text()) f->writeline(); } } ++i; if(i < size && f->text()) f->writeline(); } } catch (quit&) { } f->flush(); } template void arrayFunc(vm::stack *s) { array *a=pop(s); size_t size=checkArray(a); array *c=new array(size); for(size_t i=0; i < size; i++) (*c)[i]=func(read(a,i)); s->push(c); } template void arrayFunc2(vm::stack *s) { array *a=pop(s); size_t size=checkArray(a); array *c=new array(size); for(size_t i=0; i < size; ++i) { array *ai=read(a,i); size_t aisize=checkArray(ai); array *ci=new array(aisize); (*c)[i]=ci; for(size_t j=0; j < aisize; j++) (*ci)[j]=func(read(ai,j)); } s->push(c); } vm::array *Identity(Int n); camp::triple operator *(const vm::array& a, const camp::triple& v); double norm(double *a, size_t n); double norm(camp::triple *a, size_t n); inline size_t checkdimension(const vm::array *a, size_t dim) { size_t size=checkArray(a); if(dim && size != dim) { ostringstream buf; buf << "array of length " << dim << " expected"; vm::error(buf); } return size; } template inline void copyArrayC(T* &dest, const vm::array *a, size_t dim=0, GCPlacement placement=NoGC) { size_t size=checkdimension(a,dim); dest=(placement == NoGC) ? new T[size] : new(placement) T[size]; for(size_t i=0; i < size; i++) dest[i]=vm::read(a,i); } template inline void copyArrayC(T* &dest, const vm::array *a, T (*cast)(A), size_t dim=0, GCPlacement placement=NoGC) { size_t size=checkdimension(a,dim); dest=(placement == NoGC) ? new T[size] : new(placement) T[size]; for(size_t i=0; i < size; i++) dest[i]=cast(vm::read(a,i)); } template inline vm::array* copyCArray(const size_t n, const T* p) { vm::array* a = new vm::array(n); for(size_t i=0; i < n; ++i) (*a)[i] = p[i]; return a; } template inline void copyArray2C(T* &dest, const vm::array *a, bool square=true, size_t dim2=0, GCPlacement placement=NoGC) { size_t n=checkArray(a); size_t m=(square || n == 0) ? n : checkArray(vm::read(a,0)); if(n > 0 && dim2 && m != dim2) { ostringstream buf; buf << "second matrix dimension must be " << dim2; vm::error(buf); } dest=(placement == NoGC) ? new T[n*m] : new(placement) T[n*m]; for(size_t i=0; i < n; i++) { vm::array *ai=vm::read(a,i); size_t aisize=checkArray(ai); if(aisize == m) { T *desti=dest+i*m; for(size_t j=0; j < m; j++) desti[j]=vm::read(ai,j); } else vm::error(square ? "matrix must be square" : "matrix must be rectangular"); } } template inline vm::array* copyCArray2(const size_t n, const size_t m, const T* p) { vm::array* a=new vm::array(n); for(size_t i=0; i < n; ++i) { array *ai=new array(m); (*a)[i]=ai; for(size_t j=0; j < m; ++j) (*ai)[j]=p[m*i+j]; } return a; } } // namespace run #endif // ARRAYOP_H asymptote-2.37/aspy.py000066400000000000000000000263741265434602500150430ustar00rootroot00000000000000##### # # aspy.py # # Andy Hammerlindl 2011/09/03 # # Uses ctypes to interface with the shared library version of Python. # Asymptote can run and its datatypes inspected via Python. # # # To use the module: # 1. make asymptote.so # 2. Ensure that asymptote.so is visable to python, say adding its directory # to LD_LIBRARY_PATH # 3. Run this module. (See runExample for an example.) # ##### from ctypes import * asyInt = c_longlong handle_typ = c_void_p arguments_typ = c_void_p state_typ = c_void_p function_typ = CFUNCTYPE(None, state_typ, c_void_p) class string_typ(Structure): _fields_ = [ ("buf", c_char_p), # Should be NUL-terminated? Maybe replace with # POINTER(c_char). ("length", asyInt) ] ErrorCallbackFUNC = CFUNCTYPE(None, string_typ) NORMAL_ARG = 45000 REST_ARG = 45001 class Policy(Structure): _fields_ = [ ("version", asyInt), ("copyHandle", CFUNCTYPE(handle_typ, handle_typ)), ("releaseHandle", CFUNCTYPE(None, handle_typ)), ("handleFromInt", CFUNCTYPE(handle_typ, asyInt)), ("handleFromBool", CFUNCTYPE(handle_typ, asyInt)), ("handleFromDouble", CFUNCTYPE(handle_typ, c_double)), ("handleFromString", CFUNCTYPE(handle_typ, string_typ)), ("handleFromFunction", CFUNCTYPE(handle_typ, c_char_p, function_typ, c_void_p)), ("IntFromHandle", CFUNCTYPE(asyInt, handle_typ)), ("boolFromHandle", CFUNCTYPE(asyInt, handle_typ)), ("doubleFromHandle", CFUNCTYPE(c_double, handle_typ)), ("stringFromHandle", CFUNCTYPE(string_typ, handle_typ)), ("getField", CFUNCTYPE(handle_typ, handle_typ, c_char_p)), ("getCell", CFUNCTYPE(handle_typ, handle_typ, asyInt)), ("addField", CFUNCTYPE(None, handle_typ, c_char_p, handle_typ)), ("newArguments", CFUNCTYPE(arguments_typ)), ("releaseArguments", CFUNCTYPE(None, arguments_typ)), ("addArgument", CFUNCTYPE(None, arguments_typ, c_char_p, handle_typ, asyInt)), ("call", CFUNCTYPE(handle_typ, handle_typ, arguments_typ)), ("globals", CFUNCTYPE(handle_typ, state_typ)), ("numParams", CFUNCTYPE(asyInt, state_typ)), ("getParam", CFUNCTYPE(handle_typ, state_typ, asyInt)), ("setReturnValue", CFUNCTYPE(None, state_typ, handle_typ)), ("setErrorCallback", CFUNCTYPE(None, ErrorCallbackFUNC)), ] policy = None baseState = None def initPolicyAndBaseState(): global policy, baseState lib = CDLL("asymptote.so") getPolicy = lib._asy_getPolicy getPolicy.restype = POINTER(Policy) policy = getPolicy() getState = lib._asy_getState getState.restype = state_typ baseState = getState() initPolicyAndBaseState() def pyStringFromAsyString(st): #TODO: Handle strings with null-terminators. return str(st.buf) def pyStringFromHandle(h): #TODO: Handle strings with null-terminators. st = policy.contents.stringFromHandle(h) checkForErrors() return pyStringFromAsyString(st) def handleFromPyString(s): st = string_typ(s, len(s)) h = policy.contents.handleFromString(st) checkForErrors() return h def ensureDatum(val): return val if type(val) is Datum else Datum(val) # The error detection scheme. # policyError is set to a string when an error occurs. policyError = [] def pyErrorCallback(s): global policyError policyError.append(pyStringFromAsyString(s)) cErrorCallback = ErrorCallbackFUNC(pyErrorCallback) policy.contents.setErrorCallback(cErrorCallback) class AsyException(Exception): def __init__(self, msg): self.msg = msg def __str__(self): return self.msg def checkForErrors(): """Raises an exception if an error occured.""" global policyError if policyError != []: s = policyError[0] if len(policyError) > 1: s += ' (and other errors)' policyError = [] raise AsyException(s) class Datum(object): def _setHandle(self, handle): object.__setattr__(self, 'handle', handle) def __init__(self, val): self._setHandle(0) if val is None: return if type(val) is int: self._setHandle(policy.contents.handleFromInt(val)) checkForErrors() elif type(val) is bool: self._setHandle(policy.contents.handleFromBool(1 if val else 0)) checkForErrors() elif type(val) is float: self._setHandle(policy.contents.handleFromDouble(val)) elif type(val) is str: self._setHandle(handleFromPyString(val)) checkForErrors() elif type(val) is tuple: # Could do this more efficiently, and avoid a copyHandle ret = state.globals()["operator tuple"](*val) self._setHandle(policy.contents.copyHandle(ret.handle)) checkForErrors() elif type(val) is Datum: self._setHandle(policy.contents.copyHandle(val.handle)) checkForErrors() else: # TODO: check if val has a toDatum field raise TypeError("cannot initialize Datum from '%s'" % type(val).__name__) def __repr__(self): # TODO: Add type-checking to policy. return '' % hex(self.handle) def __int__(self): l = policy.contents.IntFromHandle(self.handle) checkForErrors() return int(l) def __nonzero__(self): # This will throw an exception for anything but an underlying bool # type. Perhaps we should be more pythonic. l = policy.contents.boolFromHandle(self.handle) checkForErrors() assert l in [0,1] return l == 1 def __float__(self): x = policy.contents.doubleFromHandle(self.handle) checkForErrors() return float(x) def __str__(self): return pyStringFromHandle(self.handle) def __getattr__(self, name): field = policy.contents.getField(self.handle, name) checkForErrors() return DatumFromHandle(field) def __getitem__(self, name): assert type(name) == str return self.__getattr__(name) #TODO: raise an IndexError when appropriate. #TODO: implement array indices def __setattr__(self, name, val): # TODO: Resolve setting versus declaring. # One idea: d.x = f or d["x"] = f sets and d["int x()"] = f declares # anew. policy.contents.addField(self.handle, name, ensureDatum(val).handle) checkForErrors() def __setitem__(self, name, val): assert type(name) == str self.__setattr__(name, val) #TODO: raise an IndexError when appropriate. #TODO: implement array indices def __call__(self, *args, **namedArgs): alist = policy.contents.newArguments() checkForErrors() for arg in args: d = ensureDatum(arg) policy.contents.addArgument(alist, "", d.handle, NORMAL_ARG) checkForErrors() for name,arg in namedArgs.items(): d = ensureDatum(arg) policy.contents.addArgument(alist, name, d.handle, NORMAL_ARG) checkForErrors() ret = policy.contents.call(self.handle, alist) checkForErrors() policy.contents.releaseArguments(alist) checkForErrors() if ret != None: return DatumFromHandle(ret) def __add__(self, other): return state.globals()["operator +"](self, other) def __sub__(self, other): return state.globals()["operator -"](self, other) def __mul__(self, other): return state.globals()["operator *"](self, other) def __div__(self, other): return state.globals()["operator /"](self, other) def __truediv__(self, other): return state.globals()["operator /"](self, other) def __mod__(self, other): return state.globals()["operator %"](self, other) def __pow__(self, other): return state.globals()["operator ^"](self, other) def __and__(self, other): return state.globals()["operator &"](self, other) def __or__(self, other): return state.globals()["operator |"](self, other) def __neg__(self, other): return state.globals()["operator -"](self) def __lt__(self, other): return state.globals()["operator <"](self, other) def __le__(self, other): return state.globals()["operator <="](self, other) def __eq__(self, other): return state.globals()["operator =="](self, other) def __ne__(self, other): return state.globals()["operator !="](self, other) def __gt__(self, other): return state.globals()["operator >"](self, other) def __ge__(self, other): return state.globals()["operator >="](self, other) def DatumFromHandle(handle): """Initializes a Datum from a given low-level handle. Does not invoke copyHandle.""" d = Datum(None) d._setHandle(handle) return d class State(object): def __init__(self, base): self.base = base def globals(self): handle = policy.contents.globals(self.base) checkForErrors() return DatumFromHandle(handle) def params(self): p = [] numParams = policy.contents.numParams(self.base) checkForErrors() for i in range(numParams): h = policy.contents.getParam(self.base, i) checkForErrors() p.append(DatumFromHandle(h)) assert len(p) == numParams return p def setReturnValue(self, val): policy.contents.setReturnValue(self.base, ensureDatum(val).handle) checkForErrors() # Keep a link to all of the callbacks created, so they aren't garbage # collected. TODO: See if this is neccessary. storedCallbacks = [] def DatumFromCallable(f): def wrapped(s, d): state = State(s) params = state.params() r = f(*params) if r != None: state.setReturnValue(r) cf = function_typ(wrapped) storedCallbacks.append(cf) h = policy.contents.handleFromFunction(f.__name__, cf, None) checkForErrors() return DatumFromHandle(h) print "version", policy.contents.version state = State(baseState) # An example def runExample(): g = state.globals() g.eval("path p = (0,0) -- (100,100) -- (200,0)", embedded=True) g.draw(g.p) g.shipout("frompython") g.draw(g.circle(100), g.red) asymptote-2.37/asy-list.pl000077500000000000000000000031141265434602500156050ustar00rootroot00000000000000#!/usr/bin/env perl ##### # asy-list.pl # # Build asy-keywords.el from list of asy global functions and variables # ##### open(keywords, "> asy-keywords.el") || die("Couldn't open asy-keywords.el for writing."); print keywords <) { if (/^%%\s*$/) { last; # Break out of the loop. } } while () { if (/^%%\s*$/) { last; # A second %% indicates the end of definitions. } if (/^(\w+)\s*\{/) { add($1); } } openlist(); while () { if (/^(\w*)[^ ]* (\w*)\(.*/) { push @types, $1; push @functions, $2; } if (/^([^ ]*) (\w*);/) { push @variables, $2; } } @saw{@types} = (); @types = sort keys %saw; undef %saw; @saw{@functions} = (); @functions = sort keys %saw; undef %saw; @saw{@variables} = (); @variables = sort keys %saw; undef %saw; print keywords <ÿÿ¬ÿÿÿüÿ5ÿfÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿðÿ§ÿRÿ ÿÊÿÿÿÿÿtÿÿ¬ÿîÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿéÿÿ)ÿÊÿÿÿÿÿwÿ$ÿiÿ¦ÿâÿþÿÿÿÿÿÿÿÿÿÿÿýÿ¤ÿ)ÿÊÿÿÿÿÿwÿ2ÿ…ÿÖÿÿÿÿÿÿÿÿÿÿÿúÿ”ÿÿÊÿÿÿÿÿwÿÿ5ÿ›ÿ÷ÿÿÿÿÿÿÿÿÿåÿQÿ%ÿ%ÿ%ÿ%ÿ%ÿ%ÿ%ÿÑÿÿÿÿÿwÿÿ™ÿøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿwÿÿ¹ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿwÿeÿúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿwÿ8ÿìÿÿÿÿÿÿÿ‘ÿÿÿÿÐÿÿÿÿÿwÿ2ÿìÿÿÿÿÿøÿ>ÿÊÿÿÿÿÿwÿ8ÿúÿÿÿÿÿåÿ ÿÊÿÿÿÿÿwÿoÿÿÿÿÿÿÿ‹ÿÊÿÿÿÿÿwÿ¹ÿÿÿÿÿúÿ)ÿÊÿÿÿÿÿwÿ'ÿøÿÿÿÿÿ¤ÿÊÿÿÿÿÿwÿ™ÿÿÿÿÿýÿàÿÿÿÿÿwÿÿ÷ÿÿÿÿÿÿÿÿÿÿÿwÿ¥ÿÿÿÿÿÿÿÿÿÿÿwÿ?ÿÿÿÿÿÿÿÿÿÿÿwÿÿÛÿÿÿÿÿÿÿÿÿwÿ…ÿÿÿÿÿÿÿÿÿwÿ=ÿÿÿÿÿÿÿÿÿwÿÿîÿÿÿÿÿÿÿwÿ¯ÿÿÿÿÿÿÿwÿsÿÿÿÿÿÿÿwÿ7ÿÿÿÿÿÿÿwÿÿøÿÿÿÿÿtÿ¬ÿÿÿüÿ,ÿ ÿFÿ,ÿÿÿÿÿÿÿÿçÿÿ÷Àÿóøÿóÿƒÿóÿàÿóÿü?óÿÿÿÿ€ÿÿàÿÿñóÿÿùóÿÿüóÿÿüsÿÿþsÿÿÿ3ÿÿÿ3ÿÿÿƒÿÿÿƒÿÿÿƒÿÿÿÃÿÿÿÃÿÿÿÃÿÿÿãÿÿÿãÿÿÿãÿÿÿãÿÿÿóÿÿÿ÷ÿÿÿÿÿÿÿÿasymptote-2.37/asy.rc000066400000000000000000000014021265434602500146200ustar00rootroot00000000000000asy ICON PRELOAD "asy.ico" 1 VERSIONINFO FILEOS 0x40004 FILETYPE 0x1 FILESUBTYPE 0x0 BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "FileDescription", "Vector Graphics Language\0" VALUE "OriginalFilename", "asy.exe\0" VALUE "LegalCopyright", "Copyright \251 2005 Andy Hammerlindl, John Bowman, Tom Prince\0" VALUE "CompanyName", "Andy Hammerlindl, John Bowman, Tom Prince\0" VALUE "ProductName", "Asymptote\0" VALUE "ProductVersion", "ASYMPTOTE_VERSION\0" VALUE "GPL Copyleft", "Released under the GNU General Public License version 2\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 0x04b0 END END asymptote-2.37/asymptote.nsi000066400000000000000000000144731265434602500162520ustar00rootroot00000000000000!define PRODUCT_NAME "Asymptote" !include AsymptoteInstallInfo.nsi !define PRODUCT_WEB_SITE "http://asymptote.sourceforge.net/" !define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\Asymptote" !define PRODUCT_FILE_TYPE_REGKEY1 "Software\Classes\.asy" !define PRODUCT_FILE_TYPE_REGKEY2 "Software\Classes\ASYFile\shell\open\command" !define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" !define PRODUCT_UNINST_ROOT_KEY "HKLM" !define PRODUCT_STARTMENU_REGVAL "NSIS:StartMenuDir" SetCompressor lzma XPStyle On ; MUI 1.67 compatible ------ !include "MUI.nsh" !include "LogicLib.nsh" !include "EnvVarUpdate.nsh" !include "lnkX64IconFix.nsh" ; MUI Settings !define MUI_ABORTWARNING !define MUI_ICON "asy.ico" !define MUI_UNICON "asy.ico" ; Welcome page !insertmacro MUI_PAGE_WELCOME ; License page !insertmacro MUI_PAGE_LICENSE "LICENSE" ;Components page ; don't bother with this until there are other components to install ; e.g.: possibility to automatically detect presence of, download, and install python, miktex, ImageMagick, etc ;!insertmacro MUI_PAGE_COMPONENTS ; Directory page !insertmacro MUI_PAGE_DIRECTORY ; Start menu page var ICONS_GROUP !define MUI_STARTMENUPAGE_NODISABLE !define MUI_STARTMENUPAGE_DEFAULTFOLDER "Asymptote" !define MUI_STARTMENUPAGE_REGISTRY_ROOT "${PRODUCT_UNINST_ROOT_KEY}" !define MUI_STARTMENUPAGE_REGISTRY_KEY "${PRODUCT_UNINST_KEY}" !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "${PRODUCT_STARTMENU_REGVAL}" !insertmacro MUI_PAGE_STARTMENU Application $ICONS_GROUP ; Instfiles page !insertmacro MUI_PAGE_INSTFILES ; Finish page ;!define MUI_FINISHPAGE_RUN "$INSTDIR\asy.bat" ;!define MUI_FINISHPAGE_SHOWREADME "$INSTDIR\asymptote.pdf" !define MUI_FINISHPAGE_LINK ${PRODUCT_WEB_SITE} !define MUI_FINISHPAGE_LINK_LOCATION ${PRODUCT_WEB_SITE} !insertmacro MUI_PAGE_FINISH ; Uninstaller pages !insertmacro MUI_UNPAGE_WELCOME !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES !insertmacro MUI_UNPAGE_FINISH ; Language files !insertmacro MUI_LANGUAGE "English" ; Reserve files !insertmacro MUI_RESERVEFILE_INSTALLOPTIONS ; MUI end ------ Name "${PRODUCT_NAME} ${PRODUCT_VERSION}" OutFile "asymptote-${PRODUCT_VERSION}-setup.exe" InstallDir "$PROGRAMFILES\Asymptote" InstallDirRegKey HKLM "${PRODUCT_DIR_REGKEY}" "" ShowInstDetails show ShowUnInstDetails show Section "Asymptote" SEC01 SetOutPath "$INSTDIR" ${EnvVarUpdate} $0 "PATH" "A" "HKLM" "$INSTDIR" Delete "$INSTDIR\_imagingtk.pyd" SetOverwrite try File /r build-${PRODUCT_VERSION}\* FileOpen $0 $INSTDIR\asy.bat w FileWrite $0 "@ECHO OFF" FileWriteByte $0 "13" FileWriteByte $0 "10" FileWrite $0 "set CYGWIN=nodosfilewarning" FileWriteByte $0 "13" FileWriteByte $0 "10" FileWrite $0 '"$INSTDIR\asy.exe" %*' FileWriteByte $0 "13" FileWriteByte $0 "10" FileWrite $0 "if %errorlevel% == 0 exit /b" FileWriteByte $0 "13" FileWriteByte $0 "10" FileWrite $0 "echo." FileWriteByte $0 "13" FileWriteByte $0 "10" FileWrite $0 "PAUSE" FileWriteByte $0 "13" FileWriteByte $0 "10" FileClose $0 ; Shortcuts !insertmacro MUI_STARTMENU_WRITE_BEGIN Application CreateDirectory "$SMPROGRAMS\$ICONS_GROUP" SetOutPath "%USERPROFILE%" CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\Asymptote.lnk" "$INSTDIR\asy.bat" "" "$INSTDIR\asy.ico" ${lnkX64IconFix} "$SMPROGRAMS\$ICONS_GROUP\Asymptote.lnk" CreateShortCut "$DESKTOP\Asymptote.lnk" "$INSTDIR\asy.bat" "" "$INSTDIR\asy.ico" ${lnkX64IconFix} "$DESKTOP\Asymptote.lnk" CreateShortCut "$DESKTOP\Xasy.lnk" "$INSTDIR\xasy.py" CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\Xasy.lnk" "$INSTDIR\xasy.py" SetOutPath "$INSTDIR" !insertmacro MUI_STARTMENU_WRITE_END SectionEnd Section "Tester" SectionEnd Section -AdditionalIcons !insertmacro MUI_STARTMENU_WRITE_BEGIN Application WriteIniStr "$INSTDIR\${PRODUCT_NAME}.url" "InternetShortcut" "URL" "${PRODUCT_WEB_SITE}" CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\Website.lnk" "$INSTDIR\${PRODUCT_NAME}.url" CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\Uninstall.lnk" "$INSTDIR\uninst.exe" !insertmacro MUI_STARTMENU_WRITE_END SectionEnd Section -Post WriteUninstaller "$INSTDIR\uninst.exe" ;create registry keys with information needed to run asymptote WriteRegStr HKLM "${PRODUCT_DIR_REGKEY}" "" "$INSTDIR\asy.exe" WriteRegStr HKLM "${PRODUCT_DIR_REGKEY}" "Path" "$INSTDIR" WriteRegStr HKLM "${PRODUCT_FILE_TYPE_REGKEY1}" "" "ASYFile" WriteRegStr HKLM "${PRODUCT_FILE_TYPE_REGKEY2}" "" '"$INSTDIR\asy.bat" "%1"' WriteRegDWORD HKLM "SOFTWARE\Cygwin" "heap_chunk_in_mb" 0xFFFFFF00 ReadRegStr $0 HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "CYGWIN" ${If} $0 == "" WriteRegExpandStr HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "CYGWIN" "nodosfilewarning" SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 ${Endif} WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)" WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe" WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\asy.exe" WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}" WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}" SectionEnd Function un.onUninstSuccess HideWindow MessageBox MB_ICONINFORMATION|MB_OK "$(^Name) was successfully removed from your computer." FunctionEnd Section Uninstall !insertmacro MUI_STARTMENU_GETFOLDER "Application" $ICONS_GROUP Delete "$INSTDIR\${PRODUCT_NAME}.url" Delete "$INSTDIR\uninst.exe" !include AsymptoteUninstallList.nsi Delete "$INSTDIR\asy.bat" ${un.EnvVarUpdate} $0 "PATH" "R" "HKLM" "$INSTDIR" RMDir "$INSTDIR" Delete "$SMPROGRAMS\$ICONS_GROUP\Uninstall.lnk" Delete "$SMPROGRAMS\$ICONS_GROUP\Website.lnk" Delete "$DESKTOP\Asymptote.lnk" Delete "$DESKTOP\Xasy.lnk" Delete "$SMPROGRAMS\$ICONS_GROUP\Asymptote.lnk" Delete "$SMPROGRAMS\$ICONS_GROUP\Xasy.lnk" RMDir "$SMPROGRAMS\$ICONS_GROUP" DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" DeleteRegKey HKLM "${PRODUCT_DIR_REGKEY}" DeleteRegKey HKLM "${PRODUCT_FILE_TYPE_REGKEY1}" DeleteRegKey HKLM "${PRODUCT_FILE_TYPE_REGKEY2}" SetAutoClose true SectionEnd asymptote-2.37/asymptote.spec000066400000000000000000000055351265434602500164120ustar00rootroot00000000000000%{!?_texmf: %global _texmf %(eval "echo `kpsewhich -expand-var '$TEXMFLOCAL'`")} Name: asymptote Version: 2.36 Release: 1%{?dist} Summary: Descriptive vector graphics language Group: Applications/Publishing License: GPL URL: http://asymptote.sourceforge.net/ Source: http://downloads.sourceforge.net/sourceforge/asymptote/asymptote-%{version}.src.tgz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: ncurses-devel BuildRequires: readline-devel BuildRequires: fftw-devel >= 3.0 BuildRequires: gc-devel >= 6.7 BuildRequires: gsl-devel BuildRequires: tetex-latex BuildRequires: ghostscript >= 9.14 BuildRequires: texinfo >= 4.7 BuildRequires: ImageMagick Requires: tetex-latex Requires: tkinter Requires: freeglut-devel >= 2.4.0 Requires(post): /usr/bin/texhash /sbin/install-info Requires(postun): /usr/bin/texhash /sbin/install-info %description Asymptote is a powerful descriptive vector graphics language for technical drawings, inspired by MetaPost but with an improved C++-like syntax. Asymptote provides for figures the same high-quality level of typesetting that LaTeX does for scientific text. %prep %setup -q %{__sed} -i 's|^#!/usr/bin/env python$|#!%{__python}|' GUI/xasy.py %build CFLAGS="`echo $RPM_OPT_FLAGS | sed s/-O2/-O3/`" \ %configure --with-latex=%{_texmf}/tex/latex --with-context=%{_texmf}/tex/context/third make %{?_smp_mflags} %install rm -rf $RPM_BUILD_ROOT make install DESTDIR=$RPM_BUILD_ROOT %{__install} -p -m 644 BUGS ChangeLog LICENSE README ReleaseNotes TODO \ $RPM_BUILD_ROOT%{_defaultdocdir}/%{name}/ %clean rm -rf $RPM_BUILD_ROOT %post texhash >/dev/null 2>&1 || : /sbin/install-info %{_infodir}/%{name}/%{name}.info.gz %{_infodir}/dir 2>/dev/null || : %postun texhash >/dev/null 2>&1 || : if [ $1 = 0 ]; then /sbin/install-info --remove %{_infodir}/%{name}/%{name}.info.gz %{_infodir}/dir 2>/dev/null || : fi %files %defattr(-,root,root,-) %doc %{_defaultdocdir}/%{name}/ %{_bindir}/* %{_datadir}/%{name}/ %{_texmf}/tex/latex/%{name} %{_texmf}/tex/context/third/%{name} %{_mandir}/man1/*.1* %{_infodir}/%{name}/ %{_infodir}/%{name}/*.info* %{_infodir}/*.info* %changelog * Thu Apr 19 2007 John Bowman <> - 1.26-1 - Update source tar ball name. * Tue May 30 2006 John Bowman <> - 1.07-1 - Use make install-all to also install info pages. * Fri May 26 2006 Jose Pedro Oliveira - 1.07-1 - Update to 1.07. * Sun May 21 2006 John Bowman <> - 1.06-1 - Update to 1.06. * Mon May 8 2006 John Bowman <> - 1.05-1 - Update to 1.05. * Sun May 7 2006 Jose Pedro Oliveira - 1.04-1 - Update to 1.04. * Fri Mar 31 2006 Jose Pedro Oliveira - 1.03-1 - Update to 1.03. * Thu Mar 23 2006 Jose Pedro Oliveira - 1.02-1 - First build. asymptote-2.37/autogen.sh000077500000000000000000000000421265434602500154760ustar00rootroot00000000000000#!/bin/sh autoheader && autoconf asymptote-2.37/ax_pthread.m4000066400000000000000000000303661265434602500160720ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_pthread.html # =========================================================================== # # SYNOPSIS # # AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) # # DESCRIPTION # # This macro figures out how to build C programs using POSIX threads. It # sets the PTHREAD_LIBS output variable to the threads library and linker # flags, and the PTHREAD_CFLAGS output variable to any special C compiler # flags that are needed. (The user can also force certain compiler # flags/libs to be tested by setting these environment variables.) # # Also sets PTHREAD_CC to any special C compiler that is needed for # multi-threaded programs (defaults to the value of CC otherwise). (This # is necessary on AIX to use the special cc_r compiler alias.) # # NOTE: You are assumed to not only compile your program with these flags, # but also link it with them as well. e.g. you should link with # $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS # # If you are only building threads programs, you may wish to use these # variables in your default LIBS, CFLAGS, and CC: # # LIBS="$PTHREAD_LIBS $LIBS" # CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # CC="$PTHREAD_CC" # # In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant # has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name # (e.g. PTHREAD_CREATE_UNDETACHED on AIX). # # Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the # PTHREAD_PRIO_INHERIT symbol is defined when compiling with # PTHREAD_CFLAGS. # # ACTION-IF-FOUND is a list of shell commands to run if a threads library # is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it # is not found. If ACTION-IF-FOUND is not specified, the default action # will define HAVE_PTHREAD. # # Please let the authors know if this macro fails on any platform, or if # you have any other suggestions or comments. This macro was based on work # by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help # from M. Frigo), as well as ac_pthread and hb_pthread macros posted by # Alejandro Forero Cuervo to the autoconf macro repository. We are also # grateful for the helpful feedback of numerous users. # # Updated for Autoconf 2.68 by Daniel Richard G. # # LICENSE # # Copyright (c) 2008 Steven G. Johnson # Copyright (c) 2011 Daniel Richard G. # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 18 AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) AC_DEFUN([AX_PTHREAD], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_LANG_PUSH([C]) ax_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h # requires special compiler flags (e.g. on True64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) AC_TRY_LINK_FUNC(pthread_join, ax_pthread_ok=yes) AC_MSG_RESULT($ax_pthread_ok) if test x"$ax_pthread_ok" = xno; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" fi # We must check for the threads library under a number of different # names; the ordering is very important because some systems # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). # Create a list of thread flags to try. Items starting with a "-" are # C compiler flags, and other items are library names, except for "none" # which indicates that we try without any flags at all, and "pthread-config" # which is a program returning the flags for the Pth emulation library. ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # pthreads: AIX (must check this before -lpthread) # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) # -pthreads: Solaris/gcc # -mthreads: Mingw32/gcc, Lynx/gcc # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads too; # also defines -D_REENTRANT) # ... -mt is also the pthreads flag for HP/aCC # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) case ${host_os} in solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (We need to link with -pthreads/-mt/ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather # a function called by this macro, so we could check for that, but # who knows whether they'll stub that too in a future libc.) So, # we'll just look for -pthreads and -lpthread first: ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags" ;; darwin*) ax_pthread_flags="-pthread $ax_pthread_flags" ;; esac if test x"$ax_pthread_ok" = xno; then for flag in $ax_pthread_flags; do case $flag in none) AC_MSG_CHECKING([whether pthreads work without any flags]) ;; -*) AC_MSG_CHECKING([whether pthreads work with $flag]) PTHREAD_CFLAGS="$flag" ;; pthread-config) AC_CHECK_PROG(ax_pthread_config, pthread-config, yes, no) if test x"$ax_pthread_config" = xno; then continue; fi PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" ;; *) AC_MSG_CHECKING([for the pthreads library -l$flag]) PTHREAD_LIBS="-l$flag" ;; esac save_LIBS="$LIBS" save_CFLAGS="$CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we # need a special flag -Kthread to make this header compile.) # We check for pthread_join because it is in -lpthread on IRIX # while pthread_create is in libc. We check for pthread_attr_init # due to DEC craziness with -lpthreads. We check for # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. AC_LINK_IFELSE([AC_LANG_PROGRAM([#include static void routine(void *a) { a = 0; } static void *start_routine(void *a) { return a; }], [pthread_t th; pthread_attr_t attr; pthread_create(&th, 0, start_routine, 0); pthread_join(th, 0); pthread_attr_init(&attr); pthread_cleanup_push(routine, 0); pthread_cleanup_pop(0) /* ; */])], [ax_pthread_ok=yes], []) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" AC_MSG_RESULT($ax_pthread_ok) if test "x$ax_pthread_ok" = xyes; then break; fi PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi # Various other checks: if test "x$ax_pthread_ok" = xyes; then save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. AC_MSG_CHECKING([for joinable pthread attribute]) attr_name=unknown for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], [int attr = $attr; return attr /* ; */])], [attr_name=$attr; break], []) done AC_MSG_RESULT($attr_name) if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, [Define to necessary symbol if this constant uses a non-standard name on your system.]) fi AC_MSG_CHECKING([if more special flags are required for pthreads]) flag=no case ${host_os} in aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";; osf* | hpux*) flag="-D_REENTRANT";; solaris*) if test "$GCC" = "yes"; then flag="-D_REENTRANT" else flag="-mt -D_REENTRANT" fi ;; esac AC_MSG_RESULT(${flag}) if test "x$flag" != xno; then PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], ax_cv_PTHREAD_PRIO_INHERIT, [ AC_LINK_IFELSE([ AC_LANG_PROGRAM([[#include ]], [[int i = PTHREAD_PRIO_INHERIT;]])], [ax_cv_PTHREAD_PRIO_INHERIT=yes], [ax_cv_PTHREAD_PRIO_INHERIT=no]) ]) AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"], AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], 1, [Have PTHREAD_PRIO_INHERIT.])) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" # More AIX lossage: must compile with xlc_r or cc_r if test x"$GCC" != xyes; then AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC}) else PTHREAD_CC=$CC fi else PTHREAD_CC="$CC" fi AC_SUBST(PTHREAD_LIBS) AC_SUBST(PTHREAD_CFLAGS) AC_SUBST(PTHREAD_CC) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test x"$ax_pthread_ok" = xyes; then ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) : else ax_pthread_ok=no $2 fi AC_LANG_POP ])dnl AX_PTHREAD asymptote-2.37/base/000077500000000000000000000000001265434602500144135ustar00rootroot00000000000000asymptote-2.37/base/CAD.asy000066400000000000000000000251161265434602500155250ustar00rootroot00000000000000struct sCAD { int nLineGroup = 0; // 0-3 pen // A pA, pVisibleEdge, // Sichtbare Kanten pVisibleContour, // Sichtbarer Umriss pUsableWindingLength, // Nitzbare Gewindelänge pSystemLine, // Systemlinie (Stahlbau) pDiagramCurve, // Kurve in Diagrammen pSurfaceStructure, // Oberflächenstrukturen // B pB, pLightEdge, // Lichtkante pMeasureLine, // Maßlinie pMeasureHelpLine, // Maßhilfslinie pMeasureLineBound, // Maßlinienbegrenzung pReferenceLine, // Hinweislinie pHatch, // Schraffur pWindingGround, // Gewindegrund pDiagonalCross, // Diagonalkreuz pBendLine, // Biegelinie pProjectionLine, // Projektionslinie pGrid, // Rasterlinien // C pC, pFreehand, // Begrenzung abgebrochener oder unterbrochener // Schnitte, wenn die Begrenzung // keine Mittellinie ist // E pE, pSurfaceTreatmentAllowed, // Bereich zulässiger Oberflächenbehandlung // F pF, pInvisibleEdge, // unsichtbare Kante pInvisibleContour, // unsichtbarer Umriss // G pG, pMiddleLine, // Mittellinie pSymmetryLine, // Symmetrielinie pPartialCircle, // Teilkreis pCircularHole, // Lochkreis pDivisionPlane, // Teilungsebene pTransferLine, // Trajektorien (Übertragunslinien) // J pJ, pCuttingPlane, // Schnittebene pSurfaceTreatmentRequested, // Bereich geforderter Behandlungen // K pK, pContourBeforeDeformation, // Umrisse vor Verformung pAdjacentPartContour, // Umrisse angrenzender Teile pEndShapeRawMaterial, // Fertigformen in Rohteilen pContourEligibleType, // Umrisse wahlweiser Ausführungen pPartInFrontOfCuttingPlane; // Teile vor der Schnittebene static sCAD Create(int nLineGroup = 1) { sCAD cad = new sCAD; if ( nLineGroup < 0 ) nLineGroup = 0; if ( nLineGroup > 3 ) nLineGroup = 3; cad.nLineGroup = nLineGroup; restricted real[] dblFullWidth = {0.35mm, 0.5mm, 0.7mm, 1.0mm}; restricted real[] dblHalfWidth = {0.18mm, 0.25mm, 0.35mm, 0.5mm}; pen pFullWidth = linewidth(dblFullWidth[nLineGroup]); pen pHalfWidth = linewidth(dblHalfWidth[nLineGroup]); // Linienarten: // A cad.pA = cad.pVisibleEdge = cad.pVisibleContour = cad.pUsableWindingLength = cad.pSystemLine = cad.pDiagramCurve = cad.pSurfaceStructure = pFullWidth + solid; // B cad.pB = cad.pLightEdge = cad.pMeasureLine = cad.pMeasureHelpLine = cad.pMeasureLineBound = cad.pReferenceLine = cad.pHatch = cad.pWindingGround = cad.pDiagonalCross = cad.pBendLine = cad.pProjectionLine = cad.pGrid = pHalfWidth + solid; // C cad.pC = cad.pFreehand = pHalfWidth + solid; // D // Missing, as I have no idea how to implement this... // E cad.pE = cad.pSurfaceTreatmentAllowed = pFullWidth + linetype(new real[] {10,2.5}); // F cad.pF = cad.pInvisibleEdge = cad.pInvisibleContour = pHalfWidth + linetype(new real[] {20,5}); // G cad.pG = cad.pMiddleLine = cad.pSymmetryLine = cad.pPartialCircle = cad.pCircularHole = cad.pDivisionPlane = cad.pTransferLine = pHalfWidth + linetype(new real[] {40,5,5,5}); // H // see J // I // This letter is not used in DIN 15 // J cad.pJ = cad.pCuttingPlane = cad.pSurfaceTreatmentRequested = pFullWidth + linetype(new real[] {20,2.5,2.5,2.5}); // K cad.pK = cad.pContourBeforeDeformation = cad.pAdjacentPartContour = cad.pEndShapeRawMaterial = cad.pContourEligibleType = cad.pPartInFrontOfCuttingPlane = pHalfWidth + linetype(new real[] {40,5,5,5,5,5}); return cad; } // end of Create real GetMeasurementBoundSize(bool bSmallBound = false) { if ( bSmallBound ) return 1.5 * linewidth(pVisibleEdge) / 2; else return 5 * linewidth(pVisibleEdge); } path GetMeasurementBound(bool bSmallBound = false) { if ( bSmallBound ) return scale(GetMeasurementBoundSize(bSmallBound = bSmallBound)) * unitcircle; else return (0,0) -- (-cos(radians(7.5)), -sin(radians(7.5))) * GetMeasurementBoundSize(bSmallBound = bSmallBound) -- (-cos(radians(7.5)), sin(radians(7.5))) * GetMeasurementBoundSize(bSmallBound = bSmallBound) -- cycle; } void MeasureLine(picture pic = currentpicture, Label L, pair pFrom, pair pTo, real dblLeft = 0, real dblRight = 0, real dblRelPosition = 0.5, bool bSmallBound = false) { if ( dblLeft < 0 ) dblLeft = 0; if ( dblRight < 0 ) dblRight = 0; if ( (dblLeft > 0) && (dblRight == 0) ) dblRight = dblLeft; if ( (dblLeft == 0) && (dblRight > 0) ) dblLeft = dblRight; pair pDiff = pTo - pFrom; real dblLength = length(pDiff); pair pBegin = pFrom - dblLeft * unit(pDiff); pair pEnd = pTo + dblRight * unit(pDiff); if ( bSmallBound ) { draw( pic = pic, g = pBegin--pEnd, p = pMeasureLine); } else { real dblBoundSize = GetMeasurementBoundSize(bSmallBound = bSmallBound); if ( dblLeft == 0 ) draw( pic = pic, g = (pFrom + dblBoundSize/2 * unit(pDiff)) -- (pTo - dblBoundSize/2 * unit(pDiff)), p = pMeasureLine); else draw( pic = pic, g = pBegin -- (pFrom - dblBoundSize/2 * unit(pDiff)) ^^ pFrom -- pTo ^^ (pTo + dblBoundSize/2 * unit(pDiff)) -- pEnd, p = pMeasureLine); } path gArrow = GetMeasurementBound(bSmallBound = bSmallBound); picture picL; label(picL, L); pair pLabelSize = 1.2 * (max(picL) - min(picL)); if ( dblLeft == 0 ) { fill( pic = pic, g = shift(pFrom) * rotate(degrees(-pDiff)) * gArrow, p = pVisibleEdge); fill( pic = pic, g = shift(pTo) * rotate(degrees(pDiff)) * gArrow, p = pVisibleEdge); if ( dblRelPosition < 0 ) dblRelPosition = 0; if ( dblRelPosition > 1 ) dblRelPosition = 1; label( pic = pic, L = rotate(degrees(pDiff)) * L, position = pFrom + dblRelPosition * pDiff + unit(rotate(90)*pDiff) * pLabelSize.y / 2); } else { fill( pic = pic, g = shift(pFrom) * rotate(degrees(pDiff)) * gArrow, p = pVisibleEdge); fill( pic = pic, g = shift(pTo) * rotate(degrees(-pDiff)) * gArrow, p = pVisibleEdge); if ( (dblRelPosition >= 0) && (dblRelPosition <= 1) ) label( pic = pic, L = rotate(degrees(pDiff)) * L, position = pFrom + dblRelPosition * pDiff + unit(rotate(90)*pDiff) * pLabelSize.y / 2); else { // draw label outside if ( dblRelPosition < 0 ) label( pic = pic, L = rotate(degrees(pDiff)) * L, position = pBegin + pLabelSize.x / 2 * unit(pDiff) + unit(rotate(90)*pDiff) * pLabelSize.y / 2); else // dblRelPosition > 1 label( pic = pic, L = rotate(degrees(pDiff)) * L, position = pEnd - pLabelSize.x / 2 * unit(pDiff) + unit(rotate(90)*pDiff) * pLabelSize.y / 2); } } } // end of MeasureLine void MeasureParallel(picture pic = currentpicture, Label L, pair pFrom, pair pTo, real dblDistance, // Variables from MeasureLine real dblLeft = 0, real dblRight = 0, real dblRelPosition = 0.5, bool bSmallBound = false) { pair pDiff = pTo - pFrom; pair pPerpendicularDiff = unit(rotate(90) * pDiff); real dblDistancePlus; if ( dblDistance >= 0 ) dblDistancePlus = dblDistance + 1mm; else dblDistancePlus = dblDistance - 1mm; draw( pic = pic, g = pFrom--(pFrom + dblDistancePlus*pPerpendicularDiff), p = pMeasureHelpLine ); draw( pic = pic, g = pTo--(pTo + dblDistancePlus*pPerpendicularDiff), p = pMeasureHelpLine ); MeasureLine( pic = pic, L = L, pFrom = pFrom + dblDistance * pPerpendicularDiff, pTo = pTo + dblDistance * pPerpendicularDiff, dblLeft = dblLeft, dblRight = dblRight, dblRelPosition = dblRelPosition, bSmallBound = bSmallBound); } // end of MeasureParallel path MakeFreehand(pair pFrom, pair pTo, real dblRelDivisionLength = 12.5, real dblRelDistortion = 2.5, bool bIncludeTo = true) { pair pDiff = pTo - pFrom; pair pPerpendicular = dblRelDistortion * linewidth(pFreehand) * unit(rotate(90) * pDiff); int nNumOfSubDivisions=ceil(length(pDiff) / (dblRelDivisionLength * linewidth(pFreehand))); restricted real[] dblDistortion = {1, -.5, .75, -.25, .25, -1, .5, -.75, .25, -.25}; int nDistortion = 0; guide g; g = pFrom; for ( int i = 1 ; i < nNumOfSubDivisions ; ++i ) { g = g .. (pFrom + pDiff * i / (real)nNumOfSubDivisions + pPerpendicular * dblDistortion[nDistortion]); nDistortion += 1; if ( nDistortion > 9 ) nDistortion = 0; } if ( bIncludeTo ) g = g .. pTo; return g; } // end of MakeFreehand } // end of CAD asymptote-2.37/base/animate.asy000066400000000000000000000000521265434602500165440ustar00rootroot00000000000000usepackage("animate"); import animation; asymptote-2.37/base/animation.asy000066400000000000000000000122371265434602500171150ustar00rootroot00000000000000/***** * animation.asy * Andy Hammerlindl and John Bowman 2005/11/06 * * Produce GIF, inline PDF, or other animations. *****/ // animation delay is in milliseconds real animationdelay=50; typedef frame enclosure(frame); frame NoBox(frame f) { return f; } enclosure BBox(real xmargin=0, real ymargin=xmargin, pen p=currentpen, filltype filltype=NoFill) { return new frame(frame f) { box(f,xmargin,ymargin,p,filltype,above=false); return f; }; } struct animation { picture[] pictures; string[] files; int index; string prefix; bool global; // If true, use a global scaling for all frames; this requires // extra memory since the actual shipout is deferred until all frames have // been generated. void operator init(string prefix="", bool global=true) { prefix=replace(stripdirectory(outprefix(prefix))," ","_"); this.prefix=prefix; this.global=global; } string basename(string prefix=stripextension(prefix)) { return "_"+prefix; } string name(string prefix, int index) { return stripextension(prefix)+"+"+string(index); } private string nextname() { string name=basename(name(prefix,index)); ++index; return name; } void shipout(string name=nextname(), frame f) { string format=nativeformat(); plain.shipout(name,f,format=format,view=false); files.push(name+"."+format); shipped=false; } void add(picture pic=currentpicture, enclosure enclosure=NoBox) { if(global) { ++index; pictures.push(pic.copy()); } else this.shipout(enclosure(pic.fit())); } void purge(bool keep=settings.keep) { if(!keep) { for(int i=0; i < files.length; ++i) delete(files[i]); } } int merge(int loops=0, real delay=animationdelay, string format="gif", string options="", bool keep=settings.keep) { string args="-loop " +(string) loops+" -delay "+(string)(delay/10)+ " -alpha Off -dispose Background "+options; for(int i=0; i < files.length; ++i) args += " " +files[i]; int rc=convert(args,prefix+"."+format,format=format); this.purge(keep); if(rc == 0) animate(file=prefix+"."+format,format=format); else abort("merge failed"); return rc; } void glmovie(string prefix=prefix, projection P=currentprojection) { if(!view() || settings.render == 0) return; fit(prefix,pictures,view=true,P); } // Export all frames with the same scaling. void export(string prefix=prefix, enclosure enclosure=NoBox, bool multipage=false, bool view=false, projection P=currentprojection) { if(pictures.length == 0) return; if(!global) multipage=false; bool inlinetex=settings.inlinetex; if(multipage) settings.inlinetex=false; frame multi; frame[] fits=fit(prefix,pictures,view=false,P); for(int i=0; i < fits.length; ++i) { string s=name(prefix,i); if(multipage) { add(multi,enclosure(fits[i])); newpage(multi); files.push(s+"."+nativeformat()); } else { if(pictures[i].empty3() || settings.render <= 0) this.shipout(s,enclosure(fits[i])); else // 3D frames files.push(s+"."+nativeformat()); } } if(multipage) { plain.shipout(prefix,multi,view=view); settings.inlinetex=inlinetex; } shipped=true; } string load(int frames, real delay=animationdelay, string options="", bool multipage=false) { if(!global) multipage=false; string s="\animategraphics["+options+"]{"+format("%.18f",1000/delay,"C")+ "}{"+basename(); if(!multipage) s += "+"; s += "}{0}{"+string(frames-1)+"}"; return s; } bool pdflatex() { return latex() && pdf(); } string pdf(enclosure enclosure=NoBox, real delay=animationdelay, string options="", bool keep=settings.keep, bool multipage=true) { settings.twice=true; if(settings.inlinetex) multipage=true; if(!global) multipage=false; if(!pdflatex()) abort("inline pdf animations require -tex pdflatex or -tex xelatex"); if(settings.outformat != "") settings.outformat="pdf"; string filename=basename(); string pdfname=filename+".pdf"; if(global) export(filename,enclosure,multipage=multipage); shipped=false; if(!keep) { exitfcn currentexitfunction=atexit(); void exitfunction() { if(currentexitfunction != null) currentexitfunction(); if(multipage || !settings.inlinetex) this.purge(); if(multipage && !settings.inlinetex) delete(pdfname); } atexit(exitfunction); } if(!multipage) delete(pdfname); return load(index,delay,options,multipage); } int movie(enclosure enclosure=NoBox, int loops=0, real delay=animationdelay, string format=settings.outformat == "" ? "gif" : settings.outformat, string options="", bool keep=settings.keep) { if(global) { if(format == "pdf") { export(enclosure,multipage=true,view=true); return 0; } export(enclosure); } return merge(loops,delay,format,options,keep); } } animation operator init() { animation a=animation(); return a; } asymptote-2.37/base/annotate.asy000066400000000000000000000011021265434602500167340ustar00rootroot00000000000000void annotate(picture pic=currentpicture, string title, string text, pair position) { pic.add(new void(frame f, transform t) { position=t*position; label(f,"\special{!/pdfmark where {pop} {userdict /pdfmark /cleartomark load put} ifelse [/Rect["+(string) position.x+" 0 0 "+(string) position.y+"] /Subtype /Text /Name /Comment /Title ("+title+") /Contents ("+text+") /ANN pdfmark}"); },true); draw(pic,position,invisible); } asymptote-2.37/base/asy-init.el000066400000000000000000000004141265434602500164710ustar00rootroot00000000000000(autoload 'asy-mode "asy-mode.el" "Asymptote major mode." t) (autoload 'lasy-mode "asy-mode.el" "hybrid Asymptote/Latex major mode." t) (autoload 'asy-insinuate-latex "asy-mode.el" "Asymptote insinuate LaTeX." t) (add-to-list 'auto-mode-alist '("\\.asy$" . asy-mode)) asymptote-2.37/base/asy-kate.sh000066400000000000000000000200631265434602500164660ustar00rootroot00000000000000#!/bin/sh echo ' ' > asymptote.xml # 1. Change Name of lists in <\list> # 2. tail to get rid of the first lines # 3. building the right line ending # 4-5. kill linebreaks # 6. change spaces into <\item> # 7. Undo change (7.) in 'list name' # 8. do some formatting cat asy-keywords.el | sed 's/^(.*\-\([^\-]*\)\-.*/\n/' | tail -14 | sed 's/ ))/<\/item><\/list>/' | tr '\n' '@' | sed 's/@//g' | sed 's/ /<\/item>/g' | sed 's/list<\/item>name/list name/g' | sed 's/>\n> asymptote.xml echo ' ' >> asymptote.xml asymptote-2.37/base/asy-mode.el000066400000000000000000002130671265434602500164640ustar00rootroot00000000000000;;; asy-mode.el --- Major mode for editing Asymptote source code. ;; Copyright (C) 2006-8 ;; Author: Philippe IVALDI 20 August 2006 ;; Maintainer: John Bowman ;; URL: https://github.com/vectorgraphics/asymptote ;; Version: 1.6 ;; Keywords: language, mode ;;; License: ;; This program is free software ; you can redistribute it and/or modify ;; it under the terms of the GNU Lesser General Public License as published by ;; the Free Software Foundation ; either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, but ;; WITHOUT ANY WARRANTY ; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;; Lesser General Public License for more details. ;; ;; You should have received a copy of the GNU Lesser General Public License ;; along with this program ; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ;;; Commentary ;; Major mode for editing Asymptote source code. ;; INSTALLATION: ;; Place this file (asy-mode.el) and asy-keywords.el in your Emacs load path. ;; Then choose ONE of the following installation methods: ;; * Method 1: ;; Copy and uncomment the following lines to your .emacs initialization file: ;;(autoload 'asy-mode "asy-mode.el" "Asymptote major mode." t) ;;(autoload 'lasy-mode "asy-mode.el" "hybrid Asymptote/Latex major mode." t) ;;(autoload 'asy-insinuate-latex "asy-mode.el" "Asymptote insinuate LaTeX." t) ;;(add-to-list 'auto-mode-alist '("\\.asy$" . asy-mode)) ;; * Method 2: ;; Copy and uncomment the following line to your .emacs initialization file: ;;(require 'asy-mode) ;; Notes: ;; ;; For full functionality the two-mode-mode package should also be installed ;; (http://www.dedasys.com/freesoftware/files/two-mode-mode.el). ;; ;; See also paragraph II of the documentation below to automate asy-insinuate-latex. ;;; Code: (defvar asy-mode-version "1.6") ;;;###autoload (define-derived-mode asy-mode objc-mode "Asymptote" "Emacs mode for editing Asymptote source code. For full functionality the `two-mode-mode' package should also be installed (http://www.dedasys.com/freesoftware/files/two-mode-mode.el). I. This package provides two modes: 1- asy-mode: All the files with the extension '.asy' are edited in this mode, which provides the following features: * Syntax color highlighting; * Compiling and viewing current buffer with the key binding C-c C-c; * Moving cursor to the error by pressing the key F4. * Showing the available function prototypes for the command at the cursor with the key binding C-c ? * Compiling and viewing a TeX document linked with the current buffer (usually a document that includes the output picture). To link a Tex document try 'M-x asy-set-master-tex' follow by C-Return (see descriptions further of the key binding C-Return, C-S-Return, M-Return, M-S-Return etc within 2- lasy-mode) 2- lasy-mode Editing a TeX file that contains Asymptote code is facilitated with the hybrid mode 'lasy-mode'. Toggle lasy-mode with M-x lasy-mode. In this hybrid mode the major mode is LaTeX when the cursor is in LaTeX code and becomes asy-mode when the cursor is between '\\begin{asy}' and '\\end{asy}'. All the features of asy-mode are provided and the key binding C-c C-c of asy-mode compiles and views only the code of the picture where the cursor is. Note that some keys binding are added to the LaTeX-mode-map in lasy-mode if the value of the variable lasy-extra-key is t (the default) . * C-return: compile (if the buffer/file is modified) and view the PostScript output with sequence [latex->[asy->latex]->dvips]->PSviewer * M-return: same with pdf output and with the sequence [pdflatex->[asy->pdflatex]]->PDFviewer * C-M-return: same with pdf output and with the sequence [latex->[asy->latex]->dvips->ps2pdf]->PSviewer * Add the Shift key to the sequence of keys to compile even if the file is not modified. II. To add a menu bar in current 'latex-mode' buffer and activate hot keys, use 'M-x asy-insinuate-latex '. You can automate this feature for all the 'latex-mode' buffers by inserting the five following lines in your .emacs initialization file: (eval-after-load \"latex\" '(progn ;; Add here your personal features for 'latex-mode': (asy-insinuate-latex t) ;; Asymptote globally insinuates Latex. )) You can access this help within Emacs by the key binding C-h f asy-mode BUGS: This package has been tested in: * Linux Debian Etch - GNU Emacs 22.0.50.1 - GNU Emacs 21.4.1 (only basic errors management and basic font-lock features within lasy-mode are supported) * WindowsXP - GNU Emacs 22.0.990.1 (i386-mingw-nt5.1.2600) This package seems to work with XEmacs 21.4 but not all the features are available (in particular syntax highlighting). Report bugs to http://asymptote.sourceforge.net Some variables can be customized: M-x customize-group asymptote ." (setq c++-font-lock-extra-types (cons "true" c++-font-lock-extra-types))) (require 'font-lock) (require 'cc-mode) (require 'cl) ;; Common Lisp extensions for Emacs (require 'compile) (require 'wid-edit) ;;;###autoload (add-to-list 'auto-mode-alist '("\\.asy$" . asy-mode)) (defvar running-xemacs-p (featurep 'xemacs)) (defvar running-unix-p (not (string-match "windows-nt\\|ms-dos" (symbol-name system-type)))) (when running-xemacs-p (defalias 'turn-on-font-lock-if-enabled 'ignore) (defalias 'line-number-at-pos 'line-number) (defvar temporary-file-directory (temp-directory)) (defun replace-regexp-in-string (regexp rep string) (replace-in-string string regexp rep)) ) (when (or (< emacs-major-version 22) running-xemacs-p) ;; Add regexp for parsing the compilation errors of asy (add-to-list 'compilation-error-regexp-alist '("\\(.*?.asy\\): \\(.*?\\)\\.\\(.*?\\):" 1 2 3))) (when (< emacs-major-version 22) (defun line-number-at-pos (&optional pos) "Return (narrowed) buffer line number at position POS. If POS is nil, use current buffer location. Counting starts at (point-min), so the value refers to the contents of the accessible portion of the buffer." (let ((opoint (or pos (point))) start) (save-excursion (goto-char (point-min)) (setq start (point)) (goto-char opoint) (forward-line 0) (1+ (count-lines start (point))))))) (defcustom lasy-extra-key t "* If on, the folowing binding keys are added in lasy-mode : (define-key lasy-mode-map (kbd \"\") 'lasy-view-ps) (define-key lasy-mode-map (kbd \"\") 'asy-master-tex-view-ps-f) (define-key lasy-mode-map (kbd \"\") 'lasy-view-pdf-via-pdflatex) (define-key lasy-mode-map (kbd \"\") 'asy-master-tex-view-pdflatex-f) (define-key lasy-mode-map (kbd \"\") 'lasy-view-pdf-via-ps2pdf) (define-key lasy-mode-map (kbd \"\") 'asy-master-tex-view-ps2pdf-f) If you also want this feature in pure latex-mode, you can set this variable to `nil' and add these lines in your .emacs: (require 'asy-mode) (eval-after-load \"latex\" '(progn (define-key LaTeX-mode-map (kbd \"\") 'lasy-view-ps) (define-key LaTeX-mode-map (kbd \"\") 'asy-master-tex-view-ps-f) (define-key LaTeX-mode-map (kbd \"\") 'lasy-view-pdf-via-pdflatex) (define-key LaTeX-mode-map (kbd \"\") 'asy-master-tex-view-pdflatex-f) (define-key LaTeX-mode-map (kbd \"\") 'lasy-view-pdf-via-ps2pdf) (define-key LaTeX-mode-map (kbd \"\") 'asy-master-tex-view-ps2pdf-f)))" :type 'boolean :group 'asymptote) (defcustom asy-compilation-buffer 'none " 'visible means keep compilation buffer visible ; 'available means keep compilation buffer available in other buffer but not visible; 'none means delete compilation buffer automatically after a *successful* compilation. 'never means don't open any window or buffer attached to the compilation process. If the value is 'never': * Emacs is suspended until the child program returns; * the management of errors is poorer than with other value; * the compilation doesn't modify your current window configuration." :type '(choice (const visible) (const available) (const none) (const never)) :group 'asymptote) (defcustom lasy-ask-about-temp-compilation-buffer t "* If t, ask before visiting a temporary buffer of compilation." :type 'boolean :group 'asymptote) (defcustom lasy-compilation-inline-auto-detection nil "* If t, lasy-mode detects automatically if the option 'inline' is passed to asymptote.sty. In case of 'inline' option, the compilation of a figure separately of the document is processed by rebuilding the preamble and compiling it as a file '.tex' containing only this picture. If nil (the default), the compilation of a figure separately of the document is processed by building a file '.asy', without the features of the LaTeX preamble." :type 'boolean :group 'asymptote) (defcustom asy-command-location "" "* If not in the path, you can put here the name of the directory containing Asy's binary files. this variable must end in /." :type 'directory :group 'asymptote) (defcustom asy-command "asy -V" "* Command invoked to compile a Asymptote file. You can define the location of this command with the variable `asy-command-location'." :type 'string :group 'asymptote) (defcustom lasy-command "asy" "* Command invoked to compile a Asymptote file generated compiling a .tex file. You can define the location of this command with the variable `asy-command-location'." :type 'string :group 'asymptote) (defcustom lasy-latex-command "latex -halt-on-error" "* Command invoked to compile a .tex file with LaTeX." :type 'string :group 'asymptote) (defcustom lasy-pdflatex-command "pdflatex -halt-on-error" "* Command invoked to compile a .tex file with pdflaTex." :type 'string :group 'asymptote) (defcustom lasy-dvips-pre-pdf-command "dvips -Ppdf" "* Command invoked to convert a .dvi file to a temporary .ps file in order to generate a final .pdf file." :type 'string :group 'asymptote) (defcustom lasy-dvips-command "dvips -q" "* Command invoked to convert a .dvi file to a final .ps file." :type 'string :group 'asymptote) (defcustom lasy-ps2pdf-command "ps2pdf14" "* Command invoked to convert a .dvi file to .ps file." :type 'string :group 'asymptote) (defcustom asy-temp-dir temporary-file-directory "*The name of a directory for Asy's temporary files. Such files are generated by functions like `asy-compile' when lasy-mode is enable." :type 'directory :group 'asymptote) (defcustom ps-view-command (if running-unix-p "gv" "") "Command to view a PostScript file generated by compiling a tex file within lasy-mode. This variable is not used when running the Windows OS. See `asy-open-file'." :type 'string :group 'asymptote) (defcustom pdf-view-command (if running-unix-p "xpdf" "") "Command to view a pdf file generated by compiling a tex file within lasy-mode. This variable is not used when running the Windows OS. See `asy-open-file'." :type 'string :group 'asymptote) (defvar asy-TeX-master-file nil "TeX file associate with current asymptote code. This variable must be modified only using the function 'asy-set-master-tex by M-x asy-set-master-tex .") (make-variable-buffer-local 'asy-TeX-master-file) (defvar lasy-compile-tex nil "* Internal use. t if LaTeX compilation come from latex-mode.") (when (fboundp 'font-lock-add-keywords) (if (< max-specpdl-size 2000) (setq max-specpdl-size 2000)) (defun asy-add-function-keywords (function-keywords face-name) (let* ((keyword-list (mapcar #'(lambda (x) (symbol-name x)) function-keywords)) (keyword-regexp (concat "\\<\\(" (regexp-opt keyword-list) "\\)("))) (font-lock-add-keywords 'asy-mode `((,keyword-regexp 1 ',face-name))))) (defun asy-add-variable-keywords (function-keywords face-name) (let* ((keyword-list (mapcar #'(lambda (x) (symbol-name x)) function-keywords)) (keyword-regexp (concat "\\<[0-9]*\\(" (regexp-opt keyword-list) "\\)\\(?:[^(a-zA-Z]\\|\\'\\)"))) (font-lock-add-keywords 'asy-mode `((,keyword-regexp 1 ',face-name))))) ;; External definitions of keywords: ;; asy-function-name and asy-variable-name (if (locate-library "asy-keywords.el") (load "asy-keywords.el") (progn ;; Use dummy keyword definitions if asy-keywords.el is not found: (defvar asy-keyword-name nil) (defvar asy-type-name nil) (defvar asy-function-name nil) (defvar asy-variable-name nil))) (defcustom asy-extra-type-name '() "Extra user type names highlighted with 'font-lock-type-face" :type '(repeat symbol) :group 'asymptote) (defcustom asy-extra-function-name '() "Extra user function names highlighted with 'font-lock-function-name-face" :type '(repeat symbol) :group 'asymptote) (defcustom asy-extra-variable-name '() "Extra user variable names highlighted with 'font-lock-constant-face" :type '(repeat symbol) :group 'asymptote) (asy-add-variable-keywords asy-keyword-name 'font-lock-builtin-face) (asy-add-variable-keywords (nconc asy-type-name asy-extra-type-name) 'font-lock-type-face) (asy-add-function-keywords (nconc asy-function-name asy-extra-function-name) 'font-lock-function-name-face) (asy-add-variable-keywords (nconc asy-variable-name asy-extra-variable-name) 'font-lock-constant-face) (defface asy-environment-face `((t (:underline t :inverse-video t))) "Face used to highlighting the keywords '\\begin{asy}' and '\\end{asy}' within lasy-mode." :group 'asymptote) (font-lock-add-keywords 'asy-mode '(("\\\\begin{asy}.*" . 'asy-environment-face) ("\\\\end{asy}" . 'asy-environment-face))) (defface asy-link-face ;; widget-field-face `((t (:underline t))) "Face used to highlighting the links." :group 'asymptote) (font-lock-add-keywords 'asy-mode '(("\\[.*?\\.asy\\]" . 'asy-link-face))) ) (setq buffers-menu-max-size nil) (setq mode-name "Asymptote") (if running-xemacs-p (defvar asy-menu '("Asy" ["Toggle lasy-mode" lasy-mode :active (and (featurep 'two-mode-mode) two-mode-bool)] ["Compile/View" asy-compile t] ["Go to error" asy-goto-error t] ["Describe command" asy-show-function-at-point t]"--" ("Master TeX file" ["Set/Change value" (asy-set-master-tex) :active (not (and (boundp two-mode-bool) two-mode-bool))] ["Erase value" (asy-unset-master-tex) :active (not (and (boundp two-mode-bool) two-mode-bool))] ("Compile OR View" ["PS" asy-master-tex-view-ps :active t] ["PDF (pdflatex)" asy-master-tex-view-pdflatex :active t] ["PDF (ps2pdf)" asy-master-tex-view-ps2pdf :active t]) ("Compile AND View" ["PS" asy-master-tex-view-ps-f :active t] ["PDF (pdflatex)" asy-master-tex-view-pdflatex-f :active t] ["PDF (ps2pdf)" asy-master-tex-view-ps2pdf-f :active t])) ["Asymptote insinuates globally LaTeX" asy-insinuate-latex-globally :active (not asy-insinuate-latex-globally-p)]"--" ("Debugger Buffer" ["Visible" (setq asy-compilation-buffer 'visible) :style radio :selected (eq asy-compilation-buffer 'visible) :active t] ["Available" (setq asy-compilation-buffer 'available) :style radio :selected (eq asy-compilation-buffer 'available) :active t] ["None" (setq asy-compilation-buffer 'none) :style radio :selected (eq asy-compilation-buffer 'none) :active t] ["Never" (setq asy-compilation-buffer 'never) :style radio :selected (eq asy-compilation-buffer 'never) :active t]) ("Compilation Options" :included (and (featurep 'two-mode-mode) two-mode-bool) ["Enable Automatic Detection of Option" (setq lasy-compilation-inline-auto-detection t) :style radio :selected lasy-compilation-inline-auto-detection :active t] ["Disable Automatic Detection of Option" (setq lasy-compilation-inline-auto-detection nil) :style radio :selected (not lasy-compilation-inline-auto-detection) :active t]) ["Customize" (customize-group "asymptote") :active t] ["Help" (describe-function 'asy-mode) :active t] )) (defvar asy-menu '("Asy" ["Toggle Lasy-Mode" lasy-mode :visible (and (featurep 'two-mode-mode) two-mode-bool)] ["Compile/View" asy-compile t] ["Go to Error" asy-goto-error t] ["Describe Command" asy-show-function-at-point t]"--" ("Master TeX File" ["Set/Change Value" (asy-set-master-tex) :active (not (and (boundp two-mode-bool) two-mode-bool)) :key-sequence nil] ["Erase Value" (asy-unset-master-tex) :active (not (and (boundp two-mode-bool) two-mode-bool)) :key-sequence nil] ("Compile or View" ["PS" asy-master-tex-view-ps :active t] ["PDF (pdflatex)" asy-master-tex-view-pdflatex :active t] ["PDF (ps2pdf)" asy-master-tex-view-ps2pdf :active t]) ("Compile and View" ["PS" asy-master-tex-view-ps-f :active t] ["PDF (pdflatex)" asy-master-tex-view-pdflatex-f :active t] ["PDF (ps2pdf)" asy-master-tex-view-ps2pdf-f :active t])) ["Asymptote Insinuates Globally LaTeX" asy-insinuate-latex-globally :active (not asy-insinuate-latex-globally-p)]"--" ("Debugger Buffer" ["Visible" (setq asy-compilation-buffer 'visible) :style radio :selected (eq asy-compilation-buffer 'visible) :active t :key-sequence nil] ["Available" (setq asy-compilation-buffer 'available) :style radio :selected (eq asy-compilation-buffer 'available) :active t :key-sequence nil] ["None" (setq asy-compilation-buffer 'none) :style radio :selected (eq asy-compilation-buffer 'none) :active t :key-sequence nil] ["Never" (setq asy-compilation-buffer 'never) :style radio :selected (eq asy-compilation-buffer 'never) :active t :key-sequence nil]) ("Compilation Options" :visible (and (featurep 'two-mode-mode) two-mode-bool) ["Enable Automatic Detection of Option" (setq lasy-compilation-inline-auto-detection t) :style radio :selected lasy-compilation-inline-auto-detection :active t :key-sequence nil] ["Disable Automatic Detection of Option" (setq lasy-compilation-inline-auto-detection nil) :style radio :selected (not lasy-compilation-inline-auto-detection) :active t :key-sequence nil]) ["Customize" (customize-group "asymptote") :active t :key-sequence nil] ["Help" (describe-function 'asy-mode) :active t :key-sequence nil] ))) (easy-menu-define asy-mode-menu asy-mode-map "Asymptote Mode Commands" asy-menu) ;; On the hook for XEmacs only. (if running-xemacs-p (add-hook 'asy-mode-hook (lambda () (and (eq major-mode 'asy-mode) (easy-menu-add asy-mode-menu asy-mode-map))))) (defun asy-protect-file-name(Filename) (concat "\"" Filename "\"")) (defun asy-get-temp-file-name(&optional noext) "Get a temp file name for printing." (if running-xemacs-p (concat (make-temp-name asy-temp-dir) (if noext "" ".asy")) (concat (make-temp-file (expand-file-name "asy" asy-temp-dir)) (if noext "" ".asy")))) (defun asy-log-filename() (concat buffer-file-name ".log")) (defun asy-compile() "Compile Asymptote code." (interactive) (if (and (boundp two-mode-bool) two-mode-bool) (lasy-compile) ;; compile asy code in a TeX file. (progn ;; compile asy code in a asy file. (let* ((buffer-base-name (file-name-sans-extension (file-name-nondirectory buffer-file-name))) (asy-compile-command (concat asy-command-location asy-command (if (eq asy-compilation-buffer 'never) " " " -wait ") (asy-protect-file-name buffer-base-name)))) (if (buffer-modified-p) (save-buffer)) (message "%s" asy-compile-command) (asy-internal-compile asy-compile-command t t))))) (defun asy-error-message(&optional P) (let ((asy-last-error (asy-log-field-string (asy-log-filename) 0))) (if (and asy-last-error (not (string= asy-last-error ""))) (message (concat asy-last-error (if P "\nPress F4 to go to error" ""))) (when (and (boundp two-mode-bool) two-mode-bool lasy-run-tex (not (zerop asy-last-compilation-code))) (message "The LaTeX code may be incorrect."))))) (defun asy-log-field-string(Filename Field) "Return field of first line of file filename. Fields are defined as 'field1: field2.field3:field4' . Field=0 <-> all fields" (let ((view-inhibit-help-message t)) (with-temp-buffer (progn (insert-file Filename) (beginning-of-buffer) (if (re-search-forward "^\\(.*?\\): \\(.*?\\)\\.\\(.*?\\):\\(.*\\)$" (point-max) t) (match-string Field) nil))))) (defun asy-next-error(arg reset) (if (> emacs-major-version 21) (next-error arg reset) (next-error arg))) (defun lasy-ask-visit-tem-compilation-buffer() "* Ask before visiting a temporary compilation buffer depending the value of `lasy-ask-about-temp-compilation-buffer'." (if lasy-ask-about-temp-compilation-buffer (y-or-n-p "Visit temporary buffer of compilation ? ") t)) (defun lasy-place-cursor-to-error(Filename li co) (save-excursion (with-temp-buffer (insert-file-contents (if running-unix-p Filename (replace-regexp-in-string "//" ":/" (replace-regexp-in-string "/cygdrive/" "" Filename)))) ;; Not right, ;;;maybe take a look at the code of compilation-find-file (beginning-of-buffer) (next-line (1- (string-to-number li))) (setq line-err (buffer-substring-no-properties (progn (beginning-of-line) (point)) (progn (end-of-line) (point)))))) (beginning-of-buffer) (search-forward line-err) (beginning-of-line) (forward-char (1- (string-to-number co)))) (defun asy-goto-error(&optional arg reset) "Go to point of last error within asy/lasy-mode." (interactive "P") (if (or (eq asy-compilation-buffer 'never) (and (boundp two-mode-bool) two-mode-bool)) (let* ((log-file (asy-log-filename)) (li_ (asy-log-field-string log-file 2)) (co_ (asy-log-field-string log-file 3))) (if (and (boundp two-mode-bool) two-mode-bool) ;; Within Lasy-mode (progn ;; lasy-mode need the compilation of file.tex ;; the error can be in Tex commands or in Asymptote commands (if (eq asy-compilation-buffer 'never) ;; Find error in the log file. (if li_ ;; Asy error found in the log-file (progn (lasy-place-cursor-to-error (asy-log-field-string log-file 1) li_ co_) (asy-error-message)) (message "There is an error in your LaTeX code...")) (if (or running-xemacs-p (< emacs-major-version 22)) (when (lasy-ask-visit-tem-compilation-buffer) (next-error arg)) (let ((msg)) ;; Find error in the compilation buffer (save-excursion (set-buffer (next-error-find-buffer)) (when reset (setq compilation-current-error nil)) (let* ((columns compilation-error-screen-columns) (last 1) (loc (compilation-next-error (or arg 1) nil (or compilation-current-error compilation-messages-start (point-min)))) (end-loc (nth 2 loc)) (marker (point-marker))) (setq compilation-current-error (point-marker) overlay-arrow-position (if (bolp) compilation-current-error (copy-marker (line-beginning-position))) loc (car loc))) (if (re-search-forward "^\\(.*?\\): \\(.*?\\)\\.\\(.*?\\):\\(.*\\)$" (point-max) t) (progn (setq msg (match-string 0) log-file (match-string 1) li_ (match-string 2) co_ (match-string 3))) (error "Not other errors."))) (lasy-place-cursor-to-error log-file li_ co_) (message msg))))) (if li_ ;;Pure asy-mode and compilation with shell-command (progn (goto-line (string-to-number li_)) (forward-char (1- (string-to-number co_))) (asy-error-message)) (progn (message "No error."))))) (asy-next-error arg reset))) (defun asy-grep (Regexp) "Internal function used by asymptote." (let ((Strout "") (case-fold-search-asy case-fold-search)) (progn (beginning-of-buffer) (setq case-fold-search nil) (while (re-search-forward Regexp (point-max) t) (setq Strout (concat Strout (match-string 0) "\n\n"))) (setq case-fold-search case-fold-search-asy) (if (string= Strout "") "No match.\n" Strout)))) (defun asy-widget-open-file-at-pos (widget &optional event) "" (kill-buffer (current-buffer)) (find-file (widget-get widget :follow-link)) (goto-line (string-to-number (widget-get widget :value)))) (defun asy-show-function-at-point() "Show the Asymptote definitions of the command at point." (interactive) (save-excursion (let ((cWord (current-word)) (cWindow (selected-window))) (switch-to-buffer-other-window "*asy-help*") (fundamental-mode) (setq default-directory "/") (if (> emacs-major-version 21) (call-process-shell-command (concat asy-command-location "asy -l --where") nil t nil) (insert (shell-command-to-string "asy -l --where"))) (let ((rHelp (asy-grep (concat "^.*\\b" cWord "(\\(.\\)*?$"))) (tag)(file)(line)) (erase-buffer) (insert rHelp) (beginning-of-buffer) (while (re-search-forward "\\(.*\\): \\([0-9]*\\)\\.\\([0-9]*\\)" (point-max) t) (setq file (match-string 1) line (match-string 2) tag (file-name-nondirectory file)) (widget-create `(file-link :tag ,tag :follow-link ,file :value ,line :action asy-widget-open-file-at-pos )))) (beginning-of-buffer) (while (re-search-forward "\\(.*: [0-9]*\\.[0-9]*\\)" (point-max) t) (replace-match "")) (asy-mode) (use-local-map widget-keymap) (widget-setup) (goto-char (point-min)) (select-window cWindow)))) (add-hook 'asy-mode-hook (lambda () (c-set-style "gnu"); (c-set-offset (quote topmost-intro-cont) 0 nil) (make-local-variable 'c-label-minimum-indentation) (setq c-label-minimum-indentation 0) (when (fboundp 'flyspell-mode) (flyspell-mode -1)) (turn-on-font-lock) (column-number-mode t) )) ;;;###autoload (defun lasy-mode ()) ;;; ************************************ ;;; asy-mode mixed with LaTeX-mode: lasy ;;; ************************************ (if (locate-library "two-mode-mode") (progn (defvar lasy-fontify-asy-p nil "Variable to communicate with `font-lock-unfontify-region'. Internal use, don't set in any fashion.") (setq lasy-fontify-asy-p nil) (eval-after-load "two-mode-mode" '(progn ;; Redefine `two-mode-mode-update-mode' to use regexp. (defun two-mode-mode-update-mode () "Redefined in `asy-mode.el' to use regexp" (when (and two-mode-bool two-mode-update) (setq two-mode-update 0) (let ((mode-list second-modes) (flag 0)) (while mode-list (let ((mode (car mode-list)) (lm -1) (rm -1)) (save-excursion (if (search-backward-regexp (cadr mode) nil t) (setq lm (point)) (setq lm -1))) (save-excursion (if (search-backward-regexp (car (cddr mode)) nil t) (setq rm (point)) (setq rm -1))) (if (and (not (and (= lm -1) (= rm -1))) (>= lm rm)) (progn (setq flag 1) (setq mode-list '()) (two-mode-change-mode (car mode) (car (cdr (cddr mode))))))) (setq mode-list (cdr mode-list))) (if (= flag 0) (two-mode-change-mode (car default-mode) (cadr default-mode)))))) (defun two-mode-change-mode (to-mode func) "Redefined in asy-mode. Change the variable `lasy-fontify-asy-p' according to the value of func and the current mode." (if (string= to-mode mode-name) t (progn (setq lasy-fontify-asy-p (eq func 'asy-mode)) (funcall func) (hack-local-variables) (two-mode-mode-setup) (if two-mode-switch-hook (run-hooks 'two-mode-switch-hook)) (if (eq font-lock-mode t) (font-lock-fontify-buffer)) (turn-on-font-lock-if-enabled)))) )) (require 'two-mode-mode) (defun lasy-mode () "Treat, in some cases, the current buffer as a literal Asymptote program." (interactive) (save-excursion (let ((prefix (progn (goto-char (point-max)) (re-search-backward "^\\([^\n]+\\)Local Variables:" (- (point-max) 3000) t) (match-string 1))) (pos-b (point))) (when (and prefix (progn (re-search-forward (regexp-quote (concat prefix "End:")) (point-max) t) (re-search-backward (concat "\\(" prefix "mode: .*\\)") pos-b t)) ) (error (concat "lasy-mode can not work if a mode is specified as local file variable. You should remove the line " (int-to-string (line-number-at-pos))))))) (set (make-local-variable 'asy-insinuate-latex-p) asy-insinuate-latex-p) (make-local-variable 'lasy-fontify-asy-p) (when (< emacs-major-version 22) (make-local-variable 'font-lock-keywords-only)) (setq default-mode '("LaTeX" latex-mode) second-modes '(("Asymptote" "^\\\\begin{asy}.*$" "^\\\\end{asy}" asy-mode))) (if two-mode-bool (progn (latex-mode) (asy-insinuate-latex)) (progn (two-mode-mode) ))) (when (not running-xemacs-p) (defadvice TeX-command-master (around asy-choose-compile act) "Hack to circumvent the preempt of 'C-c C-c' by AucTeX within `lasy-mode'." (if (string-match "asymptote" (downcase mode-name)) (asy-compile) ad-do-it))) (add-hook 'two-mode-switch-hook (lambda () (if (eq major-mode 'latex-mode) (progn ;; Switch to latex-mode ;; Disable LaTeX-math-Mode within lasy-mode (because of incompatibility) (when LaTeX-math-mode (LaTeX-math-mode -1)) (asy-insinuate-latex) (when (< emacs-major-version 22) (setq font-lock-keywords-only nil))) (progn ;; Switch to asy-mode (when (< emacs-major-version 22) (setq font-lock-keywords-only t)) )))) ;; (setq two-mode-switch-hook nil) ;; Solve a problem restoring a TeX file via desktop.el previously in lasy-mode. (if (boundp 'desktop-buffer-mode-handlers) (progn (defun asy-restore-desktop-buffer (desktop-b-f-name d-b-n d-b-m) (find-file desktop-b-f-name)) (add-to-list 'desktop-buffer-mode-handlers '(asy-mode . asy-restore-desktop-buffer)))) ;; Functions and 'advises' to restrict 'font-lock-unfontify-region' ;; and 'font-lock-fontify-syntactically-region' within lasy-mode ;; Special thanks to Olivier Ramaré for his help. (when (and (fboundp 'font-lock-add-keywords) (> emacs-major-version 21)) (defun lasy-mode-at-pos (pos &optional interior strictly) "If point at POS is in an asy environment return the list (start end)." (save-excursion (save-match-data (goto-char pos) (let* ((basy (progn (unless strictly (end-of-line)) (when (re-search-backward "^\\\\begin{asy}" (point-min) t) (when interior (next-line)) (point)))) (easy (and basy (progn (when (re-search-forward "^\\\\end{asy}" (point-max) t) (when interior (previous-line)(beginning-of-line)) (point)))))) (and basy easy (> pos (- basy (if interior 12 0))) (< pos (+ easy (if interior 10 0))) (list basy easy)))))) (defun lasy-region (start end &optional interior) "If the region 'start to end' contains the beginning or the end of an asy environment return the list of points where the asy environment starts and ends." (let* ((beg (min start end)) (lim (max start end))) (or (lasy-mode-at-pos beg interior) (save-match-data (save-excursion (goto-char beg) (and (re-search-forward "^\\\\begin{asy}" lim t) (lasy-mode-at-pos (point) interior))))))) (defun lasy-tags (start end) "Return associated list of points where the tags starts and ends restricted to the region (start end). \"b\" associated with (start-beginTag end-beginTag), \"e\" associated with (start-endTag end-endTag)." (let* ((beg (min start end)) (lim (max start end)) out) (save-excursion (goto-char beg)(beginning-of-line) (while (when (re-search-forward "^\\\\begin{asy}.*" lim t) (push (list (progn (beginning-of-line)(point)) (progn (end-of-line)(point))) out))) (goto-char beg)(beginning-of-line) (while (when (re-search-forward "^\\\\end{asy}" lim t) (push (list (progn (beginning-of-line)(point)) (progn (end-of-line)(point))) out))) out))) (defun lasy-restrict-region (start end &optional interior) "If the region 'start to end' contains the beginning or the end of an asy environment, returns the list of points wich restricts the region to the asy environment. Else, return (start end)." (let* ((beg (min start end)) (lim (max start end)) (be (if (lasy-mode-at-pos beg) beg (or (save-excursion (goto-char beg) (when (re-search-forward "^\\\\begin{asy}.*" lim t) (unless interior (beginning-of-line)) (point))) beg))) (en (or (save-excursion (goto-char be) (when (re-search-forward "^\\\\end{asy}" lim t) (when interior (beginning-of-line)) (point))) lim))) (list be en))) (defun lasy-parse-region (start end) "Return a list ((a (start1 end1)) (b (start2 end2)) [...]). where a, b, ... are nil or t; t means the region from 'startX' through 'endX' (are points) is in a asy environnement." (let (regasy out rr brr err tags) (save-excursion (goto-char start) (while (< (point) end) (setq regasy (lasy-region (point) end)) (if regasy (progn (setq rr (lasy-mode-at-pos (point))) (setq brr (and rr (nth 0 rr)) err (and rr (nth 1 rr))) (if rr (progn (push (list t (list (max 1 (1- (point))) (min end err))) out) (goto-char (min end err))) (progn (push (list nil (list (point) (nth 0 regasy))) out) (goto-char (1+ (nth 0 regasy)))))) (progn (push (list nil (list (min (1+ (point)) end) end)) out) (goto-char end))) )) ;; Put start and end of tag in latex fontification. (setq tags (lasy-tags start end)) (dolist (tag tags) (push (list nil tag) out)) (reverse out))) (defadvice font-lock-unfontify-region (around asy-font-lock-unfontify-region (beg end)) (if two-mode-bool (let ((rstate (lasy-parse-region beg end)) curr reg asy-fontify latex-fontify) (while (setq curr (pop rstate)) (setq reg (nth 1 curr)) (setq asy-fontify (and (nth 0 curr) lasy-fontify-asy-p) latex-fontify (and (not (nth 0 curr)) (not lasy-fontify-asy-p))) (when (or asy-fontify latex-fontify) (setq beg (nth 0 reg) end (nth 1 reg)) (save-excursion (save-restriction (narrow-to-region beg end) ad-do-it (widen)))))) ad-do-it)) (ad-activate 'font-lock-unfontify-region) ;; (ad-deactivate 'font-lock-unfontify-region) (defadvice font-lock-fontify-syntactically-region (around asy-font-lock-fontify-syntactically-region (start end &optional loudly)) (if (and two-mode-bool (eq major-mode 'asy-mode)) (let*((reg (lasy-restrict-region start end))) (save-restriction (setq start (nth 0 reg) end (nth 1 reg)) (narrow-to-region start end) (condition-case nil ad-do-it (error nil)) (widen) )) ad-do-it)) (ad-activate 'font-lock-fontify-syntactically-region) ;; (ad-deactivate 'font-lock-fontify-syntactically-region) (defadvice font-lock-default-fontify-region (around asy-font-lock-default-fontify-region (beg end loudly)) (if two-mode-bool (let ((rstate (lasy-parse-region beg end)) asy-fontify latex-fontify curr reg) (while (setq curr (pop rstate)) (setq reg (nth 1 curr)) (setq asy-fontify (and (nth 0 curr) lasy-fontify-asy-p) latex-fontify (and (not (nth 0 curr)) (not lasy-fontify-asy-p))) (when (or asy-fontify latex-fontify) (setq beg (nth 0 reg) end (nth 1 reg)) (save-excursion (save-restriction (narrow-to-region beg end) (condition-case nil ad-do-it (error nil)) (widen) ))))) ad-do-it)) (ad-activate 'font-lock-default-fontify-region) ;; (ad-deactivate 'font-lock-default-fontify-region) )) (progn (defvar two-mode-bool nil) (defun lasy-mode () (message "You must install the package two-mode-mode.el.")))) (setq asy-latex-menu-item '(["Toggle lasy-mode" lasy-mode :active (featurep 'two-mode-mode)] ["View asy picture near cursor" lasy-compile :active t]"--" ("Compile OR View" ["PS" lasy-view-ps :active t] ["PDF (pdflatex)" lasy-view-pdf-via-pdflatex :active t] ["PDF (ps2pdf)" lasy-view-pdf-via-ps2pdf :active t]) ("Compile AND View" ["PS" asy-master-tex-view-ps-f :active t] ["PDF (pdflatex)" asy-master-tex-view-pdflatex-f :active t] ["PDF (ps2pdf)" asy-master-tex-view-ps2pdf-f :active t])"--" ["Asymptote insinuates globally LaTeX" asy-insinuate-latex-globally :active (not asy-insinuate-latex-globally-p)] ("Disable Asymptote insinuate Latex" ["locally" asy-no-insinuate-locally :active t] ["globally" asy-no-insinuate-globally :active t]) ("Debugger Buffer" ["Visible" (setq asy-compilation-buffer 'visible) :style radio :selected (eq asy-compilation-buffer 'visible) :active t] ["Available" (setq asy-compilation-buffer 'available) :style radio :selected (eq asy-compilation-buffer 'available) :active t] ["None" (setq asy-compilation-buffer 'none) :style radio :selected (eq asy-compilation-buffer 'none) :active t] ["Never" (setq asy-compilation-buffer 'never) :style radio :selected (eq asy-compilation-buffer 'never) :active t]) )) (if running-xemacs-p (setq asy-latex-menu-item (nconc '("Asymptote") asy-latex-menu-item)) (setq asy-latex-menu-item (nconc '("Asymptote" :visible asy-insinuate-latex-p) asy-latex-menu-item))) (defun asy-insinuate-latex-maybe () "This function is added to `LaTeX-mode-hook' to define the environment 'asy' and, eventually, set its indentation. For internal use only." (when (or asy-insinuate-latex-globally-p (save-excursion (beginning-of-buffer) (save-match-data (search-forward "\\begin{asy}" nil t)))) (asy-insinuate-latex)) (LaTeX-add-environments '("asy" (lambda (env &rest ignore) (unless asy-insinuate-latex-p (asy-insinuate-latex)) (LaTeX-insert-environment env))))) ;; (add-hook 'after-init-hook ;; (lambda () (eval-after-load "latex" '(progn (add-hook 'LaTeX-mode-hook 'asy-insinuate-latex-maybe) (setq lasy-mode-map (copy-keymap LaTeX-mode-map)) (setq LaTeX-mode-map-backup (copy-keymap LaTeX-mode-map)) (defadvice TeX-add-local-master (after asy-adjust-local-variable ()) "Delete the line that defines the mode in a file .tex because two-mode-mode reread the local variables after switching mode." (when (string= (file-name-extension buffer-file-name) "tex") (save-excursion (goto-char (point-max)) (delete-matching-lines "mode: latex" (re-search-backward "^\\([^\n]+\\)Local Variables:" (- (point-max) 3000) t) (re-search-forward (regexp-quote (concat (match-string 1) "End:"))) nil)))) (ad-activate 'TeX-add-local-master) ;; (ad-deactivate 'TeX-add-local-master) (when lasy-extra-key (define-key lasy-mode-map (kbd "") (lambda () (interactive) (lasy-view-ps nil nil t))) (define-key lasy-mode-map (kbd "") (lambda () (interactive) (lasy-view-ps t nil t))) (define-key lasy-mode-map (kbd "") (lambda () (interactive) (lasy-view-pdf-via-pdflatex nil nil t))) (define-key lasy-mode-map (kbd "") (lambda () (interactive) (lasy-view-pdf-via-pdflatex t nil t))) (define-key lasy-mode-map (kbd "") (lambda () (interactive) (lasy-view-pdf-via-ps2pdf nil nil t))) (define-key lasy-mode-map (kbd "") (lambda () (interactive) (lasy-view-pdf-via-ps2pdf t nil t))) (define-key lasy-mode-map (kbd "") 'asy-goto-error)) (easy-menu-define asy-latex-mode-menu lasy-mode-map "Asymptote insinuates LaTeX" asy-latex-menu-item) )) ;; )) (defvar asy-insinuate-latex-p nil "Not nil when current buffer is insinuated by Asymptote. May be a local variable. For internal use.") (defvar asy-insinuate-latex-globally-p nil "Not nil when all latex-mode buffers is insinuated by Asymptote. For internal use.") (defun asy-set-latex-asy-indentation () "Set the indentation of environnment 'asy' like the environnment 'verbatim' is." ;; Regexp matching environments with indentation at col 0 for begin/end. (set (make-local-variable 'LaTeX-verbatim-regexp) (concat (default-value 'LaTeX-verbatim-regexp) "\\|asy")) ;; Alist of environments with special indentation. (make-local-variable 'LaTeX-indent-environment-list) (add-to-list 'LaTeX-indent-environment-list '("asy" current-indentation))) (defun asy-unset-latex-asy-indentation () "Unset the indentation of environnment 'asy' like the environnment 'verbatim' is." (set (make-local-variable 'LaTeX-verbatim-regexp) (default-value 'LaTeX-verbatim-regexp)) (set (make-local-variable 'LaTeX-indent-environment-list) (default-value 'LaTeX-indent-environment-list))) (defun asy-no-insinuate-locally () (interactive) (set (make-local-variable 'asy-insinuate-latex-p) nil) (setq asy-insinuate-latex-globally-p nil) (asy-unset-latex-asy-indentation) (if running-xemacs-p (easy-menu-remove-item nil nil "Asymptote") (menu-bar-update-buffers)) (if (and (boundp 'two-mode-bool) two-mode-bool) (lasy-mode)) (use-local-map LaTeX-mode-map-backup)) (defun asy-no-insinuate-globally () (interactive) (if running-xemacs-p (easy-menu-remove-item nil nil "Asymptote") (easy-menu-remove-item LaTeX-mode-map nil "Asymptote")) (kill-local-variable asy-insinuate-latex-p) (setq-default asy-insinuate-latex-p nil) (setq asy-insinuate-latex-globally-p nil) (if (not running-xemacs-p) (menu-bar-update-buffers)) (setq LaTeX-mode-map (copy-keymap LaTeX-mode-map-backup)) ;;Disable lasy-mode in all latex-mode buffers. (when (featurep 'two-mode-mode) (mapc (lambda (buffer) (with-current-buffer buffer (when (and (buffer-file-name) (string= (file-name-extension (buffer-file-name)) "tex")) (asy-unset-latex-asy-indentation) (latex-mode) (setq asy-insinuate-latex-p nil)))) (buffer-list)))) ;;;###autoload (defun asy-insinuate-latex (&optional global) "Add a menu bar in current 'latex-mode' buffer and activate asy keys bindings. If the optional parameter (only for internal use) 'global' is 't' then all the FUTURE 'latex-mode' buffers are insinuated. To insinuate all (current and future) 'latex-mode' buffers, use 'asy-insinuate-latex-globally' instead. You can automate this feature for all the 'latex-mode' buffers by inserting the five following lines in your .emacs initialization file: (eval-after-load \"latex\" '(progn ;; Add here your personal features for 'latex-mode': (asy-insinuate-latex t) ;; Asymptote insinuates globally Latex. ))" (interactive) (if (and (not asy-insinuate-latex-globally-p) (or global (string= major-mode "latex-mode"))) (progn (asy-set-latex-asy-indentation) (if global (progn (setq asy-insinuate-latex-p t) (setq asy-insinuate-latex-globally-p t) (setq LaTeX-mode-map (copy-keymap lasy-mode-map)) (if running-xemacs-p (add-hook 'LaTeX-mode-hook (lambda () (if asy-insinuate-latex-globally-p (easy-menu-add asy-latex-mode-menu lasy-mode-map)))))) (progn (use-local-map lasy-mode-map) (easy-menu-add asy-latex-mode-menu lasy-mode-map) (set (make-local-variable 'asy-insinuate-latex-p) t))) ))) (defun asy-insinuate-latex-globally () "Insinuates all (current and future) 'latex-mode' buffers. See `asy-insinuate-latex'." (interactive) (asy-insinuate-latex t) (if running-xemacs-p (add-hook 'LaTeX-mode-hook (lambda () (if asy-insinuate-latex-globally-p (easy-menu-add asy-latex-mode-menu lasy-mode-map))))) (mapc (lambda (buffer) (with-current-buffer buffer (when (and (buffer-file-name) (string= (file-name-extension (buffer-file-name)) "tex")) (setq asy-insinuate-latex-p t) (use-local-map LaTeX-mode-map) (use-local-map lasy-mode-map) (asy-set-latex-asy-indentation) (easy-menu-add asy-latex-mode-menu lasy-mode-map)))) (buffer-list))) (defun lasy-inline-p() "Return nil if the option 'inline' is not used or if `lasy-compilation-inline-auto-detection' value is nil." (if lasy-compilation-inline-auto-detection (save-excursion (re-search-backward "^[^%]* *\\\\usepackage\\[ *inline *\\]{ *asymptote *}" 0 t)) nil)) (defvar lasy-run-tex nil) (defun lasy-asydef() "Return the content between the tags \\begin{asydef} and \\end{asydef}." (save-excursion (if (re-search-backward "\\\\begin{asydef}" 0 t) (buffer-substring (progn (next-line)(beginning-of-line)(point)) (progn (re-search-forward "\\\\end{asydef}") (previous-line)(end-of-line) (point))) ""))) (defun lasy-compile-tex() "Compile region between \\begin{asy}[text with backslash] and \\end{asy} through a reconstructed file .tex." (interactive) (setq lasy-run-tex t) (save-excursion (let* ((Filename (asy-get-temp-file-name t)) (FilenameTex (concat Filename ".tex")) (asydef (lasy-asydef))) (save-excursion (beginning-of-buffer) (write-region (point) (progn (re-search-forward "\\\\begin{document}.*\n") (point)) FilenameTex) (write-region (concat "\\begin{asydef}\n" asydef "\n\\end{asydef}\n") 0 FilenameTex t)) (re-search-backward "\\\\begin{asy}") (write-region (point) (progn (re-search-forward "\\\\end{asy}") (point)) FilenameTex t) (with-temp-file FilenameTex (insert-file FilenameTex) (end-of-buffer) (insert "\n\\end{document}")) (let ((default-directory asy-temp-dir)) (lasy-view-ps t Filename))))) (defun lasy-compile() "Compile region between \\begin{asy} and \\end{asy}." (interactive) (if (or (lasy-inline-p) (progn ;; find \begin{asy}[any backslash] (save-excursion (re-search-forward "\\\\end{asy}" (point-max) t) (re-search-backward "\\\\begin{asy}.*\\(\\[.*\\\\.*\\]\\)" 0 t)) (match-string 1))) (progn (lasy-compile-tex)) ;; a temporary TeX file must be reconstructed. (progn (setq lasy-run-tex nil) (save-excursion (let ((Filename (asy-get-temp-file-name)) (asydef (lasy-asydef))) (write-region (match-string 0) 0 Filename) (re-search-backward "\\\\begin{asy}") (write-region (point) (progn (re-search-forward "\\\\end{asy}") (point)) Filename) (with-temp-file Filename (insert-file-contents Filename) (beginning-of-buffer) (if (re-search-forward "\\\\begin{asy}\\[\\(.*\\)\\]" (point-max) t) (let ((sz (match-string 1))) (replace-match "") (insert (concat asydef "\nsize(" sz ");"))) (when (re-search-forward "\\\\begin{asy}" (point-max) t) (replace-match "") (insert asydef))) (while (re-search-forward "\\\\end{asy}" (point-max) t) (replace-match ""))) (let* ((asy-compile-command (concat asy-command-location asy-command (if (eq asy-compilation-buffer 'never) " " " -wait ") (asy-protect-file-name Filename)))) (asy-internal-compile asy-compile-command t (not (eq asy-compilation-buffer 'never))))))))) (defun asy-set-master-tex () "Set the local variable 'asy-TeX-master-file. This variable is used by 'asy-master-tex-view-ps" (interactive) (set (make-local-variable 'asy-TeX-master-file) (file-name-sans-extension (file-relative-name (expand-file-name (read-file-name "TeX document: "))))) (if (string= (concat default-directory asy-TeX-master-file) (file-name-sans-extension buffer-file-name)) (prog1 (set (make-local-variable 'asy-TeX-master-file) nil) (error "You should never give the same name to the TeX file and the Asymptote file")) (save-excursion (end-of-buffer) (if (re-search-backward "asy-TeX-master-file\\(.\\)*$" 0 t) (replace-match (concat "asy-TeX-master-file: \"" asy-TeX-master-file "\"")) (insert (concat " /// Local Variables: /// asy-TeX-master-file: \"" asy-TeX-master-file "\" /// End:")) t)))) (defun asy-unset-master-tex () "Set the local variable 'asy-TeX-master-file to 'nil. This variable is used by 'asy-master-tex-view-ps" (interactive) (set (make-local-variable 'asy-TeX-master-file) nil) (save-excursion (end-of-buffer) (if (re-search-backward "^.*asy-TeX-master-file:.*\n" 0 t) (replace-match "")))) (defun asy-master-tex-error () "Asy-mode internal use..." (if (y-or-n-p "You try to compile the TeX document that contains this picture. You must set the local variable asy-TeX-master-file. Do you want set this variable now ?") (asy-set-master-tex) nil)) (defun asy-master-tex-view (Func-view &optional Force fromtex) "Compile the LaTeX document that contains the picture of the current Asymptote code with the function Func-view. Func-view can be one of 'lasy-view-ps, 'lasy-view-pdf-via-pdflatex, 'lasy-view-pdf-via-ps2pdf." (interactive) (if (or (and (boundp two-mode-bool) two-mode-bool) (string-match "latex" (downcase mode-name))) (progn ;; Current mode is lasy-mode or latex-mode not asy-mode (funcall Func-view Force nil fromtex)) (if asy-TeX-master-file (if (string= asy-TeX-master-file (file-name-sans-extension buffer-file-name)) (error "You should never give the same name to the TeX file and the Asymptote file") (funcall Func-view Force asy-TeX-master-file fromtex)) (if (asy-master-tex-error) (funcall Func-view Force asy-TeX-master-file fromtex))))) (defvar asy-last-compilation-code nil "Code returned by the last compilation with `compile'.") (defvar asy-compilation-auto-close nil "Variable to communicate with `asy-compilation-finish-function'. Do not set this variable in any fashion.") (defun asy-compilation-finish-function (buf msg) "Function to automatically close the compilation buffer '*asy-compilation*' when no error or warning occurs." (when (string-match "*asy-compilation*" (buffer-name buf)) (when (and asy-compilation-auto-close (eq asy-compilation-buffer 'none)) (setq asy-compilation-auto-close nil) (if (not (string-match "exited abnormally" msg)) (progn (save-excursion (set-buffer buf) (beginning-of-buffer) (if (not (search-forward-regexp "[wW]arning" nil t)) (when (not (eq asy-compilation-buffer 'visible)) ;;no errors/Warning, make the compilation window go away (run-at-time 0.5 nil (lambda (buf_) (delete-windows-on buf_) (kill-buffer buf_)) buf) (message (replace-regexp-in-string "\n" "" msg))) (message "Compilation warnings...")))))))) (if running-xemacs-p (setq compilation-finish-function 'asy-compilation-finish-function) (add-to-list 'compilation-finish-functions 'asy-compilation-finish-function)) (defun asy-compilation-wait(&optional pass auto-close) "Wait for process in *asy-compilation* exits. If pass is 't' don't wait. If auto-close is 't' close the window if the process exit with success." (setq asy-compilation-auto-close auto-close) (let* ((buff (get-buffer "*asy-compilation*")) (comp-proc (get-buffer-process buff))) (while (and comp-proc (not (eq (process-status comp-proc) 'exit)) (not pass)) (setq comp-proc (get-buffer-process buff)) (sit-for 1) (message "Waiting process...") ;; need message in Windows system ) (message "") ;; Erase previous message. (if (and (not pass) comp-proc) (setq asy-last-compilation-code (process-exit-status comp-proc)) (setq asy-last-compilation-code 0)) (when (and (eq asy-compilation-buffer 'available) (zerop asy-last-compilation-code)) (delete-windows-on buff)))) (defun asy-internal-shell (command &optional pass) "Execute 'command' in a inferior shell discarding output and redirecting stderr in the file given by the command `asy-log-filename'. `asy-internal-shell' waits for PROGRAM to terminate and returns a numeric exit status. The variable `asy-last-compilation-code' is always set to the exit status. The optional argument pass, for compatibility, is not used." (let* ((log-file (asy-log-filename)) (discard (if pass 0 nil)) (status (progn (let ((view-inhibit-help-message t))(write-region "" 0 log-file nil)) (message "%s" command) (call-process shell-file-name nil (list nil log-file) nil shell-command-switch command)))) (setq asy-last-compilation-code (if status status 0)) (if status status nil))) ;; (defun asy-internal-shell (command &optional pass) ;; "Execute 'command' in a inferior shell discarding output and ;; redirecting stderr in the file given by the command `asy-log-filename'. ;; pass non-nil means `asy-internal-shell' returns immediately with nil value. ;; Otherwise it waits for PROGRAM to terminate and returns a numeric exit status. ;; The variable `asy-last-compilation-code' is always set to the exit status or 0 if the ;; process returns immediately." ;; (let* ((log-file (asy-log-filename)) ;; (discard (if pass 0 nil)) ;; (status ;; (progn ;; (let ((inhibit-redisplay t))(write-region "" 0 log-file nil)) ;; (message "%s" command) ;; (call-process shell-file-name nil (list discard log-file) nil shell-command-switch command)))) ;; (setq asy-last-compilation-code (if status status 0)) ;; (when pass (sit-for 1)) ;; (if status status nil))) (defun asy-internal-compile (command &optional pass auto-close stderr) "Execute command. pass non-nil means don't wait the end of the process. auto-close non-nil means automatically close the compilation buffer. stderr non-nil means redirect the standard output error to the file returned by `asy-log-filename'. In this case command is running in an inferior shell without any output and the parameter auto-close is not used (see `asy-internal-shell')." (setq asy-last-compilation-code -1) (let* ((compilation-buffer-name "*asy-compilation*") (compilation-buffer-name-function (lambda (mj) compilation-buffer-name))) (if (or stderr (eq asy-compilation-buffer 'never)) (progn (asy-internal-shell command pass) (asy-error-message t)) (progn (let ((comp-proc (get-buffer-process compilation-buffer-name))) (if comp-proc (condition-case () (progn (interrupt-process comp-proc) (sit-for 1) (delete-process comp-proc) (when (and asy-compilation-auto-close (eq asy-compilation-buffer 'none) (not (eq asy-compilation-buffer 'visible))) (sit-for 0.6))) (error "")) )) (let ((view-inhibit-help-message t)) (write-region "" 0 (asy-log-filename) nil)) (compile command)) (asy-compilation-wait pass auto-close)))) (defun asy-open-file(Filename) "Open the ps or pdf file Filename. In unix-like system the variables `ps-view-command' and `pdf-view-command' are used. In Windows the associated system file type is used instead." (let ((command (if running-unix-p (let ((ext (file-name-extension Filename))) (cond ((string= ext "ps") ps-view-command) ((string= ext "pdf") pdf-view-command) (t (error "Extension Not Supported.")))) (asy-protect-file-name (file-name-nondirectory Filename)))) ) (if running-unix-p (start-process "" nil command Filename) (call-process-shell-command command nil 0)))) (defun lasy-TeX-master-file () "Return the file name of the master file for the current document. The returned string contain the directory but does not contain the extension of the file." (expand-file-name (concat (TeX-master-directory) (TeX-master-file nil t)))) (defun lasy-must-compile-p (TeX-Master-File out-file &optional Force) "" (or Force (file-newer-than-file-p (concat TeX-Master-File ".tex") out-file) (and (stringp (TeX-master-file)) ;; current buffer is not a mater tex file (file-newer-than-file-p buffer-file-name out-file)))) (defun lasy-view-ps (&optional Force Filename fromtex) "Compile a LaTeX document embedding Asymptote code with latex->asy->latex->dvips and/or view the PostScript output. If optional argument Force is t then force compilation." (interactive) (setq lasy-run-tex t) (setq lasy-compile-tex fromtex) (if (buffer-modified-p) (save-buffer)) (when (eq asy-compilation-buffer 'never) (write-region "" 0 (asy-log-filename) nil)) (let* ((b-b-n (if Filename Filename (lasy-TeX-master-file))) (b-b-n-tex (asy-protect-file-name (concat b-b-n ".tex"))) (b-b-n-ps (asy-protect-file-name (concat b-b-n ".ps"))) (b-b-n-dvi (asy-protect-file-name (concat b-b-n ".dvi"))) (b-b-n-asy (asy-protect-file-name (concat b-b-n ".asy"))) (stderr (eq asy-compilation-buffer 'never))) (if (lasy-must-compile-p b-b-n (concat b-b-n ".ps") Force) (progn (let ((default-directory (file-name-directory b-b-n))) (asy-internal-compile (concat lasy-latex-command " " b-b-n-tex)) (when (and (zerop asy-last-compilation-code) (file-readable-p (concat b-b-n ".asy"))) (asy-internal-compile (concat asy-command-location lasy-command " " b-b-n-asy) nil nil stderr) (when (zerop asy-last-compilation-code) (asy-internal-compile (concat lasy-latex-command " " b-b-n-tex)))) (when (zerop asy-last-compilation-code) (asy-internal-compile (concat lasy-dvips-command " " b-b-n-dvi " -o " b-b-n-ps) nil t) (when (zerop asy-last-compilation-code) (asy-open-file (concat b-b-n ".ps")))))) (asy-open-file (concat b-b-n ".ps"))))) (defun lasy-view-pdf-via-pdflatex (&optional Force Filename fromtex) "Compile a LaTeX document embedding Asymptote code with pdflatex->asy->pdflatex and/or view the PDF output. If optional argument Force is t then force compilation." (interactive) (setq lasy-run-tex t) (setq lasy-compile-tex fromtex) (if (buffer-modified-p) (save-buffer)) (when (eq asy-compilation-buffer 'never) (write-region "" 0 (asy-log-filename) nil)) (let* ((b-b-n (if Filename Filename (lasy-TeX-master-file))) (b-b-n-tex (asy-protect-file-name (concat b-b-n ".tex"))) (b-b-n-pdf (asy-protect-file-name (concat b-b-n ".pdf"))) (b-b-n-asy (asy-protect-file-name (concat b-b-n ".asy"))) ;; (stderr (or (eq asy-compilation-buffer 'never) lasy-compile-tex))) (stderr (eq asy-compilation-buffer 'never))) (if (lasy-must-compile-p b-b-n (concat b-b-n ".pdf") Force) (progn (let ((default-directory (file-name-directory b-b-n))) (asy-internal-compile (concat lasy-pdflatex-command " " b-b-n-tex)) (when (and (zerop asy-last-compilation-code) (file-readable-p (concat b-b-n ".asy"))) (asy-internal-compile (concat asy-command-location lasy-command " " b-b-n-asy) nil nil stderr) (when (zerop asy-last-compilation-code) (asy-internal-compile (concat lasy-pdflatex-command " " b-b-n-tex) t))) (when (zerop asy-last-compilation-code) (asy-open-file (concat b-b-n ".pdf"))))) (asy-open-file (concat b-b-n ".pdf"))))) (defun lasy-view-pdf-via-ps2pdf (&optional Force Filename fromtex) "Compile a LaTeX document embedding Asymptote code with latex->asy->latex->dvips->ps2pdf14 and/or view the PDF output. If optional argument Force is t then force compilation." (interactive) (setq lasy-run-tex t) (setq lasy-compile-tex fromtex) (if (buffer-modified-p) (save-buffer)) (when (eq asy-compilation-buffer 'never) (write-region "" 0 (asy-log-filename) nil)) (let* ((b-b-n (if Filename Filename (lasy-TeX-master-file))) (b-b-n-tex (asy-protect-file-name (concat b-b-n ".tex"))) (b-b-n-ps (asy-protect-file-name (concat b-b-n ".ps"))) (b-b-n-dvi (asy-protect-file-name (concat b-b-n ".dvi"))) (b-b-n-pdf (asy-protect-file-name (concat b-b-n ".pdf"))) (b-b-n-asy (asy-protect-file-name (concat b-b-n ".asy"))) ;; (stderr (or (eq asy-compilation-buffer 'never) lasy-compile-tex))) (stderr (eq asy-compilation-buffer 'never))) (if (lasy-must-compile-p b-b-n (concat b-b-n ".pdf") Force) (progn (let ((default-directory (file-name-directory b-b-n))) (asy-internal-compile (concat lasy-latex-command " " b-b-n-tex)) (when (and (zerop asy-last-compilation-code) (file-readable-p (concat b-b-n ".asy"))) (asy-internal-compile (concat asy-command-location lasy-command " " b-b-n-asy) nil nil stderr) (when (zerop asy-last-compilation-code) (asy-internal-compile (concat lasy-latex-command " " b-b-n-tex)))) (when (zerop asy-last-compilation-code) (asy-internal-compile (concat lasy-dvips-pre-pdf-command " " b-b-n-dvi " -o " b-b-n-ps)) (when (zerop asy-last-compilation-code) (asy-internal-compile (concat lasy-ps2pdf-command " " b-b-n-ps " " b-b-n-pdf) t) (when (zerop asy-last-compilation-code) (asy-open-file (concat b-b-n ".pdf"))))))) (asy-open-file (concat b-b-n ".pdf"))))) ;; Goto error of last compilation (define-key asy-mode-map (kbd "") 'asy-goto-error) ;; Save and compile the file with option -V (define-key asy-mode-map (kbd "C-c C-c") 'asy-compile) ;; Show the definitions of command at point (define-key asy-mode-map (kbd "C-c ?") 'asy-show-function-at-point) ;; new line and indent (define-key asy-mode-map (kbd "RET") 'newline-and-indent) (defun asy-master-tex-view-ps () "Look at `asy-master-tex-view'" (interactive) (asy-master-tex-view 'lasy-view-ps nil t)) (define-key asy-mode-map (kbd "") 'asy-master-tex-view-ps) (defun asy-master-tex-view-ps-f () "Look at `asy-master-tex-view'" (interactive) (asy-master-tex-view 'lasy-view-ps t t)) (define-key asy-mode-map (kbd "") 'asy-master-tex-view-ps-f) (defun asy-master-tex-view-pdflatex () "Look at `asy-master-tex-view'" (interactive) (asy-master-tex-view 'lasy-view-pdf-via-pdflatex nil t)) (define-key asy-mode-map (kbd "") 'asy-master-tex-view-pdflatex) (defun asy-master-tex-view-pdflatex-f () "Look at `asy-master-tex-view'" (interactive) (asy-master-tex-view 'lasy-view-pdf-via-pdflatex t t)) (define-key asy-mode-map (kbd "") 'asy-master-tex-view-pdflatex-f) (defun asy-master-tex-view-ps2pdf () "Look at `asy-master-tex-view'" (interactive) (asy-master-tex-view 'lasy-view-pdf-via-ps2pdf nil t)) (define-key asy-mode-map (kbd "") 'asy-master-tex-view-ps2pdf) (defun asy-master-tex-view-ps2pdf-f () "Look at `asy-master-tex-view'" (interactive) (asy-master-tex-view 'lasy-view-pdf-via-ps2pdf t t)) (define-key asy-mode-map (kbd "") 'asy-master-tex-view-ps2pdf-f) (provide `asy-mode) ;;; asy-mode.el ends here asymptote-2.37/base/asy.vim000066400000000000000000000212461265434602500157310ustar00rootroot00000000000000" Vim syntax file " Language: Asymptote " Maintainer: Andy Hammerlindl " Last Change: 2005 Aug 23 " Hacked together from Bram Moolenaar's C syntax file, and Claudio Fleiner's " Java syntax file. " For version 5.x: Clear all syntax items " For version 6.x: Quit when a syntax file was already loaded if version < 600 syntax clear elseif exists("b:current_syntax") finish endif " A bunch of useful C keywords syn keyword asyStatement break return continue unravel syn keyword asyConditional if else syn keyword asyRepeat while for do syn keyword asyExternal access from import include syn keyword asyOperator new operator syn keyword asyTodo contained TODO FIXME XXX " asyCommentGroup allows adding matches for special things in comments syn cluster asyCommentGroup contains=asyTodo " String and Character constants " Highlight special characters (those proceding a double backslash) differently syn match asySpecial display contained "\\\\." " Highlight line continuation slashes syn match asySpecial display contained "\\$" syn region asyString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=asySpecial " asyCppString: same as asyString, but ends at end of line if 0 syn region asyCppString start=+"+ skip=+\\\\\|\\"\|\\$+ excludenl end=+"+ end='$' contains=asySpecial endif "when wanted, highlight trailing white space if exists("asy_space_errors") if !exists("asy_no_trail_space_error") syn match asySpaceError display excludenl "\s\+$" endif if !exists("asy_no_tab_space_error") syn match asySpaceError display " \+\t"me=e-1 endif endif "catch errors caused by wrong parenthesis and brackets syn cluster asyParenGroup contains=asyParenError,asyIncluded,asySpecial,asyCommentSkip,asyCommentString,asyComment2String,@asyCommentGroup,asyCommentStartError,asyUserCont,asyUserLabel,asyBitField,asyCommentSkip,asyOctalZero,asyCppOut,asyCppOut2,asyCppSkip,asyFormat,asyNumber,asyFloat,asyOctal,asyOctalError,asyNumbersCom if exists("asy_no_bracket_error") syn region asyParen transparent start='(' end=')' contains=ALLBUT,@asyParenGroup,asyCppParen,asyCppString " asyCppParen: same as asyParen but ends at end-of-line; used in asyDefine syn region asyCppParen transparent start='(' skip='\\$' excludenl end=')' end='$' contained contains=ALLBUT,@asyParenGroup,asyParen,asyString syn match asyParenError display ")" syn match asyErrInParen display contained "[{}]" else syn region asyParen transparent start='(' end=')' contains=ALLBUT,@asyParenGroup,asyCppParen,asyErrInBracket,asyCppBracket,asyCppString " asyCppParen: same as asyParen but ends at end-of-line; used in asyDefine syn region asyCppParen transparent start='(' skip='\\$' excludenl end=')' end='$' contained contains=ALLBUT,@asyParenGroup,asyErrInBracket,asyParen,asyBracket,asyString if 0 syn match asyParenError display "[\])]" syn match asyErrInParen display contained "[\]]" endif syn region asyBracket transparent start='\[' end=']' contains=ALLBUT,@asyParenGroup,asyErrInParen,asyCppParen,asyCppBracket,asyCppString " asyCppBracket: same as asyParen but ends at end-of-line; used in asyDefine syn region asyCppBracket transparent start='\[' skip='\\$' excludenl end=']' end='$' contained contains=ALLBUT,@asyParenGroup,asyErrInParen,asyParen,asyBracket,asyString syn match asyErrInBracket display contained "[);]" endif "integer number, or floating point number without a dot and with "f". syn case ignore syn match asyNumbers display transparent "\<\d\|\.\d" contains=asyNumber,asyFloat syn match asyNumber display contained "\d\+" "floating point number, with dot, optional exponent syn match asyFloat display contained "\d\+\.\d*\(e[-+]\=\d\+\)\=" "floating point number, starting with a dot, optional exponent syn match asyFloat display contained "\.\d\+\(e[-+]\=\d\+\)\=" "floating point number, without dot, with exponent syn match asyFloat display contained "\d\+e[-+]\=\d\+" syn case match if exists("asy_comment_strings") " A comment can contain asyString, asyCharacter and asyNumber. " But a "*/" inside a asyString in a asyComment DOES end the comment! So we " need to use a special type of asyString: asyCommentString, which also ends on " "*/", and sees a "*" at the start of the line as comment again. " Unfortunately this doesn't very well work for // type of comments :-( syntax match asyCommentSkip contained "^\s*\*\($\|\s\+\)" syntax region asyCommentString contained start=+L\="+ skip=+\\\\\|\\"+ end=+"+ end=+\*/+me=s-1 contains=asySpecial,asyCommentSkip syntax region asyComment2String contained start=+L\="+ skip=+\\\\\|\\"+ end=+"+ end="$" contains=asySpecial syntax region asyCommentL start="//" skip="\\$" end="$" keepend contains=@asyCommentGroup,asyComment2String,asyCharacter,asyNumbersCom,asySpaceError syntax region asyComment matchgroup=asyCommentStart start="/\*" matchgroup=NONE end="\*/" contains=@asyCommentGroup,asyCommentStartError,asyCommentString,asyCharacter,asyNumbersCom,asySpaceError else syn region asyCommentL start="//" skip="\\$" end="$" keepend contains=@asyCommentGroup,asySpaceError syn region asyComment matchgroup=asyCommentStart start="/\*" matchgroup=NONE end="\*/" contains=@asyCommentGroup,asyCommentStartError,asySpaceError endif " keep a // comment separately, it terminates a preproc. conditional syntax match asyCommentError display "\*/" syntax match asyCommentStartError display "/\*"me=e-1 contained syn keyword asyType void bool int real string syn keyword asyType pair triple transform guide path pen frame syn keyword asyType picture syn keyword asyStructure struct typedef syn keyword asyStorageClass static public readable private explicit syn keyword asyPathSpec and cycle controls tension atleast curl syn keyword asyConstant true false syn keyword asyConstant null nullframe nullpath if exists("asy_syn_plain") syn keyword asyConstant currentpicture currentpen currentprojection syn keyword asyConstant inch inches cm mm bp pt up down right left syn keyword asyConstant E NE N NW W SW S SE syn keyword asyConstant ENE NNE NNW WNW WSW SSW SSE ESE syn keyword asyConstant I pi twopi syn keyword asyConstant solid dotted dashed dashdotted syn keyword asyConstant longdashed longdashdotted syn keyword asyConstant squarecap roundcap extendcap syn keyword asyConstant miterjoin roundjoin beveljoin syn keyword asyConstant zerowinding evenodd syn keyword asyConstant invisible black gray grey white syn keyword asyConstant lightgray lightgrey syn keyword asyConstant red green blue syn keyword asyConstant cmyk Cyan Magenta Yellow Black syn keyword asyConstant yellow magenta cyan syn keyword asyConstant brown darkgreen darkblue syn keyword asyConstant orange purple royalblue olive syn keyword asyConstant chartreuse fuchsia salmon lightblue springgreen syn keyword asyConstant pink endif syn sync ccomment asyComment minlines=15 " Define the default highlighting. " For version 5.7 and earlier: only when not done already " For version 5.8 and later: only when an item doesn't have highlighting yet if version >= 508 || !exists("did_asy_syn_inits") if version < 508 let did_asy_syn_inits = 1 command -nargs=+ HiLink hi link else command -nargs=+ HiLink hi def link endif HiLink asyFormat asySpecial HiLink asyCppString asyString HiLink asyCommentL asyComment HiLink asyCommentStart asyComment HiLink asyLabel Label HiLink asyUserLabel Label HiLink asyConditional Conditional HiLink asyRepeat Repeat HiLink asyCharacter Character HiLink asySpecialCharacter asySpecial HiLink asyNumber Number HiLink asyOctal Number HiLink asyOctalZero PreProc " link this to Error if you want HiLink asyFloat Float HiLink asyOctalError asyError HiLink asyParenError asyError HiLink asyErrInParen asyError HiLink asyErrInBracket asyError HiLink asyCommentError asyError HiLink asyCommentStartError asyError HiLink asySpaceError asyError HiLink asySpecialError asyError HiLink asyOperator Operator HiLink asyStructure Structure HiLink asyStorageClass StorageClass HiLink asyExternal Include HiLink asyPreProc PreProc HiLink asyDefine Macro HiLink asyIncluded asyString HiLink asyError Error HiLink asyStatement Statement HiLink asyPreCondit PreCondit HiLink asyType Type HiLink asyConstant Constant HiLink asyCommentString asyString HiLink asyComment2String asyString HiLink asyCommentSkip asyComment HiLink asyString String HiLink asyComment Comment HiLink asySpecial SpecialChar HiLink asyTodo Todo HiLink asyCppSkip asyCppOut HiLink asyCppOut2 asyCppOut HiLink asyCppOut Comment HiLink asyPathSpec Statement delcommand HiLink endif let b:current_syntax = "c" " vim: ts=8 asymptote-2.37/base/asy_filetype.vim000066400000000000000000000001431265434602500176230ustar00rootroot00000000000000" Vim filetype detection file " Language: Asymptote au BufNewFile,BufRead *.asy setfiletype asy asymptote-2.37/base/asymptote.py000077500000000000000000000023311265434602500170140ustar00rootroot00000000000000# Python module to feed Asymptote with commands # (modified from gnuplot.py) from subprocess import * class asy: def __init__(self): self.session = Popen(['asy','-quiet','-interactive'],stdin=PIPE) self.help() def send(self, cmd): self.session.stdin.write(cmd+'\n') self.session.stdin.flush() def size(self, size): self.send("size(%d);" % size) def draw(self, str): self.send("draw(%s);" % str) def fill(self, str): self.send("fill(%s);" % str) def clip(self, str): self.send("clip(%s);" % str) def label(self, str): self.send("label(%s);" % str) def shipout(self, str): self.send("shipout(\"%s\");" % str) def erase(self): self.send("erase();") def help(self): print "Asymptote session is open. Available methods are:" print " help(), size(int), draw(str), fill(str), clip(str), label(str), shipout(str), send(str), erase()" def __del__(self): print "closing Asymptote session..." self.send('quit'); self.session.stdin.close(); self.session.wait() if __name__=="__main__": g = asy() g.size(200) g.draw("unitcircle") g.send("draw(unitsquare)") g.fill("unitsquare, blue") g.clip("unitcircle") g.label("\"$O$\", (0,0), SW") raw_input("press ENTER to continue") g.erase() del g asymptote-2.37/base/babel.asy000066400000000000000000000000631265434602500161750ustar00rootroot00000000000000void babel(string s) { usepackage("babel",s); } asymptote-2.37/base/bezulate.asy000066400000000000000000000225351265434602500167530ustar00rootroot00000000000000// Bezier triangulation routines written by Orest Shardt, 2008. private real fuzz=sqrtEpsilon; real duplicateFuzz=1e-3; // Work around font errors. real maxrefinements=7; private real[][] intersections(pair a, pair b, path p) { pair delta=fuzz*unit(b-a); return intersections(a-delta--b+delta,p,fuzz); } int countIntersections(path[] p, pair start, pair end) { int intersects=0; for(path q : p) intersects += intersections(start,end,q).length; return intersects; } path[][] containmentTree(path[] paths) { path[][] result; for(path g : paths) { // check if current curve contains or is contained in a group of curves int j; for(j=0; j < result.length; ++j) { path[] resultj=result[j]; int test=inside(g,resultj[0],zerowinding); if(test == 1) { // current curve contains group's toplevel curve; // replace toplevel curve with current curve resultj.insert(0,g); // check to see if any other groups are contained within this curve for(int k=j+1; k < result.length;) { if(inside(g,result[k][0],zerowinding) == 1) { resultj.append(result[k]); result.delete(k); } else ++k; } break; } else if(test == -1) { // current curve contained within group's toplevel curve resultj.push(g); break; } } // create a new group if this curve does not belong to another group if(j == result.length) result.push(new path[] {g}); } return result; } bool isDuplicate(pair a, pair b, real relSize) { return abs(a-b) <= duplicateFuzz*relSize; } path removeDuplicates(path p) { real relSize = abs(max(p)-min(p)); bool cyclic=cyclic(p); for(int i=0; i < length(p); ++i) { if(isDuplicate(point(p,i),point(p,i+1),relSize)) { p=subpath(p,0,i)&subpath(p,i+1,length(p)); --i; } } return cyclic ? p&cycle : p; } path section(path p, real t1, real t2, bool loop=false) { if(t2 < t1 || loop && t1 == t2) t2 += length(p); return subpath(p,t1,t2); } path uncycle(path p, real t) { return subpath(p,t,t+length(p)); } // returns outer paths void connect(path[] paths, path[] result, path[] patch) { path[][] tree=containmentTree(paths); for(path[] group : tree) { path outer = group[0]; group.delete(0); path[][] innerTree = containmentTree(group); path[] remainingCurves; path[] inners; for(path[] innerGroup:innerTree) { inners.push(innerGroup[0]); if(innerGroup.length>1) remainingCurves.append(innerGroup[1:]); } connect(remainingCurves,result,patch); real d=2*abs(max(outer)-min(outer)); while(inners.length > 0) { int curveIndex = 0; //pair direction=I*dir(inners[curveIndex],0,1); // Use outgoing direction //if(direction == 0) // Try a random direction // direction=expi(2pi*unitrand()); //pair start=point(inners[curveIndex],0); // find shortest distance between a node on the inner curve and a node // on the outer curve real mindist = d; int inner_i = 0; int outer_i = 0; for(int ni = 0; ni < length(inners[curveIndex]); ++ni) { for(int no = 0; no < length(outer); ++no) { real dist = abs(point(inners[curveIndex],ni)-point(outer,no)); if(dist < mindist) { inner_i = ni; outer_i = no; mindist = dist; } } } pair start=point(inners[curveIndex],inner_i); pair end = point(outer,outer_i); // find first intersection of line segment with outer curve //real[][] ints=intersections(start,start+d*direction,outer); real[][] ints=intersections(start,end,outer); assert(ints.length != 0); real endtime=ints[0][1]; // endtime is time on outer end = point(outer,endtime); // find first intersection of end--start with any inner curve real starttime=inner_i; // starttime is time on inners[curveIndex] real earliestTime=1; for(int j=0; j < inners.length; ++j) { real[][] ints=intersections(end,start,inners[j]); if(ints.length > 0 && ints[0][0] < earliestTime) { earliestTime=ints[0][0]; // time on end--start starttime=ints[0][1]; // time on inner curve curveIndex=j; } } start=point(inners[curveIndex],starttime); bool found_forward = false; real timeoffset_forward = 2; path portion_forward; path[] allCurves = {outer}; allCurves.append(inners); while(!found_forward && timeoffset_forward > fuzz) { timeoffset_forward /= 2; if(countIntersections(allCurves,start, point(outer,endtime+timeoffset_forward)) == 2) { portion_forward = subpath(outer,endtime,endtime+timeoffset_forward)--start--cycle; found_forward=true; // check if an inner curve is inside the portion for(int k = 0; found_forward && k < inners.length; ++k) { if(k!=curveIndex && inside(portion_forward,point(inners[k],0),zerowinding)) found_forward = false; } } } bool found_backward = false; real timeoffset_backward = -2; path portion_backward; while(!found_backward && timeoffset_backward < -fuzz) { timeoffset_backward /= 2; if(countIntersections(allCurves,start, point(outer,endtime+timeoffset_backward))==2) { portion_backward = subpath(outer,endtime+timeoffset_backward,endtime)--start--cycle; found_backward = true; // check if an inner curve is inside the portion for(int k = 0; found_backward && k < inners.length; ++k) { if(k!=curveIndex && inside(portion_backward,point(inners[k],0),zerowinding)) found_backward = false; } } } assert(found_forward || found_backward); real timeoffset; path portion; if(found_forward && !found_backward) { timeoffset = timeoffset_forward; portion = portion_forward; } else if(found_backward && !found_forward) { timeoffset = timeoffset_backward; portion = portion_backward; } else // assert handles case of neither found { if(timeoffset_forward > -timeoffset_backward) { timeoffset = timeoffset_forward; portion = portion_forward; } else { timeoffset = timeoffset_backward; portion = portion_backward; } } endtime=min(endtime,endtime+timeoffset); // or go from timeoffset+timeoffset_backward to timeoffset+timeoffset_forward? timeoffset=abs(timeoffset); // depends on the curves having opposite orientations path remainder=section(outer,endtime+timeoffset,endtime) --uncycle(inners[curveIndex], starttime)--cycle; inners.delete(curveIndex); outer = remainder; patch.append(portion); } result.append(outer); } } bool checkSegment(path g, pair p, pair q) { pair mid=0.5*(p+q); return intersections(p,q,g).length == 2 && inside(g,mid,zerowinding) && intersections(g,mid).length == 0; } path subdivide(path p) { path q; int l=length(p); for(int i=0; i < l; ++i) q=q&(straight(p,i) ? subpath(p,i,i+1) : subpath(p,i,i+0.5)&subpath(p,i+0.5,i+1)); return cyclic(p) ? q&cycle : q; } path[] bezulate(path[] p) { if(p.length == 1 && length(p[0]) <= 4) return p; path[] patch; path[] result; connect(p,result,patch); for(int i=0; i < result.length; ++i) { path p=result[i]; int refinements=0; if(size(p) <= 1) return p; if(!cyclic(p)) abort("path must be cyclic and nonselfintersecting."); p=removeDuplicates(p); if(length(p) > 4) { static real SIZE_STEPS=10; static real factor=1.05/SIZE_STEPS; for(int k=1; k <= SIZE_STEPS; ++k) { real L=factor*k*abs(max(p)-min(p)); for(int i=0; length(p) > 4 && i < length(p); ++i) { bool found=false; pair start=point(p,i); //look for quadrilaterals and triangles with one line, 4 | 3 curves for(int desiredSides=4; !found && desiredSides >= 3; --desiredSides) { if(desiredSides == 3 && length(p) <= 3) break; pair end; int endi=i+desiredSides-1; end=point(p,endi); found=checkSegment(p,start,end) && abs(end-start) < L; if(found) { path p1=subpath(p,endi,i+length(p))--cycle; patch.append(subpath(p,i,endi)--cycle); p=removeDuplicates(p1); i=-1; // increment will make i be 0 } } if(!found && k == SIZE_STEPS && length(p) > 4 && i == length(p)-1) { // avoid infinite recursion ++refinements; if(refinements > maxrefinements) { warning("subdivisions","too many subdivisions",position=true); } else { p=subdivide(p); i=-1; } } } } } if(length(p) <= 4) patch.append(p); } return patch; } asymptote-2.37/base/binarytree.asy000066400000000000000000000263321265434602500173030ustar00rootroot00000000000000/* ********************************************************************** * binarytree: An Asymptote module to draw binary trees * * * * Copyright(C) 2006 * * Tobias Langner tobias[at]langner[dot]nightlabs[dot]de * * * * Modified by John Bowman * * * * Condensed mode: * * Copyright(C) 2012 * * Gerasimos Dimitriadis dimeg [at] intracom [dot] gr * * * ************************************************************************ * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 3 of the License, or(at your option) any later version. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, * * Boston, MA 02110-1301 USA * * * * Or get it online: * * http: //www.gnu.org/copyleft/lesser.html * * * ***********************************************************************/ // default values real minDistDefault=0.2cm; real nodeMarginDefault=0.1cm; // structure to represent nodes in a binary tree struct binarytreeNode { int key; binarytreeNode left; binarytreeNode right; binarytreeNode parent; bool spans_calculated=false; int left_span,total_left_span; int right_span,total_right_span; void update_spans(); // Get the horizontal span of the tree consisting of the current // node plus the whole subtree that is rooted at the right child // (condensed mode) int getTotalRightSpan() { if(spans_calculated == false) { update_spans(); } return total_right_span; } // Get the horizontal span of the tree consisting of the current // node plus the whole subtree that is rooted at the left child // (condensed mode) int getTotalLeftSpan() { if(spans_calculated == false) { update_spans(); } return total_left_span; } // Get the horizontal distance between this node and its right child // (condensed mode) int getRightSpan() { if(spans_calculated == false) { update_spans(); } return right_span; } // Get the horizontal distance between this node and its left child // (condensed mode) int getLeftSpan() { if(spans_calculated == false) { update_spans(); } return left_span; } // Update all span figures for this node. // condensed mode) update_spans=new void() { if(spans_calculated == true) return; left_span=0; total_left_span=0; right_span=0; total_right_span=0; if(left != null) { left_span=left.getTotalRightSpan()+1; total_left_span=left_span+left.getTotalLeftSpan(); } if(right != null) { right_span=right.getTotalLeftSpan()+1; total_right_span=right_span+right.getTotalRightSpan(); } spans_calculated=true; }; // set the left child of this node void setLeft(binarytreeNode left) { this.left=left; this.left.parent=this; } // set the right child of this node void setRight(binarytreeNode right) { this.right=right; this.right.parent=this; } // return a boolean indicating whether this node is the root bool isRoot() { return parent == null; } // return the level of the subtree rooted at this node. int getLevel() { if(isRoot()) return 1; else return parent.getLevel()+1; } // set the children of this binarytreeNode void setChildren(binarytreeNode left, binarytreeNode right) { setLeft(left); setRight(right); } // create a new binarytreeNode with key static binarytreeNode binarytreeNode(int key) { binarytreeNode toReturn=new binarytreeNode; toReturn.key=key; return toReturn; } // returns the height of the subtree rooted at this node. int getHeight() { if(left == null && right == null) return 1; if(left == null) return right.getHeight()+1; if(right == null) return left.getHeight()+1; return max(left.getHeight(),right.getHeight())+1; } } binarytreeNode operator init() {return null;} // "constructor" for binarytreeNode binarytreeNode binarytreeNode(int key)=binarytreeNode.binarytreeNode; // draw the tree rooted at the given at the given position , with // =the height of the containing tree, // =the minimal horizontal distance of two nodes at the lowest level, // =the vertical distance between two levels, // =the diameter of one node. object draw(picture pic=currentpicture, binarytreeNode node, pair pos, int height, real minDist, real levelDist, real nodeDiameter, pen p=currentpen, bool condensed=false) { Label label=Label(math((string) node.key),pos); binarytreeNode left=node.left; binarytreeNode right=node.right; // return the distance for two nodes at the given when the // containing tree has height // and the minimal distance between two nodes is . real getDistance(int level, int height, real minDist) { return(nodeDiameter+minDist)*2^(height-level); } // return the horiontal distance between node and its left child // (condensed mode) real getLeftDistance(binarytreeNode n) { return(nodeDiameter+minDist) *(real)n.getLeftSpan() * 0.5; } // return the horiontal distance between node and its right child // (condensed mode) real getRightDistance(binarytreeNode n) { return(nodeDiameter+minDist) *(real)n.getRightSpan() * 0.5; } real dist=getDistance(node.getLevel(),height,minDist)/2; // draw the connection between the two nodes at the given positions // by calculating the connection points and drawing the corresponding // arrow. void deferredDrawNodeConnection(pair parentPos, pair childPos) { pic.add(new void(frame f, transform t) { pair start,end; // calculate connection path transform T=shift(nodeDiameter/2*unit(t*childPos-t*parentPos)); path arr=(T*t*parentPos)--(inverse(T)*t*childPos); draw(f,PenMargin(arr,p).g,p,Arrow(5)); }); pic.addPoint(parentPos); pic.addPoint(childPos); } if(left != null) { pair childPos; if(condensed == false) { childPos=pos-(0,levelDist)-(dist/2,0); } else { childPos=pos-(0,levelDist)-((real)getLeftDistance(node),0); } draw(pic,left,childPos,height,minDist,levelDist,nodeDiameter,p,condensed); deferredDrawNodeConnection(pos,childPos); } if(right != null) { pair childPos; if(condensed == false) { childPos=pos-(0,levelDist)+(dist/2,0); } else { childPos=pos-(0,levelDist)+((real)getRightDistance(node),0); } draw(pic,right,childPos,height,minDist,levelDist,nodeDiameter,p,condensed); deferredDrawNodeConnection(pos,childPos); } picture obj; draw(obj,circle((0,0),nodeDiameter/2),p); label(obj,label,(0,0),p); add(pic,obj,pos); return label; } struct key { int n; bool active; } key key(int n, bool active=true) {key k; k.n=n; k.active=active; return k;} key operator cast(int n) {return key(n);} int operator cast(key k) {return k.n;} int[] operator cast(key[] k) { int[] I; for(int i=0; i < k.length; ++i) I[i]=k[i].n; return I; } key nil=key(0,false); // structure to represent a binary tree. struct binarytree { binarytreeNode root; int[] keys; // add the given to the tree by searching for its place and // inserting it there. void addKey(int key) { binarytreeNode newNode=binarytreeNode(key); if(root == null) { root=newNode; keys.push(key); return; } binarytreeNode n=root; while(n != null) { if(key < n.key) { if(n.left != null) n=n.left; else { n.setLeft(newNode); keys.push(key); return; } } else if(key > n.key) { if(n.right != null) n=n.right; else { n.setRight(newNode); keys.push(key); return; } } } } // return the height of the tree int getHeight() { if(root == null) return 0; else return root.getHeight(); } // add all given keys to the tree sequentially void addSearchKeys(int[] keys) { for(int i=0; i < keys.length; ++i) { int key=keys[i]; // Ignore duplicate keys if(find(this.keys == key) == -1) addKey(key); } } binarytreeNode build(key[] keys, int[] ind) { if(ind[0] >= keys.length) return null; key k=keys[ind[0]]; ++ind[0]; if(!k.active) return null; binarytreeNode bt=binarytreeNode(k); binarytreeNode left=build(keys,ind); binarytreeNode right=build(keys,ind); bt.left=left; bt.right=right; if(left != null) left.parent=bt; if(right != null) right.parent=bt; return bt; } void addKeys(key[] keys) { int[] ind={0}; root=build(keys,ind); this.keys=keys; } // return all key in the tree int[] getKeys() { return keys; } } binarytree searchtree(...int[] keys) { binarytree bt; bt.addSearchKeys(keys); return bt; } binarytree binarytree(...key[] keys) { binarytree bt; bt.addKeys(keys); return bt; } // draw the given binary tree. void draw(picture pic=currentpicture, binarytree tree, real minDist=minDistDefault, real nodeMargin=nodeMarginDefault, pen p=currentpen, bool condensed=false) { int[] keys=tree.getKeys(); // calculate the node diameter so that all keys fit into it frame f; for(int i=0; i < keys.length; ++i) label(f,math(string(keys[i])),p); real nodeDiameter=abs(max(f)-min(f))+2*nodeMargin; real levelDist=nodeDiameter*1.8; draw(pic,tree.root,(0,0),tree.getHeight(),minDist,levelDist,nodeDiameter,p, condensed); } asymptote-2.37/base/bsp.asy000066400000000000000000000124271265434602500157230ustar00rootroot00000000000000private import math; import three; real epsilon=10*realEpsilon; // Routines for hidden surface removal (via binary space partition): // Structure face is derived from picture. struct face { picture pic; transform t; frame fit; triple normal,point; triple min,max; void operator init(path3 p) { this.normal=normal(p); if(this.normal == O) abort("path is linear"); this.point=point(p,0); min=min(p); max=max(p); } face copy() { face f=new face; f.pic=pic.copy(); f.t=t; f.normal=normal; f.point=point; f.min=min; f.max=max; add(f.fit,fit); return f; } } picture operator cast(face f) {return f.pic;} face operator cast(path3 p) {return face(p);} struct line { triple point; triple dir; } private line intersection(face a, face b) { line L; L.point=intersectionpoint(a.normal,a.point,b.normal,b.point); L.dir=unit(cross(a.normal,b.normal)); return L; } struct half { pair[] left,right; // Sort the points in the pair array z according to whether they lie on the // left or right side of the line L in the direction dir passing through P. // Points exactly on L are considered to be on the right side. // Also push any points of intersection of L with the path operator --(... z) // onto each of the arrays left and right. void operator init(pair dir, pair P ... pair[] z) { pair lastz; pair invdir=dir != 0 ? 1/dir : 0; bool left,last; for(int i=0; i < z.length; ++i) { left=(invdir*z[i]).y > (invdir*P).y; if(i > 0 && last != left) { pair w=extension(P,P+dir,lastz,z[i]); this.left.push(w); this.right.push(w); } if(left) this.left.push(z[i]); else this.right.push(z[i]); last=left; lastz=z[i]; } } } struct splitface { face back,front; } // Return the pieces obtained by splitting face a by face cut. splitface split(face a, face cut, projection P) { splitface S; void nointersection() { if(abs(dot(a.point-P.camera,a.normal)) >= abs(dot(cut.point-P.camera,cut.normal))) { S.back=a; S.front=null; } else { S.back=null; S.front=a; } } if(P.infinity) { P=P.copy(); static real factor=1/sqrtEpsilon; P.camera *= factor*max(abs(a.min),abs(a.max), abs(cut.min),abs(cut.max)); } if((abs(a.normal-cut.normal) < epsilon || abs(a.normal+cut.normal) < epsilon)) { nointersection(); return S; } line L=intersection(a,cut); if(dot(P.camera-L.point,P.camera-P.target) < 0) { nointersection(); return S; } pair point=a.t*project(L.point,P); pair dir=a.t*project(L.point+L.dir,P)-point; pair invdir=dir != 0 ? 1/dir : 0; triple apoint=L.point+cross(L.dir,a.normal); bool left=(invdir*(a.t*project(apoint,P))).y >= (invdir*point).y; real t=intersect(apoint,P.camera,cut.normal,cut.point); bool rightfront=left ^ (t <= 0 || t >= 1); face back=a, front=a.copy(); pair max=max(a.fit); pair min=min(a.fit); half h=half(dir,point,max,(min.x,max.y),min,(max.x,min.y),max); if(h.right.length == 0) { if(rightfront) front=null; else back=null; } else if(h.left.length == 0) { if(rightfront) back=null; else front=null; } if(front != null) clip(front.fit,operator --(... rightfront ? h.right : h.left)--cycle, zerowinding); if(back != null) clip(back.fit,operator --(... rightfront ? h.left : h.right)--cycle, zerowinding); S.back=back; S.front=front; return S; } // A binary space partition struct bsp { bsp back; bsp front; face node; // Construct the bsp. void operator init(face[] faces, projection P) { if(faces.length != 0) { this.node=faces.pop(); face[] front,back; for(int i=0; i < faces.length; ++i) { splitface split=split(faces[i],this.node,P); if(split.front != null) front.push(split.front); if(split.back != null) back.push(split.back); } this.front=bsp(front,P); this.back=bsp(back,P); } } // Draw from back to front. void add(frame f) { if(back != null) back.add(f); add(f,node.fit,group=true); if(labels(node.fit)) layer(f); // Draw over any existing TeX layers. if(front != null) front.add(f); } } void add(picture pic=currentpicture, face[] faces, projection P=currentprojection) { int n=faces.length; face[] Faces=new face[n]; for(int i=0; i < n; ++i) Faces[i]=faces[i].copy(); pic.nodes.push(new void (frame f, transform t, transform T, pair m, pair M) { // Fit all of the pictures so we know their exact sizes. face[] faces=new face[n]; for(int i=0; i < n; ++i) { faces[i]=Faces[i].copy(); face F=faces[i]; F.t=t*T*F.pic.T; F.fit=F.pic.fit(t,T*F.pic.T,m,M); } bsp bsp=bsp(faces,P); if(bsp != null) bsp.add(f); }); for(int i=0; i < n; ++i) { picture F=Faces[i].pic; pic.userBox3(F.userMin3(), F.userMax3()); pic.bounds.append(F.T, F.bounds); // The above 2 lines should be replaced with a routine in picture which // copies only sizing data from another picture. } } asymptote-2.37/base/contour.asy000066400000000000000000000472111265434602500166270ustar00rootroot00000000000000// Contour routines written by Radoslav Marinov and John Bowman. import graph_settings; real eps=10000*realEpsilon; // 1 // 6 +-------------------+ 5 // | \ / | // | \ / | // | \ / | // | \ / | // 2 | X | 0 // | / \ | // | / \ | // | / \ | // | / \ | // 7 +-------------------+ 4 or 8 // 3 private struct segment { bool active; pair a,b; // Endpoints; a is always an edge point if one exists. int c; // Contour value. int edge; // -1: interior, 0 to 3: edge, // 4-8: single-vertex edge, 9: double-vertex edge. } // Case 1: line passes through two vertices of a triangle private segment case1(pair p0, pair p1, int edge) { // Will cause a duplicate guide; luckily case1 is rare segment rtrn; rtrn.active=true; rtrn.a=p0; rtrn.b=p1; rtrn.edge=edge; return rtrn; } // Case 2: line passes through a vertex and a side of a triangle // (the first vertex passed and the side between the other two) private segment case2(pair p0, pair p1, pair p2, real v0, real v1, real v2, int edge) { segment rtrn; pair val=interp(p1,p2,abs(v1/(v2-v1))); rtrn.active=true; if(edge < 4) { rtrn.a=val; rtrn.b=p0; } else { rtrn.a=p0; rtrn.b=val; } rtrn.edge=edge; return rtrn; } // Case 3: line passes through two sides of a triangle // (through the sides formed by the first & second, and second & third // vertices) private segment case3(pair p0, pair p1, pair p2, real v0, real v1, real v2, int edge=-1) { segment rtrn; rtrn.active=true; rtrn.a=interp(p1,p0,abs(v1/(v0-v1))); rtrn.b=interp(p1,p2,abs(v1/(v2-v1))); rtrn.edge=edge; return rtrn; } // Check if a line passes through a triangle, and draw the required line. private segment checktriangle(pair p0, pair p1, pair p2, real v0, real v1, real v2, int edge=-1) { // default null return static segment dflt; real eps=eps*max(abs(v0),abs(v1),abs(v2)); if(v0 < -eps) { if(v1 < -eps) { if(v2 < -eps) return dflt; // nothing to do else if(v2 <= eps) return dflt; // nothing to do else return case3(p0,p2,p1,v0,v2,v1); } else if(v1 <= eps) { if(v2 < -eps) return dflt; // nothing to do else if(v2 <= eps) return case1(p1,p2,5+edge); else return case2(p1,p0,p2,v1,v0,v2,5+edge); } else { if(v2 < -eps) return case3(p0,p1,p2,v0,v1,v2,edge); else if(v2 <= eps) return case2(p2,p0,p1,v2,v0,v1,edge); else return case3(p1,p0,p2,v1,v0,v2,edge); } } else if(v0 <= eps) { if(v1 < -eps) { if(v2 < -eps) return dflt; // nothing to do else if(v2 <= eps) return case1(p0,p2,4+edge); else return case2(p0,p1,p2,v0,v1,v2,4+edge); } else if(v1 <= eps) { if(v2 < -eps) return case1(p0,p1,9); else if(v2 <= eps) return dflt; // use finer partitioning. else return case1(p0,p1,9); } else { if(v2 < -eps) return case2(p0,p1,p2,v0,v1,v2,4+edge); else if(v2 <= eps) return case1(p0,p2,4+edge); else return dflt; // nothing to do } } else { if(v1 < -eps) { if(v2 < -eps) return case3(p1,p0,p2,v1,v0,v2,edge); else if(v2 <= eps) return case2(p2,p0,p1,v2,v0,v1,edge); else return case3(p0,p1,p2,v0,v1,v2,edge); } else if(v1 <= eps) { if(v2 < -eps) return case2(p1,p0,p2,v1,v0,v2,5+edge); else if(v2 <= eps) return case1(p1,p2,5+edge); else return dflt; // nothing to do } else { if(v2 < -eps) return case3(p0,p2,p1,v0,v2,v1); else if(v2 <= eps) return dflt; // nothing to do else return dflt; // nothing to do } } } // Collect connecting path segments. private void collect(pair[][][] points, real[] c) { // use to reverse an array, omitting the first point int[] reverseF(int n) {return sequence(new int(int x){return n-1-x;},n-1);} // use to reverse an array, omitting the last point int[] reverseL(int n) {return sequence(new int(int x){return n-2-x;},n-1);} for(int cnt=0; cnt < c.length; ++cnt) { pair[][] gdscnt=points[cnt]; for(int i=0; i < gdscnt.length; ++i) { pair[] gig=gdscnt[i]; int Li=gig.length; for(int j=i+1; j < gdscnt.length; ++j) { pair[] gjg=gdscnt[j]; int Lj=gjg.length; if(abs(gig[0]-gjg[0]) < eps) { gdscnt[j]=gjg[reverseF(Lj)]; gdscnt[j].append(gig); gdscnt.delete(i); --i; break; } else if(abs(gig[0]-gjg[Lj-1]) < eps) { gig.delete(0); gdscnt[j].append(gig); gdscnt.delete(i); --i; break; } else if(abs(gig[Li-1]-gjg[0]) < eps) { gjg.delete(0); gig.append(gjg); gdscnt[j]=gig; gdscnt.delete(i); --i; break; } else if(abs(gig[Li-1]-gjg[Lj-1]) < eps) { gig.append(gjg[reverseL(Lj)]); gdscnt[j]=gig; gdscnt.delete(i); --i; break; } } } } } // Join path segments. private guide[][] connect(pair[][][] points, real[] c, interpolate join) { // set up return value guide[][] result=new guide[c.length][]; for(int cnt=0; cnt < c.length; ++cnt) { pair[][] pointscnt=points[cnt]; guide[] resultcnt=result[cnt]=new guide[pointscnt.length]; for(int i=0; i < pointscnt.length; ++i) { pair[] pts=pointscnt[i]; guide gd; if(pts.length > 0) { if(pts.length > 1 && abs(pts[0]-pts[pts.length-1]) < eps) { guide[] g=sequence(new guide(int i) { return pts[i]; },pts.length-1); g.push(cycle); gd=join(...g); } else gd=join(...sequence(new guide(int i) { return pts[i]; },pts.length)); } resultcnt[i]=gd; } } return result; } // Return contour guides for a 2D data array. // z: two-dimensional array of nonoverlapping mesh points // f: two-dimensional array of corresponding f(z) data values // midpoint: optional array containing values of f at cell midpoints // c: array of contour values // join: interpolation operator (e.g. operator -- or operator ..) guide[][] contour(pair[][] z, real[][] f, real[][] midpoint=new real[][], real[] c, interpolate join=operator --) { int nx=z.length-1; if(nx == 0) abort("array z must have length >= 2"); int ny=z[0].length-1; if(ny == 0) abort("array z[0] must have length >= 2"); c=sort(c); bool midpoints=midpoint.length > 0; segment segments[][][]=new segment[nx][ny][]; // go over region a rectangle at a time for(int i=0; i < nx; ++i) { pair[] zi=z[i]; pair[] zp=z[i+1]; real[] fi=f[i]; real[] fp=f[i+1]; real[] midpointi; if(midpoints) midpointi=midpoint[i]; segment[][] segmentsi=segments[i]; for(int j=0; j < ny; ++j) { segment[] segmentsij=segmentsi[j]; // define points pair bleft=zi[j]; pair bright=zp[j]; pair tleft=zi[j+1]; pair tright=zp[j+1]; pair middle=0.25*(bleft+bright+tleft+tright); real f00=fi[j]; real f01=fi[j+1]; real f10=fp[j]; real f11=fp[j+1]; real fmm=midpoints ? midpoint[i][j] : 0.25*(f00+f01+f10+f11); // optimization: we make sure we don't work with empty rectangles int checkcell(int cnt) { real C=c[cnt]; real vertdat0=f00-C; // bottom-left vertex real vertdat1=f10-C; // bottom-right vertex real vertdat2=f01-C; // top-left vertex real vertdat3=f11-C; // top-right vertex // optimization: we make sure we don't work with empty rectangles int countm=0; int countz=0; int countp=0; void check(real vertdat) { if(vertdat < -eps) ++countm; else { if(vertdat <= eps) ++countz; else ++countp; } } check(vertdat0); check(vertdat1); check(vertdat2); check(vertdat3); if(countm == 4) return 1; // nothing to do if(countp == 4) return -1; // nothing to do if((countm == 3 || countp == 3) && countz == 1) return 0; // go through the triangles void addseg(segment seg) { if(seg.active) { seg.c=cnt; segmentsij.push(seg); } } real vertdat4=fmm-C; addseg(checktriangle(bright,tright,middle, vertdat1,vertdat3,vertdat4,0)); addseg(checktriangle(tright,tleft,middle, vertdat3,vertdat2,vertdat4,1)); addseg(checktriangle(tleft,bleft,middle, vertdat2,vertdat0,vertdat4,2)); addseg(checktriangle(bleft,bright,middle, vertdat0,vertdat1,vertdat4,3)); return 0; } void process(int l, int u) { if(l >= u) return; int i=quotient(l+u,2); int sign=checkcell(i); if(sign == -1) process(i+1,u); else if(sign == 1) process(l,i); else { process(l,i); process(i+1,u); } } process(0,c.length); } } // set up return value pair[][][] points=new pair[c.length][][]; for(int i=0; i < nx; ++i) { segment[][] segmentsi=segments[i]; for(int j=0; j < ny; ++j) { segment[] segmentsij=segmentsi[j]; for(int k=0; k < segmentsij.length; ++k) { segment C=segmentsij[k]; if(!C.active) continue; pair[] g=new pair[] {C.a,C.b}; segmentsij[k].active=false; int forward(int I, int J, bool first=true) { if(I >= 0 && I < nx && J >= 0 && J < ny) { segment[] segmentsIJ=segments[I][J]; for(int l=0; l < segmentsIJ.length; ++l) { segment D=segmentsIJ[l]; if(!D.active) continue; if(abs(D.a-g[g.length-1]) < eps) { g.push(D.b); segmentsIJ[l].active=false; if(D.edge >= 0 && !first) return D.edge; first=false; l=-1; } else if(abs(D.b-g[g.length-1]) < eps) { g.push(D.a); segmentsIJ[l].active=false; if(D.edge >= 0 && !first) return D.edge; first=false; l=-1; } } } return -1; } int backward(int I, int J, bool first=true) { if(I >= 0 && I < nx && J >= 0 && J < ny) { segment[] segmentsIJ=segments[I][J]; for(int l=0; l < segmentsIJ.length; ++l) { segment D=segmentsIJ[l]; if(!D.active) continue; if(abs(D.a-g[0]) < eps) { g.insert(0,D.b); segmentsIJ[l].active=false; if(D.edge >= 0 && !first) return D.edge; first=false; l=-1; } else if(abs(D.b-g[0]) < eps) { g.insert(0,D.a); segmentsIJ[l].active=false; if(D.edge >= 0 && !first) return D.edge; first=false; l=-1; } } } return -1; } void follow(int f(int, int, bool first=true), int edge) { int I=i; int J=j; while(true) { static int ix[]={1,0,-1,0}; static int iy[]={0,1,0,-1}; if(edge >= 0 && edge < 4) { I += ix[edge]; J += iy[edge]; edge=f(I,J); } else { if(edge == -1) break; if(edge < 9) { int edge0=(edge-5) % 4; int edge1=(edge-4) % 4; int ix0=ix[edge0]; int iy0=iy[edge0]; I += ix0; J += iy0; // Search all 3 corner cells if((edge=f(I,J)) == -1) { I += ix[edge1]; J += iy[edge1]; if((edge=f(I,J)) == -1) { I -= ix0; J -= iy0; edge=f(I,J); } } } else { // Double-vertex edge: search all 8 surrounding cells void search() { for(int i=-1; i <= 1; ++i) { for(int j=-1; j <= 1; ++j) { if((edge=f(I+i,J+j,false)) >= 0) { I += i; J += j; return; } } } } search(); } } } } // Follow contour in cell int edge=forward(i,j,first=false); // Follow contour forward outside of cell follow(forward,edge); // Follow contour backward outside of cell follow(backward,C.edge); points[C.c].push(g); } } } collect(points,c); // Required to join remaining case1 cycles. return connect(points,c,join); } // Return contour guides for a 2D data array on a uniform lattice // f: two-dimensional array of real data values // midpoint: optional array containing data values at cell midpoints // a,b: diagonally opposite vertices of rectangular domain // c: array of contour values // join: interpolation operator (e.g. operator -- or operator ..) guide[][] contour(real[][] f, real[][] midpoint=new real[][], pair a, pair b, real[] c, interpolate join=operator --) { int nx=f.length-1; if(nx == 0) abort("array f must have length >= 2"); int ny=f[0].length-1; if(ny == 0) abort("array f[0] must have length >= 2"); pair[][] z=new pair[nx+1][ny+1]; for(int i=0; i <= nx; ++i) { pair[] zi=z[i]; real xi=interp(a.x,b.x,i/nx); for(int j=0; j <= ny; ++j) { zi[j]=(xi,interp(a.y,b.y,j/ny)); } } return contour(z,f,midpoint,c,join); } // return contour guides for a real-valued function // f: real-valued function of two real variables // a,b: diagonally opposite vertices of rectangular domain // c: array of contour values // nx,ny: number of subdivisions in x and y directions (determines accuracy) // join: interpolation operator (e.g. operator -- or operator ..) guide[][] contour(real f(real, real), pair a, pair b, real[] c, int nx=ngraph, int ny=nx, interpolate join=operator --) { // evaluate function at points and midpoints real[][] dat=new real[nx+1][ny+1]; real[][] midpoint=new real[nx+1][ny+1]; for(int i=0; i <= nx; ++i) { real x=interp(a.x,b.x,i/nx); real x2=interp(a.x,b.x,(i+0.5)/nx); real[] dati=dat[i]; real[] midpointi=midpoint[i]; for(int j=0; j <= ny; ++j) { dati[j]=f(x,interp(a.y,b.y,j/ny)); midpointi[j]=f(x2,interp(a.y,b.y,(j+0.5)/ny)); } } return contour(dat,midpoint,a,b,c,join); } void draw(picture pic=currentpicture, Label[] L=new Label[], guide[][] g, pen[] p) { begingroup(pic); for(int cnt=0; cnt < g.length; ++cnt) { guide[] gcnt=g[cnt]; pen pcnt=p[cnt]; for(int i=0; i < gcnt.length; ++i) draw(pic,gcnt[i],pcnt); if(L.length > 0) { Label Lcnt=L[cnt]; for(int i=0; i < gcnt.length; ++i) { if(Lcnt.s != "" && size(gcnt[i]) > 1) label(pic,Lcnt,gcnt[i],pcnt); } } } endgroup(pic); } void draw(picture pic=currentpicture, Label[] L=new Label[], guide[][] g, pen p=currentpen) { draw(pic,L,g,sequence(new pen(int) {return p;},g.length)); } // Extend palette by the colors below and above at each end. pen[] extend(pen[] palette, pen below, pen above) { pen[] p=copy(palette); p.insert(0,below); p.push(above); return p; } // Compute the interior palette for a sequence of cyclic contours // corresponding to palette. pen[][] interior(picture pic=currentpicture, guide[][] g, pen[] palette) { if(palette.length != g.length+1) abort("Palette array must have length one more than guide array"); pen[][] fillpalette=new pen[g.length][]; for(int i=0; i < g.length; ++i) { guide[] gi=g[i]; guide[] gp; if(i+1 < g.length) gp=g[i+1]; guide[] gm; if(i > 0) gm=g[i-1]; pen[] fillpalettei=new pen[gi.length]; for(int j=0; j < gi.length; ++j) { path P=gi[j]; if(cyclic(P)) { int index=i+1; bool nextinside; for(int k=0; k < gp.length; ++k) { path next=gp[k]; if(cyclic(next)) { if(inside(P,point(next,0))) nextinside=true; else if(inside(next,point(P,0))) index=i; } } if(!nextinside) { // Check to see if previous contour is inside for(int k=0; k < gm.length; ++k) { path prev=gm[k]; if(cyclic(prev)) { if(inside(P,point(prev,0))) index=i; } } } fillpalettei[j]=palette[index]; } fillpalette[i]=fillpalettei; } } return fillpalette; } // Fill the interior of cyclic contours with palette void fill(picture pic=currentpicture, guide[][] g, pen[][] palette) { for(int i=0; i < g.length; ++i) { guide[] gi=g[i]; guide[] gp; if(i+1 < g.length) gp=g[i+1]; guide[] gm; if(i > 0) gm=g[i-1]; for(int j=0; j < gi.length; ++j) { path P=gi[j]; path[] S=P; if(cyclic(P)) { for(int k=0; k < gp.length; ++k) { path next=gp[k]; if(cyclic(next) && inside(P,point(next,0))) S=S^^next; } for(int k=0; k < gm.length; ++k) { path next=gm[k]; if(cyclic(next) && inside(P,point(next,0))) S=S^^next; } fill(pic,S,palette[i][j]+evenodd); } } } } // routines for irregularly spaced points: // check existing guides and adds new segment to them if possible, // or otherwise store segment as a new guide private void addseg(pair[][] gds, segment seg) { if(!seg.active) return; // search for a path to extend for(int i=0; i < gds.length; ++i) { pair[] gd=gds[i]; if(abs(gd[0]-seg.b) < eps) { gd.insert(0,seg.a); return; } else if(abs(gd[gd.length-1]-seg.b) < eps) { gd.push(seg.a); return; } else if(abs(gd[0]-seg.a) < eps) { gd.insert(0,seg.b); return; } else if(abs(gd[gd.length-1]-seg.a) < eps) { gd.push(seg.b); return; } } // in case nothing is found pair[] segm; segm=new pair[] {seg.a,seg.b}; gds.push(segm); return; } guide[][] contour(real f(pair), pair a, pair b, real[] c, int nx=ngraph, int ny=nx, interpolate join=operator --) { return contour(new real(real x, real y) {return f((x,y));},a,b,c,nx,ny,join); } guide[][] contour(pair[] z, real[] f, real[] c, interpolate join=operator --) { if(z.length != f.length) abort("z and f arrays have different lengths"); int[][] trn=triangulate(z); // array to store guides found so far pair[][][] points=new pair[c.length][][]; for(int cnt=0; cnt < c.length; ++cnt) { pair[][] pointscnt=points[cnt]; real C=c[cnt]; for(int i=0; i < trn.length; ++i) { int[] trni=trn[i]; int i0=trni[0], i1=trni[1], i2=trni[2]; addseg(pointscnt,checktriangle(z[i0],z[i1],z[i2], f[i0]-C,f[i1]-C,f[i2]-C)); } } collect(points,c); return connect(points,c,join); } asymptote-2.37/base/contour3.asy000066400000000000000000000345041265434602500167130ustar00rootroot00000000000000import graph_settings; import three; real eps=10000*realEpsilon; private struct weighted { triple normal; real ratio; int kpa0,kpa1,kpa2; int kpb0,kpb1,kpb2; triple v; } private struct bucket { triple v; triple val; int count; } struct vertex { triple v; triple normal; } // A group of 3 or 4 points. private struct object { bool active; weighted[] pts; } // Return contour vertices for a 3D data array. // z: three-dimensional array of nonoverlapping mesh points // f: three-dimensional arrays of real data values // midpoint: optional array containing estimate of f at midpoint values vertex[][] contour3(triple[][][] v, real[][][] f, real[][][] midpoint=new real[][][], projection P=currentprojection) { int nx=v.length-1; if(nx == 0) abort("array v must have length >= 2"); int ny=v[0].length-1; if(ny == 0) abort("array v[0] must have length >= 2"); int nz=v[0][0].length-1; if(nz == 0) abort("array v[0][0] must have length >= 2"); bool midpoints=midpoint.length > 0; bucket[][][][] kps=new bucket[2nx+1][2ny+1][2nz+1][]; for(int i=0; i < 2nx+1; ++i) for(int j=0; j < 2ny+1; ++j) for(int k=0; k < 2nz+1; ++k) kps[i][j][k]=new bucket[]; object[] objects; // go over region a rectangle at a time for(int i=0; i < nx; ++i) { triple[][] vi=v[i]; triple[][] vp=v[i+1]; real[][] fi=f[i]; real[][] fp=f[i+1]; int i2=2i; int i2p1=i2+1; int i2p2=i2+2; for(int j=0; j < ny; ++j) { triple[] vij=vi[j]; triple[] vpj=vp[j]; triple[] vip=vi[j+1]; triple[] vpp=vp[j+1]; real[] fij=fi[j]; real[] fpj=fp[j]; real[] fip=fi[j+1]; real[] fpp=fp[j+1]; int j2=2j; int j2p1=j2+1; int j2p2=j2+2; for(int k=0; k < nz; ++k) { // vertex values real vdat0=fij[k]; real vdat1=fij[k+1]; real vdat2=fip[k]; real vdat3=fip[k+1]; real vdat4=fpj[k]; real vdat5=fpj[k+1]; real vdat6=fpp[k]; real vdat7=fpp[k+1]; // define points triple p000=vij[k]; triple p001=vij[k+1]; triple p010=vip[k]; triple p011=vip[k+1]; triple p100=vpj[k]; triple p101=vpj[k+1]; triple p110=vpp[k]; triple p111=vpp[k+1]; triple m0=0.25*(p000+p010+p110+p100); triple m1=0.25*(p010+p110+p111+p011); triple m2=0.25*(p110+p100+p101+p111); triple m3=0.25*(p100+p000+p001+p101); triple m4=0.25*(p000+p010+p011+p001); triple m5=0.25*(p001+p011+p111+p101); triple mc=0.5*(m0+m5); // optimization: we make sure we don't work with empty rectangles int countm=0; int countz=0; int countp=0; void check(real vdat) { if(vdat < -eps) ++countm; else { if(vdat <= eps) ++countz; else ++countp; } } check(vdat0); check(vdat1); check(vdat2); check(vdat3); check(vdat4); check(vdat5); check(vdat6); check(vdat7); if(countm == 8 || countp == 8 || ((countm == 7 || countp == 7) && countz == 1)) continue; int k2=2k; int k2p1=k2+1; int k2p2=k2+2; // Evaluate midpoints of cube sides. // Then evaluate midpoint of cube. real vdat8=midpoints ? midpoint[i2p1][j2p1][k2] : 0.25*(vdat0+vdat2+vdat6+vdat4); real vdat9=midpoints ? midpoint[i2p1][j2p2][k2p1] : 0.25*(vdat2+vdat6+vdat7+vdat3); real vdat10=midpoints ? midpoint[i2p2][j2p1][k2p1] : 0.25*(vdat7+vdat6+vdat4+vdat5); real vdat11=midpoints ? midpoint[i2p1][j2][k2p1] : 0.25*(vdat0+vdat4+vdat5+vdat1); real vdat12=midpoints ? midpoint[i2][j2p1][k2p1] : 0.25*(vdat0+vdat2+vdat3+vdat1); real vdat13=midpoints ? midpoint[i2p1][j2p1][k2p2] : 0.25*(vdat1+vdat3+vdat7+vdat5); real vdat14=midpoints ? midpoint[i2p1][j2p1][k2p1] : 0.125*(vdat0+vdat1+vdat2+vdat3+vdat4+vdat5+vdat6+vdat7); // Go through the 24 pyramids, 4 for each side. void addval(int kp0, int kp1, int kp2, triple add, triple v) { bucket[] cur=kps[kp0][kp1][kp2]; for(int q=0; q < cur.length; ++q) { if(length(cur[q].v-v) < eps) { cur[q].val += add; ++cur[q].count; return; } } bucket newbuck; newbuck.v=v; newbuck.val=add; newbuck.count=1; cur.push(newbuck); } void accrue(weighted w) { triple val1=w.normal*w.ratio; triple val2=w.normal*(1-w.ratio); addval(w.kpa0,w.kpa1,w.kpa2,val1,w.v); addval(w.kpb0,w.kpb1,w.kpb2,val2,w.v); } triple dir=P.normal; void addnormals(weighted[] pts) { triple vec2=pts[1].v-pts[0].v; triple vec1=pts[0].v-pts[2].v; triple vec0=-vec2-vec1; vec2=unit(vec2); vec1=unit(vec1); vec0=unit(vec0); triple normal=cross(vec2,vec1); normal *= sgn(dot(normal,dir)); real angle0=acos(-dot(vec1,vec2)); real angle1=acos(-dot(vec2,vec0)); pts[0].normal=normal*angle0; pts[1].normal=normal*angle1; pts[2].normal=normal*(pi-angle0-angle1); } void addobj(object obj) { if(!obj.active) return; if(obj.pts.length == 4) { weighted[] points=obj.pts; object obj1; object obj2; obj1.active=true; obj2.active=true; obj1.pts=new weighted[] {points[0],points[1],points[2]}; obj2.pts=new weighted[] {points[1],points[2],points[3]}; addobj(obj1); addobj(obj2); } else { addnormals(obj.pts); for(int q=0; q < obj.pts.length; ++q) accrue(obj.pts[q]); objects.push(obj); } } weighted setupweighted(triple va, triple vb, real da, real db, int[] kpa, int[] kpb) { weighted w; real ratio=abs(da/(db-da)); w.v=interp(va,vb,ratio); w.ratio=ratio; w.kpa0=i2+kpa[0]; w.kpa1=j2+kpa[1]; w.kpa2=k2+kpa[2]; w.kpb0=i2+kpb[0]; w.kpb1=j2+kpb[1]; w.kpb2=k2+kpb[2]; return w; } weighted setupweighted(triple v, int[] kp) { weighted w; w.v=v; w.ratio=0.5; w.kpa0=w.kpb0=i2+kp[0]; w.kpa1=w.kpb1=j2+kp[1]; w.kpa2=w.kpb2=k2+kp[2]; return w; } // Checks if a pyramid contains a contour object. object checkpyr(triple v0, triple v1, triple v2, triple v3, real d0, real d1, real d2, real d3, int[] c0, int[] c1, int[] c2, int[] c3) { object obj; real a0=abs(d0); real a1=abs(d1); real a2=abs(d2); real a3=abs(d3); bool b0=a0 < eps; bool b1=a1 < eps; bool b2=a2 < eps; bool b3=a3 < eps; weighted[] pts; if(b0) pts.push(setupweighted(v0,c0)); if(b1) pts.push(setupweighted(v1,c1)); if(b2) pts.push(setupweighted(v2,c2)); if(b3) pts.push(setupweighted(v3,c3)); if(!b0 && !b1 && abs(d0+d1)+eps < a0+a1) pts.push(setupweighted(v0,v1,d0,d1,c0,c1)); if(!b0 && !b2 && abs(d0+d2)+eps < a0+a2) pts.push(setupweighted(v0,v2,d0,d2,c0,c2)); if(!b0 && !b3 && abs(d0+d3)+eps < a0+a3) pts.push(setupweighted(v0,v3,d0,d3,c0,c3)); if(!b1 && !b2 && abs(d1+d2)+eps < a1+a2) pts.push(setupweighted(v1,v2,d1,d2,c1,c2)); if(!b1 && !b3 && abs(d1+d3)+eps < a1+a3) pts.push(setupweighted(v1,v3,d1,d3,c1,c3)); if(!b2 && !b3 && abs(d2+d3)+eps < a2+a3) pts.push(setupweighted(v2,v3,d2,d3,c2,c3)); int s=pts.length; //There are three or four points. if(s > 2) { obj.active=true; obj.pts=pts; } else obj.active=false; return obj; } void check4pyr(triple v0, triple v1, triple v2, triple v3, triple v4, triple v5, real d0, real d1, real d2, real d3, real d4, real d5, int[] c0, int[] c1, int[] c2, int[] c3, int[] c4, int[] c5) { addobj(checkpyr(v5,v4,v0,v1,d5,d4,d0,d1,c5,c4,c0,c1)); addobj(checkpyr(v5,v4,v1,v2,d5,d4,d1,d2,c5,c4,c1,c2)); addobj(checkpyr(v5,v4,v2,v3,d5,d4,d2,d3,c5,c4,c2,c3)); addobj(checkpyr(v5,v4,v3,v0,d5,d4,d3,d0,c5,c4,c3,c0)); } static int[] pp000={0,0,0}; static int[] pp001={0,0,2}; static int[] pp010={0,2,0}; static int[] pp011={0,2,2}; static int[] pp100={2,0,0}; static int[] pp101={2,0,2}; static int[] pp110={2,2,0}; static int[] pp111={2,2,2}; static int[] pm0={1,1,0}; static int[] pm1={1,2,1}; static int[] pm2={2,1,1}; static int[] pm3={1,0,1}; static int[] pm4={0,1,1}; static int[] pm5={1,1,2}; static int[] pmc={1,1,1}; check4pyr(p000,p010,p110,p100,mc,m0, vdat0,vdat2,vdat6,vdat4,vdat14,vdat8, pp000,pp010,pp110,pp100,pmc,pm0); check4pyr(p010,p110,p111,p011,mc,m1, vdat2,vdat6,vdat7,vdat3,vdat14,vdat9, pp010,pp110,pp111,pp011,pmc,pm1); check4pyr(p110,p100,p101,p111,mc,m2, vdat6,vdat4,vdat5,vdat7,vdat14,vdat10, pp110,pp100,pp101,pp111,pmc,pm2); check4pyr(p100,p000,p001,p101,mc,m3, vdat4,vdat0,vdat1,vdat5,vdat14,vdat11, pp100,pp000,pp001,pp101,pmc,pm3); check4pyr(p000,p010,p011,p001,mc,m4, vdat0,vdat2,vdat3,vdat1,vdat14,vdat12, pp000,pp010,pp011,pp001,pmc,pm4); check4pyr(p001,p011,p111,p101,mc,m5, vdat1,vdat3,vdat7,vdat5,vdat14,vdat13, pp001,pp011,pp111,pp101,pmc,pm5); } } } vertex preparevertex(weighted w) { vertex ret; triple normal=O; bool first=true; bucket[] kp1=kps[w.kpa0][w.kpa1][w.kpa2]; bucket[] kp2=kps[w.kpb0][w.kpb1][w.kpb2]; bool notfound1=true; bool notfound2=true; int count=0; int stop=max(kp1.length,kp2.length); for(int r=0; r < stop; ++r) { if(notfound1) { if(length(w.v-kp1[r].v) < eps) { if(first) { ret.v=kp1[r].v; first=false; } normal += kp1[r].val; count += kp1[r].count; notfound1=false; } } if(notfound2) { if(length(w.v-kp2[r].v) < eps) { if(first) { ret.v=kp2[r].v; first=false; } normal += kp2[r].val; count += kp2[r].count; notfound2=false; } } } ret.normal=normal*2/count; return ret; } // Prepare return value. vertex[][] g; for(int q=0; q < objects.length; ++q) { object p=objects[q]; g.push(new vertex[] {preparevertex(p.pts[0]),preparevertex(p.pts[1]), preparevertex(p.pts[2])}); } return g; } // Return contour vertices for a 3D data array on a uniform lattice. // f: three-dimensional arrays of real data values // midpoint: optional array containing estimate of f at midpoint values // a,b: diagonally opposite points of rectangular parellelpiped domain vertex[][] contour3(real[][][] f, real[][][] midpoint=new real[][][], triple a, triple b, projection P=currentprojection) { int nx=f.length-1; if(nx == 0) abort("array f must have length >= 2"); int ny=f[0].length-1; if(ny == 0) abort("array f[0] must have length >= 2"); int nz=f[0][0].length-1; if(nz == 0) abort("array f[0][0] must have length >= 2"); triple[][][] v=new triple[nx+1][ny+1][nz+1]; for(int i=0; i <= nx; ++i) { real xi=interp(a.x,b.x,i/nx); triple[][] vi=v[i]; for(int j=0; j <= ny; ++j) { triple[] vij=v[i][j]; real yj=interp(a.y,b.y,j/ny); for(int k=0; k <= nz; ++k) { vij[k]=(xi,yj,interp(a.z,b.z,k/nz)); } } } return contour3(v,f,midpoint,P); } // Return contour vertices for a 3D data array, using a pyramid mesh // f: real-valued function of three real variables // a,b: diagonally opposite points of rectangular parellelpiped domain // nx,ny,nz number of subdivisions in x, y, and z directions vertex[][] contour3(real f(real, real, real), triple a, triple b, int nx=nmesh, int ny=nx, int nz=nx, projection P=currentprojection) { // evaluate function at points and midpoints real[][][] dat=new real[nx+1][ny+1][nz+1]; real[][][] midpoint=new real[2nx+2][2ny+2][2nz+1]; for(int i=0; i <= nx; ++i) { real x=interp(a.x,b.x,i/nx); real x2=interp(a.x,b.x,(i+0.5)/nx); real[][] dati=dat[i]; real[][] midpointi2=midpoint[2i]; real[][] midpointi2p1=midpoint[2i+1]; for(int j=0; j <= ny; ++j) { real y=interp(a.y,b.y,j/ny); real y2=interp(a.y,b.y,(j+0.5)/ny); real datij[]=dati[j]; real[] midpointi2p1j2=midpointi2p1[2j]; real[] midpointi2p1j2p1=midpointi2p1[2j+1]; real[] midpointi2j2p1=midpointi2[2j+1]; for(int k=0; k <= nz; ++k) { real z=interp(a.z,b.z,k/nz); real z2=interp(a.z,b.z,(k+0.5)/nz); datij[k]=f(x,y,z); if(i == nx || j == ny || k == nz) continue; int k2p1=2k+1; midpointi2p1j2p1[2k]=f(x2,y2,z); midpointi2p1j2p1[k2p1]=f(x2,y2,z2); midpointi2p1j2[k2p1]=f(x2,y,z2); midpointi2j2p1[k2p1]=f(x,y2,z2); if(i == 0) midpoint[2nx][2j+1][k2p1]=f(b.x,y2,z2); if(j == 0) midpointi2p1[2ny][k2p1]=f(x2,b.y,z2); if(k == 0) midpointi2p1j2p1[2nz]=f(x2,y2,b.z); } } } return contour3(dat,midpoint,a,b,P); } // Construct contour surface for a 3D data array, using a pyramid mesh. surface surface(vertex[][] g) { surface s=surface(g.length); for(int i=0; i < g.length; ++i) { vertex[] cur=g[i]; s.s[i]=patch(cur[0].v--cur[1].v--cur[2].v--cycle); } return s; } asymptote-2.37/base/drawtree.asy000066400000000000000000000040751265434602500167540ustar00rootroot00000000000000// A simple tree drawing module contributed by adarovsky // See example treetest.asy real treeNodeStep = 0.5cm; real treeLevelStep = 1cm; real treeMinNodeWidth = 2cm; struct TreeNode { TreeNode parent; TreeNode[] children; frame content; pair pos; real adjust; } void add( TreeNode child, TreeNode parent ) { child.parent = parent; parent.children.push( child ); } TreeNode makeNode( TreeNode parent = null, frame f ) { TreeNode child = new TreeNode; child.content = f; if( parent != null ) { add( child, parent ); } return child; } TreeNode makeNode( TreeNode parent = null, Label label ) { frame f; box( f, label); return makeNode( parent, f ); } real layout( int level, TreeNode node ) { if( node.children.length > 0 ) { real width[] = new real[node.children.length]; real curWidth = 0; for( int i = 0; i < node.children.length; ++i ) { width[i] = layout( level+1, node.children[i] ); node.children[i].pos = (curWidth + width[i]/2, -level*treeLevelStep); curWidth += width[i] + treeNodeStep; } real midPoint = ( sum( width )+treeNodeStep*(width.length-1)) / 2; for( int i = 0; i < node.children.length; ++i ) { node.children[i].adjust = - midPoint; } return max( (max(node.content)-min(node.content)).x, sum(width)+treeNodeStep*(width.length-1) ); } else { return max( treeMinNodeWidth, (max(node.content)-min(node.content)).x ); } } void drawAll( TreeNode node, frame f ) { pair pos; if( node.parent != null ) pos = (node.parent.pos.x+node.adjust, 0); else pos = (node.adjust, 0); node.pos += pos; node.content = shift(node.pos)*node.content; add( f, node.content ); if( node.parent != null ) { path p = point(node.content, N)--point(node.parent.content,S); draw( f, p, currentpen ); } for( int i = 0; i < node.children.length; ++i ) drawAll( node.children[i], f ); } void draw( TreeNode root, pair pos ) { frame f; root.pos = (0,0); layout( 1, root ); drawAll( root, f ); add(f,pos); } asymptote-2.37/base/embed.asy000066400000000000000000000026371265434602500162150ustar00rootroot00000000000000if(latex()) { usepackage("hyperref"); texpreamble("\hypersetup{"+settings.hyperrefOptions+"}"); usepackage("media9","bigfiles"); texpreamble("\newif\ifplaybutton"); texpreamble("\count255=\the\catcode`\@\makeatletter% \@ifpackagelater{media9}{2013/11/15}{}{\playbuttontrue}% \catcode`\@=\the\count255 %"); } // For documentation of the options see // http://mirror.ctan.org/macros/latex/contrib/media9/doc/media9.pdf // Embed PRC or SWF content in pdf file string embedplayer(string name, string text="", string options="", real width=0, real height=0) { if(width != 0) options += ",width="+(string) (width/pt)+"pt"; if(height != 0) options += ",height="+(string) (height/pt)+"pt"; return "% \ifplaybutton% \includemedia["+options+"]{"+text+"}{"+name+"}% \else% \includemedia[noplaybutton,"+options+"]{"+text+"}{"+name+"}% \fi"; } // Embed media in pdf file string embed(string name, string text="", string options="", real width=0, real height=0) { return embedplayer("VPlayer.swf",text,"label="+name+ ",activate=pageopen,addresource="+name+ ",flashvars={source="+name+"&scaleMode=letterbox},"+ options,width,height); } string link(string label, string text="Play") { return "\PushButton[ onclick={ annotRM['"+label+"'].activated=true; annotRM['"+label+"'].callAS('playPause'); }]{\fbox{"+text+"}}"; } asymptote-2.37/base/external.asy000066400000000000000000000021421265434602500167520ustar00rootroot00000000000000usepackage("hyperref"); texpreamble("\hypersetup{"+settings.hyperrefOptions+"}"); // Embed object to be run in an external window. An image file name can be // specified; if not given one will be automatically generated. string embed(string name, string text="", string options="", real width=0, real height=0, string image="") { string options; // Ignore passed options. if(image == "") { image=stripdirectory(stripextension(name))+"."+nativeformat(); convert(name+"[0]",image,nativeformat()); if(!settings.keep) { exitfcn currentexitfunction=atexit(); void exitfunction() { if(currentexitfunction != null) currentexitfunction(); delete(image); } atexit(exitfunction); } } if(width != 0) options += ", width="+(string) (width/pt)+"pt"; if(height != 0) options +=", height="+(string) (height/pt)+"pt"; return "\href{run:"+name+"}{"+graphic(image,options)+"}"; } string hyperlink(string url, string text) { return "\href{"+url+"}{"+text+"}"; } string link(string label, string text="Play") { return hyperlink("run:"+label,text); } asymptote-2.37/base/feynman.asy000066400000000000000000000517231265434602500165760ustar00rootroot00000000000000/***************************************************************************** * feynman.asy -- An Asymptote library for drawing Feynman diagrams. * * * * by: Martin Wiebusch * * last change: 2007/04/13 * *****************************************************************************/ /* default parameters ********************************************************/ // default ratio of width (distance between two loops) to amplitude for a gluon // line. The gluon function uses this ratio, if the width parameter is // negative. real gluonratio; // default ratio of width (distance between two crests) to amplitude for a // photon line. The photon function uses this ratio, if the width parameter is // negative. real photonratio; // default gluon amplitude real gluonamplitude; // default photon amplitude real photonamplitude; // default pen for drawing the background. Usually white. pen backgroundpen; // default pen for drawing gluon lines pen gluonpen; // default pen for drawing photon lines pen photonpen; // default pen for drawing fermion lines pen fermionpen; // default pen for drawing scalar lines pen scalarpen; // default pen for drawing ghost lines pen ghostpen; // default pen for drawing double lines pen doublelinepen; // default pen for drawing vertices pen vertexpen; // default pen for drawing big vertices (drawVertexOX and drawVertexBoxX) pen bigvertexpen; // inner spacing of a double line real doublelinespacing; // default arrow for propagators arrowbar currentarrow; // if true, each of the drawSomething commands blots out the background // (with pen backgroundpen) before drawing. bool overpaint; // margin around lines. If one line is drawn over anoter, a white margin // of size linemargin is kept around the top one. real linemargin; // at vertices, where many lines join, the last line drawn should not blot // out the others. By not erasing the background near the ends of lines, // this is prevented for lines with an angle greater than minvertexangle to // each other. Note, that small values for minvertexangle mean that the // background is only erased behind a small segment of every line. Setting // minvertexangle = 0 effectively disables background erasing for lines. real minvertexangle; // size (radius) of vertices real vertexsize; // size (radius) of big vertices (drawVertexOX and drawVertexBoxX) real bigvertexsize; /* defaults for momentum arrows **********************************************/ // (momentum arrows are small arrows parallel to particle lines indicating the // direction of momentum) // default size of the arrowhead of momentum arrows arrowbar currentmomarrow; // default length of momentum arrows real momarrowlength; // default pen for momentum arrows pen momarrowpen; // default offset between momentum arrow and related particle line real momarrowoffset; // default margin for momentum arrows real momarrowmargin; // factor for determining the size of momentum arrowheads. After changing it, // you still have to update currentmomarrow manually. real momarrowfactor; // size function for momentum arrowheads real momarrowsize(pen p=momarrowpen) { return momarrowfactor*linewidth(p); } /* defaults for texshipout ***************************************************/ // tex command for including graphics. It takes one argument, which is the // name of the graphics (eps or pdf) file. string includegraphicscommand; // Determines whether the suffix (.eps or .pdf) should be appended to the stem // of the file name in the \includegraphics command. bool appendsuffix; /* helper functions **********************************************************/ // internal function for overpainting private void do_overpaint(picture pic, path p, pen bgpen, real halfwidth, real vertexangle) { real tanvertexangle = tan(vertexangle*pi/180); if(tanvertexangle != 0) { real t1 = arctime(p, halfwidth/tanvertexangle+halfwidth); real t2 = arctime(p, arclength(p)-halfwidth/tanvertexangle-halfwidth); draw(pic, subpath(p, t1, t2), bgpen+linewidth(2*halfwidth)); } } // returns the path of a gluon line along path p, with amplitude amp and width // width (distance between two loops). If width is negative, the width is // set to amp*gluonratio path gluon(path p, real amp = gluonamplitude, real width=-1) { if(width < 0) width = abs(gluonratio*amp); real pathlen = arclength(p); int ncurls = floor(pathlen/width); real firstlen = (pathlen - width*(ncurls-1))/2; real firstt = arctime(p, firstlen); pair firstv = dir(p, firstt); guide g = point(p, 0)..{firstv}( point(p, firstt) +amp*unit(rotate(90)*firstv)); real t1; pair v1; real t2; pair v2; pathlen -= firstlen; for(real len = firstlen+width/2; len < pathlen; len += width) { t1 = arctime(p, len); v1 = dir(p, t1); t2 = arctime(p, len + width/2); v2 = dir(p, t2); g=g..{-v1}(point(p, t1)+amp*unit(rotate(-90)*v1)) ..{+v2}(point(p, t2)+amp*unit(rotate(+90)*v2)); } g = g..point(p, size(p)); return g; } // returns the path of a photon line along path p, with amplitude amp and width // width (distance between two crests). If width is negative, the width is // set to amp*photonratio path photon(path p, real amp = photonamplitude, real width=-1) { if(width < 0) width = abs(photonratio*amp)/2; else width = width/2; real pathlen = arclength(p); int ncurls = floor(pathlen/width); real firstlen = (pathlen - width*ncurls)/2; real firstt = arctime(p, firstlen+width); guide g = point(p, 0){unit(point(p, firstt)-point(p, 0))}; real t; pair v; pathlen -= firstlen; for(real len = firstlen+width; len < pathlen; len += width) { t = arctime(p, len); v = dir(p, t); g=g..{v}(point(p, t)+amp*unit(rotate(90)*v)); amp = -amp; } g = g..{unit(point(p, size(p))-point(p, t))}point(p, size(p)); return g; } // returns the path of a momentum arrow along path p, with length length, // an offset offset from the path p and at position position. position will // usually be one of the predefined pairs left or right. Making adjust // nonzero shifts the momentum arrow along the path. path momArrowPath(path p, align align, position pos, real offset = momarrowoffset, real length = momarrowlength) { real pathlen = arclength(p); real t1, t2; if(pos.relative) { t1 = arctime(p, (pathlen-length)*pos.position.x); t2 = arctime(p, (pathlen-length)*pos.position.x+length); } else { t1 = arctime(p, (pathlen-length)/2 + pos.position.x); t2 = arctime(p, (pathlen+length)/2+ pos.position.x); } pair v1 = dir(p, t1); pair v2 = dir(p, t2); pair p1, p2; if(align.relative) { p1 = point(p, t1) + offset*abs(align.dir) *unit(rotate(degrees(align.dir)-90)*v1); p2 = point(p, t2) + offset*abs(align.dir) *unit(rotate(degrees(align.dir)-90)*v2); } else { p1 = point(p, t1) + offset*align.dir; p2 = point(p, t2) + offset*align.dir; } return p1{v1}..{v2}p2; } /* drawing functions *********************************************************/ // draw a gluon line on picture pic, along path p, with amplitude amp, width // width (distance between loops) and with pen fgpen. If erasebg is true, // bgpen is used to erase the background behind the line and at a margin // margin around it. The background is not erased at a certain distance to // the endpoints, which is determined by vertexangle (see comments to the // default parameter minvertexangle). For negative values of width, the width // is set to gluonratio*amp. void drawGluon(picture pic = currentpicture, path p, real amp = gluonamplitude, real width = -1, pen fgpen = gluonpen, bool erasebg = overpaint, pen bgpen = backgroundpen, real vertexangle = minvertexangle, real margin = linemargin) { if(width < 0) width = abs(2*amp); if(erasebg) do_overpaint(pic, p, bgpen, amp+margin, vertexangle); draw(pic, gluon(p, amp, width), fgpen); } // draw a photon line on picture pic, along path p, with amplitude amp, width // width (distance between loops) and with pen fgpen. If erasebg is true, // bgpen is used to erase the background behind the line and at a margin // margin around it. The background is not erased at a certain distance to // the endpoints, which is determined by vertexangle (see comments to the // default parameter minvertexangle). For negative values of width, the width // is set to photonratio*amp. void drawPhoton(picture pic = currentpicture, path p, real amp = photonamplitude, real width = -1, pen fgpen = currentpen, bool erasebg = overpaint, pen bgpen = backgroundpen, real vertexangle = minvertexangle, real margin = linemargin) { if(width < 0) width = abs(4*amp); if(erasebg) do_overpaint(pic, p, bgpen, amp+margin, vertexangle); draw(pic, photon(p, amp, width), fgpen); } // draw a fermion line on picture pic, along path p with pen fgpen and an // arrowhead arrow. If erasebg is true, bgpen is used to erase the background // at a margin margin around the line. The background is not erased at a // certain distance to the endpoints, which is determined by vertexangle // (see comments to the default parameter minvertexangle). void drawFermion(picture pic = currentpicture, path p, pen fgpen = currentpen, arrowbar arrow = currentarrow, bool erasebg = overpaint, pen bgpen = backgroundpen, real vertexangle = minvertexangle, real margin = linemargin) { if(erasebg) do_overpaint(pic, p, bgpen, linewidth(fgpen)+margin, vertexangle); draw(pic, p, fgpen, arrow); } // draw a scalar line on picture pic, along path p with pen fgpen and an // arrowhead arrow. If erasebg is true, bgpen is used to erase the background // at a margin margin around the line. The background is not erased at a // certain distance to the endpoints, which is determined by vertexangle // (see comments to the default parameter minvertexangle). void drawScalar(picture pic = currentpicture, path p, pen fgpen = scalarpen, arrowbar arrow = currentarrow, bool erasebg = overpaint, pen bgpen = backgroundpen, real vertexangle = minvertexangle, real margin = linemargin) { if(erasebg) do_overpaint(pic, p, bgpen, linewidth(fgpen)+margin, vertexangle); draw(pic, p, fgpen, arrow); } // draw a ghost line on picture pic, along path p with pen fgpen and an // arrowhead arrow. If erasebg is true, bgpen is used to erase the background // at a margin margin around the line. The background is not erased at a // certain distance to the endpoints, which is determined by vertexangle // (see comments to the default parameter minvertexangle). void drawGhost(picture pic = currentpicture, path p, pen fgpen = ghostpen, arrowbar arrow = currentarrow, bool erasebg = overpaint, pen bgpen = backgroundpen, real vertexangle = minvertexangle, real margin = linemargin) { if(erasebg) do_overpaint(pic, p, bgpen, linewidth(fgpen)+margin, vertexangle); draw(pic, p, fgpen, arrow); } // draw a double line on picture pic, along path p with pen fgpen, an inner // spacing of dlspacint and an arrowhead arrow. If erasebg is true, bgpen is // used to erase the background at a margin margin around the line. The // background is not erased at a certain distance to the endpoints, which is // determined by vertexangle (see comments to the default parameter // minvertexangle). void drawDoubleLine(picture pic = currentpicture, path p, pen fgpen = doublelinepen, real dlspacing = doublelinespacing, arrowbar arrow = currentarrow, bool erasebg = overpaint, pen bgpen = backgroundpen, real vertexangle = minvertexangle, real margin = linemargin) { if(erasebg) do_overpaint(pic, p, bgpen, linewidth(fgpen)+margin, vertexangle); real htw = linewidth(fgpen)+dlspacing/2; draw(pic, p, fgpen+2*htw); draw(pic, p, bgpen+(linewidth(dlspacing))); path rect = (-htw,-htw)--(-htw,htw)--(0,htw)--(0,-htw)--cycle; fill(shift(point(p,0))*rotate(degrees(dir(p,0)))*rect, bgpen); fill(shift(point(p,size(p)))*scale(-1)*rotate(degrees(dir(p,size(p))))* rect,bgpen); draw(pic, p, invisible, arrow); } // draw a vertex dot on picture pic, at position xy with radius r and pen // fgpen void drawVertex(picture pic = currentpicture, pair xy, real r = vertexsize, pen fgpen = vertexpen) { fill(pic, circle(xy, r), fgpen); } // draw an empty vertex dot on picture pic, at position xy with radius r // and pen fgpen. If erasebg is true, the background is erased in the inside // of the circle. void drawVertexO(picture pic = currentpicture, pair xy, real r = vertexsize, pen fgpen = vertexpen, bool erasebg = overpaint, pen bgpen = backgroundpen) { if(erasebg) filldraw(pic, circle(xy, r), bgpen, fgpen); else draw(pic, circle(xy, r), fgpen); } // draw a vertex triangle on picture pic, at position xy with radius r and pen // fgpen void drawVertexTriangle(picture pic = currentpicture, pair xy, real r = vertexsize, pen fgpen = vertexpen) { real cospi6 = cos(pi/6); real sinpi6 = sin(pi/6); path triangle = (cospi6,-sinpi6)--(0,1)--(-cospi6,-sinpi6)--cycle; fill(pic, shift(xy)*scale(r)*triangle, fgpen); } // draw an empty vertex triangle on picture pic, at position xy with size r // and pen fgpen. If erasebg is true, the background is erased in the inside // of the triangle. void drawVertexTriangleO(picture pic = currentpicture, pair xy, real r = vertexsize, pen fgpen = vertexpen, bool erasebg = overpaint, pen bgpen = backgroundpen) { real cospi6 = cos(pi/6); real sinpi6 = sin(pi/6); path triangle = (cospi6,-sinpi6)--(0,1)--(-cospi6,-sinpi6)--cycle; if(erasebg) filldraw(pic, shift(xy)*scale(r)*triangle, bgpen, fgpen); else draw(pic, shift(xy)*scale(r)*triangle, fgpen); } // draw a vertex box on picture pic, at position xy with radius r and pen // fgpen void drawVertexBox(picture pic = currentpicture, pair xy, real r = vertexsize, pen fgpen = vertexpen) { path box = (1,1)--(-1,1)--(-1,-1)--(1,-1)--cycle; fill(pic, shift(xy)*scale(r)*box, fgpen); } // draw an empty vertex box on picture pic, at position xy with size r // and pen fgpen. If erasebg is true, the background is erased in the inside // of the box. void drawVertexBoxO(picture pic = currentpicture, pair xy, real r = vertexsize, pen fgpen = vertexpen, bool erasebg = overpaint, pen bgpen = backgroundpen) { path box = (1,1)--(-1,1)--(-1,-1)--(1,-1)--cycle; if(erasebg) filldraw(pic, shift(xy)*scale(r)*box, bgpen, fgpen); else draw(pic, shift(xy)*scale(r)*box, fgpen); } // draw an X on picture pic, at position xy with size r and pen // fgpen void drawVertexX(picture pic = currentpicture, pair xy, real r = vertexsize, pen fgpen = vertexpen) { draw(pic, shift(xy)*scale(r)*((-1,-1)--(1,1)), fgpen); draw(pic, shift(xy)*scale(r)*((1,-1)--(-1,1)), fgpen); } // draw a circle with an X in the middle on picture pic, at position xy with // size r and pen fgpen. If erasebg is true, the background is erased in the // inside of the circle. void drawVertexOX(picture pic = currentpicture, pair xy, real r = bigvertexsize, pen fgpen = vertexpen, bool erasebg = overpaint, pen bgpen = backgroundpen) { if(erasebg) filldraw(pic, circle(xy, r), bgpen, fgpen); else draw(pic, circle(xy, r), fgpen); draw(pic, shift(xy)*scale(r)*(NW--SE), fgpen); draw(pic, shift(xy)*scale(r)*(SW--NE), fgpen); } // draw a box with an X in the middle on picture pic, at position xy with // size r and pen fgpen. If erasebg is true, the background is erased in the // inside of the box. void drawVertexBoxX(picture pic = currentpicture, pair xy, real r = bigvertexsize, pen fgpen = vertexpen, bool erasebg = overpaint, pen bgpen = backgroundpen) { path box = (1,1)--(-1,1)--(-1,-1)--(1,-1)--cycle; box = shift(xy)*scale(r)*box; if(erasebg) filldraw(pic, box, bgpen, fgpen); else draw(pic, box, fgpen); draw(pic, shift(xy)*scale(r)*((-1,-1)--(1,1)), fgpen); draw(pic, shift(xy)*scale(r)*((1,-1)--(-1,1)), fgpen); } // draw a momentum arrow on picture pic, along path p, at position position // (use one of the predefined pairs left or right), with an offset offset // from the path, a length length, a pen fgpen and an arrowhead arrow. Making // adjust nonzero shifts the momentum arrow along the path. If erasebg is true, // the background is erased inside a margin margin around the momentum arrow. // Make sure that offset and margin are chosen in such a way that the momentum // arrow does not overdraw the particle line. void drawMomArrow(picture pic = currentpicture, path p, align align, position pos = MidPoint, real offset = momarrowoffset, real length = momarrowlength, pen fgpen = momarrowpen, arrowbar arrow = currentmomarrow, bool erasebg = overpaint, pen bgpen = backgroundpen, real margin = momarrowmargin) { path momarrow = momArrowPath(p, align, pos, offset, length); if(erasebg) do_overpaint(pic, momarrow, bgpen, linewidth(fgpen)+margin, 90); draw(pic, momarrow, fgpen, arrow); } /* initialisation ************************************************************/ // The function fmdefaults() tries to guess reasonable values for the // default parameters above by looking at the default parameters of plain.asy // (essentially, currentpen, arrowfactor and dotfactor). After customising the // default parameters of plain.asy, you may call fmdefaults to adjust the // parameters of feynman.asy. void fmdefaults() { real arrowsize=arrowsize(currentpen); real linewidth=linewidth(currentpen); gluonratio = 2; photonratio = 4; gluonamplitude = arrowsize/3; photonamplitude = arrowsize/4; backgroundpen = white; gluonpen = currentpen; photonpen = currentpen; fermionpen = currentpen; scalarpen = dashed+linewidth; ghostpen = dotted+linewidth; doublelinepen = currentpen; vertexpen = currentpen; bigvertexpen = currentpen; currentarrow = MidArrow; doublelinespacing = 2*linewidth; linemargin = 0.5*arrowsize; minvertexangle = 30; overpaint = true; vertexsize = 0.5*dotfactor*linewidth; bigvertexsize = 0.4*arrowsize; momarrowfactor = 1.5*arrowfactor; momarrowlength = 2.5*arrowsize; momarrowpen = currentpen+0.5*linewidth; momarrowoffset = 0.8*arrowsize; momarrowmargin = 0.25*arrowsize; currentmomarrow = EndArrow(momarrowsize()); includegraphicscommand = "\includegraphics"; appendsuffix = false; } // We call fmdefaults once, when the module is loaded. fmdefaults(); /* shipout *******************************************************************/ bool YAlign = false; bool XYAlign = true; // texshipout("filename", pic) creates two files: filename.eps holding the // picture pic and filename.tex holding some LaTeX code that includes the // picture from filename.eps and shifts it vertically in such a way that the // point (0,0) lies on the baseline. void texshipout(string stem, picture pic = currentpicture, bool xalign = YAlign) { file tf = output(stem + ".tex"); pair min=pic.min(); real depth = min.y; real xoffset = min.x; if(xalign) { write(tf, "\makebox[0pt][l]{\kern"); write(tf, xoffset); write(tf, "bp\relax"); } write(tf, "\raisebox{"); write(tf, depth); write(tf, "bp}{"+includegraphicscommand+"{"); write(tf, stem); string suffix="."+nativeformat(); if(appendsuffix) write(tf, suffix); write(tf, "}}"); if(xalign) write(tf, "}"); close(tf); shipout(stem+suffix, pic); } asymptote-2.37/base/flowchart.asy000066400000000000000000000337471265434602500171400ustar00rootroot00000000000000// Flowchart routines written by Jacques Pienaar, Steve Melenchuk, John Bowman. private import math; struct flowdir {} restricted flowdir Horizontal; restricted flowdir Vertical; real minblockwidth=0; real minblockheight=0; real mincirclediameter=0; real defaultexcursion=0.1; struct block { // The absolute center of the block in user coordinates. pair center; // The size of the block pair size; // The relative center of the block. pair f_center; // These eight variables return the appropriate location on the block // in relative coordinates, where the lower left corner of the block is (0,0). pair f_top; pair f_left; pair f_right; pair f_bottom; pair f_topleft; pair f_topright; pair f_bottomleft; pair f_bottomright; void operator init(pair z) { center=z; } void operator init(real x, real y) { center=(x,y); } pair shift(transform t=identity()) { return t*center-f_center; } // Returns the relative position along the boundary of the block. pair f_position(real x); // Returns the absolute position along the boundary of the block. pair position(real x, transform t=identity()) { return shift(t)+f_position(x); } // These eight functions return the appropriate location on the block // in absolute coordinates. pair top(transform t=identity()) { return shift(t)+f_top; } pair bottom(transform t=identity()) { return shift(t)+f_bottom; } pair left(transform t=identity()) { return shift(t)+f_left; } pair right(transform t=identity()) { return shift(t)+f_right; } pair topleft(transform t=identity()) { return shift(t)+f_topleft; } pair topright(transform t=identity()) { return shift(t)+f_topright; } pair bottomleft(transform t=identity()) { return shift(t)+f_bottomleft; } pair bottomright(transform t=identity()) { return shift(t)+f_bottomright; } // Return a frame representing the block. frame draw(pen p=currentpen); // Store optional label on outgoing edge. Label label; // Store rectilinear path directions. pair[] dirs; // Store optional arrow. arrowbar arrow=None; }; // Construct a rectangular block with header and body objects. block rectangle(object header, object body, pair center=(0,0), pen headerpen=mediumgray, pen bodypen=invisible, pen drawpen=currentpen, real dx=3, real minheaderwidth=minblockwidth, real minheaderheight=minblockwidth, real minbodywidth=minblockheight, real minbodyheight=minblockheight) { frame fbody=body.f; frame fheader=header.f; pair mheader=min(fheader); pair Mheader=max(fheader); pair mbody=min(fbody); pair Mbody=max(fbody); pair bound0=Mheader-mheader; pair bound1=Mbody-mbody; real width=max(bound0.x,bound1.x); pair z0=maxbound((width+2dx,bound0.y+2dx),(minbodywidth,minbodyheight)); pair z1=maxbound((width+2dx,bound1.y+2dx),(minheaderwidth,minheaderheight)); path shape=(0,0)--(0,z1.y)--(0,z0.y+z1.y)--(z0.x,z0.y+z1.y)--z1--(z0.x,0)-- cycle; block block; block.draw=new frame(pen p) { frame block; filldraw(block,shift(0,z1.y)*box((0,0),z0),headerpen,drawpen); add(block,shift(-0.5*(Mheader+mheader))*fheader,(0,z1.y)+0.5z0); filldraw(block,box((0,0),z1),bodypen,drawpen); add(block,shift(-0.5*(Mbody+mbody))*fbody,0.5z1); return block; }; block.f_position=new pair(real x) { return point(shape,x); }; block.f_center=interp(point(shape,0),point(shape,3),0.5); block.f_bottomleft=point(shape,0); block.f_bottom=point(shape,5.5); block.f_bottomright=point(shape,5); block.f_right=point(shape,4.5); block.f_topright=point(shape,3); block.f_top=point(shape,2.5); block.f_topleft=point(shape,2); block.f_left=point(shape,0.5); block.center=center; block.size=point(shape,3); return block; } // As above, but without the header. block rectangle(object body, pair center=(0,0), pen fillpen=invisible, pen drawpen=currentpen, real dx=3, real minwidth=minblockwidth, real minheight=minblockheight) { frame f=body.f; pair m=min(f); pair M=max(f); pair z=maxbound(M-m+dx*(2,2),(minwidth,minheight)); path shape=box((0,0),z); block block; block.draw=new frame(pen p) { frame block; filldraw(block,shape,fillpen,drawpen); add(block,shift(-0.5*(M+m))*f,0.5z); return block; }; block.f_position=new pair(real x) { return point(shape,x); }; block.f_center=0.5*z; block.center=center; block.size=z; block.f_bottomleft=point(shape,0); block.f_bottom=point(shape,0.5); block.f_bottomright=point(shape,1); block.f_right=point(shape,1.5); block.f_topright=point(shape,2); block.f_top=point(shape,2.5); block.f_topleft=point(shape,3); block.f_left=point(shape,3.5); return block; } block parallelogram(object body, pair center=(0,0), pen fillpen=invisible, pen drawpen=currentpen, real dx=3, real slope=2, real minwidth=minblockwidth, real minheight=minblockheight) { frame f=body.f; pair m=min(f); pair M=max(f); pair bound=maxbound(M-m+dx*(0,2),(minwidth,minheight)); real skew=bound.y/slope; real a=bound.x+skew; real b=bound.y; path shape=(0,0)--(a,0)--(a+skew,b)--(skew,b)--cycle; block block; block.draw=new frame(pen p) { frame block; filldraw(block,shape,fillpen,drawpen); add(block,shift(-0.5*(M+m))*f,((a+skew)/2,b/2)); return block; }; block.f_position=new pair(real x) { return point(shape,x); }; block.f_center=((a+skew)/2,b/2); block.center=center; block.size=(a+skew,b); block.f_bottomleft=(0,0); block.f_bottom=((a+skew)/2,0); block.f_bottomright=(a,0); block.f_right=(a+skew/2,b/2); block.f_topright=(a+skew,b); block.f_top=((a+skew)/2,b); block.f_topleft=(skew,b); block.f_left=(skew/2,b/2); return block; } block diamond(object body, pair center=(0,0), pen fillpen=invisible, pen drawpen=currentpen, real ds=5, real dw=1, real height=20, real minwidth=minblockwidth, real minheight=minblockheight) { frame f=body.f; pair m=min(f); pair M=max(f); pair bound=maxbound(M-m,(minwidth,minheight)); real e=ds; real a=0.5bound.x-dw; real b=0.5bound.y; real c=b+height; real arg=a^2+b^2+c^2-2b*c-e^2; real denom=e^2-a^2; real slope=arg >= 0 && denom != 0 ? (a*(c-b)-e*sqrt(arg))/denom : 1.0; real d=abs(c/slope); path shape=(2d,c)--(d,2c)--(0,c)--(d,0)--cycle; block block; block.draw=new frame(pen p) { frame block; filldraw(block,shape,fillpen,drawpen); add(block,shift(-0.5*(M+m))*f,(d,c)); return block; }; block.f_position=new pair(real x) { return point(shape,x); }; block.f_center=(point(shape,1).x,point(shape,0).y); block.center=center; block.size=(point(shape,0).x,point(shape,1).y); block.f_bottomleft=point(shape,2.5); block.f_bottom=point(shape,3); block.f_bottomright=point(shape,3.5); block.f_right=point(shape,0); block.f_topright=point(shape,0.5); block.f_top=point(shape,1); block.f_topleft=point(shape,1.5); block.f_left=point(shape,2); return block; } block circle(object body, pair center=(0,0), pen fillpen=invisible, pen drawpen=currentpen, real dr=3, real mindiameter=mincirclediameter) { frame f=body.f; pair m=min(f); pair M=max(f); real r=max(0.5length(M-m)+dr,0.5mindiameter); path shape=(0,r)..(r,2r)..(2r,r)..(r,0)..cycle; block block; block.draw=new frame(pen p) { frame block; filldraw(block,shape,fillpen,drawpen); add(block,shift(-0.5*(M+m))*f,(r,r)); return block; }; block.f_position=new pair(real x) { return point(shape,x); }; block.f_center=(r,r); block.center=center; block.size=(2r,2r); block.f_left=point(shape,0); block.f_topleft=point(shape,0.5); block.f_top=point(shape,1); block.f_topright=point(shape,1.5); block.f_right=point(shape,2); block.f_bottomright=point(shape,2.5); block.f_bottom=point(shape,3); block.f_bottomleft=point(shape,3.5); return block; } block roundrectangle(object body, pair center=(0,0), pen fillpen=invisible, pen drawpen=currentpen, real ds=5, real dw=0, real minwidth=minblockwidth, real minheight=minblockheight) { frame f=body.f; pair m=min(f); pair M=max(f); pair bound=maxbound(M-m,(minwidth,minheight)); real a=bound.x; real b=bound.y; path shape=(0,ds+dw)--(0,ds+b-dw){up}..{right} (ds+dw,2ds+b)--(ds+a-dw,2ds+b){right}..{down} (2ds+a,ds+b-dw)--(2ds+a,ds+dw){down}..{left} (ds+a-dw,0)--(ds+dw,0){left}..{up}cycle; block block; block.draw=new frame(pen p) { frame block; filldraw(block,shape,fillpen,drawpen); add(block,shift(-0.5*(M+m))*f,(ds,ds)+0.5bound); return block; }; block.f_position=new pair(real x) { return point(shape,x); }; block.f_center=(ds+0.5a,ds+0.5b); block.center=center; block.size=(2ds+a,2ds+b); block.f_bottomleft=point(shape,7.5); block.f_bottom=point(shape,6.5); block.f_bottomright=point(shape,5.5); block.f_right=point(shape,4.5); block.f_topright=point(shape,3.5); block.f_top=point(shape,2.5); block.f_topleft=point(shape,1.5); block.f_left=point(shape,0.5); return block; } block bevel(object body, pair center=(0,0), pen fillpen=invisible, pen drawpen=currentpen, real dh=5, real dw=5, real minwidth=minblockwidth, real minheight=minblockheight) { frame f=body.f; pair m=min(f); pair M=max(f); pair bound=maxbound(M-m,(minwidth,minheight)); real a=bound.x; real b=0.5bound.y; path shape=(2dw+a,b+dh)--(dw+a,2b+2dh)--(dw,2b+2dh)--(0,b+dh)--(dw,0)-- (dw+a,0)--cycle; block block; block.draw=new frame(pen p) { frame block; filldraw(block,shape,fillpen,drawpen); add(block,shift(-0.5*(M+m))*f,(0.5bound+(dw,dh))); return block; }; block.f_position=new pair(real x) { return point(shape,x); }; block.f_center=(dw+0.5a,dh+b); block.center=center; block.size=(2dw+a,2dh+2b); block.f_bottomleft=point(shape,4); block.f_bottom=point(shape,4.5); block.f_bottomright=point(shape,5); block.f_right=point(shape,0); block.f_topright=point(shape,1); block.f_top=point(shape,1.5); block.f_topleft=point(shape,2); block.f_left=point(shape,3); return block; } path path(pair point[] ... flowdir dir[]) { path line=point[0]; pair current, prev=point[0]; for(int i=1; i < point.length; ++i) { if(i-1 >= dir.length || dir[i-1] == Horizontal) current=(point[i].x,point[i-1].y); else current=(point[i-1].x,point[i].y); if(current != prev) { line=line--current; prev=current; } current=point[i]; if(current != prev) { line=line--current; prev=current; } } return line; } void draw(picture pic=currentpicture, block block, pen p=currentpen) { pic.add(new void(frame f, transform t) { add(f,shift(block.shift(t))*block.draw(p)); },true); pic.addBox(block.center,block.center, -0.5*block.size+min(p),0.5*block.size+max(p)); } typedef block blockconnector(block, block); blockconnector blockconnector(picture pic, transform t, pen p=currentpen, margin margin=PenMargin) { return new block(block b1, block b2) { if(b1.dirs.length == 0) { if(abs(b1.center.y-b2.center.y) < sqrtEpsilon) { // horizontally aligned b1.dirs[0]=b1.center.x < b2.center.x ? right : left; blockconnector(pic,t,p,margin)(b1,b2); } else if(abs(b1.center.x-b2.center.x) < sqrtEpsilon) { // vertically aligned b1.dirs[0]=b1.center.y < b2.center.y ? up : down; blockconnector(pic,t,p,margin)(b1,b2); } else { if(abs(b1.center.y-b2.center.y) < abs(b1.center.x-b2.center.x)) { b1.dirs[0]=b1.center.x < b2.center.x ? right : left; b1.dirs[1]=b1.center.y < b2.center.y ? up : down; blockconnector(pic,t,p,margin)(b1,b2); } else { b1.dirs[0]=b1.center.y < b2.center.y ? up : down; b1.dirs[1]=b1.center.x < b2.center.x ? right : left; blockconnector(pic,t,p,margin)(b1,b2); } } return b2; } // compute the link for given directions (and label if any) pair[] dirs=copy(b1.dirs); // deep copy pair current,prev; pair dir=dirs[0]; if(dir == up) prev=b1.top(t); if(dir == down) prev=b1.bottom(t); if(dir == left) prev=b1.left(t); if(dir == right) prev=b1.right(t); path line=prev; arrowbar arrow=b1.arrow; int i; for(i=1; i < dirs.length-1; ++i) { if(abs(length(dirs[i-1])-1) < sqrtEpsilon) current=prev+t*dirs[i-1]*defaultexcursion; else current=prev+t*dirs[i-1]; if(current != prev) { line=line--current; prev=current; } } dir=dirs[dirs.length-1]; current=0; if(dir == up) current=b2.bottom(t); if(dir == down) current=b2.top(t); if(dir == left) current=b2.right(t); if(dir == right) current=b2.left(t); if(abs(dirs[i-1].y) < sqrtEpsilon && abs(prev.x-current.x) > sqrtEpsilon) { prev=(current.x,prev.y); line=line--prev; // horizontal } else if(abs(dirs[i-1].x) < sqrtEpsilon && abs(prev.y-current.y) > sqrtEpsilon) { prev=(prev.x,current.y); line=line--prev; } if(current != prev) line=line--current; draw(pic,b1.label,line,p,arrow,margin); b1.label=""; b1.dirs.delete(); b1.arrow=None; return b2; }; } struct Dir { pair z; void operator init(pair z) {this.z=z;} } Dir Right=Dir(right); Dir Left=Dir(left); Dir Up=Dir(up); Dir Down=Dir(down); // Add a label to the current link block operator --(block b1, Label label) { b1.label=label; return b1; } // Add a direction to the current link block operator --(block b1, Dir dir) { b1.dirs.push(dir.z); return b1; } // Add an arrowbar to the current link block operator --(block b, arrowbar arrowbar) { b.arrow=arrowbar; return b; } asymptote-2.37/base/fontsize.asy000066400000000000000000000000431265434602500167670ustar00rootroot00000000000000if(latex()) usepackage("type1cm"); asymptote-2.37/base/geometry.asy000066400000000000000000011636741265434602500170060ustar00rootroot00000000000000// geometry.asy // Copyright (C) 2007 // Author: Philippe IVALDI 2007/09/01 // http://www.piprime.fr/ // This program is free software ; you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation ; either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY ; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // You should have received a copy of the GNU Lesser General Public License // along with this program ; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // COMMENTARY: // An Asymptote geometry module. // THANKS: // Special thanks to Olivier Guibé for his help in mathematical issues. // BUGS: // CODE: import math; import markers; // A rotation in the direction dir limited to [-90,90] // This is useful for rotating text along a line in the direction dir. private transform rotate(explicit pair dir) { real angle=degrees(dir); if(angle > 90 && angle < 270) angle -= 180; return rotate(angle); } // *=======================================================* // *........................HEADER.........................* /**/ real epsgeo = 10 * sqrt(realEpsilon);/*Variable used in the approximate calculations.*/ /**/ void addMargins(picture pic = currentpicture, real lmargin = 0, real bmargin = 0, real rmargin = lmargin, real tmargin = bmargin, bool rigid = true, bool allObject = true) {/*Add margins to 'pic' with respect to the current bounding box of 'pic'. If 'rigid' is false, margins are added iff an infinite curve will be prolonged on the margin. If 'allObject' is false, fixed - size objects (such as labels and arrowheads) will be ignored.*/ pair m = allObject ? truepoint(pic, SW) : point(pic, SW); pair M = allObject ? truepoint(pic, NE) : point(pic, NE); if(rigid) { draw(m - inverse(pic.calculateTransform()) * (lmargin, bmargin), invisible); draw(M + inverse(pic.calculateTransform()) * (rmargin, tmargin), invisible); } else pic.addBox(m, M, -(lmargin, bmargin), (rmargin, tmargin)); } real approximate(real t) { real ot = t; if(abs(t - ceil(t)) < epsgeo) ot = ceil(t); else if(abs(t - floor(t)) < epsgeo) ot = floor(t); return ot; } real[] approximate(real[] T) { return map(approximate, T); } /**/ real binomial(real n, real k) {/*Return n!/((n - k)!*k!)*/ return gamma(n + 1)/(gamma(n - k + 1) * gamma(k + 1)); } /**/ real rf(real x, real y, real z) {/*Computes Carlson's elliptic integral of the first kind. x, y, and z must be non negative, and at most one can be zero.*/ real ERRTOL = 0.0025, TINY = 1.5e-38, BIG = 3e37, THIRD = 1/3, C1 = 1/24, C2 = 0.1, C3 = 3/44, C4 = 1/14; real alamb, ave, delx, dely, delz, e2, e3, sqrtx, sqrty, sqrtz, xt, yt, zt; if(min(x, y, z) < 0 || min(x + y, x + z, y + z) < TINY || max(x, y, z) > BIG) abort("rf: invalid arguments."); xt = x; yt = y; zt = z; do { sqrtx = sqrt(xt); sqrty = sqrt(yt); sqrtz = sqrt(zt); alamb = sqrtx * (sqrty + sqrtz) + sqrty * sqrtz; xt = 0.25 * (xt + alamb); yt = 0.25 * (yt + alamb); zt = 0.25 * (zt + alamb); ave = THIRD * (xt + yt + zt); delx = (ave - xt)/ave; dely = (ave - yt)/ave; delz = (ave - zt)/ave; } while(max(fabs(delx), fabs(dely), fabs(delz)) > ERRTOL); e2 = delx * dely - delz * delz; e3 = delx * dely * delz; return (1.0 + (C1 * e2 - C2 - C3 * e3) * e2 + C4 * e3)/sqrt(ave); } /**/ real rd(real x, real y, real z) {/*Computes Carlson's elliptic integral of the second kind. x and y must be positive, and at most one can be zero. z must be non negative.*/ real ERRTOL = 0.0015, TINY = 1e-25, BIG = 4.5 * 10.0^21, C1 = (3/14), C2 = (1/6), C3 = (9/22), C4 = (3/26), C5 = (0.25 * C3), C6 = (1.5 * C4); real alamb, ave, delx, dely, delz, ea, eb, ec, ed, ee, fac, sqrtx, sqrty, sqrtz, sum, xt, yt, zt; if (min(x, y) < 0 || min(x + y, z) < TINY || max(x, y, z) > BIG) abort("rd: invalid arguments"); xt = x; yt = y; zt = z; sum = 0; fac = 1; do { sqrtx = sqrt(xt); sqrty = sqrt(yt); sqrtz = sqrt(zt); alamb = sqrtx * (sqrty + sqrtz) + sqrty * sqrtz; sum += fac/(sqrtz * (zt + alamb)); fac = 0.25 * fac; xt = 0.25 * (xt + alamb); yt = 0.25 * (yt + alamb); zt = 0.25 * (zt + alamb); ave = 0.2 * (xt + yt + 3.0 * zt); delx = (ave - xt)/ave; dely = (ave - yt)/ave; delz = (ave - zt)/ave; } while (max(fabs(delx), fabs(dely), fabs(delz)) > ERRTOL); ea = delx * dely; eb = delz * delz; ec = ea - eb; ed = ea - 6 * eb; ee = ed + ec + ec; return 3 * sum + fac * (1.0 + ed * (-C1 + C5 * ed - C6 * delz * ee) +delz * (C2 * ee + delz * (-C3 * ec + delz * C4 * ea)))/(ave * sqrt(ave)); } /**/ real elle(real phi, real k) {/*Legendre elliptic integral of the 2nd kind, evaluated using Carlson's functions RD and RF. The argument ranges are -infinity < phi < +infinity, 0 <= k * sin(phi) <= 1.*/ real result; if (phi >= 0 && phi <= pi/2) { real cc, q, s; s = sin(phi); cc = cos(phi)^2; q = (1 - s * k) * (1 + s * k); result = s * (rf(cc, q, 1) - (s * k)^2 * rd(cc, q, 1)/3); } else if (phi <= pi && phi >= 0) { result = 2 * elle(pi/2, k) - elle(pi - phi, k); } else if (phi <= 3 * pi/2 && phi >= 0) { result = 2 * elle(pi/2, k) + elle(phi - pi, k); } else if (phi <= 2 * pi && phi >= 0) { result = 4 * elle(pi/2, k) - elle(2 * pi - phi, k); } else if (phi >= 0) { int nb = floor(0.5 * phi/pi); result = nb * elle(2 * pi, k) + elle(phi%(2 * pi), k); } else result = -elle(-phi, k); return result; } /**/ pair[] intersectionpoints(pair A, pair B, real a, real b, real c, real d, real f, real g) {/*Intersection points with the line (AB) and the quadric curve a * x^2 + b * x * y + c * y^2 + d * x + f * y + g = 0 given in the default coordinate system*/ pair[] op; real ap = B.y - A.y, bpp = A.x - B.x, cp = A.y * B.x - A.x * B.y; real sol[]; if (abs(ap) > epsgeo) { real aa = ap * c + a * bpp^2/ap - b * bpp, bb = ap * f - bpp * d + 2 * a * bpp * cp/ap - b * cp, cc = ap * g - cp * d + a * cp^2/ap; sol = quadraticroots(aa, bb, cc); for (int i = 0; i < sol.length; ++i) { op.push((-bpp * sol[i]/ap - cp/ap, sol[i])); } } else { real aa = a * bpp, bb = d * bpp - b * cp, cc = g * bpp - cp * f + c * cp^2/bpp; sol = quadraticroots(aa, bb, cc); for (int i = 0; i < sol.length; ++i) { op.push((sol[i], -cp/bpp)); } } return op; } /**/ pair[] intersectionpoints(pair A, pair B, real[] equation) {/*Return the intersection points of the line AB with the conic whose an equation is equation[0] * x^2 + equation[1] * x * y + equation[2] * y^2 + equation[3] * x + equation[4] * y + equation[5] = 0*/ if(equation.length != 6) abort("intersectionpoints: bad length of array for a conic equation."); return intersectionpoints(A, B, equation[0], equation[1], equation[2], equation[3], equation[4], equation[5]); } // *........................HEADER.........................* // *=======================================================* // *=======================================================* // *......................COORDINATES......................* real EPS = sqrt(realEpsilon); /**/ typedef pair convert(pair);/*Function type to convert pair in an other coordinate system.*/ /**/ typedef real abs(pair);/*Function type to calculate modulus of pair.*/ /**/ typedef real dot(pair, pair);/*Function type to calculate dot product.*/ /**/ typedef pair polar(real, real);/*Function type to calculate the coordinates from the polar coordinates.*/ /**/ struct coordsys {/*This structure represents a coordinate system in the plane.*/ /**/ restricted convert relativetodefault = new pair(pair m){return m;};/*Convert a pair given relatively to this coordinate system to the pair relatively to the default coordinate system.*/ /**/ restricted convert defaulttorelative = new pair(pair m){return m;};/*Convert a pair given relatively to the default coordinate system to the pair relatively to this coordinate system.*/ /**/ restricted dot dot = new real(pair m, pair n){return dot(m, n);};/*Return the dot product of this coordinate system.*/ /**/ restricted abs abs = new real(pair m){return abs(m);};/*Return the modulus of a pair in this coordinate system.*/ /**/ restricted polar polar = new pair(real r, real a){return (r * cos(a), r * sin(a));};/*Polar coordinates routine of this coordinate system.*/ /**/ restricted pair O = (0, 0), i = (1, 0), j = (0, 1);/*Origin and units vector.*/ /**/ void init(convert rtd, convert dtr, polar polar, dot dot) {/*The default constructor of the coordinate system.*/ this.relativetodefault = rtd; this.defaulttorelative = dtr; this.polar = polar; this.dot = dot; this.abs = new real(pair m){return sqrt(dot(m, m));};; this.O = rtd((0, 0)); this.i = rtd((1, 0)) - O; this.j = rtd((0, 1)) - O; } }/**/ /**/ bool operator ==(coordsys c1, coordsys c2) {/*Return true iff the coordinate system have the same origin and units vector.*/ return c1.O == c2.O && c1.i == c2.i && c1.j == c2.j; } /**/ coordsys cartesiansystem(pair O = (0, 0), pair i, pair j) {/*Return the Cartesian coordinate system (O, i, j).*/ coordsys R; real[][] P = {{0, 0}, {0, 0}}; real[][] iP; P[0][0] = i.x; P[0][1] = j.x; P[1][0] = i.y; P[1][1] = j.y; iP = inverse(P); real ni = abs(i); real nj = abs(j); real ij = angle(j) - angle(i); pair rtd(pair m) { return O + (P[0][0] * m.x + P[0][1] * m.y, P[1][0] * m.x + P[1][1] * m.y); } pair dtr(pair m) { m-=O; return (iP[0][0] * m.x + iP[0][1] * m.y, iP[1][0] * m.x + iP[1][1] * m.y); } pair polar(real r, real a) { real ca = sin(ij - a)/(ni * sin(ij)); real sa = sin(a)/(nj * sin(ij)); return r * (ca, sa); } real tdot(pair m, pair n) { return m.x * n.x * ni^2 + m.y * n.y * nj^2 + (m.x * n.y + n.x * m.y) * dot(i, j); } R.init(rtd, dtr, polar, tdot); return R; } /**/ void show(picture pic = currentpicture, Label lo = "$O$", Label li = "$\vec{\imath}$", Label lj = "$\vec{\jmath}$", coordsys R, pen dotpen = currentpen, pen xpen = currentpen, pen ypen = xpen, pen ipen = red, pen jpen = ipen, arrowbar arrow = Arrow) {/*Draw the components (O, i, j, x - axis, y - axis) of 'R'.*/ unravel R; dot(pic, O, dotpen); drawline(pic, O, O + i, xpen); drawline(pic, O, O + j, ypen); draw(pic, li, O--(O + i), ipen, arrow); Label lj = lj.copy(); lj.align(lj.align, unit(I * j)); draw(pic, lj, O--(O + j), jpen, arrow); draw(pic, lj, O--(O + j), jpen, arrow); Label lo = lo.copy(); lo.align(lo.align, -2 * dir(O--O + i, O--O + j)); lo.p(dotpen); label(pic, lo, O); } /**/ pair operator /(pair p, coordsys R) {/*Return the xy - coordinates of 'p' relatively to the coordinate system 'R'. For example, if R = cartesiansystem((1, 2), (1, 0), (0, 1)), (0, 0)/R is (-1, -2).*/ return R.defaulttorelative(p); } /**/ pair operator *(coordsys R, pair p) {/*Return the coordinates of 'p' given in the xy - coordinates 'R'. For example, if R = cartesiansystem((1, 2), (1, 0), (0, 1)), R * (0, 0) is (1, 2).*/ return R.relativetodefault(p); } /**/ path operator *(coordsys R, path g) {/*Return the reconstructed path applying R * pair to each node, pre and post control point of 'g'.*/ guide og = R * point(g, 0); real l = length(g); for(int i = 1; i <= l; ++i) { pair P = R * point(g, i); pair post = R * postcontrol(g, i - 1); pair pre = R * precontrol(g, i); if(i == l && (cyclic(g))) og = og..controls post and pre..cycle; else og = og..controls post and pre..P; } return og; } /**/ coordsys operator *(transform t,coordsys R) {/*Provide transform * coordsys. Note that shiftless(t) is applied to R.i and R.j.*/ coordsys oc; oc = cartesiansystem(t * R.O, shiftless(t) * R.i, shiftless(t) * R.j); return oc; } /**/ restricted coordsys defaultcoordsys = cartesiansystem(0, (1, 0), (0, 1));/*One can always refer to the default coordinate system using this constant.*/ /**/ coordsys currentcoordsys = defaultcoordsys;/*The coordinate system used by default.*/ /**/ struct point {/*This structure replaces the pair to embed its coordinate system. For example, if 'P = point(cartesiansystem((1, 2), i, j), (0, 0))', P is equal to the pair (1, 2).*/ /**/ coordsys coordsys;/*The coordinate system of this point.*/ restricted pair coordinates;/*The coordinates of this point relatively to the coordinate system 'coordsys'.*/ restricted real x, y;/*The xpart and the ypart of 'coordinates'.*/ /**/ real m = 1;/*Used to cast mass<->point.*/ void init(coordsys R, pair coordinates, real mass) {/*The constructor.*/ this.coordsys = R; this.coordinates = coordinates; this.x = coordinates.x; this.y = coordinates.y; this.m = mass; } }/**/ /**/ point point(coordsys R, pair p, real m = 1) {/*Return the point which has the coodinates 'p' in the coordinate system 'R' and the mass 'm'.*/ point op; op.init(R, p, m); return op; } /**/ point point(explicit pair p, real m) {/*Return the point which has the coodinates 'p' in the current coordinate system and the mass 'm'.*/ point op; op.init(currentcoordsys, p, m); return op; } /**/ point point(coordsys R, explicit point M, real m = M.m) {/*Return the point of 'R' which has the coordinates of 'M' and the mass 'm'. Do not confuse this routine with the further routine 'changecoordsys'.*/ point op; op.init(R, M.coordinates, M.m); return op; } /**/ point changecoordsys(coordsys R, point M) {/*Return the point 'M' in the coordinate system 'coordsys'. In other words, the returned point marks the same plot as 'M' does.*/ point op; coordsys mco = M.coordsys; op.init(R, R.defaulttorelative(mco.relativetodefault(M.coordinates)), M.m); return op; } /**/ pair coordinates(point M) {/*Return the coordinates of 'M' in its coordinate system.*/ return M.coordinates; } /**/ bool samecoordsys(bool warn = true ... point[] M) {/*Return true iff all the points have the same coordinate system. If 'warn' is true and the coordinate systems are different, a warning is sent.*/ bool ret = true; coordsys t = M[0].coordsys; for (int i = 1; i < M.length; ++i) { ret = (t == M[i].coordsys); if(!ret) break; t = M[i].coordsys; } if(warn && !ret) warning("coodinatesystem", "the coordinate system of two objects are not the same. The operation will be done relative to the default coordinate system."); return ret; } /**/ point[] standardizecoordsys(coordsys R = currentcoordsys, bool warn = true ... point[] M) {/*Return the points with the same coordinate system 'R'. If 'warn' is true and the coordinate systems are different, a warning is sent.*/ point[] op = new point[]; op = M; if(!samecoordsys(warn ... M)) for (int i = 1; i < M.length; ++i) op[i] = changecoordsys(R, M[i]); return op; } /**/ pair operator cast(point P) {/*Cast point to pair.*/ return P.coordsys.relativetodefault(P.coordinates); } /**/ pair[] operator cast(point[] P) {/*Cast point[] to pair[].*/ pair[] op; for (int i = 0; i < P.length; ++i) { op.push((pair)P[i]); } return op; } /**/ point operator cast(pair p) {/*Cast pair to point relatively to the current coordinate system 'currentcoordsys'.*/ return point(currentcoordsys, p); } /**/ point[] operator cast(pair[] p) {/*Cast pair[] to point[] relatively to the current coordinate system 'currentcoordsys'.*/ pair[] op; for (int i = 0; i < p.length; ++i) { op.push((point)p[i]); } return op; } /**/ pair locate(point P) {/*Return the coordinates of 'P' in the default coordinate system.*/ return P.coordsys * P.coordinates; } /**/ point locate(pair p) {/*Return the point in the current coordinate system 'currentcoordsys'.*/ return p; //automatic casting 'pair to point'. } /**/ point operator *(real x, explicit point P) {/*Multiply the coordinates (not the mass) of 'P' by 'x'.*/ return point(P.coordsys, x * P.coordinates, P.m); } /**/ point operator /(explicit point P, real x) {/*Divide the coordinates (not the mass) of 'P' by 'x'.*/ return point(P.coordsys, P.coordinates/x, P.m); } /**/ point operator /(real x, explicit point P) {/**/ return point(P.coordsys, x/P.coordinates, P.m); } /**/ point operator -(explicit point P) {/*-P. The mass is inchanged.*/ return point(P.coordsys, -P.coordinates, P.m); } /**/ point operator +(explicit point P1, explicit point P2) {/*Provide 'point + point'. If the two points haven't the same coordinate system, a warning is sent and the returned point has the default coordinate system 'defaultcoordsys'. The masses are added.*/ point[] P = standardizecoordsys(P1, P2); coordsys R = P[0].coordsys; return point(R, P[0].coordinates + P[1].coordinates, P1.m + P2.m); } /**/ point operator +(explicit point P1, explicit pair p2) {/*Provide 'point + pair'. The pair 'p2' is supposed to be coordinates relatively to the coordinates system of 'P1'. The mass is not changed.*/ coordsys R = currentcoordsys; return point(R, P1.coordinates + point(R, p2).coordinates, P1.m); } point operator +(explicit pair p1, explicit point p2) { return p2 + p1; } /**/ point operator -(explicit point P1, explicit point P2) {/*Provide 'point - point'.*/ return P1 + (-P2); } /**/ point operator -(explicit point P1, explicit pair p2) {/*Provide 'point - pair'. The pair 'p2' is supposed to be coordinates relatively to the coordinates system of 'P1'.*/ return P1 + (-p2); } point operator -(explicit pair p1, explicit point P2) { return p1 + (-P2); } /**/ point operator *(transform t, explicit point P) {/*Provide 'transform * point'. Note that the transforms scale, xscale, yscale and rotate are carried out relatively the default coordinate system 'defaultcoordsys' which is not desired for point defined in an other coordinate system. On can use scale(real, point), xscale(real, point), yscale(real, point), rotate(real, point), scaleO(real), xscaleO(real), yscaleO(real) and rotateO(real) (described further) to change the coordinate system of reference.*/ coordsys R = P.coordsys; return point(R, (t * locate(P))/R, P.m); } /**/ point operator *(explicit point P1, explicit point P2) {/*Provide 'point * point'. The resulted mass is the mass of P2*/ point[] P = standardizecoordsys(P1, P2); coordsys R = P[0].coordsys; return point(R, P[0].coordinates * P[1].coordinates, P2.m); } /**/ point operator *(explicit point P1, explicit pair p2) {/*Provide 'point * pair'. The pair 'p2' is supposed to be the coordinates of the point in the coordinates system of 'P1'. 'pair * point' is also defined.*/ point P = point(P1.coordsys, p2, P1.m); return P1 * P; } point operator *(explicit pair p1, explicit point p2) { return p2 * p1; } /**/ bool operator ==(explicit point M, explicit point N) {/*Provide the test 'M == N' wish returns true iff MN < EPS*/ return abs(locate(M) - locate(N)) < EPS; } /**/ bool operator !=(explicit point M, explicit point N) {/*Provide the test 'M != N' wish return true iff MN >= EPS*/ return !(M == N); } /**/ guide operator cast(point p) {/*Cast point to guide.*/ return locate(p); } /**/ path operator cast(point p) {/*Cast point to path.*/ return locate(p); } /**/ void dot(picture pic = currentpicture, Label L, explicit point Z, align align = NoAlign, string format = defaultformat, pen p = currentpen) {/**/ Label L = L.copy(); L.position(locate(Z)); if(L.s == "") { if(format == "") format = defaultformat; L.s = "("+format(format, Z.x)+", "+format(format, Z.y)+")"; } L.align(align, E); L.p(p); dot(pic, locate(Z), p); add(pic, L); } /**/ real abs(coordsys R, pair m) {/*Return the modulus |m| in the coordinate system 'R'.*/ return R.abs(m); } /**/ real abs(explicit point M) {/*Return the modulus |M| in its coordinate system.*/ return M.coordsys.abs(M.coordinates); } /**/ real length(explicit point M) {/*Return the modulus |M| in its coordinate system (same as 'abs').*/ return M.coordsys.abs(M.coordinates); } /**/ point conj(explicit point M) {/*Conjugate.*/ return point(M.coordsys, conj(M.coordinates), M.m); } /**/ real degrees(explicit point M, coordsys R = M.coordsys, bool warn = true) {/*Return the angle of M (in degrees) relatively to 'R'.*/ return (degrees(locate(M) - R.O, warn) - degrees(R.i))%360; } /**/ real angle(explicit point M, coordsys R = M.coordsys, bool warn = true) {/*Return the angle of M (in radians) relatively to 'R'.*/ return radians(degrees(M, R, warn)); } /**/ bool finite(explicit point p) {/*Avoid to compute 'finite((pair)(infinite_point))'.*/ return finite(p.coordinates); } /**/ real dot(point A, point B) {/*Return the dot product in the coordinate system of 'A'.*/ point[] P = standardizecoordsys(A.coordsys, A, B); return P[0].coordsys.dot(P[0].coordinates, P[1].coordinates); } /**/ real dot(point A, explicit pair B) {/*Return the dot product in the default coordinate system. dot(explicit pair, point) is also defined.*/ return dot(locate(A), B); } real dot(explicit pair A, point B) { return dot(A, locate(B)); } /**/ transform rotateO(real a) {/*Rotation around the origin of the current coordinate system.*/ return rotate(a, currentcoordsys.O); }; /**/ transform projection(point A, point B) {/*Return the orthogonal projection on the line (AB).*/ pair dir = unit(locate(A) - locate(B)); pair a = locate(A); real cof = dir.x * a.x + dir.y * a.y; real tx = a.x - dir.x * cof; real txx = dir.x^2; real txy = dir.x * dir.y; real ty = a.y - dir.y * cof; real tyx = txy; real tyy = dir.y^2; transform t = (tx, ty, txx, txy, tyx, tyy); return t; } /**/ transform projection(point A, point B, point C, point D, bool safe = false) {/*Return the (CD) parallel projection on (AB). If 'safe = true' and (AB)//(CD) return the identity. If 'safe = false' and (AB)//(CD) return an infinity scaling.*/ pair a = locate(A); pair u = unit(locate(B) - locate(A)); pair v = unit(locate(D) - locate(C)); real c = u.x * a.y - u.y * a.x; real d = (conj(u) * v).y; if (abs(d) < epsgeo) { return safe ? identity() : scale(infinity); } real tx = c * v.x/d; real ty = c * v.y/d; real txx = u.x * v.y/d; real txy = -u.x * v.x/d; real tyx = u.y * v.y/d; real tyy = -u.y * v.x/d; transform t = (tx, ty, txx, txy, tyx, tyy); return t; } /**/ transform scale(real k, point M) {/*Homothety.*/ pair P = locate(M); return shift(P) * scale(k) * shift(-P); } /**/ transform xscale(real k, point M) {/*xscale from 'M' relatively to the x - axis of the coordinate system of 'M'.*/ pair P = locate(M); real a = degrees(M.coordsys.i); return (shift(P) * rotate(a)) * xscale(k) * (rotate(-a) * shift(-P)); } /**/ transform yscale(real k, point M) {/*yscale from 'M' relatively to the y - axis of the coordinate system of 'M'.*/ pair P = locate(M); real a = degrees(M.coordsys.j) - 90; return (shift(P) * rotate(a)) * yscale(k) * (rotate(-a) * shift(-P)); } /**/ transform scale(real k, point A, point B, point C, point D, bool safe = false) {/* (help me for English translation...) If 'safe = true' and (AB)//(CD) return the identity. If 'safe = false' and (AB)//(CD) return a infinity scaling.*/ pair a = locate(A); pair u = unit(locate(B) - locate(A)); pair v = unit(locate(D) - locate(C)); real c = u.x * a.y - u.y * a.x; real d = (conj(u) * v).y; real d = (conj(u) * v).y; if (abs(d) < epsgeo) { return safe ? identity() : scale(infinity); } real tx = (1 - k) * c * v.x/d; real ty = (1 - k) * c * v.y/d; real txx = (1 - k) * u.x * v.y/d + k; real txy = (k - 1) * u.x * v.x/d; real tyx = (1 - k) * u.y * v.y/d; real tyy = (k - 1) * u.y * v.x/d + k; transform t = (tx, ty, txx, txy, tyx, tyy); return t; } /**/ transform scaleO(real x) {/*Homothety from the origin of the current coordinate system.*/ return scale(x, (0, 0)); } /**/ transform xscaleO(real x) {/*xscale from the origin and relatively to the current coordinate system.*/ return scale(x, (0, 0), (0, 1), (0, 0), (1, 0)); } /**/ transform yscaleO(real x) {/*yscale from the origin and relatively to the current coordinate system.*/ return scale(x, (0, 0), (1, 0), (0, 0), (0, 1)); } /**/ struct vector {/*Like a point but casting to pair, adding etc does not take account of the origin of the coordinate system.*/ point v;/*Coordinates as a point (embed coordinate system and pair).*/ }/**/ /**/ point operator cast(vector v) {/*Cast vector 'v' to point 'M' so that OM = v.*/ return v.v; } /**/ vector operator cast(pair v) {/*Cast pair to vector relatively to the current coordinate system 'currentcoordsys'.*/ vector ov; ov.v = point(currentcoordsys, v); return ov; } /**/ vector operator cast(explicit point v) {/*A point can be interpreted like a vector using the code '(vector)a_point'.*/ vector ov; ov.v = v; return ov; } /**/ pair operator cast(explicit vector v) {/*Cast vector to pair (the coordinates of 'v' in the default coordinate system).*/ return locate(v.v) - v.v.coordsys.O; } /**/ align operator cast(vector v) {/*Cast vector to align.*/ return (pair)v; } /**/ vector vector(coordsys R = currentcoordsys, pair v) {/*Return the vector of 'R' which has the coordinates 'v'.*/ vector ov; ov.v = point(R, v); return ov; } /**/ vector vector(point M) {/*Return the vector OM, where O is the origin of the coordinate system of 'M'. Useful to write 'vector(P - M);' instead of '(vector)(P - M)'.*/ return M; } /**/ point point(explicit vector u) {/*Return the point M so that OM = u, where O is the origin of the coordinate system of 'u'.*/ return u.v; } /**/ pair locate(explicit vector v) {/*Return the coordinates of 'v' in the default coordinate system (like casting vector to pair).*/ return (pair)v; } /**/ void show(Label L, vector v, pen p = currentpen, arrowbar arrow = Arrow) {/*Draw the vector v (from the origin of its coordinate system).*/ coordsys R = v.v.coordsys; draw(L, R.O--v.v, p, arrow); } /**/ vector changecoordsys(coordsys R, vector v) {/*Return the vector 'v' relatively to coordinate system 'R'.*/ vector ov; ov.v = point(R, (locate(v) + R.O)/R); return ov; } /**/ vector operator *(real x, explicit vector v) {/*Provide real * vector.*/ return x * v.v; } /**/ vector operator /(explicit vector v, real x) {/*Provide vector/real*/ return v.v/x; } /**/ vector operator *(transform t, explicit vector v) {/*Provide transform * vector.*/ return t * v.v; } /**/ vector operator *(explicit point M, explicit vector v) {/*Provide point * vector*/ return M * v.v; } /**/ point operator +(point M, explicit vector v) {/*Return 'M' shifted by 'v'.*/ return shift(locate(v)) * M; } /**/ point operator -(point M, explicit vector v) {/*Return 'M' shifted by '-v'.*/ return shift(-locate(v)) * M; } /**/ vector operator -(explicit vector v) {/*Provide -v.*/ return -v.v; } /**/ point operator +(explicit pair m, explicit vector v) {/*The pair 'm' is supposed to be the coordinates of a point in the current coordinates system 'currentcoordsys'. Return this point shifted by the vector 'v'.*/ return locate(m) + v; } /**/ point operator -(explicit pair m, explicit vector v) {/*The pair 'm' is supposed to be the coordinates of a point in the current coordinates system 'currentcoordsys'. Return this point shifted by the vector '-v'.*/ return m + (-v); } /**/ vector operator +(explicit vector v1, explicit vector v2) {/*Provide vector + vector. If the two vector haven't the same coordinate system, the returned vector is relative to the default coordinate system (without warning).*/ coordsys R = v1.v.coordsys; if(samecoordsys(false, v1, v2)){R = defaultcoordsys;} return vector(R, (locate(v1) + locate(v2))/R); } /**/ vector operator -(explicit vector v1, explicit vector v2) {/*Provide vector - vector. If the two vector haven't the same coordinate system, the returned vector is relative to the default coordinate system (without warning).*/ return v1 + (-v2); } /**/ bool operator ==(explicit vector u, explicit vector v) {/*Return true iff |u - v|*/ return abs(u - v) < EPS; } /**/ bool collinear(vector u, vector v) {/*Return 'true' iff the vectors 'u' and 'v' are collinear.*/ return abs(ypart((conj((pair)u) * (pair)v))) < EPS; } /**/ vector unit(point M) {/*Return the unit vector according to the modulus of its coordinate system.*/ return M/abs(M); } /**/ vector unit(vector u) {/*Return the unit vector according to the modulus of its coordinate system.*/ return u.v/abs(u.v); } /**/ real degrees(vector v, coordsys R = v.v.coordsys, bool warn = true) {/*Return the angle of 'v' (in degrees) relatively to 'R'.*/ return (degrees(locate(v), warn) - degrees(R.i))%360; } /**/ real angle(explicit vector v, coordsys R = v.v.coordsys, bool warn = true) {/*Return the angle of 'v' (in radians) relatively to 'R'.*/ return radians(degrees(v, R, warn)); } /**/ vector conj(explicit vector u) {/*Conjugate.*/ return conj(u.v); } /**/ transform rotate(explicit vector dir) {/*A rotation in the direction 'dir' limited to [-90, 90] This is useful for rotating text along a line in the direction dir. rotate(explicit point dir) is also defined. */ return rotate(locate(dir)); } transform rotate(explicit point dir){return rotate(locate(vector(dir)));} // *......................COORDINATES......................* // *=======================================================* // *=======================================================* // *.........................BASES.........................* /**/ point origin = point(defaultcoordsys, (0, 0));/*The origin of the current coordinate system.*/ /**/ point origin(coordsys R = currentcoordsys) {/*Return the origin of the coordinate system 'R'.*/ return point(R, (0, 0)); //use automatic casting; } /**/ real linemargin = 0;/*Margin used to draw lines.*/ /**/ real linemargin() {/*Return the margin used to draw lines.*/ return linemargin; } /**/ pen addpenline = squarecap;/*Add this property to the drawing pen of "finish" lines.*/ pen addpenline(pen p) { return addpenline + p; } /**/ pen addpenarc = squarecap;/*Add this property to the drawing pen of arcs.*/ pen addpenarc(pen p) {return addpenarc + p;} /**/ string defaultmassformat = "$\left(%L;%.4g\right)$";/*Format used to construct the default label of masses.*/ /**/ int sgnd(real x) {/*Return the -1 if x < 0, 1 if x >= 0.*/ return (x == 0) ? 1 : sgn(x); } int sgnd(int x) { return (x == 0) ? 1 : sgn(x); } /**/ bool defined(point P) {/*Return true iff the coordinates of 'P' are finite.*/ return finite(P.coordinates); } /**/ bool onpath(picture pic = currentpicture, path g, point M, pen p = currentpen) {/*Return true iff 'M' is on the path drawn with the pen 'p' in 'pic'.*/ transform t = inverse(pic.calculateTransform()); return intersect(g, shift(locate(M)) * scale(linewidth(p)/2) * t * unitcircle).length > 0; } /**/ bool sameside(point M, point N, point O) {/*Return 'true' iff 'M' and 'N' are same side of the point 'O'.*/ pair m = M, n = N, o = O; return dot(m - o, n - o) >= -epsgeo; } /**/ bool between(point M, point O, point N) {/*Return 'true' iff 'O' is between 'M' and 'N'.*/ return (!sameside(N, M, O) || M == O || N == O); } typedef path pathModifier(path); pathModifier NoModifier = new path(path g){return g;}; private void Drawline(picture pic = currentpicture, Label L = "", pair P, bool dirP = true, pair Q, bool dirQ = true, align align = NoAlign, pen p = currentpen, arrowbar arrow = None, Label legend = "", marker marker = nomarker, pathModifier pathModifier = NoModifier) {/* Add the two parameters 'dirP' and 'dirQ' to the native routine 'drawline' of the module 'math'. Segment [PQ] will be prolonged in direction of P if 'dirP = true', in direction of Q if 'dirQ = true'. If 'dirP = dirQ = true', the behavior is that of the native 'drawline'. Add all the other parameters of 'Draw'.*/ pic.add(new void (frame f, transform t, transform T, pair m, pair M) { picture opic; // Reduce the bounds by the size of the pen. m -= min(p) - (linemargin(), linemargin()); M -= max(p) + (linemargin(), linemargin()); // Calculate the points and direction vector in the transformed space. t = t * T; pair z = t * P; pair q = t * Q; pair v = q - z; // path g; pair ptp, ptq; real cp = dirP ? 1:0; real cq = dirQ ? 1:0; // Handle horizontal and vertical lines. if(v.x == 0) { if(m.x <= z.x && z.x <= M.x) if (dot(v, m - z) < 0) { ptp = (z.x, z.y + cp * (m.y - z.y)); ptq = (z.x, q.y + cq * (M.y - q.y)); } else { ptq = (z.x, q.y + cq * (m.y - q.y)); ptp = (z.x, z.y + cp * (M.y - z.y)); } } else if(v.y == 0) { if (dot(v, m - z) < 0) { ptp = (z.x + cp * (m.x - z.x), z.y); ptq = (q.x + cq * (M.x - q.x), z.y); } else { ptq = (q.x + cq * (m.x - q.x), z.y); ptp = (z.x + cp * (M.x - z.x), z.y); } } else { // Calculate the maximum and minimum t values allowed for the // parametric equation z + t * v real mx = (m.x - z.x)/v.x, Mx = (M.x - z.x)/v.x; real my = (m.y - z.y)/v.y, My = (M.y - z.y)/v.y; real tmin = max(v.x > 0 ? mx : Mx, v.y > 0 ? my : My); real tmax = min(v.x > 0 ? Mx : mx, v.y > 0 ? My : my); pair pmin = z + tmin * v; pair pmax = z + tmax * v; if(tmin <= tmax) { ptp = z + cp * tmin * v; ptq = z + (cq == 0 ? v:tmax * v); } } path g = ptp--ptq; if (length(g)>0) { if(L.s != "") { Label lL = L.copy(); if(L.defaultposition) lL.position(Relative(.9)); lL.p(p); lL.out(opic, g); } g = pathModifier(g); if(linetype(p).length == 0){ pair m = midpoint(g); pen tp; tp = dirP ? p : addpenline(p); draw(opic, pathModifier(m--ptp), tp); tp = dirQ ? p : addpenline(p); draw(opic, pathModifier(m--ptq), tp); } else { draw(opic, g, p); } marker.markroutine(opic, marker.f, g); arrow(opic, g, p, NoMargin); add(f, opic.fit()); } }); } /**/ void clipdraw(picture pic = currentpicture, Label L = "", path g, align align = NoAlign, pen p = currentpen, arrowbar arrow = None, arrowbar bar = None, real xmargin = 0, real ymargin = xmargin, Label legend = "", marker marker = nomarker) {/*Draw the path 'g' on 'pic' clipped to the bounding box of 'pic'.*/ if(L.s != "") { picture tmp; label(tmp, L, g, p); add(pic, tmp); } pic.add(new void (frame f, transform t, transform T, pair m, pair M) { // Reduce the bounds by the size of the pen and the margins. m += min(p) + (xmargin, ymargin); M -= max(p) + (xmargin, ymargin); path bound = box(m, M); picture tmp; draw(tmp, "", t * T * g, align, p, arrow, bar, NoMargin, legend, marker); clip(tmp, bound); add(f, tmp.fit()); }); } /**/ void distance(picture pic = currentpicture, Label L = "", point A, point B, bool rotated = true, real offset = 3mm, pen p = currentpen, pen joinpen = invisible, arrowbar arrow = Arrows(NoFill)) {/*Draw arrow between A and B (from FAQ).*/ pair A = A, B = B; path g = A--B; transform Tp = shift(-offset * unit(B - A) * I); pic.add(new void(frame f, transform t) { picture opic; path G = Tp * t * g; transform id = identity(); transform T = rotated ? rotate(B - A) : id; Label L = L.copy(); L.align(L.align, Center); if(abs(ypart((conj(A - B) * L.align.dir))) < epsgeo && L.filltype == NoFill) L.filltype = UnFill(1); draw(opic, T * L, G, p, arrow, Bars, PenMargins); pair Ap = t * A, Bp = t * B; draw(opic, (Ap--Tp * Ap)^^(Bp--Tp * Bp), joinpen); add(f, opic.fit()); }, true); pic.addBox(min(g), max(g), Tp * min(p), Tp * max(p)); } /**/ real perpfactor = 1;/*Factor for drawing perpendicular symbol.*/ /**/ void perpendicularmark(picture pic = currentpicture, point z, explicit pair align, explicit pair dir = E, real size = 0, pen p = currentpen, margin margin = NoMargin, filltype filltype = NoFill) {/*Draw a perpendicular symbol at z aligned in the direction align relative to the path z--z + dir. dir(45 + n * 90), where n in N*, are common values for 'align'.*/ p = squarecap + p; if(size == 0) size = perpfactor * 3mm + sqrt(1 + linewidth(p)) - 1; frame apic; pair d1 = size * align * unit(dir) * dir(-45); pair d2 = I * d1; path g = d1--d1 + d2--d2; g = margin(g, p).g; draw(apic, g, p); if(filltype != NoFill) filltype.fill(apic, (relpoint(g, 0) - relpoint(g, 0.5)+ relpoint(g, 1))--g--cycle, p + solid); add(pic, apic, locate(z)); } /**/ void perpendicularmark(picture pic = currentpicture, point z, vector align, vector dir = E, real size = 0, pen p = currentpen, margin margin = NoMargin, filltype filltype = NoFill) {/*Draw a perpendicular symbol at z aligned in the direction align relative to the path z--z + dir. dir(45 + n * 90), where n in N, are common values for 'align'.*/ perpendicularmark(pic, z, (pair)align, (pair)dir, size, p, margin, filltype); } /**/ void perpendicularmark(picture pic = currentpicture, point z, explicit pair align, path g, real size = 0, pen p = currentpen, margin margin = NoMargin, filltype filltype = NoFill) {/*Draw a perpendicular symbol at z aligned in the direction align relative to the path z--z + dir(g, 0). dir(45 + n * 90), where n in N, are common values for 'align'.*/ perpendicularmark(pic, z, align, dir(g, 0), size, p, margin, filltype); } /**/ void perpendicularmark(picture pic = currentpicture, point z, vector align, path g, real size = 0, pen p = currentpen, margin margin = NoMargin, filltype filltype = NoFill) {/*Draw a perpendicular symbol at z aligned in the direction align relative to the path z--z + dir(g, 0). dir(45 + n * 90), where n in N, are common values for 'align'.*/ perpendicularmark(pic, z, (pair)align, dir(g, 0), size, p, margin, filltype); } /**/ void markrightangle(picture pic = currentpicture, point A, point O, point B, real size = 0, pen p = currentpen, margin margin = NoMargin, filltype filltype = NoFill) {/*Mark the angle AOB with a perpendicular symbol.*/ pair Ap = A, Bp = B, Op = O; pair dir = Ap - Op; real a1 = degrees(dir); pair align = rotate(-a1) * unit(dir(Op--Ap, Op--Bp)); if (margin == NoMargin) margin = TrueMargin(linewidth(currentpen)/2, linewidth(currentpen)/2); perpendicularmark(pic = pic, z = O, align = align, dir = dir, size = size, p = p, margin = margin, filltype = filltype); } /**/ bool simeq(point A, point B, real fuzz = epsgeo) {/*Return true iff abs(A - B) < fuzz. This routine is used internally to know if two points are equal, in particular by the operator == in 'point == point'.*/ return (abs(A - B) < fuzz); } bool simeq(point a, real b, real fuzz = epsgeo) { coordsys R = a.coordsys; return (abs(a - point(R, ((pair)b)/R)) < fuzz); } /**/ pair attract(pair m, path g, real fuzz = 0) {/*Return the nearest point (A PAIR) of 'm' which is on the path g. 'fuzz' is the argument 'fuzz' of 'intersect'.*/ if(intersect(m, g, fuzz).length > 0) return m; pair p; real step = 1, r = 0; real[] t; static real eps = sqrt(realEpsilon); do {// Find a radius for intersection r += step; t = intersect(shift(m) * scale(r) * unitcircle, g); } while(t.length <= 0); p = point(g, t[1]); real rm = 0, rM = r; while(rM - rm > eps) { r = (rm + rM)/2; t = intersect(shift(m) * scale(r) * unitcircle, g, fuzz); if(t.length <= 0) { rm = r; } else { rM = r; p = point(g, t[1]); } } return p; } /**/ point attract(point M, path g, real fuzz = 0) {/*Return the nearest point (A POINT) of 'M' which is on the path g. 'fuzz' is the argument 'fuzz' of 'intersect'.*/ return point(M.coordsys, attract(locate(M), g)/M.coordsys); } /**/ real[] intersect(path g, explicit pair p, real fuzz = 0) {/**/ fuzz = fuzz <= 0 ? sqrt(realEpsilon) : fuzz; real[] or; real r = realEpsilon; do{ or = intersect(g, shift(p) * scale(r) * unitcircle, fuzz); r *= 2; } while(or.length == 0); return or; } /**/ real[] intersect(path g, explicit point P, real fuzz = epsgeo) {/**/ return intersect(g, locate(P), fuzz); } // *.........................BASES.........................* // *=======================================================* // *=======================================================* // *.........................LINES.........................* /**/ struct line {/*This structure provides the objects line, semi - line and segment oriented from A to B. All the calculus with this structure will be as exact as Asymptote can do. For a full precision, you must not cast 'line' to 'path' excepted for drawing routines.*/ /**/ restricted point A,B;/*Two line's points with same coordinate system.*/ bool extendA,extendB;/*If true,extend 'l' in direction of A (resp. B).*/ restricted vector u,v;/*u = unit(AB) = direction vector,v = normal vector.*/ restricted real a,b,c;/*Coefficients of the equation ax + by + c = 0 in the coordinate system of 'A'.*/ restricted real slope, origin;/*Slope and ordinate at the origin.*/ /**/ line copy() {/*Copy a line in a new instance.*/ line l = new line; l.A = A; l.B = B; l.a = a; l.b = b; l.c = c; l.slope = slope; l.origin = origin; l.u = u; l.v = v; l.extendA = extendA; l.extendB = extendB; return l; } /**/ void init(point A, bool extendA = true, point B, bool extendB = true) {/*Initialize line. If 'extendA' is true, the "line" is infinite in the direction of A.*/ point[] P = standardizecoordsys(A, B); this.A = P[0]; this.B = P[1]; this.a = B.y - A.y; this.b = A.x - B.x; this.c = A.y * B.x - A.x * B.y; this.slope= (this.b == 0) ? infinity : -this.a/this.b; this.origin = (this.b == 0) ? (this.c == 0) ? 0:infinity : -this.c/this.b; this.u = unit(P[1]-P[0]); // int tmp = sgnd(this.slope); // this.u = (dot((pair)this.u, N) >= 0) ? tmp * this.u : -tmp * this.u; this.v = rotate(90, point(P[0].coordsys, (0, 0))) * this.u; this.extendA = extendA; this.extendB = extendB; } }/**/ /**/ line line(point A, bool extendA = true, point B, bool extendB = true) {/*Return the line passing through 'A' and 'B'. If 'extendA' is true, the "line" is infinite in the direction of A. A "line" can be half-line or segment.*/ if (A == B) abort("line: the points must be distinct."); line l; l.init(A, extendA, B, extendB); return l; } /**/ struct segment {/*.*/ restricted point A, B;// Extremity. restricted vector u, v;// u = direction vector, v = normal vector. restricted real a, b, c;// Coefficients of the équation ax + by + c = 0 restricted real slope, origin; segment copy() { segment s = new segment; s.A = A; s.B = B; s.a = a; s.b = b; s.c = c; s.slope = slope; s.origin = origin; s.u = u; s.v = v; return s; } void init(point A, point B) { line l; l.init(A, B); this.A = l.A; this.B = l.B; this.a = l.a; this.b = l.b; this.c = l.c; this.slope = l.slope; this.origin = l.origin; this.u = l.u; this.v = l.v; } }/**/ /**/ segment segment(point A, point B) {/*Return the segment whose the extremities are A and B.*/ segment s; s.init(A, B); return s; } /**/ real length(segment s) {/*Return the length of 's'.*/ return abs(s.A - s.B); } /**/ line operator cast(segment s) {/*A segment is casted to a "finite line".*/ return line(s.A, false, s.B, false); } /**/ segment operator cast(line l) {/*Cast line 'l' to segment [l.A l.B].*/ return segment(l.A, l.B); } /**/ line operator *(transform t, line l) {/*Provide transform * line*/ return line(t * l.A, l.extendA, t * l.B, l.extendB); } /**/ line operator /(line l, real x) {/*Provide l/x. Return the line passing through l.A/x and l.B/x.*/ return line(l.A/x, l.extendA, l.B/x, l.extendB); } line operator /(line l, int x){return line(l.A/x, l.B/x);} /**/ line operator *(real x, line l) {/*Provide x * l. Return the line passing through x * l.A and x * l.B.*/ return line(x * l.A, l.extendA, x * l.B, l.extendB); } line operator *(int x, line l){return line(x * l.A, l.extendA, x * l.B, l.extendB);} /**/ line operator *(point M, line l) {/*Provide point * line. Return the line passing through unit(M) * l.A and unit(M) * l.B.*/ return line(unit(M) * l.A, l.extendA, unit(M) * l.B, l.extendB); } /**/ line operator +(line l, vector u) {/*Provide line + vector (and so line + point). Return the line 'l' shifted by 'u'.*/ return line(l.A + u, l.extendA, l.B + u, l.extendB); } /**/ line operator -(line l, vector u) {/*Provide line - vector (and so line - point). Return the line 'l' shifted by '-u'.*/ return line(l.A - u, l.extendA, l.B - u, l.extendB); } /**/ line[] operator ^^(line l1, line l2) {/*Provide line^^line. Return the line array {l1, l2}.*/ line[] ol; ol.push(l1); ol.push(l2); return ol; } /**/ line[] operator ^^(line l1, line[] l2) {/*Provide line^^line[]. Return the line array {l1, l2[0], l2[1]...}. line[]^^line is also defined.*/ line[] ol; ol.push(l1); for (int i = 0; i < l2.length; ++i) { ol.push(l2[i]); } return ol; } line[] operator ^^(line[] l2, line l1) { line[] ol = l2; ol.push(l1); return ol; } /**/ line[] operator ^^(line l1[], line[] l2) {/*Provide line[]^^line[]. Return the line array {l1[0], l1[1], ..., l2[0], l2[1], ...}.*/ line[] ol = l1; for (int i = 0; i < l2.length; ++i) { ol.push(l2[i]); } return ol; } /**/ bool sameside(point M, point P, line l) {/*Return 'true' iff 'M' and 'N' are same side of the line (or on the line) 'l'.*/ pair A = l.A, B = l.B, m = M, p = P; pair mil = (A + B)/2; pair mA = rotate(90, mil) * A; pair mB = rotate(-90, mil) * A; return (abs(m - mA) <= abs(m - mB)) == (abs(p - mA) <= abs(p - mB)); // transform proj = projection(l.A, l.B); // point Mp = proj * M; // point Pp = proj * P; // dot(Mp);dot(Pp); // return dot(locate(Mp - M), locate(Pp - P)) >= 0; } /**/ line line(segment s) {/*Return the line passing through 's.A' and 's.B'.*/ return line(s.A, s.B); } /**/ segment segment(line l) {/*Return the segment whose extremities are 'l.A' and 'l.B'.*/ return segment(l.A, l.B); } /**/ point midpoint(segment s) {/*Return the midpoint of 's'.*/ return 0.5 * (s.A + s.B); } /**/ void write(explicit line l) {/*Write some informations about 'l'.*/ write("A = "+(string)((pair)l.A)); write("Extend A = "+(l.extendA ? "true" : "false")); write("B = "+(string)((pair)l.B)); write("Extend B = "+(l.extendB ? "true" : "false")); write("u = "+(string)((pair)l.u)); write("v = "+(string)((pair)l.v)); write("a = "+(string) l.a); write("b = "+(string) l.b); write("c = "+(string) l.c); write("slope = "+(string) l.slope); write("origin = "+(string) l.origin); } /**/ void write(explicit segment s) {/*Write some informations about 's'.*/ write("A = "+(string)((pair)s.A)); write("B = "+(string)((pair)s.B)); write("u = "+(string)((pair)s.u)); write("v = "+(string)((pair)s.v)); write("a = "+(string) s.a); write("b = "+(string) s.b); write("c = "+(string) s.c); write("slope = "+(string) s.slope); write("origin = "+(string) s.origin); } /**/ bool operator ==(line l1, line l2) {/*Provide the test 'line == line'.*/ return (collinear(l1.u, l2.u) && abs(ypart((locate(l1.A) - locate(l1.B))/(locate(l1.A) - locate(l2.B)))) < epsgeo && l1.extendA == l2.extendA && l1.extendB == l2.extendB); } /**/ bool operator !=(line l1, line l2) {/*Provide the test 'line != line'.*/ return !(l1 == l2); } /**/ bool operator @(point m, line l) {/*Provide the test 'point @ line'. Return true iff 'm' is on the 'l'.*/ point M = changecoordsys(l.A.coordsys, m); if (abs(l.a * M.x + l.b * M.y + l.c) >= epsgeo) return false; if (l.extendA && l.extendB) return true; if (!l.extendA && !l.extendB) return between(l.A, M, l.B); if (l.extendA) return sameside(M, l.A, l.B); return sameside(M, l.B, l.A); } /**/ coordsys coordsys(line l) {/*Return the coordinate system in which 'l' is defined.*/ return l.A.coordsys; } /**/ line reverse(line l) {/*Permute the points 'A' and 'B' of 'l' and so its orientation.*/ return line(l.B, l.extendB, l.A, l.extendA); } /**/ line extend(line l) {/*Return the infinite line passing through 'l.A' and 'l.B'.*/ line ol = l.copy(); ol.extendA = true; ol.extendB = true; return ol; } /**/ line complementary(explicit line l) {/*Return the complementary of a half-line with respect of the full line 'l'.*/ if (l.extendA && l.extendB) abort("complementary: the parameter is not a half-line."); point origin = l.extendA ? l.B : l.A; point ptdir = l.extendA ? rotate(180, l.B) * l.A : rotate(180, l.A) * l.B; return line(origin, false, ptdir); } /**/ line[] complementary(explicit segment s) {/*Return the two half-lines of origin 's.A' and 's.B' respectively.*/ line[] ol = new line[2]; ol[0] = complementary(line(s.A, false, s.B)); ol[1] = complementary(line(s.A, s.B, false)); return ol; } /**/ line Ox(coordsys R = currentcoordsys) {/*Return the x-axis of 'R'.*/ return line(point(R, (0, 0)), point(R, E)); } /**/ restricted line Ox = Ox();/*the x-axis of the default coordinate system.*/ /**/ line Oy(coordsys R = currentcoordsys) {/*Return the y-axis of 'R'.*/ return line(point(R, (0, 0)), point(R, N)); } /**/ restricted line Oy = Oy();/*the y-axis of the default coordinate system.*/ /**/ line line(real a, point A = point(currentcoordsys, (0, 0))) {/*Return the line passing through 'A' with an angle (in the coordinate system of A) 'a' in degrees. line(point, real) is also defined.*/ return line(A, A + point(A.coordsys, A.coordsys.polar(1, radians(a)))); } line line(point A = point(currentcoordsys, (0, 0)), real a) { return line(a, A); } line line(int a, point A = point(currentcoordsys, (0, 0))) { return line((real)a, A); } /**/ line line(coordsys R = currentcoordsys, real slope, real origin) {/*Return the line defined by slope and y-intercept relative to 'R'.*/ if (slope == infinity || slope == -infinity) abort("The slope is infinite. Please, use the routine 'vline'."); return line(point(R, (0, origin)), point(R, (1, origin + slope))); } /**/ line line(coordsys R = currentcoordsys, real a, real b, real c) {/*Retrun the line defined by equation relative to 'R'.*/ if (a == 0 && b == 0) abort("line: inconsistent equation..."); pair M; M = (a == 0) ? (0, -c/b) : (-c/a, 0); return line(point(R, M), point(R, M + (-b, a))); } /**/ line vline(coordsys R = currentcoordsys) {/*Return a vertical line in 'R' passing through the origin of 'R'.*/ point P = point(R, (0, 0)); point PP = point(R, (R.O + N)/R); return line(P, PP); } /**/ restricted line vline = vline();/*The vertical line in the current coordinate system passing through the origin of this system.*/ /**/ line hline(coordsys R = currentcoordsys) {/*Return a horizontal line in 'R' passing through the origin of 'R'.*/ point P = point(R, (0, 0)); point PP = point(R, (R.O + E)/R); return line(P, PP); } /**/ line hline = hline();/*The horizontal line in the current coordinate system passing through the origin of this system.*/ /**/ line changecoordsys(coordsys R, line l) {/*Return the line 'l' in the coordinate system 'R'.*/ point A = changecoordsys(R, l.A); point B = changecoordsys(R, l.B); return line(A, B); } /**/ transform scale(real k, line l1, line l2, bool safe = false) {/*Return the dilatation with respect to 'l1' in the direction of 'l2'.*/ return scale(k, l1.A, l1.B, l2.A, l2.B, safe); } /**/ transform reflect(line l) {/*Return the reflect about the line 'l'.*/ return reflect((pair)l.A, (pair)l.B); } /**/ transform reflect(line l1, line l2, bool safe = false) {/*Return the reflect about the line 'l1' in the direction of 'l2'.*/ return scale(-1.0, l1, l2, safe); } /**/ point[] intersectionpoints(line l, path g) {/*Return all points of intersection of the line 'l' with the path 'g'.*/ // TODO utiliser la version 1.44 de intersections(path g, pair p, pair q) // real [] t = intersections(g, l.A, l.B); // coordsys R = coordsys(l); // return sequence(new point(int n){return point(R, point(g, t[n])/R);}, t.length); real [] t; pair[] op; pair A = l.A; pair B = l.B; real dy = B.y - A.y, dx = A.x - B.x, lg = length(g); for (int i = 0; i < lg; ++i) { pair z0 = point(g, i), z1 = point(g, i + 1), c0 = postcontrol(g, i), c1 = precontrol(g, i + 1), t3 = z1 - z0 - 3 * c1 + 3 * c0, t2 = 3 * z0 + 3 * c1 - 6 * c0, t1 = 3 * c0 - 3z0; real a = dy * t3.x + dx * t3.y, b = dy * t2.x + dx * t2.y, c = dy * t1.x + dx * t1.y, d = dy * z0.x + dx * z0.y + A.y * B.x - A.x * B.y; t = cubicroots(a, b, c, d); for (int j = 0; j < t.length; ++j) if ( t[j]>=0 && ( t[j]<1 || ( t[j] == 1 && (i == lg - 1) && !cyclic(g) ) ) ) { op.push(point(g, i + t[j])); } } point[] opp; for (int i = 0; i < op.length; ++i) opp.push(point(coordsys(l), op[i]/coordsys(l))); return opp; } /**/ point intersectionpoint(line l1, line l2) {/*Return the point of intersection of line 'l1' with 'l2'. If 'l1' and 'l2' have an infinity or none point of intersection, this routine return (infinity, infinity).*/ point[] P = standardizecoordsys(l1.A, l1.B, l2.A, l2.B); coordsys R = P[0].coordsys; pair p = extension(P[0], P[1], P[2], P[3]); if(finite(p)){ point p = point(R, p/R); if (p @ l1 && p @ l2) return p; } return point(R, (infinity, infinity)); } /**/ line parallel(point M, line l) {/*Return the line parallel to 'l' passing through 'M'.*/ point A, B; if (M.coordsys != coordsys(l)) { A = changecoordsys(M.coordsys, l.A); B = changecoordsys(M.coordsys, l.B); } else {A = l.A;B = l.B;} return line(M, M - A + B); } /**/ line parallel(point M, explicit vector dir) {/*Return the line of direction 'dir' and passing through 'M'.*/ return line(M, M + locate(dir)); } /**/ line parallel(point M, explicit pair dir) {/*Return the line of direction 'dir' and passing through 'M'.*/ return line(M, M + vector(currentcoordsys, dir)); } /**/ bool parallel(line l1, line l2, bool strictly = false) {/*Return 'true' if 'l1' and 'l2' are (strictly ?) parallel.*/ bool coll = collinear(l1.u, l2.u); return strictly ? coll && (l1 != l2) : coll; } /**/ bool concurrent(... line[] l) {/*Returns true if all the lines 'l' are concurrent.*/ if (l.length < 3) abort("'concurrent' needs at least for three lines ..."); pair point = intersectionpoint(l[0], l[1]); bool conc; for (int i = 2; i < l.length; ++i) { pair pt = intersectionpoint(l[i - 1], l[i]); conc = simeq(pt, point); if (!conc) break; } return conc; } /**/ transform projection(line l) {/*Return the orthogonal projection on 'l'.*/ return projection(l.A, l.B); } /**/ transform projection(line l1, line l2, bool safe = false) {/*Return the projection on (AB) in parallel of (CD). If 'safe = true' and (l1)//(l2) return the identity. If 'safe = false' and (l1)//(l2) return a infinity scaling.*/ return projection(l1.A, l1.B, l2.A, l2.B, safe); } /**/ transform vprojection(line l, bool safe = false) {/*Return the projection on 'l' in parallel of N--S. If 'safe' is 'true' the projected point keeps the same place if 'l' is vertical.*/ coordsys R = defaultcoordsys; return projection(l, line(point(R, N), point(R, S)), safe); } /**/ transform hprojection(line l, bool safe = false) {/*Return the projection on 'l' in parallel of E--W. If 'safe' is 'true' the projected point keeps the same place if 'l' is horizontal.*/ coordsys R = defaultcoordsys; return projection(l, line(point(R, E), point(R, W)), safe); } /**/ line perpendicular(point M, line l) {/*Return the perpendicular line of 'l' passing through 'M'.*/ point Mp = projection(l) * M; point A = Mp == l.A ? l.B : l.A; return line(Mp, rotate(90, Mp) * A); } /**/ line perpendicular(point M, explicit vector normal) {/*Return the line passing through 'M' whose normal is \param{normal}.*/ return perpendicular(M, line(M, M + locate(normal))); } /**/ line perpendicular(point M, explicit pair normal) {/*Return the line passing through 'M' whose normal is \param{normal} (given in the currentcoordsys).*/ return perpendicular(M, line(M, M + vector(currentcoordsys, normal))); } /**/ bool perpendicular(line l1, line l2) {/*Return 'true' if 'l1' and 'l2' are perpendicular.*/ return abs(dot(locate(l1.u), locate(l2.u))) < epsgeo ; } /**/ real angle(line l, coordsys R = coordsys(l)) {/*Return the angle of the oriented line 'l', in radian, in the interval ]-pi, pi] and relatively to 'R'.*/ return angle(l.u, R, false); } /**/ real degrees(line l, coordsys R = coordsys(l)) {/*Returns the angle of the oriented line 'l' in degrees, in the interval [0, 360[ and relatively to 'R'.*/ return degrees(angle(l, R)); } /**/ real sharpangle(line l1, line l2) {/*Return the measure in radians of the sharp angle formed by 'l1' and 'l2'.*/ vector u1 = l1.u; vector u2 = (dot(l1.u, l2.u) < 0) ? -l2.u : l2.u; real a12 = angle(locate(u2)) - angle(locate(u1)); a12 = a12%(sgnd(a12) * pi); if (a12 <= -pi/2) { a12 += pi; } else if (a12 > pi/2) { a12 -= pi; } return a12; } /**/ real angle(line l1, line l2) {/*Return the measure in radians of oriented angle (l1.u, l2.u).*/ return angle(locate(l2.u)) - angle(locate(l1.u)); } /**/ real degrees(line l1, line l2) {/*Return the measure in degrees of the angle formed by the oriented lines 'l1' and 'l2'.*/ return degrees(angle(l1, l2)); } /**/ real sharpdegrees(line l1, line l2) {/*Return the measure in degrees of the sharp angle formed by 'l1' and 'l2'.*/ return degrees(sharpangle(l1, l2)); } /**/ line bisector(line l1, line l2, real angle = 0, bool sharp = true) {/*Return the bisector of the angle formed by 'l1' and 'l2' rotated by the angle 'angle' (in degrees) around intersection point of 'l1' with 'l2'. If 'sharp' is true (the default), this routine returns the bisector of the sharp angle. Note that the returned line inherit of coordinate system of 'l1'.*/ line ol; if (l1 == l2) return l1; point A = intersectionpoint(l1, l2); if (finite(A)) { if(sharp) ol = rotate(sharpdegrees(l1, l2)/2 + angle, A) * l1; else { coordsys R = coordsys(l1); pair a = A, b = A + l1.u, c = A + l2.u; pair pp = extension(a, a + dir(a--b, a--c), b, b + dir(b--a, b--c)); return rotate(angle, A) * line(A, point(R, pp/R)); } } else { ol = l1; } return ol; } /**/ line sector(int n = 2, int p = 1, line l1, line l2, real angle = 0, bool sharp = true) {/*Return the p-th nth-sector of the angle formed by the oriented line 'l1' and 'l2' rotated by the angle 'angle' (in degrees) around the intersection point of 'l1' with 'l2'. If 'sharp' is true (the default), this routine returns the bisector of the sharp angle. Note that the returned line inherit of coordinate system of 'l1'.*/ line ol; if (l1 == l2) return l1; point A = intersectionpoint(l1, l2); if (finite(A)) { if(sharp) ol = rotate(p * sharpdegrees(l1, l2)/n + angle, A) * l1; else { ol = rotate(p * degrees(l1, l2)/n + angle, A) * l1; } } else { ol = l1; } return ol; } /**/ line bisector(point A, point B, point C, point D, real angle = 0, bool sharp = true) {/*Return the bisector of the angle formed by the lines (AB) and (CD). .*/ point[] P = standardizecoordsys(A, B, C, D); return bisector(line(P[0], P[1]), line(P[2], P[3]), angle, sharp); } /**/ line bisector(segment s, real angle = 0) {/*Return the bisector of the segment line 's' rotated by 'angle' (in degrees) around the midpoint of 's'.*/ coordsys R = coordsys(s); point m = midpoint(s); vector dir = rotateO(90) * unit(s.A - m); return rotate(angle, m) * line(m + dir, m - dir); } /**/ line bisector(point A, point B, real angle = 0) {/*Return the bisector of the segment line [AB] rotated by 'angle' (in degrees) around the midpoint of [AB].*/ point[] P = standardizecoordsys(A, B); return bisector(segment(P[0], P[1]), angle); } /**/ real distance(point M, line l) {/*Return the distance from 'M' to 'l'. distance(line, point) is also defined.*/ point A = changecoordsys(defaultcoordsys, l.A); point B = changecoordsys(defaultcoordsys, l.B); line ll = line(A, B); pair m = locate(M); return abs(ll.a * m.x + ll.b * m.y + ll.c)/sqrt(ll.a^2 + ll.b^2); } real distance(line l, point M) { return distance(M, l); } /**/ void draw(picture pic = currentpicture, Label L = "", line l, bool dirA = l.extendA, bool dirB = l.extendB, align align = NoAlign, pen p = currentpen, arrowbar arrow = None, Label legend = "", marker marker = nomarker, pathModifier pathModifier = NoModifier) {/*Draw the line 'l' without altering the size of picture pic. The boolean parameters control the infinite section. The global variable 'linemargin' (default value is 0) allows to modify the bounding box in which the line must be drawn.*/ if(!(dirA || dirB)) draw(l.A--l.B, invisible);// l is a segment. Drawline(pic, L, l.A, dirP = dirA, l.B, dirQ = dirB, align, p, arrow, legend, marker, pathModifier); } /**/ void draw(picture pic = currentpicture, Label[] L = new Label[], line[] l, align align = NoAlign, pen[] p = new pen[], arrowbar arrow = None, Label[] legend = new Label[], marker marker = nomarker, pathModifier pathModifier = NoModifier) {/*Draw each lines with the corresponding pen.*/ for (int i = 0; i < l.length; ++i) { draw(pic, L.length>0 ? L[i] : "", l[i], align, p = p.length>0 ? p[i] : currentpen, arrow, legend.length>0 ? legend[i] : "", marker, pathModifier); } } /**/ void draw(picture pic = currentpicture, Label[] L = new Label[], line[] l, align align = NoAlign, pen p, arrowbar arrow = None, Label[] legend = new Label[], marker marker = nomarker, pathModifier pathModifier = NoModifier) {/*Draw each lines with the same pen 'p'.*/ pen[] tp = sequence(new pen(int i){return p;}, l.length); draw(pic, L, l, align, tp, arrow, legend, marker, pathModifier); } /**/ void show(picture pic = currentpicture, line l, pen p = red) {/*Draw some informations of 'l'.*/ dot("$A$", (pair)l.A, align = -locate(l.v), p); dot("$B$", (pair)l.B, align = -locate(l.v), p); draw(l, dotted); draw("$\vec{u}$", locate(l.A)--locate(l.A + l.u), p, Arrow); draw("$\vec{v}$", locate(l.A)--locate(l.A + l.v), p, Arrow); } /**/ point[] sameside(point M, line l1, line l2) {/*Return two points on 'l1' and 'l2' respectively. The first point is from the same side of M relatively to 'l2', the second point is from the same side of M relatively to 'l1'.*/ point[] op; coordsys R1 = coordsys(l1); coordsys R2 = coordsys(l2); if (parallel(l1, l2)) { op.push(projection(l1) * M); op.push(projection(l2) * M); } else { point O = intersectionpoint(l1, l2); if (M @ l2) op.push((sameside(M, O + l1.u, l2)) ? O + l1.u : rotate(180, O) * (O + l1.u)); else op.push(projection(l1, l2) * M); if (M @ l1) op.push((sameside(M, O + l2.u, l1)) ? O + l2.u : rotate(180, O) * (O + l2.u)); else {op.push(projection(l2, l1) * M);} } return op; } /**/ void markangle(picture pic = currentpicture, Label L = "", int n = 1, real radius = 0, real space = 0, explicit line l1, explicit line l2, explicit pair align = dir(1), arrowbar arrow = None, pen p = currentpen, filltype filltype = NoFill, margin margin = NoMargin, marker marker = nomarker) {/*Mark the angle (l1, l2) aligned in the direction 'align' relative to 'l1'. Commune values for 'align' are dir(real).*/ if (parallel(l1, l2, true)) return; real al = degrees(l1, defaultcoordsys); pair O, A, B; if (radius == 0) radius = markangleradius(p); real d = degrees(locate(l1.u)); align = rotate(d) * align; if (l1 == l2) { O = midpoint(segment(l1.A, l1.B)); A = l1.A;B = l1.B; if (sameside(rotate(sgn(angle(B-A)) * 45, O) * A, O + align, l1)) {radius = -radius;} } else { O = intersectionpoint(extend(l1), extend(l2)); pair R = O + align; point [] ss = sameside(point(coordsys(l1), R/coordsys(l1)), l1, l2); A = ss[0]; B = ss[1]; } markangle(pic = pic, L = L, n = n, radius = radius, space = space, O = O, A = A, B = B, arrow = arrow, p = p, filltype = filltype, margin = margin, marker = marker); } /**/ void markangle(picture pic = currentpicture, Label L = "", int n = 1, real radius = 0, real space = 0, explicit line l1, explicit line l2, explicit vector align, arrowbar arrow = None, pen p = currentpen, filltype filltype = NoFill, margin margin = NoMargin, marker marker = nomarker) {/*Mark the angle (l1, l2) in the direction 'dir' given relatively to 'l1'.*/ markangle(pic, L, n, radius, space, l1, l2, (pair)align, arrow, p, filltype, margin, marker); } /**/ // void markangle(picture pic = currentpicture, // Label L = "", int n = 1, real radius = 0, real space = 0, // explicit line l1, explicit line l2, // arrowbar arrow = None, pen p = currentpen, // filltype filltype = NoFill, // margin margin = NoMargin, marker marker = nomarker) // {/*Mark the oriented angle (l1, l2).*/ // if (parallel(l1, l2, true)) return; // real al = degrees(l1, defaultcoordsys); // pair O, A, B; // if (radius == 0) radius = markangleradius(p); // real d = degrees(locate(l1.u)); // if (l1 == l2) { // O = midpoint(segment(l1.A, l1.B)); // } else { // O = intersectionpoint(extend(l1), extend(l2)); // } // A = O + locate(l1.u); // B = O + locate(l2.u); // markangle(pic = pic, L = L, n = n, radius = radius, space = space, // O = O, A = A, B = B, // arrow = arrow, p = p, filltype = filltype, // margin = margin, marker = marker); // } /**/ void perpendicularmark(picture pic = currentpicture, line l1, line l2, real size = 0, pen p = currentpen, int quarter = 1, margin margin = NoMargin, filltype filltype = NoFill) {/*Draw a right angle at the intersection point of lines and aligned in the 'quarter' nth quarter of circle formed by 'l1.u' and 'l2.u'.*/ point P = intersectionpoint(l1, l2); pair align = rotate(90 * (quarter - 1)) * dir(45); perpendicularmark(P, align, locate(l1.u), size, p, margin, filltype); } // *.........................LINES.........................* // *=======================================================* // *=======================================================* // *........................CONICS.........................* /**/ struct bqe {/*Bivariate Quadratic Equation.*/ /**/ real[] a;/*a[0] * x^2 + a[1] * x * y + a[2] * y^2 + a[3] * x + a[4] * y + a[5] = 0*/ coordsys coordsys;/**/ }/**/ /**/ bqe bqe(coordsys R = currentcoordsys, real a, real b, real c, real d, real e, real f) {/*Return the bivariate quadratic equation a[0] * x^2 + a[1] * x * y + a[2] * y^2 + a[3] * x + a[4] * y + a[5] = 0 relatively to the coordinate system R.*/ bqe obqe; obqe.coordsys = R; obqe.a = new real[] {a, b, c, d, e, f}; return obqe; } /**/ bqe changecoordsys(coordsys R, bqe bqe) {/*Returns the bivariate quadratic equation relatively to 'R'.*/ pair i = coordinates(changecoordsys(R, vector(defaultcoordsys, bqe.coordsys.i))); pair j = coordinates(changecoordsys(R, vector(defaultcoordsys, bqe.coordsys.j))); pair O = coordinates(changecoordsys(R, point(defaultcoordsys, bqe.coordsys.O))); real a = bqe.a[0], b = bqe.a[1], c = bqe.a[2], d = bqe.a[3], f = bqe.a[4], g = bqe.a[5]; real ux = i.x, uy = i.y; real vx = j.x, vy = j.y; real ox = O.x, oy = O.y; real D = ux * vy - uy * vx; real ap = (a * vy^2 - b * uy * vy + c * uy^2)/D^2; real bpp = (-2 * a * vx * vy + b * ux * vy + b * uy * vx - 2 * c * ux * uy)/D^2; real cp = (a * vx^2 - b * ux * vx + c * ux^2)/D^2; real dp = (-2a * ox * vy^2 + 2a * oy * vx * vy + 2b * ox * uy * vy- b * oy * ux * vy - b * oy * uy * vx - 2c * ox * uy^2 + 2c * oy * uy * ux)/D^2+ (d * vy - f * uy)/D; real fp = (2a * ox * vx * vy - b * ox * ux * vy - 2a * oy * vx^2- b * ox * uy * vx + 2 * b * oy * ux * vx + 2c * ox * ux * uy - 2c * oy * ux^2)/D^2+ (f * ux - d * vx)/D; g = (a * ox^2 * vy^2 - 2a * ox * oy * vx * vy - b * ox^2 * uy * vy + b * ox * oy * ux * vy+ a * oy^2 * vx^2 + b * ox * oy * uy * vx - b * oy^2 * ux * vx + c * ox^2 * uy^2- 2 * c * ox * oy * ux * uy + c * oy^2 * ux^2)/D^2+ (d * oy * vx + f * ox * uy - d * ox * vy - f * oy * ux)/D + g; bqe obqe; obqe.a = approximate(new real[] {ap, bpp, cp, dp, fp, g}); obqe.coordsys = R; return obqe; } /**/ bqe bqe(point M1, point M2, point M3, point M4, point M5) {/*Return the bqe of conic passing through the five points (if possible).*/ coordsys R; pair[] pts; if (samecoordsys(M1, M2, M3, M4, M5)) { R = M1.coordsys; pts= new pair[] {M1.coordinates, M2.coordinates, M3.coordinates, M4.coordinates, M5.coordinates}; } else { R = defaultcoordsys; pts= new pair[] {M1, M2, M3, M4, M5}; } real[][] M; real[] x; bqe bqe; bqe.coordsys = R; for (int i = 0; i < 5; ++i) {// Try a = -1 M[i] = new real[] {pts[i].x * pts[i].y, pts[i].y^2, pts[i].x, pts[i].y, 1}; x[i] = pts[i].x^2; } if(abs(determinant(M)) < 1e-5) {// Try c = -1 for (int i = 0; i < 5; ++i) { M[i] = new real[] {pts[i].x^2, pts[i].x * pts[i].y, pts[i].x, pts[i].y, 1}; x[i] = pts[i].y^2; } real[] coef = solve(M, x); bqe.a = new real[] {coef[0], coef[1], -1, coef[2], coef[3], coef[4]}; } else { real[] coef = solve(M, x); bqe.a = new real[] {-1, coef[0], coef[1], coef[2], coef[3], coef[4]}; } bqe.a = approximate(bqe.a); return bqe; } /**/ bool samecoordsys(bool warn = true ... bqe[] bqes) {/*Return true if all the bivariate quadratic equations have the same coordinate system.*/ bool ret = true; coordsys t = bqes[0].coordsys; for (int i = 1; i < bqes.length; ++i) { ret = (t == bqes[i].coordsys); if(!ret) break; t = bqes[i].coordsys; } if(warn && !ret) warning("coodinatesystem", "the coordinate system of two bivariate quadratic equations are not the same. The operation will be done relatively to the default coordinate system."); return ret; } /**/ real[] realquarticroots(real a, real b, real c, real d, real e) {/*Return the real roots of the quartic equation ax^4 + b^x3 + cx^2 + dx = 0.*/ static real Fuzz = sqrt(realEpsilon); pair[] zroots = quarticroots(a, b, c, d, e); real[] roots; real p(real x){return a * x^4 + b * x^3 + c * x^2 + d * x + e;} real prime(real x){return 4 * a * x^3 + 3 * b * x^2 + 2 * c * x + d;} real x; bool search = true; int n; void addroot(real x) { bool exist = false; for (int i = 0; i < roots.length; ++i) { if(abs(roots[i]-x) < 1e-5) {exist = true; break;} } if(!exist) roots.push(x); } for(int i = 0; i < zroots.length; ++i) { if(zroots[i].y == 0 || abs(p(zroots[i].x)) < Fuzz) addroot(zroots[i].x); else { if(abs(zroots[i].y) < 1e-3) { x = zroots[i].x; search = true; n = 200; while(search) { real tx = abs(p(x)) < Fuzz ? x : newton(iterations = n, p, prime, x); if(tx < realMax) { if(abs(p(tx)) < Fuzz) { addroot(tx); search = false; } else if(n < 200) n *=2; else { search = false; } } else search = false; //It's not a real root. } } } } return roots; } /**/ point[] intersectionpoints(bqe bqe1, bqe bqe2) {/*Return the interscetion of the two conic sections whose equations are 'bqe1' and 'bqe2'.*/ coordsys R = bqe1.coordsys; bqe lbqe1, lbqe2; real[] a, b; if(R != bqe2.coordsys) { R = currentcoordsys; a = changecoordsys(R, bqe1).a; b = changecoordsys(R, bqe2).a; } else { a = bqe1.a; b = bqe2.a; } static real e = 100 * sqrt(realEpsilon); real[] x, y, c; point[] P; if(abs(a[0]-b[0]) > e || abs(a[1]-b[1]) > e || abs(a[2]-b[2]) > e) { c = new real[] {-2 * a[0]*a[2]*b[0]*b[2]+a[0]*a[2]*b[1]^2 - a[0]*a[1]*b[2]*b[1]+a[1]^2 * b[0]*b[2]- a[2]*a[1]*b[0]*b[1]+a[0]^2 * b[2]^2 + a[2]^2 * b[0]^2, -a[2]*a[1]*b[0]*b[4]-a[2]*a[4]*b[0]*b[1]-a[1]*a[3]*b[2]*b[1]+2 * a[0]*a[2]*b[1]*b[4]- a[0]*a[1]*b[2]*b[4]+a[1]^2 * b[2]*b[3]-2 * a[2]*a[3]*b[0]*b[2]-2 * a[0]*a[2]*b[2]*b[3]+ a[2]*a[3]*b[1]^2 - a[2]*a[1]*b[1]*b[3]+2 * a[1]*a[4]*b[0]*b[2]+2 * a[2]^2 * b[0]*b[3]- a[0]*a[4]*b[2]*b[1]+2 * a[0]*a[3]*b[2]^2, -a[3]*a[4]*b[2]*b[1]+a[2]*a[5]*b[1]^2 - a[1]*a[5]*b[2]*b[1]-a[1]*a[3]*b[2]*b[4]+ a[1]^2 * b[2]*b[5]-2 * a[2]*a[3]*b[2]*b[3]+2 * a[2]^2 * b[0]*b[5]+2 * a[0]*a[5]*b[2]^2 + a[3]^2 * b[2]^2- 2 * a[2]*a[5]*b[0]*b[2]+2 * a[1]*a[4]*b[2]*b[3]-a[2]*a[4]*b[1]*b[3]-2 * a[0]*a[2]*b[2]*b[5]+ a[2]^2 * b[3]^2 + 2 * a[2]*a[3]*b[1]*b[4]-a[2]*a[4]*b[0]*b[4]+a[4]^2 * b[0]*b[2]-a[2]*a[1]*b[3]*b[4]- a[2]*a[1]*b[1]*b[5]-a[0]*a[4]*b[2]*b[4]+a[0]*a[2]*b[4]^2, -a[4]*a[5]*b[2]*b[1]+a[2]*a[3]*b[4]^2 + 2 * a[3]*a[5]*b[2]^2 - a[2]*a[1]*b[4]*b[5]- a[2]*a[4]*b[3]*b[4]+2 * a[2]^2 * b[3]*b[5]-2 * a[2]*a[3]*b[2]*b[5]-a[3]*a[4]*b[2]*b[4]- 2 * a[2]*a[5]*b[2]*b[3]-a[2]*a[4]*b[1]*b[5]+2 * a[1]*a[4]*b[2]*b[5]-a[1]*a[5]*b[2]*b[4]+ a[4]^2 * b[2]*b[3]+2 * a[2]*a[5]*b[1]*b[4], -2 * a[2]*a[5]*b[2]*b[5]+a[4]^2 * b[2]*b[5]+a[5]^2 * b[2]^2 - a[4]*a[5]*b[2]*b[4]+a[2]*a[5]*b[4]^2+ a[2]^2 * b[5]^2 - a[2]*a[4]*b[4]*b[5]}; x = realquarticroots(c[0], c[1], c[2], c[3], c[4]); } else { if(abs(b[4]-a[4]) > e){ real D = (b[4]-a[4])^2; c = new real[] {(a[0]*b[4]^2 + (-a[1]*b[3]-2 * a[0]*a[4]+a[1]*a[3]) * b[4]+a[2]*b[3]^2+ (a[1]*a[4]-2 * a[2]*a[3]) * b[3]+a[0]*a[4]^2 - a[1]*a[3]*a[4]+a[2]*a[3]^2)/D, -((a[1]*b[4]-2 * a[2]*b[3]-a[1]*a[4]+2 * a[2]*a[3]) * b[5]-a[3]*b[4]^2 + (a[4]*b[3]-a[1]*a[5]+a[3]*a[4]) * b[4]+(2 * a[2]*a[5]-a[4]^2) * b[3]+(a[1]*a[4]-2 * a[2]*a[3]) * a[5])/D, a[2]*(a[5]-b[5])^2/D + a[4]*(a[5]-b[5])/(b[4]-a[4]) + a[5]}; x = quadraticroots(c[0], c[1], c[2]); } else { if(abs(a[3]-b[3]) > e) { real D = b[3]-a[3]; c = new real[] {a[2], (-a[1]*b[5] + a[4]*b[3] + a[1]*a[5] - a[3]*a[4])/D, a[0]*(a[5]-b[5])^2/D^2 + a[3]*(a[5]-b[5])/D + a[5]}; y = quadraticroots(c[0], c[1], c[2]); for (int i = 0; i < y.length; ++i) { c = new real[] {a[0], a[1]*y[i]+a[3], a[2]*y[i]^2 + a[4]*y[i]+a[5]}; x = quadraticroots(c[0], c[1], c[2]); for (int j = 0; j < x.length; ++j) { if(abs(b[0]*x[j]^2 + b[1]*x[j]*y[i]+b[2]*y[i]^2 + b[3]*x[j]+b[4]*y[i]+b[5]) < 1e-5) P.push(point(R, (x[j], y[i]))); } } return P; } else { if(abs(a[5]-b[5]) < e) abort("intersectionpoints: intersection of identical conics."); } } } for (int i = 0; i < x.length; ++i) { c = new real[] {a[2], a[1]*x[i]+a[4], a[0]*x[i]^2 + a[3]*x[i]+a[5]}; y = quadraticroots(c[0], c[1], c[2]); for (int j = 0; j < y.length; ++j) { if(abs(b[0]*x[i]^2 + b[1]*x[i]*y[j]+b[2]*y[j]^2 + b[3]*x[i]+b[4]*y[j]+b[5]) < 1e-5) P.push(point(R, (x[i], y[j]))); } } return P; } /**/ struct conic {/**/ real e, p, h;/*BE CAREFUL: h = distance(F, D) and p = h * e (http://en.wikipedia.org/wiki/Ellipse) While http://mathworld.wolfram.com/ takes p = distance(F,D).*/ point F;/*Focus.*/ line D;/*Directrix.*/ line[] l;/*Case of degenerated conic (not yet implemented !).*/ }/**/ bool degenerate(conic c) { return !finite(c.p) || !finite(c.h); } /*ANCconic conic(point, line, real)ANC*/ conic conic(point F, line l, real e) {/*DOC The conic section define by the eccentricity 'e', the focus 'F' and the directrix 'l'. Note that an eccentricity equal to 0 defines a circle centered at F, with a radius equal at the distance from 'F' to 'l'. If the coordinate system of 'F' and 'l' are not identical, the conic is attached to 'defaultcoordsys'. DOC*/ if(e < 0) abort("conic: 'e' can't be negative."); conic oc; point[] P = standardizecoordsys(F, l.A, l.B); line ll; ll = line(P[1], P[2]); oc.e = e < epsgeo ? 0 : e; // Handle case of circle. oc.F = P[0]; oc.D = ll; oc.h = distance(P[0], ll); oc.p = abs(e) < epsgeo ? oc.h : e * oc.h; return oc; } /**/ struct circle {/*All the calculus with this structure will be as exact as Asymptote can do. For a full precision, you must not cast 'circle' to 'path' excepted for drawing routines.*/ /**/ point C;/*Center*/ real r;/*Radius*/ line l;/*If the radius is infinite, this line is used instead of circle.*/ }/**/ bool degenerate(circle c) { return !finite(c.r); } line line(circle c){ if(finite(c.r)) abort("Circle can not be casted to line here."); return c.l; } /**/ struct ellipse {/*Look at http://mathworld.wolfram.com/Ellipse.html*/ /**/ restricted point F1,F2,C;/*Foci and center.*/ restricted real a,b,c,e,p;/**/ restricted real angle;/*Value is degrees(F1 - F2).*/ restricted line D1,D2;/*Directrices.*/ line l;/*If one axis is infinite, this line is used instead of ellipse.*/ /**/ void init(point f1, point f2, real a) {/*Ellipse given by foci and semimajor axis*/ point[] P = standardizecoordsys(f1, f2); this.F1 = P[0]; this.F2 = P[1]; this.angle = abs(P[1]-P[0]) < 10 * epsgeo ? 0 : degrees(P[1]-P[0]); this.C = (P[0] + P[1])/2; this.a = a; if(!finite(a)) { this.l = line(P[0], P[1]); this.b = infinity; this.e = 0; this.c = 0; } else { this.c = abs(C - P[0]); this.b = this.c < epsgeo ? a : sqrt(a^2 - c^2); // Handle case of circle. this.e = this.c < epsgeo ? 0 : this.c/a; // Handle case of circle. if(this.e >= 1) abort("ellipse.init: wrong parameter: e >= 1."); this.p = a * (1 - this.e^2); if (this.c != 0) {// directrix is not set for a circle. point A = this.C + (a^2/this.c) * unit(P[0]-this.C); this.D1 = line(A, A + rotateO(90) * unit(A - this.C)); this.D2 = reverse(rotate(180, C) * D1); } } } }/**/ bool degenerate(ellipse el) { return (!finite(el.a) || !finite(el.b)); } /**/ struct parabola {/*Look at http://mathworld.wolfram.com/Parabola.html*/ restricted point F,V;/*Focus and vertex*/ restricted real a,p,e = 1;/**/ restricted real angle;/*Angle, in degrees, of the line (FV).*/ restricted line D;/*Directrix*/ pair bmin, bmax;/*The (left, bottom) and (right, top) coordinates of region bounding box for drawing the parabola. If unset the current picture bounding box is used instead.*/ /**/ void init(point F, line directrix) {/*Parabola given by focus and directrix.*/ point[] P = standardizecoordsys(F, directrix.A, directrix.B); line l = line(P[1], P[2]); this.F = P[0]; this.D = l; this.a = distance(P[0], l)/2; this.p = 2 * a; this.V = 0.5 * (F + projection(D) * P[0]); this.angle = degrees(F - V); } }/**/ /**/ struct hyperbola {/*Look at http://mathworld.wolfram.com/Hyperbola.html*/ restricted point F1,F2;/*Foci.*/ restricted point C,V1,V2;/*Center and vertices.*/ restricted real a,b,c,e,p;/**/ restricted real angle;/*Angle,in degrees,of the line (F1F2).*/ restricted line D1,D2,A1,A2;/*Directrices and asymptotes.*/ pair bmin, bmax; /*The (left, bottom) and (right, top) coordinates of region bounding box for drawing the hyperbola. If unset the current picture bounding box is used instead.*/ /**/ void init(point f1, point f2, real a) {/*Hyperbola given by foci and semimajor axis.*/ point[] P = standardizecoordsys(f1, f2); this.F1 = P[0]; this.F2 = P[1]; this.angle = degrees(F2 - F1); this.a = a; this.C = (P[0] + P[1])/2; this.c = abs(C - P[0]); this.e = this.c/a; if(this.e <= 1) abort("hyperbola.init: wrong parameter: e <= 1."); this.b = a * sqrt(this.e^2 - 1); this.p = a * (this.e^2 - 1); point A = this.C + (a^2/this.c) * unit(P[0]-this.C); this.D1 = line(A, A + rotateO(90) * unit(A - this.C)); this.D2 = reverse(rotate(180, C) * D1); this.V1 = C + a * unit(F1 - C); this.V2 = C + a * unit(F2 - C); this.A1 = line(C, V1 + b * unit(rotateO(-90) * (C - V1))); this.A2 = line(C, V1 + b * unit(rotateO(90) * (C - V1))); } }/**/ /**/ int conicnodesfactor = 1;/*Factor for the node number of all conics.*/ /**/ int circlenodesnumberfactor = 100;/*Factor for the node number of circles.*/ /**/ int circlenodesnumber(real r) {/*Return the number of nodes for drawing a circle of radius 'r'.*/ if (circlenodesnumberfactor < 100) warning("circlenodesnumberfactor", "variable 'circlenodesnumberfactor' may be too small."); int oi = ceil(circlenodesnumberfactor * abs(r)^0.1); oi = 45 * floor(oi/45); return oi == 0 ? 4 : conicnodesfactor * oi; } /**/ int circlenodesnumber(real r, real angle1, real angle2) {/*Return the number of nodes to draw a circle arc.*/ return (r > 0) ? ceil(circlenodesnumber(r) * abs(angle1 - angle2)/360) : ceil(circlenodesnumber(r) * abs((1 - abs(angle1 - angle2)/360))); } /**/ int ellipsenodesnumberfactor = 250;/*Factor for the node number of ellispe (non-circle).*/ /**/ int ellipsenodesnumber(real a, real b) {/*Return the number of nodes to draw a ellipse of axis 'a' and 'b'.*/ if (ellipsenodesnumberfactor < 250) write("ellipsenodesnumberfactor", "variable 'ellipsenodesnumberfactor' maybe too small."); int tmp = circlenodesnumberfactor; circlenodesnumberfactor = ellipsenodesnumberfactor; int oi = circlenodesnumber(max(abs(a), abs(b))/min(abs(a), abs(b))); circlenodesnumberfactor = tmp; return conicnodesfactor * oi; } /**/ int ellipsenodesnumber(real a, real b, real angle1, real angle2, bool dir) {/*Return the number of nodes to draw an ellipse arc.*/ real d; real da = angle2 - angle1; if(dir) { d = angle1 < angle2 ? da : 360 + da; } else { d = angle1 < angle2 ? -360 + da : da; } int n = floor(ellipsenodesnumber(a, b) * abs(d)/360); return n < 5 ? 5 : n; } /**/ int parabolanodesnumberfactor = 100;/*Factor for the number of nodes of parabolas.*/ /**/ int parabolanodesnumber(parabola p, real angle1, real angle2) {/*Return the number of nodes for drawing a parabola.*/ return conicnodesfactor * floor(0.01 * parabolanodesnumberfactor * abs(angle1 - angle2)); } /**/ int hyperbolanodesnumberfactor = 100;/*Factor for the number of nodes of hyperbolas.*/ /**/ int hyperbolanodesnumber(hyperbola h, real angle1, real angle2) {/*Return the number of nodes for drawing an hyperbola.*/ return conicnodesfactor * floor(0.01 * hyperbolanodesnumberfactor * abs(angle1 - angle2)/h.e); } /**/ conic operator +(conic c, explicit point M) {/**/ return conic(c.F + M, c.D + M, c.e); } /**/ conic operator -(conic c, explicit point M) {/**/ return conic(c.F - M, c.D - M, c.e); } /**/ conic operator +(conic c, explicit pair m) {/**/ point M = point(c.F.coordsys, m); return conic(c.F + M, c.D + M, c.e); } /**/ conic operator -(conic c, explicit pair m) {/**/ point M = point(c.F.coordsys, m); return conic(c.F - M, c.D - M, c.e); } /**/ conic operator +(conic c, vector v) {/**/ return conic(c.F + v, c.D + v, c.e); } /**/ conic operator -(conic c, vector v) {/**/ return conic(c.F - v, c.D - v, c.e); } /**/ coordsys coordsys(conic co) {/*Return the coordinate system of 'co'.*/ return co.F.coordsys; } /**/ conic changecoordsys(coordsys R, conic co) {/*Change the coordinate system of 'co' to 'R'*/ line l = changecoordsys(R, co.D); point F = changecoordsys(R, co.F); return conic(F, l, co.e); } /**/ typedef path polarconicroutine(conic co, real angle1, real angle2, int n, bool direction);/*Routine type used to draw conics from 'angle1' to 'angle2'*/ /**/ path arcfromfocus(conic co, real angle1, real angle2, int n = 400, bool direction = CCW) {/*Return the path of the conic section 'co' from angle1 to angle2 in degrees, drawing in the given direction, with n nodes.*/ guide op; if (n < 1) return op; if (angle1 > angle2) { path g = arcfromfocus(co, angle2, angle1, n, !direction); return g == nullpath ? g : reverse(g); } point O = projection(co.D) * co.F; pair i = unit(locate(co.F) - locate(O)); pair j = rotate(90) * i; coordsys Rp = cartesiansystem(co.F, i, j); real a1 = direction ? radians(angle1) : radians(angle2); real a2 = direction ? radians(angle2) : radians(angle1) + 2 * pi; real step = n == 1 ? 0 : (a2 - a1)/(n - 1); real a, r; for (int i = 0; i < n; ++i) { a = a1 + i * step; if(co.e >= 1) { r = 1 - co.e * cos(a); if(r > epsgeo) { r = co.p/r; op = op--Rp * Rp.polar(r, a); } } else { r = co.p/(1 - co.e * cos(a)); op = op..Rp * Rp.polar(r, a); } } if(co.e < 1 && abs(abs(a2 - a1) - 2 * pi) < epsgeo) op = (path)op..cycle; return (direction ? op : op == nullpath ? op :reverse(op)); } /**/ polarconicroutine currentpolarconicroutine = arcfromfocus;/*Default routine used to cast conic section to path.*/ /**/ point angpoint(conic co, real angle) {/*Return the point of 'co' whose the angular (in degrees) coordinate is 'angle' (mesured from the focus of 'co', relatively to its 'natural coordinate system').*/ coordsys R = coordsys(co); return point(R, point(arcfromfocus(co, angle, angle, 1, CCW), 0)/R); } /**/ bool operator @(point M, conic co) {/*Return true iff 'M' on 'co'.*/ if(co.e == 0) return abs(abs(co.F - M) - co.p) < 10 * epsgeo; return abs(co.e * distance(M, co.D) - abs(co.F - M)) < 10 * epsgeo; } /**/ coordsys coordsys(ellipse el) {/*Return the coordinate system of 'el'.*/ return el.F1.coordsys; } /**/ coordsys canonicalcartesiansystem(ellipse el) {/*Return the canonical cartesian system of the ellipse 'el'.*/ if(degenerate(el)) return cartesiansystem(el.l.A, el.l.u, el.l.v); pair O = locate(el.C); pair i = el.e == 0 ? el.C.coordsys.i : unit(locate(el.F1) - O); pair j = rotate(90) * i; return cartesiansystem(O, i, j); } /**/ coordsys canonicalcartesiansystem(parabola p) {/*Return the canonical cartesian system of a parabola, so that Origin = vertex of 'p' and directrix: x = -a.*/ point A = projection(p.D) * p.F; pair O = locate((A + p.F)/2); pair i = unit(locate(p.F) - O); pair j = rotate(90) * i; return cartesiansystem(O, i, j); } /**/ coordsys canonicalcartesiansystem(hyperbola h) {/*Return the canonical cartesian system of an hyperbola.*/ pair O = locate(h.C); pair i = unit(locate(h.F2) - O); pair j = rotate(90) * i; return cartesiansystem(O, i, j); } /**/ ellipse ellipse(point F1, point F2, real a) {/*Return the ellipse whose the foci are 'F1' and 'F2' and the semimajor axis is 'a'.*/ ellipse oe; oe.init(F1, F2, a); return oe; } /**/ restricted bool byfoci = true, byvertices = false;/*Constants useful for the routine 'hyperbola(point P1, point P2, real ae, bool byfoci = byfoci)'*/ /**/ hyperbola hyperbola(point P1, point P2, real ae, bool byfoci = byfoci) {/*if 'byfoci = true': return the hyperbola whose the foci are 'P1' and 'P2' and the semimajor axis is 'ae'. else return the hyperbola whose vertexes are 'P1' and 'P2' with eccentricity 'ae'.*/ hyperbola oh; point[] P = standardizecoordsys(P1, P2); if(byfoci) { oh.init(P[0], P[1], ae); } else { real a = abs(P[0]-P[1])/2; vector V = unit(P[0]-P[1]); point F1 = P[0] + a * (ae - 1) * V; point F2 = P[1]-a * (ae - 1) * V; oh.init(F1, F2, a); } return oh; } /**/ ellipse ellipse(point F1, point F2, point M) {/*Return the ellipse passing through 'M' whose the foci are 'F1' and 'F2'.*/ point P[] = standardizecoordsys(false, F1, F2, M); real a = abs(F1 - M) + abs(F2 - M); return ellipse(F1, F2, finite(a) ? a/2 : a); } /**/ ellipse ellipse(point C, real a, real b, real angle = 0) {/*Return the ellipse centered at 'C' with semimajor axis 'a' along C--C + dir(angle), semiminor axis 'b' along the perpendicular.*/ ellipse oe; coordsys R = C.coordsys; angle += degrees(R.i); if(a < b) {angle += 90; real tmp = a; a = b; b = tmp;} if(finite(a) && finite(b)) { real c = sqrt(abs(a^2 - b^2)); point f1, f2; if(abs(a - b) < epsgeo) { f1 = C; f2 = C; } else { f1 = point(R, (locate(C) + rotate(angle) * (-c, 0))/R); f2 = point(R, (locate(C) + rotate(angle) * (c, 0))/R); } oe.init(f1, f2, a); } else { if(finite(b) || !finite(a)) oe.init(C, C + R.polar(1, angle), infinity); else oe.init(C, C + R.polar(1, 90 + angle), infinity); } return oe; } /**/ ellipse ellipse(bqe bqe) {/*Return the ellipse a[0] * x^2 + a[1] * xy + a[2] * y^2 + a[3] * x + a[4] * y + a[5] = 0 given in the coordinate system of 'bqe' with a[i] = bque.a[i]. .*/ bqe lbqe = changecoordsys(defaultcoordsys, bqe); real a = lbqe.a[0], b = lbqe.a[1]/2, c = lbqe.a[2], d = lbqe.a[3]/2, f = lbqe.a[4]/2, g = lbqe.a[5]; coordsys R = bqe.coordsys; string message = "ellipse: the given equation is not an equation of an ellipse."; real u = b^2 * g + d^2 * c + f^2 * a; real delta = a * c * g + b * f * d + d * b * f - u; if(abs(delta) < epsgeo) abort(message); real j = b^2 - a * c; real i = a + c; real dd = j * (sgnd(c - a) * sqrt((a - c)^2 + 4 * (b^2)) - c-a); real ddd = j * (-sgnd(c - a) * sqrt((a - c)^2 + 4 * (b^2)) - c-a); if(abs(ddd) < epsgeo || abs(dd) < epsgeo || j >= -epsgeo || delta/sgnd(i) > 0) abort(message); real x = (c * d - b * f)/j, y = (a * f - b * d)/j; // real dir = abs(b) < epsgeo ? 0 : pi/2-0.5 * acot(0.5 * (c-a)/b); real dir = abs(b) < epsgeo ? 0 : 0.5 * acot(0.5 * (c - a)/b); if(dir * (c - a) * b < 0) dir = dir < 0 ? dir + pi/2 : dir - pi/2; real cd = cos(dir), sd = sin(dir); real t = a * cd^2 - 2 * b * cd * sd + c * sd^2; real tt = a * sd^2 + 2 * b * cd * sd + c * cd^2; real gg = -g + ((d * cd - f * sd)^2)/t + ((d * sd + f * cd)^2)/tt; t = t/gg; tt = tt/gg; // The equation of the ellipse is t * (x - center.x)^2 + tt * (y - center.y)^2 = 1; real aa, bb; aa = sqrt(2 * (u - 2 * b * d * f - a * c * g)/dd); bb = sqrt(2 * (u - 2 * b * d * f - a * c * g)/ddd); a = t > tt ? max(aa, bb) : min(aa, bb); b = t > tt ? min(aa, bb) : max(aa, bb); return ellipse(point(R, (x, y)/R), a, b, degrees(pi/2 - dir - angle(R.i))); } /**/ ellipse ellipse(point M1, point M2, point M3, point M4, point M5) {/*Return the ellipse passing through the five points (if possible)*/ return ellipse(bqe(M1, M2, M3, M4, M5)); } /**/ bool inside(ellipse el, point M) {/*Return 'true' iff 'M' is inside 'el'.*/ return abs(el.F1 - M) + abs(el.F2 - M) - 2 * el.a < -epsgeo; } /**/ bool inside(parabola p, point M) {/*Return 'true' if 'M' is inside 'p'.*/ return distance(p.D, M) - abs(p.F - M) > epsgeo; } /**/ parabola parabola(point F, line l) {/*Return the parabola whose focus is 'F' and directrix is 'l'.*/ parabola op; op.init(F, l); return op; } /**/ parabola parabola(point F, point vertex) {/*Return the parabola whose focus is 'F' and vertex is 'vertex'.*/ parabola op; point[] P = standardizecoordsys(F, vertex); point A = rotate(180, P[1]) * P[0]; point B = A + rotateO(90) * unit(P[1]-A); op.init(P[0], line(A, B)); return op; } /**/ parabola parabola(point F, real a, real angle) {/*Return the parabola whose focus is F, latus rectum is 4a and the angle of the axis of symmetry (in the coordinate system of F) is 'angle'.*/ parabola op; coordsys R = F.coordsys; point A = F - point(R, R.polar(2a, radians(angle))); point B = A + point(R, R.polar(1, radians(90 + angle))); op.init(F, line(A, B)); return op; } /**/ bool isparabola(bqe bqe) {/*Return true iff 'bqe' is the equation of a parabola.*/ bqe lbqe = changecoordsys(defaultcoordsys, bqe); real a = lbqe.a[0], b = lbqe.a[1]/2, c = lbqe.a[2], d = lbqe.a[3]/2, f = lbqe.a[4]/2, g = lbqe.a[5]; real delta = a * c * g + b * f * d + d * b * f - (b^2 * g + d^2 * c + f^2 * a); return (abs(delta) > epsgeo && abs(b^2 - a * c) < epsgeo); } /**/ parabola parabola(bqe bqe) {/*Return the parabola a[0]x^2 + a[1]xy + a[2]y^2 + a[3]x + a[4]y + a[5]] = 0 (a[n] means bqe.a[n]). */ bqe lbqe = changecoordsys(defaultcoordsys, bqe); real a = lbqe.a[0], b = lbqe.a[1]/2, c = lbqe.a[2], d = lbqe.a[3]/2, f = lbqe.a[4]/2, g = lbqe.a[5]; string message = "parabola: the given equation is not an equation of a parabola."; real delta = a * c * g + b * f * d + d * b * f - (b^2 * g + d^2 * c + f^2 * a); if(abs(delta) < 10 * epsgeo || abs(b^2 - a * c) > 10 * epsgeo) abort(message); real dir = abs(b) < epsgeo ? 0 : 0.5 * acot(0.5 * (c - a)/b); if(dir * (c - a) * b < 0) dir = dir < 0 ? dir + pi/2 : dir - pi/2; real cd = cos(dir), sd = sin(dir); real ap = a * cd^2 - 2 * b * cd * sd + c * sd^2; real cp = a * sd^2 + 2 * b * cd * sd + c * cd^2; real dp = d * cd - f * sd; real fp = d * sd + f * cd; real gp = g; parabola op; coordsys R = bqe.coordsys; // The equation of the parabola is ap * x'^2 + cp * y'^2 + 2dp * x'+2fp * y'+gp = 0 if (abs(ap) < epsgeo) {/* directrix parallel to the rotated(dir) y-axis equation: (y-vertex.y)^2 = 4 * a * (x-vertex) */ pair pvertex = rotate(degrees(-dir)) * (0.5(-gp + fp^2/cp)/dp, -fp/cp); real a = -0.5 * dp/cp; point vertex = point(R, pvertex/R); point focus = point(R, (pvertex + a * expi(-dir))/R); op = parabola(focus, vertex); } else {/* directrix parallel to the rotated(dir) x-axis equation: (x-vertex)^2 = 4 * a * (y-vertex.y) */ pair pvertex = rotate(degrees(-dir)) * (-dp/ap, 0.5 * (-gp + dp^2/ap)/fp); real a = -0.5 * fp/ap; point vertex = point(R, pvertex/R); point focus = point(R, (pvertex + a * expi(pi/2 - dir))/R); op = parabola(focus, vertex); } return op; } /**/ parabola parabola(point M1, point M2, point M3, line l) {/*Return the parabola passing through the three points with its directix parallel to the line 'l'.*/ coordsys R; pair[] pts; if (samecoordsys(M1, M2, M3)) { R = M1.coordsys; } else { R = defaultcoordsys; } real gle = degrees(l); coordsys Rp = cartesiansystem(R.O, rotate(gle) * R.i, rotate(gle) * R.j); pts = new pair[] {coordinates(changecoordsys(Rp, M1)), coordinates(changecoordsys(Rp, M2)), coordinates(changecoordsys(Rp, M3))}; real[][] M; real[] x; for (int i = 0; i < 3; ++i) { M[i] = new real[] {pts[i].x, pts[i].y, 1}; x[i] = -pts[i].x^2; } real[] coef = solve(M, x); return parabola(changecoordsys(R, bqe(Rp, 1, 0, 0, coef[0], coef[1], coef[2]))); } /**/ parabola parabola(point M1, point M2, point M3, point M4, point M5) {/*Return the parabola passing through the five points.*/ return parabola(bqe(M1, M2, M3, M4, M5)); } /**/ hyperbola hyperbola(point C, real a, real b, real angle = 0) {/*Return the hyperbola centered at 'C' with semimajor axis 'a' along C--C + dir(angle), semiminor axis 'b' along the perpendicular.*/ hyperbola oh; coordsys R = C.coordsys; angle += degrees(R.i); real c = sqrt(a^2 + b^2); point f1 = point(R, (locate(C) + rotate(angle) * (-c, 0))/R); point f2 = point(R, (locate(C) + rotate(angle) * (c, 0))/R); oh.init(f1, f2, a); return oh; } /**/ hyperbola hyperbola(bqe bqe) {/*Return the hyperbola a[0]x^2 + a[1]xy + a[2]y^2 + a[3]x + a[4]y + a[5]] = 0 (a[n] means bqe.a[n]). */ bqe lbqe = changecoordsys(defaultcoordsys, bqe); real a = lbqe.a[0], b = lbqe.a[1]/2, c = lbqe.a[2], d = lbqe.a[3]/2, f = lbqe.a[4]/2, g = lbqe.a[5]; string message = "hyperbola: the given equation is not an equation of a hyperbola."; real delta = a * c * g + b * f * d + d * b * f - (b^2 * g + d^2 * c + f^2 * a); if(abs(delta) < 10 * epsgeo || abs(b^2 - a * c) < 0) abort(message); real dir = abs(b) < epsgeo ? 0 : 0.5 * acot(0.5 * (c - a)/b); real cd = cos(dir), sd = sin(dir); real ap = a * cd^2 - 2 * b * cd * sd + c * sd^2; real cp = a * sd^2 + 2 * b * cd * sd + c * cd^2; real dp = d * cd - f * sd; real fp = d * sd + f * cd; real gp = -g + dp^2/ap + fp^2/cp; hyperbola op; coordsys R = bqe.coordsys; real j = b^2 - a * c; point C = point(R, ((c * d - b * f)/j, (a * f - b * d)/j)/R); real aa = gp/ap, bb = gp/cp; real a = sqrt(abs(aa)), b = sqrt(abs(bb)); if(aa < 0) {dir -= pi/2; aa = a; a = b; b = aa;} return hyperbola(C, a, b, degrees(-dir - angle(R.i))); } /**/ hyperbola hyperbola(point M1, point M2, point M3, point M4, point M5) {/*Return the hyperbola passing through the five points (if possible).*/ return hyperbola(bqe(M1, M2, M3, M4, M5)); } /**/ hyperbola conj(hyperbola h) {/*Conjugate.*/ return hyperbola(h.C, h.b, h.a, 90 + h.angle); } /**/ circle circle(explicit point C, real r) {/*Circle given by center and radius.*/ circle oc = new circle; oc.C = C; oc.r = r; if(!finite(r)) oc.l = line(C, C + vector(C.coordsys, (1, 0))); return oc; } /**/ circle circle(point A, point B) {/*Return the circle of diameter AB.*/ real r; circle oc; real a = abs(A), b = abs(B); if(finite(a) && finite(b)) { oc = circle((A + B)/2, abs(A - B)/2); } else { oc.r = infinity; if(finite(abs(A))) oc.l = line(A, A + unit(B)); else { if(finite(abs(B))) oc.l = line(B, B + unit(A)); else if(finite(abs(A - B)/2)) oc = circle((A + B)/2, abs(A - B)/2); else oc.l = line(A, B); } } return oc; } /**/ circle circle(segment s) {/*Return the circle of diameter 's'.*/ return circle(s.A, s.B); } /**/ point circumcenter(point A, point B, point C) {/*Return the circumcenter of triangle ABC.*/ point[] P = standardizecoordsys(A, B, C); coordsys R = P[0].coordsys; pair a = A, b = B, c = C; pair mAB = (a + b)/2; pair mAC = (a + c)/2; pair pp = extension(mAB, rotate(90, mAB) * a, mAC, rotate(90, mAC) * c); return point(R, pp/R); } /**/ circle circle(point A, point B, point C) {/*Return the circumcircle of the triangle ABC.*/ if(collinear(A - B, A - C)) { circle oc; oc.r = infinity; oc.C = (A + B + C)/3; oc.l = line(oc.C, oc.C == A ? B : A); return oc; } point c = circumcenter(A, B, C); return circle(c, abs(c - A)); } /**/ circle circumcircle(point A, point B, point C) {/*Return the circumcircle of the triangle ABC.*/ return circle(A, B, C); } /**/ circle operator *(real x, explicit circle c) {/*Multiply the radius of 'c'.*/ return finite(c.r) ? circle(c.C, x * c.r) : c; } circle operator *(int x, explicit circle c) { return finite(c.r) ? circle(c.C, x * c.r) : c; } /**/ circle operator /(explicit circle c, real x) {/*Divide the radius of 'c'*/ return finite(c.r) ? circle(c.C, c.r/x) : c; } circle operator /(explicit circle c, int x) { return finite(c.r) ? circle(c.C, c.r/x) : c; } /**/ circle operator +(explicit circle c, explicit point M) {/*Translation of 'c'.*/ return circle(c.C + M, c.r); } /**/ circle operator -(explicit circle c, explicit point M) {/*Translation of 'c'.*/ return circle(c.C - M, c.r); } /**/ circle operator +(explicit circle c, pair m) {/*Translation of 'c'. 'm' represent coordinates in the coordinate system where 'c' is defined.*/ return circle(c.C + m, c.r); } /**/ circle operator -(explicit circle c, pair m) {/*Translation of 'c'. 'm' represent coordinates in the coordinate system where 'c' is defined.*/ return circle(c.C - m, c.r); } /**/ circle operator +(explicit circle c, vector m) {/*Translation of 'c'.*/ return circle(c.C + m, c.r); } /**/ circle operator -(explicit circle c, vector m) {/*Translation of 'c'.*/ return circle(c.C - m, c.r); } /**/ real operator ^(point M, explicit circle c) {/*The power of 'M' with respect to the circle 'c'*/ return xpart((abs(locate(M) - locate(c.C)), c.r)^2); } /**/ bool operator @(point M, explicit circle c) {/*Return true iff 'M' is on the circle 'c'.*/ return finite(c.r) ? abs(abs(locate(M) - locate(c.C)) - abs(c.r)) <= 10 * epsgeo : M @ c.l; } /**/ ellipse operator cast(circle c) {/**/ return finite(c.r) ? ellipse(c.C, c.r, c.r, 0) : ellipse(c.l.A, c.l.B, infinity); } /**/ circle operator cast(ellipse el) {/**/ circle oc; bool infb = (!finite(el.a) || !finite(el.b)); if(!infb && abs(el.a - el.b) > epsgeo) abort("Can not cast ellipse with different axis values to circle"); oc = circle(el.C, infb ? infinity : el.a); oc.l = el.l.copy(); return oc; } /**/ ellipse operator cast(conic co) {/*Cast a conic to an ellipse (can be a circle).*/ if(degenerate(co) && co.e < 1) return ellipse(co.l[0].A, co.l[0].B, infinity); ellipse oe; if(co.e < 1) { real a = co.p/(1 - co.e^2); real c = co.e * a; vector v = co.D.v; if(!sameside(co.D.A + v, co.F, co.D)) v = -v; point f2 = co.F + 2 * c * v; f2 = changecoordsys(co.F.coordsys, f2); oe = a == 0 ? ellipse(co.F, co.p, co.p, 0) : ellipse(co.F, f2, a); } else abort("casting: The conic section is not an ellipse."); return oe; } /**/ parabola operator cast(conic co) {/*Cast a conic to a parabola.*/ parabola op; if(abs(co.e - 1) > epsgeo) abort("casting: The conic section is not a parabola."); op.init(co.F, co.D); return op; } /**/ conic operator cast(parabola p) {/*Cast a parabola to a conic section.*/ return conic(p.F, p.D, 1); } /**/ hyperbola operator cast(conic co) {/*Cast a conic section to an hyperbola.*/ hyperbola oh; if(co.e > 1) { real a = co.p/(co.e^2 - 1); real c = co.e * a; vector v = co.D.v; if(sameside(co.D.A + v, co.F, co.D)) v = -v; point f2 = co.F + 2 * c * v; f2 = changecoordsys(co.F.coordsys, f2); oh = hyperbola(co.F, f2, a); } else abort("casting: The conic section is not an hyperbola."); return oh; } /**/ conic operator cast(hyperbola h) {/*Hyperbola to conic section.*/ return conic(h.F1, h.D1, h.e); } /**/ conic operator cast(ellipse el) {/*Ellipse to conic section.*/ conic oc; if(abs(el.c) > epsgeo) { real x = el.a^2/el.c; point O = (el.F1 + el.F2)/2; point A = O + x * unit(el.F1 - el.F2); oc = conic(el.F1, perpendicular(A, line(el.F1, el.F2)), el.e); } else {//The ellipse is a circle coordsys R = coordsys(el); point M = el.F1 + point(R, R.polar(el.a, 0)); line l = line(rotate(90, M) * el.F1, M); oc = conic(el.F1, l, 0); } if(degenerate(el)) { oc.p = infinity; oc.h = infinity; oc.l = new line[]{el.l}; } return oc; } /**/ conic operator cast(circle c) {/*Circle to conic section.*/ return (conic)((ellipse)c); } /**/ circle operator cast(conic c) {/*Conic section to circle.*/ ellipse el = (ellipse)c; circle oc; if(abs(el.a - el.b) < epsgeo) { oc = circle(el.C, el.a); if(degenerate(c)) oc.l = c.l[0]; } else abort("Can not cast this conic to a circle"); return oc; } /**/ ellipse operator *(transform t, ellipse el) {/*Provide transform * ellipse.*/ if(!degenerate(el)) { point[] ep; for (int i = 0; i < 360; i += 72) { ep.push(t * angpoint(el, i)); } ellipse oe = ellipse(ep[0], ep[1], ep[2], ep[3], ep[4]); if(angpoint(oe, 0) != ep[0]) return ellipse(oe.F2, oe.F1, oe.a); return oe; } return ellipse(t * el.l.A, t * el.l.B, infinity); } /**/ parabola operator *(transform t, parabola p) {/*Provide transform * parabola.*/ point[] P; P.push(t * angpoint(p, 45)); P.push(t * angpoint(p, -45)); P.push(t * angpoint(p, 180)); parabola op = parabola(P[0], P[1], P[2], t * p.D); op.bmin = p.bmin; op.bmax = p.bmax; return op; } /**/ ellipse operator *(transform t, circle c) {/*Provide transform * circle. For example, 'circle C = scale(2) * circle' and 'ellipse E = xscale(2) * circle' are valid but 'circle C = xscale(2) * circle' is invalid.*/ return t * ((ellipse)c); } /**/ hyperbola operator *(transform t, hyperbola h) {/*Provide transform * hyperbola.*/ if (t == identity()) { return h; } point[] ep; for (int i = 90; i <= 270; i += 45) { ep.push(t * angpoint(h, i)); } hyperbola oe = hyperbola(ep[0], ep[1], ep[2], ep[3], ep[4]); if(angpoint(oe, 90) != ep[0]) { oe = hyperbola(oe.F2, oe.F1, oe.a); } oe.bmin = h.bmin; oe.bmax = h.bmax; return oe; } /**/ conic operator *(transform t, conic co) {/*Provide transform * conic.*/ if(co.e < 1) return (t * ((ellipse)co)); if(co.e == 1) return (t * ((parabola)co)); return (t * ((hyperbola)co)); } /**/ ellipse operator *(real x, ellipse el) {/*Identical but more efficient (rapid) than 'scale(x, el.C) * el'.*/ return degenerate(el) ? el : ellipse(el.C, x * el.a, x * el.b, el.angle); } /**/ ellipse operator /(ellipse el, real x) {/*Identical but more efficient (rapid) than 'scale(1/x, el.C) * el'.*/ return degenerate(el) ? el : ellipse(el.C, el.a/x, el.b/x, el.angle); } /**/ path arcfromcenter(ellipse el, real angle1, real angle2, bool direction=CCW, int n=ellipsenodesnumber(el.a,el.b,angle1,angle2,direction)) {/*Return the path of the ellipse 'el' from angle1 to angle2 in degrees, drawing in the given direction, with n nodes. The angles are mesured relatively to the axis (C,x-axis) where C is the center of the ellipse.*/ if(degenerate(el)) abort("arcfromcenter: can not convert degenerated ellipse to path."); if (angle1 > angle2) return reverse(arcfromcenter(el, angle2, angle1, !direction, n)); guide op; coordsys Rp=coordsys(el); if (n < 1) return op; interpolate join = operator ..; real stretch = max(el.a/el.b, el.b/el.a); if (stretch > 10) { n *= floor(stretch/5); join = operator --; } real a1 = direction ? radians(angle1) : radians(angle2); real a2 = direction ? radians(angle2) : radians(angle1) + 2 * pi; real step=(a2 - a1)/(n != 1 ? n-1 : 1); real a, r; real da = radians(el.angle); for (int i=0; i < n; ++i) { a = a1 + i * step; r = el.b/sqrt(1 - (el.e * cos(a))^2); op = join(op, Rp*Rp.polar(r, da + a)); } return shift(el.C.x*Rp.i + el.C.y*Rp.j) * (direction ? op : reverse(op)); } /**/ path arcfromcenter(hyperbola h, real angle1, real angle2, int n = hyperbolanodesnumber(h, angle1, angle2), bool direction = CCW) {/*Return the path of the hyperbola 'h' from angle1 to angle2 in degrees, drawing in the given direction, with n nodes. The angles are mesured relatively to the axis (C, x-axis) where C is the center of the hyperbola.*/ guide op; coordsys Rp = coordsys(h); if (n < 1) return op; if (angle1 > angle2) { path g = reverse(arcfromcenter(h, angle2, angle1, n, !direction)); return g == nullpath ? g : reverse(g); } real a1 = direction ? radians(angle1) : radians(angle2); real a2 = direction ? radians(angle2) : radians(angle1) + 2 * pi; real step = (a2 - a1)/(n != 1 ? n - 1 : 1); real a, r; typedef guide interpolate(... guide[]); interpolate join = operator ..; real da = radians(h.angle); for (int i = 0; i < n; ++i) { a = a1 + i * step; r = (h.b * cos(a))^2 - (h.a * sin(a))^2; if(r > epsgeo) { r = sqrt(h.a^2 * h.b^2/r); op = join(op, Rp * Rp.polar(r, a + da)); join = operator ..; } else join = operator --; } return shift(h.C.x * Rp.i + h.C.y * Rp.j)* (direction ? op : op == nullpath ? op : reverse(op)); } /**/ path arcfromcenter(explicit conic co, real angle1, real angle2, int n, bool direction = CCW) {/*Use arcfromcenter(ellipse, ...) or arcfromcenter(hyperbola, ...) depending of the eccentricity of 'co'.*/ path g; if(co.e < 1) g = arcfromcenter((ellipse)co, angle1, angle2, direction, n); else if(co.e > 1) g = arcfromcenter((hyperbola)co, angle1, angle2, n, direction); else abort("arcfromcenter: does not exist for a parabola."); return g; } /**/ restricted polarconicroutine fromCenter = arcfromcenter;/**/ /**/ restricted polarconicroutine fromFocus = arcfromfocus;/**/ /**/ bqe equation(ellipse el) {/*Return the coefficients of the equation of the ellipse in its coordinate system: bqe.a[0] * x^2 + bqe.a[1] * x * y + bqe.a[2] * y^2 + bqe.a[3] * x + bqe.a[4] * y + bqe.a[5] = 0. One can change the coordinate system of 'bqe' using the routine 'changecoordsys'.*/ pair[] pts; for (int i = 0; i < 360; i += 72) pts.push(locate(angpoint(el, i))); real[][] M; real[] x; for (int i = 0; i < 5; ++i) { M[i] = new real[] {pts[i].x * pts[i].y, pts[i].y^2, pts[i].x, pts[i].y, 1}; x[i] = -pts[i].x^2; } real[] coef = solve(M, x); bqe bqe = changecoordsys(coordsys(el), bqe(defaultcoordsys, 1, coef[0], coef[1], coef[2], coef[3], coef[4])); bqe.a = approximate(bqe.a); return bqe; } /**/ bqe equation(parabola p) {/*Return the coefficients of the equation of the parabola in its coordinate system. bqe.a[0] * x^2 + bqe.a[1] * x * y + bqe.a[2] * y^2 + bqe.a[3] * x + bqe.a[4] * y + bqe.a[5] = 0 One can change the coordinate system of 'bqe' using the routine 'changecoordsys'.*/ coordsys R = canonicalcartesiansystem(p); parabola tp = changecoordsys(R, p); point A = projection(tp.D) * point(R, (0, 0)); real a = abs(A); return changecoordsys(coordsys(p), bqe(R, 0, 0, 1, -4 * a, 0, 0)); } /**/ bqe equation(hyperbola h) {/*Return the coefficients of the equation of the hyperbola in its coordinate system. bqe.a[0] * x^2 + bqe.a[1] * x * y + bqe.a[2] * y^2 + bqe.a[3] * x + bqe.a[4] * y + bqe.a[5] = 0 One can change the coordinate system of 'bqe' using the routine 'changecoordsys'.*/ coordsys R = canonicalcartesiansystem(h); return changecoordsys(coordsys(h), bqe(R, 1/h.a^2, 0, -1/h.b^2, 0, 0, -1)); } /**/ path operator cast(ellipse el) {/*Cast ellipse to path.*/ if(degenerate(el)) abort("Casting degenerated ellipse to path is not possible."); int n = el.e == 0 ? circlenodesnumber(el.a) : ellipsenodesnumber(el.a, el.b); return arcfromcenter(el, 0.0, 360, CCW, n)&cycle; } /**/ path operator cast(circle c) {/*Cast circle to path.*/ return (path)((ellipse)c); } /**/ real[] bangles(picture pic = currentpicture, parabola p) {/*Return the array {ma, Ma} where 'ma' and 'Ma' are respectively the smaller and the larger angles for which the parabola 'p' is included in the bounding box of the picture 'pic'.*/ pair bmin, bmax; pair[] b; if (p.bmin == p.bmax) { bmin = pic.userMin(); bmax = pic.userMax(); } else { bmin = p.bmin;bmax = p.bmax; } if(bmin.x == bmax.x || bmin.y == bmax.y || !finite(abs(bmin)) || !finite(abs(bmax))) return new real[] {0, 0}; b[0] = bmin; b[1] = (bmax.x, bmin.y); b[2] = bmax; b[3] = (bmin.x, bmax.y); real[] eq = changecoordsys(defaultcoordsys, equation(p)).a; pair[] inter; for (int i = 0; i < 4; ++i) { pair[] tmp = intersectionpoints(b[i], b[(i + 1)%4], eq); for (int j = 0; j < tmp.length; ++j) { if(dot(b[i]-tmp[j], b[(i + 1)%4]-tmp[j]) <= epsgeo) inter.push(tmp[j]); } } pair F = p.F, V = p.V; real d = degrees(F - V); real[] a = sequence(new real(int n){ return (360 - d + degrees(inter[n]-F))%360; }, inter.length); real ma = a.length != 0 ? min(a) : 0, Ma= a.length != 0 ? max(a) : 0; return new real[] {ma, Ma}; } /**/ real[][] bangles(picture pic = currentpicture, hyperbola h) {/*Return the array {{ma1, Ma1}, {ma2, Ma2}} where 'maX' and 'MaX' are respectively the smaller and the bigger angles (from h.FX) for which the hyperbola 'h' is included in the bounding box of the picture 'pic'.*/ pair bmin, bmax; pair[] b; if (h.bmin == h.bmax) { bmin = pic.userMin(); bmax = pic.userMax(); } else { bmin = h.bmin;bmax = h.bmax; } if(bmin.x == bmax.x || bmin.y == bmax.y || !finite(abs(bmin)) || !finite(abs(bmax))) return new real[][] {{0, 0}, {0, 0}}; b[0] = bmin; b[1] = (bmax.x, bmin.y); b[2] = bmax; b[3] = (bmin.x, bmax.y); real[] eq = changecoordsys(defaultcoordsys, equation(h)).a; pair[] inter0, inter1; pair C = locate(h.C); pair F1 = h.F1; for (int i = 0; i < 4; ++i) { pair[] tmp = intersectionpoints(b[i], b[(i + 1)%4], eq); for (int j = 0; j < tmp.length; ++j) { if(dot(b[i]-tmp[j], b[(i + 1)%4]-tmp[j]) <= epsgeo) { if(dot(F1 - C, tmp[j]-C) > 0) inter0.push(tmp[j]); else inter1.push(tmp[j]); } } } real d = degrees(F1 - C); real[] ma, Ma; pair[][] inter = new pair[][] {inter0, inter1}; for (int i = 0; i < 2; ++i) { real[] a = sequence(new real(int n){ return (360 - d + degrees(inter[i][n]-F1))%360; }, inter[i].length); ma[i] = a.length != 0 ? min(a) : 0; Ma[i] = a.length != 0 ? max(a) : 0; } return new real[][] {{ma[0], Ma[0]}, {ma[1], Ma[1]}}; } /**/ path operator cast(parabola p) {/*Cast parabola to path. If possible, the returned path is restricted to the actual bounding box of the current picture if the variables 'p.bmin' and 'p.bmax' are not set else the bounding box of box(p.bmin, p.bmax) is used instead.*/ real[] bangles = bangles(p); int n = parabolanodesnumber(p, bangles[0], bangles[1]); return arcfromfocus(p, bangles[0], bangles[1], n, CCW); } /**/ void draw(picture pic = currentpicture, Label L = "", circle c, align align = NoAlign, pen p = currentpen, arrowbar arrow = None, arrowbar bar = None, margin margin = NoMargin, Label legend = "", marker marker = nomarker) {/**/ if(degenerate(c)) draw(pic, L, c.l, align, p, arrow, legend, marker); else draw(pic, L, (path)c, align, p, arrow, bar, margin, legend, marker); } /**/ void draw(picture pic = currentpicture, Label L = "", ellipse el, align align = NoAlign, pen p = currentpen, arrowbar arrow = None, arrowbar bar = None, margin margin = NoMargin, Label legend = "", marker marker = nomarker) {/*Draw the ellipse 'el' if it is not degenerated else draw 'el.l'.*/ if(degenerate(el)) draw(pic, L, el.l, align, p, arrow, legend, marker); else draw(pic, L, (path)el, align, p, arrow, bar, margin, legend, marker); } /**/ void draw(picture pic = currentpicture, Label L = "", parabola parabola, align align = NoAlign, pen p = currentpen, arrowbar arrow = None, arrowbar bar = None, margin margin = NoMargin, Label legend = "", marker marker = nomarker) {/*Draw the parabola 'p' on 'pic' without (if possible) altering the size of picture pic.*/ pic.add(new void (frame f, transform t, transform T, pair m, pair M) { // Reduce the bounds by the size of the pen and the margins. m -= min(p); M -= max(p); parabola.bmin = inverse(t) * m; parabola.bmax = inverse(t) * M; picture tmp; path pp = t * ((path) (T * parabola)); if (pp != nullpath) { draw(tmp, L, pp, align, p, arrow, bar, NoMargin, legend, marker); add(f, tmp.fit()); } }, true); pair m = pic.userMin(), M = pic.userMax(); if(m != M) { pic.addBox(truepoint(SW), truepoint(NE)); } } /**/ path operator cast(hyperbola h) {/*Cast hyperbola to path. If possible, the returned path is restricted to the actual bounding box of the current picture unless the variables 'h.bmin' and 'h.bmax' are set; in this case the bounding box of box(h.bmin, h.bmax) is used instead. Only the branch on the side of 'h.F1' is considered.*/ real[][] bangles = bangles(h); int n = hyperbolanodesnumber(h, bangles[0][0], bangles[0][1]); return arcfromfocus(h, bangles[0][0], bangles[0][1], n, CCW); } /**/ void draw(picture pic = currentpicture, Label L = "", hyperbola h, align align = NoAlign, pen p = currentpen, arrowbar arrow = None, arrowbar bar = None, margin margin = NoMargin, Label legend = "", marker marker = nomarker) {/*Draw the hyperbola 'h' on 'pic' without (if possible) altering the size of the picture pic.*/ pic.add(new void (frame f, transform t, transform T, pair m, pair M) { // Reduce the bounds by the size of the pen and the margins. m -= min(p); M -= max(p); h.bmin = inverse(t) * m; h.bmax = inverse(t) * M; path hp; picture tmp; hp = t * ((path) (T * h)); if (hp != nullpath) { draw(tmp, L, hp, align, p, arrow, bar, NoMargin, legend, marker); } hyperbola ht = hyperbola(h.F2, h.F1, h.a); ht.bmin = h.bmin; ht.bmax = h.bmax; hp = t * ((path) (T * ht)); if (hp != nullpath) { draw(tmp, "", hp, align, p, arrow, bar, NoMargin, marker); } add(f, tmp.fit()); }, true); pair m = pic.userMin(), M = pic.userMax(); if(m != M) pic.addBox(truepoint(SW), truepoint(NE)); } /**/ void draw(picture pic = currentpicture, Label L = "", explicit conic co, align align = NoAlign, pen p = currentpen, arrowbar arrow = None, arrowbar bar = None, margin margin = NoMargin, Label legend = "", marker marker = nomarker) {/*Use one of the routine 'draw(ellipse, ...)', 'draw(parabola, ...)' or 'draw(hyperbola, ...)' depending of the value of eccentricity of 'co'.*/ if(co.e == 0) draw(pic, L, (circle)co, align, p, arrow, bar, margin, legend, marker); else if(co.e < 1) draw(pic, L, (ellipse)co, align, p, arrow, bar, margin, legend, marker); else if(co.e == 1) draw(pic, L, (parabola)co, align, p, arrow, bar, margin, legend, marker); else if(co.e > 1) draw(pic, L, (hyperbola)co, align, p, arrow, bar, margin, legend, marker); else abort("draw: unknown conic."); } /**/ int conicnodesnumber(conic co, real angle1, real angle2, bool dir = CCW) {/*Return the number of node to draw a conic arc.*/ int oi; if(co.e == 0) { circle c = (circle)co; oi = circlenodesnumber(c.r, angle1, angle2); } else if(co.e < 1) { ellipse el = (ellipse)co; oi = ellipsenodesnumber(el.a, el.b, angle1, angle2, dir); } else if(co.e == 1) { parabola p = (parabola)co; oi = parabolanodesnumber(p, angle1, angle2); } else { hyperbola h = (hyperbola)co; oi = hyperbolanodesnumber(h, angle1, angle2); } return oi; } /**/ path operator cast(conic co) {/*Cast conic section to path.*/ if(co.e < 1) return (path)((ellipse)co); if(co.e == 1) return (path)((parabola)co); return (path)((hyperbola)co); } /**/ bqe equation(explicit conic co) {/*Return the coefficients of the equation of conic section in its coordinate system: bqe.a[0] * x^2 + bqe.a[1] * x * y + bqe.a[2] * y^2 + bqe.a[3] * x + bqe.a[4] * y + bqe.a[5] = 0. One can change the coordinate system of 'bqe' using the routine 'changecoordsys'.*/ bqe obqe; if(co.e == 0) obqe = equation((circle)co); else if(co.e < 1) obqe = equation((ellipse)co); else if(co.e == 1) obqe = equation((parabola)co); else if(co.e > 1) obqe = equation((hyperbola)co); else abort("draw: unknown conic."); return obqe; } /**/ string conictype(bqe bqe) {/*Returned values are "ellipse" or "parabola" or "hyperbola" depending of the conic section represented by 'bqe'.*/ bqe lbqe = changecoordsys(defaultcoordsys, bqe); string os = "degenerated"; real a = lbqe.a[0], b = lbqe.a[1]/2, c = lbqe.a[2], d = lbqe.a[3]/2, f = lbqe.a[4]/2, g = lbqe.a[5]; real delta = a * c * g + b * f * d + d * b * f - (b^2 * g + d^2 * c + f^2 * a); if(abs(delta) < 10 * epsgeo) return os; real J = a * c - b^2; real I = a + c; if(J > epsgeo) { if(delta/I < -epsgeo); os = "ellipse"; } else { if(abs(J) < epsgeo) os = "parabola"; else os = "hyperbola"; } return os; } /**/ conic conic(point M1, point M2, point M3, point M4, point M5) {/*Return the conic passing through 'M1', 'M2', 'M3', 'M4' and 'M5' if the conic is not degenerated.*/ bqe bqe = bqe(M1, M2, M3, M4, M5); string ct = conictype(bqe); if(ct == "degenerated") abort("conic: degenerated conic passing through five points."); if(ct == "ellipse") return ellipse(bqe); if(ct == "parabola") return parabola(bqe); return hyperbola(bqe); } /**/ coordsys canonicalcartesiansystem(explicit conic co) {/*Return the canonical cartesian system of the conic 'co'.*/ if(co.e < 1) return canonicalcartesiansystem((ellipse)co); else if(co.e == 1) return canonicalcartesiansystem((parabola)co); return canonicalcartesiansystem((hyperbola)co); } /**/ bqe canonical(bqe bqe) {/*Return the bivariate quadratic equation relative to the canonical coordinate system of the conic section represented by 'bqe'.*/ string type = conictype(bqe); if(type == "") abort("canonical: the equation can not be performed."); bqe obqe; if(type == "ellipse") { ellipse el = ellipse(bqe); obqe = changecoordsys(canonicalcartesiansystem(el), equation(el)); } else { if(type == "parabola") { parabola p = parabola(bqe); obqe = changecoordsys(canonicalcartesiansystem(p), equation(p)); } else { hyperbola h = hyperbola(bqe); obqe = changecoordsys(canonicalcartesiansystem(h), equation(h)); } } return obqe; } /**/ conic conic(bqe bqe) {/*Return the conic section represented by the bivariate quartic equation 'bqe'.*/ string type = conictype(bqe); if(type == "") abort("canonical: the equation can not be performed."); conic oc; if(type == "ellipse") { oc = ellipse(bqe); } else { if(type == "parabola") oc = parabola(bqe); else oc = hyperbola(bqe); } return oc; } /**/ real arclength(circle c) {/**/ return c.r * 2 * pi; } /**/ real focusToCenter(ellipse el, real a) {/*Return the angle relatively to the center of 'el' for the angle 'a' given relatively to the focus of 'el'.*/ pair p = point(fromFocus(el, a, a, 1, CCW), 0); pair c = locate(el.C); real d = degrees(p - c) - el.angle; d = abs(d) < epsgeo ? 0 : d; // Avoid -1e-15 return d%(sgnd(a) * 360); } /**/ real centerToFocus(ellipse el, real a) {/*Return the angle relatively to the focus of 'el' for the angle 'a' given relatively to the center of 'el'.*/ pair P = point(fromCenter(el, a, a, 1, CCW), 0); pair F1 = locate(el.F1); pair F2 = locate(el.F2); real d = degrees(P - F1) - degrees(F2 - F1); d = abs(d) < epsgeo ? 0 : d; // Avoid -1e-15 return d%(sgnd(a) * 360); } /**/ real arclength(ellipse el) {/**/ return degenerate(el) ? infinity : 4 * el.a * elle(pi/2, el.e); } /**/ real arclength(ellipse el, real angle1, real angle2, bool direction = CCW, polarconicroutine polarconicroutine = currentpolarconicroutine) {/*Return the length of the arc of the ellipse between 'angle1' and 'angle2'. 'angle1' and 'angle2' must be in the interval ]-360;+oo[ if polarconicroutine = fromFocus, ]-oo;+oo[ if polarconicroutine = fromCenter.*/ if(degenerate(el)) return infinity; if(angle1 > angle2) return arclength(el, angle2, angle1, !direction, polarconicroutine); // path g;int n = 1000; // if(el.e == 0) g = arcfromcenter(el, angle1, angle2, n, direction); // if(el.e != 1) g = polarconicroutine(el, angle1, angle2, n, direction); // write("with path = ", arclength(g)); if(polarconicroutine == fromFocus) { // dot(point(fromFocus(el, angle1, angle1, 1, CCW), 0), 2mm + blue); // dot(point(fromFocus(el, angle2, angle2, 1, CCW), 0), 2mm + blue); // write("fromfocus1 = ", angle1); // write("fromfocus2 = ", angle2); real gle1 = focusToCenter(el, angle1); real gle2 = focusToCenter(el, angle2); if((gle1 - gle2) * (angle1 - angle2) > 0) { angle1 = gle1; angle2 = gle2; } else { angle1 = gle2; angle2 = gle1; } // dot(point(fromCenter(el, angle1, angle1, 1, CCW), 0), 1mm + red); // dot(point(fromCenter(el, angle2, angle2, 1, CCW), 0), 1mm + red); // write("fromcenter1 = ", angle1); // write("fromcenter2 = ", angle2); } if(angle1 < 0 || angle2 < 0) return arclength(el, 180 + angle1, 180 + angle2, direction, fromCenter); real a1 = direction ? angle1 : angle2; real a2 = direction ? angle2 : angle1 + 360; real elleq = el.a * elle(pi/2, el.e); real S(real a) {//Return the arclength from 0 to the angle 'a' (in degrees) // given form the center of the ellipse. real gle = atan(el.a * tan(radians(a))/el.b)+ pi * (((a%90 == 0 && a != 0) ? floor(a/90) - 1 : floor(a/90)) - ((a%180 == 0) ? 0 : floor(a/180)) - (a%360 == 0 ? floor(a/(360)) : 0)); /* // Uncomment to visualize the used branches unitsize(2cm, 1cm); import graph; real xmin = 0, xmax = 3pi; xlimits( xmin, xmax); ylimits( 0, 10); yaxis( "y" , LeftRight(), RightTicks(pTick=.8red, ptick = lightgrey, extend = true)); xaxis( "x - value", BottomTop(), Ticks(Label("$%.2f$", red), Step = pi/2, step = pi/4, pTick=.8red, ptick = lightgrey, extend = true)); real p2 = pi/2; real f(real t) { return atan(0.6 * tan(t))+ pi * ((t%p2 == 0 && t != 0) ? floor(t/p2) - 1 : floor(t/p2)) - ((t%pi == 0) ? 0 : pi * floor(t/pi)) - (t%(2pi) == 0 ? pi * floor(t/(2 * pi)) : 0); } draw(graph(f, xmin, xmax, 100)); write(degrees(f(pi/2))); write(degrees(f(pi))); write(degrees(f(3pi/2))); write(degrees(f(2pi))); draw(graph(new real(real t){return t;}, xmin, xmax, 3)); */ return elleq - el.a * elle(pi/2 - gle, el.e); } return S(a2) - S(a1); } /**/ real arclength(parabola p, real angle) {/*Return the arclength from 180 to 'angle' given from focus in the canonical coordinate system of 'p'.*/ real a = p.a; /* In canonicalcartesiansystem(p) the equation of p is x = y^2/(4a) */ // integrate(sqrt(1 + (x/(2 * a))^2), x); real S(real t){return 0.5 * t * sqrt(1 + t^2/(4 * a^2)) + a * asinh(t/(2 * a));} real R(real gle){return 2 * a/(1 - Cos(gle));} real t = Sin(angle) * R(angle); return S(t); } /**/ real arclength(parabola p, real angle1, real angle2) {/*Return the arclength from 'angle1' to 'angle2' given from focus in the canonical coordinate system of 'p'*/ return arclength(p, angle1) - arclength(p, angle2); } /**/ real arclength(parabola p) {/*Return the length of the arc of the parabola bounded to the bounding box of the current picture.*/ real[] b = bangles(p); return arclength(p, b[0], b[1]); } // *........................CONICS.........................* // *=======================================================* // *=======================================================* // *.......................ABSCISSA........................* /**/ struct abscissa {/*Provide abscissa structure on a curve used in the routine-like 'point(object, abscissa)' where object can be 'line','segment','ellipse','circle','conic'...*/ real x;/*The abscissa value.*/ int system;/*0 = relativesystem; 1 = curvilinearsystem; 2 = angularsystem; 3 = nodesystem*/ polarconicroutine polarconicroutine = fromCenter;/*The routine used with angular system and two foci conic section. Possible values are 'formCenter' and 'formFocus'.*/ /**/ abscissa copy() {/*Return a copy of this abscissa.*/ abscissa oa = new abscissa; oa.x = this.x; oa.system = this.system; oa.polarconicroutine = this.polarconicroutine; return oa; } }/**/ /**/ restricted int relativesystem = 0, curvilinearsystem = 1, angularsystem = 2, nodesystem = 3;/*Constant used to set the abscissa system.*/ /**/ abscissa operator cast(explicit position position) {/*Cast position to abscissa. If 'position' is relative, the abscissa is relative else it's a curvilinear abscissa.*/ abscissa oarcc; oarcc.x = position.position.x; oarcc.system = position.relative ? relativesystem : curvilinearsystem; return oarcc; } /**/ abscissa operator +(real x, explicit abscissa a) {/*Provide 'real + abscissa'. Return abscissa b so that b.x = a.x + x. +(explicit abscissa, real), -(real, explicit abscissa) and -(explicit abscissa, real) are also defined.*/ abscissa oa = a.copy(); oa.x = a.x + x; return oa; } abscissa operator +(explicit abscissa a, real x) { return x + a; } abscissa operator +(int x, explicit abscissa a) { return ((real)x) + a; } /**/ abscissa operator -(explicit abscissa a) {/*Return the abscissa b so that b.x = -a.x.*/ abscissa oa; oa.system = a.system; oa.x = -a.x; return oa; } abscissa operator -(real x, explicit abscissa a) { abscissa oa; oa.system = a.system; oa.x = x - a.x; return oa; } abscissa operator -(explicit abscissa a, real x) { abscissa oa; oa.system = a.system; oa.x = a.x - x; return oa; } abscissa operator -(int x, explicit abscissa a) { return ((real)x) - a; } /**/ abscissa operator *(real x, explicit abscissa a) {/*Provide 'real * abscissa'. Return abscissa b so that b.x = x * a.x. *(explicit abscissa, real), /(real, explicit abscissa) and /(explicit abscissa, real) are also defined.*/ abscissa oa; oa.system = a.system; oa.x = a.x * x; return oa; } abscissa operator *(explicit abscissa a, real x) { return x * a; } abscissa operator /(real x, explicit abscissa a) { abscissa oa; oa.system = a.system; oa.x = x/a.x; return oa; } abscissa operator /(explicit abscissa a, real x) { abscissa oa; oa.system = a.system; oa.x = a.x/x; return oa; } abscissa operator /(int x, explicit abscissa a) { return ((real)x)/a; } /**/ abscissa relabscissa(real x) {/*Return a relative abscissa.*/ return (abscissa)(Relative(x)); } abscissa relabscissa(int x) { return (abscissa)(Relative(x)); } /**/ abscissa curabscissa(real x) {/*Return a curvilinear abscissa.*/ return (abscissa)((position)x); } abscissa curabscissa(int x) { return (abscissa)((position)x); } /**/ abscissa angabscissa(real x, polarconicroutine polarconicroutine = currentpolarconicroutine) {/*Return a angular abscissa.*/ abscissa oarcc; oarcc.x = x; oarcc.polarconicroutine = polarconicroutine; oarcc.system = angularsystem; return oarcc; } abscissa angabscissa(int x, polarconicroutine polarconicroutine = currentpolarconicroutine) { return angabscissa((real)x, polarconicroutine); } /**/ abscissa nodabscissa(real x) {/*Return an abscissa as time on the path.*/ abscissa oarcc; oarcc.x = x; oarcc.system = nodesystem; return oarcc; } abscissa nodabscissa(int x) { return nodabscissa((real)x); } /**/ abscissa operator cast(real x) {/*Cast real to abscissa, precisely 'nodabscissa'.*/ return nodabscissa(x); } abscissa operator cast(int x) { return nodabscissa((real)x); } /**/ point point(circle c, abscissa l) {/*Return the point of 'c' which has the abscissa 'l.x' according to the abscissa system 'l.system'.*/ coordsys R = c.C.coordsys; if (l.system == nodesystem) return point(R, point((path)c, l.x)/R); if (l.system == relativesystem) return c.C + point(R, R.polar(c.r, 2 * pi * l.x)); if (l.system == curvilinearsystem) return c.C + point(R, R.polar(c.r, l.x/c.r)); if (l.system == angularsystem) return c.C + point(R, R.polar(c.r, radians(l.x))); abort("point: bad abscissa system."); return (0, 0); } /**/ point point(ellipse el, abscissa l) {/*Return the point of 'el' which has the abscissa 'l.x' according to the abscissa system 'l.system'.*/ if(el.e == 0) return point((circle)el, l); coordsys R = coordsys(el); if (l.system == nodesystem) return point(R, point((path)el, l.x)/R); if (l.system == relativesystem) { return point(el, curabscissa((l.x%1) * arclength(el))); } if (l.system == curvilinearsystem) { real a1 = 0, a2 = 360, cx = 0; real aout = a1; real x = abs(l.x)%arclength(el); while (abs(cx - x) > epsgeo) { aout = (a1 + a2)/2; cx = arclength(el, 0, aout, CCW, fromCenter); //fromCenter is speeder if(cx > x) a2 = (a1 + a2)/2; else a1 = (a1 + a2)/2; } path pel = fromCenter(el, sgn(l.x) * aout, sgn(l.x) * aout, 1, CCW); return point(R, point(pel, 0)/R); } if (l.system == angularsystem) { return point(R, point(l.polarconicroutine(el, l.x, l.x, 1, CCW), 0)/R); } abort("point: bad abscissa system."); return (0, 0); } /**/ point point(parabola p, abscissa l) {/*Return the point of 'p' which has the abscissa 'l.x' according to the abscissa system 'l.system'.*/ coordsys R = coordsys(p); if (l.system == nodesystem) return point(R, point((path)p, l.x)/R); if (l.system == relativesystem) { real[] b = bangles(p); real al = sgn(l.x) > 0 ? arclength(p, 180, b[1]) : arclength(p, 180, b[0]); return point(p, curabscissa(abs(l.x) * al)); } if (l.system == curvilinearsystem) { real a1 = 1e-3, a2 = 360 - 1e-3, cx = infinity; while (abs(cx - l.x) > epsgeo) { cx = arclength(p, 180, (a1 + a2)/2); if(cx > l.x) a2 = (a1 + a2)/2; else a1 = (a1 + a2)/2; } path pp = fromFocus(p, a1, a1, 1, CCW); return point(R, point(pp, 0)/R); } if (l.system == angularsystem) { return point(R, point(fromFocus(p, l.x, l.x, 1, CCW), 0)/R); } abort("point: bad abscissa system."); return (0, 0); } /**/ point point(hyperbola h, abscissa l) {/*Return the point of 'h' which has the abscissa 'l.x' according to the abscissa system 'l.system'.*/ coordsys R = coordsys(h); if (l.system == nodesystem) return point(R, point((path)h, l.x)/R); if (l.system == relativesystem) { abort("point(hyperbola, relativeSystem) is not implemented... Try relpoint((path)your_hyperbola, x);"); } if (l.system == curvilinearsystem) { abort("point(hyperbola, curvilinearSystem) is not implemented..."); } if (l.system == angularsystem) { return point(R, point(l.polarconicroutine(h, l.x, l.x, 1, CCW), 0)/R); } abort("point: bad abscissa system."); return (0, 0); } /**/ point point(explicit conic co, abscissa l) {/*Return the curvilinear abscissa of 'M' on the conic 'co'.*/ if(co.e == 0) return point((circle)co, l); if(co.e < 1) return point((ellipse)co, l); if(co.e == 1) return point((parabola)co, l); return point((hyperbola)co, l); } /**/ point point(line l, abscissa x) {/*Return the point of 'l' which has the abscissa 'l.x' according to the abscissa system 'l.system'. Note that the origin is l.A, and point(l, relabscissa(x)) returns l.A + x.x * vector(l.B - l.A).*/ coordsys R = l.A.coordsys; if (x.system == nodesystem) return l.A + (x.x < 0 ? 0 : x.x > 1 ? 1 : x.x) * vector(l.B - l.A); if (x.system == relativesystem) return l.A + x.x * vector(l.B - l.A); if (x.system == curvilinearsystem) return l.A + x.x * l.u; if (x.system == angularsystem) abort("point: what the meaning of angular abscissa on line ?."); abort("point: bad abscissa system."); return (0, 0); } /**/ point point(line l, explicit real x) {/*Return the point between node l.A and l.B (x <= 0 means l.A, x >=1 means l.B).*/ return point(l, nodabscissa(x)); } point point(line l, explicit int x) { return point(l, nodabscissa(x)); } /**/ point point(explicit circle c, explicit real x) {/*Return the point between node floor(x) and floor(x) + 1.*/ return point(c, nodabscissa(x)); } point point(explicit circle c, explicit int x) { return point(c, nodabscissa(x)); } /**/ point point(explicit ellipse el, explicit real x) {/*Return the point between node floor(x) and floor(x) + 1.*/ return point(el, nodabscissa(x)); } point point(explicit ellipse el, explicit int x) { return point(el, nodabscissa(x)); } /**/ point point(explicit parabola p, explicit real x) {/*Return the point between node floor(x) and floor(x) + 1.*/ return point(p, nodabscissa(x)); } point point(explicit parabola p, explicit int x) { return point(p, nodabscissa(x)); } /**/ point point(explicit hyperbola h, explicit real x) {/*Return the point between node floor(x) and floor(x) + 1.*/ return point(h, nodabscissa(x)); } point point(explicit hyperbola h, explicit int x) { return point(h, nodabscissa(x)); } /**/ point point(explicit conic co, explicit real x) {/*Return the point between node floor(x) and floor(x) + 1.*/ point op; if(co.e == 0) op = point((circle)co, nodabscissa(x)); else if(co.e < 1) op = point((ellipse)co, nodabscissa(x)); else if(co.e == 1) op = point((parabola)co, nodabscissa(x)); else op = point((hyperbola)co, nodabscissa(x)); return op; } point point(explicit conic co, explicit int x) { return point(co, (real)x); } /**/ point relpoint(line l, real x) {/*Return the relative point of 'l' (0 means l.A, 1 means l.B, x means l.A + x * vector(l.B - l.A) ).*/ return point(l, Relative(x)); } /**/ point relpoint(explicit circle c, real x) {/*Return the relative point of 'c' (0 means origin, 1 means end). Origin is c.center + c.r * (1, 0).*/ return point(c, Relative(x)); } /**/ point relpoint(explicit ellipse el, real x) {/*Return the relative point of 'el' (0 means origin, 1 means end).*/ return point(el, Relative(x)); } /**/ point relpoint(explicit parabola p, real x) {/*Return the relative point of the path of the parabola bounded by the bounding box of the current picture. 0 means origin, 1 means end, where the origin is the vertex of 'p'.*/ return point(p, Relative(x)); } /**/ point relpoint(explicit hyperbola h, real x) {/*Not yet implemented... */ return point(h, Relative(x)); } /**/ point relpoint(explicit conic co, explicit real x) {/*Return the relative point of 'co' (0 means origin, 1 means end).*/ point op; if(co.e == 0) op = point((circle)co, Relative(x)); else if(co.e < 1) op = point((ellipse)co, Relative(x)); else if(co.e == 1) op = point((parabola)co, Relative(x)); else op = point((hyperbola)co, Relative(x)); return op; } point relpoint(explicit conic co, explicit int x) { return relpoint(co, (real)x); } /**/ point angpoint(explicit circle c, real x) {/*Return the point of 'c' in the direction 'x' measured in degrees.*/ return point(c, angabscissa(x)); } /**/ point angpoint(explicit ellipse el, real x, polarconicroutine polarconicroutine = currentpolarconicroutine) {/*Return the point of 'el' in the direction 'x' measured in degrees according to 'polarconicroutine'.*/ return el.e == 0 ? angpoint((circle) el, x) : point(el, angabscissa(x, polarconicroutine)); } /**/ point angpoint(explicit parabola p, real x) {/*Return the point of 'p' in the direction 'x' measured in degrees.*/ return point(p, angabscissa(x)); } /**/ point angpoint(explicit hyperbola h, real x, polarconicroutine polarconicroutine = currentpolarconicroutine) {/*Return the point of 'h' in the direction 'x' measured in degrees according to 'polarconicroutine'.*/ return point(h, angabscissa(x, polarconicroutine)); } /**/ point curpoint(line l, real x) {/*Return the point of 'l' which has the curvilinear abscissa 'x'. Origin is l.A.*/ return point(l, curabscissa(x)); } /**/ point curpoint(explicit circle c, real x) {/*Return the point of 'c' which has the curvilinear abscissa 'x'. Origin is c.center + c.r * (1, 0).*/ return point(c, curabscissa(x)); } /**/ point curpoint(explicit ellipse el, real x) {/*Return the point of 'el' which has the curvilinear abscissa 'el'.*/ return point(el, curabscissa(x)); } /**/ point curpoint(explicit parabola p, real x) {/*Return the point of 'p' which has the curvilinear abscissa 'x'. Origin is the vertex of 'p'.*/ return point(p, curabscissa(x)); } /**/ point curpoint(conic co, real x) {/*Return the point of 'co' which has the curvilinear abscissa 'x'.*/ point op; if(co.e == 0) op = point((circle)co, curabscissa(x)); else if(co.e < 1) op = point((ellipse)co, curabscissa(x)); else if(co.e == 1) op = point((parabola)co, curabscissa(x)); else op = point((hyperbola)co, curabscissa(x)); return op; } /**/ abscissa angabscissa(circle c, point M) {/*Return the angular abscissa of 'M' on the circle 'c'.*/ if(!(M @ c)) abort("angabscissa: the point is not on the circle."); abscissa oa; oa.system = angularsystem; oa.x = degrees(M - c.C); if(oa.x < 0) oa.x+=360; return oa; } /**/ abscissa angabscissa(ellipse el, point M, polarconicroutine polarconicroutine = currentpolarconicroutine) {/*Return the angular abscissa of 'M' on the ellipse 'el' according to 'polarconicroutine'.*/ if(!(M @ el)) abort("angabscissa: the point is not on the ellipse."); abscissa oa; oa.system = angularsystem; oa.polarconicroutine = polarconicroutine; oa.x = polarconicroutine == fromCenter ? degrees(M - el.C) : degrees(M - el.F1); oa.x -= el.angle; if(oa.x < 0) oa.x += 360; return oa; } /**/ abscissa angabscissa(hyperbola h, point M, polarconicroutine polarconicroutine = currentpolarconicroutine) {/*Return the angular abscissa of 'M' on the hyperbola 'h' according to 'polarconicroutine'.*/ if(!(M @ h)) abort("angabscissa: the point is not on the hyperbola."); abscissa oa; oa.system = angularsystem; oa.polarconicroutine = polarconicroutine; oa.x = polarconicroutine == fromCenter ? degrees(M - h.C) : degrees(M - h.F1) + 180; oa.x -= h.angle; if(oa.x < 0) oa.x += 360; return oa; } /**/ abscissa angabscissa(parabola p, point M) {/*Return the angular abscissa of 'M' on the parabola 'p'.*/ if(!(M @ p)) abort("angabscissa: the point is not on the parabola."); abscissa oa; oa.system = angularsystem; oa.polarconicroutine = fromFocus;// Not used oa.x = degrees(M - p.F); oa.x -= p.angle; if(oa.x < 0) oa.x += 360; return oa; } /**/ abscissa angabscissa(explicit conic co, point M) {/*Return the angular abscissa of 'M' on the conic 'co'.*/ if(co.e == 0) return angabscissa((circle)co, M); if(co.e < 1) return angabscissa((ellipse)co, M); if(co.e == 1) return angabscissa((parabola)co, M); return angabscissa((hyperbola)co, M); } /**/ abscissa curabscissa(line l, point M) {/*Return the curvilinear abscissa of 'M' on the line 'l'.*/ if(!(M @ extend(l))) abort("curabscissa: the point is not on the line."); abscissa oa; oa.system = curvilinearsystem; oa.x = sgn(dot(M - l.A, l.B - l.A)) * abs(M - l.A); return oa; } /**/ abscissa curabscissa(circle c, point M) {/*Return the curvilinear abscissa of 'M' on the circle 'c'.*/ if(!(M @ c)) abort("curabscissa: the point is not on the circle."); abscissa oa; oa.system = curvilinearsystem; oa.x = pi * angabscissa(c, M).x * c.r/180; return oa; } /**/ abscissa curabscissa(ellipse el, point M) {/*Return the curvilinear abscissa of 'M' on the ellipse 'el'.*/ if(!(M @ el)) abort("curabscissa: the point is not on the ellipse."); abscissa oa; oa.system = curvilinearsystem; real a = angabscissa(el, M, fromCenter).x; oa.x = arclength(el, 0, a, fromCenter); oa.polarconicroutine = fromCenter; return oa; } /**/ abscissa curabscissa(parabola p, point M) {/*Return the curvilinear abscissa of 'M' on the parabola 'p'.*/ if(!(M @ p)) abort("curabscissa: the point is not on the parabola."); abscissa oa; oa.system = curvilinearsystem; real a = angabscissa(p, M).x; oa.x = arclength(p, 180, a); oa.polarconicroutine = fromFocus; // Not used. return oa; } /**/ abscissa curabscissa(conic co, point M) {/*Return the curvilinear abscissa of 'M' on the conic 'co'.*/ if(co.e > 1) abort("curabscissa: not implemented for this hyperbola."); if(co.e == 0) return curabscissa((circle)co, M); if(co.e < 1) return curabscissa((ellipse)co, M); return curabscissa((parabola)co, M); } /**/ abscissa nodabscissa(line l, point M) {/*Return the node abscissa of 'M' on the line 'l'.*/ if(!(M @ (segment)l)) abort("nodabscissa: the point is not on the segment."); abscissa oa; oa.system = nodesystem; oa.x = abs(M - l.A)/abs(l.A - l.B); return oa; } /**/ abscissa nodabscissa(circle c, point M) {/*Return the node abscissa of 'M' on the circle 'c'.*/ if(!(M @ c)) abort("nodabscissa: the point is not on the circle."); abscissa oa; oa.system = nodesystem; oa.x = intersect((path)c, locate(M))[0]; return oa; } /**/ abscissa nodabscissa(ellipse el, point M) {/*Return the node abscissa of 'M' on the ellipse 'el'.*/ if(!(M @ el)) abort("nodabscissa: the point is not on the ellipse."); abscissa oa; oa.system = nodesystem; oa.x = intersect((path)el, M)[0]; return oa; } /**/ abscissa nodabscissa(parabola p, point M) {/*Return the node abscissa OF 'M' on the parabola 'p'.*/ if(!(M @ p)) abort("nodabscissa: the point is not on the parabola."); abscissa oa; oa.system = nodesystem; path pg = p; real[] t = intersect(pg, M, 1e-5); if(t.length == 0) abort("nodabscissa: the point is not on the path of the parabola."); oa.x = t[0]; return oa; } /**/ abscissa nodabscissa(conic co, point M) {/*Return the node abscissa of 'M' on the conic 'co'.*/ if(co.e > 1) abort("nodabscissa: not implemented for hyperbola."); if(co.e == 0) return nodabscissa((circle)co, M); if(co.e < 1) return nodabscissa((ellipse)co, M); return nodabscissa((parabola)co, M); } /**/ abscissa relabscissa(line l, point M) {/*Return the relative abscissa of 'M' on the line 'l'.*/ if(!(M @ extend(l))) abort("relabscissa: the point is not on the line."); abscissa oa; oa.system = relativesystem; oa.x = sgn(dot(M - l.A, l.B - l.A)) * abs(M - l.A)/abs(l.A - l.B); return oa; } /**/ abscissa relabscissa(circle c, point M) {/*Return the relative abscissa of 'M' on the circle 'c'.*/ if(!(M @ c)) abort("relabscissa: the point is not on the circle."); abscissa oa; oa.system = relativesystem; oa.x = angabscissa(c, M).x/360; return oa; } /**/ abscissa relabscissa(ellipse el, point M) {/*Return the relative abscissa of 'M' on the ellipse 'el'.*/ if(!(M @ el)) abort("relabscissa: the point is not on the ellipse."); abscissa oa; oa.system = relativesystem; oa.x = curabscissa(el, M).x/arclength(el); oa.polarconicroutine = fromFocus; return oa; } /**/ abscissa relabscissa(conic co, point M) {/*Return the relative abscissa of 'M' on the conic 'co'.*/ if(co.e > 1) abort("relabscissa: not implemented for hyperbola and parabola."); if(co.e == 1) return relabscissa((parabola)co, M); if(co.e == 0) return relabscissa((circle)co, M); return relabscissa((ellipse)co, M); } // *.......................ABSCISSA........................* // *=======================================================* // *=======================================================* // *.........................ARCS..........................* /**/ struct arc { /*Implement oriented ellipse (included circle) arcs. All the calculus with this structure will be as exact as Asymptote can do. For a full precision, you must not cast 'arc' to 'path' excepted for drawing routines. */ ellipse el;/*The support of the arc.*/ restricted real angle0 = 0;/*Internal use: rotating a circle does not modify the origin point,this variable stocks the eventual angle rotation. This value is not used for ellipses which are not circles.*/ restricted real angle1, angle2;/*Values (in degrees) in ]-360, 360[.*/ bool direction = CCW;/*The arc will be drawn from 'angle1' to 'angle2' rotating in the direction 'direction'.*/ polarconicroutine polarconicroutine = currentpolarconicroutine;/*The routine to which the angles refer. If 'el' is a circle 'fromCenter' is always used.*/ /**/ void setangles(real a0, real a1, real a2) {/*Set the angles.*/ if (a1 < 0 && a2 < 0) { a1 += 360; a2 += 360; } this.angle0 = a0%(sgnd(a0) * 360); this.angle1 = a1%(sgnd(a1) * 360); this.angle2 = a2%(sgnd(2) * 360); } /**/ void init(ellipse el, real angle0 = 0, real angle1, real angle2, polarconicroutine polarconicroutine, bool direction = CCW) {/*Constructor.*/ if(abs(angle1 - angle2) > 360) abort("arc: |angle1 - angle2| > 360."); this.el = el; this.setangles(angle0, angle1, angle2); this.polarconicroutine = polarconicroutine; this.direction = direction; } /**/ arc copy() {/*Copy the arc.*/ arc oa = new arc; oa.el = this.el; oa.direction = this.direction; oa.polarconicroutine = this.polarconicroutine; oa.angle1 = this.angle1; oa.angle2 = this.angle2; oa.angle0 = this.angle0; return oa; } }/**/ /**/ polarconicroutine polarconicroutine(conic co) {/*Return the default routine used to draw a conic.*/ if(co.e == 0) return fromCenter; if(co.e == 1) return fromFocus; return currentpolarconicroutine; } /**/ arc arc(ellipse el, real angle1, real angle2, polarconicroutine polarconicroutine = polarconicroutine(el), bool direction = CCW) {/*Return the ellipse arc from 'angle1' to 'angle2' with respect to 'polarconicroutine' and rotating in the direction 'direction'.*/ arc oa; oa.init(el, 0, angle1, angle2, polarconicroutine, direction); return oa; } /**/ arc complementary(arc a) {/*Return the complementary of 'a'.*/ arc oa; oa.init(a.el, a.angle0, a.angle2, a.angle1, a.polarconicroutine, a.direction); return oa; } /**/ arc reverse(arc a) {/*Return arc 'a' oriented in reverse direction.*/ arc oa; oa.init(a.el, a.angle0, a.angle2, a.angle1, a.polarconicroutine, !a.direction); return oa; } /**/ real degrees(arc a) {/*Return the measure in degrees of the oriented arc 'a'.*/ real or; real da = a.angle2 - a.angle1; if(a.direction) { or = a.angle1 < a.angle2 ? da : 360 + da; } else { or = a.angle1 < a.angle2 ? -360 + da : da; } return or; } /**/ real angle(arc a) {/*Return the measure in radians of the oriented arc 'a'.*/ return radians(degrees(a)); } /**/ int arcnodesnumber(explicit arc a) {/*Return the number of nodes to draw the arc 'a'.*/ return ellipsenodesnumber(a.el.a, a.el.b, a.angle1, a.angle2, a.direction); } private path arctopath(arc a, int n) { if(a.el.e == 0) return arcfromcenter(a.el, a.angle0 + a.angle1, a.angle0 + a.angle2, a.direction, n); if(a.el.e != 1) return a.polarconicroutine(a.el, a.angle1, a.angle2, n, a.direction); return arcfromfocus(a.el, a.angle1, a.angle2, n, a.direction); } /**/ point angpoint(arc a, real angle) {/*Return the point given by its angular position (in degrees) relative to the arc 'a'. If 'angle > degrees(a)' or 'angle < 0' the returned point is on the extended arc.*/ pair p; if(a.el.e == 0) { real gle = a.angle0 + a.angle1 + (a.direction ? angle : -angle); p = point(arcfromcenter(a.el, gle, gle, CCW, 1), 0); } else { real gle = a.angle1 + (a.direction ? angle : -angle); p = point(a.polarconicroutine(a.el, gle, gle, 1, CCW), 0); } return point(coordsys(a.el), p/coordsys(a.el)); } /**/ path operator cast(explicit arc a) {/*Cast arc to path.*/ return arctopath(a, arcnodesnumber(a)); } /**/ guide operator cast(explicit arc a) {/*Cast arc to guide.*/ return arctopath(a, arcnodesnumber(a)); } /**/ arc operator *(transform t, explicit arc a) {/*Provide transform * arc.*/ pair[] P, PP; path g = arctopath(a, 3); real a0, a1 = a.angle1, a2 = a.angle2, ap1, ap2; bool dir = a.direction; P[0] = t * point(g, 0); P[1] = t * point(g, 2); ellipse el = t * a.el; arc oa; a0 = (a.angle0 + angle(shiftless(t)))%360; pair C; if(a.polarconicroutine == fromCenter) C = el.C; else C = el.F1; real d = abs(locate(el.F2 - el.F1)) > epsgeo ? degrees(locate(el.F2 - el.F1)) : a0 + degrees(el.C.coordsys.i); ap1 = (degrees(P[0]-C, false) - d)%360; ap2 = (degrees(P[1]-C, false) - d)%360; oa.init(el, a0, ap1, ap2, a.polarconicroutine, dir); g = arctopath(oa, 3); PP[0] = point(g, 0); PP[1] = point(g, 2); if((a1 - a2) * (ap1 - ap2) < 0) {// Handle reflection. dir=!a.direction; oa.init(el, a0, ap1, ap2, a.polarconicroutine, dir); } return oa; } /**/ arc operator *(real x, explicit arc a) {/*Provide real * arc. Return the arc subtracting and adding '(x - 1) * degrees(a)/2' to 'a.angle1' and 'a.angle2' respectively.*/ real a1, a2, gle; gle = (x - 1) * degrees(a)/2; a1 = a.angle1 - gle; a2 = a.angle2 + gle; arc oa; oa.init(a.el, a.angle0, a1, a2, a.polarconicroutine, a.direction); return oa; } arc operator *(int x, explicit arc a){return (real)x * a;} /**/ arc operator /(explicit arc a, real x) {/*Provide arc/real. Return the arc subtracting and adding '(1/x - 1) * degrees(a)/2' to 'a.angle1' and 'a.angle2' respectively.*/ return (1/x) * a; } /**/ arc operator +(explicit arc a, point M) {/*Provide arc + point. Return shifted arc. 'operator +(explicit arc, point)', 'operator +(explicit arc, vector)' and 'operator -(explicit arc, vector)' are also defined.*/ return shift(M) * a; } arc operator -(explicit arc a, point M){return a + (-M);} arc operator +(explicit arc a, vector v){return shift(locate(v)) * a;} arc operator -(explicit arc a, vector v){return a + (-v);} /**/ bool operator @(point M, arc a) {/*Return true iff 'M' is on the arc 'a'.*/ if (!(M @ a.el)) return false; coordsys R = defaultcoordsys; path ap = arctopath(a, 3); line l = line(point(R, point(ap, 0)), point(R, point(ap, 2))); return sameside(M, point(R, point(ap, 1)), l); } /**/ void draw(picture pic = currentpicture, Label L = "", arc a, align align = NoAlign, pen p = currentpen, arrowbar arrow = None, arrowbar bar = None, margin margin = NoMargin, Label legend = "", marker marker = nomarker) {/*Draw 'arc' adding the pen returned by 'addpenarc(p)' to the pen 'p'. */ draw(pic, L, (path)a, align, addpenarc(p), arrow, bar, margin, legend, marker); } /**/ real arclength(arc a) {/*The arc length of 'a'.*/ return arclength(a.el, a.angle1, a.angle2, a.direction, a.polarconicroutine); } private point ppoint(arc a, real x) {// Return the point of the arc proportionally to its length. point oP; if(a.el.e == 0) { // Case of circle. oP = angpoint(a, x * abs(degrees(a))); } else { // Ellipse and not circle. if(!a.direction) { transform t = reflect(line(a.el.F1, a.el.F2)); return t * ppoint(t * a, x); } real angle1 = a.angle1, angle2 = a.angle2; if(a.polarconicroutine == fromFocus) { // dot(point(fromFocus(a.el, angle1, angle1, 1, CCW), 0), 2mm + blue); // dot(point(fromFocus(a.el, angle2, angle2, 1, CCW), 0), 2mm + blue); // write("fromfocus1 = ", angle1); // write("fromfocus2 = ", angle2); real gle1 = focusToCenter(a.el, angle1); real gle2 = focusToCenter(a.el, angle2); if((gle1 - gle2) * (angle1 - angle2) > 0) { angle1 = gle1; angle2 = gle2; } else { angle1 = gle2; angle2 = gle1; } // write("fromcenter1 = ", angle1); // write("fromcenter2 = ", angle2); // dot(point(fromCenter(a.el, angle1, angle1, 1, CCW), 0), 1mm + red); // dot(point(fromCenter(a.el, angle2, angle2, 1, CCW), 0), 1mm + red); } if(angle1 > angle2) { arc ta = a.copy(); ta.polarconicroutine = fromCenter; ta.setangles(a0 = a.angle0, a1 = angle1 - 360, a2 = angle2); return ppoint(ta, x); } ellipse co = a.el; real gle, a1, a2, cx = 0; bool direction; if(x >= 0) { a1 = angle1; a2 = a1 + 360; direction = CCW; } else { a1 = angle1 - 360; a2 = a1 - 360; direction = CW; } gle = a1; real L = arclength(co, angle1, angle2, a.direction, fromCenter); real tx = L * abs(x)%arclength(co); real aout = a1; while(abs(cx - tx) > epsgeo) { aout = (a1 + a2)/2; cx = abs(arclength(co, gle, aout, direction, fromCenter)); if(cx > tx) a2 = (a1 + a2)/2 ; else a1 = (a1 + a2)/2; } pair p = point(arcfromcenter(co, aout, aout, CCW, 1), 0); oP = point(coordsys(co), p/coordsys(co)); } return oP; } /**/ point point(arc a, abscissa l) {/*Return the point of 'a' which has the abscissa 'l.x' according to the abscissa system 'l.system'. Note that 'a.polarconicroutine' is used instead of 'l.polarconicroutine'. */ real posx; arc ta = a.copy(); ellipse co = a.el; if (l.system == relativesystem) { posx = l.x; } else if (l.system == curvilinearsystem) { real tl; if(co.e == 0) { tl = curabscissa(a.el, angpoint(a.el, a.angle0 + a.angle1)).x; return curpoint(a.el, tl + (a.direction ? l.x : -l.x)); } else { tl = curabscissa(a.el, angpoint(a.el, a.angle1, a.polarconicroutine)).x; return curpoint(a.el, tl + (a.direction ? l.x : -l.x)); } } else if (l.system == nodesystem) { coordsys R = coordsys(co); return point(R, point((path)a, l.x)/R); } else if (l.system == angularsystem) { return angpoint(a, l.x); } else abort("point: bad abscissa system."); return ppoint(ta, posx); } /**/ point point(arc a, real x) {/*Return the point between node floor(t) and floor(t) + 1.*/ return point(a, nodabscissa(x)); } pair point(explicit arc a, int x) { return point(a, nodabscissa(x)); } /**/ point relpoint(arc a, real x) {/*Return the relative point of 'a'. If x > 1 or x < 0, the returned point is on the extended arc.*/ return point(a, relabscissa(x)); } /**/ point curpoint(arc a, real x) {/*Return the point of 'a' which has the curvilinear abscissa 'x'. If x < 0 or x > arclength(a), the returned point is on the extended arc.*/ return point(a, curabscissa(x)); } /**/ abscissa angabscissa(arc a, point M) {/*Return the angular abscissa of 'M' according to the arc 'a'.*/ if(!(M @ a.el)) abort("angabscissa: the point is not on the extended arc."); abscissa oa; oa.system = angularsystem; oa.polarconicroutine = a.polarconicroutine; real am = angabscissa(a.el, M, a.polarconicroutine).x; oa.x = (am - a.angle1 - (a.el.e == 0 ? a.angle0 : 0))%360; oa.x = a.direction ? oa.x : 360 - oa.x; return oa; } /**/ abscissa curabscissa(arc a, point M) {/*Return the curvilinear abscissa according to the arc 'a'.*/ ellipse el = a.el; if(!(M @ el)) abort("angabscissa: the point is not on the extended arc."); abscissa oa; oa.system = curvilinearsystem; real xm = curabscissa(el, M).x; real a0 = el.e == 0 ? a.angle0 : 0; real am = curabscissa(el, angpoint(el, a.angle1 + a0, a.polarconicroutine)).x; real l = arclength(el); oa.x = (xm - am)%l; oa.x = a.direction ? oa.x : l - oa.x; return oa; } /**/ abscissa nodabscissa(arc a, point M) {/*Return the node abscissa according to the arc 'a'.*/ if(!(M @ a)) abort("nodabscissa: the point is not on the arc."); abscissa oa; oa.system = nodesystem; oa.x = intersect((path)a, M)[0]; return oa; } /**/ abscissa relabscissa(arc a, point M) {/*Return the relative abscissa according to the arc 'a'.*/ ellipse el = a.el; if(!( M @ el)) abort("relabscissa: the point is not on the prolonged arc."); abscissa oa; oa.system = relativesystem; oa.x = curabscissa(a, M).x/arclength(a); return oa; } /**/ void markarc(picture pic = currentpicture, Label L = "", int n = 1, real radius = 0, real space = 0, arc a, pen sectorpen = currentpen, pen markpen = sectorpen, margin margin = NoMargin, arrowbar arrow = None, marker marker = nomarker) {/**/ real Da = degrees(a); pair p1 = point(a, 0); pair p2 = relpoint(a, 1); pair c = a.polarconicroutine == fromCenter ? locate(a.el.C) : locate(a.el.F1); if(radius == 0) radius = markangleradius(markpen); if(abs(Da) > 180) radius = -radius; radius = (a.direction ? 1 : -1) * sgnd(Da) * radius; draw(c--p1^^c--p2, sectorpen); markangle(pic = pic, L = L, n = n, radius = radius, space = space, A = p1, O = c, B = p2, arrow = arrow, p = markpen, margin = margin, marker = marker); } // *.........................ARCS..........................* // *=======================================================* // *=======================================================* // *........................MASSES.........................* /**/ struct mass {/**/ point M;/**/ real m;/**/ }/**/ /**/ mass mass(point M, real m) {/*Constructor of mass point.*/ mass om; om.M = M; om.m = m; return om; } /**/ point operator cast(mass m) {/*Cast mass point to point.*/ point op; op = m.M; op.m = m.m; return op; } /**/ point point(explicit mass m){return m;}/*Cast 'm' to point*/ /**/ mass operator cast(point M) {/*Cast point to mass point.*/ mass om; om.M = M; om.m = M.m; return om; } /**/ mass mass(explicit point P) {/*Cast 'P' to mass.*/ return mass(P, P.m); } /**/ point[] operator cast(mass[] m) {/*Cast mass[] to point[].*/ point[] op; for(mass am : m) op.push(point(am)); return op; } /**/ mass[] operator cast(point[] P) {/*Cast point[] to mass[].*/ mass[] om; for(point op : P) om.push(mass(op)); return om; } /**/ mass mass(coordsys R, explicit pair p, real m) {/*Return the mass which has coordinates 'p' with respect to 'R' and weight 'm'.*/ return point(R, p, m);// Using casting. } /**/ mass operator cast(pair m){return mass((point)m, 1);}/*Cast pair to mass point.*/ /**/ path operator cast(mass M){return M.M;}/*Cast mass point to path.*/ /**/ guide operator cast(mass M){return M.M;}/*Cast mass to guide.*/ /**/ mass operator +(mass M1, mass M2) {/*Provide mass + mass. mass - mass is also defined.*/ return mass(M1.M + M2.M, M1.m + M2.m); } mass operator -(mass M1, mass M2) { return mass(M1.M - M2.M, M1.m - M2.m); } /**/ mass operator *(real x, explicit mass M) {/*Provide real * mass. The resulted mass is the mass of 'M' multiplied by 'x' . mass/real, mass + real and mass - real are also defined.*/ return mass(M.M, x * M.m); } mass operator *(int x, explicit mass M){return mass(M.M, x * M.m);} mass operator /(explicit mass M, real x){return mass(M.M, M.m/x);} mass operator /(explicit mass M, int x){return mass(M.M, M.m/x);} mass operator +(explicit mass M, real x){return mass(M.M, M.m + x);} mass operator +(explicit mass M, int x){return mass(M.M, M.m + x);} mass operator -(explicit mass M, real x){return mass(M.M, M.m - x);} mass operator -(explicit mass M, int x){return mass(M.M, M.m - x);} /**/ mass operator *(transform t, mass M) {/*Provide transform * mass.*/ return mass(t * M.M, M.m); } /**/ mass masscenter(... mass[] M) {/*Return the center of the masses 'M'.*/ point[] P; for (int i = 0; i < M.length; ++i) P.push(M[i].M); P = standardizecoordsys(currentcoordsys, true ... P); real m = M[0].m; point oM = M[0].m * P[0]; for (int i = 1; i < M.length; ++i) { oM += M[i].m * P[i]; m += M[i].m; } if (m == 0) abort("masscenter: the sum of masses is null."); return mass(oM/m, m); } /**/ string massformat(string format = defaultmassformat, string s, mass M) {/*Return the string formated by 'format' with the mass value. In the parameter 'format', %L will be replaced by 's'. .*/ return format == "" ? s : format(replace(format, "%L", replace(s, "$", "")), M.m); } /**/ void label(picture pic = currentpicture, Label L, explicit mass M, align align = NoAlign, string format = defaultmassformat, pen p = nullpen, filltype filltype = NoFill) {/*Draw label returned by massformat(format, L, M) at coordinates of M. .*/ Label lL = L.copy(); lL.s = massformat(format, lL.s, M); Label L = Label(lL, M.M, align, p, filltype); add(pic, L); } /**/ void dot(picture pic = currentpicture, Label L, explicit mass M, align align = NoAlign, string format = defaultmassformat, pen p = currentpen) {/*Draw a dot with label 'L' as label(picture, Label, explicit mass, align, string, pen, filltype) does. .*/ Label lL = L.copy(); lL.s = massformat(format, lL.s, M); lL.position(locate(M.M)); lL.align(align, E); lL.p(p); dot(pic, M.M, p); add(pic, lL); } // *........................MASSES.........................* // *=======================================================* // *=======================================================* // *.......................TRIANGLES.......................* /**/ point orthocentercenter(point A, point B, point C) {/*Return the orthocenter of the triangle ABC.*/ point[] P = standardizecoordsys(A, B, C); coordsys R = P[0].coordsys; pair pp = extension(A, projection(P[1], P[2]) * P[0], B, projection(P[0], P[2]) * P[1]); return point(R, pp/R); } /**/ point centroid(point A, point B, point C) {/*Return the centroid of the triangle ABC.*/ return (A + B + C)/3; } /**/ point incenter(point A, point B, point C) {/*Return the center of the incircle of the triangle ABC.*/ point[] P = standardizecoordsys(A, B, C); coordsys R = P[0].coordsys; pair a = A, b = B, c = C; pair pp = extension(a, a + dir(a--b, a--c), b, b + dir(b--a, b--c)); return point(R, pp/R); } /**/ real inradius(point A, point B, point C) {/*Return the radius of the incircle of the triangle ABC.*/ point IC = incenter(A, B, C); return abs(IC - projection(A, B) * IC); } /**/ circle incircle(point A, point B, point C) {/*Return the incircle of the triangle ABC.*/ point IC = incenter(A, B, C); return circle(IC, abs(IC - projection(A, B) * IC)); } /**/ point excenter(point A, point B, point C) {/*Return the center of the excircle of the triangle tangent with (AB).*/ point[] P = standardizecoordsys(A, B, C); coordsys R = P[0].coordsys; pair a = A, b = B, c = C; pair pp = extension(a, a + rotate(90) * dir(a--b, a--c), b, b + rotate(90) * dir(b--a, b--c)); return point(R, pp/R); } /**/ real exradius(point A, point B, point C) {/*Return the radius of the excircle of the triangle ABC with (AB).*/ point EC = excenter(A, B, C); return abs(EC - projection(A, B) * EC); } /**/ circle excircle(point A, point B, point C) {/*Return the excircle of the triangle ABC tangent with (AB).*/ point center = excenter(A, B, C); real radius = abs(center - projection(B, C) * center); return circle(center, radius); } private int[] numarray = {1, 2, 3}; numarray.cyclic = true; /**/ struct triangle {/**/ /**/ struct vertex {/*Structure used to communicate the vertex of a triangle.*/ int n;/*1 means VA,2 means VB,3 means VC,4 means VA etc...*/ triangle t;/*The triangle to which the vertex refers.*/ }/**/ /**/ restricted point A, B, C;/*The vertices of the triangle (as point).*/ restricted vertex VA, VB, VC;/*The vertices of the triangle (as vertex). Note that the vertex structure contains the triangle to wish it refers.*/ VA.n = 1;VB.n = 2;VC.n = 3; /**/ vertex vertex(int n) {/*Return numbered vertex. 'n' is 1 means VA, 2 means VB, 3 means VC, 4 means VA etc...*/ n = numarray[n - 1]; if(n == 1) return VA; else if(n == 2) return VB; return VC; } /**/ point point(int n) {/*Return numbered point. n is 1 means A, 2 means B, 3 means C, 4 means A etc...*/ n = numarray[n - 1]; if(n == 1) return A; else if(n == 2) return B; return C; } /**/ void init(point A, point B, point C) {/*Constructor.*/ point[] P = standardizecoordsys(A, B, C); this.A = P[0]; this.B = P[1]; this.C = P[2]; VA.t = this; VB.t = this; VC.t = this; } /**/ void operator init(point A, point B, point C) {/*For backward compatibility. Provide the routine 'triangle(point A, point B, point C)'.*/ this.init(A, B, C); } /**/ void operator init(real b, real alpha, real c, real angle = 0, point A = (0, 0)) {/*For backward compatibility. Provide the routine 'triangle(real b, real alpha, real c, real angle = 0, point A = (0, 0)) which returns the triangle ABC rotated by 'angle' (in degrees) and where b = AC, degrees(A) = alpha, AB = c.*/ coordsys R = A.coordsys; this.init(A, A + R.polar(c, radians(angle)), A + R.polar(b, radians(angle + alpha))); } /**/ real a() {/*Return the length BC. b() and c() are also defined and return the length AC and AB respectively.*/ return length(C - B); } real b() {return length(A - C);} real c() {return length(B - A);} private real det(pair a, pair b) {return a.x * b.y - a.y * b.x;} /**/ real area() {/**/ pair a = locate(A), b = locate(B), c = locate(C); return 0.5 * abs(det(a, b) + det(b, c) + det(c, a)); } /**/ real alpha() {/*Return the measure (in degrees) of the angle A. beta() and gamma() are also defined and return the measure of the angles B and C respectively.*/ return degrees(acos((b()^2 + c()^2 - a()^2)/(2b() * c()))); } real beta() {return degrees(acos((c()^2 + a()^2 - b()^2)/(2c() * a())));} real gamma() {return degrees(acos((a()^2 + b()^2 - c()^2)/(2a() * b())));} /**/ path Path() {/*The path of the triangle.*/ return A--C--B--cycle; } /**/ struct side {/*Structure used to communicate the side of a triangle.*/ int n;/*1 or 0 means [AB],-1 means [BA],2 means [BC],-2 means [CB] etc.*/ triangle t;/*The triangle to which the side refers.*/ }/**/ /**/ side AB;/*For the routines using the structure 'side', triangle.AB means 'side AB'. BA, AC, CA etc are also defined.*/ AB.n = 1; AB.t = this; side BA; BA.n = -1; BA.t = this; side BC; BC.n = 2; BC.t = this; side CB; CB.n = -2; CB.t = this; side CA; CA.n = 3; CA.t = this; side AC; AC.n = -3; AC.t = this; /**/ side side(int n) {/*Return numbered side. n is 1 means AB, -1 means BA, 2 means BC, -2 means CB, etc.*/ if(n == 0) abort('Invalid side number.'); int an = numarray[abs(n)-1]; if(an == 1) return n > 0 ? AB : BA; else if(an == 2) return n > 0 ? BC : CB; return n > 0 ? CA : AC; } /**/ line line(int n) {/*Return the numbered line.*/ if(n == 0) abort('Invalid line number.'); int an = numarray[abs(n)-1]; if(an == 1) return n > 0 ? line(A, B) : line(B, A); else if(an == 2) return n > 0 ? line(B, C) : line(C, B); return n > 0 ? line(C, A) : line(A, C); } }/**/ from triangle unravel side; // The structure 'side' is now available outside the triangle structure. from triangle unravel vertex; // The structure 'vertex' is now available outside the triangle structure. triangle[] operator ^^(triangle[] t1, triangle t2) { triangle[] T; for (int i = 0; i < t1.length; ++i) T.push(t1[i]); T.push(t2); return T; } triangle[] operator ^^(... triangle[] t) { triangle[] T; for (int i = 0; i < t.length; ++i) { T.push(t[i]); } return T; } /**/ line operator cast(side side) {/*Cast side to (infinite) line. Most routine with line parameters works with side parameters. One can use the code 'segment(a_side)' to obtain a line segment.*/ triangle t = side.t; return t.line(side.n); } /**/ line line(explicit side side) {/*Return 'side' as line.*/ return (line)side; } /**/ segment segment(explicit side side) {/*Return 'side' as segment.*/ return (segment)(line)side; } /**/ point operator cast(vertex V) {/*Cast vertex to point. Most routine with point parameters works with vertex parameters.*/ return V.t.point(V.n); } /**/ point point(explicit vertex V) {/*Return the point corresponding to the vertex 'V'.*/ return (point)V; } /**/ side opposite(vertex V) {/*Return the opposite side of vertex 'V'.*/ return V.t.side(numarray[abs(V.n)]); } /**/ vertex opposite(side side) {/*Return the opposite vertex of side 'side'.*/ return side.t.vertex(numarray[abs(side.n) + 1]); } /**/ point midpoint(side side) {/**/ return midpoint(segment(side)); } /**/ triangle operator *(transform T, triangle t) {/*Provide transform * triangle.*/ return triangle(T * t.A, T * t.B, T * t.C); } /**/ triangle triangleAbc(real alpha, real b, real c, real angle = 0, point A = (0, 0)) {/*Return the triangle ABC rotated by 'angle' with BAC = alpha, AC = b and AB = c.*/ triangle T; coordsys R = A.coordsys; T.init(A, A + R.polar(c, radians(angle)), A + R.polar(b, radians(angle + alpha))); return T; } /**/ triangle triangleabc(real a, real b, real c, real angle = 0, point A = (0, 0)) {/*Return the triangle ABC rotated by 'angle' with BC = a, AC = b and AB = c.*/ triangle T; coordsys R = A.coordsys; T.init(A, A + R.polar(c, radians(angle)), A + R.polar(b, radians(angle) + acos((b^2 + c^2 - a^2)/(2 * b * c)))); return T; } /**/ triangle triangle(line l1, line l2, line l3) {/*Return the triangle defined by three line.*/ point P1, P2, P3; P1 = intersectionpoint(l1, l2); P2 = intersectionpoint(l1, l3); P3 = intersectionpoint(l2, l3); if(!(defined(P1) && defined(P2) && defined(P3))) abort("triangle: two lines are parallel."); return triangle(P1, P2, P3); } /**/ point foot(vertex V) {/*Return the endpoint of the altitude from V.*/ return projection((line)opposite(V)) * ((point)V); } /**/ point foot(side side) {/*Return the endpoint of the altitude on 'side'.*/ return projection((line)side) * point(opposite(side)); } /**/ line altitude(vertex V) {/*Return the altitude passing through 'V'.*/ return line(point(V), foot(V)); } /**/ line altitude(side side) {/*Return the altitude cutting 'side'.*/ return altitude(opposite(side)); } /**/ point orthocentercenter(triangle t) {/*Return the orthocenter of the triangle t.*/ return orthocentercenter(t.A, t.B, t.C); } /**/ point centroid(triangle t) {/*Return the centroid of the triangle 't'.*/ return (t.A + t.B + t.C)/3; } /**/ point circumcenter(triangle t) {/*Return the circumcenter of the triangle 't'.*/ return circumcenter(t.A, t.B, t.C); } /**/ circle circle(triangle t) {/*Return the circumcircle of the triangle 't'.*/ return circle(t.A, t.B, t.C); } /**/ circle circumcircle(triangle t) {/*Return the circumcircle of the triangle 't'.*/ return circle(t.A, t.B, t.C); } /**/ point incenter(triangle t) {/*Return the center of the incircle of the triangle 't'.*/ return incenter(t.A, t.B, t.C); } /**/ real inradius(triangle t) {/*Return the radius of the incircle of the triangle 't'.*/ return inradius(t.A, t.B, t.C); } /**/ circle incircle(triangle t) {/*Return the the incircle of the triangle 't'.*/ return incircle(t.A, t.B, t.C); } /**/ point excenter(side side) {/*Return the center of the excircle tangent with the side 'side' of its triangle. side = 0 means AB, 1 means AC, other means BC. One must use the predefined sides t.AB, t.AC where 't' is a triangle....*/ point op; triangle t = side.t; int n = numarray[abs(side.n) - 1]; if(n == 1) op = excenter(t.A, t.B, t.C); else if(n == 2) op = excenter(t.B, t.C, t.A); else op = excenter(t.C, t.A, t.B); return op; } /**/ real exradius(side side) {/*Return radius of the excircle tangent with the side 'side' of its triangle. side = 0 means AB, 1 means BC, other means CA. One must use the predefined sides t.AB, t.AC where 't' is a triangle....*/ real or; triangle t = side.t; int n = numarray[abs(side.n) - 1]; if(n == 1) or = exradius(t.A, t.B, t.C); else if(n == 2) or = exradius(t.B, t.C, t.A); else or = exradius(t.A, t.C, t.B); return or; } /**/ circle excircle(side side) {/*Return the excircle tangent with the side 'side' of its triangle. side = 0 means AB, 1 means AC, other means BC. One must use the predefined sides t.AB, t.AC where 't' is a triangle....*/ circle oc; int n = numarray[abs(side.n) - 1]; triangle t = side.t; if(n == 1) oc = excircle(t.A, t.B, t.C); else if(n == 2) oc = excircle(t.B, t.C, t.A); else oc = excircle(t.A, t.C, t.B); return oc; } /**/ struct trilinear {/*Trilinear coordinates 'a:b:c' relative to triangle 't'. */ real a,b,c;/*The trilinear coordinates.*/ triangle t;/*The reference triangle.*/ }/**/ /**/ trilinear trilinear(triangle t, real a, real b, real c) {/*Return the trilinear coordinates relative to 't'. */ trilinear ot; ot.a = a; ot.b = b; ot.c = c; ot.t = t; return ot; } /**/ trilinear trilinear(triangle t, point M) {/*Return the trilinear coordinates of 'M' relative to 't'. */ trilinear ot; pair m = locate(M); int sameside(pair A, pair B, pair m, pair p) {// Return 1 if 'm' and 'p' are same side of line (AB) else return -1. pair mil = (A + B)/2; pair mA = rotate(90, mil) * A; pair mB = rotate(-90, mil) * A; return (abs(m - mA) <= abs(m - mB)) == (abs(p - mA) <= abs(p - mB)) ? 1 : -1; } real det(pair a, pair b) {return a.x * b.y - a.y * b.x;} real area(pair a, pair b, pair c){return 0.5 * abs(det(a, b) + det(b, c) + det(c, a));} pair A = t.A, B = t.B, C = t.C; real t1 = area(B, C, m), t2 = area(C, A, m), t3 = area(A, B, m); ot.a = sameside(B, C, A, m) * t1/t.a(); ot.b = sameside(A, C, B, m) * t2/t.b(); ot.c = sameside(A, B, C, m) * t3/t.c(); ot.t = t; return ot; } /**/ void write(trilinear tri) {/**/ write(format("%f : ", tri.a) + format("%f : ", tri.b) + format("%f", tri.c)); } /**/ point point(trilinear tri) {/*Return the trilinear coordinates relative to 't'. */ triangle t = tri.t; return masscenter(0.5 * t.a() * mass(t.A, tri.a), 0.5 * t.b() * mass(t.B, tri.b), 0.5 * t.c() * mass(t.C, tri.c)); } /**/ int[] tricoef(side side) {/*Return an array of integer (values are 0 or 1) which represents 'side'. For example, side = t.BC will be represented by {0, 1, 1}.*/ int[] oi; int n = numarray[abs(side.n) - 1]; oi.push((n == 1 || n == 3) ? 1 : 0); oi.push((n == 1 || n == 2) ? 1 : 0); oi.push((n == 2 || n == 3) ? 1 : 0); return oi; } /**/ point operator cast(trilinear tri) {/*Cast trilinear to point. One may use the routine 'point(trilinear)' to force the casting.*/ return point(tri); } /**/ typedef real centerfunction(real, real, real);/**/ /**/ trilinear trilinear(triangle t, centerfunction f, real a = t.a(), real b = t.b(), real c = t.c()) {/**/ return trilinear(t, f(a, b, c), f(b, c, a), f(c, a, b)); } /**/ point symmedian(triangle t) {/*Return the symmedian point of 't'.*/ point A, B, C; real a = t.a(), b = t.b(), c = t.c(); A = trilinear(t, 0, b, c); B = trilinear(t, a, 0, c); return intersectionpoint(line(t.A, A), line(t.B, B)); } /**/ point symmedian(side side) {/*The symmedian point on the side 'side'.*/ triangle t = side.t; int n = numarray[abs(side.n) - 1]; if(n == 1) return trilinear(t, t.a(), t.b(), 0); if(n == 2) return trilinear(t, 0, t.b(), t.c()); return trilinear(t, t.a(), 0, t.c()); } /**/ line symmedian(vertex V) {/*Return the symmedian passing through 'V'.*/ return line(point(V), symmedian(V.t)); } /**/ triangle cevian(triangle t, point P) {/*Return the Cevian triangle with respect of 'P' .*/ trilinear tri = trilinear(t, locate(P)); point A = point(trilinear(t, 0, tri.b, tri.c)); point B = point(trilinear(t, tri.a, 0, tri.c)); point C = point(trilinear(t, tri.a, tri.b, 0)); return triangle(A, B, C); } /**/ point cevian(side side, point P) {/*Return the Cevian point on 'side' with respect of 'P'.*/ triangle t = side.t; trilinear tri = trilinear(t, locate(P)); int[] s = tricoef(side); return point(trilinear(t, s[0] * tri.a, s[1] * tri.b, s[2] * tri.c)); } /**/ line cevian(vertex V, point P) {/*Return line passing through 'V' and its Cevian image with respect of 'P'.*/ return line(point(V), cevian(opposite(V), P)); } /**/ point gergonne(triangle t) {/*Return the Gergonne point of 't'.*/ real f(real a, real b, real c){return 1/(a * (b + c - a));} return point(trilinear(t, f)); } /**/ point[] fermat(triangle t) {/*Return the Fermat points of 't'.*/ point[] P; real A = t.alpha(), B = t.beta(), C = t.gamma(); P.push(point(trilinear(t, 1/Sin(A + 60), 1/Sin(B + 60), 1/Sin(C + 60)))); P.push(point(trilinear(t, 1/Sin(A - 60), 1/Sin(B - 60), 1/Sin(C - 60)))); return P; } /**/ point isotomicconjugate(triangle t, point M) {/**/ if(!inside(t.Path(), locate(M))) abort("isotomic: the point must be inside the triangle."); trilinear tr = trilinear(t, M); return point(trilinear(t, 1/(t.a()^2 * tr.a), 1/(t.b()^2 * tr.b), 1/(t.c()^2 * tr.c))); } /**/ line isotomic(vertex V, point M) {/*.*/ side op = opposite(V); return line(V, rotate(180, midpoint(op)) * cevian(op, M)); } /**/ point isotomic(side side, point M) {/**/ return intersectionpoint(isotomic(opposite(side), M), side); } /**/ triangle isotomic(triangle t, point M) {/**/ return triangle(isotomic(t.BC, M), isotomic(t.CA, M), isotomic(t.AB, M)); } /**/ point isogonalconjugate(triangle t, point M) {/**/ trilinear tr = trilinear(t, M); return point(trilinear(t, 1/tr.a, 1/tr.b, 1/tr.c)); } /**/ point isogonal(side side, point M) {/**/ return cevian(side, isogonalconjugate(side.t, M)); } /**/ line isogonal(vertex V, point M) {/**/ return line(V, isogonal(opposite(V), M)); } /**/ triangle isogonal(triangle t, point M) {/**/ return triangle(isogonal(t.BC, M), isogonal(t.CA, M), isogonal(t.AB, M)); } /**/ triangle pedal(triangle t, point M) {/*Return the pedal triangle of 'M' in 't'. */ return triangle(projection(t.BC) * M, projection(t.AC) * M, projection(t.AB) * M); } /**/ line pedal(side side, point M) {/*Return the pedal line of 'M' cutting 'side'. */ return line(M, projection(side) * M); } /**/ triangle antipedal(triangle t, point M) {/**/ trilinear Tm = trilinear(t, M); real a = Tm.a, b = Tm.b, c = Tm.c; real CA = Cos(t.alpha()), CB = Cos(t.beta()), CC = Cos(t.gamma()); point A = trilinear(t, -(b + a * CC) * (c + a * CB), (c + a * CB) * (a + b * CC), (b + a * CC) * (a + c * CB)); point B = trilinear(t, (c + b * CA) * (b + a * CC), -(c + b * CA) * (a + b * CC), (a + b * CC) * (b + c * CA)); point C = trilinear(t, (b + c * CA) * (c + a * CB), (a + c * CB) * (c + b * CA), -(a + c * CB) * (b + c * CA)); return triangle(A, B, C); } /**/ triangle extouch(triangle t) {/*Return the extouch triangle of the triangle 't'. The extouch triangle of 't' is the triangle formed by the points of tangency of a triangle 't' with its excircles.*/ point A, B, C; real a = t.a(), b = t.b(), c = t.c(); A = trilinear(t, 0, (a - b + c)/b, (a + b - c)/c); B = trilinear(t, (-a + b + c)/a, 0, (a + b - c)/c); C = trilinear(t, (-a + b + c)/a, (a - b + c)/b, 0); return triangle(A, B, C); } /**/ triangle incentral(triangle t) {/*Return the incentral triangle of the triangle 't'. It is the triangle whose vertices are determined by the intersections of the reference triangle's angle bisectors with the respective opposite sides.*/ point A, B, C; // real a = t.a(), b = t.b(), c = t.c(); A = trilinear(t, 0, 1, 1); B = trilinear(t, 1, 0, 1); C = trilinear(t, 1, 1, 0); return triangle(A, B, C); } /**/ triangle extouch(side side) {/*Return the triangle formed by the points of tangency of the triangle referenced by 'side' with its excircles. One vertex of the returned triangle is on the segment 'side'.*/ triangle t = side.t; transform p1 = projection((line)t.AB); transform p2 = projection((line)t.AC); transform p3 = projection((line)t.BC); point EP = excenter(side); return triangle(p3 * EP, p2 * EP, p1 * EP); } /**/ point bisectorpoint(side side) {/*The intersection point of the angle bisector from the opposite point of 'side' with the side 'side'.*/ triangle t = side.t; int n = numarray[abs(side.n) - 1]; if(n == 1) return trilinear(t, 1, 1, 0); if(n == 2) return trilinear(t, 0, 1, 1); return trilinear(t, 1, 0, 1); } /**/ line bisector(vertex V, real angle = 0) {/*Return the interior bisector passing through 'V' rotated by angle (in degrees) around 'V'.*/ return rotate(angle, point(V)) * line(point(V), incenter(V.t)); } /**/ line bisector(side side) {/*Return the bisector of the line segment 'side'.*/ return bisector(segment(side)); } /**/ point intouch(side side) {/*The point of tangency on the side 'side' of its incircle.*/ triangle t = side.t; real a = t.a(), b = t.b(), c = t.c(); int n = numarray[abs(side.n) - 1]; if(n == 1) return trilinear(t, b * c/(-a + b + c), a * c/(a - b + c), 0); if(n == 2) return trilinear(t, 0, a * c/(a - b + c), a * b/(a + b - c)); return trilinear(t, b * c/(-a + b + c), 0, a * b/(a + b - c)); } /**/ triangle intouch(triangle t) {/*Return the intouch triangle of the triangle 't'. The intouch triangle of 't' is the triangle formed by the points of tangency of a triangle 't' with its incircles.*/ point A, B, C; real a = t.a(), b = t.b(), c = t.c(); A = trilinear(t, 0, a * c/(a - b + c), a * b/(a + b - c)); B = trilinear(t, b * c/(-a + b + c), 0, a * b/(a + b - c)); C = trilinear(t, b * c/(-a + b + c), a * c/(a - b + c), 0); return triangle(A, B, C); } /**/ triangle tangential(triangle t) {/*Return the tangential triangle of the triangle 't'. The tangential triangle of 't' is the triangle formed by the lines tangent to the circumcircle of the given triangle 't' at its vertices.*/ point A, B, C; real a = t.a(), b = t.b(), c = t.c(); A = trilinear(t, -a, b, c); B = trilinear(t, a, -b, c); C = trilinear(t, a, b, -c); return triangle(A, B, C); } /**/ triangle medial(triangle t) {/*Return the triangle whose vertices are midpoints of the sides of 't'.*/ return triangle(midpoint(t.BC), midpoint(t.AC), midpoint(t.AB)); } /**/ line median(vertex V) {/*Return median from 'V'.*/ return line(point(V), midpoint(segment(opposite(V)))); } /**/ line median(side side) {/*Return median from the opposite vertex of 'side'.*/ return median(opposite(side)); } /**/ triangle orthic(triangle t) {/*Return the triangle whose vertices are endpoints of the altitudes from each of the vertices of 't'.*/ return triangle(foot(t.BC), foot(t.AC), foot(t.AB)); } /**/ triangle symmedial(triangle t) {/*Return the symmedial triangle of 't'.*/ point A, B, C; real a = t.a(), b = t.b(), c = t.c(); A = trilinear(t, 0, b, c); B = trilinear(t, a, 0, c); C = trilinear(t, a, b, 0); return triangle(A, B, C); } /**/ triangle anticomplementary(triangle t) {/*Return the triangle which has the given triangle 't' as its medial triangle.*/ real a = t.a(), b = t.b(), c = t.c(); real ab = a * b, bc = b * c, ca = c * a; point A = trilinear(t, -bc, ca, ab); point B = trilinear(t, bc, -ca, ab); point C = trilinear(t, bc, ca, -ab); return triangle(A, B, C); } /**/ point[] intersectionpoints(triangle t, line l, bool extended = false) {/*Return the intersection points. If 'extended' is true, the sides are lines else the sides are segments. intersectionpoints(line, triangle, bool) is also defined.*/ point[] OP; void addpoint(point P) { if(defined(P)) { bool exist = false; for (int i = 0; i < OP.length; ++i) { if(P == OP[i]) {exist = true; break;} } if(!exist) OP.push(P); } } if(extended) { for (int i = 1; i <= 3; ++i) { addpoint(intersectionpoint(t.line(i), l)); } } else { for (int i = 1; i <= 3; ++i) { addpoint(intersectionpoint((segment)t.line(i), l)); } } return OP; } point[] intersectionpoints(line l, triangle t, bool extended = false) { return intersectionpoints(t, l, extended); } /**/ vector dir(vertex V) {/*The direction (towards the outside of the triangle) of the interior angle bisector of 'V'.*/ triangle t = V.t; if(V.n == 1) return vector(defaultcoordsys, (-dir(t.A--t.B, t.A--t.C))); if(V.n == 2) return vector(defaultcoordsys, (-dir(t.B--t.A, t.B--t.C))); return vector(defaultcoordsys, (-dir(t.C--t.A, t.C--t.B))); } /**/ void label(picture pic = currentpicture, Label L, vertex V, pair align = dir(V), real alignFactor = 1, pen p = nullpen, filltype filltype = NoFill) {/*Draw 'L' on picture 'pic' at vertex 'V' aligned by 'alignFactor * align'.*/ label(pic, L, locate(point(V)), alignFactor * align, p, filltype); } /**/ void label(picture pic = currentpicture, Label LA = "$A$", Label LB = "$B$", Label LC = "$C$", triangle t, real alignAngle = 0, real alignFactor = 1, pen p = nullpen, filltype filltype = NoFill) {/*Draw labels LA, LB and LC aligned in the rotated (by 'alignAngle' in degrees) direction (towards the outside of the triangle) of the interior angle bisector of vertices. One can individually modify the alignment by setting the Label parameter 'align'.*/ Label lla = LA.copy(); lla.align(lla.align, rotate(alignAngle) * locate(dir(t.VA))); label(pic, LA, t.VA, align = lla.align.dir, alignFactor = alignFactor, p, filltype); Label llb = LB.copy(); llb.align(llb.align, rotate(alignAngle) * locate(dir(t.VB))); label(pic, llb, t.VB, align = llb.align.dir, alignFactor = alignFactor, p, filltype); Label llc = LC.copy(); llc.align(llc.align, rotate(alignAngle) * locate(dir(t.VC))); label(pic, llc, t.VC, align = llc.align.dir, alignFactor = alignFactor, p, filltype); } /**/ void show(picture pic = currentpicture, Label LA = "$A$", Label LB = "$B$", Label LC = "$C$", Label La = "$a$", Label Lb = "$b$", Label Lc = "$c$", triangle t, pen p = currentpen, filltype filltype = NoFill) {/*Draw triangle and labels of sides and vertices.*/ pair a = locate(t.A), b = locate(t.B), c = locate(t.C); draw(pic, a--b--c--cycle, p); label(pic, LA, a, -dir(a--b, a--c), p, filltype); label(pic, LB, b, -dir(b--a, b--c), p, filltype); label(pic, LC, c, -dir(c--a, c--b), p, filltype); pair aligna = I * unit(c - b), alignb = I * unit(c - a), alignc = I * unit(b - a); pair mAB = locate(midpoint(t.AB)), mAC = locate(midpoint(t.AC)), mBC = locate(midpoint(t.BC)); label(pic, La, b--c, align = rotate(dot(a - mBC, aligna) > 0 ? 180 :0) * aligna, p); label(pic, Lb, a--c, align = rotate(dot(b - mAC, alignb) > 0 ? 180 :0) * alignb, p); label(pic, Lc, a--b, align = rotate(dot(c - mAB, alignc) > 0 ? 180 :0) * alignc, p); } /**/ void draw(picture pic = currentpicture, triangle t, pen p = currentpen, marker marker = nomarker) {/*Draw sides of the triangle 't' on picture 'pic' using pen 'p'.*/ draw(pic, t.Path(), p, marker); } /**/ void draw(picture pic = currentpicture, triangle[] t, pen p = currentpen, marker marker = nomarker) {/*Draw sides of the triangles 't' on picture 'pic' using pen 'p'.*/ for(int i = 0; i < t.length; ++i) draw(pic, t[i], p, marker); } /**/ void drawline(picture pic = currentpicture, triangle t, pen p = currentpen) {/*Draw lines of the triangle 't' on picture 'pic' using pen 'p'.*/ draw(t, p); draw(pic, line(t.A, t.B), p); draw(pic, line(t.A, t.C), p); draw(pic, line(t.B, t.C), p); } /**/ void dot(picture pic = currentpicture, triangle t, pen p = currentpen) {/*Draw a dot at each vertex of 't'.*/ dot(pic, t.A^^t.B^^t.C, p); } // *.......................TRIANGLES.......................* // *=======================================================* // *=======================================================* // *.......................INVERSIONS......................* /**/ point inverse(real k, point A, point M) {/*Return the inverse point of 'M' with respect to point A and inversion radius 'k'.*/ return A + k/conj(M - A); } /**/ point radicalcenter(circle c1, circle c2) {/**/ point[] P = standardizecoordsys(c1.C, c2.C); real k = c1.r^2 - c2.r^2; pair C1 = locate(c1.C); pair C2 = locate(c2.C); pair oop = C2 - C1; pair K = (abs(oop) == 0) ? (infinity, infinity) : midpoint(C1--C2) + 0.5 * k * oop/dot(oop, oop); return point(P[0].coordsys, K/P[0].coordsys); } /**/ line radicalline(circle c1, circle c2) {/**/ if (c1.C == c2.C) abort("radicalline: the centers must be distinct"); return perpendicular(radicalcenter(c1, c2), line(c1.C, c2.C)); } /**/ point radicalcenter(circle c1, circle c2, circle c3) {/**/ return intersectionpoint(radicalline(c1, c2), radicalline(c1, c3)); } /**/ struct inversion {/*http://mathworld.wolfram.com/Inversion.html*/ point C; real k; }/**/ /**/ inversion inversion(real k, point C) {/*Return the inversion with respect to 'C' having inversion radius 'k'.*/ inversion oi; oi.k = k; oi.C = C; return oi; } /**/ inversion inversion(point C, real k) {/*Return the inversion with respect to 'C' having inversion radius 'k'.*/ return inversion(k, C); } /**/ inversion inversion(circle c1, circle c2, real sgn = 1) {/*Return the inversion which transforms 'c1' to . 'c2' and positive inversion radius if 'sgn > 0'; . 'c2' and negative inversion radius if 'sgn < 0'; . 'c1' and 'c2' to 'c2' if 'sgn = 0'.*/ if(sgn == 0) { point O = radicalcenter(c1, c2); return inversion(O^c1, O); } real a = abs(c1.r/c2.r); if(sgn > 0) { point O = c1.C + a/abs(1 - a) * (c2.C - c1.C); return inversion(a * abs(abs(O - c2.C)^2 - c2.r^2), O); } point O = c1.C + a/abs(1 + a) * (c2.C - c1.C); return inversion(-a * abs(abs(O - c2.C)^2 - c2.r^2), O); } /**/ inversion inversion(circle c1, circle c2, circle c3) {/*Return the inversion which transform 'c1' to 'c1', 'c2' to 'c2' and 'c3' to 'c3'.*/ point Rc = radicalcenter(c1, c2, c3); return inversion(Rc, Rc^c1); } circle operator cast(inversion i){return circle(i.C, sgn(i.k) * sqrt(abs(i.k)));} /**/ circle circle(inversion i) {/*Return the inversion circle of 'i'.*/ return i; } inversion operator cast(circle c) { return inversion(sgn(c.r) * c.r^2, c.C); } /**/ inversion inversion(circle c) {/*Return the inversion represented by the circle of 'c'.*/ return c; } /**/ point operator *(inversion i, point P) {/*Provide inversion * point.*/ return inverse(i.k, i.C, P); } void lineinversion() { warning("lineinversion", "the inversion of the line is not a circle. The returned circle has an infinite radius, circle.l has been set."); } /**/ circle inverse(real k, point A, line l) {/*Return the inverse circle of 'l' with respect to point 'A' and inversion radius 'k'.*/ if(A @ l) { lineinversion(); circle C = circle(A, infinity); C.l = l; return C; } point Ap = inverse(k, A, l.A), Bp = inverse(k, A, l.B); return circle(A, Ap, Bp); } /**/ circle operator *(inversion i, line l) {/*Provide inversion * line for lines that don't pass through the inversion center.*/ return inverse(i.k, i.C, l); } /**/ circle inverse(real k, point A, circle c) {/*Return the inverse circle of 'c' with respect to point A and inversion radius 'k'.*/ if(degenerate(c)) return inverse(k, A, c.l); if(A @ c) { lineinversion(); point M = rotate(180, c.C) * A, Mp = rotate(90, c.C) * A; circle oc = circle(A, infinity); oc.l = line(inverse(k, A, M), inverse(k, A, Mp)); return oc; } point[] P = standardizecoordsys(A, c.C); real s = k/((P[1].x - P[0].x)^2 + (P[1].y - P[0].y)^2 - c.r^2); return circle(P[0] + s * (P[1]-P[0]), abs(s) * c.r); } /**/ circle operator *(inversion i, circle c) {/*Provide inversion * circle.*/ return inverse(i.k, i.C, c); } // *.......................INVERSIONS......................* // *=======================================================* // *=======================================================* // *........................FOOTER.........................* /**/ point[] intersectionpoints(line l, circle c) {/*Note that the line 'l' may be a segment by casting. intersectionpoints(circle, line) is also defined.*/ if(degenerate(c)) return new point[]{intersectionpoint(l, c.l)}; point[] op; coordsys R = samecoordsys(l.A, c.C) ? l.A.coordsys : defaultcoordsys; coordsys Rp = defaultcoordsys; circle cc = circle(changecoordsys(Rp, c.C), c.r); point proj = projection(l) * c.C; if(proj @ cc) { // The line is a tangente of the circle. if(proj @ l) op.push(proj);// line may be a segement... } else { coordsys Rc = cartesiansystem(c.C, (1, 0), (0, 1)); line ll = changecoordsys(Rc, l); pair[] P = intersectionpoints(ll.A.coordinates, ll.B.coordinates, 1, 0, 1, 0, 0, -c.r^2); for (int i = 0; i < P.length; ++i) { point inter = changecoordsys(R, point(Rc, P[i])); if(inter @ l) op.push(inter); } } return op; } point[] intersectionpoints(circle c, line l) { return intersectionpoints(l, c); } /**/ point[] intersectionpoints(line l, ellipse el) {/*Note that the line 'l' may be a segment by casting. intersectionpoints(ellipse, line) is also defined.*/ if(el.e == 0) return intersectionpoints(l, (circle)el); if(degenerate(el)) return new point[]{intersectionpoint(l, el.l)}; point[] op; coordsys R = samecoordsys(l.A, el.C) ? l.A.coordsys : defaultcoordsys; coordsys Rp = defaultcoordsys; line ll = changecoordsys(Rp, l); ellipse ell = changecoordsys(Rp, el); circle C = circle(ell.C, ell.a); point[] Ip = intersectionpoints(ll, C); if (Ip.length > 0 && (perpendicular(ll, line(ell.F1, Ip[0])) || perpendicular(ll, line(ell.F2, Ip[0])))) { // http://www.mathcurve.com/courbes2d/ellipse/ellipse.shtml // Définition tangentielle par antipodaire de cercle. // 'l' is a tangent of 'el' transform t = scale(el.a/el.b, el.F1, el.F2, el.C, rotate(90, el.C) * el.F1); point inter = inverse(t) * intersectionpoints(C, t * ll)[0]; if(inter @ l) op.push(inter); } else { coordsys Rc = canonicalcartesiansystem(el); line ll = changecoordsys(Rc, l); pair[] P = intersectionpoints(ll.A.coordinates, ll.B.coordinates, 1/el.a^2, 0, 1/el.b^2, 0, 0, -1); for (int i = 0; i < P.length; ++i) { point inter = changecoordsys(R, point(Rc, P[i])); if(inter @ l) op.push(inter); } } return op; } point[] intersectionpoints(ellipse el, line l) { return intersectionpoints(l, el); } /**/ point[] intersectionpoints(line l, parabola p) {/*Note that the line 'l' may be a segment by casting. intersectionpoints(parabola, line) is also defined.*/ point[] op; coordsys R = coordsys(p); bool tgt = false; line ll = changecoordsys(R, l), lv = parallel(p.V, p.D); point M = intersectionpoint(lv, ll), tgtp; if(finite(M)) {// Test if 'l' is tangent to 'p' line l1 = bisector(line(M, p.F)); line l2 = rotate(90, M) * lv; point P = intersectionpoint(l1, l2); tgtp = rotate(180, P) * p.F; tgt = (tgtp @ l); } if(tgt) { if(tgtp @ l) op.push(tgtp); } else { real[] eq = changecoordsys(defaultcoordsys, equation(p)).a; pair[] tp = intersectionpoints(locate(l.A), locate(l.B), eq); point inter; for (int i = 0; i < tp.length; ++i) { inter = point(R, tp[i]/R); if(inter @ l) op.push(inter); } } return op; } point[] intersectionpoints(parabola p, line l) { return intersectionpoints(l, p); } /**/ point[] intersectionpoints(line l, hyperbola h) {/*Note that the line 'l' may be a segment by casting. intersectionpoints(hyperbola, line) is also defined.*/ point[] op; coordsys R = coordsys(h); point A = intersectionpoint(l, h.A1), B = intersectionpoint(l, h.A2); point M = midpoint(segment(A, B)); bool tgt = M @ h; if(tgt) { if(M @ l) op.push(M); } else { real[] eq = changecoordsys(defaultcoordsys, equation(h)).a; pair[] tp = intersectionpoints(locate(l.A), locate(l.B), eq); point inter; for (int i = 0; i < tp.length; ++i) { inter = point(R, tp[i]/R); if(inter @ l) op.push(inter); } } return op; } point[] intersectionpoints(hyperbola h, line l) { return intersectionpoints(l, h); } /**/ point[] intersectionpoints(line l, conic co) {/*Note that the line 'l' may be a segment by casting. intersectionpoints(conic, line) is also defined.*/ point[] op; if(co.e < 1) op = intersectionpoints((ellipse)co, l); else if(co.e == 1) op = intersectionpoints((parabola)co, l); else op = intersectionpoints((hyperbola)co, l); return op; } point[] intersectionpoints(conic co, line l) { return intersectionpoints(l, co); } /**/ point[] intersectionpoints(conic co1, conic co2) {/*Return the intersection points of the two conics.*/ if(degenerate(co1)) return intersectionpoints(co1.l[0], co2); if(degenerate(co2)) return intersectionpoints(co1, co2.l[0]); return intersectionpoints(equation(co1), equation(co2)); } /**/ point[] intersectionpoints(triangle t, conic co, bool extended = false) {/*Return the intersection points. If 'extended' is true, the sides are lines else the sides are segments. intersectionpoints(conic, triangle, bool) is also defined.*/ if(degenerate(co)) return intersectionpoints(t, co.l[0], extended); point[] OP; void addpoint(point P[]) { for (int i = 0; i < P.length; ++i) { if(defined(P[i])) { bool exist = false; for (int j = 0; j < OP.length; ++j) { if(P[i] == OP[j]) {exist = true; break;} } if(!exist) OP.push(P[i]); }}} if(extended) { for (int i = 1; i <= 3; ++i) { addpoint(intersectionpoints(t.line(i), co)); } } else { for (int i = 1; i <= 3; ++i) { addpoint(intersectionpoints((segment)t.line(i), co)); } } return OP; } point[] intersectionpoints(conic co, triangle t, bool extended = false) { return intersectionpoints(t, co, extended); } /**/ point[] intersectionpoints(ellipse a, ellipse b) {/**/ // if(degenerate(a)) return intersectionpoints(a.l, b); // if(degenerate(b)) return intersectionpoints(a, b.l);; return intersectionpoints((conic)a, (conic)b); } /**/ point[] intersectionpoints(ellipse a, circle b) {/**/ // if(degenerate(a)) return intersectionpoints(a.l, b); // if(degenerate(b)) return intersectionpoints(a, b.l);; return intersectionpoints((conic)a, (conic)b); } /**/ point[] intersectionpoints(circle a, ellipse b) {/**/ return intersectionpoints(b, a); } /**/ point[] intersectionpoints(ellipse a, parabola b) {/**/ // if(degenerate(a)) return intersectionpoints(a.l, b); return intersectionpoints((conic)a, (conic)b); } /**/ point[] intersectionpoints(parabola a, ellipse b) {/**/ return intersectionpoints(b, a); } /**/ point[] intersectionpoints(ellipse a, hyperbola b) {/**/ // if(degenerate(a)) return intersectionpoints(a.l, b); return intersectionpoints((conic)a, (conic)b); } /**/ point[] intersectionpoints(hyperbola a, ellipse b) {/**/ return intersectionpoints(b, a); } /**/ point[] intersectionpoints(circle a, parabola b) {/**/ return intersectionpoints((conic)a, (conic)b); } /**/ point[] intersectionpoints(parabola a, circle b) {/**/ return intersectionpoints((conic)a, (conic)b); } /**/ point[] intersectionpoints(circle a, hyperbola b) {/**/ return intersectionpoints((conic)a, (conic)b); } /**/ point[] intersectionpoints(hyperbola a, circle b) {/**/ return intersectionpoints((conic)a, (conic)b); } /**/ point[] intersectionpoints(parabola a, parabola b) {/**/ return intersectionpoints((conic)a, (conic)b); } /**/ point[] intersectionpoints(parabola a, hyperbola b) {/**/ return intersectionpoints((conic)a, (conic)b); } /**/ point[] intersectionpoints(hyperbola a, parabola b) {/**/ return intersectionpoints((conic)a, (conic)b); } /**/ point[] intersectionpoints(hyperbola a, hyperbola b) {/**/ return intersectionpoints((conic)a, (conic)b); } /**/ point[] intersectionpoints(circle c1, circle c2) {/**/ if(degenerate(c1)) return degenerate(c2) ? new point[]{intersectionpoint(c1.l, c2.l)} : intersectionpoints(c1.l, c2); if(degenerate(c2)) return intersectionpoints(c1, c2.l); return (c1.C == c2.C) ? new point[] : intersectionpoints(radicalline(c1, c2), c1); } /**/ line tangent(circle c, abscissa x) {/*Return the tangent of 'c' at 'point(c, x)'.*/ if(c.r == 0) abort("tangent: a circle with a radius equals zero has no tangent."); point M = point(c, x); return line(rotate(90, M) * c.C, M); } /**/ line[] tangents(circle c, point M) {/*Return the tangents of 'c' passing through 'M'.*/ line[] ol; if(inside(c, M)) return ol; if(M @ c) { ol.push(tangent(c, relabscissa(c, M))); } else { circle cc = circle(c.C, M); point[] inter = intersectionpoints(c, cc); for (int i = 0; i < inter.length; ++i) ol.push(tangents(c, inter[i])[0]); } return ol; } /**/ point point(circle c, point M) {/*Return the intersection point of 'c' with the half-line '[c.C M)'.*/ return intersectionpoints(c, line(c.C, false, M))[0]; } /**/ line tangent(circle c, point M) {/*Return the tangent of 'c' at the intersection point of the half-line'[c.C M)'.*/ return tangents(c, point(c, M))[0]; } /**/ point point(circle c, explicit vector v) {/*Return the intersection point of 'c' with the half-line '[c.C v)'.*/ return point(c, c.C + v); } /**/ line tangent(circle c, explicit vector v) {/*Return the tangent of 'c' at the point M so that vec(c.C M) is collinear to 'v' with the same sense.*/ line ol = tangent(c, c.C + v); return dot(ol.v, v) > 0 ? ol : reverse(ol); } /**/ line tangent(ellipse el, abscissa x) {/*Return the tangent of 'el' at 'point(el, x)'.*/ point M = point(el, x); line l1 = line(el.F1, M); line l2 = line(el.F2, M); line ol = (l1 == l2) ? perpendicular(M, l1) : bisector(l1, l2, 90, false); return ol; } /**/ line[] tangents(ellipse el, point M) {/*Return the tangents of 'el' passing through 'M'.*/ line[] ol; if(inside(el, M)) return ol; if(M @ el) { ol.push(tangent(el, relabscissa(el, M))); } else { point Mp = samecoordsys(M, el.F2) ? M : changecoordsys(el.F2.coordsys, M); circle c = circle(Mp, abs(el.F1 - Mp)); circle cc = circle(el.F2, 2 * el.a); point[] inter = intersectionpoints(c, cc); for (int i = 0; i < inter.length; ++i) { line tl = line(inter[i], el.F2, false); point[] P = intersectionpoints(tl, el); ol.push(line(Mp, P[0])); } } return ol; } /**/ line tangent(parabola p, abscissa x) {/*Return the tangent of 'p' at 'point(p, x)' (use the Wells method).*/ line lt = rotate(90, p.V) * line(p.V, p.F); point P = point(p, x); if(P == p.V) return lt; point M = midpoint(segment(P, p.F)); line l = rotate(90, M) * line(P, p.F); return line(P, projection(lt) * M); } /**/ line[] tangents(parabola p, point M) {/*Return the tangent of 'p' at 'M' (use the Wells method).*/ line[] ol; if(inside(p, M)) return ol; if(M @ p) { ol.push(tangent(p, angabscissa(p, M))); } else { point Mt = changecoordsys(coordsys(p), M); circle c = circle(Mt, p.F); line l = rotate(90, p.V) * line(p.V, p.F); point[] R = intersectionpoints(l, c); for (int i = 0; i < R.length; ++i) { ol.push(line(Mt, R[i])); } // An other method: http://www.du.edu/~jcalvert/math/parabola.htm // point[] R = intersectionpoints(p.directrix, c); // for (int i = 0; i < R.length; ++i) { // ol.push(bisector(segment(p.F, R[i]))); // } } return ol; } /**/ line tangent(hyperbola h, abscissa x) {/*Return the tangent of 'h' at 'point(p, x)'.*/ point M = point(h, x); line ol = bisector(line(M, h.F1), line(M, h.F2)); if(sameside(h.F1, h.F2, ol) || ol == line(h.F1, h.F2)) ol = rotate(90, M) * ol; return ol; } /**/ line[] tangents(hyperbola h, point M) {/*Return the tangent of 'h' at 'M'.*/ line[] ol; if(M @ h) { ol.push(tangent(h, angabscissa(h, M, fromCenter))); } else { coordsys cano = canonicalcartesiansystem(h); bqe bqe = changecoordsys(cano, equation(h)); real a = abs(1/(bqe.a[5] * bqe.a[0])), b = abs(1/(bqe.a[5] * bqe.a[2])); point Mp = changecoordsys(cano, M); real x0 = Mp.x, y0 = Mp.y; if(abs(x0) > epsgeo) { real c0 = a * y0^2/(b * x0)^2 - 1/b, c1 = 2 * a * y0/(b * x0^2), c2 = a/x0^2 - 1; real[] sol = quadraticroots(c0, c1, c2); for (real y:sol) { point tmp = changecoordsys(coordsys(h), point(cano, (a * (1 + y * y0/b)/x0, y))); ol.push(line(M, tmp)); } } else if(abs(y0) > epsgeo) { real y = -b/y0, x = sqrt(a * (1 + b/y0^2)); ol.push(line(M, changecoordsys(coordsys(h), point(cano, (x, y))))); ol.push(line(M, changecoordsys(coordsys(h), point(cano, (-x, y))))); }} return ol; } /**/ point[] intersectionpoints(conic co, arc a) {/*intersectionpoints(arc, circle) is also defined.*/ point[] op; point[] tp = intersectionpoints(co, (conic)a.el); for (int i = 0; i < tp.length; ++i) if(tp[i] @ a) op.push(tp[i]); return op; } point[] intersectionpoints(arc a, conic co) { return intersectionpoints(co, a); } /**/ point[] intersectionpoints(arc a1, arc a2) {/**/ point[] op; point[] tp = intersectionpoints(a1.el, a2.el); for (int i = 0; i < tp.length; ++i) if(tp[i] @ a1 && tp[i] @ a2) op.push(tp[i]); return op; } /**/ point[] intersectionpoints(line l, arc a) {/*intersectionpoints(arc, line) is also defined.*/ point[] op; point[] tp = intersectionpoints(a.el, l); for (int i = 0; i < tp.length; ++i) if(tp[i] @ a && tp[i] @ l) op.push(tp[i]); return op; } point[] intersectionpoints(arc a, line l) { return intersectionpoints(l, a); } /**/ point arcsubtendedcenter(point A, point B, real angle) {/*Return the center of the arc retuned by the 'arcsubtended' routine.*/ point OM; point[] P = standardizecoordsys(A, B); angle = angle%(sgnd(angle) * 180); line bis = bisector(P[0], P[1]); line AB = line(P[0], P[1]); return intersectionpoint(bis, rotate(90 - angle, A) * AB); } /**/ arc arcsubtended(point A, point B, real angle) {/*Return the arc circle from which the segment AB is saw with the angle 'angle'. If the point 'M' is on this arc, the oriented angle (MA, MB) is equal to 'angle'.*/ point[] P = standardizecoordsys(A, B); line AB = line(P[0], P[1]); angle = angle%(sgnd(angle) * 180); point C = arcsubtendedcenter(P[0], P[1], angle); real BC = degrees(B - C)%360; real AC = degrees(A - C)%360; return arc(circle(C, abs(B - C)), BC, AC, angle > 0 ? CCW : CW); } /**/ arc arccircle(point A, point M, point B) {/*Return the CCW arc circle 'AB' passing through 'M'.*/ circle tc = circle(A, M, B); real a = degrees(A - tc.C); real b = degrees(B - tc.C); real m = degrees(M - tc.C); arc oa = arc(tc, a, b); // TODO : use cross product to determine CWW or CW if (!(M @ oa)) { oa.direction = !oa.direction; } return oa; } /**/ arc arc(ellipse el, explicit abscissa x1, explicit abscissa x2, bool direction = CCW) {/*Return the arc from 'point(c, x1)' to 'point(c, x2)' in the direction 'direction'.*/ real a = degrees(point(el, x1) - el.C); real b = degrees(point(el, x2) - el.C); arc oa = arc(el, a - el.angle, b - el.angle, fromCenter, direction); return oa; } /**/ arc arc(ellipse el, point M, point N, bool direction = CCW) {/*Return the arc from 'M' to 'N' in the direction 'direction'. The points 'M' and 'N' must belong to the ellipse 'el'.*/ return arc(el, relabscissa(el, M), relabscissa(el, N), direction); } /**/ arc arccircle(point A, point B, real angle, bool direction = CCW) {/*Return the arc circle centered on A from B to rotate(angle, A) * B in the direction 'direction'.*/ point M = rotate(angle, A) * B; return arc(circle(A, abs(A - B)), B, M, direction); } /**/ arc arc(explicit arc a, abscissa x1, abscissa x2) {/*Return the arc from 'point(a, x1)' to 'point(a, x2)' traversed in the direction of the arc direction.*/ real a1 = angabscissa(a.el, point(a, x1), a.polarconicroutine).x; real a2 = angabscissa(a.el, point(a, x2), a.polarconicroutine).x; return arc(a.el, a1, a2, a.polarconicroutine, a.direction); } /**/ arc arc(explicit arc a, point M, point N) {/*Return the arc from 'M' to 'N'. The points 'M' and 'N' must belong to the arc 'a'.*/ return arc(a, relabscissa(a, M), relabscissa(a, N)); } /**/ arc inverse(real k, point A, segment s) {/*Return the inverse arc circle of 's' with respect to point A and inversion radius 'k'.*/ point Ap = inverse(k, A, s.A), Bp = inverse(k, A, s.B), M = inverse(k, A, midpoint(s)); return arccircle(Ap, M, Bp); } /**/ arc operator *(inversion i, segment s) {/*Provide inversion * segment.*/ return inverse(i.k, i.C, s); } /**/ path operator *(inversion i, triangle t) {/*Provide inversion * triangle.*/ return (path)(i * segment(t.AB))-- (path)(i * segment(t.BC))-- (path)(i * segment(t.CA))&cycle; } /**/ path compassmark(pair O, pair A, real position, real angle = 10) {/*Return an arc centered on O with the angle 'angle' so that the position of 'A' on this arc makes an angle 'position * angle'.*/ real a = degrees(A - O); real pa = (a - position * angle)%360, pb = (a - (position - 1) * angle)%360; real t1 = intersect(unitcircle, (0, 0)--2 * dir(pa))[0]; real t2 = intersect(unitcircle, (0, 0)--2 * dir(pb))[0]; int n = length(unitcircle); if(t1 >= t2) t1 -= n; return shift(O) * scale(abs(O - A)) * subpath(unitcircle, t1, t2); } /**/ line tangent(explicit arc a, abscissa x) {/*Return the tangent of 'a' at 'point(a, x)'.*/ abscissa ag = angabscissa(a, point(a, x)); return tangent(a.el, ag + a.angle1 + (a.el.e == 0 ? a.angle0 : 0)); } /**/ line tangent(explicit arc a, point M) {/*Return the tangent of 'a' at 'M'. The points 'M' must belong to the arc 'a'.*/ return tangent(a, angabscissa(a, M)); } // *=======================================================* // *.......Routines for compatibility with original geometry module........* path square(pair z1, pair z2) { pair v = z2 - z1; pair z3 = z2 + I * v; pair z4 = z3 - v; return z1--z2--z3--z4--cycle; } // Draw a perpendicular symbol at z aligned in the direction align // relative to the path z--z + dir. void perpendicular(picture pic = currentpicture, pair z, pair align, pair dir = E, real size = 0, pen p = currentpen, margin margin = NoMargin, filltype filltype = NoFill) { perpendicularmark(pic, (point) z, align, dir, size, p, margin, filltype); } // Draw a perpendicular symbol at z aligned in the direction align // relative to the path z--z + dir(g, 0) void perpendicular(picture pic = currentpicture, pair z, pair align, path g, real size = 0, pen p = currentpen, margin margin = NoMargin, filltype filltype = NoFill) { perpendicularmark(pic, (point) z, align, dir(g, 0), size, p, margin, filltype); } // Return an interior arc BAC of triangle ABC, given a radius r > 0. // If r < 0, return the corresponding exterior arc of radius |r|. path arc(explicit pair B, explicit pair A, explicit pair C, real r) { real BA = degrees(B - A); real CA = degrees(C - A); return arc(A, abs(r), BA, CA, (r < 0) ^ ((BA-CA) % 360 < 180) ? CW : CCW); } // *.......End of compatibility routines........* // *=======================================================* // *........................FOOTER.........................* // *=======================================================* asymptote-2.37/base/graph.asy000066400000000000000000001745701265434602500162500ustar00rootroot00000000000000private import math; import graph_splinetype; import graph_settings; scaleT Linear; scaleT Log=scaleT(log10,pow10,logarithmic=true); scaleT Logarithmic=Log; string baselinetemplate="$10^4$"; // A linear scale, with optional autoscaling of minimum and maximum values, // scaling factor s and intercept. scaleT Linear(bool automin=false, bool automax=automin, real s=1, real intercept=0) { real sinv=1/s; scalefcn T,Tinv; if(s == 1 && intercept == 0) T=Tinv=identity; else { T=new real(real x) {return (x-intercept)*s;}; Tinv=new real(real x) {return x*sinv+intercept;}; } return scaleT(T,Tinv,logarithmic=false,automin,automax); } // A logarithmic scale, with optional autoscaling of minimum and maximum // values. scaleT Log(bool automin=false, bool automax=automin) { return scaleT(Log.T,Log.Tinv,logarithmic=true,automin,automax); } // A "broken" linear axis omitting the segment [a,b]. scaleT Broken(real a, real b, bool automin=false, bool automax=automin) { real skip=b-a; real T(real x) { if(x <= a) return x; if(x <= b) return a; return x-skip; } real Tinv(real x) { if(x <= a) return x; return x+skip; } return scaleT(T,Tinv,logarithmic=false,automin,automax); } // A "broken" logarithmic axis omitting the segment [a,b], where a and b are // automatically rounded to the nearest integral power of the base. scaleT BrokenLog(real a, real b, bool automin=false, bool automax=automin) { real A=round(Log.T(a)); real B=round(Log.T(b)); a=Log.Tinv(A); b=Log.Tinv(B); real skip=B-A; real T(real x) { if(x <= a) return Log.T(x); if(x <= b) return A; return Log.T(x)-skip; } real Tinv(real x) { real X=Log.Tinv(x); if(X <= a) return X; return Log.Tinv(x+skip); } return scaleT(T,Tinv,logarithmic=true,automin,automax); } Label Break=Label("$\approx$",UnFill(0.2mm)); void scale(picture pic=currentpicture, scaleT x, scaleT y=x, scaleT z=y) { pic.scale.x.scale=x; pic.scale.y.scale=y; pic.scale.z.scale=z; pic.scale.x.automin=x.automin; pic.scale.y.automin=y.automin; pic.scale.z.automin=z.automin; pic.scale.x.automax=x.automax; pic.scale.y.automax=y.automax; pic.scale.z.automax=z.automax; } void scale(picture pic=currentpicture, bool xautoscale=false, bool yautoscale=xautoscale, bool zautoscale=yautoscale) { scale(pic,Linear(xautoscale,xautoscale),Linear(yautoscale,yautoscale), Linear(zautoscale,zautoscale)); } struct scientific { int sign; real mantissa; int exponent; int ceil() {return sign*ceil(mantissa);} real scale(real x, real exp) { static real max=0.1*realMax; static real limit=-log10(max); return x*(exp > limit ? 10^-exp : max); } real ceil(real x, real exp) {return ceil(sign*scale(abs(x),exp));} real floor(real x, real exp) {return floor(sign*scale(abs(x),exp));} } // Convert x to scientific notation scientific scientific(real x) { scientific s; s.sign=sgn(x); x=abs(x); if(x == 0) {s.mantissa=0; s.exponent=-intMax; return s;} real logx=log10(x); s.exponent=floor(logx); s.mantissa=s.scale(x,s.exponent); return s; } // Autoscale limits and tick divisor. struct bounds { real min; real max; // Possible tick intervals: int[] divisor; void operator init(real min, real max, int[] divisor=new int[]) { this.min=min; this.max=max; this.divisor=divisor; } } // Compute tick divisors. int[] divisors(int a, int b) { int[] dlist; int n=b-a; dlist[0]=1; if(n == 1) {dlist[1]=10; dlist[2]=100; return dlist;} if(n == 2) {dlist[1]=2; return dlist;} int sqrtn=floor(sqrt(n)); int i=0; for(int d=2; d <= sqrtn; ++d) if(n % d == 0 && (a*b >= 0 || b % (n/d) == 0)) dlist[++i]=d; for(int d=sqrtn; d >= 1; --d) if(n % d == 0 && (a*b >= 0 || b % d == 0)) dlist[++i]=quotient(n,d); return dlist; } real upscale(real b, real a) { if(b <= 5) b=5; else if (b > 10 && a >= 0 && b <= 12) b=12; else if (b > 10 && (a >= 0 || 15 % -a == 0) && b <= 15) b=15; else b=ceil(b/10)*10; return b; } // Compute autoscale limits and tick divisor. bounds autoscale(real Min, real Max, scaleT scale=Linear) { bounds m; if(scale.logarithmic) { m.min=floor(Min); m.max=ceil(Max); return m; } if(!(finite(Min) && finite(Max))) abort("autoscale requires finite limits"); Min=scale.Tinv(Min); Max=scale.Tinv(Max); m.min=Min; m.max=Max; if(Min > Max) {real temp=Min; Min=Max; Max=temp;} if(Min == Max) { if(Min == 0) {m.max=1; return m;} if(Min > 0) {Min=0; Max *= 2;} else {Min *= 2; Max=0;} } int sign; if(Min < 0 && Max <= 0) {real temp=-Min; Min=-Max; Max=temp; sign=-1;} else sign=1; scientific sa=scientific(Min); scientific sb=scientific(Max); int exp=max(sa.exponent,sb.exponent); real a=sa.floor(Min,exp); real b=sb.ceil(Max,exp); void zoom() { --exp; a=sa.floor(Min,exp); b=sb.ceil(Max,exp); } if(sb.mantissa <= 1.5) zoom(); while((b-a)*10.0^exp > 10*(Max-Min)) zoom(); real bsave=b; if(b-a > (a >= 0 ? 8 : 6)) { b=upscale(b,a); if(a >= 0) { if(a <= 5) a=0; else a=floor(a/10)*10; } else a=-upscale(-a,-1); } // Redo b in case the value of a has changed if(bsave-a > (a >= 0 ? 8 : 6)) b=upscale(bsave,a); if(sign == -1) {real temp=-a; a=-b; b=temp;} real Scale=10.0^exp; m.min=scale.T(a*Scale); m.max=scale.T(b*Scale); if(m.min > m.max) {real temp=m.min; m.min=m.max; m.max=temp;} m.divisor=divisors(round(a),round(b)); return m; } typedef string ticklabel(real); ticklabel Format(string s=defaultformat) { return new string(real x) {return format(s,x);}; } ticklabel OmitFormat(string s=defaultformat ... real[] x) { return new string(real v) { string V=format(s,v); for(real a : x) if(format(s,a) == V) return ""; return V; }; } string trailingzero="$%#$"; string signedtrailingzero="$%+#$"; ticklabel DefaultFormat=Format(); ticklabel NoZeroFormat=OmitFormat(0); // Format tick values as integral powers of base; otherwise with DefaultFormat. ticklabel DefaultLogFormat(int base) { return new string(real x) { string exponent=format("%.4f",log(x)/log(base)); return find(exponent,".") == -1 ? "$"+(string) base+"^{"+exponent+"}$" : format(x); }; } // Format all tick values as powers of base. ticklabel LogFormat(int base) { return new string(real x) { return format("$"+(string) base+"^{%g}$",log(x)/log(base)); }; } ticklabel LogFormat=LogFormat(10); ticklabel DefaultLogFormat=DefaultLogFormat(10); // The default direction specifier. pair zero(real) {return 0;} struct ticklocate { real a,b; // Tick values at point(g,0), point(g,length(g)). autoscaleT S; // Autoscaling transformation. pair dir(real t); // Absolute 2D tick direction. triple dir3(real t); // Absolute 3D tick direction. real time(real v); // Returns the time corresponding to the value v. ticklocate copy() { ticklocate T=new ticklocate; T.a=a; T.b=b; T.S=S.copy(); T.dir=dir; T.dir3=dir3; T.time=time; return T; } } autoscaleT defaultS; typedef real valuetime(real); valuetime linear(scalefcn S=identity, real Min, real Max) { real factor=Max == Min ? 0.0 : 1.0/(Max-Min); return new real(real v) {return (S(v)-Min)*factor;}; } ticklocate ticklocate(real a, real b, autoscaleT S=defaultS, real tickmin=-infinity, real tickmax=infinity, real time(real)=null, pair dir(real)=zero) { if((valuetime) time == null) time=linear(S.T(),a,b); ticklocate locate; locate.a=a; locate.b=b; locate.S=S.copy(); if(finite(tickmin)) locate.S.tickMin=tickmin; if(finite(tickmax)) locate.S.tickMax=tickmax; locate.time=time; locate.dir=dir; return locate; } private struct locateT { real t; // tick location time pair Z; // tick location in frame coordinates pair pathdir; // path direction in frame coordinates pair dir; // tick direction in frame coordinates void dir(transform T, path g, ticklocate locate, real t) { pathdir=unit(shiftless(T)*dir(g,t)); pair Dir=locate.dir(t); dir=Dir == 0 ? -I*pathdir : unit(Dir); } // Locate the desired position of a tick along a path. void calc(transform T, path g, ticklocate locate, real val) { t=locate.time(val); Z=T*point(g,t); dir(T,g,locate,t); } } pair ticklabelshift(pair align, pen p=currentpen) { return 0.25*unit(align)*labelmargin(p); } void drawtick(frame f, transform T, path g, path g2, ticklocate locate, real val, real Size, int sign, pen p, bool extend) { locateT locate1,locate2; locate1.calc(T,g,locate,val); if(extend && size(g2) > 0) { locate2.calc(T,g2,locate,val); draw(f,locate1.Z--locate2.Z,p); } else if(sign == 0) draw(f,locate1.Z-Size*locate1.dir--locate1.Z+Size*locate1.dir,p); else draw(f,locate1.Z--locate1.Z+Size*sign*locate1.dir,p); } real zerotickfuzz=10*epsilon; // Label a tick on a frame. pair labeltick(frame d, transform T, path g, ticklocate locate, real val, pair side, int sign, real Size, ticklabel ticklabel, Label F, real norm=0) { locateT locate1; locate1.calc(T,g,locate,val); pair align=side*locate1.dir; pair perp=I*locate1.pathdir; // Adjust tick label alignment pair adjust=unit(align+0.75perp*sgn(dot(align,perp))); // Project align onto adjusted direction. align=adjust*dot(align,adjust); pair shift=dot(align,-sign*locate1.dir) <= 0 ? align*Size : ticklabelshift(align,F.p); real label; if(locate.S.scale.logarithmic) label=locate.S.scale.Tinv(val); else { label=val; if(abs(label) < zerotickfuzz*norm) label=0; // Fix epsilon errors at +/-1e-4 // default format changes to scientific notation here if(abs(abs(label)-1e-4) < epsilon) label=sgn(label)*1e-4; } string s=ticklabel(label); if(s != "") label(d,F.T*baseline(s,baselinetemplate),locate1.Z+shift,align,F.p, F.filltype); return locate1.pathdir; } // Add axis label L to frame f. void labelaxis(frame f, transform T, Label L, path g, ticklocate locate=null, int sign=1, bool ticklabels=false) { Label L0=L.copy(); real t=L0.relative(g); pair z=point(g,t); pair dir=dir(g,t); pair perp=I*dir; if(locate != null) { locateT locate1; locate1.dir(T,g,locate,t); L0.align(L0.align,unit(-sgn(dot(sign*locate1.dir,perp))*perp)); } pair align=L0.align.dir; if(L0.align.relative) align *= -perp; pair alignperp=dot(align,perp)*perp; pair offset; if(ticklabels) { if(piecewisestraight(g)) { real angle=degrees(dir,warn=false); transform S=rotate(-angle,z); frame F=S*f; pair Align=rotate(-angle)*alignperp; offset=unit(alignperp-sign*locate.dir(t))* abs((Align.y >= 0 ? max(F).y : (Align.y < 0 ? min(F).y : 0))-z.y); } z += offset; } L0.align(align); L0.position(z); frame d; add(d,L0); pair width=0.5*size(d); int n=length(g); real t=L.relative(); pair s=realmult(width,dir(g,t)); if(t <= 0) { if(L.align.default) s *= -axislabelfactor; d=shift(s)*d; } else if(t >= n) { if(L.align.default) s *= -axislabelfactor; d=shift(-s)*d; } else if(offset == 0 && L.align.default) { pair s=realmult(width,I*dir(g,t)); s=axislabelfactor*s; d=shift(s)*d; } add(f,d); } // Check the tick coverage of a linear axis. bool axiscoverage(int N, transform T, path g, ticklocate locate, real Step, pair side, int sign, real Size, Label F, ticklabel ticklabel, real norm, real limit) { real coverage=0; bool loop=cyclic(g); real a=locate.S.Tinv(locate.a); real b=locate.S.Tinv(locate.b); real tickmin=finite(locate.S.tickMin) ? locate.S.Tinv(locate.S.tickMin) : a; if(Size > 0) { int count=0; if(loop) count=N+1; else { for(int i=0; i <= N; ++i) { real val=tickmin+i*Step; if(val >= a && val <= b) ++count; } } if(count > 0) limit /= count; for(int i=0; i <= N; ++i) { real val=tickmin+i*Step; if(loop || (val >= a && val <= b)) { frame d; pair dir=labeltick(d,T,g,locate,val,side,sign,Size,ticklabel,F,norm); if(abs(dot(size(d),dir)) > limit) return false; } } } return true; } // Check the tick coverage of a logarithmic axis. bool logaxiscoverage(int N, transform T, path g, ticklocate locate, pair side, int sign, real Size, Label F, ticklabel ticklabel, real limit, int first, int last) { bool loop=cyclic(g); real coverage=0; real a=locate.a; real b=locate.b; int count=0; for(int i=first-1; i <= last+1; i += N) { if(loop || i >= a && i <= b) ++count; } if(count > 0) limit /= count; for(int i=first-1; i <= last+1; i += N) { if(loop || i >= a && i <= b) { frame d; pair dir=labeltick(d,T,g,locate,i,side,sign,Size,ticklabel,F); if(abs(dot(size(d),dir)) > limit) return false; } } return true; } struct tickvalues { real[] major; real[] minor; int N; // For logarithmic axes: number of decades between tick labels. } // Determine a format that distinguishes adjacent pairs of ticks, optionally // adding trailing zeros. string autoformat(string format="", real norm ... real[] a) { bool trailingzero=(format == trailingzero); bool signedtrailingzero=(format == signedtrailingzero); if(!trailingzero && !signedtrailingzero && format != "") return format; real[] A=sort(a); real[] a=abs(A); bool signchange=(A.length > 1 && A[0] < 0 && A[A.length-1] >= 0); for(int i=0; i < A.length; ++i) if(a[i] < zerotickfuzz*norm) A[i]=a[i]=0; int n=0; bool Fixed=find(a >= 1e4-epsilon | (a > 0 & a <= 1e-4-epsilon)) < 0; string Format=defaultformat(4,fixed=Fixed); if(Fixed && n < 4) { for(int i=0; i < A.length; ++i) { real a=A[i]; while(format(defaultformat(n,fixed=Fixed),a) != format(Format,a)) ++n; } } string trailing=trailingzero ? (signchange ? "# " : "#") : signedtrailingzero ? "#+" : ""; string format=defaultformat(n,trailing,Fixed); for(int i=0; i < A.length-1; ++i) { real a=A[i]; real b=A[i+1]; // Check if an extra digit of precision should be added. string fixedformat="%#."+string(n+1)+"f"; string A=format(fixedformat,a); string B=format(fixedformat,b); if(substr(A,length(A)-1,1) != "0" || substr(B,length(B)-1,1) != "0") { a *= 0.1; b *= 0.1; } if(a != b) { while(format(format,a) == format(format,b)) format=defaultformat(++n,trailing,Fixed); } } if(n == 0) return defaultformat; return format; } // Automatic tick generation routine. tickvalues generateticks(int sign, Label F="", ticklabel ticklabel=null, int N, int n=0, real Step=0, real step=0, real Size=0, real size=0, transform T, pair side, path g, real limit, pen p, ticklocate locate, int[] divisor, bool opposite) { tickvalues tickvalues; sign=opposite ? -sign : sign; if(Size == 0) Size=Ticksize; if(size == 0) size=ticksize; F=F.copy(); F.p(p); if(F.align.dir != 0) side=F.align.dir; else if(side == 0) side=((sign == 1) ? left : right); bool ticklabels=false; path G=T*g; if(!locate.S.scale.logarithmic) { real a=locate.S.Tinv(locate.a); real b=locate.S.Tinv(locate.b); real norm=max(abs(a),abs(b)); string format=autoformat(F.s,norm,a,b); if(F.s == "%") F.s=""; if(ticklabel == null) ticklabel=Format(format); if(a > b) {real temp=a; a=b; b=temp;} if(b-a < 100.0*epsilon*norm) b=a; bool autotick=Step == 0 && N == 0; real tickmin=finite(locate.S.tickMin) && (autotick || locate.S.automin) ? locate.S.Tinv(locate.S.tickMin) : a; real tickmax=finite(locate.S.tickMax) && (autotick || locate.S.automax) ? locate.S.Tinv(locate.S.tickMax) : b; if(tickmin > tickmax) {real temp=tickmin; tickmin=tickmax; tickmax=temp;} real inStep=Step; bool calcStep=true; real len=tickmax-tickmin; if(autotick) { N=1; if(divisor.length > 0) { bool autoscale=locate.S.automin && locate.S.automax; real h=0.5*(b-a); if(h > 0) { for(int d=divisor.length-1; d >= 0; --d) { int N0=divisor[d]; Step=len/N0; int N1=N0; int m=2; while(Step > h) { N0=m*N1; Step=len/N0; m *= 2; } if(axiscoverage(N0,T,g,locate,Step,side,sign,Size,F,ticklabel,norm, limit)) { N=N0; if(N0 == 1 && !autoscale && d < divisor.length-1) { // Try using 2 ticks (otherwise 1); int div=divisor[d+1]; Step=quotient(div,2)*len/div; calcStep=false; if(axiscoverage(2,T,g,locate,Step,side,sign,Size,F,ticklabel, norm,limit)) N=2; else Step=len; } // Found a good divisor; now compute subtick divisor if(n == 0) { if(step != 0) n=ceil(Step/step); else { n=quotient(divisor[divisor.length-1],N); if(N == 1) n=(a*b >= 0) ? 2 : 1; if(n == 1) n=2; } } break; } } } } } if(inStep != 0 && !locate.S.automin) { tickmin=floor(tickmin/Step)*Step; len=tickmax-tickmin; } if(calcStep) { if(N == 0) N=(int) (len/Step); else Step=len/N; } if(n == 0) { if(step != 0) n=ceil(Step/step); } else step=Step/n; b += epsilon*norm; if(Size > 0) { for(int i=0; i <= N; ++i) { real val=tickmin+i*Step; if(val >= a && val <= b) tickvalues.major.push(val); if(size > 0 && step > 0) { real iStep=i*Step; real jstop=(len-iStep)/step; for(int j=1; j < n && j <= jstop; ++j) { real val=tickmin+iStep+j*step; if(val >= a && val <= b) tickvalues.minor.push(val); } } } } } else { // Logarithmic string format=F.s; if(F.s == "%") F.s=""; int base=round(locate.S.scale.Tinv(1)); if(ticklabel == null) ticklabel=format == "%" ? Format("") : DefaultLogFormat(base); real a=locate.S.postscale.Tinv(locate.a); real b=locate.S.postscale.Tinv(locate.b); if(a > b) {real temp=a; a=b; b=temp;} int first=floor(a-epsilon); int last=ceil(b+epsilon); if(N == 0) { N=1; while(N <= last-first) { if(logaxiscoverage(N,T,g,locate,side,sign,Size,F,ticklabel,limit, first,last)) break; ++N; } } if(N <= 2 && n == 0) n=base; tickvalues.N=N; if(N > 0) { for(int i=first-1; i <= last+1; ++i) { if(i >= a && i <= b) tickvalues.major.push(locate.S.scale.Tinv(i)); if(n > 0) { for(int j=2; j < n; ++j) { real val=(i+1+locate.S.scale.T(j/n)); if(val >= a && val <= b) tickvalues.minor.push(locate.S.scale.Tinv(val)); } } } } } return tickvalues; } // Signature of routines that draw labelled paths with ticks and tick labels. typedef void ticks(frame, transform, Label, pair, path, path, pen, arrowbar, margin, ticklocate, int[], bool opposite=false); // Tick construction routine for a user-specified array of tick values. ticks Ticks(int sign, Label F="", ticklabel ticklabel=null, bool beginlabel=true, bool endlabel=true, real[] Ticks=new real[], real[] ticks=new real[], int N=1, bool begin=true, bool end=true, real Size=0, real size=0, bool extend=false, pen pTick=nullpen, pen ptick=nullpen) { return new void(frame f, transform t, Label L, pair side, path g, path g2, pen p, arrowbar arrow, margin margin, ticklocate locate, int[] divisor, bool opposite) { // Use local copy of context variables: int sign=opposite ? -sign : sign; pen pTick=pTick; pen ptick=ptick; ticklabel ticklabel=ticklabel; real Size=Size; real size=size; if(Size == 0) Size=Ticksize; if(size == 0) size=ticksize; Label L=L.copy(); Label F=F.copy(); L.p(p); F.p(p); if(pTick == nullpen) pTick=p; if(ptick == nullpen) ptick=pTick; if(F.align.dir != 0) side=F.align.dir; else if(side == 0) side=F.T*((sign == 1) ? left : right); bool ticklabels=false; path G=t*g; path G2=t*g2; scalefcn T; real a,b; if(locate.S.scale.logarithmic) { a=locate.S.postscale.Tinv(locate.a); b=locate.S.postscale.Tinv(locate.b); T=locate.S.scale.T; } else { a=locate.S.Tinv(locate.a); b=locate.S.Tinv(locate.b); T=identity; } if(a > b) {real temp=a; a=b; b=temp;} real norm=max(abs(a),abs(b)); string format=autoformat(F.s,norm...Ticks); if(F.s == "%") F.s=""; if(ticklabel == null) { if(locate.S.scale.logarithmic) { int base=round(locate.S.scale.Tinv(1)); ticklabel=format == "%" ? Format("") : DefaultLogFormat(base); } else ticklabel=Format(format); } begingroup(f); if(opposite) draw(f,G,p); else draw(f,margin(G,p).g,p,arrow); for(int i=(begin ? 0 : 1); i < (end ? Ticks.length : Ticks.length-1); ++i) { real val=T(Ticks[i]); if(val >= a && val <= b) drawtick(f,t,g,g2,locate,val,Size,sign,pTick,extend); } for(int i=0; i < ticks.length; ++i) { real val=T(ticks[i]); if(val >= a && val <= b) drawtick(f,t,g,g2,locate,val,size,sign,ptick,extend); } endgroup(f); if(N == 0) N=1; if(Size > 0 && !opposite) { for(int i=(beginlabel ? 0 : 1); i < (endlabel ? Ticks.length : Ticks.length-1); i += N) { real val=T(Ticks[i]); if(val >= a && val <= b) { ticklabels=true; labeltick(f,t,g,locate,val,side,sign,Size,ticklabel,F,norm); } } } if(L.s != "" && !opposite) labelaxis(f,t,L,G,locate,sign,ticklabels); }; } // Optional routine to allow modification of auto-generated tick values. typedef tickvalues tickmodifier(tickvalues); tickvalues None(tickvalues v) {return v;} // Tickmodifier that removes all ticks in the intervals [a[i],b[i]]. tickmodifier OmitTickIntervals(real[] a, real[] b) { return new tickvalues(tickvalues v) { if(a.length != b.length) abort(differentlengths); void omit(real[] A) { if(A.length != 0) { real norm=max(abs(A)); for(int i=0; i < a.length; ++i) { int j; while((j=find(A > a[i]-zerotickfuzz*norm & A < b[i]+zerotickfuzz*norm)) >= 0) { A.delete(j); } } } } omit(v.major); omit(v.minor); return v; }; } // Tickmodifier that removes all ticks in the interval [a,b]. tickmodifier OmitTickInterval(real a, real b) { return OmitTickIntervals(new real[] {a}, new real[] {b}); } // Tickmodifier that removes the specified ticks. tickmodifier OmitTick(... real[] x) { return OmitTickIntervals(x,x); } tickmodifier NoZero=OmitTick(0); tickmodifier Break(real, real)=OmitTickInterval; // Automatic tick construction routine. ticks Ticks(int sign, Label F="", ticklabel ticklabel=null, bool beginlabel=true, bool endlabel=true, int N, int n=0, real Step=0, real step=0, bool begin=true, bool end=true, tickmodifier modify=None, real Size=0, real size=0, bool extend=false, pen pTick=nullpen, pen ptick=nullpen) { return new void(frame f, transform T, Label L, pair side, path g, path g2, pen p, arrowbar arrow, margin margin, ticklocate locate, int[] divisor, bool opposite) { real limit=Step == 0 ? axiscoverage*arclength(T*g) : 0; tickvalues values=modify(generateticks(sign,F,ticklabel,N,n,Step,step, Size,size,T,side,g, limit,p,locate,divisor,opposite)); Ticks(sign,F,ticklabel,beginlabel,endlabel,values.major,values.minor, values.N,begin,end,Size,size,extend,pTick,ptick) (f,T,L,side,g,g2,p,arrow,margin,locate,divisor,opposite); }; } ticks NoTicks() { return new void(frame f, transform T, Label L, pair, path g, path, pen p, arrowbar arrow, margin margin, ticklocate, int[], bool opposite) { path G=T*g; if(opposite) draw(f,G,p); else { draw(f,margin(G,p).g,p,arrow); if(L.s != "") { Label L=L.copy(); L.p(p); labelaxis(f,T,L,G); } } }; } ticks LeftTicks(Label format="", ticklabel ticklabel=null, bool beginlabel=true, bool endlabel=true, int N=0, int n=0, real Step=0, real step=0, bool begin=true, bool end=true, tickmodifier modify=None, real Size=0, real size=0, bool extend=false, pen pTick=nullpen, pen ptick=nullpen) { return Ticks(-1,format,ticklabel,beginlabel,endlabel,N,n,Step,step, begin,end,modify,Size,size,extend,pTick,ptick); } ticks RightTicks(Label format="", ticklabel ticklabel=null, bool beginlabel=true, bool endlabel=true, int N=0, int n=0, real Step=0, real step=0, bool begin=true, bool end=true, tickmodifier modify=None, real Size=0, real size=0, bool extend=false, pen pTick=nullpen, pen ptick=nullpen) { return Ticks(1,format,ticklabel,beginlabel,endlabel,N,n,Step,step, begin,end,modify,Size,size,extend,pTick,ptick); } ticks Ticks(Label format="", ticklabel ticklabel=null, bool beginlabel=true, bool endlabel=true, int N=0, int n=0, real Step=0, real step=0, bool begin=true, bool end=true, tickmodifier modify=None, real Size=0, real size=0, bool extend=false, pen pTick=nullpen, pen ptick=nullpen) { return Ticks(0,format,ticklabel,beginlabel,endlabel,N,n,Step,step, begin,end,modify,Size,size,extend,pTick,ptick); } ticks LeftTicks(Label format="", ticklabel ticklabel=null, bool beginlabel=true, bool endlabel=true, real[] Ticks, real[] ticks=new real[], real Size=0, real size=0, bool extend=false, pen pTick=nullpen, pen ptick=nullpen) { return Ticks(-1,format,ticklabel,beginlabel,endlabel, Ticks,ticks,Size,size,extend,pTick,ptick); } ticks RightTicks(Label format="", ticklabel ticklabel=null, bool beginlabel=true, bool endlabel=true, real[] Ticks, real[] ticks=new real[], real Size=0, real size=0, bool extend=false, pen pTick=nullpen, pen ptick=nullpen) { return Ticks(1,format,ticklabel,beginlabel,endlabel, Ticks,ticks,Size,size,extend,pTick,ptick); } ticks Ticks(Label format="", ticklabel ticklabel=null, bool beginlabel=true, bool endlabel=true, real[] Ticks, real[] ticks=new real[], real Size=0, real size=0, bool extend=false, pen pTick=nullpen, pen ptick=nullpen) { return Ticks(0,format,ticklabel,beginlabel,endlabel, Ticks,ticks,Size,size,extend,pTick,ptick); } ticks NoTicks=NoTicks(), LeftTicks=LeftTicks(), RightTicks=RightTicks(), Ticks=Ticks(); pair tickMin(picture pic) { return minbound(pic.userMin(),(pic.scale.x.tickMin,pic.scale.y.tickMin)); } pair tickMax(picture pic) { return maxbound(pic.userMax(),(pic.scale.x.tickMax,pic.scale.y.tickMax)); } int Min=-1; int Value=0; int Max=1; int Both=2; // Structure used to communicate axis and autoscale settings to tick routines. struct axisT { int type; // -1 = min, 0 = given value, 1 = max, 2 = min/max int type2; // for 3D axis real value; real value2; pair side; // 2D tick label direction relative to path (left or right) real position; // label position along axis align align; // default axis label alignment and 3D tick label direction int[] xdivisor; int[] ydivisor; int[] zdivisor; bool extend; // extend axis to graph boundary? }; axisT axis; typedef void axis(picture, axisT); axis Bottom(bool extend=false) { return new void(picture pic, axisT axis) { axis.type=Min; axis.position=0.5; axis.side=right; axis.align=S; axis.extend=extend; }; } axis Top(bool extend=false) { return new void(picture pic, axisT axis) { axis.type=Max; axis.position=0.5; axis.side=left; axis.align=N; axis.extend=extend; }; } axis BottomTop(bool extend=false) { return new void(picture pic, axisT axis) { axis.type=Both; axis.position=0.5; axis.side=right; axis.align=S; axis.extend=extend; }; } axis Left(bool extend=false) { return new void(picture pic, axisT axis) { axis.type=Min; axis.position=0.5; axis.side=left; axis.align=W; axis.extend=extend; }; } axis Right(bool extend=false) { return new void(picture pic, axisT axis) { axis.type=Max; axis.position=0.5; axis.side=right; axis.align=E; axis.extend=extend; }; } axis LeftRight(bool extend=false) { return new void(picture pic, axisT axis) { axis.type=Both; axis.position=0.5; axis.side=left; axis.align=W; axis.extend=extend; }; } axis XEquals(real x, bool extend=true) { return new void(picture pic, axisT axis) { axis.type=Value; axis.value=pic.scale.x.T(x); axis.position=1; axis.side=left; axis.align=W; axis.extend=extend; }; } axis YEquals(real y, bool extend=true) { return new void(picture pic, axisT axis) { axis.type=Value; axis.value=pic.scale.y.T(y); axis.position=1; axis.side=right; axis.align=S; axis.extend=extend; }; } axis XZero(bool extend=true) { return new void(picture pic, axisT axis) { axis.type=Value; axis.value=pic.scale.x.T(pic.scale.x.scale.logarithmic ? 1 : 0); axis.position=1; axis.side=left; axis.align=W; axis.extend=extend; }; } axis YZero(bool extend=true) { return new void(picture pic, axisT axis) { axis.type=Value; axis.value=pic.scale.y.T(pic.scale.y.scale.logarithmic ? 1 : 0); axis.position=1; axis.side=right; axis.align=S; axis.extend=extend; }; } axis Bottom=Bottom(), Top=Top(), BottomTop=BottomTop(), Left=Left(), Right=Right(), LeftRight=LeftRight(), XZero=XZero(), YZero=YZero(); // Draw a general axis. void axis(picture pic=currentpicture, Label L="", path g, path g2=nullpath, pen p=currentpen, ticks ticks, ticklocate locate, arrowbar arrow=None, margin margin=NoMargin, int[] divisor=new int[], bool above=false, bool opposite=false) { Label L=L.copy(); real t=reltime(g,0.5); if(L.defaultposition) L.position(t); divisor=copy(divisor); locate=locate.copy(); pic.add(new void (frame f, transform t, transform T, pair lb, pair rt) { frame d; ticks(d,t,L,0,g,g2,p,arrow,margin,locate,divisor,opposite); (above ? add : prepend)(f,t*T*inverse(t)*d); }); pic.addPath(g,p); if(L.s != "") { frame f; Label L0=L.copy(); L0.position(0); add(f,L0); pair pos=point(g,L.relative()*length(g)); pic.addBox(pos,pos,min(f),max(f)); } } real xtrans(transform t, real x) { return (t*(x,0)).x; } real ytrans(transform t, real y) { return (t*(0,y)).y; } // An internal routine to draw an x axis at a particular y value. void xaxisAt(picture pic=currentpicture, Label L="", axis axis, real xmin=-infinity, real xmax=infinity, pen p=currentpen, ticks ticks=NoTicks, arrowbar arrow=None, margin margin=NoMargin, bool above=true, bool opposite=false) { real y=axis.value; real y2; Label L=L.copy(); int[] divisor=copy(axis.xdivisor); pair side=axis.side; int type=axis.type; pic.add(new void (frame f, transform t, transform T, pair lb, pair rt) { transform tinv=inverse(t); pair a=xmin == -infinity ? tinv*(lb.x-min(p).x,ytrans(t,y)) : (xmin,y); pair b=xmax == infinity ? tinv*(rt.x-max(p).x,ytrans(t,y)) : (xmax,y); pair a2=xmin == -infinity ? tinv*(lb.x-min(p).x,ytrans(t,y2)) : (xmin,y2); pair b2=xmax == infinity ? tinv*(rt.x-max(p).x,ytrans(t,y2)) : (xmax,y2); if(xmin == -infinity || xmax == infinity) { bounds mx=autoscale(a.x,b.x,pic.scale.x.scale); pic.scale.x.tickMin=mx.min; pic.scale.x.tickMax=mx.max; divisor=mx.divisor; } real fuzz=epsilon*max(abs(a.x),abs(b.x)); a -= (fuzz,0); b += (fuzz,0); frame d; ticks(d,t,L,side,a--b,finite(y2) ? a2--b2 : nullpath,p,arrow,margin, ticklocate(a.x,b.x,pic.scale.x),divisor,opposite); (above ? add : prepend)(f,t*T*tinv*d); }); void bounds() { if(type == Both) { y2=pic.scale.y.automax() ? tickMax(pic).y : pic.userMax().y; y=opposite ? y2 : (pic.scale.y.automin() ? tickMin(pic).y : pic.userMin().y); } else if(type == Min) y=pic.scale.y.automin() ? tickMin(pic).y : pic.userMin().y; else if(type == Max) y=pic.scale.y.automax() ? tickMax(pic).y : pic.userMax().y; real Xmin=finite(xmin) ? xmin : pic.userMin().x; real Xmax=finite(xmax) ? xmax : pic.userMax().x; pair a=(Xmin,y); pair b=(Xmax,y); pair a2=(Xmin,y2); pair b2=(Xmax,y2); if(finite(a)) { pic.addPoint(a,min(p)); pic.addPoint(a,max(p)); } if(finite(b)) { pic.addPoint(b,min(p)); pic.addPoint(b,max(p)); } if(finite(a) && finite(b)) { frame d; ticks(d,pic.scaling(warn=false),L,side, (a.x,0)--(b.x,0),(a2.x,0)--(b2.x,0),p,arrow,margin, ticklocate(a.x,b.x,pic.scale.x),divisor,opposite); frame f; if(L.s != "") { Label L0=L.copy(); L0.position(0); add(f,L0); } pair pos=a+L.relative()*(b-a); pic.addBox(pos,pos,(min(f).x,min(d).y),(max(f).x,max(d).y)); } } // Process any queued y axis bound calculation requests. for(int i=0; i < pic.scale.y.bound.length; ++i) pic.scale.y.bound[i](); pic.scale.y.bound.delete(); bounds(); // Request another x bounds calculation before final picture scaling. pic.scale.x.bound.push(bounds); } // An internal routine to draw a y axis at a particular x value. void yaxisAt(picture pic=currentpicture, Label L="", axis axis, real ymin=-infinity, real ymax=infinity, pen p=currentpen, ticks ticks=NoTicks, arrowbar arrow=None, margin margin=NoMargin, bool above=true, bool opposite=false) { real x=axis.value; real x2; Label L=L.copy(); int[] divisor=copy(axis.ydivisor); pair side=axis.side; int type=axis.type; pic.add(new void (frame f, transform t, transform T, pair lb, pair rt) { transform tinv=inverse(t); pair a=ymin == -infinity ? tinv*(xtrans(t,x),lb.y-min(p).y) : (x,ymin); pair b=ymax == infinity ? tinv*(xtrans(t,x),rt.y-max(p).y) : (x,ymax); pair a2=ymin == -infinity ? tinv*(xtrans(t,x2),lb.y-min(p).y) : (x2,ymin); pair b2=ymax == infinity ? tinv*(xtrans(t,x2),rt.y-max(p).y) : (x2,ymax); if(ymin == -infinity || ymax == infinity) { bounds my=autoscale(a.y,b.y,pic.scale.y.scale); pic.scale.y.tickMin=my.min; pic.scale.y.tickMax=my.max; divisor=my.divisor; } real fuzz=epsilon*max(abs(a.y),abs(b.y)); a -= (0,fuzz); b += (0,fuzz); frame d; ticks(d,t,L,side,a--b,finite(x2) ? a2--b2 : nullpath,p,arrow,margin, ticklocate(a.y,b.y,pic.scale.y),divisor,opposite); (above ? add : prepend)(f,t*T*tinv*d); }); void bounds() { if(type == Both) { x2=pic.scale.x.automax() ? tickMax(pic).x : pic.userMax().x; x=opposite ? x2 : (pic.scale.x.automin() ? tickMin(pic).x : pic.userMin().x); } else if(type == Min) x=pic.scale.x.automin() ? tickMin(pic).x : pic.userMin().x; else if(type == Max) x=pic.scale.x.automax() ? tickMax(pic).x : pic.userMax().x; real Ymin=finite(ymin) ? ymin : pic.userMin().y; real Ymax=finite(ymax) ? ymax : pic.userMax().y; pair a=(x,Ymin); pair b=(x,Ymax); pair a2=(x2,Ymin); pair b2=(x2,Ymax); if(finite(a)) { pic.addPoint(a,min(p)); pic.addPoint(a,max(p)); } if(finite(b)) { pic.addPoint(b,min(p)); pic.addPoint(b,max(p)); } if(finite(a) && finite(b)) { frame d; ticks(d,pic.scaling(warn=false),L,side, (0,a.y)--(0,b.y),(0,a2.y)--(0,b2.y),p,arrow,margin, ticklocate(a.y,b.y,pic.scale.y),divisor,opposite); frame f; if(L.s != "") { Label L0=L.copy(); L0.position(0); add(f,L0); } pair pos=a+L.relative()*(b-a); pic.addBox(pos,pos,(min(d).x,min(f).y),(max(d).x,max(f).y)); } } // Process any queued x axis bound calculation requests. for(int i=0; i < pic.scale.x.bound.length; ++i) pic.scale.x.bound[i](); pic.scale.x.bound.delete(); bounds(); // Request another y bounds calculation before final picture scaling. pic.scale.y.bound.push(bounds); } // Set the x limits of a picture. void xlimits(picture pic=currentpicture, real min=-infinity, real max=infinity, bool crop=NoCrop) { if(min > max) return; pic.scale.x.automin=min <= -infinity; pic.scale.x.automax=max >= infinity; bounds mx; if(pic.scale.x.automin() || pic.scale.x.automax()) mx=autoscale(pic.userMin().x,pic.userMax().x,pic.scale.x.scale); if(pic.scale.x.automin) { if(pic.scale.x.automin()) pic.userMinx(mx.min); } else pic.userMinx(min(pic.scale.x.T(min),pic.scale.x.T(max))); if(pic.scale.x.automax) { if(pic.scale.x.automax()) pic.userMaxx(mx.max); } else pic.userMaxx(max(pic.scale.x.T(min),pic.scale.x.T(max))); if(crop) { pair userMin=pic.userMin(); pair userMax=pic.userMax(); pic.bounds.xclip(userMin.x,userMax.x); pic.clip(userMin, userMax, new void (frame f, transform t, transform T, pair, pair) { frame Tinvf=T == identity() ? f : t*inverse(T)*inverse(t)*f; clip(f,T*box(((t*userMin).x,(min(Tinvf)).y), ((t*userMax).x,(max(Tinvf)).y))); }); } } // Set the y limits of a picture. void ylimits(picture pic=currentpicture, real min=-infinity, real max=infinity, bool crop=NoCrop) { if(min > max) return; pic.scale.y.automin=min <= -infinity; pic.scale.y.automax=max >= infinity; bounds my; if(pic.scale.y.automin() || pic.scale.y.automax()) my=autoscale(pic.userMin().y,pic.userMax().y,pic.scale.y.scale); if(pic.scale.y.automin) { if(pic.scale.y.automin()) pic.userMiny(my.min); } else pic.userMiny(min(pic.scale.y.T(min),pic.scale.y.T(max))); if(pic.scale.y.automax) { if(pic.scale.y.automax()) pic.userMaxy(my.max); } else pic.userMaxy(max(pic.scale.y.T(min),pic.scale.y.T(max))); if(crop) { pair userMin=pic.userMin(); pair userMax=pic.userMax(); pic.bounds.yclip(userMin.y,userMax.y); pic.clip(userMin, userMax, new void (frame f, transform t, transform T, pair, pair) { frame Tinvf=T == identity() ? f : t*inverse(T)*inverse(t)*f; clip(f,T*box(((min(Tinvf)).x,(t*userMin).y), ((max(Tinvf)).x,(t*userMax).y))); }); } } // Crop a picture to the current user-space picture limits. void crop(picture pic=currentpicture) { xlimits(pic,false); ylimits(pic,false); if(pic.userSetx() && pic.userSety()) clip(pic,box(pic.userMin(),pic.userMax())); } // Restrict the x and y limits to box(min,max). void limits(picture pic=currentpicture, pair min, pair max, bool crop=NoCrop) { xlimits(pic,min.x,max.x); ylimits(pic,min.y,max.y); if(crop && pic.userSetx() && pic.userSety()) clip(pic,box(pic.userMin(),pic.userMax())); } // Internal routine to autoscale the user limits of a picture. void autoscale(picture pic=currentpicture, axis axis) { if(!pic.scale.set) { bounds mx,my; pic.scale.set=true; if(pic.userSetx()) { mx=autoscale(pic.userMin().x,pic.userMax().x,pic.scale.x.scale); if(pic.scale.x.scale.logarithmic && floor(pic.userMin().x) == floor(pic.userMax().x)) { if(pic.scale.x.automin()) pic.userMinx2(floor(pic.userMin().x)); if(pic.scale.x.automax()) pic.userMaxx2(ceil(pic.userMax().x)); } } else {mx.min=mx.max=0; pic.scale.set=false;} if(pic.userSety()) { my=autoscale(pic.userMin().y,pic.userMax().y,pic.scale.y.scale); if(pic.scale.y.scale.logarithmic && floor(pic.userMin().y) == floor(pic.userMax().y)) { if(pic.scale.y.automin()) pic.userMiny2(floor(pic.userMin().y)); if(pic.scale.y.automax()) pic.userMaxy2(ceil(pic.userMax().y)); } } else {my.min=my.max=0; pic.scale.set=false;} pic.scale.x.tickMin=mx.min; pic.scale.x.tickMax=mx.max; pic.scale.y.tickMin=my.min; pic.scale.y.tickMax=my.max; axis.xdivisor=mx.divisor; axis.ydivisor=my.divisor; } } // Draw an x axis. void xaxis(picture pic=currentpicture, Label L="", axis axis=YZero, real xmin=-infinity, real xmax=infinity, pen p=currentpen, ticks ticks=NoTicks, arrowbar arrow=None, margin margin=NoMargin, bool above=false) { if(xmin > xmax) return; if(pic.scale.x.automin && xmin > -infinity) pic.scale.x.automin=false; if(pic.scale.x.automax && xmax < infinity) pic.scale.x.automax=false; if(!pic.scale.set) { axis(pic,axis); autoscale(pic,axis); } Label L=L.copy(); bool newticks=false; if(xmin != -infinity) { xmin=pic.scale.x.T(xmin); newticks=true; } if(xmax != infinity) { xmax=pic.scale.x.T(xmax); newticks=true; } if(newticks && pic.userSetx() && ticks != NoTicks) { if(xmin == -infinity) xmin=pic.userMin().x; if(xmax == infinity) xmax=pic.userMax().x; bounds mx=autoscale(xmin,xmax,pic.scale.x.scale); pic.scale.x.tickMin=mx.min; pic.scale.x.tickMax=mx.max; axis.xdivisor=mx.divisor; } axis(pic,axis); if(xmin == -infinity && !axis.extend) { if(pic.scale.set) xmin=pic.scale.x.automin() ? pic.scale.x.tickMin : max(pic.scale.x.tickMin,pic.userMin().x); else xmin=pic.userMin().x; } if(xmax == infinity && !axis.extend) { if(pic.scale.set) xmax=pic.scale.x.automax() ? pic.scale.x.tickMax : min(pic.scale.x.tickMax,pic.userMax().x); else xmax=pic.userMax().x; } if(L.defaultposition) L.position(axis.position); L.align(L.align,axis.align); xaxisAt(pic,L,axis,xmin,xmax,p,ticks,arrow,margin,above); if(axis.type == Both) xaxisAt(pic,L,axis,xmin,xmax,p,ticks,arrow,margin,above,true); } // Draw a y axis. void yaxis(picture pic=currentpicture, Label L="", axis axis=XZero, real ymin=-infinity, real ymax=infinity, pen p=currentpen, ticks ticks=NoTicks, arrowbar arrow=None, margin margin=NoMargin, bool above=false, bool autorotate=true) { if(ymin > ymax) return; if(pic.scale.y.automin && ymin > -infinity) pic.scale.y.automin=false; if(pic.scale.y.automax && ymax < infinity) pic.scale.y.automax=false; if(!pic.scale.set) { axis(pic,axis); autoscale(pic,axis); } Label L=L.copy(); bool newticks=false; if(ymin != -infinity) { ymin=pic.scale.y.T(ymin); newticks=true; } if(ymax != infinity) { ymax=pic.scale.y.T(ymax); newticks=true; } if(newticks && pic.userSety() && ticks != NoTicks) { if(ymin == -infinity) ymin=pic.userMin().y; if(ymax == infinity) ymax=pic.userMax().y; bounds my=autoscale(ymin,ymax,pic.scale.y.scale); pic.scale.y.tickMin=my.min; pic.scale.y.tickMax=my.max; axis.ydivisor=my.divisor; } axis(pic,axis); if(ymin == -infinity && !axis.extend) { if(pic.scale.set) ymin=pic.scale.y.automin() ? pic.scale.y.tickMin : max(pic.scale.y.tickMin,pic.userMin().y); else ymin=pic.userMin().y; } if(ymax == infinity && !axis.extend) { if(pic.scale.set) ymax=pic.scale.y.automax() ? pic.scale.y.tickMax : min(pic.scale.y.tickMax,pic.userMax().y); else ymax=pic.userMax().y; } if(L.defaultposition) L.position(axis.position); L.align(L.align,axis.align); if(autorotate && L.defaulttransform) { frame f; add(f,Label(L.s,(0,0),L.p)); if(length(max(f)-min(f)) > ylabelwidth*fontsize(L.p)) L.transform(rotate(90)); } yaxisAt(pic,L,axis,ymin,ymax,p,ticks,arrow,margin,above); if(axis.type == Both) yaxisAt(pic,L,axis,ymin,ymax,p,ticks,arrow,margin,above,true); } // Draw x and y axes. void axes(picture pic=currentpicture, Label xlabel="", Label ylabel="", bool extend=true, pair min=(-infinity,-infinity), pair max=(infinity,infinity), pen p=currentpen, arrowbar arrow=None, margin margin=NoMargin, bool above=false) { xaxis(pic,xlabel,YZero(extend),min.x,max.x,p,arrow,margin,above); yaxis(pic,ylabel,XZero(extend),min.y,max.y,p,arrow,margin,above); } // Draw a yaxis at x. void xequals(picture pic=currentpicture, Label L="", real x, bool extend=false, real ymin=-infinity, real ymax=infinity, pen p=currentpen, ticks ticks=NoTicks, arrowbar arrow=None, margin margin=NoMargin, bool above=true) { yaxis(pic,L,XEquals(x,extend),ymin,ymax,p,ticks,arrow,margin,above); } // Draw an xaxis at y. void yequals(picture pic=currentpicture, Label L="", real y, bool extend=false, real xmin=-infinity, real xmax=infinity, pen p=currentpen, ticks ticks=NoTicks, arrowbar arrow=None, margin margin=NoMargin, bool above=true) { xaxis(pic,L,YEquals(y,extend),xmin,xmax,p,ticks,arrow,margin,above); } pair Scale(picture pic=currentpicture, pair z) { return (pic.scale.x.T(z.x),pic.scale.y.T(z.y)); } real ScaleX(picture pic=currentpicture, real x) { return pic.scale.x.T(x); } real ScaleY(picture pic=currentpicture, real y) { return pic.scale.y.T(y); } // Draw a tick of length size at pair z in direction dir using pen p. void tick(picture pic=currentpicture, pair z, pair dir, real size=Ticksize, pen p=currentpen) { pair z=Scale(pic,z); pic.add(new void (frame f, transform t) { pair tz=t*z; draw(f,tz--tz+unit(dir)*size,p); }); pic.addPoint(z,p); pic.addPoint(z,unit(dir)*size,p); } void xtick(picture pic=currentpicture, explicit pair z, pair dir=N, real size=Ticksize, pen p=currentpen) { tick(pic,z,dir,size,p); } void xtick(picture pic=currentpicture, real x, pair dir=N, real size=Ticksize, pen p=currentpen) { tick(pic,(x,pic.scale.y.scale.logarithmic ? 1 : 0),dir,size,p); } void ytick(picture pic=currentpicture, explicit pair z, pair dir=E, real size=Ticksize, pen p=currentpen) { tick(pic,z,dir,size,p); } void ytick(picture pic=currentpicture, real y, pair dir=E, real size=Ticksize, pen p=currentpen) { tick(pic,(pic.scale.x.scale.logarithmic ? 1 : 0,y),dir,size,p); } void tick(picture pic=currentpicture, Label L, real value, explicit pair z, pair dir, string format="", real size=Ticksize, pen p=currentpen) { Label L=L.copy(); L.position(Scale(pic,z)); L.align(L.align,-dir); if(shift(L.T)*0 == 0) L.T=shift(dot(dir,L.align.dir) > 0 ? dir*size : ticklabelshift(L.align.dir,p))*L.T; L.p(p); if(L.s == "") L.s=format(format == "" ? defaultformat : format,value); L.s=baseline(L.s,baselinetemplate); add(pic,L); tick(pic,z,dir,size,p); } void xtick(picture pic=currentpicture, Label L, explicit pair z, pair dir=N, string format="", real size=Ticksize, pen p=currentpen) { tick(pic,L,z.x,z,dir,format,size,p); } void xtick(picture pic=currentpicture, Label L, real x, pair dir=N, string format="", real size=Ticksize, pen p=currentpen) { xtick(pic,L,(x,pic.scale.y.scale.logarithmic ? 1 : 0),dir,size,p); } void ytick(picture pic=currentpicture, Label L, explicit pair z, pair dir=E, string format="", real size=Ticksize, pen p=currentpen) { tick(pic,L,z.y,z,dir,format,size,p); } void ytick(picture pic=currentpicture, Label L, real y, pair dir=E, string format="", real size=Ticksize, pen p=currentpen) { xtick(pic,L,(pic.scale.x.scale.logarithmic ? 1 : 0,y),dir,format,size,p); } private void label(picture pic, Label L, pair z, real x, align align, string format, pen p) { Label L=L.copy(); L.position(z); L.align(align); L.p(p); if(shift(L.T)*0 == 0) L.T=shift(ticklabelshift(L.align.dir,L.p))*L.T; if(L.s == "") L.s=format(format == "" ? defaultformat : format,x); L.s=baseline(L.s,baselinetemplate); add(pic,L); } // Put a label on the x axis. void labelx(picture pic=currentpicture, Label L="", explicit pair z, align align=S, string format="", pen p=currentpen) { label(pic,L,Scale(pic,z),z.x,align,format,p); } void labelx(picture pic=currentpicture, Label L="", real x, align align=S, string format="", pen p=currentpen) { labelx(pic,L,(x,pic.scale.y.scale.logarithmic ? 1 : 0),align,format,p); } void labelx(picture pic=currentpicture, Label L, string format="", explicit pen p=currentpen) { labelx(pic,L,L.position.position,format,p); } // Put a label on the y axis. void labely(picture pic=currentpicture, Label L="", explicit pair z, align align=W, string format="", pen p=currentpen) { label(pic,L,Scale(pic,z),z.y,align,format,p); } void labely(picture pic=currentpicture, Label L="", real y, align align=W, string format="", pen p=currentpen) { labely(pic,L,(pic.scale.x.scale.logarithmic ? 1 : 0,y),align,format,p); } void labely(picture pic=currentpicture, Label L, string format="", explicit pen p=currentpen) { labely(pic,L,L.position.position,format,p); } private string noprimary="Primary axis must be drawn before secondary axis"; // Construct a secondary X axis picture secondaryX(picture primary=currentpicture, void f(picture)) { if(!primary.scale.set) abort(noprimary); picture pic; size(pic,primary); if(primary.userMax().x == primary.userMin().x) return pic; f(pic); if(!pic.userSetx()) return pic; bounds a=autoscale(pic.userMin().x,pic.userMax().x,pic.scale.x.scale); real bmin=pic.scale.x.automin() ? a.min : pic.userMin().x; real bmax=pic.scale.x.automax() ? a.max : pic.userMax().x; real denom=bmax-bmin; if(denom != 0) { pic.erase(); real m=(primary.userMax().x-primary.userMin().x)/denom; pic.scale.x.postscale=Linear(m,bmin-primary.userMin().x/m); pic.scale.set=true; pic.scale.x.tickMin=pic.scale.x.postscale.T(a.min); pic.scale.x.tickMax=pic.scale.x.postscale.T(a.max); pic.scale.y.tickMin=primary.userMin().y; pic.scale.y.tickMax=primary.userMax().y; axis.xdivisor=a.divisor; f(pic); } pic.userCopy(primary); return pic; } // Construct a secondary Y axis picture secondaryY(picture primary=currentpicture, void f(picture)) { if(!primary.scale.set) abort(noprimary); picture pic; size(pic,primary); if(primary.userMax().y == primary.userMin().y) return pic; f(pic); if(!pic.userSety()) return pic; bounds a=autoscale(pic.userMin().y,pic.userMax().y,pic.scale.y.scale); real bmin=pic.scale.y.automin() ? a.min : pic.userMin().y; real bmax=pic.scale.y.automax() ? a.max : pic.userMax().y; real denom=bmax-bmin; if(denom != 0) { pic.erase(); real m=(primary.userMax().y-primary.userMin().y)/denom; pic.scale.y.postscale=Linear(m,bmin-primary.userMin().y/m); pic.scale.set=true; pic.scale.x.tickMin=primary.userMin().x; pic.scale.x.tickMax=primary.userMax().x; pic.scale.y.tickMin=pic.scale.y.postscale.T(a.min); pic.scale.y.tickMax=pic.scale.y.postscale.T(a.max); axis.ydivisor=a.divisor; f(pic); } pic.userCopy(primary); return pic; } typedef guide graph(pair f(real), real, real, int); typedef guide[] multigraph(pair f(real), real, real, int); graph graph(interpolate join) { return new guide(pair f(real), real a, real b, int n) { real width=b-a; return n == 0 ? join(f(a)) : join(...sequence(new guide(int i) {return f(a+(i/n)*width);},n+1)); }; } multigraph graph(interpolate join, bool3 cond(real)) { return new guide[](pair f(real), real a, real b, int n) { real width=b-a; if(n == 0) return new guide[] {join(cond(a) ? f(a) : nullpath)}; guide[] G; guide[] g; for(int i=0; i < n+1; ++i) { real t=a+(i/n)*width; bool3 b=cond(t); if(b) g.push(f(t)); else { if(g.length > 0) { G.push(join(...g)); g=new guide[] {}; } if(b == default) g.push(f(t)); } } if(g.length > 0) G.push(join(...g)); return G; }; } guide Straight(... guide[])=operator --; guide Spline(... guide[])=operator ..; interpolate Hermite(splinetype splinetype) { return new guide(... guide[] a) { int n=a.length; if(n == 0) return nullpath; real[] x,y; guide G; for(int i=0; i < n; ++i) { guide g=a[i]; int m=size(g); if(m == 0) continue; pair z=point(g,0); x.push(z.x); y.push(z.y); if(m > 1) { G=G..hermite(x,y,splinetype) & g; pair z=point(g,m); x=new real[] {z.x}; y=new real[] {z.y}; } } return G & hermite(x,y,splinetype); }; } interpolate Hermite=Hermite(Spline); guide graph(picture pic=currentpicture, real f(real), real a, real b, int n=ngraph, real T(real)=identity, interpolate join=operator --) { if(T == identity) return graph(join)(new pair(real x) { return (x,pic.scale.y.T(f(pic.scale.x.Tinv(x))));}, pic.scale.x.T(a),pic.scale.x.T(b),n); else return graph(join)(new pair(real x) { return Scale(pic,(T(x),f(T(x))));}, a,b,n); } guide[] graph(picture pic=currentpicture, real f(real), real a, real b, int n=ngraph, real T(real)=identity, bool3 cond(real), interpolate join=operator --) { if(T == identity) return graph(join,cond)(new pair(real x) { return (x,pic.scale.y.T(f(pic.scale.x.Tinv(x))));}, pic.scale.x.T(a),pic.scale.x.T(b),n); else return graph(join,cond)(new pair(real x) { return Scale(pic,(T(x),f(T(x))));}, a,b,n); } guide graph(picture pic=currentpicture, real x(real), real y(real), real a, real b, int n=ngraph, real T(real)=identity, interpolate join=operator --) { if(T == identity) return graph(join)(new pair(real t) {return Scale(pic,(x(t),y(t)));},a,b,n); else return graph(join)(new pair(real t) { return Scale(pic,(x(T(t)),y(T(t)))); },a,b,n); } guide[] graph(picture pic=currentpicture, real x(real), real y(real), real a, real b, int n=ngraph, real T(real)=identity, bool3 cond(real), interpolate join=operator --) { if(T == identity) return graph(join,cond)(new pair(real t) {return Scale(pic,(x(t),y(t)));}, a,b,n); else return graph(join,cond)(new pair(real t) { return Scale(pic,(x(T(t)),y(T(t))));}, a,b,n); } guide graph(picture pic=currentpicture, pair z(real), real a, real b, int n=ngraph, real T(real)=identity, interpolate join=operator --) { if(T == identity) return graph(join)(new pair(real t) {return Scale(pic,z(t));},a,b,n); else return graph(join)(new pair(real t) { return Scale(pic,z(T(t))); },a,b,n); } guide[] graph(picture pic=currentpicture, pair z(real), real a, real b, int n=ngraph, real T(real)=identity, bool3 cond(real), interpolate join=operator --) { if(T == identity) return graph(join,cond)(new pair(real t) {return Scale(pic,z(t));},a,b,n); else return graph(join,cond)(new pair(real t) { return Scale(pic,z(T(t))); },a,b,n); } string conditionlength="condition array has different length than data"; void checkconditionlength(int x, int y) { checklengths(x,y,conditionlength); } guide graph(picture pic=currentpicture, pair[] z, interpolate join=operator --) { int i=0; return graph(join)(new pair(real) { pair w=Scale(pic,z[i]); ++i; return w; },0,0,z.length-1); } guide[] graph(picture pic=currentpicture, pair[] z, bool3[] cond, interpolate join=operator --) { int n=z.length; int i=0; pair w; checkconditionlength(cond.length,n); bool3 condition(real) { bool3 b=cond[i]; if(b != false) w=Scale(pic,z[i]); ++i; return b; } return graph(join,condition)(new pair(real) {return w;},0,0,n-1); } guide graph(picture pic=currentpicture, real[] x, real[] y, interpolate join=operator --) { int n=x.length; checklengths(n,y.length); int i=0; return graph(join)(new pair(real) { pair w=Scale(pic,(x[i],y[i])); ++i; return w; },0,0,n-1); } guide[] graph(picture pic=currentpicture, real[] x, real[] y, bool3[] cond, interpolate join=operator --) { int n=x.length; checklengths(n,y.length); int i=0; pair w; checkconditionlength(cond.length,n); bool3 condition(real) { bool3 b=cond[i]; if(b != false) w=Scale(pic,(x[i],y[i])); ++i; return b; } return graph(join,condition)(new pair(real) {return w;},0,0,n-1); } // Connect points in z into segments corresponding to consecutive true elements // of b using interpolation operator join. path[] segment(pair[] z, bool[] cond, interpolate join=operator --) { checkconditionlength(cond.length,z.length); int[][] segment=segment(cond); return sequence(new path(int i) {return join(...z[segment[i]]);}, segment.length); } pair polar(real r, real theta) { return r*expi(theta); } guide polargraph(picture pic=currentpicture, real r(real), real a, real b, int n=ngraph, interpolate join=operator --) { return graph(join)(new pair(real theta) { return Scale(pic,polar(r(theta),theta)); },a,b,n); } guide polargraph(picture pic=currentpicture, real[] r, real[] theta, interpolate join=operator--) { int n=r.length; checklengths(n,theta.length); int i=0; return graph(join)(new pair(real) { pair w=Scale(pic,polar(r[i],theta[i])); ++i; return w; },0,0,n-1); } void errorbar(picture pic, pair z, pair dp, pair dm, pen p=currentpen, real size=0) { real dmx=-abs(dm.x); real dmy=-abs(dm.y); real dpx=abs(dp.x); real dpy=abs(dp.y); if(dmx != dpx) draw(pic,Scale(pic,z+(dmx,0))--Scale(pic,z+(dpx,0)),p, Bars(size)); if(dmy != dpy) draw(pic,Scale(pic,z+(0,dmy))--Scale(pic,z+(0,dpy)),p, Bars(size)); } void errorbars(picture pic=currentpicture, pair[] z, pair[] dp, pair[] dm={}, bool[] cond={}, pen p=currentpen, real size=0) { if(dm.length == 0) dm=dp; int n=z.length; checklengths(n,dm.length); checklengths(n,dp.length); bool all=cond.length == 0; if(!all) checkconditionlength(cond.length,n); for(int i=0; i < n; ++i) { if(all || cond[i]) errorbar(pic,z[i],dp[i],dm[i],p,size); } } void errorbars(picture pic=currentpicture, real[] x, real[] y, real[] dpx, real[] dpy, real[] dmx={}, real[] dmy={}, bool[] cond={}, pen p=currentpen, real size=0) { if(dmx.length == 0) dmx=dpx; if(dmy.length == 0) dmy=dpy; int n=x.length; checklengths(n,y.length); checklengths(n,dpx.length); checklengths(n,dpy.length); checklengths(n,dmx.length); checklengths(n,dmy.length); bool all=cond.length == 0; if(!all) checkconditionlength(cond.length,n); for(int i=0; i < n; ++i) { if(all || cond[i]) errorbar(pic,(x[i],y[i]),(dpx[i],dpy[i]),(dmx[i],dmy[i]),p,size); } } void errorbars(picture pic=currentpicture, real[] x, real[] y, real[] dpy, bool[] cond={}, pen p=currentpen, real size=0) { errorbars(pic,x,y,0*x,dpy,cond,p,size); } // Return a vector field on path g, specifying the vector as a function of the // relative position along path g in [0,1]. picture vectorfield(path vector(real), path g, int n, bool truesize=false, pen p=currentpen, arrowbar arrow=Arrow, margin margin=PenMargin) { picture pic; for(int i=0; i < n; ++i) { real x=(n == 1) ? 0.5 : i/(n-1); if(truesize) draw(relpoint(g,x),pic,vector(x),p,arrow); else draw(pic,shift(relpoint(g,x))*vector(x),p,arrow,margin); } return pic; } real maxlength(pair a, pair b, int nx, int ny) { return min((b.x-a.x)/nx,(b.y-a.y)/ny); } // return a vector field over box(a,b). picture vectorfield(path vector(pair), pair a, pair b, int nx=nmesh, int ny=nx, bool truesize=false, real maxlength=truesize ? 0 : maxlength(a,b,nx,ny), bool cond(pair z)=null, pen p=currentpen, arrowbar arrow=Arrow, margin margin=PenMargin) { picture pic; real dx=1/nx; real dy=1/ny; bool all=cond == null; real scale; if(maxlength > 0) { real size(pair z) { path g=vector(z); return abs(point(g,size(g)-1)-point(g,0)); } real max=size(a); for(int i=0; i <= nx; ++i) { real x=interp(a.x,b.x,i*dx); for(int j=0; j <= ny; ++j) max=max(max,size((x,interp(a.y,b.y,j*dy)))); } scale=max > 0 ? maxlength/max : 1; } else scale=1; for(int i=0; i <= nx; ++i) { real x=interp(a.x,b.x,i*dx); for(int j=0; j <= ny; ++j) { real y=interp(a.y,b.y,j*dy); pair z=(x,y); if(all || cond(z)) { path g=scale(scale)*vector(z); if(truesize) draw(z,pic,g,p,arrow); else draw(pic,shift(z)*g,p,arrow,margin); } } } return pic; } // True arc path Arc(pair c, real r, real angle1, real angle2, bool direction, int n=nCircle) { angle1=radians(angle1); angle2=radians(angle2); if(direction) { if(angle1 >= angle2) angle1 -= 2pi; } else if(angle2 >= angle1) angle2 -= 2pi; return shift(c)*polargraph(new real(real t){return r;},angle1,angle2,n, operator ..); } path Arc(pair c, real r, real angle1, real angle2, int n=nCircle) { return Arc(c,r,angle1,angle2,angle2 >= angle1 ? CCW : CW,n); } path Arc(pair c, explicit pair z1, explicit pair z2, bool direction=CCW, int n=nCircle) { return Arc(c,abs(z1-c),degrees(z1-c),degrees(z2-c),direction,n); } // True circle path Circle(pair c, real r, int n=nCircle) { return Arc(c,r,0,360,n)&cycle; } asymptote-2.37/base/graph3.asy000066400000000000000000001713571265434602500163330ustar00rootroot00000000000000// Three-dimensional graphing routines private import math; import graph; import three; triple zero3(real) {return O;} typedef triple direction3(real); direction3 Dir(triple dir) {return new triple(real) {return dir;};} ticklocate ticklocate(real a, real b, autoscaleT S=defaultS, real tickmin=-infinity, real tickmax=infinity, real time(real)=null, direction3 dir) { if((valuetime) time == null) time=linear(S.T(),a,b); ticklocate locate; locate.a=a; locate.b=b; locate.S=S.copy(); if(finite(tickmin)) locate.S.tickMin=tickmin; if(finite(tickmax)) locate.S.tickMax=tickmax; locate.time=time; locate.dir=zero; locate.dir3=dir; return locate; } private struct locateT { real t; // tick location time triple V; // tick location in frame coordinates triple pathdir; // path direction in frame coordinates triple dir; // tick direction in frame coordinates void dir(transform3 T, path3 g, ticklocate locate, real t) { pathdir=unit(shiftless(T)*dir(g,t)); triple Dir=locate.dir3(t); dir=unit(Dir); } // Locate the desired position of a tick along a path. void calc(transform3 T, path3 g, ticklocate locate, real val) { t=locate.time(val); V=T*point(g,t); dir(T,g,locate,t); } } void drawtick(picture pic, transform3 T, path3 g, path3 g2, ticklocate locate, real val, real Size, int sign, pen p, bool extend) { locateT locate1,locate2; locate1.calc(T,g,locate,val); path3 G; if(extend && size(g2) > 0) { locate2.calc(T,g2,locate,val); G=locate1.V--locate2.V; } else G=(sign == 0) ? locate1.V-Size*locate1.dir--locate1.V+Size*locate1.dir : locate1.V--locate1.V+Size*sign*locate1.dir; draw(pic,G,p,name="tick"); } triple ticklabelshift(triple align, pen p=currentpen) { return 0.25*unit(align)*labelmargin(p); } // Signature of routines that draw labelled paths with ticks and tick labels. typedef void ticks3(picture, transform3, Label, path3, path3, pen, arrowbar3, margin3, ticklocate, int[], bool opposite=false, bool primary=true); // Label a tick on a frame. void labeltick(picture pic, transform3 T, path3 g, ticklocate locate, real val, int sign, real Size, ticklabel ticklabel, Label F, real norm=0) { locateT locate1; locate1.calc(T,g,locate,val); triple align=F.align.dir3; if(align == O) align=sign*locate1.dir; triple shift=align*labelmargin(F.p); if(dot(align,sign*locate1.dir) >= 0) shift=sign*(Size)*locate1.dir; real label; if(locate.S.scale.logarithmic) label=locate.S.scale.Tinv(val); else { label=val; if(abs(label) < zerotickfuzz*norm) label=0; // Fix epsilon errors at +/-1e-4 // default format changes to scientific notation here if(abs(abs(label)-1e-4) < epsilon) label=sgn(label)*1e-4; } string s=ticklabel(label); triple v=locate1.V+shift; if(s != "") label(pic,F.defaulttransform3 ? baseline(s,baselinetemplate) : F.T3*s,v, align,F.p); } // Add axis label L to frame f. void labelaxis(picture pic, transform3 T, Label L, path3 g, ticklocate locate=null, int sign=1, bool ticklabels=false) { triple m=pic.min(identity4); triple M=pic.max(identity4); triple align=L.align.dir3; Label L=L.copy(); pic.add(new void(frame f, transform3 T, picture pic2, projection P) { path3 g=T*g; real t=relative(L,g); triple v=point(g,t); picture F; if(L.align.dir3 == O) align=unit(invert(L.align.dir,v,P))*abs(L.align.dir); if(ticklabels && locate != null && piecewisestraight(g)) { locateT locate1; locate1.dir(T,g,locate,t); triple pathdir=locate1.pathdir; triple perp=cross(pathdir,P.normal); if(align == O) align=unit(sgn(dot(sign*locate1.dir,perp))*perp); path[] g=project(box(T*m,T*M),P); pair z=project(v,P); pair Ppathdir=project(v+pathdir,P)-z; pair Perp=unit(I*Ppathdir); real angle=degrees(Ppathdir,warn=false); transform S=rotate(-angle,z); path[] G=S*g; pair Palign=project(v+align,P)-z; pair Align=rotate(-angle)*dot(Palign,Perp)*Perp; pair offset=unit(Palign)* abs((Align.y >= 0 ? max(G).y : (Align.y < 0 ? min(G).y : 0))-z.y); triple normal=cross(pathdir,align); if(normal != O) v=invert(z+offset,normal,v,P); } label(F,L,v); add(f,F.fit3(identity4,pic2,P)); },exact=false); path3[] G=path3(texpath(L,bbox=true)); if(G.length > 0) { G=L.align.is3D ? align(G,O,align,L.p) : L.T3*G; triple v=point(g,relative(L,g)); pic.addBox(v,v,min(G),max(G)); } } // Tick construction routine for a user-specified array of tick values. ticks3 Ticks3(int sign, Label F="", ticklabel ticklabel=null, bool beginlabel=true, bool endlabel=true, real[] Ticks=new real[], real[] ticks=new real[], int N=1, bool begin=true, bool end=true, real Size=0, real size=0, bool extend=false, pen pTick=nullpen, pen ptick=nullpen) { return new void(picture pic, transform3 t, Label L, path3 g, path3 g2, pen p, arrowbar3 arrow, margin3 margin, ticklocate locate, int[] divisor, bool opposite, bool primary) { // Use local copy of context variables: int Sign=opposite ? -1 : 1; int sign=Sign*sign; pen pTick=pTick; pen ptick=ptick; ticklabel ticklabel=ticklabel; real Size=Size; real size=size; if(Size == 0) Size=Ticksize; if(size == 0) size=ticksize; Label L=L.copy(); Label F=F.copy(); L.p(p); F.p(p); if(pTick == nullpen) pTick=p; if(ptick == nullpen) ptick=pTick; bool ticklabels=false; path3 G=t*g; path3 G2=t*g2; scalefcn T; real a,b; if(locate.S.scale.logarithmic) { a=locate.S.postscale.Tinv(locate.a); b=locate.S.postscale.Tinv(locate.b); T=locate.S.scale.T; } else { a=locate.S.Tinv(locate.a); b=locate.S.Tinv(locate.b); T=identity; } if(a > b) {real temp=a; a=b; b=temp;} real norm=max(abs(a),abs(b)); string format=autoformat(F.s,norm...Ticks); if(F.s == "%") F.s=""; if(ticklabel == null) { if(locate.S.scale.logarithmic) { int base=round(locate.S.scale.Tinv(1)); ticklabel=format == "%" ? Format("") : DefaultLogFormat(base); } else ticklabel=Format(format); } bool labelaxis=L.s != "" && primary; begingroup3(pic,"axis"); if(primary) draw(pic,margin(G,p).g,p,arrow); else draw(pic,G,p); for(int i=(begin ? 0 : 1); i < (end ? Ticks.length : Ticks.length-1); ++i) { real val=T(Ticks[i]); if(val >= a && val <= b) drawtick(pic,t,g,g2,locate,val,Size,sign,pTick,extend); } for(int i=0; i < ticks.length; ++i) { real val=T(ticks[i]); if(val >= a && val <= b) drawtick(pic,t,g,g2,locate,val,size,sign,ptick,extend); } if(N == 0) N=1; if(Size > 0 && primary) { for(int i=(beginlabel ? 0 : 1); i < (endlabel ? Ticks.length : Ticks.length-1); i += N) { real val=T(Ticks[i]); if(val >= a && val <= b) { ticklabels=true; labeltick(pic,t,g,locate,val,Sign,Size,ticklabel,F,norm); } } } if(labelaxis) labelaxis(pic,t,L,G,locate,Sign,ticklabels); endgroup3(pic); }; } // Automatic tick construction routine. ticks3 Ticks3(int sign, Label F="", ticklabel ticklabel=null, bool beginlabel=true, bool endlabel=true, int N, int n=0, real Step=0, real step=0, bool begin=true, bool end=true, tickmodifier modify=None, real Size=0, real size=0, bool extend=false, pen pTick=nullpen, pen ptick=nullpen) { return new void(picture pic, transform3 T, Label L, path3 g, path3 g2, pen p, arrowbar3 arrow, margin3 margin=NoMargin3, ticklocate locate, int[] divisor, bool opposite, bool primary) { path3 G=T*g; real limit=Step == 0 ? axiscoverage*arclength(G) : 0; tickvalues values=modify(generateticks(sign,F,ticklabel,N,n,Step,step, Size,size,identity(),1, project(G,currentprojection), limit,p,locate,divisor, opposite)); Ticks3(sign,F,ticklabel,beginlabel,endlabel,values.major,values.minor, values.N,begin,end,Size,size,extend,pTick,ptick) (pic,T,L,g,g2,p,arrow,margin,locate,divisor,opposite,primary); }; } ticks3 NoTicks3() { return new void(picture pic, transform3 T, Label L, path3 g, path3, pen p, arrowbar3 arrow, margin3 margin, ticklocate, int[], bool opposite, bool primary) { path3 G=T*g; if(primary) draw(pic,margin(G,p).g,p,arrow,margin); else draw(pic,G,p); if(L.s != "" && primary) { Label L=L.copy(); L.p(p); labelaxis(pic,T,L,G,opposite ? -1 : 1); } }; } ticks3 InTicks(Label format="", ticklabel ticklabel=null, bool beginlabel=true, bool endlabel=true, int N=0, int n=0, real Step=0, real step=0, bool begin=true, bool end=true, tickmodifier modify=None, real Size=0, real size=0, bool extend=false, pen pTick=nullpen, pen ptick=nullpen) { return Ticks3(-1,format,ticklabel,beginlabel,endlabel,N,n,Step,step, begin,end,modify,Size,size,extend,pTick,ptick); } ticks3 OutTicks(Label format="", ticklabel ticklabel=null, bool beginlabel=true, bool endlabel=true, int N=0, int n=0, real Step=0, real step=0, bool begin=true, bool end=true, tickmodifier modify=None, real Size=0, real size=0, bool extend=false, pen pTick=nullpen, pen ptick=nullpen) { return Ticks3(1,format,ticklabel,beginlabel,endlabel,N,n,Step,step, begin,end,modify,Size,size,extend,pTick,ptick); } ticks3 InOutTicks(Label format="", ticklabel ticklabel=null, bool beginlabel=true, bool endlabel=true, int N=0, int n=0, real Step=0, real step=0, bool begin=true, bool end=true, tickmodifier modify=None, real Size=0, real size=0, bool extend=false, pen pTick=nullpen, pen ptick=nullpen) { return Ticks3(0,format,ticklabel,beginlabel,endlabel,N,n,Step,step, begin,end,modify,Size,size,extend,pTick,ptick); } ticks3 InTicks(Label format="", ticklabel ticklabel=null, bool beginlabel=true, bool endlabel=true, real[] Ticks, real[] ticks=new real[], real Size=0, real size=0, bool extend=false, pen pTick=nullpen, pen ptick=nullpen) { return Ticks3(-1,format,ticklabel,beginlabel,endlabel, Ticks,ticks,Size,size,extend,pTick,ptick); } ticks3 OutTicks(Label format="", ticklabel ticklabel=null, bool beginlabel=true, bool endlabel=true, real[] Ticks, real[] ticks=new real[], real Size=0, real size=0, bool extend=false, pen pTick=nullpen, pen ptick=nullpen) { return Ticks3(1,format,ticklabel,beginlabel,endlabel, Ticks,ticks,Size,size,extend,pTick,ptick); } ticks3 InOutTicks(Label format="", ticklabel ticklabel=null, bool beginlabel=true, bool endlabel=true, real[] Ticks, real[] ticks=new real[], real Size=0, real size=0, bool extend=false, pen pTick=nullpen, pen ptick=nullpen) { return Ticks3(0,format,ticklabel,beginlabel,endlabel, Ticks,ticks,Size,size,extend,pTick,ptick); } ticks3 NoTicks3=NoTicks3(), InTicks=InTicks(), OutTicks=OutTicks(), InOutTicks=InOutTicks(); triple tickMin3(picture pic) { return minbound(pic.userMin(),(pic.scale.x.tickMin,pic.scale.y.tickMin, pic.scale.z.tickMin)); } triple tickMax3(picture pic) { return maxbound(pic.userMax(),(pic.scale.x.tickMax,pic.scale.y.tickMax, pic.scale.z.tickMax)); } axis Bounds(int type=Both, int type2=Both, triple align=O, bool extend=false) { return new void(picture pic, axisT axis) { axis.type=type; axis.type2=type2; axis.position=0.5; axis.align=align; axis.extend=extend; }; } axis YZEquals(real y, real z, triple align=O, bool extend=false) { return new void(picture pic, axisT axis) { axis.type=Value; axis.type2=Value; axis.value=pic.scale.y.T(y); axis.value2=pic.scale.z.T(z); axis.position=1; axis.align=align; axis.extend=extend; }; } axis XZEquals(real x, real z, triple align=O, bool extend=false) { return new void(picture pic, axisT axis) { axis.type=Value; axis.type2=Value; axis.value=pic.scale.x.T(x); axis.value2=pic.scale.z.T(z); axis.position=1; axis.align=align; axis.extend=extend; }; } axis XYEquals(real x, real y, triple align=O, bool extend=false) { return new void(picture pic, axisT axis) { axis.type=Value; axis.type2=Value; axis.value=pic.scale.x.T(x); axis.value2=pic.scale.y.T(y); axis.position=1; axis.align=align; axis.extend=extend; }; } axis YZZero(triple align=O, bool extend=false) { return new void(picture pic, axisT axis) { axis.type=Value; axis.type2=Value; axis.value=pic.scale.y.T(pic.scale.y.scale.logarithmic ? 1 : 0); axis.value2=pic.scale.z.T(pic.scale.z.scale.logarithmic ? 1 : 0); axis.position=1; axis.align=align; axis.extend=extend; }; } axis XZZero(triple align=O, bool extend=false) { return new void(picture pic, axisT axis) { axis.type=Value; axis.type2=Value; axis.value=pic.scale.x.T(pic.scale.x.scale.logarithmic ? 1 : 0); axis.value2=pic.scale.z.T(pic.scale.z.scale.logarithmic ? 1 : 0); axis.position=1; axis.align=align; axis.extend=extend; }; } axis XYZero(triple align=O, bool extend=false) { return new void(picture pic, axisT axis) { axis.type=Value; axis.type2=Value; axis.value=pic.scale.x.T(pic.scale.x.scale.logarithmic ? 1 : 0); axis.value2=pic.scale.y.T(pic.scale.y.scale.logarithmic ? 1 : 0); axis.position=1; axis.align=align; axis.extend=extend; }; } axis Bounds=Bounds(), YZZero=YZZero(), XZZero=XZZero(), XYZero=XYZero(); // Draw a general three-dimensional axis. void axis(picture pic=currentpicture, Label L="", path3 g, path3 g2=nullpath3, pen p=currentpen, ticks3 ticks, ticklocate locate, arrowbar3 arrow=None, margin3 margin=NoMargin3, int[] divisor=new int[], bool above=false, bool opposite=false) { Label L=L.copy(); real t=reltime(g,0.5); if(L.defaultposition) L.position(t); divisor=copy(divisor); locate=locate.copy(); pic.add(new void (picture f, transform3 t, transform3 T, triple, triple) { picture d; ticks(d,t,L,g,g2,p,arrow,margin,locate,divisor,opposite,true); add(f,t*T*inverse(t)*d); },above=above); addPath(pic,g,p); if(L.s != "") { frame f; Label L0=L.copy(); L0.position(0); add(f,L0); triple pos=point(g,L.relative()*length(g)); pic.addBox(pos,pos,min3(f),max3(f)); } } real xtrans(transform3 t, real x) { return (t*(x,0,0)).x; } real ytrans(transform3 t, real y) { return (t*(0,y,0)).y; } real ztrans(transform3 t, real z) { return (t*(0,0,z)).z; } private triple defaultdir(triple X, triple Y, triple Z, bool opposite=false, projection P) { triple u=cross(P.normal,Z); return abs(dot(u,X)) > abs(dot(u,Y)) ? -X : (opposite ? Y : -Y); } // An internal routine to draw an x axis at a particular y value. void xaxis3At(picture pic=currentpicture, Label L="", axis axis, real xmin=-infinity, real xmax=infinity, pen p=currentpen, ticks3 ticks=NoTicks3, arrowbar3 arrow=None, margin3 margin=NoMargin3, bool above=true, bool opposite=false, bool opposite2=false, bool primary=true) { int type=axis.type; int type2=axis.type2; triple dir=axis.align.dir3 == O ? defaultdir(Y,Z,X,opposite^opposite2,currentprojection) : axis.align.dir3; Label L=L.copy(); if(L.align.dir3 == O && L.align.dir == 0) L.align(opposite ? -dir : dir); real y=axis.value; real z=axis.value2; real y2,z2; int[] divisor=copy(axis.xdivisor); pic.add(new void(picture f, transform3 t, transform3 T, triple lb, triple rt) { transform3 tinv=inverse(t); triple a=xmin == -infinity ? tinv*(lb.x-min3(p).x,ytrans(t,y), ztrans(t,z)) : (xmin,y,z); triple b=xmax == infinity ? tinv*(rt.x-max3(p).x,ytrans(t,y), ztrans(t,z)) : (xmax,y,z); real y0; real z0; if(abs(dir.y) < abs(dir.z)) { y0=y; z0=z2; } else { y0=y2; z0=z; } triple a2=xmin == -infinity ? tinv*(lb.x-min3(p).x,ytrans(t,y0), ztrans(t,z0)) : (xmin,y0,z0); triple b2=xmax == infinity ? tinv*(rt.x-max3(p).x,ytrans(t,y0), ztrans(t,z0)) : (xmax,y0,z0); if(xmin == -infinity || xmax == infinity) { bounds mx=autoscale(a.x,b.x,pic.scale.x.scale); pic.scale.x.tickMin=mx.min; pic.scale.x.tickMax=mx.max; divisor=mx.divisor; } triple fuzz=X*epsilon*max(abs(a.x),abs(b.x)); a -= fuzz; b += fuzz; picture d; ticks(d,t,L,a--b,finite(y0) && finite(z0) ? a2--b2 : nullpath3, p,arrow,margin, ticklocate(a.x,b.x,pic.scale.x,Dir(dir)),divisor, opposite,primary); add(f,t*T*tinv*d); },above=above); void bounds() { if(type == Min) y=pic.scale.y.automin() ? tickMin3(pic).y : pic.userMin().y; else if(type == Max) y=pic.scale.y.automax() ? tickMax3(pic).y : pic.userMax().y; else if(type == Both) { y2=pic.scale.y.automax() ? tickMax3(pic).y : pic.userMax().y; y=opposite ? y2 : (pic.scale.y.automin() ? tickMin3(pic).y : pic.userMin().y); } if(type2 == Min) z=pic.scale.z.automin() ? tickMin3(pic).z : pic.userMin().z; else if(type2 == Max) z=pic.scale.z.automax() ? tickMax3(pic).z : pic.userMax().z; else if(type2 == Both) { z2=pic.scale.z.automax() ? tickMax3(pic).z : pic.userMax().z; z=opposite2 ? z2 : (pic.scale.z.automin() ? tickMin3(pic).z : pic.userMin().z); } real Xmin=finite(xmin) ? xmin : pic.userMin().x; real Xmax=finite(xmax) ? xmax : pic.userMax().x; triple a=(Xmin,y,z); triple b=(Xmax,y,z); triple a2=(Xmin,y2,z2); triple b2=(Xmax,y2,z2); if(finite(a)) { pic.addPoint(a,min3(p)); pic.addPoint(a,max3(p)); } if(finite(b)) { pic.addPoint(b,min3(p)); pic.addPoint(b,max3(p)); } if(finite(a) && finite(b)) { picture d; ticks(d,pic.scaling3(warn=false),L, (a.x,0,0)--(b.x,0,0),(a2.x,0,0)--(b2.x,0,0),p,arrow,margin, ticklocate(a.x,b.x,pic.scale.x,Dir(dir)),divisor, opposite,primary); frame f; if(L.s != "") { Label L0=L.copy(); L0.position(0); add(f,L0); } triple pos=a+L.relative()*(b-a); triple m=min3(d); triple M=max3(d); pic.addBox(pos,pos,(min3(f).x,m.y,m.z),(max3(f).x,m.y,m.z)); } } // Process any queued y and z axes bound calculation requests. for(int i=0; i < pic.scale.y.bound.length; ++i) pic.scale.y.bound[i](); for(int i=0; i < pic.scale.z.bound.length; ++i) pic.scale.z.bound[i](); pic.scale.y.bound.delete(); pic.scale.z.bound.delete(); bounds(); // Request another x bounds calculation before final picture scaling. pic.scale.x.bound.push(bounds); } // An internal routine to draw an x axis at a particular y value. void yaxis3At(picture pic=currentpicture, Label L="", axis axis, real ymin=-infinity, real ymax=infinity, pen p=currentpen, ticks3 ticks=NoTicks3, arrowbar3 arrow=None, margin3 margin=NoMargin3, bool above=true, bool opposite=false, bool opposite2=false, bool primary=true) { int type=axis.type; int type2=axis.type2; triple dir=axis.align.dir3 == O ? defaultdir(X,Z,Y,opposite^opposite2,currentprojection) : axis.align.dir3; Label L=L.copy(); if(L.align.dir3 == O && L.align.dir == 0) L.align(opposite ? -dir : dir); real x=axis.value; real z=axis.value2; real x2,z2; int[] divisor=copy(axis.ydivisor); pic.add(new void(picture f, transform3 t, transform3 T, triple lb, triple rt) { transform3 tinv=inverse(t); triple a=ymin == -infinity ? tinv*(xtrans(t,x),lb.y-min3(p).y, ztrans(t,z)) : (x,ymin,z); triple b=ymax == infinity ? tinv*(xtrans(t,x),rt.y-max3(p).y, ztrans(t,z)) : (x,ymax,z); real x0; real z0; if(abs(dir.x) < abs(dir.z)) { x0=x; z0=z2; } else { x0=x2; z0=z; } triple a2=ymin == -infinity ? tinv*(xtrans(t,x0),lb.y-min3(p).y, ztrans(t,z0)) : (x0,ymin,z0); triple b2=ymax == infinity ? tinv*(xtrans(t,x0),rt.y-max3(p).y, ztrans(t,z0)) : (x0,ymax,z0); if(ymin == -infinity || ymax == infinity) { bounds my=autoscale(a.y,b.y,pic.scale.y.scale); pic.scale.y.tickMin=my.min; pic.scale.y.tickMax=my.max; divisor=my.divisor; } triple fuzz=Y*epsilon*max(abs(a.y),abs(b.y)); a -= fuzz; b += fuzz; picture d; ticks(d,t,L,a--b,finite(x0) && finite(z0) ? a2--b2 : nullpath3, p,arrow,margin, ticklocate(a.y,b.y,pic.scale.y,Dir(dir)),divisor, opposite,primary); add(f,t*T*tinv*d); },above=above); void bounds() { if(type == Min) x=pic.scale.x.automin() ? tickMin3(pic).x : pic.userMin().x; else if(type == Max) x=pic.scale.x.automax() ? tickMax3(pic).x : pic.userMax().x; else if(type == Both) { x2=pic.scale.x.automax() ? tickMax3(pic).x : pic.userMax().x; x=opposite ? x2 : (pic.scale.x.automin() ? tickMin3(pic).x : pic.userMin().x); } if(type2 == Min) z=pic.scale.z.automin() ? tickMin3(pic).z : pic.userMin().z; else if(type2 == Max) z=pic.scale.z.automax() ? tickMax3(pic).z : pic.userMax().z; else if(type2 == Both) { z2=pic.scale.z.automax() ? tickMax3(pic).z : pic.userMax().z; z=opposite2 ? z2 : (pic.scale.z.automin() ? tickMin3(pic).z : pic.userMin().z); } real Ymin=finite(ymin) ? ymin : pic.userMin().y; real Ymax=finite(ymax) ? ymax : pic.userMax().y; triple a=(x,Ymin,z); triple b=(x,Ymax,z); triple a2=(x2,Ymin,z2); triple b2=(x2,Ymax,z2); if(finite(a)) { pic.addPoint(a,min3(p)); pic.addPoint(a,max3(p)); } if(finite(b)) { pic.addPoint(b,min3(p)); pic.addPoint(b,max3(p)); } if(finite(a) && finite(b)) { picture d; ticks(d,pic.scaling3(warn=false),L, (0,a.y,0)--(0,b.y,0),(0,a2.y,0)--(0,a2.y,0),p,arrow,margin, ticklocate(a.y,b.y,pic.scale.y,Dir(dir)),divisor, opposite,primary); frame f; if(L.s != "") { Label L0=L.copy(); L0.position(0); add(f,L0); } triple pos=a+L.relative()*(b-a); triple m=min3(d); triple M=max3(d); pic.addBox(pos,pos,(m.x,min3(f).y,m.z),(m.x,max3(f).y,m.z)); } } // Process any queued x and z axis bound calculation requests. for(int i=0; i < pic.scale.x.bound.length; ++i) pic.scale.x.bound[i](); for(int i=0; i < pic.scale.z.bound.length; ++i) pic.scale.z.bound[i](); pic.scale.x.bound.delete(); pic.scale.z.bound.delete(); bounds(); // Request another y bounds calculation before final picture scaling. pic.scale.y.bound.push(bounds); } // An internal routine to draw an x axis at a particular y value. void zaxis3At(picture pic=currentpicture, Label L="", axis axis, real zmin=-infinity, real zmax=infinity, pen p=currentpen, ticks3 ticks=NoTicks3, arrowbar3 arrow=None, margin3 margin=NoMargin3, bool above=true, bool opposite=false, bool opposite2=false, bool primary=true) { int type=axis.type; int type2=axis.type2; triple dir=axis.align.dir3 == O ? defaultdir(X,Y,Z,opposite^opposite2,currentprojection) : axis.align.dir3; Label L=L.copy(); if(L.align.dir3 == O && L.align.dir == 0) L.align(opposite ? -dir : dir); real x=axis.value; real y=axis.value2; real x2,y2; int[] divisor=copy(axis.zdivisor); pic.add(new void(picture f, transform3 t, transform3 T, triple lb, triple rt) { transform3 tinv=inverse(t); triple a=zmin == -infinity ? tinv*(xtrans(t,x),ytrans(t,y), lb.z-min3(p).z) : (x,y,zmin); triple b=zmax == infinity ? tinv*(xtrans(t,x),ytrans(t,y), rt.z-max3(p).z) : (x,y,zmax); real x0; real y0; if(abs(dir.x) < abs(dir.y)) { x0=x; y0=y2; } else { x0=x2; y0=y; } triple a2=zmin == -infinity ? tinv*(xtrans(t,x0),ytrans(t,y0), lb.z-min3(p).z) : (x0,y0,zmin); triple b2=zmax == infinity ? tinv*(xtrans(t,x0),ytrans(t,y0), rt.z-max3(p).z) : (x0,y0,zmax); if(zmin == -infinity || zmax == infinity) { bounds mz=autoscale(a.z,b.z,pic.scale.z.scale); pic.scale.z.tickMin=mz.min; pic.scale.z.tickMax=mz.max; divisor=mz.divisor; } triple fuzz=Z*epsilon*max(abs(a.z),abs(b.z)); a -= fuzz; b += fuzz; picture d; ticks(d,t,L,a--b,finite(x0) && finite(y0) ? a2--b2 : nullpath3, p,arrow,margin, ticklocate(a.z,b.z,pic.scale.z,Dir(dir)),divisor, opposite,primary); add(f,t*T*tinv*d); },above=above); void bounds() { if(type == Min) x=pic.scale.x.automin() ? tickMin3(pic).x : pic.userMin().x; else if(type == Max) x=pic.scale.x.automax() ? tickMax3(pic).x : pic.userMax().x; else if(type == Both) { x2=pic.scale.x.automax() ? tickMax3(pic).x : pic.userMax().x; x=opposite ? x2 : (pic.scale.x.automin() ? tickMin3(pic).x : pic.userMin().x); } if(type2 == Min) y=pic.scale.y.automin() ? tickMin3(pic).y : pic.userMin().y; else if(type2 == Max) y=pic.scale.y.automax() ? tickMax3(pic).y : pic.userMax().y; else if(type2 == Both) { y2=pic.scale.y.automax() ? tickMax3(pic).y : pic.userMax().y; y=opposite2 ? y2 : (pic.scale.y.automin() ? tickMin3(pic).y : pic.userMin().y); } real Zmin=finite(zmin) ? zmin : pic.userMin().z; real Zmax=finite(zmax) ? zmax : pic.userMax().z; triple a=(x,y,Zmin); triple b=(x,y,Zmax); triple a2=(x2,y2,Zmin); triple b2=(x2,y2,Zmax); if(finite(a)) { pic.addPoint(a,min3(p)); pic.addPoint(a,max3(p)); } if(finite(b)) { pic.addPoint(b,min3(p)); pic.addPoint(b,max3(p)); } if(finite(a) && finite(b)) { picture d; ticks(d,pic.scaling3(warn=false),L, (0,0,a.z)--(0,0,b.z),(0,0,a2.z)--(0,0,a2.z),p,arrow,margin, ticklocate(a.z,b.z,pic.scale.z,Dir(dir)),divisor, opposite,primary); frame f; if(L.s != "") { Label L0=L.copy(); L0.position(0); add(f,L0); } triple pos=a+L.relative()*(b-a); triple m=min3(d); triple M=max3(d); pic.addBox(pos,pos,(m.x,m.y,min3(f).z),(m.x,m.y,max3(f).z)); } } // Process any queued x and y axes bound calculation requests. for(int i=0; i < pic.scale.x.bound.length; ++i) pic.scale.x.bound[i](); for(int i=0; i < pic.scale.y.bound.length; ++i) pic.scale.y.bound[i](); pic.scale.x.bound.delete(); pic.scale.y.bound.delete(); bounds(); // Request another z bounds calculation before final picture scaling. pic.scale.z.bound.push(bounds); } // Internal routine to autoscale the user limits of a picture. void autoscale3(picture pic=currentpicture, axis axis) { bool set=pic.scale.set; autoscale(pic,axis); if(!set) { bounds mz; if(pic.userSetz()) { mz=autoscale(pic.userMin().z,pic.userMax().z,pic.scale.z.scale); if(pic.scale.z.scale.logarithmic && floor(pic.userMin().z) == floor(pic.userMax().z)) { if(pic.scale.z.automin()) pic.userMinz3(floor(pic.userMin().z)); if(pic.scale.z.automax()) pic.userMaxz3(ceil(pic.userMax().z)); } } else {mz.min=mz.max=0; pic.scale.set=false;} pic.scale.z.tickMin=mz.min; pic.scale.z.tickMax=mz.max; axis.zdivisor=mz.divisor; } } // Draw an x axis in three dimensions. void xaxis3(picture pic=currentpicture, Label L="", axis axis=YZZero, real xmin=-infinity, real xmax=infinity, pen p=currentpen, ticks3 ticks=NoTicks3, arrowbar3 arrow=None, margin3 margin=NoMargin3, bool above=false) { if(xmin > xmax) return; if(pic.scale.x.automin && xmin > -infinity) pic.scale.x.automin=false; if(pic.scale.x.automax && xmax < infinity) pic.scale.x.automax=false; if(!pic.scale.set) { axis(pic,axis); autoscale3(pic,axis); } bool newticks=false; if(xmin != -infinity) { xmin=pic.scale.x.T(xmin); newticks=true; } if(xmax != infinity) { xmax=pic.scale.x.T(xmax); newticks=true; } if(newticks && pic.userSetx() && ticks != NoTicks3) { if(xmin == -infinity) xmin=pic.userMin().x; if(xmax == infinity) xmax=pic.userMax().x; bounds mx=autoscale(xmin,xmax,pic.scale.x.scale); pic.scale.x.tickMin=mx.min; pic.scale.x.tickMax=mx.max; axis.xdivisor=mx.divisor; } axis(pic,axis); if(xmin == -infinity && !axis.extend) { if(pic.scale.set) xmin=pic.scale.x.automin() ? pic.scale.x.tickMin : max(pic.scale.x.tickMin,pic.userMin().x); else xmin=pic.userMin().x; } if(xmax == infinity && !axis.extend) { if(pic.scale.set) xmax=pic.scale.x.automax() ? pic.scale.x.tickMax : min(pic.scale.x.tickMax,pic.userMax().x); else xmax=pic.userMax().x; } if(L.defaultposition) { L=L.copy(); L.position(axis.position); } bool back=false; if(axis.type == Both) { triple v=currentprojection.normal; back=dot((0,pic.userMax().y-pic.userMin().y,0),v)*sgn(v.z) > 0; } xaxis3At(pic,L,axis,xmin,xmax,p,ticks,arrow,margin,above,false,false,!back); if(axis.type == Both) xaxis3At(pic,L,axis,xmin,xmax,p,ticks,arrow,margin,above,true,false,back); if(axis.type2 == Both) { xaxis3At(pic,L,axis,xmin,xmax,p,ticks,arrow,margin,above,false,true,false); if(axis.type == Both) xaxis3At(pic,L,axis,xmin,xmax,p,ticks,arrow,margin,above,true,true,false); } } // Draw a y axis in three dimensions. void yaxis3(picture pic=currentpicture, Label L="", axis axis=XZZero, real ymin=-infinity, real ymax=infinity, pen p=currentpen, ticks3 ticks=NoTicks3, arrowbar3 arrow=None, margin3 margin=NoMargin3, bool above=false) { if(ymin > ymax) return; if(pic.scale.y.automin && ymin > -infinity) pic.scale.y.automin=false; if(pic.scale.y.automax && ymax < infinity) pic.scale.y.automax=false; if(!pic.scale.set) { axis(pic,axis); autoscale3(pic,axis); } bool newticks=false; if(ymin != -infinity) { ymin=pic.scale.y.T(ymin); newticks=true; } if(ymax != infinity) { ymax=pic.scale.y.T(ymax); newticks=true; } if(newticks && pic.userSety() && ticks != NoTicks3) { if(ymin == -infinity) ymin=pic.userMin().y; if(ymax == infinity) ymax=pic.userMax().y; bounds my=autoscale(ymin,ymax,pic.scale.y.scale); pic.scale.y.tickMin=my.min; pic.scale.y.tickMax=my.max; axis.ydivisor=my.divisor; } axis(pic,axis); if(ymin == -infinity && !axis.extend) { if(pic.scale.set) ymin=pic.scale.y.automin() ? pic.scale.y.tickMin : max(pic.scale.y.tickMin,pic.userMin().y); else ymin=pic.userMin().y; } if(ymax == infinity && !axis.extend) { if(pic.scale.set) ymax=pic.scale.y.automax() ? pic.scale.y.tickMax : min(pic.scale.y.tickMax,pic.userMax().y); else ymax=pic.userMax().y; } if(L.defaultposition) { L=L.copy(); L.position(axis.position); } bool back=false; if(axis.type == Both) { triple v=currentprojection.normal; back=dot((pic.userMax().x-pic.userMin().x,0,0),v)*sgn(v.z) > 0; } yaxis3At(pic,L,axis,ymin,ymax,p,ticks,arrow,margin,above,false,false,!back); if(axis.type == Both) yaxis3At(pic,L,axis,ymin,ymax,p,ticks,arrow,margin,above,true,false,back); if(axis.type2 == Both) { yaxis3At(pic,L,axis,ymin,ymax,p,ticks,arrow,margin,above,false,true,false); if(axis.type == Both) yaxis3At(pic,L,axis,ymin,ymax,p,ticks,arrow,margin,above,true,true,false); } } // Draw a z axis in three dimensions. void zaxis3(picture pic=currentpicture, Label L="", axis axis=XYZero, real zmin=-infinity, real zmax=infinity, pen p=currentpen, ticks3 ticks=NoTicks3, arrowbar3 arrow=None, margin3 margin=NoMargin3, bool above=false) { if(zmin > zmax) return; if(pic.scale.z.automin && zmin > -infinity) pic.scale.z.automin=false; if(pic.scale.z.automax && zmax < infinity) pic.scale.z.automax=false; if(!pic.scale.set) { axis(pic,axis); autoscale3(pic,axis); } bool newticks=false; if(zmin != -infinity) { zmin=pic.scale.z.T(zmin); newticks=true; } if(zmax != infinity) { zmax=pic.scale.z.T(zmax); newticks=true; } if(newticks && pic.userSetz() && ticks != NoTicks3) { if(zmin == -infinity) zmin=pic.userMin().z; if(zmax == infinity) zmax=pic.userMax().z; bounds mz=autoscale(zmin,zmax,pic.scale.z.scale); pic.scale.z.tickMin=mz.min; pic.scale.z.tickMax=mz.max; axis.zdivisor=mz.divisor; } axis(pic,axis); if(zmin == -infinity && !axis.extend) { if(pic.scale.set) zmin=pic.scale.z.automin() ? pic.scale.z.tickMin : max(pic.scale.z.tickMin,pic.userMin().z); else zmin=pic.userMin().z; } if(zmax == infinity && !axis.extend) { if(pic.scale.set) zmax=pic.scale.z.automax() ? pic.scale.z.tickMax : min(pic.scale.z.tickMax,pic.userMax().z); else zmax=pic.userMax().z; } if(L.defaultposition) { L=L.copy(); L.position(axis.position); } bool back=false; if(axis.type == Both) { triple v=currentprojection.vector(); back=dot((pic.userMax().x-pic.userMin().x,0,0),v)*sgn(v.y) > 0; } zaxis3At(pic,L,axis,zmin,zmax,p,ticks,arrow,margin,above,false,false,!back); if(axis.type == Both) zaxis3At(pic,L,axis,zmin,zmax,p,ticks,arrow,margin,above,true,false,back); if(axis.type2 == Both) { zaxis3At(pic,L,axis,zmin,zmax,p,ticks,arrow,margin,above,false,true,false); if(axis.type == Both) zaxis3At(pic,L,axis,zmin,zmax,p,ticks,arrow,margin,above,true,true,false); } } // Set the z limits of a picture. void zlimits(picture pic=currentpicture, real min=-infinity, real max=infinity, bool crop=NoCrop) { if(min > max) return; pic.scale.z.automin=min <= -infinity; pic.scale.z.automax=max >= infinity; bounds mz; if(pic.scale.z.automin() || pic.scale.z.automax()) mz=autoscale(pic.userMin().z,pic.userMax().z,pic.scale.z.scale); if(pic.scale.z.automin) { if(pic.scale.z.automin()) pic.userMinz(mz.min); } else pic.userMinz(min(pic.scale.z.T(min),pic.scale.z.T(max))); if(pic.scale.z.automax) { if(pic.scale.z.automax()) pic.userMaxz(mz.max); } else pic.userMaxz(max(pic.scale.z.T(min),pic.scale.z.T(max))); } // Restrict the x, y, and z limits to box(min,max). void limits(picture pic=currentpicture, triple min, triple max) { xlimits(pic,min.x,max.x); ylimits(pic,min.y,max.y); zlimits(pic,min.z,max.z); } // Draw x, y and z axes. void axes3(picture pic=currentpicture, Label xlabel="", Label ylabel="", Label zlabel="", bool extend=false, triple min=(-infinity,-infinity,-infinity), triple max=(infinity,infinity,infinity), pen p=currentpen, arrowbar3 arrow=None, margin3 margin=NoMargin3) { xaxis3(pic,xlabel,YZZero(extend),min.x,max.x,p,arrow,margin); yaxis3(pic,ylabel,XZZero(extend),min.y,max.y,p,arrow,margin); zaxis3(pic,zlabel,XYZero(extend),min.z,max.z,p,arrow,margin); } triple Scale(picture pic=currentpicture, triple v) { return (pic.scale.x.T(v.x),pic.scale.y.T(v.y),pic.scale.z.T(v.z)); } real ScaleZ(picture pic=currentpicture, real z) { return pic.scale.z.T(z); } // Draw a tick of length size at triple v in direction dir using pen p. void tick(picture pic=currentpicture, triple v, triple dir, real size=Ticksize, pen p=currentpen) { triple v=Scale(pic,v); pic.add(new void (picture f, transform3 t) { triple tv=t*v; draw(f,tv--tv+unit(dir)*size,p); }); pic.addPoint(v,p); pic.addPoint(v,unit(dir)*size,p); } void xtick(picture pic=currentpicture, triple v, triple dir=Y, real size=Ticksize, pen p=currentpen) { tick(pic,v,dir,size,p); } void xtick3(picture pic=currentpicture, real x, triple dir=Y, real size=Ticksize, pen p=currentpen) { tick(pic,(x,pic.scale.y.scale.logarithmic ? 1 : 0, pic.scale.z.scale.logarithmic ? 1 : 0),dir,size,p); } void ytick(picture pic=currentpicture, triple v, triple dir=X, real size=Ticksize, pen p=currentpen) { tick(pic,v,dir,size,p); } void ytick3(picture pic=currentpicture, real y, triple dir=X, real size=Ticksize, pen p=currentpen) { tick(pic,(pic.scale.x.scale.logarithmic ? 1 : 0,y, pic.scale.z.scale.logarithmic ? 1 : 0),dir,size,p); } void ztick(picture pic=currentpicture, triple v, triple dir=X, real size=Ticksize, pen p=currentpen) { xtick(pic,v,dir,size,p); } void ztick3(picture pic=currentpicture, real z, triple dir=X, real size=Ticksize, pen p=currentpen) { xtick(pic,(pic.scale.x.scale.logarithmic ? 1 : 0, pic.scale.y.scale.logarithmic ? 1 : 0,z),dir,size,p); } void tick(picture pic=currentpicture, Label L, real value, triple v, triple dir, string format="", real size=Ticksize, pen p=currentpen) { Label L=L.copy(); L.align(L.align,-dir); if(shift(L.T3)*O == O) L.T3=shift(dot(dir,L.align.dir3) > 0 ? dir*size : ticklabelshift(L.align.dir3,p))*L.T3; L.p(p); if(L.s == "") L.s=format(format == "" ? defaultformat : format,value); L.s=baseline(L.s,baselinetemplate); label(pic,L,Scale(pic,v)); tick(pic,v,dir,size,p); } void xtick(picture pic=currentpicture, Label L, triple v, triple dir=Y, string format="", real size=Ticksize, pen p=currentpen) { tick(pic,L,v.x,v,dir,format,size,p); } void xtick3(picture pic=currentpicture, Label L, real x, triple dir=Y, string format="", real size=Ticksize, pen p=currentpen) { xtick(pic,L,(x,pic.scale.y.scale.logarithmic ? 1 : 0, pic.scale.z.scale.logarithmic ? 1 : 0),dir,size,p); } void ytick(picture pic=currentpicture, Label L, triple v, triple dir=X, string format="", real size=Ticksize, pen p=currentpen) { tick(pic,L,v.y,v,dir,format,size,p); } void ytick3(picture pic=currentpicture, Label L, real y, triple dir=X, string format="", real size=Ticksize, pen p=currentpen) { xtick(pic,L,(pic.scale.x.scale.logarithmic ? 1 : 0,y, pic.scale.z.scale.logarithmic ? 1 : 0),dir,format,size,p); } void ztick(picture pic=currentpicture, Label L, triple v, triple dir=X, string format="", real size=Ticksize, pen p=currentpen) { tick(pic,L,v.z,v,dir,format,size,p); } void ztick3(picture pic=currentpicture, Label L, real z, triple dir=X, string format="", real size=Ticksize, pen p=currentpen) { xtick(pic,L,(pic.scale.x.scale.logarithmic ? 1 : 0, pic.scale.z.scale.logarithmic ? 1 : 0,z),dir,format,size,p); } private void label(picture pic, Label L, triple v, real x, align align, string format, pen p) { Label L=L.copy(); L.align(align); L.p(p); if(shift(L.T3)*O == O) L.T3=shift(ticklabelshift(L.align.dir3,L.p))*L.T3; if(L.s == "") L.s=format(format == "" ? defaultformat : format,x); L.s=baseline(L.s,baselinetemplate); label(pic,L,v); } void labelx(picture pic=currentpicture, Label L="", triple v, align align=-Y, string format="", pen p=currentpen) { label(pic,L,Scale(pic,v),v.x,align,format,p); } void labelx3(picture pic=currentpicture, Label L="", real x, align align=-Y, string format="", pen p=currentpen) { labelx(pic,L,(x,pic.scale.y.scale.logarithmic ? 1 : 0, pic.scale.z.scale.logarithmic ? 1 : 0),align,format,p); } void labely(picture pic=currentpicture, Label L="", triple v, align align=-X, string format="", pen p=currentpen) { label(pic,L,Scale(pic,v),v.y,align,format,p); } void labely3(picture pic=currentpicture, Label L="", real y, align align=-X, string format="", pen p=currentpen) { labely(pic,L,(pic.scale.x.scale.logarithmic ? 1 : 0,y, pic.scale.z.scale.logarithmic ? 1 : 0),align,format,p); } void labelz(picture pic=currentpicture, Label L="", triple v, align align=-X, string format="", pen p=currentpen) { label(pic,L,Scale(pic,v),v.z,align,format,p); } void labelz3(picture pic=currentpicture, Label L="", real z, align align=-X, string format="", pen p=currentpen) { labelz(pic,L,(pic.scale.x.scale.logarithmic ? 1 : 0, pic.scale.y.scale.logarithmic ? 1 : 0,z),align,format,p); } typedef guide3 graph(triple F(real), real, real, int); typedef guide3[] multigraph(triple F(real), real, real, int); graph graph(interpolate3 join) { return new guide3(triple f(real), real a, real b, int n) { real width=b-a; return n == 0 ? join(f(a)) : join(...sequence(new guide3(int i) {return f(a+(i/n)*width);},n+1)); }; } multigraph graph(interpolate3 join, bool3 cond(real)) { return new guide3[](triple f(real), real a, real b, int n) { real width=b-a; if(n == 0) return new guide3[] {join(cond(a) ? f(a) : nullpath3)}; guide3[] G; guide3[] g; for(int i=0; i < n+1; ++i) { real t=a+(i/n)*width; bool3 b=cond(t); if(b) g.push(f(t)); else { if(g.length > 0) { G.push(join(...g)); g=new guide3[] {}; } if(b == default) g.push(f(t)); } } if(g.length > 0) G.push(join(...g)); return G; }; } guide3 Straight(... guide3[])=operator --; guide3 Spline(... guide3[])=operator ..; guide3 graph(picture pic=currentpicture, real x(real), real y(real), real z(real), real a, real b, int n=ngraph, interpolate3 join=operator --) { return graph(join)(new triple(real t) {return Scale(pic,(x(t),y(t),z(t)));}, a,b,n); } guide3[] graph(picture pic=currentpicture, real x(real), real y(real), real z(real), real a, real b, int n=ngraph, bool3 cond(real), interpolate3 join=operator --) { return graph(join,cond)(new triple(real t) { return Scale(pic,(x(t),y(t),z(t))); },a,b,n); } guide3 graph(picture pic=currentpicture, triple v(real), real a, real b, int n=ngraph, interpolate3 join=operator --) { return graph(join)(new triple(real t) {return Scale(pic,v(t));},a,b,n); } guide3[] graph(picture pic=currentpicture, triple v(real), real a, real b, int n=ngraph, bool3 cond(real), interpolate3 join=operator --) { return graph(join,cond)(new triple(real t) { return Scale(pic,v(t)); },a,b,n); } guide3 graph(picture pic=currentpicture, triple[] v, interpolate3 join=operator --) { int i=0; return graph(join)(new triple(real) { triple w=Scale(pic,v[i]); ++i; return w; },0,0,v.length-1); } guide3[] graph(picture pic=currentpicture, triple[] v, bool3[] cond, interpolate3 join=operator --) { int n=v.length; int i=0; triple w; checkconditionlength(cond.length,n); bool3 condition(real) { bool b=cond[i]; if(b) w=Scale(pic,v[i]); ++i; return b; } return graph(join,condition)(new triple(real) {return w;},0,0,n-1); } guide3 graph(picture pic=currentpicture, real[] x, real[] y, real[] z, interpolate3 join=operator --) { int n=x.length; checklengths(n,y.length); checklengths(n,z.length); int i=0; return graph(join)(new triple(real) { triple w=Scale(pic,(x[i],y[i],z[i])); ++i; return w; },0,0,n-1); } guide3[] graph(picture pic=currentpicture, real[] x, real[] y, real[] z, bool3[] cond, interpolate3 join=operator --) { int n=x.length; checklengths(n,y.length); checklengths(n,z.length); int i=0; triple w; checkconditionlength(cond.length,n); bool3 condition(real) { bool3 b=cond[i]; if(b != false) w=Scale(pic,(x[i],y[i],z[i])); ++i; return b; } return graph(join,condition)(new triple(real) {return w;},0,0,n-1); } // The graph of a function along a path. guide3 graph(triple F(path, real), path p, int n=1, interpolate3 join=operator --) { guide3 g=join(...sequence(new guide3(int i) { return F(p,i/n); },n*length(p))); return cyclic(p) ? join(g,cycle) : join(g,F(p,length(p))); } guide3 graph(triple F(pair), path p, int n=1, interpolate3 join=operator --) { return graph(new triple(path p, real position) {return F(point(p,position));},p,n,join); } guide3 graph(picture pic=currentpicture, real f(pair), path p, int n=1, interpolate3 join=operator --) { return graph(new triple(pair z) {return Scale(pic,(z.x,z.y,f(z)));},p,n, join); } guide3 graph(real f(pair), path p, int n=1, real T(pair), interpolate3 join=operator --) { return graph(new triple(pair z) {pair w=T(z); return (w.x,w.y,f(w));},p,n, join); } // Connect points in v into segments corresponding to consecutive true elements // of b using interpolation operator join. path3[] segment(triple[] v, bool[] cond, interpolate3 join=operator --) { checkconditionlength(cond.length,v.length); int[][] segment=segment(cond); return sequence(new path3(int i) {return join(...v[segment[i]]);}, segment.length); } bool uperiodic(triple[][] a) { int n=a.length; if(n == 0) return false; int m=a[0].length; triple[] a0=a[0]; triple[] a1=a[n-1]; real epsilon=sqrtEpsilon*norm(a); for(int j=0; j < m; ++j) if(abs(a0[j]-a1[j]) > epsilon) return false; return true; } bool vperiodic(triple[][] a) { int n=a.length; if(n == 0) return false; int m=a[0].length-1; real epsilon=sqrtEpsilon*norm(a); for(int i=0; i < n; ++i) if(abs(a[i][0]-a[i][m]) > epsilon) return false; return true; } // return the surface described by a matrix f surface surface(triple[][] f, bool[][] cond={}) { if(!rectangular(f)) abort("matrix is not rectangular"); int nx=f.length-1; int ny=nx > 0 ? f[0].length-1 : 0; bool all=cond.length == 0; int count; if(all) count=nx*ny; else { count=0; for(int i=0; i < nx; ++i) { bool[] condi=cond[i]; bool[] condp=cond[i+1]; for(int j=0; j < ny; ++j) if(condi[j] && condi[j+1] && condp[j] && condp[j+1]) ++count; } } surface s=surface(count); s.index=new int[nx][ny]; int k=-1; for(int i=0; i < nx; ++i) { bool[] condi,condp; if(!all) { condi=cond[i]; condp=cond[i+1]; } triple[] fi=f[i]; triple[] fp=f[i+1]; int[] indexi=s.index[i]; for(int j=0; j < ny; ++j) { if(all || (condi[j] && condi[j+1] && condp[j] && condp[j+1])) s.s[++k]=patch(new triple[] {fi[j],fp[j],fp[j+1],fi[j+1]}); indexi[j]=k; } } if(count == nx*ny) { if(uperiodic(f)) s.ucyclic(true); if(vperiodic(f)) s.vcyclic(true); } return s; } surface bispline(real[][] z, real[][] p, real[][] q, real[][] r, real[] x, real[] y, bool[][] cond={}) { // z[i][j] is the value at (x[i],y[j]) // p and q are the first derivatives with respect to x and y, respectively // r is the second derivative ddu/dxdy int n=x.length-1; int m=y.length-1; bool all=cond.length == 0; int count; if(all) count=n*m; else { count=0; for(int i=0; i < n; ++i) { bool[] condi=cond[i]; for(int j=0; j < m; ++j) if(condi[j]) ++count; } } surface s=surface(count); s.index=new int[n][m]; int k=0; for(int i=0; i < n; ++i) { int ip=i+1; real xi=x[i]; real xp=x[ip]; real x1=interp(xi,xp,1/3); real x2=interp(xi,xp,2/3); real hx=x1-xi; real[] zi=z[i]; real[] zp=z[ip]; real[] ri=r[i]; real[] rp=r[ip]; real[] pi=p[i]; real[] pp=p[ip]; real[] qi=q[i]; real[] qp=q[ip]; int[] indexi=s.index[i]; bool[] condi=all ? null : cond[i]; for(int j=0; j < m; ++j) { if(all || condi[j]) { real yj=y[j]; int jp=j+1; real yp=y[jp]; real y1=interp(yj,yp,1/3); real y2=interp(yj,yp,2/3); real hy=y1-yj; real hxy=hx*hy; real zij=zi[j]; real zip=zi[jp]; real zpj=zp[j]; real zpp=zp[jp]; real pij=hx*pi[j]; real ppj=hx*pp[j]; real qip=hy*qi[jp]; real qpp=hy*qp[jp]; real zippip=zip+hx*pi[jp]; real zppmppp=zpp-hx*pp[jp]; real zijqij=zij+hy*qi[j]; real zpjqpj=zpj+hy*qp[j]; s.s[k]=patch(new triple[][] { {(xi,yj,zij),(xi,y1,zijqij),(xi,y2,zip-qip),(xi,yp,zip)}, {(x1,yj,zij+pij),(x1,y1,zijqij+pij+hxy*ri[j]), (x1,y2,zippip-qip-hxy*ri[jp]),(x1,yp,zippip)}, {(x2,yj,zpj-ppj),(x2,y1,zpjqpj-ppj-hxy*rp[j]), (x2,y2,zppmppp-qpp+hxy*rp[jp]),(x2,yp,zppmppp)}, {(xp,yj,zpj),(xp,y1,zpjqpj),(xp,y2,zpp-qpp),(xp,yp,zpp)}},copy=false); indexi[j]=k; ++k; } } } return s; } // return the surface described by a real matrix f, interpolated with // xsplinetype and ysplinetype. surface surface(real[][] f, real[] x, real[] y, splinetype xsplinetype=null, splinetype ysplinetype=xsplinetype, bool[][] cond={}) { real epsilon=sqrtEpsilon*norm(y); if(xsplinetype == null) xsplinetype=(abs(x[0]-x[x.length-1]) <= epsilon) ? periodic : notaknot; if(ysplinetype == null) ysplinetype=(abs(y[0]-y[y.length-1]) <= epsilon) ? periodic : notaknot; int n=x.length; int m=y.length; real[][] ft=transpose(f); real[][] tp=new real[m][]; for(int j=0; j < m; ++j) tp[j]=xsplinetype(x,ft[j]); real[][] q=new real[n][]; for(int i=0; i < n; ++i) q[i]=ysplinetype(y,f[i]); real[][] qt=transpose(q); real[] d1=xsplinetype(x,qt[0]); real[] d2=xsplinetype(x,qt[m-1]); real[][] r=new real[n][]; real[][] p=transpose(tp); for(int i=0; i < n; ++i) r[i]=clamped(d1[i],d2[i])(y,p[i]); surface s=bispline(f,p,q,r,x,y,cond); if(xsplinetype == periodic) s.ucyclic(true); if(ysplinetype == periodic) s.vcyclic(true); return s; } // return the surface described by a real matrix f, interpolated with // xsplinetype and ysplinetype. surface surface(real[][] f, pair a, pair b, splinetype xsplinetype, splinetype ysplinetype=xsplinetype, bool[][] cond={}) { if(!rectangular(f)) abort("matrix is not rectangular"); int nx=f.length-1; int ny=nx > 0 ? f[0].length-1 : 0; if(nx == 0 || ny == 0) return nullsurface; real[] x=uniform(a.x,b.x,nx); real[] y=uniform(a.y,b.y,ny); return surface(f,x,y,xsplinetype,ysplinetype,cond); } // return the surface described by a real matrix f, interpolated linearly. surface surface(real[][] f, pair a, pair b, bool[][] cond={}) { if(!rectangular(f)) abort("matrix is not rectangular"); int nx=f.length-1; int ny=nx > 0 ? f[0].length-1 : 0; if(nx == 0 || ny == 0) return nullsurface; bool all=cond.length == 0; triple[][] v=new triple[nx+1][ny+1]; for(int i=0; i <= nx; ++i) { real x=interp(a.x,b.x,i/nx); bool[] condi=all ? null : cond[i]; triple[] vi=v[i]; real[] fi=f[i]; for(int j=0; j <= ny; ++j) if(all || condi[j]) vi[j]=(x,interp(a.y,b.y,j/ny),fi[j]); } return surface(v,cond); } // return the surface described by a parametric function f over box(a,b), // interpolated linearly. surface surface(triple f(pair z), pair a, pair b, int nu=nmesh, int nv=nu, bool cond(pair z)=null) { if(nu <= 0 || nv <= 0) return nullsurface; bool[][] active; bool all=cond == null; if(!all) active=new bool[nu+1][nv+1]; real du=1/nu; real dv=1/nv; pair Idv=(0,dv); pair dz=(du,dv); triple[][] v=new triple[nu+1][nv+1]; for(int i=0; i <= nu; ++i) { real x=interp(a.x,b.x,i*du); bool[] activei=all ? null : active[i]; triple[] vi=v[i]; for(int j=0; j <= nv; ++j) { pair z=(x,interp(a.y,b.y,j*dv)); if(all || (activei[j]=cond(z))) vi[j]=f(z); } } return surface(v,active); } // return the surface described by a parametric function f over box(a,b), // interpolated with usplinetype and vsplinetype. surface surface(triple f(pair z), pair a, pair b, int nu=nmesh, int nv=nu, splinetype[] usplinetype, splinetype[] vsplinetype=Spline, bool cond(pair z)=null) { return surface(f,uniform(a.x,b.x,nu),uniform(a.y,b.y,nv), usplinetype,vsplinetype,cond); } // return the surface described by a real function f over box(a,b), // interpolated linearly. surface surface(real f(pair z), pair a, pair b, int nx=nmesh, int ny=nx, bool cond(pair z)=null) { return surface(new triple(pair z) {return (z.x,z.y,f(z));},a,b,nx,ny,cond); } // return the surface described by a real function f over box(a,b), // interpolated with xsplinetype and ysplinetype. surface surface(real f(pair z), pair a, pair b, int nx=nmesh, int ny=nx, splinetype xsplinetype, splinetype ysplinetype=xsplinetype, bool cond(pair z)=null) { bool[][] active; bool all=cond == null; if(!all) active=new bool[nx+1][ny+1]; real dx=1/nx; real dy=1/ny; pair Idy=(0,dy); pair dz=(dx,dy); real[][] F=new real[nx+1][ny+1]; real[] x=uniform(a.x,b.x,nx); real[] y=uniform(a.y,b.y,ny); for(int i=0; i <= nx; ++i) { bool[] activei=all ? null : active[i]; real[] Fi=F[i]; real x=x[i]; for(int j=0; j <= ny; ++j) { pair z=(x,y[j]); Fi[j]=f(z); if(!all) activei[j]=cond(z); } } return surface(F,x,y,xsplinetype,ysplinetype,active); } guide3[][] lift(real f(real x, real y), guide[][] g, interpolate3 join=operator --) { guide3[][] G=new guide3[g.length][]; for(int cnt=0; cnt < g.length; ++cnt) { guide[] gcnt=g[cnt]; guide3[] Gcnt=new guide3[gcnt.length]; for(int i=0; i < gcnt.length; ++i) { guide gcnti=gcnt[i]; guide3 Gcnti=join(...sequence(new guide3(int j) { pair z=point(gcnti,j); return (z.x,z.y,f(z.x,z.y)); },size(gcnti))); if(cyclic(gcnti)) Gcnti=Gcnti..cycle; Gcnt[i]=Gcnti; } G[cnt]=Gcnt; } return G; } guide3[][] lift(real f(pair z), guide[][] g, interpolate3 join=operator --) { return lift(new real(real x, real y) {return f((x,y));},g,join); } void draw(picture pic=currentpicture, Label[] L=new Label[], guide3[][] g, pen[] p, light light=currentlight, string name="", render render=defaultrender, interaction interaction=LabelInteraction()) { pen thin=is3D() ? thin() : defaultpen; bool group=g.length > 1 && (name != "" || render.defaultnames); if(group) begingroup3(pic,name == "" ? "contours" : name,render); for(int cnt=0; cnt < g.length; ++cnt) { guide3[] gcnt=g[cnt]; pen pcnt=thin+p[cnt]; for(int i=0; i < gcnt.length; ++i) draw(pic,gcnt[i],pcnt,light,name); if(L.length > 0) { Label Lcnt=L[cnt]; for(int i=0; i < gcnt.length; ++i) { if(Lcnt.s != "" && size(gcnt[i]) > 1) label(pic,Lcnt,gcnt[i],pcnt,name,interaction); } } } if(group) endgroup3(pic); } void draw(picture pic=currentpicture, Label[] L=new Label[], guide3[][] g, pen p=currentpen, light light=currentlight, string name="", render render=defaultrender, interaction interaction=LabelInteraction()) { draw(pic,L,g,sequence(new pen(int) {return p;},g.length),light,name, render,interaction); } real maxlength(triple f(pair z), pair a, pair b, int nu, int nv) { return min(abs(f((b.x,a.y))-f(a))/nu,abs(f((a.x,b.y))-f(a))/nv); } // return a vector field on a parametric surface f over box(a,b). picture vectorfield(path3 vector(pair v), triple f(pair z), pair a, pair b, int nu=nmesh, int nv=nu, bool truesize=false, real maxlength=truesize ? 0 : maxlength(f,a,b,nu,nv), bool cond(pair z)=null, pen p=currentpen, arrowbar3 arrow=Arrow3, margin3 margin=PenMargin3, string name="", render render=defaultrender) { picture pic; real du=1/nu; real dv=1/nv; bool all=cond == null; real scale; if(maxlength > 0) { real size(pair z) { path3 g=vector(z); return abs(point(g,size(g)-1)-point(g,0)); } real max=size((0,0)); for(int i=0; i <= nu; ++i) { real x=interp(a.x,b.x,i*du); for(int j=0; j <= nv; ++j) max=max(max,size((x,interp(a.y,b.y,j*dv)))); } scale=max > 0 ? maxlength/max : 1; } else scale=1; bool group=name != "" || render.defaultnames; if(group) begingroup3(pic,name == "" ? "vectorfield" : name,render); for(int i=0; i <= nu; ++i) { real x=interp(a.x,b.x,i*du); for(int j=0; j <= nv; ++j) { pair z=(x,interp(a.y,b.y,j*dv)); if(all || cond(z)) { path3 g=scale3(scale)*vector(z); string name="vector"; if(truesize) { picture opic; draw(opic,g,p,arrow,margin,name,render); add(pic,opic,f(z)); } else draw(pic,shift(f(z))*g,p,arrow,margin,name,render); } } } if(group) endgroup3(pic); return pic; } triple polar(real r, real theta, real phi) { return r*expi(theta,phi); } guide3 polargraph(real r(real,real), real theta(real), real phi(real), int n=ngraph, interpolate3 join=operator --) { return graph(join)(new triple(real t) { return polar(r(theta(t),phi(t)),theta(t),phi(t)); },0,1,n); } // True arc path3 Arc(triple c, triple v1, triple v2, triple normal=O, bool direction=CCW, int n=nCircle) { v1 -= c; real r=abs(v1); v1=unit(v1); v2=unit(v2-c); if(normal == O) { normal=cross(v1,v2); if(normal == O) abort("explicit normal required for these endpoints"); } transform3 T=align(unit(normal)); transform3 Tinv=transpose(T); v1=Tinv*v1; v2=Tinv*v2; real fuzz=sqrtEpsilon*max(abs(v1),abs(v2)); if(abs(v1.z) > fuzz || abs(v2.z) > fuzz) abort("invalid normal vector"); real phi1=radians(longitude(v1,warn=false)); real phi2=radians(longitude(v2,warn=false)); if(direction) { if(phi1 >= phi2) phi1 -= 2pi; } else if(phi2 >= phi1) phi2 -= 2pi; static real piby2=pi/2; return shift(c)*T*polargraph(new real(real theta, real phi) {return r;}, new real(real t) {return piby2;}, new real(real t) {return interp(phi1,phi2,t);}, n,operator ..); } path3 Arc(triple c, real r, real theta1, real phi1, real theta2, real phi2, triple normal=O, bool direction, int n=nCircle) { return Arc(c,c+r*dir(theta1,phi1),c+r*dir(theta2,phi2),normal,direction,n); } path3 Arc(triple c, real r, real theta1, real phi1, real theta2, real phi2, triple normal=O, int n=nCircle) { return Arc(c,r,theta1,phi1,theta2,phi2,normal, theta2 > theta1 || (theta2 == theta1 && phi2 >= phi1) ? CCW : CW, n); } // True circle path3 Circle(triple c, real r, triple normal=Z, int n=nCircle) { static real piby2=pi/2; return shift(c)*align(unit(normal))* polargraph(new real(real theta, real phi) {return r;}, new real(real t) {return piby2;}, new real(real t) {return interp(0,2pi,t);},n,operator ..); } asymptote-2.37/base/graph_settings.asy000066400000000000000000000004721265434602500201550ustar00rootroot00000000000000// Number of function samples. int ngraph=100; int nCircle=400; // Number of mesh intervals. int nmesh=10; real ticksize=1mm; real Ticksize=2*ticksize; real ylabelwidth=2.0; real axislabelfactor=1.5; real axiscoverage=0.8; real epsilon=10*realEpsilon; restricted bool Crop=true; restricted bool NoCrop=false; asymptote-2.37/base/graph_splinetype.asy000066400000000000000000000163761265434602500205230ustar00rootroot00000000000000private import math; typedef real[] splinetype(real[], real[]); restricted real[] Spline(real[] x, real[] y); restricted splinetype[] Spline; string morepoints="interpolation requires at least 2 points"; string differentlengths="arrays have different lengths"; void checklengths(int x, int y, string text=differentlengths) { if(x != y) abort(text+": "+string(x)+" != "+string(y)); } void checkincreasing(real[] x) { if(!increasing(x,true)) abort("strictly increasing array expected"); } // Linear interpolation real[] linear(real[] x, real[] y) { int n=x.length; checklengths(n,y.length); real[] d=new real[n]; for(int i=0; i < n-1; ++i) d[i]=(y[i+1]-y[i])/(x[i+1]-x[i]); d[n-1]=d[n-2]; return d; } // Standard cubic spline interpolation with not-a-knot condition: // s'''(x_2^-)=s'''(x_2^+) et s'''(x_(n_2)^-)=s'''(x_(n-2)^+) // if n=2, linear interpolation is returned // if n=3, an interpolation polynomial of degree <= 2 is returned: // p(x_1)=y_1, p(x_2)=y_2, p(x_3)=y_3 real[] notaknot(real[] x, real[] y) { int n=x.length; checklengths(n,y.length); checkincreasing(x); real[] d; if(n > 3) { real[] a=new real[n]; real[] b=new real[n]; real[] c=new real[n]; real[] g=new real[n]; b[0]=x[2]-x[1]; c[0]=x[2]-x[0]; a[0]=0; g[0]=((x[1]-x[0])^2*(y[2]-y[1])/b[0]+b[0]*(2*b[0]+3*(x[1]-x[0]))* (y[1]-y[0])/(x[1]-x[0]))/c[0]; for(int i=1; i < n-1; ++i) { a[i]=x[i+1]-x[i]; c[i]=x[i]-x[i-1]; b[i]=2*(a[i]+c[i]); g[i]=3*(c[i]*(y[i+1]-y[i])/a[i]+a[i]*(y[i]-y[i-1])/c[i]); } c[n-1]=0; b[n-1]=x[n-2]-x[n-3]; a[n-1]=x[n-1]-x[n-3]; g[n-1]=((x[n-1]-x[n-2])^2*(y[n-2]-y[n-3])/b[n-1]+ b[n-1]*(2*b[n-1]+3(x[n-1]-x[n-2]))* (y[n-1]-y[n-2])/(x[n-1]-x[n-2]))/a[n-1]; d=tridiagonal(a,b,c,g); } else if(n == 2) { real val=(y[1]-y[0])/(x[1]-x[0]); d=new real[] {val,val}; } else if(n == 3) { real a=(y[1]-y[0])/(x[1]-x[0]); real b=(y[2]-y[1])/(x[2]-x[1]); real c=(b-a)/(x[2]-x[0]); d=new real[] {a+c*(x[0]-x[1]),a+c*(x[1]-x[0]),a+c*(2*x[2]-x[0]-x[1])}; } else abort(morepoints); return d; } // Standard cubic spline interpolation with periodic condition // s'(a)=s'(b), s''(a)=s''(b), assuming that f(a)=f(b) // if n=2, linear interpolation is returned real[] periodic(real[] x, real[] y) { int n=x.length; checklengths(n,y.length); checkincreasing(x); if(abs(y[n-1]-y[0]) > sqrtEpsilon*norm(y)) abort("function values are not periodic"); real[] d; if(n > 2) { real[] a=new real[n-1]; real[] b=new real[n-1]; real[] c=new real[n-1]; real[] g=new real[n-1]; c[0]=x[n-1]-x[n-2]; a[0]=x[1]-x[0]; b[0]=2*(a[0]+c[0]); g[0]=3*c[0]*(y[1]-y[0])/a[0]+3*a[0]*(y[n-1]-y[n-2])/c[0]; for(int i=1; i < n-1; ++i) { a[i]=x[i+1]-x[i]; c[i]=x[i]-x[i-1]; b[i]=2*(a[i]+c[i]); g[i]=3*(c[i]*(y[i+1]-y[i])/a[i]+a[i]*(y[i]-y[i-1])/c[i]); } d=tridiagonal(a,b,c,g); d.push(d[0]); } else if(n == 2) { d=new real[] {0,0}; } else abort(morepoints); return d; } // Standard cubic spline interpolation with the natural condition // s''(a)=s''(b)=0. // if n=2, linear interpolation is returned // Don't use the natural type unless the underlying function // has zero second end points derivatives. real[] natural(real[] x, real[] y) { int n=x.length; checklengths(n,y.length); checkincreasing(x); real[] d; if(n > 2) { real[] a=new real[n]; real[] b=new real[n]; real[] c=new real[n]; real[] g=new real[n]; b[0]=2*(x[1]-x[0]); c[0]=x[1]-x[0]; a[0]=0; g[0]=3*(y[1]-y[0]); for(int i=1; i < n-1; ++i) { a[i]=x[i+1]-x[i]; c[i]=x[i]-x[i-1]; b[i]=2*(a[i]+c[i]); g[i]=3*(c[i]*(y[i+1]-y[i])/a[i]+a[i]*(y[i]-y[i-1])/c[i]); } c[n-1]=0; a[n-1]=x[n-1]-x[n-2]; b[n-1]=2*a[n-1]; g[n-1]=3*(y[n-1]-y[n-2]); d=tridiagonal(a,b,c,g); } else if(n == 2) { real val=(y[1]-y[0])/(x[1]-x[0]); d=new real[] {val,val}; } else abort(morepoints); return d; } // Standard cubic spline interpolation with clamped conditions f'(a), f'(b) splinetype clamped(real slopea, real slopeb) { return new real[] (real[] x, real[] y) { int n=x.length; checklengths(n,y.length); checkincreasing(x); real[] d; if(n > 2) { real[] a=new real[n]; real[] b=new real[n]; real[] c=new real[n]; real[] g=new real[n]; b[0]=x[1]-x[0]; g[0]=b[0]*slopea; c[0]=0; a[0]=0; for(int i=1; i < n-1; ++i) { a[i]=x[i+1]-x[i]; c[i]=x[i]-x[i-1]; b[i]=2*(a[i]+c[i]); g[i]=3*(c[i]*(y[i+1]-y[i])/a[i]+a[i]*(y[i]-y[i-1])/c[i]); } c[n-1]=0; a[n-1]=0; b[n-1]=x[n-1]-x[n-2]; g[n-1]=b[n-1]*slopeb; d=tridiagonal(a,b,c,g); } else if(n == 2) { d=new real[] {slopea,slopeb}; } else abort(morepoints); return d; }; } // Piecewise Cubic Hermite Interpolating Polynomial (PCHIP) // Modified MATLAB code // [1] Fritsch, F. N. and R. E. Carlson, // "Monotone Piecewise Cubic Interpolation," // SIAM J. Numerical Analysis, Vol. 17, 1980, pp.238-246. // [2] Kahaner, David, Cleve Moler, Stephen Nash, // Numerical Methods and Software, Prentice Hall, 1988. real[] monotonic(real[] x, real[] y) { int n=x.length; checklengths(n,y.length); checkincreasing(x); real[] d=new real[n]; if(n > 2) { real[] h=new real[n-1]; real[] del=new real[n-1]; for(int i=0; i < n-1; ++i) { h[i]=x[i+1]-x[i]; del[i]=(y[i+1]-y[i])/h[i]; } int j=0; int k[]=new int[]; for(int i=0; i < n-2; ++i) if((sgn(del[i])*sgn(del[i+1])) > 0) {k[j]=i; j=j+1;} real[] hs=new real[j]; for(int i=0; i < j; ++i) hs[i]=h[k[i]]+h[k[i]+1]; real w1[]=new real[j]; real w2[]=new real[j]; real dmax[]=new real[j]; real dmin[]=new real[j]; for(int i=0; i < j; ++i) { w1[i]=(h[k[i]]+hs[i])/(3*hs[i]); w2[i]=(h[k[i]+1]+hs[i])/(3*hs[i]); dmax[i]=max(abs(del[k[i]]),abs(del[k[i]+1])); dmin[i]=min(abs(del[k[i]]),abs(del[k[i]+1])); } for(int i=0; i < n; ++i) d[i]=0; for(int i=0; i < j; ++i) d[k[i]+1]=dmin[i]/(w1[i]*(del[k[i]]/dmax[i])+w2[i]*(del[k[i]+1]/dmax[i])); d[0]=((2*h[0]+h[1])*del[0]-h[0]*del[1])/(h[0]+h[1]); if(sgn(d[0]) != sgn(del[0])) {d[0]=0;} else if((sgn(del[0]) != sgn(del[1])) && (abs(d[0]) > abs(3*del[0]))) d[0]=3*del[0]; d[n-1]=((2*h[n-2]+h[n-3])*del[n-2]-h[n-2]*del[n-2])/(h[n-2]+h[n-3]); if(sgn(d[n-1]) != sgn(del[n-2])) {d[n-1]=0;} else if((sgn(del[n-2]) != sgn(del[n-3])) && (abs(d[n-1]) > abs(3*del[n-2]))) d[n-1]=3*del[n-2]; } else if(n == 2) { d[0]=d[1]=(y[1]-y[0])/(x[1]-x[0]); } else abort(morepoints); return d; } // Return standard cubic spline interpolation as a guide guide hermite(real[] x, real[] y, splinetype splinetype=null) { int n=x.length; if(n == 0) return nullpath; guide g=(x[0],y[0]); if(n == 1) return g; if(n == 2) return g--(x[1],y[1]); if(splinetype == null) splinetype=(x[0] == x[x.length-1] && y[0] == y[y.length-1]) ? periodic : notaknot; real[] dy=splinetype(x,y); for(int i=1; i < n; ++i) { pair z=(x[i],y[i]); real dx=x[i]-x[i-1]; g=g..controls((x[i-1],y[i-1])+dx*(1,dy[i-1])/3) and (z-dx*(1,dy[i])/3)..z; } return g; } asymptote-2.37/base/grid3.asy000066400000000000000000000322441265434602500161460ustar00rootroot00000000000000// grid3.asy // Author: Philippe Ivaldi (Grids in 3D) // http://www.piprime.fr/ // Created: 10 janvier 2007 import graph3; struct grid3 { path3 axea,axeb; bounds bds; triple dir; valuetime vt; ticklocate locate; void create(picture pic, path3 axea, path3 axeb, path3 axelevel, real min, real max, position pos, autoscaleT t) { real position=pos.position.x; triple level; if(pos.relative) { position=reltime(axelevel,position); level=point(axelevel,position)-point(axelevel,0); } else { triple v=unit(point(axelevel,1)-point(axelevel,0)); triple zerolevel=dot(-point(axelevel,0),v)*v; level=zerolevel+position*v; } this.axea=shift(level)*axea; this.axeb=shift(level)*axeb; bds=autoscale(min,max,t.scale); locate=ticklocate(min,max,t,bds.min,bds.max, Dir(point(axeb,0)-point(axea,0))); } }; typedef grid3 grid3routine(picture pic); triple X(picture pic) {return (pic.userMax().x,pic.userMin().y,pic.userMin().z);} triple XY(picture pic) {return (pic.userMax().x,pic.userMax().y,pic.userMin().z);} triple Y(picture pic) {return (pic.userMin().x,pic.userMax().y,pic.userMin().z);} triple YZ(picture pic) {return (pic.userMin().x,pic.userMax().y,pic.userMax().z);} triple Z(picture pic) {return (pic.userMin().x,pic.userMin().y,pic.userMax().z);} triple ZX(picture pic) {return (pic.userMax().x,pic.userMin().y,pic.userMax().z);} grid3routine XYgrid(position pos=Relative(0)) { return new grid3(picture pic) { grid3 og; triple m=pic.userMin(); triple M=pic.userMax(); og.create(pic,m--X(pic),Y(pic)--XY(pic),m--Z(pic), m.x,M.x,pos,pic.scale.x); return og; }; }; grid3routine XYgrid=XYgrid(); grid3routine YXgrid(position pos=Relative(0)) { return new grid3(picture pic) { grid3 og; triple m=pic.userMin(); triple M=pic.userMax(); og.create(pic,m--Y(pic),X(pic)--XY(pic),m--Z(pic), m.y,M.y,pos,pic.scale.y); return og; }; }; grid3routine YXgrid=YXgrid(); grid3routine XZgrid(position pos=Relative(0)) { return new grid3(picture pic) { grid3 og; triple m=pic.userMin(); triple M=pic.userMax(); og.create(pic,m--X(pic),Z(pic)--ZX(pic),m--Y(pic), m.x,M.x,pos,pic.scale.x); return og; }; }; grid3routine XZgrid=XZgrid(); grid3routine ZXgrid(position pos=Relative(0)) { return new grid3(picture pic) { grid3 og; triple m=pic.userMin(); triple M=pic.userMax(); og.create(pic,m--Z(pic),X(pic)--ZX(pic),m--Y(pic), m.z,M.z,pos,pic.scale.z); return og; }; }; grid3routine ZXgrid=ZXgrid(); grid3routine YZgrid(position pos=Relative(0)) { return new grid3(picture pic) { grid3 og; triple m=pic.userMin(); triple M=pic.userMax(); og.create(pic,m--Y(pic),Z(pic)--YZ(pic),m--X(pic), m.y,M.y,pos,pic.scale.y); return og; }; }; grid3routine YZgrid=YZgrid(); grid3routine ZYgrid(position pos=Relative(0)) { return new grid3(picture pic) { grid3 og; triple m=pic.userMin(); triple M=pic.userMax(); og.create(pic,m--Z(pic),Y(pic)--YZ(pic),m--X(pic), m.z,M.z,pos,pic.scale.z); return og; }; }; grid3routine ZYgrid=ZYgrid(); typedef grid3routine grid3routines[] ; grid3routines XYXgrid(position pos=Relative(0)) { grid3routines ogs=new grid3routine[] {XYgrid(pos),YXgrid(pos)}; return ogs; }; grid3routines XYXgrid=XYXgrid(); grid3routines YXYgrid(position pos=Relative(0)) {return XYXgrid(pos);}; grid3routines YXYgrid=XYXgrid(); grid3routines ZXZgrid(position pos=Relative(0)) { grid3routines ogs=new grid3routine[] {ZXgrid(pos),XZgrid(pos)}; return ogs; }; grid3routines ZXZgrid=ZXZgrid(); grid3routines XZXgrid(position pos=Relative(0)) {return ZXZgrid(pos);}; grid3routines XZXgrid=XZXgrid(); grid3routines ZYZgrid(position pos=Relative(0)) { grid3routines ogs=new grid3routine[] {ZYgrid(pos),YZgrid(pos)}; return ogs; }; grid3routines ZYZgrid=ZYZgrid(); grid3routines YZYgrid(position pos=Relative(0)) {return ZYZgrid(pos);}; grid3routines YZYgrid=YZYgrid(); grid3routines XY_XZgrid(position posa=Relative(0), position posb=Relative(0)) { grid3routines ogs=new grid3routine[] {XYgrid(posa),XZgrid(posb)}; return ogs; }; grid3routines XY_XZgrid=XY_XZgrid(); grid3routines YX_YZgrid(position posa=Relative(0), position posb=Relative(0)) { grid3routines ogs=new grid3routine[] {YXgrid(posa),YZgrid(posb)}; return ogs; }; grid3routines YX_YZgrid=YX_YZgrid(); grid3routines ZX_ZYgrid(position posa=Relative(0), position posb=Relative(0)) { grid3routines ogs=new grid3routine[] {ZXgrid(posa),ZYgrid(posb)}; return ogs; }; grid3routines ZX_ZYgrid=ZX_ZYgrid(); typedef grid3routines[] grid3routinetype; grid3routinetype XYZgrid(position pos=Relative(0)) { grid3routinetype ogs=new grid3routines[] {YZYgrid(pos),XYXgrid(pos), XZXgrid(pos)}; return ogs; } grid3routinetype XYZgrid=XYZgrid(); grid3routines operator cast(grid3routine gridroutine) { grid3routines og=new grid3routine[] {gridroutine}; return og; } grid3routinetype operator cast(grid3routines gridroutine) { grid3routinetype og=new grid3routines[] {gridroutine}; return og; } grid3routinetype operator cast(grid3routine gridroutine) { grid3routinetype og=(grid3routinetype)(grid3routines) gridroutine; return og; } void grid3(picture pic=currentpicture, grid3routinetype gridroutine=XYZgrid, int N=0, int n=0, real Step=0, real step=0, bool begin=true, bool end=true, pen pGrid=grey, pen pgrid=lightgrey, bool above=false) { for(int j=0; j < gridroutine.length; ++j) { grid3routines gridroutinej=gridroutine[j]; for(int i=0; i < gridroutinej.length; ++i) { grid3 gt=gridroutinej[i](pic); pic.add(new void(picture f, transform3 t, transform3 T, triple, triple) { picture d; ticks3 ticks=Ticks3(1,F="%",ticklabel=null, beginlabel=false,endlabel=false, N=N,n=n,Step=Step,step=step, begin=begin,end=end, Size=0,size=0,extend=true, pTick=pGrid,ptick=pgrid); ticks(d,t,"",gt.axea,gt.axeb,nullpen,None,NoMargin3,gt.locate, gt.bds.divisor,opposite=true,primary=false); add(f,t*T*inverse(t)*d); },above=above); addPath(pic,gt.axea,pGrid); addPath(pic,gt.axeb,pGrid); } } } void grid3(picture pic=currentpicture, grid3routinetype gridroutine, int N=0, int n=0, real Step=0, real step=0, bool begin=true, bool end=true, pen[] pGrid, pen[] pgrid, bool above=false) { if(pGrid.length != gridroutine.length || pgrid.length != gridroutine.length) abort("pen array has different length than grid"); for(int i=0; i < gridroutine.length; ++i) { grid3(pic=pic,gridroutine=gridroutine[i], N=N,n=n,Step=Step,step=step, begin=begin,end=end, pGrid=pGrid[i],pgrid=pgrid[i], above=above); } } position top=Relative(1); position bottom=Relative(0); position middle=Relative(0.5); // Structure used to communicate ticks and axis settings to grid3 routines. struct ticksgridT { ticks3 ticks; // Other arguments of grid3 are define by ticks and axis settings void grid3(picture, bool); }; typedef ticksgridT ticksgrid(); ticksgrid InOutTicks(Label F="", ticklabel ticklabel=null, bool beginlabel=true, bool endlabel=true, int N=0, int n=0, real Step=0, real step=0, bool begin=true, bool end=true, real Size=0, real size=0, pen pTick=nullpen, pen ptick=nullpen, grid3routinetype gridroutine, pen pGrid=grey, pen pgrid=lightgrey) { return new ticksgridT() { ticksgridT otg; otg.ticks=Ticks3(0,F,ticklabel,beginlabel,endlabel, N,n,Step,step,begin,end, Size,size,false,pTick,ptick); otg.grid3=new void(picture pic, bool above) { grid3(pic,gridroutine,N,n,Step,step,begin,end,pGrid,pgrid,above); }; return otg; }; } ticksgrid InTicks(Label F="", ticklabel ticklabel=null, bool beginlabel=true, bool endlabel=true, int N=0, int n=0, real Step=0, real step=0, bool begin=true, bool end=true, real Size=0, real size=0, pen pTick=nullpen, pen ptick=nullpen, grid3routinetype gridroutine, pen pGrid=grey, pen pgrid=lightgrey) { return new ticksgridT() { ticksgridT otg; otg.ticks=Ticks3(-1,F,ticklabel,beginlabel,endlabel,N,n,Step,step, begin,end,Size,size,false,pTick,ptick); otg.grid3=new void(picture pic, bool above) { grid3(pic,gridroutine,N,n,Step,step,begin,end,pGrid,pgrid,above); }; return otg; }; } ticksgrid OutTicks(Label F="", ticklabel ticklabel=null, bool beginlabel=true, bool endlabel=true, int N=0, int n=0, real Step=0, real step=0, bool begin=true, bool end=true, real Size=0, real size=0, pen pTick=nullpen, pen ptick=nullpen, grid3routinetype gridroutine, pen pGrid=grey, pen pgrid=lightgrey) { return new ticksgridT() { ticksgridT otg; otg.ticks=Ticks3(1,F,ticklabel,beginlabel,endlabel,N,n,Step,step, begin,end,Size,size,false,pTick,ptick); otg.grid3=new void(picture pic, bool above) { grid3(pic,gridroutine,N,n,Step,step,begin,end,pGrid,pgrid,above); }; return otg; }; } void xaxis3(picture pic=currentpicture, Label L="", axis axis=YZZero, pen p=currentpen, ticksgrid ticks, arrowbar3 arrow=None, bool above=false) { xaxis3(pic,L,axis,p,ticks().ticks,arrow,above); ticks().grid3(pic,above); } void yaxis3(picture pic=currentpicture, Label L="", axis axis=XZZero, pen p=currentpen, ticksgrid ticks, arrowbar3 arrow=None, bool above=false) { yaxis3(pic,L,axis,p,ticks().ticks,arrow,above); ticks().grid3(pic,above); } void zaxis3(picture pic=currentpicture, Label L="", axis axis=XYZero, pen p=currentpen, ticksgrid ticks, arrowbar3 arrow=None, bool above=false) { zaxis3(pic,L,axis,p,ticks().ticks,arrow,above); ticks().grid3(pic,above); } /* Example: import grid3; size(8cm,0); currentprojection=orthographic(0.5,1,0.5); defaultpen(overwrite(SuppressQuiet)); scale(Linear, Linear, Log); grid3(pic=currentpicture, // picture gridroutine=XYZgrid(// grid3routine // or grid3routine[] (alias grid3routines) // or grid3routines[]: // The routine(s) to draw the grid(s): // *XYgrid: draw grid from X in direction of Y // *YXgrid: draw grid from Y in direction of X, ... // *An array of previous values XYgrid, YXgrid, ... // *XYXgrid: draw XYgrid and YXgrid grids // *YXYgrid: draw XYgrid and YXgrid grids // *ZXZgrid: draw ZXgrid and XZgrid grids // *YX_YZgrid: draw YXgrid and YZgrid grids // *XY_XZgrid: draw XYgrid and XZgrid grids // *YX_YZgrid: draw YXgrid and YZgrid grids // *An array of previous values XYXgrid,... // *XYZgrid: draw XYXgrid, ZYZgrid, XZXgrid grids. pos=Relative(0)), // the position of the grid relative to the axis // perpendicular to the grid; a real number // specifies a coordinate relative to this axis. // Aliases: top=Relative(1), middle=Relative(0.5) // and bottom=Relative(0). // These arguments are similar to those of InOutTicks(): N=0, // int n=0, // int Step=0, // real step=0, // real begin=true, // bool end=true, // bool pGrid=grey, // pen pgrid=lightgrey, // pen above=false // bool ); xaxis3(Label("$x$",position=EndPoint,align=S),OutTicks()); yaxis3(Label("$y$",position=EndPoint,align=S),OutTicks()); zaxis3(Label("$z$",position=EndPoint,align=(0,0.5)+W),OutTicks()); */ /* Other examples: int N=10, n=2; xaxis3(Label("$x$",position=EndPoint,align=S),OutTicks()); yaxis3(Label("$y$",position=EndPoint,align=S),OutTicks(N=N,n=n)); zaxis3(Label("$z$",position=EndPoint,align=(0,0.5)+W),OutTicks()); grid3(N=N,n=n); xaxis3(Label("$x$",position=EndPoint,align=S),OutTicks()); yaxis3(Label("$y$",position=EndPoint,align=S),OutTicks()); zaxis3(Label("$z$",position=EndPoint,align=(0,0.5)+W),OutTicks()); grid3(new grid3routines[] {XYXgrid(top),XZXgrid(0)}); xaxis3(Label("$x$",position=EndPoint,align=S),OutTicks()); yaxis3(Label("$y$",position=EndPoint,align=S),OutTicks()); zaxis3(Label("$z$",position=EndPoint,align=(0,0.5)+W),OutTicks()); grid3(new grid3routines[] {XYXgrid(-0.5),XYXgrid(1.5)}, pGrid=new pen[] {red,blue}, pgrid=new pen[] {0.5red,0.5blue}); // Axes with grids: xaxis3(Label("$x$",position=EndPoint,align=S), OutTicks(Step=0.5,gridroutine=XYgrid)); yaxis3(Label("$y$",position=EndPoint,align=S), InOutTicks(Label("",align=0.5X),N=8,n=2,gridroutine=YX_YZgrid)); zaxis3("$z$",OutTicks(ZYgrid)); */ asymptote-2.37/base/interpolate.asy000066400000000000000000000075501265434602500174660ustar00rootroot00000000000000// Lagrange and Hermite interpolation in Asymptote // Author: Olivier Guibé // Acknowledgements: Philippe Ivaldi // diffdiv(x,y) computes Newton's Divided Difference for // Lagrange interpolation with distinct values {x_0,..,x_n} in the array x // and values y_0,...,y_n in the array y, // hdiffdiv(x,y,dyp) computes Newton's Divided Difference for // Hermite interpolation where dyp={dy_0,...,dy_n}. // // fhorner(x,coeff) uses Horner's rule to compute the polynomial // a_0+a_1(x-x_0)+a_2(x-x_0)(x-x_1)+...+a_n(x-x_0)..(x-x_{n-1}), // where coeff={a_0,a_1,...,a_n}. // fspline does standard cubic spline interpolation of a function f // on the interval [a,b]. // The points a=x_1 < x_2 < .. < x_n=b form the array x; // the points y_1=f(x_1),....,y_n=f(x_n) form the array y // We use the Hermite form for the spline. // The syntax is: // s=fspline(x,y); default not_a_knot condition // s=fspline(x,y,natural); natural spline // s=fspline(x,y,periodic); periodic spline // s=fspline(x,y,clamped(1,1)); clamped spline // s=fspline(x,y,monotonic); piecewise monotonic spline // Here s is a real function that is constant on (-infinity,a] and [b,infinity). private import math; import graph_splinetype; typedef real fhorner(real); struct horner { // x={x0,..,xn}(not necessarily distinct) // a={a0,..,an} corresponds to the polyonmial // a_0+a_1(x-x_0)+a_2(x-x_0)(x-x_1)+...+a_n(x-x_0)..(x-x_{n-1}), real[] x; real[] a; } // Evaluate p(x)=d0+(x-x0)(d1+(x-x1)+...+(d(n-1)+(x-x(n-1))*dn))) // via Horner's rule: n-1 multiplications, 2n-2 additions. fhorner fhorner(horner sh) { int n=sh.x.length; checklengths(n,sh.a.length); return new real(real x) { real s=sh.a[n-1]; for(int k=n-2; k >= 0; --k) s=sh.a[k]+(x-sh.x[k])*s; return s; }; } // Newton's Divided Difference method: n(n-1)/2 divisions, n(n-1) additions. horner diffdiv(real[] x, real[] y) { int n=x.length; horner s; checklengths(n,y.length); for(int i=0; i < n; ++i) s.a[i]=y[i]; for(int k=0; k < n-1; ++k) { for(int i=n-1; i > k; --i) { s.a[i]=(s.a[i]-s.a[i-1])/(x[i]-x[i-k-1]); } } s.x=x; return s; } // Newton's Divided Difference for simple Hermite interpolation, // where one specifies both p(x_i) and p'(x_i). horner hdiffdiv(real[] x, real[] y, real[] dy) { int n=x.length; horner s; checklengths(n,y.length); checklengths(n,dy.length); for(int i=0; i < n; ++i) { s.a[2*i]=y[i]; s.a[2*i+1]=dy[i]; s.x[2*i]=x[i]; s.x[2*i+1]=x[i]; } for(int i=n-1; i > 0; --i) s.a[2*i]=(s.a[2*i]-s.a[2*i-2])/(x[i]-x[i-1]); int stop=2*n-1; for(int k=1; k < stop; ++k) { for(int i=stop; i > k; --i) { s.a[i]=(s.a[i]-s.a[i-1])/(s.x[i]-s.x[i-k-1]); } } return s; } typedef real realfunction(real); // piecewise Hermite interpolation: // return the piecewise polynomial p(x), where on [x_i,x_i+1], deg(p) <= 3, // p(x_i)=y_i, p(x_{i+1})=y_i+1, p'(x_i)=dy_i, and p'(x_{i+1})=dy_i+1. // Outside [x_1,x_n] the returned function is constant: y_1 on (infinity,x_1] // and y_n on [x_n,infinity). realfunction pwhermite(real[] x, real[] y, real[] dy) { int n=x.length; checklengths(n,y.length); checklengths(n,dy.length); if(n < 2) abort(morepoints); if(!increasing(x,strict=true)) abort("array x is not strictly increasing"); return new real(real t) { int i=search(x,t); if(i == n-1) { i=n-2; t=x[n-1]; } else if(i == -1) { i=0; t=x[0]; } real h=x[i+1]-x[i]; real delta=(y[i+1]-y[i])/h; real e=(3*delta-2*dy[i]-dy[i+1])/h; real f=(dy[i]-2*delta+dy[i+1])/h^2; real s=t-x[i]; return y[i]+s*(dy[i]+s*(e+s*f)); }; } realfunction fspline(real[] x, real[] y, splinetype splinetype=notaknot) { real[] dy=splinetype(x,y); return new real(real t) { return pwhermite(x,y,dy)(t); }; } asymptote-2.37/base/labelpath.asy000066400000000000000000000013311265434602500170630ustar00rootroot00000000000000usepackage("pstricks"); usepackage("pst-text"); string LeftJustified="l"; string RightJustified="r"; string Centered="c"; void labelpath(frame f, Label L, path g, string justify=Centered, pen p=currentpen) { if(latex() && !pdf()) { _labelpath(f,L.s,L.size,g,justify,(L.T.x,L.T.y+0.5linewidth(p)),p); return; } warning("labelpathlatex","labelpath requires -tex latex"); } void labelpath(picture pic=currentpicture, Label L, path g, string justify=Centered, pen p=currentpen) { pic.add(new void(frame f, transform t) { labelpath(f,L,t*g,justify,p); }); frame f; label(f,Label(L.s,L.size)); real w=size(f).y+L.T.y+0.5linewidth(p); pic.addBox(min(g),max(g),-w,w); } asymptote-2.37/base/labelpath3.asy000066400000000000000000000046411265434602500171550ustar00rootroot00000000000000// Fit a label to a path3. // Author: Jens Schwaiger import three; private real eps=100*realEpsilon; triple nextnormal(triple p, triple q) { triple nw=p-(dot(p,q)*q); return abs(nw) < 0.0001 ? p : unit(nw); } triple[] firstframe(path3 p, triple optional=O) { triple[] start=new triple[3]; start[0]=dir(p,reltime(p,0)); start[1]=(abs(cross(start[0],optional)) < eps) ? perp(start[0]) : unit(cross(start[0],optional)); start[2]=cross(start[0],start[1]); return start; } // Modification of the bishop frame construction contained in // space_tube.asy (from Philippe Ivaldi's modules). // For noncyclic path3s only triple[] nextframe(path3 p, real reltimestart, triple[] start, real reltimeend, int subdiv=20) { triple[][] bf=new triple[subdiv+1][3]; real lg=reltimeend-reltimestart; if(lg <= 0) return start; bf[0]=start; int n=subdiv+1; for(int i=1; i < n; ++i) bf[i][0]=dir(p,reltime(p,reltimestart+(i/subdiv)*lg)); for(int i=1; i < n; ++i) { bf[i][1]=nextnormal(bf[i-1][1],bf[i][0]); bf[i][2]=cross(bf[i][0],bf[i][1]); } return bf[subdiv]; } surface labelpath(string s, path3 p, real angle=90, triple optional=O) { real Cos=Cos(angle); real Sin=Sin(angle); path[] text=texpath(Label(s,(0,0),Align,basealign)); text=scale(1/(max(text).x-min(text).x))*text; path[][] decompose=containmentTree(text); real[][] xpos=new real[decompose.length][2]; surface sf; for(int i=0; i < decompose.length; ++i) {// Identify positions along x-axis xpos[i][1]=i; real pos0=0.5(max(decompose[i]).x+min(decompose[i]).x); xpos[i][0]=pos0; } xpos=sort(xpos); // sort by distance from 0; triple[] pos=new triple[decompose.length]; real lg=arclength(p); //create frames; triple[] first=firstframe(p,optional); triple[] t0=first; real tm0=0; triple[][] bfr=new triple[decompose.length][3]; for(int j=0; j < decompose.length; ++j) { bfr[j]=nextframe(p,tm0,t0,xpos[j][0]); tm0=xpos[j][0]; t0=bfr[j]; } transform3[] mt=new transform3[bfr.length]; for(int j=0; j < bfr.length; ++j) { triple f2=Cos*bfr[j][1]+Sin*bfr[j][2]; triple f3=Sin*bfr[j][1]+Cos*bfr[j][2]; mt[j]=shift(relpoint(p,xpos[j][0]))*transform3(bfr[j][0],f2,f3); } for(int j=0; j < bfr.length; ++j) { path[] dc=decompose[(int) xpos[j][1]]; pair pos0=(0.5(max(dc).x+min(dc).x),0); sf.append(mt[j]*surface(scale(lg)*shift(-pos0)*dc)); } return sf; } asymptote-2.37/base/latin1.asy000066400000000000000000000000751265434602500163230ustar00rootroot00000000000000usepackage("fontenc","T1"); usepackage("inputenc","latin1"); asymptote-2.37/base/lmfit.asy000066400000000000000000000601231265434602500162460ustar00rootroot00000000000000/* Copyright (c) 2009 Philipp Stephani Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* Fitting $n$ data points $(x_1, y_1 \pm \Delta y_1), \dots, (x_n, y_n \pm \Delta y_n)$ to a function $f$ that depends on $m$ parameters $a_1, \dots, a_m$ means minimizing the least-squares sum % \begin{equation*} \sum_{i = 1}^n \left( \frac{y_i - f(a_1, \dots, a_m; x_i)}{\Delta y_i} \right)^2 \end{equation*} % with respect to the parameters $a_1, \dots, a_m$. */ /* This module provides an implementation of the Levenberg--Marquardt (LM) algorithm, converted from the C lmfit routine by Joachim Wuttke (see http://www.messen-und-deuten.de/lmfit/). Implementation strategy: Fortunately, Asymptote's syntax is very similar to C, and the original code cleanly separates the customizable parts (user-provided data, output routines, etc.) from the dirty number crunching. Thus, mst of the code was just copied and slightly modified from the original source files. I have amended the lm_data_type structure and the callback routines with a weight array that can be used to provide experimental errors. I have also created two simple wrapper functions. */ // copied from the C code private real LM_MACHEP = realEpsilon; private real LM_DWARF = realMin; private real LM_SQRT_DWARF = sqrt(realMin); private real LM_SQRT_GIANT = sqrt(realMax); private real LM_USERTOL = 30 * LM_MACHEP; restricted string lm_infmsg[] = { "improper input parameters", "the relative error in the sum of squares is at most tol", "the relative error between x and the solution is at most tol", "both errors are at most tol", "fvec is orthogonal to the columns of the jacobian to machine precision", "number of calls to fcn has reached or exceeded maxcall*(n+1)", "ftol is too small: no further reduction in the sum of squares is possible", "xtol too small: no further improvement in approximate solution x possible", "gtol too small: no further improvement in approximate solution x possible", "not enough memory", "break requested within function evaluation" }; restricted string lm_shortmsg[] = { "invalid input", "success (f)", "success (p)", "success (f,p)", "degenerate", "call limit", "failed (f)", "failed (p)", "failed (o)", "no memory", "user break" }; // copied from the C code and amended with the weight (user_w) array struct lm_data_type { real[] user_t; real[] user_y; real[] user_w; real user_func(real user_t_point, real[] par); }; // Asymptote has no pointer support, so we need reference wrappers for // the int and real types struct lm_int_type { int val; void operator init(int val) { this.val = val; } }; struct lm_real_type { real val; void operator init(real val) { this.val = val; } }; // copied from the C code; the lm_initialize_control function turned // into a constructor struct lm_control_type { real ftol; real xtol; real gtol; real epsilon; real stepbound; real fnorm; int maxcall; lm_int_type nfev; lm_int_type info; void operator init() { maxcall = 100; epsilon = LM_USERTOL; stepbound = 100; ftol = LM_USERTOL; xtol = LM_USERTOL; gtol = LM_USERTOL; } }; // copied from the C code typedef void lm_evaluate_ftype(real[] par, int m_dat, real[] fvec, lm_data_type data, lm_int_type info); typedef void lm_print_ftype(int n_par, real[] par, int m_dat, real[] fvec, lm_data_type data, int iflag, int iter, int nfev); // copied from the C code private real SQR(real x) { return x * x; } // Asymptote doesn't support pointers to arbitrary array elements, so // we provide an offset parameter. private real lm_enorm(int n, real[] x, int offset=0) { real s1 = 0; real s2 = 0; real s3 = 0; real x1max = 0; real x3max = 0; real agiant = LM_SQRT_GIANT / n; real xabs, temp; for (int i = 0; i < n; ++i) { xabs = fabs(x[offset + i]); if (xabs > LM_SQRT_DWARF && xabs < agiant) { s2 += SQR(xabs); continue; } if (xabs > LM_SQRT_DWARF) { if (xabs > x1max) { temp = x1max / xabs; s1 = 1 + s1 * SQR(temp); x1max = xabs; } else { temp = xabs / x1max; s1 += SQR(temp); } continue; } if (xabs > x3max) { temp = x3max / xabs; s3 = 1 + s3 * SQR(temp); x3max = xabs; } else { if (xabs != 0.0) { temp = xabs / x3max; s3 += SQR(temp); } } } if (s1 != 0) return x1max * sqrt(s1 + (s2 / x1max) / x1max); if (s2 != 0) { if (s2 >= x3max) return sqrt(s2 * (1 + (x3max / s2) * (x3max * s3))); else return sqrt(x3max * ((s2 / x3max) + (x3max * s3))); } return x3max * sqrt(s3); } // This function calculated the vector whose square sum is to be // minimized. We use a slight modification of the original code that // includes the weight factor. The user may provide different // customizations. void lm_evaluate_default(real[] par, int m_dat, real[] fvec, lm_data_type data, lm_int_type info) { for (int i = 0; i < m_dat; ++i) { fvec[i] = data.user_w[i] * (data.user_y[i] - data.user_func(data.user_t[i], par)); } } // Helper functions to print padded strings and numbers (until // Asymptote provides a real printf function) private string pad(string str, int count, string pad=" ") { string res = str; while (length(res) < count) res = pad + res; return res; } private string pad(int num, int digits, string pad=" ") { return pad(string(num), digits, pad); } private string pad(real num, int digits, string pad=" ") { return pad(string(num), digits, pad); } // Similar to the C code, also prints weights void lm_print_default(int n_par, real[] par, int m_dat, real[] fvec, lm_data_type data, int iflag, int iter, int nfev) { real f, y, t, w; int i; if (iflag == 2) { write("trying step in gradient direction"); } else if (iflag == 1) { write(format("determining gradient (iteration %d)", iter)); } else if (iflag == 0) { write("starting minimization"); } else if (iflag == -1) { write(format("terminated after %d evaluations", nfev)); } write(" par: ", none); for (i = 0; i < n_par; ++i) { write(" " + pad(par[i], 12), none); } write(" => norm: " + pad(lm_enorm(m_dat, fvec), 12)); if (iflag == -1) { write(" fitting data as follows:"); for (i = 0; i < m_dat; ++i) { t = data.user_t[i]; y = data.user_y[i]; w = data.user_w[i]; f = data.user_func(t, par); write(format(" t[%2d]=", i) + pad(t, 12) + " y=" + pad(y, 12) + " w=" + pad(w, 12) + " fit=" + pad(f, 12) + " residue=" + pad(y - f, 12)); } } } // Prints nothing void lm_print_quiet(int n_par, real[] par, int m_dat, real[] fvec, lm_data_type data, int iflag, int iter, int nfev) { } // copied from the C code private void lm_qrfac(int m, int n, real[] a, bool pivot, int[] ipvt, real[] rdiag, real[] acnorm, real[] wa) { int i, j, k, kmax, minmn; real ajnorm, sum, temp; static real p05 = 0.05; for (j = 0; j < n; ++j) { acnorm[j] = lm_enorm(m, a, j * m); rdiag[j] = acnorm[j]; wa[j] = rdiag[j]; if (pivot) ipvt[j] = j; } minmn = min(m, n); for (j = 0; j < minmn; ++j) { while (pivot) { kmax = j; for (k = j + 1; k < n; ++k) if (rdiag[k] > rdiag[kmax]) kmax = k; if (kmax == j) break; for (i = 0; i < m; ++i) { temp = a[j * m + i]; a[j * m + i] = a[kmax * m + i]; a[kmax * m + i] = temp; } rdiag[kmax] = rdiag[j]; wa[kmax] = wa[j]; k = ipvt[j]; ipvt[j] = ipvt[kmax]; ipvt[kmax] = k; break; } ajnorm = lm_enorm(m - j, a, j * m + j); if (ajnorm == 0.0) { rdiag[j] = 0; continue; } if (a[j * m + j] < 0.0) ajnorm = -ajnorm; for (i = j; i < m; ++i) a[j * m + i] /= ajnorm; a[j * m + j] += 1; for (k = j + 1; k < n; ++k) { sum = 0; for (i = j; i < m; ++i) sum += a[j * m + i] * a[k * m + i]; temp = sum / a[j + m * j]; for (i = j; i < m; ++i) a[k * m + i] -= temp * a[j * m + i]; if (pivot && rdiag[k] != 0.0) { temp = a[m * k + j] / rdiag[k]; temp = max(0.0, 1 - SQR(temp)); rdiag[k] *= sqrt(temp); temp = rdiag[k] / wa[k]; if (p05 * SQR(temp) <= LM_MACHEP) { rdiag[k] = lm_enorm(m - j - 1, a, m * k + j + 1); wa[k] = rdiag[k]; } } } rdiag[j] = -ajnorm; } } // copied from the C code private void lm_qrsolv(int n, real[] r, int ldr, int[] ipvt, real[] diag, real[] qtb, real[] x, real[] sdiag, real[] wa) { static real p25 = 0.25; static real p5 = 0.5; int i, kk, j, k, nsing; real qtbpj, sum, temp; real _sin, _cos, _tan, _cot; for (j = 0; j < n; ++j) { for (i = j; i < n; ++i) r[j * ldr + i] = r[i * ldr + j]; x[j] = r[j * ldr + j]; wa[j] = qtb[j]; } for (j = 0; j < n; ++j) { while (diag[ipvt[j]] != 0.0) { for (k = j; k < n; ++k) sdiag[k] = 0.0; sdiag[j] = diag[ipvt[j]]; qtbpj = 0.; for (k = j; k < n; ++k) { if (sdiag[k] == 0.) continue; kk = k + ldr * k; if (fabs(r[kk]) < fabs(sdiag[k])) { _cot = r[kk] / sdiag[k]; _sin = p5 / sqrt(p25 + p25 * _cot * _cot); _cos = _sin * _cot; } else { _tan = sdiag[k] / r[kk]; _cos = p5 / sqrt(p25 + p25 * _tan * _tan); _sin = _cos * _tan; } r[kk] = _cos * r[kk] + _sin * sdiag[k]; temp = _cos * wa[k] + _sin * qtbpj; qtbpj = -_sin * wa[k] + _cos * qtbpj; wa[k] = temp; for (i = k + 1; i < n; ++i) { temp = _cos * r[k * ldr + i] + _sin * sdiag[i]; sdiag[i] = -_sin * r[k * ldr + i] + _cos * sdiag[i]; r[k * ldr + i] = temp; } } break; } sdiag[j] = r[j * ldr + j]; r[j * ldr + j] = x[j]; } nsing = n; for (j = 0; j < n; ++j) { if (sdiag[j] == 0.0 && nsing == n) nsing = j; if (nsing < n) wa[j] = 0; } for (j = nsing - 1; j >= 0; --j) { sum = 0; for (i = j + 1; i < nsing; ++i) sum += r[j * ldr + i] * wa[i]; wa[j] = (wa[j] - sum) / sdiag[j]; } for (j = 0; j < n; ++j) x[ipvt[j]] = wa[j]; } // copied from the C code private void lm_lmpar(int n, real[] r, int ldr, int[] ipvt, real[] diag, real[] qtb, real delta, lm_real_type par, real[] x, real[] sdiag, real[] wa1, real[] wa2) { static real p1 = 0.1; static real p001 = 0.001; int nsing = n; real parl = 0.0; int i, iter, j; real dxnorm, fp, fp_old, gnorm, parc, paru; real sum, temp; for (j = 0; j < n; ++j) { wa1[j] = qtb[j]; if (r[j * ldr + j] == 0 && nsing == n) nsing = j; if (nsing < n) wa1[j] = 0; } for (j = nsing - 1; j >= 0; --j) { wa1[j] = wa1[j] / r[j + ldr * j]; temp = wa1[j]; for (i = 0; i < j; ++i) wa1[i] -= r[j * ldr + i] * temp; } for (j = 0; j < n; ++j) x[ipvt[j]] = wa1[j]; iter = 0; for (j = 0; j < n; ++j) wa2[j] = diag[j] * x[j]; dxnorm = lm_enorm(n, wa2); fp = dxnorm - delta; if (fp <= p1 * delta) { par.val = 0; return; } if (nsing >= n) { for (j = 0; j < n; ++j) wa1[j] = diag[ipvt[j]] * wa2[ipvt[j]] / dxnorm; for (j = 0; j < n; ++j) { sum = 0.0; for (i = 0; i < j; ++i) sum += r[j * ldr + i] * wa1[i]; wa1[j] = (wa1[j] - sum) / r[j + ldr * j]; } temp = lm_enorm(n, wa1); parl = fp / delta / temp / temp; } for (j = 0; j < n; ++j) { sum = 0; for (i = 0; i <= j; ++i) sum += r[j * ldr + i] * qtb[i]; wa1[j] = sum / diag[ipvt[j]]; } gnorm = lm_enorm(n, wa1); paru = gnorm / delta; if (paru == 0.0) paru = LM_DWARF / min(delta, p1); par.val = max(par.val, parl); par.val = min(par.val, paru); if (par.val == 0.0) par.val = gnorm / dxnorm; for (;; ++iter) { if (par.val == 0.0) par.val = max(LM_DWARF, p001 * paru); temp = sqrt(par.val); for (j = 0; j < n; ++j) wa1[j] = temp * diag[j]; lm_qrsolv(n, r, ldr, ipvt, wa1, qtb, x, sdiag, wa2); for (j = 0; j < n; ++j) wa2[j] = diag[j] * x[j]; dxnorm = lm_enorm(n, wa2); fp_old = fp; fp = dxnorm - delta; if (fabs(fp) <= p1 * delta || (parl == 0.0 && fp <= fp_old && fp_old < 0.0) || iter == 10) break; for (j = 0; j < n; ++j) wa1[j] = diag[ipvt[j]] * wa2[ipvt[j]] / dxnorm; for (j = 0; j < n; ++j) { wa1[j] = wa1[j] / sdiag[j]; for (i = j + 1; i < n; ++i) wa1[i] -= r[j * ldr + i] * wa1[j]; } temp = lm_enorm(n, wa1); parc = fp / delta / temp / temp; if (fp > 0) parl = max(parl, par.val); else if (fp < 0) paru = min(paru, par.val); par.val = max(parl, par.val + parc); } } // copied from the C code; the main function void lm_lmdif(int m, int n, real[] x, real[] fvec, real ftol, real xtol, real gtol, int maxfev, real epsfcn, real[] diag, int mode, real factor, lm_int_type info, lm_int_type nfev, real[] fjac, int[] ipvt, real[] qtf, real[] wa1, real[] wa2, real[] wa3, real[] wa4, lm_evaluate_ftype evaluate, lm_print_ftype printout, lm_data_type data) { static real p1 = 0.1; static real p5 = 0.5; static real p25 = 0.25; static real p75 = 0.75; static real p0001 = 1.0e-4; nfev.val = 0; int iter = 1; lm_real_type par = lm_real_type(0); real delta = 0; real xnorm = 0; real temp = max(epsfcn, LM_MACHEP); real eps = sqrt(temp); int i, j; real actred, dirder, fnorm, fnorm1, gnorm, pnorm, prered, ratio, step, sum, temp1, temp2, temp3; if ((n <= 0) || (m < n) || (ftol < 0.0) || (xtol < 0.0) || (gtol < 0.0) || (maxfev <= 0) || (factor <= 0)) { info.val = 0; return; } if (mode == 2) { for (j = 0; j < n; ++j) { if (diag[j] <= 0.0) { info.val = 0; return; } } } info.val = 0; evaluate(x, m, fvec, data, info); if(printout != null) printout(n, x, m, fvec, data, 0, 0, ++nfev.val); if (info.val < 0) return; fnorm = lm_enorm(m, fvec); do { for (j = 0; j < n; ++j) { temp = x[j]; step = eps * fabs(temp); if (step == 0.0) step = eps; x[j] = temp + step; info.val = 0; evaluate(x, m, wa4, data, info); if(printout != null) printout(n, x, m, wa4, data, 1, iter, ++nfev.val); if (info.val < 0) return; for (i = 0; i < m; ++i) fjac[j * m + i] = (wa4[i] - fvec[i]) / (x[j] - temp); x[j] = temp; } lm_qrfac(m, n, fjac, true, ipvt, wa1, wa2, wa3); if (iter == 1) { if (mode != 2) { for (j = 0; j < n; ++j) { diag[j] = wa2[j]; if (wa2[j] == 0.0) diag[j] = 1.0; } } for (j = 0; j < n; ++j) wa3[j] = diag[j] * x[j]; xnorm = lm_enorm(n, wa3); delta = factor * xnorm; if (delta == 0.0) delta = factor; } for (i = 0; i < m; ++i) wa4[i] = fvec[i]; for (j = 0; j < n; ++j) { temp3 = fjac[j * m + j]; if (temp3 != 0.0) { sum = 0; for (i = j; i < m; ++i) sum += fjac[j * m + i] * wa4[i]; temp = -sum / temp3; for (i = j; i < m; ++i) wa4[i] += fjac[j * m + i] * temp; } fjac[j * m + j] = wa1[j]; qtf[j] = wa4[j]; } gnorm = 0; if (fnorm != 0) { for (j = 0; j < n; ++j) { if (wa2[ipvt[j]] == 0) continue; sum = 0.0; for (i = 0; i <= j; ++i) sum += fjac[j * m + i] * qtf[i] / fnorm; gnorm = max(gnorm, fabs(sum / wa2[ipvt[j]])); } } if (gnorm <= gtol) { info.val = 4; return; } if (mode != 2) { for (j = 0; j < n; ++j) diag[j] = max(diag[j], wa2[j]); } do { lm_lmpar(n, fjac, m, ipvt, diag, qtf, delta, par, wa1, wa2, wa3, wa4); for (j = 0; j < n; ++j) { wa1[j] = -wa1[j]; wa2[j] = x[j] + wa1[j]; wa3[j] = diag[j] * wa1[j]; } pnorm = lm_enorm(n, wa3); if (nfev.val <= 1 + n) delta = min(delta, pnorm); info.val = 0; evaluate(wa2, m, wa4, data, info); if(printout != null) printout(n, x, m, wa4, data, 2, iter, ++nfev.val); if (info.val < 0) return; fnorm1 = lm_enorm(m, wa4); if (p1 * fnorm1 < fnorm) actred = 1 - SQR(fnorm1 / fnorm); else actred = -1; for (j = 0; j < n; ++j) { wa3[j] = 0; for (i = 0; i <= j; ++i) wa3[i] += fjac[j * m + i] * wa1[ipvt[j]]; } temp1 = lm_enorm(n, wa3) / fnorm; temp2 = sqrt(par.val) * pnorm / fnorm; prered = SQR(temp1) + 2 * SQR(temp2); dirder = -(SQR(temp1) + SQR(temp2)); ratio = prered != 0 ? actred / prered : 0; if (ratio <= p25) { if (actred >= 0.0) temp = p5; else temp = p5 * dirder / (dirder + p5 * actred); if (p1 * fnorm1 >= fnorm || temp < p1) temp = p1; delta = temp * min(delta, pnorm / p1); par.val /= temp; } else if (par.val == 0.0 || ratio >= p75) { delta = pnorm / p5; par.val *= p5; } if (ratio >= p0001) { for (j = 0; j < n; ++j) { x[j] = wa2[j]; wa2[j] = diag[j] * x[j]; } for (i = 0; i < m; ++i) fvec[i] = wa4[i]; xnorm = lm_enorm(n, wa2); fnorm = fnorm1; ++iter; } info.val = 0; if (fabs(actred) <= ftol && prered <= ftol && p5 * ratio <= 1) info.val = 1; if (delta <= xtol * xnorm) info.val += 2; if (info.val != 0) return; if (nfev.val >= maxfev) info.val = 5; if (fabs(actred) <= LM_MACHEP && prered <= LM_MACHEP && p5 * ratio <= 1) info.val = 6; if (delta <= LM_MACHEP * xnorm) info.val = 7; if (gnorm <= LM_MACHEP) info.val = 8; if (info.val != 0) return; } while (ratio < p0001); } while (true); } // copied from the C code; wrapper of lm_lmdif void lm_minimize(int m_dat, int n_par, real[] par, lm_evaluate_ftype evaluate, lm_print_ftype printout, lm_data_type data, lm_control_type control) { int n = n_par; int m = m_dat; real[] fvec = new real[m]; real[] diag = new real[n]; real[] qtf = new real[n]; real[] fjac = new real[n * m]; real[] wa1 = new real[n]; real[] wa2 = new real[n]; real[] wa3 = new real[n]; real[] wa4 = new real[m]; int[] ipvt = new int[n]; control.info.val = 0; control.nfev.val = 0; lm_lmdif(m, n, par, fvec, control.ftol, control.xtol, control.gtol, control.maxcall * (n + 1), control.epsilon, diag, 1, control.stepbound, control.info, control.nfev, fjac, ipvt, qtf, wa1, wa2, wa3, wa4, evaluate, printout, data); if(printout != null) printout(n, par, m, fvec, data, -1, 0, control.nfev.val); control.fnorm = lm_enorm(m, fvec); if (control.info.val < 0) control.info.val = 10; } // convenience functions; wrappers of lm_minimize /* The structure FitControl specifies various control parameters. */ struct FitControl { real squareSumTolerance; // relative error desired in the sum of squares real approximationTolerance; // relative error between last two approximations real desiredOrthogonality; // orthogonality desired between the residue vector and its derivatives real epsilon; // step used to calculate the jacobian real stepBound; // initial bound to steps in the outer loop int maxIterations; // maximum number of iterations bool verbose; // whether to print detailed information about every iteration, or nothing void operator init(real squareSumTolerance=LM_USERTOL, real approximationTolerance=LM_USERTOL, real desiredOrthogonality=LM_USERTOL, real epsilon=LM_USERTOL, real stepBound=100, int maxIterations=100, bool verbose=false) { this.squareSumTolerance = squareSumTolerance; this.approximationTolerance = approximationTolerance; this.desiredOrthogonality = desiredOrthogonality; this.epsilon = epsilon; this.stepBound = stepBound; this.maxIterations = maxIterations; this.verbose = verbose; } FitControl copy() { FitControl result = new FitControl; result.squareSumTolerance = this.squareSumTolerance; result.approximationTolerance = this.approximationTolerance; result.desiredOrthogonality = this.desiredOrthogonality; result.epsilon = this.epsilon; result.stepBound = this.stepBound; result.maxIterations = this.maxIterations; result.verbose = this.verbose; return result; } }; FitControl operator init() { return FitControl(); } FitControl defaultControl; /* Upon returning, this structure provides information about the fit. */ struct FitResult { real norm; // norm of the residue vector int iterations; // actual number of iterations int status; // status of minimization void operator init(real norm, int iterations, int status) { this.norm = norm; this.iterations = iterations; this.status = status; } }; /* Fits data points to a function that depends on some parameters. Parameters: - xdata: Array of x values. - ydata: Array of y values. - errors: Array of experimental errors; each element must be strictly positive - function: Fit function. - parameters: Parameter array. Before calling fit(), this must contain the initial guesses for the parameters. Upon return, it will contain the solution parameters. - control: object of type FitControl that controls various aspects of the fitting procedure. Returns: An object of type FitResult that conveys information about the fitting process. */ FitResult fit(real[] xdata, real[] ydata, real[] errors, real function(real[], real), real[] parameters, FitControl control=defaultControl) { int m_dat = min(xdata.length, ydata.length); int n_par = parameters.length; lm_evaluate_ftype evaluate = lm_evaluate_default; lm_print_ftype printout = control.verbose ? lm_print_default : lm_print_quiet; lm_data_type data; data.user_t = xdata; data.user_y = ydata; data.user_w = 1 / errors; data.user_func = new real(real x, real[] params) { return function(params, x); }; lm_control_type ctrl; ctrl.ftol = control.squareSumTolerance; ctrl.xtol = control.approximationTolerance; ctrl.gtol = control.desiredOrthogonality; ctrl.epsilon = control.epsilon; ctrl.stepbound = control.stepBound; ctrl.maxcall = control.maxIterations; lm_minimize(m_dat, n_par, parameters, evaluate, printout, data, ctrl); return FitResult(ctrl.fnorm, ctrl.nfev.val, ctrl.info.val); } /* Fits data points to a function that depends on some parameters. Parameters: - xdata: Array of x values. - ydata: Array of y values. - function: Fit function. - parameters: Parameter array. Before calling fit(), this must contain the initial guesses for the parameters. Upon return, it will contain the solution parameters. - control: object of type FitControl that controls various aspects of the fitting procedure. Returns: An object of type FitResult that conveys information about the fitting process. */ FitResult fit(real[] xdata, real[] ydata, real function(real[], real), real[] parameters, FitControl control=defaultControl) { return fit(xdata, ydata, array(min(xdata.length, ydata.length), 1.0), function, parameters, control); } asymptote-2.37/base/markers.asy000066400000000000000000000162061265434602500166020ustar00rootroot00000000000000// Mark routines and markers written by Philippe Ivaldi. // http://www.piprime.fr/ marker operator * (transform T, marker m) { marker M=new marker; M.f=T*m.f; M.above=m.above; M.markroutine=m.markroutine; return M; } // Add n frames f midway (in arclength) between n+1 uniformly spaced marks. markroutine markinterval(int n=1, frame f, bool rotated=false) { return new void(picture pic=currentpicture, frame mark, path g) { markuniform(n+1,rotated)(pic,mark,g); markuniform(centered=true,n,rotated)(pic,f,g); }; } // Return a frame containing n copies of the path g shifted by space // drawn with pen p. frame duplicate(path g, int n=1, pair space=0, pen p=currentpen) { if(space == 0) space=dotsize(p); frame f; int pos=0; int sign=1; int m=(n+1) % 2; for(int i=1; i <= n; ++i) { draw(f,shift(space*(pos-0.5*m))*g,p); pos += i*sign; sign *= -1; } return f; } real tildemarksizefactor=5; real tildemarksize(pen p=currentpen) { static real golden=(1+sqrt(5))/2; return (1mm+tildemarksizefactor*sqrt(linewidth(p)))/golden; } frame tildeframe(int n=1, real size=0, pair space=0, real angle=0, pair offset=0, pen p=currentpen) { size=(size == 0) ? tildemarksize(p) : size; space=(space == 0) ? 1.5*size : space; path g=yscale(1.25)*((-1.5,-0.5)..(-0.75,0.5)..(0,0)..(0.75,-0.5)..(1.5,0.5)); return duplicate(shift(offset)*rotate(angle)*scale(size)*g,n,space,p); } frame tildeframe=tildeframe(); real stickmarkspacefactor=4; real stickmarksizefactor=10; real stickmarksize(pen p=currentpen) { return 1mm+stickmarksizefactor*sqrt(linewidth(p)); } real stickmarkspace(pen p=currentpen) { return stickmarkspacefactor*sqrt(linewidth(p)); } frame stickframe(int n=1, real size=0, pair space=0, real angle=0, pair offset=0, pen p=currentpen) { if(size == 0) size=stickmarksize(p); if(space == 0) space=stickmarkspace(p); return duplicate(shift(offset)*rotate(angle)*scale(0.5*size)*(N--S),n, space,p); } frame stickframe=stickframe(); real circlemarkradiusfactor=stickmarksizefactor/2; real circlemarkradius(pen p=currentpen) { static real golden=(1+sqrt(5))/2; return (1mm+circlemarkradiusfactor*sqrt(linewidth(p)))/golden; } real barmarksizefactor=stickmarksizefactor; real barmarksize(pen p=currentpen) { return 1mm+barmarksizefactor*sqrt(linewidth(p)); } frame circlebarframe(int n=1, real barsize=0, real radius=0,real angle=0, pair offset=0, pen p=currentpen, filltype filltype=NoFill, bool above=false) { if(barsize == 0) barsize=barmarksize(p); if(radius == 0) radius=circlemarkradius(p); frame opic; path g=circle(offset,radius); frame f=stickframe(n,barsize,space=2*radius/(n+1),angle,offset,p); if(above) { add(opic,f); filltype.fill(opic,g,p); } else { filltype.fill(opic,g,p); add(opic,f); } return opic; } real crossmarksizefactor=5; real crossmarksize(pen p=currentpen) { return 1mm+crossmarksizefactor*sqrt(linewidth(p)); } frame crossframe(int n=3, real size=0, pair space=0, real angle=0, pair offset=0, pen p=currentpen) { if(size == 0) size=crossmarksize(p); frame opic; draw(opic,shift(offset)*rotate(angle)*scale(size)*cross(n),p); return opic; } real markanglespacefactor=4; real markangleradiusfactor=8; real markangleradius(pen p=currentpen) { return 8mm+markangleradiusfactor*sqrt(linewidth(p)); } real markangleradius=markangleradius(); real markanglespace(pen p=currentpen) { return markanglespacefactor*sqrt(linewidth(p)); } real markanglespace=markanglespace(); // Mark the oriented angle AOB counterclockwise with optional Label, arrows, and markers. // With radius < 0, AOB-2pi is marked clockwise. void markangle(picture pic=currentpicture, Label L="", int n=1, real radius=0, real space=0, pair A, pair O, pair B, arrowbar arrow=None, pen p=currentpen, filltype filltype=NoFill, margin margin=NoMargin, marker marker=nomarker) { if(space == 0) space=markanglespace(p); if(radius == 0) radius=markangleradius(p); picture lpic,phantom; frame ff; path lpth; p=squarecap+p; pair OB=unit(B-O), OA=unit(A-O); real xoa=degrees(OA,false); real gle=degrees(acos(dot(OA,OB))); if((conj(OA)*OB).y < 0) gle *= -1; bool ccw=radius > 0; if(!ccw) radius=-radius; bool drawarrow = !arrow(phantom,arc((0,0),radius,xoa,xoa+gle,ccw),p,margin); if(drawarrow && margin == NoMargin) margin=TrueMargin(0,0.5linewidth(p)); if(filltype != NoFill) { lpth=margin(arc((0,0),radius+(n-1)*space,xoa,xoa+gle,ccw),p).g; pair p0=relpoint(lpth,0), p1=relpoint(lpth,1); pair ac=p0-p0-A+O, bd=p1-p1-B+O, det=(conj(ac)*bd).y; pair op=(det == 0) ? O : p0+(conj(p1-p0)*bd).y*ac/det; filltype.fill(ff,op--lpth--relpoint(lpth,1)--cycle,p); add(lpic,ff); } for(int i=0; i < n; ++i) { lpth=margin(arc((0,0),radius+i*space,xoa,xoa+gle,ccw),p).g; draw(lpic,lpth,p=p,arrow=arrow,margin=NoMargin,marker=marker); } Label lL=L.copy(); real position=lL.position.position.x; if(lL.defaultposition) {lL.position.relative=true; position=0.5;} if(lL.position.relative) position=reltime(lpth,position); if(lL.align.default) { lL.align.relative=true; lL.align.dir=unit(point(lpth,position)); } label(lpic,lL,point(lpth,position),align=NoAlign, p=p); add(pic,lpic,O); } marker StickIntervalMarker(int i=2, int n=1, real size=0, real space=0, real angle=0, pair offset=0, bool rotated=true, pen p=currentpen, frame uniform=newframe, bool above=true) { return marker(uniform,markinterval(i,stickframe(n,size,space,angle,offset,p), rotated),above); } marker CrossIntervalMarker(int i=2, int n=3, real size=0, real space=0, real angle=0, pair offset=0, bool rotated=true, pen p=currentpen, frame uniform=newframe, bool above=true) { return marker(uniform,markinterval(i,crossframe(n,size,space,angle,offset,p), rotated=rotated),above); } marker CircleBarIntervalMarker(int i=2, int n=1, real barsize=0, real radius=0, real angle=0, pair offset=0, bool rotated=true, pen p=currentpen, filltype filltype=NoFill, bool circleabove=false, frame uniform=newframe, bool above=true) { return marker(uniform,markinterval(i,circlebarframe(n,barsize,radius,angle, offset,p,filltype, circleabove), rotated),above); } marker TildeIntervalMarker(int i=2, int n=1, real size=0, real space=0, real angle=0, pair offset=0, bool rotated=true, pen p=currentpen, frame uniform=newframe, bool above=true) { return marker(uniform,markinterval(i,tildeframe(n,size,space,angle,offset,p), rotated),above); } asymptote-2.37/base/math.asy000066400000000000000000000247771265434602500161030ustar00rootroot00000000000000// Asymptote mathematics routines int quadrant(real degrees) { return floor(degrees/90) % 4; } // Roots of unity. pair unityroot(int n, int k=1) { return expi(2pi*k/n); } real csc(real x) {return 1/sin(x);} real sec(real x) {return 1/cos(x);} real cot(real x) {return tan(pi/2-x);} real acsc(real x) {return asin(1/x);} real asec(real x) {return acos(1/x);} real acot(real x) {return pi/2-atan(x);} real frac(real x) {return x-(int)x;} pair exp(explicit pair z) {return exp(z.x)*expi(z.y);} pair log(explicit pair z) {return log(abs(z))+I*angle(z);} // Return an Nx by Ny unit square lattice with lower-left corner at (0,0). picture grid(int Nx, int Ny, pen p=currentpen) { picture pic; for(int i=0; i <= Nx; ++i) draw(pic,(i,0)--(i,Ny),p); for(int j=0; j <= Ny; ++j) draw(pic,(0,j)--(Nx,j),p); return pic; } bool polygon(path p) { return cyclic(p) && piecewisestraight(p); } // Return the intersection time of the point on the line through p and q // that is closest to z. real intersect(pair p, pair q, pair z) { pair u=q-p; real denom=dot(u,u); return denom == 0 ? infinity : dot(z-p,u)/denom; } // Return the intersection time of the extension of the line segment PQ // with the plane perpendicular to n and passing through Z. real intersect(triple P, triple Q, triple n, triple Z) { real d=n.x*Z.x+n.y*Z.y+n.z*Z.z; real denom=n.x*(Q.x-P.x)+n.y*(Q.y-P.y)+n.z*(Q.z-P.z); return denom == 0 ? infinity : (d-n.x*P.x-n.y*P.y-n.z*P.z)/denom; } // Return any point on the intersection of the two planes with normals // n0 and n1 passing through points P0 and P1, respectively. // If the planes are parallel return (infinity,infinity,infinity). triple intersectionpoint(triple n0, triple P0, triple n1, triple P1) { real Dx=n0.y*n1.z-n1.y*n0.z; real Dy=n0.z*n1.x-n1.z*n0.x; real Dz=n0.x*n1.y-n1.x*n0.y; if(abs(Dx) > abs(Dy) && abs(Dx) > abs(Dz)) { Dx=1/Dx; real d0=n0.y*P0.y+n0.z*P0.z; real d1=n1.y*P1.y+n1.z*P1.z+n1.x*(P1.x-P0.x); real y=(d0*n1.z-d1*n0.z)*Dx; real z=(d1*n0.y-d0*n1.y)*Dx; return (P0.x,y,z); } else if(abs(Dy) > abs(Dz)) { Dy=1/Dy; real d0=n0.z*P0.z+n0.x*P0.x; real d1=n1.z*P1.z+n1.x*P1.x+n1.y*(P1.y-P0.y); real z=(d0*n1.x-d1*n0.x)*Dy; real x=(d1*n0.z-d0*n1.z)*Dy; return (x,P0.y,z); } else { if(Dz == 0) return (infinity,infinity,infinity); Dz=1/Dz; real d0=n0.x*P0.x+n0.y*P0.y; real d1=n1.x*P1.x+n1.y*P1.y+n1.z*(P1.z-P0.z); real x=(d0*n1.y-d1*n0.y)*Dz; real y=(d1*n0.x-d0*n1.x)*Dz; return (x,y,P0.z); } } // Given a real array a, return its partial sums. real[] partialsum(real[] a) { real[] b=new real[a.length]; real sum=0; for(int i=0; i < a.length; ++i) { sum += a[i]; b[i]=sum; } return b; } // Given a real array a, return its partial dx-weighted sums. real[] partialsum(real[] a, real[] dx) { real[] b=new real[a.length]; real sum=0; for(int i=0; i < a.length; ++i) { sum += a[i]*dx[i]; b[i]=sum; } return b; } // Given an integer array a, return its partial sums. int[] partialsum(int[] a) { int[] b=new int[a.length]; int sum=0; for(int i=0; i < a.length; ++i) { sum += a[i]; b[i]=sum; } return b; } // Given an integer array a, return its partial dx-weighted sums. int[] partialsum(int[] a, int[] dx) { int[] b=new int[a.length]; int sum=0; for(int i=0; i < a.length; ++i) { sum += a[i]*dx[i]; b[i]=sum; } return b; } // If strict=false, return whether i > j implies a[i] >= a[j] // If strict=true, return whether i > j implies a[i] > a[j] bool increasing(real[] a, bool strict=false) { real[] ap=copy(a); ap.delete(0); ap.push(0); bool[] b=strict ? (ap > a) : (ap >= a); b[a.length-1]=true; return all(b); } // Return the first and last indices of consecutive true-element segments // of bool[] b. int[][] segmentlimits(bool[] b) { int[][] segment; bool[] n=copy(b); n.delete(0); n.push(!b[b.length-1]); int[] edge=(b != n) ? sequence(1,b.length) : null; edge.insert(0,0); int stop=edge[0]; for(int i=1; i < edge.length; ++i) { int start=stop; stop=edge[i]; if(b[start]) segment.push(new int[] {start,stop-1}); } return segment; } // Return the indices of consecutive true-element segments of bool[] b. int[][] segment(bool[] b) { int[][] S=segmentlimits(b); return sequence(new int[](int i) { return sequence(S[i][0],S[i][1]); },S.length); } // If the sorted array a does not contain x, insert it sequentially, // returning the index of x in the resulting array. int unique(real[] a, real x) { int i=search(a,x); if(i == -1 || x != a[i]) { ++i; a.insert(i,x); } return i; } int unique(string[] a, string x) { int i=search(a,x); if(i == -1 || x != a[i]) { ++i; a.insert(i,x); } return i; } bool lexorder(pair a, pair b) { return a.x < b.x || (a.x == b.x && a.y < b.y); } bool lexorder(triple a, triple b) { return a.x < b.x || (a.x == b.x && (a.y < b.y || (a.y == b.y && a.z < b.z))); } real[] zero(int n) { return sequence(new real(int) {return 0;},n); } real[][] zero(int n, int m) { real[][] M=new real[n][]; for(int i=0; i < n; ++i) M[i]=sequence(new real(int) {return 0;},m); return M; } bool square(real[][] m) { int n=m.length; for(int i=0; i < n; ++i) if(m[i].length != n) return false; return true; } bool rectangular(real[][] m) { int n=m.length; if(n > 0) { int m0=m[0].length; for(int i=1; i < n; ++i) if(m[i].length != m0) return false; } return true; } bool rectangular(pair[][] m) { int n=m.length; if(n > 0) { int m0=m[0].length; for(int i=1; i < n; ++i) if(m[i].length != m0) return false; } return true; } bool rectangular(triple[][] m) { int n=m.length; if(n > 0) { int m0=m[0].length; for(int i=1; i < n; ++i) if(m[i].length != m0) return false; } return true; } // draw the (infinite) line going through P and Q, without altering the // size of picture pic. void drawline(picture pic=currentpicture, pair P, pair Q, pen p=currentpen) { pic.add(new void (frame f, transform t, transform T, pair m, pair M) { // Reduce the bounds by the size of the pen. m -= min(p); M -= max(p); // Calculate the points and direction vector in the transformed space. t=t*T; pair z=t*P; pair v=t*Q-z; // Handle horizontal and vertical lines. if(v.x == 0) { if(m.x <= z.x && z.x <= M.x) draw(f,(z.x,m.y)--(z.x,M.y),p); } else if(v.y == 0) { if(m.y <= z.y && z.y <= M.y) draw(f,(m.x,z.y)--(M.x,z.y),p); } else { // Calculate the maximum and minimum t values allowed for the // parametric equation z + t*v real mx=(m.x-z.x)/v.x, Mx=(M.x-z.x)/v.x; real my=(m.y-z.y)/v.y, My=(M.y-z.y)/v.y; real tmin=max(v.x > 0 ? mx : Mx, v.y > 0 ? my : My); real tmax=min(v.x > 0 ? Mx : mx, v.y > 0 ? My : my); if(tmin <= tmax) draw(f,z+tmin*v--z+tmax*v,p); } },true); } real interpolate(real[] x, real[] y, real x0, int i) { int n=x.length; if(n == 0) abort("Zero data points in interpolate"); if(n == 1) return y[0]; if(i < 0) { real dx=x[1]-x[0]; return y[0]+(y[1]-y[0])/dx*(x0-x[0]); } if(i >= n-1) { real dx=x[n-1]-x[n-2]; return y[n-1]+(y[n-1]-y[n-2])/dx*(x0-x[n-1]); } real D=x[i+1]-x[i]; real B=(x0-x[i])/D; real A=1.0-B; return A*y[i]+B*y[i+1]; } // Linearly interpolate data points (x,y) to (x0,y0), where the elements of // real[] x are listed in ascending order and return y0. Values outside the // available data range are linearly extrapolated using the first derivative // at the nearest endpoint. real interpolate(real[] x, real[] y, real x0) { return interpolate(x,y,x0,search(x,x0)); } private string nopoint="point not found"; // Return the nth intersection time of path g with the vertical line through x. real time(path g, real x, int n=0) { real[] t=times(g,x); if(t.length <= n) abort(nopoint); return t[n]; } // Return the nth intersection time of path g with the horizontal line through // (0,z.y). real time(path g, explicit pair z, int n=0) { real[] t=times(g,z); if(t.length <= n) abort(nopoint); return t[n]; } // Return the nth y value of g at x. real value(path g, real x, int n=0) { return point(g,time(g,x,n)).y; } // Return the nth x value of g at y=z.y. real value(path g, explicit pair z, int n=0) { return point(g,time(g,(0,z.y),n)).x; } // Return the nth slope of g at x. real slope(path g, real x, int n=0) { pair a=dir(g,time(g,x,n)); return a.y/a.x; } // Return the nth slope of g at y=z.y. real slope(path g, explicit pair z, int n=0) { pair a=dir(g,time(g,(0,z.y),n)); return a.y/a.x; } // A quartic complex root solver based on these references: // http://planetmath.org/encyclopedia/GaloisTheoreticDerivationOfTheQuarticFormula.html // Neumark, S., Solution of Cubic and Quartic Equations, Pergamon Press // Oxford (1965). pair[] quarticroots(real a, real b, real c, real d, real e) { real Fuzz=100000*realEpsilon; // Remove roots at numerical infinity. if(abs(a) <= Fuzz*(abs(b)+Fuzz*(abs(c)+Fuzz*(abs(d)+Fuzz*abs(e))))) return cubicroots(b,c,d,e); // Detect roots at numerical zero. if(abs(e) <= Fuzz*(abs(d)+Fuzz*(abs(c)+Fuzz*(abs(b)+Fuzz*abs(a))))) return cubicroots(a,b,c,d); real ainv=1/a; b *= ainv; c *= ainv; d *= ainv; e *= ainv; pair[] roots; real[] T=cubicroots(1,-2c,c^2+b*d-4e,d^2+b^2*e-b*c*d); if(T.length == 0) return roots; real t0=T[0]; pair[] sum=quadraticroots((1,0),(b,0),(t0,0)); pair[] product=quadraticroots((1,0),(t0-c,0),(e,0)); if(abs(sum[0]*product[0]+sum[1]*product[1]+d) < abs(sum[0]*product[1]+sum[1]*product[0]+d)) product=reverse(product); for(int i=0; i < 2; ++i) roots.append(quadraticroots((1,0),-sum[i],product[i])); return roots; } pair[][] fft(pair[][] a, int sign=1) { pair[][] A=new pair[a.length][]; int k=0; for(pair[] v : a) { A[k]=fft(v,sign); ++k; } a=transpose(A); k=0; for(pair[] v : a) { A[k]=fft(v,sign); ++k; } return transpose(A); } // Given a matrix A with independent columns, return // the unique vector y minimizing |Ay - b|^2 (the L2 norm). // If the columns of A are not linearly independent, // throw an error (if warn == true) or return an empty array // (if warn == false). real[] leastsquares(real[][] A, real[] b, bool warn=true) { real[] solution=solve(AtA(A),b*A,warn=false); if (solution.length == 0 && warn) abort("Cannot compute least-squares approximation for " + "a matrix with linearly dependent columns."); return solution; } asymptote-2.37/base/metapost.asy000066400000000000000000000003751265434602500167720ustar00rootroot00000000000000// MetaPost compatibility routines path cuttings; path cutbefore(path p, path q) { slice s=firstcut(p,q); cuttings=s.before; return s.after; } path cutafter(path p, path q) { slice s=lastcut(p,q); cuttings=s.after; return s.before; } asymptote-2.37/base/nopapersize.ps000066400000000000000000000000471265434602500173170ustar00rootroot00000000000000@ a4size 0in 0in @ letterSize 0in 0in asymptote-2.37/base/obj.asy000066400000000000000000000063171265434602500157120ustar00rootroot00000000000000// A module for reading simple obj files with groups. // Authors: Jens Schwaiger and John Bowman // // Here simple means that : // // 1) all vertex statements should come before the face statements; // // 2) face informations with respect to texture and/or normal vectors are // ignored; // // 3) face statements only contain positive numbers(no relative positions). // // The reading process only takes into account lines starting with "v" or // "f" or "g"(group). import three; struct obj { surface s; material[] surfacepen; pen[] meshpen; path3[][] read(string datafile, bool verbose=false) { file in=input(datafile).word().line(); triple[] vert; path3[][] g; g[0]=new path3[] ; string[] G; void Vertex(real x,real y ,real z) {vert.push((x,y,z));} void Face(int[] vertnr, int groupnr) { guide3 gh; for(int i=0; i < vertnr.length; ++i) gh=gh--vert[vertnr[i]-1]; gh=gh--cycle; g[groupnr].push(gh); } if(verbose) write("Reading data from "+datafile+"."); int groupnr; while(true) { string[] str=in; if(str.length == 0) break; str=sequence(new string(int i) {return split(str[i],"/")[0];},str.length); if(str[0] == "g" && str.length > 1) { int tst=find(G == str[1]); if(tst == -1) { G.push(str[1]); groupnr=G.length-1; g[groupnr]=new path3[] ; } if(tst > -1) groupnr=tst; } if(str[0] == "v") Vertex((real) str[1],(real) str[2],(real) str[3]); if(str[0] == "f") { int[] vertnr; for(int i=1; i < str.length; ++i) vertnr[i-1]=(int) str[i]; Face(vertnr,groupnr); } if(eof(in)) break; } close(in); if(verbose) { write("Number of groups: ",G.length); write("Groups and their names:"); write(G); write("Reading done."); write("Number of faces contained in the groups: "); for(int j=0; j < G.length; ++j) write(G[j],": ",(string) g[j].length); } return g; } void operator init(path3[][] g, material[] surfacepen, pen[] meshpen) { for(int i=0; i < g.length; ++i) { path3[] gi=g[i]; for(int j=0; j < gi.length; ++j) { // Treat all faces as planar to avoid subdivision cracks. surface sij=surface(gi[j],planar=true); s.append(sij); this.surfacepen.append(array(sij.s.length,surfacepen[i])); this.meshpen.append(array(sij.s.length,meshpen[i])); } } } void operator init(string datafile, bool verbose=false, material[] surfacepen, pen[] meshpen=nullpens) { operator init(read(datafile,verbose),surfacepen,meshpen); } void operator init(string datafile, bool verbose=false, material surfacepen, pen meshpen=nullpen) { material[] surfacepen={surfacepen}; pen[] meshpen={meshpen}; surfacepen.cyclic=true; meshpen.cyclic=true; operator init(read(datafile,verbose),surfacepen,meshpen); } } obj operator * (transform3 T, obj o) { obj ot; ot.s=T*o.s; ot.surfacepen=copy(o.surfacepen); ot.meshpen=copy(o.meshpen); return ot; } void draw(picture pic=currentpicture, obj o, light light=currentlight) { draw(pic,o.s,o.surfacepen,o.meshpen,light); } asymptote-2.37/base/ode.asy000066400000000000000000000355361265434602500157140ustar00rootroot00000000000000real stepfactor=2; // Maximum dynamic step size adjustment factor. struct coefficients { real[] steps; real[] factors; real[][] weights; real[] highOrderWeights; real[] lowOrderWeights; } struct RKTableau { int order; coefficients a; void stepDependence(real h, real c, coefficients a) {} real pgrow; real pshrink; bool exponential; void operator init(int order, real[][] weights, real[] highOrderWeights, real[] lowOrderWeights=new real[], real[] steps=sequence(new real(int i) { return sum(weights[i]);},weights.length), void stepDependence(real, real, coefficients)=null) { this.order=order; a.steps=steps; a.factors=array(a.steps.length+1,1); a.weights=weights; a.highOrderWeights=highOrderWeights; a.lowOrderWeights=lowOrderWeights; if(stepDependence != null) { this.stepDependence=stepDependence; exponential=true; } pgrow=(order > 0) ? 1/order : 0; pshrink=(order > 1) ? 1/(order-1) : pgrow; } } real[] Coeff={1,1/2,1/6,1/24,1/120,1/720,1/5040,1/40320,1/362880,1/3628800, 1/39916800.0,1/479001600.0,1/6227020800.0,1/87178291200.0, 1/1307674368000.0,1/20922789888000.0,1/355687428096000.0, 1/6402373705728000.0,1/121645100408832000.0, 1/2432902008176640000.0,1/51090942171709440000.0, 1/1124000727777607680000.0}; real phi1(real x) {return x != 0 ? expm1(x)/x : 1;} real phi2(real x) { real x2=x*x; if(fabs(x) > 1) return (exp(x)-x-1)/x2; real x3=x2*x; real x5=x2*x3; if(fabs(x) < 0.1) return Coeff[1]+x*Coeff[2]+x2*Coeff[3]+x3*Coeff[4]+x2*x2*Coeff[5] +x5*Coeff[6]+x3*x3*Coeff[7]+x5*x2*Coeff[8]+x5*x3*Coeff[9]; else { real x7=x5*x2; real x8=x7*x; return Coeff[1]+x*Coeff[2]+x2*Coeff[3]+x3*Coeff[4]+x2*x2*Coeff[5] +x5*Coeff[6]+x3*x3*Coeff[7]+x7*Coeff[8]+x8*Coeff[9] +x8*x*Coeff[10]+x5*x5*Coeff[11]+x8*x3*Coeff[12]+x7*x5*Coeff[13]+ x8*x5*Coeff[14]+x7*x7*Coeff[15]+x8*x7*Coeff[16]+x8*x8*Coeff[17]; } } real phi3(real x) { real x2=x*x; real x3=x2*x; if(fabs(x) > 1.6) return (exp(x)-0.5*x2-x-1)/x3; real x5=x2*x3; if(fabs(x) < 0.1) return Coeff[2]+x*Coeff[3]+x2*Coeff[4]+x3*Coeff[5] +x2*x2*Coeff[6]+x5*Coeff[7]+x3*x3*Coeff[8]+x5*x2*Coeff[9] +x5*x3*Coeff[10]; else { real x7=x5*x2; real x8=x7*x; real x16=x8*x8; return Coeff[2]+x*Coeff[3]+x2*Coeff[4]+x3*Coeff[5] +x2*x2*Coeff[6]+x5*Coeff[7]+x3*x3*Coeff[8]+x5*x2*Coeff[9] +x5*x3*Coeff[10]+x8*x*Coeff[11] +x5*x5*Coeff[12]+x8*x3*Coeff[13]+x7*x5*Coeff[14] +x8*x5*Coeff[15]+x7*x7*Coeff[16]+x8*x7*Coeff[17]+x16*Coeff[18] +x16*x*Coeff[19]+x16*x2*Coeff[20]; } } void expfactors(real x, coefficients a) { for(int i=0; i < a.steps.length; ++i) a.factors[i]=exp(x*a.steps[i]); a.factors[a.steps.length]=exp(x); } // First-Order Euler RKTableau Euler=RKTableau(1,new real[][], new real[] {1}); // First-Order Exponential Euler RKTableau E_Euler=RKTableau(1,new real[][], new real[] {1}, new void(real h, real c, coefficients a) { real x=-c*h; expfactors(x,a); a.highOrderWeights[0]=phi1(x); }); // Second-Order Runge-Kutta RKTableau RK2=RKTableau(2,new real[][] {{1/2}}, new real[] {0,1}, // 2nd order new real[] {1,0}); // 1st order // Second-Order Exponential Runge-Kutta RKTableau E_RK2=RKTableau(2,new real[][] {{1/2}}, new real[] {0,1}, // 2nd order new real[] {1,0}, // 1st order new void(real h, real c, coefficients a) { real x=-c*h; expfactors(x,a); a.weights[0][0]=1/2*phi1(x/2); real w=phi1(x); a.highOrderWeights[0]=0; a.highOrderWeights[1]=w; a.lowOrderWeights[0]=w; }); // Second-Order Predictor-Corrector RKTableau PC=RKTableau(2,new real[][] {{1}}, new real[] {1/2,1/2}, // 2nd order new real[] {1,0}); // 1st order // Second-Order Exponential Predictor-Corrector RKTableau E_PC=RKTableau(2,new real[][] {{1}}, new real[] {1/2,1/2}, // 2nd order new real[] {1,0}, // 1st order new void(real h, real c, coefficients a) { real x=-c*h; expfactors(x,a); real w=phi1(x); a.weights[0][0]=w; a.highOrderWeights[0]=w/2; a.highOrderWeights[1]=w/2; a.lowOrderWeights[0]=w; }); // Third-Order Classical Runge-Kutta RKTableau RK3=RKTableau(3,new real[][] {{1/2},{-1,2}}, new real[] {1/6,2/3,1/6}); // Third-Order Bogacki-Shampine Runge-Kutta RKTableau RK3BS=RKTableau(3,new real[][] {{1/2},{0,3/4}}, new real[] {2/9,1/3,4/9}, // 3rd order new real[] {7/24,1/4,1/3,1/8}); // 2nd order // Third-Order Exponential Bogacki-Shampine Runge-Kutta RKTableau E_RK3BS=RKTableau(3,new real[][] {{1/2},{0,3/4}}, new real[] {2/9,1/3,4/9}, // 3rd order new real[] {7/24,1/4,1/3,1/8}, // 2nd order new void(real h, real c, coefficients a) { real x=-c*h; expfactors(x,a); real w=phi1(x); real w2=phi2(x); a.weights[0][0]=1/2*phi1(x/2); real a11=9/8*phi2(3/4*x)+3/8*phi2(x/2); a.weights[1][0]=3/4*phi1(3/4*x)-a11; a.weights[1][1]=a11; real a21=1/3*w; real a22=4/3*w2-2/9*w; a.highOrderWeights[0]=w-a21-a22; a.highOrderWeights[1]=a21; a.highOrderWeights[2]=a22; a.lowOrderWeights[0]=w-17/12*w2; a.lowOrderWeights[1]=w2/2; a.lowOrderWeights[2]=2/3*w2; a.lowOrderWeights[3]=w2/4; }); // Fourth-Order Classical Runge-Kutta RKTableau RK4=RKTableau(4,new real[][] {{1/2},{0,1/2},{0,0,1}}, new real[] {1/6,1/3,1/3,1/6}); // Fifth-Order Cash-Karp Runge-Kutta RKTableau RK5=RKTableau(5,new real[][] {{1/5}, {3/40,9/40}, {3/10,-9/10,6/5}, {-11/54,5/2,-70/27,35/27}, {1631/55296,175/512,575/13824, 44275/110592,253/4096}}, new real[] {37/378,0,250/621,125/594, 0,512/1771}, // 5th order new real[] {2825/27648,0,18575/48384,13525/55296, 277/14336,1/4}); // 4th order // Fifth-Order Fehlberg Runge-Kutta RKTableau RK5F=RKTableau(5,new real[][] {{1/4}, {3/32,9/32}, {1932/2197,-7200/2197,7296/2197}, {439/216,-8,3680/513,-845/4104}, {-8/27,2,-3544/2565,1859/4104, -11/40}}, new real[] {16/135,0,6656/12825,28561/56430,-9/50,2/55}, // 5th order new real[] {25/216,0,1408/2565,2197/4104,-1/5,0}); // 4th order // Fifth-Order Dormand-Prince Runge-Kutta RKTableau RK5DP=RKTableau(5,new real[][] {{1/5}, {3/40,9/40}, {44/45,-56/15,32/9}, {19372/6561,-25360/2187,64448/6561, -212/729}, {9017/3168,-355/33,46732/5247,49/176, -5103/18656}}, new real[] {35/384,0,500/1113,125/192,-2187/6784, 11/84}, // 5th order new real[] {5179/57600,0,7571/16695,393/640, -92097/339200,187/2100,1/40}); // 4th order real error(real error, real initial, real lowOrder, real norm, real diff) { if(initial != 0 && lowOrder != initial) { static real epsilon=realMin/realEpsilon; real denom=max(abs(norm),abs(initial))+epsilon; return max(error,max(abs(diff)/denom)); } return error; } void report(real old, real h, real t) { write("Time step changed from "+(string) old+" to "+(string) h+" at t="+ (string) t+"."); } real adjust(real h, real error, real tolmin, real tolmax, RKTableau tableau) { if(error > tolmax) h *= max((tolmin/error)^tableau.pshrink,1/stepfactor); else if(error > 0 && error < tolmin) h *= min((tolmin/error)^tableau.pgrow,stepfactor); return h; } struct solution { real[] t; real[] y; } void write(solution S) { for(int i=0; i < S.t.length; ++i) write(S.t[i],S.y[i]); } // Integrate dy/dt+cy=f(t,y) from a to b using initial conditions y, // specifying either the step size h or the number of steps n. solution integrate(real y, real c=0, real f(real t, real y), real a, real b=a, real h=0, int n=0, bool dynamic=false, real tolmin=0, real tolmax=0, real dtmin=0, real dtmax=realMax, RKTableau tableau, bool verbose=false) { solution S; S.t=new real[] {a}; S.y=new real[]{y}; if(h == 0) { if(b == a) return S; if(n == 0) abort("Either n or h must be specified"); else h=(b-a)/n; } real F(real t, real y)=(c == 0 || tableau.exponential) ? f : new real(real t, real y) {return f(t,y)-c*y;}; tableau.stepDependence(h,c,tableau.a); real t=a; real f0; if(tableau.a.lowOrderWeights.length == 0) dynamic=false; bool fsal=dynamic && (tableau.a.lowOrderWeights.length > tableau.a.highOrderWeights.length); if(fsal) f0=F(t,y); real dt=h; while(t < b) { h=min(h,b-t); if(t+h == t) break; if(h != dt) { if(verbose) report(dt,h,t); tableau.stepDependence(h,c,tableau.a); dt=h; } real[] predictions={fsal ? f0 : F(t,y)}; for(int i=0; i < tableau.a.steps.length; ++i) predictions.push(F(t+h*tableau.a.steps[i], tableau.a.factors[i]*y+h*dot(tableau.a.weights[i], predictions))); real highOrder=h*dot(tableau.a.highOrderWeights,predictions); real y0=tableau.a.factors[tableau.a.steps.length]*y; if(dynamic) { real f1; if(fsal) { f1=F(t+h,y0+highOrder); predictions.push(f1); } real lowOrder=h*dot(tableau.a.lowOrderWeights,predictions); real error; error=error(error,y,y0+lowOrder,y0+highOrder,highOrder-lowOrder); h=adjust(h,error,tolmin,tolmax,tableau); if(h >= dt) { t += dt; y=y0+highOrder; S.t.push(t); S.y.push(y); f0=f1; } h=min(max(h,dtmin),dtmax); } else { t += h; y=y0+highOrder; S.y.push(y); } } return S; } struct Solution { real[] t; real[][] y; } void write(Solution S) { for(int i=0; i < S.t.length; ++i) { write(S.t[i],tab); for(real y : S.y[i]) write(y,tab); write(); } } // Integrate a set of equations, dy/dt=f(t,y), from a to b using initial // conditions y, specifying either the step size h or the number of steps n. Solution integrate(real[] y, real[] f(real t, real[] y), real a, real b=a, real h=0, int n=0, bool dynamic=false, real tolmin=0, real tolmax=0, real dtmin=0, real dtmax=realMax, RKTableau tableau, bool verbose=false) { Solution S; S.t=new real[] {a}; S.y=new real[][] {copy(y)}; if(h == 0) { if(b == a) return S; if(n == 0) abort("Either n or h must be specified"); else h=(b-a)/n; } real t=a; real[] f0; if(tableau.a.lowOrderWeights.length == 0) dynamic=false; bool fsal=dynamic && (tableau.a.lowOrderWeights.length > tableau.a.highOrderWeights.length); if(fsal) f0=f(t,y); real dt=h; while(t < b) { h=min(h,b-t); if(t+h == t) break; if(h != dt) { if(verbose) report(dt,h,t); dt=h; } real[][] predictions={fsal ? f0 : f(t,y)}; for(int i=0; i < tableau.a.steps.length; ++i) predictions.push(f(t+h*tableau.a.steps[i], y+h*tableau.a.weights[i]*predictions)); real[] highOrder=h*tableau.a.highOrderWeights*predictions; if(dynamic) { real[] f1; if(fsal) { f1=f(t+h,y+highOrder); predictions.push(f1); } real[] lowOrder=h*tableau.a.lowOrderWeights*predictions; real error; for(int i=0; i < y.length; ++i) error=error(error,y[i],y[i]+lowOrder[i],y[i]+highOrder[i], highOrder[i]-lowOrder[i]); h=adjust(h,error,tolmin,tolmax,tableau); if(h >= dt) { t += dt; y += highOrder; S.t.push(t); S.y.push(y); f0=f1; } h=min(max(h,dtmin),dtmax); } else { t += h; y += highOrder; S.t.push(t); S.y.push(y); } } return S; } real[][] finiteDifferenceJacobian(real[] f(real[]), real[] t, real[] h=sqrtEpsilon*abs(t)) { real[] ft=f(t); real[][] J=new real[t.length][ft.length]; real[] ti=copy(t); real tlast=ti[0]; ti[0] += h[0]; J[0]=(f(ti)-ft)/h[0]; for(int i=1; i < t.length; ++i) { ti[i-1]=tlast; tlast=ti[i]; ti[i] += h[i]; J[i]=(f(ti)-ft)/h[i]; } return transpose(J); } // Solve simultaneous nonlinear system by Newton's method. real[] newton(int iterations=100, real[] f(real[]), real[][] jacobian(real[]), real[] t) { real[] t=copy(t); for(int i=0; i < iterations; ++i) t += solve(jacobian(t),-f(t)); return t; } real[] solveBVP(real[] f(real, real[]), real a, real b=a, real h=0, int n=0, bool dynamic=false, real tolmin=0, real tolmax=0, real dtmin=0, real dtmax=realMax, RKTableau tableau, bool verbose=false, real[] initial(real[]), real[] discrepancy(real[]), real[] guess, int iterations=100) { real[] g(real[] t) { real[][] y=integrate(initial(t),f,a,b,h,n,dynamic,tolmin,tolmax,dtmin,dtmax, tableau,verbose).y;return discrepancy(y[y.length-1]); } real[][] jacobian(real[] t) {return finiteDifferenceJacobian(g,t);} return initial(newton(iterations,g,jacobian,guess)); } asymptote-2.37/base/palette.asy000066400000000000000000000344731265434602500166020ustar00rootroot00000000000000private import graph; private transform swap=(0,0,0,1,1,0); typedef bounds range(picture pic, real min, real max); range Range(bool automin=false, real min=-infinity, bool automax=false, real max=infinity) { return new bounds(picture pic, real dmin, real dmax) { // autoscale routine finds reasonable limits bounds mz=autoscale(pic.scale.z.T(dmin), pic.scale.z.T(dmax), pic.scale.z.scale); // If automin/max, use autoscale result, else // if min/max is finite, use specified value, else // use minimum/maximum data value real pmin=automin ? pic.scale.z.Tinv(mz.min) : (finite(min) ? min : dmin); real pmax=automax ? pic.scale.z.Tinv(mz.max) : (finite(max) ? max : dmax); return bounds(pmin,pmax); }; } range Automatic=Range(true,true); range Full=Range(); void image(frame f, real[][] data, pair initial, pair final, pen[] palette, bool transpose=(initial.x < final.x && initial.y < final.y), transform t=identity(), bool copy=true, bool antialias=false) { transform T=transpose ? swap : identity(); _image(f,copy ? copy(data) : data,T*initial,T*final,palette,t*T,copy=false, antialias=antialias); } void image(frame f, pen[][] data, pair initial, pair final, bool transpose=(initial.x < final.x && initial.y < final.y), transform t=identity(), bool copy=true, bool antialias=false) { transform T=transpose ? swap : identity(); _image(f,copy ? copy(data) : data,T*initial,T*final,t*T,copy=false, antialias=antialias); } // Reduce color palette to approximate range of data relative to "display" // range => errors of 1/palette.length in resulting color space. pen[] adjust(picture pic, real min, real max, real rmin, real rmax, pen[] palette) { real dmin=pic.scale.z.T(min); real dmax=pic.scale.z.T(max); real delta=rmax-rmin; if(delta > 0) { real factor=palette.length/delta; int minindex=floor(factor*(dmin-rmin)); if(minindex < 0) minindex=0; int maxindex=ceil(factor*(dmax-rmin)); if(maxindex > palette.length) maxindex=palette.length; if(minindex > 0 || maxindex < palette.length) return palette[minindex:maxindex]; } return palette; } private real[] sequencereal; bounds image(picture pic=currentpicture, real[][] f, range range=Full, pair initial, pair final, pen[] palette, bool transpose=(initial.x < final.x && initial.y < final.y), bool copy=true, bool antialias=false) { if(copy) f=copy(f); if(copy) palette=copy(palette); real m=min(f); real M=max(f); bounds bounds=range(pic,m,M); real rmin=pic.scale.z.T(bounds.min); real rmax=pic.scale.z.T(bounds.max); palette=adjust(pic,m,M,rmin,rmax,palette); // Crop data to allowed range and scale if(range != Full || pic.scale.z.scale.T != identity || pic.scale.z.postscale.T != identity) { scalefcn T=pic.scale.z.T; real m=bounds.min; real M=bounds.max; for(int i=0; i < f.length; ++i) f[i]=map(new real(real x) {return T(min(max(x,m),M));},f[i]); } initial=Scale(pic,initial); final=Scale(pic,final); pic.addBox(initial,final); transform T; if(transpose) { T=swap; initial=T*initial; final=T*final; } pic.add(new void(frame F, transform t) { _image(F,f,initial,final,palette,t*T,copy=false,antialias=antialias); },true); return bounds; // Return bounds used for color space } bounds image(picture pic=currentpicture, real f(real, real), range range=Full, pair initial, pair final, int nx=ngraph, int ny=nx, pen[] palette, bool antialias=false) { // Generate data, taking scaling into account real xmin=pic.scale.x.T(initial.x); real xmax=pic.scale.x.T(final.x); real ymin=pic.scale.y.T(initial.y); real ymax=pic.scale.y.T(final.y); real[][] data=new real[ny][nx]; for(int j=0; j < ny; ++j) { real y=pic.scale.y.Tinv(interp(ymin,ymax,(j+0.5)/ny)); scalefcn Tinv=pic.scale.x.Tinv; // Take center point of each bin data[j]=sequence(new real(int i) { return f(Tinv(interp(xmin,xmax,(i+0.5)/nx)),y); },nx); } return image(pic,data,range,initial,final,palette,transpose=false, copy=false,antialias=antialias); } void image(picture pic=currentpicture, pen[][] data, pair initial, pair final, bool transpose=(initial.x < final.x && initial.y < final.y), bool copy=true, bool antialias=false) { if(copy) data=copy(data); initial=Scale(pic,initial); final=Scale(pic,final); pic.addBox(initial,final); transform T; if(transpose) { T=swap; initial=T*initial; final=T*final; } pic.add(new void(frame F, transform t) { _image(F,data,initial,final,t*T,copy=false,antialias=antialias); },true); } void image(picture pic=currentpicture, pen f(int, int), int width, int height, pair initial, pair final, bool transpose=(initial.x < final.x && initial.y < final.y), bool antialias=false) { initial=Scale(pic,initial); final=Scale(pic,final); pic.addBox(initial,final); transform T; if(transpose) { T=swap; int temp=width; width=height; height=temp; initial=T*initial; final=T*final; } pic.add(new void(frame F, transform t) { _image(F,f,width,height,initial,final,t*T,antialias=antialias); },true); } bounds image(picture pic=currentpicture, pair[] z, real[] f, range range=Full, pen[] palette) { if(z.length != f.length) abort("z and f arrays have different lengths"); real m=min(f); real M=max(f); bounds bounds=range(pic,m,M); real rmin=pic.scale.z.T(bounds.min); real rmax=pic.scale.z.T(bounds.max); palette=adjust(pic,m,M,rmin,rmax,palette); rmin=max(rmin,m); rmax=min(rmax,M); // Crop data to allowed range and scale if(range != Full || pic.scale.z.scale.T != identity || pic.scale.z.postscale.T != identity) { scalefcn T=pic.scale.z.T; real m=bounds.min; real M=bounds.max; f=map(new real(real x) {return T(min(max(x,m),M));},f); } int[] edges={0,0,1}; int N=palette.length-1; int[][] trn=triangulate(z); real step=rmax == rmin ? 0.0 : N/(rmax-rmin); for(int i=0; i < trn.length; ++i) { int[] trni=trn[i]; int i0=trni[0], i1=trni[1], i2=trni[2]; pen color(int i) {return palette[round((f[i]-rmin)*step)];} gouraudshade(pic,z[i0]--z[i1]--z[i2]--cycle, new pen[] {color(i0),color(i1),color(i2)},edges); } return bounds; // Return bounds used for color space } bounds image(picture pic=currentpicture, real[] x, real[] y, real[] f, range range=Full, pen[] palette) { int n=x.length; if(n != y.length) abort("x and y arrays have different lengths"); pair[] z=sequence(new pair(int i) {return (x[i],y[i]);},n); return image(pic,z,f,range,palette); } // Construct a pen[] array from f using the specified palette. pen[] palette(real[] f, pen[] palette) { real Min=min(f); real Max=max(f); if(palette.length == 0) return new pen[]; real step=Max == Min ? 0.0 : (palette.length-1)/(Max-Min); return sequence(new pen(int i) {return palette[round((f[i]-Min)*step)];}, f.length); } // Construct a pen[][] array from f using the specified palette. pen[][] palette(real[][] f, pen[] palette) { real Min=min(f); real Max=max(f); int n=f.length; int m=n > 0 ? f[0].length : 0; pen[][] p=new pen[n][m]; real step=(Max == Min) ? 0.0 : (palette.length-1)/(Max-Min); for(int i=0; i < n; ++i) { real[] fi=f[i]; p[i]=sequence(new pen(int j) {return palette[round((fi[j]-Min)*step)];},m); } return p; } typedef ticks paletteticks(int sign=-1); paletteticks PaletteTicks(Label format="", ticklabel ticklabel=null, bool beginlabel=true, bool endlabel=true, int N=0, int n=0, real Step=0, real step=0, pen pTick=nullpen, pen ptick=nullpen) { return new ticks(int sign=-1) { format.align(sign > 0 ? RightSide : LeftSide); return Ticks(sign,format,ticklabel,beginlabel,endlabel,N,n,Step,step, true,true,extend=true,pTick,ptick); }; } paletteticks PaletteTicks=PaletteTicks(); void palette(picture pic=currentpicture, Label L="", bounds bounds, pair initial, pair final, axis axis=Right, pen[] palette, pen p=currentpen, paletteticks ticks=PaletteTicks, bool copy=true, bool antialias=false) { real initialz=pic.scale.z.T(bounds.min); real finalz=pic.scale.z.T(bounds.max); bounds mz=autoscale(initialz,finalz,pic.scale.z.scale); axisT axis; axis(pic,axis); real angle=degrees(axis.align.dir); initial=Scale(pic,initial); final=Scale(pic,final); pair lambda=final-initial; bool vertical=(floor((angle+45)/90) % 2 == 0); pair perp,par; if(vertical) {perp=E; par=N;} else {perp=N; par=E;} path g=(final-dot(lambda,par)*par)--final; path g2=initial--final-dot(lambda,perp)*perp; if(sgn(dot(lambda,perp)*dot(axis.align.dir,perp)) == -1) { path tmp=g; g=g2; g2=tmp; } if(copy) palette=copy(palette); Label L=L.copy(); if(L.defaultposition) L.position(0.5); L.align(axis.align); L.p(p); if(vertical && L.defaulttransform) { frame f; add(f,Label(L.s,(0,0),L.p)); if(length(max(f)-min(f)) > ylabelwidth*fontsize(L.p)) L.transform(rotate(90)); } real[][] pdata={sequence(palette.length)}; transform T; pair Tinitial,Tfinal; if(vertical) { T=swap; Tinitial=T*initial; Tfinal=T*final; } else { Tinitial=initial; Tfinal=final; } pic.add(new void(frame f, transform t) { _image(f,pdata,Tinitial,Tfinal,palette,t*T,copy=false, antialias=antialias); },true); ticklocate locate=ticklocate(initialz,finalz,pic.scale.z,mz.min,mz.max); axis(pic,L,g,g2,p,ticks(sgn(axis.side.x*dot(lambda,par))),locate,mz.divisor, true); pic.add(new void(frame f, transform t) { pair Z0=t*initial; pair Z1=t*final; draw(f,Z0--(Z0.x,Z1.y)--Z1--(Z1.x,Z0.y)--cycle,p); },true); pic.addBox(initial,final); } // A grayscale palette pen[] Grayscale(int NColors=256) { real ninv=1.0/(NColors-1.0); return sequence(new pen(int i) {return gray(i*ninv);},NColors); } // A color wheel palette pen[] Wheel(int NColors=32766) { if(settings.gray) return Grayscale(NColors); int nintervals=6; int n=-quotient(NColors,-nintervals); pen[] Palette; if(n == 0) return Palette; Palette=new pen[n*nintervals]; real ninv=1.0/n; for(int i=0; i < n; ++i) { real ininv=i*ninv; real ininv1=1.0-ininv; Palette[i]=rgb(1.0,0.0,ininv); Palette[n+i]=rgb(ininv1,0.0,1.0); Palette[2n+i]=rgb(0.0,ininv,1.0); Palette[3n+i]=rgb(0.0,1.0,ininv1); Palette[4n+i]=rgb(ininv,1.0,0.0); Palette[5n+i]=rgb(1.0,ininv1,0.0); } return Palette; } // A rainbow palette pen[] Rainbow(int NColors=32766) { if(settings.gray) return Grayscale(NColors); int offset=1; int nintervals=5; int n=-quotient(NColors-1,-nintervals); pen[] Palette; if(n == 0) return Palette; Palette=new pen[n*nintervals+offset]; real ninv=1.0/n; for(int i=0; i < n; ++i) { real ininv=i*ninv; real ininv1=1.0-ininv; Palette[i]=rgb(ininv1,0.0,1.0); Palette[n+i]=rgb(0.0,ininv,1.0); Palette[2n+i]=rgb(0.0,1.0,ininv1); Palette[3n+i]=rgb(ininv,1.0,0.0); Palette[4n+i]=rgb(1.0,ininv1,0.0); } Palette[4n+n]=rgb(1.0,0.0,0.0); return Palette; } private pen[] BWRainbow(int NColors, bool two) { if(settings.gray) return Grayscale(NColors); int offset=1; int nintervals=6; int divisor=3; if(two) nintervals += 6; int num=NColors-offset; int n=-quotient(num,-nintervals*divisor)*divisor; NColors=n*nintervals+offset; pen[] Palette; if(n == 0) return Palette; Palette=new pen[NColors]; real ninv=1.0/n; int k=0; if(two) { for(int i=0; i < n; ++i) { real ininv=i*ninv; real ininv1=1.0-ininv; Palette[i]=rgb(ininv1,0.0,1.0); Palette[n+i]=rgb(0.0,ininv,1.0); Palette[2n+i]=rgb(0.0,1.0,ininv1); Palette[3n+i]=rgb(ininv,1.0,0.0); Palette[4n+i]=rgb(1.0,ininv1,0.0); Palette[5n+i]=rgb(1.0,0.0,ininv); } k += 6n; } if(two) for(int i=0; i < n; ++i) Palette[k+i]=rgb(1.0-i*ninv,0.0,1.0); else { int n3=-quotient(n,-3); int n23=2*n3; real third=n3*ninv; real twothirds=n23*ninv; for(int i=0; i < n3; ++i) { real ininv=i*ninv; Palette[k+i]=rgb(ininv,0.0,ininv); Palette[k+n3+i]=rgb(third,0.0,third+ininv); Palette[k+n23+i]=rgb(third-ininv,0.0,twothirds+ininv); } } k += n; for(int i=0; i < n; ++i) { real ininv=i*ninv; real ininv1=1.0-ininv; Palette[k+i]=rgb(0.0,ininv,1.0); Palette[k+n+i]=rgb(0.0,1.0,ininv1); Palette[k+2n+i]=rgb(ininv,1.0,0.0); Palette[k+3n+i]=rgb(1.0,ininv1,0.0); Palette[k+4n+i]=rgb(1.0,ininv,ininv); } Palette[k+5n]=rgb(1.0,1.0,1.0); return Palette; } // Quantize palette to exactly n values pen[] quantize(pen[] Palette, int n) { if(Palette.length == 0) abort("cannot quantize empty palette"); if(n <= 1) abort("palette must contain at least two pens"); real step=(Palette.length-1)/(n-1); return sequence(new pen(int i) { return Palette[round(i*step)]; },n); } // A rainbow palette tapering off to black/white at the spectrum ends, pen[] BWRainbow(int NColors=32761) { return BWRainbow(NColors,false); } // A double rainbow palette tapering off to black/white at the spectrum ends, // with a linearly scaled intensity. pen[] BWRainbow2(int NColors=32761) { pen[] Palette=BWRainbow(NColors,true); int n=Palette.length; real ninv=1.0/n; for(int i=0; i < n; ++i) Palette[i]=i*ninv*Palette[i]; return Palette; } //A palette varying linearly over the specified array of pens, using // NColors in each interpolation interval. pen[] Gradient(int NColors=256 ... pen[] p) { pen[] P; if(p.length < 2) abort("at least 2 colors must be specified"); real step=NColors > 1 ? (1/(NColors-1)) : 1; for(int i=0; i < p.length-1; ++i) { pen begin=p[i]; pen end=p[i+1]; P.append(sequence(new pen(int j) { return interp(begin,end,j*step); },NColors)); } return P; } pen[] cmyk(pen[] Palette) { int n=Palette.length; for(int i=0; i < n; ++i) Palette[i]=cmyk(Palette[i]); return Palette; } asymptote-2.37/base/patterns.asy000066400000000000000000000050671265434602500170010ustar00rootroot00000000000000// Create a tiling named name from picture pic // with optional left-bottom margin lb and right-top margin rt. frame tiling(string name, picture pic, pair lb=0, pair rt=0) { frame tiling; frame f=pic.fit(identity()); pair pmin=min(f)-lb; pair pmax=max(f)+rt; string s="%.6f"; postscript(tiling,"<< /PaintType 1 /PatternType 1 /TilingType 1 /BBox ["+format(s,pmin.x,"C")+" "+format(s,pmin.y,"C")+" "+ format(s,pmax.x,"C")+" "+format(s,pmax.y,"C")+"] /XStep "+format(s,pmax.x-pmin.x,"C")+" /YStep "+format(s,pmax.y-pmin.y,"C")+" /PaintProc {pop"); add(tiling,f); postscript(tiling,"} >> matrix makepattern /"+name+" exch def"); return tiling; } // Add to frame preamble a tiling name constructed from picture pic // with optional left-bottom margin lb and right-top margin rt. void add(string name, picture pic, pair lb=0, pair rt=0) { add(currentpatterns,tiling(name,pic,lb,rt)); } picture tile(real Hx=5mm, real Hy=0, pen p=currentpen, filltype filltype=NoFill) { picture tiling; if(Hy == 0) Hy=Hx; path tile=box((0,0),(Hx,Hy)); tiling.add(new void (frame f, transform t) { filltype.fill(f,t*tile,p); }); clip(tiling,tile); return tiling; } picture checker(real Hx=5mm, real Hy=0, pen p=currentpen) { picture tiling; if(Hy == 0) Hy=Hx; path tile=box((0,0),(Hx,Hy)); fill(tiling,tile,p); fill(tiling,shift(Hx,Hy)*tile,p); clip(tiling,box((0,0),(2Hx,2Hy))); return tiling; } picture brick(real Hx=5mm, real Hy=0, pen p=currentpen) { picture tiling; if(Hy == 0) Hy=Hx/2; path tile=box((0,0),(Hx,Hy)); draw(tiling,tile,p); draw(tiling,(Hx/2,Hy)--(Hx/2,2Hy),p); draw(tiling,(0,2Hy)--(Hx,2Hy),p); clip(tiling,box((0,0),(Hx,2Hy))); return tiling; } real hatchepsilon=1e-4; picture hatch(real H=5mm, pair dir=NE, pen p=currentpen) { picture tiling; real theta=angle(dir); real s=sin(theta); real c=cos(theta); if(abs(s) <= hatchepsilon) { path g=(0,0)--(H,0); draw(tiling,g,p); draw(tiling,shift(0,H)*g,p); clip(tiling,scale(H)*unitsquare); } else if(abs(c) <= hatchepsilon) { path g=(0,0)--(0,H); draw(tiling,g,p); draw(tiling,shift(H,0)*g,p); clip(tiling,scale(H)*unitsquare); } else { real h=H/s; real y=H/c; path g=(0,0)--(h,y); draw(tiling,g,p); draw(tiling,shift(-h/2,y/2)*g,p); draw(tiling,shift(h/2,-y/2)*g,p); clip(tiling,box((0,0),(h,y))); } return tiling; } picture crosshatch(real H=5mm, pen p=currentpen) { picture tiling; add(tiling,hatch(H,p)); add(tiling,shift(H*sqrt(2))*rotate(90)*hatch(H,p)); return tiling; } asymptote-2.37/base/plain.asy000066400000000000000000000145721265434602500162450ustar00rootroot00000000000000/***** * plain.asy * Andy Hammerlindl and John Bowman 2004/08/19 * * A package for general purpose drawing, with automatic sizing of pictures. * *****/ access settings; if(settings.command != "") { string s=settings.command; settings.command=""; settings.multipleView=settings.batchView=settings.interactiveView; _eval(s+";",false,true); exit(); } include plain_constants; access version; if(version.VERSION != VERSION) { warning("version","using possibly incompatible version "+ version.VERSION+" of plain.asy"+'\n'); nowarn("version"); } include plain_strings; include plain_pens; include plain_paths; include plain_filldraw; include plain_margins; include plain_picture; include plain_Label; include plain_shipout; include plain_arcs; include plain_boxes; include plain_markers; include plain_arrows; include plain_debugger; typedef void exitfcn(); bool needshipout() { return !shipped && !currentpicture.empty(); } void updatefunction() { if(!currentpicture.uptodate) shipout(); } void exitfunction() { if(needshipout()) shipout(); } atupdate(updatefunction); atexit(exitfunction); // A restore thunk is a function, that when called, restores the graphics state // to what it was when the restore thunk was created. typedef void restoreThunk(); typedef restoreThunk saveFunction(); saveFunction[] saveFunctions={}; // When save is called, this will be redefined to do the corresponding restore. void restore() { warning("nomatchingsave","restore called with no matching save"); } void addSaveFunction(saveFunction s) { saveFunctions.push(s); } restoreThunk buildRestoreThunk() { // Call the save functions in reverse order, storing their restore thunks. restoreThunk[] thunks={}; for (int i=saveFunctions.length-1; i >= 0; --i) thunks.push(saveFunctions[i]()); return new void() { // Call the restore thunks in an order matching the saves. for (int i=thunks.length-1; i >= 0; --i) thunks[i](); }; } // Add the default save function. addSaveFunction(new restoreThunk () { pen defaultpen=defaultpen(); pen p=currentpen; picture pic=currentpicture.copy(); restoreThunk r=restore; return new void() { defaultpen(defaultpen); currentpen=p; currentpicture=pic; currentpicture.uptodate=false; restore=r; }; }); // Save the current state, so that restore will put things back in that state. restoreThunk save() { return restore=buildRestoreThunk(); } void restoredefaults() { warning("nomatchingsavedefaults", "restoredefaults called with no matching savedefaults"); } restoreThunk buildRestoreDefaults() { pen defaultpen=defaultpen(); exitfcn atupdate=atupdate(); exitfcn atexit=atexit(); restoreThunk r=restoredefaults; return new void() { defaultpen(defaultpen); atupdate(atupdate); atexit(atexit); restoredefaults=r; }; } // Save the current state, so that restore will put things back in that state. restoreThunk savedefaults() { return restoredefaults=buildRestoreDefaults(); } void initdefaults() { savedefaults(); resetdefaultpen(); atupdate(null); atexit(null); } // Return the sequence n,...m int[] sequence(int n, int m) { return sequence(new int(int x){return x;},m-n+1)+n; } int[] reverse(int n) {return sequence(new int(int x){return n-1-x;},n);} bool[] reverse(bool[] a) {return a[reverse(a.length)];} int[] reverse(int[] a) {return a[reverse(a.length)];} real[] reverse(real[] a) {return a[reverse(a.length)];} pair[] reverse(pair[] a) {return a[reverse(a.length)];} triple[] reverse(triple[] a) {return a[reverse(a.length)];} string[] reverse(string[] a) {return a[reverse(a.length)];} // Return a uniform partition dividing [a,b] into n subintervals. real[] uniform(real a, real b, int n) { if(n <= 0) return new real[]; return a+(b-a)/n*sequence(n+1); } void eval(string s, bool embedded=false) { if(!embedded) initdefaults(); _eval(s+";",embedded); if(!embedded) restoredefaults(); } void eval(code s, bool embedded=false) { if(!embedded) initdefaults(); _eval(s,embedded); if(!embedded) restoredefaults(); } // Evaluate user command line option. void usersetting() { eval(settings.user,true); } string stripsuffix(string f, string suffix=".asy") { int n=rfind(f,suffix); if(n != -1) f=erase(f,n,-1); return f; } // Conditionally process each file name in array s in a new environment. void asy(string format, bool overwrite=false ... string[] s) { for(string f : s) { f=stripsuffix(f); string suffix="."+format; string fsuffix=f+suffix; if(overwrite || error(input(fsuffix,check=false))) { string outformat=settings.outformat; bool interactiveView=settings.interactiveView; bool batchView=settings.batchView; settings.outformat=format; settings.interactiveView=false; settings.batchView=false; string outname=outname(); delete(outname+"_"+".aux"); eval("import \""+f+"\" as dummy"); rename(stripsuffix(outname)+suffix,fsuffix); settings.outformat=outformat; settings.interactiveView=interactiveView; settings.batchView=batchView; } } } void beep() { write('\7',flush); } struct processtime { real user; real system; } struct cputime { processtime parent; processtime child; processtime change; } cputime cputime() { static processtime last; real [] a=_cputime(); cputime cputime; cputime.parent.user=a[0]; cputime.parent.system=a[1]; cputime.child.user=a[2]; cputime.child.system=a[3]; real user=a[0]+a[2]; real system=a[1]+a[3]; cputime.change.user=user-last.user; cputime.change.system=system-last.system; last.user=user; last.system=system; return cputime; } string cputimeformat="%#.2f"; void write(file file, string s="", cputime c, string format=cputimeformat, suffix suffix=none) { write(file,s, format(format,c.change.user)+"u "+ format(format,c.change.system)+"s "+ format(format,c.parent.user+c.child.user)+"U "+ format(format,c.parent.system+c.child.system)+"S ",suffix); } void write(string s="", cputime c, string format=cputimeformat, suffix suffix=endl) { write(stdout,s,c,format,suffix); } if(settings.autoimport != "") { string s=settings.autoimport; settings.autoimport=""; eval("import \""+s+"\" as dummy",true); shipped=false; atupdate(updatefunction); atexit(exitfunction); settings.autoimport=s; } cputime(); asymptote-2.37/base/plain_Label.asy000066400000000000000000000376131265434602500173450ustar00rootroot00000000000000real angle(transform t) { pair z=(2t.xx*t.yy,t.yx*t.yy-t.xx*t.xy); if(t.xx < 0) z=-z; return degrees(z,warn=false); } transform rotation(transform t) { return rotate(angle(t)); } transform scaleless(transform t) { real a=t.xx, b=t.xy, c=t.yx, d=t.yy; real arg=(a-d)^2+4b*c; pair delta=arg >= 0 ? sqrt(arg) : I*sqrt(-arg); real trace=a+d; pair l1=0.5(trace+delta); pair l2=0.5(trace-delta); if(abs(delta) < sqrtEpsilon*max(abs(l1),abs(l2))) { real s=abs(0.5trace); return (s != 0) ? scale(1/s)*t : t; } if(abs(l1-d) < abs(l2-d)) {pair temp=l1; l1=l2; l2=temp;} pair dot(pair[] u, pair[] v) {return conj(u[0])*v[0]+conj(u[1])*v[1];} pair[] unit(pair[] u) { real norm2=abs(u[0])^2+abs(u[1])^2; return norm2 != 0 ? u/sqrt(norm2) : u; } pair[] u={l1-d,b}; pair[] v={c,l2-a}; u=unit(u); pair d=dot(u,u); if(d != 0) v -= dot(u,v)/d*u; v=unit(v); pair[][] U={{u[0],v[0]},{u[1],v[1]}}; pair[][] A={{a,b},{c,d}}; pair[][] operator *(pair[][] a, pair[][] b) { pair[][] c=new pair[2][2]; for(int i=0; i < 2; ++i) { for(int j=0; j < 2; ++j) { c[i][j]=a[i][0]*b[0][j]+a[i][1]*b[1][j]; } } return c; } pair[][] conj(pair[][] a) { pair[][] c=new pair[2][2]; for(int i=0; i < 2; ++i) { for(int j=0; j < 2; ++j) { c[i][j]=conj(a[j][i]); } } return c; } A=conj(U)*A*U; real D=abs(A[0][0]); if(D != 0) { A[0][0] /= D; A[0][1] /= D; } D=abs(A[1][1]); if(D != 0) { A[1][0] /= D; A[1][1] /= D; } A=U*A*conj(U); return (0,0,A[0][0].x,A[0][1].x,A[1][0].x,A[1][1].x); } struct align { pair dir; triple dir3; bool relative=false; bool default=true; bool is3D=false; void init(pair dir=0, bool relative=false, bool default=false) { this.dir=dir; this.relative=relative; this.default=default; is3D=false; } void init(triple dir=(0,0,0), bool relative=false, bool default=false) { this.dir3=dir; this.relative=relative; this.default=default; is3D=true; } align copy() { align align=new align; align.init(dir,relative,default); align.dir3=dir3; align.is3D=is3D; return align; } void align(align align) { if(!align.default) { bool is3D=align.is3D; init(align.dir,align.relative); dir3=align.dir3; this.is3D=is3D; } } void align(align align, align default) { align(align); if(this.default) { init(default.dir,default.relative,default.default); dir3=default.dir3; is3D=default.is3D; } } void write(file file=stdout, suffix suffix=endl) { if(!default) { if(relative) { write(file,"Relative("); if(is3D) write(file,dir3); else write(file,dir); write(file,")",suffix); } else { if(is3D) write(file,dir3,suffix); else write(file,dir,suffix); } } } bool Center() { return relative && (is3D ? dir3 == (0,0,0) : dir == 0); } } struct side { pair align; } side Relative(explicit pair align) { side s; s.align=align; return s; } restricted side NoSide; restricted side LeftSide=Relative(W); restricted side Center=Relative((0,0)); restricted side RightSide=Relative(E); side operator * (real x, side s) { side S; S.align=x*s.align; return S; } align operator cast(pair dir) {align A; A.init(dir,false); return A;} align operator cast(triple dir) {align A; A.init(dir,false); return A;} align operator cast(side side) {align A; A.init(side.align,true); return A;} restricted align NoAlign; void write(file file=stdout, align align, suffix suffix=endl) { align.write(file,suffix); } struct position { pair position; bool relative; } position Relative(real position) { position p; p.position=position; p.relative=true; return p; } restricted position BeginPoint=Relative(0); restricted position MidPoint=Relative(0.5); restricted position EndPoint=Relative(1); position operator cast(pair x) {position P; P.position=x; return P;} position operator cast(real x) {return (pair) x;} position operator cast(int x) {return (pair) x;} pair operator cast(position P) {return P.position;} typedef transform embed(transform); transform Shift(transform t) {return identity();} transform Rotate(transform t) {return rotation(t);} transform Slant(transform t) {return scaleless(t);} transform Scale(transform t) {return t;} embed Rotate(pair z) { return new transform(transform t) {return rotate(degrees(shiftless(t)*z, warn=false));}; } path[] texpath(string s, pen p, bool tex=settings.tex != "none", bool bbox=false); struct Label { string s,size; position position; bool defaultposition=true; align align; pen p=nullpen; transform T; transform3 T3=identity(4); bool defaulttransform=true; bool defaulttransform3=true; embed embed=Rotate; // Shift, Rotate, Slant, or Scale with embedded picture filltype filltype=NoFill; void init(string s="", string size="", position position=0, bool defaultposition=true, align align=NoAlign, pen p=nullpen, transform T=identity(), transform3 T3=identity4, bool defaulttransform=true, bool defaulttransform3=true, embed embed=Rotate, filltype filltype=NoFill) { this.s=s; this.size=size; this.position=position; this.defaultposition=defaultposition; this.align=align.copy(); this.p=p; this.T=T; this.T3=copy(T3); this.defaulttransform=defaulttransform; this.defaulttransform3=defaulttransform3; this.embed=embed; this.filltype=filltype; } void initalign(string s="", string size="", align align, pen p=nullpen, embed embed=Rotate, filltype filltype=NoFill) { init(s,size,align,p,embed,filltype); } void transform(transform T) { this.T=T; defaulttransform=false; } void transform3(transform3 T) { this.T3=copy(T); defaulttransform3=false; } Label copy(transform3 T3=this.T3) { Label L=new Label; L.init(s,size,position,defaultposition,align,p,T,T3,defaulttransform, defaulttransform3,embed,filltype); return L; } void position(position pos) { this.position=pos; defaultposition=false; } void align(align a) { align.align(a); } void align(align a, align default) { align.align(a,default); } void p(pen p0) { if(this.p == nullpen) this.p=p0; } void filltype(filltype filltype0) { if(this.filltype == NoFill) this.filltype=filltype0; } void label(frame f, transform t=identity(), pair position, pair align) { pen p0=p == nullpen ? currentpen : p; align=length(align)*unit(rotation(t)*align); pair S=t*position+align*labelmargin(p0)+shift(T)*0; if(settings.tex != "none") label(f,s,size,embed(t)*shiftless(T),S,align,p0); else fill(f,align(texpath(s,p0),S,align,p0),p0); } void out(frame f, transform t=identity(), pair position=position.position, pair align=align.dir) { if(filltype == NoFill) label(f,t,position,align); else { frame d; label(d,t,position,align); add(f,d,filltype); } } void label(picture pic=currentpicture, pair position, pair align) { if(s == "") return; pic.add(new void (frame f, transform t) { out(f,t,position,align); },true); frame f; // Create a picture with label at the origin to extract its bbox truesize. label(f,(0,0),align); pic.addBox(position,position,min(f),max(f)); } void out(picture pic=currentpicture) { label(pic,position.position,align.dir); } void out(picture pic=currentpicture, path g) { bool relative=position.relative; real position=position.position.x; pair Align=align.dir; bool alignrelative=align.relative; if(defaultposition) {relative=true; position=0.5;} if(relative) position=reltime(g,position); if(align.default) { alignrelative=true; Align=position <= sqrtEpsilon ? S : position >= length(g)-sqrtEpsilon ? N : E; } pic.add(new void (frame f, transform t) { out(f,t,point(g,position), alignrelative ? -Align*dir(t*g,position)*I : Align); },!alignrelative); frame f; pair align=alignrelative ? -Align*dir(g,position)*I : Align; label(f,(0,0),align); pair position=point(g,position); pic.addBox(position,position,min(f),max(f)); } void write(file file=stdout, suffix suffix=endl) { write(file,"\""+s+"\""); if(!defaultposition) write(file,", position=",position.position); if(!align.default) write(file,", align="); write(file,align); if(p != nullpen) write(file,", pen=",p); if(!defaulttransform) write(file,", transform=",T); if(!defaulttransform3) { write(file,", transform3=",endl); write(file,T3); } write(file,"",suffix); } real relative() { return defaultposition ? 0.5 : position.position.x; }; real relative(path g) { return position.relative ? reltime(g,relative()) : relative(); }; } Label Label; void add(frame f, transform t=identity(), Label L) { L.out(f,t); } void add(picture pic=currentpicture, Label L) { L.out(pic); } Label operator * (transform t, Label L) { Label tL=L.copy(); tL.align.dir=L.align.dir; tL.transform(t*L.T); return tL; } Label operator * (transform3 t, Label L) { Label tL=L.copy(t*L.T3); tL.align.dir=L.align.dir; tL.defaulttransform3=false; return tL; } Label Label(string s, string size="", explicit position position, align align=NoAlign, pen p=nullpen, embed embed=Rotate, filltype filltype=NoFill) { Label L; L.init(s,size,position,false,align,p,embed,filltype); return L; } Label Label(string s, string size="", pair position, align align=NoAlign, pen p=nullpen, embed embed=Rotate, filltype filltype=NoFill) { return Label(s,size,(position) position,align,p,embed,filltype); } Label Label(explicit pair position, align align=NoAlign, pen p=nullpen, embed embed=Rotate, filltype filltype=NoFill) { return Label((string) position,position,align,p,embed,filltype); } Label Label(string s="", string size="", align align=NoAlign, pen p=nullpen, embed embed=Rotate, filltype filltype=NoFill) { Label L; L.initalign(s,size,align,p,embed,filltype); return L; } Label Label(Label L, align align=NoAlign, pen p=nullpen, embed embed=L.embed, filltype filltype=NoFill) { Label L=L.copy(); L.align(align); L.p(p); L.embed=embed; L.filltype(filltype); return L; } Label Label(Label L, explicit position position, align align=NoAlign, pen p=nullpen, embed embed=L.embed, filltype filltype=NoFill) { Label L=Label(L,align,p,embed,filltype); L.position(position); return L; } Label Label(Label L, pair position, align align=NoAlign, pen p=nullpen, embed embed=L.embed, filltype filltype=NoFill) { return Label(L,(position) position,align,p,embed,filltype); } void write(file file=stdout, Label L, suffix suffix=endl) { L.write(file,suffix); } void label(frame f, Label L, pair position, align align=NoAlign, pen p=currentpen, filltype filltype=NoFill) { add(f,Label(L,position,align,p,filltype)); } void label(frame f, Label L, align align=NoAlign, pen p=currentpen, filltype filltype=NoFill) { add(f,Label(L,L.position,align,p,filltype)); } void label(picture pic=currentpicture, Label L, pair position, align align=NoAlign, pen p=currentpen, filltype filltype=NoFill) { Label L=Label(L,position,align,p,filltype); add(pic,L); } void label(picture pic=currentpicture, Label L, align align=NoAlign, pen p=currentpen, filltype filltype=NoFill) { label(pic,L,L.position,align,p,filltype); } void label(picture pic=currentpicture, Label L, explicit path g, align align=NoAlign, pen p=currentpen, filltype filltype=NoFill) { Label L=Label(L,align,p,filltype); L.out(pic,g); } void label(picture pic=currentpicture, Label L, explicit guide g, align align=NoAlign, pen p=currentpen, filltype filltype=NoFill) { label(pic,L,(path) g,align,p,filltype); } Label operator cast(string s) {return Label(s);} // A structure that a string, Label, or frame can be cast to. struct object { frame f; Label L=Label; path g; // Bounding path void operator init(frame f) { this.f=f; g=box(min(f),max(f)); } void operator init(Label L) { this.L=L.copy(); if(L != Label) L.out(f); g=box(min(f),max(f)); } } object operator cast(frame f) { return object(f); } object operator cast(Label L) { return object(L); } object operator cast(string s) { return object(s); } Label operator cast(object F) { return F.L; } frame operator cast(object F) { return F.f; } object operator * (transform t, explicit object F) { object f; f.f=t*F.f; f.L=t*F.L; f.g=t*F.g; return f; } // Returns a copy of object F aligned in the direction align object align(object F, pair align) { return shift(F.f,align)*F; } void add(picture dest=currentpicture, object F, pair position=0, bool group=true, filltype filltype=NoFill, bool above=true) { add(dest,F.f,position,group,filltype,above); } // Pack a list of objects into a frame. frame pack(pair align=2S ... object inset[]) { frame F; int n=inset.length; pair z; for (int i=0; i < n; ++i) { add(F,inset[i].f,z); z += align+realmult(unit(align),size(inset[i].f)); } return F; } path[] texpath(Label L, bool tex=settings.tex != "none", bool bbox=false) { struct stringfont { string s; real fontsize; string font; void operator init(Label L) { s=replace(L.s,'\n',' '); fontsize=fontsize(L.p); font=font(L.p); } pen pen() {return fontsize(fontsize)+fontcommand(font);} } bool lexorder(stringfont a, stringfont b) { return a.s < b.s || (a.s == b.s && (a.fontsize < b.fontsize || (a.fontsize == b.fontsize && a.font < b.font))); } static stringfont[] stringcache; static path[][] pathcache; static stringfont[] stringlist; static bool adjust[]; path[] G; stringfont s=stringfont(L); pen p=s.pen(); int i=search(stringcache,s,lexorder); if(i == -1 || lexorder(stringcache[i],s)) { int k=search(stringlist,s,lexorder); if(k == -1 || lexorder(stringlist[k],s)) { ++k; stringlist.insert(k,s); // PDF tex engines lose track of the baseline. adjust.insert(k,tex && basealign(L.p) == 1 && pdf()); } } path[] transform(path[] g, Label L) { if(g.length == 0) return g; pair m=min(g); pair M=max(g); pair dir=rectify(inverse(L.T)*-L.align.dir); if(tex && basealign(L.p) == 1) dir -= (0,(1-dir.y)*m.y/(M.y-m.y)); pair a=m+realmult(dir,M-m); return shift(L.position+L.align.dir*labelmargin(L.p))*L.T*shift(-a)*g; } if(tex && bbox) { frame f; label(f,L); return transform(box(min(f),max(f)),L); } if(stringlist.length > 0) { path[][] g; int n=stringlist.length; string[] s=new string[n]; pen[] p=new pen[n]; for(int i=0; i < n; ++i) { stringfont S=stringlist[i]; s[i]=adjust[i] ? "."+S.s : S.s; p[i]=adjust[i] ? S.pen()+basealign : S.pen(); } g=tex ? _texpath(s,p) : textpath(s,p); if(tex) for(int i=0; i < n; ++i) if(adjust[i]) { real y=min(g[i][0]).y; g[i].delete(0); g[i]=shift(0,-y)*g[i]; } for(int i=0; i < stringlist.length; ++i) { stringfont s=stringlist[i]; int j=search(stringcache,s,lexorder)+1; stringcache.insert(j,s); pathcache.insert(j,g[i]); } stringlist.delete(); adjust.delete(); } return transform(pathcache[search(stringcache,stringfont(L),lexorder)],L); } texpath=new path[](string s, pen p, bool tex=settings.tex != "none", bool bbox=false) { return texpath(Label(s,p)); }; asymptote-2.37/base/plain_arcs.asy000066400000000000000000000023531265434602500172470ustar00rootroot00000000000000bool CCW=true; bool CW=false; path circle(pair c, real r) { return shift(c)*scale(r)*unitcircle; } path ellipse(pair c, real a, real b) { return shift(c)*scale(a,b)*unitcircle; } // return an arc centered at c from pair z1 to z2 (assuming |z2-c|=|z1-c|), // drawing in the given direction. path arc(pair c, explicit pair z1, explicit pair z2, bool direction=CCW) { z1 -= c; real r=abs(z1); z1=unit(z1); z2=unit(z2-c); real t1=intersect(unitcircle,(0,0)--2*z1)[0]; real t2=intersect(unitcircle,(0,0)--2*z2)[0]; static int n=length(unitcircle); if(direction) { if (t1 >= t2) t1 -= n; } else if(t2 >= t1) t2 -= n; return shift(c)*scale(r)*subpath(unitcircle,t1,t2); } // return an arc centered at c with radius r from angle1 to angle2 in degrees, // drawing in the given direction. path arc(pair c, real r, real angle1, real angle2, bool direction) { return arc(c,c+r*dir(angle1),c+r*dir(angle2),direction); } // return an arc centered at c with radius r > 0 from angle1 to angle2 in // degrees, drawing counterclockwise if angle2 >= angle1 (otherwise clockwise). path arc(pair c, real r, real angle1, real angle2) { return arc(c,r,angle1,angle2,angle2 >= angle1 ? CCW : CW); } asymptote-2.37/base/plain_arrows.asy000066400000000000000000000452151265434602500176400ustar00rootroot00000000000000real arrowlength=0.75cm; real arrowfactor=15; real arrowangle=15; real arcarrowfactor=0.5*arrowfactor; real arcarrowangle=2*arrowangle; real arrowsizelimit=0.5; real arrow2sizelimit=1/3; real arrowdir=5; real arrowbarb=3; real arrowhookfactor=1.5; real arrowtexfactor=1; real barfactor=arrowfactor; real arrowsize(pen p=currentpen) { return arrowfactor*linewidth(p); } real arcarrowsize(pen p=currentpen) { return arcarrowfactor*linewidth(p); } real barsize(pen p=currentpen) { return barfactor*linewidth(p); } struct arrowhead { path head(path g, position position=EndPoint, pen p=currentpen, real size=0, real angle=arrowangle); real size(pen p)=arrowsize; real arcsize(pen p)=arcarrowsize; filltype defaultfilltype(pen) {return FillDraw;} } real[] arrowbasepoints(path base, path left, path right, real default=0) { real[][] Tl=transpose(intersections(left,base)); real[][] Tr=transpose(intersections(right,base)); return new real[] {Tl.length > 0 ? Tl[0][0] : default, Tr.length > 0 ? Tr[0][0] : default}; } path arrowbase(path r, pair y, real t, real size) { pair perp=2*size*I*dir(r,t); return size == 0 ? y : y+perp--y-perp; } arrowhead DefaultHead; DefaultHead.head=new path(path g, position position=EndPoint, pen p=currentpen, real size=0, real angle=arrowangle) { if(size == 0) size=DefaultHead.size(p); bool relative=position.relative; real position=position.position.x; if(relative) position=reltime(g,position); path r=subpath(g,position,0); pair x=point(r,0); real t=arctime(r,size); pair y=point(r,t); path base=arrowbase(r,y,t,size); path left=rotate(-angle,x)*r; path right=rotate(angle,x)*r; real[] T=arrowbasepoints(base,left,right); pair denom=point(right,T[1])-y; real factor=denom != 0 ? length((point(left,T[0])-y)/denom) : 1; path left=rotate(-angle*factor,x)*r; path right=rotate(angle*factor,x)*r; real[] T=arrowbasepoints(base,left,right); return subpath(left,0,T[0])--subpath(right,T[1],0)&cycle; }; arrowhead SimpleHead; SimpleHead.head=new path(path g, position position=EndPoint, pen p=currentpen, real size=0, real angle=arrowangle) { if(size == 0) size=SimpleHead.size(p); bool relative=position.relative; real position=position.position.x; if(relative) position=reltime(g,position); path r=subpath(g,position,0); pair x=point(r,0); real t=arctime(r,size); path left=rotate(-angle,x)*r; path right=rotate(angle,x)*r; return subpath(left,t,0)--subpath(right,0,t); }; arrowhead HookHead(real dir=arrowdir, real barb=arrowbarb) { arrowhead a; a.head=new path(path g, position position=EndPoint, pen p=currentpen, real size=0, real angle=arrowangle) { if(size == 0) size=a.size(p); angle=min(angle*arrowhookfactor,45); bool relative=position.relative; real position=position.position.x; if(relative) position=reltime(g,position); path r=subpath(g,position,0); pair x=point(r,0); real t=arctime(r,size); pair y=point(r,t); path base=arrowbase(r,y,t,size); path left=rotate(-angle,x)*r; path right=rotate(angle,x)*r; real[] T=arrowbasepoints(base,left,right,1); pair denom=point(right,T[1])-y; real factor=denom != 0 ? length((point(left,T[0])-y)/denom) : 1; path left=rotate(-angle*factor,x)*r; path right=rotate(angle*factor,x)*r; real[] T=arrowbasepoints(base,left,right,1); left=subpath(left,0,T[0]); right=subpath(right,T[1],0); pair pl0=point(left,0), pl1=relpoint(left,1); pair pr0=relpoint(right,0), pr1=relpoint(right,1); pair M=(pl1+pr0)/2; pair v=barb*unit(M-pl0); pl1=pl1+v; pr0=pr0+v; left=pl0{dir(-dir+degrees(M-pl0,false))}..pl1--M; right=M--pr0..pr1{dir(dir+degrees(pr1-M,false))}; return left--right&cycle; }; return a; } arrowhead HookHead=HookHead(); arrowhead TeXHead; TeXHead.size=new real(pen p) { static real hcoef=2.1; // 84/40=abs(base-hint)/base_height return hcoef*arrowtexfactor*linewidth(p); }; TeXHead.arcsize=TeXHead.size; TeXHead.head=new path(path g, position position=EndPoint, pen p=currentpen, real size=0, real angle=arrowangle) { static real wcoef=1/84; // 1/abs(base-hint) static path texhead=scale(wcoef)* ((0,20) .. controls (-75,75) and (-108,158) .. (-108,166) .. controls (-108,175) and (-100,178) .. (-93,178) .. controls (-82,178) and (-80,173) .. (-77,168) .. controls (-62,134) and (-30,61) .. (70,14) .. controls (82,8) and (84,7) .. (84,0) .. controls (84,-7) and (82,-8) .. (70,-14) .. controls (-30,-61) and (-62,-134) .. (-77,-168) .. controls (-80,-173) and (-82,-178) .. (-93,-178) .. controls (-100,-178) and (-108,-175).. (-108,-166).. controls (-108,-158) and (-75,-75) .. (0,-20)--cycle); if(size == 0) size=TeXHead.size(p); path gp=scale(size)*texhead; bool relative=position.relative; real position=position.position.x; if(relative) position=reltime(g,position); path r=subpath(g,position,0); pair y=point(r,arctime(r,size)); return shift(y)*rotate(degrees(-dir(r,arctime(r,0.5*size))))*gp; }; TeXHead.defaultfilltype=new filltype(pen p) {return Fill(p);}; private real position(position position, real size, path g, bool center) { bool relative=position.relative; real position=position.position.x; if(relative) { position *= arclength(g); if(center) position += 0.5*size; position=arctime(g,position); } else if(center) position=arctime(g,arclength(subpath(g,0,position))+0.5*size); return position; } void drawarrow(frame f, arrowhead arrowhead=DefaultHead, path g, pen p=currentpen, real size=0, real angle=arrowangle, filltype filltype=null, position position=EndPoint, bool forwards=true, margin margin=NoMargin, bool center=false) { if(size == 0) size=arrowhead.size(p); if(filltype == null) filltype=arrowhead.defaultfilltype(p); size=min(arrowsizelimit*arclength(g),size); real position=position(position,size,g,center); g=margin(g,p).g; int L=length(g); if(!forwards) { g=reverse(g); position=L-position; } path r=subpath(g,position,0); size=min(arrowsizelimit*arclength(r),size); path head=arrowhead.head(g,position,p,size,angle); bool endpoint=position > L-sqrtEpsilon; if(cyclic(head) && (filltype == NoFill || endpoint)) { if(position > 0) draw(f,subpath(r,arctime(r,size),length(r)),p); if(!endpoint) draw(f,subpath(g,position,L),p); } else draw(f,g,p); filltype.fill(f,head,p+solid); } void drawarrow2(frame f, arrowhead arrowhead=DefaultHead, path g, pen p=currentpen, real size=0, real angle=arrowangle, filltype filltype=null, margin margin=NoMargin) { if(size == 0) size=arrowhead.size(p); if(filltype == null) filltype=arrowhead.defaultfilltype(p); g=margin(g,p).g; size=min(arrow2sizelimit*arclength(g),size); path r=reverse(g); int L=length(g); path head=arrowhead.head(g,L,p,size,angle); path tail=arrowhead.head(r,L,p,size,angle); if(cyclic(head)) draw(f,subpath(r,arctime(r,size),L-arctime(g,size)),p); else draw(f,g,p); filltype.fill(f,head,p+solid); filltype.fill(f,tail,p+solid); } // Add to picture an estimate of the bounding box contribution of arrowhead // using the local slope at endpoint and ignoring margin. void addArrow(picture pic, arrowhead arrowhead, path g, pen p, real size, real angle, filltype filltype, real position) { if(filltype == null) filltype=arrowhead.defaultfilltype(p); pair z=point(g,position); path g=z-(size+linewidth(p))*dir(g,position)--z; frame f; filltype.fill(f,arrowhead.head(g,position,p,size,angle),p); pic.addBox(z,z,min(f)-z,max(f)-z); } picture arrow(arrowhead arrowhead=DefaultHead, path g, pen p=currentpen, real size=0, real angle=arrowangle, filltype filltype=null, position position=EndPoint, bool forwards=true, margin margin=NoMargin, bool center=false) { if(size == 0) size=arrowhead.size(p); picture pic; pic.add(new void(frame f, transform t) { drawarrow(f,arrowhead,t*g,p,size,angle,filltype,position,forwards,margin, center); }); pic.addPath(g,p); real position=position(position,size,g,center); path G; if(!forwards) { G=reverse(g); position=length(g)-position; } else G=g; addArrow(pic,arrowhead,G,p,size,angle,filltype,position); return pic; } picture arrow2(arrowhead arrowhead=DefaultHead, path g, pen p=currentpen, real size=0, real angle=arrowangle, filltype filltype=null, margin margin=NoMargin) { if(size == 0) size=arrowhead.size(p); picture pic; pic.add(new void(frame f, transform t) { drawarrow2(f,arrowhead,t*g,p,size,angle,filltype,margin); }); pic.addPath(g,p); int L=length(g); addArrow(pic,arrowhead,g,p,size,angle,filltype,L); addArrow(pic,arrowhead,reverse(g),p,size,angle,filltype,L); return pic; } void bar(picture pic, pair a, pair d, pen p=currentpen) { picture opic; Draw(opic,-0.5d--0.5d,p+solid); add(pic,opic,a); } picture bar(pair a, pair d, pen p=currentpen) { picture pic; bar(pic,a,d,p); return pic; } typedef bool arrowbar(picture, path, pen, margin); bool Blank(picture, path, pen, margin) { return false; } bool None(picture, path, pen, margin) { return true; } arrowbar BeginArrow(arrowhead arrowhead=DefaultHead, real size=0, real angle=arrowangle, filltype filltype=null, position position=BeginPoint) { return new bool(picture pic, path g, pen p, margin margin) { add(pic,arrow(arrowhead,g,p,size,angle,filltype,position,forwards=false, margin)); return false; }; } arrowbar Arrow(arrowhead arrowhead=DefaultHead, real size=0, real angle=arrowangle, filltype filltype=null, position position=EndPoint) { return new bool(picture pic, path g, pen p, margin margin) { add(pic,arrow(arrowhead,g,p,size,angle,filltype,position,margin)); return false; }; } arrowbar EndArrow(arrowhead arrowhead=DefaultHead, real size=0, real angle=arrowangle, filltype filltype=null, position position=EndPoint)=Arrow; arrowbar MidArrow(arrowhead arrowhead=DefaultHead, real size=0, real angle=arrowangle, filltype filltype=null) { return new bool(picture pic, path g, pen p, margin margin) { add(pic,arrow(arrowhead,g,p,size,angle,filltype,MidPoint,margin, center=true)); return false; }; } arrowbar Arrows(arrowhead arrowhead=DefaultHead, real size=0, real angle=arrowangle, filltype filltype=null) { return new bool(picture pic, path g, pen p, margin margin) { add(pic,arrow2(arrowhead,g,p,size,angle,filltype,margin)); return false; }; } arrowbar BeginArcArrow(arrowhead arrowhead=DefaultHead, real size=0, real angle=arcarrowangle, filltype filltype=null, position position=BeginPoint) { return new bool(picture pic, path g, pen p, margin margin) { real size=size == 0 ? arrowhead.arcsize(p) : size; add(pic,arrow(arrowhead,g,p,size,angle,filltype,position, forwards=false,margin)); return false; }; } arrowbar ArcArrow(arrowhead arrowhead=DefaultHead, real size=0, real angle=arcarrowangle, filltype filltype=null, position position=EndPoint) { return new bool(picture pic, path g, pen p, margin margin) { real size=size == 0 ? arrowhead.arcsize(p) : size; add(pic,arrow(arrowhead,g,p,size,angle,filltype,position,margin)); return false; }; } arrowbar EndArcArrow(arrowhead arrowhead=DefaultHead, real size=0, real angle=arcarrowangle, filltype filltype=null, position position=EndPoint)=ArcArrow; arrowbar MidArcArrow(arrowhead arrowhead=DefaultHead, real size=0, real angle=arcarrowangle, filltype filltype=null) { return new bool(picture pic, path g, pen p, margin margin) { real size=size == 0 ? arrowhead.arcsize(p) : size; add(pic,arrow(arrowhead,g,p,size,angle,filltype,MidPoint,margin, center=true)); return false; }; } arrowbar ArcArrows(arrowhead arrowhead=DefaultHead, real size=0, real angle=arcarrowangle, filltype filltype=null) { return new bool(picture pic, path g, pen p, margin margin) { real size=size == 0 ? arrowhead.arcsize(p) : size; add(pic,arrow2(arrowhead,g,p,size,angle,filltype,margin)); return false; }; } arrowbar BeginBar(real size=0) { return new bool(picture pic, path g, pen p, margin margin) { real size=size == 0 ? barsize(p) : size; bar(pic,point(g,0),size*dir(g,0)*I,p); return true; }; } arrowbar Bar(real size=0) { return new bool(picture pic, path g, pen p, margin margin) { int L=length(g); real size=size == 0 ? barsize(p) : size; bar(pic,point(g,L),size*dir(g,L)*I,p); return true; }; } arrowbar EndBar(real size=0)=Bar; arrowbar Bars(real size=0) { return new bool(picture pic, path g, pen p, margin margin) { real size=size == 0 ? barsize(p) : size; BeginBar(size)(pic,g,p,margin); EndBar(size)(pic,g,p,margin); return true; }; } arrowbar BeginArrow=BeginArrow(), MidArrow=MidArrow(), Arrow=Arrow(), EndArrow=Arrow(), Arrows=Arrows(), BeginArcArrow=BeginArcArrow(), MidArcArrow=MidArcArrow(), ArcArrow=ArcArrow(), EndArcArrow=ArcArrow(), ArcArrows=ArcArrows(), BeginBar=BeginBar(), Bar=Bar(), EndBar=Bar(), Bars=Bars(); void draw(frame f, path g, pen p=currentpen, arrowbar arrow) { picture pic; if(arrow(pic,g,p,NoMargin)) draw(f,g,p); add(f,pic.fit()); } void draw(picture pic=currentpicture, Label L=null, path g, align align=NoAlign, pen p=currentpen, arrowbar arrow=None, arrowbar bar=None, margin margin=NoMargin, Label legend=null, marker marker=nomarker) { // These if statements are ordered in such a way that the most common case // (with just a path and a pen) executes the least bytecode. if (marker == nomarker) { if (arrow == None && bar == None) { if (margin == NoMargin && size(nib(p)) == 0) { pic.addExactAbove( new void(frame f, transform t, transform T, pair, pair) { _draw(f,t*T*g,p); }); pic.addPath(g,p); // Jumping over else clauses takes time, so test if we can return // here. if (L == null && legend == null) return; } else // With margin or polygonal pen. { _draw(pic, g, p, margin); } } else /* arrow or bar */ { // Note we are using & instead of && as both arrow and bar need to be // called. if (arrow(pic, g, p, margin) & bar(pic, g, p, margin)) _draw(pic, g, p, margin); } if(L != null && L.s != "") { L=L.copy(); L.align(align); L.p(p); L.out(pic,g); } if(legend != null && legend.s != "") { legend.p(p); pic.legend.push(Legend(legend.s,legend.p,p,marker.f,marker.above)); } } else /* marker != nomarker */ { if(marker != nomarker && !marker.above) marker.mark(pic,g); // Note we are using & instead of && as both arrow and bar need to be // called. if ((arrow == None || arrow(pic, g, p, margin)) & (bar == None || bar(pic, g, p, margin))) { _draw(pic, g, p, margin); } if(L != null && L.s != "") { L=L.copy(); L.align(align); L.p(p); L.out(pic,g); } if(legend != null && legend.s != "") { legend.p(p); pic.legend.push(Legend(legend.s,legend.p,p,marker.f,marker.above)); } if(marker != nomarker && marker.above) marker.mark(pic,g); } } // Draw a fixed-size line about the user-coordinate 'origin'. void draw(pair origin, picture pic=currentpicture, Label L=null, path g, align align=NoAlign, pen p=currentpen, arrowbar arrow=None, arrowbar bar=None, margin margin=NoMargin, Label legend=null, marker marker=nomarker) { picture opic; draw(opic,L,g,align,p,arrow,bar,margin,legend,marker); add(pic,opic,origin); } void draw(picture pic=currentpicture, explicit path[] g, pen p=currentpen, Label legend=null, marker marker=nomarker) { // This could be optimized to size and draw the entire array as a batch. for(int i=0; i < g.length-1; ++i) draw(pic,g[i],p,marker); if(g.length > 0) draw(pic,g[g.length-1],p,legend,marker); } void draw(picture pic=currentpicture, guide[] g, pen p=currentpen, Label legend=null, marker marker=nomarker) { draw(pic,(path[]) g,p,legend,marker); } void draw(pair origin, picture pic=currentpicture, explicit path[] g, pen p=currentpen, Label legend=null, marker marker=nomarker) { picture opic; draw(opic,g,p,legend,marker); add(pic,opic,origin); } void draw(pair origin, picture pic=currentpicture, guide[] g, pen p=currentpen, Label legend=null, marker marker=nomarker) { draw(origin,pic,(path[]) g,p,legend,marker); } // Align an arrow pointing to b from the direction dir. The arrow is // 'length' PostScript units long. void arrow(picture pic=currentpicture, Label L=null, pair b, pair dir, real length=arrowlength, align align=NoAlign, pen p=currentpen, arrowbar arrow=Arrow, margin margin=EndMargin) { if(L != null && L.s != "") { L=L.copy(); if(L.defaultposition) L.position(0); L.align(L.align,dir); L.p(p); } marginT margin=margin(b--b,p); // Extract margin.begin and margin.end pair a=(margin.begin+length+margin.end)*unit(dir); draw(b,pic,L,a--(0,0),align,p,arrow,margin); } // Fit an array of pictures simultaneously using the sizing of picture all. frame[] fit2(picture[] pictures, picture all) { frame[] out; if(!all.empty2()) { transform t=all.calculateTransform(); pair m=all.min(t); pair M=all.max(t); for(picture pic : pictures) { frame f=pic.fit(t); draw(f,m,nullpen); draw(f,M,nullpen); out.push(f); } } return out; } // Fit an array of pictures simultaneously using the size of the first picture. // TODO: Remove unused arguments. frame[] fit(string prefix="", picture[] pictures, string format="", bool view=true, string options="", string script="", projection P=currentprojection) { if(pictures.length == 0) return new frame[]; picture all; size(all,pictures[0]); for(picture pic : pictures) add(all,pic); return fit2(pictures,all); } asymptote-2.37/base/plain_bounds.asy000066400000000000000000000510151265434602500176100ustar00rootroot00000000000000include plain_scaling; // After a transformation, produce new coordinate bounds. For paths that // have been added, this is only an approximation since it takes the bounds of // their transformed bounding box. private void addTransformedCoords(coords2 dest, transform t, coords2 point, coords2 min, coords2 max) { dest.push(t, point, point); // Add in all 4 corner coords, to properly size rectangular pictures. dest.push(t,min,min); dest.push(t,min,max); dest.push(t,max,min); dest.push(t,max,max); } // Adds another sizing restriction to the coordinates, but only if it is // maximal, that is, if under some scaling, this coordinate could be the // largest. private void addIfMaximal(coord[] coords, real user, real truesize) { // TODO: Test promoting coordinates for efficiency. for (coord c : coords) if (user <= c.user && truesize <= c.truesize) // Not maximal. return; // The coordinate is not dominated by any existing extreme, so it is // maximal and will be added, but first remove any coords it now dominates. int i = 0; while (i < coords.length) { coord c = coords[i]; if (c.user <= user && c.truesize <= truesize) coords.delete(i); else ++i; } // Add the coordinate to the extremes. coords.push(coord.build(user, truesize)); } private void addIfMaximal(coord[] dest, coord[] src) { // This may be inefficient, as it rebuilds the coord struct when adding it. for (coord c : src) addIfMaximal(dest, c.user, c.truesize); } // Same as addIfMaximal, but testing for minimal coords. private void addIfMinimal(coord[] coords, real user, real truesize) { for (coord c : coords) if (user >= c.user && truesize >= c.truesize) return; int i = 0; while (i < coords.length) { coord c = coords[i]; if (c.user >= user && c.truesize >= truesize) coords.delete(i); else ++i; } coords.push(coord.build(user, truesize)); } private void addIfMinimal(coord[] dest, coord[] src) { for (coord c : src) addIfMinimal(dest, c.user, c.truesize); } // This stores a list of sizing bounds for picture data. If the object is // frozen, then it cannot be modified further, and therefore can be safely // passed by reference and stored in the sizing data for multiple pictures. private struct freezableBounds { restricted bool frozen = false; void freeze() { frozen = true; } // Optional links to further (frozen) sizing data. private freezableBounds[] links; // Links to (frozen) sizing data that is transformed when added here. private static struct transformedBounds { transform t; freezableBounds link; }; private transformedBounds[] tlinks; // The sizing data. It cannot be modified once this object is frozen. private coords2 point, min, max; // A bound represented by a path. Using the path instead of the bounding // box means it will be accurate after a transformation by coordinates. private path[] pathBounds; // A bound represented by a path and a pen. // As often many paths use the same pen, we store an array of paths. private static struct pathpen { path[] g; pen p; void operator init(path g, pen p) { this.g.push(g); this.p = p; } } private static pathpen operator *(transform t, pathpen pp) { // Should the pen be transformed? pathpen newpp; for (path g : pp.g) newpp.g.push(t*g); newpp.p = pp.p; return newpp; } // WARNING: Due to crazy optimizations, if this array is changed between an // empty and non-empty state, the assignment of a method to // addPath(path,pen) must also change. private pathpen[] pathpenBounds; // Once frozen, the sizing is immutable, and therefore we can compute and // store the extremal coordinates. public static struct extremes { coord[] left, bottom, right, top; void operator init(coord[] left, coord[] bottom, coord[] right, coord[] top) { this.left = left; this.bottom = bottom; this.right = right; this.top = top; } } private static void addMaxToExtremes(extremes e, pair user, pair truesize) { addIfMaximal(e.right, user.x, truesize.x); addIfMaximal(e.top, user.y, truesize.y); } private static void addMinToExtremes(extremes e, pair user, pair truesize) { addIfMinimal(e.left, user.x, truesize.x); addIfMinimal(e.bottom, user.y, truesize.y); } private static void addMaxToExtremes(extremes e, coords2 coords) { addIfMaximal(e.right, coords.x); addIfMaximal(e.top, coords.y); } private static void addMinToExtremes(extremes e, coords2 coords) { addIfMinimal(e.left, coords.x); addIfMinimal(e.bottom, coords.y); } private extremes cachedExtremes = null; // Once frozen, getMutable returns a new object based on this one, which can // be modified. freezableBounds getMutable() { assert(frozen); var f = new freezableBounds; f.links.push(this); return f; } freezableBounds transformed(transform t) { // Freeze these bounds, as we are storing a reference to them. freeze(); var tlink = new transformedBounds; tlink.t = t; tlink.link = this; var b = new freezableBounds; b.tlinks.push(tlink); return b; } void append(freezableBounds b) { // Check that we can modify the object. assert(!frozen); //TODO: If b is "small", ie. a single tlink or cliplink, just copy the //link. // As we only reference b, we must freeze it to ensure it does not change. b.freeze(); links.push(b); } void addPoint(pair user, pair truesize) { assert(!frozen); point.push(user, truesize); } void addBox(pair userMin, pair userMax, pair trueMin, pair trueMax) { assert(!frozen); this.min.push(userMin, trueMin); this.max.push(userMax, trueMax); } void addPath(path g) { // This, and other asserts have been removed to speed things up slightly. //assert(!frozen); this.pathBounds.push(g); } void addPath(path[] g) { //assert(!frozen); this.pathBounds.append(g); } // To squeeze out a bit more performance, this method is either assigned // addPathToNonEmptyArray or addPathToEmptyArray depending on the state of // the pathpenBounds array. void addPath(path g, pen p); private void addPathToNonEmptyArray(path g, pen p) { //assert(!frozen); //assert(!pathpenBounds.empty()); var pp = pathpenBounds[0]; // Test if the pens are equal or have the same bounds. if (pp.p == p || (min(pp.p) == min(p) && max(pp.p) == max(p))) { // If this path has the same pen as the last one, just add it to the // array corresponding to that pen. pp.g.push(g); } else { // A different pen. Start a new bound and put it on the front. Put // the old bound at the end of the array. pathpenBounds[0] = pathpen(g,p); pathpenBounds.push(pp); } } void addPathToEmptyArray(path g, pen p) { //assert(!frozen); //assert(pathpenBounds.empty()); pathpenBounds.push(pathpen(g,p)); addPath = addPathToNonEmptyArray; } // Initial setting for addPath. addPath = addPathToEmptyArray; // Transform the sizing info by t then add the result to the coords // structure. private void accumulateCoords(transform t, coords2 coords) { for (var link : links) link.accumulateCoords(t, coords); for (var tlink : tlinks) tlink.link.accumulateCoords(t*tlink.t, coords); addTransformedCoords(coords, t, this.point, this.min, this.max); for (var g : pathBounds) { g = t*g; coords.push(min(g), (0,0)); coords.push(max(g), (0,0)); } for (var pp: pathpenBounds) { pair pm = min(pp.p), pM = max(pp.p); for (var g : pp.g) { g = t*g; coords.push(min(g), pm); coords.push(max(g), pM); } } } // Add all of the sizing info to the given coords structure. private void accumulateCoords(coords2 coords) { for (var link : links) link.accumulateCoords(coords); for (var tlink : tlinks) tlink.link.accumulateCoords(tlink.t, coords); coords.append(this.point); coords.append(this.min); coords.append(this.max); for (var g : pathBounds) { coords.push(min(g), (0,0)); coords.push(max(g), (0,0)); } for (var pp: pathpenBounds) { pair pm = min(pp.p), pM = max(pp.p); for (var g : pp.g) { coords.push(min(g), pm); coords.push(max(g), pM); } } } // Returns all of the coords that this sizing data represents. private coords2 allCoords() { coords2 coords; accumulateCoords(coords); return coords; } private void addLocalsToExtremes(transform t, extremes e) { coords2 coords; addTransformedCoords(coords, t, this.point, this.min, this.max); addMinToExtremes(e, coords); addMaxToExtremes(e, coords); if (pathBounds.length > 0) { addMinToExtremes(e, minAfterTransform(t, pathBounds), (0,0)); addMaxToExtremes(e, maxAfterTransform(t, pathBounds), (0,0)); } for (var pp : pathpenBounds) { if (pp.g.length > 0) { addMinToExtremes(e, minAfterTransform(t, pp.g), min(pp.p)); addMaxToExtremes(e, maxAfterTransform(t, pp.g), max(pp.p)); } } } private void addToExtremes(transform t, extremes e) { for (var link : links) link.addToExtremes(t, e); for (var tlink : tlinks) tlink.link.addToExtremes(t*tlink.t, e); addLocalsToExtremes(t, e); } private void addLocalsToExtremes(extremes e) { addMinToExtremes(e, point); addMaxToExtremes(e, point); addMinToExtremes(e, min); addMaxToExtremes(e, max); if (pathBounds.length > 0) { addMinToExtremes(e, min(pathBounds), (0,0)); addMaxToExtremes(e, max(pathBounds), (0,0)); } for(var pp : pathpenBounds) { pair m=min(pp.p); pair M=max(pp.p); for(path gg : pp.g) { if (size(gg) > 0) { addMinToExtremes(e,min(gg),m); addMaxToExtremes(e,max(gg),M); } } } } private void addToExtremes(extremes e) { for (var link : links) link.addToExtremes(e); for (var tlink : tlinks) tlink.link.addToExtremes(tlink.t, e); addLocalsToExtremes(e); } private static void write(extremes e) { static void write(coord[] coords) { for (coord c : coords) write(" " + (string)c.user + " u + " + (string)c.truesize); } write("left:"); write(e.left); write("bottom:"); write(e.bottom); write("right:"); write(e.right); write("top:"); write(e.top); } // Returns the extremal coordinates of the sizing data. public extremes extremes() { if (cachedExtremes == null) { freeze(); extremes e; addToExtremes(e); cachedExtremes = e; } return cachedExtremes; } // Helper functions for computing the usersize bounds. usermin and usermax // would be easily computable from extremes, except that the picture // interface actually allows calls that manually change the usermin and // usermax values. Therefore, we have to compute these values separately. private static struct userbounds { bool areSet=false; pair min; pair max; } private static struct boundsAccumulator { pair[] mins; pair[] maxs; void push(pair m, pair M) { mins.push(m); maxs.push(M); } void push(userbounds b) { if (b.areSet) push(b.min, b.max); } void push(transform t, userbounds b) { if (b.areSet) { pair[] box = { t*(b.min.x,b.max.y), t*b.max, t*b.min, t*(b.max.x,b.min.y) }; for (var z : box) push(z,z); } } void pushUserCoords(coords2 min, coords2 max) { int n = min.x.length; assert(min.y.length == n); assert(max.x.length == n); assert(max.y.length == n); for (int i = 0; i < n; ++i) push((min.x[i].user, min.y[i].user), (max.x[i].user, max.y[i].user)); } userbounds collapse() { userbounds b; if (mins.length > 0) { b.areSet = true; b.min = minbound(mins); b.max = maxbound(maxs); } else { b.areSet = false; } return b; } } // The user bounds already calculated for this data. private userbounds storedUserBounds = null; private void accumulateUserBounds(boundsAccumulator acc) { if (storedUserBounds != null) { assert(frozen); acc.push(storedUserBounds); } else { acc.pushUserCoords(point, point); acc.pushUserCoords(min, max); if (pathBounds.length > 0) acc.push(min(pathBounds), max(pathBounds)); for (var pp : pathpenBounds) if(size(pp.g) > 0) acc.push(min(pp.g), max(pp.g)); for (var link : links) link.accumulateUserBounds(acc); // Transforms are handled as they were in the old system. for (var tlink : tlinks) { boundsAccumulator tacc; tlink.link.accumulateUserBounds(tacc); acc.push(tlink.t, tacc.collapse()); } } } private void computeUserBounds() { freeze(); boundsAccumulator acc; accumulateUserBounds(acc); storedUserBounds = acc.collapse(); } private userbounds userBounds() { if (storedUserBounds == null) computeUserBounds(); assert(storedUserBounds != null); return storedUserBounds; } // userMin/userMax returns the minimal/maximal userspace coordinate of the // sizing data. As coordinates for objects such as labels can have // significant truesize dimensions, this userMin/userMax values may not // correspond closely to the end of the screen, and are of limited use. // userSetx and userSety determine if there is sizing data in order to even // have userMin/userMax defined. public bool userBoundsAreSet() { return userBounds().areSet; } public pair userMin() { return userBounds().min; } public pair userMax() { return userBounds().max; } // To override the true userMin and userMax bounds, first compute the // userBounds as they should be at this point, then change the values. public void alterUserBound(string which, real val) { // We are changing the bounds data, so it cannot be frozen yet. After the // user bounds are set, however, the sizing data cannot change, so it will // be frozen. assert(!frozen); computeUserBounds(); assert(frozen); var b = storedUserBounds; if (which == "minx") b.min = (val, b.min.y); else if (which == "miny") b.min = (b.min.x, val); else if (which == "maxx") b.max = (val, b.max.y); else { assert(which == "maxy"); b.max = (b.max.x, val); } } // A temporary measure. Stuffs all of the data from the links and paths // into the coords. private void flatten() { assert(!frozen); // First, compute the user bounds, taking into account any manual // alterations. computeUserBounds(); // Calculate all coordinates. coords2 coords = allCoords(); // Erase all the old data. point.erase(); min.erase(); max.erase(); pathBounds.delete(); pathpenBounds.delete(); addPath = addPathToEmptyArray; links.delete(); tlinks.delete(); // Put all of the coordinates into point. point = coords; } void xclip(real Min, real Max) { assert(!frozen); flatten(); point.xclip(Min,Max); min.xclip(Min,Max); max.xclip(Min,Max); // Cap the userBounds. userbounds b = storedUserBounds; b.min = (max(Min, b.min.x), b.min.y); b.max = (min(Max, b.max.x), b.max.y); } void yclip(real Min, real Max) { assert(!frozen); flatten(); point.yclip(Min,Max); min.yclip(Min,Max); max.yclip(Min,Max); // Cap the userBounds. userbounds b = storedUserBounds; b.min = (b.min.x, max(Min, b.min.y)); b.max = (b.max.x, min(Max, b.max.y)); } // Calculate the min for the final frame, given the coordinate transform. pair min(transform t) { extremes e = extremes(); if (e.left.length == 0) return 0; pair a=t*(1,1)-t*(0,0), b=t*(0,0); scaling xs=scaling.build(a.x,b.x); scaling ys=scaling.build(a.y,b.y); return (min(infinity, xs, e.left), min(infinity, ys, e.bottom)); } // Calculate the max for the final frame, given the coordinate transform. pair max(transform t) { extremes e = extremes(); if (e.right.length == 0) return 0; pair a=t*(1,1)-t*(0,0), b=t*(0,0); scaling xs=scaling.build(a.x,b.x); scaling ys=scaling.build(a.y,b.y); return (max(-infinity, xs, e.right), max(-infinity, ys, e.top)); } // Returns the transform for turning user-space pairs into true-space pairs. transform scaling(real xsize, real ysize, real xunitsize, real yunitsize, bool keepAspect, bool warn) { if(xsize == 0 && xunitsize == 0 && ysize == 0 && yunitsize == 0) return identity(); // Get the extremal coordinates. extremes e = extremes(); real sx; if(xunitsize == 0) { if(xsize != 0) sx=calculateScaling("x",e.left,e.right,xsize,warn); } else sx=xunitsize; /* Possible alternative code : real sx = xunitsize != 0 ? xunitsize : xsize != 0 ? calculateScaling("x", Coords.x, xsize, warn) : 0; */ real sy; if(yunitsize == 0) { if(ysize != 0) sy=calculateScaling("y",e.bottom,e.top,ysize,warn); } else sy=yunitsize; if(sx == 0) { sx=sy; if(sx == 0) return identity(); } else if(sy == 0) sy=sx; if(keepAspect && (xunitsize == 0 || yunitsize == 0)) return scale(min(sx,sy)); else return scale(sx,sy); } } struct bounds { private var base = new freezableBounds; // We should probably put this back into picture. bool exact = true; // Called just before modifying the sizing data. It ensures base is // non-frozen. // Note that this is manually inlined for speed reasons in a couple often // called methods below. private void makeMutable() { if (base.frozen) base = base.getMutable(); //assert(!base.frozen); // Disabled for speed reasons. } void erase() { // Just discard the old bounds. base = new freezableBounds; // We don't reset the 'exact' field, for backward compatibility. } bounds copy() { // Freeze the underlying bounds and make a shallow copy. base.freeze(); var b = new bounds; b.base = this.base; b.exact = this.exact; return b; } bounds transformed(transform t) { var b = new bounds; b.base = base.transformed(t); b.exact = this.exact; return b; } void append(bounds b) { makeMutable(); base.append(b.base); } void append(transform t, bounds b) { // makeMutable will be called by append. if (t == identity()) append(b); else append(b.transformed(t)); } void addPoint(pair user, pair truesize) { makeMutable(); base.addPoint(user, truesize); } void addBox(pair userMin, pair userMax, pair trueMin, pair trueMax) { makeMutable(); base.addBox(userMin, userMax, trueMin, trueMax); } void addPath(path g) { //makeMutable(); // Manually inlined here for speed reasons. if (base.frozen) base = base.getMutable(); base.addPath(g); } void addPath(path[] g) { //makeMutable(); // Manually inlined here for speed reasons. if (base.frozen) base = base.getMutable(); base.addPath(g); } void addPath(path g, pen p) { //makeMutable(); // Manually inlined here for speed reasons. if (base.frozen) base = base.getMutable(); base.addPath(g, p); } public bool userBoundsAreSet() { return base.userBoundsAreSet(); } public pair userMin() { return base.userMin(); } public pair userMax() { return base.userMax(); } public void alterUserBound(string which, real val) { makeMutable(); base.alterUserBound(which, val); } void xclip(real Min, real Max) { makeMutable(); base.xclip(Min,Max); } void yclip(real Min, real Max) { makeMutable(); base.yclip(Min,Max); } void clip(pair Min, pair Max) { // TODO: If the user bounds have been manually altered, they may be // incorrect after the clip. xclip(Min.x,Max.x); yclip(Min.y,Max.y); } pair min(transform t) { return base.min(t); } pair max(transform t) { return base.max(t); } transform scaling(real xsize, real ysize, real xunitsize, real yunitsize, bool keepAspect, bool warn) { return base.scaling(xsize, ysize, xunitsize, yunitsize, keepAspect, warn); } } bounds operator *(transform t, bounds b) { return b.transformed(t); } asymptote-2.37/base/plain_boxes.asy000066400000000000000000000077311265434602500174440ustar00rootroot00000000000000// Draw and/or fill a box on frame dest using the dimensions of frame src. path box(frame dest, frame src=dest, real xmargin=0, real ymargin=xmargin, pen p=currentpen, filltype filltype=NoFill, bool above=true) { pair z=(xmargin,ymargin); int sign=filltype == NoFill ? 1 : -1; pair h=0.5*sign*(max(p)-min(p)); path g=box(min(src)-h-z,max(src)+h+z); frame F; if(above == false) { filltype.fill(F,g,p); prepend(dest,F); } else filltype.fill(dest,g,p); return g; } path roundbox(frame dest, frame src=dest, real xmargin=0, real ymargin=xmargin, pen p=currentpen, filltype filltype=NoFill, bool above=true) { pair m=min(src); pair M=max(src); pair bound=M-m; int sign=filltype == NoFill ? 1 : -1; real a=bound.x+2*xmargin; real b=bound.y+2*ymargin; real ds=0; real dw=min(a,b)*0.3; path g=shift(m-(xmargin,ymargin))*((0,dw)--(0,b-dw){up}..{right} (dw,b)--(a-dw,b){right}..{down} (a,b-dw)--(a,dw){down}..{left} (a-dw,0)--(dw,0){left}..{up}cycle); frame F; if(above == false) { filltype.fill(F,g,p); prepend(dest,F); } else filltype.fill(dest,g,p); return g; } path ellipse(frame dest, frame src=dest, real xmargin=0, real ymargin=xmargin, pen p=currentpen, filltype filltype=NoFill, bool above=true) { pair m=min(src); pair M=max(src); pair D=M-m; static real factor=0.5*sqrt(2); int sign=filltype == NoFill ? 1 : -1; pair h=0.5*sign*(max(p)-min(p)); path g=ellipse(0.5*(M+m),factor*D.x+h.x+xmargin,factor*D.y+h.y+ymargin); frame F; if(above == false) { filltype.fill(F,g,p); prepend(dest,F); } else filltype.fill(dest,g,p); return g; } path box(frame f, Label L, real xmargin=0, real ymargin=xmargin, pen p=currentpen, filltype filltype=NoFill, bool above=true) { add(f,L); return box(f,xmargin,ymargin,p,filltype,above); } path roundbox(frame f, Label L, real xmargin=0, real ymargin=xmargin, pen p=currentpen, filltype filltype=NoFill, bool above=true) { add(f,L); return roundbox(f,xmargin,ymargin,p,filltype,above); } path ellipse(frame f, Label L, real xmargin=0, real ymargin=xmargin, pen p=currentpen, filltype filltype=NoFill, bool above=true) { add(f,L); return ellipse(f,xmargin,ymargin,p,filltype,above); } typedef path envelope(frame dest, frame src=dest, real xmargin=0, real ymargin=xmargin, pen p=currentpen, filltype filltype=NoFill, bool above=true); object object(Label L, envelope e, real xmargin=0, real ymargin=xmargin, pen p=currentpen, filltype filltype=NoFill, bool above=true) { object F; F.L=L.copy(); Label L0=L.copy(); L0.position(0); L0.p(p); add(F.f,L0); F.g=e(F.f,xmargin,ymargin,p,filltype); return F; } object draw(picture pic=currentpicture, Label L, envelope e, real xmargin=0, real ymargin=xmargin, pen p=currentpen, filltype filltype=NoFill, bool above=true) { object F=object(L,e,xmargin,ymargin,p,filltype,above); pic.add(new void (frame f, transform t) { frame d; add(d,t,F.L); e(f,d,xmargin,ymargin,p,filltype,above); add(f,d); },true); pic.addBox(L.position,L.position,min(F.f),max(F.f)); return F; } object draw(picture pic=currentpicture, Label L, envelope e, pair position, real xmargin=0, real ymargin=xmargin, pen p=currentpen, filltype filltype=NoFill, bool above=true) { return draw(pic,Label(L,position),e,xmargin,ymargin,p,filltype,above); } pair point(object F, pair dir, transform t=identity()) { pair m=min(F.g); pair M=max(F.g); pair c=0.5*(m+M); pair z=t*F.L.position; real[] T=intersect(F.g,c--2*(m+realmult(rectify(dir),M-m))-c); if(T.length == 0) return z; return z+point(F.g,T[0]); } frame bbox(picture pic=currentpicture, real xmargin=0, real ymargin=xmargin, pen p=currentpen, filltype filltype=NoFill) { frame f=pic.fit(max(pic.xsize-2*xmargin,0),max(pic.ysize-2*ymargin,0)); box(f,xmargin,ymargin,p,filltype,above=false); return f; } asymptote-2.37/base/plain_constants.asy000066400000000000000000000070621265434602500203350ustar00rootroot00000000000000restricted int undefined=(intMax % 2 == 1) ? intMax : intMax-1; restricted real inches=72; restricted real inch=inches; restricted real cm=inches/2.54; restricted real mm=0.1cm; restricted real bp=1; // A PostScript point. restricted real pt=72.0/72.27; // A TeX pt; smaller than a PostScript bp. restricted pair I=(0,1); restricted pair right=(1,0); restricted pair left=(-1,0); restricted pair up=(0,1); restricted pair down=(0,-1); restricted pair E=(1,0); restricted pair N=(0,1); restricted pair W=(-1,0); restricted pair S=(0,-1); restricted pair NE=unit(N+E); restricted pair NW=unit(N+W); restricted pair SW=unit(S+W); restricted pair SE=unit(S+E); restricted pair ENE=unit(E+NE); restricted pair NNE=unit(N+NE); restricted pair NNW=unit(N+NW); restricted pair WNW=unit(W+NW); restricted pair WSW=unit(W+SW); restricted pair SSW=unit(S+SW); restricted pair SSE=unit(S+SE); restricted pair ESE=unit(E+SE); restricted real sqrtEpsilon=sqrt(realEpsilon); restricted pair Align=sqrtEpsilon*NE; restricted int mantissaBits=ceil(-log(realEpsilon)/log(2))+1; int min(... int[] a) {return min(a);} int max(... int[] a) {return max(a);} real min(... real[] a) {return min(a);} real max(... real[] a) {return max(a);} bool finite(real x) { return abs(x) < infinity; } bool finite(pair z) { return abs(z.x) < infinity && abs(z.y) < infinity; } bool finite(triple v) { return abs(v.x) < infinity && abs(v.y) < infinity && abs(v.z) < infinity; } restricted file stdin=input(); restricted file stdout=output(); void none(file file) {} void endl(file file) {write(file,'\n',flush);} void newl(file file) {write(file,'\n');} void DOSendl(file file) {write(file,'\r\n',flush);} void DOSnewl(file file) {write(file,'\r\n');} void tab(file file) {write(file,'\t');} void comma(file file) {write(file,',');} typedef void suffix(file); // Used by interactive write to warn that the outputted type is the resolution // of an overloaded name. void overloadedMessage(file file) { write(file,' '); endl(file); } void write(suffix suffix=endl) {suffix(stdout);} void write(file file, suffix suffix=none) {suffix(file);} path box(pair a, pair b) { return a--(b.x,a.y)--b--(a.x,b.y)--cycle; } restricted path unitsquare=box((0,0),(1,1)); restricted path unitcircle=E..N..W..S..cycle; restricted real circleprecision=0.0006; restricted transform invert=reflect((0,0),(1,0)); restricted pen defaultpen; // A type that takes on one of the values true, false, or default. struct bool3 { bool value; bool set; } void write(file file, string s="", bool3 b, suffix suffix=none) { if(b.set) write(b.value,suffix); else write("default",suffix); } void write(string s="", bool3 b, suffix suffix=endl) { write(stdout,s,b,suffix); } restricted bool3 default; bool operator cast(bool3 b) { return b.set && b.value; } bool3 operator cast(bool b) { bool3 B; B.value=b; B.set=true; return B; } bool operator == (bool3 a, bool3 b) { return a.set == b.set && (!a.set || (a.value == b.value)); } bool operator != (bool3 a, bool3 b) { return a.set != b.set || (a.set && (a.value != b.value)); } bool operator == (bool3 a, bool b) { return a.set && a.value == b; } bool operator != (bool3 a, bool b) { return !a.set || a.value != b; } bool operator == (bool a, bool3 b) { return b.set && b.value == a; } bool operator != (bool a, bool3 b) { return !b.set || b.value != a; } bool[] operator cast(bool3[] b) { return sequence(new bool(int i) {return b[i];},b.length); } bool3[] operator cast(bool[] b) { return sequence(new bool3(int i) {return b[i];},b.length); } asymptote-2.37/base/plain_debugger.asy000066400000000000000000000042131265434602500201000ustar00rootroot00000000000000int debuggerlines=5; int sourceline(string file, string text) { string file=locatefile(file); string[] source=input(file); for(int line=0; line < source.length; ++line) if(find(source[line],text) >= 0) return line+1; write("no matching line in "+file+": \""+text+"\""); return 0; } void stop(string file, string text, code s=quote{}) { int line=sourceline(file,text); if(line > 0) stop(file,line,s); } void clear(string file, string text) { int line=sourceline(file,text); if(line > 0) clear(file,line); } // Enable debugging. bool debugging=true; // Variables used by conditional expressions: // e.g. stop("test",2,quote{ignore=(++count <= 10);}); bool ignore; int count=0; string debugger(string file, int line, int column, code s=quote{}) { int verbose=settings.verbose; settings.verbose=0; _eval(s,true); if(ignore) { ignore=false; settings.verbose=verbose; return "c"; } static string s; if(debugging) { static string lastfile; static string[] source; bool help=false; while(true) { if(file != lastfile && file != "-") {source=input(file); lastfile=file;} write(); for(int i=max(line-debuggerlines,0); i < min(line,source.length); ++i) write(source[i]); for(int i=0; i < column-1; ++i) write(" ",none); write("^"+(verbose == 5 ? " trace" : "")); if(help) { write("c:continue f:file h:help i:inst n:next r:return s:step t:trace q:quit x:exit"); help=false; } string Prompt=file+": "+(string) line+"."+(string) column; Prompt += "? [%s] "; s=getstring(name="debug",default="h",prompt=Prompt,store=false); if(s == "h" || s == "?") {help=true; continue;} if(s == "c" || s == "s" || s == "n" || s == "i" || s == "f" || s == "r") break; if(s == "q") {debugging=false; abort();} // quit if(s == "x") {debugging=false; return "";} // exit if(s == "t") { // trace if(verbose == 0) { verbose=5; } else { verbose=0; } continue; } _eval(s+";",true); } } settings.verbose=verbose; return s; } atbreakpoint(debugger); asymptote-2.37/base/plain_filldraw.asy000066400000000000000000000142241265434602500201230ustar00rootroot00000000000000// Draw path g on frame f with user-constructed pen p. void makedraw(frame f, path g, pen p, int depth=mantissaBits) { if(depth == 0) return; --depth; path n=nib(p); for(int i=0; i < size(g); ++i) fill(f,shift(point(g,i))*n,p); static real epsilon=1000*realEpsilon; int L=length(g); real stop=L-epsilon; int N=length(n); pair first=point(n,0); pair n0=first; for(int i=0; i < N; ++i) { pair n1=point(n,i+1); pair dir=unit(n1-n0); real t=dirtime(g,-dir)-epsilon; if(straight(g,(int) t)) t=ceil(t); if(t > epsilon && t < stop) { makedraw(f,subpath(g,0,t),p,depth); makedraw(f,subpath(g,t,L),p,depth); return; } real t=dirtime(g,dir); if(straight(g,(int) t)) t=ceil(t); if(t > epsilon && t < stop) { makedraw(f,subpath(g,0,t),p,depth); makedraw(f,subpath(g,t,L),p,depth); return; } n0=n1; } n0=first; for(int i=0; i < N; ++i) { pair n1=point(n,i+1); fill(f,shift(n0)*g--shift(n1)*reverse(g)--cycle,p); n0=n1; } } void draw(frame f, path g, pen p=currentpen) { if(size(nib(p)) == 0) _draw(f,g,p); else { begingroup(f); makedraw(f,g,p); endgroup(f); } } void draw(frame f, explicit path[] g, pen p=currentpen) { for(int i=0; i < g.length; ++i) draw(f,g[i],p); } void draw(frame f, guide[] g, pen p=currentpen) { for(int i=0; i < g.length; ++i) draw(f,g[i],p); } void filldraw(frame f, path[] g, pen fillpen=currentpen, pen drawpen=currentpen) { begingroup(f); fill(f,g,fillpen); draw(f,g,drawpen); endgroup(f); } path[] complement(frame f, path[] g) { static pair margin=(0.5,0.5); return box(minbound(min(f),min(g))-margin,maxbound(max(f),max(g))+margin)^^g; } void unfill(frame f, path[] g, bool copy=true) { clip(f,complement(f,g),evenodd,copy); } void filloutside(frame f, path[] g, pen p=currentpen, bool copy=true) { fill(f,complement(f,g),p+evenodd,copy); } struct filltype { typedef void fill2(frame f, path[] g, pen fillpen); fill2 fill2; pen fillpen; pen drawpen; int type; static int Fill=1; static int FillDraw=2; static int Draw=3; static int NoFill=4; static int UnFill=5; void operator init(int type=0, pen fillpen=nullpen, pen drawpen=nullpen, fill2 fill2) { this.type=type; this.fillpen=fillpen; this.drawpen=drawpen; this.fill2=fill2; } void fill(frame f, path[] g, pen p) {fill2(f,g,p);} } path[] margin(path[] g, real xmargin, real ymargin) { if(xmargin != 0 || ymargin != 0) { pair M=max(g); pair m=min(g); real width=M.x-m.x; real height=M.y-m.y; real xfactor=width > 0 ? (width+2xmargin)/width : 1; real yfactor=height > 0 ? (height+2ymargin)/height : 1; g=scale(xfactor,yfactor)*g; g=shift(0.5*(M+m)-0.5*(max(g)+min(g)))*g; } return g; } filltype Fill(real xmargin=0, real ymargin=xmargin, pen p=nullpen) { return filltype(filltype.Fill,p,new void(frame f, path[] g, pen fillpen) { if(p != nullpen) fillpen=p; if(fillpen == nullpen) fillpen=currentpen; fill(f,margin(g,xmargin,ymargin),fillpen); }); } filltype FillDraw(real xmargin=0, real ymargin=xmargin, pen fillpen=nullpen, pen drawpen=nullpen) { return filltype(filltype.FillDraw,fillpen,drawpen, new void(frame f, path[] g, pen Drawpen) { if(drawpen != nullpen) Drawpen=drawpen; pen Fillpen=fillpen == nullpen ? Drawpen : fillpen; if(Fillpen == nullpen) Fillpen=currentpen; if(Drawpen == nullpen) Drawpen=Fillpen; if(cyclic(g[0])) filldraw(f,margin(g,xmargin,ymargin),Fillpen,Drawpen); else draw(f,margin(g,xmargin,ymargin),Drawpen); }); } filltype Draw(real xmargin=0, real ymargin=xmargin, pen p=nullpen) { return filltype(filltype.Draw,drawpen=p, new void(frame f, path[] g, pen drawpen) { pen drawpen=p == nullpen ? drawpen : p; if(drawpen == nullpen) drawpen=currentpen; draw(f,margin(g,xmargin,ymargin),drawpen); }); } filltype NoFill=filltype(filltype.NoFill,new void(frame f, path[] g, pen p) { draw(f,g,p); }); filltype UnFill(real xmargin=0, real ymargin=xmargin) { return filltype(filltype.UnFill,new void(frame f, path[] g, pen) { unfill(f,margin(g,xmargin,ymargin)); }); } filltype FillDraw=FillDraw(), Fill=Fill(), Draw=Draw(), UnFill=UnFill(); // Fill varying radially from penc at the center of the bounding box to // penr at the edge. filltype RadialShade(pen penc, pen penr) { return filltype(new void(frame f, path[] g, pen) { pair c=(min(g)+max(g))/2; radialshade(f,g,penc,c,0,penr,c,abs(max(g)-min(g))/2); }); } filltype RadialShadeDraw(real xmargin=0, real ymargin=xmargin, pen penc, pen penr, pen drawpen=nullpen) { return filltype(new void(frame f, path[] g, pen Drawpen) { if(drawpen != nullpen) Drawpen=drawpen; if(Drawpen == nullpen) Drawpen=penc; pair c=(min(g)+max(g))/2; if(cyclic(g[0])) radialshade(f,margin(g,xmargin,ymargin),penc,c,0,penr,c, abs(max(g)-min(g))/2); draw(f,margin(g,xmargin,ymargin),Drawpen); }); } // Fill the region in frame dest underneath frame src and return the // boundary of src. path fill(frame dest, frame src, filltype filltype=NoFill, real xmargin=0, real ymargin=xmargin) { pair z=(xmargin,ymargin); path g=box(min(src)-z,max(src)+z); filltype.fill(dest,g,nullpen); return g; } // Add frame dest to frame src with optional grouping and background fill. void add(frame dest, frame src, bool group, filltype filltype=NoFill, bool above=true) { if(above) { if(filltype != NoFill) fill(dest,src,filltype); if(group) begingroup(dest); add(dest,src); if(group) endgroup(dest); } else { if(group) { frame f; endgroup(f); prepend(dest,f); } prepend(dest,src); if(group) { frame f; begingroup(f); prepend(dest,f); } if(filltype != NoFill) { frame f; fill(f,src,filltype); prepend(dest,f); } } } void add(frame dest, frame src, filltype filltype, bool above=filltype.type != filltype.UnFill) { if(filltype != NoFill) fill(dest,src,filltype); (above ? add : prepend)(dest,src); } asymptote-2.37/base/plain_margins.asy000066400000000000000000000047701265434602500177640ustar00rootroot00000000000000struct marginT { path g; real begin,end; }; typedef marginT margin(path, pen); path trim(path g, real begin, real end) { real a=arctime(g,begin); real b=arctime(g,arclength(g)-end); return a <= b ? subpath(g,a,b) : point(g,a); } margin operator +(margin ma, margin mb) { return new marginT(path g, pen p) { marginT margin; real ba=ma(g,p).begin < 0 ? 0 : ma(g,p).begin; real bb=mb(g,p).begin < 0 ? 0 : mb(g,p).begin; real ea=ma(g,p).end < 0 ? 0 : ma(g,p).end; real eb=mb(g,p).end < 0 ? 0 : mb(g,p).end; margin.begin=ba+bb; margin.end=ea+eb; margin.g=trim(g,margin.begin,margin.end); return margin; }; } margin NoMargin() { return new marginT(path g, pen) { marginT margin; margin.begin=margin.end=0; margin.g=g; return margin; }; } margin Margin(real begin, real end) { return new marginT(path g, pen p) { marginT margin; real factor=labelmargin(p); margin.begin=begin*factor; margin.end=end*factor; margin.g=trim(g,margin.begin,margin.end); return margin; }; } margin PenMargin(real begin, real end) { return new marginT(path g, pen p) { marginT margin; real factor=linewidth(p); margin.begin=(begin+0.5)*factor; margin.end=(end+0.5)*factor; margin.g=trim(g,margin.begin,margin.end); return margin; }; } margin DotMargin(real begin, real end) { return new marginT(path g, pen p) { marginT margin; real margindot(real x) {return x > 0 ? dotfactor*x : x;} real factor=linewidth(p); margin.begin=(margindot(begin)+0.5)*factor; margin.end=(margindot(end)+0.5)*factor; margin.g=trim(g,margin.begin,margin.end); return margin; }; } margin TrueMargin(real begin, real end) { return new marginT(path g, pen p) { marginT margin; margin.begin=begin; margin.end=end; margin.g=trim(g,begin,end); return margin; }; } margin NoMargin=NoMargin(), BeginMargin=Margin(1,0), Margin=Margin(0,1), EndMargin=Margin, Margins=Margin(1,1), BeginPenMargin=PenMargin(0.5,-0.5), PenMargin=PenMargin(-0.5,0.5), EndPenMargin=PenMargin, PenMargins=PenMargin(0.5,0.5), BeginDotMargin=DotMargin(0.5,-0.5), DotMargin=DotMargin(-0.5,0.5), EndDotMargin=DotMargin, DotMargins=DotMargin(0.5,0.5); asymptote-2.37/base/plain_markers.asy000066400000000000000000000257071265434602500177730ustar00rootroot00000000000000real legendlinelength=50; real legendhskip=1.2; real legendvskip=legendhskip; real legendmargin=10; real legendmaxrelativewidth=1; // Return a unit polygon with n sides. path polygon(int n) { guide g; for(int i=0; i < n; ++i) g=g--expi(2pi*(i+0.5)/n-0.5*pi); return g--cycle; } // Return a unit n-point cyclic cross, with optional inner radius r and // end rounding. path cross(int n, bool round=true, real r=0) { assert(n > 1); real r=min(r,1); real theta=pi/n; real s=sin(theta); real c=cos(theta); pair z=(c,s); transform mirror=reflect(0,z); pair p1=(r,0); path elementary; if(round) { pair e1=p1+z*max(1-r*(s+c),0); elementary=p1--e1..(c,s)..mirror*e1--mirror*p1; } else { pair p2=p1+z*(max(sqrt(1-(r*s)^2)-r*c),0); elementary=p1--p2--mirror*p2--mirror*p1; } guide g; real step=360/n; for(int i=0; i < n; ++i) g=g--rotate(i*step-90)*elementary; return g--cycle; } path[] plus=(-1,0)--(1,0)^^(0,-1)--(0,1); typedef void markroutine(picture pic=currentpicture, frame f, path g); // On picture pic, add frame f about every node of path g. void marknodes(picture pic=currentpicture, frame f, path g) { for(int i=0; i < size(g); ++i) add(pic,f,point(g,i)); } // On picture pic, add n copies of frame f to path g, evenly spaced in // arclength. // If rotated=true, the frame will be rotated by the angle of the tangent // to the path at the points where the frame will be added. // If centered is true, center the frames within n evenly spaced arclength // intervals. markroutine markuniform(bool centered=false, int n, bool rotated=false) { return new void(picture pic=currentpicture, frame f, path g) { if(n <= 0) return; void add(real x) { real t=reltime(g,x); add(pic,rotated ? rotate(degrees(dir(g,t)))*f : f,point(g,t)); } if(centered) { real width=1/n; for(int i=0; i < n; ++i) add((i+0.5)*width); } else { if(n == 1) add(0.5); else { real width=1/(n-1); for(int i=0; i < n; ++i) add(i*width); } } }; } // On picture pic, add frame f at points z(t) for n evenly spaced values of // t in [a,b]. markroutine markuniform(pair z(real t), real a, real b, int n) { return new void(picture pic=currentpicture, frame f, path) { real width=b-a; for(int i=0; i <= n; ++i) { add(pic,f,z(a+i/n*width)); } }; } struct marker { frame f; bool above=true; markroutine markroutine=marknodes; void mark(picture pic=currentpicture, path g) { markroutine(pic,f,g); }; } marker marker(frame f=newframe, markroutine markroutine=marknodes, bool above=true) { marker m=new marker; m.f=f; m.above=above; m.markroutine=markroutine; return m; } marker marker(path[] g, markroutine markroutine=marknodes, pen p=currentpen, filltype filltype=NoFill, bool above=true) { frame f; filltype.fill(f,g,p); return marker(f,markroutine,above); } // On picture pic, add path g with opacity thinning about every node. marker markthin(path g, pen p=currentpen, real thin(real fraction)=new real(real x) {return x^2;}, filltype filltype=NoFill) { marker M=new marker; M.above=true; filltype.fill(M.f,g,p); real factor=1/abs(size(M.f)); M.markroutine=new void(picture pic=currentpicture, frame, path G) { transform t=pic.calculateTransform(); int n=size(G); for(int i=0; i < n; ++i) { pair z=point(G,i); frame f; real fraction=1; if(i > 0) fraction=min(fraction,abs(t*(z-point(G,i-1)))*factor); if(i < n-1) fraction=min(fraction,abs(t*(point(G,i+1)-z))*factor); filltype.fill(f,g,p+opacity(thin(fraction))); add(pic,f,point(G,i)); } }; return M; } marker nomarker; real circlescale=0.85; path[] MarkPath={scale(circlescale)*unitcircle, polygon(3),polygon(4),polygon(5),invert*polygon(3), cross(4),cross(6)}; marker[] Mark=sequence(new marker(int i) {return marker(MarkPath[i]);}, MarkPath.length); marker[] MarkFill=sequence(new marker(int i) {return marker(MarkPath[i],Fill);}, MarkPath.length-2); marker Mark(int n) { n=n % (Mark.length+MarkFill.length); if(n < Mark.length) return Mark[n]; else return MarkFill[n-Mark.length]; } picture legenditem(Legend legenditem, real linelength) { picture pic; pair z1=(0,0); pair z2=z1+(linelength,0); if(!legenditem.above && !empty(legenditem.mark)) marknodes(pic,legenditem.mark,interp(z1,z2,0.5)); if(linelength > 0) Draw(pic,z1--z2,legenditem.p); if(legenditem.above && !empty(legenditem.mark)) marknodes(pic,legenditem.mark,interp(z1,z2,0.5)); if(legenditem.plabel != invisible) label(pic,legenditem.label,z2,E,legenditem.plabel); else label(pic,legenditem.label,z2,E,currentpen); return pic; } picture legend(Legend[] Legend, int perline=1, real linelength, real hskip, real vskip, real maxwidth=0, real maxheight=0, bool hstretch=false, bool vstretch=false) { if(maxwidth <= 0) hstretch=false; if(maxheight <= 0) vstretch=false; if(Legend.length <= 1) vstretch=hstretch=false; picture inset; size(inset,0,0,IgnoreAspect); if(Legend.length == 0) return inset; // Check for legend entries with lines: bool bLineEntriesAvailable=false; for(int i=0; i < Legend.length; ++i) { if(Legend[i].p != invisible) { bLineEntriesAvailable=true; break; } } real markersize=0; for(int i=0; i < Legend.length; ++i) markersize=max(markersize,size(Legend[i].mark).x); // If no legend has a line, set the line length to zero if(!bLineEntriesAvailable) linelength=0; linelength=max(linelength,markersize*(linelength == 0 ? 1 : 2)); // Get the maximum dimensions per legend entry; // calculate line length for a one-line legend real heightPerEntry=0; real widthPerEntry=0; real totalwidth=0; for(int i=0; i < Legend.length; ++i) { picture pic=legenditem(Legend[i],linelength); pair lambda=size(pic); heightPerEntry=max(heightPerEntry,lambda.y); widthPerEntry=max(widthPerEntry,lambda.x); if(Legend[i].p != invisible) totalwidth += lambda.x; else { // Legend entries without leading line need less space in one-line legends picture pic=legenditem(Legend[i],0); totalwidth += size(pic).x; } } // Does everything fit into one line? if(((perline < 1) || (perline >= Legend.length)) && (maxwidth >= totalwidth+(totalwidth/Legend.length)* (Legend.length-1)*(hskip-1))) { // One-line legend real currPosX=0; real itemDistance; if(hstretch) itemDistance=(maxwidth-totalwidth)/(Legend.length-1); else itemDistance=(totalwidth/Legend.length)*(hskip-1); for(int i=0; i < Legend.length; ++i) { picture pic=legenditem(Legend[i], Legend[i].p == invisible ? 0 : linelength); add(inset,pic,(currPosX,0)); currPosX += size(pic).x+itemDistance; } } else { // multiline legend if(maxwidth > 0) { int maxperline=floor(maxwidth/(widthPerEntry*hskip)); if((perline < 1) || (perline > maxperline)) perline=maxperline; } if(perline < 1) // This means: maxwidth < widthPerEntry perline=1; if(perline <= 1) hstretch=false; if(hstretch) hskip=(maxwidth/widthPerEntry-perline)/(perline-1)+1; if(vstretch) { int rows=ceil(Legend.length/perline); vskip=(maxheight/heightPerEntry-rows)/(rows-1)+1; } if(hstretch && (perline == 1)) { Draw(inset,(0,0)--(maxwidth,0),invisible()); for(int i=0; i < Legend.length; ++i) add(inset,legenditem(Legend[i],linelength), (0.5*(maxwidth-widthPerEntry), -quotient(i,perline)*heightPerEntry*vskip)); } else for(int i=0; i < Legend.length; ++i) add(inset,legenditem(Legend[i],linelength), ((i%perline)*widthPerEntry*hskip, -quotient(i,perline)*heightPerEntry*vskip)); } return inset; } frame legend(picture pic=currentpicture, int perline=1, real xmargin=legendmargin, real ymargin=xmargin, real linelength=legendlinelength, real hskip=legendhskip, real vskip=legendvskip, real maxwidth=perline == 0 ? legendmaxrelativewidth*size(pic).x : 0, real maxheight=0, bool hstretch=false, bool vstretch=false, pen p=currentpen) { frame F; if(pic.legend.length == 0) return F; F=legend(pic.legend,perline,linelength,hskip,vskip, max(maxwidth-2xmargin,0), max(maxheight-2ymargin,0), hstretch,vstretch).fit(); box(F,xmargin,ymargin,p); return F; } pair[] pairs(real[] x, real[] y) { if(x.length != y.length) abort("arrays have different lengths"); return sequence(new pair(int i) {return (x[i],y[i]);},x.length); } void dot(frame f, pair z, pen p=currentpen, filltype filltype=Fill) { if(filltype == Fill) draw(f,z,dotsize(p)+p); else { transform t=shift(z); path g=t*scale(0.5*(dotsize(p)-linewidth(p)))*unitcircle; begingroup(f); filltype.fill(f,g,p); draw(f,g,p); endgroup(f); } } void dot(picture pic=currentpicture, pair z, pen p=currentpen, filltype filltype=Fill) { pic.add(new void(frame f, transform t) { dot(f,t*z,p,filltype); },true); pic.addPoint(z,dotsize(p)+p); } void dot(picture pic=currentpicture, Label L, pair z, align align=NoAlign, string format=defaultformat, pen p=currentpen, filltype filltype=Fill) { Label L=L.copy(); L.position(z); if(L.s == "") { if(format == "") format=defaultformat; L.s="("+format(format,z.x)+","+format(format,z.y)+")"; } L.align(align,E); L.p(p); dot(pic,z,p,filltype); add(pic,L); } void dot(picture pic=currentpicture, Label[] L=new Label[], pair[] z, align align=NoAlign, string format=defaultformat, pen p=currentpen, filltype filltype=Fill) { int stop=min(L.length,z.length); for(int i=0; i < stop; ++i) dot(pic,L[i],z[i],align,format,p,filltype); for(int i=stop; i < z.length; ++i) dot(pic,z[i],p,filltype); } void dot(picture pic=currentpicture, Label[] L=new Label[], explicit path g, align align=RightSide, string format=defaultformat, pen p=currentpen, filltype filltype=Fill) { int n=size(g); int stop=min(L.length,n); for(int i=0; i < stop; ++i) dot(pic,L[i],point(g,i),-sgn(align.dir.x)*I*dir(g,i),format,p,filltype); for(int i=stop; i < n; ++i) dot(pic,point(g,i),p,filltype); } void dot(picture pic=currentpicture, path[] g, pen p=currentpen, filltype filltype=Fill) { for(int i=0; i < g.length; ++i) dot(pic,g[i],p,filltype); } void dot(picture pic=currentpicture, Label L, pen p=currentpen, filltype filltype=Fill) { dot(pic,L,L.position,p,filltype); } // A dot in a frame. frame dotframe(pen p=currentpen, filltype filltype=Fill) { frame f; dot(f,(0,0),p,filltype); return f; } frame dotframe=dotframe(); marker dot(pen p=currentpen, filltype filltype=Fill) { return marker(dotframe(p,filltype)); } marker dot=dot(); asymptote-2.37/base/plain_paths.asy000066400000000000000000000221351265434602500174360ustar00rootroot00000000000000path nullpath; typedef guide interpolate(... guide[]); // These numbers identify the side of a specifier in an operator spec or // operator curl expression: // a{out} .. {in}b restricted int JOIN_OUT=0; restricted int JOIN_IN=1; // Define a.. tension t ..b to be equivalent to // a.. tension t and t ..b // and likewise with controls. tensionSpecifier operator tension(real t, bool atLeast) { return operator tension(t,t,atLeast); } guide operator controls(pair z) { return operator controls(z,z); } guide[] operator cast(pair[] z) { return sequence(new guide(int i) {return z[i];},z.length); } path[] operator cast(pair[] z) { return sequence(new path(int i) {return z[i];},z.length); } path[] operator cast(guide[] g) { return sequence(new path(int i) {return g[i];},g.length); } guide[] operator cast(path[] g) { return sequence(new guide(int i) {return g[i];},g.length); } path[] operator cast(path p) { return new path[] {p}; } path[] operator cast(guide g) { return new path[] {(path) g}; } path[] operator ^^ (path p, path q) { return new path[] {p,q}; } path[] operator ^^ (path p, explicit path[] q) { return concat(new path[] {p},q); } path[] operator ^^ (explicit path[] p, path q) { return concat(p,new path[] {q}); } path[] operator ^^ (explicit path[] p, explicit path[] q) { return concat(p,q); } path[] operator * (transform t, explicit path[] p) { return sequence(new path(int i) {return t*p[i];},p.length); } pair[] operator * (transform t, pair[] z) { return sequence(new pair(int i) {return t*z[i];},z.length); } void write(file file, string s="", explicit path[] x, suffix suffix=none) { write(file,s); if(x.length > 0) write(file,x[0]); for(int i=1; i < x.length; ++i) { write(file,endl); write(file," ^^"); write(file,x[i]); } write(file,suffix); } void write(string s="", explicit path[] x, suffix suffix=endl) { write(stdout,s,x,suffix); } void write(file file, string s="", explicit guide[] x, suffix suffix=none) { write(file,s); if(x.length > 0) write(file,x[0]); for(int i=1; i < x.length; ++i) { write(file,endl); write(file," ^^"); write(file,x[i]); } write(file,suffix); } void write(string s="", explicit guide[] x, suffix suffix=endl) { write(stdout,s,x,suffix); } interpolate operator ..(tensionSpecifier t) { return new guide(... guide[] a) { if(a.length == 0) return nullpath; guide g=a[0]; for(int i=1; i < a.length; ++i) g=g..t..a[i]; return g; }; } interpolate operator ::=operator ..(operator tension(1,true)); interpolate operator ---=operator ..(operator tension(infinity,true)); // return an arbitrary intersection point of paths p and q pair intersectionpoint(path p, path q, real fuzz=-1) { real[] t=intersect(p,q,fuzz); if(t.length == 0) abort("paths do not intersect"); return point(p,t[0]); } // return an array containing all intersection points of the paths p and q pair[] intersectionpoints(path p, path q, real fuzz=-1) { real[][] t=intersections(p,q,fuzz); return sequence(new pair(int i) {return point(p,t[i][0]);},t.length); } pair[] intersectionpoints(explicit path[] p, explicit path[] q, real fuzz=-1) { pair[] z; for(int i=0; i < p.length; ++i) for(int j=0; j < q.length; ++j) z.append(intersectionpoints(p[i],q[j],fuzz)); return z; } struct slice { path before,after; } slice cut(path p, path knife, int n) { slice s; real[][] T=intersections(p,knife); if(T.length == 0) {s.before=p; s.after=nullpath; return s;} T.cyclic=true; real t=T[n][0]; s.before=subpath(p,0,t); s.after=subpath(p,t,length(p)); return s; } slice firstcut(path p, path knife) { return cut(p,knife,0); } slice lastcut(path p, path knife) { return cut(p,knife,-1); } pair dir(path p) { return dir(p,length(p)); } pair dir(path p, path q) { return unit(dir(p)+dir(q)); } // return the point on path p at arclength L pair arcpoint(path p, real L) { return point(p,arctime(p,L)); } // return the direction on path p at arclength L pair arcdir(path p, real L) { return dir(p,arctime(p,L)); } // return the time on path p at the relative fraction l of its arclength real reltime(path p, real l) { return arctime(p,l*arclength(p)); } // return the point on path p at the relative fraction l of its arclength pair relpoint(path p, real l) { return point(p,reltime(p,l)); } // return the direction of path p at the relative fraction l of its arclength pair reldir(path p, real l) { return dir(p,reltime(p,l)); } // return the initial point of path p pair beginpoint(path p) { return point(p,0); } // return the point on path p at half of its arclength pair midpoint(path p) { return relpoint(p,0.5); } // return the final point of path p pair endpoint(path p) { return point(p,length(p)); } path operator &(path p, cycleToken tok) { int n=length(p); if(n < 0) return nullpath; if(n == 0) return p--cycle; if(cyclic(p)) return p; return straight(p,n-1) ? subpath(p,0,n-1)--cycle : subpath(p,0,n-1)..controls postcontrol(p,n-1) and precontrol(p,n)..cycle; } // return a cyclic path enclosing a region bounded by a list of two or more // consecutively intersecting paths path buildcycle(... path[] p) { int n=p.length; if(n < 2) return nullpath; real[] ta=new real[n]; real[] tb=new real[n]; if(n == 2) { real[][] t=intersections(p[0],p[1]); if(t.length < 2) return nullpath; int k=t.length-1; ta[0]=t[0][0]; tb[0]=t[k][0]; ta[1]=t[k][1]; tb[1]=t[0][1]; } else { int j=n-1; for(int i=0; i < n; ++i) { real[][] t=intersections(p[i],p[j]); if(t.length == 0) return nullpath; ta[i]=t[0][0]; tb[j]=t[0][1]; j=i; } } pair c; for(int i=0; i < n ; ++i) c += point(p[i],ta[i]); c /= n; path G; for(int i=0; i < n ; ++i) { real Ta=ta[i]; real Tb=tb[i]; if(cyclic(p[i])) { int L=length(p[i]); real t=Tb-L; if(abs(c-point(p[i],0.5(Ta+t))) < abs(c-point(p[i],0.5(Ta+Tb)))) Tb=t; while(Tb < Ta) Tb += L; } G=G&subpath(p[i],Ta,Tb); } return G&cycle; } // return 1 if p strictly contains q, // -1 if q strictly contains p, // 0 otherwise. int inside(path p, path q, pen fillrule=currentpen) { if(intersect(p,q).length > 0) return 0; if(cyclic(p) && inside(p,point(q,0),fillrule)) return 1; if(cyclic(q) && inside(q,point(p,0),fillrule)) return -1; return 0; } // Return an arbitrary point strictly inside a cyclic path p according to // the specified fill rule. pair inside(path p, pen fillrule=currentpen) { if(!cyclic(p)) abort("path is not cyclic"); int n=length(p); for(int i=0; i < n; ++i) { pair z=point(p,i); pair dir=dir(p,i); if(dir == 0) continue; real[] T=intersections(p,z,z+I*dir); // Check midpoints of line segments formed between the // corresponding intersection points and z. for(int j=0; j < T.length; ++j) { if(T[j] != i) { pair w=point(p,T[j]); pair m=0.5*(z+w); if(interior(windingnumber(p,m),fillrule)) return m; } } } // cannot find an interior point: path is degenerate return point(p,0); } // Return all intersection times of path g with the vertical line through (x,0). real[] times(path p, real x) { return intersections(p,(x,0),(x,1)); } // Return all intersection times of path g with the horizontal line through // (0,z.y). real[] times(path p, explicit pair z) { return intersections(p,(0,z.y),(1,z.y)); } path randompath(int n, bool cumulate=true, interpolate join=operator ..) { guide g; pair w; for(int i=0; i <= n; ++i) { pair z=(unitrand()-0.5,unitrand()-0.5); if(cumulate) w += z; else w=z; g=join(g,w); } return g; } path[] strokepath(path g, pen p=currentpen) { path[] G=_strokepath(g,p); if(G.length == 0) return G; pair center(path g) {return 0.5*(min(g)+max(g));} pair center(path[] g) {return 0.5*(min(g)+max(g));} return shift(center(g)-center(G))*G; } real braceinnerangle=radians(60); real braceouterangle=radians(70); real bracemidangle=radians(0); real bracedefaultratio=0.14; path brace(pair a, pair b, real amplitude=bracedefaultratio*length(b-a)) { real length=length(b-a); real sign=sgn(amplitude); real hamplitude=0.5*amplitude; real hlength=0.5*length; path brace; if(abs(amplitude) < bracedefaultratio*length) { real slope=2*bracedefaultratio; real controldist=(abs(hamplitude))/slope; brace=(0,0){expi(sign*braceouterangle)}:: {expi(sign*bracemidangle)}(controldist,hamplitude):: {expi(sign*bracemidangle)}(hlength-controldist,hamplitude):: {expi(sign*braceinnerangle)}(hlength,amplitude) {expi(-sign*braceinnerangle)}:: {expi(-sign*bracemidangle)}(hlength+controldist,hamplitude):: {expi(-sign*bracemidangle)}(length-controldist,hamplitude):: {expi(-sign*braceouterangle)}(length,0); } else { brace=(0,0){expi(sign*braceouterangle)}:: {expi(sign*bracemidangle)}(0.25*length,hamplitude):: {expi(sign*braceinnerangle)}(hlength,amplitude){expi(-sign*braceinnerangle)}:: {expi(-sign*bracemidangle)}(0.75*length,hamplitude):: {expi(-sign*braceouterangle)}(length,0); } return shift(a)*rotate(degrees(b-a,warn=false))*brace; } asymptote-2.37/base/plain_pens.asy000066400000000000000000000205051265434602500172630ustar00rootroot00000000000000real labelmargin=0.3; real dotfactor=6; pen solid=linetype(new real[]); pen dotted=linetype(new real[] {0,4}); pen dashed=linetype(new real[] {8,8}); pen longdashed=linetype(new real[] {24,8}); pen dashdotted=linetype(new real[] {8,8,0,8}); pen longdashdotted=linetype(new real[] {24,8,0,8}); pen linetype(string pattern, real offset=0, bool scale=true, bool adjust=true) { return linetype((real[]) split(pattern),offset,scale,adjust); } void defaultpen(real w) {defaultpen(linewidth(w));} pen operator +(pen p, real w) {return p+linewidth(w);} pen operator +(real w, pen p) {return linewidth(w)+p;} pen Dotted(pen p=currentpen) {return linetype(new real[] {0,3})+2*linewidth(p);} pen Dotted=Dotted(); restricted pen squarecap=linecap(0); restricted pen roundcap=linecap(1); restricted pen extendcap=linecap(2); restricted pen miterjoin=linejoin(0); restricted pen roundjoin=linejoin(1); restricted pen beveljoin=linejoin(2); restricted pen zerowinding=fillrule(0); restricted pen evenodd=fillrule(1); bool interior(int windingnumber, pen fillrule) { return windingnumber != undefined && (fillrule(fillrule) == 1 ? windingnumber % 2 == 1 : windingnumber != 0); } restricted pen nobasealign=basealign(0); restricted pen basealign=basealign(1); pen invisible=invisible(); pen thin() {return settings.thin ? linewidth(0) : defaultpen;} pen thick(pen p=currentpen) {return linewidth(linewidth(p));} pen nullpen=linewidth(0)+invisible; pen black=gray(0); pen white=gray(1); pen gray=gray(0.5); pen red=rgb(1,0,0); pen green=rgb(0,1,0); pen blue=rgb(0,0,1); pen Cyan=cmyk(1,0,0,0); pen Magenta=cmyk(0,1,0,0); pen Yellow=cmyk(0,0,1,0); pen Black=cmyk(0,0,0,1); pen cyan=rgb(0,1,1); pen magenta=rgb(1,0,1); pen yellow=rgb(1,1,0); pen palered=rgb(1,0.75,0.75); pen palegreen=rgb(0.75,1,0.75); pen paleblue=rgb(0.75,0.75,1); pen palecyan=rgb(0.75,1,1); pen palemagenta=rgb(1,0.75,1); pen paleyellow=rgb(1,1,0.75); pen palegray=gray(0.95); pen lightred=rgb(1,0.5,0.5); pen lightgreen=rgb(0.5,1,0.5); pen lightblue=rgb(0.5,0.5,1); pen lightcyan=rgb(0.5,1,1); pen lightmagenta=rgb(1,0.5,1); pen lightyellow=rgb(1,1,0.5); pen lightgray=gray(0.9); pen mediumred=rgb(1,0.25,0.25); pen mediumgreen=rgb(0.25,1,0.25); pen mediumblue=rgb(0.25,0.25,1); pen mediumcyan=rgb(0.25,1,1); pen mediummagenta=rgb(1,0.25,1); pen mediumyellow=rgb(1,1,0.25); pen mediumgray=gray(0.75); pen heavyred=rgb(0.75,0,0); pen heavygreen=rgb(0,0.75,0); pen heavyblue=rgb(0,0,0.75); pen heavycyan=rgb(0,0.75,0.75); pen heavymagenta=rgb(0.75,0,0.75); pen lightolive=rgb(0.75,0.75,0); pen heavygray=gray(0.25); pen deepred=rgb(0.5,0,0); pen deepgreen=rgb(0,0.5,0); pen deepblue=rgb(0,0,0.5); pen deepcyan=rgb(0,0.5,0.5); pen deepmagenta=rgb(0.5,0,0.5); pen olive=rgb(0.5,0.5,0); pen deepgray=gray(0.1); pen darkred=rgb(0.25,0,0); pen darkgreen=rgb(0,0.25,0); pen darkblue=rgb(0,0,0.25); pen darkcyan=rgb(0,0.25,0.25); pen darkmagenta=rgb(0.25,0,0.25); pen darkolive=rgb(0.25,0.25,0); pen darkgray=gray(0.05); pen orange=rgb(1,0.5,0); pen fuchsia=rgb(1,0,0.5); pen chartreuse=rgb(0.5,1,0); pen springgreen=rgb(0,1,0.5); pen purple=rgb(0.5,0,1); pen royalblue=rgb(0,0.5,1); // Synonyms: pen salmon=lightred; pen brown=deepred; pen darkbrown=darkred; pen pink=palemagenta; pen palegrey=palegray; pen lightgrey=lightgray; pen mediumgrey=mediumgray; pen grey=gray; pen heavygrey=heavygray; pen deepgrey=deepgray; pen darkgrey=darkgray; // Options for handling label overwriting restricted int Allow=0; restricted int Suppress=1; restricted int SuppressQuiet=2; restricted int Move=3; restricted int MoveQuiet=4; pen[] colorPen={red,blue,green,magenta,cyan,orange,purple,brown, deepblue,deepgreen,chartreuse,fuchsia,lightred, lightblue,black,pink,yellow,gray}; colorPen.cyclic=true; pen[] monoPen={solid,dashed,dotted,longdashed,dashdotted, longdashdotted}; monoPen.cyclic=true; pen Pen(int n) { return (settings.gray || settings.bw) ? monoPen[n] : colorPen[n]; } pen Pentype(int n) { return (settings.gray || settings.bw) ? monoPen[n] : monoPen[n]+colorPen[n]; } real dotsize(pen p=currentpen) { return dotfactor*linewidth(p); } pen fontsize(real size) { return fontsize(size,1.2*size); } real labelmargin(pen p=currentpen) { return labelmargin*fontsize(p); } void write(file file=stdout, string s="", pen[] p) { for(int i=0; i < p.length; ++i) write(file,s,p[i],endl); } void usetypescript(string s, string encoding="") { string s="\usetypescript["+s+"]"; if(encoding != "") s +="["+encoding+"]"; texpreamble(s); } pen font(string name, string options="") { // Work around misalignment in ConTeXt switchtobodyfont if font is not found. return fontcommand(settings.tex == "context" ? "\switchtobodyfont["+name+ (options == "" ? "" : ","+options)+ "]\removeunwantedspaces" : "\font\ASYfont="+name+"\ASYfont"); } pen font(string name, real size, string options="") { string s=(string) (size/pt)+"pt"; if(settings.tex == "context") return fontsize(size)+font(name+","+s,options); return fontsize(size)+font(name+" at "+s); } pen font(string encoding, string family, string series, string shape) { return fontcommand("\usefont{"+encoding+"}{"+family+"}{"+series+"}{"+shape+ "}"); } pen AvantGarde(string series="m", string shape="n") { return font("OT1","pag",series,shape); } pen Bookman(string series="m", string shape="n") { return font("OT1","pbk",series,shape); } pen Courier(string series="m", string shape="n") { return font("OT1","pcr",series,shape); } pen Helvetica(string series="m", string shape="n") { return font("OT1","phv",series,shape); } pen NewCenturySchoolBook(string series="m", string shape="n") { return font("OT1","pnc",series,shape); } pen Palatino(string series="m", string shape="n") { return font("OT1","ppl",series,shape); } pen TimesRoman(string series="m", string shape="n") { return font("OT1","ptm",series,shape); } pen ZapfChancery(string series="m", string shape="n") { return font("OT1","pzc",series,shape); } pen Symbol(string series="m", string shape="n") { return font("OT1","psy",series,shape); } pen ZapfDingbats(string series="m", string shape="n") { return font("OT1","pzd",series,shape); } pen squarepen=makepen(shift(-0.5,-0.5)*unitsquare); struct hsv { real h; real v; real s; void operator init(real h, real s, real v) { this.h=h; this.s=s; this.v=v; } void operator init(pen p) { real[] c=colors(rgb(p)); real r=c[0]; real g=c[1]; real b=c[2]; real M=max(r,g,b); real m=min(r,g,b); if(M == m) this.h=0; else { real denom=1/(M-m); if(M == r) { this.h=60*(g-b)*denom; if(g < b) h += 360; } else if(M == g) { this.h=60*(b-r)*denom+120; } else this.h=60*(r-g)*denom+240; } this.s=M == 0 ? 0 : 1-m/M; this.v=M; } // return an rgb pen corresponding to h in [0,360) and s and v in [0,1]. pen rgb() { real H=(h % 360)/60; int i=floor(H) % 6; real f=H-i; real[] V={v,v*(1-s),v*(1-(i % 2 == 0 ? 1-f : f)*s)}; int[] a={0,2,1,1,2,0}; int[] b={2,0,0,2,1,1}; int[] c={1,1,2,0,0,2}; return rgb(V[a[i]],V[b[i]],V[c[i]]); } } pen operator cast(hsv hsv) { return hsv.rgb(); } hsv operator cast(pen p) { return hsv(p); } real[] rgba(pen p) { real[] a=colors(rgb(p)); a.push(opacity(p)); return a; } pen rgba(real[] a) { return rgb(a[0],a[1],a[2])+opacity(a[3]); } // Return a pen corresponding to a given 6-character RGB hexidecimal string. pen rgb(string s) { real value(string s, int i) {return hex(substr(s,2i,2))/255;} return rgb(value(s,0),value(s,1),value(s,2)); } pen[] operator +(pen[] a, pen b) { return sequence(new pen(int i) {return a[i]+b;},a.length); } pen[] operator +(pen a, pen[] b) { return sequence(new pen(int i) {return a+b[i];},b.length); } // Interpolate an array of pens in rgb space using by default their minimum // opacity. pen mean(pen[] p, real opacity(real[])=min) { if(p.length == 0) return nullpen; real[] a=rgba(p[0]); real[] t=new real[p.length]; t[0]=a[3]; for(int i=1; i < p.length; ++i) { real[] b=rgba(p[i]); a += b; t[i]=b[3]; } a /= p.length; return rgb(a[0],a[1],a[2])+opacity(opacity(t)); } pen[] mean(pen[][] palette, real opacity(real[])=min) { return sequence(new pen(int i) {return mean(palette[i],opacity);}, palette.length); } asymptote-2.37/base/plain_picture.asy000066400000000000000000001317741265434602500200040ustar00rootroot00000000000000// Pre picture <<<1 import plain_scaling; import plain_bounds; include plain_prethree; // This variable is required by asymptote.sty. pair viewportsize=0; // Horizontal and vertical viewport limits. restricted bool Aspect=true; restricted bool IgnoreAspect=false; struct coords3 { coord[] x,y,z; void erase() { x.delete(); y.delete(); z.delete(); } // Only a shallow copy of the individual elements of x and y // is needed since, once entered, they are never modified. coords3 copy() { coords3 c=new coords3; c.x=copy(x); c.y=copy(y); c.z=copy(z); return c; } void append(coords3 c) { x.append(c.x); y.append(c.y); z.append(c.z); } void push(triple user, triple truesize) { x.push(coord.build(user.x,truesize.x)); y.push(coord.build(user.y,truesize.y)); z.push(coord.build(user.z,truesize.z)); } void push(coord cx, coord cy, coord cz) { x.push(cx); y.push(cy); z.push(cz); } void push(transform3 t, coords3 c1, coords3 c2, coords3 c3) { for(int i=0; i < c1.x.length; ++i) { coord cx=c1.x[i], cy=c2.y[i], cz=c3.z[i]; triple tinf=shiftless(t)*(0,0,0); triple z=t*(cx.user,cy.user,cz.user); triple w=(cx.truesize,cy.truesize,cz.truesize); w=length(w)*unit(shiftless(t)*w); coord Cx,Cy,Cz; Cx.user=z.x; Cy.user=z.y; Cz.user=z.z; Cx.truesize=w.x; Cy.truesize=w.y; Cz.truesize=w.z; push(Cx,Cy,Cz); } } } // scaleT and Legend <<< typedef real scalefcn(real x); struct scaleT { scalefcn T,Tinv; bool logarithmic; bool automin,automax; void operator init(scalefcn T, scalefcn Tinv, bool logarithmic=false, bool automin=false, bool automax=false) { this.T=T; this.Tinv=Tinv; this.logarithmic=logarithmic; this.automin=automin; this.automax=automax; } scaleT copy() { scaleT dest=scaleT(T,Tinv,logarithmic,automin,automax); return dest; } }; scaleT operator init() { scaleT S=scaleT(identity,identity); return S; } typedef void boundRoutine(); struct autoscaleT { scaleT scale; scaleT postscale; real tickMin=-infinity, tickMax=infinity; boundRoutine[] bound; // Optional routines to recompute the bounding box. bool automin=false, automax=false; bool automin() {return automin && scale.automin;} bool automax() {return automax && scale.automax;} real T(real x) {return postscale.T(scale.T(x));} scalefcn T() {return scale.logarithmic ? postscale.T : T;} real Tinv(real x) {return scale.Tinv(postscale.Tinv(x));} autoscaleT copy() { autoscaleT dest=new autoscaleT; dest.scale=scale.copy(); dest.postscale=postscale.copy(); dest.tickMin=tickMin; dest.tickMax=tickMax; dest.bound=copy(bound); dest.automin=(bool) automin; dest.automax=(bool) automax; return dest; } } struct ScaleT { bool set; autoscaleT x; autoscaleT y; autoscaleT z; ScaleT copy() { ScaleT dest=new ScaleT; dest.set=set; dest.x=x.copy(); dest.y=y.copy(); dest.z=z.copy(); return dest; } }; struct Legend { string label; pen plabel; pen p; frame mark; bool above; void operator init(string label, pen plabel=currentpen, pen p=nullpen, frame mark=newframe, bool above=true) { this.label=label; this.plabel=plabel; this.p=(p == nullpen) ? plabel : p; this.mark=mark; this.above=above; } } // >>> // Frame Alignment was here triple min3(pen p) { return linewidth(p)*(-0.5,-0.5,-0.5); } triple max3(pen p) { return linewidth(p)*(0.5,0.5,0.5); } // A function that draws an object to frame pic, given that the transform // from user coordinates to true-size coordinates is t. typedef void drawer(frame f, transform t); // A generalization of drawer that includes the final frame's bounds. // TODO: Add documentation as to what T is. typedef void drawerBound(frame f, transform t, transform T, pair lb, pair rt); // PairOrTriple <<<1 // This struct is used to represent a userMin/userMax which serves as both a // pair and a triple depending on the context. struct pairOrTriple { real x,y,z; void init() { x = y = z = 0; } }; void copyPairOrTriple(pairOrTriple dest, pairOrTriple src) { dest.x = src.x; dest.y = src.y; dest.z = src.z; } pair operator cast (pairOrTriple a) { return (a.x, a.y); }; triple operator cast (pairOrTriple a) { return (a.x, a.y, a.z); } void write(pairOrTriple a) { write((triple) a); } struct picture { // <<<1 // Nodes <<<2 // Three-dimensional version of drawer and drawerBound: typedef void drawer3(frame f, transform3 t, picture pic, projection P); typedef void drawerBound3(frame f, transform3 t, transform3 T, picture pic, projection P, triple lb, triple rt); // The functions to do the deferred drawing. drawerBound[] nodes; drawerBound3[] nodes3; bool uptodate=true; struct bounds3 { coords3 point,min,max; bool exact=true; // An accurate picture bounds is provided by the user. void erase() { point.erase(); min.erase(); max.erase(); } bounds3 copy() { bounds3 b=new bounds3; b.point=point.copy(); b.min=min.copy(); b.max=max.copy(); b.exact=exact; return b; } } bounds bounds; bounds3 bounds3; // Other Fields <<<2 // Transform to be applied to this picture. transform T; transform3 T3; // The internal representation of the 3D user bounds. private pairOrTriple umin, umax; private bool usetx, usety, usetz; ScaleT scale; // Needed by graph Legend[] legend; pair[] clipmax; // Used by beginclip/endclip pair[] clipmin; // The maximum sizes in the x, y, and z directions; zero means no restriction. real xsize=0, ysize=0; real xsize3=0, ysize3=0, zsize3=0; // Fixed unitsizes in the x y, and z directions; zero means use // xsize, ysize, and zsize. real xunitsize=0, yunitsize=0, zunitsize=0; // If true, the x and y directions must be scaled by the same amount. bool keepAspect=true; // A fixed scaling transform. bool fixed; transform fixedscaling; // Init and erase <<<2 void init() { umin.init(); umax.init(); usetx=usety=usetz=false; T3=identity(4); } init(); // Erase the current picture, retaining any size specification. void erase() { nodes.delete(); nodes3.delete(); bounds.erase(); bounds3.erase(); T=identity(); scale=new ScaleT; legend.delete(); init(); } // Empty <<<2 bool empty2() { return nodes.length == 0; } bool empty3() { return nodes3.length == 0; } bool empty() { return empty2() && empty3(); } // User min/max <<<2 pair userMin2() {return bounds.userMin(); } pair userMax2() {return bounds.userMax(); } bool userSetx2() { return bounds.userBoundsAreSet(); } bool userSety2() { return bounds.userBoundsAreSet(); } triple userMin3() { return umin; } triple userMax3() { return umax; } bool userSetx3() { return usetx; } bool userSety3() { return usety; } bool userSetz3() { return usetz; } private typedef real binop(real, real); // Helper functions for finding the minimum/maximum of two data, one of // which may not be defined. private static real merge(real x1, bool set1, real x2, bool set2, binop m) { return set1 ? (set2 ? m(x1,x2) : x1) : x2; } private pairOrTriple userExtreme(pair u2(), triple u3(), binop m) { bool setx2 = userSetx2(); bool sety2 = userSety2(); bool setx3 = userSetx3(); bool sety3 = userSety3(); pair p; if (setx2 || sety2) p = u2(); triple t = u3(); pairOrTriple r; r.x = merge(p.x, setx2, t.x, setx3, m); r.y = merge(p.y, sety2, t.y, sety3, m); r.z = t.z; return r; } // The combination of 2D and 3D data. pairOrTriple userMin() { return userExtreme(userMin2, userMin3, min); } pairOrTriple userMax() { return userExtreme(userMax2, userMax3, max); } bool userSetx() { return userSetx2() || userSetx3(); } bool userSety() { return userSety2() || userSety3(); } bool userSetz() = userSetz3; // Functions for setting the user bounds. void userMinx3(real x) { umin.x=x; usetx=true; } void userMiny3(real y) { umin.y=y; usety=true; } void userMinz3(real z) { umin.z=z; usetz=true; } void userMaxx3(real x) { umax.x=x; usetx=true; } void userMaxy3(real y) { umax.y=y; usety=true; } void userMaxz3(real z) { umax.z=z; usetz=true; } void userMinx2(real x) { bounds.alterUserBound("minx", x); } void userMinx(real x) { userMinx2(x); userMinx3(x); } void userMiny2(real y) { bounds.alterUserBound("miny", y); } void userMiny(real y) { userMiny2(y); userMiny3(y); } void userMaxx2(real x) { bounds.alterUserBound("maxx", x); } void userMaxx(real x) { userMaxx2(x); userMaxx3(x); } void userMaxy2(real y) { bounds.alterUserBound("maxy", y); } void userMaxy(real y) { userMaxy2(y); userMaxy3(y); } void userMinz(real z) = userMinz3; void userMaxz(real z) = userMaxz3; void userCorners3(triple c000, triple c001, triple c010, triple c011, triple c100, triple c101, triple c110, triple c111) { umin.x = min(c000.x,c001.x,c010.x,c011.x,c100.x,c101.x,c110.x,c111.x); umin.y = min(c000.y,c001.y,c010.y,c011.y,c100.y,c101.y,c110.y,c111.y); umin.z = min(c000.z,c001.z,c010.z,c011.z,c100.z,c101.z,c110.z,c111.z); umax.x = max(c000.x,c001.x,c010.x,c011.x,c100.x,c101.x,c110.x,c111.x); umax.y = max(c000.y,c001.y,c010.y,c011.y,c100.y,c101.y,c110.y,c111.y); umax.z = max(c000.z,c001.z,c010.z,c011.z,c100.z,c101.z,c110.z,c111.z); } // Cache the current user-space bounding box x coodinates void userBoxX3(real min, real max, binop m=min, binop M=max) { if (usetx) { umin.x=m(umin.x,min); umax.x=M(umax.x,max); } else { umin.x=min; umax.x=max; usetx=true; } } // Cache the current user-space bounding box y coodinates void userBoxY3(real min, real max, binop m=min, binop M=max) { if (usety) { umin.y=m(umin.y,min); umax.y=M(umax.y,max); } else { umin.y=min; umax.y=max; usety=true; } } // Cache the current user-space bounding box z coodinates void userBoxZ3(real min, real max, binop m=min, binop M=max) { if (usetz) { umin.z=m(umin.z,min); umax.z=M(umax.z,max); } else { umin.z=min; umax.z=max; usetz=true; } } // Cache the current user-space bounding box void userBox3(triple min, triple max) { userBoxX3(min.x,max.x); userBoxY3(min.y,max.y); userBoxZ3(min.z,max.z); } // Add drawer <<<2 void add(drawerBound d, bool exact=false, bool above=true) { uptodate=false; if(!exact) bounds.exact=false; if(above) nodes.push(d); else nodes.insert(0,d); } // Faster implementation of most common case. void addExactAbove(drawerBound d) { uptodate=false; nodes.push(d); } void add(drawer d, bool exact=false, bool above=true) { add(new void(frame f, transform t, transform T, pair, pair) { d(f,t*T); },exact,above); } void add(drawerBound3 d, bool exact=false, bool above=true) { uptodate=false; if(!exact) bounds.exact=false; if(above) nodes3.push(d); else nodes3.insert(0,d); } void add(drawer3 d, bool exact=false, bool above=true) { add(new void(frame f, transform3 t, transform3 T, picture pic, projection P, triple, triple) { d(f,t*T,pic,P); },exact,above); } // Clip <<<2 void clip(pair min, pair max, drawer d, bool exact=false) { bounds.clip(min, max); this.add(d,exact); } void clip(pair min, pair max, drawerBound d, bool exact=false) { bounds.clip(min, max); this.add(d,exact); } // Add sizing <<<2 // Add a point to the sizing. void addPoint(pair user, pair truesize=0) { bounds.addPoint(user,truesize); //userBox(user,user); } // Add a point to the sizing, accounting also for the size of the pen. void addPoint(pair user, pair truesize=0, pen p) { addPoint(user,truesize+min(p)); addPoint(user,truesize+max(p)); } void addPoint(triple user, triple truesize=(0,0,0)) { bounds3.point.push(user,truesize); userBox3(user,user); } void addPoint(triple user, triple truesize=(0,0,0), pen p) { addPoint(user,truesize+min3(p)); addPoint(user,truesize+max3(p)); } // Add a box to the sizing. void addBox(pair userMin, pair userMax, pair trueMin=0, pair trueMax=0) { bounds.addBox(userMin, userMax, trueMin, trueMax); } void addBox(triple userMin, triple userMax, triple trueMin=(0,0,0), triple trueMax=(0,0,0)) { bounds3.min.push(userMin,trueMin); bounds3.max.push(userMax,trueMax); userBox3(userMin,userMax); } // For speed reason, we unravel the addPath routines from bounds. This // avoids an extra function call. from bounds unravel addPath; // Size commands <<<2 void size(real x, real y=x, bool keepAspect=this.keepAspect) { if(!empty()) uptodate=false; xsize=x; ysize=y; this.keepAspect=keepAspect; } void size3(real x, real y=x, real z=y, bool keepAspect=this.keepAspect) { if(!empty3()) uptodate=false; xsize3=x; ysize3=y; zsize3=z; this.keepAspect=keepAspect; } void unitsize(real x, real y=x, real z=y) { uptodate=false; xunitsize=x; yunitsize=y; zunitsize=z; } // min/max of picture <<<2 // Calculate the min for the final frame, given the coordinate transform. pair min(transform t) { return bounds.min(t); } // Calculate the max for the final frame, given the coordinate transform. pair max(transform t) { return bounds.max(t); } // Calculate the min for the final frame, given the coordinate transform. triple min(transform3 t) { if(bounds3.min.x.length == 0 && bounds3.point.x.length == 0 && bounds3.max.x.length == 0) return (0,0,0); triple a=t*(1,1,1)-t*(0,0,0), b=t*(0,0,0); scaling xs=scaling.build(a.x,b.x); scaling ys=scaling.build(a.y,b.y); scaling zs=scaling.build(a.z,b.z); return (min(min(min(infinity,xs,bounds3.point.x),xs,bounds3.min.x), xs,bounds3.max.x), min(min(min(infinity,ys,bounds3.point.y),ys,bounds3.min.y), ys,bounds3.max.y), min(min(min(infinity,zs,bounds3.point.z),zs,bounds3.min.z), zs,bounds3.max.z)); } // Calculate the max for the final frame, given the coordinate transform. triple max(transform3 t) { if(bounds3.min.x.length == 0 && bounds3.point.x.length == 0 && bounds3.max.x.length == 0) return (0,0,0); triple a=t*(1,1,1)-t*(0,0,0), b=t*(0,0,0); scaling xs=scaling.build(a.x,b.x); scaling ys=scaling.build(a.y,b.y); scaling zs=scaling.build(a.z,b.z); return (max(max(max(-infinity,xs,bounds3.point.x),xs,bounds3.min.x), xs,bounds3.max.x), max(max(max(-infinity,ys,bounds3.point.y),ys,bounds3.min.y), ys,bounds3.max.y), max(max(max(-infinity,zs,bounds3.point.z),zs,bounds3.min.z), zs,bounds3.max.z)); } void append(coords3 point, coords3 min, coords3 max, transform3 t, bounds3 bounds) { // Add the coord info to this picture. if(t == identity4) { point.append(bounds.point); min.append(bounds.min); max.append(bounds.max); } else { point.push(t,bounds.point,bounds.point,bounds.point); // Add in all 8 corner points, to properly size cuboid pictures. point.push(t,bounds.min,bounds.min,bounds.min); point.push(t,bounds.min,bounds.min,bounds.max); point.push(t,bounds.min,bounds.max,bounds.min); point.push(t,bounds.min,bounds.max,bounds.max); point.push(t,bounds.max,bounds.min,bounds.min); point.push(t,bounds.max,bounds.min,bounds.max); point.push(t,bounds.max,bounds.max,bounds.min); point.push(t,bounds.max,bounds.max,bounds.max); } } // Scaling and Fit <<<2 // Returns the transform for turning user-space pairs into true-space pairs. transform scaling(real xsize, real ysize, bool keepAspect=true, bool warn=true) { bounds b = (T == identity()) ? this.bounds : T * this.bounds; return b.scaling(xsize, ysize, xunitsize, yunitsize, keepAspect, warn); } transform scaling(bool warn=true) { return scaling(xsize,ysize,keepAspect,warn); } // Returns the transform for turning user-space pairs into true-space triples. transform3 scaling(real xsize, real ysize, real zsize, bool keepAspect=true, bool warn=true) { if(xsize == 0 && xunitsize == 0 && ysize == 0 && yunitsize == 0 && zsize == 0 && zunitsize == 0) return identity(4); coords3 Coords; append(Coords,Coords,Coords,T3,bounds3); real sx; if(xunitsize == 0) { if(xsize != 0) sx=calculateScaling("x",Coords.x,xsize,warn); } else sx=xunitsize; real sy; if(yunitsize == 0) { if(ysize != 0) sy=calculateScaling("y",Coords.y,ysize,warn); } else sy=yunitsize; real sz; if(zunitsize == 0) { if(zsize != 0) sz=calculateScaling("z",Coords.z,zsize,warn); } else sz=zunitsize; if(sx == 0) { sx=max(sy,sz); if(sx == 0) return identity(4); } if(sy == 0) sy=max(sz,sx); if(sz == 0) sz=max(sx,sy); if(keepAspect && (xunitsize == 0 || yunitsize == 0 || zunitsize == 0)) return scale3(min(sx,sy,sz)); else return scale(sx,sy,sz); } transform3 scaling3(bool warn=true) { return scaling(xsize3,ysize3,zsize3,keepAspect,warn); } frame fit(transform t, transform T0=T, pair m, pair M) { frame f; int n = nodes.length; for(int i=0; i < n; ++i) nodes[i](f,t,T0,m,M); return f; } frame fit3(transform3 t, transform3 T0=T3, picture pic, projection P, triple m, triple M) { frame f; for(int i=0; i < nodes3.length; ++i) nodes3[i](f,t,T0,pic,P,m,M); return f; } // Returns a rigid version of the picture using t to transform user coords // into truesize coords. frame fit(transform t) { return fit(t,min(t),max(t)); } frame fit3(transform3 t, picture pic, projection P) { return fit3(t,pic,P,min(t),max(t)); } // Add drawer wrappers <<<2 void add(void d(picture, transform), bool exact=false) { add(new void(frame f, transform t) { picture opic=new picture; d(opic,t); add(f,opic.fit(identity())); },exact); } void add(void d(picture, transform3), bool exact=false, bool above=true) { add(new void(frame f, transform3 t, picture pic2, projection P) { picture opic=new picture; d(opic,t); add(f,opic.fit3(identity4,pic2,P)); },exact,above); } void add(void d(picture, transform3, transform3, triple, triple), bool exact=false, bool above=true) { add(new void(frame f, transform3 t, transform3 T, picture pic2, projection P, triple lb, triple rt) { picture opic=new picture; d(opic,t,T,lb,rt); add(f,opic.fit3(identity4,pic2,P)); },exact,above); } // More scaling <<<2 frame scaled() { frame f=fit(fixedscaling); pair d=size(f); static real epsilon=100*realEpsilon; if(d.x > xsize*(1+epsilon)) warning("xlimit","frame exceeds xlimit: "+(string) d.x+" > "+ (string) xsize); if(d.y > ysize*(1+epsilon)) warning("ylimit","frame exceeds ylimit: "+(string) d.y+" > "+ (string) ysize); return f; } // Calculate additional scaling required if only an approximate picture // size estimate is available. transform scale(frame f, real xsize=this.xsize, real ysize=this.ysize, bool keepaspect=this.keepAspect) { if(bounds.exact) return identity(); pair m=min(f); pair M=max(f); real width=M.x-m.x; real height=M.y-m.y; real xgrow=xsize == 0 || width == 0 ? 1 : xsize/width; real ygrow=ysize == 0 || height == 0 ? 1 : ysize/height; if(keepAspect) { real[] grow; if(xsize > 0) grow.push(xgrow); if(ysize > 0) grow.push(ygrow); return scale(grow.length == 0 ? 1 : min(grow)); } else return scale(xgrow,ygrow); } // Calculate additional scaling required if only an approximate picture // size estimate is available. transform3 scale3(frame f, real xsize3=this.xsize3, real ysize3=this.ysize3, real zsize3=this.zsize3, bool keepaspect=this.keepAspect) { if(bounds3.exact) return identity(4); triple m=min3(f); triple M=max3(f); real width=M.x-m.x; real height=M.y-m.y; real depth=M.z-m.z; real xgrow=xsize3 == 0 || width == 0 ? 1 : xsize3/width; real ygrow=ysize3 == 0 || height == 0 ? 1 : ysize3/height; real zgrow=zsize3 == 0 || depth == 0 ? 1 : zsize3/depth; if(keepAspect) { real[] grow; if(xsize3 > 0) grow.push(xgrow); if(ysize3 > 0) grow.push(ygrow); if(zsize3 > 0) grow.push(zgrow); return scale3(grow.length == 0 ? 1 : min(grow)); } else return scale(xgrow,ygrow,zgrow); } // calculateTransform with scaling <<<2 // Return the transform that would be used to fit the picture to a frame transform calculateTransform(real xsize, real ysize, bool keepAspect=true, bool warn=true) { transform t=scaling(xsize,ysize,keepAspect,warn); return scale(fit(t),xsize,ysize,keepAspect)*t; } transform calculateTransform(bool warn=true) { if(fixed) return fixedscaling; return calculateTransform(xsize,ysize,keepAspect,warn); } transform3 calculateTransform3(real xsize=xsize3, real ysize=ysize3, real zsize=zsize3, bool keepAspect=true, bool warn=true, projection P=currentprojection) { transform3 t=scaling(xsize,ysize,zsize,keepAspect,warn); return scale3(fit3(t,null,P),keepAspect)*t; } // min/max with xsize and ysize <<<2 // NOTE: These are probably very slow as implemented. pair min(real xsize=this.xsize, real ysize=this.ysize, bool keepAspect=this.keepAspect, bool warn=true) { return min(calculateTransform(xsize,ysize,keepAspect,warn)); } pair max(real xsize=this.xsize, real ysize=this.ysize, bool keepAspect=this.keepAspect, bool warn=true) { return max(calculateTransform(xsize,ysize,keepAspect,warn)); } triple min3(real xsize=this.xsize3, real ysize=this.ysize3, real zsize=this.zsize3, bool keepAspect=this.keepAspect, bool warn=true, projection P) { return min(calculateTransform3(xsize,ysize,zsize,keepAspect,warn,P)); } triple max3(real xsize=this.xsize3, real ysize=this.ysize3, real zsize=this.zsize3, bool keepAspect=this.keepAspect, bool warn=true, projection P) { return max(calculateTransform3(xsize,ysize,zsize,keepAspect,warn,P)); } // More Fitting <<<2 // Returns the 2D picture fit to the requested size. frame fit2(real xsize=this.xsize, real ysize=this.ysize, bool keepAspect=this.keepAspect) { if(fixed) return scaled(); if(empty2()) return newframe; transform t=scaling(xsize,ysize,keepAspect); frame f=fit(t); transform s=scale(f,xsize,ysize,keepAspect); if(s == identity()) return f; return fit(s*t); } static frame fitter(string,picture,string,real,real,bool,bool,string,string, light,projection); frame fit(string prefix="", string format="", real xsize=this.xsize, real ysize=this.ysize, bool keepAspect=this.keepAspect, bool view=false, string options="", string script="", light light=currentlight, projection P=currentprojection) { return fitter == null ? fit2(xsize,ysize,keepAspect) : fitter(prefix,this,format,xsize,ysize,keepAspect,view,options,script, light,P); } // Fit a 3D picture. frame fit3(projection P=currentprojection) { if(settings.render == 0) return fit(P); if(fixed) return scaled(); if(empty3()) return newframe; transform3 t=scaling(xsize3,ysize3,zsize3,keepAspect); frame f=fit3(t,null,P); transform3 s=scale3(f,xsize3,ysize3,zsize3,keepAspect); if(s == identity4) return f; return fit3(s*t,null,P); } // In case only an approximate picture size estimate is available, return the // fitted frame slightly scaled (including labels and true size distances) // so that it precisely meets the given size specification. frame scale(real xsize=this.xsize, real ysize=this.ysize, bool keepAspect=this.keepAspect) { frame f=fit(xsize,ysize,keepAspect); transform s=scale(f,xsize,ysize,keepAspect); if(s == identity()) return f; return s*f; } // Copying <<<2 // Copies enough information to yield the same userMin/userMax. void userCopy2(picture pic) { userMinx2(pic.userMin2().x); userMiny2(pic.userMin2().y); userMaxx2(pic.userMax2().x); userMaxy2(pic.userMax2().y); } void userCopy3(picture pic) { copyPairOrTriple(umin, pic.umin); copyPairOrTriple(umax, pic.umax); usetx=pic.usetx; usety=pic.usety; usetz=pic.usetz; } void userCopy(picture pic) { userCopy2(pic); userCopy3(pic); } // Copies the drawing information, but not the sizing information into a new // picture. Fitting this picture will not scale as the original picture would. picture drawcopy() { picture dest=new picture; dest.nodes = copy(nodes); dest.nodes3=copy(nodes3); dest.T=T; dest.T3=T3; // TODO: User bounds are sizing info, which probably shouldn't be part of // a draw copy. Should we move this down to copy()? dest.userCopy3(this); dest.scale=scale.copy(); dest.legend=copy(legend); return dest; } // A deep copy of this picture. Modifying the copied picture will not affect // the original. picture copy() { picture dest=drawcopy(); dest.uptodate=uptodate; dest.bounds=bounds.copy(); dest.bounds3=bounds3.copy(); dest.xsize=xsize; dest.ysize=ysize; dest.xsize3=xsize; dest.ysize3=ysize3; dest.zsize3=zsize3; dest.keepAspect=keepAspect; dest.xunitsize=xunitsize; dest.yunitsize=yunitsize; dest.zunitsize=zunitsize; dest.fixed=fixed; dest.fixedscaling=fixedscaling; return dest; } // Helper function for defining transformed pictures. Do not call it // directly. picture transformed(transform t) { picture dest=drawcopy(); // Replace nodes with a single drawer that realizes the transform. drawerBound[] oldnodes = dest.nodes; void drawAll(frame f, transform tt, transform T, pair lb, pair rt) { transform Tt = T*t; for (var node : oldnodes) node(f, tt, Tt, lb, rt); } dest.nodes = new drawerBound[] { drawAll }; dest.uptodate=uptodate; dest.bounds=bounds.transformed(t); dest.bounds3=bounds3.copy(); dest.bounds.exact=false; dest.xsize=xsize; dest.ysize=ysize; dest.xsize3=xsize; dest.ysize3=ysize3; dest.zsize3=zsize3; dest.keepAspect=keepAspect; dest.xunitsize=xunitsize; dest.yunitsize=yunitsize; dest.zunitsize=zunitsize; dest.fixed=fixed; dest.fixedscaling=fixedscaling; return dest; } // Add Picture <<<2 // Add a picture to this picture, such that the user coordinates will be // scaled identically when fitted void add(picture src, bool group=true, filltype filltype=NoFill, bool above=true) { // Copy the picture. Only the drawing function closures are needed, so we // only copy them. This needs to be a deep copy, as src could later have // objects added to it that should not be included in this picture. if(src == this) abort("cannot add picture to itself"); uptodate=false; picture srcCopy=src.drawcopy(); // Draw by drawing the copied picture. if(srcCopy.nodes.length > 0) nodes.push(new void(frame f, transform t, transform T, pair m, pair M) { add(f,srcCopy.fit(t,T*srcCopy.T,m,M),group,filltype,above); }); if(srcCopy.nodes3.length > 0) { nodes3.push(new void(frame f, transform3 t, transform3 T3, picture pic, projection P, triple m, triple M) { add(f,srcCopy.fit3(t,T3*srcCopy.T3,pic,P,m,M),group,above); }); } legend.append(src.legend); if(src.usetx) userBoxX3(src.umin.x,src.umax.x); if(src.usety) userBoxY3(src.umin.y,src.umax.y); if(src.usetz) userBoxZ3(src.umin.z,src.umax.z); bounds.append(srcCopy.T, src.bounds); //append(bounds.point,bounds.min,bounds.max,srcCopy.T,src.bounds); append(bounds3.point,bounds3.min,bounds3.max,srcCopy.T3,src.bounds3); //if(!src.bounds.exact) bounds.exact=false; if(!src.bounds3.exact) bounds3.exact=false; } } // Post Struct <<<1 picture operator * (transform t, picture orig) { return orig.transformed(t); } picture operator * (transform3 t, picture orig) { picture pic=orig.copy(); pic.T3=t*pic.T3; triple umin=pic.userMin3(), umax=pic.userMax3(); pic.userCorners3(t*umin, t*(umin.x,umin.y,umax.z), t*(umin.x,umax.y,umin.z), t*(umin.x,umax.y,umax.z), t*(umax.x,umin.y,umin.z), t*(umax.x,umin.y,umax.z), t*(umax.x,umax.y,umin.z), t*umax); pic.bounds3.exact=false; return pic; } picture currentpicture; void size(picture pic=currentpicture, real x, real y=x, bool keepAspect=pic.keepAspect) { pic.size(x,y,keepAspect); } void size3(picture pic=currentpicture, real x, real y=x, real z=y, bool keepAspect=pic.keepAspect) { pic.size3(x,y,z,keepAspect); } void unitsize(picture pic=currentpicture, real x, real y=x, real z=y) { pic.unitsize(x,y,z); } void size(picture pic=currentpicture, real xsize, real ysize, pair min, pair max) { pair size=max-min; pic.unitsize(size.x != 0 ? xsize/size.x : 0, size.y != 0 ? ysize/size.y : 0); } void size(picture dest, picture src) { dest.size(src.xsize,src.ysize,src.keepAspect); dest.size3(src.xsize3,src.ysize3,src.zsize3,src.keepAspect); dest.unitsize(src.xunitsize,src.yunitsize,src.zunitsize); } pair min(picture pic, bool user=false) { transform t=pic.calculateTransform(); pair z=pic.min(t); return user ? inverse(t)*z : z; } pair max(picture pic, bool user=false) { transform t=pic.calculateTransform(); pair z=pic.max(t); return user ? inverse(t)*z : z; } pair size(picture pic, bool user=false) { transform t=pic.calculateTransform(); pair M=pic.max(t); pair m=pic.min(t); if(!user) return M-m; t=inverse(t); return t*M-t*m; } // Frame Alignment <<< pair rectify(pair dir) { real scale=max(abs(dir.x),abs(dir.y)); if(scale != 0) dir *= 0.5/scale; dir += (0.5,0.5); return dir; } pair point(frame f, pair dir) { pair m=min(f); pair M=max(f); return m+realmult(rectify(dir),M-m); } path[] align(path[] g, transform t=identity(), pair position, pair align, pen p=currentpen) { if(g.length == 0) return g; pair m=min(g); pair M=max(g); pair dir=rectify(inverse(t)*-align); if(basealign(p) == 1) dir -= (0,m.y/(M.y-m.y)); pair a=m+realmult(dir,M-m); return shift(position+align*labelmargin(p))*t*shift(-a)*g; } // Returns a transform for aligning frame f in the direction align transform shift(frame f, pair align) { return shift(align-point(f,-align)); } // Returns a copy of frame f aligned in the direction align frame align(frame f, pair align) { return shift(f,align)*f; } // >>> pair point(picture pic=currentpicture, pair dir, bool user=true) { pair umin = pic.userMin2(); pair umax = pic.userMax2(); pair z=umin+realmult(rectify(dir),umax-umin); return user ? z : pic.calculateTransform()*z; } pair truepoint(picture pic=currentpicture, pair dir, bool user=true) { transform t=pic.calculateTransform(); pair m=pic.min(t); pair M=pic.max(t); pair z=m+realmult(rectify(dir),M-m); return user ? inverse(t)*z : z; } // Transform coordinate in [0,1]x[0,1] to current user coordinates. pair relative(picture pic=currentpicture, pair z) { return pic.userMin2()+realmult(z,pic.userMax2()-pic.userMin2()); } void add(picture pic=currentpicture, drawer d, bool exact=false) { pic.add(d,exact); } typedef void drawer3(frame f, transform3 t, picture pic, projection P); void add(picture pic=currentpicture, drawer3 d, bool exact=false) { pic.add(d,exact); } void add(picture pic=currentpicture, void d(picture,transform), bool exact=false) { pic.add(d,exact); } void add(picture pic=currentpicture, void d(picture,transform3), bool exact=false) { pic.add(d,exact); } void begingroup(picture pic=currentpicture) { pic.add(new void(frame f, transform) { begingroup(f); },true); } void endgroup(picture pic=currentpicture) { pic.add(new void(frame f, transform) { endgroup(f); },true); } void Draw(picture pic=currentpicture, path g, pen p=currentpen) { pic.add(new void(frame f, transform t) { draw(f,t*g,p); },true); pic.addPath(g,p); } // Default arguments have been removed to increase speed. void _draw(picture pic, path g, pen p, margin margin) { if (size(nib(p)) == 0 && margin==NoMargin) { // Inline the drawerBound wrapper for speed. pic.addExactAbove(new void(frame f, transform t, transform T, pair, pair) { _draw(f,t*T*g,p); }); } else { pic.add(new void(frame f, transform t) { draw(f,margin(t*g,p).g,p); },true); } pic.addPath(g,p); } void Draw(picture pic=currentpicture, explicit path[] g, pen p=currentpen) { // Could optimize this by adding one drawer. for(int i=0; i < g.length; ++i) Draw(pic,g[i],p); } void fill(picture pic=currentpicture, path[] g, pen p=currentpen, bool copy=true) { if(copy) g=copy(g); pic.add(new void(frame f, transform t) { fill(f,t*g,p,false); },true); pic.addPath(g); } void latticeshade(picture pic=currentpicture, path[] g, bool stroke=false, pen fillrule=currentpen, pen[][] p, bool copy=true) { if(copy) { g=copy(g); p=copy(p); } pic.add(new void(frame f, transform t) { latticeshade(f,t*g,stroke,fillrule,p,t,false); },true); pic.addPath(g); } void axialshade(picture pic=currentpicture, path[] g, bool stroke=false, pen pena, pair a, bool extenda=true, pen penb, pair b, bool extendb=true, bool copy=true) { if(copy) g=copy(g); pic.add(new void(frame f, transform t) { axialshade(f,t*g,stroke,pena,t*a,extenda,penb,t*b,extendb,false); },true); pic.addPath(g); } void radialshade(picture pic=currentpicture, path[] g, bool stroke=false, pen pena, pair a, real ra, bool extenda=true, pen penb, pair b, real rb, bool extendb=true, bool copy=true) { if(copy) g=copy(g); pic.add(new void(frame f, transform t) { pair A=t*a, B=t*b; real RA=abs(t*(a+ra)-A); real RB=abs(t*(b+rb)-B); radialshade(f,t*g,stroke,pena,A,RA,extenda,penb,B,RB,extendb,false); },true); pic.addPath(g); } void gouraudshade(picture pic=currentpicture, path[] g, bool stroke=false, pen fillrule=currentpen, pen[] p, pair[] z, int[] edges, bool copy=true) { if(copy) { g=copy(g); p=copy(p); z=copy(z); edges=copy(edges); } pic.add(new void(frame f, transform t) { gouraudshade(f,t*g,stroke,fillrule,p,t*z,edges,false); },true); pic.addPath(g); } void gouraudshade(picture pic=currentpicture, path[] g, bool stroke=false, pen fillrule=currentpen, pen[] p, int[] edges, bool copy=true) { if(copy) { g=copy(g); p=copy(p); edges=copy(edges); } pic.add(new void(frame f, transform t) { gouraudshade(f,t*g,stroke,fillrule,p,edges,false); },true); pic.addPath(g); } void tensorshade(picture pic=currentpicture, path[] g, bool stroke=false, pen fillrule=currentpen, pen[][] p, path[] b=g, pair[][] z=new pair[][], bool copy=true) { if(copy) { g=copy(g); p=copy(p); b=copy(b); z=copy(z); } pic.add(new void(frame f, transform t) { pair[][] Z=new pair[z.length][]; for(int i=0; i < z.length; ++i) Z[i]=t*z[i]; tensorshade(f,t*g,stroke,fillrule,p,t*b,Z,false); },true); pic.addPath(g); } void tensorshade(frame f, path[] g, bool stroke=false, pen fillrule=currentpen, pen[] p, path b=g.length > 0 ? g[0] : nullpath) { tensorshade(f,g,stroke,fillrule,new pen[][] {p},b); } void tensorshade(frame f, path[] g, bool stroke=false, pen fillrule=currentpen, pen[] p, path b=g.length > 0 ? g[0] : nullpath, pair[] z) { tensorshade(f,g,stroke,fillrule,new pen[][] {p},b,new pair[][] {z}); } void tensorshade(picture pic=currentpicture, path[] g, bool stroke=false, pen fillrule=currentpen, pen[] p, path b=g.length > 0 ? g[0] : nullpath) { tensorshade(pic,g,stroke,fillrule,new pen[][] {p},b); } void tensorshade(picture pic=currentpicture, path[] g, bool stroke=false, pen fillrule=currentpen, pen[] p, path b=g.length > 0 ? g[0] : nullpath, pair[] z) { tensorshade(pic,g,stroke,fillrule,new pen[][] {p},b,new pair[][] {z}); } // Smoothly shade the regions between consecutive paths of a sequence using a // given array of pens: void draw(picture pic=currentpicture, path[] g, pen fillrule=currentpen, pen[] p) { path[] G; pen[][] P; string differentlengths="arrays have different lengths"; if(g.length != p.length) abort(differentlengths); for(int i=0; i < g.length-1; ++i) { path g0=g[i]; path g1=g[i+1]; if(length(g0) != length(g1)) abort(differentlengths); for(int j=0; j < length(g0); ++j) { G.push(subpath(g0,j,j+1)--reverse(subpath(g1,j,j+1))--cycle); P.push(new pen[] {p[i],p[i],p[i+1],p[i+1]}); } } tensorshade(pic,G,fillrule,P); } void functionshade(picture pic=currentpicture, path[] g, bool stroke=false, pen fillrule=currentpen, string shader, bool copy=true) { if(copy) g=copy(g); pic.add(new void(frame f, transform t) { functionshade(f,t*g,stroke,fillrule,shader); },true); pic.addPath(g); } void filldraw(picture pic=currentpicture, path[] g, pen fillpen=currentpen, pen drawpen=currentpen) { begingroup(pic); fill(pic,g,fillpen); Draw(pic,g,drawpen); endgroup(pic); } void clip(picture pic=currentpicture, path[] g, bool stroke=false, pen fillrule=currentpen, bool copy=true) { if(copy) g=copy(g); //pic.userClip(min(g),max(g)); pic.clip(min(g), max(g), new void(frame f, transform t) { clip(f,t*g,stroke,fillrule,false); }, true); } void beginclip(picture pic=currentpicture, path[] g, bool stroke=false, pen fillrule=currentpen, bool copy=true) { if(copy) g=copy(g); pic.clipmin.push(min(g)); pic.clipmax.push(max(g)); pic.add(new void(frame f, transform t) { beginclip(f,t*g,stroke,fillrule,false); },true); } void endclip(picture pic=currentpicture) { pair min,max; if (pic.clipmin.length > 0 && pic.clipmax.length > 0) { min = pic.clipmin.pop(); max = pic.clipmax.pop(); } else { // We should probably abort here, since the PostScript output will be // garbage. warning("endclip", "endclip without beginclip"); min = pic.userMin2(); max = pic.userMax2(); } pic.clip(min, max, new void(frame f, transform) { endclip(f); }, true); } void unfill(picture pic=currentpicture, path[] g, bool copy=true) { if(copy) g=copy(g); pic.add(new void(frame f, transform t) { unfill(f,t*g,false); },true); } void filloutside(picture pic=currentpicture, path[] g, pen p=currentpen, bool copy=true) { if(copy) g=copy(g); pic.add(new void(frame f, transform t) { filloutside(f,t*g,p,false); },true); pic.addPath(g); } // Use a fixed scaling to map user coordinates in box(min,max) to the // desired picture size. transform fixedscaling(picture pic=currentpicture, pair min, pair max, pen p=nullpen, bool warn=false) { Draw(pic,min,p+invisible); Draw(pic,max,p+invisible); pic.fixed=true; return pic.fixedscaling=pic.calculateTransform(pic.xsize,pic.ysize, pic.keepAspect); } // Add frame src to frame dest about position with optional grouping. void add(frame dest, frame src, pair position, bool group=false, filltype filltype=NoFill, bool above=true) { add(dest,shift(position)*src,group,filltype,above); } // Add frame src to picture dest about position with optional grouping. void add(picture dest=currentpicture, frame src, pair position=0, bool group=true, filltype filltype=NoFill, bool above=true) { if(is3D(src)) { dest.add(new void(frame f, transform3, picture, projection) { add(f,src); // always add about 3D origin (ignore position) },true); dest.addBox((0,0,0),(0,0,0),min3(src),max3(src)); } else { dest.add(new void(frame f, transform t) { add(f,shift(t*position)*src,group,filltype,above); },true); dest.addBox(position,position,min(src),max(src)); } } // Like add(picture,frame,pair) but extend picture to accommodate frame. void attach(picture dest=currentpicture, frame src, pair position=0, bool group=true, filltype filltype=NoFill, bool above=true) { transform t=dest.calculateTransform(); add(dest,src,position,group,filltype,above); pair s=size(dest.fit(t)); size(dest,dest.xsize != 0 ? s.x : 0,dest.ysize != 0 ? s.y : 0); } // Like add(picture,frame,pair) but align frame in direction align. void add(picture dest=currentpicture, frame src, pair position, pair align, bool group=true, filltype filltype=NoFill, bool above=true) { add(dest,align(src,align),position,group,filltype,above); } // Like add(frame,frame,pair) but align frame in direction align. void add(frame dest, frame src, pair position, pair align, bool group=true, filltype filltype=NoFill, bool above=true) { add(dest,align(src,align),position,group,filltype,above); } // Like add(picture,frame,pair,pair) but extend picture to accommodate frame; void attach(picture dest=currentpicture, frame src, pair position, pair align, bool group=true, filltype filltype=NoFill, bool above=true) { attach(dest,align(src,align),position,group,filltype,above); } // Add a picture to another such that user coordinates in both will be scaled // identically in the shipout. void add(picture dest, picture src, bool group=true, filltype filltype=NoFill, bool above=true) { dest.add(src,group,filltype,above); } void add(picture src, bool group=true, filltype filltype=NoFill, bool above=true) { currentpicture.add(src,group,filltype,above); } // Fit the picture src using the identity transformation (so user // coordinates and truesize coordinates agree) and add it about the point // position to picture dest. void add(picture dest, picture src, pair position, bool group=true, filltype filltype=NoFill, bool above=true) { add(dest,src.fit(identity()),position,group,filltype,above); } void add(picture src, pair position, bool group=true, filltype filltype=NoFill, bool above=true) { add(currentpicture,src,position,group,filltype,above); } // Fill a region about the user-coordinate 'origin'. void fill(pair origin, picture pic=currentpicture, path[] g, pen p=currentpen) { picture opic; fill(opic,g,p); add(pic,opic,origin); } void postscript(picture pic=currentpicture, string s) { pic.add(new void(frame f, transform) { postscript(f,s); },true); } void postscript(picture pic=currentpicture, string s, pair min, pair max) { pic.add(new void(frame f, transform t) { postscript(f,s,t*min,t*max); },true); } void tex(picture pic=currentpicture, string s) { // Force TeX string s to be evaluated immediately (in case it is a macro). frame g; tex(g,s); size(g); pic.add(new void(frame f, transform) { tex(f,s); },true); } void tex(picture pic=currentpicture, string s, pair min, pair max) { frame g; tex(g,s); size(g); pic.add(new void(frame f, transform t) { tex(f,s,t*min,t*max); },true); } void layer(picture pic=currentpicture) { pic.add(new void(frame f, transform) { layer(f); },true); } void erase(picture pic=currentpicture) { pic.uptodate=false; pic.erase(); } void begin(picture pic=currentpicture, string name, string id="", bool visible=true) { if(!latex() || !pdf()) return; settings.twice=true; if(id == "") id=string(++ocgindex); tex(pic,"\begin{ocg}{"+name+"}{"+id+"}{"+(visible ? "1" : "0")+"}"); layer(pic); } void end(picture pic=currentpicture) { if(!latex() || !pdf()) return; tex(pic,"\end{ocg}"); layer(pic); } // For users of the LaTeX babel package. void deactivatequote(picture pic=currentpicture) { tex(pic,"\catcode`\"=12"); } void activatequote(picture pic=currentpicture) { tex(pic,"\catcode`\"=13"); } asymptote-2.37/base/plain_prethree.asy000066400000000000000000000153061265434602500201370ustar00rootroot00000000000000// Critical definitions for transform3 needed by projection and picture. pair viewportmargin=(0.1,0.1); // Horizontal and vertical 3D viewport margins. typedef real[][] transform3; restricted transform3 identity4=identity(4); // A uniform 3D scaling. transform3 scale3(real s) { transform3 t=identity(4); t[0][0]=t[1][1]=t[2][2]=s; return t; } // Simultaneous 3D scalings in the x, y, and z directions. transform3 scale(real x, real y, real z) { transform3 t=identity(4); t[0][0]=x; t[1][1]=y; t[2][2]=z; return t; } transform3 shiftless(transform3 t) { transform3 T=copy(t); T[0][3]=T[1][3]=T[2][3]=0; return T; } real camerafactor=2; // Factor used for camera adjustment. struct transformation { transform3 modelview; // For orientation and positioning transform3 projection; // For 3D to 2D projection bool infinity; void operator init(transform3 modelview) { this.modelview=modelview; this.projection=identity4; infinity=true; } void operator init(transform3 modelview, transform3 projection) { this.modelview=modelview; this.projection=projection; infinity=false; } transform3 compute() { return infinity ? modelview : projection*modelview; } transformation copy() { transformation T=new transformation; T.modelview=copy(modelview); T.projection=copy(projection); T.infinity=infinity; return T; } } struct projection { transform3 t; // projection*modelview (cached) bool infinity; bool absolute=false; triple camera; // Position of camera. triple up; // A vector that should be projected to direction (0,1). triple target; // Point where camera is looking at. triple normal; // Normal vector from target to projection plane. pair viewportshift; // Fractional viewport shift. real zoom=1; // Zoom factor. real angle; // Lens angle (for perspective projection). bool showtarget=true; // Expand bounding volume to include target? typedef transformation projector(triple camera, triple up, triple target); projector projector; bool autoadjust=true; // Adjust camera to lie outside bounding volume? bool center=false; // Center target within bounding volume? int ninterpolate; // Used for projecting nurbs to 2D Bezier curves. bool bboxonly=true; // Typeset label bounding box only. transformation T; void calculate() { T=projector(camera,up,target); t=T.compute(); infinity=T.infinity; ninterpolate=infinity ? 1 : 16; } triple vector() { return camera-target; } void operator init(triple camera, triple up=(0,0,1), triple target=(0,0,0), triple normal=camera-target, real zoom=1, real angle=0, pair viewportshift=0, bool showtarget=true, bool autoadjust=true, bool center=false, projector projector) { this.camera=camera; this.up=up; this.target=target; this.normal=normal; this.zoom=zoom; this.angle=angle; this.viewportshift=viewportshift; this.showtarget=showtarget; this.autoadjust=autoadjust; this.center=center; this.projector=projector; calculate(); } projection copy() { projection P=new projection; P.t=t; P.infinity=infinity; P.absolute=absolute; P.camera=camera; P.up=up; P.target=target; P.normal=normal; P.zoom=zoom; P.angle=angle; P.viewportshift=viewportshift; P.showtarget=showtarget; P.autoadjust=autoadjust; P.center=center; P.projector=projector; P.ninterpolate=ninterpolate; P.bboxonly=bboxonly; P.T=T.copy(); return P; } // Return the maximum distance of box(m,M) from target. real distance(triple m, triple M) { triple[] c={m,(m.x,m.y,M.z),(m.x,M.y,m.z),(m.x,M.y,M.z), (M.x,m.y,m.z),(M.x,m.y,M.z),(M.x,M.y,m.z),M}; return max(abs(c-target)); } // This is redefined here to make projection as self-contained as possible. static private real sqrtEpsilon = sqrt(realEpsilon); // Move the camera so that the box(m,M) rotated about target will always // lie in front of the clipping plane. bool adjust(triple m, triple M) { triple v=camera-target; real d=distance(m,M); static real lambda=camerafactor*(1-sqrtEpsilon); if(lambda*d >= abs(v)) { camera=target+camerafactor*d*unit(v); calculate(); return true; } return false; } } projection currentprojection; struct light { real[][] diffuse; real[][] ambient; real[][] specular; pen background=nullpen; // Background color of the 3D canvas. real specularfactor; bool viewport; // Are the lights specified (and fixed) in the viewport frame? triple[] position; // Only directional lights are currently implemented. transform3 T=identity(4); // Transform to apply to normal vectors. bool on() {return position.length > 0;} void operator init(pen[] diffuse, pen[] ambient=array(diffuse.length,black), pen[] specular=diffuse, pen background=nullpen, real specularfactor=1, bool viewport=false, triple[] position) { int n=diffuse.length; assert(ambient.length == n && specular.length == n && position.length == n); this.diffuse=new real[n][]; this.ambient=new real[n][]; this.specular=new real[n][]; this.background=background; this.position=new triple[n]; for(int i=0; i < position.length; ++i) { this.diffuse[i]=rgba(diffuse[i]); this.ambient[i]=rgba(ambient[i]); this.specular[i]=rgba(specular[i]); this.position[i]=unit(position[i]); } this.specularfactor=specularfactor; this.viewport=viewport; } void operator init(pen diffuse=white, pen ambient=black, pen specular=diffuse, pen background=nullpen, real specularfactor=1, bool viewport=false...triple[] position) { int n=position.length; operator init(array(n,diffuse),array(n,ambient),array(n,specular), background,specularfactor,viewport,position); } void operator init(pen diffuse=white, pen ambient=black, pen specular=diffuse, pen background=nullpen, bool viewport=false, real x, real y, real z) { operator init(diffuse,ambient,specular,background,viewport,(x,y,z)); } void operator init(explicit light light) { diffuse=copy(light.diffuse); ambient=copy(light.ambient); specular=copy(light.specular); background=light.background; specularfactor=light.specularfactor; viewport=light.viewport; position=copy(light.position); } real[] background() {return rgba(background == nullpen ? white : background);} } light currentlight; asymptote-2.37/base/plain_scaling.asy000066400000000000000000000126021265434602500177350ustar00rootroot00000000000000real expansionfactor=sqrt(2); // A coordinate in "flex space." A linear combination of user and true-size // coordinates. struct coord { real user,truesize; // Build a coord. static coord build(real user, real truesize) { coord c=new coord; c.user=user; c.truesize=truesize; return c; } // Deep copy of coordinate. Users may add coords to the picture, but then // modify the struct. To prevent this from yielding unexpected results, deep // copying is used. coord copy() { return build(user, truesize); } void clip(real min, real max) { user=min(max(user,min),max); truesize=0; } } bool operator <= (coord a, coord b) { return a.user <= b.user && a.truesize <= b.truesize; } bool operator >= (coord a, coord b) { return a.user >= b.user && a.truesize >= b.truesize; } // Find the maximal elements of the input array, using the partial ordering // given. coord[] maxcoords(coord[] in, bool operator <= (coord,coord)) { // As operator <= is defined in the parameter list, it has a special // meaning in the body of the function. coord best; coord[] c; int n=in.length; if(n == 0) return c; int first=0; // Add the first coord without checking restrictions (as there are none). best=in[first]; c.push(best); static int NONE=-1; int dominator(coord x) { // This assumes it has already been checked against the best. for(int i=1; i < c.length; ++i) if(x <= c[i]) return i; return NONE; } void promote(int i) { // Swap with the top coord x=c[i]; c[i]=best; best=c[0]=x; } void addmaximal(coord x) { coord[] newc; // Check if it beats any others. for(int i=0; i < c.length; ++i) { coord y=c[i]; if(!(y <= x)) newc.push(y); } newc.push(x); c=newc; best=c[0]; } void add(coord x) { if(x <= best) return; else { int i=dominator(x); if(i == NONE) addmaximal(x); else promote(i); } } for(int i=1; i < n; ++i) add(in[i]); return c; } struct coords2 { coord[] x,y; void erase() { x.delete(); y.delete(); } // Only a shallow copy of the individual elements of x and y // is needed since, once entered, they are never modified. coords2 copy() { coords2 c=new coords2; c.x=copy(x); c.y=copy(y); return c; } void append(coords2 c) { x.append(c.x); y.append(c.y); } void push(pair user, pair truesize) { x.push(coord.build(user.x,truesize.x)); y.push(coord.build(user.y,truesize.y)); } void push(coord cx, coord cy) { x.push(cx); y.push(cy); } void push(transform t, coords2 c1, coords2 c2) { for(int i=0; i < c1.x.length; ++i) { coord cx=c1.x[i], cy=c2.y[i]; pair tinf=shiftless(t)*(0,0); pair z=t*(cx.user,cy.user); pair w=(cx.truesize,cy.truesize); w=length(w)*unit(shiftless(t)*w); coord Cx,Cy; Cx.user=z.x; Cy.user=z.y; Cx.truesize=w.x; Cy.truesize=w.y; push(Cx,Cy); } } void xclip(real min, real max) { for(int i=0; i < x.length; ++i) x[i].clip(min,max); } void yclip(real min, real max) { for(int i=0; i < y.length; ++i) y[i].clip(min,max); } } // The scaling in one dimension: x --> a*x + b struct scaling { real a,b; static scaling build(real a, real b) { scaling s=new scaling; s.a=a; s.b=b; return s; } real scale(real x) { return a*x+b; } real scale(coord c) { return scale(c.user) + c.truesize; } } // Calculate the minimum point in scaling the coords. real min(real m, scaling s, coord[] c) { for(int i=0; i < c.length; ++i) if(s.scale(c[i]) < m) m=s.scale(c[i]); return m; } // Calculate the maximum point in scaling the coords. real max(real M, scaling s, coord[] c) { for(int i=0; i < c.length; ++i) if(s.scale(c[i]) > M) M=s.scale(c[i]); return M; } // Calculate the sizing constants for the given array and maximum size. real calculateScaling(string dir, coord[] m, coord[] M, real size, bool warn=true) { access simplex; simplex.problem p=new simplex.problem; void addMinCoord(coord c) { // (a*user + b) + truesize >= 0: p.addRestriction(c.user,1,c.truesize); } void addMaxCoord(coord c) { // (a*user + b) + truesize <= size: p.addRestriction(-c.user,-1,size-c.truesize); } for (int i=0; i < m.length; ++i) addMinCoord(m[i]); for (int i=0; i < M.length; ++i) addMaxCoord(M[i]); int status=p.optimize(); if(status == simplex.problem.OPTIMAL) { // TODO: Could just be return a; return scaling.build(p.a(),p.b()).a; } else if(status == simplex.problem.UNBOUNDED) { if(warn) warning("unbounded",dir+" scaling in picture unbounded"); return 0; } else { if(!warn) return 1; bool userzero(coord[] coords) { for(var coord : coords) if(coord.user != 0) return false; return true; } if((userzero(m) && userzero(M)) || size >= infinity) return 1; warning("cannotfit","cannot fit picture to "+dir+"size "+(string) size +"...enlarging..."); return calculateScaling(dir,m,M,expansionfactor*size,warn); } } real calculateScaling(string dir, coord[] coords, real size, bool warn=true) { coord[] m=maxcoords(coords,operator >=); coord[] M=maxcoords(coords,operator <=); return calculateScaling(dir, m, M, size, warn); } asymptote-2.37/base/plain_shipout.asy000066400000000000000000000065451265434602500200210ustar00rootroot00000000000000// Default file prefix used for inline LaTeX mode string defaultfilename; string[] file3; string outprefix(string prefix=defaultfilename) { return stripextension(prefix != "" ? prefix : outname()); } string outformat(string format="") { if(format == "") format=settings.outformat; if(format == "") format=nativeformat(); return format; } bool shipped; // Was a picture or frame already shipped out? frame currentpatterns; frame Portrait(frame f) {return f;}; frame Landscape(frame f) {return rotate(90)*f;}; frame UpsideDown(frame f) {return rotate(180)*f;}; frame Seascape(frame f) {return rotate(-90)*f;}; typedef frame orientation(frame); orientation orientation=Portrait; // Forward references to functions defined in module three. object embed3(string, frame, string, string, string, light, projection); string Embed(string name, string text="", string options="", real width=0, real height=0); bool prconly(string format="") { return outformat(format) == "prc"; } bool prc0(string format="") { return settings.prc && (outformat(format) == "pdf" || prconly() || settings.inlineimage ); } bool prc(string format="") { return prc0(format) && Embed != null; } bool is3D(string format="") { return prc(format) || settings.render != 0; } frame enclose(string prefix=defaultfilename, object F, string format="") { if(prc(format)) { frame f; label(f,F.L); return f; } return F.f; } include plain_xasy; void shipout(string prefix=defaultfilename, frame f, string format="", bool wait=false, bool view=true, string options="", string script="", light light=currentlight, projection P=currentprojection) { if(is3D(f)) { f=enclose(prefix,embed3(prefix,f,format,options,script,light,P)); if(settings.render != 0 && !prc(format)) { shipped=true; return; } } if(inXasyMode) { erase(); add(f,group=false); return; } // Applications like LaTeX cannot handle large PostScript coordinates. pair m=min(f); int limit=2000; if(abs(m.x) > limit || abs(m.y) > limit) f=shift(-m)*f; shipout(prefix,f,currentpatterns,format,wait,view, xformStack.empty() ? null : xformStack.pop0); shipped=true; } void shipout(string prefix=defaultfilename, picture pic=currentpicture, orientation orientation=orientation, string format="", bool wait=false, bool view=true, string options="", string script="", light light=currentlight, projection P=currentprojection) { if(!uptodate()) { bool inlinetex=settings.inlinetex; bool prc=prc(format); bool empty3=pic.empty3(); if(prc && !empty3) { if(settings.render == 0) { string image=outprefix(prefix)+"+"+(string) file3.length; if(settings.inlineimage) image += "_0"; settings.inlinetex=false; settings.prc=false; shipout(image,pic,orientation,nativeformat(),view=false,light,P); settings.prc=true; } settings.inlinetex=settings.inlineimage; } frame f=pic.fit(prefix,format,view=view,options,script,light,P); if(!prconly() && (!pic.empty2() || settings.render == 0 || prc || empty3)) shipout(prefix,orientation(f),format,wait,view); settings.inlinetex=inlinetex; } pic.uptodate=true; shipped=true; } void newpage(picture pic=currentpicture) { pic.add(new void(frame f, transform) { newpage(f); },true); } asymptote-2.37/base/plain_strings.asy000066400000000000000000000126371265434602500200160ustar00rootroot00000000000000string defaultformat(int n, string trailingzero="", bool fixed=false, bool signed=true) { return "$%"+trailingzero+"."+string(n)+(fixed ? "f" : "g")+"$"; } string defaultformat=defaultformat(4); string defaultseparator="\!\times\!"; string ask(string prompt) { write(stdout,prompt); return stdin; } string getstring(string name="", string default="", string prompt="", bool store=true) { string[] history=history(name,1); if(history.length > 0) default=history[0]; if(prompt == "") prompt=name+"? [%s] "; prompt=replace(prompt,new string[][] {{"%s",default}}); string s=readline(prompt,name); if(s == "") s=default; else saveline(name,s,store); return s; } int getint(string name="", int default=0, string prompt="", bool store=true) { return (int) getstring(name,(string) default,prompt,store); } real getreal(string name="", real default=0, string prompt="", bool store=true) { return (real) getstring(name,(string) default,prompt,store); } pair getpair(string name="", pair default=0, string prompt="", bool store=true) { return (pair) getstring(name,(string) default,prompt,store); } triple gettriple(string name="", triple default=(0,0,0), string prompt="", bool store=true) { return (triple) getstring(name,(string) default,prompt,store); } // returns a string with all occurrences of string 'before' in string 's' // changed to string 'after'. string replace(string s, string before, string after) { return replace(s,new string[][] {{before,after}}); } // Like texify but don't convert embedded TeX commands: \${} string TeXify(string s) { static string[][] t={{"&","\&"},{"%","\%"},{"_","\_"},{"#","\#"},{"<","$<$"}, {">","$>$"},{"|","$|$"},{"^","$\hat{\ }$"}, {"~","$\tilde{\ }$"},{" ","\phantom{ }"}}; return replace(s,t); } private string[][] trans1={{'\\',"\backslash "}, {"$","\$"},{"{","\{"},{"}","\}"}}; private string[][] trans2={{"\backslash ","$\backslash$"}}; // Convert string to TeX string texify(string s) { return TeXify(replace(replace(s,trans1),trans2)); } // Convert string to TeX, preserving newlines string verbatim(string s) { bool space=substr(s,0,1) == '\n'; static string[][] t={{'\n',"\\"}}; t.append(trans1); s=TeXify(replace(replace(s,t),trans2)); return space ? "\ "+s : s; } // Split a string into an array of substrings delimited by delimiter // If delimiter is an empty string, use space delimiter but discard empty // substrings. string[] split(string s, string delimiter="") { bool prune=false; if(delimiter == "") { prune=true; delimiter=" "; } string[] S; int last=0; int i; int N=length(delimiter); int n=length(s); while((i=find(s,delimiter,last)) >= 0) { if(i > last || (i == last && !prune)) S.push(substr(s,last,i-last)); last=i+N; } if(n > last || (n == last && !prune)) S.push(substr(s,last,n-last)); return S; } int system(string s) { return system(split(s)); } int[] operator ecast(string[] a) { return sequence(new int(int i) {return (int) a[i];},a.length); } real[] operator ecast(string[] a) { return sequence(new real(int i) {return (real) a[i];},a.length); } // Read contents of file as a string. string file(string s) { file f=input(s); string s; while(!eof(f)) { s += f+'\n'; } return s; } string italic(string s) { return s != "" ? "{\it "+s+"}" : s; } string baseline(string s, string template="\strut") { return s != "" && settings.tex != "none" ? "\vphantom{"+template+"}"+s : s; } string math(string s) { return s != "" ? "$"+s+"$" : s; } private void notimplemented(string text) { abort(text+" is not implemented for the '"+settings.tex+"' TeX engine"); } string jobname(string name) { int pos=rfind(name,"-"); return pos >= 0 ? "\ASYprefix\jobname"+substr(name,pos) : name; } string graphic(string name, string options="") { if(latex()) { if(options != "") options="["+options+"]"; bool pdf=pdf(); string includegraphics="\includegraphics"+options; if(settings.inlinetex) return includegraphics+"{"+jobname(name)+"}"; else return includegraphics+ (find(name," ") < 0 ? "{"+name+"}" : (pdf ? "{\""+stripextension(name)+"\".pdf}" : "{\""+name+"\"}")); } if(settings.tex != "context") notimplemented("graphic"); return "\externalfigure["+name+"]["+options+"]"; } string graphicscale(real x) { return string(settings.tex == "context" ? 1000*x : x); } string minipage(string s, real width=100bp) { if(latex()) return "\begin{minipage}{"+(string) (width/pt)+"pt}"+s+"\end{minipage}"; if(settings.tex != "context") notimplemented("minipage"); return "\startframedtext[none][frame=off,width="+(string) (width/pt)+ "pt]"+s+"\stopframedtext"; } void usepackage(string s, string options="") { if(!latex()) notimplemented("usepackage"); string usepackage="\usepackage"; if(options != "") usepackage += "["+options+"]"; texpreamble(usepackage+"{"+s+"}"); } void pause(string w="Hit enter to continue") { write(w); w=stdin; } string math(real x) { return math((string) x); } string format(string format, real x, string locale="") { return format(format,defaultseparator,x,locale); } string format(real x, string locale="") { return format(defaultformat,defaultseparator,x,locale); } string phantom(string s) { return settings.tex != "none" ? "\phantom{"+s+"}" : ""; } restricted int ocgindex=0; asymptote-2.37/base/plain_xasy.asy000066400000000000000000000050311265434602500172770ustar00rootroot00000000000000restricted bool inXasyMode=false; bool diagnostics=false; void report(string text) { if(diagnostics) write(text); } void report(transform t) { if(diagnostics) write(t); } void report(int i) { if(diagnostics) write(i); } void initXasyMode() { size(0,0); inXasyMode=true; } void exitXasyMode() { inXasyMode=false; } private picture[] tempStore; private picture newPic; void startScript() { tempStore.push(currentpicture.copy()); newPic=new picture; currentpicture=newPic; } void endScript() { if(tempStore.length < 1) { abort("endScript() without matching beginScript()"); } else { currentpicture=tempStore.pop(); add(currentpicture,newPic.fit(),group=false); } shipped=false; } struct indexedTransform { int index; transform t; bool active; void operator init(int index, transform t, bool active=true) { this.index=index; this.t=t; this.active=active; } } struct framedTransformStack { struct transact { transform t; bool active; void operator init(transform t, bool active=true) { this.t=t; this.active=active; } void operator init(indexedTransform i){ this.t=i.t; this.active=i.active; } void operator init() { this.t=identity(); this.active=true; } } private transact[] stack; private int[] frames; private int stackBase=0; transform pop() { if(stack.length == 0) return identity(); else { transform popped=stack[0].t; stack.delete(0); report("Popped"); report(popped); return popped; } } transform pop0() { if(stack.length == 0) return identity(); else { static transform zerotransform=(0,0,0,0,0,0); transform popped=stack[0].active ? stack[0].t : zerotransform; stack.delete(0); report("Popped"); report(popped); return popped; } } void push(transform t, bool Active=true) { report("Pushed"); report(t); stack.push(transact(t,Active)); } void add(... indexedTransform[] tList) { transact[] toPush; for(int a=0; a < tList.length; ++a) toPush[tList[a].index]=transact(tList[a]); for(int a=0; a < toPush.length; ++a) if(!toPush.initialized(a)) toPush[a]=transact(); report("Added"); report(toPush.length); stack.append(toPush); } bool empty() { return stack.length == 0; } } framedTransformStack xformStack; void deconstruct(picture pic=currentpicture, real magnification=1) { deconstruct(pic.fit(),currentpatterns,magnification,xformStack.pop); } asymptote-2.37/base/pstoedit.asy000066400000000000000000000005461265434602500167710ustar00rootroot00000000000000pen textpen=basealign; pair align=Align; // Compatibility routines for the pstoedit (version 3.43 or later) backend. void gsave(picture pic=currentpicture) { pic.add(new void (frame f, transform) { gsave(f); },true); } void grestore(picture pic=currentpicture) { pic.add(new void (frame f, transform) { grestore(f); },true); } asymptote-2.37/base/reload.js000066400000000000000000000012211265434602500162130ustar00rootroot00000000000000// Load/reload the document associated with a given path. // UNIX: Copy to ~/.adobe/Acrobat/x.x/JavaScripts/ // To avoid random window placement we recommend specifying an acroread // geometry option, for example: -geometry +0+0 // MSWindows: Copy to %APPDATA%/Adobe/Acrobat/x.x/JavaScripts/ // Note: x.x represents the appropriate Acrobat Reader version number. reload = app.trustedFunction(function(path) { app.beginPriv(); n=app.activeDocs.length; for(i=app.activeDocs.length-1; i >= 0; --i) { Doc=app.activeDocs[i]; if(Doc.path == path && Doc != this) { Doc.closeDoc(); break; } } app.openDoc(path); app.endPriv(); }); asymptote-2.37/base/roundedpath.asy000066400000000000000000000065461265434602500174610ustar00rootroot00000000000000// a function to round sharp edges of open and cyclic paths // written by stefan knorr path roundedpath(path A, real R, real S = 1) // create rounded path from path A with radius R and scale S = 1 { path RoundPath; // returned path path LocalPath; // local straight subpath path LocalCirc; // local edge circle for intersection real LocalTime; // local intersectiontime between . and .. pair LocalPair; // local point to be added to 'RoundPath' int len=length(A); // length of given path 'A' bool PathClosed=cyclic(A); // true, if given path 'A' is cyclic // initialisation: define first Point of 'RoundPath' as if (PathClosed) // ? is 'A' cyclic RoundPath=scale(S)*point(point(A,0)--point(A,1), 0.5); // centerpoint of first straight subpath of 'A' else RoundPath=scale(S)*point(A,0); // first point of 'A' // doing everything between start and end // create round paths subpath by subpath for every i-th edge for(int i=1; i < len; ++i) { // straight subpath towards i-th edge LocalPath=point(A,i-1)---point(A,i); // circle with radius 'R' around i-th edge LocalCirc=circle(point(A,i),R); // calculate intersection time between straight subpath and circle real[] t=intersect(LocalPath, LocalCirc); if(t.length > 0) { LocalTime=t[0]; // define intersectionpoint between both paths LocalPair=point(subpath(LocalPath, 0, LocalTime), 1); // add straight subpath towards i-th curvature to 'RoundPath' RoundPath=RoundPath--scale(S)*LocalPair; } // straight subpath from i-th edge to (i+1)-th edge LocalPath=point(A,i)---point(A,i+1); // calculate intersection-time between straight subpath and circle real[] t=intersect(LocalPath, LocalCirc); if(t.length > 0) { LocalTime=t[0]; // define intersectionpoint between both paths LocalPair=point(subpath(LocalPath, 0, LocalTime), 1); // add curvature near i-th edge to 'RoundPath' RoundPath=RoundPath..scale(S)*LocalPair; } } // final steps to have a correct termination if(PathClosed) { // Is 'A' cyclic? // straight subpath towards 0-th edge LocalPath=point(A,len-1)---point(A,0); // circle with radius 'R' around 0-th edge LocalCirc=circle(point(A,0),R); // calculate intersection-time between straight subpath and circle real[] t=intersect(LocalPath, LocalCirc); if(t.length > 0) { LocalTime=t[0]; // define intersectionpoint between both paths LocalPair=point(subpath(LocalPath, 0, LocalTime), 1); // add straight subpath towards 0-th curvature to 'RoundPath' RoundPath=RoundPath--scale(S)*LocalPair; } // straight subpath from 0-th edge to 1st edge LocalPath=point(A,0)---point(A,1); // calculate intersection-time between straight subpath and circle real[] t=intersect(LocalPath, LocalCirc); if(t.length > 0) { LocalTime=t[0]; // define intersectionpoint between both paths LocalPair=point(subpath(LocalPath, 0, LocalTime), 1); // add curvature near 0-th edge to 'RoundPath' and close path RoundPath=RoundPath..scale(S)*LocalPair--cycle; } } else RoundPath=RoundPath--scale(S)*point(A,len); return RoundPath; } asymptote-2.37/base/simplex.asy000066400000000000000000000153511265434602500166170ustar00rootroot00000000000000/***** * simplex.asy * Andy Hammerlindl 2004/07/27 * * Solves the two-variable linear programming problem using the simplex method. * This problem is specialized in that the second variable, "b", does not have * a non-negativity condition, and the first variable, "a", is the quantity * being maximized. * Correct execution of the algorithm also assumes that the coefficient of "b" * will be +1 or -1 in every added restriction, and that the problem can be * initialized to a valid state by pivoting b with one of the slack * variables. This assumption may in fact be incorrect. *****/ private real infinity=sqrt(0.25*realMax); struct problem { typedef int var; static var VAR_A = 0; static var VAR_B = 1; static int OPTIMAL = -1; static var UNBOUNDED = -2; static int INVALID = -3; struct row { real c, t[]; } // The variables of the rows. // Initialized for the two variable problem. var[] v = {VAR_A, VAR_B}; // The rows of equalities. row rowA() { row r = new row; r.c = 0; r.t = new real[] {1, 0}; return r; } row rowB() { row r = new row; r.c = 0; r.t = new real[] {0, 1}; return r; } row[] rows = {rowA(), rowB()}; // The number of original variables. int n = rows.length; // Pivot the variable v[col] with vp. void pivot(int col, var vp) { var vc=v[col]; // Recalculate rows v[col] and vp for the pivot-swap. row rvc = rows[vc], rvp = rows[vp]; real factor=1/rvp.t[col]; // NOTE: Handle rvp.t[col] == 0 case. rvc.c=-rvp.c*factor; rvp.c=0; rvc.t=-rvp.t*factor; rvp.t *= 0; rvc.t[col]=factor; rvp.t[col]=1; var a=min(vc,vp); var b=max(vc,vp); // Recalculate the rows other than the two used for the above pivot. for (var i = 0; i < a; ++i) { row r=rows[i]; real m = r.t[col]; r.c += m*rvc.c; r.t += m*rvc.t; r.t[col]=m*factor; } for (var i = a+1; i < b; ++i) { row r=rows[i]; real m = r.t[col]; r.c += m*rvc.c; r.t += m*rvc.t; r.t[col]=m*factor; } for (var i = b+1; i < rows.length; ++i) { row r=rows[i]; real m = r.t[col]; r.c += m*rvc.c; r.t += m*rvc.t; r.t[col]=m*factor; } // Relabel the vars. v[col] = vp; } // As b does not have a non-negativity condition, it must initially be // pivoted out for a variable that does. This selects the initial // variable to pivot with b. It also assumes that there is a valid // solution with a == 0 to the linear programming problem, and if so, it // picks a pivot to get to that state. In our case, a == 0 corresponds to // a picture with the user coordinates shrunk down to zero, and if that // doesn't fit, nothing will. var initVar() { real min=infinity, max=-infinity; var argmin=0, argmax=0; for (var i = 2; i < rows.length; ++i) { row r=rows[i]; if (r.t[VAR_B] > 0) { real val=r.c/r.t[VAR_B]; if (val < min) { min=val; argmin=i; } } else if (r.t[VAR_B] < 0) { real val=r.c/r.t[VAR_B]; if (val > max) { max=val; argmax=i; } } } // If b has a minimal value, choose a pivot that will give b its minimal // value. Otherwise, if b has maximal value, choose a pivot to give b its // maximal value. return argmin != 0 ? argmin : argmax != 0 ? argmax : UNBOUNDED; } // Initialize the linear program problem by moving into an acceptable state // this assumes that b is unrestrained and is the second variable. // NOTE: Works in limited cases, may be bug-ridden. void init() { // Find the lowest constant term in the equations. var lowest = 0; for (var i = 2; i < rows.length; ++i) { if (rows[i].c < rows[lowest].c) lowest = i; } // Pivot if necessary. if (lowest != 0) pivot(VAR_B, lowest); } // Selects a column to pivot on. Returns OPTIMAL if the current state is // optimal. Assumes we are optimizing the first row. int selectColumn() { int i=find(rows[0].t > 0,1); return (i >= 0) ? i : OPTIMAL; } // Select the new variable associated with a pivot on the column given. // Returns UNBOUNDED if the space is unbounded. var selectVar(int col) { // We assume that the first two vars (a and b) once swapped out, won't be // swapped back in. This finds the variable which gives the tightest // non-negativity condition restricting our optimization. This turns // out to be the max of c/t[col]. Note that as c is positive, and // t[col] is negative, all c/t[col] will be negative, so we are finding // the smallest in magnitude. var vp=UNBOUNDED; real max=-infinity; for (int i = 2; i < rows.length; ++i) { row r=rows[i]; if(r.c < max*r.t[col]) { max=r.c/r.t[col]; vp=i; } } return vp; } // Checks that the rows are in a valid state. bool valid() { // Checks that constants are valid. bool validConstants() { for (int i = 0; i < rows.length; ++i) // Do not test the row for b, as it does not have a non-negativity // condition. if (i != VAR_B && rows[i].c < 0) return false; return true; } // Check a variable to see if its row is simple. // NOTE: Simple rows could be optimized out, since they are not really // used. bool validVar(int col) { var vc = v[col]; row rvc = rows[vc]; if (rvc.c != 0) return false; for (int i = 0; i < n; ++i) if (rvc.t[i] != (i == col ? 1 : 0)) return false; return true; } if (!validConstants()) { return false; } for (int i = 0; i < n; ++i) if (!validVar(i)) { return false; } return true; } // Perform the algorithm to find the optimal solution. Returns OPTIMAL, // UNBOUNDED, or INVALID (if no solution is possible). int optimize() { // Put into a valid state to begin and pivot b out. var iv=initVar(); if (iv == UNBOUNDED) return iv; pivot(VAR_B, iv); if (!valid()) return INVALID; while(true) { int col = selectColumn(); if (col == OPTIMAL) return col; var vp = selectVar(col); if (vp == UNBOUNDED) return vp; pivot(col, vp); } // Shouldn't reach here. return INVALID; } // Add a restriction to the problem: // t1*a + t2*b + c >= 0 void addRestriction(real t1, real t2, real c) { row r = new row; r.c = c; r.t = new real[] {t1, t2}; rows.push(r); } // Return the value of a computed. real a() { return rows[VAR_A].c; } // Return the value of b computed. real b() { return rows[VAR_B].c; } } asymptote-2.37/base/size10.asy000066400000000000000000000011401265434602500162400ustar00rootroot00000000000000texpreamble("\makeatletter% \renewcommand\normalsize{\@setfontsize\normalsize\@xpt\@xiipt}% \renewcommand\small{\@setfontsize\small\@ixpt{11}}% \renewcommand\footnotesize{\@setfontsize\footnotesize\@viiipt{9.5}}% \renewcommand\scriptsize{\@setfontsize\scriptsize\@viipt\@viiipt}% \renewcommand\tiny{\@setfontsize\tiny\@vpt\@vipt}% \renewcommand\large{\@setfontsize\large\@xiipt{14}}% \renewcommand\Large{\@setfontsize\Large\@xivpt{18}}% \renewcommand\LARGE{\@setfontsize\LARGE\@xviipt{22}}% \renewcommand\huge{\@setfontsize\huge\@xxpt{25}}% \renewcommand\Huge{\@setfontsize\Huge\@xxvpt{30}}% \makeatother"); asymptote-2.37/base/size11.asy000066400000000000000000000011301265434602500162400ustar00rootroot00000000000000texpreamble("\makeatletter% \renewcommand\normalsize{\@setfontsize\normalsize\@xipt{13.6}}% \renewcommand\small{\@setfontsize\small\@xpt\@xiipt}% \renewcommand\footnotesize{\@setfontsize\footnotesize\@ixpt{11}}% \renewcommand\scriptsize{\@setfontsize\scriptsize\@viiipt{9.5}} \renewcommand\tiny{\@setfontsize\tiny\@vipt\@viipt} \renewcommand\large{\@setfontsize\large\@xiipt{14}} \renewcommand\Large{\@setfontsize\Large\@xivpt{18}} \renewcommand\LARGE{\@setfontsize\LARGE\@xviipt{22}} \renewcommand\huge{\@setfontsize\huge\@xxpt{25}} \renewcommand\Huge{\@setfontsize\Huge\@xxvpt{30}} \makeatother"); asymptote-2.37/base/slide.asy000066400000000000000000000371261265434602500162420ustar00rootroot00000000000000import fontsize; usepackage("asycolors"); bool reverse=false; // Set to true to enable reverse video. bool stepping=false; // Set to true to enable stepping. bool itemstep=true; // Set to false to disable stepping on each item. settings.toolbar=false; // Disable 3D toolbar by default. if(settings.render < 0) settings.render=4; bool allowstepping=false; // Allow stepping for current slide. real pagemargin=0.5cm; real pagewidth=-2pagemargin; real pageheight=-2pagemargin; bool landscape=orientation == Landscape || orientation == Seascape; if(landscape) { orientation=Portrait; pagewidth += settings.paperheight; pageheight += settings.paperwidth; } else { pagewidth += settings.paperwidth; pageheight += settings.paperheight; } size(pagewidth,pageheight,IgnoreAspect); picture background; real minipagemargin=1inch; real minipagewidth=pagewidth-2minipagemargin; transform tinv=inverse(fixedscaling((-1,-1),(1,1),currentpen)); pen itempen=fontsize(24pt); pen codepen=fontsize(20pt); pen titlepagepen=fontsize(36pt); pen authorpen=fontsize(24pt); pen institutionpen=authorpen; pen datepen=fontsize(18pt); pen urlpen=datepen; real itemskip=0.5; real codeskip=0.25; pair dateskip=(0,0.1); pair urlskip=(0,0.2); pair titlealign=3S; pen titlepen=fontsize(32pt); real titleskip=0.5; string oldbulletcolor; string newbulletcolor="red"; string bullet="{\bulletcolor\textbullet}"; pair pagenumberposition=S+E; pair pagenumberalign=4NW; pen pagenumberpen=fontsize(12); pen steppagenumberpen=colorless(pagenumberpen); real figureborder=0.25cm; pen figuremattpen; pen backgroundcolor; pen foregroundcolor; pair titlepageposition=(-0.8,0.4); pair startposition=(-0.8,0.9); pair currentposition=startposition; string bulletcolor(string color) { return "\def\bulletcolor{"+'\\'+"color{"+color+"}}%"; } int[] firstnode=new int[] {currentpicture.nodes.length}; int[] lastnode; bool firststep=true; int page=0; bool havepagenumber=true; int preamblenodes=2; bool empty() { return currentpicture.nodes.length <= preamblenodes; } void background() { if(!background.empty()) { add(background); layer(); preamblenodes += 2; } } void color(string name, string color) { texpreamble("\def"+'\\'+name+"#1{{\color{"+color+"}#1}}%"); } string texcolor(pen p) { real[] colors=colors(p); string s; if(colors.length > 0) { s="{"+colorspace(p)+"}{"; for(int i=0; i < colors.length-1; ++i) s += format("%.6f",colors[i],"C")+","; s += format("%.6f",colors[colors.length-1],"C")+"}"; } return s; } void setpens(pen red=red, pen blue=blue, pen steppen=red) { itempen=colorless(itempen); codepen=colorless(codepen); pagenumberpen=colorless(pagenumberpen); steppagenumberpen=colorless(steppagenumberpen)+steppen; titlepagepen=colorless(titlepagepen)+red; authorpen=colorless(authorpen)+blue; institutionpen=colorless(institutionpen)+blue; datepen=colorless(datepen); urlpen=colorless(urlpen); } void reversevideo() { backgroundcolor=black; foregroundcolor=white; fill(background,box((-1,-1),(1,1)),backgroundcolor); setpens(mediumred,paleblue,mediumblue); // Work around pdflatex bug, in which white is mapped to black! figuremattpen=pdf() ? cmyk(0,0,0,1/255) : white; color("Red","mediumred"); color("Green","green"); color("Blue","paleblue"); color("Foreground","white"); color("Background","black"); oldbulletcolor="white"; defaultpen(itempen+foregroundcolor); } void normalvideo() { backgroundcolor=invisible; foregroundcolor=black; background=new picture; size(background,currentpicture); setpens(); figuremattpen=invisible; color("Red","red"); color("Green","heavygreen"); color("Blue","blue"); color("Foreground","black"); color("Background","white"); oldbulletcolor="black"; defaultpen(itempen+foregroundcolor); } normalvideo(); texpreamble(bulletcolor(newbulletcolor)); texpreamble("\hyphenpenalty=10000\tolerance=1000"); // Evaluate user command line option. void usersetting() { plain.usersetting(); if(reverse) { // Black background reversevideo(); } else { // White background normalvideo(); } } void numberpage(pen p=pagenumberpen) { if(havepagenumber) { label((string) page,pagenumberposition,pagenumberalign,p); } } void nextpage(pen p=pagenumberpen) { if(!empty()) { numberpage(p); newpage(); } background(); firststep=true; } void newslide(bool stepping=true) { allowstepping=stepping; nextpage(); ++page; havepagenumber=true; currentposition=startposition; firstnode=new int[] {currentpicture.nodes.length}; lastnode.delete(); } bool checkposition() { if(abs(currentposition.x) > 1 || abs(currentposition.y) > 1) { newslide(); return false; } return true; } void erasestep(int erasenode) { if(!stepping || !allowstepping) return; if(!checkposition()) return; lastnode.push(erasenode); nextpage(steppagenumberpen); for(int i=0; i < firstnode.length; ++i) { for(int j=firstnode[i]; j <= lastnode[i]; ++j) { tex(bulletcolor(oldbulletcolor)); currentpicture.add(currentpicture.nodes[j]); } } firstnode.push(currentpicture.nodes.length-1); tex(bulletcolor(newbulletcolor)); } void step() { // Step without erasing anything. erasestep(currentpicture.nodes.length-1); } void incrementposition(pair z) { currentposition += z; } void title(string s, pair position=N, pair align=titlealign, pen p=titlepen, bool newslide=true) { if(newslide) newslide(); checkposition(); frame f; if(s != "") label(f,minipage("\center "+s,minipagewidth),(0,0),align,p); add(f,position,labelmargin(p)*align); currentposition=(currentposition.x,position.y+ (tinv*(min(f)-titleskip*I*lineskip(p)*pt)).y); } void outline(string s="Outline", pair position=N, pair align=titlealign, pen p=titlepen) { newslide(stepping=false); title(s,position,align,p,newslide=false); } void remark(bool center=false, string s, pair align=0, pen p=itempen, real indent=0, bool minipage=true, real skip=itemskip, filltype filltype=NoFill, bool step=false) { checkposition(); if(minipage) s=minipage(s,minipagewidth); pair offset; if(center) { if(align == 0) align=S; offset=(0,currentposition.y); } else { if(align == 0) align=SE; offset=currentposition; } frame f; label(f,s,(indent,0),align,p,filltype); pair m=tinv*min(f); pair M=tinv*min(f); if(abs(offset.x+M.x) > 1) warning("slidetoowide","slide too wide on page "+(string) page+':\n'+ (string) s); if(abs(offset.y+M.y) > 1) { void toohigh() { warning("slidetoohigh","slide too high on page "+(string) page+':\n'+ (string) s); } if(M.y-m.y < 2) { newslide(); offset=(offset.x,currentposition.y); if(offset.y+M.y > 1 || offset.y+m.y < -1) toohigh(); } else toohigh(); } if(step) { if(!firststep) step(); firststep=false; } add(f,offset); incrementposition((0,(tinv*(min(f)-skip*I*lineskip(p)*pt)).y)); } void center(string s, pen p=itempen) { remark("\center "+s,p); } void equation(string s, pen p=itempen) { remark(center=true,"\vbox{$$"+s+"$$}",p,minipage=false,skip=0); } void vbox(string s, pen p=itempen) { remark(center=true,"\vbox{"+s+"}",p,minipage=false,skip=0); } void equations(string s, pen p=itempen) { vbox("\begin{eqnarray*}"+s+"\end{eqnarray*}",p); } void skip(real n=1) { incrementposition((0,(tinv*(-n*itemskip*I*lineskip(itempen)*pt)).y)); } void display(frame[] f, real margin=0, pair align=S, pen p=itempen, pen figuremattpen=figuremattpen, bool final=true) { if(f.length == 0) return; real[] width=new real[f.length]; real sum; for(int i=0; i < f.length; ++i) { width[i]=size(f[i]).x; sum += width[i]; } if(sum > pagewidth) warning("toowide","slide too wide on page "+(string) page); else margin=(pagewidth-sum)/(f.length+1); real pos; frame F; for(int i=0; i < f.length; ++i) { real w=0.5*(margin+width[i]); pos += w; add(F,f[i],(pos,0),Fill(figureborder,figuremattpen)); pos += w; } add(F,(0,currentposition.y),align); if (final) { real a=0.5(unit(align).y-1); incrementposition( (0, (tinv*(a*(max(F)-min(F))-itemskip*I*lineskip(p)*pt)).y)); } } void display(frame f, real margin=0, pair align=S, pen p=itempen, pen figuremattpen=figuremattpen, bool final=true) { display(new frame[] {f},margin,align,p,figuremattpen, final); } void display(string[] s, real margin=0, string[] captions=new string[], string caption="", pair align=S, pen p=itempen, pen figuremattpen=figuremattpen, bool final=true) { frame[] f=new frame[s.length]; frame F; for(int i=0; i < s.length; ++i) { f[i]=newframe; label(f[i],s[i]); add(F,f[i],(0,0)); } real y=point(F,S).y; int stop=min(s.length,captions.length); for(int i=0; i < stop; ++i) { if(captions[i] != "") label(f[i],captions[i],point(f[i],S).x+I*y,S); } display(f,margin,align,p,figuremattpen, final); if(caption != "") center(caption,p); } void display(string s, string caption="", pair align=S, pen p=itempen, pen figuremattpen=figuremattpen, bool final=true) { display(new string[] {s},caption,align,p,figuremattpen, final); } void figure(string[] s, string options="", real margin=0, string[] captions=new string[], string caption="", pair align=S, pen p=itempen, pen figuremattpen=figuremattpen, bool final=true) { string[] S; for(int i=0; i < s.length; ++i) { S[i]=graphic(s[i],options); } display(S,margin,captions,caption,align,itempen,figuremattpen,final); } void figure(string s, string options="", string caption="", pair align=S, pen p=itempen, pen figuremattpen=figuremattpen, bool final=true) { figure(new string[] {s},options,caption,align,p,figuremattpen,final); } void multifigure(string[] slist, string options="", string caption="", pair align=S, pen p=itempen, pen figuremattpen=figuremattpen, bool step=itemstep) { if(step) { int lastnode=currentpicture.nodes.length-1; for (int i=0; i 0 || ysize > 0) ? currentpicture.fit(xsize,ysize) : currentpicture.fit(); currentpicture=currentpictureSave; display(f); } string cropcode(string s) { while(substr(s,0,1) == '\n') s=substr(s,1,length(s)); while(substr(s,length(s)-1,1) == '\n') s=substr(s,0,length(s)-1); return s; } void code(bool center=false, string s, pen p=codepen, real indent=0, real skip=codeskip, filltype filltype=NoFill) { remark(center,"{\tt "+verbatim(cropcode(s))+"}",p,indent,skip,filltype); } void filecode(bool center=false, string s, pen p=codepen, real indent=0, real skip=codeskip, filltype filltype=NoFill) { code(center,file(s),p,indent,skip,filltype); } void asyfigure(string s, string options="", string caption="", pair align=S, pen p=codepen, pen figuremattpen=figuremattpen, filltype filltype=NoFill, bool newslide=false) { string a=s+".asy"; asy(nativeformat(),s); s += "."+nativeformat(); if(newslide && !empty()) { newslide(); currentposition=(currentposition.x,0); align=0; } figure(s,options,caption,align,p,figuremattpen); } string asywrite(string s, string preamble="") { static int count=0; string name=outprefix()+"_slide"+(string) count; ++count; file temp=output(name+".asy"); write(temp,preamble); write(temp,s); close(temp); codefile.push(name); return name; } void asycode(bool center=false, string s, string options="", string caption="", string preamble="", pair align=S, pen p=codepen, pen figuremattpen=figuremattpen, real indent=0, real skip=codeskip, filltype filltype=NoFill, bool newslide=false) { code(center,s,p,indent,skip,filltype); asyfigure(asywrite(s,preamble),options,caption,align,p,figuremattpen,filltype, newslide); } void asyfilecode(bool center=false, string s, string options="", string caption="", pair align=S, pen p=codepen, pen figuremattpen=figuremattpen, real indent=0, real skip=codeskip, filltype filltype=NoFill, bool newslide=false) { filecode(center,s+".asy",p,indent,skip,filltype); asyfigure(s,options,caption,align,p,figuremattpen,filltype,newslide); } void item(string s, pen p=itempen, bool step=itemstep) { frame b; label(b,bullet,(0,0),p); real bulletwidth=max(b).x-min(b).x; remark(bullet+"\hangindent"+(string) (bulletwidth/pt)+"pt$\,$"+s,p, -bulletwidth,step=step); } void subitem(string s, pen p=itempen) { remark("\quad -- "+s,p); } void titlepage(string title, string author, string institution="", string date="", string url="", bool newslide=false) { newslide(); currentposition=titlepageposition; center(title,titlepagepen); center(author,authorpen); if(institution != "") center(institution,institutionpen); currentposition -= dateskip; if(date != "") center(date,datepen); currentposition -= urlskip; if(url != "") center("{\tt "+url+"}",urlpen); } // Resolve optional bibtex citations: void bibliographystyle(string name) { settings.twice=true; settings.keepaux=true; texpreamble("\bibliographystyle{"+name+"}"); } void bibliography(string name) { numberpage(); havepagenumber=false; string s=texcolor(backgroundcolor); if(s != "") tex("\definecolor{Background}"+s+"\pagecolor{Background}%"); label("",itempen); tex("\eject\def\refname{\fontsize{"+string(fontsize(titlepen))+"}{"+ string(lineskip(titlepen))+"}\selectfont References}%"); real hmargin,vmargin; if(pdf()) { hmargin=1; vmargin=0; } else { hmargin=1.5; vmargin=1; } string s; if(landscape) { s="{\centering\textheight="+string(pageheight-1inch)+"bp\textwidth="+ string(pagewidth-1.5inches)+"bp"+ "\vsize=\textheight\hsize=\textwidth\linewidth=\hsize"+ "\topmargin="+string(vmargin)+"in\oddsidemargin="+string(hmargin)+"in"; } else s="{\centering\textheight="+string(pageheight-0.5inches)+"bp\textwidth="+ string(pagewidth-0.5inches)+ "bp\hsize=\textwidth\linewidth=\textwidth\vsize=\textheight"+ "\topmargin=0.5in\oddsidemargin=1in"; s += "\evensidemargin=\oddsidemargin\bibliography{"+name+"}\eject}"; tex(s); } exitfcn currentexitfunction=atexit(); void exitfunction() { numberpage(); if(currentexitfunction != null) currentexitfunction(); if(!settings.keep) for(int i=0; i < codefile.length; ++i) { string name=codefile[i]; delete(name+"."+nativeformat()); delete(name+"_.aux"); delete(name+".asy"); } codefile=new string[]; } atexit(exitfunction); asymptote-2.37/base/slopefield.asy000066400000000000000000000040241265434602500172570ustar00rootroot00000000000000import graph_settings; real stepfraction=0.05; picture slopefield(real f(real,real), pair a, pair b, int nx=nmesh, int ny=nx, real tickfactor=0.5, pen p=currentpen, arrowbar arrow=None) { picture pic; real dx=(b.x-a.x)/nx; real dy=(b.y-a.y)/ny; real step=0.5*tickfactor*min(dx,dy); for(int i=0; i <= nx; ++i) { real x=a.x+i*dx; for(int j=0; j <= ny; ++j) { pair cp=(x,a.y+j*dy); real slope=f(cp.x,cp.y); real mp=step/sqrt(1+slope^2); draw(pic,(cp.x-mp,cp.y-mp*slope)--(cp.x+mp,cp.y+mp*slope),p,arrow); } } clip(pic,box(a,b)); return pic; } picture slopefield(real f(real), pair a, pair b, int nx=nmesh, int ny=nx, pen p=currentpen, arrowbar arrow=None) { return slopefield(new real(real x, real y) {return f(x);},a,b,nx,ny,p,arrow); } path curve(pair c, real f(real,real), pair a, pair b) { real step=stepfraction*(b.x-a.x); real halfstep=0.5*step; real sixthstep=step/6; path follow(real sign) { pair cp=c; guide g=cp; real dx,dy; real factor=1; do { real slope; pair S(pair z) { slope=f(z.x,z.y); return factor*sign/sqrt(1+slope^2)*(1,slope); } pair S3; pair advance() { pair S0=S(cp); pair S1=S(cp+halfstep*S0); pair S2=S(cp+halfstep*S1); S3=S(cp+step*S2); pair cp0=cp+sixthstep*(S0+2S1+2S2+S3); dx=min(cp0.x-a.x,b.x-cp0.x); dy=min(cp0.y-a.y,b.y-cp0.y); return cp0; } pair cp0=advance(); if(dx < 0) { factor=(step+dx)/step; cp0=advance(); g=g..{S3}cp0{S3}; break; } if(dy < 0) { factor=(step+dy)/step; cp0=advance(); g=g..{S3}cp0{S3}; break; } cp=cp0; g=g..{S3}cp{S3}; } while (dx > 0 && dy > 0); return g; } return reverse(follow(-1))&follow(1); } path curve(pair c, real f(real), pair a, pair b) { return curve(c,new real(real x, real y){return f(x);},a,b); } asymptote-2.37/base/smoothcontour3.asy000066400000000000000000001376261265434602500201560ustar00rootroot00000000000000// Copyright 2015 Charles Staats III // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // smoothcontour3 // An Asymptote module for drawing smooth implicitly defined surfaces // author: Charles Staats III // charles dot staats dot iii at gmail dot com import graph_settings; // for nmesh import three; import math; /***********************************************/ /******** CREATING BEZIER PATCHES **************/ /******** WITH SPECIFIED NORMALS **************/ /***********************************************/ // The weight given to minimizing the sum of squares of // the mixed partials at the corners of the bezier patch. // If this weight is zero, the result is undefined in // places and can be rather wild even where it is // defined. // The struct is used to as a namespace. struct pathwithnormals_settings { static real wildnessweight = 1e-3; } private from pathwithnormals_settings unravel wildnessweight; // The Bernstein basis polynomials of degree 3: real B03(real t) { return (1-t)^3; } real B13(real t) { return 3*t*(1-t)^2; } real B23(real t) { return 3*t^2*(1-t); } real B33(real t) { return t^3; } private typedef real function(real); function[] bernstein = new function[] {B03, B13, B23, B33}; // This function attempts to produce a Bezier patch // with the specified boundary path and normal directions. // For instance, the patch should be normal to // u0normals[0] at (0, 0.25), // normal to u0normals[1] at (0, 0.5), and // normal to u0normals[2] at (0, 0.75). // The actual normal (as computed by the patch.normal() function) // may be parallel to the specified normal, antiparallel, or // even zero. // // A small amount of deviation is allowed in order to stabilize // the algorithm (by keeping the mixed partials at the corners from // growing too large). // // Note that the specified normals are projected to be orthogonal to // the specified boundary path. However, the entries in the array // remain intact. patch patchwithnormals(path3 external, triple[] u0normals, triple[] u1normals, triple[] v0normals, triple[] v1normals) { assert(cyclic(external)); assert(length(external) == 4); assert(u0normals.length == 3); assert(u1normals.length == 3); assert(v0normals.length == 3); assert(v1normals.length == 3); triple[][] controlpoints = new triple[4][4]; controlpoints[0][0] = point(external,0); controlpoints[1][0] = postcontrol(external,0); controlpoints[2][0] = precontrol(external,1); controlpoints[3][0] = point(external,1); controlpoints[3][1] = postcontrol(external,1); controlpoints[3][2] = precontrol(external,2); controlpoints[3][3] = point(external,2); controlpoints[2][3] = postcontrol(external,2); controlpoints[1][3] = precontrol(external,3); controlpoints[0][3] = point(external,3); controlpoints[0][2] = postcontrol(external,3); controlpoints[0][1] = precontrol(external, 4); real[][] matrix = new real[24][12]; for (int i = 0; i < matrix.length; ++i) for (int j = 0; j < matrix[i].length; ++j) matrix[i][j] = 0; real[] rightvector = new real[24]; for (int i = 0; i < rightvector.length; ++i) rightvector[i] = 0; void addtocoeff(int i, int j, int count, triple coeffs) { if (1 <= i && i <= 2 && 1 <= j && j <= 2) { int position = 3 * (2 * (i-1) + (j-1)); matrix[count][position] += coeffs.x; matrix[count][position+1] += coeffs.y; matrix[count][position+2] += coeffs.z; } else { rightvector[count] -= dot(controlpoints[i][j], coeffs); } } void addtocoeff(int i, int j, int count, real coeff) { if (1 <= i && i <= 2 && 1 <= j && j <= 2) { int position = 3 * (2 * (i-1) + (j-1)); matrix[count][position] += coeff; matrix[count+1][position+1] += coeff; matrix[count+2][position+2] += coeff; } else { rightvector[count] -= controlpoints[i][j].x * coeff; rightvector[count+1] -= controlpoints[i][j].y * coeff; rightvector[count+2] -= controlpoints[i][j].z * coeff; } } int count = 0; void apply_u0(int j, real a, triple n) { real factor = 3 * bernstein[j](a); addtocoeff(0,j,count,-factor*n); addtocoeff(1,j,count,factor*n); } void apply_u0(real a, triple n) { triple tangent = dir(external, 4-a); n -= dot(n,tangent)*tangent; n = unit(n); for (int j = 0; j < 4; ++j) { apply_u0(j,a,n); } ++count; } apply_u0(0.25, u0normals[0]); apply_u0(0.5, u0normals[1]); apply_u0(0.75, u0normals[2]); void apply_u1(int j, real a, triple n) { real factor = 3 * bernstein[j](a); addtocoeff(3,j,count,factor*n); addtocoeff(2,j,count,-factor*n); } void apply_u1(real a, triple n) { triple tangent = dir(external, 1+a); n -= dot(n,tangent)*tangent; n = unit(n); for (int j = 0; j < 4; ++j) apply_u1(j,a,n); ++count; } apply_u1(0.25, u1normals[0]); apply_u1(0.5, u1normals[1]); apply_u1(0.75, u1normals[2]); void apply_v0(int i, real a, triple n) { real factor = 3 * bernstein[i](a); addtocoeff(i,0,count,-factor*n); addtocoeff(i,1,count,factor*n); } void apply_v0(real a, triple n) { triple tangent = dir(external, a); n -= dot(n,tangent) * tangent; n = unit(n); for (int i = 0; i < 4; ++i) apply_v0(i,a,n); ++count; } apply_v0(0.25, v0normals[0]); apply_v0(0.5, v0normals[1]); apply_v0(0.75, v0normals[2]); void apply_v1(int i, real a, triple n) { real factor = 3 * bernstein[i](a); addtocoeff(i,3,count,factor*n); addtocoeff(i,2,count,-factor*n); } void apply_v1(real a, triple n) { triple tangent = dir(external, 3-a); n -= dot(n,tangent)*tangent; n = unit(n); for (int i = 0; i < 4; ++i) apply_v1(i,a,n); ++count; } apply_v1(0.25, v1normals[0]); apply_v1(0.5, v1normals[1]); apply_v1(0.75, v1normals[2]); addtocoeff(0,0,count,9*wildnessweight); addtocoeff(1,1,count,9*wildnessweight); addtocoeff(0,1,count,-9*wildnessweight); addtocoeff(1,0,count,-9*wildnessweight); count+=3; addtocoeff(3,3,count,9*wildnessweight); addtocoeff(2,2,count,9*wildnessweight); addtocoeff(3,2,count,-9*wildnessweight); addtocoeff(2,3,count,-9*wildnessweight); count+=3; addtocoeff(0,3,count,9*wildnessweight); addtocoeff(1,2,count,9*wildnessweight); addtocoeff(1,3,count,-9*wildnessweight); addtocoeff(0,2,count,-9*wildnessweight); count += 3; addtocoeff(3,0,count,9*wildnessweight); addtocoeff(2,1,count,9*wildnessweight); addtocoeff(3,1,count,-9*wildnessweight); addtocoeff(2,0,count,-9*wildnessweight); count += 3; real[] solution = leastsquares(matrix, rightvector, warn=false); if (solution.length == 0) { // if the matrix was singular write("Warning: unable to solve matrix for specifying normals " + "on bezier patch. Using standard method."); return patch(external); } for (int i = 1; i <= 2; ++i) { for (int j = 1; j <= 2; ++j) { int position = 3 * (2 * (i-1) + (j-1)); controlpoints[i][j] = (solution[position], solution[position+1], solution[position+2]); } } return patch(controlpoints); } // A wrapper for the previous function when the normal direction // is given as a function of direction. The wrapper can also // accommodate cyclic boundary paths of between one and four // segments, although the results are best by far when there // are four segments. patch patchwithnormals(path3 external, triple normalat(triple)) { assert(cyclic(external)); assert(1 <= length(external) && length(external) <= 4); while (length(external) < 4) external = external -- cycle; triple[] u0normals = new triple[3]; triple[] u1normals = new triple[3]; triple[] v0normals = new triple[3]; triple[] v1normals = new triple[3]; for (int i = 1; i <= 3; ++i) { v0normals[i-1] = unit(normalat(point(external, i/4))); u1normals[i-1] = unit(normalat(point(external, 1 + i/4))); v1normals[i-1] = unit(normalat(point(external, 3 - i/4))); u0normals[i-1] = unit(normalat(point(external, 4 - i/4))); } return patchwithnormals(external, u0normals, u1normals, v0normals, v1normals); } /***********************************************/ /*********** ROOT-FINDER UTILITY ***************/ /***********************************************/ // Namespace struct rootfinder_settings { static real roottolerance = 1e-4; } // Find a root for the specified continuous (but not // necessarily differentiable) function. Whatever // value t is returned, it is guaranteed that either // t is within tolerance of a sign change, or // abs(f(t)) <= 0.1 tolerance. // An error is thrown if fa and fb are both positive // or both negative. // // In the current implementation, binary search is interleaved // with a modified version of linear interpolation. real findroot(real f(real), real a, real b, real tolerance = rootfinder_settings.roottolerance, real fa = f(a), real fb = f(b)) { if (fa == 0) return a; if (fb == 0) return b; real g(real); if (fa < 0) { assert(fb > 0); g = f; } else { assert(fb < 0); fa = -fa; fb = -fb; g = new real(real t) { return -f(t); }; } real t = a; real ft = fa; while (b - a > tolerance && abs(ft) > 0.1*tolerance) { t = a + (b - a) / 2; ft = g(t); if (ft == 0) return t; else if (ft > 0) { b = t; fb = ft; } else if (ft < 0) { a = t; fa = ft; } // linear interpolation t = a - (b - a) / (fb - fa) * fa; // If the interpolated value is close to one edge of // the interval, move it farther away from the edge in // an effort to catch the root in the middle. if (t - a < (b-a)/8) t = a + 2*(t-a); else if (b - t < (b-a)/8) t = b - 2*(b-t); assert(t >= a && t <= b); ft = g(t); if (ft == 0) return t; else if (ft > 0) { b = t; fb = ft; } else if (ft < 0) { a = t; fa = ft; } } return a - (b - a) / (fb - fa) * fa; } /***********************************************/ /********* DUAL CUBE GRAPH UTILITY *************/ /***********************************************/ // Suppose a plane intersects a (hollow) cube, and // does not intersect any vertices. Then its intersection // with cube forms a cycle. The goal of the code below // is to reconstruct the order of the cycle // given only an unordered list of which edges the plane // intersects. // // Basically, the question is this: If we know the points // in which a more-or-less planar surface intersects the // edges of cube, how do we connect those points? // // When I wrote the code, I was thinking in terms of the // dual graph of a cube, in which "vertices" are really // faces of the cube and "edges" connect those "vertices." // An enum for the different "vertices" (i.e. faces) // available. NULL_VERTEX is primarily intended as a // return value to indicate the absence of a desired // vertex. private int NULL_VERTEX = -1; private int XHIGH = 0; private int XLOW = 1; private int YHIGH = 2; private int YLOW = 3; private int ZHIGH = 4; private int ZLOW = 5; // An unordered set of nonnegative integers. // Since the intent is to use // only the six values from the enum above, no effort // was made to use scalable algorithms. struct intset { private bool[] ints = new bool[0]; private int size = 0; bool contains(int item) { assert(item >= 0); if (item >= ints.length) return false; return ints[item]; } // Returns true if the item was added (i.e., was // not already present). bool add(int item) { assert(item >= 0); while (item >= ints.length) ints.push(false); if (ints[item]) return false; ints[item] = true; ++size; return true; } int[] elements() { int[] toreturn; for (int i = 0; i < ints.length; ++i) { if (ints[i]) toreturn.push(i); } return toreturn; } int size() { return size; } } // A map from integers to sets of integers. Again, no // attempt is made to use scalable data structures. struct int_to_intset { int[] keys = new int[0]; intset[] values = new intset[0]; void add(int key, int value) { for (int i = 0; i < keys.length; ++i) { if (keys[i] == key) { values[i].add(value); return; } } keys.push(key); intset newset; values.push(newset); newset.add(value); } private int indexOf(int key) { for (int i = 0; i < keys.length; ++i) { if (keys[i] == key) return i; } return -1; } int[] get(int key) { int i = indexOf(key); if (i < 0) return new int[0]; else return values[i].elements(); } int numvalues(int key) { int i = indexOf(key); if (i < 0) return 0; else return values[i].size(); } int numkeys() { return keys.length; } } // A struct intended to represent an undirected edge between // two "vertices." struct edge { int start; int end; void operator init(int a, int b) { start = a; end = b; } bool bordersvertex(int v) { return start == v || end == v; } } string operator cast(edge e) { int a, b; if (e.start <= e.end) {a = e.start; b = e.end;} else {a = e.end; b = e.start; } return (string)a + " <-> " + (string)b; } bool operator == (edge a, edge b) { if (a.start == b.start && a.end == b.end) return true; if (a.start == b.end && a.end == b.start) return true; return false; } string operator cast(edge[] edges) { string toreturn = "{ "; for (int i = 0; i < edges.length; ++i) { toreturn += edges[i]; if (i < edges.length-1) toreturn += ", "; } return toreturn + " }"; } // Finally, the function that strings together a list of edges // into a cycle. It makes assumptions that hold true if the // list of edges did in fact come from a plane intersection // containing no vertices of the cube. For instance, such a // plane can contain at most two noncollinear points of any // one face; consequently, no face can border more than two of // the selected edges. // // If the underlying assumptions prove to be false, the function // returns null. int[] makecircle(edge[] edges) { if (edges.length == 0) return new int[0]; int_to_intset graph; for (edge e : edges) { graph.add(e.start, e.end); graph.add(e.end, e.start); } int currentvertex = edges[0].start; int startvertex = currentvertex; int lastvertex = NULL_VERTEX; int[] toreturn = new int[0]; do { toreturn.push(currentvertex); int[] adjacentvertices = graph.get(currentvertex); if (adjacentvertices.length != 2) return null; for (int v : adjacentvertices) { if (v != lastvertex) { lastvertex = currentvertex; currentvertex = v; break; } } } while (currentvertex != startvertex); if (toreturn.length != graph.numkeys()) return null; toreturn.cyclic = true; return toreturn; } /***********************************************/ /********** PATHS BETWEEN POINTS ***************/ /***********************************************/ // Construct paths between two points with additional // constraints; for instance, the path must be orthogonal // to a certain vector at each of the endpoints, must // lie within a specified plane or a specified face // of a rectangular solid,.... // A vector (typically a normal vector) at a specified position. struct positionedvector { triple position; triple direction; void operator init(triple position, triple direction) { this.position = position; this.direction = direction; } } string operator cast(positionedvector vv) { return "position: " + (string)(vv.position) + " vector: " + (string)vv.direction; } // The angle, in degrees, between two vectors. real angledegrees(triple a, triple b) { real lengthprod = max(abs(a) * abs(b), abs(dot(a,b))); if (lengthprod == 0) return 0; return aCos(dot(a,b) / lengthprod); } // A path (single curved segment) between two points. At each point // is specified a vector orthogonal to the path. path3 pathbetween(positionedvector v1, positionedvector v2) { triple n1 = unit(v1.direction); triple n2 = unit(v2.direction); triple p1 = v1.position; triple p2 = v2.position; triple delta = p2-p1; triple dir1 = delta - dot(delta, n1)*n1; triple dir2 = delta - dot(delta, n2)*n2; return p1 {dir1} .. {dir2} p2; } // Assuming v1 and v2 are linearly independent, returns an array {a, b} // such that a v1 + b v2 is the orthogonal projection of toproject onto // the span of v1 and v2. If v1 and v2 are dependent, returns an empty array // (if warn==false) or throws an error (if warn==true). real[] projecttospan_findcoeffs(triple toproject, triple v1, triple v2, bool warn=false) { real[][] matrix = {{v1.x, v2.x}, {v1.y, v2.y}, {v1.z, v2.z}}; real[] desiredanswer = {toproject.x, toproject.y, toproject.z}; return leastsquares(matrix, desiredanswer, warn=warn); } // Project the triple toproject into the span of a and b, but restrict // to the quarter-plane of linear combinations a v1 + b v2 such that // a >= mincoeff and b >= mincoeff. If v1 and v2 are linearly dependent, // return a random (positive) linear combination. triple projecttospan(triple toproject, triple v1, triple v2, real mincoeff = 0.05) { real[] coeffs = projecttospan_findcoeffs(toproject, v1, v2, warn=false); real a, b; if (coeffs.length == 0) { a = mincoeff + unitrand(); b = mincoeff + unitrand(); } else { a = max(coeffs[0], mincoeff); b = max(coeffs[1], mincoeff); } return a*v1 + b*v2; } // A path between two specified vertices of a cyclic path. The // path tangent at each endpoint is guaranteed to lie within the // quarter-plane spanned by positive linear combinations of the // tangents of the two outgoing paths at that endpoint. path3 pathbetween(path3 edgecycle, int vertex1, int vertex2) { triple point1 = point(edgecycle, vertex1); triple point2 = point(edgecycle, vertex2); triple v1 = -dir(edgecycle, vertex1, sign=-1); triple v2 = dir(edgecycle, vertex1, sign= 1); triple direction1 = projecttospan(unit(point2-point1), v1, v2); v1 = -dir(edgecycle, vertex2, sign=-1); v2 = dir(edgecycle, vertex2, sign= 1); triple direction2 = projecttospan(unit(point1-point2), v1, v2); return point1 {direction1} .. {-direction2} point2; } // This function applies a heuristic to choose two "opposite" // vertices (separated by three segments) of edgecycle, which // is required to be a cyclic path consisting of 5 or 6 segments. // The two chosen vertices are pushed to savevertices. // // The function returns a path between the two chosen vertices. The // path tangent at each endpoint is guaranteed to lie within the // quarter-plane spanned by positive linear combinations of the // tangents of the two outgoing paths at that endpoint. path3 bisector(path3 edgecycle, int[] savevertices) { real mincoeff = 0.05; assert(cyclic(edgecycle)); int n = length(edgecycle); assert(n >= 5 && n <= 6); triple[] forwarddirections = sequence(new triple(int i) { return dir(edgecycle, i, sign=1); }, n); forwarddirections.cyclic = true; triple[] backwarddirections = sequence(new triple(int i) { return -dir(edgecycle, i, sign=-1); }, n); backwarddirections.cyclic = true; real[] angles = sequence(new real(int i) { return angledegrees(forwarddirections[i], backwarddirections[i]); }, n); angles.cyclic = true; int lastindex = (n == 5 ? 4 : 2); real maxgoodness = 0; int chosenindex = -1; triple directionout, directionin; for (int i = 0; i <= lastindex; ++i) { int opposite = i + 3; triple vec = unit(point(edgecycle, opposite) - point(edgecycle, i)); real[] coeffsbegin = projecttospan_findcoeffs(vec, forwarddirections[i], backwarddirections[i]); if (coeffsbegin.length == 0) continue; coeffsbegin[0] = max(coeffsbegin[0], mincoeff); coeffsbegin[1] = max(coeffsbegin[1], mincoeff); real[] coeffsend = projecttospan_findcoeffs(-vec, forwarddirections[opposite], backwarddirections[opposite]); if (coeffsend.length == 0) continue; coeffsend[0] = max(coeffsend[0], mincoeff); coeffsend[1] = max(coeffsend[1], mincoeff); real goodness = angles[i] * angles[opposite] * coeffsbegin[0] * coeffsend[0] * coeffsbegin[1] * coeffsend[1]; if (goodness > maxgoodness) { maxgoodness = goodness; directionout = coeffsbegin[0] * forwarddirections[i] + coeffsbegin[1] * backwarddirections[i]; directionin = -(coeffsend[0] * forwarddirections[opposite] + coeffsend[1] * backwarddirections[opposite]); chosenindex = i; } } if (chosenindex == -1) { savevertices.push(0); savevertices.push(3); return pathbetween(edgecycle, 0, 3); } else { savevertices.push(chosenindex); savevertices.push(chosenindex+3); return point(edgecycle, chosenindex) {directionout} .. {directionin} point(edgecycle, chosenindex + 3); } } // A path between two specified points (with specified normals) that lies // within a specified face of a rectangular solid. path3 pathinface(positionedvector v1, positionedvector v2, triple facenorm, triple edge1normout, triple edge2normout) { triple dir1 = cross(v1.direction, facenorm); real dotprod = dot(dir1, edge1normout); if (dotprod > 0) dir1 = -dir1; // Believe it or not, this "tiebreaker" is actually relevant at times, // for instance, when graphing the cone x^2 + y^2 = z^2 over the region // -1 <= x,y,z <= 1. else if (dotprod == 0 && dot(dir1, v2.position - v1.position) < 0) dir1 = -dir1; triple dir2 = cross(v2.direction, facenorm); dotprod = dot(dir2, edge2normout); if (dotprod < 0) dir2 = -dir2; else if (dotprod == 0 && dot(dir2, v2.position - v1.position) < 0) dir2 = -dir2; return v1.position {dir1} .. {dir2} v2.position; } triple normalout(int face) { if (face == XHIGH) return X; else if (face == YHIGH) return Y; else if (face == ZHIGH) return Z; else if (face == XLOW) return -X; else if (face == YLOW) return -Y; else if (face == ZLOW) return -Z; else return O; } // A path between two specified points (with specified normals) that lies // within a specified face of a rectangular solid. path3 pathinface(positionedvector v1, positionedvector v2, int face, int edge1face, int edge2face) { return pathinface(v1, v2, normalout(face), normalout(edge1face), normalout(edge2face)); } /***********************************************/ /******** DRAWING IMPLICIT SURFACES ************/ /***********************************************/ // Quadrilateralization: // Produce a surface (array of *nondegenerate* Bezier patches) with a // specified three-segment boundary. The surface should approximate the // zero locus of the specified f with its specified gradient. // // If it is not possible to produce the desired result without leaving the // specified rectangular region, returns a length-zero array. // // Dividing a triangle into smaller quadrilaterals this way is opposite // the usual trend in mathematics. However, the pathwithnormals algorithm // does a poor job of choosing a good surface when the boundary path does // not consist of four positive-length segments. patch[] triangletoquads(path3 external, real f(triple), triple grad(triple), triple a, triple b) { static real epsilon = 1e-3; assert(length(external) == 3); assert(cyclic(external)); triple c0 = point(external, 0); triple c1 = point(external, 1); triple c2 = point(external, 2); triple center = (c0 + c1 + c2) / 3; triple n = unit(cross(c1-c0, c2-c0)); real g(real t) { return f(center + t*n); } real tmin = -realMax, tmax = realMax; void absorb(real t) { if (t < 0) tmin = max(t,tmin); else tmax = min(t,tmax); } if (n.x != 0) { absorb((a.x - center.x) / n.x); absorb((b.x - center.x) / n.x); } if (n.y != 0) { absorb((a.y - center.y) / n.y); absorb((b.y - center.y) / n.y); } if (n.z != 0) { absorb((a.z - center.z) / n.z); absorb((b.z - center.z) / n.z); } real fa = g(tmin); real fb = g(tmax); if ((fa > 0 && fb > 0) || (fa < 0 && fb < 0)) { return new patch[0]; } else { real t = findroot(g, tmin, tmax, fa=fa, fb=fb); center += t * n; } n = unit(grad(center)); triple m0 = point(external, 0.5); positionedvector m0 = positionedvector(m0, unit(grad(m0))); triple m1 = point(external, 1.5); positionedvector m1 = positionedvector(m1, unit(grad(m1))); triple m2 = point(external, 2.5); positionedvector m2 = positionedvector(m2, unit(grad(m2))); positionedvector c = positionedvector(center, unit(grad(center))); path3 pathto_m0 = pathbetween(c, m0); path3 pathto_m1 = pathbetween(c, m1); path3 pathto_m2 = pathbetween(c, m2); path3 quad0 = subpath(external, 0, 0.5) & reverse(pathto_m0) & pathto_m2 & subpath(external, -0.5, 0) & cycle; path3 quad1 = subpath(external, 1, 1.5) & reverse(pathto_m1) & pathto_m0 & subpath(external, 0.5, 1) & cycle; path3 quad2 = subpath(external, 2, 2.5) & reverse(pathto_m2) & pathto_m1 & subpath(external, 1.5, 2) & cycle; return new patch[] {patchwithnormals(quad0, grad), patchwithnormals(quad1, grad), patchwithnormals(quad2, grad)}; } // Returns true if the point is "nonsingular" (in the sense that the magnitude // of the gradient is not too small) AND very close to the zero locus of f // (assuming f is locally linear). bool check_fpt_zero(triple testpoint, real f(triple), triple grad(triple)) { real testval = f(testpoint); real slope = abs(grad(testpoint)); static real tolerance = 2*rootfinder_settings.roottolerance; return !(slope > tolerance && abs(testval) / slope > tolerance); } // Returns true if pt lies within the rectangular solid with // opposite corners at a and b. bool checkptincube(triple pt, triple a, triple b) { real xmin = a.x; real xmax = b.x; real ymin = a.y; real ymax = b.y; real zmin = a.z; real zmax = b.z; if (xmin > xmax) { real t = xmax; xmax=xmin; xmin=t; } if (ymin > ymax) { real t = ymax; ymax=ymin; ymin=t; } if (zmin > zmax) { real t = zmax; zmax=zmin; zmin=t; } return ((xmin <= pt.x) && (pt.x <= xmax) && (ymin <= pt.y) && (pt.y <= ymax) && (zmin <= pt.z) && (pt.z <= zmax)); } // A convenience function for combining the previous two tests. bool checkpt(triple testpt, real f(triple), triple grad(triple), triple a, triple b) { return checkptincube(testpt, a, b) && check_fpt_zero(testpt, f, grad); } // Attempts to fill in the boundary cycle with a collection of // patches to approximate smoothly the zero locus of f. If unable to // do so while satisfying certain checks, returns null. // This is distinct from returning an empty // array, which merely indicates that the boundary cycle is too small // to be worth filling in. patch[] quadpatches(path3 edgecycle, positionedvector[] corners, real f(triple), triple grad(triple), triple a, triple b) { assert(corners.cyclic); // The tolerance for considering two points "essentially identical." static real tolerance = 2.5 * rootfinder_settings.roottolerance; // If there are two neighboring vertices that are essentially identical, // unify them into one. for (int i = 0; i < corners.length; ++i) { if (abs(corners[i].position - corners[i+1].position) < tolerance) { if (corners.length == 2) return new patch[0]; corners.delete(i); edgecycle = subpath(edgecycle, 0, i) & subpath(edgecycle, i+1, length(edgecycle)) & cycle; --i; assert(length(edgecycle) == corners.length); } } static real areatolerance = tolerance^2; assert(corners.length >= 2); if (corners.length == 2) { // If the area is too small, just ignore it; otherwise, subdivide. real area0 = abs(cross(-dir(edgecycle, 0, sign=-1, normalize=false), dir(edgecycle, 0, sign=1, normalize=false))); real area1 = abs(cross(-dir(edgecycle, 1, sign=-1, normalize=false), dir(edgecycle, 1, sign=1, normalize=false))); if (area0 < areatolerance && area1 < areatolerance) return new patch[0]; else return null; } if (length(edgecycle) > 6) abort("too many edges: not possible."); for (int i = 0; i < length(edgecycle); ++i) { if (angledegrees(dir(edgecycle,i,sign=1), dir(edgecycle,i+1,sign=-1)) > 80) { return null; } } if (length(edgecycle) == 3) { patch[] toreturn = triangletoquads(edgecycle, f, grad, a, b); if (toreturn.length == 0) return null; else return toreturn; } if (length(edgecycle) == 4) { return new patch[] {patchwithnormals(edgecycle, grad)}; } int[] bisectorindices; path3 middleguide = bisector(edgecycle, bisectorindices); triple testpoint = point(middleguide, 0.5); if (!checkpt(testpoint, f, grad, a, b)) { return null; } patch[] toreturn = null; path3 firstpatch = subpath(edgecycle, bisectorindices[0], bisectorindices[1]) & reverse(middleguide) & cycle; if (length(edgecycle) == 5) { path3 secondpatch = middleguide & subpath(edgecycle, bisectorindices[1], 5+bisectorindices[0]) & cycle; toreturn = triangletoquads(secondpatch, f, grad, a, b); if (toreturn.length == 0) return null; toreturn.push(patchwithnormals(firstpatch, grad)); } else { // now length(edgecycle) == 6 path3 secondpatch = middleguide & subpath(edgecycle, bisectorindices[1], 6+bisectorindices[0]) & cycle; toreturn = new patch[] {patchwithnormals(firstpatch, grad), patchwithnormals(secondpatch, grad)}; } return toreturn; } // Numerical gradient of a function typedef triple vectorfunction(triple); vectorfunction nGrad(real f(triple)) { static real epsilon = 1e-3; return new triple(triple v) { return ( (f(v + epsilon*X) - f(v - epsilon*X)) / (2 epsilon), (f(v + epsilon*Y) - f(v - epsilon*Y)) / (2 epsilon), (f(v + epsilon*Z) - f(v - epsilon*Z)) / (2 epsilon) ); }; } // A point together with a value at that location. struct evaluatedpoint { triple pt; real value; void operator init(triple pt, real value) { this.pt = pt; this.value = value; } } triple operator cast(evaluatedpoint p) { return p.pt; } // Compute the values of a function at every vertex of an nx by ny by nz // array of rectangular solids. evaluatedpoint[][][] make3dgrid(triple a, triple b, int nx, int ny, int nz, real f(triple), bool allowzero = false) { evaluatedpoint[][][] toreturn = new evaluatedpoint[nx+1][ny+1][nz+1]; for (int i = 0; i <= nx; ++i) { for (int j = 0; j <= ny; ++j) { for (int k = 0; k <= nz; ++k) { triple pt = (interp(a.x, b.x, i/nx), interp(a.y, b.y, j/ny), interp(a.z, b.z, k/nz)); real value = f(pt); if (value == 0 && !allowzero) value = 1e-5; toreturn[i][j][k] = evaluatedpoint(pt, value); } } } return toreturn; } // The following utilities make, for instance, slice(A, i, j, k, l) // equivalent to what A[i:j][k:l] ought to mean for two- and three- // -dimensional arrays of evaluatedpoints and of positionedvectors. typedef evaluatedpoint T; T[][] slice(T[][] a, int start1, int end1, int start2, int end2) { T[][] toreturn = new T[end1-start1][]; for (int i = start1; i < end1; ++i) { toreturn[i-start1] = a[i][start2:end2]; } return toreturn; } T[][][] slice(T[][][] a, int start1, int end1, int start2, int end2, int start3, int end3) { T[][][] toreturn = new T[end1-start1][][]; for (int i = start1; i < end1; ++i) { toreturn[i-start1] = slice(a[i], start2, end2, start3, end3); } return toreturn; } typedef positionedvector T; T[][] slice(T[][] a, int start1, int end1, int start2, int end2) { T[][] toreturn = new T[end1-start1][]; for (int i = start1; i < end1; ++i) { toreturn[i-start1] = a[i][start2:end2]; } return toreturn; } T[][][] slice(T[][][] a, int start1, int end1, int start2, int end2, int start3, int end3) { T[][][] toreturn = new T[end1-start1][][]; for (int i = start1; i < end1; ++i) { toreturn[i-start1] = slice(a[i], start2, end2, start3, end3); } return toreturn; } // An object of class gridwithzeros stores the values of a function at each vertex // of a three-dimensional grid, together with zeros of the function along edges // of the grid and the gradient of the function at each such zero. struct gridwithzeros { int nx, ny, nz; evaluatedpoint[][][] corners; positionedvector[][][] xdirzeros; positionedvector[][][] ydirzeros; positionedvector[][][] zdirzeros; triple grad(triple); real f(triple); int maxdepth; // Populate the edges with zeros that have a sign change and are not already // populated. void fillzeros() { for (int j = 0; j < ny+1; ++j) { for (int k = 0; k < nz+1; ++k) { real y = corners[0][j][k].pt.y; real z = corners[0][j][k].pt.z; real f_along_x(real t) { return f((t, y, z)); } for (int i = 0; i < nx; ++i) { if (xdirzeros[i][j][k] != null) continue; evaluatedpoint start = corners[i][j][k]; evaluatedpoint end = corners[i+1][j][k]; if ((start.value > 0 && end.value > 0) || (start.value < 0 && end.value < 0)) xdirzeros[i][j][k] = null; else { triple root = (0,y,z); root += X * findroot(f_along_x, start.pt.x, end.pt.x, fa=start.value, fb=end.value); triple normal = grad(root); xdirzeros[i][j][k] = positionedvector(root, normal); } } } } for (int i = 0; i < nx+1; ++i) { for (int k = 0; k < nz+1; ++k) { real x = corners[i][0][k].pt.x; real z = corners[i][0][k].pt.z; real f_along_y(real t) { return f((x, t, z)); } for (int j = 0; j < ny; ++j) { if (ydirzeros[i][j][k] != null) continue; evaluatedpoint start = corners[i][j][k]; evaluatedpoint end = corners[i][j+1][k]; if ((start.value > 0 && end.value > 0) || (start.value < 0 && end.value < 0)) ydirzeros[i][j][k] = null; else { triple root = (x,0,z); root += Y * findroot(f_along_y, start.pt.y, end.pt.y, fa=start.value, fb=end.value); triple normal = grad(root); ydirzeros[i][j][k] = positionedvector(root, normal); } } } } for (int i = 0; i < nx+1; ++i) { for (int j = 0; j < ny+1; ++j) { real x = corners[i][j][0].pt.x; real y = corners[i][j][0].pt.y; real f_along_z(real t) { return f((x, y, t)); } for (int k = 0; k < nz; ++k) { if (zdirzeros[i][j][k] != null) continue; evaluatedpoint start = corners[i][j][k]; evaluatedpoint end = corners[i][j][k+1]; if ((start.value > 0 && end.value > 0) || (start.value < 0 && end.value < 0)) zdirzeros[i][j][k] = null; else { triple root = (x,y,0); root += Z * findroot(f_along_z, start.pt.z, end.pt.z, fa=start.value, fb=end.value); triple normal = grad(root); zdirzeros[i][j][k] = positionedvector(root, normal); } } } } } // Fill in the grid vertices and the zeros along edges. Each cube starts at // depth one and the depth increases each time it subdivides; maxdepth is the // maximum subdivision depth. When a cube at maxdepth cannot be resolved to // patches, it is left empty. void operator init(int nx, int ny, int nz, real f(triple), triple a, triple b, int maxdepth = 6) { this.nx = nx; this.ny = ny; this.nz = nz; grad = nGrad(f); this.f = f; this.maxdepth = maxdepth; corners = make3dgrid(a, b, nx, ny, nz, f); xdirzeros = new positionedvector[nx][ny+1][nz+1]; ydirzeros = new positionedvector[nx+1][ny][nz+1]; zdirzeros = new positionedvector[nx+1][ny+1][nz]; for (int i = 0; i <= nx; ++i) { for (int j = 0; j <= ny; ++j) { for (int k = 0; k <= nz; ++k) { if (i < nx) xdirzeros[i][j][k] = null; if (j < ny) ydirzeros[i][j][k] = null; if (k < nz) zdirzeros[i][j][k] = null; } } } fillzeros(); } // Doubles nx, ny, and nz by halving the sizes of the cubes along the x, y, and z // directions (resulting in 8 times as many cubes). Already existing data about // function values and zeros is copied; vertices and edges with no such pre-existing // data are populated. // // Returns true if subdivide succeeded, false if it failed (because maxdepth // was exceeded). bool subdivide() { if (maxdepth <= 1) { return false; } --maxdepth; triple a = corners[0][0][0]; triple b = corners[nx][ny][nz]; nx *= 2; ny *= 2; nz *= 2; evaluatedpoint[][][] oldcorners = corners; corners = new evaluatedpoint[nx+1][ny+1][nz+1]; for (int i = 0; i <= nx; ++i) { for (int j = 0; j <= ny; ++j) { for (int k = 0; k <= nz; ++k) { if (i % 2 == 0 && j % 2 == 0 && k % 2 == 0) { corners[i][j][k] = oldcorners[quotient(i,2)][quotient(j,2)][quotient(k,2)]; } else { triple pt = (interp(a.x, b.x, i/nx), interp(a.y, b.y, j/ny), interp(a.z, b.z, k/nz)); real value = f(pt); if (value == 0) value = 1e-5; corners[i][j][k] = evaluatedpoint(pt, value); } } } } positionedvector[][][] oldxdir = xdirzeros; xdirzeros = new positionedvector[nx][ny+1][nz+1]; for (int i = 0; i < nx; ++i) { for (int j = 0; j < ny + 1; ++j) { for (int k = 0; k < nz + 1; ++k) { if (j % 2 != 0 || k % 2 != 0) { xdirzeros[i][j][k] = null; } else { positionedvector zero = oldxdir[quotient(i,2)][quotient(j,2)][quotient(k,2)]; if (zero == null) { xdirzeros[i][j][k] = null; continue; } real x = zero.position.x; if (x > interp(a.x, b.x, i/nx) && x < interp(a.x, b.x, (i+1)/nx)) { xdirzeros[i][j][k] = zero; } else { xdirzeros[i][j][k] = null; } } } } } positionedvector[][][] oldydir = ydirzeros; ydirzeros = new positionedvector[nx+1][ny][nz+1]; for (int i = 0; i < nx+1; ++i) { for (int j = 0; j < ny; ++j) { for (int k = 0; k < nz + 1; ++k) { if (i % 2 != 0 || k % 2 != 0) { ydirzeros[i][j][k] = null; } else { positionedvector zero = oldydir[quotient(i,2)][quotient(j,2)][quotient(k,2)]; if (zero == null) { ydirzeros[i][j][k] = null; continue; } real y = zero.position.y; if (y > interp(a.y, b.y, j/ny) && y < interp(a.y, b.y, (j+1)/ny)) { ydirzeros[i][j][k] = zero; } else { ydirzeros[i][j][k] = null; } } } } } positionedvector[][][] oldzdir = zdirzeros; zdirzeros = new positionedvector[nx+1][ny+1][nz]; for (int i = 0; i < nx + 1; ++i) { for (int j = 0; j < ny + 1; ++j) { for (int k = 0; k < nz; ++k) { if (i % 2 != 0 || j % 2 != 0) { zdirzeros[i][j][k] = null; } else { positionedvector zero = oldzdir[quotient(i,2)][quotient(j,2)][quotient(k,2)]; if (zero == null) { zdirzeros[i][j][k] = null; continue; } real z = zero.position.z; if (z > interp(a.z, b.z, k/nz) && z < interp(a.z, b.z, (k+1)/nz)) { zdirzeros[i][j][k] = zero; } else { zdirzeros[i][j][k] = null; } } } } } fillzeros(); return true; } // Forward declaration of the draw method, which will be called by drawcube(). patch[] draw(bool[] reportactive = null); // Construct the patches, assuming that we are working // with a single cube (nx = ny = nz = 1). This method will subdivide the // cube if necessary. The parameter reportactive should be an array of // length 6. Setting an entry to true indicates that the surface abuts the // corresponding face (according to the earlier enum), and thus that the // algorithm should be sure that something is drawn in the cube sharing // that face--even if all the vertices of that cube have the same sign. patch[] drawcube(bool[] reportactive = null) { // First, determine which edges (if any) actually have zeros on them. edge[] zeroedges = new edge[0]; positionedvector[] zeros = new positionedvector[0]; int currentface, nextface; void pushifnonnull(positionedvector v) { if (v != null) { zeroedges.push(edge(currentface, nextface)); zeros.push(v); } } positionedvector findzero(int face1, int face2) { edge e = edge(face1, face2); for (int i = 0; i < zeroedges.length; ++i) { if (zeroedges[i] == e) return zeros[i]; } return null; } currentface = XLOW; nextface = YHIGH; pushifnonnull(zdirzeros[0][1][0]); nextface = YLOW; pushifnonnull(zdirzeros[0][0][0]); nextface = ZHIGH; pushifnonnull(ydirzeros[0][0][1]); nextface = ZLOW; pushifnonnull(ydirzeros[0][0][0]); currentface = XHIGH; nextface = YHIGH; pushifnonnull(zdirzeros[1][1][0]); nextface = YLOW; pushifnonnull(zdirzeros[1][0][0]); nextface = ZHIGH; pushifnonnull(ydirzeros[1][0][1]); nextface = ZLOW; pushifnonnull(ydirzeros[1][0][0]); currentface = YHIGH; nextface = ZHIGH; pushifnonnull(xdirzeros[0][1][1]); currentface = ZHIGH; nextface = YLOW; pushifnonnull(xdirzeros[0][0][1]); currentface = YLOW; nextface = ZLOW; pushifnonnull(xdirzeros[0][0][0]); currentface = ZLOW; nextface = YHIGH; pushifnonnull(xdirzeros[0][1][0]); //Now, string those edges together to make a circle. patch[] subdividecube() { if (!subdivide()) { return new patch[0]; } return draw(reportactive); } if (zeroedges.length < 3) { return subdividecube(); } int[] faceorder = makecircle(zeroedges); if (alias(faceorder,null)) { return subdividecube(); } positionedvector[] patchcorners = new positionedvector[0]; for (int i = 0; i < faceorder.length; ++i) { patchcorners.push(findzero(faceorder[i], faceorder[i+1])); } patchcorners.cyclic = true; //Now, produce the cyclic path around the edges. path3 edgecycle; for (int i = 0; i < faceorder.length; ++i) { path3 currentpath = pathinface(patchcorners[i], patchcorners[i+1], faceorder[i+1], faceorder[i], faceorder[i+2]); triple testpoint = point(currentpath, 0.5); if (!checkpt(testpoint, f, grad, corners[0][0][0], corners[1][1][1])) { return subdividecube(); } edgecycle = edgecycle & currentpath; } edgecycle = edgecycle & cycle; patch[] toreturn = quadpatches(edgecycle, patchcorners, f, grad, corners[0][0][0], corners[1][1][1]); if (alias(toreturn, null)) return subdividecube(); return toreturn; } // Extracts the specified cube as a gridwithzeros object with // nx = ny = nz = 1. gridwithzeros getcube(int i, int j, int k) { gridwithzeros cube = new gridwithzeros; cube.grad = grad; cube.f = f; cube.nx = 1; cube.ny = 1; cube.nz = 1; cube.maxdepth = maxdepth; cube.corners = slice(corners,i,i+2,j,j+2,k,k+2); cube.xdirzeros = slice(xdirzeros,i,i+1,j,j+2,k,k+2); cube.ydirzeros = slice(ydirzeros,i,i+2,j,j+1,k,k+2); cube.zdirzeros = slice(zdirzeros,i,i+2,j,j+2,k,k+1); return cube; } // Returns an array of patches representing the surface. // The parameter reportactive should be an array of // length 6. Setting an entry to true indicates that the surface abuts the // corresponding face of the cube that bounds the entire grid. // // If reportactive == null, it is assumed that this is a top-level call; // a dot is printed to stdout for each cube drawn as a very rough // progress indicator. // // If reportactive != null, then it is assumed that the caller had a strong // reason to believe that this grid contains a part of the surface; the // grid will subdivide all the way to maxdepth if necessary to find points // on the surface. draw = new patch[](bool[] reportactive = null) { // A list of all the patches not already drawn but known // to contain part of the surface. This "queue" is // actually implemented as stack for simplicity, since // it does not make any difference. In a multi-threaded // version of the algorithm, a queue (shared across all threads) // would make more sense than a stack. triple[] queue = new triple[0]; bool[][][] enqueued = new bool[nx][ny][nz]; for (int i = 0; i < enqueued.length; ++i) { for (int j = 0; j < enqueued[i].length; ++j) { for (int k = 0; k < enqueued[i][j].length; ++k) { enqueued[i][j][k] = false; } } } void enqueue(int i, int j, int k) { if (i >= 0 && i < nx && j >= 0 && j < ny && k >= 0 && k < nz && !enqueued[i][j][k]) { queue.push((i,j,k)); enqueued[i][j][k] = true; } if (!alias(reportactive, null)) { if (i < 0) reportactive[XLOW] = true; if (i >= nx) reportactive[XHIGH] = true; if (j < 0) reportactive[YLOW] = true; if (j >= ny) reportactive[YHIGH] = true; if (k < 0) reportactive[ZLOW] = true; if (k >= nz) reportactive[ZHIGH] = true; } } for (int i = 0; i < nx+1; ++i) { for (int j = 0; j < ny+1; ++j) { for (int k = 0; k < nz+1; ++k) { if (i < nx && xdirzeros[i][j][k] != null) { for (int jj = j-1; jj <= j; ++jj) for (int kk = k-1; kk <= k; ++kk) enqueue(i, jj, kk); } if (j < ny && ydirzeros[i][j][k] != null) { for (int ii = i-1; ii <= i; ++ii) for (int kk = k-1; kk <= k; ++kk) enqueue(ii, j, kk); } if (k < nz && zdirzeros[i][j][k] != null) { for (int ii = i-1; ii <= i; ++ii) for (int jj = j-1; jj <= j; ++jj) enqueue(ii, jj, k); } } } } if (!alias(reportactive, null) && queue.length == 0) { if (subdivide()) return draw(reportactive); } patch[] surface = new patch[0]; while (queue.length > 0) { triple coord = queue.pop(); int i = floor(coord.x); int j = floor(coord.y); int k = floor(coord.z); bool[] reportface = array(6, false); patch[] toappend = getcube(i,j,k).drawcube(reportface); if (reportface[XLOW]) enqueue(i-1,j,k); if (reportface[XHIGH]) enqueue(i+1,j,k); if (reportface[YLOW]) enqueue(i,j-1,k); if (reportface[YHIGH]) enqueue(i,j+1,k); if (reportface[ZLOW]) enqueue(i,j,k-1); if (reportface[ZHIGH]) enqueue(i,j,k+1); surface.append(toappend); if (settings.verbose > 1 && alias(reportactive, null)) write(stdout, '.'); } if (settings.verbose > 1 && alias(reportactive, null)) write(stdout, '\n'); return surface; }; } // The external interface of this whole module. Accepts exactly one // function (throws an error if two or zero functions are specified). // The function should be differentiable. (Whatever you do, do not // pass in an indicator function!) Ideally, the zero locus of the // function should be smooth; singularities will significantly slow // down the algorithm and potentially give bad results. // // Returns a plot of the zero locus of the function within the // rectangular solid with opposite corners at a and b. // // Additional parameters: // n - the number of initial segments in each of the x, y, z directions. // overlapedges - if true, the patches of the surface are slightly enlarged // to compensate for an artifact in which the viewer can see through the // boundary between patches. (Some of this may actually be a result of // edges not lining up perfectly, but I'm fairly sure a lot of it arises // purely as a rendering artifact.) // nx - override n in the x direction // ny - override n in the y direction // nz - override n in the z direction // maxdepth - the maximum depth to which the algorithm will subdivide in // an effort to find patches that closely approximate the true surface. surface implicitsurface(real f(triple) = null, real ff(real,real,real) = null, triple a, triple b, int n = nmesh, bool keyword overlapedges = false, int keyword nx=n, int keyword ny=n, int keyword nz=n, int keyword maxdepth = 8) { if (f == null && ff == null) abort("implicitsurface called without specifying a function."); if (f != null && ff != null) abort("Only specify one function when calling implicitsurface."); if (f == null) f = new real(triple w) { return ff(w.x, w.y, w.z); }; gridwithzeros grid = gridwithzeros(nx, ny, nz, f, a, b, maxdepth=maxdepth); patch[] patches = grid.draw(); if (overlapedges) { for (int i = 0; i < patches.length; ++i) { triple center = patches[i].point(1/2,1/2); patches[i] = shift(center) * scale3(1.01) * shift(-center) * patches[i]; } } return surface(...patches); } asymptote-2.37/base/solids.asy000066400000000000000000000276651265434602500164460ustar00rootroot00000000000000import graph3; pen defaultbackpen=linetype(new real[] {4,4},4,scale=false); // A solid geometry package. // Try to find a bounding tangent line between two paths. real[] tangent(path p, path q, bool side) { static real fuzz=1.0e-5; if((cyclic(p) && inside(p,point(q,0)) || cyclic(q) && inside(q,point(p,0))) && intersect(p,q,fuzz).length == 0) return new real[]; for(int i=0; i < 100; ++i) { real ta=side ? mintimes(p)[1] : maxtimes(p)[1]; real tb=side ? mintimes(q)[1] : maxtimes(q)[1]; pair a=point(p,ta); pair b=point(q,tb); real angle=angle(b-a,warn=false); if(abs(angle) <= sqrtEpsilon || abs(abs(0.5*angle)-pi) <= sqrtEpsilon) return new real[] {ta,tb}; transform t=rotate(-degrees(angle)); p=t*p; q=t*q; } return new real[]; } path line(path p, path q, real[] t) { return point(p,t[0])--point(q,t[1]); } // Return the projection of a generalized cylinder of height h constructed // from area base in the XY plane and aligned with axis. path[] cylinder(path3 base, real h, triple axis=Z, projection P) { base=rotate(-colatitude(axis),cross(axis,Z))*base; path3 top=shift(h*axis)*base; path Base=project(base,P); path Top=project(top,P); real[] t1=tangent(Base,Top,true); real[] t2=tangent(Base,Top,false); path p=subpath(Base,t1[0]/P.ninterpolate,t2[0]/P.ninterpolate); path q=subpath(Base,t2[0]/P.ninterpolate,t1[0]/P.ninterpolate); return Base^^Top^^line(Base,Top,t1)^^line(Base,Top,t2); } // The three-dimensional "wireframe" used to visualize a volume of revolution struct skeleton { struct curve { path3[] front; path3[] back; } // transverse skeleton (perpendicular to axis of revolution) curve transverse; // longitudinal skeleton (parallel to axis of revolution) curve longitudinal; } // A surface of revolution generated by rotating a planar path3 g // from angle1 to angle2 about c--c+axis. struct revolution { triple c; path3 g; triple axis; real angle1,angle2; triple M; triple m; static real epsilon=10*sqrtEpsilon; void operator init(triple c=O, path3 g, triple axis=Z, real angle1=0, real angle2=360) { this.c=c; this.g=g; this.axis=unit(axis); this.angle1=angle1; this.angle2=angle2; M=max(g); m=min(g); } revolution copy() { return revolution(c,g,axis,angle1,angle2); } triple vertex(int i, real j) { triple v=point(g,i); triple center=c+dot(v-c,axis)*axis; triple perp=v-center; triple normal=cross(axis,perp); return center+Cos(j)*perp+Sin(j)*normal; } // Construct the surface of rotation generated by rotating g // from angle1 to angle2 sampled n times about the line c--c+axis. // An optional surface pen color(int i, real j) may be specified // to override the color at vertex(i,j). surface surface(int n=nslice, pen color(int i, real j)=null) { return surface(c,g,axis,n,angle1,angle2,color); } path3 slice(real position, int n=nCircle) { triple v=point(g,position); triple center=c+dot(v-c,axis)*axis; triple perp=v-center; if(abs(perp) <= epsilon*max(abs(m),abs(M))) return center; triple v1=center+rotate(angle1,axis)*perp; triple v2=center+rotate(angle2,axis)*perp; path3 p=Arc(center,v1,v2,axis,n); return (angle2-angle1) % 360 == 0 ? p&cycle : p; } triple camera(projection P) { triple camera=P.camera; if(P.infinity) { real s=abs(M-m)+abs(m-P.target); camera=P.target+camerafactor*s*unit(P.vector()); } return camera; } // add transverse slice to skeleton s; void transverse(skeleton s, real t, int n=nslice, projection P) { skeleton.curve s=s.transverse; path3 S=slice(t,n); triple camera=camera(P); int L=length(g); real midtime=0.5*L; real sign=sgn(dot(axis,camera-P.target))*sgn(dot(axis,dir(g,midtime))); if(dot(M-m,axis) == 0 || (t <= epsilon && sign < 0) || (t >= L-epsilon && sign > 0)) s.front.push(S); else { path3 Sp=slice(t+epsilon,n); path3 Sm=slice(t-epsilon,n); path sp=project(Sp,P); path sm=project(Sm,P); real[] t1=tangent(sp,sm,true); real[] t2=tangent(sp,sm,false); if(t1.length > 1 && t2.length > 1) { real t1=t1[0]/P.ninterpolate; real t2=t2[0]/P.ninterpolate; int len=length(S); if(t2 < t1) { real temp=t1; t1=t2; t2=temp; } path3 p1=subpath(S,t1,t2); path3 p2=subpath(S,t2,len); path3 P2=subpath(S,0,t1); if(abs(midpoint(p1)-camera) <= abs(midpoint(p2)-camera)) { s.front.push(p1); if(cyclic(S)) s.back.push(p2 & P2); else { s.back.push(p2); s.back.push(P2); } } else { if(cyclic(S)) s.front.push(p2 & P2); else { s.front.push(p2); s.front.push(P2); } s.back.push(p1); } } else { if((t <= midtime && sign < 0) || (t >= midtime && sign > 0)) s.front.push(S); else s.back.push(S); } } } // add m evenly spaced transverse slices to skeleton s void transverse(skeleton s, int m=0, int n=nslice, projection P) { if(m == 0) { int N=size(g); for(int i=0; i < N; ++i) transverse(s,(real) i,n,P); } else if(m == 1) transverse(s,reltime(g,0.5),n,P); else { real factor=1/(m-1); for(int i=0; i < m; ++i) transverse(s,reltime(g,i*factor),n,P); } } // return approximate silhouette based on m evenly spaced transverse slices; // must be recomputed if camera is adjusted path3[] silhouette(int m=64, projection P=currentprojection) { if(is3D()) warning("2Dsilhouette", "silhouette routine is intended only for 2d projections"); path3 G,H; int N=size(g); int M=(m == 0) ? N : m; real factor=m == 1 ? 0 : 1/(m-1); int n=nslice; real tfirst=-1; real tlast; for(int i=0; i < M; ++i) { real t=(m == 0) ? i : reltime(g,i*factor); path3 S=slice(t,n); triple camera=camera(P); path3 Sp=slice(t+epsilon,n); path3 Sm=slice(t-epsilon,n); path sp=project(Sp,P); path sm=project(Sm,P); real[] t1=tangent(sp,sm,true); real[] t2=tangent(sp,sm,false); if(t1.length > 1 && t2.length > 1) { real t1=t1[0]/P.ninterpolate; real t2=t2[0]/P.ninterpolate; if(t1 != t2) { G=G..point(S,t1); H=point(S,t2)..H; if(tfirst < 0) tfirst=t; tlast=t; } } } int L=length(g); real midtime=0.5*L; triple camera=camera(P); real sign=sgn(dot(axis,camera-P.target))*sgn(dot(axis,dir(g,midtime))); skeleton sfirst; transverse(sfirst,tfirst,n,P); triple delta=this.M-this.m; path3 cap; if(dot(delta,axis) == 0 || (tfirst <= epsilon && sign < 0)) { cap=sfirst.transverse.front[0]; } else { if(sign > 0) { if(sfirst.transverse.front.length > 0) G=reverse(sfirst.transverse.front[0])..G; } else { if(sfirst.transverse.back.length > 0) G=sfirst.transverse.back[0]..G; } } skeleton slast; transverse(slast,tlast,n,P); if(dot(delta,axis) == 0 || (tlast >= L-epsilon && sign > 0)) { cap=slast.transverse.front[0]; } else { if(sign > 0) { if(slast.transverse.back.length > 0) H=reverse(slast.transverse.back[0])..H; } else { if(slast.transverse.front.length > 0) H=slast.transverse.front[0]..H; } } return size(cap) == 0 ? G^^H : G^^H^^cap; } // add longitudinal curves to skeleton; void longitudinal(skeleton s, int n=nslice, projection P) { real t, d=0; // Find a point on g of maximal distance from the axis. int N=size(g); for(int i=0; i < N; ++i) { triple v=point(g,i); triple center=c+dot(v-c,axis)*axis; real r=abs(v-center); if(r > d) { t=i; d=r; } } path3 S=slice(t,n); path3 Sm=slice(t+epsilon,n); path3 Sp=slice(t-epsilon,n); path sp=project(Sp,P); path sm=project(Sm,P); real[] t1=tangent(sp,sm,true); real[] t2=tangent(sp,sm,false); transform3 T=transpose(align(axis)); real Longitude(triple v) {return longitude(T*(v-c),warn=false);} real ref=Longitude(point(g,t)); real angle(real t) {return Longitude(point(S,t/P.ninterpolate))-ref;} triple camera=camera(P); void push(real[] T) { if(T.length > 1) { path3 p=rotate(angle(T[0]),c,c+axis)*g; path3 p1=subpath(p,0,t); path3 p2=subpath(p,t,length(p)); if(length(p1) > 0 && abs(midpoint(p1)-camera) <= abs(midpoint(p2)-camera)) { s.longitudinal.front.push(p1); s.longitudinal.back.push(p2); } else { s.longitudinal.back.push(p1); s.longitudinal.front.push(p2); } } } push(t1); push(t2); } skeleton skeleton(int m=0, int n=nslice, projection P) { skeleton s; transverse(s,m,n,P); longitudinal(s,n,P); return s; } } surface surface(revolution r, int n=nslice, pen color(int i, real j)=null) { return r.surface(n,color); } // Draw on picture pic the skeleton of the surface of revolution r. // Draw the front portion of each of the m transverse slices with pen p and // the back portion with pen backpen. Rotational arcs are based on // n-point approximations to the unit circle. void draw(picture pic=currentpicture, revolution r, int m=0, int n=nslice, pen frontpen=currentpen, pen backpen=frontpen, pen longitudinalpen=frontpen, pen longitudinalbackpen=backpen, light light=currentlight, string name="", render render=defaultrender, projection P=currentprojection) { if(is3D()) { pen thin=thin(); void drawskeleton(frame f, transform3 t, projection P) { skeleton s=r.skeleton(m,n,inverse(t)*P); if(frontpen != nullpen) { draw(f,t*s.transverse.back,thin+defaultbackpen+backpen,light); draw(f,t*s.transverse.front,thin+frontpen,light); } if(longitudinalpen != nullpen) { draw(f,t*s.longitudinal.back,thin+defaultbackpen+longitudinalbackpen, light); draw(f,t*s.longitudinal.front,thin+longitudinalpen,light); } } bool group=name != "" || render.defaultnames; if(group) begingroup3(pic,name == "" ? "skeleton" : name,render); pic.add(new void(frame f, transform3 t, picture pic, projection P) { drawskeleton(f,t,P); if(pic != null) pic.addBox(min(f,P),max(f,P),min(frontpen),max(frontpen)); }); frame f; drawskeleton(f,identity4,P); pic.addBox(min3(f),max3(f)); if(group) endgroup3(pic); } else { skeleton s=r.skeleton(m,n,P); if(frontpen != nullpen) { draw(pic,s.transverse.back,defaultbackpen+backpen,light); draw(pic,s.transverse.front,frontpen,light); } if(longitudinalpen != nullpen) { draw(pic,s.longitudinal.back,defaultbackpen+longitudinalbackpen, light); draw(pic,s.longitudinal.front,longitudinalpen,light); } } } revolution operator * (transform3 t, revolution r) { triple trc=t*r.c; return revolution(trc,t*r.g,t*(r.c+r.axis)-trc,r.angle1,r.angle2); } // Return a right circular cylinder of height h in the direction of axis // based on a circle centered at c with radius r. revolution cylinder(triple c=O, real r, real h, triple axis=Z) { triple C=c+r*perp(axis); axis=h*unit(axis); return revolution(c,C--C+axis,axis); } // Return a right circular cone of height h in the direction of axis // based on a circle centered at c with radius r. The parameter n // controls the accuracy near the degenerate point at the apex. revolution cone(triple c=O, real r, real h, triple axis=Z, int n=nslice) { axis=unit(axis); return revolution(c,approach(c+r*perp(axis)--c+h*axis,n),axis); } // Return an approximate sphere of radius r centered at c obtained by rotating // an (n+1)-point approximation to a half circle about the Z axis. // Note: unitsphere provides a smoother and more efficient surface. revolution sphere(triple c=O, real r, int n=nslice) { return revolution(c,Arc(c,r,180,0,0,0,Y,n),Z); } asymptote-2.37/base/stats.asy000066400000000000000000000162131265434602500162720ustar00rootroot00000000000000private import graph; real legendmarkersize=2mm; real mean(real A[]) { return sum(A)/A.length; } // unbiased estimate real variance(real A[]) { return sum((A-mean(A))^2)/(A.length-1); } real variancebiased(real A[]) { return sum((A-mean(A))^2)/A.length; } // unbiased estimate real stdev(real A[]) { return sqrt(variance(A)); } real rms(real A[]) { return sqrt(sum(A^2)/A.length); } real skewness(real A[]) { real[] diff=A-mean(A); return sum(diff^3)/sqrt(sum(diff^2)^3/A.length); } real kurtosis(real A[]) { real[] diff=A-mean(A); return sum(diff^4)/sum(diff^2)^2*A.length; } real kurtosisexcess(real A[]) { return kurtosis(A)-3; } real Gaussian(real x, real sigma) { static real sqrt2pi=sqrt(2pi); return exp(-0.5*(x/sigma)^2)/(sigma*sqrt2pi); } real Gaussian(real x) { static real invsqrt2pi=1/sqrt(2pi); return exp(-0.5*x^2)*invsqrt2pi; } // Return frequency count of data in [bins[i],bins[i+1]) for i=0,...,n-1. int[] frequency(real[] data, real[] bins) { int n=bins.length-1; int[] freq=new int[n]; for(int i=0; i < n; ++i) freq[i]=sum(bins[i] <= data & data < bins[i+1]); return freq; } // Return frequency count in n uniform bins from a to b // (faster than the above more general algorithm). int[] frequency(real[] data, real a, real b, int n) { int[] freq=sequence(new int(int x) {return 0;},n); real h=n/(b-a); for(int i=0; i < data.length; ++i) { int I=Floor((data[i]-a)*h); if(I >= 0 && I < n) ++freq[I]; } return freq; } // Return frequency count in [xbins[i],xbins[i+1]) and [ybins[j],ybins[j+1]). int[][] frequency(real[] x, real[] y, real[] xbins, real[] ybins) { int n=xbins.length-1; int m=ybins.length-1; int[][] freq=new int[n][m]; bool[][] inybin=new bool[m][y.length]; for(int j=0; j < m; ++j) inybin[j]=ybins[j] <= y & y < ybins[j+1]; for(int i=0; i < n; ++i) { bool[] inxbini=xbins[i] <= x & x < xbins[i+1]; int[] freqi=freq[i]; for(int j=0; j < m; ++j) freqi[j]=sum(inxbini & inybin[j]); } return freq; } // Return frequency count in nx by ny uniform bins in box(a,b). int[][] frequency(real[] x, real[] y, pair a, pair b, int nx, int ny=nx) { int[][] freq=new int[nx][]; for(int i=0; i < nx; ++i) freq[i]=sequence(new int(int x) {return 0;},ny); real hx=nx/(b.x-a.x); real hy=ny/(b.y-a.y); real ax=a.x; real ay=a.y; for(int i=0; i < x.length; ++i) { int I=Floor((x[i]-ax)*hx); int J=Floor((y[i]-ay)*hy); if(I >= 0 && I <= nx && J >= 0 && J <= ny) ++freq[I][J]; } return freq; } int[][] frequency(pair[] z, pair a, pair b, int nx, int ny=nx) { int[][] freq=new int[nx][]; for(int i=0; i < nx; ++i) freq[i]=sequence(new int(int x) {return 0;},ny); real hx=nx/(b.x-a.x); real hy=ny/(b.y-a.y); real ax=a.x; real ay=a.y; for(int i=0; i < z.length; ++i) { int I=Floor((z[i].x-ax)*hx); int J=Floor((z[i].y-ay)*hy); if(I >= 0 && I < nx && J >= 0 && J < ny) ++freq[I][J]; } return freq; } path halfbox(pair a, pair b) { return a--(a.x,b.y)--b; } path topbox(pair a, pair b) { return a--(a.x,b.y)--b--(b.x,a.y); } // Draw a histogram for bin boundaries bin[n+1] of frequency data in count[n]. void histogram(picture pic=currentpicture, real[] bins, real[] count, real low=-infinity, pen fillpen=nullpen, pen drawpen=nullpen, bool bars=false, Label legend="", real markersize=legendmarkersize) { if((fillpen == nullpen || bars == true) && drawpen == nullpen) drawpen=currentpen; bool[] valid=count > 0; real m=min(valid ? count : null); real M=max(valid ? count : null); bounds my=autoscale(pic.scale.y.scale.T(m),pic.scale.y.T(M), pic.scale.y.scale); if(low == -infinity) low=pic.scale.y.scale.Tinv(my.min); real last=low; int n=count.length; begingroup(pic); for(int i=0; i < n; ++i) { if(valid[i]) { real c=count[i]; pair b=Scale(pic,(bins[i+1],c)); pair a=Scale(pic,(bins[i],low)); if(fillpen != nullpen) { fill(pic,box(a,b),fillpen); if(!bars) draw(pic,b--(b.x,a.y),fillpen); } if(!bars) draw(pic,halfbox(Scale(pic,(bins[i],last)),b),drawpen); else draw(pic,topbox(a,b),drawpen); last=c; } else { if(!bars && last != low) { draw(pic,Scale(pic,(bins[i],last))--Scale(pic,(bins[i],low)),drawpen); last=low; } } } if(!bars && last != low) draw(pic,Scale(pic,(bins[n],last))--Scale(pic,(bins[n],low)),drawpen); endgroup(pic); if(legend.s != "") { marker m=marker(scale(markersize)*shift((-0.5,-0.5))*unitsquare, drawpen,fillpen == nullpen ? Draw : (drawpen == nullpen ? Fill(fillpen) : FillDraw(fillpen))); legend.p(drawpen); pic.legend.push(Legend(legend.s,legend.p,invisible,m.f)); } } // Draw a histogram for data in n uniform bins between a and b // (optionally normalized). void histogram(picture pic=currentpicture, real[] data, real a, real b, int n, bool normalize=false, real low=-infinity, pen fillpen=nullpen, pen drawpen=nullpen, bool bars=false, Label legend="", real markersize=legendmarkersize) { real dx=(b-a)/n; real[] freq=frequency(data,a,b,n); if(normalize) freq /= dx*sum(freq); histogram(pic,a+sequence(n+1)*dx,freq,low,fillpen,drawpen,bars,legend, markersize); } // Method of Shimazaki and Shinomoto for selecting the optimal number of bins. // Shimazaki H. and Shinomoto S., A method for selecting the bin size of a // time histogram, Neural Computation (2007), Vol. 19(6), 1503-1527. // cf. http://www.ton.scphys.kyoto-u.ac.jp/~hideaki/res/histogram.html int bins(real[] data, int max=100) { real m=min(data); real M=max(data)*(1+epsilon); real n=data.length; int bins=1; real minC=2n-n^2; // Cost function for N=1. for(int N=2; N <= max; ++N) { real C=N*(2n-sum(frequency(data,m,M,N)^2)); if(C < minC) { minC=C; bins=N; } } return bins; } // return a pair of central Gaussian random numbers with unit variance pair Gaussrandpair() { real r2,v1,v2; do { v1=2.0*unitrand()-1.0; v2=2.0*unitrand()-1.0; r2=v1*v1+v2*v2; } while(r2 >= 1.0 || r2 == 0.0); return (v1,v2)*sqrt(-log(r2)/r2); } // return a central Gaussian random number with unit variance real Gaussrand() { static real sqrt2=sqrt(2.0); static pair z; static bool cached=true; cached=!cached; if(cached) return sqrt2*z.y; z=Gaussrandpair(); return sqrt2*z.x; } struct linefit { real m,b; // slope, intercept real dm,db; // standard error in slope, intercept real r; // correlation coefficient real fit(real x) { return m*x+b; } } // Do a least-squares fit of data in real arrays x and y to the line y=m*x+b linefit leastsquares(real[] x, real[] y) { linefit L; int n=x.length; if(n == 1) abort("Least squares fit requires at least 2 data points"); real sx=sum(x); real sy=sum(y); real sxx=n*sum(x^2)-sx^2; real sxy=n*sum(x*y)-sx*sy; L.m=sxy/sxx; L.b=(sy-L.m*sx)/n; if(n > 2) { real syy=n*sum(y^2)-sy^2; if(sxx == 0 || syy == 0) return L; L.r=sxy/sqrt(sxx*syy); real arg=syy-sxy^2/sxx; if(arg <= 0) return L; real s=sqrt(arg/(n-2)); L.dm=s*sqrt(1/sxx); L.db=s*sqrt(1+sx^2/sxx)/n; } return L; } asymptote-2.37/base/syzygy.asy000066400000000000000000000546731265434602500165260ustar00rootroot00000000000000/***** syzygy.asy {{{1 * Andy Hammerlindl 2006/12/02 * * Automates the drawing of braids, relations, and syzygies, along with the * corresponding equations. * * See * http://katlas.math.toronto.edu/drorbn/index.php?title=06-1350/Syzygies_in_Asymptote * For more information. *****/ struct Component { // {{{1 // The number of strings coming in or out of the component. int in; int out; // Which 'out' string each 'in' string is connected to. For deriving // equations. int[] connections; string symbol; // For pullback notation. string lsym; // For linear equations. string codename; // For Mathematica code. guide[] draw(picture pic, guide[] ins); } // Utility functions {{{1 pair[] endpoints(guide[] a) { pair[] z; for (int i=0; i M.x) M=(z[i].x,M.y); if (z[i].y > M.y) M=(M.x,z[i].y); } return M; } // Component Definitions {{{1 real hwratio=1.4; real gapfactor=6; Component bp=new Component; bp.in=2; bp.out=2; bp.connections=new int[] {1,0}; bp.symbol="B^+"; bp.lsym="b^+"; bp.codename="bp"; bp.draw=new guide[] (picture pic, guide[] ins) { pair[] z=endpoints(ins); pair m=min(z), M=max(z); real w=M.x-m.x, h=hwratio*w; pair centre=(0.5(m.x+M.x),M.y+h/2); /* return new guide[] {ins[1]..centre{NW}..z[0]+h*N, ins[0]..centre{NE}..z[1]+h*N}; */ real offset=gapfactor*linewidth(currentpen); draw(pic, ins[1]..(centre-offset*NW){NW}); return new guide[] {(centre+offset*NW){NW}..z[0]+h*N, ins[0]..centre{NE}..z[1]+h*N}; }; Component bm=new Component; bm.in=2; bm.out=2; bm.connections=new int[] {1,0}; bm.symbol="B^-"; bm.lsym="b^-"; bm.codename="bm"; bm.draw=new guide[] (picture pic, guide[] ins) { pair[] z=endpoints(ins); pair m=min(z), M=max(z); real w=M.x-m.x, h=hwratio*w; pair centre=(0.5(m.x+M.x),M.y+h/2); /* return new guide[] {ins[1]..centre{NW}..z[0]+h*N, ins[0]..centre{NE}..z[1]+h*N}; */ real offset=gapfactor*linewidth(currentpen); draw(pic, ins[0]..(centre-offset*NE){NE}); return new guide[] {ins[1]..centre{NW}..z[0]+h*N, (centre+offset*NE){NE}..z[1]+h*N}; }; Component phi=new Component; phi.in=2; phi.out=1; phi.connections=new int[] {0,0}; phi.symbol="\Phi"; phi.lsym="\phi"; phi.codename="phi"; phi.draw=new guide[] (picture pic, guide[] ins) { pair[] z=endpoints(ins); pair m=min(z), M=max(z); real w=M.x-m.x, h=hwratio*w; pair centre=(0.5(m.x+M.x),M.y+h/2); //real offset=4*linewidth(currentpen); draw(pic, ins[0]..centre{NE}); draw(pic, ins[1]..centre{NW}); draw(pic, centre,linewidth(5*linewidth(currentpen))); dot(pic, centre); return new guide[] {centre..centre+0.5h*N}; }; Component wye=new Component; wye.in=1; wye.out=2; wye.connections=null; // TODO: Fix this! wye.symbol="Y"; wye.lsym="y"; wye.codename="wye"; wye.draw=new guide[] (picture pic, guide[] ins) { pair z=endpoint(ins[0]); real w=10, h=hwratio*w; // The 10 is a guess here, and may produce badness. pair centre=(z.x,z.y+h/2); draw(pic, ins[0]..centre); draw(pic, centre,linewidth(5*linewidth(currentpen))); return new guide[] {centre{NW}..centre+(-0.5w,0.5h), centre{NE}..centre+(0.5w,0.5h)}; }; struct Braid { // {{{1 // Members {{{2 // Number of lines initially. int n; struct Placement { Component c; int place; Placement copy() { Placement p=new Placement; p.c=this.c; p.place=this.place; return p; } } Placement[] places; void add(Component c, int place) { Placement p=new Placement; p.c=c; p.place=place; places.push(p); } void add(Braid sub, int place) { for (int i=0; i= minheight ? ins[i] : ins[i]..(z[i].x,minheight)); } } void draw(picture pic, guide[] ins, real minheight=0) { int steps=places.length; guide[] nodes=ins; for (int i=0; ij) return swap(j,i); else { assert(j==i+1); assert(swapable(places[i],places[j])); Placement p=places[i].copy(); Placement q=places[j].copy(); /*write("swap:"); write("p originally at " + (string)p.place); write("q originally at " + (string)q.place); write("p.c.in: " + (string)p.c.in + " p.c.out: " + (string)p.c.out); write("q.c.in: " + (string)q.c.in + " q.c.out: " + (string)q.c.out);*/ if (q.place + q.c.in <= p.place) // q is left of p - adjust for q renumbering strings. p.place+=q.c.out-q.c.in; else if (p.place + p.c.out <= q.place) // q is right of p - adjust for p renumbering strings. q.place+=p.c.in-p.c.out; else // q is directly on top of p assert(false, "swapable"); /*write("q now at " + (string)q.place); write("p now at " + (string)p.place);*/ Braid b=this.copy(); b.places[i]=q; b.places[j]=p; return b; } } // Tests if the component at index 'start' can be moved to index 'end' // without interfering with other components. bool moveable(int start, int end) { assert(start= sub.places.length) return true; // The next component to match. Placement p=sub.places[acc.length]; // Start looking immediately after the last match. for (int step=acc[acc.length-1]+1; step= sub.places.length) return true; // The next component to match. Placement p=sub.places[acc.length]; // Start looking immediately after the last match. for (int step=acc[acc.length-1]+1; step place && q.place < place + size) { // It's in the window, so it must match the next component in the // subbraid. if (p.c==q.c && p.place+place==q.place) { // A match - go on to the next component. acc.push(step); return tryMatch(sub, place, size, acc); // TODO: Adjust place/size. } else return false; } // TODO: Adjust place and size. } // We've run out of components to match. return false; } // This attempts to find a subbraid within the braid. It allows other // components to be interspersed with the components of the subbraid so long // as they don't occur on the same string as the ones the subbraid lies on. // Returns null on failure. int[] match(Braid sub, int place) { for (int i=0; i<=this.places.length-sub.places.length; ++i) { // Find where the first component of the subbraid matches and try to // match the rest of the braid starting from there. if (matchComponent(sub, 0, place, i)) { int[] result; result.push(i); if (tryMatch(sub,place,sub.n,result)) return result; } } return null; } // Equations {{{2 // Returns the string that 'place' moves to when going through the section // with Placement p. static int advancePast(Placement p, int place) { // If it's to the left of the component, it is unaffected. return place=0 && place=0 && step0) s+=" "; s+=stepToFormula(step); } return s; } } string windowToLinear(int step, int w_place, int w_size) { int[] a=pullbackWindow(step, w_place, w_size); string s="("; for (int arg=1; arg<=w_size+1; ++arg) { if (arg>1) s+=","; bool first=true; for (int var=0; var1) s+=", "; bool first=true; for (int var=0; var1) s+=","; bool first=true; for (int var=0; var0) s+= subtract ? " - " : " + "; s+=stepToLinear(step); } return s; } } string toCode(bool subtract=false) { if (places.length==0) return subtract ? "0" : ""; // or "1" ? else { string s = subtract ? " - " : ""; for (int step=0; step0) s+= subtract ? " - " : " + "; s+=stepToCode(step); } return s; } } } struct Relation { // {{{1 Braid lhs, rhs; string lsym, codename; bool inverted=false; string toFormula() { return lhs.toFormula() + " = " + rhs.toFormula(); } string linearName() { assert(lhs.n==rhs.n); assert(lsym!=""); string s=(inverted ? "-" : "") + lsym+"("; for (int i=1; i<=lhs.n+1; ++i) { if (i>1) s+=","; s+="x_"+(string)i; } return s+")"; } string fullCodeName() { assert(lhs.n==rhs.n); assert(codename!=""); string s=(inverted ? "minus" : "") + codename+"["; for (int i=1; i<=lhs.n+1; ++i) { if (i>1) s+=", "; s+="x"+(string)i+"_"; } return s+"]"; } string toLinear() { return linearName() + " = " + lhs.toLinear() + rhs.toLinear(true); } string toCode() { return fullCodeName() + " :> " + lhs.toCode() + rhs.toCode(true); } void draw(picture pic=currentpicture) { picture left; lhs.draw(left); frame l=left.fit(); picture right; rhs.draw(right); frame r=right.fit(); real xpad=30; add(pic, l); label(pic, "=", (max(l).x + 0.5xpad, 0.25(max(l).y+max(r).y))); add(pic, r, (max(l).x+xpad,0)); } } Relation operator- (Relation r) { Relation opposite; opposite.lhs=r.rhs; opposite.rhs=r.lhs; opposite.lsym=r.lsym; opposite.codename=r.codename; opposite.inverted=!r.inverted; return opposite; } Braid apply(Relation r, Braid b, int step, int place) { bool valid=b.exactMatch(r.lhs,place,step); if (valid) { Braid result=new Braid; result.n=b.n; for (int i=0; i M.x) M=(z.x,M.y); if (z.y > M.y) M=(M.x,z.y); } picture pic; real xpad=2.0, ypad=1.3; void place(int index, real row, real column) { pair z=((M.x*xpad)*column,(M.y*ypad)*row); add(pic, cards[index], z); if (number) { label(pic,(string)index, z+(0.5M.x,0), S); } } // Handle small collections. if (n<=4) { for (int i=0; i1) s+=","; s+="x_"+(string)i; } return s+")"; } string fullCodeName() { assert(codename!=""); string s=codename+"["; for (int i=1; i<=initial.n+1; ++i) { if (i>1) s+=", "; s+="x"+(string)i+"_"; } return s+"]"; } string toLinear() { string s=linearName()+" = "; Braid b=initial; bool first=true; for (int i=0; i "; Braid b=initial; bool first=true; for (int i=0; i sqrtEpsilon) return unit(u); u=cross(v,Z); return (abs(u) > sqrtEpsilon) ? unit(u) : X; } // Return the transformation corresponding to moving the camera from the target // (looking in the negative z direction) to the point 'eye' (looking at target), // orienting the camera so that direction 'up' points upwards. // Since, in actuality, we are transforming the points instead of the camera, // we calculate the inverse matrix. // Based on the gluLookAt implementation in the OpenGL manual. transform3 look(triple eye, triple up=Z, triple target=O) { triple f=unit(target-eye); if(f == O) f=-Z; // The eye is already at the origin: look down. triple s=cross(f,up); // If the eye is pointing either directly up or down, there is no // preferred "up" direction. Pick one arbitrarily. s=s != O ? unit(s) : perp(f); triple u=cross(s,f); transform3 M={{ s.x, s.y, s.z, 0}, { u.x, u.y, u.z, 0}, {-f.x, -f.y, -f.z, 0}, { 0, 0, 0, 1}}; return M*shift(-eye); } // Return a matrix to do perspective distortion based on a triple v. transform3 distort(triple v) { transform3 t=identity(4); real d=length(v); if(d == 0) return t; t[3][2]=-1/d; t[3][3]=0; return t; } projection operator * (transform3 t, projection P) { projection P=P.copy(); if(!P.absolute) { P.camera=t*P.camera; triple target=P.target; P.target=t*P.target; if(P.infinity) P.normal=t*(target+P.normal)-P.target; else P.normal=P.vector(); P.calculate(); } return P; } // With this, save() and restore() in plain also save and restore the // currentprojection. addSaveFunction(new restoreThunk() { projection P=currentprojection.copy(); return new void() { currentprojection=P; }; }); pair project(triple v, projection P=currentprojection) { return project(v,P.t); } pair dir(triple v, triple dir, projection P) { return unit(project(v+0.5dir,P)-project(v-0.5*dir,P)); } // Uses the homogenous coordinate to perform perspective distortion. // When combined with a projection to the XY plane, this effectively maps // points in three space to a plane through target and // perpendicular to the vector camera-target. projection perspective(triple camera, triple up=Z, triple target=O, real zoom=1, real angle=0, pair viewportshift=0, bool showtarget=true, bool autoadjust=true, bool center=autoadjust) { if(camera == target) abort("camera cannot be at target"); return projection(camera,up,target,zoom,angle,viewportshift, showtarget,autoadjust,center, new transformation(triple camera, triple up, triple target) {return transformation(look(camera,up,target), distort(camera-target));}); } projection perspective(real x, real y, real z, triple up=Z, triple target=O, real zoom=1, real angle=0, pair viewportshift=0, bool showtarget=true, bool autoadjust=true, bool center=autoadjust) { return perspective((x,y,z),up,target,zoom,angle,viewportshift,showtarget, autoadjust,center); } projection orthographic(triple camera, triple up=Z, triple target=O, real zoom=1, pair viewportshift=0, bool showtarget=true, bool center=false) { return projection(camera,up,target,zoom,viewportshift,showtarget, center=center,new transformation(triple camera, triple up, triple target) { return transformation(look(camera,up,target));}); } projection orthographic(real x, real y, real z, triple up=Z, triple target=O, real zoom=1, pair viewportshift=0, bool showtarget=true, bool center=false) { return orthographic((x,y,z),up,target,zoom,viewportshift,showtarget, center=center); } // Compute camera position with x axis below the horizontal at angle alpha, // y axis below the horizontal at angle beta, and z axis up. triple camera(real alpha, real beta) { real denom=Tan(alpha+beta); real Tanalpha=Tan(alpha); real Tanbeta=Tan(beta); return (sqrt(Tanalpha/denom),sqrt(Tanbeta/denom),sqrt(Tanalpha*Tanbeta)); } projection oblique(real angle=45) { transform3 t=identity(4); real c2=Cos(angle)^2; real s2=1-c2; t[0][2]=-c2; t[1][2]=-s2; t[2][2]=1; t[2][3]=-1; return projection((c2,s2,1),up=Y,normal=(0,0,1), new transformation(triple,triple,triple) { return transformation(t);}); } projection obliqueZ(real angle=45) {return oblique(angle);} projection obliqueX(real angle=45) { transform3 t=identity(4); real c2=Cos(angle)^2; real s2=1-c2; t[0][0]=-c2; t[1][0]=-s2; t[1][1]=0; t[0][1]=1; t[1][2]=1; t[2][2]=0; t[2][0]=1; t[2][3]=-1; return projection((1,c2,s2),normal=(1,0,0), new transformation(triple,triple,triple) { return transformation(t);}); } projection obliqueY(real angle=45) { transform3 t=identity(4); real c2=Cos(angle)^2; real s2=1-c2; t[0][1]=c2; t[1][1]=s2; t[1][2]=1; t[2][1]=-1; t[2][2]=0; t[2][3]=-1; return projection((c2,-1,s2),normal=(0,-1,0), new transformation(triple,triple,triple) { return transformation(t);}); } projection oblique=oblique(); projection obliqueX=obliqueX(), obliqueY=obliqueY(), obliqueZ=obliqueZ(); projection LeftView=orthographic(-X,showtarget=true); projection RightView=orthographic(X,showtarget=true); projection FrontView=orthographic(-Y,showtarget=true); projection BackView=orthographic(Y,showtarget=true); projection BottomView=orthographic(-Z,up=-Y,showtarget=true); projection TopView=orthographic(Z,up=Y,showtarget=true); currentprojection=perspective(5,4,2); projection projection() { projection P; real[] a=_projection(); if(a.length == 0 || a[10] == 0.0) return currentprojection; int k=0; return a[0] == 1 ? orthographic((a[++k],a[++k],a[++k]),(a[++k],a[++k],a[++k]), (a[++k],a[++k],a[++k]),a[++k],(a[k += 2],a[++k])) : perspective((a[++k],a[++k],a[++k]),(a[++k],a[++k],a[++k]), (a[++k],a[++k],a[++k]),a[++k],a[++k],(a[++k],a[++k])); } // Map pair z to a triple by inverting the projection P onto the // plane perpendicular to normal and passing through point. triple invert(pair z, triple normal, triple point, projection P=currentprojection) { transform3 t=P.t; real[][] A={{t[0][0]-z.x*t[3][0],t[0][1]-z.x*t[3][1],t[0][2]-z.x*t[3][2]}, {t[1][0]-z.y*t[3][0],t[1][1]-z.y*t[3][1],t[1][2]-z.y*t[3][2]}, {normal.x,normal.y,normal.z}}; real[] b={z.x*t[3][3]-t[0][3],z.y*t[3][3]-t[1][3],dot(normal,point)}; real[] x=solve(A,b,warn=false); return x.length > 0 ? (x[0],x[1],x[2]) : P.camera; } // Map pair to a triple on the projection plane. triple invert(pair z, projection P=currentprojection) { return invert(z,P.normal,P.target,P); } // Map pair dir to a triple direction at point v on the projection plane. triple invert(pair dir, triple v, projection P=currentprojection) { return invert(project(v,P)+dir,P.normal,v,P)-v; } pair xypart(triple v) { return (v.x,v.y); } struct control { triple post,pre; bool active=false; bool straight=true; void operator init(triple post, triple pre, bool straight=false) { this.post=post; this.pre=pre; active=true; this.straight=straight; } } control nocontrol; control operator * (transform3 t, control c) { control C; C.post=t*c.post; C.pre=t*c.pre; C.active=c.active; C.straight=c.straight; return C; } void write(file file, control c) { write(file,".. controls "); write(file,c.post); write(file," and "); write(file,c.pre); } struct Tension { real out,in; bool atLeast; bool active; void operator init(real out=1, real in=1, bool atLeast=false, bool active=true) { real check(real val) { if(val < 0.75) abort("tension cannot be less than 3/4"); return val; } this.out=check(out); this.in=check(in); this.atLeast=atLeast; this.active=active; } } Tension operator init() { return Tension(); } Tension noTension; noTension.active=false; void write(file file, Tension t) { write(file,"..tension "); if(t.atLeast) write(file,"atleast "); write(file,t.out); write(file," and "); write(file,t.in); } struct dir { triple dir; real gamma=1; // endpoint curl bool Curl; // curl specified bool active() { return dir != O || Curl; } void init(triple v) { this.dir=v; } void init(real gamma) { if(gamma < 0) abort("curl cannot be less than 0"); this.gamma=gamma; this.Curl=true; } void init(dir d) { dir=d.dir; gamma=d.gamma; Curl=d.Curl; } void default(triple v) { if(!active()) init(v); } void default(dir d) { if(!active()) init(d); } dir copy() { dir d=new dir; d.init(this); return d; } } void write(file file, dir d) { if(d.dir != O) { write(file,"{"); write(file,unit(d.dir)); write(file,"}"); } else if(d.Curl) { write(file,"{curl "); write(file,d.gamma); write(file,"}"); } } dir operator * (transform3 t, dir d) { dir D=d.copy(); D.init(unit(shiftless(t)*d.dir)); return D; } void checkEmpty(int n) { if(n == 0) abort("nullpath3 has no points"); } int adjustedIndex(int i, int n, bool cycles) { checkEmpty(n); if(cycles) return i % n; else if(i < 0) return 0; else if(i >= n) return n-1; else return i; } struct flatguide3 { triple[] nodes; bool[] cyclic; // true if node is really a cycle control[] control; // control points for segment starting at node Tension[] Tension; // Tension parameters for segment starting at node dir[] in,out; // in and out directions for segment starting at node bool cyclic() {int n=cyclic.length; return n > 0 ? cyclic[n-1] : false;} bool precyclic() {int i=find(cyclic); return i >= 0 && i < cyclic.length-1;} int size() { return cyclic() ? nodes.length-1 : nodes.length; } void node(triple v, bool b=false) { nodes.push(v); control.push(nocontrol); Tension.push(noTension); in.push(new dir); out.push(new dir); cyclic.push(b); } void control(triple post, triple pre) { if(control.length > 0) { control c=control(post,pre,false); control[control.length-1]=c; } } void Tension(real out, real in, bool atLeast) { if(Tension.length > 0) Tension[Tension.length-1]=Tension(out,in,atLeast,true); } void in(triple v) { if(in.length > 0) { in[in.length-1].init(v); } } void out(triple v) { if(out.length > 0) { out[out.length-1].init(v); } } void in(real gamma) { if(in.length > 0) { in[in.length-1].init(gamma); } } void out(real gamma) { if(out.length > 0) { out[out.length-1].init(gamma); } } void cycleToken() { if(nodes.length > 0) node(nodes[0],true); } // Return true if outgoing direction at node i is known. bool solved(int i) { return out[i].active() || control[i].active; } } void write(file file, string s="", explicit flatguide3 x, suffix suffix=none) { write(file,s); if(x.size() == 0) write(file,""); else for(int i=0; i < x.nodes.length; ++i) { if(i > 0) write(file,endl); if(x.cyclic[i]) write(file,"cycle"); else write(file,x.nodes[i]); if(i < x.nodes.length-1) { // Explicit control points trump other specifiers if(x.control[i].active) write(file,x.control[i]); else { write(file,x.out[i]); if(x.Tension[i].active) write(file,x.Tension[i]); } write(file,".."); if(!x.control[i].active) write(file,x.in[i]); } } write(file,suffix); } void write(string s="", flatguide3 x, suffix suffix=endl) { write(stdout,s,x,suffix); } // A guide3 is most easily represented as something that modifies a flatguide3. typedef void guide3(flatguide3); restricted void nullpath3(flatguide3) {}; guide3 operator init() {return nullpath3;} guide3 operator cast(triple v) { return new void(flatguide3 f) { f.node(v); }; } guide3 operator cast(cycleToken) { return new void(flatguide3 f) { f.cycleToken(); }; } guide3 operator controls(triple post, triple pre) { return new void(flatguide3 f) { f.control(post,pre); }; }; guide3 operator controls(triple v) { return operator controls(v,v); } guide3 operator cast(tensionSpecifier t) { return new void(flatguide3 f) { f.Tension(t.out, t.in, t.atLeast); }; } guide3 operator cast(curlSpecifier spec) { return new void(flatguide3 f) { if(spec.side == JOIN_OUT) f.out(spec.value); else if(spec.side == JOIN_IN) f.in(spec.value); else abort("invalid curl specifier"); }; } guide3 operator spec(triple v, int side) { return new void(flatguide3 f) { if(side == JOIN_OUT) f.out(v); else if(side == JOIN_IN) f.in(v); else abort("invalid direction specifier"); }; } guide3 operator -- (... guide3[] g) { return new void(flatguide3 f) { if(g.length > 0) { for(int i=0; i < g.length-1; ++i) { g[i](f); f.out(1); f.in(1); } g[g.length-1](f); } }; } guide3 operator .. (... guide3[] g) { return new void(flatguide3 f) { for(int i=0; i < g.length; ++i) g[i](f); }; } typedef guide3 interpolate3(... guide3[]); interpolate3 join3(tensionSpecifier t) { return new guide3(... guide3[] a) { if(a.length == 0) return nullpath3; guide3 g=a[0]; for(int i=1; i < a.length; ++i) g=g..t..a[i]; return g; }; } interpolate3 operator ::=join3(operator tension(1,true)); interpolate3 operator ---=join3(operator tension(infinity,true)); flatguide3 operator cast(guide3 g) { flatguide3 f; g(f); return f; } flatguide3[] operator cast(guide3[] g) { flatguide3[] p=new flatguide3[g.length]; for(int i=0; i < g.length; ++i) { flatguide3 f; g[i](f); p[i]=f; } return p; } // A version of asin that tolerates numerical imprecision real asin1(real x) { return asin(min(max(x,-1),1)); } // A version of acos that tolerates numerical imprecision real acos1(real x) { return acos(min(max(x,-1),1)); } struct Controls { triple c0,c1; // 3D extension of John Hobby's control point formula // (cf. The MetaFont Book, page 131), // as described in John C. Bowman and A. Hammerlindl, // TUGBOAT: The Communications of the TeX Users Group 29:2 (2008). void operator init(triple v0, triple v1, triple d0, triple d1, real tout, real tin, bool atLeast) { triple v=v1-v0; triple u=unit(v); real L=length(v); d0=unit(d0); d1=unit(d1); real theta=acos1(dot(d0,u)); real phi=acos1(dot(d1,u)); if(dot(cross(d0,v),cross(v,d1)) < 0) phi=-phi; c0=v0+d0*L*relativedistance(theta,phi,tout,atLeast); c1=v1-d1*L*relativedistance(phi,theta,tin,atLeast); } } private triple cross(triple d0, triple d1, triple reference) { triple normal=cross(d0,d1); return normal == O ? reference : normal; } private triple dir(real theta, triple d0, triple d1, triple reference) { triple normal=cross(d0,d1,reference); if(normal == O) return d1; return rotate(degrees(theta),dot(normal,reference) >= 0 ? normal : -normal)* d1; } private real angle(triple d0, triple d1, triple reference) { real theta=acos1(dot(unit(d0),unit(d1))); return dot(cross(d0,d1,reference),reference) >= 0 ? theta : -theta; } // 3D extension of John Hobby's angle formula (The MetaFont Book, page 131). // Notational differences: here psi[i] is the turning angle at z[i+1], // beta[i] is the tension for segment i, and in[i] is the incoming // direction for segment i (where segment i begins at node i). real[] theta(triple[] v, real[] alpha, real[] beta, triple dir0, triple dirn, real g0, real gn, triple reference) { real[] a,b,c,f,l,psi; int n=alpha.length; bool cyclic=v.cyclic; for(int i=0; i < n; ++i) l[i]=1/length(v[i+1]-v[i]); int i0,in; if(cyclic) {i0=0; in=n;} else {i0=1; in=n-1;} for(int i=0; i < in; ++i) psi[i]=angle(v[i+1]-v[i],v[i+2]-v[i+1],reference); if(cyclic) { l.cyclic=true; psi.cyclic=true; } else { psi[n-1]=0; if(dir0 == O) { real a0=alpha[0]; real b0=beta[0]; real chi=g0*(b0/a0)^2; a[0]=0; b[0]=3a0-a0/b0+chi; real C=chi*(3a0-1)+a0/b0; c[0]=C; f[0]=-C*psi[0]; } else { a[0]=c[0]=0; b[0]=1; f[0]=angle(v[1]-v[0],dir0,reference); } if(dirn == O) { real an=alpha[n-1]; real bn=beta[n-1]; real chi=gn*(an/bn)^2; a[n]=chi*(3bn-1)+bn/an; b[n]=3bn-bn/an+chi; c[n]=f[n]=0; } else { a[n]=c[n]=0; b[n]=1; f[n]=angle(v[n]-v[n-1],dirn,reference); } } for(int i=i0; i < n; ++i) { real in=beta[i-1]^2*l[i-1]; real A=in/alpha[i-1]; a[i]=A; real B=3*in-A; real out=alpha[i]^2*l[i]; real C=out/beta[i]; b[i]=B+3*out-C; c[i]=C; f[i]=-B*psi[i-1]-C*psi[i]; } return tridiagonal(a,b,c,f); } triple reference(triple[] v, int n, triple d0, triple d1) { triple[] V=sequence(new triple(int i) { return cross(v[i+1]-v[i],v[i+2]-v[i+1]); },n-1); if(n > 0) { V.push(cross(d0,v[1]-v[0])); V.push(cross(v[n]-v[n-1],d1)); } triple max=V[0]; real M=abs(max); for(int i=1; i < V.length; ++i) { triple vi=V[i]; real a=abs(vi); if(a > M) { M=a; max=vi; } } triple reference; for(int i=0; i < V.length; ++i) { triple u=unit(V[i]); reference += dot(u,max) < 0 ? -u : u; } return reference; } // Fill in missing directions for n cyclic nodes. void aim(flatguide3 g, int N) { bool cyclic=true; int start=0, end=0; // If the cycle contains one or more direction specifiers, break the loop. for(int k=0; k < N; ++k) if(g.solved(k)) {cyclic=false; end=k; break;} for(int k=N-1; k >= 0; --k) if(g.solved(k)) {cyclic=false; start=k; break;} while(start < N && g.control[start].active) ++start; int n=N-(start-end); if(n <= 1 || (cyclic && n <= 2)) return; triple[] v=new triple[cyclic ? n : n+1]; real[] alpha=new real[n]; real[] beta=new real[n]; for(int k=0; k < n; ++k) { int K=(start+k) % N; v[k]=g.nodes[K]; alpha[k]=g.Tension[K].out; beta[k]=g.Tension[K].in; } if(cyclic) { v.cyclic=true; alpha.cyclic=true; beta.cyclic=true; } else v[n]=g.nodes[(start+n) % N]; int final=(end-1) % N; triple d0=g.out[start].dir; triple d1=g.in[final].dir; triple reference=reference(v,n,d0,d1); real[] theta=theta(v,alpha,beta,d0,d1,g.out[start].gamma,g.in[final].gamma, reference); v.cyclic=true; theta.cyclic=true; for(int k=1; k < (cyclic ? n+1 : n); ++k) { triple w=dir(theta[k],v[k]-v[k-1],v[k+1]-v[k],reference); g.in[(start+k-1) % N].init(w); g.out[(start+k) % N].init(w); } if(g.out[start].dir == O) g.out[start].init(dir(theta[0],v[0]-g.nodes[(start-1) % N],v[1]-v[0], reference)); if(g.in[final].dir == O) g.in[final].init(dir(theta[n],v[n-1]-v[n-2],v[n]-v[n-1],reference)); } // Fill in missing directions for the sequence of nodes i...n. void aim(flatguide3 g, int i, int n) { int j=n-i; if(j > 1 || g.out[i].dir != O || g.in[i].dir != O) { triple[] v=new triple[j+1]; real[] alpha=new real[j]; real[] beta=new real[j]; for(int k=0; k < j; ++k) { v[k]=g.nodes[i+k]; alpha[k]=g.Tension[i+k].out; beta[k]=g.Tension[i+k].in; } v[j]=g.nodes[n]; triple d0=g.out[i].dir; triple d1=g.in[n-1].dir; triple reference=reference(v,j,d0,d1); real[] theta=theta(v,alpha,beta,d0,d1,g.out[i].gamma,g.in[n-1].gamma, reference); for(int k=1; k < j; ++k) { triple w=dir(theta[k],v[k]-v[k-1],v[k+1]-v[k],reference); g.in[i+k-1].init(w); g.out[i+k].init(w); } if(g.out[i].dir == O) { triple w=dir(theta[0],g.in[i].dir,v[1]-v[0],reference); if(i > 0) g.in[i-1].init(w); g.out[i].init(w); } if(g.in[n-1].dir == O) { triple w=dir(theta[j],g.out[n-1].dir,v[j]-v[j-1],reference); g.in[n-1].init(w); g.out[n].init(w); } } } private real Fuzz=10*realEpsilon; triple XYplane(pair z) {return (z.x,z.y,0);} triple YZplane(pair z) {return (0,z.x,z.y);} triple ZXplane(pair z) {return (z.y,0,z.x);} bool cyclic(guide3 g) {flatguide3 f; g(f); return f.cyclic();} int size(guide3 g) {flatguide3 f; g(f); return f.size();} int length(guide3 g) {flatguide3 f; g(f); return f.nodes.length-1;} triple dir(path3 p) { return dir(p,length(p)); } triple dir(path3 p, path3 h) { return 0.5*(dir(p)+dir(h)); } // return the point on path3 p at arclength L triple arcpoint(path3 p, real L) { return point(p,arctime(p,L)); } // return the direction on path3 p at arclength L triple arcdir(path3 p, real L) { return dir(p,arctime(p,L)); } // return the time on path3 p at the relative fraction l of its arclength real reltime(path3 p, real l) { return arctime(p,l*arclength(p)); } // return the point on path3 p at the relative fraction l of its arclength triple relpoint(path3 p, real l) { return point(p,reltime(p,l)); } // return the direction of path3 p at the relative fraction l of its arclength triple reldir(path3 p, real l) { return dir(p,reltime(p,l)); } // return the initial point of path3 p triple beginpoint(path3 p) { return point(p,0); } // return the point on path3 p at half of its arclength triple midpoint(path3 p) { return relpoint(p,0.5); } // return the final point of path3 p triple endpoint(path3 p) { return point(p,length(p)); } path3 path3(triple v) { triple[] point={v}; return path3(point,point,point,new bool[] {false},false); } path3 path3(path p, triple plane(pair)=XYplane) { int n=size(p); return path3(sequence(new triple(int i) {return plane(precontrol(p,i));},n), sequence(new triple(int i) {return plane(point(p,i));},n), sequence(new triple(int i) {return plane(postcontrol(p,i));},n), sequence(new bool(int i) {return straight(p,i);},n), cyclic(p)); } path3[] path3(explicit path[] g, triple plane(pair)=XYplane) { return sequence(new path3(int i) {return path3(g[i],plane);},g.length); } path3 invert(path p, triple normal, triple point, projection P=currentprojection) { return path3(p,new triple(pair z) {return invert(z,normal,point,P);}); } path3 invert(path p, triple point, projection P=currentprojection) { return path3(p,new triple(pair z) {return invert(z,P.normal,point,P);}); } path3 invert(path p, projection P=currentprojection) { return path3(p,new triple(pair z) {return invert(z,P.normal,P.target,P);}); } // Construct a path from a path3 by applying P to each control point. path path(path3 p, pair P(triple)=xypart) { int n=length(p); if(n < 0) return nullpath; guide g=P(point(p,0)); if(n == 0) return g; for(int i=1; i < n; ++i) g=straight(p,i-1) ? g--P(point(p,i)) : g..controls P(postcontrol(p,i-1)) and P(precontrol(p,i))..P(point(p,i)); if(straight(p,n-1)) return cyclic(p) ? g--cycle : g--P(point(p,n)); pair post=P(postcontrol(p,n-1)); pair pre=P(precontrol(p,n)); return cyclic(p) ? g..controls post and pre..cycle : g..controls post and pre..P(point(p,n)); } void write(file file, string s="", explicit path3 x, suffix suffix=none) { write(file,s); int n=length(x); if(n < 0) write(""); else { for(int i=0; i < n; ++i) { write(file,point(x,i)); if(i < length(x)) { if(straight(x,i)) write(file,"--"); else { write(file,".. controls "); write(file,postcontrol(x,i)); write(file," and "); write(file,precontrol(x,i+1),newl); write(file," .."); } } } if(cyclic(x)) write(file,"cycle",suffix); else write(file,point(x,n),suffix); } } void write(string s="", explicit path3 x, suffix suffix=endl) { write(stdout,s,x,suffix); } void write(file file, string s="", explicit path3[] x, suffix suffix=none) { write(file,s); if(x.length > 0) write(file,x[0]); for(int i=1; i < x.length; ++i) { write(file,endl); write(file," ^^"); write(file,x[i]); } write(file,suffix); } void write(string s="", explicit path3[] x, suffix suffix=endl) { write(stdout,s,x,suffix); } path3 solve(flatguide3 g) { int n=g.nodes.length-1; // If duplicate points occur consecutively, add dummy controls (if absent). for(int i=0; i < n; ++i) { if(g.nodes[i] == g.nodes[i+1] && !g.control[i].active) g.control[i]=control(g.nodes[i],g.nodes[i],straight=true); } // Fill in empty direction specifiers inherited from explicit control points. for(int i=0; i < n; ++i) { if(g.control[i].active) { g.out[i].init(g.control[i].post-g.nodes[i]); g.in[i].init(g.nodes[i+1]-g.control[i].pre); } } // Propagate directions across nodes. for(int i=0; i < n; ++i) { int next=g.cyclic[i+1] ? 0 : i+1; if(g.out[next].active()) g.in[i].default(g.out[next]); if(g.in[i].active()) { g.out[next].default(g.in[i]); g.out[i+1].default(g.in[i]); } } // Compute missing 3D directions. // First, resolve cycles int i=find(g.cyclic); if(i > 0) { aim(g,i); // All other cycles can now be reduced to sequences. triple v=g.out[0].dir; for(int j=i; j <= n; ++j) { if(g.cyclic[j]) { g.in[j-1].default(v); g.out[j].default(v); if(g.nodes[j-1] == g.nodes[j] && !g.control[j-1].active) g.control[j-1]=control(g.nodes[j-1],g.nodes[j-1]); } } } // Next, resolve sequences. int i=0; int start=0; while(i < n) { // Look for a missing outgoing direction. while(i <= n && g.solved(i)) {start=i; ++i;} if(i > n) break; // Look for the end of the sequence. while(i < n && !g.solved(i)) ++i; while(start < i && g.control[start].active) ++start; if(start < i) aim(g,start,i); } // Compute missing 3D control points. for(int i=0; i < n; ++i) { int next=g.cyclic[i+1] ? 0 : i+1; if(!g.control[i].active) { control c; if((g.out[i].Curl && g.in[i].Curl) || (g.out[i].dir == O && g.in[i].dir == O)) { // fill in straight control points for path3 functions triple delta=(g.nodes[i+1]-g.nodes[i])/3; c=control(g.nodes[i]+delta,g.nodes[i+1]-delta,straight=true); } else { Controls C=Controls(g.nodes[i],g.nodes[next],g.out[i].dir,g.in[i].dir, g.Tension[i].out,g.Tension[i].in, g.Tension[i].atLeast); c=control(C.c0,C.c1); } g.control[i]=c; } } // Convert to Knuth's format (control points stored with nodes) int n=g.nodes.length; bool cyclic; if(n > 0) { cyclic=g.cyclic[n-1]; if(cyclic) --n; } triple[] pre=new triple[n]; triple[] point=new triple[n]; triple[] post=new triple[n]; bool[] straight=new bool[n]; if(n > 0) { for(int i=0; i < n-1; ++i) { point[i]=g.nodes[i]; post[i]=g.control[i].post; pre[i+1]=g.control[i].pre; straight[i]=g.control[i].straight; } point[n-1]=g.nodes[n-1]; if(cyclic) { pre[0]=g.control[n-1].pre; post[n-1]=g.control[n-1].post; straight[n-1]=g.control[n-1].straight; } else { pre[0]=point[0]; post[n-1]=point[n-1]; straight[n-1]=false; } } return path3(pre,point,post,straight,cyclic); } path nurb(path3 p, projection P, int ninterpolate=P.ninterpolate) { triple f=P.camera; triple u=unit(P.normal); transform3 t=P.t; path nurb(triple v0, triple v1, triple v2, triple v3) { return nurb(project(v0,t),project(v1,t),project(v2,t),project(v3,t), dot(u,f-v0),dot(u,f-v1),dot(u,f-v2),dot(u,f-v3),ninterpolate); } path g; if(straight(p,0)) g=project(point(p,0),t); int last=length(p); for(int i=0; i < last; ++i) { if(straight(p,i)) g=g--project(point(p,i+1),t); else g=g&nurb(point(p,i),postcontrol(p,i),precontrol(p,i+1),point(p,i+1)); } int n=length(g); if(cyclic(p)) g=g&cycle; return g; } path project(path3 p, projection P=currentprojection, int ninterpolate=P.ninterpolate) { guide g; int last=length(p); if(last < 0) return g; transform3 t=P.t; if(ninterpolate == 1 || piecewisestraight(p)) { g=project(point(p,0),t); // Construct the path. int stop=cyclic(p) ? last-1 : last; for(int i=0; i < stop; ++i) { if(straight(p,i)) g=g--project(point(p,i+1),t); else { g=g..controls project(postcontrol(p,i),t) and project(precontrol(p,i+1),t)..project(point(p,i+1),t); } } } else return nurb(p,P); if(cyclic(p)) g=straight(p,last-1) ? g--cycle : g..controls project(postcontrol(p,last-1),t) and project(precontrol(p,last),t)..cycle; return g; } pair[] project(triple[] v, projection P=currentprojection) { return sequence(new pair(int i) {return project(v[i],P.t);},v.length); } path[] project(explicit path3[] g, projection P=currentprojection) { return sequence(new path(int i) {return project(g[i],P);},g.length); } guide3 operator cast(path3 p) { int last=length(p); bool cyclic=cyclic(p); int stop=cyclic ? last-1 : last; return new void(flatguide3 f) { if(last >= 0) { f.node(point(p,0)); for(int i=0; i < stop; ++i) { if(straight(p,i)) { f.out(1); f.in(1); } else f.control(postcontrol(p,i),precontrol(p,i+1)); f.node(point(p,i+1)); } if(cyclic) { if(straight(p,stop)) { f.out(1); f.in(1); } else f.control(postcontrol(p,stop),precontrol(p,last)); f.cycleToken(); } } }; } // Return a unit normal vector to a planar path p (or O if the path is // nonplanar). triple normal(path3 p) { triple normal; real fuzz=sqrtEpsilon*abs(max(p)-min(p)); real absnormal; real theta; bool Cross(triple a, triple b) { if(abs(a) >= fuzz && abs(b) >= fuzz) { triple n=cross(unit(a),unit(b)); real absn=abs(n); if(absn < sqrtEpsilon) return false; n=unit(n); if(absnormal > 0 && abs(normal-n) > sqrtEpsilon && abs(normal+n) > sqrtEpsilon) return true; else { int sign=dot(n,normal) >= 0 ? 1 : -1; theta += sign*asin1(absn); if(absn > absnormal) { absnormal=absn; normal=n; theta=sign*theta; } } } return false; } int L=length(p); if(L <= 0) return O; triple zi=point(p,0); triple v0=zi-precontrol(p,0); for(int i=0; i < L; ++i) { triple c0=postcontrol(p,i); triple c1=precontrol(p,i+1); triple zp=point(p,i+1); triple v1=c0-zi; triple v2=c1-c0; triple v3=zp-c1; if(Cross(v0,v1) || Cross(v1,v2) || Cross(v2,v3)) return O; v0=v3; zi=zp; } return theta >= 0 ? normal : -normal; } // Return a unit normal vector to a polygon with vertices in p. triple normal(triple[] p) { triple normal; real fuzz=sqrtEpsilon*abs(maxbound(p)-minbound(p)); real absnormal; real theta; bool Cross(triple a, triple b) { if(abs(a) >= fuzz && abs(b) >= fuzz) { triple n=cross(unit(a),unit(b)); real absn=abs(n); n=unit(n); if(absnormal > 0 && absn > sqrtEpsilon && abs(normal-n) > sqrtEpsilon && abs(normal+n) > sqrtEpsilon) return true; else { int sign=dot(n,normal) >= 0 ? 1 : -1; theta += sign*asin1(absn); if(absn > absnormal) { absnormal=absn; normal=n; theta=sign*theta; } } } return false; } if(p.length <= 0) return O; triple zi=p[0]; triple v0=zi-p[p.length-1]; for(int i=0; i < p.length-1; ++i) { triple zp=p[i+1]; triple v1=zp-zi; if(Cross(v0,v1)) return O; v0=v1; zi=zp; } return theta >= 0 ? normal : -normal; } // Transforms that map XY plane to YX, YZ, ZY, ZX, and XZ planes. restricted transform3 XY=identity4; restricted transform3 YX=rotate(-90,O,Z); restricted transform3 YZ=rotate(90,O,Z)*rotate(90,O,X); restricted transform3 ZY=rotate(-90,O,X)*YZ; restricted transform3 ZX=rotate(-90,O,Z)*rotate(-90,O,Y); restricted transform3 XZ=rotate(-90,O,Y)*ZX; private transform3 flip(transform3 t, triple X, triple Y, triple Z, projection P) { static transform3 flip(triple v) { static real s(real x) {return x > 0 ? -1 : 1;} return scale(s(v.x),s(v.y),s(v.z)); } triple u=unit(P.normal); triple up=unit(perp(P.up,u)); bool upright=dot(Z,u) >= 0; if(dot(Y,up) < 0) { t=flip(Y)*t; upright=!upright; } return upright ? t : flip(X)*t; } restricted transform3 XY(projection P=currentprojection) { return flip(XY,X,Y,Z,P); } restricted transform3 YX(projection P=currentprojection) { return flip(YX,Y,X,Z,P); } restricted transform3 YZ(projection P=currentprojection) { return flip(YZ,Y,Z,X,P); } restricted transform3 ZY(projection P=currentprojection) { return flip(ZY,Z,Y,X,P); } restricted transform3 ZX(projection P=currentprojection) { return flip(ZX,Z,X,Y,P); } restricted transform3 XZ(projection P=currentprojection) { return flip(XZ,X,Z,Y,P); } // Transform3 that projects in direction dir onto plane with normal n // through point O. transform3 planeproject(triple n, triple O=O, triple dir=n) { real a=n.x, b=n.y, c=n.z; real u=dir.x, v=dir.y, w=dir.z; real delta=1.0/(a*u+b*v+c*w); real d=-(a*O.x+b*O.y+c*O.z)*delta; return new real[][] { {(b*v+c*w)*delta,-b*u*delta,-c*u*delta,-d*u}, {-a*v*delta,(a*u+c*w)*delta,-c*v*delta,-d*v}, {-a*w*delta,-b*w*delta,(a*u+b*v)*delta,-d*w}, {0,0,0,1} }; } // Transform3 that projects in direction dir onto plane defined by p. transform3 planeproject(path3 p, triple dir=O) { triple n=normal(p); return planeproject(n,point(p,0),dir == O ? n : dir); } // Transform for projecting onto plane through point O with normal cross(u,v). transform transform(triple u, triple v, triple O=O, projection P=currentprojection) { transform3 t=P.t; real[] tO=t*new real[] {O.x,O.y,O.z,1}; real tO3=tO[3]; real factor=1/tO3^2; real[] x=(tO3*t[0]-tO[0]*t[3])*factor; real[] y=(tO3*t[1]-tO[1]*t[3])*factor; triple x=(x[0],x[1],x[2]); triple y=(y[0],y[1],y[2]); u=unit(u); v=unit(v); return (0,0,dot(u,x),dot(v,x),dot(u,y),dot(v,y)); } // Project Label onto plane through point O with normal cross(u,v). Label project(Label L, triple u, triple v, triple O=O, projection P=currentprojection) { Label L=L.copy(); L.position=project(O,P.t); L.transform(transform(u,v,O,P)); return L; } path3 operator cast(guide3 g) {return solve(g);} path3 operator cast(triple v) {return path3(v);} guide3[] operator cast(triple[] v) { return sequence(new guide3(int i) {return v[i];},v.length); } path3[] operator cast(triple[] v) { return sequence(new path3(int i) {return v[i];},v.length); } path3[] operator cast(guide3[] g) { return sequence(new path3(int i) {return solve(g[i]);},g.length); } guide3[] operator cast(path3[] g) { return sequence(new guide3(int i) {return g[i];},g.length); } void write(file file, string s="", explicit guide3[] x, suffix suffix=none) { write(file,s,(path3[]) x,suffix); } void write(string s="", explicit guide3[] x, suffix suffix=endl) { write(stdout,s,(path3[]) x,suffix); } triple point(explicit guide3 g, int t) { flatguide3 f; g(f); int n=f.size(); return f.nodes[adjustedIndex(t,n,f.cyclic())]; } triple[] dirSpecifier(guide3 g, int t) { flatguide3 f; g(f); int n=f.size(); checkEmpty(n); if(f.cyclic()) t=t % n; else if(t < 0 || t >= n-1) return new triple[]; return new triple[] {f.out[t].dir,f.in[t].dir}; } triple[] controlSpecifier(guide3 g, int t) { flatguide3 f; g(f); int n=f.size(); checkEmpty(n); if(f.cyclic()) t=t % n; else if(t < 0 || t >= n-1) return new triple[]; control c=f.control[t]; if(c.active) return new triple[] {c.post,c.pre}; else return new triple[]; } tensionSpecifier tensionSpecifier(guide3 g, int t) { flatguide3 f; g(f); int n=f.size(); checkEmpty(n); if(f.cyclic()) t=t % n; else if(t < 0 || t >= n-1) return operator tension(1,1,false); Tension T=f.Tension[t]; return operator tension(T.out,T.in,T.atLeast); } real[] curlSpecifier(guide3 g, int t) { flatguide3 f; g(f); int n=f.size(); checkEmpty(n); if(f.cyclic()) t=t % n; else if(t < 0 || t >= n-1) return new real[]; return new real[] {f.out[t].gamma,f.in[t].gamma}; } guide3 reverse(guide3 g) { flatguide3 f; bool cyclic=cyclic(g); g(f); if(f.precyclic()) return reverse(solve(g)); int n=f.size(); checkEmpty(n); guide3 G; if(n >= 0) { int start=cyclic ? n : n-1; for(int i=start; i > 0; --i) { G=G..f.nodes[i]; control c=f.control[i-1]; if(c.active) G=G..operator controls(c.pre,c.post); else { dir in=f.in[i-1]; triple d=in.dir; if(d != O) G=G..operator spec(-d,JOIN_OUT); else if(in.Curl) G=G..operator curl(in.gamma,JOIN_OUT); dir out=f.out[i-1]; triple d=out.dir; if(d != O) G=G..operator spec(-d,JOIN_IN); else if(out.Curl) G=G..operator curl(out.gamma,JOIN_IN); } } if(cyclic) G=G..cycle; else G=G..f.nodes[0]; } return G; } triple intersectionpoint(path3 p, path3 q, real fuzz=-1) { real[] t=intersect(p,q,fuzz); if(t.length == 0) abort("paths do not intersect"); return point(p,t[0]); } // return an array containing all intersection points of p and q triple[] intersectionpoints(path3 p, path3 q, real fuzz=-1) { real[][] t=intersections(p,q,fuzz); return sequence(new triple(int i) {return point(p,t[i][0]);},t.length); } triple[] intersectionpoints(explicit path3[] p, explicit path3[] q, real fuzz=-1) { triple[] v; for(int i=0; i < p.length; ++i) for(int j=0; j < q.length; ++j) v.append(intersectionpoints(p[i],q[j],fuzz)); return v; } path3 operator &(path3 p, cycleToken tok) { int n=length(p); if(n < 0) return nullpath3; triple a=point(p,0); triple b=point(p,n); return subpath(p,0,n-1)..controls postcontrol(p,n-1) and precontrol(p,n).. cycle; } // return the point on path3 p at arclength L triple arcpoint(path3 p, real L) { return point(p,arctime(p,L)); } // return the point on path3 p at arclength L triple arcpoint(path3 p, real L) { return point(p,arctime(p,L)); } // return the direction on path3 p at arclength L triple arcdir(path3 p, real L) { return dir(p,arctime(p,L)); } // return the time on path3 p at the relative fraction l of its arclength real reltime(path3 p, real l) { return arctime(p,l*arclength(p)); } // return the point on path3 p at the relative fraction l of its arclength triple relpoint(path3 p, real l) { return point(p,reltime(p,l)); } // return the direction of path3 p at the relative fraction l of its arclength triple reldir(path3 p, real l) { return dir(p,reltime(p,l)); } // return the point on path3 p at half of its arclength triple midpoint(path3 p) { return relpoint(p,0.5); } real relative(Label L, path3 g) { return L.position.relative ? reltime(g,L.relative()) : L.relative(); } // return the linear transformation that maps X,Y,Z to u,v,w. transform3 transform3(triple u, triple v, triple w=cross(u,v)) { return new real[][] { {u.x,v.x,w.x,0}, {u.y,v.y,w.y,0}, {u.z,v.z,w.z,0}, {0,0,0,1} }; } // return the rotation that maps Z to a unit vector u about cross(u,Z), transform3 align(triple u) { real a=u.x; real b=u.y; real c=u.z; real d=a^2+b^2; if(d != 0) { d=sqrt(d); real e=1/d; return new real[][] { {-b*e,-a*c*e,a,0}, {a*e,-b*c*e,b,0}, {0,d,c,0}, {0,0,0,1}}; } return c >= 0 ? identity(4) : diagonal(1,-1,-1,1); } // return a rotation that maps X,Y to the projection plane. transform3 transform3(projection P=currentprojection) { triple w=unit(P.normal); triple v=unit(perp(P.up,w)); if(v == O) v=cross(perp(w),w); triple u=cross(v,w); return u != O ? transform3(u,v,w) : identity(4); } triple[] triples(real[] x, real[] y, real[] z) { if(x.length != y.length || x.length != z.length) abort("arrays have different lengths"); return sequence(new triple(int i) {return (x[i],y[i],z[i]);},x.length); } path3[] operator cast(path3 p) { return new path3[] {p}; } path3[] operator cast(guide3 g) { return new path3[] {(path3) g}; } path3[] operator ^^ (path3 p, path3 q) { return new path3[] {p,q}; } path3[] operator ^^ (path3 p, explicit path3[] q) { return concat(new path3[] {p},q); } path3[] operator ^^ (explicit path3[] p, path3 q) { return concat(p,new path3[] {q}); } path3[] operator ^^ (explicit path3[] p, explicit path3[] q) { return concat(p,q); } path3[] operator * (transform3 t, explicit path3[] p) { return sequence(new path3(int i) {return t*p[i];},p.length); } triple[] operator * (transform3 t, triple[] v) { return sequence(new triple(int i) {return t*v[i];},v.length); } triple[][] operator * (transform3 t, triple[][] v) { triple[][] V=new triple[v.length][]; for(int i=0; i < v.length; ++i) { triple[] vi=v[i]; V[i]=sequence(new triple(int j) {return t*vi[j];},vi.length); } return V; } triple min(explicit path3[] p) { checkEmpty(p.length); triple minp=min(p[0]); for(int i=1; i < p.length; ++i) minp=minbound(minp,min(p[i])); return minp; } triple max(explicit path3[] p) { checkEmpty(p.length); triple maxp=max(p[0]); for(int i=1; i < p.length; ++i) maxp=maxbound(maxp,max(p[i])); return maxp; } path3 randompath3(int n, bool cumulate=true, interpolate3 join=operator ..) { guide3 g; triple w; for(int i=0; i <= n; ++i) { triple z=(unitrand()-0.5,unitrand()-0.5,unitrand()-0.5); if(cumulate) w += z; else w=z; g=join(g,w); } return g; } path3[] box(triple v1, triple v2) { return (v1.x,v1.y,v1.z)-- (v1.x,v1.y,v2.z)-- (v1.x,v2.y,v2.z)-- (v1.x,v2.y,v1.z)-- (v1.x,v1.y,v1.z)-- (v2.x,v1.y,v1.z)-- (v2.x,v1.y,v2.z)-- (v2.x,v2.y,v2.z)-- (v2.x,v2.y,v1.z)-- (v2.x,v1.y,v1.z)^^ (v2.x,v2.y,v1.z)-- (v1.x,v2.y,v1.z)^^ (v1.x,v2.y,v2.z)-- (v2.x,v2.y,v2.z)^^ (v2.x,v1.y,v2.z)-- (v1.x,v1.y,v2.z); } restricted path3[] unitbox=box(O,(1,1,1)); restricted path3 unitcircle3=X..Y..-X..-Y..cycle; restricted path3 unitsquare3=O--X--X+Y--Y--cycle; path3 circle(triple c, real r, triple normal=Z) { path3 p=normal == Z ? unitcircle3 : align(unit(normal))*unitcircle3; return shift(c)*scale3(r)*p; } // return an arc centered at c from triple v1 to v2 (assuming |v2-c|=|v1-c|), // drawing in the given direction. // The normal must be explicitly specified if c and the endpoints are colinear. path3 arc(triple c, triple v1, triple v2, triple normal=O, bool direction=CCW) { v1 -= c; real r=abs(v1); v1=unit(v1); v2=unit(v2-c); if(normal == O) { normal=cross(v1,v2); if(normal == O) abort("explicit normal required for these endpoints"); } transform3 T; bool align=normal != Z; if(align) { T=align(unit(normal)); transform3 Tinv=transpose(T); v1=Tinv*v1; v2=Tinv*v2; } string invalidnormal="invalid normal vector"; real fuzz=sqrtEpsilon*max(abs(v1),abs(v2)); if(abs(v1.z) > fuzz || abs(v2.z) > fuzz) abort(invalidnormal); real[] t1=intersect(unitcircle3,O--2*(v1.x,v1.y,0)); real[] t2=intersect(unitcircle3,O--2*(v2.x,v2.y,0)); if(t1.length == 0 || t2.length == 0) abort(invalidnormal); real t1=t1[0]; real t2=t2[0]; int n=length(unitcircle3); if(direction) { if(t1 >= t2) t1 -= n; } else if(t2 >= t1) t2 -= n; path3 p=subpath(unitcircle3,t1,t2); if(align) p=T*p; return shift(c)*scale3(r)*p; } // return an arc centered at c with radius r from c+r*dir(theta1,phi1) to // c+r*dir(theta2,phi2) in degrees, drawing in the given direction // relative to the normal vector cross(dir(theta1,phi1),dir(theta2,phi2)). // The normal must be explicitly specified if c and the endpoints are colinear. path3 arc(triple c, real r, real theta1, real phi1, real theta2, real phi2, triple normal=O, bool direction) { return arc(c,c+r*dir(theta1,phi1),c+r*dir(theta2,phi2),normal,direction); } // return an arc centered at c with radius r from c+r*dir(theta1,phi1) to // c+r*dir(theta2,phi2) in degrees, drawing drawing counterclockwise // relative to the normal vector cross(dir(theta1,phi1),dir(theta2,phi2)) // iff theta2 > theta1 or (theta2 == theta1 and phi2 >= phi1). // The normal must be explicitly specified if c and the endpoints are colinear. path3 arc(triple c, real r, real theta1, real phi1, real theta2, real phi2, triple normal=O) { return arc(c,r,theta1,phi1,theta2,phi2,normal, theta2 > theta1 || (theta2 == theta1 && phi2 >= phi1) ? CCW : CW); } private real epsilon=1000*realEpsilon; // Return a representation of the plane through point O with normal cross(u,v). path3 plane(triple u, triple v, triple O=O) { return O--O+u--O+u+v--O+v--cycle; } // PRC/OpenGL support include three_light; void draw(frame f, path3 g, material p=currentpen, light light=nolight, string name="", render render=defaultrender, projection P=currentprojection); void begingroup3(frame f, string name="", render render=defaultrender, triple center=O, int interaction=0) { _begingroup3(f,name,render.compression,render.granularity,render.closed, render.tessellate,render.merge == false, render.merge == true,center,interaction); } void begingroup3(picture pic=currentpicture, string name="", render render=defaultrender, triple center=O, int interaction=0) { pic.add(new void(frame f, transform3, picture pic, projection) { if(is3D()) begingroup3(f,name,render,center,interaction); if(pic != null) begingroup(pic); },true); } void endgroup3(picture pic=currentpicture) { pic.add(new void(frame f, transform3, picture pic, projection) { if(is3D()) endgroup3(f); if(pic != null) endgroup(pic); },true); } void addPath(picture pic, path3 g, pen p) { if(size(g) > 0) pic.addBox(min(g),max(g),min3(p),max3(p)); } include three_surface; include three_margins; pair min(path3 p, projection P) { path3 q=P.T.modelview*p; if(P.infinity) return xypart(min(q)); return maxratio(q)/P.T.projection[3][2]; } pair max(path3 p, projection P) { path3 q=P.T.modelview*p; if(P.infinity) return xypart(max(q)); return minratio(q)/P.T.projection[3][2]; } pair min(frame f, projection P) { frame g=P.T.modelview*f; if(P.infinity) return xypart(min3(g)); return maxratio(g)/P.T.projection[3][2]; } pair max(frame f, projection P) { frame g=P.T.modelview*f; if(P.infinity) return xypart(max3(g)); return minratio(g)/P.T.projection[3][2]; } void draw(picture pic=currentpicture, Label L="", path3 g, align align=NoAlign, material p=currentpen, margin3 margin=NoMargin3, light light=nolight, string name="", render render=defaultrender) { pen q=(pen) p; pic.add(new void(frame f, transform3 t, picture pic, projection P) { path3 G=margin(t*g,q).g; if(is3D()) { draw(f,G,p,light,name,render,null); if(pic != null && size(G) > 0) pic.addBox(min(G,P),max(G,P),min(q),max(q)); } if(pic != null) draw(pic,project(G,P),q); },true); Label L=L.copy(); L.align(align); if(L.s != "") { L.p(q); label(pic,L,g); } addPath(pic,g,q); } include three_tube; draw=new void(frame f, path3 g, material p=currentpen, light light=nolight, string name="", render render=defaultrender, projection P=currentprojection) { pen q=(pen) p; if(is3D()) { p=material(p); real width=linewidth(q); void drawthick(path3 g) { if(settings.thick) { if(width > 0) { bool prc=prc(); void cylinder(transform3) {}; void sphere(transform3, bool half) {}; void disk(transform3) {}; void pipe(path3, path3); if(prc) { cylinder=new void(transform3 t) {drawPRCcylinder(f,t,p,light);}; sphere=new void(transform3 t, bool half) {drawPRCsphere(f,t,half,p,light,render);}; disk=new void(transform3 t) {draw(f,t*unitdisk,p,light,render);}; pipe=new void(path3 center, path3 g) {drawPRCtube(f,center,g,p,light);}; } real linecap=linecap(q); real r=0.5*width; bool open=!cyclic(g); int L=length(g); triple g0=point(g,0); triple gL=point(g,L); if(open && L > 0) { if(linecap == 2) { g0 -= r*dir(g,0); gL += r*dir(g,L); g=g0..g..gL; L += 2; } } tube T=tube(g,width,render,cylinder,sphere,pipe); path3 c=T.center; if(L >= 0) { if(open) { int Lc=length(c); triple c0=point(c,0); triple cL=point(c,Lc); triple dir0=dir(g,0); triple dirL=dir(g,L); triple dirc0=dir(c,0); triple dircL=dir(c,Lc); transform3 t0=shift(g0)*align(-dir0); transform3 tL=shift(gL)*align(dirL); transform3 tc0=shift(c0)*align(-dirc0); transform3 tcL=shift(cL)*align(dircL); if(linecap == 0 || linecap == 2) { transform3 scale2r=scale(r,r,1); T.s.append(t0*scale2r*unitdisk); disk(tc0*scale2r); if(L > 0) { T.s.append(tL*scale2r*unitdisk); disk(tcL*scale2r); } } else if(linecap == 1) { transform3 scale3r=scale3(r); T.s.append(t0*scale3r* (dir0 != O ? unithemisphere : unitsphere)); sphere(tc0*scale3r,half=straight(c,0)); if(L > 0) { T.s.append(tL*scale3r* (dirL != O ? unithemisphere : unitsphere)); sphere(tcL*scale3r,half=straight(c,Lc-1)); } } } if(opacity(q) == 1) _draw(f,c,q); } for(patch s : T.s.s) draw3D(f,s,p,light,prc=false); } else _draw(f,g,q); } else _draw(f,g,q); } bool group=q != nullpen && (name != "" || render.defaultnames); if(group) begingroup3(f,name == "" ? "curve" : name,render); if(linetype(q).length == 0) drawthick(g); else { real[] dash=linetype(adjust(q,arclength(g),cyclic(g))); if(sum(dash) > 0) { dash.cyclic=true; real offset=offset(q); real L=arclength(g); int i=0; real l=offset; while(l <= L) { real t1=arctime(g,l); l += dash[i]; real t2=arctime(g,min(l,L)); drawthick(subpath(g,t1,t2)); ++i; l += dash[i]; ++i; } } } if(group) endgroup3(f); } else draw(f,project(g,P),q); }; void draw(frame f, explicit path3[] g, material p=currentpen, light light=nolight, string name="", render render=defaultrender, projection P=currentprojection) { bool group=g.length > 1 && (name != "" || render.defaultnames); if(group) begingroup3(f,name == "" ? "curves" : name,render); for(int i=0; i < g.length; ++i) draw(f,g[i],p,light,partname(i,render),render,P); if(group) endgroup3(f); } void draw(picture pic=currentpicture, explicit path3[] g, material p=currentpen, margin3 margin=NoMargin3, light light=nolight, string name="", render render=defaultrender) { bool group=g.length > 1 && (name != "" || render.defaultnames); if(group) begingroup3(pic,name == "" ? "curves" : name,render); for(int i=0; i < g.length; ++i) draw(pic,g[i],p,margin,light,partname(i,render),render); if(group) endgroup3(pic); } include three_arrows; void draw(picture pic=currentpicture, Label L="", path3 g, align align=NoAlign, material p=currentpen, arrowbar3 arrow, arrowbar3 bar=None, margin3 margin=NoMargin3, light light=nolight, light arrowheadlight=currentlight, string name="", render render=defaultrender) { bool group=arrow != None || bar != None; if(group) begingroup3(pic,name,render); bool drawpath=arrow(pic,g,p,margin,light,arrowheadlight); if(bar(pic,g,p,margin,light,arrowheadlight) && drawpath) draw(pic,L,g,align,p,margin,light,render); if(group) endgroup3(pic); if(L.s != "") label(pic,L,g,align,(pen) p); } void draw(frame f, path3 g, material p=currentpen, arrowbar3 arrow, light light=nolight, light arrowheadlight=currentlight, string name="", render render=defaultrender, projection P=currentprojection) { picture pic; bool group=arrow != None; if(group) begingroup3(f,name,render); if(arrow(pic,g,p,NoMargin3,light,arrowheadlight)) draw(f,g,p,light,render,P); add(f,pic.fit()); if(group) endgroup3(f); } void add(picture pic=currentpicture, void d(picture,transform3), bool exact=false) { pic.add(d,exact); } // Fit the picture src using the identity transformation (so user // coordinates and truesize coordinates agree) and add it about the point // position to picture dest. void add(picture dest, picture src, triple position, bool group=true, bool above=true) { dest.add(new void(picture f, transform3 t) { f.add(shift(t*position)*src,group,above); }); } void add(picture src, triple position, bool group=true, bool above=true) { add(currentpicture,src,position,group,above); } // Align an arrow pointing to b from the direction dir. The arrow is // 'length' PostScript units long. void arrow(picture pic=currentpicture, Label L="", triple b, triple dir, real length=arrowlength, align align=NoAlign, pen p=currentpen, arrowbar3 arrow=Arrow3, margin3 margin=EndMargin3, light light=nolight, light arrowheadlight=currentlight, string name="", render render=defaultrender) { Label L=L.copy(); if(L.defaultposition) L.position(0); L.align(L.align,dir); L.p(p); picture opic; marginT3 margin=margin(b--b,p); // Extract margin.begin and margin.end triple a=(margin.begin+length+margin.end)*unit(dir); draw(opic,L,a--O,align,p,arrow,margin,light,arrowheadlight,name,render); add(pic,opic,b); } void arrow(picture pic=currentpicture, Label L="", triple b, pair dir, real length=arrowlength, align align=NoAlign, pen p=currentpen, arrowbar3 arrow=Arrow3, margin3 margin=EndMargin3, light light=nolight, light arrowheadlight=currentlight, string name="", render render=defaultrender, projection P=currentprojection) { arrow(pic,L,b,invert(dir,b,P),length,align,p,arrow,margin,light, arrowheadlight,name,render); } triple min3(picture pic, projection P=currentprojection) { return pic.min3(P); } triple max3(picture pic, projection P=currentprojection) { return pic.max3(P); } triple size3(picture pic, bool user=false, projection P=currentprojection) { transform3 t=pic.calculateTransform3(P); triple M=pic.max(t); triple m=pic.min(t); if(!user) return M-m; t=inverse(t); return t*M-t*m; } triple point(frame f, triple dir) { triple m=min3(f); triple M=max3(f); return m+realmult(rectify(dir),M-m); } triple point(picture pic=currentpicture, triple dir, bool user=true, projection P=currentprojection) { triple min = pic.userMin(), max = pic.userMax(); triple v=min+realmult(rectify(dir),max-min); return user ? v : pic.calculateTransform3(P)*v; } triple truepoint(picture pic=currentpicture, triple dir, bool user=true, projection P=currentprojection) { transform3 t=pic.calculateTransform3(P); triple m=pic.min(t); triple M=pic.max(t); triple v=m+realmult(rectify(dir),M-m); return user ? inverse(t)*v : v; } void add(picture dest=currentpicture, object src, pair position=0, pair align=0, bool group=true, filltype filltype=NoFill, bool above=true) { if(prc()) label(dest,src,position,align); else if(settings.render == 0) plain.add(dest,src,position,align,group,filltype,above); } private struct viewpoint { triple target,camera,up; real angle; void operator init(string s) { s=replace(s,'\n'," "); string[] S=split(s); int pos(string s, string key) { int pos=find(s,key); if(pos < 0) return -1; pos += length(key); while(substr(s,pos,1) == " ") ++pos; if(substr(s,pos,1) == "=") return pos+1; return -1; } triple C2C=X; real ROO=1; real ROLL=0; angle=30; int pos; for(int k=0; k < S.length; ++k) { if((pos=pos(S[k],"COO")) >= 0) target=((real) substr(S[k],pos),(real) S[++k],(real) S[++k]); else if((pos=pos(S[k],"C2C")) >= 0) C2C=((real) substr(S[k],pos),(real) S[++k],(real) S[++k]); else if((pos=pos(S[k],"ROO")) >= 0) ROO=(real) substr(S[k],pos); else if((pos=pos(S[k],"ROLL")) >= 0) ROLL=(real) substr(S[k],pos); else if((pos=pos(S[k],"AAC")) >= 0) angle=(real) substr(S[k],pos); } camera=target+ROO*C2C; triple u=unit(target-camera); triple w=unit(Z-u.z*u); up=rotate(ROLL,O,u)*w; } } projection perspective(string s) { viewpoint v=viewpoint(s); projection P=perspective(v.camera,v.up,v.target); P.angle=v.angle; P.absolute=true; return P; } projection absorthographic(triple camera=Z, triple target=O, real roll=0) { triple u=unit(target-camera); triple w=unit(Z-u.z*u); triple up=rotate(roll,O,u)*w; projection P= projection(camera,up,target,1,0,false,false, new transformation(triple camera, triple up, triple target) {return transformation(look(camera,up,target));}); P.absolute=true; return P; } projection absperspective(triple camera=Z, triple target=O, real roll=0, real angle=30) { triple u=unit(target-camera); triple w=unit(Z-u.z*u); triple up=rotate(roll,O,u)*w; projection P=perspective(camera,up,target); P.angle=angle; P.absolute=true; return P; } private string Format(real x) { assert(abs(x) < 1e17,"Number too large: "+string(x)); return format("%.9f",x,"C"); } private string Format(triple v, string sep=" ") { return Format(v.x)+sep+Format(v.y)+sep+Format(v.z); } private string Format(real[] c) { return Format((c[0],c[1],c[2])); } private string format(triple v, string sep=" ") { return string(v.x)+sep+string(v.y)+sep+string(v.z); } private string Format(transform3 t, string sep=" ") { return Format(t[0][0])+sep+Format(t[1][0])+sep+Format(t[2][0])+sep+ Format(t[0][1])+sep+Format(t[1][1])+sep+Format(t[2][1])+sep+ Format(t[0][2])+sep+Format(t[1][2])+sep+Format(t[2][2])+sep+ Format(t[0][3])+sep+Format(t[1][3])+sep+Format(t[2][3]); } string lightscript(light light) { string script="for(var i=scene.lights.count-1; i >= 0; i--) scene.lights.removeByIndex(i);"+'\n\n'; for(int i=0; i < light.position.length; ++i) { string Li="L"+string(i); real[] diffuse=light.diffuse[i]; script += Li+"=scene.createLight();"+'\n'+ Li+".direction.set("+format(-light.position[i],",")+");"+'\n'+ Li+".color.set("+format((diffuse[0],diffuse[1],diffuse[2]),",")+");"+'\n'; } // Work around initialization bug in Adobe Reader 8.0: return script +" scene.lightScheme=scene.LIGHT_MODE_HEADLAMP; scene.lightScheme=scene.LIGHT_MODE_FILE; "; } void writeJavaScript(string name, string preamble, string script) { file out=output(name); write(out,preamble); if(script != "") { write(out,endl); file in=input(script); while(true) { string line=in; if(eof(in)) break; write(out,line,endl); } } close(out); if(settings.verbose > 1) write("Wrote "+name); if(!settings.inlinetex) file3.push(name); } pair viewportmargin(pair lambda) { return maxbound(0.5*(viewportsize-lambda),viewportmargin); } string embed3D(string prefix, string label=prefix, string text=label, frame f, string format="", real width=0, real height=0, string options="", string script="", light light=currentlight, projection P=currentprojection, real viewplanesize=0) { if(!prc(format) || Embed == null) return ""; if(width == 0) width=settings.paperwidth; if(height == 0) height=settings.paperheight; if(script == "") script=defaultembed3Dscript; if(P.infinity) { if(viewplanesize==0) { triple lambda=max3(f)-min3(f); pair margin=viewportmargin((lambda.x,lambda.y)); viewplanesize=(max(lambda.x+2*margin.x,lambda.y+2*margin.y))/P.zoom; } } else if(!P.absolute) P.angle=2*aTan(Tan(0.5*P.angle)); shipout3(prefix,f); string name=prefix+".js"; // Adobe Reader doesn't appear to support user-specified viewport lights. bool lightscript=light.on() && !light.viewport; if(lightscript) writeJavaScript(name,lightscript(light),script); if(!settings.inlinetex && !prconly()) file3.push(prefix+".prc"); static transform3 flipxz=xscale3(-1)*zscale3(-1); transform3 inv=inverse(flipxz*P.T.modelview); string options3="3Dlights="+ (light.on() ? (light.viewport ? "Headlamp" : "File") : "None"); if(defaultembed3Doptions != "") options3 += ","+defaultembed3Doptions; if((settings.render < 0 || !settings.embed) && settings.auto3D) options3 += ",activate=pagevisible"; options3 += ",3Dtoolbar="+(settings.toolbar ? "true" : "false")+ ",label="+label+ (P.infinity ? ",3Dortho="+Format(1/viewplanesize) : ",3Daac="+Format(P.angle))+ ",3Dc2w="+Format(inv)+ ",3Droo="+Format(abs(P.vector()))+ ",3Dpsob="+(P.infinity ? "Max" : "H")+ ",3Dbg="+Format(light.background()); if(options != "") options3 += ","+options; if(settings.inlinetex) prefix=jobname(prefix); if(lightscript) options3 += ",add3Djscript="+prefix+".js"; options3 += ",add3Djscript=asylabels.js"; return text == "" ? Embed(prefix+".prc","",options3,width,height) : "\hbox to 0pt{"+text+"\hss}"+Embed(prefix+".prc","\phantom{"+text+"}", options3); } struct scene { frame f; transform3 t; projection P; bool adjusted; real width,height; pair viewportmargin; transform3 T=identity4; picture pic2; void operator init(frame f, real width, real height, projection P=currentprojection) { this.f=f; this.t=identity4; this.P=P; this.width=width; this.height=height; } void operator init(picture pic, real xsize=pic.xsize, real ysize=pic.ysize, bool keepAspect=pic.keepAspect, bool is3D=true, projection P=currentprojection) { real xsize3=pic.xsize3, ysize3=pic.ysize3, zsize3=pic.zsize3; bool warn=true; if(xsize3 == 0 && ysize3 == 0 && zsize3 == 0) { xsize3=ysize3=zsize3=max(xsize,ysize); warn=false; } if(P.absolute) this.P=P.copy(); else if(P.showtarget) draw(pic,P.target,nullpen); t=pic.scaling(xsize3,ysize3,zsize3,keepAspect,warn); adjusted=false; triple m=pic.min(t); triple M=pic.max(t); if(!P.absolute) { this.P=t*P; if(this.P.center && settings.render != 0) { triple target=0.5*(m+M); this.P.target=target; this.P.calculate(); } if(this.P.autoadjust || this.P.infinity) adjusted=adjusted | this.P.adjust(m,M); } bool scale=xsize != 0 || ysize != 0; bool scaleAdjust=scale && this.P.autoadjust; bool noAdjust=(this.P.absolute || !scaleAdjust); if(pic.bounds3.exact && noAdjust) this.P.bboxonly=false; f=pic.fit3(t,pic.bounds3.exact ? pic2 : null,this.P); if(!pic.bounds3.exact) { if(noAdjust) this.P.bboxonly=false; transform3 s=pic.scale3(f,xsize3,ysize3,zsize3,keepAspect); t=s*t; this.P=s*this.P; f=pic.fit3(t,pic2,this.P); } if(is3D || scale) { pic2.bounds.exact=true; transform s=pic2.scaling(xsize,ysize,keepAspect); pair m2=pic2.min(s); pair M2=pic2.max(s); pair lambda=M2-m2; viewportmargin=viewportmargin(lambda); width=ceil(lambda.x+2*viewportmargin.x); height=ceil(lambda.y+2*viewportmargin.y); if(!this.P.absolute) { if(scaleAdjust) { pair v=(s.xx,s.yy); transform3 T=this.P.t; pair x=project(X,T); pair y=project(Y,T); pair z=project(Z,T); real f(pair a, pair b) { return b == 0 ? (0.5*(a.x+a.y)) : (b.x^2*a.x+b.y^2*a.y)/(b.x^2+b.y^2); } transform3 s=keepAspect ? scale3(min(f(v,x),f(v,y),f(v,z))) : xscale3(f(v,x))*yscale3(f(v,y))*zscale3(f(v,z)); s=shift(this.P.target)*s*shift(-this.P.target); t=s*t; this.P=s*this.P; this.P.bboxonly=false; if(!is3D) pic2.erase(); f=pic.fit3(t,is3D ? null : pic2,this.P); } if(this.P.autoadjust || this.P.infinity) adjusted=adjusted | this.P.adjust(min3(f),max3(f)); } } } // Choose the angle to be just large enough to view the entire image. real angle(projection P) { T=identity4; real h=-0.5*P.target.z; pair r,R; real diff=realMax; pair s; int i; do { r=minratio(f); R=maxratio(f); pair lasts=s; if(P.autoadjust) { s=r+R; if(s != 0) { transform3 t=shift(h*s.x,h*s.y,0); f=t*f; T=t*T; adjusted=true; } } diff=abs(s-lasts); ++i; } while (diff > angleprecision && i < maxangleiterations); real aspect=width > 0 ? height/width : 1; real rx=-r.x*aspect; real Rx=R.x*aspect; real ry=-r.y; real Ry=R.y; if(!P.autoadjust) { if(rx > Rx) Rx=rx; else rx=Rx; if(ry > Ry) Ry=ry; else ry=Ry; } return (1+angleprecision)*max(aTan(rx)+aTan(Rx),aTan(ry)+aTan(Ry)); } } object embed(string prefix=outprefix(), string label=prefix, string text=label, scene S, string format="", bool view=true, string options="", string script="", light light=currentlight) { object F; transform3 modelview; projection P=S.P; transform3 tinv=inverse(S.t); projection Q; triple orthoshift; modelview=P.T.modelview; transform3 inv; if(P.absolute) { Q=modelview*P; inv=inverse(modelview); } else { triple target=P.target; S.f=modelview*S.f; P=modelview*P; Q=P.copy(); if(P.infinity) { triple m=min3(S.f); triple M=max3(S.f); triple lambda=M-m; S.viewportmargin=viewportmargin((lambda.x,lambda.y)); S.width=ceil(lambda.x+2*S.viewportmargin.x); S.height=ceil(lambda.y+2*S.viewportmargin.y); orthoshift=(-0.5(m.x+M.x),-0.5*(m.y+M.y),0); S.f=shift(orthoshift)*S.f; // Eye will be at (0,0,0) inv=inverse(modelview); } else { if(P.angle == 0) { P.angle=S.angle(P); modelview=S.T*modelview; if(S.viewportmargin.y != 0) P.angle=2*aTan(Tan(0.5*P.angle)-S.viewportmargin.y/P.target.z); } inv=inverse(modelview); Q.angle=P.angle; if(settings.verbose > 0) { if(S.adjusted) write("adjusting camera to ",tinv*inv*P.camera); target=inv*P.target; } P=S.T*P; } if(settings.verbose > 0) { if((P.center && settings.render != 0) || (!P.infinity && P.autoadjust)) write("adjusting target to ",tinv*target); } } light Light=modelview*light; if(prefix == "") prefix=outprefix(); bool prc=prc(format); bool preview=settings.render > 0 && !prconly(); if(prc) { // The media9.sty package cannot handle spaces or dots in filenames. string dir=stripfile(prefix); prefix=dir+replace(stripdirectory(prefix), new string[][]{{" ","_"},{".","_"}}); if((settings.embed || nativeformat() == "pdf") && !prconly()) prefix += "+"+(string) file3.length; } else preview=false; if(preview || (!prc && settings.render != 0)) { frame f=S.f; triple m,M; real zcenter; real r; if(P.absolute) { f=modelview*f; m=min3(f); M=max3(f); r=0.5*abs(M-m); zcenter=0.5*(M.z+m.z); } else { m=min3(f); M=max3(f); zcenter=P.target.z; r=P.distance(m,M); } M=(M.x,M.y,zcenter+r); m=(m.x,m.y,zcenter-r); if(P.infinity) { triple margin=(S.viewportmargin.x,S.viewportmargin.y,0); M += margin; m -= margin; } else if(M.z >= 0) abort("camera too close"); shipout3(prefix,f,preview ? nativeformat() : format, S.width-defaultrender.margin,S.height-defaultrender.margin, P.infinity ? 0 : 2aTan(Tan(0.5*P.angle)*P.zoom), P.zoom,m,M,P.viewportshift, tinv*inv*shift(0,0,zcenter),Light.background(),Light.position, Light.diffuse,Light.ambient,Light.specular, Light.viewport,view && !preview); if(!preview) return F; } string image; if((preview || (prc && settings.render == 0)) && settings.embed) { image=prefix; if(settings.inlinetex) image += "_0"; if(!preview && !shipped && !S.pic2.empty2()) { transform T=S.pic2.scaling(S.width,S.height); shipout(image,S.pic2.fit(T),newframe,nativeformat(),false,false,null); } image += "."+nativeformat(); if(!settings.inlinetex) file3.push(image); image=graphic(image,"hiresbb"); } if(prc) { if(P.viewportshift != 0) { if(!P.infinity) warning("offaxis", "PRC does not support off-axis projections; use pan instead of shift"); triple lambda=max3(S.f)-min3(S.f); Q.target -= (P.viewportshift.x*lambda.x/P.zoom, P.viewportshift.y*lambda.y/P.zoom,0); } real viewplanesize=0; if(P.absolute) { if(P.infinity) { S.f=modelview*S.f; triple lambda=max3(S.f)-min3(S.f); pair margin=viewportmargin((lambda.x,lambda.y)); viewplanesize=(max(lambda.x+2*margin.x,lambda.y+2*margin.y))/Q.zoom; S.f=inv*S.f; } Q=inv*Q; } else { if(P.infinity) { triple lambda=max3(S.f)-min3(S.f); pair margin=viewportmargin((lambda.x,lambda.y)); viewplanesize=(max(lambda.x+2*margin.x,lambda.y+2*margin.y))/(Q.zoom); transform3 t=inv*shift(-orthoshift); Q=t*Q; S.f=t*S.f; } else { Q=inv*Q; S.f=inv*S.f; } } F.L=embed3D(prefix,label,text=image,S.f,format, S.width-2,S.height-2,options,script,light,Q,viewplanesize); } return F; } object embed(string prefix=outprefix(), string label=prefix, string text=label, picture pic, string format="", real xsize=pic.xsize, real ysize=pic.ysize, bool keepAspect=pic.keepAspect, bool view=true, string options="", string script="", light light=currentlight, projection P=currentprojection) { bool is3D=is3D(format); scene S=scene(pic,xsize,ysize,keepAspect,is3D,P); if(is3D) return embed(prefix,label,text,S,format,view,options,script,light); else { object F; transform T=S.pic2.scaling(xsize,ysize,keepAspect); F.f=pic.fit(scale(S.t[0][0])*T); add(F.f,S.pic2.fit()); return F; } } object embed(string prefix=outprefix(), string label=prefix, string text=label, frame f, string format="", real width=0, real height=0, bool view=true, string options="", string script="", light light=currentlight, projection P=currentprojection) { if(is3D(format)) return embed(label,text,prefix,scene(f,width,height,P),format,view,options, script,light); else { object F; F.f=f; return F; } } embed3=new object(string prefix, frame f, string format, string options, string script, light light, projection P) { return embed(prefix=prefix,f,format,options,script,light,P); }; frame embedder(object embedder(string prefix, string format), string prefix, string format, bool view, light light) { frame f; bool prc=prc(format); if(!prc && settings.render != 0 && !view) { static int previewcount=0; bool keep=prefix != ""; prefix=outprefix(prefix)+"+"+(string) previewcount; ++previewcount; format=nativeformat(); if(!keep) file3.push(prefix+"."+format); } object F=embedder(prefix,format); if(prc) label(f,F.L); else { if(settings.render == 0) { add(f,F.f); if(light.background != nullpen) box(f,light.background,Fill,above=false); } else if(!view) label(f,graphic(prefix,"hiresbb")); } return f; } currentpicture.fitter=new frame(string prefix, picture pic, string format, real xsize, real ysize, bool keepAspect, bool view, string options, string script, light light, projection P) { frame f; bool empty3=pic.empty3(); if(!empty3) f=embedder(new object(string prefix, string format) { return embed(prefix=prefix,pic,format,xsize,ysize,keepAspect,view, options,script,light,P); },prefix,format,view,light); if(is3D(format) || empty3) add(f,pic.fit2(xsize,ysize,keepAspect)); return f; }; frame embedder(string prefix, frame f, string format, real width, real height, bool view, string options, string script, light light, projection P) { return embedder(new object(string prefix, string format) { return embed(prefix=prefix,f,format,width,height,view,options,script, light,P); },prefix,format,view,light); } projection[][] ThreeViewsUS={{TopView}, {FrontView,RightView}}; projection[][] SixViewsUS={{null,TopView}, {LeftView,FrontView,RightView,BackView}, {null,BottomView}}; projection[][] ThreeViewsFR={{RightView,FrontView}, {null,TopView}}; projection[][] SixViewsFR={{null,BottomView}, {RightView,FrontView,LeftView,BackView}, {null,TopView}}; projection[][] ThreeViews={{FrontView,TopView,RightView}}; projection[][] SixViews={{FrontView,TopView,RightView}, {BackView,BottomView,LeftView}}; void addViews(picture dest, picture src, projection[][] views=SixViewsUS, bool group=true, filltype filltype=NoFill) { frame[][] F=array(views.length,new frame[]); pair[][] M=array(views.length,new pair[]); pair[][] m=array(views.length,new pair[]); for(int i=0; i < views.length; ++i) { projection[] viewsi=views[i]; frame[] Fi=F[i]; pair[] Mi=M[i]; pair[] mi=m[i]; for(projection P : viewsi) { if(P != null) { frame f=src.fit(P); mi.push(min(f)); Mi.push(max(f)); Fi.push(f); } else { pair Infinity=(infinity,infinity); mi.push(Infinity); Mi.push(-Infinity); Fi.push(newframe); } } } real[] my=new real[views.length]; real[] My=new real[views.length]; int Nj=0; for(int i=0; i < views.length; ++i) { my[i]=minbound(m[i]).y; My[i]=maxbound(M[i]).y; Nj=max(Nj,views[i].length); } real[] mx=array(Nj,infinity); real[] Mx=array(Nj,-infinity); for(int i=0; i < views.length; ++i) { pair[] mi=m[i]; pair[] Mi=M[i]; for(int j=0; j < views[i].length; ++j) { mx[j]=min(mx[j],mi[j].x); Mx[j]=max(Mx[j],Mi[j].x); } } if(group) begingroup(dest); real y; for(int i=0; i < views.length; ++i) { real x; pair[] mi=m[i]; for(int j=0; j < views[i].length; ++j) { if(size(F[i][j]) != 0) add(dest,shift(x-mx[j],y+my[i])*F[i][j],filltype); x += (Mx[j]-mx[j]); } y -= (My[i]-my[i]); } if(group) endgroup(dest); } void addViews(picture src, projection[][] views=SixViewsUS, bool group=true, filltype filltype=NoFill) { addViews(currentpicture,src,views,group,filltype); } void addStereoViews(picture dest, picture src, bool group=true, filltype filltype=NoFill, real eyetoview=defaulteyetoview, bool leftright=true, projection P=currentprojection) { triple v=P.vector(); triple h=0.5*abs(v)*eyetoview*unit(cross(P.up,v)); projection leftEye=P.copy(); leftEye.camera -= h; leftEye.calculate(); projection rightEye=P.copy(); rightEye.camera += h; rightEye.calculate(); addViews(dest,src,leftright ? new projection[][] {{leftEye,rightEye}} : new projection[][] {{rightEye,leftEye}},group,filltype); } void addStereoViews(picture src, bool group=true, filltype filltype=NoFill, real eyetoview=defaulteyetoview, bool leftright=true, projection P=currentprojection) { addStereoViews(currentpicture,src,group,filltype,eyetoview,leftright,P); } // Fit an array of 3D pictures simultaneously using the sizing of picture all. frame[] fit3(string prefix="", picture[] pictures, picture all, string format="", bool view=true, string options="", string script="", light light=currentlight, projection P=currentprojection) { frame[] out; scene S=scene(all,P); triple m=all.min(S.t); triple M=all.max(S.t); out=new frame[pictures.length]; int i=0; bool reverse=settings.reverse; settings.animating=true; for(picture pic : pictures) { picture pic2; frame f=pic.fit3(S.t,pic2,S.P); if(settings.interrupt) break; add(f,pic2.fit2()); draw(f,m,nullpen); draw(f,M,nullpen); out[i]=f; ++i; } while(!settings.interrupt) { for(int i=settings.reverse ? pictures.length-1 : 0; i >= 0 && i < pictures.length && !settings.interrupt; settings.reverse ? --i : ++i) { frame f=embedder(prefix,out[i],format,S.width,S.height,view,options, script,light,S.P); if(!settings.loop) out[i]=f; } if(!settings.loop) break; } settings.animating=false; settings.interrupt=false; settings.reverse=reverse; return out; } // Fit an array of pictures simultaneously using the size of the first picture. fit=new frame[](string prefix="", picture[] pictures, string format="", bool view=true, string options="", string script="", projection P=currentprojection) { if(pictures.length == 0) return new frame[]; picture all; size(all,pictures[0]); for(picture pic : pictures) add(all,pic); return all.empty3() ? fit2(pictures,all) : fit3(prefix,pictures,all,format,view,options,script,P); }; // Add frame src to picture dest about position. void add(picture dest=currentpicture, frame src, triple position) { if(is3D(src)) { dest.add(new void(frame f, transform3 t, picture, projection) { add(f,shift(t*position)*src); },true); } else { dest.add(new void(frame, transform3 t, picture pic, projection P) { if(pic != null) { pic.add(new void(frame f, transform T) { add(f,T*shift(project(t*position,P))*src); },true); } },true); } dest.addBox(position,position,min3(src),max3(src)); } exitfcn currentexitfunction=atexit(); void exitfunction() { if(currentexitfunction != null) currentexitfunction(); if(!settings.keep) for(int i=0; i < file3.length; ++i) delete(file3[i]); file3=new string[]; } atexit(exitfunction); asymptote-2.37/base/three_arrows.asy000066400000000000000000000564461265434602500176540ustar00rootroot00000000000000// A transformation that bends points along a path transform3 bend(path3 g, real t) { triple dir=dir(g,t); triple a=point(g,0), b=postcontrol(g,0); triple c=precontrol(g,1), d=point(g,1); triple dir1=b-a; triple dir2=c-b; triple dir3=d-c; triple u = unit(cross(dir1,dir3)); real eps=1000*realEpsilon; if(abs(u) < eps) { u = unit(cross(dir1,dir2)); if(abs(u) < eps) { u = unit(cross(dir2,dir3)); if(abs(u) < eps) // linear segment: use any direction perpendicular to initial direction u = perp(dir1); } } u = unit(perp(u,dir)); triple w=cross(dir,u); triple q=point(g,t); return new real[][] { {u.x,w.x,dir.x,q.x}, {u.y,w.y,dir.y,q.y}, {u.z,w.z,dir.z,q.z}, {0,0,0,1} }; } // bend a point along a path; assumes that p.z is in [0,scale] triple bend(triple p, path3 g, real scale) { return bend(g,arctime(g,arclength(g)+p.z-scale))*(p.x,p.y,0); } void bend(surface s, path3 g, real L) { for(patch p : s.s) { for(int i=0; i < 4; ++i) { for(int j=0; j < 4; ++j) { p.P[i][j]=bend(p.P[i][j],g,L); } } } } // Refine a noncyclic path3 g so that it approaches its endpoint in // geometrically spaced steps. path3 approach(path3 p, int n, real radix=3) { guide3 G; real L=length(p); real tlast=0; real r=1/radix; for(int i=1; i < n; ++i) { real t=L*(1-r^i); G=G&subpath(p,tlast,t); tlast=t; } return G&subpath(p,tlast,L); } struct arrowhead3 { arrowhead arrowhead2=DefaultHead; real size(pen p)=arrowsize; real arcsize(pen p)=arcarrowsize; real gap=1; real size; bool splitpath=true; surface head(path3 g, position position=EndPoint, pen p=currentpen, real size=0, real angle=arrowangle, filltype filltype=null, bool forwards=true, projection P=currentprojection); static surface surface(path3 g, position position, real size, path[] h, pen p, filltype filltype, triple normal, projection P) { bool relative=position.relative; real position=position.position.x; if(relative) position=reltime(g,position); path3 r=subpath(g,position,0); path3 s=subpath(r,arctime(r,size),0); if(filltype == null) filltype=FillDraw(p); bool draw=filltype.type != filltype.Fill; triple v=point(s,length(s)); triple N=normal == O ? P.normal : normal; triple w=unit(v-point(s,0)); transform3 t=transform3(w,unit(cross(w,N))); path3[] H=t*path3(h); surface s; real width=linewidth(p); if(filltype != NoFill && filltype.type != filltype.UnFill && filltype.type != filltype.Draw) { triple n=0.5*width*unit(t*Z); s=surface(shift(n)*H,planar=true); s.append(surface(shift(-n)*H,planar=true)); if(!draw) for(path g : h) s.append(shift(-n)*t*extrude(g,width*Z)); } if(draw) for(path3 g : H) s.append(tube(g,width).s); return shift(v)*s; } static path project(path3 g, bool forwards, projection P) { path h=project(forwards ? g : reverse(g),P); return shift(-point(h,length(h)))*h; } static path[] align(path H, path h) { static real fuzz=1000*realEpsilon; real[][] t=intersections(H,h,fuzz*max(abs(max(h)),abs(min(h)))); return t.length >= 2 ? rotate(-degrees(point(H,t[0][0])-point(H,t[1][0]),warn=false))*H : H; } } arrowhead3 DefaultHead3; DefaultHead3.head=new surface(path3 g, position position=EndPoint, pen p=currentpen, real size=0, real angle=arrowangle, filltype filltype=null, bool forwards=true, projection P=currentprojection) { if(size == 0) size=DefaultHead3.size(p); bool relative=position.relative; real position=position.position.x; if(relative) position=reltime(g,position); path3 r=subpath(g,position,0); path3 s=subpath(r,arctime(r,size),0); int n=length(s); bool straight1=n == 1 && straight(g,0); real aspect=Tan(angle); real width=size*aspect; surface head; if(straight1) { triple v=point(s,0); triple u=point(s,1)-v; return shift(v)*align(unit(u))*scale(width,width,size)*unitsolidcone; } else { real remainL=size; bool first=true; for(int i=0; i < n; ++i) { render(subpath(s,i,i+1),new void(path3 q, real) { if(remainL > 0) { real l=arclength(q); real w=remainL*aspect; surface segment=scale(w,w,l)*unitcylinder; if(first) { // add base first=false; segment.append(scale(w,w,1)*unitdisk); } for(patch p : segment.s) { for(int i=0; i < 4; ++i) { for(int j=0; j < 4; ++j) { real k=1-p.P[i][j].z/remainL; p.P[i][j]=bend((k*p.P[i][j].x,k*p.P[i][j].y,p.P[i][j].z),q,l); } } } head.append(segment); remainL -= l; } }); } } return head; }; arrowhead3 HookHead3(real dir=arrowdir, real barb=arrowbarb) { arrowhead3 a; a.head=new surface(path3 g, position position=EndPoint, pen p=currentpen, real size=0, real angle=arrowangle, filltype filltype=null, bool forwards=true, projection P=currentprojection) { if(size == 0) size=a.size(p); bool relative=position.relative; real position=position.position.x; if(relative) position=reltime(g,position); path3 r=subpath(g,position,0); path3 s=subpath(r,arctime(r,size),0); bool straight1=length(s) == 1 && straight(g,0); path3 H=path3(HookHead(dir,barb).head((0,0)--(0,size),p,size,angle), YZplane); surface head=surface(O,reverse(approach(subpath(H,1,0),7,1.5))& approach(subpath(H,1,2),4,2),Z); if(straight1) { triple v=point(s,0); triple u=point(s,1)-v; return shift(v)*align(unit(u))*head; } else { bend(head,s,size); return head; } }; a.arrowhead2=HookHead; a.gap=0.7; return a; } arrowhead3 HookHead3=HookHead3(); arrowhead3 TeXHead3; TeXHead3.size=TeXHead.size; TeXHead3.arcsize=TeXHead.size; TeXHead3.arrowhead2=TeXHead; TeXHead3.head=new surface(path3 g, position position=EndPoint, pen p=currentpen, real size=0, real angle=arrowangle, filltype filltype=null, bool forwards=true, projection P=currentprojection) { real texsize=TeXHead3.size(p); if(size == 0) size=texsize; bool relative=position.relative; real position=position.position.x; if(relative) position=reltime(g,position); path3 r=subpath(g,position,0); path3 s=subpath(r,arctime(r,size),0); bool straight1=length(s) == 1 && straight(g,0); surface head=surface(O,approach(subpath(path3(TeXHead.head((0,0)--(0,1),p, size), YZplane),5,0),8,1.5),Z); if(straight1) { triple v=point(s,0); triple u=point(s,1)-v; return shift(v)*align(unit(u))*head; } else { path3 s=subpath(r,arctime(r,size/texsize*arrowsize(p)),0); bend(head,s,size); return head; } }; path3 arrowbase(path3 r, triple y, real t, real size) { triple perp=2*size*perp(dir(r,t)); return size == 0 ? y : y+perp--y-perp; } arrowhead3 DefaultHead2(triple normal=O) { arrowhead3 a; a.head=new surface(path3 g, position position=EndPoint, pen p=currentpen, real size=0, real angle=arrowangle, filltype filltype=null, bool forwards=true, projection P=currentprojection) { if(size == 0) size=a.size(p); path h=a.project(g,forwards,P); a.size=min(size,arclength(h)); path[] H=a.align(DefaultHead.head(h,p,size,angle),h); H=forwards ? yscale(-1)*H : H; return a.surface(g,position,size,H,p,filltype,normal,P); }; a.gap=1.005; return a; } arrowhead3 DefaultHead2=DefaultHead2(); arrowhead3 HookHead2(real dir=arrowdir, real barb=arrowbarb, triple normal=O) { arrowhead3 a; a.head=new surface(path3 g, position position=EndPoint, pen p=currentpen, real size=0, real angle=arrowangle, filltype filltype=null, bool forwards=true, projection P=currentprojection) { if(size == 0) size=a.size(p); path h=a.project(g,forwards,P); a.size=min(size,arclength(h)); path[] H=a.align(HookHead.head(h,p,size,angle),h); H=forwards ? yscale(-1)*H : H; return a.surface(g,position,size,H,p,filltype,normal,P); }; a.arrowhead2=HookHead; a.gap=1.005; return a; } arrowhead3 HookHead2=HookHead2(); arrowhead3 TeXHead2(triple normal=O) { arrowhead3 a; a.head=new surface(path3 g, position position=EndPoint, pen p=currentpen, real size=0, real angle=arrowangle, filltype filltype=null, bool forwards=true, projection P=currentprojection) { if(size == 0) size=a.size(p); path h=a.project(g,forwards,P); a.size=min(size,arclength(h)); h=rotate(-degrees(dir(h,length(h)),warn=false))*h; path[] H=TeXHead.head(h,p,size,angle); H=forwards ? yscale(-1)*H : H; return a.surface(g,position,size,H,p, filltype == null ? TeXHead.defaultfilltype(p) : filltype, normal,P); }; a.arrowhead2=TeXHead; a.size=TeXHead.size; a.splitpath=false; a.gap=1.005; return a; } arrowhead3 TeXHead2=TeXHead2(); private real position(position position, real size, path3 g, bool center) { bool relative=position.relative; real position=position.position.x; if(relative) { position *= arclength(g); if(center) position += 0.5*size; position=arctime(g,position); } else if(center) position=arctime(g,arclength(subpath(g,0,position))+0.5*size); return position; } void drawarrow(picture pic, arrowhead3 arrowhead=DefaultHead3, path3 g, material p=currentpen, material arrowheadpen=nullpen, real size=0, real angle=arrowangle, position position=EndPoint, filltype filltype=null, bool forwards=true, margin3 margin=NoMargin3, bool center=false, light light=nolight, light arrowheadlight=currentlight, projection P=currentprojection) { pen q=(pen) p; if(filltype != null) { if(arrowheadpen == nullpen && filltype != null) arrowheadpen=filltype.fillpen; if(arrowheadpen == nullpen && filltype != null) arrowheadpen=filltype.drawpen; } if(arrowheadpen == nullpen) arrowheadpen=p; if(size == 0) size=arrowhead.size(q); size=min(arrowsizelimit*arclength(g),size); real position=position(position,size,g,center); g=margin(g,q).g; int L=length(g); if(!forwards) { g=reverse(g); position=L-position; } path3 r=subpath(g,position,0); size=min(arrowsizelimit*arclength(r),size); surface head=arrowhead.head(g,position,q,size,angle,filltype,forwards,P); if(arrowhead.size > 0) size=arrowhead.size; bool endpoint=position > L-sqrtEpsilon; if(arrowhead.splitpath || endpoint) { if(position > 0) { real Size=size*arrowhead.gap; draw(pic,subpath(r,arctime(r,Size),length(r)),p,light); } if(!endpoint) draw(pic,subpath(g,position,L),p,light); } else draw(pic,g,p,light); draw(pic,head,arrowheadpen,arrowheadlight); } void drawarrow2(picture pic, arrowhead3 arrowhead=DefaultHead3, path3 g, material p=currentpen, material arrowheadpen=nullpen, real size=0, real angle=arrowangle, filltype filltype=null, margin3 margin=NoMargin3, light light=nolight, light arrowheadlight=currentlight, projection P=currentprojection) { pen q=(pen) p; if(filltype != null) { if(arrowheadpen == nullpen && filltype != null) arrowheadpen=filltype.fillpen; if(arrowheadpen == nullpen && filltype != null) arrowheadpen=filltype.drawpen; } if(arrowheadpen == nullpen) arrowheadpen=p; if(size == 0) size=arrowhead.size(q); g=margin(g,q).g; size=min(arrow2sizelimit*arclength(g),size); path3 r=reverse(g); int L=length(g); real Size=size*arrowhead.gap; draw(pic,subpath(r,arctime(r,Size),L-arctime(g,Size)),p,light); draw(pic,arrowhead.head(g,L,q,size,angle,filltype,forwards=true,P), arrowheadpen,arrowheadlight); draw(pic,arrowhead.head(r,L,q,size,angle,filltype,forwards=false,P), arrowheadpen,arrowheadlight); } // Add to picture an estimate of the bounding box contribution of arrowhead // using the local slope at endpoint. void addArrow(picture pic, arrowhead3 arrowhead, path3 g, pen p, real size, real angle, filltype filltype, real position) { triple v=point(g,position); path3 g=v-(size+linewidth(p))*dir(g,position)--v; surface s=arrowhead.head(g,position,p,size,angle); if(s.s.length > 0) { pic.addPoint(v,min(s)-v); pic.addPoint(v,max(s)-v); } else pic.addPoint(v); } picture arrow(arrowhead3 arrowhead=DefaultHead3, path3 g, material p=currentpen, material arrowheadpen=p, real size=0, real angle=arrowangle, filltype filltype=null, position position=EndPoint, bool forwards=true, margin3 margin=NoMargin3, bool center=false, light light=nolight, light arrowheadlight=currentlight) { pen q=(pen) p; if(size == 0) size=arrowhead.size(q); picture pic; if(is3D()) pic.add(new void(frame f, transform3 t, picture pic2, projection P) { picture opic; drawarrow(opic,arrowhead,t*g,p,arrowheadpen,size,angle,position, filltype,forwards,margin,center,light,arrowheadlight,P); add(f,opic.fit3(identity4,pic2,P)); }); addPath(pic,g,q); real position=position(position,size,g,center); path3 G; if(!forwards) { G=reverse(g); position=length(g)-position; } else G=g; addArrow(pic,arrowhead,G,q,size,angle,filltype,position); return pic; } picture arrow2(arrowhead3 arrowhead=DefaultHead3, path3 g, material p=currentpen, material arrowheadpen=p, real size=0, real angle=arrowangle, filltype filltype=null, margin3 margin=NoMargin3, light light=nolight, light arrowheadlight=currentlight) { pen q=(pen) p; if(size == 0) size=arrowhead.size(q); picture pic; if(is3D()) pic.add(new void(frame f, transform3 t, picture pic2, projection P) { picture opic; drawarrow2(opic,arrowhead,t*g,p,arrowheadpen,size,angle,filltype, margin,light,arrowheadlight,P); add(f,opic.fit3(identity4,pic2,P)); }); addPath(pic,g,q); int L=length(g); addArrow(pic,arrowhead,g,q,size,angle,filltype,L); addArrow(pic,arrowhead,reverse(g),q,size,angle,filltype,L); return pic; } void add(picture pic, arrowhead3 arrowhead, real size, real angle, filltype filltype, position position, material arrowheadpen, path3 g, material p, bool forwards=true, margin3 margin, bool center=false, light light, light arrowheadlight) { add(pic,arrow(arrowhead,g,p,arrowheadpen,size,angle,filltype,position, forwards,margin,center,light,arrowheadlight)); if(!is3D()) { pic.add(new void(frame f, transform3 t, picture pic, projection P) { if(pic != null) { pen q=(pen) p; path3 G=t*g; marginT3 m=margin(G,q); add(pic,arrow(arrowhead.arrowhead2,project(G,P),q,size,angle, filltype == null ? arrowhead.arrowhead2.defaultfilltype ((pen) arrowheadpen) : filltype,position, forwards,TrueMargin(m.begin,m.end),center)); } },true); } } void add2(picture pic, arrowhead3 arrowhead, real size, real angle, filltype filltype, material arrowheadpen, path3 g, material p, margin3 margin, light light, light arrowheadlight) { add(pic,arrow2(arrowhead,g,p,arrowheadpen,size,angle,filltype,margin,light, arrowheadlight)); if(!is3D()) { pic.add(new void(frame f, transform3 t, picture pic, projection P) { if(pic != null) { pen q=(pen) p; path3 G=t*g; marginT3 m=margin(G,q); add(pic,arrow2(arrowhead.arrowhead2,project(G,P),q,size,angle, filltype == null ? arrowhead.arrowhead2.defaultfilltype ((pen) arrowheadpen) : filltype, TrueMargin(m.begin,m.end))); } },true); } } void bar(picture pic, triple a, triple d, triple perp=O, material p=currentpen, light light=nolight) { d *= 0.5; perp *= 0.5; pic.add(new void(frame f, transform3 t, picture pic2, projection P) { picture opic; triple A=t*a; triple v=d == O ? abs(perp)*unit(cross(P.normal,perp)) : d; draw(opic,A-v--A+v,p,light); add(f,opic.fit3(identity4,pic2,P)); }); triple v=d == O ? cross(currentprojection.normal,perp) : d; pen q=(pen) p; triple m=min3(q); triple M=max3(q); pic.addPoint(a,-v-m); pic.addPoint(a,-v+m); pic.addPoint(a,v-M); pic.addPoint(a,v+M); } picture bar(triple a, triple dir, triple perp=O, material p=currentpen) { picture pic; bar(pic,a,dir,perp,p); return pic; } typedef bool arrowbar3(picture, path3, material, margin3, light, light); bool Blank(picture, path3, material, margin3, light, light) { return false; } bool None(picture, path3, material, margin3, light, light) { return true; } arrowbar3 BeginArrow3(arrowhead3 arrowhead=DefaultHead3, real size=0, real angle=arrowangle, filltype filltype=null, position position=BeginPoint, material arrowheadpen=nullpen) { return new bool(picture pic, path3 g, material p, margin3 margin, light light, light arrowheadlight) { add(pic,arrowhead,size,angle,filltype,position,arrowheadpen,g,p, forwards=false,margin,light,arrowheadlight); return false; }; } arrowbar3 Arrow3(arrowhead3 arrowhead=DefaultHead3, real size=0, real angle=arrowangle, filltype filltype=null, position position=EndPoint, material arrowheadpen=nullpen) { return new bool(picture pic, path3 g, material p, margin3 margin, light light, light arrowheadlight) { add(pic,arrowhead,size,angle,filltype,position,arrowheadpen,g,p,margin, light,arrowheadlight); return false; }; } arrowbar3 EndArrow3(arrowhead3 arrowhead=DefaultHead3, real size=0, real angle=arrowangle, filltype filltype=null, position position=EndPoint, material arrowheadpen=nullpen)=Arrow3; arrowbar3 MidArrow3(arrowhead3 arrowhead=DefaultHead3, real size=0, real angle=arrowangle, filltype filltype=null, material arrowheadpen=nullpen) { return new bool(picture pic, path3 g, material p, margin3 margin, light light, light arrowheadlight) { add(pic,arrowhead,size,angle,filltype,MidPoint, arrowheadpen,g,p,margin,center=true,light,arrowheadlight); return false; }; } arrowbar3 Arrows3(arrowhead3 arrowhead=DefaultHead3, real size=0, real angle=arrowangle, filltype filltype=null, material arrowheadpen=nullpen) { return new bool(picture pic, path3 g, material p, margin3 margin, light light, light arrowheadlight) { add2(pic,arrowhead,size,angle,filltype,arrowheadpen,g,p,margin,light, arrowheadlight); return false; }; } arrowbar3 BeginArcArrow3(arrowhead3 arrowhead=DefaultHead3, real size=0, real angle=arcarrowangle, filltype filltype=null, position position=BeginPoint, material arrowheadpen=nullpen) { return new bool(picture pic, path3 g, material p, margin3 margin, light light, light arrowheadlight) { real size=size == 0 ? arrowhead.arcsize((pen) p) : size; add(pic,arrowhead,size,angle,filltype,position,arrowheadpen,g,p, forwards=false,margin,light,arrowheadlight); return false; }; } arrowbar3 ArcArrow3(arrowhead3 arrowhead=DefaultHead3, real size=0, real angle=arcarrowangle, filltype filltype=null, position position=EndPoint, material arrowheadpen=nullpen) { return new bool(picture pic, path3 g, material p, margin3 margin, light light, light arrowheadlight) { real size=size == 0 ? arrowhead.arcsize((pen) p) : size; add(pic,arrowhead,size,angle,filltype,position,arrowheadpen,g,p,margin, light,arrowheadlight); return false; }; } arrowbar3 EndArcArrow3(arrowhead3 arrowhead=DefaultHead3, real size=0, real angle=arcarrowangle, filltype filltype=null, position position=EndPoint, material arrowheadpen=nullpen)=ArcArrow3; arrowbar3 MidArcArrow3(arrowhead3 arrowhead=DefaultHead3, real size=0, real angle=arcarrowangle, filltype filltype=null, material arrowheadpen=nullpen) { return new bool(picture pic, path3 g, material p, margin3 margin, light light, light arrowheadlight) { real size=size == 0 ? arrowhead.arcsize((pen) p) : size; add(pic,arrowhead,size,angle,filltype,MidPoint,arrowheadpen,g,p,margin, center=true,light,arrowheadlight); return false; }; } arrowbar3 ArcArrows3(arrowhead3 arrowhead=DefaultHead3, real size=0, real angle=arcarrowangle, filltype filltype=null, material arrowheadpen=nullpen) { return new bool(picture pic, path3 g, material p, margin3 margin, light light, light arrowheadlight) { real size=size == 0 ? arrowhead.arcsize((pen) p) : size; add2(pic,arrowhead,size,angle,filltype,arrowheadpen,g,p,margin,light, arrowheadlight); return false; }; } arrowbar3 BeginBar3(real size=0, triple dir=O) { return new bool(picture pic, path3 g, material p, margin3 margin, light light, light) { real size=size == 0 ? barsize((pen) p) : size; bar(pic,point(g,0),size*unit(dir),size*dir(g,0),p,light); return true; }; } arrowbar3 Bar3(real size=0, triple dir=O) { return new bool(picture pic, path3 g, material p, margin3 margin, light light, light) { int L=length(g); real size=size == 0 ? barsize((pen) p) : size; bar(pic,point(g,L),size*unit(dir),size*dir(g,L),p,light); return true; }; } arrowbar3 EndBar3(real size=0, triple dir=O)=Bar3; arrowbar3 Bars3(real size=0, triple dir=O) { return new bool(picture pic, path3 g, material p, margin3 margin, light light, light) { real size=size == 0 ? barsize((pen) p) : size; BeginBar3(size,dir)(pic,g,p,margin,light,nolight); EndBar3(size,dir)(pic,g,p,margin,light,nolight); return true; }; } arrowbar3 BeginArrow3=BeginArrow3(), MidArrow3=MidArrow3(), Arrow3=Arrow3(), EndArrow3=Arrow3(), Arrows3=Arrows3(), BeginArcArrow3=BeginArcArrow3(), MidArcArrow3=MidArcArrow3(), ArcArrow3=ArcArrow3(), EndArcArrow3=ArcArrow3(), ArcArrows3=ArcArrows3(), BeginBar3=BeginBar3(), Bar3=Bar3(), EndBar3=Bar3(), Bars3=Bars3(); asymptote-2.37/base/three_light.asy000066400000000000000000000067111265434602500174340ustar00rootroot00000000000000struct material { pen[] p; // diffusepen,ambientpen,emissivepen,specularpen real opacity; real shininess; void operator init(pen diffusepen=black, pen ambientpen=black, pen emissivepen=black, pen specularpen=mediumgray, real opacity=opacity(diffusepen), real shininess=defaultshininess) { p=new pen[] {diffusepen,ambientpen,emissivepen,specularpen}; this.opacity=opacity; this.shininess=shininess; } void operator init(material m) { p=copy(m.p); opacity=m.opacity; shininess=m.shininess; } pen diffuse() {return p[0];} pen ambient() {return p[1];} pen emissive() {return p[2];} pen specular() {return p[3];} void diffuse(pen q) {p[0]=q;} void ambient(pen q) {p[1]=q;} void emissive(pen q) {p[2]=q;} void specular(pen q) {p[3]=q;} } material operator init() { return material(); } void write(file file, string s="", material x, suffix suffix=none) { write(file,s); write(file,"{"); write(file,"diffuse=",x.diffuse()); write(file,", ambient=",x.ambient()); write(file,", emissive=",x.emissive()); write(file,", specular=",x.specular()); write(file,", opacity=",x.opacity); write(file,", shininess=",x.shininess); write(file,"}",suffix); } void write(string s="", material x, suffix suffix=endl) { write(stdout,s,x,suffix); } bool operator == (material m, material n) { return all(m.p == n.p) && m.opacity == n.opacity && m.shininess == n.shininess; } material operator cast(pen p) { return material(p); } material[] operator cast(pen[] p) { return sequence(new material(int i) {return p[i];},p.length); } pen operator ecast(material m) { return m.p.length > 0 ? m.diffuse() : nullpen; } material emissive(material m) { return material(black+opacity(m.opacity),black,m.diffuse(),black,m.opacity,1); } pen color(triple normal, material m, light light, transform3 T=light.T) { triple[] position=light.position; if(invisible((pen) m)) return invisible; if(position.length == 0) return m.diffuse(); normal=unit(transpose(inverse(shiftless(T)))*normal); if(settings.twosided) normal *= sgn(normal.z); real s=m.shininess*128; real[] Diffuse=rgba(m.diffuse()); real[] Ambient=rgba(m.ambient()); real[] Specular=rgba(m.specular()); real[] p=rgba(m.emissive()); for(int i=0; i < position.length; ++i) { triple L=light.viewport ? position[i] : T*position[i]; real Ldotn=max(dot(normal,L),0); p += light.ambient[i]*Ambient+Ldotn*light.diffuse[i]*Diffuse; // Apply specularfactor to partially compensate non-pixel-based rendering. if(Ldotn > 0) // Phong-Blinn model of specular reflection p += dot(normal,unit(L+Z))^s*light.specularfactor* light.specular[i]*Specular; } return rgb(p[0],p[1],p[2])+opacity(opacity(m.diffuse())); } light operator * (transform3 t, light light) { light light=light(light); if(!light.viewport) light.position=shiftless(t)*light.position; return light; } light operator cast(triple v) {return light(v);} light Viewport=light(ambient=gray(0.1),specularfactor=3,viewport=true, (0.25,-0.25,1)); light White=light(new pen[] {rgb(0.38,0.38,0.45),rgb(0.6,0.6,0.67), rgb(0.5,0.5,0.57)},specularfactor=3, new triple[] {(-2,-1.5,-0.5),(2,1.1,-2.5),(-0.5,0,2)}); light Headlamp=light(gray(0.8),ambient=gray(0.1),specular=gray(0.7), specularfactor=3,viewport=true,dir(42,48)); currentlight=Headlamp; light nolight; asymptote-2.37/base/three_margins.asy000066400000000000000000000053141265434602500177630ustar00rootroot00000000000000struct marginT3 { path3 g; real begin,end; }; typedef marginT3 margin3(path3, pen); path3 trim(path3 g, real begin, real end) { real a=arctime(g,begin); real b=arctime(g,arclength(g)-end); return a <= b ? subpath(g,a,b) : point(g,a); } margin3 operator +(margin3 ma, margin3 mb) { return new marginT3(path3 g, pen p) { marginT3 margin; real ba=ma(g,p).begin < 0 ? 0 : ma(g,p).begin; real bb=mb(g,p).begin < 0 ? 0 : mb(g,p).begin; real ea=ma(g,p).end < 0 ? 0 : ma(g,p).end; real eb=mb(g,p).end < 0 ? 0 : mb(g,p).end; margin.begin=ba+bb; margin.end=ea+eb; margin.g=trim(g,margin.begin,margin.end); return margin; }; } margin3 NoMargin3() { return new marginT3(path3 g, pen) { marginT3 margin; margin.begin=margin.end=0; margin.g=g; return margin; }; } margin3 Margin3(real begin, real end) { return new marginT3(path3 g, pen p) { marginT3 margin; real factor=labelmargin(p); real w=0.5*linewidth(p); margin.begin=begin*factor-w; margin.end=end*factor-w; margin.g=trim(g,margin.begin,margin.end); return margin; }; } margin3 PenMargin3(real begin, real end) { return new marginT3(path3 g, pen p) { marginT3 margin; real factor=linewidth(p); margin.begin=begin*factor; margin.end=end*factor; margin.g=trim(g,margin.begin,margin.end); return margin; }; } margin3 DotMargin3(real begin, real end) { return new marginT3(path3 g, pen p) { marginT3 margin; real margindot(real x) {return x > 0 ? dotfactor*x : x;} real factor=linewidth(p); margin.begin=margindot(begin)*factor; margin.end=margindot(end)*factor; margin.g=trim(g,margin.begin,margin.end); return margin; }; } margin3 TrueMargin3(real begin, real end) { return new marginT3(path3 g, pen p) { marginT3 margin; margin.begin=begin; margin.end=end; margin.g=trim(g,begin,end); return margin; }; } margin3 NoMargin3=NoMargin3(), BeginMargin3=Margin3(1,0), Margin3=Margin3(0,1), EndMargin3=Margin3, Margins3=Margin3(1,1), BeginPenMargin3=PenMargin3(0.5,-0.5), BeginPenMargin2=PenMargin3(1.0,-0.5), PenMargin3=PenMargin3(-0.5,0.5), PenMargin2=PenMargin3(-0.5,1.0), EndPenMargin3=PenMargin3, EndPenMargin2=PenMargin2, PenMargins3=PenMargin3(0.5,0.5), PenMargins2=PenMargin3(1.0,1.0), BeginDotMargin3=DotMargin3(0.5,-0.5), DotMargin3=DotMargin3(-0.5,0.5), EndDotMargin3=DotMargin3, DotMargins3=DotMargin3(0.5,0.5); asymptote-2.37/base/three_surface.asy000066400000000000000000002124541265434602500177600ustar00rootroot00000000000000import bezulate; private import interpolate; int nslice=12; real camerafactor=1.2; string meshname(string name) {return name+" mesh";} private real Fuzz=10.0*realEpsilon; private real nineth=1/9; // Return the default Coons interior control point for a Bezier triangle // based on the cyclic path3 external. triple coons3(path3 external) { return 0.25*(precontrol(external,0)+postcontrol(external,0)+ precontrol(external,1)+postcontrol(external,1)+ precontrol(external,2)+postcontrol(external,2))- (point(external,0)+point(external,1)+point(external,2))/6; } struct patch { triple[][] P; pen[] colors; // Optionally specify 4 corner colors. bool straight; // Patch is based on a piecewise straight external path. bool3 planar; // Patch is planar. bool triangular; // Patch is a Bezier triangle. path3 external() { return straight ? P[0][0]--P[3][0]--P[3][3]--P[0][3]--cycle : P[0][0]..controls P[1][0] and P[2][0].. P[3][0]..controls P[3][1] and P[3][2].. P[3][3]..controls P[2][3] and P[1][3].. P[0][3]..controls P[0][2] and P[0][1]..cycle; } path3 externaltriangular() { return P[0][0]..controls P[1][0] and P[2][0].. P[3][0]..controls P[3][1] and P[3][2].. P[3][3]..controls P[2][2] and P[1][1]..cycle; } triple[] internal() { return new triple[] {P[1][1],P[2][1],P[2][2],P[1][2]}; } triple[] internaltriangular() { return new triple[] {P[2][1]}; } triple cornermean() { return 0.25*(P[0][0]+P[0][3]+P[3][0]+P[3][3]); } triple cornermeantriangular() { return (P[0][0]+P[3][0]+P[3][3])/3; } triple[] corners() {return new triple[] {P[0][0],P[3][0],P[3][3],P[0][3]};} triple[] cornerstriangular() {return new triple[] {P[0][0],P[3][0],P[3][3]};} real[] map(real f(triple)) { return new real[] {f(P[0][0]),f(P[3][0]),f(P[3][3]),f(P[0][3])}; } real[] maptriangular(real f(triple)) { return new real[] {f(P[0][0]),f(P[3][0]),f(P[3][3])}; } triple Bu(int j, real u) {return bezier(P[0][j],P[1][j],P[2][j],P[3][j],u);} triple BuP(int j, real u) {return bezierP(P[0][j],P[1][j],P[2][j],P[3][j],u);} triple BuPP(int j, real u) { return bezierPP(P[0][j],P[1][j],P[2][j],P[3][j],u); } triple BuPPP(int j) {return bezierPPP(P[0][j],P[1][j],P[2][j],P[3][j]);} path3 uequals(real u) { triple z0=Bu(0,u); triple z1=Bu(3,u); return path3(new triple[] {z0,Bu(2,u)},new triple[] {z0,z1}, new triple[] {Bu(1,u),z1},new bool[] {straight,false},false); } triple Bv(int i, real v) {return bezier(P[i][0],P[i][1],P[i][2],P[i][3],v);} triple BvP(int i, real v) {return bezierP(P[i][0],P[i][1],P[i][2],P[i][3],v);} triple BvPP(int i, real v) { return bezierPP(P[i][0],P[i][1],P[i][2],P[i][3],v); } triple BvPPP(int i) {return bezierPPP(P[i][0],P[i][1],P[i][2],P[i][3]);} path3 vequals(real v) { triple z0=Bv(0,v); triple z1=Bv(3,v); return path3(new triple[] {z0,Bv(2,v)},new triple[] {z0,z1}, new triple[] {Bv(1,v),z1},new bool[] {straight,false},false); } triple point(real u, real v) { return bezier(Bu(0,u),Bu(1,u),Bu(2,u),Bu(3,u),v); } triple pointtriangular(real u, real v) { real w=1-u-v; return w^2*(w*P[0][0]+3*(u*P[1][0]+v*P[1][1]))+ u^2*(u*P[3][0]+3*(w*P[2][0]+v*P[3][1]))+ 6*u*v*w*P[2][1]+v^2*(v*P[3][3]+3*(w*P[2][2]+u*P[3][2])); } // compute normal vectors for degenerate cases private triple normal0(real u, real v, real epsilon) { triple n=0.5*(cross(bezier(BuPP(0,u),BuPP(1,u),BuPP(2,u),BuPP(3,u),v), bezier(BvP(0,v),BvP(1,v),BvP(2,v),BvP(3,v),u))+ cross(bezier(BuP(0,u),BuP(1,u),BuP(2,u),BuP(3,u),v), bezier(BvPP(0,v),BvPP(1,v),BvPP(2,v),BvPP(3,v),u))); return abs(n) > epsilon ? n : 0.25*cross(bezier(BuPP(0,u),BuPP(1,u),BuPP(2,u),BuPP(3,u),v), bezier(BvPP(0,v),BvPP(1,v),BvPP(2,v),BvPP(3,v),u))+ 1/6*(cross(bezier(BuP(0,u),BuP(1,u),BuP(2,u),BuP(3,u),v), bezier(BvPPP(0),BvPPP(1),BvPPP(2),BvPPP(3),u))+ cross(bezier(BuPPP(0),BuPPP(1),BuPPP(2),BuPPP(3),v), bezier(BvP(0,v),BvP(1,v),BvP(2,v),BvP(3,v),u)))+ 1/12*(cross(bezier(BuPPP(0),BuPPP(1),BuPPP(2),BuPPP(3),v), bezier(BvPP(0,v),BvPP(1,v),BvPP(2,v),BvPP(3,v),u))+ cross(bezier(BuPP(0,u),BuPP(1,u),BuPP(2,u),BuPP(3,u),v), bezier(BvPPP(0),BvPPP(1),BvPPP(2),BvPPP(3),u)))+ 1/36*cross(bezier(BuPPP(0),BuPPP(1),BuPPP(2),BuPPP(3),v), bezier(BvPPP(0),BvPPP(1),BvPPP(2),BvPPP(3),u)); } static real fuzz=1000*realEpsilon; triple partialu(real u, real v) { return bezier(BuP(0,u),BuP(1,u),BuP(2,u),BuP(3,u),v); } triple partialv(real u, real v) { return bezier(BvP(0,v),BvP(1,v),BvP(2,v),BvP(3,v),u); } triple normal(real u, real v) { triple n=cross(partialu(u,v),partialv(u,v)); real epsilon=fuzz*change2(P); return (abs(n) > epsilon) ? n : normal0(u,v,epsilon); } triple normal00() { triple n=9*cross(P[1][0]-P[0][0],P[0][1]-P[0][0]); real epsilon=fuzz*change2(P); return abs(n) > epsilon ? n : normal0(0,0,epsilon); } triple normal10() { triple n=9*cross(P[3][0]-P[2][0],P[3][1]-P[3][0]); real epsilon=fuzz*change2(P); return abs(n) > epsilon ? n : normal0(1,0,epsilon); } triple normal11() { triple n=9*cross(P[3][3]-P[2][3],P[3][3]-P[3][2]); real epsilon=fuzz*change2(P); return abs(n) > epsilon ? n : normal0(1,1,epsilon); } triple normal01() { triple n=9*cross(P[1][3]-P[0][3],P[0][3]-P[0][2]); real epsilon=fuzz*change2(P); return abs(n) > epsilon ? n : normal0(0,1,epsilon); } triple normal00triangular() { triple n=9*cross(P[1][0]-P[0][0],P[1][1]-P[0][0]); real epsilon=fuzz*change2(P); return abs(n) > epsilon ? n : normal0(0,0,epsilon); } triple normal10triangular() { triple n=9*cross(P[3][0]-P[2][0],P[3][1]-P[2][0]); real epsilon=fuzz*change2(P); return abs(n) > epsilon ? n : normal0(1,0,epsilon); } triple normal01triangular() { triple n=9*cross(P[3][2]-P[2][2],P[3][3]-P[2][2]); real epsilon=fuzz*change2(P); return abs(n) > epsilon ? n : normal0(0,1,epsilon); } // Compute one-third of the directional derivative of a Bezier triangle in the u // direction at point (u,v). private triple bu(real u, real v) { real w=1-u-v; return u*(w*2-u)*P[2][0]+2*v*(w-u)*P[2][1]+w*(w-2*u)*P[1][0]+ u*(u*P[3][0]+2*v*P[3][1])+v*v*P[3][2]-w*(2*v*P[1][1]+w*P[0][0])- v*v*P[2][2]; } // Compute one-third of the directional derivative of a Bezier triangle in the v // direction at point (u,v). private triple bv(real u, real v) { real w=1-u-v; return u*2*(w-v)*P[2][1]+v*(2*w-v)*P[2][2]+w*(w-2*v)*P[1][1]+ u*(u*P[3][1]+2*v*P[3][2])+v*v*P[3][3]-w*(2*u*P[1][0]+w*P[0][0])- u*u*P[2][0]; } // Compute the normal of a Bezier triangle at (u,v) triple normaltriangular(real u, real v) { // TODO: handle degeneracy return 9*cross(bu(u,v),bv(u,v)); } pen[] colors(material m, light light=currentlight) { bool nocolors=colors.length == 0; if(planar) { triple normal=normal(0.5,0.5); return new pen[] {color(normal,nocolors ? m : colors[0],light), color(normal,nocolors ? m : colors[1],light), color(normal,nocolors ? m : colors[2],light), color(normal,nocolors ? m : colors[3],light)}; } return new pen[] {color(normal00(),nocolors ? m : colors[0],light), color(normal10(),nocolors ? m : colors[1],light), color(normal11(),nocolors ? m : colors[2],light), color(normal01(),nocolors ? m : colors[3],light)}; } pen[] colorstriangular(material m, light light=currentlight) { bool nocolors=colors.length == 0; if(planar) { triple normal=normal(1/3,1/3); return new pen[] {color(normal,nocolors ? m : colors[0],light), color(normal,nocolors ? m : colors[1],light), color(normal,nocolors ? m : colors[2],light)}; } return new pen[] {color(normal00(),nocolors ? m : colors[0],light), color(normal10(),nocolors ? m : colors[1],light), color(normal01(),nocolors ? m : colors[2],light)}; } triple min3,max3; bool havemin3,havemax3; void init() { havemin3=false; havemax3=false; if(triangular) { external=externaltriangular; internal=internaltriangular; cornermean=cornermeantriangular; corners=cornerstriangular; map=maptriangular; point=pointtriangular; normal=normaltriangular; normal00=normal00triangular; normal10=normal10triangular; normal01=normal01triangular; colors=colorstriangular; } } triple min(triple bound=P[0][0]) { if(havemin3) return minbound(min3,bound); havemin3=true; return min3=minbezier(P,bound); } triple max(triple bound=P[0][0]) { if(havemax3) return maxbound(max3,bound); havemax3=true; return max3=maxbezier(P,bound); } triple center() { return 0.5*(this.min()+this.max()); } pair min(projection P, pair bound=project(this.P[0][0],P.t)) { triple[][] Q=P.T.modelview*this.P; if(P.infinity) return xypart(minbezier(Q,(bound.x,bound.y,0))); real d=P.T.projection[3][2]; return maxratio(Q,d*bound)/d; // d is negative } pair max(projection P, pair bound=project(this.P[0][0],P.t)) { triple[][] Q=P.T.modelview*this.P; if(P.infinity) return xypart(maxbezier(Q,(bound.x,bound.y,0))); real d=P.T.projection[3][2]; return minratio(Q,d*bound)/d; // d is negative } void operator init(triple[][] P, pen[] colors=new pen[], bool straight=false, bool3 planar=default, bool triangular=false, bool copy=true) { this.P=copy ? copy(P) : P; if(colors.length != 0) this.colors=copy(colors); this.straight=straight; this.planar=planar; this.triangular=triangular; init(); } void operator init(pair[][] P, triple plane(pair)=XYplane, bool straight=false, bool triangular=false) { triple[][] Q=new triple[4][]; for(int i=0; i < 4; ++i) { pair[] Pi=P[i]; Q[i]=sequence(new triple(int j) {return plane(Pi[j]);},4); } operator init(Q,straight,planar=true,triangular); } void operator init(patch s) { operator init(s.P,s.colors,s.straight,s.planar,s.triangular); } // A constructor for a cyclic path3 of length 3 with a specified // internal point, corner normals, and pens (rendered as a Bezier triangle). void operator init(path3 external, triple internal, pen[] colors=new pen[], bool3 planar=default) { triangular=true; this.planar=planar; init(); if(colors.length != 0) this.colors=copy(colors); P=new triple[][] { {point(external,0)}, {postcontrol(external,0),precontrol(external,0)}, {precontrol(external,1),internal,postcontrol(external,2)}, {point(external,1),postcontrol(external,1),precontrol(external,2), point(external,2)} }; } // A constructor for a convex cyclic path3 of length <= 4 with optional // arrays of internal points (4 for a Bezier patch, 1 for a Bezier // triangle), and pens. void operator init(path3 external, triple[] internal=new triple[], pen[] colors=new pen[], bool3 planar=default) { if(internal.length == 0 && planar == default) this.planar=normal(external) != O; else this.planar=planar; int L=length(external); if(L == 3) { operator init(external,internal.length == 1 ? internal[0] : coons3(external),colors,this.planar); straight=piecewisestraight(external); return; } if(L > 4 || !cyclic(external)) abort("cyclic path3 of length <= 4 expected"); if(L == 1) { external=external--cycle--cycle--cycle; if(colors.length > 0) colors.append(array(3,colors[0])); } else if(L == 2) { external=external--cycle--cycle; if(colors.length > 0) colors.append(array(2,colors[0])); } init(); if(colors.length != 0) this.colors=copy(colors); if(internal.length == 0) { straight=piecewisestraight(external); internal=new triple[4]; for(int j=0; j < 4; ++j) internal[j]=nineth*(-4*point(external,j) +6*(precontrol(external,j)+postcontrol(external,j)) -2*(point(external,j-1)+point(external,j+1)) +3*(precontrol(external,j-1)+ postcontrol(external,j+1)) -point(external,j+2)); } P=new triple[][] { {point(external,0),precontrol(external,0),postcontrol(external,3), point(external,3)}, {postcontrol(external,0),internal[0],internal[3],precontrol(external,3)}, {precontrol(external,1),internal[1],internal[2],postcontrol(external,2)}, {point(external,1),postcontrol(external,1),precontrol(external,2), point(external,2)} }; } // A constructor for a convex quadrilateral. void operator init(triple[] external, triple[] internal=new triple[], pen[] colors=new pen[], bool3 planar=default) { init(); if(internal.length == 0 && planar == default) this.planar=normal(external) != O; else this.planar=planar; if(colors.length != 0) this.colors=copy(colors); if(internal.length == 0) { internal=new triple[4]; for(int j=0; j < 4; ++j) internal[j]=nineth*(4*external[j]+2*external[(j+1)%4]+ external[(j+2)%4]+2*external[(j+3)%4]); } straight=true; triple delta[]=new triple[4]; for(int j=0; j < 4; ++j) delta[j]=(external[(j+1)% 4]-external[j])/3; P=new triple[][] { {external[0],external[0]-delta[3],external[3]+delta[3],external[3]}, {external[0]+delta[0],internal[0],internal[3],external[3]-delta[2]}, {external[1]-delta[0],internal[1],internal[2],external[2]+delta[2]}, {external[1],external[1]+delta[1],external[2]-delta[1],external[2]} }; } } patch operator * (transform3 t, patch s) { patch S; S.P=new triple[s.P.length][]; for(int i=0; i < s.P.length; ++i) { triple[] si=s.P[i]; triple[] Si=S.P[i]; for(int j=0; j < si.length; ++j) Si[j]=t*si[j]; } S.colors=copy(s.colors); S.planar=s.planar; S.straight=s.straight; S.triangular=s.triangular; S.init(); return S; } patch reverse(patch s) { assert(!s.triangular); patch S; S.P=transpose(s.P); if(s.colors.length > 0) S.colors=new pen[] {s.colors[0],s.colors[3],s.colors[2],s.colors[1]}; S.straight=s.straight; S.planar=s.planar; return S; } // Return a degenerate tensor patch representation of a Bezier triangle. patch tensor(patch s) { if(!s.triangular) return patch(s); triple[][] P=s.P; return patch(new triple[][] {{P[0][0],P[0][0],P[0][0],P[0][0]}, {P[1][0],P[1][0]*2/3+P[1][1]/3,P[1][0]/3+P[1][1]*2/3,P[1][1]}, {P[2][0],P[2][0]/3+P[2][1]*2/3,P[2][1]*2/3+P[2][2]/3,P[2][2]}, {P[3][0],P[3][1],P[3][2],P[3][3]}}, s.colors.length > 0 ? new pen[] {s.colors[0],s.colors[1],s.colors[2],s.colors[0]} : new pen[], s.straight,s.planar,false,false); } // Return the tensor product patch control points corresponding to path p // and points internal. pair[][] tensor(path p, pair[] internal) { return new pair[][] { {point(p,0),precontrol(p,0),postcontrol(p,3),point(p,3)}, {postcontrol(p,0),internal[0],internal[3],precontrol(p,3)}, {precontrol(p,1),internal[1],internal[2],postcontrol(p,2)}, {point(p,1),postcontrol(p,1),precontrol(p,2),point(p,2)} }; } // Return the Coons patch control points corresponding to path p. pair[][] coons(path p) { int L=length(p); if(L == 1) p=p--cycle--cycle--cycle; else if(L == 2) p=p--cycle--cycle; else if(L == 3) p=p--cycle; pair[] internal=new pair[4]; for(int j=0; j < 4; ++j) { internal[j]=nineth*(-4*point(p,j) +6*(precontrol(p,j)+postcontrol(p,j)) -2*(point(p,j-1)+point(p,j+1)) +3*(precontrol(p,j-1)+postcontrol(p,j+1)) -point(p,j+2)); } return tensor(p,internal); } // Decompose a possibly nonconvex cyclic path into an array of paths that // yield nondegenerate Coons patches. path[] regularize(path p, bool checkboundary=true) { path[] s; if(!cyclic(p)) abort("cyclic path expected"); int L=length(p); if(L > 4) { for(path g : bezulate(p)) s.append(regularize(g,checkboundary)); return s; } bool straight=piecewisestraight(p); if(L <= 3 && straight) { return new path[] {p}; } // Split p along the angle bisector at t. bool split(path p, real t) { pair dir=dir(p,t); if(dir != 0) { path g=subpath(p,t,t+length(p)); int L=length(g); pair z=point(g,0); real[] T=intersections(g,z,z+I*dir); for(int i=0; i < T.length; ++i) { real cut=T[i]; if(cut > sqrtEpsilon && cut < L-sqrtEpsilon) { pair w=point(g,cut); if(!inside(p,0.5*(z+w),zerowinding)) continue; pair delta=sqrtEpsilon*(w-z); if(intersections(g,z-delta--w+delta).length != 2) continue; s.append(regularize(subpath(g,0,cut)--cycle,checkboundary)); s.append(regularize(subpath(g,cut,L)--cycle,checkboundary)); return true; } } } return false; } // Ensure that all interior angles are less than 180 degrees. real fuzz=1e-4; int sign=sgn(windingnumber(p,inside(p,zerowinding))); for(int i=0; i < L; ++i) { if(sign*(conj(dir(p,i,-1))*dir(p,i,1)).y < -fuzz) { if(split(p,i)) return s; } } if(straight) return new path[] {p}; pair[][] P=coons(p); // Check for degeneracy. pair[][] U=new pair[3][4]; pair[][] V=new pair[4][3]; for(int i=0; i < 3; ++i) { for(int j=0; j < 4; ++j) U[i][j]=P[i+1][j]-P[i][j]; } for(int i=0; i < 4; ++i) { for(int j=0; j < 3; ++j) V[i][j]=P[i][j+1]-P[i][j]; } int[] choose2={1,2,1}; int[] choose3={1,3,3,1}; real T[][]=new real[6][6]; for(int p=0; p < 6; ++p) { int kstart=max(p-2,0); int kstop=min(p,3); real[] Tp=T[p]; for(int q=0; q < 6; ++q) { real Tpq; int jstop=min(q,3); int jstart=max(q-2,0); for(int k=kstart; k <= kstop; ++k) { int choose3k=choose3[k]; for(int j=jstart; j <= jstop; ++j) { int i=p-k; int l=q-j; Tpq += (conj(U[i][j])*V[k][l]).y* choose2[i]*choose3k*choose3[j]*choose2[l]; } } Tp[q]=Tpq; } } bool3 aligned=default; bool degenerate=false; for(int p=0; p < 6; ++p) { for(int q=0; q < 6; ++q) { if(aligned == default) { if(T[p][q] > sqrtEpsilon) aligned=true; if(T[p][q] < -sqrtEpsilon) aligned=false; } else { if((T[p][q] > sqrtEpsilon && aligned == false) || (T[p][q] < -sqrtEpsilon && aligned == true)) degenerate=true; } } } if(!degenerate) { if(aligned == (sign >= 0)) return new path[] {p}; return s; } if(checkboundary) { // Polynomial coefficients of (B_i'' B_j + B_i' B_j')/3. static real[][][] fpv0={ {{5, -20, 30, -20, 5}, {-3, 24, -54, 48, -15}, {0, -6, 27, -36, 15}, {0, 0, -3, 8, -5}}, {{-7, 36, -66, 52, -15}, {3, -36, 108, -120, 45}, {0, 6, -45, 84, -45}, {0, 0, 3, -16, 15}}, {{2, -18, 45, -44, 15}, {0, 12, -63, 96, -45}, {0, 0, 18, -60, 45}, {0, 0, 0, 8, -15}}, {{0, 2, -9, 12, -5}, {0, 0, 9, -24, 15}, {0, 0, 0, 12, -15}, {0, 0, 0, 0, 5}} }; // Compute one-ninth of the derivative of the Jacobian along the boundary. real[][] c=array(4,array(5,0.0)); for(int i=0; i < 4; ++i) { real[][] fpv0i=fpv0[i]; for(int j=0; j < 4; ++j) { real[] w=fpv0i[j]; c[0] += w*(conj(P[i][0])*(P[j][1]-P[j][0])).y; // v=0 c[1] += w*(conj(P[3][j]-P[2][j])*P[3][i]).y; // u=1 c[2] += w*(conj(P[i][3])*(P[j][3]-P[j][2])).y; // v=1 c[3] += w*(conj(P[0][j]-P[1][j])*P[0][i]).y; // u=0 } } pair BuP(int j, real u) { return bezierP(P[0][j],P[1][j],P[2][j],P[3][j],u); } pair BvP(int i, real v) { return bezierP(P[i][0],P[i][1],P[i][2],P[i][3],v); } real normal(real u, real v) { return (conj(bezier(BuP(0,u),BuP(1,u),BuP(2,u),BuP(3,u),v))* bezier(BvP(0,v),BvP(1,v),BvP(2,v),BvP(3,v),u)).y; } // Use Rolle's theorem to check for degeneracy on the boundary. real M=0; real cut; for(int i=0; i < 4; ++i) { if(!straight(p,i)) { real[] ci=c[i]; pair[] R=quarticroots(ci[4],ci[3],ci[2],ci[1],ci[0]); for(pair r : R) { if(fabs(r.y) < sqrtEpsilon) { real t=r.x; if(0 <= t && t <= 1) { real[] U={t,1,t,0}; real[] V={0,t,1,t}; real[] T={t,t,1-t,1-t}; real N=sign*normal(U[i],V[i]); if(N < M) { M=N; cut=i+T[i]; } } } } } } // Split at the worst boundary degeneracy. if(M < 0 && split(p,cut)) return s; } // Split arbitrarily to resolve any remaining (internal) degeneracy. checkboundary=false; for(int i=0; i < L; ++i) if(!straight(p,i) && split(p,i+0.5)) return s; while(true) for(int i=0; i < L; ++i) if(!straight(p,i) && split(p,i+unitrand())) return s; return s; } struct surface { patch[] s; int index[][];// Position of patch corresponding to major U,V parameter in s. bool vcyclic; bool empty() { return s.length == 0; } void operator init(int n) { s=new patch[n]; } void operator init(... patch[] s) { this.s=s; } void operator init(surface s) { this.s=new patch[s.s.length]; for(int i=0; i < s.s.length; ++i) this.s[i]=patch(s.s[i]); this.index=copy(s.index); this.vcyclic=s.vcyclic; } void operator init(triple[][][] P, pen[][] colors=new pen[][], bool3 planar=default, bool triangular=false) { s=sequence(new patch(int i) { return patch(P[i],colors.length == 0 ? new pen[] : colors[i],planar, triangular); },P.length); } void colors(pen[][] palette) { for(int i=0; i < s.length; ++i) s[i].colors=copy(palette[i]); } triple[][] corners() { triple[][] a=new triple[s.length][]; for(int i=0; i < s.length; ++i) a[i]=s[i].corners(); return a; } real[][] map(real f(triple)) { real[][] a=new real[s.length][]; for(int i=0; i < s.length; ++i) a[i]=s[i].map(f); return a; } triple[] cornermean() { return sequence(new triple(int i) {return s[i].cornermean();},s.length); } triple point(real u, real v) { int U=floor(u); int V=floor(v); int index=index.length == 0 ? U+V : index[U][V]; return s[index].point(u-U,v-V); } triple normal(real u, real v) { int U=floor(u); int V=floor(v); int index=index.length == 0 ? U+V : index[U][V]; return s[index].normal(u-U,v-V); } void ucyclic(bool f) { index.cyclic=f; } void vcyclic(bool f) { for(int[] i : index) i.cyclic=f; vcyclic=f; } bool ucyclic() { return index.cyclic; } bool vcyclic() { return vcyclic; } path3 uequals(real u) { if(index.length == 0) return nullpath3; int U=floor(u); int[] index=index[U]; path3 g; for(int i : index) g=g&s[i].uequals(u-U); return vcyclic() ? g&cycle : g; } path3 vequals(real v) { if(index.length == 0) return nullpath3; int V=floor(v); path3 g; for(int[] i : index) g=g&s[i[V]].vequals(v-V); return ucyclic() ? g&cycle : g; } // A constructor for a possibly nonconvex simple cyclic path in a given plane. void operator init(path p, triple plane(pair)=XYplane) { bool straight=piecewisestraight(p); for(path g : regularize(p)) { if(length(g) == 3) { path3 G=path3(g,plane); s.push(patch(G,coons3(G))); } else s.push(patch(coons(g),plane,straight)); } } void operator init(explicit path[] g, triple plane(pair)=XYplane) { for(path p : bezulate(g)) s.append(surface(p,plane).s); } // A general surface constructor for both planar and nonplanar 3D paths. void construct(path3 external, triple[] internal=new triple[], pen[] colors=new pen[], bool3 planar=default) { int L=length(external); if(!cyclic(external)) abort("cyclic path expected"); if(L <= 3 && piecewisestraight(external)) { s.push(patch(external,internal,colors,planar)); return; } // Construct a surface from a possibly nonconvex planar cyclic path3. if(planar != false && internal.length == 0 && colors.length == 0) { triple n=normal(external); if(n != O) { transform3 T=align(n); external=transpose(T)*external; T *= shift(0,0,point(external,0).z); for(patch p : surface(path(external)).s) s.push(T*p); return; } } if(L <= 4 || internal.length > 0) { s.push(patch(external,internal,colors,planar)); return; } // Path is not planar; split into patches. real factor=1/L; pen[] p; triple[] n; bool nocolors=colors.length == 0; triple center; for(int i=0; i < L; ++i) center += point(external,i); center *= factor; if(!nocolors) p=new pen[] {mean(colors)}; // Use triangles for nonplanar surfaces. int step=normal(external) == O ? 1 : 2; int i=0; int end; while((end=i+step) < L) { s.push(patch(subpath(external,i,end)--center--cycle, nocolors ? p : concat(colors[i:end+1],p),planar)); i=end; } s.push(patch(subpath(external,i,L)--center--cycle, nocolors ? p : concat(colors[i:],colors[0:1],p),planar)); } void operator init(path3 external, triple[] internal=new triple[], pen[] colors=new pen[], bool3 planar=default) { s=new patch[]; construct(external,internal,colors,planar); } void operator init(explicit path3[] external, triple[][] internal=new triple[][], pen[][] colors=new pen[][], bool3 planar=default) { s=new patch[]; if(planar == true) {// Assume all path3 elements share a common normal. if(external.length != 0) { triple n=normal(external[0]); if(n != O) { transform3 T=align(n); external=transpose(T)*external; T *= shift(0,0,point(external[0],0).z); path[] g=sequence(new path(int i) {return path(external[i]);}, external.length); for(patch p : surface(g).s) s.push(T*p); return; } } } for(int i=0; i < external.length; ++i) construct(external[i], internal.length == 0 ? new triple[] : internal[i], colors.length == 0 ? new pen[] : colors[i],planar); } void push(path3 external, triple[] internal=new triple[], pen[] colors=new pen[], bool3 planar=default) { s.push(patch(external,internal,colors,planar)); } // Construct the surface of rotation generated by rotating g // from angle1 to angle2 sampled n times about the line c--c+axis. // An optional surface pen color(int i, real j) may be specified // to override the color at vertex(i,j). void operator init(triple c, path3 g, triple axis, int n=nslice, real angle1=0, real angle2=360, pen color(int i, real j)=null) { axis=unit(axis); real w=(angle2-angle1)/n; int L=length(g); s=new patch[L*n]; index=new int[n][L]; int m=-1; transform3[] T=new transform3[n+1]; transform3 t=rotate(w,c,c+axis); T[0]=rotate(angle1,c,c+axis); for(int k=1; k <= n; ++k) T[k]=T[k-1]*t; typedef pen colorfcn(int i, real j); bool defaultcolors=(colorfcn) color == null; for(int i=0; i < L; ++i) { path3 h=subpath(g,i,i+1); path3 r=reverse(h); path3 H=shift(-c)*h; real M=0; triple perp; void test(real[] t) { for(int i=0; i < 3; ++i) { triple v=point(H,t[i]); triple V=v-dot(v,axis)*axis; real a=abs(V); if(a > M) {M=a; perp=V;} } } test(maxtimes(H)); test(mintimes(H)); perp=unit(perp); triple normal=unit(cross(axis,perp)); triple dir(real j) {return Cos(j)*normal-Sin(j)*perp;} real j=angle1; transform3 Tk=T[0]; triple dirj=dir(j); for(int k=0; k < n; ++k, j += w) { transform3 Tp=T[k+1]; triple dirp=dir(j+w); path3 G=reverse(Tk*h{dirj}..{dirp}Tp*r{-dirp}..{-dirj}cycle); Tk=Tp; dirj=dirp; s[++m]=defaultcolors ? patch(G) : patch(G,new pen[] {color(i,j),color(i,j+w),color(i+1,j+w), color(i+1,j)}); index[k][i]=m; } ucyclic((angle2-angle1) % 360 == 0); vcyclic(cyclic(g)); } } void push(patch s) { this.s.push(s); } void append(surface s) { this.s.append(s.s); } void operator init(... surface[] s) { for(surface S : s) this.s.append(S.s); } } surface operator * (transform3 t, surface s) { surface S; S.s=new patch[s.s.length]; for(int i=0; i < s.s.length; ++i) S.s[i]=t*s.s[i]; S.index=copy(s.index); S.vcyclic=(bool) s.vcyclic; return S; } private string nullsurface="null surface"; triple min(surface s) { if(s.s.length == 0) abort(nullsurface); triple bound=s.s[0].min(); for(int i=1; i < s.s.length; ++i) bound=s.s[i].min(bound); return bound; } triple max(surface s) { if(s.s.length == 0) abort(nullsurface); triple bound=s.s[0].max(); for(int i=1; i < s.s.length; ++i) bound=s.s[i].max(bound); return bound; } pair min(surface s, projection P) { if(s.s.length == 0) abort(nullsurface); pair bound=s.s[0].min(P); for(int i=1; i < s.s.length; ++i) bound=s.s[i].min(P,bound); return bound; } pair max(surface s, projection P) { if(s.s.length == 0) abort(nullsurface); pair bound=s.s[0].max(P); for(int i=1; i < s.s.length; ++i) bound=s.s[i].max(P,bound); return bound; } private triple[] split(triple z0, triple c0, triple c1, triple z1, real t=0.5) { triple m0=interp(z0,c0,t); triple m1=interp(c0,c1,t); triple m2=interp(c1,z1,t); triple m3=interp(m0,m1,t); triple m4=interp(m1,m2,t); triple m5=interp(m3,m4,t); return new triple[] {m0,m3,m5,m4,m2}; } // Return the control points of the subpatches // produced by a horizontal split of P triple[][][] hsplit(triple[][] P, real v=0.5) { // get control points in rows triple[] P0=P[0]; triple[] P1=P[1]; triple[] P2=P[2]; triple[] P3=P[3]; triple[] c0=split(P0[0],P0[1],P0[2],P0[3],v); triple[] c1=split(P1[0],P1[1],P1[2],P1[3],v); triple[] c2=split(P2[0],P2[1],P2[2],P2[3],v); triple[] c3=split(P3[0],P3[1],P3[2],P3[3],v); // bottom, top return new triple[][][] { {{P0[0],c0[0],c0[1],c0[2]}, {P1[0],c1[0],c1[1],c1[2]}, {P2[0],c2[0],c2[1],c2[2]}, {P3[0],c3[0],c3[1],c3[2]}}, {{c0[2],c0[3],c0[4],P0[3]}, {c1[2],c1[3],c1[4],P1[3]}, {c2[2],c2[3],c2[4],P2[3]}, {c3[2],c3[3],c3[4],P3[3]}} }; } // Return the control points of the subpatches // produced by a vertical split of P triple[][][] vsplit(triple[][] P, real u=0.5) { // get control points in rows triple[] P0=P[0]; triple[] P1=P[1]; triple[] P2=P[2]; triple[] P3=P[3]; triple[] c0=split(P0[0],P1[0],P2[0],P3[0],u); triple[] c1=split(P0[1],P1[1],P2[1],P3[1],u); triple[] c2=split(P0[2],P1[2],P2[2],P3[2],u); triple[] c3=split(P0[3],P1[3],P2[3],P3[3],u); // left, right return new triple[][][] { {{P0[0],P0[1],P0[2],P0[3]}, {c0[0],c1[0],c2[0],c3[0]}, {c0[1],c1[1],c2[1],c3[1]}, {c0[2],c1[2],c2[2],c3[2]}}, {{c0[2],c1[2],c2[2],c3[2]}, {c0[3],c1[3],c2[3],c3[3]}, {c0[4],c1[4],c2[4],c3[4]}, {P3[0],P3[1],P3[2],P3[3]}} }; } // Return a 2D array of the control point arrays of the subpatches // produced by horizontal and vertical splits of P at u and v triple[][][][] split(triple[][] P, real u=0.5, real v=0.5) { triple[] P0=P[0]; triple[] P1=P[1]; triple[] P2=P[2]; triple[] P3=P[3]; // slice horizontally triple[] c0=split(P0[0],P0[1],P0[2],P0[3],v); triple[] c1=split(P1[0],P1[1],P1[2],P1[3],v); triple[] c2=split(P2[0],P2[1],P2[2],P2[3],v); triple[] c3=split(P3[0],P3[1],P3[2],P3[3],v); // bottom patch triple[] c4=split(P0[0],P1[0],P2[0],P3[0],u); triple[] c5=split(c0[0],c1[0],c2[0],c3[0],u); triple[] c6=split(c0[1],c1[1],c2[1],c3[1],u); triple[] c7=split(c0[2],c1[2],c2[2],c3[2],u); // top patch triple[] c8=split(c0[3],c1[3],c2[3],c3[3],u); triple[] c9=split(c0[4],c1[4],c2[4],c3[4],u); triple[] cA=split(P0[3],P1[3],P2[3],P3[3],u); // {{bottom-left, top-left}, {bottom-right, top-right}} return new triple[][][][] { {{{P0[0],c0[0],c0[1],c0[2]}, {c4[0],c5[0],c6[0],c7[0]}, {c4[1],c5[1],c6[1],c7[1]}, {c4[2],c5[2],c6[2],c7[2]}}, {{c0[2],c0[3],c0[4],P0[3]}, {c7[0],c8[0],c9[0],cA[0]}, {c7[1],c8[1],c9[1],cA[1]}, {c7[2],c8[2],c9[2],cA[2]}}}, {{{c4[2],c5[2],c6[2],c7[2]}, {c4[3],c5[3],c6[3],c7[3]}, {c4[4],c5[4],c6[4],c7[4]}, {P3[0],c3[0],c3[1],c3[2]}}, {{c7[2],c8[2],c9[2],cA[2]}, {c7[3],c8[3],c9[3],cA[3]}, {c7[4],c8[4],c9[4],cA[4]}, {c3[2],c3[3],c3[4],P3[3]}}} }; } // Return the control points for a subpatch of P on [u,1] x [v,1]. triple[][] subpatchend(triple[][] P, real u, real v) { triple[] P0=P[0]; triple[] P1=P[1]; triple[] P2=P[2]; triple[] P3=P[3]; triple[] c0=split(P0[0],P0[1],P0[2],P0[3],v); triple[] c1=split(P1[0],P1[1],P1[2],P1[3],v); triple[] c2=split(P2[0],P2[1],P2[2],P2[3],v); triple[] c3=split(P3[0],P3[1],P3[2],P3[3],v); triple[] c7=split(c0[2],c1[2],c2[2],c3[2],u); triple[] c8=split(c0[3],c1[3],c2[3],c3[3],u); triple[] c9=split(c0[4],c1[4],c2[4],c3[4],u); triple[] cA=split(P0[3],P1[3],P2[3],P3[3],u); return new triple[][] { {c7[2],c8[2],c9[2],cA[2]}, {c7[3],c8[3],c9[3],cA[3]}, {c7[4],c8[4],c9[4],cA[4]}, {c3[2],c3[3],c3[4],P3[3]}}; } // Return the control points for a subpatch of P on [0,u] x [0,v]. triple[][] subpatchbegin(triple[][] P, real u, real v) { triple[] P0=P[0]; triple[] P1=P[1]; triple[] P2=P[2]; triple[] P3=P[3]; triple[] c0=split(P0[0],P0[1],P0[2],P0[3],v); triple[] c1=split(P1[0],P1[1],P1[2],P1[3],v); triple[] c2=split(P2[0],P2[1],P2[2],P2[3],v); triple[] c3=split(P3[0],P3[1],P3[2],P3[3],v); triple[] c4=split(P0[0],P1[0],P2[0],P3[0],u); triple[] c5=split(c0[0],c1[0],c2[0],c3[0],u); triple[] c6=split(c0[1],c1[1],c2[1],c3[1],u); triple[] c7=split(c0[2],c1[2],c2[2],c3[2],u); return new triple[][] { {P0[0],c0[0],c0[1],c0[2]}, {c4[0],c5[0],c6[0],c7[0]}, {c4[1],c5[1],c6[1],c7[1]}, {c4[2],c5[2],c6[2],c7[2]}}; } triple[][] subpatch(triple[][] P, pair a, pair b) { return subpatchend(subpatchbegin(P,b.x,b.y),a.x/b.x,a.y/b.y); } patch subpatch(patch s, pair a, pair b) { assert(a.x >= 0 && a.y >= 0 && b.x <= 1 && b.y <= 1 && a.x < b.x && a.y < b.y && !s.triangular); return patch(subpatch(s.P,a,b),s.straight,s.planar); } // return an array containing an intersection times of path p and surface s. real[] intersect(path3 p, patch s, real fuzz=-1) { return intersect(p,s.P,fuzz); } // return an array containing an intersection times of path p and surface s. real[] intersect(path3 p, surface s, real fuzz=-1) { for(int i=0; i < s.s.length; ++i) { real[] T=intersect(p,s.s[i].P,fuzz); if(T.length > 0) return T; } return new real[]; } // return an array containing all intersection times of path p and patch s. real[][] intersections(path3 p, patch s, real fuzz=-1) { return sort(intersections(p,s.P,fuzz)); } // return an array containing all intersection times of path p and surface s. real[][] intersections(path3 p, surface s, real fuzz=-1) { real[][] T; if(length(p) < 0) return T; for(int i=0; i < s.s.length; ++i) for(real[] s: intersections(p,s.s[i].P,fuzz)) T.push(s); static real Fuzz=1000*realEpsilon; real fuzz=max(10*fuzz,Fuzz*max(abs(min(s)),abs(max(s)))); // Remove intrapatch duplicate points. for(int i=0; i < T.length; ++i) { triple v=point(p,T[i][0]); for(int j=i+1; j < T.length;) { if(abs(v-point(p,T[j][0])) < fuzz) T.delete(j); else ++j; } } return sort(T); } // return an array containing all intersection points of path p and surface s. triple[] intersectionpoints(path3 p, patch s, real fuzz=-1) { real[][] t=intersections(p,s,fuzz); return sequence(new triple(int i) {return point(p,t[i][0]);},t.length); } // return an array containing all intersection points of path p and surface s. triple[] intersectionpoints(path3 p, surface s, real fuzz=-1) { real[][] t=intersections(p,s,fuzz); return sequence(new triple(int i) {return point(p,t[i][0]);},t.length); } // Return true iff the control point bounding boxes of patches p and q overlap. bool overlap(triple[][] p, triple[][] q, real fuzz=-1) { triple pmin=minbound(p); triple pmax=maxbound(p); triple qmin=minbound(q); triple qmax=maxbound(q); if(fuzz == -1) fuzz=1000*realEpsilon*max(abs(pmin),abs(pmax),abs(qmin),abs(qmax)); return pmax.x+fuzz >= qmin.x && pmax.y+fuzz >= qmin.y && pmax.z+fuzz >= qmin.z && qmax.x+fuzz >= pmin.x && qmax.y+fuzz >= pmin.y && qmax.z+fuzz >= pmin.z; // Overlapping bounding boxes? } triple point(patch s, real u, real v) { return s.point(u,v); } real PRCshininess(real shininess) { // Empirical translation table from Phong-Blinn to PRC shininess model: static real[] x={0.015,0.025,0.05,0.07,0.1,0.14,0.23,0.5,0.65,0.75,0.85, 0.875,0.9,1}; static real[] y={0.05,0.1,0.15,0.2,0.25,0.3,0.4,0.5,0.55,0.6,0.7,0.8,0.9,1}; static realfunction s=fspline(x,y,monotonic); return s(shininess); } struct interaction { int type; bool targetsize; void operator init(int type, bool targetsize=false) { this.type=type; this.targetsize=targetsize; } } restricted interaction Embedded=interaction(0); restricted interaction Billboard=interaction(1); interaction LabelInteraction() { return settings.autobillboard ? Billboard : Embedded; } material material(material m, light light) { return light.on() || invisible((pen) m) ? m : emissive(m); } void draw3D(frame f, int type=0, patch s, triple center=O, material m, light light=currentlight, interaction interaction=Embedded, bool prc=true) { if(s.colors.length > 0) m=mean(s.colors); m=material(m,light); real PRCshininess; if(prc()) PRCshininess=PRCshininess(m.shininess); if(s.triangular) drawbeziertriangle(f,s.P,center,s.straight && s.planar,m.p, m.opacity,m.shininess,PRCshininess,s.colors, interaction.type); else draw(f,s.P,center,s.straight && s.planar,m.p,m.opacity,m.shininess, PRCshininess,s.planar ? s.normal(0.5,0.5) : O,s.colors, interaction.type,prc); } // Draw triangles on a frame. void draw(frame f, triple[] v, int[][] vi, triple[] n={}, int[][] ni={}, material m=currentpen, pen[] p={}, int[][] pi={}, light light=currentlight) { if(p.length > 0) m=mean(p); m=material(m,light); real PRCshininess; if(prc()) PRCshininess=PRCshininess(m.shininess); draw(f,v,vi,n,ni,m.p,m.opacity,m.shininess,PRCshininess,p,pi); } // Draw triangles on a picture. void draw(picture pic=currentpicture, triple[] v, int[][] vi, triple[] n={}, int[][] ni={}, material m=currentpen, pen[] p={}, int[][] pi={}, light light=currentlight) { bool colors=pi.length > 0; bool normals=ni.length > 0; if(!colors && !normals) { n=new triple[]; ni=new int[vi.length][3]; triple lastnormal=O; for(int i=0; i < vi.length; ++i) { int[] vii=vi[i]; int[] nii=ni[i]; triple normal=normal(new triple[] {v[vii[0]],v[vii[1]],v[vii[2]]}); if(normal != lastnormal || n.length == 0) { n.push(normal); lastnormal=normal; } nii[0]=nii[1]=nii[2]=n.length-1; } } pic.add(new void(frame f, transform3 t, picture pic, projection P) { triple[] v=t*v; triple[] n=t*n; if(is3D()) { draw(f,v,vi,n,ni,m,p,pi,light); if(pic != null) { for(int[] vii : vi) for(int viij : vii) pic.addPoint(project(v[viij],P)); } } else if(pic != null) { static int[] edges={0,0,1}; if(colors) { for(int i=0; i < vi.length; ++i) { int[] vii=vi[i]; int[] pii=pi[i]; gouraudshade(pic,project(v[vii[0]],P)--project(v[vii[1]],P)-- project(v[vii[2]],P)--cycle, new pen[] {p[pii[0]],p[pii[1]],p[pii[2]]},edges); } } else { if(normals) { for(int i=0; i < vi.length; ++i) { int[] vii=vi[i]; int[] nii=ni[i]; gouraudshade(pic,project(v[vii[0]],P)--project(v[vii[1]],P)-- project(v[vii[2]],P)--cycle, new pen[] {color(n[nii[0]],m,light), color(n[nii[1]],m,light), color(n[nii[2]],m,light)},edges); } } else { for(int i=0; i < vi.length; ++i) { int[] vii=vi[i]; path g=project(v[vii[0]],P)--project(v[vii[1]],P)-- project(v[vii[2]],P)--cycle; pen p=color(n[ni[i][0]],m,light); fill(pic,g,p); if(opacity(m.diffuse()) == 1) // Fill subdivision cracks draw(pic,g,p); } } } } },true); for(int[] vii : vi) for(int viij : vii) pic.addPoint(v[viij]); } void drawPRCsphere(frame f, transform3 t=identity4, bool half=false, material m, light light=currentlight, render render=defaultrender) { m=material(m,light); drawPRCsphere(f,t,half,m.p,m.opacity,PRCshininess(m.shininess), render.sphere); } void drawPRCcylinder(frame f, transform3 t=identity4, material m, light light=currentlight) { m=material(m,light); drawPRCcylinder(f,t,m.p,m.opacity,PRCshininess(m.shininess)); } void drawPRCdisk(frame f, transform3 t=identity4, material m, light light=currentlight) { m=material(m,light); drawPRCdisk(f,t,m.p,m.opacity,PRCshininess(m.shininess)); } void drawPRCtube(frame f, path3 center, path3 g, material m, light light=currentlight) { m=material(m,light); drawPRCtube(f,center,g,m.p,m.opacity,PRCshininess(m.shininess)); } void tensorshade(transform t=identity(), frame f, patch s, material m, light light=currentlight, projection P) { if(s.triangular) s=tensor(s); tensorshade(f,box(t*s.min(P),t*s.max(P)),m.diffuse(), s.colors(m,light),t*project(s.external(),P,1),t*project(s.internal(),P)); } restricted pen[] nullpens={nullpen}; nullpens.cyclic=true; void draw(transform t=identity(), frame f, surface s, int nu=1, int nv=1, material[] surfacepen, pen[] meshpen=nullpens, light light=currentlight, light meshlight=nolight, string name="", render render=defaultrender, projection P=currentprojection) { bool is3D=is3D(); if(is3D) { bool group=name != "" || render.defaultnames; if(group) begingroup3(f,name == "" ? "surface" : name,render); // Sort patches by mean distance from camera triple camera=P.camera; if(P.infinity) { triple m=min(s); triple M=max(s); camera=P.target+camerafactor*(abs(M-m)+abs(m-P.target))*unit(P.vector()); } real[][] depth=new real[s.s.length][]; for(int i=0; i < depth.length; ++i) depth[i]=new real[] {dot(P.normal,camera-s.s[i].cornermean()),i}; depth=sort(depth); for(int p=depth.length-1; p >= 0; --p) { real[] a=depth[p]; int k=round(a[1]); draw3D(f,s.s[k],surfacepen[k],light); } if(group) endgroup3(f); pen modifiers=thin()+squarecap; for(int p=depth.length-1; p >= 0; --p) { real[] a=depth[p]; int k=round(a[1]); pen meshpen=meshpen[k]; if(!invisible(meshpen)) { if(group) begingroup3(f,meshname(name),render); meshpen=modifiers+meshpen; real step=nu == 0 ? 0 : 1/nu; for(int i=0; i <= nu; ++i) draw(f,s.s[k].uequals(i*step),meshpen,meshlight,partname(i,render), render); step=nv == 0 ? 0 : 1/nv; for(int j=0; j <= nv; ++j) draw(f,s.s[k].vequals(j*step),meshpen,meshlight,partname(j,render), render); if(group) endgroup3(f); } } } if(!is3D || settings.render == 0) { begingroup(f); // Sort patches by mean distance from camera triple camera=P.camera; if(P.infinity) { triple m=min(s); triple M=max(s); camera=P.target+camerafactor*(abs(M-m)+abs(m-P.target))*unit(P.vector()); } real[][] depth=new real[s.s.length][]; for(int i=0; i < depth.length; ++i) depth[i]=new real[] {dot(P.normal,camera-s.s[i].cornermean()),i}; depth=sort(depth); light.T=shiftless(P.T.modelview); // Draw from farthest to nearest for(int p=depth.length-1; p >= 0; --p) { real[] a=depth[p]; int k=round(a[1]); tensorshade(t,f,s.s[k],surfacepen[k],light,P); pen meshpen=meshpen[k]; if(!invisible(meshpen)) draw(f,t*project(s.s[k].external(),P),meshpen); } endgroup(f); } } void draw(transform t=identity(), frame f, surface s, int nu=1, int nv=1, material surfacepen=currentpen, pen meshpen=nullpen, light light=currentlight, light meshlight=nolight, string name="", render render=defaultrender, projection P=currentprojection) { material[] surfacepen={surfacepen}; pen[] meshpen={meshpen}; surfacepen.cyclic=true; meshpen.cyclic=true; draw(t,f,s,nu,nv,surfacepen,meshpen,light,meshlight,name,render,P); } void draw(picture pic=currentpicture, surface s, int nu=1, int nv=1, material[] surfacepen, pen[] meshpen=nullpens, light light=currentlight, light meshlight=nolight, string name="", render render=defaultrender) { if(s.empty()) return; bool cyclic=surfacepen.cyclic; surfacepen=copy(surfacepen); surfacepen.cyclic=cyclic; cyclic=meshpen.cyclic; meshpen=copy(meshpen); meshpen.cyclic=cyclic; pic.add(new void(frame f, transform3 t, picture pic, projection P) { surface S=t*s; if(is3D()) draw(f,S,nu,nv,surfacepen,meshpen,light,meshlight,name,render); if(pic != null) { pic.add(new void(frame f, transform T) { draw(T,f,S,nu,nv,surfacepen,meshpen,light,meshlight,P); },true); pic.addPoint(min(S,P)); pic.addPoint(max(S,P)); } },true); pic.addPoint(min(s)); pic.addPoint(max(s)); pen modifiers; if(is3D()) modifiers=thin()+squarecap; for(int k=0; k < s.s.length; ++k) { pen meshpen=meshpen[k]; if(!invisible(meshpen)) { meshpen=modifiers+meshpen; real step=nu == 0 ? 0 : 1/nu; for(int i=0; i <= nu; ++i) addPath(pic,s.s[k].uequals(i*step),meshpen); step=nv == 0 ? 0 : 1/nv; for(int j=0; j <= nv; ++j) addPath(pic,s.s[k].vequals(j*step),meshpen); } } } void draw(picture pic=currentpicture, surface s, int nu=1, int nv=1, material surfacepen=currentpen, pen meshpen=nullpen, light light=currentlight, light meshlight=nolight, string name="", render render=defaultrender) { material[] surfacepen={surfacepen}; pen[] meshpen={meshpen}; surfacepen.cyclic=true; meshpen.cyclic=true; draw(pic,s,nu,nv,surfacepen,meshpen,light,meshlight,name,render); } void draw(picture pic=currentpicture, surface s, int nu=1, int nv=1, material[] surfacepen, pen meshpen, light light=currentlight, light meshlight=nolight, string name="", render render=defaultrender) { pen[] meshpen={meshpen}; meshpen.cyclic=true; draw(pic,s,nu,nv,surfacepen,meshpen,light,meshlight,name,render); } surface extrude(path3 p, path3 q) { static patch[] allocate; return surface(...sequence(new patch(int i) { return patch(subpath(p,i,i+1)--subpath(q,i+1,i)--cycle); },length(p))); } surface extrude(path3 p, triple axis=Z) { return extrude(p,shift(axis)*p); } surface extrude(path p, triple plane(pair)=XYplane, triple axis=Z) { return extrude(path3(p,plane),axis); } surface extrude(explicit path[] p, triple axis=Z) { surface s; for(path g:p) s.append(extrude(g,axis)); return s; } triple rectify(triple dir) { real scale=max(abs(dir.x),abs(dir.y),abs(dir.z)); if(scale != 0) dir *= 0.5/scale; dir += (0.5,0.5,0.5); return dir; } path3[] align(path3[] g, transform3 t=identity4, triple position, triple align, pen p=currentpen) { if(determinant(t) == 0 || g.length == 0) return g; triple m=min(g); triple dir=rectify(inverse(t)*-align); triple a=m+realmult(dir,max(g)-m); return shift(position+align*labelmargin(p))*t*shift(-a)*g; } surface align(surface s, transform3 t=identity4, triple position, triple align, pen p=currentpen) { if(determinant(t) == 0 || s.s.length == 0) return s; triple m=min(s); triple dir=rectify(inverse(t)*-align); triple a=m+realmult(dir,max(s)-m); return shift(position+align*labelmargin(p))*t*shift(-a)*s; } surface surface(Label L, triple position=O, bool bbox=false) { surface s=surface(texpath(L,bbox=bbox)); return L.align.is3D ? align(s,L.T3,position,L.align.dir3,L.p) : shift(position)*L.T3*s; } private path[] path(Label L, pair z=0, projection P) { path[] g=texpath(L,bbox=P.bboxonly); return L.align.is3D ? align(g,z,project(L.align.dir3,P)-project(O,P),L.p) : shift(z)*g; } transform3 alignshift(path3[] g, transform3 t=identity4, triple position, triple align) { if(determinant(t) == 0) return identity4; triple m=min(g); triple dir=rectify(inverse(t)*-align); triple a=m+realmult(dir,max(g)-m); return shift(-a); } transform3 alignshift(surface s, transform3 t=identity4, triple position, triple align) { if(determinant(t) == 0) return identity4; triple m=min(s); triple dir=rectify(inverse(t)*-align); triple a=m+realmult(dir,max(s)-m); return shift(-a); } transform3 aligntransform(path3[] g, transform3 t=identity4, triple position, triple align, pen p=currentpen) { if(determinant(t) == 0) return identity4; triple m=min(g); triple dir=rectify(inverse(t)*-align); triple a=m+realmult(dir,max(g)-m); return shift(position+align*labelmargin(p))*t*shift(-a); } transform3 aligntransform(surface s, transform3 t=identity4, triple position, triple align, pen p=currentpen) { if(determinant(t) == 0) return identity4; triple m=min(s); triple dir=rectify(inverse(t)*-align); triple a=m+realmult(dir,max(s)-m); return shift(position+align*labelmargin(p))*t*shift(-a); } void label(frame f, Label L, triple position, align align=NoAlign, pen p=currentpen, light light=nolight, string name="", render render=defaultrender, interaction interaction=LabelInteraction(), projection P=currentprojection) { Label L=L.copy(); L.align(align); L.p(p); if(interaction.targetsize && settings.render != 0) L.T=L.T*scale(abs(P.camera-position)/abs(P.vector())); transform3 T=transform3(P); if(L.defaulttransform3) L.T3=T; if(is3D()) { bool lighton=light.on(); if(name == "") name=L.s; if(prc() && interaction.type == Billboard.type) { surface s=surface(texpath(L)); transform3 centering=L.align.is3D ? alignshift(s,L.T3,position,L.align.dir3) : identity4; transform3 positioning= shift(L.align.is3D ? position+L.align.dir3*labelmargin(L.p) : position); frame f1,f2,f3; begingroup3(f1,name,render); if(L.defaulttransform3) begingroup3(f3,render,position,interaction.type); else { begingroup3(f2,render,position,interaction.type); begingroup3(f3,render,position); } for(patch S : s.s) { S=centering*S; draw3D(f3,S,position,L.p,light,interaction); // Fill subdivision cracks if(render.labelfill && opacity(L.p) == 1 && !lighton) _draw(f3,S.external(),position,L.p,interaction.type); } endgroup3(f3); if(L.defaulttransform3) add(f1,T*f3); else { add(f2,inverse(T)*L.T3*f3); endgroup3(f2); add(f1,T*f2); } endgroup3(f1); add(f,positioning*f1); } else { begingroup3(f,name,render); for(patch S : surface(L,position).s) { triple V=L.align.is3D ? position+L.align.dir3*labelmargin(L.p) : position; draw3D(f,S,V,L.p,light,interaction); // Fill subdivision cracks if(render.labelfill && opacity(L.p) == 1 && !lighton) _draw(f,S.external(),V,L.p,interaction.type); } endgroup3(f); } } else { pen p=color(L.T3*Z,L.p,light,shiftless(P.T.modelview)); if(L.defaulttransform3) { if(L.filltype == NoFill) fill(f,path(L,project(position,P.t),P),p); else { frame d; fill(d,path(L,project(position,P.t),P),p); add(f,d,L.filltype); } } else for(patch S : surface(L,position).s) fill(f,project(S.external(),P,1),p); } } void label(picture pic=currentpicture, Label L, triple position, align align=NoAlign, pen p=currentpen, light light=nolight, string name="", render render=defaultrender, interaction interaction=LabelInteraction()) { Label L=L.copy(); L.align(align); L.p(p); L.position(0); pic.add(new void(frame f, transform3 t, picture pic2, projection P) { // Handle relative projected 3D alignments. Label L=L.copy(); triple v=t*position; if(!align.is3D && L.align.relative && L.align.dir3 != O && determinant(P.t) != 0) L.align(L.align.dir*unit(project(v+L.align.dir3,P.t)-project(v,P.t))); if(interaction.targetsize && settings.render != 0) L.T=L.T*scale(abs(P.camera-v)/abs(P.vector())); transform3 T=transform3(P); if(L.defaulttransform3) L.T3=T; if(is3D()) { bool lighton=light.on(); if(name == "") name=L.s; if(prc() && interaction.type == Billboard.type) { surface s=surface(texpath(L,bbox=P.bboxonly)); transform3 centering=L.align.is3D ? alignshift(s,L.T3,v,L.align.dir3) : identity4; transform3 positioning= shift(L.align.is3D ? v+L.align.dir3*labelmargin(L.p) : v); frame f1,f2,f3; begingroup3(f1,name,render); if(L.defaulttransform3) begingroup3(f3,render,v,interaction.type); else { begingroup3(f2,render,v,interaction.type); begingroup3(f3,render,v); } for(patch S : s.s) { S=centering*S; draw3D(f3,S,v,L.p,light,interaction); // Fill subdivision cracks if(render.labelfill && opacity(L.p) == 1 && !lighton) _draw(f3,S.external(),v,L.p,interaction.type); } endgroup3(f3); if(L.defaulttransform3) add(f1,T*f3); else { add(f2,inverse(T)*L.T3*f3); endgroup3(f2); add(f1,T*f2); } endgroup3(f1); add(f,positioning*f1); } else { begingroup3(f,name,render); for(patch S : surface(L,v,bbox=P.bboxonly).s) { triple V=L.align.is3D ? v+L.align.dir3*labelmargin(L.p) : v; draw3D(f,S,V,L.p,light,interaction); // Fill subdivision cracks if(render.labelfill && opacity(L.p) == 1 && !lighton) _draw(f,S.external(),V,L.p,interaction.type); } endgroup3(f); } } if(pic2 != null) { pen p=color(L.T3*Z,L.p,light,shiftless(P.T.modelview)); if(L.defaulttransform3) { if(L.filltype == NoFill) fill(project(v,P.t),pic2,path(L,P),p); else { picture d; fill(project(v,P.t),d,path(L,P),p); add(pic2,d,L.filltype); } } else pic2.add(new void(frame f, transform T) { for(patch S : surface(L,v).s) fill(f,T*project(S.external(),P,1),p); }); } },!L.defaulttransform3); Label L=L.copy(); if(interaction.targetsize && settings.render != 0) L.T=L.T*scale(abs(currentprojection.camera-position)/ abs(currentprojection.vector())); path[] g=texpath(L,bbox=true); if(g.length == 0 || (g.length == 1 && size(g[0]) == 0)) return; if(L.defaulttransform3) L.T3=transform3(currentprojection); path3[] G=path3(g); G=L.align.is3D ? align(G,L.T3,O,L.align.dir3,L.p) : L.T3*G; pic.addBox(position,position,min(G),max(G)); } void label(picture pic=currentpicture, Label L, path3 g, align align=NoAlign, pen p=currentpen, light light=nolight, string name="", interaction interaction=LabelInteraction()) { Label L=L.copy(); L.align(align); L.p(p); bool relative=L.position.relative; real position=L.position.position.x; if(L.defaultposition) {relative=true; position=0.5;} if(relative) position=reltime(g,position); if(L.align.default) { align a; a.init(-I*(position <= sqrtEpsilon ? S : position >= length(g)-sqrtEpsilon ? N : E),relative=true); a.dir3=dir(g,position); // Pass 3D direction via unused field. L.align(a); } label(pic,L,point(g,position),light,name,interaction); } surface extrude(Label L, triple axis=Z) { Label L=L.copy(); path[] g=texpath(L); surface S=extrude(g,axis); surface s=surface(g); S.append(s); S.append(shift(axis)*s); return S; } restricted surface nullsurface; // Embed a Label onto a surface. surface surface(Label L, surface s, real uoffset, real voffset, real height=0, bool bottom=true, bool top=true) { int nu=s.index.length; int nv; if(nu == 0) nu=nv=1; else { nv=s.index[0].length; if(nv == 0) nv=1; } path[] g=texpath(L); pair m=min(g); pair M=max(g); pair lambda=inverse(L.T*scale(nu-epsilon,nv-epsilon))*(M-m); lambda=(abs(lambda.x),abs(lambda.y)); path[] G=bezulate(g); path3 transpath(path p, real height) { return path3(unstraighten(p),new triple(pair z) { real u=uoffset+(z.x-m.x)/lambda.x; real v=voffset+(z.y-m.y)/lambda.y; if(((u < 0 || u >= nu) && !s.ucyclic()) || ((v < 0 || v >= nv) && !s.vcyclic())) { warning("cannotfit","cannot fit string to surface"); u=v=0; } return s.point(u,v)+height*unit(s.normal(u,v)); }); } surface s; for(path p : G) { for(path g : regularize(p)) { path3 b; bool extrude=height > 0; if(bottom || extrude) b=transpath(g,0); if(bottom) s.s.push(patch(b)); if(top || extrude) { path3 h=transpath(g,height); if(top) s.s.push(patch(h)); if(extrude) s.append(extrude(b,h)); } } } return s; } private real a=4/3*(sqrt(2)-1); private transform3 t1=rotate(90,O,Z); private transform3 t2=t1*t1; private transform3 t3=t2*t1; private transform3 i=xscale3(-1)*zscale3(-1); restricted patch octant1=patch(X{Y}..{-X}Y{Z}..{-Y}Z..Z{X}..{-Z}cycle, new triple[] {(1,a,a),(a,1,a),(a^2,a,1), (a,a^2,1)}); restricted surface unithemisphere=surface(octant1,t1*octant1,t2*octant1, t3*octant1); restricted surface unitsphere=surface(octant1,t1*octant1,t2*octant1,t3*octant1, i*octant1,i*t1*octant1,i*t2*octant1, i*t3*octant1); restricted patch unitfrustum(real t1, real t2) { real s1=interp(t1,t2,1/3); real s2=interp(t1,t2,2/3); return patch(interp(Z,X,t2){Y}..{-X}interp(Z,Y,t2)--interp(Z,Y,t1){X}..{-Y} interp(Z,X,t1)--cycle, new triple[] {(s2,s2*a,1-s2),(s2*a,s2,1-s2),(s1*a,s1,1-s1), (s1,s1*a,1-s1)}); } // Return a unitcone constructed from n frusta (the final one being degenerate) surface unitcone(int n=6) { surface unitcone; unitcone.s=new patch[4*n]; real r=1/3; for(int i=0; i < n; ++i) { patch s=unitfrustum(i < n-1 ? r^(i+1) : 0,r^i); unitcone.s[i]=s; unitcone.s[n+i]=t1*s; unitcone.s[2n+i]=t2*s; unitcone.s[3n+i]=t3*s; } return unitcone; } restricted surface unitcone=unitcone(); restricted surface unitsolidcone=surface(patch(unitcircle3)...unitcone.s); // Construct an approximate cone over an arbitrary base. surface cone(path3 base, triple vertex) {return extrude(base,vertex--cycle);} private patch unitcylinder1=patch(X{Y}..{-X}Y--Y+Z{X}..{-Y}X+Z--cycle); restricted surface unitcylinder=surface(unitcylinder1,t1*unitcylinder1, t2*unitcylinder1,t3*unitcylinder1); private patch unitplane=patch(new triple[] {O,X,X+Y,Y}); restricted surface unitcube=surface(reverse(unitplane), rotate(90,O,X)*unitplane, rotate(-90,O,Y)*unitplane, shift(Z)*unitplane, rotate(90,X,X+Y)*unitplane, rotate(-90,Y,X+Y)*unitplane); restricted surface unitplane=surface(unitplane); restricted surface unitdisk=surface(unitcircle3); void dot(frame f, triple v, material p=currentpen, light light=nolight, string name="", render render=defaultrender, projection P=currentprojection) { pen q=(pen) p; if(is3D()) { bool group=name != "" || render.defaultnames; if(group) begingroup3(f,name == "" ? "dot" : name,render); real size=0.5*linewidth(dotsize(q)+q); transform3 T=shift(v)*scale3(size); for(patch s : unitsphere.s) draw3D(f,T*s,v,p,light,prc=false); if(prc()) drawPRCsphere(f,T,p,light); if(group) endgroup3(f); } else dot(f,project(v,P.t),q); } void dot(frame f, triple[] v, material p=currentpen, light light=nolight, string name="", render render=defaultrender, projection P=currentprojection) { if(v.length > 0) { // Remove duplicate points. v=sort(v,lexorder); triple last=v[0]; dot(f,last,p,light,name,render,P); for(int i=1; i < v.length; ++i) { triple V=v[i]; if(V != last) { dot(f,V,p,light,name,render,P); last=V; } } } } void dot(frame f, path3 g, material p=currentpen, light light=nolight, string name="", render render=defaultrender, projection P=currentprojection) { dot(f,sequence(new triple(int i) {return point(g,i);},size(g)), p,light,name,render,P); } void dot(frame f, path3[] g, material p=currentpen, light light=nolight, string name="", render render=defaultrender, projection P=currentprojection) { int sum; for(path3 G : g) sum += size(G); int i,j; dot(f,sequence(new triple(int) { while(j >= size(g[i])) { ++i; j=0; } triple v=point(g[i],j); ++j; return v; },sum),p,light,name,render,P); } void dot(picture pic=currentpicture, triple v, material p=currentpen, light light=nolight, string name="", render render=defaultrender) { pen q=(pen) p; real size=0.5*linewidth(dotsize(q)+q); pic.add(new void(frame f, transform3 t, picture pic, projection P) { triple V=t*v; if(is3D()) { bool group=name != "" || render.defaultnames; if(group) begingroup3(f,name == "" ? "dot" : name,render); transform3 T=shift(V)*scale3(size); for(patch s : unitsphere.s) draw3D(f,T*s,V,p,light,prc=false); if(prc()) drawPRCsphere(f,T,p,light,render); if(group) endgroup3(f); } if(pic != null) dot(pic,project(V,P.t),q); },true); triple R=size*(1,1,1); pic.addBox(v,v,-R,R); } void dot(picture pic=currentpicture, triple[] v, material p=currentpen, light light=nolight, string name="", render render=defaultrender) { if(v.length > 0) { // Remove duplicate points. v=sort(v,lexorder); triple last=v[0]; bool group=name != "" || render.defaultnames; if(group) begingroup3(pic,name == "" ? "dots" : name,render); dot(pic,last,p,light,partname(0,render),render); int k=0; for(int i=1; i < v.length; ++i) { triple V=v[i]; if(V != last) { dot(pic,V,p,light,partname(++k,render),render); last=V; } } if(group) endgroup3(pic); } } void dot(picture pic=currentpicture, explicit path3 g, material p=currentpen, light light=nolight, string name="", render render=defaultrender) { dot(pic,sequence(new triple(int i) {return point(g,i);},size(g)), p,light,name,render); } void dot(picture pic=currentpicture, path3[] g, material p=currentpen, light light=nolight, string name="", render render=defaultrender) { int sum; for(path3 G : g) sum += size(G); int i,j; dot(pic,sequence(new triple(int) { while(j >= size(g[i])) { ++i; j=0; } triple v=point(g[i],j); ++j; return v; },sum),p,light,name,render); } void dot(picture pic=currentpicture, Label L, triple v, align align=NoAlign, string format=defaultformat, material p=currentpen, light light=nolight, string name="", render render=defaultrender) { Label L=L.copy(); if(L.s == "") { if(format == "") format=defaultformat; L.s="("+format(format,v.x)+","+format(format,v.y)+","+ format(format,v.z)+")"; } L.align(align,E); L.p((pen) p); dot(pic,v,p,light,name,render); label(pic,L,v,render); } void pixel(picture pic=currentpicture, triple v, pen p=currentpen, real width=1) { real h=0.5*width; pic.add(new void(frame f, transform3 t, picture pic, projection P) { triple V=t*v; if(is3D()) drawpixel(f,V,p,width); if(pic != null) { triple R=h*unit(cross(unit(P.vector()),P.up)); pair z=project(V,P.t); real h=0.5*abs(project(V+R,P.t)-project(V-R,P.t)); pair r=h*(1,1)/mm; fill(pic,box(z-r,z+r),p,false); } },true); triple R=h*(1,1,1); pic.addBox(v,v,-R,R); } pair minbound(triple[] A, projection P) { pair b=project(A[0],P); for(triple v : A) b=minbound(b,project(v,P.t)); return b; } pair maxbound(triple[] A, projection P) { pair b=project(A[0],P); for(triple v : A) b=maxbound(b,project(v,P.t)); return b; } pair minbound(triple[][] A, projection P) { pair b=project(A[0][0],P); for(triple[] a : A) { for(triple v : a) { b=minbound(b,project(v,P.t)); } } return b; } pair maxbound(triple[][] A, projection P) { pair b=project(A[0][0],P); for(triple[] a : A) { for(triple v : a) { b=maxbound(b,project(v,P.t)); } } return b; } triple[][] operator / (triple[][] a, real[][] b) { triple[][] A=new triple[a.length][]; for(int i=0; i < a.length; ++i) { triple[] ai=a[i]; real[] bi=b[i]; A[i]=sequence(new triple(int j) {return ai[j]/bi[j];},ai.length); } return A; } // Draw a NURBS curve. void draw(picture pic=currentpicture, triple[] P, real[] knot, real[] weights=new real[], pen p=currentpen, string name="", render render=defaultrender) { P=copy(P); knot=copy(knot); weights=copy(weights); pic.add(new void(frame f, transform3 t, picture pic, projection Q) { if(is3D()) { triple[] P=t*P; bool group=name != "" || render.defaultnames; if(group) begingroup3(f,name == "" ? "curve" : name,render); draw(f,P,knot,weights,p); if(group) endgroup3(f); if(pic != null) pic.addBox(minbound(P,Q),maxbound(P,Q)); } },true); pic.addBox(minbound(P),maxbound(P)); } // Draw a NURBS surface. void draw(picture pic=currentpicture, triple[][] P, real[] uknot, real[] vknot, real[][] weights=new real[][], material m=currentpen, pen[] colors=new pen[], light light=currentlight, string name="", render render=defaultrender) { if(colors.length > 0) m=mean(colors); m=material(m,light); bool lighton=light.on(); P=copy(P); uknot=copy(uknot); vknot=copy(vknot); weights=copy(weights); colors=copy(colors); pic.add(new void(frame f, transform3 t, picture pic, projection Q) { if(is3D()) { bool group=name != "" || render.defaultnames; if(group) begingroup3(f,name == "" ? "surface" : name,render); triple[][] P=t*P; real PRCshininess; if(prc()) PRCshininess=PRCshininess(m.shininess); draw(f,P,uknot,vknot,weights,m.p,m.opacity,m.shininess,PRCshininess, colors); if(group) endgroup3(f); if(pic != null) pic.addBox(minbound(P,Q),maxbound(P,Q)); } },true); pic.addBox(minbound(P),maxbound(P)); } asymptote-2.37/base/three_tube.asy000066400000000000000000000303521265434602500172620ustar00rootroot00000000000000void render(path3 s, void f(path3, real), render render=defaultrender) { real granularity=render.tubegranularity; void Split(triple z0, triple c0, triple c1, triple z1, real t0=0, real t1=1, real depth=mantissaBits) { if(depth > 0) { real S=straightness(z0,c0,c1,z1); if(S > 0) { --depth; if(S > max(granularity*max(abs(z0),abs(c0),abs(c1),abs(z1)))) { triple m0=0.5*(z0+c0); triple m1=0.5*(c0+c1); triple m2=0.5*(c1+z1); triple m3=0.5*(m0+m1); triple m4=0.5*(m1+m2); triple m5=0.5*(m3+m4); real tm=0.5*(t0+t1); Split(z0,m0,m3,m5,t0,tm,depth); Split(m5,m4,m2,z1,tm,t1,depth); return; } } } f(z0..controls c0 and c1..z1,t0); } Split(point(s,0),postcontrol(s,0),precontrol(s,1),point(s,1)); } struct rmf { triple p,r,t,s; void operator init(triple p, triple r, triple t) { this.p=p; this.r=r; this.t=t; s=cross(t,r); } } // Rotation minimizing frame // http://www.cs.hku.hk/research/techreps/document/TR-2007-07.pdf rmf[] rmf(path3 g, real[] t) { rmf[] R=new rmf[t.length]; triple d=dir(g,0); R[0]=rmf(point(g,0),perp(d),d); for(int i=1; i < t.length; ++i) { rmf Ri=R[i-1]; real t=t[i]; triple p=point(g,t); triple v1=p-Ri.p; if(v1 != O) { triple r=Ri.r; triple u1=unit(v1); triple ti=Ri.t; triple tp=ti-2*dot(u1,ti)*u1; ti=dir(g,t); triple rp=r-2*dot(u1,r)*u1; triple u2=unit(ti-tp); rp=rp-2*dot(u2,rp)*u2; R[i]=rmf(p,unit(rp),unit(ti)); } else R[i]=R[i-1]; } return R; } private real[][][] bispline0(real[][] z, real[][] p, real[][] q, real[][] r, real[] x, real[] y, bool[][] cond={}) { // z[i][j] is the value at (x[i],y[j]) // p and q are the first derivatives with respect to x and y, respectively // r is the second derivative ddu/dxdy int n=x.length-1; int m=y.length-1; bool all=cond.length == 0; int count; if(all) count=n*m; else { count=0; for(int i=0; i < n; ++i) { bool[] condi=cond[i]; bool[] condp=cond[i+1]; for(int j=0; j < m; ++j) if(all || (condi[j] && condi[j+1] && condp[j] && condp[j+1])) ++count; } } real[][][] s=new real[count][][]; int k=0; for(int i=0; i < n; ++i) { int ip=i+1; real xi=x[i]; real xp=x[ip]; real hx=(xp-xi)/3; real[] zi=z[i]; real[] zp=z[ip]; real[] ri=r[i]; real[] rp=r[ip]; real[] pi=p[i]; real[] pp=p[ip]; real[] qi=q[i]; real[] qp=q[ip]; bool[] condi=all ? null : cond[i]; bool[] condp=all ? null : cond[i+1]; for(int j=0; j < m; ++j) { if(all || (condi[j] && condi[j+1] && condp[j] && condp[j+1])) { real yj=y[j]; int jp=j+1; real yp=y[jp]; real hy=(yp-yj)/3; real hxy=hx*hy; real zij=zi[j]; real zip=zi[jp]; real zpj=zp[j]; real zpp=zp[jp]; real pij=hx*pi[j]; real ppj=hx*pp[j]; real qip=hy*qi[jp]; real qpp=hy*qp[jp]; real zippip=zip+hx*pi[jp]; real zppmppp=zpp-hx*pp[jp]; real zijqij=zij+hy*qi[j]; real zpjqpj=zpj+hy*qp[j]; s[k]=new real[][] {{zij,zijqij,zip-qip,zip}, {zij+pij,zijqij+pij+hxy*ri[j], zippip-qip-hxy*ri[jp],zippip}, {zpj-ppj,zpjqpj-ppj-hxy*rp[j], zppmppp-qpp+hxy*rp[jp],zppmppp}, {zpj,zpjqpj,zpp-qpp,zpp}}; ++k; } } } return s; } // return the surface values described by a real matrix f, interpolated with // xsplinetype and ysplinetype. real[][][] bispline(real[][] f, real[] x, real[] y, splinetype xsplinetype=null, splinetype ysplinetype=xsplinetype, bool[][] cond={}) { real epsilon=sqrtEpsilon*norm(y); if(xsplinetype == null) xsplinetype=(abs(x[0]-x[x.length-1]) <= epsilon) ? periodic : notaknot; if(ysplinetype == null) ysplinetype=(abs(y[0]-y[y.length-1]) <= epsilon) ? periodic : notaknot; int n=x.length; int m=y.length; real[][] ft=transpose(f); real[][] tp=new real[m][]; for(int j=0; j < m; ++j) tp[j]=xsplinetype(x,ft[j]); real[][] q=new real[n][]; for(int i=0; i < n; ++i) q[i]=ysplinetype(y,f[i]); real[][] qt=transpose(q); real[] d1=xsplinetype(x,qt[0]); real[] d2=xsplinetype(x,qt[m-1]); real[][] r=new real[n][]; real[][] p=transpose(tp); for(int i=0; i < n; ++i) r[i]=clamped(d1[i],d2[i])(y,p[i]); return bispline0(f,p,q,r,x,y,cond); } bool uperiodic(real[][] a) { int n=a.length; if(n == 0) return false; int m=a[0].length; real[] a0=a[0]; real[] a1=a[n-1]; for(int j=0; j < m; ++j) { real norm=0; for(int i=0; i < n; ++i) norm=max(norm,abs(a[i][j])); real epsilon=sqrtEpsilon*norm; if(abs(a0[j]-a1[j]) > epsilon) return false; } return true; } bool vperiodic(real[][] a) { int n=a.length; if(n == 0) return false; int m=a[0].length-1; for(int i=0; i < n; ++i) { real[] ai=a[i]; real epsilon=sqrtEpsilon*norm(ai); if(abs(ai[0]-ai[m]) > epsilon) return false; } return true; } // return the surface described by a parametric function f evaluated at u and v // and interpolated with usplinetype and vsplinetype. surface surface(triple f(pair z), real[] u, real[] v, splinetype[] usplinetype, splinetype[] vsplinetype=Spline, bool cond(pair z)=null) { int nu=u.length-1; int nv=v.length-1; real[] ipt=sequence(u.length); real[] jpt=sequence(v.length); real[][] fx=new real[u.length][v.length]; real[][] fy=new real[u.length][v.length]; real[][] fz=new real[u.length][v.length]; bool[][] active; bool all=cond == null; if(!all) active=new bool[u.length][v.length]; for(int i=0; i <= nu; ++i) { real ui=u[i]; real[] fxi=fx[i]; real[] fyi=fy[i]; real[] fzi=fz[i]; bool[] activei=all ? null : active[i]; for(int j=0; j <= nv; ++j) { pair z=(ui,v[j]); if(!all) activei[j]=cond(z); triple f=f(z); fxi[j]=f.x; fyi[j]=f.y; fzi[j]=f.z; } } if(usplinetype.length == 0) { usplinetype=new splinetype[] {uperiodic(fx) ? periodic : notaknot, uperiodic(fy) ? periodic : notaknot, uperiodic(fz) ? periodic : notaknot}; } else if(usplinetype.length != 3) abort("usplinetype must have length 3"); if(vsplinetype.length == 0) { vsplinetype=new splinetype[] {vperiodic(fx) ? periodic : notaknot, vperiodic(fy) ? periodic : notaknot, vperiodic(fz) ? periodic : notaknot}; } else if(vsplinetype.length != 3) abort("vsplinetype must have length 3"); real[][][] sx=bispline(fx,ipt,jpt,usplinetype[0],vsplinetype[0],active); real[][][] sy=bispline(fy,ipt,jpt,usplinetype[1],vsplinetype[1],active); real[][][] sz=bispline(fz,ipt,jpt,usplinetype[2],vsplinetype[2],active); surface s=surface(sx.length); s.index=new int[nu][nv]; int k=-1; for(int i=0; i < nu; ++i) { int[] indexi=s.index[i]; for(int j=0; j < nv; ++j) indexi[j]=++k; } for(int k=0; k < sx.length; ++k) { triple[][] Q=new triple[4][]; real[][] Px=sx[k]; real[][] Py=sy[k]; real[][] Pz=sz[k]; for(int i=0; i < 4 ; ++i) { real[] Pxi=Px[i]; real[] Pyi=Py[i]; real[] Pzi=Pz[i]; Q[i]=new triple[] {(Pxi[0],Pyi[0],Pzi[0]), (Pxi[1],Pyi[1],Pzi[1]), (Pxi[2],Pyi[2],Pzi[2]), (Pxi[3],Pyi[3],Pzi[3])}; } s.s[k]=patch(Q); } if(usplinetype[0] == periodic && usplinetype[1] == periodic && usplinetype[1] == periodic) s.ucyclic(true); if(vsplinetype[0] == periodic && vsplinetype[1] == periodic && vsplinetype[1] == periodic) s.vcyclic(true); return s; } path3 interp(path3 a, path3 b, real t) { int n=size(a); return path3(sequence(new triple(int i) { return interp(precontrol(a,i),precontrol(b,i),t);},n), sequence(new triple(int i) {return interp(point(a,i),point(b,i),t);},n), sequence(new triple(int i) {return interp(postcontrol(a,i), postcontrol(b,i),t);},n), sequence(new bool(int i) {return straight(a,i) && straight(b,i);},n), cyclic(a) && cyclic(b)); } struct tube { surface s; path3 center; // tube axis void Null(transform3) {} void Null(transform3, bool) {} void operator init(path3 p, real width, render render=defaultrender, void cylinder(transform3)=Null, void sphere(transform3, bool half)=Null, void pipe(path3, path3)=null) { real r=0.5*width; void generate(path3 p) { int n=length(p); if(piecewisestraight(p)) { for(int i=0; i < n; ++i) { triple v=point(p,i); triple u=point(p,i+1)-v; transform3 t=shift(v)*align(unit(u))*scale(r,r,abs(u)); s.append(t*unitcylinder); cylinder(t); } center=center&p; } else { real[] T; path3 G; for(int i=0; i < n; ++i) render(subpath(p,i,i+1), new void(path3 g, real s) { G=G&g; T.push(i+s); },render); T.push(n); T.cyclic=cyclic(p); rmf[] rmf=rmf(p,T); triple f(pair t) { rmf R=rmf[round(t.x)]; int n=round(t.y); static real[] x={1,0,-1,0}; static real[] y={0,1,0,-1}; return point(G,t.x)+r*(R.r*x[n]-R.s*y[n]); } static real[] v={0,1,2,3,0}; static real[] circular(real[] x, real[] y) { static real a=8/3*(sqrt(2)-1); return a*periodic(x,y); } static splinetype[] Monotonic={monotonic,monotonic,monotonic}; static splinetype[] Circular={circular,circular,circular}; if(T.length > 0) { surface S=surface(f,sequence(T.length),v,Monotonic,Circular); s.append(S); // Compute center of tube: int n=S.index.length; if(T.cyclic) --n; triple[] pre=new triple[n+1]; triple[] point=new triple[n+1]; triple[] post=new triple[n+1]; int[] index=S.index[0]; triple Point; for(int m=0; m < 4; ++m) Point += S.s[index[m]].P[0][0]; pre[0]=point[0]=0.25*Point; for(int i=0; i < n; ++i) { index=S.index[i]; triple Pre,Point,Post; for(int m=0; m < 4; ++m) { triple [][] P=S.s[index[m]].P; Post += P[1][0]; Pre += P[2][0]; Point += P[3][0]; } post[i]=0.25*Post; pre[i+1]=0.25*Pre; point[i+1]=0.25*Point; } index=S.index[n-1]; triple Post; for(int m=0; m < 4; ++m) Post += S.s[index[m]].P[3][0]; post[n]=0.25*Post; bool[] b=array(n+1,false); path3 Center=path3(pre,point,post,b,T.cyclic); center=center&Center; if(pipe != null) { // Compute path along tube triple[] pre=new triple[n+1]; triple[] point=new triple[n+1]; triple[] post=new triple[n+1]; pre[0]=point[0]=S.s[S.index[0][0]].P[0][0]; for(int i=0; i < n; ++i) { triple [][] P=S.s[S.index[i][0]].P; post[i]=P[1][0]; pre[i+1]=P[2][0]; point[i+1]=P[3][0]; } post[n]=S.s[S.index[n-1][0]].P[3][0]; pipe(Center,path3(pre,point,post,b,T.cyclic)); } } } } transform3 t=scale3(r); bool cyclic=cyclic(p); int begin=0; int n=length(p); for(int i=cyclic ? 0 : 1; i < n; ++i) if(abs(dir(p,i,1)-dir(p,i,-1)) > sqrtEpsilon) { generate(subpath(p,begin,i)); triple dir=dir(p,i,-1); transform3 T=t*align(dir); s.append(shift(point(p,i))*T*(dir != O ? unithemisphere : unitsphere)); sphere(shift(point(center,length(center)))*T, half=straight(p,i-1) && straight(p,i)); begin=i; } generate(subpath(p,begin,n)); } } asymptote-2.37/base/tree.asy000066400000000000000000000025371265434602500160770ustar00rootroot00000000000000/***** * treedef.asy * Andy Hammerlindl 2003/10/25 * * Implements a dynamic binary search tree. *****/ struct tree { tree left; tree right; int key = 0; int value = 0; } tree newtree() { return null; } tree add(tree t, int key, int value) { if (t == null) { tree tt; tt.key = key; tt.value = value; return tt; } else if (key == t.key) { return t; } else if (key < t.key) { tree tt; tt.left = add(t.left, key, value); tt.key = t.key; tt.value = t.value; tt.right = t.right; return tt; } else { tree tt; tt.left = t.left; tt.key = t.key; tt.value = t.value; tt.right = add(t.right, key, value); return tt; } } bool contains(tree t, int key) { if (t == null) return false; else if (key == t.key) return true; else if (key < t.key) return contains(t.left, key); else return contains(t.right, key); } int lookup(tree t, int key) { if (t == null) return 0; else if (key == t.key) return t.value; else if (key < t.key) return lookup(t.left, key); else return lookup(t.right, key); } void write(file out=stdout, tree t) { if (t != null) { if(t.left != null) { write(out,t.left); } write(out,t.key); write(out,"->"); write(out,t.value,endl); if (t.right != null) { write(out,t.right); } } } asymptote-2.37/base/trembling.asy000066400000000000000000000132451265434602500171210ustar00rootroot00000000000000// Copyright(c) 2008, Philippe Ivaldi. // Simplified by John Bowman 02Feb2011 // http: //www.piprime.fr/ // trembling.asy: handwriting package for the software Asymptote. // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation; either version 3 of the License, or //(at your option) any later version. // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // COMMENTARY: // THANKS: // BUGS: // magnetic points are experimental... // CODE: real magneticRadius=1; // unit is bp in postscript coordinates. real trembleFuzz(){return min(1e-3,magneticRadius/10);} real trembleAngle=4, trembleFrequency=0.5, trembleRandom=2; struct tremble { static real test=5; real angle,frequency,random,fuzz; pair[] single(pair[] P) { pair[] op; bool allow; for(int i=0; i < P.length-1; ++i) { allow=true; for(int j=i+1; j < P.length; ++j) { if(abs(P[i]-P[j]) < magneticRadius) { allow=false; break; } } if(allow) op.push(P[i]); } if(P.length > 0) op.push(P[P.length-1]); return op; } real atime(pair m, path g, real fuzz=trembleFuzz()) {// Return the time of the point on path g nearest to m, within fuzz. if(length(g) == 0) return 0.0; real[] t=intersect(m,g,fuzz); if(t.length > 0) return t[1]; real ot; static real eps=sqrt(realEpsilon); real abmax=abs(max(g)-m), abmin=abs(min(g)-m); real initr=abs(m-midpoint(g)); real maxR=2*max(abmax,abmin), step=eps, r=initr; real shx=1e-4; transform T=shift(m); path ig; if(t.length > 0) ot=t[1]; real rm=0, rM=r; while(rM-rm > eps) { r=(rm+rM)/2; t=intersect(T*scale(r)*unitcircle,g,fuzz); if(t.length <= 0) { rm=r; } else { rM=r; ot=t[1]; } } return ot; } path addnode(path g, real t) {// Add a node to 'g' at point(g,t). real l=length(g); real rt=t % 1; if(l == 0 || (t > l && !cyclic(g)) || rt == 0) return g; if(cyclic(g)) t=t % l; int t0=floor(t); int t1=t0+1; pair z0=point(g,t0), z1=point(g,t1), c0=postcontrol(g,t0), c1=precontrol(g,t1), m0=(1-rt)*z0+rt*c0, m1=(1-rt)*c0+rt*c1, m2=(1-rt)*c1+rt*z1, m3=(1-rt)*m0+rt*m1, m4=(1-rt)*m1+rt*m2; guide og=subpath(g,0,t0)..controls m0 and m3..point(g,t); if(cyclic(g)) { if(t1 < l) og=og..controls m4 and m2..subpath(g,t1,l)&cycle; else og=og..controls m4 and m2..cycle; } else og=og..controls m4 and m2..subpath(g,t1,l); return og; } path addnodes(path g, real fuzz=trembleFuzz()...pair[] P) { pair[] P=single(P); if(length(g) == 0 || P.length == 0 || magneticRadius <= 0) return g; path og=g; for(pair tp: P) { real t=atime(tp,og,fuzz); real d=abs(tp-point(og,t)); if(d < magneticRadius) og=addnode(og,t); } return og; } path addnodes(path g, int n) {// Add 'n' nodes between each node of 'g'. real l=length(g); if(n == 0 || l == 0) return g; path og=g; int np=0; for(int i=0; i < l; ++i) { real step=1/(n+1); for(int j=0; j < n; ++j) { og=addnode(og,i*(n+1)+j+step); step=1/(n-j); } } return og; } void operator init(real angle=trembleAngle, real frequency=trembleFrequency, real random=trembleRandom, real fuzz=trembleFuzz()) { this.angle=angle; this.frequency=frequency; this.random=random; this.fuzz=fuzz; } path deform(path g...pair[] magneticPoints) { /* Return g as it was handwriting. The postcontrols and precontrols of the nodes of g will be rotated by an angle proportional to 'angle'(in degrees). If frequency < 1, floor(1/frequency) nodes will be added to g to increase the control points. If frequency>= 1, one point for floor(frequency) will be used to deform the path. 'random' controls the randomized coefficient which will be multiplied by 'angle'. random is 0 means don't use randomized coefficient; The higher 'random' is, the more the trembling is randomized. */ if(length(g) == 0) return g; g=addnodes(g,fuzz*abs(max(g)-min(g))...magneticPoints); path tg=g; frequency=abs(frequency); int f=abs(floor(1/frequency)-1); tg=addnodes(tg,f); int frequency=floor(frequency); int tf=(frequency == 0) ? 1 : frequency; int l=length(tg); guide og=point(tg,0); random=abs(random); int rsgn(real x){ int d2=floor(100*x)-10*floor(10*x); if(d2 == 0) return 1; return 2 % d2 == 0 ? 1 : -1; } real randf() { real or; if(random != 0) { if(1 % tf != 0) or=0; else { real ur=unitrand(); or=rsgn(ur)*angle*(1+ur^(1/random)); } } else or=rsgn(unitrand())*1.5*angle; return or; } real first=randf(); for(int i=1; i <= l; ++i) { pair P=point(tg,i); real a=randf(); pair post=rotate(a,point(tg,i-1))*postcontrol(tg,i-1); pair pre=rotate((a+randf())/2,P)*precontrol(tg,i); if(i == l && (cyclic(tg))) og=og..controls post and pre..cycle; else og=og..controls post and pre..P; } return og; } } asymptote-2.37/base/tube.asy000066400000000000000000000103111265434602500160640ustar00rootroot00000000000000// Author: Philippe Ivaldi // http://www.piprime.fr/ // Based on this paper: // http://www.cs.hku.hk/research/techreps/document/TR-2007-07.pdf // Note: the additional rotation for a cyclic smooth spine curve is not // yet properly determined. // TODO: Implement variational principles for RMF with boundary conditions: // minimum total angular speed OR minimum total squared angular speed import three; // A 3D version of roundedpath(path, real). path3 roundedpath(path3 A, real r) { // Author of this routine: Jens Schwaiger guide3 rounded; triple before, after, indir, outdir; int len=length(A); bool cyclic=cyclic(A); if(len < 2) {return A;}; if(cyclic) {rounded=point(point(A,0)--point(A,1),r);} else {rounded=point(A,0);} for(int i=1; i < len; i=i+1) { before=point(point(A,i)--point(A,i-1),r); after=point(point(A,i)--point(A,i+1),r); indir=dir(point(A,i-1)--point(A,i),1); outdir=dir(point(A,i)--point(A,i+1),1); rounded=rounded--before{indir}..{outdir}after; } if(cyclic) { before=point(point(A,0)--point(A,len-1),r); indir=dir(point(A,len-1)--point(A,0),1); outdir=dir(point(A,0)--point(A,1),1); rounded=rounded--before{indir}..{outdir}cycle; } else rounded=rounded--point(A,len); return rounded; } real[] sample(path3 g, real r, real relstep=0) { real[] t; int n=length(g); if(relstep <= 0) { for(int i=0; i < n; ++i) { real S=straightness(g,i); if(S < sqrtEpsilon*r) t.push(i); else render(subpath(g,i,i+1),new void(path3, real s) {t.push(i+s);}); } t.push(n); } else { int nb=ceil(1/relstep); relstep=n/nb; for(int i=0; i <= nb; ++i) t.push(i*relstep); } return t; } real degrees(rmf a, rmf b) { real d=degrees(acos1(dot(a.r,b.r))); real dt=dot(cross(a.r,b.r),a.t); d=dt > 0 ? d : 360-d; return d%360; } restricted int coloredNodes=1; restricted int coloredSegments=2; struct coloredpath { path p; pen[] pens(real); bool usepens=false; int colortype=coloredSegments; void operator init(path p, pen[] pens=new pen[] {currentpen}, int colortype=coloredSegments) { this.p=p; this.pens=new pen[] (real t) {return pens;}; this.usepens=true; this.colortype=colortype; } void operator init(path p, pen[] pens(real), int colortype=coloredSegments) { this.p=p; this.pens=pens; this.usepens=true; this.colortype=colortype; } void operator init(path p, pen pen(real)) { this.p=p; this.pens=new pen[] (real t) {return new pen[] {pen(t)};}; this.usepens=true; this.colortype=coloredSegments; } } coloredpath operator cast(path p) { coloredpath cp=coloredpath(p); cp.usepens=false; return cp; } coloredpath operator cast(guide p) { return coloredpath(p); } private surface surface(rmf[] R, real[] t, coloredpath cp, transform T(real), bool cyclic) { path g=cp.p; int l=length(g); bool[] planar; for(int i=0; i < l; ++i) planar[i]=straight(g,i); surface s; path3 sec=path3(T(t[0]/l)*g); real adjust=0; if(cyclic) adjust=-degrees(R[0],R[R.length-1])/(R.length-1); path3 sec1=shift(R[0].p)*transform3(R[0].r,R[0].s,R[0].t)*sec, sec2; for(int i=1; i < R.length; ++i) { sec=path3(T(t[i]/l)*g); sec2=shift(R[i].p)*transform3(R[i].r,cross(R[i].t,R[i].r),R[i].t)* rotate(i*adjust,Z)*sec; for(int j=0; j < l; ++j) { surface st=surface(subpath(sec1,j,j+1)--subpath(sec2,j+1,j)--cycle, planar=planar[j]); if(cp.usepens) { pen[] tp1=cp.pens(t[i-1]/l), tp2=cp.pens(t[i]/l); tp1.cyclic=true; tp2.cyclic=true; if(cp.colortype == coloredSegments) { st.colors(new pen[][] {{tp1[j],tp1[j],tp2[j],tp2[j]}}); } else { st.colors(new pen[][] {{tp1[j],tp1[j+1],tp2[j+1],tp2[j]}}); } } s.append(st); } sec1=sec2; } return s; } surface tube(path3 g, coloredpath section, transform T(real)=new transform(real t) {return identity();}, real corner=1, real relstep=0) { pair M=max(section.p), m=min(section.p); real[] t=sample(g,max(M.x-m.x,M.y-m.y)/max(realEpsilon,abs(corner)), min(abs(relstep),1)); bool cyclic=cyclic(g); t.cyclic=cyclic; return surface(rmf(g,t),t,section,T,cyclic); } asymptote-2.37/base/unicode.asy000066400000000000000000000000631265434602500165560ustar00rootroot00000000000000usepackage("ucs"); usepackage("inputenc","utf8x"); asymptote-2.37/base/x11colors.asy000066400000000000000000000113141265434602500167640ustar00rootroot00000000000000pen rgbint(int r, int g, int b) { return rgb(r/255,g/255,b/255); } pen AliceBlue=rgbint(240,248,255); pen AntiqueWhite=rgbint(250,235,215); pen Aqua=rgbint(0,255,255); pen Aquamarine=rgbint(127,255,212); pen Azure=rgbint(240,255,255); pen Beige=rgbint(245,245,220); pen Bisque=rgbint(255,228,196); pen Black=rgbint(0,0,0); pen BlanchedAlmond=rgbint(255,235,205); pen Blue=rgbint(0,0,255); pen BlueViolet=rgbint(138,43,226); pen Brown=rgbint(165,42,42); pen BurlyWood=rgbint(222,184,135); pen CadetBlue=rgbint(95,158,160); pen Chartreuse=rgbint(127,255,0); pen Chocolate=rgbint(210,105,30); pen Coral=rgbint(255,127,80); pen CornflowerBlue=rgbint(100,149,237); pen Cornsilk=rgbint(255,248,220); pen Crimson=rgbint(220,20,60); pen Cyan=rgbint(0,255,255); pen DarkBlue=rgbint(0,0,139); pen DarkCyan=rgbint(0,139,139); pen DarkGoldenrod=rgbint(184,134,11); pen DarkGray=rgbint(169,169,169); pen DarkGreen=rgbint(0,100,0); pen DarkKhaki=rgbint(189,183,107); pen DarkMagenta=rgbint(139,0,139); pen DarkOliveGreen=rgbint(85,107,47); pen DarkOrange=rgbint(255,140,0); pen DarkOrchid=rgbint(153,50,204); pen DarkRed=rgbint(139,0,0); pen DarkSalmon=rgbint(233,150,122); pen DarkSeaGreen=rgbint(143,188,143); pen DarkSlateBlue=rgbint(72,61,139); pen DarkSlateGray=rgbint(47,79,79); pen DarkTurquoise=rgbint(0,206,209); pen DarkViolet=rgbint(148,0,211); pen DeepPink=rgbint(255,20,147); pen DeepSkyBlue=rgbint(0,191,255); pen DimGray=rgbint(105,105,105); pen DodgerBlue=rgbint(30,144,255); pen FireBrick=rgbint(178,34,34); pen FloralWhite=rgbint(255,250,240); pen ForestGreen=rgbint(34,139,34); pen Fuchsia=rgbint(255,0,255); pen Gainsboro=rgbint(220,220,220); pen GhostWhite=rgbint(248,248,255); pen Gold=rgbint(255,215,0); pen Goldenrod=rgbint(218,165,32); pen Gray=rgbint(128,128,128); pen Green=rgbint(0,128,0); pen GreenYellow=rgbint(173,255,47); pen Honeydew=rgbint(240,255,240); pen HotPink=rgbint(255,105,180); pen IndianRed=rgbint(205,92,92); pen Indigo=rgbint(75,0,130); pen Ivory=rgbint(255,255,240); pen Khaki=rgbint(240,230,140); pen Lavender=rgbint(230,230,250); pen LavenderBlush=rgbint(255,240,245); pen LawnGreen=rgbint(124,252,0); pen LemonChiffon=rgbint(255,250,205); pen LightBlue=rgbint(173,216,230); pen LightCoral=rgbint(240,128,128); pen LightCyan=rgbint(224,255,255); pen LightGoldenrodYellow=rgbint(250,250,210); pen LightGreen=rgbint(144,238,144); pen LightGrey=rgbint(211,211,211); pen LightPink=rgbint(255,182,193); pen LightSalmon=rgbint(255,160,122); pen LightSeaGreen=rgbint(32,178,170); pen LightSkyBlue=rgbint(135,206,250); pen LightSlateGray=rgbint(119,136,153); pen LightSteelBlue=rgbint(176,196,222); pen LightYellow=rgbint(255,255,224); pen Lime=rgbint(0,255,0); pen LimeGreen=rgbint(50,205,50); pen Linen=rgbint(250,240,230); pen Magenta=rgbint(255,0,255); pen Maroon=rgbint(128,0,0); pen MediumAquamarine=rgbint(102,205,170); pen MediumBlue=rgbint(0,0,205); pen MediumOrchid=rgbint(186,85,211); pen MediumPurple=rgbint(147,112,219); pen MediumSeaGreen=rgbint(60,179,113); pen MediumSlateBlue=rgbint(123,104,238); pen MediumSpringGreen=rgbint(0,250,154); pen MediumTurquoise=rgbint(72,209,204); pen MediumVioletRed=rgbint(199,21,133); pen MidnightBlue=rgbint(25,25,112); pen MintCream=rgbint(245,255,250); pen MistyRose=rgbint(255,228,225); pen Moccasin=rgbint(255,228,181); pen NavajoWhite=rgbint(255,222,173); pen Navy=rgbint(0,0,128); pen OldLace=rgbint(253,245,230); pen Olive=rgbint(128,128,0); pen OliveDrab=rgbint(107,142,35); pen Orange=rgbint(255,165,0); pen OrangeRed=rgbint(255,69,0); pen Orchid=rgbint(218,112,214); pen PaleGoldenrod=rgbint(238,232,170); pen PaleGreen=rgbint(152,251,152); pen PaleTurquoise=rgbint(175,238,238); pen PaleVioletRed=rgbint(219,112,147); pen PapayaWhip=rgbint(255,239,213); pen PeachPuff=rgbint(255,218,185); pen Peru=rgbint(205,133,63); pen Pink=rgbint(255,192,203); pen Plum=rgbint(221,160,221); pen PowderBlue=rgbint(176,224,230); pen Purple=rgbint(128,0,128); pen Red=rgbint(255,0,0); pen RosyBrown=rgbint(188,143,143); pen RoyalBlue=rgbint(65,105,225); pen SaddleBrown=rgbint(139,69,19); pen Salmon=rgbint(250,128,114); pen SandyBrown=rgbint(244,164,96); pen SeaGreen=rgbint(46,139,87); pen Seashell=rgbint(255,245,238); pen Sienna=rgbint(160,82,45); pen Silver=rgbint(192,192,192); pen SkyBlue=rgbint(135,206,235); pen SlateBlue=rgbint(106,90,205); pen SlateGray=rgbint(112,128,144); pen Snow=rgbint(255,250,250); pen SpringGreen=rgbint(0,255,127); pen SteelBlue=rgbint(70,130,180); pen Tan=rgbint(210,180,140); pen Teal=rgbint(0,128,128); pen Thistle=rgbint(216,191,216); pen Tomato=rgbint(255,99,71); pen Turquoise=rgbint(64,224,208); pen Violet=rgbint(238,130,238); pen Wheat=rgbint(245,222,179); pen White=rgbint(255,255,255); pen WhiteSmoke=rgbint(245,245,245); pen Yellow=rgbint(255,255,0); pen YellowGreen=rgbint(154,205,50); asymptote-2.37/bbox.h000066400000000000000000000100661265434602500146070ustar00rootroot00000000000000/***** * bbox.h * Andy Hammerlindl 2002/06/06 * * Stores a rectangle that encloses a drawing object. *****/ #ifndef BBOX_H #define BBOX_H #include "pair.h" namespace camp { template inline T min(T a, T b) { return (a < b) ? a : b; } template inline T max(T a, T b) { return (a > b) ? a : b; } // The box that encloses a path struct bbox { bool empty; double left; double bottom; double right; double top; // Start bbox about the origin bbox() : empty(true), left(0.0), bottom(0.0), right(0.0), top(0.0) { } bbox(double left, double bottom, double right, double top) : empty(false), left(left), bottom(bottom), right(right), top(top) { } // Start a bbox with a point bbox(const pair& z) : empty(false), left(z.getx()), bottom(z.gety()), right(z.getx()), top(z.gety()) { } bool nonempty() const { return !empty; } // Add a point to a bbox bbox add(const pair& z) { double x = z.getx(), y = z.gety(); if (empty) { left = right = x; top = bottom = y; empty = false; } else { if (x < left) left = x; else if (x > right) right = x; if (y < bottom) bottom = y; else if (y > top) top = y; } return *this; } // Add a point to a nonempty bbox void addnonempty(const pair& z) { double x = z.getx(), y = z.gety(); if (x < left) left = x; else if (x > right) right = x; if (y < bottom) bottom = y; else if (y > top) top = y; } // Add a point to a nonempty bbox, updating bounding times void addnonempty(const pair& z, bbox& times, double t) { double x = z.getx(), y = z.gety(); if (x < left) { left = x; times.left = t; } else if (x > right) { right = x; times.right = t; } if (y < bottom) { bottom = y; times.bottom = t; } else if (y > top) { top = y; times.top = t; } } bbox operator+= (const pair& z) { add(z); return *this; } bbox operator*= (double x) { left *= x; right *= x; top *= x; bottom *=x; return *this; } // Add two bounding boxes friend bbox operator+ (const bbox& b1, const bbox& b2) { if (b1.empty) return b2; else if (b2.empty) return b1; else return bbox(min(b1.left, b2.left), max(b1.right, b2.right), min(b1.bottom, b2.bottom), max(b1.top, b2.top)); } // Add one bounding box to another void add(const bbox& b) { if (this->empty) *this = b; else if (!b.empty) { left = min(left, b.left); right = max(right, b.right); bottom = min(bottom, b.bottom); top = max(top, b.top); } } bbox operator+= (const bbox& b) { add(b); return *this; } void clip(const bbox& b) { if(this->empty) return; left = max(left, b.left); right = min(right, b.right); bottom = max(bottom, b.bottom); top = min(top, b.top); if(left > right || bottom > top) *this=bbox(); } void shift(const pair& p) { left += p.getx(); right += p.getx(); bottom += p.gety(); top += p.gety(); } pair Min() const { return pair(left,bottom); } pair Max() const { return pair(right,top); } double diameter() { return (Max()-Min()).length(); } bbox LowRes() const { return bbox(floor(left),floor(bottom),ceil(right),ceil(top)); } friend ostream& operator<< (ostream& out, const bbox& b) { out << b.left << " " << b.bottom << " " << b.right << " " << b.top; return out; } }; // Add results of both bounding boxes, say for a path and a pen. inline bbox pad(bbox b1, bbox b2) { if (b1.empty) return b2; else if (b2.empty) return b1; else { bbox b; b.empty = false; b.left = b1.left + b2.left; b.right = b1.right + b2.right; b.top = b1.top + b2.top; b.bottom = b1.bottom + b2.bottom; return b; } } } // namespace camp GC_DECLARE_PTRFREE(camp::bbox); #endif asymptote-2.37/bbox3.h000066400000000000000000000075161265434602500147000ustar00rootroot00000000000000/***** * bbox3.h * Andy Hammerlindl 2002/06/06 * * Stores a rectangle that encloses a drawing object. *****/ #ifndef BBOX3_H #define BBOX3_H #include "triple.h" namespace camp { // The box that encloses a path struct bbox3 { bool empty; double left; double bottom; double lower; double right; double top; double upper; // Start bbox3 about the origin bbox3() : empty(true), left(0.0), bottom(0.0), lower(0.0), right(0.0), top(0.0), upper(0.0) { } bbox3(double left, double bottom, double lower, double right, double top, double upper) : empty(false), left(left), bottom(bottom), lower(lower), right(right), top(top), upper(upper) { } // Start a bbox3 with a point bbox3(double x, double y, double z) : empty(false), left(x), bottom(y), lower(z), right(x), top(y), upper(z) { } // Start a bbox3 with a point bbox3(const triple& v) : empty(false), left(v.getx()), bottom(v.gety()), lower(v.getz()), right(v.getx()), top(v.gety()), upper(v.getz()) { } // Start a bbox3 with 2 points bbox3(const triple& m, const triple& M) : empty(false), left(m.getx()), bottom(m.gety()), lower(m.getz()), right(M.getx()), top(M.gety()), upper(M.getz()) { } // Add a point to a bbox3 void add(const triple& v) { const double x = v.getx(), y = v.gety(), z = v.getz(); add(x,y,z); } void add(double x, double y, double z) { if (empty) { left = right = x; top = bottom = y; lower = upper = z; empty = false; } else { if(x < left) left = x; else if(x > right) right = x; if(y < bottom) bottom = y; else if(y > top) top = y; if(z < lower) lower = z; else if(z > upper) upper = z; } } // Add a point to a nonempty bbox3 void addnonempty(double x, double y, double z) { if(x < left) left = x; else if(x > right) right = x; if(y < bottom) bottom = y; else if(y > top) top = y; if(z < lower) lower = z; else if(z > upper) upper = z; } // Add a point to a nonempty bbox3 void addnonempty(const triple& v) { addnonempty(v.getx(),v.gety(),v.getz()); } // Add a point to a nonempty bbox, updating bounding times void addnonempty(const triple& v, bbox3& times, double t) { double x = v.getx(), y = v.gety(), z = v.getz(); if(x < left) { left = x; times.left = t; } else if(x > right) { right = x; times.right = t; } if(y < bottom) { bottom = y; times.bottom = t; } else if(y > top) { top = y; times.top = t; } if(z < lower) { lower = z; times.lower=t; } else if(z > upper) { upper = z; times.upper=t; } } bbox3 operator+= (const triple& v) { add(v); return *this; } triple Min() const { return triple(left,bottom,lower); } triple Max() const { return triple(right,top,upper); } // transform bbox3 by 4x4 matrix void transform(const double* m) { const double xmin = left; const double ymin = bottom; const double zmin = lower; const double xmax = right; const double ymax = top; const double zmax = upper; empty = true; add(m*triple(xmin,ymin,zmin)); addnonempty(m*triple(xmin,ymin,zmax)); addnonempty(m*triple(xmin,ymax,zmin)); addnonempty(m*triple(xmin,ymax,zmax)); addnonempty(m*triple(xmax,ymin,zmin)); addnonempty(m*triple(xmax,ymin,zmax)); addnonempty(m*triple(xmax,ymax,zmin)); addnonempty(m*triple(xmax,ymax,zmax)); } friend ostream& operator << (ostream& out, const bbox3& b) { out << "Min " << b.Min() << " Max " << b.Max(); return out; } }; } // namespace camp GC_DECLARE_PTRFREE(camp::bbox3); #endif asymptote-2.37/beziertriangle.cc000066400000000000000000000330061265434602500170200ustar00rootroot00000000000000/***** * drawbeziertriangle.cc * Authors: Jesse Frohlich and John C. Bowman * * Render a Bezier triangle. *****/ #include "drawsurface.h" namespace camp { static const double pixel=0.5; // Adaptive rendering constant. extern const double Fuzz; extern const double Fuzz2; inline triple maxabs(triple u, triple v) { return triple(max(fabs(u.getx()),fabs(v.getx())), max(fabs(u.gety()),fabs(v.gety())), max(fabs(u.getz()),fabs(v.getz()))); } inline triple displacement1(const triple& z0, const triple& c0, const triple& c1, const triple& z1) { // z0-z1 is computed twice. This is unnecessary, although perhaps not a big // deal and way easier to understand in this case. return maxabs(displacement(c0,z0,z1),displacement(c1,z0,z1)); } // return the perpendicular displacement of a point z from the plane // through u with unit normal n. inline triple displacement2(const triple& z, const triple& u, const triple& n) { triple Z=z-u; return n != triple(0,0,0) ? dot(Z,n)*n : Z; } triple displacement(const triple *controls) { triple d=drawElement::zero; triple z0=controls[0]; triple z1=controls[6]; triple z2=controls[9]; // Optimize straight & planar cases. //for(size_t i=1; i < 10; ++i) // The last three lines compute how straight the edges are. This should be a // sufficient test for the boundry points, so only the central point is // tested for deviance from the main triangle. d=maxabs(d,displacement2(controls[4],z0,unit(cross(z1-z0,z2-z0)))); d=maxabs(d,displacement1(z0,controls[1],controls[3],z1)); d=maxabs(d,displacement1(z0,controls[2],controls[5],z2)); d=maxabs(d,displacement1(z1,controls[7],controls[8],z2)); // TODO: calculate displacement d from interior // Or simply assume a nondegenerate Jacobian. return d; } // Returns one-third of the first derivative of the Bezier curve defined by // a,b,c,d at 0. inline triple bezierP(triple a, triple b) { return b-a; } // Returns one-sixth of the second derivative of the Bezier curve defined // by a,b,c,d at 0. inline triple bezierPP(triple a, triple b, triple c) { return a+c-2.0*b; } // Returns one-third of the third derivative of the Bezier curve defined by // a,b,c,d. inline triple bezierPPP(triple a, triple b, triple c, triple d) { return d-a+3.0*(b-c); } struct Render { std::vector buffer; std::vector indices; triple u,v,w; GLuint nvertices; double cx,cy,cz; double epsilon; double res; bool billboard; void init(bool havebillboard, const triple& center) { const size_t nbuffer=10000; buffer.reserve(nbuffer); indices.reserve(nbuffer); nvertices=0; billboard=havebillboard; if(billboard) { cx=center.getx(); cy=center.gety(); cz=center.getz(); gl::projection P=gl::camera(false); w=unit(P.camera-P.target); v=unit(perp(P.up,w)); u=cross(v,w); } } void clear() { buffer.clear(); indices.clear(); } // Store the vertex v and its normal vector n in the buffer. GLuint vertex(const triple& V, const triple& n) { if(billboard) { double x=V.getx()-cx; double y=V.gety()-cy; double z=V.getz()-cz; buffer.push_back(cx+u.getx()*x+v.getx()*y+w.getx()*z); buffer.push_back(cy+u.gety()*x+v.gety()*y+w.gety()*z); buffer.push_back(cz+u.getz()*x+v.getz()*y+w.getz()*z); } else { buffer.push_back(V.getx()); buffer.push_back(V.gety()); buffer.push_back(V.getz()); } buffer.push_back(n.getx()); buffer.push_back(n.gety()); buffer.push_back(n.getz()); return nvertices++; } // Store the vertex v and its normal vector n and colour in the buffer. GLuint vertex(const triple& V, const triple& n, GLfloat *c) { int rc=vertex(V,n); buffer.push_back(c[0]); buffer.push_back(c[1]); buffer.push_back(c[2]); buffer.push_back(c[3]); return rc; } triple normal0(triple left3, triple left2, triple left1, triple middle, triple right1, triple right2, triple right3) { //cout << "normal0 called." << endl; // Lots of repetition here. // TODO: Check if lp,rp,lpp,rpp should be manually inlined (i.e., is the // third order normal usually computed when normal0() is called?). triple lp=bezierP(middle,left1); triple rp=bezierP(middle,right1); triple lpp=bezierPP(middle,left1,left2); triple rpp=bezierPP(middle,right1,right2); triple n1=cross(rpp,lp)+cross(rp,lpp); if(abs2(n1) > epsilon) { return unit(n1); } else { triple lppp=bezierPPP(middle,left1,left2,left3); triple rppp=bezierPPP(middle,right1,right2,right3); triple n2= 9.0*cross(rpp,lpp)+ 3.0*(cross(rp,lppp)+cross(rppp,lp)+ cross(rppp,lpp)+cross(rpp,lppp))+ cross(rppp,lppp); return unit(n2); } } triple normal(triple left3, triple left2, triple left1, triple middle, triple right1, triple right2, triple right3) { triple bu=right1-middle; triple bv=left1-middle; triple n=triple(bu.gety()*bv.getz()-bu.getz()*bv.gety(), bu.getz()*bv.getx()-bu.getx()*bv.getz(), bu.getx()*bv.gety()-bu.gety()*bv.getx()); return abs2(n) > epsilon ? unit(n) : normal0(left3,left2,left1,middle,right1,right2,right3); } void mesh(const triple *p, const GLuint *I) { // Draw the frame of the control points of a cubic Bezier mesh GLuint I0=I[0]; GLuint I1=I[1]; GLuint I2=I[2]; indices.push_back(I0); indices.push_back(I1); indices.push_back(I2); } // Pi is the full precision value indexed by Ii. // The 'flati' are flatness flags for each boundary. void render(const triple *p, int n, GLuint I0, GLuint I1, GLuint I2, triple P0, triple P1, triple P2, bool flat1, bool flat2, bool flat3, GLfloat *C0=NULL, GLfloat *C1=NULL, GLfloat *C2=NULL) { // Uses a uniform partition // p points to an array of 10 triples. // Draw a Bezier triangle. // p is the set of control points for the Bezier triangle // n is the maximum number of iterations to compute triple d=displacement(p); // This involves fewer triangle computations at the end (since if the // surface is sufficiently flat, it just draws the sufficiently flat // triangle, rather than trying to properly utilize the already // computed values. if(n == 0 || length(d) < res) { // If triangle is flat... GLuint I[]={I0,I1,I2}; mesh(p,I); } else { // Triangle is not flat /* Naming Convention: * * P2 * 030 * /\ * / \ * / \ * / \ * / up \ * / \ * / \ * / \ * p1 /________________\ p0 * /\ / \ * / \ / \ * / \ / \ * / \ center / \ * / \ / \ * / \ / \ * / left \ / right \ * / \ / \ * /________________V_________________\ * 003 p2 300 * P0 P1 */ // Subdivide triangle triple l003=p[0]; triple p102=p[1]; triple p012=p[2]; triple p201=p[3]; triple p111=p[4]; triple p021=p[5]; triple r300=p[6]; triple p210=p[7]; triple p120=p[8]; triple u030=p[9]; triple u021=0.5*(u030+p021); triple u120=0.5*(u030+p120); triple p033=0.5*(p021+p012); triple p231=0.5*(p120+p111); triple p330=0.5*(p120+p210); triple p123=0.5*(p012+p111); triple l012=0.5*(p012+l003); triple p312=0.5*(p111+p201); triple r210=0.5*(p210+r300); triple l102=0.5*(l003+p102); triple p303=0.5*(p102+p201); triple r201=0.5*(p201+r300); triple u012=0.5*(u021+p033); triple u210=0.5*(u120+p330); triple l021=0.5*(p033+l012); triple p4xx=0.5*p231+0.25*(p111+p102); triple r120=0.5*(p330+r210); triple px4x=0.5*p123+0.25*(p111+p210); triple pxx4=0.25*(p021+p111)+0.5*p312; triple l201=0.5*(l102+p303); triple r102=0.5*(p303+r201); triple l210=0.5*(px4x+l201); // =c120 triple r012=0.5*(px4x+r102); // =c021 triple l300=0.5*(l201+r102); // =r003=c030 triple r021=0.5*(pxx4+r120); // =c012 triple u201=0.5*(u210+pxx4); // =c102 triple r030=0.5*(u210+r120); // =u300=c003 triple u102=0.5*(u012+p4xx); // =c201 triple l120=0.5*(l021+p4xx); // =c210 triple l030=0.5*(u012+l021); // =u003=c300 triple l111=0.5*(p123+l102); triple r111=0.5*(p312+r210); triple u111=0.5*(u021+p231); triple c111=0.25*(p033+p330+p303+p111); // For each edge of the triangle // * Check for flatness // * Store points in the GLU array accordingly // A kludge to remove subdivision cracks, only applied the first time // an edge is found to be flat before the rest of the sub-patch is. #ifdef __MSDOS__ const double epsilon=1.0*res; #else const double epsilon=0.1*res; #endif triple p2,p1,p0; if(flat1) p2=0.5*(P1+P0); else { if((flat1=length(displacement1(l003,p102,p201,r300)) < res)) p2=0.5*(P1+P0)+epsilon*unit(l300-u030); else p2=l300; } if(flat2) p1=0.5*(P2+P0); else { if((flat2=length(displacement1(l003,p012,p021,u030)) < res)) p1=0.5*(P2+P0)+epsilon*unit(l030-r300); else p1=l030; } if(flat3) p0=0.5*(P2+P1); else { if((flat3=length(displacement1(r300,p210,p120,u030)) < res)) p0=0.5*(P2+P1)+epsilon*unit(r030-l003); else p0=r030; } triple l[]={l003,l102,l012,l201,l111,l021,l300,l210,l120,l030}; // left triple r[]={l300,r102,r012,r201,r111,r021,r300,r210,r120,r030}; // right triple u[]={l030,u102,u012,u201,u111,u021,r030,u210,u120,u030}; // up triple c[]={r030,u201,r021,u102,c111,r012,l030,l120,l210,l300}; // center --n; if(C0) { GLfloat c0[4],c1[4],c2[4]; for(int i=0; i < 4; ++i) { c0[i]=0.5*(C1[i]+C2[i]); c1[i]=0.5*(C0[i]+C2[i]); c2[i]=0.5*(C0[i]+C1[i]); } GLuint i0=vertex(p0,normal(l300,r012,r021,r030,u201,u102,l030),c0); GLuint i1=vertex(p1,normal(r030,u201,u102,l030,l120,l210,l300),c1); GLuint i2=vertex(p2,normal(l030,l120,l210,l300,r012,r021,r030),c2); render(l,n,I0,i2,i1,P0,p2,p1,flat1,flat2,false,C0,c2,c1); render(r,n,i2,I1,i0,p2,P1,p0,flat1,false,flat3,c2,C1,c0); render(u,n,i1,i0,I2,p1,p0,P2,false,flat2,flat3,c1,c0,C2); render(c,n,i0,i1,i2,p0,p1,p2,false,false,false,c0,c1,c2); } else { GLuint i0=vertex(p0,normal(l300,r012,r021,r030,u201,u102,l030)); GLuint i1=vertex(p1,normal(r030,u201,u102,l030,l120,l210,l300)); GLuint i2=vertex(p2,normal(l030,l120,l210,l300,r012,r021,r030)); render(l,n,I0,i2,i1,P0,p2,p1,flat1,flat2,false); render(r,n,i2,I1,i0,p2,P1,p0,flat1,false,flat3); render(u,n,i1,i0,I2,p1,p0,P2,false,flat2,flat3); render(c,n,i0,i1,i2,p0,p1,p2,false,false,false); } } } // n is the maximum depth void render(const triple *p, double res, GLfloat *c0, int n) { this->res=res; triple po=p[0]; double epsilon=0; for(int i=1; i < 10; ++i) epsilon=max(epsilon,abs2(p[i]-po)); epsilon *= Fuzz2; GLuint i0,i1,i2; if(c0) { GLfloat *c1=c0+4; GLfloat *c2=c0+8; i0=vertex(p[0],normal(p[9],p[5],p[2],p[0],p[1],p[3],p[6]),c0); i1=vertex(p[6],normal(p[0],p[1],p[3],p[6],p[7],p[8],p[9]),c1); i2=vertex(p[9],normal(p[6],p[7],p[8],p[9],p[5],p[2],p[0]),c2); if(n > 0) render(p,n,i0,i1,i2,p[0],p[6],p[9],false,false,false,c0,c1,c2); } else { i0=vertex(p[0],normal(p[9],p[5],p[2],p[0],p[1],p[3],p[6])); i1=vertex(p[6],normal(p[0],p[1],p[3],p[6],p[7],p[8],p[9])); i2=vertex(p[9],normal(p[6],p[7],p[8],p[9],p[5],p[2],p[0])); if(n > 0) render(p,n,i0,i1,i2,p[0],p[6],p[9],false,false,false); } if(n == 0) { GLuint I[]={i0,i1,i2}; mesh(p,I); } size_t stride=(c0 ? 10 : 6)*sizeof(GL_FLOAT); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); if(c0) glEnableClientState(GL_COLOR_ARRAY); glVertexPointer(3,GL_FLOAT,stride,&buffer[0]); glNormalPointer(GL_FLOAT,stride,&buffer[3]); if(c0) glColorPointer(4,GL_FLOAT,stride,&buffer[6]); glDrawElements(GL_TRIANGLES,indices.size(),GL_UNSIGNED_INT,&indices[0]); if(c0) glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); } }; Render R; void bezierTriangle(const triple *g, bool straight, double Size2, triple Size3, bool havebillboard, triple center, GLfloat *colors) { R.init(havebillboard,center); R.render(g,pixel*length(Size3)/fabs(Size2),colors,straight ? 0 : 8); R.clear(); } } //namespace camp asymptote-2.37/builtin.cc000066400000000000000000000745161265434602500154730ustar00rootroot00000000000000/***** * builtin.cc * Tom Prince 2004/08/25 * * Initialize builtins. *****/ #include #include "builtin.h" #include "entry.h" #include "runtime.h" #include "runpicture.h" #include "runlabel.h" #include "runhistory.h" #include "runarray.h" #include "runfile.h" #include "runsystem.h" #include "runstring.h" #include "runpair.h" #include "runtriple.h" #include "runpath.h" #include "runpath3d.h" #include "runmath.h" #include "types.h" #include "castop.h" #include "mathop.h" #include "arrayop.h" #include "vm.h" #include "coder.h" #include "exp.h" #include "refaccess.h" #include "settings.h" #include "opsymbols.h" #ifndef NOSYM #include "builtin.symbols.h" #endif namespace vm { // Defined in stack.cc extern vm::frame *make_dummyframe(string name); } using namespace types; using namespace camp; using namespace vm; namespace trans { using camp::transform; using camp::pair; using vm::bltin; using run::divide; using run::less; using run::greater; using run::plus; using run::minus; using namespace run; void gen_runtime_venv(venv &ve); void gen_runbacktrace_venv(venv &ve); void gen_runpicture_venv(venv &ve); void gen_runlabel_venv(venv &ve); void gen_runhistory_venv(venv &ve); void gen_runarray_venv(venv &ve); void gen_runfile_venv(venv &ve); void gen_runsystem_venv(venv &ve); void gen_runstring_venv(venv &ve); void gen_runpair_venv(venv &ve); void gen_runtriple_venv(venv &ve); void gen_runpath_venv(venv &ve); void gen_runpath3d_venv(venv &ve); void gen_runmath_venv(venv &ve); void gen_rungsl_venv(venv &ve); void addType(tenv &te, symbol name, ty *t) { te.enter(name, new tyEntry(t,0,0,position())); } // The base environments for built-in types and functions void base_tenv(tenv &te) { #define PRIMITIVE(name,Name,asyName) \ addType(te, symbol::trans(#asyName), prim##Name()); #include "primitives.h" #undef PRIMITIVE } const formal noformal(0); function *functionFromFormals(ty *result, formal f1=noformal, formal f2=noformal, formal f3=noformal, formal f4=noformal, formal f5=noformal, formal f6=noformal, formal f7=noformal, formal f8=noformal, formal f9=noformal, formal fA=noformal, formal fB=noformal, formal fC=noformal, formal fD=noformal, formal fE=noformal, formal fF=noformal, formal fG=noformal, formal fH=noformal, formal fI=noformal) { function *fun = new function(result); if (f1.t) fun->add(f1); if (f2.t) fun->add(f2); if (f3.t) fun->add(f3); if (f4.t) fun->add(f4); if (f5.t) fun->add(f5); if (f6.t) fun->add(f6); if (f7.t) fun->add(f7); if (f8.t) fun->add(f8); if (f9.t) fun->add(f9); if (fA.t) fun->add(fA); if (fB.t) fun->add(fB); if (fC.t) fun->add(fC); if (fD.t) fun->add(fD); if (fE.t) fun->add(fE); if (fF.t) fun->add(fF); if (fG.t) fun->add(fG); if (fH.t) fun->add(fH); if (fI.t) fun->add(fI); return fun; } void addFunc(venv &ve, access *a, ty *result, symbol id, formal f1=noformal, formal f2=noformal, formal f3=noformal, formal f4=noformal, formal f5=noformal, formal f6=noformal, formal f7=noformal, formal f8=noformal, formal f9=noformal, formal fA=noformal, formal fB=noformal, formal fC=noformal, formal fD=noformal, formal fE=noformal, formal fF=noformal, formal fG=noformal, formal fH=noformal, formal fI=noformal) { function *fun = functionFromFormals(result,f1,f2,f3,f4,f5,f6,f7,f8,f9, fA,fB,fC,fD,fE,fF,fG,fH,fI); // NOTE: If the function is a field, we should encode the defining record in // the entry varEntry *ent = new varEntry(fun, a, 0, position()); ve.enter(id, ent); } // Add a function with one or more default arguments. void addFunc(venv &ve, bltin f, ty *result, symbol name, formal f1, formal f2, formal f3, formal f4, formal f5, formal f6, formal f7, formal f8, formal f9, formal fA, formal fB, formal fC, formal fD, formal fE, formal fF, formal fG, formal fH, formal fI) { #ifdef DEBUG_BLTIN // If the function is an operator, print out the whole signature with the // types, as operators are heavily overloaded. min and max are also heavily // overloaded, so we check for them too. Many builtin functions have so // many arguments that it is noise to print out their full signatures. string s = name; if (s.find("operator ", 0) == 0 || s == "min" || s == "max") { function *fun = functionFromFormals(result,f1,f2,f3,f4,f5,f6,f7,f8,f9, fA,fB,fC,fD,fE,fF,fG,fH,fI); ostringstream out; fun->printVar(out, name); REGISTER_BLTIN(f, out.str()); } else { REGISTER_BLTIN(f, name); } #endif access *a = new bltinAccess(f); addFunc(ve,a,result,name,f1,f2,f3,f4,f5,f6,f7,f8,f9, fA,fB,fC,fD,fE,fF,fG,fH,fI); } void addOpenFunc(venv &ve, bltin f, ty *result, symbol name) { function *fun = new function(result, signature::OPEN); REGISTER_BLTIN(f, name); access *a= new bltinAccess(f); varEntry *ent = new varEntry(fun, a, 0, position()); ve.enter(name, ent); } // Add a rest function with zero or more default/explicit arguments. void addRestFunc(venv &ve, bltin f, ty *result, symbol name, formal frest, formal f1=noformal, formal f2=noformal, formal f3=noformal, formal f4=noformal, formal f5=noformal, formal f6=noformal, formal f7=noformal, formal f8=noformal, formal f9=noformal) { REGISTER_BLTIN(f, name); access *a = new bltinAccess(f); function *fun = new function(result); if (f1.t) fun->add(f1); if (f2.t) fun->add(f2); if (f3.t) fun->add(f3); if (f4.t) fun->add(f4); if (f5.t) fun->add(f5); if (f6.t) fun->add(f6); if (f7.t) fun->add(f7); if (f8.t) fun->add(f8); if (f9.t) fun->add(f9); if (frest.t) fun->addRest(frest); varEntry *ent = new varEntry(fun, a, 0, position()); ve.enter(name, ent); } void addRealFunc0(venv &ve, bltin fcn, symbol name) { addFunc(ve, fcn, primReal(), name); } template void addRealFunc(venv &ve, symbol name) { addFunc(ve, realReal, primReal(), name, formal(primReal(),SYM(x))); addFunc(ve, arrayFunc, realArray(), name, formal(realArray(),SYM(a))); } #define addRealFunc(fcn, sym) addRealFunc(ve, sym); void addRealFunc2(venv &ve, bltin fcn, symbol name) { addFunc(ve,fcn,primReal(),name,formal(primReal(),SYM(a)), formal(primReal(),SYM(b))); } template void realRealInt(vm::stack *s) { Int n = pop(s); double x = pop(s); s->push(func(x, intcast(n))); } template void addRealIntFunc(venv& ve, symbol name, symbol arg1, symbol arg2) { addFunc(ve, realRealInt, primReal(), name, formal(primReal(), arg1), formal(primInt(), arg2)); } void addInitializer(venv &ve, ty *t, access *a) { addFunc(ve, a, t, symbol::initsym); } void addInitializer(venv &ve, ty *t, bltin f) { #ifdef DEBUG_BLTIN ostringstream s; s << "initializer for " << *t; REGISTER_BLTIN(f, s.str()); #endif access *a = new bltinAccess(f); addInitializer(ve, t, a); } // Specifies that source may be cast to target, but only if an explicit // cast expression is used. void addExplicitCast(venv &ve, ty *target, ty *source, access *a) { addFunc(ve, a, target, symbol::ecastsym, source); } // Specifies that source may be implicitly cast to target by the // function or instruction stores at a. void addCast(venv &ve, ty *target, ty *source, access *a) { //addExplicitCast(target,source,a); addFunc(ve, a, target, symbol::castsym, source); } void addExplicitCast(venv &ve, ty *target, ty *source, bltin f) { #ifdef DEBUG_BLTIN ostringstream s; s << "explicit cast from " << *source << " to " << *target; REGISTER_BLTIN(f, s.str()); #endif addExplicitCast(ve, target, source, new bltinAccess(f)); } void addCast(venv &ve, ty *target, ty *source, bltin f) { #ifdef DEBUG_BLTIN ostringstream s; s << "cast from " << *source << " to " << *target; REGISTER_BLTIN(f, s.str()); #endif addCast(ve, target, source, new bltinAccess(f)); } template void addVariable(venv &ve, T *ref, ty *t, symbol name, record *module=settings::getSettingsModule()) { access *a = new refAccess(ref); varEntry *ent = new varEntry(t, a, PUBLIC, module, 0, position()); ve.enter(name, ent); } template void addVariable(venv &ve, T value, ty *t, symbol name, record *module=settings::getSettingsModule(), permission perm=PUBLIC) { item* ref=new item; *ref=value; access *a = new itemRefAccess(ref); varEntry *ent = new varEntry(t, a, perm, module, 0, position()); ve.enter(name, ent); } template void addConstant(venv &ve, T value, ty *t, symbol name, record *module=settings::getSettingsModule()) { addVariable(ve,value,t,name,module,RESTRICTED); } // The identity access, i.e. no instructions are encoded for a cast or // operation, and no functions are called. identAccess id; function *IntRealFunction() { return new function(primInt(),primReal()); } function *realPairFunction() { return new function(primReal(),primPair()); } function *voidFileFunction() { return new function(primVoid(),primFile()); } void addInitializers(venv &ve) { addInitializer(ve, primBoolean(), boolFalse); addInitializer(ve, primInt(), IntZero); addInitializer(ve, primReal(), realZero); addInitializer(ve, primString(), emptyString); addInitializer(ve, primPair(), pairZero); addInitializer(ve, primTriple(), tripleZero); addInitializer(ve, primTransform(), transformIdentity); addInitializer(ve, primGuide(), nullGuide); addInitializer(ve, primPath(), nullPath); addInitializer(ve, primPath3(), nullPath3); addInitializer(ve, primPen(), newPen); addInitializer(ve, primPicture(), newPicture); addInitializer(ve, primFile(), nullFile); } void addCasts(venv &ve) { addExplicitCast(ve, primString(), primInt(), stringCast); addExplicitCast(ve, primString(), primReal(), stringCast); addExplicitCast(ve, primString(), primPair(), stringCast); addExplicitCast(ve, primString(), primTriple(), stringCast); addExplicitCast(ve, primInt(), primString(), castString); addExplicitCast(ve, primReal(), primString(), castString); addExplicitCast(ve, primPair(), primString(), castString); addExplicitCast(ve, primTriple(), primString(), castString); addExplicitCast(ve, primInt(), primReal(), castDoubleInt); addCast(ve, primReal(), primInt(), cast); addCast(ve, primPair(), primInt(), cast); addCast(ve, primPair(), primReal(), cast); addCast(ve, primPath(), primPair(), cast); addCast(ve, primGuide(), primPair(), pairToGuide); addCast(ve, primGuide(), primPath(), pathToGuide); addCast(ve, primPath(), primGuide(), guideToPath); addCast(ve, primFile(), primNull(), nullFile); // Vectorized casts. addExplicitCast(ve, IntArray(), realArray(), arrayToArray); addCast(ve, realArray(), IntArray(), arrayToArray); addCast(ve, pairArray(), IntArray(), arrayToArray); addCast(ve, pairArray(), realArray(), arrayToArray); addCast(ve, realArray2(), IntArray2(), array2ToArray2); addCast(ve, pairArray2(), IntArray2(), array2ToArray2); addCast(ve, pairArray2(), realArray2(), array2ToArray2); } void addTupleOperators(venv &ve) { addFunc(ve, realRealToPair, primPair(), SYM_TUPLE, formal(primReal(), SYM(x)), formal(primReal(), SYM(y))); addFunc(ve, realRealRealToTriple, primTriple(), SYM_TUPLE, formal(primReal(), SYM(x)), formal(primReal(), SYM(y)), formal(primReal(), SYM(z))); addFunc(ve, real6ToTransform, primTransform(), SYM_TUPLE, formal(primReal(), SYM(x)), formal(primReal(), SYM(y)), formal(primReal(), SYM(xx)), formal(primReal(), SYM(xy)), formal(primReal(), SYM(yx)), formal(primReal(), SYM(yy))); } void addGuideOperators(venv &ve) { // The guide operators .. and -- take an array of guides, and turn them // into a single guide. addRestFunc(ve, dotsGuide, primGuide(), SYM_DOTS, guideArray()); addRestFunc(ve, dashesGuide, primGuide(), SYM_DASHES, guideArray()); } /* Avoid typing the same type three times. */ void addSimpleOperator(venv &ve, bltin f, ty *t, symbol name) { addFunc(ve,f,t,name,formal(t,SYM(a)),formal(t,SYM(b))); } void addBooleanOperator(venv &ve, bltin f, ty *t, symbol name) { addFunc(ve,f,primBoolean(),name,formal(t,SYM(a)),formal(t,SYM(b))); } template class op> void addArray2Array2Op(venv &ve, ty *t3, symbol name) { addFunc(ve,array2Array2Op,t3,name,formal(t3,SYM(a)),formal(t3,SYM(b))); } template class op> void addOpArray2(venv &ve, ty *t1, symbol name, ty *t3) { addFunc(ve,opArray2,t3,name,formal(t1,SYM(a)),formal(t3,SYM(b))); } template class op> void addArray2Op(venv &ve, ty *t1, symbol name, ty *t3) { addFunc(ve,array2Op,t3,name,formal(t3,SYM(a)),formal(t1,SYM(b))); } template class op> void addOps(venv &ve, ty *t1, symbol name, ty *t2) { addSimpleOperator(ve,binaryOp,t1,name); addFunc(ve,opArray,t2,name,formal(t1,SYM(a)),formal(t2,SYM(b))); addFunc(ve,arrayOp,t2,name,formal(t2,SYM(a)),formal(t1,SYM(b))); addSimpleOperator(ve,arrayArrayOp,t2,name); } template class op> void addBooleanOps(venv &ve, ty *t1, symbol name, ty *t2) { addBooleanOperator(ve,binaryOp,t1,name); addFunc(ve,opArray, booleanArray(),name,formal(t1,SYM(a)),formal(t2,SYM(b))); addFunc(ve,arrayOp, booleanArray(),name,formal(t2,SYM(a)),formal(t1,SYM(b))); addFunc(ve,arrayArrayOp,booleanArray(),name,formal(t2,SYM(a)), formal(t2,SYM(b))); } void addWrite(venv &ve, bltin f, ty *t1, ty *t2) { addRestFunc(ve,f,primVoid(),SYM(write),t2, formal(primFile(),SYM(file),true), formal(primString(),SYM(s),true), formal(t1,SYM(x)),formal(voidFileFunction(),SYM(suffix),true)); } template void addUnorderedOps(venv &ve, ty *t1, ty *t2, ty *t3, ty *t4) { addBooleanOps(ve,t1,SYM_EQ,t2); addBooleanOps(ve,t1,SYM_NEQ,t2); addFunc(ve, run::array2Equals, primBoolean(), SYM_EQ, formal(t3, SYM(a)), formal(t3, SYM(b))); addFunc(ve, run::array2NotEquals, primBoolean(), SYM_NEQ, formal(t3, SYM(a)), formal(t3, SYM(b))); addCast(ve,t1,primFile(),read); addCast(ve,t2,primFile(),readArray1); addCast(ve,t3,primFile(),readArray2); addCast(ve,t4,primFile(),readArray3); addWrite(ve,write,t1,t2); addRestFunc(ve,writeArray,primVoid(),SYM(write),t3, formal(primFile(),SYM(file),true), formal(primString(),SYM(s),true), formal(t2,SYM(a),false,true)); addFunc(ve,writeArray2,primVoid(),SYM(write), formal(primFile(),SYM(file),true),t3); addFunc(ve,writeArray3,primVoid(),SYM(write), formal(primFile(),SYM(file),true),t4); } inline double abs(pair z) { return z.length(); } inline double abs(triple v) { return v.length(); } inline pair conjugate(pair z) { return conj(z); } template inline T negate(T x) { return -x; } template class op> void addBinOps(venv &ve, ty *t1, ty *t2, ty *t3, ty *t4, symbol name) { addFunc(ve,binopArray,t1,name,formal(t2,SYM(a))); addFunc(ve,binopArray2,t1,name,formal(t3,SYM(a))); addFunc(ve,binopArray3,t1,name,formal(t4,SYM(a))); } template void addOrderedOps(venv &ve, ty *t1, ty *t2, ty *t3, ty *t4) { addBooleanOps(ve,t1,SYM_LT,t2); addBooleanOps(ve,t1,SYM_LE,t2); addBooleanOps(ve,t1,SYM_GE,t2); addBooleanOps(ve,t1,SYM_GT,t2); addOps(ve,t1,SYM(min),t2); addOps(ve,t1,SYM(max),t2); addBinOps(ve,t1,t2,t3,t4,SYM(min)); addBinOps(ve,t1,t2,t3,t4,SYM(max)); addFunc(ve,sortArray,t2,SYM(sort),formal(t2,SYM(a))); addFunc(ve,sortArray2,t3,SYM(sort),formal(t3,SYM(a))); addFunc(ve,searchArray,primInt(),SYM(search),formal(t2,SYM(a)), formal(t1,SYM(key))); } template void addBasicOps(venv &ve, ty *t1, ty *t2, ty *t3, ty *t4, bool integer=false, bool Explicit=false) { addOps(ve,t1,SYM_PLUS,t2); addOps(ve,t1,SYM_MINUS,t2); addArray2Array2Op(ve,t3,SYM_PLUS); addArray2Array2Op(ve,t3,SYM_MINUS); addFunc(ve,&id,t1,SYM_PLUS,formal(t1,SYM(a))); addFunc(ve,&id,t2,SYM_PLUS,formal(t2,SYM(a))); addFunc(ve,Negate,t1,SYM_MINUS,formal(t1,SYM(a))); addFunc(ve,arrayFunc,t2,SYM_MINUS,formal(t2,SYM(a))); addFunc(ve,arrayFunc2,t3,SYM_MINUS,formal(t3,SYM(a))); if(!integer) addFunc(ve,interp,t1,SYM(interp), formal(t1,SYM(a),false,Explicit), formal(t1,SYM(b),false,Explicit), formal(primReal(),SYM(t))); addFunc(ve,sumArray,t1,SYM(sum),formal(t2,SYM(a))); addUnorderedOps(ve,t1,t2,t3,t4); } template void addOps(venv &ve, ty *t1, ty *t2, ty *t3, ty *t4, bool integer=false, bool Explicit=false) { addBasicOps(ve,t1,t2,t3,t4,integer,Explicit); addOps(ve,t1,SYM_TIMES,t2); addOpArray2(ve,t1,SYM_TIMES,t3); addArray2Op(ve,t1,SYM_TIMES,t3); if(!integer) { addOps(ve,t1,SYM_DIVIDE,t2); addArray2Op(ve,t1,SYM_DIVIDE,t3); } addOps(ve,t1,SYM_CARET,t2); } // Adds standard functions for a newly added array type. void addArrayOps(venv &ve, types::array *t) { ty *ct = t->celltype; // Check for the alias function to see if these operation have already been // added, if they have, don't add them again. static types::function aliasType(primBoolean(), primVoid(), primVoid()); aliasType.sig.formals[0].t = t; aliasType.sig.formals[1].t = t; if (ve.lookByType(SYM(alias), &aliasType)) return; addFunc(ve, run::arrayAlias, primBoolean(), SYM(alias), formal(t, SYM(a)), formal(t, SYM(b))); size_t depth=(size_t) t->depth(); // Define an array constructor. This needs to know the depth of the array, // which may not be known at runtime. Therefore, the depth, which is known // here at compile-time, is pushed on the stack beforehand by use of a // thunk. callable *copyValueFunc = new thunk(new vm::bfunc(run::copyArrayValue),(Int) depth-1); addFunc(ve, new callableAccess(copyValueFunc), t, SYM(array), formal(primInt(), SYM(n)), formal(ct, SYM(value)), formal(primInt(), SYM(depth), true)); callable *copyFunc = new thunk(new vm::bfunc(run::copyArray),(Int) depth); addFunc(ve, new callableAccess(copyFunc), t, SYM(copy), formal(t, SYM(a)), formal(primInt(), SYM(depth), true)); addFunc(ve, run::arrayFunction, t, SYM(map), formal(new function(ct, ct), SYM(f)), formal(t, SYM(a))); addFunc(ve, run::arraySequence, t, SYM(sequence), formal(new function(ct, primInt()), SYM(f)), formal(primInt(), SYM(n))); addFunc(ve, run::arraySort, t, SYM(sort), formal(t, SYM(a)), formal(new function(primBoolean(), ct, ct), SYM(less))); switch (depth) { case 1: addRestFunc(ve, run::arrayConcat, t, SYM(concat), new types::array(t)); addFunc(ve, run::arraySearch, primInt(), SYM(search), formal(t, SYM(a)), formal(ct, SYM(key)), formal(new function(primBoolean(), ct, ct), SYM(less))); break; case 2: addFunc(ve, run::array2Transpose, t, SYM(transpose), formal(t, SYM(a))); break; case 3: addFunc(ve, run::array3Transpose, t, SYM(transpose), formal(t, SYM(a)), formal(IntArray(),SYM(perm))); break; default: break; } } void addRecordOps(venv &ve, record *r) { addFunc(ve, run::boolMemEq, primBoolean(), SYM(alias), formal(r, SYM(a)), formal(r, SYM(b))); addFunc(ve, run::boolMemEq, primBoolean(), SYM_EQ, formal(r, SYM(a)), formal(r, SYM(b))); addFunc(ve, run::boolMemNeq, primBoolean(), SYM_NEQ, formal(r, SYM(a)), formal(r, SYM(b))); } void addFunctionOps(venv &ve, function *f) { // No function ops. } void addOperators(venv &ve) { addSimpleOperator(ve,binaryOp,primString(),SYM_PLUS); addBooleanOps(ve,primBoolean(),SYM_AMPERSAND,booleanArray()); addBooleanOps(ve,primBoolean(),SYM_BAR,booleanArray()); addBooleanOps(ve,primBoolean(),SYM_CARET,booleanArray()); addUnorderedOps(ve,primBoolean(),booleanArray(),booleanArray2(), booleanArray3()); addOps(ve,primInt(),IntArray(),IntArray2(),IntArray3(),true); addOps(ve,primReal(),realArray(),realArray2(),realArray3()); addOps(ve,primPair(),pairArray(),pairArray2(),pairArray3(),false,true); addBasicOps(ve,primTriple(),tripleArray(),tripleArray2(), tripleArray3()); addFunc(ve,opArray,tripleArray(),SYM_TIMES, formal(primReal(),SYM(a)),formal(tripleArray(),SYM(b))); addFunc(ve,opArray2,tripleArray2(),SYM_TIMES, formal(primReal(),SYM(a)),formal(tripleArray2(),SYM(b))); addFunc(ve,arrayOp,tripleArray(),SYM_TIMES, formal(tripleArray(),SYM(a)),formal(primReal(),SYM(b))); addFunc(ve,array2Op,tripleArray2(),SYM_TIMES, formal(tripleArray2(),SYM(a)),formal(primReal(),SYM(b))); addFunc(ve,arrayOp,tripleArray(),SYM_DIVIDE, formal(tripleArray(),SYM(a)),formal(primReal(),SYM(b))); addUnorderedOps(ve,primString(),stringArray(),stringArray2(), stringArray3()); addSimpleOperator(ve,binaryOp,primPair(),SYM(minbound)); addSimpleOperator(ve,binaryOp,primPair(),SYM(maxbound)); addSimpleOperator(ve,binaryOp,primTriple(),SYM(minbound)); addSimpleOperator(ve,binaryOp,primTriple(),SYM(maxbound)); addBinOps(ve,primPair(),pairArray(),pairArray2(),pairArray3(), SYM(minbound)); addBinOps(ve,primPair(),pairArray(),pairArray2(),pairArray3(), SYM(maxbound)); addBinOps(ve,primTriple(),tripleArray(),tripleArray2(), tripleArray3(),SYM(minbound)); addBinOps(ve,primTriple(),tripleArray(),tripleArray2(), tripleArray3(),SYM(maxbound)); addFunc(ve,arrayFunc,realArray(),SYM(abs), formal(pairArray(),SYM(a))); addFunc(ve,arrayFunc,realArray(),SYM(abs), formal(tripleArray(),SYM(a))); addFunc(ve,arrayFunc,pairArray(),SYM(conj), formal(pairArray(),SYM(a))); addFunc(ve,arrayFunc2,pairArray2(),SYM(conj), formal(pairArray2(),SYM(a))); addFunc(ve,binaryOp,primReal(),SYM_DIVIDE, formal(primInt(),SYM(a)),formal(primInt(),SYM(b))); addFunc(ve,arrayOp,realArray(),SYM_DIVIDE, formal(IntArray(),SYM(a)),formal(primInt(),SYM(b))); addFunc(ve,opArray,realArray(),SYM_DIVIDE, formal(primInt(),SYM(a)),formal(IntArray(),SYM(b))); addFunc(ve,arrayArrayOp,realArray(),SYM_DIVIDE, formal(IntArray(),SYM(a)),formal(IntArray(),SYM(b))); addOrderedOps(ve,primInt(),IntArray(),IntArray2(),IntArray3()); addOrderedOps(ve,primReal(),realArray(),realArray2(),realArray3()); addOrderedOps(ve,primString(),stringArray(),stringArray2(), stringArray3()); addOps(ve,primInt(),SYM_MOD,IntArray()); addOps(ve,primReal(),SYM_MOD,realArray()); addRestFunc(ve,diagonal,IntArray2(),SYM(diagonal),IntArray()); addRestFunc(ve,diagonal,realArray2(),SYM(diagonal),realArray()); addRestFunc(ve,diagonal,pairArray2(),SYM(diagonal),pairArray()); } dummyRecord *createDummyRecord(venv &ve, symbol name) { dummyRecord *r=new dummyRecord(name); vm::frame *f = make_dummyframe(name); addConstant(ve, f, r, name); addRecordOps(ve, r); return r; } double identity(double x) {return x;} double pow10(double x) {return run::pow(10.0,x);} // An example of an open function. #ifdef OPENFUNCEXAMPLE void openFunc(stack *Stack) { vm::array *a=vm::pop(Stack); size_t numArgs=checkArray(a); for (size_t k=0; kpush((Int)numArgs); } #endif // A function accessible in asy code print the bytecode of a function. void printBytecode(stack *Stack) { // As arbitrary addresses can be sent to printBytecode, it should not be run // in safe mode. if (settings::safe) { cerr << "use -nosafe flag to enable printBytecode" << endl; return; } vm::array *a=vm::pop(Stack); size_t numArgs=checkArray(a); if (numArgs != 1) cerr << "printBytecode takes one argument" << endl; // TODO: Add a reliable test for the object being a func. callable *c = a->read(0); if (func *f = dynamic_cast(c)) print(cout, f->body->code); else cout << "callable is not a standard function"; } // NOTE: We should move all of these into a "builtin" module. void base_venv(venv &ve) { // Register the name of arrayDeleteHelper for debugging in "asy -s" mode. // This is done automatically for other function, but because // arrayDeleteHelper is not defined in the usual way, it must be done // explicitly, and here is as good a place as any. REGISTER_BLTIN(arrayDeleteHelper, "arrayDeleteHelper"); addInitializers(ve); addCasts(ve); addOperators(ve); addTupleOperators(ve); addGuideOperators(ve); addRealFunc(sin,SYM(sin)); addRealFunc(cos,SYM(cos)); addRealFunc(tan,SYM(tan)); addRealFunc(asin,SYM(asin)); addRealFunc(acos,SYM(acos)); addRealFunc(atan,SYM(atan)); addRealFunc(exp,SYM(exp)); addRealFunc(log,SYM(log)); addRealFunc(log10,SYM(log10)); addRealFunc(sinh,SYM(sinh)); addRealFunc(cosh,SYM(cosh)); addRealFunc(tanh,SYM(tanh)); addRealFunc(asinh,SYM(asinh)); addRealFunc(acosh,SYM(acosh)); addRealFunc(atanh,SYM(atanh)); addRealFunc(sqrt,SYM(sqrt)); addRealFunc(cbrt,SYM(cbrt)); addRealFunc(fabs,SYM(fabs)); addRealFunc(ve,SYM(abs)); addRealFunc(expm1,SYM(expm1)); addRealFunc(log1p,SYM(log1p)); addRealIntFunc(ve, SYM(ldexp), SYM(x), SYM(e)); addRealFunc(pow10,SYM(pow10)); addRealFunc(identity,SYM(identity)); #ifdef STRUCTEXAMPLE dummyRecord *fun=createDummyRecord(ve, SYM(test)); addFunc(fun->e.ve,realReal,primReal(),SYM(f),formal(primReal(),SYM(x))); addVariable(fun->e.ve,1,primInt(),SYM(x)); #endif addFunc(ve,writestring,primVoid(),SYM(write), formal(primFile(),SYM(file),true), formal(primString(),SYM(s)), formal(voidFileFunction(),SYM(suffix),true)); addWrite(ve,write,primTransform(),transformArray()); addWrite(ve,write,primGuide(),guideArray()); addWrite(ve,write,primPen(),penArray()); addFunc(ve,arrayArrayOp,booleanArray(),SYM_EQ, formal(penArray(),SYM(a)),formal(penArray(),SYM(b))); addFunc(ve,arrayArrayOp,booleanArray(),SYM_NEQ, formal(penArray(),SYM(a)),formal(penArray(),SYM(b))); addFunc(ve,arrayFunction,realArray(),SYM(map), formal(realPairFunction(),SYM(f)), formal(pairArray(),SYM(a))); addFunc(ve,arrayFunction,IntArray(),SYM(map), formal(IntRealFunction(),SYM(f)), formal(realArray(),SYM(a))); addConstant(ve, Int_MAX, primInt(), SYM(intMax)); addConstant(ve, Int_MIN, primInt(), SYM(intMin)); addConstant(ve, HUGE_VAL, primReal(), SYM(inf)); addConstant(ve, run::infinity, primReal(), SYM(infinity)); addConstant(ve, nan(""), primReal(), SYM(nan)); addConstant(ve, DBL_MAX, primReal(), SYM(realMax)); addConstant(ve, DBL_MIN, primReal(), SYM(realMin)); addConstant(ve, DBL_EPSILON, primReal(), SYM(realEpsilon)); addConstant(ve, DBL_DIG, primInt(), SYM(realDigits)); addConstant(ve, RANDOM_MAX, primInt(), SYM(randMax)); addConstant(ve, PI, primReal(), SYM(pi)); addConstant(ve, string(REVISION),primString(),SYM(VERSION)); addVariable(ve, &processData().currentpen, primPen(), SYM(currentpen)); #ifdef OPENFUNCEXAMPLE addOpenFunc(ve, openFunc, primInt(), SYM(openFunc)); #endif addOpenFunc(ve, printBytecode, primVoid(), SYM(printBytecode)); gen_runtime_venv(ve); gen_runbacktrace_venv(ve); gen_runpicture_venv(ve); gen_runlabel_venv(ve); gen_runhistory_venv(ve); gen_runarray_venv(ve); gen_runfile_venv(ve); gen_runsystem_venv(ve); gen_runstring_venv(ve); gen_runpair_venv(ve); gen_runtriple_venv(ve); gen_runpath_venv(ve); gen_runpath3d_venv(ve); gen_runmath_venv(ve); #ifdef HAVE_LIBGSL gen_rungsl_venv(ve); #endif } } //namespace trans namespace run { double infinity=cbrt(DBL_MAX); // Reduced for tension atleast infinity void arrayDeleteHelper(stack *Stack) { array *a=pop(Stack); item itj=pop(Stack); bool jdefault=isdefault(itj); item iti=pop(Stack); Int i,j; if(isdefault(iti)) { if(jdefault) { (*a).clear(); return; } else i=j=get(itj); } else { i=get(iti); j=jdefault ? i : get(itj); } size_t asize=checkArray(a); if(a->cyclic() && asize > 0) { if(j-i+1 >= (Int) asize) { (*a).clear(); return; } i=imod(i,asize); j=imod(j,asize); if(j >= i) (*a).erase((*a).begin()+i,(*a).begin()+j+1); else { (*a).erase((*a).begin()+i,(*a).end()); (*a).erase((*a).begin(),(*a).begin()+j+1); } return; } if(i < 0 || i >= (Int) asize || i > j || j >= (Int) asize) { ostringstream buf; buf << "delete called on array of length " << (Int) asize << " with out-of-bounds index range [" << i << "," << j << "]"; error(buf); } (*a).erase((*a).begin()+i,(*a).begin()+j+1); } // Used by coder to optimize conditional jumps. const bltin intLess = binaryOp; const bltin intGreater = binaryOp; } asymptote-2.37/builtin.h000066400000000000000000000031451265434602500153230ustar00rootroot00000000000000/***** * builtin.h * Tom Prince 2004/08/25 * * Initialize builtins. *****/ #ifndef BUILTIN_H #define BUILTIN_H #include "vm.h" #include "types.h" #include "arrayop.h" namespace trans { class tenv; class venv; // The base environments for built-in types and functions void base_tenv(tenv &); void base_venv(venv &); extern const types::formal noformal; // Add a function with one or more default arguments. void addFunc(venv &ve, vm::bltin f, types::ty *result, symbol name, types::formal f1=noformal, types::formal f2=noformal, types::formal f3=noformal, types::formal f4=noformal, types::formal f5=noformal, types::formal f6=noformal, types::formal f7=noformal, types::formal f8=noformal, types::formal f9=noformal, types::formal fA=noformal, types::formal fB=noformal, types::formal fC=noformal, types::formal fD=noformal, types::formal fE=noformal, types::formal fF=noformal, types::formal fG=noformal, types::formal fH=noformal, types::formal fI=noformal); // Adds standard functions for a newly added types. void addArrayOps(venv &ve, types::array *t); void addRecordOps(venv &ve, types::record *r); void addFunctionOps(venv &ve, types::function *f); #ifdef HAVE_LIBGSL types::record *getGSLModule(); void GSLrngFree(); #endif } //namespace trans namespace run { extern double infinity; void single(vm::stack *Stack); void arrayDeleteHelper(vm::stack *Stack); // Used by to optimize conditional jumps. extern const vm::bltin intLess; extern const vm::bltin intGreater; } #endif //BUILTIN_H asymptote-2.37/callable.cc000066400000000000000000000021771265434602500155560ustar00rootroot00000000000000/***** * callable.cc * Tom Prince 2005/06/19 * * Runtime representation of functions. *****/ #include "stack.h" #include "callable.h" namespace vm { callable::~callable() {} void func::call(stack *s) { s->run(this); } void nullfunc::print(ostream& out) { out << "nullfunc"; } bool func::compare(callable* F) { if (func* f=dynamic_cast(F)) return (body == f->body) && (closure == f->closure); else return false; } void func::print(ostream& out) { out << "func with lambda"; #ifdef DEBUG_FRAME out << " " << body->name; #endif } bool bfunc::compare(callable* F) { if (bfunc* f=dynamic_cast(F)) return (func == f->func); else return false; } void bfunc::print(ostream& out) { out << "bltin"; #ifdef DEBUG_BLTIN out << " " << lookupBltin(func); #endif } void thunk::call(stack *s) { s->push(arg); func->call(s); } void thunk::print(ostream& out) { out << "thunk on " << arg << " with "; func->print(out); } nullfunc nullfunc::func; void nullfunc::call(stack *) { error("dereference of null function"); } bool nullfunc::compare(callable* f) { return f == &func; } } // namespace vm asymptote-2.37/callable.h000066400000000000000000000031521265434602500154120ustar00rootroot00000000000000/***** * callable.h * Tom Prince 2005/06/19 * * Runtime representation of functions. *****/ #ifndef CALLABLE_H #define CALLABLE_H #include "common.h" #include "item.h" #include "inst.h" namespace vm { class stack; typedef void (*bltin)(stack *s); struct callable : public gc { virtual void call(stack *) = 0; virtual ~callable(); virtual bool compare(callable*) { return false; } // For debugging: virtual void print(ostream& out) = 0; }; class nullfunc : public callable { private: nullfunc() {} static nullfunc func; public: virtual void call (stack*); virtual bool compare(callable*); static callable* instance() { return &func; } void print(ostream& out); }; // How a function reference to a non-builtin function is stored. struct func : public callable { lambda *body; frame *closure; func () : body(), closure() {} virtual void call (stack*); virtual bool compare(callable*); void print(ostream& out); }; class bfunc : public callable { public: bfunc(bltin b) : func(b) {} virtual void call (stack *s) { func(s); } virtual bool compare(callable*); void print(ostream& out); private: bltin func; }; class thunk : public callable { public: thunk(callable *f, item i) : func(f), arg(i) {} virtual void call (stack*); void print(ostream& out); private: callable *func; item arg; }; inline ostream& operator<< (ostream& out, callable &c) { c.print(out); return out; } } // namespace vm GC_DECLARE_PTRFREE(vm::nullfunc); // I believe this is safe, as pointers to C++ functions do not point to // the heap. GC_DECLARE_PTRFREE(vm::bfunc); #endif // CALLABLE_H asymptote-2.37/camp.l000066400000000000000000000316351265434602500146060ustar00rootroot00000000000000%{ /***** * camp.l * Andy Hammerlindl 2002/06/14 * * The lexical analyzer of the Asymptote language. *****/ #include #include #include #include #include "util.h" #include "modifier.h" #include "exp.h" #include "stm.h" #include "fundec.h" #include "errormsg.h" #include "interact.h" #include "lexical.h" using namespace absyntax; using mem::string; #include "camp.tab.h" #include "opsymbols.h" #define YY_NO_INPUT static void yyunput(int, char *); void (*unused)(int,char *) = yyunput; fileinfo* fi; Int tokPos; Int charPos; //int commentDepth = 0; bool eof; string eofMessage; extern errorstream em; extern "C" int yywrap(void) { charPos=1; return 1; } typedef size_t (*input_f) (char* bif, size_t max_size); input_f yy_input = NULL; void setlexer(input_f input, string filename) { YY_FLUSH_BUFFER; yywrap(); fi = new fileinfo(filename); yy_input = input; tokPos = charPos = 1; eof=false; eofMessage=""; } #define YY_INPUT(buf,result,max_size) {result=yy_input(buf,max_size);} position lexerPos() { position p; p.init(fi, tokPos); return p; } namespace { position here() { return lexerPos(); } void adjust() { tokPos = charPos; charPos += yyleng; yylval.pos = here(); } void savesymbol(symbol name) { adjust(); yylval.ps.pos=yylval.pos; // avoid invoking here() twice yylval.ps.sym=name; } /* For optimization reasons, the operator names are translated into symbols * just once, and can be accessed throughout the code as SYM_PLUS, SYM_DASHES, * etc. Following the Don't Repeat Yourself principle, the mapping from * strings to names is defined only here in camp.l (because we can't produce * lex rules from a C style macro). * The script opsymbols.pl reads this file scanning for rules using DEFSYMBOL * and creates opsymbols.h which defines the names for use in C++ code. */ #define DEFSYMBOL(name) \ savesymbol(name) /* Extra symbols can be added by EXTRASYMBOL */ #define EXTRASYMBOL(chars, codename) /* blank */ EXTRASYMBOL(tuple, SYM_TUPLE); void makesymbol() { assert(strlen(yytext) == (size_t)yyleng); savesymbol(symbol::rawTrans(yytext, yyleng+1)); } void makeopsymbol() { savesymbol(symbol::opTrans(yytext)); } void makemod(trans::modifier mod) { yylval.mod.pos=here(); yylval.mod.val=mod; } void makeperm(trans::permission perm) { yylval.perm.pos=here(); yylval.perm.val=perm; } void newline() { fi->newline(); charPos = tokPos = 1; } void error(void) { em.error(here()); } } // Used by the lexer rules to flag an unexpected end of input. The message is // the error message that should be reported, and may differ if, say the input // ends in the middle of a string or comment. void setEOF(string message) { eof=true; eofMessage=message; } // Called by code outside of the lexer to see if a parse error was caused by // running out of input. bool lexerEOF() { return eof; } // Called by code outside of the lexer when it wants to report the unexpected // eof as an error (instead of looking for more input). void reportEOF() { assert(eof); error(); em << eofMessage; em.sync(); } position stringpos; // The position of the start of the string. string stringbuild; // Stores the string literal as it is read. namespace { void startstring() { adjust(); stringpos = here(); } void append(char c) { stringbuild.push_back(c); yylval.pos = here(); } void getstring(void) { // NOTE: Replace here() with a position at the start of the string. yylval.stre = new stringExp(stringpos, stringbuild); string().swap(stringbuild); } } %} %x lexcomment %x texstring %x cstring %x lexformat %x opname LETTER [_A-Za-z] ESC \\ ENDL \\?(\r\n|\n|\r) EXTRAOPS <<|>>|$|$$|@|@@|~ %% { \/\* {adjust(); /*commentDepth++;*/} \*\/ {adjust(); /*commentDepth--;*/ /*if (commentDepth == 0)*/ BEGIN INITIAL; } \r\n|\n|\r {adjust(); newline(); continue; } <> {adjust(); setEOF("comment not terminated"); BEGIN INITIAL; return GARBAGE; } . {adjust(); continue; } } { \"/([ \t]|{ENDL})*[\"\'] {adjust(); BEGIN INITIAL;} \" {adjust(); BEGIN INITIAL; getstring(); return STRING; } <> {adjust(); setEOF("string not terminated"); BEGIN INITIAL; getstring(); return GARBAGE; } {ENDL} {adjust(); newline(); append('\n'); continue; } {ESC}{ESC} {adjust(); append('\\'); append('\\'); continue; } {ESC}\" {adjust(); append('\"'); continue; } . {adjust(); append(*yytext); } } { \'/([ \t]|{ENDL})*[\"\'] {adjust(); BEGIN INITIAL;} \' {adjust(); BEGIN INITIAL; getstring(); return STRING; } <> {adjust(); setEOF("string not terminated"); BEGIN INITIAL; getstring(); return GARBAGE; } {ENDL} {adjust(); newline(); append('\n'); continue; } {ESC}(\'|\"|\?|\\) {adjust(); append(yytext[1]); continue; } {ESC}a {adjust(); append('\a'); continue; } {ESC}b {adjust(); append('\b'); continue; } {ESC}f {adjust(); append('\f'); continue; } {ESC}n {adjust(); append('\n'); continue; } {ESC}r {adjust(); append('\r'); continue; } {ESC}t {adjust(); append('\t'); continue; } {ESC}v {adjust(); append('\v'); continue; } {ESC}[0-7] {adjust(); char x=(char)(yytext[1]-'0'); append(x); continue; } {ESC}[0-7][0-7] {adjust(); char x=(char)((yytext[1]-'0')*8+yytext[2]-'0'); append(x); continue; } {ESC}[0-3][0-7][0-7] {adjust(); char x=(char)((yytext[1]-'0')*64+(yytext[2]-'0')*8 +yytext[3]-'0'); append(x); continue; } {ESC}x[0-9,A-F] {adjust(); char x=(char) (yytext[2] <= '9' ? yytext[2]-'0' : 10+yytext[2]-'A'); append(x); continue; } {ESC}x[0-9,A-F][0-9,A-F] {adjust(); char x=(char) ((yytext[2] <= '9' ? yytext[2]-'0' : 10+yytext[2]-'A')*16 +(yytext[3] <= '9' ? yytext[3]-'0' : 10+yytext[3]-'A')); append(x); continue; } . {adjust(); append(*yytext); } } [ \t] {adjust(); continue;} {ENDL} {adjust(); newline(); continue;} \/\/[^\n]* {adjust(); continue;} "," {adjust(); return ','; } ":" {adjust(); return ':'; } ";" {adjust(); return ';'; } "(" {adjust(); return '('; } ")" {adjust(); return ')'; } "[" {adjust(); return '['; } "]" {adjust(); return ']'; } "{" {adjust(); return '{'; } "}" {adjust(); return '}'; } "." {adjust(); return '.'; } "..." {adjust(); return ELLIPSIS; } "+" {DEFSYMBOL(SYM_PLUS); return '+'; } "-" {DEFSYMBOL(SYM_MINUS); return '-'; } "*" {DEFSYMBOL(SYM_TIMES); return '*'; } "/" {DEFSYMBOL(SYM_DIVIDE); return '/'; } "%" {DEFSYMBOL(SYM_MOD); return '%'; } "^" {DEFSYMBOL(SYM_CARET); return '^'; } "**" {savesymbol(SYM_CARET); return '^'; } "?" {adjust(); return '?'; } "=" {adjust(); return ASSIGN; } "==" {DEFSYMBOL(SYM_EQ); return EQ; } "!=" {DEFSYMBOL(SYM_NEQ); return NEQ; } "<" {DEFSYMBOL(SYM_LT); return LT; } "<=" {DEFSYMBOL(SYM_LE); return LE; } ">" {DEFSYMBOL(SYM_GT); return GT; } ">=" {DEFSYMBOL(SYM_GE); return GE; } "&&" {DEFSYMBOL(SYM_CAND); return CAND; } "||" {DEFSYMBOL(SYM_COR); return COR; } "!" {DEFSYMBOL(SYM_LOGNOT); return OPERATOR; } "^^" {DEFSYMBOL(SYM_CARETS); return CARETS; } "::" {DEFSYMBOL(SYM_COLONS); return COLONS; } "++" {DEFSYMBOL(SYM_INCR); return INCR; } ".." {DEFSYMBOL(SYM_DOTS); return DOTS; } "--" {DEFSYMBOL(SYM_DASHES); return DASHES; } "---" {DEFSYMBOL(SYM_LONGDASH); return LONGDASH; } "&" {DEFSYMBOL(SYM_AMPERSAND); return AMPERSAND; } "|" {DEFSYMBOL(SYM_BAR); return BAR; } {EXTRAOPS} {makeopsymbol(); return OPERATOR; } "+=" {savesymbol(SYM_PLUS); return SELFOP; } "-=" {savesymbol(SYM_MINUS); return SELFOP; } "*=" {savesymbol(SYM_TIMES); return SELFOP; } "/=" {savesymbol(SYM_DIVIDE); return SELFOP; } "%=" {savesymbol(SYM_MOD); return SELFOP; } "^=" {savesymbol(SYM_CARET); return SELFOP; } and {adjust(); return AND; } controls {DEFSYMBOL(SYM_CONTROLS); return CONTROLS; } tension {DEFSYMBOL(SYM_TENSION); return TENSION; } atleast {DEFSYMBOL(SYM_ATLEAST); return ATLEAST; } curl {DEFSYMBOL(SYM_CURL); return CURL; } if {adjust(); return IF; } else {adjust(); return ELSE; } while {adjust(); return WHILE; } for {adjust(); return FOR; } do {adjust(); return DO; } return {adjust(); return RETURN_; } break {adjust(); return BREAK; } continue {adjust(); return CONTINUE; } struct {adjust(); return STRUCT; } typedef {adjust(); return TYPEDEF; } new {adjust(); return NEW; } access {adjust(); return ACCESS; } import {adjust(); return IMPORT; } unravel {adjust(); return UNRAVEL; } from {adjust(); return FROM; } include {adjust(); return INCLUDE; } quote {adjust(); return QUOTE; } static {adjust(); makemod(trans::EXPLICIT_STATIC); return MODIFIER; } public {adjust(); makeperm(trans::PUBLIC); return PERM; } private {adjust(); makeperm(trans::PRIVATE); return PERM; } restricted {adjust(); makeperm(trans::RESTRICTED); return PERM; } this {adjust(); return THIS; } explicit {adjust(); return EXPLICIT; } [0-9]+ try { adjust(); yylval.e= new intExp(here(), lexical::cast(yytext)); } catch (lexical::bad_cast&) { error(); em << "invalid integer"; yylval.e= new intExp(here(), 0); } return LIT; ([0-9]*\.[0-9]+)|([0-9]+\.[0-9]*)|([0-9]*\.*[0-9]+e[-+]*[0-9]+)|([0-9]+\.[0-9]*e[-+]*[0-9]+) try { adjust(); yylval.e= new realExp(here(), lexical::cast(yytext)); } catch (lexical::bad_cast&) { error(); em << "invalid real"; yylval.e= new realExp(here(), 0); } return LIT; true { adjust(); yylval.e= new booleanExp(here(), true); return LIT; } false { adjust(); yylval.e= new booleanExp(here(), false); return LIT; } null { adjust(); yylval.e= new nullExp(here()); return LIT; } cycle { adjust(); yylval.e= new cycleExp(here()); return LIT; } newframe { adjust(); yylval.e= new newPictureExp(here()); return LIT; } operator {adjust(); BEGIN opname; } { [ \t\r] {adjust(); continue;} {ENDL} {adjust(); newline(); continue;} <> {adjust(); setEOF("missing operator name"); BEGIN INITIAL; return GARBAGE; } "**" { savesymbol(SYM_CARET); BEGIN INITIAL; return ID; } [-+*/%^!<>]|==|!=|<=|>=|&|\||\^\^|\.\.|::|--|---|\+\+|{EXTRAOPS} { makeopsymbol(); BEGIN INITIAL; return ID;} {LETTER}({LETTER}|[0-9])* { makeopsymbol(); BEGIN INITIAL; return ID; } . {} } {LETTER}({LETTER}|[0-9])* { makesymbol(); return ID; } \/\* {adjust(); /*commentDepth = 1;*/ BEGIN lexcomment; } \" {startstring(); BEGIN texstring; } \' {startstring(); BEGIN cstring; } <> { setEOF("unexpected end of input"); yyterminate(); } . {adjust(); error(); em << "invalid token"; if (isgraph(yytext[0])) em << " '" << yytext[0] << "'"; } asymptote-2.37/camp.y000066400000000000000000000467621265434602500146320ustar00rootroot00000000000000%{ /***** * camp.y * Andy Hammerlindl 08/12/2002 * * The grammar of the camp language. *****/ #include "errormsg.h" #include "exp.h" #include "newexp.h" #include "dec.h" #include "fundec.h" #include "stm.h" #include "modifier.h" #include "opsymbols.h" // Avoid error messages with unpatched bison-1.875: #ifndef __attribute__ #define __attribute__(x) #endif // Used when a position needs to be determined and no token is // available. Defined in camp.l. position lexerPos(); bool lexerEOF(); int yylex(void); /* function prototype */ void yyerror(const char *s) { if (!lexerEOF()) { em.error(lexerPos()); em << s; em.cont(); } } // Check if the symbol given is "keyword". Returns true in this case and // returns false and reports an error otherwise. bool checkKeyword(position pos, symbol sym) { if (sym != symbol::trans("keyword")) { em.error(pos); em << "expected 'keyword' here"; return false; } return true; } namespace absyntax { file *root; } using namespace absyntax; using sym::symbol; using mem::string; %} %union { position pos; bool boo; struct { position pos; sym::symbol sym; } ps; absyntax::name *n; absyntax::varinit *vi; absyntax::arrayinit *ai; absyntax::exp *e; absyntax::stringExp *stre; absyntax::specExp *se; absyntax::joinExp *j; absyntax::explist *elist; absyntax::argument arg; absyntax::arglist *alist; absyntax::slice *slice; absyntax::dimensions *dim; absyntax::ty *t; absyntax::decid *di; absyntax::decidlist *dil; absyntax::decidstart *dis; absyntax::runnable *run; struct { position pos; trans::permission val; } perm; struct { position pos; trans::modifier val; } mod; absyntax::modifierList *ml; //absyntax::program *prog; absyntax::vardec *vd; //absyntax::vardecs *vds; absyntax::dec *d; absyntax::idpair *ip; absyntax::idpairlist *ipl; absyntax::stm *s; absyntax::block *b; absyntax::stmExpList *sel; //absyntax::funheader *fh; absyntax::formal *fl; absyntax::formals *fls; } %token ID SELFOP DOTS COLONS DASHES INCR LONGDASH CONTROLS TENSION ATLEAST CURL COR CAND BAR AMPERSAND EQ NEQ LT LE GT GE CARETS '+' '-' '*' '/' '%' '^' OPERATOR %token LOOSE ASSIGN '?' ':' DIRTAG JOIN_PREC AND '{' '}' '(' ')' '.' ',' '[' ']' ';' ELLIPSIS ACCESS UNRAVEL IMPORT INCLUDE FROM QUOTE STRUCT TYPEDEF NEW IF ELSE WHILE DO FOR BREAK CONTINUE RETURN_ THIS EXPLICIT GARBAGE %token LIT %token STRING %token PERM %token MODIFIER %right ASSIGN SELFOP %right '?' ':' %left COR %left CAND %left BAR %left AMPERSAND %left EQ NEQ %left LT LE GT GE %left OPERATOR %left CARETS %left JOIN_PREC DOTS COLONS DASHES INCR LONGDASH %left DIRTAG CONTROLS TENSION ATLEAST AND %left CURL '{' '}' %left '+' '-' %left '*' '/' '%' LIT %left UNARY %right '^' %left EXP_IN_PARENS_RULE %left '(' ')' %type fileblock bareblock block %type name %type runnable %type modifiers %type dec fundec typedec %type strid %type idpair stridpair %type idpairlist stridpairlist %type vardec barevardec %type type celltype %type dims %type decidlist %type decid %type decidstart %type varinit %type arrayinit basearrayinit varinits %type formal %type formals %type value exp fortest %type argument %type slice %type join basicjoin %type tension controls %type dir %type dimexps %type arglist tuple %type stm stmexp blockstm %type forinit %type forupdate stmexplist %type explicitornot /* There are four shift/reduce conflicts: * the dangling ELSE in IF (exp) IF (exp) stm ELSE stm * new ID * the argument id=exp is taken as an argument instead of an assignExp * explicit cast */ %expect 4 /* Enable grammar debugging. */ /*%debug*/ %% file: fileblock { absyntax::root = $1; } ; fileblock: /* empty */ { $$ = new file(lexerPos(), false); } | fileblock runnable { $$ = $1; $$->add($2); } ; bareblock: /* empty */ { $$ = new block(lexerPos(), true); } | bareblock runnable { $$ = $1; $$->add($2); } ; name: ID { $$ = new simpleName($1.pos, $1.sym); } | name '.' ID { $$ = new qualifiedName($2, $1, $3.sym); } | '%' { $$ = new simpleName($1.pos, symbol::trans("operator answer")); } ; runnable: dec { $$ = $1; } | stm { $$ = $1; } | modifiers dec { $$ = new modifiedRunnable($1->getPos(), $1, $2); } | modifiers stm { $$ = new modifiedRunnable($1->getPos(), $1, $2); } ; modifiers: MODIFIER { $$ = new modifierList($1.pos); $$->add($1.val); } | PERM { $$ = new modifierList($1.pos); $$->add($1.val); } | modifiers MODIFIER { $$ = $1; $$->add($2.val); } | modifiers PERM { $$ = $1; $$->add($2.val); } ; dec: vardec { $$ = $1; } | fundec { $$ = $1; } | typedec { $$ = $1; } | ACCESS stridpairlist ';' { $$ = new accessdec($1, $2); } | FROM name UNRAVEL idpairlist ';' { $$ = new unraveldec($1, $2, $4); } | FROM name UNRAVEL '*' ';' { $$ = new unraveldec($1, $2, WILDCARD); } | UNRAVEL name ';' { $$ = new unraveldec($1, $2, WILDCARD); } | FROM strid ACCESS idpairlist ';' { $$ = new fromaccessdec($1, $2.sym, $4); } | FROM strid ACCESS '*' ';' { $$ = new fromaccessdec($1, $2.sym, WILDCARD); } | IMPORT stridpair ';' { $$ = new importdec($1, $2); } | INCLUDE ID ';' { $$ = new includedec($1, $2.sym); } | INCLUDE STRING ';' { $$ = new includedec($1, $2->getString()); } ; idpair: ID { $$ = new idpair($1.pos, $1.sym); } /* ID 'as' ID */ | ID ID ID { $$ = new idpair($1.pos, $1.sym, $2.sym , $3.sym); } ; idpairlist: idpair { $$ = new idpairlist(); $$->add($1); } | idpairlist ',' idpair { $$ = $1; $$->add($3); } ; strid: ID { $$ = $1; } | STRING { $$.pos = $1->getPos(); $$.sym = symbol::literalTrans($1->getString()); } ; stridpair: ID { $$ = new idpair($1.pos, $1.sym); } /* strid 'as' ID */ | strid ID ID { $$ = new idpair($1.pos, $1.sym, $2.sym , $3.sym); } ; stridpairlist: stridpair { $$ = new idpairlist(); $$->add($1); } | stridpairlist ',' stridpair { $$ = $1; $$->add($3); } ; vardec: barevardec ';' { $$ = $1; } ; barevardec: type decidlist { $$ = new vardec($1->getPos(), $1, $2); } ; type: celltype { $$ = $1; } | name dims { $$ = new arrayTy($1, $2); } ; celltype: name { $$ = new nameTy($1); } ; dims: '[' ']' { $$ = new dimensions($1); } | dims '[' ']' { $$ = $1; $$->increase(); } ; dimexps: '[' exp ']' { $$ = new explist($1); $$->add($2); } | dimexps '[' exp ']' { $$ = $1; $$->add($3); } ; decidlist: decid { $$ = new decidlist($1->getPos()); $$->add($1); } | decidlist ',' decid { $$ = $1; $$->add($3); } ; decid: decidstart { $$ = new decid($1->getPos(), $1); } | decidstart ASSIGN varinit { $$ = new decid($1->getPos(), $1, $3); } ; decidstart: ID { $$ = new decidstart($1.pos, $1.sym); } | ID dims { $$ = new decidstart($1.pos, $1.sym, $2); } | ID '(' ')' { $$ = new fundecidstart($1.pos, $1.sym, 0, new formals($2)); } | ID '(' formals ')' { $$ = new fundecidstart($1.pos, $1.sym, 0, $3); } ; varinit: exp { $$ = $1; } | arrayinit { $$ = $1; } ; block: '{' bareblock '}' { $$ = $2; } ; arrayinit: '{' '}' { $$ = new arrayinit($1); } | '{' ELLIPSIS varinit '}' { $$ = new arrayinit($1); $$->addRest($3); } | '{' basearrayinit '}' { $$ = $2; } | '{' basearrayinit ELLIPSIS varinit '}' { $$ = $2; $$->addRest($4); } ; basearrayinit: ',' { $$ = new arrayinit($1); } | varinits { $$ = $1; } | varinits ',' { $$ = $1; } ; varinits: varinit { $$ = new arrayinit($1->getPos()); $$->add($1);} | varinits ',' varinit { $$ = $1; $$->add($3); } ; formals: formal { $$ = new formals($1->getPos()); $$->add($1); } | ELLIPSIS formal { $$ = new formals($1); $$->addRest($2); } | formals ',' formal { $$ = $1; $$->add($3); } | formals ELLIPSIS formal { $$ = $1; $$->addRest($3); } ; explicitornot: EXPLICIT { $$ = true; } | { $$ = false; } ; formal: explicitornot type { $$ = new formal($2->getPos(), $2, 0, 0, $1, 0); } | explicitornot type decidstart { $$ = new formal($2->getPos(), $2, $3, 0, $1, 0); } | explicitornot type decidstart ASSIGN varinit { $$ = new formal($2->getPos(), $2, $3, $5, $1, 0); } /* The uses of ID below are 'keyword' qualifiers before the parameter name. */ | explicitornot type ID decidstart { bool k = checkKeyword($3.pos, $3.sym); $$ = new formal($2->getPos(), $2, $4, 0, $1, k); } | explicitornot type ID decidstart ASSIGN varinit { bool k = checkKeyword($3.pos, $3.sym); $$ = new formal($2->getPos(), $2, $4, $6, $1, k); } ; fundec: type ID '(' ')' blockstm { $$ = new fundec($3, $1, $2.sym, new formals($3), $5); } | type ID '(' formals ')' blockstm { $$ = new fundec($3, $1, $2.sym, $4, $6); } ; typedec: STRUCT ID block { $$ = new recorddec($1, $2.sym, $3); } | TYPEDEF vardec { $$ = new typedec($1, $2); } ; slice: ':' { $$ = new slice($1, 0, 0); } | exp ':' { $$ = new slice($2, $1, 0); } | ':' exp { $$ = new slice($1, 0, $2); } | exp ':' exp { $$ = new slice($2, $1, $3); } ; value: value '.' ID { $$ = new fieldExp($2, $1, $3.sym); } | name '[' exp ']' { $$ = new subscriptExp($2, new nameExp($1->getPos(), $1), $3); } | value '[' exp ']'{ $$ = new subscriptExp($2, $1, $3); } | name '[' slice ']' { $$ = new sliceExp($2, new nameExp($1->getPos(), $1), $3); } | value '[' slice ']'{ $$ = new sliceExp($2, $1, $3); } | name '(' ')' { $$ = new callExp($2, new nameExp($1->getPos(), $1), new arglist()); } | name '(' arglist ')' { $$ = new callExp($2, new nameExp($1->getPos(), $1), $3); } | value '(' ')' { $$ = new callExp($2, $1, new arglist()); } | value '(' arglist ')' { $$ = new callExp($2, $1, $3); } | '(' exp ')' %prec EXP_IN_PARENS_RULE { $$ = $2; } | '(' name ')' %prec EXP_IN_PARENS_RULE { $$ = new nameExp($2->getPos(), $2); } | THIS { $$ = new thisExp($1); } ; argument: exp { $$.name = symbol::nullsym; $$.val=$1; } | ID ASSIGN exp { $$.name = $1.sym; $$.val=$3; } ; arglist: argument { $$ = new arglist(); $$->add($1); } | ELLIPSIS argument { $$ = new arglist(); $$->addRest($2); } | arglist ',' argument { $$ = $1; $$->add($3); } | arglist ELLIPSIS argument { $$ = $1; $$->addRest($3); } ; /* A list of two or more expressions, separated by commas. */ tuple: exp ',' exp { $$ = new arglist(); $$->add($1); $$->add($3); } | tuple ',' exp { $$ = $1; $$->add($3); } ; exp: name { $$ = new nameExp($1->getPos(), $1); } | value { $$ = $1; } | LIT { $$ = $1; } | STRING { $$ = $1; } /* This is for scaling expressions such as 105cm */ | LIT exp { $$ = new scaleExp($1->getPos(), $1, $2); } | '(' name ')' exp { $$ = new castExp($2->getPos(), new nameTy($2), $4); } | '(' name dims ')' exp { $$ = new castExp($2->getPos(), new arrayTy($2, $3), $5); } | '+' exp %prec UNARY { $$ = new unaryExp($1.pos, $2, $1.sym); } | '-' exp %prec UNARY { $$ = new unaryExp($1.pos, $2, $1.sym); } | OPERATOR exp { $$ = new unaryExp($1.pos, $2, $1.sym); } | exp '+' exp { $$ = new binaryExp($2.pos, $1, $2.sym, $3); } | exp '-' exp { $$ = new binaryExp($2.pos, $1, $2.sym, $3); } | exp '*' exp { $$ = new binaryExp($2.pos, $1, $2.sym, $3); } | exp '/' exp { $$ = new binaryExp($2.pos, $1, $2.sym, $3); } | exp '%' exp { $$ = new binaryExp($2.pos, $1, $2.sym, $3); } | exp '^' exp { $$ = new binaryExp($2.pos, $1, $2.sym, $3); } | exp LT exp { $$ = new binaryExp($2.pos, $1, $2.sym, $3); } | exp LE exp { $$ = new binaryExp($2.pos, $1, $2.sym, $3); } | exp GT exp { $$ = new binaryExp($2.pos, $1, $2.sym, $3); } | exp GE exp { $$ = new binaryExp($2.pos, $1, $2.sym, $3); } | exp EQ exp { $$ = new equalityExp($2.pos, $1, $2.sym, $3); } | exp NEQ exp { $$ = new equalityExp($2.pos, $1, $2.sym, $3); } | exp CAND exp { $$ = new andExp($2.pos, $1, $2.sym, $3); } | exp COR exp { $$ = new orExp($2.pos, $1, $2.sym, $3); } | exp CARETS exp { $$ = new binaryExp($2.pos, $1, $2.sym, $3); } | exp AMPERSAND exp{ $$ = new binaryExp($2.pos, $1, $2.sym, $3); } | exp BAR exp{ $$ = new binaryExp($2.pos, $1, $2.sym, $3); } | exp OPERATOR exp { $$ = new binaryExp($2.pos, $1, $2.sym, $3); } | exp INCR exp { $$ = new binaryExp($2.pos, $1, $2.sym, $3); } | NEW celltype { $$ = new newRecordExp($1, $2); } | NEW celltype dimexps { $$ = new newArrayExp($1, $2, $3, 0, 0); } | NEW celltype dimexps dims { $$ = new newArrayExp($1, $2, $3, $4, 0); } | NEW celltype dims { $$ = new newArrayExp($1, $2, 0, $3, 0); } | NEW celltype dims arrayinit { $$ = new newArrayExp($1, $2, 0, $3, $4); } | NEW celltype '(' ')' blockstm { $$ = new newFunctionExp($1, $2, new formals($3), $5); } | NEW celltype dims '(' ')' blockstm { $$ = new newFunctionExp($1, new arrayTy($2->getPos(), $2, $3), new formals($4), $6); } | NEW celltype '(' formals ')' blockstm { $$ = new newFunctionExp($1, $2, $4, $6); } | NEW celltype dims '(' formals ')' blockstm { $$ = new newFunctionExp($1, new arrayTy($2->getPos(), $2, $3), $5, $7); } | exp '?' exp ':' exp { $$ = new conditionalExp($2, $1, $3, $5); } | exp ASSIGN exp { $$ = new assignExp($2, $1, $3); } | '(' tuple ')' { $$ = new callExp($1, new nameExp($1, SYM_TUPLE), $2); } | exp join exp %prec JOIN_PREC { $2->pushFront($1); $2->pushBack($3); $$ = $2; } | exp dir %prec DIRTAG { $2->setSide(camp::OUT); joinExp *jexp = new joinExp($2->getPos(), SYM_DOTS); $$=jexp; jexp->pushBack($1); jexp->pushBack($2); } | INCR exp %prec UNARY { $$ = new prefixExp($1.pos, $2, SYM_PLUS); } | DASHES exp %prec UNARY { $$ = new prefixExp($1.pos, $2, SYM_MINUS); } /* Illegal - will be caught during translation. */ | exp INCR %prec UNARY { $$ = new postfixExp($2.pos, $1, SYM_PLUS); } | exp SELFOP exp { $$ = new selfExp($2.pos, $1, $2.sym, $3); } | QUOTE '{' fileblock '}' { $$ = new quoteExp($1, $3); } ; // This verbose definition is because leaving empty as an expansion for dir // made a whack of reduce/reduce errors. join: DASHES { $$ = new joinExp($1.pos,$1.sym); } | basicjoin %prec JOIN_PREC { $$ = $1; } | dir basicjoin %prec JOIN_PREC { $1->setSide(camp::OUT); $$ = $2; $$->pushFront($1); } | basicjoin dir %prec JOIN_PREC { $2->setSide(camp::IN); $$ = $1; $$->pushBack($2); } | dir basicjoin dir %prec JOIN_PREC { $1->setSide(camp::OUT); $3->setSide(camp::IN); $$ = $2; $$->pushFront($1); $$->pushBack($3); } ; dir: '{' CURL exp '}' { $$ = new specExp($2.pos, $2.sym, $3); } | '{' exp '}' { $$ = new specExp($1, symbol::opTrans("spec"), $2); } | '{' exp ',' exp '}' { $$ = new specExp($1, symbol::opTrans("spec"), new pairExp($3, $2, $4)); } | '{' exp ',' exp ',' exp '}' { $$ = new specExp($1, symbol::opTrans("spec"), new tripleExp($3, $2, $4, $6)); } ; basicjoin: DOTS { $$ = new joinExp($1.pos, $1.sym); } | DOTS tension DOTS { $$ = new joinExp($1.pos, $1.sym); $$->pushBack($2); } | DOTS controls DOTS { $$ = new joinExp($1.pos, $1.sym); $$->pushBack($2); } | COLONS { $$ = new joinExp($1.pos, $1.sym); } | LONGDASH { $$ = new joinExp($1.pos, $1.sym); } ; tension: TENSION exp { $$ = new binaryExp($1.pos, $2, $1.sym, new booleanExp($1.pos, false)); } | TENSION exp AND exp { $$ = new ternaryExp($1.pos, $2, $1.sym, $4, new booleanExp($1.pos, false)); } | TENSION ATLEAST exp { $$ = new binaryExp($1.pos, $3, $1.sym, new booleanExp($2.pos, true)); } | TENSION ATLEAST exp AND exp { $$ = new ternaryExp($1.pos, $3, $1.sym, $5, new booleanExp($2.pos, true)); } ; controls: CONTROLS exp { $$ = new unaryExp($1.pos, $2, $1.sym); } | CONTROLS exp AND exp { $$ = new binaryExp($1.pos, $2, $1.sym, $4); } ; stm: ';' { $$ = new emptyStm($1); } | blockstm { $$ = $1; } | stmexp ';' { $$ = $1; } | IF '(' exp ')' stm { $$ = new ifStm($1, $3, $5); } | IF '(' exp ')' stm ELSE stm { $$ = new ifStm($1, $3, $5, $7); } | WHILE '(' exp ')' stm { $$ = new whileStm($1, $3, $5); } | DO stm WHILE '(' exp ')' ';' { $$ = new doStm($1, $2, $5); } | FOR '(' forinit ';' fortest ';' forupdate ')' stm { $$ = new forStm($1, $3, $5, $7, $9); } | FOR '(' type ID ':' exp ')' stm { $$ = new extendedForStm($1, $3, $4.sym, $6, $8); } | BREAK ';' { $$ = new breakStm($1); } | CONTINUE ';' { $$ = new continueStm($1); } | RETURN_ ';' { $$ = new returnStm($1); } | RETURN_ exp ';' { $$ = new returnStm($1, $2); } ; stmexp: exp { $$ = new expStm($1->getPos(), $1); } ; blockstm: block { $$ = new blockStm($1->getPos(), $1); } ; forinit: /* empty */ { $$ = 0; } | stmexplist { $$ = $1; } | barevardec { $$ = $1; } ; fortest: /* empty */ { $$ = 0; } | exp { $$ = $1; } ; forupdate: /* empty */ { $$ = 0; } | stmexplist { $$ = $1; } ; stmexplist: stmexp { $$ = new stmExpList($1->getPos()); $$->add($1); } | stmexplist ',' stmexp { $$ = $1; $$->add($3); } ; asymptote-2.37/camperror.cc000066400000000000000000000022471265434602500160070ustar00rootroot00000000000000/***** * camperror.cc * 2003/02/25 Andy Hammerlindl * * Provides a way for the classes in camp to report errors in * computation elegantly. After running a method on a camp object that * could encounter an error, the program should call camp::errors to see * if any errors were encountered. *****/ #include #include #include "camperror.h" #include "vm.h" #include "errormsg.h" namespace camp { // Used internally to report an error in an operation. void reportError(const string& desc) { em.runtime(vm::getPos()); em << desc; em.sync(); throw handled_error(); } // Used internally to report a warning in an operation. void reportWarning(const string& desc) { em.warning(vm::getPos()); em << desc; em.sync(); } void reportFatal(const string& desc) { em.fatal(vm::getPos()); em << desc; em.sync(); em.statusError(); try { throw quit(); } catch(handled_error) { } } void reportError(const ostringstream& desc) { reportError(desc.str()); } void reportWarning(const ostringstream& desc) { reportWarning(desc.str()); } void reportFatal(const ostringstream& desc) { reportFatal(desc.str()); } } // namespace camp asymptote-2.37/camperror.h000066400000000000000000000014621265434602500156470ustar00rootroot00000000000000/***** * camperror.h * 2003/02/25 Andy Hammerlindl * * Provides a way for the classes in camp to report errors in * computation elegantly. After running a method on a camp object that * could encounter an error, the program should call camp::errors to see * if any errors were encountered. *****/ #ifndef CAMPERROR_H #define CAMPERROR_H #include #include "common.h" namespace camp { // Used internally to report an error in an operation. void reportError(const string& desc); void reportError(const ostringstream& desc); void reportWarning(const string& desc); void reportWarning(const ostringstream& desc); void reportFatal(const string& desc); void reportFatal(const ostringstream& desc); inline std::ostream& newl(std::ostream& s) {s << '\n'; return s;} } // namespace camp #endif asymptote-2.37/castop.h000066400000000000000000000111251265434602500151430ustar00rootroot00000000000000/***** * castop.h * Tom Prince 2005/3/18 * * Defines some runtime functions used by the stack machine. * *****/ #ifndef CASTOP_H #define CASTOP_H #include #include "common.h" #include "stack.h" #include "fileio.h" #include "lexical.h" #include "mathop.h" #include "array.h" namespace run { using vm::read; using vm::pop; template void cast(vm::stack *s) { s->push((S) pop(s)); } void castDoubleInt(vm::stack *s) { double x=pop(s); s->push(Intcast(x)); } template void stringCast(vm::stack *s) { ostringstream buf; buf.precision(DBL_DIG); buf << pop(s); s->push(buf.str()); } template void castString(vm::stack *s) { string *S=pop(s); if(S->empty()) { T x=0; s->push(x); } else { try { s->push(lexical::cast(*S)); } catch (lexical::bad_cast&) { ostringstream buf; buf << "invalid cast from string \"" << *S << "\""; vm::error(buf); } } } template void arrayToArray(vm::stack *s) { vm::array *a=pop(s); size_t size=checkArray(a); vm::array *c=new vm::array(size); for(size_t i=0; i < size; i++) (*c)[i]=(S) read(a,i); s->push(c); } template void array2ToArray2(vm::stack *s) { vm::array *a=pop(s); size_t size=checkArray(a); vm::array *c=new vm::array(size); for(size_t i=0; i < size; ++i) { vm::array *ai=vm::read(a,i); size_t aisize=checkArray(ai); vm::array *ci=new vm::array(aisize); (*c)[i]=ci; for(size_t j=0; j < aisize; ++j) (*ci)[j]=(S) read(ai,j); } s->push(c); } template void read(vm::stack *s) { camp::file *f = pop(s); T val=T(); if(f->isOpen()) { f->read(val); if(f->LineMode()) f->nexteol(); if(interact::interactive) f->purgeStandard(val); } s->push(val); } inline Int Limit(Int nx) {return nx == 0 ? Int_MAX : nx;} inline void reportEof(camp::file *f, Int count) { if(count > 0) { ostringstream buf; buf << "EOF after reading " << count << " values from file '" << f->filename() << "'."; vm::error(buf); } } template void readArray(vm::stack *s, Int nx=-1, Int ny=-1, Int nz=-1) { camp::file *f = pop(s); vm::array *c=new vm::array(0); if(f->isOpen()) { if(nx != -1 && f->Nx() != -1) nx=f->Nx(); if(nx == -2) {f->read(nx); f->Nx(-1); if(nx == 0) {s->push(c); return;}} if(ny != -1 && f->Ny() != -1) ny=f->Ny(); if(ny == -2) {f->read(ny); f->Ny(-1); if(ny == 0) {s->push(c); return;}} if(nz != -1 && f->Nz() != -1) nz=f->Nz(); if(nz == -2) {f->read(nz); f->Nz(-1); if(nz == 0) {s->push(c); return;}} T v; if(nx >= 0) { for(Int i=0; i < Limit(nx); i++) { if(ny >= 0) { vm::array *ci=new vm::array(0); for(Int j=0; j < Limit(ny); j++) { if(nz >= 0) { vm::array *cij=new vm::array(0); bool break2=false; for(Int k=0; k < Limit(nz); k++) { f->read(v); if(f->error()) { if(nx && ny && nz) reportEof(f,(i*ny+j)*nz+k); s->push(c); return; } if(k == 0) { if(j == 0) c->push(ci); ci->push(cij); } cij->push(v); if(f->LineMode() && f->nexteol()) { if(f->nexteol()) break2=true; break; } } if(break2) break; } else { f->read(v); if(f->error()) { if(nx && ny) reportEof(f,i*ny+j); s->push(c); return; } if(j == 0) c->push(ci); ci->push(v); if(f->LineMode() && f->nexteol()) break; } } } else { f->read(v); if(f->error()) { if(nx) reportEof(f,i); s->push(c); return; } c->push(v); if(f->LineMode() && f->nexteol()) break; } } } else { for(;;) { f->read(v); if(f->error()) break; c->push(v); if(f->LineMode() && f->nexteol()) break; } } if(interact::interactive) f->purgeStandard(v); } s->push(c); } template void readArray1(vm::stack *s) { readArray(s,0); } template void readArray2(vm::stack *s) { readArray(s,0,0); } template void readArray3(vm::stack *s) { readArray(s,0,0,0); } } // namespace run #endif // CASTOP_H asymptote-2.37/coder.cc000066400000000000000000000172001265434602500151040ustar00rootroot00000000000000/***** * coder.cc * Andy Hammerlindl 2004/11/06 * * Handles encoding of syntax into programs. It's methods are called by * abstract syntax objects during translation to construct the virtual machine * code. *****/ #include #include "errormsg.h" #include "coder.h" #include "genv.h" #include "entry.h" #include "builtin.h" using namespace sym; using namespace types; namespace trans { namespace { function *inittype(); function *bootuptype(); } vm::lambda *newLambda(string name) { assert(!name.empty()); vm::lambda *l = new vm::lambda; #ifdef DEBUG_FRAME l->name = name; #endif return l; } // Used purely for global variables and static code blocks of file // level modules. coder::coder(position pos, string name, modifier sord) #if SIMPLE_FRAME : level(frame::indirect_frame(name)), #else : level(new frame(name, 0, 0)), #endif recordLevel(0), recordType(0), isCodelet(false), l(newLambda(name)), funtype(bootuptype()), parent(0), sord(sord), perm(DEFAULT_PERM), program(new vm::program), curPos(pos) { sord_stack.push(sord); } // Defines a new function environment. coder::coder(position pos, string name, function *t, coder *parent, modifier sord, bool reframe) : level(reframe ? new frame(name, parent->getFrame(), t->sig.getNumFormals()) : parent->getFrame()), recordLevel(parent->recordLevel), recordType(parent->recordType), isCodelet(!reframe), l(newLambda(name)), funtype(t), parent(parent), sord(sord), perm(DEFAULT_PERM), program(new vm::program), curPos(pos) { sord_stack.push(sord); } // Start encoding the body of the record. The function being encoded // is the record's initializer. coder::coder(position pos, record *t, coder *parent, modifier sord) : level(t->getLevel()), recordLevel(t->getLevel()), recordType(t), isCodelet(false), l(t->getInit()), funtype(inittype()), parent(parent), sord(sord), perm(DEFAULT_PERM), program(new vm::program), curPos(pos) { sord_stack.push(sord); } coder coder::newFunction(position pos, string name, function *t, modifier sord) { return coder(pos, name, t, this, sord); } coder coder::newCodelet(position pos) { return coder(pos, "", new function(primVoid()), this, DEFAULT_DYNAMIC, false); } record *coder::newRecord(symbol id) { frame *underlevel = getFrame(); frame *level = new frame(id, underlevel, 0); record *r = new record(id, level); return r; } coder coder::newRecordInit(position pos, record *r, modifier sord) { return coder(pos, r, this, sord); } #ifdef DEBUG_BLTIN void assertBltinLookup(inst::opcode op, item it) { if (op == inst::builtin) { string name=lookupBltin(vm::get(it)); assert(!name.empty()); } } #endif void coder::encodePop() { if (isStatic() && !isTopLevel()) { assert(parent); parent->encodePop(); } else { #ifdef COMBO vm::program::label end = program->end(); --end; inst& lastInst = *end; if (lastInst.op == inst::varsave) { lastInst.op = inst::varpop; return; } if (lastInst.op == inst::fieldsave) { lastInst.op = inst::fieldpop; return; } // TODO: push+pop into no op. #endif // No combo applicable. Just encode a usual pop. encode(inst::pop); } } bool coder::encode(frame *f) { frame *toplevel = getFrame(); if (f == 0) { encode(inst::constpush,(item)0); return true; } else if (f == toplevel) { encode(inst::pushclosure); return true; } else { encode(inst::varpush,toplevel->parentIndex()); return encode(f, toplevel->getParent()); } } bool coder::encode(frame *dest, frame *top) { if (dest == 0) { // Change to encodePop? encode(inst::pop); encode(inst::constpush,(item)0); } else { frame *level = top; while (level != dest) { if (level == 0) { // Frame request was in an improper scope. return false; } encode(inst::fieldpush, level->parentIndex()); level = level->getParent(); } } //cerr << "succeeded\n"; return true; } vm::program::label coder::encodeEmptyJump(inst::opcode op) { // Get the end position before encoding the label. Once encoded, this will // point to the instruction. vm::program::label pos = program->end(); encode(op); return pos; } void replaceEmptyJump(vm::program::label from, vm::program::label to) { from->ref = to; } label coder::defNewLabel() { if (isStatic()) return parent->defNewLabel(); label l = new label_t(); assert(!l->location.defined()); assert(!l->firstUse.defined()); return defLabel(l); } label coder::defLabel(label label) { if (isStatic()) return parent->defLabel(label); //cout << "defining label " << label << endl; assert(!label->location.defined()); //vm::program::label here = program->end(); label->location = program->end(); assert(label->location.defined()); if (label->firstUse.defined()) { replaceEmptyJump(label->firstUse, program->end()); //vm::printInst(cout, label->firstUse, program->begin()); //cout << endl; if (label->moreUses) { typedef label_t::useVector useVector; useVector& v = *label->moreUses; for (useVector::iterator p = v.begin(); p != v.end(); ++p) { replaceEmptyJump(*p, program->end()); } } } return label; } void coder::useLabel(inst::opcode op, label label) { if (isStatic()) return parent->useLabel(op,label); if (label->location.defined()) { encode(op, label->location); } else { if (label->firstUse.defined()) { // Store additional uses in the moreUses array. if (!label->moreUses) label->moreUses = new label_t::useVector; label->moreUses->push_back(encodeEmptyJump(op)); } else { label->firstUse = encodeEmptyJump(op); assert(label->firstUse.defined()); assert(!label->location.defined()); } } } label coder::fwdLabel() { if (isStatic()) return parent->fwdLabel(); // Create a new label without specifying its position. label l = new label_t(); assert(!l->location.defined()); assert(!l->firstUse.defined()); //cout << "forward label " << l << endl; return l; } bool coder::usesClosureSinceLabel(label l) { assert(l->location.defined()); for (vm::program::label i = l->location; i != program->end(); ++i) if (i->op == inst::pushclosure) return true; return false; } void coder::encodePatch(label from, label to) { assert(from->location.defined()); assert(to->location.defined()); assert(from->location->op == inst::nop); from->location->op = inst::jmp; from->location->ref = to->location; } void coder::markPos(position pos) { curPos = pos; } // When translating the function is finished, this ties up loose ends // and returns the lambda. vm::lambda *coder::close() { // These steps must be done dynamically, not statically. sord = EXPLICIT_DYNAMIC; sord_stack.push(sord); // Add a return for void types; may be redundant. if (funtype->result->kind == types::ty_void) encode(inst::ret); l->code = program; l->parentIndex = level->parentIndex(); l->framesize = level->size(); sord_stack.pop(); sord = sord_stack.top(); return l; } void coder::closeRecord() { // Put record into finished state. encode(inst::pushclosure); close(); } bool coder::isRecord() { return (funtype==inittype()); } namespace { function *inittype() { static function t(types::primVoid()); return &t; } function *bootuptype() { static function t(types::primVoid()); return &t; } } // private } // namespace trans asymptote-2.37/coder.h000066400000000000000000000266121265434602500147550ustar00rootroot00000000000000/***** * coder.h * Andy Hammerlindl 2004/11/06 * * Handles encoding of syntax into programs. It's methods are called by * abstract syntax objects during translation to construct the virtual machine * code. *****/ #ifndef CODER_H #define CODER_H #include "errormsg.h" #include "entry.h" #include "types.h" #include "record.h" #include "frame.h" #include "program.h" #include "util.h" #include "modifier.h" #include "inst.h" namespace trans { using sym::symbol; using types::ty; using types::function; using types::record; using vm::bltin; using vm::inst; using vm::item; #ifdef DEBUG_BLTIN void assertBltinLookup(inst::opcode op, item it); #endif // Labels used by the coder class to denote where in the code a jump // instruction should go to. Label can be used before their exact location is // known. // Declared outside of the coder class, so that it can be declared in exp.h. struct label_t : public gc { vm::program::label location; vm::program::label firstUse; // Most labels are used only once, and so we optimize for that case. We do, // however, have to handle labels which are used multiple times (such as // break locations in a loop), and so a useVector is allocated to store // these if necessary. typedef mem::vector useVector; useVector *moreUses; // Only the constructor is defined. Everything else is handles by methods // of the coder class. label_t() : location(), firstUse(), moreUses(0) {} }; typedef label_t *label; class coder { // The frame of the function we are currently encoding. This keeps // track of local variables, and parameters with respect to the stack. frame *level; // The frame of the enclosing record that the "this" expression yields. ie. // the highest frame that is a record, not a function. frame *recordLevel; // The type of the enclosing record. Also needed for the "this" expression. record *recordType; // Are we translating a codelet? bool isCodelet; // The lambda being constructed. In some cases, this lambda is needed // before full translation of the function, so it is stored, // incomplete, here. vm::lambda *l; // The type of the function being translated. const function *funtype; // The enclosing environment. Null if this is a file-level module. coder *parent; // The mode of encoding, either static or dynamic. sord is used as an // acronym for Static OR Dynamic. // Once something is static, no amount of dynamic modifiers can change // that, so once a stack is EXPLICIT_STATIC, additional modifiers will // be pushed on as EXPLICIT_STATIC. modifier sord; std::stack sord_stack; // What permissions will be given to a new access. // TODO: Ensure private fields don't show up calling lookup for a // record. permission perm; // The function code as its being written. Code points to next place in // array to write. vm::program *program; // Some loops allocate nested frames, in case variables in an // iteration escape in a closure. This stack keeps track of where the // pushframe instructions are, so the size of the frame can be encoded. std::stack pushframeLabels; // Loops need to store labels to where break and continue statements // should pass control. Since loops can be nested, this needs to // be stored as a stack. We also store which of the loops are being encoded // with an additional frame for variables. This is needed to know if the // break and continue statements need to pop the frame. struct loopdata_t : gc { label continueLabel; label breakLabel; bool pushedFrame; loopdata_t(label c, label b) : continueLabel(c), breakLabel(b), pushedFrame(false) {} }; mem::stack loopdata; // Current File Position position curPos; public: // Define a new function coder. If reframe is true, this gives the function // its own frame, which is the usual (sensible) thing to do. It is set to // false for a line-at-a-time codelet, where variables should be allocated in // the lower frame. coder(position pos, string name, function *t, coder *parent, modifier sord = DEFAULT_DYNAMIC, bool reframe=true); // Start encoding the body of the record. The function being encoded // is the record's initializer. coder(position pos, record *t, coder *parent, modifier sord = DEFAULT_DYNAMIC); coder(position pos, string name, modifier sord = DEFAULT_DYNAMIC); coder(const coder&); /* Add a static or dynamic modifier. */ void pushModifier(modifier s) { /* Default setting should only be used in the constructor. */ assert(s != DEFAULT_STATIC && s != DEFAULT_DYNAMIC); /* Non-default static overrules. */ if (sord != EXPLICIT_STATIC) sord = s; sord_stack.push(sord); } /* Tests if encoding mode is currently static. */ bool isStatic() { switch(sord) { case DEFAULT_STATIC: case EXPLICIT_STATIC: return true; case DEFAULT_DYNAMIC: case EXPLICIT_DYNAMIC: return false; default: assert(False); return false; } } /* Remove a modifier. */ void popModifier() { assert(!sord_stack.empty()); sord_stack.pop(); assert(!sord_stack.empty()); sord = sord_stack.top(); } /* Set/get/clear permissions. */ void setPermission(permission p) { perm = p; } permission getPermission() { return perm; } void clearPermission() { perm = DEFAULT_PERM; } // Says what the return type of the function is. ty *getReturnType() { return funtype->result; } bool isRecord(); // Creates a new coder to handle the translation of a new function. coder newFunction(position pos, string name, function *t, modifier sord=DEFAULT_DYNAMIC); // Creates a new record type. record *newRecord(symbol id); // Create a coder for the initializer of the record. coder newRecordInit(position pos, record *r, modifier sord=DEFAULT_DYNAMIC); // Create a coder for translating a small piece of code. Used for // line-at-a-time mode. coder newCodelet(position pos); frame *getFrame() { if (isStatic() && !isTopLevel()) { assert(parent->getFrame()); return parent->getFrame(); } else return level; } // Tests if the function or record with the given frame is currently under // translation (either by this coder or an ancestor). bool inTranslation(frame *f) { frame *level=this->level; while (level) { if (f==level) return true; level=level->getParent(); } return parent && parent->inTranslation(f); } // Allocates space in the function or record frame for a new local variable. access *allocLocal() { return getFrame()->allocLocal(); } // Get the access in the frame for a specified formal parameter. access *accessFormal(Int index) { // NOTE: This hasn't been extended to handle frames for loops, but is // currently only called when starting to translate a function, where there // can be no loops. return level->accessFormal(index); } // Checks if we are at the top level, which is true for a file-level module or // a codelet. bool isTopLevel() { return parent==0 || isCodelet; } // The encode functions add instructions and operands on to the code array. private: void encode(inst i) { i.pos = curPos; // Static code is put into the enclosing coder, unless we are translating a // codelet. if (isStatic() && !isTopLevel()) { assert(parent); parent->encode(i); } else { program->encode(i); } } // Encode a jump to a not yet known location. vm::program::label encodeEmptyJump(inst::opcode op); public: void encode(inst::opcode op) { inst i; i.op = op; i.pos = nullPos; encode(i); } void encode(inst::opcode op, item it) { #ifdef DEBUG_BLTIN assertBltinLookup(op, it); #endif inst i; i.op = op; i.pos = nullPos; i.ref = it; encode(i); } // Encodes a pop instruction, or merges the pop into the previous // instruction (ex. varsave+pop becomes varpop). void encodePop(); // Puts the requested frame on the stack. If the frame is not that of // this coder or its ancestors, false is returned. bool encode(frame *f); // Puts the frame corresponding to the expression "this" on the stack. bool encodeThis() { assert(recordLevel); return encode(recordLevel); } // An access that encodes the frame corresponding to "this". access *thisLocation() { assert(recordLevel); return new frameAccess(recordLevel); } // Returns the type of the enclosing record. record *thisType() { return recordType; } // Puts the 'dest' frame on the stack, assuming the frame 'top' is on // top of the stack. If 'dest' is not an ancestor frame of 'top', // false is returned. bool encode(frame *dest, frame *top); // Assigns a handle to the current point in the list of bytecode // instructions and returns that handle. label defNewLabel(); // Sets the handle given by label to the current point in the list of // instructions. label defLabel(label label); // Encodes the address pointed to by the handle label into the // sequence of instructions. This is useful for a jump instruction to // jump to where a label was defined. void useLabel(inst::opcode op, label label); // If an address has to be used for a jump instruction before it is // actually encoded, a handle can be given to it by this function. // When that handle's label is later defined, the proper address will // be inserted into the code where the handle was used. label fwdLabel(); void pushLoop(label c, label b) { loopdata.push(loopdata_t(c,b)); } void popLoop() { loopdata.pop(); } void loopPushesFrame() { assert(!loopdata.empty()); loopdata_t& d = loopdata.top(); d.pushedFrame = true; } bool encodeBreak() { if (loopdata.empty()) return false; else { loopdata_t& d = loopdata.top(); if (d.pushedFrame) encode(inst::popframe); useLabel(inst::jmp,d.breakLabel); return true; } } bool encodeContinue() { if (loopdata.empty()) return false; else { loopdata_t& d = loopdata.top(); if (d.pushedFrame) encode(inst::popframe); useLabel(inst::jmp,d.continueLabel); return true; } } // Returns true if a pushclosure has been encoded since the definition of // the label. bool usesClosureSinceLabel(label l); // Turn a no-op into a jump to bypass incorrect code. void encodePatch(label from, label to); public: void encodePushFrame() { pushframeLabels.push(program->end()); encode(inst::pushframe, (Int)0); level = new frame("encodePushFrame", level, 0); } void encodePopFrame() { pushframeLabels.top()->ref = level->size(); pushframeLabels.pop(); encode(inst::popframe); level = level->getParent(); } // Adds an entry into the position list, linking the given point in the // source code to the current position in the virtual machine code. This is // used to print positions at runtime. void markPos(position pos); // When translation of the function is finished, this ties up loose ends // and returns the lambda. vm::lambda *close(); // Finishes translating the initializer of a record. void closeRecord(); private: // Non-copyable void operator=(const coder&); }; } // namespace trans #endif asymptote-2.37/coenv.cc000066400000000000000000000021461265434602500151250ustar00rootroot00000000000000/***** * coenv.cc * Andy Hammerlindl 2004/11/18 * * Bundles the env and coder classes needed in translating the abstract syntax * tree. It also also implements some functions that involve both the env and * coder, such as implicitCast(). *****/ #include "coenv.h" namespace trans { // Prints out error messages for the cast methods. static inline void castError(position pos, ty *target, ty *source) { em.error(pos); em << "cannot convert \'" << *source << "\' to \'" << *target << "\'"; } static inline bool accessCast(position pos, ty *target, ty *source, access *a, coder& c) { if (a) { a->encode(CALL, pos, c); return true; } else { castError(pos, target, source); return false; } } bool coenv::implicitCast(position pos, ty *target, ty *source) { return accessCast(pos, target, source, e.lookupCast(target, source, symbol::castsym), c); } bool coenv::explicitCast(position pos, ty *target, ty *source) { return accessCast(pos, target, source, e.lookupCast(target, source, symbol::ecastsym), c); } } asymptote-2.37/coenv.h000066400000000000000000000016141265434602500147660ustar00rootroot00000000000000/***** * coenv.h * Andy Hammerlindl 2004/11/18 * * Bundles the env and coder classes needed in translating the abstract syntax * tree. It also also implements some functions that involve both the env and * coder, such as implicitCast(). *****/ #ifndef COENV_H #define COENV_H #include "env.h" #include "coder.h" namespace trans { class coenv { public: coder &c; env &e; coenv(coder &c, env &e) : c(c), e(e) {} // This is used when an expression of type source needs to be an // expression of type target. // If it is allowed, the casting instructions (if any) will be added. // Otherwise, an appropriate error message will be printed. bool implicitCast(position pos, ty *target, ty *source); bool explicitCast(position pos, ty *target, ty *source); void add(protoenv &source, varEntry *qualifier) { e.add(source, qualifier, c); } }; } // namespace trans #endif asymptote-2.37/common.h000066400000000000000000000031731265434602500151460ustar00rootroot00000000000000/**** * common.h * * Definitions common to all files. *****/ #ifndef COMMON_H #define COMMON_H #undef NDEBUG #include #include #ifdef __CYGWIN__ #undef LONG_LONG_MAX #define LONG_LONG_MAX __LONG_LONG_MAX__ #undef LONG_LONG_MIN #define LONG_LONG_MIN (-LONG_LONG_MAX-1) #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif #if !defined(FOR_SHARED) && defined(HAVE_LIBGLU) && \ ((defined(HAVE_LIBGL) && defined(HAVE_LIBGLUT)) || defined(HAVE_LIBOSMESA)) #define HAVE_GL #endif #ifdef HAVE_PTHREAD #include #endif #include "memory.h" #if defined(HAVE_LONG_LONG) && defined(LONG_LONG_MAX) && defined(LONG_LONG_MIN) #define Int_MAX2 LONG_LONG_MAX #define Int_MIN LONG_LONG_MIN typedef long long Int; typedef unsigned long long unsignedInt; #else #undef HAVE_LONG_LONG #ifdef HAVE_LONG #define Int_MAX2 LONG_MAX #define Int_MIN LONG_MIN typedef long Int; typedef unsigned long unsignedInt; #else #define Int_MAX2 INT_MAX #define Int_MIN INT_MIN typedef int Int; typedef unsigned int unsignedInt; #endif #endif #ifndef COMPACT #if Int_MAX2 >= 0x7fffffffffffffffLL #define COMPACT 1 #else #define COMPACT 0 #endif #endif #if COMPACT // Reserve highest two values for DefaultValue and Undefined states. #define Int_MAX (Int_MAX2-2) #define int_MAX (LONG_MAX-2) #else #define Int_MAX Int_MAX2 #define int_MAX LONG_MAX #endif #define int_MIN LONG_MIN #define RANDOM_MAX 0x7FFFFFFF using std::cout; using std::cin; using std::cerr; using std::endl; using std::istream; using std::ostream; using mem::string; using mem::stringstream; using mem::istringstream; using mem::ostringstream; using mem::stringbuf; #endif asymptote-2.37/config.guess000066400000000000000000001275341265434602500160320ustar00rootroot00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 # Free Software Foundation, Inc. timestamp='2008-01-23' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner . # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # The plan is that this can be called by configure scripts if you # don't specify an explicit build system type. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep __ELF__ >/dev/null then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm:riscos:*:*|arm:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[456]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep __LP64__ >/dev/null then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) case ${UNAME_MACHINE} in pc98) echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:[3456]*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; EM64T | authenticamd) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-gnu else echo ${UNAME_MACHINE}-unknown-linux-gnueabi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) echo cris-axis-linux-gnu exit ;; crisv32:Linux:*:*) echo crisv32-axis-linux-gnu exit ;; frv:Linux:*:*) echo frv-unknown-linux-gnu exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; mips:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips #undef mipsel #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mipsel #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips #else CPU= #endif #endif EOF eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' /^CPU/{ s: ::g p }'`" test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips64 #undef mips64el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mips64el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips64 #else CPU= #endif #endif EOF eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' /^CPU/{ s: ::g p }'`" test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; or32:Linux:*:*) echo or32-unknown-linux-gnu exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-gnu exit ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:Linux:*:*) # The BFD linker knows what the default object file format is, so # first see if it will tell us. cd to the root directory to prevent # problems with other programs or directories called `ld' in the path. # Set LC_ALL=C to ensure ld outputs messages in English. ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ | sed -ne '/supported targets:/!d s/[ ][ ]*/ /g s/.*supported targets: *// s/ .*// p'` case "$ld_supported_targets" in elf32-i386) TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" ;; a.out-i386-linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" exit ;; coff-i386) echo "${UNAME_MACHINE}-pc-linux-gnucoff" exit ;; "") # Either a pre-BFD a.out linker (linux-gnuoldld) or # one that does not give us useful --help. echo "${UNAME_MACHINE}-pc-linux-gnuoldld" exit ;; esac # Determine whether the default compiler is a.out or elf eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include #ifdef __ELF__ # ifdef __GLIBC__ # if __GLIBC__ >= 2 LIBC=gnu # else LIBC=gnulibc1 # endif # else LIBC=gnulibc1 # endif #else #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) LIBC=gnu #else LIBC=gnuaout #endif #endif #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' /^LIBC/{ s: ::g p }'`" test x"${LIBC}" != x && { echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit } test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i386. echo i386-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: asymptote-2.37/config.sub000066400000000000000000001052741265434602500154720ustar00rootroot00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 2011, 2012 Free Software Foundation, Inc. timestamp='2012-04-18' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted GNU ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; android-linux) os=-linux-android basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*178) os=-lynxos178 ;; -lynx*5) os=-lynxos5 ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ | be32 | be64 \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | epiphany \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 \ | ns16k | ns32k \ | open8 \ | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown ;; c55x) basic_machine=tic55x-unknown ;; c6x) basic_machine=tic6x-unknown ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown os=-none ;; xscaleeb) basic_machine=armeb-unknown ;; xscaleel) basic_machine=armel-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c54x-*) basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c55x-*) basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c6x-*) basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze) basic_machine=microblaze-xilinx ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; msys) basic_machine=i386-pc os=-msys ;; mvs) basic_machine=i370-ibm os=-mvs ;; nacl) basic_machine=le32-unknown os=-nacl ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; neo-tandem) basic_machine=neo-tandem ;; nse-tandem) basic_machine=nse-tandem ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; strongarm-* | thumb-*) basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tile*) basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -auroraux) os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -nacl*) ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; tic54x-*) os=-coff ;; tic55x-*) os=-coff ;; tic6x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: asymptote-2.37/configure.ac000066400000000000000000000301741265434602500157740ustar00rootroot00000000000000# -*- Autoconf -*- # Run autoheader and autoconf to produce a header and configure script from # this file. AC_PREREQ(2) AC_INIT([Asymptote],[2.37],[http://sourceforge.net/projects/asymptote]) VERSION=$PACKAGE_VERSION AC_SUBST(VERSION) m4_include([ax_pthread.m4]) test "$CFLAGS" || CFLAGS="-g -O3 -ansi" AC_C_BIGENDIAN test "$prefix" = NONE && prefix=/usr/local Datadir=$datadir test "$Datadir" = '${datarootdir}' && Datadir=$datarootdir test "$Datadir" = '${prefix}/share' && Datadir=$prefix/share AC_SUBST(Datadir) AC_ARG_WITH(latex, [AS_HELP_STRING(--with-latex=PATH, specify path to LaTeX installation)], [if test "x$withval" != "x" ; then latexdir=$withval fi ],[ AC_CHECK_PROG(kpsewhich,kpsewhich,true) if test "x$kpsewhich" = "xtrue"; then latexdir=`kpsewhich -expand-var='$TEXMFLOCAL'/tex/latex` else latexdir=$prefix/share/texmf/tex/latex AC_CHECK_FILE($latexdir/base/latex.ltx,, [latexdir=/usr/share/texmf/tex/latex AC_CHECK_FILE($latexdir/base/latex.ltx,,)]) fi ]) AC_ARG_WITH(context, [AS_HELP_STRING(--with-context=PATH, specify path to ConTeXt installation)], [if test "x$withval" != "x" ; then contextdir=$withval fi ],[ AC_CHECK_PROG(kpsewhich,kpsewhich,true) if test "x$kpsewhich" = "xtrue"; then contextdir=`kpsewhich -expand-var='$TEXMFLOCAL'/tex/context/third` else contextdir=$prefix/share/texmf/tex/context/third fi ]) AC_CHECK_PROGS(TEXI2DVI,[texi2dvi], [echo texi2dvi is missing! Please put http://asymptote.sourceforge.net/asymptote.pdf in the doc directory, touch doc/asymptote.pdf, and run configure again; exit 1;]) AC_SUBST(TEXI2DVI) latexdir=$latexdir/asymptote contextdir=$contextdir/asymptote AC_MSG_NOTICE([Using $latexdir for LaTeX style file]) AC_MSG_NOTICE([Using $contextdir for ConTeXT style file]) AC_SUBST(latexdir) AC_SUBST(contextdir) docdir=$Datadir/doc/asymptote AC_ARG_WITH(docdir, [AS_HELP_STRING(--with-docdir=PATH, alternate documentation installation directory)], [if test "x$withval" != "x" ; then docdir=$withval fi ]) AC_SUBST(docdir) sysdir=$Datadir/asymptote AC_ARG_ENABLE(texlive-build, [AS_HELP_STRING(--enable-texlive-build, automatically determine sysdir from kpsewhich)], [ if test "x$enableval" = "xyes" ; then sysdir="" fi ]) AC_DEFINE_UNQUOTED(ASYMPTOTE_SYSDIR,"$sysdir", [System directory for global .asy files]) AC_DEFINE_UNQUOTED(ASYMPTOTE_DOCDIR,"$docdir", [Directory for documentation]) AC_CONFIG_SRCDIR([absyn.cc]) AC_LANG([C++]) # Checks for programs. AC_PROG_LEX AC_PROG_CXX AC_PROG_INSTALL AC_PROG_CC AC_PROG_MAKE_SET AC_PROG_YACC if test "$GXX" = yes ; then ac_gcc_version=`echo __GNUC__ | $CC -E - | grep -v ^\#` ac_clang=`echo __clang__ | $CC -E - | grep -v ^\#` if test "$ac_gcc_version" -lt 4; then CFLAGS=$CFLAGS" -finline-limit=400" else if test "$ac_clang" != 1; then CFLAGS=$CFLAGS" -fno-var-tracking" fi fi fi AC_CHECK_HEADER(unordered_map,AC_DEFINE(HAVE_UNORDERED_MAP,1, [Define to 1 if you have unordered_map]), [AC_CHECK_HEADER(tr1/unordered_map,AC_DEFINE(HAVE_TR1_UNORDERED_MAP,1, [Define to 1 if you have tr1/unordered_map]), [AC_CHECK_HEADER(ext/hash_map,,OPTIONS=$OPTIONS"-DNOHASH ")])]) GCVERSION=7.4.2 GCFILE=gc-$GCVERSION ac_cv_use_gc="system" AC_CHECK_FILE($GCFILE.tar.gz, ac_cv_use_gc=$GCVERSION) AC_ARG_ENABLE(gc, [AS_HELP_STRING(--enable-gc[[[=system]]], enable system Boehm garbage collector)] [ [[=VERSION]] enable local VERSION of Boehm garbage collector] [ [[=PREFIX]] use Boehm garbage collector installed in PREFIX], [ if test "x$enableval" != "xyes" ; then ac_cv_use_gc=$enableval fi ]) OPTIONS="-D_FILE_OFFSET_BITS=64 " GCLIB= GCPPLIB= GCNAME="Boehm Garbage Collector" GCOPTIONS="--disable-shared --enable-large-config" if test "x$ac_cv_use_gc" != "xno" ; then OPTIONS=$OPTIONS"-DUSEGC " case _$ac_cv_use_gc in _|_system|_*[[\\/]]*) if test "x$ac_cv_use_gc" = "xsystem" ; then INCL="-I$prefix/include/gc -I/usr/include/gc" LIBS=$LIBS"-L$prefix/lib " else INCL="-I$ac_cv_use_gc/include/gc" LIBS=$LIBS"-L$ac_cv_use_gc/lib " fi CPPFLAGS_SAVE=$CPPFLAGS CPPFLAGS=$CPPFLAGS" $INCL" AC_CHECK_HEADER(gc.h, AC_CHECK_LIB([gc],[GC_malloc],[ LIBS=$LIBS"-lgc " AC_MSG_NOTICE([enabling system $GCNAME])],[ GCDIR=$GCFILE INCL="-I\$(GC)/include" GCLIB="\$(GC)/.libs/libgc.a" AC_MSG_NOTICE($GCNAME library not found)]), GCDIR=$GCFILE GCLIB="\$(GC)/.libs/libgc.a" INCL="-I\$(GC)/include" AC_MSG_NOTICE($GCNAME header file not found)) CPPFLAGS=$CPPFLAGS_SAVE ;; *) GCVERSION=$ac_cv_use_gc GCFILE=gc-$GCVERSION GCDIR=$GCFILE AC_MSG_NOTICE([enabling local $GCNAME $GCDIR]) GCLIB="\$(GC)/.libs/libgc.a" INCL="-I\$(GC)/include" ;; esac else AC_MSG_NOTICE([disabling the $GCNAME]) fi AC_ARG_ENABLE(gc-debug, [AS_HELP_STRING(--enable-gc-debug,enable (slow) garbage collector debugging)], [ if test "x$ac_cv_use_gc" != "xno" ; then if test "x$enableval" = "xyes" ; then OPTIONS=$OPTIONS"-DGC_DEBUG " AC_MSG_NOTICE([*** Enabling GC debugging: remember to make clean ***]) AC_MSG_NOTICE([*** Set the environment variable GC_FIND_LEAK at runtime ***]) fi fi ]) AC_ARG_ENABLE(gc-full-debug, [AS_HELP_STRING(--enable-gc-full-debug,enable (very slow) garbage collector backtrace)], [ if test "x$ac_cv_use_gc" != "xno" ; then if test "x$enableval" = "xyes" ; then OPTIONS=$OPTIONS"-DGC_DEBUG -DGC_BACKTRACE " GCOPTIONS=$GCOPTIONS"--enable-gc-debug " AC_MSG_NOTICE([*** Enabling GC backtrace debugging; remember to make gc-clean ***]) fi fi ]) if test "$OSTYPE" = "msdos"; then INCL=$INCL" -I/usr/include/tirpc" CPPFLAGS=$CPPFLAGS" -D__MSDOS__ $INCL" fi AC_CHECK_FUNC(getopt_long_only, AC_DEFINE(HAVE_GNU_GETOPT_H, 1, [Define if getopt.h is the GNU version]), getopt="getopt getopt1",) AC_SUBST(getopt) AC_SUBST(GCVERSION) AC_SUBST(GCOPTIONS) AC_SUBST(GCLIB) AC_SUBST(GCPPLIB) AC_SUBST(INCL) AC_SUBST(OPTIONS) # Checks for libraries. AC_CHECK_LIB([ncurses], [setupterm], [AC_DEFINE(HAVE_LIBCURSES) LIBS=$LIBS"-lncurses "], AC_CHECK_LIB([curses], [setupterm])) AC_CHECK_LIB([m], [sqrt],, AC_MSG_ERROR([*** Please install libm on your system ***])) AC_CHECK_LIB([z], [deflate],, AC_MSG_ERROR([*** Please install libz or zlib-devel on your system ***])) AX_PTHREAD AC_CHECK_LIB([sigsegv], [stackoverflow_install_handler]) AC_CHECK_LIB([rt], [sched_yield]) AC_ARG_ENABLE(readline, [AS_HELP_STRING(--enable-readline[[[=yes]]],enable GNU Readline Library)]) if test "x$enable_readline" != "xno"; then AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #include #include #include ],[ #ifndef RL_READLINE_VERSION abort #endif ])],AC_CHECK_LIB([readline], [history_list],, AC_MSG_NOTICE(*** Could not find GNU libreadline 4.3 or later: will compile without readline support ***)), AC_MSG_NOTICE(*** Could not find GNU readline 4.3 or later: will compile without readline support ***)) fi # Checks for header files. AC_HEADER_SYS_WAIT AC_CHECK_HEADERS([fenv.h stddef.h libintl.h]) AC_CHECK_HEADERS([ncurses/curses.h ncurses.h curses.h], [break]) AC_CHECK_HEADERS(fpu_control.h) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include "xstream.h"])], [AC_SEARCH_LIBS([xdrstdio_create],[nsl rpc]) AC_DEFINE(HAVE_RPC_RPC_H, 1, [Define if you have a working header file])], AC_MSG_WARN([*** Broken rpc headers; XDR support disabled ***])) AC_ARG_ENABLE(gsl, [AS_HELP_STRING(--enable-gsl[[[=yes]]],enable GNU Scientific Library)]) if test "x$enable_gsl" != "xno"; then AC_CHECK_HEADER(gsl/gsl_sf.h, AC_CHECK_LIB([gsl], gsl_sf_debye_6, [AC_DEFINE(HAVE_LIBGSL, 1, [Define to 1 if you have the `gsl' library (-lgsl).]) LIBS=$LIBS"-lgsl -lgslcblas "], AC_MSG_NOTICE([*** Could not find libgsl: will compile without optional special functions. ***]),[-lgslcblas]), AC_MSG_NOTICE([*** Header file gsl_sf.h not found: will compile without optional special functions. ***])) fi AC_ARG_ENABLE(fftw, [AS_HELP_STRING(--enable-fftw[[[=yes]]],enable FFTW Library)]) if test "x$enable_fftw" != "xno"; then AC_CHECK_HEADER(fftw3.h, AC_CHECK_LIB([fftw3], fftw_execute,, AC_MSG_NOTICE([*** Could not find libfftw3: will compile without optional fast Fourier transforms. ***])), AC_MSG_NOTICE([*** Header file fftw3.h not found: will compile without optional fast Fourier transforms. ***])) fi AC_ARG_ENABLE(gl, [AS_HELP_STRING(--enable-gl[[[=yes]]],enable OpenGL Library)]) AC_ARG_ENABLE(offscreen, [AS_HELP_STRING(--enable-offscreen[[[=yes]]],enable offscreen rendering using OSMesa library)]) if test "x$enable_gl" != "xno"; then case "$OSTYPE" in msdos) AC_CHECK_HEADER(GL/gl.h, [AC_DEFINE(HAVE_LIBGL, 1, [Define if you have the `opengl32' library (-lopengl32).]) LIBS=$LIBS"-lopengl32 "], AC_MSG_NOTICE([*** Could not find libopengl32: will compile without OpenGL support ***])) AC_CHECK_LIB([GLU], [gluNewNurbsRenderer],[AC_DEFINE(HAVE_LIBGLU, 1, [Define to 1 if you have the `glu32' library (-lglu32).]) LIBS=$LIBS"-lglu32 "], AC_MSG_NOTICE([*** Could not find libglu32: will compile without OpenGL support ***])) AC_CHECK_HEADER(GL/glut.h, [AC_DEFINE(HAVE_LIBGLUT, 1, [Define if you have the `freeglut' library (-lfreeglut).]) LIBS=$LIBS"-lfreeglut "], AC_MSG_NOTICE([*** Could not find libfreeglut: will compile without GLUT support ***])) ;; darwin*) AC_CHECK_HEADER(OpenGL/gl.h, [AC_DEFINE(HAVE_LIBGL, 1, [Define if you have the `OpenGL' library.])]) AC_CHECK_HEADER(OpenGL/glu.h, [AC_DEFINE(HAVE_LIBGLU, 1, [Define if you have the `GLU' library.])]) AC_CHECK_HEADER(GLUT/glut.h, [AC_DEFINE(HAVE_LIBGLUT, 1, [Define if you have the `GLUT' library.]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #include #include #ifndef GLU_TESS_CALLBACK_TRIPLEDOT typedef GLvoid (* _GLUfuncptr)(...); void f(void) { gluNurbsCallback(gluNewNurbsRenderer(),GLU_NURBS_BEGIN,(_GLUfuncptr) glBegin); } #endif ])],[AC_DEFINE(GLU_TESS_CALLBACK_TRIPLEDOT, 1, [Define if gluNurbsCallback expects a variadic function.])]) LIBS=$LIBS"-framework GLUT -framework OpenGL -framework Cocoa"], AC_MSG_NOTICE([*** Could not find glut: will compile without GLUT support ***])) ;; *) AC_CHECK_LIB([GL], [glDepthMask]) AC_CHECK_LIB([GLU], [gluNewNurbsRenderer],, AC_MSG_NOTICE([*** Could not find libGLU: will compile without OpenGL support ***])) AC_CHECK_LIB([glut], [glutMainLoop],, AC_MSG_NOTICE([*** Could not find libglut: will compile without GLUT support ***])) esac if test "x$enable_offscreen" != "xno"; then AC_CHECK_LIB([OSMesa],OSMesaCreateContext,, AC_MSG_NOTICE([*** Could not find libOSMesa: will compile without offscreen rendering support ***])) fi fi # Checks for typedefs, structures, and compiler characteristics. AC_TYPE_PID_T AC_TYPE_SIZE_T AC_CHECK_TYPES([ptrdiff_t]) AC_CHECK_TYPES([long long]) AC_CHECK_TYPES([long]) AC_C_CONST AC_C_INLINE AC_TYPE_SIGNAL AC_DEFUN([ac_FUNC_STRPTIME], [ AC_CHECK_FUNCS(strptime) ]) # Checks for library functions. AC_FUNC_FORK AC_CHECK_FUNCS([dup2 floor memset pow sqrt strchr tgamma memrchr]) AC_FUNC_STRFTIME ac_FUNC_STRPTIME AC_FUNC_ERROR_AT_LINE AC_FUNC_FSEEKO AC_CONFIG_HEADERS(config.h) AC_CONFIG_FILES([Makefile doc/Makefile doc/png/Makefile]) AC_OUTPUT if test "x$GCDIR" != "x" ; then AC_CHECK_FILE($GCDIR.tar.gz,,[ echo echo Please put the Boehm garbage collector tar.gz files in the current directory. echo FOR EXAMPLE, USE THE COMMANDS: echo echo wget http://hboehm.info/gc/gc_source/$GCFILE.tar.gz echo wget http://www.ivmaisoft.com/_bin/atomic_ops/libatomic_ops-$GCVERSION.tar.gz echo exit 1 ]) fi asymptote-2.37/constructor.cc000066400000000000000000000071311265434602500163770ustar00rootroot00000000000000/***** * constructor.cc * Andy Hammerlindl 2007/05/12 * * Using * * void operator init() * * as a field in the definition structure named Foo implicitly creates a * function that could be explicitly defined with code similar to * * static Foo Foo() { * Foo a=new Foo; * a.operator init(); * return a; * } * * This function is usable within further code in the structure definition and, * after the end of the structure definition, is carried over into the enclosing * scope so that it lasts as long as the type definition. *****/ #include "stack.h" #include "entry.h" #include "coenv.h" #include "dec.h" #include "newexp.h" namespace absyntax { using namespace trans; using namespace types; // Defined in dec.cc. varEntry *makeVarEntry(position pos, coenv &e, record *r, types::ty *t); bool definesImplicitConstructor(coenv &e, record *r, varEntry *v, symbol id) { if (id == symbol::initsym && r != 0 && v->getType()->kind == ty_function && e.c.isStatic() == false && e.c.isTopLevel() == false) { function *ft=dynamic_cast(v->getType()); if (ft->getResult()->kind == ty_void) return true; } return false; } // Given the coenv of the body of the constructor, encode the neccessary // instructions to make a new initialized object. void transConstructorBody(position pos, coenv &e, record *r, varEntry *init) { assert(r); assert(init); // Create a varEntry to hold the new object. Foo a; varEntry *v=makeVarEntry(pos, e, 0 /* not a field */, r); // Initialize the object. a=new Foo; newRecordExp::transFromTyEntry(pos, e, new tyEntry(r, 0, 0, position())); v->encode(WRITE, pos, e.c); e.c.encodePop(); // Push the args onto the stack. size_t numArgs=init->getSignature()->getNumFormals(); for (size_t i=0; iencode(READ, pos, e.c); } // Push the object on the stack. v->encode(READ, pos, e.c); // Call the 'operator init' field of the object. init->encode(CALL, pos, e.c, v->getLevel()); // Push the object again. v->encode(READ, pos, e.c); // Return the initialized object. e.c.encode(inst::ret); } varEntry *constructorFromInitializer(position pos, coenv &e, record *r, varEntry *init) { assert(r); types::function *ft=new types::function(r, init->getSignature()); ostringstream out; ft->printVar(out, symbol::trans("")); // Create a new function environment. coder fc = e.c.newFunction(pos, out.str(), ft); coenv fe(fc,e.e); // Translate the function. fe.e.beginScope(); transConstructorBody(pos, fe, r, init); fe.e.endScope(); // Put an instance of the new function on the stack. vm::lambda *l = fe.c.close(); e.c.encode(inst::pushclosure); e.c.encode(inst::makefunc, l); // Save it into a varEntry. varEntry *v=makeVarEntry(pos, e, r, ft); v->encode(WRITE, pos, e.c); e.c.encodePop(); return v; } void addConstructorFromInitializer(position pos, coenv &e, record *r, varEntry *init) { assert(r); // Constructors are declared statically. e.c.pushModifier(EXPLICIT_STATIC); varEntry *v=constructorFromInitializer(pos, e, r, init); // Add the constructor function under the same name as the record. addVar(e, r, v, r->getName()); // Add to the "post definition environment" of the record, so it will also be // added to the enclosing scope when the record definition ends. r->postdefenv.addVar(r->getName(), v); e.c.popModifier(); } } // namespace absyntax asymptote-2.37/dec.cc000066400000000000000000000506351265434602500145540ustar00rootroot00000000000000/***** * dec.cc * Andy Hammerlindl 2002/8/29 * * Represents the abstract syntax tree for declarations in the language. * Also included is an abstract syntax for types as they are most often * used with declarations. *****/ #include "errormsg.h" #include "coenv.h" #include "dec.h" #include "fundec.h" #include "newexp.h" #include "stm.h" #include "exp.h" #include "modifier.h" #include "runtime.h" #include "parser.h" namespace absyntax { using namespace trans; using namespace types; using mem::list; trans::tyEntry *ty::transAsTyEntry(coenv &e, record *where) { return new trans::tyEntry(trans(e, false), 0, where, getPos()); } void nameTy::prettyprint(ostream &out, Int indent) { prettyname(out, "nameTy",indent); id->prettyprint(out, indent+1); } types::ty *nameTy::trans(coenv &e, bool tacit) { return id->typeTrans(e, tacit); } trans::tyEntry *nameTy::transAsTyEntry(coenv &e, record *) { return id->tyEntryTrans(e); } void dimensions::prettyprint(ostream &out, Int indent) { prettyindent(out, indent); out << "dimensions (" << depth << ")\n"; } types::array *dimensions::truetype(types::ty *base) { if (base->kind == ty_void) { em.error(getPos()); em << "cannot declare array of type void"; } assert(depth >= 1); size_t d=depth; types::array *a=new types::array(base); d--; for (; d > 0; d--) { a = new types::array(a); } return a; } void arrayTy::prettyprint(ostream &out, Int indent) { prettyname(out, "arrayTy",indent); cell->prettyprint(out, indent+1); dims->prettyprint(out, indent+1); } // NOTE: Can this be merged with trans somehow? void arrayTy::addOps(coenv &e, record *r) { types::ty *t=trans(e, true); // Only add ops if it is an array (and not, say, an error) if (t->kind == types::ty_array) { types::array *at=dynamic_cast(t); assert(at); e.e.addArrayOps(at); if (r) r->e.addArrayOps(at); } } types::ty *arrayTy::trans(coenv &e, bool tacit) { types::ty *ct = cell->trans(e, tacit); assert(ct); // Don't make an array of errors. if (ct->kind == types::ty_error) return ct; types::array *t = dims->truetype(ct); assert(t); return t; } tyEntryTy::tyEntryTy(position pos, types::ty *t) : ty(pos), ent(new trans::tyEntry(t, 0, 0, position())) { } void tyEntryTy::prettyprint(ostream &out, Int indent) { prettyindent(out,indent); out << "tyEntryTy: " << *(ent->t) << "\n"; } types::ty *tyEntryTy::trans(coenv &, bool) { return ent->t; } vm::lambda *runnable::transAsCodelet(coenv &e) { coder c=e.c.newCodelet(getPos()); coenv ce(c, e.e); markTrans(ce); return c.close(); } void block::prettystms(ostream &out, Int indent) { for (list::iterator p = stms.begin(); p != stms.end(); ++p) (*p)->prettyprint(out, indent); } void block::prettyprint(ostream &out, Int indent) { prettyname(out,"block",indent); prettystms(out, indent+1); } void block::trans(coenv &e) { if (scope) e.e.beginScope(); for (list::iterator p = stms.begin(); p != stms.end(); ++p) { (*p)->markTrans(e); } if (scope) e.e.endScope(); } void block::transAsField(coenv &e, record *r) { if (scope) e.e.beginScope(); for (list::iterator p = stms.begin(); p != stms.end(); ++p) { (*p)->markTransAsField(e, r); } if (scope) e.e.endScope(); } void block::transAsRecordBody(coenv &e, record *r) { transAsField(e, r); e.c.closeRecord(); } record *block::transAsFile(genv& ge, symbol id) { // Create the new module. record *r = new record(id, new frame(id,0,0)); // Create coder and environment to translate the module. // File-level modules have dynamic fields by default. coder c(getPos(), r, 0); env e(ge); coenv ce(c, e); // Translate the abstract syntax. if (settings::getSetting("autoplain")) { autoplainRunnable()->transAsField(ce, r); } transAsRecordBody(ce, r); em.sync(); return r; } bool block::returns() { // Search for a returning runnable, starting at the end for efficiency. for (list::reverse_iterator p=stms.rbegin(); p != stms.rend(); ++p) if ((*p)->returns()) return true; return false; } vardec *block::asVardec() { vardec *var = 0; for (list::iterator p=stms.begin(); p != stms.end(); ++p) { vardec *v = dynamic_cast(*p); if (v) { if (var) // Multiple vardecs. return 0; var = v; } else if (!dynamic_cast(*p)) // Failure due to another runnable in the block. return 0; } return var; } void dec::prettyprint(ostream &out, Int indent) { prettyname(out, "dec", indent); } void modifierList::prettyprint(ostream &out, Int indent) { prettyindent(out,indent); out << "modifierList ("; for (list::iterator p = mods.begin(); p != mods.end(); ++p) { if (p != mods.begin()) out << ", "; switch (*p) { case EXPLICIT_STATIC: out << "static"; break; #if 0 case EXPLICIT_DYNAMIC: out << "dynamic"; break; #endif default: out << "invalid code"; } } for (list::iterator p = perms.begin(); p != perms.end(); ++p) { if (p != perms.begin() || !mods.empty()) out << ", "; switch (*p) { case PUBLIC: out << "public"; break; case PRIVATE: out << "private"; break; default: out << "invalid code"; } } out << ")\n"; } bool modifierList::staticSet() { return !mods.empty(); } modifier modifierList::getModifier() { if (mods.size() > 1) { em.error(getPos()); em << "too many modifiers"; } assert(staticSet()); return mods.front(); } permission modifierList::getPermission() { if (perms.size() > 1) { em.error(getPos()); em << "too many modifiers"; } return perms.empty() ? DEFAULT_PERM : perms.front(); } void modifiedRunnable::prettyprint(ostream &out, Int indent) { prettyname(out, "modifierRunnable",indent); mods->prettyprint(out, indent+1); body->prettyprint(out, indent+1); } void modifiedRunnable::transAsField(coenv &e, record *r) { if (mods->staticSet()) { if (e.c.isTopLevel()) { em.warning(getPos()); em << "static modifier is meaningless at top level"; } e.c.pushModifier(mods->getModifier()); } permission p = mods->getPermission(); #if 0 // This is innocuous if (p != DEFAULT_PERM && (!r || !body->allowPermissions())) { em.warning(pos); em << "permission modifier is meaningless"; } #endif e.c.setPermission(p); body->transAsField(e,r); e.c.clearPermission(); if (mods->staticSet()) e.c.popModifier(); } void decidstart::prettyprint(ostream &out, Int indent) { prettyindent(out, indent); out << "decidstart '" << id << "'\n"; if (dims) dims->prettyprint(out, indent+1); } types::ty *decidstart::getType(types::ty *base, coenv &, bool) { return dims ? dims->truetype(base) : base; } trans::tyEntry *decidstart::getTyEntry(trans::tyEntry *base, coenv &e, record *where) { return dims ? new trans::tyEntry(getType(base->t,e,false), 0, where, getPos()) : base; } void decidstart::addOps(types::ty *base, coenv &e, record *r) { if (dims) { e.e.addArrayOps(dims->truetype(base)); if (r) r->e.addArrayOps(dims->truetype(base)); } } void fundecidstart::prettyprint(ostream &out, Int indent) { prettyindent(out, indent); out << "fundecidstart '" << id << "'\n"; if (dims) dims->prettyprint(out, indent+1); if (params) params->prettyprint(out, indent+1); } types::ty *fundecidstart::getType(types::ty *base, coenv &e, bool tacit) { types::ty *result = decidstart::getType(base, e, tacit); if (params) { return params->getType(result, e, true, tacit); } else { types::ty *t = new function(base); return t; } } trans::tyEntry *fundecidstart::getTyEntry(trans::tyEntry *base, coenv &e, record *where) { return new trans::tyEntry(getType(base->t,e,false), 0, where, getPos()); } void fundecidstart::addOps(types::ty *base, coenv &e, record *r) { decidstart::addOps(base, e, r); params->addOps(e, r); types::function *ft=dynamic_cast(getType(base, e, true)); assert(ft); e.e.addFunctionOps(ft); if (r) r->e.addFunctionOps(ft); } void decid::prettyprint(ostream &out, Int indent) { prettyname(out, "decid",indent); start->prettyprint(out, indent+1); if (init) init->prettyprint(out, indent+1); } varEntry *makeVarEntryWhere(coenv &e, record *r, types::ty *t, record *where, position pos) { access *a = r ? r->allocField(e.c.isStatic()) : e.c.allocLocal(); return r ? new varEntry(t, a, e.c.getPermission(), r, where, pos) : new varEntry(t, a, where, pos); } varEntry *makeVarEntry(position pos, coenv &e, record *r, types::ty *t) { return makeVarEntryWhere(e, r, t, r, pos); } // Defined in constructor.cc. bool definesImplicitConstructor(coenv &e, record *r, varEntry *v, symbol id); void addConstructorFromInitializer(position pos, coenv &e, record *r, varEntry *init); void addVar(coenv &e, record *r, varEntry *v, symbol id) { // Test for 'operator init' definitions that implicitly define constructors: if (definesImplicitConstructor(e, r, v, id)) addConstructorFromInitializer(position(), e, r, v); // Add to the record so it can be accessed when qualified; add to the // environment so it can be accessed unqualified in the scope of the // record definition. if (r) r->e.addVar(id, v); e.e.addVar(id, v); } void initializeVar(position pos, coenv &e, varEntry *v, varinit *init) { types::ty *t=v->getType(); if (init) init->transToType(e, t); else { definit d(pos); d.transToType(e, t); } v->getLocation()->encode(WRITE, pos, e.c); e.c.encodePop(); } types::ty *inferType(position pos, coenv &e, varinit *init) { if (!init) { em.error(pos); em << "inferred variable declaration without initializer"; return primError(); } exp *base = dynamic_cast(init); if (base) { types::ty *t = base->cgetType(e); if (t->kind != ty_overloaded) return t; } em.error(pos); em << "could not infer type of initializer"; return primError(); } void createVar(position pos, coenv &e, record *r, symbol id, types::ty *t, varinit *init) { // I'm not sure how to handle inferred types in these cases. assert(t->kind != types::ty_inferred); varEntry *v=makeVarEntry(pos, e, r, t); addVar(e, r, v, id); initializeVar(pos, e, v, init); } void createVarOutOfOrder(position pos, coenv &e, record *r, symbol id, types::ty *t, varinit *init) { /* For declarations such as "var x = 5;", infer the type from the * initializer. */ if (t->kind == types::ty_inferred) t = inferType(pos, e, init); varEntry *v=makeVarEntry(pos, e, r, t); initializeVar(pos, e, v, init); addVar(e, r, v, id); } void addTypeWithPermission(coenv &e, record *r, tyEntry *base, symbol id) { // Only bother encoding permissions for private types. tyEntry *ent = (r && e.c.getPermission()==PRIVATE) ? new trans::tyEntry(base, PRIVATE, r) : base; if (r) r->e.addType(id, ent); e.e.addType(id, ent); } void decid::transAsField(coenv &e, record *r, types::ty *base) { types::ty *t = start->getType(base, e); assert(t); if (t->kind == ty_void) { em.error(getPos()); em << "cannot declare variable of type void"; } start->addOps(base, e, r); createVarOutOfOrder(getPos(), e, r, start->getName(), t, init); } void decid::transAsTypedefField(coenv &e, trans::tyEntry *base, record *r) { trans::tyEntry *ent = start->getTyEntry(base, e, r); assert(ent && ent->t); if (init) { em.error(getPos()); em << "type definition cannot have initializer"; } start->addOps(base->t, e, r); addTypeWithPermission(e, r, ent, start->getName()); } void decidlist::prettyprint(ostream &out, Int indent) { prettyname(out, "decidlist",indent); for (list::iterator p = decs.begin(); p != decs.end(); ++p) (*p)->prettyprint(out, indent+1); } void decidlist::transAsField(coenv &e, record *r, types::ty *base) { for (list::iterator p = decs.begin(); p != decs.end(); ++p) (*p)->transAsField(e, r, base); } void decidlist::transAsTypedefField(coenv &e, trans::tyEntry *base, record *r) { for (list::iterator p = decs.begin(); p != decs.end(); ++p) (*p)->transAsTypedefField(e, base, r); } void vardec::prettyprint(ostream &out, Int indent) { prettyname(out, "vardec",indent); base->prettyprint(out, indent+1); decs->prettyprint(out, indent+1); } void vardec::transAsTypedefField(coenv &e, record *r) { base->addOps(e, r); decs->transAsTypedefField(e, base->transAsTyEntry(e, r), r); } symbol vardec::singleName() { decid *did = decs->singleEntry(); if (!did) return symbol::nullsym; return did->getStart()->getName(); } types::ty *vardec::singleGetType(coenv &e) { decid *did = decs->singleEntry(); if (!did) return 0; return did->getStart()->getType(base->trans(e), e); } // Helper class for imports. This essentially evaluates to the run::loadModule // function. However, that function returns different types of records // depending on the filename given to it, so we cannot add it to the // environment. Instead, we explicitly tell it what types::record it is // returning for each use. class loadModuleExp : public exp { record *imp; function *ft; public: loadModuleExp(position pos, record *imp) : exp(pos), imp(imp), ft(new function(imp,primString())) {} void prettyprint(ostream &out, Int indent) { prettyname(out, "loadModuleExp", indent); } types::ty *trans(coenv &) { em.compiler(getPos()); em << "trans called for loadModuleExp"; return primError(); } void transCall(coenv &e, types::ty *t) { assert(equivalent(t, ft)); e.c.encode(inst::builtin, run::loadModule); } types::ty *getType(coenv &) { return ft; } exp *evaluate(coenv &, types::ty *) { // Don't alias. return this; } }; // Creates a local variable to hold the import and translate the accessing of // the import, but doesn't add the import to the environment. varEntry *accessModule(position pos, coenv &e, record *r, symbol id) { record *imp=e.e.getModule(id, (string)id); if (!imp) { em.error(pos); em << "could not load module '" << id << "'"; em.sync(); return 0; } else { // Create a varinit that evaluates to the module. // This is effectively the expression "loadModule(filename)". callExp init(pos, new loadModuleExp(pos, imp), new stringExp(pos, (string)id)); // The varEntry should have whereDefined()==0 as it is not defined inside // the record r. varEntry *v=makeVarEntryWhere(e, r, imp, 0, pos); initializeVar(pos, e, v, &init); return v; } } void idpair::prettyprint(ostream &out, Int indent) { prettyindent(out, indent); out << "idpair (" << "'" << src << "' as " << dest << ")\n"; } void idpair::transAsAccess(coenv &e, record *r) { checkValidity(); varEntry *v=accessModule(getPos(), e, r, src); if (v) addVar(e, r, v, dest); } void idpair::transAsUnravel(coenv &e, record *r, protoenv &source, varEntry *qualifier) { checkValidity(); if (r) r->e.add(src, dest, source, qualifier, e.c); if (!e.e.add(src, dest, source, qualifier, e.c)) { em.error(getPos()); em << "no matching types or fields of name '" << src << "'"; } } void idpairlist::prettyprint(ostream &out, Int indent) { for (list::iterator p=base.begin(); p != base.end(); ++p) (*p)->prettyprint(out, indent); } void idpairlist::transAsAccess(coenv &e, record *r) { for (list::iterator p=base.begin(); p != base.end(); ++p) (*p)->transAsAccess(e,r); } void idpairlist::transAsUnravel(coenv &e, record *r, protoenv &source, varEntry *qualifier) { for (list::iterator p=base.begin(); p != base.end(); ++p) (*p)->transAsUnravel(e,r,source,qualifier); } idpairlist * const WILDCARD = 0; void accessdec::prettyprint(ostream &out, Int indent) { prettyname(out, "accessdec", indent); base->prettyprint(out, indent+1); } void fromdec::prettyprint(ostream &out, Int indent) { prettyname(out, "fromdec", indent); fields->prettyprint(out, indent+1); } void fromdec::transAsField(coenv &e, record *r) { qualifier q=getQualifier(e,r); if (q.t) { if (fields==WILDCARD) { if (r) r->e.add(q.t->e, q.v, e.c); e.e.add(q.t->e, q.v, e.c); } else fields->transAsUnravel(e, r, q.t->e, q.v); } } void unraveldec::prettyprint(ostream &out, Int indent) { prettyname(out, "unraveldec", indent); id->prettyprint(out, indent+1); idpairlist *f=this->fields; if(f) f->prettyprint(out, indent+1); } fromdec::qualifier unraveldec::getQualifier(coenv &e, record *) { // getType is where errors in the qualifier are reported. record *qt=dynamic_cast(id->getType(e, false)); if (!qt) { em.error(getPos()); em << "qualifier is not a record"; } return qualifier(qt,id->getVarEntry(e)); } void fromaccessdec::prettyprint(ostream &out, Int indent) { prettyindent(out, indent); out << "fromaccessdec '" << id << "'\n"; idpairlist *f=this->fields; if(f) f->prettyprint(out, indent+1); } fromdec::qualifier fromaccessdec::getQualifier(coenv &e, record *r) { varEntry *v=accessModule(getPos(), e, r, id); if (v) { record *qt=dynamic_cast(v->getType()); if (!qt) { em.compiler(getPos()); em << "qualifier is not a record"; } return qualifier(qt, v); } else return qualifier(0,0); } void importdec::prettyprint(ostream &out, Int indent) { prettyname(out, "importdec", indent); base.prettyprint(out, indent+1); } void includedec::prettyprint(ostream &out, Int indent) { prettyindent(out, indent); out << "includedec ('" << filename << "')\n"; } void includedec::loadFailed(coenv &) { em.warning(getPos()); em << "could not parse file of name '" << filename << "'"; em.sync(); } void includedec::transAsField(coenv &e, record *r) { file *ast = parser::parseFile(filename,"Including"); em.sync(); // The runnables will be translated, one at a time, without any additional // scoping. ast->transAsField(e, r); } void typedec::prettyprint(ostream &out, Int indent) { prettyname(out, "typedec",indent); body->prettyprint(out, indent+1); } void recorddec::prettyprint(ostream &out, Int indent) { prettyindent(out, indent); out << "structdec '" << id << "'\n"; body->prettyprint(out, indent+1); } void recorddec::transRecordInitializer(coenv &e, record *parent) { position here=getPos(); // This is equivalent to the code // A operator init() { return new A; } // where A is the name of the record. formals formals(here); simpleName recordName(here, id); nameTy result(here, &recordName); newRecordExp exp(here, &result); returnStm stm(here, &exp); fundec init(here, &result, symbol::opTrans("init"), &formals, &stm); init.transAsField(e, parent); } void recorddec::addPostRecordEnvironment(coenv &e, record *r, record *parent) { if (parent) parent->e.add(r->postdefenv, 0, e.c); e.e.add(r->postdefenv, 0, e.c); } void recorddec::transAsField(coenv &e, record *parent) { record *r = parent ? parent->newRecord(id, e.c.isStatic()) : e.c.newRecord(id); addTypeWithPermission(e, parent, new trans::tyEntry(r,0,parent,getPos()), id); e.e.addRecordOps(r); if (parent) parent->e.addRecordOps(r); // Start translating the initializer. coder c=e.c.newRecordInit(getPos(), r); coenv re(c,e.e); body->transAsRecordBody(re, r); // After the record is translated, add a default initializer so that a // variable of the type of the record is initialized to a new instance by // default. transRecordInitializer(e, parent); // Add types and variables defined during the record that should be added to // the enclosing environment. These are the implicit constructors defined by // "operator init". addPostRecordEnvironment(e, r, parent); } runnable *autoplainRunnable() { // Abstract syntax for the code: // private import plain; position pos=position(); static importdec ap(pos, new idpair(pos, symbol::trans("plain"))); static modifiedRunnable mr(pos, trans::PRIVATE, &ap); return &mr; } } // namespace absyntax asymptote-2.37/dec.h000066400000000000000000000367451265434602500144240ustar00rootroot00000000000000/***** * dec.h * Andy Hammerlindl 2002/8/29 * * Represents the abstract syntax tree for declatations in the language. * Also included is abstract syntax for types as they are most often * used with declarations. *****/ #ifndef DEC_H #define DEC_H #include "symbol.h" #include "absyn.h" #include "name.h" #include "varinit.h" #include "modifier.h" namespace trans { class coenv; class genv; class protoenv; class varEntry; class access; } namespace types { class ty; struct formal; struct signature; struct function; } namespace vm { struct lambda; } namespace absyntax { using trans::genv; using trans::coenv; using trans::protoenv; using trans::varEntry; using trans::access; using sym::symbol; class vardec; class ty : public absyn { public: ty(position pos) : absyn(pos) {} virtual void prettyprint(ostream &out, Int indent) = 0; // If we introduced a new type, automatically add corresponding functions for // that type. virtual void addOps(coenv &, record *) {} // Returns the internal representation of the type. This method can // be called by exp::getType which does not report errors, so tacit is // needed to silence errors in this case. virtual types::ty *trans(coenv &e, bool tacit = false) = 0; virtual trans::tyEntry *transAsTyEntry(coenv &e, record *where); }; class nameTy : public ty { name *id; public: nameTy(position pos, name *id) : ty(pos), id(id) {} nameTy(name *id) : ty(id->getPos()), id(id) {} void prettyprint(ostream &out, Int indent); types::ty *trans(coenv &e, bool tacit = false); trans::tyEntry *transAsTyEntry(coenv &e, record *where); }; class dimensions : public absyn { size_t depth; public: dimensions(position pos) : absyn(pos), depth(1) {} void prettyprint(ostream &out, Int indent); void increase() { depth++; } size_t size() { return depth; } types::array *truetype(types::ty *base); }; class arrayTy : public ty { ty *cell; dimensions *dims; public: arrayTy(position pos, ty *cell, dimensions *dims) : ty(pos), cell(cell), dims(dims) {} arrayTy(name *id, dimensions *dims) : ty(dims->getPos()), cell(new nameTy(id)), dims(dims) {} void prettyprint(ostream &out, Int indent); void addOps(coenv &e, record *r); types::ty *trans(coenv &e, bool tacit = false); }; // Similar to varEntryExp, this helper class always translates to the same fixed // type. class tyEntryTy : public ty { trans::tyEntry *ent; public: tyEntryTy(position pos, trans::tyEntry *ent) : ty(pos), ent(ent) {} tyEntryTy(position pos, types::ty *t); void prettyprint(ostream &out, Int indent); types::ty *trans(coenv &e, bool tacit = false); trans::tyEntry *transAsTyEntry(coenv &, record *) { return ent; } }; // Runnable is anything that can be executed by the program, including // any declaration or statement. class runnable : public absyn { public: runnable(position pos) : absyn(pos) {} virtual void prettyprint(ostream &out, Int indent) = 0; void markTrans(coenv &e) { markPos(e); trans(e); } /* Translates the stm or dec as if it were in a function definition. */ virtual void trans(coenv &e) { transAsField(e, 0); } /* This can be overridden, to specify a special way of translating the code * when it is run at the top of the interactive prompt. */ virtual void interactiveTrans(coenv &e) { trans(e); } void markTransAsField(coenv &e, record *r) { markPos(e); transAsField(e,r); } /* Translate the runnable as in the lowest lexical scope of a record * definition. If it is simply a statement, it will be added to the * record's initializer. A declaration, however, will also have to * add a new type or field to the record. */ virtual void transAsField(coenv &e, record *) = 0; virtual vm::lambda *transAsCodelet(coenv &e); // For functions that return a value, we must guarantee that they end // with a return statement. This checks for that condition. virtual bool returns() { return false; } // Returns true if it is syntatically allowable to modify this // runnable by a PUBLIC or PRIVATE modifier. virtual bool allowPermissions() { return false; } }; class block : public runnable { public: mem::list stms; // If the runnables should be interpreted in their own scope. bool scope; protected: void prettystms(ostream &out, Int indent); public: block(position pos, bool scope=true) : runnable(pos), scope(scope) {} // To ensure list deallocates properly. virtual ~block() {} void add(runnable *r) { stms.push_back(r); } void prettyprint(ostream &out, Int indent); void trans(coenv &e); void transAsField(coenv &e, record *r); void transAsRecordBody(coenv &e, record *r); types::record *transAsFile(genv& ge, symbol id); // If the block can be interpreted as a single vardec, return that vardec // (otherwise 0). vardec *asVardec(); // A block is guaranteed to return iff one of the runnables is guaranteed to // return. // This is conservative in that // // int f(int x) // { // if (x==1) return 0; // if (x!=1) return 1; // } // // is not guaranteed to return. bool returns(); }; class modifierList : public absyn { mem::list perms; mem::list mods; public: modifierList(position pos) : absyn(pos) {} virtual ~modifierList() {} void prettyprint(ostream &out, Int indent); void add(trans::permission p) { perms.push_back(p); } void add(trans::modifier m) { mods.push_back(m); } /* True if a static or dynamic modifier is present. */ bool staticSet(); /* Says if the modifiers indicate static or dynamic. Prints error if * there are duplicates. */ trans::modifier getModifier(); /* Says if it is declared public, private, or read-only (default). * Prints error if there are duplicates. */ trans::permission getPermission(); }; // Modifiers of static or dynamic can change the way declarations and // statements are encoded. class modifiedRunnable : public runnable { modifierList *mods; runnable *body; public: modifiedRunnable(position pos, modifierList *mods, runnable *body) : runnable(pos), mods(mods), body(body) {} modifiedRunnable(position pos, trans::permission perm, runnable *body) : runnable(pos), mods(new modifierList(pos)), body(body) { mods->add(perm); } void prettyprint(ostream &out, Int indent); void transAsField(coenv &e, record *r); bool returns() { return body->returns(); } }; class decidstart : public absyn { protected: symbol id; dimensions *dims; public: decidstart(position pos, symbol id, dimensions *dims = 0) : absyn(pos), id(id), dims(dims) {} virtual void prettyprint(ostream &out, Int indent); virtual types::ty *getType(types::ty *base, coenv &, bool = false); virtual trans::tyEntry *getTyEntry(trans::tyEntry *base, coenv &e, record *where); // If a new type is formed by adding dimensions (or a function signature) // after the id, this will add the standard functions for that new type. virtual void addOps(types::ty *base, coenv &e, record *r); virtual symbol getName() { return id; } }; // Forward declaration. class formals; class fundecidstart : public decidstart { formals *params; public: fundecidstart(position pos, symbol id, dimensions *dims = 0, formals *params = 0) : decidstart(pos, id, dims), params(params) {} void prettyprint(ostream &out, Int indent); types::ty *getType(types::ty *base, coenv &e, bool tacit = false); trans::tyEntry *getTyEntry(trans::tyEntry *base, coenv &e, record *where); void addOps(types::ty *base, coenv &e, record *r); }; class decid : public absyn { decidstart *start; varinit *init; // Returns the default initializer for the type. access *defaultInit(coenv &e, types::ty *t); public: decid(position pos, decidstart *start, varinit *init = 0) : absyn(pos), start(start), init(init) {} virtual void prettyprint(ostream &out, Int indent); virtual void transAsField(coenv &e, record *r, types::ty *base); // Translate, but add the names in as types rather than variables. virtual void transAsTypedefField(coenv &e, trans::tyEntry *base, record *r); decidstart *getStart() { return start; } }; class decidlist : public absyn { mem::list decs; public: decidlist(position pos) : absyn(pos) {} virtual ~decidlist() {} void add(decid *p) { decs.push_back(p); } virtual void prettyprint(ostream &out, Int indent); virtual void transAsField(coenv &e, record *r, types::ty *base); // Translate, but add the names in as types rather than variables. virtual void transAsTypedefField(coenv &e, trans::tyEntry *base, record *r); // If the list consists of a single entry, return it. decid *singleEntry() { if (decs.size() == 1) return decs.front(); else return 0; } }; class dec : public runnable { public: dec(position pos) : runnable(pos) {} void prettyprint(ostream &out, Int indent); // Declarations can be public or private. bool allowPermissions() { return true; } }; void createVar(position pos, coenv &e, record *r, symbol id, types::ty *t, varinit *init); class vardec : public dec { ty *base; decidlist *decs; public: vardec(position pos, ty *base, decidlist *decs) : dec(pos), base(base), decs(decs) {} vardec(position pos, ty *base, decid *di) : dec(pos), base(base), decs(new decidlist(pos)) { decs->add(di); } void prettyprint(ostream &out, Int indent); void transAsField(coenv &e, record *r) { base->addOps(e, r); decs->transAsField(e, r, base->trans(e)); } // Translate, but add the names in as types rather than variables. virtual void transAsTypedefField(coenv &e, record *r); // If the vardec encodes a single declaration, return the name of that // declaration (otherwise nullsym). symbol singleName(); // If the vardec encodes a single declaration, return the type of that // declaration (otherwise 0). types::ty *singleGetType(coenv& e); }; struct idpair : public absyn { symbol src; // The name of the module to access. symbol dest; // What to call it in the local environment. bool valid; // If it parsed properly. idpair(position pos, symbol id) : absyn(pos), src(id), dest(id), valid(true) {} idpair(position pos, symbol src, symbol as, symbol dest) : absyn(pos), src(src), dest(dest), valid(as==symbol::trans("as")) {} idpair(position pos, string src, symbol as, symbol dest) : absyn(pos), src(symbol::trans(src)), dest(dest), valid(as==symbol::trans("as")) {} void checkValidity() { if (!valid) { em.error(getPos()); em << "expected 'as'"; } } void prettyprint(ostream &out, Int indent); // Translates as: access src as dest; void transAsAccess(coenv &e, record *r); // Translates as: from _ unravel src as dest; // where _ is the qualifier record with source as its fields and types. void transAsUnravel(coenv &e, record *r, protoenv &source, varEntry *qualifier); }; struct idpairlist : public gc { mem::list base; void add(idpair *x) { base.push_back(x); } void prettyprint(ostream &out, Int indent); void transAsAccess(coenv &e, record *r); void transAsUnravel(coenv &e, record *r, protoenv &source, varEntry *qualifier); }; extern idpairlist * const WILDCARD; class accessdec : public dec { idpairlist *base; public: accessdec(position pos, idpairlist *base) : dec(pos), base(base) {} void prettyprint(ostream &out, Int indent); void transAsField(coenv &e, record *r) { base->transAsAccess(e,r); } }; // Abstract base class for // from _ access _; (fromaccessdec) // and // from _ unravel _; (unraveldec) class fromdec : public dec { protected: struct qualifier { // The varEntry holds the location and the type of the highest framed // structure that can be put on the stack. The record holds the actual type // of the qualifier. // For example: // struct A { // struct B { // static int x; // } // } // A a=new A; // from a.B unravel x; // // Here, v->getType() will yield A and v->getLocation() will yield the // location of the the variable a, but the record type t will be B. record *t; varEntry *v; qualifier(record *t, varEntry *v) : t(t), v(v) {} }; // Return the qualifier from which the fields are taken. If t==0, it is // assumed that an error occurred and was reported. virtual qualifier getQualifier(coenv &e, record *r) = 0; idpairlist *fields; public: fromdec(position pos, idpairlist *fields) : dec(pos), fields(fields) {} void prettyprint(ostream &out, Int indent); void transAsField(coenv &e, record *r); }; // An unravel declaration dumps fields and types of a record into the local // scope. class unraveldec : public fromdec { name *id; qualifier getQualifier(coenv &e, record *); public: unraveldec(position pos, name *id, idpairlist *fields) : fromdec(pos, fields), id(id) {} void prettyprint(ostream &out, Int indent); }; // A fromaccess declaration dumps fields and types of a module into the local // scope. It does not add the module as a variable in the local scope. class fromaccessdec : public fromdec { symbol id; qualifier getQualifier(coenv &e, record *r); public: fromaccessdec(position pos, symbol id, idpairlist *fields) : fromdec(pos, fields), id(id) {} void prettyprint(ostream &out, Int indent); }; // An import declaration dumps fields and types of a module into the local // scope. It also adds the module as a variable in the local scope. class importdec : public dec { block base; public: importdec(position pos, idpair *id) : dec(pos), base(pos, false) { idpairlist *i=new idpairlist; i->add(id); base.add(new accessdec(pos, i)); base.add(new unraveldec(pos, new simpleName(pos, id->dest), WILDCARD)); } void trans(coenv &e) { base.trans(e); } void transAsField(coenv &e, record *r) { base.transAsField(e, r); } void prettyprint(ostream &out, Int indent); }; // Parses the file given, and translates the resulting runnables as if they // occurred at this place in the code. class includedec : public dec { string filename; public: includedec(position pos, string filename) : dec(pos), filename(filename) {} includedec(position pos, symbol id) : dec(pos), filename(id) {} void prettyprint(ostream &out, Int indent); void loadFailed(coenv &e); void transAsField(coenv &e, record *r); }; // Types defined from others in typedef. class typedec : public dec { vardec *body; public: typedec(position pos, vardec *body) : dec(pos), body(body) {} void prettyprint(ostream &out, Int indent); void transAsField(coenv &e, record *r) { body->transAsTypedefField(e,r); } }; // A struct declaration. class recorddec : public dec { symbol id; block *body; void transRecordInitializer(coenv &e, record *parent); void addPostRecordEnvironment(coenv &e, record *r, record *parent); public: recorddec(position pos, symbol id, block *body) : dec(pos), id(id), body(body) {} virtual ~recorddec() {} void prettyprint(ostream &out, Int indent); void transAsField(coenv &e, record *parent); }; // Returns a runnable that facilitates the autoplain feature. runnable *autoplainRunnable(); void addVar(coenv &e, record *r, varEntry *v, symbol id); } // namespace absyntax #endif asymptote-2.37/doc/000077500000000000000000000000001265434602500142465ustar00rootroot00000000000000asymptote-2.37/doc/Bode.asy000066400000000000000000000012451265434602500156370ustar00rootroot00000000000000import graph; texpreamble("\def\Arg{\mathop {\rm Arg}\nolimits}"); size(10cm,5cm,IgnoreAspect); real ampl(real x) {return 2.5/sqrt(1+x^2);} real phas(real x) {return -atan(x)/pi;} scale(Log,Log); draw(graph(ampl,0.01,10)); ylimits(0.001,100); xaxis("$\omega\tau_0$",BottomTop,LeftTicks); yaxis("$|G(\omega\tau_0)|$",Left,RightTicks); picture q=secondaryY(new void(picture pic) { scale(pic,Log,Linear); draw(pic,graph(pic,phas,0.01,10),red); ylimits(pic,-1.0,1.5); yaxis(pic,"$\Arg G/\pi$",Right,red, LeftTicks("$% #.1f$", begin=false,end=false)); yequals(pic,1,Dotted); }); label(q,"(1,0)",Scale(q,(1,0)),red); add(q); asymptote-2.37/doc/CAD.tex000066400000000000000000000237241265434602500153670ustar00rootroot00000000000000\documentclass{ltxguide} \usepackage{graphicx} \begin{document} \title{Asymptote package CAD.asy\footnote{This document describes version 1.0.}} \author{Mark Henning, Germany\thanks{URL: http://www.markhenning.de}} \date{29 September 2006} \maketitle \tableofcontents \section{Introduction} The package {\tt CAD.asy} provides basic pen definitions and measurement functions for simple 2D CAD drawings according to DIN 15. \section{Important rules for using this package} If a function is declared like this: % \begin{verbatim} void foo(int nParam1, string strParam2) \end{verbatim} % You may call it \verb\foo(0, 'abc');\ or \verb\foo(nParam1=0, strParam2='abc');\. The definitions of the functions in this package may change in future version: the order of the parameters may be changed, new parameters may be inserted. Therefore it is \emph{strongly recommended} always calling the functions \verb\foo(nParam1=0, strParam2='abc');\. \section{Usage} To use the capabilities of the package, import it: % \begin{verbatim} import CAD; \end{verbatim} % All functions are encapsulated in the structure \verb\sCAD\. As the pen definitions may differ depending on the size of your drawing, you have to initialize the structure before drawing: \begin{verbatim} static sCAD Create(int nLineGroup = 1) \end{verbatim} % The parameter \verb\nLineGroup\ depends on the size of your drawing. It specifies the line group to define the pens and thus the width used for the lines. The parameter has to be within the range $[0;3]$. The larger the value, the thicker the lines. Code example: % \begin{quote}\begin{verbatim} sCAD cad = sCAD.Create(); \end{verbatim}\end{quote} The created variable \verb\cad\ then provides the most important pens. Available pens are: % \begin{itemize} \item The pens of group A: \begin{itemize} \item\verb\pA\ \item\verb\pVisibleEdge\ \item\verb\pVisibleContour\ \item\verb\pUsableWindingLength\ \item\verb\pSystemLine\ \item\verb\pDiagramCurve\ \item\verb\pSurfaceStructure\ \end{itemize} \item The pens of group B: \begin{itemize} \item\verb\pB\ \item\verb\pLightEdge\ \item\verb\pMeasureLine\ \item\verb\pMeasureHelpLine\ \item\verb\pMeasureLineBound\ \item\verb\pReferenceLine\ \item\verb\pHatch\ \item\verb\pWindingGround\ \item\verb\pDiagonalCross\ \item\verb\pBendLine\ \item\verb\pProjectionLine\ \item\verb\pGrid\ \end{itemize} \item The pens of group C: \begin{itemize} \item\verb\pC\ \item\verb\pFreehand\ \end{itemize} \item The pens of group E: \begin{itemize} \item\verb\pE\ \item\verb\pSurfaceTreatmentAllowed\ \end{itemize} \item The pens of group F: \begin{itemize} \item\verb\pF\ \item\verb\pInvisibleEdge\ \item\verb\pInvisibleContour\ \end{itemize} \item The pens of group G: \begin{itemize} \item\verb\pG\ \item\verb\pMiddleLine\ \item\verb\pSymmetryLine\ \item\verb\pPartialCircle\ \item\verb\pCircularHole\ \item\verb\pDivisionPlane\ \item\verb\pTransferLine\ \end{itemize} \item The pens of group J: \begin{itemize} \item\verb\pJ\ \item\verb\pCuttingPlane\ \item\verb\pSurfaceTreatmentRequested\ \end{itemize} \item The pens of group K: \begin{itemize} \item\verb\pK\ \item\verb\pContourBeforeDeformation\ \item\verb\pAdjacentPartContour\ \item\verb\pEndShapeRawMaterial\ \item\verb\pContourEligibleType\ \item\verb\pPartInFrontOfCuttingPlane\ \end{itemize} \end{itemize} % All pens of one group are the same. So there is no difference between the pen \verb\pA\ and the pen \verb\pVisibleEdge\. You may use the short names or the descriptive ones. The list of groups is not complete. I had no idea how to implement the pens of group D. For me, group H seems to be obsolete, and there is no group I contained in DIN 15. In the case I did something wrong translating the German names into English, the source file also contains the original German names of each pen. Whenever a drawing function does not allow you to select the pen, the right pen is selected automatically. \begin{verbatim} void MeasureLine(picture pic = currentpicture, Label L, pair pFrom, pair pTo, real dblLeft = 0, real dblRight = 0, real dblRelPosition = 0.5, bool bSmallBound = false) \end{verbatim} % This is the basic function to draw labeled straight measurement lines. \verb\pic\ denotes the picture the line has to be drawn into, \verb\L\ is the label of the line. The pairs \verb\pFrom\ and \verb\pTo\ are the start and the end point of the distance to measure, respectively. Note, that these two points do \emph{not} refer to the start and end point of the line, as it may be longer than the measured distance. The line is extended on its left side (= the part of the line 'before' the start point) by the distance \verb\dblLeft\. On its right side (= the part of the line 'behind' the end point) it is extended by the distance \verb\dblRight\. \verb\dblLeft\ and \verb\dblRight\ must be $\leq 0$. If only one of both values is zero, it is set to the value of the other one, because according to DIN 15 it is not allowed to draw a measurement line asymmetrically. The position of the arrows indicating begin and end of the distance depends on \verb\dblLeft\ and \verb\dblRight\. If both values are 0, the measurement arrows are drawn within the measurement distance. Otherwise they are drawn outside. The parameter \verb\dblRelPosition\ refers to the relative position of the label between the start and end point. This means: The value 0 positions the label at the start point, 0.5 refers to the center between the start and the end point. Finally, the value 1 will position the label at the end point. If \verb\dblLeft\ or \verb\dblRight\ are nonzero, you may position the label at the left side of the start point ($< 0$) or at the right side of the start point ($> 1$). Usually, there is enough space to draw the measurement arrows. If you wish to use small circles instead of the arrows, set \verb\bSmallBound\ to \verb\true\. \begin{verbatim} real GetMeasurementBoundSize(bool bSmallBound = false) \end{verbatim} % Returns the size of the arrow or the small bound circle used for measurement lines. \begin{verbatim} guide GetMeasurementBound(bool bSmallBound = false) \end{verbatim} % Returns the correctly scaled guide of the arrow or the small bound circle used for measurement lines. \begin{verbatim} void MeasureParallel(picture pic = currentpicture, Label L, pair pFrom, pair pTo, real dblDistance, // Variables from MeasureLine real dblLeft = 0, real dblRight = 0, real dblRelPosition = 0.5, bool bSmallBound = false) \end{verbatim} % Usually, measurement lines are placed outside the drawing with reference lines to the measured distance. \verb\pFrom\ and \verb\pTo\ denote the points of the drawing marking the begin and the end of the distance to measure, and not the begin and the end of the measurement line as in the case of the function \verb\MeasureLine\. The measurement line is placed \verb\dblDistance\ away from the distance to measure. If you would be at \verb\pFrom\ and look into the direction \verb\pTo\, it is placed on the left for positive values of \verb\dblDistance\. For negative values, it is positioned on the right. For the meaning of the other parameters see the function \verb\MeasureLine\. \begin{verbatim} guide MakeFreehand(pair pFrom, pair pTo, real dblRelDivisionLength = 12.5, real dblRelDistortion = 2.5, bool bIncludeTo = true) \end{verbatim} % To draw a line between two points, which is not straight, but more like a freehand line, use this function. The pairs \verb\pFrom\ and \verb\pTo\ denote start and end point, respectively. \verb\dblRelDivisionLength\ is the length of the parts, the line is subdivided into. \verb\dblRelDistortion\ is the amount of distortion. Both sizes are given relative to the width of a freehand line. If \verb\bIncludeTo\ is \verb\true\, the point \verb\pTo\ is added to the path. Otherwise it is not. This may be useful for converting a guide containing more than two points to a freehand line. \section{Example} \begin{figure} \includegraphics{CAD1} \caption{Example showing the measurement capabilities and a small freehand line.\label{fig:example1}} \end{figure} To produce figure \ref{fig:example1}, use this code: \begin{quote} \begin{verbatim} import CAD; sCAD cad = sCAD.Create(); // Freehand line draw(g = cad.MakeFreehand(pFrom = (3, -1)*cm, (6, -1)*cm), p = cad.pFreehand); // Standard measurement lines draw(g = box((0, 0)*cm, (1, 1)*cm), p = cad.pVisibleEdge); cad.MeasureParallel(L = "$\sqrt{2}$", pFrom = (0, 1)*cm, pTo = (1, 0)*cm, dblDistance = -15mm); // Label inside, shifted to the right; arrows outside draw(g = box((2, 0)*cm, (3, 1)*cm), p = cad.pVisibleEdge); cad.MeasureParallel(L = "1", pFrom = (2, 1)*cm, pTo = (3, 1)*cm, dblDistance = 5mm, dblLeft = 5mm, dblRelPosition = 0.75); // Label and arrows outside draw(g = box((5, 0)*cm, (5.5, 1)*cm), p = cad.pVisibleEdge); cad.MeasureParallel(L = "0.5", pFrom = (5, 1)*cm, pTo = (5.5, 1)*cm, dblDistance = 5mm, dblLeft = 10mm, dblRelPosition = -1); // Small bounds, asymmetric measurement line draw(g = box((7, 0)*cm, (7.5, 1)*cm), p = cad.pVisibleEdge); cad.MeasureParallel(L = "0.5", pFrom = (7, 1)*cm, pTo = (7.5, 1)*cm, dblDistance = 5mm, dblLeft = 2*cad.GetMeasurementBoundSize( bSmallBound = true), dblRight = 10mm, dblRelPosition = 2, bSmallBound = true); \end{verbatim} \end{quote} \end{document} asymptote-2.37/doc/CAD1.asy000066400000000000000000000025571265434602500154450ustar00rootroot00000000000000import CAD; sCAD cad=sCAD.Create(); // Freehand line draw(g=cad.MakeFreehand(pFrom=(3,-1)*cm,(6,-1)*cm), p=cad.pFreehand); // Standard measurement lines draw(g=box((0,0)*cm,(1,1)*cm),p=cad.pVisibleEdge); cad.MeasureParallel(L="$\sqrt{2}$", pFrom=(0,1)*cm, pTo=(1,0)*cm, dblDistance=-15mm); // Label inside,shifted to the right; arrows outside draw(g=box((2,0)*cm,(3,1)*cm),p=cad.pVisibleEdge); cad.MeasureParallel(L="1", pFrom=(2,1)*cm, pTo=(3,1)*cm, dblDistance=5mm, dblLeft=5mm, dblRelPosition=0.75); // Label and arrows outside draw(g=box((5,0)*cm,(5.5,1)*cm),p=cad.pVisibleEdge); cad.MeasureParallel(L="0.5", pFrom=(5,1)*cm, pTo=(5.5,1)*cm, dblDistance=5mm, dblLeft=10mm, dblRelPosition=-1); // Small bounds,asymmetric measurement line draw(g=box((7,0)*cm,(7.5,1)*cm),p=cad.pVisibleEdge); cad.MeasureParallel(L="0.5", pFrom=(7,1)*cm, pTo=(7.5,1)*cm, dblDistance=5mm, dblLeft=2*cad.GetMeasurementBoundSize(bSmallBound=true), dblRight=10mm, dblRelPosition=2, bSmallBound=true); asymptote-2.37/doc/CDlabel.asy000066400000000000000000000007721265434602500162600ustar00rootroot00000000000000size(11.7cm,11.7cm); asy(nativeformat(),"logo"); fill(unitcircle^^(scale(2/11.7)*unitcircle), evenodd+rgb(124/255,205/255,124/255)); label(scale(1.1)*minipage( "\centering\scriptsize \textbf{\LARGE {\tt Asymptote}\\ \smallskip \small The Vector Graphics Language}\\ \smallskip \textsc{Andy Hammerlindl, John Bowman, and Tom Prince} http://asymptote.sourceforge.net\\ ",8cm),(0,0.6)); label(graphic("logo."+nativeformat(),"height=7cm"),(0,-0.22)); clip(unitcircle^^(scale(2/11.7)*unitcircle),evenodd); asymptote-2.37/doc/FAQ/000077500000000000000000000000001265434602500146555ustar00rootroot00000000000000asymptote-2.37/doc/FAQ/Makefile000066400000000000000000000017501265434602500163200ustar00rootroot00000000000000BFNNCONV = bfnnconv.pl m-ascii.pl m-html.pl m-info.pl m-lout.pl m-post.pl all: faq faq: $(BFNNCONV) asy-faq.bfnn mkdir -p asy-faq.html perl bfnnconv.pl asy-faq.bfnn perl bfnnconv.pl asy-faq.bfnn clean: FORCE -rm -f *~ core a.out *.lout *.ps *.info *.ascii *.xrefdb *.post -rm -rf *.html install-all: install install: faq install-prebuilt ${INSTALL} -d -m 755 $(docdir) $(docdir)/asy-faq.html ${INSTALL} -p -m 644 asy-faq.ascii $(docdir) ${INSTALL} -p -m 644 asy-faq.html/* $(docdir)/asy-faq.html install-prebuilt: ${INSTALL} -d -m 755 $(infodir) ${INSTALL} -p -m 644 asy-faq.info $(infodir) -if test -z "$(DESTDIR)"; then \ install-info --infodir=$(infodir) asy-faq.info; \ fi install-info: faq install-prebuilt uninstall: uninstall-all uninstall-all: -cd $(docdir)/asy-faq.html && rm -rf *.html -cd $(docdir) && rmdir asy-faq.html && rm asy-faq.ascii -install-info --remove --infodir=$(infodir) asy-faq.info -rm -f $(infodir)/asy-faq.info distclean: FORCE clean FORCE: asymptote-2.37/doc/FAQ/asy-faq.bfnn000066400000000000000000001174741265434602500171010ustar00rootroot00000000000000\comment This is the source for the Asymptote FAQ list, in \comment the Bizarre Format With No Name. It is turned into Lout \comment input, HTML, plain ASCII and an Info document by a Perl script. \comment \comment The format and scripts come from the Linux FAQ, by \comment Ian Jackson. \set brieftitle Asymptote FAQ \set author Asymptote \set title Asymptote Frequently Asked Questions \copyto ASCII ASYMPTOTE FREQUENTLY ASKED QUESTIONS `date '+%d %h %Y'` \endcopy \copyto INFO INFO-DIR-SECTION Languages START-INFO-DIR-ENTRY * asymptote FAQ: (asy-faq). Asymptote Frequently Asked Questions. END-INFO-DIR-ENTRY  File: asy-faq.info, Node: Top, Next: Question 1.1, Up: (dir) ASYMPTOTE FREQUENTLY ASKED QUESTIONS `date '+%d %h %Y'` \endcopy This is the list of Frequently Asked Questions about Asymptote (asy). \section Index \index \comment ###################################################################### \section About Asymptote \question 26jun:whatisasy What is Asymptote? Asymptote is a vector graphics language designed for technical graphics, inspired by MetaPost but with IEEE floating-point numerics, native three-dimensional graphics, Grayscale/RGB/CMYK colourspaces, and a C++-like syntax. Unlike MetaPost, it natively supports multiple-segment paths (and hence regions other than simply connected ones), tiling patterns, Gouraud shading, tensor patch shading, and PostScript images. \question 22jun:whereisasy How do I obtain Asymptote? Binary releases are available for Linux, MacOS X, and Microsoft Windows platforms, in addition to full source code, from the website \docref{http://asymptote.sourceforge.net/\}. Many Linux distributions (such as RedHat and Debian) now include an Asymptote package (check your distribution's documentation for further information about this). \question 28jun:beforeasking Where can I ask questions about Asymptote? If you have a question, please try to find an answer in this FAQ, in the extensive Asymptote documentation at \docref{http://asymptote.sourceforge.net/doc/\}, or search the forum: \docref{http://sourceforge.net/forum/forum.php?forum_id=409349\}. \question 02sep:whyasy Why was the name Asymptote chosen? Well, it isn't the perfect graphics package, but we do think it is getting there asymptotically... \question 02sep:whycamp In the internal Asymptote source code, what does the name \courier{camp\} refer to? That was our original tentative name for this project, which stood for "C's Answer to MetaPost" (the language that inspired Asymptote). However, we eventually decided that the name \courier{Asymptote\} better emphasizes the mathematical and graphical nature of this language. \comment ###################################################################### \section Questions about installation and setup \question 26jun:osx Is it possible to install Asymptote on Mac OS X? It is easy to compile Asymptote directly from the source code at \docref{http://sourceforge.net/project/showfiles.php?group_id=120000\} We recommend first upgrading to the latest GNU readline library, unless you don't care about interactive readline support (in which case configure will automatically detect and disable obsolete versions of the readline library). Marius Schamschula also maintains a binary package for various MacOS X platforms \docref{http://www.hmug.org/pub/MacOS_X/X/Applications/Publishing/asymptote\}. \question 26jun:osxbadCPU Why do I get the error \courier{Bad CPU type in executable\} on installing Asymptote from the MAC OS binary? This means either that you have a binary distribution for another MAC architecture, or (according to Marius Schamschula) that you may have a missing library. The simplest solution is to compile Asymptote directly from the official source: \docref{http://sourceforge.net/project/showfiles.php?group_id=120000\}. \question 04nov:brokenpdftex What do I do if I get the error: \courier{Error: pdfetex (file pdftex.cfg): cannot open config file...texinfo.tex appears to be broken\}? Simply put \docref{http://asymptote.sourceforge.net/asymptote.pdf\} in the directory \courier{doc\} and repeat the command \courier{make all\}. Or, if you don't want to build a local copy of the documentation, simply proceed with \courier{make install-asy\}. \question 04nov:brokentexinfo What do I do if I get the error: \courier{! Undefined control sequence. l.6 @copying\}? Either upgrade your \courier{texinfo\} package or follow one of the easy work arounds in \qref brokenpdftex. \question 27jun:latexintegration Is it possible to integrate Asymptote into LaTeX? Yes, see the example latexusage.tex. Dario Teixeira has also written a detailed guide on the topic. You can download it from \docref{http://dario.dse.nl/projects/asylatex/\}. Philippe Ivaldi has contributed an Asymptote mode for Emacs users \docref{http://asymptote.sourceforge.net/doc/Editing-modes.html\}, which includes a \courier{lasy-mode\} that allows one to compile and view the output of one \\begin{asy}...\\end{asy} section at a time. \question 02sep:pdflatex Is it possible to integrate Asymptote into latex or pdflatex? Yes, as of version 1.14, Asymptote supports latex and pdflatex (both in EPS/PDF and inline mode), as illustrated by the example \courier{latexusage.tex\}: \verbatim pdflatex latexusage asy latexusage pdflatex latexusage \endverbatim \question 02sep:tkinterdepend Do I need the \courier{tkinter\} package to install an Asymptote rpm binary? No, you don't need \courier{tkinter\} unless you want to try out the GUI \courier{xasy\}. Try \verbatim rpm -Uvh --nodeps asymptote-x.xx-1.i386.rpm \endverbatim where \courier{x.xx\} represents the version number. \question 26jun:windir What does the path \courier{%USERPROFILE%\\.asy\\config.asy\} mean? That is the way that Microsoft Windows refers to the user profile directory. There's nothing really to understand here, just put your configuration commands in the file \courier{config.asy\} in a new folder \courier{%USERPROFILE%\\.asy\}. \question 25dec:escapechar Why do I get the error "string not terminated" when I try to set \courier{settings.dir="C:\\asymptote\\";\}? The backslash is an escape character here, so \courier{\\"\} is interpreted as a verbatim quotation mark, leaving the string without a terminating quotation mark. Fortunately, this is the only escaped character in double-quoted strings. A final backslash isn't needed here anyway, but should you really want one somewhere, you can say: \courier{settings.dir="C:\\asymptote"+'\\\\';\}. \question 27jun:winglobal How do I change environment variables in Microsoft Windows, for example, in order to change the default PostScript viewer? While it is easier to set the corresponding Asymptote configuration variable in your \courier{config.asy\} file, here is the procedure for changing Microsoft Windows environment variables: Click on the [Start] button * RIGHT-click on 'My Computer' * Choose 'Properties' from the popup menu * Click the 'Advanced' tab * Click the 'Environment Variables' button. \question 02sep:convert Under Microsoft Windows XP, why do I get an error like "Invalid Parameter - 432x432"? This means that ImageMagick wasn't properly installed and you are using the MSDOS convert program rather than the ImageMagick one. Or you may have installed ImageMagick but ran Asymptote from an existing MSDOS window. In that case, simply open a new window and try again. If that doesn't work, check that \verbatim convert --version \endverbatim returns something like \verbatim Version: ImageMagick 6.2.8 06/27/06 Q16 http://www.imagemagick.org \endverbatim \question 26jun:miktex Why does Asymptote freeze upon trying to draw a label with my MikTex installation under Microsoft Windows? Likely, this means that latex and dvips are not in your default path. Try adding the appropriate paths in your \courier{config.asy\} file, for example: \verbatim import settings; latex="C:\Program Files\MiKTeX 2.7\miktex\bin\latex.exe"; dvips="C:\Program Files\MiKTeX 2.7\miktex\bin\dvips.exe"; \endverbatim \comment ##################################################################### \section Questions about paths \question 02sep:tensionsyntax Why do I get a syntax error message when I specify an integer value for the path tension? What is happening here is that \verbatim draw((0,0)..tension 2..(0,50)..(100,100)); \endverbatim is read as \verbatim draw((0,0)..tension 2. .(0,50)..(100,100)); \endverbatim So the first . after the two is treated as a decimal point. Just put a space after the integer tension value: \verbatim draw((0,0)..tension 2 ..(0,50)..(100,100)); \endverbatim \question 27jun:dots Shouldn't dots always be the same size? From the documentation: "The dot command defined in the module plain draws a dot having a diameter equal to an explicit pen linewidth or the default linewidth magnified by dotfactor (6 by default)." Thus, when you use the default pen, the dot will have size 6*linewidth, but when you give a pen with an explicit width specified, you will have a dot of size linewidth. If you want the first case to behave like the second, you may set dotfactor=1. \comment ##################################################################### \section Questions about labels \question 02sep:greek How do I get Greek letters like omega to show up in my labels? In (La)TeX, Greek letters can be obtained in math mode by prepending a backslash to the letter name. So for a omega symbol, use "$\\omega$". Everything between the dollar signs is considered to be a math formula. Uppercase Greek letters can be used by capitalizing the first letter of the name: \verbatim label("$\omega$",(0,0)); label("$\Omega$",(20,0)); \endverbatim \question 29jun:matlabels Can Asymptote use matrices as labels? Yes: \verbatim usepackage("amsmath"); label("$\begin{matrix} 1 & 2 \\\ 1 & 1 \end{matrix}$",(0,0)); \endverbatim \question 27jun:latexpackage How do I tell Asymptote to load a particular LaTeX package, like \courier{mathptmx\}? Put \verbatim usepackage("mathptmx"); \endverbatim at the beginning of your file. Note: to enable the Adobe Times Roman font for text, you will also need to say: \verbatim defaultpen(TimesRoman()); \endverbatim \question 28jun:internatfonts How can I use international fonts in Asymptote labels? See \docref{http://asymptote.sourceforge.net/doc/unicode.html\}. \question 10jul:Fourier How can I use Fourier fonts? \verbatim usepackage("fourier"); defaultpen(font("T1","fut\textfamilyextension","m","n")); \endverbatim \question 26jun:decsep Is there any way to change the default appearance of the decimal separator, using a comma instead of a dot? Just set your locale appropriately: \verbatim locale("it_IT"); usepackage("icomma"); label(format(0.5)); \endverbatim \question 02sep:rotatelabel How can I get a rotated label with the filled box rotated as well so that it fits the text? \verbatim frame f; label(f,"This is some text",white,Fill(blue)); add(rotate(65)*f); \endverbatim \question 02sep:rotatelabel3D How can I rotate labels in a 3D figure? You need to first project the triple to a pair like this: \verbatim import three; size(100,100); draw(rotate(90,project(Z))*"A",O--X); \endverbatim \question 02sep:fixedsize How can I draw some squares and circles of a fixed size and put a label in the middle of them? Fixed-size objects should be drawn on a separate picture and then added to currentpicture. Here is one way (see also \docref{http://asymptote.sourceforge.net/gallery/subpictures.asy\} and \docref{http://asymptote.sourceforge.net/gallery/mosquito.asy\}): \verbatim real u=2cm; picture square; draw(square,scale(u)*shift(-0.5,-0.5)*unitsquare); picture circle; draw(circle,scale(0.5u)*unitcircle); void add(picture pic=currentpicture, Label L, picture object, pair z) { add(pic,object,z); label(pic,L,z); } add("square",square,(0,0)); add("circle",circle,(5cm,0)); \endverbatim \question 27jun:colorssaturation The binary operator * can be used to scale the color of a pen by a real number. Does this scaling factor have to be less than 1? The scaling factor can be greater than 1. But keep in mind that the rgb color components saturate at 1. Try \verbatim write(cyan); write(0.8*cyan); write(1.5*cyan); \endverbatim and you will quickly see what is going on. To get a lighter cyan you can say white+cyan, which yields rgb(0.5,1,1). If you want something even lighter specify the rgb colors directly, for example, rgb(0.9,1,1). Alternatively, work in cmyk colour space, which is nicer in that it handles saturation separately from hue: 0.1*Cyan is light and 0.9*Cyan is dark. You can also say 0.1*cmyk(red). \question 05mar:commadecimalseparator Why is the space after the comma decimal separator in my locale so large? LaTeX is treating the comma as punctuation and not as a decimal separator. The solution is to load the \courier{icomma\} package near the beginning of your file: \verbatim usepackage("icomma"); \endverbatim \question 11mar:hyperref How can I prevent \courier{texpreamble("\\usepackage[pdftex]{hyperref}")\} from changing the page size? \verbatim texpreamble("\usepackage[pdftex,setpagesize=false]{hyperref}"); \endverbatim \comment ##################################################################### \section Questions about arrows \question 02sep:doublearrows How do I draw two arrows at arbitrary positions along a path? Assuming that at least one of the arrowheads is to be filled, you can do this: \verbatim size(200); path g = (0,0)..(1,3)..(3,0); draw(g,Arrow(Relative(0.9))); add(arrow(g,invisible,FillDraw(black),Relative(0.5))); add(arrow(reverse(g),invisible,FillDraw(white,black),Relative(0.9))); \endverbatim If both of the arrowheads are to be drawn with filltype NoFill, one will need to create a specialized version of the arrow routine in \courier{plain_arrows.asy\}: \verbatim void arrow(frame f, arrowhead arrowhead=DefaultHead, path g, pen p=currentpen, real size=0, real angle=arrowangle, filltype filltype=arrowhead.defaultfilltype, position position=EndPoint, bool forwards=true, margin margin=NoMargin, bool center=false); \endverbatim \question 02sep:reversearrow How do I reverse the direction of an arrowhead? Simply reverse the direction of the path. \verbatim path g=((0,0)--(5cm,0)); draw(reverse(g),Arrow(Relative(0.55))); \endverbatim \question 02sep:reversearrow How do I change the size of all arrows? To override the arrowsize you can give every Arrow drawing attribute a real size argument. If you want to do this globally, you can override the pen-dependent arrowsize function like this: \verbatim DefaultHead.size=new real(pen p=currentpen) {return 2mm;}; \endverbatim \question 26jun:arrowhead Can I create other arrowhead styles? Yes, you can build custom arrowheads like this (see the predefined arrowhead styles in \courier{plain_arrows.asy\} for further examples): \verbatim arrowhead DotHead; DotHead.head=new path(path g, position position=EndPoint, pen p=currentpen, real size=0, real angle=arrowangle) { if(size == 0) size=DotHead.size(p); bool relative=position.relative; real position=position.position.x; if(relative) position=reltime(g,position); path r=subpath(g,position,0); pair x=point(r,0); real t=arctime(r,size); pair y=point(r,t); return circle(0.5(x+y),0.5size); }; size(100); draw((0,0)..(1,1)..(2,0),Arrow(DotHead)); dot((2,0),red); \endverbatim If you submit your alternate arrowheads to the Forum or the Patch Tracking System, we'll consider including them in a future release. \comment ##################################################################### \section Questions about 2D graphs \question 02sep:axisticks How can I draw x axis ticks on the right side, with the tick labels on the left side (relative to the axis path)? \verbatim import graph; size(250,200,IgnoreAspect); draw(graph(exp,-1,1),red); xaxis("$x$",RightTicks(Label(align=left))); yaxis("$y$",RightTicks); \endverbatim \question 02sep:axislabel How can I reposition the x axis label to three-quarters along the axis length? \verbatim import graph; size(250,200,IgnoreAspect); draw(graph(exp,-1,1),red); xaxis(Label("$x$",0.75),LeftTicks); yaxis("$y$",RightTicks); \endverbatim \question 02sep:axislabeldown How can I move the x axis label down 10bp? \verbatim import graph; size(250,200,IgnoreAspect); draw(graph(exp,-1,1),red); xaxis(shift(0,-10)*"$x$",LeftTicks); yaxis("$y$",RightTicks); \endverbatim \question 02sep:threeaxispens Can I use different pens for the axis, the axis label, and the tick labels? Yes: \verbatim import graph; size(300,200,IgnoreAspect); xlimits(-50,50); ylimits(0,100); xaxis(Label("$x$",MidPoint,red),Bottom,blue,LeftTicks(green)); yaxis("$y$",Left,RightTicks); \endverbatim \question 02sep:axislabelfont How can I change the font type of the axes label? \verbatim import graph; size(300,200,IgnoreAspect); xlimits(-50,50); ylimits(0,100); xaxis("x",Bottom,Courier("m","n"),LeftTicks); yaxis("$y$",Left,RightTicks); \endverbatim \question 02sep:axisticklabelfont How can I change the font type of the tick labels on an axis? Tick labels are by default typeset in (TeX) math mode, so to use other fonts you need to override the default tick format: \verbatim import graph; size(300,200,IgnoreAspect); xlimits(-50,50); ylimits(0,100); xaxis("$x$",Bottom,LeftTicks("%.4g",Courier("m","n")+fontsize(12))); yaxis("$y$",Left,RightTicks); \endverbatim \question 26jun:overlappingticklabels How can I prevent axes tick labels from rendering on top of each other? Either: (i) give LeftTicks/RightTicks/Ticks the arguments beginlabel=false and/or endlabel=false; (ii) explicitly remove specific ticks and their labels (drawing them manually; see \docref{http://www.github.com/vectorgraphics/asymptote/base/graph.asy\} for the definition of NoZero): \verbatim import graph; size(10cm); real f(real x) {return x^2;} draw(graph(f,-2,2)); xaxis(Ticks(NoZero)); yaxis(Ticks(NoZero)); label("$0$",(0,0),SW); \endverbatim (iii) explicitly remove specific tick labels and draw them manually (see \docref{http://www.github.com/vectorgraphics/asymptote/base/graph.asy\} for the definition of NoZeroFormat): \verbatim import graph; size(10cm); real f(real x) {return x^2;} draw(graph(f,-2,2)); xaxis(Ticks(NoZeroFormat)); yaxis(Ticks(NoZeroFormat)); label("$0$",(0,0),SW); \endverbatim (iv) use the xasy GUI to move overlapping labels; (v) change the Label argument of LeftTicks, RightTicks, or Ticks to: \verbatim Label(currentpen+overwrite(Move)) \endverbatim Solution (v) will move labels that might otherwise overwrite a previous label. Other possible overwrite arguments are Allow (allows overlapping labels; the default), Suppress (an overlapping label will not be written at all), SuppressQuiet, and MoveQuiet. The last two achieve the same result as the non-quiet types, but will not notify you which labels are overlapping. See: \docref{http://asymptote.sourceforge.net/doc/Pens.html\}. In the case of a user-specified tick array, you can change which labels get suppressed/moved by changing the order of array entries. \question 04nov:fixedsizegraphs How do I make the plot region of a graph, ignoring labels and legends, have a fixed size? Either: i) Specify an explicit unitsize, which overrides any call to \courier{size\}: \verbatim unitsize(x=1cm,y=2cm); \endverbatim ii) Explicitly tell Asymptote to map the plot region to a specific size: \verbatim import graph; real[] x={0,1,2,3}; real[] y=x^2; draw(graph(x,y),red); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks); size(5cm,5cm,point(SW),point(NE)); label("$f_\mathrm{T}$",point(N),2N); \endverbatim iii) Specify the points in user coordinates that should correspond to a given picture size: \verbatim import graph; size(250,200,IgnoreAspect); draw(graph(exp,-1,1),red); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks); fixedscaling((-1.5,-0.5),(1.5,3.5)); \endverbatim In this example, the user coordinate \courier{(-1.5,-0.5)\} will end up being the lower left corner of the figure and \courier{(1.5,3.5)\} will be the upper right corner. You can use this option to ensure multiple figures have the same scaling and same resulting figure size (just ensure the two coordinates given to \courier{fixedscaling()\} leaves room for any labels). See also \docref{http://asymptote.sourceforge.net/doc/Frames-and-pictures.html\}. \question 26jun:graphlimits How can I plot a function f(x) within [0,1]x[0,2] without explicitly calculating the x values for which f(x) hits the boundary? Call \courier{limits\} with the \courier{Crop\} option before drawing the graph: \verbatim import graph; size(250,200,IgnoreAspect); draw(graph(exp,-1,1),red); limits((0,0),(1,2),Crop); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks); \endverbatim See also \docref{http://asymptote.sourceforge.net/doc/graph.html\}. \question 26jun:custompalettes Is it possible to define customized palettes? Yes, you may generate your own pen[] array. For example: \verbatim int NColors=32768; pen[] MyPalette=new pen[NColors]; real step=1/(NColors-1.0); // Start at black: rgb(0,0,0) // End at yellow: rgb(1,1,0) for(int i=0; i < NColors; ++i) { real rgval=i*step; MyPalette[i]=rgb(rgval,rgval,0.0); } \endverbatim \question 26jun:factorial Is there an easy way to graph factorial functions nicely? The example below shows a continuous function and two methods for placing markers at integer values of x: \verbatim import graph; size(200,200,IgnoreAspect); real factorial(real t) {return gamma(t+1);} scale(Linear,Log); // Graph the factorial function. draw(graph(factorial,0,10)); // Method 1: Draw nodes, but hide line pair F(int t) {return (t,factorial(t));} // Graph of factorial function from 0 to 10 pair[] z=sequence(F,11); draw(graph(z),invisible,marker(scale(0.8mm)*unitcircle,blue,Fill)); // Method 2: Nongraphing routines require explicit scaling: pair dotloc(int t) {return Scale(F(t));} pair[] dotlocs=sequence(dotloc,11); dot(dotlocs); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks); \endverbatim \question 26jun:length How do I indicate that a certain length should be exactly the size I prescribe with no rescaling, within a picture which has its own size? Here's an easy way to do this. \verbatim size(12cm,0); void distance(picture pic=currentpicture, pair A, pair B, Label L="", real n=0, pen p=currentpen) { real d=3mm; path g=A--B; transform T=shift(-n*d*unit(B-A)*I); pic.add(new void(frame f, transform t) { picture opic; path G=T*t*g; draw(opic,Label(L,Center,UnFill(1)),G,p,Arrows(NoFill),Bars,PenMargins); add(f,opic.fit()); }); pic.addBox(min(g),max(g),T*min(p),T*max(p)); } pair A=(0,0), B=(3,3); dot(A); dot(B); distance(A,B,"$\ell$",1); \endverbatim \question 26jun:log2 How can I make the y axis display base-2 logarithmic values? See the example \docref{http://asymptote.sourceforge.net/gallery/2D graphs/log2graph.asy\}. \question 27jun:align How can I align the x axes of two graphs on the same figure? An easy way to do this, if the axes to be aligned have the same scaling and size, is illustrated in the example \docref{http://asymptote.sourceforge.net/gallery/2D graphs/alignedaxis.asy\}. Here is a more general solution to the problem of aligning two arbitrary axes. One fits the second picture to a frame based on the horizontal scaling for the first picture: \verbatim import graph; real width=15cm; real aspect=0.3; picture pic1,pic2; size(pic1,width,aspect*width,IgnoreAspect); size(pic2,width,aspect*width,IgnoreAspect); scale(pic1,false); scale(pic2,false); real xmin1=6; real xmax1=9; real xmin2=8; real xmax2=16; real a1=1; real a2=0.001; real f1(real x) {return a1*sin(x/2*pi);} real f2(real x) {return a2*sin(x/4*pi);} draw(pic1,graph(pic1,f1,xmin1,xmax1)); draw(pic2,graph(pic2,f2,xmin2,xmax2)); xaxis(pic1,Bottom,LeftTicks()); yaxis(pic1,"$f_1(x)$",Left,RightTicks); xaxis(pic2,"$x$",Bottom,LeftTicks(Step=4)); yaxis(pic2,"$f_2(x)$",Left,RightTicks); yequals(pic1,0,Dotted); yequals(pic2,0,Dotted); pair min1=point(pic1,SW); pair max1=point(pic1,NE); pair min2=point(pic2,SW); pair max2=point(pic2,NE); real scale=(max1.x-min1.x)/(max2.x-min2.x); real shift=min1.x/scale-min2.x; transform t1=pic1.calculateTransform(); transform t2=pic2.calculateTransform(); transform T=xscale(scale*t1.xx)*yscale(t2.yy); add(pic1.fit()); real height=truepoint(N,user=false).y-truepoint(S,user=false).y; add(shift(0,-height)*(shift(shift)*pic2).fit(T)); \endverbatim \question 27jun:changeaxis How can I change the direction of the y-axis, such that negatives values are on the upper y-axis? Here is a simple example (see also the example \docref{http://asymptote.sourceforge.net/gallery/2D graphs/diatom.asy\} or the discussion of Linear(-1) in the documentation): \verbatim import graph; size(250,200,IgnoreAspect); scale(Linear,Linear(-1)); draw(graph(log,0.1,10),red); xaxis("$x$",LeftTicks); yaxis("$y$",RightTicks); \endverbatim \question 27jun:functioncolor How can I fill a path with a function that defines the color of each location? Use \courier{functionshade\} with a PDF tex engine, as illustrated by the example {functionshading.asy}. If you want to produce PostScript output, an approximate solution for now would be to superimpose a fine grid and specify colors to \courier{latticeshade\} that depend on position as a single pen[][] lattice. Alternatively, it may be more efficient to use \courier{tensorshade}. \question 27jun:nonexplicitfun Is there a way to draw a function that is not explicitly given, such as (y - 2)^2 = x - 1 ? Yes, use the parametric form \verbatim y=t x=(t-2)^2+1 \endverbatim See the example \docref{http://asymptote.sourceforge.net/gallery/2D graphs/parametricgraph.asy\}. \question 27jun:scalesecondaryaxis Is it possible to reverse or stretch an axis? The real scaling argument to Linear is used to stretch (or reverse) the axis. To see the effect of axis stretching, be sure not to specify IgnoreAspect in the picture size command. A secondary axis has the same length as the primary axis, so stretching cannot have any effect. But one can still reverse the axis, with Linear(-1). \question 02sep:emptymarkers Why can't I use the UnFill option to draw graphs with empty markers? UnFill won't work here because it only affects the local frame the markers are initially drawn on, before being added to currentpicture. Here is a way of achieving the desired effect (assuming a white background): \verbatim import graph; size(10cm,0); pair[] z={(0,0),(0.5,0.5),(1,1)}; path g=graph(z); draw(shift(0,.5)*g,marker(scale(5)*unitcircle,FillDraw(white))); xaxis(BottomTop,LeftTicks); yaxis(LeftRight,RightTicks); \endverbatim \question 02sep:paletterange How can I force several images to use the same palette range (e.g. the entire 0-255 grayscale range)? The palette color space corresponds to a range of values specified by the argument range, which can be \courier{Full\}, \courier{Automatic\} or an explicit range \courier{Range(pair min, pair max)\}. Here \courier{Full} specifies a range varying from the minimum to maximum values of the function over the sampling interval, while \courier{Automatic\} selects "nice" limits. \comment ##################################################################### \section Questions about programming \question 27jun:comporint Is Asymptote an interpreter or a compiler? Asymptote compiles Asymptote commands into its own virtual machine code. It then runs this pseudocode on a virtual machine to produce PostScript code. \question 05sep:framepicture What is the difference between a frame and a picture? Frames are canvases for drawing in PostScript coordinates. While working with frames directly is occasionally necessary for constructing deferred drawing routines, pictures are usually more convenient to work with. See \qref unitsizes. \question 05sep:pathguide What is the difference between a path and a guide? A path is a cubic spline with fixed endpoint conditions. A guide is an unresolved cubic spline (list of cubic-spline nodes and control points). A guide is like a path except that the computation of the cubic spline is deferred until drawing time (when it is resolved into a path); this allows two guides with free endpoint conditions to be joined together smoothly. \question 27jun:picarray What is a convenient way to declare and initialize an array of pictures? You could write yourself a routine such as: \verbatim picture[] picture(int n) { picture[] pic; for(int i=0; i < n; ++i) { pic[i]=new picture; size(pic[i],19cm,0); } return pic; } picture[] pic=picture(6); \endverbatim \question 27jun:genarrays Is there a way to define functions that act on arrays in general (i.e. work for arrays of any type)? Generic types aren't yet implemented. But for now you can at least say \verbatim typedef string T; include F; typedef real T; include F; \endverbatim where \courier{F.asy\} contains some type-dependent code like \verbatim T[] operator $(T A, T B) {return new T[] {A,B};} \endverbatim \question 27jun:cirdep Is there any way to declare structures ahead of their definition, e.g. where struct A performs some operation on struct B, but B contains an A member? Asymptote does not support forward declaration of types. You can, however, nest structures, so that both types are visible for parts of the bodies of both structure definitions. For example: \verbatim struct B { typedef void someroutine(B b); static struct A { someroutine routine; void operator init(someroutine routine) { this.routine=routine; } } string test="Testing"; } typedef B.A A; A a=B.A(new void(B b){write(b.test);}); B b; a.routine(b); \endverbatim \question 04nov:static Where are static variables in for loops allocated? In the example \verbatim void f() { for(int i=0; i < 3; ++i) { static int n; ++n; write(n); } } f(); // Writes 1, 2, 3 \endverbatim the static qualifier means that \courier{n\} is allocated not just outside of the for loop, but also outside the function. This is clear if you call \courier{f\} multiple times; there is still only one instance of \courier{n\}. The "level" of a variable (where it is allocated) has nothing to do with the "scope" of a variable (how long it can be referred to by name). The curly braces enclosing a block affect only a variable's scope, not its level. Static modifiers are meaningless at the top level; they generate a warning and are simply ignored: \verbatim for(int i=0; i < 3; ++i) { static int n; ++n; write(n); } // Writes warning about top-level static modifier and then 1, 1, 1 \endverbatim Since version 1.22, non-static variables allocated in a loop body are allocated anew every iteration. This is only noticable in obscure cases where a variable in a loop is accessed in the closure of a function defined in the loop: \verbatim int f(); for(int i=0; i < 10; ++i) { int j=10*i; if(i == 5) f=new int() {return j;}; } write(f()); // Writes 50 \endverbatim Variables in the body of a loop last as long as that iteration of the loop, unless they are kept alive by a function closure as in the example above. In a function body, variables will last at least as long as the function call, though because of closures and garbage collection, they may last longer than that. If defined at the top level of a file or at the interactive prompt, they will last at least until the end of the file or prompt's run. \question 26jun:debug Is there a debugger for asy? Yes, Asymptote includes a line-based debugger: \docref{http://asymptote.sourceforge.net/doc/Debugger.html\} \question 27jun:patches Do you accept patches for Asymptote? Yes, in fact we would prefer that users submit patches for customized features (to \docref{http://sourceforge.net/tracker/?atid=685685&group_id=120000\}) instead of relying on us to do all of the coding. Development will proceed faster that way. \comment ##################################################################### \section Questions about differences between Asymptote and MetaPost \question 29jun:interp What is the equivalent of the MetaPost c[a,b] interpolation operator? \verbatim interp(a,b,c); \endverbatim \question 02sep:automaticscaling How does picture scaling differ in Asymptote and MetaPost? Asymptote includes an optional facility to do automatic scaling of pictures to achieve a given overall picture size, whereas Metapost only supports manual scaling. Asymptote defers drawing of objects drawn to pictures and distinguishes between true-size objects and objects that should scale with the picture size. The resulting linear programming problem is solved via the Simplex method. See the \docref{http://asymptote.sourceforge.net/gallery/dimension.asy\} example for an example of how deferred drawing is used to accomodate both user and true-size (PostScript) coordinates. \question 02sep:manualscaling How can I avoid automatic scaling of a picture? If you really like Metapost-style manual (hard-wired) scaling either: (i) use the default size(0,0) for the entire picture and do all of the scaling by hand, just like in MetaPost; (ii) draw to a separate picture pic and add(pic.fit()); (iii) use frames. \question 23jun:mp3dots What is the equivalent of MetaPost ... command? The connector \courier{::\} is a macro for tension atleast 1: \verbatim size(100); pair z0=(0,0); pair z1=(1,0.25); pair z2=(2,0); draw(z0{up}::z1{right}::z2{down}); \endverbatim \question 23jun:mppickup What is the equivalent of the MetaPost pickup command? Just say, for example: \verbatim currentpen=red; \endverbatim \question 29aug:whatever What is the equivalent of the MetaPost whatever command? Asymptote does not implicitly solve linear equations and therefore does not have the notion of a \courier{whatever\} unknown. Such a facility could certainly be added (perhaps using the notation \courier{?=\} since \courier{=\} means assignment). However, the most common uses of \courier{whatever\} in MetaPost are covered by functions like \courier{extension\} in \courier{math.asy\}: \verbatim pair extension(pair P, pair Q, pair p, pair q); \endverbatim this returns the intersection point of the extensions of the line segments \courier{PQ\} and \courier{pq\}. We find using routines like \courier{extension\} more explicit and less confusing to new users. But we could be persuaded to add something similar if someone can justify the need. In the meantime, one can always use the explicit built-in linear solver \courier{solve\} (see \docref{http://asymptote.sourceforge.net/doc/solve.html\}), which uses LU decomposition. \question 23jun:lray What is the equivalent for the MetaPost command for \courier{lray - horiz*v - verti*u = whatever*(LightSource - R)\}, a system of three linear equations for three unknowns: \courier{horiz, verti, whatever\}? Since \courier{horiz*v+verti*u\} spans a plane, you could use \verbatim real intersect(vector P, vector Q, vector n, vector Z); \endverbatim to find the intersection time for the line \courier{lray-whatever*(LightSource - R)\} and then extract the three desired values from there. (You'll still need to use the built-in explicit linear solver to solve a 2x2 system to get \courier{horiz\} and \courier{verti\}.) \question 27jun:unitsizes In MetaPost, it is possible to have a drawing remain the same size in different pictures by defining a unit \courier{u\} and explicitly multiply all the coordinates by \courier{u\}. Is there a better way to do this in Asymptote? Yes, Asymptote has a better way: you definitely don't want to manually scale all of your coordinates. To make the user coordinates represent multiples of exactly \courier{1cm\}: \verbatim unitsize(1cm); draw(unitsquare); \endverbatim One can also specify different x and y unit sizes: \verbatim unitsize(x=1cm,y=2cm); draw(unitsquare); \endverbatim Another way is to draw your fixed size object to a frame and add it to currentpicture like this: \verbatim path p=(0,0)--(1,0); frame object; draw(object,scale(100)*p); add(object); add(object,(0,-10)); \endverbatim To understand the difference between frames and pictures, try this: \verbatim size(300,300); path p=(0,0)--(1,0); picture object; draw(object,scale(100)*p); add(object); add(object,(0,-10)); // Adds truesize object to currentpicture \endverbatim \question 28jun:tiles In MetaPost, one could produce tiling pictures by generating a picture, and then clipping the picture to a rectangle of fixed dimensions around the center of the picture. How is that done in Asymptote? If you are using currentpicture the way one would in MetaPost (drawing in raw PostScript coordinates), you can simply do something like: \verbatim fill((0,0)--(100,100)--(200,0)--cycle); pair center(picture pic=currentpicture) {return 0.5*(pic.min()+pic.max());} real height=100; real width=100; pair delta=0.5(width,height); pair c=center(); clip(box(c-delta,c+delta)); \endverbatim However, drawing in PostScript coordinates is often inconvenient. Here's the Asymptote way of doing the same thing, using deferred drawing: \verbatim size(200,100); fill((0,0)--(1,1)--(2,0)--cycle); void clip(picture pic=currentpicture, real width, real height) { pic.clip(new void (frame f, transform) { pair center=0.5(min(f)+max(f)); pair delta=0.5(width,height); clip(f,box(center-delta,center+delta)); }); } clip(100,100); \endverbatim See also the discussion of tilings in the documentation: \docref{http://asymptote.sourceforge.net/doc/Pens.html\}. \comment ###################################################################### \section Questions about output \question 27jun:psviewer How can I disable automatic invocation of the PS viewer after an asy file is done processing? It's actually not on by default, unless you happen to be using Microsoft Windows (because that is what most Microsoft Windows users expect). Microsoft Windows users can turn this feature off with the command-line option -noV or by putting \verbatim import settings; interactiveView=false; batchView=false; \endverbatim in their \courier{config.asy\} file. See \docref{http://asymptote.sourceforge.net/doc/Options.html\}. \question 26jun:jpeg How do I output jpeg images? If you have the ImageMagick convert program installed, simply type \verbatim asy -f jpg test.asy \endverbatim \question 27jun:embedbitmaps Can I embed bitmaps (photos) into my drawings and position and scale them? Convert them to eps format and use the graphic(string) function just like a Label: \verbatim label(graphic("file"),(0,0)); \endverbatim See the example \docref{http://asymptote.sourceforge.net/gallery/orthocenter.asy\} and \docref{http://asymptote.sourceforge.net/doc/label.html\}. \question 28jun:directpdf Does Asymptote support direct PDF output? Yes, PDF output can be produced by the -f pdf option or -tex pdflatex option. This supports transparency, annotations, embedded movies, and U3D/PRC content. \question 28jun:bigpictures How to I produce large pictures of high quality in raster format (e.g. png, giff etc). Try using some of the options to convert, mainly -geometry and -density. For example: \verbatim convert -geometry 1000x3000 example.eps example.png \endverbatim You can also change the default resolution of the image with: \verbatim convert -geometry 1000x3000 -density 300 -units PixelsPerInch example.eps example.png \endverbatim This does not change the number of pixels in the image, but just gives a hint as to how large each pixel should be displayed. If you include the -density option without the -geometry option, convert will keep the image size constant (so a 4cm x 3cm eps figure will generate a 4cm x 3cm png image). \question 28jun:multipage Is it possible to produce multi-page documents with asymptote? Yes, simply call the newpage() function. This is used by the \courier{slide.asy\} package to produce high-quality slide presentations (easier to use than Prosper). \comment Here it ends! asymptote-2.37/doc/FAQ/bfnnconv.pl000077500000000000000000000217601265434602500170340ustar00rootroot00000000000000#!/usr/bin/perl -- # Copyright (C) 1993-1995 Ian Jackson. # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # It is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with GNU Emacs; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # (Note: I do not consider works produced using these BFNN processing # tools to be derivative works of the tools, so they are NOT covered # by the GPL. However, I would appreciate it if you credited me if # appropriate in any documents you format using BFNN.) @outputs=('ascii','info','html'); while ($ARGV[0] =~ m/^\-/) { $_= shift(@ARGV); if (m/^-only/) { @outputs= (shift(@ARGV)); } else { warn "unknown option `$_' ignored"; } } $prefix= $ARGV[0]; $prefix= 'stdin' unless length($prefix); $prefix =~ s/\.bfnn$//; if (open(O,"$prefix.xrefdb")) { @xrefdb= ; close(O); } else { warn "no $prefix.xrefdb ($!)"; } $section= -1; for $thisxr (@xrefdb) { $_= $thisxr; chop; if (m/^Q (\w+) ((\d+)\.(\d+)) (.*)$/) { $qrefn{$1}= $2; $qreft{$1}= $5; $qn2ref{$3,$4}= $1; $maxsection= $3; $maxquestion[$3]= $4; } elsif (m/^S (\d+) /) { $maxsection= $1; $sn2title{$1}=$'; } } open(U,">$prefix.xrefdb-new"); for $x (@outputs) { require("m-$x.pl"); } &call('init'); while (<>) { chop; next if m/^\\comment\b/; if (!m/\S/) { &call('endpara'); next; } if (s/^\\section +//) { $line= $_; $section++; $question=0; print U "S $section $line\n"; $|=1; print "S$section",' 'x10,"\r"; $|=0; &call('endpara'); &call('startmajorheading',"$section", "Section $section", $section<$maxsection ? "Section ".($section+1) : '', $section>1 ? 'Section '.($section-1) : 'Top'); &text($line); &call('endmajorheading'); if ($section) { &call('endpara'); &call('startindex'); for $thisxr (@xrefdb) { $_= $thisxr; chop; if (m/^Q (\w+) (\d+)\.(\d+) (.*)$/) { $ref= $1; $num1= $2; $num2= $3; $text= $4; next unless $num1 == $section; &call('startindexitem',$ref,"Q$num1.$num2","Question $num1.$num2"); &text($text); &call('endindexitem'); } } &call('endindex'); } } elsif (s/^\\question \d{2}[a-z]{3}((:\w+)?) +//) { $line= $_; $question++; $qrefstring= $1; $qrefstring= "q_${section}_$question" unless $qrefstring =~ s/^://; print U "Q $qrefstring $section.$question $line\n"; $|=1; print "Q$section.$question",' 'x10,"\r"; $|=0; &call('endpara'); &call('startminorheading',$qrefstring, "Question $section.$question", $question < $maxquestion[$section] ? "Question $section.".($question+1) : $section < $maxsection ? "Question ".($section+1).".1" : '', $question > 1 ? "Question $section.".($question-1) : $section > 1 ? "Question ".($section-1).'.'.($maxquestion[$section-1]) : 'Top', "Section $section"); &text("Question $section.$question. $line"); &call('endminorheading'); } elsif (s/^\\only +//) { @saveoutputs= @outputs; @outputs=(); for $x (split(/\s+/,$_)) { push(@outputs,$x) if grep($x eq $_, @saveoutputs); } } elsif (s/^\\endonly$//) { @outputs= @saveoutputs; } elsif (s/^\\copyto +//) { $fh= $'; while(<>) { last if m/^\\endcopy$/; while (s/^([^\`]*)\`//) { print $fh $1; m/([^\\])\`/ || warn "`$_'"; $_= $'; $cmd= $`.$1; $it= `$cmd`; chop $it; print $fh $it; } print $fh $_; } } elsif (m/\\index$/) { &call('startindex'); for $thisxr (@xrefdb) { $_= $thisxr; chop; if (m/^Q (\w+) (\d+\.\d+) (.*)$/) { $ref= $1; $num= $2; $text= $3; &call('startindexitem',$ref,"Q$num","Question $num"); &text($text); &call('endindexitem'); } elsif (m/^S (\d+) (.*)$/) { $num= $1; $text= $2; next unless $num; &call('startindexmainitem',"s_$num", "Section $num.","Section $num"); &text($text); &call('endindexitem'); } else { warn $_; } } &call('endindex'); } elsif (m/^\\call-(\w+) +(\w+)\s*(.*)$/) { $fn= $1.'_'.$2; eval { &$fn($3); }; warn $@ if length($@); } elsif (m/^\\call +(\w+)\s*(.*)$/) { eval { &call($1,$2); }; warn $@ if length($@); } elsif (s/^\\set +(\w+)\s*//) { $svalue= $'; $svari= $1; eval("\$user_$svari=\$svalue"); $@ && warn "setting $svalue failed: $@\n"; } elsif (m/^\\verbatim$/) { &call('startverbatim'); while (<>) { chop; last if m/^\\endverbatim$/; &call('verbatim',$_); } &call('endverbatim'); } else { s/\.$/\. /; &text($_." "); } } print ' 'x25,"\r"; &call('finish'); rename("$prefix.xrefdb-new","$prefix.xrefdb") || warn "rename xrefdb: $!"; exit 0; sub text { local($in,$rhs,$word,$refn,$reft,$fn,$style); $in= "$holdover$_[0]"; $holdover= ''; while ($in =~ m/\\/) { #print STDERR ">$`##$'\n"; $rhs=$'; &call('text',$`); $_= $rhs; if (m/^\w+ $/) { $holdover= "\\$&"; $in= ''; } elsif (s/^fn\s+([^\s\\]*\w)//) { $in= $_; $word= $1; &call('courier'); &call('text',$word); &call('endcourier'); } elsif (s/^tab\s+(\d+)\s+//) { $in= $_; &call('tab',$1); } elsif (s/^nl\s+//) { $in= $_; &call('newline'); } elsif (s/^qref\s+(\w+)//) { $refn= $qrefn{$1}; $reft= $qreft{$1}; if (!length($refn)) { warn "unknown question `$1'"; } $in= "$`\\pageref:$1:$refn:$reft\\endpageref.$_"; } elsif (s/^pageref:(\w+):([^:\n]+)://) { $in= $_; &call('pageref',$1,$2); } elsif (s/^endpageref\.//) { $in= $_; &call('endpageref'); } elsif (s/^(\w+)\{//) { $in= $_; $fn= $1; eval { &call("$fn"); }; if (length($@)) { warn $@; $fn= 'x'; } push(@styles,$fn); } elsif (s/^\}//) { $in= $_; $fn= pop(@styles); if ($fn ne 'x') { &call("end$fn"); } } elsif (s/^\\//) { $in= $_; &call('text',"\\"); } elsif (s,^(\w+)\s+([-A-Za-z0-9.\@:/]*\w),,) { #print STDERR "**$&**$_\n"; $in= $_; $style=$1; $word= $2; &call($style); &call('text',$word); &call("end$style"); } else { warn "unknown control `\\$_'"; $in= $_; } } &call('text',$in); } sub call { local ($fnbase, @callargs) = @_; local ($coutput); for $coutput (@outputs) { if ($fnbase eq 'text' && eval("\@${coutput}_cmds")) { #print STDERR "special handling text (@callargs) for $coutput\n"; $evstrg= "\$${coutput}_args[\$#${coutput}_args].=\"\@callargs\""; eval($evstrg); length($@) && warn "call adding for $coutput (($evstrg)): $@"; } else { $fntc= $coutput.'_'.$fnbase; &$fntc(@callargs); } } } sub recurse { local (@outputs) = $coutput; local ($holdover); &text($_[0]); } sub arg { #print STDERR "arg($_[0]) from $coutput\n"; $cmd= $_[0]; eval("push(\@${coutput}_cmds,\$cmd); push(\@${coutput}_args,'')"); length($@) && warn "arg setting up for $coutput: $@"; } sub endarg { #print STDERR "endarg($_[0]) from $coutput\n"; $evstrg= "\$${coutput}_cmd= \$cmd= pop(\@${coutput}_cmds); ". "\$${coutput}_arg= \$arg= pop(\@${coutput}_args); "; eval($evstrg); length($@) && warn "endarg extracting for $coutput (($evstrg)): $@"; #print STDERR ">call $coutput $cmd $arg< (($evstrg))\n"; $evstrg= "&${coutput}_do_${cmd}(\$arg)"; eval($evstrg); length($@) && warn "endarg running ${coutput}_do_${cmd} (($evstrg)): $@"; } asymptote-2.37/doc/FAQ/install-sh000077500000000000000000000325371265434602500166730ustar00rootroot00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2009-04-28.21; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then trap '(exit $?); exit' 1 2 13 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names starting with `-'. case $src in -*) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # Protect names starting with `-'. case $dst in -*) dst=./$dst;; esac # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writeable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; -*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test -z "$d" && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: asymptote-2.37/doc/FAQ/m-ascii.pl000066400000000000000000000111561265434602500165400ustar00rootroot00000000000000## ASCII output # Copyright (C) 1993-1995 Ian Jackson. # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # It is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with GNU Emacs; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # (Note: I do not consider works produced using these BFNN processing # tools to be derivative works of the tools, so they are NOT covered # by the GPL. However, I would appreciate it if you credited me if # appropriate in any documents you format using BFNN.) sub ascii_init { open(ASCII,">$prefix.ascii"); } sub ascii_startmajorheading { print ASCII '='x79,"\n\n"; $ascii_status= 'h'; &ascii_text($_[0] ? "Section $_[0]. " : ''); } sub ascii_startminorheading { print ASCII '-'x79,"\n\n"; $ascii_status= 'h'; } sub ascii_italic { &ascii_text('*'); } sub ascii_enditalic { $ascii_para .= '*'; } sub ascii_email { &ascii_text('<'); } sub ascii_endemail { &ascii_text('>'); } sub ascii_ftpon { } sub ascii_endftpon { } sub ascii_ftpin { } sub ascii_endftpin { } sub ascii_docref { } sub ascii_enddocref { } sub ascii_courier { } sub ascii_endcourier { } sub ascii_newsgroup { } sub ascii_endnewsgroup { } sub ascii_ftpsilent { $ascii_ignore++; } sub ascii_endftpsilent { $ascii_ignore--; } sub ascii_text { return if $ascii_ignore; if ($ascii_status eq '') { $ascii_status= 'p'; } $ascii_para .= $_[0]; } sub ascii_tab { local ($n) = $_[0]-length($ascii_para); $ascii_para .= ' 'x$n if $n>0; } sub ascii_newline { return unless $ascii_status eq 'p'; &ascii_writepara; } sub ascii_writepara { local ($thisline, $thisword, $rest); for (;;) { last unless $ascii_para =~ m/\S/; $thisline= $ascii_indentstring; for (;;) { last unless $ascii_para =~ m/^(\s*\S+)/; unless (length($1) + length($thisline) < 75 || length($thisline) == length($ascii_indentstring)) { last; } $thisline .= $1; $ascii_para= $'; } $ascii_para =~ s/^\s*//; print ASCII $thisline,"\n"; $ascii_indentstring= $ascii_nextindent; last unless length($ascii_para); } $ascii_status= ''; $ascii_para= ''; } sub ascii_endpara { return unless $ascii_status eq 'p'; &ascii_writepara; print ASCII "\n"; } sub ascii_endheading { $ascii_para =~ s/\s*$//; print ASCII "$ascii_para\n\n"; $ascii_status= ''; $ascii_para= ''; } sub ascii_endmajorheading { &ascii_endheading(@_); } sub ascii_endminorheading { &ascii_endheading(@_); } sub ascii_startverbatim { $ascii_vstatus= $ascii_status; &ascii_writepara; } sub ascii_verbatim { print ASCII $_[0],"\n"; } sub ascii_endverbatim { $ascii_status= $ascii_vstatus; } sub ascii_finish { close(ASCII); } sub ascii_startindex { $ascii_status= ''; } sub ascii_endindex { $ascii_status= 'p'; } sub ascii_endindexitem { printf ASCII " %-11s %-.66s\n",$ascii_left,$ascii_para; $ascii_status= 'p'; $ascii_para= ''; } sub ascii_startindexitem { $ascii_left= $_[1]; } sub ascii_startindexmainitem { $ascii_left= $_[1]; print ASCII "\n" if $ascii_status eq 'p'; } sub ascii_startindent { $ascii_istatus= $ascii_status; &ascii_writepara; $ascii_indentstring= " $ascii_indentstring"; $ascii_nextindent= " $ascii_nextindent"; } sub ascii_endindent { $ascii_indentstring =~ s/^ //; $ascii_nextindent =~ s/^ //; $ascii_status= $ascii_istatus; } sub ascii_startpackedlist { $ascii_plc=0; } sub ascii_endpackedlist { &ascii_newline if !$ascii_plc; } sub ascii_packeditem { &ascii_newline if !$ascii_plc; &ascii_tab($ascii_plc*40+5); $ascii_plc= !$ascii_plc; } sub ascii_startlist { &ascii_endpara; $ascii_indentstring= " $ascii_indentstring"; $ascii_nextindent= " $ascii_nextindent"; } sub ascii_endlist { &ascii_endpara; $ascii_indentstring =~ s/^ //; $ascii_nextindent =~ s/^ //; } sub ascii_item { &ascii_newline; $ascii_indentstring =~ s/ $/* /; } sub ascii_pageref { &ascii_text("Q$_[1] \`"); } sub ascii_endpageref { &ascii_text("'"); } 1; asymptote-2.37/doc/FAQ/m-html.pl000066400000000000000000000227751265434602500164250ustar00rootroot00000000000000## HTML output # Copyright (C) 1993-1995 Ian Jackson. # Modified by John Bowman 02Sep06: simply docref usage # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # It is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with GNU Emacs; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # (Note: I do not consider works produced using these BFNN processing # tools to be derivative works of the tools, so they are NOT covered # by the GPL. However, I would appreciate it if you credited me if # appropriate in any documents you format using BFNN.) %saniarray= ('<','lt', '>','gt', '&','amp', '"','quot'); sub html_init { $html_prefix = './'.$prefix; $html_prefix =~ s:^\.//:/:; system('rm','-r',"$html_prefix.html"); system('mkdir',"$html_prefix.html"); open(HTML,">$html_prefix.html/index.html"); print HTML "\n"; print HTML "\n"; $html_needpara= -1; $html_end=''; chop($html_date=`date '+%d %B %Y'`); chop($html_year=`date '+%Y'`); } sub html_startup { print HTML < $user_title

$user_title

END &html_readrefs($_[0]); if (length($user_copyrightref)) { local ($refn) = $qrefn{$user_copyrightref}; if (!length($refn)) { warn "unknown question (copyright) `$user_copyrightref'"; } $refn =~ m/(\d+)\.(\d+)/; local ($s,$n) = ($1,$2); $html_copyrighthref= ($s == $html_sectionn)?'':"section$s.html"; $html_copyrighthref.= "#$qn2ref{$s,$n}"; } } sub html_close { print HTML $html_end,"
\n$user_author\n"; print HTML "- $html_date\n

\n"; print HTML "Extracted from $user_title,\n"; print HTML "" if length($html_copyrighthref); print HTML "Copyright © $html_year $user_copyholder."; print HTML "" if length($html_copyrighthref); print HTML "\n\n"; close(HTML); } sub html_startmajorheading { local ($ref, $this,$next,$back) = @_; local ($nextt,$backt); $this =~ s/^Section /section/; $html_sectionn= $ref; $next =~ s/^Section /section/ && ($nextt= $sn2title{$'}); $back =~ s/^Section /section/ ? ($backt= $sn2title{$'}) : ($back=''); if ($html_sectionn) { &html_close; open(HTML,">$html_prefix.html/$this.html"); print HTML "\n"; print HTML "\n"; $html_end= "
\n"; $html_end.= "Next: $nextt.
\n" if $next; $html_end.= "Back: $backt.
\n" if $back; $html_end.= ""; $html_end.= "Return to contents.

\n"; print HTML < $user_brieftitle - Section $html_sectionn END print HTML "" if $next; print HTML "" if $back; print HTML <

$user_brieftitle - Section $html_sectionn
END $html_needpara= -1; } else { print HTML "\n

\n"; $html_needpara=-1; } } sub html_endmajorheading { print HTML "\n

\n\n"; $html_needpara=-1; } sub html_startminorheading { local ($ref, $this) = @_; $html_needpara=0; $this =~ m/^Question (\d+)\.(\d+)/; local ($s,$n) = ($1,$2); print HTML "\n

\n"; } sub html_endminorheading { print HTML "\n

\n\n"; $html_needpara=-1; } sub html_newsgroup { &arg('newsgroup'); } sub html_endnewsgroup { &endarg('newsgroup'); } sub html_do_newsgroup { print HTML "$_[0]"; } sub html_email { &arg('email'); } sub html_endemail { &endarg('email'); } sub html_do_email { print HTML "$_[0]"; } sub html_courier { print HTML "" ; } sub html_endcourier { print HTML ""; } sub html_italic { print HTML "" ; } sub html_enditalic { print HTML "" ; } sub html_docref { &arg('docref'); } sub html_enddocref { &endarg('docref'); } sub html_do_docref { if (!defined($html_refval{$_[0]})) { # Modified by John Bowman 02Sep06: interpret the argument as an html reference # warn "undefined HTML reference $_[0]"; # $html_refval{$n}='UNDEFINED'; print HTML ""; } else { print HTML ""; } &recurse($_[0]); print HTML ""; } sub html_readrefs { local ($p); open(HTMLREFS,"<$_[0]") || (warn("failed to open HTML refs $_[0]: $!"),return); while() { next if m/^\\\s/; s/\s*\n$//; if (s/^\\prefix\s*//) { $p= $'; next; } elsif (s/^\s*(\S.*\S)\s*\\\s*//) { $_=$1; $v=$'; s/\\\\/\\/g; $html_refval{$_}= $p.$v; } else { warn("cannot understand line in HTML refs >$_<"); } } close(HTMLREFS); } sub html_ftpsilent { &arg('ftpsilent'); } sub html_endftpsilent { &endarg('ftpsilent'); } sub html_do_ftpsilent { if ($_[0] =~ m/:/) { $html_ftpsite= $`; $html_ftpdir= $'.'/'; } else { $html_ftpsite= $_[0]; $html_ftpdir= ''; } } sub html_ftpon { &arg('ftpon'); } sub html_endftpon { &endarg('ftpon'); } sub html_do_ftpon { #print STDERR "ftpon($_[0])\n"; $html_ftpsite= $_[0]; $html_ftpdir= ''; print HTML ""; &recurse($_[0]); print HTML ""; } sub html_ftpin { &arg('ftpin'); } sub html_endftpin { &endarg('ftpin'); } sub html_do_ftpin { #print STDERR "ftpin($_[0])\n"; print HTML ""; &recurse($_[0]); print HTML ""; } sub html_text { print HTML "\n

\n" if $html_needpara > 0; $html_needpara=0; $html_stuff= &html_sanitise($_[0]); while ($html_stuff =~ s/^(.{40,70}) //) { print HTML "$1\n"; } print HTML $html_stuff; } sub html_tab { $htmltabignore++ || warn "html tab ignored"; } sub html_newline { print HTML "
\n" ; } sub html_startverbatim { print HTML "

\n"   ;                       }
sub html_verbatim      { print HTML &html_sanitise($_[0]),"\n";         }
sub html_endverbatim   { print HTML "
\n" ; $html_needpara= -1; } sub html_endpara { $html_needpara || $html_needpara++; } sub html_finish { &html_close; } sub html_startindex { print HTML "
    \n"; } sub html_endindex { print HTML "

\n"; } sub html_startindexitem { local ($ref,$qval) = @_; $qval =~ m/Q(\d+)\.(\d+)/; local ($s,$n) = ($1,$2); print HTML "
  • Q$s.$n. "; $html_indexunhead=''; } sub html_startindexmainitem { local ($ref,$s) = @_; $s =~ m/\d+/; $s= $&; print HTML "

    " if ($s > 1); print HTML "
  • Section $s. "; $html_indexunhead=''; } sub html_endindexitem { print HTML "$html_indexunhead\n"; } sub html_startlist { print HTML "\n"; $html_itemend="
      "; } sub html_endlist { print HTML "$html_itemend\n
    \n"; $html_needpara=-1 } sub html_item { print HTML "$html_itemend\n
  • "; $html_itemend=""; $html_needpara=-1; } sub html_startpackedlist { print HTML "\n"; $html_itemend=""; } sub html_endpackedlist { print HTML "$html_itemend\n\n"; $html_needpara=-1; } sub html_packeditem { print HTML "$html_itemend\n
  • "; $html_itemend=""; $html_needpara=-1; } sub html_startindent { print HTML "
    \n"; } sub html_endindent { print HTML "
    \n"; } sub html_pageref { local ($ref,$sq) = @_; $sq =~ m/(\d+)\.(\d+)/; local ($s,$n) = ($1,$2); print HTML "Q$sq \`"; } sub html_endpageref { print HTML "'"; } sub html_sanitise { local ($in) = @_; local ($out); while ($in =~ m/[<>&"]/) { $out.= $`. '&'. $saniarray{$&}. ';'; $in=$'; } $out.= $in; $out; } 1; asymptote-2.37/doc/FAQ/m-info.pl000066400000000000000000000127731265434602500164110ustar00rootroot00000000000000## Info output # Copyright (C) 1993-1995 Ian Jackson. # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # It is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with GNU Emacs; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # (Note: I do not consider works produced using these BFNN processing # tools to be derivative works of the tools, so they are NOT covered # by the GPL. However, I would appreciate it if you credited me if # appropriate in any documents you format using BFNN.) sub info_init { open(INFO,">$prefix.info"); print INFO <'); } sub info_ftpon { } sub info_endftpon { } sub info_ftpin { } sub info_endftpin { } sub info_docref { } sub info_enddocref { } sub info_courier { } sub info_endcourier { } sub info_newsgroup { } sub info_endnewsgroup { } sub info_ftpsilent { $info_ignore++; } sub info_endftpsilent { $info_ignore--; } sub info_text { return if $info_ignore; if ($info_status eq '') { $info_status= 'p'; } $info_para .= $_[0]; } sub info_tab { local ($n) = $_[0]-length($info_para); $info_para .= ' 'x$n if $n>0; } sub info_newline { return unless $info_status eq 'p'; print INFO &info_writepara; } sub info_writepara { local ($thisline, $thisword, $rest, $output); for (;;) { last unless $info_para =~ m/\S/; $thisline= $info_indentstring; for (;;) { last unless $info_para =~ m/^(\s*\S+)/; unless (length($1) + length($thisline) < 75 || length($thisline) == length($info_indentstring)) { last; } $thisline .= $1; $info_para= $'; } $info_para =~ s/^\s*//; $output.= $thisline."\n"; $info_indentstring= $info_nextindent; last unless length($info_para); } $info_status= ''; $info_para= ''; return $output; } sub info_endpara { return unless $info_status eq 'p'; print INFO &info_writepara; print INFO "\n"; } sub info_endheading { $info_para =~ s/\s*$//; print INFO "$info_para\n\n"; $info_status= ''; $info_para= ''; } sub info_endmajorheading { &info_endheading(@_); } sub info_endminorheading { &info_endheading(@_); } sub info_startverbatim { print INFO &info_writepara; } sub info_verbatim { print INFO $_[0],"\n"; } sub info_endverbatim { $info_status= $info_vstatus; } sub info_finish { close(INFO); } sub info_startindex { &info_endpara; $info_moredetail= ''; $info_status= ''; } sub info_endindex { print INFO "$info_moredetail\n" if length($info_moredetail); } sub info_endindexitem { $info_indentstring= sprintf("* %-17s ",$info_label.'::'); $info_nextindent= ' 'x20; local ($txt); $txt= &info_writepara; if ($info_main) { print INFO $label.$txt; $txt =~ s/^.{20}//; $info_moredetail.= $txt; } else { $info_moredetail.= $label.$txt; } $info_indentstring= $info_nextindent= ''; $info_status='p'; } sub info_startindexitem { print INFO "* Menu:\n" if $info_status eq ''; $info_status= ''; $info_label= $_[2]; $info_main= 0; } sub info_startindexmainitem { print INFO "* Menu:\n" if $info_status eq ''; $info_label= $_[2]; $info_main= 1; $info_moredetail .= "\n$_[2], "; $info_status= ''; } sub info_startindent { $info_istatus= $info_status; print INFO &info_writepara; $info_indentstring= " $info_indentstring"; $info_nextindent= " $info_nextindent"; } sub info_endindent { $info_indentstring =~ s/^ //; $info_nextindent =~ s/^ //; $info_status= $info_istatus; } sub info_startpackedlist { $info_plc=0; } sub info_endpackedlist { &info_newline if !$info_plc; } sub info_packeditem { &info_newline if !$info_plc; &info_tab($info_plc*40+5); $info_plc= !$info_plc; } sub info_startlist { $info_istatus= $info_status; print INFO &info_writepara; $info_indentstring= " $info_indentstring"; $info_nextindent= " $info_nextindent"; } sub info_endlist { $info_indentstring =~ s/^ //; $info_nextindent =~ s/^ //; $info_status= $info_lstatus; } sub info_item { &info_newline; $info_indentstring =~ s/ $/* /; } sub info_pageref { &info_text("*Note Question $_[1]:: \`"); } sub info_endpageref { &info_text("'"); } 1; asymptote-2.37/doc/FAQ/m-lout.pl000066400000000000000000000137301265434602500164330ustar00rootroot00000000000000## Lout output # Copyright (C) 1993-1995 Ian Jackson. # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # It is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with GNU Emacs; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # (Note: I do not consider works produced using these BFNN processing # tools to be derivative works of the tools, so they are NOT covered # by the GPL. However, I would appreciate it if you credited me if # appropriate in any documents you format using BFNN.) sub lout_init { open(LOUT,">$prefix.lout"); chop($dprint= `date '+%d %B %Y'`); $dprint =~ s/^0//; } sub lout_startup { local ($lbs) = &lout_sanitise($user_brieftitle); print LOUT <0)*40+5); $lout_plc= !$lout_plc; } sub lout_startlist { &lout_endpara; print LOUT "\@RawIndentedList style {\@Bullet} indent {0.5i} gap {1.1vx}\n"; $lout_styles .= 'l'; $lout_status= ''; } sub lout_endlist { &lout_endpara; print LOUT "\@EndList\n\n"; $lout_styles =~ s/.$//; } sub lout_item { &lout_endpara; print LOUT "\@ListItem{"; $lout_styles.= 'I'; } sub lout_startindex { print LOUT "//0.0fe\n"; } sub lout_endindex { $lout_status='p'; } sub lout_startindexmainitem { $lout_marker= $_[0]; $lout_status= ''; print LOUT "//0.3vx Bold \@Font \@HAdjust { \@HContract { { $_[1] } |3cx {"; $lout_iiendheight= '1.00'; $lout_styles .= 'X'; } sub lout_startindexitem { $lout_marker= $_[0]; print LOUT "\@HAdjust { \@HContract { { $_[1] } |3cx {"; $lout_iiendheight= '0.95'; $lout_styles .= 'X'; } sub lout_endindexitem { print LOUT "} } |0c \@PageOf { $lout_marker } } //${lout_iiendheight}vx\n"; $lout_styles =~ s/.$//; } sub lout_email { &lout_courier; &lout_text('<'); } sub lout_endemail { &lout_text('>'); &lout_endcourier; } sub lout_ftpon { &lout_courier; } sub lout_endftpon { &lout_endcourier; } sub lout_ftpin { &lout_courier; } sub lout_endftpin { &lout_endcourier; } sub lout_docref { } sub lout_enddocref { } sub lout_ftpsilent { $lout_ignore++; } sub lout_endftpsilent { $lout_ignore--; } sub lout_newsgroup { &lout_courier; } sub lout_endnewsgroup { &lout_endcourier; } sub lout_text { return if $lout_ignore; $lout_status= 'p'; $_= &lout_sanitise($_[0]); s/ $/\n/ unless $lout_styles =~ m/[fhX]/; print LOUT $_; } sub lout_tab { local ($size) = $_[0]*0.5; print LOUT " |${size}ft "; } sub lout_newline { print LOUT " //1.0vx\n"; } sub lout_sanitise { local ($in) = @_; local ($out); $in= ' '.$in.' '; $out=''; while ($in =~ m/(\s)(\S*[\@\/|\\\"\^\&\{\}\#]\S*)(\s)/) { $out .= $`.$1; $in = $3.$'; $_= $2; s/[\\\"]/\\$&/g; $out .= '"'.$_.'"'; } $out .= $in; $out =~ s/^ //; $out =~ s/ $//; $out; } sub lout_endpara { return if $lout_status eq ''; if ($lout_styles eq '') { print LOUT "\@LP\n\n"; } elsif ($lout_styles =~ s/I$//) { print LOUT "}\n"; } $lout_status= ''; } sub lout_startverbatim { print LOUT "//0.4f\n\@RawIndentedDisplay lines \@Break". " { {0.7 1.0} \@Scale {Courier Bold} \@Font {\n"; } sub lout_verbatim { $_= $_[0]; s/^\s*//; print LOUT &lout_sanitise($_),"\n"; } sub lout_endverbatim { print LOUT "}\n}\n//0.4f\n"; } 1; asymptote-2.37/doc/FAQ/m-post.pl000066400000000000000000000107421265434602500164350ustar00rootroot00000000000000## POST output # Copyright (C) 1993-1995 Ian Jackson. # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # It is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with GNU Emacs; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # (Note: I do not consider works produced using these BFNN processing # tools to be derivative works of the tools, so they are NOT covered # by the GPL. However, I would appreciate it if you credited me if # appropriate in any documents you format using BFNN.) sub post_init { open(POST,">$prefix.post"); } sub post_startmajorheading { print POST '='x79,"\n\n"; $post_status= 'h'; &post_text($_[0] ? "Section $_[0]. " : ''); } sub post_startminorheading { print POST '-'x77,"\n\n"; $post_status= 'h'; } sub post_italic { &post_text('*'); } sub post_enditalic { $post_para .= '*'; } sub post_email { &post_text('<'); } sub post_endemail { &post_text('>'); } sub post_ftpon { } sub post_endftpon { } sub post_ftpin { } sub post_endftpin { } sub post_docref { } sub post_enddocref { } sub post_courier { } sub post_endcourier { } sub post_newsgroup { } sub post_endnewsgroup { } sub post_ftpsilent { $post_ignore++; } sub post_endftpsilent { $post_ignore--; } sub post_text { return if $post_ignore; if ($post_status eq '') { $post_status= 'p'; } $post_para .= $_[0]; } sub post_tab { local ($n) = $_[0]-length($post_para); $post_para .= ' 'x$n if $n>0; } sub post_newline { return unless $post_status eq 'p'; &post_writepara; } sub post_writepara { local ($thisline, $thisword, $rest); for (;;) { last unless $post_para =~ m/\S/; $thisline= $post_indentstring; for (;;) { last unless $post_para =~ m/^(\s*\S+)/; unless (length($1) + length($thisline) < 75 || length($thisline) == length($post_indentstring)) { last; } $thisline .= $1; $post_para= $'; } $post_para =~ s/^\s*//; print POST $thisline,"\n"; $post_indentstring= $post_nextindent; last unless length($post_para); } $post_status= ''; $post_para= ''; } sub post_endpara { return unless $post_status eq 'p'; &post_writepara; print POST "\n"; } sub post_endheading { $post_para =~ s/\s*$//; print POST "$post_para\n\n"; $post_status= ''; $post_para= ''; } sub post_endmajorheading { &post_endheading(@_); } sub post_endminorheading { &post_endheading(@_); } sub post_startverbatim { $post_vstatus= $post_status; &post_writepara; } sub post_verbatim { print POST $_[0],"\n"; } sub post_endverbatim { $post_status= $post_vstatus; } sub post_finish { close(POST); } sub post_startindex { $post_status= ''; } sub post_endindex { $post_status= 'p'; } sub post_endindexitem { printf POST " %-11s %-.66s\n",$post_left,$post_para; $post_status= 'p'; $post_para= ''; } sub post_startindexitem { $post_left= $_[1]; } sub post_startindexmainitem { $post_left= $_[1]; print POST "\n" if $post_status eq 'p'; } sub post_startindent { $post_istatus= $post_status; &post_writepara; $post_indentstring= " $post_indentstring"; $post_nextindent= " $post_nextindent"; } sub post_endindent { $post_indentstring =~ s/^ //; $post_nextindent =~ s/^ //; $post_status= $post_istatus; } sub post_startpackedlist { $post_plc=0; } sub post_endpackedlist { &post_newline if !$post_plc; } sub post_packeditem { &post_newline if !$post_plc; &post_tab($post_plc*40+5); $post_plc= !$post_plc; } sub post_startlist { &post_endpara; $post_indentstring= " $post_indentstring"; $post_nextindent= " $post_nextindent"; } sub post_endlist { &post_endpara; $post_indentstring =~ s/^ //; $post_nextindent =~ s/^ //; } sub post_item { &post_newline; $post_indentstring =~ s/ $/* /; } sub post_pageref { &post_text("Q$_[1] \`"); } sub post_endpageref { &post_text("'"); } 1; asymptote-2.37/doc/GaussianSurface.asy000066400000000000000000000007201265434602500200460ustar00rootroot00000000000000import graph3; size(200,0); currentprojection=perspective(10,8,4); real f(pair z) {return 0.5+exp(-abs(z)^2);} draw((-1,-1,0)--(1,-1,0)--(1,1,0)--(-1,1,0)--cycle); draw(arc(0.12Z,0.2,90,60,90,25),ArcArrow3); surface s=surface(f,(-1,-1),(1,1),nx=5,Spline); xaxis3(Label("$x$"),red,Arrow3); yaxis3(Label("$y$"),red,Arrow3); zaxis3(XYZero(extend=true),red,Arrow3); draw(s,lightgray,meshpen=black+thick(),nolight,render(merge=true)); label("$O$",O,-Z+Y,red); asymptote-2.37/doc/HermiteSpline.asy000066400000000000000000000005121265434602500175320ustar00rootroot00000000000000import graph; size(140mm,70mm,IgnoreAspect); scale(false); real[] x={1,3,4,5,6}; real[] y={1,5,2,0,4}; marker mark=marker(scale(1mm)*cross(6,false,r=0.35),red,Fill); draw(graph(x,y,Hermite),"Hermite Spline",mark); xaxis("$x$",Bottom,LeftTicks(x)); yaxis("$y$",Left,LeftTicks); attach(legend(),point(NW),40S+30E,UnFill); asymptote-2.37/doc/Hobbycontrol.asy000066400000000000000000000010111265434602500174210ustar00rootroot00000000000000size(200); pair z0=(0,0); pair z1=(0.5,3); pair z2=(2,1); path g=z0..z1..z2; pair d0=dir(g,0); pair d1=dir(g,1); draw(Label("$\omega_0$",1),z0-d0..z0+d0,blue+dashed,Arrow); draw(Label("$\omega_1$",1),z1-d1..z1+1.5d1,blue+dashed,Arrow); draw(z0--interp(z0,z1,1.5),dashed); draw(subpath(g,0,1),blue); draw("$\theta$",arc(z0,0.4,degrees(z1-z0),degrees(d0)),red,Arrow, EndPenMargin); draw("$\phi$",arc(z1,1.05,degrees(z1-z0),degrees(d1)),red,Arrow, EndPenMargin); dot("$z_0$",z0,SW,red); dot("$z_1$",z1,SE,red); asymptote-2.37/doc/Hobbydir.asy000066400000000000000000000007641265434602500165350ustar00rootroot00000000000000size(200); pair z0=(0,0); pair z1=(1,2); pair z2=(2,1); path g=z0..z1..z2; label("$\ell_k$",z0--z1); draw("$\ell_{k+1}$",z1--z2,dashed); draw(z0--interp(z0,z1,1.5),dashed); pair d1=dir(g,1); draw(z1-d1..z1+d1,blue+dashed); draw(g,blue); draw(Label("$\theta_k$",0.4),arc(z1,0.4,degrees(z2-z1),degrees(d1)),blue,Arrow, EndPenMargin); draw("$\phi_k$",arc(z1,0.4,degrees(d1),degrees(z1-z0),CCW),Arrow, EndPenMargin); dot("$z_{k-1}$",z0,red); dot("$z_k$",z1,NW,red); dot("$z_{k+1}$",z2,red); asymptote-2.37/doc/Makefile.in000066400000000000000000000061721265434602500163210ustar00rootroot00000000000000MANFILES = asy.1 xasy.1x ASYFILES = $(filter-out $(wildcard latexusage-*.asy),$(wildcard *.asy)) SOURCE = asymptote.texi version.texi options ASY = ../asy -dir ../base -config "" -render=0 DOCFILES = asymptote.pdf asy-latex.pdf CAD.pdf TeXShopAndAsymptote.pdf \ asyRefCard.pdf docdir = $(DESTDIR)@docdir@ infodir = $(DESTDIR)@infodir@ datarootdir = @datarootdir@ INSTALL = @INSTALL@ TEXI2DVI = @TEXI2DVI@ export docdir infodir INSTALL all: doc asy-latex.pdf: pdflatex asy-latex.dtx asymptote.sty: pdflatex asy-latex.dtx dvi: doc asymptote.dvi doc: $(DOCFILES) asy.1 faq latexusage.eps cd png && $(MAKE) all manpage: $(MANFILES) man: $(DOCFILES) manpage cd png && $(MAKE) asymptote.info faq: cd FAQ && $(MAKE) faq %.eps: %.asy $(ASY) -f eps $< %.pdf: %.asy $(ASY) -f pdf -noprc $< latexusage.dvi: latexusage.tex asymptote.sty rm -f latexusage-* rm -f latexusage.pre rm -f latexusage.aux latex latexusage $(ASY) -noprc latexusage-*.asy latex latexusage latexusage.eps: latexusage.dvi dvips -o latexusage.eps latexusage latexusage.pdf: latexusage.dvi dvipdf -P latexusage options: ../settings.cc $(ASY) -h 2>&1 | grep -iv Asymptote > options asy.1: options asy.1.begin asy.1.end cat options | grep \^- | \ sed -e "s/-\(.*\) \([a-zA-Z0-9].*\)/.TP\n.B -\1\n\2\./" | \ sed -e "/^.B/ s/-/\\\\-/g" | cat asy.1.begin - asy.1.end > asy.1 asymptote.dvi: $(SOURCE) $(ASYFILES:.asy=.eps) latexusage.pdf ln -sf asymptote.texi asymptote_.texi $(TEXI2DVI) asymptote_.texi mv asymptote_.dvi asymptote.dvi asymptote.pdf: $(SOURCE) $(ASYFILES:.asy=.pdf) latexusage.pdf $(TEXI2DVI) --pdf asymptote.texi CAD.pdf: CAD.tex CAD1.eps latex CAD latex CAD latex CAD dvipdf -P CAD TeXShopAndAsymptote.pdf: TeXShopAndAsymptote.tex latex TeXShopAndAsymptote latex TeXShopAndAsymptote dvipdf -P TeXShopAndAsymptote asyRefCard.pdf: asyRefCard.tex tex asyRefCard dvipdf -P asyRefCard clean: FORCE -rm -f asy-latex.{aux,idx,ins,log,toc} -rm -f $(ASYFILES:.asy=.pdf) -rm -f *.eps latexusage.{dvi,eps,pdf,log,aux,*.eps} latexusage-* \ latexusage.pre -rm -f \ {asymptote,asymptote_}.{aux,cp,cps,dvi,fn,info,ky,log,pg,toc,tp,vr} -rm -f asymptote_.texi -rm -f {CAD,TeXShopAndAsymptote,asyRefCard}.{aux,dvi,log,toc} -rm -f options asy.1 cd png && $(MAKE) clean install-man: ${INSTALL} -d -m 755 $(docdir) $(mandir)/man1 ${INSTALL} -p -m 644 $(DOCFILES) $(docdir) ${INSTALL} -p -m 644 $(MANFILES) $(mandir)/man1 install: man faq install-man cd png && $(MAKE) install cd FAQ && $(MAKE) install install-prebuilt: install-man options touch png/asymptote.info cd png && $(MAKE) install cd FAQ && $(MAKE) install-prebuilt install-all: $(DOCFILES) $(MANFILES) faq latexusage.eps install-man cd png && $(MAKE) install-all cd FAQ && $(MAKE) install-info uninstall: uninstall-all uninstall-all: cd png && $(MAKE) uninstall cd FAQ && $(MAKE) uninstall -cd $(mandir)/man1 && rm -f $(MANFILES) -rm -f $(addprefix $(docdir)/,$(DOCFILES)) distclean: FORCE clean -rm -f version.texi Makefile -rm -f $(DOCFILES) cd png && $(MAKE) distclean cd FAQ && $(MAKE) distclean FORCE: Makefile: Makefile.in cd ..; config.status asymptote-2.37/doc/TeXShopAndAsymptote.tex000066400000000000000000000051351265434602500206570ustar00rootroot00000000000000\documentclass[11pt]{article} \usepackage{geometry} \geometry{letterpaper} \usepackage[parfill]{parskip} \usepackage{graphicx} \usepackage{amssymb} \title{Integrating Asymptote and TeXShop for Mac OS X} \author{Vishaal Rajani \& Cole Zmurchok \\ University of Alberta} \date{\today} \begin{document} \maketitle \begin{enumerate} \item Download Asymptote and place the \emph{asymptote-x.xx.src.tgz} file on the desktop. \item Open Terminal and type the following. Note that you will have to enter the root password for the final command. \begin{verbatim} cd Desktop gunzip asymptote-x.xx.src.tgz tar -xf asymptote-x.xx.src.tar cd asymptote-x.xx ./configure make all sudo make install \end{verbatim} If you get an error at the \verb+./configure+ step, stating that you there is \verb+no acceptable C+ \verb+compiler found in $PATH+, a solution is to download and install Xcode here: \\ \verb+http://developer.apple.com/TOOLS/Xcode/+. \item We now create the engine that will typeset Asymptote in TeXShop. The easiest way to create this engine, which we will call \emph{asyEngine.engine}, is to navigate to \verb+~/Library/TeXShop/Engines+ and duplicate one of the existing \emph{.engine} files. Open the duplicate file and delete the code there. Type the following: \begin{verbatim} #!/bin/sh location=$(dirname "$1") basename="${1%.tex}" #process cd $location pdflatex "$1" asy "${basename}"-*.asy pdflatex "$1" \end{verbatim} Save this file as \emph{asyEngine.engine}. \item Now we set our engine to be executable. In the terminal, navigate to the Engines directory and type: \begin{verbatim} chmod +x asyEngine.engine \end{verbatim} \item Finally, in the terminal, type: \begin{verbatim} defaults write TeXShop OtherTeXExtensions -array-add "asy" \end{verbatim} This last command allows you choose the \emph{asyEngine} option from the drop-down menu when you wish to typeset a document that includes asymptote. \end{enumerate} Now, if you wish to typeset something simple, like the following red line, create a new document in TeXShop and type: \begin{verbatim} \documentclass[letterpaper,12pt]{article} \usepackage{amsmath} \usepackage{amssymb} \usepackage{asymptote} \begin{document} \begin{asy} size(300); draw((0,0)--(1,1),red); \end{asy} \end{document} \end{verbatim} Choose the \emph{asyEngine} option from the drop-down menu and press \emph{Typeset}. Your red line will be created in a PDF Document. On a final note, it is best to avoid using filenames with spaces in them. For example, avoid filenames such as \verb+asy test.tex+ and instead use filenames without spaces, such as \verb+asyTest.tex+. \end{document} asymptote-2.37/doc/asy-latex.dtx000066400000000000000000000433021265434602500167000ustar00rootroot00000000000000% \iffalse % %<*internal> \begingroup % %<*batchfile> \input docstrip.tex \keepsilent \preamble ____________________________ The ASYMPTOTE package (C) 2003 Tom Prince (C) 2003-2015 John Bowman (C) 2010 Will Robertson Adapted from comment.sty Licence: GPL2+ \endpreamble \nopostamble \askforoverwritefalse \generate{\file{asymptote.sty}{\from{\jobname.dtx}{pkg}}} % %\endbatchfile %<*internal> \generate{\file{\jobname.ins}{\from{\jobname.dtx}{batchfile}}} \edef\tmpa{plain} \ifx\tmpa\fmtname\endgroup\expandafter\bye\fi \endgroup \immediate\write18{makeindex -s gind.ist -o \jobname.ind \jobname.idx} \immediate\write18{makeindex -s gglo.ist -o \jobname.gls \jobname.glo} % % %<*driver> \ProvidesFile{asy-latex.dtx} % %\ProvidesPackage{asymptote} %<*pkg> [2015/05/10 v1.29 Asymptote style file for LaTeX] % % %<*driver> \documentclass{ltxdoc} \EnableCrossrefs \CodelineIndex \begin{document} \DocInput{\jobname.dtx} \end{document} % % \fi % % \GetFileInfo{asy-latex.dtx} % \title{The \textsf{asymptote} package} % \author{% % John Bowman, Tom Prince, and Will Robertson % } % \date{\filedate\qquad\fileversion} % \maketitle % \begin{abstract} % This package provides integration of inline and external Asymptote % graphics within a \LaTeX\ document. % \end{abstract} % % \tableofcontents % % \section{Introduction} % % This is the documentation for the \LaTeX\ package \texttt{asymptote} % which accompanies the Asymptote drawing package. For further details on % Asymptote, please see its documentation in \texttt{asymptote.pdf}. % % \section{User syntax} % % \subsection{Package loading and options} % % The package may take two options at load time: \texttt{inline} or % \texttt{attach}. % These options can also be set at any time with the % \cmd\asysetup\marg{options} command, or specified individually in the % optional argument to each \texttt{asy} environment or \texttt{asyinclude} % command. % % The \texttt{inline} option uses Asymptote's `inline' mode whereby % included graphics have their labels typeset in the environment of the % document they are contained within. Otherwise the Asymptote graphics are % self-contained and their formatting is independent of the document. % % The \texttt{attach} option allows generated graphics to be embedded % within the PDF using the \texttt{attachfile2} package; please load that % package separately if you wish to use it. The \texttt{attach} option % takes precedence over the \texttt{inline} option. % % This package produces quite a number of output files, which by default % are created in the same directory as the \LaTeX\ document that is being % compiled. To keep things more tidy, you can specify an output directory % for these files by defining the \cmd\asydir\ command. For example, if you % wish to store the figure files in the subdirectory \texttt{asytmp/}, the % you would write \verb|\renewcommand\asydir{asytmp}|. % % Alternatively (and tentatively), you may write \verb|dir=asytmp| in % either the \texttt{asy} environment options or the options to % \cmd\asysetup. % % \subsection{Commands for inserting Asymptote graphics} % % The main environment defined by the package is the \texttt{asy} % environment, in which verbatim Asymptote code is placed that will be % compiled for generating a graphic in the document. For example, % \begin{verbatim} % \begin{figure} % \begin{asy}[ ] % % \end{asy} % \caption{...}\label{...} % \end{verbatim} % % If you have Asymptote code in a separate file, you can include it with % the \cmd\asyinclude\oarg{options}\marg{filename}\ command. % % For Asymptote code that should be included in \emph{every} graphic, % define it using the \texttt{asydef} environment. % % \subsection{Graphics options} % % Both the \texttt{asy} environment and the \cmd\asyinclude\ command take % optional parameters for controlling aspects of the graphics creation. In % addition to locally setting \texttt{inline} and \texttt{attach}, the % following options may also be used: % \begin{description} % \item[width] Width of the figure % \item[height] Height of the figure % \item[keepAspect] Maintain aspect ratio [default true] % \item[viewportwidth] Viewport width for 3D figures % \item[viewportheight] Viewport height for 3D figures % \end{description} % These may also be set globally using the \cmd\asysetup\ command. % % \section{Processing the document} % % After running \LaTeX\ on the document, it is necessary to process the % Asymptote graphics so they can be included in the next compilation. The % simplest procedure is a recipe such as % \begin{verbatim} % pdflatex mydoc % asy mydoc-*.asy % pdflatex mydoc % \end{verbatim} % This technique will recompile each graphic every time, however. To only % recompile graphics that have changed, use the \texttt{latexmk} % tool. Asymptote is distributed with a \texttt{latexmkrc} configuration % file; place this file in a place where \texttt{latexmk} will find it and % your document may be compiled, including the \texttt{asy} compilations, % with \texttt{latexmk mydoc} or \texttt{latexmk --pdf mydoc}. % % \section{Implementation} % % \iffalse %<*pkg> % \fi % % \begin{macrocode} \def\Asymptote{{\tt Asymptote}} % \end{macrocode} % % \begin{macrocode} \InputIfFileExists{\jobname.pre}{}{} % \end{macrocode} % % \subsection{Allocations} % % \paragraph{Allocations} % % \begin{macrocode} \newbox\ASYbox \newcounter{asy} % \end{macrocode} % % \begin{macrocode} \newwrite\AsyStream \newwrite\AsyPreStream % \end{macrocode} % % \begin{macrocode} \newif\ifASYinline \newif\ifASYattach \newif\ifASYkeepAspect \ASYkeepAspecttrue % \end{macrocode} % % \subsection{Packages} % % \begin{macrocode} \RequirePackage{keyval} \RequirePackage{ifthen} \RequirePackage{color,graphicx} % \end{macrocode} % % \paragraph{Emulating packages} % We cannot assume that Asymptote users have recent % \TeX\ distributions. (E.g., Fedora until recently still shipped teTeX.) % So load \textsf{ifpdf} and \textsf{ifxetex} if they exist; otherwise, % emulate them. % % In due course, delete this code and just load the packages. % \begin{macrocode} \IfFileExists{ifpdf.sty}{ \RequirePackage{ifpdf} }{ \expandafter\newif\csname ifpdf\endcsname \ifx\pdfoutput\@undefined\else \ifcase\pdfoutput\else \pdftrue \fi \fi } % \end{macrocode} % % \begin{macrocode} \IfFileExists{ifxetex.sty}{ \RequirePackage{ifxetex} }{ \expandafter\newif\csname ifxetex\endcsname \ifx\XeTeXversion\@undefined\else \xetextrue \fi } % \end{macrocode} % % \begin{macro}{\CatchFileDef} % Used for \cmd\asyinclude. % Note that the fallback definition is not as robust as the one provided by catchfile. % \begin{macrocode} \IfFileExists{catchfile.sty}{ \RequirePackage{catchfile} }{ \newcommand\CatchFileDef[3]{% \begingroup \everyeof{% \ENDCATCHFILEMARKER \noexpand }% \long\def\@tempa####1\ENDCATCHFILEMARKER{% \endgroup \def##1{####1}% }% ##3% \expandafter\@tempa\@@input ##2\relax } } % \end{macrocode} % \end{macro} % % \paragraph{Ensuring attachfile2 is loaded if [attach] is requested} % \begin{macrocode} \newif\if@asy@attachfile@loaded % \end{macrocode} % % \begin{macrocode} \AtBeginDocument{% \@ifpackageloaded{attachfile2}{\@asy@attachfile@loadedtrue}{}% \let\asy@check@attachfile\asy@check@attachfile@loaded } % \end{macrocode} % % \begin{macrocode} \newcommand\asy@check@attachfile@loaded{% \if@asy@attachfile@loaded\else \PackageError{asymptote}{You must load the attachfile2 package}{^^J% You have requested the [attach] option for some or all of your^^J% Asymptote graphics, which requires the attachfile2 package.^^J% Please load it in the document preamble.^^J% }% \fi } % \end{macrocode} % % \begin{macrocode} \newcommand\asy@check@attachfile{% \AtBeginDocument{\asy@check@attachfile@loaded}% \let\asy@check@attachfile\@empty } % \end{macrocode} % % \paragraph{Macros} % \begin{macrocode} \def\csarg#1#2{\expandafter#1\csname#2\endcsname} % \end{macrocode} % % \subsection{Package options} % % \begin{macrocode} \DeclareOption{inline}{% \ASYinlinetrue } \DeclareOption{attach}{% \asy@check@attachfile \ASYattachtrue } \ProcessOptions* % \end{macrocode} % % \begin{macrocode} \def\asylatexdir{} \def\asydir{} \def\ASYasydir{} \def\ASYprefix{} % \end{macrocode} % % % \subsection{Testing for PDF output} % Note this is not quite the same as \cs{ifpdf}, since we still want PDF % output when using XeTeX. % \begin{macrocode} \newif\ifASYPDF \ifxetex \ASYPDFtrue \usepackage{everypage} \else \ifpdf \ASYPDFtrue \fi \fi \ifASYPDF \def\AsyExtension{pdf} \else \def\AsyExtension{eps} \fi % \end{macrocode} % % \subsection{Bug squashing} % % \begin{macrocode} \def\unquoteJobname#1"#2"#3\relax{% \def\rawJobname{#1}% \ifx\rawJobname\empty \def\rawJobname{#2}% \fi } \expandafter\unquoteJobname\jobname""\relax % \end{macrocode} % Work around jobname bug in MiKTeX 2.5 and 2.6: % Turn stars in file names (resulting from spaces, etc.) into minus signs % \begin{macrocode} \def\fixstar#1*#2\relax{% \def\argtwo{#2}% \ifx\argtwo\empty \gdef\Jobname{#1}% \else \fixstar#1-#2\relax \fi } \expandafter\fixstar\rawJobname*\relax % \end{macrocode} % % Work around bug in dvips.def: allow spaces in file names. % \begin{macrocode} \def\Ginclude@eps#1{% \message{<#1>}% \bgroup \def\@tempa{!}% \dimen@\Gin@req@width \dimen@ii.1bp\relax \divide\dimen@\dimen@ii \@tempdima\Gin@req@height \divide\@tempdima\dimen@ii \special{PSfile=#1\space llx=\Gin@llx\space lly=\Gin@lly\space urx=\Gin@urx\space ury=\Gin@ury\space \ifx\Gin@scalex\@tempa\else rwi=\number\dimen@\space\fi \ifx\Gin@scaley\@tempa\else rhi=\number\@tempdima\space\fi \ifGin@clip clip\fi}% \egroup } % \end{macrocode} % % \subsection{Input/Output} % % \begin{macrocode} \immediate\openout\AsyPreStream=\jobname.pre\relax \AtEndDocument{\immediate\closeout\AsyPreStream} % \end{macrocode} % % \begin{macrocode} \def\WriteAsyLine#1{% \immediate\write\AsyStream{\detokenize{#1}}% } % \end{macrocode} % % \begin{macrocode} \def\globalASYdefs{} \def\WriteGlobalAsyLine#1{% \expandafter\g@addto@macro \expandafter\globalASYdefs \expandafter{\detokenize{#1^^J}}% } % \end{macrocode} % % \subsection{Commands for verbatim processing environments} % % \begin{macrocode} \def\ProcessAsymptote#1{% \begingroup \def\CurrentAsymptote{#1}% \let\do\@makeother \dospecials \@makeother\^^L% and whatever other special cases \catcode`\ =10 \endlinechar`\^^M \catcode`\^^M=12 \xAsymptote } % \end{macrocode} % Need lots of comment chars here because \meta{line end} is no longer a % space character. % \begin{macrocode} \begingroup \catcode`\^^M=12 \endlinechar=-1\relax% \gdef\xAsymptote{% \expandafter\ProcessAsymptoteLine% } \gdef\ProcessAsymptoteLine#1^^M{% \def\@tempa{#1}% {% \escapechar=-1\relax% \xdef\@tempb{\string\\end\string\{\CurrentAsymptote\string\}}% }% \ifx\@tempa\@tempb% \edef\next{\endgroup\noexpand\end{\CurrentAsymptote}}% \else% \ThisAsymptote{#1}% \let\next\ProcessAsymptoteLine% \fi% \next% } \endgroup \def\asy@init{ \def\ASYlatexdir{} \ifx\asylatexdir\empty\else \def\ASYlatexdir{\asylatexdir/}% \fi \ifx\asydir\empty\else \def\ASYasydir{\asydir/}% \fi \def\ASYprefix{\ASYlatexdir\ASYasydir}% } % \end{macrocode} % % \subsection{User interface} % % \begin{macrocode} \newcommand\asy[1][]{% \stepcounter{asy}% \setkeys{ASYkeys}{#1}% % \end{macrocode} % Disable the "inline" option if "attach" is enabled: % \begin{macrocode} \ifASYattach \ASYinlinefalse \fi % \end{macrocode} % % \begin{macrocode} \asy@init \immediate\write\AsyPreStream{% \noexpand\InputIfFileExists{% \ASYprefix\noexpand\jobname-\the\c@asy.pre}{}{}% } \asy@write@graphic@header \let\ThisAsymptote\WriteAsyLine \ProcessAsymptote{asy}% } % \end{macrocode} % % \begin{macrocode} \def\endasy{% \asy@finalise@stream \asy@input@graphic } % \end{macrocode} % % \begin{macrocode} \def\asy@write@graphic@header{% \immediate\openout\AsyStream=\ASYasydir\jobname-\the\c@asy.asy\relax \gdef\AsyFile{\ASYprefix\Jobname-\the\c@asy}% \immediate\write\AsyStream{% if(!settings.multipleView) settings.batchView=false;^^J% \ifxetex settings.tex="xelatex";^^J% \else\ifASYPDF settings.tex="pdflatex";^^J% \fi\fi \ifASYinline settings.inlinetex=true;^^J% deletepreamble();^^J% \fi defaultfilename="\Jobname-\the\c@asy";^^J% if(settings.render < 0) settings.render=4;^^J% settings.outformat="";^^J% \ifASYattach settings.inlineimage=false;^^J% settings.embed=false;^^J% settings.toolbar=true;^^J% \else settings.inlineimage=true;^^J% settings.embed=true;^^J% settings.toolbar=false;^^J% viewportmargin=(2,2);^^J% \fi \globalASYdefs }% } \def\asy@expand@keepAspect{% \ifASYkeepAspect keepAspect=true% \else keepAspect=false% \fi% } % \end{macrocode} % % \begin{macrocode} \def\asy@finalise@stream{% % \end{macrocode} % Setting \verb|size()|. Only inserted if one of the dimensions is % set explicitly (i.e., if both height and width are not empty). % \begin{macrocode} \ifx\ASYwidth\@empty \ifx\ASYheight\@empty % write nothing! \else \immediate\write\AsyStream{size(0,\ASYheight,\asy@expand@keepAspect);}% \fi \else \ifx\ASYheight\@empty \immediate\write\AsyStream{size(\ASYwidth,0,\asy@expand@keepAspect);}% \else \immediate\write\AsyStream{size(\ASYwidth,\ASYheight,\asy@expand@keepAspect);}% \fi \fi % \end{macrocode} % Setting \verb|viewportsize=()|. Same logic as for \verb|size()|. % \begin{macrocode} \ifx\ASYviewportwidth\@empty \ifx\ASYviewportheight\@empty % write nothing! \else \immediate\write\AsyStream{viewportsize=(0,\ASYviewportheight);}% \fi \else \ifx\ASYviewportheight\@empty \immediate\write\AsyStream{viewportsize=(\ASYviewportwidth,0);}% \else \immediate\write\AsyStream{% viewportsize=(\ASYviewportwidth,\ASYviewportheight);}% \fi \fi \immediate\closeout\AsyStream } % \end{macrocode} % % \begin{macrocode} \def\asy@input@graphic{% \ifASYinline \IfFileExists{"\AsyFile.tex"}{% \catcode`:=12\relax \@@input"\AsyFile.tex"\relax }{% \PackageWarning{asymptote}{file `\AsyFile.tex' not found}% }% \else \IfFileExists{"\AsyFile.\AsyExtension"}{% \ifASYattach \ifASYPDF \IfFileExists{"\AsyFile+0.pdf"}{% \setbox\ASYbox=\hbox{\includegraphics[hiresbb]{"\AsyFile+0".pdf}}% }{% \setbox\ASYbox=\hbox{\includegraphics[hiresbb]{"\AsyFile".pdf}}% }% \else \setbox\ASYbox=\hbox{\includegraphics[hiresbb]{"\AsyFile.eps"}}% \fi \textattachfile{\AsyFile.\AsyExtension}{\phantom{\copy\ASYbox}}% \vskip-\ht\ASYbox \indent \box\ASYbox \else \ifASYPDF \includegraphics[hiresbb]{"\AsyFile".pdf}% \else \includegraphics[hiresbb]{"\AsyFile.eps"}% \fi \fi }{% % \end{macrocode} % 3D PRC figures require inline mode. % \begin{macrocode} \IfFileExists{"\AsyFile.tex"}{% \catcode`:=12 \@@input"\AsyFile.tex"\relax }{% \PackageWarning{asymptote}{% file `\AsyFile.\AsyExtension' not found% }% }% }% \fi } % \end{macrocode} % % \begin{macrocode} \def\asydef{% \let\ThisAsymptote\WriteGlobalAsyLine \ProcessAsymptote{asydef}% } % \end{macrocode} % % \begin{macrocode} \newcommand\asyinclude[2][]{% \begingroup \stepcounter{asy}% \setkeys{ASYkeys}{#1}% \ifASYattach \ASYinlinefalse \fi \asy@init \immediate\write\AsyPreStream{% \noexpand\InputIfFileExists{% \ASYprefix\noexpand\jobname-\the\c@asy.pre}{}{}% }% \asy@write@graphic@header \IfFileExists{#2.asy}{% \CatchFileDef\@tempa{#2.asy}{% \let\do\@makeother \dospecials \endlinechar=10\relax }% }{% \IfFileExists{#2}{% \CatchFileDef\@tempa{#2}{% \let\do\@makeother \dospecials \endlinechar=10\relax }% }{% \PackageWarning{asymptote}{file #2 not found}% \def\@tempa{}% }% }% \immediate\write\AsyStream{\unexpanded\expandafter{\@tempa}}% \asy@finalise@stream \asy@input@graphic \endgroup } % \end{macrocode} % % \begin{macrocode} \newcommand{\ASYanimategraphics}[5][]{% \IfFileExists{_#3.pdf}{% \animategraphics[{#1}]{#2}{_#3}{#4}{#5}% }{}% } % \end{macrocode} % % \subsection{Keys for graphics processing} % % \begin{macrocode} \newcommand\asysetup[1]{\setkeys{ASYkeys}{#1}} % \end{macrocode} % % \begin{macrocode} \define@key{ASYkeys}{dir}{% \def\asydir{#1}% } \def\ASYwidth{} \define@key{ASYkeys}{width}{% \edef\ASYwidth{\the\dimexpr#1\relax}% } \def\ASYheight{} \define@key{ASYkeys}{height}{% \edef\ASYheight{\the\dimexpr#1\relax}% } \define@key{ASYkeys}{keepAspect}[true]{% \ifthenelse{\equal{#1}{true}} {\ASYkeepAspecttrue} {\ASYkeepAspectfalse}% } \def\ASYviewportwidth{} \define@key{ASYkeys}{viewportwidth}{% \edef\ASYviewportwidth{\the\dimexpr#1\relax}% } \def\ASYviewportheight{} \define@key{ASYkeys}{viewportheight}{% \edef\ASYviewportheight{\the\dimexpr#1\relax}% } % \end{macrocode} % % \begin{macrocode} \define@key{ASYkeys}{inline}[true]{% \ifthenelse{\equal{#1}{true}} {\ASYinlinetrue} {\ASYinlinefalse}% } \define@key{ASYkeys}{attach}[true]{% \ifthenelse{\equal{#1}{true}} {\ASYattachtrue} {\ASYattachfalse}% } % \end{macrocode} % % \iffalse % % \fi % % \Finale % asymptote-2.37/doc/asy.1.begin000066400000000000000000000017551265434602500162170ustar00rootroot00000000000000.\" Hey, EMACS: -*- nroff -*- .TH ASY 1 "1 Dec 2004" .SH NAME asy \- Asymptote: a script-based vector graphics language .SH SYNOPSIS .B asy .RI [ options ] .RI [ file \ ...] .SH DESCRIPTION \fBAsymptote\fP is a powerful descriptive vector graphics language for technical drawings, inspired by MetaPost but with an improved C++-like syntax. Asymptote provides for figures the same high-quality level of typesetting that LaTeX does for scientific text. .SH OPTIONS If no arguments are given, Asymptote runs in interactive mode. .PP If "\-" is given as the file argument, Asymptote reads from standard input. .PP A summary of options is included below. The effect of most options can be negated by prepending .B no to the option name. Default values for most options may also be entered in the file .B .asy/config.asy in the user's home directory using the long form: .PP import settings; batchView=true; .PP For a complete description, see the Info files. asymptote-2.37/doc/asy.1.end000066400000000000000000000005151265434602500156720ustar00rootroot00000000000000 .SH SEE ALSO Asymptote is documented fully in the asymptote Info page. The manual can also be accessed in interactive mode with the "help" command. .SH AUTHOR Asymptote was written by Andy Hammerlindl, John Bowman, and Tom Prince. .PP This manual page was written by Hubert Chan for the Debian project (but may be used by others). asymptote-2.37/doc/asyRefCard.tex000066400000000000000000000471231265434602500170220ustar00rootroot00000000000000% Reference Card for Asymptote % Copyright (c) 2011 John C. Bowman. May be freely distributed. % Thanks to Stephen Gildea for the multicolumn macro package % and Joseph H. Silverman for the C Reference card. %**start of header \newcount\columnsperpage \overfullrule=0pt % This file can be printed with 1, 2, or 3 columns per page (see below). % [For 2 or 3 columns, you'll need 6 and 8 point fonts.] % Specify how many you want here. Nothing else needs to be changed. \columnsperpage=2 % This reference card is distributed in the hope that it will be useful, % but WITHOUT ANY WARRANTY; without even the implied warranty of % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. % This file is intended to be processed by plain TeX (TeX82). % % The final reference card has six columns, three on each side. % This file can be used to produce it in any of three ways: % 1 column per page % produces six separate pages, each of which needs to be reduced to 80%. % This gives the best resolution. % 2 columns per page % produces three already-reduced pages. % You will still need to cut and paste. % 3 columns per page % produces two pages which must be printed sideways to make a % ready-to-use 8.5 x 11 inch reference card. % For this you need a dvi device driver that can print sideways. % Which mode to use is controlled by setting \columnsperpage above. % % (reference card macros due to Stephen Gildea) % \def\versionnumber{1.1} % Version of this reference card \def\year{2014} \def\month{May} \def\version{\month\ \year\ v\versionnumber} \def\shortcopyrightnotice{\vskip .5ex plus 2 fill \centerline{\small \copyright\ \year\ John C. Bowman Permissions on back. v\versionnumber}} \def\copyrightnotice{ \vskip 1ex plus 100 fill\begingroup\small \centerline{\version. Copyright \copyright\ \year\ John C. Bowman} Permission is granted to make and distribute copies of this card, with or without modifications, provided the copyright notice and this permission notice are preserved on all copies. \endgroup} % make \bye not \outer so that the \def\bye in the \else clause below % can be scanned without complaint. \def\bye{\par\vfill\supereject\end} \newdimen\intercolumnskip \newbox\columna \newbox\columnb \def\ncolumns{\the\columnsperpage} \message{[\ncolumns\space column\if 1\ncolumns\else s\fi\space per page]} \def\scaledmag#1{ scaled \magstep #1} % This multi-way format was designed by Stephen Gildea % October 1986. \if 1\ncolumns \hsize 4in \vsize 10in \voffset -.7in \font\titlefont=\fontname\tenbf \scaledmag3 \font\headingfont=\fontname\tenbf \scaledmag2 \font\headingfonttt=\fontname\tentt \scaledmag2 \font\smallfont=\fontname\sevenrm \font\smallsy=\fontname\sevensy \footline{\hss\folio} \def\makefootline{\baselineskip10pt\hsize6.5in\line{\the\footline}} \else \hsize 3.2in \vsize 7.95in \hoffset -.75in \voffset -.745in \font\titlefont=cmbx10 \scaledmag2 \font\headingfont=cmbx10 \scaledmag1 \font\headingfonttt=cmtt10 \scaledmag1 \font\smallfont=cmr6 \font\smallsy=cmsy6 \font\eightrm=cmr8 \font\eightbf=cmbx8 \font\eightit=cmti8 \font\eighttt=cmtt8 \font\eightsy=cmsy8 \font\eightsl=cmsl8 \font\eighti=cmmi8 \font\eightex=cmex10 at 8pt \textfont0=\eightrm \textfont1=\eighti \textfont2=\eightsy \textfont3=\eightex \def\rm{\fam0 \eightrm} \def\bf{\eightbf} \def\it{\eightit} \def\tt{\eighttt} \def\sl{\eightsl} \normalbaselineskip=.8\normalbaselineskip \normallineskip=.8\normallineskip \normallineskiplimit=.8\normallineskiplimit \normalbaselines\rm %make definitions take effect \if 2\ncolumns \let\maxcolumn=b \footline{\hss\rm\folio\hss} \def\makefootline{\vskip 2in \hsize=6.86in\line{\the\footline}} \else \if 3\ncolumns \let\maxcolumn=c \nopagenumbers \else \errhelp{You must set \columnsperpage equal to 1, 2, or 3.} \errmessage{Illegal number of columns per page} \fi\fi \intercolumnskip=.46in \def\abc{a} \output={% % This next line is useful when designing the layout. %\immediate\write16{Column \folio\abc\space starts with \firstmark} \if \maxcolumn\abc \multicolumnformat \global\def\abc{a} \else\if a\abc \global\setbox\columna\columnbox \global\def\abc{b} %% in case we never use \columnb (two-column mode) \global\setbox\columnb\hbox to -\intercolumnskip{} \else \global\setbox\columnb\columnbox \global\def\abc{c}\fi\fi} \def\multicolumnformat{\shipout\vbox{\makeheadline \hbox{\box\columna\hskip\intercolumnskip \box\columnb\hskip\intercolumnskip\columnbox} \makefootline}\advancepageno} \def\columnbox{\leftline{\pagebody}} \def\bye{\par\vfill\supereject \if a\abc \else\null\vfill\eject\fi \if a\abc \else\null\vfill\eject\fi \end} \fi % we won't be using math mode much, so redefine some of the characters % we might want to talk about \catcode`\^=12 %\catcode`\_=12 \catcode`\~=12 \chardef\\=`\\ \chardef\{=`\{ \chardef\}=`\} \chardef\underscore=`\_ \hyphenation{} \parindent 0pt \parskip .85ex plus .35ex minus .5ex \def\small{\smallfont\textfont2=\smallsy\baselineskip=.8\baselineskip} \outer\def\newcolumn{\vfill\eject} \outer\def\title#1{{\titlefont\centerline{#1}}\vskip 1ex plus .5ex} \outer\def\section#1{\par\filbreak \vskip .5ex minus .1ex {\headingfont #1}\mark{#1}% \vskip .3ex minus .1ex} \outer\def\librarysection#1#2{\par\filbreak \vskip .5ex minus .1ex {\headingfont #1}\quad{\headingfonttt<#2>}\mark{#1}% \vskip .3ex minus .1ex} \newdimen\keyindent \def\beginindentedkeys{\keyindent=1em} \def\endindentedkeys{\keyindent=0em} \def\begindoubleindentedkeys{\keyindent=2em} \def\enddoubleindentedkeys{\keyindent=1em} \endindentedkeys \def\paralign{\vskip\parskip\halign} \def\<#1>{$\langle${\rm #1}$\rangle$} \def\kbd#1{{\tt#1}\null} %\null so not an abbrev even if period follows \def\beginexample{\par\vskip1\jot \hrule width.5\hsize \vskip1\jot \begingroup\parindent=2em \obeylines\obeyspaces\parskip0pt\tt} {\obeyspaces\global\let =\ } \def\endexample{\endgroup} \def\Example{\qquad{\sl Example\/}.\enspace\ignorespaces} \def\key#1#2{\leavevmode\hbox to \hsize{\vtop {\hsize=.75\hsize\rightskip=1em \hskip\keyindent\relax#1}\kbd{#2}\hfil}} \newbox\metaxbox \setbox\metaxbox\hbox{\kbd{M-x }} \newdimen\metaxwidth \metaxwidth=\wd\metaxbox \def\metax#1#2{\leavevmode\hbox to \hsize{\hbox to .75\hsize {\hskip\keyindent\relax#1\hfil}% \hskip -\metaxwidth minus 1fil \kbd{#2}\hfil}} \def\threecol#1#2#3{\hskip\keyindent\relax#1\hfil&\kbd{#2}\quad &\kbd{#3}\quad\cr} % Define Italic Names \def\makedef#1 {% \expandafter\edef\csname#1\endcsname{\hbox{\it#1\/}}} \makedef array \makedef arg \makedef const \makedef dim \makedef expr \makedef filename \makedef f \makedef format \makedef member \makedef name \makedef statement \makedef statements \makedef string \makedef type \makedef value \makedef var %**end of header \title{Asymptote Reference Card} \section{Program structure/functions} \halign{\tt#\hfil&\qquad#\hfil\cr import "\filename"&import module\cr import "\filename" as name&import filename as module name\cr include "\filename"&include verbatim text from file\cr \type\ \f(\type,\dots);&optional function declaration\cr \type\ \name;&variable declaration\cr \type\ \f(\type\ \arg,\dots) \{&function definition\cr \quad\statements\cr \quad return \value;\cr \}\cr } \section{Data types/declarations} \key{boolean (true or false)}{bool} \key{tri-state boolean (true, default, or false)}{bool3} \key{integer}{int} \key{float (double precision)}{real} \key{ordered pair (complex number)}{pair} \key{character string}{string} \key{fixed piecewise cubic Bezier spline}{path} \key{unresolved piecewise cubic Bezier spline}{guide} \key{color, line type/width/cap, font, fill rule}{pen} \key{label with position, alignment, pen attributes}{Label} \key{drawing canvas}{picture} \key{affine transform}{transform} \key{constant (unchanging) value}{const} \key{allocate in higher scope}{static} \key{no value}{void} \key{inhibit implicit argument casting}{explicit} \key{structure}{struct} \key{create name by data type}{typedef \type\ \name} \section{3D data types (import three;)} \key{ordered triple}{triple} \key{3D path}{path3} \key{3D guide}{guide3} \key{3D affine transform}{transform3} \section{Constants} \key{exponential form}{6.02e23} \key{\TeX\ string constant}{"abc\dots de"} \key{\TeX\ strings: special characters}{\\\\, \\"} \key{C strings: constant}{'abc\dots de'} \key{C strings: special characters}{\\\\, \\" \\' \\?} \key{C strings: newline, cr, tab, backspace}{\\n \\r \\t \\b} \key{C strings: octal, hexadecimal bytes}{\\0-\\377 \\x0-\\xFF} \section{Operators} \key{arithmetic operations}{+ - * /} \key{modulus (remainder)}{\%} \key{comparisons}{== != > >= < <=} \key{not}{!} \key{and or (conditional evaluation of RHS)}{\&\& ||} \key{and or xor}{\& | ^} \key{cast expression to type}{(\type) \expr} \key{increment decrement prefix operators}{++ --} \key{assignment operators}{+= -= *= /= \%=} \key{conditional expression}{\expr$_1$\ {?}\ \expr$_2$\ {:}\ \expr$_3$} \key{structure member operator}{\name.\member} \key{expression evaluation separator}{,} \section{Flow control} \key{statement terminator}{;} \key{block delimeters}{\{\quad\}} \key{comment delimeters}{/*\quad*/} \key{comment to end of line delimiter}{//} \key{exit from \kbd{while}/\kbd{do}/\kbd{for}}{break;} \key{next iteration of \kbd{while}/\kbd{do}/\kbd{for}}{continue;} \key{return value from function}{return \expr;} \key{terminate execution}{exit();} \key{abort execution with error message}{abort(string);} \metax{{\bf Flow constructions} ({\tt if/while/for/do})\hidewidth}{} \beginexample if(\expr)\ \statement else if(\expr)\ \statement else \statement \endexample \beginexample while(\expr) \quad\statement \endexample \beginexample for(\expr$_1$; \expr$_2$; \expr$_3$) \quad\statement \endexample \beginexample for(\type var : \array) \quad\statement \endexample \beginexample do \statement \quad while(\expr); \endexample \section{Arrays} \key{array}{\type[]\ \name;} \key{array element i}{\name[i]} \key{array indexed by elements of int array {\tt A}}{\name[A]} \key{anonymous array}{new \type[\dim]} \key{array containing {\tt n} deep copies of {\tt x}}{array(n,x)} \key{length}{\name.length} \key{cyclic flag}{\name.cyclic} \key{pop element {\tt x}}{\name.pop()} \key{push element {\tt x}}{\name.push(x)} \key{append array {\tt a}}{\name.append(a)} \key{insert rest arguments at index {\tt i}}{\name.insert(i,\dots)} \key{delete element at index {\tt i}}{\name.delete(i)} \key{delete elements with indices in [{\tt i},{\tt j}]}{\name.delete(i,j)} \key{delete all elements}{\name.delete()} \key{test whether element n is initialized}{\name.initialized(n)} \key{array of indices of initialized elements}{\name.keys} \key{complement of int array in {\tt \{0,\dots,n-1\}}}{complement(a,n)} \key{deep copy of array {\tt a}}{copy(a)} \key{array {\tt \{0,1,\dots,n-1\}}}{sequence(n)} \key{array {\tt \{n,n+1,\dots,m\}}}{sequence(n,m)} \key{array {\tt \{n-1,n-2,\dots,0\}}}{reverse(n)} \key{array {\tt \{f(0),f(1),\dots,f(n-1)\}}}{sequence(f,n)} \key{array obtained by applying {\tt f} to array {\tt a}}{map(f,a)} \key{uniform partition of [{\tt a},{\tt b}] into n intervals}{uniform(a,b,n)} \key{concat specified 1D arrays}{concat(a,b,\dots)} \key{return sorted array}{sort(a)} \key{return array sorted using ordering {\tt less}}{sort(a,{\tt less})} \key{search sorted array {\tt a} for key}{search(a,key)} \key{index of first true value of bool array {\tt a}}{find(a)} \key{index of nth true value of bool array {\tt a}}{find(a,n)} \section{Initialization} \key{initialize variable}{\type\ \name=\value;} \key{initialize array}{\type[]\ \name=\{\dots\};} \section{path connectors} \key{straight segment}{--} \key{Bezi\'er segment with implicit control points}{..} \key{Bezi\'er segment with explicit control points}{..controls c0 and c1..} \key{concatenate}{\&} \key{lift pen}{^^} \key{..tension atleast 1..}{::} \key{..tension atleast infinity..}{---} \section{Labels} \key{implicit cast of string {\tt s} to Label}{s} \key{Label {\tt s} with relative position and alignment}{Label(s,real,pair)} \key{Label {\tt s} with absolute position and alignment}{Label(s,pair,pair)} \key{Label {\tt s} with specified pen}{Label(s,pen)} \section{draw commands} \key{draw path with current pen}{draw(path)} \key{draw path with pen}{draw(path,pen)} \key{draw labeled path}{draw(Label,path)} \key{draw arrow with pen}{draw(path,pen,Arrow)} \key{draw path on picture}{draw(picture,path)} \key{draw visible portion of line through two pairs}{drawline(pair,pair)} \section{fill commands} \key{fill path with current pen}{fill(path)} \key{fill path with pen}{fill(path,pen)} \key{fill path on picture}{fill(picture,path)} \section{label commands} \key{label a pair with optional alignment z}{label(Label,pair,{\tt z})} \key{label a path with optional alignment z}{label(Label,path,{\tt z})} \key{add label to picture}{label(picture,Label)} \section{clip commands} \key{clip to path}{clip(path)} \key{clip to path with fill rule}{clip(path,pen)} \key{clip picture to path}{clip(picture,path)} \section{pens} \key{Grayscale pen from value in [0,1]}{gray(g)} \key{RGB pen from values in [0,1]}{rgb(r,g,b)} \key{CMYK pen from values in [0,1]}{cmyk(r,g,b)} \key{RGB pen from heximdecimal string]}{rgb(string)} \key{heximdecimal string from rgb pen]}{hex(pen)} \key{hsv pen from values in [0,1]}{hsv(h,s,v)} \key{invisible pen}{invisible} \key{default pen}{defaultpen} \key{current pen}{currentpen} \key{solid pen}{solid} \key{dotted pen}{dotted} \key{wide dotted current pen}{Dotted} \key{wide dotted pen}{Dotted(pen)} \key{dashed pen}{dashed} \key{long dashed pen}{longdashed} \key{dash dotted pen}{dashdotted} \key{long dash dotted pen}{longdashdotted} \key{PostScript butt line cap}{squarecap} \key{PostScript round line cap}{roundcap} \key{PostScript projecting square line cap}{extendcap} \key{miter join}{miterjoin} \key{round join}{roundjoin} \key{bevel join}{beveljoin} \key{pen with miter limit}{miterlimit(real)} \key{zero-winding fill rule}{zerowinding} \key{even-odd fill rule}{evenodd} \key{align to character bounding box (default)}{nobasealign} \key{align to \TeX\ baseline}{basealign} \key{pen with font size (pt)}{fontsize(real)} \key{LaTeX pen from encoding,family,series,shape}{font(strings)} \key{\TeX\ pen}{font(string)} \key{scaled \TeX\ pen}{font(string,real)} \key{PostScript font from strings}{Courier(series,shape)} \key{pen with opacity in [0,1]}{opacity(real)} \key{construct pen nib from polygonal path}{makepen(path)} \key{pen mixing operator}{+} \section{path operations} \key{number of segments in path {\tt p}}{length(p)} \key{number of nodes in path {\tt p}}{size(p)} \key{is path {\tt p} cyclic?}{cyclic(p)} \key{is segment {\tt i} of path {\tt p} straight?}{straight(p,i)} \key{is path {\tt p} straight?}{piecewisestraight(p)} \key{coordinates of path {\tt p} at time {\tt t}}{point(p,t)} \key{direction of path {\tt p} at time {\tt t}}{dir(p,t)} \key{direction of path {\tt p} at {\tt length(p)}}{dir(p)} \key{unit(dir(p)+dir(q))}{dir(p,q)} \key{acceleration of path {\tt p} at time {\tt t}}{accel(p,t)} \key{radius of curvature of path {\tt p} at time {\tt t}}{radius(p,t)} \key{precontrol point of path {\tt p} at time {\tt t}}{precontrol(p,t)} \key{postcontrol point of path {\tt p} at time {\tt t}}{postcontrol(p,t)} \key{arclength of path {\tt p}}{arclength(p)} \key{time at which {\tt arclength(p)=L}}{arctime(p,L)} \key{point on path {\tt p} at arclength {\tt L}}{arcpoint(p,L)} \key{first value {\tt t} at which {\tt dir(p,t)=z}}{dirtime(p,z)} \key{time {\tt t} at relative fraction {\tt l} of {\tt arclength(p)}}{reltime(p,l)} \key{point at relative fraction {\tt l} of {\tt arclength(p)}}{relpoint(p,l)} \key{point midway along arclength of {\tt p}}{midpoint(p)} \key{path running backwards along {\tt p}}{reverse(p)} \key{subpath of {\tt p} between times {\tt a} and {\tt b}}{subpath(p,a,b)} \key{times for one intersection of paths {\tt p} and {\tt q}}{intersect(p,q)} \key{times at which {\tt p} reaches minimal extents}{mintimes(p)} \key{times at which {\tt p} reaches maximal extents}{maxtimes(p)} \key{intersection times of paths {\tt p} and {\tt q}}{intersections(p,q)} \key{intersection times of path {\tt p} with `{\tt --a--b--}'}{intersections(p,a,b)} \key{intersection times of path {\tt p} crossing $x=${\tt x}}{times(p,x)} \key{intersection times of path {\tt p} crossing $y=${\tt z.y}}{times(p,z)} \key{intersection point of paths {\tt p} and {\tt q}}{intersectionpoint(p,q)} \key{intersection points of {\tt p} and {\tt q}}{intersectionpoints(p,q)} \key{intersection of extension of {\tt P--Q} and {\tt p--q}}{extension(P,Q,p,q)} \key{lower left point of bounding box of path {\tt p}}{min(p)} \key{upper right point of bounding box of path {\tt p}}{max(p)} \key{subpaths of {\tt p} split by {\tt n}th cut of {\tt knife}}{cut(p,knife,n)} \key{winding number of path {\tt p} about pair {\tt z}}{windingnumber(p,z)} \key{pair {\tt z} lies within path {\tt p}?}{interior(p,z)} \key{pair {\tt z} lies within or on path {\tt p}?}{inside(p,z)} \key{path surrounding region bounded by paths}{buildcycle(\dots)} \key{path filled by \tt{draw(g,p)}}{strokepath(g,p)} \key{unit square with lower-left vertex at origin}{unitsquare} \key{unit circle centered at origin}{unitcircle} \key{circle of radius {\tt r} about {\tt c}}{circle(c,r)} \key{arc of radius {\tt r} about {\tt c} from angle {\tt a} to {\tt b}}{arc(c,r,a,b)} \key{unit {\tt n}-sided polygon}{polygon(n)} \key{unit {\tt n}-point cyclic cross}{cross(n)} \section{pictures} \key{add picture {\tt pic} to currentpicture}{add(pic)} \key{add picture {\tt pic} about pair {\tt z}}{add(pic,z)} \section{affine transforms} \key{identity transform}{identity()} \key{shift by values}{shift(real,real)} \key{shift by pair}{shift(pair)} \key{scale by {\tt x} in the $x$ direction}{xscale(x)} \key{scale by {\tt y} in the $y$ direction}{yscale(y)} \key{scale by {\tt x} in both directions}{scale(x)} \key{scale by real values {\tt x} and {\tt y}}{scale(x,y)} \key{map $(x,y) \rightarrow (x+${\tt s}$y,y)$}{slant(s)} \key{rotate by real {\tt angle} in degrees about pair {\tt z}}{rotate(angle,z=(0,0))} \key{reflect about line from {\tt P--Q}}{reflect(P,Q)} \section{string operations} \key{concatenate operator}{+} \key{string length}{length(string)} \key{position $\ge$ {\tt pos} of first occurence of {\tt t} in {\tt s}}{find({\tt s},{\tt t},pos=0)} \key{position $\le$ {\tt pos} of last occurence of {\tt t} in {\tt s}}{rfind({\tt s},{\tt t},pos=-1)} \key{string with {\tt t} inserted in {\tt s} at {\tt pos}}{insert({\tt s},{\tt pos},{\tt t})} \key{string {\tt s} with {\tt n} characters at {\tt pos} erased}{erase({\tt s},{\tt pos},{\tt n})} \key{substring of string {\tt s} of length {\tt n} at {\tt pos}}{substr({\tt s},{\tt pos},{\tt n})} \key{string {\tt s} reversed}{reverse({\tt s})} \key{string {\tt s} with {\tt before} changed to {\tt after}}{replace({\tt s},{\tt before},{\tt after})} \key{string {\tt s} translated via {\tt \{\{before,after\},\dots\}}}{replace({\tt s},string [][] table)} \key{format {\tt x} using C-style format string {\tt s} }{format({\tt s},x)} \key{casts hexidecimal string to an integer}{hex(s)} \key{casts {\tt x} to string using precision {\tt digits}}{string(x,digits=realDigits)} \key{current time formatted by {\tt format}}{time(format="\%a \%b \%d \%T \%Z \%Y")} \key{time in seconds of string {\tt t} using {\tt format}}{seconds(t,format)} \key{string corresponding to {\tt seconds} using {\tt format}}{time(seconds,format)} \key{split {\tt s} into strings separated by {\tt delimiter}}{split(s,delimiter="")} %%%%%%%%%%%%%%%%%%%%%%%%%% END LIBRARIES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This goes at the bottom of the last page (column 6) \copyrightnotice % \bye % Local variables: % compile-command: "tex AsyRefCard" % End: asymptote-2.37/doc/asycolors.sty000066400000000000000000000053601265434602500170310ustar00rootroot00000000000000\usepackage{color} \definecolor{cyan}{cmyk}{1,0,0,0} \definecolor{magenta}{cmyk}{0,1,0,0} \definecolor{yellow}{cmyk}{0,0,1,0} \definecolor{black}{cmyk}{0,0,0,1} \definecolor{white}{cmyk}{0,0,0,0} \definecolor{gray}{cmyk}{0,0,0,0.5} \definecolor{red}{cmyk}{0,1,1,0} \definecolor{green}{cmyk}{1,0,1,0} \definecolor{blue}{cmyk}{1,1,0,0} \definecolor{palered}{cmyk}{0,0.25,0.25,0} \definecolor{palegreen}{cmyk}{0.25,0,0.25,0} \definecolor{paleblue}{cmyk}{0.25,0.25,0,0} \definecolor{palecyan}{cmyk}{0.25,0,0,0} \definecolor{palemagenta}{cmyk}{0,0.25,0,0} \definecolor{paleyellow}{cmyk}{0,0,0.25,0} \definecolor{palegray}{cmyk}{0,0,0,0.05} \definecolor{lightred}{cmyk}{0,0.5,0.5,0} \definecolor{lightgreen}{cmyk}{0.5,0,0.5,0} \definecolor{lightblue}{cmyk}{0.5,0.5,0,0} \definecolor{lightcyan}{cmyk}{0.5,0,0,0} \definecolor{lightmagenta}{cmyk}{0,0.5,0,0} \definecolor{lightyellow}{cmyk}{0,0,0.5,0} \definecolor{lightgray}{cmyk}{0,0,0,0.1} \definecolor{mediumred}{cmyk}{0,0.75,0.75,0} \definecolor{mediumgreen}{cmyk}{0.75,0,0.75,0} \definecolor{mediumblue}{cmyk}{0.75,0.75,0,0} \definecolor{mediumcyan}{cmyk}{0.75,0,0,0} \definecolor{mediummagenta}{cmyk}{0,0.75,0,0} \definecolor{mediumyellow}{cmyk}{0,0,0.75,0} \definecolor{mediumgray}{cmyk}{0,0,0,0.25} \definecolor{heavyred}{cmyk}{0,1,1,0.25} \definecolor{heavygreen}{cmyk}{1,0,1,0.25} \definecolor{heavyblue}{cmyk}{1,1,0,0.25} \definecolor{heavycyan}{cmyk}{1,0,0,0.25} \definecolor{heavymagenta}{cmyk}{0,1,0,0.25} \definecolor{lightolive}{cmyk}{0,0,1,0.25} \definecolor{heavygray}{cmyk}{0,0,0,0.75} \definecolor{deepred}{cmyk}{0,1,1,0.5} \definecolor{deepgreen}{cmyk}{1,0,1,0.5} \definecolor{deepblue}{cmyk}{1,1,0,0.5} \definecolor{deepcyan}{cmyk}{1,0,0,0.5} \definecolor{deepmagenta}{cmyk}{0,1,0,0.5} \definecolor{olive}{cmyk}{0,0,1,0.5} \definecolor{deepgray}{cmyk}{0,0,0,0.9} \definecolor{darkred}{cmyk}{0,1,1,0.75} \definecolor{darkgreen}{cmyk}{1,0,1,0.75} \definecolor{darkblue}{cmyk}{1,1,0,0.75} \definecolor{darkcyan}{cmyk}{1,0,0,0.75} \definecolor{darkmagenta}{cmyk}{0,1,0,0.75} \definecolor{darkolive}{cmyk}{0,0,1,0.75} \definecolor{darkgray}{cmyk}{0,0,0,0.95} \definecolor{orange}{cmyk}{0,0.5,1,0} \definecolor{fuchsia}{cmyk}{0,1,0.5,0} \definecolor{chartreuse}{cmyk}{0.5,0,1,0} \definecolor{springgreen}{cmyk}{1,0,0.5,0} \definecolor{purple}{cmyk}{0.5,1,0,0} \definecolor{royalblue}{cmyk}{1,0.5,0,0} \definecolor{salmon}{cmyk}{0,0.5,0.5,0} \definecolor{brown}{cmyk}{0,1,1,0.5} \definecolor{darkbrown}{cmyk}{0,1,1,0.75} \definecolor{pink}{cmyk}{0,0.25,0,0} \definecolor{palegrey}{cmyk}{0,0,0,0.05} \definecolor{lightgrey}{cmyk}{0,0,0,0.1} \definecolor{mediumgrey}{cmyk}{0,0,0,0.25} \definecolor{grey}{cmyk}{0,0,0,0.5} \definecolor{heavygrey}{cmyk}{0,0,0,0.5} \definecolor{deepgrey}{cmyk}{0,0,0,0.9} \definecolor{darkgrey}{cmyk}{0,0,0,0.95} asymptote-2.37/doc/asymptote.texi000066400000000000000000013056441265434602500172030ustar00rootroot00000000000000\input texinfo @c -*-texinfo-*- @setfilename asymptote.info @settitle Asymptote: the Vector Graphics Language @include version.texi @finalout @copying This file documents @code{Asymptote}, version @value{VERSION}. @url{http://asymptote.sourceforge.net} Copyright @copyright{} 2004-14 Andy Hammerlindl, John Bowman, and Tom Prince. @quotation Permission is granted to copy, distribute and/or modify this document under the terms of the @acronym{GNU} Lesser General Public License (see the file LICENSE in the top-level source directory). @end quotation @end copying @dircategory Languages @direntry * asymptote: (asymptote/asymptote). Vector graphics language. @end direntry @titlepage @title Asymptote: the Vector Graphics Language @subtitle For version @value{VERSION} @sp 1 @center @image{logo} @page @vskip 0pt plus 1filll @insertcopying @end titlepage @c So the toc is printed at the start. @contents @ifnottex @node Top @top Asymptote @insertcopying @end ifnottex @menu * Description:: What is @code{Asymptote}? * Installation:: Downloading and installing * Tutorial:: Getting started * Drawing commands:: Four primitive graphics commands * Bezier curves:: Path connectors and direction specifiers * Programming:: The @code{Asymptote} vector graphics language * LaTeX usage:: Embedding @code{Asymptote} commands within @code{LaTeX} * Base modules:: Base modules shipped with @code{Asymptote} * Options:: Command-line options * Interactive mode:: Typing @code{Asymptote} commands interactively * GUI:: Graphical user interface * PostScript to Asymptote:: @code{Asymptote} backend to @code{pstoedit} * Help:: Where to get help and submit bug reports * Debugger:: Squish those bugs! * Credits:: Contributions and acknowledgments * Index:: General index @detailmenu --- The Detailed Node Listing --- Installation * UNIX binary distributions:: Prebuilt @code{UNIX} binaries * MacOS X binary distributions:: Prebuilt @code{MacOS X} binaries * Microsoft Windows:: Prebuilt @code{Microsoft Windows} binary * Configuring:: Configuring @code{Asymptote} for your system * Search paths:: Where @code{Asymptote} looks for your files * Compiling from UNIX source:: Building @code{Asymptote} from scratch * Editing modes:: Convenient @code{emacs} and @code{vim} modes * Git:: Getting the latest development source * Uninstall:: Goodbye, @code{Asymptote}! Drawing commands * draw:: Draw a path on a picture or frame * fill:: Fill a cyclic path on a picture or frame * clip:: Clip a picture or frame to a cyclic path * label:: Label a point on a picture Programming * Data types:: void, bool, int, real, pair, triple, string * Paths and guides:: Bezier curves * Pens:: Colors, line types, line widths, font sizes * Transforms:: Affine transforms * Frames and pictures:: Canvases for immediate and deferred drawing * Files:: Reading and writing your data * Variable initializers:: Initialize your variables * Structures:: Organize your data * Operators:: Arithmetic and logical operators * Implicit scaling:: Avoiding those ugly *s * Functions:: Traditional and high-order functions * Arrays:: Dynamic vectors * Casts:: Implicit and explicit casts * Import:: Importing external @code{Asymptote} modules * Static:: Where to allocate your variable? Operators * Arithmetic & logical:: Basic mathematical operators * Self & prefix operators:: Increment and decrement * User-defined operators:: Overloading operators Functions * Default arguments:: Default values can appear anywhere * Named arguments:: Assigning function arguments by keyword * Rest arguments:: Functions with a variable number of arguments * Mathematical functions:: Standard libm functions Arrays * Slices:: Python-style array slices Base modules * plain:: Default @code{Asymptote} base file * simplex:: Linear programming: simplex method * math:: Extend @code{Asymptote}'s math capabilities * interpolate:: Interpolation routines * geometry:: Geometry routines * trembling:: Wavy lines * stats:: Statistics routines and histograms * patterns:: Custom fill and draw patterns * markers:: Custom path marker routines * tree:: Dynamic binary search tree * binarytree:: Binary tree drawing module * drawtree:: Tree drawing module * syzygy:: Syzygy and braid drawing module * feynman:: Feynman diagrams * roundedpath:: Round the sharp corners of paths * animation:: Embedded @acronym{PDF} and @acronym{MPEG} movies * embed:: Embedding movies, sounds, and 3D objects * slide:: Making presentations with @code{Asymptote} * MetaPost:: @code{MetaPost} compatibility routines * unicode:: Accept @code{unicode} (UTF-8) characters * latin1:: Accept @code{ISO 8859-1} characters * babel:: Interface to @code{LaTeX} @code{babel} package * labelpath:: Drawing curved labels * labelpath3:: Drawing curved labels in 3D * annotate:: Annotate your @acronym{PDF} files * CAD:: 2D CAD pen and measurement functions (DIN 15) * graph:: 2D linear & logarithmic graphs * palette:: Color density images and palettes * three:: 3D vector graphics * obj:: 3D obj files * graph3:: 3D linear & logarithmic graphs * grid3:: 3D grids * solids:: 3D solid geometry * tube:: 3D rotation minimizing tubes * flowchart:: Flowchart drawing routines * contour:: Contour lines * contour3:: Contour surfaces * smoothcontour3:: Smooth implicit surfaces * slopefield:: Slope fields * ode:: Ordinary differential equations Graphical User Interface * GUI installation:: Installing @code{xasy} * GUI usage:: @end detailmenu @end menu @node Description @chapter Description @cindex description @code{Asymptote} is a powerful descriptive vector graphics language that provides a mathematical coordinate-based framework for technical drawing. Labels and equations are typeset with @code{LaTeX}, for overall document consistency, yielding the same high-quality level of typesetting that @code{LaTeX} provides for scientific text. By default it produces @code{PostScript} output, but it can also generate any format that the @code{ImageMagick} package can produce. A major advantage of @code{Asymptote} over other graphics packages is that it is a high-level programming language, as opposed to just a graphics program: it can therefore exploit the best features of the script (command-driven) and graphical-user-interface (@acronym{GUI}) methods for producing figures. The rudimentary @acronym{GUI} @code{xasy} included with the package allows one to move script-generated objects around. To make @code{Asymptote} accessible to the average user, this @acronym{GUI} is currently being developed into a full-fledged interface that can generate objects directly. However, the script portion of the language is now ready for general use by users who are willing to learn a few simple @code{Asymptote} graphics commands (@pxref{Drawing commands}). @code{Asymptote} is mathematically oriented (e.g.@ one can use complex multiplication to rotate a vector) and uses @code{LaTeX} to do the typesetting of labels. This is an important feature for scientific applications. It was inspired by an earlier drawing program (with a weaker syntax and capabilities) called @code{MetaPost}. The @code{Asymptote} vector graphics language provides: @itemize @bullet @item a standard for typesetting mathematical figures, just as @TeX{}/@code{LaTeX} is the de-facto standard for typesetting equations. @item @code{LaTeX} typesetting of labels, for overall document consistency; @item the ability to generate and embed 3D vector @acronym{PRC} graphics within @acronym{PDF} files; @item a natural coordinate-based framework for technical drawing, inspired by @code{MetaPost}, with a much cleaner, powerful C++-like programming syntax; @item compilation of figures into virtual machine code for speed, without sacrificing portability; @item the power of a script-based language coupled to the convenience of a @acronym{GUI}; @item customization using its own C++-like graphics programming language; @item sensible defaults for graphical features, with the ability to override; @item a high-level mathematically oriented interface to the @code{PostScript} language for vector graphics, including affine transforms and complex variables; @item functions that can create new (anonymous) functions; @item deferred drawing that uses the simplex method to solve overall size constraint issues between fixed-sized objects (labels and arrowheads) and objects that should scale with figure size; @end itemize Many of the features of @code{Asymptote} are written in the @code{Asymptote} language itself. While the stock version of @code{Asymptote} is designed for mathematics typesetting needs, one can write @code{Asymptote} modules that tailor it to specific applications. A scientific graphing module has already been written (@pxref{graph}). Examples of @code{Asymptote} code and output, including animations, are available at @quotation @url{http://asymptote.sourceforge.net/gallery/}. @end quotation @noindent Links to many external resources, including an excellent user-written @code{Asymptote} tutorial can be found at @quotation @url{http://asymptote.sourceforge.net/links.html}. @end quotation @cindex reference @cindex quick reference A quick reference card for @code{Asymptote} is available at @quotation @url{http://asymptote.sourceforge.net/asyRefCard.pdf}. @end quotation @node Installation @chapter Installation @cindex installation @menu * UNIX binary distributions:: Prebuilt @code{UNIX} binaries * MacOS X binary distributions:: Prebuilt @code{MacOS X} binaries * Microsoft Windows:: Prebuilt @code{Microsoft Windows} binary * Configuring:: Configuring @code{Asymptote} for your system * Search paths:: Where @code{Asymptote} looks for your files * Compiling from UNIX source:: Building @code{Asymptote} from scratch * Editing modes:: Convenient @code{emacs} and @code{vim} modes * Git:: Getting the latest development source * Uninstall:: Goodbye, @code{Asymptote}! @end menu After following the instructions for your specific distribution, please see also @ref{Configuring}. @noindent We recommend subscribing to new release announcements at @quotation @url{http://freecode.com/projects/asy} @end quotation @noindent Users may also wish to monitor the @code{Asymptote} forum: @quotation @url{http://sourceforge.net/p/asymptote/discussion/409349} @end quotation @noindent @node UNIX binary distributions @section UNIX binary distributions @cindex UNIX binary distributions @cindex @acronym{RPM} @cindex @code{tgz} We release both @code{tgz} and @acronym{RPM} binary distributions of @code{Asymptote}. The root user can install the @code{Linux i386} @code{tgz} distribution of version @code{x.xx} of @code{Asymptote} with the commands: @verbatim tar -C / -zxf asymptote-x.xx.i386.tgz texhash @end verbatim @noindent The @code{texhash} command, which installs LaTeX style files, is optional. The executable file will be @code{/usr/local/bin/asy}) and example code will be installed by default in @code{@value{Datadir}/doc/asymptote/examples}. @noindent @cindex Fedora Fedora users can easily install the most recent version of @code{Asymptote} with the command @verbatim yum --enablerepo=rawhide install asymptote @end verbatim @cindex Debian @noindent To install the latest version of @code{Asymptote} on a Debian-based distribution (e.g.@ Ubuntu, Mepis, Linspire) follow the instructions for compiling from @code{UNIX} source (@pxref{Compiling from UNIX source}). Alternatively, Debian users can install one of Hubert Chan's prebuilt @code{Asymptote} binaries from @quotation @url{http://ftp.debian.org/debian/pool/main/a/asymptote} @end quotation @node MacOS X binary distributions @section MacOS X binary distributions @cindex @code{MacOS X} binary distributions @code{MacOS X} users can either compile the @code{UNIX} source code (@pxref{Compiling from UNIX source}) or install the @code{Asymptote} binary available at @url{http://www.macports.org/} @noindent Note that many @code{MacOS X} (and FreeBSD) systems lack the @acronym{GNU} @code{readline} library. For full interactive functionality, @acronym{GNU} @code{readline} version 4.3 or later must be installed. @node Microsoft Windows @section Microsoft Windows @cindex Microsoft Windows Users of the @code{Microsoft Windows} operating system can install the self-extracting @code{Asymptote} executable @code{asymptote-x.xx-setup.exe}, where @code{x.xx} denotes the latest version. A working @TeX{} implementation (such as the one available at @url{http://www.miktex.org}) will be required to typeset labels. You will also need to install @code{GPL Ghostscript} version 9.14 or later from @url{http://downloads.ghostscript.com/public}. To view the default @code{PostScript} output, you can install the program @code{gsview} available from @url{http://www.cs.wisc.edu/~ghost/gsview/}. @cindex @code{psview} @anchor{psview} A better (and free) @code{PostScript} viewer available at @url{http://psview.sourceforge.net/} (which in particular works properly in interactive mode) unfortunately currently requires some manual configuration. Specifically, if version @code{x.xx} of @code{psview} is extracted to the directory @code{c:\Program Files} one needs to put @verbatim import settings; psviewer="c:\Program Files\psview-x.xx\psv.exe"; @end verbatim @noindent in the optional @code{Asymptote} configuration file; @pxref{configuration file}). The @code{ImageMagick} package from @url{http://www.imagemagick.org/script/binary-releases.php} @noindent is required to support output formats other than @acronym{EPS}, @acronym{PDF}, @acronym{SVG}, and @acronym{PNG} (@pxref{convert}). The @code{Python 2} interpreter from @url{http://www.python.org} is only required if you wish to try out the graphical user interface (@pxref{GUI}). @noindent Example code will be installed by default in the @code{examples} subdirectory of the installation directory (by default, @code{C:\Program Files\Asymptote}). @node Configuring @section Configuring @cindex configuring @cindex @code{-V} @cindex @code{psviewer} @cindex @code{pdfviewer} @cindex @code{gs} In interactive mode, or when given the @code{-V} option (the default when running @code{Asymptote} on a single file under @code{MSDOS}), @code{Asymptote} will automatically invoke the @code{PostScript} viewer @code{gv} (under @code{UNIX}) or @code{gsview} (under @code{MSDOS} to display graphical output. These defaults may be overridden with the configuration variable @code{psviewer}. The @code{PostScript} viewer should be capable of automatically redrawing whenever the output file is updated. The default @code{UNIX} @code{PostScript} viewer @code{gv} supports this (via a @code{SIGHUP} signal). Version @code{gv-3.6.3} or later (from @url{http://ftp.gnu.org/gnu/gv/}) is required for interactive mode to work properly. Users of @code{ggv} will need to enable @code{Watch file} under @code{Edit/Postscript Viewer Preferences}. Users of @code{gsview} will need to enable @code{Options/Auto Redisplay} (however, under @code{MSDOS} it is still necessary to click on the @code{gsview} window; under @code{UNIX} one must manually redisplay by pressing the @code{r} key). A better (and free) multiplatform alternative to @code{gsview} is @code{psview} (@pxref{psview}). @cindex @code{settings} @cindex configuration file Configuration variables are most easily set as @code{Asymptote} variables in an optional configuration file @code{config.asy} @pxref{configuration file}). Here are the default values of several important configuration variables under @code{UNIX}: @noindent @verbatim import settings; psviewer="gv"; pdfviewer="acroread"; gs="gs"; @end verbatim @noindent @cindex @code{cmd} Under @code{MSDOS}, the (installation-dependent) default values of these configuration variables are determined automatically from the @code{Microsoft Windows} registry. Viewer settings (such as @code{psviewer} and @code{pdfviewer}) can be set to the string @code{cmd} to request the application normally associated with the corresponding file type. For @acronym{PDF} format output, the @code{gs} setting specifies the location of the @code{PostScript}-to-@acronym{PDF} processor @code{Ghostscript}, available from @url{http://downloads.ghostscript.com/public}. The setting @code{pdfviewer} specifies the location of the @acronym{PDF} viewer. On @code{UNIX} systems, to support automatic document reloading in @code{Adobe Reader}, we recommend copying the file @code{reload.js} from the @code{Asymptote} system directory (by default, @code{@value{Datadir}/asymptote} under @code{UNIX} to @code{~/.adobe/Acrobat/x.x/JavaScripts/}, where @code{x.x} represents the appropriate @code{Adobe Reader} version number. The automatic document reload feature must then be explicitly enabled by putting @verbatim import settings; pdfreload=true; pdfreloadOptions="-tempFile"; @end verbatim @noindent in the @code{Asymptote} configuration file. This reload feature is not useful under @code{MSDOS} since the document cannot be updated anyway on that operating system until it is first closed by @code{Adobe Reader}. The configuration variable @code{dir} can be used to adjust the search path (@pxref{Search paths}). @cindex @code{papertype} @cindex @code{paperwidth} @cindex @code{paperheight} @cindex @code{letter} @cindex @code{a4} By default, @code{Asymptote} attempts to center the figure on the page, assuming that the paper type is @code{letter}. The default paper type may be changed to @code{a4} with the configuration variable @code{papertype}. Alignment to other paper sizes can be obtained by setting the configuration variables @code{paperwidth} and @code{paperheight}. @cindex @code{config} @cindex @code{texpath} @cindex @code{texcommand} @cindex @code{dvips} @cindex @code{dvisvgm} @cindex @code{libgs} @cindex @code{convert} @cindex @code{display} @cindex @code{animate} @cindex @code{ImageMagick} The following configuration variables normally do not require adjustment: @verbatim config texpath texcommand dvips dvisvgm libgs convert display animate @end verbatim @noindent Warnings (such as "unbounded" and "offaxis") may be enabled or disabled with the functions @verbatim warn(string s); nowarn(string s); @end verbatim @noindent or by directly modifying the string array @code{settings.suppress}, which lists all disabled warnings. @cindex command-line options Configuration variables may also be set or overwritten with a command-line option: @verbatim asy -psviewer=gsview -V venn @end verbatim @cindex environment variables Alternatively, system environment versions of the above configuration variables may be set in the conventional way. The corresponding environment variable name is obtained by converting the configuration variable name to upper case and prepending @code{ASYMPTOTE_}: for example, to set the environment variable @verbatim ASYMPTOTE_PSVIEWER="C:\Program Files\Ghostgum\gsview\gsview32.exe"; @end verbatim @noindent under @code{Microsoft Windows XP}: @enumerate @item Click on the @code{Start} button; @item Right-click on @code{My Computer}; @item Choose @code{View system information}; @item Click the @code{Advanced} tab; @item Click the @code{Environment Variables} button. @end enumerate @node Search paths @section Search paths @cindex search paths In looking for @code{Asymptote} system files, @code{asy} will search the following paths, in the order listed: @enumerate @item The current directory; @item @cindex @code{dir} A list of one or more directories specified by the configuration variable @code{dir} or environment variable @code{ASYMPTOTE_DIR} (separated by @code{:} under UNIX and @code{;} under @code{MSDOS}); @item @cindex @code{.asy} The directory specified by the environment variable @code{ASYMPTOTE_HOME}; if this variable is not set, the directory @code{.asy} in the user's home directory (@code{%USERPROFILE%\.asy} under @code{MSDOS}) is used; @item The @code{Asymptote} system directory (by default, @code{@value{Datadir}/asymptote} under @code{UNIX} and @code{C:\Program Files\Asymptote} under @code{MSDOS}). @end enumerate @node Compiling from UNIX source @section Compiling from UNIX source @cindex Compiling from UNIX source To compile and install a @code{UNIX} executable from the source release @code{asymptote-x.xx.src.tgz} in the subdirectory @code{x.xx} under @url{http://sourceforge.net/projects/asymptote/files/} execute the commands: @verbatim gunzip asymptote-x.xx.src.tgz tar -xf asymptote-x.xx.src.tar cd asymptote-x.xx @end verbatim By default the system version of the Boehm garbage collector will be used; if it is old we recommend first putting @url{http://hboehm.info/gc/gc_source/gc-7.4.2.tar.gz} @url{http://www.ivmaisoft.com/_bin/atomic_ops/libatomic_ops-7.4.2.tar.gz} in the @code{Asymptote} source directory. On @code{UNIX} platforms (other than @code{MacOS X}), we recommend using version @code{3.0.0} of the @code{freeglut} library. To compile @code{freeglut}, download @quotation @url{http://prdownloads.sourceforge.net/freeglut/freeglut-3.0.0.tar.gz} @end quotation @noindent and type (as the root user): @verbatim gunzip freeglut-3.0.0.tar.gz tar -xf freeglut-3.0.0.tar cd freeglut-3.0.0 ./configure --prefix=/usr cmake . make make install cd .. @end verbatim @noindent Then compile @code{Asymptote} with the commands @verbatim ./configure make all make install @end verbatim @noindent Be sure to use @acronym{GNU} @code{make} (on non-@acronym{GNU} systems this command may be called @code{gmake}). To build the documentation, you may need to install the @code{texinfo-tex} package. If you get errors from a broken @code{texinfo} or @code{pdftex} installation, simply put @quotation @url{http://asymptote.sourceforge.net/asymptote.pdf} @end quotation @noindent in the directory @code{doc} and repeat the command @code{make all}. @noindent For a (default) system-wide installation, the last command should be done as the root user. To install without root privileges, change the @code{./configure} command to @verbatim ./configure --prefix=$HOME/asymptote @end verbatim One can disable use of the Boehm garbage collector by configuring with @code{./configure --disable-gc}. For a list of other configuration options, say @code{./configure --help}. For example, one can tell configure to look for header files and libraries in nonstandard locations: @verbatim ./configure CFLAGS=-I/opt/usr/include LDFLAGS=-L/opt/usr/lib @end verbatim If you are compiling @code{Asymptote} with @code{gcc}, you will need a relatively recent version (e.g.@ 3.4.4 or later). For full interactive functionality, you will need version 4.3 or later of the @acronym{GNU} @code{readline} library. The file @code{gcc3.3.2curses.patch} in the @code{patches} directory can be used to patch the broken curses.h header file (or a local copy thereof in the current directory) on some @code{AIX} and @code{IRIX} systems. @cindex @code{FFTW} @cindex @code{GSL} The @code{FFTW} library is only required if you want @code{Asymptote} to be able to take Fourier transforms of data (say, to compute an audio power spectrum). The @code{GSL} library is only required if you require the special functions that it supports. If you don't want to install @code{Asymptote} system wide, just make sure the compiled binary @code{asy} and @acronym{GUI} script @code{xasy} are in your path and set the configuration variable @code{dir} to point to the directory @code{base} (in the top level directory of the @code{Asymptote} source code). @node Editing modes @section Editing modes @cindex Editing modes @cindex @code{emacs} @cindex @code{asy-mode} @cindex @code{lasy-mode} Users of @code{emacs} can edit @code{Asymptote} code with the mode @code{asy-mode}, after enabling it by putting the following lines in their @code{.emacs} initialization file, replacing @code{ASYDIR} with the location of the @code{Asymptote} system directory (by default, @code{@value{Datadir}/asymptote} or @code{C:\Program Files\Asymptote} under @code{MSDOS}): @verbatim (add-to-list 'load-path "ASYDIR") (autoload 'asy-mode "asy-mode.el" "Asymptote major mode." t) (autoload 'lasy-mode "asy-mode.el" "hybrid Asymptote/Latex major mode." t) (autoload 'asy-insinuate-latex "asy-mode.el" "Asymptote insinuate LaTeX." t) (add-to-list 'auto-mode-alist '("\\.asy$" . asy-mode)) @end verbatim @noindent Particularly useful key bindings in this mode are @code{C-c C-c}, which compiles and displays the current buffer, and the key binding @code{C-c ?}, which shows the available function prototypes for the command at the cursor. For full functionality you should also install the Apache Software Foundation package @code{two-mode-mode}: @quotation @url{http://www.dedasys.com/freesoftware/files/two-mode-mode.el} @end quotation @noindent Once installed, you can use the hybrid mode @code{lasy-mode} to edit a LaTeX file containing embedded @code{Asymptote} code (@pxref{LaTeX usage}). This mode can be enabled within @code{latex-mode} with the key sequence @code{M-x lasy-mode }. On @code{UNIX} systems, additional keywords will be generated from all @code{asy} files in the space-separated list of directories specified by the environment variable @code{ASYMPTOTE_SITEDIR}. Further documentation of @code{asy-mode} is available within @code{emacs} by pressing the sequence keys @code{C-h f asy-mode }. @cindex @code{vim} @cindex @code{asy.vim} Fans of @code{vim} can customize @code{vim} for @code{Asymptote} with @noindent @code{cp @value{Datadir}/asymptote/asy.vim ~/.vim/syntax/asy.vim} @noindent and add the following to their @code{~/.vimrc} file: @verbatim augroup filetypedetect au BufNewFile,BufRead *.asy setf asy augroup END filetype plugin on @end verbatim If any of these directories or files don't exist, just create them. To set @code{vim} up to run the current asymptote script using @code{:make} just add to @code{~/.vim/ftplugin/asy.vim}: @verbatim setlocal makeprg=asy\ % setlocal errorformat=%f:\ %l.%c:\ %m @end verbatim @cindex @code{KDE editor} @cindex @code{Kate} @cindex @code{asymptote.xml} Syntax highlighting support for the @acronym{KDE} editor @code{Kate} can be enabled by running @code{asy-kate.sh} in the @code{@value{Datadir}/asymptote} directory and putting the generated @code{asymptote.xml} file in @code{~/.kde/share/apps/katepart/syntax/}. @node Git @section Git @cindex git The following commands are needed to install the latest development version of @code{Asymptote} using @code{git}: @verbatim git clone http://github.com/vectorgraphics/asymptote cd asymptote ./autogen.sh ./configure make all make install @end verbatim @noindent To compile without optimization, use the command @code{make CFLAGS=-g}. @node Uninstall @section Uninstall @cindex Uninstall To uninstall an @code{Linux i386} binary distribution, use the commands @verbatim tar -zxvf asymptote-x.xx.i386.tgz | xargs --replace=% rm /% texhash @end verbatim @noindent To uninstall all @code{Asymptote} files installed from a source distribution, use the command @verbatim make uninstall @end verbatim @node Tutorial @chapter Tutorial @cindex tutorial @cindex batch mode @section Drawing in batch mode To draw a line from coordinate (0,0) to coordinate (100,100), create a text file @code{test.asy} containing @verbatiminclude diagonal.asy @noindent Then execute the command @verbatim asy -V test @end verbatim @noindent Alternatively, @code{MSDOS} users can drag and drop @code{test.asy} onto the Desktop @code{asy} icon (or make @code{Asymptote} the default application for the extension @code{asy}). @noindent @cindex @code{-V} This method, known as @emph{batch mode}, outputs a @code{PostScript} file @code{test.eps}. If you prefer @acronym{PDF} output, use the command line @verbatim asy -V -f pdf test @end verbatim In either case, the @code{-V} option opens up a viewer window so you can immediately view the result: @sp 1 @center @image{diagonal} @cindex @code{bp} @noindent Here, the @code{--} connector joins the two points @code{(0,0)} and @code{(100,100)} with a line segment. @section Drawing in interactive mode Another method is @emph{interactive mode}, where @code{Asymptote} reads individual commands as they are entered by the user. To try this out, enter @code{Asymptote}'s interactive mode by clicking on the @code{Asymptote} icon or typing the command @code{asy}. Then type @verbatim draw((0,0)--(100,100)); @end verbatim @noindent followed by @code{Enter}, to obtain the above image. @cindex tab completion @cindex arrow keys @cindex erase @cindex quit @noindent At this point you can type further @code{draw} commands, which will be added to the displayed figure, @code{erase} to clear the canvas, @verbatim input test; @end verbatim @noindent to execute all of the commands contained in the file @code{test.asy}, or @code{quit} to exit interactive mode. You can use the arrow keys in interactive mode to edit previous lines. The tab key will automatically complete unambiguous words; otherwise, hitting tab again will show the possible choices. Further commands specific to interactive mode are described in @ref{Interactive mode}. @section Figure size @cindex @code{pair} In @code{Asymptote}, coordinates like @code{(0,0)} and @code{(100,100)}, called @emph{pairs}, are expressed in @code{PostScript} "big points" (1 @code{bp} = 1/72 @code{inch}) and the default line width is @code{0.5bp}. However, it is often inconvenient to work directly in @code{PostScript} coordinates. The next example produces identical output to the previous example, by scaling the line @code{(0,0)--(1,1)} to fit a rectangle of width @code{100.5 bp} and height @code{100.5 bp} (the extra @code{0.5bp} accounts for the line width): @verbatim size(100.5,100.5); draw((0,0)--(1,1)); @end verbatim @sp 1 @center @image{diagonal} @cindex @code{inches} @cindex @code{cm} @cindex @code{mm} @cindex @code{pt} One can also specify the size in @code{pt} (1 @code{pt} = 1/72.27 @code{inch}), @code{cm}, @code{mm}, or @code{inches}. Two nonzero size arguments (or a single size argument) restrict the size in both directions, preserving the aspect ratio. If 0 is given as a size argument, no restriction is made in that direction; the overall scaling will be determined by the other direction (@pxref{size}): @verbatiminclude bigdiagonal.asy @sp 1 @center @image{bigdiagonal} @cindex @code{cycle} To connect several points and create a cyclic path, use the @code{cycle} keyword: @verbatiminclude square.asy @sp 1 @center @image{square} @noindent For convenience, the path @code{(0,0)--(1,0)--(1,1)--(0,1)--cycle} may be replaced with the predefined variable @code{unitsquare}, or equivalently, @code{box((0,0),(1,1))}. @cindex user coordinates @cindex @code{unitsize} To make the user coordinates represent multiples of exactly @code{1cm}: @verbatim unitsize(1cm); draw(unitsquare); @end verbatim @noindent @section Labels Adding labels is easy in @code{Asymptote}; one specifies the label as a double-quoted @code{LaTeX} string, a coordinate, and an optional alignment direction: @verbatiminclude labelsquare.asy @sp 1 @center @image{labelsquare} @cindex compass directions @cindex @code{N} @cindex @code{E} @cindex @code{W} @cindex @code{S} @code{Asymptote} uses the standard compass directions @code{E=(1,0)}, @code{N=(0,1)}, @code{NE=unit(N+E)}, and @code{ENE=unit(E+NE)}, etc., which along with the directions @code{up}, @code{down}, @code{right}, and @code{left} are defined as pairs in the @code{Asymptote} base module @code{plain} (a user who has a local variable named @code{E} may access the compass direction @code{E} by prefixing it with the name of the module where it is defined: @code{plain.E}). @section Paths This example draws a path that approximates a quarter circle, terminated with an arrowhead: @verbatiminclude quartercircle.asy @sp 1 @center @image{quartercircle} @noindent Here the directions @code{up} and @code{left} in braces specify the incoming and outgoing directions at the points @code{(1,0)} and @code{(0,1)}, respectively. In general, a path is specified as a list of points (or other paths) interconnected with @cindex @code{cycle} @cindex @code{--} @cindex @code{..} @code{--}, which denotes a straight line segment, or @code{..}, which denotes a cubic spline (@pxref{Bezier curves}). @cindex @code{unitcircle} @anchor{unitcircle} @cindex @code{unitcircle} Specifying a final @code{..cycle} creates a cyclic path that connects smoothly back to the initial node, as in this approximation (accurate to within 0.06%) of a unit circle: @verbatim path unitcircle=E..N..W..S..cycle; @end verbatim @cindex @code{PostScript} subpath @cindex @code{^^} @cindex @code{path[]} @cindex superpath @noindent An @code{Asymptote} path, being connected, is equivalent to a @code{Postscript subpath}. The @code{^^} binary operator, which requests that the pen be moved (without drawing or affecting endpoint curvatures) from the final point of the left-hand path to the initial point of the right-hand path, may be used to group several @code{Asymptote} paths into a @code{path[]} array (equivalent to a @code{PostScript} path): @verbatiminclude superpath.asy @sp 1 @center @image{superpath} @cindex evenodd @noindent The @code{PostScript} even-odd fill rule here specifies that only the region bounded between the two unit circles is filled (@pxref{fillrule}). In this example, the same effect can be achieved by using the default zero winding number fill rule, if one is careful to alternate the orientation of the paths: @verbatim filldraw(unitcircle^^reverse(g),yellow,black); @end verbatim @cindex @code{unitbox} The @code{^^} operator is used by the @code{box(triple, triple)} function in the module @code{three.asy} to construct the edges of a cube @code{unitbox} without retracing steps (@pxref{three}): @verbatiminclude cube.asy @sp 1 @center @image{cube} See section @ref{graph} (or the online @code{Asymptote} gallery and external links posted at @url{http://asymptote.sourceforge.net}) for further examples, including two-dimensional and interactive three-dimensional scientific graphs. Additional examples have been posted by Philippe Ivaldi at @url{http://www.piprime.fr/asymptote}. Excellent user-written @code{Asymptote} tutorials are also available: @url{http://www.artofproblemsolving.com/Wiki/index.php/Asymptote:_Basics} @url{http://math.uchicago.edu/~cstaats/Charles_Staats_III/Notes_and_papers_files/asymptote_tutorial.pdf} @node Drawing commands @chapter Drawing commands @cindex drawing commands All of @code{Asymptote}'s graphical capabilities are based on four primitive commands. The three @code{PostScript} drawing commands @code{draw}, @code{fill}, and @code{clip} add objects to a picture in the order in which they are executed, with the most recently drawn object appearing on top. The labeling command @code{label} can be used to add text labels and external @acronym{EPS} images, which will appear on top of the @code{PostScript} objects (since this is normally what one wants), but again in the relative order in which they were executed. After drawing objects on a picture, the picture can be output with the @code{shipout} function (@pxref{shipout}). @cindex @code{layer} If you wish to draw @code{PostScript} objects on top of labels (or verbatim @code{tex} commands; @pxref{tex}), the @code{layer} command may be used to start a new @code{PostScript/LaTeX} layer: @verbatim void layer(picture pic=currentpicture); @end verbatim The @code{layer} function gives one full control over the order in which objects are drawn. Layers are drawn sequentially, with the most recent layer appearing on top. Within each layer, labels, images, and verbatim @code{tex} commands are always drawn after the @code{PostScript} objects in that layer. While some of these drawing commands take many options, they all have sensible default values (for example, the picture argument defaults to currentpicture). @cindex legend @cindex @code{draw} @cindex @code{arrow} @menu * draw:: Draw a path on a picture or frame * fill:: Fill a cyclic path on a picture or frame * clip:: Clip a picture or frame to a cyclic path * label:: Label a point on a picture @end menu @node draw @section draw @verbatim void draw(picture pic=currentpicture, Label L="", path g, align align=NoAlign, pen p=currentpen, arrowbar arrow=None, arrowbar bar=None, margin margin=NoMargin, Label legend="", marker marker=nomarker); @end verbatim Draw the path @code{g} on the picture @code{pic} using pen @code{p} for drawing, with optional drawing attributes (Label @code{L}, explicit label alignment @code{align}, arrows and bars @code{arrow} and @code{bar}, margins @code{margin}, legend, and markers @code{marker}). Only one parameter, the path, is required. For convenience, the arguments @code{arrow} and @code{bar} may be specified in either order. The argument @code{legend} is a Label to use in constructing an optional legend entry. @cindex @code{None} @cindex @code{BeginBar} @cindex @code{EndBar} @cindex @code{Bar} @cindex @code{Bars} @cindex @code{barsize} Bars are useful for indicating dimensions. The possible values of @code{bar} are @code{None}, @code{BeginBar}, @code{EndBar} (or equivalently @code{Bar}), and @code{Bars} (which draws a bar at both ends of the path). Each of these bar specifiers (except for @code{None}) will accept an optional real argument that denotes the length of the bar in @code{PostScript} coordinates. The default bar length is @code{barsize(pen)}. @cindex arrows @anchor{arrows} @cindex @code{None} @cindex @code{Blank} @cindex @code{BeginArrow} @cindex @code{MidArrow} @cindex @code{EndArrow} @cindex @code{Arrow} @cindex @code{Arrows} @cindex @code{FillDraw} @cindex @code{Fill} @cindex @code{Draw} @cindex @code{NoFill} @cindex @code{UnFill} @cindex @code{BeginArcArrow} @cindex @code{MidArcArrow} @cindex @code{EndArcArrow} @cindex @code{ArcArrow} @cindex @code{ArcArrows} @cindex @code{DefaultHead} @cindex @code{SimpleHead} @cindex @code{HookHead} @cindex @code{TeXHead} The possible values of @code{arrow} are @code{None}, @code{Blank} (which draws no arrows or path), @code{BeginArrow}, @code{MidArrow}, @code{EndArrow} (or equivalently @code{Arrow}), and @code{Arrows} (which draws an arrow at both ends of the path). All of the arrow specifiers except for @code{None} and @code{Blank} may be given the optional arguments arrowhead @code{arrowhead} (one of the predefined arrowhead styles @code{DefaultHead}, @code{SimpleHead}, @code{HookHead}, @code{TeXHead}), real @code{size} (arrowhead size in @code{PostScript} coordinates), real @code{angle} (arrowhead angle in degrees), filltype @code{filltype} (one of @code{FillDraw}, @code{Fill}, @code{NoFill}, @code{UnFill}, @code{Draw}) and (except for @code{MidArrow} and @code{Arrows}) a real @code{position} (in the sense of @code{point(path p, real t)}) along the path where the tip of the arrow should be placed. The default arrowhead size when drawn with a pen @code{p} is @code{arrowsize(p)}. There are also arrow versions with slightly modified default values of @code{size} and @code{angle} suitable for curved arrows: @code{BeginArcArrow}, @code{EndArcArrow} (or equivalently @code{ArcArrow}), @code{MidArcArrow}, and @code{ArcArrows}. @cindex @code{NoMargin} @cindex @code{BeginMargin} @cindex @code{EndMargin} @cindex @code{Margin} @cindex @code{Margins} @cindex @code{BeginPenMargin} @cindex @code{EndPenMargin} @cindex @code{PenMargin} @cindex @code{PenMargins} @cindex @code{BeginDotMargin} @cindex @code{EndDotMargin} @cindex @code{DotMargin} @cindex @code{DotMargins} @cindex @code{Margin} @cindex @code{TrueMargin} Margins can be used to shrink the visible portion of a path by @code{labelmargin(p)} to avoid overlap with other drawn objects. Typical values of @code{margin} are @code{NoMargin}, @code{BeginMargin}, @code{EndMargin} (or equivalently @code{Margin}), and @code{Margins} (which leaves a margin at both ends of the path). One may use @code{Margin(real begin, real end)} to specify the size of the beginning and ending margin, respectively, in multiples of the units @code{labelmargin(p)} used for aligning labels. Alternatively, @code{BeginPenMargin}, @code{EndPenMargin} (or equivalently @code{PenMargin}), @code{PenMargins}, @code{PenMargin(real begin, real end)} specify a margin in units of the pen line width, taking account of the pen line width when drawing the path or arrow. For example, use @code{DotMargin}, an abbreviation for @code{PenMargin(-0.5*dotfactor,0.5*dotfactor)}, to draw from the usual beginning point just up to the boundary of an end dot of width @code{dotfactor*linewidth(p)}. The qualifiers @code{BeginDotMargin}, @code{EndDotMargin}, and @code{DotMargins} work similarly. The qualifier @code{TrueMargin(real begin, real end)} allows one to specify a margin directly in @code{PostScript} units, independent of the pen line width. The use of arrows, bars, and margins is illustrated by the examples @code{Pythagoras.asy}, @code{sqrtx01.asy}, and @code{triads.asy}. The legend for a picture @code{pic} can be fit and aligned to a frame with the routine: @cindex @code{legend} @verbatim frame legend(picture pic=currentpicture, int perline=1, real xmargin=legendmargin, real ymargin=xmargin, real linelength=legendlinelength, real hskip=legendhskip, real vskip=legendvskip, real maxwidth=0, real maxheight=0, bool hstretch=false, bool vstretch=false, pen p=currentpen); @end verbatim @noindent Here @code{xmargin} and @code{ymargin} specify the surrounding @math{x} and @math{y} margins, @code{perline} specifies the number of entries per line (default 1; 0 means choose this number automatically), @code{linelength} specifies the length of the path lines, @code{hskip} and @code{vskip} specify the line skip (as a multiple of the legend entry size), @code{maxwidth} and @code{maxheight} specify optional upper limits on the width and height of the resulting legend (0 means unlimited), @code{hstretch} and @code{vstretch} allow the legend to stretch horizontally or vertically, and @code{p} specifies the pen used to draw the bounding box. The legend frame can then be added and aligned about a point on a picture @code{dest} using @code{add} or @code{attach} (@pxref{add about}). @cindex @code{dot} To draw a dot, simply draw a path containing a single point. The @code{dot} command defined in the module @code{plain} draws a dot having a diameter equal to an explicit pen line width or the default line width magnified by @code{dotfactor} (6 by default), using the specified filltype (@pxref{filltype}): @verbatim void dot(picture pic=currentpicture, pair z, pen p=currentpen, filltype filltype=Fill); void dot(picture pic=currentpicture, Label L, pair z, align align=NoAlign, string format=defaultformat, pen p=currentpen, filltype filltype=Fill); void dot(picture pic=currentpicture, Label[] L=new Label[], pair[] z, align align=NoAlign, string format=defaultformat, pen p=currentpen, filltype filltype=Fill) void dot(picture pic=currentpicture, Label L, pen p=currentpen, filltype filltype=Fill); @end verbatim @cindex @code{Label} If the variable @code{Label} is given as the @code{Label} argument to the second routine, the @code{format} argument will be used to format a string based on the dot location (here @code{defaultformat} is @code{"$%.4g$"}). The third routine draws a dot at every point of a pair array @code{z}. One can also draw a dot at every node of a path: @verbatim void dot(picture pic=currentpicture, Label[] L=new Label[], path g, align align=RightSide, string format=defaultformat, pen p=currentpen, filltype filltype=Fill); @end verbatim See @ref{pathmarkers} and @ref{markers} for more general methods for marking path nodes. To draw a fixed-sized object (in @code{PostScript} coordinates) about the user coordinate @code{origin}, use the routine @cindex @code{draw} @verbatim void draw(pair origin, picture pic=currentpicture, Label L="", path g, align align=NoAlign, pen p=currentpen, arrowbar arrow=None, arrowbar bar=None, margin margin=NoMargin, Label legend="", marker marker=nomarker); @end verbatim @cindex @code{fill} @node fill @section fill @verbatim void fill(picture pic=currentpicture, path g, pen p=currentpen); @end verbatim Fill the interior region bounded by the cyclic path @code{g} on the picture @code{pic}, using the pen @code{p}. @cindex @code{filldraw} There is also a convenient @code{filldraw} command, which fills the path and then draws in the boundary. One can specify separate pens for each operation: @verbatim void filldraw(picture pic=currentpicture, path g, pen fillpen=currentpen, pen drawpen=currentpen); @end verbatim @cindex @code{fill} This fixed-size version of @code{fill} allows one to fill an object described in @code{PostScript} coordinates about the user coordinate @code{origin}: @verbatim void fill(pair origin, picture pic=currentpicture, path g, pen p=currentpen); @end verbatim @noindent This is just a convenient abbreviation for the commands: @verbatim picture opic; fill(opic,g,p); add(pic,opic,origin); @end verbatim The routine @cindex @code{filloutside} @verbatim void filloutside(picture pic=currentpicture, path g, pen p=currentpen); @end verbatim @noindent fills the region exterior to the path @code{g}, out to the current boundary of picture @code{pic}. @anchor{gradient shading} @cindex gradient shading @cindex shading @cindex @code{latticeshade} Lattice gradient shading varying smoothly over a two-dimensional array of pens @code{p}, using fill rule @code{fillrule}, can be produced with @verbatim void latticeshade(picture pic=currentpicture, path g, bool stroke=false, pen fillrule=currentpen, pen[][] p) @end verbatim @cindex @code{stroke} If @code{stroke=true}, the region filled is the same as the region that would be drawn by @code{draw(pic,g,fillrule+zerowinding)}; in this case the path @code{g} need not be cyclic. The pens in @code{p} must belong to the same color space. One can use the functions @code{rgb(pen)} or @code{cmyk(pen)} to promote pens to a higher color space, as illustrated in the example file @code{latticeshading.asy}. @cindex @code{axialshade} Axial gradient shading varying smoothly from @code{pena} to @code{penb} in the direction of the line segment @code{a--b} can be achieved with @verbatim void axialshade(picture pic=currentpicture, path g, bool stroke=false, pen pena, pair a, bool extenda=true, pen penb, pair b, bool extendb=true); @end verbatim @noindent The boolean parameters @code{extenda} and @code{extendb} indicate whether the shading should extend beyond the axis endpoints @code{a} and @code{b}. @cindex @code{radialshade} Radial gradient shading varying smoothly from @code{pena} on the circle with center @code{a} and radius @code{ra} to @code{penb} on the circle with center @code{b} and radius @code{rb} is similar: @verbatim void radialshade(picture pic=currentpicture, path g, bool stroke=false, pen pena, pair a, real ra, bool extenda=true, pen penb, pair b, real rb, bool extendb=true); @end verbatim @noindent The boolean parameters @code{extenda} and @code{extendb} indicate whether the shading should extend beyond the radii @code{a} and @code{b}. Illustrations of radial shading are provided in the example files @code{shade.asy}, @code{ring.asy}, and @code{shadestroke.asy}. @cindex @code{gouraudshade} Gouraud shading using fill rule @code{fillrule} and the vertex colors in the pen array @code{p} on a triangular lattice defined by the vertices @code{z} and edge flags @code{edges} is implemented with @verbatim void gouraudshade(picture pic=currentpicture, path g, bool stroke=false, pen fillrule=currentpen, pen[] p, pair[] z, int[] edges); void gouraudshade(picture pic=currentpicture, path g, bool stroke=false, pen fillrule=currentpen, pen[] p, int[] edges); @end verbatim @noindent In the second form, the elements of @code{z} are taken to be successive nodes of path @code{g}. The pens in @code{p} must belong to the same color space. Illustrations of Gouraud shading are provided in the example file @code{Gouraud.asy} and in the solid geometry module @code{solids.asy}. The edge flags used in Gouraud shading are documented here: @quotation @url{http://partners.adobe.com/public/developer/en/ps/sdk/TN5600.SmoothShading.pdf}. @end quotation @cindex Coons shading @cindex tensor product shading @cindex @code{tensorshade} Tensor product shading using fill rule @code{fillrule} on patches bounded by the @math{n} cyclic paths of length 4 in path array @code{b}, using the vertex colors specified in the @math{n \times 4} pen array @code{p} and internal control points in the @math{n \times 4} array @code{z}, is implemented with @verbatim void tensorshade(picture pic=currentpicture, path[] g, bool stroke=false, pen fillrule=currentpen, pen[][] p, path[] b=g, pair[][] z=new pair[][]); @end verbatim @noindent If the array @code{z} is empty, Coons shading, in which the color control points are calculated automatically, is used. The pens in @code{p} must belong to the same color space. A simpler interface for the case of a single patch (@math{n=1}) is also available: @verbatim void tensorshade(picture pic=currentpicture, path g, bool stroke=false, pen fillrule=currentpen, pen[] p, path b=g, pair[] z=new pair[]); @end verbatim One can also smoothly shade the regions between consecutive paths of a sequence using a given array of pens: @verbatim void draw(picture pic=currentpicture, pen fillrule=currentpen, path[] g, pen[] p); @end verbatim @noindent Illustrations of tensor product and Coons shading are provided in the example files @code{tensor.asy}, @code{Coons.asy}, @code{BezierSurface.asy}, and @code{rainbow.asy}. @cindex Function shading @cindex function shading @cindex @code{functionshade} More general shading possibilities are available using @TeX{} engines that produce PDF output (@pxref{texengines}): the routine @verbatim void functionshade(picture pic=currentpicture, path[] g, bool stroke=false, pen fillrule=currentpen, string shader); @end verbatim @noindent shades on picture @code{pic} the interior of path @code{g} according to fill rule @code{fillrule} using the @code{PostScript} calculator routine specified by the string @code{shader}; this routine takes 2 arguments, each in [0,1], and returns @code{colors(fillrule).length} color components. Function shading is illustrated in the example @code{functionshading.asy}. @cindex unfill The following routine uses @code{evenodd} clipping together with the @code{^^} operator to unfill a region: @verbatim void unfill(picture pic=currentpicture, path g); @end verbatim @cindex @code{clip} @cindex @code{stroke} @node clip @section clip @verbatim void clip(picture pic=currentpicture, path g, stroke=false, pen fillrule=currentpen); @end verbatim Clip the current contents of picture @code{pic} to the region bounded by the path @code{g}, using fill rule @code{fillrule} (@pxref{fillrule}). If @code{stroke=true}, the clipped portion is the same as the region that would be drawn with @code{draw(pic,g,fillrule+zerowinding)}; in this case the path @code{g} need not be cyclic. For an illustration of picture clipping, see the first example in @ref{LaTeX usage}. @cindex @code{label} @node label @section label @verbatim void label(picture pic=currentpicture, Label L, pair position, align align=NoAlign, pen p=currentpen, filltype filltype=NoFill) @end verbatim Draw Label @code{L} on picture @code{pic} using pen @code{p}. If @code{align} is @code{NoAlign}, the label will be centered at user coordinate @code{position}; otherwise it will be aligned in the direction of @code{align} and displaced from @code{position} by the @code{PostScript} offset @code{align*labelmargin(p)}. @cindex @code{Align} The constant @code{Align} can be used to align the bottom-left corner of the label at @code{position}. @cindex @code{nullpen} @cindex @code{Label} @anchor{Label} The Label @code{L} can either be a string or the structure obtained by calling one of the functions @verbatim Label Label(string s="", pair position, align align=NoAlign, pen p=nullpen, embed embed=Rotate, filltype filltype=NoFill); Label Label(string s="", align align=NoAlign, pen p=nullpen, embed embed=Rotate, filltype filltype=NoFill); Label Label(Label L, pair position, align align=NoAlign, pen p=nullpen, embed embed=L.embed, filltype filltype=NoFill); Label Label(Label L, align align=NoAlign, pen p=nullpen, embed embed=L.embed, filltype filltype=NoFill); @end verbatim The text of a Label can be scaled, slanted, rotated, or shifted by multiplying it on the left by an affine transform (@pxref{Transforms}). For example, @code{rotate(45)*xscale(2)*L} first scales @code{L} in the @math{x} direction and then rotates it counterclockwise by 45 degrees. The final position of a Label can also be shifted by a @code{PostScript} coordinate translation: @code{shift(10,0)*L}. An explicit pen specified within the Label overrides other pen arguments. The @code{embed} argument determines how the Label should transform with the embedding picture: @table @code @item Shift @cindex @code{Shift} only shift with embedding picture; @item Rotate @cindex @code{Rotate} only shift and rotate with embedding picture (default); @item Rotate(pair z) @cindex @code{Rotate(pair z)} rotate with (picture-transformed) vector @code{z}. @item Slant @cindex @code{Slant} only shift, rotate, slant, and reflect with embedding picture; @item Scale @cindex @code{Scale} shift, rotate, slant, reflect, and scale with embedding picture. @end table To add a label to a path, use @verbatim void label(picture pic=currentpicture, Label L, path g, align align=NoAlign, pen p=currentpen, filltype filltype=NoFill); @end verbatim @cindex @code{Relative} By default the label will be positioned at the midpoint of the path. An alternative label position (in the sense of @code{point(path p, real t)}) may be specified as a real value for @code{position} in constructing the Label. The position @code{Relative(real)} specifies a location relative to the total arclength of the path. These convenient abbreviations are predefined: @cindex @code{BeginPoint} @cindex @code{MidPoint} @cindex @code{EndPoint} @verbatim position BeginPoint=Relative(0); position MidPoint=Relative(0.5); position EndPoint=Relative(1); @end verbatim @cindex @code{Relative} @cindex @code{LeftSide} @cindex @code{Center} @cindex @code{RightSide} Path labels are aligned in the direction @code{align}, which may be specified as an absolute compass direction (pair) or a direction @code{Relative(pair)} measured relative to a north axis in the local direction of the path. For convenience @code{LeftSide}, @code{Center}, and @code{RightSide} are defined as @code{Relative(W)}, @code{Relative((0,0))}, and @code{Relative(E)}, respectively. Multiplying @code{LeftSide} and @code{RightSide} on the left by a real scaling factor will move the label further away from or closer to the path. A label with a fixed-size arrow of length @code{arrowlength} pointing to @code{b} from direction @code{dir} can be produced with the routine @cindex @code{arrow} @verbatim void arrow(picture pic=currentpicture, Label L="", pair b, pair dir, real length=arrowlength, align align=NoAlign, pen p=currentpen, arrowbar arrow=Arrow, margin margin=EndMargin); @end verbatim If no alignment is specified (either in the Label or as an explicit argument), the optional Label will be aligned in the direction @code{dir}, using margin @code{margin}. @cindex including images @cindex @code{graphic} @cindex @acronym{EPS} The function @code{string graphic(string name, string options="")} returns a string that can be used to include an encapsulated @code{PostScript} (@acronym{EPS}) file. Here, @code{name} is the name of the file to include and @code{options} is a string containing a comma-separated list of optional bounding box (@code{bb=llx lly urx ury}), width (@code{width=value}), height (@code{height=value}), rotation (@code{angle=value}), scaling (@code{scale=factor}), clipping (@code{clip=bool}), and draft mode (@code{draft=bool}) parameters. The @code{layer()} function can be used to force future objects to be drawn on top of the included image: @verbatim label(graphic("file.eps","width=1cm"),(0,0),NE); layer(); @end verbatim @cindex @code{baseline} The @code{string baseline(string s, string template="\strut")} function can be used to enlarge the bounding box of labels to match a given template, so that their baselines will be typeset on a horizontal line. See @code{Pythagoras.asy} for an example. One can prevent labels from overwriting one another with the @code{overwrite} pen attribute (@pxref{overwrite}). The structure @code{object} defined in @code{plain_Label.asy} allows Labels and frames to be treated in a uniform manner. A group of objects may be packed together into single frame with the routine @cindex @code{pack} @verbatim frame pack(pair align=2S ... object inset[]); @end verbatim @noindent To draw or fill a box (or ellipse or other path) around a Label and return the bounding object, use one of the routines @verbatim object draw(picture pic=currentpicture, Label L, envelope e, real xmargin=0, real ymargin=xmargin, pen p=currentpen, filltype filltype=NoFill, bool above=true); object draw(picture pic=currentpicture, Label L, envelope e, pair position, real xmargin=0, real ymargin=xmargin, pen p=currentpen, filltype filltype=NoFill, bool above=true); @end verbatim @noindent Here @code{envelope} is a boundary-drawing routine such as @code{box}, @code{roundbox}, or @code{ellipse} defined in @code{plain_boxes.asy} (@pxref{envelope}). @cindex @code{texpath} The function @code{path[] texpath(Label L)} returns the path array that @TeX{} would fill to draw the Label @code{L}. @cindex @code{minipage} The @code{string minipage(string s, width=100pt)} function can be used to format string @code{s} into a paragraph of width @code{width}. This example uses @code{minipage}, @code{clip}, and @code{graphic} to produce a CD label: @sp 1 @center @image{CDlabel} @verbatiminclude CDlabel.asy @node Bezier curves @chapter Bezier curves @cindex Bezier curves @cindex direction specifier Each interior node of a cubic spline may be given a direction prefix or suffix @code{@{dir@}}: the direction of the pair @code{dir} specifies the direction of the incoming or outgoing tangent, respectively, to the curve at that node. Exterior nodes may be given direction specifiers only on their interior side. A cubic spline between the node @math{z_0}, with postcontrol point @math{c_0}, and the node @math{z_1}, with precontrol point @math{c_1}, is computed as the Bezier curve @sp 1 @center @image{bezier,,,(1-t)^3*z_0+3t(1-t)^2*c_0+3t^2(1-t)*c_1+t^3*z_1 for 0 <=t <= 1.} As illustrated in the diagram below, the third-order midpoint (@math{m_5}) constructed from two endpoints @math{z_0} and @math{z_1} and two control points @math{c_0} and @math{c_1}, is the point corresponding to @math{t=1/2} on the Bezier curve formed by the quadruple (@math{z_0}, @math{c_0}, @math{c_1}, @math{z_1}). This allows one to recursively construct the desired curve, by using the newly extracted third-order midpoint as an endpoint and the respective second- and first-order midpoints as control points: @sp 1 @center @image{bezier2} Here @math{m_0}, @math{m_1} and @math{m_2} are the first-order midpoints, @math{m_3} and @math{m_4} are the second-order midpoints, and @math{m_5} is the third-order midpoint. The curve is then constructed by recursively applying the algorithm to (@math{z_0}, @math{m_0}, @math{m_3}, @math{m_5}) and (@math{m_5}, @math{m_4}, @math{m_2}, @math{z_1}). In fact, an analogous property holds for points located at any fraction @math{t} in @math{[0,1]} of each segment, not just for midpoints (@math{t=1/2}). The Bezier curve constructed in this manner has the following properties: @itemize @bullet @item It is entirely contained in the convex hull of the given four points. @item It starts heading from the first endpoint to the first control point and finishes heading from the second control point to the second endpoint. @end itemize @cindex @code{controls} The user can specify explicit control points between two nodes like this: @verbatim draw((0,0)..controls (0,100) and (100,100)..(100,0)); @end verbatim However, it is usually more convenient to just use the @code{..} operator, which tells @code{Asymptote} to choose its own control points using the algorithms described in Donald Knuth's monograph, The MetaFontbook, Chapter 14. The user can still customize the guide (or path) by specifying direction, tension, and curl values. The higher the tension, the straighter the curve is, and the more it approximates a straight line. @cindex @code{tension} @cindex @code{and} @cindex @code{atleast} One can change the spline tension from its default value of 1 to any real value greater than or equal to 0.75 (cf. John D. Hobby, Discrete and Computational Geometry 1, 1986): @verbatim draw((100,0)..tension 2 ..(100,100)..(0,100)); draw((100,0)..tension 3 and 2 ..(100,100)..(0,100)); draw((100,0)..tension atleast 2 ..(100,100)..(0,100)); @end verbatim In these examples there is a space between @code{2} and @code{..}. This is needed as @code{2.} is interpreted as a numerical constant. @cindex @code{curl} The curl parameter specifies the curvature at the endpoints of a path (0 means straight; the default value of 1 means approximately circular): @verbatim draw((100,0){curl 0}..(100,100)..{curl 0}(0,100)); @end verbatim @cindex @code{MetaPost ...@ } @cindex @code{::} The @code{MetaPost ...} path connector, which requests, when possible, an inflection-free curve confined to a triangle defined by the endpoints and directions, is implemented in @code{Asymptote} as the convenient abbreviation @code{::} for @code{..tension atleast 1 ..} (the ellipsis @code{...} is used in @code{Asymptote} to indicate a variable number of arguments; @pxref{Rest arguments}). For example, compare @verbatiminclude dots.asy @sp 1 @center @image{dots} @noindent with @verbatiminclude colons.asy @sp 1 @center @image{colons} @cindex @code{---} @cindex @code{&} The @code{---} connector is an abbreviation for @code{..tension atleast infinity..} and the @code{&} connector concatenates two paths, after first stripping off the last node of the first path (which normally should coincide with the first node of the second path). @node Programming @chapter Programming @cindex programming Here is a short introductory example to the @code{Asymptote} programming language that highlights the similarity of its control structures with those of C, C++, and Java: @cindex declaration @cindex assignment @cindex conditional @cindex loop @cindex @code{if} @cindex @code{else} @cindex @code{for} @verbatim // This is a comment. // Declaration: Declare x to be a real variable; real x; // Assignment: Assign the real variable x the value 1. x=1.0; // Conditional: Test if x equals 1 or not. if(x == 1.0) { write("x equals 1.0"); } else { write("x is not equal to 1.0"); } // Loop: iterate 10 times for(int i=0; i < 10; ++i) { write(i); } @end verbatim @cindex @code{while} @cindex @code{do} @cindex @code{break} @cindex @code{continue} @code{Asymptote} supports @code{while}, @code{do}, @code{break}, and @code{continue} statements just as in C/C++. It also supports the Java-style shorthand for iterating over all elements of an array: @cindex array iteration @anchor{array iteration} @verbatim // Iterate over an array int[] array={1,1,2,3,5}; for(int k : array) { write(k); } @end verbatim @noindent In addition, it supports many features beyond the ones found in those languages. @menu * Data types:: void, bool, int, real, pair, triple, string * Paths and guides:: Bezier curves * Pens:: Colors, line types, line widths, font sizes * Transforms:: Affine transforms * Frames and pictures:: Canvases for immediate and deferred drawing * Files:: Reading and writing your data * Variable initializers:: Initialize your variables * Structures:: Organize your data * Operators:: Arithmetic and logical operators * Implicit scaling:: Avoiding those ugly *s * Functions:: Traditional and high-order functions * Arrays:: Dynamic vectors * Casts:: Implicit and explicit casts * Import:: Importing external @code{Asymptote} modules * Static:: Where to allocate your variable? @end menu @node Data types @section Data types @cindex data types @code{Asymptote} supports the following data types (in addition to user-defined types): @table @code @item void @cindex @code{void} The void type is used only by functions that take or return no arguments. @item bool @cindex @code{bool} a boolean type that can only take on the values @code{true} or @code{false}. For example: @verbatim bool b=true; @end verbatim @noindent defines a boolean variable @code{b} and initializes it to the value @code{true}. If no initializer is given: @verbatim bool b; @end verbatim @noindent the value @code{false} is assumed. @item bool3 @cindex @code{bool3} an extended boolean type that can take on the values @code{true}, @code{default}, or @code{false}. A bool3 type can be cast to or from a bool. The default initializer for bool3 is @code{default}. @item int @cindex @code{int} @cindex @code{intMin} @cindex @code{intMax} an integer type; if no initializer is given, the implicit value @code{0} is assumed. The minimum allowed value of an integer is @code{intMin} and the maximum value is @code{intMax}. @item real @cindex @code{real} @cindex @code{realMin} @cindex @code{realMax} @cindex @code{realEpsilon} @cindex @code{realDigits} @cindex @code{mask} @cindex @code{inf} @cindex @code{nan} @cindex @code{isnan} a real number; this should be set to the highest-precision native floating-point type on the architecture. The implicit initializer for reals is @code{0.0}. Real numbers have precision @code{realEpsilon}, with @code{realDigits} significant digits. The smallest positive real number is @code{realMin} and the largest positive real number is @code{realMax}. The variables @code{inf} and @code{nan}, along with the function @code{bool isnan(real x)} are useful when floating-point exceptions are masked with the @code{-mask} command-line option (the default in interactive mode). @item pair @cindex @code{pair} complex number, that is, an ordered pair of real components @code{(x,y)}. The real and imaginary parts of a pair @code{z} can read as @code{z.x} and @code{z.y}. We say that @code{x} and @code{y} are virtual members of the data element pair; they cannot be directly modified, however. The implicit initializer for pairs is @code{(0.0,0.0)}. There are a number of ways to take the complex conjugate of a pair: @example pair z=(3,4); z=(z.x,-z.y); z=z.x-I*z.y; z=conj(z); @end example Here @code{I} is the pair @code{(0,1)}. A number of built-in functions are defined for pairs: @table @code @item pair conj(pair z) @cindex @code{conj} returns the conjugate of @code{z}; @item real length(pair z) @cindex @code{length} @cindex @code{abs} returns the complex modulus @code{|z|} of its argument @code{z}. For example, @example pair z=(3,4); length(z); @end example returns the result 5. A synonym for @code{length(pair)} is @code{abs(pair)}; @item real angle(pair z, bool warn=true) @cindex @code{angle} returns the angle of @code{z} in radians in the interval [-@code{pi},@code{pi}] or @code{0} if @code{warn} is @code{false} and @code{z=(0,0)} (rather than producing an error); @item real degrees(pair z, bool warn=true) @cindex @code{degrees} returns the angle of @code{z} in degrees in the interval [0,360) or @code{0} if @code{warn} is @code{false} and @code{z=(0,0)} (rather than producing an error); @item pair unit(pair z) @cindex @code{unit} returns a unit vector in the direction of the pair @code{z}; @item pair expi(real angle) @cindex @code{expi} returns a unit vector in the direction @code{angle} measured in radians; @item pair dir(real degrees) @cindex @code{dir} returns a unit vector in the direction @code{degrees} measured in degrees; @item real xpart(pair z) @cindex @code{xpart} returns @code{z.x}; @item real ypart(pair z) @cindex @code{ypart} returns @code{z.y}; @item pair realmult(pair z, pair w) @cindex @code{realmult} returns the element-by-element product @code{(z.x*w.x,z.y*w.y)}; @item real dot(explicit pair z, explicit pair w) @cindex @code{dot} returns the dot product @code{z.x*w.x+z.y*w.y}; @item real cross(explicit pair z, explicit pair w) @cindex @code{cross} returns the 2D scalar product @code{z.x*w.y-z.y*w.x}; @cindex @code{orient} @item real orient(pair a, pair b, pair c); returns a positive (negative) value if @code{a--b--c--cycle} is oriented counterclockwise (clockwise) or zero if all three points are colinear. Equivalently, a positive (negative) value is returned if @code{c} lies to the left (right) of the line through @code{a} and @code{b} or zero if @code{c} lies on this line. The value returned can be expressed in terms of the 2D scalar cross product as @code{cross(a-c,b-c)}, which is the determinant @verbatim |a.x a.y 1| |b.x b.y 1| |c.x c.y 1| @end verbatim @cindex @code{incircle} @item real incircle(pair a, pair b, pair c, pair d); returns a positive (negative) value if @code{d} lies inside (outside) the circle passing through the counterclockwise-oriented points @code{a,b,c} or zero if @code{d} lies on the this circle. The value returned is the determinant @verbatim |a.x a.y a.x^2+a.y^2 1| |b.x b.y b.x^2+b.y^2 1| |c.x c.y c.x^2+c.y^2 1| |d.x d.y d.x^2+d.y^2 1| @end verbatim @item pair minbound(pair z, pair w) @cindex @code{minbound} returns @code{(min(z.x,w.x),min(z.y,w.y))}; @item pair maxbound(pair z, pair w) @cindex @code{maxbound} returns @code{(max(z.x,w.x),max(z.y,w.y))}. @end table @item triple @cindex @code{triple} an ordered triple of real components @code{(x,y,z)} used for three-dimensional drawings. The respective components of a triple @code{v} can read as @code{v.x}, @code{v.y}, and @code{v.z}. The implicit initializer for triples is @code{(0.0,0.0,0.0)}. Here are the built-in functions for triples: @table @code @item real length(triple v) @cindex @code{length} returns the length @code{|v|} of the vector @code{v}. A synonym for @code{length(triple)} is @code{abs(triple)}; @item real polar(triple v, bool warn=true) @cindex @code{polar} returns the colatitude of @code{v} measured from the @math{z} axis in radians or @code{0} if @code{warn} is @code{false} and @code{v=O} (rather than producing an error); @item real azimuth(triple v, bool warn=true) @cindex @code{azimuth} returns the longitude of @code{v} measured from the @math{x} axis in radians or @code{0} if @code{warn} is @code{false} and @code{v.x=v.y=0} (rather than producing an error); @item real colatitude(triple v, bool warn=true) @cindex @code{colatitude} returns the colatitude of @code{v} measured from the @math{z} axis in degrees or @code{0} if @code{warn} is @code{false} and @code{v=O} (rather than producing an error); @item real latitude(triple v, bool warn=true) @cindex @code{latitude} returns the latitude of @code{v} measured from the @math{xy} plane in degrees or @code{0} if @code{warn} is @code{false} and @code{v=O} (rather than producing an error); @item real longitude(triple v, bool warn=true) @cindex @code{longitude} returns the longitude of @code{v} measured from the @math{x} axis in degrees or @code{0} if @code{warn} is @code{false} and @code{v.x=v.y=0} (rather than producing an error); @item triple unit(triple v) @cindex @code{unit} returns a unit triple in the direction of the triple @code{v}; @item triple expi(real polar, real azimuth) @cindex @code{expi} returns a unit triple in the direction @code{(polar,azimuth)} measured in radians; @item triple dir(real colatitude, real longitude) @cindex @code{dir} returns a unit triple in the direction @code{(colatitude,longitude)} measured in degrees; @item real xpart(triple v) @cindex @code{xpart} returns @code{v.x}; @item real ypart(triple v) @cindex @code{ypart} returns @code{v.y}; @item real zpart(triple v) @cindex @code{zpart} returns @code{v.z}; @item real dot(triple u, triple v) @cindex @code{dot} returns the dot product @code{u.x*v.x+u.y*v.y+u.z*v.z}; @item triple cross(triple u, triple v) @cindex @code{cross} returns the cross product @code{(u.y*v.z-u.z*v.y,u.z*v.x-u.x*v.z,u.x*v.y-v.x*u.y)}; @item triple minbound(triple u, triple v) @cindex @code{minbound} returns @code{(min(u.x,v.x),min(u.y,v.y),min(u.z,v.z))}; @item triple maxbound(triple u, triple v) @cindex @code{maxbound} returns @code{(max(u.x,v.x),max(u.y,v.y),max(u.z,v.z)}). @end table @item string @cindex @code{string} @cindex @TeX{} string a character string, implemented using the STL @code{string} class. Strings delimited by double quotes (@code{"}) are subject to the following mappings to allow the use of double quotes in @TeX{} (e.g.@ for using the @code{babel} package, @pxref{babel}): @itemize @bullet @item \" maps to " @item \\ maps to \\ @end itemize @cindex @code{C} string Strings delimited by single quotes (@code{'}) have the same mappings as character strings in ANSI @code{C}: @itemize @bullet @item \' maps to ' @item \" maps to " @item \? maps to ? @item \\ maps to backslash @item \a maps to alert @item \b maps to backspace @item \f maps to form feed @item \n maps to newline @item \r maps to carriage return @item \t maps to tab @item \v maps to vertical tab @item \0-\377 map to corresponding octal byte @item \x0-\xFF map to corresponding hexadecimal byte @end itemize The implicit initializer for strings is the empty string @code{""}. Strings may be concatenated with the @code{+} operator. In the following string functions, position @code{0} denotes the start of the string: @table @code @cindex @code{length} @item int length(string s) returns the length of the string @code{s}; @cindex @code{find} @item int find(string s, string t, int pos=0) returns the position of the first occurrence of string @code{t} in string @code{s} at or after position @code{pos}, or -1 if @code{t} is not a substring of @code{s}; @cindex @code{rfind} @item int rfind(string s, string t, int pos=-1) returns the position of the last occurrence of string @code{t} in string @code{s} at or before position @code{pos} (if @code{pos}=-1, at the end of the string @code{s}), or -1 if @code{t} is not a substring of @code{s}; @cindex @code{insert} @item string insert(string s, int pos, string t) returns the string formed by inserting string @code{t} at position @code{pos} in @code{s}; @cindex @code{erase} @item string erase(string s, int pos, int n) returns the string formed by erasing the string of length @code{n} (if @code{n}=-1, to the end of the string @code{s}) at position @code{pos} in @code{s}; @cindex @code{substr} @item string substr(string s, int pos, int n=-1) returns the substring of @code{s} starting at position @code{pos} and of length @code{n} (if @code{n}=-1, until the end of the string @code{s}); @cindex @code{reverse} @item string reverse(string s) returns the string formed by reversing string @code{s}; @item string replace(string s, string before, string after) @cindex @code{replace} returns a string with all occurrences of the string @code{before} in the string @code{s} changed to the string @code{after}; @item string replace(string s, string[][] table) returns a string constructed by translating in string @code{s} all occurrences of the string @code{before} in an array @code{table} of string pairs @{@code{before},@code{after}@} to the corresponding string @code{after}; @cindex @code{split} @item string[] split(string s, string delimiter="") returns an array of strings obtained by splitting @code{s} into substrings delimited by @code{delimiter} (an empty delimiter signifies a space, but with duplicate delimiters discarded); @anchor{format} @item string format(string s, int n, string locale="") @cindex @code{format} returns a string containing @code{n} formatted according to the C-style format string @code{s} using locale @code{locale} (or the current locale if an empty string is specified); @item string format(string s=defaultformat, string s=defaultseparator, real x, string locale="") returns a string containing @code{x} formatted according to the C-style format string @code{s} using locale @code{locale} (or the current locale if an empty string is specified), following the behaviour of the C function @code{fprintf}), except that only one data field is allowed, trailing zeros are removed by default (unless @code{#} is specified), and (if the format string specifies math mode) @TeX{} is used to typeset scientific notation using the @code{defaultseparator="\!\times\!";}; @cindex @code{hex} @cindex @code{hexidecimal} @item int hex(string s); casts a hexidecimal string @code{s} to an integer; @cindex @code{ascii} @cindex @code{ascii} @item int ascii(string s); returns the ASCII code for the first character of string @code{s}; @cindex @code{string} @item string string(real x, int digits=realDigits) casts @code{x} to a string using precision @code{digits} and the C locale; @cindex @code{locale} @item string locale(string s="") sets the locale to the given string, if nonempty, and returns the current locale; @item string time(string format="%a %b %d %T %Z %Y") @cindex @code{time} @cindex @code{date} @cindex @code{strftime} returns the current time formatted by the ANSI C routine @code{strftime} according to the string @code{format} using the current locale. Thus @verbatim time(); time("%a %b %d %H:%M:%S %Z %Y"); @end verbatim @noindent are equivalent ways of returning the current time in the default format used by the @code{UNIX} @code{date} command; @cindex @code{seconds} @cindex @code{strptime} @item int seconds(string t="", string format="") returns the time measured in seconds after the Epoch (Thu Jan 01 00:00:00 UTC 1970) as determined by the ANSI C routine @code{strptime} according to the string @code{format} using the current locale, or the current time if @code{t} is the empty string. Note that the @code{"%Z"} extension to the POSIX @code{strptime} specification is ignored by the current GNU C Library. If an error occurs, the value -1 is returned. Here are some examples: @verbatim seconds("Mar 02 11:12:36 AM PST 2007","%b %d %r PST %Y"); seconds(time("%b %d %r %z %Y"),"%b %d %r %z %Y"); seconds(time("%b %d %r %Z %Y"),"%b %d %r "+time("%Z")+" %Y"); 1+(seconds()-seconds("Jan 1","%b %d"))/(24*60*60); @end verbatim The last example returns today's ordinal date, measured from the beginning of the year. @cindex @code{time} @cindex @code{strftime} @item string time(int seconds, string format="%a %b %d %T %Z %Y") returns the time corresponding to @code{seconds} seconds after the Epoch (Thu Jan 01 00:00:00 UTC 1970) formatted by the ANSI C routine @code{strftime} according to the string @code{format} using the current locale. For example, to return the date corresponding to 24 hours ago: @verbatim time(seconds()-24*60*60); @end verbatim @cindex @code{system} @item int system(string s) @item int system(string[] s) if the setting @code{safe} is false, call the arbitrary system command @code{s}; @cindex @code{asy} @item void asy(string format, bool overwrite=false ... string[] s) conditionally process each file name in array @code{s} in a new environment, using format @code{format}, overwriting the output file only if @code{overwrite} is true; @cindex @code{abort} @item void abort(string s="") aborts execution (with a non-zero return code in batch mode); if string @code{s} is nonempty, a diagnostic message constructed from the source file, line number, and @code{s} is printed; @cindex @code{assert} @item void assert(bool b, string s="") aborts execution with an error message constructed from @code{s} if @code{b=false}; @cindex @code{exit} @item void exit() exits (with a zero error return code in batch mode); @cindex @code{sleep} @item void sleep(int seconds) pauses for the given number of seconds; @cindex @code{usleep} @item void usleep(int microseconds) pauses for the given number of microseconds; @cindex @code{beep} @item void beep() produces a beep on the console; @end table @cindex @code{typedef} @end table As in C/C++, complicated types may be abbreviated with @code{typedef} (see the example in @ref{Functions}). @node Paths and guides @section Paths and guides @table @code @item path @cindex @code{path} a cubic spline resolved into a fixed path. The implicit initializer for paths is @code{nullpath}. @cindex @code{circle} @anchor{circle} For example, the routine @code{circle(pair c, real r)}, which returns a Bezier curve approximating a circle of radius @code{r} centered on @code{c}, is based on @code{unitcircle} (@pxref{unitcircle}): @verbatim path circle(pair c, real r) { return shift(c)*scale(r)*unitcircle; } @end verbatim If high accuracy is needed, a true circle may be produced with the routine @code{Circle} defined in the module @code{graph.asy}: @cindex @code{Circle} @verbatim import graph; path Circle(pair c, real r, int n=nCircle); @end verbatim A circular arc consistent with @code{circle} centered on @code{c} with radius @code{r} from @code{angle1} to @code{angle2} degrees, drawing counterclockwise if @code{angle2 >= angle1}, can be constructed with @cindex @code{arc} @verbatim path arc(pair c, real r, real angle1, real angle2); @end verbatim One may also specify the direction explicitly: @verbatim path arc(pair c, real r, real angle1, real angle2, bool direction); @end verbatim Here the direction can be specified as CCW (counter-clockwise) or CW (clockwise). For convenience, an arc centered at @code{c} from pair @code{z1} to @code{z2} (assuming @code{|z2-c|=|z1-c|}) in the may also be constructed with @verbatim path arc(pair c, explicit pair z1, explicit pair z2, bool direction=CCW) @end verbatim If high accuracy is needed, true arcs may be produced with routines in the module @code{graph.asy} that produce Bezier curves with @code{n} control points: @cindex @code{Arc} @verbatim import graph; path Arc(pair c, real r, real angle1, real angle2, bool direction, int n=nCircle); path Arc(pair c, real r, real angle1, real angle2, int n=nCircle); path Arc(pair c, explicit pair z1, explicit pair z2, bool direction=CCW, int n=nCircle); @end verbatim An ellipse can be drawn with the routine @cindex @code{ellipse} @verbatim path ellipse(pair c, real a, real b) { return shift(c)*scale(a,b)*unitcircle; } @end verbatim A brace can be constructed between pairs @code{a} and @code{b} with @cindex @code{brace} @verbatim path brace(pair a, pair b, real amplitude=bracedefaultratio*length(b-a)); @end verbatim This example illustrates the use of all five guide connectors discussed in @ref{Tutorial} and @ref{Bezier curves}: @verbatiminclude join.asy @sp 1 @center @image{join} Here are some useful functions for paths: @table @code @cindex @code{length} @item int length(path p); This is the number of (linear or cubic) segments in path @code{p}. If @code{p} is cyclic, this is the same as the number of nodes in @code{p}. @cindex @code{size} @item int size(path p); This is the number of nodes in the path @code{p}. If @code{p} is cyclic, this is the same as @code{length(p)}. @cindex @code{cyclic} @item bool cyclic(path p); returns @code{true} iff path @code{p} is cyclic. @cindex @code{straight} @item bool straight(path p, int i); returns @code{true} iff the segment of path @code{p} between node @code{i} and node @code{i+1} is straight. @cindex @code{piecewisestraight} @item bool piecewisestraight(path p) returns @code{true} iff the path @code{p} is piecewise straight. @cindex @code{point} @item pair point(path p, int t); If @code{p} is cyclic, return the coordinates of node @code{t} mod @code{length(p)}. Otherwise, return the coordinates of node @code{t}, unless @code{t} < 0 (in which case @code{point(0)} is returned) or @code{t} > @code{length(p)} (in which case @code{point(length(p))} is returned). @item pair point(path p, real t); This returns the coordinates of the point between node @code{floor(t)} and @code{floor(t)+1} corresponding to the cubic spline parameter @code{t-floor(t)} (@pxref{Bezier curves}). If @code{t} lies outside the range [0,@code{length(p)}], it is first reduced modulo @code{length(p)} in the case where @code{p} is cyclic or else converted to the corresponding endpoint of @code{p}. @cindex @code{dir} @item pair dir(path p, int t, int sign=0, bool normalize=true); If @code{sign < 0}, return the direction (as a pair) of the incoming tangent to path @code{p} at node @code{t}; if @code{sign > 0}, return the direction of the outgoing tangent. If @code{sign=0}, the mean of these two directions is returned. @item pair dir(path p, real t, bool normalize=true); returns the direction of the tangent to path @code{p} at the point between node @code{floor(t)} and @code{floor(t)+1} corresponding to the cubic spline parameter @code{t-floor(t)} (@pxref{Bezier curves}). @item pair dir(path p) returns dir(p,length(p)). @item pair dir(path p, path q) returns unit(dir(p)+dir(q)). @cindex @code{accel} @item pair accel(path p, int t, int sign=0); If @code{sign < 0}, return the acceleration of the incoming path @code{p} at node @code{t}; if @code{sign > 0}, return the acceleration of the outgoing path. If @code{sign=0}, the mean of these two accelerations is returned. @cindex @code{accel} @item pair accel(path p, real t); returns the acceleration of the path @code{p} at the point @code{t}. @cindex @code{radius} @item real radius(path p, real t); returns the radius of curvature of the path @code{p} at the point @code{t}. @cindex @code{precontrol} @item pair precontrol(path p, int t); returns the precontrol point of @code{p} at node @code{t}. @item pair precontrol(path p, real t); returns the effective precontrol point of @code{p} at parameter @code{t}. @cindex @code{postcontrol} @item pair postcontrol(path p, int t); returns the postcontrol point of @code{p} at node @code{t}. @item pair postcontrol(path p, real t); returns the effective postcontrol point of @code{p} at parameter @code{t}. @cindex @code{arclength} @item real arclength(path p); returns the length (in user coordinates) of the piecewise linear or cubic curve that path @code{p} represents. @cindex @code{arctime} @item real arctime(path p, real L); returns the path "time", a real number between 0 and the length of the path in the sense of @code{point(path p, real t)}, at which the cumulative arclength (measured from the beginning of the path) equals @code{L}. @cindex @code{arcpoint} @item real arcpoint(path p, real L); returns @code{point(p,arctime(p,L))}. @cindex @code{dirtime} @item real dirtime(path p, pair z); returns the first "time", a real number between 0 and the length of the path in the sense of @code{point(path, real)}, at which the tangent to the path has the direction of pair @code{z}, or -1 if this never happens. @cindex @code{reltime} @item real reltime(path p, real l); returns the time on path @code{p} at the relative fraction @code{l} of its arclength. @cindex @code{relpoint} @item pair relpoint(path p, real l); returns the point on path @code{p} at the relative fraction @code{l} of its arclength. @cindex @code{midpoint} @item pair midpoint(path p); returns the point on path @code{p} at half of its arclength. @cindex @code{reverse} @item path reverse(path p); returns a path running backwards along @code{p}. @cindex @code{subpath} @item path subpath(path p, int a, int b); returns the subpath of @code{p} running from node @code{a} to node @code{b}. If @code{a} < @code{b}, the direction of the subpath is reversed. @item path subpath(path p, real a, real b); returns the subpath of @code{p} running from path time @code{a} to path time @code{b}, in the sense of @code{point(path, real)}. If @code{a} < @code{b}, the direction of the subpath is reversed. @cindex @code{intersect} @item real[] intersect(path p, path q, real fuzz=-1); If @code{p} and @code{q} have at least one intersection point, return a real array of length 2 containing the times representing the respective path times along @code{p} and @code{q}, in the sense of @code{point(path, real)}, for one such intersection point (as chosen by the algorithm described on page 137 of @code{The MetaFontbook}). The computations are performed to the absolute error specified by @code{fuzz}, or if @code{fuzz < 0}, to machine precision. If the paths do not intersect, return a real array of length 0. @cindex @code{intersections} @item real[][] intersections(path p, path q, real fuzz=-1); Return all (unless there are infinitely many) intersection times of paths @code{p} and @code{q} as a sorted array of real arrays of length 2 (@pxref{sort}). The computations are performed to the absolute error specified by @code{fuzz}, or if @code{fuzz < 0}, to machine precision. @cindex @code{intersections} @item real[] intersections(path p, explicit pair a, explicit pair b, real fuzz=-1); Return all (unless there are infinitely many) intersection times of path @code{p} with the (infinite) line through points @code{a} and @code{b} as a sorted array. The intersections returned are guaranteed to be correct to within the absolute error specified by @code{fuzz}, or if @code{fuzz < 0}, to machine precision. @cindex @code{times} @item real[] times(path p, real x) returns all intersection times of path @code{p} with the vertical line through @code{(x,0)}. @cindex @code{times} @item real[] times(path p, explicit pair z) returns all intersection times of path @code{p} with the horizontal line through @code{(0,z.y)}. @cindex @code{mintimes} @item real[] mintimes(path p) returns an array of length 2 containing times at which path @code{p} reaches its minimal horizontal and vertical extents, respectively. @cindex @code{maxtimes} @item real[] maxtimes(path p) returns an array of length 2 containing times at which path @code{p} reaches its maximal horizontal and vertical extents, respectively. @cindex @code{intersectionpoint} @item pair intersectionpoint(path p, path q, real fuzz=-1); returns the intersection point @code{point(p,intersect(p,q,fuzz)[0])}. @cindex @code{intersectionpoints} @item pair[] intersectionpoints(path p, path q, real fuzz=-1); returns an array containing all intersection points of the paths @code{p} and @code{q}. @anchor{extension} @cindex @code{whatever} @cindex @code{extension} @item pair extension(pair P, pair Q, pair p, pair q); returns the intersection point of the extensions of the line segments @code{P--Q} and @code{p--q}, or if the lines are parallel, @code{(infinity,infinity)}. @cindex @code{cut} @cindex @code{slice} @item slice cut(path p, path knife, int n); returns the portions of path @code{p} before and after the @code{n}th intersection of @code{p} with path @code{knife} as a structure @code{slice} (if no intersection exist is found, the entire path is considered to be `before' the intersection): @verbatim struct slice { path before,after; } @end verbatim The argument @code{n} is treated as modulo the number of intersections. @cindex @code{firstcut} @cindex @code{slice} @item slice firstcut(path p, path knife); equivalent to @code{cut(p,knife,0);} @cindex @code{MetaPost cutbefore} Note that @code{firstcut.after} plays the role of the @code{MetaPost cutbefore} command. @cindex @code{lastcut} @item slice lastcut(path p, path knife); equivalent to @code{cut(p,knife,-1);} @cindex @code{MetaPost cutafter} Note that @code{lastcut.before} plays the role of the @code{MetaPost cutafter} command. @cindex @code{buildcycle} @item path buildcycle(... path[] p); This returns the path surrounding a region bounded by a list of two or more consecutively intersecting paths, following the behaviour of the @code{MetaPost buildcycle} command. @cindex @code{min} @item pair min(path p); returns the pair (left,bottom) for the path bounding box of path @code{p}. @cindex @code{max} @item pair max(path p); returns the pair (right,top) for the path bounding box of path @code{p}. @cindex @code{windingnumber} @cindex @code{undefined} @item int windingnumber(path p, pair z); returns the winding number of the cyclic path @code{p} relative to the point @code{z}. The winding number is positive if the path encircles @code{z} in the counterclockwise direction. If @code{z} lies on @code{p} the constant @code{undefined} (defined to be the largest odd integer) is returned. @cindex @code{interior} @item bool interior(int windingnumber, pen fillrule) returns true if @code{windingnumber} corresponds to an interior point according to @code{fillrule}. @cindex @code{inside} @item bool inside(path p, pair z, pen fillrule=currentpen); returns @code{true} iff the point @code{z} lies inside or on the edge of the region bounded by the cyclic path @code{p} according to the fill rule @code{fillrule} (@pxref{fillrule}). @cindex @code{inside} @item int inside(path p, path q, pen fillrule=currentpen); returns @code{1} if the cyclic path @code{p} strictly contains @code{q} according to the fill rule @code{fillrule} (@pxref{fillrule}), @code{-1} if the cyclic path @code{q} strictly contains @code{p}, and @code{0} otherwise. @cindex @code{inside} @item pair inside(path p, pen fillrule=currentpen); returns an arbitrary point strictly inside a cyclic path @code{p} according to the fill rule @code{fillrule} (@pxref{fillrule}). @cindex @code{strokepath} @item path[] strokepath(path g, pen p=currentpen); returns the path array that @code{PostScript} would fill in drawing path @code{g} with pen @code{p}. @end table @item guide @cindex @code{guide} an unresolved cubic spline (list of cubic-spline nodes and control points). The implicit initializer for a guide is @code{nullpath}; this is useful for building up a guide within a loop. A guide is similar to a path except that the computation of the cubic spline is deferred until drawing time (when it is resolved into a path); this allows two guides with free endpoint conditions to be joined together smoothly. The solid curve in the following example is built up incrementally as a guide, but only resolved at drawing time; the dashed curve is incrementally resolved at each iteration, before the entire set of nodes (shown in red) is known: @verbatiminclude mexicanhat.asy @sp 1 @center @image{mexicanhat} We point out an efficiency distinction in the use of guides and paths: @verbatim guide g; for(int i=0; i < 10; ++i) g=g--(i,i); path p=g; @end verbatim @noindent runs in linear time, whereas @verbatim path p; for(int i=0; i < 10; ++i) p=p--(i,i); @end verbatim @noindent runs in quadratic time, as the entire path up to that point is copied at each step of the iteration. The following routines can be used to examine the individual elements of a guide without actually resolving the guide to a fixed path (except for internal cycles, which are resolved): @table @code @cindex @code{size} @item int size(guide g); Analogous to @code{size(path p)}. @cindex @code{length} @item int length(guide g); Analogous to @code{length(path p)}. @cindex @code{cyclic} @item bool cyclic(path p); Analogous to @code{cyclic(path p)}. @cindex @code{point} @item pair point(guide g, int t); Analogous to @code{point(path p, int t)}. @cindex @code{reverse} @item guide reverse(guide g); Analogous to @code{reverse(path p)}. If @code{g} is cyclic and also contains a secondary cycle, it is first solved to a path, then reversed. If @code{g} is not cyclic but contains an internal cycle, only the internal cycle is solved before reversal. If there are no internal cycles, the guide is reversed but not solved to a path. @cindex @code{dirSpecifier} @item pair[] dirSpecifier(guide g, int i); This returns a pair array of length 2 containing the outgoing (in element 0) and incoming (in element 1) direction specifiers (or @code{(0,0)} if none specified) for the segment of guide @code{g} between nodes @code{i} and @code{i+1}. @cindex @code{controlSpecifier} @item pair[] controlSpecifier(guide g, int i); If the segment of guide @code{g} between nodes @code{i} and @code{i+1} has explicit outgoing and incoming control points, they are returned as elements 0 and 1, respectively, of a two-element array. Otherwise, an empty array is returned. @cindex @code{tensionSpecifier} @item tensionSpecifier tensionSpecifier(guide g, int i); This returns the tension specifier for the segment of guide @code{g} between nodes @code{i} and @code{i+1}. The individual components of the @code{tensionSpecifier} type can be accessed as the virtual members @code{in}, @code{out}, and @code{atLeast}. @cindex @code{curlSpecifier} @item real[] curlSpecifier(guide g); This returns an array containing the initial curl specifier (in element 0) and final curl specifier (in element 1) for guide @code{g}. @end table As a technical detail we note that a direction specifier given to @code{nullpath} modifies the node on the other side: the guides @verbatim a..{up}nullpath..b; c..nullpath{up}..d; e..{up}nullpath{down}..f; @end verbatim are respectively equivalent to @verbatim a..nullpath..{up}b; c{up}..nullpath..d; e{down}..nullpath..{up}f; @end verbatim @end table @node Pens @section Pens @cindex @code{pen} @cindex @code{currentpen} @cindex @code{MetaPost pickup} In @code{Asymptote}, pens provide a context for the four basic drawing commands (@pxref{Drawing commands}). They are used to specify the following drawing attributes: color, line type, line width, line cap, line join, fill rule, text alignment, font, font size, pattern, overwrite mode, and calligraphic transforms on the pen nib. The default pen used by the drawing routines is called @code{currentpen}. This provides the same functionality as the @code{MetaPost} command @code{pickup}. The implicit initializer for pens is @code{defaultpen}. @cindex @code{+} @cindex @code{*} Pens may be added together with the nonassociative binary operator @code{+}. This will add the colors of the two pens. All other non-default attributes of the rightmost pen will override those of the leftmost pen. Thus, one can obtain a yellow dashed pen by saying @code{dashed+red+green} or @code{red+green+dashed} or @code{red+dashed+green}. The binary operator @code{*} can be used to scale the color of a pen by a real number, until it saturates with one or more color components equal to 1. @itemize @bullet @item Colors are specified using one of the following colorspaces: @cindex color @table @code @item pen gray(real g); @cindex @code{gray} @cindex grayscale This produces a grayscale color, where the intensity @code{g} lies in the interval [0,1], with 0.0 denoting black and 1.0 denoting white. @item pen rgb(real r, real g, real b); @cindex @code{rgb} This produces an @acronym{RGB} color, where each of the red, green, and blue intensities @code{r}, @code{g}, @code{b}, lies in the interval [0,1]. @item pen cmyk(real c, real m, real y, real k); @cindex @code{cmyk} This produces a @acronym{CMYK} color, where each of the cyan, magenta, yellow, and black intensities @code{c}, @code{m}, @code{y}, @code{k}, lies in the interval [0,1]. @item pen invisible; @cindex @code{invisible} This special pen writes in invisible ink, but adjusts the bounding box as if something had been drawn (like the @code{\phantom} command in @TeX{}). The function @code{bool invisible(pen)} can be used to test whether a pen is invisible. @end table @cindex @code{defaultpen} The default color is @code{black}; this may be changed with the routine @code{defaultpen(pen)}. The function @code{colorspace(pen p)} returns the colorspace of pen @code{p} as a string (@code{"gray"}, @code{"rgb"}, @code{"cmyk"}, or @code{""}). @cindex @code{colors} The function @code{real[] colors(pen)} returns the color components of a pen. The functions @code{pen gray(pen)}, @code{pen rgb(pen)}, and @code{pen cmyk(pen)} return new pens obtained by converting their arguments to the respective color spaces. @cindex @code{colorless} The function @code{colorless(pen=currentpen)} returns a copy of its argument with the color attributes stripped (to avoid color mixing). A 6-character RGB hexidecimal string can be converted to a pen with the routine @cindex @code{rgb} @cindex @code{hexidecimal} @verbatim pen rgb(string s); @end verbatim @noindent A pen can be converted to a hexidecimal string with @cindex @code{hex} @item string hex(pen p); Various shades and mixtures of the grayscale primary colors @code{black} and @code{white}, @acronym{RGB} primary colors @code{red}, @code{green}, and @code{blue}, and @acronym{RGB} secondary colors @code{cyan}, @code{magenta}, and @code{yellow} are defined as named colors, along with the @acronym{CMYK} primary colors @code{Cyan}, @code{Magenta}, @code{Yellow}, and @code{Black}, in the module @code{plain}: @sp 1 @center @image{colors} The standard 140 @acronym{RGB} @code{X11} colors can be imported with the command @verbatim import x11colors; @end verbatim and the standard 68 @acronym{CMYK} @TeX{} colors can be imported with the command @verbatim import texcolors; @end verbatim Note that there is some overlap between these two standards and the definitions of some colors (e.g.@ @code{Green}) actually disagree. @code{Asymptote} also comes with a @code{asycolors.sty} @code{LaTeX} package that defines to @code{LaTeX} @acronym{CMYK} versions of @code{Asymptote}'s predefined colors, so that they can be used directly within @code{LaTeX} strings. Normally, such colors are passed to @code{LaTeX} via a pen argument; however, to change the color of only a portion of a string, say for a slide presentation, (@pxref{slide}) it may be desirable to specify the color directly to @code{LaTeX}. This file can be passed to @code{LaTeX} with the @code{Asymptote} command @verbatim usepackage("asycolors"); @end verbatim The structure @code{hsv} defined in @code{plain_pens.asy} may be used to convert between @acronym{HSV} and @acronym{RGB} spaces, where the hue @code{h} is an angle in @math{[0,360)} and the saturation @code{s} and value @code{v} lie in @code{[0,1]}: @verbatim pen p=hsv(180,0.5,0.75); write(p); // ([default], red=0.375, green=0.75, blue=0.75) hsv q=p; write(q.h,q.s,q.v); // 180 0.5 0.75 @end verbatim @item Line types are specified with the function @code{pen linetype(real[] a, real offset=0, bool scale=true, bool adjust=true)}, @cindex @code{solid} @cindex @code{dashed} @cindex @code{dotted} @cindex @code{longdashed} @cindex @code{dashdotted} @cindex @code{longdashdotted} where @code{a} is an array of real array numbers. The optional parameter @code{offset} specifies where in the pattern to begin. The first number specifies how far (if @code{scale} is @code{true}, in units of the pen line width; otherwise in @code{PostScript} units) to draw with the pen on, the second number specifies how far to draw with the pen off, and so on. If @code{adjust} is @code{true}, these spacings are automatically adjusted by @code{Asymptote} to fit the arclength of the path. Here are the predefined line types: @verbatim pen solid=linetype(new real[]); pen dotted=linetype(new real[] {0,4}); pen dashed=linetype(new real[] {8,8}); pen longdashed=linetype(new real[] {24,8}); pen dashdotted=linetype(new real[] {8,8,0,8}); pen longdashdotted=linetype(new real[] {24,8,0,8}); pen Dotted(pen p=currentpen) {return linetype(new real[] {0,3})+2*linewidth(p);} pen Dotted=Dotted(); @end verbatim @sp 1 @center @image{linetype} @cindex @code{defaultpen} The default line type is @code{solid}; this may be changed with @code{defaultpen(pen)}. @cindex @code{linetype} @cindex @code{offset} @cindex @code{scale} @cindex @code{adjust} The line type of a pen can be determined with the functions @code{real[] linetype(pen p=currentpen)}, @code{real offset(pen p)}, @code{bool scale(pen p)}, and @code{bool adjust(pen p)}. @cindex @code{linewidth} @cindex @code{defaultpen} @item The pen line width is specified in @code{PostScript} units with @code{pen linewidth(real)}. The default line width is 0.5 bp; this value may be changed with @code{defaultpen(pen)}. The line width of a pen is returned by @code{real linewidth(pen p=currentpen)}. For convenience, in the module @code{plain_pens} we define @verbatim void defaultpen(real w) {defaultpen(linewidth(w));} pen operator +(pen p, real w) {return p+linewidth(w);} pen operator +(real w, pen p) {return linewidth(w)+p;} @end verbatim so that one may set the line width like this: @verbatim defaultpen(2); pen p=red+0.5; @end verbatim @cindex @code{linecap} @cindex @code{squarecap} @cindex @code{roundcap} @cindex @code{extendcap} @cindex @code{defaultpen} @item A pen with a specific @code{PostScript} line cap is returned on calling @code{linecap} with an integer argument: @verbatim pen squarecap=linecap(0); pen roundcap=linecap(1); pen extendcap=linecap(2); @end verbatim @noindent The default line cap, @code{roundcap}, may be changed with @code{defaultpen(pen)}. The line cap of a pen is returned by @code{int linecap(pen p=currentpen)}. @cindex @code{linejoin} @cindex @code{miterjoin} @cindex @code{roundjoin} @cindex @code{beveljoin} @item A pen with a specific @code{PostScript} join style is returned on calling @code{linejoin} with an integer argument: @verbatim pen miterjoin=linejoin(0); pen roundjoin=linejoin(1); pen beveljoin=linejoin(2); @end verbatim @noindent The default join style, @code{roundjoin}, may be changed with @code{defaultpen(pen)}.The join style of a pen is returned by @code{int linejoin(pen p=currentpen)}. @cindex @code{miterlimit} @item A pen with a specific @code{PostScript} miter limit is returned by calling @code{miterlimit(real)}. The default miterlimit, @code{10.0}, may be changed with @code{defaultpen(pen)}. The miter limit of a pen is returned by @code{real miterlimit(pen p=currentpen)}. @cindex @code{fillrule} @cindex @code{zerowinding} @cindex @code{evenodd} @anchor{fillrule} @item A pen with a specific @code{PostScript} fill rule is returned on calling @code{fillrule} with an integer argument: @verbatim pen zerowinding=fillrule(0); pen evenodd=fillrule(1); @end verbatim @noindent The fill rule, which identifies the algorithm used to determine the insideness of a path or array of paths, only affects the @code{clip}, @code{fill}, and @code{inside} functions. For the @code{zerowinding} fill rule, a point @code{z} is outside the region bounded by a path if the number of upward intersections of the path with the horizontal line @code{z--z+infinity} minus the number of downward intersections is zero. For the @code{evenodd} fill rule, @code{z} is considered to be outside the region if the total number of such intersections is even. The default fill rule, @code{zerowinding}, may be changed with @code{defaultpen(pen)}. The fill rule of a pen is returned by @code{int fillrule(pen p=currentpen)}. @cindex @code{nobasealign} @cindex @code{basealign} @anchor{basealign} @item A pen with a specific text alignment setting is returned on calling @code{basealign} with an integer argument: @verbatim pen nobasealign=basealign(0); pen basealign=basealign(1); @end verbatim @noindent The default setting, @code{nobasealign},which may be changed with @code{defaultpen(pen)}, causes the label alignment routines to use the full label bounding box for alignment. In contrast, @code{basealign} requests that the @TeX{} baseline be respected. The base align setting of a pen is returned by @code{int basealigin(pen p=currentpen)}. @cindex @code{fontsize} @cindex @code{lineskip} @cindex @code{defaultpen} @cindex @code{type1cm} @item The font size is specified in @TeX{} points (1 pt = 1/72.27 inches) with the function @code{pen fontsize(real size, real lineskip=1.2*size)}. The default font size, 12pt, may be changed with @code{defaultpen(pen)}. Nonstandard font sizes may require inserting @verbatim import fontsize; @end verbatim at the beginning of the file (this requires the @code{type1cm} package available from @quotation @url{http://mirror.ctan.org/macros/latex/contrib/type1cm/} @end quotation and included in recent @code{LaTeX} distributions). The font size and line skip of a pen can be examined with the routines @code{real fontsize(pen p=currentpen)} and @code{real lineskip(pen p=currentpen)}, respectively. @cindex @code{font} @cindex @code{LaTeX fonts} @cindex @code{NFSS} @cindex @code{font command} @item A pen using a specific @code{LaTeX} @code{NFSS} font is returned by calling the function @code{pen font(string encoding, string family, string series, string shape)}. The default setting, @code{font("OT1","cmr","m","n")}, corresponds to 12pt Computer Modern Roman; this may be changed with @code{defaultpen(pen)}. The font setting of a pen is returned by @code{string font(pen p=currentpen)}. Support for standardized international characters is provided by the @code{unicode} package (@pxref{unicode}). @cindex @code{TeX fonts} Alternatively, one may select a fixed-size @TeX{} font (on which @code{fontsize} has no effect) like @code{"cmr12"} (12pt Computer Modern Roman) or @code{"pcrr"} (Courier) using the function @code{pen font(string name)}. An optional size argument can also be given to scale the font to the requested size: @code{pen font(string name, real size)}. @cindex @code{fontcommand} A nonstandard font command can be generated with @code{pen fontcommand(string)}. @cindex @code{PostScript fonts} A convenient interface to the following standard @code{PostScript} fonts is also provided: @verbatim pen AvantGarde(string series="m", string shape="n"); pen Bookman(string series="m", string shape="n"); pen Courier(string series="m", string shape="n"); pen Helvetica(string series="m", string shape="n"); pen NewCenturySchoolBook(string series="m", string shape="n"); pen Palatino(string series="m", string shape="n"); pen TimesRoman(string series="m", string shape="n"); pen ZapfChancery(string series="m", string shape="n"); pen Symbol(string series="m", string shape="n"); pen ZapfDingbats(string series="m", string shape="n"); @end verbatim @anchor{transparency} @cindex transparency @cindex @code{opacity} @item The transparency of a pen can be changed with the command: @verbatim pen opacity(real opacity=1, string blend="Compatible"); @end verbatim The opacity can be varied from @code{0} (fully transparent) to the default value of @code{1} (opaque), and @code{blend} specifies one of the following foreground--background blending operations: @verbatim "Compatible","Normal","Multiply","Screen","Overlay","SoftLight", "HardLight","ColorDodge","ColorBurn","Darken","Lighten","Difference", "Exclusion","Hue","Saturation","Color","Luminosity", @end verbatim as described in @url{http://partners.adobe.com/public/developer/en/pdf/PDFReference16.pdf}. Since @code{PostScript} does not support transparency, this feature is only effective with the @code{-f pdf} output format option; other formats can be produced from the resulting @acronym{PDF} file with the @code{ImageMagick} @code{convert} program. Labels are always drawn with an @code{opacity} of 1. A simple example of transparent filling is provided in the example file @code{transparency.asy}. @cindex patterns @cindex tilings @item @code{PostScript} commands within a @code{picture} may be used to create a tiling pattern, identified by the string @code{name}, for @code{fill} and @code{draw} operations by adding it to the global @code{PostScript} frame @code{currentpatterns}, with optional left-bottom margin @code{lb} and right-top margin @code{rt}. @verbatim import patterns; void add(string name, picture pic, pair lb=0, pair rt=0); @end verbatim To @code{fill} or @code{draw} using pattern @code{name}, use the pen @code{pattern("name")}. For example, rectangular tilings can be constructed using the routines @code{picture tile(real Hx=5mm, real Hy=0, pen p=currentpen, filltype filltype=NoFill)}, @code{picture checker(real Hx=5mm, real Hy=0, pen p=currentpen)}, and @code{picture brick(real Hx=5mm, real Hy=0, pen p=currentpen)} defined in @code{patterns.asy}: @cindex grid @cindex tile @cindex checker @cindex brick @verbatiminclude tile.asy @sp 1 @center @image{tile} @cindex hatch @cindex crosshatch Hatch patterns can be generated with the routines @code{picture hatch(real H=5mm, pair dir=NE, pen p=currentpen)}, @code{picture crosshatch(real H=5mm, pen p=currentpen)}: @verbatiminclude hatch.asy @sp 1 @center @image{hatch} You may need to turn off aliasing in your @code{PostScript} viewer for patterns to appear correctly. Custom patterns can easily be constructed, following the examples in @code{patterns.asy}. The tiled pattern can even incorporate shading (@pxref{gradient shading}), as illustrated in this example (not included in the manual because not all printers support @code{PostScript} 3): @verbatiminclude shadedtiling.asy @anchor{makepen} @cindex @code{makepen} @item One can specify a custom pen nib as an arbitrary polygonal path with @code{pen makepen(path)}; this path represents the mark to be drawn for paths containing a single point. This pen nib path can be recovered from a pen with @code{path nib(pen)}. Unlike in @code{MetaPost}, the path need not be convex: @verbatiminclude makepen.asy @sp 1 @center @image{makepen} The value @code{nullpath} represents a circular pen nib (the default); an elliptical pen can be achieved simply by multiplying the pen by a transform: @code{yscale(2)*currentpen}. @anchor{overwrite} @cindex @code{overwrite} @item One can prevent labels from overwriting one another by using the pen attribute @code{overwrite}, which takes a single argument: @table @code @cindex @code{Allow} @cindex @code{defaultpen} @item Allow Allow labels to overwrite one another. This is the default behaviour (unless overridden with @code{defaultpen(pen)}. @cindex @code{Suppress} @item Suppress Suppress, with a warning, each label that would overwrite another label. @cindex @code{SuppressQuiet} @item SuppressQuiet Suppress, without warning, each label that would overwrite another label. @cindex @code{Move} @item Move Move a label that would overwrite another out of the way and issue a warning. As this adjustment is during the final output phase (in @code{PostScript} coordinates) it could result in a larger figure than requested. @cindex @code{MoveQuiet} @item MoveQuiet Move a label that would overwrite another out of the way, without warning. As this adjustment is during the final output phase (in @code{PostScript} coordinates) it could result in a larger figure than requested. @end table @end itemize @cindex @code{defaultpen} @cindex @code{resetdefaultpen} The routine @code{defaultpen()} returns the current default pen attributes. Calling the routine @code{resetdefaultpen()} resets all pen default attributes to their initial values. @node Transforms @section Transforms @cindex @code{transform} @code{Asymptote} makes extensive use of affine transforms. A pair @code{(x,y)} is transformed by the transform @code{t=(t.x,t.y,t.xx,t.xy,t.yx,t.yy)} to @code{(x',y')}, where @verbatim x' = t.x + t.xx * x + t.xy * y y' = t.y + t.yx * x + t.yy * y @end verbatim @noindent This is equivalent to the @code{PostScript} transformation @code{[t.xx t.yx t.xy t.yy t.x t.y]}. Transforms can be applied to pairs, guides, paths, pens, strings, transforms, frames, and pictures by multiplication (via the binary operator @code{*}) on the left (@pxref{circle} for an example). @cindex @code{inverse} Transforms can be composed with one another and inverted with the function @code{transform inverse(transform t)}; they can also be raised to any integer power with the @code{^} operator. The built-in transforms are: @table @code @item transform identity(); @cindex @code{identity} the identity transform; @item transform shift(pair z); @cindex @code{shift} translates by the pair @code{z}; @item transform shift(real x, real y); @cindex @code{shift} translates by the pair @code{(x,y)}; @item transform xscale(real x); @cindex @code{xscale} scales by @code{x} in the @math{x} direction; @item transform yscale(real y); @cindex @code{yscale} scales by @code{y} in the @math{y} direction; @item transform scale(real s); @cindex @code{scale} scale by @code{s} in both @math{x} and @math{y} directions; @item transform scale(real x, real y); @cindex @code{scale} scale by @code{x} in the @math{x} direction and by @code{y} in the @math{y} direction; @item transform slant(real s); @cindex @code{slant} maps @code{(x,y)} --> @code{(x+s*y,y)}; @item transform rotate(real angle, pair z=(0,0)); rotates by @code{angle} in degrees about @code{z}; @item transform reflect(pair a, pair b); @cindex @code{reflect} reflects about the line @code{a--b}. @end table @cindex @code{shift} @cindex @code{shiftless} The implicit initializer for transforms is @code{identity()}. The routines @code{shift(transform t)} and @code{shiftless(transform t)} return the transforms @code{(t.x,t.y,0,0,0,0)} and @code{(0,0,t.xx,t.xy,t.yx,t.yy)} respectively. @node Frames and pictures @section Frames and pictures @table @code @item frame @cindex @code{frame} @cindex @code{newframe} @cindex @code{empty} @cindex @code{erase} @cindex @code{min} @cindex @code{max} Frames are canvases for drawing in @code{PostScript} coordinates. While working with frames directly is occasionally necessary for constructing deferred drawing routines, pictures are usually more convenient to work with. The implicit initializer for frames is @code{newframe}. The function @code{bool empty(frame f)} returns @code{true} only if the frame @code{f} is empty. A frame may be erased with the @code{erase(frame)} routine. The functions @code{pair min(frame)} and @code{pair max(frame)} return the (left,bottom) and (right,top) coordinates of the frame bounding box, respectively. The contents of frame @code{src} may be appended to frame @code{dest} with the command @verbatim void add(frame dest, frame src); @end verbatim or prepended with @verbatim void prepend(frame dest, frame src); @end verbatim A frame obtained by aligning frame @code{f} in the direction @code{align}, in a manner analogous to the @code{align} argument of @code{label} (@pxref{label}), is returned by @verbatim frame align(frame f, pair align); @end verbatim @cindex @code{box} @cindex @code{ellipse} @anchor{envelope} @cindex @code{envelope} To draw or fill a box or ellipse around a label or frame and return the boundary as a path, use one of the predefined @code{envelope} routines @verbatim path box(frame f, Label L="", real xmargin=0, real ymargin=xmargin, pen p=currentpen, filltype filltype=NoFill, bool above=true); path roundbox(frame f, Label L="", real xmargin=0, real ymargin=xmargin, pen p=currentpen, filltype filltype=NoFill, bool above=true); path ellipse(frame f, Label L="", real xmargin=0, real ymargin=xmargin, pen p=currentpen, filltype filltype=NoFill, bool above=true); @end verbatim @item picture @cindex @code{picture} Pictures are high-level structures (@pxref{Structures}) defined in the module @code{plain} that provide canvases for drawing in user coordinates. The default picture is called @code{currentpicture}. A new picture can be created like this: @verbatim picture pic; @end verbatim @noindent Anonymous pictures can be made by the expression @code{new picture}. The @code{size} routine specifies the dimensions of the desired picture: @anchor{size} @cindex @code{size} @verbatim void size(picture pic=currentpicture, real x, real y=x, bool keepAspect=Aspect); @end verbatim If the @code{x} and @code{y} sizes are both 0, user coordinates will be interpreted as @code{PostScript} coordinates. In this case, the transform mapping @code{pic} to the final output frame is @code{identity()}. If exactly one of @code{x} or @code{y} is 0, no size restriction is imposed in that direction; it will be scaled the same as the other direction. @cindex @code{keepAspect} @cindex @code{Aspect} If @code{keepAspect} is set to @code{Aspect} or @code{true}, the picture will be scaled with its aspect ratio preserved such that the final width is no more than @code{x} and the final height is no more than @code{y}. @cindex @code{keepAspect} @cindex @code{IgnoreAspect} If @code{keepAspect} is set to @code{IgnoreAspect} or @code{false}, the picture will be scaled in both directions so that the final width is @code{x} and the height is @code{y}. To make the user coordinates of picture @code{pic} represent multiples of @code{x} units in the @math{x} direction and @code{y} units in the @math{y} direction, use @anchor{unitsize} @cindex @code{unitsize} @verbatim void unitsize(picture pic=currentpicture, real x, real y=x); @end verbatim When nonzero, these @code{x} and @code{y} values override the corresponding size parameters of picture @code{pic}. The routine @cindex @code{size} @verbatim void size(picture pic=currentpicture, real xsize, real ysize, pair min, pair max); @end verbatim forces the final picture scaling to map the user coordinates @code{box(min,max)} to a region of width @code{xsize} and height @code{ysize} (when these parameters are nonzero). Alternatively, calling the routine @cindex @code{fixedscaling} @verbatim transform fixedscaling(picture pic=currentpicture, pair min, pair max, pen p=nullpen, bool warn=false); @end verbatim will cause picture @code{pic} to use a fixed scaling to map user coordinates in @code{box(min,max)} to the (already specified) picture size, taking account of the width of pen @code{p}. A warning will be issued if the final picture exceeds the specified size. A picture @code{pic} can be fit to a frame and output to a file @code{prefix}.@code{format} using image format @code{format} by calling the @code{shipout} function: @anchor{shipout} @cindex @code{shipout} @cindex @code{outprefix} @verbatim void shipout(string prefix=defaultfilename, picture pic=currentpicture, orientation orientation=orientation, string format="", bool wait=false, bool view=true, string options="", string script="", light light=currentlight, projection P=currentprojection) @end verbatim @noindent The default output format, @code{PostScript}, may be changed with the @code{-f} or @code{-tex} command-line options. The @code{options}, @code{script}, and @code{projection} parameters are only relevant for 3D pictures. If @code{defaultfilename} is an empty string, the prefix @code{outprefix()} will be used. A @code{shipout()} command is added implicitly at file exit if no previous @code{shipout} commands have been executed. @cindex @code{orientation} @cindex @code{Portrait} @cindex @code{Landscape} @cindex @code{UpsideDown} The default page orientation is @code{Portrait}; this may be modified by changing the variable @code{orientation}. To output in landscape mode, simply set the variable @code{orientation=Landscape} or issue the command @verbatim shipout(Landscape); @end verbatim @cindex @code{Seascape} To rotate the page by @math{-90} degrees, use the orientation @code{Seascape}. @cindex @code{UpsideDown} The orientation @code{UpsideDown} rotates the page by 180 degrees. @cindex subpictures @cindex @code{fit} A picture @code{pic} can be explicitly fit to a frame by calling @verbatim frame pic.fit(real xsize=pic.xsize, real ysize=pic.ysize, bool keepAspect=pic.keepAspect); @end verbatim The default size and aspect ratio settings are those given to the @code{size} command (which default to @code{0}, @code{0}, and @code{true}, respectively). @cindex @code{calculateTransform} The transformation that would currently be used to fit a picture @code{pic} to a frame is returned by the member function @code{pic.calculateTransform()}. In certain cases (e.g.@ 2D graphs) where only an approximate size estimate for @code{pic} is available, the picture fitting routine @verbatim frame pic.scale(real xsize=this.xsize, real ysize=this.ysize, bool keepAspect=this.keepAspect); @end verbatim (which scales the resulting frame, including labels and fixed-size objects) will enforce perfect compliance with the requested size specification, but should not normally be required. @cindex @code{box} To draw a bounding box with margins around a picture, fit the picture to a frame using the function @verbatim frame bbox(picture pic=currentpicture, real xmargin=0, real ymargin=xmargin, pen p=currentpen, filltype filltype=NoFill); @end verbatim @anchor{filltype} Here @code{filltype} specifies one of the following fill types: @table @code @cindex @code{FillDraw} @item FillDraw Fill the interior and draw the boundary. @item FillDraw(real xmargin=0, real ymargin=xmargin, pen fillpen=nullpen, @code{pen drawpen=nullpen)} @cindex @code{nullpen} If @code{fillpen} is @code{nullpen}, fill with the drawing pen; otherwise fill with pen @code{fillpen}. If @code{drawpen} is @code{nullpen}, draw the boundary with @code{fillpen}; otherwise with @code{drawpen}. An optional margin of @code{xmargin} and @code{ymargin} can be specified. @cindex @code{Fill} @item Fill Fill the interior. @cindex @code{nullpen} @item Fill(real xmargin=0, real ymargin=xmargin, pen p=nullpen) If @code{p} is @code{nullpen}, fill with the drawing pen; otherwise fill with pen @code{p}. An optional margin of @code{xmargin} and @code{ymargin} can be specified. @cindex @code{NoFill} @item NoFill Do not fill. @item Draw Draw only the boundary. @cindex @code{Draw} @item Draw(real xmargin=0, real ymargin=xmargin, pen p=nullpen) If @code{p} is @code{nullpen}, draw the boundary with the drawing pen; otherwise draw with pen @code{p}. An optional margin of @code{xmargin} and @code{ymargin} can be specified. @cindex @code{UnFill} @item UnFill Clip the region. @cindex @code{UnFill} @item UnFill(real xmargin=0, real ymargin=xmargin) Clip the region and surrounding margins @code{xmargin} and @code{ymargin}. @cindex @code{RadialShade} @item RadialShade(pen penc, pen penr) Fill varying radially from @code{penc} at the center of the bounding box to @code{penr} at the edge. @cindex @code{RadialShadeDraw} @item RadialShadeDraw(real xmargin=0, real ymargin=xmargin, pen penc, @code{pen penr, pen drawpen=nullpen)} Fill with RadialShade and draw the boundary. @end table @cindex bounding box @cindex background color For example, to draw a bounding box around a picture with a 0.25 cm margin and output the resulting frame, use the command: @verbatim shipout(bbox(0.25cm)); @end verbatim A @code{picture} may be fit to a frame with the background color pen @code{p}, using the function @code{bbox(p,Fill)}. The functions @verbatim pair min(picture pic, user=false); pair max(picture pic, user=false); pair size(picture pic, user=false); @end verbatim calculate the bounds that picture @code{pic} would have if it were currently fit to a frame using its default size specification. If @code{user} is @code{false} the returned value is in @code{PostScript} coordinates, otherwise it is in user coordinates. The function @verbatim pair point(picture pic=currentpicture, pair dir, bool user=true); @end verbatim is a convenient way of determining the point on the bounding box of @code{pic} in the direction @code{dir} relative to its center, ignoring the contributions from fixed-size objects (such as labels and arrowheads). If @code{user} is @code{true} the returned value is in user coordinates, otherwise it is in @code{PostScript} coordinates. The function @verbatim pair truepoint(picture pic=currentpicture, pair dir, bool user=true); @end verbatim is identical to @code{point}, except that it also accounts for fixed-size objects, using the scaling transform that picture @code{pic} would have if currently fit to a frame using its default size specification. If @code{user} is @code{true} the returned value is in user coordinates, otherwise it is in @code{PostScript} coordinates. @anchor{add} Sometimes it is useful to draw objects on separate pictures and add one picture to another using the @code{add} function: @cindex @code{add} @verbatim void add(picture src, bool group=true, filltype filltype=NoFill, bool above=true); void add(picture dest, picture src, bool group=true, filltype filltype=NoFill, bool above=true); @end verbatim @noindent The first example adds @code{src} to @code{currentpicture}; the second one adds @code{src} to @code{dest}. The @code{group} option specifies whether or not the graphical user interface @code{xasy} should treat all of the elements of @code{src} as a single entity (@pxref{GUI}), @code{filltype} requests optional background filling or clipping, and @code{above} specifies whether to add @code{src} above or below existing objects. There are also routines to add a picture or frame @code{src} specified in postscript coordinates to another picture @code{dest} (or @code{currentpicture}) about the user coordinate @code{position}: @anchor{add about} @cindex @code{add} @cindex picture alignment @verbatim void add(picture src, pair position, bool group=true, filltype filltype=NoFill, bool above=true); void add(picture dest, picture src, pair position, bool group=true, filltype filltype=NoFill, bool above=true); void add(picture dest=currentpicture, frame src, pair position=0, bool group=true, filltype filltype=NoFill, bool above=true); void add(picture dest=currentpicture, frame src, pair position, pair align, bool group=true, filltype filltype=NoFill, bool above=true); @end verbatim The optional @code{align} argument in the last form specifies a direction to use for aligning the frame, in a manner analogous to the @code{align} argument of @code{label} (@pxref{label}). However, one key difference is that when @code{align} is not specified, labels are centered, whereas frames and pictures are aligned so that their origin is at @code{position}. Illustrations of frame alignment can be found in the examples @ref{errorbars} and @ref{image}. If you want to align three or more subpictures, group them two at a time: @verbatiminclude subpictures.asy @sp 1 @center @image{subpictures} Alternatively, one can use @code{attach} to automatically increase the size of picture @code{dest} to accommodate adding a frame @code{src} about the user coordinate @code{position}: @cindex @code{attach} @verbatim void attach(picture dest=currentpicture, frame src, pair position=0, bool group=true, filltype filltype=NoFill, bool above=true); void attach(picture dest=currentpicture, frame src, pair position, pair align, bool group=true, filltype filltype=NoFill, bool above=true); @end verbatim @cindex @code{erase} To erase the contents of a picture (but not the size specification), use the function @verbatim void erase(picture pic=currentpicture); @end verbatim @cindex @code{save} To save a snapshot of @code{currentpicture}, @code{currentpen}, and @code{currentprojection}, use the function @code{save()}. @cindex @code{restore} To restore a snapshot of @code{currentpicture}, @code{currentpen}, and @code{currentprojection}, use the function @code{restore()}. Many further examples of picture and frame operations are provided in the base module @code{plain}. @cindex verbatim @cindex @code{postscript} It is possible to insert verbatim @code{PostScript} commands in a picture with one of the routines @verbatim void postscript(picture pic=currentpicture, string s); void postscript(picture pic=currentpicture, string s, pair min, pair max) @end verbatim Here @code{min} and @code{max} can be used to specify explicit bounds associated with the resulting @code{PostScript} code. @anchor{tex} @cindex @code{tex} Verbatim @TeX{} commands can be inserted in the intermediate @code{LaTeX} output file with one of the functions @verbatim void tex(picture pic=currentpicture, string s); void tex(picture pic=currentpicture, string s, pair min, pair max) @end verbatim Here @code{min} and @code{max} can be used to specify explicit bounds associated with the resulting @TeX{} code. To issue a global @TeX{} command (such as a @TeX{} macro definition) in the @TeX{} preamble (valid for the remainder of the top-level module) use: @cindex @code{texpreamble} @verbatim void texpreamble(string s); @end verbatim The @TeX{} environment can be reset to its initial state, clearing all macro definitions, with the function @cindex @code{texreset} @verbatim void texreset(); @end verbatim @cindex @code{usepackage} The routine @verbatim void usepackage(string s, string options=""); @end verbatim provides a convenient abbreviation for @verbatim texpreamble("\usepackage["+options+"]{"+s+"}"); @end verbatim @noindent that can be used for importing @code{LaTeX} packages. @end table @node Files @section Files @cindex @code{file} @code{Asymptote} can read and write text files (including comma-separated value) files and portable @acronym{XDR} (External Data Representation) binary files. @cindex @code{input} An input file must first be opened with @verbatim input(string name="", bool check=true, string comment="#", string mode=""); @end verbatim reading is then done by assignment: @cindex open @cindex @code{input} @cindex reading @verbatim file fin=input("test.txt"); real a=fin; @end verbatim @cindex comment character @cindex @code{error} If the optional boolean argument @code{check} is @code{false}, no check will be made that the file exists. If the file does not exist or is not readable, the function @code{bool error(file)} will return @code{true}. The first character of the string @code{comment} specifies a comment character. If this character is encountered in a data file, the remainder of the line is ignored. When reading strings, a comment character followed immediately by another comment character is treated as a single literal comment character. @anchor{cd} @cindex @code{cd} @cindex directory One can change the current working directory for read operations to the contents of the string @code{s} with the function @code{string cd(string s)}, which returns the new working directory. If @code{string s} is empty, the path is reset to the value it had at program startup. @cindex @code{getc} When reading pairs, the enclosing parenthesis are optional. Strings are also read by assignment, by reading characters up to but not including a newline. In addition, @code{Asymptote} provides the function @code{string getc(file)} to read the next character (treating the comment character as an ordinary character) and return it as a string. @cindex @code{output} @cindex @code{update} @cindex append A file named @code{name} can be open for output with @verbatim file output(string name="", bool update=false, string comment="#", string mode=""); @end verbatim @noindent If @code{update=false}, any existing data in the file will be erased and only write operations can be used on the file. If @code{update=true}, any existing data will be preserved, the position will be set to the end-of-file, and both reading and writing operations will be enabled. For security reasons, writing to files in directories other than the current directory is allowed only if the @code{-globalwrite} (or @code{-nosafe}) command-line option is specified. @cindex @code{mktemp} The function @code{string mktemp(string s)} may be used to create and return the name of a unique temporary file in the current directory based on the string @code{s}. @cindex @code{stdin} @cindex @code{stdout} There are two special files: @code{stdin}, which reads from the keyboard, and @code{stdout}, which writes to the terminal. The implicit initializer for files is @code{null}. Data of a built-in type @code{T} can be written to an output file by calling one of the functions @cindex @code{write} @verbatim write(string s="", T x, suffix suffix=endl ... T[]); write(file file, string s="", T x, suffix suffix=none ... T[]); write(file file=stdout, string s="", explicit T[] x ... T[][]); write(file file=stdout, T[][]); write(file file=stdout, T[][][]); write(suffix suffix=endl); write(file file, suffix suffix=none); @end verbatim @cindex @code{none} @cindex @code{flush} @cindex @code{endl} @cindex @code{newl} @cindex @code{DOSendl} @cindex @code{DOSnewl} @cindex @code{tab} @cindex @code{comma} If @code{file} is not specified, @code{stdout} is used and terminated by default with a newline. If specified, the optional identifying string @code{s} is written before the data @code{x}. An arbitrary number of data values may be listed when writing scalars or one-dimensional arrays. The @code{suffix} may be one of the following: @code{none} (do nothing), @code{flush} (output buffered data), @code{endl} (terminate with a newline and flush), @code{newl} (terminate with a newline), @code{DOSendl} (terminate with a DOS newline and flush), @code{DOSnewl} (terminate with a DOS newline), @code{tab} (terminate with a tab), or @code{comma} (terminate with a comma). Here are some simple examples of data output: @verbatim file fout=output("test.txt"); write(fout,1); // Writes "1" write(fout); // Writes a new line write(fout,"List: ",1,2,3); // Writes "List: 1 2 3" @end verbatim @noindent @cindex binary format @cindex single precision @cindex double precision @cindex @code{singlereal} @cindex @code{singleint} @cindex @code{signedint} @cindex @code{mode} @cindex @code{binary} @cindex @code{xdr} A file may be opened with @code{mode="xdr"}, to read or write double precision (64-bit) reals and single precision (32-bit) integers in Sun Microsystem's @acronym{XDR} (External Data Representation) portable binary format (available on all @code{UNIX} platforms). Alternatively, a file may also be opened with @code{mode="binary"} to read or write double precision reals and single precision integers in the native (nonportable) machine binary format. The virtual member functions @code{file singlereal(bool b=true)} and @code{file singleint(bool b=true)} be used to change the precision of real and integer I/O operations, respectively, for an @acronym{XDR} or binary file @code{f}. Similarly, the function @code{file signedint(bool b=true)} can be used to modify the signedness of integer reads and writes for an @acronym{XDR} or binary file @code{f}. @cindex @code{name} @cindex @code{mode} @cindex @code{singlereal} @cindex @code{singleint} @cindex @code{signedint} The virtual members @code{name}, @code{mode}, @code{singlereal}, @code{singleint}, and @code{signedint} may be used to query the respective parameters for a given file. @cindex @code{eof} @cindex @code{eol} @cindex @code{error} @cindex @code{flush} @cindex @code{clear} @cindex @code{precision} @cindex @code{seek} @cindex @code{tell} @cindex rewind @cindex @code{seekeof} One can test a file for end-of-file with the boolean function @code{eof(file)}, end-of-line with @code{eol(file)}, and for I/O errors with @code{error(file)}. One can flush the output buffers with @code{flush(file)}, clear a previous I/O error with @code{clear(file)}, and close the file with @code{close(file)}. The function @code{int precision(file file=stdout, int digits=0)} sets the number of digits of output precision for @code{file} to @code{digits}, provided @code{digits} is nonzero, and returns the previous precision setting. The function @code{int tell(file)} returns the current position in a file relative to the beginning. The routine @code{seek(file file, int pos)} can be used to change this position, where a negative value for the position @code{pos} is interpreted as relative to the end-of-file. For example, one can rewind a file @code{file} with the command @code{seek(file,0)} and position to the final character in the file with @code{seek(file,-1)}. The command @code{seekeof(file)} sets the position to the end of the file. @cindex @code{scroll} @anchor{scroll} Assigning @code{settings.scroll=n} for a positive integer @code{n} requests a pause after every @code{n} output lines to @code{stdout}. One may then press @code{Enter} to continue to the next @code{n} output lines, @code{s} followed by @code{Enter} to scroll without further interruption, or @code{q} followed by @code{Enter} to quit the current output operation. If @code{n} is negative, the output scrolls a page at a time (i.e. by one less than the current number of display lines). The default value, @code{settings.scroll=0}, specifies continuous scrolling. The routines @cindex @code{getstring} @cindex @code{getreal} @cindex @code{getpair} @cindex @code{gettriple} @verbatim string getstring(string name="", string default="", string prompt="", bool store=true); int getint(string name="", int default=0, string prompt="", bool store=true); real getreal(string name="", real default=0, string prompt="", bool store=true); pair getpair(string name="", pair default=0, string prompt="", bool store=true); triple gettriple(string name="", triple default=(0,0,0), string prompt="", bool store=true); @end verbatim @noindent defined in the module @code{plain} may be used to prompt for a value from @code{stdin} using the @acronym{GNU} @code{readline} library. If @code{store=true}, the history of values for @code{name} is stored in the file @code{".asy_history_"+name} (@pxref{history}). The most recent value in the history will be used to provide a default value for subsequent runs. The default value (initially @code{default}) is displayed after @code{prompt}. These functions are based on the internal routines @cindex @code{readline} @cindex @code{saveline} @verbatim string readline(string prompt="", string name="", bool tabcompletion=false); void saveline(string name, string value, bool store=true); @end verbatim Here, @code{readline} prompts the user with the default value formatted according to @code{prompt}, while @code{saveline} is used to save the string @code{value} in a local history named @code{name}, optionally storing the local history in a file @code{".asy_history_"+name}. @cindex @code{history} The routine @code{history(string name, int n=1)} can be used to look up the @code{n} most recent values (or all values up to @code{historylines} if @code{n=0}) entered for string @code{name}. The routine @code{history(int n=0)} returns the interactive history. For example, @verbatim write(output("transcript.asy"),history()); @end verbatim @noindent outputs the interactive history to the file @code{transcript.asy}. @cindex @code{delete} The function @code{int delete(string s)} deletes the file named by the string @code{s}. Unless the @code{-globalwrite} (or @code{-nosafe}) option is enabled, the file must reside in the current directory. @cindex @code{rename} The function @code{int rename(string from, string to)} may be used to rename file @code{from} to file @code{to}. Unless the @code{-globalwrite} (or @code{-nosafe}) option is enabled, this operation is restricted to the current directory. @cindex @code{convert} @cindex @code{animate} The functions @verbatim int convert(string args="", string file="", string format=""); int animate(string args="", string file="", string format=""); @end verbatim @noindent call the @code{ImageMagick} commands @code{convert} and @code{animate}, respectively, with the arguments @code{args} and the file name constructed from the strings @code{file} and @code{format}. @node Variable initializers @section Variable initializers @cindex variable initializers @cindex @code{operator init} @cindex initializers A variable can be assigned a value when it is declared, as in @code{int x=3;} where the variable @code{x} is assigned the value @code{3}. As well as literal constants such as @code{3}, arbitary expressions can be used as initializers, as in @code{real x=2*sin(pi/2);}. A variable is not added to the namespace until after the initializer is evaluated, so for example, in @verbatim int x=2; int x=5*x; @end verbatim @noindent the @code{x} in the initializer on the second line refers to the variable @code{x} declared on the first line. The second line, then, declares a variable @code{x} shadowing the original @code{x} and initializes it to the value @code{10}. Variables of most types can be declared without an explicit initializer and they will be initialized by the default initializer of that type: @itemize @item Variables of the numeric types @code{int}, @code{real}, and @code{pair} are all initialized to zero; variables of type @code{triple} are initialized to @code{O=(0,0,0)}. @item @code{boolean} variables are initialized to @code{false}. @item @code{string} variables are initialized to the empty string. @item @code{transform} variables are initialized to the identity transformation. @item @code{path} and @code{guide} variables are initialized to @code{nullpath}. @item @code{pen} variables are initialized to the default pen. @item @code{frame} and @code{picture} variables are initialized to empty frames and pictures, respectively. @item @code{file} variables are initialized to @code{null}. @end itemize The default initializers for user-defined array, structure, and function types are explained in their respective sections. Some types, such as @code{code}, do not have default initializers. When a variable of such a type is introduced, the user must initialize it by explicitly giving it a value. The default initializer for any type @code{T} can be redeclared by defining the function @code{T operator init()}. For instance, @code{int} variables are usually initialized to zero, but in @verbatim int operator init() { return 3; } int y; @end verbatim @noindent the variable @code{y} is initialized to @code{3}. This example was given for illustrative purposes; redeclaring the initializers of built-in types is not recommended. Typically, @code{operator init} is used to define sensible defaults for user-defined types. @cindex @code{var} The special type @code{var} may be used to infer the type of a variable from its initializer. If the initializer is an expression of a unique type, then the variable will be defined with that type. For instance, @verbatim var x=5; var y=4.3; var reddash=red+dashed; @end verbatim @noindent is equivalent to @verbatim int x=5; real y=4.3; pen reddash=red+dashed; @end verbatim @code{var} may also be used with the extended @code{for} loop syntax. @verbatim int[] a = {1,2,3}; for (var x : a) write(x); @end verbatim @node Structures @section Structures @cindex @code{struct} @cindex structures @cindex @code{public} @cindex @code{restricted} @cindex @code{private} @cindex @code{this} @cindex @code{new} @cindex @code{null} Users may also define their own data types as structures, along with user-defined operators, much as in C++. By default, structure members are @code{public} (may be read and modified anywhere in the code), but may be optionally declared @code{restricted} (readable anywhere but writeable only inside the structure where they are defined) or @code{private} (readable and writable only inside the structure). In a structure definition, the keyword @code{this} can be used as an expression to refer to the enclosing structure. Any code at the top-level scope within the structure is executed on initialization. Variables hold references to structures. That is, in the example: @verbatim struct T { int x; } T foo; T bar=foo; bar.x=5; @end verbatim The variable @code{foo} holds a reference to an instance of the structure @code{T}. When @code{bar} is assigned the value of @code{foo}, it too now holds a reference to the same instance as @code{foo} does. The assignment @code{bar.x=5} changes the value of the field @code{x} in that instance, so that @code{foo.x} will also be equal to @code{5}. The expression @code{new T} creates a new instance of the structure @code{T} and returns a reference to that instance. In creating the new instance, any code in the body of the record definition is executed. For example: @verbatim int Tcount=0; struct T { int x; ++Tcount; } T foo=new T; T foo; @end verbatim @noindent Here, @code{new T} produces a new instance of the class, which causes @code{Tcount} to be incremented, tracking the number of instances produced. The declarations @code{T foo=new T} and @code{T foo} are equivalent: the second form implicitly creates a new instance of @code{T}. That is, after the definition of a structure @code{T}, a variable of type @code{T} is initialized to a new instance (@code{new T}) by default. During the definition of the structure, however, variables of type @code{T} are initialized to @code{null} by default. This special behaviour is to avoid infinite recursion of creating new instances in code such as @verbatim struct tree { int value; tree left; tree right; } @end verbatim The expression @code{null} can be cast to any structure type to yield a null reference, a reference that does not actually refer to any instance of the structure. Trying to use a field of a null reference will cause an error. @cindex alias @cindex @code{==} @cindex @code{!=} The function @code{bool alias(T,T)} checks to see if two structure references refer to the same instance of the structure (or both to @code{null}). In example at the beginning of this section, @code{alias(foo,bar)} would return true, but @code{alias(foo,new T)} would return false, as @code{new T} creates a new instance of the structure @code{T}. The boolean operators @code{==} and @code{!=} are by default equivalent to @code{alias} and @code{!alias} respectively, but may be overwritten for a particular type (for example, to do a deep comparison). Here is a simple example that illustrates the use of structures: @verbatim struct S { real a=1; real f(real a) {return a+this.a;} } S s; // Initializes s with new S; write(s.f(2)); // Outputs 3 S operator + (S s1, S s2) { S result; result.a=s1.a+s2.a; return result; } write((s+s).f(0)); // Outputs 2 @end verbatim @cindex constructors It is often convenient to have functions that construct new instances of a structure. Say we have a @code{Person} structure: @verbatim struct Person { string firstname; string lastname; } Person joe; joe.firstname="Joe"; joe.lastname="Jones"; @end verbatim @noindent Creating a new Person is a chore; it takes three lines to create a new instance and to initialize its fields (that's still considerably less effort than creating a new person in real life, though). We can reduce the work by defining a constructor function @code{Person(string,string)}: @verbatim struct Person { string firstname; string lastname; static Person Person(string firstname, string lastname) { Person p=new Person; p.firstname=firstname; p.lastname=lastname; return p; } } Person joe=Person.Person("Joe", "Jones"); @end verbatim While it is now easier than before to create a new instance, we still have to refer to the constructor by the qualified name @code{Person.Person}. If we add the line @verbatim from Person unravel Person; @end verbatim @noindent immediately after the structure definition, then the constructor can be used without qualification: @code{Person joe=Person("Joe", "Jones");}. The constructor is now easy to use, but it is quite a hassle to define. If you write a lot of constructors, you will find that you are repeating a lot of code in each of them. Fortunately, your friendly neighbourhood Asymptote developers have devised a way to automate much of the process. @cindex @code{operator init} If, in the body of a structure, Asymptote encounters the definition of a function of the form @code{void operator init(@var{args})}, it implicitly defines a constructor function of the arguments @code{@var{args}} that uses the @code{void operator init} function to initialize a new instance of the structure. That is, it essentially defines the following constructor (assuming the structure is called @code{Foo}): @example static Foo Foo(@var{args}) @{ Foo instance=new Foo; instance.operator init(@var{args}); return instance; @} @end example This constructor is also implicitly copied to the enclosing scope after the end of the structure definition, so that it can used subsequently without qualifying it by the structure name. Our @code{Person} example can thus be implemented as: @verbatim struct Person { string firstname; string lastname; void operator init(string firstname, string lastname) { this.firstname=firstname; this.lastname=lastname; } } Person joe=Person("Joe", "Jones"); @end verbatim The use of @code{operator init} to implicitly define constructors should not be confused with its use to define default values for variables (@pxref{Variable initializers}). Indeed, in the first case, the return type of the @code{operator init} must be @code{void} while in the second, it must be the (non-@code{void}) type of the variable. @cindex @code{cputime} The function @code{cputime()} returns a structure @code{cputime} with cumulative @acronym{CPU} times broken down into the fields @code{parent.user}, @code{parent.system}, @code{child.user}, and @code{child.system}. For convenience, the incremental fields @code{change.user} and @code{change.system} indicate the change in the corresponding total parent and child @acronym{CPU} times since the last call to @code{cputime()}. The function @verbatim void write(file file=stdout, string s="", cputime c, string format=cputimeformat, suffix suffix=none); @end verbatim @noindent displays the incremental user cputime followed by ``u'', the incremental system cputime followed by ``s'', the total user cputime followed by ``U'', and the total system cputime followed by ``S''. @cindex inheritance @cindex virtual functions Much like in C++, casting (@pxref{Casts}) provides for an elegant implementation of structure inheritance, including virtual functions: @verbatim struct parent { real x; void operator init(int x) {this.x=x;} void virtual(int) {write(0);} void f() {virtual(1);} } void write(parent p) {write(p.x);} struct child { parent parent; real y=3; void operator init(int x) {parent.operator init(x);} void virtual(int x) {write(x);} parent.virtual=virtual; void f()=parent.f; } parent operator cast(child child) {return child.parent;} parent p=parent(1); child c=child(2); write(c); // Outputs 2; p.f(); // Outputs 0; c.f(); // Outputs 1; write(c.parent.x); // Outputs 2; write(c.y); // Outputs 3; @end verbatim For further examples of structures, see @code{Legend} and @code{picture} in the @code{Asymptote} base module @code{plain}. @node Operators @section Operators @cindex operators @menu * Arithmetic & logical:: Basic mathematical operators * Self & prefix operators:: Increment and decrement * User-defined operators:: Overloading operators @end menu @node Arithmetic & logical @subsection Arithmetic & logical operators @cindex arithmetic operators @cindex binary operators @cindex boolean operators @cindex logical operators @cindex integer division @cindex @code{quotient} @code{Asymptote} uses the standard binary arithmetic operators. However, when one integer is divided by another, both arguments are converted to real values before dividing and a real quotient is returned (since this is usually what is intended). The function @code{int quotient(int x, int y)} returns the greatest integer less than or equal to @code{x/y}. In all other cases both operands are promoted to the same type, which will also be the type of the result: @table @code @cindex @code{+} @item + addition @cindex @code{-} @item - subtraction @cindex @code{*} @item * multiplication @cindex @code{/} @item / division @cindex @code{%} @item % modulo; the result always has the same sign as the divisor. In particular, this makes @code{q*quotient(p,q)+p%q == p} for all integers @code{p} and nonzero integers @code{q}. @cindex @code{^} @item ^ @cindex @code{**} power; if the exponent (second argument) is an int, recursive multiplication is used; otherwise, logarithms and exponentials are used (@code{**} is a synonym for @code{^}). @end table The usual boolean operators are also defined: @table @code @cindex @code{==} @item == equals @cindex @code{!=} @item != not equals @cindex @code{<} @item < less than @cindex @code{<=} @item <= less than or equals @cindex @code{>=} @item >= greater than or equals @cindex @code{>} @item > greater than @cindex @code{&&} @item && and (with conditional evaluation of right-hand argument) @cindex @code{&} @item & and @cindex @code{||} @item || or (with conditional evaluation of right-hand argument) @cindex @code{|} @item | or @cindex @code{^} @item ^ xor @cindex @code{!} @item ! not @end table @code{Asymptote} also supports the C-like conditional syntax: @cindex @code{:} @cindex @code{?} @cindex conditional @verbatim bool positive=(pi > 0) ? true : false; @end verbatim @cindex @code{interp} The function @code{T interp(T a, T b, real t)} returns @code{(1-t)*a+t*b} for nonintegral built-in arithmetic types @code{T}. If @code{a} and @code{b} are pens, they are first promoted to the same color space. @cindex @code{AND} @cindex @code{OR} @cindex @code{XOR} @cindex @code{NOT} @cindex @code{CLZ} @cindex @code{CTZ} @code{Asymptote} also defines bitwise functions @code{int AND(int,int)}, @code{int OR(int,int)}, @code{int XOR(int,int)}, @code{int NOT(int)}, @code{int CLZ(int)} (count leading zeros), and @code{int CTZ(int)} (count trailing zeros). @node Self & prefix operators @subsection Self & prefix operators @cindex self operators @cindex prefix operators @cindex @code{+=} @cindex @code{-=} @cindex @code{*=} @cindex @code{/=} @cindex @code{%=} @cindex @code{^=} @cindex @code{++} @cindex @code{--} As in C, each of the arithmetic operators @code{+}, @code{-}, @code{*}, @code{/}, @code{%}, and @code{^} can be used as a self operator. The prefix operators @code{++} (increment by one) and @code{--} (decrement by one) are also defined. For example, @verbatim int i=1; i += 2; int j=++i; @end verbatim @noindent is equivalent to the code @verbatim int i=1; i=i+2; int j=i=i+1; @end verbatim @cindex postfix operators However, postfix operators like @code{i++} and @code{i--} are not defined (because of the inherent ambiguities that would arise with the @code{--} path-joining operator). In the rare instances where @code{i++} and @code{i--} are really needed, one can substitute the expressions @code{(++i-1)} and @code{(--i+1)}, respectively. @node User-defined operators @subsection User-defined operators @cindex user-defined operators @cindex @code{operator} The following symbols may be used with @code{operator} to define or redefine operators on structures and built-in types: @verbatim - + * / % ^ ! < > == != <= >= & | ^^ .. :: -- --- ++ << >> $ $$ @ @@ @end verbatim @noindent The operators on the second line have precedence one higher than the boolean operators @code{<}, @code{>}, @code{<=}, and @code{>=}. Guide operators like @code{..} may be overloaded, say, to write a user function that produces a new guide from a given guide: @verbatim guide dots(... guide[] g)=operator ..; guide operator ..(... guide[] g) { guide G; if(g.length > 0) { write(g[0]); G=g[0]; } for(int i=1; i < g.length; ++i) { write(g[i]); write(); G=dots(G,g[i]); } return G; } guide g=(0,0){up}..{SW}(100,100){NE}..{curl 3}(50,50)..(10,10); write("g=",g); @end verbatim @node Implicit scaling @section Implicit scaling @cindex implicit scaling If a numeric literal is in front of certain types of expressions, then the two are multiplied: @verbatim int x=2; real y=2.0; real cm=72/2.540005; write(3x); write(2.5x); write(3y); write(-1.602e-19 y); write(0.5(x,y)); write(2x^2); write(3x+2y); write(3(x+2y)); write(3sin(x)); write(3(sin(x))^2); write(10cm); @end verbatim This produces the output @verbatim 6 5 6 -3.204e-19 (1,1) 8 10 18 2.72789228047704 2.48046543129542 283.464008929116 @end verbatim @node Functions @section Functions @cindex functions @code{Asymptote} functions are treated as variables with a signature (non-function variables have null signatures). Variables with the same name are allowed, so long as they have distinct signatures. Functions arguments are passed by value. To pass an argument by reference, simply enclose it in a structure (@pxref{Structures}). Here are some significant features of @code{Asymptote} functions: @enumerate @item Variables with signatures (functions) and without signatures (nonfunction variables) are distinct: @verbatim int x, x(); x=5; x=new int() {return 17;}; x=x(); // calls x() and puts the result, 17, in the scalar x @end verbatim @item Traditional function definitions are allowed: @verbatim int sqr(int x) { return x*x; } sqr=null; // but the function is still just a variable. @end verbatim @item Casting can be used to resolve ambiguities: @verbatim int a, a(), b, b(); // Valid: creates four variables. a=b; // Invalid: assignment is ambiguous. a=(int) b; // Valid: resolves ambiguity. (int) (a=b); // Valid: resolves ambiguity. (int) a=b; // Invalid: cast expressions cannot be L-values. int c(); c=a; // Valid: only one possible assignment. @end verbatim @item Anonymous (so-called "high-order") functions are also allowed: @cindex @code{typedef} @verbatim typedef int intop(int); intop adder(int m) { return new int(int n) {return m+n;}; } intop addby7=adder(7); write(addby7(1)); // Writes 8. @end verbatim @item @cindex overloading functions One may redefine a function @code{f}, even for calls to @code{f} in previously declared functions, by assigning another (anonymous or named) function to it. However, if @code{f} is overloaded by a new function definition, previous calls will still access the original version of @code{f}, as illustrated in this example: @verbatim void f() { write("hi"); } void g() { f(); } g(); // writes "hi" f=new void() {write("bye");}; g(); // writes "bye" void f() {write("overloaded");}; f(); // writes "overloaded" g(); // writes "bye" @end verbatim @cindex function declarations @item Anonymous functions can be used to redefine a function variable that has been declared (and implicitly initialized to the null function) but not yet explicitly defined: @verbatim void f(bool b); void g(bool b) { if(b) f(b); else write(b); } f=new void(bool b) { write(b); g(false); }; g(true); // Writes true, then writes false. @end verbatim @end enumerate @code{Asymptote} is the only language we know of that treats functions as variables, but allows overloading by distinguishing variables based on their signatures. @cindex @code{libsigsegv} @cindex stack overflow @anchor{stack overflow} @cindex recursion @cindex stack overflow Functions are allowed to call themselves recursively. As in C++, infinite nested recursion will generate a stack overflow (reported as a segmentation fault, unless a fully working version of the @acronym{GNU} library @code{libsigsegv} (e.g.@ 2.4 or later) is installed at configuration time). @menu * Default arguments:: Default values can appear anywhere * Named arguments:: Assigning function arguments by keyword * Rest arguments:: Functions with a variable number of arguments * Mathematical functions:: Standard libm functions @end menu @node Default arguments @subsection Default arguments @cindex default arguments @cindex arguments @code{Asymptote} supports a more flexible mechanism for default function arguments than C++: they may appear anywhere in the function prototype. Because certain data types are implicitly cast to more sophisticated types (@pxref{Casts}) one can often avoid ambiguities by ordering function arguments from the simplest to the most complicated. For example, given @verbatim real f(int a=1, real b=0) {return a+b;} @end verbatim @noindent then @code{f(1)} returns 1.0, but @code{f(1.0)} returns 2.0. The value of a default argument is determined by evaluating the given @code{Asymptote} expression in the scope where the called function is defined. @node Named arguments @subsection Named arguments @cindex keywords @cindex named arguments It is sometimes difficult to remember the order in which arguments appear in a function declaration. Named (keyword) arguments make calling functions with multiple arguments easier. Unlike in the C and C++ languages, an assignment in a function argument is interpreted as an assignment to a parameter of the same name in the function signature, @emph{not within the local scope}. The command-line option @code{-d} may be used to check @code{Asymptote} code for cases where a named argument may be mistaken for a local assignment. When matching arguments to signatures, first all of the keywords are matched, then the arguments without names are matched against the unmatched formals as usual. For example, @verbatim int f(int x, int y) { return 10x+y; } write(f(4,x=3)); @end verbatim @noindent outputs 34, as @code{x} is already matched when we try to match the unnamed argument @code{4}, so it gets matched to the next item, @code{y}. For the rare occasions where it is desirable to assign a value to local variable within a function argument (generally @emph{not} a good programming practice), simply enclose the assignment in parentheses. For example, given the definition of @code{f} in the previous example, @verbatim int x; write(f(4,(x=3))); @end verbatim @noindent is equivalent to the statements @verbatim int x; x=3; write(f(4,3)); @end verbatim @noindent and outputs 43. @cindex @code{keyword} @cindex keyword-only Parameters can be specified as ``keyword-only'' by putting @code{keyword} immediately before the parameter name, as in @code{int f(int keyword x)} or @code{int f(int keyword x=77)}. This forces the caller of the function to use a named argument to give a value for this parameter. That is, @code{f(x=42)} is legal, but @code{f(25)} is not. Keyword-only parameters must be listed after normal parameters in a function definition. As a technical detail, we point out that, since variables of the same name but different signatures are allowed in the same scope, the code @verbatim int f(int x, int x()) { return x+x(); } int seven() {return 7;} @end verbatim @noindent is legal in @code{Asymptote}, with @code{f(2,seven)} returning 9. A named argument matches the first unmatched formal of the same name, so @code{f(x=2,x=seven)} is an equivalent call, but @code{f(x=seven,2)} is not, as the first argument is matched to the first formal, and @code{int ()} cannot be implicitly cast to @code{int}. Default arguments do not affect which formal a named argument is matched to, so if @code{f} were defined as @verbatim int f(int x=3, int x()) { return x+x(); } @end verbatim @noindent then @code{f(x=seven)} would be illegal, even though @code{f(seven)} obviously would be allowed. @node Rest arguments @subsection Rest arguments @cindex rest arguments Rest arguments allow one to write functions that take a variable number of arguments: @verbatim // This function sums its arguments. int sum(... int[] nums) { int total=0; for(int i=0; i < nums.length; ++i) total += nums[i]; return total; } sum(1,2,3,4); // returns 10 sum(); // returns 0 // This function subtracts subsequent arguments from the first. int subtract(int start ... int[] subs) { for(int i=0; i < subs.length; ++i) start -= subs[i]; return start; } subtract(10,1,2); // returns 7 subtract(10); // returns 10 subtract(); // illegal @end verbatim @cindex packing Putting an argument into a rest array is called @emph{packing}. One can give an explicit list of arguments for the rest argument, so @code{subtract} could alternatively be implemented as @verbatim int subtract(int start ... int[] subs) { return start - sum(... subs); } @end verbatim One can even combine normal arguments with rest arguments: @verbatim sum(1,2,3 ... new int[] {4,5,6}); // returns 21 @end verbatim @noindent @cindex unpacking This builds a new six-element array that is passed to @code{sum} as @code{nums}. The opposite operation, @emph{unpacking}, is not allowed: @verbatim subtract(... new int[] {10, 1, 2}); @end verbatim @noindent is illegal, as the start formal is not matched. If no arguments are packed, then a zero-length array (as opposed to @code{null}) is bound to the rest parameter. Note that default arguments are ignored for rest formals and the rest argument is not bound to a keyword. In some cases, keyword-only parameters are helpful to avoid arguments intended for the rest parameter to be assigned to other parameters. For example, here the use of @code{keyword} is to avoid @code{pnorm(1.0,2.0,0.3)} matching @code{1.0} to @code{p}. @verbatim real pnorm(real keyword p=2.0 ... real[] v) { return sum(v^p)^(1/p); } @end verbatim The overloading resolution in @code{Asymptote} is similar to the function matching rules used in C++. Every argument match is given a score. Exact matches score better than matches with casting, and matches with formals (regardless of casting) score better than packing an argument into the rest array. A candidate is maximal if all of the arguments score as well in it as with any other candidate. If there is one unique maximal candidate, it is chosen; otherwise, there is an ambiguity error. @verbatim int f(path g); int f(guide g); f((0,0)--(100,100)); // matches the second; the argument is a guide int g(int x, real y); int g(real x, int x); g(3,4); // ambiguous; the first candidate is better for the first argument, // but the second candidate is better for the second argument int h(... int[] rest); int h(real x ... int[] rest); h(1,2); // the second definition matches, even though there is a cast, // because casting is preferred over packing int i(int x ... int[] rest); int i(real x, real y ... int[] rest); i(3,4); // ambiguous; the first candidate is better for the first argument, // but the second candidate is better for the second one @end verbatim @node Mathematical functions @subsection Mathematical functions @cindex mathematical functions @cindex functions @cindex @code{libm} routines @cindex @code{sin} @cindex @code{cos} @cindex @code{tan} @cindex @code{asin} @cindex @code{acos} @cindex @code{atan} @cindex @code{exp} @cindex @code{log} @cindex @code{pow10} @cindex @code{log10} @cindex @code{sinh} @cindex @code{cosh} @cindex @code{tanh} @cindex @code{asinh} @cindex @code{acosh} @cindex @code{atanh} @cindex @code{sqrt} @cindex @code{cbrt} @cindex @code{fabs} @cindex @code{expm1} @cindex @code{log1p} @cindex @code{identity} @cindex @code{J} @cindex @code{Y} @cindex @code{gamma} @cindex @code{erf} @cindex @code{erfc} @cindex @code{atan2} @cindex @code{hypot} @cindex @code{fmod} @cindex @code{remainder} @code{Asymptote} has built-in versions of the standard @code{libm} mathematical real(real) functions @code{sin}, @code{cos}, @code{tan}, @code{asin}, @code{acos}, @code{atan}, @code{exp}, @code{log}, @code{pow10}, @code{log10}, @code{sinh}, @code{cosh}, @code{tanh}, @code{asinh}, @code{acosh}, @code{atanh}, @code{sqrt}, @code{cbrt}, @code{fabs}, @code{expm1}, @code{log1p}, as well as the identity function @code{identity}. @code{Asymptote} also defines the order @code{n} Bessel functions of the first kind @code{Jn(int n, real)} and second kind @code{Yn(int n, real)}, as well as the gamma function @code{gamma}, the error function @code{erf}, and the complementary error function @code{erfc}. The standard real(real, real) functions @code{atan2}, @code{hypot}, @code{fmod}, @code{remainder} are also included. @cindex @code{degrees} @cindex @code{radians} @cindex @code{Degrees} The functions @code{degrees(real radians)} and @code{radians(real degrees)} can be used to convert between radians and degrees. The function @code{Degrees(real radians)} returns the angle in degrees in the interval [0,360). @cindex @code{Sin} @cindex @code{Cos} @cindex @code{Tan} @cindex @code{aSin} @cindex @code{aCos} @cindex @code{aTan} For convenience, @code{Asymptote} defines variants @code{Sin}, @code{Cos}, @code{Tan}, @code{aSin}, @code{aCos}, and @code{aTan} of the standard trigonometric functions that use degrees rather than radians. We also define complex versions of the @code{sqrt}, @code{sin}, @code{cos}, @code{exp}, @code{log}, and @code{gamma} functions. @cindex @code{floor} @cindex @code{ceil} @cindex @code{round} @cindex @code{sgn} The functions @code{floor}, @code{ceil}, and @code{round} differ from their usual definitions in that they all return an int value rather than a real (since that is normally what one wants). The functions @code{Floor}, @code{Ceil}, and @code{Round} are respectively similar, except that if the result cannot be converted to a valid int, they return @code{intMax} for positive arguments and @code{intMin} for negative arguments, rather than generating an integer overflow. We also define a function @code{sgn}, which returns the sign of its real argument as an integer (-1, 0, or 1). @cindex @code{abs} There is an @code{abs(int)} function, as well as an @code{abs(real)} function (equivalent to @code{fabs(real)}), an @code{abs(pair)} function (equivalent to @code{length(pair)}). @cindex @code{srand} @cindex @code{rand} @cindex @code{randMax} @cindex @code{unitrand} @cindex @code{Gaussrand} @cindex @code{histogram} @cindex @code{factorial} @cindex @code{choose} Random numbers can be seeded with @code{srand(int)} and generated with the @code{int rand()} function, which returns a random integer between 0 and the integer @code{randMax}. The @code{unitrand()} function returns a random number uniformly distributed in the interval [0,1]. A Gaussian random number generator @code{Gaussrand} and a collection of statistics routines, including @code{histogram}, are provided in the base file @code{stats.asy}. The functions @code{factorial(int n)}, which returns @math{n!}, and @code{choose(int n, int k)}, which returns @math{n!/(k!(n-k)!)}, are also defined. @cindex @acronym{GNU} Scientific Library @cindex @code{gsl} @cindex Airy @cindex Bessel @cindex Legendre @cindex elliptic functions @cindex exponential integral @cindex trigonometric integrals @cindex Riemann zeta function @cindex @code{Ai} @cindex @code{Bi} @cindex @code{Ai_deriv} @cindex @code{Bi_deriv} @cindex @code{zero_Ai} @cindex @code{zero_Bi} @cindex @code{zero_Ai_deriv} @cindex @code{zero_Bi_deriv} @cindex @code{J} @cindex @code{Y} @cindex @code{I} @cindex @code{K} @cindex @code{i_scaled} @cindex @code{k_scaled} @cindex @code{zero_J} @cindex @code{F} @cindex @code{E} @cindex @code{P} @cindex @code{sncndn} @cindex @code{Ei} @cindex @code{Si} @cindex @code{Ci} @cindex @code{Pl} @cindex @code{zeta} When configured with the @acronym{GNU} Scientific Library (GSL), available from @url{http://www.gnu.org/software/gsl/}, @code{Asymptote} contains an internal module @code{gsl} that defines the airy functions @code{Ai(real)}, @code{Bi(real)}, @code{Ai_deriv(real)}, @code{Bi_deriv(real)}, @code{zero_Ai(int)}, @code{zero_Bi(int)}, @code{zero_Ai_deriv(int)}, @code{zero_Bi_deriv(int)}, the Bessel functions @code{I(int, real)}, @code{K(int, real)}, @code{j(int, real)}, @code{y(int, real)}, @code{i_scaled(int, real)}, @code{k_scaled(int, real)}, @code{J(real, real)}, @code{Y(real, real)}, @code{I(real, real)}, @code{K(real, real)}, @code{zero_J(real, int)}, the elliptic functions @code{F(real, real)}, @code{E(real, real)}, and @code{P(real, real)}, the Jacobi elliptic functions @code{real[] sncndn(real,real)}, the exponential/trigonometric integrals @code{Ei}, @code{Si}, and @code{Ci}, the Legendre polynomials @code{Pl(int, real)}, and the Riemann zeta function @code{zeta(real)}. For example, to compute the sine integral @code{Si} of 1.0: @verbatim import gsl; write(Si(1.0)); @end verbatim @code{Asymptote} also provides a few general purpose numerical routines: @table @code @cindex @code{newton} @item @code{real newton(int iterations=100, real f(real), real fprime(real), real x, bool verbose=false);} Use Newton-Raphson iteration to solve for a root of a real-valued differentiable function @code{f}, given its derivative @code{fprime} and an initial guess @code{x}. Diagnostics for each iteration are printed if @code{verbose=true}. If the iteration fails after the maximum allowed number of loops (@code{iterations}), @code{realMax} is returned. @cindex @code{newton} @item @code{real newton(int iterations=100, real f(real), real fprime(real), real x1, real x2, bool verbose=false);} Use bracketed Newton-Raphson bisection to solve for a root of a real-valued differentiable function @code{f} within an interval [@code{x1},@code{x2}] (on which the endpoint values of @code{f} have opposite signs), given its derivative @code{fprime}. Diagnostics for each iteration are printed if @code{verbose=true}. If the iteration fails after the maximum allowed number of loops (@code{iterations}), @code{realMax} is returned. @cindex @code{simpson} @item @code{real simpson(real f(real), real a, real b, real acc=realEpsilon, real dxmax=b-a)} returns the integral of @code{f} from @code{a} to @code{b} using adaptive Simpson integration. @end table @node Arrays @section Arrays @cindex arrays @menu * Slices:: Python-style array slices @end menu Appending @code{[]} to a built-in or user-defined type yields an array. The array element @code{i} of an array @code{A} can be accessed as @code{A[i]}. By default, attempts to access or assign to an array element using a negative index generates an error. Reading an array element with an index beyond the length of the array also generates an error; however, assignment to an element beyond the length of the array causes the array to be resized to accommodate the new element. One can also index an array @code{A} with an integer array @code{B}: the array @code{A[B]} is formed by indexing array @code{A} with successive elements of array @code{B}. A convenient Java-style shorthand exists for iterating over all elements of an array; see @ref{array iteration}. The declaration @verbatim real[] A; @end verbatim @noindent initializes @code{A} to be an empty (zero-length) array. Empty arrays should be distinguished from null arrays. If we say @verbatim real[] A=null; @end verbatim @noindent then @code{A} cannot be dereferenced at all (null arrays have no length and cannot be read from or assigned to). Arrays can be explicitly initialized like this: @verbatim real[] A={0,1,2}; @end verbatim Array assignment in @code{Asymptote} does a shallow copy: only the pointer is copied (if one copy if modified, the other will be too). The @code{copy} function listed below provides a deep copy of an array. @cindex @code{length} @cindex @code{cyclic} @cindex @code{keys} @cindex @code{push} @cindex @code{append} @cindex @code{pop} @cindex @code{insert} @cindex @code{delete} @cindex @code{initialized} Every array @code{A} of type @code{T[]} has the virtual members @itemize @item @code{int length}, @item @code{int cyclic}, @item @code{int[] keys}, @item @code{T push(T x)}, @item @code{void append(T[] a)}, @item @code{T pop()}, @item @code{void insert(int i ... T[] x)}, @item @code{void delete(int i, int j=i)}, @item @code{void delete()}, and @item @code{bool initialized(int n)}. @end itemize The member @code{A.length} evaluates to the length of the array. Setting @code{A.cyclic=true} signifies that array indices should be reduced modulo the current array length. Reading from or writing to a nonempty cyclic array never leads to out-of-bounds errors or array resizing. The member @code{A.keys} evaluates to an array of integers containing the indices of initialized entries in the array in ascending order. Hence, for an array of length @code{n} with all entries initialized, @code{A.keys} evaluates to @code{@{0,1,...,n-1@}}. A new keys array is produced each time @code{A.keys} is evaluated. The functions @code{A.push} and @code{A.append} append their arguments onto the end of the array, while @code{A.insert(int i ... T[] x)} inserts @code{x} into the array at index @code{i}. For convenience @code{A.push} returns the pushed item. The function @code{A.pop()} pops and returns the last element, while @code{A.delete(int i, int j=i)} deletes elements with indices in the range [@code{i},@code{j}], shifting the position of all higher-indexed elements down. If no arguments are given, @code{A.delete()} provides a convenient way of deleting all elements of @code{A}. The routine @code{A.initialized(int n)} can be used to examine whether the element at index @code{n} is initialized. Like all @code{Asymptote} functions, @code{push}, @code{append}, @code{pop}, @code{insert}, @code{delete}, and @code{initialized} can be "pulled off" of the array and used on their own. For example, @verbatim int[] A={1}; A.push(2); // A now contains {1,2}. A.append(A); // A now contains {1,2,1,2}. int f(int)=A.push; f(3); // A now contains {1,2,1,2,3}. int g()=A.pop; write(g()); // Outputs 3. A.delete(0); // A now contains {2,1,2}. A.delete(0,1); // A now contains {2}. A.insert(1,3); // A now contains {2,3}. A.insert(1 ... A); // A now contains {2,2,3,3} A.insert(2,4,5); // A now contains {2,2,4,5,3,3}. @end verbatim The @code{[]} suffix can also appear after the variable name; this is sometimes convenient for declaring a list of variables and arrays of the same type: @verbatim real a,A[]; @end verbatim @noindent This declares @code{a} to be @code{real} and implicitly declares @code{A} to be of type @code{real[]}. In the following list of built-in array functions, @code{T} represents a generic type. Note that the internal functions @code{alias}, @code{array}, @code{copy}, @code{concat}, @code{sequence}, @code{map}, and @code{transpose}, which depend on type @code{T[]}, are defined only after the first declaration of a variable of type @code{T[]}. @table @code @cindex @code{new} @item new T[] returns a new empty array of type @code{T[]}; @cindex @code{new} @item new T[] @{list@} returns a new array of type @code{T[]} initialized with @code{list} (a comma delimited list of elements). @item new T[n] returns a new array of @code{n} elements of type @code{T[]}. These @code{n} array elements are not initialized unless they are arrays themselves (in which case they are each initialized to empty arrays). @cindex @code{array} @item T[] array(int n, T value, int depth=intMax) returns an array consisting of @code{n} copies of @code{value}. If @code{value} is itself an array, a deep copy of @code{value} is made for each entry. If @code{depth} is specified, this deep copying only recurses to the specified number of levels. @cindex @code{sequence} @item int[] sequence(int n) if @code{n >= 1} returns the array @code{@{0,1,...,n-1@}} (otherwise returns a null array); @item int[] sequence(int n, int m) if @code{m >= n} returns an array @code{@{n,n+1,...,m@}} (otherwise returns a null array); @item T[] sequence(T f(int), int n) if @code{n >= 1} returns the sequence @code{@{f_i :i=0,1,...n-1@}} given a function @code{T f(int)} and integer @code{int n} (otherwise returns a null array); @cindex @code{map} @item T[] map(T f(T), T[] a) returns the array obtained by applying the function @code{f} to each element of the array @code{a}. This is equivalent to @code{sequence(new T(int i) @{return f(a[i]);@},a.length)}. @cindex @code{reverse} @item int[] reverse(int n) if @code{n >= 1} returns the array @code{@{n-1,n-2,...,0@}} (otherwise returns a null array); @cindex @code{complement} @item int[] complement(int[] a, int n) returns the complement of the integer array @code{a} in @code{@{0,1,2,...,n-1@}}, so that @code{b[complement(a,b.length)]} yields the complement of @code{b[a]}. @cindex @code{uniform} @item real[] uniform(real a, real b, int n) if @code{n >= 1} returns a uniform partition of @code{[a,b]} into @code{n} subintervals (otherwise returns a null array); @cindex @code{find} @item int find(bool[], int n=1) returns the index of the @code{n}th @code{true} value or -1 if not found. If @code{n} is negative, search backwards from the end of the array for the @code{-n}th value; @cindex @code{search} @item int search(T[] a, T key) For built-in ordered types @code{T}, searches a sorted array @code{a} of @code{n} elements for k, returning the index @code{i} if @code{a[i] <= key < a[i+1]}, @code{-1} if @code{key} is less than all elements of @code{a}, or @code{n-1} if @code{key} is greater than or equal to the last element of @code{a}. @cindex @code{search} @item int search(T[] a, T key, bool less(T i, T j)) searches an array @code{a} sorted in ascending order such that element @code{i} precedes element @code{j} if @code{less(i,j)} is true; @cindex @code{copy} @item T[] copy(T[] a) returns a deep copy of the array @code{a}; @cindex @code{concat} @item T[] concat(... T[][] a) returns a new array formed by concatenating the given one-dimensional arrays given as arguments; @cindex @code{alias} @item bool alias(T[] a, T[] b) returns @code{true} if the arrays @code{a} and @code{b} are identical; @cindex @code{sort} @item T[] sort(T[] a) For built-in ordered types @code{T}, returns a copy of @code{a} sorted in ascending order; @cindex @code{sort} @anchor{sort} @item T[][] sort(T[][] a) For built-in ordered types @code{T}, returns a copy of @code{a} with the rows sorted by the first column, breaking ties with successively higher columns. For example: @verbatim string[][] a={{"bob","9"},{"alice","5"},{"pete","7"}, {"alice","4"}}; // Row sort (by column 0, using column 1 to break ties): write(sort(a)); @end verbatim produces @verbatim alice 4 alice 5 bob 9 pete 7 @end verbatim @cindex @code{sort} @item T[] sort(T[] a, bool less(T i, T j)) returns a copy of @code{a} stably sorted in ascending order such that element @code{i} precedes element @code{j} if @code{less(i,j)} is true. @cindex @code{transpose} @item T[][] transpose(T[][] a) returns the transpose of @code{a}. @cindex @code{transpose} @item T[][][] transpose(T[][][] a, int[] perm) returns the 3D transpose of @code{a} obtained by applying the permutation @code{perm} of @code{new int[]@{0,1,2@}} to the indices of each entry. @cindex @code{sum} @item T sum(T[] a) For arithmetic types @code{T}, returns the sum of @code{a}. In the case where @code{T} is @code{bool}, the number of true elements in @code{a} is returned. @cindex @code{min} @item T min(T[] a) @item T min(T[][] a) @item T min(T[][][] a) For built-in ordered types @code{T}, returns the minimum element of @code{a}. @cindex @code{max} @item T max(T[] a) @item T max(T[][] a) @item T max(T[][][] a) For built-in ordered types @code{T}, returns the maximum element of @code{a}. @cindex @code{min} @item T[] min(T[] a, T[] b) For built-in ordered types @code{T}, and arrays @code{a} and @code{b} of the same length, returns an array composed of the minimum of the corresponding elements of @code{a} and @code{b}. @cindex @code{max} @item T[] max(T[] a, T[] b) For built-in ordered types @code{T}, and arrays @code{a} and @code{b} of the same length, returns an array composed of the maximum of the corresponding elements of @code{a} and @code{b}. @cindex @code{pairs} @item pair[] pairs(real[] x, real[] y); For arrays @code{x} and @code{y} of the same length, returns the pair array @code{sequence(new pair(int i) @{return (x[i],y[i]);@},x.length)}. @cindex @code{fft} @item pair[] fft(pair[] a, int sign=1) returns the unnormalized Fast Fourier Transform of @code{a} (if the optional @code{FFTW} package is installed), using the given @code{sign}. Here is a simple example: @verbatim int n=4; pair[] f=sequence(n); write(f); pair[] g=fft(f,-1); write(); write(g); f=fft(g,1); write(); write(f/n); @end verbatim @cindex @code{dot} @item real dot(real[] a, real[] b) returns the dot product of the vectors @code{a} and @code{b}. @cindex @code{dot} @item pair dot(pair[] a, pair[] b) returns the complex dot product @code{sum(a*conj(b))} of the vectors @code{a} and @code{b}. @anchor{tridiagonal} @cindex @code{tridiagonal} @item real[] tridiagonal(real[] a, real[] b, real[] c, real[] f); Solve the periodic tridiagonal problem @math{L@code{x}=@code{f}} and return the solution @code{x}, where @code{f} is an @math{n} vector and @math{L} is the @math{n \times n} matrix @verbatim [ b[0] c[0] a[0] ] [ a[1] b[1] c[1] ] [ a[2] b[2] c[2] ] [ ... ] [ c[n-1] a[n-1] b[n-1] ] @end verbatim For Dirichlet boundary conditions (denoted here by @code{u[-1]} and @code{u[n]}), replace @code{f[0]} by @code{f[0]-a[0]u[-1]} and @code{f[n-1]-c[n-1]u[n]}; then set @code{a[0]=c[n-1]=0}. @cindex @code{solve} @item real[] solve(real[][] a, real[] b, bool warn=true) Solve the linear equation @math{@code{a}x=@code{b}} by LU decomposition and return the solution @math{x}, where @code{a} is an @math{n \times n} matrix and @code{b} is an array of length @math{n}. For example: @verbatim import math; real[][] a={{1,-2,3,0},{4,-5,6,2},{-7,-8,10,5},{1,50,1,-2}}; real[] b={7,19,33,3}; real[] x=solve(a,b); write(a); write(); write(b); write(); write(x); write(); write(a*x); @end verbatim If @code{a} is a singular matrix and @code{warn} is @code{false}, return an empty array. If the matrix @code{a} is tridiagonal, the routine @code{tridiagonal} provides a more efficient algorithm (@pxref{tridiagonal}). @anchor{solve} @cindex @code{solve} @item real[][] solve(real[][] a, real[][] b, bool warn=true) Solve the linear equation @math{@code{a}x=@code{b}} and return the solution @math{x}, where @code{a} is an @math{n \times n} matrix and @code{b} is an @math{n \times m} matrix. If @code{a} is a singular matrix and @code{warn} is @code{false}, return an empty matrix. @cindex @code{identity} @item real[][] identity(int n); returns the @math{n \times n} identity matrix. @cindex @code{diagonal} @item real[][] diagonal(... real[] a) returns the diagonal matrix with diagonal entries given by a. @cindex @code{inverse} @item real[][] inverse(real[][] a) returns the inverse of a square matrix @code{a}. @cindex @code{quadraticroots} @item @code{real[] quadraticroots(real a, real b, real c);} This numerically robust solver returns the real roots of the quadratic equation @math{ax^2+bx+c=0}, in ascending order. Multiple roots are listed separately. @cindex @code{quadraticroots} @item @code{pair[] quadraticroots(explicit pair a, explicit pair b, explicit pair c);} This numerically robust solver returns the complex roots of the quadratic equation @math{ax^2+bx+c=0}. @cindex @code{cubicroots} @item @code{real[] cubicroots(real a, real b, real c, real d);} This numerically robust solver returns the real roots of the cubic equation @math{ax^3+bx^2+cx+d=0}. Multiple roots are listed separately. @end table @cindex vectorization @code{Asymptote} includes a full set of vectorized array instructions for arithmetic (including self) and logical operations. These element-by-element instructions are implemented in C++ code for speed. Given @verbatim real[] a={1,2}; real[] b={3,2}; @end verbatim @noindent then @code{a == b} and @code{a >= 2} both evaluate to the vector @code{@{false, true@}}. @cindex @code{all} To test whether all components of @code{a} and @code{b} agree, use the boolean function @code{all(a == b)}. One can also use conditionals like @code{(a >= 2) ? a : b}, which returns the array @code{@{3,2@}}, or @code{write((a >= 2) ? a : null}, which returns the array @code{@{2@}}. All of the standard built-in @code{libm} functions of signature @code{real(real)} also take a real array as an argument, effectively like an implicit call to @code{map}. As with other built-in types, arrays of the basic data types can be read in by assignment. In this example, the code @verbatim file fin=input("test.txt"); real[] A=fin; @end verbatim @cindex @code{eof} @cindex @code{eol} @cindex @code{line} @cindex line mode @noindent reads real values into @code{A} until the end-of-file is reached (or an I/O error occurs). The virtual members @code{dimension}, @code{line}, @code{csv}, @code{word}, and @code{read} of a file are useful for reading arrays. @cindex @code{line} For example, if line mode is set with @code{file line(bool b=true)}, then reading will stop once the end of the line is reached instead: @verbatim file fin=input("test.txt"); real[] A=fin.line(); @end verbatim @cindex reading string arrays @cindex @code{word} @cindex white-space string delimiter mode Since string reads by default read up to the end of line anyway, line mode normally has no effect on string array reads. However, there is a white-space delimiter mode for reading strings, @code{file word(bool b=true)}, which causes string reads to respect white-space delimiters, instead of the default end-of-line delimiter: @verbatim file fin=input("test.txt").line().word(); real[] A=fin; @end verbatim @cindex @code{csv} @cindex comma-separated-value mode Another useful mode is comma-separated-value mode, @code{file csv(bool b=true)}, which causes reads to respect comma delimiters: @verbatim file fin=csv(input("test.txt")); real[] A=fin; @end verbatim @cindex @code{dimension} To restrict the number of values read, use the @code{file dimension(int)} function: @verbatim file fin=input("test.txt"); real[] A=dimension(fin,10); @end verbatim This reads 10 values into A, unless end-of-file (or end-of-line in line mode) occurs first. Attempting to read beyond the end of the file will produce a runtime error message. Specifying a value of 0 for the integer limit is equivalent to the previous example of reading until end-of-file (or end-of-line in line mode) is encountered. Two- and three-dimensional arrays of the basic data types can be read in like this: @verbatim file fin=input("test.txt"); real[][] A=fin.dimension(2,3); real[][][] B=fin.dimension(2,3,4); @end verbatim @noindent @cindex @code{read} Sometimes the array dimensions are stored with the data as integer fields at the beginning of an array. Such 1, 2, or 3 dimensional arrays can be read in with the virtual member functions @code{read(1)}, @code{read(2)}, or @code{read(3)}, respectively: @verbatim file fin=input("test.txt"); real[] A=fin.read(1); real[][] B=fin.read(2); real[][][] C=fin.read(3); @end verbatim @cindex @code{write} One, two, and three-dimensional arrays of the basic data types can be output with the functions @code{write(file,T[])}, @code{write(file,T[][])}, @code{write(file,T[][][])}, respectively. @node Slices @subsection Slices @cindex slices Asymptote allows a section of an array to be addressed as a slice using a Python-like syntax. If @code{A} is an array, the expression @code{A[m:n]} returns a new array consisting of the elements of @code{A} with indices from @code{m} up to but not including @code{n}. For example, @verbatim int[] x={0,1,2,3,4,5,6,7,8,9}; int[] y=x[2:6]; // y={2,3,4,5}; int[] z=x[5:10]; // z={5,6,7,8,9}; @end verbatim If the left index is omitted, it is taken be @code{0}. If the right index is omitted it is taken to be the length of the array. If both are omitted, the slice then goes from the start of the array to the end, producing a non-cyclic deep copy of the array. For example: @verbatim int[] x={0,1,2,3,4,5,6,7,8,9}; int[] y=x[:4]; // y={0,1,2,3} int[] z=x[5:]; // z={5,6,7,8,9} int[] w=x[:]; // w={0,1,2,3,4,5,6,7,8,9}, distinct from array x. @end verbatim If A is a non-cyclic array, it is illegal to use negative values for either of the indices. If the indices exceed the length of the array, however, they are politely truncated to that length. For cyclic arrays, the slice @code{A[m:n]} still consists of the cells with indices in the set [@code{m},@code{n}), but now negative values and values beyond the length of the array are allowed. The indices simply wrap around. For example: @verbatim int[] x={0,1,2,3,4,5,6,7,8,9}; x.cyclic=true; int[] y=x[8:15]; // y={8,9,0,1,2,3,4}. int[] z=x[-5:5]; // z={5,6,7,8,9,0,1,2,3,4} int[] w=x[-3:17]; // w={7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6} @end verbatim Notice that with cyclic arrays, it is possible to include the same element of the original array multiple times within a slice. Regardless of the original array, arrays produced by slices are always non-cyclic. If the left and right indices of a slice are the same, the result is an empty array. If the array being sliced is empty, the result is an empty array. Any slice with a left index greater than its right index will yield an error. Slices can also be assigned to, changing the value of the original array. If the array being assigned to the slice has a different length than the slice itself, elements will be inserted or removed from the array to accommodate it. For instance: @verbatim string[] toppings={"mayo", "salt", "ham", "lettuce"}; toppings[0:2]=new string[] {"mustard", "pepper"}; // Now toppings={"mustard", "pepper", "ham", "lettuce"} toppings[2:3]=new string[] {"turkey", "bacon" }; // Now toppings={"mustard", "pepper", "turkey", "bacon", "lettuce"} toppings[0:3]=new string[] {"tomato"}; // Now toppings={"tomato", "bacon", "lettuce"} @end verbatim If an array is assigned to a slice of itself, a copy of the original array is assigned to the slice. That is, code such as @code{x[m:n]=x} is equivalent to @code{x[m:n]=copy(x)}. One can use the shorthand @code{x[m:m]=y} to insert the contents of the array @code{y} into the array @code{x} starting at the location just before @code{x[m]}. For a cyclic array, a slice is bridging if it addresses cells up to the end of the array and then continues on to address cells at the start of the array. For instance, if @code{A} is a cyclic array of length 10, @code{A[8:12]}, @code{A[-3:1]}, and @code{A[5:25]} are bridging slices whereas @code{A[3:7]}, @code{A[7:10]}, @code{A[-3:0]} and @code{A[103:107]} are not. Bridging slices can only be assigned to if the number of elements in the slice is exactly equal to the number of elements we are assigning to it. Otherwise, there is no clear way to decide which of the new entries should be @code{A[0]} and an error is reported. Non-bridging slices may be assigned an array of any length. For a cyclic array @code{A} an expression of the form @code{A[A.length:A.length]} is equivalent to the expression @code{A[0:0]} and so assigning to this slice will insert values at the start of the array. @code{A.append()} can be used to insert values at the end of the array. It is illegal to assign to a slice of a cyclic array that repeats any of the cells. @node Casts @section Casts @cindex casts @cindex implicit casts @cindex @code{explicit} @code{Asymptote} implicitly casts @code{int} to @code{real}, @code{int} to @code{pair}, @code{real} to @code{pair}, @code{pair} to @code{path}, @code{pair} to @code{guide}, @code{path} to @code{guide}, @code{guide} to @code{path}, @code{real} to @code{pen}, @code{pair[]} to @code{guide[]}, @code{pair[]} to @code{path[]}, @code{path} to @code{path[]}, and @code{guide} to @code{path[]}, along with various three-dimensional casts defined in @code{three.asy}. Implicit casts are automatically attempted on assignment and when trying to match function calls with possible function signatures. Implicit casting can be inhibited by declaring individual arguments @code{explicit} in the function signature, say to avoid an ambiguous function call in the following example, which outputs 0: @verbatim int f(pair a) {return 0;} int f(explicit real x) {return 1;} write(f(0)); @end verbatim @cindex explicit casts Other conversions, say @code{real} to @code{int} or @code{real} to @code{string}, require an explicit cast: @verbatim int i=(int) 2.5; string s=(string) 2.5; real[] a={2.5,-3.5}; int[] b=(int []) a; write(stdout,b); // Outputs 2,-3 @end verbatim @cindex @code{operator cast} Casting to user-defined types is also possible using @code{operator cast}: @verbatim struct rpair { real radius; real angle; } pair operator cast(rpair x) { return (x.radius*cos(x.angle),x.radius*sin(x.angle)); } rpair x; x.radius=1; x.angle=pi/6; write(x); // Outputs (0.866025403784439,0.5) @end verbatim One must use care when defining new cast operators. Suppose that in some code one wants all integers to represent multiples of 100. To convert them to reals, one would first want to multiply them by 100. However, the straightforward implementation @verbatim real operator cast(int x) {return x*100;} @end verbatim is equivalent to an infinite recursion, since the result @code{x*100} needs itself to be cast from an integer to a real. Instead, we want to use the standard conversion of int to real: @verbatim real convert(int x) {return x*100;} real operator cast(int x)=convert; @end verbatim @cindex @code{operator ecast} Explicit casts are implemented similarly, with @code{operator ecast}. @node Import @section Import @cindex @code{access} While @code{Asymptote} provides many features by default, some applications require specialized features contained in external @code{Asymptote} modules. For instance, the lines @verbatim access graph; graph.axes(); @end verbatim @noindent draw @math{x} and @math{y} axes on a two-dimensional graph. Here, the command looks up the module under the name @code{graph} in a global dictionary of modules and puts it in a new variable named @code{graph}. The module is a structure, and we can refer to its fields as we usually would with a structure. @cindex @code{from} Often, one wants to use module functions without having to specify the module name. The code @verbatim from graph access axes; @end verbatim @noindent adds the @code{axes} field of @code{graph} into the local name space, so that subsequently, one can just write @code{axes()}. If the given name is overloaded, all types and variables of that name are added. To add more than one name, just use a comma-separated list: @verbatim from graph access axes, xaxis, yaxis; @end verbatim @noindent Wild card notation can be used to add all non-private fields and types of a module to the local name space: @verbatim from graph access *; @end verbatim @cindex @code{unravel} Similarly, one can add the non-private fields and types of a structure to the local environment with the @code{unravel} keyword: @verbatim struct matrix { real a,b,c,d; } real det(matrix m) { unravel m; return a*d-b*c; } @end verbatim Alternatively, one can unravel selective fields: @verbatim real det(matrix m) { from m unravel a,b,c as C,d; return a*d-b*C; } @end verbatim @cindex @code{import} The command @verbatim import graph; @end verbatim is a convenient abbreviation for the commands @verbatim access graph; unravel graph; @end verbatim That is, @code{import graph} first loads a module into a structure called @code{graph} and then adds its non-private fields and types to the local environment. This way, if a member variable (or function) is overwritten with a local variable (or function of the same signature), the original one can still be accessed by qualifying it with the module name. Wild card importing will work fine in most cases, but one does not usually know all of the internal types and variables of a module, which can also change as the module writer adds or changes features of the module. As such, it is prudent to add @code{import} commands at the start of an @code{Asymptote} file, so that imported names won't shadow locally defined functions. Still, imported names may shadow other imported names, depending on the order in which they were imported, and imported functions may cause overloading resolution problems if they have the same name as local functions defined later. @cindex @code{as} To rename modules or fields when adding them to the local environment, use @code{as}: @verbatim access graph as graph2d; from graph access xaxis as xline, yaxis as yline; @end verbatim The command @verbatim import graph as graph2d; @end verbatim is a convenient abbreviation for the commands @verbatim access graph as graph2d; unravel graph2d; @end verbatim Except for a few built-in modules, such as @code{settings}, all modules are implemented as @code{Asymptote} files. When looking up a module that has not yet been loaded, @code{Asymptote} searches the standard search paths (@pxref{Search paths}) for the matching file. The file corresponding to that name is read and the code within it is interpreted as the body of a structure defining the module. If the file name contains nonalphanumeric characters, enclose it with quotation marks: @noindent @code{access "@value{Datadir}/asymptote/graph.asy" as graph;} @noindent @code{from "@value{Datadir}/asymptote/graph.asy" access axes;} @noindent @code{import "@value{Datadir}/asymptote/graph.asy" as graph;} It is an error if modules import themselves (or each other in a cycle). The module name to be imported must be known at compile time. @cindex runtime imports @cindex @code{eval} However, you can import an @code{Asymptote} module determined by the string @code{s} at runtime like this: @verbatim eval("import "+s,true); @end verbatim @cindex @code{asy} To conditionally execute an array of asy files, use @verbatim void asy(string format, bool overwrite ... string[] s); @end verbatim The file will only be processed, using output format @code{format}, if overwrite is @code{true} or the output file is missing. One can evaluate an @code{Asymptote} expression (without any return value, however) contained in the string @code{s} with: @cindex @code{eval} @verbatim void eval(string s, bool embedded=false); @end verbatim It is not necessary to terminate the string @code{s} with a semicolon. If @code{embedded} is @code{true}, the string will be evaluated at the top level of the current environment. If @code{embedded} is @code{false} (the default), the string will be evaluated in an independent environment, sharing the same @code{settings} module (@pxref{settings}). @cindex @code{quote} One can evaluate arbitrary @code{Asymptote} code (which may contain unescaped quotation marks) with the command @verbatim void eval(code s, bool embedded=false); @end verbatim Here @code{code} is a special type used with @code{quote @{@}} to enclose @code{Asymptote code} like this: @verbatim real a=1; code s=quote { write(a); }; eval(s,true); // Outputs 1 @end verbatim @cindex @code{include} To include the contents of an existing file @code{graph} verbatim (as if the contents of the file were inserted at that point), use one of the forms: @verbatim include graph; @end verbatim @noindent @code{include "@value{Datadir}/asymptote/graph.asy";} To list all global functions and variables defined in a module named by the contents of the string @code{s}, use the function @verbatim void list(string s, bool imports=false); @end verbatim @noindent Imported global functions and variables are also listed if @code{imports} is @code{true}. @node Static @section Static @cindex @code{static} Static qualifiers allocate the memory address of a variable in a higher enclosing level. For a function body, the variable is allocated in the block where the function is defined; so in the code @verbatim struct s { int count() { static int c=0; ++c; return c; } } @end verbatim @noindent there is one instance of the variable @code{c} for each object @code{s} (as opposed to each call of @code{count}). Similarly, in @verbatim int factorial(int n) { int helper(int k) { static int x=1; x *= k; return k == 1 ? x : helper(k-1); } return helper(n); } @end verbatim @noindent there is one instance of @code{x} for every call to @code{factorial} (and not for every call to @code{helper}), so this is a correct, but ugly, implementation of factorial. Similarly, a static variable declared within a structure is allocated in the block where the structure is defined. Thus, @verbatim struct A { struct B { static pair z; } } @end verbatim @noindent creates one object @code{z} for each object of type @code{A} created. In this example, @verbatim int pow(int n, int k) { struct A { static int x=1; void helper() { x *= n; } } for(int i=0; i < k; ++i) { A a; a.helper(); } return A.x; } @end verbatim @noindent there is one instance of @code{x} for each call to @code{pow}, so this is an ugly implementation of exponentiation. Loop constructs allocate a new frame in every iteration. This is so that higher-order functions can refer to variables of a specific iteration of a loop: @verbatim void f(); for(int i=0; i < 10; ++i) { int x=i; if(x==5) { f=new void () { write(x); } } } f(); @end verbatim Here, every iteration of the loop has its own variable @code{x}, so @code{f()} will write @code{5}. If a variable in a loop is declared static, it will be allocated where the enclosing function or structure was defined (just as if it were declared static outside of the loop). For instance, in: @verbatim void f() { static int x; for(int i=0; i < 10; ++i) { static int y; } } @end verbatim @noindent both @code{x} and @code{y} will be allocated in the same place, which is also where @code{f} is also allocated. Statements may also be declared static, in which case they are run at the place where the enclosing function or structure is defined. Declarations or statements not enclosed in a function or structure definition are already at the top level, so static modifiers are meaningless. A warning is given in such a case. Since structures can have static fields, it is not always clear for a qualified name whether the qualifier is a variable or a type. For instance, in: @verbatim struct A { static int x; } pair A; int y=A.x; @end verbatim @noindent does the @code{A} in @code{A.x} refer to the structure or to the pair variable. It is the convention in Asymptote that, if there is a non-function variable with the same name as the qualifier, the qualifier refers to that variable, and not to the type. This is regardless of what fields the variable actually possesses. @node LaTeX usage @chapter @code{LaTeX} usage @cindex @code{LaTeX} usage @cindex @code{asymptote.sty} @code{Asymptote} comes with a convenient @code{LaTeX} style file @code{asymptote.sty} that makes @code{LaTeX} @code{Asymptote}-aware. Entering @code{Asymptote} code directly into the @code{LaTeX} source file, at the point where it is needed, keeps figures organized and avoids the need to invent new file names for each figure. Simply add the line @code{\usepackage@{asymptote@}} at the beginning of your file and enclose your @code{Asymptote} code within a @code{\begin@{asy@}...\end@{asy@}} environment. As with the @code{LaTeX} @code{comment} environment, the @code{\end@{asy@}} command must appear on a line by itself, with no trailing commands/comments. A blank line is not allowed after @code{\begin@{asy@}}. The sample @code{LaTeX} file below, named @code{latexusage.tex}, can be run as follows: @verbatim latex latexusage asy latexusage-*.asy latex latexusage @end verbatim @noindent or @verbatim pdflatex latexusage asy latexusage-*.asy pdflatex latexusage @end verbatim @noindent To switch between using inline Asymptote code with @code{latex} and @code{pdflatex} you may first need to remove the files @code{latexusage-*.tex}. @cindex @code{latexmk} @cindex @code{perl} An even better method for processing a @code{LaTeX} file with embedded @code{Asymptote} code is to use the @code{latexmk} utility from @quotation @url{http://mirror.ctan.org/support/latexmk/} @end quotation @noindent after putting the contents of @url{http://sourceforge.net/p/asymptote/code/HEAD/tree/trunk/asymptote/doc/latexmkrc} @noindent in a file @code{latexmkrc} in the same directory. The command @verbatim latexmk -pdf latexusage @end verbatim @noindent will then call @code{Asymptote} automatically, recompiling only the figures that have changed. Since each figure is compiled in a separate system process, this method also tends to use less memory. To store the figures in a separate directory named @code{asy}, one can define @verbatim \def\asydir{asy} @end verbatim in @code{latexusage.tex} and put the contents of @url{http://sourceforge.net/p/asymptote/code/HEAD/tree/trunk/asymptote/doc/latexmkrc_asydir} in a file @code{latexmkrc} in the same directory. @noindent External @code{Asymptote} code in @code{filename.asy} should be included with @cindex @code{asyinclude} @verbatim \asyinclude[]{} @end verbatim @noindent so that @code{latexmk} will recognize when the code is changed. Note that @code{latemk} requires @code{perl}, available from @url{http://www.perl.org/}. @cindex @code{width} @cindex @code{height} @cindex @code{keepAspect} @cindex @code{viewportwidth} @cindex @code{viewportheight} @cindex @code{attach} @cindex @code{inline} One can specify @code{width}, @code{height}, @code{keepAspect}, @code{viewportwidth}, @code{viewportheight}, @code{attach}, and @code{inline}. @code{keyval}-style options to the @code{asy} and @code{asyinclude} environments. Three-dimensional @acronym{PRC} files may either be embedded within the page (the default) or attached as annotated (but printable) attachments, using the @code{attach} option and the @code{attachfile2} (or older @code{attachfile}) @code{LaTeX} package. The @code{inline} option generates inline @code{LaTeX} code instead of @acronym{EPS} or @acronym{PDF} files. This makes 2D LaTeX symbols visible to the @code{\begin@{asy@}...\end@{asy@}} environment. In this mode, Asymptote correctly aligns 2D LaTeX symbols defined outside of @code{\begin@{asy@}...\end@{asy@}}, but treats their size as zero; an optional second string can be given to @code{Label} to provide an estimate of the unknown label size. Note that if the @code{latex} @TeX{} engine is used with the @code{inline} option, labels might not show up in @acronym{DVI} viewers that cannot handle raw @code{PostScript} code. One can use @code{dvips}/@code{dvipdf} to produce @code{PostScript}/@acronym{PDF} output (we recommend using the modified version of @code{dvipdf} in the @code{Asymptote} patches directory, which accepts the @code{dvips -z} hyperdvi option). Here now is @code{latexusage.tex}: @verbatiminclude latexusage.tex @page @image{latexusage,,25cm} @node Base modules @chapter Base modules @cindex base modules @code{Asymptote} currently ships with the following base modules: @menu * plain:: Default @code{Asymptote} base file * simplex:: Linear programming: simplex method * math:: Extend @code{Asymptote}'s math capabilities * interpolate:: Interpolation routines * geometry:: Geometry routines * trembling:: Wavy lines * stats:: Statistics routines and histograms * patterns:: Custom fill and draw patterns * markers:: Custom path marker routines * tree:: Dynamic binary search tree * binarytree:: Binary tree drawing module * drawtree:: Tree drawing module * syzygy:: Syzygy and braid drawing module * feynman:: Feynman diagrams * roundedpath:: Round the sharp corners of paths * animation:: Embedded @acronym{PDF} and @acronym{MPEG} movies * embed:: Embedding movies, sounds, and 3D objects * slide:: Making presentations with @code{Asymptote} * MetaPost:: @code{MetaPost} compatibility routines * unicode:: Accept @code{unicode} (UTF-8) characters * latin1:: Accept @code{ISO 8859-1} characters * babel:: Interface to @code{LaTeX} @code{babel} package * labelpath:: Drawing curved labels * labelpath3:: Drawing curved labels in 3D * annotate:: Annotate your @acronym{PDF} files * CAD:: 2D CAD pen and measurement functions (DIN 15) * graph:: 2D linear & logarithmic graphs * palette:: Color density images and palettes * three:: 3D vector graphics * obj:: 3D obj files * graph3:: 3D linear & logarithmic graphs * grid3:: 3D grids * solids:: 3D solid geometry * tube:: 3D rotation minimizing tubes * flowchart:: Flowchart drawing routines * contour:: Contour lines * contour3:: Contour surfaces * smoothcontour3:: Smooth implicit surfaces * slopefield:: Slope fields * ode:: Ordinary differential equations @end menu @node plain @section @code{plain} @cindex @code{plain} This is the default @code{Asymptote} base file, which defines key parts of the drawing language (such as the @code{picture} structure). By default, an implicit @code{private import plain;} occurs before translating a file and before the first command given in interactive mode. This also applies when translating files for module definitions (except when translating @code{plain}, of course). This means that the types and functions defined in @code{plain} are accessible in almost all @code{Asymptote} code. Use the @code{-noautoplain} command-line option to disable this feature. @node simplex @section @code{simplex} @cindex @code{simplex} @cindex @code{deferred drawing} This package solves the two-variable linear programming problem using the simplex method. It is used by the module @code{plain} for automatic sizing of pictures. @node math @section @code{math} @cindex @code{math} This package extends @code{Asymptote}'s mathematical capabilities with useful functions such as @table @code @cindex @code{drawline} @item void drawline(picture pic=currentpicture, pair P, pair Q, pen p=currentpen); draw the visible portion of the (infinite) line going through @code{P} and @code{Q}, without altering the size of picture @code{pic}, using pen @code{p}. @cindex @code{intersect} @item real intersect(triple P, triple Q, triple n, triple Z); returns the intersection time of the extension of the line segment @code{PQ} with the plane perpendicular to @code{n} and passing through @code{Z}. @cindex @code{intersectionpoint} @item triple intersectionpoint(triple n0, triple P0, triple n1, triple P1); Return any point on the intersection of the two planes with normals @code{n0} and @code{n1} passing through points @code{P0} and @code{P1}, respectively. If the planes are parallel, return @code{(infinity,infinity,infinity)}. @cindex @code{quarticroots} @item pair[] quarticroots(real a, real b, real c, real d, real e); returns the four complex roots of the quartic equation @math{ax^4+bx^3+cx^2+dx+e=0}. @cindex @code{fft} @item pair[][] fft(pair[][] a, int sign=1) returns the two-dimensional Fourier transform of a using the given @code{sign}. @cindex @code{time} @item real time(path g, real x, int n=0) returns the @code{n}th intersection time of path @code{g} with the vertical line through x. @cindex @code{time} @item real time(path g, explicit pair z, int n=0) returns the @code{n}th intersection time of path @code{g} with the horizontal line through @code{(0,z.y)}. @cindex @code{value} @item real value(path g, real x, int n=0) returns the @code{n}th @code{y} value of @code{g} at @code{x}. @cindex @code{value} @item real value(path g, explicit pair z, int n=0) returns the @code{n}th @code{x} value of @code{g} at @code{y=z.y}. @cindex @code{slope} @item real slope(path g, real x, int n=0) returns the @code{n}th slope of @code{g} at @code{x}. @cindex @code{slope} @item real slope(path g, explicit pair z, int n=0) returns the @code{n}th slope of @code{g} at @code{y=z.y}. @cindex @code{segment} int[][] segment(bool[] b) returns the indices of consecutive true-element segments of bool[] @code{b}. @cindex @code{partialsum} @item real[] partialsum(real[] a) returns the partial sums of a real array @code{a}. @cindex @code{partialsum} @item real[] partialsum(real[] a, real[] dx) returns the partial @code{dx}-weighted sums of a real array @code{a}. @cindex @code{increasing} @item bool increasing(real[] a, bool strict=false) returns, if @code{strict=false}, whether @code{i > j} implies @code{a[i] >= a[j]}, or if @code{strict=true}, whether @code{i > j} implies implies @code{a[i] > a[j]}. @cindex @code{unique} @item int unique(real[] a, real x) if the sorted array @code{a} does not contain @code{x}, insert it sequentially, returning the index of @code{x} in the resulting array. @cindex @code{lexorder} @item bool lexorder(pair a, pair b) returns the strict lexicographical partial order of @code{a} and @code{b}. @cindex @code{lexorder} @item bool lexorder(triple a, triple b) returns the strict lexicographical partial order of @code{a} and @code{b}. @end table @node interpolate @section @code{interpolate} @cindex @code{interpolate} This module implements Lagrange, Hermite, and standard cubic spline interpolation in @code{Asymptote}, as illustrated in the example @code{interpolate1.asy}. @node geometry @section @code{geometry} @cindex @code{geometry} @cindex @code{triangle} @cindex @code{perpendicular} This module, written by Philippe Ivaldi, provides an extensive set of geometry routines, including @code{perpendicular} symbols and a @code{triangle} structure. Link to the documentation for the @code{geometry} module are posted here: @url{http://asymptote.sourceforge.net/links.html}, including an extensive set of examples, @url{http://www.piprime.fr/files/asymptote/geometry/}, and an index: @quotation @url{http://www.piprime.fr/files/asymptote/geometry/modules/geometry.asy.index.type.html} @end quotation @node trembling @section @code{trembling} @cindex @code{trembling} This module, written by Philippe Ivaldi and illustrated in the example @code{floatingdisk.asy}, allows one to draw wavy lines, as if drawn by hand. @node stats @section @code{stats} @cindex @code{stats} @cindex @code{leastsquares} This package implements a Gaussian random number generator and a collection of statistics routines, including @code{histogram} and @code{leastsquares}. @node patterns @section @code{patterns} @cindex @code{patterns} This package implements @code{Postscript} tiling patterns and includes several convenient pattern generation routines. @node markers @section @code{markers} @cindex @code{markers} This package implements specialized routines for marking paths and angles. The principal mark routine provided by this package is @verbatim markroutine markinterval(int n=1, frame f, bool rotated=false); @end verbatim @noindent which centers @code{n} copies of frame @code{f} within uniformly space intervals in arclength along the path, optionally rotated by the angle of the local tangent. The @code{marker} (@pxref{marker}) routine can be used to construct new markers from these predefined frames: @cindex @code{stickframe} @verbatim frame stickframe(int n=1, real size=0, pair space=0, real angle=0, pair offset=0, pen p=currentpen); @end verbatim @cindex @code{circlebarframe} @verbatim frame circlebarframe(int n=1, real barsize=0, real radius=0,real angle=0, pair offset=0, pen p=currentpen, filltype filltype=NoFill, bool above=false); @end verbatim @cindex @code{crossframe} @verbatim frame crossframe(int n=3, real size=0, pair space=0, real angle=0, pair offset=0, pen p=currentpen); @end verbatim @cindex @code{tildeframe} @verbatim frame tildeframe(int n=1, real size=0, pair space=0, real angle=0, pair offset=0, pen p=currentpen); @end verbatim For convenience, this module also constructs the markers @code{StickIntervalMarker}, @code{CrossIntervalMarker}, @code{CircleBarIntervalMarker}, and @code{TildeIntervalMarker} from the above frames. The example @code{markers1.asy} illustrates the use of these markers: @sp 1 @center @image{markers1} This package also provides a routine for marking an angle @math{AOB}: @cindex @code{markangle} @verbatim void markangle(picture pic=currentpicture, Label L="", int n=1, real radius=0, real space=0, pair A, pair O, pair B, arrowbar arrow=None, pen p=currentpen, margin margin=NoMargin, marker marker=nomarker); @end verbatim @noindent as illustrated in the example @code{markers2.asy}. @sp 1 @center @image{markers2} @node tree @section @code{tree} @cindex @code{tree} This package implements an example of a dynamic binary search tree. @node binarytree @section @code{binarytree} @cindex @code{binarytree} This module can be used to draw an arbitrary binary tree and includes an input routine for the special case of a binary search tree, as illustrated in the example @code{binarytreetest.asy}: @verbatiminclude binarytreetest.asy @sp 1 @center @image{binarytreetest} @node drawtree @section @code{drawtree} @cindex @code{drawtree} This is a simple tree drawing module used by the example @code{treetest.asy}. @node syzygy @section @code{syzygy} @cindex @code{syzygy} This module automates the drawing of braids, relations, and syzygies, along with the corresponding equations, as illustrated in the example @code{knots.asy}. @node feynman @section @code{feynman} @cindex @code{feynman} This package, contributed by Martin Wiebusch, is useful for drawing Feynman diagrams, as illustrated by the examples @code{eetomumu.asy} and @code{fermi.asy}. @node roundedpath @section @code{roundedpath} @cindex @code{roundedpath} This package, contributed by Stefan Knorr, is useful for rounding the sharp corners of paths, as illustrated in the example file @code{roundpath.asy}. @node animation @section @code{animation} @cindex @code{animation} @cindex @code{convert} @cindex animation @cindex @code{ImageMagick} This module allows one to generate animations, as illustrated by the files @code{wheel.asy}, @code{wavepacket.asy}, and @code{cube.asy} in the @code{animations} subdirectory of the examples directory. These animations use the @code{ImageMagick} @code{convert} program to merge multiple images into a @acronym{GIF} or @acronym{MPEG} movie. @cindex @code{animate} @anchor{animate} The related @code{animate} module, derived from the @code{animation} module, generates higher-quality portable clickable @acronym{PDF} movies, with optional controls. This requires installing the package @quotation @url{http://mirror.ctan.org/macros/latex/contrib/animate/animate.sty} @noindent @end quotation @noindent (version 2007/11/30 or later) in a new directory @code{animate} in the local @code{LaTeX} directory (for example, in @code{/usr/local/share/texmf/tex/latex/animate}). On @code{UNIX} systems, one must then execute the command @code{texhash}. The example @code{pdfmovie.asy} in the @code{animations} directory, along with the slide presentations @code{slidemovies.asy} and @code{intro.asy}, illustrate the use of embedded @acronym{PDF} movies. The examples @code{inlinemovie.tex} and @code{inlinemovie3.tex} show how to generate and embed @acronym{PDF} movies directly within a @code{LaTeX} file (@pxref{LaTeX usage}). The member function @verbatim string pdf(fit fit=NoBox, real delay=animationdelay, string options="", bool keep=settings.keep, bool multipage=true); @end verbatim @noindent of the @code{animate} structure accepts any of the @code{animate.sty} options, as described here: @quotation @url{http://mirror.ctan.org/macros/latex/contrib/animate/doc/animate.pdf} @end quotation @node embed @section @code{embed} @cindex @code{embed} This module provides an interface to the @code{LaTeX} package (included with @code{MikTeX}) @quotation @url{http://mirror.ctan.org/macros/latex/contrib/media9} @end quotation @noindent for embedding movies, sounds, and 3D objects into a @acronym{PDF} document. @cindex @code{external} A more portable method for embedding movie files, which should work on any platform and does not require the @code{media9} package, is provided by using the @code{external} module instead of @code{embed}. Examples of the above two interfaces is provided in the file @code{embeddedmovie.asy} and @code{externalmovie.asy} in the @code{animations} subdirectory of the examples directory. For a higher quality embedded movie generated directly by @code{Asymptote}, use the @code{animate} module along with the @code{animate.sty} package to embed a portable @acronym{PDF} animation (@pxref{animate}). @cindex @code{U3D} An example of embedding @code{U3D} code is provided in the file @code{embeddedu3d.asy}. @node slide @section @code{slide} @cindex @code{slide} This package provides a simple yet high-quality facility for making presentation slides, including portable embedded @acronym{PDF} animations (see the file @code{slidemovies.asy}). A simple example is provided in the file @code{slidedemo.asy}. @node MetaPost @section @code{MetaPost} @cindex @code{MetaPost} This package provides some useful routines to help @code{MetaPost} users migrate old @code{MetaPost} code to @code{Asymptote}. Further contributions here are welcome. @cindex @code{implicit linear solver} @cindex @code{MetaPost whatever} @cindex @code{extension} Unlike @code{MetaPost}, @code{Asymptote} does not implicitly solve linear equations and therefore does not have the notion of a @code{whatever} unknown. The routine @code{extension} (@pxref{extension}) provides a useful replacement for a common use of @code{whatever}: finding the intersection point of the lines through @code{P}, @code{Q} and @code{p}, @code{q}. For less common occurrences of @code{whatever}, one can use the built-in explicit linear equation solver @code{solve} instead. @node unicode @section @code{unicode} @cindex @code{unicode} @cindex international characters Import this package at the beginning of the file to instruct @code{LaTeX} to accept @code{unicode} (UTF-8) standardized international characters. @noindent @cindex Cyrillic @cindex Russian To use Cyrillic fonts, you will need to change the font encoding: @verbatim import unicode; texpreamble("\usepackage{mathtext}\usepackage[russian]{babel}"); defaultpen(font("T2A","cmr","m","n")); @end verbatim @noindent @cindex Chinese @cindex Japanese @cindex Korean @cindex CJK Support for Chinese, Japanese, and Korean fonts is provided by the CJK package: @quotation @url{http://mirror.ctan.org/languages/chinese/CJK/} @end quotation @noindent The following commands enable the CJK song family (within a label, you can also temporarily switch to another family, say kai, by prepending @code{"\CJKfamily@{kai@}"} to the label string): @verbatim texpreamble("\usepackage{CJK} \AtBeginDocument{\begin{CJK*}{GBK}{song}} \AtEndDocument{\clearpage\end{CJK*}}"); @end verbatim @node latin1 @section @code{latin1} @cindex @code{latin1} If you don't have @code{LaTeX} support for @code{unicode} installed, you can enable support for Western European languages (ISO 8859-1) by importing the module @code{latin1}. This module can be used as a template for providing support for other ISO 8859 alphabets. @node babel @section @code{babel} @cindex @code{babel} This module implements the @code{LaTeX} @code{babel} package in @code{Asymptote}. For example: @verbatim import babel; babel("german"); @end verbatim @node labelpath @section @code{labelpath} @cindex @code{labelpath} This module uses the @code{PSTricks} @code{pstextpath} macro to fit labels along a path (properly kerned, as illustrated in the example file @code{curvedlabel.asy}), using the command @verbatim void labelpath(picture pic=currentpicture, Label L, path g, string justify=Centered, pen p=currentpen); @end verbatim @noindent Here @code{justify} is one of @code{LeftJustified}, @code{Centered}, or @code{RightJustified}. The @math{x} component of a shift transform applied to the Label is interpreted as a shift along the curve, whereas the @math{y} component is interpreted as a shift away from the curve. All other Label transforms are ignored. This package requires the @code{latex} tex engine and inherits the limitations of the @code{PSTricks} @code{\pstextpath} macro. @node labelpath3 @section @code{labelpath3} @cindex @code{labelpath3} This module, contributed by Jens Schwaiger, implements a 3D version of @code{labelpath} that does not require the @code{PSTricks} package. An example is provided in @code{curvedlabel3.asy}. @node annotate @section @code{annotate} @cindex @code{annotate} This module supports @acronym{PDF} annotations for viewing with @code{Adobe Reader}, via the function @verbatim void annotate(picture pic=currentpicture, string title, string text, pair position); @end verbatim @noindent Annotations are illustrated in the example file @code{annotation.asy}. Currently, annotations are only implemented for the @code{latex} (default) and @code{tex} @TeX{} engines. @node CAD @section @code{CAD} @cindex @code{CAD} This package, contributed by Mark Henning, provides basic pen definitions and measurement functions for simple 2D CAD drawings according to DIN 15. It is documented separately, in the file @code{CAD.pdf}. @node graph @section @code{graph} @cindex @code{graph} @cindex 2D graphs This package implements two-dimensional linear and logarithmic graphs, including automatic scale and tick selection (with the ability to override manually). A graph is a @code{guide} (that can be drawn with the draw command, with an optional legend) constructed with one of the following routines: @itemize @item @verbatim guide graph(picture pic=currentpicture, real f(real), real a, real b, int n=ngraph, real T(real)=identity, interpolate join=operator --); guide[] graph(picture pic=currentpicture, real f(real), real a, real b, int n=ngraph, real T(real)=identity, bool3 cond(real), interpolate join=operator --); @end verbatim Returns a graph using the scaling information for picture @code{pic} (@pxref{automatic scaling}) of the function @code{f} on the interval [@code{T}(@code{a}),@code{T}(@code{b})], sampling at @code{n} points evenly spaced in [@code{a},@code{b}], optionally restricted by the bool3 function @code{cond} on [@code{a},@code{b}]. If @code{cond} is: @itemize @bullet @item @code{true}, the point is added to the existing guide; @item @code{default}, the point is added to a new guide; @item @code{false}, the point is omitted and a new guide is begun. @end itemize The points are connected using the interpolation specified by @code{join}: @itemize @bullet @cindex @code{operator --} @cindex @code{Straight} @item @code{operator --} (linear interpolation; the abbreviation @code{Straight} is also accepted); @cindex @code{operator ..} @cindex @code{Spline} @item @code{operator ..} (piecewise Bezier cubic spline interpolation; the abbreviation @code{Spline} is also accepted); @cindex @code{Hermite} @cindex @code{notaknot} @cindex @code{natural} @cindex @code{periodic} @cindex @code{clamped} @cindex @code{monotonic} @cindex @code{Hermite(splinetype splinetype} @item @code{Hermite} (standard cubic spline interpolation using boundary condition @code{notaknot}, @code{natural}, @code{periodic}, @code{clamped(real slopea, real slopeb)}), or @code{monotonic}. The abbreviation @code{Hermite} is equivalent to @code{Hermite(notaknot)} for nonperiodic data and @code{Hermite(periodic)} for periodic data). @end itemize @item @verbatim guide graph(picture pic=currentpicture, real x(real), real y(real), real a, real b, int n=ngraph, real T(real)=identity, interpolate join=operator --); guide[] graph(picture pic=currentpicture, real x(real), real y(real), real a, real b, int n=ngraph, real T(real)=identity, bool3 cond(real), interpolate join=operator --); @end verbatim Returns a graph using the scaling information for picture @code{pic} of the parametrized function (@code{x}(@math{t}),@code{y}(@math{t})) for @math{t} in the interval [@code{T}(@code{a}),@code{T}(@code{b})], sampling at @code{n} points evenly spaced in [@code{a},@code{b}], optionally restricted by the bool3 function @code{cond} on [@code{a},@code{b}], using the given interpolation type. @item @verbatim guide graph(picture pic=currentpicture, pair z(real), real a, real b, int n=ngraph, real T(real)=identity, interpolate join=operator --); guide[] graph(picture pic=currentpicture, pair z(real), real a, real b, int n=ngraph, real T(real)=identity, bool3 cond(real), interpolate join=operator --); @end verbatim Returns a graph using the scaling information for picture @code{pic} of the parametrized function @code{z}(@math{t}) for @math{t} in the interval [@code{T}(@code{a}),@code{T}(@code{b})], sampling at @code{n} points evenly spaced in [@code{a},@code{b}], optionally restricted by the bool3 function @code{cond} on [@code{a},@code{b}], using the given interpolation type. @item @verbatim guide graph(picture pic=currentpicture, pair[] z, interpolate join=operator --); guide[] graph(picture pic=currentpicture, pair[] z, bool3[] cond, interpolate join=operator --); @end verbatim Returns a graph using the scaling information for picture @code{pic} of the elements of the array @code{z}, optionally restricted to those indices for which the elements of the boolean array @code{cond} are @code{true}, using the given interpolation type. @item @verbatim guide graph(picture pic=currentpicture, real[] x, real[] y, interpolate join=operator --); guide[] graph(picture pic=currentpicture, real[] x, real[] y, bool3[] cond, interpolate join=operator --); @end verbatim Returns a graph using the scaling information for picture @code{pic} of the elements of the arrays (@code{x},@code{y}), optionally restricted to those indices for which the elements of the boolean array @code{cond} are @code{true}, using the given interpolation type. @item @cindex @code{polargraph} @verbatim guide polargraph(picture pic=currentpicture, real f(real), real a, real b, int n=ngraph, interpolate join=operator --); @end verbatim Returns a polar-coordinate graph using the scaling information for picture @code{pic} of the function @code{f} on the interval [@code{a},@code{b}], sampling at @code{n} evenly spaced points, with the given interpolation type. @item @verbatim guide polargraph(picture pic=currentpicture, real[] r, real[] theta, interpolate join=operator--); @end verbatim Returns a polar-coordinate graph using the scaling information for picture @code{pic} of the elements of the arrays (@code{r},@code{theta}), using the given interpolation type. @end itemize @verbatim @end verbatim An axis can be drawn on a picture with one of the following commands: @itemize @item @verbatim void xaxis(picture pic=currentpicture, Label L="", axis axis=YZero, real xmin=-infinity, real xmax=infinity, pen p=currentpen, ticks ticks=NoTicks, arrowbar arrow=None, bool above=false); @end verbatim Draw an @math{x} axis on picture @code{pic} from @math{x}=@code{xmin} to @math{x}=@code{xmax} using pen @code{p}, optionally labelling it with Label @code{L}. The relative label location along the axis (a real number from [0,1]) defaults to 1 (@pxref{Label}), so that the label is drawn at the end of the axis. An infinite value of @code{xmin} or @code{xmax} specifies that the corresponding axis limit will be automatically determined from the picture limits. The optional @code{arrow} argument takes the same values as in the @code{draw} command (@pxref{arrows}). The axis is drawn before any existing objects in @code{pic} unless @code{above=true}. The axis placement is determined by one of the following @code{axis} types: @table @code @cindex @code{YZero} @item YZero(bool extend=true) Request an @math{x} axis at @math{y}=0 (or @math{y}=1 on a logarithmic axis) extending to the full dimensions of the picture, unless @code{extend}=false. @cindex @code{YEquals} @item YEquals(real Y, bool extend=true) Request an @math{x} axis at @math{y}=@code{Y} extending to the full dimensions of the picture, unless @code{extend}=false. @cindex @code{Bottom} @item Bottom(bool extend=false) Request a bottom axis. @cindex @code{Top} @item Top(bool extend=false) Request a top axis. @cindex @code{BottomTop} @item BottomTop(bool extend=false) Request a bottom and top axis. @end table @cindex custom axis types Custom axis types can be created by following the examples in @code{graph.asy}. One can easily override the default values for the standard axis types: @verbatim import graph; YZero=new axis(bool extend=true) { return new void(picture pic, axisT axis) { real y=pic.scale.x.scale.logarithmic ? 1 : 0; axis.value=I*pic.scale.y.T(y); axis.position=1; axis.side=right; axis.align=2.5E; axis.value2=Infinity; axis.extend=extend; }; }; YZero=YZero(); @end verbatim @anchor{ticks} @cindex @code{ticks} @cindex @code{NoTicks} @cindex @code{LeftTicks} @cindex @code{RightTicks} @cindex @code{Ticks} The default tick option is @code{NoTicks}. The options @code{LeftTicks}, @code{RightTicks}, or @code{Ticks} can be used to draw ticks on the left, right, or both sides of the path, relative to the direction in which the path is drawn. These tick routines accept a number of optional arguments: @verbatim ticks LeftTicks(Label format="", ticklabel ticklabel=null, bool beginlabel=true, bool endlabel=true, int N=0, int n=0, real Step=0, real step=0, bool begin=true, bool end=true, tickmodifier modify=None, real Size=0, real size=0, bool extend=false, pen pTick=nullpen, pen ptick=nullpen); @end verbatim If any of these parameters are omitted, reasonable defaults will be chosen: @table @code @item Label format @cindex @code{defaultformat} @cindex @code{trailingzero} override the default tick label format (@code{defaultformat}, initially "$%.4g$"), rotation, pen, and alignment (for example, @code{LeftSide}, @code{Center}, or @code{RightSide}) relative to the axis. To enable @code{LaTeX} math mode fonts, the format string should begin and end with @code{$} @pxref{format}. If the format string is @code{trailingzero}, trailing zeros will be added to the tick labels; if the format string is @code{"%"}, the tick label will be suppressed; @item ticklabel is a function @code{string(real x)} returning the label (by default, format(format.s,x)) for each major tick value @code{x}; @item bool beginlabel include the first label; @item bool endlabel include the last label; @item int N when automatic scaling is enabled (the default; @pxref{automatic scaling}), divide a linear axis evenly into this many intervals, separated by major ticks; for a logarithmic axis, this is the number of decades between labelled ticks; @item int n divide each interval into this many subintervals, separated by minor ticks; @item real Step the tick value spacing between major ticks (if @code{N}=@code{0}); @item real step the tick value spacing between minor ticks (if @code{n}=@code{0}); @item bool begin include the first major tick; @item bool end include the last major tick; @item tickmodifier modify; an optional function that takes and returns a @code{tickvalue} structure having real[] members @code{major} and @code{minor} consisting of the tick values (to allow modification of the automatically generated tick values); @item real Size the size of the major ticks (in @code{PostScript} coordinates); @item real size the size of the minor ticks (in @code{PostScript} coordinates); @item bool extend; extend the ticks between two axes (useful for drawing a grid on the graph); @item pen pTick an optional pen used to draw the major ticks; @item pen ptick an optional pen used to draw the minor ticks. @end table @cindex @code{OmitTick} @cindex @code{OmitTickInterval} @cindex @code{OmitTickIntervals} For convenience, the predefined tickmodifiers @code{OmitTick(... real[] x)}, @code{OmitTickInterval(real a, real b)}, and @code{OmitTickIntervals(real[] a, real[] b)} can be used to remove specific auto-generated ticks and their labels. The @code{OmitFormat(string s=defaultformat ... real[] x)} ticklabel can be used to remove specific tick labels but not the corresponding ticks. The tickmodifier @code{NoZero} is an abbreviation for @code{OmitTick(0)} and the ticklabel @code{NoZeroFormat} is an abbrevation for @code{OmitFormat(0)}. @cindex custom tick locations @cindex @code{LeftTicks} @cindex @code{RightTicks} @cindex @code{Ticks} It is also possible to specify custom tick locations with @code{LeftTicks}, @code{RightTicks}, and @code{Ticks} by passing explicit real arrays @code{Ticks} and (optionally) @code{ticks} containing the locations of the major and minor ticks, respectively: @verbatim ticks LeftTicks(Label format="", ticklabel ticklabel=null, bool beginlabel=true, bool endlabel=true, real[] Ticks, real[] ticks=new real[], real Size=0, real size=0, bool extend=false, pen pTick=nullpen, pen ptick=nullpen) @end verbatim @item @verbatim void yaxis(picture pic=currentpicture, Label L="", axis axis=XZero, real ymin=-infinity, real ymax=infinity, pen p=currentpen, ticks ticks=NoTicks, arrowbar arrow=None, bool above=false, bool autorotate=true); @end verbatim Draw a @math{y} axis on picture @code{pic} from @math{y}=@code{ymin} to @math{y}=@code{ymax} using pen @code{p}, optionally labelling it with a Label @code{L} that is autorotated unless @code{autorotate=false}. The relative location of the label (a real number from [0,1]) defaults to 1 (@pxref{Label}). An infinite value of @code{ymin} or @code{ymax} specifies that the corresponding axis limit will be automatically determined from the picture limits. The optional @code{arrow} argument takes the same values as in the @code{draw} command (@pxref{arrows}). The axis is drawn before any existing objects in @code{pic} unless @code{above=true}. The tick type is specified by @code{ticks} and the axis placement is determined by one of the following @code{axis} types: @table @code @cindex @code{XZero} @item XZero(bool extend=true) Request a @math{y} axis at @math{x}=0 (or @math{x}=1 on a logarithmic axis) extending to the full dimensions of the picture, unless @code{extend}=false. @cindex @code{XEquals} @item XEquals(real X, bool extend=true) Request a @math{y} axis at @math{x}=@code{X} extending to the full dimensions of the picture, unless @code{extend}=false. @cindex @code{Left} @item Left(bool extend=false) Request a left axis. @cindex @code{Right} @item Right(bool extend=false) Request a right axis. @cindex @code{LeftRight} @item LeftRight(bool extend=false) Request a left and right axis. @end table @item @cindex @code{xequals} @cindex @code{yequals} For convenience, the functions @verbatim void xequals(picture pic=currentpicture, Label L="", real x, bool extend=false, real ymin=-infinity, real ymax=infinity, pen p=currentpen, ticks ticks=NoTicks, bool above=true, arrowbar arrow=None); @end verbatim and @verbatim void yequals(picture pic=currentpicture, Label L="", real y, bool extend=false, real xmin=-infinity, real xmax=infinity, pen p=currentpen, ticks ticks=NoTicks, bool above=true, arrowbar arrow=None); @end verbatim can be respectively used to call @code{yaxis} and @code{xaxis} with the appropriate axis types @code{XEquals(x,extend)} and @code{YEquals(y,extend)}. This is the recommended way of drawing vertical or horizontal lines and axes at arbitrary locations. @item @verbatim void axes(picture pic=currentpicture, Label xlabel="", Label ylabel="", bool extend=true, pair min=(-infinity,-infinity), pair max=(infinity,infinity), pen p=currentpen, arrowbar arrow=None, bool above=false); @end verbatim This convenience routine draws both @math{x} and @math{y} axes on picture @code{pic} from @code{min} to @code{max}, with optional labels @code{xlabel} and @code{ylabel} and any arrows specified by @code{arrow}. The axes are drawn on top of existing objects in @code{pic} only if @code{above=true}. @item @verbatim void axis(picture pic=currentpicture, Label L="", path g, pen p=currentpen, ticks ticks, ticklocate locate, arrowbar arrow=None, int[] divisor=new int[], bool above=false, bool opposite=false); @end verbatim This routine can be used to draw on picture @code{pic} a general axis based on an arbitrary path @code{g}, using pen @code{p}. One can optionally label the axis with Label @code{L} and add an arrow @code{arrow}. The tick type is given by @code{ticks}. The optional integer array @code{divisor} specifies what tick divisors to try in the attempt to produce uncrowded tick labels. A @code{true} value for the flag @code{opposite} identifies an unlabelled secondary axis (typically drawn opposite a primary axis). The axis is drawn before any existing objects in @code{pic} unless @code{above=true}. The tick locator @code{ticklocate} is constructed by the routine @verbatim ticklocate ticklocate(real a, real b, autoscaleT S=defaultS, real tickmin=-infinity, real tickmax=infinity, real time(real)=null, pair dir(real)=zero); @end verbatim @noindent where @code{a} and @code{b} specify the respective tick values at @code{point(g,0)} and @code{point(g,length(g))}, @code{S} specifies the autoscaling transformation, the function @code{real time(real v)} returns the time corresponding to the value @code{v}, and @code{pair dir(real t)} returns the absolute tick direction as a function of @code{t} (zero means draw the tick perpendicular to the axis). @item These routines are useful for manually putting ticks and labels on axes (if the variable @code{Label} is given as the @code{Label} argument, the @code{format} argument will be used to format a string based on the tick location): @cindex xtick @cindex ytick @cindex labelx @cindex labely @cindex tick @cindex Label @verbatim void xtick(picture pic=currentpicture, Label L="", explicit pair z, pair dir=N, string format="", real size=Ticksize, pen p=currentpen); void xtick(picture pic=currentpicture, Label L="", real x, pair dir=N, string format="", real size=Ticksize, pen p=currentpen); void ytick(picture pic=currentpicture, Label L="", explicit pair z, pair dir=E, string format="", real size=Ticksize, pen p=currentpen); void ytick(picture pic=currentpicture, Label L="", real y, pair dir=E, string format="", real size=Ticksize, pen p=currentpen); void tick(picture pic=currentpicture, pair z, pair dir, real size=Ticksize, pen p=currentpen); void labelx(picture pic=currentpicture, Label L="", explicit pair z, align align=S, string format="", pen p=currentpen); void labelx(picture pic=currentpicture, Label L="", real x, align align=S, string format="", pen p=currentpen); void labelx(picture pic=currentpicture, Label L, string format="", explicit pen p=currentpen); void labely(picture pic=currentpicture, Label L="", explicit pair z, align align=W, string format="", pen p=currentpen); void labely(picture pic=currentpicture, Label L="", real y, align align=W, string format="", pen p=currentpen); void labely(picture pic=currentpicture, Label L, string format="", explicit pen p=currentpen); @end verbatim @end itemize Here are some simple examples of two-dimensional graphs: @enumerate @cindex textbook graph @item This example draws a textbook-style graph of @math{y=} exp@math{(x)}, with the @math{y} axis starting at @math{y=0}: @verbatiminclude exp.asy @sp 1 @center @image{exp} @item The next example draws a scientific-style graph with a legend. The position of the legend can be adjusted either explicitly or by using the graphical user interface @code{xasy} (@pxref{GUI}). If an @code{UnFill(real xmargin=0, real ymargin=xmargin)} or @code{Fill(pen)} option is specified to @code{add}, the legend will obscure any underlying objects. Here we illustrate how to clip the portion of the picture covered by a label: @cindex scientific graph @verbatiminclude lineargraph0.asy @sp 1 @center @image{lineargraph0} @cindex @code{attach} To specify a fixed size for the graph proper, use @code{attach}: @verbatiminclude lineargraph.asy @cindex @code{legend} A legend can have multiple entries per line: @verbatiminclude legend.asy @sp 1 @center @image{legend} @item This example draws a graph of one array versus another (both of the same size) using custom tick locations and a smaller font size for the tick labels on the @math{y} axis. @verbatiminclude datagraph.asy @sp 1 @center @image{datagraph} @item This example shows how to graph columns of data read from a file. @verbatiminclude filegraph.asy @sp 1 @center @image{filegraph} @cindex @code{polygon} @cindex @code{cross} @cindex @code{errorbars} @cindex @code{marker} @cindex @code{marknodes} @cindex @code{markuniform} @cindex @code{mark} @cindex path markers @anchor{pathmarkers} @item The next example draws two graphs of an array of coordinate pairs, using frame alignment and data markers. In the left-hand graph, the markers, constructed with @verbatim marker marker(path g, markroutine markroutine=marknodes, pen p=currentpen, filltype filltype=NoFill, bool above=true); @end verbatim using the path @code{unitcircle} (@pxref{filltype}), are drawn below each node. Any frame can be converted to a marker, using @anchor{marker} @verbatim marker marker(frame f, markroutine markroutine=marknodes, bool above=true); @end verbatim In the right-hand graph, the unit @math{n}-sided regular polygon @code{polygon(int n)} and the unit @math{n}-point cyclic cross @code{cross(int n, bool round=true, real r=0)} (where @code{r} is an optional ``inner'' radius) are used to build a custom marker frame. @anchor{markuniform} Here @code{markuniform(bool centered=false, int n, bool rotated=false)} adds this frame at @code{n} uniformly spaced points along the arclength of the path, optionally rotated by the angle of the local tangent to the path (if centered is true, the frames will be centered within @code{n} evenly spaced arclength intervals). Alternatively, one can use markroutine @code{marknodes} to request that the marks be placed at each Bezier node of the path, or markroutine @code{markuniform(pair z(real t), real a, real b, int n)} to place marks at points @code{z(t)} for n evenly spaced values of @code{t} in @code{[a,b]}. These markers are predefined: @verbatim marker[] Mark={ marker(scale(circlescale)*unitcircle), marker(polygon(3)),marker(polygon(4)), marker(polygon(5)),marker(invert*polygon(3)), marker(cross(4)),marker(cross(6)) }; marker[] MarkFill={ marker(scale(circlescale)*unitcircle,Fill),marker(polygon(3),Fill), marker(polygon(4),Fill),marker(polygon(5),Fill), marker(invert*polygon(3),Fill) }; @end verbatim The example also illustrates the @code{errorbar} routines: @verbatim void errorbars(picture pic=currentpicture, pair[] z, pair[] dp, pair[] dm={}, bool[] cond={}, pen p=currentpen, real size=0); void errorbars(picture pic=currentpicture, real[] x, real[] y, real[] dpx, real[] dpy, real[] dmx={}, real[] dmy={}, bool[] cond={}, pen p=currentpen, real size=0); @end verbatim @noindent Here, the positive and negative extents of the error are given by the absolute values of the elements of the pair array @code{dp} and the optional pair array @code{dm}. If @code{dm} is not specified, the positive and negative extents of the error are assumed to be equal. @anchor{errorbars} @cindex error bars @verbatiminclude errorbars.asy @sp 1 @center @image{errorbars} @cindex custom mark routine @item A custom mark routine can be also be specified: @verbatiminclude graphmarkers.asy @sp 1 @center @image{graphmarkers} @item This example shows how to label an axis with arbitrary strings. @verbatiminclude monthaxis.asy @sp 1 @center @image{monthaxis} @item The next example draws a graph of a parametrized curve. @cindex parametrized curve @cindex cropping graphs @cindex @code{xlimits} @cindex @code{ylimits} @cindex @code{limits} @cindex @code{crop} The calls to @verbatim xlimits(picture pic=currentpicture, real min=-infinity, real max=infinity, bool crop=NoCrop); @end verbatim @noindent and the analogous function @code{ylimits} can be uncommented to set the respective axes limits for picture @code{pic} to the specified @code{min} and @code{max} values. Alternatively, the function @verbatim void limits(picture pic=currentpicture, pair min, pair max, bool crop=NoCrop); @end verbatim can be used to limit the axes to the box having opposite vertices at the given pairs). Existing objects in picture @code{pic} will be cropped to lie within the given limits if @code{crop}=@code{Crop}. The function @code{crop(picture pic)} can be used to crop a graph to the current graph limits. @verbatiminclude parametricgraph.asy @sp 1 @center @image{parametricgraph} @cindex scaled graph The next example illustrates how one can extract a common axis scaling factor. @verbatiminclude scaledgraph.asy @sp 1 @center @image{scaledgraph} @anchor{automatic scaling} @cindex automatic scaling @cindex @code{scale} @cindex @code{Linear} @cindex @code{Log} @cindex automatic scaling Axis scaling can be requested and/or automatic selection of the axis limits can be inhibited with one of these @code{scale} routines: @verbatim void scale(picture pic=currentpicture, scaleT x, scaleT y); void scale(picture pic=currentpicture, bool xautoscale=true, bool yautoscale=xautoscale, bool zautoscale=yautoscale); @end verbatim This sets the scalings for picture @code{pic}. The @code{graph} routines accept an optional @code{picture} argument for determining the appropriate scalings to use; if none is given, it uses those set for @code{currentpicture}. Two frequently used scaling routines @code{Linear} and @code{Log} are predefined in @code{graph}. All picture coordinates (including those in paths and those given to the @code{label} and @code{limits} functions) are always treated as linear (post-scaled) coordinates. Use @cindex @code{Scale} @verbatim pair Scale(picture pic=currentpicture, pair z); @end verbatim to convert a graph coordinate into a scaled picture coordinate. The @math{x} and @math{y} components can be individually scaled using the analogous routines @verbatim real ScaleX(picture pic=currentpicture, real x); real ScaleY(picture pic=currentpicture, real y); @end verbatim The predefined scaling routines can be given two optional boolean arguments: @code{automin=false} and @code{automax=automin}. These default to @code{false} but can be respectively set to @code{true} to enable automatic selection of "nice" axis minimum and maximum values. The @code{Linear} scaling can also take as optional final arguments a multiplicative scaling factor and intercept (e.g.@ for a depth axis, @code{Linear(-1)} requests axis reversal). @cindex logarithmic graph @cindex log-log graph For example, to draw a log/log graph of a function, use @code{scale(Log,Log)}: @verbatiminclude loggraph.asy @sp 1 @center @image{loggraph} @cindex grid By extending the ticks, one can easily produce a logarithmic grid: @verbatiminclude loggrid.asy @sp 1 @center @image{loggrid} One can also specify custom tick locations and formats for logarithmic axes: @verbatiminclude logticks.asy @sp 1 @center @image{logticks} @cindex @code{log2} graph It is easy to draw logarithmic graphs with respect to other bases: @verbatiminclude log2graph.asy @sp 1 @center @image{log2graph} @cindex broken axis Here is an example of "broken" linear @math{x} and logarithmic @math{y} axes that omit the segments [3,8] and [100,1000], respectively. In the case of a logarithmic axis, the break endpoints are automatically rounded to the nearest integral power of the base. @verbatiminclude brokenaxis.asy @sp 1 @center @image{brokenaxis} @cindex secondary axis @cindex @code{secondaryX} @cindex @code{secondaryY} @item @code{Asymptote} can draw secondary axes with the routines @verbatim picture secondaryX(picture primary=currentpicture, void f(picture)); picture secondaryY(picture primary=currentpicture, void f(picture)); @end verbatim In this example, @code{secondaryY} is used to draw a secondary linear @math{y} axis against a primary logarithmic @math{y} axis: @verbatiminclude Bode.asy @sp 1 @center @image{Bode} A secondary logarithmic @math{y} axis can be drawn like this: @verbatiminclude secondaryaxis.asy @sp 1 @center @image{secondaryaxis} @item Here is a histogram example, which uses the @code{stats} module. @cindex @code{axis} @verbatiminclude histogram.asy @sp 1 @center @image{histogram} @item Here is an example of reading column data in from a file and a least-squares fit, using the @code{stats} module. @cindex @code{leastsquares} @verbatiminclude leastsquares.asy @sp 1 @center @image{leastsquares} @item Here is an example that illustrates the general @code{axis} routine. @cindex @code{axis} @verbatiminclude generalaxis.asy @sp 1 @center @image{generalaxis} @item To draw a vector field of @code{n} arrows evenly spaced along the arclength of a path, use the routine @cindex @code{vectorfield} @verbatim picture vectorfield(path vector(real), path g, int n, bool truesize=false, pen p=currentpen, arrowbar arrow=Arrow); @end verbatim as illustrated in this simple example of a flow field: @verbatiminclude flow.asy @sp 1 @center @image{flow} @item To draw a vector field of @code{nx}@math{\times}@code{ny} arrows in @code{box(a,b)}, use the routine @cindex @code{vectorfield} @verbatim picture vectorfield(path vector(pair), pair a, pair b, int nx=nmesh, int ny=nx, bool truesize=false, real maxlength=truesize ? 0 : maxlength(a,b,nx,ny), bool cond(pair z)=null, pen p=currentpen, arrowbar arrow=Arrow, margin margin=PenMargin) @end verbatim as illustrated in this example: @verbatiminclude vectorfield.asy @sp 1 @center @image{vectorfield} @item The following scientific graphs, which illustrate many features of @code{Asymptote}'s graphics routines, were generated from the examples @code{diatom.asy} and @code{westnile.asy}, using the comma-separated data in @code{diatom.csv} and @code{westnile.csv}. @page @sp 1 @center @image{diatom} @sp 1 @center @image{westnile,,7.5cm} @end enumerate @page @node palette @section @code{palette} @anchor{images} @cindex images @code{Asymptote} can also generate color density images and palettes. The following palettes are predefined in @code{palette.asy}: @table @code @cindex @code{Grayscale} @item pen[] Grayscale(int NColors=256) a grayscale palette; @cindex @code{Rainbow} @item pen[] Rainbow(int NColors=32766) a rainbow spectrum; @cindex @code{BWRainbow} @item pen[] BWRainbow(int NColors=32761) a rainbow spectrum tapering off to black/white at the ends; @cindex @code{BWRainbow2} @item pen[] BWRainbow2(int NColors=32761) a double rainbow palette tapering off to black/white at the ends, with a linearly scaled intensity. @cindex @code{Wheel} @item pen[] Wheel(int NColors=32766) a full color wheel palette; @cindex @code{Gradient} @item pen[] Gradient(int NColors=256 ... pen[] p) a palette varying linearly over the specified array of pens, using NColors in each interpolation interval; @end table The function @code{cmyk(pen[] Palette)} may be used to convert any of these palettes to the @acronym{CMYK} colorspace. A color density plot using palette @code{palette} can be generated from a function @code{f}(@math{x},@math{y}) and added to a picture @code{pic}: @cindex @code{image} @verbatim bounds image(picture pic=currentpicture, real f(real, real), range range=Full, pair initial, pair final, int nx=ngraph, int ny=nx, pen[] palette, bool antialias=false) @end verbatim The function @code{f} will be sampled at @code{nx} and @code{ny} evenly spaced points over a rectangle defined by the points @code{initial} and @code{final}, respecting the current graphical scaling of @code{pic}. The color space is scaled according to the @math{z} axis scaling (@pxref{automatic scaling}). A bounds structure for the function values is returned: @verbatim struct bounds { real min; real max; // Possible tick intervals: int[] divisor; } @end verbatim @noindent This information can be used for generating an optional palette bar. The palette color space corresponds to a range of values specified by the argument @code{range}, which can be @code{Full}, @code{Automatic}, or an explicit range @code{Range(real min, real max)}. Here @code{Full} specifies a range varying from the minimum to maximum values of the function over the sampling interval, while @code{Automatic} selects "nice" limits. The example @code{imagecontour.asy} illustrates how level sets (contour lines) can be drawn on a color density plot (@pxref{contour}). A color density plot can also be generated from an explicit real[][] array @code{data}: @cindex @code{image} @verbatim bounds image(picture pic=currentpicture, real[][] f, range range=Full, pair initial, pair final, pen[] palette, bool transpose=(initial.x < final.x && initial.y < final.y), bool copy=true, bool antialias=false); @end verbatim @noindent If the initial point is to the left and below the final point, by default the array indices are interpreted according to the Cartesian convention (first index: @math{x}, second index: @math{y}) rather than the usual matrix convention (first index: @math{-y}, second index: @math{x}). To construct an image from an array of irregularly spaced points and an array of values @code{f} at these points, use one of the routines @verbatim bounds image(picture pic=currentpicture, pair[] z, real[] f, range range=Full, pen[] palette) bounds image(picture pic=currentpicture, real[] x, real[] y, real[] f, range range=Full, pen[] palette) @end verbatim An optionally labelled palette bar may be generated with the routine @verbatim void palette(picture pic=currentpicture, Label L="", bounds bounds, pair initial, pair final, axis axis=Right, pen[] palette, pen p=currentpen, paletteticks ticks=PaletteTicks, bool copy=true, bool antialias=false); @end verbatim The color space of @code{palette} is taken to be over bounds @code{bounds} with scaling given by the @math{z} scaling of @code{pic}. The palette orientation is specified by @code{axis}, which may be one of @code{Right}, @code{Left}, @code{Top}, or @code{Bottom}. The bar is drawn over the rectangle from @code{initial} to @code{final}. The argument @code{paletteticks} is a special tick type (@pxref{ticks}) that takes the following arguments: @verbatim paletteticks PaletteTicks(Label format="", ticklabel ticklabel=null, bool beginlabel=true, bool endlabel=true, int N=0, int n=0, real Step=0, real step=0, pen pTick=nullpen, pen ptick=nullpen); @end verbatim The image and palette bar can be fit to a frame and added and optionally aligned to a picture at the desired location: @anchor{image} @verbatiminclude image.asy @sp 1 @center @image{image} Here is an example that uses logarithmic scaling of the function values: @anchor{logimage} @verbatiminclude logimage.asy @sp 1 @center @image{logimage} One can also draw an image directly from a two-dimensional pen array or a function @code{pen f(int, int)}: @verbatim void image(picture pic=currentpicture, pen[][] data, pair initial, pair final, bool transpose=(initial.x < final.x && initial.y < final.y), bool copy=true, bool antialias=false); void image(picture pic=currentpicture, pen f(int, int), int width, int height, pair initial, pair final, bool transpose=(initial.x < final.x && initial.y < final.y), bool antialias=false); @end verbatim @noindent as illustrated in the following examples: @anchor{penimage} @verbatiminclude penimage.asy @sp 1 @center @image{penimage} @anchor{penfunctionimage} @verbatiminclude penfunctionimage.asy @sp 1 @center @image{penfunctionimage} For convenience, the module @code{palette} also defines functions that may be used to construct a pen array from a given function and palette: @verbatim pen[] palette(real[] f, pen[] palette); pen[][] palette(real[][] f, pen[] palette); @end verbatim @node three @section @code{three} @cindex @code{three} @cindex @code{guide3} @cindex @code{path3} @cindex @code{cycle} @cindex @code{curl} @cindex @code{tension} @cindex @code{controls} This module fully extends the notion of guides and paths in @code{Asymptote} to three dimensions. It introduces the new types guide3, path3, and surface. Guides in three dimensions are specified with the same syntax as in two dimensions except that triples @code{(x,y,z)} are used in place of pairs @code{(x,y)} for the nodes and direction specifiers. This generalization of John Hobby's spline algorithm is shape-invariant under three-dimensional rotation, scaling, and shifting, and reduces in the planar case to the two-dimensional algorithm used in @code{Asymptote}, @code{MetaPost}, and @code{MetaFont} [cf.@ J. C. Bowman, Proceedings in Applied Mathematics and Mechanics, 7:1, 2010021-2010022 (2007)]. For example, a unit circle in the @math{XY} plane may be filled and drawn like this: @verbatiminclude unitcircle3.asy @sp 1 @center @image{unitcircle3} @noindent and then distorted into a saddle: @verbatiminclude saddle.asy @sp 1 @center @image{saddle} @noindent Module @code{three} provides constructors for converting two-dimensional paths to three-dimensional ones, and vice-versa: @cindex @code{path3} @cindex @code{path} @verbatim path3 path3(path p, triple plane(pair)=XYplane); path path(path3 p, pair P(triple)=xypart); @end verbatim @cindex @code{surface} @cindex @code{render} @cindex @code{defaultrender} A Bezier surface, the natural two-dimensional generalization of Bezier curves, is defined in @code{three_surface.asy} as a structure containing an array of Bezier patches. Surfaces may drawn with one of the routines @verbatim void draw(picture pic=currentpicture, surface s, int nu=1, int nv=1, material surfacepen=currentpen, pen meshpen=nullpen, light light=currentlight, light meshlight=nolight, string name="", render render=defaultrender); void draw(picture pic=currentpicture, surface s, int nu=1, int nv=1, material[] surfacepen, pen meshpen, light light=currentlight, light meshlight=nolight, string name="", render render=defaultrender); void draw(picture pic=currentpicture, surface s, int nu=1, int nv=1, material[] surfacepen, pen[] meshpen=nullpens, light light=currentlight, light meshlight=nolight, string name="", render render=defaultrender); @end verbatim The parameters @code{nu} and @code{nv} specify the number of subdivisions for drawing optional mesh lines for each Bezier patch. The optional @code{name} parameter is used as a prefix for naming the surface patches in the @acronym{PRC} model tree. Here material is a structure defined in @code{three_light.asy}: @verbatim struct material { pen[] p; // diffusepen,ambientpen,emissivepen,specularpen real opacity; real shininess; ... } @end verbatim @noindent These material properties are used to implement @code{OpenGL}-style lighting, based on the Phong-Blinn specular model. Sample Bezier surfaces are contained in the example files @code{BezierSurface.asy}, @code{teapot.asy}, and @code{parametricsurface.asy}. The structure @code{render} contains specialized rendering options documented at the beginning of module @code{three.asy}. @cindex patch-dependent colors @cindex vertex-dependent colors The examples @code{elevation.asy} and @code{sphericalharmonic.asy} illustrate how to draw a surface with patch-dependent colors. The examples @code{vertexshading} and @code{smoothelevation} illustrate vertex-dependent colors, which is supported for both @code{Asymptote}'s native @code{OpenGL} renderer and two-dimensional projections. Since the @acronym{PRC} output format does not currently support vertex shading of Bezier surfaces, @acronym{PRC} patches are shaded with the mean of the four vertex colors. @cindex @code{surface} @cindex @code{planar} @cindex @code{Bezier patch} @cindex @code{Bezier triangle} A surface can be constructed from a cyclic @code{path3} with the constructor @verbatim surface surface(path3 external, triple[] internal=new triple[], pen[] colors=new pen[], bool3 planar=default); @end verbatim @noindent and then filled: @verbatim draw(surface(unitsquare3,new triple[] {X,Y,Z,O}),red); draw(surface(O--X{Y}..Y{-X}--cycle,new triple[] {Z}),red); draw(surface(path3(polygon(5))),red,nolight); draw(surface(unitcircle3),red,nolight); draw(surface(unitcircle3,new pen[] {red,green,blue,black}),nolight); @end verbatim @noindent The first example draws a Bezier patch and the second example draws a Bezier triangle. The third and fourth examples are planar surfaces. The last example constructs a patch with vertex-specific colors. A three-dimensional planar surface in the plane @code{plane} can be constructed from a two-dimensional cyclic path @code{g} with the constructor @cindex @code{surface} @verbatim surface surface(path p, triple plane(pair)=XYplane); @end verbatim @noindent and then filled: @verbatim draw(surface((0,0)--E+2N--2E--E+N..0.2E..cycle),red); @end verbatim @noindent @cindex @code{bezulate} Planar Bezier surfaces patches are constructed using Orest Shardt's @code{bezulate} routine, which decomposes (possibly nonsimply connected) regions bounded (according to the @code{zerowinding} fill rule) by simple cyclic paths (intersecting only at the endpoints) into subregions bounded by cyclic paths of length @code{4} or less. A more efficient routine also exists for drawing tessellations composed of many 3D triangles, with specified vertices, and optional normals or vertex colors: @cindex @code{draw} @cindex @code{triangles} @cindex @code{tessellation} @verbatim void draw(picture pic=currentpicture, triple[] v, int[][] vi, triple[] n={}, int[][] ni={}, material m=currentpen, pen[] p={}, int[][] pi={}, light light=currentlight); @end verbatim Here, the triple array @code{v} lists the distinct vertices, while the array @code{vi} lists integer arrays of length 3 containing the indices of @code{v} corresponding to the vertices of each triangle. Similarly, the arguments @code{n} and @code{ni} contain optional normal data and @code{p} and @code{pi} contain optional pen vertex data. An example of this tessellation facility is given in @code{triangles.asy}. @cindex @code{thin} @cindex @code{thick} @cindex @code{tube} Arbitrary thick three-dimensional curves and line caps (which the @code{OpenGL} standard does not require implementations to provide) are constructed with @verbatim tube tube(path3 p, real width, render render=defaultrender); @end verbatim @noindent this returns a tube structure representing a tube of diameter @code{width} centered approximately on @code{g}. The tube structure consists of a surface @code{s} and the actual tube center, path3 @code{center}. Drawing thick lines as tubes can be slow to render, especially with the @code{Adobe Reader} renderer. The setting @code{thick=false} can be used to disable this feature and force all lines to be drawn with @code{linewidth(0)} (one pixel wide, regardless of the resolution). By default, mesh and contour lines in three-dimensions are always drawn thin, unless an explicit line width is given in the pen parameter or the setting @code{thin} is set to @code{false}. The pens @code{thin()} and @code{thick()} defined in plain_pens.asy can also be used to override these defaults for specific draw commands. @noindent There are four choices for viewing 3D @code{Asymptote} output: @enumerate @cindex @code{OpenGL} @cindex @code{render} @cindex @code{outformat} @cindex @code{multisample} @item Use the native @code{Asymptote} adaptive @code{OpenGL}-based renderer (with the command-line option @code{-V} and the default settings @code{outformat=""} and @code{render=-1}). If you encounter warnings from your graphics card driver, try specifying @code{-glOptions=-indirect} on the command line. On @code{UNIX} systems with graphics support for multisampling, the sample width can be controlled with the setting @code{multisample}. An initial screen position can be specified with the pair setting @code{position}, where negative values are interpreted as relative to the corresponding maximum screen dimension. The default settings @cindex mouse bindings @verbatim import settings; leftbutton=new string[] {"rotate","zoom","shift","pan"}; middlebutton=new string[] {"menu"}; rightbutton=new string[] {"zoom/menu","rotateX","rotateY","rotateZ"}; wheelup=new string[] {"zoomin"}; wheeldown=new string[] {"zoomout"}; @end verbatim bind the mouse buttons as follows: @itemize @item Left: rotate @item Shift Left: zoom @item Ctrl Left: shift viewport @item Alt Left: pan @item Middle: menu (must be unmodified; ignores Shift, Ctrl, and Alt) @item Wheel Up: zoom in @item Wheel Down: zoom out @item Right: zoom/menu (must be unmodified) @item Right double click: menu @item Shift Right: rotate about the X axis @item Ctrl Right: rotate about the Y axis @item Alt Right: rotate about the Z axis @end itemize The keyboard shortcuts are: @cindex keyboard bindings: @itemize @item h: home @item f: toggle fitscreen @item x: spin about the X axis @item y: spin about the Y axis @item z: spin about the Z axis @item s: stop spinning @item m: rendering mode (solid/mesh/patch) @item e: export @item c: show camera parameters @item p: play animation @item r: reverse animation @item : step animation @item +: expand @item =: expand @item >: expand @item -: shrink @item _: shrink @item <: shrink @item q: exit @item Ctrl-q: exit @end itemize @cindex @code{antialias} @cindex @code{maxviewport} @cindex @code{maxtile} @cindex @code{glOptions} @cindex @code{iconic} @cindex @code{black stripes} @item Render the scene to a specified rasterized format @code{outformat} at the resolution of @code{n} pixels per @code{bp}, as specified by the setting @code{render=n}. A negative value of @code{n} is interpreted as @code{|2n|} for @acronym{EPS} and @acronym{PDF} formats and @code{|n|} for other formats. The default value of @code{render} is -1. By default, the scene is internally rendered at twice the specified resolution; this can be disabled by setting @code{antialias=1}. High resolution rendering is done by tiling the image. If your graphics card allows it, the rendering can be made more efficient by increasing the maximum tile size @code{maxtile} to your screen dimensions (indicated by @code{maxtile=(0,0)}. If your video card generates unwanted black stripes in the output, try setting the horizontal and vertical components of @code{maxtiles} to something less than your screen dimensions. The tile size is also limited by the setting @code{maxviewport}, which restricts the maximum width and height of the viewport. On @code{UNIX} systems some graphics drivers support batch mode (@code{-noV}) rendering in an iconified window; this can be enabled with the setting @code{iconify=true}. Some (broken) @code{UNIX} graphics drivers may require the command line setting @code{-glOptions=-indirect}, which requests (slower) indirect rendering. @cindex @code{prc} @cindex @code{views} @item Embed the 3D @acronym{PRC} format in a @acronym{PDF} file and view the resulting @acronym{PDF} file with version @code{9.0} or later of @code{Adobe Reader}. In addition to the default @code{settings.prc=true}, this requires @code{settings.outformat="pdf"}, which can be specified by the command line option @code{-f pdf}, put in the @code{Asymptote} configuration file (@pxref{configuration file}), or specified in the script before @code{three.asy} (or @code{graph3.asy}) is imported. The @code{media9} LaTeX package is also required (@pxref{embed}). The example @code{pdb.asy} illustrates how one can generate a list of predefined views (see @code{100d.views}). A stationary preview image with a resolution of @code{n} pixels per @code{bp} can be embedded with the setting @code{render=n}; this allows the file to be viewed with other @code{PDF} viewers. Alternatively, the file @code{externalprc.tex} illustrates how the resulting @acronym{PRC} and rendered image files can be extracted and processed in a separate @code{LaTeX} file. However, see @ref{LaTeX usage} for an easier way to embed three-dimensional @code{Asymptote} pictures within @code{LaTeX}. For specialized applications where only the raw @acronym{PRC} file is required, specify @code{settings.outformat="prc"}. The open-source @acronym{PRC} specification is available from @url{http://livedocs.adobe.com/acrobat_sdk/9/Acrobat9_HTMLHelp/API_References/PRCReference/PRC_Format_Specification/}. @item Project the scene to a two-dimensional vector (@acronym{EPS} or @acronym{PDF}) format with @code{render=0}. Only limited hidden surface removal facilities are currently available with this approach (@pxref{PostScript3D}). @end enumerate @cindex @code{double deferred drawing} Automatic picture sizing in three dimensions is accomplished with double deferred drawing. The maximal desired dimensions of the scene in each of the three dimensions can optionally be specified with the routine @cindex @code{size3} @verbatim void size3(picture pic=currentpicture, real x, real y=x, real z=y, bool keepAspect=pic.keepAspect); @end verbatim @noindent @cindex margins @cindex @code{viewportmargin} @cindex @code{viewportsize} The resulting simplex linear programming problem is then solved to produce a 3D version of a frame (actually implemented as a 3D picture). The result is then fit with another application of deferred drawing to the viewport dimensions corresponding to the usual two-dimensional picture @code{size} parameters. The global pair @code{viewportmargin} may be used to add horizontal and vertical margins to the viewport dimensions. Alternatively, a minimum @code{viewportsize} may be specified. A 3D picture @code{pic} can be explicitly fit to a 3D frame by calling @cindex @code{fit3} @verbatim frame pic.fit3(projection P=currentprojection); @end verbatim @noindent and then added to picture @code{dest} about @code{position} with @cindex @code{add} @verbatim void add(picture dest=currentpicture, frame src, triple position=(0,0,0)); @end verbatim @cindex @code{O} @cindex @code{X} @cindex @code{Y} @cindex @code{Z} @cindex @code{unitcircle} For convenience, the @code{three} module defines @code{O=(0,0,0)}, @code{X=(1,0,0)}, @code{Y=(0,1,0)}, and @code{Z=(0,0,1)}, along with a unitcircle in the XY plane: @verbatim path3 unitcircle3=X..Y..-X..-Y..cycle; @end verbatim @cindex @code{circle} A general (approximate) circle can be drawn perpendicular to the direction @code{normal} with the routine @verbatim path3 circle(triple c, real r, triple normal=Z); @end verbatim @cindex @code{arc} A circular arc centered at @code{c} with radius @code{r} from @code{c+r*dir(theta1,phi1)} to @code{c+r*dir(theta2,phi2)}, drawing counterclockwise relative to the normal vector @code{cross(dir(theta1,phi1),dir(theta2,phi2))} if @code{theta2 > theta1} or if @code{theta2 == theta1} and @code{phi2 >= phi1}, can be constructed with @verbatim path3 arc(triple c, real r, real theta1, real phi1, real theta2, real phi2, triple normal=O); @end verbatim The normal must be explicitly specified if @code{c} and the endpoints are colinear. If @code{r} < 0, the complementary arc of radius @code{|r|} is constructed. For convenience, an arc centered at @code{c} from triple @code{v1} to @code{v2} (assuming @code{|v2-c|=|v1-c|}) in the direction CCW (counter-clockwise) or CW (clockwise) may also be constructed with @verbatim path3 arc(triple c, triple v1, triple v2, triple normal=O, bool direction=CCW); @end verbatim @noindent When high accuracy is needed, the routines @code{Circle} and @code{Arc} defined in @code{graph3} may be used instead. See @ref{GaussianSurface} for an example of a three-dimensional circular arc. @cindex @code{plane} The representation @code{O--O+u--O+u+v--O+v--cycle} of the plane passing through point @code{O} with normal @code{cross(u,v)} is returned by @verbatim path3 plane(triple u, triple v, triple O=O); @end verbatim A three-dimensional box with opposite vertices at triples @code{v1} and @code{v2} may be drawn with the function @cindex @code{box} @verbatim path3[] box(triple v1, triple v2); @end verbatim @noindent For example, a unit box is predefined as @cindex @code{box} @cindex @code{unitbox} @verbatim path3[] unitbox=box(O,(1,1,1)); @end verbatim @code{Asymptote} also provides optimized definitions for the three-dimensional paths @code{unitsquare3} and @code{unitcircle3}, along with the surfaces @code{unitdisk}, @code{unitplane}, @code{unitcube}, @code{unitcylinder}, @code{unitcone}, @code{unitsolidcone}, @code{unitfrustum(real t1, real t2)}, @code{unitsphere}, and @code{unithemisphere}. @noindent These projections to two dimensions are predefined: @table @code @item oblique @item oblique(real angle) @cindex @code{oblique} @cindex @code{obliqueZ} The point @code{(x,y,z)} is projected to @code{(x-0.5z,y-0.5z)}. If an optional real argument is given, the negative @math{z} axis is drawn at this angle in degrees. The projection @code{obliqueZ} is a synonym for @code{oblique}. @item obliqueX @item obliqueX(real angle) @cindex @code{obliqueX} The point @code{(x,y,z)} is projected to @code{(y-0.5x,z-0.5x)}. If an optional real argument is given, the negative @math{x} axis is drawn at this angle in degrees. @item obliqueY @item obliqueY(real angle) @cindex @code{obliqueY} The point @code{(x,y,z)} is projected to @code{(x+0.5y,z+0.5y)}. If an optional real argument is given, the positive @math{y} axis is drawn at this angle in degrees. @cindex @code{orthographic} @cindex @code{up} @cindex @code{target} @cindex @code{showtarget} @cindex @code{center} @item orthographic(triple camera, triple up=Z, triple target=O, @*@ @ @ @ @ @ @ @ @ @ @ @ @ real zoom=1, pair viewportshift=0, bool showtarget=true, @*@ @ @ @ @ @ @ @ @ @ @ @ @ bool center=false) This projects from three to two dimensions using the view as seen at a point infinitely far away in the direction @code{unit(camera)}, orienting the camera so that, if possible, the vector @code{up} points upwards. Parallel lines are projected to parallel lines. The bounding volume is expanded to include @code{target} if @code{showtarget=true}. If @code{center=true}, the target will be adjusted to the center of the bounding volume. @item orthographic(real x, real y, real z, triple up=Z, triple target=O, @*@ @ @ @ @ @ @ @ @ @ @ @ @ real zoom=1, pair viewportshift=0, bool showtarget=true, @*@ @ @ @ @ @ @ @ @ @ @ @ @ bool center=false) This is equivalent to @verbatim orthographic((x,y,z),up,target,zoom,viewportshift,showtarget,center) @end verbatim The routine @cindex @code{camera} @verbatim triple camera(real alpha, real beta); @end verbatim can be used to compute the camera position with the @math{x} axis below the horizontal at angle @code{alpha}, the @math{y} axis below the horizontal at angle @code{beta}, and the @math{z} axis up. @cindex @code{autoadjust} @item perspective(triple camera, triple up=Z, triple target=O, @*@ @ @ @ @ @ @ @ @ @ @ @ real zoom=1, real angle=0, pair viewportshift=0, @*@ @ @ @ @ @ @ @ @ @ @ @ bool showtarget=true, bool autoadjust=true, @*@ @ @ @ @ @ @ @ @ @ @ @ bool center=autoadjust) @cindex @code{perspective} @cindex @code{NURBS} This projects from three to two dimensions, taking account of perspective, as seen from the location @code{camera} looking at @code{target}, orienting the camera so that, if possible, the vector @code{up} points upwards. If @code{render=0}, projection of three-dimensional cubic Bezier splines is implemented by approximating a two-dimensional nonuniform rational B-spline (@acronym{NURBS}) with a two-dimensional Bezier curve containing additional nodes and control points. If @code{autoadjust=true}, the camera will automatically be adjusted to lie outside the bounding volume for all possible interactive rotations about @code{target}. If @code{center=true}, the target will be adjusted to the center of the bounding volume. @item perspective(real x, real y, real z, triple up=Z, triple target=O, @*@ @ @ @ @ @ @ @ @ @ @ @ real zoom=1, real angle=0, pair viewportshift=0, @*@ @ @ @ @ @ @ @ @ @ @ @ bool showtarget=true, bool autoadjust=true, @*@ @ @ @ @ @ @ @ @ @ @ @ bool center=autoadjust) This is equivalent to @verbatim perspective((x,y,z),up,target,zoom,angle,viewportshift,showtarget, autoadjust,center) @end verbatim @end table @cindex @code{currentprojection} @noindent The default projection, @code{currentprojection}, is initially set to @code{perspective(5,4,2)}. @cindex @code{LeftView} @cindex @code{RightView} @cindex @code{FrontView} @cindex @code{BackView} @cindex @code{BottomView} @cindex @code{TopView} We also define standard orthographic views used in technical drawing: @verbatim projection LeftView=orthographic(-X,showtarget=true); projection RightView=orthographic(X,showtarget=true); projection FrontView=orthographic(-Y,showtarget=true); projection BackView=orthographic(Y,showtarget=true); projection BottomView=orthographic(-Z,showtarget=true); projection TopView=orthographic(Z,showtarget=true); @end verbatim @noindent The function @cindex @code{addViews} @verbatim void addViews(picture dest=currentpicture, picture src, projection[][] views=SixViewsUS, bool group=true, filltype filltype=NoFill); @end verbatim @noindent adds to picture @code{dest} an array of views of picture @code{src} using the layout projection[][] @code{views}. The default layout @code{SixViewsUS} aligns the projection @code{FrontView} below @code{TopView} and above @code{BottomView}, to the right of @code{LeftView} and left of @code{RightView} and @code{BackView}. The predefined layouts are: @cindex @code{ThreeViewsUS} @cindex @code{SixViewsUS} @cindex @code{ThreeViewsFR} @cindex @code{SixViewsFR} @cindex @code{ThreeViews} @cindex @code{SixViews} @verbatim projection[][] ThreeViewsUS={{TopView}, {FrontView,RightView}}; projection[][] SixViewsUS={{null,TopView}, {LeftView,FrontView,RightView,BackView}, {null,BottomView}}; projection[][] ThreeViewsFR={{RightView,FrontView}, {null,TopView}}; projection[][] SixViewsFR={{null,BottomView}, {RightView,FrontView,LeftView,BackView}, {null,TopView}}; projection[][] ThreeViews={{FrontView,TopView,RightView}}; projection[][] SixViews={{FrontView,TopView,RightView}, {BackView,BottomView,LeftView}}; @end verbatim A triple or path3 can be projected to a pair or path, with @code{project(triple, projection P=currentprojection)} or @code{project(path3, projection P=currentprojection)}. It is occasionally useful to be able to invert a projection, sending a pair @code{z} onto the plane perpendicular to @code{normal} and passing through @code{point}: @cindex @code{invert} @verbatim triple invert(pair z, triple normal, triple point, projection P=currentprojection); @end verbatim @noindent A pair @code{z} on the projection plane can be inverted to a triple with the routine @verbatim triple invert(pair z, projection P=currentprojection); @end verbatim @noindent A pair direction @code{dir} on the projection plane can be inverted to a triple direction relative to a point @code{v} with the routine @verbatim triple invert(pair dir, triple v, projection P=currentprojection). @end verbatim @cindex @code{transform3} @cindex @code{identity4} Three-dimensional objects may be transformed with one of the following built-in transform3 types (the identity transformation is @code{identity4}): @table @code @item shift(triple v) @cindex @code{shift} translates by the triple @code{v}; @item xscale3(real x) @cindex @code{xscale3} scales by @code{x} in the @math{x} direction; @item yscale3(real y) @cindex @code{yscale3} scales by @code{y} in the @math{y} direction; @item zscale3(real z) @cindex @code{zscale3} scales by @code{z} in the @math{z} direction; @item scale3(real s) @cindex @code{scale3} scales by @code{s} in the @math{x}, @math{y}, and @math{z} directions; @item scale(real x, real y, real z) @cindex @code{scale} scales by @code{x} in the @math{x} direction, by @code{y} in the @math{y} direction, and by @code{z} in the @math{z} direction; @cindex @code{rotate} @item rotate(real angle, triple v) rotates by @code{angle} in degrees about an axis @code{v} through the origin; @item rotate(real angle, triple u, triple v) rotates by @code{angle} in degrees about the axis @code{u--v}; @item reflect(triple u, triple v, triple w) reflects about the plane through @code{u}, @code{v}, and @code{w}. @cindex @code{XY} @end table When not multiplied on the left by a transform3, three-dimensional @TeX{} Labels are drawn as Bezier surfaces directly on the projection plane: @cindex @code{label} @verbatim void label(picture pic=currentpicture, Label L, triple position, align align=NoAlign, pen p=currentpen, light light=nolight, string name="", render render=defaultrender, interaction interaction= settings.autobillboard ? Billboard : Embedded) @end verbatim @noindent @cindex @code{Billboard} @cindex @code{Embedded} The optional @code{name} parameter is used as a prefix for naming the label patches in the @acronym{PRC} model tree. The default interaction is @code{Billboard}, which means that labels are rotated interactively so that they always face the camera. The interaction @code{Embedded} means that the label interacts as a normal @code{3D} surface, as illustrated in the example @code{billboard.asy}. @cindex @code{transform} @cindex @code{XY} @cindex @code{YZ} @cindex @code{ZX} @cindex @code{YX} @cindex @code{ZY} @cindex @code{ZX} Alternatively, a label can be transformed from the @code{XY} plane by an explicit transform3 or mapped to a specified two-dimensional plane with the predefined transform3 types @code{XY}, @code{YZ}, @code{ZX}, @code{YX}, @code{ZY}, @code{ZX}. There are also modified versions of these transforms that take an optional argument @code{projection P=currentprojection} that rotate and/or flip the label so that it is more readable from the initial viewpoint. @cindex @code{planeproject} A transform3 that projects in the direction @code{dir} onto the plane with normal @code{n} through point @code{O} is returned by @verbatim transform3 planeproject(triple n, triple O=O, triple dir=n); @end verbatim @noindent One can use @cindex @code{normal} @verbatim triple normal(path3 p); @end verbatim @noindent to find the unit normal vector to a planar three-dimensional path @code{p}. As illustrated in the example @code{planeproject.asy}, a transform3 that projects in the direction @code{dir} onto the plane defined by a planar path @code{p} is returned by @verbatim transform3 planeproject(path3 p, triple dir=normal(p)); @end verbatim The functions @cindex @code{extrude} @verbatim surface extrude(path p, triple axis=Z); surface extrude(Label L, triple axis=Z); @end verbatim @noindent return the surface obtained by extruding path @code{p} or Label @code{L} along @code{axis}. @cindex @code{length} @cindex @code{size} @cindex @code{point} @cindex @code{dir} @cindex @code{accel} @cindex @code{radius} @cindex @code{precontrol} @cindex @code{postcontrol} @cindex @code{arclength} @cindex @code{arctime} @cindex @code{reverse} @cindex @code{subpath} @cindex @code{intersect} @cindex @code{intersections} @cindex @code{intersectionpoint} @cindex @code{intersectionpoints} @cindex @code{min} @cindex @code{max} @cindex @code{cyclic} @cindex @code{straight} Three-dimensional versions of the path functions @code{length}, @code{size}, @code{point}, @code{dir}, @code{accel}, @code{radius}, @code{precontrol}, @code{postcontrol}, @code{arclength}, @code{arctime}, @code{reverse}, @code{subpath}, @code{intersect}, @code{intersections}, @code{intersectionpoint}, @code{intersectionpoints}, @code{min}, @code{max}, @code{cyclic}, and @code{straight} are also defined. The routine @cindex @code{intersections} @verbatim real[] intersect(path3 p, surface s, real fuzz=-1); @end verbatim @noindent returns a real array of length 3 containing the intersection times, if any, of a path @code{p} with a surface @code{s}. The routine @verbatim real[][] intersections(path3 p, surface s, real fuzz=-1); @end verbatim @noindent returns all (unless there are infinitely many) intersection times of a path @code{p} with a surface @code{s} as a sorted array of real arrays of length 3, and @cindex @code{intersectionpoints} @verbatim triple[] intersectionpoints(path3 p, surface s, real fuzz=-1); @end verbatim @noindent returns the corresponding intersection points. Here, the computations are performed to the absolute error specified by @code{fuzz}, or if @code{fuzz < 0}, to machine precision. The routine @cindex @code{orient} @verbatim real orient(triple a, triple b, triple c, triple d); @end verbatim @noindent is a numerically robust computation of @code{dot(cross(a-d,b-d),c-d)}, which is the determinant @verbatim |a.x a.y a.z 1| |b.x b.y b.z 1| |c.x c.y c.z 1| |d.x d.y d.z 1| @end verbatim The routine @cindex @code{insphere} @verbatim real insphere(triple a, triple b, triple c, triple d, triple e); @end verbatim @noindent returns a positive (negative) value if @code{e} lies inside (outside) the sphere passing through points @code{a,b,c,d} oriented so that @code{dot(cross(a-d,b-d),c-d)} is positive, or zero if all five points are cospherical. The value returned is the determinant @verbatim |a.x a.y a.z a.x^2+a.y^2+a.z^2 1| |b.x b.y b.z b.x^2+b.y^2+b.z^2 1| |c.x c.y c.z c.x^2+c.y^2+c.z^2 1| |d.x d.y d.z d.x^2+d.y^2+d.z^2 1| |e.x e.y e.z e.x^2+e.y^2+e.z^2 1| @end verbatim Here is an example showing all five guide3 connectors: @verbatiminclude join3.asy @sp 1 @center @image{join3} @cindex @code{BeginBar3} @cindex @code{EndBar3} @cindex @code{Bar3} @cindex @code{Bars3} @cindex @code{BeginArrow3} @cindex @code{MidArrow3} @cindex @code{EndArrow3} @cindex @code{Arrow3} @cindex @code{Arrows3} @cindex @code{BeginArcArrow3} @cindex @code{MidArcArrow3} @cindex @code{EndArcArrow3} @cindex @code{ArcArrow3} @cindex @code{ArcArrows3} @cindex @code{DefaultHead3} @cindex @code{HookHead3} @cindex @code{TeXHead3} Three-dimensional versions of bars or arrows can be drawn with one of the specifiers @code{None}, @code{Blank}, @code{BeginBar3}, @code{EndBar3} (or equivalently @code{Bar3}), @code{Bars3}, @code{BeginArrow3}, @code{MidArrow3}, @code{EndArrow3} (or equivalently @code{Arrow3}), @code{Arrows3}, @code{BeginArcArrow3}, @code{EndArcArrow3} (or equivalently @code{ArcArrow3}), @code{MidArcArrow3}, and @code{ArcArrows3}. Three-dimensional bars accept the optional arguments @code{(real size=0, triple dir=O)}. If @code{size=O}, the default bar length is used; if @code{dir=O}, the bar is drawn perpendicular to the path and the initial viewing direction. The predefined three-dimensional arrowhead styles are @code{DefaultHead3}, @code{HookHead3}, @code{TeXHead3}. Versions of the two-dimensional arrowheads lifted to three-dimensional space and aligned according to the initial viewpoint (or an optionally specified @code{normal} vector) are also defined: @code{DefaultHead2(triple normal=O)}, @code{HookHead2(triple normal=O)}, @code{TeXHead2(triple normal=O)}. These are illustrated in the example @code{arrows3.asy}. @cindex @code{NoMargin3} @cindex @code{BeginMargin3} @cindex @code{EndMargin3} @cindex @code{Margin3} @cindex @code{Margins3} @cindex @code{BeginPenMargin2} @cindex @code{EndPenMargin2} @cindex @code{PenMargin2} @cindex @code{PenMargins2} @cindex @code{BeginPenMargin3} @cindex @code{EndPenMargin3} @cindex @code{PenMargin3} @cindex @code{PenMargins3} @cindex @code{BeginDotMargin3} @cindex @code{EndDotMargin3} @cindex @code{DotMargin3} @cindex @code{DotMargins3} @cindex @code{Margin3} @cindex @code{TrueMargin3} Module @code{three} also defines the three-dimensional margins @code{NoMargin3}, @code{BeginMargin3}, @code{EndMargin3}, @code{Margin3}, @code{Margins3}, @code{BeginPenMargin2}, @code{EndPenMargin2}, @code{PenMargin2}, @code{PenMargins2}, @code{BeginPenMargin3}, @code{EndPenMargin3}, @code{PenMargin3}, @code{PenMargins3}, @code{BeginDotMargin3}, @code{EndDotMargin3}, @code{DotMargin3}, @code{DotMargins3}, @code{Margin3}, and @code{TrueMargin3}. @cindex @code{pixel} The routine @verbatim void pixel(picture pic=currentpicture, triple v, pen p=currentpen, real width=1); @end verbatim @noindent can be used to draw on picture @code{pic} a pixel of width @code{width} at position @code{v} using pen @code{p}. Further three-dimensional examples are provided in the files @code{near_earth.asy}, @code{conicurv.asy}, and (in the @code{animations} subdirectory) @code{cube.asy}. @anchor{PostScript3D} @cindex 3D @code{PostScript} Limited support for projected vector graphics (effectively three-dimensional nonrendered @code{PostScript}) is available with the setting @code{render=0}. This currently only works for piecewise planar surfaces, such as those produced by the parametric @code{surface} routines in the @code{graph3} module. Surfaces produced by the @code{solids} package will also be properly rendered if the parameter @code{nslices} is sufficiently large. @cindex hidden surface removal @cindex @code{face} In the module @code{bsp}, hidden surface removal of planar pictures is implemented using a binary space partition and picture clipping. A planar path is first converted to a structure @code{face} derived from @code{picture}. A @code{face} may be given to a two-dimensional drawing routine in place of any @code{picture} argument. An array of such faces may then be drawn, removing hidden surfaces: @verbatim void add(picture pic=currentpicture, face[] faces, projection P=currentprojection); @end verbatim Labels may be projected to two dimensions, using projection @code{P}, onto the plane passing through point @code{O} with normal @code{cross(u,v)} by multiplying it on the left by the transform @verbatim transform transform(triple u, triple v, triple O=O, projection P=currentprojection); @end verbatim Here is an example that shows how a binary space partition may be used to draw a two-dimensional vector graphics projection of three orthogonal intersecting planes: @verbatiminclude planes.asy @sp 1 @center @image{planes} @node obj @section @code{obj} @cindex @code{obj} This module allows one to construct surfaces from simple obj files, as illustrated in the example files @code{galleon.asy} and @code{triceratops.asy}. @node graph3 @section @code{graph3} @cindex @code{graph3} @cindex 3D graphs This module implements three-dimensional versions of the functions in @code{graph.asy}. @cindex @code{xaxis3} @cindex @code{yaxis3} @cindex @code{zaxis3} @noindent To draw an @math{x} axis in three dimensions, use the routine @verbatim void xaxis3(picture pic=currentpicture, Label L="", axis axis=YZZero, real xmin=-infinity, real xmax=infinity, pen p=currentpen, ticks3 ticks=NoTicks3, arrowbar3 arrow=None, bool above=false); @end verbatim @noindent Analogous routines @code{yaxis} and @code{zaxis} can be used to draw @math{y} and @math{z} axes in three dimensions. There is also a routine for drawing all three axis: @verbatim void axes3(picture pic=currentpicture, Label xlabel="", Label ylabel="", Label zlabel="", bool extend=false, triple min=(-infinity,-infinity,-infinity), triple max=(infinity,infinity,infinity), pen p=currentpen, arrowbar3 arrow=None); @end verbatim @cindex @code{YZEquals} @cindex @code{XZEquals} @cindex @code{XYEquals} @cindex @code{YZZero} @cindex @code{XZZero} @cindex @code{XYZero} @cindex @code{Bounds} @noindent The predefined three-dimensional axis types are @verbatim axis YZEquals(real y, real z, triple align=O, bool extend=false); axis XZEquals(real x, real z, triple align=O, bool extend=false); axis XYEquals(real x, real y, triple align=O, bool extend=false); axis YZZero(triple align=O, bool extend=false); axis XZZero(triple align=O, bool extend=false); axis XYZero(triple align=O, bool extend=false); axis Bounds(int type=Both, int type2=Both, triple align=O, bool extend=false); @end verbatim @noindent The optional @code{align} parameter to these routines can be used to specify the default axis and tick label alignments. The @code{Bounds} axis accepts two type parameters, each of which must be one of @code{Min}, @code{Max}, or @code{Both}. These parameters specify which of the four possible three-dimensional bounding box edges should be drawn. @cindex @code{NoTicks3} @cindex @code{InTicks} @cindex @code{OutTicks} @cindex @code{InOutTicks} The three-dimensional tick options are @code{NoTicks3}, @code{InTicks}, @code{OutTicks}, and @code{InOutTicks}. These specify the tick directions for the @code{Bounds} axis type; other axis types inherit the direction that would be used for the @code{Bounds(Min,Min)} axis. Here is an example of a helix and bounding box axes with ticks and axis labels, using orthographic projection: @verbatiminclude helix.asy @sp 1 @center @image{helix} The next example illustrates three-dimensional @math{x}, @math{y}, and @math{z} axes, without autoscaling of the axis limits: @cindex @code{axis} @verbatiminclude axis3.asy @sp 1 @center @image{axis3} One can also place ticks along a general three-dimensional axis: @cindex @code{axis} @verbatiminclude generalaxis3.asy @sp 1 @center @image{generalaxis3} @cindex @code{surface} @cindex @code{Spline} @cindex parametric surface Surface plots of matrices and functions over the region @code{box(a,b)} in the @math{XY} plane are also implemented: @verbatim surface surface(real[][] f, pair a, pair b, bool[][] cond={}); surface surface(real[][] f, pair a, pair b, splinetype xsplinetype, splinetype ysplinetype=xsplinetype, bool[][] cond={}); surface surface(real[][] f, real[] x, real[] y, splinetype xsplinetype=null, splinetype ysplinetype=xsplinetype, bool[][] cond={}) surface surface(triple[][] f, bool[][] cond={}); surface surface(real f(pair z), pair a, pair b, int nx=nmesh, int ny=nx, bool cond(pair z)=null); surface surface(real f(pair z), pair a, pair b, int nx=nmesh, int ny=nx, splinetype xsplinetype, splinetype ysplinetype=xsplinetype, bool cond(pair z)=null); surface surface(triple f(pair z), real[] u, real[] v, splinetype[] usplinetype, splinetype[] vsplinetype=Spline, bool cond(pair z)=null); surface surface(triple f(pair z), pair a, pair b, int nu=nmesh, int nv=nu, bool cond(pair z)=null); surface surface(triple f(pair z), pair a, pair b, int nu=nmesh, int nv=nu, splinetype[] usplinetype, splinetype[] vsplinetype=Spline, bool cond(pair z)=null); @end verbatim @noindent The final two versions draw parametric surfaces for a function @math{f(u,v)} over the parameter space @code{box(a,b)}, as illustrated in the example @code{parametricsurface.asy}. An optional splinetype @code{Spline} may be specified. The boolean array or function @code{cond} can be used to control which surface mesh cells are actually drawn (by default all mesh cells over @code{box(a,b)} are drawn). Surface lighting is illustrated in the example files @code{parametricsurface.asy} and @code{sinc.asy}. Lighting can be disabled by setting @code{light=nolight}, as in this example of a Gaussian surface: @anchor{GaussianSurface} @verbatiminclude GaussianSurface.asy @sp 1 @center @image{GaussianSurface} @noindent A mesh can be drawn without surface filling by specifying @code{nullpen} for the surfacepen. A vector field of @code{nu}@math{\times}@code{nv} arrows on a parametric surface @code{f} over @code{box(a,b)} can be drawn with the routine @cindex @code{vectorfield3} @verbatim picture vectorfield(path3 vector(pair v), triple f(pair z), pair a, pair b, int nu=nmesh, int nv=nu, bool truesize=false, real maxlength=truesize ? 0 : maxlength(f,a,b,nu,nv), bool cond(pair z)=null, pen p=currentpen, arrowbar3 arrow=Arrow3, margin3 margin=PenMargin3) @end verbatim as illustrated in the examples @code{vectorfield3.asy} and @code{vectorfieldsphere.asy}. @node grid3 @section @code{grid3} @cindex @code{grid3} @cindex 3D grids This module, contributed by Philippe Ivaldi, can be used for drawing 3D grids. Here is an example (further examples can be found in @code{grid3.asy} and at @url{http://www.piprime.fr/files/asymptote/grid3/}): @verbatiminclude grid3xyz.asy @sp 1 @center @image{grid3xyz} @node solids @section @code{solids} @cindex @code{solids} This solid geometry package defines a structure @code{revolution} that can be used to fill and draw surfaces of revolution. The following example uses it to display the outline of a circular cylinder of radius 1 with axis @code{O--1.5unit(Y+Z)} with perspective projection: @verbatiminclude cylinderskeleton.asy @sp 1 @center @image{cylinderskeleton} Further illustrations are provided in the example files @code{cylinder.asy}, @code{cones.asy}, @code{hyperboloid.asy}, and @code{torus.asy}. The structure @code{skeleton} contains the three-dimensional wireframe used to visualize a volume of revolution: @verbatim struct skeleton { struct curve { path3[] front; path3[] back; } // transverse skeleton (perpendicular to axis of revolution) curve transverse; // longitudinal skeleton (parallel to axis of revolution) curve longitudinal; } @end verbatim @node tube @section @code{tube} @cindex @code{tube} This package extends the @code{tube} surfaces constructed in @code{three_arrows.asy} to arbitrary cross sections, colors, and spine transformations. The routine @verbatim surface tube(path3 g, coloredpath section, transform T(real)=new transform(real t) {return identity();}, real corner=1, real relstep=0); @end verbatim @noindent draws a tube along @code{g} with cross section @code{section}, after applying the transformation @code{T(t)} at @code{relpoint(g,t)}. The parameter @code{corner} controls the number of elementary tubes at the angular points of @code{g}. A nonzero value of @code{relstep} specifies a fixed relative time step (in the sense of @code{relpoint(g,t)}) to use in constructing elementary tubes along @code{g}. The type @code{coloredpath} is a generalization of @code{path} to which a @code{path} can be cast: @cindex @code{coloredpath} @verbatim struct coloredpath { path p; pen[] pens(real); int colortype=coloredSegments; } @end verbatim @noindent @cindex @code{coloredSegments} @cindex @code{coloredNodes} Here @code{p} defines the cross section and the method @code{pens(real t)} returns an array of pens (interpreted as a cyclic array) used for shading the tube patches at @code{relpoint(g,t)}. If @code{colortype=coloredSegments}, the tube patches are filled as if each segment of the section was colored with the pen returned by @code{pens(t)}, whereas if @code{colortype=coloredNodes}, the tube components are vertex shaded as if the nodes of the section were colored. A @code{coloredpath} can be constructed with one of the routines: @verbatim coloredpath coloredpath(path p, pen[] pens(real), int colortype=coloredSegments); coloredpath coloredpath(path p, pen[] pens=new pen[] {currentpen}, int colortype=coloredSegments); coloredpath coloredpath(path p, pen pen(real)); @end verbatim @noindent In the second case, the pens are independent of the relative time. In the third case, the array of pens contains only one pen, which depends of the relative time. The casting of @code{path} to @code{coloredpath} allows the use of a @code{path} instead of a @code{coloredpath}; in this case the shading behaviour is the default shading behavior for a surface. An example of @code{tube} is provided in the file @code{trefoilknot.asy}. Further examples can be found at @url{http://www.piprime.fr/files/asymptote/tube/}. @node flowchart @section @code{flowchart} @cindex @code{flowchart} This package provides routines for drawing flowcharts. The primary structure is a @code{block}, which represents a single block on the flowchart. The following eight functions return a position on the appropriate edge of the block, given picture transform @code{t}: @verbatim pair block.top(transform t=identity()); pair block.left(transform t=identity()); pair block.right(transform t=identity()); pair block.bottom(transform t=identity()); pair block.topleft(transform t=identity()); pair block.topright(transform t=identity()); pair block.bottomleft(transform t=identity()); pair block.bottomright(transform t=identity()); @end verbatim @cindex @code{block.top} @cindex @code{block.left} @cindex @code{block.right} @cindex @code{block.bottom} @cindex @code{block.topleft} @cindex @code{block.topright} @cindex @code{block.bottomleft} @cindex @code{block.bottomright} @noindent To obtain an arbitrary position along the boundary of the block in user coordinates, use: @verbatim pair block.position(real x, transform t=identity()); @end verbatim @cindex @code{block.position} @noindent @cindex @code{block.center} The center of the block in user coordinates is stored in @code{block.center} and the block size in @code{PostScript} coordinates is given by @code{block.size}. @noindent A frame containing the block is returned by @verbatim frame block.draw(pen p=currentpen); @end verbatim @cindex @code{block.draw} The following block generation routines accept a Label, string, or frame for their object argument: @table @dfn @item rectangular block with an optional header (and padding @code{dx} around header and body): @cindex @code{rectangle} @verbatim block rectangle(object header, object body, pair center=(0,0), pen headerpen=mediumgray, pen bodypen=invisible, pen drawpen=currentpen, real dx=3, real minheaderwidth=minblockwidth, real minheaderheight=minblockwidth, real minbodywidth=minblockheight, real minbodyheight=minblockheight); block rectangle(object body, pair center=(0,0), pen fillpen=invisible, pen drawpen=currentpen, real dx=3, real minwidth=minblockwidth, real minheight=minblockheight); @end verbatim @item parallelogram block: @cindex @code{parallelogram} @verbatim block parallelogram(object body, pair center=(0,0), pen fillpen=invisible, pen drawpen=currentpen, real dx=3, real slope=2, real minwidth=minblockwidth, real minheight=minblockheight); @end verbatim @item diamond-shaped block: @cindex @code{diamond} @verbatim block diamond(object body, pair center=(0,0), pen fillpen=invisible, pen drawpen=currentpen, real ds=5, real dw=1, real height=20, real minwidth=minblockwidth, real minheight=minblockheight); @end verbatim @item circular block: @cindex @code{circle} @verbatim block circle(object body, pair center=(0,0), pen fillpen=invisible, pen drawpen=currentpen, real dr=3, real mindiameter=mincirclediameter); @end verbatim @item rectangular block with rounded corners: @cindex @code{roundrectangle} @verbatim block roundrectangle(object body, pair center=(0,0), pen fillpen=invisible, pen drawpen=currentpen, real ds=5, real dw=0, real minwidth=minblockwidth, real minheight=minblockheight); @end verbatim @item rectangular block with beveled edges: @cindex @code{bevel} @verbatim block bevel(object body, pair center=(0,0), pen fillpen=invisible, pen drawpen=currentpen, real dh=5, real dw=5, real minwidth=minblockwidth, real minheight=minblockheight); @end verbatim @end table To draw paths joining the pairs in @code{point} with right-angled lines, use the routine: @cindex @code{path} @cindex @code{Horizontal} @cindex @code{Vertical} @verbatim path path(pair point[] ... flowdir dir[]); @end verbatim @noindent The entries in @code{dir} identify whether successive segments between the pairs specified by @code{point} should be drawn in the @code{Horizontal} or @code{Vertical} direction. Here is a simple flowchart example (see also the example @code{controlsystem.asy}): @verbatiminclude flowchartdemo.asy @sp 1 @center @image{flowchartdemo} @node contour @section @code{contour} @cindex @code{contour} This package draws contour lines. To construct contours corresponding to the values in a real array @code{c} for a function @code{f} on @code{box(a,b)}, use the routine @verbatim guide[][] contour(real f(real, real), pair a, pair b, real[] c, int nx=ngraph, int ny=nx, interpolate join=operator --, int subsample=1); @end verbatim @noindent The integers @code{nx} and @code{ny} define the resolution. The default resolution, @code{ngraph x ngraph} (here @code{ngraph} defaults to @code{100}) can be increased for greater accuracy. The default interpolation operator is @code{operator --} (linear). Spline interpolation (@code{operator ..}) may produce smoother contours but it can also lead to overshooting. The @code{subsample} parameter indicates the number of interior points that should be used to sample contours within each @code{1 x 1} box; the default value of @code{1} is usually sufficient. To construct contours for an array of data values on a uniform two-dimensional lattice on @code{box(a,b)}, use @verbatim guide[][] contour(real[][] f, pair a, pair b, real[] c, interpolate join=operator --, int subsample=1); @end verbatim To construct contours for an array of data values on a nonoverlapping regular mesh specified by the two-dimensional array @code{z}, @verbatim guide[][] contour(pair[][] z, real[][] f, real[] c, interpolate join=operator --, int subsample=1); @end verbatim @noindent To construct contours for an array of values @code{f} specified at irregularly positioned points @code{z}, use the routine @verbatim guide[][] contour(pair[] z, real[] f, real[] c, interpolate join=operator --); @end verbatim @noindent The contours themselves can be drawn with one of the routines @verbatim void draw(picture pic=currentpicture, Label[] L=new Label[], guide[][] g, pen p=currentpen); void draw(picture pic=currentpicture, Label[] L=new Label[], guide[][] g, pen[] p); @end verbatim The following simple example draws the contour at value @code{1} for the function @math{z=x^2+y^2}, which is a unit circle: @verbatiminclude onecontour.asy @sp 1 @center @image{onecontour} The next example draws and labels multiple contours for the function @math{z=x^2-y^2} with the resolution @code{100 x 100}, using a dashed pen for negative contours and a solid pen for positive (and zero) contours: @verbatiminclude multicontour.asy @sp 1 @center @image{multicontour} The next example illustrates how contour lines can be drawn on color density images: @verbatiminclude imagecontour.asy @sp 1 @center @image{imagecontour} Finally, here is an example that illustrates the construction of contours from irregularly spaced data: @verbatiminclude irregularcontour.asy @sp 1 @center @image{irregularcontour} In the above example, the contours of irregularly spaced data are constructed by first creating a triangular mesh from an array @code{z} of pairs: @cindex @code{triangulate} @verbatim int[][] triangulate(pair[] z); @end verbatim @verbatiminclude triangulate.asy @sp 1 @center @image{triangulate} The example @code{Gouraudcontour.asy} illustrates how to produce color density images over such irregular triangular meshes. @code{Asymptote} uses a robust version of Paul Bourke's Delaunay triangulation algorithm based on the public-domain exact arithmetic predicates written by Jonathan Shewchuk. @node contour3 @section @code{contour3} @cindex @code{contour3} This package draws surfaces described as the null space of real-valued functions of @math{(x,y,z)} or @code{real[][][]} matrices. Its usage is illustrated in the example file @code{magnetic.asy}. @node smoothcontour3 @section @code{smoothcontour3} @cindex @code{smoothcontour3} This module, written by Charles Staats, draws implicitly defined surfaces with smooth appearance. The purpose of this module is similar to that of @code{contour3}: given a real-valued function @math{f(x,y,z)}, construct the surface described by the equation @math{f(x,y,z) = 0}. The @code{smoothcontour3} module generally produces nicer results than @code{contour3}, but takes longer to compile. Additionally, the algorithm assumes that the function and the surface are both smooth; if they are not, then @code{contour3} may be a better choice. To construct the null surface of a function @code{f(triple)} or @code{ff(real,real,real)} over @code{box(a,b)}, use the routine @cindex @code{implicitsurface} @verbatim surface implicitsurface(real f(triple)=null, real ff(real,real,real)=null, triple a, triple b, int n=nmesh, bool keyword overlapedges=false, int keyword nx=n, int keyword ny=n, int keyword nz=n, int keyword maxdepth=8); @end verbatim @noindent The optional parameter @code{overlapedges} attempts to compensate for an artifact that can cause the renderer to ``see through'' the boundary between patches. Although it defaults to @code{false}, it should usually be set to @code{true}. The example @code{genustwo.asy} illustrates the use of this function: Additional examples, together with a more in-depth explanation of the module's usage and pitfalls, are available at @url{https://github.com/charlesstaats/smoothcontour3}. @node slopefield @section @code{slopefield} @cindex @code{slopefield} To draw a slope field for the differential equation @math{dy/dx=f(x,y)} (or @math{dy/dx=f(x)}), use: @verbatim picture slopefield(real f(real,real), pair a, pair b, int nx=nmesh, int ny=nx, real tickfactor=0.5, pen p=currentpen, arrowbar arrow=None); @end verbatim @noindent Here, the points @code{a} and @code{b} are the lower left and upper right corners of the rectangle in which the slope field is to be drawn, @code{nx} and @code{ny} are the respective number of ticks in the @math{x} and @math{y} directions, @code{tickfactor} is the fraction of the minimum cell dimension to use for drawing ticks, and @code{p} is the pen to use for drawing the slope fields. The return value is a picture that can be added to @code{currentpicture} via the @code{add(picture)} command. The function @cindex @code{curve} @verbatim path curve(pair c, real f(real,real), pair a, pair b); @end verbatim @noindent takes a point (@code{c}) and a slope field-defining function @code{f} and returns, as a path, the curve passing through that point. The points @code{a} and @code{b} represent the rectangular boundaries over which the curve is interpolated. Both @code{slopefield} and @code{curve} alternatively accept a function @code{real f(real)} that depends on @math{x} only, as seen in this example: @verbatiminclude slopefield1.asy @sp 1 @center @image{slopefield1} @node ode @section @code{ode} @cindex @code{ode} The @code{ode} module, illustrated in the example @code{odetest.asy}, implements a number of explicit numerical integration schemes for ordinary differential equations. @node Options @chapter Command-line options @cindex options @cindex command-line options Type @code{asy -h} to see the full list of command-line options supported by @code{Asymptote}: @verbatiminclude options All boolean options can be negated by prepending @code{no} to the option name. If no arguments are given, @code{Asymptote} runs in interactive mode (@pxref{Interactive mode}). In this case, the default output file is @code{out.eps}. If @code{-} is given as the file argument, @code{Asymptote} reads from standard input. If multiple files are specified, they are treated as separate @code{Asymptote} runs. @cindex @code{autoimport} If the string @code{autoimport} is nonempty, a module with this name is automatically imported for each run as the final step in loading module @code{plain}. @anchor{configuration file} @cindex configuration file @cindex @code{ASYMPTOTE_CONFIG} @cindex @code{config} @cindex @code{settings} @anchor{settings} Default option values may be entered as @code{Asymptote} code in a configuration file named @code{config.asy} (or the file specified by the environment variable @code{ASYMPTOTE_CONFIG} or @code{-config} option). @code{Asymptote} will look for this file in its usual search path (@pxref{Search paths}). Typically the configuration file is placed in the @code{.asy} directory in the user's home directory (@code{%USERPROFILE%\.asy} under @code{MSDOS}). Configuration variables are accessed using the long form of the option names: @verbatim import settings; outformat="pdf"; batchView=false; interactiveView=true; batchMask=false; interactiveMask=true; @end verbatim Command-line options override these defaults. Most configuration variables may also be changed at runtime. @cindex @code{dvipsOptions} @cindex @code{hyperrefOptions} @cindex @code{convertOptions} @cindex @code{gsOptions} @cindex @code{psviewerOptions} @cindex @code{pdfviewerOptions} @cindex @code{pdfreloadOptions} @cindex @code{glOptions} @cindex @code{dvisvgmOptions} The advanced configuration variables @code{dvipsOptions}, @code{hyperrefOptions}, @code{convertOptions}, @code{gsOptions}, @code{psviewerOptions}, @code{pdfviewerOptions}, @code{pdfreloadOptions}, @code{glOptions}, and @code{dvisvgmOptions} allow specialized options to be passed as a string to the respective applications or libraries. The default value of @code{hyperrefOptions} is @code{setpagesize=false,unicode,pdfborder=0 0 0}. If you insert @verbatim import plain; settings.autoplain=true; @end verbatim @noindent at the beginning of the configuration file, it can contain arbitrary @code{Asymptote} code. @cindex @code{convert} @cindex @code{output} @cindex @code{format} @cindex @code{ImageMagick} @cindex @code{render} @cindex @code{antialias} @cindex @code{size} @cindex @code{latex} @cindex @code{tex} @cindex @code{pdflatex} @cindex @code{xelatex} @cindex @code{context} @cindex @code{luatex} @cindex @code{lualatex} @cindex @code{EPS} @cindex @code{PDF} @anchor{texengines} @anchor{convert} The default output format is @acronym{EPS} for the (default) @code{latex} and @code{tex} tex engine and @acronym{PDF} for the @code{pdflatex}, @code{xelatex}, @code{context}, @code{luatex}, and @code{lualatex} tex engines. Alternative output formats may be produced using the @code{-f} option (or @code{outformat} setting). @cindex @code{SVG} @cindex @code{dvisvgm} @cindex @code{libgs} To produce @acronym{SVG} output, you will need @code{dvisvgm} (version 1.5.3 or later) from @url{http://dvisvgm.sourceforge.net} and must use the @code{latex} or @code{tex} tex engine. You might need to adjust the configuration variable @code{libgs} to point to the location of your @code{Ghostscript} library @code{libgs.so} (or to an empty string, depending on how @code{dvisvgm} was configured). @code{Asymptote} can also produce any output format supported by the @code{ImageMagick} @code{convert} program (version 6.3.5 or later recommended; an @code{Invalid Parameter} error message indicates that the @code{MSDOS} utility @code{convert} is being used instead of the one that comes with @code{ImageMagick}). The optional setting @code{-render n} requests an output resolution of @code{n} pixels per @code{bp}. Antialiasing is controlled by the parameter @code{antialias}, which by default specifies a sampling width of 2 pixels. To give other options to @code{convert}, use the @code{convertOptions} setting or call convert manually. This example emulates how @code{Asymptote} produces antialiased @code{tiff} output at one pixel per @code{bp}: @verbatim asy -o - venn | convert -alpha Off -density 144x144 -geometry 50%x eps:- venn.tiff @end verbatim @cindex @code{nosafe} @cindex @code{safe} @cindex @code{system} If the option @code{-nosafe} is given, @code{Asymptote} runs in unsafe mode. This enables the @code{int system(string s)} and @code{int system(string[] s)} calls, allowing one to execute arbitrary shell commands. The default mode, @code{-safe}, disables this call. @cindex offset @cindex @code{aligndir} A @code{PostScript} offset may be specified as a pair (in @code{bp} units) with the @code{-O} option: @verbatim asy -O 0,0 file @end verbatim @noindent The default offset is zero. The pair @code{aligndir} specifies an optional direction on the boundary of the page (mapped to the rectangle [-1,1]@math{\times}[-1,1]) to which the picture should be aligned; the default value @code{(0,0)} species center alignment. @cindex @code{-c} The @code{-c} (@code{command}) option may be used to execute arbitrary @code{Asymptote} code on the command line as a string. It is not necessary to terminate the string with a semicolon. Multiple @code{-c} options are executed in the order they are given. For example @verbatim asy -c 2+2 -c "sin(1)" -c "size(100); draw(unitsquare)" @end verbatim @noindent produces the output @verbatim 4 0.841470984807897 @end verbatim @noindent and draws a unitsquare of size @code{100}. @cindex @code{-u} The @code{-u} (@code{user}) option may be used to specify arbitrary @code{Asymptote} settings on the command line as a string. It is not necessary to terminate the string with a semicolon. Multiple @code{-u} options are executed in the order they are given. Command-line code like @code{-u x=sqrt(2)} can be executed within a module like this: @verbatim real x; usersetting(); write(x); @end verbatim @cindex @code{-l} When the @code{-l} (@code{listvariables}) option is used with file arguments, only global functions and variables defined in the specified file(s) are listed. Additional debugging output is produced with each additional @code{-v} option: @table @code @item -v Display top-level module and final output file names. @item -vv Also display imported and included module names and final @code{LaTeX} and @code{dvips} processing information. @item -vvv Also output @code{LaTeX} bidirectional pipe diagnostics. @item -vvvv Also output knot guide solver diagnostics. @item -vvvvv Also output @code{Asymptote} traceback diagnostics. @end table @node Interactive mode @chapter Interactive mode @cindex interactive mode Interactive mode is entered by executing the command @code{asy} with no file arguments. When the @code{-multiline} option is disabled (the default), each line must be a complete @code{Asymptote} statement (unless explicitly continued by a final backslash character @code{\}); it is not necessary to terminate input lines with a semicolon. If one assigns @code{settings.multiline=true}, interactive code can be entered over multiple lines; in this mode, the automatic termination of interactive input lines by a semicolon is inhibited. Multiline mode is useful for cutting and pasting @code{Asymptote} code directly into the interactive input buffer. @cindex @code{%} Interactive mode can be conveniently used as a calculator: expressions entered at the interactive prompt (for which a corresponding @code{write} function exists) are automatically evaluated and written to @code{stdout}. If the expression is non-writable, its type signature will be printed out instead. In either case, the expression can be referred to using the symbol @code{%} in the next line input at the prompt. For example: @verbatim > 2+3 5 > %*4 20 > 1/% 0.05 > sin(%) 0.0499791692706783 > currentpicture > %.size(200,0) > @end verbatim @cindex @code{operator answer} The @code{%} symbol, when used as a variable, is shorthand for the identifier @code{operator answer}, which is set by the prompt after each written expression evaluation. The following special commands are supported only in interactive mode and must be entered immediately after the prompt: @table @code @cindex @code{help} @item help view the manual; @item erase erase @code{currentpicture}; @cindex @code{input} @item reset reset the @code{Asymptote} environment to its initial state, except for changes to the settings module (@pxref{settings}), the current directory (@pxref{cd}), and breakpoints (@pxref{Debugger}); @cindex @code{input} @item input FILE does an interactive reset, followed by the command @code{include FILE}. If the file name @code{FILE} contains nonalphanumeric characters, enclose it with quotation marks. A trailing semi-colon followed by optional @code{Asymptote} commands may be entered on the same line. @cindex @code{quit} @cindex @code{exit} @cindex @code{history} @anchor{history} @item quit exit interactive mode (@code{exit} is a synonym; the abbreviation @code{q} is also accepted unless there exists a top-level variable named @code{q}). @cindex @code{historylines} A history of the most recent 1000 (this number can be changed with the @code{historylines} configuration variable) previous commands will be retained in the file @code{.asy/history} in the user's home directory (unless the command-line option @code{-localhistory} was specified, in which case the history will be stored in the file @code{.asy_history} in the current directory). @end table Typing @code{ctrl-C} interrupts the execution of @code{Asymptote} code and returns control to the interactive prompt. Interactive mode is implemented with the @acronym{GNU} @code{readline} library, with command history and auto-completion. To customize the key bindings, see: @url{http://cnswww.cns.cwru.edu/php/chet/readline/readline.html} @cindex @code{Python} usage The file @code{asymptote.py} in the @code{Asymptote} system directory provides an alternative way of entering @code{Asymptote} commands interactively, coupled with the full power of @code{Python}. Copy this file to your @code{Python path} and then execute from within @code{Python} the commands @verbatim from asymptote import * g=asy() g.size(200) g.draw("unitcircle") g.send("draw(unitsquare)") g.fill("unitsquare, blue") g.clip("unitcircle") g.label("\"$O$\", (0,0), SW") @end verbatim @node GUI @chapter Graphical User Interface @cindex graphical user interface @cindex @acronym{GUI} @cindex mouse @cindex wheel mouse @cindex @code{Button-1} @cindex @code{Button-2} @cindex @code{xasy} In the event that adjustments to the final figure are required, the preliminary Graphical User Interface (@acronym{GUI}) @code{xasy} included with @code{Asymptote} allows you to move graphical objects and draw new ones. The modified figure can then be saved as a normal @code{Asymptote} file. @menu * GUI installation:: Installing @code{xasy} * GUI usage:: @end menu @node GUI installation @section GUI installation @cindex GUI installation As @code{xasy} is written in the interactive scripting language @code{Python/TK}, it requires @code{Python} (@url{http://www.python.org}), the @code{Python Imaging Library} (@url{http://www.pythonware.com/products/pil/}), and the @code{tkinter} package (included with @code{Python} under @code{Microsoft Windows}) be installed. @code{Fedora Linux} users can either install @code{tkinter} with the commands @verbatim yum install tkinter yum install tk-devel @end verbatim @noindent or manually install the @code{tkinter}, @code{tix}, @code{tk}, and @code{tk-devel} packages. Pictures are deconstructed into the @acronym{PNG} image format, which supports full alpha channel transparency. Under @code{Microsoft Windows}, this requires @code{Python 2.7.4} or later and version @code{3.1.0} of the @code{Pillow} fork of the @code{Python Imaging Library}, available from @quotation @url{https://pypi.python.org/pypi/Pillow/3.1.0} @end quotation @node GUI usage @section GUI usage @cindex GUI usage @cindex @code{deconstruct} A wheel mouse is convenient for raising and lowering objects within @code{xasy}, to expose the object to be moved. If a wheel mouse is not available, mouse @code{Button-2} can be used to repeatedly lower an object instead. When run from the command line, @code{xasy} accepts a command line option @code{-x n}, which sets the initial magnification to @code{n}. Deconstruction of compound objects (such as arrows) can be prevented by enclosing them within the commands @verbatim void begingroup(picture pic=currentpicture); void endgroup(picture pic=currentpicture); @end verbatim By default, the elements of a picture or frame will be grouped together on adding them to a picture. However, the elements of a frame added to another frame are not grouped together by default: their elements will be individually deconstructed (@pxref{add}). @node PostScript to Asymptote @chapter @code{PostScript} to @code{Asymptote} @cindex @code{pstoedit} The excellent @code{PostScript} editor @code{pstoedit} (version 3.50 or later; available from @url{http://sourceforge.net/projects/pstoedit/}) includes an @code{Asymptote} backend. Unlike virtually all other @code{pstoedit} backends, this driver includes native clipping, even-odd fill rule, @code{PostScript} subpath, and full image support. Here is an example: @noindent @code{asy -V @value{Datadir}/doc/asymptote/examples/venn.asy} @noindent @verbatim pstoedit -f asy venn.eps test.asy asy -V test @end verbatim @noindent If the line widths aren't quite correct, try giving @code{pstoedit} the @code{-dis} option. If the fonts aren't typeset correctly, try giving @code{pstoedit} the @code{-dt} option. @node Help @chapter Help @cindex help @cindex forum A list of frequently asked questions (@acronym{FAQ}) is maintained at @quotation @url{http://asymptote.sourceforge.net/FAQ} @end quotation @noindent Questions on installing and using @code{Asymptote} that are not addressed in the @acronym{FAQ} should be sent to the @code{Asymptote} forum: @quotation @url{http://sourceforge.net/p/asymptote/discussion/409349} @end quotation @noindent Including an example that illustrates what you are trying to do will help you get useful feedback. @code{LaTeX} problems can often be diagnosed with the @code{-vv} or @code{-vvv} command-line options. Contributions in the form of patches or @code{Asymptote} modules can be posted here: @quotation @url{http://sourceforge.net/p/asymptote/patches} @end quotation @noindent To receive announcements of upcoming releases, please subscribe to @code{Asymptote} at @quotation @url{http://freecode.com/projects/asy} @end quotation @cindex bug reports @noindent If you find a bug in @code{Asymptote}, please check (if possible) whether the bug is still present in the latest @code{git} developmental code (@pxref{Git}) before submitting a bug report. New bugs can be submitted using the Bug Tracking System at @quotation @url{http://sourceforge.net/projects/asymptote} @end quotation @noindent To see if the bug has already been fixed, check bugs with Status @code{Closed} and recent lines in @quotation @url{http://asymptote.sourceforge.net/ChangeLog} @end quotation @noindent @cindex stack overflow @cindex segmentation fault @cindex @code{libsigsegv} @code{Asymptote} can be configured with the optional @acronym{GNU} library @code{libsigsegv}, available from @url{http://libsigsegv.sourceforge.net}, which allows one to distinguish user-generated @code{Asymptote} stack overflows (@pxref{stack overflow}) from true segmentation faults (due to internal C++ programming errors; please submit the @code{Asymptote} code that generates such segmentation faults along with your bug report). @node Debugger @chapter Debugger @cindex debugger Asymptote now includes a line-based (as opposed to code-based) debugger that can assist the user in following flow control. To set a break point in file @code{file} at line @code{line}, use the command @cindex @code{stop} @verbatim void stop(string file, int line, code s=quote{}); @end verbatim @noindent The optional argument @code{s} may be used to conditionally set the variable @code{ignore} in @code{plain_debugger.asy} to @code{true}. For example, the first 10 instances of this breakpoint will be ignored (the variable @code{int count=0} is defined in @code{plain_debugger.asy}): @verbatim stop("test",2,quote{ignore=(++count <= 10);}); @end verbatim To set a break point in file @code{file} at the first line containing the string @code{text}, use @verbatim void stop(string file, string text, code s=quote{}); @end verbatim @noindent To list all breakpoints, use: @cindex @code{breakpoints} @verbatim void breakpoints(); @end verbatim @noindent To clear a breakpoint, use: @cindex @code{clear} @verbatim void clear(string file, int line); @end verbatim @noindent To clear all breakpoints, use: @verbatim void clear(); @end verbatim The following commands may be entered at the debugging prompt: @table @code @cindex @code{help} @item @code{h} help; @cindex @code{continue} @item @code{c} continue execution; @cindex @code{inst} @item @code{i} step to the next instruction; @cindex @code{step} @item @code{s} step to the next executable line; @cindex @code{next} @item @code{n} step to the next executable line in the current file; @cindex @code{file} @item @code{f} step to the next file; @cindex @code{return} @item @code{r} return to the file associated with the most recent breakpoint; @cindex @code{trace} @item @code{t} toggle tracing (@code{-vvvvv}) mode; @cindex @code{quit} @item @code{q} quit debugging and end execution; @cindex @code{exit} @item @code{x} exit the debugger and run to completion. @end table @noindent Arbitrary @code{Asymptote} code may also be entered at the debugging prompt; however, since the debugger is implemented with @code{eval}, currently only top-level (global) variables can be displayed or modified. The debugging prompt may be entered manually with the call @verbatim void breakpoint(code s=quote{}); @end verbatim @node Credits @chapter Acknowledgments @cindex acknowledgments Financial support for the development of @code{Asymptote} was generously provided by the Natural Sciences and Engineering Research Council of Canada, the Pacific Institute for Mathematical Sciences, and the University of Alberta Faculty of Science. We also would like to acknowledge the previous work of John D. Hobby, author of the program @code{MetaPost} that inspired the development of @code{Asymptote}, and Donald E. Knuth, author of @TeX{} and @code{MetaFont} (on which @code{MetaPost} is based). The authors of @code{Asymptote} are Andy Hammerlindl, John Bowman, and Tom Prince. Sean Healy designed the @code{Asymptote} logo. Other contributors include Michail Vidiassov, Radoslav Marinov, Orest Shardt, Chris Savage, Philippe Ivaldi, Olivier Guib@'e, Jacques Pienaar, Mark Henning, Steve Melenchuk, Martin Wiebusch, and Stefan Knorr. @node Index @unnumbered Index @printindex cp @bye @c LocalWords: randMax Gaussrand asy cindex indices resized LaTeX TK latin au @c LocalWords: latexusage tex bbox PostScript subdirectory gcc emacs ASYDIR @c LocalWords: documentclass usepackage subpath shipout sqrt xN Mx bw AcroRd @c LocalWords: xscale xaxis yaxis BeginBar GIF postprocessing fpu de rpair xy @c LocalWords: ImageMagick cd asymptote Hy 0pt 1filll 's 3D 2D 'asy @c LocalWords: startup natively xasy tkinter VxN yingyang currentpicture toc @c LocalWords: MetaPost MetaFont Hammerlindl Healy texinfo autoload setq setf @c LocalWords: printindex setfilename settitle dircategory direntry titlepage @c LocalWords: vskip filll insertcopying ifnottex detailmenu alist augroup PQ @c LocalWords: bool behaviour facto zxf login Debian dev filetypedetect @c LocalWords: FFTW bp readline gv eps args Boehm gc evenoddoverlap png joe @c LocalWords: boolean initializer expi dir xpart ypart STL substring rfind @c LocalWords: pos substr strftime typedef pxref unitcircle yscale Bezier iff @c LocalWords: postcontrol precontrol atleast nullpath arclength arctime rgb @c LocalWords: dirtime currentpen colorspaces grayscale cmyk defaultpen x cx @c LocalWords: linetype longdashed dashdotted longdashdotted linewidth y XP @c LocalWords: fontsize defaultfilename keepAspect IgnoreAspect ise flushleft @c LocalWords: src dest XDR txt getc fout stdin stdout endl eof js prc ni @c LocalWords: Microsystem's eol exponentials postfix sayhi th Ubuntu @c LocalWords: sqr intop addby libm asin acos atan sinh tanh asinh acosh cbrt @c LocalWords: atanh fabs hypot fmod ceil srand dereferenced alice pete sqrtx @c LocalWords: eval fft csv runtime nonalphanumeric labely LeftTicks NoTicks @c LocalWords: RightTicks BottomTop LeftRight Ticksize UTF BufNewFile BufRead @c LocalWords: ticksize subintervals xlimits filetype plugin setlocal makeprg @c LocalWords: ylimits uncommented automin automax cp uninstall reals ecast @c LocalWords: scaleT unicode RightSide yx yy NoAlign legendmargin opic CCW @c LocalWords: arrowbar LeftSide EndBar BeginArrow lly feynman isi showtarget @c LocalWords: EndArrow BeginArcArrow EndArcArrow ArcArrow ArcArrows NoFill @c LocalWords: filldraw fillpen drawpen errorformat bigsquare bezier darkblue @c LocalWords: quartercircle darkgreen lightblue urx ury texpreamble sgn texi @c LocalWords: lineargraph datagraph vertices parametricgraph uncomment ggv @c LocalWords: loggraph generalaxis texhash arrowsize arrowangle arrowlength @c LocalWords: SuppressQuiet MoveQuiet LIBREADLINE config MacOS prebuilt @c LocalWords: ghostview gsview SIGHUP PDF acroread xpdf cutbefore strptime @c LocalWords: libsigsegv intersectionpoint dotfactor vv firstcut pq logticks @c LocalWords: Unisys dvips vvv vvvv vvvvv traceback lastcut cutafter infodir @c LocalWords: zxvf xargs cond polargraph xmin xmax plabel YZero labelling ln @c LocalWords: ymin ymax XZero xequals tickmin tickmax unlabelled se pq pena @c LocalWords: yequals Nobre Barbarosie Schwaiger nearearth conicurv Wiebusch @c LocalWords: unfill posterSize ngraph interpolatetype ctrl dt pic getint Ai @c LocalWords: NNE jxf linecap linejoin unitsquare shadedtiling ei nomarker @c LocalWords: westnile minipage ra penb paletteticks drawline nV FillDraw uv @c LocalWords: susceptibleM flushright secondaryX secondaryY secondaryaxis tt @c LocalWords: titlelabel columnlabel rb xtick ytick labelx XEquals YEquals @c LocalWords: treetest eetomumu fermi backend pstoedit drawtree xFF MSDOS gz @c LocalWords: vimrc CFLAGS verbatiminclude online noindent bezier superpath @c LocalWords: evenodd squarecap roundcap extendcap miterjoin roundjoin NFSS @c LocalWords: beveljoin fillrule zerowinding insideness lineskip cmr pcrr Hx @c LocalWords: AvantGarde Bookman Helvetica NewCenturySchoolBook minbound pdf @c LocalWords: Palatino TimesRoman ZapfChancery ZapfDingbats german basealign @c LocalWords: nondeconstructed backends usr venn labelsquare nobasealign dp @c LocalWords: NoMargin BeginMargin EndMargin BeginPenMargin EndPenMargin dm @c LocalWords: PenMargin PenMargins TrueMargin labelmargin errorbars errorbar @c LocalWords: dpx dpy dmx dmy barsize arrowsize BeginDotMargin DotMargin acc @c LocalWords: EndDotMargin DotMargins NColors BWRainbow colorspace labelled @c LocalWords: PaletteTicks defaultformat leastsquares bjam fprintf endgroup @c LocalWords: begingroup xmargin ymargin pbox box ellipse wget exe Gouraud @c LocalWords: multithreaded newframe init emph nums concat xline yline zpart @c LocalWords: colatitude zscale cosh nullpen MetaFontbook cyclicflag FreeBSD @c LocalWords: nodeps Ghostgum beginlabel endlabel pTick ptick loggrid SAS dy @c LocalWords: currentprojection latticeshading subpictures colinear unitcube @c LocalWords: Autoscaling solveQuadratic MidArrow MidArcArrow Prebuilt url @c LocalWords: pdftex comment getstring getstringprefix getreal defaultS hsv @c LocalWords: ticklocate autoscaleT autoscaling vectorfield autolimits dvi @c LocalWords: zlimits inline dvipdf hyperdvi autoconf gui zerowindingoverlap @c LocalWords: prepended intMax quadraticroots cubicroots filltype prepend dx @c LocalWords: ticklabel popup UnFill markroutine marknodes markuniform erf @c LocalWords: intersectpoint cyrillic mathtext russian brokenaxis Datadir ds @c LocalWords: resetdefaultpen latticeshade axialshade radialshade erfc det @c LocalWords: gouraudshade unescaped nmesh surfacepen getpair MikTeX dw YZ @c LocalWords: meshpen localhistory axisT roundedpath unitsize aSin accel pre @c LocalWords: fontcommand makepen aCos aTan Knorr roundpath BeginPoint nView @c LocalWords: MidPoint EndPoint nmask antialiasing autoplain batchMask libgc @c LocalWords: batchView clearGUI ignoreGUI interactiveMask interactiveView @c LocalWords: listvariables outformat parseonly prepending psviewer nCircle @c LocalWords: pdfviewer papertype tabcompletion noautoplain plugins Teixeira @c LocalWords: embeddedmovie historylines RadialShade penc penr CJK tgz GPL @c LocalWords: legendlinelength legendskip USERPROFILE LDFLAGS currentlight @c LocalWords: subsampled sinc kai AtBeginDocument GBK clearpage lasy texpath @c LocalWords: AtEndDocument zaxis maxbound truepoint paperwidth paperheight @c LocalWords: GSL deriv texcolors fixedscaling UpsideDown texreset slidedemo @c LocalWords: subitem newslide realMin realMax realEpsilon realDigits gsl dh @c LocalWords: obliqueX asycolors monthaxis xautoscale yautoscale zautoscale @c LocalWords: obliqueZ obliqueY cylinderskeleton block llcorner dr py nx CPU @c LocalWords: loc topleft topright bottomleft bottomright flowrectangle UTC @c LocalWords: chartblock flowdiamond flowcircle xlabel BezierSurface el xyz @c LocalWords: flowroundrectangle flowbevel flowpath drawflow blocks ny cpu @c LocalWords: multipleView usersetting mediumgray flowchartdemo ylabel nv xf @c LocalWords: zlabel slopefields cputime roundrectangle slopefield libgccpp @c LocalWords: tickfactor USERNAME writeable imagecontour logimage Dumoulin's @c LocalWords: NoCrop parametricsurface realmult SoftLight HardLight interp @c LocalWords: ColorDodge ColorBurn Ivaldi buildcycle autorotate mexicanhat @c LocalWords: Gouraudcontour pdflatex preconfigured perline linelength hskip @c LocalWords: penimage filloutside legendhskip legendvskip maxwidth CDlabel @c LocalWords: tensorshade MPEG framepoint nonfunction Radoslav Marinov Mepis @c LocalWords: Pienaar Melenchuk finalout Linspire Dpkg sudo dpkg dtx Tcount @c LocalWords: windingnumber clickable pdfmovie dfn du animationdelay fprime @c LocalWords: slidemovies ifdraft embeddedu externalmovie headerpen bodypen @c LocalWords: GaussianSurface multiline binarytree tridiagonal portably AIX @c LocalWords: binarytreetest Henning subsample breakpoint locator wireframe @c LocalWords: labelpath intersectionpoints PSTricks pstextpath curvedlabel @c LocalWords: LeftJustified RightJustified tickmodifier gunzip gmake IRIX dv @c LocalWords: texcommand RET SITEDIR filegraph pathmarkers POSIX binput AOB @c LocalWords: nonportable markinterval stickframe circlebarframe tix @c LocalWords: crossframe tildeframe markangle StickIntervalMarker gswin expm @c LocalWords: CrossIntervalMarker CircleBarIntervalMarker Ghostscript syzygy @c LocalWords: TildeIntervalMarker autoimport calculateTransform bitwise tk @c LocalWords: headersize bodysize minheaderwidth minheaderheight minwidth ZX @c LocalWords: minbodywidth minbodyheight minheight mindiameter reltime PNG @c LocalWords: relpoint Syzygy syzygies seekeof splinetype notaknot slopea ZY @c LocalWords: slopeb nonperiodic circlescale MarkFill ScaleX ScaleY xformat @c LocalWords: onecontour multicontour irregularcontour dvipsOptions saveline @c LocalWords: dirSpecifier controlSpecifier tensionSpecifier atleastflag bsp @c LocalWords: curlSpecifier cputimeformat initializers arbitary redeclaring @c LocalWords: firstname lastname multdiagonal Raphson OmitTick OmitFormat sp @c LocalWords: NoZero NoZeroFormat abbrevation gsOptions namespace redeclared @c LocalWords: atLeast intMin globalwrite quarticroots deconsruct substrings @c LocalWords: usleep currentpatterns trailingzero Orest Shardt DefaultHead @c LocalWords: SimpleHead HookHead TeXHead multipage NURBS inlinemovie dxmax @c LocalWords: simpson NoBox truesize autoscale shadestroke recurses mintimes @c LocalWords: nonoverlapping texengine maxtimes maxheight pdb TEXMFCONFIG Jn @c LocalWords: piecewisestraight unitrand graphmarkers antialias nolight newl @c LocalWords: Delaunay Shewchuk convertOptions APPDATA pdfreload tempFile Yn @c LocalWords: pdfreloadOptions deferred OpenGL Phong Blinn renderer unitbox @c LocalWords: bezulate Shardt's rasterized viewport unitdisk unitplane devel @c LocalWords: unitcylinder unitcone solidcone unitfrustum unitsphere nslices @c LocalWords: DPostScript YZZero externalprc nonrendered nosafe KDE @c LocalWords: unithemisphere versa XYplane xypart unitsolidcone YZEquals xml @c LocalWords: XZEquals XYEquals XZZero XYZero InTicks OutTicks InOutTicks @c LocalWords: fitscreen planeproject strokepath meshlight nullpens arrowdir @c LocalWords: diffusepen ambientpen emissivepen specularpen arrowbarb keyval @c LocalWords: hstretch vstretch roundbox nonconvex miterlimit basealigin cmd @c LocalWords: maxviewport maxtile antialiased sphericalharmonic attachfile @c LocalWords: vertexshading smoothelevation glOptions iconified iconify kate @c LocalWords: psviewerOptions pdfviewerOptions viewportmargin asyattach SVG @c LocalWords: multisampling autogen multisample coloredpath relstep flowdir @c LocalWords: colortype coloredSegments coloredNodes trefoilknot scaledgraph @c LocalWords: minblockwidth minblockheight mincirclediameter nonassociative @c LocalWords: nonintegral gettriple enablerepo hexidecimal XeLaTeX xelatex @c LocalWords: dvipdfmx autoadjust viewportsize viewportwidth viewportheight @c LocalWords: subregions nonsimply functionshade shader floatingdisk TopView @c LocalWords: functionshading maxlength LeftView odetest RadialShadeDraw CLZ @c LocalWords: vectorfieldsphere RightView FrontView BackView BottomView CTZ @c LocalWords: addViews outprefix addAllViews xsplinetype ysplinetype rotateX @c LocalWords: usplinetype vsplinetype leftbutton middlebutton rightbutton @c LocalWords: rotateY rotateZ wheelup zoomin wheeldown zoomout TeXLive pnorm @c LocalWords: viewportshift signedint signedness psview multiplatform nowarn @c LocalWords: singlereal singleint writeoverloaded dvisvg reddash lexorder @c LocalWords: bigdiagonal autobillboard dvisvgm maxtiles hyperrefOptions xdr @c LocalWords: setpagesize pdfborder controlsystem OmitTickInterval SixViews @c LocalWords: OmitTickIntervals tickmodifiers autorotated SixViewsUS latexmk @c LocalWords: ThreeViewsUS ThreeViewsFR SixViewsFR ThreeViews partialsum @c LocalWords: defaultrender Vidiassov latexmkrc mktemp DOSendl DOSnewl perl @c LocalWords: filename asyinclude latemk penfunctionimage Affine decrement @c LocalWords: affine Redisplay redisplay isnan radians defaultseparator Jens @c LocalWords: ascii piecewise arcpoint spacings tilings sncndn resizing @c LocalWords: differentiable vectorization vectorized asydir normals quartic @c LocalWords: wavepacket kerned parametrized specular hyperboloid Bourke's @c LocalWords: Michail 0pt 1filll 's 3D latin1 labelpath3 2D graph3 @c LocalWords: grid3 contour3 i386 psv a4 gsview32 freeglut 'load ' @c LocalWords: 'asy 'lasy 'auto 5bp 1cm sqrtx01 4g extenda extendb @c LocalWords: bb llx 2S 100pt 3t bezier2 bool3 x0 angle1 angle2 z1 @c LocalWords: z2 before' struct X11 x11colors type1cm 12pt OT1 5mm @c LocalWords: cmr12 x' y' xsize ysize 25cm s1 s2 neighbourhood u'' @c LocalWords: s'' 3x 5x 3y 602e 2x 2y 3sin 10cm 204e addby7 10x Ai @c LocalWords: only'' pow10 log10 expm1 log1p atan2 0pt 1filll 's ' @c LocalWords: x1 x2 graph2d attachfile2 n0 P0 n1 P1 markers1 3D 2D @c LocalWords: interpolate1 markers2 inlinemovie3 media9 U3D T2A 5E @c LocalWords: embeddedu3d curvedlabel3 value2 tickvalue inner'' 2N @c LocalWords: lineargraph0 scalings log2 log2graph 5cm BWRainbow2 @c LocalWords: guide3 path3 unitcircle3 2E 2n noV 100d PostScript3D @c LocalWords: size3 fit3 theta1 phi1 theta2 phi2 v1 v2 unitsquare3 @c LocalWords: t1 t2 5z 5y transform3 identity4 xscale3 yscale3 0pt @c LocalWords: zscale3 scale3 join3 BeginBar3 EndBar3 Bar3 Bars3 's @c LocalWords: BeginArrow3 MidArrow3 EndArrow3 Arrow3 Arrows3 axes3 @c LocalWords: BeginArcArrow3 MidArcArrow3 EndArcArrow3 ArcArrow3 ' @c LocalWords: ArcArrows3 DefaultHead3 HookHead3 TeXHead3 HookHead2 @c LocalWords: DefaultHead2 TeXHead2 arrows3 NoMargin3 BeginMargin3 @c LocalWords: EndMargin3 Margin3 Margins3 BeginPenMargin2 xaxis3 ' @c LocalWords: EndPenMargin2 PenMargin2 PenMargins2 BeginPenMargin3 @c LocalWords: EndPenMargin3 PenMargin3 PenMargins3 BeginDotMargin3 @c LocalWords: EndDotMargin3 DotMargin3 DotMargins3 TrueMargin3 3D @c LocalWords: yaxis3 zaxis3 ticks3 NoTicks3 arrowbar3 type2 axis3 @c LocalWords: generalaxis3 vectorfield3 margin3 grid3xyz 5unit 2D @c LocalWords: slopefield1 144x144 1filll 'load 'asy 'lasy 'auto 4g @c LocalWords: libgs 'load 'asy 'lasy 'auto 5bp 1cm 2S 100pt 3t 5mm @c LocalWords: bracedefaultratio incircle 12pt 25cm 3x 5x 3y 602e ' @c LocalWords: 2x 2y 3sin 10cm 204e 10x Ai 5E offaxis 'load 'lasy ' @c LocalWords: 5cm 2N 2E 2n 100d 5z 5y 5unit dvisvgmOptions 144x144 @c LocalWords: 4g texengines coplanar 0pt 1filll 's 3D 2D 'load 5bp @c LocalWords: insphere cospherical 5unit luatex lualatex 'asy 1cm @c LocalWords: 'lasy 'auto 4g 2S 100pt 3t 12pt 5mm 25cm 3x 5x 3y 2x @c LocalWords: 602e 2y 3sin 10cm 204e 10x Ai Ai Ai Ai Ai Ai Ai Ai ' @c LocalWords: unnormalized 5E 5cm 2N 2E 2n 100d 5z 5y 0pt 1filll @c LocalWords: 5unit 144x144 aligndir smoothcontour3 's 3D 2D cmake @c LocalWords: 'load 'asy 'lasy 'auto 5bp 1cm 4g 2S 100pt 3t nan 3x @c LocalWords: 12pt 5mm 25cm 5x 3y 602e 2x 2y 3sin 10cm 204e 10x Ai @c LocalWords: Ai Ai Ai Ai Ai Ai Ai 5E 5cm 2N 2E 2n 100d 5z 5y nz @c LocalWords: 5unit Staats implicitsurface overlapedges maxdepth @c LocalWords: through'' genustwo 144x144 asymptote-2.37/doc/axis3.asy000066400000000000000000000003661265434602500160200ustar00rootroot00000000000000import graph3; size(0,200); size3(200,IgnoreAspect); currentprojection=perspective(5,2,2); scale(Linear,Linear,Log); xaxis3("$x$",0,1,red,OutTicks(2,2)); yaxis3("$y$",0,1,red,OutTicks(2,2)); zaxis3("$z$",1,30,red,OutTicks(beginlabel=false)); asymptote-2.37/doc/bezier.asy000066400000000000000000000001211265434602500162360ustar00rootroot00000000000000label("$(1-t)^3z_0+3t(1-t)^2c_0+3t^2(1-t)c_1+t^3z_1\qquad 0\le t\le 1$.",(0,0)); asymptote-2.37/doc/bezier2.asy000066400000000000000000000006401265434602500163260ustar00rootroot00000000000000import beziercurve; pair midpoint(pair a, pair b) {return interp(a,b,0.5);} pair m0=midpoint(z0,c0); pair m1=midpoint(c0,c1); pair m2=midpoint(c1,z1); draw(m0--m1--m2,dashed); dot("$m_0$",m0,NW,red); dot("$m_1$",m1,N,red); dot("$m_2$",m2,red); pair m3=midpoint(m0,m1); pair m4=midpoint(m1,m2); pair m5=midpoint(m3,m4); draw(m3--m4,dashed); dot("$m_3$",m3,NW,red); dot("$m_4$",m4,NE,red); dot("$m_5$",m5,N,red); asymptote-2.37/doc/beziercurve.asy000066400000000000000000000003521265434602500173110ustar00rootroot00000000000000size(400); pair z0=(0,0); pair c0=(1,1); pair c1=(2,1); pair z1=(3,0); draw(z0..controls c0 and c1 .. z1,blue); draw(z0--c0--c1--z1,dashed); dot("$z_0$",z0,W,red); dot("$c_0$",c0,NW,red); dot("$c_1$",c1,NE,red); dot("$z_1$",z1,red); asymptote-2.37/doc/bigdiagonal.asy000066400000000000000000000000511265434602500172200ustar00rootroot00000000000000size(0,100.5); draw((0,0)--(2,1),Arrow); asymptote-2.37/doc/binarytreetest.asy000066400000000000000000000004621265434602500200320ustar00rootroot00000000000000import binarytree; picture pic,pic2; binarytree bt=binarytree(1,2,4,nil,5,nil,nil,0,nil,nil,3,6,nil,nil,7); draw(pic,bt,condensed=false); binarytree st=searchtree(10,5,2,1,3,4,7,6,8,9,15,13,12,11,14,17,16,18,19); draw(pic2,st,blue,condensed=true); add(pic.fit(),(0,0),10N); add(pic2.fit(),(0,0),10S); asymptote-2.37/doc/brokenaxis.asy000066400000000000000000000010141265434602500171250ustar00rootroot00000000000000import graph; size(200,150,IgnoreAspect); // Break the x axis at 3; restart at 8: real a=3, b=8; // Break the y axis at 100; restart at 1000: real c=100, d=1000; scale(Broken(a,b),BrokenLog(c,d)); real[] x={1,2,4,6,10}; real[] y=x^4; draw(graph(x,y),red,MarkFill[0]); xaxis("$x$",BottomTop,LeftTicks(Break(a,b))); yaxis("$y$",LeftRight,RightTicks(Break(c,d))); label(rotate(90)*Break,(a,point(S).y)); label(rotate(90)*Break,(a,point(N).y)); label(Break,(point(W).x,ScaleY(c))); label(Break,(point(E).x,ScaleY(c))); asymptote-2.37/doc/colo-asy.tex000066400000000000000000000103741265434602500165230ustar00rootroot00000000000000%D \module %D [ file=colo-asy, %D version=2009.05.20, %D title=\CONTEXT\ Color Macros, %D subtitle=\asymptote\ Colors, %D author=\asymptote\ developers, %D date=\currentdate, %D copyright={put something here}] %C %C any copyright notice may go here % call with \setupcolor[asy] \definecolor [cyan] [c=1.00,m=0.00,y=0.00,k=0.00] \definecolor [magenta] [c=0.00,m=1.00,y=0.00,k=0.00] \definecolor [yellow] [c=0.00,m=0.00,y=1.00,k=0.00] \definecolor [black] [c=0.00,m=0.00,y=0.00,k=1.00] \definecolor [white] [c=0.00,m=0.00,y=0.00,k=0.00] \definecolor [gray] [c=0.00,m=0.00,y=0.00,k=0.50] \definecolor [red] [c=0.00,m=1.00,y=1.00,k=0.00] \definecolor [green] [c=1.00,m=0.00,y=1.00,k=0.00] \definecolor [blue] [c=1.00,m=1.00,y=0.00,k=0.00] \definecolor [palered] [c=0.00,m=0.25,y=0.25,k=0.00] \definecolor [palegreen] [c=0.25,m=0.00,y=0.25,k=0.00] \definecolor [paleblue] [c=0.25,m=0.25,y=0.00,k=0.00] \definecolor [palecyan] [c=0.25,m=0.00,y=0.00,k=0.00] \definecolor [palemagenta] [c=0.00,m=0.25,y=0.00,k=0.00] \definecolor [paleyellow] [c=0.00,m=0.00,y=0.25,k=0.00] \definecolor [palegray] [c=0.00,m=0.00,y=0.00,k=0.05] \definecolor [lightred] [c=0.00,m=0.50,y=0.50,k=0.00] \definecolor [lightgreen] [c=0.50,m=0.00,y=0.50,k=0.00] \definecolor [lightblue] [c=0.50,m=0.50,y=0.00,k=0.00] \definecolor [lightcyan] [c=0.50,m=0.00,y=0.00,k=0.00] \definecolor [lightmagenta] [c=0.00,m=0.50,y=0.00,k=0.00] \definecolor [lightyellow] [c=0.00,m=0.00,y=0.50,k=0.00] \definecolor [lightgray] [c=0.00,m=0.00,y=0.00,k=0.10] \definecolor [mediumred] [c=0.00,m=0.75,y=0.75,k=0.00] \definecolor [mediumgreen] [c=0.75,m=0.00,y=0.75,k=0.00] \definecolor [mediumblue] [c=0.75,m=0.75,y=0.00,k=0.00] \definecolor [mediumcyan] [c=0.75,m=0.00,y=0.00,k=0.00] \definecolor [mediummagenta] [c=0.00,m=0.75,y=0.00,k=0.00] \definecolor [mediumyellow] [c=0.00,m=0.00,y=0.75,k=0.00] \definecolor [mediumgray] [c=0.00,m=0.00,y=0.00,k=0.25] \definecolor [heavyred] [c=0.00,m=1.00,y=1.00,k=0.25] \definecolor [heavygreen] [c=1.00,m=0.00,y=1.00,k=0.25] \definecolor [heavyblue] [c=1.00,m=1.00,y=0.00,k=0.25] \definecolor [heavycyan] [c=1.00,m=0.00,y=0.00,k=0.25] \definecolor [heavymagenta] [c=0.00,m=1.00,y=0.00,k=0.25] \definecolor [lightolive] [c=0.00,m=0.00,y=1.00,k=0.25] \definecolor [heavygray] [c=0.00,m=0.00,y=0.00,k=0.75] \definecolor [deepred] [c=0.00,m=1.00,y=1.00,k=0.50] \definecolor [deepgreen] [c=1.00,m=0.00,y=1.00,k=0.50] \definecolor [deepblue] [c=1.00,m=1.00,y=0.00,k=0.50] \definecolor [deepcyan] [c=1.00,m=0.00,y=0.00,k=0.50] \definecolor [deepmagenta] [c=0.00,m=1.00,y=0.00,k=0.50] \definecolor [olive] [c=0.00,m=0.00,y=1.00,k=0.50] \definecolor [deepgray] [c=0.00,m=0.00,y=0.00,k=0.90] \definecolor [darkred] [c=0.00,m=1.00,y=1.00,k=0.75] \definecolor [darkgreen] [c=1.00,m=0.00,y=1.00,k=0.75] \definecolor [darkblue] [c=1.00,m=1.00,y=0.00,k=0.75] \definecolor [darkcyan] [c=1.00,m=0.00,y=0.00,k=0.75] \definecolor [darkmagenta] [c=0.00,m=1.00,y=0.00,k=0.75] \definecolor [darkolive] [c=0.00,m=0.00,y=1.00,k=0.75] \definecolor [darkgray] [c=0.00,m=0.00,y=0.00,k=0.95] \definecolor [orange] [c=0.00,m=0.50,y=1.00,k=0.00] \definecolor [fuchsia] [c=0.00,m=1.00,y=0.50,k=0.00] \definecolor [chartreuse] [c=0.50,m=0.00,y=1.00,k=0.00] \definecolor [springgreen] [c=1.00,m=0.00,y=0.50,k=0.00] \definecolor [purple] [c=0.50,m=1.00,y=0.00,k=0.00] \definecolor [royalblue] [c=1.00,m=0.50,y=0.00,k=0.00] \definecolor [salmon] [c=0.00,m=0.50,y=0.50,k=0.00] \definecolor [brown] [c=0.00,m=1.00,y=1.00,k=0.50] \definecolor [darkbrown] [c=0.00,m=1.00,y=1.00,k=0.75] \definecolor [pink] [c=0.00,m=0.25,y=0.00,k=0.00] \definecolor [palegrey] [c=0.00,m=0.00,y=0.00,k=0.05] \definecolor [lightgrey] [c=0.00,m=0.00,y=0.00,k=0.10] \definecolor [mediumgrey] [c=0.00,m=0.00,y=0.00,k=0.25] \definecolor [grey] [c=0.00,m=0.00,y=0.00,k=0.50] \definecolor [heavygrey] [c=0.00,m=0.00,y=0.00,k=0.50] \definecolor [deepgrey] [c=0.00,m=0.00,y=0.00,k=0.90] \definecolor [darkgrey] [c=0.00,m=0.00,y=0.00,k=0.95] asymptote-2.37/doc/colons.asy000066400000000000000000000000611265434602500162560ustar00rootroot00000000000000draw((0,0){up}::(100,25){right}::(200,0){down}); asymptote-2.37/doc/colors.asy000066400000000000000000000031241265434602500162650ustar00rootroot00000000000000int i=0; int j=0; bool components=false; pen p; void col(... string[] s) { for(int n=0; n < s.length; ++n) { j -= 10; string s=s[n]; eval("p="+s+";",true); if(components) { real[] a=colors(p); for(int i=0; i < a.length; ++i) s += " "+(string) a[i]; } label(s,(i+10,j),E); filldraw(box((i,j-5),(i+10,j+5)),p); } } col("palered"); col("lightred"); col("mediumred"); col("red"); col("heavyred"); col("brown"); col("darkbrown"); j -= 10; col("palegreen"); col("lightgreen"); col("mediumgreen"); col("green"); col("heavygreen"); col("deepgreen"); col("darkgreen"); j -= 10; col("paleblue"); col("lightblue"); col("mediumblue"); col("blue"); col("heavyblue"); col("deepblue"); col("darkblue"); j -= 10; i += 150; j=0; col("palecyan"); col("lightcyan"); col("mediumcyan"); col("cyan"); col("heavycyan"); col("deepcyan"); col("darkcyan"); j -= 10; col("pink"); col("lightmagenta"); col("mediummagenta"); col("magenta"); col("heavymagenta"); col("deepmagenta"); col("darkmagenta"); j -= 10; col("paleyellow"); col("lightyellow"); col("mediumyellow"); col("yellow"); col("lightolive"); col("olive"); col("darkolive"); j -= 10; col("palegray"); col("lightgray"); col("mediumgray"); col("gray"); col("heavygray"); col("deepgray"); col("darkgray"); j -= 10; i += 150; j=0; col("black"); col("white"); j -= 10; col("orange"); col("fuchsia"); j -= 10; col("chartreuse"); col("springgreen"); j -= 10; col("purple"); col("royalblue"); j -= 10; col("Cyan"); col("Magenta"); col("Yellow"); col("Black"); j -= 10; col("cmyk(red)"); col("cmyk(blue)"); col("cmyk(green)"); asymptote-2.37/doc/cube.asy000066400000000000000000000003631265434602500157040ustar00rootroot00000000000000import three; currentprojection=orthographic(5,4,2,center=true); size(5cm); size3(3cm,5cm,8cm); draw(unitbox); dot(unitbox,red); label("$O$",(0,0,0),NW); label("(1,0,0)",(1,0,0),S); label("(0,1,0)",(0,1,0),E); label("(0,0,1)",(0,0,1),Z); asymptote-2.37/doc/cylinderskeleton.asy000066400000000000000000000001261265434602500203410ustar00rootroot00000000000000import solids; size(0,100); revolution r=cylinder(O,1,1.5,Y+Z); draw(r,heavygreen); asymptote-2.37/doc/datagraph.asy000066400000000000000000000003321265434602500167150ustar00rootroot00000000000000import graph; size(200,150,IgnoreAspect); real[] x={0,1,2,3}; real[] y=x^2; draw(graph(x,y),red); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight, RightTicks(Label(fontsize(8pt)),new real[]{0,4,9})); asymptote-2.37/doc/diagonal.asy000066400000000000000000000000301265434602500165330ustar00rootroot00000000000000draw((0,0)--(100,100)); asymptote-2.37/doc/diatom.asy000066400000000000000000000055021265434602500162430ustar00rootroot00000000000000import graph; size(15cm,12cm,IgnoreAspect); real minpercent=20; real ignorebelow=0; string data="diatom.csv"; string[] group; int[] begin,end; defaultpen(fontsize(8pt)+overwrite(MoveQuiet)); file in=input(data).line().csv(); string depthlabel=in; string yearlabel=in; string[] taxa=in; group=in; begin=in; real[] depth; int[] year; real[][] percentage; while(true) { real d=in; if(eof(in)) break; depth.push(d); year.push(in); percentage.push(in); } percentage=transpose(percentage); real depthmin=-min(depth); real depthmax=-max(depth); int n=percentage.length; int final; for(int taxon=0; taxon < n; ++taxon) { real[] P=percentage[taxon]; if(max(P) < ignorebelow) continue; final=taxon; } real angle=45; real L=3cm; pair Ldir=L*dir(angle); real ymax=-infinity; real margin=labelmargin(); real location=0; for(int i=0; i < begin.length-1; ++i) end[i]=begin[i+1]-1; end[begin.length-1]=n-1; typedef void drawfcn(frame f); drawfcn[] draw=new drawfcn[begin.length]; pair z0; for(int taxon=0; taxon < n; ++taxon) { real[] P=percentage[taxon]; real maxP=max(P); if(maxP < ignorebelow) continue; picture pic; real x=1; if(maxP < minpercent) x=minpercent/maxP; if(maxP > 100) x=50/maxP; scale(pic,Linear(true,x),Linear(-1)); filldraw(pic,(0,depthmin)--graph(pic,P,depth)--(0,depthmax)--cycle, gray(0.9)); xaxis(pic,Bottom,LeftTicks("$%.3g$",beginlabel=false,0,2),above=true); xaxis(pic,Top,above=true); frame label; label(label,rotate(angle)*TeXify(taxa[taxon]),(0,0),N); pair z=point(pic,N); pair v=max(label); int taxon=taxon; pic.add(new void(frame f, transform t) { pair z1=t*z+v; ymax=max(ymax,z1.y+margin); }); for(int i=0; i < begin.length; ++i) { pair z=point(pic,N); pair v=max(label); if(taxon == begin[i]) { pic.add(new void(frame f, transform t) { pair Z=t*z+v; z0=Z; pair w0=Z+Ldir; }); } else if(taxon == end[i]) { int i=i; pair align=2N; pic.add(new void(frame, transform t) { pair z0=z0; pair z1=t*z+v; pair w1=z1+Ldir; draw[i]=new void(frame f) { path g=z0--(z0.x+(ymax-z0.y)/Tan(angle),ymax)-- (z1.x+(ymax-z1.y)/Tan(angle),ymax)--z1; draw(f,g); label(f,group[i],point(g,1.5),align); }; }); } } add(pic,label,point(pic,N)); if(taxon == 0) yaxis(pic,depthlabel,Left,RightTicks(0,10),above=true); if(taxon == final) yaxis(pic,Right,LeftTicks("%",0,10),above=true); add(shift(location,0)*pic); location += pic.userMax().x; } add(new void(frame f, transform) { for(int i=0; i < draw.length; ++i) draw[i](f); }); for(int i=0; i < year.length; ++i) if(year[i] != 0) label((string) year[i],(location,-depth[i]),E); label("\%",(0.5*location,point(S).y),5*S); asymptote-2.37/doc/diatom.csv000066400000000000000000000077431265434602500162530ustar00rootroot00000000000000"sediment depth (cm)","year","Achnanthes minutissima Kuetzing","Anomoeoneis vitrea (Grunow) Ross","Asterionella formosa Hassall","Tabellaria flocculosa (Roth) Kuetzing","Fragilaria cf. tenera","Chaetoceros muelleri/elmorei cysts","Aulacoseira spp. ","Fragilaria capucina var. vaucheriae (Kuetzing)","Fragilaria crotonensis Kitton" "A","B","C" 0,4,6 0,2000,11.6959064327485,9.55165692007797,49.6101364522417,1.364522417154,0,0.974658869395711,0,2.14424951267057,4.09356725146199 10,1998,20.2676864244742,11.2810707456979,34.7992351816444,2.39005736137667,0,0.191204588910134,0.573613766730402,0.382409177820268,7.55258126195029 20,1996,21.1282051282051,33.6410256410256,24,2.35897435897436,0.615384615384615,0,0.205128205128205,0.615384615384615,2.56410256410256 30,1994,25.7620452310718,21.0422812192724,31.3667649950836,2.16322517207473,0.393313667649951,0.393313667649951,0.196656833824975,1.76991150442478,3.73647984267453 40,1992,21.0422812192724,16.5191740412979,42.9695181907571,0.589970501474926,0,0.983284169124877,0.589970501474926,0.393313667649951,1.96656833824975 50,1990,23.1067961165049,24.0776699029126,29.126213592233,1.35922330097087,0,0.970873786407767,0.388349514563107,0.58252427184466,3.30097087378641 60,1988,35.0738916256158,33.3004926108374,4.33497536945813,1.37931034482759,0.591133004926108,1.97044334975369,1.18226600985222,0.985221674876847,2.75862068965517 70,1986,42.2090729783037,33.7278106508876,2.26824457593688,1.38067061143984,0.788954635108481,1.18343195266272,0.591715976331361,1.38067061143984,3.25443786982249 90,1984,34.5098039215686,41.9607843137255,0.196078431372549,2.15686274509804,0.588235294117647,2.74509803921569,0.588235294117647,2.15686274509804,0 95,1982,38.0487804878049,45.4634146341463,0.487804878048781,0.975609756097561,0.975609756097561,0,0.390243902439024,0.390243902439024,0 110,1980,40.1860465116279,41.4883720930233,1.30232558139535,0.837209302325581,0,0.930232558139535,0.372093023255814,0.372093023255814,1.3953488372093 130,1978,39.6501457725948,42.1768707482993,0.291545189504373,0.194363459669582,2.72108843537415,1.55490767735666,0,1.36054421768707,0.777453838678329 150,1972,32.6298701298701,31.4935064935065,1.86688311688312,1.78571428571429,0.162337662337662,13.961038961039,0.162337662337662,1.94805194805195,1.86688311688312 170,1970,30.7692307692308,47.534516765286,0.986193293885602,3.35305719921105,0.19723865877712,1.38067061143984,0,1.18343195266272,0.591715976331361 190,1965,40.5268490374873,37.8926038500507,1.82370820668693,2.63424518743668,0,1.21580547112462,0.405268490374873,1.21580547112462,1.01317122593718 260,1961,40.4494382022472,26.0299625468165,0.468164794007491,1.31086142322097,0.561797752808989,8.05243445692884,0,3.74531835205992,0.374531835205993 280,1950,44.946025515211,11.9725220804711,0.294406280667321,0.785083415112856,16.48675171737,1.96270853778214,0.392541707556428,2.35525024533857,0 290,1942,41.2818096135721,8.29406220546654,0.188501413760603,0.282752120640905,28.6522148916117,0.942507068803016,0.377002827521206,4.33553251649387,0 300,1940,18.0995475113122,12.3076923076923,0,0.180995475113122,40.3619909502262,5.61085972850679,0,2.35294117647059,0 310,1920,28.6844708209693,11.2759643916914,0.593471810089021,3.26409495548961,13.0563798219585,13.2542037586548,0.19782393669634,9.89119683481701,0.989119683481701 320,1915,6.17977528089888,1.31086142322097,4.30711610486891,6.74157303370787,32.7715355805243,34.4569288389513,1.31086142322097,2.62172284644195,0 330,1910,4.03846153846154,0.769230769230769,14.5192307692308,36.4423076923077,5,0.769230769230769,11.1538461538462,0,2.11538461538462 340,1888,7.37148399612027,1.1639185257032,9.40834141610087,31.8137730358875,1.1639185257032,0.969932104752667,14.3549951503395,0.193986420950533,0.969932104752667 400,1763,2.69749518304432,0.192678227360308,24.8554913294798,26.7822736030829,0.385356454720617,2.69749518304432,20.0385356454721,0,1.54142581888247 450,1726,2.37859266600595,0.396432111000991,9.71258671952428,28.5431119920714,0.198216055500496,0.594648166501487,30.5252725470763,0,0.792864222001982 asymptote-2.37/doc/dots.asy000066400000000000000000000000611265434602500157320ustar00rootroot00000000000000draw((0,0){up}..(100,25){right}..(200,0){down}); asymptote-2.37/doc/eetomumu.asy000066400000000000000000000020331265434602500166220ustar00rootroot00000000000000import feynman; // set default line width to 0.8bp currentpen = linewidth(0.8); // scale all other defaults of the feynman module appropriately fmdefaults(); // define vertex and external points real L = 50; pair zl = (-0.75*L,0); pair zr = (+0.75*L,0); pair xu = zl + L*dir(+120); pair xl = zl + L*dir(-120); pair yu = zr + L*dir(+60); pair yl = zr + L*dir(-60); // draw propagators and vertices drawFermion(xu--zl); drawFermion(zl--xl); drawPhoton(zl--zr); drawFermion(yu--zr); drawFermion(zr--yl); drawVertex(zl); drawVertex(zr); // draw momentum arrows and momentum labels drawMomArrow(xl--zl, Relative(left)); label(Label("$k'$",2RightSide), xl--zl); label(Label("$k$",2LeftSide), xu--zl); drawMomArrow(zl--zr, Relative(left)); label(Label("$q$",2RightSide), zl--zr); drawMomArrow(zr--yu, Relative(right)); label(Label("$p'$",2LeftSide), zr--yu); label(Label("$p$",2RightSide), zr--yl); // draw particle labels label("$e^-$", xu, left); label("$e^+$", xl, left); label("$\mu^+$", yu, right); label("$\mu^-$", yl, right); asymptote-2.37/doc/elliptic.asy000066400000000000000000000037671265434602500166060ustar00rootroot00000000000000struct curve { real a=0; real b=8; real y2(real x) { return x^3+a*x+b; } real disc() { return -16*(4*a*a*a+27*b*b); } real lowx () { return sqrt(-a/3); } int comps() { if (a < 0) { real x=sqrt(-a/3); return y2(x) < 0 ? 2 : 1; } return 1; } void locus(picture pic=currentpicture, real m, real M, int n=100, pen p=currentpen) { path flip(path p, bool close) { path pp=reverse(yscale(-1)*p)..p; return close ? pp..cycle : pp; } path section(real m, real M, int n) { guide g; real width=(M-m)/n; for(int i=0; i <= n; ++i) { real x=m+width*i; real yy=y2(x); if (yy > 0) g=g..(x,sqrt(yy)); } return g; } if (comps() == 1) { draw(pic,flip(section(m,M,n),false),p); } else { real x=lowx(); // The minimum on x^3+ax+b if (m < x) draw(pic,flip(section(m,min(x,M),n),true),p); if (x < M) draw(pic,flip(section(max(x,m),M,n),false),p); } } pair neg(pair P) { return finite(P.y) ? yscale(-1)*P : P; } pair add(pair P, pair Q) { if (P.x == Q.x && P.x != Q.x) return (0,infinity); else { real lambda=P == Q ? (3*P.x^2+a)/(2*P.y) : (Q.y-P.y)/(Q.x-P.x); real Rx=lambda^2-P.x-Q.x; return (Rx,(P.x-Rx)*lambda-P.y); } } } import graph; import math; size(0,200); curve c; c.a=-1; c.b=4; pair oncurve(real x) { return (x,sqrt(c.y2(x))); } picture output; axes(); c.locus(-4,3,.3red+.7blue); pair P=oncurve(-1),Q=oncurve(1.2); pair PP=c.add(P,P),sum=c.add(P,Q); save(); drawline(P,Q,dashed); drawline(c.neg(sum),sum,dashed); dot("$P$", P, NW); dot("$Q$", Q, SSE); dot(c.neg(sum)); dot("$P+Q$", sum, 2SW); add(output,currentpicture.fit(),(-0.5cm,0),W); restore(); save(); drawline(P,c.neg(PP),dashed); drawline(c.neg(PP),PP,dashed); dot("$P$", P, NW); dot(c.neg(PP)); dot("$2P$", PP, SW); add(output,currentpicture.fit(),(0.5cm,0),E); shipout(output); restore(); asymptote-2.37/doc/errorbars.asy000066400000000000000000000016201265434602500167640ustar00rootroot00000000000000import graph; picture pic; real xsize=200, ysize=140; size(pic,xsize,ysize,IgnoreAspect); pair[] f={(5,5),(50,20),(90,90)}; pair[] df={(0,0),(5,7),(0,5)}; errorbars(pic,f,df,red); draw(pic,graph(pic,f),"legend", marker(scale(0.8mm)*unitcircle,red,FillDraw(blue),above=false)); scale(pic,true); xaxis(pic,"$x$",BottomTop,LeftTicks); yaxis(pic,"$y$",LeftRight,RightTicks); add(pic,legend(pic),point(pic,NW),20SE,UnFill); picture pic2; size(pic2,xsize,ysize,IgnoreAspect); frame mark; filldraw(mark,scale(0.8mm)*polygon(6),green,green); draw(mark,scale(0.8mm)*cross(6),blue); draw(pic2,graph(pic2,f),marker(mark,markuniform(5))); scale(pic2,true); xaxis(pic2,"$x$",BottomTop,LeftTicks); yaxis(pic2,"$y$",LeftRight,RightTicks); yequals(pic2,55.0,red+Dotted); xequals(pic2,70.0,red+Dotted); // Fit pic to W of origin: add(pic.fit(),(0,0),W); // Fit pic2 to E of (5mm,0): add(pic2.fit(),(5mm,0),E); asymptote-2.37/doc/exp.asy000066400000000000000000000003121265434602500155540ustar00rootroot00000000000000import graph; size(150,0); real f(real x) {return exp(x);} pair F(real x) {return (x,f(x));} xaxis("$x$"); yaxis("$y$",0); draw(graph(f,-4,2,operator ..),red); labely(1,E); label("$e^x$",F(1),SE); asymptote-2.37/doc/external-proposal.html000066400000000000000000000462151265434602500206230ustar00rootroot00000000000000 Asymptote Proposal - External Modules

    Asymptote Proposal &mdash External Modules

    Overview

    External modules allow users to extend Asymptote by calling functions written in another programming language.

    Users do this by writing a .asyc file, which contains a mix of Asymptote code and code from another language, say C++. Then, a program is run which produces a .asy file and a C++ source file. The C++ file is compiled to produce a shared library file. Then, the .asy file can be imported in Asymptote to use the externally defined features.

    This spec is describes a proposed feature that has not yet been implemented. It is incomplete, and does not address all of the issues involved in implementing the feature.

    Example

    Let’s look at a simple example that shows off the main features. Asymptote currently doesn’t offer a way to read the contents of a directory. This would be useful if, say, we wanted to make a series of graphs for every .csv file in a directory.

    /*****
     * dir.asyc
     * Andy Hammerlindl 2007/09/11
     *
     * An example for the proposed external module support in Asymptote.  This reads
     * the contents of a directory via the POSIX commands.
     *
     * Example usage in asymptote:
     *   access dir;
     *   dir.entry[] entries= dir.open('.');
     *   for (dir.entry e : entries)
     *     write(e.name);
     *****/
    
    // Verbatim code will appear in the c++ or asy file (as specified) interleaved
    // in the same order as it appears here.
    verbatim c++ {
      #include <sys/types.h>
      #include <dirent.h>
      #include <errno.h>
    
      // asy.h is included by default (needed for hidden code, anyway).
      // Asymptote-specific types, such as array below, are in the asy namespace.
      using namespace asy;
    }
    
    // Define a new opaque type in asy which is internally represented by struct
    // dirent *.  This is too messy to expose to users of the module, so define
    // everything as private.
    private asytype const struct dirent *entry_t;
    
    private int entry_d_ino(entry_t e) {
      return (Int)e->d_ino;
    }
    
    private int entry_d_off(entry_t e) {
      return (Int)e->d_off;
    }
    
    private int entry_d_reclen(entry_t e) {
      return (Int)e->reclen;
    }
    
    private string entry_d_type(entry_t e) {
      return string( /*length*/ 1, e->d_type);
    }
    
    private string entry_d_name(entry_t e) {
      return string(e->d_name);
    }
    
    // Define an asy structure to expose the information.  These steps are annoying,
    // but straightforward, and not too hard to plow through.
    verbatim asy {
      struct entry {
        restricted int ino;
        restricted int off;
        restricted int reclen;
        restricted int type;
        restricted string name;
    
        void operator init(entry_t e) {
          ino=entry_d_ino(e);
          off=entry_d_off(e);
          reclen=entry_d_reclen(e);
          type=entry_d_type(e);
          name=entry_d_name(e);
        }
      }
    }
    
    
    // Given the name of a directory, return an array of entries.  Return 0
    // (a null array) on error.
    private entry_t[] base_read(string name)
    {
      DIR *dir=opendir(name.c_str());
    
      // TODO: Add standard style of error reporting.
      if (dir == NULL)
        return 0;
    
      // Create the array structure.
      // array is derived from gc, so will be automatically memory-managed.
      array *a=new array();
    
      struct dirent *entry;
      while (entry=readdir(dir))
        a->push<struct dirent *>(entry);
    
      // The loop has exited, either by error, or after reading the entire
      // directory.  Check before closedir(), in case that call resets errno.
      if (errno != 0) {
        closedir(dir);
        return 0;
      }
    
      closedir(dir);
      return a;
    }
    
    verbatim asy {
      private entry[] cleanEntries(entry_t[] raw_entries) {
        if (raw_entries) {
          entry[] entries;
          for (entry_t e : raw_entries)
            entries.push(entry(e));
          return entries;
        }
        return null;
      }
    
      entry[] read(string name) {
        return cleanEntries(base_read(name));
      }
    }
    
    

    Type Mappings

    Types in Asymptote do not directly relate to types in C++, but there is a partial mapping between them. The header file asymptote.h provides typedefs for the primitive asymptote types. For instance string in Asymptote maps to the C++ class asy::string which is a variant of std::string and real to asy::real which is a basic floating point type (probably double). Because int is a reserved word in C++, the Asymptote type int is mapped to asy::Int which is one of the basic signed numeric types in C++ (currently 64 bit). asy::pair is a class that implements complex numbers. In the first version of the external module implementation, these will be the only primitive types with mappings, but eventually all of them will be added.

    All Asymptote arrays, regardless of the cell type, are mapped to asy::array * where asy::array is a C++ class. The cells of the array are of the type asy::item which can hold any Asymptote data type. Items can be constructed from any C++ type. Once constructed, the value of an item can be retrieved by the function template<typename T> T get(const item&). Calling get on an item using the wrong type generates a runtime error.

    // Examples of using item.
    item x((asy::Int)2);
    item y(3.4);
    item z=new array;
    item w=(asy::real)3.4;
    
    cout << get<asy::Int>(x);
    cout << get<double>(y);
    
    x=y;  // x now stores a double.
    cout << get<double>(x);
    
    cout << get<asy::real>(w);
    

    The asy::array class implements, at a minimum, the methods:

    • size_t size() which returns the number of elements,
    • template <typename T> T read(size_t i) const which returns the i-th element, interpreted as being of type t.
    • template <typename T> void push(item i) adds the item to the end of the array.

    It allows access to elements of the array as items by operator[]. We may specify that asy::array be a model of the Random Access Container in the C++ Standard Template Library. It is currently implemented as a subclass of an STL vector.

    // Example of a C++ function that doubles the entries in an array of integers.
    using namespace asy;
    
    void doubler(array *a) {
      assert(a);
      size_t length=a->size();
      for (size_t i=0; i<length; ++i) {
        Int x=a->read<Int>(i);  // This is shorthand for get<Int>((*a)[i]).
        a[i]=2*x;               // The type of 2*x is also Int, so this will enter
                                // the item as the proper type.
      }
    }
    

    Users can map new Asymptote types to their own custom C++ types using Opaque Type Declarations, explained below.

    Syntactic Features

    A .asyc file is neither an asy file with some C++ in it, nor a C++ with some asy code in it. It can only contain a small number of specific constructs:

    • Comments
    • Function Definitions
    • Verbatim Code Block
    • Opaque Type Declaration

    Each component may produce code for either the .asy file, the .cc file, or both. The pieces of code produced by each construct appears in the output file in the same order as the constructs in the .asyc. For example, if a function definition occurs before a verbatim Asymptote code block, we can be sure that the function is defined and can be used in that block. Similarly, if a verbatim C++ block occurs before a function definition, then the body of the function can use features declared in the verbatim section.

    Comments

    C++/Asymptote style comments using /* */ or // are allowed at the top level. These do not affect the definition of the module, but the implementation may copy them into the .asy and .cc to help explain the resulting code.

    Verbatim Code Blocks

    Verbatim code, ie. code to be copied directly into the either the output .asy or .cc file can be specified in the .asyc file by enclosing it in a verbatim code block. This starts with the special identifier verbatim followed by either c++ or asy to specify into which file the code will be copied, and then a block of code in braces. When the .asyc file is parsed, the parser keeps track of matching open and close braces inside the verbatim code block, so that the brace at the start of the block can be matched with the one at the end. This matching process will ignore braces occuring in comments and string and character literals.

    Open issue

    It may prove to be impractical to walk through the code, matching braces. Also, this plan precludes having a verbatim block with an unbalanced number of braces which might be useful, say to start a namespace at the beginning of the C++ file, and end it at the end of the file. As such, it may be useful to have another technique. A really simple idea (with obvious drawbacks) would be to use the first closing braces that occur at the same indentation level as the verbatim keyword (assuming that the code block itself will be indented). Other alternatives are to use more complicated tokens such as %{ and %}, or the shell style <<EOF.

    Function Definitions

    A function definition given at the top level of the file (and not inside a verbatim block) looks much like a function definition in Asymptote or C++, but is actually a mix of both. The header of the function is given in Asymptote code, and defines how the function will look in the resulting Asymptote module. The body, on the other hand, is given in C++, and defines how the function is implemented in C++. As a simple example, consider:

    real sum(real x, real y=0.0) {
      return x+y;
    }

    Header

    The header of the definition gives the name, permission, return type, and parameters of the function. Because the function is defined for use in Asymptote, all of the types are given as Asymptote types.

    Permissions

    As in pure Asymptote, the function can optionally be given a private, restricted or public permission. If not specified, the permission is public by default. This is the permission that the function will have when it is part of the Asymptote module. The example of sum above specifies no permission, so it is public.

    Just as public methods such as plain.draw can be re-assigned by scripts that import the plain module, the current plan is to allow Asymptote code to modify public members of any module, including ones defined using native code. This is in contrast to builtin functions bindings, which cannot be modified.

    Return Type

    This gives the Asymptote return type of the function. This cannot be an arbitrary Asymptote type, but must one which maps to a C++ type as explained in the type mapping section above. Our example of sum gives real as a return type, which maps to the C++ type asy::real.

    Function Name

    This gives the name of the function as it will appear in the Asymptote module. In our example, the Asymptote name is sum. The name can be any Asymptote identifier, including operator names, such as operator +.

    It is important to note that the Asymptote name has no relation to the C++ name of the function, which may be something strange, such as _asy_func_modulename162. Also, the actual signature and return type of the C++ function may bear no relation to the Asymptote signature. That said, the C++ name of the function may be defined by giving the function name as asyname:cname. Then it can be referred to by other C++ code. The function will be defined with C calling convention, so that its name is not mangled.

    Formal Parameters

    The function header takes a list of formal parameters. Just as in pure Asymptote code, these can include explicit keywords, type declarations with array and functional types, and rest parameters. Just as with the return type of the function, the type of each of the parameters must map to a C++ type.

    Parameters may be given an optional Asymptote name and an optional C++ name. These may be declared in one of six ways as in the following examples:

    void f(int)
    void f(int name)
    void f(int :)
    void f(int asyname:)
    void f(int :cname)
    void f(int asyname:cname)
    

    If the parameter just contains a type, with no identifier, then it has no Asymptote name and no C++ name. If it contains a single name (with no colon), then that name is both the Asymptote and the C++ name. If it contains a colon in the place of an identifier, with an optional name in front of the colon and an optional name behind the colon, than the name in front (if given) is the Asymptote name, and the name behind (if given) is the C++ name.

    The Asymptote name can be any Asymptote identifier, including operator names, but the C++ name must be a valid C++ identifier. For instance void f(int operator +) is not allowed, as the parameter would not have a valid C++ name. The examples void f(int operator +:) and void f(int operator +:addop) are allowed.

    When called by Asymptote code, named arguments are only matched to the Asymptote names, so for example a function defined by void f(int :x, string x:y) could be called by f(x="hi mom", 4), but one defined by void f(int x, string x:y) could not.

    Each formal parameter may take a piece of code as a default value. Because the function is implemented in C++, this code must be given as C++ code. More akin to Asymptote than C++, default arguments may occur for any non-rest parameters, not just those at the end of the list, and may refer to earlier parameters in the list. Earlier parameters are refered to by their C++ names. Example:

    void drawbox(pair center, real width, real height=2*width, pen p)
    Default arguments are parsed by finding the next comma that is not part of a comment, string literal, or character constant, and is not nested inside parentheses. The C++ code between the equals-sign and the comma is taken as the expression for the default argument.

    Body

    The body of the function is written as C++ code. When the .asyc file is processed, this C++ code is copied verbatim into an actual C++ function providing the implementation. However, the actual body of the resultant C++ function may contain code other than the body provided by the user. This auxillary code could include instruction to retrieve the arguments of the function from their representation in the Asymptote virtual machine and bind them to local variables with their C++ names. It could also include initialization and finalization code for the function.

    In writing code for the function body, one can be assured that all function arguments with C++ names have been bound and are therefore usable in the code. Since all parameters must have Asymptote types that map to C++ types, the types of the paramaters in the body have the type resulting from that mapping.

    The return keyword can be used to return the result of the function (or without an expression, if the return type was declared as void). The Asymptote return type must map to a C++ type, and the expression given in the return statement will be implicitly cast to that type.

    Since the implementation will likely not use an actual return statement to return the value of the function back to the Asymptote virtual machine, the interpreter of the .asyc file may walk through the code converting return expressions into a special format in the actual implementation of the function.

    Opaque Type Declarations

    There are a number of mappings between Asymptote and C++ types builtin to the facility. For instance int maps to asy::Int and real to asy::real. Users, however, may want to reference other C++ objects in Asymptote code. This done though opaque type declarations.

    An opaque type declaration is given by an optional permission modifier, the keyword asytype, a C++ type, and an Asymptote identifier; in that order.

    // Examples
    asytype char char;
    public asytype const std::list<asy::Int> *intList;
    private asytype const struct dirert *entry_t;
    

    This declaration mapping the Asymptote identifier to the C++ type within the module. The permission of the Asymptote type is given by the permission modifier (or public if the modifier is omitted). The type is opaque, in that none of its internal structure is revealed in the Asymptote code. Like any other type, however, objects of this new type can be returned from functions, given as an arguments to functions, and stored in variables, structures and arrays.

    In many cases, such as the directory listing example at the start, it will be practical to declare the type as private, and use an Asymptote structure as a wrapper hiding the C++ implementation.

    asymptote-2.37/doc/externalprc.tex000066400000000000000000000005361265434602500173230ustar00rootroot00000000000000% Generate inline PRC images for latex with % asy -inlineimage cube -render=4 % % Generate inline PRC images for pdflatex with % asy -inlineimage cube -render=4 -tex pdflatex % \documentclass[12pt]{article} \input cube.pre \usepackage[bigfiles]{media9} \playbuttonfalse \RequirePackage{color,graphicx} \begin{document} \input cube.tex \end{document} asymptote-2.37/doc/extra/000077500000000000000000000000001265434602500153715ustar00rootroot00000000000000asymptote-2.37/doc/extra/intro.asy000066400000000000000000000610611265434602500172460ustar00rootroot00000000000000orientation=Landscape; settings.tex="pdflatex"; import slide; import three; import animate; bool long=true; usepackage("mflogo"); usersetting(); viewportsize=pagewidth-2pagemargin; // To generate bibliographic references: // asy -k intro // bibtex intro_ // asy -k intro bibliographystyle("alpha"); itempen=fontsize(22pt); defaultpen(itempen); viewportmargin=(2,2); titlepage(long ? "Asymptote: The Vector Graphics Language" : "Interactive TeX-Aware 3D Vector Graphics", "John Bowman and Andy Hammerlindl", "Department of Mathematical and Statistical Sciences\\ University of Alberta\\ %and Instituto Nacional de Matem\'atica Pura e Aplicada (IMPA) \medskip\Green{Collaborators: Orest Shardt, Michail Vidiassov}", "June 30, 2010", "http://asymptote.sf.net/intro.pdf"); title("History"); item("1979: \TeX\ and \MF\ (Knuth)"); item("1986: 2D B\'ezier control point selection (Hobby)"); item("1989: MetaPost (Hobby)"); item("2004: Asymptote"); subitem("2004: initial public release (Hammerlindl, Bowman, \& Prince)"); subitem("2005: 3D B\'ezier control point selection (Bowman)"); subitem("2008: 3D interactive \TeX\ within PDF files (Shardt \& Bowman)"); subitem("2009: 3D billboard labels that always face camera (Bowman)"); subitem("2010: 3D PDF enhancements (Vidiassov \& Bowman)"); title("Statistics (as of June, 2010)"); item("Runs under Linux/UNIX, Mac OS X, Microsoft Windows."); item("4000 downloads/month from primary\hfill\\ {\tt asymptote.sourceforge.net} site alone."); item("80\ 000 lines of low-level C++ code."); item("36\ 000 lines of high-level Asymptote code."); if(long) { title("Vector Graphics"); item("Raster graphics assign colors to a grid of pixels."); figure("pixel.pdf"); item("Vector graphics are graphics which still maintain their look when inspected at arbitrarily small scales."); asyfigure(asywrite(" picture pic; path zoombox(real h) { return box((-h,-h/2),(min(10,h),min(10,h)/2)); } frame zoom(real h, real next=0) { frame f; draw(f, (0,-100){W}..{E}(0,0), Arrow); clip(f, zoombox(h)); if(next > 0) draw(f, zoombox(next)); return scale(100/h)*f; } add(zoom(100), (0,0)); add(zoom(10), (200,0)); add(zoom(1), (400,0)); ")); } title("Cartesian Coordinates"); item("Asymptote's graphical capabilities are based on four primitive commands: {\tt draw}, {\tt label}, {\tt fill}, {\tt clip} \cite{Bowman08}"); asyfilecode("diagonal"); item("units are {\tt PostScript} {\it big points\/} (1 {\tt bp} = 1/72 {\tt inch})"); item("{\tt --} means join the points with a linear segment to create a {\it path}"); item("{\it cyclic\/} path:"); asycode(" draw((0,0)--(100,0)--(100,100)--(0,100)--cycle); "); title("Scaling to a Given Size"); item("{\tt PostScript} units are often inconvenient."); item("Instead, scale user coordinates to a specified final size:"); asyfilecode("square"); item("One can also specify the size in {\tt cm}:"); asycode(" size(3cm,3cm); draw(unitsquare); "); title("Labels"); item("Adding and aligning \LaTeX\ labels is easy:"); asycode(preamble="defaultpen(fontsize("+string(fontsize(itempen))+"));", "size(6cm); draw(unitsquare); label(\"$A$\",(0,0),SW); label(\"$B$\",(1,0),SE); label(\"$C$\",(1,1),NE); label(\"$D$\",(0,1),NW); "); title("2D B\'ezier Splines"); item("Using {\tt ..} instead of {\tt --} specifies a {\it B\'ezier cubic spline}:"); code(" draw(z0 .. controls c0 and c1 .. z1,blue); "); asyfigure(asywrite("defaultpen(fontsize("+string(fontsize(itempen))+")); size(0,7cm); pair z0=(0,0); pair c0=(1,1); pair c1=(2,1); pair z1=(3,0); draw(z0..controls c0 and c1 .. z1,blue); draw(z0--c0--c1--z1,dashed); dot(\"$z_0$\",z0,W,red); dot(\"$c_0$\",c0,NW,red); dot(\"$c_1$\",c1,NE,red); dot(\"$z_1$\",z1,red); ")); equation("(1-t)^3 z_0+3t(1-t)^2 c_0+3t^2(1-t) c_1+t^3 z_1, \qquad t\in [0,1]."); title("Smooth Paths"); item("Asymptote can choose control points for you, using the algorithms of Hobby and Knuth \cite{Hobby86,Knuth86b}:"); string bean=" pair[] z={(0,0), (0,1), (2,1), (2,0), (1,0)}; "; asycode(preamble="size(130,0);",bean+" draw(z[0]..z[1]..z[2]..z[3]..z[4]..cycle, grey+linewidth(5)); dot(z,linewidth(7)); "); item("First, linear equations involving the curvature are solved to find the direction through each knot. Then, control points along those directions are chosen:"); asyfigure(asywrite(preamble="size(130,0);",bean+" path p=z[0]..z[1]..z[2]..z[3]..z[4]..cycle; dot(z); draw(p,lightgrey+linewidth(5)); dot(z); picture output; save(); for(int i=0; i0$ and a shift $b$ so that all of the coordinates when transformed will lie in the interval $[0,S]$."); item("That is, if $u$ and $t$ are the user and truesize components:"); equation("0\le au+t+b \le S."); item("Maximize the variable $a$ subject to a number of inequalities."); item("Use the simplex method to solve the resulting linear programming problem."); if(long) { title("Sizing"); item("Every addition of a coordinate $(t,u)$ adds two restrictions"); equation("au+t+b\ge 0,"); equation("au+t+b\le S,"); remark("and each drawing component adds two coordinates."); item("A figure could easily produce thousands of restrictions, making the simplex method impractical."); item("Most of these restrictions are redundant, however. For instance, with concentric circles, only the largest circle needs to be accounted for."); asyfigure(asywrite(" import palette; size(160,0); pen[] p=Rainbow(NColors=11); for(int i=1; i<10; ++i) { draw(scale(i)*unitcircle, p[i]+linewidth(2)); } ")); title("Redundant Restrictions"); item("In general, if $u\le u'$ and $t\le t'$ then"); equation("au+t+b\le au'+t'+b"); remark("for all choices of $a>0$ and $b$, so"); equation("0\le au+t+b\le au'+t'+b\le S."); item("This defines a partial ordering on coordinates. When sizing a picture, the program first computes which coordinates are maximal (or minimal) and only sends effective constraints to the simplex algorithm."); item("In practice, the linear programming problem will have less than a dozen restraints."); item("All picture sizing is implemented in Asymptote code."); } title("Infinite Lines"); item("Deferred drawing allows us to draw infinite lines."); code("drawline(P, Q);"); asyfigure("elliptic","height=12cm"); title("Helpful Math Notation"); item("Integer division returns a {\tt real}. Use {\tt quotient} for an integer result:"); code("3/4 == 0.75 quotient(3,4) == 0"); item("Caret for real and integer exponentiation:"); code("2^3 2.7^3 2.7^3.2"); item("Many expressions can be implicitly scaled by a numeric constant:"); code("2pi 10cm 2x^2 3sin(x) 2(a+b)"); item("Pairs are complex numbers:"); code("(0,1)*(0,1) == (-1,0)"); title("Function Calls"); item("Functions can take default arguments in any position. Arguments are matched to the first possible location:"); string unitsize="unitsize(0.65cm);"; string preamble="void drawEllipse(real xsize=1, real ysize=xsize, pen p=blue) { draw(xscale(xsize)*yscale(ysize)*unitcircle, p); } "; asycode(preamble=unitsize,preamble+" drawEllipse(2); drawEllipse(red); "); item("Arguments can be given by name:"); asycode(preamble=unitsize+preamble," drawEllipse(xsize=2, ysize=1); drawEllipse(ysize=2, xsize=3, green); "); if(long) { title("Rest Arguments"); item("Rest arguments allow one to write a function that takes an arbitrary number of arguments:"); code(" int sum(... int[] nums) { int total=0; for(int i=0; i < nums.length; ++i) total += nums[i]; return total; } sum(1,2,3,4); // returns 10 sum(); // returns 0 sum(1,2,3 ... new int[] {4,5,6}); // returns 21 int subtract(int start ... int[] subs) { return start - sum(... subs); } "); } title("High-Order Functions"); item("Functions are first-class values. They can be passed to other functions:"); code("import graph; real f(real x) { return x*sin(10x); } draw(graph(f,-3,3,300),red);"); asyfigure(asywrite(" import graph; size(300,0); real f(real x) { return x*sin(10x); } draw(graph(f,-3,3,300),red); ")); if(long) { title("Higher-Order Functions"); item("Functions can return functions:"); equation("f_n(x)=n\sin\left(\frac{x}{n}\right)."); skip(); string preamble=" import graph; size(300,0); "; string graphfunc2=" typedef real func(real); func f(int n) { real fn(real x) { return n*sin(x/n); } return fn; } func f1=f(1); real y=f1(pi); for(int i=1; i<=5; ++i) draw(graph(f(i),-10,10),red); "; code(graphfunc2); string name=asywrite(graphfunc2,preamble=preamble); asy(nativeformat(),name+".asy"); label(graphic(name+"."+nativeformat()),(0.5,0), Fill(figureborder,figuremattpen)); title("Anonymous Functions"); item("Create new functions with {\tt new}:"); code(" path p=graph(new real (real x) { return x*sin(10x); },-3,3,red); func f(int n) { return new real (real x) { return n*sin(x/n); }; }"); item("Function definitions are just syntactic sugar for assigning function objects to variables."); code(" real square(real x) { return x^2; } "); remark("is equivalent to"); code(" real square(real x); square=new real (real x) { return x^2; }; "); title("Structures"); item("As in other languages, structures group together data."); code(" struct Person { string firstname, lastname; int age; } Person bob=new Person; bob.firstname=\"Bob\"; bob.lastname=\"Chesterton\"; bob.age=24; "); item("Any code in the structure body will be executed every time a new structure is allocated..."); code(" struct Person { write(\"Making a person.\"); string firstname, lastname; int age=18; } Person eve=new Person; // Writes \"Making a person.\" write(eve.age); // Writes 18. "); title("Modules"); item("Function and structure definitions can be grouped into modules:"); code(" // powers.asy real square(real x) { return x^2; } real cube(real x) { return x^3; } "); remark("and imported:"); code(" import powers; real eight=cube(2.0); draw(graph(powers.square, -1, 1)); "); } title("Object-Oriented Programming"); item("Functions are defined for each instance of a structure."); code(" struct Quadratic { real a,b,c; real discriminant() { return b^2-4*a*c; } real eval(real x) { return a*x^2 + b*x + c; } } "); item("This allows us to construct ``methods'' which are just normal functions declared in the environment of a particular object:"); code(" Quadratic poly=new Quadratic; poly.a=-1; poly.b=1; poly.c=2; real f(real x)=poly.eval; real y=f(2); draw(graph(poly.eval, -5, 5)); "); title("Specialization"); item("Can create specialized objects just by redefining methods:"); code(" struct Shape { void draw(); real area(); } Shape rectangle(real w, real h) { Shape s=new Shape; s.draw = new void () { fill((0,0)--(w,0)--(w,h)--(0,h)--cycle); }; s.area = new real () { return w*h; }; return s; } Shape circle(real radius) { Shape s=new Shape; s.draw = new void () { fill(scale(radius)*unitcircle); }; s.area = new real () { return pi*radius^2; } return s; } "); title("Overloading"); item("Consider the code:"); code(" int x1=2; int x2() { return 7; } int x3(int y) { return 2y; } write(x1+x2()); // Writes 9. write(x3(x1)+x2()); // Writes 11. "); title("Overloading"); item("{\tt x1}, {\tt x2}, and {\tt x3} are never used in the same context, so they can all be renamed {\tt x} without ambiguity:"); code(" int x=2; int x() { return 7; } int x(int y) { return 2y; } write(x+x()); // Writes 9. write(x(x)+x()); // Writes 11. "); item("Function definitions are just variable definitions, but variables are distinguished by their signatures to allow overloading."); title("Operators"); item("Operators are just syntactic sugar for functions, and can be addressed or defined as functions with the {\tt operator} keyword."); code(" int add(int x, int y)=operator +; write(add(2,3)); // Writes 5. // Don't try this at home. int operator +(int x, int y) { return add(2x,y); } write(2+3); // Writes 7. "); item("This allows operators to be defined for new types."); title("Operators"); item("Operators for constructing paths are also functions:"); code("a.. controls b and c .. d--e"); remark("is equivalent to"); code( "operator --(operator ..(a, operator controls(b,c), d), e)"); item("This allowed us to redefine all of the path operators for 3D paths."); title("Summary"); item("Asymptote:"); subitem("uses IEEE floating point numerics;"); subitem("uses C++/Java-like syntax;"); subitem("supports deferred drawing for automatic picture sizing;"); subitem("supports Grayscale, RGB, CMYK, and HSV colour spaces;"); subitem("supports PostScript shading, pattern fills, and function shading;"); subitem("can fill nonsimply connected regions;"); subitem("generalizes MetaPost path construction algorithms to 3D;"); subitem("lifts \TeX\ to 3D;"); subitem("supports 3D billboard labels and PDF grouping."); bibliography("../examples/refs"); viewportmargin=(2,2); viewportsize=0; defaultpen(0.5); title("\mbox{Asymptote: 2D \& 3D Vector Graphics Language}"); asyinclude("../examples/logo3"); skip(); center("\tt http://asymptote.sf.net"); center("(freely available under the LGPL license)"); // LocalWords: pdflatex mflogo viewportsize pagewidth pagemargin goysr bibtex // LocalWords: itempen defaultrender medskip Orest Shardt Vidiassov MF ezier // LocalWords: Hammerlindl MetaPost PDF hfill LGPL pdf asywrite zoombox LaTeX // LocalWords: asyfilecode PostScript asycode unitsquare beziercurve grey bw // LocalWords: lightgrey zerowinding evenodd sw unitsize drawEllipse nums fn // LocalWords: frac graphfunc func nativeformat figureborder figuremattpen bt // LocalWords: firstname lastname eval eetomumu binarytree filecode datagraph // LocalWords: lineargraph filegraph loggraph secondaryaxis imagecontour ij // LocalWords: tridiagonal Hobbydir nonumber Hobbycontrol th viewportmargin // LocalWords: asyinclude dotpen wheelpoint yequals xaxis yaxis cardsize mc // LocalWords: polargraph filldraw addPoint lightblue truesize le au NColors // LocalWords: drawline unityroot mult oct intang IEEE numerics HSV colour // LocalWords: nonsimply asymptote-2.37/doc/filegraph.asy000066400000000000000000000003561265434602500167310ustar00rootroot00000000000000import graph; size(200,150,IgnoreAspect); file in=input("filegraph.dat").line(); real[][] a=in; a=transpose(a); real[] x=a[0]; real[] y=a[1]; draw(graph(x,y),red); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks); asymptote-2.37/doc/filegraph.dat000066400000000000000000000000321265434602500166740ustar00rootroot00000000000000# x y 50 0 100 0.5 125 2 asymptote-2.37/doc/flow.asy000066400000000000000000000011341265434602500157320ustar00rootroot00000000000000import graph; defaultpen(1.0); size(0,150,IgnoreAspect); real arrowsize=4mm; real arrowlength=2arrowsize; typedef path vector(real); // Return a vector interpolated linearly between a and b. vector vector(pair a, pair b) { return new path(real x) { return (0,0)--arrowlength*interp(a,b,x); }; } real f(real x) {return 1/x;} real epsilon=0.5; path g=graph(f,epsilon,1/epsilon); int n=3; draw(g); xaxis("$x$"); yaxis("$y$"); add(vectorfield(vector(W,W),g,n,true)); add(vectorfield(vector(NE,NW),(0,0)--(point(E).x,0),n,true)); add(vectorfield(vector(NE,NE),(0,0)--(0,point(N).y),n,true)); asymptote-2.37/doc/flowchartdemo.asy000066400000000000000000000015361265434602500176270ustar00rootroot00000000000000size(0,300); import flowchart; block block1=rectangle(Label("Example",magenta), pack(Label("Start:",heavygreen),"",Label("$A:=0$",blue), "$B:=1$"),(-0.5,3),palegreen,paleblue,red); block block2=diamond(Label("Choice?",blue),(0,2),palegreen,red); block block3=roundrectangle("Do something",(-1,1)); block block4=bevel("Don't do something",(1,1)); block block5=circle("End",(0,0)); draw(block1); draw(block2); draw(block3); draw(block4); draw(block5); add(new void(picture pic, transform t) { blockconnector operator --=blockconnector(pic,t); // draw(pic,block1.right(t)--block2.top(t)); block1--Right--Down--Arrow--block2; block2--Label("Yes",0.5,NW)--Left--Down--Arrow--block3; block2--Right--Label("No",0.5,NE)--Down--Arrow--block4; block4--Down--Left--Arrow--block5; block3--Down--Right--Arrow--block5; }); asymptote-2.37/doc/generalaxis.asy000066400000000000000000000004251265434602500172670ustar00rootroot00000000000000import graph; size(0,100); path g=ellipse((0,0),1,2); scale(true); axis(Label("C",align=10W),g,LeftTicks(endlabel=false,8,end=false), ticklocate(0,360,new real(real v) { path h=(0,0)--max(abs(max(g)),abs(min(g)))*dir(v); return intersect(g,h)[0];})); asymptote-2.37/doc/generalaxis3.asy000066400000000000000000000005701265434602500173530ustar00rootroot00000000000000import graph3; size(0,100); path3 g=yscale3(2)*unitcircle3; currentprojection=perspective(10,10,10); axis(Label("C",position=0,align=15X),g,InTicks(endlabel=false,8,end=false), ticklocate(0,360,new real(real v) { path3 h=O--max(abs(max(g)),abs(min(g)))*dir(90,v); return intersect(g,h)[0];}, new triple(real t) {return cross(dir(g,t),Z);})); asymptote-2.37/doc/graphmarkers.asy000066400000000000000000000013621265434602500174540ustar00rootroot00000000000000import graph; size(200,100,IgnoreAspect); markroutine marks() { return new void(picture pic=currentpicture, frame f, path g) { path p=scale(1mm)*unitcircle; for(int i=0; i <= length(g); ++i) { pair z=point(g,i); frame f; if(i % 4 == 0) { fill(f,p); add(pic,f,z); } else { if(z.y > 50) { pic.add(new void(frame F, transform t) { path q=shift(t*z)*p; unfill(F,q); draw(F,q); }); } else { draw(f,p); add(pic,f,z); } } } }; } pair[] f={(5,5),(40,20),(55,51),(90,30)}; draw(graph(f),marker(marks())); scale(true); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks); asymptote-2.37/doc/grid3xyz.asy000066400000000000000000000006521265434602500165520ustar00rootroot00000000000000import grid3; size(8cm,0,IgnoreAspect); currentprojection=orthographic(0.5,1,0.5); scale(Linear, Linear, Log); limits((-2,-2,1),(0,2,100)); grid3(XYZgrid); xaxis3(Label("$x$",position=EndPoint,align=S),Bounds(Min,Min), OutTicks()); yaxis3(Label("$y$",position=EndPoint,align=S),Bounds(Min,Min),OutTicks()); zaxis3(Label("$z$",position=EndPoint,align=(-1,0.5)),Bounds(Min,Min), OutTicks(beginlabel=false)); asymptote-2.37/doc/hatch.asy000066400000000000000000000004271265434602500160560ustar00rootroot00000000000000size(0,100); import patterns; add("hatch",hatch()); add("hatchback",hatch(NW)); add("crosshatch",crosshatch(3mm)); real s=1.25; filldraw(unitsquare,pattern("hatch")); filldraw(shift(s,0)*unitsquare,pattern("hatchback")); filldraw(shift(2s,0)*unitsquare,pattern("crosshatch")); asymptote-2.37/doc/helix.asy000066400000000000000000000006471265434602500161040ustar00rootroot00000000000000import graph3; size(0,200); size3(200,IgnoreAspect); currentprojection=orthographic(4,6,3); real x(real t) {return cos(2pi*t);} real y(real t) {return sin(2pi*t);} real z(real t) {return t;} path3 p=graph(x,y,z,0,2.7,operator ..); draw(p,Arrow3); scale(true); xaxis3(XZ()*"$x$",Bounds,red,InTicks(Label,2,2)); yaxis3(YZ()*"$y$",Bounds,red,InTicks(beginlabel=false,Label,2,2)); zaxis3(XZ()*"$z$",Bounds,red,InTicks); asymptote-2.37/doc/histogram.asy000066400000000000000000000006711265434602500167650ustar00rootroot00000000000000import graph; import stats; size(400,200,IgnoreAspect); int n=10000; real[] a=new real[n]; for(int i=0; i < n; ++i) a[i]=Gaussrand(); draw(graph(Gaussian,min(a),max(a)),blue); // Optionally calculate "optimal" number of bins a la Shimazaki and Shinomoto. int N=bins(a); histogram(a,min(a),max(a),N,normalize=true,low=0,lightred,black,bars=false); xaxis("$x$",BottomTop,LeftTicks); yaxis("$dP/dx$",LeftRight,RightTicks(trailingzero)); asymptote-2.37/doc/icon.asy000066400000000000000000000005741265434602500157220ustar00rootroot00000000000000import graph; size(30,30,IgnoreAspect); real f(real t) {return t < 0 ? -1/t : -0.5/t;} picture logo(pair s=0, pen q) { picture pic; pen p=linewidth(3)+q; real a=-0.5; real b=1; real eps=0.1; draw(pic,shift((eps,-f(a)))*graph(f,a,-eps),p); real c=0.5*a; pair z=(0,f(c)-f(a)); draw(pic,z+c+eps--z,p); yaxis(pic,p); return shift(s)*pic; } add(logo(red)); asymptote-2.37/doc/image.asy000066400000000000000000000006211265434602500160450ustar00rootroot00000000000000size(12cm,12cm); import graph; import palette; int n=256; real ninv=2pi/n; real[][] v=new real[n][n]; for(int i=0; i < n; ++i) for(int j=0; j < n; ++j) v[i][j]=sin(i*ninv)*cos(j*ninv); pen[] Palette=BWRainbow(); picture bar; bounds range=image(v,(0,0),(1,1),Palette); palette(bar,"$A$",range,(0,0),(0.5cm,8cm),Right,Palette, PaletteTicks("$%+#.1f$")); add(bar.fit(),point(E),30E); asymptote-2.37/doc/imagecontour.asy000066400000000000000000000015501265434602500174610ustar00rootroot00000000000000import graph; import palette; import contour; size(10cm,10cm,IgnoreAspect); pair a=(0,0); pair b=(2pi,2pi); real f(real x, real y) {return cos(x)*sin(y);} int N=200; int Divs=10; int divs=2; defaultpen(1bp); pen Tickpen=black; pen tickpen=gray+0.5*linewidth(currentpen); pen[] Palette=BWRainbow(); bounds range=image(f,Automatic,a,b,N,Palette); // Major contours real[] Cvals=uniform(range.min,range.max,Divs); draw(contour(f,a,b,Cvals,N,operator --),Tickpen); // Minor contours real[] cvals; for(int i=0; i < Cvals.length-1; ++i) cvals.append(uniform(Cvals[i],Cvals[i+1],divs)[1:divs]); draw(contour(f,a,b,cvals,N,operator --),tickpen); xaxis("$x$",BottomTop,LeftTicks,above=true); yaxis("$y$",LeftRight,RightTicks,above=true); palette("$f(x,y)$",range,point(NW)+(0,0.5),point(NE)+(0,1),Top,Palette, PaletteTicks(N=Divs,n=divs,Tickpen,tickpen)); asymptote-2.37/doc/install-sh000077500000000000000000000325371265434602500162640ustar00rootroot00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2009-04-28.21; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then trap '(exit $?); exit' 1 2 13 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names starting with `-'. case $src in -*) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # Protect names starting with `-'. case $dst in -*) dst=./$dst;; esac # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writeable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; -*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test -z "$d" && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: asymptote-2.37/doc/irregularcontour.asy000066400000000000000000000005451265434602500203760ustar00rootroot00000000000000import contour; size(200); int n=100; real f(real a, real b) {return a^2+b^2;} srand(1); real r() {return 1.1*(rand()/randMax*2-1);} pair[] points=new pair[n]; real[] values=new real[n]; for(int i=0; i < n; ++i) { points[i]=(r(),r()); values[i]=f(points[i].x,points[i].y); } draw(contour(points,values,new real[]{0.25,0.5,1},operator ..),blue); asymptote-2.37/doc/join.asy000066400000000000000000000004051265434602500157220ustar00rootroot00000000000000size(300,0); pair[] z=new pair[10]; z[0]=(0,100); z[1]=(50,0); z[2]=(180,0); for(int n=3; n <= 9; ++n) z[n]=z[n-3]+(200,0); path p=z[0]..z[1]---z[2]::{up}z[3] &z[3]..z[4]--z[5]::{up}z[6] &z[6]::z[7]---z[8]..{up}z[9]; draw(p,grey+linewidth(4mm)); dot(z); asymptote-2.37/doc/join3.asy000066400000000000000000000006721265434602500160130ustar00rootroot00000000000000import graph3; size(200); currentprojection=orthographic(500,-500,500); triple[] z=new triple[10]; z[0]=(0,100,0); z[1]=(50,0,0); z[2]=(180,0,0); for(int n=3; n <= 9; ++n) z[n]=z[n-3]+(200,0,0); path3 p=z[0]..z[1]---z[2]::{Y}z[3] &z[3]..z[4]--z[5]::{Y}z[6] &z[6]::z[7]---z[8]..{Y}z[9]; draw(p,grey+linewidth(4mm),currentlight); xaxis3(Label(XY()*"$x$",align=-3Y),red,above=true); yaxis3(Label(XY()*"$y$",align=-3X),red,above=true); asymptote-2.37/doc/knots.asy000066400000000000000000000006411265434602500161230ustar00rootroot00000000000000import syzygy; Braid initial; initial.n = 4; initial.add(bp,1); initial.add(bp,0); initial.add(bp,2); initial.add(bp,1); initial.add(phi,2); initial.add(phi,0); Syzygy pp; pp.lsym="\Phi\Phi"; pp.codename="PhiAroundPhi"; pp.number=true; pp.initial=initial; pp.apply(r4b,2,1); pp.apply(r4b,0,0); pp.apply(r4a,1,0); pp.swap(0,1); pp.apply(-r4b,1,0); pp.apply(-r4a,0,1); pp.apply(-r4a,2,0); pp.swap(4,5); pp.draw(); asymptote-2.37/doc/labelsquare.asy000066400000000000000000000001711265434602500172630ustar00rootroot00000000000000size(3cm); draw(unitsquare); label("$A$",(0,0),SW); label("$B$",(1,0),SE); label("$C$",(1,1),NE); label("$D$",(0,1),NW); asymptote-2.37/doc/latexmkrc000066400000000000000000000002161265434602500161620ustar00rootroot00000000000000sub asy {return system("asy '$_[0]'");} add_cus_dep("asy","eps",0,"asy"); add_cus_dep("asy","pdf",0,"asy"); add_cus_dep("asy","tex",0,"asy"); asymptote-2.37/doc/latexmkrc_asydir000066400000000000000000000002261265434602500175360ustar00rootroot00000000000000sub asy {return system("asy -o asy/ '$_[0]'");} add_cus_dep("asy","eps",0,"asy"); add_cus_dep("asy","pdf",0,"asy"); add_cus_dep("asy","tex",0,"asy"); asymptote-2.37/doc/latexusage.tex000066400000000000000000000060421265434602500171340ustar00rootroot00000000000000\documentclass[12pt]{article} % Use this form to include EPS (latex) or PDF (pdflatex) files: \usepackage{asymptote} % Use this form with latex or pdflatex to include inline LaTeX code by default: %\usepackage[inline]{asymptote} % Use this form with latex or pdflatex to create PDF attachments by default: %\usepackage[attach]{asymptote} % Enable this line to support the attach option: %\usepackage[dvips]{attachfile2} \begin{document} % Optional subdirectory for latex files (no spaces): \def\asylatexdir{} % Optional subdirectory for asy files (no spaces): \def\asydir{} \begin{asydef} // Global Asymptote definitions can be put here. import three; usepackage("bm"); texpreamble("\def\V#1{\bm{#1}}"); // One can globally override the default toolbar settings here: // settings.toolbar=true; \end{asydef} Here is a venn diagram produced with Asymptote, drawn to width 4cm: \def\A{A} \def\B{\V{B}} %\begin{figure} \begin{center} \begin{asy} size(4cm,0); pen colour1=red; pen colour2=green; pair z0=(0,0); pair z1=(-1,0); pair z2=(1,0); real r=1.5; path c1=circle(z1,r); path c2=circle(z2,r); fill(c1,colour1); fill(c2,colour2); picture intersection=new picture; fill(intersection,c1,colour1+colour2); clip(intersection,c2); add(intersection); draw(c1); draw(c2); //draw("$\A$",box,z1); // Requires [inline] package option. //draw(Label("$\B$","$B$"),box,z2); // Requires [inline] package option. draw("$A$",box,z1); draw("$\V{B}$",box,z2); pair z=(0,-2); real m=3; margin BigMargin=Margin(0,m*dot(unit(z1-z),unit(z0-z))); draw(Label("$A\cap B$",0),conj(z)--z0,Arrow,BigMargin); draw(Label("$A\cup B$",0),z--z0,Arrow,BigMargin); draw(z--z1,Arrow,Margin(0,m)); draw(z--z2,Arrow,Margin(0,m)); shipout(bbox(0.25cm)); \end{asy} %\caption{Venn diagram}\label{venn} \end{center} %\end{figure} Each graph is drawn in its own environment. One can specify the width and height to \LaTeX\ explicitly. This 3D example can be viewed interactively either with Adobe Reader or Asymptote's fast OpenGL-based renderer. To support {\tt latexmk}, 3D figures should specify \verb+inline=true+. It is sometimes desirable to embed 3D files as annotated attachments; this requires the \verb+attach=true+ option as well as the \verb+attachfile2+ \LaTeX\ package. \begin{center} \begin{asy}[height=4cm,inline=true,attach=false,viewportwidth=\linewidth] currentprojection=orthographic(5,4,2); draw(unitcube,blue); label("$V-E+F=2$",(0,1,0.5),3Y,blue+fontsize(17pt)); \end{asy} \end{center} One can also scale the figure to the full line width: \begin{center} \begin{asy}[width=\the\linewidth,inline=true] pair z0=(0,0); pair z1=(2,0); pair z2=(5,0); pair zf=z1+0.75*(z2-z1); draw(z1--z2); dot(z1,red+0.15cm); dot(z2,darkgreen+0.3cm); label("$m$",z1,1.2N,red); label("$M$",z2,1.5N,darkgreen); label("$\hat{\ }$",zf,0.2*S,fontsize(24pt)+blue); pair s=-0.2*I; draw("$x$",z0+s--z1+s,N,red,Arrows,Bars,PenMargins); s=-0.5*I; draw("$\bar{x}$",z0+s--zf+s,blue,Arrows,Bars,PenMargins); s=-0.95*I; draw("$X$",z0+s--z2+s,darkgreen,Arrows,Bars,PenMargins); \end{asy} \end{center} \end{document} asymptote-2.37/doc/leastsquares.asy000066400000000000000000000020011265434602500174710ustar00rootroot00000000000000size(400,200,IgnoreAspect); import graph; import stats; file fin=input("leastsquares.dat").line(); real[][] a=fin; a=transpose(a); real[] t=a[0], rho=a[1]; // Read in parameters from the keyboard: //real first=getreal("first"); //real step=getreal("step"); //real last=getreal("last"); real first=100; real step=50; real last=700; // Remove negative or zero values of rho: t=rho > 0 ? t : null; rho=rho > 0 ? rho : null; scale(Log(true),Linear(true)); int n=step > 0 ? ceil((last-first)/step) : 0; real[] T,xi,dxi; for(int i=0; i <= n; ++i) { real first=first+i*step; real[] logrho=(t >= first & t <= last) ? log(rho) : null; real[] logt=(t >= first & t <= last) ? -log(t) : null; if(logt.length < 2) break; // Fit to the line logt=L.m*logrho+L.b: linefit L=leastsquares(logt,logrho); T.push(first); xi.push(L.m); dxi.push(L.dm); } draw(graph(T,xi),blue); errorbars(T,xi,dxi,red); crop(); ylimits(0); xaxis("$T$",BottomTop,LeftTicks); yaxis("$\xi$",LeftRight,RightTicks); asymptote-2.37/doc/leastsquares.dat000066400000000000000000000142561265434602500174640ustar00rootroot000000000000001 3825 2 4057 3 4217 4 4278 5 4353 6 4483 7 4410 8 4462 9 4626 10 4511 11 4531 12 4450 13 4354 14 4402 15 4489 16 4441 17 4366 18 4443 19 4442 20 4335 21 4292 22 4458 23 4444 24 4426 25 4310 26 4264 27 4263 28 4252 29 4330 30 4304 31 4242 32 4272 33 4284 34 4198 35 4242 36 4096 37 4142 38 4248 39 4186 40 4210 41 4125 42 4134 43 4098 44 4129 45 3960 46 4012 47 4079 48 4038 49 4024 50 3949 51 3996 52 3970 53 4031 54 3895 55 3806 56 3825 57 3850 58 3742 59 3678 60 3589 61 3648 62 3476 63 3490 64 3353 65 3270 66 3134 67 3018 68 2922 69 2801 70 2691 71 2528 72 2460 73 2254 74 2105 75 2009 76 1854 77 1677 78 1562 79 1501 80 1399 81 1244 82 1160 83 1080 84 963 85 879 86 797 87 745 88 701 89 634 90 554 91 532 92 549 93 521 94 466 95 460 96 435 97 412 98 376 99 367 100 350 101 360 102 321 103 302 104 291 105 273 106 261 107 255 108 231 109 245 110 252 111 236 112 227 113 207 114 196 115 199 116 211 117 232 118 220 119 214 120 229 121 213 122 208 123 196 124 218 125 196 126 192 127 178 128 177 129 178 130 179 131 170 132 173 133 170 134 150 135 144 136 149 137 145 138 145 139 139 140 147 141 140 142 128 143 133 144 156 145 136 146 164 147 152 148 140 149 141 150 112 151 108 152 110 153 133 154 118 155 113 156 113 157 108 158 88 159 109 160 97 161 99 162 94 163 97 164 104 165 105 166 118 167 108 168 130 169 126 170 114 171 112 172 107 173 96 174 96 175 102 176 85 177 89 178 93 179 96 180 101 181 82 182 97 183 96 184 94 185 97 186 85 187 79 188 72 189 75 190 63 191 65 192 62 193 54 194 53 195 49 196 55 197 48 198 53 199 46 200 50 201 48 202 50 203 51 204 50 205 49 206 46 207 47 208 44 209 42 210 47 211 45 212 44 213 46 214 43 215 40 216 42 217 41 218 40 219 43 220 41 221 42 222 43 223 40 224 42 225 39 226 41 227 42 228 44 229 40 230 40 231 35 232 38 233 37 234 36 235 34 236 34 237 34 238 36 239 36 240 36 241 37 242 37 243 37 244 36 245 36 246 45 247 43 248 43 249 43 250 49 251 58 252 48 253 50 254 56 255 51 256 50 257 55 258 64 259 55 260 49 261 36 262 36 263 40 264 49 265 37 266 35 267 35 268 33 269 33 270 39 271 35 272 34 273 36 274 32 275 37 276 31 277 31 278 32 279 30 280 32 281 29 282 31 283 30 284 30 285 28 286 27 287 26 288 24 289 25 290 28 291 30 292 29 293 27 294 27 295 27 296 26 297 26 298 28 299 27 300 24 301 22 302 27 303 26 304 25 305 25 306 25 307 26 308 28 309 26 310 25 311 24 312 26 313 25 314 23 315 25 316 24 317 23 318 23 319 24 320 23 321 24 322 22 323 24 324 24 325 24 326 23 327 25 328 24 329 22 330 22 331 23 332 23 333 23 334 21 335 19 336 20 337 22 338 26 339 25 340 24 341 22 342 22 343 23 344 23 345 23 346 20 347 21 348 20 349 21 350 25 351 22 352 22 353 21 354 24 355 24 356 22 357 23 358 26 359 24 360 23 361 22 362 26 363 30 364 27 365 25 366 26 367 26 368 25 369 24 370 24 371 22 372 21 373 20 374 20 375 19 376 20 377 21 378 20 379 20 380 19 381 19 382 19 383 19 384 20 385 20 386 19 387 20 388 20 389 20 390 17 391 18 392 16 393 18 394 32 395 31 396 47 397 57 398 64 399 34 400 42 401 40 402 41 403 35 404 26 405 25 406 25 407 36 408 42 409 55 410 75 411 94 412 87 413 97 414 95 415 101 416 70 417 66 418 66 419 73 420 77 421 89 422 79 423 63 424 66 425 71 426 70 427 49 428 46 429 46 430 43 431 49 432 48 433 44 434 36 435 33 436 28 437 29 438 32 439 31 440 29 441 28 442 29 443 31 444 31 445 33 446 33 447 39 448 44 449 37 450 58 451 64 452 38 453 31 454 36 455 33 456 29 457 34 458 28 459 27 460 23 461 31 462 26 463 21 464 23 465 26 466 21 467 21 468 24 469 24 470 24 471 24 472 26 473 23 474 26 475 20 476 21 477 25 478 21 479 22 480 22 481 23 482 22 483 23 484 22 485 20 486 22 487 20 488 22 489 20 490 24 491 20 492 22 493 19 494 19 495 20 496 19 497 18 498 18 499 17 500 16 501 16 502 17 503 17 504 16 505 17 506 16 507 16 508 16 509 17 510 18 511 17 512 16 513 17 514 16 515 16 516 16 517 17 518 16 519 16 520 16 521 16 522 16 523 16 524 16 525 16 526 16 527 17 528 17 529 18 530 17 531 16 532 15 533 15 534 15 535 15 536 16 537 17 538 16 539 18 540 17 541 17 542 15 543 15 544 15 545 16 546 15 547 15 548 15 549 15 550 15 551 14 552 14 553 14 554 14 555 14 556 14 557 14 558 15 559 14 560 16 561 15 562 16 563 17 564 15 565 14 566 17 567 18 568 17 569 16 570 17 571 14 572 15 573 15 574 15 575 14 576 15 577 14 578 14 579 13 580 13 581 13 582 13 583 13 584 12 585 12 586 13 587 12 588 12 589 12 590 13 591 15 592 16 593 14 594 13 595 14 596 13 597 13 598 13 599 13 600 14 601 13 602 13 603 13 604 14 605 15 606 15 607 15 608 15 609 15 610 15 611 15 612 15 613 15 614 15 615 15 616 14 617 14 618 14 619 14 620 14 621 14 622 14 623 15 624 15 625 15 626 14 627 15 628 14 629 14 630 14 631 14 632 14 633 14 634 13 635 13 636 13 637 13 638 13 639 13 640 13 641 13 642 13 643 13 644 13 645 13 646 13 647 13 648 13 649 13 650 13 651 13 652 13 653 13 654 13 655 13 656 13 657 13 658 13 659 13 660 13 661 13 662 13 663 13 664 13 665 13 666 13 667 13 668 13 669 13 670 13 671 13 672 13 673 13 674 13 675 13 676 13 677 13 678 13 679 12 680 12 681 13 682 13 683 13 684 13 685 12 686 12 687 13 688 13 689 13 690 13 691 13 692 13 693 13 694 13 695 13 696 13 697 13 698 13 699 13 700 13 701 13 702 13 703 13 704 13 705 13 706 13 707 13 708 13 709 13 710 13 711 13 712 13 713 13 714 13 715 13 716 13 717 13 718 13 719 13 720 13 721 13 722 13 723 13 724 13 725 13 726 13 727 13 728 13 729 13 730 13 731 13 732 13 733 13 734 13 735 13 736 13 737 13 738 13 739 13 740 13 741 13 742 13 743 13 744 13 745 13 746 13 747 13 748 13 749 13 750 13 751 13 752 13 753 13 754 13 755 12 756 12 757 12 758 12 759 11 760 12 761 11 762 12 763 11 764 12 765 12 766 12 767 12 768 14 769 14 770 14 771 14 772 12 773 12 774 12 775 13 776 13 777 13 778 12 779 13 780 13 781 13 782 13 783 13 784 13 785 12 786 11 787 11 788 11 789 12 790 13 791 13 792 13 793 12 794 13 795 13 796 13 797 13 798 13 799 12 800 12 801 12 802 12 803 12 804 12 805 11 806 11 807 11 808 12 809 13 810 13 811 12 812 12 813 12 814 12 815 12 816 12 817 12 818 12 819 12 820 13 821 13 822 13 823 13 824 12 825 13 826 12 827 13 828 13 829 13 830 13 831 12 832 12 833 12 834 13 835 13 836 12 837 9 838 9 839 10 840 10 841 11 842 11 843 11 844 12 845 12 846 11 847 12 848 12 849 12 850 12 851 12 852 12 853 12 854 12 855 12 856 11 857 10 858 11 859 12 860 11 861 11 862 11 863 10 864 10 865 10 866 11 867 10 868 10 869 10 870 11 871 11 872 12 873 12 874 12 875 12 876 12 877 12 878 12 879 12 880 12 881 0 882 0 asymptote-2.37/doc/legend.asy000066400000000000000000000006321265434602500162230ustar00rootroot00000000000000import graph; size(8cm,6cm,IgnoreAspect); typedef real realfcn(real); realfcn F(real p) { return new real(real x) {return sin(p*x);}; }; for(int i=1; i < 5; ++i) draw(graph(F(i*pi),0,1),Pen(i), "$\sin("+(i == 1 ? "" : (string) i)+"\pi x)$"); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks(trailingzero)); attach(legend(2),(point(S).x,truepoint(S).y),10S,UnFill); asymptote-2.37/doc/lineargraph.asy000066400000000000000000000005651265434602500172660ustar00rootroot00000000000000import graph; size(250,200,IgnoreAspect); real Sin(real t) {return sin(2pi*t);} real Cos(real t) {return cos(2pi*t);} draw(graph(Sin,0,1),red,"$\sin(2\pi x)$"); draw(graph(Cos,0,1),blue,"$\cos(2\pi x)$"); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks(trailingzero)); label("LABEL",point(0),UnFill(1mm)); attach(legend(),truepoint(E),20E,UnFill); asymptote-2.37/doc/lineargraph0.asy000066400000000000000000000005561265434602500173460ustar00rootroot00000000000000import graph; size(400,200,IgnoreAspect); real Sin(real t) {return sin(2pi*t);} real Cos(real t) {return cos(2pi*t);} draw(graph(Sin,0,1),red,"$\sin(2\pi x)$"); draw(graph(Cos,0,1),blue,"$\cos(2\pi x)$"); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks(trailingzero)); label("LABEL",point(0),UnFill(1mm)); add(legend(),point(E),20E,UnFill); asymptote-2.37/doc/linetype.asy000066400000000000000000000006401265434602500166150ustar00rootroot00000000000000void testline(real y) { draw((0,y)--(100,y),currentpen+solid); draw((0,y-10)--(100,y-10),currentpen+dotted); draw((0,y-20)--(100,y-20),currentpen+dashed); draw((0,y-30)--(100,y-30),currentpen+longdashed); draw((0,y-40)--(100,y-40),currentpen+dashdotted); draw((0,y-50)--(100,y-50),currentpen+longdashdotted); draw((0,y-60)--(100,y-60),currentpen+Dotted); } currentpen=linewidth(0.5); testline(100); asymptote-2.37/doc/log2graph.asy000066400000000000000000000006471265434602500166600ustar00rootroot00000000000000import graph; size(200,IgnoreAspect); // Base-2 logarithmic scale on y-axis: real log2(real x) {static real log2=log(2); return log(x)/log2;} real pow2(real x) {return 2^x;} scaleT yscale=scaleT(log2,pow2,logarithmic=true); scale(Linear,yscale); real f(real x) {return 1+x^2;} draw(graph(f,-4,4)); yaxis("$y$",ymin=1,ymax=f(5),RightTicks(Label(Fill(white))),EndArrow); xaxis("$x$",xmin=-5,xmax=5,LeftTicks,EndArrow); asymptote-2.37/doc/loggraph.asy000066400000000000000000000004061265434602500165670ustar00rootroot00000000000000import graph; size(200,200,IgnoreAspect); real f(real t) {return 1/t;} scale(Log,Log); draw(graph(f,0.1,10)); //limits((1,0.1),(10,0.5),Crop); dot(Label("(3,5)",align=S),Scale((3,5))); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks); asymptote-2.37/doc/loggrid.asy000066400000000000000000000005761265434602500164230ustar00rootroot00000000000000import graph; size(200,200,IgnoreAspect); real f(real t) {return 1/t;} scale(Log,Log); draw(graph(f,0.1,10),red); pen thin=linewidth(0.5*linewidth()); xaxis("$x$",BottomTop,LeftTicks(begin=false,end=false,extend=true, ptick=thin)); yaxis("$y$",LeftRight,RightTicks(begin=false,end=false,extend=true, ptick=thin)); asymptote-2.37/doc/logimage.asy000066400000000000000000000007401265434602500165510ustar00rootroot00000000000000import graph; import palette; size(10cm,10cm,IgnoreAspect); real f(real x, real y) { return 0.9*pow10(2*sin(x/5+2*y^0.25)) + 0.1*(1+cos(10*log(y))); } scale(Linear,Log,Log); pen[] Palette=BWRainbow(); bounds range=image(f,Automatic,(0,1),(100,100),nx=200,Palette); xaxis("$x$",BottomTop,LeftTicks,above=true); yaxis("$y$",LeftRight,RightTicks,above=true); palette("$f(x,y)$",range,(0,200),(100,250),Top,Palette, PaletteTicks(ptick=linewidth(0.5*linewidth()))); asymptote-2.37/doc/logo.asy000066400000000000000000000011531265434602500157240ustar00rootroot00000000000000size(140,80,IgnoreAspect); picture logo(pair s=0, pen q) { picture pic; pen p=linewidth(2)+fontsize(24pt)+q; real a=-0.4; real b=0.95; real y1=-5; real y2=-3y1/2; path A=(a,0){dir(10)}::{dir(89.5)}(0,y2); draw(pic,A,p); draw(pic,(0,y1){dir(88.3)}::{dir(20)}(b,0),p); real c=0.5*a; pair z=(0,2.5); label(pic,"{\it symptote}",z,0.25*E+0.169S,p); pair w=(0,1.7); draw(pic,intersectionpoint(A,w-1--w)--w,p); draw(pic,(0,y1)--(0,y2),p); draw(pic,(a,0)--(b,0),p); return shift(s)*pic; } pair z=(-0.015,0.08); for(int x=0; x < 10; ++x) add(logo(0.1*x*z,gray(0.04*x))); add(logo(red)); asymptote-2.37/doc/logticks.asy000066400000000000000000000004721265434602500166060ustar00rootroot00000000000000import graph; size(300,175,IgnoreAspect); scale(Log,Log); draw(graph(identity,5,20)); xlimits(5,20); ylimits(1,100); xaxis("$M/M_\odot$",BottomTop,LeftTicks(DefaultFormat, new real[] {6,10,12,14,16,18})); yaxis("$\nu_{\rm upp}$ [Hz]",LeftRight,RightTicks(DefaultFormat)); asymptote-2.37/doc/makepen.asy000066400000000000000000000004451265434602500164070ustar00rootroot00000000000000size(200); pen convex=makepen(scale(10)*polygon(8))+grey; draw((1,0.4),convex); draw((0,0)---(1,1)..(2,0)--cycle,convex); pen nonconvex=scale(10)* makepen((0,0)--(0.25,-1)--(0.5,0.25)--(1,0)--(0.5,1.25)--cycle)+red; draw((0.5,-1.5),nonconvex); draw((0,-1.5)..(1,-0.5)..(2,-1.5),nonconvex); asymptote-2.37/doc/markers1.asy000066400000000000000000000051351265434602500165150ustar00rootroot00000000000000size(12cm,0); import markers; pair A=(0,0), B=(1,0), C=(2,0), D=(3,0); path p=A--B--C--D; transform T=shift(-4,-1); transform t=shift(4,0); //line 1 ********** draw(p,marker(markinterval(3,dotframe,true))); label("$1$",point(p,0),3W); //line 2 ********** p=t*p; draw(p,marker(stickframe,markuniform(4))); label("$2$",point(p,0),3W); //line 3 ********** p=T*p; draw(p,marker(stickframe(red),markinterval(3,dotframe(blue),true))); label("$3$",point(p,0),3W); //line 4 ********** p=t*p; draw(p,StickIntervalMarker(3,2,blue,dotframe(red))); label("$4$",point(p,0),3W); //line 5 ********** p=T*p; pen pn=linewidth(4bp); draw(p,pn,StickIntervalMarker(3,3,angle=25,pn,dotframe(red+pn))); label("$5$",point(p,0),3W); //line 6 ********** p=t*p; draw(p,StickIntervalMarker(3,5,angle=25,size=4mm,space=2mm,offset=I*2mm, scale(2)*dotframe(red))); label("$6$",point(p,0),3W); //line 7 ********** p=T*p; draw(p,StickIntervalMarker(n=3,angle=45,size=10mm,space=3mm,dotframe)); label("$7$",point(p,0),3W); //line 8 ********** p=t*p; draw(p,CircleBarIntervalMarker(n=2,dotframe)); label("$8$",point(p,0),3W); //line 9 ********** p=T*p; draw(p,CircleBarIntervalMarker(n=3,angle=30,barsize=8mm,radius=2mm, FillDraw(.8red), dotframe)); label("$9$",point(p,0),3W); //line 10 ********** p=t*p; draw(p,CircleBarIntervalMarker(n=3,angle=30,barsize=8mm,radius=2mm, FillDraw(.8red),circleabove=true,dotframe)); label("$10$",point(p,0),3W); //line 11 ********** p=T*p; draw(p,CircleBarIntervalMarker(n=3,angle=30,barsize=8mm,radius=2mm, FillDraw(.8red),circleabove=true,dotframe, above=false)); label("$11$",point(p,0),3W); //line 12 ********** p=t*p; draw(p,TildeIntervalMarker(i=3,dotframe)); label("$12$",point(p,0),3W); //line 13 ********** p=T*p; draw(p,TildeIntervalMarker(i=3,n=2,angle=-20,dotframe)); label("$13$",point(p,0),3W); //line 14 ********** p=t*p; draw(p,CrossIntervalMarker(3,3,dotframe)); label("$14$",point(p,0),3W); //line 15 ********** p=shift(.25S)*T*p; path cle=shift(relpoint(p,.5))*scale(abs(A-D)/4)*unitcircle; draw(cle,StickIntervalMarker(5,3,dotframe(6bp+red))); label("$15$",point(p,0),3W); //line 16 ********** cle=t*cle; p=t*p; frame a; label(a,"$a$",(0,-2labelmargin())); draw(cle,marker(dotframe(6bp+red),markinterval(5,a,true))); label("$16$",point(p,0),3W); // line 17 ********** p=T*shift(relpoint(p,.5)+.65S)*scale(.5)*shift(-relpoint(p,.5))*rotate(45,relpoint(p,.5))*p; draw(p,TildeIntervalMarker(size=5mm,rotated=false,dotframe)); label("$17$",point(p,0),3W); asymptote-2.37/doc/markers2.asy000066400000000000000000000015551265434602500165200ustar00rootroot00000000000000size(10cm,0); import markers; import geometry; import math; pair A=0, B=(1,0), C=(0.7,1), D=(-0.5,0), F=rotate(-90)*(C-B)/2+B; draw(A--B); draw(A--C); pen p=linewidth(1mm); draw(B--C,p); draw(A--D); draw(B--F,p); label("$A$",A,SW); label("$B$",B,S); label("$C$",C,N); dot(Label("$D$",D,S)); dot(Label("$F$",F,N+NW)); markangle(A,C,B); markangle(scale(1.5)*"$\theta$",radius=40,C,B,A,ArcArrow(2mm),1mm+red); markangle(scale(1.5)*"$-\theta$",radius=-70,A,B,C,ArcArrow,green); markangle(Label("$\gamma$",Relative(0.25)),n=2,radius=-30,A,C,B,p=0.7blue+2); markangle(n=3,B,A,C,marker(markinterval(stickframe(n=2),true))); pen RedPen=0.7red+1bp; markangle(C,A,D,RedPen,marker(markinterval(2,stickframe(3,4mm,RedPen),true))); drawline(A,A+dir(A--D,A--C),dotted); perpendicular(B,NE,F-B,size=10mm,1mm+red, TrueMargin(linewidth(p)/2,linewidth(p)/2),Fill(yellow)); asymptote-2.37/doc/mexicanhat.asy000066400000000000000000000004401265434602500171030ustar00rootroot00000000000000size(200); real mexican(real x) {return (1-8x^2)*exp(-(4x^2));} int n=30; real a=1.5; real width=2a/n; guide hat; path solved; for(int i=0; i < n; ++i) { real t=-a+i*width; pair z=(t,mexican(t)); hat=hat..z; solved=solved..z; } draw(hat); dot(hat,red); draw(solved,dashed); asymptote-2.37/doc/monthaxis.asy000066400000000000000000000005661265434602500170050ustar00rootroot00000000000000import graph; size(400,150,IgnoreAspect); real[] x=sequence(12); real[] y=sin(2pi*x/12); scale(false); string[] month={"Jan","Feb","Mar","Apr","May","Jun", "Jul","Aug","Sep","Oct","Nov","Dec"}; draw(graph(x,y),red,MarkFill[0]); xaxis(BottomTop,LeftTicks(new string(real x) { return month[round(x % 12)];})); yaxis("$y$",LeftRight,RightTicks(4)); asymptote-2.37/doc/multicontour.asy000066400000000000000000000007121265434602500175300ustar00rootroot00000000000000import contour; size(200); real f(real x, real y) {return x^2-y^2;} int n=10; real[] c=new real[n]; for(int i=0; i < n; ++i) c[i]=(i-n/2)/n; pen[] p=sequence(new pen(int i) { return (c[i] >= 0 ? solid : dashed)+fontsize(6pt); },c.length); Label[] Labels=sequence(new Label(int i) { return Label(c[i] != 0 ? (string) c[i] : "",Relative(unitrand()),(0,0), UnFill(1bp)); },c.length); draw(Labels,contour(f,(-1,-1),(1,1),c),p); asymptote-2.37/doc/ocg.sty000066400000000000000000000066511265434602500155670ustar00rootroot00000000000000%% Copyright (C) 2007 by Michael Ritzert %% Spurious spaces removed by John Bowman [2009/06/01]. %% Global macros to find the number of a PDF OCG object from its LaTeX %% reference contributed by Paul Gaborit [2012/09/13]. \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{ocg}[2012/09/13] \RequirePackage{ifpdf} \ifpdf \else \PackageWarningNoLine{ocg}{% Loading aborted, because pdfTeX is not running in PDF mode% }% \expandafter\endinput \fi \DeclareOption*{}\ProcessOptions*\relax %allow anything as option for the moment %testing for correct pdfTeX version %TODO: find out minimum required version! \ifnum\pdftexversion<120 \PackageError{ocg}{% pdfeTeX, version >= 1.20, required% }{% Install a newer version!% }% \fi % Next OCG id -- TODO: autogenerate. but keep possibility to reopen an OCG. \newcount\@ocg@num\@ocg@num=0 \gdef\@ocg@layersnames{} % called from the aux file \def\@ocg@makeknown#1#2#3{% #1: OCG name, #2: OC id, #3: on/off \@ifundefined{OCG#2}{% \message{OCG#2} \expandafter\gdef\csname OCG#2\endcsname{#1}% \immediate\pdfobj{<< /Type /OCG /Name (#1) >>}% new ocg \xdef\@ocg@curocg{\the\pdflastobj\space 0 R}% reference to id \expandafter\xdef\csname OCGpdfobj#2\endcsname{\@ocg@curocg} \xdef\@ocg@ocgs{\@ocg@ocgs\space\@ocg@curocg}% list of all OCGs in "first defined" order \ifnum#3=1 %on \xdef\@ocg@ocgson{\@ocg@ocgson\space\@ocg@curocg}% list of all default-on OCGs \else% \xdef\@ocg@ocgsoff{\@ocg@ocgsoff\space\@ocg@curocg}% list of all default-off OCGs \fi% \xdef\@ocg@layersnames{% \@ocg@layersnames\space/OC#2\space\@ocg@curocg% name-to-id mapping }% }{% \message{OCG#2 reopened} % layer reopened } } \AtBeginDocument{% % the auxfile has been read if available. register the OCGs in the page resources. \@ocg@addresource \let\@ocg@makeknown\@gobble } % set page resources to include the layers defined in the aux file \def\@ocg@addresource{% \immediate\pdfobj{<<\@ocg@layersnames\space>>}% \xdef\@ocg@namesobj{\the\pdflastobj\space 0 R}% % append to pageresources \begingroup \edef\x{\endgroup \pdfpageresources{% \the\pdfpageresources /Properties \@ocg@namesobj% }% }% \x } \newcount\@ocg@@ocgs \pdfobj reserveobjnum \@ocg@@ocgs=\pdflastobj \newcount\@ocg@@layersconfig \pdfobj reserveobjnum \@ocg@@layersconfig=\pdflastobj \pdfcatalog{% /OCProperties << /OCGs \the\@ocg@@ocgs\space0 R\space /D \the\@ocg@@layersconfig\space0 R\space >>% } \def\@ocg@ocgs{} \def\@ocg@ocgson{} \def\@ocg@ocgsoff{} \AtEndDocument{% \immediate\pdfobj useobjnum \@ocg@@ocgs {% [\@ocg@ocgs\space]% }% \immediate\pdfobj useobjnum \@ocg@@layersconfig {% << /Order [\@ocg@ocgs\space] /ON [\@ocg@ocgson\space] /OFF [\@ocg@ocgsoff\space] >>% }% }% % schedule a OCG for creation on the next pdflatex run (via the auxfile) \def\@ocg@newocg#1#2#3{% #1:name, #2:num, #3:on \if@filesw% \immediate\write\@auxout{% \string\@ocg@makeknown{#1}{#2}{#3}% }% \fi% } % TODO: Are nested OCGs allowed? \newenvironment{ocg}[3]{% \@ocg@newocg{#1}{#2}{#3}% \gdef\@ocg@curnum{#2}% \pdfliteral{/OC /OC\@ocg@curnum\space BDC}% \message{/OC\@ocg@curnum}% \ignorespaces }{% \pdfliteral{EMC}% %\unskip% %\endgroup% \ignorespacesafterend } asymptote-2.37/doc/onecontour.asy000066400000000000000000000001631265434602500171570ustar00rootroot00000000000000import contour; size(75); real f(real a, real b) {return a^2+b^2;} draw(contour(f,(-1,-1),(1,1),new real[] {1})); asymptote-2.37/doc/parametricgraph.asy000066400000000000000000000003601265434602500201340ustar00rootroot00000000000000import graph; size(0,200); real x(real t) {return cos(2pi*t);} real y(real t) {return sin(2pi*t);} draw(graph(x,y,0,1)); //limits((0,-1),(1,0),Crop); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks(trailingzero)); asymptote-2.37/doc/penfunctionimage.asy000066400000000000000000000007621265434602500203240ustar00rootroot00000000000000import palette; size(200); real fracpart(real x) {return (x-floor(x));} pair pws(pair z) { pair w=(z+exp(pi*I/5)/0.9)/(1+z/0.9*exp(-pi*I/5)); return exp(w)*(w^3-0.5*I); } int N=512; pair a=(-1,-1); pair b=(0.5,0.5); real dx=(b-a).x/N; real dy=(b-a).y/N; pen f(int u, int v) { pair z=a+(u*dx,v*dy); pair w=pws(z); real phase=degrees(w,warn=false); real modulus=w == 0 ? 0: fracpart(log(abs(w))); return hsv(phase,1,sqrt(modulus)); } image(f,N,N,(0,0),(300,300),antialias=true); asymptote-2.37/doc/penimage.asy000066400000000000000000000003331265434602500165500ustar00rootroot00000000000000size(200); import palette; int n=256; real ninv=2pi/n; pen[][] v=new pen[n][n]; for(int i=0; i < n; ++i) for(int j=0; j < n; ++j) v[i][j]=rgb(0.5*(1+sin(i*ninv)),0.5*(1+cos(j*ninv)),0); image(v,(0,0),(1,1)); asymptote-2.37/doc/pixel.pdf000066400000000000000000000053231265434602500160650ustar00rootroot00000000000000%PDF-1.2 %Çì¢ 5 0 obj <> stream xœ+T0Ð3T0A(œËU¨`bnf©gæš[êY€™¡%H~¹‚K>W Ê÷ sendstream endobj 6 0 obj 57 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 8 0 obj <> endobj 7 0 obj <>/Length 1686>>stream xœí]lU†gÊ…Rü!j"5€LdW`V¬©WJC½¨h´¢RÿÀˆTåçBÀ4µQB/$ ’p‰‚%z£ÒBB°´&rA×ݶœíÏvÚnö·=yŸ«/éì¼_öéÌž™Ý9'LÂ[BÙõÙõÙõÙõÙõÙõÙõÙõÙõÙõÙõÙEbÜø„ì"1n¼ìB1n¼ìB1n¼ìB1n¼ìB1n¼ìB1n¼ìB1n¼ìB1n¼ìB1n¼ìB1n¼ìB1n¼ìB1n¼ìB1n¼ìB1n¼ìB1n¼ìB1n¼ìB1n¼ìB1n¼ìB1n¼ìB1n¼ìB1n¼ìB1n¼ìBùû$5^v¡7~øÛ½ìªsYþ:ÙU£bèeÈ7^v¡7^v¡7^v¡7^v¡7^v¡7^v¡7^v¡7^v¡7^v¡7~øÛmrU‘«Z]UìªÑ®šëª9®*pÕ$WÅðÿ`øˆ(dŠá#¢](†ˆBv¡>" Ù…bøˆ(dŠá#¢](†ˆBv¡>" Ù…bøˆ(dŠá#¢þv[\U⪃‘¯çªBWqÕW-wÕ¹µ60†ÚñàÝ4²ËBvsGvÓÈ. ÙÍÙM#»,d7w†`÷ò¹`2á²›;C°ÛTÔZ{aßU§‚Y—VìÚ2jâüEEÓÆ ðŠ¡"»(²ÛzàØñû[îº÷ÚÔIÎ —å]m »8"í¶ŸÚ×4öž…èa”좈°Û~z÷‘e³ úû{Þ]ýÚ½ø×þƒóÊfâÝÊ.Ž~ì¶7¾Ïéæ…ì¢èÇnÝΧ–^W²‹"«Ý¦.¬Ç9¹ÙE‘Ån{ãÖñOO±ÙEÑ×î¿õ­)µ‡ WÍrÕ%W­pUÆîWeF]5ßU‹\•ùÅÝ4W.Ý{cøˆ(úØm®]ãY9ì¢èm·ù­ñqž•ÓÈ.Š^vÏVÜñfì=È.Š^v_ýmÇu±÷ »(zÚ­ý¡zJü=È.Šv¿´ê¸?sÓÈ.Šîv¿ø®†päÊ.Žnv¿}¡¦(jS²‹"c·mõCeœdEÆîç ÛbûÞ ']U±U÷·ª!Ë+–¹*VÑ7ÞÙ=Y±ãR²‹ÂÙ­ã¿Ñ…좸b·þ«Íñ߯èBvQtÙm[]ú0­ÙEÑe—7¤ dG§Ý3On»•׃ì¢è´ûõ¯¯{]vÛÊKKÞ†ì¢è°ûû¶w™ïƒì¢è°»9¨âvá-ÆOÛm}þ™Û¹]x‹qãÓv÷Ö}È»òãÆ§í¾q'ïN†ç7>e÷ÌšÓÞPä‚qãSv÷þ¼ØõãÆ§ìV'7r{ðãÆ§ì¾w³>vQ7>þórÕtncÜøDØXþ©U(ŒŸ>ø,·Ÿ1n|"|ñê×¹-øŒqãaõÝTÁ0n|"|ì ª`7>N?|#·Ÿ1n¼ìB1n¼ìB1n¼ìB1n¼ìB1n¼ìB1n|"œý½nDÂ0n|"Üø ·¯1n¼ìB1n¼ÎÌPŒ¯QãÆë>3ãÆ'šų¹-øŒqãaå”—¸-øŒqãõí½×„?ýXÎîA O½¿‰þ ¤6®ªÕ%‘¯„-U•z¾ÓWÂdMRÏfûJ˜üc+u^$LêÑ{ “š6Ã_RvÉSÞ)»gžøä&vBzF#Mœá+i»šôÆW†ÁL‚FÇ, :x=¥Ã®^Oéœ}[¯ŸtÍœ¯ƒ×KºV½ÐÁë%]vÛÊÑ5¯\Y¨¾Ž³Ä£@âVŠÛÓ°]çfßȬòXùà*j'"ÿdVhm®Z¼’Ù‰È?ÝVWþfÃÖBC÷•Ñë­×ÈÊ+ºÛ ÖšªÙ+zØmÞ°°x,­‘wzØM¬þÛ®“³?ô´4í8¿~*©‘wzÙ ‚ÚCÏÍ( ´"òN»A]ÍÚLjüÓ×nríÒG­ˆ¼Ó×nêÃwÓõ%3uvö€lvƒ¶úï+“ß‘OV»AûéÝGThð<ÒÉn7í÷³ó‹é ”‘MvÓ~7µ®œW½žµÖôo7õñ{àØá™·-¹A‚G*ÿè › endstream endobj 2 0 obj <>endobj xref 0 9 0000000000 65535 f 0000000359 00000 n 0000002314 00000 n 0000000300 00000 n 0000000160 00000 n 0000000015 00000 n 0000000142 00000 n 0000000436 00000 n 0000000407 00000 n trailer << /Size 9 /Root 1 0 R /Info 2 0 R /ID [( œæ›eYšÓI„k÷Û)( œæ›eYšÓI„k÷Û)] >> startxref 2472 %%EOF asymptote-2.37/doc/planes.asy000066400000000000000000000005431265434602500162500ustar00rootroot00000000000000size(6cm,0); import bsp; real u=2.5; real v=1; currentprojection=oblique; path3 y=plane((2u,0,0),(0,2v,0),(-u,-v,0)); path3 l=rotate(90,Z)*rotate(90,Y)*y; path3 g=rotate(90,X)*rotate(90,Y)*y; face[] faces; filldraw(faces.push(y),project(y),yellow); filldraw(faces.push(l),project(l),lightgrey); filldraw(faces.push(g),project(g),green); add(faces); asymptote-2.37/doc/png/000077500000000000000000000000001265434602500150325ustar00rootroot00000000000000asymptote-2.37/doc/png/Makefile.in000066400000000000000000000026751265434602500171110ustar00rootroot00000000000000ASYFILES = $(notdir $(filter-out $(wildcard ../latexusage-*.asy),$(wildcard ../*.asy))) SOURCE = ../asymptote.texi ../version.texi ../options ASY = ../asy -dir ../base -config "" -render=0 docdir = $(DESTDIR)@docdir@ infodir = $(DESTDIR)@infodir@ datarootdir = @datarootdir@ INSTALL = @INSTALL@ all: html info %.png: ../%.asy cd .. && $(ASY) -f png -o png/ $(notdir $<) latexusage.png: ../latexusage.eps gs -q -dNOPAUSE -dBATCH -sDEVICE=pngalpha -dEPSCrop -dSAFER -r72x72 \ -sOutputFile=latexusage.png ../latexusage.eps index.html: $(SOURCE) $(ASYFILES:.asy=.png) latexusage.png makeinfo --html ../asymptote -o . asymptote.info: $(SOURCE) makeinfo --no-warn --no-split ../asymptote info: $(SOURCE) $(ASYFILES:.asy=.png) latexusage.png makeinfo --no-split ../asymptote ../options: cd .. && $(MAKE) options html: index.html clean: FORCE -rm -f *.png *.html asymptote.info* texput.aux texput.log distclean: FORCE clean -rm -f Makefile install: asymptote.info ${INSTALL} -d -m 755 $(infodir)/asymptote ${INSTALL} -p -m 644 asymptote.info $(infodir)/asymptote -if test -z "$(DESTDIR)"; then \ install-info --infodir=$(infodir) asymptote.info; \ fi install-all: all install ${INSTALL} -p -m 644 *.png $(infodir)/asymptote uninstall: -install-info --remove --infodir=$(infodir) asymptote.info -cd $(infodir)/asymptote && rm -f asymptote.info *.png -rmdir $(infodir)/asymptote FORCE: Makefile: Makefile.in cd ../..; config.status asymptote-2.37/doc/quartercircle.asy000066400000000000000000000000611265434602500176260ustar00rootroot00000000000000size(100,0); draw((1,0){up}..{left}(0,1),Arrow); asymptote-2.37/doc/reloadpdf.tex000066400000000000000000000005421265434602500167310ustar00rootroot00000000000000% Tex file for generating the reloadpdf.pdf utility to force Adobe Reader % to reload all currently loaded documents. Usage: % % pdflatex reloadpdf % acroread reloadpdf.pdf % \documentclass{article} \begin{document} \ \pdfannot width 0pt height 0pt { /AA << /PO << /S /JavaScript /JS (try{reload();} catch(e) {} closeDoc(this);) >> >> } \end{document} asymptote-2.37/doc/saddle.asy000066400000000000000000000002351265434602500162200ustar00rootroot00000000000000import three; size(100,0); path3 g=(1,0,0)..(0,1,1)..(-1,0,0)..(0,-1,1)..cycle; draw(g); draw(((-1,-1,0)--(1,-1,0)--(1,1,0)--(-1,1,0)--cycle)); dot(g,red); asymptote-2.37/doc/scaledgraph.asy000066400000000000000000000005431265434602500172430ustar00rootroot00000000000000import graph; axiscoverage=0.9; size(200,IgnoreAspect); real[] x={-1e-11,1e-11}; real[] y={0,1e6}; real xscale=round(log10(max(x))); real yscale=round(log10(max(y)))-1; draw(graph(x*10^(-xscale),y*10^(-yscale)),red); xaxis("$x/10^{"+(string) xscale+"}$",BottomTop,LeftTicks); yaxis("$y/10^{"+(string) yscale+"}$",LeftRight,RightTicks(trailingzero)); asymptote-2.37/doc/secondaryaxis.asy000066400000000000000000000014651265434602500176460ustar00rootroot00000000000000import graph; size(9cm,6cm,IgnoreAspect); string data="secondaryaxis.csv"; file in=input(data).line().csv(); string[] titlelabel=in; string[] columnlabel=in; real[][] a=in; a=transpose(a); real[] t=a[0], susceptible=a[1], infectious=a[2], dead=a[3], larvae=a[4]; real[] susceptibleM=a[5], exposed=a[6],infectiousM=a[7]; scale(true); draw(graph(t,susceptible,t >= 10 & t <= 15)); draw(graph(t,dead,t >= 10 & t <= 15),dashed); xaxis("Time ($\tau$)",BottomTop,LeftTicks); yaxis(Left,RightTicks); picture secondary=secondaryY(new void(picture pic) { scale(pic,Linear(true),Log(true)); draw(pic,graph(pic,t,infectious,t >= 10 & t <= 15),red); yaxis(pic,Right,red,LeftTicks(begin=false,end=false)); }); add(secondary); label(shift(5mm*N)*"Proportion of crows",point(NW),E); asymptote-2.37/doc/secondaryaxis.csv000066400000000000000000001373171265434602500176530ustar00rootroot00000000000000,"Proportion of crows",,,"Mosquitoes per crow",,, Time,Susceptible,Infectious,Dead,Larvae,Susceptible,Exposed,Infectious 0,1,0,0,,30,0.000,0.001 0.1,1.000,0.000,0.000,12.794,30.000,0.000,0.001 0.2,1.000,0.000,0.000,12.794,30.000,0.000,0.001 0.3,1.000,0.000,0.000,12.795,30.000,0.000,0.001 0.4,1.000,0.000,0.000,12.795,30.000,0.000,0.001 0.5,1.000,0.000,0.000,12.795,30.000,0.000,0.001 0.6,1.000,0.000,0.000,12.795,30.000,0.000,0.001 0.7,1.000,0.000,0.000,12.795,30.000,0.000,0.001 0.8,0.999,0.000,0.000,12.795,30.000,0.000,0.001 0.9,0.999,0.000,0.000,12.795,29.999,0.001,0.001 1,0.999,0.000,0.000,12.795,29.999,0.001,0.001 1.1,0.999,0.000,0.000,12.795,29.999,0.001,0.001 1.2,0.999,0.000,0.000,12.795,29.999,0.001,0.001 1.3,0.999,0.000,0.000,12.795,29.999,0.001,0.001 1.4,0.999,0.000,0.001,12.795,29.999,0.001,0.001 1.5,0.999,0.001,0.001,12.795,29.999,0.001,0.001 1.6,0.999,0.001,0.001,12.795,29.999,0.001,0.001 1.7,0.999,0.001,0.001,12.795,29.998,0.001,0.001 1.8,0.999,0.001,0.001,12.795,29.998,0.001,0.001 1.9,0.998,0.001,0.001,12.795,29.998,0.001,0.002 2,0.998,0.001,0.001,12.795,29.998,0.001,0.002 2.1,0.998,0.001,0.001,12.795,29.998,0.002,0.002 2.2,0.998,0.001,0.001,12.795,29.998,0.002,0.002 2.3,0.998,0.001,0.001,12.795,29.997,0.002,0.002 2.4,0.998,0.001,0.001,12.795,29.997,0.002,0.002 2.5,0.998,0.001,0.002,12.795,29.997,0.002,0.002 2.6,0.997,0.001,0.002,12.795,29.997,0.002,0.002 2.7,0.997,0.001,0.002,12.795,29.996,0.002,0.003 2.8,0.997,0.001,0.002,12.795,29.996,0.002,0.003 2.9,0.997,0.001,0.002,12.795,29.996,0.002,0.003 3,0.997,0.001,0.002,12.795,29.995,0.003,0.003 3.1,0.996,0.001,0.002,12.795,29.995,0.003,0.003 3.2,0.996,0.001,0.003,12.795,29.995,0.003,0.003 3.3,0.996,0.001,0.003,12.795,29.994,0.003,0.004 3.4,0.996,0.001,0.003,12.795,29.994,0.003,0.004 3.5,0.995,0.002,0.003,12.795,29.994,0.003,0.004 3.6,0.995,0.002,0.003,12.795,29.993,0.004,0.004 3.7,0.995,0.002,0.004,12.795,29.993,0.004,0.004 3.8,0.994,0.002,0.004,12.795,29.992,0.004,0.005 3.9,0.994,0.002,0.004,12.795,29.992,0.004,0.005 4,0.994,0.002,0.004,12.795,29.991,0.005,0.005 4.1,0.993,0.002,0.005,12.795,29.991,0.005,0.006 4.2,0.993,0.002,0.005,12.795,29.990,0.005,0.006 4.3,0.992,0.002,0.005,12.795,29.989,0.005,0.006 4.4,0.992,0.003,0.006,12.795,29.989,0.006,0.007 4.5,0.991,0.003,0.006,12.795,29.988,0.006,0.007 4.6,0.991,0.003,0.006,12.795,29.987,0.006,0.008 4.7,0.990,0.003,0.007,12.795,29.986,0.007,0.008 4.8,0.990,0.003,0.007,12.795,29.985,0.007,0.008 4.9,0.989,0.003,0.008,12.795,29.984,0.008,0.009 5,0.988,0.004,0.008,12.795,29.984,0.008,0.009 5.1,0.988,0.004,0.009,12.795,29.982,0.008,0.010 5.2,0.987,0.004,0.009,12.795,29.981,0.009,0.011 5.3,0.986,0.004,0.010,12.795,29.980,0.010,0.011 5.4,0.985,0.005,0.010,12.795,29.979,0.010,0.012 5.5,0.984,0.005,0.011,12.795,29.978,0.011,0.013 5.6,0.983,0.005,0.012,12.795,29.976,0.011,0.013 5.7,0.982,0.005,0.012,12.795,29.975,0.012,0.014 5.8,0.981,0.006,0.013,12.795,29.973,0.013,0.015 5.9,0.980,0.006,0.014,12.795,29.972,0.013,0.016 6,0.979,0.006,0.015,12.795,29.970,0.014,0.017 6.1,0.978,0.007,0.016,12.795,29.968,0.015,0.018 6.2,0.976,0.007,0.016,12.795,29.966,0.016,0.019 6.3,0.975,0.008,0.017,12.795,29.964,0.017,0.020 6.4,0.973,0.008,0.019,12.795,29.962,0.018,0.021 6.5,0.972,0.008,0.020,12.795,29.960,0.019,0.022 6.6,0.970,0.009,0.021,12.795,29.957,0.020,0.024 6.7,0.968,0.009,0.022,12.795,29.955,0.021,0.025 6.8,0.967,0.010,0.023,12.795,29.952,0.022,0.026 6.9,0.965,0.011,0.025,12.795,29.949,0.024,0.028 7,0.963,0.011,0.026,12.795,29.946,0.025,0.030 7.1,0.960,0.012,0.028,12.795,29.943,0.026,0.031 7.2,0.958,0.013,0.029,12.795,29.940,0.028,0.033 7.3,0.956,0.013,0.031,12.795,29.936,0.029,0.035 7.4,0.953,0.014,0.033,12.795,29.933,0.031,0.037 7.5,0.950,0.015,0.035,12.795,29.929,0.033,0.039 7.6,0.947,0.016,0.037,12.795,29.925,0.035,0.042 7.7,0.944,0.016,0.039,12.795,29.920,0.037,0.044 7.8,0.941,0.017,0.041,12.795,29.916,0.039,0.046 7.9,0.938,0.018,0.044,12.795,29.911,0.041,0.049 8,0.934,0.019,0.046,12.795,29.906,0.043,0.052 8.1,0.931,0.020,0.049,12.795,29.900,0.046,0.055 8.2,0.927,0.021,0.052,12.795,29.895,0.048,0.058 8.3,0.923,0.023,0.055,12.795,29.889,0.051,0.061 8.4,0.918,0.024,0.058,12.795,29.883,0.054,0.065 8.5,0.914,0.025,0.061,12.795,29.876,0.056,0.069 8.6,0.909,0.026,0.065,12.795,29.869,0.059,0.072 8.7,0.904,0.028,0.068,12.795,29.862,0.063,0.076 8.8,0.899,0.029,0.072,12.795,29.854,0.066,0.081 8.9,0.893,0.031,0.076,12.795,29.846,0.070,0.085 9,0.887,0.032,0.080,12.795,29.838,0.073,0.090 9.1,0.881,0.034,0.085,12.795,29.829,0.077,0.095 9.2,0.875,0.036,0.090,12.795,29.820,0.081,0.100 9.3,0.868,0.037,0.095,12.795,29.810,0.085,0.106 9.4,0.861,0.039,0.100,12.795,29.800,0.090,0.112 9.5,0.854,0.041,0.105,12.795,29.789,0.094,0.118 9.6,0.846,0.043,0.111,12.795,29.778,0.099,0.124 9.7,0.838,0.045,0.117,12.795,29.766,0.104,0.131 9.8,0.830,0.047,0.123,12.795,29.754,0.109,0.138 9.9,0.821,0.049,0.130,12.795,29.742,0.114,0.145 10,0.812,0.052,0.136,12.795,29.729,0.120,0.153 10.1,0.802,0.054,0.144,12.795,29.715,0.126,0.161 10.2,0.793,0.056,0.151,12.795,29.701,0.132,0.169 10.3,0.782,0.059,0.159,12.795,29.686,0.138,0.178 10.4,0.772,0.061,0.167,12.795,29.670,0.144,0.187 10.5,0.761,0.064,0.175,12.795,29.654,0.150,0.196 10.6,0.750,0.066,0.184,12.795,29.638,0.157,0.206 10.7,0.738,0.069,0.193,12.795,29.621,0.164,0.216 10.8,0.726,0.072,0.203,12.795,29.603,0.171,0.227 10.9,0.713,0.074,0.212,12.795,29.585,0.178,0.238 11,0.700,0.077,0.223,12.795,29.566,0.185,0.250 11.1,0.687,0.080,0.233,12.795,29.547,0.193,0.261 11.2,0.674,0.082,0.244,12.795,29.527,0.200,0.274 11.3,0.660,0.085,0.255,12.795,29.507,0.208,0.286 11.4,0.645,0.088,0.267,12.795,29.486,0.215,0.300 11.5,0.631,0.090,0.279,12.795,29.465,0.223,0.313 11.6,0.616,0.093,0.291,12.795,29.443,0.231,0.327 11.7,0.601,0.095,0.304,12.795,29.421,0.238,0.341 11.8,0.585,0.098,0.317,12.795,29.399,0.246,0.356 11.9,0.570,0.100,0.330,12.795,29.376,0.254,0.371 12,0.554,0.102,0.344,12.795,29.353,0.261,0.386 12.1,0.538,0.104,0.358,12.795,29.330,0.269,0.402 12.2,0.521,0.106,0.372,12.795,29.307,0.276,0.418 12.3,0.505,0.108,0.387,12.795,29.283,0.283,0.434 12.4,0.489,0.110,0.401,12.795,29.260,0.290,0.451 12.5,0.472,0.112,0.416,12.795,29.236,0.297,0.468 12.6,0.456,0.113,0.432,12.795,29.213,0.303,0.485 12.7,0.439,0.114,0.447,12.795,29.190,0.309,0.502 12.8,0.423,0.115,0.462,12.795,29.167,0.315,0.519 12.9,0.406,0.116,0.478,12.795,29.144,0.320,0.536 13,0.390,0.116,0.494,12.795,29.122,0.325,0.554 13.1,0.374,0.117,0.509,12.795,29.100,0.329,0.571 13.2,0.358,0.117,0.525,12.795,29.079,0.333,0.588 13.3,0.343,0.117,0.541,12.795,29.059,0.337,0.606 13.4,0.327,0.116,0.557,12.795,29.039,0.340,0.623 13.5,0.312,0.116,0.572,12.795,29.020,0.342,0.639 13.6,0.297,0.115,0.588,12.795,29.001,0.344,0.656 13.7,0.283,0.114,0.603,12.795,28.984,0.345,0.672 13.8,0.269,0.113,0.618,12.795,28.967,0.346,0.688 13.9,0.255,0.111,0.634,12.795,28.952,0.346,0.704 14,0.242,0.109,0.648,12.795,28.937,0.345,0.719 14.1,0.229,0.108,0.663,12.795,28.924,0.344,0.733 14.2,0.217,0.106,0.677,12.795,28.912,0.342,0.747 14.3,0.205,0.103,0.692,12.795,28.900,0.340,0.761 14.4,0.194,0.101,0.705,12.795,28.891,0.337,0.774 14.5,0.183,0.099,0.719,12.795,28.882,0.333,0.786 14.6,0.172,0.096,0.732,12.795,28.874,0.329,0.797 14.7,0.162,0.093,0.745,12.795,28.868,0.325,0.808 14.8,0.153,0.090,0.757,12.795,28.863,0.320,0.818 14.9,0.143,0.087,0.769,12.795,28.860,0.314,0.827 15,0.135,0.084,0.781,12.795,28.857,0.308,0.836 15.1,0.127,0.081,0.792,12.795,28.856,0.302,0.843 15.2,0.119,0.078,0.803,12.795,28.856,0.295,0.850 15.3,0.112,0.075,0.813,12.795,28.857,0.288,0.856 15.4,0.105,0.072,0.823,12.795,28.859,0.281,0.861 15.5,0.098,0.069,0.833,12.795,28.863,0.273,0.865 15.6,0.092,0.066,0.842,12.795,28.867,0.266,0.868 15.7,0.086,0.063,0.850,12.795,28.873,0.258,0.870 15.8,0.081,0.060,0.859,12.795,28.879,0.250,0.872 15.9,0.076,0.058,0.867,12.795,28.887,0.242,0.873 16,0.071,0.055,0.874,12.795,28.895,0.233,0.873 16.1,0.066,0.052,0.882,12.795,28.904,0.225,0.872 16.2,0.062,0.049,0.888,12.795,28.914,0.217,0.870 16.3,0.058,0.047,0.895,12.795,28.925,0.209,0.867 16.4,0.055,0.044,0.901,12.795,28.936,0.201,0.864 16.5,0.051,0.042,0.907,12.795,28.948,0.192,0.860 16.6,0.048,0.040,0.912,12.795,28.961,0.185,0.856 16.7,0.045,0.037,0.918,12.795,28.974,0.177,0.850 16.8,0.042,0.035,0.922,12.795,28.988,0.169,0.844 16.9,0.040,0.033,0.927,12.795,29.002,0.161,0.838 17,0.037,0.031,0.931,12.795,29.016,0.154,0.831 17.1,0.035,0.029,0.936,12.795,29.031,0.147,0.823 17.2,0.033,0.028,0.939,12.795,29.046,0.140,0.815 17.3,0.031,0.026,0.943,12.795,29.061,0.133,0.807 17.4,0.029,0.024,0.946,12.795,29.077,0.126,0.798 17.5,0.028,0.023,0.950,12.795,29.093,0.120,0.788 17.6,0.026,0.021,0.953,12.795,29.108,0.114,0.779 17.7,0.025,0.020,0.955,12.795,29.124,0.108,0.769 17.8,0.023,0.019,0.958,12.795,29.141,0.102,0.758 17.9,0.022,0.018,0.960,12.795,29.157,0.097,0.748 18,0.021,0.017,0.963,12.795,29.173,0.092,0.737 18.1,0.020,0.015,0.965,12.795,29.189,0.087,0.726 18.2,0.019,0.014,0.967,12.795,29.205,0.082,0.714 18.3,0.018,0.014,0.969,12.795,29.221,0.077,0.703 18.4,0.017,0.013,0.971,12.795,29.237,0.073,0.691 18.5,0.016,0.012,0.972,12.795,29.253,0.069,0.680 18.6,0.015,0.011,0.974,12.795,29.268,0.065,0.668 18.7,0.014,0.010,0.975,12.795,29.284,0.061,0.656 18.8,0.014,0.010,0.977,12.795,29.299,0.057,0.644 18.9,0.013,0.009,0.978,12.795,29.315,0.054,0.632 19,0.012,0.008,0.979,12.795,29.330,0.051,0.620 19.1,0.012,0.008,0.980,12.795,29.345,0.048,0.609 19.2,0.011,0.007,0.981,12.795,29.359,0.045,0.597 19.3,0.011,0.007,0.982,12.795,29.374,0.042,0.585 19.4,0.010,0.007,0.983,12.795,29.388,0.040,0.573 19.5,0.010,0.006,0.984,12.795,29.402,0.037,0.562 19.6,0.010,0.006,0.985,12.795,29.416,0.035,0.550 19.7,0.009,0.005,0.985,12.795,29.430,0.033,0.538 19.8,0.009,0.005,0.986,12.795,29.443,0.031,0.527 19.9,0.009,0.005,0.987,12.795,29.456,0.029,0.516 20,0.008,0.004,0.987,12.795,29.469,0.027,0.505 20.1,0.008,0.004,0.988,12.795,29.482,0.026,0.494 20.2,0.008,0.004,0.989,12.795,29.494,0.024,0.483 20.3,0.007,0.004,0.989,12.795,29.506,0.023,0.472 20.4,0.007,0.003,0.990,12.795,29.518,0.021,0.461 20.5,0.007,0.003,0.990,12.795,29.530,0.020,0.451 20.6,0.007,0.003,0.990,12.795,29.541,0.019,0.441 20.7,0.006,0.003,0.991,12.795,29.553,0.018,0.431 20.8,0.006,0.003,0.991,12.795,29.564,0.017,0.421 20.9,0.006,0.002,0.991,12.795,29.575,0.016,0.411 21,0.006,0.002,0.992,12.795,29.585,0.015,0.401 21.1,0.006,0.002,0.992,12.795,29.595,0.014,0.392 21.2,0.006,0.002,0.992,12.795,29.605,0.013,0.383 21.3,0.005,0.002,0.993,12.795,29.615,0.012,0.374 21.4,0.005,0.002,0.993,12.795,29.625,0.011,0.365 21.5,0.005,0.002,0.993,12.795,29.634,0.011,0.356 21.6,0.005,0.002,0.993,12.795,29.644,0.010,0.347 21.7,0.005,0.002,0.994,12.795,29.653,0.009,0.339 21.8,0.005,0.001,0.994,12.795,29.661,0.009,0.331 21.9,0.005,0.001,0.994,12.795,29.670,0.008,0.323 22,0.004,0.001,0.994,12.795,29.678,0.008,0.315 22.1,0.004,0.001,0.994,12.795,29.687,0.007,0.307 22.2,0.004,0.001,0.995,12.795,29.695,0.007,0.299 22.3,0.004,0.001,0.995,12.795,29.702,0.007,0.292 22.4,0.004,0.001,0.995,12.795,29.710,0.006,0.285 22.5,0.004,0.001,0.995,12.795,29.718,0.006,0.278 22.6,0.004,0.001,0.995,12.795,29.725,0.006,0.271 22.7,0.004,0.001,0.995,12.795,29.732,0.005,0.264 22.8,0.004,0.001,0.995,12.795,29.739,0.005,0.257 22.9,0.004,0.001,0.995,12.795,29.746,0.005,0.251 23,0.004,0.001,0.996,12.795,29.752,0.004,0.244 23.1,0.004,0.001,0.996,12.795,29.758,0.004,0.238 23.2,0.004,0.001,0.996,12.795,29.765,0.004,0.232 23.3,0.003,0.001,0.996,12.795,29.771,0.004,0.226 23.4,0.003,0.001,0.996,12.795,29.777,0.004,0.221 23.5,0.003,0.001,0.996,12.795,29.783,0.003,0.215 23.6,0.003,0.001,0.996,12.795,29.788,0.003,0.210 23.7,0.003,0.001,0.996,12.795,29.794,0.003,0.204 23.8,0.003,0.001,0.996,12.795,29.799,0.003,0.199 23.9,0.003,0.001,0.996,12.795,29.804,0.003,0.194 24,0.003,0.000,0.996,12.795,29.809,0.003,0.189 24.1,0.003,0.000,0.996,12.795,29.814,0.002,0.184 24.2,0.003,0.000,0.997,12.795,29.819,0.002,0.179 24.3,0.003,0.000,0.997,12.795,29.824,0.002,0.175 24.4,0.003,0.000,0.997,12.795,29.829,0.002,0.170 24.5,0.003,0.000,0.997,12.795,29.833,0.002,0.166 24.6,0.003,0.000,0.997,12.795,29.838,0.002,0.162 24.7,0.003,0.000,0.997,12.795,29.842,0.002,0.157 24.8,0.003,0.000,0.997,12.795,29.846,0.002,0.153 24.9,0.003,0.000,0.997,12.795,29.850,0.002,0.149 25,0.003,0.000,0.997,12.795,29.854,0.002,0.145 25.1,0.003,0.000,0.997,12.795,29.858,0.002,0.142 25.2,0.003,0.000,0.997,12.795,29.862,0.001,0.138 25.3,0.003,0.000,0.997,12.795,29.865,0.001,0.134 25.4,0.003,0.000,0.997,12.795,29.869,0.001,0.131 25.5,0.003,0.000,0.997,12.795,29.872,0.001,0.128 25.6,0.003,0.000,0.997,12.795,29.876,0.001,0.124 25.7,0.003,0.000,0.997,12.795,29.879,0.001,0.121 25.8,0.003,0.000,0.997,12.795,29.882,0.001,0.118 25.9,0.003,0.000,0.997,12.795,29.885,0.001,0.115 26,0.002,0.000,0.997,12.795,29.888,0.001,0.112 26.1,0.002,0.000,0.997,12.795,29.891,0.001,0.109 26.2,0.002,0.000,0.997,12.795,29.894,0.001,0.106 26.3,0.002,0.000,0.997,12.795,29.897,0.001,0.103 26.4,0.002,0.000,0.997,12.795,29.900,0.001,0.101 26.5,0.002,0.000,0.997,12.795,29.902,0.001,0.098 26.6,0.002,0.000,0.997,12.795,29.905,0.001,0.095 26.7,0.002,0.000,0.997,12.795,29.907,0.001,0.093 26.8,0.002,0.000,0.997,12.795,29.910,0.001,0.090 26.9,0.002,0.000,0.998,12.795,29.912,0.001,0.088 27,0.002,0.000,0.998,12.795,29.915,0.001,0.086 27.1,0.002,0.000,0.998,12.795,29.917,0.001,0.083 27.2,0.002,0.000,0.998,12.795,29.919,0.001,0.081 27.3,0.002,0.000,0.998,12.795,29.921,0.001,0.079 27.4,0.002,0.000,0.998,12.795,29.923,0.001,0.077 27.5,0.002,0.000,0.998,12.795,29.925,0.001,0.075 27.6,0.002,0.000,0.998,12.795,29.927,0.001,0.073 27.7,0.002,0.000,0.998,12.795,29.929,0.001,0.071 27.8,0.002,0.000,0.998,12.795,29.931,0.001,0.069 27.9,0.002,0.000,0.998,12.795,29.933,0.000,0.067 28,0.002,0.000,0.998,12.795,29.935,0.000,0.066 28.1,0.002,0.000,0.998,12.795,29.937,0.000,0.064 28.2,0.002,0.000,0.998,12.795,29.938,0.000,0.062 28.3,0.002,0.000,0.998,12.795,29.940,0.000,0.061 28.4,0.002,0.000,0.998,12.795,29.942,0.000,0.059 28.5,0.002,0.000,0.998,12.795,29.943,0.000,0.057 28.6,0.002,0.000,0.998,12.795,29.945,0.000,0.056 28.7,0.002,0.000,0.998,12.795,29.946,0.000,0.054 28.8,0.002,0.000,0.998,12.795,29.948,0.000,0.053 28.9,0.002,0.000,0.998,12.795,29.949,0.000,0.052 29,0.002,0.000,0.998,12.795,29.950,0.000,0.050 29.1,0.002,0.000,0.998,12.795,29.952,0.000,0.049 29.2,0.002,0.000,0.998,12.795,29.953,0.000,0.048 29.3,0.002,0.000,0.998,12.795,29.954,0.000,0.046 29.4,0.002,0.000,0.998,12.795,29.955,0.000,0.045 29.5,0.002,0.000,0.998,12.795,29.957,0.000,0.044 29.6,0.002,0.000,0.998,12.795,29.958,0.000,0.043 29.7,0.002,0.000,0.998,12.795,29.959,0.000,0.042 29.8,0.002,0.000,0.998,12.795,29.960,0.000,0.041 29.9,0.002,0.000,0.998,12.795,29.961,0.000,0.040 30,0.002,0.000,0.998,12.795,29.962,0.000,0.039 30.1,0.002,0.000,0.998,12.795,29.963,0.000,0.037 30.2,0.002,0.000,0.998,12.795,29.964,0.000,0.037 30.3,0.002,0.000,0.998,12.795,29.965,0.000,0.036 30.4,0.002,0.000,0.998,12.795,29.966,0.000,0.035 30.5,0.002,0.000,0.998,12.795,29.967,0.000,0.034 30.6,0.002,0.000,0.998,12.795,29.968,0.000,0.033 30.7,0.002,0.000,0.998,12.795,29.969,0.000,0.032 30.8,0.002,0.000,0.998,12.795,29.970,0.000,0.031 30.9,0.002,0.000,0.998,12.795,29.971,0.000,0.030 31,0.002,0.000,0.998,12.795,29.971,0.000,0.029 31.1,0.002,0.000,0.998,12.795,29.972,0.000,0.029 31.2,0.002,0.000,0.998,12.795,29.973,0.000,0.028 31.3,0.002,0.000,0.998,12.795,29.974,0.000,0.027 31.4,0.002,0.000,0.998,12.795,29.974,0.000,0.026 31.5,0.002,0.000,0.998,12.795,29.975,0.000,0.026 31.6,0.002,0.000,0.998,12.795,29.976,0.000,0.025 31.7,0.002,0.000,0.998,12.795,29.976,0.000,0.024 31.8,0.002,0.000,0.998,12.795,29.977,0.000,0.024 31.9,0.002,0.000,0.998,12.795,29.978,0.000,0.023 32,0.002,0.000,0.998,12.795,29.978,0.000,0.023 32.1,0.002,0.000,0.998,12.795,29.979,0.000,0.022 32.2,0.002,0.000,0.998,12.795,29.979,0.000,0.021 32.3,0.002,0.000,0.998,12.795,29.980,0.000,0.021 32.4,0.002,0.000,0.998,12.795,29.981,0.000,0.020 32.5,0.002,0.000,0.998,12.795,29.981,0.000,0.020 32.6,0.002,0.000,0.998,12.795,29.982,0.000,0.019 32.7,0.002,0.000,0.998,12.795,29.982,0.000,0.019 32.8,0.002,0.000,0.998,12.795,29.983,0.000,0.018 32.9,0.002,0.000,0.998,12.795,29.983,0.000,0.018 33,0.002,0.000,0.998,12.795,29.984,0.000,0.017 33.1,0.002,0.000,0.998,12.795,29.984,0.000,0.017 33.2,0.002,0.000,0.998,12.795,29.985,0.000,0.016 33.3,0.002,0.000,0.998,12.795,29.985,0.000,0.016 33.4,0.002,0.000,0.998,12.795,29.985,0.000,0.015 33.5,0.002,0.000,0.998,12.795,29.986,0.000,0.015 33.6,0.002,0.000,0.998,12.795,29.986,0.000,0.015 33.7,0.002,0.000,0.998,12.795,29.987,0.000,0.014 33.8,0.002,0.000,0.998,12.795,29.987,0.000,0.014 33.9,0.002,0.000,0.998,12.795,29.987,0.000,0.014 34,0.002,0.000,0.998,12.795,29.988,0.000,0.013 34.1,0.002,0.000,0.998,12.795,29.988,0.000,0.013 34.2,0.002,0.000,0.998,12.795,29.988,0.000,0.012 34.3,0.002,0.000,0.998,12.795,29.989,0.000,0.012 34.4,0.002,0.000,0.998,12.795,29.989,0.000,0.012 34.5,0.002,0.000,0.998,12.795,29.989,0.000,0.012 34.6,0.002,0.000,0.998,12.795,29.990,0.000,0.011 34.7,0.002,0.000,0.998,12.795,29.990,0.000,0.011 34.8,0.002,0.000,0.998,12.795,29.990,0.000,0.011 34.9,0.002,0.000,0.998,12.795,29.991,0.000,0.010 35,0.002,0.000,0.998,12.795,29.991,0.000,0.010 35.1,0.002,0.000,0.998,12.795,29.991,0.000,0.010 35.2,0.002,0.000,0.998,12.795,29.991,0.000,0.010 35.3,0.002,0.000,0.998,12.795,29.992,0.000,0.009 35.4,0.002,0.000,0.998,12.795,29.992,0.000,0.009 35.5,0.002,0.000,0.998,12.795,29.992,0.000,0.009 35.6,0.002,0.000,0.998,12.795,29.992,0.000,0.009 35.7,0.002,0.000,0.998,12.795,29.993,0.000,0.008 35.8,0.002,0.000,0.998,12.795,29.993,0.000,0.008 35.9,0.002,0.000,0.998,12.795,29.993,0.000,0.008 36,0.002,0.000,0.998,12.795,29.993,0.000,0.008 36.1,0.002,0.000,0.998,12.795,29.993,0.000,0.008 36.2,0.002,0.000,0.998,12.795,29.994,0.000,0.007 36.3,0.002,0.000,0.998,12.795,29.994,0.000,0.007 36.4,0.002,0.000,0.998,12.795,29.994,0.000,0.007 36.5,0.002,0.000,0.998,12.795,29.994,0.000,0.007 36.6,0.002,0.000,0.998,12.795,29.994,0.000,0.007 36.7,0.002,0.000,0.998,12.795,29.995,0.000,0.006 36.8,0.002,0.000,0.998,12.795,29.995,0.000,0.006 36.9,0.002,0.000,0.998,12.795,29.995,0.000,0.006 37,0.002,0.000,0.998,12.795,29.995,0.000,0.006 37.1,0.002,0.000,0.998,12.795,29.995,0.000,0.006 37.2,0.002,0.000,0.998,12.795,29.995,0.000,0.006 37.3,0.002,0.000,0.998,12.795,29.996,0.000,0.005 37.4,0.002,0.000,0.998,12.795,29.996,0.000,0.005 37.5,0.002,0.000,0.998,12.795,29.996,0.000,0.005 37.6,0.002,0.000,0.998,12.795,29.996,0.000,0.005 37.7,0.002,0.000,0.998,12.795,29.996,0.000,0.005 37.8,0.002,0.000,0.998,12.795,29.996,0.000,0.005 37.9,0.002,0.000,0.998,12.795,29.996,0.000,0.005 38,0.002,0.000,0.998,12.795,29.996,0.000,0.005 38.1,0.002,0.000,0.998,12.795,29.997,0.000,0.004 38.2,0.002,0.000,0.998,12.795,29.997,0.000,0.004 38.3,0.002,0.000,0.998,12.795,29.997,0.000,0.004 38.4,0.002,0.000,0.998,12.795,29.997,0.000,0.004 38.5,0.002,0.000,0.998,12.795,29.997,0.000,0.004 38.6,0.002,0.000,0.998,12.795,29.997,0.000,0.004 38.7,0.002,0.000,0.998,12.795,29.997,0.000,0.004 38.8,0.002,0.000,0.998,12.795,29.997,0.000,0.004 38.9,0.002,0.000,0.998,12.795,29.997,0.000,0.004 39,0.002,0.000,0.998,12.795,29.998,0.000,0.003 39.1,0.002,0.000,0.998,12.795,29.998,0.000,0.003 39.2,0.002,0.000,0.998,12.795,29.998,0.000,0.003 39.3,0.002,0.000,0.998,12.795,29.998,0.000,0.003 39.4,0.002,0.000,0.998,12.795,29.998,0.000,0.003 39.5,0.002,0.000,0.998,12.795,29.998,0.000,0.003 39.6,0.002,0.000,0.998,12.795,29.998,0.000,0.003 39.7,0.002,0.000,0.998,12.795,29.998,0.000,0.003 39.8,0.002,0.000,0.998,12.795,29.998,0.000,0.003 39.9,0.002,0.000,0.998,12.795,29.998,0.000,0.003 40,0.002,0.000,0.998,12.795,29.998,0.000,0.003 40.1,0.002,0.000,0.998,12.795,29.998,0.000,0.003 40.2,0.002,0.000,0.998,12.795,29.998,0.000,0.002 40.3,0.002,0.000,0.998,12.795,29.999,0.000,0.002 40.4,0.002,0.000,0.998,12.795,29.999,0.000,0.002 40.5,0.002,0.000,0.998,12.795,29.999,0.000,0.002 40.6,0.002,0.000,0.998,12.795,29.999,0.000,0.002 40.7,0.002,0.000,0.998,12.795,29.999,0.000,0.002 40.8,0.002,0.000,0.998,12.795,29.999,0.000,0.002 40.9,0.002,0.000,0.998,12.795,29.999,0.000,0.002 41,0.002,0.000,0.998,12.795,29.999,0.000,0.002 41.1,0.002,0.000,0.998,12.795,29.999,0.000,0.002 41.2,0.002,0.000,0.998,12.795,29.999,0.000,0.002 41.3,0.002,0.000,0.998,12.795,29.999,0.000,0.002 41.4,0.002,0.000,0.998,12.795,29.999,0.000,0.002 41.5,0.002,0.000,0.998,12.795,29.999,0.000,0.002 41.6,0.002,0.000,0.998,12.795,29.999,0.000,0.002 41.7,0.002,0.000,0.998,12.795,29.999,0.000,0.002 41.8,0.002,0.000,0.998,12.795,29.999,0.000,0.002 41.9,0.002,0.000,0.998,12.795,29.999,0.000,0.002 42,0.002,0.000,0.998,12.795,29.999,0.000,0.002 42.1,0.002,0.000,0.998,12.795,29.999,0.000,0.001 42.2,0.002,0.000,0.998,12.795,30.000,0.000,0.001 42.3,0.002,0.000,0.998,12.795,30.000,0.000,0.001 42.4,0.002,0.000,0.998,12.795,30.000,0.000,0.001 42.5,0.002,0.000,0.998,12.795,30.000,0.000,0.001 42.6,0.002,0.000,0.998,12.795,30.000,0.000,0.001 42.7,0.002,0.000,0.998,12.795,30.000,0.000,0.001 42.8,0.002,0.000,0.998,12.795,30.000,0.000,0.001 42.9,0.002,0.000,0.998,12.795,30.000,0.000,0.001 43,0.002,0.000,0.998,12.795,30.000,0.000,0.001 43.1,0.002,0.000,0.998,12.795,30.000,0.000,0.001 43.2,0.002,0.000,0.998,12.795,30.000,0.000,0.001 43.3,0.002,0.000,0.998,12.795,30.000,0.000,0.001 43.4,0.002,0.000,0.998,12.795,30.000,0.000,0.001 43.5,0.002,0.000,0.998,12.795,30.000,0.000,0.001 43.6,0.002,0.000,0.998,12.795,30.000,0.000,0.001 43.7,0.002,0.000,0.998,12.795,30.000,0.000,0.001 43.8,0.002,0.000,0.998,12.795,30.000,0.000,0.001 43.9,0.002,0.000,0.998,12.795,30.000,0.000,0.001 44,0.002,0.000,0.998,12.795,30.000,0.000,0.001 44.1,0.002,0.000,0.998,12.795,30.000,0.000,0.001 44.2,0.002,0.000,0.998,12.795,30.000,0.000,0.001 44.3,0.002,0.000,0.998,12.795,30.000,0.000,0.001 44.4,0.002,0.000,0.998,12.795,30.000,0.000,0.001 44.5,0.002,0.000,0.998,12.795,30.000,0.000,0.001 44.6,0.002,0.000,0.998,12.795,30.000,0.000,0.001 44.7,0.002,0.000,0.998,12.795,30.000,0.000,0.001 44.8,0.002,0.000,0.998,12.795,30.000,0.000,0.001 44.9,0.002,0.000,0.998,12.795,30.000,0.000,0.001 45,0.002,0.000,0.998,12.795,30.000,0.000,0.001 45.1,0.002,0.000,0.998,12.795,30.000,0.000,0.001 45.2,0.002,0.000,0.998,12.795,30.000,0.000,0.001 45.3,0.002,0.000,0.998,12.795,30.000,0.000,0.001 45.4,0.002,0.000,0.998,12.795,30.000,0.000,0.001 45.5,0.002,0.000,0.998,12.795,30.000,0.000,0.001 45.6,0.002,0.000,0.998,12.795,30.000,0.000,0.001 45.7,0.002,0.000,0.998,12.795,30.000,0.000,0.001 45.8,0.002,0.000,0.998,12.795,30.000,0.000,0.001 45.9,0.002,0.000,0.998,12.795,30.000,0.000,0.001 46,0.002,0.000,0.998,12.795,30.000,0.000,0.001 46.1,0.002,0.000,0.998,12.795,30.000,0.000,0.001 46.2,0.002,0.000,0.998,12.795,30.000,0.000,0.000 46.3,0.002,0.000,0.998,12.795,30.000,0.000,0.000 46.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 46.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 46.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 46.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 46.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 46.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 47,0.002,0.000,0.998,12.795,30.001,0.000,0.000 47.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 47.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 47.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 47.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 47.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 47.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 47.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 47.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 47.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 48,0.002,0.000,0.998,12.795,30.001,0.000,0.000 48.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 48.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 48.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 48.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 48.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 48.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 48.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 48.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 48.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 49,0.002,0.000,0.998,12.795,30.001,0.000,0.000 49.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 49.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 49.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 49.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 49.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 49.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 49.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 49.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 49.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 50,0.002,0.000,0.998,12.795,30.001,0.000,0.000 50.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 50.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 50.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 50.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 50.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 50.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 50.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 50.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 50.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 51,0.002,0.000,0.998,12.795,30.001,0.000,0.000 51.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 51.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 51.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 51.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 51.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 51.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 51.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 51.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 51.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 52,0.002,0.000,0.998,12.795,30.001,0.000,0.000 52.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 52.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 52.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 52.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 52.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 52.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 52.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 52.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 52.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 53,0.002,0.000,0.998,12.795,30.001,0.000,0.000 53.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 53.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 53.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 53.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 53.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 53.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 53.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 53.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 53.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 54,0.002,0.000,0.998,12.795,30.001,0.000,0.000 54.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 54.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 54.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 54.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 54.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 54.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 54.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 54.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 54.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 55,0.002,0.000,0.998,12.795,30.001,0.000,0.000 55.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 55.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 55.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 55.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 55.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 55.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 55.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 55.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 55.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 56,0.002,0.000,0.998,12.795,30.001,0.000,0.000 56.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 56.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 56.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 56.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 56.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 56.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 56.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 56.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 56.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 57,0.002,0.000,0.998,12.795,30.001,0.000,0.000 57.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 57.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 57.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 57.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 57.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 57.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 57.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 57.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 57.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 58,0.002,0.000,0.998,12.795,30.001,0.000,0.000 58.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 58.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 58.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 58.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 58.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 58.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 58.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 58.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 58.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 59,0.002,0.000,0.998,12.795,30.001,0.000,0.000 59.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 59.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 59.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 59.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 59.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 59.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 59.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 59.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 59.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 60,0.002,0.000,0.998,12.795,30.001,0.000,0.000 60.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 60.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 60.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 60.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 60.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 60.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 60.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 60.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 60.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 61,0.002,0.000,0.998,12.795,30.001,0.000,0.000 61.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 61.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 61.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 61.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 61.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 61.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 61.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 61.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 61.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 62,0.002,0.000,0.998,12.795,30.001,0.000,0.000 62.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 62.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 62.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 62.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 62.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 62.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 62.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 62.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 62.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 63,0.002,0.000,0.998,12.795,30.001,0.000,0.000 63.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 63.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 63.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 63.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 63.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 63.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 63.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 63.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 63.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 64,0.002,0.000,0.998,12.795,30.001,0.000,0.000 64.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 64.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 64.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 64.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 64.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 64.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 64.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 64.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 64.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 65,0.002,0.000,0.998,12.795,30.001,0.000,0.000 65.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 65.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 65.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 65.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 65.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 65.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 65.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 65.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 65.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 66,0.002,0.000,0.998,12.795,30.001,0.000,0.000 66.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 66.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 66.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 66.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 66.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 66.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 66.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 66.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 66.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 67,0.002,0.000,0.998,12.795,30.001,0.000,0.000 67.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 67.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 67.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 67.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 67.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 67.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 67.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 67.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 67.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 68,0.002,0.000,0.998,12.795,30.001,0.000,0.000 68.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 68.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 68.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 68.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 68.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 68.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 68.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 68.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 68.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 69,0.002,0.000,0.998,12.795,30.001,0.000,0.000 69.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 69.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 69.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 69.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 69.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 69.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 69.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 69.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 69.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 70,0.002,0.000,0.998,12.795,30.001,0.000,0.000 70.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 70.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 70.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 70.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 70.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 70.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 70.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 70.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 70.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 71,0.002,0.000,0.998,12.795,30.001,0.000,0.000 71.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 71.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 71.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 71.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 71.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 71.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 71.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 71.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 71.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 72,0.002,0.000,0.998,12.795,30.001,0.000,0.000 72.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 72.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 72.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 72.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 72.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 72.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 72.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 72.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 72.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 73,0.002,0.000,0.998,12.795,30.001,0.000,0.000 73.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 73.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 73.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 73.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 73.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 73.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 73.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 73.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 73.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 74,0.002,0.000,0.998,12.795,30.001,0.000,0.000 74.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 74.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 74.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 74.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 74.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 74.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 74.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 74.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 74.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 75,0.002,0.000,0.998,12.795,30.001,0.000,0.000 75.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 75.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 75.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 75.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 75.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 75.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 75.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 75.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 75.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 76,0.002,0.000,0.998,12.795,30.001,0.000,0.000 76.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 76.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 76.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 76.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 76.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 76.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 76.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 76.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 76.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 77,0.002,0.000,0.998,12.795,30.001,0.000,0.000 77.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 77.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 77.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 77.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 77.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 77.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 77.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 77.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 77.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 78,0.002,0.000,0.998,12.795,30.001,0.000,0.000 78.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 78.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 78.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 78.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 78.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 78.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 78.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 78.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 78.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 79,0.002,0.000,0.998,12.795,30.001,0.000,0.000 79.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 79.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 79.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 79.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 79.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 79.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 79.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 79.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 79.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 80,0.002,0.000,0.998,12.795,30.001,0.000,0.000 80.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 80.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 80.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 80.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 80.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 80.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 80.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 80.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 80.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 81,0.002,0.000,0.998,12.795,30.001,0.000,0.000 81.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 81.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 81.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 81.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 81.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 81.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 81.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 81.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 81.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 82,0.002,0.000,0.998,12.795,30.001,0.000,0.000 82.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 82.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 82.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 82.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 82.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 82.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 82.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 82.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 82.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 83,0.002,0.000,0.998,12.795,30.001,0.000,0.000 83.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 83.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 83.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 83.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 83.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 83.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 83.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 83.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 83.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 84,0.002,0.000,0.998,12.795,30.001,0.000,0.000 84.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 84.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 84.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 84.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 84.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 84.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 84.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 84.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 84.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 85,0.002,0.000,0.998,12.795,30.001,0.000,0.000 85.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 85.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 85.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 85.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 85.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 85.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 85.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 85.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 85.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 86,0.002,0.000,0.998,12.795,30.001,0.000,0.000 86.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 86.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 86.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 86.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 86.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 86.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 86.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 86.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 86.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 87,0.002,0.000,0.998,12.795,30.001,0.000,0.000 87.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 87.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 87.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 87.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 87.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 87.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 87.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 87.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 87.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 88,0.002,0.000,0.998,12.795,30.001,0.000,0.000 88.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 88.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 88.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 88.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 88.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 88.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 88.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 88.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 88.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 89,0.002,0.000,0.998,12.795,30.001,0.000,0.000 89.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 89.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 89.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 89.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 89.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 89.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 89.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 89.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 89.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 90,0.002,0.000,0.998,12.795,30.001,0.000,0.000 90.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 90.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 90.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 90.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 90.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 90.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 90.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 90.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 90.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 91,0.002,0.000,0.998,12.795,30.001,0.000,0.000 91.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 91.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 91.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 91.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 91.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 91.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 91.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 91.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 91.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 92,0.002,0.000,0.998,12.795,30.001,0.000,0.000 92.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 92.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 92.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 92.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 92.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 92.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 92.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 92.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 92.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 93,0.002,0.000,0.998,12.795,30.001,0.000,0.000 93.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 93.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 93.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 93.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 93.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 93.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 93.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 93.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 93.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 94,0.002,0.000,0.998,12.795,30.001,0.000,0.000 94.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 94.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 94.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 94.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 94.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 94.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 94.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 94.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 94.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 95,0.002,0.000,0.998,12.795,30.001,0.000,0.000 95.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 95.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 95.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 95.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 95.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 95.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 95.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 95.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 95.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 96,0.002,0.000,0.998,12.795,30.001,0.000,0.000 96.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 96.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 96.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 96.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 96.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 96.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 96.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 96.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 96.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 97,0.002,0.000,0.998,12.795,30.001,0.000,0.000 97.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 97.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 97.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 97.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 97.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 97.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 97.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 97.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 97.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 98,0.002,0.000,0.998,12.795,30.001,0.000,0.000 98.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 98.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 98.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 98.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 98.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 98.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 98.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 98.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 98.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 99,0.002,0.000,0.998,12.795,30.001,0.000,0.000 99.1,0.002,0.000,0.998,12.795,30.001,0.000,0.000 99.2,0.002,0.000,0.998,12.795,30.001,0.000,0.000 99.3,0.002,0.000,0.998,12.795,30.001,0.000,0.000 99.4,0.002,0.000,0.998,12.795,30.001,0.000,0.000 99.5,0.002,0.000,0.998,12.795,30.001,0.000,0.000 99.6,0.002,0.000,0.998,12.795,30.001,0.000,0.000 99.7,0.002,0.000,0.998,12.795,30.001,0.000,0.000 99.8,0.002,0.000,0.998,12.795,30.001,0.000,0.000 99.9,0.002,0.000,0.998,12.795,30.001,0.000,0.000 100,0.002,0.000,0.998,12.795,30.001,0.000,0.000 asymptote-2.37/doc/shadedtiling.asy000066400000000000000000000004001265434602500174150ustar00rootroot00000000000000size(0,100); import patterns; real d=4mm; picture tiling; path square=scale(d)*unitsquare; axialshade(tiling,square,white,(0,0),black,(d,d)); fill(tiling,shift(d,d)*square,blue); add("shadedtiling",tiling); filldraw(unitcircle,pattern("shadedtiling")); asymptote-2.37/doc/slopefield1.asy000066400000000000000000000002321265434602500171700ustar00rootroot00000000000000import slopefield; size(200); real func(real x) {return 2x;} add(slopefield(func,(-3,-3),(3,3),20,Arrow)); draw(curve((0,0),func,(-3,-3),(3,3)),red); asymptote-2.37/doc/square.asy000066400000000000000000000000641265434602500162640ustar00rootroot00000000000000size(3cm); draw((0,0)--(1,0)--(1,1)--(0,1)--cycle); asymptote-2.37/doc/subpictures.asy000066400000000000000000000005251265434602500173360ustar00rootroot00000000000000picture pic1; real size=50; size(pic1,size); fill(pic1,(0,0)--(50,100)--(100,0)--cycle,red); picture pic2; size(pic2,size); fill(pic2,unitcircle,green); picture pic3; size(pic3,size); fill(pic3,unitsquare,blue); picture pic; add(pic,pic1.fit(),(0,0),N); add(pic,pic2.fit(),(0,0),10S); add(pic.fit(),(0,0),N); add(pic3.fit(),(0,0),10S); asymptote-2.37/doc/superpath.asy000066400000000000000000000001731265434602500170000ustar00rootroot00000000000000size(0,100); path unitcircle=E..N..W..S..cycle; path g=scale(2)*unitcircle; filldraw(unitcircle^^g,evenodd+yellow,black); asymptote-2.37/doc/tile.asy000066400000000000000000000006061265434602500157230ustar00rootroot00000000000000size(0,90); import patterns; add("tile",tile()); add("filledtilewithmargin",tile(6mm,4mm,red,Fill),(1mm,1mm),(1mm,1mm)); add("checker",checker()); add("brick",brick()); real s=2.5; filldraw(unitcircle,pattern("tile")); filldraw(shift(s,0)*unitcircle,pattern("filledtilewithmargin")); filldraw(shift(2s,0)*unitcircle,pattern("checker")); filldraw(shift(3s,0)*unitcircle,pattern("brick")); asymptote-2.37/doc/triangulate.asy000066400000000000000000000006141265434602500173040ustar00rootroot00000000000000size(200); int np=100; pair[] points; real r() {return 1.2*(rand()/randMax*2-1);} for(int i=0; i < np; ++i) points.push((r(),r())); int[][] trn=triangulate(points); for(int i=0; i < trn.length; ++i) { draw(points[trn[i][0]]--points[trn[i][1]]); draw(points[trn[i][1]]--points[trn[i][2]]); draw(points[trn[i][2]]--points[trn[i][0]]); } for(int i=0; i < np; ++i) dot(points[i],red); asymptote-2.37/doc/unitcircle3.asy000066400000000000000000000002721265434602500172110ustar00rootroot00000000000000import three; size(100); path3 g=(1,0,0)..(0,1,0)..(-1,0,0)..(0,-1,0)..cycle; draw(g); draw(O--Z,red+dashed,Arrow3); draw(((-1,-1,0)--(1,-1,0)--(1,1,0)--(-1,1,0)--cycle)); dot(g,red); asymptote-2.37/doc/vectorfield.asy000066400000000000000000000002231265434602500172670ustar00rootroot00000000000000import graph; size(100); pair a=(0,0); pair b=(2pi,2pi); path vector(pair z) {return (0,0)--(sin(z.x),cos(z.y));} add(vectorfield(vector,a,b)); asymptote-2.37/doc/westnile.asy000066400000000000000000000033221265434602500166160ustar00rootroot00000000000000import graph; size(9cm,8cm,IgnoreAspect); string data="westnile.csv"; file in=input(data).line().csv(); string[] columnlabel=in; real[][] A=in; A=transpose(A); real[] number=A[0], survival=A[1]; path g=graph(number,survival); draw(g); scale(true); xaxis("Initial no.\ of mosquitoes per bird ($S_{M_0}/N_{B_0}$)", Bottom,LeftTicks); xaxis(Top); yaxis("Susceptible bird survival",Left,RightTicks(trailingzero)); yaxis(Right); real a=number[0]; real b=number[number.length-1]; real S1=0.475; path h1=(a,S1)--(b,S1); real M1=interp(a,b,intersect(h1,g)[0]); real S2=0.9; path h2=(a,S2)--(b,S2); real M2=interp(a,b,intersect(h2,g)[0]); labelx("$M_1$",M1); labelx("$M_2$",M2); draw((a,S2)--(M2,S2)--(M2,0),Dotted); draw((a,S1)--(M1,S1)--(M1,0),dashed); pen p=fontsize(10pt); real y3=0.043; path reduction=(M1,y3)--(M2,y3); draw(reduction,Arrow,TrueMargin(0,0.5*(linewidth(Dotted)+linewidth()))); arrow(shift(-20,5)*Label(minipage("\flushleft{\begin{itemize}\item[1.] Estimate proportion of birds surviving at end of season\end{itemize}}",100), align=NNE), (M1,S1),NNE,1cm,p,Arrow(NoFill)); arrow(shift(-24,5)*Label(minipage("\flushleft{\begin{itemize}\item[2.] Read off initial mosquito abundance\end{itemize}}",80),align=NNE), (M1,0),NE,2cm,p,Arrow(NoFill)); arrow(shift(20,0)*Label(minipage("\flushleft{\begin{itemize}\item[3.] Determine desired bird survival for next season\end{itemize}}",90),align=SW), (M2,S2),SW,arrowlength,p,Arrow(NoFill)); arrow(shift(8,-15)*Label(minipage("\flushleft{\begin{itemize}\item[4.] Calculate required proportional reduction in mosquitoes\end{itemize}}",90), align=NW), point(reduction,0.5),NW,1.5cm,p,Arrow(NoFill)); asymptote-2.37/doc/westnile.csv000066400000000000000000000111671265434602500166230ustar00rootroot00000000000000sm0,0.001(T14) 0.0,0.9973 0.1,0.9973 0.2,0.9972 0.3,0.9972 0.4,0.9971 0.5,0.9971 0.6,0.9970 0.7,0.9970 0.8,0.9969 0.9,0.9968 1.0,0.9968 1.1,0.9967 1.2,0.9966 1.3,0.9966 1.4,0.9965 1.5,0.9964 1.6,0.9963 1.7,0.9963 1.8,0.9962 1.9,0.9961 2.0,0.9960 2.1,0.9959 2.2,0.9958 2.3,0.9957 2.4,0.9957 2.5,0.9956 2.6,0.9955 2.7,0.9954 2.8,0.9952 2.9,0.9951 3.0,0.9950 3.1,0.9949 3.2,0.9948 3.3,0.9947 3.4,0.9945 3.5,0.9944 3.6,0.9943 3.7,0.9941 3.8,0.9940 3.9,0.9939 4.0,0.9937 4.1,0.9936 4.2,0.9934 4.3,0.9932 4.4,0.9931 4.5,0.9929 4.6,0.9927 4.7,0.9926 4.8,0.9924 4.9,0.9922 5.0,0.9920 5.1,0.9918 5.2,0.9916 5.3,0.9914 5.4,0.9912 5.5,0.9909 5.6,0.9907 5.7,0.9905 5.8,0.9902 5.9,0.9900 6.0,0.9897 6.1,0.9895 6.2,0.9892 6.3,0.9889 6.4,0.9887 6.5,0.9884 6.6,0.9881 6.7,0.9878 6.8,0.9875 6.9,0.9872 7.0,0.9868 7.1,0.9865 7.2,0.9861 7.3,0.9858 7.4,0.9854 7.5,0.9851 7.6,0.9847 7.7,0.9843 7.8,0.9839 7.9,0.9835 8.0,0.9831 8.1,0.9826 8.2,0.9822 8.3,0.9818 8.4,0.9813 8.5,0.9808 8.6,0.9803 8.7,0.9798 8.8,0.9793 8.9,0.9788 9.0,0.9783 9.1,0.9777 9.2,0.9772 9.3,0.9766 9.4,0.9760 9.5,0.9754 9.6,0.9748 9.7,0.9742 9.8,0.9735 9.9,0.9729 10.0,0.9722 10.1,0.9715 10.2,0.9708 10.3,0.9701 10.4,0.9694 10.5,0.9686 10.6,0.9679 10.7,0.9671 10.8,0.9663 10.9,0.9654 11.0,0.9646 11.1,0.9637 11.2,0.9629 11.3,0.9620 11.4,0.9611 11.5,0.9601 11.6,0.9592 11.7,0.9582 11.8,0.9572 11.9,0.9562 12.0,0.9551 12.1,0.9541 12.2,0.9530 12.3,0.9519 12.4,0.9507 12.5,0.9496 12.6,0.9484 12.7,0.9472 12.8,0.9460 12.9,0.9447 13.0,0.9434 13.1,0.9421 13.2,0.9408 13.3,0.9394 13.4,0.9380 13.5,0.9366 13.6,0.9352 13.7,0.9337 13.8,0.9322 13.9,0.9307 14.0,0.9291 14.1,0.9275 14.2,0.9259 14.3,0.9243 14.4,0.9226 14.5,0.9209 14.6,0.9191 14.7,0.9174 14.8,0.9156 14.9,0.9137 15.0,0.9118 15.1,0.9099 15.2,0.9080 15.3,0.9060 15.4,0.9041 15.5,0.9020 15.6,0.8999 15.7,0.8978 15.8,0.8956 15.9,0.8934 16.0,0.8912 16.1,0.8889 16.2,0.8866 16.3,0.8843 16.4,0.8819 16.5,0.8795 16.6,0.8770 16.7,0.8745 16.8,0.8720 16.9,0.8694 17.0,0.8668 17.1,0.8641 17.2,0.8614 17.3,0.8587 17.4,0.8559 17.5,0.8531 17.6,0.8502 17.7,0.8473 17.8,0.8444 17.9,0.8414 18.0,0.8383 18.1,0.8353 18.2,0.8323 18.3,0.8291 18.4,0.8259 18.5,0.8227 18.6,0.8194 18.7,0.8160 18.8,0.8127 18.9,0.8092 19.0,0.8058 19.1,0.8022 19.2,0.7987 19.3,0.7951 19.4,0.7914 19.5,0.7878 19.6,0.7840 19.7,0.7803 19.8,0.7764 19.9,0.7726 20.0,0.7687 20.1,0.7647 20.2,0.7607 20.3,0.7567 20.4,0.7526 20.5,0.7485 20.6,0.7443 20.7,0.7401 20.8,0.7359 20.9,0.7316 21.0,0.7272 21.1,0.7229 21.2,0.7185 21.3,0.7140 21.4,0.7096 21.5,0.7050 21.6,0.7005 21.7,0.6959 21.8,0.6912 21.9,0.6866 22.0,0.6819 22.1,0.6771 22.2,0.6723 22.3,0.6675 22.4,0.6627 22.5,0.6578 22.6,0.6530 22.7,0.6480 22.8,0.6430 22.9,0.6380 23.0,0.6330 23.1,0.6280 23.2,0.6229 23.3,0.6178 23.4,0.6126 23.5,0.6075 23.6,0.6023 23.7,0.5971 23.8,0.5918 23.9,0.5866 24.0,0.5813 24.1,0.5760 24.2,0.5706 24.3,0.5653 24.4,0.5600 24.5,0.5547 24.6,0.5493 24.7,0.5440 24.8,0.5385 24.9,0.5332 25.0,0.5278 25.1,0.5224 25.2,0.5170 25.3,0.5115 25.4,0.5061 25.5,0.5007 25.6,0.4952 25.7,0.4898 25.8,0.4844 25.9,0.4789 26.0,0.4735 26.1,0.4681 26.2,0.4627 26.3,0.4572 26.4,0.4518 26.5,0.4464 26.6,0.4410 26.7,0.4356 26.8,0.4303 26.9,0.4249 27.0,0.4194 27.1,0.4143 27.2,0.4089 27.3,0.4036 27.4,0.3983 27.5,0.3931 27.6,0.3878 27.7,0.3826 27.8,0.3774 27.9,0.3724 28.0,0.3672 28.1,0.3621 28.2,0.3571 28.3,0.3520 28.4,0.3470 28.5,0.3420 28.6,0.3370 28.7,0.3320 28.8,0.3271 28.9,0.3223 29.0,0.3174 29.1,0.3126 29.2,0.3078 29.3,0.3031 29.4,0.2983 29.5,0.2936 29.6,0.2890 29.7,0.2845 29.8,0.2801 29.9,0.2756 30.0,0.2711 30.1,0.2667 30.2,0.2623 30.3,0.2580 30.4,0.2537 30.5,0.2495 30.6,0.2453 30.7,0.2411 30.8,0.2370 30.9,0.2329 31.0,0.2289 31.1,0.2250 31.2,0.2210 31.3,0.2171 31.4,0.2133 31.5,0.2095 31.6,0.2057 31.7,0.2019 31.8,0.1983 31.9,0.1947 32.0,0.1912 32.1,0.1876 32.2,0.1842 32.3,0.1807 32.4,0.1773 32.5,0.1740 32.6,0.1707 32.7,0.1674 32.8,0.1642 32.9,0.1611 33.0,0.1580 33.1,0.1549 33.2,0.1520 33.3,0.1490 33.4,0.1461 33.5,0.1432 33.6,0.1404 33.7,0.1376 33.8,0.1348 33.9,0.1321 34.0,0.1294 34.1,0.1268 34.2,0.1242 34.3,0.1217 34.4,0.1193 34.5,0.1168 34.6,0.1144 34.7,0.1120 34.8,0.1097 34.9,0.1074 35.0,0.1052 35.1,0.1029 35.2,0.1008 35.3,0.0987 35.4,0.0966 35.5,0.0946 35.6,0.0925 35.7,0.0905 35.8,0.0886 35.9,0.0867 36.0,0.0848 36.1,0.0830 36.2,0.0812 36.3,0.0794 36.4,0.0777 36.5,0.0760 36.6,0.0743 36.7,0.0727 36.8,0.0711 36.9,0.0696 37.0,0.0680 37.1,0.0665 37.2,0.0651 37.3,0.0636 37.4,0.0622 37.5,0.0608 37.6,0.0595 37.7,0.0581 37.8,0.0568 37.9,0.0555 38.0,0.0543 38.1,0.0531 38.2,0.0519 38.3,0.0507 38.4,0.0495 38.5,0.0484 38.6,0.0473 38.7,0.0462 38.8,0.0452 38.9,0.0441 39.0,0.0431 39.1,0.0421 39.2,0.0412 39.3,0.0402 39.4,0.0393 39.5,0.0384 39.6,0.0375 39.7,0.0366 39.8,0.0358 39.9,0.0350 40.0,0.0342 asymptote-2.37/doc/xasy.1x000066400000000000000000000015601265434602500155060ustar00rootroot00000000000000.\" Hey, EMACS: -*- nroff -*- .TH XASY 1x "27 Nov 2007" .SH NAME asy \- script-based vector graphics language .SH SYNOPSIS .B xasy .RI " [-x magnification] [filename]" .SH DESCRIPTION \fBAsymptote\fP is a powerful descriptive vector graphics language for technical drawing, inspired by MetaPost but with an improved C++\-like syntax. Asymptote provides for figures the same high\-quality level of typesetting that LaTeX does for scientific text. .PP \fBxasy\fP is a GUI for Asymptote that allows for final figure adjustments. .SH OPTIONS .TP .B \-x magnification Initial zoom. .SH SEE ALSO Asymptote and xasy are documented fully in the Asymptote Info page. .SH AUTHOR Asymptote was written by Andy Hammerlindl, John Bowman, and Tom Prince. .PP This manual page was written by Hubert Chan for the Debian project (but may be used by others). asymptote-2.37/drawclipbegin.h000066400000000000000000000034201265434602500164630ustar00rootroot00000000000000/***** * drawclipbegin.h * John Bowman * * Begin clip of picture to specified path. *****/ #ifndef DRAWCLIPBEGIN_H #define DRAWCLIPBEGIN_H #include "drawelement.h" #include "path.h" #include "drawpath.h" namespace camp { class drawClipBegin : public drawSuperPathPenBase { bool gsave; bool stroke; public: void noncyclic() { reportError("cannot clip to non-cyclic path"); } drawClipBegin(const vm::array& src, bool stroke, pen pentype, bool gsave=true) : drawSuperPathPenBase(src,pentype), gsave(gsave), stroke(stroke) { if(!stroke && !cyclic()) noncyclic(); } virtual ~drawClipBegin() {} bool beginclip() {return true;} void bounds(bbox& b, iopipestream& iopipe, boxvector& vbox, bboxlist& bboxstack) { bboxstack.push_back(b); bbox bpath; if(stroke) strokebounds(bpath); else drawSuperPathPenBase::bounds(bpath,iopipe,vbox,bboxstack); bboxstack.push_back(bpath); } bool begingroup() {return true;} bool svg() {return true;} void save(bool b) { gsave=b; } bool draw(psfile *out) { if(gsave) out->gsave(); if(empty()) return true; out->beginclip(); writepath(out,false); if(stroke) strokepath(out); out->endclip(pentype); return true; } bool write(texfile *out, const bbox& bpath) { if(gsave) out->gsave(); if(empty()) return true; if(out->toplevel()) out->beginpicture(bpath); out->begingroup(); out->beginspecial(); out->beginraw(); writeshiftedpath(out); if(stroke) strokepath(out); out->endclip(pentype); out->endraw(); out->endspecial(); return true; } drawElement *transformed(const transform& t) { return new drawClipBegin(transpath(t),stroke,transpen(t)); } }; } #endif asymptote-2.37/drawclipend.h000066400000000000000000000022751265434602500161540ustar00rootroot00000000000000/***** * drawclipend.h * John Bowman * * End clip of picture to specified path. *****/ #ifndef DRAWCLIPEND_H #define DRAWCLIPEND_H #include "drawclipbegin.h" #include "path.h" namespace camp { class drawClipEnd : public drawElement { bool grestore; drawClipBegin *partner; public: drawClipEnd(bool grestore=true, drawClipBegin *partner=NULL) : grestore(grestore), partner(partner) {} virtual ~drawClipEnd() {} bool endclip() {return true;} void bounds(bbox& b, iopipestream&, boxvector&, bboxlist& bboxstack) { if(bboxstack.size() < 2) reportError("endclip without matching beginclip"); b.clip(bboxstack.back()); bboxstack.pop_back(); b += bboxstack.back(); bboxstack.pop_back(); } bool endgroup() {return true;} bool svg() {return true;} void save(bool b) { grestore=b; if(partner) partner->save(b); } bool draw(psfile *out) { if(grestore) out->grestore(); return true; } bool write(texfile *out, const bbox& bpath) { out->endgroup(); if(out->toplevel()) out->endpicture(bpath); if(grestore) out->grestore(); return true; } }; } GC_DECLARE_PTRFREE(camp::drawClipEnd); #endif asymptote-2.37/drawelement.h000066400000000000000000000220051265434602500161600ustar00rootroot00000000000000/***** * drawelement.h * Andy Hammerlindl 2002/06/06 * * Abstract base class of any drawable item in camp. *****/ #ifndef DRAWELEMENT_H #define DRAWELEMENT_H #include #include "common.h" #include "bbox.h" #include "bbox3.h" #include "pen.h" #include "psfile.h" #include "texfile.h" #include "prcfile.h" #include "glrender.h" #include "arrayop.h" namespace camp { enum Interaction {EMBEDDED=0,BILLBOARD}; void copyArray4x4C(double*& dest, const vm::array *a); class box { pair p[4]; public: box() {} box(const pair& a, const pair& b, const pair& c, const pair& d) { p[0]=a; p[1]=b; p[2]=c; p[3]=d; } // Returns true if the line a--b intersects box b. bool intersect(const pair& a, const pair& b) const { for(Int i=0; i < 4; ++i) { pair A=p[i]; pair B=p[i < 3 ? i+1 : 0]; double de=(b.x-a.x)*(A.y-B.y)-(A.x-B.x)*(b.y-a.y); if(de != 0.0) { de=1.0/de; double t=((A.x-a.x)*(A.y-B.y)-(A.x-B.x)*(A.y-a.y))*de; double T=((b.x-a.x)*(A.y-a.y)-(A.x-a.x)*(b.y-a.y))*de; if(0 <= t && t <= 1 && 0 <= T && T <= 1) return true; } } return false; } pair operator [] (Int i) const {return p[i];} bool intersect(const box& b) const { for(Int i=0; i < 4; ++i) { pair A=b[i]; pair B=b[i < 3 ? i+1 : 0]; if(intersect(A,B)) return true; } return false; } // Returns true iff the point z lies in the region bounded by b. bool inside(const pair& z) const { bool c=false; for(Int i=0; i < 3; ++i) { pair pi=p[i]; pair pj=p[i < 3 ? i+1 : 0]; if(((pi.y <= z.y && z.y < pj.y) || (pj.y <= z.y && z.y < pi.y)) && z.x < pi.x+(pj.x-pi.x)*(z.y-pi.y)/(pj.y-pi.y)) c=!c; } return c; } double xmax() { return max(max(max(p[0].x,p[1].x),p[2].x),p[3].x); } double ymax() { return max(max(max(p[0].y,p[1].y),p[2].y),p[3].y); } double xmin() { return min(min(min(p[0].x,p[1].x),p[2].x),p[3].x); } double ymin() { return min(min(min(p[0].y,p[1].y),p[2].y),p[3].y); } }; typedef mem::vector boxvector; typedef mem::list bboxlist; typedef mem::map groupmap; typedef mem::vector groupsmap; class drawElement : public gc { public: virtual ~drawElement() {} static pen lastpen; static const triple zero; // Adjust the bbox of the picture based on the addition of this // element. The iopipestream is needed for determining label sizes. virtual void bounds(bbox&, iopipestream&, boxvector&, bboxlist&) {} virtual void bounds(const double*, bbox3&) {} virtual void bounds(bbox3& b) { bounds(NULL, b); } // Compute bounds on ratio (x,y)/z for 3d picture (not cached). virtual void ratio(const double *t, pair &b, double (*m)(double, double), double fuzz, bool &first) {} virtual void minratio(const double *t, pair &b, double fuzz, bool &first) { ratio(t, b, camp::min, fuzz, first); } virtual void maxratio(const double *t,pair &b, double fuzz, bool &first) { ratio(t, b, camp::max, fuzz, first); } virtual void ratio(pair &b, double (*m)(double, double), double fuzz, bool &first) { ratio(NULL, b, m, fuzz, first); } virtual void minratio(pair &b, double fuzz, bool &first) { minratio(NULL, b, fuzz, first); } virtual void maxratio(pair &b, double fuzz, bool &first) { maxratio(NULL, b, fuzz, first); } virtual bool islabel() {return false;} virtual bool islayer() {return false;} virtual bool is3D() {return false;} // Implement element as raw SVG code? virtual bool svg() {return false;} // Implement SVG element as png image? virtual bool svgpng() {return false;} virtual bool beginclip() {return false;} virtual bool endclip() {return false;} virtual bool begingroup() {return false;} virtual bool begingroup3() {return false;} virtual bool endgroup() {return false;} virtual bool endgroup3() {return false;} virtual const double* transf3() {return NULL;} virtual void save(bool b) {} // Output to a PostScript file virtual bool draw(psfile *) { return false; } // Output to a TeX file virtual bool write(texfile *, const bbox&) { return false; } // Output to a PRC file virtual bool write(prcfile *out, unsigned int *count, double compressionlimit, groupsmap& groups) { return false; } // Used to compute deviation of a surface from a quadrilateral. virtual void displacement() {} // Render with OpenGL virtual void render(GLUnurbs *nurb, double size2, const triple& Min, const triple& Max, double perspective, bool lighton, bool transparent) {} // Transform as part of a picture. virtual drawElement *transformed(const transform&) { return this; } virtual drawElement *transformed(const double* t) { return this; } }; // Hold transform of an object. class drawElementLC : public virtual drawElement { public: double *T; // Keep track of accumulative picture transform drawElementLC() : T(NULL) {} drawElementLC(const double *t) : T(NULL) { copyTransform3(T,t); } drawElementLC(const vm::array& t) : T(NULL) { copyArray4x4C(T,&t); } drawElementLC(const double* t, const drawElementLC *s) : T(NULL) { multiplyTransform3(T,t,s->T); } virtual ~drawElementLC() {} virtual bool is3D() {return true;} virtual const double* transf3() {return T;} virtual drawElement* transformed(const double* t) { return new drawElementLC(t,this); } }; // Base class for drawElements that involve paths. class drawPathBase : public virtual drawElement { protected: path p; path transpath(const transform& t) const { return p.transformed(t); } public: drawPathBase() {} drawPathBase(path p) : p(p) {} virtual ~drawPathBase() {} virtual void bounds(bbox& b, iopipestream&, boxvector&, bboxlist&) { b += p.bounds(); } virtual void writepath(psfile *out,bool) { out->write(p); } virtual void writeclippath(psfile *out, bool newpath=true) { out->writeclip(p,newpath); } virtual void writeshiftedpath(texfile *out) { out->writeshifted(p); } }; // Base class for drawElements that involve paths and pens. class drawPathPenBase : public drawPathBase { protected: pen pentype; pen transpen(const transform& t) const { return camp::transformed(shiftless(t),pentype); } public: drawPathPenBase(path p, pen pentype) : drawPathBase(p), pentype(pentype) {} drawPathPenBase(pen pentype) : pentype(pentype) {} virtual bool empty() { return p.empty(); } virtual bool cyclic() { return p.cyclic(); } void strokebounds(bbox& b, const path& p); virtual void penSave(psfile *out) { if (!pentype.getTransform().isIdentity()) out->gsave(); } virtual void penTranslate(psfile *out) { out->translate(shiftpair(pentype.getTransform())); } virtual void penConcat(psfile *out) { out->concat(shiftless(pentype.getTransform())); } virtual void penRestore(psfile *out) { if (!pentype.getTransform().isIdentity()) out->grestore(); } }; // Base class for drawElements that involve superpaths and pens. class drawSuperPathPenBase : public drawPathPenBase { protected: vm::array P; size_t size; bbox bpath; vm::array transpath(const transform& t) const { vm::array *Pt=new vm::array(size); for(size_t i=0; i < size; i++) (*Pt)[i]=vm::read(P,i).transformed(t); return *Pt; } public: drawSuperPathPenBase(const vm::array& P, pen pentype) : drawPathPenBase(pentype), P(P), size(P.size()) {} bool empty() { for(size_t i=0; i < size; i++) if(vm::read(P,i).size() != 0) return false; return true; } bool cyclic() { for(size_t i=0; i < size; i++) if(!vm::read(P,i).cyclic()) return false; return true; } void bounds(bbox& b, iopipestream&, boxvector&, bboxlist&) { for(size_t i=0; i < size; i++) bpath += vm::read(P,i).bounds(); b += bpath; } void strokepath(psfile *out) { // strokepath and evenodd are incompatible static pen zerowinding=pen((FillRule) ZEROWINDING); pentype=pentype+zerowinding; out->setpen(pentype); out->strokepath(); } void strokebounds(bbox& b) { for(size_t i=0; i < size; i++) drawPathPenBase::strokebounds(bpath,vm::read(P,i)); b += bpath; } void writepath(psfile *out, bool newpath=true) { if(size > 0) out->write(vm::read(P,0),newpath); for(size_t i=1; i < size; i++) out->write(vm::read(P,i),false); } void writeclippath(psfile *out, bool newpath=true) { if(size > 0) out->writeclip(vm::read(P,0),newpath); for(size_t i=1; i < size; i++) out->writeclip(vm::read(P,i),false); } void writeshiftedpath(texfile *out) { for(size_t i=0; i < size; i++) out->writeshifted(vm::read(P,i),i == 0); } }; } GC_DECLARE_PTRFREE(camp::box); GC_DECLARE_PTRFREE(camp::drawElement); #endif asymptote-2.37/drawfill.cc000066400000000000000000000106321265434602500156160ustar00rootroot00000000000000/***** * drawfill.cc * Andy Hammerlindl 2002/06/06 * * Stores a cyclic path that will outline a filled shape in a picture. *****/ #include "drawfill.h" namespace camp { void drawAxialShade::palette(psfile *out) { pentype.convert(); penb.convert(); colorspace=(ColorSpace) max(pentype.colorspace(),penb.colorspace()); switch(colorspace) { case RGB: { if (pentype.grayscale()) pentype.greytorgb(); else if (penb.grayscale()) penb.greytorgb(); break; } case CMYK: { if (pentype.grayscale()) pentype.greytocmyk(); else if (penb.grayscale()) penb.greytocmyk(); if (pentype.rgb()) pentype.rgbtocmyk(); else if (penb.rgb()) penb.rgbtocmyk(); break; } default: break; } out->gsave(); } bool drawFill::draw(psfile *out) { if(pentype.invisible() || empty()) return true; palette(out); writepath(out); fill(out); return true; } drawElement *drawFill::transformed(const transform& t) { return new drawFill(transpath(t),stroke,transpen(t)); } drawElement *drawLatticeShade::transformed(const transform& t) { return new drawLatticeShade(transpath(t),stroke,pentype,pens,t*T); } drawElement *drawAxialShade::transformed(const transform& t) { pair A=t*a, B=t*b; return new drawAxialShade(transpath(t),stroke,pentype,A,extenda,penb,B, extendb); } drawElement *drawRadialShade::transformed(const transform& t) { pair A=t*a, B=t*b; double RA=length(t*(a+ra)-A); double RB=length(t*(b+rb)-B); return new drawRadialShade(transpath(t),stroke,pentype,A,RA,extenda,penb,B,RB, extendb); } drawElement *drawGouraudShade::transformed(const transform& t) { size_t size=vertices.size(); vm::array *Vertices=new vm::array(size); for(size_t i=0; i < size; i++) (*Vertices)[i]=t*vm::read(vertices,i); return new drawGouraudShade(transpath(t),stroke,pentype,pens,*Vertices,edges); } drawElement *drawTensorShade::transformed(const transform& t) { size_t size=boundaries.size(); size_t zsize=z.size(); vm::array *Boundaries=new vm::array(size); vm::array *Z=new vm::array(zsize); for(size_t i=0; i < size; i++) (*Boundaries)[i]=vm::read(boundaries,i).transformed(t); for(size_t i=0; i < zsize; i++) { vm::array *zi=vm::read(z,i); size_t zisize=checkArray(zi); vm::array *Zi=new vm::array(zisize); (*Z)[i]=Zi; for(size_t j=0; j < zisize; j++) (*Zi)[j]=t*vm::read(zi,j); } return new drawTensorShade(transpath(t),stroke,pentype,pens,*Boundaries,*Z); } bool drawFunctionShade::write(texfile *out, const bbox& box) { if(empty()) return true; ColorSpace colorspace=pentype.colorspace(); size_t ncomponents=ColorComponents[colorspace]; out->verbatim("\\pdfobj stream attr {/FunctionType 4"); out->verbatim("/Domain [0 1 0 1]"); out->verbatim("/Range ["); for(size_t i=0; i < ncomponents; ++i) out->verbatim("0 1 "); out->verbatim("]}{{"); out->verbatimline(shader); out->verbatimline("}}%"); out->verbatimline("\\edef\\lastobj{\\the\\pdflastobj}\\pdfrefobj\\lastobj"); out->verbatim("\\setbox\\ASYbox=\\hbox to "); double Hoffset=out->hoffset(); double hoffset=(bpath.Max().getx()-Hoffset)*ps2tex; out->write(hoffset); out->verbatim("pt {"); out->verbatim("\\vbox to "); out->write((box.top-box.bottom)*ps2tex); out->verbatimline("pt {\\vfil%"); out->gsave(); out->beginspecial(); out->beginraw(); writeshiftedpath(out); if(stroke) strokepath(out); out->endclip(pentype); out->verbatimline("/Sh sh"); out->endraw(); out->endspecial(); out->grestore(); out->verbatimline("}\\hfil}%"); out->verbatimline("\\pdfxform resources {"); out->verbatimline("/Shading << /Sh << /ShadingType 1"); out->verbatim("/Matrix ["); out->write(shift(pair(-Hoffset,-box.bottom))*matrix(bpath.Min(),bpath.Max())); out->verbatimline("]"); out->verbatim("/Domain [0 1 0 1]"); out->verbatim("/ColorSpace /Device"); out->verbatimline(ColorDeviceSuffix[colorspace]); out->verbatimline("/Function \\lastobj\\space 0 R >> >>}\\ASYbox"); out->verbatimline("\\pdfrefxform\\the\\pdflastxform"); out->verbatim("\\kern"); out->write(-hoffset); out->verbatimline("pt%"); return true; } drawElement *drawFunctionShade::transformed(const transform& t) { return new drawFunctionShade(transpath(t),stroke,pentype,shader); } } // namespace camp asymptote-2.37/drawfill.h000066400000000000000000000141041265434602500154560ustar00rootroot00000000000000/***** * 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) : 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) : drawFill(src,stroke,pentype) {} void bounds(bbox& b, iopipestream& iopipe, boxvector& vbox, bboxlist& bboxstack) { if(stroke) strokebounds(b); else drawSuperPathPenBase::bounds(b,iopipe,vbox,bboxstack); } // Shading in SVG is incomplete and not supported at all by dvisvgm. 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) : drawShade(src,stroke,pentype), 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(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) : drawShade(src,stroke,pentype), a(a), extenda(extenda), penb(penb), b(b), extendb(extendb) {} bool svgpng() {return false;} 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) : drawAxialShade(src,stroke,pentype,a,extenda,penb,b,extendb), ra(ra), rb(rb) {} bool svgpng() {return ra > 0.0;} 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) : drawShade(src,stroke,pentype), pens(pens), vertices(vertices), edges(edges) {} bool svgpng() {return !settings::getSetting("svgemulation");} 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) : drawShade(src,stroke,pentype), pens(pens), boundaries(boundaries), z(z) {} bool svgpng() { return pens.size() > 1 || !settings::getSetting("svgemulation"); } void palette(psfile *out) { out->gsave(); } void beginshade(psfile *out) { out->begintensorshade(pens,boundaries,z); } 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) : drawFill(src,stroke,pentype), shader(shader) { string texengine=settings::getSetting("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 asymptote-2.37/drawgrestore.h000066400000000000000000000007601265434602500163650ustar00rootroot00000000000000/***** * drawgrestore.h * John Bowman * * Output PostScript grestore to picture. *****/ #ifndef DRAWGRESTORE_H #define DRAWGRESTORE_H #include "drawelement.h" namespace camp { class drawGrestore : public drawElement { public: drawGrestore() {} virtual ~drawGrestore() {} bool draw(psfile *out) { out->grestore(); return true; } bool write(texfile *out, const bbox&) { out->grestore(); return true; } }; } GC_DECLARE_PTRFREE(camp::drawGrestore); #endif asymptote-2.37/drawgroup.h000066400000000000000000000055251265434602500156730ustar00rootroot00000000000000/***** * drawgroup.h * John Bowman * * Group elements in a picture to be deconstructed as a single object. *****/ #ifndef DRAWGROUP_H #define DRAWGROUP_H #include "drawelement.h" namespace camp { class drawBegin : public drawElement { public: drawBegin() {} virtual ~drawBegin() {} bool begingroup() {return true;} }; class drawEnd : public drawElement { public: drawEnd() {} virtual ~drawEnd() {} bool endgroup() {return true;} }; class drawBegin3 : public drawElementLC { string name; double compression; double granularity; bool closed; // render the surface as one-sided; may yield faster rendering bool tessellate; // use tessellated mesh to store straight patches bool dobreak; // force breaking bool nobreak; // force grouping for transparent patches triple center; int interaction; public: drawBegin3(string name, double compression, double granularity, bool closed, bool tessellate, bool dobreak, bool nobreak, triple center, int interaction) : name(name), compression(compression), granularity(granularity), closed(closed), tessellate(tessellate), dobreak(dobreak), nobreak(nobreak), center(center), interaction(interaction) {} virtual ~drawBegin3() {} bool begingroup() {return true;} bool begingroup3() {return true;} bool write(prcfile *out, unsigned int *count, double compressionlimit, groupsmap& groups) { groupmap& group=groups.back(); if(name.empty()) name="group"; groupmap::const_iterator p=group.find(name); unsigned c=(p != group.end()) ? p->second+1 : 0; group[name]=c; ostringstream buf; buf << name; if(c > 0) buf << "-" << (c+1); if(interaction == BILLBOARD) buf << "-" << (*count)++ << "\001"; prc::PRCoptions options(compression > 0.0 ? max(compression,compressionlimit) : 0.0, granularity,closed,tessellate,dobreak,nobreak); groups.push_back(groupmap()); out->begingroup(buf.str().c_str(),&options,T); return true; } drawBegin3(const double* t, const drawBegin3 *s) : drawElementLC(t, s), name(s->name), compression(s->compression), granularity(s->granularity), closed(s->closed), tessellate(s->tessellate), dobreak(s->dobreak), nobreak(s->nobreak), interaction(s->interaction) { center=t*s->center; } drawElement *transformed(const double* t) { return new drawBegin3(t,this); } }; class drawEnd3 : public drawElement { public: drawEnd3() {} virtual ~drawEnd3() {} bool endgroup() {return true;} bool endgroup3() {return true;} bool write(prcfile *out, unsigned int *, double, groupsmap& groups) { groups.pop_back(); out->endgroup(); return true; } }; } GC_DECLARE_PTRFREE(camp::drawBegin); GC_DECLARE_PTRFREE(camp::drawEnd); #endif asymptote-2.37/drawgsave.h000066400000000000000000000007221265434602500156360ustar00rootroot00000000000000/***** * drawgsave.h * John Bowman * * Output PostScript gsave to picture. *****/ #ifndef DRAWGSAVE_H #define DRAWGSAVE_H #include "drawelement.h" namespace camp { class drawGsave : public drawElement { public: drawGsave() {} virtual ~drawGsave() {} bool draw(psfile *out) { out->gsave(); return true; } bool write(texfile *out, const bbox&) { out->gsave(); return true; } }; } GC_DECLARE_PTRFREE(camp::drawGsave); #endif asymptote-2.37/drawimage.h000066400000000000000000000054621265434602500156210ustar00rootroot00000000000000/***** * drawimage.h * John Bowman * * Stores a image that has been added to a picture. *****/ #ifndef DRAWIMAGE_H #define DRAWIMAGE_H #include "drawelement.h" #include "array.h" namespace camp { class drawImage : public drawElement { protected: transform t; bool antialias; public: drawImage(const transform& t, bool antialias) : t(t), antialias(antialias) {} virtual ~drawImage() {} void bounds(bbox& b, iopipestream&, boxvector&, bboxlist&) { b += t*pair(0,0); b += t*pair(1,1); } bool svg() {return true;} bool svgpng() {return true;} }; class drawPaletteImage : public drawImage { vm::array image; vm::array palette; public: drawPaletteImage(const vm::array& image, const vm::array& palette, const transform& t, bool antialias) : drawImage(t,antialias), image(image), palette(palette) {} virtual ~drawPaletteImage() {} bool draw(psfile *out) { out->gsave(); out->concat(t); out->image(image,palette,antialias); out->grestore(); return true; } drawElement *transformed(const transform& T) { return new drawPaletteImage(image,palette,T*t,antialias); } }; class drawNoPaletteImage : public drawImage { vm::array image; public: drawNoPaletteImage(const vm::array& image, const transform& t, bool antialias) : drawImage(t,antialias), image(image) {} virtual ~drawNoPaletteImage() {} bool draw(psfile *out) { out->gsave(); out->concat(t); out->image(image,antialias); out->grestore(); return true; } drawElement *transformed(const transform& T) { return new drawNoPaletteImage(image,T*t,antialias); } }; class drawFunctionImage : public drawImage { vm::stack *Stack; vm::callable *f; Int width, height; public: drawFunctionImage(vm::stack *Stack, vm::callable *f, Int width, Int height, const transform& t, bool antialias) : drawImage(t,antialias), Stack(Stack), f(f), width(width), height(height) {} virtual ~drawFunctionImage() {} bool draw(psfile *out) { out->gsave(); out->concat(t); out->image(Stack,f,width,height,antialias); out->grestore(); return true; } drawElement *transformed(const transform& T) { return new drawFunctionImage(Stack,f,width,height,T*t,antialias); } }; class drawRawImage : public drawImage { unsigned char *raw; // For internal use; not buffered, may be overwritten. size_t width,height; public: drawRawImage(unsigned char *raw, size_t width, size_t height, const transform& t, bool antialias) : drawImage(t,antialias), raw(raw), width(width), height(height) {} virtual ~drawRawImage() {} bool draw(psfile *out) { out->gsave(); out->concat(t); out->rawimage(raw,width,height,antialias); out->grestore(); return true; } }; } #endif asymptote-2.37/drawlabel.cc000066400000000000000000000153171265434602500157540ustar00rootroot00000000000000/***** * drawlabel.cc * John Bowman 2003/04/07 * * Add a label to a picture. *****/ #include #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*"); void drawLabel::labelwarning(const char *action) { cerr << "warning: label \"" << label << "\" " << action << " to avoid overwriting" << endl; } // Reads one of the dimensions from the pipe. void texdim(iopipestream& tex, double& dest, const string command, const string name) { string start(">dim("); string stop(")dim"); string expect("pt"+stop+"\n\n*"); // ask the tex engine for dimension tex << "\\immediate\\write16{" << start << "\\the\\" << command << "\\ASYbox" << stop << "}\n"; // keep reading output until ')dim\n\n*' is read tex.wait(expect.c_str()); string buffer = tex.getbuffer(); size_t dim1=buffer.find(start); size_t dim2=buffer.find("pt" + stop); string cannotread="Cannot read label "+name; if (dim1 != string::npos && dim2 != string::npos) { string n=buffer.substr(dim1+start.size(),dim2-dim1-start.size()); try { dest=lexical::cast(n,true)*camp::tex2ps; } catch(lexical::bad_cast&) { camp::reportError(cannotread); } } else { camp::reportError(cannotread); } } void texbounds(double& width, double& height, double& depth, iopipestream& tex, string& s) { tex << "\\setbox\\ASYbox=\\hbox{" << stripblanklines(s) << "}\n\n"; tex.wait(texready.c_str()); texdim(tex,width,"wd","width"); texdim(tex,height,"ht","height"); texdim(tex,depth,"dp","depth"); } inline double urand() { static const double factor=2.0/RANDOM_MAX; return random()*factor-1.0; } void setpen(iopipestream& tex, const string& texengine, const pen& pentype) { bool Latex=latex(texengine); if(Latex && setlatexfont(tex,pentype,drawElement::lastpen)) { tex << "\n"; tex.wait(texready.c_str()); } if(settexfont(tex,pentype,drawElement::lastpen,Latex)) { tex << "\n"; tex.wait(texready.c_str()); } drawElement::lastpen=pentype; } void drawLabel::getbounds(iopipestream& tex, const string& texengine) { if(havebounds) return; havebounds=true; setpen(tex,texengine,pentype); texbounds(width,height,depth,tex,label); if(width == 0.0 && height == 0.0 && depth == 0.0 && !size.empty()) texbounds(width,height,depth,tex,size); 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("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("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("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 asymptote-2.37/drawlabel.h000066400000000000000000000040331265434602500156070ustar00rootroot00000000000000/***** * drawlabel.h * John Bowman 2003/03/14 * * Add a label to a picture. *****/ #ifndef DRAWLABEL_H #define DRAWLABEL_H #include "drawelement.h" #include "path.h" #include "angle.h" #include "transform.h" namespace camp { class drawLabel : public virtual drawElement { protected: string label,size; transform T; // A linear (shiftless) transformation. pair position; pair align; pair scale; pen pentype; double width,height,depth; bool havebounds; bool suppress; pair Align; pair texAlign; bbox Box; bool enabled; public: drawLabel(string label, string size, transform T, pair position, pair align, pen pentype) : label(label), size(size), T(shiftless(T)), position(position), align(align), pentype(pentype), width(0.0), height(0.0), depth(0.0), havebounds(false), suppress(false), enabled(false) {} virtual ~drawLabel() {} void getbounds(iopipestream& tex, const string& texengine); void checkbounds(); void bounds(bbox& b, iopipestream&, boxvector&, bboxlist&); bool islabel() { return true; } bool write(texfile *out, const bbox&); drawElement *transformed(const transform& t); void labelwarning(const char *action); }; class drawLabelPath : public drawLabel, public drawPathPenBase { private: string justify; pair shift; public: drawLabelPath(string label, string size, path src, string justify, pair shift, pen pentype) : drawLabel(label,size,identity,pair(0.0,0.0),pair(0.0,0.0),pentype), drawPathPenBase(src,pentype), justify(justify), shift(shift) {} virtual ~drawLabelPath() {} bool svg() {return true;} bool svgpng() {return true;} void bounds(bbox& b, iopipestream& tex, boxvector&, bboxlist&); bool write(texfile *out, const bbox&); drawElement *transformed(const transform& t); }; void setpen(iopipestream& tex, const string& texengine, const pen& pentype); void texbounds(double& width, double& height, double& depth, iopipestream& tex, string& s); } #endif asymptote-2.37/drawlayer.h000066400000000000000000000013431265434602500156450ustar00rootroot00000000000000/***** * drawlayer.h * John Bowman * * Start a new postscript/TeX layer in picture. *****/ #ifndef DRAWLAYER_H #define DRAWLAYER_H #include "drawelement.h" namespace camp { class drawLayer : public drawElement { public: drawLayer() {} virtual ~drawLayer() {} bool islayer() {return true;} }; class drawNewPage : public drawLayer { public: drawNewPage() {} virtual ~drawNewPage() {} bool islabel() {return true;} bool write(texfile *out, const bbox&) { out->verbatimline(settings::latex(out->texengine) ? "\\newpage" : settings::context(out->texengine) ? "}\\page\\hbox{%" : "\\eject"); return true; } }; } GC_DECLARE_PTRFREE(camp::drawLayer); #endif asymptote-2.37/drawpath.cc000066400000000000000000000066141265434602500156310ustar00rootroot00000000000000/***** * drawpath.cc * Andy Hammerlindl 2002/06/06 * * Stores a path that has been added to a picture. *****/ #include #include #include #include "drawpath.h" #include "psfile.h" #include "util.h" using vm::array; using vm::read; namespace camp { double PatternLength(double arclength, const array& pat, bool cyclic, double penwidth) { double sum=0.0; size_t n=pat.size(); for(unsigned i=0; i < n; i ++) sum += read(pat,i)*penwidth; if(sum == 0.0) return 0.0; if(n % 2 == 1) sum *= 2.0; // On/off pattern repeats after 2 cycles. double pat0=read(pat,0); // Fix bounding box resolution problem. Example: // asy -f pdf testlinetype; gv -scale -2 testlinetype.pdf if(!cyclic && pat0 == 0) sum += 1.0e-3*penwidth; double terminator=(cyclic && arclength >= 0.5*sum) ? 0.0 : pat0*penwidth; int ncycle=(int)((arclength-terminator)/sum+0.5); return (ncycle >= 1 || terminator >= 0.75*arclength) ? ncycle*sum+terminator : 0.0; } bool isdashed(pen& p) { const LineType *linetype=p.linetype(); size_t n=linetype->pattern.size(); return n > 0; } pen adjustdash(pen& p, double arclength, bool cyclic) { pen q=p; // Adjust dash sizes to fit arclength; also compensate for linewidth. const LineType *linetype=q.linetype(); size_t n=linetype->pattern.size(); if(n > 0) { double penwidth=linetype->scale ? q.width() : 1.0; double factor=penwidth; if(linetype->adjust && arclength) { double denom=PatternLength(arclength,linetype->pattern,cyclic,penwidth); if(denom != 0.0) factor *= arclength/denom; } if(factor != 1.0) q.adjust(max(factor,0.1)); } return q; } // Account for square or extended pen cap contributions to bounding box. void cap(bbox& b, double t, path p, pen pentype) { transform T=pentype.getTransform(); double h=0.5*pentype.width(); pair v=p.dir(t); transform S=rotate(conj(v))*shiftless(T); double xx=S.getxx(), xy=S.getxy(); double yx=S.getyx(), yy=S.getyy(); double y=hypot(yx,yy); if(y == 0) return; double numer=xx*yx+xy*yy; double x=numer/y; pair z=shift(T)*p.point(t); switch(pentype.cap()) { case 0: { pair d=rotate(v)*pair(x,y)*h; b += z+d; b += z-d; break; } case 2: { transform R=rotate(v); double w=(xx*yy-xy*yx)/y; pair dp=R*pair(x+w,y)*h; pair dm=R*pair(x-w,y)*h; b += z+dp; b += z+dm; b += z-dp; b += z-dm; break; } } } void drawPathPenBase::strokebounds(bbox& b, const path& p) { Int l=p.length(); if(l < 0) return; bbox penbounds=pentype.bounds(); if(cyclic() || pentype.cap() == 1) { b += pad(p.bounds(),penbounds); return; } b += p.internalbounds(penbounds); cap(b,0,p,pentype); cap(b,l,p,pentype); } bool drawPath::draw(psfile *out) { Int n = p.size(); if (n == 0 || pentype.invisible()) return true; pen q = isdashed(pentype) ? adjustdash(pentype,p.arclength(),p.cyclic()) : pentype; penSave(out); penTranslate(out); if(n > 1) out->write(p); else out->dot(p,q); penConcat(out); out->setpen(q); out->stroke(q,n == 1); penRestore(out); return true; } drawElement *drawPath::transformed(const transform& t) { return new drawPath(transpath(t), transpen(t)); } } //namespace camp asymptote-2.37/drawpath.h000066400000000000000000000011661265434602500154700ustar00rootroot00000000000000/***** * drawpath.h * Andy Hammerlindl 2002/06/06 * * Stores a path that has been added to a picture. *****/ #ifndef DRAWPATH_H #define DRAWPATH_H #include "drawelement.h" #include "path.h" namespace camp { class drawPath : public drawPathPenBase { public: drawPath(path src, pen pentype) : drawPathPenBase(src, pentype) {} virtual ~drawPath() {} void bounds(bbox& b, iopipestream&, boxvector&, bboxlist&) { strokebounds(b,p); } bool svg() {return true;} bool draw(psfile *out); drawElement *transformed(const transform& t); }; pen adjustdash(pen& p, double arclength, bool cyclic); } #endif asymptote-2.37/drawpath3.cc000066400000000000000000000133651265434602500157150ustar00rootroot00000000000000/***** * drawpath3.cc * * Stores a path3 that has been added to a picture. *****/ #include "drawpath3.h" namespace camp { using vm::array; using namespace prc; bool drawPath3::write(prcfile *out, unsigned int *, double, groupsmap&) { Int n=g.length(); if(n == 0 || invisible) return true; if(straight) { triple *controls=new(UseGC) triple[n+1]; for(Int i=0; i <= n; ++i) controls[i]=g.point(i); out->addLine(n+1,controls,color); } else { int m=3*n+1; triple *controls=new(UseGC) triple[m]; controls[0]=g.point((Int) 0); controls[1]=g.postcontrol((Int) 0); size_t k=1; for(Int i=1; i < n; ++i) { controls[++k]=g.precontrol(i); controls[++k]=g.point(i); controls[++k]=g.postcontrol(i); } controls[++k]=g.precontrol(n); controls[++k]=g.point(n); out->addBezierCurve(m,controls,color); } return true; } void drawPath3::render(GLUnurbs *nurb, double, const triple&, const triple&, double, bool lighton, bool transparent) { #ifdef HAVE_GL Int n=g.length(); if(n == 0 || invisible || ((color.A < 1.0) ^ transparent)) return; bool havebillboard=interaction == BILLBOARD; GLfloat Diffuse[]={0.0,0.0,0.0,(GLfloat) color.A}; glMaterialfv(GL_FRONT,GL_DIFFUSE,Diffuse); static GLfloat Black[]={0.0,0.0,0.0,1.0}; glMaterialfv(GL_FRONT,GL_AMBIENT,Black); GLfloat Emissive[]={(GLfloat) color.R,(GLfloat) color.G,(GLfloat) color.B, (GLfloat) color.A}; glMaterialfv(GL_FRONT,GL_EMISSION,Emissive); glMaterialfv(GL_FRONT,GL_SPECULAR,Black); glMaterialf(GL_FRONT,GL_SHININESS,128.0); if(havebillboard) BB.init(); if(straight) { glBegin(GL_LINE_STRIP); for(Int i=0; i <= n; ++i) { triple v=g.point(i); if(havebillboard) { static GLfloat controlpoints[3]; BB.store(controlpoints,v,center); glVertex3fv(controlpoints); } else glVertex3f(v.getx(),v.gety(),v.getz()); } glEnd(); } else { for(Int i=0; i < n; ++i) { static GLfloat knots[8]={0.0,0.0,0.0,0.0,1.0,1.0,1.0,1.0}; static GLfloat controlpoints[12]; if(havebillboard) { BB.store(controlpoints,g.point(i),center); BB.store(controlpoints+3,g.postcontrol(i),center); BB.store(controlpoints+6,g.precontrol(i+1),center); BB.store(controlpoints+9,g.point(i+1),center); } else { store(controlpoints,g.point(i)); store(controlpoints+3,g.postcontrol(i)); store(controlpoints+6,g.precontrol(i+1)); store(controlpoints+9,g.point(i+1)); } gluBeginCurve(nurb); gluNurbsCurve(nurb,8,knots,3,controlpoints,4,GL_MAP1_VERTEX_3); gluEndCurve(nurb); } } #endif } drawElement *drawPath3::transformed(const double* t) { return new drawPath3(t,this); } bool drawNurbsPath3::write(prcfile *out, unsigned int *, double, groupsmap&) { if(invisible) return true; out->addCurve(degree,n,controls,knots,color,weights); return true; } // Approximate bounds by bounding box of control polyhedron. void drawNurbsPath3::bounds(const double* t, bbox3& b) { double x,y,z; double X,Y,Z; triple* Controls; if(t == NULL) Controls=controls; else { Controls=new triple[n]; for(size_t i=0; i < n; i++) Controls[i]=t*controls[i]; } boundstriples(x,y,z,X,Y,Z,n,Controls); b.add(x,y,z); b.add(X,Y,Z); if(t == NULL) { Min=triple(x,y,z); Max=triple(X,Y,Z); } else delete[] Controls; } drawElement *drawNurbsPath3::transformed(const double* t) { return new drawNurbsPath3(t,this); } void drawNurbsPath3::ratio(const double* t, pair &b, double (*m)(double, double), double, bool &first) { triple* Controls; if(t == NULL) Controls=controls; else { Controls=new triple[n]; for(size_t i=0; i < n; i++) Controls[i]=t*controls[i]; } if(first) { first=false; triple v=Controls[0]; b=pair(xratio(v),yratio(v)); } double x=b.getx(); double y=b.gety(); for(size_t i=0; i < n; ++i) { triple v=Controls[i]; x=m(x,xratio(v)); y=m(y,yratio(v)); } b=pair(x,y); if(t != NULL) delete[] Controls; } void drawNurbsPath3::displacement() { #ifdef HAVE_GL size_t nknots=degree+n+1; if(Controls == NULL) { Controls=new(UseGC) GLfloat[(weights ? 4 : 3)*n]; Knots=new(UseGC) GLfloat[nknots]; } if(weights) for(size_t i=0; i < n; ++i) store(Controls+4*i,controls[i],weights[i]); else for(size_t i=0; i < n; ++i) store(Controls+3*i,controls[i]); for(size_t i=0; i < nknots; ++i) Knots[i]=knots[i]; #endif } void drawNurbsPath3::render(GLUnurbs *nurb, double, const triple&, const triple&, double, bool lighton, bool transparent) { #ifdef HAVE_GL if(invisible || ((color.A < 1.0) ^ transparent)) return; GLfloat Diffuse[]={0.0,0.0,0.0,(GLfloat) color.A}; glMaterialfv(GL_FRONT,GL_DIFFUSE,Diffuse); static GLfloat Black[]={0.0,0.0,0.0,1.0}; glMaterialfv(GL_FRONT,GL_AMBIENT,Black); GLfloat Emissive[]={(GLfloat) color.R,(GLfloat) color.G,(GLfloat) color.B, (GLfloat) color.A}; glMaterialfv(GL_FRONT,GL_EMISSION,Emissive); glMaterialfv(GL_FRONT,GL_SPECULAR,Black); glMaterialf(GL_FRONT,GL_SHININESS,128.0); if(weights) gluNurbsCallback(nurb,GLU_NURBS_VERTEX,(_GLUfuncptr) glVertex4fv); else gluNurbsCallback(nurb,GLU_NURBS_VERTEX,(_GLUfuncptr) glVertex3fv); gluBeginCurve(nurb); int order=degree+1; gluNurbsCurve(nurb,order+n,Knots,weights ? 4 : 3,Controls,order, weights ? GL_MAP1_VERTEX_4 : GL_MAP1_VERTEX_3); gluEndCurve(nurb); if(weights) gluNurbsCallback(nurb,GLU_NURBS_VERTEX,(_GLUfuncptr) glVertex3fv); #endif } } //namespace camp asymptote-2.37/drawpath3.h000066400000000000000000000073771265434602500155650ustar00rootroot00000000000000/***** * drawpath3.h * * Stores a path3 that has been added to a picture. *****/ #ifndef DRAWPATH3_H #define DRAWPATH3_H #include "drawelement.h" #include "path3.h" namespace camp { class drawPath3 : public drawElement { protected: const path3 g; triple center; bool straight; prc::RGBAColour color; bool invisible; Interaction interaction; triple Min,Max; public: drawPath3(path3 g, triple center, const pen& p, Interaction interaction) : g(g), center(center), straight(g.piecewisestraight()), color(rgba(p)), invisible(p.invisible()), interaction(interaction), Min(g.min()), Max(g.max()) {} drawPath3(const double* t, const drawPath3 *s) : g(camp::transformed(t,s->g)), straight(s->straight), color(s->color), invisible(s->invisible), interaction(s->interaction), Min(g.min()), Max(g.max()) { center=t*s->center; } virtual ~drawPath3() {} bool is3D() {return true;} void bounds(const double* t, bbox3& B) { if(t != NULL) { const path3 tg(camp::transformed(t,g)); B.add(tg.min()); B.add(tg.max()); } else { B.add(Min); B.add(Max); } } void ratio(const double* t, pair &b, double (*m)(double, double), double, bool &first) { pair z; if(t != NULL) { const path3 tg(camp::transformed(t,g)); z=tg.ratio(m); } else z=g.ratio(m); if(first) { b=z; first=false; } else b=pair(m(b.getx(),z.getx()),m(b.gety(),z.gety())); } bool write(prcfile *out, unsigned int *, double, groupsmap&); void render(GLUnurbs*, double, const triple&, const triple&, double, bool lighton, bool transparent); drawElement *transformed(const double* t); }; class drawNurbsPath3 : public drawElement { protected: size_t degree; size_t n; triple *controls; double *weights; double *knots; prc::RGBAColour color; bool invisible; triple Min,Max; #ifdef HAVE_GL GLfloat *Controls; GLfloat *Knots; #endif public: drawNurbsPath3(const vm::array& g, const vm::array* knot, const vm::array* weight, const pen& p) : color(rgba(p)), invisible(p.invisible()) { size_t weightsize=checkArray(weight); string wrongsize="Inconsistent NURBS data"; n=checkArray(&g); if(n == 0 || (weightsize != 0 && weightsize != n)) reportError(wrongsize); controls=new(UseGC) triple[n]; size_t k=0; for(size_t i=0; i < n; ++i) controls[k++]=vm::read(g,i); if(weightsize > 0) { size_t k=0; weights=new(UseGC) double[n]; for(size_t i=0; i < n; ++i) weights[k++]=vm::read(weight,i); } else weights=NULL; size_t nknots=checkArray(knot); if(nknots <= n+1 || nknots > 2*n) reportError(wrongsize); degree=nknots-n-1; run::copyArrayC(knots,knot,0,NoGC); #ifdef HAVE_GL Controls=NULL; #endif } drawNurbsPath3(const double* t, const drawNurbsPath3 *s) : degree(s->degree), n(s->n), weights(s->weights), knots(s->knots), color(s->color), invisible(s->invisible) { controls=new(UseGC) triple[n]; for(unsigned int i=0; i < n; ++i) controls[i]=t*s->controls[i]; #ifdef HAVE_GL Controls=NULL; #endif } bool is3D() {return true;} void bounds(const double* t, bbox3& b); virtual ~drawNurbsPath3() {} bool write(prcfile *out, unsigned int *, double, groupsmap&); void displacement(); void ratio(const double* t, pair &b, double (*m)(double, double), double fuzz, bool &first); void render(GLUnurbs *nurb, double size2, const triple& Min, const triple& Max, double perspective, bool lighton, bool transparent); drawElement *transformed(const double* t); }; } #endif asymptote-2.37/drawsurface.cc000066400000000000000000000674611265434602500163340ustar00rootroot00000000000000/***** * drawsurface.cc * * Stores a surface that has been added to a picture. *****/ #include "drawsurface.h" #include "arrayop.h" #include #include #include using namespace prc; namespace camp { void bezierTriangle(const triple *g, bool straight, double Size2, triple Size3, bool havebillboard, triple center, GLfloat *colors); const double pixel=1.0; // Adaptive rendering constant. const triple drawElement::zero; using vm::array; #ifdef HAVE_GL void storecolor(GLfloat *colors, int i, const vm::array &pens, int j) { pen p=vm::read(pens,j); p.torgb(); colors[i]=p.red(); colors[i+1]=p.green(); colors[i+2]=p.blue(); colors[i+3]=p.opacity(); } void storecolor(GLfloat *colors, int i, const RGBAColour& p) { colors[i]=p.R; colors[i+1]=p.G; colors[i+2]=p.B; colors[i+3]=p.A; } void setcolors(bool colors, bool lighton, const RGBAColour& diffuse, const RGBAColour& ambient, const RGBAColour& emissive, const RGBAColour& specular, double shininess) { if(colors) { glEnable(GL_COLOR_MATERIAL); if(!lighton) glColorMaterial(GL_FRONT_AND_BACK,GL_EMISSION); GLfloat Black[]={0,0,0,(GLfloat) diffuse.A}; glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,Black); glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,Black); glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,Black); } else { GLfloat Diffuse[]={(GLfloat) diffuse.R,(GLfloat) diffuse.G, (GLfloat) diffuse.B,(GLfloat) diffuse.A}; glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,Diffuse); GLfloat Ambient[]={(GLfloat) ambient.R,(GLfloat) ambient.G, (GLfloat) ambient.B,(GLfloat) ambient.A}; glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,Ambient); GLfloat Emissive[]={(GLfloat) emissive.R,(GLfloat) emissive.G, (GLfloat) emissive.B,(GLfloat) emissive.A}; glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,Emissive); } if(lighton) { GLfloat Specular[]={(GLfloat) specular.R,(GLfloat) specular.G, (GLfloat) specular.B,(GLfloat) specular.A}; glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,Specular); glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,128.0*shininess); } } #endif void drawSurface::bounds(const double* t, bbox3& b) { double x,y,z; double X,Y,Z; if(straight) { triple *Vertices; if(t == NULL) Vertices=vertices; else { triple buf[4]; Vertices=buf; for(int i=0; i < 4; ++i) Vertices[i]=t*vertices[i]; } boundstriples(x,y,z,X,Y,Z,4,Vertices); } else { double cx[16]; double cy[16]; double cz[16]; if(t == NULL) { for(int i=0; i < 16; ++i) { triple v=controls[i]; cx[i]=v.getx(); cy[i]=v.gety(); cz[i]=v.getz(); } } else { for(int i=0; i < 16; ++i) { triple v=t*controls[i]; cx[i]=v.getx(); cy[i]=v.gety(); cz[i]=v.getz(); } } double c0=cx[0]; double fuzz=sqrtFuzz*run::norm(cx,16); x=bound(cx,min,b.empty ? c0 : min(c0,b.left),fuzz,maxdepth); X=bound(cx,max,b.empty ? c0 : max(c0,b.right),fuzz,maxdepth); c0=cy[0]; fuzz=sqrtFuzz*run::norm(cy,16); y=bound(cy,min,b.empty ? c0 : min(c0,b.bottom),fuzz,maxdepth); Y=boundtri(cy,max,b.empty ? c0 : max(c0,b.top),fuzz,maxdepth); c0=cz[0]; fuzz=sqrtFuzz*run::norm(cz,16); z=bound(cz,min,b.empty ? c0 : min(c0,b.lower),fuzz,maxdepth); Z=bound(cz,max,b.empty ? c0 : max(c0,b.upper),fuzz,maxdepth); } b.add(x,y,z); b.add(X,Y,Z); if(t == NULL) { Min=triple(x,y,z); Max=triple(X,Y,Z); } } void drawSurface::ratio(const double* t, pair &b, double (*m)(double, double), double fuzz, bool &first) { triple buf[16]; if(straight) { triple *Vertices; if(t == NULL) Vertices=vertices; else { Vertices=buf; for(int i=0; i < 4; ++i) Vertices[i]=t*vertices[i]; } triple v=Vertices[0]; double x=xratio(v); double y=yratio(v); if(first) { first=false; b=pair(x,y); } else { x=m(b.getx(),x); y=m(b.gety(),y); } for(size_t i=1; i < 4; ++i) { triple v=Vertices[i]; x=m(x,xratio(v)); y=m(y,yratio(v)); } b=pair(x,y); } else { triple* Controls; if(t == NULL) Controls=controls; else { Controls=buf; for(int i=0; i < 16; ++i) Controls[i]=t*controls[i]; } if(first) { triple v=Controls[0]; b=pair(xratio(v),yratio(v)); first=false; } b=pair(bound(Controls,m,xratio,b.getx(),fuzz,maxdepth), bound(Controls,m,yratio,b.gety(),fuzz,maxdepth)); } } bool drawSurface::write(prcfile *out, unsigned int *, double, groupsmap&) { if(invisible || !prc) return true; PRCmaterial m(ambient,diffuse,emissive,specular,opacity,PRCshininess); if(straight) { if(colors) out->addQuad(vertices,colors); else out->addRectangle(vertices,m); } else out->addPatch(controls,m); return true; } // return the perpendicular displacement of a point z from the plane // through u with unit normal n. inline triple displacement2(const triple& z, const triple& u, const triple& n) { triple Z=z-u; return n != triple(0,0,0) ? dot(Z,n)*n : Z; } inline triple maxabs(triple u, triple v) { return triple(max(fabs(u.getx()),fabs(v.getx())), max(fabs(u.gety()),fabs(v.gety())), max(fabs(u.getz()),fabs(v.getz()))); } inline triple displacement1(const triple& z0, const triple& c0, const triple& c1, const triple& z1) { return maxabs(displacement(c0,z0,z1),displacement(c1,z0,z1)); } void drawSurface::displacement() { #ifdef HAVE_GL if(normal != zero) { d=zero; if(!straight) { for(size_t i=1; i < 16; ++i) d=maxabs(d,displacement2(controls[i],controls[0],normal)); dperp=d; for(size_t i=0; i < 4; ++i) d=maxabs(d,displacement1(controls[4*i],controls[4*i+1], controls[4*i+2],controls[4*i+3])); for(size_t i=0; i < 4; ++i) d=maxabs(d,displacement1(controls[i],controls[i+4], controls[i+8],controls[i+12])); } } #endif } inline double fraction(double d, double size) { return size == 0 ? 1.0 : min(fabs(d)/size,1.0); } // estimate the viewport fraction associated with the displacement d inline double fraction(const triple& d, const triple& size) { return max(max(fraction(d.getx(),size.getx()), fraction(d.gety(),size.gety())), fraction(d.getz(),size.getz())); } void drawSurface::render(GLUnurbs *nurb, double size2, const triple& Min, const triple& Max, double perspective, bool lighton, bool transparent) { #ifdef HAVE_GL if(invisible || ((colors ? colors[0].A+colors[1].A+colors[2].A+colors[3].A < 4.0 : diffuse.A < 1.0) ^ transparent)) return; double s; GLfloat Normal[3]; GLfloat v[16]; const bool havebillboard=interaction == BILLBOARD && !settings::getSetting("offscreen"); triple m,M; if(perspective || !havebillboard) { double t[16]; glGetDoublev(GL_MODELVIEW_MATRIX,t); // Like Fortran, OpenGL uses transposed (column-major) format! run::transpose(t,4); bbox3 B(this->Min,this->Max); B.transform(t); m=B.Min(); M=B.Max(); } if(perspective) { const double f=m.getz()*perspective; const double F=M.getz()*perspective; if(!havebillboard && (M.getx() < min(f*Min.getx(),F*Min.getx()) || m.getx() > max(f*Max.getx(),F*Max.getx()) || M.gety() < min(f*Min.gety(),F*Min.gety()) || m.gety() > max(f*Max.gety(),F*Max.gety()) || M.getz() < Min.getz() || m.getz() > Max.getz())) return; s=max(f,F); } else { if(!havebillboard && (M.getx() < Min.getx() || m.getx() > Max.getx() || M.gety() < Min.gety() || m.gety() > Max.gety() || M.getz() < Min.getz() || m.getz() > Max.getz())) return; s=1.0; } setcolors(colors,lighton,diffuse,ambient,emissive,specular,shininess); const triple size3(s*(Max.getx()-Min.getx()),s*(Max.gety()-Min.gety()),0.0); bool havenormal=normal != zero; if(havebillboard) BB.init(); if(colors) for(size_t i=0; i < 4; ++i) storecolor(v,4*i,colors[i]); if(!straight && (!havenormal || fraction(d,size3)*size2 >= pixel)) { if(lighton) { if(havenormal && fraction(dperp,size3)*size2 <= 0.1) { if(havebillboard) BB.store(Normal,normal,zero); else store(Normal,normal); glNormal3fv(Normal); gluNurbsCallback(nurb,GLU_NURBS_NORMAL,NULL); } else gluNurbsCallback(nurb,GLU_NURBS_NORMAL,(_GLUfuncptr) glNormal3fv); } GLfloat Controls[48]; if(havebillboard) { for(size_t i=0; i < 16; ++i) BB.store(Controls+3*i,controls[i],center); } else { for(size_t i=0; i < 16; ++i) store(Controls+3*i,controls[i]); } static GLfloat bezier[]={0.0,0.0,0.0,0.0,1.0,1.0,1.0,1.0}; gluBeginSurface(nurb); gluNurbsSurface(nurb,8,bezier,8,bezier,12,3,Controls,4,4,GL_MAP2_VERTEX_3); if(colors) { static GLfloat linear[]={0.0,0.0,1.0,1.0}; gluNurbsSurface(nurb,4,linear,4,linear,8,4,v,2,2,GL_MAP2_COLOR_4); } gluEndSurface(nurb); } else { GLfloat Vertices[12]; if(havebillboard) { for(size_t i=0; i < 4; ++i) BB.store(Vertices+3*i,vertices[i],center); } else { for(size_t i=0; i < 4; ++i) store(Vertices+3*i,vertices[i]); } if(havebillboard) BB.store(Normal,normal,zero); else store(Normal,normal); glBegin(GL_QUADS); if(lighton) glNormal3fv(Normal); if(colors) glColor4fv(v); glVertex3fv(Vertices); if(colors) glColor4fv(v+8); glVertex3fv(Vertices+6); if(colors) glColor4fv(v+12); glVertex3fv(Vertices+9); if(colors) glColor4fv(v+4); glVertex3fv(Vertices+3); glEnd(); } if(colors) glDisable(GL_COLOR_MATERIAL); #endif } drawElement *drawSurface::transformed(const double* t) { return new drawSurface(t,this); } void drawBezierTriangle::bounds(const double* t, bbox3& b) { double x,y,z; double X,Y,Z; if(straight) { triple Vertices[3]; if(t == NULL) { Vertices[0]=controls[0]; Vertices[1]=controls[6]; Vertices[2]=controls[9]; } else { Vertices[0]=t*controls[0]; Vertices[1]=t*controls[6]; Vertices[2]=t*controls[9]; } boundstriples(x,y,z,X,Y,Z,3,Vertices); } else { double cx[10]; double cy[10]; double cz[10]; if(t == NULL) { for(unsigned int i=0; i < 10; ++i) { triple v=controls[i]; cx[i]=v.getx(); cy[i]=v.gety(); cz[i]=v.getz(); } } else { for(unsigned int i=0; i < 10; ++i) { triple v=t*controls[i]; cx[i]=v.getx(); cy[i]=v.gety(); cz[i]=v.getz(); } } double c0=cx[0]; double fuzz=sqrtFuzz*run::norm(cx,10); x=boundtri(cx,min,b.empty ? c0 : min(c0,b.left),fuzz,maxdepth); X=boundtri(cx,max,b.empty ? c0 : max(c0,b.right),fuzz,maxdepth); c0=cy[0]; fuzz=sqrtFuzz*run::norm(cy,10); y=boundtri(cy,min,b.empty ? c0 : min(c0,b.bottom),fuzz,maxdepth); Y=boundtri(cy,max,b.empty ? c0 : max(c0,b.top),fuzz,maxdepth); c0=cz[0]; fuzz=sqrtFuzz*run::norm(cz,10); z=boundtri(cz,min,b.empty ? c0 : min(c0,b.lower),fuzz,maxdepth); Z=boundtri(cz,max,b.empty ? c0 : max(c0,b.upper),fuzz,maxdepth); } b.add(x,y,z); b.add(X,Y,Z); if(t == NULL) { Min=triple(x,y,z); Max=triple(X,Y,Z); } } void drawBezierTriangle::ratio(const double* t, pair &b, double (*m)(double, double), double fuzz, bool &first) { triple buf[10]; triple* Controls; if(straight) { if(t == NULL) Controls=controls; else { Controls=buf; Controls[0]=t*controls[0]; Controls[6]=t*controls[6]; Controls[9]=t*controls[9]; } triple v=Controls[0]; double x=xratio(v); double y=yratio(v); if(first) { first=false; b=pair(x,y); } else { x=m(b.getx(),x); y=m(b.gety(),y); } v=Controls[6]; x=m(x,xratio(v)); y=m(y,yratio(v)); v=Controls[9]; x=m(x,xratio(v)); y=m(y,yratio(v)); b=pair(x,y); } else { if(t == NULL) Controls=controls; else { Controls=buf; for(unsigned int i=0; i < 10; ++i) Controls[i]=t*controls[i]; } if(first) { triple v=Controls[0]; b=pair(xratio(v),yratio(v)); first=false; } b=pair(boundtri(Controls,m,xratio,b.getx(),fuzz,maxdepth), boundtri(Controls,m,yratio,b.gety(),fuzz,maxdepth)); } } bool drawBezierTriangle::write(prcfile *out, unsigned int *, double, groupsmap&) { if(invisible) return true; PRCmaterial m(ambient,diffuse,emissive,specular,opacity,PRCshininess); static const double third=1.0/3.0; static const double third2=2.0/3.0; triple Controls[]={controls[0],controls[0],controls[0],controls[0], controls[1],third2*controls[1]+third*controls[2], third*controls[1]+third2*controls[2], controls[2],controls[3], third*controls[3]+third2*controls[4], third2*controls[4]+third*controls[5], controls[5],controls[6],controls[7], controls[8],controls[9]}; out->addPatch(Controls,m); return true; } void drawBezierTriangle::render(GLUnurbs *nurb, double size2, const triple& Min, const triple& Max, double perspective, bool lighton, bool transparent) { #ifdef HAVE_GL if(invisible) return; if(invisible || ((colors ? colors[0].A+colors[1].A+colors[2].A < 3.0 : diffuse.A < 1.0) ^ transparent)) return; double s; const bool havebillboard=interaction == BILLBOARD && !settings::getSetting("offscreen"); triple m,M; double t[16]; // current transform glGetDoublev(GL_MODELVIEW_MATRIX,t); // Like Fortran, OpenGL uses transposed (column-major) format! run::transpose(t,4); bbox3 B(this->Min,this->Max); B.transform(t); m=B.Min(); M=B.Max(); if(perspective) { const double f=m.getz()*perspective; const double F=M.getz()*perspective; if((M.getx() < min(f*Min.getx(),F*Min.getx()) || m.getx() > max(f*Max.getx(),F*Max.getx()) || M.gety() < min(f*Min.gety(),F*Min.gety()) || m.gety() > max(f*Max.gety(),F*Max.gety()) || M.getz() < Min.getz() || m.getz() > Max.getz())) return; s=max(f,F); } else { if((M.getx() < Min.getx() || m.getx() > Max.getx() || M.gety() < Min.gety() || m.gety() > Max.gety() || M.getz() < Min.getz() || m.getz() > Max.getz())) return; s=1.0; } setcolors(colors,lighton,diffuse,ambient,emissive,specular,shininess); const triple size3(s*(Max.getx()-Min.getx()),s*(Max.gety()-Min.gety()),0); GLfloat v[12]; if(colors) for(size_t i=0; i < 3; ++i) storecolor(v,4*i,colors[i]); bezierTriangle(controls,straight,size2,size3,havebillboard,center, colors ? v : NULL); if(colors) glDisable(GL_COLOR_MATERIAL); #endif } drawElement *drawBezierTriangle::transformed(const double* t) { return new drawBezierTriangle(t,this); } bool drawNurbs::write(prcfile *out, unsigned int *, double, groupsmap&) { if(invisible) return true; PRCmaterial m(ambient,diffuse,emissive,specular,opacity,PRCshininess); out->addSurface(udegree,vdegree,nu,nv,controls,uknots,vknots,m,weights); return true; } // Approximate bounds by bounding box of control polyhedron. void drawNurbs::bounds(const double* t, bbox3& b) { double x,y,z; double X,Y,Z; const size_t n=nu*nv; triple* Controls; if(t == NULL) Controls=controls; else { Controls=new triple[n]; for(size_t i=0; i < n; i++) Controls[i]=t*controls[i]; } boundstriples(x,y,z,X,Y,Z,n,Controls); b.add(x,y,z); b.add(X,Y,Z); if(t == NULL) { Min=triple(x,y,z); Max=triple(X,Y,Z); } else delete[] Controls; } drawElement *drawNurbs::transformed(const double* t) { return new drawNurbs(t,this); } void drawNurbs::ratio(const double *t, pair &b, double (*m)(double, double), double, bool &first) { const size_t n=nu*nv; triple* Controls; if(t == NULL) Controls=controls; else { Controls=new triple[n]; for(unsigned int i=0; i < n; ++i) Controls[i]=t*controls[i]; } if(first) { first=false; triple v=Controls[0]; b=pair(xratio(v),yratio(v)); } double x=b.getx(); double y=b.gety(); for(size_t i=0; i < n; ++i) { triple v=Controls[i]; x=m(x,xratio(v)); y=m(y,yratio(v)); } b=pair(x,y); if(t != NULL) delete[] Controls; } void drawNurbs::displacement() { #ifdef HAVE_GL size_t n=nu*nv; size_t nuknots=udegree+nu+1; size_t nvknots=vdegree+nv+1; if(Controls == NULL) { Controls=new(UseGC) GLfloat[(weights ? 4 : 3)*n]; uKnots=new(UseGC) GLfloat[nuknots]; vKnots=new(UseGC) GLfloat[nvknots]; } if(weights) for(size_t i=0; i < n; ++i) store(Controls+4*i,controls[i],weights[i]); else for(size_t i=0; i < n; ++i) store(Controls+3*i,controls[i]); for(size_t i=0; i < nuknots; ++i) uKnots[i]=uknots[i]; for(size_t i=0; i < nvknots; ++i) vKnots[i]=vknots[i]; #endif } void drawNurbs::render(GLUnurbs *nurb, double size2, const triple& Min, const triple& Max, double perspective, bool lighton, bool transparent) { #ifdef HAVE_GL if(invisible || ((colors ? colors[3]+colors[7]+colors[11]+colors[15] < 4.0 : diffuse.A < 1.0) ^ transparent)) return; double t[16]; // current transform glGetDoublev(GL_MODELVIEW_MATRIX,t); run::transpose(t,4); bbox3 B(this->Min,this->Max); B.transform(t); triple m=B.Min(); triple M=B.Max(); if(perspective) { double f=m.getz()*perspective; double F=M.getz()*perspective; if(M.getx() < min(f*Min.getx(),F*Min.getx()) || m.getx() > max(f*Max.getx(),F*Max.getx()) || M.gety() < min(f*Min.gety(),F*Min.gety()) || m.gety() > max(f*Max.gety(),F*Max.gety()) || M.getz() < Min.getz() || m.getz() > Max.getz()) return; } else { if(M.getx() < Min.getx() || m.getx() > Max.getx() || M.gety() < Min.gety() || m.gety() > Max.gety() || M.getz() < Min.getz() || m.getz() > Max.getz()) return; } setcolors(colors,lighton,diffuse,ambient,emissive,specular,shininess); gluBeginSurface(nurb); int uorder=udegree+1; int vorder=vdegree+1; size_t stride=weights ? 4 : 3; gluNurbsSurface(nurb,uorder+nu,uKnots,vorder+nv,vKnots,stride*nv,stride, Controls,uorder,vorder, weights ? GL_MAP2_VERTEX_4 : GL_MAP2_VERTEX_3); if(lighton) gluNurbsCallback(nurb,GLU_NURBS_NORMAL,(_GLUfuncptr) glNormal3fv); if(colors) { static GLfloat linear[]={0.0,0.0,1.0,1.0}; gluNurbsSurface(nurb,4,linear,4,linear,8,4,colors,2,2,GL_MAP2_COLOR_4); } gluEndSurface(nurb); if(colors) glDisable(GL_COLOR_MATERIAL); #endif } void drawSphere::P(triple& t, double x, double y, double z) { if(half) { double temp=z; z=x; x=-temp; } if(T == NULL) { t=triple(x,y,z); return; } double f=T[12]*x+T[13]*y+T[14]*z+T[15]; if(f == 0.0) run::dividebyzero(); f=1.0/f; t=triple((T[0]*x+T[1]*y+T[2]*z+T[3])*f,(T[4]*x+T[5]*y+T[6]*z+T[7])*f, (T[8]*x+T[9]*y+T[10]*z+T[11])*f); } bool drawSphere::write(prcfile *out, unsigned int *, double, groupsmap&) { if(invisible) return true; PRCmaterial m(ambient,diffuse,emissive,specular,opacity,shininess); switch(type) { case 0: // PRCsphere { if(half) out->addHemisphere(1.0,m,NULL,NULL,NULL,1.0,T); else out->addSphere(1.0,m,NULL,NULL,NULL,1.0,T); break; } case 1: // NURBSsphere { static double uknot[]={0.0,0.0,1.0/3.0,0.5,1.0,1.0}; static double vknot[]={0.0,0.0,0.0,0.0,1.0,1.0,1.0,1.0}; static double Weights[12]={2.0/3.0,2.0/9.0,2.0/9.0,2.0/3.0, 1.0/3.0,1.0/9.0,1.0/9.0,1.0/3.0, 1.0,1.0/3.0,1.0/3.0,1.0}; // NURBS representation of a sphere using 10 distinct control points // K. Qin, J. Comp. Sci. and Tech. 12, 210-216 (1997). triple N,S,P1,P2,P3,P4,P5,P6,P7,P8; P(N,0.0,0.0,1.0); P(P1,-2.0,-2.0,1.0); P(P2,-2.0,-2.0,-1.0); P(S,0.0,0.0,-1.0); P(P3,2.0,-2.0,1.0); P(P4,2.0,-2.0,-1.0); P(P5,2.0,2.0,1.0); P(P6,2.0,2.0,-1.0); P(P7,-2.0,2.0,1.0); P(P8,-2.0,2.0,-1.0); triple p0[]={N,P1,P2,S, N,P3,P4,S, N,P5,P6,S, N,P7,P8,S, N,P1,P2,S, N,P3,P4,S}; out->addSurface(2,3,3,4,p0,uknot,vknot,m,Weights); out->addSurface(2,3,3,4,p0+4,uknot,vknot,m,Weights); if(!half) { out->addSurface(2,3,3,4,p0+8,uknot,vknot,m,Weights); out->addSurface(2,3,3,4,p0+12,uknot,vknot,m,Weights); } break; } default: reportError("Invalid sphere type"); } return true; } bool drawCylinder::write(prcfile *out, unsigned int *, double, groupsmap&) { if(invisible) return true; PRCmaterial m(ambient,diffuse,emissive,specular,opacity,shininess); out->addCylinder(1.0,1.0,m,NULL,NULL,NULL,1.0,T); return true; } bool drawDisk::write(prcfile *out, unsigned int *, double, groupsmap&) { if(invisible) return true; PRCmaterial m(ambient,diffuse,emissive,specular,opacity,shininess); out->addDisk(1.0,m,NULL,NULL,NULL,1.0,T); return true; } bool drawTube::write(prcfile *out, unsigned int *, double, groupsmap&) { if(invisible) return true; PRCmaterial m(ambient,diffuse,emissive,specular,opacity,shininess); Int n=center.length(); if(center.piecewisestraight()) { triple *centerControls=new(UseGC) triple[n+1]; for(Int i=0; i <= n; ++i) centerControls[i]=center.point(i); size_t N=n+1; triple *controls=new(UseGC) triple[N]; for(Int i=0; i <= n; ++i) controls[i]=g.point(i); out->addTube(N,centerControls,controls,true,m); } else { size_t N=3*n+1; triple *centerControls=new(UseGC) triple[N]; centerControls[0]=center.point((Int) 0); centerControls[1]=center.postcontrol((Int) 0); size_t k=1; for(Int i=1; i < n; ++i) { centerControls[++k]=center.precontrol(i); centerControls[++k]=center.point(i); centerControls[++k]=center.postcontrol(i); } centerControls[++k]=center.precontrol(n); centerControls[++k]=center.point(n); triple *controls=new(UseGC) triple[N]; controls[0]=g.point((Int) 0); controls[1]=g.postcontrol((Int) 0); k=1; for(Int i=1; i < n; ++i) { controls[++k]=g.precontrol(i); controls[++k]=g.point(i); controls[++k]=g.postcontrol(i); } controls[++k]=g.precontrol(n); controls[++k]=g.point(n); out->addTube(N,centerControls,controls,false,m); } return true; } bool drawPixel::write(prcfile *out, unsigned int *, double, groupsmap&) { if(invisible) return true; out->addPoint(v,c,width); return true; } void drawPixel::render(GLUnurbs *nurb, double size2, const triple& Min, const triple& Max, double perspective, bool lighton, bool transparent) { #ifdef HAVE_GL if(invisible) return; GLfloat V[4]; glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT_AND_BACK,GL_EMISSION); static GLfloat Black[]={0,0,0,1}; glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,Black); glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,Black); glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,Black); glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,0.0); glPointSize(1.0+width); glBegin(GL_POINT); storecolor(V,0,c); glColor4fv(V); store(V,v); glVertex3fv(V); glEnd(); glPointSize(1.0); glDisable(GL_COLOR_MATERIAL); #endif } const string drawBaseTriangles::wrongsize= "triangle indices require 3 components"; const string drawBaseTriangles::outofrange="index out of range"; void drawBaseTriangles::bounds(const double* t, bbox3& b) { double x,y,z; double X,Y,Z; triple* tP; if(t == NULL) tP=P; else { tP=new triple[nP]; for(size_t i=0; i < nP; i++) tP[i]=t*P[i]; } boundstriples(x,y,z,X,Y,Z,nP,tP); b.add(x,y,z); b.add(X,Y,Z); if(t == NULL) { Min=triple(x,y,z); Max=triple(X,Y,Z); } else delete[] tP; } void drawBaseTriangles::ratio(const double* t, pair &b, double (*m)(double, double), double fuzz, bool &first) { triple* tP; if(t == NULL) tP=P; else { tP=new triple[nP]; for(size_t i=0; i < nP; i++) tP[i]=t*P[i]; } ratiotriples(b,m,first,nP,tP); if(t != NULL) delete[] tP; } bool drawTriangles::write(prcfile *out, unsigned int *, double, groupsmap&) { if(invisible) return true; if (nC) { const RGBAColour white(1,1,1,opacity); const RGBAColour black(0,0,0,opacity); const PRCmaterial m(black,white,black,specular,opacity,PRCshininess); out->addTriangles(nP,P,nI,PI,m,nN,N,NI,0,NULL,NULL,nC,C,CI,0,NULL,NULL,30); } else { const PRCmaterial m(ambient,diffuse,emissive,specular,opacity,PRCshininess); out->addTriangles(nP,P,nI,PI,m,nN,N,NI,0,NULL,NULL,0,NULL,NULL,0,NULL,NULL,30); } return true; } void drawTriangles::render(GLUnurbs *nurb, double size2, const triple& Min, const triple& Max, double perspective, bool lighton, bool transparent) { #ifdef HAVE_GL if(invisible) return; if(invisible || ((diffuse.A < 1.0) ^ transparent)) return; triple m,M; double t[16]; // current transform glGetDoublev(GL_MODELVIEW_MATRIX,t); run::transpose(t,4); bbox3 B(this->Min,this->Max); B.transform(t); m=B.Min(); M=B.Max(); if(perspective) { const double f=m.getz()*perspective; const double F=M.getz()*perspective; if((M.getx() < min(f*Min.getx(),F*Min.getx()) || m.getx() > max(f*Max.getx(),F*Max.getx()) || M.gety() < min(f*Min.gety(),F*Min.gety()) || m.gety() > max(f*Max.gety(),F*Max.gety()) || M.getz() < Min.getz() || m.getz() > Max.getz())) return; } else { if((M.getx() < Min.getx() || m.getx() > Max.getx() || M.gety() < Min.gety() || m.gety() > Max.gety() || M.getz() < Min.getz() || m.getz() > Max.getz())) return; } setcolors(nC,!nC,diffuse,ambient,emissive,specular,shininess); if(!nN) lighton=false; glBegin(GL_TRIANGLES); for(size_t i=0; i < nI; i++) { const uint32_t *pi=PI[i]; const uint32_t *ni=NI[i]; const uint32_t *ci=nC ? CI[i] : 0; if(lighton) glNormal3f(N[ni[0]].getx(),N[ni[0]].gety(),N[ni[0]].getz()); if(nC) glColor4f(C[ci[0]].R,C[ci[0]].G,C[ci[0]].B,C[ci[0]].A); glVertex3f(P[pi[0]].getx(),P[pi[0]].gety(),P[pi[0]].getz()); if(lighton) glNormal3f(N[ni[1]].getx(),N[ni[1]].gety(),N[ni[1]].getz()); if(nC) glColor4f(C[ci[1]].R,C[ci[1]].G,C[ci[1]].B,C[ci[1]].A); glVertex3f(P[pi[1]].getx(),P[pi[1]].gety(),P[pi[1]].getz()); if(lighton) glNormal3f(N[ni[2]].getx(),N[ni[2]].gety(),N[ni[2]].getz()); if(nC) glColor4f(C[ci[2]].R,C[ci[2]].G,C[ci[2]].B,C[ci[2]].A); glVertex3f(P[pi[2]].getx(),P[pi[2]].gety(),P[pi[2]].getz()); } glEnd(); if(nC) glDisable(GL_COLOR_MATERIAL); #endif } } //namespace camp asymptote-2.37/drawsurface.h000066400000000000000000000522561265434602500161720ustar00rootroot00000000000000/***** * drawsurface.h * * Stores a surface that has been added to a picture. *****/ #ifndef DRAWSURFACE_H #define DRAWSURFACE_H #include "drawelement.h" #include "triple.h" #include "arrayop.h" #include "path3.h" namespace camp { #ifdef HAVE_GL void storecolor(GLfloat *colors, int i, const vm::array &pens, int j); #endif class drawSurface : public drawElement { protected: triple *controls; triple vertices[4]; triple center; bool straight; // True iff Bezier patch is planar and has straight edges. prc::RGBAColour diffuse; prc::RGBAColour ambient; prc::RGBAColour emissive; prc::RGBAColour specular; prc::RGBAColour *colors; double opacity; double shininess; double PRCshininess; triple normal; bool invisible; Interaction interaction; triple Min,Max; bool prc; #ifdef HAVE_GL triple d; // Maximum deviation of surface from a quadrilateral. triple dperp; #endif public: drawSurface(const vm::array& g, triple center, bool straight, const vm::array&p, double opacity, double shininess, double PRCshininess, triple normal, const vm::array &pens, Interaction interaction, bool prc) : center(center), straight(straight), opacity(opacity), shininess(shininess), PRCshininess(PRCshininess), normal(unit(normal)), interaction(interaction), prc(prc) { const string wrongsize= "Bezier surface patch requires 4x4 array of triples and array of 4 pens"; if(checkArray(&g) != 4 || checkArray(&p) != 4) reportError(wrongsize); vm::array *g0=vm::read(g,0); vm::array *g3=vm::read(g,3); if(checkArray(g0) != 4 || checkArray(g3) != 4) reportError(wrongsize); vertices[0]=vm::read(g0,0); vertices[1]=vm::read(g0,3); vertices[2]=vm::read(g3,0); vertices[3]=vm::read(g3,3); if(!straight) { size_t k=0; controls=new(UseGC) triple[16]; for(size_t i=0; i < 4; ++i) { vm::array *gi=vm::read(g,i); if(checkArray(gi) != 4) reportError(wrongsize); for(size_t j=0; j < 4; ++j) controls[k++]=vm::read(gi,j); } } else controls=NULL; pen surfacepen=vm::read(p,0); invisible=surfacepen.invisible(); diffuse=rgba(surfacepen); ambient=rgba(vm::read(p,1)); emissive=rgba(vm::read(p,2)); specular=rgba(vm::read(p,3)); int size=checkArray(&pens); if(size > 0) { if(size != 4) reportError("4 vertex pens required"); colors=new(UseGC) prc::RGBAColour[4]; colors[0]=rgba(vm::read(pens,0)); colors[1]=rgba(vm::read(pens,3)); colors[2]=rgba(vm::read(pens,1)); colors[3]=rgba(vm::read(pens,2)); } else colors=NULL; } drawSurface(const double* t, const drawSurface *s) : straight(s->straight), diffuse(s->diffuse), ambient(s->ambient), emissive(s->emissive), specular(s->specular), colors(s->colors), opacity(s->opacity), shininess(s->shininess), PRCshininess(s->PRCshininess), invisible(s->invisible), interaction(s->interaction), prc(s->prc) { for(unsigned int i=0; i < 4; ++i) vertices[i]=t*s->vertices[i]; if(s->controls) { controls=new(UseGC) triple[16]; for(unsigned int i=0; i < 16; ++i) controls[i]=t*s->controls[i]; } else controls=NULL; #ifdef HAVE_GL center=t*s->center; normal=transformNormal(t,s->normal); #endif } bool is3D() {return true;} void bounds(const double* t, bbox3& b); void ratio(const double* t, pair &b, double (*m)(double, double), double fuzz, bool &first); virtual ~drawSurface() {} bool write(prcfile *out, unsigned int *, double, groupsmap&); void displacement(); void render(GLUnurbs *nurb, double, const triple& Min, const triple& Max, double perspective, bool lighton, bool transparent); drawElement *transformed(const double* t); }; class drawBezierTriangle : public drawElement { protected: triple *controls; triple center; bool straight; // True iff Bezier triangle is planar and has straight edges. prc::RGBAColour diffuse; prc::RGBAColour ambient; prc::RGBAColour emissive; prc::RGBAColour specular; prc::RGBAColour *colors; double opacity; double shininess; double PRCshininess; bool invisible; Interaction interaction; triple Min,Max; bool prc; #ifdef HAVE_GL triple d; // Maximum deviation of surface from a triangle. triple dperp; #endif public: drawBezierTriangle(const vm::array& g, triple center, bool straight, const vm::array&p, double opacity, double shininess, double PRCshininess, const vm::array &pens, Interaction interaction, bool prc) : center(center), straight(straight), opacity(opacity), shininess(shininess), PRCshininess(PRCshininess), interaction(interaction), prc(prc) { const string wrongsize= "Bezier triangle requires triangular array of 10 triples and array of 4 pens"; if(checkArray(&g) != 4 || checkArray(&p) != 4) reportError(wrongsize); size_t k=0; controls=new(UseGC) triple[10]; for(unsigned int i=0; i < 4; ++i) { vm::array *gi=vm::read(g,i); for(unsigned int j=0; j <= i; ++j) { controls[k++]=vm::read(gi,j); } } pen surfacepen=vm::read(p,0); invisible=surfacepen.invisible(); diffuse=rgba(surfacepen); ambient=rgba(vm::read(p,1)); emissive=rgba(vm::read(p,2)); specular=rgba(vm::read(p,3)); int size=checkArray(&pens); if(size > 0) { if(size != 3) reportError("3 vertex pens required"); colors=new(UseGC) prc::RGBAColour[3]; colors[0]=rgba(vm::read(pens,0)); colors[1]=rgba(vm::read(pens,1)); colors[2]=rgba(vm::read(pens,2)); } else colors=NULL; } drawBezierTriangle(const double* t, const drawBezierTriangle *s) : straight(s->straight), diffuse(s->diffuse), ambient(s->ambient), emissive(s->emissive), specular(s->specular), colors(s->colors), opacity(s->opacity), shininess(s->shininess), PRCshininess(s->PRCshininess), invisible(s->invisible), interaction(s->interaction), prc(s->prc) { if(s->controls) { controls=new(UseGC) triple[10]; for(unsigned int i=0; i < 10; ++i) controls[i]=t*s->controls[i]; } else controls=NULL; #ifdef HAVE_GL center=t*s->center; #endif } bool is3D() {return true;} void bounds(const double* t, bbox3& b); void ratio(const double* t, pair &b, double (*m)(double, double), double fuzz, bool &first); virtual ~drawBezierTriangle() {} bool write(prcfile *out, unsigned int *, double, groupsmap&); // void displacement(); void render(GLUnurbs *nurb, double, const triple& Min, const triple& Max, double perspective, bool lighton, bool transparent); drawElement *transformed(const double* t); }; class drawNurbs : public drawElement { protected: size_t udegree,vdegree; size_t nu,nv; triple *controls; double *weights; double *uknots, *vknots; prc::RGBAColour diffuse; prc::RGBAColour ambient; prc::RGBAColour emissive; prc::RGBAColour specular; double opacity; double shininess; double PRCshininess; triple normal; bool invisible; triple Min,Max; #ifdef HAVE_GL GLfloat *colors; GLfloat *Controls; GLfloat *uKnots; GLfloat *vKnots; #endif public: drawNurbs(const vm::array& g, const vm::array* uknot, const vm::array* vknot, const vm::array* weight, const vm::array&p, double opacity, double shininess, double PRCshininess, const vm::array &pens) : opacity(opacity), shininess(shininess), PRCshininess(PRCshininess) { size_t weightsize=checkArray(weight); const string wrongsize="Inconsistent NURBS data"; nu=checkArray(&g); if(nu == 0 || (weightsize != 0 && weightsize != nu) || checkArray(&p) != 4) reportError(wrongsize); vm::array *g0=vm::read(g,0); nv=checkArray(g0); size_t n=nu*nv; controls=new(UseGC) triple[n]; size_t k=0; for(size_t i=0; i < nu; ++i) { vm::array *gi=vm::read(g,i); if(checkArray(gi) != nv) reportError(wrongsize); for(size_t j=0; j < nv; ++j) controls[k++]=vm::read(gi,j); } if(weightsize > 0) { size_t k=0; weights=new(UseGC) double[n]; for(size_t i=0; i < nu; ++i) { vm::array *weighti=vm::read(weight,i); if(checkArray(weighti) != nv) reportError(wrongsize); for(size_t j=0; j < nv; ++j) weights[k++]=vm::read(weighti,j); } } else weights=NULL; size_t nuknots=checkArray(uknot); size_t nvknots=checkArray(vknot); if(nuknots <= nu+1 || nuknots > 2*nu || nvknots <= nv+1 || nvknots > 2*nv) reportError(wrongsize); udegree=nuknots-nu-1; vdegree=nvknots-nv-1; run::copyArrayC(uknots,uknot,0,UseGC); run::copyArrayC(vknots,vknot,0,UseGC); pen surfacepen=vm::read(p,0); invisible=surfacepen.invisible(); diffuse=rgba(surfacepen); ambient=rgba(vm::read(p,1)); emissive=rgba(vm::read(p,2)); specular=rgba(vm::read(p,3)); #ifdef HAVE_GL Controls=NULL; int size=checkArray(&pens); if(size > 0) { colors=new(UseGC) GLfloat[16]; if(size != 4) reportError(wrongsize); storecolor(colors,0,pens,0); storecolor(colors,8,pens,1); storecolor(colors,12,pens,2); storecolor(colors,4,pens,3); } else colors=NULL; #endif } drawNurbs(const double* t, const drawNurbs *s) : udegree(s->udegree), vdegree(s->vdegree), nu(s->nu), nv(s->nv), weights(s->weights), uknots(s->uknots), vknots(s->vknots), diffuse(s->diffuse), ambient(s->ambient), emissive(s->emissive), specular(s->specular), opacity(s->opacity), shininess(s->shininess), PRCshininess(s->PRCshininess), invisible(s->invisible) { const size_t n=nu*nv; controls=new(UseGC) triple[n]; for(unsigned int i=0; i < n; ++i) controls[i]=t*s->controls[i]; #ifdef HAVE_GL Controls=NULL; colors=s->colors; #endif } bool is3D() {return true;} void bounds(const double* t, bbox3& b); virtual ~drawNurbs() {} bool write(prcfile *out, unsigned int *, double, groupsmap&); void displacement(); void ratio(const double* t, pair &b, double (*m)(double, double), double, bool &first); void render(GLUnurbs *nurb, double size2, const triple& Min, const triple& Max, double perspective, bool lighton, bool transparent); drawElement *transformed(const double* t); }; // Draw a transformed PRC object. class drawPRC : public drawElementLC { protected: prc::RGBAColour diffuse; prc::RGBAColour ambient; prc::RGBAColour emissive; prc::RGBAColour specular; double opacity; double shininess; bool invisible; public: drawPRC(const vm::array& t, const vm::array&p, double opacity, double shininess) : drawElementLC(t), opacity(opacity), shininess(shininess) { string needfourpens="array of 4 pens required"; if(checkArray(&p) != 4) reportError(needfourpens); pen surfacepen=vm::read(p,0); invisible=surfacepen.invisible(); diffuse=rgba(surfacepen); ambient=rgba(vm::read(p,1)); emissive=rgba(vm::read(p,2)); specular=rgba(vm::read(p,3)); } drawPRC(const double* t, const drawPRC *s) : drawElementLC(t, s), diffuse(s->diffuse), ambient(s->ambient), emissive(s->emissive), specular(s->specular), opacity(s->opacity), shininess(s->shininess), invisible(s->invisible) { } bool write(prcfile *out, unsigned int *, double, groupsmap&) { return true; } virtual void transformedbounds(const double*, bbox3&) {} virtual void transformedratio(const double*, pair&, double (*)(double, double), double, bool&) {} }; // Draw a PRC unit sphere. class drawSphere : public drawPRC { bool half; int type; public: drawSphere(const vm::array& t, bool half, const vm::array&p, double opacity, double shininess, int type) : drawPRC(t,p,opacity,shininess), half(half), type(type) {} drawSphere(const double* t, const drawSphere *s) : drawPRC(t,s), half(s->half), type(s->type) {} void P(triple& t, double x, double y, double z); bool write(prcfile *out, unsigned int *, double, groupsmap&); drawElement *transformed(const double* t) { return new drawSphere(t,this); } }; // Draw a PRC unit cylinder. class drawCylinder : public drawPRC { public: drawCylinder(const vm::array& t, const vm::array&p, double opacity, double shininess) : drawPRC(t,p,opacity,shininess) {} drawCylinder(const double* t, const drawCylinder *s) : drawPRC(t,s) {} bool write(prcfile *out, unsigned int *, double, groupsmap&); drawElement *transformed(const double* t) { return new drawCylinder(t,this); } }; // Draw a PRC unit disk. class drawDisk : public drawPRC { public: drawDisk(const vm::array& t, const vm::array&p, double opacity, double shininess) : drawPRC(t,p,opacity,shininess) {} drawDisk(const double* t, const drawDisk *s) : drawPRC(t,s) {} bool write(prcfile *out, unsigned int *, double, groupsmap&); drawElement *transformed(const double* t) { return new drawDisk(t,this); } }; // Draw a PRC tube. class drawTube : public drawElement { protected: path3 center; path3 g; prc::RGBAColour diffuse; prc::RGBAColour ambient; prc::RGBAColour emissive; prc::RGBAColour specular; double opacity; double shininess; bool invisible; public: drawTube(path3 center, path3 g, const vm::array&p, double opacity, double shininess) : center(center), g(g), opacity(opacity), shininess(shininess) { string needfourpens="array of 4 pens required"; if(checkArray(&p) != 4) reportError(needfourpens); pen surfacepen=vm::read(p,0); invisible=surfacepen.invisible(); diffuse=rgba(surfacepen); ambient=rgba(vm::read(p,1)); emissive=rgba(vm::read(p,2)); specular=rgba(vm::read(p,3)); } drawTube(const double* t, const drawTube *s) : center(camp::transformed(t,s->center)), g(camp::transformed(t,s->g)), diffuse(s->diffuse), ambient(s->ambient), emissive(s->emissive), specular(s->specular), opacity(s->opacity), shininess(s->shininess), invisible(s->invisible) { } bool write(prcfile *out, unsigned int *, double, groupsmap&); drawElement *transformed(const double* t) { return new drawTube(t,this); } }; // Draw a PRC pixel. class drawPixel : public drawElement { triple v; prc::RGBAColour c; double width; bool invisible; public: drawPixel(const triple& v0, const pen& p, double width) : c(rgba(p)), width(width) { v=v0; invisible=p.invisible(); } drawPixel(const double* t, const drawPixel *s) : c(s->c), width(s->width), invisible(s->invisible) { v=t*s->v; } void bounds(const double* t, bbox3& b) { const triple R=0.5*width*triple(1.0,1.0,1.0); if (t != NULL) { triple tv; tv=t*v; b.add(tv-R); b.add(tv+R); } else { b.add(v-R); b.add(v+R); } } void render(GLUnurbs *nurb, double size2, const triple& Min, const triple& Max, double perspective, bool lighton, bool transparent); bool write(prcfile *out, unsigned int *, double, groupsmap&); drawElement *transformed(const double* t) { return new drawPixel(t,this); } }; class drawBaseTriangles : public drawElement { protected: size_t nP; triple* P; size_t nN; triple* N; size_t nI; uint32_t (*PI)[3]; uint32_t (*NI)[3]; triple Min,Max; static const string wrongsize; static const string outofrange; public: drawBaseTriangles(const vm::array& v, const vm::array& vi, const vm::array& n, const vm::array& ni) { nP=checkArray(&v); P=new(UseGC) triple[nP]; for(size_t i=0; i < nP; ++i) P[i]=vm::read(v,i); nI=checkArray(&vi); PI=new(UseGC) uint32_t[nI][3]; for(size_t i=0; i < nI; ++i) { vm::array *vii=vm::read(vi,i); if(checkArray(vii) != 3) reportError(wrongsize); uint32_t *PIi=PI[i]; for(size_t j=0; j < 3; ++j) { size_t index=unsignedcast(vm::read(vii,j)); if(index >= nP) reportError(outofrange); PIi[j]=index; } } nN=checkArray(&n); if(nN) { N=new(UseGC) triple[nN]; for(size_t i=0; i < nN; ++i) N[i]=vm::read(n,i); if(checkArray(&ni) != nI) reportError("Index arrays have different lengths"); NI=new(UseGC) uint32_t[nI][3]; for(size_t i=0; i < nI; ++i) { vm::array *nii=vm::read(ni,i); if(checkArray(nii) != 3) reportError(wrongsize); uint32_t *NIi=NI[i]; for(size_t j=0; j < 3; ++j) { size_t index=unsignedcast(vm::read(nii,j)); if(index >= nN) reportError(outofrange); NIi[j]=index; } } } } drawBaseTriangles(const double* t, const drawBaseTriangles *s) : nP(s->nP), nN(s->nN), nI(s->nI) { P=new(UseGC) triple[nP]; for(size_t i=0; i < nP; i++) P[i]=t*s->P[i]; PI=new(UseGC) uint32_t[nI][3]; for(size_t i=0; i < nI; ++i) { uint32_t *PIi=PI[i]; uint32_t *sPIi=s->PI[i]; for(size_t j=0; j < 3; ++j) PIi[j]=sPIi[j]; } if(nN) { N=new(UseGC) triple[nN]; for(size_t i=0; i < nN; i++) N[i]=transformNormal(t,s->N[i]); NI=new(UseGC) uint32_t[nI][3]; for(size_t i=0; i < nI; ++i) { uint32_t *NIi=NI[i]; uint32_t *sNIi=s->NI[i]; for(size_t j=0; j < 3; ++j) NIi[j]=sNIi[j]; } } } bool is3D() {return true;} void bounds(const double* t, bbox3& b); void ratio(const double* t, pair &b, double (*m)(double, double), double fuzz, bool &first); virtual ~drawBaseTriangles() {} drawElement *transformed(const double* t) { return new drawBaseTriangles(t,this); } }; class drawTriangles : public drawBaseTriangles { size_t nC; prc::RGBAColour*C; uint32_t (*CI)[3]; // Asymptote material data prc::RGBAColour diffuse; prc::RGBAColour ambient; prc::RGBAColour emissive; prc::RGBAColour specular; double opacity; double shininess; double PRCshininess; bool invisible; public: drawTriangles(const vm::array& v, const vm::array& vi, const vm::array& n, const vm::array& ni, const vm::array&p, double opacity, double shininess, double PRCshininess, const vm::array& c, const vm::array& ci) : drawBaseTriangles(v,vi,n,ni), opacity(opacity), shininess(shininess), PRCshininess(PRCshininess) { const string needfourpens="array of 4 pens required"; if(checkArray(&p) != 4) reportError(needfourpens); const pen surfacepen=vm::read(p,0); invisible=surfacepen.invisible(); diffuse=rgba(surfacepen); nC=checkArray(&c); if(nC) { C=new(UseGC) prc::RGBAColour[nC]; for(size_t i=0; i < nC; ++i) C[i]=rgba(vm::read(c,i)); size_t nI=checkArray(&vi); if(checkArray(&ci) != nI) reportError("Index arrays have different lengths"); CI=new(UseGC) uint32_t[nI][3]; for(size_t i=0; i < nI; ++i) { vm::array *cii=vm::read(ci,i); if(checkArray(cii) != 3) reportError(wrongsize); uint32_t *CIi=CI[i]; for(size_t j=0; j < 3; ++j) { size_t index=unsignedcast(vm::read(cii,j)); if(index >= nC) reportError(outofrange); CIi[j]=index; } } } else { ambient=rgba(vm::read(p,1)); emissive=rgba(vm::read(p,2)); } specular=rgba(vm::read(p,3)); } drawTriangles(const double* t, const drawTriangles *s) : drawBaseTriangles(t,s), nC(s->nC), diffuse(s->diffuse), ambient(s->ambient), emissive(s->emissive), specular(s->specular), opacity(s->opacity), shininess(s->shininess), PRCshininess(s->PRCshininess), invisible(s->invisible) { if(nC) { C=new(UseGC) prc::RGBAColour[nC]; for(size_t i=0; i < nC; ++i) C[i]=s->C[i]; CI=new(UseGC) uint32_t[nI][3]; for(size_t i=0; i < nI; ++i) { uint32_t *CIi=CI[i]; uint32_t *sCIi=s->CI[i]; for(size_t j=0; j < 3; ++j) CIi[j]=sCIi[j]; } } } virtual ~drawTriangles() {} void render(GLUnurbs *nurb, double size2, const triple& Min, const triple& Max, double perspective, bool lighton, bool transparent); bool write(prcfile *out, unsigned int *, double, groupsmap&); drawElement *transformed(const double* t) { return new drawTriangles(t,this); } }; } #endif asymptote-2.37/drawverbatim.h000066400000000000000000000023771265434602500163520ustar00rootroot00000000000000/***** * drawverbatim.h * John Bowman 2003/03/18 * * Add verbatim postscript to picture. *****/ #ifndef DRAWVERBATIM_H #define DRAWVERBATIM_H #include "drawelement.h" namespace camp { enum Language {PostScript,TeX}; class drawVerbatim : public drawElement { private: Language language; string text; bool userbounds; pair min,max; bool havebounds; public: drawVerbatim(Language language, const string& text) : language(language), text(text), userbounds(false), havebounds(false) {} drawVerbatim(Language language, const string& text, pair min, pair max) : language(language), text(text), userbounds(true), min(min), max(max), havebounds(false) {} virtual ~drawVerbatim() {} void bounds(bbox& b, iopipestream& tex, boxvector&, bboxlist&) { if(havebounds) return; havebounds=true; if(language == TeX) tex << text << "%" << newl; if(userbounds) { b += min; b += max; } } bool islabel() { return language == TeX; } bool draw(psfile *out) { if(language == PostScript) out->verbatimline(text); return true; } bool write(texfile *out, const bbox&) { if(language == TeX) out->verbatimline(stripblanklines(text)); return true; } }; } #endif asymptote-2.37/entry.cc000066400000000000000000000504021265434602500151520ustar00rootroot00000000000000/***** * entry.cc * Andy Hammerlindl 2002/08/29 * * All variables, built-in functions and user-defined functions reside * within the same namespace. To keep track of all these, table of * "entries" is used. *****/ #include #include #include #include #include "entry.h" #include "coder.h" using std::memset; using types::ty; using types::signature; using types::overloaded; using types::ty_vector; using types::ty_iterator; namespace trans { bool entry::pr::check(action act, coder &c) { // We assume PUBLIC permissions and one's without an associated record are not // stored. assert(perm!=PUBLIC && r!=0); return c.inTranslation(r->getLevel()) || (perm == RESTRICTED && act != WRITE); } void entry::pr::report(action act, position pos, coder &c) { if (!c.inTranslation(r->getLevel())) { if (perm == PRIVATE) { em.error(pos); em << "accessing private field outside of structure"; } else if (perm == RESTRICTED && act == WRITE) { em.error(pos); em << "modifying non-public field outside of structure"; } } } entry::entry(entry &e1, entry &e2) : where(e2.where), pos(e2.pos) { perms.insert(perms.end(), e1.perms.begin(), e1.perms.end()); perms.insert(perms.end(), e2.perms.begin(), e2.perms.end()); } entry::entry(entry &base, permission perm, record *r) : where(base.where), pos(base.pos) { perms.insert(perms.end(), base.perms.begin(), base.perms.end()); addPerm(perm, r); } bool entry::checkPerm(action act, coder &c) { for (mem::list::iterator p=perms.begin(); p != perms.end(); ++p) if (!p->check(act, c)) return false; return true; } void entry::reportPerm(action act, position pos, coder &c) { for (mem::list::iterator p=perms.begin(); p != perms.end(); ++p) p->report(act, pos, c); } varEntry::varEntry(varEntry &qv, varEntry &v) : entry(qv,v), t(v.t), location(new qualifiedAccess(qv.location, qv.getLevel(), v.location)) {} frame *varEntry::getLevel() { record *r=dynamic_cast(t); assert(r); return r->getLevel(); } void varEntry::encode(action act, position pos, coder &c) { reportPerm(act, pos, c); getLocation()->encode(act, pos, c); } void varEntry::encode(action act, position pos, coder &c, frame *top) { reportPerm(act, pos, c); getLocation()->encode(act, pos, c, top); } varEntry *qualifyVarEntry(varEntry *qv, varEntry *v) { return qv ? (v ? new varEntry(*qv,*v) : qv) : v; } bool tenv::add(symbol dest, names_t::value_type &x, varEntry *qualifier, coder &c) { if (!x.second.empty()) { tyEntry *ent=x.second.front(); if (ent->checkPerm(READ, c)) { enter(dest, qualifyTyEntry(qualifier, ent)); return true; } } return false; } void tenv::add(tenv& source, varEntry *qualifier, coder &c) { // Enter each distinct (unshadowed) name,type pair. for(names_t::iterator p = source.names.begin(); p != source.names.end(); ++p) add(p->first, *p, qualifier, c); } bool tenv::add(symbol src, symbol dest, tenv& source, varEntry *qualifier, coder &c) { names_t::iterator p = source.names.find(src); if (p != source.names.end()) return add(dest, *p, qualifier, c); else return false; } #if 0 //{{{ /*NOHASH*/ void venv::add(venv& source, varEntry *qualifier, coder &c) /*NOHASH*/ { /*NOHASH*/ // Enter each distinct (unshadowed) name,type pair. /*NOHASH*/ for(names_t::iterator p = source.names.begin(); /*NOHASH*/ p != source.names.end(); /*NOHASH*/ ++p) /*NOHASH*/ add(p->first, p->first, source, qualifier, c); /*NOHASH*/ } /*NOHASH*/ /*NOHASH*/ bool venv::add(symbol src, symbol dest, /*NOHASH*/ venv& source, varEntry *qualifier, coder &c) /*NOHASH*/ { /*NOHASH*/ bool added=false; /*NOHASH*/ name_t &list=source.names[src]; /*NOHASH*/ types::overloaded set; // To keep track of what is shadowed. /*NOHASH*/ bool special = src.special(); /*NOHASH*/ /*NOHASH*/ for(name_iterator p = list.begin(); /*NOHASH*/ p != list.end(); /*NOHASH*/ ++p) { /*NOHASH*/ varEntry *v=*p; /*NOHASH*/ if (!equivalent(v->getType(), &set)) { /*NOHASH*/ set.addDistinct(v->getType(), special); /*NOHASH*/ if (v->checkPerm(READ, c)) { /*NOHASH*/ enter(dest, qualifyVarEntry(qualifier, v)); /*NOHASH*/ added=true; /*NOHASH*/ } /*NOHASH*/ } /*NOHASH*/ } /*NOHASH*/ /*NOHASH*/ return added; /*NOHASH*/ } /*NOHASH*/ /*NOHASH*/ varEntry *venv::lookByType(symbol name, ty *t) /*NOHASH*/ { /*NOHASH*/ // Find first applicable function. /*NOHASH*/ name_t &list = names[name]; /*NOHASH*/ for(name_iterator p = list.begin(); /*NOHASH*/ p != list.end(); /*NOHASH*/ ++p) { /*NOHASH*/ if (equivalent((*p)->getType(), t)) /*NOHASH*/ return *p; /*NOHASH*/ } /*NOHASH*/ return 0; /*NOHASH*/ } /*NOHASH*/ /*NOHASH*/ void venv::list(record *module) /*NOHASH*/ { /*NOHASH*/ bool where=settings::getSetting("where"); /*NOHASH*/ // List all functions and variables. /*NOHASH*/ for(names_t::iterator N = names.begin(); N != names.end(); ++N) { /*NOHASH*/ symbol s=N->first; /*NOHASH*/ name_t &list=names[s]; /*NOHASH*/ for(name_iterator p = list.begin(); p != list.end(); ++p) { /*NOHASH*/ if(!module || (*p)->whereDefined() == module) { /*NOHASH*/ if(where) cout << (*p)->getPos(); /*NOHASH*/ (*p)->getType()->printVar(cout, s); /*NOHASH*/ cout << ";\n"; /*NOHASH*/ } /*NOHASH*/ } /*NOHASH*/ } /*NOHASH*/ flush(cout); /*NOHASH*/ } /*NOHASH*/ /*NOHASH*/ ty *venv::getType(symbol name) /*NOHASH*/ { /*NOHASH*/ types::overloaded set; /*NOHASH*/ /*NOHASH*/ // Find all applicable functions in scope. /*NOHASH*/ name_t &list = names[name]; /*NOHASH*/ bool special = name.special(); /*NOHASH*/ /*NOHASH*/ for(name_iterator p = list.begin(); /*NOHASH*/ p != list.end(); /*NOHASH*/ ++p) { /*NOHASH*/ set.addDistinct((*p)->getType(), special); /*NOHASH*/ } /*NOHASH*/ /*NOHASH*/ return set.simplify(); /*NOHASH*/ } // }}} #else // To avoid writing qualifiers everywhere. typedef core_venv::cell cell; void core_venv::initTable(size_t capacity) { // Assert that capacity is a power of two. assert((capacity & (capacity-1)) == 0); this->capacity = capacity; size = 0; mask = capacity - 1; table = new (UseGC) cell[capacity]; memset(table, 0, sizeof(cell) * capacity); } void core_venv::clear() { if (size != 0) { memset(table, 0, sizeof(cell) * capacity); size = 0; } } void core_venv::resize() { size_t oldCapacity = capacity; size_t oldSize = size; cell *oldTable = table; initTable(capacity * 4); for (size_t i = 0; i < oldCapacity; ++i) { cell& b = oldTable[i]; if (!b.empty() && !b.isATomb()) { varEntry *old = store(b.name, b.ent); // We should not be shadowing anything when reconstructing the table. DEBUG_CACHE_ASSERT(old == 0); } } assert(size == oldSize); #if DEBUG_CACHE confirm_size(); for (size_t i = 0; i < oldCapacity; ++i) { cell& b = oldTable[i]; if (!b.empty() && !b.isATomb()) { assert(lookup(b.name, b.ent->getType()) == b.ent); } } #endif //cout << "resized from " << oldCapacity << " to " << capacity << endl; } cell& core_venv::cellByIndex(size_t i) { return table[i & mask]; } const cell& core_venv::cellByIndex(size_t i) const { return table[i & mask]; } void core_venv::confirm_size() { size_t sum = 0; for (size_t i = 0; i < capacity; ++i) { cell& b = table[i]; if (!b.empty() && !b.isATomb()) ++sum; } assert(sum == size); } varEntry *core_venv::storeNew(cell& cell, symbol name, varEntry *ent) { // Store the value into the cell. cell.storeNew(name, ent); // We now have a new entry. Update the size. ++size; // Check if the hash table has grown too big and needs to be expanded. if (2*size > capacity) resize(); // Nothing is shadowed. return 0; } varEntry *core_venv::storeNonSpecialAfterTomb(size_t tombIndex, symbol name, varEntry *ent) { DEBUG_CACHE_ASSERT(name.notSpecial()); DEBUG_CACHE_ASSERT(ent); DEBUG_CACHE_ASSERT(ent->getType()); signature *sig = ent->getSignature(); for (size_t i = tombIndex+1; ; ++i) { cell& b = cellByIndex(i); if (b.empty()) return storeNew(cellByIndex(tombIndex), name, ent); if (b.matches(name, sig)) return b.replaceWith(name, ent); } } varEntry *core_venv::storeSpecialAfterTomb(size_t tombIndex, symbol name, varEntry *ent) { DEBUG_CACHE_ASSERT(name.special()); DEBUG_CACHE_ASSERT(ent); DEBUG_CACHE_ASSERT(ent->getType()); ty *t = ent->getType(); for (size_t i = tombIndex+1; ; ++i) { cell& b = cellByIndex(i); if (b.empty()) return storeNew(cellByIndex(tombIndex), name, ent); if (b.matches(name, t)) return b.replaceWith(name, ent); } } size_t hashSig(const signature *sig) { return sig ? sig->hash() : 0; } size_t nonSpecialHash(symbol name, const signature *sig) { return name.hash() * 107 + hashSig(sig); } size_t nonSpecialHash(symbol name, const ty *t) { DEBUG_CACHE_ASSERT(t); return nonSpecialHash(name, t->getSignature()); } size_t specialHash(symbol name, const ty *t) { DEBUG_CACHE_ASSERT(t); return name.hash() * 107 + t->hash(); } varEntry *core_venv::storeNonSpecial(symbol name, varEntry *ent) { DEBUG_CACHE_ASSERT(name.notSpecial()); DEBUG_CACHE_ASSERT(ent); DEBUG_CACHE_ASSERT(ent->getType()); signature *sig = ent->getSignature(); for (size_t i = nonSpecialHash(name, sig); ; ++i) { cell& b = cellByIndex(i); if (b.empty()) return storeNew(b, name, ent); if (b.matches(name, sig)) return b.replaceWith(name, ent); if (b.isATomb()) return storeNonSpecialAfterTomb(i, name, ent); } } varEntry *core_venv::storeSpecial(symbol name, varEntry *ent) { DEBUG_CACHE_ASSERT(name.special()); DEBUG_CACHE_ASSERT(ent); DEBUG_CACHE_ASSERT(ent->getType()); ty *t = ent->getType(); for (size_t i = specialHash(name, t); ; ++i) { cell& b = cellByIndex(i); if (b.empty()) return storeNew(b, name, ent); if (b.matches(name, t)) return b.replaceWith(name, ent); if (b.isATomb()) return storeSpecialAfterTomb(i, name, ent); } } varEntry *core_venv::store(symbol name, varEntry *ent) { DEBUG_CACHE_ASSERT(ent); DEBUG_CACHE_ASSERT(ent->getType()); return name.special() ? storeSpecial(name, ent) : storeNonSpecial(name, ent); } varEntry *core_venv::lookupSpecial(symbol name, const ty *t) { DEBUG_CACHE_ASSERT(name.special()); DEBUG_CACHE_ASSERT(t); for (size_t i = specialHash(name, t); ; ++i) { cell& b = cellByIndex(i); if (b.matches(name, t)) return b.ent; if (b.empty()) return 0; } } varEntry *core_venv::lookupNonSpecial(symbol name, const signature *sig) { DEBUG_CACHE_ASSERT(name.notSpecial()); for (size_t i = nonSpecialHash(name, sig); ; ++i) { cell& b = cellByIndex(i); if (b.matches(name, sig)) return b.ent; if (b.empty()) return 0; } } varEntry *core_venv::lookup(symbol name, const ty *t) { DEBUG_CACHE_ASSERT(t); return name.special() ? lookupSpecial(name, t) : lookupNonSpecial(name, t->getSignature()); } void core_venv::removeNonSpecial(symbol name, const signature *sig) { DEBUG_CACHE_ASSERT(name.notSpecial()); for (size_t i = nonSpecialHash(name, sig); ; ++i) { cell& b = cellByIndex(i); if (b.matches(name, sig)) { b.remove(); --size; return; } DEBUG_CACHE_ASSERT(!b.empty()); } } void core_venv::removeSpecial(symbol name, const ty *t) { DEBUG_CACHE_ASSERT(name.special()); DEBUG_CACHE_ASSERT(t); for (size_t i = specialHash(name, t); ; ++i) { cell& b = cellByIndex(i); if (b.matches(name, t)) { b.remove(); --size; return; } DEBUG_CACHE_ASSERT(!b.empty()); } } void core_venv::remove(symbol name, const ty *t) { DEBUG_CACHE_ASSERT(t); if (name.special()) removeSpecial(name, t); else removeNonSpecial(name, t->getSignature()); } size_t numFormals(ty *t) { signature *sig = t->getSignature(); return sig ? sig->getNumFormals() : 0; } void venv::checkName(symbol name) { #if 0 // This size test is too slow, even for DEBUG_CACHE. core.confirm_size(); #endif // Get the type, and make it overloaded if it is not (for uniformity). overloaded o; ty *t = getType(name); if (!t) t = &o; if (!t->isOverloaded()) { o.add(t); t = &o; } assert(t->isOverloaded()); size_t maxFormals = names[name].maxFormals; size_t size = 0; for (ty_iterator i = t->begin(); i != t->end(); ++i) { assert(numFormals(*i) <= maxFormals); varEntry *v = lookByType(name, *i); assert(v); assert(equivalent(v->getType(), *i)); ++size; } size_t matches = 0; core_venv::const_iterator end = core.end(); for (core_venv::const_iterator p = core.begin(); p != end; ++p) { if (p->name == name) { ++matches; varEntry *v=p->ent; assert(v); assert(equivalent(t, v->getType())); } } assert(matches == size); } void rightKind(ty *t) { if (t && t->isOverloaded()) { ty_vector& set=((overloaded *)t)->sub; assert(set.size() > 1); } } #ifdef DEBUG_CACHE #define RIGHTKIND(t) (rightKind(t)) #define CHECKNAME(name) (checkName(name)) #else #define RIGHTKIND(t) (void)(t) #define CHECKNAME(name) (void)(name) #endif void venv::namevalue::addType(ty *s) { RIGHTKIND(t); #ifdef DEBUG_CACHE assert(!s->isOverloaded()); #endif if (t == 0) { maxFormals = numFormals(s); t = s; } else { if (!t->isOverloaded()) t = new overloaded(t); #ifdef DEBUG_CACHE assert(t->isOverloaded()); assert(!equivalent(t, s)); #endif ((overloaded *)t)->add(s); size_t n = numFormals(s); if (n > maxFormals) maxFormals = n; } RIGHTKIND(t); } void venv::namevalue::replaceType(ty *new_t, ty *old_t) { #ifdef DEBUG_CACHE assert(t != 0); RIGHTKIND(t); #endif // TODO: Test for equivalence. if (t->isOverloaded()) { for (ty_iterator i = t->begin(); i != t->end(); ++i) { if (equivalent(old_t, *i)) { *i = new_t; return; } } // An error, the type was not found. assert("unreachable code" == 0); } else { #ifdef DEBUG_CACHE assert(equivalent(old_t, t)); #endif t = new_t; } #ifdef DEBUG_CACHE assert(t != 0); RIGHTKIND(t); #endif } #ifdef DEBUG_CACHE void venv::namevalue::popType(ty *s) #else void venv::namevalue::popType() #endif { #ifdef DEBUG_CACHE assert(t); RIGHTKIND(t); assert(!s->isOverloaded()); #endif if (t->isOverloaded()) { ty_vector& set=((overloaded *)t)->sub; #ifdef DEBUG_CACHE assert(set.size() > 0); assert(equivalent(set.back(), s)); #endif // We are relying on the fact that this was the last type added to t, and // that type are added by pushing them on the end of the vector. set.pop_back(); if (set.size() == 1) t = set.front(); } else { #ifdef DEBUG_CACHE assert(equivalent(t, s)); #endif t = 0; } RIGHTKIND(t); // Don't try to reduce numFormals as I doubt it is worth the cost of // recalculating. } void venv::remove(const addition& a) { CHECKNAME(a.name); if (a.shadowed) { varEntry *popEnt = core.store(a.name, a.shadowed); DEBUG_CACHE_ASSERT(popEnt); // Unshadow the previously shadowed varEntry. names[a.name].replaceType(a.shadowed->getType(), popEnt->getType()); } else { // Remove the (name,sig) key completely. #if DEBUG_CACHE varEntry *popEnt = core.lookup(a.name, a.t); assert(popEnt); names[a.name].popType(popEnt->getType()); #else names[a.name].popType(); #endif core.remove(a.name, a.t); } CHECKNAME(a.name); } void venv::beginScope() { if (core.empty()) { assert(scopesizes.empty()); ++empty_scopes; } else { scopesizes.push(additions.size()); } } void venv::endScope() { if (scopesizes.empty()) { // The corresponding beginScope happened when the venv was empty, so // clear the hash tables to return to that state. core.clear(); names.clear(); assert(empty_scopes > 0); --empty_scopes; } else { size_t scopesize = scopesizes.top(); assert(additions.size() >= scopesize); while (additions.size() > scopesize) { remove(additions.top()); additions.pop(); } scopesizes.pop(); } } // Adds the definitions of the top-level scope to the level underneath, // and then removes the top scope. void venv::collapseScope() { if (scopesizes.empty()) { // Collapsing an empty scope. assert(empty_scopes > 0); --empty_scopes; } else { // As scopes are stored solely by the number of entries at the beginning // of the scope, popping the top size will put all of the entries into the // next scope down. scopesizes.pop(); } } void venv::enter(symbol name, varEntry *v) { CHECKNAME(name); // Store the new variable. If it shadows an older variable, that varEntry // will be returned. varEntry *shadowed = core.store(name, v); ty *t = v->getType(); // Record the addition, so it can be undone during endScope. if (!scopesizes.empty()) additions.push(addition(name, t, shadowed)); if (shadowed) // The new value shadows an old value. They have the same signature, but // possibly different return types. If necessary, update the type stored // by name. names[name].replaceType(t, shadowed->getType()); else // Add to the names hash table. names[name].addType(t); CHECKNAME(name); } varEntry *venv::lookBySignature(symbol name, signature *sig) { // Rest arguments are complicated and rare. Don't handle them here. if (sig->hasRest()) return 0; // Likewise with the special operators. if (name.special()) return 0; namevalue& nv = names[name]; // Avoid ambiguities with default parameters. if (nv.maxFormals != sig->getNumFormals()) return 0; // See if this exactly matches a function in the table. varEntry *ve = core.lookupNonSpecial(name, sig); if (!ve) return 0; // Keyword-only arguments may cause matching to fail. if (ve->getSignature()->numKeywordOnly > 0) return 0; // At this point, any function with an equivalent signature will be equal // to the result of the normal overloaded function resolution. We may // safely return it. return ve; } void venv::add(venv& source, varEntry *qualifier, coder &c) { core_venv::const_iterator end = source.core.end(); for (core_venv::const_iterator p = source.core.begin(); p != end; ++p) { DEBUG_CACHE_ASSERT(p->filled()); varEntry *v=p->ent; if (v->checkPerm(READ, c)) { enter(p->name, qualifyVarEntry(qualifier, v)); } } } bool venv::add(symbol src, symbol dest, venv& source, varEntry *qualifier, coder &c) { ty *t=source.getType(src); if (!t) return false; if (t->isOverloaded()) { bool added=false; for (ty_iterator i = t->begin(); i != t->end(); ++i) { varEntry *v=source.lookByType(src, *i); if (v->checkPerm(READ, c)) { enter(dest, qualifyVarEntry(qualifier, v)); added=true; } } return added; } else { varEntry *v=source.lookByType(src, t); if (v->checkPerm(READ, c)) { enter(dest, qualifyVarEntry(qualifier, v)); return true; } return false; } } ty *venv::getType(symbol name) { return names[name].t; } void listValue(symbol name, varEntry *v, record *module) { if (!module || v->whereDefined() == module) { if (settings::getSetting("where")) cout << v->getPos(); v->getType()->printVar(cout, name); cout << ";\n"; } } void venv::listValues(symbol name, record *module) { ty *t=getType(name); if (t->isOverloaded()) for (ty_iterator i = t->begin(); i != t->end(); ++i) listValue(name, lookByType(name, *i), module); else listValue(name, lookByType(name, t), module); flush(cout); } void venv::list(record *module) { // List all functions and variables. for (namemap::iterator N = names.begin(); N != names.end(); ++N) listValues(N->first, module); } void venv::completions(mem::list& l, string start) { for(namemap::iterator N = names.begin(); N != names.end(); ++N) if (prefix(start, N->first) && N->second.t) l.push_back(N->first); } #endif /* not NOHASH */ } // namespace trans asymptote-2.37/entry.h000066400000000000000000000347131265434602500150230ustar00rootroot00000000000000/***** * entry.h * Andy Hammerlindl 2002/08/29 * * All variables, built-in functions and user-defined functions reside * within the same namespace. To keep track of all these, a table of * "entries" is used. *****/ #ifndef ENTRY_H #define ENTRY_H #include #include "common.h" #include "frame.h" #include "table.h" #include "types.h" #include "modifier.h" using sym::symbol; using types::ty; using types::signature; // Forward declaration. namespace types { class record; } using types::record; namespace trans { // An entry is associated to a name in the (variable or type) environment, and // has permission based on the enclosing records where it was defined or // imported. class entry : public gc { struct pr { permission perm; record *r; pr(permission perm, record *r) : perm(perm), r(r) {} // Returns true if the permission allows access in this context. bool check(action act, coder &c); // Reports an error if permission is not allowed. void report(action act, position pos, coder &c); }; mem::list perms; void addPerm(permission perm, record *r) { // Only store restrictive permissions. if (perm != PUBLIC && r) perms.push_back(pr(perm,r)); } // The record where the variable or type is defined, or 0 if the entry is // not a field. record *where; // The location (file and line number) where the entry was defined. position pos; public: entry(record *where, position pos) : where(where), pos(pos) {} entry(permission perm, record *r, record *where, position pos) : where(where), pos(pos) { addPerm(perm, r); } // (Non-destructively) merges two entries, appending permission lists. // The 'where' member is taken from the second entry. entry(entry &e1, entry &e2); // Create an entry with one more permission in the list. entry(entry &base, permission perm, record *r); bool checkPerm(action act, coder &c); void reportPerm(action act, position pos, coder &c); record *whereDefined() { return where; } position getPos() { return pos; } }; class varEntry : public entry { ty *t; access *location; public: varEntry(ty *t, access *location, record *where, position pos) : entry(where, pos), t(t), location(location) {} varEntry(ty *t, access *location, permission perm, record *r, record *where, position pos) : entry(perm, r, where, pos), t(t), location(location) {} // (Non-destructively) merges two varEntries, creating a qualified varEntry. varEntry(varEntry &qv, varEntry &v); ty *getType() { return t; } signature *getSignature() { return t->getSignature(); } access *getLocation() { return location; } frame *getLevel(); // Encodes the access, but also checks permissions. void encode(action act, position pos, coder &c); void encode(action act, position pos, coder &c, frame *top); }; varEntry *qualifyVarEntry(varEntry *qv, varEntry *v); // As looked-up types can be allocated in a new expression, we need to know // what frame they should be allocated on. Type entries store this extra // information along with the type. class tyEntry : public entry { public: ty *t; varEntry *v; // NOTE: Name isn't very descriptive. tyEntry(ty *t, varEntry *v, record *where, position pos) : entry(where, pos), t(t), v(v) {} tyEntry(tyEntry *base, permission perm, record *r) : entry(*base, perm, r), t(base->t), v(base->v) {} // Records need a varEntry that refers back to the qualifier qv; i.e. in // the last new of the code // struct A { // struct B {} // } // A a=new A; // unravel a; // new B; // we need to put a's frame on the stack before allocating an instance of B. // NOTE: A possible optimization could be to only qualify the varEntry if // the type is a record, as other types don't use the varEntry. private: tyEntry(tyEntry *base, varEntry *qv) : entry(*base, *qv), t(base->t), v(qualifyVarEntry(qv, base->v)) {} public: // Since the constructor can only be used when qv is non-null it is private // for safety reasons, and we provide this method instead. friend tyEntry *qualifyTyEntry(varEntry *qv, tyEntry *ent); }; inline tyEntry *qualifyTyEntry(varEntry *qv, tyEntry *ent) { return qv ? new tyEntry(ent, qv) : ent; } // The type environment. class tenv : public sym::table { bool add(symbol dest, names_t::value_type &x, varEntry *qualifier, coder &c); public: // Add the entries in one environment to another, if qualifier is // non-null, it is a record and the source environment is its types. The // coder is used to see which entries are accessible and should be added. void add(tenv& source, varEntry *qualifier, coder &c); // Adds entries of the name src in source as the name dest, returning true if // any were added. bool add(symbol src, symbol dest, tenv& source, varEntry *qualifier, coder &c); }; #if 0 //{{{ /* This version of venv is provided for compiling on systems which do not * have some form of STL hash table. It will eventually be removed. * See the hash version below for documentation on the functions. */ /*NOHASH*/ class venv : public sym::table { /*NOHASH*/ public: /*NOHASH*/ venv() {} /*NOHASH*/ /*NOHASH*/ struct file_env_tag {}; /*NOHASH*/ venv(file_env_tag) {} /*NOHASH*/ /*NOHASH*/ void add(venv& source, varEntry *qualifier, coder &c); /*NOHASH*/ /*NOHASH*/ bool add(symbol src, symbol dest, /*NOHASH*/ venv& source, varEntry *qualifier, coder &c); /*NOHASH*/ /*NOHASH*/ varEntry *lookByType(symbol name, ty *t); /*NOHASH*/ /*NOHASH*/ varEntry *lookBySignature(symbol name, signature *sig) { /*NOHASH*/ // This optimization is not implemented for the NOHASH version. /*NOHASH*/ return 0; /*NOHASH*/ } /*NOHASH*/ /*NOHASH*/ ty *getType(symbol name); /*NOHASH*/ /*NOHASH*/ friend std::ostream& operator<< (std::ostream& out, /*NOHASH*/ const venv& ve); /*NOHASH*/ /*NOHASH*/ void list(record *module=0); /*NOHASH*/ }; //}}} #else // For speed reasons, many asserts are only tested when DEBUG_CACHE is set. #ifdef DEBUG_CACHE #define DEBUG_CACHE_ASSERT(x) assert(x) #else #define DEBUG_CACHE_ASSERT(x) (void)(x) #endif // The hash table which is at the core of the variable environment venv. class core_venv : public gc { public: // The cells of the table struct cell { symbol name; varEntry *ent; bool empty() const { return name == 0; } bool isATomb() const { DEBUG_CACHE_ASSERT(!empty()); return ent == 0; } bool filled() const { return !empty() and !isATomb(); } bool matches(symbol name, const ty *t) { DEBUG_CACHE_ASSERT(name.special()); DEBUG_CACHE_ASSERT(t); if (this->name != name) return false; if (!this->ent) return false; return equivalent(this->ent->getType(), t); } bool matches(symbol name, const signature *sig) { DEBUG_CACHE_ASSERT(!name.special()); if (this->name != name) return false; if (!this->ent) return false; return equivalent(this->ent->getSignature(), sig); } void storeNew(symbol name, varEntry *ent) { DEBUG_CACHE_ASSERT(empty() || isATomb()); this->name = name; this->ent = ent; } varEntry *replaceWith(symbol name, varEntry *ent) { this->name = name; varEntry *old = this->ent; this->ent = ent; return old; } void remove() { this->ent = 0; } }; private: size_t capacity; size_t size; size_t mask; cell *table; void initTable(size_t capacity); void resize(); cell& cellByIndex(size_t i); const cell& cellByIndex(size_t i) const; varEntry *storeNew(cell& cell, symbol name, varEntry *ent); varEntry *storeNonSpecialAfterTomb(size_t tombIndex, symbol name, varEntry *ent); varEntry *storeSpecialAfterTomb(size_t tombIndex, symbol name, varEntry *ent); public: core_venv(size_t capacity) { initTable(capacity); } bool empty() const { return size == 0; } void clear(); void confirm_size(); // Store an entry into the table. If this shadows a previous entry, the old // entry is returned, otherwise 0 is returned. varEntry *storeNonSpecial(symbol name, varEntry *ent); varEntry *storeSpecial(symbol name, varEntry *ent); varEntry *store(symbol name, varEntry *ent); // Lookup an entry in the table. varEntry *lookupNonSpecial(symbol name, const signature *sig); varEntry *lookupSpecial(symbol name, const ty *t); varEntry *lookup(symbol name, const ty *t); // Remove an entry from the table. void removeNonSpecial(symbol name, const signature *sig); void removeSpecial(symbol name, const ty *t); void remove(symbol name, const ty *t); // Features for iterating over the entire table. class const_iterator { const core_venv& core; size_t index; public: const_iterator(const core_venv& core, size_t index) : core(core), index(index) {} const cell& operator * () const { return core.cellByIndex(index); } const cell* operator -> () const { return &core.cellByIndex(index); } const_iterator& operator ++ () { // Advance to the next filled cell, or stop at the end of the array. do { ++index; } while (!(*this)->filled() && index < core.capacity); DEBUG_CACHE_ASSERT((*this)->filled() || (*this) == core.end()); return *this; } friend bool operator == (const const_iterator& a, const const_iterator& b) { // For speed, we don't compare the hashtables. return a.index == b.index; } friend bool operator != (const const_iterator& a, const const_iterator& b) { // For speed, we don't compare the hashtables. return a.index != b.index; } }; const_iterator begin() const { size_t index = 0; while (index < capacity && !cellByIndex(index).filled()) ++index; return const_iterator(*this, index); } const_iterator end() const { return const_iterator(*this, capacity); } }; // venv implemented with a hash table. class venv { // A hash table used to quickly look up a variable once its name and type are // known. Includes all scopes. core_venv core; // Record of added variables in the order they were added. struct addition { symbol name; ty *t; varEntry *shadowed; addition(symbol name, ty *t, varEntry *shadowed) : name(name), t(t), shadowed(shadowed) {} }; typedef mem::stack addstack; addstack additions; // A scope can be recorded by the size of the addition stack at the time the // scope began. typedef mem::stack scopestack; scopestack scopesizes; struct namehash { size_t operator()(const symbol name) const { return name.hash(); } }; struct nameeq { bool operator()(const symbol s, const symbol t) const { return s==t; } }; struct namevalue { size_t maxFormals; ty *t; namevalue() : maxFormals(0), t(0) {} void addType(ty *s); void replaceType(ty *new_t, ty *old_t); #if DEBUG_CACHE void popType(ty *tnew); #else void popType(); #endif }; // A dictionary indexed solely on the name, storing for each name the // current (possibly overloaded) type of the name. // The hash table implementation is slightly faster than the std::map binary // tree implementation, so we use it if we can. #ifdef NOHASH typedef mem::map namemap; #else typedef mem::unordered_map namemap; #endif namemap names; // A sanity check. For a given name, it checks that the type stored in the // names hash table exactly matches with all of the entries of that name // stored in the full hash table. void checkName(symbol name); void listValues(symbol name, record *module); // Helper function for endScope. void remove(const addition& a); // These are roughly the size the hashtables will be after loading the // builtin functions and plain module. static const size_t fileCoreSize=1 << 13; static const size_t fileNamesSize=1000; // The number of scopes begun (but not yet ended) when the venv was empty. size_t empty_scopes; public: venv() : core(1 << 2), empty_scopes(0) {} // Most file level modules automatically import plain, so allocate hashtables // big enough to hold it in advance. struct file_env_tag {}; venv(file_env_tag) : core(fileCoreSize), #ifndef NOHASH names(fileNamesSize), #endif empty_scopes(0) {} // Add a new variable definition. void enter(symbol name, varEntry *v); // Add the entries in one environment to another, if qualifier is // non-null, it is a record and entries of the source environment are its // fields. The coder is necessary to check which variables are accessible and // should be added. void add(venv& source, varEntry *qualifier, coder &c); // Add all unshadowed variables from source of the name src as variables // named dest. Returns true if at least one was added. bool add(symbol src, symbol dest, venv& source, varEntry *qualifier, coder &c); // Look for a function that exactly matches the type given. varEntry *lookByType(symbol name, ty *t) { return core.lookup(name, t); } // An optimization heuristic. Try to guess the signature of a variable and // look it up. This is allowed to return 0 even if the appropriate variable // exists. If it returns a varEntry from an overloaded number of choices, // the returned function must be the one which would be called with // arguments given by sig, and its signature must be equivalent to sig. // For instance, in // int f(int a, int b); // int f(int a, int b, int c = 1); // f(a,b); // looking up the signature of 'f' with arguments (int, int) must return 0 // as there is an ambiguity. The maxFormals field is used to ensure we // avoid such ambiguities. varEntry *lookBySignature(symbol name, signature *sig); // Get the (possibly overloaded) type of all variables associated to a // particular name. ty *getType(symbol name); void beginScope(); void endScope(); // Merges the top-level scope with the level immediately underneath it. void collapseScope(); // Prints a list of the variables to the standard output. void list(record *module=0); // Adds to l, all names prefixed by start. void completions(mem::list& l, string start); }; #endif } // namespace trans #endif //ENTRY_H asymptote-2.37/env.cc000066400000000000000000000125311265434602500146020ustar00rootroot00000000000000/***** * env.cc * Andy Hammerlindl 2002/6/20 * * Keeps track of the namespaces of variables and types when traversing * the abstract syntax. *****/ #include "env.h" #include "record.h" #include "genv.h" #include "builtin.h" using namespace types; namespace trans { // Instances of this class are passed to types::ty objects so that they can call // back to env when checking casting of subtypes. class envCaster : public caster { protoenv &e; symbol name; public: envCaster(protoenv &e, symbol name) : e(e), name(name) {} access *operator() (ty *target, ty *source) { return e.lookupCast(target, source, name); } bool castable(ty *target, ty *source) { return e.castable(target, source, name); } }; access *protoenv::baseLookupCast(ty *target, ty *source, symbol name) { static identAccess id; assert(target->kind != ty_overloaded && source->kind != ty_overloaded); // If errors already exist, don't report more. This may, however, cause // problems with resoving the signature of an overloaded function. The // abstract syntax should check if any of the parameters had an error before // finding the signature. if (target->kind == ty_error || source->kind == ty_error) return &id; else if (equivalent(target,source)) return &id; else { varEntry *v=lookupVarByType(name,new function(target,source)); return v ? v->getLocation() : 0; } } access *protoenv::lookupCast(ty *target, ty *source, symbol name) { access *a=baseLookupCast(target, source, name); if (a) return a; envCaster ec(*this, name); return source->castTo(target, ec); } bool protoenv::castable(ty *target, ty *source, symbol name) { struct castTester : public tester { protoenv &e; symbol name; castTester(protoenv &e, symbol name) : e(e), name(name) {} bool base(ty *t, ty *s) { access *a=e.baseLookupCast(t, s, name); if (a) return true; envCaster ec(e, name); return s->castable(t, ec); } }; castTester ct(*this, name); return ct.test(target,source); } bool protoenv::fastCastable(ty *target, ty *source) { assert(target->kind != types::ty_overloaded); assert(target->kind != types::ty_error); assert(source->kind != types::ty_error); // To avoid memory allocation, fill one static variable with new parameters // in each call. // Warning: This is not re-entrant if asy ever goes multi-threaded. static types::function castFunc(primVoid(), primVoid()); castFunc.result = target; if (source->kind == types::ty_overloaded) { bool result = false; types::ty_vector& v = ((overloaded *)source)->sub; for (size_t i = 0; i < v.size(); ++i) { castFunc.sig.formals[0].t = v[i]; if (lookupVarByType(symbol::castsym, &castFunc)) { result = true; break; } } //assert(result == castable(target, source, symbol::castsym)); //cout << "fc OVERLOADED " << (result ? "CAST" : "FAIL") << endl; return result; } //else cout << "fc SIMPLE" << endl; // Don't test for equivalent, as that is already done by the castScore // code. Assert disabled for speed. #if 0 assert(!equivalent(target, source)); #endif castFunc.sig.formals[0].t = source; if (lookupVarByType(symbol::castsym, &castFunc)) return true; // Test for generic casts of null. This should be moved to a types.h // routine. return source->kind == ty_null && target->isReference(); } access *protoenv::fastLookupCast(ty *target, ty *source) { assert(target->kind != types::ty_overloaded); assert(target->kind != types::ty_error); assert(source->kind != types::ty_overloaded); assert(source->kind != types::ty_error); // Warning: This is not re-entrant. static types::function castFunc(primVoid(), primVoid()); castFunc.result = target; castFunc.sig.formals[0].t = source; varEntry *ve = lookupVarByType(symbol::castsym, &castFunc); if (ve) return ve->getLocation(); // Fall back on slow routine. return lookupCast(target, source, symbol::castsym); } ty *protoenv::castTarget(ty *target, ty *source, symbol name) { struct resolver : public collector { protoenv &e; symbol name; resolver(protoenv &e, symbol name) : e(e), name(name) {} types::ty *base(types::ty *target, types::ty *source) { return e.castable(target, source, name) ? target : 0; } }; resolver r(*this, name); return r.collect(target, source); } ty *protoenv::castSource(ty *target, ty *source, symbol name) { struct resolver : public collector { protoenv &e; symbol name; resolver(protoenv &e, symbol name) : e(e), name(name) {} types::ty *base(types::ty *target, types::ty *source) { return e.castable(target, source, name) ? source : 0; } }; resolver r(*this, name); return r.collect(target, source); } void protoenv::addArrayOps(array *a) { trans::addArrayOps(ve, a); } void protoenv::addRecordOps(record *r) { trans::addRecordOps(ve, r); } void protoenv::addFunctionOps(function *f) { trans::addFunctionOps(ve, f); } env::env(genv &ge) : protoenv(venv::file_env_tag()), ge(ge) { // NOTE: May want to make this initial environment into a "builtin" module, // and then import the builtin module. base_tenv(te); base_venv(ve); } env::~env() { } record *env::getModule(symbol id, string filename) { return ge.getModule(id, filename); } } asymptote-2.37/env.h000066400000000000000000000107371265434602500144520ustar00rootroot00000000000000/***** * env.h * Andy Hammerlindl 2002/6/20 * * Keeps track of the namespaces of variables and types when traversing * the abstract syntax. *****/ #ifndef ENV_H #define ENV_H #include "errormsg.h" #include "entry.h" #include "types.h" #include "util.h" namespace types { class record; } namespace trans { using sym::symbol; using types::ty; using types::function; using types::record; class genv; // Keeps track of the name bindings of variables and types. This is used for // the fields of a record, whereas the derived class env is used for unqualified // names in translation. class protoenv { //protected: public: // These tables keep track of type and variable definitions. tenv te; venv ve; access *baseLookupCast(ty *target, ty *source, symbol name); public: // Start an environment for a file-level module. protoenv() {} protoenv(venv::file_env_tag tag) : ve(tag) {} protoenv(const protoenv&); void beginScope() { te.beginScope(); ve.beginScope(); } void endScope() { te.endScope(); ve.endScope(); } void collapseScope() { te.collapseScope(); ve.collapseScope(); } tyEntry *lookupTyEntry(symbol s) { return te.look(s); } ty *lookupType(symbol s) { tyEntry *ent=lookupTyEntry(s); return ent ? ent->t : 0; } varEntry *lookupVarByType(symbol name, ty *t) { // Search in local vars. return ve.lookByType(name, t); } varEntry *lookupVarBySignature(symbol name, types::signature *sig) { return ve.lookBySignature(name, sig); } access *lookupInitializer(ty *t) { // The initializer's type is a function returning the desired type. function *it=new function(t); varEntry *v=lookupVarByType(symbol::initsym,it); // If not in the environment, try the type itself. return v ? v->getLocation() : t->initializer(); } // Find the function that handles casting between the types. // The name is "operator cast" for implicit casting and "operator ecast" for // explicit. access *lookupCast(ty *target, ty *source, symbol name); bool castable(ty *target, ty *source, symbol name); // A cast lookup designed to work quickly with the application matching // code. The target type must not be overloaded. bool fastCastable(ty *target, ty *source); // For the lookup, neither target nor source may be overloaded. access *fastLookupCast(ty *target, ty *source); // Given overloaded types, this resolves which types should be the target and // the source of the cast. ty *castTarget(ty *target, ty *source, symbol name); ty *castSource(ty *target, ty *source, symbol name); ty *varGetType(symbol name) { return ve.getType(name); } void addType(symbol name, tyEntry *desc) { te.enter(name, desc); } void addVar(symbol name, varEntry *desc) { // Don't check for multiple variables, as this makes adding casts // and initializers harder. ve.enter(name, desc); } // Add another environment, say from a record. void add(protoenv &source, varEntry *qualifier, coder &c) { te.add(source.te, qualifier, c); ve.add(source.ve, qualifier, c); } // Add variables and types of name src from another environment under the // name dest in this environment. bool add(symbol src, symbol dest, protoenv &source, varEntry *qualifier, coder &c) { return te.add(src, dest, source.te, qualifier, c) | ve.add(src, dest, source.ve, qualifier, c); } // Add the standard functions for a new type. void addArrayOps(types::array *t); void addRecordOps(types::record *r); void addFunctionOps(types::function *f); void list(record *r=0) { ve.list(r); } // Adds to a list the keywords in the environment that start with the given // prefix. Used for automatic completion at the interactive prompt. typedef mem::list symbol_list; void completions(symbol_list &l, string start) { te.completions(l, start); ve.completions(l, start); } private: // Non-copyable void operator=(const protoenv&); }; // Environment used in translating statements and expressions at all scopes. As // opposed to protoenv which is suitable for keeping track of the fields of // records, this also keeps track of the global env, for loading modules. class env : public protoenv { // The global environment - keeps track of modules. genv ≥ public: // Start an environment for a file-level module. env(genv &ge); ~env(); record *getModule(symbol id, string filename); }; } // namespace trans #endif asymptote-2.37/envcompleter.cc000066400000000000000000000021661265434602500165200ustar00rootroot00000000000000/***** * envcompleter.cc * Andy Hammerlindl 2006/07/31 * * Implements a text completion function for readline based on symbols in the * environment. *****/ #include #include "table.h" #include "envcompleter.h" namespace trans { bool basicListLoaded=false; envCompleter::symbol_list basicList; static void loadBasicList() { assert(basicListLoaded==false); #define ADD(word) basicList.push_back(symbol::literalTrans(#word)) #include "keywords.cc" #undef ADD basicListLoaded=true; } void envCompleter::basicCompletions(symbol_list &l, string start) { if (!basicListLoaded) loadBasicList(); for (symbol_list::iterator p = basicList.begin(); p != basicList.end(); ++p) if (prefix(start, *p)) l.push_back(*p); } void envCompleter::makeList(const char *text) { l.clear(); basicCompletions(l, text); e.completions(l, text); index=l.begin(); } char *envCompleter::operator () (const char *text, int state) { if (state==0) makeList(text); if (index==l.end()) return 0; else { symbol name=*index; ++index; return StrdupMalloc((string)name); } } } // namespace trans asymptote-2.37/envcompleter.h000066400000000000000000000015151265434602500163570ustar00rootroot00000000000000/***** * envcompleter.h * Andy Hammerlindl 2006/07/31 * * Implements a text completion function for readline based on symbols in the * environment. *****/ #ifndef ENVCOMPLETER_H #define ENVCOMPLETER_H #include "env.h" #include "interact.h" namespace trans { class envCompleter : public interact::completer { public: typedef protoenv::symbol_list symbol_list; private: protoenv &e; symbol_list l; symbol_list::iterator index; // These are completions that don't come from the environment, such as // keywords. They are read from the keywords file. static void basicCompletions(symbol_list &l, string start); void makeList(const char *text); public: envCompleter(protoenv &e) : e(e), l(), index(l.end()) {} char *operator () (const char *text, int state); }; } // namespace trans #endif // ENVCOMPLETER_H asymptote-2.37/errormsg.cc000066400000000000000000000033311265434602500156500ustar00rootroot00000000000000/***** * errormsg.cc * Andy Hammerlindl 2002/06/17 * * Used in all phases of the compiler to give error messages. *****/ #include #include #include "errormsg.h" errorstream em; position nullPos; static nullPosInitializer nullPosInit; bool errorstream::interrupt=false; ostream& operator<< (ostream& out, const position& pos) { if (!pos) return out; out << pos.file->name() << ": "; out << pos.line << "." << pos.column << ": "; return out; } void errorstream::clear() { sync(); anyErrors = anyWarnings = false; } void errorstream::message(position pos, const string& s) { if (floating) out << endl; out << pos << s; floating = true; } void errorstream::compiler(position pos) { message(pos,"compiler: "); anyErrors = true; } void errorstream::compiler() { message(nullPos,"compiler: "); anyErrors = true; } void errorstream::runtime(position pos) { message(pos,"runtime: "); anyErrors = true; } void errorstream::error(position pos) { message(pos,""); anyErrors = true; } void errorstream::warning(position pos, string s) { message(pos,"warning ["+s+"]: "); anyWarnings = true; } void errorstream::warning(position pos) { message(pos,"warning: "); anyWarnings = true; } void errorstream::fatal(position pos) { message(pos,"abort: "); anyErrors = true; } void errorstream::trace(position pos) { static position lastpos; if(!pos || (pos.match(lastpos.filename()) && pos.match(lastpos.Line()))) return; lastpos=pos; message(pos,""); sync(); } void errorstream::cont() { floating = false; } void errorstream::sync() { if (floating) out << endl; floating = false; } void outOfMemory() { cerr << "error: out of memory" << endl; exit(1); } asymptote-2.37/errormsg.h000066400000000000000000000116061265434602500155160ustar00rootroot00000000000000/***** * errormsg.h * Andy Hammerlindl 2002/06/17 * * Used in all phases of the compiler to give error messages. *****/ #ifndef ERRORMSG_H #define ERRORMSG_H #include #include "common.h" #include "settings.h" using std::ostream; struct handled_error {}; // Exception to process next file. struct interrupted {}; // Exception to interrupt execution. struct quit {}; // Exception to quit current operation. struct eof {}; // Exception to exit interactive mode. class fileinfo : public gc { string filename; size_t lineNum; public: fileinfo(string filename, size_t lineNum=1) : filename(filename), lineNum(lineNum) {} size_t line() const { return lineNum; } string name() const { return filename; } // The filename without the directory and without the '.asy' suffix. // Note that this assumes name are separated by a forward slash. string moduleName() const { size_t start = filename.rfind('/'); if (start == filename.npos) start = 0; else // Step over slash. ++start; size_t end = filename.rfind(".asy"); if (end != filename.size() - 4) end = filename.size(); return filename.substr(start, end-start); } // Specifies a newline symbol at the character position given. void newline() { ++lineNum; } }; inline bool operator == (const fileinfo& a, const fileinfo& b) { return a.line() == b.line() && a.name() == b.name(); } class position : public gc { fileinfo *file; size_t line; size_t column; public: void init(fileinfo *f, Int p) { file = f; if (file) { line = file->line(); column = p; } else { line = column = 0; } } string filename() const { return file ? file->name() : ""; } size_t Line() const { return line; } size_t Column() const { return column; } bool match(const string& s) { return file && file->name() == s; } bool match(size_t l) { return line == l; } bool matchColumn(size_t c) { return column == c; } bool operator! () const { return (file == 0); } friend ostream& operator << (ostream& out, const position& pos); // Write out just the module name and line number. void printTerse(ostream& out) const { if (file) { out << file->moduleName() << ":" << line; } } }; extern position nullPos; struct nullPosInitializer { nullPosInitializer() {nullPos.init(NULL,0);} }; inline bool operator == (const position& a, const position& b) { return a.Line() == b.Line() && a.Column() == b.Column() && a.filename() == b.filename(); } string warning(string s); class errorstream { ostream& out; bool anyErrors; bool anyWarnings; bool floating; // Was a message output without a terminating newline? // Is there an error that warrants the asy process to return 1 instead of 0? bool anyStatusErrors; public: static bool interrupt; // Is there a pending interrupt? errorstream(ostream& out = cerr) : out(out), anyErrors(false), anyWarnings(false), floating(false), anyStatusErrors(false) {} void clear(); void message(position pos, const string& s); void Interrupt(bool b) { interrupt=b; } // An error is encountered, not in the user's code, but in the way the // compiler works! This may be augmented in the future with a message // to contact the compiler writers. void compiler(); void compiler(position pos); // An error encountered when running compiled code. This method does // not stop the executable, but the executable should be stopped // shortly after calling this method. void runtime(position pos); // Errors encountered when compiling making it impossible to run the code. void error(position pos); // Indicate potential problems in the code, but the code is still usable. void warning(position pos); void warning(position pos, string s); // Single a fatal error and execute the main process. void fatal(position pos); // Print out position in code to aid debugging. void trace(position pos); // Sends stuff to out to print. // NOTE: May later make it do automatic line breaking for long messages. template errorstream& operator << (const T& x) { flush(out); out << x; return *this; } // Reporting errors to the stream may be incomplete. This draws the // appropriate newlines or file excerpts that may be needed at the end. void sync(); void cont(); bool errors() const { return anyErrors; } bool warnings() const { return anyWarnings || errors(); } void statusError() { anyStatusErrors=true; } // Returns true if no errors have occured that should be reported by the // return value of the process. bool processStatus() const { return !anyStatusErrors; } }; extern errorstream em; void outOfMemory(); GC_DECLARE_PTRFREE(nullPosInitializer); #endif asymptote-2.37/errors000066400000000000000000000220431265434602500147410ustar00rootroot00000000000000errortest.asy: 476.34: unnamed argument after rest argument errortest.asy: 477.37: additional rest argument errortest.asy: 478.28: unnamed argument after rest argument errortest.asy: 479.31: additional rest argument errortest.asy: 482.22: normal parameter after rest parameter errortest.asy: 483.22: normal parameter after rest parameter errortest.asy: 484.31: normal parameter after rest parameter errortest.asy: 485.31: normal parameter after rest parameter errortest.asy: 486.24: normal parameter after keyword-only parameter errortest.asy: 487.24: normal parameter after keyword-only parameter errortest.asy: 488.24: normal parameter after keyword-only parameter errortest.asy: 488.31: normal parameter after keyword-only parameter errortest.asy: 489.24: normal parameter after keyword-only parameter errortest.asy: 489.31: normal parameter after keyword-only parameter errortest.asy: 490.32: normal parameter after keyword-only parameter errortest.asy: 491.32: normal parameter after keyword-only parameter errortest.asy: 492.32: normal parameter after keyword-only parameter errortest.asy: 492.39: normal parameter after keyword-only parameter errortest.asy: 493.32: normal parameter after keyword-only parameter errortest.asy: 493.39: normal parameter after keyword-only parameter errortest.asy: 496.13: expected 'keyword' here errortest.asy: 497.13: expected 'keyword' here errortest.asy: 498.21: expected 'keyword' here errortest.asy: 499.21: expected 'keyword' here errortest.asy: 500.36: expected 'keyword' here errortest.asy: 500.32: normal parameter after keyword-only parameter errortest.asy: 501.36: expected 'keyword' here errortest.asy: 501.32: normal parameter after keyword-only parameter errortest.asy: 502.21: expected 'keyword' here errortest.asy: 503.21: expected 'keyword' here errortest.asy: 504.13: expected 'keyword' here errortest.asy: 505.13: expected 'keyword' here errortest.asy: 506.13: expected 'keyword' here errortest.asy: 507.13: expected 'keyword' here errortest.asy: 508.13: expected 'keyword' here errortest.asy: 509.13: expected 'keyword' here errortest.asy: 510.21: expected 'keyword' here errortest.asy: 511.21: expected 'keyword' here errortest.asy: 512.21: expected 'keyword' here errortest.asy: 513.21: expected 'keyword' here errortest.asy: 12.4: no matching variable 'x.y' errortest.asy: 16.11: no matching variable of name 'z' errortest.asy: 20.3: no matching variable 'x' errortest.asy: 27.3: no type of name 'x' errortest.asy: 28.3: no type of name 'x' errortest.asy: 29.3: no type of name 'x' errortest.asy: 30.10: no type of name 'x' errortest.asy: 32.5: no type of name 'x' errortest.asy: 33.5: no type of name 'x' errortest.asy: 34.5: no type of name 'x' errortest.asy: 35.12: no type of name 'x' errortest.asy: 41.4: no matching variable 'x.y' errortest.asy: 48.6: no matching variable 'm.u.v' errortest.asy: 55.12: no matching field of name 'z' in 'm' errortest.asy: 62.4: no matching variable 'm.z' errortest.asy: 75.4: no matching field or type of name 'u' in 'm' errortest.asy: 77.5: no matching field or type of name 'u' in 'm' errortest.asy: 84.3: expression cannot be used as an address errortest.asy: 89.3: use of variable 'f' is ambiguous errortest.asy: 91.4: use of variable 'm.f' is ambiguous errortest.asy: 97.11: array initializer used for non-array errortest.asy: 98.12: array initializer used for non-array errortest.asy: 103.4: no matching variable 'f.m' errortest.asy: 108.4: no matching variable 'x.m' errortest.asy: 116.12: no matching field of name 'z' in 'point' errortest.asy: 124.4: no matching variable 'p.z' errortest.asy: 132.4: use of variable 'p.f' is ambiguous errortest.asy: 140.4: no matching variable 'p.z' errortest.asy: 151.4: no matching function 'f()' errortest.asy: 152.4: no matching function 'f(string)' errortest.asy: 160.4: cannot call 'void f(int)' without parameters errortest.asy: 168.7: no matching function 'operator +(point)' errortest.asy: 173.10: types in conditional expression do not match errortest.asy: 178.10: type of conditional expression is ambiguous errortest.asy: 183.5: cannot convert 'int()' to 'int' in assignment errortest.asy: 188.5: assignment is ambiguous errortest.asy: 194.24: function must return a value errortest.asy: 200.11: type 'int' is not a structure errortest.asy: 209.3: allocation of struct 'b' is not in a valid scope errortest.asy: 219.3: break statement outside of a loop errortest.asy: 223.3: continue statement outside of a loop errortest.asy: 228.5: function cannot return a value errortest.asy: 234.5: function must return a value errortest.asy: 241.11: function must return a value errortest.asy: 244.11: function must return a value errortest.asy: 290.3: built-in functions cannot be modified errortest.asy: 298.11: cannot cast 'string' to 'int' errortest.asy: 312.4: accessing private field outside of structure errortest.asy: 313.4: accessing private field outside of structure errortest.asy: 314.4: accessing private field outside of structure errortest.asy: 314.4: accessing private field outside of structure errortest.asy: 315.4: modifying non-public field outside of structure errortest.asy: 316.4: modifying non-public field outside of structure errortest.asy: 318.4: accessing private field outside of structure errortest.asy: 319.4: accessing private field outside of structure errortest.asy: 320.4: accessing private field outside of structure errortest.asy: 321.4: modifying non-public field outside of structure errortest.asy: 330.18: no matching types or fields of name 'x' errortest.asy: 331.18: no matching types or fields of name 'f' errortest.asy: 341.3: modifying non-public field outside of structure errortest.asy: 342.3: modifying non-public field outside of structure errortest.asy: 344.3: modifying non-public field outside of structure errortest.asy: 350.4: accessing private field outside of structure errortest.asy: 351.4: accessing private field outside of structure errortest.asy: 353.4: accessing private field outside of structure errortest.asy: 354.4: accessing private field outside of structure errortest.asy: 360.18: no matching types or fields of name 'T' errortest.asy: 367.4: accessing private field outside of structure errortest.asy: 368.4: accessing private field outside of structure errortest.asy: 370.4: accessing private field outside of structure errortest.asy: 371.4: accessing private field outside of structure errortest.asy: 378.18: no matching types or fields of name 'T' errortest.asy: 386.11: modifying non-public field outside of structure errortest.asy: 387.11: modifying non-public field outside of structure errortest.asy: 388.11: modifying non-public field outside of structure errortest.asy: 389.11: modifying non-public field outside of structure errortest.asy: 393.3: modifying non-public field outside of structure errortest.asy: 394.3: modifying non-public field outside of structure errortest.asy: 395.3: modifying non-public field outside of structure errortest.asy: 396.3: modifying non-public field outside of structure errortest.asy: 400.3: modifying non-public field outside of structure errortest.asy: 401.3: modifying non-public field outside of structure errortest.asy: 402.3: modifying non-public field outside of structure errortest.asy: 403.3: modifying non-public field outside of structure errortest.asy: 407.11: modifying non-public field outside of structure errortest.asy: 408.11: modifying non-public field outside of structure errortest.asy: 409.11: modifying non-public field outside of structure errortest.asy: 410.11: modifying non-public field outside of structure errortest.asy: 411.3: modifying non-public field outside of structure errortest.asy: 412.3: modifying non-public field outside of structure errortest.asy: 413.3: modifying non-public field outside of structure errortest.asy: 414.3: modifying non-public field outside of structure errortest.asy: 419.7: inferred variable declaration without initializer errortest.asy: 422.20: cannot cast 'int' to 'var' errortest.asy: 425.4: cannot cast 'int' to 'var' errortest.asy: 426.12: cannot cast 'int' to 'var' errortest.asy: 427.12: cannot cast 'var' to 'int' errortest.asy: 430.25: cannot cast 'int' to 'var' errortest.asy: 430.28: cannot cast 'int' to 'var' errortest.asy: 430.31: cannot cast 'int' to 'var' errortest.asy: 431.13: cannot cast 'int[]' to 'var[]' errortest.asy: 432.14: cannot cast 'int' to 'var' errortest.asy: 432.17: cannot cast 'int' to 'var' errortest.asy: 432.20: cannot cast 'int' to 'var' errortest.asy: 433.15: cannot cast 'int' to 'var' errortest.asy: 433.18: cannot cast 'int' to 'var' errortest.asy: 433.21: cannot cast 'int' to 'var' errortest.asy: 434.13: cannot cast 'var[]' to 'int[]' errortest.asy: 435.3: type 'var' is not a structure errortest.asy: 438.17: cannot cast 'int' to 'var' errortest.asy: 442.7: could not infer type of initializer errortest.asy: 446.7: could not infer type of initializer errortest.asy: 448.7: could not infer type of initializer errortest.asy: 452.16: expression is not an array of inferable type errortest.asy: 457.16: expression is not an array of inferable type errortest.asy: 463.16: expression is not an array of inferable type errortest.asy: 470.7: array expression cannot be used as an address asymptote-2.37/errortest.asy000066400000000000000000000153771265434602500162650ustar00rootroot00000000000000/***** * errortest.asy * Andy Hammerlindl 2003/08/08 * * This struct attempts to trigger every error message reportable by the * compiler to ensure that errors are being reported properly. *****/ // name.cc { // line 33 x.y = 5; } { // line 50 int x = z; } { // line 67 x = 5; } { // line 84 - unreachable } { // line 95 x y1; x y2(); x y3(int); int y4(x); struct m { x y1; x y2(); x y3(int); int y4(x); } } { // line 130 int x; x.y = 4; } { // line 156 struct m { int x,y; } m.u.v = 5; } { // line 186 struct m { int x,y; } int x = m.z; } { // line 217 struct m { int x,y; } m.z = 5; } { // line 249 - unreachable } { // line 272 - not testable without typedef } { // line 283 struct m { int x,y; } m.u v; struct mm { m.u v; } } // exp.h { // line 109 5 = 4; } { // line 136 int f, f(); f; struct m { int f, f(); } m.f; } // exp.cc { // line 40 int x = {}; int y = {4, 5, 6}; } { // line 110 int f(), f(int); f.m = 5; } { // line 122 int x; x.m = 5; } { // line 147 struct point { int x,y; } point p; int x = p.z; } { // line 157 struct point { int x, y; } point p; p.z; } { // line 163 struct point { int f(), f(int); } point p; p.f; } { // line 204 struct point { int x, y; } point p; p.z = 5; } { // line 229 - unreachable } { // lines 261 and 275 - wait for subscript to be fully implemented. } { // line 515 void f(int), f(int, int); f(); f("Hello?"); } { // line 520 - not yet testable (need int->float casting or the like) } { // line 525 void f(int); f(); } { // line 649 struct point { int x,y; } point p; p = +p; } { // line 1359 int x, f(); (true) ? x : f; } { // line 1359 int a, a(), b, b(); (true) ? a : b; } { // line 1581 int x, f(); x = f; } { // line 1586 int a, a(), b, b(); a = b; } // newexp.cc { // line 34 int f() = new int () { int x = 5; }; } { // line 64 int x = new int; } { // line 72 struct a { struct b { } } new a.b; } // stm.cc { // line 86 5; } { // line 246 break; } { // line 261 continue; } { // line 282 void f() { return 17; } } { // line 288 int f() { return; } } // dec.cc { // line 378 int f() { int x = 5; } int g() { if (true) return 7; } } // env.h { // line 99 struct m {} struct m {} } { // line 109 int f() { return 1; } int f() { return 2; } int x = 1; int x = 2; struct m { int f() { return 1; } int f() { return 2; } int x = 1; int x = 2; } } // env.cc { // line 107 - currently unreachable as no built-ins are currently used // in records. } { // line 140 // Assuming there is a built-in function void abort(string): void f(string); abort = f; } { // line 168 - currently unreachable as no built-in functions are // currently used in records. } { // line 222 int x = "Hello"; } // Test permissions. { struct A { private int x=4; restricted int y=5; private void f() {} restricted void g() {} } A a; a.x; a.x = 4; a.x += 5; a.y = 6; a.y += 7; a.f; a.f(); a.f = new void() {}; a.g = new void() {}; } { struct A { private int x=4; private void f() {} } A a; from a unravel x; from a unravel f; } { struct A { restricted int y=5; restricted void g() {} } A a; from a unravel y,g; y = 6; y += 7; g = new void() {}; } { struct A { private typedef int T; } A.T x; A.T x=4; int y=2; A.T x=y; A.T x=17+3*y; } { struct A { private typedef int T; } from A unravel T; } { struct A { private typedef int T; } A a; a.T x; a.T x=4; int y=2; a.T x=y; a.T x=17+3*y; } { struct A { private typedef int T; } A a; from a unravel T; } // Read-only settings // Ensure that the safe and globalwrite options can't be modified inside the // code. { access settings; settings.safe=false; settings.safe=true; settings.globalwrite=false; settings.globalwrite=true; } { from settings access safe, globalwrite; safe=false; safe=true; globalwrite=false; globalwrite=true; } { from settings access safe as x, globalwrite as y; x=false; x=true; y=false; y=true; } { import settings; settings.safe=false; settings.safe=true; settings.globalwrite=false; settings.globalwrite=true; safe=false; safe=true; globalwrite=false; globalwrite=true; } // Test cases where var is used outside of type inference. { var x; } { var f() { return 4; } } { (var)3; var x = (var)3; int y = (var)3; } { var[] b = new var[] { 1, 2, 3}; var[] b = new int[] { 1, 2, 3}; var[] c = {1, 2, 3}; new var[] { 4, 5, 6}; int[] d = new var[] { 4, 5, 6}; new var; } { int f(var x = 3) { return 0; } } { int f, f(); var g = f; } { struct A { int f, f(); } var g = A.f; A a; var h = a.f; } { int x; for (var i : x) ; } { int x, x(); for (var i : x) ; } { int x, x(); int[] x = {2,3,4}; for (var i : x) ; } { int[] temp={0}; int[] v={0}; temp[v]= v; } // Keyword and rest errors. { int f(string s="" ... int[] a); f(1,2,3 ... new int[] {4,5,6}, "hi"); f(1,2,3 ... new int[] {4,5,6} ... new int[] {7,8,9}); f(... new int[] {4,5,6}, "hi"); f(... new int[] {4,5,6} ... new int[] {7,8,9}); } { int f(... int[] x, int y); int g(... int[] x, int y) { return 7; } int f(string s ... int[] x, int y); int g(string s ... int[] x, int y) { return 7; } int f(int keyword x, int y); int g(int keyword x, int y) { return 7; } int f(int keyword x, int y, string z); int g(int keyword x, int y, string z) { return 7; } int f(real t, int keyword x, int y); int g(real t, int keyword x, int y) { return 7; } int f(real t, int keyword x, int y, string z); int g(real t, int keyword x, int y, string z) { return 7; } } { int f(int notkeyword x); int g(int notkeyword x) { return 7; } int f(real w, int notkeyword x); int g(real w, int notkeyword x) { return 7; } int f(real w, int keyword y, int notkeyword x); int g(real w, int keyword y, int notkeyword x) { return 7; } int f(real w, int notkeyword y, int keyword x); int g(real w, int notkeyword y, int keyword x) { return 7; } int f(int notkeyword x, int y, string z); int g(int notkeyword x, int y, string z) { return 7; } int f(int notkeyword x, int y); int g(int notkeyword x, int y) { return 7; } int f(int notkeyword x, int y, string z); int g(int notkeyword x, int y, string z) { return 7; } int f(real t, int notkeyword x, int y); int g(real t, int notkeyword x, int y) { return 7; } int f(real t, int notkeyword x, int y, string z); int g(real t, int notkeyword x, int y, string z) { return 7; } } asymptote-2.37/examples/000077500000000000000000000000001265434602500153175ustar00rootroot00000000000000asymptote-2.37/examples/100d.views000066400000000000000000000012211265434602500170360ustar00rootroot00000000000000VIEW={View A} COO=95.703857421875 -26.603919982910156 122.73419952392578 C2C=-0.4144790768623352 0.7603927254676819 0.5000100135803223 ROO=141.69743417830577 ROLL=13.566625455930614 AAC=34.903342413559436 END VIEW={View B} COO=15.9437837600708 -12.494922637939453 67.1521987915039 C2C=0.9024380445480347 0.3321097493171692 0.27442431449890137 ROO=303.7409567061654 ROLL=66.40207458248847 AAC=34.903342413559436 END VIEW={View C} COO=-42.11725616455078 -13.32657241821289 18.372915267944336 C2C=0.6989848017692566 -0.009704185649752617 0.7150706648826599 ROO=444.70718853041143 ROLL=78.84753985408712 AAC=34.903342413559436 END asymptote-2.37/examples/1overx.asy000066400000000000000000000004651265434602500172660ustar00rootroot00000000000000import graph; size(200,IgnoreAspect); real f(real x) {return 1/x;}; bool3 branch(real x) { static int lastsign=0; if(x == 0) return false; int sign=sgn(x); bool b=lastsign == 0 || sign == lastsign; lastsign=sign; return b ? true : default; } draw(graph(f,-1,1,branch)); axes("$x$","$y$",red); asymptote-2.37/examples/BezierPatch.asy000066400000000000000000000006131265434602500202350ustar00rootroot00000000000000import three; size(10cm); currentlight=Headlamp; surface s=surface(patch(new triple[][] { {(0,0,0),(1,0,0),(1,0,0),(2,0,0)}, {(0,1,0),(1,0,1),(1,0,1),(2,1,0)}, {(0,1,0),(1,0,-1),(1,0,-1),(2,1,0)}, {(0,2,0),(1,2,0),(1,2,0),(2,2,0)}})); draw(s,yellow); draw(s.s[0].vequals(0.5),squarecap+2bp+blue,currentlight); draw(s.s[0].uequals(0.5),squarecap+2bp+red,currentlight); asymptote-2.37/examples/BezierSurface.asy000066400000000000000000000027661265434602500206010ustar00rootroot00000000000000import three; string viewpoint=" COO=-684.0787963867188 206.90650939941406 218.13809204101562 C2C=0.8244762420654297 -0.563306450843811 0.0540805421769619 ROO=1009.7407942621448 ROLL=17.39344555165265 "; // viewpoint=getstring("viewpoint",viewpoint); currentprojection=perspective(viewpoint); triple[][][] P={ { {(-1.6,0,1.875),(-2.3,0,1.875),(-2.7,0,1.875),(-2.7,0,1.65),}, {(-1.6,-0.3,1.875),(-2.3,-0.3,1.875),(-2.7,-0.3,1.875),(-2.7,-0.3,1.65),}, {(-1.5,-0.3,2.1),(-2.5,-0.3,2.1),(-3,-0.3,2.1),(-3,-0.3,1.65),}, {(-1.5,0,2.1),(-2.5,0,2.1),(-3,0,2.1),(-3,0,1.65),} },{ {(-2.7,0,1.65),(-2.7,0,1.425),(-2.5,0,0.975),(-2,0,0.75),}, {(-2.7,-0.3,1.65),(-2.7,-0.3,1.425),(-2.5,-0.3,0.975),(-2,-0.3,0.75),}, {(-3,-0.3,1.65),(-3,-0.3,1.2),(-2.65,-0.3,0.7275),(-1.9,-0.3,0.45),}, {(-3,0,1.65),(-3,0,1.2),(-2.65,0,0.7275),(-1.9,0,0.45),} },{ {(-2.7,0,1.65),(-2.7,0,1.875),(-2.3,0,1.875),(-1.6,0,1.875),}, {(-2.7,0.3,1.65),(-2.7,0.3,1.875),(-2.3,0.3,1.875),(-1.6,0.3,1.875),}, {(-3,0.3,1.65),(-3,0.3,2.1),(-2.5,0.3,2.1),(-1.5,0.3,2.1),}, {(-3,0,1.65),(-3,0,2.1),(-2.5,0,2.1),(-1.5,0,2.1),} },{ {(-2,0,0.75),(-2.5,0,0.975),(-2.7,0,1.425),(-2.7,0,1.65),}, {(-2,0.3,0.75),(-2.5,0.3,0.975),(-2.7,0.3,1.425),(-2.7,0.3,1.65),}, {(-1.9,0.3,0.45),(-2.65,0.3,0.7275),(-3,0.3,1.2),(-3,0.3,1.65),}, {(-1.9,0,0.45),(-2.65,0,0.7275),(-3,0,1.2),(-3,0,1.65),} } }; picture pic; size(pic,15cm); size3(pic,10cm); draw(pic,surface(P),blue); add(embed("label",pic),(0,0),N); asymptote-2.37/examples/BezierTriangle.asy000066400000000000000000000003071265434602500207430ustar00rootroot00000000000000import three; currentprojection=perspective(-2,5,1); size(10cm); surface s=surface((0,0,0)--(3,0,0)--(1.5,3*sqrt(3)/2,0)--cycle, new triple[] {(1.5,sqrt(3)/2,2)}); draw(s,red); asymptote-2.37/examples/Coons.asy000066400000000000000000000001731265434602500171170ustar00rootroot00000000000000size(200); pen[] p={red,green,blue,magenta}; path g=(0,0){dir(45)}..(1,0)..(1,1)..(0,1)..cycle; tensorshade(g,p); dot(g); asymptote-2.37/examples/Gouraud.asy000066400000000000000000000006001265434602500174370ustar00rootroot00000000000000size(200); pen[] p={red,green,blue,magenta}; pair[] z={(-1,0),(0,0),(0,1),(1,0)}; int[] edges={0,0,0,1}; gouraudshade(z[0]--z[2]--z[3]--cycle,p,z,edges); draw(z[0]--z[1]--z[2]--cycle); draw(z[1]--z[3]--z[2],dashed); dot(Label,z[0],W); dot(Label,z[1],S); dot(Label,z[2],N); dot(Label,z[3],E); label("0",z[0]--z[1],S,red); label("1",z[1]--z[2],E,red); label("2",z[2]--z[0],NW,red); asymptote-2.37/examples/Gouraudcontour.asy000066400000000000000000000011501265434602500210520ustar00rootroot00000000000000import graph; import palette; import contour; size(200); int n=100; real[] x=new real[n]; real[] y=new real[n]; real[] f=new real[n]; real F(real a, real b) {return a^2+b^2;} real r() {return 1.1*(rand()/randMax*2-1);} for(int i=0; i < n; ++i) { x[i]=r(); y[i]=r(); f[i]=F(x[i],y[i]); } pen Tickpen=black; pen tickpen=gray+0.5*linewidth(currentpen); pen[] Palette=BWRainbow(); bounds range=image(x,y,f,Range(0,2),Palette); draw(contour(pairs(x,y),f,new real[]{0.25,0.5,1},operator ..)); palette("$f(x,y)$",range,point(NW)+(0,0.5),point(NE)+(0,0.8),Top,Palette, PaletteTicks(Tickpen,tickpen)); asymptote-2.37/examples/Klein.asy000066400000000000000000000024601265434602500171010ustar00rootroot00000000000000import graph3; size(469pt); viewportmargin=0; currentprojection=perspective( camera=(25.0851928432063,-30.3337528952473,19.3728775115443), up=Z, target=(-0.590622314050054,0.692357205025578,-0.627122488455679), zoom=1, autoadjust=false); triple f(pair t) { real u=t.x; real v=t.y; real r=2-cos(u); real x=3*cos(u)*(1+sin(u))+r*cos(v)*(u < pi ? cos(u) : -1); real y=8*sin(u)+(u < pi ? r*sin(u)*cos(v) : 0); real z=r*sin(v); return (x,y,z); } surface s=surface(f,(0,0),(2pi,2pi),8,8,Spline); draw(s,lightolive+white,"bottle",render(merge=true)); string lo="$\displaystyle u\in[0,\pi]: \cases{x=3\cos u(1+\sin u)+(2-\cos u)\cos u\cos v,\cr y=8\sin u+(2-\cos u)\sin u\cos v,\cr z=(2-\cos u)\sin v.\cr}$"; string hi="$\displaystyle u\in[\pi,2\pi]:\\\cases{x=3\cos u(1+\sin u)-(2-\cos u)\cos v,\cr y=8\sin u,\cr z=(2-\cos u)\sin v.\cr}$"; real h=0.0125; begingroup3("parametrization"); draw(surface(xscale(-0.38)*yscale(-0.18)*lo,s,0,1.7,h,bottom=false), "[0,pi]"); draw(surface(xscale(0.26)*yscale(0.1)*rotate(90)*hi,s,4.9,1.4,h,bottom=false), "[pi,2pi]"); endgroup3(); begingroup3("boundary"); draw(s.uequals(0),blue+dashed); draw(s.uequals(pi),blue+dashed); endgroup3(); add(new void(frame f, transform3 t, picture pic, projection P) { draw(f,invert(box(min(f,P),max(f,P)),P),"frame"); }); asymptote-2.37/examples/NURBScurve.asy000066400000000000000000000012111265434602500177660ustar00rootroot00000000000000import three; size(10cm); currentprojection=perspective(50,80,50); // Nonrational curve: // udegree=3, nu=6; real[] knot={0,0,0,0,0.4,0.6,1,1,1,1}; triple[] P={ (-31.2061,12.001,6.45082), (-31.3952,14.7353,6.53707), (-31.5909,21.277,6.70051), (-31.4284,25.4933,6.76745), (-31.5413,30.3485,6.68777), (-31.4896,32.2839,6.58385) }; draw(P,knot,green); // Rational Bezier curve: // udegree=3, nu=4; real[] knot={0,0,0,0,1,1,1,1}; path3 g=scale3(20)*(X{Y}..{-X}Y); triple[] P={point(g,0),postcontrol(g,0),precontrol(g,1),point(g,1)}; // Optional weights: real[] weights=array(P.length,1.0); weights[2]=5; draw(P,knot,weights,red); asymptote-2.37/examples/NURBSsphere.asy000066400000000000000000000017741265434602500201460ustar00rootroot00000000000000import three; /* Reference: @article{Qin97, title={{Representing quadric surfaces using NURBS surfaces}}, author={Qin, K.}, journal={Journal of Computer Science and Technology}, volume={12}, number={3}, pages={210--216}, year={1997}, publisher={Springer} } */ size(10cm); currentprojection=perspective(5,4,2,autoadjust=false); // udegree=2, vdegree=3, nu=3, nv=4; real[] W={2/3,1/3,1}; real[] w={1,1/3,1/3,1}; // 10 distinct control points triple[][] P={{(0,0,1),(-2,-2,1),(-2,-2,-1),(0,0,-1)}, {(0,0,1),(2,-2,1),(2,-2,-1),(0,0,-1)}, {(0,0,1),(2,2,1),(2,2,-1),(0,0,-1)}, {(0,0,1),(-2,2,1),(-2,2,-1),(0,0,-1)}}; P.cyclic=true; real[][] weights=new real[3][4]; for(int i=0; i < 3; ++i) for(int j=0; j < 4; ++j) weights[i][j]=W[i]*w[j]; real[] uknot={0,0,1/3,1/2,1,1}; real[] vknot={0,0,0,0,1,1,1,1}; int N=1; for(int k=0; k < N; ++k) for(int i=0; i < 4; ++i) draw(shift(k*Z)*P[i:i+3],uknot,vknot,weights,blue); // draw(unitsphere,red+opacity(0.1)); asymptote-2.37/examples/NURBSsurface.asy000066400000000000000000000026651265434602500203100ustar00rootroot00000000000000import three; size(10cm); currentprojection=perspective(50,80,50); // Nonrational surface: // udegree=3, vdegree=3, nu=5, nv=6; real[] uknot={0,0,0,0,0.5,1,1,1,1}; real[] vknot={0,0,0,0,0.4,0.6,1,1,1,1}; triple[][] P={{ (-31.2061,12.001,6.45082), (-31.3952,14.7353,6.53707), (-31.5909,21.277,6.70051), (-31.4284,25.4933,6.76745), (-31.5413,30.3485,6.68777), (-31.4896,32.2839,6.58385) },{ (-28.279,12.001,7.89625), (-28.4187,14.7353,8.00954), (-28.5633,21.277,8.22422), (-28.4433,25.4933,8.31214), (-28.5266,30.3485,8.20749), (-28.4885,32.2839,8.07099) },{ (-20,12.001,10.0379), (-20,14.7353,10.2001), (-20,21.277,10.5076), (-20,25.4933,10.6335), (-20,30.3485,10.4836), (-20,32.2839,10.2881) },{ (-11.721,12.001,7.84024), (-11.5813,14.7353,7.95269), (-11.4367,21.277,8.16575), (-11.5567,25.4933,8.25302), (-11.4734,30.3485,8.14915), (-11.5115,32.2839,8.01367) },{ (-8.79391,12.001,6.39481), (-8.60483,14.7353,6.48022), (-8.40905,21.277,6.64204), (-8.57158,25.4933,6.70832), (-8.45874,30.3485,6.62943), (-8.51041,32.2839,6.52653) } }; draw(P,uknot,vknot,new pen[] {red,green,blue,magenta}); // Rational Bezier patch: // udegree=3, vdegree=3, nu=4, nv=4; real[] uknot={0,0,0,0,1,1,1,1}; real[] vknot={0,0,0,0,1,1,1,1}; triple[][] P=scale3(20)*octant1.P; // Optional weights: real[][] weights=array(P.length,array(P[0].length,1.0)); weights[0][2]=5.0; draw(P,uknot,vknot,weights,blue); asymptote-2.37/examples/Pythagoras.asy000066400000000000000000000010551265434602500201570ustar00rootroot00000000000000size(0,150); import geometry; real a=3; real b=4; real c=hypot(a,b); pair z1=(0,b); pair z2=(a,0); pair z3=(a+b,0); perpendicular(z1,NE,z1--z2,blue); perpendicular(z3,NW,blue); draw(square((0,0),z3)); draw(square(z1,z2)); real d=0.3; pair v=unit(z2-z1); draw(baseline("$a$"),-d*I--z2-d*I,red,Bars,Arrows,PenMargins); draw(baseline("$b$"),z2-d*I--z3-d*I,red,Arrows,Bars,PenMargins); draw("$c$",z3+z2*I-d*v--z2-d*v,red,Arrows,PenMargins); draw("$a$",z3+d--z3+z2*I+d,red,Arrows,Bars,PenMargins); draw("$b$",z3+z2*I+d--z3+z3*I+d,red,Arrows,Bars,PenMargins); asymptote-2.37/examples/PythagoreanTree.asy000066400000000000000000000006441265434602500211420ustar00rootroot00000000000000size(250); real a=3; real b=4; real c=hypot(a,b); transform ta=shift(c,c)*rotate(-aCos(a/c))*scale(a/c)*shift(-c); transform tb=shift(0,c)*rotate(aCos(b/c))*scale(b/c); picture Pythagorean(int n) { picture pic; fill(pic,scale(c)*unitsquare,1/(n+1)*green+n/(n+1)*brown); if(n == 0) return pic; picture branch=Pythagorean(--n); add(pic,ta*branch); add(pic,tb*branch); return pic; } add(Pythagorean(12)); asymptote-2.37/examples/RiemannSphere.asy000066400000000000000000000017411265434602500206000ustar00rootroot00000000000000import graph3; import solids; currentlight=White; defaultrender.merge=true; size(10cm,0); pair k=(1,0.2); real r=abs(k); real theta=angle(k); real x(real t) { return r^t*cos(t*theta); } real y(real t) { return r^t*sin(t*theta); } real z(real t) { return 0; } real u(real t) { return x(t)/(x(t)^2+y(t)^2+1); } real v(real t) { return y(t)/(x(t)^2+y(t)^2+1); } real w(real t) { return (x(t)^2+y(t)^2)/(x(t)^2+y(t)^2+1); } real nb=3; for (int i=0; i<12; ++i) draw((0,0,0)--nb*(Cos(i*30),Sin(i*30),0),yellow); for (int i=0; i<=nb; ++i) draw(circle((0,0,0),i),lightgreen+white); path3 p=graph(x,y,z,-200,40,operator ..); path3 q=graph(u,v,w,-200,40,operator ..); revolution sph=sphere((0,0,0.5),0.5); draw(surface(sph),green+white+opacity(0.5)); draw(p,1bp+heavyred); draw(q,1bp+heavyblue); triple A=(0,0,1), B=(u(40),v(40),w(40)), C=(x(40),y(40),z(40)); path3 L=A--C; draw(L,1bp+black); pen p=fontsize(8pt); dot("$(0,0,1)$",A,N,p); dot("$(u,v,w)$",B,E,p); dot("$(x,y,0)$",C,E,p); asymptote-2.37/examples/RiemannSurface.asy000066400000000000000000000005611265434602500207410ustar00rootroot00000000000000import graph3; import palette; size(200,300,keepAspect=false); //settings.nothin=true; currentprojection=orthographic(10,10,30); currentlight=(10,10,5); triple f(pair t) {return (exp(t.x)*cos(t.y),exp(t.x)*sin(t.y),t.y);} surface s=surface(f,(-4,-2pi),(0,4pi),8,16,Spline); s.colors(palette(s.map(zpart),Rainbow())); draw(s,render(merge=true)); asymptote-2.37/examples/RiemannSurfaceRoot.asy000066400000000000000000000006021265434602500216010ustar00rootroot00000000000000// Riemann surface of z^{1/n} import graph3; import palette; int n=3; size(200,300,keepAspect=false); currentprojection=orthographic(10,10,30); currentlight=(10,10,5); triple f(pair t) {return (t.x*cos(t.y),t.x*sin(t.y),t.x^(1/n)*sin(t.y/n));} surface s=surface(f,(0,0),(1,2pi*n),8,16,Spline); s.colors(palette(s.map(zpart),Rainbow())); draw(s,meshpen=black,render(merge=true)); asymptote-2.37/examples/Sierpinski.asy000066400000000000000000000006301265434602500201540ustar00rootroot00000000000000size(10cm); // Draw Sierpinski triangle with top vertex A, side s, and depth q. void Sierpinski(pair A, real s, int q, bool top=true) { pair B=A-(1,sqrt(2))*s/2; pair C=B+s; if(top) draw(A--B--C--cycle); draw((A+B)/2--(B+C)/2--(A+C)/2--cycle); if(q > 0) { Sierpinski(A,s/2,q-1,false); Sierpinski((A+B)/2,s/2,q-1,false); Sierpinski((A+C)/2,s/2,q-1,false); } } Sierpinski((0,1),1,5); asymptote-2.37/examples/SierpinskiGasket.asy000066400000000000000000000015211265434602500213130ustar00rootroot00000000000000size(200); import palette; import three; currentprojection=perspective(8,2,1); triple[] M={(0,0,1),1/3*(sqrt(8),0,-1), 1/3*((sqrt(8))*Cos(120),(sqrt(8))*Sin(120),-1), 1/3*((sqrt(8))*Cos(240),(sqrt(8))*Sin(240),-1)}; int level=5; surface s; void recur(triple p, real u, int l) { if(l < level) for(triple V : M) recur(p+u*V,u/2,l+1); else for(triple V : M) { s.append(surface((p+u*(V+M[0]))--(p+u*(V+M[1]))--(p+u*(V+M[2]))--cycle)); s.append(surface((p+u*(V+M[0]))--(p+u*(V+M[2]))--(p+u*(V+M[3]))--cycle)); s.append(surface((p+u*(V+M[0]))--(p+u*(V+M[3]))--(p+u*(V+M[1]))--cycle)); s.append(surface((p+u*(V+M[3]))--(p+u*(V+M[2]))--(p+u*(V+M[1]))--cycle)); } } recur(O,0.5,1); s.colors(palette(s.map(zpart),Rainbow())); draw(s,render(merge=true)); asymptote-2.37/examples/SierpinskiSponge.asy000066400000000000000000000045661265434602500213440ustar00rootroot00000000000000size(200); import palette; import three; currentprojection=orthographic(1,1,1); triple[] M={ (-1,-1,-1),(0,-1,-1),(1,-1,-1),(1,0,-1), (1,1,-1),(0,1,-1),(-1,1,-1),(-1,0,-1), (-1,-1,0),(1,-1,0),(1,1,0),(-1,1,0), (-1,-1,1),(0,-1,1),(1,-1,1),(1,0,1),(1,1,1),(0,1,1),(-1,1,1),(-1,0,1) }; surface[] Squares={ surface((1,-1,-1)--(1,1,-1)--(1,1,1)--(1,-1,1)--cycle), surface((-1,-1,-1)--(-1,1,-1)--(-1,1,1)--(-1,-1,1)--cycle), surface((1,1,-1)--(-1,1,-1)--(-1,1,1)--(1,1,1)--cycle), surface((1,-1,-1)--(-1,-1,-1)--(-1,-1,1)--(1,-1,1)--cycle), surface((1,-1,1)--(1,1,1)--(-1,1,1)--(-1,-1,1)--cycle), surface((1,-1,-1)--(1,1,-1)--(-1,1,-1)--(-1,-1,-1)--cycle), }; int[][] SquaresPoints={ {2,3,4,10,16,15,14,9}, {0,7,6,11,18,19,12,8}, {4,5,6,11,18,17,16,10}, {2,1,0,8,12,13,14,9}, {12,13,14,15,16,17,18,19}, {0,1,2,3,4,5,6,7} }; int[][] index={ {0,2,4},{0,1},{1,2,4},{2,3},{1,3,4},{0,1},{0,3,4},{2,3}, {4,5},{4,5},{4,5},{4,5}, {0,2,5},{0,1},{1,2,5},{2,3},{1,3,5},{0,1},{0,3,5},{2,3} }; int[] Sponge0=array(n=6,value=1); int[] eraseFaces(int n, int[] Sponge0) { int[] temp=copy(Sponge0); for(int k : index[n]) { temp[k]=0; } return temp; } int[][] Sponge1=new int[20][]; for(int n=0; n < 20; ++n) { Sponge1[n]=eraseFaces(n,Sponge0); } int[][] eraseFaces(int n, int[][] Sponge1) { int[][] temp=copy(Sponge1); for(int k : index[n]) for(int n1 : SquaresPoints[k]) temp[n1][k]=0; return temp; } int[][][] Sponge2=new int[20][][]; for(int n=0; n < 20; ++n) Sponge2[n]=eraseFaces(n,Sponge1); int[][][] eraseFaces(int n, int[][][] Sponge2) { int[][][] temp=copy(Sponge2); for(int k : index[n]) for(int n2: SquaresPoints[k]) for(int n1: SquaresPoints[k]) temp[n2][n1][k]=0; return temp; } int[][][][] Sponge3=new int[20][][][]; for(int n=0; n < 20; ++n) Sponge3[n]=eraseFaces(n,Sponge2); surface s3; real u=2/3; for(int n3=0; n3 < 20; ++n3) { surface s2; for(int n2=0; n2 < 20; ++n2) { surface s1; for(int n1=0; n1 < 20; ++n1) { for(int k=0; k < 6; ++k){ transform3 T=scale3(u)*shift(M[n1])*scale3(0.5); if(Sponge3[n3][n2][n1][k] > 0) { s1.append(T*Squares[k]); } } } transform3 T=scale3(u)*shift(M[n2])*scale3(0.5); s2.append(T*s1); } transform3 T=scale3(u)*shift(M[n3])*scale3(0.5); s3.append(T*s2); } s3.colors(palette(s3.map(abs),Rainbow())); draw(s3); asymptote-2.37/examples/advection.asy000066400000000000000000000100761265434602500200150ustar00rootroot00000000000000size(0,22cm); texpreamble(" \usepackage{bm} \def\v{\bm} \def\grad{\v\nabla} \def\cross{{\v\times}} \def\curl{\grad\cross} \def\del{\nabla} "); defaultpen(fontsize(10pt)); real margin=1.5mm; object IC=draw("initial condition $\v U_0$",box,(0,1), margin,black,FillDraw(palegray)); object Adv0=draw("Lagrangian state $\v U(t)$",ellipse,(1,1), margin,red,FillDraw(palered)); object Adv=draw("Lagrangian prediction $\v U(t+\tau)$",ellipse,(1,0), margin,red,FillDraw(palered)); object AdvD=draw("diffused parcels",ellipse,(1.8,1), margin,red,FillDraw(palered)); object Ur=draw("rearranged $\v \widetilde U$",box,(0,0), margin,orange+gray,FillDraw(paleyellow)); object Ui=draw("interpolated $\v \widetilde U$",box,(1,-1), margin,blue,FillDraw(paleblue)); object Crank=draw("${\cal L}^{-1}(-\tau){\cal L}(\tau)\v \widetilde U$", box,(0.5,-1),margin,blue,FillDraw(paleblue)); object CrankR=draw("${\cal L}^{-1}(-\tau){\cal L}(\tau)\v \widetilde U$", box,(0,-1),margin,orange+gray,FillDraw(paleyellow)); object Urout=draw(minipage("\center{Lagrangian rearranged solution~$\v U_R$}", 100pt),box,(0,-2),margin,orange+gray, FillDraw(paleyellow)); object Diff=draw("$\v D\del^2 \v \widetilde U$",box,(0.75,-1.5), margin,blue,FillDraw(paleblue)); object UIout=draw(minipage("\center{semi-Lagrangian solution~$\v U_I$}",80pt), box,(0.5,-2),margin,FillDraw(palered+paleyellow)); object psi=draw("$\psi=\del^{-2}\omega$",box,(1.6,-1), margin,darkgreen,FillDraw(palegreen)); object vel=draw("$\v v=\v{\hat z} \cross\grad\psi$",box,(1.6,-0.5), margin,darkgreen,FillDraw(palegreen)); add(new void(frame f, transform t) { pair padv=0.5*(point(Adv0,S,t)+point(Adv,N,t)); picture pic; draw(pic,"initialize",point(IC,E,t)--point(Adv0,W,t),RightSide,Arrow, PenMargin); draw(pic,minipage("\flushright{advect: Runge-Kutta}",80pt), point(Adv0,S,t)--point(Adv,N,t),RightSide,red,Arrow,PenMargin); draw(pic,Label("Lagrange $\rightarrow$ Euler",0.45), point(Adv,W,t)--point(Ur,E,t),5LeftSide,orange+gray, Arrow,PenMargin); draw(pic,"Lagrange $\rightarrow$ Euler",point(Adv,S,t)--point(Ui,N,t), RightSide,blue,Arrow,PenMargin); draw(pic,point(Adv,E,t)--(point(AdvD,S,t).x,point(Adv,E,t).y),red, Arrow(Relative(0.7)),PenMargin); draw(pic,minipage("\flushleft{diffuse: multigrid Crank--Nicholson}",80pt), point(Ui,W,t)--point(Crank,E,t),5N,blue,MidArrow,PenMargin); draw(pic,minipage("\flushleft{diffuse: multigrid Crank--Nicholson}",80pt), point(Ur,S,t)--point(CrankR,N,t),LeftSide,orange+gray,Arrow,PenMargin); draw(pic,"output",point(CrankR,S,t)--point(Urout,N,t),RightSide, orange+gray,Arrow,PenMargin); draw(pic,point(Ui,S,t)--point(Diff,N,t),blue,MidArrow,PenMargin); draw(pic,point(Crank,S,t)--point(Diff,N,t),blue,MidArrow,PenMargin); label(pic,"subtract",point(Diff,N,t),12N,blue); draw(pic,Label("Euler $\rightarrow$ Lagrange",0.5), point(Diff,E,t)--(point(AdvD,S,t).x,point(Diff,E,t).y)-- (point(AdvD,S,t).x,point(Adv,E,t).y),RightSide,blue, Arrow(position=1.5),PenMargin); dot(pic,(point(AdvD,S,t).x,point(Adv,E,t).y),red); draw(pic,(point(AdvD,S,t).x,point(Adv,E,t).y)--point(AdvD,S,t),red,Arrow, PenMargin); draw(pic,"output",point(Crank,S,t)--point(UIout,N,t),RightSide,brown,Arrow, PenMargin); draw(pic,Label("$t+\tau\rightarrow t$",0.45), point(AdvD,W,t)--point(Adv0,E,t),2.5LeftSide,red,Arrow,PenMargin); draw(pic,point(psi,N,t)--point(vel,S,t),darkgreen,Arrow,PenMargin); draw(pic,Label("self-advection",4.5),point(vel,N,t)-- arc((point(vel,N,t).x,point(Adv,E,t).y),5,270,90)-- (point(vel,N,t).x,padv.y)-- padv,LeftSide,darkgreen,Arrow,PenMargin); draw(pic,Label("multigrid",0.5,S),point(Ui,E,t)--point(psi,W,t),darkgreen, Arrow,PenMargin); add(f,pic.fit()); }); asymptote-2.37/examples/alignbox.asy000066400000000000000000000003651265434602500176440ustar00rootroot00000000000000real margin=1.5mm; object left=align(object("$x^2$",ellipse,margin),W); add(left); object right=align(object("$\sin x$",ellipse,margin),4E); add(right); add(new void(frame f, transform t) { draw(f,point(left,NE,t)--point(right,W,t)); }); asymptote-2.37/examples/alignedaxis.asy000066400000000000000000000054201265434602500203260ustar00rootroot00000000000000import graph; real Freq=60.0; real margin=5mm; pair exp(pair x) { return exp(x.x)*(cos(x.y)+I*sin(x.y)); } real Merr(real x, real w) { real tau=x/(2*Freq); return 20*log(abs((tau*w+tau/(exp(I*2*pi*Freq*tau)-1))*(I*2*pi*Freq))); } real Aerr(real x, real w) { real tau=x/(2*Freq); return degrees((tau*w+tau/(exp(I*2*pi*Freq*tau)-1))*(I*2*pi*Freq)); } picture pic1; scale(pic1,Log,Linear); real Merr1(real x){return Merr(x,1);} draw(pic1,graph(pic1,Merr1,1e-4,1),black+1.2); ylimits(pic1,-60,20); yaxis(pic1,"magnitude (dB)",LeftRight,RightTicks(new real[] {-60,-40,-20,0,20})); xaxis(pic1,"$f/f_\mathrm{Ny}$",BottomTop,LeftTicks(N=5)); yequals(pic1,0,Dotted); yequals(pic1,-20,Dotted); yequals(pic1,-40,Dotted); xequals(pic1,1e-3,Dotted); xequals(pic1,1e-2,Dotted); xequals(pic1,1e-1,Dotted); size(pic1,100,100,point(pic1,SW),point(pic1,NE)); label(pic1,"$\theta=1$",point(pic1,N),2N); frame f1=pic1.fit(); add(f1); picture pic1p; scale(pic1p,Log,Linear); real Aerr1(real x){return Aerr(x,1);} draw(pic1p,graph(pic1p,Aerr1,1e-4,1),black+1.2); ylimits(pic1p,-5,95); yaxis(pic1p,"phase (deg)",LeftRight,RightTicks(new real[] {0,45,90})); xaxis(pic1p,"$f/f_\mathrm{Ny}$",BottomTop,LeftTicks(N=5)); yequals(pic1p,0,Dotted); yequals(pic1p,45,Dotted); yequals(pic1p,90,Dotted); xequals(pic1p,1e-3,Dotted); xequals(pic1p,1e-2,Dotted); xequals(pic1p,1e-1,Dotted); size(pic1p,100,100,point(pic1p,SW),point(pic1p,NE)); frame f1p=pic1p.fit(); f1p=shift(0,min(f1).y-max(f1p).y-margin)*f1p; add(f1p); picture pic2; scale(pic2,Log,Linear); real Merr2(real x){return Merr(x,0.75);} draw(pic2,graph(pic2,Merr2,1e-4,1),black+1.2); ylimits(pic2,-60,20); yaxis(pic2,"magnitude (dB)",LeftRight,RightTicks(new real[] {-60,-40,-20,0,20})); xaxis(pic2,"$f/f_\mathrm{Ny}$",BottomTop,LeftTicks(N=5)); yequals(pic2,0,Dotted); yequals(pic2,-20,Dotted); yequals(pic2,-40,Dotted); xequals(pic2,1e-3,Dotted); xequals(pic2,1e-2,Dotted); xequals(pic2,1e-1,Dotted); size(pic2,100,100,point(pic2,SW),point(pic2,NE)); label(pic2,"$\theta=0.75$",point(pic2,N),2N); frame f2=pic2.fit(); f2=shift(max(f1).x-min(f2).x+margin)*f2; add(f2); picture pic2p; scale(pic2p,Log,Linear); real Aerr2(real x){return Aerr(x,0.75);} draw(pic2p,graph(pic2p,Aerr2,1e-4,1),black+1.2); ylimits(pic2p,-5,95); yaxis(pic2p,"phase (deg)",LeftRight,RightTicks(new real[] {0,45.1,90})); xaxis(pic2p,"$f/f_\mathrm{Ny}$",BottomTop,LeftTicks(N=5)); yequals(pic2p,0,Dotted); yequals(pic2p,45,Dotted); yequals(pic2p,90,Dotted); xequals(pic2p,1e-3,Dotted); xequals(pic2p,1e-2,Dotted); xequals(pic2p,1e-1,Dotted); size(pic2p,100,100,point(pic2p,SW),point(pic2p,NE)); frame f2p=pic2p.fit(); f2p=shift(max(f1p).x-min(f2p).x+margin,min(f2).y-max(f2p).y-margin)*f2p; add(f2p); asymptote-2.37/examples/animations/000077500000000000000000000000001265434602500174615ustar00rootroot00000000000000asymptote-2.37/examples/animations/cube.asy000066400000000000000000000016621265434602500211220ustar00rootroot00000000000000import math; import bsp; import animation; size(100,100); animation a; void face(face[] faces, path3 p, int j, int k) { picture pic=faces.push(p); filldraw(pic,project(p),Pen(j)); int sign=(k % 2 == 0) ? 1 : -1; transform t=scale(4)*transform(dir(p,0,sign),dir(p,0,-sign)); label(pic,t*(string) j,project(0.5*(min(p)+max(p)))); } void snapshot(transform3 t) { static transform3 s=shift(-0.5*(X+Y+Z)); save(); face[] faces; int j=-1; transform3 T=t*s; for(int k=0; k < 2; ++k) { face(faces,T*plane((1,0,0),(0,1,0),(0,0,k)),++j,k); face(faces,T*plane((0,1,0),(0,0,1),(k,0,0)),++j,k); face(faces,T*plane((0,0,1),(1,0,0),(0,k,0)),++j,k); } add(faces); a.add(); restore(); } int n=50; real step=360/n; for(int i=0; i < n; ++i) snapshot(rotate(i*step,X)); for(int i=0; i < n; ++i) snapshot(rotate(i*step,Y)); for(int i=0; i < n; ++i) snapshot(rotate(i*step,Z)); a.movie(loops=10,delay=50); asymptote-2.37/examples/animations/dice.u3d000066400000000000000000004716401265434602500210160ustar00rootroot00000000000000U3DRx sj CreatedBy"3dif.x3d 4.0.17.1382 (3.5.10.1242)RHAdobeUnitsMeters0ÿÿÿÿÿÿtobject0!ÿÿÿOobject0€?€?€?€?ÿÿÿt_dice!ÿÿÿT_diceobject0€?€?€?€?ÿÿÿ¸object44"ÿÿÿcobject44_dice€?€?€?€?object44Eÿÿÿ$object44Materialÿÿÿ|_sphere0!ÿÿÿW_sphere0object0€?€?€?€?ÿÿÿÀobject42"ÿÿÿfobject42_sphere0€?€?€?À@€À€?object42Eÿÿÿ%object42 Material1ÿÿÿ€ _sphere0_0!ÿÿÿY _sphere0_0object0€?€?€?€?ÿÿÿÀobject40"ÿÿÿhobject40 _sphere0_0€?€?€?@À€À€?object40Eÿÿÿ%object40 Material1ÿÿÿ€ _sphere0_1!ÿÿÿY _sphere0_1object0€?€?€?€?ÿÿÿÀobject38"ÿÿÿhobject38 _sphere0_1€?€?€?À@€@€?object38Eÿÿÿ%object38 Material2ÿÿÿ„ _sphere0_0_1!ÿÿÿ[ _sphere0_0_1object0€?€?€?€?ÿÿÿÄobject36"ÿÿÿjobject36 _sphere0_0_1€?€?€?@À€@€?object36Eÿÿÿ%object36 Material2ÿÿÿ„ _sphere0_1_2!ÿÿÿ[ _sphere0_1_2object0€?€?€?€?ÿÿÿÄobject34"ÿÿÿjobject34 _sphere0_1_2€?€?€?€@€?object34Eÿÿÿ%object34 Material2ÿÿÿ„ _sphere0_1_3!ÿÿÿ[ _sphere0_1_3object0€?€?€?€?ÿÿÿÄobject32"ÿÿÿjobject32 _sphere0_1_3€?€?€?€À@À?€?object32Eÿÿÿ%object32 Material3ÿÿÿˆ_sphere0_0_1_3!ÿÿÿ]_sphere0_0_1_3object0€?€?€?€?ÿÿÿÄobject30"ÿÿÿlobject30_sphere0_0_1_3€?€?€?€À@À¿€?object30Eÿÿÿ%object30 Material3ÿÿÿˆ_sphere0_1_3_4!ÿÿÿ]_sphere0_1_3_4object0€?€?€?€?ÿÿÿÄobject28"ÿÿÿlobject28_sphere0_1_3_4€?€?€?€ÀÀ?€?object28Eÿÿÿ%object28 Material3ÿÿÿŒ_sphere0_0_1_3_4!ÿÿÿ__sphere0_0_1_3_4object0€?€?€?€?ÿÿÿÈobject26"ÿÿÿnobject26_sphere0_0_1_3_4€?€?€?€ÀÀÀ¿€?object26Eÿÿÿ%object26 Material3ÿÿÿŒ_sphere0_1_2_3_4!ÿÿÿ__sphere0_1_2_3_4object0€?€?€?€?ÿÿÿÈobject24"ÿÿÿnobject24_sphere0_1_2_3_4€?€?€?€ÀÀÀ?€?object24Eÿÿÿ%object24 Material3ÿÿÿ_sphere0_1_2_3_5_6!ÿÿÿa_sphere0_1_2_3_5_6object0€?€?€?€?ÿÿÿÈobject22"ÿÿÿpobject22_sphere0_1_2_3_5_6€?€?€?€@€?object22Eÿÿÿ%object22 Material4ÿÿÿ_sphere0_1_2_3_5_7!ÿÿÿa_sphere0_1_2_3_5_7object0€?€?€?€?ÿÿÿÈobject20"ÿÿÿpobject20_sphere0_1_2_3_5_7€?€?€?@€@À€?object20Eÿÿÿ%object20 Material4ÿÿÿ”_sphere0_1_2_3_5_6_7!ÿÿÿc_sphere0_1_2_3_5_6_7object0€?€?€?€?ÿÿÿÌobject18"ÿÿÿrobject18_sphere0_1_2_3_5_6_7€?€?€?@€@@€?object18Eÿÿÿ%object18 Material4ÿÿÿ”_sphere0_1_2_3_5_7_8!ÿÿÿc_sphere0_1_2_3_5_7_8object0€?€?€?€?ÿÿÿÌobject16"ÿÿÿrobject16_sphere0_1_2_3_5_7_8€?€?€?À€ÀÀ€?object16Eÿÿÿ%object16 Material5ÿÿÿ˜_sphere0_1_2_3_5_6_7_8!ÿÿÿe_sphere0_1_2_3_5_6_7_8object0€?€?€?€?ÿÿÿÌobject14"ÿÿÿtobject14_sphere0_1_2_3_5_6_7_8€?€?€?À€À@€?object14Eÿÿÿ%object14 Material5ÿÿÿ”_sphere0_1_2_3_5_7_9!ÿÿÿc_sphere0_1_2_3_5_7_9object0€?€?€?€?ÿÿÿÌobject12"ÿÿÿrobject12_sphere0_1_2_3_5_7_9€?€?€?@€ÀÀ€?object12Eÿÿÿ%object12 Material5ÿÿÿ˜_sphere0_1_2_3_5_6_7_9!ÿÿÿe_sphere0_1_2_3_5_6_7_9object0€?€?€?€?ÿÿÿÌobject10"ÿÿÿtobject10_sphere0_1_2_3_5_6_7_9€?€?€?@€À@€?object10Eÿÿÿ%object10 Material5ÿÿÿ˜_sphere0_1_2_3_5_7_8_9!ÿÿÿe_sphere0_1_2_3_5_7_8_9object0€?€?€?€?ÿÿÿÈobject8"ÿÿÿrobject8_sphere0_1_2_3_5_7_8_9€?€?€?À€@À€?object8Eÿÿÿ$object8 Material4ÿÿÿœ_sphere0_1_2_3_5_6_7_8_9!ÿÿÿg_sphere0_1_2_3_5_6_7_8_9object0€?€?€?€?ÿÿÿÈobject6"ÿÿÿtobject6_sphere0_1_2_3_5_6_7_8_9€?€?€?À€@@€?object6Eÿÿÿ$object6 Material4ÿÿÿŒ_sphere0_1_3_10!ÿÿÿ^_sphere0_1_3_10object0€?€?€?€?ÿÿÿÀobject4"ÿÿÿkobject4_sphere0_1_3_10€?€?€?€@€?object4Eÿÿÿ$object4 Material6ÿÿÿŒ_sphere0_1_3_4_12!ÿÿÿ`_sphere0_1_3_4_12object0€?€?€?€?ÿÿÿÄobject2"ÿÿÿmobject2_sphere0_1_3_4_12€?€?€?€ÀÀ¿€?object2Eÿÿÿ$object2 Material3ÿÿÿŒ AmbientLight#ÿÿÿb AmbientLight€?€?€?€? AmbientLightÿÿÿœobject441ÿÿÿvobject44 èèèسÝ7€8€8€8€8Êh?¿\|?ÿÿÿœobject421ÿÿÿvobject42àrr™rrèèè€6€8€8€8€8Êh?¿\|?ÿÿÿœobject401ÿÿÿvobject40àrr™rrèèè€6€8€8€8€8Êh?¿\|?ÿÿÿœobject381ÿÿÿvobject38àrr™rrèèè€6€8€8€8€8Êh?¿\|?ÿÿÿœobject361ÿÿÿvobject36àrr™rrèèè€6€8€8€8€8Êh?¿\|?ÿÿÿœobject341ÿÿÿvobject34àrr™rrèèè€6€8€8€8€8Êh?¿\|?ÿÿÿœobject321ÿÿÿvobject32àrr™rrèèè€6€8€8€8€8Êh?¿\|?ÿÿÿœobject301ÿÿÿvobject30àrr™rrèèè€6€8€8€8€8Êh?¿\|?ÿÿÿœobject281ÿÿÿvobject28àrr™rrèèè€6€8€8€8€8Êh?¿\|?ÿÿÿœobject261ÿÿÿvobject26àrr™rrèèè€6€8€8€8€8Êh?¿\|?ÿÿÿœobject241ÿÿÿvobject24àrr™rrèèè€6€8€8€8€8Êh?¿\|?ÿÿÿœobject221ÿÿÿvobject22àrr™rrèèè€6€8€8€8€8Êh?¿\|?ÿÿÿœobject201ÿÿÿvobject20àrr™rrèèè€6€8€8€8€8Êh?¿\|?ÿÿÿœobject181ÿÿÿvobject18àrr™rrèèè€6€8€8€8€8Êh?¿\|?ÿÿÿœobject161ÿÿÿvobject16àrr™rrèèè€6€8€8€8€8Êh?¿\|?ÿÿÿœobject141ÿÿÿvobject14àrr™rrèèè€6€8€8€8€8Êh?¿\|?ÿÿÿœobject121ÿÿÿvobject12àrr™rrèèè€6€8€8€8€8Êh?¿\|?ÿÿÿœobject101ÿÿÿvobject10àrr™rrèèè€6€8€8€8€8Êh?¿\|?ÿÿÿœobject81ÿÿÿuobject8àrr™rrèèè€6€8€8€8€8Êh?¿\|?ÿÿÿœobject61ÿÿÿuobject6àrr™rrèèè€6€8€8€8€8Êh?¿\|?ÿÿÿœobject41ÿÿÿuobject4àrr™rrèèè€6€8€8€8€8Êh?¿\|?ÿÿÿœobject21ÿÿÿuobject2àrr™rrèèè€6€8€8€8€8Êh?¿\|?Sÿÿÿ0MaterialMaterialSÿÿÿ2 Material1 Material1Sÿÿÿ2 Material2 Material2Sÿÿÿ2 Material3 Material3Sÿÿÿ2 Material4 Material4Sÿÿÿ2 Material5 Material5Sÿÿÿ2 Material6 Material6TÿÿÿFMaterial?òðð=òðð=òðð=ÂÀ@?ÂÀ@?ÂÀ@?ÂÀ@?ÂÀ@?ÂÀ@?ÍÌL>€?TÿÿÿG Material1?ÍÌL>ÍÌL>ÍÌL>ÍÌL>ÍÌL?ÍÌL>ÍÌL>ÍÌL>ÍÌL>9Q¼>€?TÿÿÿG Material2?ÍÌL>ÍÌL>ÍÌL>€??ÍÌL?ÍÌL>ÍÌL>ÍÌL>9Q¼>€?TÿÿÿG Material3?ÍÌL>ÍÌL>ÍÌL>š™™>š™™>€?ÍÌL>ÍÌL>ÍÌL>9Q¼>€?TÿÿÿG Material4?ÍÌL>ÍÌL>ÍÌL>€?€?ÍÌL>ÍÌL>ÍÌL>9Q¼>€?TÿÿÿG Material5?ÍÌL>ÍÌL>ÍÌL>€?ÍÌL>ÍÌL>ÍÌL>9Q¼>€?TÿÿÿG Material6?ÍÌL>ÍÌL>ÍÌL>€?€?ÍÌL>ÍÌL>ÍÌL>9Q¼>€?Qÿÿÿ7 AmbientLightÍÌL>ÍÌL>ÍÌL>€?€?4C€?ÿÿÿ;ÿÿÿ=object44 €À€@€@€À€@€À€@€@€À€@€@€@€À€À€@€À€À€À€@€À€À€@€À€@€?€?€¿€¿€?€¿€?€?€?€?€?Á©hŠû«$±º«—ÚˆäòM°l5§Ažr“ZQÍ«Ÿ;ÿÿÿRobject42àrr™€?ïÃ>^ƒl?ôµ>ö>^ƒl?Ô‹Š>Õ‹Š>^ƒl?ö>ôµ>^ƒl?•ã¶±ïÃ>^ƒl?ö¾ôµ>^ƒl?Õ‹Š¾Ô‹Š>^ƒl?ôµ¾ö>^ƒl?ïþ×tÊ2^ƒl?õµ¾ö¾^ƒl?Ö‹Š¾Ò‹Š¾^ƒl?!ö¾òµ¾^ƒl?IQa³ïþ^ƒl?ö>ôµ¾^ƒl?Ö‹Š>Ӌо^ƒl?öµ>ö¾^ƒl?ó5?ó5?t='?Ô‹Š>ó5?ÿÿÿ>?ó5?Ó‹Š>u='?ó5?¦÷(²ó5?ó5?Ջоt='?ó5?¿þÿÿ>ó5?t='¿Ó‹Š>ó5?ó5¿™ ;3ó5?u='¿Ñ‹Š¾ó5?¿üÿÿ¾ó5?Ú‹Š¾s='¿ó5?Ž*гó5¿ó5?Ô‹Š>t='¿ó5??ýÿÿ¾ó5?v='?Ì‹Š¾ó5?^ƒl?ïÃ>y‚Z?óµ>ïÃ>t='?t='?ïÃ>òµ>y‚Z?ïÃ>:Ä\²^ƒl?ïÃ>ôµ¾y‚Z?ïÃ>u='¿s='?ïÃ>y‚Z¿òµ>ïÃ>^ƒl¿ðbt3ïÃ>z‚Z¿ïµ¾ïÃ>w='¿r='¿ïÃ>ûµ¾w‚Z¿ïÃ>¼ý´^ƒl¿ïÃ>óµ>y‚Z¿ïÃ>v='?r='¿ïÃ>{‚Z?éµ¾ïÃ>€?.½;³^ƒl?ïÃ>.½;³ó5?ó5?.½;³ïÃ>_ƒl?.½;³ºôn²€?.½;³ïþ^ƒl?.½;³ô5¿ò5?.½;³_ƒl¿ïÃ>.½;³€¿ÒB„3.½;³_ƒl¿ïþ.½;³ö5¿ñ5¿.½;³ïþ]ƒl¿.½;³2´€¿.½;³ïÃ>^ƒl¿.½;³õ5?ñ5¿.½;³aƒl? ïþ.½;³^ƒl?ïþy‚Z?óµ>ïþt='?t='?ïþòµ>y‚Z?ïþ:Ä\²^ƒl?ïþôµ¾y‚Z?ïþu='¿s='?ïþy‚Z¿òµ>ïþ^ƒl¿ðbt3ïþz‚Z¿ïµ¾ïþw='¿r='¿ïþûµ¾w‚Z¿ïþ¼ý´^ƒl¿ïþóµ>y‚Z¿ïþv='?r='¿ïþ{‚Z?éµ¾ïþó5?ó5¿t='?Ô‹Š>ó5¿ÿÿÿ>?ó5¿Ó‹Š>u='?ó5¿¦÷(²ó5?ó5¿Õ‹Š¾t='?ó5¿¿þÿÿ>ó5¿t='¿Ó‹Š>ó5¿ó5¿™ ;3ó5¿u='¿Ñ‹Š¾ó5¿¿üÿÿ¾ó5¿Ú‹Š¾s='¿ó5¿Ž*гó5¿ó5¿Ô‹Š>t='¿ó5¿?ýÿÿ¾ó5¿v='?Ì‹Š¾ó5¿ïÃ>^ƒl¿õµ>ö>^ƒl¿Õ‹Š>Õ‹Š>^ƒl¿ö>õµ>^ƒl¿–ã¶±ïÃ>^ƒl¿ö¾õµ>^ƒl¿Ö‹Š¾Ô‹Š>^ƒl¿õµ¾ö>^ƒl¿ïþØtÊ2^ƒl¿öµ¾ö¾^ƒl¿×‹Š¾Ó‹Š¾^ƒl¿"ö¾óµ¾^ƒl¿JQa³ïþ^ƒl¿ö>õµ¾^ƒl¿×‹Š>Ӌо^ƒl¿÷µ>ö¾^ƒl¿€¿›²…ýG2€?áJÖ>¸·C9>zmh?e>©Ÿ>zmh?Â>ÆaÊ>zmh?w¸¼áJÖ>zmh?¸C9¾8”Á>zmh?©Ÿ¾e>zmh?ÆaʾŸÂ>zmh?áJÖ¾_¸¼zmh?9”Á¾´C9¾zmh?e¾©Ÿ¾zmh?¦Â¾Äaʾzmh?T¸<áJÖ¾zmh?¸C9>8”Á¾zmh?©Ÿ>e¾zmh?ÇaÊ>™Â¾zmh?Èà4?(ð<6%5?‡6&?WÄŽ>6%5?°|ü>ƒŽ?5%5?õ†>Ž(?6%5?ùï¼Èà4?6%5?WÄŽ¾‡6&?6%5?„Ž¿­|ü>5%5?Ž(¿õ†>6%5?Èà4¿€ï¼6%5?ˆ6&¿QÄŽ¾6%5?°|ü¾Ž¿7%5?û†¾(¿6%5?jï<Èà4¿5%5?VÄŽ>‡6&¿6%5?„Ž?¬|ü¾5%5?(?ñ†¾5%5?µul?. ;è,Ä>CûY?rJ·>é,Ä>EQ&?S(?é,Ä>ª²>tðZ?è,Ä>õ- »µul?è,Ä>rJ·¾AûY?è,Ä>R(¿DQ&?è,Ä>tðZ¿‹ª²>é,Ä>µul¿.- »è,Ä>CûY¿kJ·¾è,Ä>GQ&¿P(¿ë,Ä>“ª²¾rðZ¿é,Ä>©, ;µul¿è,Ä>rJ·>CûY¿é,Ä>U(?CQ&¿é,Ä>tðZ?‡ª²¾è,Ä>€?¨24 !›2^ƒl?ïÃ>mJ1±ô5?ó5?!!›²ïÃ>_ƒl?mJ1³€?mJ±2ïþ^ƒl?mJ1±ô5¿ó5?¼sDz_ƒl¿ïÃ>€¿ Ý2»sÇ2_ƒl¿ïþmJ±1ö5¿ñ5¿ !›²ïþ^ƒl¿WÆó³€¿mJ±2ïÃ>^ƒl¿mJ1±ö5?ò5¿Ó÷„²`ƒl?ïþnJ1±´ul?ö, »ê,ľrðZ?Žª²>ì,ľS(?EQ&?ë,ľqJ·>AûY?ë,ľ®- ;µul?ì,Ä¾Žª²¾rðZ?ì,ľEQ&¿Q(?ë,ľAûY¿rJ·>ì,ľµul¿N. ;ì,ľtðZ¿ˆª²¾ë,ľT(¿CQ&¿ë,ľuJ·¾@ûY¿ë,ľã. »µul¿ì,Ä¾Žª²>rðZ¿ì,ľFQ&?P(¿ë,ľCûY?jJ·¾ì,ľÈà4?sï¼6%5¿Ž(?÷†>6%5¿ƒŽ?¯|ü>6%5¿UÄŽ>‡6&?6%5¿Ÿï<Èà4?6%5¿÷†¾Ž(?6%5¿°|ü¾Ž?6%5¿‡6&¿UÄŽ>6%5¿Èà4¿ð<6%5¿Ž(¿ó†¾6%5¿„Ž¿¨|ü¾6%5¿YÄŽ¾†6&¿6%5¿7ð¼Èà4¿6%5¿÷†>Ž(¿6%5¿°|ü>Ž¿6%5¿ˆ6&?QÄŽ¾6%5¿ãJÖ>W¸¼zmh¿ÆaÊ> Â>zmh¿©Ÿ>e>zmh¿¸C9>8”Á>zmh¿n¸<áJÖ>zmh¿¡Â¾ÅaÊ>zmh¿e¾©Ÿ>zmh¿:”Á¾·C9>zmh¿ãJÖ¾¸Çaʾzmh¿e>©Ÿ¾zmh¿;”Á>³C9¾zmh¿¬èC±±€2€¿€=>@>€> >À>à>?? ?0?@?P?`?p?€?>€=>>>@>>€>> >>À>>à>>?>?> ?>0?>@?>P?>`?>p?>€?>€>€=€>>€>@>€>€>€> >€>À>€>à>€>?€>?€> ?€>0?€>@?€>P?€>`?€>p?€>€?€>À>€=À>>À>@>À>€>À> >À>À>À>à>À>?À>?À> ?À>0?À>@?À>P?À>`?À>p?À>€?À>?€=?>?@>?€>? >?À>?à>????? ??0??@??P??`??p??€?? ?€= ?> ?@> ?€> ? > ?À> ?à> ?? ?? ? ? ?0? ?@? ?P? ?`? ?p? ?€? ?@?€=@?>@?@>@?€>@? >@?À>@?à>@??@??@? ?@?0?@?@?@?P?@?`?@?p?@?€?@?`?€=`?>`?@>`?€>`? >`?À>`?à>`??`??`? ?`?0?`?@?`?P?`?`?`?p?`?€?`?€?€=€?>€?@>€?€>€? >€?À>€?à>€??€??€? ?€?0?€?@?€?P?€?`?€?p?€?€?€?Èðh®¶ `¥©Ãìqð1OP£&Ú`í[¹>¨- ±9…*¹¼D€”W·ÑNÕSE«†D,Ř¡â³D&Où.Ð’Ä)8ìUâï¢g> r,Ä¡‡Ž .\1ó€˜O¿'aÍEóìAÔY 3®%ý§]¬”ö<¢/’|B—0ˆ?%Ú•²®<¤Ì3S MU²›¹µ^F!ïYï[Û4ävAŠ´ÍkËÒäeŸu¿åŸ08râ¾xÂìSn ÈJVȬ¡„˜…ß̬³Íç­TÖ ˆûÉ´–eq#î»’bpOðVà®p†ÔÛÍ* þ±íl ’`ÿ›5ðòdN–ë'ëd³‰MPòÀ>Ûg†èènd™ÃHÚ‚+²jë gæŽÄÝåÞ!”’Yæe^¯j…ìÿÞê(àØ§”!äégQ˜JÕE6EÙ[øpR6d›ÕÏ0£jìÏKÒá(T ¤ÏÞ‘ ÷.ñÆÑqw‹W8F²-{hº_Sx T´BôxE™B}ó„Å—²ã´¾þž|^Õárt-°+ Y¾ÿŠYà(à9ÄM€WÂô…)ÁôrmÆQ'JÉãª_([3Â!®ÙazõëBoR““Ÿ‚‡(§Š®™q ïHsš‰˜ô?‚:]0¡È‡?kK|§ÎÎð«M6ÔOˆÄ8˜Äs´Ûkä_\ˆP®&^‰âÈV§¦üíÿ(K;öņM¸fx³˜†h°e[.¡hµI^L•bÛDÅú-3fz¢Øü©¾žy BVj™O~˦.<ãöQT=9âbõЧ÷ù™þ¿²¬ïݳ8Þ‘?KUë›õ…þUƒ°?@°3¬65¨Ê@F|f ˆ1UÉŽ\ö_ÖL°ÌÖ³{‹mœSlÄùeF9oƒ†³\äëŽõ}"n¯¶øîçž ×-!s_L)4/I=Í=×ÖšZ°òzô$^½yàÓ<|Û¾Øäyç`Æ7îÂÓÑYÎK/Å3gK„á_ƒ‰A|ž ÂR ü¾ÿ €·Œ‡ê}Ç?Ë‚X_`ö"£ÁÀò[ŽHO“"”Ž8èI›owšc‰¨·Uº½õHVº!¡«Uw~×<Ýl7_oûž}UG’)%àÞŠa?sôš2B5ÂpVŒpÞ,}‹Àv&ENqîúÖ½<_ùúc’í«6›ç‘êÆ³A¯gâµrHÐÆ]8ð …Û…@×”¡…"(ÝßÂmª_ÝY×_–ÎÏüøJ¯é¹àRA‹“ˆ#–ïø;l¹¯^ÿÓKV&œy7ðC;wžåefo®Þ€§^âNïþÝ€0ŸÃÕJñÀÑÎâÄ.ZIʸŸCV³«?½”ª«_l2-h[fî8ý×È[MÓ±È+lð%ÜcÌbôk6aØ.…ùE»¾Räi ßÜ5¸iΆúÊ¡Ÿ@KŠž…é ÌØhñWÎHig«¥šk*Ñ?êRç«/@^egÖ«å“U$ƦJ~æí¹(ˆ·š6CH½MÖ4”m _Öß›Ms åy‡ïÊ„À3îH@#²µ¹"[ª;ÓÇF¹:Å5ÖÚÞ=¢ Ÿy›xî]O‚·Ë£]àu–οØ^Ó¦öˆ ù‚"*Ö‹ÚZA¸h–æ5UY3|è%Ì.Âì_…l¾/oBµü6åû5 î?T­ÆÞ?"Ô€õÚ[&zÀÇ|ºô(#¼5¶\àa•àúï{ËéT5½ƒ²ëÊ0©ÿ7˜ÄœðԂ c “ ÙÆ²ù§/GQ,*Pcç¬Ør³®ýÈzl%”ch-owJƆxʃw†¾:k£ç×Ð"óÌ.0G& îm“ZqÓ'|àpÞÖVL(ȘÞÿÝÄŽŽÆNþÿ¶Š²Ì‘âs~êÒ.«ò¿QWÁÔfRýß@Fh‹üoXŽñ)ÌÃþ7£VH^„ÿ;ÈÎÚª;ïÿƒk4öÿyw$]ëùÿþˆ†ÈI¿;ÿÿÿRobject40àrr™€?ïÃ>^ƒl?ôµ>ö>^ƒl?Ô‹Š>Õ‹Š>^ƒl?ö>ôµ>^ƒl?•ã¶±ïÃ>^ƒl?ö¾ôµ>^ƒl?Õ‹Š¾Ô‹Š>^ƒl?ôµ¾ö>^ƒl?ïþ×tÊ2^ƒl?õµ¾ö¾^ƒl?Ö‹Š¾Ò‹Š¾^ƒl?!ö¾òµ¾^ƒl?IQa³ïþ^ƒl?ö>ôµ¾^ƒl?Ö‹Š>Ӌо^ƒl?öµ>ö¾^ƒl?ó5?ó5?t='?Ô‹Š>ó5?ÿÿÿ>?ó5?Ó‹Š>u='?ó5?¦÷(²ó5?ó5?Ջоt='?ó5?¿þÿÿ>ó5?t='¿Ó‹Š>ó5?ó5¿™ ;3ó5?u='¿Ñ‹Š¾ó5?¿üÿÿ¾ó5?Ú‹Š¾s='¿ó5?Ž*гó5¿ó5?Ô‹Š>t='¿ó5??ýÿÿ¾ó5?v='?Ì‹Š¾ó5?^ƒl?ïÃ>y‚Z?óµ>ïÃ>t='?t='?ïÃ>òµ>y‚Z?ïÃ>:Ä\²^ƒl?ïÃ>ôµ¾y‚Z?ïÃ>u='¿s='?ïÃ>y‚Z¿òµ>ïÃ>^ƒl¿ðbt3ïÃ>z‚Z¿ïµ¾ïÃ>w='¿r='¿ïÃ>ûµ¾w‚Z¿ïÃ>¼ý´^ƒl¿ïÃ>óµ>y‚Z¿ïÃ>v='?r='¿ïÃ>{‚Z?éµ¾ïÃ>€?.½;³^ƒl?ïÃ>.½;³ó5?ó5?.½;³ïÃ>_ƒl?.½;³ºôn²€?.½;³ïþ^ƒl?.½;³ô5¿ò5?.½;³_ƒl¿ïÃ>.½;³€¿ÒB„3.½;³_ƒl¿ïþ.½;³ö5¿ñ5¿.½;³ïþ]ƒl¿.½;³2´€¿.½;³ïÃ>^ƒl¿.½;³õ5?ñ5¿.½;³aƒl? ïþ.½;³^ƒl?ïþy‚Z?óµ>ïþt='?t='?ïþòµ>y‚Z?ïþ:Ä\²^ƒl?ïþôµ¾y‚Z?ïþu='¿s='?ïþy‚Z¿òµ>ïþ^ƒl¿ðbt3ïþz‚Z¿ïµ¾ïþw='¿r='¿ïþûµ¾w‚Z¿ïþ¼ý´^ƒl¿ïþóµ>y‚Z¿ïþv='?r='¿ïþ{‚Z?éµ¾ïþó5?ó5¿t='?Ô‹Š>ó5¿ÿÿÿ>?ó5¿Ó‹Š>u='?ó5¿¦÷(²ó5?ó5¿Õ‹Š¾t='?ó5¿¿þÿÿ>ó5¿t='¿Ó‹Š>ó5¿ó5¿™ ;3ó5¿u='¿Ñ‹Š¾ó5¿¿üÿÿ¾ó5¿Ú‹Š¾s='¿ó5¿Ž*гó5¿ó5¿Ô‹Š>t='¿ó5¿?ýÿÿ¾ó5¿v='?Ì‹Š¾ó5¿ïÃ>^ƒl¿õµ>ö>^ƒl¿Õ‹Š>Õ‹Š>^ƒl¿ö>õµ>^ƒl¿–ã¶±ïÃ>^ƒl¿ö¾õµ>^ƒl¿Ö‹Š¾Ô‹Š>^ƒl¿õµ¾ö>^ƒl¿ïþØtÊ2^ƒl¿öµ¾ö¾^ƒl¿×‹Š¾Ó‹Š¾^ƒl¿"ö¾óµ¾^ƒl¿JQa³ïþ^ƒl¿ö>õµ¾^ƒl¿×‹Š>Ӌо^ƒl¿÷µ>ö¾^ƒl¿€¿›²…ýG2€?áJÖ>¸·C9>zmh?e>©Ÿ>zmh?Â>ÆaÊ>zmh?w¸¼áJÖ>zmh?¸C9¾8”Á>zmh?©Ÿ¾e>zmh?ÆaʾŸÂ>zmh?áJÖ¾_¸¼zmh?9”Á¾´C9¾zmh?e¾©Ÿ¾zmh?¦Â¾Äaʾzmh?T¸<áJÖ¾zmh?¸C9>8”Á¾zmh?©Ÿ>e¾zmh?ÇaÊ>™Â¾zmh?Èà4?(ð<6%5?‡6&?WÄŽ>6%5?°|ü>ƒŽ?5%5?õ†>Ž(?6%5?ùï¼Èà4?6%5?WÄŽ¾‡6&?6%5?„Ž¿­|ü>5%5?Ž(¿õ†>6%5?Èà4¿€ï¼6%5?ˆ6&¿QÄŽ¾6%5?°|ü¾Ž¿7%5?û†¾(¿6%5?jï<Èà4¿5%5?VÄŽ>‡6&¿6%5?„Ž?¬|ü¾5%5?(?ñ†¾5%5?µul?. ;è,Ä>CûY?rJ·>é,Ä>EQ&?S(?é,Ä>ª²>tðZ?è,Ä>õ- »µul?è,Ä>rJ·¾AûY?è,Ä>R(¿DQ&?è,Ä>tðZ¿‹ª²>é,Ä>µul¿.- »è,Ä>CûY¿kJ·¾è,Ä>GQ&¿P(¿ë,Ä>“ª²¾rðZ¿é,Ä>©, ;µul¿è,Ä>rJ·>CûY¿é,Ä>U(?CQ&¿é,Ä>tðZ?‡ª²¾è,Ä>€?¨24 !›2^ƒl?ïÃ>mJ1±ô5?ó5?!!›²ïÃ>_ƒl?mJ1³€?mJ±2ïþ^ƒl?mJ1±ô5¿ó5?¼sDz_ƒl¿ïÃ>€¿ Ý2»sÇ2_ƒl¿ïþmJ±1ö5¿ñ5¿ !›²ïþ^ƒl¿WÆó³€¿mJ±2ïÃ>^ƒl¿mJ1±ö5?ò5¿Ó÷„²`ƒl?ïþnJ1±´ul?ö, »ê,ľrðZ?Žª²>ì,ľS(?EQ&?ë,ľqJ·>AûY?ë,ľ®- ;µul?ì,Ä¾Žª²¾rðZ?ì,ľEQ&¿Q(?ë,ľAûY¿rJ·>ì,ľµul¿N. ;ì,ľtðZ¿ˆª²¾ë,ľT(¿CQ&¿ë,ľuJ·¾@ûY¿ë,ľã. »µul¿ì,Ä¾Žª²>rðZ¿ì,ľFQ&?P(¿ë,ľCûY?jJ·¾ì,ľÈà4?sï¼6%5¿Ž(?÷†>6%5¿ƒŽ?¯|ü>6%5¿UÄŽ>‡6&?6%5¿Ÿï<Èà4?6%5¿÷†¾Ž(?6%5¿°|ü¾Ž?6%5¿‡6&¿UÄŽ>6%5¿Èà4¿ð<6%5¿Ž(¿ó†¾6%5¿„Ž¿¨|ü¾6%5¿YÄŽ¾†6&¿6%5¿7ð¼Èà4¿6%5¿÷†>Ž(¿6%5¿°|ü>Ž¿6%5¿ˆ6&?QÄŽ¾6%5¿ãJÖ>W¸¼zmh¿ÆaÊ> Â>zmh¿©Ÿ>e>zmh¿¸C9>8”Á>zmh¿n¸<áJÖ>zmh¿¡Â¾ÅaÊ>zmh¿e¾©Ÿ>zmh¿:”Á¾·C9>zmh¿ãJÖ¾¸Çaʾzmh¿e>©Ÿ¾zmh¿;”Á>³C9¾zmh¿¬èC±±€2€¿ €= > @>€>  >À> à> ?? ?0? @? P?`?p?€? > €=>>>@>>€>>  >> À>>à>>/?>?> ?> 0?>@?>P?>`?> p?> €?>€>€=€>>€> @>€> €>€> >€>À>€>à>€> ?€> ?€> ?€>0?€>@?€> P?€> `?€>p?€>€?€>À> €=À> >À>@>À>€>À> >À> À>À> à>À>?À>?À> ?À> 0?À> @?À>P?À> `?À>p?À> €?À> ?€=?">?@>? €>?  >?À>?$à>??? ?? ??0??&@??P?? `?? p??€??( ?€= ? > ? @> ?€> ?* > ?À> ? à> ? ? ?? ?, ? ?0? ? @? ? P? ?`? ?.p? ?€? ? @? €=@?>@?O@>@?€>@?  >@? À>@?à>@?2?@??@? ?@? 0?@?@?@?4P?@?`?@? p?@? €?@?`?6€=`?>`? @>`? €>`? >`?8À>`?à>`? ?`? ?`? ?`?:0?`?@?`? P?`? `?`?p?`?<€?`?€? €=€? >€?@>€?>€>€? >€? À>€? à>€??€?@?€? ?€? 0?€? @?€?P?€?B`?€?p?€? €?€? Èðh®¶ `¥©Ãìqð1OP£&Ú`í[¹>¨- ±9…*¹¼D€”W·ÑNÕSE«†D,Ř¡â³D&Où.Ð’Ä)8ìUâï¢g> r,Ä¡‡Ž .\1ó€˜O¿'aÍEóìAÔY 3®%ý§]¬”ö<¢/’|B—0ˆ?%Ú•²®<¤Ì3S MU²›¹µ^F!ïYï[Û4ävAŠ´ÍkËÒäeŸu¿åŸ08râ¾xÂìSn ÈJVȬ¡„˜…ß̬³Íç­TÖ ˆûÉ´–eq#î»’bpOðVà®p†ÔÛÍ* þ±íl ’`ÿ›5ðòdN–ë'ëd³‰MPòÀ>Ûg†èènd™ÃHÚ‚+²jë gæŽÄÝåÞ!”’Yæe^¯j…ìÿÞê(àØ§”!äégQ˜JÕE6EÙ[øpR6d›ÕÏ0£jìÏKÒá(T ¤ÏÞ‘ ÷.ñÆÑqw‹W8F²-{hº_Sx T´BôxE™B}ó„Å—²ã´¾þž|^Õárt-°+ Y¾ÿŠYà(à9ÄM€WÂô…)ÁôrmÆQ'JÉãª_([3Â!®ÙazõëBoR““Ÿ‚‡(§Š®™q ïHsš‰˜ô?‚:]0¡È‡?kK|§ÎÎð«M6ÔOˆÄ8˜Äs´Ûkä_\ˆP®&^‰âÈV§¦üíÿ(K;öņM¸fx³˜†h°e[.¡hµI^L•bÛDÅú-3fz¢Øü©¾žy BVj™O~˦.<ãöQT=9âbõЧ÷ù™þ¿²¬ïݳ8Þ‘?KUë›õ…þUƒ°?@°3¬65¨Ê@F|f ˆ1UÉŽ\ö_ÖL°ÌÖ³{‹mœSlÄùeF9oƒ†³\äëŽõ}"n¯¶øîçž ×-!s_L)4/I=Í=×ÖšZ°òzô$^½yàÓ<|Û¾Øäyç`Æ7îÂÓÑYÎK/Å3gK„á_ƒ‰A|ž ÂR ü¾ÿ €·Œ‡ê}Ç?Ë‚X_`ö"£ÁÀò[ŽHO“"”Ž8èI›owšc‰¨·Uº½õHVº!¡«Uw~×<Ýl7_oûž}UG’)%àÞŠa?sôš2B5ÂpVŒpÞ,}‹Àv&ENqîúÖ½<_ùúc’í«6›ç‘êÆ³A¯gâµrHÐÆ]8ð …Û…@×”¡…"(ÝßÂmª_ÝY×_–ÎÏüøJ¯é¹àRA‹“ˆ#–ïø;l¹¯^ÿÓKV&œy7ðC;wžåefo®Þ€§^âNïþÝ€0ŸÃÕJñÀÑÎâÄ.ZIʸŸCV³«?½”ª«_l2-h[fî8ý×È[MÓ±È+lð%ÜcÌbôk6aØ.…ùE»¾Räi ßÜ5¸iΆúÊ¡Ÿ@KŠž…é ÌØhñWÎHig«¥šk*Ñ?êRç«/@^egÖ«å“U$ƦJ~æí¹(ˆ·š6CH½MÖ4”m _Öß›Ms åy‡ïÊ„À3îH@#²µ¹"[ª;ÓÇF¹:Å5ÖÚÞ=¢ Ÿy›xî]O‚·Ë£]àu–οØ^Ó¦öˆ ù‚"*Ö‹ÚZA¸h–æ5UY3|è%Ì.Âì_…l¾/oBµü6åû5 î?T­ÆÞ?"Ô€õÚ[&zÀÇ|ºô(#¼5¶\àa•àúï{ËéT5½ƒ²ëÊ0©ÿ7˜ÄœðԂ c “ ÙÆ²ù§/GQ,*Pcç¬Ør³®ýÈzl%”ch-owJƆxʃw†¾:k£ç×Ð"óÌ.0G& îm“ZqÓ'|àpÞÖVL(ȘÞÿÝÄŽŽÆNþÿ¶Š²Ì‘âs~êÒ.«ò¿QWÁÔfRýß@Fh‹üoXŽñ)ÌÃþ7£VH^„ÿ;ÈÎÚª;ïÿƒk4öÿyw$]ëùÿþˆ†ÈI¿;ÿÿÿRobject38àrr™€?ïÃ>^ƒl?ôµ>ö>^ƒl?Ô‹Š>Õ‹Š>^ƒl?ö>ôµ>^ƒl?•ã¶±ïÃ>^ƒl?ö¾ôµ>^ƒl?Õ‹Š¾Ô‹Š>^ƒl?ôµ¾ö>^ƒl?ïþ×tÊ2^ƒl?õµ¾ö¾^ƒl?Ö‹Š¾Ò‹Š¾^ƒl?!ö¾òµ¾^ƒl?IQa³ïþ^ƒl?ö>ôµ¾^ƒl?Ö‹Š>Ӌо^ƒl?öµ>ö¾^ƒl?ó5?ó5?t='?Ô‹Š>ó5?ÿÿÿ>?ó5?Ó‹Š>u='?ó5?¦÷(²ó5?ó5?Ջоt='?ó5?¿þÿÿ>ó5?t='¿Ó‹Š>ó5?ó5¿™ ;3ó5?u='¿Ñ‹Š¾ó5?¿üÿÿ¾ó5?Ú‹Š¾s='¿ó5?Ž*гó5¿ó5?Ô‹Š>t='¿ó5??ýÿÿ¾ó5?v='?Ì‹Š¾ó5?^ƒl?ïÃ>y‚Z?óµ>ïÃ>t='?t='?ïÃ>òµ>y‚Z?ïÃ>:Ä\²^ƒl?ïÃ>ôµ¾y‚Z?ïÃ>u='¿s='?ïÃ>y‚Z¿òµ>ïÃ>^ƒl¿ðbt3ïÃ>z‚Z¿ïµ¾ïÃ>w='¿r='¿ïÃ>ûµ¾w‚Z¿ïÃ>¼ý´^ƒl¿ïÃ>óµ>y‚Z¿ïÃ>v='?r='¿ïÃ>{‚Z?éµ¾ïÃ>€?.½;³^ƒl?ïÃ>.½;³ó5?ó5?.½;³ïÃ>_ƒl?.½;³ºôn²€?.½;³ïþ^ƒl?.½;³ô5¿ò5?.½;³_ƒl¿ïÃ>.½;³€¿ÒB„3.½;³_ƒl¿ïþ.½;³ö5¿ñ5¿.½;³ïþ]ƒl¿.½;³2´€¿.½;³ïÃ>^ƒl¿.½;³õ5?ñ5¿.½;³aƒl? ïþ.½;³^ƒl?ïþy‚Z?óµ>ïþt='?t='?ïþòµ>y‚Z?ïþ:Ä\²^ƒl?ïþôµ¾y‚Z?ïþu='¿s='?ïþy‚Z¿òµ>ïþ^ƒl¿ðbt3ïþz‚Z¿ïµ¾ïþw='¿r='¿ïþûµ¾w‚Z¿ïþ¼ý´^ƒl¿ïþóµ>y‚Z¿ïþv='?r='¿ïþ{‚Z?éµ¾ïþó5?ó5¿t='?Ô‹Š>ó5¿ÿÿÿ>?ó5¿Ó‹Š>u='?ó5¿¦÷(²ó5?ó5¿Õ‹Š¾t='?ó5¿¿þÿÿ>ó5¿t='¿Ó‹Š>ó5¿ó5¿™ ;3ó5¿u='¿Ñ‹Š¾ó5¿¿üÿÿ¾ó5¿Ú‹Š¾s='¿ó5¿Ž*гó5¿ó5¿Ô‹Š>t='¿ó5¿?ýÿÿ¾ó5¿v='?Ì‹Š¾ó5¿ïÃ>^ƒl¿õµ>ö>^ƒl¿Õ‹Š>Õ‹Š>^ƒl¿ö>õµ>^ƒl¿–ã¶±ïÃ>^ƒl¿ö¾õµ>^ƒl¿Ö‹Š¾Ô‹Š>^ƒl¿õµ¾ö>^ƒl¿ïþØtÊ2^ƒl¿öµ¾ö¾^ƒl¿×‹Š¾Ó‹Š¾^ƒl¿"ö¾óµ¾^ƒl¿JQa³ïþ^ƒl¿ö>õµ¾^ƒl¿×‹Š>Ӌо^ƒl¿÷µ>ö¾^ƒl¿€¿›²…ýG2€?áJÖ>¸·C9>zmh?e>©Ÿ>zmh?Â>ÆaÊ>zmh?w¸¼áJÖ>zmh?¸C9¾8”Á>zmh?©Ÿ¾e>zmh?ÆaʾŸÂ>zmh?áJÖ¾_¸¼zmh?9”Á¾´C9¾zmh?e¾©Ÿ¾zmh?¦Â¾Äaʾzmh?T¸<áJÖ¾zmh?¸C9>8”Á¾zmh?©Ÿ>e¾zmh?ÇaÊ>™Â¾zmh?Èà4?(ð<6%5?‡6&?WÄŽ>6%5?°|ü>ƒŽ?5%5?õ†>Ž(?6%5?ùï¼Èà4?6%5?WÄŽ¾‡6&?6%5?„Ž¿­|ü>5%5?Ž(¿õ†>6%5?Èà4¿€ï¼6%5?ˆ6&¿QÄŽ¾6%5?°|ü¾Ž¿7%5?û†¾(¿6%5?jï<Èà4¿5%5?VÄŽ>‡6&¿6%5?„Ž?¬|ü¾5%5?(?ñ†¾5%5?µul?. ;è,Ä>CûY?rJ·>é,Ä>EQ&?S(?é,Ä>ª²>tðZ?è,Ä>õ- »µul?è,Ä>rJ·¾AûY?è,Ä>R(¿DQ&?è,Ä>tðZ¿‹ª²>é,Ä>µul¿.- »è,Ä>CûY¿kJ·¾è,Ä>GQ&¿P(¿ë,Ä>“ª²¾rðZ¿é,Ä>©, ;µul¿è,Ä>rJ·>CûY¿é,Ä>U(?CQ&¿é,Ä>tðZ?‡ª²¾è,Ä>€?¨24 !›2^ƒl?ïÃ>mJ1±ô5?ó5?!!›²ïÃ>_ƒl?mJ1³€?mJ±2ïþ^ƒl?mJ1±ô5¿ó5?¼sDz_ƒl¿ïÃ>€¿ Ý2»sÇ2_ƒl¿ïþmJ±1ö5¿ñ5¿ !›²ïþ^ƒl¿WÆó³€¿mJ±2ïÃ>^ƒl¿mJ1±ö5?ò5¿Ó÷„²`ƒl?ïþnJ1±´ul?ö, »ê,ľrðZ?Žª²>ì,ľS(?EQ&?ë,ľqJ·>AûY?ë,ľ®- ;µul?ì,Ä¾Žª²¾rðZ?ì,ľEQ&¿Q(?ë,ľAûY¿rJ·>ì,ľµul¿N. ;ì,ľtðZ¿ˆª²¾ë,ľT(¿CQ&¿ë,ľuJ·¾@ûY¿ë,ľã. »µul¿ì,Ä¾Žª²>rðZ¿ì,ľFQ&?P(¿ë,ľCûY?jJ·¾ì,ľÈà4?sï¼6%5¿Ž(?÷†>6%5¿ƒŽ?¯|ü>6%5¿UÄŽ>‡6&?6%5¿Ÿï<Èà4?6%5¿÷†¾Ž(?6%5¿°|ü¾Ž?6%5¿‡6&¿UÄŽ>6%5¿Èà4¿ð<6%5¿Ž(¿ó†¾6%5¿„Ž¿¨|ü¾6%5¿YÄŽ¾†6&¿6%5¿7ð¼Èà4¿6%5¿÷†>Ž(¿6%5¿°|ü>Ž¿6%5¿ˆ6&?QÄŽ¾6%5¿ãJÖ>W¸¼zmh¿ÆaÊ> Â>zmh¿©Ÿ>e>zmh¿¸C9>8”Á>zmh¿n¸<áJÖ>zmh¿¡Â¾ÅaÊ>zmh¿e¾©Ÿ>zmh¿:”Á¾·C9>zmh¿ãJÖ¾¸Çaʾzmh¿e>©Ÿ¾zmh¿;”Á>³C9¾zmh¿¬èC±±€2€¿i€=Z>Z@>k€>\ >\À>mà>^?^?o ?`0?`@?bP?b`?qp?f€?f>q€=>j>>j@>>q€>>n >>nÀ>>qà>> ?>?> ?>$øô 0?>@?>P?>`?>p?>$øô €?>€>€=€>>€>@>€>$øô €>€> >€>À>€>à>€>?€>$øô ?€> ?€>0?€>@?€>P?€>$øô `?€>p?€>€?€>À>€=À>$øô >À>@>À>€>À> >À>À>À>$øô à>À>?À>?À> ?À>0?À>$øô @?À>P?À>`?À>p?À>€?À>$øô ?€=?>?@>?€>?$øô  >?À>?à>?????$øô ??0??@??P??`??$øô p??€?? ?€= ?> ?$øô @> ?€> ? > ?À> ?à> ?$øô ? ?? ? ? ?0? ?@? ?$øô P? ?`? ?p? ?€? ?@?$øô €=@?>@?@>@?€>@? >@?$øô À>@?à>@??@??@? ?@?$øô 0?@?@?@?P?@?`?@?p?@?$øô €?@?`?€=`?>`?@>`?$øô €>`? >`?À>`?à>`??`?$øô ?`? ?`?0?`?@?`?P?`?$øô `?`?p?`?€?`?€?€=€?$øô >€?@>€?€>€? >€?À>€?$øô à>€??€??€? ?€?0?€?$øô @?€?P?€?`?€?p?€?€?€?$øô Èðh®¶ `¥©Ãìqð1OP£&Ú`í[¹>¨- ±9…*¹¼D€”W·ÑNÕSE«†D,Ř¡â³D&Où.Ð’Ä)8ìUâï¢g> r,Ä¡‡Ž .\1ó€˜O¿'aÍEóìAÔY 3®%ý§]¬”ö<¢/’|B—0ˆ?%Ú•²®<¤Ì3S MU²›¹µ^F!ïYï[Û4ävAŠ´ÍkËÒäeŸu¿åŸ08râ¾xÂìSn ÈJVȬ¡„˜…ß̬³Íç­TÖ ˆûÉ´–eq#î»’bpOðVà®p†ÔÛÍ* þ±íl ’`ÿ›5ðòdN–ë'ëd³‰MPòÀ>Ûg†èènd™ÃHÚ‚+²jë gæŽÄÝåÞ!”’Yæe^¯j…ìÿÞê(àØ§”!äégQ˜JÕE6EÙ[øpR6d›ÕÏ0£jìÏKÒá(T ¤ÏÞ‘ ÷.ñÆÑqw‹W8F²-{hº_Sx T´BôxE™B}ó„Å—²ã´¾þž|^Õárt-°+ Y¾ÿŠYà(à9ÄM€WÂô…)ÁôrmÆQ'JÉãª_([3Â!®ÙazõëBoR““Ÿ‚‡(§Š®™q ïHsš‰˜ô?‚:]0¡È‡?kK|§ÎÎð«M6ÔOˆÄ8˜Äs´Ûkä_\ˆP®&^‰âÈV§¦üíÿ(K;öņM¸fx³˜†h°e[.¡hµI^L•bÛDÅú-3fz¢Øü©¾žy BVj™O~˦.<ãöQT=9âbõЧ÷ù™þ¿²¬ïݳ8Þ‘?KUë›õ…þUƒ°?@°3¬65¨Ê@F|f ˆ1UÉŽ\ö_ÖL°ÌÖ³{‹mœSlÄùeF9oƒ†³\äëŽõ}"n¯¶øîçž ×-!s_L)4/I=Í=×ÖšZ°òzô$^½yàÓ<|Û¾Øäyç`Æ7îÂÓÑYÎK/Å3gK„á_ƒ‰A|ž ÂR ü¾ÿ €·Œ‡ê}Ç?Ë‚X_`ö"£ÁÀò[ŽHO“"”Ž8èI›owšc‰¨·Uº½õHVº!¡«Uw~×<Ýl7_oûž}UG’)%àÞŠa?sôš2B5ÂpVŒpÞ,}‹Àv&ENqîúÖ½<_ùúc’í«6›ç‘êÆ³A¯gâµrHÐÆ]8ð …Û…@×”¡…"(ÝßÂmª_ÝY×_–ÎÏüøJ¯é¹àRA‹“ˆ#–ïø;l¹¯^ÿÓKV&œy7ðC;wžåefo®Þ€§^âNïþÝ€0ŸÃÕJñÀÑÎâÄ.ZIʸŸCV³«?½”ª«_l2-h[fî8ý×È[MÓ±È+lð%ÜcÌbôk6aØ.…ùE»¾Räi ßÜ5¸iΆúÊ¡Ÿ@KŠž…é ÌØhñWÎHig«¥šk*Ñ?êRç«/@^egÖ«å“U$ƦJ~æí¹(ˆ·š6CH½MÖ4”m _Öß›Ms åy‡ïÊ„À3îH@#²µ¹"[ª;ÓÇF¹:Å5ÖÚÞ=¢ Ÿy›xî]O‚·Ë£]àu–οØ^Ó¦öˆ ù‚"*Ö‹ÚZA¸h–æ5UY3|è%Ì.Âì_…l¾/oBµü6åû5 î?T­ÆÞ?"Ô€õÚ[&zÀÇ|ºô(#¼5¶\àa•àúï{ËéT5½ƒ²ëÊ0©ÿ7˜ÄœðԂ c “ ÙÆ²ù§/GQ,*Pcç¬Ør³®ýÈzl%”ch-owJƆxʃw†¾:k£ç×Ð"óÌ.0G& îm“ZqÓ'|àpÞÖVL(ȘÞÿÝÄŽŽÆNþÿ¶Š²Ì‘âs~êÒ.«ò¿QWÁÔfRýß@Fh‹üoXŽñ)ÌÃþ7£VH^„ÿ;ÈÎÚª;ïÿƒk4öÿyw$]ëùÿþˆ†ÈI¿;ÿÿÿRobject36àrr™€?ïÃ>^ƒl?ôµ>ö>^ƒl?Ô‹Š>Õ‹Š>^ƒl?ö>ôµ>^ƒl?•ã¶±ïÃ>^ƒl?ö¾ôµ>^ƒl?Õ‹Š¾Ô‹Š>^ƒl?ôµ¾ö>^ƒl?ïþ×tÊ2^ƒl?õµ¾ö¾^ƒl?Ö‹Š¾Ò‹Š¾^ƒl?!ö¾òµ¾^ƒl?IQa³ïþ^ƒl?ö>ôµ¾^ƒl?Ö‹Š>Ӌо^ƒl?öµ>ö¾^ƒl?ó5?ó5?t='?Ô‹Š>ó5?ÿÿÿ>?ó5?Ó‹Š>u='?ó5?¦÷(²ó5?ó5?Ջоt='?ó5?¿þÿÿ>ó5?t='¿Ó‹Š>ó5?ó5¿™ ;3ó5?u='¿Ñ‹Š¾ó5?¿üÿÿ¾ó5?Ú‹Š¾s='¿ó5?Ž*гó5¿ó5?Ô‹Š>t='¿ó5??ýÿÿ¾ó5?v='?Ì‹Š¾ó5?^ƒl?ïÃ>y‚Z?óµ>ïÃ>t='?t='?ïÃ>òµ>y‚Z?ïÃ>:Ä\²^ƒl?ïÃ>ôµ¾y‚Z?ïÃ>u='¿s='?ïÃ>y‚Z¿òµ>ïÃ>^ƒl¿ðbt3ïÃ>z‚Z¿ïµ¾ïÃ>w='¿r='¿ïÃ>ûµ¾w‚Z¿ïÃ>¼ý´^ƒl¿ïÃ>óµ>y‚Z¿ïÃ>v='?r='¿ïÃ>{‚Z?éµ¾ïÃ>€?.½;³^ƒl?ïÃ>.½;³ó5?ó5?.½;³ïÃ>_ƒl?.½;³ºôn²€?.½;³ïþ^ƒl?.½;³ô5¿ò5?.½;³_ƒl¿ïÃ>.½;³€¿ÒB„3.½;³_ƒl¿ïþ.½;³ö5¿ñ5¿.½;³ïþ]ƒl¿.½;³2´€¿.½;³ïÃ>^ƒl¿.½;³õ5?ñ5¿.½;³aƒl? ïþ.½;³^ƒl?ïþy‚Z?óµ>ïþt='?t='?ïþòµ>y‚Z?ïþ:Ä\²^ƒl?ïþôµ¾y‚Z?ïþu='¿s='?ïþy‚Z¿òµ>ïþ^ƒl¿ðbt3ïþz‚Z¿ïµ¾ïþw='¿r='¿ïþûµ¾w‚Z¿ïþ¼ý´^ƒl¿ïþóµ>y‚Z¿ïþv='?r='¿ïþ{‚Z?éµ¾ïþó5?ó5¿t='?Ô‹Š>ó5¿ÿÿÿ>?ó5¿Ó‹Š>u='?ó5¿¦÷(²ó5?ó5¿Õ‹Š¾t='?ó5¿¿þÿÿ>ó5¿t='¿Ó‹Š>ó5¿ó5¿™ ;3ó5¿u='¿Ñ‹Š¾ó5¿¿üÿÿ¾ó5¿Ú‹Š¾s='¿ó5¿Ž*гó5¿ó5¿Ô‹Š>t='¿ó5¿?ýÿÿ¾ó5¿v='?Ì‹Š¾ó5¿ïÃ>^ƒl¿õµ>ö>^ƒl¿Õ‹Š>Õ‹Š>^ƒl¿ö>õµ>^ƒl¿–ã¶±ïÃ>^ƒl¿ö¾õµ>^ƒl¿Ö‹Š¾Ô‹Š>^ƒl¿õµ¾ö>^ƒl¿ïþØtÊ2^ƒl¿öµ¾ö¾^ƒl¿×‹Š¾Ó‹Š¾^ƒl¿"ö¾óµ¾^ƒl¿JQa³ïþ^ƒl¿ö>õµ¾^ƒl¿×‹Š>Ӌо^ƒl¿÷µ>ö¾^ƒl¿€¿›²…ýG2€?áJÖ>¸·C9>zmh?e>©Ÿ>zmh?Â>ÆaÊ>zmh?w¸¼áJÖ>zmh?¸C9¾8”Á>zmh?©Ÿ¾e>zmh?ÆaʾŸÂ>zmh?áJÖ¾_¸¼zmh?9”Á¾´C9¾zmh?e¾©Ÿ¾zmh?¦Â¾Äaʾzmh?T¸<áJÖ¾zmh?¸C9>8”Á¾zmh?©Ÿ>e¾zmh?ÇaÊ>™Â¾zmh?Èà4?(ð<6%5?‡6&?WÄŽ>6%5?°|ü>ƒŽ?5%5?õ†>Ž(?6%5?ùï¼Èà4?6%5?WÄŽ¾‡6&?6%5?„Ž¿­|ü>5%5?Ž(¿õ†>6%5?Èà4¿€ï¼6%5?ˆ6&¿QÄŽ¾6%5?°|ü¾Ž¿7%5?û†¾(¿6%5?jï<Èà4¿5%5?VÄŽ>‡6&¿6%5?„Ž?¬|ü¾5%5?(?ñ†¾5%5?µul?. ;è,Ä>CûY?rJ·>é,Ä>EQ&?S(?é,Ä>ª²>tðZ?è,Ä>õ- »µul?è,Ä>rJ·¾AûY?è,Ä>R(¿DQ&?è,Ä>tðZ¿‹ª²>é,Ä>µul¿.- »è,Ä>CûY¿kJ·¾è,Ä>GQ&¿P(¿ë,Ä>“ª²¾rðZ¿é,Ä>©, ;µul¿è,Ä>rJ·>CûY¿é,Ä>U(?CQ&¿é,Ä>tðZ?‡ª²¾è,Ä>€?¨24 !›2^ƒl?ïÃ>mJ1±ô5?ó5?!!›²ïÃ>_ƒl?mJ1³€?mJ±2ïþ^ƒl?mJ1±ô5¿ó5?¼sDz_ƒl¿ïÃ>€¿ Ý2»sÇ2_ƒl¿ïþmJ±1ö5¿ñ5¿ !›²ïþ^ƒl¿WÆó³€¿mJ±2ïÃ>^ƒl¿mJ1±ö5?ò5¿Ó÷„²`ƒl?ïþnJ1±´ul?ö, »ê,ľrðZ?Žª²>ì,ľS(?EQ&?ë,ľqJ·>AûY?ë,ľ®- ;µul?ì,Ä¾Žª²¾rðZ?ì,ľEQ&¿Q(?ë,ľAûY¿rJ·>ì,ľµul¿N. ;ì,ľtðZ¿ˆª²¾ë,ľT(¿CQ&¿ë,ľuJ·¾@ûY¿ë,ľã. »µul¿ì,Ä¾Žª²>rðZ¿ì,ľFQ&?P(¿ë,ľCûY?jJ·¾ì,ľÈà4?sï¼6%5¿Ž(?÷†>6%5¿ƒŽ?¯|ü>6%5¿UÄŽ>‡6&?6%5¿Ÿï<Èà4?6%5¿÷†¾Ž(?6%5¿°|ü¾Ž?6%5¿‡6&¿UÄŽ>6%5¿Èà4¿ð<6%5¿Ž(¿ó†¾6%5¿„Ž¿¨|ü¾6%5¿YÄŽ¾†6&¿6%5¿7ð¼Èà4¿6%5¿÷†>Ž(¿6%5¿°|ü>Ž¿6%5¿ˆ6&?QÄŽ¾6%5¿ãJÖ>W¸¼zmh¿ÆaÊ> Â>zmh¿©Ÿ>e>zmh¿¸C9>8”Á>zmh¿n¸<áJÖ>zmh¿¡Â¾ÅaÊ>zmh¿e¾©Ÿ>zmh¿:”Á¾·C9>zmh¿ãJÖ¾¸Çaʾzmh¿e>©Ÿ¾zmh¿;”Á>³C9¾zmh¿¬èC±±€2€¿€=$øô >@>€> >À>$øô à>?? ?0?$øô @?P?`?p?€?$øô >€=>>>@>>€>>$øô  >>À>>à>>?>?>$øô ?>0?>@?>P?>`?>$øô p?>€?>€>€=€>>€>$øô @>€>€>€> >€>À>€>à>€>$øô ?€>?€> ?€>0?€>@?€>$øô P?€>`?€>p?€>€?€>À>$øô €=À>>À>@>À>€>À> >À>hÀ>À>à>À>?À>?À> ?À>0?À>@?À>P?À>`?À>p?À>€?À>?€=?>?@>?€>? >?À>?>à>?>??>??> ??>0??>@??>P??>`??>p??>€??> ?>€= ?>> ?>@> ?>€> ?> > ?>À> ?€>à> ?€>? ?€>? ?€> ? ?€>0? ?€>@? ?€>P? ?€>`? ?€>p? ?€>€? ?€>@?€>€=@?€>>@?€>@>@?€>€>@?€> >@?€>À>@?À>à>@?À>?@?À>?@?À> ?@?À>0?@?À>@?@?À>P?@?À>`?@?À>p?@?À>€?@?À>`?À>€=`?À>>`?À>@>`?À>€>`?À> >`?À>À>`??à>`???`???`?? ?`??0?`??@?`??P?`??`?`??p?`??€?`??€??€=€??>€??@>€??€>€?? >€??À>€? ?à>€? ??€? ??€? ? ?€? ?0?€? ?@?€? ?P?€? ?`?€? ?p?€? ?€?€? ?Èðh®¶ `¥©Ãìqð1OP£&Ú`í[¹>¨- ±9…*¹¼D€”W·ÑNÕSE«†D,Ř¡â³D&Où.Ð’Ä)8ìUâï¢g> r,Ä¡‡Ž .\1ó€˜O¿'aÍEóìAÔY 3®%ý§]¬”ö<¢/’|B—0ˆ?%Ú•²®<¤Ì3S MU²›¹µ^F!ïYï[Û4ävAŠ´ÍkËÒäeŸu¿åŸ08râ¾xÂìSn ÈJVȬ¡„˜…ß̬³Íç­TÖ ˆûÉ´–eq#î»’bpOðVà®p†ÔÛÍ* þ±íl ’`ÿ›5ðòdN–ë'ëd³‰MPòÀ>Ûg†èènd™ÃHÚ‚+²jë gæŽÄÝåÞ!”’Yæe^¯j…ìÿÞê(àØ§”!äégQ˜JÕE6EÙ[øpR6d›ÕÏ0£jìÏKÒá(T ¤ÏÞ‘ ÷.ñÆÑqw‹W8F²-{hº_Sx T´BôxE™B}ó„Å—²ã´¾þž|^Õárt-°+ Y¾ÿŠYà(à9ÄM€WÂô…)ÁôrmÆQ'JÉãª_([3Â!®ÙazõëBoR““Ÿ‚‡(§Š®™q ïHsš‰˜ô?‚:]0¡È‡?kK|§ÎÎð«M6ÔOˆÄ8˜Äs´Ûkä_\ˆP®&^‰âÈV§¦üíÿ(K;öņM¸fx³˜†h°e[.¡hµI^L•bÛDÅú-3fz¢Øü©¾žy BVj™O~˦.<ãöQT=9âbõЧ÷ù™þ¿²¬ïݳ8Þ‘?KUë›õ…þUƒ°?@°3¬65¨Ê@F|f ˆ1UÉŽ\ö_ÖL°ÌÖ³{‹mœSlÄùeF9oƒ†³\äëŽõ}"n¯¶øîçž ×-!s_L)4/I=Í=×ÖšZ°òzô$^½yàÓ<|Û¾Øäyç`Æ7îÂÓÑYÎK/Å3gK„á_ƒ‰A|ž ÂR ü¾ÿ €·Œ‡ê}Ç?Ë‚X_`ö"£ÁÀò[ŽHO“"”Ž8èI›owšc‰¨·Uº½õHVº!¡«Uw~×<Ýl7_oûž}UG’)%àÞŠa?sôš2B5ÂpVŒpÞ,}‹Àv&ENqîúÖ½<_ùúc’í«6›ç‘êÆ³A¯gâµrHÐÆ]8ð …Û…@×”¡…"(ÝßÂmª_ÝY×_–ÎÏüøJ¯é¹àRA‹“ˆ#–ïø;l¹¯^ÿÓKV&œy7ðC;wžåefo®Þ€§^âNïþÝ€0ŸÃÕJñÀÑÎâÄ.ZIʸŸCV³«?½”ª«_l2-h[fî8ý×È[MÓ±È+lð%ÜcÌbôk6aØ.…ùE»¾Räi ßÜ5¸iΆúÊ¡Ÿ@KŠž…é ÌØhñWÎHig«¥šk*Ñ?êRç«/@^egÖ«å“U$ƦJ~æí¹(ˆ·š6CH½MÖ4”m _Öß›Ms åy‡ïÊ„À3îH@#²µ¹"[ª;ÓÇF¹:Å5ÖÚÞ=¢ Ÿy›xî]O‚·Ë£]àu–οØ^Ó¦öˆ ù‚"*Ö‹ÚZA¸h–æ5UY3|è%Ì.Âì_…l¾/oBµü6åû5 î?T­ÆÞ?"Ô€õÚ[&zÀÇ|ºô(#¼5¶\àa•àúï{ËéT5½ƒ²ëÊ0©ÿ7˜ÄœðԂ c “ ÙÆ²ù§/GQ,*Pcç¬Ør³®ýÈzl%”ch-owJƆxʃw†¾:k£ç×Ð"óÌ.0G& îm“ZqÓ'|àpÞÖVL(ȘÞÿÝÄŽŽÆNþÿ¶Š²Ì‘âs~êÒ.«ò¿QWÁÔfRýß@Fh‹üoXŽñ)ÌÃþ7£VH^„ÿ;ÈÎÚª;ïÿƒk4öÿyw$]ëùÿþˆ†ÈI¿;ÿÿÿRobject34àrr™€?ïÃ>^ƒl?ôµ>ö>^ƒl?Ô‹Š>Õ‹Š>^ƒl?ö>ôµ>^ƒl?•ã¶±ïÃ>^ƒl?ö¾ôµ>^ƒl?Õ‹Š¾Ô‹Š>^ƒl?ôµ¾ö>^ƒl?ïþ×tÊ2^ƒl?õµ¾ö¾^ƒl?Ö‹Š¾Ò‹Š¾^ƒl?!ö¾òµ¾^ƒl?IQa³ïþ^ƒl?ö>ôµ¾^ƒl?Ö‹Š>Ӌо^ƒl?öµ>ö¾^ƒl?ó5?ó5?t='?Ô‹Š>ó5?ÿÿÿ>?ó5?Ó‹Š>u='?ó5?¦÷(²ó5?ó5?Ջоt='?ó5?¿þÿÿ>ó5?t='¿Ó‹Š>ó5?ó5¿™ ;3ó5?u='¿Ñ‹Š¾ó5?¿üÿÿ¾ó5?Ú‹Š¾s='¿ó5?Ž*гó5¿ó5?Ô‹Š>t='¿ó5??ýÿÿ¾ó5?v='?Ì‹Š¾ó5?^ƒl?ïÃ>y‚Z?óµ>ïÃ>t='?t='?ïÃ>òµ>y‚Z?ïÃ>:Ä\²^ƒl?ïÃ>ôµ¾y‚Z?ïÃ>u='¿s='?ïÃ>y‚Z¿òµ>ïÃ>^ƒl¿ðbt3ïÃ>z‚Z¿ïµ¾ïÃ>w='¿r='¿ïÃ>ûµ¾w‚Z¿ïÃ>¼ý´^ƒl¿ïÃ>óµ>y‚Z¿ïÃ>v='?r='¿ïÃ>{‚Z?éµ¾ïÃ>€?.½;³^ƒl?ïÃ>.½;³ó5?ó5?.½;³ïÃ>_ƒl?.½;³ºôn²€?.½;³ïþ^ƒl?.½;³ô5¿ò5?.½;³_ƒl¿ïÃ>.½;³€¿ÒB„3.½;³_ƒl¿ïþ.½;³ö5¿ñ5¿.½;³ïþ]ƒl¿.½;³2´€¿.½;³ïÃ>^ƒl¿.½;³õ5?ñ5¿.½;³aƒl? ïþ.½;³^ƒl?ïþy‚Z?óµ>ïþt='?t='?ïþòµ>y‚Z?ïþ:Ä\²^ƒl?ïþôµ¾y‚Z?ïþu='¿s='?ïþy‚Z¿òµ>ïþ^ƒl¿ðbt3ïþz‚Z¿ïµ¾ïþw='¿r='¿ïþûµ¾w‚Z¿ïþ¼ý´^ƒl¿ïþóµ>y‚Z¿ïþv='?r='¿ïþ{‚Z?éµ¾ïþó5?ó5¿t='?Ô‹Š>ó5¿ÿÿÿ>?ó5¿Ó‹Š>u='?ó5¿¦÷(²ó5?ó5¿Õ‹Š¾t='?ó5¿¿þÿÿ>ó5¿t='¿Ó‹Š>ó5¿ó5¿™ ;3ó5¿u='¿Ñ‹Š¾ó5¿¿üÿÿ¾ó5¿Ú‹Š¾s='¿ó5¿Ž*гó5¿ó5¿Ô‹Š>t='¿ó5¿?ýÿÿ¾ó5¿v='?Ì‹Š¾ó5¿ïÃ>^ƒl¿õµ>ö>^ƒl¿Õ‹Š>Õ‹Š>^ƒl¿ö>õµ>^ƒl¿–ã¶±ïÃ>^ƒl¿ö¾õµ>^ƒl¿Ö‹Š¾Ô‹Š>^ƒl¿õµ¾ö>^ƒl¿ïþØtÊ2^ƒl¿öµ¾ö¾^ƒl¿×‹Š¾Ó‹Š¾^ƒl¿"ö¾óµ¾^ƒl¿JQa³ïþ^ƒl¿ö>õµ¾^ƒl¿×‹Š>Ӌо^ƒl¿÷µ>ö¾^ƒl¿€¿›²…ýG2€?áJÖ>¸·C9>zmh?e>©Ÿ>zmh?Â>ÆaÊ>zmh?w¸¼áJÖ>zmh?¸C9¾8”Á>zmh?©Ÿ¾e>zmh?ÆaʾŸÂ>zmh?áJÖ¾_¸¼zmh?9”Á¾´C9¾zmh?e¾©Ÿ¾zmh?¦Â¾Äaʾzmh?T¸<áJÖ¾zmh?¸C9>8”Á¾zmh?©Ÿ>e¾zmh?ÇaÊ>™Â¾zmh?Èà4?(ð<6%5?‡6&?WÄŽ>6%5?°|ü>ƒŽ?5%5?õ†>Ž(?6%5?ùï¼Èà4?6%5?WÄŽ¾‡6&?6%5?„Ž¿­|ü>5%5?Ž(¿õ†>6%5?Èà4¿€ï¼6%5?ˆ6&¿QÄŽ¾6%5?°|ü¾Ž¿7%5?û†¾(¿6%5?jï<Èà4¿5%5?VÄŽ>‡6&¿6%5?„Ž?¬|ü¾5%5?(?ñ†¾5%5?µul?. ;è,Ä>CûY?rJ·>é,Ä>EQ&?S(?é,Ä>ª²>tðZ?è,Ä>õ- »µul?è,Ä>rJ·¾AûY?è,Ä>R(¿DQ&?è,Ä>tðZ¿‹ª²>é,Ä>µul¿.- »è,Ä>CûY¿kJ·¾è,Ä>GQ&¿P(¿ë,Ä>“ª²¾rðZ¿é,Ä>©, ;µul¿è,Ä>rJ·>CûY¿é,Ä>U(?CQ&¿é,Ä>tðZ?‡ª²¾è,Ä>€?¨24 !›2^ƒl?ïÃ>mJ1±ô5?ó5?!!›²ïÃ>_ƒl?mJ1³€?mJ±2ïþ^ƒl?mJ1±ô5¿ó5?¼sDz_ƒl¿ïÃ>€¿ Ý2»sÇ2_ƒl¿ïþmJ±1ö5¿ñ5¿ !›²ïþ^ƒl¿WÆó³€¿mJ±2ïÃ>^ƒl¿mJ1±ö5?ò5¿Ó÷„²`ƒl?ïþnJ1±´ul?ö, »ê,ľrðZ?Žª²>ì,ľS(?EQ&?ë,ľqJ·>AûY?ë,ľ®- ;µul?ì,Ä¾Žª²¾rðZ?ì,ľEQ&¿Q(?ë,ľAûY¿rJ·>ì,ľµul¿N. ;ì,ľtðZ¿ˆª²¾ë,ľT(¿CQ&¿ë,ľuJ·¾@ûY¿ë,ľã. »µul¿ì,Ä¾Žª²>rðZ¿ì,ľFQ&?P(¿ë,ľCûY?jJ·¾ì,ľÈà4?sï¼6%5¿Ž(?÷†>6%5¿ƒŽ?¯|ü>6%5¿UÄŽ>‡6&?6%5¿Ÿï<Èà4?6%5¿÷†¾Ž(?6%5¿°|ü¾Ž?6%5¿‡6&¿UÄŽ>6%5¿Èà4¿ð<6%5¿Ž(¿ó†¾6%5¿„Ž¿¨|ü¾6%5¿YÄŽ¾†6&¿6%5¿7ð¼Èà4¿6%5¿÷†>Ž(¿6%5¿°|ü>Ž¿6%5¿ˆ6&?QÄŽ¾6%5¿ãJÖ>W¸¼zmh¿ÆaÊ> Â>zmh¿©Ÿ>e>zmh¿¸C9>8”Á>zmh¿n¸<áJÖ>zmh¿¡Â¾ÅaÊ>zmh¿e¾©Ÿ>zmh¿:”Á¾·C9>zmh¿ãJÖ¾¸Çaʾzmh¿e>©Ÿ¾zmh¿;”Á>³C9¾zmh¿¬èC±±€2€¿2€=#>#@>4€>% >%À>6à>'?'?8 ?)0?)@?:P?+`?+p?<€?->-€=>>>>/@>>/€>>@ >>!À>>1à>>B?>3?>3 ?>D0?>5@?>5P?>F`?>7p?>7€?>H€>9€=€>9>€>J@>€>;€>€>; >€>LÀ>€>=à>€>=?€>N?€>? ?€>?0?€>P@?€>1P?€>A`?€>Rp?€>C€?€>CÀ>T€=À>E>À>E@>À>V€>À>G >À>GÀ>À>Xà>À>I?À>I?À>Z ?À>K0?À>K@?À>\P?À>M`?À>Mp?À>^€?À>O?O€=?`>?A@>?Q€>?b >?SÀ>?Sà>?d??U??U ??f0??W@??WP??h`??Yp??Y€??j ?[€= ?[> ?l@> ?]€> ?] > ?nÀ> ?_à> ?_? ?p? ?Q ? ?q0? ?d@? ?dP? ?q`? ?hp? ?h€? ?q@?l€=@?l>@?q@>@?p€>@?p >@?Pû À>@?^ƒl?à>@?Ô‹Š>?@?ôµ>?@?^ƒl? ?@?Ջо0?@?ö>@?@?^ƒl?P?@?֋о`?@?òµ¾p?@?^ƒl?€?@?Ö‹Š>`?ö¾€=`?ó5?>`?ÿÿÿ>@>`?u='?€>`?ó5? >`?¿À>`?Ó‹Š>à>`?ó5??`?¿?`?s='¿ ?`?ó5?0?`??@?`?Ì‹Š¾P?`?ïÃ>`?`?t='?p?`?y‚Z?€?`?ïÃ>€?u='¿€=€?òµ>>€?ïÃ>@>€?w='¿€>€?w‚Z¿ >€?ïÃ>À>€?v='?à>€?éµ¾?€?.½;³?€?ó5? ?€?_ƒl?0?€?.½;³@?€?ô5¿P?€?ïÃ>`?€?.½;³p?€?ö5¿€?€?]ƒl¿Èðh®¶ `¥©Ãìqð1OP£&Ú`í[¹>¨- ±9…*¹¼D€”W·ÑNÕSE«†D,Ř¡â³D&Où.Ð’Ä)8ìUâï¢g> r,Ä¡‡Ž .\1ó€˜O¿'aÍEóìAÔY 3®%ý§]¬”ö<¢/’|B—0ˆ?%Ú•²®<¤Ì3S MU²›¹µ^F!ïYï[Û4ävAŠ´ÍkËÒäeŸu¿åŸ08râ¾xÂìSn ÈJVȬ¡„˜…ß̬³Íç­TÖ ˆûÉ´–eq#î»’bpOðVà®p†ÔÛÍ* þ±íl ’`ÿ›5ðòdN–ë'ëd³‰MPòÀ>Ûg†èènd™ÃHÚ‚+²jë gæŽÄÝåÞ!”’Yæe^¯j…ìÿÞê(àØ§”!äégQ˜JÕE6EÙ[øpR6d›ÕÏ0£jìÏKÒá(T ¤ÏÞ‘ ÷.ñÆÑqw‹W8F²-{hº_Sx T´BôxE™B}ó„Å—²ã´¾þž|^Õárt-°+ Y¾ÿŠYà(à9ÄM€WÂô…)ÁôrmÆQ'JÉãª_([3Â!®ÙazõëBoR““Ÿ‚‡(§Š®™q ïHsš‰˜ô?‚:]0¡È‡?kK|§ÎÎð«M6ÔOˆÄ8˜Äs´Ûkä_\ˆP®&^‰âÈV§¦üíÿ(K;öņM¸fx³˜†h°e[.¡hµI^L•bÛDÅú-3fz¢Øü©¾žy BVj™O~˦.<ãöQT=9âbõЧ÷ù™þ¿²¬ïݳ8Þ‘?KUë›õ…þUƒ°?@°3¬65¨Ê@F|f ˆ1UÉŽ\ö_ÖL°ÌÖ³{‹mœSlÄùeF9oƒ†³\äëŽõ}"n¯¶øîçž ×-!s_L)4/I=Í=×ÖšZ°òzô$^½yàÓ<|Û¾Øäyç`Æ7îÂÓÑYÎK/Å3gK„á_ƒ‰A|ž ÂR ü¾ÿ €·Œ‡ê}Ç?Ë‚X_`ö"£ÁÀò[ŽHO“"”Ž8èI›owšc‰¨·Uº½õHVº!¡«Uw~×<Ýl7_oûž}UG’)%àÞŠa?sôš2B5ÂpVŒpÞ,}‹Àv&ENqîúÖ½<_ùúc’í«6›ç‘êÆ³A¯gâµrHÐÆ]8ð …Û…@×”¡…"(ÝßÂmª_ÝY×_–ÎÏüøJ¯é¹àRA‹“ˆ#–ïø;l¹¯^ÿÓKV&œy7ðC;wžåefo®Þ€§^âNïþÝ€0ŸÃÕJñÀÑÎâÄ.ZIʸŸCV³«?½”ª«_l2-h[fî8ý×È[MÓ±È+lð%ÜcÌbôk6aØ.…ùE»¾Räi ßÜ5¸iΆúÊ¡Ÿ@KŠž…é ÌØhñWÎHig«¥šk*Ñ?êRç«/@^egÖ«å“U$ƦJ~æí¹(ˆ·š6CH½MÖ4”m _Öß›Ms åy‡ïÊ„À3îH@#²µ¹"[ª;ÓÇF¹:Å5ÖÚÞ=¢ Ÿy›xî]O‚·Ë£]àu–οØ^Ó¦öˆ ù‚"*Ö‹ÚZA¸h–æ5UY3|è%Ì.Âì_…l¾/oBµü6åû5 î?T­ÆÞ?"Ô€õÚ[&zÀÇ|ºô(#¼5¶\àa•àúï{ËéT5½ƒ²ëÊ0©ÿ7˜ÄœðԂ c “ ÙÆ²ù§/GQ,*Pcç¬Ør³®ýÈzl%”ch-owJƆxʃw†¾:k£ç×Ð"óÌ.0G& îm“ZqÓ'|àpÞÖVL(ȘÞÿÝÄŽŽÆNþÿ¶Š²Ì‘âs~êÒ.«ò¿QWÁÔfRýß@Fh‹üoXŽñ)ÌÃþ7£VH^„ÿ;ÈÎÚª;ïÿƒk4öÿyw$]ëùÿþˆ†ÈI¿;ÿÿÿRobject32àrr™€?ïÃ>^ƒl?ôµ>ö>^ƒl?Ô‹Š>Õ‹Š>^ƒl?ö>ôµ>^ƒl?•ã¶±ïÃ>^ƒl?ö¾ôµ>^ƒl?Õ‹Š¾Ô‹Š>^ƒl?ôµ¾ö>^ƒl?ïþ×tÊ2^ƒl?õµ¾ö¾^ƒl?Ö‹Š¾Ò‹Š¾^ƒl?!ö¾òµ¾^ƒl?IQa³ïþ^ƒl?ö>ôµ¾^ƒl?Ö‹Š>Ӌо^ƒl?öµ>ö¾^ƒl?ó5?ó5?t='?Ô‹Š>ó5?ÿÿÿ>?ó5?Ó‹Š>u='?ó5?¦÷(²ó5?ó5?Ջоt='?ó5?¿þÿÿ>ó5?t='¿Ó‹Š>ó5?ó5¿™ ;3ó5?u='¿Ñ‹Š¾ó5?¿üÿÿ¾ó5?Ú‹Š¾s='¿ó5?Ž*гó5¿ó5?Ô‹Š>t='¿ó5??ýÿÿ¾ó5?v='?Ì‹Š¾ó5?^ƒl?ïÃ>y‚Z?óµ>ïÃ>t='?t='?ïÃ>òµ>y‚Z?ïÃ>:Ä\²^ƒl?ïÃ>ôµ¾y‚Z?ïÃ>u='¿s='?ïÃ>y‚Z¿òµ>ïÃ>^ƒl¿ðbt3ïÃ>z‚Z¿ïµ¾ïÃ>w='¿r='¿ïÃ>ûµ¾w‚Z¿ïÃ>¼ý´^ƒl¿ïÃ>óµ>y‚Z¿ïÃ>v='?r='¿ïÃ>{‚Z?éµ¾ïÃ>€?.½;³^ƒl?ïÃ>.½;³ó5?ó5?.½;³ïÃ>_ƒl?.½;³ºôn²€?.½;³ïþ^ƒl?.½;³ô5¿ò5?.½;³_ƒl¿ïÃ>.½;³€¿ÒB„3.½;³_ƒl¿ïþ.½;³ö5¿ñ5¿.½;³ïþ]ƒl¿.½;³2´€¿.½;³ïÃ>^ƒl¿.½;³õ5?ñ5¿.½;³aƒl? ïþ.½;³^ƒl?ïþy‚Z?óµ>ïþt='?t='?ïþòµ>y‚Z?ïþ:Ä\²^ƒl?ïþôµ¾y‚Z?ïþu='¿s='?ïþy‚Z¿òµ>ïþ^ƒl¿ðbt3ïþz‚Z¿ïµ¾ïþw='¿r='¿ïþûµ¾w‚Z¿ïþ¼ý´^ƒl¿ïþóµ>y‚Z¿ïþv='?r='¿ïþ{‚Z?éµ¾ïþó5?ó5¿t='?Ô‹Š>ó5¿ÿÿÿ>?ó5¿Ó‹Š>u='?ó5¿¦÷(²ó5?ó5¿Õ‹Š¾t='?ó5¿¿þÿÿ>ó5¿t='¿Ó‹Š>ó5¿ó5¿™ ;3ó5¿u='¿Ñ‹Š¾ó5¿¿üÿÿ¾ó5¿Ú‹Š¾s='¿ó5¿Ž*гó5¿ó5¿Ô‹Š>t='¿ó5¿?ýÿÿ¾ó5¿v='?Ì‹Š¾ó5¿ïÃ>^ƒl¿õµ>ö>^ƒl¿Õ‹Š>Õ‹Š>^ƒl¿ö>õµ>^ƒl¿–ã¶±ïÃ>^ƒl¿ö¾õµ>^ƒl¿Ö‹Š¾Ô‹Š>^ƒl¿õµ¾ö>^ƒl¿ïþØtÊ2^ƒl¿öµ¾ö¾^ƒl¿×‹Š¾Ó‹Š¾^ƒl¿"ö¾óµ¾^ƒl¿JQa³ïþ^ƒl¿ö>õµ¾^ƒl¿×‹Š>Ӌо^ƒl¿÷µ>ö¾^ƒl¿€¿›²…ýG2€?áJÖ>¸·C9>zmh?e>©Ÿ>zmh?Â>ÆaÊ>zmh?w¸¼áJÖ>zmh?¸C9¾8”Á>zmh?©Ÿ¾e>zmh?ÆaʾŸÂ>zmh?áJÖ¾_¸¼zmh?9”Á¾´C9¾zmh?e¾©Ÿ¾zmh?¦Â¾Äaʾzmh?T¸<áJÖ¾zmh?¸C9>8”Á¾zmh?©Ÿ>e¾zmh?ÇaÊ>™Â¾zmh?Èà4?(ð<6%5?‡6&?WÄŽ>6%5?°|ü>ƒŽ?5%5?õ†>Ž(?6%5?ùï¼Èà4?6%5?WÄŽ¾‡6&?6%5?„Ž¿­|ü>5%5?Ž(¿õ†>6%5?Èà4¿€ï¼6%5?ˆ6&¿QÄŽ¾6%5?°|ü¾Ž¿7%5?û†¾(¿6%5?jï<Èà4¿5%5?VÄŽ>‡6&¿6%5?„Ž?¬|ü¾5%5?(?ñ†¾5%5?µul?. ;è,Ä>CûY?rJ·>é,Ä>EQ&?S(?é,Ä>ª²>tðZ?è,Ä>õ- »µul?è,Ä>rJ·¾AûY?è,Ä>R(¿DQ&?è,Ä>tðZ¿‹ª²>é,Ä>µul¿.- »è,Ä>CûY¿kJ·¾è,Ä>GQ&¿P(¿ë,Ä>“ª²¾rðZ¿é,Ä>©, ;µul¿è,Ä>rJ·>CûY¿é,Ä>U(?CQ&¿é,Ä>tðZ?‡ª²¾è,Ä>€?¨24 !›2^ƒl?ïÃ>mJ1±ô5?ó5?!!›²ïÃ>_ƒl?mJ1³€?mJ±2ïþ^ƒl?mJ1±ô5¿ó5?¼sDz_ƒl¿ïÃ>€¿ Ý2»sÇ2_ƒl¿ïþmJ±1ö5¿ñ5¿ !›²ïþ^ƒl¿WÆó³€¿mJ±2ïÃ>^ƒl¿mJ1±ö5?ò5¿Ó÷„²`ƒl?ïþnJ1±´ul?ö, »ê,ľrðZ?Žª²>ì,ľS(?EQ&?ë,ľqJ·>AûY?ë,ľ®- ;µul?ì,Ä¾Žª²¾rðZ?ì,ľEQ&¿Q(?ë,ľAûY¿rJ·>ì,ľµul¿N. ;ì,ľtðZ¿ˆª²¾ë,ľT(¿CQ&¿ë,ľuJ·¾@ûY¿ë,ľã. »µul¿ì,Ä¾Žª²>rðZ¿ì,ľFQ&?P(¿ë,ľCûY?jJ·¾ì,ľÈà4?sï¼6%5¿Ž(?÷†>6%5¿ƒŽ?¯|ü>6%5¿UÄŽ>‡6&?6%5¿Ÿï<Èà4?6%5¿÷†¾Ž(?6%5¿°|ü¾Ž?6%5¿‡6&¿UÄŽ>6%5¿Èà4¿ð<6%5¿Ž(¿ó†¾6%5¿„Ž¿¨|ü¾6%5¿YÄŽ¾†6&¿6%5¿7ð¼Èà4¿6%5¿÷†>Ž(¿6%5¿°|ü>Ž¿6%5¿ˆ6&?QÄŽ¾6%5¿ãJÖ>W¸¼zmh¿ÆaÊ> Â>zmh¿©Ÿ>e>zmh¿¸C9>8”Á>zmh¿n¸<áJÖ>zmh¿¡Â¾ÅaÊ>zmh¿e¾©Ÿ>zmh¿:”Á¾·C9>zmh¿ãJÖ¾¸Çaʾzmh¿e>©Ÿ¾zmh¿;”Á>³C9¾zmh¿¬èC±±€2€¿…ýG2€=zmh?>e>@>ÆaÊ>€>zmh? >©Ÿ¾À>ŸÂ>à>zmh??e¾?Äaʾ ?zmh?0?©Ÿ>@?™Â¾P?6%5?`?°|ü>p?Ž(?€?6%5?>„Ž¿€=>õ†>>>6%5?@>>°|ü¾€>>(¿ >>5%5?À>>„Ž?à>>ñ†¾?>è,Ä>?>EQ&? ?>tðZ?0?>è,Ä>@?>R(¿P?>‹ª²>`?>è,Ä>p?>GQ&¿€?>rðZ¿€>è,Ä>€=€>U(?>€>‡ª²¾@>€> !›2€>€>ô5? >€>_ƒl?À>€>mJ±2à>€>ô5¿?€>ïÃ>?€>»sÇ2 ?€>ö5¿0?€>^ƒl¿@?€>mJ±2P?€>ö5?`?€>ïþp?€>ê,ľ€?€>S(?À>AûY?€=À>ì,ľ>À>EQ&¿@>À>rJ·>€>À>ì,ľ >À>T(¿À>À>@ûY¿à>À>ì,ľ?À>FQ&??À>jJ·¾ ?À>6%5¿0?À>ƒŽ?@?À>‡6&?P?À>6%5¿`?À>°|ü¾p?À>UÄŽ>€?À>6%5¿?„Ž¿€=?†6&¿>?6%5¿@>?°|ü>€>?QÄŽ¾ >?zmh¿À>?©Ÿ>à>?8”Á>??zmh¿??e¾ ??·C9>0??zmh¿@??©Ÿ¾P??7”Á¾`??zmh¿p??e>€??³C9¾ ?€¿€= ?xø > ?@> ?€> ? > ?À> ?à> ?? ?? ? ? ?0? ?@? ?P? ?`? ?p? ?€? ?@?€=@?>>@?>@>@?>€>@?> >@?>À>@?>à>@?>?@?>?@?> ?@?>0?@?>@?@?>P?@?>`?@?>p?@?>€?@?>`?>€=`?€>>`?€>@>`?€>€>`?€> >`?€>À>`?€>à>`?€>?`?€>?`?€> ?`?€>0?`?€>@?`?€>P?`?€>`?`?€>p?`?€>€?`?€>€?€>€=€?À>>€?À>@>€?À>€>€?À> >€?À>À>€?À>à>€?À>?€?À>?€?À> ?€?À>0?€?À>@?€?À>P?€?À>`?€?À>p?€?À>€?€?À>Èðh®¶ `¥©Ãìqð1OP£&Ú`í[¹>¨- ±9…*¹¼D€”W·ÑNÕSE«†D,Ř¡â³D&Où.Ð’Ä)8ìUâï¢g> r,Ä¡‡Ž .\1ó€˜O¿'aÍEóìAÔY 3®%ý§]¬”ö<¢/’|B—0ˆ?%Ú•²®<¤Ì3S MU²›¹µ^F!ïYï[Û4ävAŠ´ÍkËÒäeŸu¿åŸ08râ¾xÂìSn ÈJVȬ¡„˜…ß̬³Íç­TÖ ˆûÉ´–eq#î»’bpOðVà®p†ÔÛÍ* þ±íl ’`ÿ›5ðòdN–ë'ëd³‰MPòÀ>Ûg†èènd™ÃHÚ‚+²jë gæŽÄÝåÞ!”’Yæe^¯j…ìÿÞê(àØ§”!äégQ˜JÕE6EÙ[øpR6d›ÕÏ0£jìÏKÒá(T ¤ÏÞ‘ ÷.ñÆÑqw‹W8F²-{hº_Sx T´BôxE™B}ó„Å—²ã´¾þž|^Õárt-°+ Y¾ÿŠYà(à9ÄM€WÂô…)ÁôrmÆQ'JÉãª_([3Â!®ÙazõëBoR““Ÿ‚‡(§Š®™q ïHsš‰˜ô?‚:]0¡È‡?kK|§ÎÎð«M6ÔOˆÄ8˜Äs´Ûkä_\ˆP®&^‰âÈV§¦üíÿ(K;öņM¸fx³˜†h°e[.¡hµI^L•bÛDÅú-3fz¢Øü©¾žy BVj™O~˦.<ãöQT=9âbõЧ÷ù™þ¿²¬ïݳ8Þ‘?KUë›õ…þUƒ°?@°3¬65¨Ê@F|f ˆ1UÉŽ\ö_ÖL°ÌÖ³{‹mœSlÄùeF9oƒ†³\äëŽõ}"n¯¶øîçž ×-!s_L)4/I=Í=×ÖšZ°òzô$^½yàÓ<|Û¾Øäyç`Æ7îÂÓÑYÎK/Å3gK„á_ƒ‰A|ž ÂR ü¾ÿ €·Œ‡ê}Ç?Ë‚X_`ö"£ÁÀò[ŽHO“"”Ž8èI›owšc‰¨·Uº½õHVº!¡«Uw~×<Ýl7_oûž}UG’)%àÞŠa?sôš2B5ÂpVŒpÞ,}‹Àv&ENqîúÖ½<_ùúc’í«6›ç‘êÆ³A¯gâµrHÐÆ]8ð …Û…@×”¡…"(ÝßÂmª_ÝY×_–ÎÏüøJ¯é¹àRA‹“ˆ#–ïø;l¹¯^ÿÓKV&œy7ðC;wžåefo®Þ€§^âNïþÝ€0ŸÃÕJñÀÑÎâÄ.ZIʸŸCV³«?½”ª«_l2-h[fî8ý×È[MÓ±È+lð%ÜcÌbôk6aØ.…ùE»¾Räi ßÜ5¸iΆúÊ¡Ÿ@KŠž…é ÌØhñWÎHig«¥šk*Ñ?êRç«/@^egÖ«å“U$ƦJ~æí¹(ˆ·š6CH½MÖ4”m _Öß›Ms åy‡ïÊ„À3îH@#²µ¹"[ª;ÓÇF¹:Å5ÖÚÞ=¢ Ÿy›xî]O‚·Ë£]àu–οØ^Ó¦öˆ ù‚"*Ö‹ÚZA¸h–æ5UY3|è%Ì.Âì_…l¾/oBµü6åû5 î?T­ÆÞ?"Ô€õÚ[&zÀÇ|ºô(#¼5¶\àa•àúï{ËéT5½ƒ²ëÊ0©ÿ7˜ÄœðԂ c “ ÙÆ²ù§/GQ,*Pcç¬Ør³®ýÈzl%”ch-owJƆxʃw†¾:k£ç×Ð"óÌ.0G& îm“ZqÓ'|àpÞÖVL(ȘÞÿÝÄŽŽÆNþÿ¶Š²Ì‘âs~êÒ.«ò¿QWÁÔfRýß@Fh‹üoXŽñ)ÌÃþ7£VH^„ÿ;ÈÎÚª;ïÿƒk4öÿyw$]ëùÿþˆ†ÈI¿;ÿÿÿRobject30àrr™€?ïÃ>^ƒl?ôµ>ö>^ƒl?Ô‹Š>Õ‹Š>^ƒl?ö>ôµ>^ƒl?•ã¶±ïÃ>^ƒl?ö¾ôµ>^ƒl?Õ‹Š¾Ô‹Š>^ƒl?ôµ¾ö>^ƒl?ïþ×tÊ2^ƒl?õµ¾ö¾^ƒl?Ö‹Š¾Ò‹Š¾^ƒl?!ö¾òµ¾^ƒl?IQa³ïþ^ƒl?ö>ôµ¾^ƒl?Ö‹Š>Ӌо^ƒl?öµ>ö¾^ƒl?ó5?ó5?t='?Ô‹Š>ó5?ÿÿÿ>?ó5?Ó‹Š>u='?ó5?¦÷(²ó5?ó5?Ջоt='?ó5?¿þÿÿ>ó5?t='¿Ó‹Š>ó5?ó5¿™ ;3ó5?u='¿Ñ‹Š¾ó5?¿üÿÿ¾ó5?Ú‹Š¾s='¿ó5?Ž*гó5¿ó5?Ô‹Š>t='¿ó5??ýÿÿ¾ó5?v='?Ì‹Š¾ó5?^ƒl?ïÃ>y‚Z?óµ>ïÃ>t='?t='?ïÃ>òµ>y‚Z?ïÃ>:Ä\²^ƒl?ïÃ>ôµ¾y‚Z?ïÃ>u='¿s='?ïÃ>y‚Z¿òµ>ïÃ>^ƒl¿ðbt3ïÃ>z‚Z¿ïµ¾ïÃ>w='¿r='¿ïÃ>ûµ¾w‚Z¿ïÃ>¼ý´^ƒl¿ïÃ>óµ>y‚Z¿ïÃ>v='?r='¿ïÃ>{‚Z?éµ¾ïÃ>€?.½;³^ƒl?ïÃ>.½;³ó5?ó5?.½;³ïÃ>_ƒl?.½;³ºôn²€?.½;³ïþ^ƒl?.½;³ô5¿ò5?.½;³_ƒl¿ïÃ>.½;³€¿ÒB„3.½;³_ƒl¿ïþ.½;³ö5¿ñ5¿.½;³ïþ]ƒl¿.½;³2´€¿.½;³ïÃ>^ƒl¿.½;³õ5?ñ5¿.½;³aƒl? ïþ.½;³^ƒl?ïþy‚Z?óµ>ïþt='?t='?ïþòµ>y‚Z?ïþ:Ä\²^ƒl?ïþôµ¾y‚Z?ïþu='¿s='?ïþy‚Z¿òµ>ïþ^ƒl¿ðbt3ïþz‚Z¿ïµ¾ïþw='¿r='¿ïþûµ¾w‚Z¿ïþ¼ý´^ƒl¿ïþóµ>y‚Z¿ïþv='?r='¿ïþ{‚Z?éµ¾ïþó5?ó5¿t='?Ô‹Š>ó5¿ÿÿÿ>?ó5¿Ó‹Š>u='?ó5¿¦÷(²ó5?ó5¿Õ‹Š¾t='?ó5¿¿þÿÿ>ó5¿t='¿Ó‹Š>ó5¿ó5¿™ ;3ó5¿u='¿Ñ‹Š¾ó5¿¿üÿÿ¾ó5¿Ú‹Š¾s='¿ó5¿Ž*гó5¿ó5¿Ô‹Š>t='¿ó5¿?ýÿÿ¾ó5¿v='?Ì‹Š¾ó5¿ïÃ>^ƒl¿õµ>ö>^ƒl¿Õ‹Š>Õ‹Š>^ƒl¿ö>õµ>^ƒl¿–ã¶±ïÃ>^ƒl¿ö¾õµ>^ƒl¿Ö‹Š¾Ô‹Š>^ƒl¿õµ¾ö>^ƒl¿ïþØtÊ2^ƒl¿öµ¾ö¾^ƒl¿×‹Š¾Ó‹Š¾^ƒl¿"ö¾óµ¾^ƒl¿JQa³ïþ^ƒl¿ö>õµ¾^ƒl¿×‹Š>Ӌо^ƒl¿÷µ>ö¾^ƒl¿€¿›²…ýG2€?áJÖ>¸·C9>zmh?e>©Ÿ>zmh?Â>ÆaÊ>zmh?w¸¼áJÖ>zmh?¸C9¾8”Á>zmh?©Ÿ¾e>zmh?ÆaʾŸÂ>zmh?áJÖ¾_¸¼zmh?9”Á¾´C9¾zmh?e¾©Ÿ¾zmh?¦Â¾Äaʾzmh?T¸<áJÖ¾zmh?¸C9>8”Á¾zmh?©Ÿ>e¾zmh?ÇaÊ>™Â¾zmh?Èà4?(ð<6%5?‡6&?WÄŽ>6%5?°|ü>ƒŽ?5%5?õ†>Ž(?6%5?ùï¼Èà4?6%5?WÄŽ¾‡6&?6%5?„Ž¿­|ü>5%5?Ž(¿õ†>6%5?Èà4¿€ï¼6%5?ˆ6&¿QÄŽ¾6%5?°|ü¾Ž¿7%5?û†¾(¿6%5?jï<Èà4¿5%5?VÄŽ>‡6&¿6%5?„Ž?¬|ü¾5%5?(?ñ†¾5%5?µul?. ;è,Ä>CûY?rJ·>é,Ä>EQ&?S(?é,Ä>ª²>tðZ?è,Ä>õ- »µul?è,Ä>rJ·¾AûY?è,Ä>R(¿DQ&?è,Ä>tðZ¿‹ª²>é,Ä>µul¿.- »è,Ä>CûY¿kJ·¾è,Ä>GQ&¿P(¿ë,Ä>“ª²¾rðZ¿é,Ä>©, ;µul¿è,Ä>rJ·>CûY¿é,Ä>U(?CQ&¿é,Ä>tðZ?‡ª²¾è,Ä>€?¨24 !›2^ƒl?ïÃ>mJ1±ô5?ó5?!!›²ïÃ>_ƒl?mJ1³€?mJ±2ïþ^ƒl?mJ1±ô5¿ó5?¼sDz_ƒl¿ïÃ>€¿ Ý2»sÇ2_ƒl¿ïþmJ±1ö5¿ñ5¿ !›²ïþ^ƒl¿WÆó³€¿mJ±2ïÃ>^ƒl¿mJ1±ö5?ò5¿Ó÷„²`ƒl?ïþnJ1±´ul?ö, »ê,ľrðZ?Žª²>ì,ľS(?EQ&?ë,ľqJ·>AûY?ë,ľ®- ;µul?ì,Ä¾Žª²¾rðZ?ì,ľEQ&¿Q(?ë,ľAûY¿rJ·>ì,ľµul¿N. ;ì,ľtðZ¿ˆª²¾ë,ľT(¿CQ&¿ë,ľuJ·¾@ûY¿ë,ľã. »µul¿ì,Ä¾Žª²>rðZ¿ì,ľFQ&?P(¿ë,ľCûY?jJ·¾ì,ľÈà4?sï¼6%5¿Ž(?÷†>6%5¿ƒŽ?¯|ü>6%5¿UÄŽ>‡6&?6%5¿Ÿï<Èà4?6%5¿÷†¾Ž(?6%5¿°|ü¾Ž?6%5¿‡6&¿UÄŽ>6%5¿Èà4¿ð<6%5¿Ž(¿ó†¾6%5¿„Ž¿¨|ü¾6%5¿YÄŽ¾†6&¿6%5¿7ð¼Èà4¿6%5¿÷†>Ž(¿6%5¿°|ü>Ž¿6%5¿ˆ6&?QÄŽ¾6%5¿ãJÖ>W¸¼zmh¿ÆaÊ> Â>zmh¿©Ÿ>e>zmh¿¸C9>8”Á>zmh¿n¸<áJÖ>zmh¿¡Â¾ÅaÊ>zmh¿e¾©Ÿ>zmh¿:”Á¾·C9>zmh¿ãJÖ¾¸Çaʾzmh¿e>©Ÿ¾zmh¿;”Á>³C9¾zmh¿¬èC±±€2€¿€=>@>€> >À>à>?? ?0?@?P?`?p?€?>€=>>>@>>€>> >>À>>à>>?>?> ?>0?>@?>P?>`?>p?>€?>€>€=€>>€>@>€>€>€> >€>À>€>à>€>?€>?€> ?€>0?€>@?€>P?€>`?€>p?€>€?€>À>€=À>>À>@>À>€>À> >À>À>À>à>À>?À>?À> ?À>0?À>@?À>P?À>`?À>p?À>€?À>?€=?>?@>?€>? >?À>?à>????? ??0??@??P??`??p??€?? ?€= ?> ?@> ?€> ? > ?À> ?à> ?? ?? ? ? ?0? ?@? ?P? ?`? ?p? ?€? ?@?€=@?>@?@>@?€>@? >@?À>@?à>@??@??@? ?@?0?@?@?@?P?@?`?@?p?@?€?@?`?€=`?>`?@>`?€>`? >`?À>`?à>`??`??`? ?`?0?`?@?`?P?`?`?`?p?`?€?`?€?€=€?>€?@>€?€>€? >€?À>€?à>€??€??€? ?€?0?€?@?€?P?€?`?€?p?€?€?€?Èðh®¶ `¥©Ãìqð1OP£&Ú`í[¹>¨- ±9…*¹¼D€”W·ÑNÕSE«†D,Ř¡â³D&Où.Ð’Ä)8ìUâï¢g> r,Ä¡‡Ž .\1ó€˜O¿'aÍEóìAÔY 3®%ý§]¬”ö<¢/’|B—0ˆ?%Ú•²®<¤Ì3S MU²›¹µ^F!ïYï[Û4ävAŠ´ÍkËÒäeŸu¿åŸ08râ¾xÂìSn ÈJVȬ¡„˜…ß̬³Íç­TÖ ˆûÉ´–eq#î»’bpOðVà®p†ÔÛÍ* þ±íl ’`ÿ›5ðòdN–ë'ëd³‰MPòÀ>Ûg†èènd™ÃHÚ‚+²jë gæŽÄÝåÞ!”’Yæe^¯j…ìÿÞê(àØ§”!äégQ˜JÕE6EÙ[øpR6d›ÕÏ0£jìÏKÒá(T ¤ÏÞ‘ ÷.ñÆÑqw‹W8F²-{hº_Sx T´BôxE™B}ó„Å—²ã´¾þž|^Õárt-°+ Y¾ÿŠYà(à9ÄM€WÂô…)ÁôrmÆQ'JÉãª_([3Â!®ÙazõëBoR““Ÿ‚‡(§Š®™q ïHsš‰˜ô?‚:]0¡È‡?kK|§ÎÎð«M6ÔOˆÄ8˜Äs´Ûkä_\ˆP®&^‰âÈV§¦üíÿ(K;öņM¸fx³˜†h°e[.¡hµI^L•bÛDÅú-3fz¢Øü©¾žy BVj™O~˦.<ãöQT=9âbõЧ÷ù™þ¿²¬ïݳ8Þ‘?KUë›õ…þUƒ°?@°3¬65¨Ê@F|f ˆ1UÉŽ\ö_ÖL°ÌÖ³{‹mœSlÄùeF9oƒ†³\äëŽõ}"n¯¶øîçž ×-!s_L)4/I=Í=×ÖšZ°òzô$^½yàÓ<|Û¾Øäyç`Æ7îÂÓÑYÎK/Å3gK„á_ƒ‰A|ž ÂR ü¾ÿ €·Œ‡ê}Ç?Ë‚X_`ö"£ÁÀò[ŽHO“"”Ž8èI›owšc‰¨·Uº½õHVº!¡«Uw~×<Ýl7_oûž}UG’)%àÞŠa?sôš2B5ÂpVŒpÞ,}‹Àv&ENqîúÖ½<_ùúc’í«6›ç‘êÆ³A¯gâµrHÐÆ]8ð …Û…@×”¡…"(ÝßÂmª_ÝY×_–ÎÏüøJ¯é¹àRA‹“ˆ#–ïø;l¹¯^ÿÓKV&œy7ðC;wžåefo®Þ€§^âNïþÝ€0ŸÃÕJñÀÑÎâÄ.ZIʸŸCV³«?½”ª«_l2-h[fî8ý×È[MÓ±È+lð%ÜcÌbôk6aØ.…ùE»¾Räi ßÜ5¸iΆúÊ¡Ÿ@KŠž…é ÌØhñWÎHig«¥šk*Ñ?êRç«/@^egÖ«å“U$ƦJ~æí¹(ˆ·š6CH½MÖ4”m _Öß›Ms åy‡ïÊ„À3îH@#²µ¹"[ª;ÓÇF¹:Å5ÖÚÞ=¢ Ÿy›xî]O‚·Ë£]àu–οØ^Ó¦öˆ ù‚"*Ö‹ÚZA¸h–æ5UY3|è%Ì.Âì_…l¾/oBµü6åû5 î?T­ÆÞ?"Ô€õÚ[&zÀÇ|ºô(#¼5¶\àa•àúï{ËéT5½ƒ²ëÊ0©ÿ7˜ÄœðԂ c “ ÙÆ²ù§/GQ,*Pcç¬Ør³®ýÈzl%”ch-owJƆxʃw†¾:k£ç×Ð"óÌ.0G& îm“ZqÓ'|àpÞÖVL(ȘÞÿÝÄŽŽÆNþÿ¶Š²Ì‘âs~êÒ.«ò¿QWÁÔfRýß@Fh‹üoXŽñ)ÌÃþ7£VH^„ÿ;ÈÎÚª;ïÿƒk4öÿyw$]ëùÿþˆ†ÈI¿;ÿÿÿRobject28àrr™€?ïÃ>^ƒl?ôµ>ö>^ƒl?Ô‹Š>Õ‹Š>^ƒl?ö>ôµ>^ƒl?•ã¶±ïÃ>^ƒl?ö¾ôµ>^ƒl?Õ‹Š¾Ô‹Š>^ƒl?ôµ¾ö>^ƒl?ïþ×tÊ2^ƒl?õµ¾ö¾^ƒl?Ö‹Š¾Ò‹Š¾^ƒl?!ö¾òµ¾^ƒl?IQa³ïþ^ƒl?ö>ôµ¾^ƒl?Ö‹Š>Ӌо^ƒl?öµ>ö¾^ƒl?ó5?ó5?t='?Ô‹Š>ó5?ÿÿÿ>?ó5?Ó‹Š>u='?ó5?¦÷(²ó5?ó5?Ջоt='?ó5?¿þÿÿ>ó5?t='¿Ó‹Š>ó5?ó5¿™ ;3ó5?u='¿Ñ‹Š¾ó5?¿üÿÿ¾ó5?Ú‹Š¾s='¿ó5?Ž*гó5¿ó5?Ô‹Š>t='¿ó5??ýÿÿ¾ó5?v='?Ì‹Š¾ó5?^ƒl?ïÃ>y‚Z?óµ>ïÃ>t='?t='?ïÃ>òµ>y‚Z?ïÃ>:Ä\²^ƒl?ïÃ>ôµ¾y‚Z?ïÃ>u='¿s='?ïÃ>y‚Z¿òµ>ïÃ>^ƒl¿ðbt3ïÃ>z‚Z¿ïµ¾ïÃ>w='¿r='¿ïÃ>ûµ¾w‚Z¿ïÃ>¼ý´^ƒl¿ïÃ>óµ>y‚Z¿ïÃ>v='?r='¿ïÃ>{‚Z?éµ¾ïÃ>€?.½;³^ƒl?ïÃ>.½;³ó5?ó5?.½;³ïÃ>_ƒl?.½;³ºôn²€?.½;³ïþ^ƒl?.½;³ô5¿ò5?.½;³_ƒl¿ïÃ>.½;³€¿ÒB„3.½;³_ƒl¿ïþ.½;³ö5¿ñ5¿.½;³ïþ]ƒl¿.½;³2´€¿.½;³ïÃ>^ƒl¿.½;³õ5?ñ5¿.½;³aƒl? ïþ.½;³^ƒl?ïþy‚Z?óµ>ïþt='?t='?ïþòµ>y‚Z?ïþ:Ä\²^ƒl?ïþôµ¾y‚Z?ïþu='¿s='?ïþy‚Z¿òµ>ïþ^ƒl¿ðbt3ïþz‚Z¿ïµ¾ïþw='¿r='¿ïþûµ¾w‚Z¿ïþ¼ý´^ƒl¿ïþóµ>y‚Z¿ïþv='?r='¿ïþ{‚Z?éµ¾ïþó5?ó5¿t='?Ô‹Š>ó5¿ÿÿÿ>?ó5¿Ó‹Š>u='?ó5¿¦÷(²ó5?ó5¿Õ‹Š¾t='?ó5¿¿þÿÿ>ó5¿t='¿Ó‹Š>ó5¿ó5¿™ ;3ó5¿u='¿Ñ‹Š¾ó5¿¿üÿÿ¾ó5¿Ú‹Š¾s='¿ó5¿Ž*гó5¿ó5¿Ô‹Š>t='¿ó5¿?ýÿÿ¾ó5¿v='?Ì‹Š¾ó5¿ïÃ>^ƒl¿õµ>ö>^ƒl¿Õ‹Š>Õ‹Š>^ƒl¿ö>õµ>^ƒl¿–ã¶±ïÃ>^ƒl¿ö¾õµ>^ƒl¿Ö‹Š¾Ô‹Š>^ƒl¿õµ¾ö>^ƒl¿ïþØtÊ2^ƒl¿öµ¾ö¾^ƒl¿×‹Š¾Ó‹Š¾^ƒl¿"ö¾óµ¾^ƒl¿JQa³ïþ^ƒl¿ö>õµ¾^ƒl¿×‹Š>Ӌо^ƒl¿÷µ>ö¾^ƒl¿€¿›²…ýG2€?áJÖ>¸·C9>zmh?e>©Ÿ>zmh?Â>ÆaÊ>zmh?w¸¼áJÖ>zmh?¸C9¾8”Á>zmh?©Ÿ¾e>zmh?ÆaʾŸÂ>zmh?áJÖ¾_¸¼zmh?9”Á¾´C9¾zmh?e¾©Ÿ¾zmh?¦Â¾Äaʾzmh?T¸<áJÖ¾zmh?¸C9>8”Á¾zmh?©Ÿ>e¾zmh?ÇaÊ>™Â¾zmh?Èà4?(ð<6%5?‡6&?WÄŽ>6%5?°|ü>ƒŽ?5%5?õ†>Ž(?6%5?ùï¼Èà4?6%5?WÄŽ¾‡6&?6%5?„Ž¿­|ü>5%5?Ž(¿õ†>6%5?Èà4¿€ï¼6%5?ˆ6&¿QÄŽ¾6%5?°|ü¾Ž¿7%5?û†¾(¿6%5?jï<Èà4¿5%5?VÄŽ>‡6&¿6%5?„Ž?¬|ü¾5%5?(?ñ†¾5%5?µul?. ;è,Ä>CûY?rJ·>é,Ä>EQ&?S(?é,Ä>ª²>tðZ?è,Ä>õ- »µul?è,Ä>rJ·¾AûY?è,Ä>R(¿DQ&?è,Ä>tðZ¿‹ª²>é,Ä>µul¿.- »è,Ä>CûY¿kJ·¾è,Ä>GQ&¿P(¿ë,Ä>“ª²¾rðZ¿é,Ä>©, ;µul¿è,Ä>rJ·>CûY¿é,Ä>U(?CQ&¿é,Ä>tðZ?‡ª²¾è,Ä>€?¨24 !›2^ƒl?ïÃ>mJ1±ô5?ó5?!!›²ïÃ>_ƒl?mJ1³€?mJ±2ïþ^ƒl?mJ1±ô5¿ó5?¼sDz_ƒl¿ïÃ>€¿ Ý2»sÇ2_ƒl¿ïþmJ±1ö5¿ñ5¿ !›²ïþ^ƒl¿WÆó³€¿mJ±2ïÃ>^ƒl¿mJ1±ö5?ò5¿Ó÷„²`ƒl?ïþnJ1±´ul?ö, »ê,ľrðZ?Žª²>ì,ľS(?EQ&?ë,ľqJ·>AûY?ë,ľ®- ;µul?ì,Ä¾Žª²¾rðZ?ì,ľEQ&¿Q(?ë,ľAûY¿rJ·>ì,ľµul¿N. ;ì,ľtðZ¿ˆª²¾ë,ľT(¿CQ&¿ë,ľuJ·¾@ûY¿ë,ľã. »µul¿ì,Ä¾Žª²>rðZ¿ì,ľFQ&?P(¿ë,ľCûY?jJ·¾ì,ľÈà4?sï¼6%5¿Ž(?÷†>6%5¿ƒŽ?¯|ü>6%5¿UÄŽ>‡6&?6%5¿Ÿï<Èà4?6%5¿÷†¾Ž(?6%5¿°|ü¾Ž?6%5¿‡6&¿UÄŽ>6%5¿Èà4¿ð<6%5¿Ž(¿ó†¾6%5¿„Ž¿¨|ü¾6%5¿YÄŽ¾†6&¿6%5¿7ð¼Èà4¿6%5¿÷†>Ž(¿6%5¿°|ü>Ž¿6%5¿ˆ6&?QÄŽ¾6%5¿ãJÖ>W¸¼zmh¿ÆaÊ> Â>zmh¿©Ÿ>e>zmh¿¸C9>8”Á>zmh¿n¸<áJÖ>zmh¿¡Â¾ÅaÊ>zmh¿e¾©Ÿ>zmh¿:”Á¾·C9>zmh¿ãJÖ¾¸Çaʾzmh¿e>©Ÿ¾zmh¿;”Á>³C9¾zmh¿¬èC±±€2€¿€=>$øô @>€> >À>à>$øô ?? ?0?@?$øô P?`?p?€?>$øô €=>>>@>>€>> >>$øô À>>à>>?>?> ?>$øô 0?>@?>P?>`?>p?>$øô €?>€>€=€>>€>@>€>$øô €>€> >€>À>€>à>€>?€>$øô ?€> ?€>0?€>@?€>P?€>$øô `?€>p?€>€?€>À>€=À>$øô >À>@>À>€>À> >À>À>À>$øô à>À>?À>?À> ?À>0?À>$øô @?À>P?À>`?À>p?À>€?À>$øô ?€=?>?@>?€>?$øô  >?À>?à>?????$øô ??0??@??P??`??$øô p??€?? ?€= ?> ?$øô @> ?€> ? > ?À> ?à> ?$øô ? ?? ? ? ?0? ?@? ?$øô P? ?`? ?p? ?€? ?@?$øô €=@?>@?@>@?€>@? >@?$øô À>@?à>@??@??@? ?@?$øô 0?@?@?@?P?@?`?@?p?@?$øô €?@?`?€=`?>`?@>`?$øô €>`? >`?À>`?à>`??`?$øô ?`? ?`?0?`?@?`?P?`?$øô `?`?p?`?€?`?€?€=€?$øô >€?@>€?€>€? >€?À>€?à>€?…ýG2?€?zmh??€?e> ?€?ÆaÊ>0?€?zmh?@?€?©Ÿ¾P?€?ŸÂ>`?€?zmh?p?€?e¾€?€?ÄaʾÈðh®¶ `¥©Ãìqð1OP£&Ú`í[¹>¨- ±9…*¹¼D€”W·ÑNÕSE«†D,Ř¡â³D&Où.Ð’Ä)8ìUâï¢g> r,Ä¡‡Ž .\1ó€˜O¿'aÍEóìAÔY 3®%ý§]¬”ö<¢/’|B—0ˆ?%Ú•²®<¤Ì3S MU²›¹µ^F!ïYï[Û4ävAŠ´ÍkËÒäeŸu¿åŸ08râ¾xÂìSn ÈJVȬ¡„˜…ß̬³Íç­TÖ ˆûÉ´–eq#î»’bpOðVà®p†ÔÛÍ* þ±íl ’`ÿ›5ðòdN–ë'ëd³‰MPòÀ>Ûg†èènd™ÃHÚ‚+²jë gæŽÄÝåÞ!”’Yæe^¯j…ìÿÞê(àØ§”!äégQ˜JÕE6EÙ[øpR6d›ÕÏ0£jìÏKÒá(T ¤ÏÞ‘ ÷.ñÆÑqw‹W8F²-{hº_Sx T´BôxE™B}ó„Å—²ã´¾þž|^Õárt-°+ Y¾ÿŠYà(à9ÄM€WÂô…)ÁôrmÆQ'JÉãª_([3Â!®ÙazõëBoR““Ÿ‚‡(§Š®™q ïHsš‰˜ô?‚:]0¡È‡?kK|§ÎÎð«M6ÔOˆÄ8˜Äs´Ûkä_\ˆP®&^‰âÈV§¦üíÿ(K;öņM¸fx³˜†h°e[.¡hµI^L•bÛDÅú-3fz¢Øü©¾žy BVj™O~˦.<ãöQT=9âbõЧ÷ù™þ¿²¬ïݳ8Þ‘?KUë›õ…þUƒ°?@°3¬65¨Ê@F|f ˆ1UÉŽ\ö_ÖL°ÌÖ³{‹mœSlÄùeF9oƒ†³\äëŽõ}"n¯¶øîçž ×-!s_L)4/I=Í=×ÖšZ°òzô$^½yàÓ<|Û¾Øäyç`Æ7îÂÓÑYÎK/Å3gK„á_ƒ‰A|ž ÂR ü¾ÿ €·Œ‡ê}Ç?Ë‚X_`ö"£ÁÀò[ŽHO“"”Ž8èI›owšc‰¨·Uº½õHVº!¡«Uw~×<Ýl7_oûž}UG’)%àÞŠa?sôš2B5ÂpVŒpÞ,}‹Àv&ENqîúÖ½<_ùúc’í«6›ç‘êÆ³A¯gâµrHÐÆ]8ð …Û…@×”¡…"(ÝßÂmª_ÝY×_–ÎÏüøJ¯é¹àRA‹“ˆ#–ïø;l¹¯^ÿÓKV&œy7ðC;wžåefo®Þ€§^âNïþÝ€0ŸÃÕJñÀÑÎâÄ.ZIʸŸCV³«?½”ª«_l2-h[fî8ý×È[MÓ±È+lð%ÜcÌbôk6aØ.…ùE»¾Räi ßÜ5¸iΆúÊ¡Ÿ@KŠž…é ÌØhñWÎHig«¥šk*Ñ?êRç«/@^egÖ«å“U$ƦJ~æí¹(ˆ·š6CH½MÖ4”m _Öß›Ms åy‡ïÊ„À3îH@#²µ¹"[ª;ÓÇF¹:Å5ÖÚÞ=¢ Ÿy›xî]O‚·Ë£]àu–οØ^Ó¦öˆ ù‚"*Ö‹ÚZA¸h–æ5UY3|è%Ì.Âì_…l¾/oBµü6åû5 î?T­ÆÞ?"Ô€õÚ[&zÀÇ|ºô(#¼5¶\àa•àúï{ËéT5½ƒ²ëÊ0©ÿ7˜ÄœðԂ c “ ÙÆ²ù§/GQ,*Pcç¬Ør³®ýÈzl%”ch-owJƆxʃw†¾:k£ç×Ð"óÌ.0G& îm“ZqÓ'|àpÞÖVL(ȘÞÿÝÄŽŽÆNþÿ¶Š²Ì‘âs~êÒ.«ò¿QWÁÔfRýß@Fh‹üoXŽñ)ÌÃþ7£VH^„ÿ;ÈÎÚª;ïÿƒk4öÿyw$]ëùÿþˆ†ÈI¿;ÿÿÿRobject26àrr™€?ïÃ>^ƒl?ôµ>ö>^ƒl?Ô‹Š>Õ‹Š>^ƒl?ö>ôµ>^ƒl?•ã¶±ïÃ>^ƒl?ö¾ôµ>^ƒl?Õ‹Š¾Ô‹Š>^ƒl?ôµ¾ö>^ƒl?ïþ×tÊ2^ƒl?õµ¾ö¾^ƒl?Ö‹Š¾Ò‹Š¾^ƒl?!ö¾òµ¾^ƒl?IQa³ïþ^ƒl?ö>ôµ¾^ƒl?Ö‹Š>Ӌо^ƒl?öµ>ö¾^ƒl?ó5?ó5?t='?Ô‹Š>ó5?ÿÿÿ>?ó5?Ó‹Š>u='?ó5?¦÷(²ó5?ó5?Ջоt='?ó5?¿þÿÿ>ó5?t='¿Ó‹Š>ó5?ó5¿™ ;3ó5?u='¿Ñ‹Š¾ó5?¿üÿÿ¾ó5?Ú‹Š¾s='¿ó5?Ž*гó5¿ó5?Ô‹Š>t='¿ó5??ýÿÿ¾ó5?v='?Ì‹Š¾ó5?^ƒl?ïÃ>y‚Z?óµ>ïÃ>t='?t='?ïÃ>òµ>y‚Z?ïÃ>:Ä\²^ƒl?ïÃ>ôµ¾y‚Z?ïÃ>u='¿s='?ïÃ>y‚Z¿òµ>ïÃ>^ƒl¿ðbt3ïÃ>z‚Z¿ïµ¾ïÃ>w='¿r='¿ïÃ>ûµ¾w‚Z¿ïÃ>¼ý´^ƒl¿ïÃ>óµ>y‚Z¿ïÃ>v='?r='¿ïÃ>{‚Z?éµ¾ïÃ>€?.½;³^ƒl?ïÃ>.½;³ó5?ó5?.½;³ïÃ>_ƒl?.½;³ºôn²€?.½;³ïþ^ƒl?.½;³ô5¿ò5?.½;³_ƒl¿ïÃ>.½;³€¿ÒB„3.½;³_ƒl¿ïþ.½;³ö5¿ñ5¿.½;³ïþ]ƒl¿.½;³2´€¿.½;³ïÃ>^ƒl¿.½;³õ5?ñ5¿.½;³aƒl? ïþ.½;³^ƒl?ïþy‚Z?óµ>ïþt='?t='?ïþòµ>y‚Z?ïþ:Ä\²^ƒl?ïþôµ¾y‚Z?ïþu='¿s='?ïþy‚Z¿òµ>ïþ^ƒl¿ðbt3ïþz‚Z¿ïµ¾ïþw='¿r='¿ïþûµ¾w‚Z¿ïþ¼ý´^ƒl¿ïþóµ>y‚Z¿ïþv='?r='¿ïþ{‚Z?éµ¾ïþó5?ó5¿t='?Ô‹Š>ó5¿ÿÿÿ>?ó5¿Ó‹Š>u='?ó5¿¦÷(²ó5?ó5¿Õ‹Š¾t='?ó5¿¿þÿÿ>ó5¿t='¿Ó‹Š>ó5¿ó5¿™ ;3ó5¿u='¿Ñ‹Š¾ó5¿¿üÿÿ¾ó5¿Ú‹Š¾s='¿ó5¿Ž*гó5¿ó5¿Ô‹Š>t='¿ó5¿?ýÿÿ¾ó5¿v='?Ì‹Š¾ó5¿ïÃ>^ƒl¿õµ>ö>^ƒl¿Õ‹Š>Õ‹Š>^ƒl¿ö>õµ>^ƒl¿–ã¶±ïÃ>^ƒl¿ö¾õµ>^ƒl¿Ö‹Š¾Ô‹Š>^ƒl¿õµ¾ö>^ƒl¿ïþØtÊ2^ƒl¿öµ¾ö¾^ƒl¿×‹Š¾Ó‹Š¾^ƒl¿"ö¾óµ¾^ƒl¿JQa³ïþ^ƒl¿ö>õµ¾^ƒl¿×‹Š>Ӌо^ƒl¿÷µ>ö¾^ƒl¿€¿›²…ýG2€?áJÖ>¸·C9>zmh?e>©Ÿ>zmh?Â>ÆaÊ>zmh?w¸¼áJÖ>zmh?¸C9¾8”Á>zmh?©Ÿ¾e>zmh?ÆaʾŸÂ>zmh?áJÖ¾_¸¼zmh?9”Á¾´C9¾zmh?e¾©Ÿ¾zmh?¦Â¾Äaʾzmh?T¸<áJÖ¾zmh?¸C9>8”Á¾zmh?©Ÿ>e¾zmh?ÇaÊ>™Â¾zmh?Èà4?(ð<6%5?‡6&?WÄŽ>6%5?°|ü>ƒŽ?5%5?õ†>Ž(?6%5?ùï¼Èà4?6%5?WÄŽ¾‡6&?6%5?„Ž¿­|ü>5%5?Ž(¿õ†>6%5?Èà4¿€ï¼6%5?ˆ6&¿QÄŽ¾6%5?°|ü¾Ž¿7%5?û†¾(¿6%5?jï<Èà4¿5%5?VÄŽ>‡6&¿6%5?„Ž?¬|ü¾5%5?(?ñ†¾5%5?µul?. ;è,Ä>CûY?rJ·>é,Ä>EQ&?S(?é,Ä>ª²>tðZ?è,Ä>õ- »µul?è,Ä>rJ·¾AûY?è,Ä>R(¿DQ&?è,Ä>tðZ¿‹ª²>é,Ä>µul¿.- »è,Ä>CûY¿kJ·¾è,Ä>GQ&¿P(¿ë,Ä>“ª²¾rðZ¿é,Ä>©, ;µul¿è,Ä>rJ·>CûY¿é,Ä>U(?CQ&¿é,Ä>tðZ?‡ª²¾è,Ä>€?¨24 !›2^ƒl?ïÃ>mJ1±ô5?ó5?!!›²ïÃ>_ƒl?mJ1³€?mJ±2ïþ^ƒl?mJ1±ô5¿ó5?¼sDz_ƒl¿ïÃ>€¿ Ý2»sÇ2_ƒl¿ïþmJ±1ö5¿ñ5¿ !›²ïþ^ƒl¿WÆó³€¿mJ±2ïÃ>^ƒl¿mJ1±ö5?ò5¿Ó÷„²`ƒl?ïþnJ1±´ul?ö, »ê,ľrðZ?Žª²>ì,ľS(?EQ&?ë,ľqJ·>AûY?ë,ľ®- ;µul?ì,Ä¾Žª²¾rðZ?ì,ľEQ&¿Q(?ë,ľAûY¿rJ·>ì,ľµul¿N. ;ì,ľtðZ¿ˆª²¾ë,ľT(¿CQ&¿ë,ľuJ·¾@ûY¿ë,ľã. »µul¿ì,Ä¾Žª²>rðZ¿ì,ľFQ&?P(¿ë,ľCûY?jJ·¾ì,ľÈà4?sï¼6%5¿Ž(?÷†>6%5¿ƒŽ?¯|ü>6%5¿UÄŽ>‡6&?6%5¿Ÿï<Èà4?6%5¿÷†¾Ž(?6%5¿°|ü¾Ž?6%5¿‡6&¿UÄŽ>6%5¿Èà4¿ð<6%5¿Ž(¿ó†¾6%5¿„Ž¿¨|ü¾6%5¿YÄŽ¾†6&¿6%5¿7ð¼Èà4¿6%5¿÷†>Ž(¿6%5¿°|ü>Ž¿6%5¿ˆ6&?QÄŽ¾6%5¿ãJÖ>W¸¼zmh¿ÆaÊ> Â>zmh¿©Ÿ>e>zmh¿¸C9>8”Á>zmh¿n¸<áJÖ>zmh¿¡Â¾ÅaÊ>zmh¿e¾©Ÿ>zmh¿:”Á¾·C9>zmh¿ãJÖ¾¸Çaʾzmh¿e>©Ÿ¾zmh¿;”Á>³C9¾zmh¿¬èC±±€2€¿áJÖ>€=·C9>>zmh?@>w¸¼€>8”Á> >zmh?À>áJÖ¾à>´C9¾?zmh??T¸< ?8”Á¾0?zmh?@?Èà4?P?WÄŽ>`?5%5?p?ùï¼€?‡6&?>5%5?€=>Èà4¿>>QÄŽ¾@>>7%5?€>>jï< >>‡6&¿À>>5%5?à>>µul??>rJ·>?>é,Ä> ?>õ- »0?>AûY?@?>è,Ä>P?>µul¿`?>kJ·¾p?>ë,Ä>€?>©, ;€>CûY¿€=€>é,Ä>>€>€?@>€>ïÃ>€>€>!!›² >€>mJ1³À>€>^ƒl?à>€>¼sDz?€>€¿?€>ïþ ?€> !›²0?€>WÆó³@?€>^ƒl¿P?€>Ó÷„²`?€>´ul?p?€>Žª²>€?€>ë,ľÀ>®- ;€=À>rðZ?>À>ë,ľ@>À>µul¿€>À>ˆª²¾ >À>ë,ľÀ>À>ã. »à>À>rðZ¿?À>ë,ľ?À>Èà4? ?À>÷†>0?À>6%5¿@?À>Ÿï<P?À>Ž(?`?À>6%5¿p?À>Èà4¿€?À>ó†¾?6%5¿€=?7ð¼>?Ž(¿@>?6%5¿€>?ãJÖ> >? Â>À>?zmh¿à>?n¸<??ÅaÊ>??zmh¿ ??ãJÖ¾0??›Â¾@??zmh¿P??¦¸¼`??Çaʾp??zmh¿€??¬èC± ?€= ?> ?@> ?$øô €> ? > ?À> ?à> ?? ?$øô ? ? ? ?0? ?@? ?P? ?$øô `? ?p? ?€? ?@?€=@?$øô >@?@>@?€>@? >@?À>@?$øô à>@??@??@? ?@?0?@?$øô @?@?P?@?`?@?p?@?€?@?$øô `?€=`?>`?@>`?€>`?$øô  >`?À>`?à>`??`??`?$øô ?`?0?`?@?`?P?`?`?`?$øô p?`?€?`?€?€=€?>€?$øô @>€?€>€? >€?À>€?à>€?$øô ?€??€? ?€?0?€?@?€?$øô P?€?`?€?p?€?€?€?Èðh®¶ `¥©Ãìqð1OP£&Ú`í[¹>¨- ±9…*¹¼D€”W·ÑNÕSE«†D,Ř¡â³D&Où.Ð’Ä)8ìUâï¢g> r,Ä¡‡Ž .\1ó€˜O¿'aÍEóìAÔY 3®%ý§]¬”ö<¢/’|B—0ˆ?%Ú•²®<¤Ì3S MU²›¹µ^F!ïYï[Û4ävAŠ´ÍkËÒäeŸu¿åŸ08râ¾xÂìSn ÈJVȬ¡„˜…ß̬³Íç­TÖ ˆûÉ´–eq#î»’bpOðVà®p†ÔÛÍ* þ±íl ’`ÿ›5ðòdN–ë'ëd³‰MPòÀ>Ûg†èènd™ÃHÚ‚+²jë gæŽÄÝåÞ!”’Yæe^¯j…ìÿÞê(àØ§”!äégQ˜JÕE6EÙ[øpR6d›ÕÏ0£jìÏKÒá(T ¤ÏÞ‘ ÷.ñÆÑqw‹W8F²-{hº_Sx T´BôxE™B}ó„Å—²ã´¾þž|^Õárt-°+ Y¾ÿŠYà(à9ÄM€WÂô…)ÁôrmÆQ'JÉãª_([3Â!®ÙazõëBoR““Ÿ‚‡(§Š®™q ïHsš‰˜ô?‚:]0¡È‡?kK|§ÎÎð«M6ÔOˆÄ8˜Äs´Ûkä_\ˆP®&^‰âÈV§¦üíÿ(K;öņM¸fx³˜†h°e[.¡hµI^L•bÛDÅú-3fz¢Øü©¾žy BVj™O~˦.<ãöQT=9âbõЧ÷ù™þ¿²¬ïݳ8Þ‘?KUë›õ…þUƒ°?@°3¬65¨Ê@F|f ˆ1UÉŽ\ö_ÖL°ÌÖ³{‹mœSlÄùeF9oƒ†³\äëŽõ}"n¯¶øîçž ×-!s_L)4/I=Í=×ÖšZ°òzô$^½yàÓ<|Û¾Øäyç`Æ7îÂÓÑYÎK/Å3gK„á_ƒ‰A|ž ÂR ü¾ÿ €·Œ‡ê}Ç?Ë‚X_`ö"£ÁÀò[ŽHO“"”Ž8èI›owšc‰¨·Uº½õHVº!¡«Uw~×<Ýl7_oûž}UG’)%àÞŠa?sôš2B5ÂpVŒpÞ,}‹Àv&ENqîúÖ½<_ùúc’í«6›ç‘êÆ³A¯gâµrHÐÆ]8ð …Û…@×”¡…"(ÝßÂmª_ÝY×_–ÎÏüøJ¯é¹àRA‹“ˆ#–ïø;l¹¯^ÿÓKV&œy7ðC;wžåefo®Þ€§^âNïþÝ€0ŸÃÕJñÀÑÎâÄ.ZIʸŸCV³«?½”ª«_l2-h[fî8ý×È[MÓ±È+lð%ÜcÌbôk6aØ.…ùE»¾Räi ßÜ5¸iΆúÊ¡Ÿ@KŠž…é ÌØhñWÎHig«¥šk*Ñ?êRç«/@^egÖ«å“U$ƦJ~æí¹(ˆ·š6CH½MÖ4”m _Öß›Ms åy‡ïÊ„À3îH@#²µ¹"[ª;ÓÇF¹:Å5ÖÚÞ=¢ Ÿy›xî]O‚·Ë£]àu–οØ^Ó¦öˆ ù‚"*Ö‹ÚZA¸h–æ5UY3|è%Ì.Âì_…l¾/oBµü6åû5 î?T­ÆÞ?"Ô€õÚ[&zÀÇ|ºô(#¼5¶\àa•àúï{ËéT5½ƒ²ëÊ0©ÿ7˜ÄœðԂ c “ ÙÆ²ù§/GQ,*Pcç¬Ør³®ýÈzl%”ch-owJƆxʃw†¾:k£ç×Ð"óÌ.0G& îm“ZqÓ'|àpÞÖVL(ȘÞÿÝÄŽŽÆNþÿ¶Š²Ì‘âs~êÒ.«ò¿QWÁÔfRýß@Fh‹üoXŽñ)ÌÃþ7£VH^„ÿ;ÈÎÚª;ïÿƒk4öÿyw$]ëùÿþˆ†ÈI¿;ÿÿÿRobject24àrr™€?ïÃ>^ƒl?ôµ>ö>^ƒl?Ô‹Š>Õ‹Š>^ƒl?ö>ôµ>^ƒl?•ã¶±ïÃ>^ƒl?ö¾ôµ>^ƒl?Õ‹Š¾Ô‹Š>^ƒl?ôµ¾ö>^ƒl?ïþ×tÊ2^ƒl?õµ¾ö¾^ƒl?Ö‹Š¾Ò‹Š¾^ƒl?!ö¾òµ¾^ƒl?IQa³ïþ^ƒl?ö>ôµ¾^ƒl?Ö‹Š>Ӌо^ƒl?öµ>ö¾^ƒl?ó5?ó5?t='?Ô‹Š>ó5?ÿÿÿ>?ó5?Ó‹Š>u='?ó5?¦÷(²ó5?ó5?Ջоt='?ó5?¿þÿÿ>ó5?t='¿Ó‹Š>ó5?ó5¿™ ;3ó5?u='¿Ñ‹Š¾ó5?¿üÿÿ¾ó5?Ú‹Š¾s='¿ó5?Ž*гó5¿ó5?Ô‹Š>t='¿ó5??ýÿÿ¾ó5?v='?Ì‹Š¾ó5?^ƒl?ïÃ>y‚Z?óµ>ïÃ>t='?t='?ïÃ>òµ>y‚Z?ïÃ>:Ä\²^ƒl?ïÃ>ôµ¾y‚Z?ïÃ>u='¿s='?ïÃ>y‚Z¿òµ>ïÃ>^ƒl¿ðbt3ïÃ>z‚Z¿ïµ¾ïÃ>w='¿r='¿ïÃ>ûµ¾w‚Z¿ïÃ>¼ý´^ƒl¿ïÃ>óµ>y‚Z¿ïÃ>v='?r='¿ïÃ>{‚Z?éµ¾ïÃ>€?.½;³^ƒl?ïÃ>.½;³ó5?ó5?.½;³ïÃ>_ƒl?.½;³ºôn²€?.½;³ïþ^ƒl?.½;³ô5¿ò5?.½;³_ƒl¿ïÃ>.½;³€¿ÒB„3.½;³_ƒl¿ïþ.½;³ö5¿ñ5¿.½;³ïþ]ƒl¿.½;³2´€¿.½;³ïÃ>^ƒl¿.½;³õ5?ñ5¿.½;³aƒl? ïþ.½;³^ƒl?ïþy‚Z?óµ>ïþt='?t='?ïþòµ>y‚Z?ïþ:Ä\²^ƒl?ïþôµ¾y‚Z?ïþu='¿s='?ïþy‚Z¿òµ>ïþ^ƒl¿ðbt3ïþz‚Z¿ïµ¾ïþw='¿r='¿ïþûµ¾w‚Z¿ïþ¼ý´^ƒl¿ïþóµ>y‚Z¿ïþv='?r='¿ïþ{‚Z?éµ¾ïþó5?ó5¿t='?Ô‹Š>ó5¿ÿÿÿ>?ó5¿Ó‹Š>u='?ó5¿¦÷(²ó5?ó5¿Õ‹Š¾t='?ó5¿¿þÿÿ>ó5¿t='¿Ó‹Š>ó5¿ó5¿™ ;3ó5¿u='¿Ñ‹Š¾ó5¿¿üÿÿ¾ó5¿Ú‹Š¾s='¿ó5¿Ž*гó5¿ó5¿Ô‹Š>t='¿ó5¿?ýÿÿ¾ó5¿v='?Ì‹Š¾ó5¿ïÃ>^ƒl¿õµ>ö>^ƒl¿Õ‹Š>Õ‹Š>^ƒl¿ö>õµ>^ƒl¿–ã¶±ïÃ>^ƒl¿ö¾õµ>^ƒl¿Ö‹Š¾Ô‹Š>^ƒl¿õµ¾ö>^ƒl¿ïþØtÊ2^ƒl¿öµ¾ö¾^ƒl¿×‹Š¾Ó‹Š¾^ƒl¿"ö¾óµ¾^ƒl¿JQa³ïþ^ƒl¿ö>õµ¾^ƒl¿×‹Š>Ӌо^ƒl¿÷µ>ö¾^ƒl¿€¿›²…ýG2€?áJÖ>¸·C9>zmh?e>©Ÿ>zmh?Â>ÆaÊ>zmh?w¸¼áJÖ>zmh?¸C9¾8”Á>zmh?©Ÿ¾e>zmh?ÆaʾŸÂ>zmh?áJÖ¾_¸¼zmh?9”Á¾´C9¾zmh?e¾©Ÿ¾zmh?¦Â¾Äaʾzmh?T¸<áJÖ¾zmh?¸C9>8”Á¾zmh?©Ÿ>e¾zmh?ÇaÊ>™Â¾zmh?Èà4?(ð<6%5?‡6&?WÄŽ>6%5?°|ü>ƒŽ?5%5?õ†>Ž(?6%5?ùï¼Èà4?6%5?WÄŽ¾‡6&?6%5?„Ž¿­|ü>5%5?Ž(¿õ†>6%5?Èà4¿€ï¼6%5?ˆ6&¿QÄŽ¾6%5?°|ü¾Ž¿7%5?û†¾(¿6%5?jï<Èà4¿5%5?VÄŽ>‡6&¿6%5?„Ž?¬|ü¾5%5?(?ñ†¾5%5?µul?. ;è,Ä>CûY?rJ·>é,Ä>EQ&?S(?é,Ä>ª²>tðZ?è,Ä>õ- »µul?è,Ä>rJ·¾AûY?è,Ä>R(¿DQ&?è,Ä>tðZ¿‹ª²>é,Ä>µul¿.- »è,Ä>CûY¿kJ·¾è,Ä>GQ&¿P(¿ë,Ä>“ª²¾rðZ¿é,Ä>©, ;µul¿è,Ä>rJ·>CûY¿é,Ä>U(?CQ&¿é,Ä>tðZ?‡ª²¾è,Ä>€?¨24 !›2^ƒl?ïÃ>mJ1±ô5?ó5?!!›²ïÃ>_ƒl?mJ1³€?mJ±2ïþ^ƒl?mJ1±ô5¿ó5?¼sDz_ƒl¿ïÃ>€¿ Ý2»sÇ2_ƒl¿ïþmJ±1ö5¿ñ5¿ !›²ïþ^ƒl¿WÆó³€¿mJ±2ïÃ>^ƒl¿mJ1±ö5?ò5¿Ó÷„²`ƒl?ïþnJ1±´ul?ö, »ê,ľrðZ?Žª²>ì,ľS(?EQ&?ë,ľqJ·>AûY?ë,ľ®- ;µul?ì,Ä¾Žª²¾rðZ?ì,ľEQ&¿Q(?ë,ľAûY¿rJ·>ì,ľµul¿N. ;ì,ľtðZ¿ˆª²¾ë,ľT(¿CQ&¿ë,ľuJ·¾@ûY¿ë,ľã. »µul¿ì,Ä¾Žª²>rðZ¿ì,ľFQ&?P(¿ë,ľCûY?jJ·¾ì,ľÈà4?sï¼6%5¿Ž(?÷†>6%5¿ƒŽ?¯|ü>6%5¿UÄŽ>‡6&?6%5¿Ÿï<Èà4?6%5¿÷†¾Ž(?6%5¿°|ü¾Ž?6%5¿‡6&¿UÄŽ>6%5¿Èà4¿ð<6%5¿Ž(¿ó†¾6%5¿„Ž¿¨|ü¾6%5¿YÄŽ¾†6&¿6%5¿7ð¼Èà4¿6%5¿÷†>Ž(¿6%5¿°|ü>Ž¿6%5¿ˆ6&?QÄŽ¾6%5¿ãJÖ>W¸¼zmh¿ÆaÊ> Â>zmh¿©Ÿ>e>zmh¿¸C9>8”Á>zmh¿n¸<áJÖ>zmh¿¡Â¾ÅaÊ>zmh¿e¾©Ÿ>zmh¿:”Á¾·C9>zmh¿ãJÖ¾¸Çaʾzmh¿e>©Ÿ¾zmh¿;”Á>³C9¾zmh¿¬èC±±€2€¿€=>@>€> >À>à>?? ?0?@?P?`?p?€?>€=>>>@>>€>> >>À>>à>>?>?> ?>0?>@?>P?>`?>p?>€?>€>€=€>>€>@>€>€>€> >€>À>€>à>€>?€>?€> ?€>0?€>@?€>P?€>`?€>p?€>€?€>À>€=À>>À>@>À>€>À> >À>À>À>à>À>?À>?À> ?À>0?À>@?À>P?À>`?À>p?À>€?À>?€=?>?@>?€>? >?À>?à>????? ??0??@??P??`??p??€?? ?€= ?> ?@> ?€> ? > ?À> ?à> ?? ?? ? ? ?0? ?@? ?P? ?`? ?p? ?€? ?@?€=@?>@?@>@?€>@? >@?À>@?à>@??@??@? ?@?0?@?@?@?P?@?`?@?p?@?€?@?`?€=`?>`?@>`?€>`? >`?À>`?à>`??`??`? ?`?0?`?@?`?P?`?`?`?p?`?€?`?€?€=€?>€?@>€?€>€? >€?À>€?à>€??€??€? ?€?0?€?@?€?P?€?`?€?p?€?€?€?Èðh®¶ `¥©Ãìqð1OP£&Ú`í[¹>¨- ±9…*¹¼D€”W·ÑNÕSE«†D,Ř¡â³D&Où.Ð’Ä)8ìUâï¢g> r,Ä¡‡Ž .\1ó€˜O¿'aÍEóìAÔY 3®%ý§]¬”ö<¢/’|B—0ˆ?%Ú•²®<¤Ì3S MU²›¹µ^F!ïYï[Û4ävAŠ´ÍkËÒäeŸu¿åŸ08râ¾xÂìSn ÈJVȬ¡„˜…ß̬³Íç­TÖ ˆûÉ´–eq#î»’bpOðVà®p†ÔÛÍ* þ±íl ’`ÿ›5ðòdN–ë'ëd³‰MPòÀ>Ûg†èènd™ÃHÚ‚+²jë gæŽÄÝåÞ!”’Yæe^¯j…ìÿÞê(àØ§”!äégQ˜JÕE6EÙ[øpR6d›ÕÏ0£jìÏKÒá(T ¤ÏÞ‘ ÷.ñÆÑqw‹W8F²-{hº_Sx T´BôxE™B}ó„Å—²ã´¾þž|^Õárt-°+ Y¾ÿŠYà(à9ÄM€WÂô…)ÁôrmÆQ'JÉãª_([3Â!®ÙazõëBoR““Ÿ‚‡(§Š®™q ïHsš‰˜ô?‚:]0¡È‡?kK|§ÎÎð«M6ÔOˆÄ8˜Äs´Ûkä_\ˆP®&^‰âÈV§¦üíÿ(K;öņM¸fx³˜†h°e[.¡hµI^L•bÛDÅú-3fz¢Øü©¾žy BVj™O~˦.<ãöQT=9âbõЧ÷ù™þ¿²¬ïݳ8Þ‘?KUë›õ…þUƒ°?@°3¬65¨Ê@F|f ˆ1UÉŽ\ö_ÖL°ÌÖ³{‹mœSlÄùeF9oƒ†³\äëŽõ}"n¯¶øîçž ×-!s_L)4/I=Í=×ÖšZ°òzô$^½yàÓ<|Û¾Øäyç`Æ7îÂÓÑYÎK/Å3gK„á_ƒ‰A|ž ÂR ü¾ÿ €·Œ‡ê}Ç?Ë‚X_`ö"£ÁÀò[ŽHO“"”Ž8èI›owšc‰¨·Uº½õHVº!¡«Uw~×<Ýl7_oûž}UG’)%àÞŠa?sôš2B5ÂpVŒpÞ,}‹Àv&ENqîúÖ½<_ùúc’í«6›ç‘êÆ³A¯gâµrHÐÆ]8ð …Û…@×”¡…"(ÝßÂmª_ÝY×_–ÎÏüøJ¯é¹àRA‹“ˆ#–ïø;l¹¯^ÿÓKV&œy7ðC;wžåefo®Þ€§^âNïþÝ€0ŸÃÕJñÀÑÎâÄ.ZIʸŸCV³«?½”ª«_l2-h[fî8ý×È[MÓ±È+lð%ÜcÌbôk6aØ.…ùE»¾Räi ßÜ5¸iΆúÊ¡Ÿ@KŠž…é ÌØhñWÎHig«¥šk*Ñ?êRç«/@^egÖ«å“U$ƦJ~æí¹(ˆ·š6CH½MÖ4”m _Öß›Ms åy‡ïÊ„À3îH@#²µ¹"[ª;ÓÇF¹:Å5ÖÚÞ=¢ Ÿy›xî]O‚·Ë£]àu–οØ^Ó¦öˆ ù‚"*Ö‹ÚZA¸h–æ5UY3|è%Ì.Âì_…l¾/oBµü6åû5 î?T­ÆÞ?"Ô€õÚ[&zÀÇ|ºô(#¼5¶\àa•àúï{ËéT5½ƒ²ëÊ0©ÿ7˜ÄœðԂ c “ ÙÆ²ù§/GQ,*Pcç¬Ør³®ýÈzl%”ch-owJƆxʃw†¾:k£ç×Ð"óÌ.0G& îm“ZqÓ'|àpÞÖVL(ȘÞÿÝÄŽŽÆNþÿ¶Š²Ì‘âs~êÒ.«ò¿QWÁÔfRýß@Fh‹üoXŽñ)ÌÃþ7£VH^„ÿ;ÈÎÚª;ïÿƒk4öÿyw$]ëùÿþˆ†ÈI¿;ÿÿÿRobject22àrr™€?ïÃ>^ƒl?ôµ>ö>^ƒl?Ô‹Š>Õ‹Š>^ƒl?ö>ôµ>^ƒl?•ã¶±ïÃ>^ƒl?ö¾ôµ>^ƒl?Õ‹Š¾Ô‹Š>^ƒl?ôµ¾ö>^ƒl?ïþ×tÊ2^ƒl?õµ¾ö¾^ƒl?Ö‹Š¾Ò‹Š¾^ƒl?!ö¾òµ¾^ƒl?IQa³ïþ^ƒl?ö>ôµ¾^ƒl?Ö‹Š>Ӌо^ƒl?öµ>ö¾^ƒl?ó5?ó5?t='?Ô‹Š>ó5?ÿÿÿ>?ó5?Ó‹Š>u='?ó5?¦÷(²ó5?ó5?Ջоt='?ó5?¿þÿÿ>ó5?t='¿Ó‹Š>ó5?ó5¿™ ;3ó5?u='¿Ñ‹Š¾ó5?¿üÿÿ¾ó5?Ú‹Š¾s='¿ó5?Ž*гó5¿ó5?Ô‹Š>t='¿ó5??ýÿÿ¾ó5?v='?Ì‹Š¾ó5?^ƒl?ïÃ>y‚Z?óµ>ïÃ>t='?t='?ïÃ>òµ>y‚Z?ïÃ>:Ä\²^ƒl?ïÃ>ôµ¾y‚Z?ïÃ>u='¿s='?ïÃ>y‚Z¿òµ>ïÃ>^ƒl¿ðbt3ïÃ>z‚Z¿ïµ¾ïÃ>w='¿r='¿ïÃ>ûµ¾w‚Z¿ïÃ>¼ý´^ƒl¿ïÃ>óµ>y‚Z¿ïÃ>v='?r='¿ïÃ>{‚Z?éµ¾ïÃ>€?.½;³^ƒl?ïÃ>.½;³ó5?ó5?.½;³ïÃ>_ƒl?.½;³ºôn²€?.½;³ïþ^ƒl?.½;³ô5¿ò5?.½;³_ƒl¿ïÃ>.½;³€¿ÒB„3.½;³_ƒl¿ïþ.½;³ö5¿ñ5¿.½;³ïþ]ƒl¿.½;³2´€¿.½;³ïÃ>^ƒl¿.½;³õ5?ñ5¿.½;³aƒl? ïþ.½;³^ƒl?ïþy‚Z?óµ>ïþt='?t='?ïþòµ>y‚Z?ïþ:Ä\²^ƒl?ïþôµ¾y‚Z?ïþu='¿s='?ïþy‚Z¿òµ>ïþ^ƒl¿ðbt3ïþz‚Z¿ïµ¾ïþw='¿r='¿ïþûµ¾w‚Z¿ïþ¼ý´^ƒl¿ïþóµ>y‚Z¿ïþv='?r='¿ïþ{‚Z?éµ¾ïþó5?ó5¿t='?Ô‹Š>ó5¿ÿÿÿ>?ó5¿Ó‹Š>u='?ó5¿¦÷(²ó5?ó5¿Õ‹Š¾t='?ó5¿¿þÿÿ>ó5¿t='¿Ó‹Š>ó5¿ó5¿™ ;3ó5¿u='¿Ñ‹Š¾ó5¿¿üÿÿ¾ó5¿Ú‹Š¾s='¿ó5¿Ž*гó5¿ó5¿Ô‹Š>t='¿ó5¿?ýÿÿ¾ó5¿v='?Ì‹Š¾ó5¿ïÃ>^ƒl¿õµ>ö>^ƒl¿Õ‹Š>Õ‹Š>^ƒl¿ö>õµ>^ƒl¿–ã¶±ïÃ>^ƒl¿ö¾õµ>^ƒl¿Ö‹Š¾Ô‹Š>^ƒl¿õµ¾ö>^ƒl¿ïþØtÊ2^ƒl¿öµ¾ö¾^ƒl¿×‹Š¾Ó‹Š¾^ƒl¿"ö¾óµ¾^ƒl¿JQa³ïþ^ƒl¿ö>õµ¾^ƒl¿×‹Š>Ӌо^ƒl¿÷µ>ö¾^ƒl¿€¿›²…ýG2€?áJÖ>¸·C9>zmh?e>©Ÿ>zmh?Â>ÆaÊ>zmh?w¸¼áJÖ>zmh?¸C9¾8”Á>zmh?©Ÿ¾e>zmh?ÆaʾŸÂ>zmh?áJÖ¾_¸¼zmh?9”Á¾´C9¾zmh?e¾©Ÿ¾zmh?¦Â¾Äaʾzmh?T¸<áJÖ¾zmh?¸C9>8”Á¾zmh?©Ÿ>e¾zmh?ÇaÊ>™Â¾zmh?Èà4?(ð<6%5?‡6&?WÄŽ>6%5?°|ü>ƒŽ?5%5?õ†>Ž(?6%5?ùï¼Èà4?6%5?WÄŽ¾‡6&?6%5?„Ž¿­|ü>5%5?Ž(¿õ†>6%5?Èà4¿€ï¼6%5?ˆ6&¿QÄŽ¾6%5?°|ü¾Ž¿7%5?û†¾(¿6%5?jï<Èà4¿5%5?VÄŽ>‡6&¿6%5?„Ž?¬|ü¾5%5?(?ñ†¾5%5?µul?. ;è,Ä>CûY?rJ·>é,Ä>EQ&?S(?é,Ä>ª²>tðZ?è,Ä>õ- »µul?è,Ä>rJ·¾AûY?è,Ä>R(¿DQ&?è,Ä>tðZ¿‹ª²>é,Ä>µul¿.- »è,Ä>CûY¿kJ·¾è,Ä>GQ&¿P(¿ë,Ä>“ª²¾rðZ¿é,Ä>©, ;µul¿è,Ä>rJ·>CûY¿é,Ä>U(?CQ&¿é,Ä>tðZ?‡ª²¾è,Ä>€?¨24 !›2^ƒl?ïÃ>mJ1±ô5?ó5?!!›²ïÃ>_ƒl?mJ1³€?mJ±2ïþ^ƒl?mJ1±ô5¿ó5?¼sDz_ƒl¿ïÃ>€¿ Ý2»sÇ2_ƒl¿ïþmJ±1ö5¿ñ5¿ !›²ïþ^ƒl¿WÆó³€¿mJ±2ïÃ>^ƒl¿mJ1±ö5?ò5¿Ó÷„²`ƒl?ïþnJ1±´ul?ö, »ê,ľrðZ?Žª²>ì,ľS(?EQ&?ë,ľqJ·>AûY?ë,ľ®- ;µul?ì,Ä¾Žª²¾rðZ?ì,ľEQ&¿Q(?ë,ľAûY¿rJ·>ì,ľµul¿N. ;ì,ľtðZ¿ˆª²¾ë,ľT(¿CQ&¿ë,ľuJ·¾@ûY¿ë,ľã. »µul¿ì,Ä¾Žª²>rðZ¿ì,ľFQ&?P(¿ë,ľCûY?jJ·¾ì,ľÈà4?sï¼6%5¿Ž(?÷†>6%5¿ƒŽ?¯|ü>6%5¿UÄŽ>‡6&?6%5¿Ÿï<Èà4?6%5¿÷†¾Ž(?6%5¿°|ü¾Ž?6%5¿‡6&¿UÄŽ>6%5¿Èà4¿ð<6%5¿Ž(¿ó†¾6%5¿„Ž¿¨|ü¾6%5¿YÄŽ¾†6&¿6%5¿7ð¼Èà4¿6%5¿÷†>Ž(¿6%5¿°|ü>Ž¿6%5¿ˆ6&?QÄŽ¾6%5¿ãJÖ>W¸¼zmh¿ÆaÊ> Â>zmh¿©Ÿ>e>zmh¿¸C9>8”Á>zmh¿n¸<áJÖ>zmh¿¡Â¾ÅaÊ>zmh¿e¾©Ÿ>zmh¿:”Á¾·C9>zmh¿ãJÖ¾¸Çaʾzmh¿e>©Ÿ¾zmh¿;”Á>³C9¾zmh¿¬èC±±€2€¿€=>@>€> >À>à>?? ?0?@?P?`?p?€?>€=>>>@>>€>> >>À>>à>>?>?> ?>0?>@?>P?>`?>p?>€?>€>€=€>>€>@>€>€>€> >€>À>€>à>€>?€>?€> ?€>0?€>@?€>P?€>`?€>p?€>€?€>À>€=À>>À>@>À>€>À> >À>À>À>à>À>?À>?À> ?À>0?À>@?À>P?À>`?À>p?À>€?À>?€=?>?@>?€>? >?À>?à>????? ??0??@??P??`??p??€?? ?€= ?> ?@> ?€> ? > ?À> ?à> ?? ?? ? ? ?0? ?@? ?P? ?`? ?p? ?€? ?@?€=@?>@?@>@?€>@? >@?À>@?à>@??@??@? ?@?0?@?@?@?P?@?`?@?p?@?€?@?`?€=`?>`?@>`?€>`? >`?À>`?à>`??`??`? ?`?0?`?@?`?P?`?`?`?p?`?€?`?€?€=€?>€?@>€?€>€? >€?À>€?à>€??€??€? ?€?0?€?@?€?P?€?`?€?p?€?€?€?Èðh®¶ `¥©Ãìqð1OP£&Ú`í[¹>¨- ±9…*¹¼D€”W·ÑNÕSE«†D,Ř¡â³D&Où.Ð’Ä)8ìUâï¢g> r,Ä¡‡Ž .\1ó€˜O¿'aÍEóìAÔY 3®%ý§]¬”ö<¢/’|B—0ˆ?%Ú•²®<¤Ì3S MU²›¹µ^F!ïYï[Û4ävAŠ´ÍkËÒäeŸu¿åŸ08râ¾xÂìSn ÈJVȬ¡„˜…ß̬³Íç­TÖ ˆûÉ´–eq#î»’bpOðVà®p†ÔÛÍ* þ±íl ’`ÿ›5ðòdN–ë'ëd³‰MPòÀ>Ûg†èènd™ÃHÚ‚+²jë gæŽÄÝåÞ!”’Yæe^¯j…ìÿÞê(àØ§”!äégQ˜JÕE6EÙ[øpR6d›ÕÏ0£jìÏKÒá(T ¤ÏÞ‘ ÷.ñÆÑqw‹W8F²-{hº_Sx T´BôxE™B}ó„Å—²ã´¾þž|^Õárt-°+ Y¾ÿŠYà(à9ÄM€WÂô…)ÁôrmÆQ'JÉãª_([3Â!®ÙazõëBoR““Ÿ‚‡(§Š®™q ïHsš‰˜ô?‚:]0¡È‡?kK|§ÎÎð«M6ÔOˆÄ8˜Äs´Ûkä_\ˆP®&^‰âÈV§¦üíÿ(K;öņM¸fx³˜†h°e[.¡hµI^L•bÛDÅú-3fz¢Øü©¾žy BVj™O~˦.<ãöQT=9âbõЧ÷ù™þ¿²¬ïݳ8Þ‘?KUë›õ…þUƒ°?@°3¬65¨Ê@F|f ˆ1UÉŽ\ö_ÖL°ÌÖ³{‹mœSlÄùeF9oƒ†³\äëŽõ}"n¯¶øîçž ×-!s_L)4/I=Í=×ÖšZ°òzô$^½yàÓ<|Û¾Øäyç`Æ7îÂÓÑYÎK/Å3gK„á_ƒ‰A|ž ÂR ü¾ÿ €·Œ‡ê}Ç?Ë‚X_`ö"£ÁÀò[ŽHO“"”Ž8èI›owšc‰¨·Uº½õHVº!¡«Uw~×<Ýl7_oûž}UG’)%àÞŠa?sôš2B5ÂpVŒpÞ,}‹Àv&ENqîúÖ½<_ùúc’í«6›ç‘êÆ³A¯gâµrHÐÆ]8ð …Û…@×”¡…"(ÝßÂmª_ÝY×_–ÎÏüøJ¯é¹àRA‹“ˆ#–ïø;l¹¯^ÿÓKV&œy7ðC;wžåefo®Þ€§^âNïþÝ€0ŸÃÕJñÀÑÎâÄ.ZIʸŸCV³«?½”ª«_l2-h[fî8ý×È[MÓ±È+lð%ÜcÌbôk6aØ.…ùE»¾Räi ßÜ5¸iΆúÊ¡Ÿ@KŠž…é ÌØhñWÎHig«¥šk*Ñ?êRç«/@^egÖ«å“U$ƦJ~æí¹(ˆ·š6CH½MÖ4”m _Öß›Ms åy‡ïÊ„À3îH@#²µ¹"[ª;ÓÇF¹:Å5ÖÚÞ=¢ Ÿy›xî]O‚·Ë£]àu–οØ^Ó¦öˆ ù‚"*Ö‹ÚZA¸h–æ5UY3|è%Ì.Âì_…l¾/oBµü6åû5 î?T­ÆÞ?"Ô€õÚ[&zÀÇ|ºô(#¼5¶\àa•àúï{ËéT5½ƒ²ëÊ0©ÿ7˜ÄœðԂ c “ ÙÆ²ù§/GQ,*Pcç¬Ør³®ýÈzl%”ch-owJƆxʃw†¾:k£ç×Ð"óÌ.0G& îm“ZqÓ'|àpÞÖVL(ȘÞÿÝÄŽŽÆNþÿ¶Š²Ì‘âs~êÒ.«ò¿QWÁÔfRýß@Fh‹üoXŽñ)ÌÃþ7£VH^„ÿ;ÈÎÚª;ïÿƒk4öÿyw$]ëùÿþˆ†ÈI¿;ÿÿÿRobject20àrr™€?ïÃ>^ƒl?ôµ>ö>^ƒl?Ô‹Š>Õ‹Š>^ƒl?ö>ôµ>^ƒl?•ã¶±ïÃ>^ƒl?ö¾ôµ>^ƒl?Õ‹Š¾Ô‹Š>^ƒl?ôµ¾ö>^ƒl?ïþ×tÊ2^ƒl?õµ¾ö¾^ƒl?Ö‹Š¾Ò‹Š¾^ƒl?!ö¾òµ¾^ƒl?IQa³ïþ^ƒl?ö>ôµ¾^ƒl?Ö‹Š>Ӌо^ƒl?öµ>ö¾^ƒl?ó5?ó5?t='?Ô‹Š>ó5?ÿÿÿ>?ó5?Ó‹Š>u='?ó5?¦÷(²ó5?ó5?Ջоt='?ó5?¿þÿÿ>ó5?t='¿Ó‹Š>ó5?ó5¿™ ;3ó5?u='¿Ñ‹Š¾ó5?¿üÿÿ¾ó5?Ú‹Š¾s='¿ó5?Ž*гó5¿ó5?Ô‹Š>t='¿ó5??ýÿÿ¾ó5?v='?Ì‹Š¾ó5?^ƒl?ïÃ>y‚Z?óµ>ïÃ>t='?t='?ïÃ>òµ>y‚Z?ïÃ>:Ä\²^ƒl?ïÃ>ôµ¾y‚Z?ïÃ>u='¿s='?ïÃ>y‚Z¿òµ>ïÃ>^ƒl¿ðbt3ïÃ>z‚Z¿ïµ¾ïÃ>w='¿r='¿ïÃ>ûµ¾w‚Z¿ïÃ>¼ý´^ƒl¿ïÃ>óµ>y‚Z¿ïÃ>v='?r='¿ïÃ>{‚Z?éµ¾ïÃ>€?.½;³^ƒl?ïÃ>.½;³ó5?ó5?.½;³ïÃ>_ƒl?.½;³ºôn²€?.½;³ïþ^ƒl?.½;³ô5¿ò5?.½;³_ƒl¿ïÃ>.½;³€¿ÒB„3.½;³_ƒl¿ïþ.½;³ö5¿ñ5¿.½;³ïþ]ƒl¿.½;³2´€¿.½;³ïÃ>^ƒl¿.½;³õ5?ñ5¿.½;³aƒl? ïþ.½;³^ƒl?ïþy‚Z?óµ>ïþt='?t='?ïþòµ>y‚Z?ïþ:Ä\²^ƒl?ïþôµ¾y‚Z?ïþu='¿s='?ïþy‚Z¿òµ>ïþ^ƒl¿ðbt3ïþz‚Z¿ïµ¾ïþw='¿r='¿ïþûµ¾w‚Z¿ïþ¼ý´^ƒl¿ïþóµ>y‚Z¿ïþv='?r='¿ïþ{‚Z?éµ¾ïþó5?ó5¿t='?Ô‹Š>ó5¿ÿÿÿ>?ó5¿Ó‹Š>u='?ó5¿¦÷(²ó5?ó5¿Õ‹Š¾t='?ó5¿¿þÿÿ>ó5¿t='¿Ó‹Š>ó5¿ó5¿™ ;3ó5¿u='¿Ñ‹Š¾ó5¿¿üÿÿ¾ó5¿Ú‹Š¾s='¿ó5¿Ž*гó5¿ó5¿Ô‹Š>t='¿ó5¿?ýÿÿ¾ó5¿v='?Ì‹Š¾ó5¿ïÃ>^ƒl¿õµ>ö>^ƒl¿Õ‹Š>Õ‹Š>^ƒl¿ö>õµ>^ƒl¿–ã¶±ïÃ>^ƒl¿ö¾õµ>^ƒl¿Ö‹Š¾Ô‹Š>^ƒl¿õµ¾ö>^ƒl¿ïþØtÊ2^ƒl¿öµ¾ö¾^ƒl¿×‹Š¾Ó‹Š¾^ƒl¿"ö¾óµ¾^ƒl¿JQa³ïþ^ƒl¿ö>õµ¾^ƒl¿×‹Š>Ӌо^ƒl¿÷µ>ö¾^ƒl¿€¿›²…ýG2€?áJÖ>¸·C9>zmh?e>©Ÿ>zmh?Â>ÆaÊ>zmh?w¸¼áJÖ>zmh?¸C9¾8”Á>zmh?©Ÿ¾e>zmh?ÆaʾŸÂ>zmh?áJÖ¾_¸¼zmh?9”Á¾´C9¾zmh?e¾©Ÿ¾zmh?¦Â¾Äaʾzmh?T¸<áJÖ¾zmh?¸C9>8”Á¾zmh?©Ÿ>e¾zmh?ÇaÊ>™Â¾zmh?Èà4?(ð<6%5?‡6&?WÄŽ>6%5?°|ü>ƒŽ?5%5?õ†>Ž(?6%5?ùï¼Èà4?6%5?WÄŽ¾‡6&?6%5?„Ž¿­|ü>5%5?Ž(¿õ†>6%5?Èà4¿€ï¼6%5?ˆ6&¿QÄŽ¾6%5?°|ü¾Ž¿7%5?û†¾(¿6%5?jï<Èà4¿5%5?VÄŽ>‡6&¿6%5?„Ž?¬|ü¾5%5?(?ñ†¾5%5?µul?. ;è,Ä>CûY?rJ·>é,Ä>EQ&?S(?é,Ä>ª²>tðZ?è,Ä>õ- »µul?è,Ä>rJ·¾AûY?è,Ä>R(¿DQ&?è,Ä>tðZ¿‹ª²>é,Ä>µul¿.- »è,Ä>CûY¿kJ·¾è,Ä>GQ&¿P(¿ë,Ä>“ª²¾rðZ¿é,Ä>©, ;µul¿è,Ä>rJ·>CûY¿é,Ä>U(?CQ&¿é,Ä>tðZ?‡ª²¾è,Ä>€?¨24 !›2^ƒl?ïÃ>mJ1±ô5?ó5?!!›²ïÃ>_ƒl?mJ1³€?mJ±2ïþ^ƒl?mJ1±ô5¿ó5?¼sDz_ƒl¿ïÃ>€¿ Ý2»sÇ2_ƒl¿ïþmJ±1ö5¿ñ5¿ !›²ïþ^ƒl¿WÆó³€¿mJ±2ïÃ>^ƒl¿mJ1±ö5?ò5¿Ó÷„²`ƒl?ïþnJ1±´ul?ö, »ê,ľrðZ?Žª²>ì,ľS(?EQ&?ë,ľqJ·>AûY?ë,ľ®- ;µul?ì,Ä¾Žª²¾rðZ?ì,ľEQ&¿Q(?ë,ľAûY¿rJ·>ì,ľµul¿N. ;ì,ľtðZ¿ˆª²¾ë,ľT(¿CQ&¿ë,ľuJ·¾@ûY¿ë,ľã. »µul¿ì,Ä¾Žª²>rðZ¿ì,ľFQ&?P(¿ë,ľCûY?jJ·¾ì,ľÈà4?sï¼6%5¿Ž(?÷†>6%5¿ƒŽ?¯|ü>6%5¿UÄŽ>‡6&?6%5¿Ÿï<Èà4?6%5¿÷†¾Ž(?6%5¿°|ü¾Ž?6%5¿‡6&¿UÄŽ>6%5¿Èà4¿ð<6%5¿Ž(¿ó†¾6%5¿„Ž¿¨|ü¾6%5¿YÄŽ¾†6&¿6%5¿7ð¼Èà4¿6%5¿÷†>Ž(¿6%5¿°|ü>Ž¿6%5¿ˆ6&?QÄŽ¾6%5¿ãJÖ>W¸¼zmh¿ÆaÊ> Â>zmh¿©Ÿ>e>zmh¿¸C9>8”Á>zmh¿n¸<áJÖ>zmh¿¡Â¾ÅaÊ>zmh¿e¾©Ÿ>zmh¿:”Á¾·C9>zmh¿ãJÖ¾¸Çaʾzmh¿e>©Ÿ¾zmh¿;”Á>³C9¾zmh¿¬èC±±€2€¿áJÖ>€=·C9>>zmh?@>w¸¼€>8”Á> >zmh?À>áJÖ¾à>´C9¾?zmh??T¸< ?8”Á¾0?zmh?@?Èà4?P?WÄŽ>`?5%5?p?ùï¼€?‡6&?>5%5?€=>Èà4¿>>QÄŽ¾@>>7%5?€>>jï< >>‡6&¿À>>5%5?à>>µul??>rJ·>?>é,Ä> ?>õ- »0?>AûY?@?>è,Ä>P?>µul¿`?>kJ·¾p?>ë,Ä>€?>©, ;€>CûY¿€=€>é,Ä>>€>€?@>€>ïÃ>€>€>!!›² >€>mJ1³À>€>^ƒl?à>€>¼sDz?€>€¿?€>ïþ ?€> !›²0?€>WÆó³@?€>^ƒl¿P?€>Ó÷„²`?€>´ul?p?€>Žª²>€?€>ë,ľÀ>®- ;€=À>rðZ?>À>ë,ľ@>À>µul¿€>À>ˆª²¾ >À>ë,ľÀ>À>ã. »à>À>rðZ¿?À>ë,ľ?À>Èà4? ?À>÷†>0?À>6%5¿@?À>Ÿï<P?À>Ž(?`?À>6%5¿p?À>Èà4¿€?À>ó†¾?6%5¿€=?7ð¼>?Ž(¿@>?6%5¿€>?ãJÖ> >? Â>À>?zmh¿à>?n¸<??ÅaÊ>??zmh¿ ??ãJÖ¾0??›Â¾@??zmh¿P??¦¸¼`??Çaʾp??zmh¿€??¬èC± ?€= ?> ?@> ?€> ? > ?À> ?à> ?? ?? ? ? ?0? ?@? ?P? ?`? ?p? ?€? ?@?€=@?>@?@>@?€>@? >@?À>@?à>@??@??@? ?@?0?@?@?@?P?@?`?@?p?@?€?@?`?€=`?>`?@>`?€>`? >`?À>`?à>`??`??`? ?`?0?`?@?`?P?`?`?`?p?`?€?`?€?€=€?>€?@>€?€>€? >€?À>€?à>€??€??€? ?€?0?€?@?€?P?€?`?€?p?€?€?€?Èðh®¶ `¥©Ãìqð1OP£&Ú`í[¹>¨- ±9…*¹¼D€”W·ÑNÕSE«†D,Ř¡â³D&Où.Ð’Ä)8ìUâï¢g> r,Ä¡‡Ž .\1ó€˜O¿'aÍEóìAÔY 3®%ý§]¬”ö<¢/’|B—0ˆ?%Ú•²®<¤Ì3S MU²›¹µ^F!ïYï[Û4ävAŠ´ÍkËÒäeŸu¿åŸ08râ¾xÂìSn ÈJVȬ¡„˜…ß̬³Íç­TÖ ˆûÉ´–eq#î»’bpOðVà®p†ÔÛÍ* þ±íl ’`ÿ›5ðòdN–ë'ëd³‰MPòÀ>Ûg†èènd™ÃHÚ‚+²jë gæŽÄÝåÞ!”’Yæe^¯j…ìÿÞê(àØ§”!äégQ˜JÕE6EÙ[øpR6d›ÕÏ0£jìÏKÒá(T ¤ÏÞ‘ ÷.ñÆÑqw‹W8F²-{hº_Sx T´BôxE™B}ó„Å—²ã´¾þž|^Õárt-°+ Y¾ÿŠYà(à9ÄM€WÂô…)ÁôrmÆQ'JÉãª_([3Â!®ÙazõëBoR““Ÿ‚‡(§Š®™q ïHsš‰˜ô?‚:]0¡È‡?kK|§ÎÎð«M6ÔOˆÄ8˜Äs´Ûkä_\ˆP®&^‰âÈV§¦üíÿ(K;öņM¸fx³˜†h°e[.¡hµI^L•bÛDÅú-3fz¢Øü©¾žy BVj™O~˦.<ãöQT=9âbõЧ÷ù™þ¿²¬ïݳ8Þ‘?KUë›õ…þUƒ°?@°3¬65¨Ê@F|f ˆ1UÉŽ\ö_ÖL°ÌÖ³{‹mœSlÄùeF9oƒ†³\äëŽõ}"n¯¶øîçž ×-!s_L)4/I=Í=×ÖšZ°òzô$^½yàÓ<|Û¾Øäyç`Æ7îÂÓÑYÎK/Å3gK„á_ƒ‰A|ž ÂR ü¾ÿ €·Œ‡ê}Ç?Ë‚X_`ö"£ÁÀò[ŽHO“"”Ž8èI›owšc‰¨·Uº½õHVº!¡«Uw~×<Ýl7_oûž}UG’)%àÞŠa?sôš2B5ÂpVŒpÞ,}‹Àv&ENqîúÖ½<_ùúc’í«6›ç‘êÆ³A¯gâµrHÐÆ]8ð …Û…@×”¡…"(ÝßÂmª_ÝY×_–ÎÏüøJ¯é¹àRA‹“ˆ#–ïø;l¹¯^ÿÓKV&œy7ðC;wžåefo®Þ€§^âNïþÝ€0ŸÃÕJñÀÑÎâÄ.ZIʸŸCV³«?½”ª«_l2-h[fî8ý×È[MÓ±È+lð%ÜcÌbôk6aØ.…ùE»¾Räi ßÜ5¸iΆúÊ¡Ÿ@KŠž…é ÌØhñWÎHig«¥šk*Ñ?êRç«/@^egÖ«å“U$ƦJ~æí¹(ˆ·š6CH½MÖ4”m _Öß›Ms åy‡ïÊ„À3îH@#²µ¹"[ª;ÓÇF¹:Å5ÖÚÞ=¢ Ÿy›xî]O‚·Ë£]àu–οØ^Ó¦öˆ ù‚"*Ö‹ÚZA¸h–æ5UY3|è%Ì.Âì_…l¾/oBµü6åû5 î?T­ÆÞ?"Ô€õÚ[&zÀÇ|ºô(#¼5¶\àa•àúï{ËéT5½ƒ²ëÊ0©ÿ7˜ÄœðԂ c “ ÙÆ²ù§/GQ,*Pcç¬Ør³®ýÈzl%”ch-owJƆxʃw†¾:k£ç×Ð"óÌ.0G& îm“ZqÓ'|àpÞÖVL(ȘÞÿÝÄŽŽÆNþÿ¶Š²Ì‘âs~êÒ.«ò¿QWÁÔfRýß@Fh‹üoXŽñ)ÌÃþ7£VH^„ÿ;ÈÎÚª;ïÿƒk4öÿyw$]ëùÿþˆ†ÈI¿;ÿÿÿRobject18àrr™€?ïÃ>^ƒl?ôµ>ö>^ƒl?Ô‹Š>Õ‹Š>^ƒl?ö>ôµ>^ƒl?•ã¶±ïÃ>^ƒl?ö¾ôµ>^ƒl?Õ‹Š¾Ô‹Š>^ƒl?ôµ¾ö>^ƒl?ïþ×tÊ2^ƒl?õµ¾ö¾^ƒl?Ö‹Š¾Ò‹Š¾^ƒl?!ö¾òµ¾^ƒl?IQa³ïþ^ƒl?ö>ôµ¾^ƒl?Ö‹Š>Ӌо^ƒl?öµ>ö¾^ƒl?ó5?ó5?t='?Ô‹Š>ó5?ÿÿÿ>?ó5?Ó‹Š>u='?ó5?¦÷(²ó5?ó5?Ջоt='?ó5?¿þÿÿ>ó5?t='¿Ó‹Š>ó5?ó5¿™ ;3ó5?u='¿Ñ‹Š¾ó5?¿üÿÿ¾ó5?Ú‹Š¾s='¿ó5?Ž*гó5¿ó5?Ô‹Š>t='¿ó5??ýÿÿ¾ó5?v='?Ì‹Š¾ó5?^ƒl?ïÃ>y‚Z?óµ>ïÃ>t='?t='?ïÃ>òµ>y‚Z?ïÃ>:Ä\²^ƒl?ïÃ>ôµ¾y‚Z?ïÃ>u='¿s='?ïÃ>y‚Z¿òµ>ïÃ>^ƒl¿ðbt3ïÃ>z‚Z¿ïµ¾ïÃ>w='¿r='¿ïÃ>ûµ¾w‚Z¿ïÃ>¼ý´^ƒl¿ïÃ>óµ>y‚Z¿ïÃ>v='?r='¿ïÃ>{‚Z?éµ¾ïÃ>€?.½;³^ƒl?ïÃ>.½;³ó5?ó5?.½;³ïÃ>_ƒl?.½;³ºôn²€?.½;³ïþ^ƒl?.½;³ô5¿ò5?.½;³_ƒl¿ïÃ>.½;³€¿ÒB„3.½;³_ƒl¿ïþ.½;³ö5¿ñ5¿.½;³ïþ]ƒl¿.½;³2´€¿.½;³ïÃ>^ƒl¿.½;³õ5?ñ5¿.½;³aƒl? ïþ.½;³^ƒl?ïþy‚Z?óµ>ïþt='?t='?ïþòµ>y‚Z?ïþ:Ä\²^ƒl?ïþôµ¾y‚Z?ïþu='¿s='?ïþy‚Z¿òµ>ïþ^ƒl¿ðbt3ïþz‚Z¿ïµ¾ïþw='¿r='¿ïþûµ¾w‚Z¿ïþ¼ý´^ƒl¿ïþóµ>y‚Z¿ïþv='?r='¿ïþ{‚Z?éµ¾ïþó5?ó5¿t='?Ô‹Š>ó5¿ÿÿÿ>?ó5¿Ó‹Š>u='?ó5¿¦÷(²ó5?ó5¿Õ‹Š¾t='?ó5¿¿þÿÿ>ó5¿t='¿Ó‹Š>ó5¿ó5¿™ ;3ó5¿u='¿Ñ‹Š¾ó5¿¿üÿÿ¾ó5¿Ú‹Š¾s='¿ó5¿Ž*гó5¿ó5¿Ô‹Š>t='¿ó5¿?ýÿÿ¾ó5¿v='?Ì‹Š¾ó5¿ïÃ>^ƒl¿õµ>ö>^ƒl¿Õ‹Š>Õ‹Š>^ƒl¿ö>õµ>^ƒl¿–ã¶±ïÃ>^ƒl¿ö¾õµ>^ƒl¿Ö‹Š¾Ô‹Š>^ƒl¿õµ¾ö>^ƒl¿ïþØtÊ2^ƒl¿öµ¾ö¾^ƒl¿×‹Š¾Ó‹Š¾^ƒl¿"ö¾óµ¾^ƒl¿JQa³ïþ^ƒl¿ö>õµ¾^ƒl¿×‹Š>Ӌо^ƒl¿÷µ>ö¾^ƒl¿€¿›²…ýG2€?áJÖ>¸·C9>zmh?e>©Ÿ>zmh?Â>ÆaÊ>zmh?w¸¼áJÖ>zmh?¸C9¾8”Á>zmh?©Ÿ¾e>zmh?ÆaʾŸÂ>zmh?áJÖ¾_¸¼zmh?9”Á¾´C9¾zmh?e¾©Ÿ¾zmh?¦Â¾Äaʾzmh?T¸<áJÖ¾zmh?¸C9>8”Á¾zmh?©Ÿ>e¾zmh?ÇaÊ>™Â¾zmh?Èà4?(ð<6%5?‡6&?WÄŽ>6%5?°|ü>ƒŽ?5%5?õ†>Ž(?6%5?ùï¼Èà4?6%5?WÄŽ¾‡6&?6%5?„Ž¿­|ü>5%5?Ž(¿õ†>6%5?Èà4¿€ï¼6%5?ˆ6&¿QÄŽ¾6%5?°|ü¾Ž¿7%5?û†¾(¿6%5?jï<Èà4¿5%5?VÄŽ>‡6&¿6%5?„Ž?¬|ü¾5%5?(?ñ†¾5%5?µul?. ;è,Ä>CûY?rJ·>é,Ä>EQ&?S(?é,Ä>ª²>tðZ?è,Ä>õ- »µul?è,Ä>rJ·¾AûY?è,Ä>R(¿DQ&?è,Ä>tðZ¿‹ª²>é,Ä>µul¿.- »è,Ä>CûY¿kJ·¾è,Ä>GQ&¿P(¿ë,Ä>“ª²¾rðZ¿é,Ä>©, ;µul¿è,Ä>rJ·>CûY¿é,Ä>U(?CQ&¿é,Ä>tðZ?‡ª²¾è,Ä>€?¨24 !›2^ƒl?ïÃ>mJ1±ô5?ó5?!!›²ïÃ>_ƒl?mJ1³€?mJ±2ïþ^ƒl?mJ1±ô5¿ó5?¼sDz_ƒl¿ïÃ>€¿ Ý2»sÇ2_ƒl¿ïþmJ±1ö5¿ñ5¿ !›²ïþ^ƒl¿WÆó³€¿mJ±2ïÃ>^ƒl¿mJ1±ö5?ò5¿Ó÷„²`ƒl?ïþnJ1±´ul?ö, »ê,ľrðZ?Žª²>ì,ľS(?EQ&?ë,ľqJ·>AûY?ë,ľ®- ;µul?ì,Ä¾Žª²¾rðZ?ì,ľEQ&¿Q(?ë,ľAûY¿rJ·>ì,ľµul¿N. ;ì,ľtðZ¿ˆª²¾ë,ľT(¿CQ&¿ë,ľuJ·¾@ûY¿ë,ľã. »µul¿ì,Ä¾Žª²>rðZ¿ì,ľFQ&?P(¿ë,ľCûY?jJ·¾ì,ľÈà4?sï¼6%5¿Ž(?÷†>6%5¿ƒŽ?¯|ü>6%5¿UÄŽ>‡6&?6%5¿Ÿï<Èà4?6%5¿÷†¾Ž(?6%5¿°|ü¾Ž?6%5¿‡6&¿UÄŽ>6%5¿Èà4¿ð<6%5¿Ž(¿ó†¾6%5¿„Ž¿¨|ü¾6%5¿YÄŽ¾†6&¿6%5¿7ð¼Èà4¿6%5¿÷†>Ž(¿6%5¿°|ü>Ž¿6%5¿ˆ6&?QÄŽ¾6%5¿ãJÖ>W¸¼zmh¿ÆaÊ> Â>zmh¿©Ÿ>e>zmh¿¸C9>8”Á>zmh¿n¸<áJÖ>zmh¿¡Â¾ÅaÊ>zmh¿e¾©Ÿ>zmh¿:”Á¾·C9>zmh¿ãJÖ¾¸Çaʾzmh¿e>©Ÿ¾zmh¿;”Á>³C9¾zmh¿¬èC±±€2€¿áJÖ>€=·C9>>zmh?@>w¸¼€>8”Á> >zmh?À>áJÖ¾à>´C9¾?zmh??T¸< ?8”Á¾0?zmh?@?Èà4?P?WÄŽ>`?5%5?p?ùï¼€?‡6&?>5%5?€=>Èà4¿>>QÄŽ¾@>>7%5?€>>jï< >>‡6&¿À>>5%5?à>>µul??>rJ·>?>é,Ä> ?>õ- »0?>AûY?@?>è,Ä>P?>µul¿`?>kJ·¾p?>ë,Ä>€?>©, ;€>CûY¿€=€>é,Ä>>€>€?@>€>ïÃ>€>€>!!›² >€>mJ1³À>€>^ƒl?à>€>¼sDz?€>€¿?€>ïþ ?€> !›²0?€>WÆó³@?€>^ƒl¿P?€>Ó÷„²`?€>´ul?p?€>Žª²>€?€>ë,ľÀ>®- ;€=À>rðZ?>À>ë,ľ@>À>µul¿€>À>ˆª²¾ >À>ë,ľÀ>À>ã. »à>À>rðZ¿?À>ë,ľ?À>Èà4? ?À>÷†>0?À>6%5¿@?À>Ÿï<P?À>Ž(?`?À>6%5¿p?À>Èà4¿€?À>ó†¾?6%5¿€=?7ð¼>?Ž(¿@>?6%5¿€>?ãJÖ> >? Â>À>?zmh¿à>?n¸<??ÅaÊ>??zmh¿ ??ãJÖ¾0??›Â¾@??zmh¿P??¦¸¼`??Çaʾp??zmh¿€??¬èC± ?€= ?> ?@> ?€> ? > ?À> ?à> ?? ?? ? ? ?0? ?@? ?P? ?`? ?p? ?€? ?@?€=@?>@?@>@?€>@? >@?À>@?à>@??@??@? ?@?0?@?@?@?P?@?`?@?p?@?€?@?`?€=`?>`?@>`?€>`? >`?À>`?à>`??`??`? ?`?0?`?@?`?P?`?`?`?p?`?€?`?€?€=€?>€?@>€?€>€? >€?À>€?à>€??€??€? ?€?0?€?@?€?P?€?`?€?p?€?€?€?Èðh®¶ `¥©Ãìqð1OP£&Ú`í[¹>¨- ±9…*¹¼D€”W·ÑNÕSE«†D,Ř¡â³D&Où.Ð’Ä)8ìUâï¢g> r,Ä¡‡Ž .\1ó€˜O¿'aÍEóìAÔY 3®%ý§]¬”ö<¢/’|B—0ˆ?%Ú•²®<¤Ì3S MU²›¹µ^F!ïYï[Û4ävAŠ´ÍkËÒäeŸu¿åŸ08râ¾xÂìSn ÈJVȬ¡„˜…ß̬³Íç­TÖ ˆûÉ´–eq#î»’bpOðVà®p†ÔÛÍ* þ±íl ’`ÿ›5ðòdN–ë'ëd³‰MPòÀ>Ûg†èènd™ÃHÚ‚+²jë gæŽÄÝåÞ!”’Yæe^¯j…ìÿÞê(àØ§”!äégQ˜JÕE6EÙ[øpR6d›ÕÏ0£jìÏKÒá(T ¤ÏÞ‘ ÷.ñÆÑqw‹W8F²-{hº_Sx T´BôxE™B}ó„Å—²ã´¾þž|^Õárt-°+ Y¾ÿŠYà(à9ÄM€WÂô…)ÁôrmÆQ'JÉãª_([3Â!®ÙazõëBoR““Ÿ‚‡(§Š®™q ïHsš‰˜ô?‚:]0¡È‡?kK|§ÎÎð«M6ÔOˆÄ8˜Äs´Ûkä_\ˆP®&^‰âÈV§¦üíÿ(K;öņM¸fx³˜†h°e[.¡hµI^L•bÛDÅú-3fz¢Øü©¾žy BVj™O~˦.<ãöQT=9âbõЧ÷ù™þ¿²¬ïݳ8Þ‘?KUë›õ…þUƒ°?@°3¬65¨Ê@F|f ˆ1UÉŽ\ö_ÖL°ÌÖ³{‹mœSlÄùeF9oƒ†³\äëŽõ}"n¯¶øîçž ×-!s_L)4/I=Í=×ÖšZ°òzô$^½yàÓ<|Û¾Øäyç`Æ7îÂÓÑYÎK/Å3gK„á_ƒ‰A|ž ÂR ü¾ÿ €·Œ‡ê}Ç?Ë‚X_`ö"£ÁÀò[ŽHO“"”Ž8èI›owšc‰¨·Uº½õHVº!¡«Uw~×<Ýl7_oûž}UG’)%àÞŠa?sôš2B5ÂpVŒpÞ,}‹Àv&ENqîúÖ½<_ùúc’í«6›ç‘êÆ³A¯gâµrHÐÆ]8ð …Û…@×”¡…"(ÝßÂmª_ÝY×_–ÎÏüøJ¯é¹àRA‹“ˆ#–ïø;l¹¯^ÿÓKV&œy7ðC;wžåefo®Þ€§^âNïþÝ€0ŸÃÕJñÀÑÎâÄ.ZIʸŸCV³«?½”ª«_l2-h[fî8ý×È[MÓ±È+lð%ÜcÌbôk6aØ.…ùE»¾Räi ßÜ5¸iΆúÊ¡Ÿ@KŠž…é ÌØhñWÎHig«¥šk*Ñ?êRç«/@^egÖ«å“U$ƦJ~æí¹(ˆ·š6CH½MÖ4”m _Öß›Ms åy‡ïÊ„À3îH@#²µ¹"[ª;ÓÇF¹:Å5ÖÚÞ=¢ Ÿy›xî]O‚·Ë£]àu–οØ^Ó¦öˆ ù‚"*Ö‹ÚZA¸h–æ5UY3|è%Ì.Âì_…l¾/oBµü6åû5 î?T­ÆÞ?"Ô€õÚ[&zÀÇ|ºô(#¼5¶\àa•àúï{ËéT5½ƒ²ëÊ0©ÿ7˜ÄœðԂ c “ ÙÆ²ù§/GQ,*Pcç¬Ør³®ýÈzl%”ch-owJƆxʃw†¾:k£ç×Ð"óÌ.0G& îm“ZqÓ'|àpÞÖVL(ȘÞÿÝÄŽŽÆNþÿ¶Š²Ì‘âs~êÒ.«ò¿QWÁÔfRýß@Fh‹üoXŽñ)ÌÃþ7£VH^„ÿ;ÈÎÚª;ïÿƒk4öÿyw$]ëùÿþˆ†ÈI¿;ÿÿÿRobject16àrr™€?ïÃ>^ƒl?ôµ>ö>^ƒl?Ô‹Š>Õ‹Š>^ƒl?ö>ôµ>^ƒl?•ã¶±ïÃ>^ƒl?ö¾ôµ>^ƒl?Õ‹Š¾Ô‹Š>^ƒl?ôµ¾ö>^ƒl?ïþ×tÊ2^ƒl?õµ¾ö¾^ƒl?Ö‹Š¾Ò‹Š¾^ƒl?!ö¾òµ¾^ƒl?IQa³ïþ^ƒl?ö>ôµ¾^ƒl?Ö‹Š>Ӌо^ƒl?öµ>ö¾^ƒl?ó5?ó5?t='?Ô‹Š>ó5?ÿÿÿ>?ó5?Ó‹Š>u='?ó5?¦÷(²ó5?ó5?Ջоt='?ó5?¿þÿÿ>ó5?t='¿Ó‹Š>ó5?ó5¿™ ;3ó5?u='¿Ñ‹Š¾ó5?¿üÿÿ¾ó5?Ú‹Š¾s='¿ó5?Ž*гó5¿ó5?Ô‹Š>t='¿ó5??ýÿÿ¾ó5?v='?Ì‹Š¾ó5?^ƒl?ïÃ>y‚Z?óµ>ïÃ>t='?t='?ïÃ>òµ>y‚Z?ïÃ>:Ä\²^ƒl?ïÃ>ôµ¾y‚Z?ïÃ>u='¿s='?ïÃ>y‚Z¿òµ>ïÃ>^ƒl¿ðbt3ïÃ>z‚Z¿ïµ¾ïÃ>w='¿r='¿ïÃ>ûµ¾w‚Z¿ïÃ>¼ý´^ƒl¿ïÃ>óµ>y‚Z¿ïÃ>v='?r='¿ïÃ>{‚Z?éµ¾ïÃ>€?.½;³^ƒl?ïÃ>.½;³ó5?ó5?.½;³ïÃ>_ƒl?.½;³ºôn²€?.½;³ïþ^ƒl?.½;³ô5¿ò5?.½;³_ƒl¿ïÃ>.½;³€¿ÒB„3.½;³_ƒl¿ïþ.½;³ö5¿ñ5¿.½;³ïþ]ƒl¿.½;³2´€¿.½;³ïÃ>^ƒl¿.½;³õ5?ñ5¿.½;³aƒl? ïþ.½;³^ƒl?ïþy‚Z?óµ>ïþt='?t='?ïþòµ>y‚Z?ïþ:Ä\²^ƒl?ïþôµ¾y‚Z?ïþu='¿s='?ïþy‚Z¿òµ>ïþ^ƒl¿ðbt3ïþz‚Z¿ïµ¾ïþw='¿r='¿ïþûµ¾w‚Z¿ïþ¼ý´^ƒl¿ïþóµ>y‚Z¿ïþv='?r='¿ïþ{‚Z?éµ¾ïþó5?ó5¿t='?Ô‹Š>ó5¿ÿÿÿ>?ó5¿Ó‹Š>u='?ó5¿¦÷(²ó5?ó5¿Õ‹Š¾t='?ó5¿¿þÿÿ>ó5¿t='¿Ó‹Š>ó5¿ó5¿™ ;3ó5¿u='¿Ñ‹Š¾ó5¿¿üÿÿ¾ó5¿Ú‹Š¾s='¿ó5¿Ž*гó5¿ó5¿Ô‹Š>t='¿ó5¿?ýÿÿ¾ó5¿v='?Ì‹Š¾ó5¿ïÃ>^ƒl¿õµ>ö>^ƒl¿Õ‹Š>Õ‹Š>^ƒl¿ö>õµ>^ƒl¿–ã¶±ïÃ>^ƒl¿ö¾õµ>^ƒl¿Ö‹Š¾Ô‹Š>^ƒl¿õµ¾ö>^ƒl¿ïþØtÊ2^ƒl¿öµ¾ö¾^ƒl¿×‹Š¾Ó‹Š¾^ƒl¿"ö¾óµ¾^ƒl¿JQa³ïþ^ƒl¿ö>õµ¾^ƒl¿×‹Š>Ӌо^ƒl¿÷µ>ö¾^ƒl¿€¿›²…ýG2€?áJÖ>¸·C9>zmh?e>©Ÿ>zmh?Â>ÆaÊ>zmh?w¸¼áJÖ>zmh?¸C9¾8”Á>zmh?©Ÿ¾e>zmh?ÆaʾŸÂ>zmh?áJÖ¾_¸¼zmh?9”Á¾´C9¾zmh?e¾©Ÿ¾zmh?¦Â¾Äaʾzmh?T¸<áJÖ¾zmh?¸C9>8”Á¾zmh?©Ÿ>e¾zmh?ÇaÊ>™Â¾zmh?Èà4?(ð<6%5?‡6&?WÄŽ>6%5?°|ü>ƒŽ?5%5?õ†>Ž(?6%5?ùï¼Èà4?6%5?WÄŽ¾‡6&?6%5?„Ž¿­|ü>5%5?Ž(¿õ†>6%5?Èà4¿€ï¼6%5?ˆ6&¿QÄŽ¾6%5?°|ü¾Ž¿7%5?û†¾(¿6%5?jï<Èà4¿5%5?VÄŽ>‡6&¿6%5?„Ž?¬|ü¾5%5?(?ñ†¾5%5?µul?. ;è,Ä>CûY?rJ·>é,Ä>EQ&?S(?é,Ä>ª²>tðZ?è,Ä>õ- »µul?è,Ä>rJ·¾AûY?è,Ä>R(¿DQ&?è,Ä>tðZ¿‹ª²>é,Ä>µul¿.- »è,Ä>CûY¿kJ·¾è,Ä>GQ&¿P(¿ë,Ä>“ª²¾rðZ¿é,Ä>©, ;µul¿è,Ä>rJ·>CûY¿é,Ä>U(?CQ&¿é,Ä>tðZ?‡ª²¾è,Ä>€?¨24 !›2^ƒl?ïÃ>mJ1±ô5?ó5?!!›²ïÃ>_ƒl?mJ1³€?mJ±2ïþ^ƒl?mJ1±ô5¿ó5?¼sDz_ƒl¿ïÃ>€¿ Ý2»sÇ2_ƒl¿ïþmJ±1ö5¿ñ5¿ !›²ïþ^ƒl¿WÆó³€¿mJ±2ïÃ>^ƒl¿mJ1±ö5?ò5¿Ó÷„²`ƒl?ïþnJ1±´ul?ö, »ê,ľrðZ?Žª²>ì,ľS(?EQ&?ë,ľqJ·>AûY?ë,ľ®- ;µul?ì,Ä¾Žª²¾rðZ?ì,ľEQ&¿Q(?ë,ľAûY¿rJ·>ì,ľµul¿N. ;ì,ľtðZ¿ˆª²¾ë,ľT(¿CQ&¿ë,ľuJ·¾@ûY¿ë,ľã. »µul¿ì,Ä¾Žª²>rðZ¿ì,ľFQ&?P(¿ë,ľCûY?jJ·¾ì,ľÈà4?sï¼6%5¿Ž(?÷†>6%5¿ƒŽ?¯|ü>6%5¿UÄŽ>‡6&?6%5¿Ÿï<Èà4?6%5¿÷†¾Ž(?6%5¿°|ü¾Ž?6%5¿‡6&¿UÄŽ>6%5¿Èà4¿ð<6%5¿Ž(¿ó†¾6%5¿„Ž¿¨|ü¾6%5¿YÄŽ¾†6&¿6%5¿7ð¼Èà4¿6%5¿÷†>Ž(¿6%5¿°|ü>Ž¿6%5¿ˆ6&?QÄŽ¾6%5¿ãJÖ>W¸¼zmh¿ÆaÊ> Â>zmh¿©Ÿ>e>zmh¿¸C9>8”Á>zmh¿n¸<áJÖ>zmh¿¡Â¾ÅaÊ>zmh¿e¾©Ÿ>zmh¿:”Á¾·C9>zmh¿ãJÖ¾¸Çaʾzmh¿e>©Ÿ¾zmh¿;”Á>³C9¾zmh¿¬èC±±€2€¿€=>$øô @>€> >À>à>$øô ?? ?0?@?$øô P?`?p?€?>$øô €=>>>@>>€>> >>$øô À>>à>>?>?> ?>$øô 0?>@?>P?>`?>p?>$øô €?>€>€=€>>€>@>€>$øô €>€> >€>À>€>à>€>?€>$øô ?€> ?€>0?€>@?€>P?€>$øô `?€>p?€>€?€>À>€=À>$øô >À>@>À>€>À> >À>À>À>$øô à>À>?À>?À> ?À>0?À>$øô @?À>P?À>`?À>p?À>€?À>$øô ?€=?>?@>?€>?$øô  >?À>?à>?????$øô ??0??@??P??`??$øô p??€?? ?€= ?> ?$øô @> ?€> ? > ?À> ?à> ?$øô ? ?? ? ? ?0? ?@? ?$øô P? ?`? ?p? ?€? ?@?$øô €=@?>@?@>@?€>@? >@?$øô À>@?à>@??@??@? ?@?$øô 0?@?@?@?P?@?`?@?p?@?$øô €?@?`?€=`?>`?@>`?$øô €>`? >`?À>`?à>`??`?$øô ?`? ?`?0?`?@?`?P?`?$øô `?`?p?`?€?`?€?€=€?$øô >€?@>€?€>€? >€?À>€?à>€?…ýG2?€?zmh??€?e> ?€?ÆaÊ>0?€?zmh?@?€?©Ÿ¾P?€?ŸÂ>`?€?zmh?p?€?e¾€?€?ÄaʾÈðh®¶ `¥©Ãìqð1OP£&Ú`í[¹>¨- ±9…*¹¼D€”W·ÑNÕSE«†D,Ř¡â³D&Où.Ð’Ä)8ìUâï¢g> r,Ä¡‡Ž .\1ó€˜O¿'aÍEóìAÔY 3®%ý§]¬”ö<¢/’|B—0ˆ?%Ú•²®<¤Ì3S MU²›¹µ^F!ïYï[Û4ävAŠ´ÍkËÒäeŸu¿åŸ08râ¾xÂìSn ÈJVȬ¡„˜…ß̬³Íç­TÖ ˆûÉ´–eq#î»’bpOðVà®p†ÔÛÍ* þ±íl ’`ÿ›5ðòdN–ë'ëd³‰MPòÀ>Ûg†èènd™ÃHÚ‚+²jë gæŽÄÝåÞ!”’Yæe^¯j…ìÿÞê(àØ§”!äégQ˜JÕE6EÙ[øpR6d›ÕÏ0£jìÏKÒá(T ¤ÏÞ‘ ÷.ñÆÑqw‹W8F²-{hº_Sx T´BôxE™B}ó„Å—²ã´¾þž|^Õárt-°+ Y¾ÿŠYà(à9ÄM€WÂô…)ÁôrmÆQ'JÉãª_([3Â!®ÙazõëBoR““Ÿ‚‡(§Š®™q ïHsš‰˜ô?‚:]0¡È‡?kK|§ÎÎð«M6ÔOˆÄ8˜Äs´Ûkä_\ˆP®&^‰âÈV§¦üíÿ(K;öņM¸fx³˜†h°e[.¡hµI^L•bÛDÅú-3fz¢Øü©¾žy BVj™O~˦.<ãöQT=9âbõЧ÷ù™þ¿²¬ïݳ8Þ‘?KUë›õ…þUƒ°?@°3¬65¨Ê@F|f ˆ1UÉŽ\ö_ÖL°ÌÖ³{‹mœSlÄùeF9oƒ†³\äëŽõ}"n¯¶øîçž ×-!s_L)4/I=Í=×ÖšZ°òzô$^½yàÓ<|Û¾Øäyç`Æ7îÂÓÑYÎK/Å3gK„á_ƒ‰A|ž ÂR ü¾ÿ €·Œ‡ê}Ç?Ë‚X_`ö"£ÁÀò[ŽHO“"”Ž8èI›owšc‰¨·Uº½õHVº!¡«Uw~×<Ýl7_oûž}UG’)%àÞŠa?sôš2B5ÂpVŒpÞ,}‹Àv&ENqîúÖ½<_ùúc’í«6›ç‘êÆ³A¯gâµrHÐÆ]8ð …Û…@×”¡…"(ÝßÂmª_ÝY×_–ÎÏüøJ¯é¹àRA‹“ˆ#–ïø;l¹¯^ÿÓKV&œy7ðC;wžåefo®Þ€§^âNïþÝ€0ŸÃÕJñÀÑÎâÄ.ZIʸŸCV³«?½”ª«_l2-h[fî8ý×È[MÓ±È+lð%ÜcÌbôk6aØ.…ùE»¾Räi ßÜ5¸iΆúÊ¡Ÿ@KŠž…é ÌØhñWÎHig«¥šk*Ñ?êRç«/@^egÖ«å“U$ƦJ~æí¹(ˆ·š6CH½MÖ4”m _Öß›Ms åy‡ïÊ„À3îH@#²µ¹"[ª;ÓÇF¹:Å5ÖÚÞ=¢ Ÿy›xî]O‚·Ë£]àu–οØ^Ó¦öˆ ù‚"*Ö‹ÚZA¸h–æ5UY3|è%Ì.Âì_…l¾/oBµü6åû5 î?T­ÆÞ?"Ô€õÚ[&zÀÇ|ºô(#¼5¶\àa•àúï{ËéT5½ƒ²ëÊ0©ÿ7˜ÄœðԂ c “ ÙÆ²ù§/GQ,*Pcç¬Ør³®ýÈzl%”ch-owJƆxʃw†¾:k£ç×Ð"óÌ.0G& îm“ZqÓ'|àpÞÖVL(ȘÞÿÝÄŽŽÆNþÿ¶Š²Ì‘âs~êÒ.«ò¿QWÁÔfRýß@Fh‹üoXŽñ)ÌÃþ7£VH^„ÿ;ÈÎÚª;ïÿƒk4öÿyw$]ëùÿþˆ†ÈI¿;ÿÿÿRobject14àrr™€?ïÃ>^ƒl?ôµ>ö>^ƒl?Ô‹Š>Õ‹Š>^ƒl?ö>ôµ>^ƒl?•ã¶±ïÃ>^ƒl?ö¾ôµ>^ƒl?Õ‹Š¾Ô‹Š>^ƒl?ôµ¾ö>^ƒl?ïþ×tÊ2^ƒl?õµ¾ö¾^ƒl?Ö‹Š¾Ò‹Š¾^ƒl?!ö¾òµ¾^ƒl?IQa³ïþ^ƒl?ö>ôµ¾^ƒl?Ö‹Š>Ӌо^ƒl?öµ>ö¾^ƒl?ó5?ó5?t='?Ô‹Š>ó5?ÿÿÿ>?ó5?Ó‹Š>u='?ó5?¦÷(²ó5?ó5?Ջоt='?ó5?¿þÿÿ>ó5?t='¿Ó‹Š>ó5?ó5¿™ ;3ó5?u='¿Ñ‹Š¾ó5?¿üÿÿ¾ó5?Ú‹Š¾s='¿ó5?Ž*гó5¿ó5?Ô‹Š>t='¿ó5??ýÿÿ¾ó5?v='?Ì‹Š¾ó5?^ƒl?ïÃ>y‚Z?óµ>ïÃ>t='?t='?ïÃ>òµ>y‚Z?ïÃ>:Ä\²^ƒl?ïÃ>ôµ¾y‚Z?ïÃ>u='¿s='?ïÃ>y‚Z¿òµ>ïÃ>^ƒl¿ðbt3ïÃ>z‚Z¿ïµ¾ïÃ>w='¿r='¿ïÃ>ûµ¾w‚Z¿ïÃ>¼ý´^ƒl¿ïÃ>óµ>y‚Z¿ïÃ>v='?r='¿ïÃ>{‚Z?éµ¾ïÃ>€?.½;³^ƒl?ïÃ>.½;³ó5?ó5?.½;³ïÃ>_ƒl?.½;³ºôn²€?.½;³ïþ^ƒl?.½;³ô5¿ò5?.½;³_ƒl¿ïÃ>.½;³€¿ÒB„3.½;³_ƒl¿ïþ.½;³ö5¿ñ5¿.½;³ïþ]ƒl¿.½;³2´€¿.½;³ïÃ>^ƒl¿.½;³õ5?ñ5¿.½;³aƒl? ïþ.½;³^ƒl?ïþy‚Z?óµ>ïþt='?t='?ïþòµ>y‚Z?ïþ:Ä\²^ƒl?ïþôµ¾y‚Z?ïþu='¿s='?ïþy‚Z¿òµ>ïþ^ƒl¿ðbt3ïþz‚Z¿ïµ¾ïþw='¿r='¿ïþûµ¾w‚Z¿ïþ¼ý´^ƒl¿ïþóµ>y‚Z¿ïþv='?r='¿ïþ{‚Z?éµ¾ïþó5?ó5¿t='?Ô‹Š>ó5¿ÿÿÿ>?ó5¿Ó‹Š>u='?ó5¿¦÷(²ó5?ó5¿Õ‹Š¾t='?ó5¿¿þÿÿ>ó5¿t='¿Ó‹Š>ó5¿ó5¿™ ;3ó5¿u='¿Ñ‹Š¾ó5¿¿üÿÿ¾ó5¿Ú‹Š¾s='¿ó5¿Ž*гó5¿ó5¿Ô‹Š>t='¿ó5¿?ýÿÿ¾ó5¿v='?Ì‹Š¾ó5¿ïÃ>^ƒl¿õµ>ö>^ƒl¿Õ‹Š>Õ‹Š>^ƒl¿ö>õµ>^ƒl¿–ã¶±ïÃ>^ƒl¿ö¾õµ>^ƒl¿Ö‹Š¾Ô‹Š>^ƒl¿õµ¾ö>^ƒl¿ïþØtÊ2^ƒl¿öµ¾ö¾^ƒl¿×‹Š¾Ó‹Š¾^ƒl¿"ö¾óµ¾^ƒl¿JQa³ïþ^ƒl¿ö>õµ¾^ƒl¿×‹Š>Ӌо^ƒl¿÷µ>ö¾^ƒl¿€¿›²…ýG2€?áJÖ>¸·C9>zmh?e>©Ÿ>zmh?Â>ÆaÊ>zmh?w¸¼áJÖ>zmh?¸C9¾8”Á>zmh?©Ÿ¾e>zmh?ÆaʾŸÂ>zmh?áJÖ¾_¸¼zmh?9”Á¾´C9¾zmh?e¾©Ÿ¾zmh?¦Â¾Äaʾzmh?T¸<áJÖ¾zmh?¸C9>8”Á¾zmh?©Ÿ>e¾zmh?ÇaÊ>™Â¾zmh?Èà4?(ð<6%5?‡6&?WÄŽ>6%5?°|ü>ƒŽ?5%5?õ†>Ž(?6%5?ùï¼Èà4?6%5?WÄŽ¾‡6&?6%5?„Ž¿­|ü>5%5?Ž(¿õ†>6%5?Èà4¿€ï¼6%5?ˆ6&¿QÄŽ¾6%5?°|ü¾Ž¿7%5?û†¾(¿6%5?jï<Èà4¿5%5?VÄŽ>‡6&¿6%5?„Ž?¬|ü¾5%5?(?ñ†¾5%5?µul?. ;è,Ä>CûY?rJ·>é,Ä>EQ&?S(?é,Ä>ª²>tðZ?è,Ä>õ- »µul?è,Ä>rJ·¾AûY?è,Ä>R(¿DQ&?è,Ä>tðZ¿‹ª²>é,Ä>µul¿.- »è,Ä>CûY¿kJ·¾è,Ä>GQ&¿P(¿ë,Ä>“ª²¾rðZ¿é,Ä>©, ;µul¿è,Ä>rJ·>CûY¿é,Ä>U(?CQ&¿é,Ä>tðZ?‡ª²¾è,Ä>€?¨24 !›2^ƒl?ïÃ>mJ1±ô5?ó5?!!›²ïÃ>_ƒl?mJ1³€?mJ±2ïþ^ƒl?mJ1±ô5¿ó5?¼sDz_ƒl¿ïÃ>€¿ Ý2»sÇ2_ƒl¿ïþmJ±1ö5¿ñ5¿ !›²ïþ^ƒl¿WÆó³€¿mJ±2ïÃ>^ƒl¿mJ1±ö5?ò5¿Ó÷„²`ƒl?ïþnJ1±´ul?ö, »ê,ľrðZ?Žª²>ì,ľS(?EQ&?ë,ľqJ·>AûY?ë,ľ®- ;µul?ì,Ä¾Žª²¾rðZ?ì,ľEQ&¿Q(?ë,ľAûY¿rJ·>ì,ľµul¿N. ;ì,ľtðZ¿ˆª²¾ë,ľT(¿CQ&¿ë,ľuJ·¾@ûY¿ë,ľã. »µul¿ì,Ä¾Žª²>rðZ¿ì,ľFQ&?P(¿ë,ľCûY?jJ·¾ì,ľÈà4?sï¼6%5¿Ž(?÷†>6%5¿ƒŽ?¯|ü>6%5¿UÄŽ>‡6&?6%5¿Ÿï<Èà4?6%5¿÷†¾Ž(?6%5¿°|ü¾Ž?6%5¿‡6&¿UÄŽ>6%5¿Èà4¿ð<6%5¿Ž(¿ó†¾6%5¿„Ž¿¨|ü¾6%5¿YÄŽ¾†6&¿6%5¿7ð¼Èà4¿6%5¿÷†>Ž(¿6%5¿°|ü>Ž¿6%5¿ˆ6&?QÄŽ¾6%5¿ãJÖ>W¸¼zmh¿ÆaÊ> Â>zmh¿©Ÿ>e>zmh¿¸C9>8”Á>zmh¿n¸<áJÖ>zmh¿¡Â¾ÅaÊ>zmh¿e¾©Ÿ>zmh¿:”Á¾·C9>zmh¿ãJÖ¾¸Çaʾzmh¿e>©Ÿ¾zmh¿;”Á>³C9¾zmh¿¬èC±±€2€¿€=>@>€> >À>à>?? ?0?@?P?`?p?€?>€=>>>@>>€>> >>À>>à>>?>?> ?>0?>@?>P?>`?>p?>€?>€>€=€>>€>@>€>€>€> >€>À>€>à>€>?€>?€> ?€>0?€>@?€>P?€>`?€>p?€>€?€>À>€=À>>À>@>À>€>À> >À>À>À>à>À>?À>?À> ?À>0?À>@?À>P?À>`?À>p?À>€?À>?€=?>?@>?€>? >?À>?à>????? ??0??@??P??`??p??€?? ?€= ?> ?@> ?€> ? > ?À> ?à> ?? ?? ? ? ?0? ?@? ?P? ?`? ?p? ?€? ?@?€=@?>@?@>@?€>@? >@?À>@?à>@??@??@? ?@?0?@? @?@?P?@?`?@?p?@?€?@?`?€=`?>`?@>`?€>`? >`?À>`?à>`??`??`? ?`?0?`?@?`?P?`?`?`?p?`?€?`?€?€=€?>€?@>€?€>€? >€?À>€?à>€??€??€? ?€?0?€?@?€?P?€?`?€?p?€?€?€? Èðh®¶ `¥©Ãìqð1OP£&Ú`í[¹>¨- ±9…*¹¼D€”W·ÑNÕSE«†D,Ř¡â³D&Où.Ð’Ä)8ìUâï¢g> r,Ä¡‡Ž .\1ó€˜O¿'aÍEóìAÔY 3®%ý§]¬”ö<¢/’|B—0ˆ?%Ú•²®<¤Ì3S MU²›¹µ^F!ïYï[Û4ävAŠ´ÍkËÒäeŸu¿åŸ08râ¾xÂìSn ÈJVȬ¡„˜…ß̬³Íç­TÖ ˆûÉ´–eq#î»’bpOðVà®p†ÔÛÍ* þ±íl ’`ÿ›5ðòdN–ë'ëd³‰MPòÀ>Ûg†èènd™ÃHÚ‚+²jë gæŽÄÝåÞ!”’Yæe^¯j…ìÿÞê(àØ§”!äégQ˜JÕE6EÙ[øpR6d›ÕÏ0£jìÏKÒá(T ¤ÏÞ‘ ÷.ñÆÑqw‹W8F²-{hº_Sx T´BôxE™B}ó„Å—²ã´¾þž|^Õárt-°+ Y¾ÿŠYà(à9ÄM€WÂô…)ÁôrmÆQ'JÉãª_([3Â!®ÙazõëBoR““Ÿ‚‡(§Š®™q ïHsš‰˜ô?‚:]0¡È‡?kK|§ÎÎð«M6ÔOˆÄ8˜Äs´Ûkä_\ˆP®&^‰âÈV§¦üíÿ(K;öņM¸fx³˜†h°e[.¡hµI^L•bÛDÅú-3fz¢Øü©¾žy BVj™O~˦.<ãöQT=9âbõЧ÷ù™þ¿²¬ïݳ8Þ‘?KUë›õ…þUƒ°?@°3¬65¨Ê@F|f ˆ1UÉŽ\ö_ÖL°ÌÖ³{‹mœSlÄùeF9oƒ†³\äëŽõ}"n¯¶øîçž ×-!s_L)4/I=Í=×ÖšZ°òzô$^½yàÓ<|Û¾Øäyç`Æ7îÂÓÑYÎK/Å3gK„á_ƒ‰A|ž ÂR ü¾ÿ €·Œ‡ê}Ç?Ë‚X_`ö"£ÁÀò[ŽHO“"”Ž8èI›owšc‰¨·Uº½õHVº!¡«Uw~×<Ýl7_oûž}UG’)%àÞŠa?sôš2B5ÂpVŒpÞ,}‹Àv&ENqîúÖ½<_ùúc’í«6›ç‘êÆ³A¯gâµrHÐÆ]8ð …Û…@×”¡…"(ÝßÂmª_ÝY×_–ÎÏüøJ¯é¹àRA‹“ˆ#–ïø;l¹¯^ÿÓKV&œy7ðC;wžåefo®Þ€§^âNïþÝ€0ŸÃÕJñÀÑÎâÄ.ZIʸŸCV³«?½”ª«_l2-h[fî8ý×È[MÓ±È+lð%ÜcÌbôk6aØ.…ùE»¾Räi ßÜ5¸iΆúÊ¡Ÿ@KŠž…é ÌØhñWÎHig«¥šk*Ñ?êRç«/@^egÖ«å“U$ƦJ~æí¹(ˆ·š6CH½MÖ4”m _Öß›Ms åy‡ïÊ„À3îH@#²µ¹"[ª;ÓÇF¹:Å5ÖÚÞ=¢ Ÿy›xî]O‚·Ë£]àu–οØ^Ó¦öˆ ù‚"*Ö‹ÚZA¸h–æ5UY3|è%Ì.Âì_…l¾/oBµü6åû5 î?T­ÆÞ?"Ô€õÚ[&zÀÇ|ºô(#¼5¶\àa•àúï{ËéT5½ƒ²ëÊ0©ÿ7˜ÄœðԂ c “ ÙÆ²ù§/GQ,*Pcç¬Ør³®ýÈzl%”ch-owJƆxʃw†¾:k£ç×Ð"óÌ.0G& îm“ZqÓ'|àpÞÖVL(ȘÞÿÝÄŽŽÆNþÿ¶Š²Ì‘âs~êÒ.«ò¿QWÁÔfRýß@Fh‹üoXŽñ)ÌÃþ7£VH^„ÿ;ÈÎÚª;ïÿƒk4öÿyw$]ëùÿþˆ†ÈI¿;ÿÿÿRobject12àrr™€?ïÃ>^ƒl?ôµ>ö>^ƒl?Ô‹Š>Õ‹Š>^ƒl?ö>ôµ>^ƒl?•ã¶±ïÃ>^ƒl?ö¾ôµ>^ƒl?Õ‹Š¾Ô‹Š>^ƒl?ôµ¾ö>^ƒl?ïþ×tÊ2^ƒl?õµ¾ö¾^ƒl?Ö‹Š¾Ò‹Š¾^ƒl?!ö¾òµ¾^ƒl?IQa³ïþ^ƒl?ö>ôµ¾^ƒl?Ö‹Š>Ӌо^ƒl?öµ>ö¾^ƒl?ó5?ó5?t='?Ô‹Š>ó5?ÿÿÿ>?ó5?Ó‹Š>u='?ó5?¦÷(²ó5?ó5?Ջоt='?ó5?¿þÿÿ>ó5?t='¿Ó‹Š>ó5?ó5¿™ ;3ó5?u='¿Ñ‹Š¾ó5?¿üÿÿ¾ó5?Ú‹Š¾s='¿ó5?Ž*гó5¿ó5?Ô‹Š>t='¿ó5??ýÿÿ¾ó5?v='?Ì‹Š¾ó5?^ƒl?ïÃ>y‚Z?óµ>ïÃ>t='?t='?ïÃ>òµ>y‚Z?ïÃ>:Ä\²^ƒl?ïÃ>ôµ¾y‚Z?ïÃ>u='¿s='?ïÃ>y‚Z¿òµ>ïÃ>^ƒl¿ðbt3ïÃ>z‚Z¿ïµ¾ïÃ>w='¿r='¿ïÃ>ûµ¾w‚Z¿ïÃ>¼ý´^ƒl¿ïÃ>óµ>y‚Z¿ïÃ>v='?r='¿ïÃ>{‚Z?éµ¾ïÃ>€?.½;³^ƒl?ïÃ>.½;³ó5?ó5?.½;³ïÃ>_ƒl?.½;³ºôn²€?.½;³ïþ^ƒl?.½;³ô5¿ò5?.½;³_ƒl¿ïÃ>.½;³€¿ÒB„3.½;³_ƒl¿ïþ.½;³ö5¿ñ5¿.½;³ïþ]ƒl¿.½;³2´€¿.½;³ïÃ>^ƒl¿.½;³õ5?ñ5¿.½;³aƒl? ïþ.½;³^ƒl?ïþy‚Z?óµ>ïþt='?t='?ïþòµ>y‚Z?ïþ:Ä\²^ƒl?ïþôµ¾y‚Z?ïþu='¿s='?ïþy‚Z¿òµ>ïþ^ƒl¿ðbt3ïþz‚Z¿ïµ¾ïþw='¿r='¿ïþûµ¾w‚Z¿ïþ¼ý´^ƒl¿ïþóµ>y‚Z¿ïþv='?r='¿ïþ{‚Z?éµ¾ïþó5?ó5¿t='?Ô‹Š>ó5¿ÿÿÿ>?ó5¿Ó‹Š>u='?ó5¿¦÷(²ó5?ó5¿Õ‹Š¾t='?ó5¿¿þÿÿ>ó5¿t='¿Ó‹Š>ó5¿ó5¿™ ;3ó5¿u='¿Ñ‹Š¾ó5¿¿üÿÿ¾ó5¿Ú‹Š¾s='¿ó5¿Ž*гó5¿ó5¿Ô‹Š>t='¿ó5¿?ýÿÿ¾ó5¿v='?Ì‹Š¾ó5¿ïÃ>^ƒl¿õµ>ö>^ƒl¿Õ‹Š>Õ‹Š>^ƒl¿ö>õµ>^ƒl¿–ã¶±ïÃ>^ƒl¿ö¾õµ>^ƒl¿Ö‹Š¾Ô‹Š>^ƒl¿õµ¾ö>^ƒl¿ïþØtÊ2^ƒl¿öµ¾ö¾^ƒl¿×‹Š¾Ó‹Š¾^ƒl¿"ö¾óµ¾^ƒl¿JQa³ïþ^ƒl¿ö>õµ¾^ƒl¿×‹Š>Ӌо^ƒl¿÷µ>ö¾^ƒl¿€¿›²…ýG2€?áJÖ>¸·C9>zmh?e>©Ÿ>zmh?Â>ÆaÊ>zmh?w¸¼áJÖ>zmh?¸C9¾8”Á>zmh?©Ÿ¾e>zmh?ÆaʾŸÂ>zmh?áJÖ¾_¸¼zmh?9”Á¾´C9¾zmh?e¾©Ÿ¾zmh?¦Â¾Äaʾzmh?T¸<áJÖ¾zmh?¸C9>8”Á¾zmh?©Ÿ>e¾zmh?ÇaÊ>™Â¾zmh?Èà4?(ð<6%5?‡6&?WÄŽ>6%5?°|ü>ƒŽ?5%5?õ†>Ž(?6%5?ùï¼Èà4?6%5?WÄŽ¾‡6&?6%5?„Ž¿­|ü>5%5?Ž(¿õ†>6%5?Èà4¿€ï¼6%5?ˆ6&¿QÄŽ¾6%5?°|ü¾Ž¿7%5?û†¾(¿6%5?jï<Èà4¿5%5?VÄŽ>‡6&¿6%5?„Ž?¬|ü¾5%5?(?ñ†¾5%5?µul?. ;è,Ä>CûY?rJ·>é,Ä>EQ&?S(?é,Ä>ª²>tðZ?è,Ä>õ- »µul?è,Ä>rJ·¾AûY?è,Ä>R(¿DQ&?è,Ä>tðZ¿‹ª²>é,Ä>µul¿.- »è,Ä>CûY¿kJ·¾è,Ä>GQ&¿P(¿ë,Ä>“ª²¾rðZ¿é,Ä>©, ;µul¿è,Ä>rJ·>CûY¿é,Ä>U(?CQ&¿é,Ä>tðZ?‡ª²¾è,Ä>€?¨24 !›2^ƒl?ïÃ>mJ1±ô5?ó5?!!›²ïÃ>_ƒl?mJ1³€?mJ±2ïþ^ƒl?mJ1±ô5¿ó5?¼sDz_ƒl¿ïÃ>€¿ Ý2»sÇ2_ƒl¿ïþmJ±1ö5¿ñ5¿ !›²ïþ^ƒl¿WÆó³€¿mJ±2ïÃ>^ƒl¿mJ1±ö5?ò5¿Ó÷„²`ƒl?ïþnJ1±´ul?ö, »ê,ľrðZ?Žª²>ì,ľS(?EQ&?ë,ľqJ·>AûY?ë,ľ®- ;µul?ì,Ä¾Žª²¾rðZ?ì,ľEQ&¿Q(?ë,ľAûY¿rJ·>ì,ľµul¿N. ;ì,ľtðZ¿ˆª²¾ë,ľT(¿CQ&¿ë,ľuJ·¾@ûY¿ë,ľã. »µul¿ì,Ä¾Žª²>rðZ¿ì,ľFQ&?P(¿ë,ľCûY?jJ·¾ì,ľÈà4?sï¼6%5¿Ž(?÷†>6%5¿ƒŽ?¯|ü>6%5¿UÄŽ>‡6&?6%5¿Ÿï<Èà4?6%5¿÷†¾Ž(?6%5¿°|ü¾Ž?6%5¿‡6&¿UÄŽ>6%5¿Èà4¿ð<6%5¿Ž(¿ó†¾6%5¿„Ž¿¨|ü¾6%5¿YÄŽ¾†6&¿6%5¿7ð¼Èà4¿6%5¿÷†>Ž(¿6%5¿°|ü>Ž¿6%5¿ˆ6&?QÄŽ¾6%5¿ãJÖ>W¸¼zmh¿ÆaÊ> Â>zmh¿©Ÿ>e>zmh¿¸C9>8”Á>zmh¿n¸<áJÖ>zmh¿¡Â¾ÅaÊ>zmh¿e¾©Ÿ>zmh¿:”Á¾·C9>zmh¿ãJÖ¾¸Çaʾzmh¿e>©Ÿ¾zmh¿;”Á>³C9¾zmh¿¬èC±±€2€¿€=>$øô @>€> >À>à>$øô ?? ?0?@?$øô P?`?p?€?>$øô €=>>>@>>€>> >>$øô À>>à>>?>?> ?>$øô 0?>@?>P?>`?>p?>$øô €?>€>€=€>>€>@>€>$øô €>€> >€>À>€>à>€>?€>$øô ?€> ?€>0?€>@?€>P?€>$øô `?€>p?€>€?€>À>€=À>$øô >À>@>À>€>À> >À>À>À>$øô à>À>?À>?À> ?À>0?À>$øô @?À>P?À>`?À>p?À>€?À>$øô ?€=?>?@>?€>?$øô  >?À>?à>?????$øô ??0??@??P??`??$øô p??€?? ?€= ?> ?$øô @> ?€> ? > ?À> ?à> ?$øô ? ?? ? ? ?0? ?@? ?$øô P? ?`? ?p? ?€? ?@?$øô €=@?>@?@>@?€>@? >@?$øô À>@?à>@??@??@? ?@?$øô 0?@?@?@?P?@?`?@?p?@?$øô €?@?`?€=`?>`?@>`?$øô €>`? >`?À>`?à>`??`?$øô ?`? ?`?0?`?@?`?P?`?$øô `?`?p?`?€?`?€?€=€?$øô >€?@>€?€>€? >€?À>€?à>€?…ýG2?€?zmh??€?e> ?€?ÆaÊ>0?€?zmh?@?€?©Ÿ¾P?€?ŸÂ>`?€?zmh?p?€?e¾€?€?ÄaʾÈðh®¶ `¥©Ãìqð1OP£&Ú`í[¹>¨- ±9…*¹¼D€”W·ÑNÕSE«†D,Ř¡â³D&Où.Ð’Ä)8ìUâï¢g> r,Ä¡‡Ž .\1ó€˜O¿'aÍEóìAÔY 3®%ý§]¬”ö<¢/’|B—0ˆ?%Ú•²®<¤Ì3S MU²›¹µ^F!ïYï[Û4ävAŠ´ÍkËÒäeŸu¿åŸ08râ¾xÂìSn ÈJVȬ¡„˜…ß̬³Íç­TÖ ˆûÉ´–eq#î»’bpOðVà®p†ÔÛÍ* þ±íl ’`ÿ›5ðòdN–ë'ëd³‰MPòÀ>Ûg†èènd™ÃHÚ‚+²jë gæŽÄÝåÞ!”’Yæe^¯j…ìÿÞê(àØ§”!äégQ˜JÕE6EÙ[øpR6d›ÕÏ0£jìÏKÒá(T ¤ÏÞ‘ ÷.ñÆÑqw‹W8F²-{hº_Sx T´BôxE™B}ó„Å—²ã´¾þž|^Õárt-°+ Y¾ÿŠYà(à9ÄM€WÂô…)ÁôrmÆQ'JÉãª_([3Â!®ÙazõëBoR““Ÿ‚‡(§Š®™q ïHsš‰˜ô?‚:]0¡È‡?kK|§ÎÎð«M6ÔOˆÄ8˜Äs´Ûkä_\ˆP®&^‰âÈV§¦üíÿ(K;öņM¸fx³˜†h°e[.¡hµI^L•bÛDÅú-3fz¢Øü©¾žy BVj™O~˦.<ãöQT=9âbõЧ÷ù™þ¿²¬ïݳ8Þ‘?KUë›õ…þUƒ°?@°3¬65¨Ê@F|f ˆ1UÉŽ\ö_ÖL°ÌÖ³{‹mœSlÄùeF9oƒ†³\äëŽõ}"n¯¶øîçž ×-!s_L)4/I=Í=×ÖšZ°òzô$^½yàÓ<|Û¾Øäyç`Æ7îÂÓÑYÎK/Å3gK„á_ƒ‰A|ž ÂR ü¾ÿ €·Œ‡ê}Ç?Ë‚X_`ö"£ÁÀò[ŽHO“"”Ž8èI›owšc‰¨·Uº½õHVº!¡«Uw~×<Ýl7_oûž}UG’)%àÞŠa?sôš2B5ÂpVŒpÞ,}‹Àv&ENqîúÖ½<_ùúc’í«6›ç‘êÆ³A¯gâµrHÐÆ]8ð …Û…@×”¡…"(ÝßÂmª_ÝY×_–ÎÏüøJ¯é¹àRA‹“ˆ#–ïø;l¹¯^ÿÓKV&œy7ðC;wžåefo®Þ€§^âNïþÝ€0ŸÃÕJñÀÑÎâÄ.ZIʸŸCV³«?½”ª«_l2-h[fî8ý×È[MÓ±È+lð%ÜcÌbôk6aØ.…ùE»¾Räi ßÜ5¸iΆúÊ¡Ÿ@KŠž…é ÌØhñWÎHig«¥šk*Ñ?êRç«/@^egÖ«å“U$ƦJ~æí¹(ˆ·š6CH½MÖ4”m _Öß›Ms åy‡ïÊ„À3îH@#²µ¹"[ª;ÓÇF¹:Å5ÖÚÞ=¢ Ÿy›xî]O‚·Ë£]àu–οØ^Ó¦öˆ ù‚"*Ö‹ÚZA¸h–æ5UY3|è%Ì.Âì_…l¾/oBµü6åû5 î?T­ÆÞ?"Ô€õÚ[&zÀÇ|ºô(#¼5¶\àa•àúï{ËéT5½ƒ²ëÊ0©ÿ7˜ÄœðԂ c “ ÙÆ²ù§/GQ,*Pcç¬Ør³®ýÈzl%”ch-owJƆxʃw†¾:k£ç×Ð"óÌ.0G& îm“ZqÓ'|àpÞÖVL(ȘÞÿÝÄŽŽÆNþÿ¶Š²Ì‘âs~êÒ.«ò¿QWÁÔfRýß@Fh‹üoXŽñ)ÌÃþ7£VH^„ÿ;ÈÎÚª;ïÿƒk4öÿyw$]ëùÿþˆ†ÈI¿;ÿÿÿRobject10àrr™€?ïÃ>^ƒl?ôµ>ö>^ƒl?Ô‹Š>Õ‹Š>^ƒl?ö>ôµ>^ƒl?•ã¶±ïÃ>^ƒl?ö¾ôµ>^ƒl?Õ‹Š¾Ô‹Š>^ƒl?ôµ¾ö>^ƒl?ïþ×tÊ2^ƒl?õµ¾ö¾^ƒl?Ö‹Š¾Ò‹Š¾^ƒl?!ö¾òµ¾^ƒl?IQa³ïþ^ƒl?ö>ôµ¾^ƒl?Ö‹Š>Ӌо^ƒl?öµ>ö¾^ƒl?ó5?ó5?t='?Ô‹Š>ó5?ÿÿÿ>?ó5?Ó‹Š>u='?ó5?¦÷(²ó5?ó5?Ջоt='?ó5?¿þÿÿ>ó5?t='¿Ó‹Š>ó5?ó5¿™ ;3ó5?u='¿Ñ‹Š¾ó5?¿üÿÿ¾ó5?Ú‹Š¾s='¿ó5?Ž*гó5¿ó5?Ô‹Š>t='¿ó5??ýÿÿ¾ó5?v='?Ì‹Š¾ó5?^ƒl?ïÃ>y‚Z?óµ>ïÃ>t='?t='?ïÃ>òµ>y‚Z?ïÃ>:Ä\²^ƒl?ïÃ>ôµ¾y‚Z?ïÃ>u='¿s='?ïÃ>y‚Z¿òµ>ïÃ>^ƒl¿ðbt3ïÃ>z‚Z¿ïµ¾ïÃ>w='¿r='¿ïÃ>ûµ¾w‚Z¿ïÃ>¼ý´^ƒl¿ïÃ>óµ>y‚Z¿ïÃ>v='?r='¿ïÃ>{‚Z?éµ¾ïÃ>€?.½;³^ƒl?ïÃ>.½;³ó5?ó5?.½;³ïÃ>_ƒl?.½;³ºôn²€?.½;³ïþ^ƒl?.½;³ô5¿ò5?.½;³_ƒl¿ïÃ>.½;³€¿ÒB„3.½;³_ƒl¿ïþ.½;³ö5¿ñ5¿.½;³ïþ]ƒl¿.½;³2´€¿.½;³ïÃ>^ƒl¿.½;³õ5?ñ5¿.½;³aƒl? ïþ.½;³^ƒl?ïþy‚Z?óµ>ïþt='?t='?ïþòµ>y‚Z?ïþ:Ä\²^ƒl?ïþôµ¾y‚Z?ïþu='¿s='?ïþy‚Z¿òµ>ïþ^ƒl¿ðbt3ïþz‚Z¿ïµ¾ïþw='¿r='¿ïþûµ¾w‚Z¿ïþ¼ý´^ƒl¿ïþóµ>y‚Z¿ïþv='?r='¿ïþ{‚Z?éµ¾ïþó5?ó5¿t='?Ô‹Š>ó5¿ÿÿÿ>?ó5¿Ó‹Š>u='?ó5¿¦÷(²ó5?ó5¿Õ‹Š¾t='?ó5¿¿þÿÿ>ó5¿t='¿Ó‹Š>ó5¿ó5¿™ ;3ó5¿u='¿Ñ‹Š¾ó5¿¿üÿÿ¾ó5¿Ú‹Š¾s='¿ó5¿Ž*гó5¿ó5¿Ô‹Š>t='¿ó5¿?ýÿÿ¾ó5¿v='?Ì‹Š¾ó5¿ïÃ>^ƒl¿õµ>ö>^ƒl¿Õ‹Š>Õ‹Š>^ƒl¿ö>õµ>^ƒl¿–ã¶±ïÃ>^ƒl¿ö¾õµ>^ƒl¿Ö‹Š¾Ô‹Š>^ƒl¿õµ¾ö>^ƒl¿ïþØtÊ2^ƒl¿öµ¾ö¾^ƒl¿×‹Š¾Ó‹Š¾^ƒl¿"ö¾óµ¾^ƒl¿JQa³ïþ^ƒl¿ö>õµ¾^ƒl¿×‹Š>Ӌо^ƒl¿÷µ>ö¾^ƒl¿€¿›²…ýG2€?áJÖ>¸·C9>zmh?e>©Ÿ>zmh?Â>ÆaÊ>zmh?w¸¼áJÖ>zmh?¸C9¾8”Á>zmh?©Ÿ¾e>zmh?ÆaʾŸÂ>zmh?áJÖ¾_¸¼zmh?9”Á¾´C9¾zmh?e¾©Ÿ¾zmh?¦Â¾Äaʾzmh?T¸<áJÖ¾zmh?¸C9>8”Á¾zmh?©Ÿ>e¾zmh?ÇaÊ>™Â¾zmh?Èà4?(ð<6%5?‡6&?WÄŽ>6%5?°|ü>ƒŽ?5%5?õ†>Ž(?6%5?ùï¼Èà4?6%5?WÄŽ¾‡6&?6%5?„Ž¿­|ü>5%5?Ž(¿õ†>6%5?Èà4¿€ï¼6%5?ˆ6&¿QÄŽ¾6%5?°|ü¾Ž¿7%5?û†¾(¿6%5?jï<Èà4¿5%5?VÄŽ>‡6&¿6%5?„Ž?¬|ü¾5%5?(?ñ†¾5%5?µul?. ;è,Ä>CûY?rJ·>é,Ä>EQ&?S(?é,Ä>ª²>tðZ?è,Ä>õ- »µul?è,Ä>rJ·¾AûY?è,Ä>R(¿DQ&?è,Ä>tðZ¿‹ª²>é,Ä>µul¿.- »è,Ä>CûY¿kJ·¾è,Ä>GQ&¿P(¿ë,Ä>“ª²¾rðZ¿é,Ä>©, ;µul¿è,Ä>rJ·>CûY¿é,Ä>U(?CQ&¿é,Ä>tðZ?‡ª²¾è,Ä>€?¨24 !›2^ƒl?ïÃ>mJ1±ô5?ó5?!!›²ïÃ>_ƒl?mJ1³€?mJ±2ïþ^ƒl?mJ1±ô5¿ó5?¼sDz_ƒl¿ïÃ>€¿ Ý2»sÇ2_ƒl¿ïþmJ±1ö5¿ñ5¿ !›²ïþ^ƒl¿WÆó³€¿mJ±2ïÃ>^ƒl¿mJ1±ö5?ò5¿Ó÷„²`ƒl?ïþnJ1±´ul?ö, »ê,ľrðZ?Žª²>ì,ľS(?EQ&?ë,ľqJ·>AûY?ë,ľ®- ;µul?ì,Ä¾Žª²¾rðZ?ì,ľEQ&¿Q(?ë,ľAûY¿rJ·>ì,ľµul¿N. ;ì,ľtðZ¿ˆª²¾ë,ľT(¿CQ&¿ë,ľuJ·¾@ûY¿ë,ľã. »µul¿ì,Ä¾Žª²>rðZ¿ì,ľFQ&?P(¿ë,ľCûY?jJ·¾ì,ľÈà4?sï¼6%5¿Ž(?÷†>6%5¿ƒŽ?¯|ü>6%5¿UÄŽ>‡6&?6%5¿Ÿï<Èà4?6%5¿÷†¾Ž(?6%5¿°|ü¾Ž?6%5¿‡6&¿UÄŽ>6%5¿Èà4¿ð<6%5¿Ž(¿ó†¾6%5¿„Ž¿¨|ü¾6%5¿YÄŽ¾†6&¿6%5¿7ð¼Èà4¿6%5¿÷†>Ž(¿6%5¿°|ü>Ž¿6%5¿ˆ6&?QÄŽ¾6%5¿ãJÖ>W¸¼zmh¿ÆaÊ> Â>zmh¿©Ÿ>e>zmh¿¸C9>8”Á>zmh¿n¸<áJÖ>zmh¿¡Â¾ÅaÊ>zmh¿e¾©Ÿ>zmh¿:”Á¾·C9>zmh¿ãJÖ¾¸Çaʾzmh¿e>©Ÿ¾zmh¿;”Á>³C9¾zmh¿¬èC±±€2€¿€=>@>€> >À>à>?? ?0?@?P?`?p?€?>€=>>>@>>€>> >>À>>à>>?>?> ?>0?>@?>P?>`?>p?>€?>€>€=€>>€>@>€>€>€> >€>À>€>à>€>?€>?€> ?€>0?€>@?€>P?€>`?€>p?€>€?€>À>€=À>>À>@>À>€>À> >À>À>À>à>À>?À>?À> ?À>0?À>@?À>P?À>`?À>p?À>€?À>?€=?>?@>?€>? >?À>?à>????? ??0??@??P??`??p??€?? ?€= ?> ?@> ?€> ? > ?À> ?à> ?? ?? ? ? ?0? ?@? ?P? ?`? ?p? ?€? ?@?€=@?>@?@>@?€>@? >@?À>@?à>@??@??@? ?@?0?@?@?@?P?@?`?@?p?@?€?@?`?€=`?>`?@>`?€>`? >`?À>`?à>`??`??`? ?`?0?`?@?`?P?`?`?`?p?`?€?`?€?€=€?>€?@>€?€>€? >€?À>€?à>€??€??€? ?€?0?€?@?€?P?€?`?€?p?€?€?€?Èðh®¶ `¥©Ãìqð1OP£&Ú`í[¹>¨- ±9…*¹¼D€”W·ÑNÕSE«†D,Ř¡â³D&Où.Ð’Ä)8ìUâï¢g> r,Ä¡‡Ž .\1ó€˜O¿'aÍEóìAÔY 3®%ý§]¬”ö<¢/’|B—0ˆ?%Ú•²®<¤Ì3S MU²›¹µ^F!ïYï[Û4ävAŠ´ÍkËÒäeŸu¿åŸ08râ¾xÂìSn ÈJVȬ¡„˜…ß̬³Íç­TÖ ˆûÉ´–eq#î»’bpOðVà®p†ÔÛÍ* þ±íl ’`ÿ›5ðòdN–ë'ëd³‰MPòÀ>Ûg†èènd™ÃHÚ‚+²jë gæŽÄÝåÞ!”’Yæe^¯j…ìÿÞê(àØ§”!äégQ˜JÕE6EÙ[øpR6d›ÕÏ0£jìÏKÒá(T ¤ÏÞ‘ ÷.ñÆÑqw‹W8F²-{hº_Sx T´BôxE™B}ó„Å—²ã´¾þž|^Õárt-°+ Y¾ÿŠYà(à9ÄM€WÂô…)ÁôrmÆQ'JÉãª_([3Â!®ÙazõëBoR““Ÿ‚‡(§Š®™q ïHsš‰˜ô?‚:]0¡È‡?kK|§ÎÎð«M6ÔOˆÄ8˜Äs´Ûkä_\ˆP®&^‰âÈV§¦üíÿ(K;öņM¸fx³˜†h°e[.¡hµI^L•bÛDÅú-3fz¢Øü©¾žy BVj™O~˦.<ãöQT=9âbõЧ÷ù™þ¿²¬ïݳ8Þ‘?KUë›õ…þUƒ°?@°3¬65¨Ê@F|f ˆ1UÉŽ\ö_ÖL°ÌÖ³{‹mœSlÄùeF9oƒ†³\äëŽõ}"n¯¶øîçž ×-!s_L)4/I=Í=×ÖšZ°òzô$^½yàÓ<|Û¾Øäyç`Æ7îÂÓÑYÎK/Å3gK„á_ƒ‰A|ž ÂR ü¾ÿ €·Œ‡ê}Ç?Ë‚X_`ö"£ÁÀò[ŽHO“"”Ž8èI›owšc‰¨·Uº½õHVº!¡«Uw~×<Ýl7_oûž}UG’)%àÞŠa?sôš2B5ÂpVŒpÞ,}‹Àv&ENqîúÖ½<_ùúc’í«6›ç‘êÆ³A¯gâµrHÐÆ]8ð …Û…@×”¡…"(ÝßÂmª_ÝY×_–ÎÏüøJ¯é¹àRA‹“ˆ#–ïø;l¹¯^ÿÓKV&œy7ðC;wžåefo®Þ€§^âNïþÝ€0ŸÃÕJñÀÑÎâÄ.ZIʸŸCV³«?½”ª«_l2-h[fî8ý×È[MÓ±È+lð%ÜcÌbôk6aØ.…ùE»¾Räi ßÜ5¸iΆúÊ¡Ÿ@KŠž…é ÌØhñWÎHig«¥šk*Ñ?êRç«/@^egÖ«å“U$ƦJ~æí¹(ˆ·š6CH½MÖ4”m _Öß›Ms åy‡ïÊ„À3îH@#²µ¹"[ª;ÓÇF¹:Å5ÖÚÞ=¢ Ÿy›xî]O‚·Ë£]àu–οØ^Ó¦öˆ ù‚"*Ö‹ÚZA¸h–æ5UY3|è%Ì.Âì_…l¾/oBµü6åû5 î?T­ÆÞ?"Ô€õÚ[&zÀÇ|ºô(#¼5¶\àa•àúï{ËéT5½ƒ²ëÊ0©ÿ7˜ÄœðԂ c “ ÙÆ²ù§/GQ,*Pcç¬Ør³®ýÈzl%”ch-owJƆxʃw†¾:k£ç×Ð"óÌ.0G& îm“ZqÓ'|àpÞÖVL(ȘÞÿÝÄŽŽÆNþÿ¶Š²Ì‘âs~êÒ.«ò¿QWÁÔfRýß@Fh‹üoXŽñ)ÌÃþ7£VH^„ÿ;ÈÎÚª;ïÿƒk4öÿyw$]ëùÿþˆ†ÈI¿;ÿÿÿQobject8àrr™€?ïÃ>^ƒl?ôµ>ö>^ƒl?Ô‹Š>Õ‹Š>^ƒl?ö>ôµ>^ƒl?•ã¶±ïÃ>^ƒl?ö¾ôµ>^ƒl?Õ‹Š¾Ô‹Š>^ƒl?ôµ¾ö>^ƒl?ïþ×tÊ2^ƒl?õµ¾ö¾^ƒl?Ö‹Š¾Ò‹Š¾^ƒl?!ö¾òµ¾^ƒl?IQa³ïþ^ƒl?ö>ôµ¾^ƒl?Ö‹Š>Ӌо^ƒl?öµ>ö¾^ƒl?ó5?ó5?t='?Ô‹Š>ó5?ÿÿÿ>?ó5?Ó‹Š>u='?ó5?¦÷(²ó5?ó5?Ջоt='?ó5?¿þÿÿ>ó5?t='¿Ó‹Š>ó5?ó5¿™ ;3ó5?u='¿Ñ‹Š¾ó5?¿üÿÿ¾ó5?Ú‹Š¾s='¿ó5?Ž*гó5¿ó5?Ô‹Š>t='¿ó5??ýÿÿ¾ó5?v='?Ì‹Š¾ó5?^ƒl?ïÃ>y‚Z?óµ>ïÃ>t='?t='?ïÃ>òµ>y‚Z?ïÃ>:Ä\²^ƒl?ïÃ>ôµ¾y‚Z?ïÃ>u='¿s='?ïÃ>y‚Z¿òµ>ïÃ>^ƒl¿ðbt3ïÃ>z‚Z¿ïµ¾ïÃ>w='¿r='¿ïÃ>ûµ¾w‚Z¿ïÃ>¼ý´^ƒl¿ïÃ>óµ>y‚Z¿ïÃ>v='?r='¿ïÃ>{‚Z?éµ¾ïÃ>€?.½;³^ƒl?ïÃ>.½;³ó5?ó5?.½;³ïÃ>_ƒl?.½;³ºôn²€?.½;³ïþ^ƒl?.½;³ô5¿ò5?.½;³_ƒl¿ïÃ>.½;³€¿ÒB„3.½;³_ƒl¿ïþ.½;³ö5¿ñ5¿.½;³ïþ]ƒl¿.½;³2´€¿.½;³ïÃ>^ƒl¿.½;³õ5?ñ5¿.½;³aƒl? ïþ.½;³^ƒl?ïþy‚Z?óµ>ïþt='?t='?ïþòµ>y‚Z?ïþ:Ä\²^ƒl?ïþôµ¾y‚Z?ïþu='¿s='?ïþy‚Z¿òµ>ïþ^ƒl¿ðbt3ïþz‚Z¿ïµ¾ïþw='¿r='¿ïþûµ¾w‚Z¿ïþ¼ý´^ƒl¿ïþóµ>y‚Z¿ïþv='?r='¿ïþ{‚Z?éµ¾ïþó5?ó5¿t='?Ô‹Š>ó5¿ÿÿÿ>?ó5¿Ó‹Š>u='?ó5¿¦÷(²ó5?ó5¿Õ‹Š¾t='?ó5¿¿þÿÿ>ó5¿t='¿Ó‹Š>ó5¿ó5¿™ ;3ó5¿u='¿Ñ‹Š¾ó5¿¿üÿÿ¾ó5¿Ú‹Š¾s='¿ó5¿Ž*гó5¿ó5¿Ô‹Š>t='¿ó5¿?ýÿÿ¾ó5¿v='?Ì‹Š¾ó5¿ïÃ>^ƒl¿õµ>ö>^ƒl¿Õ‹Š>Õ‹Š>^ƒl¿ö>õµ>^ƒl¿–ã¶±ïÃ>^ƒl¿ö¾õµ>^ƒl¿Ö‹Š¾Ô‹Š>^ƒl¿õµ¾ö>^ƒl¿ïþØtÊ2^ƒl¿öµ¾ö¾^ƒl¿×‹Š¾Ó‹Š¾^ƒl¿"ö¾óµ¾^ƒl¿JQa³ïþ^ƒl¿ö>õµ¾^ƒl¿×‹Š>Ӌо^ƒl¿÷µ>ö¾^ƒl¿€¿›²…ýG2€?áJÖ>¸·C9>zmh?e>©Ÿ>zmh?Â>ÆaÊ>zmh?w¸¼áJÖ>zmh?¸C9¾8”Á>zmh?©Ÿ¾e>zmh?ÆaʾŸÂ>zmh?áJÖ¾_¸¼zmh?9”Á¾´C9¾zmh?e¾©Ÿ¾zmh?¦Â¾Äaʾzmh?T¸<áJÖ¾zmh?¸C9>8”Á¾zmh?©Ÿ>e¾zmh?ÇaÊ>™Â¾zmh?Èà4?(ð<6%5?‡6&?WÄŽ>6%5?°|ü>ƒŽ?5%5?õ†>Ž(?6%5?ùï¼Èà4?6%5?WÄŽ¾‡6&?6%5?„Ž¿­|ü>5%5?Ž(¿õ†>6%5?Èà4¿€ï¼6%5?ˆ6&¿QÄŽ¾6%5?°|ü¾Ž¿7%5?û†¾(¿6%5?jï<Èà4¿5%5?VÄŽ>‡6&¿6%5?„Ž?¬|ü¾5%5?(?ñ†¾5%5?µul?. ;è,Ä>CûY?rJ·>é,Ä>EQ&?S(?é,Ä>ª²>tðZ?è,Ä>õ- »µul?è,Ä>rJ·¾AûY?è,Ä>R(¿DQ&?è,Ä>tðZ¿‹ª²>é,Ä>µul¿.- »è,Ä>CûY¿kJ·¾è,Ä>GQ&¿P(¿ë,Ä>“ª²¾rðZ¿é,Ä>©, ;µul¿è,Ä>rJ·>CûY¿é,Ä>U(?CQ&¿é,Ä>tðZ?‡ª²¾è,Ä>€?¨24 !›2^ƒl?ïÃ>mJ1±ô5?ó5?!!›²ïÃ>_ƒl?mJ1³€?mJ±2ïþ^ƒl?mJ1±ô5¿ó5?¼sDz_ƒl¿ïÃ>€¿ Ý2»sÇ2_ƒl¿ïþmJ±1ö5¿ñ5¿ !›²ïþ^ƒl¿WÆó³€¿mJ±2ïÃ>^ƒl¿mJ1±ö5?ò5¿Ó÷„²`ƒl?ïþnJ1±´ul?ö, »ê,ľrðZ?Žª²>ì,ľS(?EQ&?ë,ľqJ·>AûY?ë,ľ®- ;µul?ì,Ä¾Žª²¾rðZ?ì,ľEQ&¿Q(?ë,ľAûY¿rJ·>ì,ľµul¿N. ;ì,ľtðZ¿ˆª²¾ë,ľT(¿CQ&¿ë,ľuJ·¾@ûY¿ë,ľã. »µul¿ì,Ä¾Žª²>rðZ¿ì,ľFQ&?P(¿ë,ľCûY?jJ·¾ì,ľÈà4?sï¼6%5¿Ž(?÷†>6%5¿ƒŽ?¯|ü>6%5¿UÄŽ>‡6&?6%5¿Ÿï<Èà4?6%5¿÷†¾Ž(?6%5¿°|ü¾Ž?6%5¿‡6&¿UÄŽ>6%5¿Èà4¿ð<6%5¿Ž(¿ó†¾6%5¿„Ž¿¨|ü¾6%5¿YÄŽ¾†6&¿6%5¿7ð¼Èà4¿6%5¿÷†>Ž(¿6%5¿°|ü>Ž¿6%5¿ˆ6&?QÄŽ¾6%5¿ãJÖ>W¸¼zmh¿ÆaÊ> Â>zmh¿©Ÿ>e>zmh¿¸C9>8”Á>zmh¿n¸<áJÖ>zmh¿¡Â¾ÅaÊ>zmh¿e¾©Ÿ>zmh¿:”Á¾·C9>zmh¿ãJÖ¾¸Çaʾzmh¿e>©Ÿ¾zmh¿;”Á>³C9¾zmh¿¬èC±±€2€¿€=o>o@>€>q >qÀ>ƒà>s?s?… ?u0?u@?xP?x`?‹p?|€?|>€=>€>>€@>>“€>>„ >>„À>>—à>>?>?> ?> 0?>@?>P?>`?>p?>€?>#€>'€=€>+>€>/@>€>3€>€>7 >€>;À>€>?à>€>C?€>G?€>K ?€>O0?€>S@?€>WP?€>[`?€>_p?€>c€?€>gÀ>k€=À>o>À>s@>À>w€>À>{ >À>À>À>ƒà>À>‡?À>‹?À> ?À>“0?À>—@?À>›P?À>Ÿ`?À>£p?À>§€?À>«?¯€=?³>?·@>?»€>?¿ >?ÃÀ>?Çà>?Ë??Ï??Ó ??×0??Û@??ßP??`??p??€?? ?€= ?> ? @> ? €> ? > ? À> ?à> ?? ?? ? ? ?0? ?@? ?P? ?`? ?p? ?€? ?@?€=@?>@?@>@?€>@?  >@? À>@?à>@? ?@? ?@? ?@?0?@?@?@?P?@?`?@?p?@?!€?@?`?€=`?#>`?@>`?€>`?% >`?À>`?à>`?'?`??`? ?`?)0?`?@?`?P?`?+`?`?p?`?€?`?-€?€=€?>€?/@>€? €>€?  >€?1À>€?"à>€?"?€?3?€?$ ?€?$0?€?5@?€?&P?€?&`?€?7p?€?(€?€?(Èðh®¶ `¥©Ãìqð1OP£&Ú`í[¹>¨- ±9…*¹¼D€”W·ÑNÕSE«†D,Ř¡â³D&Où.Ð’Ä)8ìUâï¢g> r,Ä¡‡Ž .\1ó€˜O¿'aÍEóìAÔY 3®%ý§]¬”ö<¢/’|B—0ˆ?%Ú•²®<¤Ì3S MU²›¹µ^F!ïYï[Û4ävAŠ´ÍkËÒäeŸu¿åŸ08râ¾xÂìSn ÈJVȬ¡„˜…ß̬³Íç­TÖ ˆûÉ´–eq#î»’bpOðVà®p†ÔÛÍ* þ±íl ’`ÿ›5ðòdN–ë'ëd³‰MPòÀ>Ûg†èènd™ÃHÚ‚+²jë gæŽÄÝåÞ!”’Yæe^¯j…ìÿÞê(àØ§”!äégQ˜JÕE6EÙ[øpR6d›ÕÏ0£jìÏKÒá(T ¤ÏÞ‘ ÷.ñÆÑqw‹W8F²-{hº_Sx T´BôxE™B}ó„Å—²ã´¾þž|^Õárt-°+ Y¾ÿŠYà(à9ÄM€WÂô…)ÁôrmÆQ'JÉãª_([3Â!®ÙazõëBoR““Ÿ‚‡(§Š®™q ïHsš‰˜ô?‚:]0¡È‡?kK|§ÎÎð«M6ÔOˆÄ8˜Äs´Ûkä_\ˆP®&^‰âÈV§¦üíÿ(K;öņM¸fx³˜†h°e[.¡hµI^L•bÛDÅú-3fz¢Øü©¾žy BVj™O~˦.<ãöQT=9âbõЧ÷ù™þ¿²¬ïݳ8Þ‘?KUë›õ…þUƒ°?@°3¬65¨Ê@F|f ˆ1UÉŽ\ö_ÖL°ÌÖ³{‹mœSlÄùeF9oƒ†³\äëŽõ}"n¯¶øîçž ×-!s_L)4/I=Í=×ÖšZ°òzô$^½yàÓ<|Û¾Øäyç`Æ7îÂÓÑYÎK/Å3gK„á_ƒ‰A|ž ÂR ü¾ÿ €·Œ‡ê}Ç?Ë‚X_`ö"£ÁÀò[ŽHO“"”Ž8èI›owšc‰¨·Uº½õHVº!¡«Uw~×<Ýl7_oûž}UG’)%àÞŠa?sôš2B5ÂpVŒpÞ,}‹Àv&ENqîúÖ½<_ùúc’í«6›ç‘êÆ³A¯gâµrHÐÆ]8ð …Û…@×”¡…"(ÝßÂmª_ÝY×_–ÎÏüøJ¯é¹àRA‹“ˆ#–ïø;l¹¯^ÿÓKV&œy7ðC;wžåefo®Þ€§^âNïþÝ€0ŸÃÕJñÀÑÎâÄ.ZIʸŸCV³«?½”ª«_l2-h[fî8ý×È[MÓ±È+lð%ÜcÌbôk6aØ.…ùE»¾Räi ßÜ5¸iΆúÊ¡Ÿ@KŠž…é ÌØhñWÎHig«¥šk*Ñ?êRç«/@^egÖ«å“U$ƦJ~æí¹(ˆ·š6CH½MÖ4”m _Öß›Ms åy‡ïÊ„À3îH@#²µ¹"[ª;ÓÇF¹:Å5ÖÚÞ=¢ Ÿy›xî]O‚·Ë£]àu–οØ^Ó¦öˆ ù‚"*Ö‹ÚZA¸h–æ5UY3|è%Ì.Âì_…l¾/oBµü6åû5 î?T­ÆÞ?"Ô€õÚ[&zÀÇ|ºô(#¼5¶\àa•àúï{ËéT5½ƒ²ëÊ0©ÿ7˜ÄœðԂ c “ ÙÆ²ù§/GQ,*Pcç¬Ør³®ýÈzl%”ch-owJƆxʃw†¾:k£ç×Ð"óÌ.0G& îm“ZqÓ'|àpÞÖVL(ȘÞÿÝÄŽŽÆNþÿ¶Š²Ì‘âs~êÒ.«ò¿QWÁÔfRýß@Fh‹üoXŽñ)ÌÃþ7£VH^„ÿ;ÈÎÚª;ïÿƒk4öÿyw$]ëùÿþˆ†ÈI¿;ÿÿÿQobject6àrr™€?ïÃ>^ƒl?ôµ>ö>^ƒl?Ô‹Š>Õ‹Š>^ƒl?ö>ôµ>^ƒl?•ã¶±ïÃ>^ƒl?ö¾ôµ>^ƒl?Õ‹Š¾Ô‹Š>^ƒl?ôµ¾ö>^ƒl?ïþ×tÊ2^ƒl?õµ¾ö¾^ƒl?Ö‹Š¾Ò‹Š¾^ƒl?!ö¾òµ¾^ƒl?IQa³ïþ^ƒl?ö>ôµ¾^ƒl?Ö‹Š>Ӌо^ƒl?öµ>ö¾^ƒl?ó5?ó5?t='?Ô‹Š>ó5?ÿÿÿ>?ó5?Ó‹Š>u='?ó5?¦÷(²ó5?ó5?Ջоt='?ó5?¿þÿÿ>ó5?t='¿Ó‹Š>ó5?ó5¿™ ;3ó5?u='¿Ñ‹Š¾ó5?¿üÿÿ¾ó5?Ú‹Š¾s='¿ó5?Ž*гó5¿ó5?Ô‹Š>t='¿ó5??ýÿÿ¾ó5?v='?Ì‹Š¾ó5?^ƒl?ïÃ>y‚Z?óµ>ïÃ>t='?t='?ïÃ>òµ>y‚Z?ïÃ>:Ä\²^ƒl?ïÃ>ôµ¾y‚Z?ïÃ>u='¿s='?ïÃ>y‚Z¿òµ>ïÃ>^ƒl¿ðbt3ïÃ>z‚Z¿ïµ¾ïÃ>w='¿r='¿ïÃ>ûµ¾w‚Z¿ïÃ>¼ý´^ƒl¿ïÃ>óµ>y‚Z¿ïÃ>v='?r='¿ïÃ>{‚Z?éµ¾ïÃ>€?.½;³^ƒl?ïÃ>.½;³ó5?ó5?.½;³ïÃ>_ƒl?.½;³ºôn²€?.½;³ïþ^ƒl?.½;³ô5¿ò5?.½;³_ƒl¿ïÃ>.½;³€¿ÒB„3.½;³_ƒl¿ïþ.½;³ö5¿ñ5¿.½;³ïþ]ƒl¿.½;³2´€¿.½;³ïÃ>^ƒl¿.½;³õ5?ñ5¿.½;³aƒl? ïþ.½;³^ƒl?ïþy‚Z?óµ>ïþt='?t='?ïþòµ>y‚Z?ïþ:Ä\²^ƒl?ïþôµ¾y‚Z?ïþu='¿s='?ïþy‚Z¿òµ>ïþ^ƒl¿ðbt3ïþz‚Z¿ïµ¾ïþw='¿r='¿ïþûµ¾w‚Z¿ïþ¼ý´^ƒl¿ïþóµ>y‚Z¿ïþv='?r='¿ïþ{‚Z?éµ¾ïþó5?ó5¿t='?Ô‹Š>ó5¿ÿÿÿ>?ó5¿Ó‹Š>u='?ó5¿¦÷(²ó5?ó5¿Õ‹Š¾t='?ó5¿¿þÿÿ>ó5¿t='¿Ó‹Š>ó5¿ó5¿™ ;3ó5¿u='¿Ñ‹Š¾ó5¿¿üÿÿ¾ó5¿Ú‹Š¾s='¿ó5¿Ž*гó5¿ó5¿Ô‹Š>t='¿ó5¿?ýÿÿ¾ó5¿v='?Ì‹Š¾ó5¿ïÃ>^ƒl¿õµ>ö>^ƒl¿Õ‹Š>Õ‹Š>^ƒl¿ö>õµ>^ƒl¿–ã¶±ïÃ>^ƒl¿ö¾õµ>^ƒl¿Ö‹Š¾Ô‹Š>^ƒl¿õµ¾ö>^ƒl¿ïþØtÊ2^ƒl¿öµ¾ö¾^ƒl¿×‹Š¾Ó‹Š¾^ƒl¿"ö¾óµ¾^ƒl¿JQa³ïþ^ƒl¿ö>õµ¾^ƒl¿×‹Š>Ӌо^ƒl¿÷µ>ö¾^ƒl¿€¿›²…ýG2€?áJÖ>¸·C9>zmh?e>©Ÿ>zmh?Â>ÆaÊ>zmh?w¸¼áJÖ>zmh?¸C9¾8”Á>zmh?©Ÿ¾e>zmh?ÆaʾŸÂ>zmh?áJÖ¾_¸¼zmh?9”Á¾´C9¾zmh?e¾©Ÿ¾zmh?¦Â¾Äaʾzmh?T¸<áJÖ¾zmh?¸C9>8”Á¾zmh?©Ÿ>e¾zmh?ÇaÊ>™Â¾zmh?Èà4?(ð<6%5?‡6&?WÄŽ>6%5?°|ü>ƒŽ?5%5?õ†>Ž(?6%5?ùï¼Èà4?6%5?WÄŽ¾‡6&?6%5?„Ž¿­|ü>5%5?Ž(¿õ†>6%5?Èà4¿€ï¼6%5?ˆ6&¿QÄŽ¾6%5?°|ü¾Ž¿7%5?û†¾(¿6%5?jï<Èà4¿5%5?VÄŽ>‡6&¿6%5?„Ž?¬|ü¾5%5?(?ñ†¾5%5?µul?. ;è,Ä>CûY?rJ·>é,Ä>EQ&?S(?é,Ä>ª²>tðZ?è,Ä>õ- »µul?è,Ä>rJ·¾AûY?è,Ä>R(¿DQ&?è,Ä>tðZ¿‹ª²>é,Ä>µul¿.- »è,Ä>CûY¿kJ·¾è,Ä>GQ&¿P(¿ë,Ä>“ª²¾rðZ¿é,Ä>©, ;µul¿è,Ä>rJ·>CûY¿é,Ä>U(?CQ&¿é,Ä>tðZ?‡ª²¾è,Ä>€?¨24 !›2^ƒl?ïÃ>mJ1±ô5?ó5?!!›²ïÃ>_ƒl?mJ1³€?mJ±2ïþ^ƒl?mJ1±ô5¿ó5?¼sDz_ƒl¿ïÃ>€¿ Ý2»sÇ2_ƒl¿ïþmJ±1ö5¿ñ5¿ !›²ïþ^ƒl¿WÆó³€¿mJ±2ïÃ>^ƒl¿mJ1±ö5?ò5¿Ó÷„²`ƒl?ïþnJ1±´ul?ö, »ê,ľrðZ?Žª²>ì,ľS(?EQ&?ë,ľqJ·>AûY?ë,ľ®- ;µul?ì,Ä¾Žª²¾rðZ?ì,ľEQ&¿Q(?ë,ľAûY¿rJ·>ì,ľµul¿N. ;ì,ľtðZ¿ˆª²¾ë,ľT(¿CQ&¿ë,ľuJ·¾@ûY¿ë,ľã. »µul¿ì,Ä¾Žª²>rðZ¿ì,ľFQ&?P(¿ë,ľCûY?jJ·¾ì,ľÈà4?sï¼6%5¿Ž(?÷†>6%5¿ƒŽ?¯|ü>6%5¿UÄŽ>‡6&?6%5¿Ÿï<Èà4?6%5¿÷†¾Ž(?6%5¿°|ü¾Ž?6%5¿‡6&¿UÄŽ>6%5¿Èà4¿ð<6%5¿Ž(¿ó†¾6%5¿„Ž¿¨|ü¾6%5¿YÄŽ¾†6&¿6%5¿7ð¼Èà4¿6%5¿÷†>Ž(¿6%5¿°|ü>Ž¿6%5¿ˆ6&?QÄŽ¾6%5¿ãJÖ>W¸¼zmh¿ÆaÊ> Â>zmh¿©Ÿ>e>zmh¿¸C9>8”Á>zmh¿n¸<áJÖ>zmh¿¡Â¾ÅaÊ>zmh¿e¾©Ÿ>zmh¿:”Á¾·C9>zmh¿ãJÖ¾¸Çaʾzmh¿e>©Ÿ¾zmh¿;”Á>³C9¾zmh¿¬èC±±€2€¿Ô‹Š>€=ó5¿>¦÷(²@>t='?€>ó5¿ >ó5¿À>Ñ‹Š¾à>ó5¿?Ž*г?t='¿ ?ó5¿0?ïÃ>@?ö>P?^ƒl¿`?–ã¶±p?õµ>€?^ƒl¿>ïþ€=>ö¾>>^ƒl¿@>>JQa³€>>õµ¾ >>^ƒl¿À>>à>> ?>?> ?>$øô 0?>@?>P?>`?>p?>$øô €?>€>€=€>>€>@>€>$øô €>€> >€>À>€>à>€>?€>$øô ?€> ?€>0?€>@?€>P?€>$øô `?€>p?€>€?€>À>€=À>$øô >À>@>À>€>À> >À>À>À>$øô à>À>?À>?À> ?À>0?À>$øô @?À>P?À>`?À>p?À>€?À>$øô ?€=?>?@>?€>?$øô  >?À>?à>?????$øô ??0??@??P??`??$øô p??€?? ?€= ?> ?$øô @> ?€> ? > ?À> ?à> ?$øô ? ?? ? ? ?0? ?@? ?$øô P? ?`? ?p? ?€? ?@?$øô €=@?>@?@>@?€>@? >@?$øô À>@?à>@??@??@? ?@?$øô 0?@?@?@?P?@?`?@?p?@?$øô €?@?`?€=`?>`?@>`?$øô €>`? >`?À>`?à>`??`?$øô ?`? ?`?0?`?@?`?P?`?$øô `?`?p?`?€?`?€?€=€?$øô >€?@>€?€>€? >€?À>€?$øô à>€??€??€? ?€?0?€?$øô @?€?P?€?`?€?p?€?€?€?$øô Èðh®¶ `¥©Ãìqð1OP£&Ú`í[¹>¨- ±9…*¹¼D€”W·ÑNÕSE«†D,Ř¡â³D&Où.Ð’Ä)8ìUâï¢g> r,Ä¡‡Ž .\1ó€˜O¿'aÍEóìAÔY 3®%ý§]¬”ö<¢/’|B—0ˆ?%Ú•²®<¤Ì3S MU²›¹µ^F!ïYï[Û4ävAŠ´ÍkËÒäeŸu¿åŸ08râ¾xÂìSn ÈJVȬ¡„˜…ß̬³Íç­TÖ ˆûÉ´–eq#î»’bpOðVà®p†ÔÛÍ* þ±íl ’`ÿ›5ðòdN–ë'ëd³‰MPòÀ>Ûg†èènd™ÃHÚ‚+²jë gæŽÄÝåÞ!”’Yæe^¯j…ìÿÞê(àØ§”!äégQ˜JÕE6EÙ[øpR6d›ÕÏ0£jìÏKÒá(T ¤ÏÞ‘ ÷.ñÆÑqw‹W8F²-{hº_Sx T´BôxE™B}ó„Å—²ã´¾þž|^Õárt-°+ Y¾ÿŠYà(à9ÄM€WÂô…)ÁôrmÆQ'JÉãª_([3Â!®ÙazõëBoR““Ÿ‚‡(§Š®™q ïHsš‰˜ô?‚:]0¡È‡?kK|§ÎÎð«M6ÔOˆÄ8˜Äs´Ûkä_\ˆP®&^‰âÈV§¦üíÿ(K;öņM¸fx³˜†h°e[.¡hµI^L•bÛDÅú-3fz¢Øü©¾žy BVj™O~˦.<ãöQT=9âbõЧ÷ù™þ¿²¬ïݳ8Þ‘?KUë›õ…þUƒ°?@°3¬65¨Ê@F|f ˆ1UÉŽ\ö_ÖL°ÌÖ³{‹mœSlÄùeF9oƒ†³\äëŽõ}"n¯¶øîçž ×-!s_L)4/I=Í=×ÖšZ°òzô$^½yàÓ<|Û¾Øäyç`Æ7îÂÓÑYÎK/Å3gK„á_ƒ‰A|ž ÂR ü¾ÿ €·Œ‡ê}Ç?Ë‚X_`ö"£ÁÀò[ŽHO“"”Ž8èI›owšc‰¨·Uº½õHVº!¡«Uw~×<Ýl7_oûž}UG’)%àÞŠa?sôš2B5ÂpVŒpÞ,}‹Àv&ENqîúÖ½<_ùúc’í«6›ç‘êÆ³A¯gâµrHÐÆ]8ð …Û…@×”¡…"(ÝßÂmª_ÝY×_–ÎÏüøJ¯é¹àRA‹“ˆ#–ïø;l¹¯^ÿÓKV&œy7ðC;wžåefo®Þ€§^âNïþÝ€0ŸÃÕJñÀÑÎâÄ.ZIʸŸCV³«?½”ª«_l2-h[fî8ý×È[MÓ±È+lð%ÜcÌbôk6aØ.…ùE»¾Räi ßÜ5¸iΆúÊ¡Ÿ@KŠž…é ÌØhñWÎHig«¥šk*Ñ?êRç«/@^egÖ«å“U$ƦJ~æí¹(ˆ·š6CH½MÖ4”m _Öß›Ms åy‡ïÊ„À3îH@#²µ¹"[ª;ÓÇF¹:Å5ÖÚÞ=¢ Ÿy›xî]O‚·Ë£]àu–οØ^Ó¦öˆ ù‚"*Ö‹ÚZA¸h–æ5UY3|è%Ì.Âì_…l¾/oBµü6åû5 î?T­ÆÞ?"Ô€õÚ[&zÀÇ|ºô(#¼5¶\àa•àúï{ËéT5½ƒ²ëÊ0©ÿ7˜ÄœðԂ c “ ÙÆ²ù§/GQ,*Pcç¬Ør³®ýÈzl%”ch-owJƆxʃw†¾:k£ç×Ð"óÌ.0G& îm“ZqÓ'|àpÞÖVL(ȘÞÿÝÄŽŽÆNþÿ¶Š²Ì‘âs~êÒ.«ò¿QWÁÔfRýß@Fh‹üoXŽñ)ÌÃþ7£VH^„ÿ;ÈÎÚª;ïÿƒk4öÿyw$]ëùÿþˆ†ÈI¿;ÿÿÿQobject4àrr™€?ïÃ>^ƒl?ôµ>ö>^ƒl?Ô‹Š>Õ‹Š>^ƒl?ö>ôµ>^ƒl?•ã¶±ïÃ>^ƒl?ö¾ôµ>^ƒl?Õ‹Š¾Ô‹Š>^ƒl?ôµ¾ö>^ƒl?ïþ×tÊ2^ƒl?õµ¾ö¾^ƒl?Ö‹Š¾Ò‹Š¾^ƒl?!ö¾òµ¾^ƒl?IQa³ïþ^ƒl?ö>ôµ¾^ƒl?Ö‹Š>Ӌо^ƒl?öµ>ö¾^ƒl?ó5?ó5?t='?Ô‹Š>ó5?ÿÿÿ>?ó5?Ó‹Š>u='?ó5?¦÷(²ó5?ó5?Ջоt='?ó5?¿þÿÿ>ó5?t='¿Ó‹Š>ó5?ó5¿™ ;3ó5?u='¿Ñ‹Š¾ó5?¿üÿÿ¾ó5?Ú‹Š¾s='¿ó5?Ž*гó5¿ó5?Ô‹Š>t='¿ó5??ýÿÿ¾ó5?v='?Ì‹Š¾ó5?^ƒl?ïÃ>y‚Z?óµ>ïÃ>t='?t='?ïÃ>òµ>y‚Z?ïÃ>:Ä\²^ƒl?ïÃ>ôµ¾y‚Z?ïÃ>u='¿s='?ïÃ>y‚Z¿òµ>ïÃ>^ƒl¿ðbt3ïÃ>z‚Z¿ïµ¾ïÃ>w='¿r='¿ïÃ>ûµ¾w‚Z¿ïÃ>¼ý´^ƒl¿ïÃ>óµ>y‚Z¿ïÃ>v='?r='¿ïÃ>{‚Z?éµ¾ïÃ>€?.½;³^ƒl?ïÃ>.½;³ó5?ó5?.½;³ïÃ>_ƒl?.½;³ºôn²€?.½;³ïþ^ƒl?.½;³ô5¿ò5?.½;³_ƒl¿ïÃ>.½;³€¿ÒB„3.½;³_ƒl¿ïþ.½;³ö5¿ñ5¿.½;³ïþ]ƒl¿.½;³2´€¿.½;³ïÃ>^ƒl¿.½;³õ5?ñ5¿.½;³aƒl? ïþ.½;³^ƒl?ïþy‚Z?óµ>ïþt='?t='?ïþòµ>y‚Z?ïþ:Ä\²^ƒl?ïþôµ¾y‚Z?ïþu='¿s='?ïþy‚Z¿òµ>ïþ^ƒl¿ðbt3ïþz‚Z¿ïµ¾ïþw='¿r='¿ïþûµ¾w‚Z¿ïþ¼ý´^ƒl¿ïþóµ>y‚Z¿ïþv='?r='¿ïþ{‚Z?éµ¾ïþó5?ó5¿t='?Ô‹Š>ó5¿ÿÿÿ>?ó5¿Ó‹Š>u='?ó5¿¦÷(²ó5?ó5¿Õ‹Š¾t='?ó5¿¿þÿÿ>ó5¿t='¿Ó‹Š>ó5¿ó5¿™ ;3ó5¿u='¿Ñ‹Š¾ó5¿¿üÿÿ¾ó5¿Ú‹Š¾s='¿ó5¿Ž*гó5¿ó5¿Ô‹Š>t='¿ó5¿?ýÿÿ¾ó5¿v='?Ì‹Š¾ó5¿ïÃ>^ƒl¿õµ>ö>^ƒl¿Õ‹Š>Õ‹Š>^ƒl¿ö>õµ>^ƒl¿–ã¶±ïÃ>^ƒl¿ö¾õµ>^ƒl¿Ö‹Š¾Ô‹Š>^ƒl¿õµ¾ö>^ƒl¿ïþØtÊ2^ƒl¿öµ¾ö¾^ƒl¿×‹Š¾Ó‹Š¾^ƒl¿"ö¾óµ¾^ƒl¿JQa³ïþ^ƒl¿ö>õµ¾^ƒl¿×‹Š>Ӌо^ƒl¿÷µ>ö¾^ƒl¿€¿›²…ýG2€?áJÖ>¸·C9>zmh?e>©Ÿ>zmh?Â>ÆaÊ>zmh?w¸¼áJÖ>zmh?¸C9¾8”Á>zmh?©Ÿ¾e>zmh?ÆaʾŸÂ>zmh?áJÖ¾_¸¼zmh?9”Á¾´C9¾zmh?e¾©Ÿ¾zmh?¦Â¾Äaʾzmh?T¸<áJÖ¾zmh?¸C9>8”Á¾zmh?©Ÿ>e¾zmh?ÇaÊ>™Â¾zmh?Èà4?(ð<6%5?‡6&?WÄŽ>6%5?°|ü>ƒŽ?5%5?õ†>Ž(?6%5?ùï¼Èà4?6%5?WÄŽ¾‡6&?6%5?„Ž¿­|ü>5%5?Ž(¿õ†>6%5?Èà4¿€ï¼6%5?ˆ6&¿QÄŽ¾6%5?°|ü¾Ž¿7%5?û†¾(¿6%5?jï<Èà4¿5%5?VÄŽ>‡6&¿6%5?„Ž?¬|ü¾5%5?(?ñ†¾5%5?µul?. ;è,Ä>CûY?rJ·>é,Ä>EQ&?S(?é,Ä>ª²>tðZ?è,Ä>õ- »µul?è,Ä>rJ·¾AûY?è,Ä>R(¿DQ&?è,Ä>tðZ¿‹ª²>é,Ä>µul¿.- »è,Ä>CûY¿kJ·¾è,Ä>GQ&¿P(¿ë,Ä>“ª²¾rðZ¿é,Ä>©, ;µul¿è,Ä>rJ·>CûY¿é,Ä>U(?CQ&¿é,Ä>tðZ?‡ª²¾è,Ä>€?¨24 !›2^ƒl?ïÃ>mJ1±ô5?ó5?!!›²ïÃ>_ƒl?mJ1³€?mJ±2ïþ^ƒl?mJ1±ô5¿ó5?¼sDz_ƒl¿ïÃ>€¿ Ý2»sÇ2_ƒl¿ïþmJ±1ö5¿ñ5¿ !›²ïþ^ƒl¿WÆó³€¿mJ±2ïÃ>^ƒl¿mJ1±ö5?ò5¿Ó÷„²`ƒl?ïþnJ1±´ul?ö, »ê,ľrðZ?Žª²>ì,ľS(?EQ&?ë,ľqJ·>AûY?ë,ľ®- ;µul?ì,Ä¾Žª²¾rðZ?ì,ľEQ&¿Q(?ë,ľAûY¿rJ·>ì,ľµul¿N. ;ì,ľtðZ¿ˆª²¾ë,ľT(¿CQ&¿ë,ľuJ·¾@ûY¿ë,ľã. »µul¿ì,Ä¾Žª²>rðZ¿ì,ľFQ&?P(¿ë,ľCûY?jJ·¾ì,ľÈà4?sï¼6%5¿Ž(?÷†>6%5¿ƒŽ?¯|ü>6%5¿UÄŽ>‡6&?6%5¿Ÿï<Èà4?6%5¿÷†¾Ž(?6%5¿°|ü¾Ž?6%5¿‡6&¿UÄŽ>6%5¿Èà4¿ð<6%5¿Ž(¿ó†¾6%5¿„Ž¿¨|ü¾6%5¿YÄŽ¾†6&¿6%5¿7ð¼Èà4¿6%5¿÷†>Ž(¿6%5¿°|ü>Ž¿6%5¿ˆ6&?QÄŽ¾6%5¿ãJÖ>W¸¼zmh¿ÆaÊ> Â>zmh¿©Ÿ>e>zmh¿¸C9>8”Á>zmh¿n¸<áJÖ>zmh¿¡Â¾ÅaÊ>zmh¿e¾©Ÿ>zmh¿:”Á¾·C9>zmh¿ãJÖ¾¸Çaʾzmh¿e>©Ÿ¾zmh¿;”Á>³C9¾zmh¿¬èC±±€2€¿i€=Z>Z@>k€>\ >\À>mà>^?^?o ?`0?`@?bP?b`?qp?f€?f>q€=>j>>j@>>q€>>n >>nÀ>>qà>>?>ïÃ>?>ö> ?>^ƒl?0?>•ã¶±@?>ôµ>P?>^ƒl?`?>ïþp?>ö¾€?>^ƒl?€>IQa³€=€>ôµ¾>€>^ƒl?@>€>ó5?€>€>Ô‹Š> >€>ó5?À>€>¦÷(²à>€>t='??€>ó5??€>ó5¿ ?€>Ñ‹Š¾0?€>ó5?@?€>Ž*гP?€>t='¿`?€>ó5?p?€>^ƒl?€?€>óµ>À>ïÃ>€=À>:Ä\²>À>y‚Z?@>À>ïÃ>€>À>^ƒl¿ >À>ïµ¾À>À>ïÃ>à>À>¼ý´?À>y‚Z¿?À>ïÃ> ?À>€?0?À>ïÃ>@?À>.½;³P?À>ºôn²`?À>^ƒl?p?À>.½;³€?À>€¿?ïþ€=?.½;³>?2´@>?^ƒl¿€>?.½;³ >?^ƒl?À>?óµ>à>?ïþ??:Ä\²??y‚Z? ??ïþ0??^ƒl¿@??ïµ¾P??ïþ`??¼ý´p??y‚Z¿€??ïþ ?ó5?€= ?Ô‹Š>> ?ó5¿@> ?¦÷(²€> ?t='? > ?ó5¿À> ?ó5¿à> ?Ñ‹Š¾? ?ó5¿? ?Ž*г ? ?t='¿0? ?ó5¿@? ?ïÃ>P? ?ö>`? ?^ƒl¿p? ?–ã¶±€? ?õµ>@?^ƒl¿€=@?ïþ>@?ö¾@>@?^ƒl¿€>@?JQa³ >@?õµ¾À>@?^ƒl¿à>@??@? ?@? ?@?0?@?$øô @?@?P?@?`?@?p?@?€?@?$øô `?€=`?>`?@>`?€>`?$øô  >`?À>`?à>`??`??`?$øô ?`?0?`?@?`?P?`?`?`?$øô p?`?€?`?€?€=€?>€?$øô @>€?€>€? >€?À>€?à>€?$øô ?€??€? ?€?0?€?@?€?$øô P?€?`?€?p?€?€?€?Èðh®¶ `¥©Ãìqð1OP£&Ú`í[¹>¨- ±9…*¹¼D€”W·ÑNÕSE«†D,Ř¡â³D&Où.Ð’Ä)8ìUâï¢g> r,Ä¡‡Ž .\1ó€˜O¿'aÍEóìAÔY 3®%ý§]¬”ö<¢/’|B—0ˆ?%Ú•²®<¤Ì3S MU²›¹µ^F!ïYï[Û4ävAŠ´ÍkËÒäeŸu¿åŸ08râ¾xÂìSn ÈJVȬ¡„˜…ß̬³Íç­TÖ ˆûÉ´–eq#î»’bpOðVà®p†ÔÛÍ* þ±íl ’`ÿ›5ðòdN–ë'ëd³‰MPòÀ>Ûg†èènd™ÃHÚ‚+²jë gæŽÄÝåÞ!”’Yæe^¯j…ìÿÞê(àØ§”!äégQ˜JÕE6EÙ[øpR6d›ÕÏ0£jìÏKÒá(T ¤ÏÞ‘ ÷.ñÆÑqw‹W8F²-{hº_Sx T´BôxE™B}ó„Å—²ã´¾þž|^Õárt-°+ Y¾ÿŠYà(à9ÄM€WÂô…)ÁôrmÆQ'JÉãª_([3Â!®ÙazõëBoR““Ÿ‚‡(§Š®™q ïHsš‰˜ô?‚:]0¡È‡?kK|§ÎÎð«M6ÔOˆÄ8˜Äs´Ûkä_\ˆP®&^‰âÈV§¦üíÿ(K;öņM¸fx³˜†h°e[.¡hµI^L•bÛDÅú-3fz¢Øü©¾žy BVj™O~˦.<ãöQT=9âbõЧ÷ù™þ¿²¬ïݳ8Þ‘?KUë›õ…þUƒ°?@°3¬65¨Ê@F|f ˆ1UÉŽ\ö_ÖL°ÌÖ³{‹mœSlÄùeF9oƒ†³\äëŽõ}"n¯¶øîçž ×-!s_L)4/I=Í=×ÖšZ°òzô$^½yàÓ<|Û¾Øäyç`Æ7îÂÓÑYÎK/Å3gK„á_ƒ‰A|ž ÂR ü¾ÿ €·Œ‡ê}Ç?Ë‚X_`ö"£ÁÀò[ŽHO“"”Ž8èI›owšc‰¨·Uº½õHVº!¡«Uw~×<Ýl7_oûž}UG’)%àÞŠa?sôš2B5ÂpVŒpÞ,}‹Àv&ENqîúÖ½<_ùúc’í«6›ç‘êÆ³A¯gâµrHÐÆ]8ð …Û…@×”¡…"(ÝßÂmª_ÝY×_–ÎÏüøJ¯é¹àRA‹“ˆ#–ïø;l¹¯^ÿÓKV&œy7ðC;wžåefo®Þ€§^âNïþÝ€0ŸÃÕJñÀÑÎâÄ.ZIʸŸCV³«?½”ª«_l2-h[fî8ý×È[MÓ±È+lð%ÜcÌbôk6aØ.…ùE»¾Räi ßÜ5¸iΆúÊ¡Ÿ@KŠž…é ÌØhñWÎHig«¥šk*Ñ?êRç«/@^egÖ«å“U$ƦJ~æí¹(ˆ·š6CH½MÖ4”m _Öß›Ms åy‡ïÊ„À3îH@#²µ¹"[ª;ÓÇF¹:Å5ÖÚÞ=¢ Ÿy›xî]O‚·Ë£]àu–οØ^Ó¦öˆ ù‚"*Ö‹ÚZA¸h–æ5UY3|è%Ì.Âì_…l¾/oBµü6åû5 î?T­ÆÞ?"Ô€õÚ[&zÀÇ|ºô(#¼5¶\àa•àúï{ËéT5½ƒ²ëÊ0©ÿ7˜ÄœðԂ c “ ÙÆ²ù§/GQ,*Pcç¬Ør³®ýÈzl%”ch-owJƆxʃw†¾:k£ç×Ð"óÌ.0G& îm“ZqÓ'|àpÞÖVL(ȘÞÿÝÄŽŽÆNþÿ¶Š²Ì‘âs~êÒ.«ò¿QWÁÔfRýß@Fh‹üoXŽñ)ÌÃþ7£VH^„ÿ;ÈÎÚª;ïÿƒk4öÿyw$]ëùÿþˆ†ÈI¿;ÿÿÿQobject2àrr™€?ïÃ>^ƒl?ôµ>ö>^ƒl?Ô‹Š>Õ‹Š>^ƒl?ö>ôµ>^ƒl?•ã¶±ïÃ>^ƒl?ö¾ôµ>^ƒl?Õ‹Š¾Ô‹Š>^ƒl?ôµ¾ö>^ƒl?ïþ×tÊ2^ƒl?õµ¾ö¾^ƒl?Ö‹Š¾Ò‹Š¾^ƒl?!ö¾òµ¾^ƒl?IQa³ïþ^ƒl?ö>ôµ¾^ƒl?Ö‹Š>Ӌо^ƒl?öµ>ö¾^ƒl?ó5?ó5?t='?Ô‹Š>ó5?ÿÿÿ>?ó5?Ó‹Š>u='?ó5?¦÷(²ó5?ó5?Ջоt='?ó5?¿þÿÿ>ó5?t='¿Ó‹Š>ó5?ó5¿™ ;3ó5?u='¿Ñ‹Š¾ó5?¿üÿÿ¾ó5?Ú‹Š¾s='¿ó5?Ž*гó5¿ó5?Ô‹Š>t='¿ó5??ýÿÿ¾ó5?v='?Ì‹Š¾ó5?^ƒl?ïÃ>y‚Z?óµ>ïÃ>t='?t='?ïÃ>òµ>y‚Z?ïÃ>:Ä\²^ƒl?ïÃ>ôµ¾y‚Z?ïÃ>u='¿s='?ïÃ>y‚Z¿òµ>ïÃ>^ƒl¿ðbt3ïÃ>z‚Z¿ïµ¾ïÃ>w='¿r='¿ïÃ>ûµ¾w‚Z¿ïÃ>¼ý´^ƒl¿ïÃ>óµ>y‚Z¿ïÃ>v='?r='¿ïÃ>{‚Z?éµ¾ïÃ>€?.½;³^ƒl?ïÃ>.½;³ó5?ó5?.½;³ïÃ>_ƒl?.½;³ºôn²€?.½;³ïþ^ƒl?.½;³ô5¿ò5?.½;³_ƒl¿ïÃ>.½;³€¿ÒB„3.½;³_ƒl¿ïþ.½;³ö5¿ñ5¿.½;³ïþ]ƒl¿.½;³2´€¿.½;³ïÃ>^ƒl¿.½;³õ5?ñ5¿.½;³aƒl? ïþ.½;³^ƒl?ïþy‚Z?óµ>ïþt='?t='?ïþòµ>y‚Z?ïþ:Ä\²^ƒl?ïþôµ¾y‚Z?ïþu='¿s='?ïþy‚Z¿òµ>ïþ^ƒl¿ðbt3ïþz‚Z¿ïµ¾ïþw='¿r='¿ïþûµ¾w‚Z¿ïþ¼ý´^ƒl¿ïþóµ>y‚Z¿ïþv='?r='¿ïþ{‚Z?éµ¾ïþó5?ó5¿t='?Ô‹Š>ó5¿ÿÿÿ>?ó5¿Ó‹Š>u='?ó5¿¦÷(²ó5?ó5¿Õ‹Š¾t='?ó5¿¿þÿÿ>ó5¿t='¿Ó‹Š>ó5¿ó5¿™ ;3ó5¿u='¿Ñ‹Š¾ó5¿¿üÿÿ¾ó5¿Ú‹Š¾s='¿ó5¿Ž*гó5¿ó5¿Ô‹Š>t='¿ó5¿?ýÿÿ¾ó5¿v='?Ì‹Š¾ó5¿ïÃ>^ƒl¿õµ>ö>^ƒl¿Õ‹Š>Õ‹Š>^ƒl¿ö>õµ>^ƒl¿–ã¶±ïÃ>^ƒl¿ö¾õµ>^ƒl¿Ö‹Š¾Ô‹Š>^ƒl¿õµ¾ö>^ƒl¿ïþØtÊ2^ƒl¿öµ¾ö¾^ƒl¿×‹Š¾Ó‹Š¾^ƒl¿"ö¾óµ¾^ƒl¿JQa³ïþ^ƒl¿ö>õµ¾^ƒl¿×‹Š>Ӌо^ƒl¿÷µ>ö¾^ƒl¿€¿›²…ýG2€?áJÖ>¸·C9>zmh?e>©Ÿ>zmh?Â>ÆaÊ>zmh?w¸¼áJÖ>zmh?¸C9¾8”Á>zmh?©Ÿ¾e>zmh?ÆaʾŸÂ>zmh?áJÖ¾_¸¼zmh?9”Á¾´C9¾zmh?e¾©Ÿ¾zmh?¦Â¾Äaʾzmh?T¸<áJÖ¾zmh?¸C9>8”Á¾zmh?©Ÿ>e¾zmh?ÇaÊ>™Â¾zmh?Èà4?(ð<6%5?‡6&?WÄŽ>6%5?°|ü>ƒŽ?5%5?õ†>Ž(?6%5?ùï¼Èà4?6%5?WÄŽ¾‡6&?6%5?„Ž¿­|ü>5%5?Ž(¿õ†>6%5?Èà4¿€ï¼6%5?ˆ6&¿QÄŽ¾6%5?°|ü¾Ž¿7%5?û†¾(¿6%5?jï<Èà4¿5%5?VÄŽ>‡6&¿6%5?„Ž?¬|ü¾5%5?(?ñ†¾5%5?µul?. ;è,Ä>CûY?rJ·>é,Ä>EQ&?S(?é,Ä>ª²>tðZ?è,Ä>õ- »µul?è,Ä>rJ·¾AûY?è,Ä>R(¿DQ&?è,Ä>tðZ¿‹ª²>é,Ä>µul¿.- »è,Ä>CûY¿kJ·¾è,Ä>GQ&¿P(¿ë,Ä>“ª²¾rðZ¿é,Ä>©, ;µul¿è,Ä>rJ·>CûY¿é,Ä>U(?CQ&¿é,Ä>tðZ?‡ª²¾è,Ä>€?¨24 !›2^ƒl?ïÃ>mJ1±ô5?ó5?!!›²ïÃ>_ƒl?mJ1³€?mJ±2ïþ^ƒl?mJ1±ô5¿ó5?¼sDz_ƒl¿ïÃ>€¿ Ý2»sÇ2_ƒl¿ïþmJ±1ö5¿ñ5¿ !›²ïþ^ƒl¿WÆó³€¿mJ±2ïÃ>^ƒl¿mJ1±ö5?ò5¿Ó÷„²`ƒl?ïþnJ1±´ul?ö, »ê,ľrðZ?Žª²>ì,ľS(?EQ&?ë,ľqJ·>AûY?ë,ľ®- ;µul?ì,Ä¾Žª²¾rðZ?ì,ľEQ&¿Q(?ë,ľAûY¿rJ·>ì,ľµul¿N. ;ì,ľtðZ¿ˆª²¾ë,ľT(¿CQ&¿ë,ľuJ·¾@ûY¿ë,ľã. »µul¿ì,Ä¾Žª²>rðZ¿ì,ľFQ&?P(¿ë,ľCûY?jJ·¾ì,ľÈà4?sï¼6%5¿Ž(?÷†>6%5¿ƒŽ?¯|ü>6%5¿UÄŽ>‡6&?6%5¿Ÿï<Èà4?6%5¿÷†¾Ž(?6%5¿°|ü¾Ž?6%5¿‡6&¿UÄŽ>6%5¿Èà4¿ð<6%5¿Ž(¿ó†¾6%5¿„Ž¿¨|ü¾6%5¿YÄŽ¾†6&¿6%5¿7ð¼Èà4¿6%5¿÷†>Ž(¿6%5¿°|ü>Ž¿6%5¿ˆ6&?QÄŽ¾6%5¿ãJÖ>W¸¼zmh¿ÆaÊ> Â>zmh¿©Ÿ>e>zmh¿¸C9>8”Á>zmh¿n¸<áJÖ>zmh¿¡Â¾ÅaÊ>zmh¿e¾©Ÿ>zmh¿:”Á¾·C9>zmh¿ãJÖ¾¸Çaʾzmh¿e>©Ÿ¾zmh¿;”Á>³C9¾zmh¿¬èC±±€2€¿À>€=À>>À>@>À>€>À> >À>À>À>à>À>?À>?À> ??0??@??P??`??p??€??>?€=>?>>?@>>?€>>? >>?À>>?à>>??>??>? ?> ?0?> ?@?> ?P?> ?`?> ?p?> ?€?> ?€> ?€=€> ?>€> ?@>€> ?€>€> ? >€> ?À>€> ?à>€> ??€> ??€> ? ?€>@?0?€>@?@?€>@?P?€>@?`?€>@?p?€>@?€?€>@?À>@?€=À>@?>À>@?@>À>@?€>À>@? >À>@?À>À>@?à>À>@??À>@??À>@? ?À>`?0?À>`?@?À>`?P?À>`?`?À>`?p?À>`?€?À>`??`?€=?`?>?`?@>?`?€>?`? >?`?À>?`?à>?`???`???`? ??€?0??€?@??€?P??€?`??€?p??€?€??€? ?€?€= ?€?> ?€?@> ?€?€> ?€? > ?€?À> ?€?à> ?€?? ?€?? ?€? ? ?0? ?@? ?P? ?`? ?p? ?€? ?@? €=@?>@?@>@? €>@? >@?!À>@?à>@?#?@??@? ?@?%0?@?@?@?P?@?'`?@?p?@?€?@?)`?€=`?>`?+@>`?€>`? >`?-À>`?à>`??`?/?`? ?`?0?`?1@?`?!P?`?"`?`?4p?`?$€?`?$€?6€=€?&>€?&@>€?8€>€?( >€?(À>€?:à>€?*?€?*?€?< ?€?,0?€?,@?€?>P?€?.`?€?.p?€?@€?€?0Èðh®¶ `¥©Ãìqð1OP£&Ú`í[¹>¨- ±9…*¹¼D€”W·ÑNÕSE«†D,Ř¡â³D&Où.Ð’Ä)8ìUâï¢g> r,Ä¡‡Ž .\1ó€˜O¿'aÍEóìAÔY 3®%ý§]¬”ö<¢/’|B—0ˆ?%Ú•²®<¤Ì3S MU²›¹µ^F!ïYï[Û4ävAŠ´ÍkËÒäeŸu¿åŸ08râ¾xÂìSn ÈJVȬ¡„˜…ß̬³Íç­TÖ ˆûÉ´–eq#î»’bpOðVà®p†ÔÛÍ* þ±íl ’`ÿ›5ðòdN–ë'ëd³‰MPòÀ>Ûg†èènd™ÃHÚ‚+²jë gæŽÄÝåÞ!”’Yæe^¯j…ìÿÞê(àØ§”!äégQ˜JÕE6EÙ[øpR6d›ÕÏ0£jìÏKÒá(T ¤ÏÞ‘ ÷.ñÆÑqw‹W8F²-{hº_Sx T´BôxE™B}ó„Å—²ã´¾þž|^Õárt-°+ Y¾ÿŠYà(à9ÄM€WÂô…)ÁôrmÆQ'JÉãª_([3Â!®ÙazõëBoR““Ÿ‚‡(§Š®™q ïHsš‰˜ô?‚:]0¡È‡?kK|§ÎÎð«M6ÔOˆÄ8˜Äs´Ûkä_\ˆP®&^‰âÈV§¦üíÿ(K;öņM¸fx³˜†h°e[.¡hµI^L•bÛDÅú-3fz¢Øü©¾žy BVj™O~˦.<ãöQT=9âbõЧ÷ù™þ¿²¬ïݳ8Þ‘?KUë›õ…þUƒ°?@°3¬65¨Ê@F|f ˆ1UÉŽ\ö_ÖL°ÌÖ³{‹mœSlÄùeF9oƒ†³\äëŽõ}"n¯¶øîçž ×-!s_L)4/I=Í=×ÖšZ°òzô$^½yàÓ<|Û¾Øäyç`Æ7îÂÓÑYÎK/Å3gK„á_ƒ‰A|ž ÂR ü¾ÿ €·Œ‡ê}Ç?Ë‚X_`ö"£ÁÀò[ŽHO“"”Ž8èI›owšc‰¨·Uº½õHVº!¡«Uw~×<Ýl7_oûž}UG’)%àÞŠa?sôš2B5ÂpVŒpÞ,}‹Àv&ENqîúÖ½<_ùúc’í«6›ç‘êÆ³A¯gâµrHÐÆ]8ð …Û…@×”¡…"(ÝßÂmª_ÝY×_–ÎÏüøJ¯é¹àRA‹“ˆ#–ïø;l¹¯^ÿÓKV&œy7ðC;wžåefo®Þ€§^âNïþÝ€0ŸÃÕJñÀÑÎâÄ.ZIʸŸCV³«?½”ª«_l2-h[fî8ý×È[MÓ±È+lð%ÜcÌbôk6aØ.…ùE»¾Räi ßÜ5¸iΆúÊ¡Ÿ@KŠž…é ÌØhñWÎHig«¥šk*Ñ?êRç«/@^egÖ«å“U$ƦJ~æí¹(ˆ·š6CH½MÖ4”m _Öß›Ms åy‡ïÊ„À3îH@#²µ¹"[ª;ÓÇF¹:Å5ÖÚÞ=¢ Ÿy›xî]O‚·Ë£]àu–οØ^Ó¦öˆ ù‚"*Ö‹ÚZA¸h–æ5UY3|è%Ì.Âì_…l¾/oBµü6åû5 î?T­ÆÞ?"Ô€õÚ[&zÀÇ|ºô(#¼5¶\àa•àúï{ËéT5½ƒ²ëÊ0©ÿ7˜ÄœðԂ c “ ÙÆ²ù§/GQ,*Pcç¬Ør³®ýÈzl%”ch-owJƆxʃw†¾:k£ç×Ð"óÌ.0G& îm“ZqÓ'|àpÞÖVL(ȘÞÿÝÄŽŽÆNþÿ¶Š²Ì‘âs~êÒ.«ò¿QWÁÔfRýß@Fh‹üoXŽñ)ÌÃþ7£VH^„ÿ;ÈÎÚª;ïÿƒk4öÿyw$]ëùÿþˆ†ÈI¿asymptote-2.37/examples/animations/earthmoon.asy000066400000000000000000000036151265434602500222000ustar00rootroot00000000000000import graph3; import solids; import three; import animate; settings.render=2; settings.tex="pdflatex"; settings.prc=false; settings.thick=false; settings.outformat="mpg"; currentprojection=orthographic(5,4,2); currentlight=light(specular=black,(0.1,-0.1,1),viewport=true); size(15cm,0); animation A; real Rst=20, Rl=0.7, Rtl=5; real ast=20, est=0.3, bst=ast*sqrt(1-est^2), cst=ast*est; real atl=5, etl=0.8, btl=atl*sqrt(1-etl^2), ctl=atl*etl; real xST(real t) {return ast*cos(t)+cst;} real yST(real t) {return bst*sin(t);} real zST(real t) {return 0;} real xTL(real t) {return atl*cos(27t);} real yTL(real t) {return btl*sin(27t);} real zTL(real t) {return 0;} real xLl(real t) {return Rl*cos(27t);} real yLl(real t) {return Rl*sin(27t);} real zLl(real t) {return 0;} real xTt(real t) {return Rtl*cos(100t)/5;} real yTt(real t) {return Rtl*sin(100t)/5;} real zTt(real t) {return 0;} real xl(real t) {return xST(t)+xTL(t)+xLl(t);} real yl(real t) {return yST(t)+yTL(t)+yLl(t);} real zl(real t) {return 0;} real xt(real t) {return xST(t)+xTt(t);} real yt(real t) {return yST(t)+yTt(t);} real zt(real t) {return 0;} real xL(real t) {return xST(t)+xTL(t);} real yL(real t) {return yST(t)+yTL(t);} real zL(real t) {return 0;} path3 Pl=graph(xl,yl,zl,0,2pi,1000),Pt=graph(xt,yt,zt,0,2pi,3000), Pts=graph(xST,yST,zST,0,2pi,500); picture pic; draw(pic,Pl,lightgray); draw(pic,Pt,lightblue); draw(pic,Pts,blue+dashed); draw(pic,shift(cst,0,0)*scale3(Rtl/2)*unitsphere,yellow); surface terre=scale3(Rtl/5)*unitsphere; surface lune=scale3(Rl)*unitsphere; int n=50; real step=2pi/n; for(int i=0; i < n; ++i) { real k=i*step; add(pic); draw(shift(xL(k),yL(k),0)*lune,lightgray); draw(shift(xST(k),yST(k),0)*terre,lightblue+lightgreen); A.add(); erase(); } A.movie(BBox(1mm,Fill(Black)),delay=500, options="-density 288x288 -geometry 50%x"); asymptote-2.37/examples/animations/embeddedmovie.asy000066400000000000000000000007671265434602500230020ustar00rootroot00000000000000// An embedded movie; // // See http://mirror.ctan.org/macros/latex/contrib/media9/doc/media9.pdf // for documentation of the options. import embed; // Add embedded movie //import external; // Add external movie (use this form under Linux). // Generated needed mp4 file if it doesn't already exist. asy("mp4","wheel"); // Produce a pdf file. settings.outformat="pdf"; settings.twice=true; // An embedded movie: label(embed("wheel.mp4",20cm,5.6cm),(0,0),N); label(link("wheel.mp4"),(0,0),S); asymptote-2.37/examples/animations/embeddedu3d.asy000066400000000000000000000003041265434602500223410ustar00rootroot00000000000000// An embedded U3D object; // import embed; settings.tex="pdflatex"; label(embedplayer("dice.u3d","dice","activate=pagevisible,3Droo=27", settings.paperwidth,settings.paperheight)); asymptote-2.37/examples/animations/externalmovie.asy000066400000000000000000000006331265434602500230630ustar00rootroot00000000000000// Embed a movie to be run in an external window. import external; // External movies require the pdflatex engine. settings.tex="pdflatex"; // Generated needed mpeg file if it doesn't already exist. asy("mp4","wheel"); // Produce a pdf file. settings.outformat="pdf"; // External movie: viewable even with the Linux version of acroread. label(embed("wheel.mp4"),(0,0),N); label(link("wheel.mp4"),(0,0),S); asymptote-2.37/examples/animations/glmovie.asy000066400000000000000000000006361265434602500216460ustar00rootroot00000000000000settings.autoplay=true; settings.loop=true; import graph3; import animate; currentprojection=orthographic(1,-2,0.5); animation A; int n=25; for(int i=0; i < n; ++i) { picture pic; size3(pic,6cm); real k=i/n*pi; real f(pair z) {return 4cos(abs(z)-k)*exp(-abs(z)/6);} draw(pic,surface(f,(-4pi,-4pi),(4pi,4pi),Spline),paleblue); draw(pic,shift(i*6Z/n)*unitsphere,yellow); A.add(pic); } A.glmovie(); asymptote-2.37/examples/animations/heatequation.asy000066400000000000000000000033401265434602500226660ustar00rootroot00000000000000import graph3; import palette; import animate; settings.tex="pdflatex"; settings.render=0; settings.prc=false; unitsize(1cm); animation a; currentprojection=perspective(-20,-18,18); currentlight=light(1,1,10); int n=26; real L=2.5; real dx=2*L/n; real CFL=0.125; real dt=CFL*dx^2; real[][] Z=new real[n][n]; real[][] W=new real[n][n]; guide initcond1=shift((-1,-1))*scale(0.5)*unitcircle; guide initcond2=shift((0.5,0))*yscale(1.2)*unitcircle; real f(pair p) {return (inside(initcond1,p)||inside(initcond2,p)) ? 2 : 0;} //Initialize for(int i=0; i < n; ++i) for (int j=0; j < n; ++j) Z[i][j]=f((-L,-L)+(2*L/n)*(i,j)); real f(pair t) { int i=round((n/2)*(t.x/L+1)); int j=round((n/2)*(t.y/L+1)); if(i > n-1) i=n-1; if(j > n-1) j=n-1; return Z[i][j]; } surface sf; void advanceZ(int iter=20) { for(int k=0; k < iter; ++k) { for(int i=0; i < n; ++i) for(int j=0; j < n; ++j) W[i][j]=0; for(int i=1; i < n-1; ++i) for(int j=1; j< n-1; ++j) W[i][j]=Z[i][j]+(dt/dx^2)*(Z[i+1][j]+Z[i-1][j]+Z[i][j-1]+Z[i][j+1] -4*Z[i][j]); for(int i=0; i < n; ++i) for(int j=0; j < n; ++j) Z[i][j]=W[i][j]; }; } pen[] Pal=Rainbow(96); int endframe=40; for(int fr=0; fr < endframe; ++fr) { if(fr == 0) {// smoothing of initial state; no Spline, but full grid advanceZ(3); sf=surface(f,(-L,-L),(L,L),nx=n); } else // use Spline and fewer grid points to save memory sf=surface(f,(-L,-L),(L,L),nx=round(n/2),Spline); sf.colors(palette(sf.map(zpart),Pal[0:round(48*max(sf).z)])); draw(sf); a.add(); erase(); advanceZ(30); }; label(a.pdf(delay=400,"controls,loop")); shipout(bbox(3mm,darkblue+3bp+miterjoin,FillDraw(fillpen=paleblue)),"pdf"); asymptote-2.37/examples/animations/inlinemovie.tex000066400000000000000000000023231265434602500225210ustar00rootroot00000000000000\documentclass{article} \usepackage[inline]{asymptote} %\usepackage{asymptote} \usepackage{animate} \begin{document} Here is an inline PDF movie, generated with the commands \begin{verbatim} pdflatex inlinemovie asy inlinemovie-*.asy pdflatex inlinemovie \end{verbatim} or equivalently, \begin{verbatim} latexmk -pdf inlinemovie \end{verbatim} \begin{center} \begin{asy} import animate; animation A=animation("movie1"); real h=2pi/10; picture pic; unitsize(pic,2cm); for(int i=0; i < 10; ++i) { draw(pic,expi(i*h)--expi((i+1)*h)); A.add(pic); } label(A.pdf("controls",delay=50,keep=!settings.inlinetex)); \end{asy} %Uncomment the following line when not using the [inline] package option: %\ASYanimategraphics[controls]{50}{movie1}{}{} \end{center} And here is another one, clickable but without the control panel: \begin{center} \begin{asy} import animate; animation A=animation("movie2"); real h=2pi/10; picture pic; unitsize(pic,2cm); for(int i=0; i < 10; ++i) { draw(pic,expi(-i*h)--expi(-(i+1)*h),red); A.add(pic); } label(A.pdf(keep=!settings.inlinetex)); \end{asy} %Uncomment the following line when not using the [inline] package option: %\ASYanimategraphics[controls]{10}{movie2}{}{} \end{center} \end{document} asymptote-2.37/examples/animations/inlinemovie3.tex000066400000000000000000000020151265434602500226020ustar00rootroot00000000000000\documentclass{article} \usepackage[inline]{asymptote} %\usepackage{asymptote} \usepackage{animate} \begin{document} Here is an inline 3D PDF movie, generated with the commands \begin{verbatim} pdflatex inlinemovie3 asy inlinemovie3-*.asy pdflatex inlinemovie3 \end{verbatim} or equivalently, \begin{verbatim} latexmk -pdf inlinemovie3 \end{verbatim} \begin{center} \begin{asy} settings.render=4; settings.prc=false; import graph3; import animate; currentprojection=orthographic(1,-2,0.5); animation A=animation("movie3"); int n=20; for(int i=0; i < n; ++i) { picture pic; size3(pic,12cm,12cm,8cm); real k=i/n*pi; real f(pair z) {return 4cos(abs(z)-k)*exp(-abs(z)/6);} draw(pic,surface(f,(-4pi,-4pi),(4pi,4pi),Spline),paleblue); draw(pic,shift(i*6Z/n)*unitsphere,yellow); A.add(pic); } label(A.pdf("autoplay,loop",delay=20,keep=!settings.inlinetex)); \end{asy} %Uncomment the following line when not using the [inline] package option: %\ASYanimategraphics[autoplay,loop]{50}{movie3}{}{} \end{center} \end{document} asymptote-2.37/examples/animations/pdfmovie.asy000066400000000000000000000005061265434602500220110ustar00rootroot00000000000000import animate; import patterns; settings.tex="pdflatex"; animation a; add("brick",brick(black)); int n=20; for(int i=0; i < 3.5n; ++i) { picture pic; size(pic,100); path g=circle((0,sin(pi/n*i)),1); fill(pic,g,mediumred); fill(pic,g,pattern("brick")); a.add(pic); } label(a.pdf("controls",multipage=false)); asymptote-2.37/examples/animations/slidemovies.asy000066400000000000000000000023261265434602500225250ustar00rootroot00000000000000// Slide demo. // Command-line options to enable stepping and/or reverse video: // asy [-u stepping=true] [-u reverse=true] slidedemo orientation=Landscape; settings.tex="pdflatex"; import slide; // Optional movie modules: import animate; // For portable embedded PDF movies access external; // For portable external movies access embed; // For non-portable embedded movies usersetting(); titlepage("Slides with {\tt Asymptote}: Animations","John C. Bowman", "University of Alberta","\today","http://asymptote.sf.net"); title("Embedded PDF movies (portable)"); animation a=animation("A"); animation b=animation("B"); int n=20; for(int i=0; i < 2n; ++i) { picture pic; size(pic,100); draw(pic,shift(0,sin(pi/n*i))*unitsquare); a.add(pic); if(i < 1.5n) b.add(rotate(45)*pic); } display(a.pdf("autoplay,loop,controls",multipage=false)); display(b.pdf("controls",multipage=false)); // Generated needed files if they don't already exist. asy("mp4","wheel"); title("External Movie (portable)"); display(external.embed("wheel.mp4",20cm,5.6cm)); display(external.link("wheel.mp4")); title("Embedded Movie (not portable)"); display(embed.embed("wheel.mp4",20cm,5.6cm)); display(embed.link("wheel.mp4")); asymptote-2.37/examples/animations/sphere.asy000066400000000000000000000015001265434602500214610ustar00rootroot00000000000000import solids; import animation; currentprojection=orthographic((0,5,2)); currentlight=(0,5,5); settings.thick=false; settings.render=0; int nbpts=200; real step=2*pi/nbpts; int angle=10; unitsize(1cm); triple[] P=new triple[nbpts]; for(int i=0; i < nbpts; ++i) { real t=-pi+i*step; P[i]=(3sin(t)*cos(2t),3sin(t)*sin(2t),3cos(t)); } transform3 t=rotate(angle,(0,0,0),(1,0.25,0.25)); revolution r=sphere(O,3); draw(surface(r),lightgrey); draw(r,backpen=linetype("8 8",8)); animation A; for(int phi=0; phi < 360; phi += angle) { bool[] front=new bool[nbpts]; save(); for(int i=0; i < nbpts; ++i) { P[i]=t*P[i]; front[i]=dot(P[i],currentprojection.camera) > 0; } draw(segment(P,front,operator ..),1mm+blue+extendcap); draw(segment(P,!front,operator ..),grey); A.add(); restore(); } A.movie(0,200); asymptote-2.37/examples/animations/torusanimation.asy000066400000000000000000000014361265434602500232570ustar00rootroot00000000000000import graph3; import animation; import solids; currentprojection=perspective(50,40,20); currentlight=(0,5,5); real R=3; real a=1; int n=8; path3[] p=new path3[n]; animation A; for(int i=0; i < n; ++i) { triple g(real s) { real twopi=2*pi; real u=twopi*s; real v=twopi/(1+i+s); real cosu=cos(u); return((R-a*cosu)*cos(v),(R-a*cosu)*sin(v),-a*sin(u)); } p[i]=graph(g,0,1,operator ..); } triple f(pair t) { real costy=cos(t.y); return((R+a*costy)*cos(t.x),(R+a*costy)*sin(t.x),a*sin(t.y)); } surface s=surface(f,(0,0),(2pi,2pi),8,8,Spline); for(int i=0; i < n; ++i){ picture fig; size(fig,20cm); draw(fig,s,yellow); for(int j=0; j <= i; ++j) draw(fig,p[j],blue+linewidth(4)); A.add(fig); } A.movie(BBox(10,Fill(rgb(0.98,0.98,0.9))),delay=100); asymptote-2.37/examples/animations/wavepacket.asy000066400000000000000000000027321265434602500223350ustar00rootroot00000000000000// Author : Philippe Ivaldi // http://www.piprime.fr/ // 2006/11/10 import animation; import graph; unitsize(x=2cm,y=1.5cm); typedef real realfcn(real); real lambda=4; real T=2; real [] k=new real[3]; real [] w=new real[3]; k[0]=2pi/lambda; w[0]=2pi/T; real dk=-.5; k[1]=k[0]-dk; k[2]=k[0]+dk; real dw=1; w[1]=w[0]-dw; w[2]=w[0]+dw; real vp=w[1]/k[1]; real vg=dw/dk; realfcn F(real x) { return new real(real t) { return cos(k[1]*x-w[1]*t)+cos(k[2]*x-w[2]*t); }; }; realfcn G(real x) { return new real(real t) { return 2*cos(0.5*(k[2]-k[1])*x+0.5*(w[1]-w[2])*t); }; }; realfcn operator -(realfcn f) {return new real(real t) {return -f(t);};}; animation A; real tmax=abs(2pi/dk); real xmax=abs(2pi/dw); pen envelope=0.8*blue; pen fillpen=lightgrey; int n=50; real step=tmax/(n-1); for(int i=0; i < n; ++i) { save(); real t=i*step; real a=xmax*t/tmax-xmax/pi; real b=xmax*t/tmax; path f=graph(F(t),a,b); path g=graph(G(t),a,b); path h=graph(-G(t),a,b); fill(buildcycle(reverse(f),g),fillpen); draw(f); draw(g,envelope); draw(h,envelope); A.add(); restore(); } for(int i=0; i < n; ++i) { save(); real t=i*step; real a=-xmax/pi; real b=xmax; path f=graph(F(t),a,b); path g=graph(G(t),a,b); path h=graph(-G(t),a,b); path B=box((-xmax/pi,-2),(xmax,2)); fill(buildcycle(reverse(f),g,B),fillpen); fill(buildcycle(f,g,reverse(B)),fillpen); draw(f); draw(g,envelope); draw(h,envelope); A.add(); restore(); } A.movie(0,10); asymptote-2.37/examples/animations/wheel.asy000066400000000000000000000021401265434602500213000ustar00rootroot00000000000000import graph; // Uncomment the following 2 lines to support pdf animations: // usepackage("animate"); // settings.tex="pdflatex"; import animation; size(0,200); defaultpen(3); dotfactor=4; pair wheelpoint(real t) { return (t+cos(t),-sin(t)); } guide wheel(guide g=nullpath, real a, real b, int n) { real width=(b-a)/n; for(int i=0; i <= n; ++i) { real t=a+width*i; g=g--wheelpoint(t); } return g; } real t1=0; real t2=t1+2*pi; animation a; draw(circle((0,0),1)); draw(wheel(t1,t2,100),linetype("0 2")); yequals(Label("$y=-1$",1.0),-1,extend=true,linetype("4 4")); xaxis(Label("$x$",align=3SW),0); yaxis("$y$",0,1.2); pair z1=wheelpoint(t1); pair z2=wheelpoint(t2); dot(z1); dot(z2); int n=10; real dt=(t2-t1)/n; for(int i=0; i <= n; ++i) { save(); real t=t1+dt*i; draw(circle((t,0),1),red); dot(wheelpoint(t)); a.add(); // Add currentpicture to animation. restore(); } erase(); // Merge the images into a gif animation. a.movie(BBox(0.25cm),loops=10,delay=250); // Merge the images into a pdf animation. // label(a.pdf(BBox(0.25cm),delay=250,"controls",multipage=false)); asymptote-2.37/examples/annotation.asy000066400000000000000000000003541265434602500202110ustar00rootroot00000000000000import annotate; settings.outformat="pdf"; size(200); draw(unitcircle); dot((0,0)); annotate("O","(0,0)",(0,0)); annotate("A","(1,0)",(1,0)); annotate("B","(0,1)",(0,1)); annotate("C","(-1,0)",(-1,0)); annotate("D","(0,-1)",(0,-1)); asymptote-2.37/examples/arrows3.asy000066400000000000000000000012441265434602500174360ustar00rootroot00000000000000import three; size(15cm); defaultrender.merge=true; currentprojection=perspective(24,14,13); currentlight=light(gray(0.5),specularfactor=3,viewport=false, (0.5,-0.5,-0.25),(0.5,0.5,0.25),(0.5,0.5,1),(-0.5,-0.5,-1)); defaultpen(0.75mm); path3 g=arc(O,1,90,-60,90,60); transform3 t=shift(invert(3S,O)); draw(g,blue,Arrows3(TeXHead3),currentlight); draw(scale3(3)*g,green,ArcArrows3(HookHead3),currentlight); draw(scale3(6)*g,red,Arrows3(DefaultHead3),currentlight); draw(t*g,blue,Arrows3(TeXHead2),currentlight); draw(t*scale3(3)*g,green,ArcArrows3(HookHead2,NoFill),currentlight); draw(t*scale3(6)*g,red,Arrows3(DefaultHead2(normal=Z)),currentlight); asymptote-2.37/examples/bars3.asy000066400000000000000000000007611265434602500170530ustar00rootroot00000000000000import three; import palette; import graph3; size(300); currentprojection=perspective(-30,-30,30,up=Z); surface s; for(int i = 0; i < 10; ++i) { for(int j = 0; j < 10; ++j) { s.append(shift(i,j,0)*scale(1,1,i+j)*unitcube); } } s.colors(palette(s.map(zpart),Rainbow())); draw(s,meshpen=black+thick(),nolight,render(merge=true)); xaxis3("$x$",Bounds,InTicks(endlabel=false,Label,2,2)); yaxis3(YZ()*"$y$",Bounds,InTicks(beginlabel=false,Label,2,2)); zaxis3(XZ()*"$z$",Bounds,InTicks); asymptote-2.37/examples/basealign.asy000066400000000000000000000020111265434602500177540ustar00rootroot00000000000000import fontsize; import three; settings.autobillboard=false; settings.embed=false; currentprojection=orthographic(Z); defaultpen(fontsize(100pt)); dot(O); label("acg",O,align=N,basealign); label("ace",O,align=N,red); label("acg",O,align=S,basealign); label("ace",O,align=S,red); label("acg",O,align=E,basealign); label("ace",O,align=E,red); label("acg",O,align=W,basealign); label("ace",O,align=W,red); picture pic; dot(pic,(labelmargin(),0,0),blue); dot(pic,(-labelmargin(),0,0),blue); dot(pic,(0,labelmargin(),0),blue); dot(pic,(0,-labelmargin(),0),blue); add(pic,O); dot((0,0)); label("acg",(0,0),align=N,basealign); label("ace",(0,0),align=N,red); label("acg",(0,0),align=S,basealign); label("ace",(0,0),align=S,red); label("acg",(0,0),align=E,basealign); label("ace",(0,0),align=E,red); label("acg",(0,0),align=W,basealign); label("ace",(0,0),align=W,red); picture pic; dot(pic,(labelmargin(),0),blue); dot(pic,(-labelmargin(),0),blue); dot(pic,(0,labelmargin()),blue); dot(pic,(0,-labelmargin()),blue); add(pic,(0,0)); asymptote-2.37/examples/billboard.asy000066400000000000000000000002321265434602500177640ustar00rootroot00000000000000import three; size(100); currentprojection=perspective(1,-2,1); draw(unitbox); label("Billboard",X,red,Billboard); label("Embedded",Y,blue,Embedded); asymptote-2.37/examples/buildcycle.asy000066400000000000000000000010011265434602500201440ustar00rootroot00000000000000size(200); real w=1.35; path[] p; for(int k=0; k < 2; ++k) { int i=2+2*k; int ii=i^2; p[k]=(w/ii,1){1,-ii}::(w/i,1/i)::(w,1/ii){ii,-1}; } path q0=(0,0)--(w,0.5); path q1=(0,0)--(w,1.5); draw(q0); draw(p[0]); draw(q1); draw(p[1]); path s=buildcycle(q0,p[0],q1,p[1]); fill(s,mediumgrey); label("$P$",intersectionpoint(p[0],q0),N); label("$Q$",intersectionpoint(p[0],q1),E); label("$R$",intersectionpoint(p[1],q1),W); label("$S$",intersectionpoint(p[1],q0),S); label("$f > 0$",0.5*(min(s)+max(s)),UnFill); asymptote-2.37/examples/cardioid.asy000066400000000000000000000003511265434602500176120ustar00rootroot00000000000000import graph; size(0,100); real f(real t) {return 1+cos(t);} path g=polargraph(f,0,2pi,operator ..)--cycle; filldraw(g,pink); xaxis("$x$",above=true); yaxis("$y$",above=true); dot("$(a,0)$",(1,0),N); dot("$(2a,0)$",(2,0),N+E); asymptote-2.37/examples/cards.asy000066400000000000000000000007451265434602500171370ustar00rootroot00000000000000picture rect; size(rect,0,2.5cm); real x=1; real y=1.25; filldraw(rect,box((-x,-y)/2,(x,y)/2),lightolive); label(rect,"1",(-x,y)*0.45,SE); label(rect,"2",(x,y)*0.45,SW); label(rect,"3",(-x,-y)*0.45,NE); label(rect,"4",(x,-y)*0.45,NW); frame rectf=rect.fit(); frame toplef=rectf; frame toprig=xscale(-1)*rectf; frame botlef=yscale(-1)*rectf; frame botrig=xscale(-1)*yscale(-1)*rectf; size(0,7.5cm); add(toplef,(-x,y)); add(toprig,(x,y)); add(botlef,(-x,-y)); add(botrig,(x,-y)); asymptote-2.37/examples/centroidfg.asy000066400000000000000000000012631265434602500201630ustar00rootroot00000000000000import graph; size(0,150); int a=-1, b=1; real f(real x) {return x^3-x+2;} real g(real x) {return x^2;} draw(graph(f,a,b,operator ..),red); draw(graph(g,a,b,operator ..),blue); xaxis(); int n=5; real width=(b-a)/(real) n; for(int i=0; i <= n; ++i) { real x=a+width*i; draw((x,g(x))--(x,f(x))); } labelx("$a$",a); labelx("$b$",b); draw((a,0)--(a,g(a)),dotted); draw((b,0)--(b,g(b)),dotted); real m=a+0.73*(b-a); arrow("$f(x)$",(m,f(m)),N,red); arrow("$g(x)$",(m,g(m)),E,0.8cm,blue); int j=2; real xi=b-j*width; real xp=xi+width; real xm=0.5*(xi+xp); pair dot=(xm,0.5*(f(xm)+g(xm))); dot(dot,darkgreen+4.0); arrow("$\left(x,\frac{f(x)+g(x)}{2}\right)$",dot,NE,2cm,darkgreen); asymptote-2.37/examples/cheese.asy000066400000000000000000000005021265434602500172660ustar00rootroot00000000000000import graph3; import palette; import contour3; size(400); real f(real x, real y, real z) { return cos(x)*sin(y)+cos(y)*sin(z)+cos(z)*sin(x); } surface sf=surface(contour3(f,(-2pi,-2pi,-2pi),(2pi,2pi,2pi),12)); sf.colors(palette(sf.map(abs),Gradient(red,yellow))); currentlight=nolight; draw(sf,render(merge=true)); asymptote-2.37/examples/circles.asy000066400000000000000000000011001265434602500174510ustar00rootroot00000000000000size(6cm,0); import math; currentpen=magenta; real r1=1; real r2=sqrt(7); real r3=4; pair O=0; path c1=circle(O,r1); draw(c1,green); draw(circle(O,r2),green); draw(circle(O,r3),green); real x=-0.6; real y=-0.8; real yD=0.3; pair A=(sqrt(r1^2-y^2),y); pair B=(-sqrt(r2^2-y^2),y); pair C=(x,sqrt(r3^2-x^2)); pair d=A+r2*dir(B--C); pair D=intersectionpoint(c1,A--d); draw(A--B--C--cycle); draw(interp(A,D,-0.5)--interp(A,D,1.5),blue); dot("$O$",O,S,red); dot("$A$",A,dir(C--A,B--A),red); dot("$B$",B,dir(C--B,A--B),red); dot("$C$",C,dir(A--C,B--C),red); dot("$D$",D,red); asymptote-2.37/examples/circumcircle.asy000066400000000000000000000003441265434602500205020ustar00rootroot00000000000000unitsize(1inch); path tri=(0,0)--(1,0)--(2,1)--cycle; pair p1=point(tri,0.5); pair p2=point(tri,1.5); pair z0=extension(p1,p1+I*dir(tri,0.5),p2,p2+I*dir(tri,1.5)); dot(z0); draw(circle(z0,abs(z0-point(tri,0)))); draw(tri,red); asymptote-2.37/examples/clockarray.asy000066400000000000000000000013721265434602500201720ustar00rootroot00000000000000int nx=3; int ny=4; real xmargin=1cm; real ymargin=xmargin; size(settings.paperwidth,settings.paperheight); picture pic; real width=settings.paperwidth/nx-xmargin; real height=settings.paperheight/ny-ymargin; if(width <= 0 || height <= 0) abort("margin too big"); size(pic,width,height); pen p=linewidth(0.5mm); draw(pic,unitcircle,p); real h=0.08; real m=0.05; for(int hour=1; hour <= 12; ++hour) { pair z=dir((12-hour+3)*30); label(pic,string(hour),z,z); draw(pic,z--(1-h)*z,p); } for(int minutes=0; minutes < 60; ++minutes) { pair z=dir(6*minutes); draw(pic,z--(1-m)*z); } dot(pic,(0,0)); frame f=pic.fit(); pair size=size(f)+(xmargin,ymargin); for(int i=0; i < nx; ++i) for(int j=0; j < ny; ++j) add(shift(realmult(size,(i,j)))*f); asymptote-2.37/examples/coag.asy000066400000000000000000000004101265434602500167410ustar00rootroot00000000000000size(0,200); import graph; pair z0=(0,0); pair m0=(0,1); pair tg=(1.5,0); pair mt=m0+tg; pair tf=(3,0); draw(m0--mt{dir(-70)}..{dir(0)}2tg+m0/4); xtick("$T_g$",tg,N); label("$M(t)$",mt,2NE); labely("$M_0$",m0); xaxis(Label("$t$",align=2S),Arrow); yaxis(Arrow); asymptote-2.37/examples/colorplanes.asy000066400000000000000000000007211265434602500203560ustar00rootroot00000000000000size(6cm,0); import bsp; real u=2.5; real v=1; currentprojection=oblique; path3 y=plane((2u,0,0),(0,2v,0),(-u,-v,0)); path3 l=rotate(90,Z)*rotate(90,Y)*y; path3 g=rotate(90,X)*rotate(90,Y)*y; face[] faces; pen[] p={red,green,blue,black}; int[] edges={0,0,0,2}; gouraudshade(faces.push(y),project(y),p,edges); gouraudshade(faces.push(l),project(l),p,edges); gouraudshade(faces.push(g),project(g),new pen[]{cyan,magenta,yellow,black}, edges); add(faces); asymptote-2.37/examples/condor.asy000066400000000000000000000013431265434602500173220ustar00rootroot00000000000000// Peter Luschny's Condor function // http://www.luschny.de/math/asy/ElCondorYElGamma.html import palette; import graph3; size(300,300,IgnoreAspect); currentprojection=orthographic(0,-1,0,center=true); currentlight=White; real K=7; triple condor(pair t) { real y=t.y; real x=t.x*y; real e=gamma(y+1); real ymx=y-x; real ypx=y+x; real a=gamma((ymx+1)/2); real b=gamma((ymx+2)/2); real c=gamma((ypx+1)/2); real d=gamma((ypx+2)/2); real A=cos(pi*ymx); real B=cos(pi*ypx); return (x,y,log(e)+log(a)*((A-1)/2)+log(b)*((-A-1)/2)+log(c)*((B-1)/2)+ log(d)*((-B-1)/2)); } surface s=surface(condor,(-1,0),(1,K),16,Spline); s.colors(palette(s.map(zpart),Rainbow())); draw(s,render(compression=Low,merge=true)); asymptote-2.37/examples/cones.asy000066400000000000000000000006751265434602500171540ustar00rootroot00000000000000import solids; size(200); currentprojection=orthographic(5,4,2); render render=render(compression=Low,merge=true); revolution upcone=cone(-Z,1,1); revolution downcone=cone(Z,1,-1); draw(surface(upcone),green,render); draw(surface(downcone),green,render); draw(upcone,5,blue,longitudinalpen=nullpen); draw(downcone,5,blue,longitudinalpen=nullpen); revolution cone=shift(2Y-2X)*cone(1,1); draw(surface(cone),green,render); draw(cone,5,blue); asymptote-2.37/examples/conicurv.asy000066400000000000000000000033641265434602500176730ustar00rootroot00000000000000// Original name : conicurv.mp // Author : L. Nobre G. // Translators : J. Pienaar (2004) and John Bowman (2005) import three; texpreamble("\usepackage{bm}"); size(300,0); currentprojection=perspective(10,-5,5.44); real theta=30, width=3, shortradius=2, bord=2, refsize=1, vecsize=2; real height=0.3, anglar=1.75, totup=3; real longradius=shortradius+width*Cos(theta), updiff=width*Sin(theta); triple iplow=(0,shortradius,0), iphig=(0,longradius,updiff); triple oplow=(-shortradius,0,0), ophig=(-longradius,0,updiff); triple aplow=-iplow, aphig=(0,-longradius,updiff); triple eplow=-oplow, ephig=(longradius,0,updiff); triple anglebase=(0,longradius,0), centre=interp(iplow,iphig,0.5)+(0,0,height); triple central=(0,0,centre.z), refo=(0,0.5*centre.y,centre.z); triple refx=refsize*(0,Cos(theta),Sin(theta)); triple refy=refsize*(0,-Sin(theta),Cos(theta)); draw("$\theta$",arc(iplow,iplow+0.58*(iphig-iplow),anglebase),E); draw(central,linewidth(2bp)); draw(iplow--iphig); draw(oplow--ophig); draw(aplow--aphig); draw(eplow--ephig); draw(iphig--anglebase--aplow,dashed); draw(oplow--eplow,dashed); draw(central--centre,dashed); draw((0,0,-bord)--(0,longradius+bord,-bord)--(0,longradius+bord,totup) --(0,0,totup)--cycle); draw(Label("$y$",1),refo--refo+refy,SW,Arrow3); draw(Label("$x$",1),refo--refo+refx,SE,Arrow3); draw(Label("$\vec{R}_N$",1),centre--centre+vecsize*refy,E,Arrow3); draw(Label("$\vec{F}_a$",1),centre--centre+vecsize*refx,N,Arrow3); draw(Label("$\vec{F}_c$",1),centre--centre+vecsize*Y,NE,Arrow3); draw(Label("$\vec{P}$",1),centre--centre-vecsize*Z,E,Arrow3); draw(Label("$\vec{v}$",1),centre--centre+vecsize*X,E,Arrow3); draw(centre,10pt+blue); draw(circle((0,0,updiff),longradius),linewidth(2bp)); draw(circle(O,shortradius),linewidth(2bp)); asymptote-2.37/examples/contextfonts.asy000066400000000000000000000003771265434602500206020ustar00rootroot00000000000000settings.tex="context"; // Work around ConTeXT bug for font sizes less than 12pt: texpreamble("\setupbodyfont[8pt]"); usetypescript("iwona"); usetypescript("antykwa-torunska"); label("$A$",0,N,font("iwona")); label("$A$",0,S,font("antykwa",8pt)+red); asymptote-2.37/examples/controlsystem.asy000066400000000000000000000014121265434602500207600ustar00rootroot00000000000000size(0,4cm); import flowchart; block delay=roundrectangle("$e^{-sT_t}$",(0.33,0)); block system=roundrectangle("$\frac{s+3}{s^2+0.3s+1}$",(0.6,0)); block controller=roundrectangle("$0.06\left( 1 + \frac{1}{s}\right)$", (0.45,-0.25)); block sum1=circle("",(0.15,0),mindiameter=0.3cm); block junction1=circle("",(0.75,0),fillpen=currentpen); draw(delay); draw(system); draw(controller); draw(sum1); draw(junction1); add(new void(picture pic, transform t) { blockconnector operator --=blockconnector(pic,t); block(0,0)--Label("$u$",align=N)--Arrow--sum1--Arrow--delay--Arrow-- system--junction1--Label("$y$",align=N)--Arrow--block(1,0); junction1--Down--Left--Arrow--controller--Left--Up-- Label("$-$",position=3,align=ESE)--Arrow--sum1; }); asymptote-2.37/examples/cos2theta.asy000066400000000000000000000003531265434602500177320ustar00rootroot00000000000000import graph; size(0,100); real f(real t) {return cos(2*t);} path g=polargraph(f,0,2pi,operator ..)--cycle; fill(g,green+white); xaxis("$x$",above=true); yaxis("$y$",above=true); draw(g); dot(Label,(1,0),NE); dot(Label,(0,1),NE); asymptote-2.37/examples/cos3.asy000066400000000000000000000011061265434602500167020ustar00rootroot00000000000000import graph3; import palette; size(12cm,IgnoreAspect); currentprojection=orthographic(1,-2,1); real f(pair z) {return abs(cos(z));} real Arg(triple v) {return degrees(cos((v.x,v.y)),warn=false);} surface s=surface(f,(-pi,-2),(pi,2),20,Spline); s.colors(palette(s.map(Arg),Wheel())); draw(s,render(compression=Low,merge=true)); real xmin=point((-1,-1,-1)).x; real xmax=point((1,1,1)).x; draw((xmin,0,0)--(xmax,0,0),dashed); xaxis3("$\mathop{\rm Re} z$",Bounds,InTicks); yaxis3("$\mathop{\rm Im} z$",Bounds,InTicks(beginlabel=false)); zaxis3("$|\cos(z)|$",Bounds,InTicks); asymptote-2.37/examples/cosaddition.asy000066400000000000000000000007151265434602500203400ustar00rootroot00000000000000size(0,200); import geometry; real A=130; real B=40; pair O=(0,0); pair R=(1,0); pair P=dir(A); pair Q=dir(B); draw(circle(O,1.0)); draw(Q--O--P); draw(P--Q,red); draw(O--Q--R--cycle); draw("$A$",arc(R,O,P,0.3),blue,Arrow,PenMargin); draw("$B$",arc(R,O,Q,0.6),blue,Arrow,PenMargin); pair S=(Cos(B),0); draw(Q--S,blue); perpendicular(S,NE,blue); dot(O); dot("$R=(1,0)$",R); dot("$P=(\cos A,\sin A)$",P,dir(O--P)+W); dot("$Q=(\cos B,\sin B)$",Q,dir(O--Q)); asymptote-2.37/examples/cpkcolors.asy000066400000000000000000000131541265434602500200400ustar00rootroot00000000000000/* * Copyright (C) 2003-2005 Miguel, Jmol Development, www.jmol.org * * Contact: miguel@jmol.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ string[] Element={ "Xx", // 0 "H", // 1 "He", // 2 "Li", // 3 "Be", // 4 "B", // 5 "C", // 6 "N", // 7 "O", // 8 "F", // 9 "Ne", // 10 "Na", // 11 "Mg", // 12 "Al", // 13 "Si", // 14 "P", // 15 "S", // 16 "Cl", // 17 "Ar", // 18 "K", // 19 "Ca", // 20 "Sc", // 21 "Ti", // 22 "V", // 23 "Cr", // 24 "Mn", // 25 "Fe", // 26 "Co", // 27 "Ni", // 28 "Cu", // 29 "Zn", // 30 "Ga", // 31 "Ge", // 32 "As", // 33 "Se", // 34 "Br", // 35 "Kr", // 36 "Rb", // 37 "Sr", // 38 "Y", // 39 "Zr", // 40 "Nb", // 41 "Mo", // 42 "Tc", // 43 "Ru", // 44 "Rh", // 45 "Pd", // 46 "Ag", // 47 "Cd", // 48 "In", // 49 "Sn", // 50 "Sb", // 51 "Te", // 52 "I", // 53 "Xe", // 54 "Cs", // 55 "Ba", // 56 "La", // 57 "Ce", // 58 "Pr", // 59 "Nd", // 60 "Pm", // 61 "Sm", // 62 "Eu", // 63 "Gd", // 64 "Tb", // 65 "Dy", // 66 "Ho", // 67 "Er", // 68 "Tm", // 69 "Yb", // 70 "Lu", // 71 "Hf", // 72 "Ta", // 73 "W", // 74 "Re", // 75 "Os", // 76 "Ir", // 77 "Pt", // 78 "Au", // 79 "Hg", // 80 "Tl", // 81 "Pb", // 82 "Bi", // 83 "Po", // 84 "At", // 85 "Rn", // 86 "Fr", // 87 "Ra", // 88 "Ac", // 89 "Th", // 90 "Pa", // 91 "U", // 92 "Np", // 93 "Pu", // 94 "Am", // 95 "Cm", // 96 "Bk", // 97 "Cf", // 98 "Es", // 99 "Fm", // 100 "Md", // 101 "No", // 102 "Lr", // 103 "Rf", // 104 "Db", // 105 "Sg", // 106 "Bh", // 107 "Hs", // 108 "Mt", // 109 /* "Ds", // 110 "Uuu",// 111 "Uub",// 112 "Uut",// 113 "Uuq",// 114 "Uup",// 115 "Uuh",// 116 "Uus",// 117 "Uuo",// 118 */ }; // Default table of CPK atom colors // (ghemical colors with a few proposed modifications). string[] Hexcolor={ "FF1493", // Xx 0 "FFFFFF", // H 1 "D9FFFF", // He 2 "CC80FF", // Li 3 "C2FF00", // Be 4 "FFB5B5", // B 5 "909090", // C 6 - changed from ghemical "3050F8", // N 7 - changed from ghemical "FF0D0D", // O 8 "90E050", // F 9 - changed from ghemical "B3E3F5", // Ne 10 "AB5CF2", // Na 11 "8AFF00", // Mg 12 "BFA6A6", // Al 13 "F0C8A0", // Si 14 - changed from ghemical "FF8000", // P 15 "FFFF30", // S 16 "1FF01F", // Cl 17 "80D1E3", // Ar 18 "8F40D4", // K 19 "3DFF00", // Ca 20 "E6E6E6", // Sc 21 "BFC2C7", // Ti 22 "A6A6AB", // V 23 "8A99C7", // Cr 24 "9C7AC7", // Mn 25 "E06633", // Fe 26 - changed from ghemical "F090A0", // Co 27 - changed from ghemical "50D050", // Ni 28 - changed from ghemical "C88033", // Cu 29 - changed from ghemical "7D80B0", // Zn 30 "C28F8F", // Ga 31 "668F8F", // Ge 32 "BD80E3", // As 33 "FFA100", // Se 34 "A62929", // Br 35 "5CB8D1", // Kr 36 "702EB0", // Rb 37 "00FF00", // Sr 38 "94FFFF", // Y 39 "94E0E0", // Zr 40 "73C2C9", // Nb 41 "54B5B5", // Mo 42 "3B9E9E", // Tc 43 "248F8F", // Ru 44 "0A7D8C", // Rh 45 "006985", // Pd 46 "C0C0C0", // Ag 47 - changed from ghemical "FFD98F", // Cd 48 "A67573", // In 49 "668080", // Sn 50 "9E63B5", // Sb 51 "D47A00", // Te 52 "940094", // I 53 "429EB0", // Xe 54 "57178F", // Cs 55 "00C900", // Ba 56 "70D4FF", // La 57 "FFFFC7", // Ce 58 "D9FFC7", // Pr 59 "C7FFC7", // Nd 60 "A3FFC7", // Pm 61 "8FFFC7", // Sm 62 "61FFC7", // Eu 63 "45FFC7", // Gd 64 "30FFC7", // Tb 65 "1FFFC7", // Dy 66 "00FF9C", // Ho 67 "00E675", // Er 68 "00D452", // Tm 69 "00BF38", // Yb 70 "00AB24", // Lu 71 "4DC2FF", // Hf 72 "4DA6FF", // Ta 73 "2194D6", // W 74 "267DAB", // Re 75 "266696", // Os 76 "175487", // Ir 77 "D0D0E0", // Pt 78 - changed from ghemical "FFD123", // Au 79 - changed from ghemical "B8B8D0", // Hg 80 - changed from ghemical "A6544D", // Tl 81 "575961", // Pb 82 "9E4FB5", // Bi 83 "AB5C00", // Po 84 "754F45", // At 85 "428296", // Rn 86 "420066", // Fr 87 "007D00", // Ra 88 "70ABFA", // Ac 89 "00BAFF", // Th 90 "00A1FF", // Pa 91 "008FFF", // U 92 "0080FF", // Np 93 "006BFF", // Pu 94 "545CF2", // Am 95 "785CE3", // Cm 96 "8A4FE3", // Bk 97 "A136D4", // Cf 98 "B31FD4", // Es 99 "B31FBA", // Fm 100 "B30DA6", // Md 101 "BD0D87", // No 102 "C70066", // Lr 103 "CC0059", // Rf 104 "D1004F", // Db 105 "D90045", // Sg 106 "E00038", // Bh 107 "E6002E", // Hs 108 "EB0026" // Mt 109 }; asymptote-2.37/examples/curvedlabel.asy000066400000000000000000000002611265434602500203240ustar00rootroot00000000000000size(200); import labelpath; labelpath("This is a test of curved labels in Asymptote (implemented with the {\tt PSTricks pstextpath} macro).",reverse(rotate(-90)*unitcircle)); asymptote-2.37/examples/curvedlabel3.asy000066400000000000000000000010751265434602500204130ustar00rootroot00000000000000size(200); import labelpath3; path3 g=(1,0,0)..(0,1,1)..(-1,0,0)..(0,-1,1)..cycle; path3 g2=shift(-Z)*reverse(unitcircle3); string txt1="\hbox{This is a test of \emph{curved} 3D labels in \textbf{Asymptote} (implemented with {\tt texpath}).}"; string txt2="This is a test of curved labels in Asymptote\\(implemented without the {\tt PSTricks pstextpath} macro)."; draw(surface(g),paleblue+opacity(0.5)); draw(labelpath(txt1,subpath(g,0,reltime(g,0.95)),angle=-90),orange); draw(g2,1bp+red); draw(labelpath(txt2,subpath(g2,0,3.9),angle=180,optional=rotate(-70,X)*Z)); asymptote-2.37/examples/cyclohexane.asy000066400000000000000000000034531265434602500203440ustar00rootroot00000000000000import three; currentprojection=perspective(300,-650,500); currentlight.background=palecyan; surface carbon=scale3(70)*unitsphere; // 70 pm surface hydrogen=scale3(25)*unitsphere; // 25 pm real alpha=90+aSin(1/3); real CCbond=156; // 156 pm real CHbond=110; // 110 pm triple c1=(0,0,0); triple h1=c1+CHbond*Z; triple c2=rotate(alpha,c1,c1+Y)*(CCbond*Z); triple h2=rotate(120,c1,c2)*h1; triple h3=c2-CHbond*Z; triple h4=rotate(120,c2,c1)*h3; triple c3=rotate(120,c2,h3)*c1; triple h5=c3+CHbond*Z; triple h6=rotate(-120,c3,c2)*h5; triple c4=rotate(-120,c3,h5)*c2; triple h7=c4-CHbond*Z; triple h8=rotate(120,c4,c3)*h7; triple c5=rotate(120,c4,h7)*c3; triple h9=c5+CHbond*Z; triple h10=rotate(-120,c5,c4)*h9; triple c6=rotate(-120,c5,h9)*c4; triple h11=c6-CHbond*Z; triple h12=rotate(120,c6,c5)*h11; pen Black=gray(0.4); defaultrender=render(compression=Zero,merge=true); draw(shift(c1)*carbon,Black); draw(shift(c2)*carbon,Black); draw(shift(c3)*carbon,Black); draw(shift(c4)*carbon,Black); draw(shift(c5)*carbon,Black); draw(shift(c6)*carbon,Black); material White=material(diffusepen=gray(0.4),emissivepen=gray(0.6)); draw(shift(h1)*hydrogen,White); draw(shift(h2)*hydrogen,White); draw(shift(h3)*hydrogen,White); draw(shift(h4)*hydrogen,White); draw(shift(h5)*hydrogen,White); draw(shift(h6)*hydrogen,White); draw(shift(h7)*hydrogen,White); draw(shift(h8)*hydrogen,White); draw(shift(h9)*hydrogen,White); draw(shift(h10)*hydrogen,White); draw(shift(h11)*hydrogen,White); draw(shift(h12)*hydrogen,White); pen thick=linewidth(10); draw(c1--c2--c3--c4--c5--c6--cycle,thick); draw(c1--h1,thick); draw(c1--h2,thick); draw(c2--h3,thick); draw(c2--h4,thick); draw(c3--h5,thick); draw(c3--h6,thick); draw(c4--h7,thick); draw(c4--h8,thick); draw(c5--h9,thick); draw(c5--h10,thick); draw(c6--h11,thick); draw(c6--h12,thick); asymptote-2.37/examples/cylinder.asy000066400000000000000000000002221265434602500176420ustar00rootroot00000000000000import solids; size(0,100); currentlight=Viewport; revolution r=cylinder(O,1,1.5,Y+Z); draw(surface(r),green,render(merge=true)); draw(r,blue); asymptote-2.37/examples/delu.asy000066400000000000000000000007721265434602500167740ustar00rootroot00000000000000size(7cm,0); pair z1=(1,-0.25); pair v1=dir(45); pair z2=-z1; pair v2=0.75*dir(260); pair z3=(z1.x,-3); // A centered random number real crand() {return unitrand()-0.5;} guide g; pair lastz; for(int i=0; i < 60; ++i) { pair z=0.75*lastz+(crand(),crand()); g=g..2.5*z; lastz=z; } g=shift(0,-.5)*g..cycle; draw(g,gray(0.7)); draw("$r$",z1--z2,RightSide,red,Arrows,DotMargins); draw(z1--z1+v1,Arrow); draw(z2--z2+v2,Arrow); draw(z3--z3+v1-v2,green,Arrow); dot("1",z1,S,blue); dot("2",z2,NW,blue); asymptote-2.37/examples/dimension.asy000066400000000000000000000010111265434602500200130ustar00rootroot00000000000000size(12cm,0); void distance(picture pic=currentpicture, pair A, pair B, Label L="", real n=0, pen p=currentpen) { real d=3mm; path g=A--B; transform T=shift(-n*d*unit(B-A)*I); pic.add(new void(frame f, transform t) { picture opic; path G=T*t*g; draw(opic,Label(L,Center,UnFill(1)),G,p,Arrows(NoFill),Bars,PenMargins); add(f,opic.fit()); }); pic.addBox(min(g),max(g),T*min(p),T*max(p)); } pair A=(0,0), B=(3,3); dot(A); dot(B); distance(A,B,"$\ell$",1); asymptote-2.37/examples/dragon.asy000066400000000000000000000023001265434602500173020ustar00rootroot00000000000000pair crease(pair z1, pair z2, bool left) { pair dz = z2 - z1; if (left) return z1 + dz * (0.5, 0.5); else return z1 + dz * (0.5, -0.5); } pair[] fold(pair[] oldz) { int n = oldz.length; pair[] newz = new pair[2n-1]; for (int i = 0; i < n-1; ++i) { newz[2i] = oldz[i]; newz[2i+1] = crease(oldz[i], oldz[i+1], i%2==0); } newz[2(n-1)] = oldz[n-1]; return newz; } pair[] dragon(int n, pair[] base={}) { if (base.length == 0) if (n%2 == 0) base = new pair[] {(0,0), (1,1) }; else base = new pair[] {(0,0), (1,0) }; pair[] z = base; for (int i = 1; i < n; ++i) z = fold(z); return z; } void drawtris(pair[] z, pen p = currentpen) { int n = z.length; for (int i = 0; i < n-2; i+=2) fill(z[i]--z[i+1]--z[i+2]--cycle, p); } void drawtris(pair[] z, pen p1, pen p2) { int n = z.length; for (int i = 0; i < n-2; i+=2) fill(z[i]--z[i+1]--z[i+2]--cycle, 2i < n-1 ? p1 : p2); } size(500,0); int n = 10; drawtris(dragon(n, new pair[] {(0,0), (1,0)}), black); drawtris(dragon(n, new pair[] {(0,0), (0,-1)}), blue); drawtris(dragon(n, new pair[] {(0,0), (-1,0)}), red); drawtris(dragon(n, new pair[] {(0,0), (0,1)}), green); asymptote-2.37/examples/electromagnetic.asy000066400000000000000000000024561265434602500212110ustar00rootroot00000000000000import graph; import palette; texpreamble("\usepackage[amssymb,thinqspace,thinspace]{SIunits}"); size(800,200); real c=3e8; real nm=1e-9; real freq(real lambda) {return c/(lambda*nm);} real lambda(real f) {return c/(f*nm);} real fmin=10; real fmax=1e23; scale(Log(true),Linear(true)); xlimits(fmin,fmax); ylimits(0,1); real uv=freq(400); real ir=freq(700); bounds visible=bounds(Scale(uv).x,Scale(ir).x); palette(visible,uv,ir+(0,2),Bottom,Rainbow(),invisible); xaxis(Label("\hertz",1),Bottom,RightTicks,above=true); real log10Left(real x) {return -log10(x);} real pow10Left(real x) {return pow10(-x);} scaleT LogLeft=scaleT(log10Left,pow10Left,logarithmic=true); picture q=secondaryX(new void(picture p) { scale(p,LogLeft,Linear); xlimits(p,lambda(fmax),lambda(fmin)); ylimits(p,0,1); xaxis(p,Label("\nano\metre",1,0.01N),Top,LeftTicks(DefaultLogFormat,n=10)); }); add(q,above=true); margin margin=PenMargin(0,0); draw("radio",Scale((10,1))--Scale((5e12,1)),S,Arrow); draw("infrared",Scale((1e12,1.75))--Scale(shift(0,1.75)*ir),LeftSide,Arrows,margin); draw("UV",Scale(shift(0,1.75)*uv)--Scale((1e17,1.76)),LeftSide,Arrows,margin); draw("x-rays",Scale((1e16,1))--Scale((1e21,1)),RightSide,Arrows); draw("$\gamma$-rays",Scale((fmax,1.75))--Scale((2e18,1.75)),Arrow); asymptote-2.37/examples/elevation.asy000066400000000000000000000005031265434602500200210ustar00rootroot00000000000000import graph3; import grid3; import palette; currentprojection=orthographic(0.8,1,1); size(400,300,IgnoreAspect); defaultrender.merge=true; real f(pair z) {return cos(2*pi*z.x)*sin(2*pi*z.y);} surface s=surface(f,(-1/2,-1/2),(1/2,1/2),50,Spline); draw(s,mean(palette(s.map(zpart),Rainbow())),black); grid3(XYZgrid); asymptote-2.37/examples/epix.asy000066400000000000000000000006161265434602500170050ustar00rootroot00000000000000import graph3; size(200,200,IgnoreAspect); currentprojection=perspective(4,2,3); real f(pair z) {return z.y^3/2-3z.x^2*z.y;} draw(surface(f,(-1,-1),(1,1),nx=10,Spline),green,render(merge=true)); draw(Label("$y$",1),(0,0,0)--(0,2,0),red,Arrow3); draw(Label("$x$",1),(0,0,0)--(2,0,0),red,Arrow3); draw(Label("$z$",1),(0,0,0)--(0,0,2.5),red,Arrow3); label("$z=\frac{1}{2}y^3-3x^2y$",(1,1,1),NE); asymptote-2.37/examples/equilateral.asy000066400000000000000000000003621265434602500203460ustar00rootroot00000000000000size(10cm,0); import math; pair b=(0,0), c=(1,0); pair a=extension(b,b+dir(60),c,c+dir(120)); pair d=extension(b,b+dir(30),a,a+dir(270)); draw(a--b--c--a--d--b^^d--c); label("$A$",a,N); label("$B$",b,W); label("$C$",c,E); label("$D$",d,S); asymptote-2.37/examples/equilchord.asy000066400000000000000000000010451265434602500201740ustar00rootroot00000000000000import graph3; size(0,150); currentprojection=perspective(5,-4,6); currentlight=(-1,-1,2); real t=0.5; real F(pair z) { return (z.x^2+z.y^2 <= 1) ? sqrt(3)*(sqrt(1-z.x^2)-abs(z.y)) : 0; } real a=1.5; draw((-a,-a,0)--(-a,a,0)--(a,a,0)--(a,-a,0)--cycle,lightgray); xaxis3(Label("$x$",1),red,Arrow3); yaxis3(Label("$y$",1),red,Arrow3); draw(circle((0,0,0),1),dashed); draw(surface(F,(-1,-1),(t,1),20,monotonic),green,black,render(merge=true)); real y=sqrt(1-t^2); draw((t,y,0)--(t,-y,0)--(t,0,sqrt(3)*y)--cycle,blue); label("$1$",(1,0,0),-Y+X); asymptote-2.37/examples/exp3.asy000066400000000000000000000011031265434602500167070ustar00rootroot00000000000000import graph3; import palette; size(12cm,IgnoreAspect); currentprojection=orthographic(1,-2,1); real f(pair z) {return abs(exp(z));} real Arg(triple v) {return degrees(exp((v.x,v.y)),warn=false);} surface s=surface(f,(-2,-pi),(2,pi),20,Spline); s.colors(palette(s.map(Arg),Wheel())); draw(s,render(compression=Low,merge=true)); real xmin=point((-1,-1,-1)).x; real xmax=point((1,1,1)).x; draw((xmin,0,0)--(xmax,0,0),dashed); xaxis3("$\mathop{\rm Re} z$",Bounds,InTicks); yaxis3("$\mathop{\rm Im} z$",Bounds,InTicks(beginlabel=false)); zaxis3("$|\exp(z)|$",Bounds,InTicks); asymptote-2.37/examples/extrudedcontour.asy000066400000000000000000000011051265434602500212700ustar00rootroot00000000000000import contour; import palette; import graph3; defaultrender.merge=true; currentprojection=orthographic(25,10,10); size(0,12cm); real a=3; real b=4; real f(pair z) {return (z.x+z.y)/(2+cos(z.x)*sin(z.y));} guide[][] g=contour(f,(-10,-10),(10,10),new real[]{8},150); render render=render(merge=true); for(guide p:g[0]){ draw(extrude(p,8Z),palered,render); draw(path3(p),red+2pt,render); } draw(lift(f,g),red+2pt,render); surface s=surface(f,(0,0),(10,10),20,Spline); s.colors(palette(s.map(zpart),Rainbow()+opacity(0.5))); draw(s,render); axes3("$x$","$y$","$z$",Arrow3); asymptote-2.37/examples/fano.asy000066400000000000000000000007621265434602500167650ustar00rootroot00000000000000import math; size(100,0); pair z4=(0,0); pair z7=(2,0); pair z1=point(rotate(60)*(z4--z7),1); pair z5=interp(z4,z7,0.5); pair z3=interp(z7,z1,0.5); pair z2=interp(z1,z4,0.5); pair z6=extension(z4,z3,z7,z2); draw(z4--z7--z1--cycle); draw(z4--z3); draw(z7--z2); draw(z1--z5); draw(circle(z6,abs(z3-z6))); label("1",z1,dir(z5--z1)); label("2",z2,dir(z7--z2)); label("3",z3,dir(z4--z3)); label("4",z4,dir(z3--z4)); label("5",z5,dir(z1--z5)); label("6",z6,2.5E+0.1*N); label("7",z7,dir(z2--z7)); asymptote-2.37/examples/fequlogo.asy000066400000000000000000000021251265434602500176560ustar00rootroot00000000000000// A compressed version of the required data file may be obtained from: // http://www-roc.inria.fr/gamma/download/counter.php?dir=ARCHITEC/&get_obj=uhrturm.obj.gz import graph3; import obj; size(200,0); size3(200); if(settings.render < 0) settings.render=8; texpreamble("\usepackage[T1]{fontenc}"); texpreamble("\usepackage{ccfonts,eulervm}"); currentprojection=perspective(4,1,2); currentlight=(4,0,2); currentlight.background=blue; real R=4; triple f1(pair t) {return (R*cos(t.x),R*sin(t.x),t.y);} draw(shift(-0.6Z)*scale3(0.66)*rotate(55,Z)*rotate(90,X)* obj("uhrturm.obj",orange)); surface s=surface(f1,(0,0),(2pi,2),8,8,Spline); string lo="$\displaystyle f(x+y)=f(x)+f(y)$"; string hi="$\displaystyle F_{t+s}=F_t\circ F_s$"; real h=0.0125; draw(surface(rotate(2)*xscale(0.32)*yscale(0.6)*lo,s,-pi/4-1.5*pi/20,0.5,h)); draw(surface(rotate(0)*xscale(-0.45)*yscale(0.3)*hi,s,0.8*pi,0.25,h),blue); add(new void(frame f, transform3 t, picture pic, projection P) { draw(f,surface(invert(box(min(f,P),max(f,P)),min3(f),P), new pen[] {orange,red,yellow,brown})); } ); asymptote-2.37/examples/fermi.asy000066400000000000000000000013271265434602500171420ustar00rootroot00000000000000import feynman; // set default line width to 0.8bp currentpen = linewidth(0.8); // scale all other defaults of the feynman module appropriately fmdefaults(); // disable middle arrows currentarrow = None; // define vertex and external points pair xu = (-40,+45); pair xl = (-40,-45); pair yu = (+40,+45); pair yl = (+40,-45); pair zu = ( 0,+ 5); pair zl = ( 0,- 5); // define mid points pair mxu = (xu+zu)/2; pair mxl = (xl+zl)/2; pair myu = (yu+zu)/2; pair myl = (yl+zl)/2; // draw fermion lines drawFermion(xu--zu--yu); drawFermion(xl--zl--yl); // draw vertices drawVertexOX(zu); drawVertexOX(zl); // draw gluon. Note that the underlying fermion line is blotted out. drawGluon(arc((0,0),mxu,myl,CW)); // shipout asymptote-2.37/examples/filesurface.asy000066400000000000000000000017131265434602500203270ustar00rootroot00000000000000import graph3; import palette; size3(200,IgnoreAspect); file in=input("filesurface.dat").line(); real[] x=in; real[] y=in; real[][] f=in; triple f(pair t) { int i=round(t.x); int j=round(t.y); return (x[i],y[j],f[i][j]); } surface s=surface(f,(0,0),(x.length-1,y.length-1),x.length-1,y.length-1); real[] level=uniform(min(f)*(1-sqrtEpsilon),max(f)*(1+sqrtEpsilon),4); s.colors(palette(s.map(new real(triple v) {return find(level >= v.z);}), Rainbow())); draw(s,meshpen=thick(),render(merge=true)); triple m=currentpicture.userMin(); triple M=currentpicture.userMax(); triple target=0.5*(m+M); xaxis3("$x$",Bounds,InTicks); yaxis3("$y$",Bounds,InTicks(Step=1,step=0.1)); zaxis3("$z$",Bounds,InTicks); /* picture palette; size3(palette,1cm); draw(palette,unitcube,red); frame F=palette.fit3(); add(F,(M.x,m.y,m.z)); */ currentprojection=perspective(camera=target+realmult(dir(68,225),M-m), target=target); asymptote-2.37/examples/filesurface.dat000066400000000000000000000126471265434602500203130ustar00rootroot000000000000001 12 24 36 60 84 120 180 240 360 2005 2005.083333 2005.166667 2005.25 2005.333333 2005.416667 2005.5 2005.583333 2005.666667 2005.75 2005.833333 2005.916667 2006 2006.083333 2006.166667 2006.25 2006.333333 2006.416667 2006.5 2006.583333 2006.666667 2006.75 2006.833333 2006.916667 2007 2007.083333 2007.166667 2007.25 2007.333333 2007.416667 2007.5 2007.583333 2007.666667 2007.75 2007.833333 2007.916667 2008 2008.083333 2008.166667 2008.25 2008.333333 2008.416667 2008.5 2008.583333 2008.666667 2008.75 2008.833333 2008.916667 2.111 2.1039 2.103 2.1047 2.1041 2.1039 2.1064 2.1126 2.1152 2.1209 2.2225 2.4112 2.3885 2.4586 2.6333 2.6489 2.6926 2.8691 2.9389 3.0941 3.1572 3.3501 3.4214 3.64 3.6159 3.6511 3.8439 3.859 3.9194 4.0982 4.105 4.3081 4.4339 4.2355 4.216 4.7114 4.1973 4.1821 4.3046 4.3691 4.3874 4.4724 4.4716 4.4875 4.6599 4.8313 3.8433 2.9929 2.223809524 2.228 2.246190476 2.165238095 2.092727273 1.997272727 2.07185 2.14 2.128636364 2.327619048 2.577272727 2.67 2.717727273 2.793 2.978695652 3.094210526 3.175 3.271363636 3.415238095 3.489565217 3.573333333 3.664090909 3.723636364 3.773157895 3.914090909 3.9605 3.982727273 4.132105263 4.254545455 4.398095238 4.44 4.228695652 4.088 4.09 4.044090909 4.0855 3.870909091 3.631904762 3.711052632 3.955909091 4.141428571 4.562380952 4.575217391 4.36952381 4.210909091 2.93173913 2.3795 2.007727273 2.431904762 2.4595 2.517142857 2.367619048 2.237272727 2.077727273 2.18235 2.253913043 2.222727273 2.484761905 2.743636364 2.804285714 2.862272727 2.968 3.192173913 3.343157895 3.381818182 3.462727273 3.574285714 3.575652174 3.602380952 3.657272727 3.677727273 3.744210526 3.926818182 3.954 3.922272727 4.105263158 4.255454545 4.464285714 4.475 4.183478261 4.0595 4.090434783 3.898636364 3.9975 3.68 3.334761905 3.402105263 3.781818182 4.07047619 4.624761905 4.542608696 4.178095238 4.008636364 3.151304348 2.641 2.375 2.638095238 2.6685 2.735714286 2.562380952 2.416818182 2.241363636 2.33035 2.400869565 2.340454545 2.60952381 2.865454545 2.895238095 2.949545455 3.0775 3.297826087 3.477368421 3.521363636 3.589545455 3.685714286 3.640434783 3.614761905 3.674545455 3.668636364 3.742631579 3.938636364 3.9625 3.91 4.106842105 4.258636364 4.496666667 4.496818182 4.210869565 4.0975 4.138695652 3.933181818 4.027 3.719090909 3.413809524 3.434210526 3.818636364 4.071428571 4.622380952 4.56826087 4.157619048 3.993181818 3.358695652 2.8285 2.594090909 2.996190476 3.015 3.124761905 2.920952381 2.753181818 2.581818182 2.6606 2.710869565 2.595 2.829047619 3.082272727 3.056190476 3.080909091 3.2445 3.45173913 3.664736842 3.703181818 3.74 3.82047619 3.726956522 3.655714286 3.712727273 3.669090909 3.753157895 3.970454545 4.0055 3.914090909 4.126315789 4.273181818 4.538095238 4.537727273 4.25826087 4.1655 4.210869565 3.982727273 4.1085 3.829545455 3.600952381 3.591578947 3.941363636 4.137619048 4.65952381 4.622173913 4.201428571 4.126363636 3.774782609 3.2075 2.983181818 3.265714286 3.2665 3.405238095 3.21 3.04 2.87 2.9277 2.959565217 2.819545455 3.021428571 3.238636364 3.144761905 3.143636364 3.3225 3.536086957 3.798421053 3.85 3.867727273 3.91047619 3.803043478 3.706666667 3.757727273 3.700454545 3.775263158 4.003181818 4.037368421 3.938181818 4.156315789 4.288636364 4.566190476 4.546363636 4.31173913 4.23 4.27 4.076818182 4.185 3.949545455 3.793333333 3.730526316 4.043636364 4.219047619 4.636190476 4.62173913 4.258095238 4.190454545 3.967826087 3.53 3.192272727 3.593809524 3.5845 3.745238095 3.543333333 3.381363636 3.209545455 3.249 3.282173913 3.122272727 3.285714286 3.488181818 3.380952381 3.344545455 3.497 3.674347826 3.935789474 4.004090909 4.004545455 4.029047619 3.906956522 3.778095238 3.817272727 3.75 3.811052632 4.055909091 4.091 3.99 4.203157895 4.330454545 4.614285714 4.590454545 4.393913043 4.344 4.397391304 4.234545455 4.346 4.165 4.105238095 4.044210526 4.252727273 4.398571429 4.718571429 4.705217391 4.407142857 4.379090909 4.255652174 3.998 3.514545455 3.78952381 3.7435 3.9255 3.75 3.582272727 3.451363636 3.50775 3.513913043 3.359545455 3.494761905 3.665909091 3.551428571 3.504545455 3.6535 3.812608696 4.098421053 4.167272727 4.175909091 4.186666667 4.056086957 3.908571429 3.916363636 3.824545455 3.882105263 4.12 4.162 4.089090909 4.306315789 4.423181818 4.699047619 4.661818182 4.504782609 4.4985 4.519565217 4.402272727 4.5115 4.382727273 4.366666667 4.336842105 4.509545455 4.613809524 4.861428571 4.877391304 4.636666667 4.659545455 4.482173913 4.2535 3.744545455 3.99 3.9085 4.098571429 3.944285714 3.771363636 3.609090909 3.6536 3.640869565 3.488181818 3.604761905 3.755454545 3.634285714 3.565909091 3.7165 3.866521739 4.151052632 4.235454545 4.235909091 4.249047619 4.116086957 3.961904762 3.953333333 3.855714286 3.92 4.153636364 4.1985 4.139090909 4.365789474 4.471818182 4.747142857 4.695454545 4.55 4.572 4.590434783 4.500909091 4.602 4.504090909 4.513809524 4.521052632 4.656818182 4.733809524 4.899047619 4.935652174 4.746190476 4.776818182 4.598695652 4.4835 3.900454545 4.137142857 4.0305 4.213333333 4.08 3.902727273 3.739090909 3.774285714 3.757391304 3.598181818 3.706190476 3.842272727 3.712 3.629545455 3.771 3.919565217 4.231111111 4.295909091 4.306818182 4.31 4.170434783 4.000952381 3.99 3.881818182 3.943684211 4.176818182 4.2195 4.163636364 4.387368421 4.480454545 4.758095238 4.710454545 4.559565217 4.595 4.612173913 4.544090909 4.64 4.57 4.58 4.614736842 4.702727273 4.768571429 4.884761905 4.905652174 4.741904762 4.775454545 4.496521739 4.3585 3.738636364 asymptote-2.37/examples/fillcontour.asy000066400000000000000000000010761265434602500204010ustar00rootroot00000000000000import graph; import palette; import contour; size(12cm,IgnoreAspect); pair a=(pi/2,0); pair b=(3pi/2,2pi); real f(real x, real y) {return cos(x)*sin(y);} int N=100; int Divs=10; defaultpen(1bp); bounds range=bounds(-1,1); real[] Cvals=uniform(range.min,range.max,Divs); guide[][] g=contour(f,a,b,Cvals,N,operator --); pen[] Palette=quantize(Rainbow(),Divs); pen[][] interior=interior(g,extend(Palette,grey,black)); fill(g,interior); draw(g); palette("$f(x,y)$",range,point(SE)+(0.5,0),point(NE)+(1,0),Right,Palette, PaletteTicks("$%+#0.1f$",N=Divs)); asymptote-2.37/examples/fin.asy000066400000000000000000000101531265434602500166110ustar00rootroot00000000000000import three; import palette; int N = 26; real[] C = array(N,0); real[][] A = new real[N][N]; for(int i = 0; i < N; ++i) for(int j = 0; j < N; ++j) A[i][j] = 0; real Tb = 100; // deg C real h = 240; // 240 W/m^2 K real k = 240; // W/m K real Tinf = 20; // deg C real L = 12; // cm real t = 2; // cm real delta = 0.01; // 1 cm = 0.01 m // (1,2)-(2,2)-(3,2)-...-(13,2) // | | | | // (1,1)-(2,1)-(3,1)-...-(13,1) // // | // \ / // V // // 13-14-15-...-24-25 // | | | ... | | // 0- 1- 2-...-11-12 // but, note zero-based array indexing, so counting starts at 0 int indexof(int m, int n) { return 13(n-1)+m-1; } int i = 0; // fixed temperature bottom left A[i][indexof(1,1)] = 1; C[i] = Tb; ++i; // fixed temperature middle left A[i][indexof(1,2)] = 1; C[i] = Tb; ++i; // interior nodes for(int m = 2; m<13; ++m) { A[i][indexof(m,2)] = -4; A[i][indexof(m-1,2)] = A[i][indexof(m+1,2)] = 1; A[i][indexof(m,1)] = 2; C[i] = 0; ++i; } // convective bottom side nodes for(int m = 2; m<13; ++m) { A[i][indexof(m,1)] = -(2+h*delta/k); A[i][indexof(m-1,1)] = A[i][indexof(m+1,1)] = 0.5; A[i][indexof(m,2)] = 1; C[i] = -h*delta*Tinf/k; ++i; } // convective bottom right corner node A[i][indexof(13,2)] = A[i][indexof(12,1)] = 0.5; A[i][indexof(13,1)] = -(1+h*delta/k); C[i] = -h*delta*Tinf/k; ++i; // convective middle right side node A[i][indexof(13,2)] = -(2+h*delta/k); A[i][indexof(13,1)] = 1; A[i][indexof(12,2)] = 1; C[i] = -h*delta*Tinf/k; ++i; real[] T = solve(A,C); pen[] Palette = Gradient(256,blue,cyan,yellow,orange,red); real[][] T = {T[0:13],T[13:26],T[0:13]}; T = transpose(T); size3(15cm); real w = 10; real h = 5; currentprojection = orthographic(2*(L,h,w),Y); draw((L,t,0)--(L,0,0)--(L,0,w)--(0,0,w)--(0,-h,w)); draw((0,t,w)--(0,t+h,w)--(0,t+h,0)--(0,t,0)); draw((L,0,w)--(L,t,w)--(0,t,w)--(0,t,0)--(L,t,0)--(L,t,w)); real wo2 = 0.5*w; draw((0,0,wo2)--(0,t,wo2)--(L,t,wo2)--(L,0,wo2)--cycle); // centre points surface square = surface(shift(-0.5,-0.5,wo2)*unitsquare3); surface bottomsquare = surface(shift(-0.5,-0.5,wo2)*scale(1,0.5,1)*unitsquare3); surface topsquare = surface(shift(-0.5,0,wo2)*scale(1,0.5,1)*unitsquare3); surface leftsquare = surface(shift(-0.5,-0.5,wo2)*scale(0.5,1,1)*unitsquare3); surface rightsquare = surface(shift(0,-0.5,wo2)*scale(0.5,1,1)*unitsquare3); surface NEcorner = surface(shift(0,0,wo2)*scale(0.5,0.5,1)*unitsquare3); surface SEcorner = surface(shift(0,-0.5,wo2)*scale(0.5,0.5,1)*unitsquare3); surface SWcorner = surface(shift(-0.5,-0.5,wo2)*scale(0.5,0.5,1)*unitsquare3); surface NWcorner = surface(shift(-0.5,0,wo2)*scale(0.5,0.5,1)*unitsquare3); material lookupColour(int m,int n) { int index = round(Palette.length*(T[m-1][n-1]-60)/(100-60)); if(index >= Palette.length) index = Palette.length-1; return emissive(Palette[index]); } draw(shift(0,1,0)*rightsquare,lookupColour(1,2)); for(int i = 2; i < 13; ++i) { draw(shift(i-1,1,0)*square,lookupColour(i,2)); } draw(shift(12,1,0)*leftsquare,lookupColour(13,2)); draw(shift(0,2,0)*SEcorner,lookupColour(1,3)); draw(shift(0,0,0)*NEcorner,lookupColour(1,1)); for(int i = 2; i < 13; ++i) { draw(shift(i-1,0,0)*topsquare,lookupColour(i,1)); draw(shift(i-1,2,0)*bottomsquare,lookupColour(i,3)); } draw(shift(12,2,0)*SWcorner,lookupColour(13,3)); draw(shift(12,0,0)*NWcorner,lookupColour(13,1)); // annotations draw("$x$",(0,-h/2,w)--(L/4,-h/2,w),Y,Arrow3(HookHead2(normal=Z)),BeginBar3(Y)); draw("$y$",(0,0,1.05*w)--(0,2t,1.05*w),Z,Arrow3(HookHead2(normal=X)), BeginBar3(Z)); draw("$z$",(L,-h/2,0)--(L,-h/2,w/4),Y,Arrow3(HookHead2(normal=X)),BeginBar3(Y)); draw("$L$",(0,-h/4,w)--(L,-h/4,w),-Y,Arrows3(HookHead2(normal=Z)), Bars3(Y),PenMargins2); draw("$w$",(L,-h/4,0)--(L,-h/4,w),-Y,Arrows3(HookHead2(normal=X)), Bars3(Y),PenMargins2); draw("$t$",(1.05*L,0,0)--(1.05*L,t,0),-2Z,Arrows3(HookHead2(normal=Z)), Bars3(X),PenMargins2); label(ZY()*"$T_b$",(0,t+h/2,wo2)); label("$h$,$T_\infty$",(L/2,t+h/2,0),Y); path3 air = (L/2,t+h/3,w/3.5)--(1.5*L/2,t+2*h/3,w/8); draw(air,EndArrow3(TeXHead2)); draw(shift(0.5,0,0)*air,EndArrow3(TeXHead2)); draw(shift(1.0,0,0)*air,EndArrow3(TeXHead2)); asymptote-2.37/examples/fjortoft.asy000066400000000000000000000013061265434602500176720ustar00rootroot00000000000000size(15cm,0); pair d=(1.5,1); real s=d.x+1; picture box(string s) { picture pic; draw(pic,box(0,d)); label(pic,s,d/2); return pic; } add(box("$k_1$")); add(shift(s)*box("$k_2$")); add(shift(s)^2*box("$k_3$")); path g=(d.x,d.y/2)--(s,d.y/2); path G=(d.x/2,-(s-d.x))--(d.x/2,0); draw(Label(baseline("$\ldots$")),shift(-s)*g,BeginArrow,BeginPenMargin); draw(Label("$Z_1$"),g,BeginArrow,BeginPenMargin); draw(Label("$E_1$",LeftSide),g,Blank); draw(Label("$Z_3$"),shift(s)*g,Arrow,PenMargin); draw(Label("$E_3$",LeftSide),shift(s)*g,Blank); draw(Label("$Z_2$"),shift(s)*G,Arrow,PenMargin); draw(Label("$E_2$",LeftSide),shift(s)*G,Blank); draw(Label(baseline("$\ldots$")),shift(s)^2*g,Arrow,PenMargin); asymptote-2.37/examples/floatingdisk.asy000066400000000000000000000010441265434602500205120ustar00rootroot00000000000000import trembling; settings.outformat="pdf"; size(6cm,0); real R=1/5; real h=0.5; real d=1/12; real l=.7; pair pA=(-l,0); pair pB=(l,0); tremble tr=tremble(angle=10,frequency=0.1,random=50,fuzz=1); path waterline=tr.deform(pA..pB); path disk=shift(0,-d)*scale(R)*unitcircle; path water=waterline--(l,-h)--(-l,-h)--(-l,0)--cycle; path container=(l,1/7)--(l,-h)--(-l,-h)--(-l,1/7); filldraw(disk,red,linewidth(.3)); fill(water,mediumgrey+opacity(0.5)); draw(waterline); draw(container,linewidth(1.5)); shipout(bbox(2mm)); asymptote-2.37/examples/floor.asy000066400000000000000000000007661265434602500171670ustar00rootroot00000000000000import graph; unitsize(1cm); real Floor(real x) {return floor(x);} pair[] Close; pair[] Open; bool3 branch(real x) { static real lasty; static bool first=true; real y=floor(x); bool samebranch=first || lasty == y; first=false; if(samebranch) lasty=x; else { Close.push((x,lasty)); Open.push((x,y)); } lasty=y; return samebranch ? true : default; }; draw(graph(Floor,-5.5,5.5,500,branch)); axes("$x$",rotate(0)*"$\lfloor x\rfloor$",red); dot(Close); dot(Open,UnFill); asymptote-2.37/examples/fractaltree.asy000066400000000000000000000012531265434602500203320ustar00rootroot00000000000000size(200); path ltrans(path p,int d) { path a=rotate(65)*scale(0.4)*p; return shift(point(p,(1/d)*length(p))-point(a,0))*a; } path rtrans(path p, int d) { path a=reflect(point(p,0),point(p,length(p)))*rotate(65)*scale(0.35)*p; return shift(point(p,(1/d)*length(p))-point(a,0))*a; } void drawtree(int depth, path branch) { if(depth == 0) return; real breakp=(1/depth)*length(branch); draw(subpath(branch,0,breakp),deepgreen); drawtree(depth-1,subpath(branch,breakp,length(branch))); drawtree(depth-1,ltrans(branch,depth)); drawtree(depth-1,rtrans(branch,depth)); return; } path start=(0,0)..controls (-1/10,1/3) and (-1/20,2/3)..(1/20,1); drawtree(6,start); asymptote-2.37/examples/functionshading.asy000066400000000000000000000022411265434602500212170ustar00rootroot00000000000000size(200); settings.tex="pdflatex"; // PostScript Calculator routine to convert from [0,1]x[0,1] to RG: string redgreen="0"; // PostScript Calculator routine to convert from [0,1]x[0,1] to HS to RGB: // (http://www.texample.net/tikz/examples/hsv-shading): string hsv="0.5 sub exch 0.5 sub exch 2 copy 2 copy 0 eq exch 0 eq and { pop pop 0.0 } {atan 360.0 div} ifelse dup 360 eq { pop 0.0 }{} ifelse 3 1 roll dup mul exch dup mul add sqrt 2.5 mul 0.25 sub 1 1 index 1.0 eq { 3 1 roll pop pop dup dup } { 3 -1 roll 6.0 mul dup 4 1 roll floor dup 5 1 roll 3 index sub neg 1.0 3 index sub 2 index mul 6 1 roll dup 3 index mul neg 1.0 add 2 index mul 7 1 roll neg 1.0 add 2 index mul neg 1.0 add 1 index mul 7 2 roll pop pop dup 0 eq { pop exch pop } { dup 1 eq { pop exch 4 1 roll exch pop } { dup 2 eq { pop 4 1 roll pop } { dup 3 eq { pop exch 4 2 roll pop } { dup 4 eq { pop exch pop 3 -1 roll } { pop 3 1 roll exch pop } ifelse } ifelse } ifelse } ifelse } ifelse } ifelse cvr 3 1 roll cvr 3 1 roll cvr 3 1 roll"; path p=unitcircle; functionshade(p,rgb(zerowinding),redgreen); layer(); draw(p); path g=shift(2*dir(-45))*p; functionshade(g,rgb(zerowinding),hsv); layer(); draw(g); asymptote-2.37/examples/galleon.asy000066400000000000000000000007631265434602500174640ustar00rootroot00000000000000import obj; size(15cm); currentprojection=orthographic(0,2,5,up=Y); // A compressed version of the required data file may be obtained from: // http://www.cs.technion.ac.il/~irit/data/Viewpoint/galleon.obj.gz pen[] surfacepen={darkred,brown,darkred+orange,heavyred,heavyred,darkred+orange, palegreen+blue+lightgrey,darkred,darkred,yellow,darkred,white, white,white,white,white,white}; surfacepen.cyclic=true; draw(obj("galleon.obj",verbose=false,surfacepen)); asymptote-2.37/examples/gamma.asy000066400000000000000000000006701265434602500171220ustar00rootroot00000000000000import graph; size(300,IgnoreAspect); bool3 branch(real x) { static int lastsign=0; if(x <= 0 && x == floor(x)) return false; int sign=sgn(gamma(x)); bool b=lastsign == 0 || sign == lastsign; lastsign=sign; return b ? true : default; } draw(graph(gamma,-4,4,n=2000,branch),red); scale(false); xlimits(-4,4); ylimits(-6,6); crop(); xaxis("$x$",RightTicks(NoZero)); yaxis(LeftTicks(NoZero)); label("$\Gamma(x)$",(1,2),red); asymptote-2.37/examples/gamma3.asy000066400000000000000000000013121265434602500171770ustar00rootroot00000000000000import graph3; import palette; size(12cm,IgnoreAspect); currentprojection=orthographic(1,-2,1); real X=4.5; real M=abs(gamma((X,0))); pair Gamma(pair z) { return (z.x > 0 || z != floor(z.x)) ? gamma(z) : M; } real f(pair z) {return min(abs(Gamma(z)),M);} surface s=surface(f,(-2.1,-2),(X,2),70,Spline); real Arg(triple v) { return degrees(Gamma((v.x,v.y)),warn=false); } s.colors(palette(s.map(Arg),Wheel())); draw(s,render(compression=Low,merge=true)); real xmin=point((-1,-1,-1)).x; real xmax=point((1,1,1)).x; draw((xmin,0,0)--(xmax,0,0),dashed); xaxis3("$\mathop{\rm Re} z$",Bounds,InTicks); yaxis3("$\mathop{\rm Im} z$",Bounds,InTicks(beginlabel=false)); zaxis3("$|\Gamma(z)|$",Bounds,InTicks); asymptote-2.37/examples/genusthree.asy000066400000000000000000000012471265434602500202120ustar00rootroot00000000000000size(8cm); import smoothcontour3; // Erdos lemniscate of order n: real erdos(pair z, int n) { return abs(z^n-1)^2 - 1; } real h = 0.12; // Erdos lemniscate of order 3: real lemn3(real x, real y) { return erdos((x,y), 3); } // "Inflate" the order 3 (planar) lemniscate into a // smooth surface: real f(real x, real y, real z) { return lemn3(x,y)^2 + (16*abs((x,y))^4 + 1) * (z^2 - h^2); } // Draw the implicit surface on a box with diagonally opposite // corners at (-3,-3,-3), (3,3,3). draw(implicitsurface(f,a=(-3,-3,-3),b=(3,3,3),overlapedges=true), surfacepen=material(diffusepen=gray(0.5),emissivepen=gray(0.4), specularpen=gray(0.1))); asymptote-2.37/examples/genustwo.asy000066400000000000000000000021601265434602500177070ustar00rootroot00000000000000size(10cm,0); import smoothcontour3; currentprojection=perspective((18,20,10)); if(settings.render < 0) settings.render=8; real tuberadius = 0.69; // Convert to cylindrical coordinates to draw // a circle revolved about the z axis. real toruscontour(real x, real y, real z) { real r = sqrt(x^2 + y^2); return (r-2)^2 + z^2 - tuberadius^2; } // Take the union of the two tangent tori (by taking // the product of the functions defining them). Then // add (or subtract) a bit of noise to smooth things // out. real f(real x, real y, real z) { real f1 = toruscontour(x - 2 - tuberadius, y, z); real f2 = toruscontour(x + 2 + tuberadius, y, z); return f1 * f2 - 0.1; } // The noisy function extends a bit farther than the union of // the two tori, so include a bit of extra space in the box. triple max = (2*(2+tuberadius), 2+tuberadius, tuberadius) + (0.1, 0.1, 0.1); triple min = -max; // Draw the implicit surface. draw(implicitsurface(f, min, max, overlapedges=true, nx=20, nz=5), surfacepen=material(diffusepen=gray(0.6), emissivepen=gray(0.3), specularpen=gray(0.1))); asymptote-2.37/examples/grid.asy000066400000000000000000000001141265434602500167560ustar00rootroot00000000000000import math; size(100,0); add(shift(-5,-5)*grid(10,10)); dot((0,0),red); asymptote-2.37/examples/hierarchy.asy000066400000000000000000000007131265434602500200140ustar00rootroot00000000000000texpreamble("\def\Ham{\mathop {\rm Ham}\nolimits}"); pair align=2N; frame f; ellipse(f,Label("$\Ham(r,2)$",(0,0)),lightblue,Fill,above=false); ellipse(f,Label("BCH Codes",point(f,N),align),green,Fill,above=false); ellipse(f,Label("Cyclic Codes",point(f,N),align),lightmagenta,Fill,above=false); ellipse(f,Label("Linear Codes",point(f,N),align),-4mm,orange,Fill,above=false); box(f,Label("General Codes",point(f,N),align),2mm,yellow,Fill,above=false); add(f); asymptote-2.37/examples/hyperboloid.asy000066400000000000000000000004641265434602500203610ustar00rootroot00000000000000size(200); import solids; currentprojection=perspective(4,4,3); revolution hyperboloid=revolution(graph(new triple(real z) { return (sqrt(1+z*z),0,z);},-2,2,20,operator ..),axis=Z); draw(surface(hyperboloid),green,render(compression=Low,merge=true)); draw(hyperboloid,6,blue,longitudinalpen=nullpen); asymptote-2.37/examples/hyperboloidsilhouette.asy000066400000000000000000000004131265434602500224610ustar00rootroot00000000000000size(200); import solids; settings.render=0; settings.prc=false; currentprojection=perspective(4,4,3); revolution hyperboloid=revolution(graph(new triple(real z) { return (sqrt(1+z*z),0,z);},-2,2,20,operator ..),axis=Z); draw(hyperboloid.silhouette(64),blue); asymptote-2.37/examples/imagehistogram.asy000066400000000000000000000021641265434602500210400ustar00rootroot00000000000000import stats; import graph; import palette; import contour; size(20cm); scale(false); pair[] data=new pair[50000]; for(int i=0; i < data.length; ++i) data[i]=Gaussrandpair(); // Histogram limits and number of bins pair datamin=(-0.15,-0.15); pair datamax=(0.15,0.15); int Nx=30; int Ny=30; int[][] bins=frequency(data,datamin,datamax,Nx,Ny); real[] values=new real[Nx*Ny]; pair[] points=new pair[Nx*Ny]; int k=0; real dx=(datamax.x-datamin.x)/Nx; real dy=(datamax.y-datamin.y)/Ny; for(int i=0; i < Nx; ++i) { for(int j=0; j < Ny; ++j) { values[k]=bins[i][j]; points[k]=(datamin.x+(i+0.5)*dx,datamin.y+(j+0.5)*dy); ++k; } } // Create a color palette pen[] InvGrayscale(int NColors=256) { real ninv=1.0/(NColors-1.0); return sequence(new pen(int i) {return gray(1-17*i*ninv);},NColors); } // Draw the histogram, with axes bounds range=image(points,values,Range(0,40),InvGrayscale()); draw(contour(points,values,new real[] {1,2,3,4,8,12,16,20,24,28,32,36,40}, operator--),blue); xaxis("$x$",BottomTop,LeftTicks,above=true); yaxis("$y$",LeftRight,RightTicks,above=true); asymptote-2.37/examples/impact.asy000066400000000000000000000011421265434602500173100ustar00rootroot00000000000000// Contributed by Philippe Ivaldi. // http://www.piprime.fr/ import graph3 ; import contour; size (6cm,0); currentprojection=orthographic(1,1,1) ; real rc=1, hc=2, c=rc/hc; draw(shift(hc*Z)*scale(rc,rc,-hc)*unitcone,blue); triple Os=(0.5,0.5,1); real r=0.5; draw(shift(Os)*scale3(r)*unitsphere,red); real a=1+1/c^2; real b=abs(Os)^2-r^2; real f(pair z) { real x=z.x, y=z.y; return a*x^2-2*Os.x*x+a*y^2-2*Os.y*y-2*Os.z*sqrt(x^2+y^2)/c+b; } real g(pair z){return (sqrt(z.x^2+z.y^2))/c;} draw(lift(g,contour(f,(-rc,-rc),(rc,rc),new real[]{0})),linewidth(2bp)+yellow); axes3("$x$","$y$","$z$",Arrow3); asymptote-2.37/examples/integraltest.asy000066400000000000000000000011351265434602500205420ustar00rootroot00000000000000import graph; size(300,150,IgnoreAspect); real f(real x) {return 1/x^(1.1);} pair F(real x) {return (x,f(x));} dotfactor=7; void subinterval(real a, real b) { path g=box((a,0),(b,f(b))); filldraw(g,lightgray); draw(box((a,f(a)),(b,0))); } int a=1, b=9; xaxis("$x$",0,b); yaxis("$y$",0); draw(graph(f,a,b,operator ..),red); int n=2; for(int i=a; i <= b; ++i) { if(i < b) subinterval(i,i+1); if(i <= n) labelx(i); dot(F(i)); } int i=n; labelx("$\ldots$",++i); labelx("$k$",++i); labelx("$k+1$",++i); labelx("$\ldots$",++i); arrow("$f(x)$",F(i-1.5),NE,1.5cm,red,Margin(0,0.5)); asymptote-2.37/examples/interpolate1.asy000066400000000000000000000113311265434602500204430ustar00rootroot00000000000000// Lagrange and Hermite interpolation in Asymptote // Author: Olivier Guibé import interpolate; import graph; // Test 1: The Runge effect in the Lagrange interpolation of 1/(x^2+1). unitsize(2cm); real f(real x) {return(1/(x^2+1));} real df(real x) {return(-2*x/(x^2+1)^2);} real a=-5, b=5; int n=15; real[] x,y,dy; x=a+(b-a)*sequence(n+1)/n; y=map(f,x); dy=map(df,x); for(int i=0; i <= n; ++i) dot((x[i],y[i]),5bp+blue); horner h=diffdiv(x,y); fhorner p=fhorner(h); draw(graph(p,a,b,n=500),"$x\longmapsto{}L_{"+string(n)+"}$"); draw(graph(f,a,b),red,"$x\longmapsto{}\frac{1}{x^2+1}$"); xlimits(-5,5); ylimits(-1,1,Crop); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks); attach(legend(),point(10S),30S); shipout("runge1"); erase(); // Test 2: The Runge effect in the Hermite interpolation of 1/(x^2+1). real f(real x) {return(1/(x^2+1));} real df(real x) {return(-2*x/(x^2+1)^2);} real a=-5, b=5; int n=16; real[] x,y,dy; x=a+(b-a)*sequence(n+1)/n; y=map(f,x); dy=map(df,x); for(int i=0; i <= n; ++i) dot((x[i],y[i]),5bp+blue); horner h=hdiffdiv(x,y,dy); fhorner ph=fhorner(h); draw(graph(p,a,b,n=500),"$x\longmapsto{}H_{"+string(n)+"}$"); draw(graph(f,a,b),red,"$x\longmapsto{}\frac{1}{x^2+1}$"); unitsize(2cm); xlimits(-5,5); ylimits(-1,5,Crop); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks); attach(legend(),point(10S),30S); shipout("runge2"); erase(); // Test 3: The Runge effect does not occur for all functions: // Lagrange interpolation of a function whose successive derivatives // are bounded by a constant M (here M=1) is shown here to converge. real f(real x) {return(sin(x));} real df(real x) {return(cos(x));} real a=-5, b=5; int n=16; real[] x,y,dy; x=a+(b-a)*sequence(n+1)/n; y=map(f,x); dy=map(df,x); for(int i=0; i <= n; ++i) dot((x[i],y[i]),5bp+blue); horner h=diffdiv(x,y); fhorner p=fhorner(h); draw(graph(p,a,b,n=500),"$x\longmapsto{}L_{"+string(n)+"}$"); draw(graph(f,a,b),red,"$x\longmapsto{}\cos(x)$"); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks); attach(legend(),point(10S),30S); shipout("runge3"); erase(); // Test 4: However, one notes here that numerical artifacts may arise // from limit precision (typically 1e-16). real f(real x) {return(sin(x));} real df(real x) {return(cos(x));} real a=-5, b=5; int n=72; real[] x,y,dy; x=a+(b-a)*sequence(n+1)/n; y=map(f,x); dy=map(df,x); for(int i=0; i <= n; ++i) dot((x[i],y[i]),5bp+blue); horner h=diffdiv(x,y); fhorner p=fhorner(h); draw(graph(p,a,b,n=500),"$x\longmapsto{}L_{"+string(n)+"}$"); draw(graph(f,a,b),red,"$x\longmapsto{}\cos(x)$"); ylimits(-1,5,Crop); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks); attach(legend(),point(10S),30S); shipout("runge4"); erase(); // Test 5: The situation is much better using Tchebychev points. unitsize(2cm); real f(real x) {return(1/(x^2+1));} real df(real x) {return(-2*x/(x^2+1)^2);} real a=-5, b=5; int n=16; real[] x,y,dy; fhorner p,ph,ph1; for(int i=0; i <= n; ++i) x[i]=(a+b)/2+(b-a)/2*cos((2*i+1)/(2*n+2)*pi); y=map(f,x); dy=map(df,x); for(int i=0; i <= n; ++i) dot((x[i],y[i]),5bp+blue); horner h=diffdiv(x,y); fhorner p=fhorner(h); draw(graph(p,a,b,n=500),"$x\longmapsto{}T_{"+string(n)+"}$"); draw(graph(f,a,b),red,"$x\longmapsto{}\frac{1}{x^2+1}$"); xlimits(-5,5); ylimits(-1,2,Crop); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks); attach(legend(),point(10S),30S); shipout("runge5"); erase(); // Test 6: Adding a few more Tchebychev points yields a very good result. unitsize(2cm); real f(real x) {return(1/(x^2+1));} real df(real x) {return(-2*x/(x^2+1)^2);} real a=-5, b=5; int n=26; real[] x,y,dy; for(int i=0; i <= n; ++i) x[i]=(a+b)/2+(b-a)/2*cos((2*i+1)/(2*n+2)*pi); y=map(f,x); dy=map(df,x); for(int i=0; i <= n; ++i) dot((x[i],y[i]),5bp+blue); horner h=diffdiv(x,y); fhorner p=fhorner(h); draw(graph(p,a,b,n=500),"$x\longmapsto{}T_{"+string(n)+"}$"); draw(graph(f,a,b),red,"$x\longmapsto{}\frac{1}{x^2+1}$"); xlimits(-5,5); ylimits(-1,2,Crop); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks); attach(legend(),point(10S),30S); shipout("runge6"); erase(); // Test 7: Another Tchebychev example. unitsize(2cm); real f(real x) {return(sqrt(abs(x-1)));} real a=-2, b=2; int n=30; real[] x,y,dy; for(int i=0; i <= n; ++i) x[i]=(a+b)/2+(b-a)/2*cos((2*i+1)/(2*n+2)*pi); y=map(f,x); dy=map(df,x); for(int i=0; i <= n; ++i) dot((x[i],y[i]),5bp+blue); horner h=diffdiv(x,y); fhorner p=fhorner(h); draw(graph(p,a,b,n=500),"$x\longmapsto{}T_{"+string(n)+"}$"); draw(graph(f,a,b),red,"$x\longmapsto{}\sqrt{|x-1|}$"); xlimits(-2,2); ylimits(-0.5,2,Crop); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks); attach(legend(),point(10S),30S); shipout("runge7"); asymptote-2.37/examples/jump.asy000066400000000000000000000004431265434602500170110ustar00rootroot00000000000000import graph; size(4inches,0); real f1(real x) {return (1+x^2);} real f2(real x) {return (4-x);} xaxis("$x$",LeftTicks,Arrow); yaxis("$y$",RightTicks,Arrow); draw("$y=1+x^2$",graph(f1,-2,1)); dot((1,f1(1)),UnFill); draw("$y=4-x$",graph(f2,1,5),LeftSide,red,Arrow); dot((1,f2(1)),red); asymptote-2.37/examples/label3.asy000066400000000000000000000002661265434602500172030ustar00rootroot00000000000000import three; currentprojection=perspective(0,0,1,up=Y); label(scale(4)*"$\displaystyle\int_{-\infty}^{+\infty} e^{-\alpha x^2}\,dx= \sqrt{\frac{\pi}{\alpha}}$",O,blue,Embedded); asymptote-2.37/examples/label3ribbon.asy000066400000000000000000000003041265434602500203700ustar00rootroot00000000000000import three; currentprojection=perspective(100,100,200,up=Y); draw(scale3(4)*extrude(texpath("$\displaystyle\int_{-\infty}^{+\infty} e^{-\alpha x^2}\,dx=\sqrt{\frac{\pi}{\alpha}}$"),2Z),blue); asymptote-2.37/examples/label3solid.asy000066400000000000000000000002731265434602500202340ustar00rootroot00000000000000import three; currentprojection=perspective(100,100,200,up=Y); draw(scale3(4)*extrude("$\displaystyle\int_{-\infty}^{+\infty} e^{-\alpha x^2}\,dx=\sqrt{\frac{\pi}{\alpha}}$",2Z),blue); asymptote-2.37/examples/label3zoom.asy000066400000000000000000000010701265434602500201020ustar00rootroot00000000000000import three; currentlight=Headlamp; size(469.75499pt,0); currentprojection=perspective( camera=(160.119024441391,136.348802919248,253.822628496226), up=(-0.188035408976828,0.910392236102215,-0.368549401594584), target=(25.5462739598034,1.77605243766079,-9.93996244768584), zoom=5.59734733413271, angle=5.14449021168139, viewportshift=(0.813449720559684,-0.604674743165144), autoadjust=false); draw(scale3(4)*extrude("$\displaystyle\int\limits_{-\infty}^{+\infty}\!\! e^{-\alpha x^2}\!\!=\sqrt{\frac{\pi}{\alpha}}$",2Z), material(blue,ambientpen=mediumgray)); asymptote-2.37/examples/labelbox.asy000066400000000000000000000004101265434602500176200ustar00rootroot00000000000000size(0,100); real margin=2mm; pair z1=(0,1); pair z0=(0,0); object Box=draw("small box",box,z1,margin); object Ellipse=draw("LARGE ELLIPSE",ellipse,z0,margin); add(new void(frame f, transform t) { draw(f,point(Box,SW,t){SW}..{SW}point(Ellipse,NNE,t)); }); asymptote-2.37/examples/laserlattice.asy000066400000000000000000000021321265434602500205070ustar00rootroot00000000000000import graph; import palette; int n=256; pen[] Palette=BWRainbow(); real w(real w0, real z0, real z) {return w0*sqrt(1+(z/z0)^2);} real pot(real lambda, real w0, real r, real z) { real z0=pi*w0^2/lambda, kappa=2pi/lambda; return exp(-2*(r/w(w0,z0,z))^2)*cos(kappa*z)^2; } picture make_field(real lambda, real w0) { real[][] v=new real[n][n]; for(int i=0; i < n; ++i) for(int j=0; j < n; ++j) v[i][j]=pot(lambda,w0,i-n/2,abs(j-n/2)); picture p=new picture; size(p,250,250,IgnoreAspect); real xm=-n/lambda, ym=-n/(2*w0), xx=n/lambda, yx=n/(2*w0); image(p,v,(xm,ym),(xx,yx),Palette); xlimits(p,xm,xx); ylimits(p,ym,yx); xaxis(p,"{\Large $z/\frac{\lambda}{2}$}",BottomTop,LeftTicks); yaxis(p,"{\Large $r/w_0$}",LeftRight,RightTicks); label(p,format("{\LARGE $w_0/\lambda=%.2f$}",w0/lambda),point(p,NW),5N); return p; } picture p=make_field(160,80); picture q=make_field(80,80); picture r=make_field(16,80); picture s=make_field(2,80); real margin=1cm; add(p.fit(),(0,0),margin*NW); add(q.fit(),(0,0),margin*NE); add(r.fit(),(0,0),margin*SW); add(s.fit(),(0,0),margin*SE); asymptote-2.37/examples/latticeshading.asy000066400000000000000000000002101265434602500210110ustar00rootroot00000000000000size(200); pen[][] p={{white,grey,black}, {red,green,blue}, {cyan,magenta,yellow}}; latticeshade(unitsquare,p); asymptote-2.37/examples/layers.asy000066400000000000000000000012601265434602500173330ustar00rootroot00000000000000usepackage("ocg"); settings.tex="pdflatex"; size(0,150); pen colour1=red; pen colour2=green; pair z0=(0,0); pair z1=(-1,0); pair z2=(1,0); real r=1.5; path c1=circle(z1,r); path c2=circle(z2,r); begin("A"); fill(c1,colour1); end(); fill(c2,colour2); picture intersection; fill(intersection,c1,colour1+colour2); clip(intersection,c2); add(intersection); draw(c1); draw(c2); label("$A$",z1); begin("B"); label("$B$",z2); end(); pair z=(0,-2); real m=3; margin BigMargin=Margin(0,m*dot(unit(z1-z),unit(z0-z))); draw(Label("$A\cap B$",0),conj(z)--z0,Arrow,BigMargin); draw(Label("$A\cup B$",0),z--z0,Arrow,BigMargin); draw(z--z1,Arrow,Margin(0,m)); draw(z--z2,Arrow,Margin(0,m)); asymptote-2.37/examples/lever.asy000066400000000000000000000007141265434602500171540ustar00rootroot00000000000000size(200,0); pair z0=(0,0); pair z1=(2,0); pair z2=(5,0); pair zf=z1+0.75*(z2-z1); draw(z1--z2); dot(z1,red+0.15cm); dot(z2,darkgreen+0.3cm); label("$m$",z1,1.2N,red); label("$M$",z2,1.5N,darkgreen); label("$\hat{\ }$",zf,0.2*S,fontsize(24pt)+blue); pair s=-0.2*I; draw("$x$",z0+s--z1+s,N,red,Arrows,Bars,PenMargins); s=-0.5*I; draw("$\bar{x}$",z0+s--zf+s,blue,Arrows,Bars,PenMargins); s=-0.95*I; draw("$X$",z0+s--z2+s,darkgreen,Arrows,Bars,PenMargins); asymptote-2.37/examples/limit.asy000066400000000000000000000012161265434602500171530ustar00rootroot00000000000000size(200,200,IgnoreAspect); import graph; real L=1; real epsilon=0.25; real a(int n) {return L+1/n;} for(int i=1; i < 20; ++i) dot((i,a(i))); real N=1/epsilon; xaxis(Label("$n$",align=2S)); yaxis(Label("$a_n$",0.85)); xtick("$2$",2); ytick("$\frac{3}{2}$",3/2); ytick("$2$",2); yequals(Label("$L$",0,up),L,extend=true,blue); yequals(Label("$L+\epsilon$",1,NW),L+epsilon,extend=true,red+dashed); yequals(Label("$L-\epsilon$",1,SW),L-epsilon,extend=true,red+dashed); xequals(N,extend=true,darkgreen+dashed); labelx(shift(0,-10)*"$N=\frac{1}{\epsilon}$",N,E,darkgreen); label("$a_n=1+\frac{1}{n},\quad \epsilon=\frac{1}{4}$",point((0,1)),10S+E); asymptote-2.37/examples/lines.asy000066400000000000000000000002501265434602500171440ustar00rootroot00000000000000import math; int n=7; size(200,0); draw(unitcircle,red); for (int i=0; i < n-1; ++i) for (int j=i+1; j < n; ++j) drawline(unityroot(n,i),unityroot(n,j),blue); asymptote-2.37/examples/lmfit1.asy000066400000000000000000000017241265434602500172350ustar00rootroot00000000000000import lmfit; import graph; size(10cm, 7cm, IgnoreAspect); real[] date = { 1790, 1800, 1810, 1820, 1830, 1840, 1850, 1860, 1870, 1880, 1890, 1900, 1910, 1920, 1930, 1940, 1950, 1960, 1970, 1980, 1990 }; real[] population = { 3.929, 5.308, 7.240, 9.638, 12.866, 17.069, 23.192, 31.443, 38.558, 50.156, 62.948, 75.996, 91.972, 105.711, 122.775, 131.669, 150.697, 179.323, 203.185, 226.546, 248.710 }; real t0 = 1776; real P(real[] params, real t) { real P0 = params[0]; real K = params[1]; real r = params[2]; return (K * P0) / (P0 + (K - P0) * exp(-r * (t - t0))); } real[] params = { 10, 500, 0.1 }; real res = lmfit.fit(date, population, P, params).norm; write("P_0 = ", params[0]); write("K = ", params[1]); write("r = ", params[2]); write("error = ", res); real P(real t) { return P(params, t); } draw(graph(date, population), blue); draw(graph(P, t0, 2000), red); xaxis("Year", BottomTop, LeftTicks); yaxis("Population in millions", LeftRight, RightTicks); asymptote-2.37/examples/log.asy000066400000000000000000000003161265434602500166160ustar00rootroot00000000000000import graph; size(150,0); real f(real x) {return log(x);} pair F(real x) {return (x,f(x));} xaxis("$x$",0); yaxis("$y$"); draw(graph(f,0.01,10,operator ..)); labelx(1,SSE); label("$\log x$",F(7),SE); asymptote-2.37/examples/logdown.asy000066400000000000000000000005351265434602500175110ustar00rootroot00000000000000import graph; size(200,IgnoreAspect); real log10Down(real x) {return -log10(x);} real pow10Down(real x) {return pow10(-x);} scaleT LogDown=scaleT(log10Down,pow10Down,logarithmic=true); scale(Linear,LogDown); draw(graph(exp,-5,5)); yaxis("$y$",RightTicks(Label(Fill(white)),DefaultLogFormat),BeginArrow); xaxis("$x$",LeftTicks(NoZero),EndArrow); asymptote-2.37/examples/logo3.asy000066400000000000000000000022171265434602500170620ustar00rootroot00000000000000import three; size(560,320,IgnoreAspect); size3(140,80,15); currentprojection=perspective(-2,20,10,up=Y); currentlight=White; real a=-0.4; real b=0.95; real y1=-5; real y2=-3y1/2; path A=(a,0){dir(10)}::{dir(89.5)}(0,y2); path B=(0,y1){dir(88.3)}::{dir(20)}(b,0); real c=0.5*a; pair z=(0,2.5); transform t=scale(1,15); transform T=inverse(scale(t.yy,t.xx)); path[] g=shift(0,1.979)*scale(0.01)*t* texpath(Label("{\it symptote}",z,0.25*E+0.169S,fontsize(24pt))); pair w=(0,1.7); pair u=intersectionpoint(A,w-1--w); real h=0.25*linewidth(); real hy=(T*(h,h)).x; g.push(t*((a,hy)--(b,hy)..(b+hy,0)..(b,-hy)--(a,-hy)..(a-hy,0)..cycle)); g.push(T*((h,y1)--(h,y2)..(0,y2+h)..(-h,y2)--(-h,y1)..(0,y1-h)..cycle)); g.push(shift(0,w.y)*t*((u.x,hy)--(w.x,hy)..(w.x+hy,0)..(w.x,-hy)--(u.x,-hy)..(u.x-hy,0)..cycle)); real f=0.75; g.push(point(A,0)--shift(-f*hy,f*h)*A--point(A,1)--shift(f*hy,-f*h)*reverse(A)--cycle); g.push(point(B,0)--shift(f*hy,-f*h)*B--point(B,1)--shift(-f*hy,f*h)*reverse(B)--cycle); triple H=-0.1Z; material m=material(lightgray,shininess=1.0); for(path p : g) draw(extrude(p,H),m); surface s=surface(g); draw(s,red,nolight); draw(shift(H)*s,m); asymptote-2.37/examples/lowint.asy000066400000000000000000000003041265434602500173460ustar00rootroot00000000000000size(100,0); import graph; import lowupint; real a=-0.8, b=1.2; real c=1.0/sqrt(3.0); partition(a,b,c,min); arrow("$f(x)$",F(0.5*(a+b)),NNE,red); label("$\cal{L}$",(0.5*(a+b),f(0.5*(a+b))/2)); asymptote-2.37/examples/lowupint.asy000066400000000000000000000012231265434602500177140ustar00rootroot00000000000000import graph; real f(real x) {return x^3-x+2;} pair F(real x) {return (x,f(x));} void rectangle(real a, real b, real c, real h(real,real)) { real height=(a < c && c < b) ? f(c) : h(f(a),f(b)); pair p=(a,0), q=(b,height); path g=box(p,q); fill(g,lightgray); draw(g); } void partition(real a, real b, real c, real h(real,real)) { rectangle(a,a+.4,c,h); rectangle(a+.4,a+.6,c,h); rectangle(a+.6,a+1.2,c,h); rectangle(a+1.2,a+1.6,c,h); rectangle(a+1.6,a+1.8,c,h); rectangle(a+1.8,b,c,h); draw((a,0)--(F(a))); draw((b,0)--(F(b))); draw(graph(f,a,b,operator ..),red); draw((a,0)--(b,0)); labelx("$a$",a); labelx("$b$",b); } asymptote-2.37/examples/magnetic.asy000066400000000000000000000007371265434602500176330ustar00rootroot00000000000000import graph3; import contour3; size(200,0); currentprojection=orthographic((6,8,2),up=Y); real a(real z) {return (z < 6) ? 1 : exp((abs(z)-6)/4);} real b(real z) {return 1/a(z);} real B(real z) {return 1-0.5cos(pi*z/10);} real f(real x, real y, real z) {return 0.5B(z)*(a(z)*x^2+b(z)*y^2)-1;} draw(surface(contour3(f,(-2,-2,-10),(2,2,10),10)),blue+opacity(0.75), render(merge=true)); xaxis3(Label("$x$",1),red); yaxis3(Label("$y$",1),red); zaxis3(Label("$z$",1),red); asymptote-2.37/examples/markregular.asy000066400000000000000000000015011265434602500203460ustar00rootroot00000000000000import graph; size(10cm,0); real xmin=-4,xmax=4; real ymin=-2,ymax=10; real f(real x) {return x^2;} marker cross=marker(scale(4)*rotate(45)*cross(4), markuniform(new pair(real t) {return Scale((t,f(t)));}, xmin,xmax,round(2*(xmax-xmin))),1bp+red); draw(graph(f,xmin,xmax,n=400),linewidth(1bp),cross); ylimits(-2.5,10,Crop); xaxis(Label("$x$",position=EndPoint, align=NE),xmin=xmin,xmax=xmax, Ticks(scale(.7)*Label(align=E),NoZero,begin=false,beginlabel=false, end=false,endlabel=false,Step=1,step=.25, Size=1mm, size=.5mm,pTick=black,ptick=gray),Arrow); yaxis(Label("$y$",position=EndPoint, align=NE),ymin=ymin,ymax=ymax, Ticks(scale(.7)*Label(),NoZero,begin=false,beginlabel=false, end=false,endlabel=false,Step=1,step=.25,Size=1mm,size=.5mm, pTick=black,ptick=gray),Arrow); asymptote-2.37/examples/mergeExample.asy000066400000000000000000000036361265434602500204600ustar00rootroot00000000000000size(16cm); import bezulate; pen edgepen=linewidth(1)+blue; pen dotpen=deepgreen; pen labelpen=fontsize(8pt); path outer = (0.5,5){E}..(5,-1){S}..{W}(4,-4)..{W}(2.5,-1.5){W}..(-0.3,-2.5){W}..(-3,0)..cycle; outer = subdivide(outer); path[] p = {outer,shift(-0.5,1.0)*rotate(-22)*scale(1.5,2.4)*subdivide(unitcircle),shift(2.3,0.3)*scale(0.7)*unitcircle}; // a filldraw(p,lightgrey+evenodd); real w = 1.1*(max(p).x-min(p).x); // b p = shift(w)*p; draw(p); path l = point(p[1],2)--point(p[0],4); draw(l,red); for(int i = 0; i < p.length; ++i) { real[][] ts = intersections(l,p[i]); for(real[] t:ts) dot(point(l,t[0])); } path l2 = point(l,intersections(l,p[0])[0][0])--point(l,intersections(l,p[2])[1][0]); real to = intersections(l,p[0])[0][1]; real ti = intersections(l,p[2])[1][1]; draw(l2,edgepen); label("$A$",point(l2,1),2E,labelpen); label("$B$",point(l2,0),1.5E,labelpen); // c p = shift(w)*p; l2 = shift(w)*l2; draw(p); real timeoffset=2; path t1=subpath(p[0],to,to+timeoffset); t1=t1--point(p[2],ti)--cycle; fill(t1,lightgrey); draw(point(p[2],ti)--point(p[0],to+4),red); dot(Label("$A$",labelpen),point(p[2],ti),2E,dotpen); dot(Label("$B$",labelpen),point(p[0],to),1.5E,dotpen); dot(Label("$C$",labelpen),point(p[0],to+timeoffset),1.5S,dotpen); draw(t1,edgepen); dot(point(p[0],to+4)); draw(shift(-0.5,-0.5)*subpath(p[0],to+4,to+timeoffset+0.5),Arrow(4)); // d p = shift(w)*p; p[0] = subpath(p[0],to+timeoffset,to+length(p[0]))--uncycle(p[2],ti)--cycle; p.delete(2); draw(p); // e p = shift(w)*p; path q=point(p[1],0)--subpath(p[0],15.4,16)--cycle; p[0] = subpath(p[0],16,15.4+length(p[0]))--uncycle(p[1],0)--cycle; p.delete(1); filldraw(p,lightgrey); // f p = shift(w)*p; filldraw(bezulate(p),lightgrey); filldraw(shift(3w)*t1,lightgrey); filldraw(shift(w)*q,lightgrey); real x = min(p).x - 4.5w; string l = "abcdef"; for(int i = 0; i < 6; ++i) { label("("+substr(l,i,1)+")",(x,min(p).y),3S,fontsize(10pt)); x += w; } asymptote-2.37/examples/mosaic.asy000066400000000000000000000122121265434602500173060ustar00rootroot00000000000000// Calendar example contributed by Jens Schwaiger // transformations path similarpath(pair a, pair b, path p) { // transform p into a path starting at a and ending at b pair first; pair last; path p_; first=point(p,0); last=point(p,length(p)); p_=shift(-first)*p; p_=rotate(degrees(b-a))*p_; p_=scale(abs(b-a)/abs(last-first))*p_; p_=shift(a)*p_; return p_; } path c_line(path p) { // returns the path obtained by adding to p a copy rotated // around the endpoint of p by 180 degrees // works only if the initial point and the endpoint of p are different // a c_line is symetric with respect to the center of // the straight line between its endpoints // return p..rotate(180,point(p,length(p)))*reverse(p); } path tounitcircle(path p, int n=300) { // the transformation pair x --> x/sqrt(1+abs(x)^2) // is a bijection from the plane to the open unitdisk real l=arclength(p); path ghlp; for(int i=0; i <= n; ++i) { real at=arctime(p,l/n*i); pair phlp=point(p,at); real trhlp=1/(1+abs(phlp)^2)^(1/2); ghlp=ghlp--trhlp*phlp; } if(cyclic(p)) {ghlp=ghlp--cycle;} return ghlp; } void centershade(picture pic=currentpicture, path p, pen in, pen out, pen drawpen=currentpen) { pair center=0.5(max(p)+min(p)); real radius=0.5abs(max(p)-min(p)); radialshade(pic,p,in,center,0,out,center,radius); draw(pic,p,drawpen); } pair zentrum(path p) {return 0.5(min(p)+max(p));} //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% real scalefactor=19/13; // For output: height=scalefactor*width real outputwidth=13cm; picture kalender;// at first we produce a calendar for february 2006 texpreamble("\usepackage[latin1]{inputenc}"); size(outputwidth,0); real yc=0.5; pair diff=(-3.5,5*yc); pen farbe(int j) { pen hlp=0.8white; if(j % 7 == 6) {hlp=red+white;} return hlp;} // farbe=German word for color path kasten=yscale(yc)*unitsquare; // Kasten is a German word meaning something like box path Gkasten=shift((0,2*yc)+diff)*xscale(7)*yscale(2)*kasten; path tage[]= new path[7]; // Tag=day string wochentag[]={"MO","DI","MI","DO","FR","SA","SO"}; path[][] bx= new path[6][7]; string[][] entry= new string[6][7]; bool[][] holiday=new bool[6][7]; // Now the necessary information for February 2006 int start=2; int days=28; for(int i=0; i < entry.length; ++i) { for(int j=0; j < entry[0].length; ++j) { int day=i*7+j-start+1; entry[i][j]=(day > 0 && day <= days ? (string) day : ""); holiday[i][j]=false; } } for(int j=0; j < 7; ++j) { tage[j]=shift((j,yc)+diff)*kasten; filldraw(tage[j],farbe(j),black+2bp); label(wochentag[j],zentrum(tage[j]),Palatino()); for(int i=0; i < 6; ++i) {bx[i][j]=shift((j,-yc*i)+diff)*kasten; filldraw(bx[i][j],farbe(j),black+2bp); if(holiday[i][j]) {filldraw(bx[i][j],farbe(6),black+2bp);}; }; }; filldraw(Gkasten,0.3white,black+2bp); for(int j=0; j < 7; ++j) for(int i=0; i < 6 ; ++i) {label(entry[i][j],zentrum(bx[i][j]),Palatino());} label("\Huge Februar 2006",zentrum(Gkasten),Palatino()+white); // Zentrum=center; Februar=february add(kalender,currentpicture); erase(); // Now the mosaic is constructed pair a[]=new pair[4]; path p[]=new path[4]; path q[]=new path[4]; path kontur[]=new path[5]; picture temppic; a[1]=(0,0); a[2]=(1,0); a[3]=(0,1); // a triangle with abs(a[2]-a[1])=abs(a[3]-a[1] // and a right angle at a[1]; q[1]=(0,0){dir(-20)}::{dir(20)}(0.2,0){dir(-140)}..{dir(0)}(0.3,-0.2){dir(0)}.. {dir(140)}(0.4,0){dir(20)}..{dir(-20)}(1,0); q[2]=(0,0){dir(20)}..{dir(-20)}(0.8,0){dir(-140)}..{dir(0)}(0.9,-0.3){dir(0)}.. {dir(140)}(1,0); q[2]=c_line(q[2]); p[1]=similarpath(a[1],a[2],q[1]);// arbitrary path from a[1] to a[2] p[2]=similarpath(a[2],a[3],q[2]);// arbitrary c_line from a[2] to a[3] p[3]=rotate(90,a[1])*reverse(p[1]);// kontur[1]=p[1]..p[2]..p[3]..cycle;// first tile kontur[2]=rotate(90,a[1])*kontur[1];// second kontur[3]=rotate(180,a[1])*kontur[1];// third kontur[4]=rotate(270,a[1])*kontur[1];// fourth pair tri=2*(interp(a[2],a[3],0.5)-a[1]); pair trii=rotate(90)*tri; // translations of kontur[i], i=1,2,3,4, with respect to // j*tri+k*trii // fill the plane for(int j=-4; j < 4; ++j) for(int k=-4; k < 4; ++k) { transform tr=shift(j*tri+k*trii); for(int i=1; i < 5; ++i) { centershade(temppic,tr*kontur[i],(1-i/10)*white, (1-i/10)*chartreuse,black+2bp); } } // Now we produce the bijective images inside // a suitably scaled unitcircle for(int k=-1; k < 2; ++k) for(int l=-1; l < 2; ++l) { transform tr=shift(k*tri+l*trii); for(int i=1; i < 5; ++i) { centershade(temppic,scale(2.5)*tounitcircle(tr*kontur[i],380), (1-i/10)*white,(1-i/10)*orange,black+2bp); } } add(temppic); // We clip the picture to a suitable box pair piccenter=0.5*(temppic.min()+temppic.max()); pair picbox=temppic.max()-temppic.min(); real picwidth=picbox.x; transform trialtrans=shift(0,-1.5)*shift(piccenter)*yscale(scalefactor)* scale(0.25picwidth)*shift((-0.5,-0.5))*identity(); clip(trialtrans*unitsquare); // add the calendar at a suitable position add(kalender.fit(0.75*outputwidth),interp(point(S),point(N),1/13)); asymptote-2.37/examples/mosquito.asy000066400000000000000000000047201265434602500177200ustar00rootroot00000000000000size(9cm,10cm,IgnoreAspect); pair d=(1,0.25); real s=1.6d.x; real y=0.6; defaultpen(fontsize(8pt)); picture box(string s, pair z=(0,0)) { picture pic; draw(pic,box(-d/2,d/2)); label(pic,s,(0,0)); return shift(z)*pic; } label("Birds",(0,y)); picture removed=box("Removed ($R_B$)"); picture infectious=box("Infectious ($I_B$)",(0,-1.5)); picture susceptible=box("Susceptible ($S_B$)",(0,-3)); add(removed); add(infectious); add(susceptible); label("Mosquitoes",(s,y)); picture larval=box("Larval ($L_M$)",(s,0)); picture susceptibleM=box("Susceptible ($S_M$)",(s,-1)); picture exposed=box("Exposed ($E_M$)",(s,-2)); picture infectiousM=box("Infectious ($I_M$)",(s,-3)); add(larval); add(susceptibleM); add(exposed); add(infectiousM); path ls=point(larval,S)--point(susceptibleM,N); path se=point(susceptibleM,S)--point(exposed,N); path ei=point(exposed,S)--point(infectiousM,N); path si=point(susceptible,N)--point(infectious,S); draw(minipage("\flushright{recovery rate ($g$) \& death rate from virus ($\mu_V$)}",40pt),point(infectious,N)--point(removed,S),LeftSide,Arrow, PenMargin); draw(si,LeftSide,Arrow,PenMargin); draw(minipage("\flushright{maturation rate ($m$)}",50pt),ls,RightSide, Arrow,PenMargin); draw(minipage("\flushright{viral incubation rate ($k$)}",40pt),ei, RightSide,Arrow,PenMargin); path ise=point(infectious,E)--point(se,0.5); draw("$(ac)$",ise,LeftSide,dashed,Arrow,PenMargin); label(minipage("\flushleft{biting rate $\times$ transmission probability}",50pt),point(infectious,SE),dir(-60)+S); path isi=point(infectiousM,W)--point(si,2.0/3); draw("$(ab)$",isi,LeftSide,dashed,Arrow,PenMargin); draw(se,LeftSide,Arrow,PenMargin); real t=2.0; draw("$\beta_M$", point(susceptibleM,E){right}..tension t..{left}point(larval,E), 2*(S+SE),red,Arrow(Fill,0.5)); draw(minipage("\flushleft{birth rate ($\beta_M$)}",20pt), point(exposed,E){right}..tension t..{left}point(larval,E),2SW,red, Arrow(Fill,0.5)); draw("$\beta_M$", point(infectiousM,E){right}..tension t..{left}point(larval,E),2SW, red,Arrow(Fill,0.5)); path arrow=(0,0)--0.75cm*dir(35); draw(point(larval,NNE), Label(minipage("\flushleft{larval death rate ($\mu_L$)}",45pt),1), arrow,blue,Arrow); draw(point(susceptibleM,NNE), Label(minipage("\flushleft{adult death rate ($\mu_A$)}",20pt),1), arrow,N,blue,Arrow); draw(point(exposed,NNE),Label("$\mu_A$",1),arrow,blue,Arrow); draw(point(infectiousM,NNE),Label("$\mu_A$",1),arrow,blue,Arrow); asymptote-2.37/examples/near_earth.asy000066400000000000000000000030411265434602500201430ustar00rootroot00000000000000import three; import math; texpreamble("\usepackage{bm}"); size(300,0); pen thickp=linewidth(0.5mm); real radius=0.8, lambda=37, aux=60; currentprojection=perspective(4,1,2); // Planes pen bg=gray(0.9)+opacity(0.5); draw(surface((1.2,0,0)--(1.2,0,1.2)--(0,0,1.2)--(0,0,0)--cycle),bg); draw(surface((0,1.2,0)--(0,1.2,1.2)--(0,0,1.2)--(0,0,0)--cycle),bg); draw(surface((1.2,0,0)--(1.2,1.2,0)--(0,1.2,0)--(0,0,0)--cycle),bg); real r=1.5; pen p=rgb(0,0.7,0); draw(Label("$x$",1),O--r*X,p,Arrow3); draw(Label("$y$",1),O--r*Y,p,Arrow3); draw(Label("$z$",1),O--r*Z,p,Arrow3); label("$\rm O$",(0,0,0),W); // Point Q triple pQ=radius*dir(lambda,aux); draw(O--radius*dir(90,aux),dashed); label("$\rm Q$",pQ,N+3*W); draw("$\lambda$",arc(O,0.15pQ,0.15*Z),N+0.3E); // Particle triple m=pQ-(0.26,-0.4,0.28); real width=5; dot("$m$",m,SE,linewidth(width)); draw("$\bm{\rho}$",(0,0,0)--m,Arrow3,PenMargin3(0,width)); draw("$\bm{r}$",pQ--m,Arrow3,PenMargin3(0,width)); // Spherical octant real r=sqrt(pQ.x^2+pQ.y^2); draw(arc((0,0,pQ.z),(r,0,pQ.z),(0,r,pQ.z)),dashed); draw(arc(O,radius*Z,radius*dir(90,aux)),dashed); draw(arc(O,radius*Z,radius*X),thickp); draw(arc(O,radius*Z,radius*Y),thickp); draw(arc(O,radius*X,radius*Y),thickp); // Moving axes triple i=dir(90+lambda,aux); triple k=unit(pQ); triple j=cross(k,i); draw(Label("$x$",1),pQ--pQ+0.2*i,2W,red,Arrow3); draw(Label("$y$",1),pQ--pQ+0.32*j,red,Arrow3); draw(Label("$z$",1),pQ--pQ+0.26*k,red,Arrow3); draw("$\bm{R}$",O--pQ,Arrow3,PenMargin3); draw("$\omega\bm{K}$",arc(0.9Z,0.2,90,-120,90,160,CW),1.2N,Arrow3); asymptote-2.37/examples/odetest.asy000066400000000000000000000023431265434602500175060ustar00rootroot00000000000000import ode; write("integration test"); real f(real t, real x) {return cos(x);} write(integrate(1,f,0,10,0.1,dynamic=true,0.0002,0.0004,RK3BS,verbose=true)); write(); write("system integration test"); real[] f(real t, real[] x) {return new real[] {x[1],1.5*x[0]^2};} write(integrate(new real[] {4,-8},f,0,1,n=100,dynamic=true,tolmin=0.0002, tolmax=0.0004,RK3BS,verbose=false)); write(); write("simultaneous newton test"); real[] function(real[] x) { return new real[] {x[0]^2+x[1]^2-25,(x[0]-6)^2+x[1]^2-25}; } real[][] fJac(real[] x) { return new real[][] {{2*x[0],2*x[1]},{2*(x[0]-6),2*x[1]}}; } write(newton(function,fJac,new real[] {0,-1})); write(); write("BVP solver test"); write("Finding initial conditions that solve w''(t)=1.5*w(t), w(0)=4, w(1)=1"); real[] initial(real[] x) { return new real[] {4,x[0]}; } real[] discrepancy(real[] x) { real error=x[0]-1; write("Error: ",error); return new real[] {error}; } real[] w0=solveBVP(f,0,1,n=10,dynamic=true,tolmin=0.0002,tolmax=0.0004,RK3BS, initial,discrepancy,guess=new real[] {-30},iterations=10); write(w0); write(); write(integrate(w0,f,0,1,n=10,dynamic=true,tolmin=0.0002,tolmax=0.0004,RK3BS, verbose=false)); write(); asymptote-2.37/examples/oneoverx.asy000066400000000000000000000004651265434602500177070ustar00rootroot00000000000000import graph; size(200,IgnoreAspect); real f(real x) {return 1/x;}; bool3 branch(real x) { static int lastsign=0; if(x == 0) return false; int sign=sgn(x); bool b=lastsign == 0 || sign == lastsign; lastsign=sign; return b ? true : default; } draw(graph(f,-1,1,branch)); axes("$x$","$y$",red); asymptote-2.37/examples/orthocenter.asy000066400000000000000000000014241265434602500203720ustar00rootroot00000000000000import geometry; import math; size(7cm,0); real theta=degrees(asin(0.5/sqrt(7))); pair B=(0,sqrt(7)); pair A=B+2sqrt(3)*dir(270-theta); pair C=A+sqrt(21); pair O=0; pair Ap=extension(A,O,B,C); pair Bp=extension(B,O,C,A); pair Cp=extension(C,O,A,B); perpendicular(Ap,NE,Ap--O,blue); perpendicular(Bp,NE,Bp--C,blue); perpendicular(Cp,NE,Cp--O,blue); draw(A--B--C--cycle); currentpen=black; draw("1",A--O,-0.25*I*dir(A--O)); draw(O--Ap); draw("$\sqrt{7}$",B--O,LeftSide); draw(O--Bp); draw("4",C--O); draw(O--Cp); dot("$O$",O,dir(B--Bp,Cp--C),red); dot("$A$",A,dir(C--A,B--A),red); dot("$B$",B,NW,red); dot("$C$",C,dir(A--C,B--C),red); dot("$A'$",Ap,dir(A--Ap),red); dot("$B'$",Bp,dir(B--Bp),red); dot("$C'$",Cp,dir(C--Cp),red); label(graphic("piicon","width=2.5cm"),Ap,5ENE,red); asymptote-2.37/examples/p-orbital.asy000066400000000000000000000011661265434602500177320ustar00rootroot00000000000000import graph3; import palette; size(200); currentprojection=orthographic(6,8,2); viewportmargin=(1cm,0); real c0=0.1; real f(real r) {return r*(1-r/6)*exp(-r/3);} triple f(pair t) { real r=t.x; real phi=t.y; real f=f(r); real s=max(min(c0/f,1),-1); real R=r*sqrt(1-s^2); return (R*cos(phi),R*sin(phi),r*s); } bool cond(pair t) {return f(t.x) != 0;} real R=abs((20,20,20)); surface s=surface(f,(0,0),(R,2pi),100,8,Spline,cond); s.colors(palette(s.map(abs),Gradient(palegreen,heavyblue))); render render=render(compression=Low,merge=true); draw(s,render); draw(zscale3(-1)*s); axes3("$x$","$y$","$z$",Arrow3); asymptote-2.37/examples/parametricelevation.asy000066400000000000000000000003761265434602500221010ustar00rootroot00000000000000import graph3; import palette; size(200); currentprojection=orthographic(4,2,4); triple f(pair z) {return expi(z.x,z.y);} surface s=surface(f,(0,0),(pi,2pi),10,Spline); draw(s,mean(palette(s.map(zpart),BWRainbow())),black,nolight,render(merge=true)); asymptote-2.37/examples/parametricsurface.asy000066400000000000000000000006271265434602500215420ustar00rootroot00000000000000import graph3; size(200,0); currentprojection=orthographic(4,0,2); real R=2; real a=1.9; triple f(pair t) { return ((R+a*cos(t.y))*cos(t.x),(R+a*cos(t.y))*sin(t.x),a*sin(t.y)); } pen p=rgb(0.2,0.5,0.7); surface s=surface(f,(0,0),(2pi,2pi),8,8,Spline); // surface only //draw(s,lightgray); // mesh only // draw(s,nullpen,meshpen=p); // surface & mesh draw(s,lightgray,meshpen=p,render(merge=true)); asymptote-2.37/examples/partialsurface.asy000066400000000000000000000013071265434602500210430ustar00rootroot00000000000000import graph3; import palette; size(0,300); currentprojection=perspective(3,-2,2); real V(real r) {return r^4-r^2;} real V(pair pos) {return V(abs(pos));} real R=1/sqrt(2); real z=-0.2; bool active(pair pos) {return abs(pos) < R;} bool above(pair pos) {return V(pos) >= z;} pair a=(-1.5,-1); pair b=(0.5,1); real f=1.2; draw(plane(f*(b.x-a.x,0,z),(0,f*(b.y-a.y),z),(a.x,a.y,z)), lightgrey+opacity(0.5)); surface s=surface(V,a,b,40,Spline,active); draw(s,mean(palette(s.map(new real(triple v) { return above((v.x,v.y)) ? 1 : 0;}), new pen[] {lightblue,lightgreen})),black); xaxis3(Label("$\phi^\dagger\phi$",1),red,Arrow3); zaxis3(Label("$V(\phi^\dagger\phi)$",1),0,0.3,red,Arrow3); asymptote-2.37/examples/partitionExample.asy000066400000000000000000000020371265434602500213640ustar00rootroot00000000000000size(15cm); import bezulate; path[] p = texpath("$\sigma \Theta$"); pair m = min(p); pair M = max(p); real midy = 0.5(M.y+m.y); path[] alpha = p[0:2]; path[] theta = p[2:5]; filldraw(p,lightgrey,black); draw("{\tt partition}",(M.x+1mm,midy)--(M.x+5mm,midy),Arrow); draw((M.x+1mm,midy+1mm)--(M.x+5mm,midy+2mm),Arrow); draw((M.x+1mm,midy-1mm)--(M.x+5mm,midy-2mm),Arrow); filldraw(shift((M.x+8.5mm,midy+3.5mm))*alpha,lightgrey,black); filldraw(shift((M.x+5.5mm,0))*theta[0:2],lightgrey,black); filldraw(shift(M.x+5.5mm,midy-2.5mm)*theta[2:3],lightgrey,black); draw("{\tt merge}, {\tt bezulate}",(M.x+9mm,midy+3mm)--(M.x+15mm,midy+3mm),Arrow); draw("{\tt merge}, {\tt bezulate}",(M.x+9mm,midy)--(M.x+15mm,midy),Arrow); draw("{\tt bezulate}",(M.x+9mm,midy-2.5mm)--(M.x+15mm,midy-2.5mm),Arrow); filldraw(shift(M.x+16mm-min(alpha).x,midy+3.5mm)*bezulate(alpha),lightgrey,black); filldraw(shift(M.x+16mm-min(theta[0:2]).x,0)*bezulate(theta[0:2]),lightgrey,black); filldraw(shift(M.x+16mm-min(theta[0:2]).x,midy-2.5mm)*bezulate(theta[2:3]),lightgrey,black); asymptote-2.37/examples/pathintersectsurface.asy000066400000000000000000000006521265434602500222660ustar00rootroot00000000000000size(500); import graph3; currentprojection=perspective(-5,-4,2); path3 g=randompath3(10); draw(g,red+thin()); triple[][] P={ {(0,0,0),(1,0,0),(1,0,0),(2,0,0)}, {(0,4/3,0),(2/3,4/3,2),(4/3,4/3,2),(2,4/3,0)}, {(0,2/3,0),(2/3,2/3,0),(4/3,2/3,0),(2,2/3,0)}, {(0,2,0),(2/3,2,0),(4/3,2,0),(2,2,0)}}; surface s=surface(patch(P)); s.append(unitplane); draw(s,lightgray+opacity(0.9)); dot(intersectionpoints(g,s),blue); asymptote-2.37/examples/pdb.asy000066400000000000000000000064121265434602500166050ustar00rootroot00000000000000import three; import cpkcolors; // A sample Protein Data Bank file for this example is available from // http://ndbserver.rutgers.edu/ftp/NDB/coordinates/na-biol/100d.pdb1 currentlight=White; //currentlight=nolight; defaultrender.merge=true; // Fast low-quality rendering //defaultrender.merge=false; // Slow high-quality rendering bool pixel=false; // Set to true to draw dots as pixels. real width=10*linewidth(currentpen); size(200); currentprojection=perspective(30,30,15); pen chainpen=green; pen hetpen=purple; string filename="100d.pdb1"; //string filename=getstring("filename"); string prefix=stripextension(filename); file data=input(filename); pen color(string e) { e=replace(e," ",""); int n=length(e); if(n < 1) return currentpen; if(n > 1) e=substr(e,0,1)+downcase(substr(e,1,n-1)); int index=find(Element == e); if(index < 0) return currentpen; return rgb(Hexcolor[index]); } // ATOM string[] name,altLoc,resName,chainID,iCode,element,charge; int[] serial,resSeq; real[][] occupancy,tempFactor; bool newchain=true; struct bond { int i,j; void operator init(int i, int j) { this.i=i; this.j=j; } } bond[] bonds; struct atom { string name; triple v; void operator init(string name, triple v) { this.name=name; this.v=v; } } struct chain { int[] serial; atom[] a; } int[] serials; chain[] chains; atom[] atoms; while(true) { string line=data; if(eof(data)) break; string record=replace(substr(line,0,6)," ",""); if(record == "TER") {newchain=true; continue;} bool ATOM=record == "ATOM"; bool HETATOM=record == "HETATM"; int serial; atom a; if(ATOM || HETATOM) { serial=(int) substr(line,6,5); a.name=substr(line,76,2); a.v=((real) substr(line,30,8), (real) substr(line,38,8), (real) substr(line,46,8)); } if(ATOM) { if(newchain) { chains.push(new chain); newchain=false; } chain c=chains[chains.length-1]; c.serial.push(serial); c.a.push(a); continue; } if(HETATOM) { serials.push(serial); atoms.push(a); } if(record == "CONECT") { int k=0; int i=(int) substr(line,6,5); while(true) { string s=replace(substr(line,11+k,5)," ",""); if(s == "") break; k += 5; int j=(int) s; if(j <= i) continue; bonds.push(bond(i,j)); } } } write("Number of atomic chains: ",chains.length); int natoms; begingroup3("chained"); for(chain c : chains) { for(int i=0; i < c.a.length-1; ++i) draw(c.a[i].v--c.a[i+1].v,chainpen,currentlight); for(atom a : c.a) if(pixel) pixel(a.v,color(a.name),width); else dot(a.v,color(a.name),currentlight); natoms += c.a.length; } endgroup3(); write("Number of chained atoms: ",natoms); write("Number of hetero atoms: ",atoms.length); begingroup3("hetero"); for(atom h : atoms) if(pixel) pixel(h.v,color(h.name),width); else dot(h.v,color(h.name),currentlight); endgroup3(); write("Number of hetero bonds: ",bonds.length); begingroup3("bonds"); for(bond b : bonds) { triple v(int i) {return atoms[find(serials == i)].v;} draw(v(b.i)--v(b.j),hetpen,currentlight); } endgroup3(); string options; string viewfilename=prefix+".views"; if(!error(input(viewfilename,check=false))) options="3Dviews="+viewfilename; shipout(prefix,options=options); asymptote-2.37/examples/phase.asy000066400000000000000000000005511265434602500171360ustar00rootroot00000000000000import graph; size(8cm,6cm,IgnoreAspect); pair S0=(4,0.2); pair S1=(2,3); pair S8=(0.5,0); xaxis("$S$"); yaxis(Label("$I$",0.5)); draw(S0{curl 0}..tension 1.5..S1{W}..tension 1.5..{curl 0}S8,Arrow(Fill,0.4)); draw((S1.x,0)..S1,dashed); draw((0,S1.y)..S1,dotted); labelx("$\frac{\gamma}{\beta}$",S1.x); labelx("$S_\infty$",S8.x); labely("$I_{\max}$",S1.y); asymptote-2.37/examples/piicon.eps000066400000000000000000002426421265434602500173230ustar00rootroot00000000000000%!PS-Adobe-3.0 EPSF-3.0 %%BoundingBox: 0 0 147 144 %%HiResBoundingBox: 0.000000 0.000000 147.000000 144.000000 %......................................... %%Creator: AFPL Ghostscript 814 (epswrite) %%CreationDate: 2005/05/07 23:32:22 %%DocumentData: Clean7Bit %%LanguageLevel: 2 %%EndComments %%BeginProlog % This copyright applies to everything between here and the %%EndProlog: % Copyright (C) 2004 artofcode LLC, Benicia, CA. All rights reserved. %%BeginResource: procset GS_epswrite_2_0_1001 /GS_epswrite_2_0_1001 80 dict dup begin /PageSize 2 array def/setpagesize{ PageSize aload pop 3 index eq exch 4 index eq and{ pop pop pop}{ PageSize dup 1 5 -1 roll put 0 4 -1 roll put dup null eq {false} {dup where} ifelse{ exch get exec} { pop/setpagedevice where { pop 1 dict dup /PageSize PageSize put setpagedevice} { /setpage where{ pop PageSize aload pop pageparams 3 {exch pop} repeat setpage}if}ifelse}ifelse}ifelse} bind def /!{bind def}bind def/#{load def}!/N/counttomark # /rG{3{3 -1 roll 255 div}repeat setrgbcolor}!/G{255 div setgray}!/K{0 G}! /r6{dup 3 -1 roll rG}!/r5{dup 3 1 roll rG}!/r3{dup rG}! /w/setlinewidth #/J/setlinecap # /j/setlinejoin #/M/setmiterlimit #/d/setdash #/i/setflat # /m/moveto #/l/lineto #/c/rcurveto # /p{N 2 idiv{N -2 roll rlineto}repeat}! /P{N 0 gt{N -2 roll moveto p}if}! /h{p closepath}!/H{P closepath}! /lx{0 rlineto}!/ly{0 exch rlineto}!/v{0 0 6 2 roll c}!/y{2 copy c}! /re{4 -2 roll m exch dup lx exch ly neg lx h}! /^{3 index neg 3 index neg}! /f{P fill}!/f*{P eofill}!/s{H stroke}!/S{P stroke}! /q/gsave #/Q/grestore #/rf{re fill}! /Y{P clip newpath}!/Y*{P eoclip newpath}!/rY{re Y}! /|={pop exch 4 1 roll 1 array astore cvx 3 array astore cvx exch 1 index def exec}! /|{exch string readstring |=}! /+{dup type/nametype eq{2 index 7 add -3 bitshift 2 index mul}if}! /@/currentfile #/${+ @ |}! /B{{2 copy string{readstring pop}aload pop 4 array astore cvx 3 1 roll}repeat pop pop true}! /Ix{[1 0 0 1 11 -2 roll exch neg exch neg]exch}! /,{true exch Ix imagemask}!/If{false exch Ix imagemask}!/I{exch Ix image}! /Ic{exch Ix false 3 colorimage}! /F{/Columns counttomark 3 add -2 roll/Rows exch/K -1/BlackIs1 true>> /CCITTFaxDecode filter}!/FX{<Y#U0HO],N3WK,= aI!gMUk8XHs8;cjs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!rr2oss8Vfco#@%As6tC0iGZDf&oh%mnF5uJs8W)trr<#u s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! rr2oss8VNUn6AL!Wd>3;]fH,mNQ@M*[&/KUs8W#oqZ$Tqs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8N#ss8W,mo^^"g,QI7\ pYfu%M\9r3)=[.cs8W,urr2rts8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8N#ss8W,en*jRQ'rlTik.NeTs,G-g)7QPss8W,sr;-Hns8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W)trr<#up@\!rR3_h&IJ;Z3]S[5<=;p\unc/Xhrr2oss8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W)trr<#umdKXM8/8.O%Hb>a s8S)$RMiW6KE(uOr;?Eks8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,urr)lss7,UF`0_bKnUC5hB"Ea,CfVJCnF?PYs8N#s s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W,urr2rts6f@F>Y#U0HO],N3WK,=c(,`_W.Y-Ms8;fks8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!r;6?js8T$jM6ML5 s7h3;]fH,mNm4+4\Z1;^s8W#pqZ$Tq s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8;cjs8W+uSV"1u"981Qp"EibL(8$")Xm1cs8W,urr2rts8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8N#ss8W,en*jRQ'rlWj k.t>qnc/Xh rr2oss8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W)trr<#un*faK8/8+O%Hb;`s8S5+Sf5/>KE(uOr;?Eks8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,sqtg?ms0/;O \:Y"cq2+[p?FGLsAPsH7n+$GXs8N#ss8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,urr2rts6oFG=\9F.HO],L3WK,Ac(5iaWe:?Os8;fk s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!r;6?js8T@"K=HXAs8.]Fe6]J7%:`6Rn*ffHs8W)trr<#us8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!rr2oss8VQVn5r3r WI,0;]K-#lOj0I9\>k2]s8W#pqZ$Tqs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8;cjs8W,+Vh;O:#ljd[o$gmNK+2?f)Xm.b s8W,urr2rts8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8N#ss8W,emdO4H'rlWjk.pq q"OL^s8W)ts8N#qrVZNkrr2rts8W-!s8W)us8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W)trr<#u mdBRE7hr%O%Hb5^s8S5,Sf58BKE(uOr;?Eks8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,sr;-Hns1PLg^lAj'rfH^!;71rb >"KOtmdL2Us8N#ss8W-!s8W-!s8W-!s8N#srr2rts8Doos8W,pq"XIOnc&Oes8W,urr2lpr;Q]p s8W,urr2rts8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8N#ss8W,urr2inqu?]r e^;=:O@[*C#j/r`gUJuhW@c,U+j$NXcF8GTb-h9Ls8N#srr2oqrVQTnrVuots8W-!s8N&us8W-! s8W-!s8W-!s8W-!s8W,urr2rts6f=EmI'HCs8W)trr2orrVc`prr2orrr2orrr2opr;-Hns5;SM W/jN?H6LM?I,NShp\=X`r;?QnrVlfprr2orrr2orrr2orrr2orrr2orrr2orrr2orrr2orrr2or rr2orrr2orrr)fpr;?Hks8UBc[W>CRY'^QLb=)C-KDtn7rr%fUomcYi?/2nBaI!gkX&RWbP4J,- s8W,urr2loqYpKmrr2orrr2orrr2orrr2orrr2orrr2orrVc]ps8VKSmo2alWI#*9]/fokOj0I9 ]W6\bs8Vunq>UBmrr2orrr2orrr2orrr2orrr2orrr2orrr2orrr2orrr2orrr2orrr2orrr2or s8W,urr2rts8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W)trr<#u rr2orrr2inrV?9dqYL-dqY^3dr:p$\s8W,1WeAaR)!L5Os8N&oq>:*frVuot rr2oss8W)trr)fns8W,Ncb"mA$aYEkeY+,8TbP\<)Ph]tfZpl(s8W)trVlfqs8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,urr2rtrr2rtLO3$79*'r`'<[$.e"nGHX=E,2/a^D> q:]3Unp:<7PQ1T?p#0?8ZR+s8W,sr;-Hns8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8N#ss8W,urr2cjr;6Birr2oss8W)trr<#us8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8N#ss8W,urr2flrVHBgrr2oss8W)trr<#us8W-!s8W#pqZ$Tq]W?k*NXYscORCCk YCI*d7i:X]nGiOgs8W,oq"O=Kn+-&>o()>@nF-)FqqTW1F&`O)B+)>2*oQ]# ]:W6to_%SAoC;ABnaZ2?nac5?oC;ABnaZ5@nal;@oC;ABnF,oBq>SUV[:)N- E`Wm0AdOT:%\n=^UNmEJHk3Z@'ul@Sd@MH?ZS;$t;#^!3s8S>]np'3-0ufP*`3P'Zl1=B4p[RbB nF,u#[dc<9`P/i 82VZWE!3_/);D2CpYTEZs-!?MHJ>GCT6M/$,>naPEs`7b#RP/M$"jPNBF5)]$41MT$#U%VE!Zki #mtVY$?-=ZE!cqk$Oh%[#@R`=@fusG1FPUr6kW`o&5"nk<'Lt1:C2GR!0qL-Xah(uN#0m5*p^L# r9//#s-NQGDq:a!LLVnJ&pY'(KbG/G&JKL('71?*HP.!?&efa-'7LQ.Ih<5Bo"'A6.,q?__0!QoXZ8FPT 5=!CS4ioiOaZr275XELY7*J"ec::CNA5uNZ@L&o^&BBqNkIWSLoRQu[?&i?J/OffN__@ =&uD3>)6Tc;dr?&Kk(@ZGSIQ>(!rBfm__3foR[#APk)s^TlguM;P@/qpKq:g?XN#)?ftg(k[7c^ ?si/+?g1s*l!n2h@:AM1@-h9.l=")e@:8A.?g(m)l!Rl_?si/+?g1s*kZqKW?!c`$?fta%jBc-Q >@$>q?0,6oi)a%=BA5a&-)Hc m`JD/IfNnVGuI`/='!jO)Gm4It"9`rM"*aeIGQ7eh!!%'?!H8#?E<#uW !!$s"aC(OJcl3V *uZ5(6j\lj(9`B-c^GgHdo$/FQi,]C]8-h:(et&2C]OQF!!$L/!+Q!/@fQL=!!$L/!+#X*?N:(; !!$U2!+Gp.?iU1:!!$L/!+Z'0@fQLB!!$j9!,MW8C]FHO!!$g8!,MW8CB+?M!!$m:!,qo@->9-`I7RIK0@a!!$L/!*K:%9E5&V!!#1a!B^>^4?tPDfqoeipPA4X9X'0_82q"X!&O]V3<0%= !!"tY!&srY2ZNhN!!#Oi!'pSb8cSic!!#Uk!&srY2#mV=m$qL@!63%!O!!"YP!%n6O/cYl( !!"VO!&"

    c#!!"DI!%%[G0`V2(!!!*B&ccfF#H!"had!_:bt7s7PPsBC]8I7J*BFZBs8W)ts8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!rr2oss8W)trqu]m rVc]fp%LmEOT>N<@V"b>C[`c&XT8NN!!$j:!au'/57%WU"pQeO7UM"/SUGpLJ:E`3Jsq7/:=#@E s7qH=Da]!2b5a a,q/2b";X5QMB08["Ah-^T@>2s6oCCnaZ/@oCV;3lCaJn`N+"5[QaEQHIT6#cH!Njq"jLKn*f`6 qYL&u\@Qj,H@^X$It**#ItN6#K7AB(It*-$ItrN'LOXf/JUrc+HA<"A2uiqQ!!$dP)OG/PnLH,\ jlPe-s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W)trr<#urVc`lqY^Bns08iO"U/fr0=5tKr('E(#RQ4c!,;Q:@K6Bm!!"3,5$#M9`:s#u p@e.Ys8W)trqu]js8W,5Y(afT%KH?]m`A,)J.GXK([UPXs8W,urr2oqr;Zfskhj>,T,7P%HN3V^ jKB\[?N?adJH,ZLr;6Bjrr2orrr<#up\F`3C.FJ%"Q6L7s88&Oem,J3&Du0[s8W,trVZ]qs8W-! s8W-!s8W&qqZ$Tq`jh8JL]mbHEW>ZZhk_-FC)ld6o)Jairr2oss8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W)trr<#uq"aeq>YA-]!2k>daHRP9cqOK>QhAd'X*bE-d(o\]s8;fls8W,dmdX4=%B+CL l+f=Zs,kEi&@A3Ys8W,sqtg?ms8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W)trqcKf s8W+EH$fSl-3OH]!WmaU?f'm`qYU'^pAb0m\u^P&Nt)-eL[N8WY^d6b72G(Mm/R+c q"XX`s8VWYm\kRKnBao0qiTmA0Vit)@8.^)l0SHMs7uKdqYL'bqYKs\p](9n]=b^g:CY.#')(@" s7VAhOq0saqYL'bq>'jcrr;6Jl\K6lgSu_&r/U3h9:Tl#Wh>+Hs8VlgpA4X^ qYL'bqYL'bqYL'bqYL'bqYL'bqYL'bqYL'bqYL$`q>UBlq"jkt>YA9c!3(MgcBfFDd8L#ERHqjU a.Pp"r;QZnqu?]rmdKUO9GsmY&EUSds8S)"R2`N2L&_2Qqtp3frVlfqrqu]lq>'m`qYL'bqYL'b qYL'bqYL'bqYL'bqYL'bqYKs\q#CBo\@B$K!%%^H=9&>@7S(Z_43`/$\,ZL.s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W)trr<#urVc]nrVl`mqaa86 "9a9`@-D68lkUJ-!!$d;"ChH54:)a8p!$4PP8\L?!0rXrs8W,rqtg<70!:TjgR(-CDZI/n,NFfrr2orrr2orrqu]ks8W,#TnT@e!;kY` s7_6"V&tA$(?t)Js8W,urr)lss8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!rr2oss8W&rrVlfp q"jl#?V4iu!N^klc^>[GfNA1RRd7jLcDX_tPm4HO],N3WK,=aI*pPVM"pKs8;cj s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!rr2orrr2rts7#OH%1Off!)3FnD)OAd :/9V78(1CsSLg P&(Lo2>mJm4drr2lqrr2rts8W-!rr2orrr2rts6T+;N,'6\U`]X5NUkIsW-Jfub.RcSs8Doo rr2orrr2rts6Aq;L1_O^W?_H@MY,G"XaC;%E(Kp*s8W,urr2orrr2rts8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!rr2oss8W&rrVc]nqtp:r3;]fH,mNQIS+[]"iYs8W#pqZ$Tqs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8N#s rVc]ps8VHPl3n(H!!#[m!,aeY^JRqd%M3:BnF-DWs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W)trr<#urVc]nrVl`mr'Ec3&JLRYHMp?*c3"5t!!$[4!)^Kp \>b1oM@BO^J*tTSZ@NNi8J^[[mem(aZB.H3ZRPqSRIA!Z^Ps+;5lch"J,fQKqYL'gs8W)trr<#u s8W-!s8W-!s8N#sr;?Eks8T3pJ"^f]o\!IKqN0:(+FIZ@mdTfIs8W&rrVuotlg*qmBcZ!.,QI\" o[['HIKkXP9)JSes8Murrr2orrr<#us8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! rr2oss8Vunqu?]r['[1f)Zk7f%BP0ueY+&]iFr8kSEIXB]9u/m8K+XW%Hb5]s8S5+Sf52>KE(uO qtp3grr2orrr2orrr2orrr2orrr2orrr2orrr2orrr)fpqYL*bq>:$bqu?]rZEgh;!'1)[A.9'/ DJo"\(RobuV>pSqs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W)trr<#u rVc]nrVl`mqa3c9+'paqY^3dr;Q]ps8W,sqtg?ms0nq^\:k4gpNH,Q9=9?^>Y#S&qZ"L?L;o;Zs87ZNk%iJ;)hqf* Cgfj1qu-Qps82]kqtp:$br:]jYs8W+dP_Xos!:%?^s8SJL]fVd0([UMR rVccjp\4^fs/DZGTPso+g0agQM:ngTHs$Zj^:4.Bs7lBbqYL*cqYU-cqtg0dqYL*cqYU-cr;HTn s8W-!s8W-!s8DoqqYL*cqYU-cqtg0dqYL*cqY^'\p](9nYHP2T)$"h_$a,1!eY+&\i+E#hRcqUL Tlpp:FV3lN2#mT7e"RhqXb6ZRs8;fks8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8N#s rVc`qs8TF3]*&6j!!$4'!I%./cXg\T!kIE=etXXcGSa(7#.(\Cs8W,dmI'cEq#CBorr2oqrVl`mrVuotrr2oss8W)trr<#u o()=,Bc#3g)?9Ggr7u%^Er`D@N;rqXs8W,Vf5S3ns8W,rqtpEns82]kr;?Nns8W-!s7Z0\qYL)u\&`T1S:5phF*"8h%UfMF@gWNR !<[3m,<*T+'*%0%o#aD2L^um0.f]QS#R+E>$>9_M@0H[;!!$:,"'uHICBk)U!X))^Q;*HGFN=PX@C]F!]aHI'dE`m^:[!-\f75Ql37kf=2@s`K= D,NGY.4.ndF+].PH$Q65H_l(9V0mWdI!_];I&24X`\mb-7>_l!,i#EA,lT[8kN4_qtg9irqu]lqtp?ir;HZqs8)TgkND5iMmGQ1L&_9h #mteT!-\VPM\d8)0JU'r35.F9_Dsd"7Rau!MBr5R8b0k_Z%O,m:OmV03;(/92j[[4!K*-n2;L/@$iZYV.Z:0f$9p1V#G(^,\9k4?peP7*.qicV73d >[?Au@d%B6l"Ol"AS1?i42D%'HiX7K[C"0Xs8W#prVuots8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8N#srr2oqrVl`mqEdN.)&]&jGlB*@XT/?="U/B9!%1B2:*frVlfq s8W,6^="r!Jcl6u"p]i--`p-=eR;qOCM`KZEV='[mo39=:/BA4:!lR,e4E6LY(@_e`&I(t0s6*O 5XNFW7En1gb!eeC7nLlo8]jRqb=bLR92l!\/h@qG%>B'a)?l==Mk AnUIBB'j)=l=+8j?=)h_3C%[f!3(Dbb*i8[dhH3k8 ;cMLK;UnQ>eOiQ`7nLom7`mq]`B$)p2)Vfs19_fDTEPLL!!$70#Z7t9`rH)=qYL*hs8W)trr<#u s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,urr2rts7uKfs8W+FHDUlNKm7nC2)`#G!-&/G@fQKY 8kN.^r;-?hrVHBfrr2oss8KaHe2]RF!!%'c-)t-PiG`c.@V+k!:!kaT\/l``',?T;%>P,lI0'Ot !!.$=!,VlBB:sJejKC,lX=LE*'I"Dq!!%*A!Gqf:E<#uT!!$d7!,DQ7C]FHN!<[aT?fj+"ZiC). <)e!38Uq'QM/-qt+8'Lr-'DbX$W ;,Z![(RZ$4;Ci#_E6dI0Bh$"U02R!d4PDC]FHO!!$d7!,)?4@fQL>!!$"#!_WLn92/-# p%A%WrVcZlrVuotrr2orrr2rts8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8N#ss8W,sr;HZqs0oJ` $4MJuB^J;]c2[ig!s2s4!%gf8=oA3pqtplXk"!!#1_!&srY0*__J%hDVJ$V>VH&&XSR_iu@EIh,OD)Z]q)&.Co/"#^Pr8Ic5) %Ll,D%o<6+<#m!KCi/eZ(7,"$7!!F"*?ArB-EC`km03fF!!$%"!'pSb4ok[M!!#P=*?qY;%HbAf s641OW?m+%'*!!$1&!([(i7fWNZ!!#Oi!([(i8,rW\!!#Oi!(R"h8,rW^!!#pt!+,^+>Q=bE ?j-9)nrK&.h>8"YN;8@Yor2It*B"G'pg0])):"nF?1*E^u4'!j74s P&D(04:H+,%VJ<4@9cLsoCVPAnFcJHhr!Ds"_'AK]O"t+!!%3U&m@Re?iU17:J]G6:X]:DD?pJ0 H$P3tJsUt:PCS4TJUN3(A.cqK)W%PCbF9W?EY18]&N_TqI!_'.JXV+=Q[jUTJ:O/?J=M.?S:H-[ J:O/=I[Z+MVFX3h!!"/B!)a::MIpMf)]YIi*+a24GlRh2&.st7BC$`aUBh-+I!h93JY%CARt-$Z J:O,>J=(k;R"0^SJ:O&X8?o8fE&'Lk1,?It*N/Iuf)/Mgp58 It*?,JVnVoHapSsqYL*Xn*ff:naZ/>naZ,NnMN8:#mu@d!,V]9=onag"9^YP7:)"8QKdYunaZ)Bp\+Xes8N#s s8W-!s8W#pr;Zfs^V76J3"8A6!\PMo(C^@@3rs,.;"jY[s8W,pq>:3ls+cB*!!$D2?/n:@a8c3N ,U?'&E0^J(Eb&eJ1H)]B!*MlbDZBb8rr2rsrr2rtrr<#uIr7c?C'D/+)m4f.M/!bj/-)oKJcGcM r;6Bjrr2rts8W-!s8W-!s8W-!s8W-!rr2ooqu$Kos*fE]!!#S:-`Cj!o)JcB=BLQ5J'dbs8W)trr<#ur;?Nhq>0saqYBs`r;?Klrr2lprVc]nkj%MlM1pY:ItWAr]=YQNrr;ooqu-Kl qYL-is8R4aUAt:BD/Sqi,c1PA=?SfP&eS7\(78rUnJN75!!#97J;XC,s7Q'YqYL*`p\=dgs2Dme :cel1>RZ'pfs8>M\FoVMJ 5XE@q?KD.eATMpQ.4J!l!*qE=[q0.;!!$PYI[gB;s7Q'ZqYL*cqYU-cqtg0dqYL*cqYU-cqtg0d qYL*cqYU*aqY^9hs8W,urr2rts8N#sqYL*cqYL'bqYL'bqYL'bqYL'bqYL'bq>'mbr;?Qnrr)fp rr2orrr2orrr)fprr2oss8W)trr<#us8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W,urr2orrr)fpr;?FU5E%]ga(8iI"p]\[!Fu014%i4Ms8W,ko^mQZV[Eod<`\*kC@<#YRfEG, !:3ls*/dh',-[UGPiI'TE"t,!!#\(&1Hl1li7"b 7Rht0!,l7QkZqNT#RZ=e!,;W>6"XM['[4?s8PDPK`hR1C2<9@=l'AgK)bmb!Wl.""!OtU\,ZL.rVc]kqYU6irVuot s8W,urr2rts8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8N#s qYL-is8R:eQiI,'B5-fe0s^i[?R[EuCi#=9!-W$iln:&r!!#c>H'\L1s82]krr2oss8W)trr2or s8W,sr;?Qnrr<#urr2opr;?Tps8N#srr2oss8W-!s8W-!s8W-!s8W-!s8N#srr2rts85>UC]FH> 3BOo`A*EsnD-:"rIt)tK!'Lf%NFZVe+XXdXmf3=erVc`qs8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! rr2orrr2lprqu]l56"X$77E"<#_d28oM/33!sO2V!GVT78HT&8 ['[7@s8VrlqYgBks8W-!s8W)trr<#us8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W)trr<#uoCMMa&R67qSn`*4',?Z1!(:sPJg2LZ()`QVD=S>TOoPJM L5)#os8Vrlqu?]rs8W-!s8W)trr<#us8W,trVcZlr;Q]prr2oss8W)trr<#us8W-!s8W-!s8W-! s8W-!s8W)trr<#unaZ#W%7L6sFB;W#84h,-!)B#QYEkKQ!!#A-+.[7co*,MX6:,qss8Drrs8N#s s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W)trr<#uq>'pfs8R=gWtQ59G''mdrr2rts8N#ss8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!rr2orrr2rts6Ak9"pSd(5/g]/hZ*Y! #R=(EEe+;p@lZTb>?p.f!-ASV;![H5s8W,trVlfqrr<#us8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!rr2opr;?Tps0oJO!!#b#$]/J.lm!dQ"U/6#mHR>;CB+?6 /M=/CD=RZ,EIWJ:s8W,qqYU8S7nNK1V !!%!>!F#O(+iVF:]tN&#"aXZgl;:I0!!+9,>j?c8T!!$OE'h@lenGiOgrr2oss8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!qYL'gs8RV"NrT/L -7>X*D=Io>MA6k-jQ,).&NKgkB0&/h?!ZCh!*al"PlLd`qYL*grr2rts8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8N#s rr2oqrVl`mr'*E*5![1t@d4+$J-#d_!!"oe@r&lqeGoSc:/KMN@d"%&K`V^Kp qtp9js8W)trr2ors8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W)trr2oss8W*c6@B:PNc8n.)B>4H!).`dOB,D>!!%RcC@3GuW;lok H?teTs8Vrlqu6Tos8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W)trr2oss8W$h8T4Y0=ueXT@:JI$!+pV+U&Y/l$O]Q,!,YS1e4E<\!!$<8\\nIIs8;fm s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W,urr2rts7uKgs8W+DGcDDkQ[!`O*$1[O!,2E58KAg)X/j)=!c:Csb\V1g &/1-*!,MW88J)O]mHs<@s8W#pr;Zfss8W,urr2rts8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!rr2orrr2rts6An8"pS"Y[f?C-qtp9js8W)trr<#us8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8N#s qYL*hs8Rh-V>pU+?!lYW6,N[&AJl=SUSFpk!,"J]aAuC"!!$sH$V]mPlMpnarVc`prr2rts8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8N#srVc`qs8VENljXA( !!.LXAEbd'[/pGGK:%7Z>s8W,trVliss8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W)trr2or rVc`nr;8`CO$5hLAS(-2#D)sWA,lTj:/4ti;Oo0aZ#OgZ*?C^O!,_i>6PgW,BPQuN(RYC/9)nqkL5)6!!(IqLSSN*5"pp,Q6?rP1rVlfr rr2oss8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!rr2orrr2lprr<#t6puhO*MR\!q]-`K!!$a6!(SUm3coJ:$4Mi6FS[I;WrN-: !s;^0"=pjd\c;^0qYL'gs8W)trr2ors8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!rr2orrr2rts6An7"U8-c1V."(k6D9E !!#6@MNV(DP6(i.!-/)@?iU0UZEgq=s8VrlqZ$Tqrr2orrr2rts8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8N#s qYL*hs8Rh-UAt:'>[HJX7)o9-BFthChVQrp$sb5-WbH28#mu=c!)0r6_#OH7r;?Kms8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!rr2oss8VWZmM$@( !!$Xu7)i;1huEa[K7fcqs83001&q;c3B=i]?fqCh?%%*ds8W,qqYU9krr<#us8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W)trr<#u r;?CW6'=l6do]f2!!@ZO!Fu01/Pf/G8P5-s0",P2mg9DV!Q=a'r;?Klrr2orrr2or s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W)trr2oss8W*c6@/nBMJ[8'+!R?X!)ZZnE4rs,!!$Iu8^(%1f)Peh %Ltqtna?GWs8N#srr2oss8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8N#ss8W,hnaR%t:&k9:?!cJS5K3['>J%MgrVcU&%8$U#C.q@K9MNt9!+*4H`W,u< r;?Kms8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W,qqYU#RG,8oC`.`s8N#ss8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!qYL-is8R+\YX(V#;,YmD!-/&>pU+?=2bZ6cT0,BFk_Ahr!-'(0V4\O_\b'*$1UM!(DEgNrT.ZqYL'gs8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,qqYU_Z0Z9 IX[[b!(eIaVf$JK!!%=nI&R)Fs8)Ths8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,rqu-Qps0]8[$4DGn?fu0>nQK2Y @V"_;B^Zr^T)\k1!WlC)"!b1[[K$:,r;?Kms8W)trr<#us8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8N#s qYL-is8Re+W;lp4?t&+Z5/R@#BF>21qu#u3H`$iDD.RDK1,ZN@!*;``CB+>2rr2rsrr2rts8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!rr2opr;?Tps0oJO !!#b#$]/J.lm!dS"p\6#nac_[s$fIm!!$.W1:(\/mJm6$I!_Ufs8Vrlqu6Tos8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! rr2orrr2rts%?"D!!$[S+eh(]^,J*e&/($)!ce8@MfD\?A4*, s8W,qqYUhuEe% !!#R']u9[>q#^_,1GlUL@H@UpHiO.7[^N^Gs8W#pr;Q]ps8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W)trr2oss8W!g8T=_1?9:?c?t&*r!+^P-V#UJp mHsH'\L1s82]krr2oss8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8N#sr;?Kms8TX?^&S.,$42AuB'^imX9Ac4kND+0s8Rb*NrT/C$4DW!AEbNmXp,,7 o()AOs8W)trr<#us8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W)trr<#us8W,trVlZiqtg0dqYL*cqYL0hrVuot s8W,urr2rts8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!rr2opr;HZqs1#S]!!$P-;:eWAeGoSi !!#9r]YFLHrsTTOoPJML5)#os8Vrlqu?]rs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8)Tgs8W+LJ;XC-6QmYICM`PN%ZV&2<:B;D s8W+JIZOO05nk&uBP6ZJ)4:sE;tT_Ps8W,urr2rts8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W)trr2or rr2rts8PGRF9;YtDf,+o-`-kD?4ml4rr2c*]#F^M=$Agc>?g%d!-ASV;![H5s8W,trVlfqrr<#u s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,urr2cjr;Zfs I!hC`!)ba7\7]I?!!$e\HD1B=s8W-!J:O'g!(S1VT5SZA!!%OlFe\p9s8)Tirr2oss8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W&rrr<#um-F!C#[B,?\79+9#muFf!(2*[NW9%YH[D%Y!*ru>j?c8T !!$OE'h@lenGiOgrr2oss8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!rr2oss8VWZmh6@*!!$_'9$U@7g&M+PJ:Npbs8W-!s*B!Y!!#bF/Zs#1oDel2 I=8!ms8Vrlqu?]rs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!rr2ooqu$Kos*fEk!!$_A@H9[>`W-!Q %LteilKJ9Js$T8&!<[siC@3GtW;lokH?teTs8Vrlqu6Tos8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8N#ss8W,hnaR%t:]LK=?XMnX5/R@#=1GcU s8W,gnEgo(5QCdm1,HCLAa9$Bha!*4T!OoPI]qYL*hs8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W,urr2inr;Zfs\@BT[!+/;hcW+$&!!%0B!(jT+^An65[C*pQ!+J5]b#MKu !!%!I$UsCIkPtS^rVc]orr2rts8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W,qqYL6ls+#W[!!#G5-DYHpo*c%d&.hV+nF$>Vs7#OH%Lu&1!,>,!cV@6b !!$E;\\nIIs8;fms8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8N#srr2onqYUjR@8P+%(s8N#ss8N#ss8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8N#srr2rts8>M\D#aQ>2E/-WAa9#[K,>[qTXG #RcCf!Dp88^An65r;?Klrr2rts8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W,trVliss6T+>$kQYH#(UB%lSLK0#7G22m-juSrr<#uL51ij!'U`!M.^Me 1,QNH$Y8i!oDejjrr2oss8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8N#srr2oss8V]_ndc=:*ZgqpFSHjuSH&Xl 7n@CnrVHQos+Q9)!!$>.=PZqTfDknj%1ktuna?GWs8N#ss8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8N#sqYL*hs8Rb,PQ1\R+!@+mDtOteSI#[% o'u2Jrr<#us+#WZ!!#=s&s$dAm3sKd#74T)o()h\s8N#ss8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W)trqu]m s8W,/\]OmPBhM1I?'sgs8RV$PlLeS(DrBPC[iJgU(.f=o^q_Ss8W)trr<#u s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W,urr2cjr;ZfsGB]VY!-rR)oeSD2!!$[I),0;[kPtS^oCMPa'4)UuS8`NC *?L^N!(MKhMuWhWqYL'gs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W,urr2ors8W,t7nR_#!+J5\`+3B@!!$Y\J#32Fs7Q'[s8W+LJsZN<8KAkA DK,@U$B0+OVuQesqYL-hrr2rts8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8N#srr2oss8VENmLKqE/haPIDY+MSO8o8O H?tGJs8W)trp&b8"UJm%3PK'9lN@KH!!#Nt\%2P=s8;fmrr2oss8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!rr2oss8VWYljXIi!!%%=<7b)Kg&M+W K8-'!s8Vcbq#CBoJ:a6j!)+U_TlY;M!1-ks+#]k!!#e@.&V62q#CGIH[Vmns8Vrlr;Q]p s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!rr2orrr2ors8W-!6:?G9&!D-ZqB[Ja!!$+k88eJ-rr2oss8Vs`7!Sb6Jo5Gq 0f--9!)e)gRK*2i/M=:5$Y/buo`+skq>'mes8RV$S,`Oc .kIfFG5M=?I!gCBs8W,qqY^Bns8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!r;?Kms8TX?_Z0[=6q#.,AEF.*K)bm@ L51ums8W)ts75^L#mscY,c5U&o+i41!!#KCLmA#?s8)Ths8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,qqYL6ls+Z>j!!#A&)4"rOoGo$J #RXf+nac_[s7uKes8W+LJtE#C;(aQ*FERBZ!.0*BWW3"uqYL-is8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W)trqlTj s8W+CGb"g7F)>g`4?^=W!,2rU6KmXos8W-!s8TR<`W-!J6Uf+(?fM+eGmb'\lg!g9s8W&rrr2or s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8N#s qYL*hs8RS!PlLeV,:0+'EVC%YPRnL/oCVVRs8VojqZ$TqJ:aHp!)tU*Y]Y*b!!%@nI]^MBI"&'ps8Vrlr;Zfss8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8N#sr;?Nns8TU>bQ%WYoI;Dl!!#oCHBnO1s8)Thrr2oss8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,urr2cjr;ZfsH@24_!*;9H^hINN !!$e`JZ&PJs8)ThqYL*hs8RV$T)\jf/hjGMFnl";H[L:As8W,qqY^Bns8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,urr2orrr2os s8W*d7!o:IMK(?irB'eIt+0ls8Vrlqtg0ds8W+LJt)f@:b40#Fa!Z_!.90CWW3"u qYL-is8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!rr2oqrVliss6K";#n(<+4ht`EljOAZ!!#T?JWTp3s7lBcs8W,0]#t'RCJ7IN ='4;Z!-\h]8*fI's8W,trVc`prr<#us8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8N#ss8W,hna?nt8H8a1<*.^L;V1sL@KE,t^V#)R_UXT/>#qYL-is8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W)trr2orrVc`qs8GARKaS?NF`mO..BXqA) s8W&rrVlZiqu?]rKnlE'!*rc3hbmA(!!$sI&4Q-Zmf3=err2oss8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8)Tgs8W+LJ;=1*66IGC D/T%`)4Cm?;"F/Fs8W,urr2cjqu?]rJ:a-g!(\1RS8E0<&.t'l7="q5rVlfrrr2oss8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,urr2inr;Zfs \@K]]!*r)bb[FuC#Rc:c!(2HpPQ1[_qYL*cqY^Bns)rU^!!%4[D=BPF\,ZM88P="%s82fps8N#s s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W,urr2cjqu?]rJqTTn!)4mmW,m(T"UKoN7XP18rr2osrr2onqYU^ EH:gn*1Hp.7Y$#Is8W,qqYL6ls8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,qqYU$Kqc!+15+U&Y/mqYL*hs8VrlqZ$TqJ:N7P!'Li)NbE.p .4_P+$XN>ooDejjrr2oss8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!rVc`qs8VNTn-on?-Rc!8EV(%aQ2gnb7nHtcs8W)ts8N#srr2rts85;VJ-Q@5 DfG>$0!50S;L*SSs8W,rqu$Hmrr<#us8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,urr2rts7,UI%1c)3!-2(@g/:l&!!$&SLn=YHs8)Th s8W,sr;?Tps1#YR!!#[s$AN8/l8:K0"q"r4o(;t^s8N#ss8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W)trqlTjs8W+JJ>3)EC1(K3:/B7;!d4PE6+FG8 s8W,sr;?Qnrr<#unaZ)S$[?8W8'V>HDY!Aks8W,urr2rts8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8N#sr;?Nns8TU=bQ%WY:f>qL>MfD`I/j7@\@B?Ss8W#pr;Q]pqYL-is8R=gRfEG) Bkcs"6Grj(?qF%9s8W)trr;usrr<#us8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8Vrlqu?]rL5;&o!(IqJRVcm5)]YFU$XsH!+`UNa8c2>r;?Kms8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,urr2orrr)fps8W*d7=PRMMK[?8_:XT4CD@R4EnaYuGs8W)trr<#us8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8)Ths8W+LJtW/E<&m"PD/AV?!-*ISu0f$!6!*Vl`B`J,1rr2rsrr2rts8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8Vrlqu?]r J:aEo!*2`GIs8)Thrr2oss8W-!s8)Ths8W+NKU`#B:*M!XEH:d\%$!YCI/j6G rr2rsrr2rts8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!rr2onqY^Bns*oTt !!$qNBBr#VaT)<`!!,3l\@;MMfD\G7+mRl07@1s8W)trr2ors8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!qYL*hs8RV$U&Y0q6q#+)@d!dl@t0') s8W,qqYUTu?sr*s!+UM0V#UJpqYL*hs8W-!s8W-!rr2oss8VW[ndQ14!!%:TA*--H`rlZ_ m-O3@s8W&rrr<#us8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8N#srr2oqrVlisr^0). $P&8@Fnm=2VZ6^,'c0.*naHMXs8N#srr2orrr2rts7>jR&J\[m*1:bdq&giR!!#Q?J<0a1s8)Th rr2oss8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W,urr2cjqu?]rJ:aQs!*Vc\a^AK;!!$JXJY`>Gs8)Ths8W-!s8W-!s8Doq s8W,fn*UVq8cSj0;Gu%F=53cU>(qa's8W,qqYU9krr<#us8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W)trqu]ls8W,/\]=aN?V*i8@:A4&$A&6X7"9`Gs8W,rqtpBlrr2orr;?Kms8TR;_Z0[C 4[-eqAa'@)K)bmD[^WmKs8W#pr;Q]ps8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,qqYUpSqqYL*hs8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!rr2orrr2ors8W-!77MP*#(gl8oeSJ7!!$XE'M.WYlMpna rVc`qs8W)trqcKgs8W+KJ"6Q>AR]3484h#*!,NDh:\42Js8W,urr2rts8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8N#s qYL-is8R@lT)\js9MNi=>MoJ]@"3a%s8W,qqYU$&ieBoI;Do!!#i@HB%t)s82]j rr2oss8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W)trr<#uoCMA`(IA*%D+m[O='+5Y!*t)*U&Y/mqYL*hs8W-!s8W-! s8W,qqYU[6:h!*t)(RfEEfqYL*hs8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W,urr2orrr<#unac5^&muXuS98uM,:'&b!*2T\BE/#2rVc`prr2orrr2orrVc`qs8VENklqGs ,q,^3EV't^Q2gnWL5;5ss8Vrlqu?]rs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W)trr<#unaZ)X&P)m%E*?K% ;c;3I!*"K#R/d3dqYL*hs8W-!s8W-!s8W,urr2ors8W,s8PF"%!+.TAZuL*X!!%1fH_pcBs8)Ti rr2oss8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!rr2opr;HZqs1#Sa!!$e3;:\uWhuEn.!!#d(\AJ:Gs8;fm rr2oss8W-!s8)Ths8W+RLn+MG>Yn8G>?p(d!-ek]9Bk^'s8W,urr2orrr<#us8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W,urr2rts75aL%hhG5!,u+Gh,@5&!!#uKJt)f?s8)Ths8W-!s8W-!s8W-!s8W,qqYL6ls+#W\ !!#S6,GK-rp(nO4%hi:@o^r1`s8N#ss8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W)trr2orrVc`qs8PGTJHuXA FER@//?8aNB,)4MnaZ&Is8W)trr2ors8W,urr2flr;ZfsGB]h_!-2jkmQEeL!!$@t9QpI9rr2os rr2oss8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!rr2oss8VWZljXId!!%(B=kZePec5\NJ:a?ls8Vrlqu?]r s8W-!s8W-!s8N#sr;?Kms8TR<]`8(0#n)T(C@*i8[g!(Jlg+!=s8W&rrr2ors8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W,urr2inrVuot\@BZ]!+JMkc"(AJ$4MUg!(MHgNrT.Zqtp9irr2rts8N#srr2oss8V]^oFM[H *$(VjEVU[uT)\j^J:N[[s8VrlqYpKns8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8N#srr2rts8>DYF8u;T ='"'S<7h0N_\'1 s8W,qqYUu4DK<`e)W!*t#&U&Y/mqYL*grr2rts8W-!s8W-!s8W)trr2os s8W!g961(5@66WdCi/P>!-*4,UAt8nqtp6"X&rr2rsrr2orrr<#us8W,urr2cjqu?]rKnu].!+oG>hbm>&!!$pQ)HQG"nc/Xh rr2orrr2rts8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!rr2orrr<#urC0D'!!$nB?/\RWe,TJN J:OBos8Vrlqu?]rs8W-!s8W-!s8W-!s8W,urr2flr;ZfsJ:a6j!*1KuXE/LX'Gd#B$ruQVkl:\_ rr2orrr2rts8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! rr2ooqu$Kos*fHm!!$bDA*HQXci=)i!!,6m\@MY>s8;fmrr2oss8W-!s8W-!rr2orrr<#us$K5* "pTa"E:bk?Z2al$H$YYRs8Vunqu6Tos8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! qYL*hs8RV"T`>'p7S([/@,q:fDad3Cs8W#rrr;usrr<#us8W-!s8W-!s8W-!s8W,trVliss6K"9 $4Kl9#D6Z&l:+4a!!$,VM51+Ns8)Thrr2oss8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W)trr2ors8W,ho(!>(@3-J`Ec_$t+J/W6<_#\ks8W)srVlfqrr2or s8W-!s8W)trr2ors8W,`l0AQ\>q@S3D/SqS%ugPhbH%:\!uDs8W,urr2rts8W-! s8W-!s8W-!s8N#srr2orrr<#us$oV'!!$Ot7`]:Xkl:^*77M_*s8N#ss8N#ss8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,urr2inrVuot\@Kf`!,>D1fNVS9 !!@NI!)0o4_#OH7r;?Klrr2rts8W-!s8W,urr2cjr;ZfsKnlT,!+K&5gf%/)!!%'O&kDH\mJm4d rr2orrr2rts8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W&rrr<#ulg*pD$==ScQZ-m9 *[%*U!*-M<_>jQ8r;?Klrr2rts8W-!s8W-!s8W-!s8N#sqYL*hs8Rh0S,`Ob+jQ&f+OM"Fk)uks.SQ!!#fFJ<^*6s8)Thrr2oss8W-!s8W-!s8W-!s8W)trr2or s8W,`l0&Ka:B1HF@:A1i9[<\=>)%j,s8W,qqYU9krr<#us8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8Doqs8W,blg5#eB0JQ!BP?]?%Yk#a8:Q2Rs8W,rqu$Hmrr<#u s8W-!s8W)trqu]ls8W,0\\8%D;)0o6Ci/_Q&<6_j;7O0Ss8W,sr;?Tps8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!rr2onqY^Bns*8m^!!$D,=4pVTg&M+c8PF@.s8N#ss8N#s s8W-!s8W-!s8W-!s8W-!s8W)trr2oss8W'g8p(+6@m3/rBPHl7!,R+5W;lntqYL*hs8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,urr2cjr;ZfsJqU-(!-E'omliqP !!$aB%S5pOlMpnarVc`qs8W-!s8W-!rr2orrr2cjqu?]rH$YbV!+K2;iDNV+!!$pQ)HZFunGiOg rr2orrr2rts8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!qYL*hs8Rk2T)\jj 3'+]fD!hH4KF/,[l07=0s8W)trr2ors8W-!s8W-!s8W-!s8W,urr2cjqu?]rJ:a?m!)Y-oWH37[ !!@muGcC`Cs8)Tirr2oss8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W,qqY^Bns*B!n&J::NG52pkQ2gnj*?d]@p%&._s8N#srr2oss8W-!s8N#srVc`qs8VKRlk'q= %M4_>E:Y\8Z2al&H?tbSs8Vunqu6Tos8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W)trr)fps8W,blg"f`=;MmCEH1Up,bb8=98A=hs8W,qqYU9krr<#us8W-!s8W-!s8W-! rr2onqYURM_Hru@q4U($%N!U9gD'HrVcTms8W)trr2or s8W,urr2rts7uKfs8W+LJsQH;<'Xua9";FGs8W,sr;?Tps8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W)trr2oss8W*f7XtI=G\_$Z6UScl!+/5eDZBb8 rr2rsrr2orrr<#us8W-!s8W)trr2orrVc`qs8>G[?2st&%1e>2C$I6%Z3q1FoCVSQs8W)trr<#u s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W)trr<#uo'u)P$!9hoeko>q !!%-A!Dj7;,4P*hs8W,trVccrs8N#srr2onqYUkcX1)@!!7HS%8#mOl2Ue`rVc`prr2rts8N#ss8W-!s8VrlqZ$Tq\@K!I!#tt?@1Np- D/JbY(nYkkW;lntqYL-hrr2rts8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W,urr2ors8W,u77WD+7*SV.ec5\m!!HF)"!FnUZ2ak(qYL'aq>0saqu6Tos8W,rqtNfZC]FH? /1muDEVC:gR/d4b\@BKWs8W#prVlfqs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!rr2orrr2rts68e5#n(&^+es+"pDtHK!!#iHK:)]=s7uKfs8W,urr2orrr2or qtp9irr;ooqaEtG!!#"Z!c9)*TQPDR#766=KWb@Ts8)Tis8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,qqY^Bns*/gi.4hi7A*F%!IfKUZ!!>"Z"p_H?ZiC(* rVc]lqu$9cp;+Va4[30O!(R8"Jm`!H;,YsF!,4qpGQ7^BrVc`prr2orrr<#us8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!rr2orrr<#us$]G&!!%:WB'MiUaoDEX &en%,md0uRs7lBbqYL'bqYL3jrr)fpp%@rM9i(fi+9MjX!!.148',1KkReGPl07R7s8W&rrr2or s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8N#sr;?Nns8T:-bTeF0 D/]%[(6ee"B`SE9!sC:X!!u.f:Pt*jGBn]R));@#1B7DO!!.=(3Os3Qq&(-@!!#g)\]+UKs8;fn rr2oss8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8N#s r;?Kms8TU>a8c3H3]t2jB^?3@NW9&W9200uqtU3ks8N#sqtp9hrVNn,ZO%'U!YS%>s8W&srr2orrr2ors8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W)trr2orrVc`qs8PMWIfot-Ci&W"34f.kF8u;)7S$jAMMlt8JpD]j 'Gr(u"s3gF3k,fD$1,W":/?:#\!c:B)hsM!oAS13N,GYPOJH?"% !X*oX$AKZIU/+V7F`dIO8_+OhNdQ;Xo^qhVs8W)trr<#urr2oss8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!rr2oss8W)trqcKhs8W,-\'8`,XXl,r -7>T/*i'\nSf]/C(`Rp1faE,bSgC@#)*gg"+@CMN6UDtd..h]qsJu[trmITrBrVc`qs8W#prVQKis8W,urr2orrr<#u s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!rr2oss8W&rrVuoto_%p(IAmnsHl!Zf,q$&U1r(t-_'gh<+C*cr;$3eqYL-grVlfqrr<#u rr2oss8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!~> Q cleartomark end end pagesave restore showpage %%PageTrailer %%Trailer %%Pages: 1 asymptote-2.37/examples/pipeintersection.asy000066400000000000000000000005521265434602500214230ustar00rootroot00000000000000import graph3; currentprojection=orthographic(5,4,2); size(12cm,0); real f(pair z) {return min(sqrt(1-z.x^2),sqrt(1-z.y^2));} surface s=surface(f,(0,0),(1,1),40,Spline); transform3 t=rotate(90,O,Z), t2=t*t, t3=t2*t, i=xscale3(-1)*zscale3(-1); draw(surface(s,t*s,t2*s,t3*s,i*s,i*t*s,i*t2*s,i*t3*s),blue, render(compression=Low,closed=true,merge=true)); asymptote-2.37/examples/pipes.asy000066400000000000000000000074341265434602500171650ustar00rootroot00000000000000import solids; import tube; import graph3; import palette; size(8cm); currentprojection=perspective( camera=(13.3596389245356,8.01038090435314,14.4864483364785), up=(-0.0207054323419367,-0.00472438375047319,0.0236460907598947), target=(-1.06042550499095,2.68154529985845,0.795007562120261)); defaultpen(fontsize(6pt)); // draw coordinates and frames // axis1 is defined by z axis of TBase // axis2 is defined by z axis of TEnd void DrawFrame(transform3 TBase, transform3 TEnd, string s) { triple p1,v1,p2,v2; p1=TBase*O; v1=TBase*Z-p1; p2=TEnd*O; v2=TEnd*Z-p2; triple n=cross(v1,v2); real[][] A= { {v1.x,-v2.x,-n.x}, {v1.y,-v2.y,-n.y}, {v1.z,-v2.z,-n.z} }; triple vb=p2-p1; real[] b={vb.x,vb.y,vb.z}; // Get the extention along vector v1 and v2, // so, we can get the common normal between two axis real[] x=solve(A,b); real s1=x[0]; real s2=x[1]; // get foot of a perpendicular on both axies triple foot1=p1+s1*v1; triple foot2=p2+s2*v2; // draw two axis triple axis_a,axis_b; axis_a=p1+s1*v1*1.5; axis_b=p1-s1*v1*1.5; draw(axis_a--axis_b); axis_a=p2+s2*v2*1.5; axis_b=p2-s2*v2*1.5; draw(axis_a--axis_b); // draw "a"(common normal) draw(Label("$a_{"+s+"}$"),foot1--foot2,linewidth(1pt)); // draw the coordinates frame triple dx,dy,dz,org; real length=0.8; org=foot1; dx =length*unit(foot2-foot1); // define the x axis of the frame on "a" dz =length*unit(v1); // define the z axis which is along axis1 dy =length*unit(cross(dz,dx)); draw(Label("$X_{"+s+"}$",1,align=-dy-dz),org--(org+dx),red+linewidth(1.5pt), Arrow3(8)); draw(Label("$Y_{"+s+"}$",1,align=2dy-dz-dx),org--(org+dy), green+linewidth(1.5pt), Arrow3(8)); draw(Label("$Z_{"+s+"}$",1,align=-2dx-dy),org--(org+dz), blue+linewidth(1.5pt), Arrow3(8)); dot(Label("$O_{"+s+"}$",align =-dx-dz,black),org,black); // origin } void DrawLink(transform3 TBase, transform3 TEnd, pen objStyle,string s) { real h=1; real r=0.5; path3 generator=(0.5*r,0,h)--(r,0,h)--(r,0,0)--(0.5*r,0,0); revolution vase=revolution(O,generator,0,360); surface objSurface=surface(vase); render render=render(merge=true); // draw two cylinders draw(TBase*objSurface,objStyle,render); draw(TEnd*shift((0,0,-h))*objSurface,objStyle,render); // draw the link between two cylinders triple pStart=TBase*(0.5*h*Z); triple pEnd =TEnd*(-0.5*h*Z); triple pControl1=0.25*(pEnd-pStart)+TBase*(0,0,h); triple pControl2=-0.25*(pEnd-pStart)+TEnd*(0,0,-h); path3 p=pStart..controls pControl1 and pControl2..pEnd; draw(tube(p,scale(0.2)*unitsquare),objStyle,render); } // t1 and t2 define the starting frame and ending frame of the first link(i-1) transform3 t1=shift((0,0,1)); transform3 t2=shift((0,0,-1))*rotate(-20,Y)*shift((0,3,2)); // as, the two links were connected, so t2 is also the starting frame of link(i) // t3 defines the ending frame of link(i) transform3 t3=t2*rotate(40,Z)*shift((0,3,1.5))*rotate(-15,Y)*shift(-1.5*Z); // draw link(i-1) DrawLink(t1,t2,palegreen,"i-1"); DrawFrame(t1,t2,"i-1"); // draw link(i) DrawLink(t2,t3,lightmagenta,"i"); DrawFrame(t2,t3,"i"); // draw angle alpha, which is the angle between axis(i-1) and axis(i) triple p0=(0,0,-1); triple p1=(0,0,2.3); triple p2=shift((0,0,-1))*rotate(-20,Y)*(0,0,4); draw(p0--p2,cyan); draw("$\alpha_{i-1}$",arc(p0,p1,p2,Y,CW),ArcArrow3(3)); // draw angle theta, which is the angle between a_i and a_{i-1} transform3 tx=shift((0,0,-1))*rotate(-20,Y)*shift((0,3,0)); p0=tx*O; p1=tx*(0,3,0); p2=tx*rotate(40,Z)*(0,3,0); draw(p0--p1,cyan); draw(p0--p2,cyan); triple p1a=tx*(0,1.5,0); draw("$\theta_{i}$",arc(p0,p1a,p2),ArcArrow3(3)); // draw d_{i-1} triple org_i =t2*shift((0,0,1.5))*O; draw(Label("$d_{i}$",0.13),p0--org_i,linewidth(1pt)); asymptote-2.37/examples/planeproject.asy000066400000000000000000000006421265434602500205250ustar00rootroot00000000000000import graph3; size3(200,IgnoreAspect); currentprojection=orthographic(4,6,3); real x(real t) {return 1+cos(2pi*t);} real y(real t) {return 1+sin(2pi*t);} real z(real t) {return t;} path3 p=graph(x,y,z,0,1,operator ..); draw(p,Arrow3); draw(planeproject(XY*unitsquare3)*p,red,Arrow3); draw(planeproject(YZ*unitsquare3)*p,green,Arrow3); draw(planeproject(ZX*unitsquare3)*p,blue,Arrow3); axes3("$x$","$y$","$z$"); asymptote-2.37/examples/polararea.asy000066400000000000000000000016421265434602500200060ustar00rootroot00000000000000import math; import graph; size(0,150); real f(real t) {return 5+cos(10*t);} xaxis("$x$"); yaxis("$y$"); real theta1=pi/8; real theta2=pi/3; path k=graph(f,theta1,theta2,operator ..); real rmin=min(k).y; real rmax=max(k).y; draw((0,0)--rmax*expi(theta1),dotted); draw((0,0)--rmax*expi(theta2),dotted); path g=polargraph(f,theta1,theta2,operator ..); path h=(0,0)--g--cycle; fill(h,lightgray); draw(h); real thetamin=3*pi/10; real thetamax=2*pi/10; pair zmin=polar(f(thetamin),thetamin); pair zmax=polar(f(thetamax),thetamax); draw((0,0)--zmin,dotted+red); draw((0,0)--zmax,dotted+blue); draw("$\theta_*$",arc((0,0),0.5*rmin,0,degrees(thetamin)),red+fontsize(10pt), PenMargins); draw("$\theta^*$",arc((0,0),0.5*rmax,0,degrees(thetamax)),blue+fontsize(10pt), PenMargins); draw(arc((0,0),rmin,degrees(theta1),degrees(theta2)),red,PenMargins); draw(arc((0,0),rmax,degrees(theta1),degrees(theta2)),blue,PenMargins); asymptote-2.37/examples/polarcircle.asy000066400000000000000000000011641265434602500203360ustar00rootroot00000000000000import math; import graph; size(0,100); real f(real t) {return 2*cos(t);} pair F(real x) {return (x,f(x));} draw(polargraph(f,0,pi,operator ..)); defaultpen(fontsize(10pt)); xaxis("$x$"); yaxis("$y$"); real theta=radians(50); real r=f(theta); draw("$\theta$",arc((0,0),0.5,0,degrees(theta)),red,Arrow,PenMargins); pair z=polar(r,theta); draw(z--(z.x,0),dotted+red); draw((0,0)--(z.x,0),dotted+red); label("$r\cos\theta$",(0.5*z.x,0),0.5*S,red); label("$r\sin\theta$",(z.x,0.5*z.y),0.5*E,red); dot("$(x,y)$",z,N); draw("r",(0,0)--z,0.5*unit(z)*I,blue,Arrow,DotMargin); dot("$(a,0)$",(1,0),NE); dot("$(2a,0)$",(2,0),NE); asymptote-2.37/examples/polardatagraph.asy000066400000000000000000000005061265434602500210270ustar00rootroot00000000000000import graph; size(100); int n=30; real minRadius=0.2; real angles[]=uniform(0,2pi,n); angles.delete(angles.length-1); real[] r=new real[n]; for(int i=0; i < n; ++i) r[i]=unitrand()*(1-minRadius)+minRadius; interpolate join=operator ..(operator tension(10,true)); draw(join(polargraph(r,angles,join),cycle),dot(red)); asymptote-2.37/examples/poster.asy000066400000000000000000000016741265434602500173610ustar00rootroot00000000000000orientation=Landscape; import slide; import graph; defaultpen(deepblue); pagenumberpen=invisible; real f(real x) {return (x != 0) ? x*sin(1/x) : 0;} pair F(real x) {return (x,f(x));} xaxis(background,grey); yaxis(background,-0.25,0.25,grey); real a=1.2/pi; draw(background,graph(background,f,-a,a,10000),grey); label(background,"$x\sin\frac{1}{x}$",F(0.92/pi),3SE,grey+fontsize(14pt)); frame f=background.fit(); box(f,RadialShade(yellow,0.6*yellow+red),above=false); background.erase(); add(background,f); title("Young Researchers' Conference",align=3S,fontsize(48pt)); center("University of Alberta, Edmonton, April 1--2, 2006"); skip(4); center("A general conference for\\ the mathematical and statistical sciences\\ for graduate students, by graduate students.",fontsize(32pt)); label("Registration and abstract submission online.",(0,-0.5)); label("\tt http://www.pims.math.ca/science/2006/06yrc/",point(SW),2NE, black+fontsize(18pt)); asymptote-2.37/examples/progrid.asy000066400000000000000000000000721265434602500175020ustar00rootroot00000000000000label("$\displaystyle X_i = \sum_{j=1}^{N} a_{ij} f_j$"); asymptote-2.37/examples/projectelevation.asy000066400000000000000000000005651265434602500214200ustar00rootroot00000000000000import graph3; import grid3; import palette; currentprojection=orthographic(0.8,1,2); size(400,300,IgnoreAspect); real f(pair z) {return cos(2*pi*z.x)*sin(2*pi*z.y);} surface s=surface(f,(-1/2,-1/2),(1/2,1/2),50,Spline); surface S=planeproject(unitsquare3)*s; S.colors(palette(s.map(zpart),Rainbow())); draw(S,nolight); draw(s,lightgray+opacity(0.7)); grid3(XYZgrid); asymptote-2.37/examples/projectrevolution.asy000066400000000000000000000006661265434602500216420ustar00rootroot00000000000000import solids; import palette; currentprojection=orthographic(20,0,3); size(400,300,IgnoreAspect); revolution r=revolution(graph(new triple(real x) { return (x,0,sin(x)*exp(-x/2));},0,2pi,operator ..),axis=Z); surface s=surface(r); surface S=planeproject(shift(-Z)*unitsquare3)*s; S.colors(palette(s.map(zpart),Rainbow())); render render=render(compression=Low,merge=true); draw(S,render); draw(s,lightgray,render); asymptote-2.37/examples/pseudosphere.asy000066400000000000000000000013531265434602500205450ustar00rootroot00000000000000// Pseudosphere: // x = a sin(u) cos(v); // y = a sin(u) sin(v); // z = a (ln(tg(u/2))+cos(u)); import three; import solids; import graph3; import palette; triple pseudosphere(real x) { return (sin(x),0,cos(x)+log(tan(x/2))); } size(20cm,IgnoreAspect); currentprojection=orthographic(160,40,100); currentlight=(50,50,50); path3 G=graph(pseudosphere,0.5pi,0.965pi,10,Spline); revolution r=revolution(O,G,Z); draw(r,1,longitudinalpen=nullpen); surface s=surface(r); s.colors(palette(s.map(zpart),Gradient(cyan+white+opacity(0.9), magenta+white+opacity(0.9)))); draw(s); draw(r,6,backpen=linetype("10 10",10),longitudinalpen=nullpen); int n=10; for(int i=0; i < n; ++i) draw(rotate(i*360/n,O,Z)*G); asymptote-2.37/examples/quilt.asy000066400000000000000000000013361265434602500171760ustar00rootroot00000000000000import math; int n=8, skip=3; pair r(int k) { return unityroot(n,k); } pen col=blue, col2=purple; guide square=box((1,1),(-1,-1)); guide step(int mult) { guide g; for(int k=0; k= 380 && wl <= 440) {rgb=((440-wl)/60,0,1);} if(wl > 440 && wl <= 490) {rgb=(0,(wl-440)/50,1);} if(wl > 490 && wl <= 510) {rgb=(0,1,(510-wl)/20);} if(wl > 510 && wl <= 580) {rgb=((wl-510)/70,1,0);} if(wl > 580 && wl <= 645) {rgb=(1,(645-wl)/65,0);} if(wl > 645 && wl <= 780) {rgb=(1,0,0);} real Intensity=1; if(intensity) { if(wl >= 700) {Intensity=0.3+0.7*(780-wl)/80;} else if(wl <= 420) {Intensity=0.3+0.7*(wl-380)/40;} } return rgb((Intensity*rgb.x)**gamma,(Intensity*rgb.y)**gamma, (Intensity*rgb.z)**gamma); } real width=1; real height=50; begin("spectrum"); for(real i=380 ; i <= 780 ; i += width) { draw((i,0)--(i,height),width+nm2rgb(wl=i,false)+squarecap); } begin("Extinction",false); // nested for(real i=380 ; i <= 780 ; i += width) { draw((i,0)--(i,height),width+nm2rgb(wl=i,true)+squarecap); } end(); end(); begin("Wavelength"); xaxis(scale(0.5)*"$\lambda$(nm)",BottomTop,380,780, RightTicks(scale(0.5)*rotate(90)*Label(),step=2,Step=10),above=true); end(); // From Astronomical Data Center(NASA) // Neutral only real[] Na={423.899, 424.208, 427.364, 427.679, 428.784, 429.101, 432.14, 432.462, 434.149, 434.474, 439.003, 439.334, 441.989, 442.325, 449.418, 449.766, 454.163, 454.519, 568.2633, 568.8204, 588.995, 589.5924}; begin("Na absorption"); for(int i=0; i < Na.length; ++i) { draw((Na[i],0)--(Na[i],height),0.1*width+squarecap); } end(); begin("Na emission"); for(int i=0; i < Na.length; ++i) { draw((Na[i],0)--(Na[i],-height),0.1*width+nm2rgb(Na[i],false)+squarecap); } end(); // Neutral only real[] Zn={388.334, 396.543, 411.321, 429.288, 429.833, 462.981, 468.014, 472.215, 481.053 , 506.866, 506.958, 518.198, 530.865, 531.024, 531.102, 577.21, 577.55, 577.711, 623.79, 623.917, 636.234, 647.918, 692.832, 693.847, 694.32, 779.936}; begin("Zn absorption",false); for(int i=0; i < Zn.length; ++i) { draw((Zn[i],0)--(Zn[i],height),width+squarecap); } end(); begin("Zn emission",false); for(int i=0; i < Zn.length; ++i) { draw((Zn[i],0)--(Zn[i],-height),width+nm2rgb(Zn[i],false)+squarecap); } end(); shipout(bbox(2mm,Fill(white))); asymptote-2.37/examples/sphere.asy000066400000000000000000000001761265434602500173270ustar00rootroot00000000000000import three; size(200); currentprojection=orthographic(5,4,3); draw(unitsphere,green,render(compression=Zero,merge=true)); asymptote-2.37/examples/spheresilhouette.asy000066400000000000000000000002261265434602500214310ustar00rootroot00000000000000import solids; settings.render=0; settings.prc=false; size(200); revolution r=sphere(O,1); draw(r,1,longitudinalpen=nullpen); draw(r.silhouette()); asymptote-2.37/examples/sphereskeleton.asy000066400000000000000000000002451265434602500210710ustar00rootroot00000000000000size(100); import solids; currentprojection=orthographic(5,4,2); revolution sphere=sphere(1); draw(surface(sphere),green+opacity(0.2)); draw(sphere,m=7,blue); asymptote-2.37/examples/sphericalharmonic.asy000066400000000000000000000005701265434602500215320ustar00rootroot00000000000000import graph3; import palette; size(200); currentprojection=orthographic(4,2,4); currentlight=Viewport; real r(real theta, real phi) {return 1+0.5*(sin(2*theta)*sin(2*phi))^2;} triple f(pair z) {return r(z.x,z.y)*expi(z.x,z.y);} surface s=surface(f,(0,0),(pi,2pi),50,Spline); s.colors(palette(s.map(abs),Gradient(yellow,red))); draw(s,render(compression=Low,merge=true)); asymptote-2.37/examples/spiral.asy000066400000000000000000000003221265434602500173240ustar00rootroot00000000000000size(0,150); import graph; real f(real t) {return exp(-t/(2pi));} draw(polargraph(f,0,20*pi,operator ..)); xaxis("$x$",-infinity,1.3); yaxis("$y$",-infinity,1); labelx(1); labelx("$e^{-1}$",1.0/exp(1),SE); asymptote-2.37/examples/spiral3.asy000066400000000000000000000006521265434602500174150ustar00rootroot00000000000000import graph3; import palette; size3(10cm); currentprojection=orthographic(5,4,2); viewportmargin=(2cm,0); real r(real t) {return 3exp(-0.1*t);} real x(real t) {return r(t)*cos(t);} real y(real t) {return r(t)*sin(t);} real z(real t) {return t;} path3 p=graph(x,y,z,0,6*pi,50,operator ..); tube T=tube(p,2); surface s=T.s; s.colors(palette(s.map(zpart),BWRainbow())); draw(s,render(merge=true)); draw(T.center,thin()); asymptote-2.37/examples/spline.asy000066400000000000000000000011521265434602500173260ustar00rootroot00000000000000import graph; import interpolate; size(15cm,15cm,IgnoreAspect); real a=1997, b=2002; int n=5; real[] xpt=a+sequence(n+1)*(b-a)/n; real[] ypt={31,36,26,22,21,24}; horner h=diffdiv(xpt,ypt); fhorner L=fhorner(h); scale(false,true); pen p=linewidth(1); draw(graph(L,a,b),dashed+black+p,"Lagrange interpolation"); draw(graph(xpt,ypt,Hermite(natural)),red+p,"natural spline"); draw(graph(xpt,ypt,Hermite(monotonic)),blue+p,"monotone spline"); xaxis("$x$",BottomTop,LeftTicks(Step=1,step=0.25)); yaxis("$y$",LeftRight,RightTicks(Step=5)); dot(pairs(xpt,ypt),4bp+gray(0.3)); attach(legend(),point(10S),30S); asymptote-2.37/examples/splitpatch.asy000066400000000000000000000042041265434602500202100ustar00rootroot00000000000000import three; size(300); // A structure to subdivide two intersecting patches about their intersection. struct split { surface[] S={new surface}; surface[] T={new surface}; struct tree { tree[] tree=new tree[2]; } // Default subdivision depth. int n=20; // Subdivide p and q to depth n if they overlap. void write(tree pt, tree qt, triple[][] p, triple[][] q, int depth=n) { --depth; triple[][][] Split(triple[][] P, real u=0)=depth % 2 == 0 ? hsplit : vsplit; triple[][][] P=Split(p); triple[][][] Q=Split(q); for(int i=0; i < 2; ++i) { triple[][] Pi=P[i]; for(int j=0; j < 2; ++j) { triple[][] Qj=Q[j]; if(overlap(Pi,Qj)) { if(!pt.tree.initialized(i)) pt.tree[i]=new tree; if(!qt.tree.initialized(j)) qt.tree[j]=new tree; if(depth > 0) write(pt.tree[i],qt.tree[j],Pi,Qj,depth); } } } } // Output the subpatches of p from subdivision. void read(surface[] S, tree t, triple[][] p, int depth=n) { --depth; triple[][][] Split(triple[][] P, real u=0)=depth % 2 == 0 ? hsplit : vsplit; triple[][][] P=Split(p); for(int i=0; i < 2; ++i) { if(t.tree.initialized(i)) read(S,t.tree[i],P[i],depth); else { S[0].push(patch(P[i])); } } } void operator init(triple[][] p, triple[][] q, int depth=n) { tree ptrunk,qtrunk; write(ptrunk,qtrunk,p,q,depth); read(T,ptrunk,p,depth); read(S,qtrunk,q,depth); } } currentprojection=orthographic(0,0,1); triple[][] A={ {(0,0,0),(1,0,0),(1,0,0),(2,0,0)}, {(0,4/3,0),(2/3,4/3,2),(4/3,4/3,2),(2,4/3,0)}, {(0,2/3,0),(2/3,2/3,0),(4/3,2/3,0),(2,2/3,0)}, {(0,2,0),(2/3,2,0),(4/3,2,0),(2,2,0)} }; triple[][] B={ {(0.5,0,-1),(0.5,1,-1),(0.5,2,-1),(0.5,3,-1)}, {(0.5,0,0),(0.5,1,0),(0.5,2,0),(0.5,3,0)}, {(0.5,0,1),(0.5,1,1),(0.5,2,1),(0.5,3,1)}, {(0.5,0,2),(0.5,1,2),(0.5,2,2),(0.5,3,2)} }; split S=split(B,A); defaultrender.merge=true; for(int i=0; i < S.S[0].s.length; ++i) draw(surface(S.S[0].s[i]),Pen(i)); for(int i=0; i < S.T[0].s.length; ++i) draw(surface(S.T[0].s[i]),Pen(i)); asymptote-2.37/examples/spring.asy000066400000000000000000000012371265434602500173420ustar00rootroot00000000000000pair coilpoint(real lambda, real r, real t) { return (2.0*lambda*t+r*cos(t),r*sin(t)); } guide coil(guide g=nullpath, real lambda, real r, real a, real b, int n) { real width=(b-a)/n; for(int i=0; i <= n; ++i) { real t=a+width*i; g=g..coilpoint(lambda,r,t); } return g; } void drawspring(real x, string label) { real r=8; real t1=-pi; real t2=10*pi; real lambda=(t2-t1+x)/(t2-t1); pair b=coilpoint(lambda,r,t1); pair c=coilpoint(lambda,r,t2); pair a=b-20; pair d=c+20; draw(a--b,BeginBar(2*barsize())); draw(c--d); draw(coil(lambda,r,t1,t2,100)); dot(d); pair h=20*I; draw(label,a-h--d-h,red,Arrow,Bars,PenMargin); } asymptote-2.37/examples/spring0.asy000066400000000000000000000000461265434602500174170ustar00rootroot00000000000000import spring; drawspring(0,"$L$"); asymptote-2.37/examples/spring2.asy000066400000000000000000000000531265434602500174170ustar00rootroot00000000000000import spring; drawspring(40.0,"$L+x$"); asymptote-2.37/examples/sqrtx01.asy000066400000000000000000000012421265434602500173560ustar00rootroot00000000000000import graph3; import solids; size(0,150); currentprojection=perspective(1.5,0,10,Y); pen color=green+opacity(0.75); real f(real x){return sqrt(x);} pair F(real x){return (x,f(x));} triple F3(real x){return (x,f(x),0);} path p=graph(F,0,1,n=20,operator ..); path3 p3=path3(p); revolution a=revolution(p3,X,0,360); draw(surface(a),color,render(compression=Low,merge=true)); draw(p3,blue); real x=relpoint(p,0.5).x; xaxis3(Label("$x$",1),xmax=1.5,dashed,Arrow3); yaxis3(Label("$y$",1),Arrow3); dot(Label("$(1,1)$"),(1,1,0)); arrow(Label("$y=\sqrt{x}$"),F3(0.7),Y,0.75cm,red); draw(arc(1.2X,0.4,90,90,175,-40,CW),Arrow3); draw("$r$",(x,0,0)--F3(x),red,Arrow3,PenMargin3); asymptote-2.37/examples/sqrtx01y1.asy000066400000000000000000000011031265434602500176240ustar00rootroot00000000000000import graph3; import solids; size(0,150); currentprojection=perspective(0,1,10,up=Y); currentlight=White; real f(real x) {return sqrt(x);} pair F(real x) {return (x,f(x));} triple F3(real x) {return (x,f(x),0);} path p=graph(F,0,1,n=25,operator ..); path3 p3=path3(p); revolution a=revolution(p3,Y,0,360); draw(surface(a),green,render(compression=Low,merge=true)); draw(p3,blue); xaxis3(Label("$x$",1),Arrow3); yaxis3(Label("$y$",1),ymax=1.5,dashed,Arrow3); dot(Label("$(1,1)$"),(1,1,0)); arrow("$y=\sqrt{x}$",F3(0.5),X,0.75cm,red); draw(arc(1.2Y,0.3,90,0,7.5,140),Arrow3); asymptote-2.37/examples/star.asy000066400000000000000000000002211265434602500170010ustar00rootroot00000000000000size(100); import math; int n=5; path p; int i=0; do { p=p--unityroot(n,i); i=(i+2) % n; } while(i != 0); filldraw(p--cycle,red+evenodd); asymptote-2.37/examples/stereoscopic.asy000066400000000000000000000002521265434602500205360ustar00rootroot00000000000000import three; currentprojection=perspective(50*dir(70,15)); picture pic; unitsize(pic,1cm); draw(pic,xscale3(10)*unitcube,yellow,blue); addStereoViews(pic); asymptote-2.37/examples/stroke3.asy000066400000000000000000000000731265434602500174270ustar00rootroot00000000000000import three; size(5cm); draw(O--X,red+1cm,currentlight); asymptote-2.37/examples/strokepath.asy000066400000000000000000000004731265434602500202250ustar00rootroot00000000000000path g=scale(100)*unitcircle; pen p=linewidth(1cm); frame f; // Equivalent to draw(f,g,p): fill(f,strokepath(g,p),red); shipout("strokepathframe",f); shipped=false; size(400); // Equivalent to draw(g,p): add(new void(frame f, transform t) { fill(f,strokepath(t*g,p),red); }); currentpicture.addPath(g,p); asymptote-2.37/examples/strokeshade.asy000066400000000000000000000002501265434602500203460ustar00rootroot00000000000000size(100); guide g=(0,0)..controls(70,30) and (-40,30)..(30,0); latticeshade(g,stroke=true,linewidth(10), new pen[][] {{red,orange,yellow},{green,blue,purple}}); asymptote-2.37/examples/tanh.asy000066400000000000000000000003061265434602500167660ustar00rootroot00000000000000import graph; size(100,0); real f(real x) {return tanh(x);} pair F(real x) {return (x,f(x));} xaxis("$x$"); yaxis("$y$"); draw(graph(f,-2.5,2.5,operator ..)); label("$\tanh x$",F(1.5),1.25*N); asymptote-2.37/examples/teapot.asy000066400000000000000000000325651265434602500173440ustar00rootroot00000000000000import three; size(20cm); currentprojection=perspective(250,-250,250); currentlight=Viewport; triple[][][] Q={ { {(39.68504,0,68.0315),(37.91339,0,71.75197),(40.74803,0,71.75197),(42.51969,0,68.0315)}, {(39.68504,-22.22362,68.0315),(37.91339,-21.2315,71.75197),(40.74803,-22.8189,71.75197),(42.51969,-23.81102,68.0315)}, {(22.22362,-39.68504,68.0315),(21.2315,-37.91339,71.75197),(22.8189,-40.74803,71.75197),(23.81102,-42.51969,68.0315)}, {(0,-39.68504,68.0315),(0,-37.91339,71.75197),(0,-40.74803,71.75197),(0,-42.51969,68.0315)} },{ {(0,-39.68504,68.0315),(0,-37.91339,71.75197),(0,-40.74803,71.75197),(0,-42.51969,68.0315)}, {(-22.22362,-39.68504,68.0315),(-21.2315,-37.91339,71.75197),(-22.8189,-40.74803,71.75197),(-23.81102,-42.51969,68.0315)}, {(-39.68504,-22.22362,68.0315),(-37.91339,-21.2315,71.75197),(-40.74803,-22.8189,71.75197),(-42.51969,-23.81102,68.0315)}, {(-39.68504,0,68.0315),(-37.91339,0,71.75197),(-40.74803,0,71.75197),(-42.51969,0,68.0315)} },{ {(-39.68504,0,68.0315),(-37.91339,0,71.75197),(-40.74803,0,71.75197),(-42.51969,0,68.0315)}, {(-39.68504,22.22362,68.0315),(-37.91339,21.2315,71.75197),(-40.74803,22.8189,71.75197),(-42.51969,23.81102,68.0315)}, {(-22.22362,39.68504,68.0315),(-21.2315,37.91339,71.75197),(-22.8189,40.74803,71.75197),(-23.81102,42.51969,68.0315)}, {(0,39.68504,68.0315),(0,37.91339,71.75197),(0,40.74803,71.75197),(0,42.51969,68.0315)} },{ {(0,39.68504,68.0315),(0,37.91339,71.75197),(0,40.74803,71.75197),(0,42.51969,68.0315)}, {(22.22362,39.68504,68.0315),(21.2315,37.91339,71.75197),(22.8189,40.74803,71.75197),(23.81102,42.51969,68.0315)}, {(39.68504,22.22362,68.0315),(37.91339,21.2315,71.75197),(40.74803,22.8189,71.75197),(42.51969,23.81102,68.0315)}, {(39.68504,0,68.0315),(37.91339,0,71.75197),(40.74803,0,71.75197),(42.51969,0,68.0315)} },{ {(42.51969,0,68.0315),(49.60629,0,53.1496),(56.69291,0,38.26771),(56.69291,0,25.51181)}, {(42.51969,-23.81102,68.0315),(49.60629,-27.77952,53.1496),(56.69291,-31.74803,38.26771),(56.69291,-31.74803,25.51181)}, {(23.81102,-42.51969,68.0315),(27.77952,-49.60629,53.1496),(31.74803,-56.69291,38.26771),(31.74803,-56.69291,25.51181)}, {(0,-42.51969,68.0315),(0,-49.60629,53.1496),(0,-56.69291,38.26771),(0,-56.69291,25.51181)} },{ {(0,-42.51969,68.0315),(0,-49.60629,53.1496),(0,-56.69291,38.26771),(0,-56.69291,25.51181)}, {(-23.81102,-42.51969,68.0315),(-27.77952,-49.60629,53.1496),(-31.74803,-56.69291,38.26771),(-31.74803,-56.69291,25.51181)}, {(-42.51969,-23.81102,68.0315),(-49.60629,-27.77952,53.1496),(-56.69291,-31.74803,38.26771),(-56.69291,-31.74803,25.51181)}, {(-42.51969,0,68.0315),(-49.60629,0,53.1496),(-56.69291,0,38.26771),(-56.69291,0,25.51181)} },{ {(-42.51969,0,68.0315),(-49.60629,0,53.1496),(-56.69291,0,38.26771),(-56.69291,0,25.51181)}, {(-42.51969,23.81102,68.0315),(-49.60629,27.77952,53.1496),(-56.69291,31.74803,38.26771),(-56.69291,31.74803,25.51181)}, {(-23.81102,42.51969,68.0315),(-27.77952,49.60629,53.1496),(-31.74803,56.69291,38.26771),(-31.74803,56.69291,25.51181)}, {(0,42.51969,68.0315),(0,49.60629,53.1496),(0,56.69291,38.26771),(0,56.69291,25.51181)} },{ {(0,42.51969,68.0315),(0,49.60629,53.1496),(0,56.69291,38.26771),(0,56.69291,25.51181)}, {(23.81102,42.51969,68.0315),(27.77952,49.60629,53.1496),(31.74803,56.69291,38.26771),(31.74803,56.69291,25.51181)}, {(42.51969,23.81102,68.0315),(49.60629,27.77952,53.1496),(56.69291,31.74803,38.26771),(56.69291,31.74803,25.51181)}, {(42.51969,0,68.0315),(49.60629,0,53.1496),(56.69291,0,38.26771),(56.69291,0,25.51181)} },{ {(56.69291,0,25.51181),(56.69291,0,12.7559),(42.51969,0,6.377957),(42.51969,0,4.251961)}, {(56.69291,-31.74803,25.51181),(56.69291,-31.74803,12.7559),(42.51969,-23.81102,6.377957),(42.51969,-23.81102,4.251961)}, {(31.74803,-56.69291,25.51181),(31.74803,-56.69291,12.7559),(23.81102,-42.51969,6.377957),(23.81102,-42.51969,4.251961)}, {(0,-56.69291,25.51181),(0,-56.69291,12.7559),(0,-42.51969,6.377957),(0,-42.51969,4.251961)} },{ {(0,-56.69291,25.51181),(0,-56.69291,12.7559),(0,-42.51969,6.377957),(0,-42.51969,4.251961)}, {(-31.74803,-56.69291,25.51181),(-31.74803,-56.69291,12.7559),(-23.81102,-42.51969,6.377957),(-23.81102,-42.51969,4.251961)}, {(-56.69291,-31.74803,25.51181),(-56.69291,-31.74803,12.7559),(-42.51969,-23.81102,6.377957),(-42.51969,-23.81102,4.251961)}, {(-56.69291,0,25.51181),(-56.69291,0,12.7559),(-42.51969,0,6.377957),(-42.51969,0,4.251961)} },{ {(-56.69291,0,25.51181),(-56.69291,0,12.7559),(-42.51969,0,6.377957),(-42.51969,0,4.251961)}, {(-56.69291,31.74803,25.51181),(-56.69291,31.74803,12.7559),(-42.51969,23.81102,6.377957),(-42.51969,23.81102,4.251961)}, {(-31.74803,56.69291,25.51181),(-31.74803,56.69291,12.7559),(-23.81102,42.51969,6.377957),(-23.81102,42.51969,4.251961)}, {(0,56.69291,25.51181),(0,56.69291,12.7559),(0,42.51969,6.377957),(0,42.51969,4.251961)} },{ {(0,56.69291,25.51181),(0,56.69291,12.7559),(0,42.51969,6.377957),(0,42.51969,4.251961)}, {(31.74803,56.69291,25.51181),(31.74803,56.69291,12.7559),(23.81102,42.51969,6.377957),(23.81102,42.51969,4.251961)}, {(56.69291,31.74803,25.51181),(56.69291,31.74803,12.7559),(42.51969,23.81102,6.377957),(42.51969,23.81102,4.251961)}, {(56.69291,0,25.51181),(56.69291,0,12.7559),(42.51969,0,6.377957),(42.51969,0,4.251961)} },{ {(-45.35433,0,57.40157),(-65.19685,0,57.40157),(-76.53543,0,57.40157),(-76.53543,0,51.02362)}, {(-45.35433,-8.503932,57.40157),(-65.19685,-8.503932,57.40157),(-76.53543,-8.503932,57.40157),(-76.53543,-8.503932,51.02362)}, {(-42.51969,-8.503932,63.77952),(-70.86614,-8.503932,63.77952),(-85.03937,-8.503932,63.77952),(-85.03937,-8.503932,51.02362)}, {(-42.51969,0,63.77952),(-70.86614,0,63.77952),(-85.03937,0,63.77952),(-85.03937,0,51.02362)} },{ {(-42.51969,0,63.77952),(-70.86614,0,63.77952),(-85.03937,0,63.77952),(-85.03937,0,51.02362)}, {(-42.51969,8.503932,63.77952),(-70.86614,8.503932,63.77952),(-85.03937,8.503932,63.77952),(-85.03937,8.503932,51.02362)}, {(-45.35433,8.503932,57.40157),(-65.19685,8.503932,57.40157),(-76.53543,8.503932,57.40157),(-76.53543,8.503932,51.02362)}, {(-45.35433,0,57.40157),(-65.19685,0,57.40157),(-76.53543,0,57.40157),(-76.53543,0,51.02362)} },{ {(-76.53543,0,51.02362),(-76.53543,0,44.64566),(-70.86614,0,31.88976),(-56.69291,0,25.51181)}, {(-76.53543,-8.503932,51.02362),(-76.53543,-8.503932,44.64566),(-70.86614,-8.503932,31.88976),(-56.69291,-8.503932,25.51181)}, {(-85.03937,-8.503932,51.02362),(-85.03937,-8.503932,38.26771),(-75.11811,-8.503932,26.5748),(-53.85826,-8.503932,17.00787)}, {(-85.03937,0,51.02362),(-85.03937,0,38.26771),(-75.11811,0,26.5748),(-53.85826,0,17.00787)} },{ {(-85.03937,0,51.02362),(-85.03937,0,38.26771),(-75.11811,0,26.5748),(-53.85826,0,17.00787)}, {(-85.03937,8.503932,51.02362),(-85.03937,8.503932,38.26771),(-75.11811,8.503932,26.5748),(-53.85826,8.503932,17.00787)}, {(-76.53543,8.503932,51.02362),(-76.53543,8.503932,44.64566),(-70.86614,8.503932,31.88976),(-56.69291,8.503932,25.51181)}, {(-76.53543,0,51.02362),(-76.53543,0,44.64566),(-70.86614,0,31.88976),(-56.69291,0,25.51181)} },{ {(48.18897,0,40.3937),(73.70078,0,40.3937),(65.19685,0,59.52755),(76.53543,0,68.0315)}, {(48.18897,-18.70866,40.3937),(73.70078,-18.70866,40.3937),(65.19685,-7.086619,59.52755),(76.53543,-7.086619,68.0315)}, {(48.18897,-18.70866,17.00787),(87.87401,-18.70866,23.38582),(68.0315,-7.086619,57.40157),(93.5433,-7.086619,68.0315)}, {(48.18897,0,17.00787),(87.87401,0,23.38582),(68.0315,0,57.40157),(93.5433,0,68.0315)} },{ {(48.18897,0,17.00787),(87.87401,0,23.38582),(68.0315,0,57.40157),(93.5433,0,68.0315)}, {(48.18897,18.70866,17.00787),(87.87401,18.70866,23.38582),(68.0315,7.086619,57.40157),(93.5433,7.086619,68.0315)}, {(48.18897,18.70866,40.3937),(73.70078,18.70866,40.3937),(65.19685,7.086619,59.52755),(76.53543,7.086619,68.0315)}, {(48.18897,0,40.3937),(73.70078,0,40.3937),(65.19685,0,59.52755),(76.53543,0,68.0315)} },{ {(76.53543,0,68.0315),(79.37007,0,70.15748),(82.20472,0,70.15748),(79.37007,0,68.0315)}, {(76.53543,-7.086619,68.0315),(79.37007,-7.086619,70.15748),(82.20472,-4.251961,70.15748),(79.37007,-4.251961,68.0315)}, {(93.5433,-7.086619,68.0315),(99.92125,-7.086619,70.68897),(97.79527,-4.251961,71.22047),(90.70866,-4.251961,68.0315)}, {(93.5433,0,68.0315),(99.92125,0,70.68897),(97.79527,0,71.22047),(90.70866,0,68.0315)} },{ {(93.5433,0,68.0315),(99.92125,0,70.68897),(97.79527,0,71.22047),(90.70866,0,68.0315)}, {(93.5433,7.086619,68.0315),(99.92125,7.086619,70.68897),(97.79527,4.251961,71.22047),(90.70866,4.251961,68.0315)}, {(76.53543,7.086619,68.0315),(79.37007,7.086619,70.15748),(82.20472,4.251961,70.15748),(79.37007,4.251961,68.0315)}, {(76.53543,0,68.0315),(79.37007,0,70.15748),(82.20472,0,70.15748),(79.37007,0,68.0315)} },{ {(0,0,89.29133),(22.67716,0,89.29133),(0,0,80.7874),(5.669294,0,76.53543)}, {(0,0,89.29133),(22.67716,-12.7559,89.29133),(0,0,80.7874),(5.669294,-3.174809,76.53543)}, {(0,0,89.29133),(12.7559,-22.67716,89.29133),(0,0,80.7874),(3.174809,-5.669294,76.53543)}, {(0,0,89.29133),(0,-22.67716,89.29133),(0,0,80.7874),(0,-5.669294,76.53543)} },{ {(0,0,89.29133),(0,-22.67716,89.29133),(0,0,80.7874),(0,-5.669294,76.53543)}, {(0,0,89.29133),(-12.7559,-22.67716,89.29133),(0,0,80.7874),(-3.174809,-5.669294,76.53543)}, {(0,0,89.29133),(-22.67716,-12.7559,89.29133),(0,0,80.7874),(-5.669294,-3.174809,76.53543)}, {(0,0,89.29133),(-22.67716,0,89.29133),(0,0,80.7874),(-5.669294,0,76.53543)} },{ {(0,0,89.29133),(-22.67716,0,89.29133),(0,0,80.7874),(-5.669294,0,76.53543)}, {(0,0,89.29133),(-22.67716,12.7559,89.29133),(0,0,80.7874),(-5.669294,3.174809,76.53543)}, {(0,0,89.29133),(-12.7559,22.67716,89.29133),(0,0,80.7874),(-3.174809,5.669294,76.53543)}, {(0,0,89.29133),(0,22.67716,89.29133),(0,0,80.7874),(0,5.669294,76.53543)} },{ {(0,0,89.29133),(0,22.67716,89.29133),(0,0,80.7874),(0,5.669294,76.53543)}, {(0,0,89.29133),(12.7559,22.67716,89.29133),(0,0,80.7874),(3.174809,5.669294,76.53543)}, {(0,0,89.29133),(22.67716,12.7559,89.29133),(0,0,80.7874),(5.669294,3.174809,76.53543)}, {(0,0,89.29133),(22.67716,0,89.29133),(0,0,80.7874),(5.669294,0,76.53543)} },{ {(5.669294,0,76.53543),(11.33858,0,72.28346),(36.85039,0,72.28346),(36.85039,0,68.0315)}, {(5.669294,-3.174809,76.53543),(11.33858,-6.349609,72.28346),(36.85039,-20.63622,72.28346),(36.85039,-20.63622,68.0315)}, {(3.174809,-5.669294,76.53543),(6.349609,-11.33858,72.28346),(20.63622,-36.85039,72.28346),(20.63622,-36.85039,68.0315)}, {(0,-5.669294,76.53543),(0,-11.33858,72.28346),(0,-36.85039,72.28346),(0,-36.85039,68.0315)} },{ {(0,-5.669294,76.53543),(0,-11.33858,72.28346),(0,-36.85039,72.28346),(0,-36.85039,68.0315)}, {(-3.174809,-5.669294,76.53543),(-6.349609,-11.33858,72.28346),(-20.63622,-36.85039,72.28346),(-20.63622,-36.85039,68.0315)}, {(-5.669294,-3.174809,76.53543),(-11.33858,-6.349609,72.28346),(-36.85039,-20.63622,72.28346),(-36.85039,-20.63622,68.0315)}, {(-5.669294,0,76.53543),(-11.33858,0,72.28346),(-36.85039,0,72.28346),(-36.85039,0,68.0315)}, },{ {(-5.669294,0,76.53543),(-11.33858,0,72.28346),(-36.85039,0,72.28346),(-36.85039,0,68.0315)}, {(-5.669294,3.174809,76.53543),(-11.33858,6.349609,72.28346),(-36.85039,20.63622,72.28346),(-36.85039,20.63622,68.0315)}, {(-3.174809,5.669294,76.53543),(-6.349609,11.33858,72.28346),(-20.63622,36.85039,72.28346),(-20.63622,36.85039,68.0315)}, {(0,5.669294,76.53543),(0,11.33858,72.28346),(0,36.85039,72.28346),(0,36.85039,68.0315)} },{ {(0,5.669294,76.53543),(0,11.33858,72.28346),(0,36.85039,72.28346),(0,36.85039,68.0315)}, {(3.174809,5.669294,76.53543),(6.349609,11.33858,72.28346),(20.63622,36.85039,72.28346),(20.63622,36.85039,68.0315)}, {(5.669294,3.174809,76.53543),(11.33858,6.349609,72.28346),(36.85039,20.63622,72.28346),(36.85039,20.63622,68.0315)}, {(5.669294,0,76.53543),(11.33858,0,72.28346),(36.85039,0,72.28346),(36.85039,0,68.0315)}, },{ {(0,0,0),(40.3937,0,0),(42.51969,0,2.12598),(42.51969,0,4.251961)}, {(0,0,0),(40.3937,22.62047,0),(42.51969,23.81102,2.12598),(42.51969,23.81102,4.251961)}, {(0,0,0),(22.62047,40.3937,0),(23.81102,42.51969,2.12598),(23.81102,42.51969,4.251961)}, {(0,0,0),(0,40.3937,0),(0,42.51969,2.12598),(0,42.51969,4.251961)} },{ {(0,0,0),(0,40.3937,0),(0,42.51969,2.12598),(0,42.51969,4.251961)}, {(0,0,0),(-22.62047,40.3937,0),(-23.81102,42.51969,2.12598),(-23.81102,42.51969,4.251961)}, {(0,0,0),(-40.3937,22.62047,0),(-42.51969,23.81102,2.12598),(-42.51969,23.81102,4.251961)}, {(0,0,0),(-40.3937,0,0),(-42.51969,0,2.12598),(-42.51969,0,4.251961)} },{ {(0,0,0),(-40.3937,0,0),(-42.51969,0,2.12598),(-42.51969,0,4.251961)}, {(0,0,0),(-40.3937,-22.62047,0),(-42.51969,-23.81102,2.12598),(-42.51969,-23.81102,4.251961)}, {(0,0,0),(-22.62047,-40.3937,0),(-23.81102,-42.51969,2.12598),(-23.81102,-42.51969,4.251961)}, {(0,0,0),(0,-40.3937,0),(0,-42.51969,2.12598),(0,-42.51969,4.251961)} },{ {(0,0,0),(0,-40.3937,0),(0,-42.51969,2.12598),(0,-42.51969,4.251961)}, {(0,0,0),(22.62047,-40.3937,0),(23.81102,-42.51969,2.12598),(23.81102,-42.51969,4.251961)}, {(0,0,0),(40.3937,-22.62047,0),(42.51969,-23.81102,2.12598),(42.51969,-23.81102,4.251961)}, {(0,0,0),(40.3937,0,0),(42.51969,0,2.12598),(42.51969,0,4.251961)} } }; draw(surface(Q),blue,render(compression=Low)); asymptote-2.37/examples/tensor.asy000066400000000000000000000004571265434602500173550ustar00rootroot00000000000000size(200); pen[][] p={{red,green,blue,cyan},{blue,green,magenta,rgb(black)}}; path G=(0,0){dir(-120)}..(1,0)..(1,1)..(0,1)..cycle; path[] g={G,subpath(G,2,1)..(2,0)..(2,1)..cycle}; pair[][] z={{(0.5,0.5),(0.5,0.5),(0.5,0.5),(0.5,0.5)},{(2,0.5),(2,0.5),(1.5,0.5),(2,0.5)}}; tensorshade(g,p,z); dot(g); asymptote-2.37/examples/tetra.asy000066400000000000000000000010431265434602500171520ustar00rootroot00000000000000import graph3; unitsize(1cm); currentprojection=orthographic(10,5,5); triple O=(0,0,0),N=(0,0,10),A=(8.66,0,-5), B=(-4.33,7.5,-5),C=(-4.33,-7.5,-5); path3[] D=N--A--B--C--N--B^^A--C; draw(surface(A--B--C--cycle),.5*blue+.5*white+opacity(.5)); draw(surface(N--B--C--cycle),.5*green+.5*white+opacity(.5)); draw(surface(N--C--A--cycle),.5*yellow+.5*white+opacity(.5)); draw(surface(N--A--B--cycle),.5*red+.5*white+opacity(.5)); draw(D,blue+1bp); dot(D);dot(O); label("$O$",O,E);label("$N$",N,N);label("$A$",A,SE);label("$B$",B,E);label("$C$",C,W+S); asymptote-2.37/examples/textpath.asy000066400000000000000000000004701265434602500176770ustar00rootroot00000000000000size(300); fill(texpath(Label("test",TimesRoman())),pink); fill(texpath(Label("test",fontcommand('.fam T\n.ps 12')),tex=false),red); pair z=10S; fill(texpath(Label("$ \sqrt{x^2} $",z,TimesRoman())),pink); fill(texpath(Label("$ sqrt {x sup 2} $",z,fontcommand('.fam T\n.ps 12')), tex=false),red); asymptote-2.37/examples/thermodynamics.asy000066400000000000000000000237421265434602500210730ustar00rootroot00000000000000// example file for roundedpath() in roundedpath.asy // written by stefan knorr // import needed packages import roundedpath; // function definition picture CreateKOOS(real Scale, string legend) // draw labeled coordinate system as picture { picture ReturnPic; real S = 1.2*Scale; draw(ReturnPic, ((-S,0)--(S,0)), bar = EndArrow); // x axis draw(ReturnPic, ((0,-S)--(0,S)), bar = EndArrow); // y axis label(ReturnPic, "$\varepsilon$", (S,0), SW); // x axis label label(ReturnPic, "$\sigma$", (0,S), SW); // y axis label label(ReturnPic, legend, (0.7S, -S), NW); // add label 'legend' return ReturnPic; // return picture } // some global definitions real S = 13mm; // universal scale factor for the whole file real grad = 0.25; // gradient for lines real radius = 0.04; // radius for the rounded path' real lw = 2; // linewidth pair A = (-1, -1); // start point for graphs pair E = ( 1, 1); // end point for graphs path graph; // local graph pen ActPen; // actual pen for each drawing picture T[]; // vector of all four diagrams real inc = 2.8; // increment-offset for combining pictures //////////////////////////////////////// 1st diagram T[1] = CreateKOOS(S, "$T_1$"); // initialise T[1] as empty diagram with label $T_1$ graph = A; // # pointwise definition of current path 'graph' graph = graph -- (A.x + grad*1.6, A.y + 1.6); // # graph = graph -- (E.x - grad*0.4, E.y - 0.4); // # graph = graph -- E; // # graph = roundedpath(graph, radius, S); // round edges of 'graph' using roundedpath() in roundedpath.asy ActPen = rgb(0,0,0.6) + linewidth(lw); // define pen for drawing in 1st diagram draw(T[1], graph, ActPen); // draw 'graph' with 'ActPen' into 'T[1]' (1st hysteresis branch) draw(T[1], rotate(180,(0,0))*graph, ActPen); // draw rotated 'graph' (2nd hysteresis branch) graph = (0,0) -- (grad*0.6, 0.6) -- ( (grad*0.6, 0.6) + (0.1, 0) ); // define branch from origin to hysteresis graph = roundedpath(graph, radius, S); // round this path draw(T[1], graph, ActPen); // draw this path into 'T[1]' //////////////////////////////////////// 2nd diagram T[2] = CreateKOOS(S, "$T_2$"); // initialise T[2] as empty diagram with label $T_2$ graph = A; // # pointwise definition of current path 'graph' graph = graph -- (A.x + grad*1.3, A.y + 1.3); // # graph = graph -- (E.x - grad*0.7 , E.y - 0.7); // # graph = graph -- E; // # graph = roundedpath(graph, radius, S); // round edges of 'graph' using roundedpath() in roundedpath.asy ActPen = rgb(0.2,0,0.4) + linewidth(lw); // define pen for drawing in 2nd diagram draw(T[2], graph, ActPen); // draw 'graph' with 'ActPen' into 'T[2]' (1st hysteresis branch) draw(T[2], rotate(180,(0,0))*graph, ActPen); // draw rotated 'graph' (2nd hysteresis branch) graph = (0,0) -- (grad*0.3, 0.3) -- ( (grad*0.3, 0.3) + (0.1, 0) ); // define branch from origin to hysteresis graph = roundedpath(graph, radius, S); // round this path draw(T[2], graph, ActPen); // draw this path into 'T[2]' //////////////////////////////////////// 3rd diagram T[3] = CreateKOOS(S, "$T_3$"); // initialise T[3] as empty diagram with label $T_3$ graph = A; // # pointwise definition of current path 'graph' graph = graph -- (A.x + grad*0.7, A.y + 0.7); // # graph = graph -- ( - grad*0.3 , - 0.3); // # graph = graph -- (0,0); // # graph = graph -- (grad*0.6, 0.6); // # graph = graph -- (E.x - grad*0.4, E.y - 0.4); // # graph = graph -- E; // # graph = roundedpath(graph, radius, S); // round edges of 'graph' using roundedpath() in roundedpath.asy ActPen = rgb(0.6,0,0.2) + linewidth(lw); // define pen for drawing in 3rd diagram draw(T[3], graph, ActPen); // draw 'graph' with 'ActPen' into 'T[3]' (1st hysteresis branch) draw(T[3], rotate(180,(0,0))*graph, ActPen); // draw rotated 'graph' (2nd hysteresis branch) //////////////////////////////////////// 4th diagram T[4] = CreateKOOS(S, "$T_4$"); // initialise T[4] as empty diagram with label $T_4$ graph = A; // # pointwise definition of current path 'graph' graph = graph -- (A.x + grad*0.4, A.y + 0.4); // # graph = graph -- ( - grad*0.6 , - 0.6); // # graph = graph -- (0,0); // # graph = graph -- (grad*0.9, 0.9); // # graph = graph -- (E.x - grad*0.1, E.y - 0.1); // # graph = graph -- E; // # graph = roundedpath(graph, radius, S); // round edges of 'graph' using roundedpath() in roundedpath.asy ActPen = rgb(0.6,0,0) + linewidth(lw); // define pen for drawing in 4th diagram draw(T[4], graph, ActPen); // draw 'graph' with 'ActPen' into 'T[4]' (1st hysteresis branch) draw(T[4], rotate(180,(0,0))*graph, ActPen); // draw rotated 'graph' (3nd hysteresis branch) // add some labels and black dots to the first two pictures pair SWW = (-0.8, -0.6); label(T[1], "$\sigma_f$", (0, 0.6S), NE); // sigma_f draw(T[1], (0, 0.6S), linewidth(3) + black); label(T[2], "$\sigma_f$", (0, 0.3S), NE); // sigma_f draw(T[2], (0, 0.3S), linewidth(3) + black); label(T[1], "$\varepsilon_p$", (0.7S, 0), SWW); // epsilon_p draw(T[1], (0.75S, 0), linewidth(3) + black); label(T[2], "$\varepsilon_p$", (0.7S, 0), SWW); // epsilon_p draw(T[2], (0.75S, 0), linewidth(3) + black); // add all pictures T[1...4] to the current one add(T[1],(0,0)); add(T[2],(1*inc*S,0)); add(T[3],(2*inc*S,0)); add(T[4],(3*inc*S,0)); // draw line of constant \sigma and all intersection points with the graphs in T[1...4] ActPen = linewidth(1) + dashed + gray(0.5); // pen definition draw((-S, 0.45*S)--((3*inc+1)*S, 0.45*S), ActPen); // draw backgoundline label("$\sigma_s$", (-S, 0.45S), W); // label 'sigma_s' path mark = scale(2)*unitcircle; // define mark-symbol to be used for intersections ActPen = linewidth(1) + gray(0.5); // define pen for intersection mark draw(shift(( 1 - grad*0.55 + 0*inc)*S, 0.45*S)*mark, ActPen); // # draw all intersections draw(shift((-1 + grad*1.45 + 0*inc)*S, 0.45*S)*mark, ActPen); // # draw(shift(( 1 - grad*0.55 + 1*inc)*S, 0.45*S)*mark, ActPen); // # draw(shift(( 1 - grad*0.55 + 2*inc)*S, 0.45*S)*mark, ActPen); // # draw(shift(( grad*0.45 + 2*inc)*S, 0.45*S)*mark, ActPen); // # draw(shift(( grad*0.45 + 3*inc)*S, 0.45*S)*mark, ActPen); // # asymptote-2.37/examples/threeviews.asy000066400000000000000000000011351265434602500202220ustar00rootroot00000000000000import three; picture pic; unitsize(pic,5cm); currentlight.viewport=false; if(settings.render < 0) settings.render=4; settings.toolbar=false; viewportmargin=(1cm,1cm); draw(pic,scale3(0.5)*unitsphere,green,render(compression=Low,merge=true)); draw(pic,Label("$x$",1),O--X); draw(pic,Label("$y$",1),O--Y); draw(pic,Label("$z$",1),O--Z); // Europe and Asia: //addViews(pic,ThreeViewsFR); //addViews(pic,SixViewsFR); // United Kingdom, United States, Canada, and Australia: addViews(pic,ThreeViewsUS); //addViews(pic,SixViewsUS); // Front, Top, Right, // Back, Bottom, Left: //addViews(pic,SixViews); asymptote-2.37/examples/torus.asy000066400000000000000000000006351265434602500172150ustar00rootroot00000000000000size(200); import graph3; currentprojection=perspective(5,4,4); real R=3; real a=1; /* import solids; revolution torus=revolution(reverse(Circle(R*X,a,Y,32)),Z,90,345); surface s=surface(torus); */ triple f(pair t) { return ((R+a*cos(t.y))*cos(t.x),(R+a*cos(t.y))*sin(t.x),a*sin(t.y)); } surface s=surface(f,(radians(90),0),(radians(345),2pi),8,8,Spline); draw(s,green,render(compression=Low,merge=true)); asymptote-2.37/examples/transparency.asy000066400000000000000000000003661265434602500205530ustar00rootroot00000000000000size(0,150); if(settings.outformat == "") settings.outformat="pdf"; begingroup(); fill(shift(1.5dir(120))*unitcircle,green+opacity(0.75)); fill(shift(1.5dir(60))*unitcircle,red+opacity(0.75)); fill(unitcircle,blue+opacity(0.75)); endgroup(); asymptote-2.37/examples/treetest.asy000066400000000000000000000011321265434602500176710ustar00rootroot00000000000000import drawtree; treeLevelStep = 2cm; TreeNode root = makeNode( "Root" ); TreeNode child1 = makeNode( root, "Child\_1" ); TreeNode child2 = makeNode( root, "Child\_2" ); TreeNode gchild1 = makeNode( child1, "Grandchild\_1" ); TreeNode gchild2 = makeNode( child1, "Grandchild\_2" ); TreeNode gchild3 = makeNode( child1, "Grandchild\_3" ); TreeNode gchild4 = makeNode( child1, "Grandchild\_4" ); TreeNode gchild11 = makeNode( child2, "Grandchild\_1" ); TreeNode gchild22 = makeNode( child2, "Grandchild\_2" ); TreeNode ggchild1 = makeNode( gchild1, "Great Grandchild\_1" ); draw( root, (0,0) ); asymptote-2.37/examples/trefoilknot.asy000066400000000000000000000011151265434602500203730ustar00rootroot00000000000000import tube; import graph3; import palette; currentlight=White; size(0,8cm); currentprojection=perspective(1,1,1,up=-Y); int e=1; real x(real t) {return cos(t)+2*cos(2t);} real y(real t) {return sin(t)-2*sin(2t);} real z(real t) {return 2*e*sin(3t);} path3 p=scale3(2)*graph(x,y,z,0,2pi,50,operator ..)&cycle; pen[] pens=Gradient(6,red,blue,purple); pens.push(yellow); for (int i=pens.length-2; i >= 0 ; --i) pens.push(pens[i]); path sec=scale(0.25)*texpath("$\pi$")[0]; coloredpath colorsec=coloredpath(sec, pens,colortype=coloredNodes); draw(tube(p,colorsec),render(merge=true)); asymptote-2.37/examples/triads.asy000066400000000000000000000016771265434602500173360ustar00rootroot00000000000000import graph; path p=(10,75)..(15,85)..(20,90)..(35,85)..(40,79)--(78,30)..(85,15)..(87,5); pair l=point(p,3.5); pair m=point(p,4.5); pair s=point(p,4.9); pen c=linewidth(1.5); pair o=(m.x,0.5(m.x+l.y)); pen d=c+darkgreen; void drawarrow(string s="", pair p, pair q, side side=RightSide, bool upscale=false, pen c) { path g=p{dir(-5)}..{dir(-85)}q; if(upscale) g=reverse(g); draw(s,g,side,c,Arrow(Fill,0.65)); } void spectrum(pair l,pair m, pair s) { draw(p,c); d += 4.0; dot("$p$",l,SW,d); dot("$q$",m,SW,d); dot("$k$",s,SW,d); xaxis("$k$",0); yaxis("$E(k)$",0); } drawarrow("$T_p$",l,m,true,blue); drawarrow("$T_k$",m,s,LeftSide,red); spectrum(l,m,s); shipout("triadpqk"); erase(); drawarrow("$-T_p$",l,m,LeftSide,red); drawarrow("$-T_q$",m,s,true,blue); spectrum(l,s,m); shipout("triadpkq"); erase(); drawarrow("$T_k$",l,m,true,blue); drawarrow("$T_q$",m,s,LeftSide,red); spectrum(m,s,l); shipout("triadkpq"); asymptote-2.37/examples/triangle.asy000066400000000000000000000003211265434602500176360ustar00rootroot00000000000000size(0,100); import geometry; triangle t=triangle(b=3,alpha=90,c=4); dot((0,0)); draw(t); draw(rotate(90)*t,red); draw(shift((-4,0))*t,blue); draw(reflect((0,0),(1,0))*t,green); draw(slant(2)*t,magenta); asymptote-2.37/examples/triangles.asy000066400000000000000000000007071265434602500200310ustar00rootroot00000000000000import three; size(10cm); triple[] v={O,X,X+Y,Y}; triple[] n={Z,X}; int[][] vi={{0,1,2},{2,3,0}}; int[][] ni={{0,0,0},{1,1,1}}; pen[] p={red+opacity(0.5),green+opacity(0.5),blue+opacity(0.5), black+opacity(0.5)}; // Adobe Reader exhibits a PRC rendering bug for opacities in (0.5,1): //pen[] p={red+opacity(0.9),green+opacity(0.9),blue+opacity(0.9),black+opacity(0.9)}; int[][] pi={{0,1,2},{2,3,0}}; draw(v,vi,n,ni,red); draw(v+Z,vi,p,pi); asymptote-2.37/examples/triceratops.asy000066400000000000000000000003731265434602500203770ustar00rootroot00000000000000import obj; size(15cm); currentprojection=orthographic(0,2,5,up=Y); // A compressed version of the required data file may be obtained from: // http://www.cs.technion.ac.il/~irit/data/Viewpoint/triceratops.obj.gz draw(obj("triceratops.obj",brown)); asymptote-2.37/examples/trumpet.asy000066400000000000000000000004431265434602500175360ustar00rootroot00000000000000import graph3; size(200,0); currentlight=Viewport; triple f(pair t) { real u=log(abs(tan(t.y/2))); return (10*sin(t.y),cos(t.x)*(cos(t.y)+u),sin(t.x)*(cos(t.y)+u)); } surface s=surface(f,(0,pi/2),(2pi,pi-0.1),7,15,Spline); draw(s,olive+0.25*white,render(compression=Low,merge=true)); asymptote-2.37/examples/truncatedIcosahedron.asy000066400000000000000000000040441265434602500222070ustar00rootroot00000000000000import graph3; size(200); defaultrender.merge=true; real c=(1+sqrt(5))/2; triple[] z={(c,1,0),(-c,1,0),(-c,-1,0),(c,-1,0)}; triple[] x={(0,c,1),(0,-c,1),(0,-c,-1),(0,c,-1)}; triple[] y={(1,0,c),(1,0,-c),(-1,0,-c),(-1,0,c)}; triple[][] Q={ {(c,1,0),(1,0,-c),(0,c,-1),(0,c,1),(1,0,c),(c,-1,0)}, {(-c,1,0),(0,c,1),(0,c,-1),(-1,0,-c),(-c,-1,0),(-1,0,c)}, {(-c,-1,0),(-c,1,0),(-1,0,-c),(0,-c,-1),(0,-c,1),(-1,0,c)}, {(c,-1,0),(c,1,0),(1,0,c),(0,-c,1),(0,-c,-1),(1,0,-c)}, {(0,c,1),(0,c,-1),(-c,1,0),(-1,0,c),(1,0,c),(c,1,0)}, {(0,-c,1),(0,-c,-1),(-c,-1,0),(-1,0,c),(1,0,c),(c,-1,0)}, {(0,-c,-1),(0,-c,1),(c,-1,0),(1,0,-c),(-1,0,-c),(-c,-1,0)}, {(0,c,-1),(0,c,1),(c,1,0),(1,0,-c),(-1,0,-c),(-c,1,0)}, {(1,0,c),(-1,0,c),(0,-c,1),(c,-1,0),(c,1,0),(0,c,1)}, {(1,0,-c),(-1,0,-c),(0,-c,-1),(c,-1,0),(c,1,0),(0,c,-1)}, {(-1,0,-c),(1,0,-c),(0,c,-1),(-c,1,0),(-c,-1,0),(0,-c,-1)}, {(-1,0,c),(1,0,c),(0,c,1),(-c,1,0),(-c,-1,0),(0,-c,1)} }; real R=abs(interp(Q[0][0],Q[0][1],1/3)); triple[][] P; for(int i=0; i < Q.length; ++i) { P[i]=new triple[] ; for(int j=0; j < Q[i].length; ++j) { P[i][j]=Q[i][j]/R; } } for(int i=0; i < P.length; ++i) { for(int j=1; j < P[i].length; ++j) { triple C=P[i][0]; triple A=P[i][j]; triple B=P[i][j % 5+1]; triple[] sixout=new triple[] {interp(C,A,1/3),interp(C,A,2/3),interp(A,B,1/3),interp(A,B,2/3), interp(B,C,1/3),interp(B,C,2/3)}; triple M=(sum(sixout))/6; triple[] sixin=sequence(new triple(int k) { return interp(sixout[k],M,0.1); },6); draw(surface(reverse(operator--(...sixout)--cycle)^^ operator--(...sixin)--cycle,planar=true),magenta); } } for(int i=0; i < P.length; ++i) { triple[] fiveout=sequence(new triple(int k) { return interp(P[i][0],P[i][k+1],1/3); },5); triple M=(sum(fiveout))/5; triple[] fivein=sequence(new triple(int k) { return interp(fiveout[k],M,0.1); },5); draw(surface(reverse(operator--(...fiveout)--cycle)^^ operator--(...fivein)--cycle,planar=true),cyan); } asymptote-2.37/examples/tvgen.asy000066400000000000000000001166061265434602500171720ustar00rootroot00000000000000/* tvgen - draw pm5544-like television test cards. * Copyright (C) 2007, 2009, 2012, Servaas Vandenberghe. * * The tvgen code below is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with tvgen: see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * * tvgen-1.2/tvgen.asy http://picaros.org/ftp/soft/tvgen-1.2.tgz * This asy script generates pm5544-like television test cards. The image * parameters were derived from a 1990 recording. The basic parameters * conform to itu-r bt.470, bt.601, and bt.709. There is no unique image * since local variants exist and parameters have varied over time. */ //papertype="a4"; import plain; int verbose=settings.verbose/*+2*/; /* uncomment for debug info */ /* tv dot coordinates --> PS points */ pair tvps(real col, real row, real xd, real yd, int Nv) { real psx, psy; psx=col*xd; psy=(Nv-row)*yd; return (psx,psy); } path tvrect(int lc, int tr, int rc, int br, real xd, real yd, int Nv) { real lx, ty, rx, by; pair[] z; lx=lc*xd; ty=(Nv-tr)*yd; rx=rc*xd; by=(Nv-br)*yd; /* bl br tr tl */ z[0]=(lx, by); z[1]=(rx, by); z[2]=(rx, ty); z[3]=(lx, ty); return z[0]--z[1]--z[2]--z[3]--cycle; } /********************* horizontal castellations ********************/ /* Draw a horizontal red line in the top left and the bottom right * castellation. These testlines disappear if the monitor is not set * in a dot-exact mode. An example is image crop due to overscan. * * For 625 line systems any analog-compatible processing removes * these red testlines since the first halfline of the odd field and * the last halfline of the even field are ignored. A full 576 * visible line frame often results via a final copy paste operation. */ void castelhor(int colortv, int[] rccoll, int[] rccolr, int cmaxi, int Nh, int topdist, int botdist, pen pdef, real xd, real yd, int Nv) { pen pblack, pwhite, pred; int i; pblack = pdef+gray(0.0); pwhite = pdef+gray(1.0); pred = pdef+rgb(0.75, 0, 0); /** top and bottom: white corners. **/ for (i=-1; i<=cmaxi; ++i) { pen pcast; int inext, lc, rc, tr, br; path zzc; inext = i+1; if (inext%2 == 0) { pcast = pwhite; } else { pcast = pblack; } if (i >= 0) { lc = rccolr[i]; } else { lc = 0; } if (inext <= cmaxi) { rc = rccoll[inext]; } else { rc = Nh; } if (i == 0 && colortv > 0 && topdist > 1) { path zzr; zzr = tvrect(lc,0, rc,1, xd,yd,Nv); fill(zzr, p=pred); tr = 1; } else { tr = 0; } zzc = tvrect(lc,tr, rc,topdist, xd,yd,Nv); fill(zzc, p=pcast); if (inext == cmaxi && colortv > 0 && botdist+1 < Nv) { path zzr; zzr = tvrect(lc,Nv-1, rc,Nv, xd,yd,Nv); fill(zzr, p=pred); br = Nv-1; } else { br = Nv; } zzc = tvrect(lc,botdist, rc,br, xd,yd,Nv); fill(zzc, p=pcast); } return; } /********************* vertical castellations ********************/ /* The bottom right red rectangle tests for a non causal color FIR * filter in the receiver. The last 2..4 dots then typically appear * colorless, green, or cyan. * * This stems from the fact that the chroma subcarrier is of lower * bandwidth than luma and thus continues after the last active sample. * These trailing (y,u,v) samples result from an abrupt signal to zero * transition and depend on the transmit and receive filters. Samples * from VHS, system B/G/D/K, system I, or a DVD player output are * different. Nevertheless, a sharpening filter uses this data and so * adds false color to the last dots. */ void castelver(int colortv, int leftdist, int rightdist, int Nh, int[] rcrowb, int[] rcrowt, int rmaxi, pen pdef, real xd, real yd, int Nv) { pen pblack, pwhite; int i; pblack = pdef+gray(0.0); pwhite = pdef+gray(1.0); for (i=0; i0) { pcastr = pdef+rgb(0.75,0.0,0); } else { pcastr = pcastl; } tr=rcrowb[i]; br=rcrowt[i+1]; zzc=tvrect( 0,tr, leftdist,br, xd,yd,Nv); fill(zzc, p=pcastl); zzc=tvrect(rightdist,tr, Nh,br, xd,yd,Nv); fill(zzc, p=pcastr); } return; } /********************* image aspect ratio markers ********************/ void rimarkers(real rimage, int Nh, int Nhc, int os, int Nvc, int Nsy, pen pdef, real xd, real yd, int Nv) { int[] ridefN={ 4, 16 }; int[] ridefD={ 3, 9 }; int i; for (i=0; i<2; ++i) { real rid=ridefN[i]/ridefD[i]; if (rimage>rid) { int off, offa, offb; /* Nhdef=Nh*rid/rimage */ off=round(Nh*rid/rimage/2); offa=off+os; offb=off-os; // write(offa,offb); if (2*offa 0) { /* black, vertical gridlines redrawn below */ pair[] z; int col; z[0]=rcright[divsy]; col = rccolc[divsx+1]; z[1]=tvps(col,rcrowc[divsy], xd,yd,Nv); z[2]=tvps(col,rcrowc[divsy-1], xd,yd,Nv); col = rccolc[divsx]; z[3]=tvps(col,rcrowc[divsy-1], xd,yd,Nv); z[4]=tvps(col,rcrowc[divsy], xd,yd,Nv); z[5]=rcleft[divsy]; z[6]=rcleft[divsy+1]; z[7]=tvps(col,rcrowc[divsy+1], xd,yd,Nv); z[8]=tvps(col,rcrowc[divsy+2], xd,yd,Nv); col = rccolc[divsx+1]; z[9]=tvps(col,rcrowc[divsy+2], xd,yd,Nv); z[10]=tvps(col,rcrowc[divsy+1], xd,yd,Nv); z[11]=rcright[divsy+1]; fill(z[1]--z[2]--z[3]--z[4] //--z[5]--z[6] --arc(ccenter, z[5], z[6]) --z[7]--z[8]--z[9]--z[10] //--z[11]--z[0] --arc(ccenter,z[11], z[0]) --cycle, p=pblack); } else { /* 3 rows of black squares inside the gratings */ int i, imax = divsy+1; for (i=divsy-1; i<=imax; ++i) { /* all 3 rows */ int lmaxoff, lmincol, lmaxcol; int inext = i+1; int tr, br, j; /* XXX rcoff is relative to ccenter */ lmaxoff = min(floor(rcoff[i]), floor(rcoff[inext])); lmincol = Nhc-lmaxoff; lmaxcol = Nhc+lmaxoff; /* square top and bottom */ tr = rcrowb[i]; br = rcrowt[inext]; for (j=0; j 1) { write("centerline long : rows tr br ", rows, tr, br); } zz=tvrect(Nhc-os, tr, Nhc+os, br, xd,yd,Nv); fill(zz, p=pwhite); zz=tvrect(Nhc-maxoff,Nvc-1, Nhc+maxoff,Nvc+1, xd,yd,Nv); fill(zz, p=pwhite); /* vertical short lines */ rows=min(Nvc-rcrowc[divsy], rcrowc[divsy+1]-Nvc); tr=Nvc-rows; br=Nvc+rows; if (verbose > 1) { write("centerline short: rows tr br ", rows, tr, br); } if (colortv > 0) { int i; for (i=0; i<=cmaxi; ++i) { int coll, colr; coll=rccoll[i]; colr=rccolr[i]; if (mincol<=coll && colr<=maxcol) { path zzv; zzv=tvrect(coll, tr, colr, br, xd,yd,Nv); fill(zzv, p=pwhite); } } } return; } /************************ topbw **************************************/ void topbw(int[] coff, int Nhc, int os, int urow, int trow, int brow, pair ccenter, pair rclt, pair rclb, pair rcrt, pair rcrb, pen pdef, real xd, real yd, int Nv) { pen pblack=pdef+gray(0.0), pwhite=pdef+gray(1.0); pair[] ze; path zext, zref, zint; int off, col, cr; off=ceil((coff[2]+coff[3])/2); ze[0]=tvps(Nhc+off,trow, xd,yd,Nv); ze[1]=rcrt; ze[2]=rclt; ze[3]=tvps(Nhc-off,trow, xd,yd,Nv); ze[4]=tvps(Nhc-off,brow, xd,yd,Nv); col=Nhc-coff[2]-os; ze[5]=tvps(col,brow, xd,yd,Nv); ze[6]=tvps(col,trow, xd,yd,Nv); cr=col+3*os; /* reflection test black pulse */ zref=tvrect(col,trow, cr,brow, xd,yd,Nv); ze[7]=tvps(cr,trow, xd,yd,Nv); ze[8]=tvps(cr,brow, xd,yd,Nv); ze[9]=tvps(Nhc+off,brow, xd,yd,Nv); //dot(ze); zext=ze[0] // --ze[1]--ze[2] --arc(ccenter, ze[1], ze[2]) --ze[3]--ze[4]--ze[5]--ze[6]--ze[7]--ze[8]--ze[9]--cycle; off=ceil((coff[1]+coff[2])/2); zint=tvrect(Nhc-off,urow, Nhc+off,trow, xd,yd,Nv); /* paths are completely resolved; no free endpoint conditions */ fill(zext^^reverse(zint), p=pwhite); fill(zint, p=pblack); fill(zref, p=pblack); fill(arc(ccenter,rclt,rclb)--ze[4]--ze[3]--cycle, p=pblack); fill(arc(ccenter,rcrb,rcrt)--ze[0]--ze[9]--cycle, p=pblack); return; } /************************ testtone **************************************/ /* x on circle -> return y>=0 * in: * x x-coordinate relative to origin * crad circle radius in y units, true size=crad*yd */ real testcircx(real x, real crad, real xd, real yd) { real relx, ph, y; relx=x*xd/yd/crad; if (relx>1) { ph=0; } else { ph=acos(relx); } y=crad*sin(ph); // or (x*xd)^2+(y*yd)^2=(crad*yd)^2 return y; } /* y on circle -> return x>=0 */ real testcircy(real y, real crad, real xd, real yd) { real rely, ph, x; rely=y/crad; if (rely>1) { ph=pi/2; } else { ph=asin(rely); } x=crad*cos(ph)*yd/xd; // or (x*xd)^2+(y*yd)^2=(crad*yd)^2 return x; } /* brow>trow && xb>xt */ void testtone(real Tt, int trow, int brow, real ccol, real crow, real crad, pen pdef, real xd, real yd, int Nv) { int blocks, i; real yt, xt, yb, xb, Ttt=Tt/2; pair ccenter; yt=crow-trow; xt=testcircy(yt, crad, xd, yd); yb=crow-brow; xb=testcircy(yb, crad, xd, yd); //write('#xt yt\t',xt,yt); write('#xb yb\t',xb,yb); ccenter=tvps(ccol,crow, xd,yd,Nv); blocks=floor(2*xb/Tt); for (i=-blocks-1; i<=blocks; ++i) { real tl, tr; path zz; tl=max(-xb,min(i*Ttt,xb)); /* limit [-xb..xb] */ tr=max(-xb,min((i+1)*Ttt,xb)); if (tl<-xt && tr<=-xt || tr>xt && tl>=xt) { /* top full circle */ pair[] z; real yl, yr; yl=testcircx(tl, crad, xd, yd); yr=testcircx(tr, crad, xd, yd); z[0]=tvps(ccol+tl,brow, xd,yd,Nv); z[1]=tvps(ccol+tr,brow, xd,yd,Nv); z[2]=tvps(ccol+tr,crow-yr, xd,yd,Nv); z[3]=tvps(ccol+tl,crow-yl, xd,yd,Nv); zz=z[0]--z[1]--arc(ccenter,z[2],z[3])--cycle; } else if(tl<-xt) { /* tl in circel, tr not, partial */ pair[] z; real yl; yl=testcircx(tl, crad, xd, yd); z[0]=tvps(ccol+tl,brow, xd,yd,Nv); z[1]=tvps(ccol+tr,brow, xd,yd,Nv); z[2]=tvps(ccol+tr,trow, xd,yd,Nv); z[3]=tvps(ccol-xt,trow, xd,yd,Nv); z[4]=tvps(ccol+tl,crow-yl, xd,yd,Nv); zz=z[0]--z[1]--z[2]--arc(ccenter,z[3],z[4])--cycle; } else if(tr>xt) { /* tr in circle, tl not, partial */ pair[] z; real yr; yr=testcircx(tr, crad, xd, yd); z[0]=tvps(ccol+tl,brow, xd,yd,Nv); z[1]=tvps(ccol+tr,brow, xd,yd,Nv); z[2]=tvps(ccol+tr,crow-yr, xd,yd,Nv); z[3]=tvps(ccol+xt,trow, xd,yd,Nv); z[4]=tvps(ccol+tl,trow, xd,yd,Nv); zz=z[0]--z[1]--arc(ccenter,z[2],z[3])--z[4]--cycle; } else { /* full block */ pair[] z; z[0]=tvps(ccol+tr,trow, xd,yd,Nv); z[1]=tvps(ccol+tl,trow, xd,yd,Nv); z[2]=tvps(ccol+tl,brow, xd,yd,Nv); z[3]=tvps(ccol+tr,brow, xd,yd,Nv); zz=z[0]--z[1]--z[2]--z[3]--cycle; } if (tl1) { thetaret=0; } else { real dpi=2*pi; cycles-=coverflow*sgn(cycles); thetaret=theta+cycles*dpi; /* cycles=(-1 .. 1) */ if (thetaret>pi) { thetaret-=dpi; } else if (thetaret<-pi) { thetaret-=dpi; } } //write("addphase: ", step, theta, thetaret); return thetaret; } void testfreqs(real[] ftones, int[] coff, int Nhc, int trow,int crow,int brow, pair ccenter, pair rclt, pair rclb, pair rcrt, pair rcrb, pen pdef, real xd, real yd, int Nv) { int[] divc; real[] divfl, divfr; int i, divs, coffmax, off, divnext; real fl, fr, thr, thl; /* Segment info for PAL continental test card * segment i extends from (divc[i] .. divc[i+1]) with frequency divf[i] */ divs=2; // the number of segments to the right, total=2*divs+1 divc[0]=0; for (i=0; i<=divs; ++i) { int ii=i*2, il=divs-i, ir=divs+i; divc[i+1]=ceil((coff[ii]+coff[ii+1])/2); /* xdot distance to center */ divfl[i]=ftones[divs-i]; divfr[i]=ftones[divs+i]; } coffmax=divc[divs+1]; int trowlim=coff[0]; int tr; tr=crow; divnext=0; fl=0; fr=0; thl=0; /* ={ 0, -pi/2 } : initial angle at center vertical line Nhc */ thr=thl; /* draw a vertical line at off..off+1, use theta for off+1/2 */ for (off=0; off0) { if (verbose > 1) write("right ears"); cy=cyr; cu=cur; cv=cvr; } else { if (verbose > 1) write("left ears"); cy=cyl; cu=cul; cv=cvl; } lcol=Nhc+dright*coffa[5]; ccol=Nhc+dright*coff[6]; cicol=Nhc+dright*coffa[6]; rcol=Nhc+dright*coffb[7]; int urow, trow, crow, brow, arow; urow=rcrowb[divsy-5]; trow=rcrowt[divsy-3]; crow=Nvc; brow=rcrowb[divsy+4]; arow=rcrowt[divsy+6]; z[0]=tvps(ccol,urow, xd,yd,Nv); z[1]=tvps(ccol,trow, xd,yd,Nv); z[2]=tvps(cicol,trow, xd,yd,Nv); z[3]=tvps(cicol,crow, xd,yd,Nv); z[4]=tvps(rcol,crow, xd,yd,Nv); z[5]=tvps(rcol,urow, xd,yd,Nv); zz[0]=z[0]--z[1]--z[2]--z[3]--z[4]--z[5]--cycle; zz[1]=tvrect(lcol,urow, ccol,trow, xd,yd,Nv); zz[2]=tvrect(lcol,brow, ccol,arow, xd,yd,Nv); z[0]=tvps(ccol,arow, xd,yd,Nv); z[1]=tvps(ccol,brow, xd,yd,Nv); z[2]=tvps(cicol,brow, xd,yd,Nv); z[3]=tvps(cicol,crow, xd,yd,Nv); z[4]=tvps(rcol,crow, xd,yd,Nv); z[5]=tvps(rcol,arow, xd,yd,Nv); zz[3]=z[0]--z[1]--z[2]--z[3]--z[4]--z[5]--cycle; for (i=0; i<4; ++i) { real y, u, v, A, ph, By, Ry, Gy, R, G, B; y=cy[i]; u=cu[i]; v=cv[i]; A=hypot(u,v); ph= (u!=0 || v!=0) ? atan2(v,u) : 0.0; if (v>=0) { if (ph<0) ph=ph+pi; } else { if (ph>0) ph=ph-pi; } if (A>0) { u=u/A*cI; v=v/A*cI; } By=u/wu; Ry=v/wv; Gy=(-wr*Ry-wb*By)/wg; //write(y,Gy,A,ph*180/pi); R=Ry+y; G=Gy+y; B=By+y; if (verbose > 1) write(y*1000, round(R*1000), round(G*1000), round(B*1000)); fill(zz[i], p=pdef+rgb(R,G,B)); } return; } /****************************** NTSC bars ***********************************/ /* amplitude equals color burst smpte (pm: -V +U) * y campl sat R G B * left 0.5 0.21 70% -I? * right 0.5 0.17 60% +Q? */ void ntscbars(int[] rccoll, int[] rccolr, int divsx, int[] rcrowt, int[] rcrowb, int divsy, int dright, pen pdef, real xd, real yd, int Nv) { /* The amplitude of (i,q) as seen on a vectorscope, * max 0.292 Vn for 100% saturation in I==0 ears. * burst: 0.143 Vcvbs, 20 IRE or 0.200 V normalized. * pedestal: (yp,up,vp)=(p,0,0)+(1-p)*(y,u,v), p=0.075. * choice: equal amplitude for colorburst and subcarrier. */ real campl=0.200/0.925; /* wg=0.587, y=wr*R+wg*G+wb*B */ real wr=0.299, wb=0.114, wg=1-wr-wb; /* iT : iq -> RyBy : rotation+scaling */ real iT11=0.95, iT12=0.62, iT21=-1.11, iT22=1.71; /* bars -2 -1 0 1 2 */ real[] cyl={ 0.50, 0.50, 1, 0.50, 0.50 }; real[] cil={ 0, 0, 0, -1, 1 }; real[] cql={ -1, 1, 0, 0, 0 }; int[] indl={ -7, -8, 0, 8, 7 }; real cy, ci, cq; int rmaxi, dri, ind, ibase, lcol, rcol, i; rmaxi=2*divsy+1; if (dright<-2 || dright>2) { dri=2; } else { dri=2+dright; } cy=cyl[dri]; ci=cil[dri]; cq=cql[dri]; ind=indl[dri]; ibase=divsx+ind; lcol=rccolr[ibase]; rcol=rccoll[ibase+1]; real A, By, Ry, Gy, R, G, B; A=hypot(ci,cq); if (A>0) { ci=ci/A*campl; cq=cq/A*campl; } Ry=iT11*ci+iT12*cq; By=iT21*ci+iT22*cq; Gy=(-wr*Ry-wb*By)/wg; //write(cy,Ry,Gy,By); R=Ry+cy; G=Gy+cy; B=By+cy; if (verbose > 1) write(ind, cy*1000, round(ci*1000), round(cq*1000), round(R*1000), round(G*1000), round(B*1000)); for (i=0; i0) { trow=rcrowb[i]; } else { trow=floor((rcrowb[i]+rcrowt[inext])/2); } if (inext768 rerastering * 16 720->768 rerastering */ access settings; usersetting(); if (bsys<0 || bsys>12 || colortv<0 || colortv>3 || os<=0 || os>16) { write("Error: bad user input: bsys, colortv, os=\t", bsys, colortv, os); abort("Bad option -u bsys=N ?"); } int[] bNdot= { 12, 16, 12, 16, 1, 1, 1, 64, 10, 8, 10, 1, 1 }; int[] bDdot= { 11, 15, 11, 11, 1, 1, 1, 45, 11, 9, 11, 1, 1 }; int[] bNh= { 704, 720, 720, 720, 768, 768, 786, 720, 704, 720, 720, 1920, 1600 }; int[] bNv= { 576, 576, 576, 576, 576, 576, 576, 576, 480, 480, 480, 1080, 1200 }; real[] bfs= { 13.5,13.5,13.5,13.5, 14.75,14.4,14.75,13.5, 13.5,13.5,13.5, 36, 30 }; int[] bNsy= { 42, 42, 42, 42, 42, 42, 42, 42, 34, 34, 34, 78, 90 }; int[] bNsh= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* active lines for a 625 line frame * The number of active video lines decreased around 1997. * old: 3 run in + 575 visible + 3 run out = 581 lines * new: 6 teletext and WSS + 575 visible * Hence the image center shifted down by 3 lines. Thus * old TV + new testcard = bottom is cut off, * new TV + old testcard = top is cut off. * * To generate the old testcard either use Nv=582 Nsh=0 or Nv=576 Nsh=3. * * aspect ratio * rimage=xsize/ysize rimage=rdot*Nh/Nv * Nh=704 dots * Nv=576 lines * rd=ri*Nv/Nh=4/3*9/11=12/11 * * Nv: 480=2^5*3*5 576=2^6*3^2 * Nh: 704=2^6*11 720=2^4*3^2*5 * * horizontal line distance for pre 1997 test pattern * top 8 lines, 13 squares of Ny=43 lines, bottom 9 lines * top 12 lines, 13 squares of Ny=42 lines, bottom 18 lines * pairs are from odd even field * Interlace test: Ny must be odd for a cross-hatch without centerline. * * squares: ly=Nsy, lx=rd*Nsx, lx=ly ==> Nsx=Nsy/rd={ 39.4, 38.5 } * x line width 230 ns -> 3 dots * bottom 2.9us red -> 39.15 dots * * resolution DPI from image aspect ratio * Rv=Nv/ly, ly=4in * ri=Ni/Di, Ni={ 4, 15, 16} Di={ 3, 11, 9} * lx=ri*ly * * Rh=Nh/lx=Di*(Nh/(Ni*ly)) * integer Rh: * Ni=4 ri=4/Di => Nh=k*16 * Ni=15 ri=15/Di => Nh=k*60 * Ni=16 ri=16/Di => Nh=k*64 * * resolution DPI from dot aspect ratio, general algorithm, * * rd=Nd/Dd=ldx/ldy * * assume 1 dot = Nd x Dd square subdots at a resolution of k, in dpi, then * * ldx=Nd/k, ldy=Dd/k ==> Rh=k/Nd, Rv=k/Dd * * choosing k=m*Nd*Dd for integer Rh and Rv gives * * ldx=1/(m*Dd), ldy=1/(m*Nd), Rh=m*Dd, Rv=m*Nd * * and * * lx=Nh*ldx=Nh/(m*Dd), ly=Nv*ldy=Nv/(m*Nd) * * so choose m for the intended height Ly, in inch, as * * m=round(Nv/(Ly*Nd)) * * which limits Ly<=Nv/Nd since Rv>=Nd. */ //cm=72/2.540005; real Ly, ly, lx, ysize, xsize, rimage, xd, yd, pwidth; int Nd, Dd, m, Nh, Nv, Nshift, Na, Nsy; real fs, Ttone; Nd=bNdot[bsys]; Dd=bDdot[bsys]*os; Nh=bNh[bsys]*os; Nv=bNv[bsys]; Ly=4; // 4 inch vertical size m=floor(0.5+Nv/(Ly*Nd)); if (m < 1) m=1; ly=Nv/(m*Nd); lx=Nh/(m*Dd); ysize=ly*1inch; xsize=lx*1inch; rimage=xsize/ysize; if (verbose > 1) { write("#Nd Dd m ri:\t", Nd, Dd, m, rimage); } //size(xsize, ysize, Aspect); // should not have any effect Nsy=bNsy[bsys]; // grating size in lines 42,43 or 34,35 Nshift=bNsh[bsys]; // shift image up: pre 1997 =3, 2007 =0 fs=1e6*bfs[bsys]*os; Na=0; // add 1,0,-1 to height of hor center squares for even Na+Nsy Ttone=fs/250e3; // period of ft=250 kHz, fs/ft=54 real[] ftones={0.8e6/fs, 1.8e6/fs, 2.8e6/fs, 3.8e6/fs, 4.8e6/fs}; xd=xsize/Nh; yd=ysize/Nv; pwidth=min(abs(xd),abs(yd)); pen pdefault = squarecap+linewidth(pwidth); pen pblack = pdefault+gray(0.0); pen pwhite = pdefault+gray(1.0); /**** calculate grating repeats and size in tv dots ****/ /* horizontal lines */ int divsy, rdisty, Nvc, Nt, Nb, rmaxi; Nvc=floor(Nv/2)-Nshift; /* top half picture (Nv-2)/2-(Nsy+Na)/2 dots for divisions of Nsy dots */ divsy=floor(((Nv-2-Na)/Nsy-1)/2); rdisty=Na+Nsy*(1+2*divsy); /* first guess free lines top and bottom */ Nt=Nvc-ceil(rdisty/2); Nb=Nv-Nt-rdisty; if (verbose > 1) { write('#divsy t b: \t', divsy, Nt, Nb); } rmaxi=2*divsy+1; /* Nsyc: center square height * line pairing test: verify distance of center to top and bot * distance is odd ==> top=even/odd, cent=odd/even, bot=even/odd * * Nsyc odd: not possible * * Nsyc even: * Nsyc/2 odd --> OK * Nsyc/2 even --> stagger the raster one line upwards * * rcrowt top dist of hor line * rcrowc true center for color info, distance to top of image. * rcrowb bot dist of hor line * * offd = offu-Nsyc * Nt = Nvc-(offu+divsy*Nsy); * Nb = Nv-( Nvc-(offd-divsy*Nsy) ); * ==> Nt+Nb = Nv-Nsyc-2*divsy*Nsy */ int Nsyc, offu, offd, Nyst=0, i; int[] rcrowt, rcrowc, rcrowb; Nsyc=Nsy+Na; offu=floor(Nsyc/2); offd=offu-Nsyc; if (Nsyc%2 != 0) { Nyst=1; } else if (Nsyc%4 == 0) { Nyst=1; /* stagger */ } for (i=0; i<=divsy; ++i) { int iu, id, ou, od, ru, rd; iu=divsy-i; id=divsy+i+1; ou=offu+Nsy*i; od=offd-Nsy*i; if (verbose > 1) { write(ou,od); } rcrowc[iu]=Nvc-ou; rcrowc[id]=Nvc-od; ru=Nvc-(ou+Nyst); rd=Nvc-(od+Nyst); rcrowt[iu]=ru-1; rcrowb[iu]=ru+1; rcrowt[id]=rd-1; rcrowb[id]=rd+1; } Nt=floor((rcrowt[0]+rcrowb[0])/2); Nb=Nv-Nt-Nsyc-2*Nsy*divsy; if (verbose > 1) { write('#st t b: \t', Nyst, Nt, Nb); } /* vertical lines * (Nh-2*os)/2-Nsx/2 dots available for divisions of Nsx dots. * At least 5 dots margin left and right ==> use -10*os */ real lsq, Nsx, rdistx; int divsx, Nhc, Nl, Nr, cmaxi; lsq=Nsy*yd; Nsx=lsq/xd; /* floating point */ divsx=floor(((Nh-10*os)/Nsx-1)/2); Nhc=round(Nh/2); rdistx=(1+2*divsx)*Nsx; Nl=Nhc-round(rdistx/2); if (verbose > 1) { write('#divsx Nsx l:\t', divsx, Nsx, Nl); } cmaxi=2*divsx+1; int[] coff, coffl, coffr; int[] rccoll, rccolc, rccolr; for (i=0; i<=divsx; ++i) { int off, offl, offr, il, ir; real cdist; cdist=Nsx*(1+2*i); /* horizontal distance 2 symmetrical vert lines */ off=round(cdist/2); // write(cdist, off); offl=off-os; offr=off+os; coff[i]=off; coffl[i]=offl; coffr[i]=offr; if (verbose > 1) { write(cdist, off); } il=divsx-i; ir=divsx+i+1; rccoll[il]=Nhc-offr; rccolc[il]=Nhc-off; rccolr[il]=Nhc-offl; rccoll[ir]=Nhc+offl; rccolc[ir]=Nhc+off; rccolr[ir]=Nhc+offr; } Nl=rccolc[0]; Nr=Nh-rccolc[cmaxi]; if (verbose > 1) { write('#divsx Nsx l r:\t', divsx, Nsx, Nl, Nr); } /**** draw gray background ****/ { path zz; //zz=tvrect(0,0, Nh,Nv, xd,yd,Nv); /* keep white canvas for castellations */ zz=tvrect(rccoll[0],rcrowt[0], rccolr[cmaxi],rcrowb[rmaxi], xd,yd,Nv); fill(zz, p=pdefault+gray(0.5)); //dot(zz); } /**** draw center circle ****/ real cx, cy, crad; pair ccenter; path ccirc; cx=Nh/2; cy=Nv/2-Nshift; crad=6*Nsy; if (Nv%2 != 0) { crad+=0.5; } ccenter=tvps(cx,cy, xd,yd,Nv); ccirc=circle(ccenter, crad*yd); if (colortv<=0) { draw(ccirc, p=pwhite+linewidth(2*yd)); } /**** draw 2*divsy+2 horizontal gridlines ****/ real[] rcang, rcoff; pair[] rcright, rcleft; int i; for (i=0; i<=rmaxi; ++i) { real y, ph, x; path zzh; pair zd; zzh=tvrect(0,rcrowt[i], Nh,rcrowb[i], xd,yd,Nv); fill(zzh, p=pwhite); y=cy-rcrowc[i]; if (abs(y)4/3) { rimarkers(rimage, Nh, Nhc, os, Nvc, Nsy, pwhite, xd, yd, Nv); } /****** line pairing center ******/ centerline(colortv, rccoll, rccolc, rccolr, divsx, Nhc, os, rcrowt, rcrowc, rcrowb, divsy, Nvc, ccenter, rcoff, rcright, rcleft, pdefault, xd, yd, Nv); if (colortv>0) { /* topbw structure */ topbw(coff, Nhc, os, rcrowc[divsy-5], rcrowc[divsy-4], rcrowc[divsy-3], ccenter, rcleft[divsy-4], rcleft[divsy-3], rcright[divsy-4], rcright[divsy-3], pdefault, xd, yd, Nv); /* 250 kHz */ testtone(Ttone, rcrowc[divsy-3], rcrowc[divsy-2], cx, cy, crad, pdefault, xd, yd, Nv); /* color bars */ colorbars(coff, Nhc, rcrowc[divsy-2], rcrowc[divsy-1], rcrowc[divsy], ccenter, rcleft[divsy-2], rcleft[divsy], rcright[divsy-2], rcright[divsy], pdefault, xd, yd, Nv); /* test frequencies */ testfreqs(ftones, coff, Nhc, rcrowc[divsy+1], rcrowc[divsy+2], rcrowc[divsy+3], ccenter, rcleft[divsy+1], rcleft[divsy+3], rcright[divsy+1],rcright[divsy+3], pdefault, xd, yd, Nv); /* gray bars */ graybars(coff, Nhc, rcrowc[divsy+3], rcrowc[divsy+4], ccenter, rcleft[divsy+3], rcleft[divsy+4], rcright[divsy+3], rcright[divsy+4], pdefault, xd,yd,Nv); /* PAL ears */ if (colortv == 1) { palears(coff,coffr,coffl, Nhc, rcrowt, rcrowb, Nvc, divsy, -1, pdefault, xd, yd, Nv); palears(coff,coffr,coffl, Nhc, rcrowt, rcrowb, Nvc, divsy, 1, pdefault, xd, yd, Nv); } else if (colortv == 2) { ntscbars(rccoll, rccolr, divsx, rcrowt, rcrowb, divsy, -1, pdefault, xd, yd, Nv); ntscbars(rccoll, rccolr, divsx, rcrowt, rcrowb, divsy, 1, pdefault, xd, yd, Nv); ntscbars(rccoll, rccolr, divsx, rcrowt, rcrowb, divsy, -2, pdefault, xd, yd, Nv); ntscbars(rccoll, rccolr, divsx, rcrowt, rcrowb, divsy, 2, pdefault, xd, yd, Nv); } /* bottom wh - black - wh */ bottombw(round((coff[2]+coff[3])/2), Nhc, rcrowc[divsy+4], rcrowc[divsy+5], ccenter, rcleft[divsy+4], rcleft[divsy+5], rcright[divsy+4], rcright[divsy+5], pdefault, xd, yd, Nv); /* bottom yellow red circle */ bottomcirc(coff[0], Nhc, rcrowc[divsy+5], cx, cy, crad, ccenter, rcleft[divsy+5], rcright[divsy+5], pdefault, xd, yd, Nv); } /********************** set id *********************/ { /* dpi */ pair rpos=tvps(Nhc,round((rcrowc[divsy-4]+rcrowc[divsy-5])/2), xd,yd,Nv); string iRhor, iRver, ires; real Rh, Rv; Rh=Nh/xsize*inch; Rv=Nv/ysize*inch; iRhor=format("%.4gx", Rh); iRver=format("%.4gdpi", Rv); ires=insert(iRver,0, iRhor); /* size info */ int rowbot=round((rcrowc[divsy+4]+rcrowc[divsy+5])/2); pair tpos=tvps(Nhc,rowbot, xd,yd,Nv); string ihor, iver, itot, iasp, ifm; real asp, fm; ihor=format("%ix",Nh); iver=format("%i ",Nv); itot=insert(iver,0, ihor); asp=xsize/ysize; iasp=format("%.3g ",asp); fm=fs/1e6; ifm=format("%.4gMHz",fm); itot=insert(iasp,0, itot); itot=insert(ifm,0, itot); /* size of square */ int rowNsy, colNsy; pair Npos; string iNsy; pen pbw; rowNsy = round((rcrowc[divsy+5]+rcrowc[divsy+6])/2); colNsy = round((rccolc[divsx+5]+rccolc[divsx+6])/2); Npos = tvps(colNsy,rowNsy, xd,yd,Nv); iNsy = format("%i", Nsy); if (colortv>0) { pbw=pdefault+gray(1.0); } else { pbw=pdefault+gray(0.0); } label(ires, rpos, p=pbw); label(itot, tpos, p=pbw); label(iNsy, Npos, p=pbw); if (verbose > 1) write('#res:\t', ires, itot, iNsy); } asymptote-2.37/examples/twistedtubes.asy000066400000000000000000000015651265434602500205720ustar00rootroot00000000000000import graph3; import palette; size(300,300,keepAspect=true); real w=0.4; real f(triple t) {return sin(t.x);} triple f1(pair t) {return (cos(t.x)-2cos(w*t.y),sin(t.x)-2sin(w*t.y),t.y);} triple f2(pair t) {return (cos(t.x)+2cos(w*t.y),sin(t.x)+2sin(w*t.y),t.y);} triple f3(pair t) {return (cos(t.x)+2sin(w*t.y),sin(t.x)-2cos(w*t.y),t.y);} triple f4(pair t) {return (cos(t.x)-2sin(w*t.y),sin(t.x)+2cos(w*t.y),t.y);} surface s1=surface(f1,(0,0),(2pi,10),8,8,Spline); surface s2=surface(f2,(0,0),(2pi,10),8,8,Spline); surface s3=surface(f3,(0,0),(2pi,10),8,8,Spline); surface s4=surface(f4,(0,0),(2pi,10),8,8,Spline); pen[] Rainbow=Rainbow(); s1.colors(palette(s1.map(f),Rainbow)); s2.colors(palette(s2.map(f),Rainbow)); s3.colors(palette(s3.map(f),Rainbow)); s4.colors(palette(s4.map(f),Rainbow)); defaultrender.merge=true; draw(s1); draw(s2); draw(s3); draw(s4); asymptote-2.37/examples/unitcircle.asy000066400000000000000000000005021265434602500201730ustar00rootroot00000000000000size(0,150); pair z0=0; pair z1=1; real theta=30; pair z=dir(theta); draw(circle(z0,1)); filldraw(z0--arc(z0,1,0,theta)--cycle,lightgrey); dot(z0); dot(Label,z1); dot("$(x,y)=(\cos\theta,\sin\theta)$",z); arrow("area $\frac{\theta}{2}$",dir(0.5*theta),2E); draw("$\theta$",arc(z0,0.7,0,theta),LeftSide,Arrow,PenMargin); asymptote-2.37/examples/unitoctant.asy000066400000000000000000000013111265434602500202210ustar00rootroot00000000000000import graph3; currentprojection=orthographic(5,4,2); size(0,150); patch s=octant1; draw(surface(s),green+opacity(0.5)); draw(s.external(),blue); triple[][] P=s.P; for(int i=0; i < 4; ++i) dot(P[i],red); axes3("$x$","$y$",Label("$z$",align=Z)); triple P00=P[0][0]; triple P10=P[1][0]; triple P01=P[0][1]; triple P02=P[0][2]; triple P11=P[1][1]; triple P12=P[1][2]; triple Q11=XYplane(xypart(P11)); triple Q12=XYplane(xypart(P12)); draw(P11--Q11,dashed); draw(P12--Q12,dashed); draw(O--Q12--Q11--(Q11.x,0,0)); draw(Q12--(Q12.x,0,0)); label("$(1,0,0)$",P00,-2Y); label("$(1,a,0)$",P10,-Z); label("$(1,0,a)$",P01,-2Y); label("$(a,0,1)$",P02,Z+X-Y); label("$(1,a,a)$",P11,3X); label("$(a,a^2,1)$",P12,7X+Y); asymptote-2.37/examples/upint.asy000066400000000000000000000003071265434602500171740ustar00rootroot00000000000000import graph; import lowupint; size(100,0); real a=-0.8, b=1.2; real c=-1.0/sqrt(3.0); partition(a,b,c,max); arrow("$f(x)$",F(0.5*(a+b)),NNE,red); label("$\cal{U}$",(0.5*(a+b),f(0.5*(a+b))/2)); asymptote-2.37/examples/vectorfield3.asy000066400000000000000000000010151265434602500204230ustar00rootroot00000000000000import graph3; size(12cm,0); currentprojection=orthographic(1,-2,1); currentlight=(1,-1,0.5); real f(pair z) {return abs(z)^2;} path3 gradient(pair z) { static real dx=sqrtEpsilon, dy=dx; return O--((f(z+dx)-f(z-dx))/2dx,(f(z+I*dy)-f(z-I*dy))/2dy,0); } pair a=(-1,-1); pair b=(1,1); triple F(pair z) {return (z.x,z.y,0);} add(vectorfield(gradient,F,a,b,red)); draw(surface(f,a,b,Spline),gray+opacity(0.5)); xaxis3(XY()*"$x$",OutTicks(XY()*Label)); yaxis3(XY()*"$y$",InTicks(YX()*Label)); zaxis3("$z$",OutTicks); asymptote-2.37/examples/vectorfieldsphere.asy000066400000000000000000000005371265434602500215570ustar00rootroot00000000000000import graph3; size(12cm); currentprojection=orthographic(1,-2,1); currentlight=(1,-1,0.5); triple f(pair z) {return expi(z.x,z.y);} path3 vector(pair z) { triple v=f(z); return O--(v.y,v.z,v.x); } add(vectorfield(vector,f,(0,0),(pi,2pi),10,0.25,red,render(merge=true))); draw(unitsphere,gray+opacity(0.5),render(compression=0,merge=true)); asymptote-2.37/examples/venn.asy000066400000000000000000000012201265434602500167760ustar00rootroot00000000000000size(0,150); pen colour1=red; pen colour2=green; pair z0=(0,0); pair z1=(-1,0); pair z2=(1,0); real r=1.5; path c1=circle(z1,r); path c2=circle(z2,r); fill(c1,colour1); fill(c2,colour2); picture intersection; fill(intersection,c1,colour1+colour2); clip(intersection,c2); add(intersection); draw(c1); draw(c2); label("$A$",z1); label("$B$",z2); pair z=(0,-2); real m=3; margin BigMargin=Margin(0,m*dot(unit(z1-z),unit(z0-z))); draw(Label("$A\cap B$",0),conj(z)--z0,Arrow,BigMargin); draw(Label("$A\cup B$",0),z--z0,Arrow,BigMargin); draw(z--z1,Arrow,Margin(0,m)); draw(z--z2,Arrow,Margin(0,m)); shipout(bbox(0.25cm)); currentpicture.uptodate=true; asymptote-2.37/examples/venn3.asy000066400000000000000000000015071265434602500170710ustar00rootroot00000000000000size(0,150); pen colour1=red; pen colour2=green; pen colour3=blue; real r=sqrt(3); pair z0=(0,0); pair z1=(-1,0); pair z2=(1,0); pair z3=(0,r); path c1=circle(z1,r); path c2=circle(z2,r); path c3=circle(z3,r); fill(c1,colour1); fill(c2,colour2); fill(c3,colour3); picture intersection12; fill(intersection12,c1,colour1+colour2); clip(intersection12,c2); picture intersection13; fill(intersection13,c1,colour1+colour3); clip(intersection13,c3); picture intersection23; fill(intersection23,c2,colour2+colour3); clip(intersection23,c3); picture intersection123; fill(intersection123,c1,colour1+colour2+colour3); clip(intersection123,c2); clip(intersection123,c3); add(intersection12); add(intersection13); add(intersection23); add(intersection123); draw(c1); draw(c2); draw(c3); label("$A$",z1); label("$B$",z2); label("$C$",z3); asymptote-2.37/examples/vertexshading.asy000066400000000000000000000010331265434602500207050ustar00rootroot00000000000000import three; size(200); currentprojection=perspective(4,5,5); draw(surface(unitcircle3,new pen[] {red,green,blue,black})); draw(surface(shift(Z)*unitsquare3, new pen[] {red,green+opacity(0.5),blue,black})); draw(surface(shift(X)*((0,0,0)..controls (1,0,0) and (2,0,0)..(3,0,0).. controls (2.5,sqrt(3)/2,0) and (2,sqrt(3),0).. (1.5,3*sqrt(3)/2,0).. controls (1,sqrt(3),0) and (0.5,sqrt(3)/2,0)..cycle), new triple[] {(1.5,sqrt(3)/2,2)},new pen[] {red,green,blue})); asymptote-2.37/examples/washer.asy000066400000000000000000000005501265434602500173260ustar00rootroot00000000000000import three; size(10cm); path3[] p=reverse(unitcircle3)^^scale3(0.5)*unitcircle3; path[] g=reverse(unitcircle)^^scale(0.5)*unitcircle; triple H=-0.4Z; render render=render(merge=true); draw(surface(p,planar=true),render); draw(surface(shift(H)*p,planar=true),render); material m=material(lightgray,shininess=1.0); for(path pp : g) draw(extrude(pp,H),m); asymptote-2.37/examples/washermethod.asy000066400000000000000000000017541265434602500205360ustar00rootroot00000000000000import graph3; import solids; size(0,150); currentprojection=perspective(0,0,11,up=Y); pen color1=green+opacity(0.25); pen color2=red; real alpha=250; real f(real x) {return 2x^2-x^3;} pair F(real x) {return (x,f(x));} triple F3(real x) {return (x,f(x),0);} ngraph=12; real x1=0.7476; real x2=1.7787; real x3=1.8043; path[] p={graph(F,x1,x2,Spline), graph(F,0.7,x1,Spline)--graph(F,x2,x3,Spline), graph(F,0,0.7,Spline)--graph(F,x3,2,Spline)}; pen[] pn=new pen[] {color1,color2,color1}; render render=render(compression=0); for(int i=0; i < p.length; ++i) { revolution a=revolution(path3(p[i]),Y,0,alpha); draw(surface(a),pn[i],render); surface s=surface(p[i]--cycle); draw(s,pn[i],render); draw(rotate(alpha,Y)*s,pn[i],render); } draw((4/3,0,0)--F3(4/3),dashed); xtick("$\frac{4}{3}$",(4/3,0,0)); xaxis3(Label("$x$",1),Arrow3); yaxis3(Label("$y$",1),ymax=1.25,dashed,Arrow3); arrow("$y=2x^2-x^3$",F3(1.6),X+Y,0.75cm,red); draw(arc(1.1Y,0.3,90,0,7.5,180),Arrow3); asymptote-2.37/examples/wedge.asy000066400000000000000000000011641265434602500171320ustar00rootroot00000000000000import graph3; import solids; size(0,150); currentprojection=perspective(8,10,2); currentlight=White; draw(circle(O,4,Z)); draw(shift(-4Z)*scale(4,4,8)*unitcylinder,green+opacity(0.2)); triple F(real x){return (x,sqrt(16-x^2),sqrt((16-x^2)/3));} path3 p=graph(F,0,4,operator ..); path3 q=reverse(p)--rotate(180,(0,4,4/sqrt(3)))*p--cycle; render render=render(merge=true); draw(surface(q--cycle),red,render); real t=2; path3 triangle=(t,0,0)--(t,sqrt(16-t^2),0)--F(t)--cycle; draw(surface(triangle),blue,render); xaxis3("$x$",Arrow3,PenMargin3(0,0.25)); yaxis3("$y$",Arrow3,PenMargin3(0,0.25)); zaxis3("$z$",dashed,Arrow3); asymptote-2.37/examples/workcone.asy000066400000000000000000000016741265434602500176740ustar00rootroot00000000000000import solids; size(0,150); currentprojection=orthographic(0,-30,5); real r=4; real h=10; real s=8; real x=r*s/h; real sr=5; real xr=r*sr/h; real s1=sr-0.1; real x1=r*s1/h; real s2=sr+0.2; real x2=r*s2/h; render render=render(compression=0,merge=true); path3 p=(0,0,0)--(x,0,s); revolution a=revolution(p,Z); draw(surface(a,4),lightblue+opacity(0.5),render); path3 q=(x,0,s)--(r,0,h); revolution b=revolution(q,Z); draw(surface(b),white+opacity(0.5),render); draw((-r-1,0,0)--(r+1,0,0)); draw((0,0,0)--(0,0,h+1),dashed); path3 w=(x1,0,s1)--(x2,0,s2)--(0,0,s2); revolution b=revolution(w,Z); draw(surface(b),blue+opacity(0.5),render); draw(circle((0,0,s2),x2)); draw(circle((0,0,s1),x1)); draw("$x$",(xr,0,0)--(xr,0,sr),red,Arrow3,PenMargin3); draw("$r$",(0,0,sr)--(xr,0,sr),N,red); draw((string) r,(0,0,h)--(r,0,h),N,red); draw((string) h,(r,0,0)--(r,0,h),red,Arrow3,PenMargin3); draw((string) s,(-x,0,0)--(-x,0,s),W,red,Arrow3,Bar3,PenMargin3); asymptote-2.37/examples/worksheet.asy000066400000000000000000000016671265434602500200620ustar00rootroot00000000000000import fontsize; defaultpen(Helvetica()); picture pic; unitsize(pic,mm); pair z=(0,0); real length=88; real height=8; pair step=height*S; label(pic,"Word Wall Spelling",z,Align); z += step; frame f; label(f,"Name:"); pair z0=(max(f).x,min(f).y); draw(f,z0--z0+50mm); add(pic,f,z,Align); z += step; for(int i=1; i <= 15; ++i) { draw(pic,z--z+length); z += step; draw(pic,z--z+length,dashed+gray); z += step; void label(int i) { label(pic,string(i)+".",z,0.2NE,fontsize(0.8*1.5*2*height*mm)+gray); } if(i <= 10) label(i); else if(i == 11) { pair z0=z+length/2; pen p=fontsize(20pt); label(pic,"Challenge Word",z0+N*height,I*Align.y,p+basealign); label(pic,"(optional)",z0,I*Align.y,p); } else if(i == 12) label(1); else if(i == 13) label(2); else if(i == 14) label(3); } draw(pic,z--z+length); add(pic.fit(),(0,0),W); add(pic.fit(),(0,0),E); newpage(); add(pic.fit(),(0,0),W); add(pic.fit(),(0,0),E); asymptote-2.37/examples/worldmap.asy000066400000000000000000000051431265434602500176650ustar00rootroot00000000000000settings.outformat="pdf"; size(20cm); // The required data file is available here: // http://www.uni-graz.at/~schwaige/asymptote/worldmap.dat // This data was originally obtained from // http://www.ngdc.noaa.gov/mgg_coastline/mapit.jsp real findtheta(real phi, real epsilon=realEpsilon) { // Determine for given phi the unique solution -pi/2 <= theta <= pi/2 off // 2*theta+sin(2*theta)=pi*sin(phi) // in the non-trivial cases by Newton iteration; // theoretically the initial guess pi*sin(phi)/4 always works. real nwtn(real x, real y) {return x-(2x+sin(2x)-y)/(2+2*cos(2x));}; real y=pi*sin(phi); if(y == 0) return 0.0; if(abs(y) == 1) return pi/2; real startv=y/4; real endv=nwtn(startv,y); if(epsilon < 500*realEpsilon) epsilon=500*realEpsilon; while(abs(endv-startv) > epsilon) {startv=endv; endv=nwtn(startv,y);}; return endv; } pair mollweide(real lambda, real phi, real lambda0=0){ // calculate the Mollweide projection centered at lambda0 for the point // with coordinates(phi,lambda) static real c1=2*sqrt(2)/pi; static real c2=sqrt(2); real theta=findtheta(phi); return(c1*(lambda-lambda0)*cos(theta), c2*sin(theta)); } guide gfrompairs(pair[] data){ guide gtmp; for(int i=0; i < data.length; ++i) { pair tmp=mollweide(radians(data[i].y),radians(data[i].x)); gtmp=gtmp--tmp; } return gtmp; } string datafile="worldmap.dat"; file in=input(datafile,comment="/").line(); // new commentchar since "#" is contained in the file pair[][] arrarrpair=new pair[][] ; int cnt=-1; bool newseg=false; while(true) { if(eof(in)) break; string str=in; string[] spstr=split(str,""); if(spstr[0] == "#") {++cnt; arrarrpair[cnt]=new pair[] ; newseg=true;} if(spstr[0] != "#" && newseg) { string[] spstr1=split(str,'\t'); // separator is TAB not SPACE pair tmp=((real) spstr1[1],(real) spstr1[0]); arrarrpair[cnt].push(tmp); } } for(int i=0; i < arrarrpair.length; ++i) draw(gfrompairs(arrarrpair[i]),1bp+black); // lines of longitude and latitude pair[] constlong(real lambda, int np=100) { pair[] tmp; for(int i=0; i <= np; ++i) tmp.push((-90+i*180/np,lambda)); return tmp; } pair[] constlat(real phi, int np=100) { pair[] tmp; for(int i=0; i <= 2*np; ++i) tmp.push((phi,-180+i*180/np)); return tmp; } for(int j=1; j <= 5; ++j) draw(gfrompairs(constlong(-180+j/6*360)),white); draw(gfrompairs(constlong(-180)),1.5bp+white); draw(gfrompairs(constlong(180)),1.5bp+white); for(int j=0; j <= 12; ++j) draw(gfrompairs(constlat(-90+j/6*180)),white); //draw(gfrompairs(constlong(10)),dotted); close(in); shipout(bbox(1mm,darkblue,Fill(lightblue)), view=true); asymptote-2.37/examples/xsin1x.asy000066400000000000000000000011041265434602500172630ustar00rootroot00000000000000import graph; size(300,0); real f(real x) {return (x != 0.0) ? x * sin(1.0 / x) : 0.0;} pair F(real x) {return (x,f(x));} xaxis("$x$",red); yaxis(red); draw(graph(f,-1.2/pi,1.2/pi,1000)); label("$x\sin\frac{1}{x}$",F(1.1/pi),NW); picture pic; size(pic,50,IgnoreAspect); xaxis(pic,red); yaxis(pic,red); draw(pic,graph(pic,f,-0.1/pi,0.1/pi,1000)); add(new void(frame f, transform t) { frame G=shift(point(f,N+0.85W))*align(bbox(pic,blue),10SE); add(f,G); draw(f,t*box(min(pic,user=true),max(pic,user=true)),blue); draw(f,point(G,E)--t*point(pic,W),blue); }); asymptote-2.37/examples/xstitch.asy000066400000000000000000000072421265434602500175300ustar00rootroot00000000000000pair c=(0,0.8); int iters(pair z, int max=160) { int n=0; while(abs(z) < 2 && n < max) { z=z*z+c; ++n; } return n; } int[] cutoffs={12,15,20,30,40,60,200}; int key(pair z) { int i=iters(z); int j=0; while(cutoffs[j] < i) ++j; return j; } int width=210; int height=190; real zoom=2.5/200; int[][] values=new int[width][height]; int[] histogram; for(int v=0; v < 10; ++v) histogram.push(0); for(int i=0; i < width; ++i) { real x=zoom*(i-width/2); for(int j=0; j < height; ++j) { real y=zoom*(j-height/2); int v=key((x,y)); values[i][j]=v; ++histogram[v]; } } // Print out a histogram. write("histogram: "); write(histogram); pen linepen(int i, int max) { real w=i == -1 || i == max+1 ? 2.0 : i % 10 == 0 || i == max ? 1.0 : i % 5 == 0 ? 0.8 : 0.25; return linewidth(w); } pen xpen(int i) { return linepen(i,width)+(i == width/2 ? red : i == 75 || i == width-75 ? dashed : black); } pen ypen(int i) { return linepen(i,height)+(i == height/2 ? red : i == 75 || i == height-75 ? dashed : black); } // The length of the side of a cross stitch cell. real cell=2.3mm; transform t=scale(cell); picture tick; draw(tick,(0,0)--(1,1)); picture ell; draw(ell,(0,1)--(0,0)--(0.7,0)); picture cross; draw(cross,(0,0)--(1,1)); draw(cross,(1,0)--(0,1)); picture star; draw(star,(0.15,0.15)--(0.85,0.85)); draw(star,(0.85,0.15)--(0.15,0.85)); draw(star,(.5,0)--(.5,1)); draw(star,(0,.5)--(1,.5)); picture triangle; draw(triangle,(0,0)--(2,0)--(1,1.5)--cycle); picture circle; fill(circle,shift(1,1)*unitcircle); picture ocircle; draw(ocircle,shift(1,1)*unitcircle); picture spare; fill(spare,(0,0)--(1,1)--(0,1)--cycle); picture[] pics={tick,ell,cross,star,triangle,circle}; pen[] colors={black,0.2purple,0.4purple,0.6purple,0.8purple,purple, 0.8purple+0.2white}; frame[] icons; icons.push(newframe); for(picture pic : pics) { // Scaling factor, so that we don't need weird line widths. real X=1.0; frame f=pic.fit(.8X*cell,.8X*cell,Aspect); f=scale(1/X)*f; // Center the icon in the cell. f=shift((cell/2,cell/2)-0.5(max(f)-min(f)))*f; icons.push(f); } void drawSection(int xmin, int xmax, int ymin, int ymax) { static int shipoutNumber=0; // Draw directly to a frame for speed reasons. frame pic; for(int i=xmin; i <= xmax; ++i) { draw(pic,t*((i,ymin)--(i,ymax)),xpen(i)); if(i%10 == 0) { label(pic,string(i),t*(i,ymin),align=S); label(pic,string(i),t*(i,ymax),align=N); } } for(int j=ymin; j <= ymax; ++j) { draw(pic,t*((xmin,j)--(xmax,j)),ypen(j)); if(j%10 == 0) { label(pic,string(j),t*(xmin,j),align=W); label(pic,string(j),t*(xmax,j),align=E); } } if(xmin < 0) xmin=0; if(xmax >= width) xmax=width-1; if(ymin < 0) ymin=0; if(ymax >= height) ymax=height-1; int stitchCount=0; path box=scale(cell) *((0,0)--(1,0)--(1,1)--(0,1)--cycle); for(int i=xmin; i < xmax; ++i) for(int j=ymin; j < ymax; ++j) { int v=values[i][j]; add(pic,icons[v],(i*cell,j*cell)); //fill(pic,shift(i*cell,j*cell)*box,colors[v]); if(v != 0) ++stitchCount; } write("stitch count: ",stitchCount); // shipout("xstitch"+string(shipoutNumber),pic); shipout(pic); ++shipoutNumber; } //drawSection(-1,width+1,-1,height+1); //drawSection(-1,80,height-80,height+1); //drawSection(70,150,height-80,height+1); drawSection(quotient(width,2)-40,quotient(width,2)+40,quotient(height,2)-40,quotient(height,2)+40); //drawSection(width-150,width-70,-1,80); //drawSection(width-80,width+1,-1,80); asymptote-2.37/examples/xxsq01.asy000066400000000000000000000013471265434602500172060ustar00rootroot00000000000000import graph3; import solids; size(0,150); currentprojection=perspective(0,0,10,up=Y); pen color=green; real alpha=250; real f(real x) {return x^2;} pair F(real x) {return (x,f(x));} triple F3(real x) {return (x,f(x),0);} path p=graph(F,0,1,n=10,operator ..)--cycle; path3 p3=path3(p); revolution a=revolution(p3,X,-alpha,0); render render=render(compression=0,merge=true); draw(surface(a),color,render); surface s=surface(p); draw(s,color,render); draw(rotate(-alpha,X)*s,color,render); draw(p3,blue); xaxis3(Label("$x$",1),xmax=1.25,dashed,Arrow3); yaxis3(Label("$y$",1),Arrow3); dot(Label("$(1,1)$"),(1,1,0),X+Y); arrow("$y=x$",(0.7,0.7,0),Y,0.75cm,red); arrow("$y=x^2$",F3(0.7),X,0.75cm,red); draw(arc(1.1X,0.3,90,90,3,-90),Arrow3); asymptote-2.37/examples/xxsq01x-1.asy000066400000000000000000000015441265434602500175330ustar00rootroot00000000000000import graph3; import solids; size(300); currentprojection=perspective(0,2,10,up=Y); currentlight=Viewport; pen color=green; real f(real x) {return x^2;} pair F(real x) {return (x,f(x));} triple F3(real x) {return (x,f(x),0);} path p=graph(F,0,1,n=10,operator ..)--cycle; path3 p3=path3(p); revolution a=revolution(-X,p3,Y,0,180); render render=render(merge=true); draw(surface(a),color); surface s=surface(p); draw(s,color); transform3 t=shift(-2X)*rotate(180,Y); draw(t*s,color); draw(p3); draw(t*p3); draw((-1,0,0)--(-1,1,0),dashed); xaxis3(Label("$x$",1),Arrow3); yaxis3(Label("$y$",1),Arrow3); dot(Label("$(1,1)$"),(1,1,0)); dot(Label("$(-1,1)$"),(-1,1,0),W); arrow("$y=x^{2}$",F3(0.7),X,1cm,red); arrow("$y=x$",(0.3,0.3,0),X,1.5cm,red); draw(circle((-1,1,0),2,Y),dashed); draw((-1,1,0)--(1,1,0),dashed); draw(shift(-X)*arc(0.02Y,0.3,90,0,0,0,CW),Arrow3); asymptote-2.37/examples/xxsq01y.asy000066400000000000000000000014731265434602500173770ustar00rootroot00000000000000import solids; size(0,150); currentprojection=perspective(0,0,10,up=Y); pen color=green; real alpha=240; real f(real x) {return x^2;} pair F(real x) {return (x,f(x));} triple F3(real x) {return (x,f(x),0);} path p=graph(F,0,1,n=10,operator ..)--cycle; path3 p3=path3(p); render render=render(compression=0,merge=true); draw(surface(revolution(p3,Y,0,alpha)),color,render); surface s=surface(p); draw(s,color,render); draw(rotate(alpha,Y)*s,color,render); draw(p3,blue); xaxis3(Label("$x$",1),Arrow3); yaxis3(Label("$y$",1),ymax=1.25,dashed,Arrow3); dot("$(1,1)$",(1,1,0),X); arrow("$y=x^{2}$",F3(0.7),X,0.75cm,red); arrow("$y=x$",(0.8,0.8,0),Y,1cm,red); real r=0.4; draw((r,f(r),0)--(r,r,0),red); draw("$r$",(0,(f(r)+r)*0.5,0)--(r,(f(r)+r)*0.5,0),N,red,Arrows3,PenMargins3); draw(arc(1.1Y,0.3,90,0,7.5,180),Arrow3); asymptote-2.37/examples/yingyang.asy000066400000000000000000000003371265434602500176650ustar00rootroot00000000000000size(0,25cm); guide center=(0,1){W}..tension 0.8..(0,0){(1,-.5)}..tension 0.8..{W}(0,-1); draw((0,1)..(-1,0)..(0,-1)); filldraw(center{E}..{N}(1,0)..{W}cycle); unfill(circle((0,0.5),0.125)); fill(circle((0,-0.5),0.125)); asymptote-2.37/exp.cc000066400000000000000000001011761265434602500146120ustar00rootroot00000000000000/***** * exp.cc * andy hammerlindl 2002/8/19 * * represents the abstract syntax tree for the expressions in the * language. this is translated into virtual machine code using trans() * and with the aid of the environment class. *****/ #include "exp.h" #include "errormsg.h" #include "runtime.h" #include "runmath.h" #include "runpicture.h" #include "runarray.h" #include "runpair.h" #include "runtriple.h" #include "runpath.h" #include "coenv.h" #include "application.h" #include "dec.h" #include "stm.h" #include "inst.h" #include "opsymbols.h" namespace absyntax { using namespace types; using namespace trans; using vm::inst; using mem::vector; #if 0 void exp::prettyprint(ostream &out, Int indent) { prettyname(out, "exp",indent); } #endif void exp::transAsType(coenv &e, types::ty *target) { types::ty *t=trans(e); assert(t->kind==ty_error || equivalent(t,target)); } void exp::transToType(coenv &e, types::ty *target) { types::ty *ct=cgetType(e); if (equivalent(target, ct)) { transAsType(e, target); return; } // See if the cast can be handled by the fastLookupCast method, which does // less memory allocation. if (ct->kind != ty_overloaded && ct->kind != ty_error && target->kind != ty_error) { access *a = e.e.fastLookupCast(target, ct); if (a) { transAsType(e, ct); a->encode(CALL, getPos(), e.c); return; } } types::ty *source = e.e.castSource(target, ct, symbol::castsym); if (source==0) { if (target->kind != ty_error) { types::ty *sources=cgetType(e); em.error(getPos()); em << "cannot cast "; if (sources->kind==ty_overloaded) em << "expression"; else em << "'" << *sources << "'"; em << " to '" << *target << "'"; } } else if (source->kind==ty_overloaded) { if (target->kind != ty_error) { em.error(getPos()); em << "expression is ambiguous in cast to '" << *target << "'"; } } else { transAsType(e, source); e.implicitCast(getPos(), target, source); } } void exp::testCachedType(coenv &e) { if (ct != 0) { types::ty *t = getType(e); if (!equivalent(t, ct)) { em.compiler(getPos()); em << "cached type '" << *ct << "' doesn't match actual type '" << *t << "'"; em.sync(); } } } void exp::transCall(coenv &e, types::ty *target) { transAsType(e, target); e.c.encode(inst::popcall); } void exp::transConditionalJump(coenv &e, bool cond, label dest) { transToType(e, primBoolean()); e.c.useLabel(cond ? inst::cjmp : inst::njmp, dest); } exp *exp::evaluate(coenv &e, types::ty *target) { return new tempExp(e, this, target); } tempExp::tempExp(coenv &e, varinit *v, types::ty *t) : exp(v->getPos()), a(e.c.allocLocal()), t(t) { v->transToType(e, t); a->encode(WRITE, getPos(), e.c); e.c.encodePop(); } void tempExp::prettyprint(ostream &out, Int indent) { prettyname(out, "tempExp", indent); } types::ty *tempExp::trans(coenv &e) { a->encode(READ, getPos(), e.c); return t; } varEntryExp::varEntryExp(position pos, types::ty *t, access *a) : exp(pos), v(new trans::varEntry(t, a, 0, position())) {} varEntryExp::varEntryExp(position pos, types::ty *t, vm::bltin f) : exp(pos), v(new trans::varEntry(t, new bltinAccess(f), 0, position())) {} void varEntryExp::prettyprint(ostream &out, Int indent) { prettyname(out, "varEntryExp", indent); } types::ty *varEntryExp::getType(coenv &) { return v->getType(); } types::ty *varEntryExp::trans(coenv &e) { v->encode(READ, getPos(), e.c); return getType(e); } trans::varEntry *varEntryExp::getCallee(coenv &e, types::signature *sig) { return equivalent(sig, v->getType()->getSignature()) ? v : 0; } void varEntryExp::transAct(action act, coenv &e, types::ty *target) { assert(equivalent(getType(e),target)); v->encode(act, getPos(), e.c); } void varEntryExp::transAsType(coenv &e, types::ty *target) { transAct(READ, e, target); } void varEntryExp::transWrite(coenv &e, types::ty *target, exp *value) { value->transToType(e, target); transAct(WRITE, e, target); } void varEntryExp::transCall(coenv &e, types::ty *target) { transAct(CALL, e, target); } void nameExp::prettyprint(ostream &out, Int indent) { prettyname(out, "nameExp",indent); value->prettyprint(out, indent+1); } void fieldExp::pseudoName::prettyprint(ostream &out, Int indent) { // This should never be called. prettyindent(out, indent); out << "pseudoName" << "\n"; object->prettyprint(out, indent+1); } void fieldExp::prettyprint(ostream &out, Int indent) { prettyindent(out, indent); out << "fieldExp '" << field << "'\n"; object->prettyprint(out, indent+1); } types::ty *fieldExp::getObject(coenv& e) { types::ty *t = object->cgetType(e); if (t->kind == ty_overloaded) { t=((overloaded *)t)->signatureless(); if(!t) return primError(); } return t; } array *arrayExp::getArrayType(coenv &e) { types::ty *a = set->cgetType(e); if (a->kind == ty_overloaded) { a = ((overloaded *)a)->signatureless(); if (!a) return 0; } switch (a->kind) { case ty_array: return (array *)a; case ty_error: return 0; default: return 0; } } array *arrayExp::transArray(coenv &e) { types::ty *a = set->cgetType(e); if (a->kind == ty_overloaded) { a = ((overloaded *)a)->signatureless(); if (!a) { em.error(set->getPos()); em << "expression is not an array"; return 0; } } set->transAsType(e, a); switch (a->kind) { case ty_array: return (array *)a; case ty_error: return 0; default: em.error(set->getPos()); em << "expression is not an array"; return 0; } } // Checks if the expression can be translated as an array. bool isAnArray(coenv &e, exp *x) { types::ty *t=x->cgetType(e); if (t->kind == ty_overloaded) t=dynamic_cast(t)->signatureless(); return t && t->kind==ty_array; } void subscriptExp::prettyprint(ostream &out, Int indent) { prettyindent(out, indent); out << "subscriptExp\n"; set->prettyprint(out, indent+1); index->prettyprint(out, indent+1); } types::ty *subscriptExp::trans(coenv &e) { array *a = transArray(e); if (!a) return primError(); if (isAnArray(e, index)) { index->transToType(e, types::IntArray()); e.c.encode(inst::builtin, run::arrayIntArray); return getArrayType(e); } else { index->transToType(e, types::primInt()); e.c.encode(inst::builtin, a->celltype->kind==ty_array ? run::arrayArrayRead : run::arrayRead); return a->celltype; } } types::ty *subscriptExp::getType(coenv &e) { array *a = getArrayType(e); return a ? (isAnArray(e, index) ? a : a->celltype) : primError(); } void subscriptExp::transWrite(coenv &e, types::ty *t, exp *value) { // Put array, index, and value on the stack in that order, then call // arrayWrite. array *a = transArray(e); if (!a) return; if (!equivalent(a->celltype, t)) { em.error(getPos()); em << "array expression cannot be used as an address"; // Translate the value for errors. value->transToType(e, t); return; } index->transToType(e, types::primInt()); value->transToType(e, t); e.c.encode(inst::builtin, run::arrayWrite); } void slice::prettyprint(ostream &out, Int indent) { prettyname(out, "slice", indent); if (left) left->prettyprint(out, indent+1); else prettyname(out, "left omitted", indent+1); if (right) right->prettyprint(out, indent+1); else prettyname(out, "right omitted", indent+1); } void slice::trans(coenv &e) { if (left) left->transToType(e, types::primInt()); else // If the left index is omitted it can be assumed to be zero. e.c.encode(inst::intpush, (Int)0); if (right) right->transToType(e, types::primInt()); } void sliceExp::prettyprint(ostream &out, Int indent) { prettyname(out, "sliceExp", indent); set->prettyprint(out, indent+1); index->prettyprint(out, indent+1); } types::ty *sliceExp::trans(coenv &e) { array *a = transArray(e); if (!a) return primError(); index->trans(e); e.c.encode(inst::builtin, index->getRight() ? run::arraySliceRead : run::arraySliceReadToEnd); return a; } types::ty *sliceExp::getType(coenv &e) { array *a = getArrayType(e); return a ? a : primError(); } void sliceExp::transWrite(coenv &e, types::ty *t, exp *value) { array *a = transArray(e); if (!a) return; assert(equivalent(a, t)); index->trans(e); value->transToType(e, t); e.c.encode(inst::builtin, index->getRight() ? run::arraySliceWrite : run::arraySliceWriteToEnd); } void thisExp::prettyprint(ostream &out, Int indent) { prettyname(out, "thisExp", indent); } types::ty *thisExp::trans(coenv &e) { if (!e.c.encodeThis()) { em.error(getPos()); em << "static use of 'this' expression"; } return cgetType(e); } types::ty *thisExp::getType(coenv &e) { return e.c.thisType(); } void equalityExp::prettyprint(ostream &out, Int indent) { prettyname(out, "equalityExp", indent); callExp::prettyprint(out, indent+1); } types::ty *equalityExp::getType(coenv &e) { // Try to the resolve the expression as a function call first. types::ty *t = callExp::getType(e); assert(t); if (t->kind != ty_error) return t; else // Either an error or handled by the function equality methods. In the // first case, we may return whatever we like, and the second case always // returns bool. In either case, it is safe to return bool. return primBoolean(); } // From a possibly overloaded type, if there is a unique function type, return // it, otherwise 0. types::ty *uniqueFunction(types::ty *t) { if (t->kind == types::ty_function) return t; if (t->isOverloaded()) { types::ty *ft = 0; for (ty_iterator i = t->begin(); i != t->end(); ++i) { if ((*i)->kind != types::ty_function) continue; if (ft) { // Multiple function types. return 0; } ft = *i; } return ft; } // Not a function. return 0; } // From two possibly overloaded types, if there is a unique function type // common to both, return it, otherwise 0. types::ty *uniqueFunction(types::ty *t1, types::ty *t2) { if (t1->kind == types::ty_function) return equivalent(t1, t2) ? t1 : 0; if (t1->isOverloaded()) { types::ty *ft = 0; for (ty_iterator i = t1->begin(); i != t1->end(); ++i) { if ((*i)->kind != types::ty_function) continue; if (!equivalent(*i, t2)) continue; if (ft) { // Multiple function types. return 0; } ft = *i; } return ft; } // Not a function. return 0; } bltin bltinFromName(symbol name) { if (name == SYM_EQ) return run::boolFuncEq; assert(name == SYM_NEQ); return run::boolFuncNeq; } types::ty *equalityExp::trans(coenv &e) { // First, try to handle by normal function resolution. types::ty *t = callExp::getType(e); assert(t); if (t->kind != ty_error) return callExp::trans(e); // Then, check for the function equality case. exp *left = (*this->args)[0].val; exp *right = (*this->args)[1].val; types::ty *lt = left->getType(e); types::ty *rt = right->getType(e); // TODO: decide what null == null should do. // Check for function == null and null == function types::ty *ft = 0; if (rt->kind == types::ty_null) ft = uniqueFunction(lt); else if (lt->kind == types::ty_null) ft = uniqueFunction(rt); else ft = uniqueFunction(lt, rt); if (ft) { assert(ft->kind == ty_function); left->transToType(e, ft); right->transToType(e, ft); e.c.encode(inst::builtin, bltinFromName(callee->getName())); return primBoolean(); } else { // Let callExp report a "no such function" error. types::ty *t = callExp::trans(e); assert(t->kind == ty_error); return t; } } void scaleExp::prettyprint(ostream &out, Int indent) { exp *left=getLeft(); exp *right=getRight(); prettyname(out, "scaleExp",indent); left->prettyprint(out, indent+1); right->prettyprint(out, indent+1); } types::ty *scaleExp::trans(coenv &e) { exp *left=getLeft(); exp *right=getRight(); types::ty *lt = left->cgetType(e); if (lt->kind != types::ty_Int && lt->kind != types::ty_real) { if (lt->kind != types::ty_error) { em.error(left->getPos()); em << "only numeric constants can do implicit scaling"; } right->trans(e); return types::primError(); } if (!right->scalable()) { em.warning(right->getPos()); em << "implicit scaling may be unintentional"; } // Defer to the binaryExp for multiplication. return binaryExp::trans(e); } void intExp::prettyprint(ostream &out, Int indent) { prettyindent(out,indent); out << "intExp: " << value << "\n"; } types::ty *intExp::trans(coenv &e) { e.c.encode(inst::intpush,value); return types::primInt(); } void realExp::prettyprint(ostream &out, Int indent) { prettyindent(out, indent); out << "realExp: " << value << "\n"; } types::ty *realExp::trans(coenv &e) { e.c.encode(inst::constpush,(item)value); return types::primReal(); } void stringExp::prettyprint(ostream &out, Int indent) { prettyindent(out, indent); out << "stringExp '" << str << "'\n"; } types::ty *stringExp::trans(coenv &e) { e.c.encode(inst::constpush,(item) string(str)); return types::primString(); } void booleanExp::prettyprint(ostream &out, Int indent) { prettyindent(out, indent); out << "booleanExp: " << value << "\n"; } types::ty *booleanExp::trans(coenv &e) { e.c.encode(inst::constpush,(item)value); return types::primBoolean(); } void newPictureExp::prettyprint(ostream &out, Int indent) { prettyname(out, "newPictureExp",indent); } types::ty *newPictureExp::trans(coenv &e) { e.c.encode(inst::builtin, run::newPicture); return types::primPicture(); } void cycleExp::prettyprint(ostream &out, Int indent) { prettyname(out, "cycleExp",indent); } types::ty *cycleExp::trans(coenv &e) { e.c.encode(inst::builtin, run::newCycleToken); return types::primCycleToken(); } void nullPathExp::prettyprint(ostream &out, Int indent) { prettyname(out, "nullPathExp",indent); } types::ty *nullPathExp::trans(coenv &e) { e.c.encode(inst::builtin, run::nullPath); return types::primPath(); } void nullExp::prettyprint(ostream &out, Int indent) { prettyname(out, "nullExp",indent); } types::ty *nullExp::trans(coenv &) { // Things get put on the stack when ty_null // is cast to an appropriate type return types::primNull(); } void quoteExp::prettyprint(ostream &out, Int indent) { prettyname(out, "quoteExp", indent); value->prettyprint(out, indent+1); } types::ty *quoteExp::trans(coenv &e) { e.c.encode(inst::constpush,(item)value); return types::primCode(); } void explist::prettyprint(ostream &out, Int indent) { prettyname(out, "explist",indent); for (expvector::iterator p = exps.begin(); p != exps.end(); ++p) (*p)->prettyprint(out, indent+1); } void argument::prettyprint(ostream &out, Int indent) { prettyindent(out, indent); out << "explist"; if (name) out << " '" << name << "'"; out << '\n'; val->prettyprint(out, indent+1); } void arglist::prettyprint(ostream &out, Int indent) { prettyname(out, "arglist",indent); for (argvector::iterator p = args.begin(); p != args.end(); ++p) p->prettyprint(out, indent+1); } void callExp::prettyprint(ostream &out, Int indent) { prettyname(out, "callExp",indent); callee->prettyprint(out, indent+1); args->prettyprint(out, indent+1); } signature *callExp::argTypes(coenv &e, bool *searchable) { signature *source=new signature; // The signature is searchable unless one of the arguments is overloaded or // named. *searchable = true; size_t n = args->size(); for (size_t i = 0; i < n; i++) { argument a=(*args)[i]; types::ty *t = a.val->cgetType(e); if (t->kind == types::ty_error) return 0; if (t->kind == types::ty_overloaded || a.name) *searchable = false; source->add(types::formal(t,a.name)); } if (args->rest.val) { argument a=args->rest; types::ty *t = a.val->cgetType(e); if (t->kind == types::ty_error) return 0; if (t->kind == types::ty_overloaded || a.name) *searchable = false; source->addRest(types::formal(t,a.name)); } return source; } application *callExp::resolve(coenv &e, overloaded *o, signature *source, bool tacit) { app_list l=multimatch(e.e, o, source, *args); if (l.empty()) { //cerr << "l is empty\n"; if (!tacit) { em.error(getPos()); symbol s = callee->getName(); if (s) em << "no matching function \'" << s; else em << "no matching function for signature \'"; em << *source << "\'"; } return 0; } else if (l.size() > 1) { // This may take O(n) time. //cerr << "l is full\n"; if (!tacit) { em.error(getPos()); symbol s = callee->getName(); if(s) em << "call of function \'" << s; else em << "call with signature \'"; em << *source << "\' is ambiguous"; } return 0; } else { //cerr << "l is singleton\n"; return l.front(); } } bool hasNamedParameters(signature *sig) { for (size_t i=0; i < sig->getNumFormals(); ++i) if (sig->getFormal(i).name) return true; return false; } void callExp::reportMismatch(function *ft, signature *source) { symbol s = callee->getName(); const char *separator=ft->getSignature()->getNumFormals() > 1 ? "\n" : " "; em.error(getPos()); em << "cannot call" << separator << "'" << *ft->getResult() << " "; if(s) em << s; em << *ft->getSignature() << "'" << separator; if (ft->getSignature()->isOpen && hasNamedParameters(source)) em << "with named parameters"; else switch(source->getNumFormals()) { case 0: em << "without parameters"; break; case 1: em << "with parameter '" << *source << "'"; break; default: em << "with parameters\n'" << *source << "'"; } } void callExp::reportArgErrors(coenv &e) { // Cycle through the parameters to report all errors. // NOTE: This may report inappropriate ambiguity errors. for (size_t i = 0; i < args->size(); i++) { (*args)[i].val->trans(e); } if (args->rest.val) args->rest.val->trans(e); } void callExp::reportNonFunction() { em.error(getPos()); symbol s = callee->getName(); if (s) em << "\'" << s << "\' is not a function"; else em << "called expression is not a function"; } types::ty *callExp::cacheAppOrVarEntry(coenv &e, bool tacit) { assert(cachedVarEntry == 0 && cachedApp == 0); // First figure out the signature of what we want to call. bool searchable; signature *source=argTypes(e, &searchable); #ifdef DEBUG_GETAPP /* {{{ */ cout << "getApp for "; if (callee->getName()) cout << *callee->getName(); else cout << "unnamed"; cout << " at " << getPos() << endl; cout << "searchable: " << searchable << endl; #endif /* }}} */ if (!source) { return primError(); } // An attempt at speeding up compilation: See if the source arguments match // the (possibly overloaded) function exactly. if (searchable) { varEntry *ve = callee->getCallee(e, source); #ifdef DEBUG_GETAPP cout << "guessed: " << (ve!=0) << endl; #endif if (ve) { cachedVarEntry = ve; #ifndef DEBUG_CACHE // Normally DEBUG_CACHE is not defined and we return here for efficiency // reasons. If DEBUG_CACHE is defined, we instead proceed to resolve // the function by the normal techniques and make sure we get the same // result. return ((function *)ve->getType())->getResult(); #endif } } // Figure out what function types we can call. types::ty *ft = callee->cgetType(e); #ifdef DEBUG_GETAPP string name = callee->getName() ? string(*callee->getName()) : string("unnamed"); if (!callee->getName()) cout << getPos() << endl; #endif switch (ft->kind) { case ty_error: if (!tacit) // Report callee errors. callee->trans(e); break; case ty_function: //cout << "name " << name << endl; cachedApp = application::match(e.e, (function *)ft, source, *args); if (!cachedApp && !tacit) reportMismatch((function *)ft, source); break; case ty_overloaded: { #ifdef DEBUG_GETAPP int size = ((overloaded *)ft)->sub.size(); for (int i = 0; i < size; ++i) cout << "name " << name << endl; #endif cachedApp = resolve(e, (overloaded *)ft, source, tacit); break; } default: if (!tacit) reportNonFunction(); break; } #ifdef DEBUG_GETAPP cout << name << " " << *source << " --> " << *cachedApp->getType()->getSignature() << endl; #endif #if DEBUG_CACHE // Make sure cachedVarEntry is giving us the right function. if (cachedVarEntry) assert(equivalent(cachedVarEntry->getType(), cachedApp->getType())); #endif // getType relies on this method for the type. return cachedApp ? cachedApp->getType()->getResult() : primError(); } types::ty *callExp::transPerfectMatch(coenv &e) { // The varEntry of the callee. (No longer needed after translation.) varEntry *ve = cachedVarEntry; cachedVarEntry = 0; assert(ve); // Translate the arguments in turn. for (size_t i = 0; i < args->size(); ++i) (*args)[i].val->trans(e); if (args->rest.val) args->rest.val->trans(e); // Call the function. ve->encode(CALL, getPos(), e.c); // That's it. Return the return type of the function. return ct ? ct : dynamic_cast(ve->getType())->getResult(); } types::ty *callExp::trans(coenv &e) { if (cachedVarEntry == 0 && cachedApp == 0) cacheAppOrVarEntry(e, false); if (cachedVarEntry) return transPerfectMatch(e); // The cached data is no longer needed after translation, so let it be // garbage collected. application *a = cachedApp; cachedApp=0; if (!a) { reportArgErrors(e); return primError(); } // To simulate left-to-right order of evaluation, produce the // side-effects for the callee. assert(a); function *t=a->getType(); assert(t); exp *temp=callee->evaluate(e, t); // Let the application handle the argument translation. a->transArgs(e); // Translate the call. temp->transCall(e, t); return t->result; } types::ty *callExp::getType(coenv &e) { if (cachedApp) return cachedApp->getType()->getResult(); if (cachedVarEntry) { function *ft = dynamic_cast(cachedVarEntry->getType()); assert(ft); return ft->getResult(); } return cacheAppOrVarEntry(e, true); } bool callExp::resolved(coenv &e) { if (cachedApp == 0 && cachedVarEntry == 0) cacheAppOrVarEntry(e, true); return cachedApp || cachedVarEntry; } void pairExp::prettyprint(ostream &out, Int indent) { prettyname(out, "pairExp",indent); x->prettyprint(out, indent+1); y->prettyprint(out, indent+1); } types::ty *pairExp::trans(coenv &e) { x->transToType(e, types::primReal()); y->transToType(e, types::primReal()); e.c.encode(inst::builtin, run::realRealToPair); return types::primPair(); } void tripleExp::prettyprint(ostream &out, Int indent) { prettyname(out, "tripleExp",indent); x->prettyprint(out, indent+1); y->prettyprint(out, indent+1); z->prettyprint(out, indent+1); } types::ty *tripleExp::trans(coenv &e) { x->transToType(e, types::primReal()); y->transToType(e, types::primReal()); z->transToType(e, types::primReal()); e.c.encode(inst::builtin, run::realRealRealToTriple); return types::primTriple(); } void transformExp::prettyprint(ostream &out, Int indent) { prettyname(out, "transformExp",indent); x->prettyprint(out, indent+1); y->prettyprint(out, indent+1); xx->prettyprint(out, indent+1); xy->prettyprint(out, indent+1); yx->prettyprint(out, indent+1); yy->prettyprint(out, indent+1); } types::ty *transformExp::trans(coenv &e) { x->transToType(e, types::primReal()); y->transToType(e, types::primReal()); xx->transToType(e, types::primReal()); xy->transToType(e, types::primReal()); yx->transToType(e, types::primReal()); yy->transToType(e, types::primReal()); e.c.encode(inst::builtin, run::real6ToTransform); return types::primTransform(); } void castExp::prettyprint(ostream &out, Int indent) { prettyname(out, "castExp",indent); target->prettyprint(out, indent+1); castee->prettyprint(out, indent+1); } types::ty *castExp::tryCast(coenv &e, types::ty *t, types::ty *s, symbol csym) { types::ty *ss=e.e.castSource(t, s, csym); if (ss == 0) { return 0; } if (ss->kind == ty_overloaded) { em.error(getPos()); em << "cast is ambiguous"; return primError(); } else { castee->transAsType(e, ss); access *a=e.e.lookupCast(t, ss, csym); assert(a); a->encode(CALL, getPos(), e.c); return ss; } } types::ty *castExp::trans(coenv &e) { target->addOps(e, (record *)0); types::ty *t=target->trans(e); types::ty *s=castee->cgetType(e); if (!tryCast(e, t, s, symbol::ecastsym)) if (!tryCast(e, t, s, symbol::castsym)) { em.error(getPos()); em << "cannot cast '" << *s << "' to '" << *t << "'"; } return t; } types::ty *castExp::getType(coenv &e) { return target->trans(e, true); } void conditionalExp::prettyprint(ostream &out, Int indent) { prettyname(out, "conditionalExp",indent); test->prettyprint(out, indent+1); onTrue->prettyprint(out, indent+1); onFalse->prettyprint(out, indent+1); } void conditionalExp::baseTransToType(coenv &e, types::ty *target) { test->transToType(e, types::primBoolean()); label tlabel = e.c.fwdLabel(); e.c.useLabel(inst::cjmp,tlabel); onFalse->transToType(e, target); label end = e.c.fwdLabel(); e.c.useLabel(inst::jmp,end); e.c.defLabel(tlabel); onTrue->transToType(e, target); e.c.defLabel(end); } void conditionalExp::transToType(coenv &e, types::ty *target) { if (isAnArray(e, test)) { if (target->kind != ty_array) { em.error(getPos()); em << "cannot cast vectorized conditional to '" << *target << "'"; } test->transToType(e, types::booleanArray()); onTrue->transToType(e, target); onFalse->transToType(e, target); e.c.encode(inst::builtin, run::arrayConditional); } else { baseTransToType(e, target); } } types::ty *promote(coenv &e, types::ty *x, types::ty *y) { struct promoter : public collector { env &e; promoter(env &e) : e(e) {} types::ty *both (types::ty *x, types::ty *y) { overloaded *o=new overloaded; o->add(x); o->add(y); return o; } types::ty *base (types::ty *x, types::ty *y) { if (equivalent(x,y)) return x; else { bool castToFirst=e.castable(x, y, symbol::castsym); bool castToSecond=e.castable(y, x, symbol::castsym); return (castToFirst && castToSecond) ? both(x,y) : castToFirst ? x : castToSecond ? y : 0; } } }; promoter p(e.e); return p.collect(x,y); } types::ty *conditionalExp::trans(coenv &e) { types::ty *tt=onTrue->cgetType(e); types::ty *ft=onFalse->cgetType(e); if (tt->kind==ty_error) return onTrue->trans(e); if (ft->kind==ty_error) return onFalse->trans(e); types::ty *t=promote(e, tt, ft); if (!t) { em.error(getPos()); em << "types in conditional expression do not match"; return primError(); } else if (t->kind == ty_overloaded) { em.error(getPos()); em << "type of conditional expression is ambiguous"; return primError(); } transToType(e,t); return t; } types::ty *conditionalExp::getType(coenv &e) { types::ty *tt=onTrue->cgetType(e); types::ty *ft=onFalse->cgetType(e); if (tt->kind==ty_error || ft->kind==ty_error) return primError(); types::ty *t = promote(e, tt, ft); return t ? t : primError(); } void orExp::prettyprint(ostream &out, Int indent) { prettyname(out, "orExp", indent); left->prettyprint(out, indent+1); right->prettyprint(out, indent+1); } types::ty *orExp::trans(coenv &e) { // a || b // translates into // a ? true : b booleanExp be(pos, true); conditionalExp ce(pos, left, &be, right); ce.baseTransToType(e, primBoolean()); return getType(e); } void orExp::transConditionalJump(coenv &e, bool cond, label dest) { if (cond == true) { left->transConditionalJump(e, true, dest); right->transConditionalJump(e, true, dest); } else { /* cond == false */ label end = e.c.fwdLabel(); left->transConditionalJump(e, true, end); right->transConditionalJump(e, false, dest); e.c.defLabel(end); } } void andExp::prettyprint(ostream &out, Int indent) { prettyname(out, "andExp", indent); left->prettyprint(out, indent+1); right->prettyprint(out, indent+1); } types::ty *andExp::trans(coenv &e) { // a && b // translates into // a ? b : false booleanExp be(pos, false); conditionalExp ce(pos, left, right, &be); ce.baseTransToType(e, primBoolean()); return getType(e); } void andExp::transConditionalJump(coenv &e, bool cond, label dest) { if (cond == true) { label end = e.c.fwdLabel(); left->transConditionalJump(e, false, end); right->transConditionalJump(e, true, dest); e.c.defLabel(end); } else { /* cond == false */ left->transConditionalJump(e, false, dest); right->transConditionalJump(e, false, dest); } } void joinExp::prettyprint(ostream &out, Int indent) { prettyname(out, "joinExp",indent); callee->prettyprint(out, indent+1); args->prettyprint(out, indent+1); } void specExp::prettyprint(ostream &out, Int indent) { prettyindent(out,indent); out << "specExp '" << op << "' " << (s==camp::OUT ? "out" : s==camp::IN ? "in" : "invalid side") << '\n'; arg->prettyprint(out, indent+1); } types::ty *specExp::trans(coenv &e) { intExp ie(getPos(), (Int)s); binaryExp be(getPos(), arg, op, &ie); return be.trans(e); } types::ty *specExp::getType(coenv &e) { intExp ie(getPos(), (Int)s); binaryExp be(getPos(), arg, op, &ie); return be.cgetType(e); } void assignExp::prettyprint(ostream &out, Int indent) { prettyname(out, "assignExp",indent); dest->prettyprint(out, indent+1); value->prettyprint(out, indent+1); } void assignExp::transAsType(coenv &e, types::ty *target) { #if 0 // For left-to-right order, we have to evaluate the side-effects of the // destination first. exp *temp=dest->evaluate(e, target); ultimateValue(temp)->transToType(e, target); temp->transWrite(e, target); #endif // All of the heavy work is handled by transWrite. dest->transWrite(e, target, value); } types::ty *assignExp::trans(coenv &e) { exp *uvalue=ultimateValue(dest); types::ty *lt = dest->cgetType(e), *rt = uvalue->cgetType(e); if (lt->kind == ty_error) return dest->trans(e); if (rt->kind == ty_error) return uvalue->trans(e); types::ty *t = e.e.castTarget(lt, rt, symbol::castsym); if (!t) { em.error(getPos()); em << "cannot convert '" << *rt << "' to '" << *lt << "' in assignment"; return primError(); } else if (t->kind == ty_overloaded) { em.error(getPos()); em << "assignment is ambiguous"; return primError(); } else { transAsType(e, t); return t; } } types::ty *assignExp::getType(coenv &e) { types::ty *lt = dest->cgetType(e), *rt = ultimateValue(dest)->cgetType(e); if (lt->kind==ty_error || rt->kind==ty_error) return primError(); types::ty *t = e.e.castTarget(lt, rt, symbol::castsym); return t ? t : primError(); } void selfExp::prettyprint(ostream &out, Int indent) { prettyindent(out, indent); out << "selfExp '" << op << "'\n"; dest->prettyprint(out, indent+1); value->prettyprint(out, indent+1); } void selfExp::transAsType(coenv &e, types::ty *target) { // Create a temp expression for the destination, so it is not evaluated // twice. exp *temp=dest->evaluate(e, target); temp->transWrite(e, target, ultimateValue(temp)); } void prefixExp::prettyprint(ostream &out, Int indent) { prettyindent(out, indent); out << "prefixExp '" << op << "'\n"; dest->prettyprint(out, indent+1); } types::ty *prefixExp::trans(coenv &e) { // Convert into the operation and the assign. // NOTE: This can cause multiple evaluations. intExp ie(getPos(), 1); selfExp se(getPos(), dest, op, &ie); return se.trans(e); } types::ty *prefixExp::getType(coenv &e) { // Convert into the operation and the assign. intExp ie(getPos(), 1); selfExp se(getPos(), dest, op, &ie); return se.getType(e); } void postfixExp::prettyprint(ostream &out, Int indent) { prettyindent(out, indent); out << "postfixExp '" << op << "'\n"; dest->prettyprint(out, indent+1); } types::ty *postfixExp::trans(coenv &) { em.error(getPos()); em << "postfix expressions are not allowed"; return primError(); } } // namespace absyntax asymptote-2.37/exp.h000066400000000000000000000702111265434602500144470ustar00rootroot00000000000000/***** * exp.h * Andy Hammerlindl 2002/8/19 * * Represents the abstract syntax tree for the expressions in the * language. this is translated into virtual machine code using trans() * and with the aid of the environment class. *****/ #ifndef EXP_H #define EXP_H #include "types.h" #include "symbol.h" #include "absyn.h" #include "varinit.h" #include "name.h" #include "guideflags.h" namespace trans { class coenv; class coder; struct label_t; typedef label_t *label; class application; } namespace absyntax { using trans::coenv; using trans::label; using trans::application; using trans::access; using sym::symbol; using types::record; using types::array; class exp : public varinit { protected: // The cached type (from a call to cgetType). types::ty *ct; public: exp(position pos) : varinit(pos), ct(0) {} void prettyprint(ostream &out, Int indent) = 0; // When reporting errors with function calls, it is nice to say "no // function f(int)" instead of "no function matching signature // (int)." Hence, this method returns the name of the expression if // there is one. virtual symbol getName() { return symbol::nullsym; } // Checks if the expression can be used as the right side of a scale // expression. ie. 3sin(x) // If a "non-scalable" expression is scaled a warning is issued. virtual bool scalable() { return true; } // Specifies if the value of the expression should be written to interactive // prompt if typed as a stand-alone expression. For example: // > 2+3; // should write 5, but // > x=2+3; // shouldn't. (These choices are largely aesthetic) virtual bool writtenToPrompt() { return true; } // Translates the expression to the given target type. This should only be // called with a type returned by getType(). It does not perform implicit // casting. virtual void transAsType(coenv &e, types::ty *target); // Translates the expression to the given target type, possibly using an // implicit cast. void transToType(coenv &e, types::ty *target); // Translates the expression and returns the resultant type. // For some expressions, this will be ambiguous and return an error. // Trans may only return ty_error, if it (or one of its recursively // called children in the syntax tree) reported an error to em. virtual types::ty *trans(coenv &) = 0; // getType() figures out the type of the expression without translating // the code into the virtual machine language or reporting errors to em. // This must follow a few rules to ensure proper translation: // 1. If this returns a valid type, t, trans(e) must return t or // report an error, and transToType(e, t) must run either reporting // an error or reporting no error and yielding the same result as // trans(e). // 2. If this returns a superposition of types (ie. for overloaded // functions), trans must not return a singular type, and every // type in the superposition must run without error properly // if fed to transAsType(e, t). // 3. If this returns ty_error, then so must a call to trans(e) and any // call to trans, transAsType, or transToType must report an error // to em. // 4. Any call to transAsType(e, t) with a type that is not returned by // getType() (or one of the subtypes in case of a superposition) // must report an error. // Any call to transToType(e, t) with a type that is not returned by // getType() (or one of the subtypes in case of a superposition) // or any type not implicitly castable from the above must report an // error. virtual types::ty *getType(coenv &) = 0; // This is an optimization which works in some cases to by-pass the slow // overloaded function resolution provided by the application class. // // If an expression is called with arguments given by sig, getCallee must // either return 0 (the default), or if it returns a varEntry, the varEntry // must correspond to the function which would be called after normal // function resolution. // // The callee must produce no side effects as there are no guarantees when // the varEntry will be translated. virtual trans::varEntry *getCallee(coenv &e, types::signature *sig) { //#define DEBUG_GETAPP #if DEBUG_GETAPP cout << "exp fail" << endl; cout << "exp fail at " << getPos() << endl; prettyprint(cout, 2); #endif return 0; } // Same result as getType, but caches the result so that subsequent // calls are faster. For this to work correctly, the expression should // only be used in one place, so the environment doesn't change between // calls. virtual types::ty *cgetType(coenv &e) { #ifdef DEBUG_CACHE testCachedType(e); #endif return ct ? ct : ct = getType(e); } void testCachedType(coenv &e); // The expression is being written. Translate code such that the value // (represented by the exp value) is stored into the address represented by // this expression. // In terms of side-effects, this expression must be evaluated (once) before // value is evaluated (once). virtual void transWrite(coenv &e, types::ty *t, exp *value) { em.error(getPos()); em << "expression cannot be used as an address"; // Translate the value for errors. value->transToType(e, t); } // Translates code for calling a function. The arguments, in the order they // appear in the function's signature, must all be on the stack. virtual void transCall(coenv &e, types::ty *target); // transConditionalJump must produce code equivalent to the following: // Evaluate the expression as a boolean. If the result equals cond, jump to // the label dest, otherwise do not jump. In either case, no value is left // on the stack. virtual void transConditionalJump(coenv &e, bool cond, label dest); // This is used to ensure the proper order and number of evaluations. When // called, it immediately translates code to perform the side-effects // consistent with a corresponding call to transAsType(e, target). // // The return value, called an evaluation for lack of a better name, is // another expression that responds to the trans methods exactly as would the // original expression, but without producing side-effects. It is also no // longer overloaded, due to the resolution effected by giving a target type // to evaluate(). // // The methods transAsType, transWrite, and transCall of the evaluation must // be called with the same target type as the original call to evaluate. // When evaluate() is called during the translation of a function, that // function must still be in translation when the evaluation is translated. // // The base implementation uses a tempExp (see below). This is // sufficient for most expressions. virtual exp *evaluate(coenv &e, types::ty *target); // NOTE: could add a "side-effects" method which says if the expression has // side-effects. This might allow some small optimizations in translating. }; class tempExp : public exp { access *a; types::ty *t; public: tempExp(coenv &e, varinit *v, types::ty *t); void prettyprint(ostream &out, Int indent); types::ty *trans(coenv &e); types::ty *getType(coenv &) { return t; } }; // Wrap a varEntry so that it can be used as an expression. // Translating the varEntry must cause no side-effects. class varEntryExp : public exp { trans::varEntry *v; public: varEntryExp(position pos, trans::varEntry *v) : exp(pos), v(v) {} varEntryExp(position pos, types::ty *t, access *a); varEntryExp(position pos, types::ty *t, vm::bltin f); void prettyprint(ostream &out, Int indent); types::ty *getType(coenv &); types::ty *trans(coenv &e); trans::varEntry *getCallee(coenv &e, types::signature *sig); void transAct(action act, coenv &e, types::ty *target); void transAsType(coenv &e, types::ty *target); void transWrite(coenv &e, types::ty *t, exp *value); void transCall(coenv &e, types::ty *target); }; class nameExp : public exp { name *value; public: nameExp(position pos, name *value) : exp(pos), value(value) {} nameExp(position pos, symbol id) : exp(pos), value(new simpleName(pos, id)) {} nameExp(position pos, string s) : exp(pos), value(new simpleName(pos, symbol::trans(s))) {} void prettyprint(ostream &out, Int indent); symbol getName() { return value->getName(); } void transAsType(coenv &e, types::ty *target) { value->varTrans(trans::READ, e, target); // After translation, the cached type is no longer needed and should be // garbage collected. This could presumably be done in every class derived // from exp, but here it is most important as nameExp can have heavily // overloaded types cached. ct=0; } types::ty *trans(coenv &e) { types::ty *t=cgetType(e); if (t->kind == types::ty_error) { em.error(getPos()); em << "no matching variable \'" << *value << "\'"; return types::primError(); } if (t->kind == types::ty_overloaded) { em.error(getPos()); em << "use of variable \'" << *value << "\' is ambiguous"; return types::primError(); } else { transAsType(e, t); return t; } } types::ty *getType(coenv &e) { types::ty *t=value->varGetType(e); return t ? t : types::primError(); } trans::varEntry *getCallee(coenv &e, types::signature *sig) { #ifdef DEBUG_GETAPP cout << "nameExp" << endl; #endif return value->getCallee(e, sig); } void transWrite(coenv &e, types::ty *target, exp *newValue) { newValue->transToType(e, target); this->value->varTrans(trans::WRITE, e, target); ct=0; // See note in transAsType. } void transCall(coenv &e, types::ty *target) { value->varTrans(trans::CALL, e, target); ct=0; // See note in transAsType. } exp *evaluate(coenv &, types::ty *) { // Names have no side-effects. return this; } }; // Most fields accessed are handled as parts of qualified names, but in cases // like f().x or (new t).x, a separate expression is needed. class fieldExp : public nameExp { exp *object; symbol field; // fieldExp has a lot of common functionality with qualifiedName, so we // essentially hack qualifiedName, by making our object expression look // like a name. class pseudoName : public name { exp *object; public: pseudoName(exp *object) : name(object->getPos()), object(object) {} // As a variable: void varTrans(trans::action act, coenv &e, types::ty *target) { assert(act == trans::READ); object->transToType(e, target); } types::ty *varGetType(coenv &e) { return object->getType(e); } trans::varEntry *getCallee(coenv &, types::signature *) { #ifdef DEBUG_GETAPP cout << "pseudoName" << endl; #endif return 0; } // As a type: types::ty *typeTrans(coenv &, bool tacit = false) { if (!tacit) { em.error(getPos()); em << "expression is not a type"; } return types::primError(); } trans::varEntry *getVarEntry(coenv &) { em.compiler(getPos()); em << "expression cannot be used as part of a type"; return 0; } trans::tyEntry *tyEntryTrans(coenv &) { em.compiler(getPos()); em << "expression cannot be used as part of a type"; return 0; } trans::frame *tyFrameTrans(coenv &) { return 0; } void prettyprint(ostream &out, Int indent); void print(ostream& out) const { out << ""; } symbol getName() { return object->getName(); } }; // Try to get this into qualifiedName somehow. types::ty *getObject(coenv &e); public: fieldExp(position pos, exp *object, symbol field) : nameExp(pos, new qualifiedName(pos, new pseudoName(object), field)), object(object), field(field) {} void prettyprint(ostream &out, Int indent); symbol getName() { return field; } exp *evaluate(coenv &e, types::ty *) { // Evaluate the object. return new fieldExp(getPos(), new tempExp(e, object, getObject(e)), field); } }; class arrayExp : public exp { protected: exp *set; array *getArrayType(coenv &e); array *transArray(coenv &e); public: arrayExp(position pos, exp *set) : exp(pos), set(set) {} }; class subscriptExp : public arrayExp { exp *index; public: subscriptExp(position pos, exp *set, exp *index) : arrayExp(pos, set), index(index) {} void prettyprint(ostream &out, Int indent); types::ty *trans(coenv &e); types::ty *getType(coenv &e); void transWrite(coenv &e, types::ty *t, exp *value); exp *evaluate(coenv &e, types::ty *) { return new subscriptExp(getPos(), new tempExp(e, set, getArrayType(e)), new tempExp(e, index, types::primInt())); } }; class slice : public absyn { exp *left; exp *right; public: slice(position pos, exp *left, exp *right) : absyn(pos), left(left), right(right) {} void prettyprint(ostream &out, Int indent); exp *getLeft() { return left; } exp *getRight() { return right; } // Translates code to put the left and right expressions on the stack (in that // order). If left is omitted, zero is pushed on the stack in it's place. If // right is omitted, nothing is pushed in its place. void trans(coenv &e); slice *evaluate(coenv &e) { return new slice(getPos(), left ? new tempExp(e, left, types::primInt()) : 0, right ? new tempExp(e, right, types::primInt()) : 0); } }; class sliceExp : public arrayExp { slice *index; public: sliceExp(position pos, exp *set, slice *index) : arrayExp(pos, set), index(index) {} void prettyprint(ostream &out, Int indent); types::ty *trans(coenv &e); types::ty *getType(coenv &e); void transWrite(coenv &e, types::ty *t, exp *value); exp *evaluate(coenv &e, types::ty *) { return new sliceExp(getPos(), new tempExp(e, set, getArrayType(e)), index->evaluate(e)); } }; // The expression "this," that evaluates to the lexically enclosing record. class thisExp : public exp { public: thisExp(position pos) : exp(pos) {} void prettyprint(ostream &out, Int indent); types::ty *trans(coenv &e); types::ty *getType(coenv &e); exp *evaluate(coenv &, types::ty *) { // this has no side-effects return this; } }; class literalExp : public exp { public: literalExp(position pos) : exp(pos) {} bool scalable() { return false; } exp *evaluate(coenv &, types::ty *) { // Literals are constant, they have no side-effects. return this; } }; class intExp : public literalExp { Int value; public: intExp(position pos, Int value) : literalExp(pos), value(value) {} void prettyprint(ostream &out, Int indent); types::ty *trans(coenv &e); types::ty *getType(coenv &) { return types::primInt(); } }; class realExp : public literalExp { protected: double value; public: realExp(position pos, double value) : literalExp(pos), value(value) {} void prettyprint(ostream &out, Int indent); types::ty *trans(coenv &e); types::ty *getType(coenv &) { return types::primReal(); } }; class stringExp : public literalExp { string str; public: stringExp(position pos, string str) : literalExp(pos), str(str) {} void prettyprint(ostream &out, Int indent); types::ty *trans(coenv &e); types::ty *getType(coenv &) { return types::primString(); } const string& getString() { return str; } }; class booleanExp : public literalExp { bool value; public: booleanExp(position pos, bool value) : literalExp(pos), value(value) {} void prettyprint(ostream &out, Int indent); types::ty *trans(coenv &e); types::ty *getType(coenv &) { return types::primBoolean(); } }; class cycleExp : public literalExp { public: cycleExp(position pos) : literalExp(pos) {} void prettyprint(ostream &out, Int indent); types::ty *trans(coenv &e); types::ty *getType(coenv &) { return types::primCycleToken(); } }; class newPictureExp : public literalExp { public: newPictureExp(position pos) : literalExp(pos) {} void prettyprint(ostream &out, Int indent); types::ty *trans(coenv &e); types::ty *getType(coenv &) { return types::primPicture(); } }; class nullPathExp : public literalExp { public: nullPathExp(position pos) : literalExp(pos) {} void prettyprint(ostream &out, Int indent); types::ty *trans(coenv &e); types::ty *getType(coenv &) { return types::primPath(); } }; class nullExp : public literalExp { public: nullExp(position pos) : literalExp(pos) {} void prettyprint(ostream &out, Int indent); types::ty *trans(coenv &e); types::ty *getType(coenv &) { return types::primNull(); } }; class quoteExp : public exp { runnable *value; public: quoteExp(position pos, runnable *value) : exp(pos), value(value) {} void prettyprint(ostream &out, Int indent); types::ty *trans(coenv &e); types::ty *getType(coenv &) { return types::primCode(); } }; // A list of expressions used in a function call. class explist : public absyn { typedef mem::vector expvector; expvector exps; public: explist(position pos) : absyn(pos) {} virtual ~explist() {} virtual void add(exp *e) { exps.push_back(e); } virtual void prettyprint(ostream &out, Int indent); virtual size_t size() { return exps.size(); } virtual exp * operator[] (size_t index) { return exps[index]; } }; struct argument { exp *val; symbol name; // No constructor due to the union in camp.y #if 0 argument(exp *val=0, symbol name=0) : val(val), name(name) {} #endif void prettyprint(ostream &out, Int indent); }; class arglist : public gc { public: typedef mem::vector argvector; argvector args; argument rest; // As the language allows named arguments after rest arguments, store the // index of the rest argument in order to ensure proper left-to-right // execution. static const size_t DUMMY_REST_POSITION = 9999; size_t restPosition; arglist() : args(), rest(), restPosition(DUMMY_REST_POSITION) {} virtual ~arglist() {} virtual void addFront(argument a) { args.insert(args.begin(), a); } virtual void addFront(exp *val, symbol name=symbol::nullsym) { argument a; a.val=val; a.name=name; addFront(a); } virtual void add(argument a) { if (rest.val && !a.name) { em.error(a.val->getPos()); em << "unnamed argument after rest argument"; return; } args.push_back(a); } virtual void add(exp *val, symbol name=symbol::nullsym) { argument a; a.val=val; a.name=name; add(a); } virtual void addRest(argument a) { if (rest.val) { em.error(a.val->getPos()); em << "additional rest argument"; return; } rest = a; assert(restPosition == DUMMY_REST_POSITION); restPosition = size(); } virtual void prettyprint(ostream &out, Int indent); virtual size_t size() { return args.size(); } virtual argument& operator[] (size_t index) { return args[index]; } virtual argument& getRest() { return rest; } }; // callExp has a global cache of resolved overloaded functions. This clears // this cache so the associated data can be garbage collected. void clearCachedCalls(); class callExp : public exp { protected: exp *callee; arglist *args; private: // Per object caching - Cache the application when it's determined. application *cachedApp; // In special cases, no application object is needed and we can store the // varEntry used in advance. trans::varEntry *cachedVarEntry; types::signature *argTypes(coenv& e, bool *searchable); void reportArgErrors(coenv &e); application *resolve(coenv &e, types::overloaded *o, types::signature *source, bool tacit); application *resolveWithCache(coenv &e, types::overloaded *o, types::signature *source, bool tacit); void reportMismatch(types::function *ft, types::signature *source); void reportNonFunction(); // Caches either the application object used to apply the function to the // arguments, or in cases where the arguments match the function perfectly, // the varEntry of the callee (or neither in case of an error). Returns // what getType should return. types::ty *cacheAppOrVarEntry(coenv &e, bool tacit); types::ty *transPerfectMatch(coenv &e); public: callExp(position pos, exp *callee, arglist *args) : exp(pos), callee(callee), args(args), cachedApp(0), cachedVarEntry(0) { assert(args); } callExp(position pos, exp *callee) : exp(pos), callee(callee), args(new arglist()), cachedApp(0), cachedVarEntry(0) {} callExp(position pos, exp *callee, exp *arg1) : exp(pos), callee(callee), args(new arglist()), cachedApp(0), cachedVarEntry(0) { args->add(arg1); } callExp(position pos, exp *callee, exp *arg1, exp *arg2) : exp(pos), callee(callee), args(new arglist()), cachedApp(0), cachedVarEntry(0) { args->add(arg1); args->add(arg2); } callExp(position pos, exp *callee, exp *arg1, exp *arg2, exp *arg3) : exp(pos), callee(callee), args(new arglist()), cachedApp(0), cachedVarEntry(0) { args->add(arg1); args->add(arg2); args->add(arg3); } void prettyprint(ostream &out, Int indent); types::ty *trans(coenv &e); types::ty *getType(coenv &e); // Returns true if the function call resolves uniquely without error. Used // in implementing the special == and != operators for functions. virtual bool resolved(coenv &e); }; class pairExp : public exp { exp *x; exp *y; public: pairExp(position pos, exp *x, exp *y) : exp(pos), x(x), y(y) {} void prettyprint(ostream &out, Int indent); types::ty *trans(coenv &e); types::ty *getType(coenv &) { return types::primPair(); } }; class tripleExp : public exp { exp *x; exp *y; exp *z; public: tripleExp(position pos, exp *x, exp *y, exp *z) : exp(pos), x(x), y(y), z(z) {} void prettyprint(ostream &out, Int indent); types::ty *trans(coenv &e); types::ty *getType(coenv &) { return types::primTriple(); } }; class transformExp : public exp { exp *x; exp *y; exp *xx,*xy,*yx,*yy; public: transformExp(position pos, exp *x, exp *y, exp *xx, exp *xy, exp *yx, exp *yy) : exp(pos), x(x), y(y), xx(xx), xy(xy), yx(yx), yy(yy) {} void prettyprint(ostream &out, Int indent); types::ty *trans(coenv &e); types::ty *getType(coenv &) { return types::primTransform(); } }; class castExp : public exp { ty *target; exp *castee; types::ty *tryCast(coenv &e, types::ty *t, types::ty *s, symbol csym); public: castExp(position pos, ty *target, exp *castee) : exp(pos), target(target), castee(castee) {} void prettyprint(ostream &out, Int indent); types::ty *trans(coenv &e); types::ty *getType(coenv &e); }; class nullaryExp : public callExp { public: nullaryExp(position pos, symbol op) : callExp(pos, new nameExp(pos, op)) {} }; class unaryExp : public callExp { public: unaryExp(position pos, exp *base, symbol op) : callExp(pos, new nameExp(pos, op), base) {} }; class binaryExp : public callExp { public: binaryExp(position pos, exp *left, symbol op, exp *right) : callExp(pos, new nameExp(pos, op), left, right) {} }; class equalityExp : public callExp { public: equalityExp(position pos, exp *left, symbol op, exp *right) : callExp(pos, new nameExp(pos, op), left, right) {} void prettyprint(ostream &out, Int indent); types::ty *trans(coenv &e); types::ty *getType(coenv &e); }; // Scaling expressions such as 3sin(x). class scaleExp : public binaryExp { exp *getLeft() { return (*this->args)[0].val; } exp *getRight() { return (*this->args)[1].val; } public: scaleExp(position pos, exp *left, exp *right) : binaryExp(pos, left, symbol::trans("*"), right) {} void prettyprint(ostream &out, Int indent); types::ty *trans(coenv &e); //types::ty *getType(coenv &e); bool scalable() { return false; } }; // Used for tension, which takes two real values, and a boolean to denote if it // is a tension atleast case. class ternaryExp : public callExp { public: ternaryExp(position pos, exp *left, symbol op, exp *right, exp *last) : callExp(pos, new nameExp(pos, op), left, right, last) {} }; // The a ? b : c ternary operator. class conditionalExp : public exp { exp *test; exp *onTrue; exp *onFalse; public: conditionalExp(position pos, exp *test, exp *onTrue, exp *onFalse) : exp(pos), test(test), onTrue(onTrue), onFalse(onFalse) {} void prettyprint(ostream &out, Int indent); void baseTransToType(coenv &e, types::ty *target); void transToType(coenv &e, types::ty *target); types::ty *trans(coenv &e); types::ty *getType(coenv &e); }; class andOrExp : public exp { protected: exp *left; symbol op; exp *right; public: andOrExp(position pos, exp *left, symbol op, exp *right) : exp(pos), left(left), op(op), right(right) {} virtual types::ty *trans(coenv &e) = 0; virtual types::ty *getType(coenv &) { return types::primBoolean(); } }; class orExp : public andOrExp { public: orExp(position pos, exp *left, symbol op, exp *right) : andOrExp(pos, left, op, right) {} void prettyprint(ostream &out, Int indent); types::ty *trans(coenv &e); void transConditionalJump(coenv &e, bool cond, label dest); }; class andExp : public andOrExp { public: andExp(position pos, exp *left, symbol op, exp *right) : andOrExp(pos, left, op, right) {} void prettyprint(ostream &out, Int indent); types::ty *trans(coenv &e); void transConditionalJump(coenv &e, bool cond, label dest); }; class joinExp : public callExp { public: joinExp(position pos, symbol op) : callExp(pos, new nameExp(pos, op)) {} void pushFront(exp *e) { args->addFront(e); } void pushBack(exp *e) { args->add(e); } void prettyprint(ostream &out, Int indent); }; class specExp : public exp { symbol op; exp *arg; camp::side s; public: specExp(position pos, symbol op, exp *arg, camp::side s=camp::OUT) : exp(pos), op(op), arg(arg), s(s) {} void setSide(camp::side ss) { s=ss; } void prettyprint(ostream &out, Int indent); types::ty *trans(coenv &e); types::ty *getType(coenv &e); }; class assignExp : public exp { protected: exp *dest; exp *value; // This is basically a hook to facilitate selfExp. dest is given as an // argument since it will be a temporary in translation in order to avoid // multiple evaluation. virtual exp *ultimateValue(exp *) { return value; } public: assignExp(position pos, exp *dest, exp *value) : exp(pos), dest(dest), value(value) {} void prettyprint(ostream &out, Int indent); // Don't write the result of an assignment to the prompt. bool writtenToPrompt() { return false; } void transAsType(coenv &e, types::ty *target); types::ty *trans(coenv &e); types::ty *getType(coenv &e); }; class selfExp : public assignExp { symbol op; exp *ultimateValue(exp *dest) { return new binaryExp(getPos(), dest, op, value); } public: selfExp(position pos, exp *dest, symbol op, exp *value) : assignExp(pos, dest, value), op(op) {} void prettyprint(ostream &out, Int indent); void transAsType(coenv &e, types::ty *target); }; class prefixExp : public exp { exp *dest; symbol op; public: prefixExp(position pos, exp *dest, symbol op) : exp(pos), dest(dest), op(op) {} void prettyprint(ostream &out, Int indent); bool scalable() { return false; } // Don't write the result to the prompt. bool writtenToPrompt() { return false; } types::ty *trans(coenv &e); types::ty *getType(coenv &e); }; // Postfix expresions are illegal. This is caught here as we can give a // more meaningful error message to the user, rather than a "parse // error." class postfixExp : public exp { exp *dest; symbol op; public: postfixExp(position pos, exp *dest, symbol op) : exp(pos), dest(dest), op(op) {} void prettyprint(ostream &out, Int indent); types::ty *trans(coenv &e); types::ty *getType(coenv &) { return types::primError(); } }; } // namespace absyntax #endif asymptote-2.37/fftw++.cc000066400000000000000000000032111265434602500151010ustar00rootroot00000000000000#include #include #include "fftw++.h" using namespace std; namespace fftwpp { const double fftw::twopi=2.0*acos(-1.0); // User settings: unsigned int fftw::effort=FFTW_MEASURE; const char *fftw::WisdomName=".wisdom"; unsigned int fftw::maxthreads=1; double fftw::testseconds=0.2; // Time limit for threading efficiency tests fftw_plan (*fftw::planner)(fftw *f, Complex *in, Complex *out)=Planner; const char *fftw::oddshift="Shift is not implemented for odd nx"; const char *inout= "constructor and call must be both in place or both out of place"; fft1d::Table fft1d::threadtable; mfft1d::Table mfft1d::threadtable; rcfft1d::Table rcfft1d::threadtable; crfft1d::Table crfft1d::threadtable; mrcfft1d::Table mrcfft1d::threadtable; mcrfft1d::Table mcrfft1d::threadtable; fft2d::Table fft2d::threadtable; void LoadWisdom() { static bool Wise=false; if(!Wise) { ifstream ifWisdom; ifWisdom.open(fftw::WisdomName); ostringstream wisdom; wisdom << ifWisdom.rdbuf(); ifWisdom.close(); fftw_import_wisdom_from_string(wisdom.str().c_str()); Wise=true; } } void SaveWisdom() { ofstream ofWisdom; ofWisdom.open(fftw::WisdomName); char *wisdom=fftw_export_wisdom_to_string(); ofWisdom << wisdom; fftw_free(wisdom); ofWisdom.close(); } fftw_plan Planner(fftw *F, Complex *in, Complex *out) { LoadWisdom(); fftw::effort |= FFTW_WISDOM_ONLY; fftw_plan plan=F->Plan(in,out); fftw::effort &= !FFTW_WISDOM_ONLY; if(!plan) { plan=F->Plan(in,out); SaveWisdom(); } return plan; } ThreadBase::ThreadBase() {threads=fftw::maxthreads;} } namespace utils { unsigned int defaultmpithreads=1; } asymptote-2.37/fftw++.h000066400000000000000000001326311265434602500147540ustar00rootroot00000000000000/* Fast Fourier transform C++ header class for the FFTW3 Library Copyright (C) 2004-15 John C. Bowman, University of Alberta Malcolm Roberts, University of Strasbourg This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __fftwpp_h__ #define __fftwpp_h__ 1 #define __FFTWPP_H_VERSION__ 2.00 #include #include #include #include #include #include #ifndef _OPENMP #ifndef FFTWPP_SINGLE_THREAD #define FFTWPP_SINGLE_THREAD #endif #endif #ifndef FFTWPP_SINGLE_THREAD #include #endif inline int get_thread_num() { #ifdef FFTWPP_SINGLE_THREAD return 0; #else return omp_get_thread_num(); #endif } inline int get_max_threads() { #ifdef FFTWPP_SINGLE_THREAD return 1; #else return omp_get_max_threads(); #endif } #ifndef FFTWPP_SINGLE_THREAD #define PARALLEL(code) \ if(threads > 1) { \ _Pragma("omp parallel for num_threads(threads)") \ code \ } else { \ code \ } #else #define PARALLEL(code) \ { \ code \ } #endif #ifndef __Complex_h__ #include typedef std::complex Complex; #endif #include "seconds.h" #include "statistics.h" #include "align.h" namespace fftwpp { // Obsolete names: #define FFTWComplex ComplexAlign #define FFTWdouble doubleAlign #define FFTWdelete deleteAlign class fftw; extern "C" fftw_plan Planner(fftw *F, Complex *in, Complex *out); void LoadWisdom(); void SaveWisdom(); extern const char *inout; struct threaddata { unsigned int threads; double mean; double stdev; threaddata() : threads(0), mean(0.0), stdev(0.0) {} threaddata(unsigned int threads, double mean, double stdev) : threads(threads), mean(mean), stdev(stdev) {} }; class fftw; class ThreadBase { protected: unsigned int threads; unsigned int innerthreads; public: ThreadBase(); ThreadBase(unsigned int threads) : threads(threads) {} void Threads(unsigned int nthreads) {threads=nthreads;} unsigned int Threads() {return threads;} void multithread(unsigned int nx) { if(nx >= threads) { innerthreads=1; } else { innerthreads=threads; threads=1; } } }; // Base clase for fft routines // class fftw : public ThreadBase { protected: unsigned int doubles; // number of double precision values in dataset int sign; unsigned int threads; double norm; fftw_plan plan; bool inplace; unsigned int Dist(unsigned int n, size_t stride, size_t dist) { return dist ? dist : ((stride == 1) ? n : 1); } unsigned int realsize(unsigned int n, Complex *in, Complex *out=NULL) { return (!out || in == out) ? 2*(n/2+1) : n; } unsigned int realsize(unsigned int n, Complex *in, double *out) { return realsize(n,in,(Complex *) out); } unsigned int realsize(unsigned int n, double *in, Complex *out) { return realsize(n,(Complex *) in,out); } static const double twopi; public: static unsigned int effort; static unsigned int maxthreads; static double testseconds; static const char *WisdomName; static fftw_plan (*planner)(fftw *f, Complex *in, Complex *out); virtual unsigned int Threads() {return threads;} static const char *oddshift; // Inplace shift of Fourier origin to (nx/2,0) for even nx. static void Shift(Complex *data, unsigned int nx, unsigned int ny, unsigned int threads) { unsigned int nyp=ny/2+1; unsigned int stop=nx*nyp; if(nx % 2 == 0) { unsigned int inc=2*nyp; #ifndef FFTWPP_SINGLE_THREAD #pragma omp parallel for num_threads(threads) #endif for(unsigned int i=nyp; i < stop; i += inc) { Complex *p=data+i; for(unsigned int j=0; j < nyp; j++) p[j]=-p[j]; } } else { std::cerr << oddshift << std::endl; exit(1); } } // Out-of-place shift of Fourier origin to (nx/2,0) for even nx. static void Shift(double *data, unsigned int nx, unsigned int ny, unsigned int threads) { if(nx % 2 == 0) { unsigned int stop=nx*ny; unsigned int inc=2*ny; #ifndef FFTWPP_SINGLE_THREAD #pragma omp parallel for num_threads(threads) #endif for(unsigned int i=ny; i < stop; i += inc) { double *p=data+i; for(unsigned int j=0; j < ny; j++) p[j]=-p[j]; } } else { std::cerr << oddshift << std::endl; exit(1); } } // Inplace shift of Fourier origin to (nx/2,ny/2,0) for even nx and ny. static void Shift(Complex *data, unsigned int nx, unsigned int ny, unsigned int nz, unsigned int threads) { unsigned int nzp=nz/2+1; unsigned int nyzp=ny*nzp; if(nx % 2 == 0 && ny % 2 == 0) { unsigned int pinc=2*nzp; Complex *pstop=data; Complex *p=data; #ifndef FFTWPP_SINGLE_THREAD #pragma omp parallel for num_threads(threads) #endif for(unsigned i=0; i < nx; i++) { if(i % 2) p -= nzp; else p += nzp; pstop += nyzp; for(; p < pstop; p += pinc) { for(unsigned int k=0; k < nzp; k++) p[k]=-p[k]; } } } else { std::cerr << oddshift << " or odd ny" << std::endl; exit(1); } } // Out-of-place shift of Fourier origin to (nx/2,ny/2,0) for even nx and ny. static void Shift(double *data, unsigned int nx, unsigned int ny, unsigned int nz, unsigned int threads) { unsigned int nyz=ny*nz; if(nx % 2 == 0 && ny % 2 == 0) { unsigned int pinc=2*nz; double *pstop=data; double *p=data; #ifndef FFTWPP_SINGLE_THREAD #pragma omp parallel for num_threads(threads) #endif for(unsigned i=0; i < nx; i++) { if(i % 2) p -= nz; else p += nz; pstop += nyz; for(; p < pstop; p += pinc) { for(unsigned int k=0; k < nz; k++) p[k]=-p[k]; } } } else { std::cerr << oddshift << " or odd ny" << std::endl; exit(1); } } fftw() : plan(NULL) {} fftw(unsigned int doubles, int sign, unsigned int threads, unsigned int n=0) : doubles(doubles), sign(sign), threads(threads), norm(1.0/(n ? n : doubles/2)), plan(NULL) { #ifndef FFTWPP_SINGLE_THREAD fftw_init_threads(); #endif } virtual ~fftw() { if(plan) fftw_destroy_plan(plan); } virtual fftw_plan Plan(Complex *in, Complex *out) {return NULL;}; inline void CheckAlign(Complex *p, const char *s) { if((size_t) p % sizeof(Complex) == 0) return; std::cerr << "WARNING: " << s << " array is not " << sizeof(Complex) << "-byte aligned: address " << p << std::endl; } void noplan() { std::cerr << "Unable to construct FFTW plan" << std::endl; exit(1); } static void planThreads(unsigned int threads) { #ifndef FFTWPP_SINGLE_THREAD omp_set_num_threads(threads); fftw_plan_with_nthreads(threads); #endif } threaddata time(fftw_plan plan1, fftw_plan planT, Complex *in, Complex *out, unsigned int Threads) { utils::statistics S,ST; double stop=utils::totalseconds()+testseconds; threads=1; plan=plan1; fft(in,out); threads=Threads; plan=planT; fft(in,out); unsigned int N=1; for(;;) { double t0=utils::totalseconds(); threads=1; plan=plan1; for(unsigned int i=0; i < N; ++i) fft(in,out); double t1=utils::totalseconds(); threads=Threads; plan=planT; for(unsigned int i=0; i < N; ++i) fft(in,out); double t=utils::totalseconds(); S.add(t1-t0); ST.add(t-t1); if(S.mean() < 100.0/CLOCKS_PER_SEC) N *= 2; if(S.count() >= 10) { double error=S.stdev(); double diff=ST.mean()-S.mean(); if(diff >= 0.0 || t > stop) { threads=1; plan=plan1; fftw_destroy_plan(planT); break; } if(diff < -error) { threads=Threads; fftw_destroy_plan(plan1); break; } } } return threaddata(threads,S.mean(),S.stdev()); } virtual threaddata lookup(bool inplace, unsigned int threads) { return threaddata(); } virtual void store(bool inplace, const threaddata& data) {} inline Complex *CheckAlign(Complex *in, Complex *out, bool constructor=true) { #ifndef NO_CHECK_ALIGN CheckAlign(in,constructor ? "constructor input" : "input"); if(out) CheckAlign(out,constructor ? "constructor output" : "output"); else out=in; #else if(!out) out=in; #endif return out; } threaddata Setup(Complex *in, Complex *out=NULL) { bool alloc=!in; if(alloc) in=utils::ComplexAlign((doubles+1)/2); out=CheckAlign(in,out); inplace=(out==in); threaddata data; unsigned int Threads=threads; if(threads > 1) data=lookup(inplace,threads); threads=data.threads > 0 ? data.threads : 1; planThreads(threads); plan=(*planner)(this,in,out); if(!plan) noplan(); fftw_plan planT; if(Threads > 1) { threads=Threads; planThreads(threads); planT=(*planner)(this,in,out); if(data.threads == 0) { if(planT) data=time(plan,planT,in,out,threads); else noplan(); store(inplace,threaddata(threads,data.mean,data.stdev)); } } if(alloc) Array::deleteAlign(in,(doubles+1)/2); return data; } threaddata Setup(Complex *in, double *out) { return Setup(in,(Complex *) out); } threaddata Setup(double *in, Complex *out=NULL) { return Setup((Complex *) in,out); } virtual void Execute(Complex *in, Complex *out, bool=false) { fftw_execute_dft(plan,(fftw_complex *) in,(fftw_complex *) out); } Complex *Setout(Complex *in, Complex *out) { out=CheckAlign(in,out,false); if(inplace ^ (out == in)) { std::cerr << "ERROR: fft " << inout << std::endl; exit(1); } return out; } void fft(Complex *in, Complex *out=NULL) { out=Setout(in,out); Execute(in,out); } void fft(double *in, Complex *out=NULL) { fft((Complex *) in,out); } void fft(Complex *in, double *out) { fft(in,(Complex *) out); } void fft0(Complex *in, Complex *out=NULL) { out=Setout(in,out); Execute(in,out,true); } void fft0(double *in, Complex *out=NULL) { fft0((Complex *) in,out); } void fft0(Complex *in, double *out) { fft0(in,(Complex *) out); } void Normalize(Complex *out) { unsigned int stop=doubles/2; #ifndef FFTWPP_SINGLE_THREAD #pragma omp parallel for num_threads(threads) #endif for(unsigned int i=0; i < stop; i++) out[i] *= norm; } void Normalize(double *out) { #ifndef FFTWPP_SINGLE_THREAD #pragma omp parallel for num_threads(threads) #endif for(unsigned int i=0; i < doubles; i++) out[i] *= norm; } virtual void fftNormalized(Complex *in, Complex *out=NULL, bool shift=false) { out=Setout(in,out); Execute(in,out,shift); Normalize(out); } void fftNormalized(Complex *in, double *out, bool shift=false) { out=(double *) Setout(in,(Complex *) out); Execute(in,(Complex *) out,shift); Normalize(out); } void fftNormalized(double *in, Complex *out, bool shift=false) { fftNormalized((Complex *) in,out,shift); } template void fft0Normalized(I in, O out) { fftNormalized(in,out,true); } template void fftNormalized(unsigned int nx, unsigned int M, size_t ostride, size_t odist, I *in, O *out=NULL, bool shift=false) { out=(O *) Setout((Complex *) in,(Complex *) out); Execute((Complex *) in,(Complex *) out,shift); unsigned int stop=nx*ostride; O *outMdist=out+M*odist; #ifndef FFTWPP_SINGLE_THREAD #pragma omp parallel for num_threads(threads) #endif for(unsigned int i=0; i < stop; i += ostride) { O *pstop=outMdist+i; for(O *p=out+i; p < pstop; p += odist) { *p *= norm; } } } }; // class fftw class Transpose { fftw_plan plan; fftw_plan plan2; unsigned int a,b; unsigned int nlength,mlength; unsigned int ilast,jlast; unsigned int rows,cols; unsigned int threads; bool inplace; unsigned int size; public: template Transpose(unsigned int rows, unsigned int cols, unsigned int length, T *in, T *out=NULL, unsigned int threads=fftw::maxthreads) : rows(rows), cols(cols), threads(threads) { size=sizeof(T); if(size % sizeof(double) != 0) { std::cerr << "ERROR: Transpose is not implemented for type of size " << size; exit(1); } if(rows == 0 || cols == 0) return; size /= sizeof(double); length *= size; if(!out) out=in; inplace=(out==in); if(inplace) threads=1; // TODO: Generalize to inplace fftw_iodim dims[3]; a=std::min(rows,threads); b=std::min(cols,threads/a); unsigned int n=utils::ceilquotient(rows,a); unsigned int m=utils::ceilquotient(cols,b); // If rows <= threads then a=rows and n=1. // If rows >= threads then b=1 and m=cols. nlength=n*length; mlength=m*length; dims[0].n=n; dims[0].is=cols*length; dims[0].os=length; dims[1].n=m; dims[1].is=length; dims[1].os=rows*length; dims[2].n=length; dims[2].is=1; dims[2].os=1; fftw::planThreads(1); // A plan with rank=0 is a transpose. plan=fftw_plan_guru_r2r(0,NULL,3,dims,(double *) in,(double *) out, NULL,fftw::effort); plan2=NULL; ilast=a; jlast=b; if(n*a > rows) { // Only happens when rows > threads. a=utils::ceilquotient(rows,n); ilast=a-1; dims[0].n=rows-n*ilast; plan2=fftw_plan_guru_r2r(0,NULL,3,dims,(double *) in,(double *) out, NULL,fftw::effort); } else { // Only happens when rows < threads. if(m*b > cols) { b=utils::ceilquotient(cols,m); jlast=b-1; dims[1].n=cols-m*jlast; plan2=fftw_plan_guru_r2r(0,NULL,3,dims,(double *) in,(double *) out, NULL,fftw::effort); } } } ~Transpose() { if(plan) fftw_destroy_plan(plan); if(plan2) fftw_destroy_plan(plan2); } template void transpose(T *in, T *out=NULL) { if(!out) out=in; if(inplace ^ (out == in)) { std::cerr << "ERROR: Transpose " << inout << std::endl; exit(1); } #ifndef FFTWPP_SINGLE_THREAD if(a > 1) { if(b > 1) { int A=a, B=b; #pragma omp parallel for num_threads(A) for(unsigned int i=0; i < a; ++i) { unsigned int I=i*nlength; #pragma omp parallel for num_threads(B) for(unsigned int j=0; j < b; ++j) { unsigned int J=j*mlength; fftw_execute_r2r((i < ilast && j < jlast) ? plan : plan2, (double *) in+cols*I+J, (double *) out+rows*J+I); } } } else { int A=a; #pragma omp parallel for num_threads(A) for(unsigned int i=0; i < a; ++i) { unsigned int I=i*nlength; fftw_execute_r2r(i < ilast ? plan : plan2, (double *) in+cols*I,(double *) out+I); } } } else if(b > 1) { int B=b; #pragma omp parallel for num_threads(B) for(unsigned int j=0; j < b; ++j) { unsigned int J=j*mlength; fftw_execute_r2r(j < jlast ? plan : plan2, (double *) in+J,(double *) out+rows*J); } } else #endif fftw_execute_r2r(plan,(double *) in,(double*) out); } }; template class Threadtable { public: typedef std::map Table; threaddata Lookup(Table& table, T key) { typename Table::iterator p=table.find(key); return p == table.end() ? threaddata() : p->second; } void Store(Table& threadtable, T key, const threaddata& data) { threadtable[key]=data; } }; struct keytype1 { unsigned int nx; unsigned int threads; bool inplace; keytype1(unsigned int nx, unsigned int threads, bool inplace) : nx(nx), threads(threads), inplace(inplace) {} }; struct keyless1 { bool operator()(const keytype1& a, const keytype1& b) const { return a.nx < b.nx || (a.nx == b.nx && (a.threads < b.threads || (a.threads == b.threads && a.inplace < b.inplace))); } }; struct keytype2 { unsigned int nx; unsigned int ny; unsigned int threads; bool inplace; keytype2(unsigned int nx, unsigned int ny, unsigned int threads, bool inplace) : nx(nx), ny(ny), threads(threads), inplace(inplace) {} }; struct keyless2 { bool operator()(const keytype2& a, const keytype2& b) const { return a.nx < b.nx || (a.nx == b.nx && (a.ny < b.ny || (a.ny == b.ny && (a.threads < b.threads || (a.threads == b.threads && a.inplace < b.inplace))))); } }; struct keytype3 { unsigned int nx; unsigned int ny; unsigned int nz; unsigned int threads; bool inplace; keytype3(unsigned int nx, unsigned int ny, unsigned int nz, unsigned int threads, bool inplace) : nx(nx), ny(ny), nz(nz), threads(threads), inplace(inplace) {} }; struct keyless3 { bool operator()(const keytype3& a, const keytype3& b) const { return a.nx < b.nx || (a.nx == b.nx && (a.ny < b.ny || (a.ny == b.ny && (a.nz < b.nz || (a.nz == b.nz && (a.threads < b.threads || (a.threads == b.threads && a.inplace < b.inplace))))))); } }; // Compute the complex Fourier transform of n complex values. // Before calling fft(), the arrays in and out (which may coincide) must be // allocated as Complex[n]. // // Out-of-place usage: // // fft1d Forward(n,-1,in,out); // Forward.fft(in,out); // // fft1d Backward(n,1,in,out); // Backward.fft(in,out); // // fft1d Backward(n,1,in,out); // Backward.fftNormalized(in,out); // True inverse of Forward.fft(out,in); // // In-place usage: // // fft1d Forward(n,-1); // Forward.fft(in); // // fft1d Backward(n,1); // Backward.fft(in); // class fft1d : public fftw, public Threadtable { unsigned int nx; static Table threadtable; public: fft1d(unsigned int nx, int sign, Complex *in=NULL, Complex *out=NULL, unsigned int threads=maxthreads) : fftw(2*nx,sign,threads), nx(nx) {Setup(in,out);} #ifdef __Array_h__ fft1d(int sign, const Array::array1& in, const Array::array1& out=Array::NULL1, unsigned int threads=maxthreads) : fftw(2*in.Nx(),sign,threads), nx(in.Nx()) {Setup(in,out);} #endif threaddata lookup(bool inplace, unsigned int threads) { return this->Lookup(threadtable,keytype1(nx,threads,inplace)); } void store(bool inplace, const threaddata& data) { this->Store(threadtable,keytype1(nx,data.threads,inplace),data); } fftw_plan Plan(Complex *in, Complex *out) { return fftw_plan_dft_1d(nx,(fftw_complex *) in,(fftw_complex *) out, sign,effort); } }; template class fftwblock : public virtual fftw { public: int nx; unsigned int M; size_t istride,ostride; size_t idist,odist; fftw_plan plan1,plan2; unsigned int T,Q,R; fftwblock(unsigned int nx, unsigned int M, size_t istride, size_t ostride, size_t idist, size_t odist, Complex *in, Complex *out, unsigned int Threads) : fftw(), nx(nx), M(M), istride(istride), ostride(ostride), idist(Dist(nx,istride,idist)), odist(Dist(nx,ostride,odist)), plan1(NULL), plan2(NULL) { T=1; Q=M; R=0; threaddata S1=Setup(in,out); fftw_plan planT1=plan; if(Threads > 1) { T=std::min(M,Threads); Q=T > 0 ? M/T : 0; R=M-Q*T; threads=Threads; threaddata ST=Setup(in,out); if(R > 0 && threads == 1 && plan1 != plan2) { fftw_destroy_plan(plan2); plan2=plan1; } if(ST.mean > S1.mean-S1.stdev) { // Use FFTW's multi-threading fftw_destroy_plan(plan); if(R > 0) { fftw_destroy_plan(plan2); plan2=NULL; } T=1; Q=M; R=0; plan=planT1; threads=S1.threads; } else { // Do the multi-threading ourselves fftw_destroy_plan(planT1); threads=ST.threads; } } } fftw_plan Plan(int Q, fftw_complex *in, fftw_complex *out) { return fftw_plan_many_dft(1,&nx,Q,in,NULL,istride,idist, out,NULL,ostride,odist,sign,effort); } fftw_plan Plan(int Q, double *in, fftw_complex *out) { return fftw_plan_many_dft_r2c(1,&nx,Q,in,NULL,istride,idist, out,NULL,ostride,odist,effort); } fftw_plan Plan(int Q, fftw_complex *in, double *out) { return fftw_plan_many_dft_c2r(1,&nx,Q,in,NULL,istride,idist, out,NULL,ostride,odist,effort); } fftw_plan Plan(Complex *in, Complex *out) { if(R > 0) { plan2=Plan(Q+1,(I *) in,(O *) out); if(!plan2) return NULL; if(threads == 1) plan1=plan2; } return Plan(Q,(I *) in,(O *) out); } void Execute(fftw_plan plan, fftw_complex *in, fftw_complex *out) { fftw_execute_dft(plan,in,out); } void Execute(fftw_plan plan, double *in, fftw_complex *out) { fftw_execute_dft_r2c(plan,in,out); } void Execute(fftw_plan plan, fftw_complex *in, double *out) { fftw_execute_dft_c2r(plan,in,out); } void Execute(Complex *in, Complex *out, bool=false) { if(T == 1) Execute(plan,(I *) in,(O *) out); else { unsigned int extra=T-R; #ifndef FFTWPP_SINGLE_THREAD #pragma omp parallel for num_threads(T) #endif for(unsigned int i=0; i < T; ++i) { unsigned int iQ=i*Q; if(i < extra) Execute(plan,(I *) in+iQ*idist,(O *) out+iQ*odist); else { unsigned int offset=iQ+i-extra; Execute(plan2,(I *) in+offset*idist,(O *) out+offset*odist); } } } } unsigned int Threads() {return std::max(T,threads);} ~fftwblock() { if(plan2) fftw_destroy_plan(plan2); } }; // Compute the complex Fourier transform of M complex vectors, each of // length n. // Before calling fft(), the arrays in and out (which may coincide) must be // allocated as Complex[M*n]. // // Out-of-place usage: // // mfft1d Forward(n,-1,M,stride,dist,in,out); // Forward.fft(in,out); // // In-place usage: // // mfft1d Forward(n,-1,M,stride,dist); // Forward.fft(in); // // Notes: // stride is the spacing between the elements of each Complex vector; // dist is the spacing between the first elements of the vectors. // // class mfft1d : public fftwblock, public Threadtable { static Table threadtable; public: mfft1d(unsigned int nx, int sign, unsigned int M=1, size_t stride=1, size_t dist=0, Complex *in=NULL, Complex *out=NULL, unsigned int threads=maxthreads) : fftw(2*((nx-1)*stride+(M-1)*Dist(nx,stride,dist)+1),sign,threads,nx), fftwblock (nx,M,stride,stride,dist,dist,in,out,threads) {} mfft1d(unsigned int nx, int sign, unsigned int M, size_t istride, size_t ostride, size_t idist, size_t odist, Complex *in=NULL, Complex *out=NULL, unsigned int threads=maxthreads): fftw(std::max(2*((nx-1)*istride+(M-1)*Dist(nx,istride,idist)+1), 2*((nx-1)*ostride+(M-1)*Dist(nx,ostride,odist)+1)),sign, threads, nx), fftwblock(nx,M,istride,ostride,idist,odist,in, out,threads) {} threaddata lookup(bool inplace, unsigned int threads) { return Lookup(threadtable,keytype3(nx,Q,R,threads,inplace)); } void store(bool inplace, const threaddata& data) { Store(threadtable,keytype3(nx,Q,R,data.threads,inplace),data); } }; // Compute the complex Fourier transform of n real values, using phase sign -1. // Before calling fft(), the array in must be allocated as double[n] and // the array out must be allocated as Complex[n/2+1]. The arrays in and out // may coincide, allocated as Complex[n/2+1]. // // Out-of-place usage: // // rcfft1d Forward(n,in,out); // Forward.fft(in,out); // // In-place usage: // // rcfft1d Forward(n); // Forward.fft(out); // // Notes: // in contains the n real values stored as a Complex array; // out contains the first n/2+1 Complex Fourier values. // class rcfft1d : public fftw, public Threadtable { unsigned int nx; static Table threadtable; public: rcfft1d(unsigned int nx, Complex *out=NULL, unsigned int threads=maxthreads) : fftw(2*(nx/2+1),-1,threads,nx), nx(nx) {Setup(out,(double*) NULL);} rcfft1d(unsigned int nx, double *in, Complex *out=NULL, unsigned int threads=maxthreads) : fftw(2*(nx/2+1),-1,threads,nx), nx(nx) {Setup(in,out);} threaddata lookup(bool inplace, unsigned int threads) { return Lookup(threadtable,keytype1(nx,threads,inplace)); } void store(bool inplace, const threaddata& data) { Store(threadtable,keytype1(nx,data.threads,inplace),data); } fftw_plan Plan(Complex *in, Complex *out) { return fftw_plan_dft_r2c_1d(nx,(double *) in,(fftw_complex *) out, effort); } void Execute(Complex *in, Complex *out, bool=false) { fftw_execute_dft_r2c(plan,(double *) in,(fftw_complex *) out); } }; // Compute the real inverse Fourier transform of the n/2+1 Complex values // corresponding to the non-negative part of the frequency spectrum, using // phase sign +1. // Before calling fft(), the array in must be allocated as Complex[n/2+1] // and the array out must be allocated as double[n]. The arrays in and out // may coincide, allocated as Complex[n/2+1]. // // Out-of-place usage (input destroyed): // // crfft1d Backward(n,in,out); // Backward.fft(in,out); // // In-place usage: // // crfft1d Backward(n); // Backward.fft(in); // // Notes: // in contains the first n/2+1 Complex Fourier values. // out contains the n real values stored as a Complex array; // class crfft1d : public fftw, public Threadtable { unsigned int nx; static Table threadtable; public: crfft1d(unsigned int nx, double *out=NULL, unsigned int threads=maxthreads) : fftw(2*(nx/2+1),1,threads,nx), nx(nx) {Setup(out);} crfft1d(unsigned int nx, Complex *in, double *out=NULL, unsigned int threads=maxthreads) : fftw(realsize(nx,in,out),1,threads,nx), nx(nx) {Setup(in,out);} threaddata lookup(bool inplace, unsigned int threads) { return Lookup(threadtable,keytype1(nx,threads,inplace)); } void store(bool inplace, const threaddata& data) { Store(threadtable,keytype1(nx,data.threads,inplace),data); } fftw_plan Plan(Complex *in, Complex *out) { return fftw_plan_dft_c2r_1d(nx,(fftw_complex *) in,(double *) out,effort); } void Execute(Complex *in, Complex *out, bool=false) { fftw_execute_dft_c2r(plan,(fftw_complex *) in,(double *) out); } }; // Compute the real Fourier transform of M real vectors, each of length n, // using phase sign -1. Before calling fft(), the array in must be // allocated as double[M*n] and the array out must be allocated as // Complex[M*(n/2+1)]. The arrays in and out may coincide, // allocated as Complex[M*(n/2+1)]. // // Out-of-place usage: // // mrcfft1d Forward(n,M,istride,ostride,idist,odist,in,out); // Forward.fft(in,out); // // In-place usage: // // mrcfft1d Forward(n,M,istride,ostride,idist,odist); // Forward.fft(out); // // Notes: // istride is the spacing between the elements of each real vector; // ostride is the spacing between the elements of each Complex vector; // idist is the spacing between the first elements of the real vectors; // odist is the spacing between the first elements of the Complex vectors; // in contains the n real values stored as a Complex array; // out contains the first n/2+1 Complex Fourier values. // class mrcfft1d : public fftwblock, public Threadtable { static Table threadtable; public: mrcfft1d(unsigned int nx, unsigned int M, size_t istride, size_t ostride, size_t idist, size_t odist, double *in=NULL, Complex *out=NULL, unsigned int threads=maxthreads) : fftw(std::max((realsize(nx,in,out)-2)*istride+(M-1)*idist+2, 2*(nx/2*ostride+(M-1)*odist+1)),-1,threads,nx), fftwblock (nx,M,istride,ostride,idist,odist,(Complex *) in,out,threads) {} threaddata lookup(bool inplace, unsigned int threads) { return Lookup(threadtable,keytype3(nx,Q,R,threads,inplace)); } void store(bool inplace, const threaddata& data) { Store(threadtable,keytype3(nx,Q,R,data.threads,inplace),data); } void fftNormalized(double *in, Complex *out=NULL) { fftw::fftNormalized(nx/2+1,M,ostride,odist,in,out,false); } void fft0Normalized(double *in, Complex *out=NULL) { fftw::fftNormalized(nx/2+1,M,ostride,odist,in,out,true); } }; // Compute the real inverse Fourier transform of M complex vectors, each of // length n/2+1, corresponding to the non-negative parts of the frequency // spectra, using phase sign +1. Before calling fft(), the array in must be // allocated as Complex[M*(n/2+1)] and the array out must be allocated as // double[M*n]. The arrays in and out may coincide, // allocated as Complex[M*(n/2+1)]. // // Out-of-place usage (input destroyed): // // mcrfft1d Backward(n,M,istride,ostride,idist,odist,in,out); // Backward.fft(in,out); // // In-place usage: // // mcrfft1d Backward(n,M,istride,ostride,idist,odist); // Backward.fft(out); // // Notes: // stride is the spacing between the elements of each Complex vector; // dist is the spacing between the first elements of the vectors; // in contains the first n/2+1 Complex Fourier values; // out contains the n real values stored as a Complex array. // class mcrfft1d : public fftwblock, public Threadtable { static Table threadtable; public: mcrfft1d(unsigned int nx, unsigned int M, size_t istride, size_t ostride, size_t idist, size_t odist, Complex *in=NULL, double *out=NULL, unsigned int threads=maxthreads) : fftw(std::max(2*(nx/2*istride+(M-1)*idist+1), (realsize(nx,in,out)-2)*ostride+(M-1)*odist+2),1,threads,nx), fftwblock (nx,M,istride,ostride,idist,odist,in,(Complex *) out,threads) {} threaddata lookup(bool inplace, unsigned int threads) { return Lookup(threadtable,keytype3(nx,Q,R,threads,inplace)); } void store(bool inplace, const threaddata& data) { Store(threadtable,keytype3(nx,Q,R,data.threads,inplace),data); } void fftNormalized(Complex *in, double *out=NULL) { fftw::fftNormalized(nx,M,ostride,odist,in,out,false); } void fft0Normalized(Complex *in, double *out=NULL) { fftw::fftNormalized(nx,M,ostride,odist,in,out,true); } }; // Compute the complex two-dimensional Fourier transform of nx times ny // complex values. Before calling fft(), the arrays in and out (which may // coincide) must be allocated as Complex[nx*ny]. // // Out-of-place usage: // // fft2d Forward(nx,ny,-1,in,out); // Forward.fft(in,out); // // fft2d Backward(nx,ny,1,in,out); // Backward.fft(in,out); // // fft2d Backward(nx,ny,1,in,out); // Backward.fftNormalized(in,out); // True inverse of Forward.fft(out,in); // // In-place usage: // // fft2d Forward(nx,ny,-1); // Forward.fft(in); // // fft2d Backward(nx,ny,1); // Backward.fft(in); // // Note: // in[ny*i+j] contains the ny Complex values for each i=0,...,nx-1. // class fft2d : public fftw, public Threadtable { unsigned int nx; unsigned int ny; static Table threadtable; public: fft2d(unsigned int nx, unsigned int ny, int sign, Complex *in=NULL, Complex *out=NULL, unsigned int threads=maxthreads) : fftw(2*nx*ny,sign,threads), nx(nx), ny(ny) {Setup(in,out);} #ifdef __Array_h__ fft2d(int sign, const Array::array2& in, const Array::array2& out=Array::NULL2, unsigned int threads=maxthreads) : fftw(2*in.Size(),sign,threads), nx(in.Nx()), ny(in.Ny()) { Setup(in,out); } #endif threaddata lookup(bool inplace, unsigned int threads) { return this->Lookup(threadtable,keytype2(nx,ny,threads,inplace)); } void store(bool inplace, const threaddata& data) { this->Store(threadtable,keytype2(nx,ny,data.threads,inplace),data); } fftw_plan Plan(Complex *in, Complex *out) { return fftw_plan_dft_2d(nx,ny,(fftw_complex *) in,(fftw_complex *) out, sign,effort); } void Execute(Complex *in, Complex *out, bool=false) { fftw_execute_dft(plan,(fftw_complex *) in,(fftw_complex *) out); } }; // Compute the complex two-dimensional Fourier transform of nx times ny real // values, using phase sign -1. // Before calling fft(), the array in must be allocated as double[nx*ny] and // the array out must be allocated as Complex[nx*(ny/2+1)]. The arrays in // and out may coincide, allocated as Complex[nx*(ny/2+1)]. // // Out-of-place usage: // // rcfft2d Forward(nx,ny,in,out); // Forward.fft(in,out); // Origin of Fourier domain at (0,0) // Forward.fft0(in,out); // Origin of Fourier domain at (nx/2,0); // input destroyed. // // In-place usage: // // rcfft2d Forward(nx,ny); // Forward.fft(in); // Origin of Fourier domain at (0,0) // Forward.fft0(in); // Origin of Fourier domain at (nx/2,0) // // Notes: // in contains the nx*ny real values stored as a Complex array; // out contains the upper-half portion (ky >= 0) of the Complex transform. // class rcfft2d : public fftw { unsigned int nx; unsigned int ny; public: rcfft2d(unsigned int nx, unsigned int ny, Complex *out=NULL, unsigned int threads=maxthreads) : fftw(2*nx*(ny/2+1),-1,threads,nx*ny), nx(nx), ny(ny) {Setup(out);} rcfft2d(unsigned int nx, unsigned int ny, double *in, Complex *out=NULL, unsigned int threads=maxthreads) : fftw(2*nx*(ny/2+1),-1,threads,nx*ny), nx(nx), ny(ny) { Setup(in,out); } fftw_plan Plan(Complex *in, Complex *out) { return fftw_plan_dft_r2c_2d(nx,ny,(double *) in,(fftw_complex *) out, effort); } void Execute(Complex *in, Complex *out, bool shift=false) { if(shift) { if(inplace) Shift(in,nx,ny,threads); else Shift((double *) in,nx,ny,threads); } fftw_execute_dft_r2c(plan,(double *) in,(fftw_complex *) out); } // Set Nyquist modes of even shifted transforms to zero. void deNyquist(Complex *f) { unsigned int nyp=ny/2+1; if(nx % 2 == 0) #ifndef FFTWPP_SINGLE_THREAD #pragma omp parallel for num_threads(threads) #endif for(unsigned int j=0; j < nyp; ++j) f[j]=0.0; if(ny % 2 == 0) #ifndef FFTWPP_SINGLE_THREAD #pragma omp parallel for num_threads(threads) #endif for(unsigned int i=0; i < nx; ++i) f[(i+1)*nyp-1]=0.0; } }; // Compute the real two-dimensional inverse Fourier transform of the // nx*(ny/2+1) Complex values corresponding to the spectral values in the // half-plane ky >= 0, using phase sign +1. // Before calling fft(), the array in must be allocated as // Complex[nx*(ny/2+1)] and the array out must be allocated as // double[nx*ny]. The arrays in and out may coincide, // allocated as Complex[nx*(ny/2+1)]. // // Out-of-place usage (input destroyed): // // crfft2d Backward(nx,ny,in,out); // Backward.fft(in,out); // Origin of Fourier domain at (0,0) // Backward.fft0(in,out); // Origin of Fourier domain at (nx/2,0) // // In-place usage: // // crfft2d Backward(nx,ny); // Backward.fft(in); // Origin of Fourier domain at (0,0) // Backward.fft0(in); // Origin of Fourier domain at (nx/2,0) // // Notes: // in contains the upper-half portion (ky >= 0) of the Complex transform; // out contains the nx*ny real values stored as a Complex array. // class crfft2d : public fftw { unsigned int nx; unsigned int ny; public: crfft2d(unsigned int nx, unsigned int ny, double *out=NULL, unsigned int threads=maxthreads) : fftw(2*nx*(ny/2+1),1,threads,nx*ny), nx(nx), ny(ny) {Setup(out);} crfft2d(unsigned int nx, unsigned int ny, Complex *in, double *out=NULL, unsigned int threads=maxthreads) : fftw(nx*realsize(ny,in,out),1,threads,nx*ny), nx(nx), ny(ny) { Setup(in,out); } fftw_plan Plan(Complex *in, Complex *out) { return fftw_plan_dft_c2r_2d(nx,ny,(fftw_complex *) in,(double *) out, effort); } void Execute(Complex *in, Complex *out, bool shift=false) { fftw_execute_dft_c2r(plan,(fftw_complex *) in,(double *) out); if(shift) { if(inplace) Shift(out,nx,ny,threads); else Shift((double *) out,nx,ny,threads); } } // Set Nyquist modes of even shifted transforms to zero. void deNyquist(Complex *f) { unsigned int nyp=ny/2+1; if(nx % 2 == 0) #ifndef FFTWPP_SINGLE_THREAD #pragma omp parallel for num_threads(threads) #endif for(unsigned int j=0; j < nyp; ++j) f[j]=0.0; if(ny % 2 == 0) #ifndef FFTWPP_SINGLE_THREAD #pragma omp parallel for num_threads(threads) #endif for(unsigned int i=0; i < nx; ++i) f[(i+1)*nyp-1]=0.0; } }; // Compute the complex three-dimensional Fourier transform of // nx times ny times nz complex values. Before calling fft(), the arrays in // and out (which may coincide) must be allocated as Complex[nx*ny*nz]. // // Out-of-place usage: // // fft3d Forward(nx,ny,nz,-1,in,out); // Forward.fft(in,out); // // fft3d Backward(nx,ny,nz,1,in,out); // Backward.fft(in,out); // // fft3d Backward(nx,ny,nz,1,in,out); // Backward.fftNormalized(in,out); // True inverse of Forward.fft(out,in); // // In-place usage: // // fft3d Forward(nx,ny,nz,-1); // Forward.fft(in); // // fft3d Backward(nx,ny,nz,1); // Backward.fft(in); // // Note: // in[nz*(ny*i+j)+k] contains the (i,j,k)th Complex value, // indexed by i=0,...,nx-1, j=0,...,ny-1, and k=0,...,nz-1. // class fft3d : public fftw { unsigned int nx; unsigned int ny; unsigned int nz; public: fft3d(unsigned int nx, unsigned int ny, unsigned int nz, int sign, Complex *in=NULL, Complex *out=NULL, unsigned int threads=maxthreads) : fftw(2*nx*ny*nz,sign,threads), nx(nx), ny(ny), nz(nz) {Setup(in,out);} #ifdef __Array_h__ fft3d(int sign, const Array::array3& in, const Array::array3& out=Array::NULL3, unsigned int threads=maxthreads) : fftw(2*in.Size(),sign,threads), nx(in.Nx()), ny(in.Ny()), nz(in.Nz()) {Setup(in,out);} #endif fftw_plan Plan(Complex *in, Complex *out) { return fftw_plan_dft_3d(nx,ny,nz,(fftw_complex *) in, (fftw_complex *) out, sign, effort); } }; // Compute the complex two-dimensional Fourier transform of // nx times ny times nz real values, using phase sign -1. // Before calling fft(), the array in must be allocated as double[nx*ny*nz] // and the array out must be allocated as Complex[nx*ny*(nz/2+1)]. The // arrays in and out may coincide, allocated as Complex[nx*ny*(nz/2+1)]. // // Out-of-place usage: // // rcfft3d Forward(nx,ny,nz,in,out); // Forward.fft(in,out); // Origin of Fourier domain at (0,0) // Forward.fft0(in,out); // Origin of Fourier domain at (nx/2,ny/2,0); // input destroyed // In-place usage: // // rcfft3d Forward(nx,ny,nz); // Forward.fft(in); // Origin of Fourier domain at (0,0) // Forward.fft0(in); // Origin of Fourier domain at (nx/2,ny/2,0) // // Notes: // in contains the nx*ny*nz real values stored as a Complex array; // out contains the upper-half portion (kz >= 0) of the Complex transform. // class rcfft3d : public fftw { unsigned int nx; unsigned int ny; unsigned int nz; public: rcfft3d(unsigned int nx, unsigned int ny, unsigned int nz, Complex *out=NULL, unsigned int threads=maxthreads) : fftw(2*nx*ny*(nz/2+1),-1,threads,nx*ny*nz), nx(nx), ny(ny), nz(nz) { Setup(out); } rcfft3d(unsigned int nx, unsigned int ny, unsigned int nz, double *in, Complex *out=NULL, unsigned int threads=maxthreads) : fftw(2*nx*ny*(nz/2+1),-1,threads,nx*ny*nz), nx(nx), ny(ny), nz(nz) {Setup(in,out);} fftw_plan Plan(Complex *in, Complex *out) { return fftw_plan_dft_r2c_3d(nx,ny,nz,(double *) in,(fftw_complex *) out, effort); } void Execute(Complex *in, Complex *out, bool shift=false) { if(shift) { if(inplace) Shift(in,nx,ny,nz,threads); else Shift((double *) in,nx,ny,nz,threads); } fftw_execute_dft_r2c(plan,(double *) in,(fftw_complex *) out); } // Set Nyquist modes of even shifted transforms to zero. void deNyquist(Complex *f) { unsigned int nzp=nz/2+1; unsigned int yz=ny*nzp; if(nx % 2 == 0) { #ifndef FFTWPP_SINGLE_THREAD #pragma omp parallel for num_threads(threads) #endif for(unsigned int k=0; k < yz; ++k) f[k]=0.0; } if(ny % 2 == 0) { #ifndef FFTWPP_SINGLE_THREAD #pragma omp parallel for num_threads(threads) #endif for(unsigned int i=0; i < nx; ++i) { unsigned int iyz=i*yz; for(unsigned int k=0; k < nzp; ++k) f[iyz+k]=0.0; } } if(nz % 2 == 0) #ifndef FFTWPP_SINGLE_THREAD #pragma omp parallel for num_threads(threads) #endif for(unsigned int i=0; i < nx; ++i) for(unsigned int j=0; j < ny; ++j) f[i*yz+(j+1)*nzp-1]=0.0; } }; // Compute the real two-dimensional inverse Fourier transform of the // nx*ny*(nz/2+1) Complex values corresponding to the spectral values in the // half-plane kz >= 0, using phase sign +1. // Before calling fft(), the array in must be allocated as // Complex[nx*ny*(nz+1)/2] and the array out must be allocated as // double[nx*ny*nz]. The arrays in and out may coincide, // allocated as Complex[nx*ny*(nz/2+1)]. // // Out-of-place usage (input destroyed): // // crfft3d Backward(nx,ny,nz,in,out); // Backward.fft(in,out); // Origin of Fourier domain at (0,0) // Backward.fft0(in,out); // Origin of Fourier domain at (nx/2,ny/2,0) // // In-place usage: // // crfft3d Backward(nx,ny,nz); // Backward.fft(in); // Origin of Fourier domain at (0,0) // Backward.fft0(in); // Origin of Fourier domain at (nx/2,ny/2,0) // // Notes: // in contains the upper-half portion (kz >= 0) of the Complex transform; // out contains the nx*ny*nz real values stored as a Complex array. // class crfft3d : public fftw { unsigned int nx; unsigned int ny; unsigned int nz; public: crfft3d(unsigned int nx, unsigned int ny, unsigned int nz, double *out=NULL, unsigned int threads=maxthreads) : fftw(2*nx*ny*(nz/2+1),1,threads,nx*ny*nz), nx(nx), ny(ny), nz(nz) {Setup(out);} crfft3d(unsigned int nx, unsigned int ny, unsigned int nz, Complex *in, double *out=NULL, unsigned int threads=maxthreads) : fftw(nx*ny*(realsize(nz,in,out)),1,threads,nx*ny*nz), nx(nx), ny(ny), nz(nz) {Setup(in,out);} fftw_plan Plan(Complex *in, Complex *out) { return fftw_plan_dft_c2r_3d(nx,ny,nz,(fftw_complex *) in,(double *) out, effort); } void Execute(Complex *in, Complex *out, bool shift=false) { fftw_execute_dft_c2r(plan,(fftw_complex *) in,(double *) out); if(shift) { if(inplace) Shift(out,nx,ny,nz,threads); else Shift((double *) out,nx,ny,nz,threads); } } // Set Nyquist modes of even shifted transforms to zero. void deNyquist(Complex *f) { unsigned int nzp=nz/2+1; unsigned int yz=ny*nzp; if(nx % 2 == 0) { #ifndef FFTWPP_SINGLE_THREAD #pragma omp parallel for num_threads(threads) #endif for(unsigned int k=0; k < yz; ++k) f[k]=0.0; } if(ny % 2 == 0) { #ifndef FFTWPP_SINGLE_THREAD #pragma omp parallel for num_threads(threads) #endif for(unsigned int i=0; i < nx; ++i) { unsigned int iyz=i*yz; for(unsigned int k=0; k < nzp; ++k) f[iyz+k]=0.0; } } if(nz % 2 == 0) #ifndef FFTWPP_SINGLE_THREAD #pragma omp parallel for num_threads(threads) #endif for(unsigned int i=0; i < nx; ++i) for(unsigned int j=0; j < ny; ++j) f[i*yz+(j+1)*nzp-1]=0.0; } }; } #endif asymptote-2.37/fftw++asy.cc000066400000000000000000000001671265434602500156250ustar00rootroot00000000000000#ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_LIBFFTW3 #include "fftw++.h" #include "fftw++.cc" #endif asymptote-2.37/fileio.cc000066400000000000000000000076731265434602500152740ustar00rootroot00000000000000/****** * fileio.cc * Tom Prince and John Bowman 2004/08/10 * * Handle input/output ******/ #include "fileio.h" #include "settings.h" namespace camp { FILE *pipeout=NULL; string tab="\t"; string newline="\n"; ofile Stdout(""); file nullfile("",false,NOMODE,false,true); void ifile::ignoreComment() { if(comment == 0) return; int c; bool eol=(stream->peek() == '\n'); if(eol && csvmode && nullfield) return; for(;;) { while(isspace(c=stream->peek())) { stream->ignore(); whitespace += (char) c; } if(c == comment) { whitespace=""; while((c=stream->peek()) != '\n' && c != EOF) stream->ignore(); if(c == '\n') stream->ignore(); } else {if(c != EOF && eol) stream->unget(); return;} } } bool ifile::eol() { int c; while(isspace(c=stream->peek())) { if(c == '\n') return true; else { stream->ignore(); whitespace += (char) c; } } return false; } bool ifile::nexteol() { int c; if(nullfield) { nullfield=false; return true; } while(isspace(c=stream->peek())) { if(c == '\n' && comma) { nullfield=true; return false; } stream->ignore(); if(c == '\n') { while(isspace(c=stream->peek())) { if(c == '\n') {nullfield=true; return true;} else { stream->ignore(); whitespace += (char) c; } } return true; } else whitespace += (char) c; } return false; } void ifile::csv() { comma=false; nullfield=false; if(!csvmode || stream->eof()) return; std::ios::iostate rdstate=stream->rdstate(); if(stream->fail()) stream->clear(); int c=stream->peek(); if(c == ',') stream->ignore(); else if(c == '\n') { stream->ignore(); if(linemode && stream->peek() != EOF) stream->unget(); } else stream->clear(rdstate); if(c == ',') comma=true; } void ifile::Read(string& val) { string s; if(wordmode) { whitespace=""; while(isspace(stream->peek())) stream->ignore(); } if(csvmode || wordmode) { bool quote=false; while(stream->good()) { int c=stream->peek(); if(c == '"') {quote=!quote; stream->ignore(); continue;} if(!quote) { if(comment && c == comment) { while((c=stream->peek()) != '\n' && c != EOF) stream->ignore(); if(wordmode && !linemode) while(isspace(stream->peek())) stream->ignore(); if(stream->peek() == '"') {quote=!quote; stream->ignore(); continue;} if(s.empty() && c == '\n') { stream->ignore(); continue; } } if(csvmode && (c == ',' || c == '\n')) break; if(wordmode && isspace(c)) { if(!linemode) while(isspace(stream->peek())) stream->ignore(); break; } } s += (char) stream->get(); } } else getline(*stream,s); if(comment) { size_t p=0; while((p=s.find(comment,p)) < string::npos) { if(p+1 < s.length() && s[p+1] == comment) { s.erase(p,1); ++p; } else { s.erase(p); break; } } } size_t pos=s.length()-1; if(s[pos] == '\r') s.erase(pos,1); val=whitespace+s; } void ofile::writeline() { if(standard && interact::query && !vm::indebugger) { Int scroll=settings::getScroll(); if(scroll && interact::lines > 0 && interact::lines % scroll == 0) { for(;;) { if(!cin.good()) { *stream << newline; cin.clear(); break; } int c=cin.get(); if(c == '\n') break; // Discard any additional characters while(cin.good() && cin.get() != '\n'); if(c == 's') {interact::query=false; break;} if(c == 'q') {interact::query=false; interact::lines=0; throw quit();} } } else *stream << newline; ++interact::lines; } else *stream << newline; if(errorstream::interrupt) {interact::lines=0; throw interrupted();} } } // namespace camp asymptote-2.37/fileio.h000066400000000000000000000463421265434602500151320ustar00rootroot00000000000000/****** * fileio.h * Tom Prince and John Bowman 2004/05/10 * * Handle input/output ******/ #ifndef FILEIO_H #define FILEIO_H #include #include #include #include "common.h" #ifdef HAVE_RPC_RPC_H #include "xstream.h" #endif #include "pair.h" #include "triple.h" #include "guide.h" #include "pen.h" #include "camperror.h" #include "interact.h" #include "errormsg.h" #include "util.h" #include "process.h" namespace vm { extern bool indebugger; } namespace camp { extern string tab; extern string newline; enum Mode {NOMODE,INPUT,OUTPUT,UPDATE,BINPUT,BOUTPUT,BUPDATE,XINPUT,XOUTPUT, XUPDATE,OPIPE}; static const string FileModes[]= {"none","input","output","output(update)", "input(binary)","output(binary)","output(binary,update)", "input(xdr)","output(xdr)","output(xdr,update)","output(pipe)"}; extern FILE *pipeout; inline void openpipeout() { int fd=settings::getSetting("outpipe"); if(!pipeout) { if(fd >= 0) pipeout=fdopen(intcast(fd),"w"); } if(!pipeout) { ostringstream buf; buf << "Cannot open outpipe " << fd; reportError(buf); } } class file : public gc { protected: string name; bool check; // Check whether input file exists. Mode type; Int nx,ny,nz; // Array dimensions bool linemode; // Array reads will stop at eol instead of eof. bool csvmode; // Read comma-separated values. bool wordmode; // Delimit strings by white space instead of eol. bool singlereal; // Read/write single-precision XDR/binary reals. bool singleint; // Read/write single-precision XDR/binary ints. bool signedint; // Read/write signed XDR/binary ints. bool closed; // File has been closed. bool standard; // Standard input/output bool binary; // Read in binary mode. bool nullfield; // Used to detect a final null field in csv+line mode. string whitespace; size_t index; // Terminator index. public: bool Standard() {return standard;} void standardEOF() { #if defined(HAVE_LIBREADLINE) && defined(HAVE_LIBCURSES) cout << endl; #endif } template void purgeStandard(T&) { if(standard) { int c; if(cin.eof()) standardEOF(); else { cin.clear(); while((c=cin.peek()) != EOF) { cin.ignore(); if(c == '\n') break; } } } } void purgeStandard(string&) { if(cin.eof()) standardEOF(); } void dimension(Int Nx=-1, Int Ny=-1, Int Nz=-1) {nx=Nx; ny=Ny; nz=Nz;} file(const string& name, bool check=true, Mode type=NOMODE, bool binary=false, bool closed=false) : name(name), check(check), type(type), linemode(false), csvmode(false), singlereal(false), singleint(true), signedint(true), closed(closed), standard(name.empty()), binary(binary), nullfield(false), whitespace("") {dimension();} virtual void open() {} void Check() { if(error()) { ostringstream buf; buf << "Cannot open file \"" << name << "\""; reportError(buf); } } virtual ~file() {} bool isOpen() { if(closed) { ostringstream buf; buf << "I/O operation attempted on "; if(name != "") buf << "closed file \'" << name << "\'"; else buf << "null file"; reportError(buf); } return true; } string filename() {return name;} virtual bool eol() {return false;} virtual bool nexteol() {return false;} virtual bool text() {return false;} virtual bool eof() {return true;} virtual bool error() {return true;} virtual void close() {} virtual void clear() {} virtual Int precision(Int) {return 0;} virtual void flush() {} virtual size_t tell() {return 0;} virtual void seek(Int, bool=true) {} string FileMode() {return FileModes[type];} void unsupported(const char *rw, const char *type) { ostringstream buf; buf << rw << " of type " << type << " not supported in " << FileMode() << " mode"; reportError(buf); } void noread(const char *type) {unsupported("Read",type);} void nowrite(const char *type) {unsupported("Write",type);} virtual void Read(bool&) {noread("bool");} virtual void Read(Int&) {noread("int");} virtual void Read(double&) {noread("real");} virtual void Read(float&) {noread("real");} virtual void Read(pair&) {noread("pair");} virtual void Read(triple&) {noread("triple");} virtual void Read(char&) {noread("char");} virtual void Read(string&) {noread("string");} virtual void readwhite(string&) {noread("string");} virtual void write(bool) {nowrite("bool");} virtual void write(Int) {nowrite("int");} virtual void write(double) {nowrite("real");} virtual void write(const pair&) {nowrite("pair");} virtual void write(const triple&) {nowrite("triple");} virtual void write(const string&) {nowrite("string");} virtual void write(const pen&) {nowrite("pen");} virtual void write(guide *) {nowrite("guide");} virtual void write(const transform&) {nowrite("transform");} virtual void writeline() {nowrite("string");} virtual void ignoreComment() {}; virtual void csv() {}; template void ignoreComment(T&) { ignoreComment(); } void ignoreComment(string&) {} void ignoreComment(char&) {} template void read(T& val) { if(binary) Read(val); else { if(standard) clear(); if(errorstream::interrupt) throw interrupted(); else { ignoreComment(val); val=T(); if(!nullfield) Read(val); csv(); whitespace=""; } } } Int Nx() {return nx;} Int Ny() {return ny;} Int Nz() {return nz;} void Nx(Int n) {nx=n;} void Ny(Int n) {ny=n;} void Nz(Int n) {nz=n;} void LineMode(bool b) {linemode=b;} bool LineMode() {return linemode;} void CSVMode(bool b) {csvmode=b; if(b) wordmode=false;} bool CSVMode() {return csvmode;} void WordMode(bool b) {wordmode=b; if(b) csvmode=false;} bool WordMode() {return wordmode;} void SingleReal(bool b) {singlereal=b;} bool SingleReal() {return singlereal;} void SingleInt(bool b) {singleint=b;} bool SingleInt() {return singleint;} void SignedInt(bool b) {signedint=b;} bool SignedInt() {return signedint;} }; class opipe : public file { public: opipe(const string& name) : file(name,false,OPIPE) {} void open() { openpipeout(); } bool text() {return true;} bool eof() {return pipeout ? feof(pipeout) : true;} bool error() {return pipeout ? ferror(pipeout) : true;} void clear() {if(pipeout) clearerr(pipeout);} void flush() {if(pipeout) fflush(pipeout);} void seek(Int pos, bool begin=true) { if(!standard && pipeout) { clear(); fseek(pipeout,pos,begin ? SEEK_SET : SEEK_END); } } size_t tell() { return pipeout ? ftell(pipeout) : 0; } void write(const string& val) { fprintf(pipeout,"%s",val.c_str()); } void write(bool val) { ostringstream s; s << val; write(s.str()); } void write(Int val) { ostringstream s; s << val; write(s.str()); } void write(double val) { ostringstream s; s << val; write(s.str()); } void write(const pair& val) { ostringstream s; s << val; write(s.str()); } void write(const triple& val) { ostringstream s; s << val; write(s.str()); } void write(const pen &val) { ostringstream s; s << val; write(s.str()); } void write(guide *val) { ostringstream s; s << *val; write(s.str()); } void write(const transform& val) { ostringstream s; s << val; write(s.str()); } void writeline() { fprintf(pipeout,"\n"); if(errorstream::interrupt) throw interrupted(); } }; class ifile : public file { protected: istream *stream; std::fstream *fstream; char comment; std::ios::openmode mode; bool comma; public: ifile(const string& name, char comment, bool check=true, Mode type=INPUT, std::ios::openmode mode=std::ios::in) : file(name,check,type), stream(&cin), fstream(NULL), comment(comment), mode(mode), comma(false) {} // Binary file ifile(const string& name, bool check=true, Mode type=BINPUT, std::ios::openmode mode=std::ios::in) : file(name,check,type,true), mode(mode) {} ~ifile() {close();} void open() { if(standard) { if(mode & std::ios::binary) reportError("Cannot open standard input in binary mode"); stream=&cin; } else { if(mode & std::ios::out) name=outpath(name); stream=fstream=new std::fstream(name.c_str(),mode); if(mode & std::ios::out) { if(error()) { delete fstream; std::ofstream f(name.c_str()); f.close(); stream=fstream=new std::fstream(name.c_str(),mode); } } index=processData().ifile.add(fstream); if(check) Check(); } } bool eol(); bool nexteol(); bool text() {return true;} bool eof() {return stream->eof();} bool error() {return stream->fail();} void close() { if(!standard && fstream) { fstream->close(); closed=true; delete fstream; fstream=NULL; processData().ifile.remove(index); } } void clear() {stream->clear();} void seek(Int pos, bool begin=true) { if(!standard && fstream) { clear(); fstream->seekg(pos,begin ? std::ios::beg : std::ios::end); } } size_t tell() { if(fstream) return fstream->tellg(); else return 0; } void csv(); virtual void ignoreComment(); // Skip over white space void readwhite(string& val) {val=string(); *stream >> val;} void Read(bool &val) {string t; readwhite(t); val=(t == "true");} void Read(Int& val) {*stream >> val;} void Read(double& val) {*stream >> val;} void Read(pair& val) {*stream >> val;} void Read(triple& val) {*stream >> val;} void Read(char& val) {stream->get(val);} void Read(string& val); }; class iofile : public ifile { public: iofile(const string& name, char comment=0) : ifile(name,comment,true,UPDATE,std::ios::in | std::ios::out) {} Int precision(Int p) { return p == 0 ? stream->precision() : stream->precision(p); } void flush() {if(fstream) fstream->flush();} void write(bool val) {*fstream << (val ? "true " : "false ");} void write(Int val) {*fstream << val;} void write(double val) {*fstream << val;} void write(const pair& val) {*fstream << val;} void write(const triple& val) {*fstream << val;} void write(const string& val) {*fstream << val;} void write(const pen& val) {*fstream << val;} void write(guide *val) {*fstream << *val;} void write(const transform& val) {*fstream << val;} void writeline() { *fstream << newline; if(errorstream::interrupt) throw interrupted(); } }; class ofile : public file { protected: ostream *stream; std::ofstream *fstream; std::ios::openmode mode; public: ofile(const string& name, Mode type=OUTPUT, std::ios::openmode mode=std::ios::trunc) : file(name,true,type), stream(&cout), fstream(NULL), mode(mode) {} ~ofile() {close();} void open() { if(standard) { if(mode & std::ios::binary) reportError("Cannot open standard output in binary mode"); stream=&cout; } else { name=outpath(name); stream=fstream=new std::ofstream(name.c_str(),mode | std::ios::trunc); index=processData().ofile.add(fstream); Check(); } } bool text() {return true;} bool eof() {return stream->eof();} bool error() {return stream->fail();} void close() { if(!standard && fstream) { fstream->close(); closed=true; delete fstream; fstream=NULL; processData().ofile.remove(index); } } void clear() {stream->clear();} Int precision(Int p) { return p == 0 ? stream->precision() : stream->precision(p); } void flush() {stream->flush();} void seek(Int pos, bool begin=true) { if(!standard && fstream) { clear(); fstream->seekp(pos,begin ? std::ios::beg : std::ios::end); } } size_t tell() { if(fstream) return fstream->tellp(); else return 0; } void write(bool val) {*stream << (val ? "true " : "false ");} void write(Int val) {*stream << val;} void write(double val) {*stream << val;} void write(const pair& val) {*stream << val;} void write(const triple& val) {*stream << val;} void write(const string& val) {*stream << val;} void write(const pen& val) {*stream << val;} void write(guide *val) {*stream << *val;} void write(const transform& val) {*stream << val;} void writeline(); }; class ibfile : public ifile { public: ibfile(const string& name, bool check=true, Mode type=BINPUT, std::ios::openmode mode=std::ios::in) : ifile(name,check,type,mode | std::ios::binary) {} template void iread(T& val) { val=T(); if(fstream) fstream->read((char *) &val,sizeof(T)); } void Read(bool& val) {iread(val);} void Read(Int& val) { if(signedint) { if(singleint) {int ival; iread(ival); val=ival;} else iread(val); } else { if(singleint) {unsigned ival; iread(ival); val=Intcast(ival);} else {unsignedInt ival; iread(ival); val=Intcast(ival);} } } void Read(char& val) {iread(val);} void Read(string& val) {char c; iread(c); val=c;} void Read(double& val) { if(singlereal) {float fval; iread(fval); val=fval;} else iread(val); } }; class iobfile : public ibfile { public: iobfile(const string& name) : ibfile(name,true,BUPDATE,std::ios::in | std::ios::out) {} void flush() {if(fstream) fstream->flush();} template void iwrite(T val) { if(fstream) fstream->write((char *) &val,sizeof(T)); } void write(bool val) {iwrite(val);} void write(Int val) { if(signedint) { if(singleint) iwrite(intcast(val)); else iwrite(val); } else { if(singleint) iwrite(unsignedcast(val)); else iwrite(unsignedIntcast(val)); } } void write(const string& val) {iwrite(val);} void write(const pen& val) {iwrite(val);} void write(guide *val) {iwrite(val);} void write(const transform& val) {iwrite(val);} void write(double val) { if(singlereal) iwrite((float) val); else iwrite(val); } void write(const pair& val) { write(val.getx()); write(val.gety()); } void write(const triple& val) { write(val.getx()); write(val.gety()); write(val.getz()); } void writeline() {} }; class obfile : public ofile { public: obfile(const string& name) : ofile(name,BOUTPUT,std::ios::binary) {} template void iwrite(T val) { if(fstream) fstream->write((char *) &val,sizeof(T)); } void write(bool val) {iwrite(val);} void write(Int val) { if(signedint) { if(singleint) iwrite(intcast(val)); else iwrite(val); } else { if(singleint) iwrite(unsignedcast(val)); else iwrite(unsignedIntcast(val)); } } void write(const string& val) {iwrite(val);} void write(const pen& val) {iwrite(val);} void write(guide *val) {iwrite(val);} void write(const transform& val) {iwrite(val);} void write(double val) { if(singlereal) iwrite((float) val); else iwrite(val); } void write(const pair& val) { write(val.getx()); write(val.gety()); } void write(const triple& val) { write(val.getx()); write(val.gety()); write(val.getz()); } void writeline() {} }; #ifdef HAVE_RPC_RPC_H class ixfile : public file { protected: xdr::ioxstream *fstream; xdr::xios::open_mode mode; public: ixfile(const string& name, bool check=true, Mode type=XINPUT, xdr::xios::open_mode mode=xdr::xios::in) : file(name,check,type,true), fstream(NULL), mode(mode) {} void open() { fstream=new xdr::ioxstream(name.c_str(),mode); index=processData().ixfile.add(fstream); if(check) Check(); } void close() { if(fstream) { fstream->close(); closed=true; delete fstream; fstream=NULL; processData().ixfile.remove(index); } } ~ixfile() {close();} bool eof() {return fstream ? fstream->eof() : true;} bool error() {return fstream ? fstream->fail() : true;} void clear() {if(fstream) fstream->clear();} void seek(Int pos, bool begin=true) { if(!standard && fstream) { clear(); fstream->seek(pos,begin ? xdr::xios::beg : xdr::xios::end); } } size_t tell() { if(fstream) return fstream->tell(); else return 0; } void Read(Int& val) { if(signedint) { if(singleint) {int ival=0; *fstream >> ival; val=ival;} else {val=0; *fstream >> val;} } else { if(singleint) {unsigned ival=0; *fstream >> ival; val=Intcast(ival);} else {unsignedInt ival=0; *fstream >> ival; val=Intcast(ival);} } } void Read(double& val) { if(singlereal) {float fval=0.0; *fstream >> fval; val=fval;} else { val=0.0; *fstream >> val; } } void Read(pair& val) { double x,y; Read(x); Read(y); val=pair(x,y); } void Read(triple& val) { double x,y,z; Read(x); Read(y); Read(z); val=triple(x,y,z); } }; class ioxfile : public ixfile { public: ioxfile(const string& name) : ixfile(name,true,XUPDATE,xdr::xios::out) {} void flush() {if(fstream) fstream->flush();} void write(Int val) { if(signedint) { if(singleint) *fstream << intcast(val); else *fstream << val; } else { if(singleint) *fstream << unsignedcast(val); else *fstream << unsignedIntcast(val); } } void write(double val) { if(singlereal) *fstream << (float) val; else *fstream << val; } void write(const pair& val) { write(val.getx()); write(val.gety()); } void write(const triple& val) { write(val.getx()); write(val.gety()); write(val.getz()); } }; class oxfile : public file { xdr::oxstream *fstream; public: oxfile(const string& name) : file(name,true,XOUTPUT), fstream(NULL) {} void open() { fstream=new xdr::oxstream(outpath(name).c_str(),xdr::xios::trunc); index=processData().oxfile.add(fstream); Check(); } void close() { if(fstream) { fstream->close(); closed=true; delete fstream; fstream=NULL; processData().oxfile.remove(index); } } ~oxfile() {close();} bool eof() {return fstream ? fstream->eof() : true;} bool error() {return fstream ? fstream->fail() : true;} void clear() {if(fstream) fstream->clear();} void flush() {if(fstream) fstream->flush();} void seek(Int pos, bool begin=true) { if(!standard && fstream) { clear(); fstream->seek(pos,begin ? xdr::xios::beg : xdr::xios::end); } } size_t tell() { if(fstream) return fstream->tell(); else return 0; } void write(Int val) { if(signedint) { if(singleint) *fstream << intcast(val); else *fstream << val; } else { if(singleint) *fstream << unsignedcast(val); else *fstream << unsignedIntcast(val); } } void write(double val) { if(singlereal) *fstream << (float) val; else *fstream << val; } void write(const pair& val) { write(val.getx()); write(val.gety()); } void write(const triple& val) { write(val.getx()); write(val.gety()); write(val.getz()); } }; #endif extern ofile Stdout; extern file nullfile; } // namespace camp #endif // FILEIO_H asymptote-2.37/findsym.pl000077500000000000000000000023351265434602500155150ustar00rootroot00000000000000#!/usr/bin/env perl ##### # findsym.pl # Andy Hammerlindl 2010/06/01 # # Extract static symbols used in builtin.cc and write code so that they are # translated only once when creating the symbol table. ##### $outname = shift(@ARGV); if (not $outname) { print STDERR "usage ./findsym.pl out_symbols.h file1.cc file2.cc ...\n"; exit(1); } open(header, ">$outname") || die("Couldn't open $outname for writing"); print header <) { while (m/SYM\(([_A-Za-z][_A-Za-z0-9]*)\)/gx) { $symbols{ $1 } = 1; } } } foreach my $s (sort keys %symbols) { add($s); } asymptote-2.37/flatguide.cc000066400000000000000000000017741265434602500157650ustar00rootroot00000000000000/***** * flatguide.cc * Andy Hammerlindl 2005/02/23 * * The data structure that builds up a knotlist. This is done by calling in * order the methods to set knots, specifiers, and tensions. * Used by the guide solving routines. *****/ #include "flatguide.h" namespace camp { void flatguide::addPre(path& p, Int j) { setSpec(new controlSpec(p.precontrol(j),p.straight(j-1)),IN); } void flatguide::addPoint(path& p, Int j) { add(p.point(j)); } void flatguide::addPost(path& p, Int j) { setSpec(new controlSpec(p.postcontrol(j),p.straight(j)),OUT); } void flatguide::uncheckedAdd(path p, bool allowsolve) { Int n=p.length(); if(n < 0) return; if(n == 0) { addPoint(p,0); return; } int nminus1=n-1; if(!allowsolve && p.cyclic()) addPre(p,0); for(Int i=0; i < nminus1;) { addPoint(p,i); addPost(p,i); ++i; addPre(p,i); } addPoint(p,nminus1); addPost(p,nminus1); if(allowsolve || !p.cyclic()) { addPre(p,n); addPoint(p,n); } } spec flatguide::open; } asymptote-2.37/flatguide.h000066400000000000000000000102071265434602500156160ustar00rootroot00000000000000/***** * flatguide.h * Andy Hammerlindl 2005/02/23 * * The data structure that builds up a knotlist. This is done by calling in * order the methods to set knots, specifiers, and tensions. * Used by the guide solving routines. * * NOTE: figure out how nullpath{}..a should be handled. *****/ #ifndef FLATGUIDE_H #define FLATGUIDE_H #include "knot.h" #include "guideflags.h" namespace camp { class flatguide { // A cached solution of the path. When traversing through a tree of guides, // if a cycle tag is encountered, then the path is solved up to that point. // If the guide continues from there (which rarely occurs in practice), all of // the control points solved are added as control specifiers, and then solved // into a path again. In the (usual) case that a cycle ends a path, the // cached path avoids this second pass. bool solved; // Used by reverse(guide) to indicate the presence of an unresolved // interior cycle. bool precycle; path p; cvector nodes; // Information before the first knot. For a non-cyclic guide, this is // ignored. For a cyclic guide, it may be useful, but I can't determine a // sensible way to use it yet. tension tout; spec *out; // Information for the next knot to come. tension tin; spec *in; static spec open; tension& tref(side s) { switch (s) { case OUT: return nodes.empty() ? tout : nodes.back().tout; case IN: default: return tin; } } // Returns a reference to a spec* so that it may be assigned. spec*& sref(side s) { switch (s) { case OUT: return nodes.empty() ? out : nodes.back().out; case IN: default: return in; } } void addPre(path& p, Int j); void addPoint(path& p, Int j); void addPost(path& p, Int j); void clearNodes() { nodes.clear(); in=&open; tin=tension(); } void clearPath() { p=path(); solved=false; } void uncheckedAdd(path p, bool allowsolve=true); // Sets solved to false, indicating that the path has been updated since last // being solved. Also, copies a solved path back in as knots and control // specifiers, as it will have to be solved again. void update() { if (solved) { solved=false; clearNodes(); add(p); clearPath(); } } public: flatguide() : solved(true), precycle(false), p(), out(&open), in(&open) {} Int size() const { return (Int) nodes.size(); } knot Nodes(Int i) const { return nodes[i]; } void setTension(tension t, side s) { update(); tref(s)=t; } void setSpec(spec *p, side s) { assert(p); update(); spec *&ref=sref(s); // Control specifiers trump normal direction specifiers. if (!ref || !ref->controlled() || p->controlled()) ref=p; } void add(pair z) { update(); // Push the pair onto the vector as a knot, using the current in-specifier // and in-tension for the in side for the knot. Use default values for the // out side, as those will be set after the point is added. nodes.push_back(knot(z,in,&open,tin,tension())); // Reset the in-spec and in-tension to defaults; tin=tension(); in=&open; } // Reverts to an empty state. void add(path p, bool allowsolve=true) { update(); uncheckedAdd(p,allowsolve); } void clear() { clearNodes(); clearPath(); } void close() { if(!nodes.empty()) { nodes.front().in=in; nodes.front().tin=tin; } } void resolvecycle() { if(!nodes.empty()) nodes.push_back(nodes.front()); } void precyclic(bool b) { precycle=b; } bool precyclic() { return precycle; } // Once all information has been added, release the flat result. simpleknotlist list(bool cycles=false) { if(cycles && !nodes.empty()) close(); return simpleknotlist(nodes,cycles); } // Yield a path from the guide as represented here. path solve(bool cycles=false) { if (solved) return p; else { simpleknotlist l=list(cycles); p=camp::solve(l); solved=true; return p; } } }; } // namespace camp #endif // FLATGUIDE_H asymptote-2.37/fpu.h000066400000000000000000000012141265434602500144420ustar00rootroot00000000000000#ifndef FPU_H #define FPU_H #ifdef HAVE_FENV_H #ifdef _GNU_SOURCE #define HAVE_FEENABLEEXCEPT #endif #endif #ifdef HAVE_FEENABLEEXCEPT #include inline int fpu_exceptions() { int excepts=0; #ifdef FE_INVALID excepts |= FE_INVALID; #endif #ifdef FE_DIVBYZERO excepts |= FE_DIVBYZERO; #endif #ifdef FE_OVERFLOW excepts |= FE_OVERFLOW; #endif return excepts; } inline void fpu_trap(bool trap=true) { // Conditionally trap FPU exceptions on NaN, zero divide and overflow. if(trap) feenableexcept(fpu_exceptions()); else fedisableexcept(fpu_exceptions()); } #else inline void fpu_trap(bool=true) {} #endif #endif asymptote-2.37/frame.h000066400000000000000000000041751265434602500147530ustar00rootroot00000000000000/***** * frame.h * Andy Hammerlindl 2002/07/22 * * Describes the frame levels for the functions of the language. * Also creates accesses for the variable for automated loading * and saving of variables. *****/ #ifndef FRAME_H #define FRAME_H #include #include "access.h" namespace trans { class frame : public gc { frame *parent; size_t numFormals; Int numLocals; // With the SIMPLE_FRAME flag, the size of frames cannot be changed at // runtime. This is an issue for runnable-at-a-time mode, where global // variables can be continually added. To handle this, the frame for // global variables is an "indirect" frame. It holds one variable, which is // a link to another frame. When the subframe is too small, a larger // runtime array is allocated, and the link is changed. enum {DIRECT_FRAME, INDIRECT_FRAME} style; #ifdef DEBUG_FRAME string name; #endif frame(string name) : parent(new frame("", 0, 0)), numFormals(0), numLocals(1), style(INDIRECT_FRAME) #ifdef DEBUG_FRAME , name(name) #endif {} public: frame(string name, frame *parent, size_t numFormals) : parent(parent), numFormals(numFormals), numLocals(0), style(DIRECT_FRAME) #ifdef DEBUG_FRAME , name(name) #endif {} static frame *indirect_frame(string name) { return new frame(name); } frame *getParent() { return parent; } // Which variable stores the link to the parent frame. Int parentIndex() { return numFormals; } Int size() { if (style == DIRECT_FRAME) return (Int) (1+numFormals+numLocals); else return parent->size(); } access *accessFormal(size_t index) { assert(index < numFormals); assert(style == DIRECT_FRAME); return new localAccess((Int) (index), this); } access *allocLocal() { if (style == DIRECT_FRAME) return new localAccess((Int) (1 + numFormals + numLocals++), this); else return parent->allocLocal(); } }; inline void print(ostream& out, frame *f) { out << f; if (f != 0) { out << " -> "; print(out, f->getParent()); } } } // namespace trans #endif asymptote-2.37/fundec.cc000066400000000000000000000173771265434602500152730ustar00rootroot00000000000000/***** * fundec.h * Andy Hammerlindl 2002/8/29 * * Defines the semantics for defining functions. Both the newexp syntax, and * the abbreviated C-style function definition. *****/ #include "fundec.h" #include "errormsg.h" #include "coenv.h" #include "stm.h" #include "runtime.h" namespace absyntax { using namespace trans; using namespace types; using mem::list; varinit *Default=new definit(nullPos); void formal::prettyprint(ostream &out, Int indent) { prettyname(out, keywordOnly ? "formal (keyword only)" : "formal", indent); base->prettyprint(out, indent+1); if (start) start->prettyprint(out, indent+1); if (defval) defval->prettyprint(out, indent+1); } types::formal formal::trans(coenv &e, bool encodeDefVal, bool tacit) { return types::formal(getType(e,tacit), getName(), encodeDefVal ? (bool) getDefaultValue() : 0, getExplicit()); } types::ty *formal::getType(coenv &e, bool tacit) { types::ty *bt = base->trans(e, tacit); types::ty *t = start ? start->getType(bt, e, tacit) : bt; if (t->kind == ty_void && !tacit) { em.error(getPos()); em << "cannot declare parameters of type void"; return primError(); } return t; } void formal::addOps(coenv &e, record *r) { base->addOps(e, r); if (start) start->addOps(base->trans(e, true), e, r); } void formals::prettyprint(ostream &out, Int indent) { prettyname(out, "formals",indent); for (list::iterator p = fields.begin(); p != fields.end(); ++p) (*p)->prettyprint(out, indent+1); } void formals::addToSignature(signature& sig, coenv &e, bool encodeDefVal, bool tacit) { for (list::iterator p = fields.begin(); p != fields.end(); ++p) { formal& f=**p; types::formal tf = f.trans(e, encodeDefVal, tacit); if (f.isKeywordOnly()) sig.addKeywordOnly(tf); else sig.add(tf); } if (rest) { if (!tacit && rest->getDefaultValue()) { em.error(rest->getPos()); em << "rest parameters cannot have default values"; } sig.addRest(rest->trans(e, encodeDefVal, tacit)); } } // Returns the types of each parameter as a signature. // encodeDefVal means that it will also encode information regarding // the default values into the signature signature *formals::getSignature(coenv &e, bool encodeDefVal, bool tacit) { signature *sig = new signature; addToSignature(*sig,e,encodeDefVal,tacit); return sig; } // Returns the corresponding function type, assuming it has a return // value of types::ty *result. function *formals::getType(types::ty *result, coenv &e, bool encodeDefVal, bool tacit) { function *ft = new function(result); addToSignature(ft->sig,e,encodeDefVal,tacit); return ft; } void formals::addOps(coenv &e, record *r) { for(list::iterator p = fields.begin(); p != fields.end(); ++p) (*p)->addOps(e, r); if (rest) rest->addOps(e, r); } // Another helper class. Does an assignment, but relying only on the // destination for the type. class basicAssignExp : public exp { varEntry *dest; varinit *value; public: basicAssignExp(position pos, varEntry *dest, varinit *value) : exp(pos), dest(dest), value(value) {} void prettyprint(ostream &out, Int indent) { prettyname(out, "basicAssignExp", indent); } types::ty *getType(coenv &) { return dest->getType(); } types::ty *trans(coenv &e) { // This doesn't handle overloaded types for the destination. value->transToType(e, getType(e)); dest->encode(WRITE, pos, e.c); return getType(e); } }; void transDefault(coenv &e, position pos, varEntry *v, varinit *init) { // This roughly translates into the statement // if (isDefault(x)) // x=init; // where x is the variable in v and isDefault is a function that tests // whether x is the default argument token. v->encode(READ, pos, e.c); label end = e.c.fwdLabel(); e.c.useLabel(inst::jump_if_not_default, end); init->transToType(e, v->getType()); v->encode(WRITE, pos, e.c); e.c.encodePop(); e.c.defLabel(end); } void formal::transAsVar(coenv &e, Int index) { symbol name = getName(); if (name) { trans::access *a = e.c.accessFormal(index); assert(a); // Suppress error messages because they will already be reported // when the formals are translated to yield the type earlier. types::ty *t = getType(e, true); varEntry *v = new varEntry(t, a, 0, getPos()); // Translate the default argument before adding the formal to the // environment, consistent with the initializers of variables. if (defval) transDefault(e, getPos(), v, defval); e.e.addVar(name, v); } } void formals::trans(coenv &e) { Int index = 0; for (list::iterator p=fields.begin(); p!=fields.end(); ++p) { (*p)->transAsVar(e, index); ++index; } if (rest) { rest->transAsVar(e, index); ++index; } } void fundef::prettyprint(ostream &out, Int indent) { result->prettyprint(out, indent+1); params->prettyprint(out, indent+1); body->prettyprint(out, indent+1); } function *fundef::transType(coenv &e, bool tacit) { bool encodeDefVal=true; return params->getType(result->trans(e, tacit), e, encodeDefVal, tacit); } function *fundef::transTypeAndAddOps(coenv &e, record *r, bool tacit) { result->addOps(e,r); params->addOps(e,r); function *ft=transType(e, tacit); e.e.addFunctionOps(ft); if (r) r->e.addFunctionOps(ft); return ft; } varinit *fundef::makeVarInit(function *ft) { struct initializer : public varinit { fundef *f; function *ft; initializer(fundef *f, function *ft) : varinit(f->getPos()), f(f), ft(ft) {} void prettyprint(ostream &out, Int indent) { prettyname(out, "initializer", indent); } void transToType(coenv &e, types::ty *target) { assert(ft==target); f->baseTrans(e, ft); } }; return new initializer(this, ft); } void fundef::baseTrans(coenv &e, types::function *ft) { string name = id ? string(id) : string(""); // Create a new function environment. coder fc = e.c.newFunction(getPos(), name, ft); coenv fe(fc,e.e); // Translate the function. fe.e.beginScope(); params->trans(fe); body->trans(fe); types::ty *rt = ft->result; if (rt->kind != ty_void && rt->kind != ty_error && !body->returns()) { em.error(body->getPos()); em << "function must return a value"; } fe.e.endScope(); // Put an instance of the new function on the stack. vm::lambda *l = fe.c.close(); e.c.encode(inst::pushclosure); e.c.encode(inst::makefunc, l); } types::ty *fundef::trans(coenv &e) { // I don't see how addFunctionOps can be useful here. // For instance, in // // new void() {} == null // // callExp has to search for == before translating either argument, and the // operator cannot be added before translation. (getType() is not allowed to // manipulate the environment.) // A new function expression is assigned to a variable, given as a return // value, or used as an argument to a function. In any of these // // We must still addOps though, for the return type and formals. ex: // // new guide[] (guide f(int)) { // return sequence(f, 10); // }; function *ft=transTypeAndAddOps(e, (record *)0, false); assert(ft); baseTrans(e, ft); return ft; } void fundec::prettyprint(ostream &out, Int indent) { prettyindent(out, indent); out << "fundec '" << id << "'\n"; fun.prettyprint(out, indent); } void fundec::trans(coenv &e) { transAsField(e,0); } void fundec::transAsField(coenv &e, record *r) { function *ft = fun.transTypeAndAddOps(e, r, false); assert(ft); createVar(getPos(), e, r, id, ft, fun.makeVarInit(ft)); } } // namespace absyntax asymptote-2.37/fundec.h000066400000000000000000000103731265434602500151220ustar00rootroot00000000000000/***** * fundec.h * Andy Hammerlindl 2002/8/29 * * Defines the semantics for defining functions. Both the newexp syntax, and * the abbreviated C-style function definition. *****/ #ifndef FUNDEC_H #define FUNDEC_H #include "dec.h" #include "exp.h" namespace absyntax { class formal : public absyn { ty *base; decidstart *start; bool Explicit; varinit *defval; bool keywordOnly; public: formal(position pos, ty *base, decidstart *start=0, varinit *defval=0, bool Explicit= false, bool keywordOnly=false) : absyn(pos), base(base), start(start), Explicit(Explicit), defval(defval), keywordOnly(keywordOnly) {} virtual void prettyprint(ostream &out, Int indent); // Build the corresponding types::formal to put into a signature. types::formal trans(coenv &e, bool encodeDefVal, bool tacit=false); // Add the formal parameter to the environment to prepare for the // function body's translation. virtual void transAsVar(coenv &e, Int index); types::ty *getType(coenv &e, bool tacit=false); virtual void addOps(coenv &e, record *r); varinit *getDefaultValue() { return defval; } symbol getName() { return start ? start->getName() : symbol::nullsym; } bool getExplicit() { return Explicit; } bool isKeywordOnly() { return keywordOnly; } }; class formals : public absyn { //friend class funheader; mem::list fields; formal *rest; // If the list of formals contains at least one keyword-only formal. bool keywordOnly; void addToSignature(types::signature& sig, coenv &e, bool encodeDefVal, bool tacit); public: formals(position pos) : absyn(pos), rest(0), keywordOnly(false) {} virtual ~formals() {} virtual void prettyprint(ostream &out, Int indent); virtual void add(formal *f) { if (f->isKeywordOnly()) { keywordOnly = true; } else if (rest) { em.error(f->getPos()); em << "normal parameter after rest parameter"; } else if (keywordOnly) { em.error(f->getPos()); em << "normal parameter after keyword-only parameter"; } fields.push_back(f); } virtual void addRest(formal *f) { if (rest) { em.error(f->getPos()); em << "additional rest parameter"; } else if (f->isKeywordOnly()) { em.error(f->getPos()); em << "rest parameter declared as keyword-only"; } rest = f; } // Returns the types of each parameter as a signature. // encodeDefVal means that it will also encode information regarding // the default values into the signature types::signature *getSignature(coenv &e, bool encodeDefVal = false, bool tacit = false); // Returns the corresponding function type, assuming it has a return // value of "result." types::function *getType(types::ty *result, coenv &e, bool encodeDefVal = false, bool tacit = false); virtual void addOps(coenv &e, record *r); // Add the formal parameters to the environment to prepare for the // function body's translation. virtual void trans(coenv &e); }; class fundef : public exp { ty *result; formals *params; stm *body; // If the fundef is part of a fundec, the name of the function is stored // here for debugging purposes. symbol id; friend class fundec; public: fundef(position pos, ty *result, formals *params, stm *body) : exp(pos), result(result), params(params), body(body), id() {} virtual void prettyprint(ostream &out, Int indent); varinit *makeVarInit(types::function *ft); virtual void baseTrans(coenv &e, types::function *ft); virtual types::ty *trans(coenv &e); virtual types::function *transType(coenv &e, bool tacit); virtual types::function *transTypeAndAddOps(coenv &e, record *r, bool tacit); virtual types::ty *getType(coenv &e) { return transType(e, true); } }; class fundec : public dec { symbol id; fundef fun; public: fundec(position pos, ty *result, symbol id, formals *params, stm *body) : dec(pos), id(id), fun(pos, result, params, body) { fun.id = id; } void prettyprint(ostream &out, Int indent); void trans(coenv &e); void transAsField(coenv &e, record *r); }; } // namespace absyntax #endif asymptote-2.37/genv.cc000066400000000000000000000061311265434602500147500ustar00rootroot00000000000000/***** * genv.cc * Andy Hammerlindl 2002/08/29 * * This is the global environment for the translation of programs. In * actuality, it is basically a module manager. When a module is * requested, it looks for the corresponding filename, and if found, * parses and translates the file, returning the resultant module. * * genv sets up the basic type bindings and function bindings for * builtin functions, casts and operators, and imports plain (if set), * but all other initialization is done by the local environment defined * in env.h. *****/ #include #include #include #include "genv.h" #include "env.h" #include "dec.h" #include "stm.h" #include "types.h" #include "settings.h" #include "runtime.h" #include "parser.h" #include "locate.h" #include "interact.h" #include "builtin.h" using namespace types; using settings::getSetting; using settings::Setting; // Dynamic loading of external libraries. types::record *transExternalModule(trans::genv& ge, string filename, symbol id); namespace trans { genv::genv() : imap() { // Add settings as a module. This is so that the init file ~/.asy/config.asy // can set settings. imap["settings"]=settings::getSettingsModule(); // Translate plain in advance, if we're using autoplain. if(getSetting("autoplain")) { Setting("autoplain")=false; // Translate plain without autoplain. getModule(symbol::trans("plain"), "plain"); Setting("autoplain")=true; } #ifdef HAVE_LIBGSL imap["gsl"]=trans::getGSLModule(); #endif } bool endswith(string suffix, string str) { return std::equal(suffix.rbegin(), suffix.rend(), str.rbegin()); } record *genv::loadModule(symbol id, string filename) { // Hackish way to load an external library. #if 0 if (endswith(".so", filename)) { return transExternalModule(*this, filename, id); } #endif // Get the abstract syntax tree. absyntax::file *ast = parser::parseFile(filename,"Loading"); inTranslation.push_front(filename); em.sync(); record *r=ast->transAsFile(*this, id); inTranslation.remove(filename); return r; } void genv::checkRecursion(string filename) { if (find(inTranslation.begin(), inTranslation.end(), filename) != inTranslation.end()) { em.sync(); em << "error: recursive loading of module '" << filename << "'\n"; em.sync(); throw handled_error(); } } record *genv::getModule(symbol id, string filename) { checkRecursion(filename); record *r=imap[filename]; if (r) return r; else { record *r=loadModule(id, filename); // Don't add an erroneous module to the dictionary in interactive mode, as // the user may try to load it again. if (!interact::interactive || !em.errors()) imap[filename]=r; return r; } } typedef vm::stack::importInitMap importInitMap; importInitMap *genv::getInitMap() { struct initMap : public importInitMap, public gc { genv ≥ initMap(genv &ge) : ge(ge) {} lambda *operator[](string s) { record *r=ge.imap[s]; return r ? r->getInit() : 0; } }; return new initMap(*this); } } // namespace trans asymptote-2.37/genv.h000066400000000000000000000031321265434602500146100ustar00rootroot00000000000000/***** * genv.h * Andy Hammerlindl 2002/08/29 * * This is the global environment for the translation of programs. In * actuality, it is basically a module manager. When a module is * requested, it looks for the corresponding filename, and if found, * parses and translates the file, returning the resultant module. * * genv sets up the basic type bindings and function bindings for * builtin functions, casts and operators, and imports plain (if set), * but all other initialization, is done by the local environmet defined * in env.h. *****/ #ifndef GENV_H #define GENV_H #include "common.h" #include "table.h" #include "record.h" #include "absyn.h" #include "access.h" #include "coenv.h" #include "stack.h" using types::record; using vm::lambda; namespace trans { class genv : public gc { // The initializer functions for imports, indexed by filename. typedef mem::map importMap; importMap imap; // List of modules in translation. Used to detect and prevent infinite // recursion in loading modules. mem::list inTranslation; // Checks for recursion in loading, reporting an error and throwing an // exception if it occurs. void checkRecursion(string filename); // Translate a module to build the record type. record *loadModule(symbol name, string s); public: genv(); // Get an imported module, translating if necessary. record *getModule(symbol name, string s); // Uses the filename->record map to build a filename->initializer map to be // used at runtime. vm::stack::importInitMap *getInitMap(); }; } // namespace trans #endif asymptote-2.37/getopt.c000066400000000000000000000727031265434602500151600ustar00rootroot00000000000000/* Getopt for GNU. NOTE: getopt is now part of the C library, so if you don't know what "Keep this file name-space clean" means, talk to drepper@gnu.org before changing it! Copyright (C) 1987,88,89,90,91,92,93,94,95,96,98,99,2000,2001 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ /* This tells Alpha OSF/1 not to define a getopt prototype in . Ditto for AIX 3.2 and . */ #ifndef _NO_PROTO # define _NO_PROTO #endif #ifdef HAVE_CONFIG_H # include #endif #if !defined __STDC__ || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ # ifndef const # define const # endif #endif #include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #define GETOPT_INTERFACE_VERSION 2 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 # include # if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION # define ELIDE_CODE # endif #endif #ifndef ELIDE_CODE /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ /* Don't include stdlib.h for non-GNU C libraries because some of them contain conflicting prototypes for getopt. */ # include # include #endif /* GNU C library. */ #ifdef VMS # include # if HAVE_STRING_H - 0 # include # endif #endif #ifndef _ /* This is for other GNU distributions with internationalized messages. */ # if defined HAVE_LIBINTL_H || defined _LIBC # include # ifndef _ # define _(msgid) gettext (msgid) # endif # else # define _(msgid) (msgid) # endif #endif /* This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves differently for the user, since it allows the user to intersperse the options with the other arguments. As `getopt' works, it permutes the elements of ARGV so that, when it is done, all the options precede everything else. Thus all application programs are extended to handle flexible argument order. Setting the environment variable POSIXLY_CORRECT disables permutation. Then the behavior is completely standard. GNU application programs can use a third alternative mode in which they can distinguish the relative order of options and other arguments. */ #include "getopt.h" /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns -1, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ /* 1003.2 says this must be 1 before any call. */ int optind = 1; /* Formerly, initialization of getopt depended on optind==0, which causes problems with re-calling getopt as programs generally don't know that. */ int __getopt_initialized; /* The next char to be scanned in the option-element in which the last option character we returned was found. This allows us to pick up the scan where we left off. If this is zero, or a null string, it means resume the scan by advancing to the next ARGV-element. */ static char *nextchar; /* Callers store zero here to inhibit the error message for unrecognized options. */ int opterr = 1; /* Set to an option character which was unrecognized. This must be initialized on some systems to avoid linking in the system's own getopt implementation. */ int optopt = '?'; /* Describe how to deal with options that follow non-option ARGV-elements. If the caller did not specify anything, the default is REQUIRE_ORDER if the environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise. REQUIRE_ORDER means don't recognize them as options; stop option processing when the first non-option is seen. This is what Unix does. This mode of operation is selected by either setting the environment variable POSIXLY_CORRECT, or using `+' as the first character of the list of option characters. PERMUTE is the default. We permute the contents of ARGV as we scan, so that eventually all the non-options are at the end. This allows options to be given in any order, even with programs that were not written to expect this. RETURN_IN_ORDER is an option available to programs that were written to expect options and other ARGV-elements in any order and that care about the ordering of the two. We describe each non-option ARGV-element as if it were the argument of an option with character code 1. Using `-' as the first character of the list of option characters selects this mode of operation. The special argument `--' forces an end of option-scanning regardless of the value of `ordering'. In the case of RETURN_IN_ORDER, only `--' can cause `getopt' to return -1 with `optind' != ARGC. */ static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering; /* Value of POSIXLY_CORRECT environment variable. */ static char *posixly_correct; #ifdef __GNU_LIBRARY__ /* We want to avoid inclusion of string.h with non-GNU libraries because there are many ways it can cause trouble. On some systems, it contains special magic macros that don't work in GCC. */ # include # define my_index strchr #else # if HAVE_STRING_H # include # else # include # endif /* Avoid depending on library functions or files whose names are inconsistent. */ #ifndef getenv extern char *getenv (); #endif static char * my_index (str, chr) const char *str; int chr; { while (*str) { if (*str == chr) return (char *) str; str++; } return 0; } /* If using GCC, we can safely declare strlen this way. If not using GCC, it is ok not to declare it. */ #ifdef __GNUC__ /* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. That was relevant to code that was here before. */ # if (!defined __STDC__ || !__STDC__) && !defined strlen /* gcc with -traditional declares the built-in strlen to return int, and has done so at least since version 2.4.5. -- rms. */ extern int strlen (const char *); # endif /* not __STDC__ */ #endif /* __GNUC__ */ #endif /* not __GNU_LIBRARY__ */ /* Handle permutation of arguments. */ /* Describe the part of ARGV that contains non-options that have been skipped. `first_nonopt' is the index in ARGV of the first of them; `last_nonopt' is the index after the last of them. */ static int first_nonopt; static int last_nonopt; #ifdef _LIBC /* Stored original parameters. XXX This is no good solution. We should rather copy the args so that we can compare them later. But we must not use malloc(3). */ extern int __libc_argc; extern char **__libc_argv; /* Bash 2.0 gives us an environment variable containing flags indicating ARGV elements that should not be considered arguments. */ # ifdef USE_NONOPTION_FLAGS /* Defined in getopt_init.c */ extern char *__getopt_nonoption_flags; static int nonoption_flags_max_len; static int nonoption_flags_len; # endif # ifdef USE_NONOPTION_FLAGS # define SWAP_FLAGS(ch1, ch2) \ if (nonoption_flags_len > 0) \ { \ char __tmp = __getopt_nonoption_flags[ch1]; \ __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ __getopt_nonoption_flags[ch2] = __tmp; \ } # else # define SWAP_FLAGS(ch1, ch2) # endif #else /* !_LIBC */ # define SWAP_FLAGS(ch1, ch2) #endif /* _LIBC */ /* Exchange two adjacent subsequences of ARGV. One subsequence is elements [first_nonopt,last_nonopt) which contains all the non-options that have been skipped so far. The other is elements [last_nonopt,optind), which contains all the options processed since those non-options were skipped. `first_nonopt' and `last_nonopt' are relocated so that they describe the new indices of the non-options in ARGV after they are moved. */ #if defined __STDC__ && __STDC__ static void exchange (char **); #endif static void exchange (argv) char **argv; { int bottom = first_nonopt; int middle = last_nonopt; int top = optind; char *tem; /* Exchange the shorter segment with the far end of the longer segment. That puts the shorter segment into the right place. It leaves the longer segment in the right place overall, but it consists of two parts that need to be swapped next. */ #if defined _LIBC && defined USE_NONOPTION_FLAGS /* First make sure the handling of the `__getopt_nonoption_flags' string can work normally. Our top argument must be in the range of the string. */ if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) { /* We must extend the array. The user plays games with us and presents new arguments. */ char *new_str = malloc (top + 1); if (new_str == NULL) nonoption_flags_len = nonoption_flags_max_len = 0; else { memset (__mempcpy (new_str, __getopt_nonoption_flags, nonoption_flags_max_len), '\0', top + 1 - nonoption_flags_max_len); nonoption_flags_max_len = top + 1; __getopt_nonoption_flags = new_str; } } #endif while (top > middle && middle > bottom) { if (top - middle > middle - bottom) { /* Bottom segment is the short one. */ int len = middle - bottom; register int i; /* Swap it with the top part of the top segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[top - (middle - bottom) + i]; argv[top - (middle - bottom) + i] = tem; SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); } /* Exclude the moved bottom segment from further swapping. */ top -= len; } else { /* Top segment is the short one. */ int len = top - middle; register int i; /* Swap it with the bottom part of the bottom segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[middle + i]; argv[middle + i] = tem; SWAP_FLAGS (bottom + i, middle + i); } /* Exclude the moved top segment from further swapping. */ bottom += len; } } /* Update records for the slots the non-options now occupy. */ first_nonopt += (optind - last_nonopt); last_nonopt = optind; } /* Initialize the internal data when the first call is made. */ #if defined __STDC__ && __STDC__ static const char *_getopt_initialize (int, char *const *, const char *); #endif static const char * _getopt_initialize (argc, argv, optstring) int argc; char *const *argv; const char *optstring; { /* Start processing options with ARGV-element 1 (since ARGV-element 0 is the program name); the sequence of previously skipped non-option ARGV-elements is empty. */ first_nonopt = last_nonopt = optind; nextchar = NULL; posixly_correct = getenv ("POSIXLY_CORRECT"); /* Determine how to handle the ordering of options and nonoptions. */ if (optstring[0] == '-') { ordering = RETURN_IN_ORDER; ++optstring; } else if (optstring[0] == '+') { ordering = REQUIRE_ORDER; ++optstring; } else if (posixly_correct != NULL) ordering = REQUIRE_ORDER; else ordering = PERMUTE; #if defined _LIBC && defined USE_NONOPTION_FLAGS if (posixly_correct == NULL && argc == __libc_argc && argv == __libc_argv) { if (nonoption_flags_max_len == 0) { if (__getopt_nonoption_flags == NULL || __getopt_nonoption_flags[0] == '\0') nonoption_flags_max_len = -1; else { const char *orig_str = __getopt_nonoption_flags; int len = nonoption_flags_max_len = strlen (orig_str); if (nonoption_flags_max_len < argc) nonoption_flags_max_len = argc; __getopt_nonoption_flags = (char *) malloc (nonoption_flags_max_len); if (__getopt_nonoption_flags == NULL) nonoption_flags_max_len = -1; else memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), '\0', nonoption_flags_max_len - len); } } nonoption_flags_len = nonoption_flags_max_len; } else nonoption_flags_len = 0; #endif return optstring; } /* Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING. If an element of ARGV starts with '-', and is not exactly "-" or "--", then it is an option element. The characters of this element (aside from the initial '-') are option characters. If `getopt' is called repeatedly, it returns successively each of the option characters from each of the option elements. If `getopt' finds another option character, it returns that character, updating `optind' and `nextchar' so that the next call to `getopt' can resume the scan with the following option character or ARGV-element. If there are no more option characters, `getopt' returns -1. Then `optind' is the index in ARGV of the first ARGV-element that is not an option. (The ARGV-elements have been permuted so that those that are not options now come last.) OPTSTRING is a string containing the legitimate option characters. If an option character is seen that is not listed in OPTSTRING, return '?' after printing an error message. If you set `opterr' to zero, the error message is suppressed but we still return '?'. If a char in OPTSTRING is followed by a colon, that means it wants an arg, so the following text in the same ARGV-element, or the text of the following ARGV-element, is returned in `optarg'. Two colons mean an option that wants an optional arg; if there is text in the current ARGV-element, it is returned in `optarg', otherwise `optarg' is set to zero. If OPTSTRING starts with `-' or `+', it requests different methods of handling the non-option ARGV-elements. See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. Long-named options begin with `--' instead of `-'. Their names may be abbreviated as long as the abbreviation is unique or is an exact match for some defined option. If they have an argument, it follows the option name in the same ARGV-element, separated from the option name by a `=', or else the in next ARGV-element. When `getopt' finds a long-named option, it returns 0 if that option's `flag' field is nonzero, the value of the option's `val' field if the `flag' field is zero. The elements of ARGV aren't really const, because we permute them. But we pretend they're const in the prototype to be compatible with other systems. LONGOPTS is a vector of `struct option' terminated by an element containing a name which is zero. LONGIND returns the index in LONGOPT of the long-named option found. It is only valid when a long-named option has been found by the most recent call. If LONG_ONLY is nonzero, '-' as well as '--' can introduce long-named options. */ int _getopt_internal (argc, argv, optstring, longopts, longind, long_only) int argc; char *const *argv; const char *optstring; const struct option *longopts; int *longind; int long_only; { int print_errors = opterr; if (optstring[0] == ':') print_errors = 0; if (argc < 1) return -1; optarg = NULL; if (optind == 0 || !__getopt_initialized) { if (optind == 0) optind = 1; /* Don't scan ARGV[0], the program name. */ optstring = _getopt_initialize (argc, argv, optstring); __getopt_initialized = 1; } /* Test whether ARGV[optind] points to a non-option argument. Either it does not have option syntax, or there is an environment flag from the shell indicating it is not an option. The later information is only used when the used in the GNU libc. */ #if defined _LIBC && defined USE_NONOPTION_FLAGS # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ || (optind < nonoption_flags_len \ && __getopt_nonoption_flags[optind] == '1')) #else # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') #endif if (nextchar == NULL || *nextchar == '\0') { /* Advance to the next ARGV-element. */ /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been moved back by the user (who may also have changed the arguments). */ if (last_nonopt > optind) last_nonopt = optind; if (first_nonopt > optind) first_nonopt = optind; if (ordering == PERMUTE) { /* If we have just processed some options following some non-options, exchange them so that the options come first. */ if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (last_nonopt != optind) first_nonopt = optind; /* Skip any additional non-options and extend the range of non-options previously skipped. */ while (optind < argc && NONOPTION_P) optind++; last_nonopt = optind; } /* The special ARGV-element `--' means premature end of options. Skip it like a null option, then exchange with previous non-options as if it were an option, then skip everything else like a non-option. */ if (optind != argc && !strcmp (argv[optind], "--")) { optind++; if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (first_nonopt == last_nonopt) first_nonopt = optind; last_nonopt = argc; optind = argc; } /* If we have done all the ARGV-elements, stop the scan and back over any non-options that we skipped and permuted. */ if (optind == argc) { /* Set the next-arg-index to point at the non-options that we previously skipped, so the caller will digest them. */ if (first_nonopt != last_nonopt) optind = first_nonopt; return -1; } /* If we have come to a non-option and did not permute it, either stop the scan or describe it to the caller and pass it by. */ if (NONOPTION_P) { if (ordering == REQUIRE_ORDER) return -1; optarg = argv[optind++]; return 1; } /* We have found another option-ARGV-element. Skip the initial punctuation. */ nextchar = (argv[optind] + 1 + (longopts != NULL && argv[optind][1] == '-')); } /* Decode the current option-ARGV-element. */ /* Check whether the ARGV-element is a long option. If long_only and the ARGV-element has the form "-f", where f is a valid short option, don't consider it an abbreviated form of a long option that starts with f. Otherwise there would be no way to give the -f short option. On the other hand, if there's a long option "fubar" and the ARGV-element is "-fu", do consider that an abbreviation of the long option, just like "--fu", and not "-f" with arg "u". This distinction seems to be the most useful approach. */ if (longopts != NULL && (argv[optind][1] == '-' || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = -1; int option_index; for (nameend = nextchar; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if ((unsigned int) (nameend - nextchar) == (unsigned int) strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (print_errors) fprintf (stderr, _("%s: option `%s' is ambiguous\n"), argv[0], argv[optind]); nextchar += strlen (nextchar); optind++; optopt = 0; return '?'; } if (pfound != NULL) { option_index = indfound; optind++; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = nameend + 1; else { if (print_errors) { if (argv[optind - 1][1] == '-') /* --option */ fprintf (stderr, _("%s: option `--%s' doesn't allow an argument\n"), argv[0], pfound->name); else /* +option or -option */ fprintf (stderr, _("%s: option `%c%s' doesn't allow an argument\n"), argv[0], argv[optind - 1][0], pfound->name); } nextchar += strlen (nextchar); optopt = pfound->val; return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (print_errors) fprintf (stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); nextchar += strlen (nextchar); optopt = pfound->val; return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } /* Can't find it as a long option. If this is not getopt_long_only, or the option starts with '--' or is not a valid short option, then it's an error. Otherwise interpret it as a short option. */ if (!long_only || argv[optind][1] == '-' || my_index (optstring, *nextchar) == NULL) { if (print_errors) { if (argv[optind][1] == '-') /* --option */ fprintf (stderr, _("%s: unrecognized option `--%s'\n"), argv[0], nextchar); else /* +option or -option */ fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), argv[0], argv[optind][0], nextchar); } nextchar = (char *) ""; optind++; optopt = 0; return '?'; } } /* Look at and handle the next short option-character. */ { char c = *nextchar++; char *temp = my_index (optstring, c); /* Increment `optind' when we start to process its last character. */ if (*nextchar == '\0') ++optind; if (temp == NULL || c == ':') { if (print_errors) { if (posixly_correct) /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: illegal option -- %c\n"), argv[0], c); else fprintf (stderr, _("%s: invalid option -- %c\n"), argv[0], c); } optopt = c; return '?'; } /* Convenience. Treat POSIX -W foo same as long option --foo */ if (temp[0] == 'W' && temp[1] == ';') { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = 0; int option_index; /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (print_errors) { /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; return c; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; /* optarg is now the argument, see if it's in the table of longopts. */ for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if ((unsigned int) (nameend - nextchar) == strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (print_errors) fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), argv[0], argv[optind]); nextchar += strlen (nextchar); optind++; return '?'; } if (pfound != NULL) { option_index = indfound; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = nameend + 1; else { if (print_errors) fprintf (stderr, _("\ %s: option `-W %s' doesn't allow an argument\n"), argv[0], pfound->name); nextchar += strlen (nextchar); return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (print_errors) fprintf (stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); nextchar += strlen (nextchar); return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } nextchar = NULL; return 'W'; /* Let the application handle it. */ } if (temp[1] == ':') { if (temp[2] == ':') { /* This is an option that accepts an argument optionally. */ if (*nextchar != '\0') { optarg = nextchar; optind++; } else optarg = NULL; nextchar = NULL; } else { /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (print_errors) { /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; nextchar = NULL; } } return c; } } int getopt (argc, argv, optstring) int argc; char *const *argv; const char *optstring; { return _getopt_internal (argc, argv, optstring, (const struct option *) 0, (int *) 0, 0); } #endif /* Not ELIDE_CODE. */ #ifdef TEST /* Compile with -DTEST to make an executable for use in testing the above definition of `getopt'. */ int main (argc, argv) int argc; char **argv; { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; c = getopt (argc, argv, "abc:d:0123456789"); if (c == -1) break; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value `%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ asymptote-2.37/getopt.h000066400000000000000000000147721265434602500151670ustar00rootroot00000000000000/* Declarations for getopt. Copyright (C) 1989-1994, 1996-1999, 2001 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #ifndef _GETOPT_H #ifndef __need_getopt # define _GETOPT_H 1 #endif /* If __GNU_LIBRARY__ is not already defined, either we are being used standalone, or this is the first header included in the source file. If we are being used with glibc, we need to include , but that does not exist if we are standalone. So: if __GNU_LIBRARY__ is not defined, include , which will pull in for us if it's from glibc. (Why ctype.h? It's guaranteed to exist and it doesn't flood the namespace with stuff the way some other headers do.) */ #if !defined __GNU_LIBRARY__ # include #endif #ifdef __cplusplus extern "C" { #endif /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ extern char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns -1, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ extern int optind; /* Callers store zero here to inhibit the error message `getopt' prints for unrecognized options. */ extern int opterr; /* Set to an option character which was unrecognized. */ extern int optopt; #ifndef __need_getopt /* Describe the long-named options requested by the application. The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector of `struct option' terminated by an element containing a name which is zero. The field `has_arg' is: no_argument (or 0) if the option does not take an argument, required_argument (or 1) if the option requires an argument, optional_argument (or 2) if the option takes an optional argument. If the field `flag' is not NULL, it points to a variable that is set to the value given in the field `val' when the option is found, but left unchanged if the option is not found. To have a long-named option do something other than set an `int' to a compiled-in constant, such as set a value from `optarg', set the option's `flag' field to zero and its `val' field to a nonzero value (the equivalent single-letter option character, if there is one). For long options that have a zero `flag' field, `getopt' returns the contents of the `val' field. */ struct option { # if (defined __STDC__ && __STDC__) || defined __cplusplus const char *name; # else char *name; # endif /* has_arg can't be an enum because some compilers complain about type mismatches in all the code that assumes it is an int. */ int has_arg; int *flag; int val; }; /* Names for the values of the `has_arg' field of `struct option'. */ # define no_argument 0 # define required_argument 1 # define optional_argument 2 #endif /* need getopt */ /* Get definitions and prototypes for functions to process the arguments in ARGV (ARGC of them, minus the program name) for options given in OPTS. Return the option character from OPTS just read. Return -1 when there are no more options. For unrecognized options, or options missing arguments, `optopt' is set to the option letter, and '?' is returned. The OPTS string is a list of characters which are recognized option letters, optionally followed by colons, specifying that that letter takes an argument, to be placed in `optarg'. If a letter in OPTS is followed by two colons, its argument is optional. This behavior is specific to the GNU `getopt'. The argument `--' causes premature termination of argument scanning, explicitly telling `getopt' that there are no more options. If OPTS begins with `--', then non-option arguments are treated as arguments to the option '\0'. This behavior is specific to the GNU `getopt'. */ #if (defined __STDC__ && __STDC__) || defined __cplusplus # ifdef __GNU_LIBRARY__ /* Many other libraries have conflicting prototypes for getopt, with differences in the consts, in stdlib.h. To avoid compilation errors, only prototype getopt for the GNU C library. */ extern int getopt (int __argc, char *const *__argv, const char *__shortopts); # else /* not __GNU_LIBRARY__ */ /* extern int getopt (); */ # endif /* __GNU_LIBRARY__ */ # ifndef __need_getopt extern int getopt_long (int __argc, char *const *__argv, const char *__shortopts, const struct option *__longopts, int *__longind); extern int getopt_long_only (int __argc, char *const *__argv, const char *__shortopts, const struct option *__longopts, int *__longind); /* Internal only. Users should not call this directly. */ extern int _getopt_internal (int __argc, char *const *__argv, const char *__shortopts, const struct option *__longopts, int *__longind, int __long_only); # endif #else /* not __STDC__ */ extern int getopt (); # ifndef __need_getopt extern int getopt_long (); extern int getopt_long_only (); extern int _getopt_internal (); # endif #endif /* __STDC__ */ #ifdef __cplusplus } #endif /* Make sure we later can get all the definitions and declarations. */ #undef __need_getopt #endif /* getopt.h */ asymptote-2.37/getopt1.c000066400000000000000000000106501265434602500152320ustar00rootroot00000000000000/* getopt_long and getopt_long_only entry points for GNU getopt. Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #ifdef HAVE_CONFIG_H #include #endif #include "getopt.h" #if !defined __STDC__ || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ #ifndef const #define const #endif #endif #include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #define GETOPT_INTERFACE_VERSION 2 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 #include #if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION #define ELIDE_CODE #endif #endif #ifndef ELIDE_CODE /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ #include #endif #ifndef NULL #define NULL 0 #endif int getopt_long (argc, argv, options, long_options, opt_index) int argc; char *const *argv; const char *options; const struct option *long_options; int *opt_index; { return _getopt_internal (argc, argv, options, long_options, opt_index, 0); } /* Like getopt_long, but '-' as well as '--' can indicate a long option. If an option that starts with '-' (not '--') doesn't match a long option, but does match a short option, it is parsed as a short option instead. */ int getopt_long_only (argc, argv, options, long_options, opt_index) int argc; char *const *argv; const char *options; const struct option *long_options; int *opt_index; { return _getopt_internal (argc, argv, options, long_options, opt_index, 1); } #endif /* Not ELIDE_CODE. */ #ifdef TEST #include int main (argc, argv) int argc; char **argv; { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; int option_index = 0; static struct option long_options[] = { {"add", 1, 0, 0}, {"append", 0, 0, 0}, {"delete", 1, 0, 0}, {"verbose", 0, 0, 0}, {"create", 0, 0, 0}, {"file", 1, 0, 0}, {0, 0, 0, 0} }; c = getopt_long (argc, argv, "abc:d:0123456789", long_options, &option_index); if (c == -1) break; switch (c) { case 0: printf ("option %s", long_options[option_index].name); if (optarg) printf (" with arg %s", optarg); printf ("\n"); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value `%s'\n", optarg); break; case 'd': printf ("option d with value `%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ asymptote-2.37/glrender.cc000066400000000000000000001076511265434602500156240ustar00rootroot00000000000000/***** * glrender.cc * John Bowman and Orest Shardt * Render 3D Bezier paths and surfaces. *****/ #include #include #include #include #include "common.h" #ifdef HAVE_GL #ifdef HAVE_LIBGLUT #ifdef __MSDOS__ #ifndef FGAPI #define FGAPI GLUTAPI #endif #ifndef FGAPIENTRY #define FGAPIENTRY APIENTRY #endif #endif #define GLUT_BUILDING_LIB #endif // HAVE_LIBGLUT #include "picture.h" #include "arcball.h" #include "bbox3.h" #include "drawimage.h" #include "interact.h" #include "tr.h" #ifdef HAVE_LIBGLUT #ifdef FREEGLUT #include #endif #endif namespace camp { billboard BB; } namespace gl { bool glthread=false; bool initialize=true; using camp::picture; using camp::drawRawImage; using camp::transform; using camp::pair; using camp::triple; using vm::array; using vm::read; using camp::bbox3; using settings::getSetting; using settings::Setting; bool Iconify=false; bool Menu; bool Motion; bool ignorezoom; int Fitscreen; bool queueExport=false; bool readyAfterExport=false; #ifdef HAVE_LIBGLUT timeval lasttime; timeval lastframetime; int oldWidth,oldHeight; bool Xspin,Yspin,Zspin; bool Animate; bool Step; bool queueScreen=false; int x0,y0; string Action; int MenuButton; double lastangle; Arcball arcball; int window; #endif double Aspect; bool View; int Oldpid; string Prefix; const picture* Picture; string Format; int Width,Height; int fullWidth,fullHeight; double oWidth,oHeight; int screenWidth,screenHeight; int maxWidth; int maxHeight; int maxTileWidth; int maxTileHeight; double T[16]; int Mode; double Angle; bool orthographic; double H; double xmin,xmax; double ymin,ymax; double zmin,zmax; double Xmin,Xmax; double Ymin,Ymax; pair Shift; double X,Y; double cx,cy; double Xfactor,Yfactor; static const double pi=acos(-1.0); static const double degrees=180.0/pi; static const double radians=1.0/degrees; double Background[4]; size_t Nlights; triple *Lights; double *Diffuse; double *Ambient; double *Specular; bool ViewportLighting; bool antialias; double Zoom; double Zoom0; double lastzoom; GLfloat Rotate[16]; GLUnurbs *nurb=NULL; void *glrenderWrapper(void *a); #ifdef HAVE_LIBOSMESA OSMesaContext ctx; unsigned char *osmesa_buffer; #endif #ifdef HAVE_PTHREAD pthread_t mainthread; pthread_cond_t initSignal=PTHREAD_COND_INITIALIZER; pthread_mutex_t initLock=PTHREAD_MUTEX_INITIALIZER; pthread_cond_t readySignal=PTHREAD_COND_INITIALIZER; pthread_mutex_t readyLock=PTHREAD_MUTEX_INITIALIZER; void endwait(pthread_cond_t& signal, pthread_mutex_t& lock) { pthread_mutex_lock(&lock); pthread_cond_signal(&signal); pthread_mutex_unlock(&lock); } void wait(pthread_cond_t& signal, pthread_mutex_t& lock) { pthread_mutex_lock(&lock); pthread_cond_signal(&signal); pthread_cond_wait(&signal,&lock); pthread_mutex_unlock(&lock); } #endif template inline T min(T a, T b) { return (a < b) ? a : b; } template inline T max(T a, T b) { return (a > b) ? a : b; } void lighting() { for(size_t i=0; i < Nlights; ++i) { GLenum index=GL_LIGHT0+i; triple Lighti=Lights[i]; GLfloat position[]={(GLfloat) Lighti.getx(),(GLfloat) Lighti.gety(), (GLfloat) Lighti.getz(),0.0}; glLightfv(index,GL_POSITION,position); } } void initlighting() { glClearColor(Background[0],Background[1],Background[2],Background[3]); glEnable(GL_LIGHTING); glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,getSetting("twosided")); for(size_t i=0; i < Nlights; ++i) { GLenum index=GL_LIGHT0+i; glEnable(index); size_t i4=4*i; GLfloat diffuse[]={(GLfloat) Diffuse[i4],(GLfloat) Diffuse[i4+1], (GLfloat) Diffuse[i4+2],(GLfloat) Diffuse[i4+3]}; glLightfv(index,GL_DIFFUSE,diffuse); GLfloat ambient[]={(GLfloat) Ambient[i4],(GLfloat) Ambient[i4+1], (GLfloat) Ambient[i4+2],(GLfloat) Ambient[i4+3]}; glLightfv(index,GL_AMBIENT,ambient); GLfloat specular[]={(GLfloat) Specular[i4],(GLfloat) Specular[i4+1], (GLfloat) Specular[i4+2],(GLfloat) Specular[i4+3]}; glLightfv(index,GL_SPECULAR,specular); } static size_t lastNlights=0; for(size_t i=Nlights; i < lastNlights; ++i) { GLenum index=GL_LIGHT0+i; glDisable(index); } lastNlights=Nlights; if(ViewportLighting) lighting(); } void setDimensions(int Width, int Height, double X, double Y) { double Aspect=((double) Width)/Height; double xshift=X/Width*lastzoom+Shift.getx()*Xfactor; double yshift=Y/Height*lastzoom+Shift.gety()*Yfactor; double Zoominv=1.0/lastzoom; if(orthographic) { double xsize=Xmax-Xmin; double ysize=Ymax-Ymin; if(xsize < ysize*Aspect) { double r=0.5*ysize*Aspect*Zoominv; double X0=2.0*r*xshift; double Y0=(Ymax-Ymin)*Zoominv*yshift; xmin=-r-X0; xmax=r-X0; ymin=Ymin*Zoominv-Y0; ymax=Ymax*Zoominv-Y0; } else { double r=0.5*xsize/(Aspect*Zoom); double X0=(Xmax-Xmin)*Zoominv*xshift; double Y0=2.0*r*yshift; xmin=Xmin*Zoominv-X0; xmax=Xmax*Zoominv-X0; ymin=-r-Y0; ymax=r-Y0; } } else { double r=H*Zoominv; double rAspect=r*Aspect; double X0=2.0*rAspect*xshift; double Y0=2.0*r*yshift; xmin=-rAspect-X0; xmax=rAspect-X0; ymin=-r-Y0; ymax=r-Y0; } } void setProjection() { glMatrixMode(GL_PROJECTION); glLoadIdentity(); setDimensions(Width,Height,X,Y); if(orthographic) glOrtho(xmin,xmax,ymin,ymax,-zmax,-zmin); else glFrustum(xmin,xmax,ymin,ymax,-zmax,-zmin); glMatrixMode(GL_MODELVIEW); #ifdef HAVE_LIBGLUT double arcballRadius=getSetting("arcballradius"); arcball.set_params(vec2(0.5*Width,0.5*Height),arcballRadius*Zoom); #endif } void drawscene(double Width, double Height) { #ifdef HAVE_PTHREAD static bool first=true; if(glthread && first && !getSetting("offscreen")) { wait(initSignal,initLock); endwait(initSignal,initLock); first=false; } #endif glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if(!ViewportLighting) lighting(); triple m(xmin,ymin,zmin); triple M(xmax,ymax,zmax); double perspective=orthographic ? 0.0 : 1.0/zmax; double size2=hypot(Width,Height); // Render opaque objects Picture->render(nurb,size2,m,M,perspective,Nlights,false); // Enable transparency glDepthMask(GL_FALSE); // Render transparent objects Picture->render(nurb,size2,m,M,perspective,Nlights,true); glDepthMask(GL_TRUE); } // Return x divided by y rounded up to the nearest integer. int Quotient(int x, int y) { return (x+y-1)/y; } void Export() { glReadBuffer(GL_BACK_LEFT); glPixelStorei(GL_PACK_ALIGNMENT,1); glFinish(); try { size_t ndata=3*fullWidth*fullHeight; unsigned char *data=new unsigned char[ndata]; if(data) { TRcontext *tr=trNew(); int width=Quotient(fullWidth,Quotient(fullWidth,min(maxTileWidth,Width))); int height=Quotient(fullHeight,Quotient(fullHeight, min(maxTileHeight,Height))); if(settings::verbose > 1) cout << "Exporting " << Prefix << " as " << fullWidth << "x" << fullHeight << " image" << " using tiles of size " << width << "x" << height << endl; trTileSize(tr,width,height,0); trImageSize(tr,fullWidth,fullHeight); trImageBuffer(tr,GL_RGB,GL_UNSIGNED_BYTE,data); setDimensions(fullWidth,fullHeight,X/Width*fullWidth,Y/Width*fullWidth); (orthographic ? trOrtho : trFrustum)(tr,xmin,xmax,ymin,ymax,-zmax,-zmin); size_t count=0; do { trBeginTile(tr); drawscene(fullWidth,fullHeight); ++count; } while (trEndTile(tr)); if(settings::verbose > 1) cout << count << " tile" << (count != 1 ? "s" : "") << " drawn" << endl; trDelete(tr); picture pic; double w=oWidth; double h=oHeight; double Aspect=((double) fullWidth)/fullHeight; if(w > h*Aspect) w=(int) (h*Aspect+0.5); else h=(int) (w/Aspect+0.5); // Render an antialiased image. drawRawImage *Image=new drawRawImage(data,fullWidth,fullHeight, transform(0.0,0.0,w,0.0,0.0,h), antialias); pic.append(Image); pic.shipout(NULL,Prefix,Format,0.0,false,View); delete Image; delete[] data; } } catch(handled_error) { } catch(std::bad_alloc&) { outOfMemory(); } setProjection(); bool offscreen=getSetting("offscreen"); #ifdef HAVE_LIBGLUT if(!offscreen) glutPostRedisplay(); #endif #ifdef HAVE_PTHREAD if(glthread && readyAfterExport && !offscreen) { readyAfterExport=false; endwait(readySignal,readyLock); } #endif } #ifdef HAVE_LIBGLUT void idle() { glutIdleFunc(NULL); Xspin=Yspin=Zspin=Animate=Step=false; } #endif void home() { X=Y=cx=cy=0.0; #ifdef HAVE_LIBGLUT if(!getSetting("offscreen")) { idle(); arcball.init(); } #endif glLoadIdentity(); glGetFloatv(GL_MODELVIEW_MATRIX,Rotate); lastzoom=Zoom=Zoom0; setDimensions(Width,Height,0,0); initlighting(); } void nodisplay() { } void quit() { #ifdef HAVE_LIBOSMESA if(getSetting("offscreen")) { if(osmesa_buffer) delete[] osmesa_buffer; if(ctx) OSMesaDestroyContext(ctx); exit(0); } #endif #ifdef HAVE_LIBGLUT if(glthread) { bool animating=getSetting("animating"); if(animating) Setting("interrupt")=true; home(); Animate=getSetting("autoplay"); #ifdef HAVE_PTHREAD if(!interact::interactive || animating) { idle(); glutDisplayFunc(nodisplay); endwait(readySignal,readyLock); } #endif if(interact::interactive) glutHideWindow(); } else { glutDestroyWindow(window); exit(0); } #endif } void mode() { switch(Mode) { case 0: for(size_t i=0; i < Nlights; ++i) glEnable(GL_LIGHT0+i); glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); gluNurbsProperty(nurb,GLU_DISPLAY_MODE,GLU_FILL); ++Mode; break; case 1: for(size_t i=0; i < Nlights; ++i) glDisable(GL_LIGHT0+i); glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); gluNurbsProperty(nurb,GLU_DISPLAY_MODE,GLU_OUTLINE_PATCH); ++Mode; break; case 2: gluNurbsProperty(nurb,GLU_DISPLAY_MODE,GLU_OUTLINE_POLYGON); Mode=0; break; } #ifdef HAVE_LIBGLUT if(!getSetting("offscreen")) glutPostRedisplay(); #endif } // GUI-related functions #ifdef HAVE_LIBGLUT bool capsize(int& width, int& height) { bool resize=false; if(width > maxWidth) { width=maxWidth; resize=true; } if(height > maxHeight) { height=maxHeight; resize=true; } return resize; } void reshape0(int width, int height) { X=(X/Width)*width; Y=(Y/Height)*height; Width=width; Height=height; setProjection(); glViewport(0,0,Width,Height); } void windowposition(int& x, int& y, int width=Width, int height=Height) { pair z=getSetting("position"); x=(int) z.getx(); y=(int) z.gety(); if(x < 0) { x += screenWidth-width; if(x < 0) x=0; } if(y < 0) { y += screenHeight-height; if(y < 0) y=0; } } void setsize(int w, int h, bool reposition=true) { int x,y; capsize(w,h); if(reposition) { windowposition(x,y,w,h); glutPositionWindow(x,y); } glutReshapeWindow(w,h); reshape0(w,h); glutPostRedisplay(); } void fullscreen(bool reposition=true) { Width=screenWidth; Height=screenHeight; reshape0(Width,Height); #ifdef __MSDOS__ glutFullScreen(); #else if(reposition) glutPositionWindow(0,0); glutReshapeWindow(Width,Height); glutPostRedisplay(); #endif } void fitscreen(bool reposition=true) { if(Animate && Fitscreen == 2) Fitscreen=0; switch(Fitscreen) { case 0: // Original size { Xfactor=Yfactor=1.0; setsize(oldWidth,oldHeight,reposition); break; } case 1: // Fit to screen in one dimension { oldWidth=Width; oldHeight=Height; int w=screenWidth; int h=screenHeight; if(w >= h*Aspect) w=(int) (h*Aspect+0.5); else h=(int) (w/Aspect+0.5); setsize(w,h,reposition); break; } case 2: // Full screen { Xfactor=((double) screenHeight)/Height; Yfactor=((double) screenWidth)/Width; fullscreen(reposition); break; } } } void togglefitscreen() { ++Fitscreen; if(Fitscreen > 2) Fitscreen=0; fitscreen(); } void initTimer() { gettimeofday(&lasttime,NULL); gettimeofday(&lastframetime,NULL); } void idleFunc(void (*f)()) { initTimer(); glutIdleFunc(f); } void screen() { if(glthread && !interact::interactive) fitscreen(false); } void nextframe(int) { #ifdef HAVE_PTHREAD endwait(readySignal,readyLock); #endif double framedelay=getSetting("framedelay"); if(framedelay > 0) usleep((unsigned int) (1000.0*framedelay+0.5)); if(Step) Animate=false; } void display() { if(queueScreen) { if(!Animate) screen(); queueScreen=false; } drawscene(Width,Height); glutSwapBuffers(); #ifdef HAVE_PTHREAD if(glthread && Animate) { queueExport=false; double delay=1.0/getSetting("framerate"); timeval tv; gettimeofday(&tv,NULL); double seconds=tv.tv_sec-lastframetime.tv_sec+ ((double) tv.tv_usec-lastframetime.tv_usec)/1000000.0; lastframetime=tv; double milliseconds=1000.0*(delay-seconds); double framedelay=getSetting("framedelay"); if(framedelay > 0) milliseconds -= framedelay; if(milliseconds > 0) glutTimerFunc((int) (milliseconds+0.5),nextframe,0); else nextframe(0); } #endif if(queueExport) { Export(); queueExport=false; } if(!glthread) { if(Oldpid != 0 && waitpid(Oldpid,NULL,WNOHANG) != Oldpid) { kill(Oldpid,SIGHUP); Oldpid=0; } } } void update() { glutDisplayFunc(display); Animate=getSetting("autoplay"); glutShowWindow(); lastzoom=Zoom; glLoadIdentity(); double cz=0.5*(zmin+zmax); glTranslatef(cx,cy,cz); glMultMatrixf(Rotate); glTranslatef(0,0,-cz); setProjection(); glutPostRedisplay(); } void updateHandler(int) { queueScreen=true; update(); if(interact::interactive || !Animate) { glutShowWindow(); } } void animate() { Animate=!Animate; if(Animate) { if(Fitscreen == 2) { togglefitscreen(); togglefitscreen(); } update(); } } void reshape(int width, int height) { if(glthread) { static bool initialize=true; if(initialize) { initialize=false; Signal(SIGUSR1,updateHandler); } } if(capsize(width,height)) glutReshapeWindow(width,height); reshape0(width,height); } void shift(int x, int y) { if(x > 0 && y > 0) { double Zoominv=1.0/Zoom; X += (x-x0)*Zoominv; Y += (y0-y)*Zoominv; x0=x; y0=y; update(); } } void pan(int x, int y) { if(x > 0 && y > 0) { if(orthographic) { double Zoominv=1.0/Zoom; X += (x-x0)*Zoominv; Y += (y0-y)*Zoominv; } else { cx += (x-x0)*(xmax-xmin)/Width; cy += (y0-y)*(ymax-ymin)/Height; } x0=x; y0=y; update(); } } void capzoom() { static double maxzoom=sqrt(DBL_MAX); static double minzoom=1/maxzoom; if(Zoom <= minzoom) Zoom=minzoom; if(Zoom >= maxzoom) Zoom=maxzoom; } int menustatus=GLUT_MENU_NOT_IN_USE; void menuStatus(int status, int x, int y) { menustatus=status; } void disableMenu() { Menu=false; if(menustatus == GLUT_MENU_NOT_IN_USE) glutDetachMenu(MenuButton); } void zoom(int x, int y) { if(ignorezoom) {ignorezoom=false; y0=y; return;} if(x > 0 && y > 0) { if(Menu) { disableMenu(); y0=y; return; } Motion=true; double zoomFactor=getSetting("zoomfactor"); if(zoomFactor > 0.0) { double zoomStep=getSetting("zoomstep"); const double limit=log(0.1*DBL_MAX)/log(zoomFactor); double s=zoomStep*(y0-y); if(fabs(s) < limit) { Zoom *= pow(zoomFactor,s); capzoom(); lastzoom=Zoom; y0=y; setProjection(); glutPostRedisplay(); } } } } void mousewheel(int wheel, int direction, int x, int y) { double zoomFactor=getSetting("zoomfactor"); if(zoomFactor > 0.0) { if(direction > 0) Zoom *= zoomFactor; else Zoom /= zoomFactor; capzoom(); lastzoom=Zoom; setProjection(); glutPostRedisplay(); } } void rotate(int x, int y) { if(x > 0 && y > 0) { if(Menu) { disableMenu(); arcball.mouse_down(x,Height-y); return; } Motion=true; arcball.mouse_motion(x,Height-y,0, Action == "rotateX", // X rotation only Action == "rotateY"); // Y rotation only for(int i=0; i < 4; ++i) { const vec4& roti=arcball.rot[i]; int i4=4*i; for(int j=0; j < 4; ++j) Rotate[i4+j]=roti[j]; } update(); } } double Degrees(int x, int y) { return atan2(0.5*Height-y-Y,x-0.5*Width-X)*degrees; } void updateArcball() { for(int i=0; i < 4; ++i) { int i4=4*i; vec4& roti=arcball.rot[i]; for(int j=0; j < 4; ++j) roti[j]=Rotate[i4+j]; } update(); } void rotateX(double step) { glLoadIdentity(); glRotatef(step,1,0,0); glMultMatrixf(Rotate); glGetFloatv(GL_MODELVIEW_MATRIX,Rotate); updateArcball(); } void rotateY(double step) { glLoadIdentity(); glRotatef(step,0,1,0); glMultMatrixf(Rotate); glGetFloatv(GL_MODELVIEW_MATRIX,Rotate); updateArcball(); } void rotateZ(double step) { glLoadIdentity(); glRotatef(step,0,0,1); glMultMatrixf(Rotate); glGetFloatv(GL_MODELVIEW_MATRIX,Rotate); updateArcball(); } void rotateZ(int x, int y) { if(x > 0 && y > 0) { if(Menu) { disableMenu(); return; } Motion=true; double angle=Degrees(x,y); rotateZ(angle-lastangle); lastangle=angle; } } #ifndef GLUT_WHEEL_UP #define GLUT_WHEEL_UP 3 #endif #ifndef GLUT_WHEEL_DOWN #define GLUT_WHEEL_DOWN 4 #endif string action(int button, int mod) { size_t Button; size_t nButtons=5; switch(button) { case GLUT_LEFT_BUTTON: Button=0; break; case GLUT_MIDDLE_BUTTON: Button=1; break; case GLUT_RIGHT_BUTTON: Button=2; break; case GLUT_WHEEL_UP: Button=3; break; case GLUT_WHEEL_DOWN: Button=4; break; default: Button=nButtons; } size_t Mod; size_t nMods=4; switch(mod) { case 0: Mod=0; break; case GLUT_ACTIVE_SHIFT: Mod=1; break; case GLUT_ACTIVE_CTRL: Mod=2; break; case GLUT_ACTIVE_ALT: Mod=3; break; default: Mod=nMods; } if(Button < nButtons) { array *left=getSetting("leftbutton"); array *middle=getSetting("middlebutton"); array *right=getSetting("rightbutton"); array *wheelup=getSetting("wheelup"); array *wheeldown=getSetting("wheeldown"); array *Buttons[]={left,middle,right,wheelup,wheeldown}; array *a=Buttons[button]; size_t size=checkArray(a); if(Mod < size) return read(a,Mod); } return ""; } void timeout(int) { if(Menu) disableMenu(); } void mouse(int button, int state, int x, int y) { int mod=glutGetModifiers(); string Action=action(button,mod); if(!Menu) { if(mod == 0 && state == GLUT_UP && !Motion && Action == "zoom/menu") { MenuButton=button; glutMotionFunc(NULL); glutTimerFunc(getSetting("doubleclick"),timeout,0); glutAttachMenu(button); Menu=true; return; } else Motion=false; } disableMenu(); if(Action == "zoomin") { glutMotionFunc(NULL); mousewheel(0,1,x,y); return; } if(Action == "zoomout") { glutMotionFunc(NULL); mousewheel(0,-1,x,y); return; } if(state == GLUT_DOWN) { if(Action == "rotate" || Action == "rotateX" || Action == "rotateY") { arcball.mouse_down(x,Height-y); glutMotionFunc(rotate); } else if(Action == "shift") { x0=x; y0=y; glutMotionFunc(shift); } else if(Action == "pan") { x0=x; y0=y; glutMotionFunc(pan); } else if(Action == "zoom" || Action == "zoom/menu") { y0=y; glutMotionFunc(zoom); } else if(Action == "rotateZ") { lastangle=Degrees(x,y); glutMotionFunc(rotateZ); } } else { arcball.mouse_up(); glutMotionFunc(NULL); } } double spinstep() { timeval tv; gettimeofday(&tv,NULL); double step=getSetting("spinstep")* (tv.tv_sec-lasttime.tv_sec+ ((double) tv.tv_usec-lasttime.tv_usec)/1000000.0); lasttime=tv; return step; } void xspin() { rotateX(spinstep()); } void yspin() { rotateY(spinstep()); } void zspin() { rotateZ(spinstep()); } void expand() { double resizeStep=getSetting("resizestep"); if(resizeStep > 0.0) setsize((int) (Width*resizeStep+0.5),(int) (Height*resizeStep+0.5)); } void shrink() { double resizeStep=getSetting("resizestep"); if(resizeStep > 0.0) setsize(max((int) (Width/resizeStep+0.5),1), max((int) (Height/resizeStep+0.5),1)); } void spinx() { if(Xspin) idle(); else { idleFunc(xspin); Xspin=true; Yspin=Zspin=false; } } void spiny() { if(Yspin) idle(); else { idleFunc(yspin); Yspin=true; Xspin=Zspin=false; } } void spinz() { if(Zspin) idle(); else { idleFunc(zspin); Zspin=true; Xspin=Yspin=false; } } void write(const char *text, const double *v) { cout << text << "=(" << v[0] << "," << v[1] << "," << v[2] << ")"; } void showCamera() { projection P=camera(); cout << endl << "currentprojection=" << (P.orthographic ? "orthographic(" : "perspective(") << endl << "camera=" << P.camera << "," << endl << "up=" << P.up << "," << endl << "target=" << P.target << "," << endl << "zoom=" << P.zoom; if(!orthographic) cout << "," << endl << "angle=" << P.angle; if(P.viewportshift != pair(0.0,0.0)) cout << "," << endl << "viewportshift=" << P.viewportshift; if(!orthographic) cout << "," << endl << "autoadjust=false"; cout << ");" << endl; } void keyboard(unsigned char key, int x, int y) { switch(key) { case 'h': home(); update(); break; case 'f': togglefitscreen(); break; case 'x': spinx(); break; case 'y': spiny(); break; case 'z': spinz(); break; case 's': idle(); break; case 'm': mode(); break; case 'e': Export(); break; case 'c': showCamera(); break; case '+': case '=': case '>': expand(); break; case '-': case '_': case '<': shrink(); break; case 'p': if(getSetting("reverse")) Animate=false; Setting("reverse")=Step=false; animate(); break; case 'r': if(!getSetting("reverse")) Animate=false; Setting("reverse")=true; Step=false; animate(); break; case ' ': Step=true; animate(); break; case 17: // Ctrl-q case 'q': if(!Format.empty()) Export(); quit(); break; } } enum Menu {HOME,FITSCREEN,XSPIN,YSPIN,ZSPIN,STOP,MODE,EXPORT,CAMERA, PLAY,STEP,REVERSE,QUIT}; void menu(int choice) { if(Menu) disableMenu(); ignorezoom=true; Motion=true; switch (choice) { case HOME: // Home home(); update(); break; case FITSCREEN: togglefitscreen(); break; case XSPIN: spinx(); break; case YSPIN: spiny(); break; case ZSPIN: spinz(); break; case STOP: idle(); break; case MODE: mode(); break; case EXPORT: queueExport=true; break; case CAMERA: showCamera(); break; case PLAY: if(getSetting("reverse")) Animate=false; Setting("reverse")=Step=false; animate(); break; case REVERSE: if(!getSetting("reverse")) Animate=false; Setting("reverse")=true; Step=false; animate(); break; case STEP: Step=true; animate(); break; case QUIT: quit(); break; } } void setosize() { oldWidth=(int) ceil(oWidth); oldHeight=(int) ceil(oHeight); } #endif // end of GUI-related functions void exportHandler(int=0) { #ifdef HAVE_LIBGLUT bool offscreen=getSetting("offscreen"); if(!Iconify && !offscreen) glutShowWindow(); #endif readyAfterExport=true; Export(); #ifdef HAVE_LIBGLUT if(!Iconify && !offscreen) glutHideWindow(); #endif glutDisplayFunc(nodisplay); } static bool glinitialize=true; projection camera(bool user) { if(glinitialize) return projection(); camp::Triple vCamera,vUp,vTarget; double cz=0.5*(zmin+zmax); if(user) { for(int i=0; i < 3; ++i) { double sumCamera=0.0, sumTarget=0.0, sumUp=0.0; int i4=4*i; for(int j=0; j < 4; ++j) { int j4=4*j; double R0=Rotate[j4]; double R1=Rotate[j4+1]; double R2=Rotate[j4+2]; double R3=Rotate[j4+3]; double T4ij=T[i4+j]; sumCamera += T4ij*(R3-cx*R0-cy*R1-cz*R2); sumUp += T4ij*R1; sumTarget += T4ij*(R3-cx*R0-cy*R1); } vCamera[i]=sumCamera; vUp[i]=sumUp; vTarget[i]=sumTarget; } } else { for(int i=0; i < 3; ++i) { int i4=4*i; double R0=Rotate[i4]; double R1=Rotate[i4+1]; double R2=Rotate[i4+2]; double R3=Rotate[i4+3]; vCamera[i]=R3-cx*R0-cy*R1-cz*R2; vUp[i]=R1; vTarget[i]=R3-cx*R0-cy*R1; } } return projection(orthographic,vCamera,vUp,vTarget,Zoom, 2.0*atan(tan(0.5*Angle)/Zoom)/radians, pair(X/Width*lastzoom+Shift.getx(), Y/Height*lastzoom+Shift.gety())); } void init() { #ifdef HAVE_LIBGLUT mem::vector cmd; cmd.push_back(settings::argv0); if(!interact::interactive && Iconify) cmd.push_back("-iconic"); push_split(cmd,getSetting("glOptions")); char **argv=args(cmd,true); int argc=cmd.size(); glutInit(&argc,argv); screenWidth=glutGet(GLUT_SCREEN_WIDTH); screenHeight=glutGet(GLUT_SCREEN_HEIGHT); #endif } void init_osmesa() { #ifdef HAVE_LIBOSMESA // create context and buffer if(settings::verbose > 1) cout << "Allocating osmesa_buffer of size " << screenWidth << "x" << screenHeight << "x4x" << sizeof(GLubyte) << endl; osmesa_buffer=new unsigned char[screenWidth*screenHeight*4*sizeof(GLubyte)]; if(!osmesa_buffer) { cerr << "Cannot allocate image buffer." << endl; exit(-1); } ctx = OSMesaCreateContextExt(OSMESA_RGBA,16,0,0,NULL); if(!ctx) { cerr << "OSMesaCreateContext failed." << endl; exit(-1); } if(!OSMesaMakeCurrent(ctx,osmesa_buffer,GL_UNSIGNED_BYTE, screenWidth,screenHeight )) { cerr << "OSMesaMakeCurrent failed." << endl; exit(-1); } int z=0, s=0, a=0; glGetIntegerv(GL_DEPTH_BITS,&z); glGetIntegerv(GL_STENCIL_BITS,&s); glGetIntegerv(GL_ACCUM_RED_BITS,&a); if(settings::verbose > 1) cout << "Offscreen context settings: Depth=" << z << " Stencil=" << s << " Accum=" << a << endl; if(z <= 0) { cerr << "Error initializing offscreen context: Depth=" << z << endl; exit(-1); } #endif // HAVE_LIBOSMESA } // angle=0 means orthographic. void glrender(const string& prefix, const picture *pic, const string& format, double width, double height, double angle, double zoom, const triple& m, const triple& M, const pair& shift, double *t, double *background, size_t nlights, triple *lights, double *diffuse, double *ambient, double *specular, bool Viewportlighting, bool view, int oldpid) { bool offscreen=getSetting("offscreen"); #ifndef __MSDOS__ Iconify=getSetting("iconify"); #endif #ifdef HAVE_PTHREAD static bool initializedView=false; #endif width=max(width,1.0); height=max(height,1.0); if(zoom == 0.0) zoom=1.0; Prefix=prefix; Picture=pic; Format=format; for(int i=0; i < 16; ++i) T[i]=t[i]; for(int i=0; i < 4; ++i) Background[i]=background[i]; Nlights=min(nlights,(size_t) GL_MAX_LIGHTS); Lights=lights; Diffuse=diffuse; Ambient=ambient; Specular=specular; ViewportLighting=Viewportlighting; View=view; Angle=angle*radians; Zoom0=zoom; Oldpid=oldpid; Shift=shift; Xmin=m.getx(); Xmax=M.getx(); Ymin=m.gety(); Ymax=M.gety(); zmin=m.getz(); zmax=M.getz(); orthographic=Angle == 0.0; H=orthographic ? 0.0 : -tan(0.5*Angle)*zmax; Menu=false; Motion=true; ignorezoom=false; Mode=0; Xfactor=Yfactor=1.0; pair maxtile=getSetting("maxtile"); maxTileWidth=(int) maxtile.getx(); maxTileHeight=(int) maxtile.gety(); if(maxTileWidth <= 0) maxTileWidth=1024; if(maxTileHeight <= 0) maxTileHeight=768; if(offscreen) { screenWidth=maxTileWidth; screenHeight=maxTileHeight; static bool osmesa_initialized=false; if(!osmesa_initialized) { osmesa_initialized=true; init_osmesa(); } } else { if(glinitialize) { glinitialize=false; init(); Fitscreen=1; } } static bool initialized=false; if(!initialized || !interact::interactive) { antialias=getSetting("antialias") > 1; double expand=getSetting("render"); if(expand < 0) expand *= (Format.empty() || Format == "eps" || Format == "pdf") ? -2.0 : -1.0; if(antialias) expand *= 2.0; // Force a hard viewport limit to work around direct rendering bugs. // Alternatively, one can use -glOptions=-indirect (with a performance // penalty). pair maxViewport=getSetting("maxviewport"); maxWidth=(int) ceil(maxViewport.getx()); maxHeight=(int) ceil(maxViewport.gety()); if(maxWidth <= 0) maxWidth=max(maxHeight,2); if(maxHeight <= 0) maxHeight=max(maxWidth,2); if(screenWidth <= 0) screenWidth=maxWidth; else screenWidth=min(screenWidth,maxWidth); if(screenHeight <= 0) screenHeight=maxHeight; else screenHeight=min(screenHeight,maxHeight); oWidth=width; oHeight=height; Aspect=width/height; fullWidth=(int) ceil(expand*width); fullHeight=(int) ceil(expand*height); Width=min(fullWidth,screenWidth); Height=min(fullHeight,screenHeight); if(Width > Height*Aspect) Width=min((int) (ceil(Height*Aspect)),screenWidth); else Height=min((int) (ceil(Width/Aspect)),screenHeight); Aspect=((double) Width)/Height; if(maxTileWidth <= 0) maxTileWidth=screenWidth; if(maxTileHeight <= 0) maxTileHeight=screenHeight; #ifdef HAVE_LIBGLUT setosize(); #endif if(View && settings::verbose > 1) cout << "Rendering " << stripDir(prefix) << " as " << Width << "x" << Height << " image" << endl; } bool havewindow=initialized && glthread && !offscreen; #ifdef HAVE_LIBGLUT unsigned int displaymode=GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH; int buttons[]={GLUT_LEFT_BUTTON,GLUT_MIDDLE_BUTTON,GLUT_RIGHT_BUTTON}; string buttonnames[]={"left","middle","right"}; size_t nbuttons=sizeof(buttons)/sizeof(int); #endif #ifdef HAVE_PTHREAD if(glthread && initializedView && !offscreen) { if(!View) readyAfterExport=queueExport=true; pthread_kill(mainthread,SIGUSR1); return; } #endif #ifdef HAVE_LIBGLUT if(!offscreen) { if(View) { int x,y; if(havewindow) glutDestroyWindow(window); windowposition(x,y); glutInitWindowPosition(x,y); glutInitWindowSize(1,1); Int multisample=getSetting("multisample"); if(multisample <= 1) multisample=0; if(multisample) displaymode |= GLUT_MULTISAMPLE; glutInitDisplayMode(displaymode); ostringstream buf; int samples; #ifdef FREEGLUT #ifdef GLUT_INIT_MAJOR_VERSION while(true) { if(multisample > 0) glutSetOption(GLUT_MULTISAMPLE,multisample); #endif #endif string title=string(settings::PROGRAM)+": "+prefix; string suffix; for(size_t i=0; i < nbuttons; ++i) { int button=buttons[i]; if(action(button,0) == "zoom/menu") { suffix="Double click "+buttonnames[i]+" button for menu"; break; } } if(suffix.empty()) { for(size_t i=0; i < nbuttons; ++i) { int button=buttons[i]; if(action(button,0) == "menu") { suffix="Click "+buttonnames[i]+" button for menu"; break; } } } title += " ["+suffix+"]"; window=glutCreateWindow(title.c_str()); GLint samplebuf[1]; glGetIntegerv(GL_SAMPLES,samplebuf); samples=samplebuf[0]; #ifdef FREEGLUT #ifdef GLUT_INIT_MAJOR_VERSION if(samples < multisample) { --multisample; if(multisample > 1) { glutDestroyWindow(window); continue; } } break; } #endif #endif if(samples > 1) { if(settings::verbose > 1 && samples > 1) cout << "Multisampling enabled with sample width " << samples << endl; } glutDisplayFunc(display); glutShowWindow(); } else if(!havewindow) { glutInitWindowSize(maxTileWidth,maxTileHeight); glutInitDisplayMode(displaymode); window=glutCreateWindow(""); glutHideWindow(); } } #endif // HAVE_LIBGLUT initialized=true; glMatrixMode(GL_MODELVIEW); home(); #ifdef HAVE_LIBGLUT if(!offscreen) { Animate=getSetting("autoplay"); if(View) { if(!getSetting("fitscreen")) Fitscreen=0; fitscreen(); setosize(); } } #endif glEnable(GL_BLEND); glEnable(GL_DEPTH_TEST); glEnable(GL_MAP1_VERTEX_3); glEnable(GL_MAP1_VERTEX_4); glEnable(GL_MAP2_VERTEX_3); glEnable(GL_MAP2_VERTEX_4); glEnable(GL_MAP2_COLOR_4); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); if(nurb == NULL) { nurb=gluNewNurbsRenderer(); if(nurb == NULL) outOfMemory(); gluNurbsProperty(nurb,GLU_SAMPLING_METHOD,GLU_PARAMETRIC_ERROR); gluNurbsProperty(nurb,GLU_SAMPLING_TOLERANCE,0.5); gluNurbsProperty(nurb,GLU_PARAMETRIC_TOLERANCE,1.0); gluNurbsProperty(nurb,GLU_CULLING,GLU_TRUE); // The callback tessellation algorithm avoids artifacts at degenerate // control points. gluNurbsProperty(nurb,GLU_NURBS_MODE,GLU_NURBS_TESSELLATOR); gluNurbsCallback(nurb,GLU_NURBS_BEGIN,(_GLUfuncptr) glBegin); gluNurbsCallback(nurb,GLU_NURBS_VERTEX,(_GLUfuncptr) glVertex3fv); gluNurbsCallback(nurb,GLU_NURBS_END,(_GLUfuncptr) glEnd); gluNurbsCallback(nurb,GLU_NURBS_COLOR,(_GLUfuncptr) glColor4fv); } mode(); if(View && !offscreen) { #ifdef HAVE_LIBGLUT #ifdef HAVE_PTHREAD initializedView=true; #endif glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutMouseFunc(mouse); glutCreateMenu(menu); glutAddMenuEntry("(h) Home",HOME); glutAddMenuEntry("(f) Fitscreen",FITSCREEN); glutAddMenuEntry("(x) X spin",XSPIN); glutAddMenuEntry("(y) Y spin",YSPIN); glutAddMenuEntry("(z) Z spin",ZSPIN); glutAddMenuEntry("(s) Stop",STOP); glutAddMenuEntry("(m) Mode",MODE); glutAddMenuEntry("(e) Export",EXPORT); glutAddMenuEntry("(c) Camera",CAMERA); glutAddMenuEntry("(p) Play",PLAY); glutAddMenuEntry("(r) Reverse",REVERSE); glutAddMenuEntry("( ) Step",STEP); glutAddMenuEntry("(q) Quit" ,QUIT); glutMenuStatusFunc(menuStatus); for(size_t i=0; i < nbuttons; ++i) { int button=buttons[i]; if(action(button,0) == "menu") glutAttachMenu(button); } glutMainLoop(); #endif // HAVE_LIBGLUT } else { if(glthread && !offscreen) { if(havewindow) { readyAfterExport=true; #ifdef HAVE_PTHREAD pthread_kill(mainthread,SIGUSR1); #endif } else { initialized=true; readyAfterExport=true; Signal(SIGUSR1,exportHandler); exportHandler(); } } else { exportHandler(); quit(); } } } } // namespace gl #endif asymptote-2.37/glrender.h000066400000000000000000000054741265434602500154660ustar00rootroot00000000000000/***** * glrender.h * Render 3D Bezier paths and surfaces. *****/ #ifndef GLRENDER_H #define GLRENDER_H #include "common.h" #include "triple.h" #ifdef HAVE_GL #include #ifdef __APPLE__ #include #include #include #ifdef HAVE_LIBGLUT #include #endif #ifdef HAVE_LIBOSMESA #include // TODO: where would you find osmesa on a mac? #endif #ifdef GLU_TESS_CALLBACK_TRIPLEDOT typedef GLvoid (* _GLUfuncptr)(...); #else typedef GLvoid (* _GLUfuncptr)(); #endif #else #include #include #include #ifdef HAVE_LIBGLUT #include #endif #ifdef HAVE_LIBOSMESA #include #endif #endif namespace camp { class picture; inline void store(GLfloat *f, double *C) { f[0]=C[0]; f[1]=C[1]; f[2]=C[2]; } inline void store(GLfloat *control, const camp::triple& v) { control[0]=v.getx(); control[1]=v.gety(); control[2]=v.getz(); } inline void store(GLfloat *control, const triple& v, double weight) { control[0]=v.getx()*weight; control[1]=v.gety()*weight; control[2]=v.getz()*weight; control[3]=weight; } } namespace gl { struct projection { public: bool orthographic; camp::triple camera; camp::triple up; camp::triple target; double zoom; double angle; camp::pair viewportshift; projection(bool orthographic=false, camp::triple camera=0.0, camp::triple up=0.0, camp::triple target=0.0, double zoom=0.0, double angle=0.0, camp::pair viewportshift=0.0) : orthographic(orthographic), camera(camera), up(up), target(target), zoom(zoom), angle(angle), viewportshift(viewportshift) {} }; projection camera(bool user=true); void glrender(const string& prefix, const camp::picture* pic, const string& format, double width, double height, double angle, double zoom, const camp::triple& m, const camp::triple& M, const camp::pair& shift, double *t, double *background, size_t nlights, camp::triple *lights, double *diffuse, double *ambient, double *specular, bool viewportlighting, bool view, int oldpid=0); } namespace camp { struct billboard { triple u,v,w; void init() { gl::projection P=gl::camera(false); w=unit(P.camera-P.target); v=unit(perp(P.up,w)); u=cross(v,w); } void store(GLfloat* C, const triple& V, const triple ¢er) { double cx=center.getx(); double cy=center.gety(); double cz=center.getz(); double x=V.getx()-cx; double y=V.gety()-cy; double z=V.getz()-cz; C[0]=cx+u.getx()*x+v.getx()*y+w.getx()*z; C[1]=cy+u.gety()*x+v.gety()*y+w.gety()*z; C[2]=cz+u.getz()*x+v.getz()*y+w.getz()*z; } }; extern billboard BB; } #else typedef void GLUnurbs; typedef float GLfloat; #endif #endif asymptote-2.37/gsl.cc000066400000000000000000001430111265434602500145750ustar00rootroot00000000000000/***** * gsl.cc * 2010/05/19 * * Initialize gsl builtins. *****/ #include "config.h" #ifdef HAVE_LIBGSL #include "vm.h" #include "types.h" #include "entry.h" #include "builtin.h" #include "record.h" #include "stack.h" #include "errormsg.h" #include "array.h" #include "triple.h" #include "callable.h" #include #include #include #include #include #include #include #include "opsymbols.h" #ifndef NOSYM #include "gsl.symbols.h" #endif namespace trans { using types::formal; using types::primVoid; using types::primInt; using types::primReal; using types::primPair; using types::primTriple; using types::primString; using types::IntArray; using types::realArray; using types::stringArray; using vm::stack; using vm::array; using vm::pop; using vm::error; using run::copyArrayC; using run::copyCArray; using camp::pair; using camp::triple; const char* GSLrngnull = "GSL random number generator not initialized"; const char* GSLinvalid = "invalid argument"; bool GSLerror=false; types::dummyRecord *GSLModule; types::record *getGSLModule() { return GSLModule; } inline void checkGSLerror() { if(GSLerror) { GSLerror=false; throw handled_error(); } } template void realRealGSL(stack *s) { double x=pop(s); s->push(func(x)); checkGSLerror(); } template void realRealDOUBLE(stack *s) { double x=pop(s); s->push(func(x,GSL_PREC_DOUBLE)); checkGSLerror(); } template void realRealRealDOUBLE(stack *s) { double y=pop(s); double x=pop(s); s->push(func(x,y,GSL_PREC_DOUBLE)); checkGSLerror(); } template void realIntGSL(stack *s) { s->push(func(unsignedcast(pop(s)))); checkGSLerror(); } template void realIntRealGSL(stack *s) { double x=pop(s); s->push(func(intcast(pop(s)),x)); checkGSLerror(); } template void realRealRealGSL(stack *s) { double x=pop(s); double n=pop(s); s->push(func(n,x)); checkGSLerror(); } template void intRealRealRealGSL(stack *s) { double x=pop(s); double n=pop(s); double a=pop(s); s->push(func(a,n,x)); checkGSLerror(); } template void realRealRealRealGSL(stack *s) { double x=pop(s); double n=pop(s); double a=pop(s); s->push(func(a,n,x)); checkGSLerror(); } template void realRealIntGSL(stack *s) { Int n=pop(s); double x=pop(s); s->push(func(x,unsignedcast(n))); checkGSLerror(); } // Add a GSL special function from the GNU GSL library template void addGSLRealFunc(symbol name, symbol arg1=SYM(x)) { addFunc(GSLModule->e.ve, realRealGSL, primReal(), name, formal(primReal(),arg1)); } // Add a GSL_PREC_DOUBLE GSL special function. template void addGSLDOUBLEFunc(symbol name, symbol arg1=SYM(x)) { addFunc(GSLModule->e.ve, realRealDOUBLE, primReal(), name, formal(primReal(),arg1)); } template void addGSLDOUBLE2Func(symbol name, symbol arg1=SYM(phi), symbol arg2=SYM(k)) { addFunc(GSLModule->e.ve, realRealRealDOUBLE, primReal(), name, formal(primReal(),arg1), formal(primReal(),arg2)); } template void realRealRealRealDOUBLE(stack *s) { double z=pop(s); double y=pop(s); double x=pop(s); s->push(func(x,y,z,GSL_PREC_DOUBLE)); checkGSLerror(); } template void addGSLDOUBLE3Func(symbol name, symbol arg1, symbol arg2, symbol arg3) { addFunc(GSLModule->e.ve, realRealRealRealDOUBLE, primReal(), name, formal(primReal(),arg1), formal(primReal(),arg2), formal(primReal(), arg3)); } template void realRealRealRealRealDOUBLE(stack *s) { double z=pop(s); double y=pop(s); double x=pop(s); double w=pop(s); s->push(func(w,x,y,z,GSL_PREC_DOUBLE)); checkGSLerror(); } template void addGSLDOUBLE4Func(symbol name, symbol arg1, symbol arg2, symbol arg3, symbol arg4) { addFunc(GSLModule->e.ve, realRealRealRealRealDOUBLE, primReal(), name, formal(primReal(),arg1), formal(primReal(),arg2), formal(primReal(), arg3), formal(primReal(), arg4)); } template void addGSLIntFunc(symbol name) { addFunc(GSLModule->e.ve, realIntGSL, primReal(), name, formal(primInt(),SYM(s))); } template void realSignedGSL(stack *s) { Int a = pop(s); s->push(func(intcast(a))); checkGSLerror(); } template void addGSLSignedFunc(symbol name, symbol arg1) { addFunc(GSLModule->e.ve, realSignedGSL, primReal(), name, formal(primInt(),arg1)); } template void addGSLIntRealFunc(symbol name, symbol arg1=SYM(n), symbol arg2=SYM(x)) { addFunc(GSLModule->e.ve, realIntRealGSL, primReal(), name, formal(primInt(),arg1), formal(primReal(),arg2)); } template void addGSLRealRealFunc(symbol name, symbol arg1=SYM(nu), symbol arg2=SYM(x)) { addFunc(GSLModule->e.ve, realRealRealGSL, primReal(), name, formal(primReal(),arg1), formal(primReal(),arg2)); } template void addGSLRealRealRealFunc(symbol name, symbol arg1, symbol arg2, symbol arg3) { addFunc(GSLModule->e.ve, realRealRealRealGSL, primReal(), name, formal(primReal(),arg1), formal(primReal(),arg2), formal(primReal(), arg3)); } template void addGSLRealRealRealFuncInt(symbol name, symbol arg1, symbol arg2, symbol arg3) { addFunc(GSLModule->e.ve, intRealRealRealGSL, primInt(), name, formal(primReal(),arg1), formal(primReal(),arg2), formal(primReal(), arg3)); } template void addGSLRealIntFunc(symbol name, symbol arg1=SYM(nu), symbol arg2=SYM(s)) { addFunc(GSLModule->e.ve, realRealIntGSL, primReal(), name, formal(primReal(),arg1), formal(primInt(),arg2)); } template void realRealSignedGSL(stack *s) { Int b = pop(s); double a = pop(s); s->push(func(a, intcast(b))); checkGSLerror(); } template void addGSLRealSignedFunc(symbol name, symbol arg1, symbol arg2) { addFunc(GSLModule->e.ve, realRealSignedGSL, primReal(), name, formal(primReal(),arg1), formal(primInt(),arg2)); } template void realUnsignedUnsignedGSL(stack *s) { Int b = pop(s); Int a = pop(s); s->push(func(unsignedcast(a), unsignedcast(b))); checkGSLerror(); } template void addGSLUnsignedUnsignedFunc(symbol name, symbol arg1, symbol arg2) { addFunc(GSLModule->e.ve, realUnsignedUnsignedGSL, primReal(), name, formal(primInt(), arg1), formal(primInt(), arg2)); } template void realIntRealRealGSL(stack *s) { double c = pop(s); double b = pop(s); Int a = pop(s); s->push(func(intcast(a), b, c)); checkGSLerror(); } template void addGSLIntRealRealFunc(symbol name, symbol arg1, symbol arg2, symbol arg3) { addFunc(GSLModule->e.ve, realIntRealRealGSL, primReal(), name, formal(primInt(), arg1), formal(primReal(), arg2), formal(primReal(), arg3)); } template void realIntIntRealGSL(stack *s) { double c = pop(s); Int b = pop(s); Int a = pop(s); s->push(func(intcast(a), intcast(b), c)); checkGSLerror(); } template void addGSLIntIntRealFunc(symbol name, symbol arg1, symbol arg2, symbol arg3) { addFunc(GSLModule->e.ve, realIntIntRealGSL, primReal(), name, formal(primInt(), arg1), formal(primInt(), arg2), formal(primReal(), arg3)); } template void realIntIntRealRealGSL(stack *s) { double d = pop(s); double c = pop(s); Int b = pop(s); Int a = pop(s); s->push(func(intcast(a), intcast(b), c, d)); checkGSLerror(); } template void addGSLIntIntRealRealFunc(symbol name, symbol arg1, symbol arg2, symbol arg3, symbol arg4) { addFunc(GSLModule->e.ve, realIntIntRealRealGSL, primReal(), name, formal(primInt(), arg1), formal(primInt(), arg2), formal(primReal(), arg3), formal(primReal(), arg4)); } template void realRealRealRealRealGSL(stack *s) { double d = pop(s); double c = pop(s); double b = pop(s); double a = pop(s); s->push(func(a, b, c, d)); checkGSLerror(); } template void addGSLRealRealRealRealFunc(symbol name, symbol arg1, symbol arg2, symbol arg3, symbol arg4) { addFunc(GSLModule->e.ve, realRealRealRealRealGSL, primReal(), name, formal(primReal(), arg1), formal(primReal(), arg2), formal(primReal(), arg3), formal(primReal(), arg4)); } template void realIntIntIntIntIntIntGSL(stack *s) { Int f = pop(s); Int e = pop(s); Int d = pop(s); Int c = pop(s); Int b = pop(s); Int a = pop(s); s->push(func(intcast(a), intcast(b), intcast(c), intcast(d), intcast(e), intcast(f))); checkGSLerror(); } template void addGSLIntIntIntIntIntIntFunc(symbol name, symbol arg1, symbol arg2, symbol arg3, symbol arg4, symbol arg5, symbol arg6) { addFunc(GSLModule->e.ve, realIntIntIntIntIntIntGSL, primReal(), name, formal(primInt(), arg1), formal(primInt(), arg2), formal(primInt(), arg3), formal(primInt(), arg4), formal(primInt(), arg5), formal(primInt(), arg6)); } template void realIntIntIntIntIntIntIntIntIntGSL(stack *s) { Int i = pop(s); Int h = pop(s); Int g = pop(s); Int f = pop(s); Int e = pop(s); Int d = pop(s); Int c = pop(s); Int b = pop(s); Int a = pop(s); s->push(func(intcast(a), intcast(b), intcast(c), intcast(d), intcast(e), intcast(f), intcast(g), intcast(h), intcast(i))); checkGSLerror(); } template void addGSLIntIntIntIntIntIntIntIntIntFunc(symbol name, symbol arg1, symbol arg2, symbol arg3, symbol arg4, symbol arg5, symbol arg6, symbol arg7, symbol arg8, symbol arg9) { addFunc(GSLModule->e.ve, realIntIntIntIntIntIntIntIntIntGSL, primReal(), name, formal(primInt(), arg1), formal(primInt(), arg2), formal(primInt(), arg3), formal(primInt(), arg4), formal(primInt(), arg5), formal(primInt(), arg6), formal(primInt(), arg7), formal(primInt(), arg8), formal(primInt(), arg9)); } template void realUIntRealGSL(stack *s) { double a = pop(s); unsigned int k = unsignedcast(pop(s)); s->push(func(k,a)); checkGSLerror(); } template void addGSLUIntRealFunc(symbol name, symbol arg1, symbol arg2) { addFunc(GSLModule->e.ve, realUIntRealGSL, primReal(), name, formal(primInt(), arg1), formal(primReal(), arg2)); } template void realUIntRealUIntGSL(stack *s) { unsigned int n = unsignedcast(pop(s)); double a = pop(s); unsigned int k = unsignedcast(pop(s)); s->push(func(k,a,n)); checkGSLerror(); } template void addGSLUIntRealUIntFunc(symbol name, symbol arg1, symbol arg2, symbol arg3) { addFunc(GSLModule->e.ve, realUIntRealUIntGSL, primReal(), name, formal(primInt(), arg1), formal(primReal(), arg2), formal(primInt(), arg3)); } template void realUIntRealRealGSL(stack *s) { double b = pop(s); double a = pop(s); unsigned int k = unsignedcast(pop(s)); s->push(func(k,a,b)); checkGSLerror(); } template void addGSLUIntRealRealFunc(symbol name, symbol arg1, symbol arg2, symbol arg3) { addFunc(GSLModule->e.ve, realUIntRealRealGSL, primReal(), name, formal(primInt(), arg1), formal(primReal(), arg2), formal(primReal(), arg3)); } template void realUIntUIntUIntUIntGSL(stack *s) { unsigned int t = unsignedcast(pop(s)); unsigned int n2 = unsignedcast(pop(s)); unsigned int n1 = unsignedcast(pop(s)); unsigned int k = unsignedcast(pop(s)); s->push(func(k,n1,n2,t)); checkGSLerror(); } template void addGSLUIntUIntUIntUIntFunc(symbol name, symbol arg1, symbol arg2, symbol arg3, symbol arg4) { addFunc(GSLModule->e.ve, realUIntUIntUIntUIntGSL, primReal(), name, formal(primInt(), arg1), formal(primInt(), arg2), formal(primInt(), arg3), formal(primInt(), arg4)); } // GSL random number generators gsl_rng *GSLrng=0; const gsl_rng_type **GSLrngFirstType=gsl_rng_types_setup(); inline void checkGSLrng() { if(GSLrng == 0) error(GSLrngnull); } void GSLrngFree() { if(GSLrng != 0) gsl_rng_free(GSLrng); GSLrng=0; } void GSLrngInit(stack *s) { string n = pop(s,string()); const gsl_rng_type **t; if(n.empty()) t = &gsl_rng_default; else { for(t=GSLrngFirstType; *t!=0; ++t) if(n == string((*t)->name)) break; if(*t == 0) error(GSLinvalid); } GSLrngFree(); GSLrng = gsl_rng_alloc(*t); if(GSLrng == 0) { GSLerror=false; error("insufficient memory for allocation of GSL random number generator"); } } void GSLrngList(stack *s) { array* a = new array(0); const gsl_rng_type **t; for(t=GSLrngFirstType; *t!=0; ++t) { a->push(string((*t)->name)); } s->push(a); checkGSLerror(); } void GSLrngSet(stack *s) { Int i=pop(s,-1); checkGSLrng(); if(i < 0) gsl_rng_set(GSLrng,gsl_rng_default_seed); else gsl_rng_set(GSLrng,unsignedcast(i)); checkGSLerror(); } template void intVoidGSLrng(stack *s) { s->push(func(GSLrng)); checkGSLrng(); checkGSLerror(); } template void addGSLrngVoidFuncInt(symbol name) { addFunc(GSLModule->e.ve, intVoidGSLrng, primInt(), name); } template void intULongGSLrng(stack *s) { unsigned long int i = unsignedcast(pop(s)); checkGSLrng(); s->push(func(GSLrng,i)); checkGSLerror(); } template void addGSLrngULongFuncInt(symbol name, symbol arg1) { addFunc(GSLModule->e.ve, intULongGSLrng, primInt(), name, formal(primInt(), arg1)); } template void intRealGSLrng(stack *s) { double x = pop(s); checkGSLrng(); s->push(func(GSLrng,x)); checkGSLerror(); } template void addGSLrngRealFuncInt(symbol name, symbol arg1) { addFunc(GSLModule->e.ve, intRealGSLrng, primInt(), name, formal(primReal(), arg1)); } template void intRealRealGSLrng(stack *s) { double y = pop(s); double x = pop(s); checkGSLrng(); s->push(func(GSLrng,x,y)); checkGSLerror(); } template void addGSLrngRealRealFuncInt(symbol name, symbol arg1, symbol arg2) { addFunc(GSLModule->e.ve, intRealRealGSLrng, primInt(), name, formal(primReal(), arg1), formal(primReal(), arg2)); } template void realVoidGSLrng(stack *s) { checkGSLrng(); s->push(func(GSLrng)); checkGSLerror(); } template void addGSLrngVoidFunc(symbol name) { addFunc(GSLModule->e.ve, realVoidGSLrng, primReal(), name); } template void realRealGSLrng(stack *s) { double x = pop(s); checkGSLrng(); s->push(func(GSLrng,x)); checkGSLerror(); } template void addGSLrngRealFunc(symbol name, symbol arg1) { addFunc(GSLModule->e.ve, realRealGSLrng, primReal(), name, formal(primReal(), arg1)); } template void realRealRealGSLrng(stack *s) { double b = pop(s); double a = pop(s); checkGSLrng(); s->push(func(GSLrng,a,b)); checkGSLerror(); } template void addGSLrngRealRealFunc(symbol name, symbol arg1, symbol arg2) { addFunc(GSLModule->e.ve, realRealRealGSLrng, primReal(), name, formal(primReal(), arg1), formal(primReal(), arg2)); } template void intRealUIntGSLrng(stack *s) { unsigned int n = unsignedcast(pop(s)); double a = pop(s); checkGSLrng(); s->push(func(GSLrng,a,n)); checkGSLerror(); } template void addGSLrngRealUIntFuncInt(symbol name, symbol arg1, symbol arg2) { addFunc(GSLModule->e.ve, intRealUIntGSLrng, primInt(), name, formal(primReal(), arg1), formal(primInt(), arg2)); } template void intUIntUIntUIntGSLrng(stack *s) { unsigned int t = unsignedcast(pop(s)); unsigned int n2 = unsignedcast(pop(s)); unsigned int n1 = unsignedcast(pop(s)); checkGSLrng(); s->push(func(GSLrng,n1,n2,t)); checkGSLerror(); } template void addGSLrngUIntUIntUIntFuncInt(symbol name, symbol arg1, symbol arg2, symbol arg3) { addFunc(GSLModule->e.ve, intUIntUIntUIntGSLrng, primInt(), name, formal(primInt(), arg1), formal(primInt(), arg2), formal(primInt(), arg3)); } template void stringVoidGSLrng(stack *s) { checkGSLrng(); s->push(func(GSLrng)); checkGSLerror(); } template void addGSLrngVoidFuncString(symbol name) { addFunc(GSLModule->e.ve, stringVoidGSLrng, primString(), name); } void GSLrng_gaussian(stack *s) { string method = pop(s,string("polar")); double sigma = pop(s,1.0); double mu = pop(s,0.0); checkGSLrng(); double x=mu; if(method == "polar") x += gsl_ran_gaussian(GSLrng,sigma); else if(method == "ziggurat") x += gsl_ran_gaussian_ziggurat(GSLrng,sigma); else if(method == "ratio") x += gsl_ran_gaussian_ratio_method(GSLrng,sigma); else error(GSLinvalid); s->push(x); checkGSLerror(); } template void realRealRealRealGSLgaussian(stack *s) { double sigma = pop(s,1.0); double mu = pop(s,0.0); double x = pop(s); s->push(func(x-mu,sigma)); checkGSLerror(); } template void addGSLgaussianrealRealRealRealFunc(symbol name, symbol arg1) { addFunc(GSLModule->e.ve, realRealRealRealGSLgaussian, primReal(), name, formal(primReal(), arg1), formal(primReal(), SYM(mu), true, false), formal(primReal(), SYM(sigma), true, false)); } template void realRealRealRealGSLinvgaussian(stack *s) { double sigma = pop(s,1.0); double mu = pop(s,0.0); double x = pop(s); s->push(func(x,sigma)+mu); checkGSLerror(); } template void addGSLinvgaussianrealRealRealRealFunc(symbol name, symbol arg1) { addFunc(GSLModule->e.ve, realRealRealRealGSLinvgaussian, primReal(), name, formal(primReal(), arg1), formal(primReal(), SYM(mu), true, false), formal(primReal(), SYM(sigma), true, false)); } void GSLrng_bivariate_gaussian(stack *s) { double rho = pop(s,0.0); pair sigma = pop(s,pair(1.0,1.0)); pair mu = pop(s,pair(0.0,0.0)); checkGSLrng(); double x,y; gsl_ran_bivariate_gaussian(GSLrng,sigma.getx(),sigma.gety(),rho,&x,&y); s->push(pair(x,y)+mu); checkGSLerror(); } void GSLpdf_bivariate_gaussian(stack *s) { double rho = pop(s,0.0); pair sigma = pop(s,pair(1.0,1.0)); pair mu = pop(s,pair(0.0,0.0)); pair z = pop(s); s->push(gsl_ran_bivariate_gaussian_pdf(z.getx()+mu.getx(),z.gety()+mu.gety(), sigma.getx(),sigma.gety(),rho)); checkGSLerror(); } void GSLrng_levy(stack *s) { double beta = pop(s,0.0); double alpha = pop(s); double c = pop(s); if((alpha<=0) || (alpha>2)) error(GSLinvalid); if((beta<-1) || (beta>1)) error(GSLinvalid); checkGSLrng(); double x; if(beta==0) x=gsl_ran_levy(GSLrng,c,alpha); else x=gsl_ran_levy_skew(GSLrng,c,alpha,beta); s->push(x); checkGSLerror(); } void GSLrng_gamma(stack *s) { string method = pop(s,string("mt")); double b = pop(s); double a = pop(s); checkGSLrng(); double x=0.0; if(method == "mt") x = gsl_ran_gamma(GSLrng,a,b); else if(method == "knuth") x = gsl_ran_gamma_knuth(GSLrng,a,b); else error(GSLinvalid); s->push(x); checkGSLerror(); } void GSLrng_dir2d(stack *s) { string method = pop(s,string("neumann")); checkGSLrng(); double x=0, y=0; if(method == "neumann") gsl_ran_dir_2d(GSLrng,&x,&y); else if(method == "trig") gsl_ran_dir_2d_trig_method(GSLrng,&x,&y); else error(GSLinvalid); s->push(pair(x,y)); checkGSLerror(); } void GSLrng_dir3d(stack *s) { checkGSLrng(); double x,y,z; gsl_ran_dir_3d(GSLrng,&x,&y,&z); s->push(triple(x,y,z)); checkGSLerror(); } void GSLrng_dir(stack *s) { size_t n = (size_t) unsignedcast(pop(s)); if(n==0) error(GSLinvalid); checkGSLrng(); double* p = new double[n]; gsl_ran_dir_nd(GSLrng,n,p); s->push(copyCArray(n,p)); delete[] p; checkGSLerror(); } void GSLrng_dirichlet(stack *s) { array* alpha = pop(s); size_t K = checkArray(alpha); checkGSLrng(); double* calpha; copyArrayC(calpha,alpha); double* ctheta = new double[K]; gsl_ran_dirichlet(GSLrng,K,calpha,ctheta); s->push(copyCArray(K,ctheta)); delete[] ctheta; delete[] calpha; checkGSLerror(); } void GSLpdf_dirichlet(stack *s) { array* theta = pop(s); array* alpha = pop(s); size_t K = checkArray(alpha); if(checkArray(theta) != K) error(GSLinvalid); double* calpha; copyArrayC(calpha,alpha); double* ctheta; copyArrayC(ctheta,theta); s->push(gsl_ran_dirichlet_pdf(K,calpha,ctheta)); delete[] ctheta; delete[] calpha; checkGSLerror(); } void GSLrng_multinomial(stack *s) { array* p = pop(s); unsigned int N = unsignedcast(pop(s)); size_t K = checkArray(p); checkGSLrng(); double* cp; copyArrayC(cp,p); unsigned int* cn = new unsigned int[K]; gsl_ran_multinomial(GSLrng,K,N,cp,cn); s->push(copyCArray(K,cn)); delete[] cn; delete[] cp; checkGSLerror(); } void GSLpdf_multinomial(stack *s) { array* n = pop(s); array* p = pop(s); size_t K = checkArray(p); if(K != checkArray(n)) error(GSLinvalid); double* cp; copyArrayC(cp,p); unsigned int* cn; copyArrayC(cn,n,unsignedcast); s->push(gsl_ran_multinomial_pdf(K,cp,cn)); delete[] cn; delete[] cp; checkGSLerror(); } void GSLsf_elljac_e(stack *s) { double m = pop(s); double u = pop(s); double sn,cn,dn; gsl_sf_elljac_e(u,m,&sn,&cn,&dn); array *result=new array(3); (*result)[0]=sn; (*result)[1]=cn; (*result)[2]=dn; s->push(result); } // Handle GSL errors gracefully. void GSLerrorhandler(const char *reason, const char *, int, int) { if(!GSLerror) { vm::errornothrow(reason); GSLerror=true; } } void gen_rungsl_venv(venv &ve) { GSLModule=new types::dummyRecord(SYM(gsl)); gsl_set_error_handler(GSLerrorhandler); // Common functions addGSLRealRealFunc(SYM(hypot),SYM(x),SYM(y)); // addGSLRealRealRealFunc(SYM(hypot),SYM(x),SYM(y),SYM(z)); addGSLRealRealRealFuncInt(SYM(fcmp),SYM(x),SYM(y),SYM(epsilon)); // Airy functions addGSLDOUBLEFunc(SYM(Ai)); addGSLDOUBLEFunc(SYM(Bi)); addGSLDOUBLEFunc(SYM(Ai_scaled)); addGSLDOUBLEFunc(SYM(Bi_scaled)); addGSLDOUBLEFunc(SYM(Ai_deriv)); addGSLDOUBLEFunc(SYM(Bi_deriv)); addGSLDOUBLEFunc(SYM(Ai_deriv_scaled)); addGSLDOUBLEFunc(SYM(Bi_deriv_scaled)); addGSLIntFunc(SYM(zero_Ai)); addGSLIntFunc(SYM(zero_Bi)); addGSLIntFunc(SYM(zero_Ai_deriv)); addGSLIntFunc(SYM(zero_Bi_deriv)); // Bessel functions addGSLRealFunc(SYM(J0)); addGSLRealFunc(SYM(J1)); addGSLIntRealFunc(SYM(Jn)); addGSLRealFunc(SYM(Y0)); addGSLRealFunc(SYM(Y1)); addGSLIntRealFunc(SYM(Yn)); addGSLRealFunc(SYM(I0)); addGSLRealFunc(SYM(I1)); addGSLIntRealFunc(SYM(I)); addGSLRealFunc(SYM(I0_scaled)); addGSLRealFunc(SYM(I1_scaled)); addGSLIntRealFunc(SYM(I_scaled)); addGSLRealFunc(SYM(K0)); addGSLRealFunc(SYM(K1)); addGSLIntRealFunc(SYM(K)); addGSLRealFunc(SYM(K0_scaled)); addGSLRealFunc(SYM(K1_scaled)); addGSLIntRealFunc(SYM(K_scaled)); addGSLRealFunc(SYM(j0)); addGSLRealFunc(SYM(j1)); addGSLRealFunc(SYM(j2)); addGSLIntRealFunc(SYM(j),SYM(l)); addGSLRealFunc(SYM(y0)); addGSLRealFunc(SYM(y1)); addGSLRealFunc(SYM(y2)); addGSLIntRealFunc(SYM(y),SYM(l)); addGSLRealFunc(SYM(i0_scaled)); addGSLRealFunc(SYM(i1_scaled)); addGSLRealFunc(SYM(i2_scaled)); addGSLIntRealFunc(SYM(i_scaled),SYM(l)); addGSLRealFunc(SYM(k0_scaled)); addGSLRealFunc(SYM(k1_scaled)); addGSLRealFunc(SYM(k2_scaled)); addGSLIntRealFunc(SYM(k_scaled),SYM(l)); addGSLRealRealFunc(SYM(J)); addGSLRealRealFunc(SYM(Y)); addGSLRealRealFunc(SYM(I)); addGSLRealRealFunc(SYM(I_scaled)); addGSLRealRealFunc(SYM(K)); addGSLRealRealFunc(SYM(lnK)); addGSLRealRealFunc(SYM(K_scaled)); addGSLIntFunc(SYM(zero_J0)); addGSLIntFunc(SYM(zero_J1)); addGSLRealIntFunc(SYM(zero_J)); // Clausen functions addGSLRealFunc(SYM(clausen)); // Coulomb functions addGSLRealRealFunc(SYM(hydrogenicR_1),SYM(Z),SYM(r)); addGSLIntIntRealRealFunc(SYM(hydrogenicR),SYM(n),SYM(l), SYM(Z),SYM(r)); // Missing: F_L(eta,x), G_L(eta,x), C_L(eta) // Coupling coefficients addGSLIntIntIntIntIntIntFunc(SYM(coupling_3j),SYM(two_ja), SYM(two_jb),SYM(two_jc), SYM(two_ma), SYM(two_mb),SYM(two_mc)); addGSLIntIntIntIntIntIntFunc(SYM(coupling_6j),SYM(two_ja), SYM(two_jb),SYM(two_jc), SYM(two_jd), SYM(two_je),SYM(two_jf)); addGSLIntIntIntIntIntIntIntIntIntFunc(SYM(coupling_9j), SYM(two_ja), SYM(two_jb), SYM(two_jc), SYM(two_jd), SYM(two_je), SYM(two_jf), SYM(two_jg), SYM(two_jh), SYM(two_ji)); // Dawson function addGSLRealFunc(SYM(dawson)); // Debye functions addGSLRealFunc(SYM(debye_1)); addGSLRealFunc(SYM(debye_2)); addGSLRealFunc(SYM(debye_3)); addGSLRealFunc(SYM(debye_4)); addGSLRealFunc(SYM(debye_5)); addGSLRealFunc(SYM(debye_6)); // Dilogarithm addGSLRealFunc(SYM(dilog)); // Missing: complex dilogarithm // Elementary operations // we don't support errors at the moment // Elliptic integrals addGSLDOUBLEFunc(SYM(K),SYM(k)); addGSLDOUBLEFunc(SYM(E),SYM(k)); addGSLDOUBLE2Func(SYM(P),SYM(k),SYM(n)); addGSLDOUBLE2Func(SYM(F)); addGSLDOUBLE2Func(SYM(E)); addGSLDOUBLE3Func(SYM(P),SYM(phi),SYM(k),SYM(n)); #if GSL_MAJOR_VERSION >= 2 addGSLDOUBLE2Func(SYM(D),SYM(phi),SYM(k)); #else addGSLDOUBLE3Func(SYM(D),SYM(phi),SYM(k),SYM(n)); #endif addGSLDOUBLE2Func(SYM(RC),SYM(x),SYM(y)); addGSLDOUBLE3Func(SYM(RD),SYM(x),SYM(y),SYM(z)); addGSLDOUBLE3Func(SYM(RF),SYM(x),SYM(y),SYM(z)); addGSLDOUBLE4Func(SYM(RJ),SYM(x),SYM(y),SYM(z),SYM(p)); // Error functions addGSLRealFunc(SYM(erf)); addGSLRealFunc(SYM(erfc)); addGSLRealFunc(SYM(log_erfc)); addGSLRealFunc(SYM(erf_Z)); addGSLRealFunc(SYM(erf_Q)); addGSLRealFunc(SYM(hazard)); // Exponential functions addGSLRealRealFunc(SYM(exp_mult),SYM(x),SYM(y)); // addGSLRealFunc(SYM(expm1)); addGSLRealFunc(SYM(exprel)); addGSLRealFunc(SYM(exprel_2)); addGSLIntRealFunc(SYM(exprel),SYM(n),SYM(x)); // Exponential integrals addGSLRealFunc(SYM(E1)); addGSLRealFunc(SYM(E2)); // addGSLIntRealFunc(SYM(En),SYM(n),SYM(x)); addGSLRealFunc(SYM(Ei)); addGSLRealFunc(SYM(Shi)); addGSLRealFunc(SYM(Chi)); addGSLRealFunc(SYM(Ei3)); addGSLRealFunc(SYM(Si)); addGSLRealFunc(SYM(Ci)); addGSLRealFunc(SYM(atanint)); // Fermi--Dirac function addGSLRealFunc(SYM(FermiDiracM1)); addGSLRealFunc(SYM(FermiDirac0)); addGSLRealFunc(SYM(FermiDirac1)); addGSLRealFunc(SYM(FermiDirac2)); addGSLIntRealFunc(SYM(FermiDirac),SYM(j),SYM(x)); addGSLRealFunc(SYM(FermiDiracMHalf)); addGSLRealFunc(SYM(FermiDiracHalf)); addGSLRealFunc(SYM(FermiDirac3Half)); addGSLRealRealFunc(SYM(FermiDiracInc0),SYM(x), SYM(b)); // Gamma and beta functions addGSLRealFunc(SYM(gamma)); addGSLRealFunc(SYM(lngamma)); addGSLRealFunc(SYM(gammastar)); addGSLRealFunc(SYM(gammainv)); addGSLIntFunc(SYM(fact)); addGSLIntFunc(SYM(doublefact)); addGSLIntFunc(SYM(lnfact)); addGSLIntFunc(SYM(lndoublefact)); addGSLUnsignedUnsignedFunc(SYM(choose),SYM(n),SYM(m)); addGSLUnsignedUnsignedFunc(SYM(lnchoose),SYM(n),SYM(m)); addGSLIntRealFunc(SYM(taylorcoeff),SYM(n),SYM(x)); addGSLRealRealFunc(SYM(poch),SYM(a),SYM(x)); addGSLRealRealFunc(SYM(lnpoch),SYM(a),SYM(x)); addGSLRealRealFunc(SYM(pochrel),SYM(a),SYM(x)); addGSLRealRealFunc(SYM(gamma),SYM(a),SYM(x)); addGSLRealRealFunc(SYM(gamma_Q),SYM(a),SYM(x)); addGSLRealRealFunc(SYM(gamma_P),SYM(a),SYM(x)); addGSLRealRealFunc(SYM(beta),SYM(a),SYM(b)); addGSLRealRealFunc(SYM(lnbeta),SYM(a),SYM(b)); addGSLRealRealRealFunc(SYM(beta),SYM(a),SYM(b),SYM(x)); // Gegenbauer functions addGSLRealRealFunc(SYM(gegenpoly_1),SYM(lambda),SYM(x)); addGSLRealRealFunc(SYM(gegenpoly_2),SYM(lambda),SYM(x)); addGSLRealRealFunc(SYM(gegenpoly_3),SYM(lambda),SYM(x)); addGSLIntRealRealFunc(SYM(gegenpoly),SYM(n),SYM(lambda), SYM(x)); // Hypergeometric functions addGSLRealRealFunc(SYM(hy0F1),SYM(c),SYM(x)); addGSLIntIntRealFunc(SYM(hy1F1),SYM(m),SYM(n),SYM(x)); addGSLRealRealRealFunc(SYM(hy1F1),SYM(a),SYM(b),SYM(x)); addGSLIntIntRealFunc(SYM(U),SYM(m),SYM(n),SYM(x)); addGSLRealRealRealFunc(SYM(U),SYM(a),SYM(b),SYM(x)); addGSLRealRealRealRealFunc(SYM(hy2F1),SYM(a),SYM(b),SYM(c), SYM(x)); addGSLRealRealRealRealFunc(SYM(hy2F1_conj),SYM(aR), SYM(aI),SYM(c),SYM(x)); addGSLRealRealRealRealFunc(SYM(hy2F1_renorm),SYM(a), SYM(b),SYM(c),SYM(x)); addGSLRealRealRealRealFunc (SYM(hy2F1_conj_renorm),SYM(aR),SYM(aI),SYM(c),SYM(x)); addGSLRealRealRealFunc(SYM(hy2F0),SYM(a),SYM(b),SYM(x)); // Laguerre functions addGSLRealRealFunc(SYM(L1),SYM(a),SYM(x)); addGSLRealRealFunc(SYM(L2),SYM(a),SYM(x)); addGSLRealRealFunc(SYM(L3),SYM(a),SYM(x)); addGSLIntRealRealFunc(SYM(L),SYM(n),SYM(a),SYM(x)); // Lambert W functions addGSLRealFunc(SYM(W0)); addGSLRealFunc(SYM(Wm1)); // Legendre functions and spherical harmonics addGSLRealFunc(SYM(P1)); addGSLRealFunc(SYM(P2)); addGSLRealFunc(SYM(P3)); addGSLIntRealFunc(SYM(Pl),SYM(l)); addGSLRealFunc(SYM(Q0)); addGSLRealFunc(SYM(Q1)); addGSLIntRealFunc(SYM(Ql),SYM(l)); addGSLIntIntRealFunc(SYM(Plm),SYM(l),SYM(m),SYM(x)); addGSLIntIntRealFunc(SYM(sphPlm),SYM(l),SYM(m), SYM(x)); addGSLRealRealFunc(SYM(conicalP_half),SYM(lambda), SYM(x)); addGSLRealRealFunc(SYM(conicalP_mhalf),SYM(lambda), SYM(x)); addGSLRealRealFunc(SYM(conicalP_0),SYM(lambda),SYM(x)); addGSLRealRealFunc(SYM(conicalP_1),SYM(lambda),SYM(x)); addGSLIntRealRealFunc(SYM(conicalP_sph_reg),SYM(l), SYM(lambda),SYM(x)); addGSLIntRealRealFunc(SYM(conicalP_cyl_reg),SYM(m), SYM(lambda),SYM(x)); addGSLRealRealFunc(SYM(H3d0),SYM(lambda),SYM(eta)); addGSLRealRealFunc(SYM(H3d1),SYM(lambda),SYM(eta)); addGSLIntRealRealFunc(SYM(H3d),SYM(l),SYM(lambda), SYM(eta)); // Logarithm and related functions addGSLRealFunc(SYM(logabs)); // addGSLRealFunc(SYM(log1p)); addGSLRealFunc(SYM(log1pm)); // Matthieu functions // to be implemented // Power function addGSLRealSignedFunc(SYM(pow),SYM(x),SYM(n)); // Psi (digamma) function addGSLSignedFunc(SYM(psi),SYM(n)); addGSLRealFunc(SYM(psi)); addGSLRealFunc(SYM(psi_1piy),SYM(y)); addGSLSignedFunc(SYM(psi1),SYM(n)); addGSLRealFunc(SYM(psi1),SYM(x)); addGSLIntRealFunc(SYM(psi),SYM(n),SYM(x)); // Synchrotron functions addGSLRealFunc(SYM(synchrotron_1)); addGSLRealFunc(SYM(synchrotron_2)); // Transport functions addGSLRealFunc(SYM(transport_2)); addGSLRealFunc(SYM(transport_3)); addGSLRealFunc(SYM(transport_4)); addGSLRealFunc(SYM(transport_5)); // Trigonometric functions addGSLRealFunc(SYM(sinc)); addGSLRealFunc(SYM(lnsinh)); addGSLRealFunc(SYM(lncosh)); // Zeta functions addGSLSignedFunc(SYM(zeta),SYM(n)); addGSLRealFunc(SYM(zeta),SYM(s)); addGSLSignedFunc(SYM(zetam1),SYM(n)); addGSLRealFunc(SYM(zetam1),SYM(s)); addGSLRealRealFunc(SYM(hzeta),SYM(s),SYM(q)); addGSLSignedFunc(SYM(eta),SYM(n)); addGSLRealFunc(SYM(eta),SYM(s)); // Random number generation gsl_rng_env_setup(); addFunc(GSLModule->e.ve,GSLrngInit,primVoid(),SYM(rng_init), formal(primString(),SYM(name),true,false)); addFunc(GSLModule->e.ve,GSLrngList,stringArray(),SYM(rng_list)); addFunc(GSLModule->e.ve,GSLrngSet,primVoid(),SYM(rng_set), formal(primInt(),SYM(seed),true,false)); addGSLrngVoidFuncString(SYM(rng_name)); addGSLrngVoidFuncInt(SYM(rng_min)); addGSLrngVoidFuncInt(SYM(rng_max)); addGSLrngVoidFuncInt(SYM(rng_get)); addGSLrngULongFuncInt(SYM(rng_uniform_int),SYM(n)); addGSLrngVoidFunc(SYM(rng_uniform)); addGSLrngVoidFunc(SYM(rng_uniform_pos)); // Gaussian distribution addFunc(GSLModule->e.ve,GSLrng_gaussian,primReal(),SYM(rng_gaussian), formal(primReal(),SYM(mu),true,false), formal(primReal(),SYM(sigma),true,false), formal(primString(),SYM(method),true,false)); addGSLgaussianrealRealRealRealFunc(SYM(pdf_gaussian), SYM(x)); addGSLgaussianrealRealRealRealFunc(SYM(cdf_gaussian_P), SYM(x)); addGSLgaussianrealRealRealRealFunc(SYM(cdf_gaussian_Q), SYM(x)); addGSLinvgaussianrealRealRealRealFunc (SYM(cdf_gaussian_Pinv),SYM(x)); addGSLinvgaussianrealRealRealRealFunc (SYM(cdf_gaussian_Qinv),SYM(x)); // Gaussian tail distribution addGSLrngRealRealFunc(SYM(rng_gaussian_tail),SYM(a), SYM(sigma)); addGSLRealRealRealFunc(SYM(pdf_gaussian_tail), SYM(x),SYM(a),SYM(sigma)); // Bivariate Gaussian distribution addFunc(GSLModule->e.ve,GSLrng_bivariate_gaussian,primPair(), SYM(rng_bivariate_gaussian), formal(primPair(),SYM(mu),true,true), formal(primPair(),SYM(sigma),true,true), formal(primReal(),SYM(rho),true,false)); addFunc(GSLModule->e.ve,GSLpdf_bivariate_gaussian,primReal(), SYM(pdf_bivariate_gaussian), formal(primPair(),SYM(z),false,true), formal(primPair(),SYM(mu),true,true), formal(primPair(),SYM(sigma),true,true), formal(primReal(),SYM(rho),true,false)); #define addGSLrealdist1param(NAME,ARG) \ addGSLrngRealFunc \ (SYM(rng_##NAME),SYM(ARG)); \ addGSLRealRealFunc \ (SYM(pdf_##NAME),SYM(x),SYM(ARG)); \ addGSLRealRealFunc \ (SYM(cdf_##NAME##_P),SYM(x),SYM(ARG)); \ addGSLRealRealFunc \ (SYM(cdf_##NAME##_Q),SYM(x),SYM(ARG)); \ addGSLRealRealFunc \ (SYM(cdf_##NAME##_Pinv),SYM(P),SYM(ARG)); \ addGSLRealRealFunc \ (SYM(cdf_##NAME##_Qinv),SYM(Q),SYM(ARG)) // Exponential, Laplace, Cauchy, Rayleigh, Chi-squared, t, // and Logistic distribution addGSLrealdist1param(exponential,mu); addGSLrealdist1param(laplace,a); addGSLrealdist1param(cauchy,a); addGSLrealdist1param(rayleigh,mu); addGSLrealdist1param(chisq,mu); addGSLrealdist1param(tdist,mu); addGSLrealdist1param(logistic,mu); #undef addGSLrealdist1param #define addGSLrealdist2param(NAME,ARG1,ARG2) \ addGSLrngRealRealFunc \ (SYM(rng_##NAME),SYM(ARG1),SYM(ARG2)); \ addGSLRealRealRealFunc \ (SYM(pdf_##NAME),SYM(x),SYM(ARG1),SYM(ARG2)); \ addGSLRealRealRealFunc \ (SYM(cdf_##NAME##_P),SYM(x),SYM(ARG1),SYM(ARG2)); \ addGSLRealRealRealFunc \ (SYM(cdf_##NAME##_Q),SYM(x),SYM(ARG1),SYM(ARG2)); \ addGSLRealRealRealFunc \ (SYM(cdf_##NAME##_Pinv),SYM(P),SYM(ARG1),SYM(ARG2)); \ addGSLRealRealRealFunc \ (SYM(cdf_##NAME##_Qinv),SYM(Q),SYM(ARG1),SYM(ARG2)) // Uniform, log-normal, F, Beta, Pareto, Weibull, Type-1 Gumbel, // and Type-2 Gumbel distribution addGSLrealdist2param(flat,a,b); addGSLrealdist2param(lognormal,zeta,sigma); addGSLrealdist2param(fdist,nu1,nu2); addGSLrealdist2param(beta,a,b); addGSLrealdist2param(pareto,a,b); addGSLrealdist2param(weibull,a,b); addGSLrealdist2param(gumbel1,a,b); addGSLrealdist2param(gumbel2,a,b); #undef addGSLrealdist2param // Exponential power distribution addGSLrngRealRealFunc (SYM(rng_exppow),SYM(a),SYM(b)); addGSLRealRealRealFunc (SYM(pdf_exppow),SYM(x),SYM(a),SYM(b)); addGSLRealRealRealFunc (SYM(cdf_exppow_P),SYM(x),SYM(a),SYM(b)); addGSLRealRealRealFunc (SYM(cdf_exppow_Q),SYM(x),SYM(a),SYM(b)); // Exponential power distribution addGSLrngRealRealFunc (SYM(rng_rayleigh_tail),SYM(a),SYM(sigma)); addGSLRealRealRealFunc (SYM(pdf_rayleigh_tail),SYM(x),SYM(a),SYM(sigma)); // Landau distribution addGSLrngVoidFunc(SYM(rng_landau)); addGSLRealFunc(SYM(pdf_landau),SYM(x)); // Levy skwew alpha-stable distribution addFunc(GSLModule->e.ve,GSLrng_levy,primReal(),SYM(rng_levy), formal(primReal(),SYM(c)), formal(primReal(),SYM(alpha)), formal(primReal(),SYM(beta),true,false)); // Gamma distribution addFunc(GSLModule->e.ve,GSLrng_gamma,primReal(),SYM(rng_gamma), formal(primReal(),SYM(a)), formal(primReal(),SYM(b)), formal(primString(),SYM(method),true,false)); addGSLRealRealRealFunc (SYM(pdf_gamma),SYM(x),SYM(a),SYM(b)); addGSLRealRealRealFunc (SYM(cdf_gamma_P),SYM(x),SYM(a),SYM(b)); addGSLRealRealRealFunc (SYM(cdf_gamma_Q),SYM(x),SYM(a),SYM(b)); addGSLRealRealRealFunc (SYM(cdf_gamma_Pinv),SYM(P),SYM(a),SYM(b)); addGSLRealRealRealFunc (SYM(cdf_gamma_Qinv),SYM(Q),SYM(a),SYM(b)); // Sperical distributions addFunc(GSLModule->e.ve,GSLrng_dir2d,primPair(),SYM(rng_dir2d), formal(primString(),SYM(method),true,false)); addFunc(GSLModule->e.ve,GSLrng_dir3d,primTriple(),SYM(rng_dir3d)); addFunc(GSLModule->e.ve,GSLrng_dir,realArray(),SYM(rng_dir), formal(primInt(),SYM(n))); // Elliptic functions (Jacobi) addFunc(GSLModule->e.ve,GSLsf_elljac_e,realArray(),SYM(sncndn), formal(primReal(),SYM(u)),formal(primReal(),SYM(m))); // Dirirchlet distribution addFunc(GSLModule->e.ve,GSLrng_dirichlet,realArray(),SYM(rng_dirichlet), formal(realArray(),SYM(alpha))); addFunc(GSLModule->e.ve,GSLpdf_dirichlet,primReal(),SYM(pdf_dirichlet), formal(realArray(),SYM(alpha)), formal(realArray(),SYM(theta))); // General discrete distributions // to be implemented #define addGSLdiscdist1param(NAME,ARG,TYPE) \ addGSLrng##TYPE##FuncInt \ (SYM(rng_##NAME),SYM(ARG)); \ addGSLUInt##TYPE##Func \ (SYM(pdf_##NAME),SYM(k),SYM(ARG)); \ addGSLUInt##TYPE##Func \ (SYM(cdf_##NAME##_P),SYM(k),SYM(ARG)); \ addGSLUInt##TYPE##Func \ (SYM(cdf_##NAME##_Q),SYM(k),SYM(ARG)) // Poisson, geometric distributions addGSLdiscdist1param(poisson,mu,Real); addGSLdiscdist1param(geometric,p,Real); #undef addGSLdiscdist1param #define addGSLdiscdist2param(NAME,ARG1,TYPE1,ARG2,TYPE2) \ addGSLrng##TYPE1##TYPE2##FuncInt \ (SYM(rng_##NAME),SYM(ARG1),SYM(ARG2)); \ addGSLUInt##TYPE1##TYPE2##Func \ (SYM(pdf_##NAME),SYM(k),SYM(ARG1),SYM(ARG2)); \ addGSLUInt##TYPE1##TYPE2##Func \ (SYM(cdf_##NAME##_P),SYM(k),SYM(ARG1),SYM(ARG2)); \ addGSLUInt##TYPE1##TYPE2##Func \ (SYM(cdf_##NAME##_Q),SYM(k),SYM(ARG1),SYM(ARG2)) // Binomial, negative binomial distributions addGSLdiscdist2param(binomial,p,Real,n,UInt); addGSLdiscdist2param(negative_binomial,p,Real,n,Real); #undef addGSLdiscdist2param // Logarithmic distribution addGSLrngRealFuncInt(SYM(rng_logarithmic),SYM(p)); addGSLUIntRealFunc(SYM(pdf_logarithmic),SYM(k), SYM(p)); // Bernoulli distribution addGSLrngRealFuncInt(SYM(rng_bernoulli),SYM(p)); addGSLUIntRealFunc(SYM(pdf_bernoulli),SYM(k),SYM(p)); // Multinomial distribution addFunc(GSLModule->e.ve,GSLrng_multinomial,IntArray(),SYM(rng_multinomial), formal(primInt(),SYM(n)), formal(realArray(),SYM(p))); addFunc(GSLModule->e.ve,GSLpdf_multinomial,primReal(),SYM(pdf_multinomial), formal(realArray(),SYM(p)), formal(IntArray(),SYM(n))); // Hypergeometric distribution addGSLrngUIntUIntUIntFuncInt (SYM(rng_hypergeometric),SYM(n1),SYM(n2),SYM(t)); addGSLUIntUIntUIntUIntFunc (SYM(pdf_hypergeometric),SYM(k),SYM(n1),SYM(n2),SYM(t)); addGSLUIntUIntUIntUIntFunc (SYM(cdf_hypergeometric_P),SYM(k),SYM(n1),SYM(n2),SYM(t)); addGSLUIntUIntUIntUIntFunc (SYM(cdf_hypergeometric_Q),SYM(k),SYM(n1),SYM(n2),SYM(t)); } } // namespace trans #endif asymptote-2.37/guide.cc000066400000000000000000000022271265434602500151100ustar00rootroot00000000000000/***** * guide.cc * Andy Hammerlindl 2005/02/23 * *****/ #include "guide.h" namespace camp { multiguide::multiguide(guidevector& v) { // This constructor tests if the first subguide is also a multiguide and, // if possible, uses the same base, extending it beyond what is used. multiguide *rg = v.empty() ? 0 : dynamic_cast(v[0]); if (rg && rg->base->size() == rg->length) { base = rg->base; base->insert(base->end(), v.begin()+1, v.end()); } else base = new guidevector(v); length = base->size(); } void multiguide::flatten(flatguide& g, bool allowsolve) { size_t n=length; if(n > 0) { for(size_t i=0; i+1 < n; ++i) { subguide(i)->flatten(g,allowsolve); if(!allowsolve && subguide(i)->cyclic()) { g.precyclic(true); g.resolvecycle(); } } subguide(n-1)->flatten(g,allowsolve); } } void multiguide::print(ostream& out) const { side lastLoc=JOIN; for(size_t i=0; i < length; ++i) { guide *g = subguide(i); side loc = g->printLocation(); adjustLocation(out,lastLoc,loc); g->print(out); lastLoc=loc; } } } // namespace camp asymptote-2.37/guide.h000066400000000000000000000151771265434602500147620ustar00rootroot00000000000000/***** * guide.h * Andy Hammerlindl 2005/02/23 * *****/ #ifndef GUIDE_H #define GUIDE_H #include #include "knot.h" #include "flatguide.h" #include "settings.h" namespace camp { // Abstract base class for guides. class guide : public gc { protected: public: virtual ~guide() {} // Returns the path that the guide represents. virtual path solve() { return path(); } // Add the information in the guide to the flatguide, so that it can be // solved via the knotlist solving routines. // Returns true if guide has an interior cycle token. virtual void flatten(flatguide&, bool allowsolve=true)=0; virtual bool cyclic() {return false;} virtual void print(ostream& out) const { out << "nullpath"; } // Needed so that multiguide can know where to put in ".." symbols. virtual side printLocation() const { return END; } }; inline ostream& operator<< (ostream& out, const guide& g) { g.print(out); return out; } // Draws dots between two printings of guides, if their locations are such that // the dots are necessary. inline void adjustLocation(ostream& out, side l1, side l2) { if (l1 == END) out << endl; if ((l1 == END || l1 == OUT) && (l2 == IN || l2 == END)) out << ".."; } // A guide representing a pair. class pairguide : public guide { pair z; public: void flatten(flatguide& g, bool=true) { g.add(z); } pairguide(pair z) : z(z) {} path solve() { return path(z); } void print(ostream& out) const { out << z; } side printLocation() const { return END; } }; // A guide representing a path. class pathguide : public guide { path p; public: void flatten(flatguide& g, bool allowsolve=true) { g.add(p,allowsolve); } pathguide(path p) : p(p) {} path solve() { return p; } bool cyclic() {return p.cyclic();} void print(ostream& out) const { out << p; } side printLocation() const { return END; } }; // Tension expressions are evaluated to this class before being cast to a guide, // so that they can be cast to other types (such as guide3) instead. class tensionSpecifier : public gc { double out,in; bool atleast; public: tensionSpecifier(double val, bool atleast=false) : out(val), in(val), atleast(atleast) {} tensionSpecifier(double out, double in, bool atleast=false) : out(out), in(in), atleast(atleast) {} double getOut() const { return out; } double getIn() const { return in; } bool getAtleast() const { return atleast; } }; // A guide giving tension information (as part of a join). class tensionguide : public guide { tension tout,tin; public: void flatten(flatguide& g, bool=true) { g.setTension(tin,IN); g.setTension(tout,OUT); } tensionguide(tensionSpecifier spec) : tout(spec.getOut(), spec.getAtleast()), tin(spec.getIn(), spec.getAtleast()) {} void print(ostream& out) const { out << (tout.atleast ? ".. tension atleast " : ".. tension ") << tout.val << " and " << tin.val << " .."; } side printLocation() const { return JOIN; } }; // Similar to tensionSpecifier, curl expression are evaluated to this type // before being cast to guides. class curlSpecifier : public gc { double value; side s; public: curlSpecifier(double value, side s) : value(value), s(s) {} double getValue() const { return value; } side getSide() const { return s; } }; // A guide giving a specifier. class specguide : public guide { spec *p; side s; public: void flatten(flatguide& g, bool=true) { g.setSpec(p,s); } specguide(spec *p, side s) : p(p), s(s) {} specguide(curlSpecifier spec) : p(new curlSpec(spec.getValue())), s(spec.getSide()) {} void print(ostream& out) const { out << *p; } side printLocation() const { return s; } }; // A guide for explicit control points between two knots. This could be done // with two specguides, instead, but this prints nicer, and is easier to encode. class controlguide : public guide { pair zout, zin; public: void flatten(flatguide& g, bool=true) { g.setSpec(new controlSpec(zout), OUT); g.setSpec(new controlSpec(zin), IN); } controlguide(pair zout,pair zin) : zout(zout),zin(zin) {} controlguide(pair z) : zout(z),zin(z) {} void print(ostream& out) const { out << ".. controls " << zout << " and " << zin << " .."; } side printLocation() const { return JOIN; } }; // A guide that is a sequence of other guides. This is used, for instance is // joins, where we have the left and right guide, and possibly specifiers and // tensions in between. typedef mem::vector guidevector; // A multiguide represents a guide given by the first "length" items of // the vector pointed to by "base". // The constructor, if given another multiguide as a first argument, // will try to avoid allocating a new "base" array. class multiguide : public guide { guidevector *base; size_t length; guide *subguide(size_t i) const { assert(i < length); assert(length <= base->size()); return (*base)[i]; } public: multiguide(guidevector& v); void flatten(flatguide&, bool=true); bool cyclic() { size_t n=length; if(n < 1) return false; return subguide(n-1)->cyclic(); } path solve() { if (settings::verbose>3) { cerr << "solving guide:\n"; print(cerr); cerr << "\n\n"; } flatguide g; this->flatten(g); path p=g.solve(false); if (settings::verbose>3) cerr << "solved as:\n" << p << "\n\n"; return p; } void print(ostream& out) const; side printLocation() const { int n = length; return subguide(n-1)->printLocation(); } }; struct cycleToken : public gc {}; // A guide representing the cycle token. class cycletokguide : public guide { public: void flatten(flatguide& g, bool allowsolve=true) { // If cycles occur in the midst of a guide, the guide up to that point // should be solved as a path. Any subsequent guide will work with that // path locked in place. if(allowsolve) g.solve(true); else g.close(); } bool cyclic() {return true;} path solve() { // Just a cycle on it's own makes an empty guide. return path(); } void print(ostream& out) const { out << "cycle"; } side printLocation() const { return END; } }; } // namespace camp GC_DECLARE_PTRFREE(camp::pairguide); GC_DECLARE_PTRFREE(camp::tensionSpecifier); GC_DECLARE_PTRFREE(camp::tensionguide); GC_DECLARE_PTRFREE(camp::curlSpecifier); GC_DECLARE_PTRFREE(camp::controlguide); GC_DECLARE_PTRFREE(camp::cycleToken); GC_DECLARE_PTRFREE(camp::cycletokguide); #endif // GUIDE_H asymptote-2.37/guideflags.h000066400000000000000000000004521265434602500157650ustar00rootroot00000000000000/***** * guideflags.h * Tom Prince 2004/5/12 * * These flags are used to indicate what specifications of the join are * put on the stack. *****/ #ifndef GUIDEFLAGS_H #define GUIDEFLAGS_H namespace camp { #undef OUT #undef IN enum side { OUT, IN, END, JOIN }; } #endif //GUIDEFLAGS_H asymptote-2.37/impdatum.cc000066400000000000000000000307101265434602500156310ustar00rootroot00000000000000#include #include "stack.h" #include "env.h" #include "exp.h" #include "stm.h" #include "refaccess.h" using std::strlen; using namespace absyntax; using namespace trans; using vm::item; using vm::get; #include "policy.h" coenv &coenvInOngoingProcess(); void runInOngoingProcess(absyntax::runnable *r); void runExp(absyntax::exp *e) { absyntax::expStm s(nullPos, e); runInOngoingProcess(&s); } class ImpDatum; class ImpArguments; ImpDatum *datumError(const char *msg); // Expression used for non-item datums. class errorExp : public absyntax::exp { public: errorExp() : exp(nullPos) {} void prettyprint(ostream &out, Int indent) { absyntax::prettyname(out, "errorExp", indent); } void complain() { em.error(nullPos); em << "cannot use datum as expression"; } types::ty *getType(coenv &) { return types::primError(); } types::ty *trans(coenv &e) { complain(); return getType(e); } void transAsType(coenv &e, types::ty *target) { complain(); } }; // Abstract base class for Datum types. class ImpDatum { public: virtual operator handle_typ() { return (handle_typ)(this); } virtual int_typ toInt() { datumError("cannot convert to integer"); // Return a weird value that will hopefully be noticed. return -777777; } virtual bool toBool() { datumError("cannot convert to bool"); return false; } virtual double toDouble() { datumError("cannot convert to double"); return -777e77; } virtual string_typ toString() { datumError("cannot convert to string"); string_typ s = { "XXXXX", 5 }; return s; } virtual absyntax::exp *getExp() { datumError("invalid use of datum"); return new errorExp; } // How to access a field of the datum. virtual absyntax::exp *getFieldExp(symbol id) { assert(id); return new fieldExp(nullPos, this->getExp(), id); } virtual ImpDatum *getField(const char *name); virtual ImpDatum *getCell(ImpDatum *index) { return datumError("cannot index datatype"); } virtual void addField(const char *name, ImpDatum *init) { datumError("cannot set field of datatype"); } }; // An ever-growing list of handles, used to avoid garbage collecting the data. // TODO: Implement effective releaseHandle. mem::vector handles; handle_typ wrap(ImpDatum *d) { handle_typ h = (handle_typ)(d); handles.push_back(h); return h; } ImpDatum *unwrap(handle_typ handle) { assert(handle != 0); return (ImpDatum *)(handle); } class ErrorDatum : public ImpDatum { }; error_callback_typ errorCallback = 0; ImpDatum *datumError(const char *msg) { static ErrorDatum ed; if (errorCallback) { string_typ s = { msg, strlen(msg) }; errorCallback(s); } else { cerr << msg << '\n'; } return &ed; } handle_typ imp_copyHandle(handle_typ handle) { //cout << "+"; // For now, don't do anything. return handle; } void imp_releaseHandle() { //cout << "-"; // Do nothing, for now. } // A datum representing a value in Asymptote. Both the runtime representation // of the value and its type are stored. class ItemDatum : public ImpDatum { item i; types::ty *t; public: // Every itemDatum has a fixed (non-overloaded) type, t ItemDatum(types::ty *t) : t(t) { assert(t); assert(t->isNotOverloaded()); assert(t->isNotError()); } // An expression that can be used to get and set the datum. // The value should only be set once, when the datum is created, and not // changed. absyntax::exp *getExp() { // It may be faster to create this once on start, but then the datum will // require more space. For now, we create the access and expression on // demand. return new varEntryExp(nullPos, t, new itemRefAccess(&i)); } int_typ toInt() { // TODO: Decide if we want to use casting. if (t->kind == types::ty_Int) return static_cast(get(i)); else return ImpDatum::toInt(); } bool toBool() { if (t->kind == types::ty_boolean) return get(i); else return ImpDatum::toBool(); } double toDouble() { if (t->kind == types::ty_real) return get(i); else return ImpDatum::toDouble(); } string_typ toString() { if (t->kind == types::ty_string) { // TODO: Fix for strings containing NUL. string *s = get(i); string_typ st = { s->c_str(), s->length() }; return st; } else return ImpDatum::toString(); } }; ItemDatum *ItemDatumFromExp(types::ty *t, absyntax::exp *e) { ItemDatum *d = new ItemDatum(t); assignExp ae(nullPos, d->getExp(), e); runExp(&ae); return d; } ItemDatum *ItemDatumFromInt(int_typ x) { intExp ie(nullPos, static_cast(x)); return ItemDatumFromExp(types::primInt(), &ie); } ItemDatum *ItemDatumFromBool(bool x) { booleanExp be(nullPos, x); return ItemDatumFromExp(types::primBoolean(), &be); } ItemDatum *ItemDatumFromDouble(double x) { realExp re(nullPos, x); return ItemDatumFromExp(types::primReal(), &re); } ItemDatum *ItemDatumFromString(string_typ x) { mem::string s(x.buf, (size_t)x.length); stringExp se(nullPos, s); return ItemDatumFromExp(types::primString(), &se); } // If the interface is asked to return a field which is overloaded, a handle // to and OverloadedDatum is returned. No evaluation actually occurs. The // datum simply consists of the containing datum and the name of the field // requested. Subsequent use of the datum will resolve the overloading (or // report an error). class OverloadedDatum : public ImpDatum { ImpDatum *parent; symbol id; public: OverloadedDatum(ImpDatum *parent, symbol id) : parent(parent), id(id) { assert(parent); assert(id); } absyntax::exp *getExp() { return parent->getFieldExp(id); return new fieldExp(nullPos, parent->getExp(), id); } }; ImpDatum *ImpDatum::getField(const char *name) { coenv &e = coenvInOngoingProcess(); symbol id = symbol::trans(name); absyntax::exp *ex = getFieldExp(id); types::ty *t = ex->getType(e); if (t->isError()) return datumError("no field of that name"); if (t->isOverloaded()) return new OverloadedDatum(this, id); // Create a new datum and assign the variable to it. ItemDatum *d = new ItemDatum(t); assignExp ae(nullPos, d->getExp(), ex); runExp(&ae); return d; } handle_typ imp_handleFromInt(int_typ x) { return wrap(ItemDatumFromInt(x)); } handle_typ imp_handleFromBool(int_typ x) { if (x != 0 && x != 1) return wrap(datumError("invalid boolean value")); return wrap(ItemDatumFromBool(x == 1)); } handle_typ imp_handleFromDouble(double x) { return wrap(ItemDatumFromDouble(x)); } int_typ imp_IntFromHandle(handle_typ handle) { return unwrap(handle)->toInt(); } int_typ imp_boolFromHandle(handle_typ handle) { return unwrap(handle)->toBool() ? 1 : 0; } double imp_doubleFromHandle(handle_typ handle) { return unwrap(handle)->toDouble(); } handle_typ imp_handleFromString(string_typ x) { return wrap(ItemDatumFromString(x)); } string_typ imp_stringFromHandle(handle_typ handle) { return unwrap(handle)->toString(); } handle_typ imp_getField(handle_typ handle, const char *name) { return wrap(unwrap(handle)->getField(name)); } handle_typ imp_getCell(handle_typ handle, handle_typ index) { return wrap(unwrap(handle)->getCell(unwrap(index))); } void imp_addField(handle_typ handle, const char *name, handle_typ init) { unwrap(handle)->addField(name, unwrap(init)); } class ImpArguments /* TODO: gc visible but not collected */ { arglist args; public: ImpArguments() {} void add(const char *name, ImpDatum *arg, arg_rest_option isRest) { assert(isRest == NORMAL_ARG); // TODO: Implement rest. symbol id = (name && name[0]) ? symbol::trans(name) : symbol::nullsym; args.add(arg->getExp(), id); } arglist *getArgs() { return &args; } }; arguments_typ wrapArgs(ImpArguments *args) { return (arguments_typ)(args); } ImpArguments *unwrapArgs(arguments_typ args) { return (ImpArguments *)(args); } arguments_typ imp_newArguments() { return wrapArgs(new ImpArguments); } void imp_releaseArguments(arguments_typ args) { // For now, do nothing. } void imp_addArgument(arguments_typ args, const char *name, handle_typ handle, arg_rest_option isRest) { unwrapArgs(args)->add(name, unwrap(handle), isRest); } ImpDatum *callDatum(ImpDatum *callee, ImpArguments *args) { coenv &e = coenvInOngoingProcess(); callExp callex(nullPos, callee->getExp(), args->getArgs()); types::ty *t = callex.getType(e); if (t->isError()) { // Run for errors. runExp(&callex); em.sync(); return datumError("invalid call"); } assert(t->isNotOverloaded()); // Calls are never overloaded. if (t->kind == types::ty_void) { // Execute the call and return 0 to indicate void. runExp(&callex); return 0; } else return ItemDatumFromExp(t, &callex); } handle_typ imp_call(handle_typ callee, arguments_typ args) { return wrap(callDatum(unwrap(callee), unwrapArgs(args))); } class GlobalsDatum : public ImpDatum { typedef std::map gmap; gmap base; virtual absyntax::exp *getFieldExp(symbol id) { // Fields of the globals datum are global variables. Use the unqualified // name. return new nameExp(nullPos, id); } virtual void addField(const char *name, ImpDatum *init) { datumError("addField not yet re-implemented"); } }; class ImpState { //ImpArguments *params; ImpDatum *retval; public: ImpState() : retval(0) {} ImpDatum *globals() { return new GlobalsDatum(); } int_typ numParams() { /*if (params) return params->val.size(); else */ { datumError("parameters accessed outside of function"); return 0; } } ImpDatum *getParam(int_typ index) { /*if (params) { if (index >= 0 && index < static_cast(params->val.size())) return params->val[index]; else return datumError("invalid index for parameter"); } else */ { return datumError("parameters accessed outside of function"); } } void setReturnValue(ImpDatum *retval) { /*if (params) { if (this->retval) datumError("return value set more than once"); else this->retval = retval; } else */ { datumError("return value set outside of function"); } } ImpDatum *getReturnValue() { return retval; } }; state_typ wrapState(ImpState *s) { return (state_typ)(s); } ImpState *unwrapState(state_typ s) { return (ImpState *)(s); } handle_typ imp_globals(state_typ state) { return wrap(unwrapState(state)->globals()); } int_typ imp_numParams(state_typ state) { return unwrapState(state)->numParams(); } handle_typ imp_getParam(state_typ state, int_typ index) { return wrap(unwrapState(state)->getParam(index)); } void imp_setReturnValue(state_typ state, handle_typ handle) { unwrapState(state)->setReturnValue(unwrap(handle)); } state_typ cheatState() { return wrapState(new ImpState()); } #if 0 class FunctionDatum : public ImpDatum { function_typ f; void *data; public: FunctionDatum(function_typ f, void *data) : f(f), data(data) {} ImpDatum *call(ImpArguments *args) { ImpState state(args); // Call the function. f(wrapState(&state),data); if (state.getReturnValue()) return state.getReturnValue(); else // TODO: Decide on datum for void return. return 0; } }; #endif handle_typ imp_handleFromFunction(const char *signature, function_typ f, void *data) { // TODO: Re-implement. return 0; //wrap(new FunctionDatum(f, data)); } void imp_setErrorCallback(error_callback_typ callback) { errorCallback = callback; } extern policy_typ imp_policy; policy_typ imp_policy = { /* version = */ 101, imp_copyHandle, imp_releaseHandle, imp_handleFromInt, imp_handleFromBool, imp_handleFromDouble, imp_handleFromString, imp_handleFromFunction, imp_IntFromHandle, imp_boolFromHandle, imp_doubleFromHandle, imp_stringFromHandle, imp_getField, imp_getCell, imp_addField, imp_newArguments, imp_releaseArguments, imp_addArgument, imp_call, imp_globals, imp_numParams, imp_getParam, imp_setReturnValue, imp_setErrorCallback, }; // Defined in process.cc void init(bool resetpath=true); extern "C" { policy_typ *_asy_getPolicy() { return &imp_policy; } state_typ _asy_getState() { static state_typ state = cheatState(); // TODO: Make sure this runs once. char buf[] = "asymptote.so"; char *argv [] = { buf }; settings::setOptions(1,argv); // Ensures uptodate is not used. init(); return state; } } asymptote-2.37/inst.h000066400000000000000000000037021265434602500146310ustar00rootroot00000000000000/***** * inst.h * Andy Hammerlindl 2002/06/27 * * Descibes the items and instructions that are used by the virtual machine. *****/ #ifndef INST_H #define INST_H #include #include #include "errormsg.h" #include "item.h" #include "vm.h" namespace vm { // Forward declarations struct inst; class stack; class program; // A function "lambda," that is, the code that runs a function. // It also needs the closure of the enclosing module or function to run. struct lambda : public gc { // The instructions to follow. program *code; // The index of the link to the parent closure in the frame corresponding to // this function. size_t parentIndex; // The total number of items that will be stored in the closure of this // function. Includes a link to the higher closure, the parameters, and the // local variables. // NOTE: In order to help garbage collection, this could be modified to // have one array store escaping items, and another to store non- // escaping items. size_t framesize; // States whether any of the variables escape the function, in which case a // closure needs to be allocated when the function is called. It is // initially set to "maybe" and it is computed the first time the function // is called. enum { NEEDS_CLOSURE, DOESNT_NEED_CLOSURE, MAYBE_NEEDS_CLOSURE} closureReq; #ifdef DEBUG_FRAME string name; lambda() : closureReq(MAYBE_NEEDS_CLOSURE), name("") {} virtual ~lambda() {} #else lambda() : closureReq(MAYBE_NEEDS_CLOSURE) {} #endif }; // The code run is just a string of instructions. The ops are actual commands // to be run, but constants, labels, and other objects can be in the code. struct inst : public gc { enum opcode { #define OPCODE(name,type) name, #include "opcodes.h" #undef OPCODE }; opcode op; position pos; item ref; }; template inline T get(const inst& it) { return get(it.ref); } } // namespace vm #endif asymptote-2.37/install-sh000077500000000000000000000325371265434602500155170ustar00rootroot00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2009-04-28.21; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then trap '(exit $?); exit' 1 2 13 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names starting with `-'. case $src in -*) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # Protect names starting with `-'. case $dst in -*) dst=./$dst;; esac # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writeable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; -*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test -z "$d" && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: asymptote-2.37/interact.cc000066400000000000000000000115301265434602500156210ustar00rootroot00000000000000/***** * interact.cc * * The glue between the lexical analyzer and the readline library. *****/ #include #include #include #include #include #include #include #include #include #include #include "interact.h" #include "runhistory.h" #if defined(HAVE_LIBREADLINE) && defined(HAVE_LIBCURSES) #include #include #endif #include "util.h" #include "errormsg.h" using namespace settings; namespace run { void init_readline(bool); } namespace interact { bool interactive=false; bool uptodate=true; int lines=0; bool query=false; bool tty=isatty(STDIN_FILENO); completer *currentCompleter=0; void setCompleter(completer *c) { currentCompleter=c; } char *call_completer(const char *text, int state) { return currentCompleter ? (*currentCompleter)(text, state) : 0; } #if defined(HAVE_LIBREADLINE) && defined(HAVE_LIBCURSES) void init_completion() { rl_completion_entry_function=call_completer; rl_completion_append_character='\0'; // Don't add a space after a match. /* // Build a string containing all characters that separate words to be // completed. All characters that can't form part of an identifier are // treated as break characters. static char break_characters[128]; Int j=0; for (unsigned char c=9; c < 128; ++c) if (!isalnum(c) && c != '_') { break_characters[j]=c; ++j; } break_characters[j]='\0'; rl_completer_word_break_characters=break_characters; */ } #endif char *(*Readline)(const char *prompt); char *readverbatimline(const char *prompt) { if(!cin.good()) {cin.clear(); return NULL;} cout << prompt; string s; getline(cin,s); return StrdupMalloc(s); } FILE *fin=NULL; char *readpipeline(const char *prompt) { #if _POSIX_VERSION >= 200809L char *line=NULL; size_t n=0; return getline(&line,&n,fin) >= 0 ? line : NULL; #else const int max_size=256; static char buf[max_size]; ostringstream s; do { if(fgets(buf,max_size-1,fin) == NULL) break; s << buf; } while(buf[std::strlen(buf)-1] != '\n'); return StrdupMalloc(s.str()); #endif } void pre_readline() { int fd=intcast(settings::getSetting("inpipe")); if(fd >= 0) { if(!fin) fin=fdopen(fd,"r"); Readline=readpipeline; } else { #if defined(HAVE_LIBREADLINE) && defined(HAVE_LIBCURSES) if(tty) { Readline=readline; } else #endif Readline=readverbatimline; } } void init_interactive() { #if defined(HAVE_LIBREADLINE) && defined(HAVE_LIBCURSES) if(tty) { init_completion(); run::init_readline(getSetting("tabcompletion")); read_history(historyname.c_str()); } #endif } string simpleline(string prompt) { // Rebind tab key, as the setting tabcompletion may be changed at runtime. pre_readline(); Signal(SIGINT,SIG_IGN); // Get a line from the user. char *line=Readline(prompt.c_str()); Signal(SIGINT,interruptHandler); // Reset scroll count. interact::lines=0; interact::query=tty; // Ignore keyboard interrupts while taking input. errorstream::interrupt=false; if(line) { string s=line; free(line); return s; } else { cout << endl; if(!tty || getSetting("exitonEOF")) throw eof(); return "\n"; } } void addToHistory(string line) { #if defined(HAVE_LIBREADLINE) && defined(HAVE_LIBCURSES) // Only add it if it has something other than newlines. if(tty && line.find_first_not_of('\n') != string::npos) { add_history(line.c_str()); } #endif } string getLastHistoryLine() { #if defined(HAVE_LIBREADLINE) && defined(HAVE_LIBCURSES) if(tty && history_length > 0) { HIST_ENTRY *entry=history_list()[history_length-1]; if(!entry) { em.compiler(); em << "cannot access last history line"; return ""; } else return entry->line; } else #endif return ""; } void setLastHistoryLine(string line) { #if defined(HAVE_LIBREADLINE) && defined(HAVE_LIBCURSES) if(tty) { if (history_length > 0) { HIST_ENTRY *entry=remove_history(history_length-1); if(!entry) { em.compiler(); em << "cannot modify last history line"; } else { free(entry->line); free(entry); } } addToHistory(line); } #endif } void deleteLastLine() { #if defined(HAVE_LIBREADLINE) && defined(HAVE_LIBCURSES) if(tty) { HIST_ENTRY *entry=remove_history(history_length-1); if(!entry) { em.compiler(); em << "cannot delete last history line"; } else { free(entry->line); free(entry); } } #endif } void cleanup_interactive() { #if defined(HAVE_LIBREADLINE) && defined(HAVE_LIBCURSES) // Write the history file. if(tty) { stifle_history(intcast(getSetting("historylines"))); write_history(historyname.c_str()); } #endif } } // namespace interact asymptote-2.37/interact.h000066400000000000000000000024351265434602500154670ustar00rootroot00000000000000/***** * interact.h * * The glue between the lexical analyzer and the readline library. *****/ #ifndef INTERACT_H #define INTERACT_H #include "common.h" void interruptHandler(int); namespace interact { extern bool interactive; extern bool uptodate; extern int lines; // Interactive scroll count extern bool query; // Enable interactive scrolling; void init_interactive(); // Read a line from the input, without any processing. string simpleline(string prompt); // Add a line of input to the readline history. void addToHistory(string line); // Functions to work with the most recently entered line in the history. string getLastHistoryLine(); void setLastHistoryLine(string line); // Remove the line last added to the history. void deleteLastLine(); // Write out the history of input lines to the history file. void cleanup_interactive(); // This class is used to set a text completion function for readline. A class // is used instead the usual function pointer so that information such as the // current environment can be coded into the function (mimicking a closure). class completer { public: virtual ~completer() {}; virtual char *operator () (const char *text, int state) = 0; }; void setCompleter(completer *c); #define YY_READ_BUF_SIZE YY_BUF_SIZE } #endif // INTERACT_H asymptote-2.37/item.h000066400000000000000000000133411265434602500146120ustar00rootroot00000000000000/***** * inst.h * Tom Prince and John Bowman 2005/04/12 * * Descibes the items that are used by the virtual machine. *****/ #ifndef ITEM_H #define ITEM_H #include "common.h" #include #include #if COMPACT #include #else #include #endif namespace vm { class item; class bad_item_value {}; template T get(const item&); #if COMPACT // Identify a default argument. extern const Int DefaultValue; // Identify an undefined item. extern const Int Undefined; // Values for true and false unlikely to match other values. extern const Int BoolTruthValue; extern const Int BoolFalseValue; inline Int valueFromBool(bool b) { return b ? BoolTruthValue : BoolFalseValue; } #endif extern const item Default; class item : public gc { private: #if !COMPACT const std::type_info *kind; #endif union { Int i; double x; #if !COMPACT bool b; #endif void *p; }; public: #if COMPACT bool empty() const {return i >= Undefined;} item() : i(Undefined) {} item(Int i) : i(i) {} item(int i) : i(i) {} item(double x) : x(x) {} item(bool b) : i(valueFromBool(b)) {} item& operator= (int a) { i=a; return *this; } item& operator= (unsigned int a) { i=a; return *this; } item& operator= (Int a) { i=a; return *this; } item& operator= (double a) { x=a; return *this; } item& operator= (bool b) { i=valueFromBool(b); return *this; } template item(T *p) : p((void *) p) { assert(!empty()); } template item(const T &p) : p(new(UseGC) T(p)) { assert(!empty()); } template item& operator= (T *a) { p=(void *) a; return *this; } template item& operator= (const T &it) { p=new(UseGC) T(it); return *this; } #else bool empty() const {return *kind == typeid(void);} item() : kind(&typeid(void)) {} item(Int i) : kind(&typeid(Int)), i(i) {} item(int i) : kind(&typeid(Int)), i(i) {} item(double x) : kind(&typeid(double)), x(x) {} item(bool b) : kind(&typeid(bool)), b(b) {} item& operator= (int a) { kind=&typeid(Int); i=a; return *this; } item& operator= (unsigned int a) { kind=&typeid(Int); i=a; return *this; } item& operator= (Int a) { kind=&typeid(Int); i=a; return *this; } item& operator= (double a) { kind=&typeid(double); x=a; return *this; } item& operator= (bool a) { kind=&typeid(bool); b=a; return *this; } template item(T *p) : kind(&typeid(T)), p((void *) p) {} template item(const T &p) : kind(&typeid(T)), p(new(UseGC) T(p)) {} template item& operator= (T *a) { kind=&typeid(T); p=(void *) a; return *this; } template item& operator= (const T &it) { kind=&typeid(T); p=new(UseGC) T(it); return *this; } const std::type_info &type() const { return *kind; } #endif template friend inline T get(const item&); friend inline bool isdefault(const item&); friend ostream& operator<< (ostream& out, const item& i); private: template struct help; template struct help { static T* unwrap(const item& it) { #if COMPACT if(!it.empty()) return (T*) it.p; #else if(*it.kind == typeid(T)) return (T*) it.p; #endif throw vm::bad_item_value(); } }; template struct help { static T& unwrap(const item& it) { #if COMPACT if(!it.empty()) return *(T*) it.p; #else if(*it.kind == typeid(T)) return *(T*) it.p; #endif throw vm::bad_item_value(); } }; }; #ifdef SIMPLE_FRAME // In the simple implementation, a frame is just an array of items. typedef item frame; #else class frame : public gc { #ifdef DEBUG_FRAME string name; Int parentIndex; #endif typedef mem::vector internal_vars_t; internal_vars_t vars; // Allow the stack direct access to vars. friend class stack; public: #ifdef DEBUG_FRAME frame(string name, Int parentIndex, size_t size) : name(name), parentIndex(parentIndex), vars(size) {} string getName() { return name; } Int getParentIndex() { return parentIndex; } #else frame(size_t size) : vars(size) {} #endif item& operator[] (size_t n) { return vars[n]; } item operator[] (size_t n) const { return vars[n]; } size_t size() { return vars.size(); } // Extends vars to ensure it has a place for any variable indexed up to n. void extend(size_t n) { if(vars.size() < n) vars.resize(n); } }; #endif template inline T get(const item& it) { return item::help::unwrap(it); } template <> inline int get(const item&) { throw vm::bad_item_value(); } template <> inline Int get(const item& it) { #if COMPACT if(!it.empty()) return it.i; #else if(*it.kind == typeid(Int)) return it.i; #endif throw vm::bad_item_value(); } template <> inline double get(const item& it) { #if COMPACT if(!it.empty()) return it.x; #else if(*it.kind == typeid(double)) return it.x; #endif throw vm::bad_item_value(); } template <> inline bool get(const item& it) { #if COMPACT if(it.i == BoolTruthValue) return true; if(it.i == BoolFalseValue) return false; #else if(*it.kind == typeid(bool)) return it.b; #endif throw vm::bad_item_value(); } #if !COMPACT // This serves as the object for representing a default argument. struct default_t : public gc {}; #endif inline bool isdefault(const item& it) { #if COMPACT return it.i == DefaultValue; #else return *it.kind == typeid(default_t); #endif } ostream& operator<< (ostream& out, const item& i); } // namespace vm #endif // ITEM_H asymptote-2.37/keywords.pl000077500000000000000000000023451265434602500157140ustar00rootroot00000000000000#!/usr/bin/env perl ##### # keywords.pl # Andy Hammerlindl 2006/07/31 # # Extract keywords from camp.l and list them in a keywords file. These # keywords are used in autocompletion at the interactive prompt. ##### # Extra keywords to add that aren't automatically extracted, currently none. @extrawords = (); open(keywords, ">keywords.cc") || die("Couldn't open keywords.out for writing."); print keywords <) { if (/^%%\s*$/) { last; # Break out of the loop. } } # Grab simple keyword definitions from camp.l while () { if (/^%%\s*$/) { last; # A second %% indicates the end of definitions. } if (/^([A-Za-z_][A-Za-z0-9_]*)\s*\{/) { add($1); } } # Grab the special commands from the interactive prompt. open(process, "process.cc") || dir("Couldn't open process.cc"); while () { if (/^\s*ADDCOMMAND\(\s*([A-Za-z_][A-Za-z0-9_]*),/) { add($1); } } asymptote-2.37/knot.cc000066400000000000000000000535231265434602500147730ustar00rootroot00000000000000/***** * knot.cc * Andy Hammerlindl 2005/02/10 * * Describes a knot, a point and its neighbouring specifiers, used as an * intermediate structure in solving paths. *****/ #include "knot.h" #include "util.h" #include "angle.h" #include "settings.h" namespace camp { /***** Debugging *****/ //bool tracing_solving=false; template ostream& info(ostream& o, const char *name, cvector& v) { if (settings::verbose > 3) { o << name << ":\n\n"; for(Int i=0; i < (Int) v.size(); ++i) o << v[i] << endl; o << endl; } return o; } ostream& info(ostream& o, string name, knotlist& l) { if (settings::verbose > 3) { o << name << ":\n\n"; for(Int i=0; i < (Int) l.size(); ++i) o << l[i] << endl; if (l.cyclic()) o << "cyclic" << endl; o << endl; } return o; } #define INFO(x) info(cerr,#x,x) /***** Auxillary computation functions *****/ // Computes the relative distance of a control point given the angles. // The name is somewhat misleading as the velocity (with respect to the // variable that parameterizes the path) is relative to the distance // between the knots and even then, is actually three times this. // The routine is based on the velocity function in Section 131 of the MetaPost // code, but differs in that it automatically accounts for the tension and // bounding with tension atleast. double velocity(double theta, double phi, tension t) { static const double VELOCITY_BOUND = 4.0; static const double a = sqrt(2.0); static const double b = 1.0/16.0; static const double c = 1.5*(sqrt(5.0)-1.0); static const double d = 1.5*(3.0-sqrt(5.0)); double st = sin(theta), ct = cos(theta), sf = sin(phi), cf = cos(phi); double denom = t.val * (3.0 + c*ct + d*cf); double r = denom != 0.0 ? (2.0 + a*(st - b*sf)*(sf - b*st)*(ct-cf)) / denom : VELOCITY_BOUND; //cerr << " velocity(" << theta << "," << phi <<")= " << r << endl; if (r > VELOCITY_BOUND) r = VELOCITY_BOUND; // Apply boundedness condition for tension atleast cases. if (t.atleast) { double sine = sin(theta + phi); if ((st >= 0.0 && sf >= 0.0 && sine > 0.0) || (st <= 0.0 && sf <= 0.0 && sine < 0.0)) { double rmax = sf / sine; if (r > rmax) r = rmax; } } return r; } double niceAngle(pair z) { return z.gety() == 0 ? z.getx() >= 0 ? 0 : PI : angle(z); } // Ensures an angle is in the range between -PI and PI. double reduceAngle(double angle) { return angle > PI ? angle - 2.0*PI : angle < -PI ? angle + 2.0*PI : angle; } bool interesting(tension t) { return t.val!=1.0 || t.atleast==true; } bool interesting(spec *s) { return !s->open(); } ostream& operator<<(ostream& out, const knot& k) { if (interesting(k.tin)) out << k.tin << " "; if (interesting(k.in)) out << *k.in << " "; out << k.z; if (interesting(k.out)) out << " " << *k.out; if (interesting(k.tout)) out << " " << k.tout; return out; } eqn dirSpec::eqnOut(Int j, knotlist& l, cvector&, cvector&) { // When choosing the control points, the path will come out the first knot // going straight to the next knot rotated by the angle theta. // Therefore, the angle theta we want is the difference between the // specified heading given and the heading to the next knot. double theta=reduceAngle(given-niceAngle(l[j+1].z-l[j].z)); // Give a simple linear equation to ensure this theta is picked. return eqn(0.0,1.0,0.0,theta); } eqn dirSpec::eqnIn(Int j, knotlist& l, cvector&, cvector&) { double theta=reduceAngle(given-niceAngle(l[j].z-l[j-1].z)); return eqn(0.0,1.0,0.0,theta); } eqn curlSpec::eqnOut(Int j, knotlist& l, cvector&, cvector& psi) { double alpha=l[j].alpha(); double beta=l[j+1].beta(); double chi=alpha*alpha*gamma/(beta*beta); double C=alpha*chi+3-beta; double D=(3.0-alpha)*chi+beta; return eqn(0.0,C,D,-D*psi[j+1]); } eqn curlSpec::eqnIn(Int j, knotlist& l, cvector&, cvector&) { double alpha=l[j-1].alpha(); double beta=l[j].beta(); double chi=beta*beta*gamma/(alpha*alpha); double A=(3-beta)*chi+alpha; double B=beta*chi+3-alpha; return eqn(A,B,0.0,0.0); } spec *controlSpec::outPartner(pair z) { static curlSpec curl; return cz==z ? (spec *)&curl : (spec *)new dirSpec(z-cz); } spec *controlSpec::inPartner(pair z) { static curlSpec curl; return cz==z ? (spec *)&curl : (spec *)new dirSpec(cz-z); } // Compute the displacement between points. The j-th result is the distance // between knot j and knot j+1. struct dzprop : public knotprop { dzprop(knotlist& l) : knotprop(l) {} pair solo(Int) { return pair(0,0); } pair start(Int j) { return l[j+1].z - l[j].z; } pair mid(Int j) { return l[j+1].z - l[j].z; } pair end(Int) { return pair(0,0); } }; // Compute the distance between points, using the already computed dz. This // doesn't use the infomation in the knots, but the knotprop class is useful as // it takes care of the iteration for us. struct dprop : public knotprop { cvector& dz; dprop(knotlist &l, cvector& dz) : knotprop(l), dz(dz) {} double solo(Int j) { return length(dz[j]); } double start(Int j) { return length(dz[j]); } double mid(Int j) { return length(dz[j]); } double end(Int j) { return length(dz[j]); } }; // Compute the turning angles (psi) between points, using the already computed // dz. struct psiprop : public knotprop { cvector& dz; psiprop(knotlist &l, cvector& dz) : knotprop(l), dz(dz) {} double solo(Int) { return 0; } // We set the starting and ending psi to zero. double start(Int) { return 0; } double end(Int) { return 0; } double mid(Int j) { return niceAngle(dz[j]/dz[j-1]); } }; struct eqnprop : public knotprop { cvector& d; cvector& psi; eqnprop(knotlist &l, cvector& d, cvector& psi) : knotprop(l), d(d), psi(psi) {} eqn solo(Int) { assert(False); return eqn(0.0,1.0,0.0,0.0); } eqn start(Int j) { // Defer to the specifier, as it knows the specifics. return dynamic_cast(l[j].out)->eqnOut(j,l,d,psi); } eqn end(Int j) { return dynamic_cast(l[j].in)->eqnIn(j,l,d,psi); } eqn mid(Int j) { double lastAlpha = l[j-1].alpha(); double thisAlpha = l[j].alpha(); double thisBeta = l[j].beta(); double nextBeta = l[j+1].beta(); // Values based on the linear approximation of the curvature coming // into the knot with respect to theta[j-1] and theta[j]. double inFactor = 1.0/(thisBeta*thisBeta*d[j-1]); double A = lastAlpha*inFactor; double B = (3.0 - lastAlpha)*inFactor; // Values based on the linear approximation of the curvature going out of // the knot with respect to theta[j] and theta[j+1]. double outFactor = 1.0/(thisAlpha*thisAlpha*d[j]); double C = (3.0 - nextBeta)*outFactor; double D = nextBeta*outFactor; return eqn(A,B+C,D,-B*psi[j]-D*psi[j+1]); } }; // If the system of equations is homogeneous (ie. we are solving for x in // Ax=0), there is no need to solve for theta; we can just use zeros for the // thetas. In fact, our general solving method may not work in this case. // A common example of this is // // a{curl 1}..{curl 1}b // // which arises when solving a one-length path a..b or in a larger path a // section a--b. bool homogeneous(cvector& e) { for(cvector::iterator p=e.begin(); p!=e.end(); ++p) if (p->aug != 0) return false; return true; } // Checks whether the equation being solved will be solved as a straight // path from the first point to the second. bool straightSection(cvector& e) { return e.size()==2 && e.front().aug==0 && e.back().aug==0; } struct weqn : public eqn { double w; weqn(double pre, double piv, double post, double aug, double w=0) : eqn(pre,piv,post,aug), w(w) {} friend ostream& operator<< (ostream& out, const weqn we) { return out << (eqn &)we << " + " << we.w << " * theta[0]"; } }; weqn scale(weqn q) { assert(q.pre == 0 && q.piv != 0); return weqn(0,1,q.post/q.piv,q.aug/q.piv,q.w/q.piv); } /* Recalculate the equations in the form: * theta[j] + post * theta[j+1] = aug + w * theta[0] * * Used as the first step in solve cyclic equations. */ cvector recalc(cvector& e) { Int n=(Int) e.size(); cvector we; weqn lasteqn(0,1,0,0,1); we.push_back(lasteqn); // As a placeholder. for (Int j=1; j < n; j++) { // Subtract a factor of the last equation so that the first entry is // zero, then procede to scale it. eqn& q=e[j]; lasteqn=scale(weqn(0,q.piv-q.pre*lasteqn.post,q.post, q.aug-q.pre*lasteqn.aug,-q.pre*lasteqn.w)); we.push_back(lasteqn); } // To keep all of the infomation enocoded in the linear equations, we need // to augment the computation to replace our trivial start weqn with a // real one. To do this, we take one more step in the iteration and // compute the weqn for j=n, since n=0 (mod n). { eqn& q=e[0]; we.front()=scale(weqn(0,q.piv-q.pre*lasteqn.post,q.post, q.aug-q.pre*lasteqn.aug,-q.pre*lasteqn.w)); } return we; } double solveForTheta0(cvector& we) { // Solve for theta[0]=theta[n]. // How we do this is essentially to write out the first equation as: // // theta[n] = aug[0] + w[0]*theta[0] - post[0]*theta[1] // // and then use the next equation to substitute in for theta[1]: // // theta[1] = aug[1] + w[1]*theta[0] - post[1]*theta[2] // // and so on until we have an equation just in terms of theta[0] and // theta[n] (which are the same theta). // // The loop invariant maintained is that after j iterations, we have // theta[n]= a + b*theta[0] + c*theta[j] Int n=(Int) we.size(); double a=0,b=0,c=1; for (Int j=0;j backsubCyclic(cvector& we, double theta0) { Int n=(Int) we.size(); cvector thetas; double lastTheta=theta0; for (Int j=1;j<=n;++j) { weqn& q=we[n-j]; assert(q.pre == 0 && q.piv == 1); double theta=-q.post*lastTheta+q.aug+q.w*theta0; thetas.push_back(theta); lastTheta=theta; } reverse(thetas.begin(),thetas.end()); return thetas; } // For the non-cyclic equations, do row operation to put the matrix into // reduced echelon form, ie. calculates equivalent equations but with pre=0 and // piv=1 for each eqn. struct ref : public knotprop { cvector& e; eqn lasteqn; ref(knotlist& l, cvector& e) : knotprop(l), e(e), lasteqn(0,1,0,0) {} // Scale the equation so that the pivot (diagonal) entry is one, and save // the new equation as lasteqn. eqn scale(eqn q) { assert(q.pre == 0 && q.piv != 0); return lasteqn = eqn(0,1,q.post/q.piv,q.aug/q.piv); } eqn start(Int j) { return scale(e[j]); } eqn mid(Int j) { // Subtract a factor of the last equation so that the first entry is // zero, then procede to scale it. eqn& q=e[j]; return scale(eqn(0,q.piv-q.pre*lasteqn.post,q.post, q.aug-q.pre*lasteqn.aug)); } // The end case is the same as the middle case. }; // Once the matrix is in reduced echelon form, we can solve for the values by // back-substitution. This algorithm works from the bottom-up, so backCompute // must be used to get the answer. struct backsub : public knotprop { cvector& e; double lastTheta; backsub(knotlist& l, cvector& e) : knotprop(l), e(e) {} double end(Int j) { eqn& q=e[j]; assert(q.pre == 0 && q.piv == 1 && q.post == 0); double theta=q.aug; lastTheta=theta; return theta; } double mid(Int j) { eqn& q=e[j]; assert(q.pre == 0 && q.piv == 1); double theta=-q.post*lastTheta+q.aug; lastTheta=theta; return theta; } // start is the same as mid. }; // Once the equations have been determined, solve for the thetas. cvector solveThetas(knotlist& l, cvector& e) { if (homogeneous(e)) // We are solving Ax=0, so a solution is zero for every theta. return cvector(e.size(),0); else if (l.cyclic()) { // The knotprop template is unusually unhelpful in this case, so I // won't use it here. The algorithm breaks into three passes on the // object. The old Asymptote code used a two-pass method, but I // implemented this to stay closer to the MetaPost source code. // This might be something to look at for optimization. cvector we=recalc(e); INFO(we); double theta0=solveForTheta0(we); return backsubCyclic(we, theta0); } else { /* Non-cyclic case. */ /* First do row operations to get it into reduced echelon form. */ cvector el=ref(l,e).compute(); /* Then, do back substitution. */ return backsub(l,el).backCompute(); } } // Once thetas have been solved, determine the first control point of every // join. struct postcontrolprop : public knotprop { cvector& dz; cvector& psi; cvector& theta; postcontrolprop(knotlist& l, cvector& dz, cvector& psi, cvector& theta) : knotprop(l), dz(dz), psi(psi), theta(theta) {} double phi(Int j) { /* The third angle: psi + theta + phi = 0 */ return -psi[j] - theta[j]; } double vel(Int j) { /* Use the standard velocity function. */ return velocity(theta[j],phi(j+1),l[j].tout); } // start is the same as mid. pair mid(Int j) { // Put a control point at the relative distance determined by the velocity, // and at an angle determined by theta. return l[j].z + vel(j)*expi(theta[j])*dz[j]; } // The end postcontrol is the same as the last knot. pair end(Int j) { return l[j].z; } }; // Determine the first control point of every join. struct precontrolprop : public knotprop { cvector& dz; cvector& psi; cvector& theta; precontrolprop(knotlist& l, cvector& dz, cvector& psi, cvector& theta) : knotprop(l), dz(dz), psi(psi), theta(theta) {} double phi(Int j) { return -psi[j] - theta[j]; } double vel(Int j) { return velocity(phi(j),theta[j-1],l[j].tin); } // The start precontrol is the same as the first knot. pair start(Int j) { return l[j].z; } pair mid(Int j) { return l[j].z - vel(j)*expi(-phi(j))*dz[j-1]; } // end is the same as mid. }; // Puts solved controls into a protopath starting at the given index. // By convention, the first knot is not coded, as it is assumed to be coded by // the previous section (or it is the first breakpoint and encoded as a special // case). struct encodeControls : public knoteffect { protopath& p; Int k; cvector& pre; cvector& post; encodeControls(protopath& p, Int k, cvector& pre, knotlist& l, cvector& post) : knoteffect(l), p(p), k(k), pre(pre), post(post) {} void encodePre(Int j) { p.pre(k+j)=pre[j]; } void encodePoint(Int j) { p.point(k+j)=l[j].z; } void encodePost(Int j) { p.post(k+j)=post[j]; } void solo(Int) { #if 0 encodePoint(j); #endif } void start(Int j) { #if 0 encodePoint(j); #endif encodePost(j); } void mid(Int j) { encodePre(j); encodePoint(j); encodePost(j); } void end(Int j) { encodePre(j); encodePoint(j); } }; void encodeStraight(protopath& p, Int k, knotlist& l) { pair a=l.front().z; double at=l.front().tout.val; pair b=l.back().z; double bt=l.back().tin.val; pair step=(b-a)/3.0; if (at==1.0 && bt==1.0) { p.straight(k)=true; p.post(k)=a+step; p.pre(k+1)=b-step; p.point(k+1)=b; } else { p.post(k)=a+step/at; p.pre(k+1)=b-step/bt; p.point(k+1)=b; } } void solveSection(protopath& p, Int k, knotlist& l) { if (l.length()>0) { info(cerr, "solving section", l); // Calculate useful properties. cvector dz = dzprop(l) .compute(); cvector d = dprop(l,dz).compute(); cvector psi = psiprop(l,dz).compute(); INFO(dz); INFO(d); INFO(psi); // Build and solve the linear equations for theta. cvector e = eqnprop(l,d,psi).compute(); INFO(e); if (straightSection(e)) // Handle straight section as special case. encodeStraight(p,k,l); else { cvector theta = solveThetas(l,e); INFO(theta); // Calculate the control points. cvector post = postcontrolprop(l,dz,psi,theta).compute(); cvector pre = precontrolprop(l,dz,psi,theta).compute(); // Encode the results into the protopath. encodeControls(p,k,pre,l,post).exec(); } } } // Find the first breakpoint in the knotlist, ie. where we can start solving a // non-cyclic section. If the knotlist is fully cyclic, then this returns // NOBREAK. // This must be called with a knot that has all of its implicit specifiers in // place. const Int NOBREAK=-1; Int firstBreakpoint(knotlist& l) { for (Int j=0;jopen()) return j; return NOBREAK; } // Once a breakpoint, a, is found, find where the next breakpoint after it is. // This must be called with a knot that has all of its implicit specifiers in // place, so that breakpoint can be identified by either an in or out specifier // that is not open. Int nextBreakpoint(knotlist& l, Int a) { // This is guaranteed to terminate if a is the index of a breakpoint. If the // path is non-cyclic it will stop at or before the last knot which must be a // breakpoint. If the path is cyclic, it will stop at or before looping back // around to a which is a breakpoint. Int j=a+1; while (l[j].in->open()) ++j; return j; } // Write out the controls for section of the form // a.. control b and c ..d void writeControls(protopath& p, Int a, knotlist& l) { // By convention, the first point will already be encoded. p.straight(a)=dynamic_cast(l[a].out)->straight; p.post(a)=dynamic_cast(l[a].out)->cz; p.pre(a+1)=dynamic_cast(l[a+1].in)->cz; p.point(a+1)=l[a+1].z; } // Solves a path that has all of its specifiers laid out explicitly. path solveSpecified(knotlist& l) { protopath p(l.size(),l.cyclic()); Int first=firstBreakpoint(l); if (first==NOBREAK) /* We are solving a fully cyclic path, so do it in one swoop. */ solveSection(p,0,l); else { // Encode the first point. p.point(first)=l[first].z; // If the path is cyclic, we should stop where we started (modulo the // length of the path); otherwise, just stop at the end. Int last=l.cyclic() ? first+l.length() : l.length(); Int a=first; while (a!=last) { if (l[a].out->controlled()) { assert(l[a+1].in->controlled()); // Controls are already picked, just write them out. writeControls(p,a,l); ++a; } else { // Find the section a to b and solve it, putting the result (starting // from index a into our protopath. Int b=nextBreakpoint(l,a); subknotlist section(l,a,b); solveSection(p,a,section); a=b; } } // For a non-cyclic path, the end control points need to be set. p.controlEnds(); } return p.fix(); } /* If a knot is open on one side and restricted on the other, this replaces the * open side with a restriction determined by the restriction on the other * side. After this, any knot will either have two open specs or two * restrictions. */ struct partnerUp : public knoteffect { partnerUp(knotlist& l) : knoteffect(l) {} void mid(Int j) { knot& k=l[j]; if (k.in->open() && !k.out->open()) k.in=k.out->inPartner(k.z); else if (!k.in->open() && k.out->open()) k.out=k.in->outPartner(k.z); } }; /* Ensures a non-cyclic path has direction specifiers at the ends, adding curls * if there are none. */ void curlEnds(knotlist& l) { static curlSpec endSpec; if (!l.cyclic()) { if (l.front().in->open()) l.front().in=&endSpec; if (l.back().out->open()) l.back().out=&endSpec; } } /* If a point occurs twice in a row in a knotlist, write in controls * between the two knots at that point (unless it already has controls). */ struct controlDuplicates : public knoteffect { controlDuplicates(knotlist& l) : knoteffect(l) {} void solo(Int) { /* One point ==> no duplicates */ } // start is the same as mid. void mid(Int j) { knot &k1=l[j]; knot &k2=l[j+1]; if (!k1.out->controlled() && k1.z==k2.z) { k1.out=k2.in=new controlSpec(k1.z,true); } } void end(Int) { /* No next point to compare with. */ } }; path solve(knotlist& l) { if (l.empty()) return path(); else { info(cerr, "input knotlist", l); curlEnds(l); controlDuplicates(l).exec(); partnerUp(l).exec(); info(cerr, "specified knotlist", l); return solveSpecified(l); } } // Code for Testing #if 0 path solveSimple(cvector& z) { // The two specifiers used: an open spec and a curl spec for the ends. spec open; // curlSpec curl; // curlSpec curly(2.0); // dirSpec E(0); // dirSpec N(PI/2.0); controlSpec here(pair(150,150)); // Encode the knots as open in the knotlist. cvector nodes; for (cvector::iterator p=z.begin(); p!=z.end(); ++p) { knot k; k.z=*p; k.in=k.out=&open; nodes.push_back(k); } // Substitute in a curl spec for the ends. //nodes.front().out=nodes.back().in=&curl; // Test direction specifiers. //nodes.front().tout=2; //nodes.front().out=nodes.back().in=&curly; //nodes[0].out=nodes[0].in=&E; nodes[1].out=nodes[2].in=&here; simpleknotlist l(nodes,false); return solve(l); } #endif } // namespace camp asymptote-2.37/knot.h000066400000000000000000000300141265434602500146230ustar00rootroot00000000000000/***** * knot.h * Andy Hammerlindl 200/02/10 * * Describes a knot, a point and its neighbouring specifiers, used as an * intermediate structure in solving paths. *****/ #ifndef KNOT_H #define KNOT_H #include #include #include #include "mod.h" #include "pair.h" #include "path.h" namespace camp { using mem::vector; // The choice of branch cuts of atan2 disguishes between y=+0.0 and y=-0.0 in // the case where x<0. This can lead to strange looking paths being // calculated from guides of the form a..b..cycle. To avoid these degenerate // cases, the niceAngle routine moves the branch cut so that the sign of a // zero won't matter. double niceAngle(pair z); // A cyclic vector: ie. a vector where the index is taken mod the size of the // vector. template class cvector : public vector { public: cvector() {} cvector(size_t n) : vector(n) {} cvector(size_t n, const T& t) : vector(n,t) {} cvector(const vector& v) : vector(v) {} T& operator[](Int j) { return vector::operator[](imod(j,(Int) this->size())); } const T& operator[](Int j) const { return vector::operator[](imod(j,(Int) this->size())); } }; // Forward declaration. class knotlist; /* A linear equation (one of a set of equations to solve for direction through knots in a path). The i-th equation is: pre*theta[i-1] + piv*theta[i] + post*theta[i+1] = aug where indices are taken mod n. */ struct eqn { double pre,piv,post,aug; eqn(double pre, double piv, double post, double aug) : pre(pre), piv(piv), post(post), aug(aug) {} friend ostream& operator<< (ostream& out, const eqn& e) { return out << e.pre << " * pre + " << e.piv << " * piv + " << e.post << " * post = " << e.aug; } }; // A direction specifier, telling how the path behaves coming in or out of a // point. The base class represents the "open" specifier. class spec : public gc { public: virtual ~spec() {} // If the knot is open, it gives no restriction on the behavior of the // path. virtual bool open() { return true; } virtual bool controlled() { return false; } virtual pair control() {return pair(0.0,0.0);} virtual double curl() { return -1.0; } virtual pair dir() { return pair(0.0,0.0); } // When a knot has a restriction on one side but is open on the other, the // restriction implies a restriction on the other side. This is the partner // restriction defined here, where the pair argument is for the location of // the knot. virtual spec *outPartner(pair) { return this; } virtual spec *inPartner(pair) { return this; } virtual void print(ostream&) const {} }; inline ostream& operator<< (ostream& out, spec& s) { s.print(out); return out; } // Specifier used at an endpoint. class endSpec : public spec { public: bool open() { return false; } // Returns an equation used to solve for the thetas along the knot. These are // called by eqnprop in the non-cyclic case for the first and last equations. virtual eqn eqnOut(Int j, knotlist& l, cvector& d, cvector& psi) = 0; virtual eqn eqnIn (Int j, knotlist& l, cvector& d, cvector& psi) = 0; }; // A specifier with a given direction (in radians). class dirSpec : public endSpec { double given; public: // Direction should be given in the range [-PI,PI] dirSpec(double given) : given(given) {} dirSpec(pair z) : given(niceAngle(z)) {} pair dir() { return expi(given); } eqn eqnOut(Int j, knotlist& l, cvector& d, cvector& psi); eqn eqnIn (Int j, knotlist& l, cvector& d, cvector& psi); void print(ostream& out) const { out << "{dir(" << degrees(given) << ")}"; } }; // A curl specifier. The curvature at the end knot should be gamma times the // curvature at the neighbouring knot. class curlSpec : public endSpec { double gamma; public: // Gamma should be non-negative. curlSpec(double gamma=1.0) : gamma(gamma) { if(gamma < 0) reportError("curl cannot be less than 0"); } double curl() { return gamma; } eqn eqnOut(Int j, knotlist& l, cvector& d, cvector& psi); eqn eqnIn (Int j, knotlist& l, cvector& d, cvector& psi); void print(ostream& out) const { out << "{curl " << gamma << "}"; } }; // A specifier with a control point. All information for this portion of the // curve has been determined. class controlSpec : public spec { public: pair cz; bool straight; controlSpec(pair cz, bool straight=false) : cz(cz), straight(straight) {} bool open() { return false; } bool controlled() { return true; } pair control() { return cz; } // The partner spec will be a dirSpec in the same direction the specifier // takes the path, unless the velocity is zero, then it uses a curl // specifier. spec *outPartner(pair); spec *inPartner(pair); void print(ostream& out) const { // NOTE: This format cannot be read back in. out << "{control " << cz << "}"; } }; // The tension information for one side of a knot. struct tension { double val; bool atleast; tension(double val=1.0, bool atleast=false) : val(val), atleast(atleast) { if(val < 0.75) reportError("tension cannot be less than 3/4"); } }; inline ostream& operator<<(ostream& out, tension t) { return out << "tension" << (t.atleast ? " atleast " : " ") << t.val; } // A knot, a point with specifiers to double the path coming in and going out // of the knot. struct knot { pair z; spec *in; spec *out; tension tin, tout; knot() {} knot(pair z, spec *in, spec *out, tension tin=tension(), tension tout=tension()) : z(z), in(in), out(out), tin(tin), tout(tout) {} double alpha() { return 1.0/tout.val; } double beta() { return 1.0/tin.val; } }; ostream& operator<<(ostream& out, const knot& k); // Abstract base class for a section of a guide. class knotlist { public: virtual ~knotlist() {} virtual Int length() = 0; virtual bool cyclic() = 0; // Returns the number of knots. Int size() { return cyclic() ? length() : length() + 1; } bool empty() { return size()==0; } virtual knot& cell(Int) = 0; virtual knot& operator[] (Int i) { #if 0 assert(cyclic() || (0 <= i && i <= length())); // Bounds check. #endif return cell(i); } knot& front() { return (*this)[0]; } knot& back() { return (*this)[length()]; } }; // Defines a knotlist as a piece of another knotlist. class subknotlist : public knotlist { knotlist& l; Int a,b; public: subknotlist(knotlist& l, Int a, Int b) : l(l), a(a), b(b) {} Int length() { return b-a; } bool cyclic() { return false; } knot& cell(Int i) { return l[a+i]; } }; struct simpleknotlist : public knotlist { cvector nodes; bool cycles; simpleknotlist(cvector nodes, bool cycles=false) : nodes(nodes), cycles(cycles) {} Int length() { return cycles ? (Int) nodes.size() : (Int) nodes.size() - 1; } bool cyclic() { return cycles; } knot& cell(Int j) { return nodes[j]; } }; // A protopath is a path being made. struct protopath { bool cycles; Int n; mem::vector nodes; protopath(Int n, bool cycles) : cycles(cycles), n(n), nodes(n) {} solvedKnot& operator[](Int j) { return nodes[imod(j,n)]; } bool& straight(Int j) { return (*this)[j].straight; } pair& pre(Int j) { return (*this)[j].pre; } pair& point(Int j) { return (*this)[j].point; } pair& post(Int j) { return (*this)[j].post; } void controlEnds() { if (!cycles) { solvedKnot& start=(*this)[0]; solvedKnot& end=(*this)[n-1]; start.pre=start.point; end.post=end.point; } } // Once all the controls are set, return the final (constant) path. path fix() { return path(nodes,n,cycles); } }; // Represents properties that can be computed along a knotlist. // Examples include distances (d), turning angles (psi), and the linear // equations used to solve for the thetas. template class knotprop { protected: knotlist& l; // Calculate the property for the usual case in the iteration (and for a // cyclic knot, the only case), at the index given. virtual T mid(Int) = 0; // The special cases, these default to the usual case: mid. virtual T solo(Int j) // Calculates the property for a list of length 0. { return mid(j); } virtual T start(Int j) // Calculates it at the start of the list. { return mid(j); } virtual T end(Int j) // Calculate it at the end. { return mid(j); } virtual cvector linearCompute() { Int n=l.length(); cvector v; if (n==0) v.push_back(solo(0)); else { v.push_back(start(0)); for (Int j=1; j cyclicCompute() { Int n=l.length(); cvector v; for (Int j=0; j linearBackCompute() { Int n=l.length(); cvector v; if (n==0) v.push_back(solo(0)); else { v.push_back(end(n)); for (Int j=1; j cyclicBackCompute() { Int n=l.length(); cvector v; for (Int j=1; j<=n; ++j) v.push_back(mid(n-j)); return v; } public: virtual ~knotprop() {} virtual cvector compute() { return l.cyclic() ? cyclicCompute() : linearCompute(); } // Compute the values in the opposite order. This is needed for instance if // the i-th calculation needed a result computed in the i+1-th, such as in the // back substitution for solving thetas. virtual cvector backCompute() { cvector v=l.cyclic() ? cyclicBackCompute() : linearBackCompute(); // Even though they are computed in the backwards order, return them in the // standard order. reverse(v.begin(),v.end()); return v; } knotprop(knotlist& l) : l(l) {} }; // A knot transforms, it takes in one knotlist and transforms it knot for knot // into a new one. class knottrans : public knotprop { protected: virtual knot mid(Int j) { /* By default, just copy the knot. */ return l[j]; } public: virtual ~knottrans() {} knottrans(knotlist& l) : knotprop(l) {} virtual simpleknotlist trans() { return simpleknotlist(compute(),l.cyclic()); } }; // Like a knotprop, but it doesn't compute a vector of values for the knot. It // iterates over the knotlist calling method for side-effect. For instance, // this is used to plug control points into protopaths. class knoteffect { protected: knotlist& l; virtual void mid(Int) = 0; // The special cases, these default to the usual case: mid. virtual void solo(Int j) { mid(j); } virtual void start(Int j) { mid(j); } virtual void end(Int j) { mid(j); } virtual void linearExec() { Int n=l.length(); if (n==0) solo(0); else { start(0); for (Int j=1; j& z); double velocity(double theta, double phi, tension t); } // namespace camp GC_DECLARE_PTRFREE(camp::eqn); GC_DECLARE_PTRFREE(camp::tension); #endif // KNOT_H asymptote-2.37/lexical.h000066400000000000000000000005311265434602500152720ustar00rootroot00000000000000#ifndef __lexical_h__ #define __lexical_h__ 1 #include #include "common.h" namespace lexical { class bad_cast {}; template T cast(const string& s, bool tolerant=false) { istringstream is(s); T value; if(is && is >> value && ((is >> std::ws).eof() || tolerant)) return value; throw bad_cast(); } } #endif asymptote-2.37/lnkX64IconFix.nsh000066400000000000000000000053161265434602500165660ustar00rootroot00000000000000/****************************************************************************** WORKAROUND - lnkX64IconFix This snippet was developed to address an issue with Windows x64 incorrectly redirecting the shortcuts icon from $PROGRAMFILES32 to $PROGRAMFILES64. See Forum post: http://forums.winamp.com/newreply.php?do=postreply&t=327806 Example: CreateShortcut "$SMPROGRAMS\My App\My App.lnk" "$INSTDIR\My App.exe" "" "$INSTDIR\My App.exe" ${lnkX64IconFix} "$SMPROGRAMS\My App\My App.lnk" Original Code by Anders [http://forums.winamp.com/member.php?u=70852] ******************************************************************************/ !ifndef ___lnkX64IconFix___ !verbose push !verbose 0 !include "LogicLib.nsh" !include "x64.nsh" !define ___lnkX64IconFix___ !define lnkX64IconFix `!insertmacro _lnkX64IconFix` !macro _lnkX64IconFix _lnkPath !verbose push !verbose 0 ${If} ${RunningX64} DetailPrint "WORKAROUND: 64bit OS Detected, Attempting to apply lnkX64IconFix" Push "${_lnkPath}" Call lnkX64IconFix ${EndIf} !verbose pop !macroend Function lnkX64IconFix ; _lnkPath Exch $5 Push $0 Push $1 Push $2 Push $3 Push $4 System::Call 'OLE32::CoCreateInstance(g "{00021401-0000-0000-c000-000000000046}",i 0,i 1,g "{000214ee-0000-0000-c000-000000000046}",*i.r1)i' ${If} $1 <> 0 System::Call '$1->0(g "{0000010b-0000-0000-C000-000000000046}",*i.r2)' ${If} $2 <> 0 System::Call '$2->5(w r5,i 2)i.r0' ${If} $0 = 0 System::Call '$1->0(g "{45e2b4ae-b1c3-11d0-b92f-00a0c90312e1}",*i.r3)i.r0' ${If} $3 <> 0 System::Call '$3->5(i 0xA0000007)i.r0' System::Call '$3->6(*i.r4)i.r0' ${If} $0 = 0 IntOp $4 $4 & 0xffffBFFF System::Call '$3->7(ir4)i.r0' ${If} $0 = 0 System::Call '$2->6(i0,i0)' DetailPrint "WORKAROUND: lnkX64IconFix Applied successfully" ${EndIf} ${EndIf} System::Call $3->2() ${EndIf} ${EndIf} System::Call $2->2() ${EndIf} System::Call $1->2() ${EndIf} Pop $4 Pop $3 Pop $2 Pop $1 Pop $0 FunctionEnd !verbose pop !endif asymptote-2.37/locate.cc000066400000000000000000000042231265434602500152600ustar00rootroot00000000000000/***** * locate.cc * Tom Prince 2005/03/24 * * Locate files in search path. *****/ #include #include "settings.h" #include "util.h" #include "locate.h" namespace settings { namespace fs { string extension(string name) { size_t n = name.rfind("."); if (n != string::npos) return name.substr(n); else return string(); } bool exists(string filename) { return ::access(filename.c_str(), R_OK) == 0; } } // namespace fs file_list_t searchPath; // Returns list of possible filenames, accounting for extensions. file_list_t mungeFileName(string id) { string ext = fs::extension(id); file_list_t files; if (ext == "."+settings::suffix) { files.push_back(id); files.push_back(id+"."+settings::suffix); } else { files.push_back(id+"."+settings::suffix); files.push_back(id); } return files; } // Join a directory with the given filename, to give the path to the file. This // also avoids unsightly joins such as './file.asy' in favour of 'file.asy' and // 'dir//file.asy' in favour of 'dir/file.asy' string join(string dir, string file) { return dir == "." ? file : *dir.rbegin() == '/' ? dir + file : dir + "/" + file; } // Find the appropriate file, first looking in the local directory, then the // directory given in settings, and finally the global system directory. string locateFile(string id) { if(id.empty()) return ""; file_list_t filenames = mungeFileName(id); for (file_list_t::iterator leaf = filenames.begin(); leaf != filenames.end(); ++leaf) { #ifdef __MSDOS__ size_t p; while ((p=leaf->find('\\')) < string::npos) (*leaf)[p]='/'; if ((p=leaf->find(':')) < string::npos && p > 0) { (*leaf)[p]='/'; leaf->insert(0,"/cygdrive/"); } #endif if ((*leaf)[0] == '/') { string file = *leaf; if (fs::exists(file)) return file; } else { for (file_list_t::iterator dir = searchPath.begin(); dir != searchPath.end(); ++dir) { string file = join(*dir,*leaf); if (fs::exists(file)) return file; } } } return string(); } } // namespace settings asymptote-2.37/locate.h000066400000000000000000000010601265434602500151160ustar00rootroot00000000000000/***** * locate.h * Tom Prince 2005/03/24 * * Locate files in search path. *****/ #ifndef LOCATE_H #define LOCATE_H #include "common.h" namespace settings { typedef mem::list file_list_t; extern file_list_t searchPath; // Find the appropriate file, first looking in the local directory, then the // directory given in settings, and finally the global system directory. string locateFile(string id); namespace fs { // Check to see if a file of given name exists. bool exists(string filename); } } // namespace settings #endif // LOCATE_H asymptote-2.37/main.cc000066400000000000000000000110471265434602500147370ustar00rootroot00000000000000/************ * * This file is part of the vector graphics language Asymptote * Copyright (C) 2004 Andy Hammerlindl, John C. Bowman, Tom Prince * http://asymptote.sourceforge.net * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * *************/ #include #include #include #include #include #include "common.h" #ifdef HAVE_LIBSIGSEGV #include #endif #include "errormsg.h" #include "fpu.h" #include "settings.h" #include "locate.h" #include "interact.h" #include "process.h" #include "stack.h" using namespace settings; using interact::interactive; namespace run { void purge(); } #ifdef PROFILE namespace vm { extern void dumpProfile(); }; #endif #ifdef HAVE_LIBSIGSEGV void stackoverflow_handler (int, stackoverflow_context_t) { em.runtime(vm::getPos()); cerr << "Stack overflow" << endl; abort(); } int sigsegv_handler (void *, int emergency) { if(!emergency) return 0; // Really a stack overflow em.runtime(vm::getPos()); #ifdef HAVE_GL if(gl::glthread) cerr << "Stack overflow or segmentation fault: rerun with -nothreads" << endl; else #endif cerr << "Segmentation fault" << endl; abort(); } #endif void setsignal(RETSIGTYPE (*handler)(int)) { #ifdef HAVE_LIBSIGSEGV char mystack[16384]; stackoverflow_install_handler(&stackoverflow_handler, mystack,sizeof (mystack)); sigsegv_install_handler(&sigsegv_handler); #endif Signal(SIGBUS,handler); Signal(SIGFPE,handler); } void signalHandler(int) { // Print the position and trust the shell to print an error message. em.runtime(vm::getPos()); Signal(SIGBUS,SIG_DFL); Signal(SIGFPE,SIG_DFL); } void interruptHandler(int) { em.Interrupt(true); } struct Args { int argc; char **argv; Args(int argc, char **argv) : argc(argc), argv(argv) {} }; void *asymain(void *A) { setsignal(signalHandler); Args *args=(Args *) A; fpu_trap(trap()); if(interactive) { Signal(SIGINT,interruptHandler); processPrompt(); } else if (getSetting("listvariables") && numArgs()==0) { try { doUnrestrictedList(); } catch(handled_error) { em.statusError(); } } else { int n=numArgs(); if(n == 0) processFile("-"); else for(int ind=0; ind < n; ind++) { processFile(string(getArg(ind)),n > 1); try { if(ind < n-1) setOptions(args->argc,args->argv); } catch(handled_error) { em.statusError(); } } } #ifdef PROFILE vm::dumpProfile(); #endif if(getSetting("wait")) { int status; while(wait(&status) > 0); } #ifdef HAVE_GL #ifdef HAVE_PTHREAD if(gl::glthread && !getSetting("offscreen")) { pthread_kill(gl::mainthread,SIGUSR2); pthread_join(gl::mainthread,NULL); } #endif #endif exit(em.processStatus() || interact::interactive ? 0 : 1); } void exitHandler(int) { exit(0); } int main(int argc, char *argv[]) { #ifdef HAVE_LIBGSL unsetenv("GSL_RNG_SEED"); unsetenv("GSL_RNG_TYPE"); #endif setsignal(signalHandler); try { setOptions(argc,argv); } catch(handled_error) { em.statusError(); } Args args(argc,argv); #ifdef HAVE_GL #ifdef __APPLE__ bool usethreads=true; #else bool usethreads=view(); #endif gl::glthread=usethreads ? getSetting("threads") : false; #if HAVE_PTHREAD if(gl::glthread) { pthread_t thread; try { if(pthread_create(&thread,NULL,asymain,&args) == 0) { gl::mainthread=pthread_self(); sigset_t set; sigemptyset(&set); sigaddset(&set, SIGCHLD); pthread_sigmask(SIG_BLOCK, &set, NULL); while(true) { Signal(SIGUSR2,exitHandler); camp::glrenderWrapper(); gl::initialize=true; } } else gl::glthread=false; } catch(std::bad_alloc&) { outOfMemory(); } } #endif gl::glthread=false; #endif asymain(&args); } asymptote-2.37/mathop.h000066400000000000000000000140431265434602500151440ustar00rootroot00000000000000/***** * mathop.h * Tom Prince 2005/3/18 * * Defines some runtime functions used by the stack machine. * *****/ #ifndef MATHOP_H #define MATHOP_H #include #include "stack.h" #include "mod.h" #include "triple.h" namespace run { template struct less { bool operator() (T x, T y, size_t=0) {return x < y;} }; template struct lessequals { bool operator() (T x, T y, size_t=0) {return x <= y;} }; template struct equals { bool operator() (T x, T y, size_t=0) {return x == y;} }; template struct greaterequals { bool operator() (T x, T y, size_t=0) {return x >= y;} }; template struct greater { bool operator() (T x, T y, size_t=0) {return x > y;} }; template struct notequals { bool operator() (T x, T y, size_t=0) {return x != y;} }; template struct And { bool operator() (T x, T y, size_t=0) {return x && y;} }; template struct Or { bool operator() (T x, T y, size_t=0) {return x || y;} }; template struct Xor { bool operator() (T x, T y, size_t=0) {return x ^ y;} }; template struct plus { T operator() (T x, T y, size_t=0) {return x+y;} }; template struct minus { T operator() (T x, T y, size_t=0) {return x-y;} }; template struct times { T operator() (T x, T y, size_t=0) {return x*y;} }; template <> struct times { camp::triple operator() (double x, camp::triple y, size_t=0) {return x*y;} }; template struct timesR { T operator () (T y, double x, size_t=0) {return x*y;} }; extern void dividebyzero(size_t i=0); extern void integeroverflow(size_t i=0); template struct divide { T operator() (T x, T y, size_t i=0) { if(y == 0) dividebyzero(i); return x/y; } }; template <> struct divide { camp::triple operator() (camp::triple x, double y, size_t=0) {return x/y;} }; inline bool validInt(double x) { return x > Int_MIN-0.5 && x < Int_MAX+0.5; } inline void checkInt(double x, size_t i) { if(validInt(x)) return; integeroverflow(i); } inline Int Intcast(double x) { if(validInt(x)) return (Int) x; integeroverflow(0); return 0; } template<> struct plus { Int operator() (Int x, Int y, size_t i=0) { if((y > 0 && x > Int_MAX-y) || (y < 0 && x < Int_MIN-y)) integeroverflow(i); return x+y; } }; template<> struct minus { Int operator() (Int x, Int y, size_t i=0) { if((y < 0 && x > Int_MAX+y) || (y > 0 && x < Int_MIN+y)) integeroverflow(i); return x-y; } }; template<> struct times { Int operator() (Int x, Int y, size_t i=0) { if(y == 0) return 0; if(y < 0) {y=-y; x=-x;} if((y > int_MAX || x > int_MAX/(int) y || x < int_MIN/(int) y) && (x > Int_MAX/y || x < Int_MIN/y)) integeroverflow(i); return x*y; } }; template<> struct divide { double operator() (Int x, Int y, size_t i=0) { if(y == 0) dividebyzero(i); return ((double) x)/(double) y; } }; template void Negate(vm::stack *s) { T a=vm::pop(s); s->push(-a); } inline Int Negate(Int x, size_t i=0) { if(x < -Int_MAX) integeroverflow(i); return -x; } template<> inline void Negate(vm::stack *s) { s->push(Negate(vm::pop(s))); } inline double pow(double x, double y) { #ifndef HAVE_POW return exp(y*log(x)); #else return ::pow(x,y); #endif } template T pow(T x, Int y) { if(y == 0) return 1.0; if(x == 0.0 && y > 0) return 0.0; if(y < 0) {y=-y; x=1/x;} T r=1.0; for(;;) { if(y & 1) r *= x; if((y >>= 1) == 0) return r; x *= x; } } template struct power { T operator() (T x, T y, size_t=0) {return pow(x,y);} }; template <> struct power { Int operator() (Int x, Int p, size_t i=0) { if(p == 0) return 1; Int sign=1; if(x < 0) { if(p % 2) sign=-1; x=-x; } if(p > 0) { if(x == 0) return 0; Int r = 1; for(;;) { if(p & 1) { if(r > Int_MAX/x) integeroverflow(i); r *= x; } if((p >>= 1) == 0) return sign*r; if(x > Int_MAX/x) integeroverflow(i); x *= x; } } else { if(x == 1) return sign; ostringstream buf; if(i > 0) buf << "array element " << i << ": "; buf << "Only 1 and -1 can be raised to negative exponents as integers."; vm::error(buf); return 0; } } }; template struct mod { T operator() (T x, T y, size_t i=0) { if(y == 0) dividebyzero(i); return portableMod(x,y); } }; template struct min { T operator() (T x, T y, size_t=0) {return x < y ? x : y;} }; template struct max { T operator() (T x, T y, size_t=0) {return x > y ? x : y;} }; template inline T Min(T a, T b) { return (a < b) ? a : b; } template inline T Max(T a, T b) { return (a > b) ? a : b; } template struct minbound { camp::pair operator() (camp::pair z, camp::pair w) { return camp::pair(Min(z.getx(),w.getx()),Min(z.gety(),w.gety())); } camp::triple operator() (camp::triple u, camp::triple v) { return camp::triple(Min(u.getx(),v.getx()),Min(u.gety(),v.gety()), Min(u.getz(),v.getz())); } }; template struct maxbound { camp::pair operator() (camp::pair z, camp::pair w) { return camp::pair(Max(z.getx(),w.getx()),Max(z.gety(),w.gety())); } camp::triple operator() (camp::triple u, camp::triple v) { return camp::triple(Max(u.getx(),v.getx()),Max(u.gety(),v.gety()), Max(u.getz(),v.getz())); } }; template void realReal(vm::stack *s) { double x=vm::pop(s); s->push(func(x)); } template class op> void binaryOp(vm::stack *s) { T b=vm::pop(s); T a=vm::pop(s); s->push(op()(a,b)); } template void interp(vm::stack *s) { double t=vm::pop(s); T b=vm::pop(s); T a=vm::pop(s); s->push((1-t)*a+t*b); } } // namespace run #endif //MATHOP_H asymptote-2.37/memory.h000066400000000000000000000116761265434602500151750ustar00rootroot00000000000000/**** * memory.h * * Interface to the Boehm Garbage Collector. *****/ #ifndef MEMORY_H #define MEMORY_H #include #include #include #include #include #include #ifndef NOHASH #ifdef HAVE_UNORDERED_MAP #include #include #define EXT std #else #ifdef HAVE_TR1_UNORDERED_MAP #include #define EXT std::tr1 #else #define EXT __gnu_cxx #include #define unordered_map hash_map #define unordered_multimap hash_multimap #endif #endif #endif #ifdef __DECCXX_LIBCXX_RH70 #define CONST #else #define CONST const #endif #ifdef USEGC #define GC_THREADS #include #ifdef GC_DEBUG extern "C" { #include } #endif inline void *asy_malloc(size_t n) { #ifdef GC_DEBUG if(void *mem=GC_debug_malloc_ignore_off_page(n, GC_EXTRAS)) #else if(void *mem=GC_malloc_ignore_off_page(n)) #endif return mem; throw std::bad_alloc(); } inline void *asy_malloc_atomic(size_t n) { #ifdef GC_DEBUG if(void *mem=GC_debug_malloc_atomic_ignore_off_page(n, GC_EXTRAS)) #else if(void *mem=GC_malloc_atomic_ignore_off_page(n)) #endif return mem; throw std::bad_alloc(); } #undef GC_MALLOC #undef GC_MALLOC_ATOMIC #define GC_MALLOC(sz) asy_malloc(sz) #define GC_MALLOC_ATOMIC(sz) asy_malloc_atomic(sz) #include #include #else // USEGC using std::allocator; #define gc_allocator allocator class gc {}; class gc_cleanup {}; enum GCPlacement {UseGC, NoGC, PointerFreeGC}; inline void* operator new(size_t size, GCPlacement) { return operator new(size); } inline void* operator new[](size_t size, GCPlacement) { return operator new(size); } template struct GC_type_traits {}; #define GC_DECLARE_PTRFREE(T) \ template<> struct GC_type_traits {} #endif // USEGC namespace mem { #define GC_CONTAINER(KIND) \ template \ struct KIND : public std::KIND >, public gc { \ KIND() : std::KIND >() {} \ KIND(size_t n) : std::KIND >(n) {} \ KIND(size_t n, const T& t) : std::KIND >(n,t) {} \ } GC_CONTAINER(list); GC_CONTAINER(vector); template > struct stack : public std::stack, public gc { }; #define PAIR_ALLOC gc_allocator > /* space */ #undef GC_CONTAINER #define GC_CONTAINER(KIND) \ template > \ struct KIND : public std::KIND, public gc \ { \ KIND() : std::KIND () {} \ } GC_CONTAINER(map); GC_CONTAINER(multimap); #undef GC_CONTAINER #ifndef NOHASH #define GC_CONTAINER(KIND) \ template , \ typename Eq = std::equal_to > \ struct KIND : public \ EXT::KIND, public gc { \ KIND() : EXT::KIND () {} \ KIND(size_t n) \ : EXT::KIND (n) {} \ } GC_CONTAINER(unordered_map); GC_CONTAINER(unordered_multimap); #undef GC_CONTAINER #undef EXT #endif #undef PAIR_ALLOC #ifdef USEGC typedef std::basic_string, gc_allocator > string; typedef std::basic_stringstream, gc_allocator > stringstream; typedef std::basic_istringstream, gc_allocator > istringstream; typedef std::basic_ostringstream, gc_allocator > ostringstream; typedef std::basic_stringbuf, gc_allocator > stringbuf; #if GC_TMP_VERSION_MAJOR >= 7 && GC_TMP_VERSION_MINOR > 1 inline void compact(int x) {GC_set_dont_expand(x);} #else inline void compact(int x) {GC_dont_expand=x;} #endif #else inline void compact(int x) {} typedef std::string string; typedef std::stringstream stringstream; typedef std::istringstream istringstream; typedef std::ostringstream ostringstream; typedef std::stringbuf stringbuf; #endif // USEGC } // namespace mem #endif asymptote-2.37/mod.h000066400000000000000000000013201265434602500144250ustar00rootroot00000000000000/***** * mod.h * Andy Hammerlindl 2005/03/16 * * Definition of implementation-independent mod function. *****/ #ifndef MOD_H #define MOD_H #include #include "common.h" using std::fmod; inline Int Mod(Int x, Int y) {return x % y;} inline double Mod(double x, double y) {return fmod(x,y);} template inline T portableMod(T x,T y) { // Implementation-independent definition of mod; ensure that result has // same sign as divisor T val=Mod(x,y); if((y > 0 && val < 0) || (y < 0 && val > 0)) val += y; return val; } inline Int imod(Int x, Int y) { return portableMod(x,y); } inline Int imod(Int i, size_t n) { i %= (Int) n; if(i < 0) i += (Int) n; return i; } #endif asymptote-2.37/modifier.h000066400000000000000000000016141265434602500154520ustar00rootroot00000000000000/***** * modifier.h * Andy Hammerlindl 2002/08/29 * * Permissions for variables. * PUBLIC means the variable can be read or written anywhere. * RESTRICTED means it can be read anywhere, but written only in the record. * PRIVATE means it can only be accessed in the record. * * The modifiers static declares that variable to be allocated, are allocated in * the parent's frame, and code is translated into the parent's frame. *****/ #ifndef MODIFIER_H #define MODIFIER_H namespace trans { // Permission tokens defined in camp.y for accessing a variable outside of // its lexically enclosing record. enum permission { RESTRICTED, PUBLIC, PRIVATE }; const permission DEFAULT_PERM=PUBLIC; enum modifier { DEFAULT_STATIC, DEFAULT_DYNAMIC, EXPLICIT_STATIC, EXPLICIT_DYNAMIC }; } // namespace trans GC_DECLARE_PTRFREE(trans::permission); GC_DECLARE_PTRFREE(trans::modifier); #endif asymptote-2.37/name.cc000066400000000000000000000164251265434602500147400ustar00rootroot00000000000000/***** * name.cc * Andy Hammerlindl2002/07/14 * * Qualified names (such as x, f, builtin.sin, a.b.c.d, etc.) can be used * either as variables or a type names. This class stores qualified * names used in nameExp and nameTy in the abstract syntax, and * implements the exp and type functions. *****/ #include "name.h" #include "frame.h" #include "record.h" #include "coenv.h" #include "inst.h" namespace absyntax { using namespace types; using trans::access; using trans::qualifiedAccess; using trans::action; using trans::READ; using trans::WRITE; using trans::CALL; using vm::inst; types::ty *signatureless(types::ty *t) { if (overloaded *o=dynamic_cast(t)) return o->signatureless(); else return (t && !t->getSignature()) ? t : 0; } void name::forceEquivalency(action act, coenv &e, types::ty *target, types::ty *source) { if (act == READ) e.implicitCast(getPos(), target, source); else if (!equivalent(target, source)) { em.compiler(getPos()); em << "type mismatch in variable: " << *target << " vs " << *source; } } frame *name::frameTrans(coenv &e) { if (types::ty *t=signatureless(varGetType(e))) { if (t->kind == types::ty_record) { varTrans(READ, e, t); return ((record *)t)->getLevel(); } else return 0; } else return tyFrameTrans(e); } types::ty *name::getType(coenv &e, bool tacit) { types::ty *t=signatureless(varGetType(e)); if (!tacit && t && t->kind == ty_error) // Report errors associated with regarding the name as a variable. varTrans(trans::READ, e, t); return t ? t : typeTrans(e, tacit); } varEntry *simpleName::getVarEntry(coenv &e) { types::ty *t=signatureless(varGetType(e)); return t ? e.e.lookupVarByType(id, t) : 0; } void simpleName::varTrans(action act, coenv &e, types::ty *target) { varEntry *v = e.e.lookupVarByType(id, target); if (v) { v->encode(act, getPos(), e.c); forceEquivalency(act, e, target, v->getType()); } else { em.error(getPos()); em << "no matching variable of name \'" << id << "\'"; } } types::ty *simpleName::varGetType(coenv &e) { return e.e.varGetType(id); } trans::varEntry *simpleName::getCallee(coenv &e, signature *sig) { varEntry *ve = e.e.lookupVarBySignature(id, sig); return ve; } types::ty *simpleName::typeTrans(coenv &e, bool tacit) { types::ty *t = e.e.lookupType(id); if (t) { return t; } else { if (!tacit) { em.error(getPos()); em << "no type of name \'" << id << "\'"; } return primError(); } } tyEntry *simpleName::tyEntryTrans(coenv &e) { tyEntry *ent = e.e.lookupTyEntry(id); if (!ent) { em.error(getPos()); em << "no type of name \'" << id << "\'"; return new tyEntry(primError(), 0, 0, position()); } return ent; } frame *simpleName::tyFrameTrans(coenv &e) { tyEntry *ent = e.e.lookupTyEntry(id); if (ent && ent->t->kind==types::ty_record && ent->v) { ent->v->encode(READ, getPos(), e.c); return ent->v->getLevel(); } else return 0; } void simpleName::prettyprint(ostream &out, Int indent) { prettyindent(out, indent); out << "simpleName '" << id << "'\n"; } record *qualifiedName::castToRecord(types::ty *t, bool tacit) { switch (t->kind) { case ty_overloaded: if (!tacit) { em.compiler(qualifier->getPos()); em << "name::getType returned overloaded"; } return 0; case ty_record: return (record *)t; case ty_error: return 0; default: if (!tacit) { em.error(qualifier->getPos()); em << "type \'" << *t << "\' is not a structure"; } return 0; } } bool qualifiedName::varTransVirtual(action act, coenv &e, types::ty *target, types::ty *qt) { varEntry *v = qt->virtualField(id, target->getSignature()); if (v) { // Push qualifier onto stack. qualifier->varTrans(READ, e, qt); v->encode(act, getPos(), e.c); // A virtual field was used. return true; } // No virtual field. return false; } void qualifiedName::varTransField(action act, coenv &e, types::ty *target, record *r) { varEntry *v = r->e.lookupVarByType(id, target); if (v) { frame *f = qualifier->frameTrans(e); if (f) v->encode(act, getPos(), e.c, f); else v->encode(act, getPos(), e.c); forceEquivalency(act, e, target, v->getType()); } else { em.error(getPos()); em << "no matching field of name \'" << id << "\' in \'" << *r << "\'"; } } void qualifiedName::varTrans(action act, coenv &e, types::ty *target) { types::ty *qt = qualifier->getType(e); // Use virtual fields if applicable. if (varTransVirtual(act, e, target, qt)) return; record *r = castToRecord(qt); if (r) varTransField(act, e, target, r); } types::ty *qualifiedName::varGetType(coenv &e) { types::ty *qt = qualifier->getType(e, true); // Look for virtual fields. types::ty *t = qt->virtualFieldGetType(id); if (t) return t; record *r = castToRecord(qt, true); return r ? r->e.varGetType(id) : 0; } trans::varEntry *qualifiedName::getCallee(coenv &e, signature *sig) { // getTypeAsCallee is an optimization attempt. We don't try optimizing the // rarer qualifiedName call case. // TODO: See if this is worth implementing. //cout << "FAIL BY QUALIFIED NAME" << endl; return 0; } trans::varEntry *qualifiedName::getVarEntry(coenv &e) { varEntry *qv = qualifier->getVarEntry(e); types::ty *qt = qualifier->getType(e, true); record *r = castToRecord(qt, true); if (r) { types::ty *t = signatureless(r->e.varGetType(id)); varEntry *v = t ? r->e.lookupVarByType(id, t) : 0; return trans::qualifyVarEntry(qv,v); } else return qv; } types::ty *qualifiedName::typeTrans(coenv &e, bool tacit) { types::ty *rt = qualifier->getType(e, tacit); record *r = castToRecord(rt, tacit); if (!r) return primError(); tyEntry *ent = r->e.lookupTyEntry(id); if (ent) { if (!tacit) ent->reportPerm(READ, getPos(), e.c); return ent->t; } else { if (!tacit) { em.error(getPos()); em << "no matching field or type of name \'" << id << "\' in \'" << *r << "\'"; } return primError(); } } tyEntry *qualifiedName::tyEntryTrans(coenv &e) { types::ty *rt = qualifier->getType(e, false); record *r = castToRecord(rt, false); if (!r) return new tyEntry(primError(), 0, 0, position()); tyEntry *ent = r->e.lookupTyEntry(id); if (!ent) { em.error(getPos()); em << "no matching type of name \'" << id << "\' in \'" << *r << "\'"; return new tyEntry(primError(), 0, 0, position()); } ent->reportPerm(READ, getPos(), e.c); return trans::qualifyTyEntry(qualifier->getVarEntry(e), ent); } frame *qualifiedName::tyFrameTrans(coenv &e) { frame *f=qualifier->frameTrans(e); tyEntry *ent = e.e.lookupTyEntry(id); if (ent && ent->t->kind==types::ty_record && ent->v) { if (f) ent->v->encode(READ, getPos(), e.c, f); else ent->v->encode(READ, getPos(), e.c); return ent->v->getLevel(); } else return f; } void qualifiedName::prettyprint(ostream &out, Int indent) { prettyindent(out, indent); out << "qualifiedName '" << id << "'\n"; qualifier->prettyprint(out, indent+1); } } // namespace absyntax asymptote-2.37/name.h000066400000000000000000000121671265434602500146010ustar00rootroot00000000000000/***** * name.h * Andy Hammerlindl 2002/07/14 * * Qualified names (such as x, f, builtin.sin, a.b.c.d, etc.) can be used * either as variables or a type names. This class stores qualified * names used in nameExp and nameTy in the abstract syntax, and * implements the exp and type functions. *****/ #ifndef NAME_H #define NAME_H #include "absyn.h" #include "types.h" #include "frame.h" #include "access.h" namespace trans { class coenv; class varEntry; class tyEntry; } namespace types { class record; } namespace absyntax { using trans::coenv; using trans::action; using types::record; using std::ostream; class name : public absyn { public: name(position pos) : absyn(pos) {} // Helper function - ensures target and source match up, using casting in the // case of a read. Issues errors on failure. void forceEquivalency(action act, coenv &e, types::ty *target, types::ty *source); // Used for determining the type when the context does not establish // the name as a variable or a type. First, the function looks for a // non-function variable fitting the description. If one fits, the // type of the variable is returned. Failing that, the function looks // for a fitting type and returns that. If nothing is found, an // appropriate error is reported and ty_error is returned. // Because this is used only on qualifiers (ie. names to the left of a // dot), it does not look at function variables. // Tacit means that no error messages will be reported to the user. virtual types::ty *getType(coenv &e, bool tacit = false); // Pushes the highest level frame possible onto the stack. Returning // the frame pushed. If no frame can be pushed, returns 0. // NOTE: This duplicates some functionality with getVarEntry. virtual trans::frame *frameTrans(coenv &e); // Helper function for the case where the name is known to be a type. virtual trans::frame *tyFrameTrans(coenv &e) = 0; // Constructs the varEntry part of the tyEntry for the name. Like // getType, this is called on the qualifier, instead of the full name. // This reports no errors, and returns 0 if there is no varEntry to // use. virtual trans::varEntry *getVarEntry(coenv &e) = 0; // As a variable: // Translates the name (much like an expression). virtual void varTrans(action act, coenv &e, types::ty *target) = 0; // Returns the possible variable types. Unlike exp, returns 0 if none // match. virtual types::ty *varGetType(coenv &e) = 0; virtual trans::varEntry *getCallee(coenv &e, types::signature *sig) = 0; // As a type: // Determines the type, as used in a variable declaration. virtual types::ty *typeTrans(coenv &e, bool tacit = false) = 0; // Constructs the tyEntry of the name, needed so that we know the // parent frame for allocating new objects of that type. Reports // errors as typeTrans() does with tacit=false. virtual trans::tyEntry *tyEntryTrans(coenv &e) = 0; virtual void prettyprint(ostream &out, Int indent) = 0; virtual void print(ostream& out) const { out << ""; } virtual symbol getName() = 0; }; inline ostream& operator<< (ostream& out, const name& n) { n.print(out); return out; } class simpleName : public name { symbol id; public: simpleName(position pos, symbol id) : name(pos), id(id) {} trans::varEntry *getVarEntry(coenv &e); // As a variable: void varTrans(action act, coenv &e, types::ty *target); types::ty *varGetType(coenv &); trans::varEntry *getCallee(coenv &e, types::signature *sig); // As a type: types::ty *typeTrans(coenv &e, bool tacit = false); virtual trans::tyEntry *tyEntryTrans(coenv &e); trans::frame *tyFrameTrans(coenv &e); void prettyprint(ostream &out, Int indent); void print(ostream& out) const { out << id; } symbol getName() { return id; } }; class qualifiedName : public name { name *qualifier; symbol id; // Gets the record type associated with the qualifier. Reports an // error and returns null if the type is not a record. record *castToRecord(types::ty *t, bool tacit = false); // Translates as a virtual field, if possible. qt is the type of the // qualifier. Return true if there was a matching virtual field. bool varTransVirtual(action act, coenv &e, types::ty *target, types::ty *qt); // Translates as an ordinary (non-virtual) field of a record, r. void varTransField(action act, coenv &e, types::ty *target, record *r); public: qualifiedName(position pos, name *qualifier, symbol id) : name(pos), qualifier(qualifier), id(id) {} trans::varEntry *getVarEntry(coenv &e); // As a variable: void varTrans(action act, coenv &, types::ty *target); types::ty *varGetType(coenv &); trans::varEntry *getCallee(coenv &e, types::signature *sig); // As a type: types::ty *typeTrans(coenv &e, bool tacit = false); trans::tyEntry *tyEntryTrans(coenv &e); trans::frame *tyFrameTrans(coenv &e); void prettyprint(ostream &out, Int indent); void print(ostream& out) const { out << *qualifier << "." << id; } symbol getName() { return id; } }; } // namespace absyntax #endif asymptote-2.37/newexp.cc000066400000000000000000000102551265434602500153210ustar00rootroot00000000000000/***** * newexp.cc * Andy Hammerlindl 2003/07/28 * * Handles the abstract syntax for expressions the create new objects, * such as record, array, and function constructors. *****/ #include "newexp.h" #include "stm.h" #include "runtime.h" #include "runarray.h" #include "coenv.h" #include "inst.h" using namespace types; using trans::coder; using trans::coenv; using vm::inst; namespace absyntax { void printFrame(frame *f) { if (f == 0) { cerr << '0'; } else { cerr << f << " of "; printFrame(f->getParent()); } } void newRecordExp::prettyprint(ostream &out, Int indent) { prettyname(out, "newRecordExp", indent); } bool newRecordExp::encodeLevel(position pos, coenv &e, trans::tyEntry *ent) { record *r = dynamic_cast(ent->t); assert(r); // The level needed on which to allocate the record. frame *level = r->getLevel()->getParent(); if (ent->v) { // Put the record on the stack. For instance, in code like // import imp; // new imp.t; // we are putting the instance of imp on the stack, so we can use it to // allocate an instance of imp.t. ent->v->getLocation()->encode(trans::READ, pos, e.c); // Adjust to the right frame. For instance, in the last new in // struct A { // struct B { // static struct C {} // } // B b=new B; // } // A a=new A; // new a.b.C; // we push a.b onto the stack, but need a as the enclosing frame for // allocating an instance of C. record *q = dynamic_cast(ent->v->getType()); return e.c.encode(level, q->getLevel()); } else return e.c.encode(level); } types::ty *newRecordExp::transFromTyEntry(position pos, coenv &e, trans::tyEntry *ent) { types::ty *t = ent->t; if (t->kind == ty_error) return t; else if (t->kind != ty_record) { em.error(pos); em << "type '" << *t << "' is not a structure"; return primError(); } // Put the enclosing frame on the stack. if (!encodeLevel(pos, e, ent)) { em.error(pos); em << "allocation of struct '" << *t << "' is not in a valid scope"; return primError(); } record *r = dynamic_cast(t); assert(r); // Encode the allocation. e.c.encode(inst::makefunc,r->getInit()); e.c.encode(inst::popcall); return t; } types::ty *newRecordExp::trans(coenv &e) { return transFromTyEntry(getPos(), e, result->transAsTyEntry(e, 0)); } types::ty *newRecordExp::getType(coenv &e) { types::ty *t = result->trans(e, true); if (t->kind != ty_error && t->kind != ty_record) return primError(); else return t; } void newArrayExp::prettyprint(ostream &out, Int indent) { prettyname(out,"newArrayExp",indent); celltype->prettyprint(out, indent+1); if (dimexps) dimexps->prettyprint(out, indent+1); if (dims) dims->prettyprint(out, indent+1); if (ai) ai->prettyprint(out, indent+1); } types::ty *newArrayExp::trans(coenv &e) { types::ty *c = celltype->trans(e); if (c->kind == ty_void) { em.error(getPos()); em << "cannot declare array of type void"; return primError(); } if (dims) c = dims->truetype(c); if (ai) { ai->transToType(e, c); return c; } else if (dimexps || dims) { if (dimexps) { for (size_t i = 0; i < dimexps->size(); ++i) { (*dimexps)[i]->transToType(e, types::primInt()); c = new types::array(c); } } if (dims) { for (size_t i = 0; i < dims->size(); ++i) { e.c.encode(inst::intpush,0); } } e.c.encode(inst::intpush, (Int) ((dimexps ? dimexps->size():0) + (dims ? dims->size():0))); e.c.encode(inst::builtin, run::newDeepArray); return c; } else { em.compiler(getPos()); em << "new array expression must have either dims or dimexps"; return primError(); } } types::ty *newArrayExp::getType(coenv &e) { types::ty *c = celltype->trans(e); if (c->kind == ty_void) { return primError(); } if (dims) c = dims->truetype(c); if (dimexps) { Int depth = (Int)dimexps->size(); while (depth > 0) { c = new types::array(c); depth--; } } return c; } } // namespace absyntax asymptote-2.37/newexp.h000066400000000000000000000023761265434602500151700ustar00rootroot00000000000000/***** * newexp.h * Andy Hammerlindl 2003/07/28 * * Handles the abstract syntax for expressions the create new objects, * such as record, array, and function constructors. *****/ #ifndef NEWEXP_H #define NEWEXP_H #include "exp.h" #include "dec.h" #include "fundec.h" #include "entry.h" namespace absyntax { typedef fundef newFunctionExp; class newRecordExp : public exp { ty *result; static bool encodeLevel(position pos, coenv &e, trans::tyEntry *ent); public: newRecordExp(position pos, ty *result) : exp(pos), result(result) {} void prettyprint(ostream &out, Int indent); static types::ty *transFromTyEntry(position pos, coenv &e, trans::tyEntry *ent); types::ty *trans(coenv &e); types::ty *getType(coenv &e); }; class newArrayExp : public exp { ty *celltype; explist *dimexps; dimensions *dims; arrayinit *ai; public: newArrayExp(position pos, ty *celltype, explist *dimexps, dimensions *dims, arrayinit *ai) : exp(pos), celltype(celltype), dimexps(dimexps), dims(dims), ai(ai) {} void prettyprint(ostream &out, Int indent); types::ty *trans(coenv &e); types::ty *getType(coenv &e); }; } // namespace absyntax #endif asymptote-2.37/opcodes.h000066400000000000000000000016251265434602500153120ustar00rootroot00000000000000/***** * opcodes.h * Andy Hammerlindl 2010/10/24 * * A list of the virtual machine opcodes, defined by the macro OPCODE. *****/ /* The first parameter is the name of the opcode. The second parameter is a * character indicating what additional information (if any) is encoded with * the opcode: * x - nothing * n - integer * t - item * b - builtin * l - lambda pointer * o - instruction offset */ OPCODE(nop, 'x') OPCODE(pop,'x') OPCODE(intpush,'n') OPCODE(constpush,'t') OPCODE(varpush,'n') OPCODE(varsave,'n') OPCODE(fieldpush,'n') OPCODE(fieldsave,'n') OPCODE(builtin,'b') OPCODE(jmp,'o') OPCODE(cjmp,'o') OPCODE(njmp,'o') OPCODE(popcall,'x') OPCODE(pushclosure,'x') OPCODE(makefunc,'l') OPCODE(ret,'x') OPCODE(pushframe,'n') OPCODE(popframe,'x') OPCODE(push_default,'x') OPCODE(jump_if_not_default,'o') #ifdef COMBO OPCODE(varpop,'n') OPCODE(fieldpop,'n') OPCODE(gejmp,'o') #endif asymptote-2.37/opsymbols.pl000077500000000000000000000020321265434602500160650ustar00rootroot00000000000000#!/usr/bin/env perl ##### # opsymbols.pl # Andy Hammerlindl 2010/06/01 # # Extract mapping such as '+' --> SYM_PLUS from camp.l ##### open(header, ">opsymbols.h") || die("Couldn't open opsymbols.h for writing"); print header <) { if (m/^"(\S+)"\s*{\s*DEFSYMBOL\((\w+)\);/) { add($1, $2); } if (m/^(\w+)\s*{\s*DEFSYMBOL\((\w+)\);/) { add($1, $2); } if (m/^\s*EXTRASYMBOL\(\s*(\w+)\s*,\s*(\w+)\s*\)/) { add($1, $2); } } print header < #include #include "common.h" #include "angle.h" namespace camp { class pair : public gc { double x; double y; public: pair() : x(0.0), y(0.0) {} pair(double x, double y=0.0) : x(x), y(y) {} double getx() const { return x; } double gety() const { return y; } bool isreal() {return y == 0;} friend pair operator+ (const pair& z, const pair& w) { return pair(z.x+w.x,z.y+w.y); } friend pair operator- (const pair& z, const pair& w) { return pair(z.x-w.x,z.y-w.y); } friend pair operator- (const pair& z) { return pair(-z.x,-z.y); } // Complex multiplication friend pair operator* (const pair& z, const pair& w) { return pair(z.x*w.x-z.y*w.y,z.x*w.y+w.x*z.y); } const pair& operator+= (const pair& w) { x += w.x; y += w.y; return *this; } const pair& operator-= (const pair& w) { x -= w.x; y -= w.y; return *this; } const pair& operator*= (const pair& w) { (*this) = (*this) * w; return (*this); } const pair& operator/= (const pair& w) { (*this) = (*this) / w; return (*this); } const pair& scale (double xscale, double yscale) { x *= xscale; y *= yscale; return *this; } friend pair operator/ (const pair &z, double t) { if (t == 0.0) reportError("division by 0"); t=1.0/t; return pair(z.x*t, z.y*t); } friend pair operator/ (const pair& z, const pair& w) { if (!w.nonZero()) reportError("division by pair (0,0)"); double t = 1.0 / (w.x*w.x + w.y*w.y); return pair(t*(z.x*w.x + z.y*w.y), t*(-z.x*w.y + w.x*z.y)); } friend bool operator== (const pair& z, const pair& w) { return z.x == w.x && z.y == w.y; } friend bool operator!= (const pair& z, const pair& w) { return z.x != w.x || z.y != w.y; } double abs2() const { return x*x + y*y; } double length() const { return sqrt(abs2()); } friend double length(const pair& z) { return z.length(); } double angle() const { return camp::angle(x,y); } friend double angle(const pair& z) { return z.angle(); } friend pair unit(const pair& z) { double scale=z.length(); if(scale == 0.0) return z; scale=1.0/scale; return pair(z.x*scale,z.y*scale); } friend pair conj(const pair& z) { return pair(z.x,-z.y); } friend double dot(const pair& z, const pair& w) { return z.x*w.x+z.y*w.y; } friend double cross(const pair& z, const pair& w) { return z.x*w.y-z.y*w.x; } // Return the principal branch of the square root (non-negative real part). friend pair Sqrt(const pair& z) { double mag=z.length(); if(mag == 0.0) return pair(0.0,0.0); else if(z.x > 0) { double re=sqrt(0.5*(mag+z.x)); return pair(re,0.5*z.y/re); } else { double im=sqrt(0.5*(mag-z.x)); if(z.y < 0) im=-im; return pair(0.5*z.y/im,im); } } bool nonZero() const { return x != 0.0 || y != 0.0; } friend istream& operator >> (istream& s, pair& z) { char c; s >> std::ws; bool paren=s.peek() == '('; // parenthesis are optional if(paren) s >> c; s >> z.x >> std::ws; if(!s.eof() && s.peek() == ',') s >> c >> z.y; else z.y=0.0; if(paren) { s >> std::ws; if(s.peek() == ')') s >> c; } return s; } friend ostream& operator << (ostream& out, const pair& z) { out << "(" << z.x << "," << z.y << ")"; return out; } friend class box; }; // Calculates exp(i * theta), useful for unit vectors. inline pair expi(double theta) { if(theta == 0.0) return pair(1.0,0.0); // Frequently occurring case return pair(cos(theta),sin(theta)); } // Complex exponentiation inline pair pow(const pair& z, const pair& w) { double u=w.getx(); double v=w.gety(); if(z == 0.0) return w == 0.0 ? 1.0 : 0.0; double logr=0.5*log(z.abs2()); double th=z.angle(); return exp(logr*u-th*v)*expi(logr*v+th*u); } } //namespace camp GC_DECLARE_PTRFREE(camp::pair); #endif asymptote-2.37/parser.cc000066400000000000000000000055601265434602500153120ustar00rootroot00000000000000/***** * parser.cc * Tom Prince 2004/01/10 * *****/ #include #include #include "common.h" #ifdef HAVE_SYS_STAT_H #include #endif #include "interact.h" #include "locate.h" #include "errormsg.h" #include "parser.h" // The lexical analysis and parsing functions used by parseFile. void setlexer(size_t (*input) (char* bif, size_t max_size), string filename); extern bool yyparse(void); extern int yydebug; extern int yy_flex_debug; static const int YY_NULL = 0; extern bool lexerEOF(); extern void reportEOF(); namespace parser { namespace yy { // Lexers std::streambuf *sbuf = NULL; size_t stream_input(char *buf, size_t max_size) { size_t count= sbuf ? sbuf->sgetn(buf,max_size) : 0; return count ? count : YY_NULL; } } // namespace yy void debug(bool state) { // For debugging the machine-generated lexer and parser. yy_flex_debug = yydebug = state; } namespace { void error(const string& filename) { em.sync(); em << "error: could not load module '" << filename << "'\n"; em.sync(); throw handled_error(); } } absyntax::file *doParse(size_t (*input) (char* bif, size_t max_size), const string& filename, bool extendable=false) { setlexer(input,filename); absyntax::file *root = yyparse() == 0 ? absyntax::root : 0; absyntax::root = 0; yy::sbuf = 0; if (!root) { if (lexerEOF()) { if (extendable) { return 0; } else { // Have the lexer report the error. reportEOF(); } } em.error(nullPos); if(!interact::interactive) error(filename); else throw handled_error(); } return root; } absyntax::file *parseStdin() { debug(false); yy::sbuf = cin.rdbuf(); return doParse(yy::stream_input,"-"); } absyntax::file *parseFile(const string& filename, const char *nameOfAction) { if(filename == "-") return parseStdin(); string file = settings::locateFile(filename); if(file.empty()) error(filename); if(nameOfAction && settings::verbose > 1) cerr << nameOfAction << " " << filename << " from " << file << endl; debug(false); std::filebuf filebuf; if(!filebuf.open(file.c_str(),std::ios::in)) error(filename); #ifdef HAVE_SYS_STAT_H // Check that the file is not a directory. static struct stat buf; if(stat(file.c_str(),&buf) == 0) { if(S_ISDIR(buf.st_mode)) error(filename); } #endif // Check that the file can actually be read. try { filebuf.sgetc(); } catch (...) { error(filename); } yy::sbuf = &filebuf; return doParse(yy::stream_input,file); } absyntax::file *parseString(const string& code, const string& filename, bool extendable) { debug(false); stringbuf buf(code); yy::sbuf = &buf; return doParse(yy::stream_input,filename,extendable); } } // namespace parser asymptote-2.37/parser.h000066400000000000000000000015241265434602500151500ustar00rootroot00000000000000/***** * parser.h * Tom Prince 2004/01/10 * *****/ #ifndef PARSER_H #define PARSER_H #include "common.h" #include "absyn.h" namespace parser { // Opens and parses the file returning the abstract syntax tree. If // there is an unrecoverable parse error, returns null. absyntax::file *parseFile(const string& filename, const char *nameOfAction); // Parses string and returns the abstract syntax tree. Any error in lexing or // parsing will be reported and a handled_error thrown. If the string is // "extendable", then a parse error simply due to running out of input will not // throw an exception, but will return null. absyntax::file *parseString(const string& code, const string& filename, bool extendable=false); } // namespace parser #endif // PARSER_H asymptote-2.37/patches/000077500000000000000000000000001265434602500151305ustar00rootroot00000000000000asymptote-2.37/patches/README000066400000000000000000000015321265434602500160110ustar00rootroot00000000000000The optional patches to flex-2.5.31 and bison-2.0a in this directory fix a number of problems with warning and/or error messages generated by strict compilers. A modified version of dvipdf that accepts common dvips options is included. The file gcc3.3.2curses.patch can be used to patch the broken curses.h header files (or a local copy thereof in the current directory) on some AIX and IRIX systems. The file gc6.8_AIX.patch fixes an incorrect Boehm garbage collector prototype in the file gc6.8/include/gc.h (version 6.8). The file gc-7.0nomem.patch avoids segmentation faults with gc-7.0 on out-of-memory errors. The file fixmem.reg patches the Microsoft Windows registry so that the cygwin1.dll library can allocate more than 384MB. It is applied automatically by the Asymptote setup.exe file but may also be applied manually: regedit /s fixmem.reg asymptote-2.37/patches/bison.patch000066400000000000000000000122161265434602500172650ustar00rootroot00000000000000diff -ru bison-2.0a/data/yacc.c bison-2.0aJ/data/yacc.c --- bison-2.0a/data/yacc.c 2005-05-21 11:12:32.000000000 -0600 +++ bison-2.0aJ/data/yacc.c 2005-06-30 18:14:16.509158136 -0600 @@ -237,7 +237,7 @@ # ifdef YYSTACK_ALLOC /* Pacify GCC's `empty if-body' warning. */ -# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# define YYSTACK_FREE(Ptr) { /* empty */; } # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely @@ -291,19 +291,20 @@ /* Copy COUNT objects from FROM to TO. The source and destination do not overlap. */ # ifndef YYCOPY -# if defined (__GNUC__) && 1 < __GNUC__ +# if defined (__GNUC__) +# if 1 < __GNUC__ # define YYCOPY(To, From, Count) \ __builtin_memcpy (To, From, (Count) * sizeof (*(From))) -# else +# endif +# endif +# endif +# ifndef YYCOPY # define YYCOPY(To, From, Count) \ - do \ { \ YYSIZE_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (To)[yyi] = (From)[yyi]; \ - } \ - while (0) -# endif + } # endif /* Relocate STACK from its old location to the new one. The @@ -312,15 +313,13 @@ stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack) \ - do \ { \ YYSIZE_T yynewbytes; \ YYCOPY (&yyptr->Stack, Stack, yysize); \ Stack = &yyptr->Stack; \ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / sizeof (*yyptr); \ - } \ - while (0) + } #endif @@ -487,6 +486,7 @@ #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab +int yy_false=false; /* Used to suppress compiler warning about unused label */ /* Like YYERROR except do call yyerror. This remains here temporarily @@ -498,7 +498,7 @@ #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ -do \ +{ \ if (yychar == YYEMPTY && yylen == 1) \ { \ yychar = (Token); \ @@ -512,7 +512,7 @@ yyerror (]b4_yyerror_args[_("syntax error: cannot back up")); \ YYERROR; \ } \ -while (0) +} #define YYTERROR 1 @@ -526,7 +526,7 @@ #define YYRHSLOC(Rhs, K) ((Rhs)[K]) #ifndef YYLLOC_DEFAULT # define YYLLOC_DEFAULT(Current, Rhs, N) \ - do \ + { \ if (N) \ { \ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ @@ -541,7 +541,7 @@ (Current).first_column = (Current).last_column = \ YYRHSLOC (Rhs, 0).last_column; \ } \ - while (0) + } #endif @@ -550,7 +550,7 @@ we won't break user code: when these are the locations we know. */ #ifndef YY_LOCATION_PRINT -# if YYLTYPE_IS_TRIVIAL +# ifdef YYLTYPE_IS_TRIVIAL # define YY_LOCATION_PRINT(File, Loc) \ fprintf (File, "%d.%d-%d.%d", \ (Loc).first_line, (Loc).first_column, \ @@ -578,13 +578,13 @@ # endif # define YYDPRINTF(Args) \ -do { \ +{ \ if (yydebug) \ YYFPRINTF Args; \ -} while (0) +} # define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ -do { \ +{ \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ @@ -592,7 +592,7 @@ Type, Value]b4_location_if([, Location])[); \ YYFPRINTF (stderr, "\n"); \ } \ -} while (0) +} /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | @@ -610,10 +610,10 @@ } # define YY_STACK_PRINT(Bottom, Top) \ -do { \ +{ \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ -} while (0) +} /*------------------------------------------------. @@ -634,10 +634,10 @@ } # define YY_REDUCE_PRINT(Rule) \ -do { \ +{ \ if (yydebug) \ yy_reduce_print (Rule); \ -} while (0) +} /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ @@ -826,7 +826,7 @@ /* When reducing, the number of symbols on the RHS of the reduced rule. */ - int yylen; + int yylen=0; YYDPRINTF ((stderr, "Starting parse\n")); @@ -874,7 +874,7 @@ yyssp++; yysetstate: - *yyssp = yystate; + *yyssp = (short int) yystate; if (yyss + yystacksize - 1 <= yyssp) { @@ -1222,12 +1222,6 @@ `---------------------------------------------------*/ yyerrorlab: - /* Pacify compilers like GCC when the user code never invokes - YYERROR and the label yyerrorlab therefore never appears in user - code. */ - if (0) - goto yyerrorlab; - ]b4_location_if([[ yyerror_range[0] = yylsp[1-yylen]; yylsp -= yylen; ]])[yyvsp -= yylen; @@ -1297,6 +1291,13 @@ `-----------------------------------*/ yyabortlab: yyresult = 1; + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (yy_false) + goto yyerrorlab; + goto yyreturn; #ifndef yyoverflow asymptote-2.37/patches/cygwin_glu.patch000066400000000000000000000060271265434602500203250ustar00rootroot00000000000000--- w32api.orig/GL/glu.h 2014-04-18 22:30:50.186158900 -0600 +++ w32api/GL/glu.h 2014-04-18 22:42:59.095926900 -0600 @@ -108,8 +108,12 @@ typedef void (CALLBACK *GLUtessCombineDataProc)(GLdouble[3],void*[4],GLfloat[4],void**,void*); typedef void (CALLBACK *GLUnurbsErrorProc)(GLenum); +#define GLU_EXT_object_space_tess 1 +#define GLU_EXT_nurbs_tessellator 1 + #define GLU_VERSION_1_1 1 #define GLU_VERSION_1_2 1 +#define GLU_VERSION_1_3 1 #define GLU_INVALID_ENUM 100900 #define GLU_INVALID_VALUE 100901 @@ -183,7 +187,17 @@ #define GLU_SAMPLING_METHOD 100205 #define GLU_U_STEP 100206 #define GLU_V_STEP 100207 - +#define GLU_NURBS_MODE 100160 +#define GLU_NURBS_MODE_EXT 100160 +#define GLU_NURBS_TESSELLATOR 100161 +#define GLU_NURBS_TESSELLATOR_EXT 100161 +#define GLU_NURBS_RENDERER 100162 +#define GLU_NURBS_RENDERER_EXT 100162 + +#define GLU_OBJECT_PARAMETRIC_ERROR 100208 +#define GLU_OBJECT_PARAMETRIC_ERROR_EXT 100208 +#define GLU_OBJECT_PATH_LENGTH 100209 +#define GLU_OBJECT_PATH_LENGTH_EXT 100209 #define GLU_PATH_LENGTH 100215 #define GLU_PARAMETRIC_ERROR 100216 #define GLU_DOMAIN_DISTANCE 100217 @@ -194,6 +208,33 @@ #define GLU_OUTLINE_POLYGON 100240 #define GLU_OUTLINE_PATCH 100241 +#define GLU_NURBS_ERROR 100103 +#define GLU_ERROR 100103 +#define GLU_NURBS_BEGIN 100164 +#define GLU_NURBS_BEGIN_EXT 100164 +#define GLU_NURBS_VERTEX 100165 +#define GLU_NURBS_VERTEX_EXT 100165 +#define GLU_NURBS_NORMAL 100166 +#define GLU_NURBS_NORMAL_EXT 100166 +#define GLU_NURBS_COLOR 100167 +#define GLU_NURBS_COLOR_EXT 100167 +#define GLU_NURBS_TEXTURE_COORD 100168 +#define GLU_NURBS_TEX_COORD_EXT 100168 +#define GLU_NURBS_END 100169 +#define GLU_NURBS_END_EXT 100169 +#define GLU_NURBS_BEGIN_DATA 100170 +#define GLU_NURBS_BEGIN_DATA_EXT 100170 +#define GLU_NURBS_VERTEX_DATA 100171 +#define GLU_NURBS_VERTEX_DATA_EXT 100171 +#define GLU_NURBS_NORMAL_DATA 100172 +#define GLU_NURBS_NORMAL_DATA_EXT 100172 +#define GLU_NURBS_COLOR_DATA 100173 +#define GLU_NURBS_COLOR_DATA_EXT 100173 +#define GLU_NURBS_TEXTURE_COORD_DATA 100174 +#define GLU_NURBS_TEX_COORD_DATA_EXT 100174 +#define GLU_NURBS_END_DATA 100175 +#define GLU_NURBS_END_DATA_EXT 100175 + #define GLU_NURBS_ERROR1 100251 #define GLU_NURBS_ERROR2 100252 #define GLU_NURBS_ERROR3 100253 @@ -248,6 +289,13 @@ #define GLU_ERROR GLU_TESS_ERROR #define GLU_EDGE_FLAG GLU_TESS_EDGE_FLAG +/* Internal convenience typedefs */ +#ifdef __cplusplus +typedef void (APIENTRY *_GLUfuncptr)(); +#else +typedef void (APIENTRY *_GLUfuncptr)(GLvoid); +#endif + #ifdef __cplusplus } #endif asymptote-2.37/patches/dvipdf000077500000000000000000000024371265434602500163400ustar00rootroot00000000000000#!/bin/sh # $Id$ # Convert DVI to PDF. # # Please contact Andrew Ford with any questions # about this file. # # Based on ps2pdf # This definition is changed on install to match the # executable name set in the makefile GS_EXECUTABLE=gs OPTIONS="-DSAFER -P" DVIPSOPTIONS="" while true do case "$1" in -R*) DVIPSOPTIONS="$DVIPSOPTIONS $1";; -z) DVIPSOPTIONS="$DVIPSOPTIONS -z" ;; -pp) shift; DVIPSOPTIONS="$DVIPSOPTIONS -pp $1" ;; -p) shift; DVIPSOPTIONS="$DVIPSOPTIONS -p $1" ;; -t) shift; DVIPSOPTIONS="$DVIPSOPTIONS -t $1" ;; -T) shift; DVIPSOPTIONS="$DVIPSOPTIONS -T $1" ;; -l) shift; DVIPSOPTIONS="$DVIPSOPTIONS -l $1" ;; -?*) OPTIONS="$OPTIONS $1" ;; *) break ;; esac shift done if [ $# -lt 1 -o $# -gt 2 ]; then echo "Usage: `basename $0` [options...] input.dvi [output.pdf]" 1>&2 exit 1 fi infile=$1; if [ $# -eq 1 ] then case "${infile}" in *.dvi) base=`basename "${infile}" .dvi` ;; *) base=`basename "${infile}"` ;; esac outfile="${base}".pdf else outfile=$2 fi # We have to include the options twice because -I only takes effect if it # appears before other options. exec dvips $DVIPSOPTIONS -q -f "$infile" | $GS_EXECUTABLE $OPTIONS -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sstdout=%stderr -sOutputFile="$outfile" $OPTIONS -c .setpdfwrite - asymptote-2.37/patches/fixmem.reg000066400000000000000000000001611265434602500171120ustar00rootroot00000000000000Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\Software\Cygwin] "heap_chunk_in_mb"=dword:ffffff00 asymptote-2.37/patches/flex.patch000066400000000000000000000027641265434602500171200ustar00rootroot00000000000000diff -u flex-2.5.39/gen.c flex-2.5.39J/gen.c --- flex-2.5.39/gen.c 2014-03-26 06:46:44.000000000 -0600 +++ flex-2.5.39J/gen.c 2014-04-26 10:52:30.962073096 -0600 @@ -55,6 +55,14 @@ * 0 elements of its arrays, too.) */ +static const char *get_yy_char_decl (void) +{ + return (gentables) + ? "static yyconst YY_CHAR %s[%d] =\n { 0,\n" + : "static yyconst YY_CHAR * %s = 0;\n"; +} + + static const char *get_int16_decl (void) { return (gentables) @@ -465,7 +473,7 @@ register int i, j; int numrows; - out_str_dec (get_int32_decl (), "yy_ec", csize); + out_str_dec (get_yy_char_decl (), "yy_ec", csize); for (i = 1; i < csize; ++i) { ecgroup[i] = ABS (ecgroup[i]); @@ -1271,7 +1279,7 @@ fputs (_("\n\nMeta-Equivalence Classes:\n"), stderr); - out_str_dec (get_int32_decl (), "yy_meta", numecs + 1); + out_str_dec (get_yy_char_decl (), "yy_meta", numecs + 1); buf_prints (&yydmap_buf, "\t{YYTD_ID_META, (void**)&yy_meta, sizeof(%s)},\n", "flex_int32_t"); @@ -1516,11 +1524,11 @@ if (yymore_used && !yytext_is_array) { indent_puts ("YY_G(yytext_ptr) -= YY_G(yy_more_len); \\"); indent_puts - ("yyleng = (size_t) (yy_cp - YY_G(yytext_ptr)); \\"); + ("yyleng = (int) (yy_cp - YY_G(yytext_ptr)); \\"); } else - indent_puts ("yyleng = (size_t) (yy_cp - yy_bp); \\"); + indent_puts ("yyleng = (int) (yy_cp - yy_bp); \\"); /* Now also deal with copying yytext_ptr to yytext if needed. */ skelout (); /* %% [3.0] - break point in skel */ asymptote-2.37/patches/gc-7.0nomem.patch000066400000000000000000000007511265434602500201030ustar00rootroot00000000000000*** gc_hdrs.h.orig Tue Jun 5 14:01:25 2007 --- gc_hdrs.h Thu Oct 18 14:32:03 2007 *************** *** 112,119 **** hhdr = hce -> hce_hdr; \ } else { \ hhdr = HEADER_CACHE_MISS(p, hce, source); \ - if (0 == hhdr) goto exit_label; \ } \ } typedef struct bi { --- 112,119 ---- hhdr = hce -> hce_hdr; \ } else { \ hhdr = HEADER_CACHE_MISS(p, hce, source); \ } \ + if (0 == hhdr) goto exit_label; \ } typedef struct bi { asymptote-2.37/patches/gc6.8_AIX.patch000066400000000000000000000004171265434602500175010ustar00rootroot00000000000000*** gc.h.orig Fri Jul 7 18:10:16 2006 --- gc.h Mon Feb 12 12:30:48 2007 *************** *** 981 **** ! # define GC_INIT() { GC_add_roots(GC_DATASTART, GC_DATAEND); } --- 981 ---- ! # define GC_INIT() { GC_add_roots((char *) GC_DATASTART, (char *) GC_DATAEND); } asymptote-2.37/patches/gcc3.3.2curses.patch000066400000000000000000000004761265434602500205250ustar00rootroot00000000000000*** curses.h.orig Sun Feb 11 21:43:36 2007 --- curses.h Sun Feb 11 21:43:21 2007 *************** *** 1302 **** ! #if defined(__USE_FIXED_PROTOTYPES__) || defined(__cplusplus) || defined (__STRICT_ANSI__) --- 1302 ---- ! #if 0 && (defined(__USE_FIXED_PROTOTYPES__) || defined(__cplusplus) || defined (__STRICT_ANSI__)) asymptote-2.37/path.cc000066400000000000000000001021101265434602500147370ustar00rootroot00000000000000/***** * path.cc * Andy Hammerlindl 2002/06/06 * * Stores and returns information on a predefined path. * * When changing the path algorithms, also update the corresponding * three-dimensional algorithms in path3.cc. *****/ #include "path.h" #include "util.h" #include "angle.h" #include "camperror.h" #include "mathop.h" #include "predicates.h" #include "rounding.h" namespace camp { const double Fuzz=1000.0*DBL_EPSILON; const double BigFuzz=10.0*Fuzz; const double Fuzz2=Fuzz*Fuzz; const double sqrtFuzz=sqrt(Fuzz); const double fuzzFactor=10.0; const double third=1.0/3.0; path nullpath; const char *nopoints="nullpath has no points"; void checkEmpty(Int n) { if(n == 0) reportError(nopoints); } // Accurate computation of sqrt(1+x)-1. inline double sqrt1pxm1(double x) { return x/(sqrt(1.0+x)+1.0); } inline pair sqrt1pxm1(pair x) { return x/(Sqrt(1.0+x)+1.0); } // Solve for the real roots of the quadratic equation ax^2+bx+c=0. quadraticroots::quadraticroots(double a, double b, double c) { // Remove roots at numerical infinity. if(fabs(a) <= Fuzz*(fabs(b)+fabs(c)*Fuzz)) { if(fabs(b) > Fuzz*fabs(c)) { distinct=quadraticroots::ONE; roots=1; t1=-c/b; } else if(c == 0.0) { distinct=quadraticroots::MANY; roots=1; t1=0.0; } else { distinct=quadraticroots::NONE; roots=0; } } else { double factor=0.5*b/a; double denom=b*factor; if(fabs(denom) <= Fuzz*fabs(c)) { double x=-c/a; if(x >= 0.0) { distinct=quadraticroots::TWO; roots=2; t2=sqrt(x); t1=-t2; } else { distinct=quadraticroots::NONE; roots=0; } } else { double x=-2.0*c/denom; if(x > -1.0) { distinct=quadraticroots::TWO; roots=2; double r2=factor*sqrt1pxm1(x); double r1=-r2-2.0*factor; if(r1 <= r2) { t1=r1; t2=r2; } else { t1=r2; t2=r1; } } else if(x == -1.0) { distinct=quadraticroots::ONE; roots=2; t1=t2=-factor; } else { distinct=quadraticroots::NONE; roots=0; } } } } // Solve for the complex roots of the quadratic equation ax^2+bx+c=0. Quadraticroots::Quadraticroots(pair a, pair b, pair c) { if(a == 0.0) { if(b != 0.0) { roots=1; z1=-c/b; } else if(c == 0.0) { roots=1; z1=0.0; } else roots=0; } else { roots=2; pair factor=0.5*b/a; pair denom=b*factor; if(denom == 0.0) { z1=Sqrt(-c/a); z2=-z1; } else { z1=factor*sqrt1pxm1(-2.0*c/denom); z2=-z1-2.0*factor; } } } inline bool goodroot(double a, double b, double c, double t) { return goodroot(t) && quadratic(a,b,c,t) >= 0.0; } // Accurate computation of cbrt(sqrt(1+x)+1)-cbrt(sqrt(1+x)-1). inline double cbrtsqrt1pxm(double x) { double s=sqrt1pxm1(x); return 2.0/(cbrt(x+2.0*(sqrt(1.0+x)+1.0))+cbrt(x)+cbrt(s*s)); } // Taylor series of cos((atan(1.0/w)+pi)/3.0). static inline double costhetapi3(double w) { static const double c1=1.0/3.0; static const double c3=-19.0/162.0; static const double c5=425.0/5832.0; static const double c7=-16829.0/314928.0; double w2=w*w; double w3=w2*w; double w5=w3*w2; return c1*w+c3*w3+c5*w5+c7*w5*w2; } // Solve for the real roots of the cubic equation ax^3+bx^2+cx+d=0. cubicroots::cubicroots(double a, double b, double c, double d) { static const double ninth=1.0/9.0; static const double fiftyfourth=1.0/54.0; // Remove roots at numerical infinity. if(fabs(a) <= Fuzz*(fabs(b)+fabs(c)*Fuzz+fabs(d)*Fuzz2)) { quadraticroots q(b,c,d); roots=q.roots; if(q.roots >= 1) t1=q.t1; if(q.roots == 2) t2=q.t2; return; } // Detect roots at numerical zero. if(fabs(d) <= Fuzz*(fabs(c)+fabs(b)*Fuzz+fabs(a)*Fuzz2)) { quadraticroots q(a,b,c); roots=q.roots+1; t1=0; if(q.roots >= 1) t2=q.t1; if(q.roots == 2) t3=q.t2; return; } b /= a; c /= a; d /= a; double b2=b*b; double Q=3.0*c-b2; if(fabs(Q) < Fuzz*(3.0*fabs(c)+fabs(b2))) Q=0.0; double R=(3.0*Q+b2)*b-27.0*d; if(fabs(R) < Fuzz*((3.0*fabs(Q)+fabs(b2))*fabs(b)+27.0*fabs(d))) R=0.0; Q *= ninth; R *= fiftyfourth; double Q3=Q*Q*Q; double R2=R*R; double D=Q3+R2; double mthirdb=-b*third; if(D > 0.0) { roots=1; t1=mthirdb; if(R2 != 0.0) t1 += cbrt(R)*cbrtsqrt1pxm(Q3/R2); } else { roots=3; double v=0.0,theta; if(R2 > 0.0) { v=sqrt(-D/R2); theta=atan(v); } else theta=0.5*PI; double factor=2.0*sqrt(-Q)*(R >= 0 ? 1 : -1); t1=mthirdb+factor*cos(third*theta); t2=mthirdb-factor*cos(third*(theta-PI)); t3=mthirdb; if(R2 > 0.0) t3 -= factor*((v < 100.0) ? cos(third*(theta+PI)) : costhetapi3(1.0/v)); } } pair path::point(double t) const { checkEmpty(n); Int i = Floor(t); Int iplus; t = fmod(t,1); if (t < 0) t += 1; if (cycles) { i = imod(i,n); iplus = imod(i+1,n); } else if (i < 0) return nodes[0].point; else if (i >= n-1) return nodes[n-1].point; else iplus = i+1; double one_t = 1.0-t; pair a = nodes[i].point, b = nodes[i].post, c = nodes[iplus].pre, d = nodes[iplus].point, ab = one_t*a + t*b, bc = one_t*b + t*c, cd = one_t*c + t*d, abc = one_t*ab + t*bc, bcd = one_t*bc + t*cd, abcd = one_t*abc + t*bcd; return abcd; } pair path::precontrol(double t) const { checkEmpty(n); Int i = Floor(t); Int iplus; t = fmod(t,1); if (t < 0) t += 1; if (cycles) { i = imod(i,n); iplus = imod(i+1,n); } else if (i < 0) return nodes[0].pre; else if (i >= n-1) return nodes[n-1].pre; else iplus = i+1; double one_t = 1.0-t; pair a = nodes[i].point, b = nodes[i].post, c = nodes[iplus].pre, ab = one_t*a + t*b, bc = one_t*b + t*c, abc = one_t*ab + t*bc; return (abc == a) ? nodes[i].pre : abc; } pair path::postcontrol(double t) const { checkEmpty(n); Int i = Floor(t); Int iplus; t = fmod(t,1); if (t < 0) t += 1; if (cycles) { i = imod(i,n); iplus = imod(i+1,n); } else if (i < 0) return nodes[0].post; else if (i >= n-1) return nodes[n-1].post; else iplus = i+1; double one_t = 1.0-t; pair b = nodes[i].post, c = nodes[iplus].pre, d = nodes[iplus].point, bc = one_t*b + t*c, cd = one_t*c + t*d, bcd = one_t*bc + t*cd; return (bcd == d) ? nodes[iplus].post : bcd; } path path::reverse() const { mem::vector nodes(n); Int len=length(); for (Int i = 0, j = len; i < n; i++, j--) { nodes[i].pre = postcontrol(j); nodes[i].point = point(j); nodes[i].post = precontrol(j); nodes[i].straight = straight(j-1); } return path(nodes, n, cycles); } path path::subpath(Int a, Int b) const { if(empty()) return path(); if (a > b) { const path &rp = reverse(); Int len=length(); path result = rp.subpath(len-a, len-b); return result; } if (!cycles) { if (a < 0) a = 0; if (b > n-1) b = n-1; } Int sn = b-a+1; mem::vector nodes(sn); for (Int i = 0, j = a; j <= b; i++, j++) { nodes[i].pre = precontrol(j); nodes[i].point = point(j); nodes[i].post = postcontrol(j); nodes[i].straight = straight(j); } nodes[0].pre = nodes[0].point; nodes[sn-1].post = nodes[sn-1].point; return path(nodes, sn); } inline pair split(double t, const pair& x, const pair& y) { return x+(y-x)*t; } inline void splitCubic(solvedKnot sn[], double t, const solvedKnot& left_, const solvedKnot& right_) { solvedKnot &left=(sn[0]=left_), &mid=sn[1], &right=(sn[2]=right_); if(left.straight) { mid.point=split(t,left.point,right.point); pair deltaL=third*(mid.point-left.point); left.post=left.point+deltaL; mid.pre=mid.point-deltaL; pair deltaR=third*(right.point-mid.point); mid.post=mid.point+deltaR; right.pre=right.point-deltaR; mid.straight=true; } else { pair x=split(t,left.post,right.pre); // m1 left.post=split(t,left.point,left.post); // m0 right.pre=split(t,right.pre,right.point); // m2 mid.pre=split(t,left.post,x); // m3 mid.post=split(t,x,right.pre); // m4 mid.point=split(t,mid.pre,mid.post); // m5 } } path path::subpath(double a, double b) const { if(empty()) return path(); if (a > b) { const path &rp = reverse(); Int len=length(); return rp.subpath(len-a, len-b); } solvedKnot aL, aR, bL, bR; if (!cycles) { if (a < 0) { a = 0; if (b < 0) b = 0; } if (b > n-1) { b = n-1; if (a > n-1) a = n-1; } aL = nodes[(Int)floor(a)]; aR = nodes[(Int)ceil(a)]; bL = nodes[(Int)floor(b)]; bR = nodes[(Int)ceil(b)]; } else { if(run::validInt(a) && run::validInt(b)) { aL = nodes[imod((Int) floor(a),n)]; aR = nodes[imod((Int) ceil(a),n)]; bL = nodes[imod((Int) floor(b),n)]; bR = nodes[imod((Int) ceil(b),n)]; } else reportError("invalid path index"); } if (a == b) return path(point(a)); solvedKnot sn[3]; path p = subpath(Ceil(a), Floor(b)); if (a > floor(a)) { if (b < ceil(a)) { splitCubic(sn,a-floor(a),aL,aR); splitCubic(sn,(b-a)/(ceil(b)-a),sn[1],sn[2]); return path(sn[0],sn[1]); } splitCubic(sn,a-floor(a),aL,aR); p=concat(path(sn[1],sn[2]),p); } if (ceil(b) > b) { splitCubic(sn,b-floor(b),bL,bR); p=concat(p,path(sn[0],sn[1])); } return p; } // Special case of subpath for paths of length 1 used by intersect. void path::halve(path &first, path &second) const { solvedKnot sn[3]; splitCubic(sn,0.5,nodes[0],nodes[1]); first=path(sn[0],sn[1]); second=path(sn[1],sn[2]); } // Calculate the coefficients of a Bezier derivative divided by 3. static inline void derivative(pair& a, pair& b, pair& c, const pair& z0, const pair& c0, const pair& c1, const pair& z1) { a=z1-z0+3.0*(c0-c1); b=2.0*(z0+c1)-4.0*c0; c=c0-z0; } bbox path::bounds() const { if(!box.empty) return box; if (empty()) { // No bounds return bbox(); } Int len=length(); box.add(point(len)); times=bbox(len,len,len,len); for (Int i = 0; i < len; i++) { addpoint(box,i); if(straight(i)) continue; pair a,b,c; derivative(a,b,c,point(i),postcontrol(i),precontrol(i+1),point(i+1)); // Check x coordinate quadraticroots x(a.getx(),b.getx(),c.getx()); if(x.distinct != quadraticroots::NONE && goodroot(x.t1)) addpoint(box,i+x.t1); if(x.distinct == quadraticroots::TWO && goodroot(x.t2)) addpoint(box,i+x.t2); // Check y coordinate quadraticroots y(a.gety(),b.gety(),c.gety()); if(y.distinct != quadraticroots::NONE && goodroot(y.t1)) addpoint(box,i+y.t1); if(y.distinct == quadraticroots::TWO && goodroot(y.t2)) addpoint(box,i+y.t2); } return box; } bbox path::bounds(double min, double max) const { bbox box; Int len=length(); for (Int i = 0; i < len; i++) { addpoint(box,i,min,max); if(straight(i)) continue; pair a,b,c; derivative(a,b,c,point(i),postcontrol(i),precontrol(i+1),point(i+1)); // Check x coordinate quadraticroots x(a.getx(),b.getx(),c.getx()); if(x.distinct != quadraticroots::NONE && goodroot(x.t1)) addpoint(box,i+x.t1,min,max); if(x.distinct == quadraticroots::TWO && goodroot(x.t2)) addpoint(box,i+x.t2,min,max); // Check y coordinate quadraticroots y(a.gety(),b.gety(),c.gety()); if(y.distinct != quadraticroots::NONE && goodroot(y.t1)) addpoint(box,i+y.t1,min,max); if(y.distinct == quadraticroots::TWO && goodroot(y.t2)) addpoint(box,i+y.t2,min,max); } addpoint(box,len,min,max); return box; } inline void add(bbox& box, const pair& z, const pair& min, const pair& max) { box += z+min; box += z+max; } bbox path::internalbounds(const bbox& padding) const { bbox box; // Check interior nodes. Int len=length(); for (Int i = 1; i < len; i++) { pair pre=point(i)-precontrol(i); pair post=postcontrol(i)-point(i); // Check node x coordinate if((pre.getx() >= 0.0) ^ (post.getx() >= 0)) add(box,point(i),padding.left,padding.right); // Check node y coordinate if((pre.gety() >= 0.0) ^ (post.gety() >= 0)) add(box,point(i),pair(0,padding.bottom),pair(0,padding.top)); } // Check interior segments. for (Int i = 0; i < len; i++) { if(straight(i)) continue; pair a,b,c; derivative(a,b,c,point(i),postcontrol(i),precontrol(i+1),point(i+1)); // Check x coordinate quadraticroots x(a.getx(),b.getx(),c.getx()); if(x.distinct != quadraticroots::NONE && goodroot(x.t1)) add(box,point(i+x.t1),padding.left,padding.right); if(x.distinct == quadraticroots::TWO && goodroot(x.t2)) add(box,point(i+x.t2),padding.left,padding.right); // Check y coordinate quadraticroots y(a.gety(),b.gety(),c.gety()); if(y.distinct != quadraticroots::NONE && goodroot(y.t1)) add(box,point(i+y.t1),pair(0,padding.bottom),pair(0,padding.top)); if(y.distinct == quadraticroots::TWO && goodroot(y.t2)) add(box,point(i+y.t2),pair(0,padding.bottom),pair(0,padding.top)); } return box; } // {{{ Arclength Calculations static pair a,b,c; static double ds(double t) { double dx=quadratic(a.getx(),b.getx(),c.getx(),t); double dy=quadratic(a.gety(),b.gety(),c.gety(),t); return sqrt(dx*dx+dy*dy); } // Calculates arclength of a cubic using adaptive simpson integration. double path::cubiclength(Int i, double goal) const { const pair& z0=point(i); const pair& z1=point(i+1); double L; if(straight(i)) { L=(z1-z0).length(); return (goal < 0 || goal >= L) ? L : -goal/L; } const pair& c0=postcontrol(i); const pair& c1=precontrol(i+1); double integral; derivative(a,b,c,z0,c0,c1,z1); if(!simpson(integral,ds,0.0,1.0,DBL_EPSILON,1.0)) reportError("nesting capacity exceeded in computing arclength"); L=3.0*integral; if(goal < 0 || goal >= L) return L; double t=goal/L; goal *= third; static double dxmin=sqrt(DBL_EPSILON); if(!unsimpson(goal,ds,0.0,t,100.0*DBL_EPSILON,integral,1.0,dxmin)) reportError("nesting capacity exceeded in computing arctime"); return -t; } double path::arclength() const { if (cached_length != -1) return cached_length; double L=0.0; for (Int i = 0; i < n-1; i++) { L += cubiclength(i); } if(cycles) L += cubiclength(n-1); cached_length = L; return cached_length; } double path::arctime(double goal) const { if (cycles) { if (goal == 0 || cached_length == 0) return 0; if (goal < 0) { const path &rp = this->reverse(); double result = -rp.arctime(-goal); return result; } if (cached_length > 0 && goal >= cached_length) { Int loops = (Int)(goal / cached_length); goal -= loops*cached_length; return loops*n+arctime(goal); } } else { if (goal <= 0) return 0; if (cached_length > 0 && goal >= cached_length) return n-1; } double l,L=0; for (Int i = 0; i < n-1; i++) { l = cubiclength(i,goal); if (l < 0) return (-l+i); else { L += l; goal -= l; if (goal <= 0) return i+1; } } if (cycles) { l = cubiclength(n-1,goal); if (l < 0) return -l+n-1; if (cached_length > 0 && cached_length != L+l) { reportError("arclength != length.\n" "path::arclength(double) must have broken semantics.\n" "Please report this error."); } cached_length = L += l; goal -= l; return arctime(goal)+n; } else { cached_length = L; return length(); } } // }}} // {{{ Direction Time Calulation // Algorithm Stolen from Knuth's MetaFont inline double cubicDir(const solvedKnot& left, const solvedKnot& right, const pair& rot) { pair a,b,c; derivative(a,b,c,left.point,left.post,right.pre,right.point); a *= rot; b *= rot; c *= rot; quadraticroots ret(a.gety(),b.gety(),c.gety()); switch(ret.distinct) { case quadraticroots::MANY: case quadraticroots::ONE: { if(goodroot(a.getx(),b.getx(),c.getx(),ret.t1)) return ret.t1; } break; case quadraticroots::TWO: { if(goodroot(a.getx(),b.getx(),c.getx(),ret.t1)) return ret.t1; if(goodroot(a.getx(),b.getx(),c.getx(),ret.t2)) return ret.t2; } break; case quadraticroots::NONE: break; } return -1; } // TODO: Check that we handle corner cases. // Velocity(t) == (0,0) double path::directiontime(const pair& dir) const { if (dir == pair(0,0)) return 0; pair rot = pair(1,0)/unit(dir); double t; double pre,post; for (Int i = 0; i < n-1+cycles; ) { t = cubicDir(this->nodes[i],(cycles && i==n-1) ? nodes[0]:nodes[i+1],rot); if (t >= 0) return i+t; i++; if (cycles || i != n-1) { pair Pre = (point(i)-precontrol(i))*rot; pair Post = (postcontrol(i)-point(i))*rot; static pair zero(0.0,0.0); if(Pre != zero && Post != zero) { pre = angle(Pre); post = angle(Post); if ((pre <= 0 && post >= 0 && pre >= post - PI) || (pre >= 0 && post <= 0 && pre <= post + PI)) return i; } } } return -1; } // }}} // {{{ Path Intersection Calculations const unsigned maxdepth=DBL_MANT_DIG; const unsigned mindepth=maxdepth-16; void roots(std::vector &roots, double a, double b, double c, double d) { cubicroots r(a,b,c,d); if(r.roots >= 1) roots.push_back(r.t1); if(r.roots >= 2) roots.push_back(r.t2); if(r.roots == 3) roots.push_back(r.t3); } void roots(std::vector &r, double x0, double c0, double c1, double x1, double x) { double a=x1-x0+3.0*(c0-c1); double b=3.0*(x0+c1)-6.0*c0; double c=3.0*(c0-x0); double d=x0-x; roots(r,a,b,c,d); } // Return all intersection times of path g with the pair z. void intersections(std::vector& T, const path& g, const pair& z, double fuzz) { double fuzz2=fuzz*fuzz; Int n=g.length(); bool cycles=g.cyclic(); for(Int i=0; i < n; ++i) { // Check both directions to circumvent degeneracy. std::vector r; roots(r,g.point(i).getx(),g.postcontrol(i).getx(), g.precontrol(i+1).getx(),g.point(i+1).getx(),z.getx()); roots(r,g.point(i).gety(),g.postcontrol(i).gety(), g.precontrol(i+1).gety(),g.point(i+1).gety(),z.gety()); size_t m=r.size(); for(size_t j=0 ; j < m; ++j) { double t=r[j]; if(t >= -Fuzz && t <= 1.0+Fuzz) { double s=i+t; if((g.point(s)-z).abs2() <= fuzz2) { if(cycles && s >= n-Fuzz) s=0; T.push_back(s); } } } } } inline bool online(const pair&p, const pair& q, const pair& z, double fuzz) { if(p == q) return (z-p).abs2() <= fuzz*fuzz; return (z.getx()-p.getx())*(q.gety()-p.gety()) == (q.getx()-p.getx())*(z.gety()-p.gety()); } // Return all intersection times of path g with the (infinite) // line through p and q; if there are an infinite number of intersection points, // the returned list is guaranteed to include the endpoint times of // the intersection if endpoints=true. void lineintersections(std::vector& T, const path& g, const pair& p, const pair& q, double fuzz, bool endpoints=false) { Int n=g.length(); if(n == 0) { if(online(p,q,g.point((Int) 0),fuzz)) T.push_back(0.0); return; } bool cycles=g.cyclic(); double dx=q.getx()-p.getx(); double dy=q.gety()-p.gety(); double det=p.gety()*q.getx()-p.getx()*q.gety(); for(Int i=0; i < n; ++i) { pair z0=g.point(i); pair c0=g.postcontrol(i); pair c1=g.precontrol(i+1); pair z1=g.point(i+1); pair t3=z1-z0+3.0*(c0-c1); pair t2=3.0*(z0+c1)-6.0*c0; pair t1=3.0*(c0-z0); double a=dy*t3.getx()-dx*t3.gety(); double b=dy*t2.getx()-dx*t2.gety(); double c=dy*t1.getx()-dx*t1.gety(); double d=dy*z0.getx()-dx*z0.gety()+det; std::vector r; if(max(max(max(a*a,b*b),c*c),d*d) > Fuzz2*max(max(max(z0.abs2(),z1.abs2()),c0.abs2()),c1.abs2())) roots(r,a,b,c,d); else r.push_back(0.0); if(endpoints) { path h=g.subpath(i,i+1); intersections(r,h,p,fuzz); intersections(r,h,q,fuzz); if(online(p,q,z0,fuzz)) r.push_back(0.0); if(online(p,q,z1,fuzz)) r.push_back(1.0); } size_t m=r.size(); for(size_t j=0 ; j < m; ++j) { double t=r[j]; if(t >= -Fuzz && t <= 1.0+Fuzz) { double s=i+t; if(cycles && s >= n-Fuzz) s=0; T.push_back(s); } } } } // An optimized implementation of intersections(g,p--q); // if there are an infinite number of intersection points, the returned list is // only guaranteed to include the endpoint times of the intersection. void intersections(std::vector& S, std::vector& T, const path& g, const pair& p, const pair& q, double fuzz) { double length2=(q-p).abs2(); if(length2 == 0.0) { std::vector S1; intersections(S1,g,p,fuzz); size_t n=S1.size(); for(size_t i=0; i < n; ++i) { S.push_back(S1[i]); T.push_back(0.0); } } else { pair factor=(q-p)/length2; std::vector S1; lineintersections(S1,g,p,q,fuzz,true); size_t n=S1.size(); for(size_t i=0; i < n; ++i) { double s=S1[i]; double t=dot(g.point(s)-p,factor); if(t >= -Fuzz && t <= 1.0+Fuzz) { S.push_back(s); T.push_back(t); } } } } void add(std::vector& S, double s, const path& p, double fuzz2) { pair z=p.point(s); size_t n=S.size(); for(size_t i=0; i < n; ++i) if((p.point(S[i])-z).abs2() <= fuzz2) return; S.push_back(s); } void add(std::vector& S, std::vector& T, double s, double t, const path& p, double fuzz2) { pair z=p.point(s); size_t n=S.size(); for(size_t i=0; i < n; ++i) if((p.point(S[i])-z).abs2() <= fuzz2) return; S.push_back(s); T.push_back(t); } void add(double& s, double& t, std::vector& S, std::vector& T, std::vector& S1, std::vector& T1, double pscale, double qscale, double poffset, double qoffset, const path& p, double fuzz2, bool single) { if(single) { s=s*pscale+poffset; t=t*qscale+qoffset; } else { size_t n=S1.size(); for(size_t i=0; i < n; ++i) add(S,T,pscale*S1[i]+poffset,qscale*T1[i]+qoffset,p,fuzz2); } } void add(double& s, double& t, std::vector& S, std::vector& T, std::vector& S1, std::vector& T1, const path& p, double fuzz2, bool single) { size_t n=S1.size(); if(single) { if(n > 0) { s=S1[0]; t=T1[0]; } } else { for(size_t i=0; i < n; ++i) add(S,T,S1[i],T1[i],p,fuzz2); } } void intersections(std::vector& S, path& g, const pair& p, const pair& q, double fuzz) { double fuzz2=max(fuzzFactor*fuzz,Fuzz); fuzz2=fuzz2*fuzz2; std::vector S1; lineintersections(S1,g,p,q,fuzz); size_t n=S1.size(); for(size_t i=0; i < n; ++i) add(S,S1[i],g,fuzz2); } bool intersections(double &s, double &t, std::vector& S, std::vector& T, path& p, path& q, double fuzz, bool single, bool exact, unsigned depth) { if(errorstream::interrupt) throw interrupted(); double fuzz2=max(fuzzFactor*fuzz,Fuzz); fuzz2=fuzz2*fuzz2; Int lp=p.length(); if(((lp == 1 && p.straight(0)) || lp == 0) && exact) { std::vector T1,S1; intersections(T1,S1,q,p.point((Int) 0),p.point(lp),fuzz); add(s,t,S,T,S1,T1,p,fuzz2,single); return S1.size() > 0; } Int lq=q.length(); if(((lq == 1 && q.straight(0)) || lq == 0) && exact) { std::vector S1,T1; intersections(S1,T1,p,q.point((Int) 0),q.point(lq),fuzz); add(s,t,S,T,S1,T1,p,fuzz2,single); return S1.size() > 0; } pair maxp=p.max(); pair minp=p.min(); pair maxq=q.max(); pair minq=q.min(); if(maxp.getx()+fuzz >= minq.getx() && maxp.gety()+fuzz >= minq.gety() && maxq.getx()+fuzz >= minp.getx() && maxq.gety()+fuzz >= minp.gety()) { // Overlapping bounding boxes --depth; if((maxp-minp).length()+(maxq-minq).length() <= fuzz || depth == 0) { if(single) { s=0.5; t=0.5; } else { S.push_back(0.5); T.push_back(0.5); } return true; } path p1,p2; double pscale,poffset; std::vector S1,T1; if(lp <= 1) { if(lp == 1) p.halve(p1,p2); if(lp == 0 || p1 == p || p2 == p) { intersections(T1,S1,q,p.point((Int) 0),p.point((Int) 0),fuzz); add(s,t,S,T,S1,T1,p,fuzz2,single); return S1.size() > 0; } pscale=poffset=0.5; } else { Int tp=lp/2; p1=p.subpath(0,tp); p2=p.subpath(tp,lp); poffset=tp; pscale=1.0; } path q1,q2; double qscale,qoffset; if(lq <= 1) { if(lq == 1) q.halve(q1,q2); if(lq == 0 || q1 == q || q2 == q) { intersections(S1,T1,p,q.point((Int) 0),q.point((Int) 0),fuzz); add(s,t,S,T,S1,T1,p,fuzz2,single); return S1.size() > 0; } qscale=qoffset=0.5; } else { Int tq=lq/2; q1=q.subpath(0,tq); q2=q.subpath(tq,lq); qoffset=tq; qscale=1.0; } bool Short=lp == 1 && lq == 1; static size_t maxcount=9; size_t count=0; if(intersections(s,t,S1,T1,p1,q1,fuzz,single,exact,depth)) { add(s,t,S,T,S1,T1,pscale,qscale,0.0,0.0,p,fuzz2,single); if(single || depth <= mindepth) return true; count += S1.size(); if(Short && count > maxcount) return true; } S1.clear(); T1.clear(); if(intersections(s,t,S1,T1,p1,q2,fuzz,single,exact,depth)) { add(s,t,S,T,S1,T1,pscale,qscale,0.0,qoffset,p,fuzz2,single); if(single || depth <= mindepth) return true; count += S1.size(); if(Short && count > maxcount) return true; } S1.clear(); T1.clear(); if(intersections(s,t,S1,T1,p2,q1,fuzz,single,exact,depth)) { add(s,t,S,T,S1,T1,pscale,qscale,poffset,0.0,p,fuzz2,single); if(single || depth <= mindepth) return true; count += S1.size(); if(Short && count > maxcount) return true; } S1.clear(); T1.clear(); if(intersections(s,t,S1,T1,p2,q2,fuzz,single,exact,depth)) { add(s,t,S,T,S1,T1,pscale,qscale,poffset,qoffset,p,fuzz2,single); if(single || depth <= mindepth) return true; count += S1.size(); if(Short && count > maxcount) return true; } return S.size() > 0; } return false; } // }}} ostream& operator<< (ostream& out, const path& p) { Int n = p.length(); if(n < 0) out << ""; else { for(Int i = 0; i < n; i++) { out << p.point(i); if(p.straight(i)) out << "--"; else out << ".. controls " << p.postcontrol(i) << " and " << p.precontrol(i+1) << newl << " .."; } if(p.cycles) out << "cycle"; else out << p.point(n); } return out; } path concat(const path& p1, const path& p2) { Int n1 = p1.length(), n2 = p2.length(); if (n1 == -1) return p2; if (n2 == -1) return p1; mem::vector nodes(n1+n2+1); Int i = 0; nodes[0].pre = p1.point((Int) 0); for (Int j = 0; j < n1; j++) { nodes[i].point = p1.point(j); nodes[i].straight = p1.straight(j); nodes[i].post = p1.postcontrol(j); nodes[i+1].pre = p1.precontrol(j+1); i++; } for (Int j = 0; j < n2; j++) { nodes[i].point = p2.point(j); nodes[i].straight = p2.straight(j); nodes[i].post = p2.postcontrol(j); nodes[i+1].pre = p2.precontrol(j+1); i++; } nodes[i].point = nodes[i].post = p2.point(n2); return path(nodes, i+1); } // Interface to orient2d predicate optimized for pairs. double orient2d(const pair& a, const pair& b, const pair& c) { double detleft, detright, det; double detsum, errbound; double orient; FPU_ROUND_DOUBLE; detleft = (a.getx() - c.getx()) * (b.gety() - c.gety()); detright = (a.gety() - c.gety()) * (b.getx() - c.getx()); det = detleft - detright; if (detleft > 0.0) { if (detright <= 0.0) { FPU_RESTORE; return det; } else { detsum = detleft + detright; } } else if (detleft < 0.0) { if (detright >= 0.0) { FPU_RESTORE; return det; } else { detsum = -detleft - detright; } } else { FPU_RESTORE; return det; } errbound = ccwerrboundA * detsum; if ((det >= errbound) || (-det >= errbound)) { FPU_RESTORE; return det; } double pa[]={a.getx(),a.gety()}; double pb[]={b.getx(),b.gety()}; double pc[]={c.getx(),c.gety()}; orient = orient2dadapt(pa, pb, pc, detsum); FPU_RESTORE; return orient; } // Returns true iff the point z lies in or on the bounding box // of a,b,c, and d. bool insidebbox(const pair& a, const pair& b, const pair& c, const pair& d, const pair& z) { bbox B(a); B.addnonempty(b); B.addnonempty(c); B.addnonempty(d); return B.left <= z.getx() && z.getx() <= B.right && B.bottom <= z.gety() && z.gety() <= B.top; } inline bool inrange(double x0, double x1, double x) { return (x0 <= x && x <= x1) || (x1 <= x && x <= x0); } // Return true if point z is on z0--z1; otherwise compute contribution to // winding number. bool checkstraight(const pair& z0, const pair& z1, const pair& z, Int& count) { if(z0.gety() <= z.gety() && z.gety() <= z1.gety()) { double side=orient2d(z0,z1,z); if(side == 0.0 && inrange(z0.getx(),z1.getx(),z.getx())) return true; if(z.gety() < z1.gety() && side > 0) ++count; } else if(z1.gety() <= z.gety() && z.gety() <= z0.gety()) { double side=orient2d(z0,z1,z); if(side == 0.0 && inrange(z0.getx(),z1.getx(),z.getx())) return true; if(z.gety() < z0.gety() && side < 0) --count; } return false; } // returns true if point is on curve; otherwise compute contribution to // winding number. bool checkcurve(const pair& z0, const pair& c0, const pair& c1, const pair& z1, const pair& z, Int& count, unsigned depth) { if(depth == 0) return true; --depth; if(insidebbox(z0,c0,c1,z1,z)) { const pair m0=0.5*(z0+c0); const pair m1=0.5*(c0+c1); const pair m2=0.5*(c1+z1); const pair m3=0.5*(m0+m1); const pair m4=0.5*(m1+m2); const pair m5=0.5*(m3+m4); if(checkcurve(z0,m0,m3,m5,z,count,depth) || checkcurve(m5,m4,m2,z1,z,count,depth)) return true; } else if(checkstraight(z0,z1,z,count)) return true; return false; } // Return the winding number of the region bounded by the (cyclic) path // relative to the point z, or the largest odd integer if the point lies on // the path. Int path::windingnumber(const pair& z) const { static const Int undefined=Int_MAX % 2 ? Int_MAX : Int_MAX-1; if(!cycles) reportError("path is not cyclic"); bbox b=bounds(); if(z.getx() < b.left || z.getx() > b.right || z.gety() < b.bottom || z.gety() > b.top) return 0; Int count=0; for(Int i=0; i < n; ++i) if(straight(i)) { if(checkstraight(point(i),point(i+1),z,count)) return undefined; } else if(checkcurve(point(i),postcontrol(i),precontrol(i+1),point(i+1),z,count, maxdepth)) return undefined; return count; } path path::transformed(const transform& t) const { mem::vector nodes(n); for (Int i = 0; i < n; ++i) { nodes[i].pre = t * this->nodes[i].pre; nodes[i].point = t * this->nodes[i].point; nodes[i].post = t * this->nodes[i].post; nodes[i].straight = this->nodes[i].straight; } path p(nodes, n, cyclic()); return p; } path transformed(const transform& t, const path& p) { Int n = p.size(); mem::vector nodes(n); for (Int i = 0; i < n; ++i) { nodes[i].pre = t * p.precontrol(i); nodes[i].point = t * p.point(i); nodes[i].post = t * p.postcontrol(i); nodes[i].straight = p.straight(i); } return path(nodes, n, p.cyclic()); } path nurb(pair z0, pair z1, pair z2, pair z3, double w0, double w1, double w2, double w3, Int m) { mem::vector nodes(m+1); if(m < 1) reportError("invalid sampling interval"); double step=1.0/m; for(Int i=0; i <= m; ++i) { double t=i*step; double t2=t*t; double onemt=1.0-t; double onemt2=onemt*onemt; double W0=w0*onemt2*onemt; double W1=w1*3.0*t*onemt2; double W2=w2*3.0*t2*onemt; double W3=w3*t2*t; nodes[i].point=(W0*z0+W1*z1+W2*z2+W3*z3)/(W0+W1+W2+W3); } static const double twothirds=2.0/3.0; pair z=nodes[0].point; nodes[0].pre=z; nodes[0].post=twothirds*z+third*nodes[1].point; for(int i=1; i < m; ++i) { pair z0=nodes[i].point; pair zm=nodes[i-1].point; pair zp=nodes[i+1].point; pair pre=twothirds*z0+third*zm; pair pos=twothirds*z0+third*zp; pair dir=unit(pos-pre); nodes[i].pre=z0-length(z0-pre)*dir; nodes[i].post=z0+length(pos-z0)*dir; } z=nodes[m].point; nodes[m].pre=twothirds*z+third*nodes[m-1].point; nodes[m].post=z; return path(nodes,m+1); } } //namespace camp asymptote-2.37/path.h000066400000000000000000000264411265434602500146150ustar00rootroot00000000000000/***** * path.h * Andy Hammerlindl 2002/05/16 * * Stores a piecewise cubic spline with known control points. * * When changing the path algorithms, also update the corresponding * three-dimensional algorithms in path3.cc and three.asy. *****/ #ifndef PATH_H #define PATH_H #include #include "mod.h" #include "pair.h" #include "transform.h" #include "bbox.h" inline double Intcap(double t) { if(t <= Int_MIN) return Int_MIN; if(t >= Int_MAX) return Int_MAX; return t; } // The are like floor and ceil, except they return an integer; // if the argument cannot be converted to a valid integer, they return // Int_MAX (for positive arguments) or Int_MIN (for negative arguments). inline Int Floor(double t) {return (Int) floor(Intcap(t));} inline Int Ceil(double t) {return (Int) ceil(Intcap(t));} bool simpson(double& integral, double (*)(double), double a, double b, double acc, double dxmax); bool unsimpson(double integral, double (*)(double), double a, double& b, double acc, double& area, double dxmax, double dxmin=0); namespace camp { void checkEmpty(Int n); inline Int adjustedIndex(Int i, Int n, bool cycles) { checkEmpty(n); if(cycles) return imod(i,n); else if(i < 0) return 0; else if(i >= n) return n-1; else return i; } // Used in the storage of solved path knots. struct solvedKnot : public gc { pair pre; pair point; pair post; bool straight; solvedKnot() : straight(false) {} friend bool operator== (const solvedKnot& p, const solvedKnot& q) { return p.pre == q.pre && p.point == q.point && p.post == q.post; } }; extern const double Fuzz; extern const double BigFuzz; extern const double Fuzz2; extern const double sqrtFuzz; extern const double fuzzFactor; class path : public gc { bool cycles; // If the path is closed in a loop Int n; // The number of knots mem::vector nodes; mutable double cached_length; // Cache length since path is immutable. mutable bbox box; mutable bbox times; // Times where minimum and maximum extents are attained. public: path() : cycles(false), n(0), nodes(), cached_length(-1) {} // Create a path of a single point path(pair z, bool = false) : cycles(false), n(1), nodes(1), cached_length(-1) { nodes[0].pre = nodes[0].point = nodes[0].post = z; nodes[0].straight = false; } // Creates path from a list of knots. This will be used by camp // methods such as the guide solver, but should probably not be used by a // user of the system unless he knows what he is doing. path(mem::vector& nodes, Int n, bool cycles = false) : cycles(cycles), n(n), nodes(nodes), cached_length(-1) { } friend bool operator== (const path& p, const path& q) { return p.cycles == q.cycles && p.nodes == q.nodes; } public: path(solvedKnot n1, solvedKnot n2) : cycles(false), n(2), nodes(2), cached_length(-1) { nodes[0] = n1; nodes[1] = n2; nodes[0].pre = nodes[0].point; nodes[1].post = nodes[1].point; } // Copy constructor path(const path& p) : cycles(p.cycles), n(p.n), nodes(p.nodes), cached_length(p.cached_length), box(p.box) {} path unstraighten() const { path P=path(*this); for(int i=0; i < n; ++i) P.nodes[i].straight=false; return P; } virtual ~path() { } // Getting control points Int size() const { return n; } bool empty() const { return n == 0; } Int length() const { return cycles ? n : n-1; } bool cyclic() const { return cycles; } mem::vector& Nodes() { return nodes; } bool straight(Int t) const { if (cycles) return nodes[imod(t,n)].straight; return (t >= 0 && t < n) ? nodes[t].straight : false; } bool piecewisestraight() const { Int L=length(); for(Int i=0; i < L; ++i) if(!straight(i)) return false; return true; } pair point(Int t) const { return nodes[adjustedIndex(t,n,cycles)].point; } pair point(double t) const; pair precontrol(Int t) const { return nodes[adjustedIndex(t,n,cycles)].pre; } pair precontrol(double t) const; pair postcontrol(Int t) const { return nodes[adjustedIndex(t,n,cycles)].post; } pair postcontrol(double t) const; inline double norm(const pair& z0, const pair& c0, const pair& c1, const pair& z1) const { return Fuzz2*camp::max((c0-z0).abs2(), camp::max((c1-z0).abs2(),(z1-z0).abs2())); } pair predir(Int t, bool normalize=true) const { if(!cycles && t <= 0) return pair(0,0); pair z1=point(t); pair c1=precontrol(t); pair dir=3.0*(z1-c1); if(!normalize) return dir; pair z0=point(t-1); pair c0=postcontrol(t-1); double epsilon=norm(z0,c0,c1,z1); if(dir.abs2() > epsilon) return unit(dir); dir=2.0*c1-c0-z1; if(dir.abs2() > epsilon) return unit(dir); return unit(z1-z0+3.0*(c0-c1)); } pair postdir(Int t, bool normalize=true) const { if(!cycles && t >= n-1) return pair(0,0); pair c0=postcontrol(t); pair z0=point(t); pair dir=3.0*(c0-z0); if(!normalize) return dir; pair z1=point(t+1); pair c1=precontrol(t+1); double epsilon=norm(z0,c0,c1,z1); if(dir.abs2() > epsilon) return unit(dir); dir=z0-2.0*c0+c1; if(dir.abs2() > epsilon) return unit(dir); return unit(z1-z0+3.0*(c0-c1)); } pair dir(Int t, Int sign, bool normalize=true) const { if(sign == 0) { pair v=predir(t,normalize)+postdir(t,normalize); return normalize ? unit(v) : 0.5*v; } if(sign > 0) return postdir(t,normalize); return predir(t,normalize); } pair dir(double t, bool normalize=true) const { if(!cycles) { if(t <= 0) return postdir((Int) 0,normalize); if(t >= n-1) return predir(n-1,normalize); } Int i=Floor(t); t -= i; if(t == 0) return dir(i,0,normalize); pair z0=point(i); pair c0=postcontrol(i); pair c1=precontrol(i+1); pair z1=point(i+1); pair a=3.0*(z1-z0)+9.0*(c0-c1); pair b=6.0*(z0+c1)-12.0*c0; pair c=3.0*(c0-z0); pair dir=a*t*t+b*t+c; if(!normalize) return dir; double epsilon=norm(z0,c0,c1,z1); if(dir.abs2() > epsilon) return unit(dir); dir=2.0*a*t+b; if(dir.abs2() > epsilon) return unit(dir); return unit(a); } pair postaccel(Int t) const { if(!cycles && t >= n-1) return pair(0,0); pair z0=point(t); pair c0=postcontrol(t); pair c1=precontrol(t+1); return 6.0*(z0+c1)-12.0*c0; } pair preaccel(Int t) const { if(!cycles && t <= 0) return pair(0,0); pair c0=postcontrol(t-1); pair c1=precontrol(t); pair z1=point(t); return 6.0*(z1+c0)-12.0*c1; } pair accel(Int t, Int sign) const { if(sign == 0) return 0.5*(preaccel(t)+postaccel(t)); if(sign > 0) return postaccel(t); return preaccel(t); } pair accel(double t) const { if(!cycles) { if(t <= 0) return postaccel((Int) 0); if(t >= n-1) return preaccel(n-1); } Int i=Floor(t); t -= i; if(t == 0) return 0.5*(postaccel(i)+preaccel(i)); pair z0=point(i); pair c0=postcontrol(i); pair c1=precontrol(i+1); pair z1=point(i+1); return 6.0*t*(z1-z0+3.0*(c0-c1))+6.0*(z0+c1)-12.0*c0; } // Returns the path traced out in reverse. path reverse() const; // Generates a path that is a section of the old path, using the time // interval given. path subpath(Int start, Int end) const; path subpath(double start, double end) const; // Special case of subpath used by intersect. void halve(path &first, path &second) const; // Used by picture to determine bounding box. bbox bounds() const; pair mintimes() const { checkEmpty(n); bounds(); return camp::pair(times.left,times.bottom); } pair maxtimes() const { checkEmpty(n); bounds(); return camp::pair(times.right,times.top); } template void addpoint(bbox& box, T i) const { box.addnonempty(point(i),times,(double) i); } template void addpoint(bbox& box, T i, double min, double max) const { static const pair I(0,1); pair v=I*dir(i); pair z=point(i); box.add(z+min*v); box.addnonempty(z+max*v); } // Return bounding box accounting for padding perpendicular to path. bbox bounds(double min, double max) const; // Return bounding box accounting for internal pen padding (but not pencap). bbox internalbounds(const bbox &padding) const; double cubiclength(Int i, double goal=-1) const; double arclength () const; double arctime (double l) const; double directiontime(const pair& z) const; pair max() const { checkEmpty(n); return bounds().Max(); } pair min() const { checkEmpty(n); return bounds().Min(); } // Debugging output friend std::ostream& operator<< (std::ostream& out, const path& p); // Increment count if the path has a vertical component at t. bool Count(Int& count, double t) const; // Count if t is in (begin,end] and z lies to the left of point(i+t). void countleft(Int& count, double x, Int i, double t, double begin, double end, double& mint, double& maxt) const; // Return the winding number of the region bounded by the (cyclic) path // relative to the point z. Int windingnumber(const pair& z) const; // Transformation path transformed(const transform& t) const; }; extern path nullpath; extern const unsigned maxdepth; extern const unsigned mindepth; extern const char *nopoints; bool intersect(double& S, double& T, path& p, path& q, double fuzz, unsigned depth=maxdepth); bool intersections(double& s, double& t, std::vector& S, std::vector& T, path& p, path& q, double fuzz, bool single, bool exact, unsigned depth=maxdepth); void intersections(std::vector& S, path& g, const pair& p, const pair& q, double fuzz); // Concatenates two paths into a new one. path concat(const path& p1, const path& p2); // Applies a transformation to the path path transformed(const transform& t, const path& p); inline double quadratic(double a, double b, double c, double x) { return a*x*x+b*x+c; } class quadraticroots { public: enum {NONE=0, ONE=1, TWO=2, MANY} distinct; // Number of distinct real roots. unsigned roots; // Total number of real roots. double t1,t2; // Real roots quadraticroots(double a, double b, double c); }; class Quadraticroots { public: unsigned roots; // Total number of roots. pair z1,z2; // Complex roots Quadraticroots(pair a, pair b, pair c); }; class cubicroots { public: unsigned roots; // Total number of real roots. double t1,t2,t3; cubicroots(double a, double b, double c, double d); }; path nurb(pair z0, pair z1, pair z2, pair z3, double w0, double w1, double w2, double w3, Int m); double orient2d(const pair& a, const pair& b, const pair& c); void roots(std::vector &roots, double a, double b, double c, double d); void roots(std::vector &r, double x0, double c0, double c1, double x1, double x); inline bool goodroot(double t) { return 0.0 <= t && t <= 1.0; } extern const double third; } #ifndef BROKEN_COMPILER // Delete the following line to work around problems with old broken compilers. GC_DECLARE_PTRFREE(camp::solvedKnot); #endif #endif asymptote-2.37/path3.cc000066400000000000000000001120441265434602500150310ustar00rootroot00000000000000/***** * path3.cc * John Bowman * * Compute information for a three-dimensional path. *****/ #include #include "path3.h" #include "util.h" #include "camperror.h" #include "mathop.h" namespace camp { using run::operator *; using vm::array; path3 nullpath3; void checkEmpty3(Int n) { if(n == 0) reportError("nullpath3 has no points"); } triple path3::point(double t) const { checkEmpty3(n); Int i = Floor(t); Int iplus; t = fmod(t,1); if (t < 0) t += 1; if (cycles) { i = imod(i,n); iplus = imod(i+1,n); } else if (i < 0) return nodes[0].point; else if (i >= n-1) return nodes[n-1].point; else iplus = i+1; double one_t = 1.0-t; triple a = nodes[i].point, b = nodes[i].post, c = nodes[iplus].pre, d = nodes[iplus].point, ab = one_t*a + t*b, bc = one_t*b + t*c, cd = one_t*c + t*d, abc = one_t*ab + t*bc, bcd = one_t*bc + t*cd, abcd = one_t*abc + t*bcd; return abcd; } triple path3::precontrol(double t) const { checkEmpty3(n); Int i = Floor(t); Int iplus; t = fmod(t,1); if (t < 0) t += 1; if (cycles) { i = imod(i,n); iplus = imod(i+1,n); } else if (i < 0) return nodes[0].pre; else if (i >= n-1) return nodes[n-1].pre; else iplus = i+1; double one_t = 1.0-t; triple a = nodes[i].point, b = nodes[i].post, c = nodes[iplus].pre, ab = one_t*a + t*b, bc = one_t*b + t*c, abc = one_t*ab + t*bc; return (abc == a) ? nodes[i].pre : abc; } triple path3::postcontrol(double t) const { checkEmpty3(n); Int i = Floor(t); Int iplus; t = fmod(t,1); if (t < 0) t += 1; if (cycles) { i = imod(i,n); iplus = imod(i+1,n); } else if (i < 0) return nodes[0].post; else if (i >= n-1) return nodes[n-1].post; else iplus = i+1; double one_t = 1.0-t; triple b = nodes[i].post, c = nodes[iplus].pre, d = nodes[iplus].point, bc = one_t*b + t*c, cd = one_t*c + t*d, bcd = one_t*bc + t*cd; return (bcd == d) ? nodes[iplus].post : bcd; } path3 path3::reverse() const { mem::vector nodes(n); Int len=length(); for (Int i = 0, j = len; i < n; i++, j--) { nodes[i].pre = postcontrol(j); nodes[i].point = point(j); nodes[i].post = precontrol(j); nodes[i].straight = straight(j-1); } return path3(nodes, n, cycles); } path3 path3::subpath(Int a, Int b) const { if(empty()) return path3(); if (a > b) { const path3 &rp = reverse(); Int len=length(); path3 result = rp.subpath(len-a, len-b); return result; } if (!cycles) { if (a < 0) a = 0; if (b > n-1) b = n-1; } Int sn = b-a+1; mem::vector nodes(sn); for (Int i = 0, j = a; j <= b; i++, j++) { nodes[i].pre = precontrol(j); nodes[i].point = point(j); nodes[i].post = postcontrol(j); nodes[i].straight = straight(j); } nodes[0].pre = nodes[0].point; nodes[sn-1].post = nodes[sn-1].point; return path3(nodes, sn); } inline triple split(double t, const triple& x, const triple& y) { return x+(y-x)*t; } inline void splitCubic(solvedKnot3 sn[], double t, const solvedKnot3& left_, const solvedKnot3& right_) { solvedKnot3 &left=(sn[0]=left_), &mid=sn[1], &right=(sn[2]=right_); if(left.straight) { mid.point=split(t,left.point,right.point); triple deltaL=third*(mid.point-left.point); left.post=left.point+deltaL; mid.pre=mid.point-deltaL; triple deltaR=third*(right.point-mid.point); mid.post=mid.point+deltaR; right.pre=right.point-deltaR; mid.straight=true; } else { triple x=split(t,left.post,right.pre); // m1 left.post=split(t,left.point,left.post); // m0 right.pre=split(t,right.pre,right.point); // m2 mid.pre=split(t,left.post,x); // m3 mid.post=split(t,x,right.pre); // m4 mid.point=split(t,mid.pre,mid.post); // m5 } } path3 path3::subpath(double a, double b) const { if(empty()) return path3(); if (a > b) { const path3 &rp = reverse(); Int len=length(); return rp.subpath(len-a, len-b); } solvedKnot3 aL, aR, bL, bR; if (!cycles) { if (a < 0) { a = 0; if (b < 0) b = 0; } if (b > n-1) { b = n-1; if (a > n-1) a = n-1; } aL = nodes[(Int)floor(a)]; aR = nodes[(Int)ceil(a)]; bL = nodes[(Int)floor(b)]; bR = nodes[(Int)ceil(b)]; } else { if(run::validInt(a) && run::validInt(b)) { aL = nodes[imod((Int) floor(a),n)]; aR = nodes[imod((Int) ceil(a),n)]; bL = nodes[imod((Int) floor(b),n)]; bR = nodes[imod((Int) ceil(b),n)]; } else reportError("invalid path3 index"); } if (a == b) return path3(point(a)); solvedKnot3 sn[3]; path3 p = subpath(Ceil(a), Floor(b)); if (a > floor(a)) { if (b < ceil(a)) { splitCubic(sn,a-floor(a),aL,aR); splitCubic(sn,(b-a)/(ceil(b)-a),sn[1],sn[2]); return path3(sn[0],sn[1]); } splitCubic(sn,a-floor(a),aL,aR); p=concat(path3(sn[1],sn[2]),p); } if (ceil(b) > b) { splitCubic(sn,b-floor(b),bL,bR); p=concat(p,path3(sn[0],sn[1])); } return p; } // Special case of subpath for paths of length 1 used by intersect. void path3::halve(path3 &first, path3 &second) const { solvedKnot3 sn[3]; splitCubic(sn,0.5,nodes[0],nodes[1]); first=path3(sn[0],sn[1]); second=path3(sn[1],sn[2]); } // Calculate the coefficients of a Bezier derivative divided by 3. static inline void derivative(triple& a, triple& b, triple& c, const triple& z0, const triple& c0, const triple& c1, const triple& z1) { a=z1-z0+3.0*(c0-c1); b=2.0*(z0+c1)-4.0*c0; c=c0-z0; } bbox3 path3::bounds() const { if(!box.empty) return box; if (empty()) { // No bounds return bbox3(); } Int len=length(); box.add(point(len)); times=bbox3(len,len,len,len,len,len); for (Int i = 0; i < len; i++) { addpoint(box,i); if(straight(i)) continue; triple a,b,c; derivative(a,b,c,point(i),postcontrol(i),precontrol(i+1),point(i+1)); // Check x coordinate quadraticroots x(a.getx(),b.getx(),c.getx()); if(x.distinct != quadraticroots::NONE && goodroot(x.t1)) addpoint(box,i+x.t1); if(x.distinct == quadraticroots::TWO && goodroot(x.t2)) addpoint(box,i+x.t2); // Check y coordinate quadraticroots y(a.gety(),b.gety(),c.gety()); if(y.distinct != quadraticroots::NONE && goodroot(y.t1)) addpoint(box,i+y.t1); if(y.distinct == quadraticroots::TWO && goodroot(y.t2)) addpoint(box,i+y.t2); // Check z coordinate quadraticroots z(a.getz(),b.getz(),c.getz()); if(z.distinct != quadraticroots::NONE && goodroot(z.t1)) addpoint(box,i+z.t1); if(z.distinct == quadraticroots::TWO && goodroot(z.t2)) addpoint(box,i+z.t2); } return box; } // Return f evaluated at controlling vertex of bounding box of convex hull for // similiar-triangle transform x'=x/z, y'=y/z, where z < 0. double ratiobound(triple z0, triple c0, triple c1, triple z1, double (*m)(double, double), double (*f)(const triple&)) { double MX=m(m(m(-z0.getx(),-c0.getx()),-c1.getx()),-z1.getx()); double MY=m(m(m(-z0.gety(),-c0.gety()),-c1.gety()),-z1.gety()); double Z=m(m(m(z0.getz(),c0.getz()),c1.getz()),z1.getz()); double MZ=m(m(m(-z0.getz(),-c0.getz()),-c1.getz()),-z1.getz()); return m(f(triple(-MX,-MY,Z)),f(triple(-MX,-MY,-MZ))); } double bound(triple z0, triple c0, triple c1, triple z1, double (*m)(double, double), double (*f)(const triple&), double b, double fuzz, int depth) { b=m(b,m(f(z0),f(z1))); if(m(-1.0,1.0)*(b-ratiobound(z0,c0,c1,z1,m,f)) >= -fuzz || depth == 0) return b; --depth; triple m0=0.5*(z0+c0); triple m1=0.5*(c0+c1); triple m2=0.5*(c1+z1); triple m3=0.5*(m0+m1); triple m4=0.5*(m1+m2); triple m5=0.5*(m3+m4); // Check both Bezier subpaths. b=bound(z0,m0,m3,m5,m,f,b,fuzz,depth); return bound(m5,m4,m2,z1,m,f,b,fuzz,depth); } pair path3::ratio(double (*m)(double, double)) const { double fuzz=sqrtFuzz*(max()-min()).length(); checkEmpty3(n); triple v=point((Int) 0); pair B=pair(xratio(v),yratio(v)); Int n=length(); for(Int i=0; i <= n; ++i) { if(straight(i)) { triple v=point(i); B=pair(m(B.getx(),xratio(v)),m(B.gety(),yratio(v))); } else { triple z0=point(i); triple c0=postcontrol(i); triple c1=precontrol(i+1); triple z1=point(i+1); B=pair(bound(z0,c0,c1,z1,m,xratio,B.getx(),fuzz), bound(z0,c0,c1,z1,m,yratio,B.gety(),fuzz)); } } return B; } // {{{ Arclength Calculations static triple a,b,c; static double ds(double t) { double dx=quadratic(a.getx(),b.getx(),c.getx(),t); double dy=quadratic(a.gety(),b.gety(),c.gety(),t); double dz=quadratic(a.getz(),b.getz(),c.getz(),t); return sqrt(dx*dx+dy*dy+dz*dz); } // Calculates arclength of a cubic using adaptive simpson integration. double path3::cubiclength(Int i, double goal) const { const triple& z0=point(i); const triple& z1=point(i+1); double L; if(straight(i)) { L=(z1-z0).length(); return (goal < 0 || goal >= L) ? L : -goal/L; } const triple& c0=postcontrol(i); const triple& c1=precontrol(i+1); double integral; derivative(a,b,c,z0,c0,c1,z1); if(!simpson(integral,ds,0.0,1.0,DBL_EPSILON,1.0)) reportError("nesting capacity exceeded in computing arclength"); L=3.0*integral; if(goal < 0 || goal >= L) return L; double t=goal/L; goal *= third; static double dxmin=sqrt(DBL_EPSILON); if(!unsimpson(goal,ds,0.0,t,100.0*DBL_EPSILON,integral,1.0,dxmin)) reportError("nesting capacity exceeded in computing arctime"); return -t; } double path3::arclength() const { if (cached_length != -1) return cached_length; double L=0.0; for (Int i = 0; i < n-1; i++) { L += cubiclength(i); } if(cycles) L += cubiclength(n-1); cached_length = L; return cached_length; } double path3::arctime(double goal) const { if (cycles) { if (goal == 0 || cached_length == 0) return 0; if (goal < 0) { const path3 &rp = this->reverse(); double result = -rp.arctime(-goal); return result; } if (cached_length > 0 && goal >= cached_length) { Int loops = (Int)(goal / cached_length); goal -= loops*cached_length; return loops*n+arctime(goal); } } else { if (goal <= 0) return 0; if (cached_length > 0 && goal >= cached_length) return n-1; } double l,L=0; for (Int i = 0; i < n-1; i++) { l = cubiclength(i,goal); if (l < 0) return (-l+i); else { L += l; goal -= l; if (goal <= 0) return i+1; } } if (cycles) { l = cubiclength(n-1,goal); if (l < 0) return -l+n-1; if (cached_length > 0 && cached_length != L+l) { reportError("arclength != length.\n" "path3::arclength(double) must have broken semantics.\n" "Please report this error."); } cached_length = L += l; goal -= l; return arctime(goal)+n; } else { cached_length = L; return length(); } } // }}} // {{{ Path3 Intersection Calculations // Return all intersection times of path3 g with the triple v. void intersections(std::vector& T, const path3& g, const triple& v, double fuzz) { double fuzz2=fuzz*fuzz; Int n=g.length(); bool cycles=g.cyclic(); for(Int i=0; i < n; ++i) { // Check all directions to circumvent degeneracy. std::vector r; roots(r,g.point(i).getx(),g.postcontrol(i).getx(), g.precontrol(i+1).getx(),g.point(i+1).getx(),v.getx()); roots(r,g.point(i).gety(),g.postcontrol(i).gety(), g.precontrol(i+1).gety(),g.point(i+1).gety(),v.gety()); roots(r,g.point(i).getz(),g.postcontrol(i).getz(), g.precontrol(i+1).getz(),g.point(i+1).getz(),v.getz()); size_t m=r.size(); for(size_t j=0 ; j < m; ++j) { double t=r[j]; if(t >= -Fuzz && t <= 1.0+Fuzz) { double s=i+t; if((g.point(s)-v).abs2() <= fuzz2) { if(cycles && s >= n-Fuzz) s=0; T.push_back(s); } } } } } // An optimized implementation of intersections(g,p--q); // if there are an infinite number of intersection points, the returned list is // only guaranteed to include the endpoint times of the intersection. void intersections(std::vector& S, std::vector& T, const path3& g, const triple& p, double fuzz) { std::vector S1; intersections(S1,g,p,fuzz); size_t n=S1.size(); for(size_t i=0; i < n; ++i) { S.push_back(S1[i]); T.push_back(0.0); } } void add(std::vector& S, std::vector& T, double s, double t, const path3& p, const path3& q, double fuzz2) { triple P=p.point(s); for(size_t i=0; i < S.size(); ++i) if((p.point(S[i])-P).abs2() <= fuzz2) return; S.push_back(s); T.push_back(t); } void add(double& s, double& t, std::vector& S, std::vector& T, std::vector& S1, std::vector& T1, double pscale, double qscale, double poffset, double qoffset, const path3& p, const path3& q, double fuzz2, bool single) { if(single) { s=s*pscale+poffset; t=t*qscale+qoffset; } else { size_t n=S1.size(); for(size_t i=0; i < n; ++i) add(S,T,pscale*S1[i]+poffset,qscale*T1[i]+qoffset,p,q,fuzz2); } } void add(double& s, double& t, std::vector& S, std::vector& T, std::vector& S1, std::vector& T1, const path3& p, const path3& q, double fuzz2, bool single) { size_t n=S1.size(); if(single) { if(n > 0) { s=S1[0]; t=T1[0]; } } else { for(size_t i=0; i < n; ++i) add(S,T,S1[i],T1[i],p,q,fuzz2); } } bool intersections(double &s, double &t, std::vector& S, std::vector& T, path3& p, path3& q, double fuzz, bool single, bool exact, unsigned depth) { if(errorstream::interrupt) throw interrupted(); double fuzz2=max(fuzzFactor*fuzz,Fuzz); fuzz2=fuzz2*fuzz2; Int lp=p.length(); if(lp == 0 && exact) { std::vector T1,S1; intersections(T1,S1,q,p.point(lp),fuzz); add(s,t,S,T,S1,T1,p,q,fuzz2,single); return S1.size() > 0; } Int lq=q.length(); if(lq == 0 && exact) { std::vector S1,T1; intersections(S1,T1,p,q.point(lq),fuzz); add(s,t,S,T,S1,T1,p,q,fuzz2,single); return S1.size() > 0; } triple maxp=p.max(); triple minp=p.min(); triple maxq=q.max(); triple minq=q.min(); if(maxp.getx()+fuzz >= minq.getx() && maxp.gety()+fuzz >= minq.gety() && maxp.getz()+fuzz >= minq.getz() && maxq.getx()+fuzz >= minp.getx() && maxq.gety()+fuzz >= minp.gety() && maxq.getz()+fuzz >= minp.getz()) { // Overlapping bounding boxes --depth; if((maxp-minp).length()+(maxq-minq).length() <= fuzz || depth == 0) { if(single) { s=0.5; t=0.5; } else { S.push_back(0.5); T.push_back(0.5); } return true; } path3 p1,p2; double pscale,poffset; std::vector S1,T1; if(lp <= 1) { if(lp == 1) p.halve(p1,p2); if(lp == 0 || p1 == p || p2 == p) { intersections(T1,S1,q,p.point((Int) 0),fuzz); add(s,t,S,T,S1,T1,p,q,fuzz2,single); return S1.size() > 0; } pscale=poffset=0.5; } else { Int tp=lp/2; p1=p.subpath(0,tp); p2=p.subpath(tp,lp); poffset=tp; pscale=1.0; } path3 q1,q2; double qscale,qoffset; if(lq <= 1) { if(lq == 1) q.halve(q1,q2); if(lq == 0 || q1 == q || q2 == q) { intersections(S1,T1,p,q.point((Int) 0),fuzz); add(s,t,S,T,S1,T1,p,q,fuzz2,single); return S1.size() > 0; } qscale=qoffset=0.5; } else { Int tq=lq/2; q1=q.subpath(0,tq); q2=q.subpath(tq,lq); qoffset=tq; qscale=1.0; } bool Short=lp == 1 && lq == 1; static size_t maxcount=9; size_t count=0; if(intersections(s,t,S1,T1,p1,q1,fuzz,single,exact,depth)) { add(s,t,S,T,S1,T1,pscale,qscale,0.0,0.0,p,q,fuzz2,single); if(single || depth <= mindepth) return true; count += S1.size(); if(Short && count > maxcount) return true; } S1.clear(); T1.clear(); if(intersections(s,t,S1,T1,p1,q2,fuzz,single,exact,depth)) { add(s,t,S,T,S1,T1,pscale,qscale,0.0,qoffset,p,q,fuzz2,single); if(single || depth <= mindepth) return true; count += S1.size(); if(Short && count > maxcount) return true; } S1.clear(); T1.clear(); if(intersections(s,t,S1,T1,p2,q1,fuzz,single,exact,depth)) { add(s,t,S,T,S1,T1,pscale,qscale,poffset,0.0,p,q,fuzz2,single); if(single || depth <= mindepth) return true; count += S1.size(); if(Short && count > maxcount) return true; } S1.clear(); T1.clear(); if(intersections(s,t,S1,T1,p2,q2,fuzz,single,exact,depth)) { add(s,t,S,T,S1,T1,pscale,qscale,poffset,qoffset,p,q,fuzz2,single); if(single || depth <= mindepth) return true; count += S1.size(); if(Short && count > maxcount) return true; } return S.size() > 0; } return false; } // }}} path3 concat(const path3& p1, const path3& p2) { Int n1 = p1.length(), n2 = p2.length(); if (n1 == -1) return p2; if (n2 == -1) return p1; triple a=p1.point(n1); triple b=p2.point((Int) 0); mem::vector nodes(n1+n2+1); Int i = 0; nodes[0].pre = p1.point((Int) 0); for (Int j = 0; j < n1; j++) { nodes[i].point = p1.point(j); nodes[i].straight = p1.straight(j); nodes[i].post = p1.postcontrol(j); nodes[i+1].pre = p1.precontrol(j+1); i++; } for (Int j = 0; j < n2; j++) { nodes[i].point = p2.point(j); nodes[i].straight = p2.straight(j); nodes[i].post = p2.postcontrol(j); nodes[i+1].pre = p2.precontrol(j+1); i++; } nodes[i].point = nodes[i].post = p2.point(n2); return path3(nodes, i+1); } path3 transformed(const array& t, const path3& p) { Int n = p.size(); mem::vector nodes(n); for (Int i = 0; i < n; ++i) { nodes[i].pre = t * p.precontrol(i); nodes[i].point = t * p.point(i); nodes[i].post = t * p.postcontrol(i); nodes[i].straight = p.straight(i); } return path3(nodes, n, p.cyclic()); } path3 transformed(const double* t, const path3& p) { Int n = p.size(); mem::vector nodes(n); for(Int i=0; i < n; ++i) { nodes[i].pre=t*p.precontrol(i); nodes[i].point=t*p.point(i); nodes[i].post=t*p.postcontrol(i); nodes[i].straight=p.straight(i); } return path3(nodes, n, p.cyclic()); } template struct Split { T m0,m1,m2,m3,m4,m5; Split(T z0, T c0, T c1, T z1) { m0=0.5*(z0+c0); m1=0.5*(c0+c1); m2=0.5*(c1+z1); m3=0.5*(m0+m1); m4=0.5*(m1+m2); m5=0.5*(m3+m4); } }; double cornerbound(double *P, double (*m)(double, double)) { double b=m(P[0],P[3]); b=m(b,P[12]); return m(b,P[15]); } double controlbound(double *P, double (*m)(double, double)) { double b=m(P[1],P[2]); b=m(b,P[4]); b=m(b,P[5]); b=m(b,P[6]); b=m(b,P[7]); b=m(b,P[8]); b=m(b,P[9]); b=m(b,P[10]); b=m(b,P[11]); b=m(b,P[13]); return m(b,P[14]); } double bound(double *P, double (*m)(double, double), double b, double fuzz, int depth) { b=m(b,cornerbound(P,m)); if(m(-1.0,1.0)*(b-controlbound(P,m)) >= -fuzz || depth == 0) return b; --depth; Split c0(P[0],P[1],P[2],P[3]); Split c1(P[4],P[5],P[6],P[7]); Split c2(P[8],P[9],P[10],P[11]); Split c3(P[12],P[13],P[14],P[15]); Split c4(P[12],P[8],P[4],P[0]); Split c5(c3.m0,c2.m0,c1.m0,c0.m0); Split c6(c3.m3,c2.m3,c1.m3,c0.m3); Split c7(c3.m5,c2.m5,c1.m5,c0.m5); Split c8(c3.m4,c2.m4,c1.m4,c0.m4); Split c9(c3.m2,c2.m2,c1.m2,c0.m2); Split c10(P[15],P[11],P[7],P[3]); // Check all 4 Bezier subpatches. double s0[]={c4.m5,c5.m5,c6.m5,c7.m5,c4.m3,c5.m3,c6.m3,c7.m3, c4.m0,c5.m0,c6.m0,c7.m0,P[12],c3.m0,c3.m3,c3.m5}; b=bound(s0,m,b,fuzz,depth); double s1[]={P[0],c0.m0,c0.m3,c0.m5,c4.m2,c5.m2,c6.m2,c7.m2, c4.m4,c5.m4,c6.m4,c7.m4,c4.m5,c5.m5,c6.m5,c7.m5}; b=bound(s1,m,b,fuzz,depth); double s2[]={c0.m5,c0.m4,c0.m2,P[3],c7.m2,c8.m2,c9.m2,c10.m2, c7.m4,c8.m4,c9.m4,c10.m4,c7.m5,c8.m5,c9.m5,c10.m5}; b=bound(s2,m,b,fuzz,depth); double s3[]={c7.m5,c8.m5,c9.m5,c10.m5,c7.m3,c8.m3,c9.m3,c10.m3, c7.m0,c8.m0,c9.m0,c10.m0,c3.m5,c3.m4,c3.m2,P[15]}; return bound(s3,m,b,fuzz,depth); } double cornerbound(triple *P, double (*m)(double, double), double (*f)(const triple&)) { double b=m(f(P[0]),f(P[3])); b=m(b,f(P[12])); return m(b,f(P[15])); } // Return f evaluated at controlling vertex of bounding box of n control // net points for similiar-triangle transform x'=x/z, y'=y/z, where z < 0. double ratiobound(triple *P, double (*m)(double, double), double (*f)(const triple&), int n) { double MX=-P[0].getx(); double MY=-P[0].gety(); double Z=P[0].getz(); double MZ=-Z; for(int i=1; i < n; ++i) { triple v=P[i]; MX=m(MX,-v.getx()); MY=m(MY,-v.gety()); Z=m(Z,v.getz()); MZ=m(MZ,-v.getz()); } return m(f(triple(-MX,-MY,Z)),f(triple(-MX,-MY,-MZ))); } double controlbound(triple *P, double (*m)(double, double), double (*f)(const triple&)) { double b=m(f(P[1]),f(P[2])); b=m(b,f(P[4])); b=m(b,f(P[5])); b=m(b,f(P[6])); b=m(b,f(P[7])); b=m(b,f(P[8])); b=m(b,f(P[9])); b=m(b,f(P[10])); b=m(b,f(P[11])); b=m(b,f(P[13])); return m(b,f(P[14])); } double bound(triple *P, double (*m)(double, double), double (*f)(const triple&), double b, double fuzz, int depth) { b=m(b,cornerbound(P,m,f)); if(m(-1.0,1.0)*(b-ratiobound(P,m,f,16)) >= -fuzz || depth == 0) return b; --depth; Split c0(P[0],P[1],P[2],P[3]); Split c1(P[4],P[5],P[6],P[7]); Split c2(P[8],P[9],P[10],P[11]); Split c3(P[12],P[13],P[14],P[15]); Split c4(P[12],P[8],P[4],P[0]); Split c5(c3.m0,c2.m0,c1.m0,c0.m0); Split c6(c3.m3,c2.m3,c1.m3,c0.m3); Split c7(c3.m5,c2.m5,c1.m5,c0.m5); Split c8(c3.m4,c2.m4,c1.m4,c0.m4); Split c9(c3.m2,c2.m2,c1.m2,c0.m2); Split c10(P[15],P[11],P[7],P[3]); // Check all 4 Bezier subpatches. triple s0[]={c4.m5,c5.m5,c6.m5,c7.m5,c4.m3,c5.m3,c6.m3,c7.m3, c4.m0,c5.m0,c6.m0,c7.m0,P[12],c3.m0,c3.m3,c3.m5}; b=bound(s0,m,f,b,fuzz,depth); triple s1[]={P[0],c0.m0,c0.m3,c0.m5,c4.m2,c5.m2,c6.m2,c7.m2, c4.m4,c5.m4,c6.m4,c7.m4,c4.m5,c5.m5,c6.m5,c7.m5}; b=bound(s1,m,f,b,fuzz,depth); triple s2[]={c0.m5,c0.m4,c0.m2,P[3],c7.m2,c8.m2,c9.m2,c10.m2, c7.m4,c8.m4,c9.m4,c10.m4,c7.m5,c8.m5,c9.m5,c10.m5}; b=bound(s2,m,f,b,fuzz,depth); triple s3[]={c7.m5,c8.m5,c9.m5,c10.m5,c7.m3,c8.m3,c9.m3,c10.m3, c7.m0,c8.m0,c9.m0,c10.m0,c3.m5,c3.m4,c3.m2,P[15]}; return bound(s3,m,f,b,fuzz,depth); } template struct Splittri { T l003,p102,p012,p201,p111,p021,r300,p210,p120,u030; T u021,u120; T p033,p231,p330; T p123; T l012,p312,r210,l102,p303,r201; T u012,u210,l021,p4xx,r120,px4x,pxx4,l201,r102; T l210,r012,l300; T r021,u201,r030; T u102,l120,l030; T l111,r111,u111,c111; Splittri(const T *p) { l003=p[0]; p102=p[1]; p012=p[2]; p201=p[3]; p111=p[4]; p021=p[5]; r300=p[6]; p210=p[7]; p120=p[8]; u030=p[9]; u021=0.5*(u030+p021); u120=0.5*(u030+p120); p033=0.5*(p021+p012); p231=0.5*(p120+p111); p330=0.5*(p120+p210); p123=0.5*(p012+p111); l012=0.5*(p012+l003); p312=0.5*(p111+p201); r210=0.5*(p210+r300); l102=0.5*(l003+p102); p303=0.5*(p102+p201); r201=0.5*(p201+r300); u012=0.5*(u021+p033); u210=0.5*(u120+p330); l021=0.5*(p033+l012); p4xx=0.5*p231+0.25*(p111+p102); r120=0.5*(p330+r210); px4x=0.5*p123+0.25*(p111+p210); pxx4=0.25*(p021+p111)+0.5*p312; l201=0.5*(l102+p303); r102=0.5*(p303+r201); l210=0.5*(px4x+l201); // = m120 r012=0.5*(px4x+r102); // = m021 l300=0.5*(l201+r102); // = r003 = m030 r021=0.5*(pxx4+r120); // = m012 u201=0.5*(u210+pxx4); // = m102 r030=0.5*(u210+r120); // = u300 = m003 u102=0.5*(u012+p4xx); // = m201 l120=0.5*(l021+p4xx); // = m210 l030=0.5*(u012+l021); // = u003 = m300 l111=0.5*(p123+l102); r111=0.5*(p312+r210); u111=0.5*(u021+p231); c111=0.25*(p033+p330+p303+p111); } }; // Return the extremum of the vertices of a Bezier triangle. double cornerboundtri(double *P, double (*m)(double, double)) { double b=m(P[0],P[6]); return m(b,P[9]); } double cornerboundtri(triple *P, double (*m)(double, double), double (*f)(const triple&)) { double b=m(f(P[0]),f(P[6])); return m(b,f(P[9])); } // Return the extremum of the non-vertex control points of a Bezier triangle. double controlboundtri(double *P, double (*m)(double, double)) { double b=m(P[1],P[2]); b=m(b,P[3]); b=m(b,P[4]); b=m(b,P[5]); b=m(b,P[7]); return m(b,P[8]); } double controlboundtri(triple *P, double (*m)(double, double), double (*f)(const triple&)) { double b=m(f(P[1]),f(P[2])); b=m(b,f(P[3])); b=m(b,f(P[4])); b=m(b,f(P[5])); b=m(b,f(P[7])); return m(b,f(P[8])); } // Return the global bound of a Bezier triangle. double boundtri(double *P, double (*m)(double, double), double b, double fuzz, int depth) { b=m(b,cornerboundtri(P,m)); if(m(-1.0,1.0)*(b-controlboundtri(P,m)) >= -fuzz || depth == 0) return b; --depth; Splittri s(P); double l[]={s.l003,s.l102,s.l012,s.l201,s.l111, s.l021,s.l300,s.l210,s.l120,s.l030}; // left b=boundtri(l,m,b,fuzz,depth); double r[]={s.l300,s.r102,s.r012,s.r201,s.r111, s.r021,s.r300,s.r210,s.r120,s.r030}; // right b=boundtri(r,m,b,fuzz,depth); double u[]={s.l030,s.u102,s.u012,s.u201,s.u111, s.u021,s.r030,s.u210,s.u120,s.u030}; // up b=boundtri(u,m,b,fuzz,depth); double c[]={s.r030,s.u201,s.r021,s.u102,s.c111, s.r012,s.l030,s.l120,s.l210,s.l300}; // center return boundtri(c,m,b,fuzz,depth); } double boundtri(triple *P, double (*m)(double, double), double (*f)(const triple&), double b, double fuzz, int depth) { b=m(b,cornerboundtri(P,m,f)); if(m(-1.0,1.0)*(b-ratiobound(P,m,f,10)) >= -fuzz || depth == 0) return b; --depth; Splittri s(P); triple l[]={s.l003,s.l102,s.l012,s.l201,s.l111, s.l021,s.l300,s.l210,s.l120,s.l030}; // left b=boundtri(l,m,f,b,fuzz,depth); triple r[]={s.l300,s.r102,s.r012,s.r201,s.r111, s.r021,s.r300,s.r210,s.r120,s.r030}; // right b=boundtri(r,m,f,b,fuzz,depth); triple u[]={s.l030,s.u102,s.u012,s.u201,s.u111, s.u021,s.r030,s.u210,s.u120,s.u030}; // up b=boundtri(u,m,f,b,fuzz,depth); triple c[]={s.r030,s.u201,s.r021,s.u102,s.c111, s.r012,s.l030,s.l120,s.l210,s.l300}; // center return boundtri(c,m,f,b,fuzz,depth); } inline void add(std::vector& T, std::vector& U, std::vector& V, double t, double u, double v, const path3& p, double fuzz2) { triple z=p.point(t); size_t n=T.size(); for(size_t i=0; i < n; ++i) if((p.point(T[i])-z).abs2() <= fuzz2) return; T.push_back(t); U.push_back(u); V.push_back(v); } void add(std::vector& T, std::vector& U, std::vector& V, std::vector& T1, std::vector& U1, std::vector& V1, const path3& p, double tscale, double toffset, double uoffset, double voffset, double fuzz2) { size_t n=T1.size(); for(size_t i=0; i < n; ++i) add(T,U,V,tscale*T1[i]+toffset,0.5*U1[i]+uoffset,0.5*V1[i]+voffset,p, fuzz2); } void bounds(triple& Pmin, triple& Pmax, triple *P, double fuzz) { double Px[]={P[0].getx(),P[1].getx(),P[2].getx(),P[3].getx(), P[4].getx(),P[5].getx(),P[6].getx(),P[7].getx(), P[8].getx(),P[9].getx(),P[10].getx(),P[11].getx(), P[12].getx(),P[13].getx(),P[14].getx(),P[15].getx()}; double bx=Px[0]; double xmin=bound(Px,min,bx,fuzz,maxdepth); double xmax=bound(Px,max,bx,fuzz,maxdepth); double Py[]={P[0].gety(),P[1].gety(),P[2].gety(),P[3].gety(), P[4].gety(),P[5].gety(),P[6].gety(),P[7].gety(), P[8].gety(),P[9].gety(),P[10].gety(),P[11].gety(), P[12].gety(),P[13].gety(),P[14].gety(),P[15].gety()}; double by=Py[0]; double ymin=bound(Py,min,by,fuzz,maxdepth); double ymax=bound(Py,max,by,fuzz,maxdepth); double Pz[]={P[0].getz(),P[1].getz(),P[2].getz(),P[3].getz(), P[4].getz(),P[5].getz(),P[6].getz(),P[7].getz(), P[8].getz(),P[9].getz(),P[10].getz(),P[11].getz(), P[12].getz(),P[13].getz(),P[14].getz(),P[15].getz()}; double bz=Pz[0]; double zmin=bound(Pz,min,bz,fuzz,maxdepth); double zmax=bound(Pz,max,bz,fuzz,maxdepth); Pmin=triple(xmin,ymin,zmin); Pmax=triple(xmax,ymax,zmax); } inline double abs2(double x, double y, double z) { return x*x+y*y+z*z; } bool intersections(double& U, double& V, const triple& v, triple *P, double fuzz, unsigned depth) { if(errorstream::interrupt) throw interrupted(); triple Pmin,Pmax; bounds(Pmin,Pmax,P,fuzz); double x=P[0].getx(); double y=P[0].gety(); double z=P[0].getz(); double X=x, Y=y, Z=z; for(int i=1; i < 16; ++i) { triple v=P[i]; double vx=v.getx(); x=min(x,vx); X=max(X,vx); double vy=v.gety(); y=min(y,vy); Y=max(Y,vy); double vz=v.getz(); z=min(z,vz); Z=max(Z,vz); } if(X+fuzz >= v.getx() && Y+fuzz >= v.gety() && Z+fuzz >= v.getz() && v.getx()+fuzz >= x && v.gety()+fuzz >= y && v.getz()+fuzz >= z) { // Overlapping bounding boxes --depth; if(abs2(X-x,Y-y,Z-z) <= fuzz*fuzz || depth == 0) { U=0.5; V=0.5; return true; } // Compute the control points of the four subpatches obtained by splitting // the patch with control points P at u=v=1/2. Split c0(P[0],P[1],P[2],P[3]); Split c1(P[4],P[5],P[6],P[7]); Split c2(P[8],P[9],P[10],P[11]); Split c3(P[12],P[13],P[14],P[15]); Split c4(P[12],P[8],P[4],P[0]); Split c5(c3.m0,c2.m0,c1.m0,c0.m0); Split c6(c3.m3,c2.m3,c1.m3,c0.m3); Split c7(c3.m5,c2.m5,c1.m5,c0.m5); Split c8(c3.m4,c2.m4,c1.m4,c0.m4); Split c9(c3.m2,c2.m2,c1.m2,c0.m2); Split c10(P[15],P[11],P[7],P[3]); // Check all 4 Bezier subpatches. double U1,V1; triple Q0[]={P[0],c0.m0,c0.m3,c0.m5,c4.m2,c5.m2,c6.m2,c7.m2, c4.m4,c5.m4,c6.m4,c7.m4,c4.m5,c5.m5,c6.m5,c7.m5}; if(intersections(U1,V1,v,Q0,fuzz,depth)) { U=0.5*U1; V=0.5*V1; return true; } triple Q1[]={c0.m5,c0.m4,c0.m2,P[3],c7.m2,c8.m2,c9.m2,c10.m2, c7.m4,c8.m4,c9.m4,c10.m4,c7.m5,c8.m5,c9.m5,c10.m5}; if(intersections(U1,V1,v,Q1,fuzz,depth)) { U=0.5*U1; V=0.5*V1+0.5; return true; } triple Q2[]={c7.m5,c8.m5,c9.m5,c10.m5,c7.m3,c8.m3,c9.m3,c10.m3, c7.m0,c8.m0,c9.m0,c10.m0,c3.m5,c3.m4,c3.m2,P[15]}; if(intersections(U1,V1,v,Q2,fuzz,depth)) { U=0.5*U1+0.5; V=0.5*V1+0.5; return true; } triple Q3[]={c4.m5,c5.m5,c6.m5,c7.m5,c4.m3,c5.m3,c6.m3,c7.m3, c4.m0,c5.m0,c6.m0,c7.m0,P[12],c3.m0,c3.m3,c3.m5}; if(intersections(U1,V1,v,Q3,fuzz,depth)) { U=0.5*U1+0.5; V=0.5*V1; return true; } } return false; } bool intersections(std::vector& T, std::vector& U, std::vector& V, path3& p, triple *P, double fuzz, bool single, unsigned depth) { if(errorstream::interrupt) throw interrupted(); triple pmin=p.min(); triple pmax=p.max(); double x=P[0].getx(); double y=P[0].gety(); double z=P[0].getz(); double X=x, Y=y, Z=z; for(int i=1; i < 16; ++i) { triple v=P[i]; double vx=v.getx(); x=min(x,vx); X=max(X,vx); double vy=v.gety(); y=min(y,vy); Y=max(Y,vy); double vz=v.getz(); z=min(z,vz); Z=max(Z,vz); } if(X+fuzz >= pmin.getx() && Y+fuzz >= pmin.gety() && Z+fuzz >= pmin.getz() && pmax.getx()+fuzz >= x && pmax.gety()+fuzz >= y && pmax.getz()+fuzz >= z) { // Overlapping bounding boxes --depth; if(((pmax-pmin).length()+sqrt(abs2(X-x,Y-y,Z-z)) <= fuzz) || depth == 0) { T.push_back(0.5); U.push_back(0.5); V.push_back(0.5); return true; } Int lp=p.length(); path3 p0,p1; p.halve(p0,p1); std::vector T1,U1,V1; double tscale,toffset; double fuzz2=max(fuzzFactor*fuzz,Fuzz); fuzz2=fuzz2*fuzz2; if(lp <= 1) { if(lp == 1) p.halve(p0,p1); if(lp == 0 || p0 == p || p1 == p) { double u,v; if(intersections(u,v,p.point((Int) 0),P,fuzz,depth)) { T1.push_back(0.0); U1.push_back(u); V1.push_back(v); add(T,U,V,T1,U1,V1,p,1.0,0.0,0.0,0.0,fuzz2); } return T1.size() > 0; } tscale=toffset=0.5; } else { Int tp=lp/2; p0=p.subpath(0,tp); p1=p.subpath(tp,lp); toffset=tp; tscale=1.0; } Split c0(P[0],P[1],P[2],P[3]); Split c1(P[4],P[5],P[6],P[7]); Split c2(P[8],P[9],P[10],P[11]); Split c3(P[12],P[13],P[14],P[15]); Split c4(P[12],P[8],P[4],P[0]); Split c5(c3.m0,c2.m0,c1.m0,c0.m0); Split c6(c3.m3,c2.m3,c1.m3,c0.m3); Split c7(c3.m5,c2.m5,c1.m5,c0.m5); Split c8(c3.m4,c2.m4,c1.m4,c0.m4); Split c9(c3.m2,c2.m2,c1.m2,c0.m2); Split c10(P[15],P[11],P[7],P[3]); static size_t maxcount=9; size_t count=0; bool Short=lp == 1; // Check all 4 Bezier subpatches against p0. triple Q0[]={P[0],c0.m0,c0.m3,c0.m5,c4.m2,c5.m2,c6.m2,c7.m2, c4.m4,c5.m4,c6.m4,c7.m4,c4.m5,c5.m5,c6.m5,c7.m5}; if(intersections(T1,U1,V1,p0,Q0,fuzz,single,depth)) { add(T,U,V,T1,U1,V1,p,tscale,0.0,0.0,0.0,fuzz2); if(single || depth <= mindepth) return true; count += T1.size(); if(Short && count > maxcount) return true; } T1.clear(); U1.clear(); V1.clear(); triple Q1[]={c0.m5,c0.m4,c0.m2,P[3],c7.m2,c8.m2,c9.m2,c10.m2, c7.m4,c8.m4,c9.m4,c10.m4,c7.m5,c8.m5,c9.m5,c10.m5}; if(intersections(T1,U1,V1,p0,Q1,fuzz,single,depth)) { add(T,U,V,T1,U1,V1,p,tscale,0.0,0.0,0.5,fuzz2); if(single || depth <= mindepth) return true; count += T1.size(); if(Short && count > maxcount) return true; } T1.clear(); U1.clear(); V1.clear(); triple Q2[]={c7.m5,c8.m5,c9.m5,c10.m5,c7.m3,c8.m3,c9.m3,c10.m3, c7.m0,c8.m0,c9.m0,c10.m0,c3.m5,c3.m4,c3.m2,P[15]}; if(intersections(T1,U1,V1,p0,Q2,fuzz,single,depth)) { add(T,U,V,T1,U1,V1,p,tscale,0.0,0.5,0.5,fuzz2); if(single || depth <= mindepth) return true; count += T1.size(); if(Short && count > maxcount) return true; } T1.clear(); U1.clear(); V1.clear(); triple Q3[]={c4.m5,c5.m5,c6.m5,c7.m5,c4.m3,c5.m3,c6.m3,c7.m3, c4.m0,c5.m0,c6.m0,c7.m0,P[12],c3.m0,c3.m3,c3.m5}; if(intersections(T1,U1,V1,p0,Q3,fuzz,single,depth)) { add(T,U,V,T1,U1,V1,p,tscale,0.0,0.5,0.0,fuzz2); if(single || depth <= mindepth) return true; count += T1.size(); if(Short && count > maxcount) return true; } // Check all 4 Bezier subpatches against p1. T1.clear(); U1.clear(); V1.clear(); if(intersections(T1,U1,V1,p1,Q0,fuzz,single,depth)) { add(T,U,V,T1,U1,V1,p,tscale,toffset,0.0,0.0,fuzz2); if(single || depth <= mindepth) return true; count += T1.size(); if(Short && count > maxcount) return true; } T1.clear(); U1.clear(); V1.clear(); if(intersections(T1,U1,V1,p1,Q1,fuzz,single,depth)) { add(T,U,V,T1,U1,V1,p,tscale,toffset,0.0,0.5,fuzz2); if(single || depth <= mindepth) return true; count += T1.size(); if(Short && count > maxcount) return true; } T1.clear(); U1.clear(); V1.clear(); if(intersections(T1,U1,V1,p1,Q2,fuzz,single,depth)) { add(T,U,V,T1,U1,V1,p,tscale,toffset,0.5,0.5,fuzz2); if(single || depth <= mindepth) return true; count += T1.size(); if(Short && count > maxcount) return true; } T1.clear(); U1.clear(); V1.clear(); if(intersections(T1,U1,V1,p1,Q3,fuzz,single,depth)) { add(T,U,V,T1,U1,V1,p,tscale,toffset,0.5,0.0,fuzz2); if(single || depth <= mindepth) return true; count += T1.size(); if(Short && count > maxcount) return true; } return T.size() > 0; } return false; } } //namespace camp asymptote-2.37/path3.h000066400000000000000000000245161265434602500147010ustar00rootroot00000000000000/***** * path.h * John Bowman * * Stores a 3D piecewise cubic spline with known control points. * *****/ #ifndef PATH3_H #define PATH3_H #include #include "mod.h" #include "triple.h" #include "bbox3.h" #include "path.h" #include "arrayop.h" namespace camp { void checkEmpty3(Int n); // Used in the storage of solved path3 knots. struct solvedKnot3 : public gc { triple pre; triple point; triple post; bool straight; solvedKnot3() : straight(false) {} friend bool operator== (const solvedKnot3& p, const solvedKnot3& q) { return p.pre == q.pre && p.point == q.point && p.post == q.post; } }; extern const double BigFuzz; extern const double Fuzz; extern const double Fuzz2; extern const double sqrtFuzz; class path3 : public gc { bool cycles; // If the path3 is closed in a loop Int n; // The number of knots mem::vector nodes; mutable double cached_length; // Cache length since path3 is immutable. mutable bbox3 box; mutable bbox3 times; // Times where minimum and maximum extents are attained. public: path3() : cycles(false), n(0), nodes(), cached_length(-1) {} // Create a path3 of a single point path3(triple z, bool = false) : cycles(false), n(1), nodes(1), cached_length(-1) { nodes[0].pre = nodes[0].point = nodes[0].post = z; nodes[0].straight = false; } // Creates path3 from a list of knots. This will be used by camp // methods such as the guide solver, but should probably not be used by a // user of the system unless he knows what he is doing. path3(mem::vector& nodes, Int n, bool cycles = false) : cycles(cycles), n(n), nodes(nodes), cached_length(-1) { } friend bool operator== (const path3& p, const path3& q) { return p.cycles == q.cycles && p.nodes == q.nodes; } public: path3(solvedKnot3 n1, solvedKnot3 n2) : cycles(false), n(2), nodes(2), cached_length(-1) { nodes[0] = n1; nodes[1] = n2; nodes[0].pre = nodes[0].point; nodes[1].post = nodes[1].point; } // Copy constructor path3(const path3& p) : cycles(p.cycles), n(p.n), nodes(p.nodes), cached_length(p.cached_length), box(p.box) {} path3 unstraighten() const { path3 P=path3(*this); for(int i=0; i < n; ++i) P.nodes[i].straight=false; return P; } virtual ~path3() { } // Getting control points Int size() const { return n; } bool empty() const { return n == 0; } Int length() const { return cycles ? n : n-1; } bool cyclic() const { return cycles; } mem::vector& Nodes() { return nodes; } bool straight(Int t) const { if (cycles) return nodes[imod(t,n)].straight; return (t >= 0 && t < n) ? nodes[t].straight : false; } bool piecewisestraight() const { Int L=length(); for(Int i=0; i < L; ++i) if(!straight(i)) return false; return true; } triple point(Int t) const { return nodes[adjustedIndex(t,n,cycles)].point; } triple point(double t) const; triple precontrol(Int t) const { return nodes[adjustedIndex(t,n,cycles)].pre; } triple precontrol(double t) const; triple postcontrol(Int t) const { return nodes[adjustedIndex(t,n,cycles)].post; } triple postcontrol(double t) const; inline double norm(const triple& z0, const triple& c0, const triple& c1, const triple& z1) const { return Fuzz2*camp::max((c0-z0).abs2(), camp::max((c1-z0).abs2(),(z1-z0).abs2())); } triple predir(Int t, bool normalize=true) const { if(!cycles && t <= 0) return triple(0,0,0); triple z1=point(t); triple c1=precontrol(t); triple dir=3.0*(z1-c1); if(!normalize) return dir; triple z0=point(t-1); triple c0=postcontrol(t-1); double epsilon=norm(z0,c0,c1,z1); if(dir.abs2() > epsilon) return unit(dir); dir=2.0*c1-c0-z1; if(dir.abs2() > epsilon) return unit(dir); return unit(z1-z0+3.0*(c0-c1)); } triple postdir(Int t, bool normalize=true) const { if(!cycles && t >= n-1) return triple(0,0,0); triple c0=postcontrol(t); triple z0=point(t); triple dir=3.0*(c0-z0); triple z1=point(t+1); triple c1=precontrol(t+1); double epsilon=norm(z0,c0,c1,z1); if(!normalize) return dir; if(dir.abs2() > epsilon) return unit(dir); dir=z0-2.0*c0+c1; if(dir.abs2() > epsilon) return unit(dir); return unit(z1-z0+3.0*(c0-c1)); } triple dir(Int t, Int sign, bool normalize=true) const { if(sign == 0) { triple v=predir(t,normalize)+postdir(t,normalize); return normalize ? unit(v) : 0.5*v; } if(sign > 0) return postdir(t,normalize); return predir(t,normalize); } triple dir(double t, bool normalize=true) const { if(!cycles) { if(t <= 0) return postdir((Int) 0,normalize); if(t >= n-1) return predir(n-1,normalize); } Int i=Floor(t); t -= i; if(t == 0) return dir(i,0,normalize); triple z0=point(i); triple c0=postcontrol(i); triple c1=precontrol(i+1); triple z1=point(i+1); triple a=3.0*(z1-z0)+9.0*(c0-c1); triple b=6.0*(z0+c1)-12.0*c0; triple c=3.0*(c0-z0); triple dir=a*t*t+b*t+c; if(!normalize) return dir; double epsilon=norm(z0,c0,c1,z1); if(dir.abs2() > epsilon) return unit(dir); dir=2.0*a*t+b; if(dir.abs2() > epsilon) return unit(dir); return unit(a); } triple postaccel(Int t) const { if(!cycles && t >= n-1) return triple(0,0,0); triple z0=point(t); triple c0=postcontrol(t); triple c1=precontrol(t+1); return 6.0*(z0+c1)-12.0*c0; } triple preaccel(Int t) const { if(!cycles && t <= 0) return triple(0,0,0); triple z0=point(t-1); triple c0=postcontrol(t-1); triple c1=precontrol(t); triple z1=point(t); return 6.0*(z1+c0)-12.0*c1; } triple accel(Int t, Int sign) const { if(sign == 0) return 0.5*(preaccel(t)+postaccel(t)); if(sign > 0) return postaccel(t); return preaccel(t); } triple accel(double t) const { if(!cycles) { if(t <= 0) return postaccel((Int) 0); if(t >= n-1) return preaccel(n-1); } Int i=Floor(t); t -= i; if(t == 0) return 0.5*(postaccel(i)+preaccel(i)); triple z0=point(i); triple c0=postcontrol(i); triple c1=precontrol(i+1); triple z1=point(i+1); return 6.0*t*(z1-z0+3.0*(c0-c1))+6.0*(z0+c1)-12.0*c0; } // Returns the path3 traced out in reverse. path3 reverse() const; // Generates a path3 that is a section of the old path3, using the time // interval given. path3 subpath(Int start, Int end) const; path3 subpath(double start, double end) const; // Special case of subpath used by intersect. void halve(path3 &first, path3 &second) const; // Used by picture to determine bounding box. bbox3 bounds() const; triple mintimes() const { checkEmpty3(n); bounds(); return camp::triple(times.left,times.bottom,times.lower); } triple maxtimes() const { checkEmpty3(n); bounds(); return camp::triple(times.right,times.top,times.upper); } template void addpoint(bbox3& box, T i) const { box.addnonempty(point(i),times,(double) i); } double cubiclength(Int i, double goal=-1) const; double arclength () const; double arctime (double l) const; triple max() const { checkEmpty3(n); return bounds().Max(); } triple min() const { checkEmpty3(n); return bounds().Min(); } pair ratio(double (*m)(double, double)) const; // Increment count if the path3 has a vertical component at t. bool Count(Int& count, double t) const; // Count if t is in (begin,end] and z lies to the left of point(i+t). void countleft(Int& count, double x, Int i, double t, double begin, double end, double& mint, double& maxt) const; // Return the winding number of the region bounded by the (cyclic) path3 // relative to the point z. Int windingnumber(const triple& z) const; }; path3 transformed(const vm::array& t, const path3& p); path3 transformed(const double* t, const path3& p); extern path3 nullpath3; extern const unsigned maxdepth; bool intersect(double& S, double& T, path3& p, path3& q, double fuzz, unsigned depth=maxdepth); bool intersections(double& s, double& t, std::vector& S, std::vector& T, path3& p, path3& q, double fuzz, bool single, bool exact, unsigned depth=maxdepth); void intersections(std::vector& S, path3& g, const triple& p, const triple& q, double fuzz); bool intersections(std::vector& T, std::vector& U, std::vector& V, path3& p, triple *P, double fuzz, bool single, unsigned depth=maxdepth); bool intersections(double& U, double& V, const triple& v, triple *P, double fuzz, unsigned depth=maxdepth); // Concatenates two path3s into a new one. path3 concat(const path3& p1, const path3& p2); // return the perpendicular displacement of a point z from the line through // points p and q. inline triple displacement(const triple& z, const triple& p, const triple& q) { triple Z=z-p; triple Q=unit(q-p); return Z-dot(Z,Q)*Q; } typedef double bound_double(double *P, double (*m)(double, double), double b, double fuzz, int depth); typedef double bound_triple(triple *P, double (*m)(double, double), double (*f)(const triple&), double b, double fuzz, int depth); bound_double bound,boundtri; double bound(triple z0, triple c0, triple c1, triple z1, double (*m)(double, double), double (*f)(const triple&), double b, double fuzz, int depth=maxdepth); double bound(double *p, double (*m)(double, double), double b, double fuzz, int depth); double bound(triple *P, double (*m)(double, double), double (*f)(const triple&), double b, double fuzz, int depth); double boundtri(double *P, double (*m)(double, double), double b, double fuzz, int depth); double boundtri(triple *P, double (*m)(double, double), double (*f)(const triple&), double b, double fuzz, int depth); } #ifndef BROKEN_COMPILER // Delete the following line to work around problems with old broken compilers. GC_DECLARE_PTRFREE(camp::solvedKnot3); #endif #endif asymptote-2.37/pen.cc000066400000000000000000000031731265434602500145760ustar00rootroot00000000000000/***** * pen.cc * John Bowman * *****/ #include "pen.h" #include "drawelement.h" namespace camp { const double tex2ps=72.0/72.27; const double ps2tex=1.0/tex2ps; const char* DEFPAT=""; const char* DEFLATEXFONT="\\usefont{\\ASYencoding}{\\ASYfamily}{\\ASYseries}{\\ASYshape}"; const char* DEFCONTEXTFONT="modern"; const char* DEFTEXFONT="cmr12"; const double DEFWIDTH=-1; const Int DEFCAP=-1; const Int DEFJOIN=-1; const double DEFMITER=0; const transform nullTransform=transform(0.0,0.0,0.0,0.0,0.0,0.0); const char* PSCap[]={"butt","round","square"}; const char* Cap[]={"square","round","extended"}; const Int nCap=sizeof(Cap)/sizeof(char*); const char* Join[]={"miter","round","bevel"}; const Int nJoin=sizeof(Join)/sizeof(char*); const char* OverwriteTag[]={"Allow","Suppress","SupressQuiet", "Move","MoveQuiet"}; const Int nOverwrite=sizeof(OverwriteTag)/sizeof(char*); const char* FillRuleTag[]={"ZeroWinding","EvenOdd"}; const Int nFill=sizeof(FillRuleTag)/sizeof(char*); const char* BaseLineTag[]={"NoAlign","Align"}; const Int nBaseLine=sizeof(BaseLineTag)/sizeof(char*); const char* ColorDeviceSuffix[]={"","","Gray","RGB","CMYK",""}; const unsigned nColorSpace=sizeof(ColorDeviceSuffix)/sizeof(char*); const char* BlendMode[]={"Compatible","Normal","Multiply","Screen", "Overlay","SoftLight","HardLight", "ColorDodge","ColorBurn","Darken", "Lighten","Difference","Exclusion", "Hue","Saturation","Color","Luminosity"}; const Int nBlendMode=sizeof(BlendMode)/sizeof(char*); pen drawElement::lastpen; } asymptote-2.37/pen.h000066400000000000000000000667711265434602500144550ustar00rootroot00000000000000/***** * pen.h * John Bowman 2003/03/23 * *****/ #ifndef PEN_H #define PEN_H #include #include "transform.h" #include "settings.h" #include "bbox.h" #include "common.h" #include "path.h" #include "array.h" namespace camp { extern const double tex2ps; extern const double ps2tex; class LineType { public: vm::array pattern; // Array of PostScript style line pattern entries. double offset; // The offset in the pattern at which to start drawing. bool scale; // Scale the line type values by the pen width? bool adjust; // Adjust the line type values to fit the arclength? bool isdefault; LineType() : offset(0.0), scale(true), adjust(true), isdefault(true) {} LineType(vm::array pattern, double offset, bool scale, bool adjust) : pattern(pattern), offset(offset), scale(scale), adjust(adjust), isdefault(false) {} void Scale(double factor) { size_t n=pattern.size(); for(size_t i=0; i < n; i++) pattern[i]=vm::read(pattern,i)*factor; offset *= factor; } }; extern const char* DEFPAT; extern const char* DEFLATEXFONT; extern const char* DEFCONTEXTFONT; extern const char* DEFTEXFONT; extern const double DEFWIDTH; extern const Int DEFCAP; extern const Int DEFJOIN; extern const double DEFMITER; extern const transform nullTransform; static const struct invisiblepen_t {} invisiblepen={}; static const struct setlinewidth_t {} setlinewidth={}; static const struct setfont_t {} setfont={}; static const struct setfontsize_t {} setfontsize={}; static const struct setpattern_t {} setpattern={}; static const struct setlinecap_t {} setlinecap={}; static const struct setlinejoin_t {} setlinejoin={}; static const struct setmiterlimit_t {} setmiterlimit={}; static const struct setoverwrite_t {} setoverwrite={}; static const struct initialpen_t {} initialpen={}; static const struct resolvepen_t {} resolvepen={}; extern const char* PSCap[]; extern const char* Cap[]; extern const Int nCap; extern const char* Join[]; extern const Int nJoin; enum overwrite_t {DEFWRITE=-1,ALLOW,SUPPRESS,SUPPRESSQUIET,MOVE,MOVEQUIET}; extern const char* OverwriteTag[]; extern const Int nOverwrite; enum FillRule {DEFFILL=-1,ZEROWINDING,EVENODD}; extern const char* FillRuleTag[]; extern const Int nFill; enum BaseLine {DEFBASE=-1,NOBASEALIGN,BASEALIGN}; extern const char* BaseLineTag[]; extern const Int nBaseLine; enum ColorSpace {DEFCOLOR=0,INVISIBLE,GRAYSCALE,RGB,CMYK,PATTERN}; extern const size_t ColorComponents[]; extern const char* ColorDeviceSuffix[]; extern const unsigned nColorSpace; inline bool operator == (const vm::array& a, const vm::array& b) { size_t asize=a.size(); size_t bsize=b.size(); if(asize != bsize) return false; for(size_t i=0; i < asize; ++i) if(vm::read(a,i) != vm::read(b,i)) return false; return true; } inline bool operator == (const LineType& a, const LineType& b) { return a.pattern == b.pattern && a.offset == b.offset && a.scale == b.scale && a.adjust == b.adjust; } inline ostream& operator << (ostream& out, const vm::array& a) { out << "["; size_t n=a.size(); if(n > 0) { out << vm::read(a,0); for(size_t i=1; i < n; ++i) out << " " << vm::read(a,i); } out << "]"; return out; } class Transparency { public: string blend; double opacity; bool isdefault; Transparency() : blend("Compatible"), opacity(1.0), isdefault(true) {} Transparency(const string& blend, double opacity) : blend(blend), opacity(opacity), isdefault(false) {} }; inline bool operator == (const Transparency& a, const Transparency& b) { return a.blend == b.blend && a.opacity == b.opacity; } extern const char* BlendMode[]; extern const Int nBlendMode; // Map [0,1] to [0,255] inline unsigned int byte(double r) { if(r < 0.0) r=0.0; else if(r > 1.0) r=1.0; int a=(int)(256.0*r); if(a == 256) a=255; return a; } class pen; pen& defaultpen(); class pen : public gc { LineType line; // Width of line, in PS units. double linewidth; path P; // A polygonal path defining a custom pen nib; // nullpath means the default (typically circular) nib. string font; double fontsize; double lineskip; ColorSpace color; double r,g,b; // RGB or CMY value double grey; // grayscale or K value string pattern; // The name of the user-defined fill/draw pattern FillRule fillrule; // Zero winding-number (default) or even-odd rule BaseLine baseline; // Align to TeX baseline? Transparency transparency; Int linecap; Int linejoin; double miterlimit; overwrite_t overwrite; // The transformation applied to the pen nib for calligraphic effects. // nullTransform means the default (typically identity) transformation. transform t; public: static double pos0(double x) {return x >= 0 ? x : 0;} void greyrange() {if(grey > 1.0) grey=1.0;} void rgbrange() { double sat=rgbsaturation(); if(sat > 1.0) { double scale=1.0/sat; r *= scale; g *= scale; b *= scale; } } void cmykrange() { double sat=cmyksaturation(); if(sat > 1.0) { double scale=1.0/sat; r *= scale; g *= scale; b *= scale; grey *= scale; } } void colorless() { r=g=b=grey=0.0; color=DEFCOLOR; } pen() : line(), linewidth(DEFWIDTH), P(nullpath), font(""), fontsize(0.0), lineskip(0.0), color(DEFCOLOR), r(0), g(0), b(0), grey(0), pattern(DEFPAT), fillrule(DEFFILL), baseline(DEFBASE), transparency(), linecap(DEFCAP), linejoin(DEFJOIN), miterlimit(DEFMITER), overwrite(DEFWRITE), t(nullTransform) {} pen(const LineType& line, double linewidth, const path& P, const string& font, double fontsize, double lineskip, ColorSpace color, double r, double g, double b, double grey, const string& pattern, FillRule fillrule, BaseLine baseline, const Transparency& transparency, Int linecap, Int linejoin, double miterlimit, overwrite_t overwrite, const transform& t) : line(line), linewidth(linewidth), P(P), font(font), fontsize(fontsize), lineskip(lineskip), color(color), r(r), g(g), b(b), grey(grey), pattern(pattern), fillrule(fillrule), baseline(baseline), transparency(transparency), linecap(linecap), linejoin(linejoin), miterlimit(miterlimit), overwrite(overwrite), t(t) {} pen(invisiblepen_t) : line(), linewidth(DEFWIDTH), P(nullpath), font(""), fontsize(0.0), lineskip(0.0), color(INVISIBLE), r(0), g(0), b(0), grey(0), pattern(DEFPAT), fillrule(DEFFILL), baseline(DEFBASE), transparency(), linecap(DEFCAP), linejoin(DEFJOIN), miterlimit(DEFMITER), overwrite(DEFWRITE), t(nullTransform) {} pen(setlinewidth_t, double linewidth) : line(), linewidth(linewidth), P(nullpath), font(""), fontsize(0.0), lineskip(0.0), color(DEFCOLOR), r(0), g(0), b(0), grey(0), pattern(DEFPAT), fillrule(DEFFILL), baseline(DEFBASE), transparency(), linecap(DEFCAP), linejoin(DEFJOIN), miterlimit(DEFMITER), overwrite(DEFWRITE), t(nullTransform) {} pen(path P) : line(), linewidth(DEFWIDTH), P(P), font(""), fontsize(0.0), lineskip(0.0), color(DEFCOLOR), r(0), g(0), b(0), grey(0), pattern(DEFPAT), fillrule(DEFFILL), baseline(DEFBASE), transparency(), linecap(DEFCAP), linejoin(DEFJOIN), miterlimit(DEFMITER), overwrite(DEFWRITE), t(nullTransform) {} pen(const LineType& line) : line(line), linewidth(DEFWIDTH), P(nullpath), font(""), fontsize(0.0), lineskip(0.0), color(DEFCOLOR), r(0), g(0), b(0), grey(0), pattern(DEFPAT), fillrule(DEFFILL), baseline(DEFBASE), transparency(), linecap(DEFCAP), linejoin(DEFJOIN), miterlimit(DEFMITER), overwrite(DEFWRITE), t(nullTransform) {} pen(setfont_t, string font) : line(), linewidth(DEFWIDTH), P(nullpath), font(font), fontsize(0.0), lineskip(0.0), color(DEFCOLOR), r(0), g(0), b(0), grey(0), pattern(DEFPAT), fillrule(DEFFILL), baseline(DEFBASE), transparency(), linecap(DEFCAP), linejoin(DEFJOIN), miterlimit(DEFMITER), overwrite(DEFWRITE), t(nullTransform) {} pen(setfontsize_t, double fontsize, double lineskip) : line(), linewidth(DEFWIDTH), P(nullpath), font(""), fontsize(fontsize), lineskip(lineskip), color(DEFCOLOR), r(0), g(0), b(0), grey(0), pattern(DEFPAT), fillrule(DEFFILL), baseline(DEFBASE), transparency(), linecap(DEFCAP), linejoin(DEFJOIN), miterlimit(DEFMITER), overwrite(DEFWRITE), t(nullTransform) {} pen(setpattern_t, const string& pattern) : line(), linewidth(DEFWIDTH), P(nullpath), font(""), fontsize(0.0), lineskip(0.0), color(PATTERN), r(0), g(0), b(0), grey(0), pattern(pattern), fillrule(DEFFILL), baseline(DEFBASE), transparency(), linecap(DEFCAP), linejoin(DEFJOIN), miterlimit(DEFMITER), overwrite(DEFWRITE), t(nullTransform) {} pen(FillRule fillrule) : line(), linewidth(DEFWIDTH), P(nullpath), font(""), fontsize(0.0), lineskip(0.0), color(DEFCOLOR), r(0), g(0), b(0), grey(0), pattern(DEFPAT), fillrule(fillrule), baseline(DEFBASE), transparency(), linecap(DEFCAP), linejoin(DEFJOIN), miterlimit(DEFMITER), overwrite(DEFWRITE), t(nullTransform) {} pen(BaseLine baseline) : line(), linewidth(DEFWIDTH), P(nullpath), font(""), fontsize(0.0), lineskip(0.0), color(DEFCOLOR), r(0), g(0), b(0), grey(0), pattern(DEFPAT), fillrule(DEFFILL), baseline(baseline), transparency(), linecap(DEFCAP), linejoin(DEFJOIN), miterlimit(DEFMITER), overwrite(DEFWRITE), t(nullTransform) {} pen(const Transparency& transparency) : line(), linewidth(DEFWIDTH), P(nullpath), font(""), fontsize(0.0), lineskip(0.0), color(DEFCOLOR), r(0), g(0), b(0), grey(0), pattern(DEFPAT), fillrule(DEFFILL), baseline(DEFBASE), transparency(transparency), linecap(DEFCAP), linejoin(DEFJOIN), miterlimit(DEFMITER), overwrite(DEFWRITE), t(nullTransform) {} pen(setlinecap_t, Int linecap) : line(), linewidth(DEFWIDTH), P(nullpath), font(""), fontsize(0.0), lineskip(0.0), color(DEFCOLOR), r(0), g(0), b(0), grey(0), pattern(DEFPAT), fillrule(DEFFILL), baseline(DEFBASE), transparency(), linecap(linecap), linejoin(DEFJOIN), miterlimit(DEFMITER), overwrite(DEFWRITE), t(nullTransform) {} pen(setlinejoin_t, Int linejoin) : line(), linewidth(DEFWIDTH), P(nullpath), font(""), fontsize(0.0), lineskip(0.0), color(DEFCOLOR), r(0), g(0), b(0), grey(0), pattern(DEFPAT), fillrule(DEFFILL), baseline(DEFBASE), transparency(), linecap(DEFCAP), linejoin(linejoin), miterlimit(DEFMITER), overwrite(DEFWRITE), t(nullTransform) {} pen(setmiterlimit_t, double miterlimit) : line(), linewidth(DEFWIDTH), P(nullpath), font(""), fontsize(0.0), lineskip(0.0), color(DEFCOLOR), r(0), g(0), b(0), grey(0), pattern(DEFPAT), fillrule(DEFFILL), baseline(DEFBASE), transparency(), linecap(DEFCAP), linejoin(DEFJOIN), miterlimit(miterlimit), overwrite(DEFWRITE), t(nullTransform) {} pen(setoverwrite_t, overwrite_t overwrite) : line(), linewidth(DEFWIDTH), P(nullpath), font(""), fontsize(0.0), lineskip(0.0), color(DEFCOLOR), r(0), g(0), b(0), grey(0), pattern(DEFPAT), fillrule(DEFFILL), baseline(DEFBASE), transparency(), linecap(DEFCAP), linejoin(DEFJOIN), miterlimit(DEFMITER), overwrite(overwrite), t(nullTransform) {} explicit pen(double grey) : line(), linewidth(DEFWIDTH), P(nullpath), font(""), fontsize(0.0), lineskip(0.0), color(GRAYSCALE), r(0.0), g(0.0), b(0.0), grey(pos0(grey)), pattern(DEFPAT), fillrule(DEFFILL), baseline(DEFBASE), transparency(), linecap(DEFCAP), linejoin(DEFJOIN), miterlimit(DEFMITER), overwrite(DEFWRITE), t(nullTransform) {greyrange();} pen(double r, double g, double b) : line(), linewidth(DEFWIDTH), P(nullpath), font(""), fontsize(0.0), lineskip(0.0), color(RGB), r(pos0(r)), g(pos0(g)), b(pos0(b)), grey(0.0), pattern(DEFPAT), fillrule(DEFFILL), baseline(DEFBASE), transparency(), linecap(DEFCAP), linejoin(DEFJOIN), miterlimit(DEFMITER), overwrite(DEFWRITE), t(nullTransform) {rgbrange();} pen(double c, double m, double y, double k) : line(), linewidth(DEFWIDTH), P(nullpath), font(""), fontsize(0.0), lineskip(0.0), color(CMYK), r(pos0(c)), g(pos0(m)), b(pos0(y)), grey(pos0(k)), pattern(DEFPAT), fillrule(DEFFILL), baseline(DEFBASE), transparency(), linecap(DEFCAP), linejoin(DEFJOIN), miterlimit(DEFMITER), overwrite(DEFWRITE), t(nullTransform) {cmykrange();} // Construct one pen from another, resolving defaults pen(resolvepen_t, const pen& p) : line(LineType(p.line.pattern,p.line.offset,p.line.scale,p.line.adjust)), linewidth(p.width()), P(p.Path()), font(p.Font()), fontsize(p.size()), lineskip(p.Lineskip()), color(p.colorspace()), r(p.red()), g(p.green()), b(p.blue()), grey(p.gray()), pattern(""), fillrule(p.Fillrule()), baseline(p.Baseline()), transparency(Transparency(p.blend(), p.opacity())), linecap(p.cap()), linejoin(p.join()), miterlimit(p.miter()), overwrite(p.Overwrite()), t(p.getTransform()) {} static pen initialpen() { return pen(LineType(vm::array(0),0.0,true,true),0.5,nullpath,"", 12.0*tex2ps,12.0*1.2*tex2ps,GRAYSCALE, 0.0,0.0,0.0,0.0,"",ZEROWINDING,NOBASEALIGN, Transparency(),1,1,10.0,ALLOW,identity); } pen(initialpen_t) : line(), linewidth(-2.0), P(nullpath), font(""), fontsize(-1.0), lineskip(-1.0), color(INVISIBLE), r(0.0), g(0.0), b(0.0), grey(0.0), pattern(DEFPAT), fillrule(DEFFILL), baseline(NOBASEALIGN), transparency(),linecap(-2), linejoin(-2), miterlimit(-1.0), overwrite(DEFWRITE), t(nullTransform) {} double width() const { return linewidth == DEFWIDTH ? defaultpen().linewidth : linewidth; } path Path() const { return P.empty() ? defaultpen().P : P; } double size() const { return fontsize == 0.0 ? defaultpen().fontsize : fontsize; } string Font() const { if(font.empty()) { if(defaultpen().font.empty()) { string texengine=settings::getSetting("tex"); if(settings::latex(texengine)) return DEFLATEXFONT; else if(texengine == "none") return settings::getSetting("textinitialfont"); else { ostringstream buf; // Work around misalignment in ConTeXt switchtobodyfont if font is not found. if(texengine == "context") buf << "\\switchtobodyfont[" << DEFCONTEXTFONT << "," << size()*ps2tex << "pt]\\removeunwantedspaces%" << newl; else buf << "\\font\\ASYfont=" << DEFTEXFONT << " at " << size()*ps2tex << "pt\\ASYfont"; return buf.str(); } } else return defaultpen().font; } return font; } double Lineskip() const { return lineskip == 0.0 ? defaultpen().lineskip : lineskip; } const LineType *linetype() const { return line.isdefault ? &defaultpen().line : &line; } void adjust(double factor) { if(line.isdefault) line=defaultpen().line; line.Scale(factor); } void setstroke(const vm::array& s) {line.pattern=s;} void setoffset(const double& offset) {line.offset=offset;} string fillpattern() const { return pattern == DEFPAT ? (string)"" : pattern; } FillRule Fillrule() const { return fillrule == DEFFILL ? defaultpen().fillrule : fillrule; } bool evenodd() const { return Fillrule() == EVENODD; } bool inside(Int count) const { return evenodd() ? count % 2 : count != 0; } BaseLine Baseline() const { return baseline == DEFBASE ? defaultpen().baseline : baseline; } Transparency transp() const { return transparency.isdefault ? defaultpen().transparency : transparency; } string blend() const { return transparency.isdefault ? defaultpen().transparency.blend : transparency.blend; } double opacity() const { return transparency.isdefault ? defaultpen().transparency.opacity : transparency.opacity; } Int cap() const { return linecap == DEFCAP ? defaultpen().linecap : linecap; } Int join() const { return linejoin == DEFJOIN ? defaultpen().linejoin : linejoin; } double miter() const { return miterlimit == DEFMITER ? defaultpen().miterlimit : miterlimit; } overwrite_t Overwrite() const { return overwrite == DEFWRITE ? defaultpen().overwrite : overwrite; } ColorSpace colorspace() const { return color == DEFCOLOR ? defaultpen().color : color; } string hex() const { int n=ColorComponents[colorspace()]; ostringstream buf; buf.setf(std::ios::hex,std::ios::basefield); buf.fill('0'); switch(n) { case 0: break; case 1: buf << std::setw(2) << byte(gray()); break; case 3: buf << std::setw(2) << byte(red()) << std::setw(2) << byte(green()) << std::setw(2) << byte(blue()); break; case 4: buf << std::setw(2) << byte(cyan()) << std::setw(2) << byte(magenta()) << std::setw(2) << byte(yellow()) << std::setw(2) << byte(black()); break; default: break; } return buf.str(); } bool invisible() const {return colorspace() == INVISIBLE;} bool grayscale() const {return colorspace() == GRAYSCALE;} bool rgb() const {return colorspace() == RGB;} bool cmyk() const {return colorspace() == CMYK;} double gray() const {return color == DEFCOLOR ? defaultpen().grey : grey;} double red() const {return color == DEFCOLOR ? defaultpen().r : r;} double green() const {return color == DEFCOLOR ? defaultpen().g : g;} double blue() const {return color == DEFCOLOR ? defaultpen().b : b;} double cyan() const {return red();} double magenta() const {return green();} double yellow() const {return blue();} double black() const {return gray();} double rgbsaturation() const {return max(max(r,g),b);} double cmyksaturation() const {return max(rgbsaturation(),black());} void greytorgb() { r=g=b=grey; grey=0.0; color=RGB; } void rgbtogrey() { grey=0.299*r+0.587*g+0.114*b; // Standard YUV luminosity coefficients r=g=b=0.0; color=GRAYSCALE; } void greytocmyk() { grey=1.0-grey; r=g=b=0.0; color=CMYK; } void rgbtocmyk() { double sat=rgbsaturation(); grey=1.0-sat; if(sat) { double scale=1.0/sat; r=1.0-r*scale; g=1.0-g*scale; b=1.0-b*scale; } color=CMYK; } void cmyktorgb() { double sat=1.0-grey; r=(1.0-r)*sat; g=(1.0-g)*sat; b=(1.0-b)*sat; grey=0.0; color=RGB; } void cmyktogrey() { cmyktorgb(); rgbtogrey(); } void togrey() { if(rgb()) rgbtogrey(); else if(cmyk()) cmyktogrey(); } void torgb() { if(cmyk()) cmyktorgb(); else if(grayscale()) greytorgb(); } void tocmyk() { if(rgb()) rgbtocmyk(); else if(grayscale()) greytocmyk(); } void settransparency(const pen& p) { transparency=p.transparency; } void setfont(const pen& p) { font=p.font; } void setfillrule(const pen& p) { fillrule=p.fillrule; } void convert() { if(settings::gray || settings::bw) { if(rgb()) rgbtogrey(); else if(cmyk()) cmyktogrey(); if(settings::bw) {grey=(grey == 1.0) ? 1.0 : 0.0;} } else if(settings::rgb && cmyk()) cmyktorgb(); else if(settings::cmyk && rgb()) rgbtocmyk(); } // Try to upgrade to the specified colorspace. bool promote(ColorSpace c) { if(color == c) return true; switch(color) { case PATTERN: case INVISIBLE: break; case DEFCOLOR: { return true; break; } break; case GRAYSCALE: { if(c == RGB) {greytorgb(); return true;} else if(c == CMYK) {greytocmyk(); return true;} break; } case RGB: { if(c == CMYK) {rgbtocmyk(); return true;} break; } case CMYK: { break; } } return false; } friend pen operator * (double x, const pen& q) { pen p=q; if(x < 0.0) x = 0.0; switch(p.color) { case PATTERN: case INVISIBLE: case DEFCOLOR: break; case GRAYSCALE: { p.grey *= x; p.greyrange(); break; } case RGB: { p.r *= x; p.g *= x; p.b *= x; p.rgbrange(); break; } case CMYK: { p.r *= x; p.g *= x; p.b *= x; p.grey *= x; p.cmykrange(); break; } } return p; } friend pen operator + (const pen& p, const pen& q) { pen P=p; pen Q=q; if(P.color == PATTERN && P.pattern.empty()) P.color=DEFCOLOR; ColorSpace colorspace=(ColorSpace) max((Int) P.color,(Int) Q.color); if(!(p.transparency.isdefault && q.transparency.isdefault)) P.transparency.opacity=max(p.opacity(),q.opacity()); switch(colorspace) { case PATTERN: case INVISIBLE: case DEFCOLOR: break; case GRAYSCALE: { P.grey += Q.grey; P.greyrange(); break; } case RGB: { if(P.color == GRAYSCALE) P.greytorgb(); else if(Q.color == GRAYSCALE) Q.greytorgb(); P.r += Q.r; P.g += Q.g; P.b += Q.b; P.rgbrange(); break; } case CMYK: { if(P.color == GRAYSCALE) P.greytocmyk(); else if(Q.color == GRAYSCALE) Q.greytocmyk(); if(P.color == RGB) P.rgbtocmyk(); else if(Q.color == RGB) Q.rgbtocmyk(); P.r += Q.r; P.g += Q.g; P.b += Q.b; P.grey += Q.grey; P.cmykrange(); break; } } return pen(q.line.isdefault ? p.line : q.line, q.linewidth == DEFWIDTH ? p.linewidth : q.linewidth, q.P.empty() ? p.P : q.P, q.font.empty() ? p.font : q.font, q.fontsize == 0.0 ? p.fontsize : q.fontsize, q.lineskip == 0.0 ? p.lineskip : q.lineskip, colorspace,P.r,P.g,P.b,P.grey, q.pattern == DEFPAT ? p.pattern : q.pattern, q.fillrule == DEFFILL ? p.fillrule : q.fillrule, q.baseline == DEFBASE ? p.baseline : q.baseline, q.transparency.isdefault ? p.transparency : q.transparency, q.linecap == DEFCAP ? p.linecap : q.linecap, q.linejoin == DEFJOIN ? p.linejoin : q.linejoin, q.miterlimit == DEFMITER ? p.miterlimit : q.miterlimit, q.overwrite == DEFWRITE ? p.overwrite : q.overwrite, q.t.isNull() ? p.t : q.t); } friend pen interpolate(const pen& p, const pen& q, double t) { pen P=p; pen Q=q; if(P.color == PATTERN && P.pattern.empty()) P.color=DEFCOLOR; ColorSpace colorspace=(ColorSpace) max((Int) P.color,(Int) Q.color); switch(colorspace) { case PATTERN: case INVISIBLE: case DEFCOLOR: case GRAYSCALE: break; case RGB: { if(P.color == GRAYSCALE) P.greytorgb(); else if(Q.color == GRAYSCALE) Q.greytorgb(); break; } case CMYK: { if(P.color == GRAYSCALE) P.greytocmyk(); else if(Q.color == GRAYSCALE) Q.greytocmyk(); if(P.color == RGB) P.rgbtocmyk(); else if(Q.color == RGB) Q.rgbtocmyk(); break; } } return (1-t)*P+t*Q; } friend bool operator == (const pen& p, const pen& q) { return *(p.linetype()) == *(q.linetype()) && p.width() == q.width() && p.Path() == q.Path() && p.Font() == q.Font() && p.Lineskip() == q.Lineskip() && p.size() == q.size() && p.colorspace() == q.colorspace() && (!(p.grayscale() || p.cmyk()) || p.gray() == q.gray()) && (!(p.rgb() || p.cmyk()) || (p.red() == q.red() && p.green() == q.green() && p.blue() == q.blue())) && p.pattern == q.pattern && p.Fillrule() == q.Fillrule() && p.Baseline() == q.Baseline() && p.transp() == q.transp() && p.cap() == q.cap() && p.join() == q.join() && p.miter() == q.miter() && p.Overwrite() == q.Overwrite() && p.t == q.t; } friend bool operator != (const pen& p, const pen& q) { return !(p == q); } friend ostream& operator << (ostream& out, const pen& p) { out << "("; if(p.line.isdefault) out << "default"; else out << p.line.pattern; if(p.line.offset) out << p.line.offset; if(!p.line.scale) out << " bp"; if(!p.line.adjust) out << " fixed"; if(p.linewidth != DEFWIDTH) out << ", linewidth=" << p.linewidth; if(!p.P.empty()) out << ", path=" << p.P; if(p.linecap != DEFCAP) out << ", linecap=" << Cap[p.linecap]; if(p.linejoin != DEFJOIN) out << ", linejoin=" << Join[p.linejoin]; if(p.miterlimit != DEFMITER) out << ", miterlimit=" << p.miterlimit; if(!p.font.empty()) out << ", font=\"" << p.font << "\""; if(p.fontsize) out << ", fontsize=" << p.fontsize; if(p.lineskip) out << ", lineskip=" << p.lineskip; if(p.color == INVISIBLE) out << ", invisible"; else if(p.color == GRAYSCALE) out << ", gray=" << p.grey; else if(p.color == RGB) out << ", red=" << p.red() << ", green=" << p.green() << ", blue=" << p.blue(); else if(p.color == CMYK) out << ", cyan=" << p.cyan() << ", magenta=" << p.magenta() << ", yellow=" << p.yellow() << ", black=" << p.black(); if(p.pattern != DEFPAT) out << ", pattern=" << "\"" << p.pattern << "\""; if(p.fillrule != DEFFILL) out << ", fillrule=" << FillRuleTag[p.fillrule]; if(p.baseline != DEFBASE) out << ", baseline=" << BaseLineTag[p.baseline]; if(!p.transparency.isdefault) { out << ", opacity=" << p.transparency.opacity; out << ", blend=" << p.transparency.blend; } if(p.overwrite != DEFWRITE) out << ", overwrite=" << OverwriteTag[p.overwrite]; if(!p.t.isNull()) out << ", transform=" << p.t; out << ")"; return out; } const transform getTransform() const { return t.isNull() ? defaultpen().t : t; } // The bounds of the circle or ellipse the pen describes. bbox bounds() const { double maxx, maxy; pair shift; if(!P.empty()) return P.bounds(); transform t=getTransform(); if(t.isIdentity()) { maxx = 1; maxy = 1; shift = pair(0,0); } else { double xx = t.getxx(), xy = t.getxy(), yx = t.getyx(), yy = t.getyy(); // These are the maximum x and y values that a linear transform can map // a point in the unit circle. This can be proven by the Lagrange // Multiplier theorem or by properties of the dot product. maxx = length(pair(xx,xy)); maxy = length(pair(yx,yy)); shift = t*pair(0,0); } bbox b; pair z=0.5*width()*pair(maxx,maxy); b += z + shift; b += -z + shift; return b; } friend pen transformed(const transform& t, const pen& p) { pen ret = p; if(!p.P.empty()) ret.P = p.P.transformed(t); ret.t = p.t.isNull() ? t : t*p.t; return ret; } }; pen transformed(const transform& t, const pen &p); } #endif asymptote-2.37/picture.cc000066400000000000000000001072011265434602500154640ustar00rootroot00000000000000/***** * picture.cc * Andy Hammerlindl 2002/06/06 * * Stores a picture as a list of drawElements and handles its output to * PostScript. *****/ #include "errormsg.h" #include "picture.h" #include "util.h" #include "settings.h" #include "interact.h" #include "drawverbatim.h" #include "drawlabel.h" #include "drawlayer.h" using std::ifstream; using std::ofstream; using vm::array; using namespace settings; using namespace gl; texstream::~texstream() { string texengine=getSetting("tex"); bool context=settings::context(texengine); string name; if(!context) name=stripFile(outname()); name += "texput."; unlink((name+"aux").c_str()); unlink((name+"log").c_str()); unlink((name+"out").c_str()); unlink((name+"m9").c_str()); if(settings::pdf(texengine)) unlink((name+"pdf").c_str()); if(context) { unlink((name+"tex").c_str()); unlink((name+"top").c_str()); unlink((name+"tua").c_str()); unlink((name+"tui").c_str()); } } namespace camp { bool isIdTransform3(const double* t) { return (t == NULL || (t[0]==1 && t[1]==0 && t[2]==0 && t[3]==0 && t[4]==0 && t[5]==1 && t[6]==0 && t[7]==0 && t[8]==0 && t[9]==0 && t[10]==1 && t[11]==0 && t[12]==0 && t[13]==0 && t[14]==0 && t[15]==1)); } // copy array to 4x4 transform matrix with range checks void copyArray4x4C(double*& dest, const vm::array *a) { double tt[16]; const size_t n=checkArray(a); const string fourbyfour="4x4 array of doubles expected"; if(n != 4) reportError(fourbyfour); for(size_t i=0; i < 4; i++) { const vm::array *ai=vm::read(a,i); const size_t aisize=checkArray(ai); double *tti=tt+4*i; if(aisize == 4) { for(size_t j=0; j < 4; j++) tti[j]=vm::read(ai,j); } else reportError(fourbyfour); } copyTransform3(dest,tt); } void copyTransform3(double*& d, const double* s, GCPlacement placement) { if(s != NULL) { if(d == NULL) d=placement == NoGC ? new double[16] : new(placement) double[16]; memcpy(d,s,sizeof(double)*16); } } // t = s*r void multiplyTransform3(double*& t, const double* s, const double* r) { if(isIdTransform3(s)) { copyTransform3(t,r); } else if(isIdTransform3(r)) { copyTransform3(t,s); } else { t=new(UseGC) double[16]; for(size_t i=0; i < 4; i++) { size_t i4=4*i; const double *si=s+i4; const double& s0=si[0]; const double& s1=si[1]; const double& s2=si[2]; const double& s3=si[3]; double *ti=t+i4; ti[0]=s0*r[0]+s1*r[4]+s2*r[8]+s3*r[12]; ti[1]=s0*r[1]+s1*r[5]+s2*r[9]+s3*r[13]; ti[2]=s0*r[2]+s1*r[6]+s2*r[10]+s3*r[14]; ti[3]=s0*r[3]+s1*r[7]+s2*r[11]+s3*r[15]; } } } void boundstriples(double& x, double& y, double& z, double& X, double& Y, double& Z, size_t n, const triple* v) { if(n == 0 || v == NULL) return; X=x=v[0].getx(); Y=y=v[0].gety(); Z=z=v[0].getz(); for(size_t i=1; i < n; ++i) { const triple vi=v[i]; const double vx=vi.getx(); x=min(x,vx); X=max(X,vx); const double vy=vi.gety(); y=min(y,vy); Y=max(Y,vy); const double vz=vi.getz(); z=min(z,vz); Z=max(Z,vz); } } double xratio(const triple& v) {return v.getx()/v.getz();} double yratio(const triple& v) {return v.gety()/v.getz();} class matrixstack { mem::stack mstack; public: // return current transform const double* T() const { if(mstack.empty()) return NULL; else return mstack.top(); } // we store the accumulated transform of all pushed transforms void push(const double *r) { double* T3 = NULL; multiplyTransform3(T3,T(),r); mstack.push(T3); } void pop() { if(!mstack.empty()) mstack.pop(); } }; const char *texpathmessage() { ostringstream buf; buf << "the directory containing your " << getSetting("tex") << " engine (" << texcommand() << ")"; return Strdup(buf.str()); } picture::~picture() { } void picture::enclose(drawElement *begin, drawElement *end) { assert(begin); assert(end); nodes.push_front(begin); lastnumber=0; lastnumber3=0; for(nodelist::iterator p=nodes.begin(); p != nodes.end(); ++p) { assert(*p); if((*p)->islayer()) { nodes.insert(p,end); ++p; while(p != nodes.end() && (*p)->islayer()) ++p; if(p == nodes.end()) return; nodes.insert(p,begin); } } nodes.push_back(end); } // Insert at beginning of picture. void picture::prepend(drawElement *p) { assert(p); nodes.push_front(p); lastnumber=0; lastnumber3=0; } void picture::append(drawElement *p) { assert(p); nodes.push_back(p); } void picture::add(picture &pic) { if (&pic == this) return; // STL's funny way of copying one list into another. copy(pic.nodes.begin(), pic.nodes.end(), back_inserter(nodes)); } // Insert picture pic at beginning of picture. void picture::prepend(picture &pic) { if (&pic == this) return; copy(pic.nodes.begin(), pic.nodes.end(), inserter(nodes, nodes.begin())); lastnumber=0; lastnumber3=0; } bool picture::havelabels() { size_t n=nodes.size(); if(n > lastnumber && !labels && getSetting("tex") != "none") { // Check to see if there are any labels yet nodelist::iterator p=nodes.begin(); for(size_t i=0; i < lastnumber; ++i) ++p; for(; p != nodes.end(); ++p) { assert(*p); if((*p)->islabel()) { labels=true; break; } } } return labels; } bool picture::have3D() { for(nodelist::iterator p=nodes.begin(); p != nodes.end(); ++p) { assert(*p); if((*p)->is3D()) return true; } return false; } bbox picture::bounds() { size_t n=nodes.size(); if(n == lastnumber) return b_cached; if(lastnumber == 0) { // Maybe these should be put into a structure. b_cached=bbox(); labelbounds.clear(); bboxstack.clear(); } if(havelabels()) texinit(); nodelist::iterator p=nodes.begin(); for(size_t i=0; i < lastnumber; ++i) ++p; for(; p != nodes.end(); ++p) { assert(*p); (*p)->bounds(b_cached,processData().tex,labelbounds,bboxstack); // Optimization for interpreters with fixed stack limits. if((*p)->endclip()) { nodelist::iterator q=p; if(q != nodes.begin()) { --q; assert(*q); if((*q)->endclip()) (*q)->save(false); } } } lastnumber=n; return b_cached; } bbox3 picture::bounds3() { size_t n=nodes.size(); if(n == lastnumber3) return b3; if(lastnumber3 == 0) b3=bbox3(); matrixstack ms; size_t i=0; for(nodelist::const_iterator p=nodes.begin(); p != nodes.end(); ++p) { assert(*p); if((*p)->begingroup3()) ms.push((*p)->transf3()); else if((*p)->endgroup3()) ms.pop(); else (*p)->bounds(ms.T(),b3); i++; } lastnumber3=n; return b3; } pair picture::ratio(double (*m)(double, double)) { bool first=true; pair b; bounds3(); double fuzz=sqrtFuzz*(b3.Max()-b3.Min()).length(); matrixstack ms; for(nodelist::const_iterator p=nodes.begin(); p != nodes.end(); ++p) { assert(*p); if((*p)->begingroup3()) ms.push((*p)->transf3()); else if((*p)->endgroup3()) ms.pop(); else (*p)->ratio(ms.T(),b,m,fuzz,first); } return b; } void texinit() { drawElement::lastpen=pen(initialpen); processDataStruct &pd=processData(); // Output any new texpreamble commands if(pd.tex.isopen()) { if(pd.TeXpipepreamble.empty()) return; texpreamble(pd.tex,pd.TeXpipepreamble,false); pd.TeXpipepreamble.clear(); return; } bool context=settings::context(getSetting("tex")); string dir=stripFile(outname()); string logname; if(!context) logname=dir; logname += "texput.log"; const char *cname=logname.c_str(); ofstream writeable(cname); if(!writeable) reportError("Cannot write to "+logname); else writeable.close(); unlink(cname); mem::vector cmd; cmd.push_back(texprogram()); if(context) { cmd.push_back("--pipe"); } else { if(!dir.empty()) cmd.push_back("-output-directory="+dir.substr(0,dir.length()-1)); if(getSetting("inlineimage") || getSetting("inlinetex")) { string name=stripDir(stripExt((outname()))); size_t pos=name.rfind("-"); if(pos < string::npos) { name=stripExt(name).substr(0,pos); unlink((name+".aux").c_str()); cmd.push_back("-jobname="+name.substr(0,pos)); #ifdef __MSDOS__ cmd.push_back("NUL"); // For MikTeX #endif } } cmd.push_back("\\scrollmode"); } pd.tex.open(cmd,"texpath",texpathmessage()); pd.tex.wait("\n*"); pd.tex << "\n"; texdocumentclass(pd.tex,true); texdefines(pd.tex,pd.TeXpreamble,true); pd.TeXpipepreamble.clear(); } int opentex(const string& texname, const string& prefix, bool dvi) { string aux=auxname(prefix,"aux"); unlink(aux.c_str()); bool context=settings::context(getSetting("tex")); mem::vector cmd; cmd.push_back(texprogram()); if(dvi) cmd.push_back("-output-format=dvi"); if(context) { cmd.push_back("--nonstopmode"); cmd.push_back(texname); } else { string dir=stripFile(texname); if(!dir.empty()) cmd.push_back("-output-directory="+dir.substr(0,dir.length()-1)); cmd.push_back("\\nonstopmode\\input"); cmd.push_back(stripDir(texname)); } bool quiet=verbose <= 1; int status=System(cmd,quiet ? 1 : 0,true,"texpath",texpathmessage()); if(!status && getSetting("twice")) status=System(cmd,quiet ? 1 : 0,true,"texpath",texpathmessage()); if(status) { if(quiet) { cmd[1]=context ? "--scrollmode" : "\\scrollmode\\input"; System(cmd,0); } } return status; } bool picture::texprocess(const string& texname, const string& outname, const string& prefix, const pair& bboxshift, bool svgformat) { int status=1; ifstream outfile; outfile.open(texname.c_str()); bool keep=getSetting("keep"); if(outfile) { outfile.close(); status=opentex(texname,prefix); string texengine=getSetting("tex"); if(status == 0) { string dviname=auxname(prefix,"dvi"); mem::vector cmd; if(svgformat) { cmd.push_back(getSetting("dvisvgm")); cmd.push_back("-n"); cmd.push_back("--verbosity=3"); string libgs=getSetting("libgs"); if(!libgs.empty()) cmd.push_back("--libgs="+libgs); push_split(cmd,getSetting("dvisvgmOptions")); cmd.push_back("-o"+outname); ostringstream buf; bbox B=b; B.shift(bboxshift+pair(1.99*cm,1.9*cm)); buf << "--bbox=" << B.left << "bp " << B.bottom << "bp " << B.right << "bp " << B.top << "bp"; cmd.push_back(buf.str()); cmd.push_back(dviname); status=System(cmd,0,true,"dvisvgm"); if(!keep) unlink(dviname.c_str()); } else { if(!settings::pdf(texengine)) { string psname=auxname(prefix,"ps"); double height=b.top-b.bottom+1.0; // Magic dvips offsets: double hoffset=-128.4; double vertical=height; if(!latex(texengine)) vertical += 2.0; double voffset=(vertical < 13.0) ? -137.8+vertical : -124.8; double paperHeight=getSetting("paperheight"); hoffset += b.left+bboxshift.getx(); voffset += paperHeight-height-b.bottom-bboxshift.gety(); string dvipsrc=getSetting("dir"); if(dvipsrc.empty()) dvipsrc=systemDir; dvipsrc += dirsep+"nopapersize.ps"; setenv("DVIPSRC",dvipsrc.c_str(),1); string papertype=getSetting("papertype") == "letter" ? "letterSize" : "a4size"; cmd.push_back(getSetting("dvips")); cmd.push_back("-R"); cmd.push_back("-Pdownload35"); cmd.push_back("-D600"); cmd.push_back("-O"+String(hoffset)+"bp,"+String(voffset)+"bp"); cmd.push_back("-T"+String(getSetting("paperwidth"))+"bp,"+ String(paperHeight)+"bp"); push_split(cmd,getSetting("dvipsOptions")); if(getSetting("papertype") != "") cmd.push_back("-t"+papertype); if(verbose <= 1) cmd.push_back("-q"); cmd.push_back("-o"+psname); cmd.push_back(dviname); status=System(cmd,0,true,"dvips"); if(status == 0) { ifstream fin(psname.c_str()); psfile fout(outname,false); string s; bool first=true; transform t=shift(bboxshift)*T; bool shift=!t.isIdentity(); const string beginspecial="TeXDict begin @defspecial"; const size_t beginlength=beginspecial.size(); const string endspecial="@fedspecial end"; const size_t endlength=endspecial.size(); while(getline(fin,s)) { if (s[0] == '%') { if (s.find("%%DocumentPaperSizes:") == 0) continue; if(s.find("%!PS-Adobe-") == 0) { fout.header(); continue; } if (first && s.find("%%BoundingBox:") == 0) { bbox box=b; box.shift(bboxshift); if(verbose > 2) BoundingBox(cout,box); fout.BoundingBox(box); first=false; continue; } } if (shift) { if (s.compare(0, beginlength, beginspecial) == 0) { fout.verbatimline(s); fout.gsave(); fout.concat(t); continue; } if (s.compare(0, endlength, endspecial) == 0) { fout.grestore(); fout.verbatimline(s); continue; } } // For the default line, output it unchanged. fout.verbatimline(s); } } if(!keep) { unlink(dviname.c_str()); unlink(psname.c_str()); } } } } if(!keep) { unlink(texname.c_str()); if(!getSetting("keepaux")) unlink(auxname(prefix,"aux").c_str()); unlink(auxname(prefix,"log").c_str()); unlink(auxname(prefix,"out").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()); unlink(auxname(prefix,"tuo").c_str()); } } if(status == 0) return true; } return false; } int picture::epstopdf(const string& epsname, const string& pdfname) { mem::vector cmd; cmd.push_back(getSetting("gs")); cmd.push_back("-q"); cmd.push_back("-dNOPAUSE"); cmd.push_back("-dBATCH"); cmd.push_back("-P"); if(safe) cmd.push_back("-dSAFER"); cmd.push_back("-sDEVICE=pdfwrite"); cmd.push_back("-dEPSCrop"); cmd.push_back("-dSubsetFonts=true"); cmd.push_back("-dEmbedAllFonts=true"); cmd.push_back("-dMaxSubsetPct=100"); cmd.push_back("-dPDFSETTINGS=/prepress"); cmd.push_back("-dCompatibilityLevel=1.4"); if(!getSetting("autorotate")) cmd.push_back("-dAutoRotatePages=/None"); cmd.push_back("-g"+String(max(ceil(getSetting("paperwidth")),1.0)) +"x"+String(max(ceil(getSetting("paperheight")),1.0))); cmd.push_back("-dDEVICEWIDTHPOINTS="+String(max(b.right-b.left,3.0))); cmd.push_back("-dDEVICEHEIGHTPOINTS="+String(max(b.top-b.bottom,3.0))); push_split(cmd,getSetting("gsOptions")); cmd.push_back("-sOutputFile="+stripDir(pdfname)); cmd.push_back(stripDir(epsname)); char *oldPath=NULL; string dir=stripFile(pdfname); if(!dir.empty()) { oldPath=getPath(); setPath(dir.c_str()); } int status=System(cmd,0,true,"gs","Ghostscript"); if(oldPath != NULL) setPath(oldPath); return status; } bool picture::reloadPDF(const string& Viewer, const string& outname) const { static bool needReload=true; static bool haveReload=false; // Send javascript code to redraw picture. picture f; string name=getPath()+string("/")+outname; f.append(new drawVerbatim(TeX,"\\ \\pdfannot width 0pt height 0pt { /AA << /PO << /S /JavaScript /JS (try{reload('"+ name+"');} catch(e) {} closeDoc(this);) >> >> }")); string reloadprefix="reload"; if(needReload) { needReload=false; string texengine=getSetting("tex"); Setting("tex")=string("pdflatex"); haveReload=f.shipout(NULL,reloadprefix,"pdf",0.0,false,false); Setting("tex")=texengine; } if(haveReload) { mem::vector cmd; push_command(cmd,Viewer); string pdfreloadOptions=getSetting("pdfreloadOptions"); if(!pdfreloadOptions.empty()) cmd.push_back(pdfreloadOptions); cmd.push_back(reloadprefix+".pdf"); System(cmd,0,false); } return true; } bool picture::postprocess(const string& prename, const string& outname, const string& outputformat, double magnification, bool wait, bool view, bool pdftex, bool svgformat) { static mem::map pids; int status=0; bool epsformat=outputformat == "eps"; bool pdfformat=(settings::pdf(getSetting("tex")) && outputformat == "") || outputformat == "pdf"; if(pdftex || !epsformat) { if(pdfformat) { if(pdftex) { status=rename(prename.c_str(),outname.c_str()); if(status != 0) reportError("Cannot rename "+prename+" to "+outname); } else status=epstopdf(prename,outname); } else { mem::vector cmd; double render=fabs(getSetting("render")); if(render == 0) render=1.0; double res=render*72.0; Int antialias=getSetting("antialias"); if(outputformat == "png" && antialias == 2) { cmd.push_back(getSetting("gs")); cmd.push_back("-q"); cmd.push_back("-dNOPAUSE"); cmd.push_back("-dBATCH"); cmd.push_back("-sDEVICE=pngalpha"); cmd.push_back("-dEPSCrop"); if(safe) cmd.push_back("-dSAFER"); cmd.push_back("-r"+String(res)+"x"+String(res)); push_split(cmd,getSetting("gsOptions")); cmd.push_back("-sOutputFile="+outname); cmd.push_back(prename); status=System(cmd,0,true,"gs","Ghostscript"); } else if(!svgformat) { double expand=antialias; if(expand < 2.0) expand=1.0; res *= expand; cmd.push_back(getSetting("convert")); cmd.push_back("-density"); cmd.push_back(String(res)+"x"+String(res)); if(expand == 1.0) cmd.push_back("+antialias"); push_split(cmd,getSetting("convertOptions")); cmd.push_back("-geometry"); cmd.push_back(String(100.0/expand)+"%x"); cmd.push_back(nativeformat()+":"+prename); cmd.push_back(outputformat+":"+outname); status=System(cmd,0,true,"convert"); } } if(!getSetting("keep")) unlink(prename.c_str()); } if(status != 0) return false; if(verbose > 0) cout << "Wrote " << outname << endl; bool View=settings::view() && view; if(View) { if(epsformat || pdfformat) { // Check to see if there is an existing viewer for this outname. mem::map::iterator p=pids.find(outname); bool running=(p != pids.end()); string Viewer=pdfformat ? getSetting("pdfviewer") : getSetting("psviewer"); int pid; if(running) { pid=p->second; if(pid) running=(waitpid(pid, &status, WNOHANG) != pid); } bool pdfreload=pdfformat && getSetting("pdfreload"); if(running) { // Tell gv/acroread to reread file. if(Viewer == "gv") kill(pid,SIGHUP); else if(pdfreload) reloadPDF(Viewer,outname); } else { mem::vector cmd; push_command(cmd,Viewer); string viewerOptions=getSetting(pdfformat ? "pdfviewerOptions" : "psviewerOptions"); if(!viewerOptions.empty()) push_split(cmd,viewerOptions); cmd.push_back(outname); status=System(cmd,0,wait, pdfformat ? "pdfviewer" : "psviewer", pdfformat ? "your PDF viewer" : "your PostScript viewer", &pid); if(status != 0) return false; if(!wait) pids[outname]=pid; if(pdfreload) { // Work around race conditions in acroread initialization script usleep(getSetting("pdfreloaddelay")); // Only reload if pdf viewer process is already running. if(waitpid(pid, &status, WNOHANG) == pid) reloadPDF(Viewer,outname); } } } else { mem::vector cmd; push_command(cmd,getSetting("display")); cmd.push_back(outname); string application="your "+outputformat+" viewer"; status=System(cmd,0,wait,"display",application.c_str()); if(status != 0) return false; } } return true; } string Outname(const string& prefix, const string& outputformat, bool standardout) { return standardout ? "-" : buildname(prefix,outputformat,""); } bool picture::shipout(picture *preamble, const string& Prefix, const string& format, double magnification, bool wait, bool view) { b=bounds(); string texengine=getSetting("tex"); bool usetex=texengine != "none"; bool TeXmode=getSetting("inlinetex") && usetex; bool pdf=settings::pdf(texengine); bool standardout=Prefix == "-"; string prefix=standardout ? standardprefix : Prefix; string preformat=nativeformat(); string outputformat=format.empty() ? defaultformat() : format; bool epsformat=outputformat == "eps"; bool pdfformat=pdf || outputformat == "pdf"; bool svgformat=outputformat == "svg" && !pdf && usetex && (!have3D() || getSetting("render") == 0.0); bool xobject=magnification > 0; string outname=Outname(prefix,outputformat,standardout); string epsname=epsformat ? (standardout ? "" : outname) : auxname(prefix,"eps"); bool Labels=labels || TeXmode; if(b.empty && !Labels) { // Output a null file bbox b; b.left=b.bottom=0; b.right=b.top=xobject ? 18 : 1; psfile out(epsname,false); out.prologue(b); out.epilogue(); out.close(); return postprocess(epsname,outname,outputformat,1.0,wait,view,false,false); } Labels |= svgformat; if(Labels) prefix=cleanpath(prefix); string prename=((epsformat && !pdf) || !Labels) ? epsname : auxname(prefix,preformat); if(xobject) { double fuzz=0.5/magnification; b.top += fuzz; b.right += fuzz; b.bottom -= fuzz; } SetPageDimensions(); pair aligndir=getSetting("aligndir"); string origin=getSetting("align"); pair bboxshift=(origin == "Z" && epsformat) ? pair(0.0,0.0) : pair(-b.left,-b.bottom); if(epsformat) { bboxshift += getSetting("offset"); double yexcess=max(getSetting("paperheight")- (b.top-b.bottom+1.0),0.0); double xexcess=max(getSetting("paperwidth")- (b.right-b.left+1.0),0.0); if(aligndir == pair(0,0)) { if(origin != "Z" && origin != "B") { if(origin == "T") bboxshift += pair(0.0,yexcess); else bboxshift += pair(0.5*xexcess,0.5*yexcess); } } else { double scale=max(fabs(aligndir.getx()),fabs(aligndir.gety())); if(scale != 0) aligndir *= 0.5/scale; bboxshift += pair((aligndir.getx()+0.5)*xexcess,(aligndir.gety()+0.5)*yexcess); } } bool status=true; string texname; texfile *tex=NULL; if(Labels) { texname=TeXmode ? buildname(prefix,"tex") : auxname(prefix,"tex"); tex=svgformat ? new svgtexfile(texname,b) : new texfile(texname,b); tex->prologue(); } nodelist::iterator layerp=nodes.begin(); nodelist::iterator p=layerp; unsigned layer=0; mem::list files; bbox bshift=b; transparency=false; int svgcount=0; typedef mem::list clipstack; clipstack begin; while(p != nodes.end()) { string psname,pdfname; if(Labels) { ostringstream buf; buf << prefix << "_" << layer; psname=buildname(buf.str(),"eps"); if(pdf) pdfname=buildname(buf.str(),"pdf"); } else { psname=epsname; bshift.shift(bboxshift); } files.push_back(psname); if(pdf) files.push_back(pdfname); psfile out(psname,pdfformat); out.prologue(bshift); if(!Labels) { out.gsave(); out.translate(bboxshift); } if(preamble) { // Postscript preamble. nodelist Nodes=preamble->nodes; nodelist::iterator P=Nodes.begin(); if(P != Nodes.end()) { out.resetpen(); for(; P != Nodes.end(); ++P) { assert(*P); (*P)->draw(&out); } } } out.resetpen(); bool postscript=false; drawLabel *L=NULL; if(svgformat) for(nodelist::const_iterator r=begin.begin(); r != begin.end(); ++r) (*r)->draw(&out); for(; p != nodes.end(); ++p) { assert(*p); if(Labels && (*p)->islayer()) break; if(svgformat && (*p)->svg()) { picture *f=(*p)->svgpng() ? new picture : NULL; nodelist::const_iterator q=layerp; for(;;) { if((*q)->beginclip()) begin.push_back(*q); else if((*q)->endclip()) { if(begin.size() < 1) reportError("endclip without matching beginclip"); begin.pop_back(); } if(q == p) break; ++q; } if(f) { for(nodelist::const_iterator r=begin.begin(); r != begin.end(); ++r) f->append(*r); f->append(*(q++)); } while(q != nodes.end() && !(*q)->islayer()) ++q; clipstack end; for(nodelist::const_iterator r=--q;; --r) { if((*r)->beginclip() && end.size() >= 1) end.pop_back(); else if((*r)->endclip()) end.push_back(*r); if(r == p) break; } for(nodelist::reverse_iterator r=end.rbegin(); r != end.rend(); ++r) { (*r)->draw(&out); if(f) f->append(*r); } if(f) { ostringstream buf; buf << prefix << "_" << svgcount; ++svgcount; string pngname=buildname(buf.str(),"png"); f->shipout(preamble,buf.str(),"png",0.0,false,false); pair m=f->bounds().Min(); pair M=f->bounds().Max(); delete f; pair size=M-m; ostringstream cmd; cmd << "\\special{dvisvgm:img " << size.getx()*ps2tex << " " << size.gety()*ps2tex << " " << pngname << "}"; static pen P; static pair zero; L=new drawLabel(cmd.str(),"",identity,pair(m.getx(),M.gety()),zero,P); texinit(); L->bounds(b_cached,processData().tex,labelbounds,bboxstack); postscript=true; } break; } else postscript |= (*p)->draw(&out); } if(Labels) { tex->beginlayer(pdf ? pdfname : psname,postscript); } else out.grestore(); out.epilogue(); out.close(); if(out.Transparency()) transparency=true; if(Labels) { tex->resetpen(); if(pdf && !b.empty) { status=(epstopdf(psname,pdfname) == 0); if(!getSetting("keep")) unlink(psname.c_str()); } if(status) { for (p=layerp; p != nodes.end(); ++p) { assert(*p); bool islayer=(*p)->islayer(); if(svgformat && (*p)->svg()) { islayer=true; if((*p)->svgpng()) L->write(tex,b); else (*p)->draw(tex); } else (*p)->write(tex,b); if(islayer) { tex->endlayer(); layerp=++p; layer++; break; } } } } } bool context=settings::context(texengine); if(status) { if(TeXmode) { if(Labels && verbose > 0) cout << "Wrote " << texname << endl; delete tex; } else { if(Labels) { tex->epilogue(); if(context) prefix=stripDir(prefix); status=texprocess(texname,svgformat ? outname : prename,prefix, bboxshift,svgformat); delete tex; if(!getSetting("keep")) { for(mem::list::iterator p=files.begin(); p != files.end(); ++p) unlink(p->c_str()); } } if(status) { if(xobject) { if(pdf || transparency) status=(epstopdf(prename,Outname(prefix,"pdf",standardout)) == 0); } else { if(context) prename=stripDir(prename); status=postprocess(prename,outname,outputformat,magnification,wait, view,pdf && Labels,svgformat); if(pdfformat && !getSetting("keep")) unlink(auxname(prefix,"m9").c_str()); } } } } if(!status) reportError("shipout failed"); return true; } // render viewport with width x height pixels. void picture::render(GLUnurbs *nurb, double size2, const triple& Min, const triple& Max, double perspective, bool lighton, bool transparent) const { for(nodelist::const_iterator p=nodes.begin(); p != nodes.end(); ++p) { assert(*p); (*p)->render(nurb,size2,Min,Max,perspective,lighton,transparent); } } struct Communicate : public gc { string prefix; picture* pic; string format; double width; double height; double angle; double zoom; triple m; triple M; pair shift; double *t; double *background; size_t nlights; triple *lights; double *diffuse; double *ambient; double *specular; bool viewportlighting; bool view; }; Communicate com; void glrenderWrapper() { #ifdef HAVE_GL #ifdef HAVE_PTHREAD wait(initSignal,initLock); endwait(initSignal,initLock); #endif glrender(com.prefix,com.pic,com.format,com.width,com.height,com.angle, com.zoom,com.m,com.M,com.shift,com.t,com.background,com.nlights, com.lights,com.diffuse,com.ambient,com.specular,com.viewportlighting, com.view); #endif } bool picture::shipout3(const string& prefix, const string& format, double width, double height, double angle, double zoom, const triple& m, const triple& M, const pair& shift, double *t, double *background, size_t nlights, triple *lights, double *diffuse, double *ambient, double *specular, bool viewportlighting, bool view) { if(getSetting("interrupt")) return true; #ifndef HAVE_LIBGLUT if(!getSetting("offscreen")) camp::reportError("to support onscreen rendering, please install glut library, run ./configure, and recompile"); #endif #ifndef HAVE_LIBOSMESA if(getSetting("offscreen")) camp::reportError("to support offscreen rendering; please install OSMesa library, run ./configure --enable-offscreen, and recompile"); #endif picture *pic = new picture; matrixstack ms; for(nodelist::const_iterator p=nodes.begin(); p != nodes.end(); ++p) { assert(*p); if((*p)->begingroup3()) ms.push((*p)->transf3()); else if((*p)->endgroup3()) ms.pop(); else pic->append((*p)->transformed(ms.T())); } pic->b3=bbox3(); for(nodelist::iterator p=pic->nodes.begin(); p != pic->nodes.end(); ++p) { assert(*p); (*p)->bounds(pic->b3); } pic->lastnumber3=pic->nodes.size(); for(nodelist::iterator p=pic->nodes.begin(); p != pic->nodes.end(); ++p) { assert(*p); (*p)->displacement(); } const string outputformat=format.empty() ? getSetting("outformat") : format; #ifdef HAVE_GL bool View=settings::view() && view; static int oldpid=0; bool offscreen=getSetting("offscreen"); #ifdef HAVE_PTHREAD bool animating=getSetting("animating"); bool Wait=!interact::interactive || !View || animating; #endif #endif #if defined(HAVE_LIBGLUT) && defined(HAVE_GL) if(glthread && !offscreen) { #ifdef HAVE_PTHREAD if(gl::initialize) { gl::initialize=false; com.prefix=prefix; com.pic=pic; com.format=outputformat; com.width=width; com.height=height; com.angle=angle; com.zoom=zoom; com.m=m; com.M=M; com.shift=shift; com.t=t; com.background=background; com.nlights=nlights; com.lights=lights; com.diffuse=diffuse; com.ambient=ambient; com.specular=specular; com.viewportlighting=viewportlighting; com.view=View; if(Wait) pthread_mutex_lock(&readyLock); wait(initSignal,initLock); endwait(initSignal,initLock); static bool initialize=true; if(initialize) { wait(initSignal,initLock); endwait(initSignal,initLock); initialize=false; } if(Wait) { pthread_cond_wait(&readySignal,&readyLock); pthread_mutex_unlock(&readyLock); } return true; } if(Wait) pthread_mutex_lock(&readyLock); #endif } else { int pid=fork(); if(pid == -1) camp::reportError("Cannot fork process"); if(pid != 0) { oldpid=pid; waitpid(pid,NULL,interact::interactive && View ? WNOHANG : 0); return true; } } #endif #ifdef HAVE_GL glrender(prefix,pic,outputformat,width,height,angle,zoom,m,M,shift,t, background,nlights,lights,diffuse,ambient,specular,viewportlighting, View,oldpid); #ifdef HAVE_PTHREAD if(glthread && !offscreen && Wait) { pthread_cond_wait(&readySignal,&readyLock); pthread_mutex_unlock(&readyLock); } return true; #endif #endif return false; } bool picture::shipout3(const string& prefix) { bounds3(); bool status = true; string prcname=buildname(prefix,"prc"); prcfile prc(prcname); static const double limit=2.5*10.0/INT_MAX; double compressionlimit=max(length(b3.Max()),length(b3.Min()))*limit; groups.push_back(groupmap()); for(nodelist::iterator p=nodes.begin(); p != nodes.end(); ++p) { assert(*p); (*p)->write(&prc,&billboard,compressionlimit,groups); } groups.pop_back(); if(status) status=prc.finish(); if(!status) reportError("shipout3 failed"); if(verbose > 0) cout << "Wrote " << prcname << endl; return true; } picture *picture::transformed(const transform& t) { picture *pic = new picture; nodelist::iterator p; for (p = nodes.begin(); p != nodes.end(); ++p) { assert(*p); pic->append((*p)->transformed(t)); } pic->T=transform(t*T); return pic; } picture *picture::transformed(const array& t) { picture *pic = new picture; double* T=NULL; copyArray4x4C(T,&t); size_t level = 0; for (nodelist::iterator p = nodes.begin(); p != nodes.end(); ++p) { assert(*p); if(level==0) pic->append((*p)->transformed(T)); else pic->append(*p); if((*p)->begingroup3()) level++; if((*p)->endgroup3()) { if(level==0) reportError("endgroup3 without matching begingroup3"); else level--; } } return pic; } } // namespace camp asymptote-2.37/picture.h000066400000000000000000000063351265434602500153340ustar00rootroot00000000000000/***** * picture.h * Andy Hamerlindl 2002/06/06 * * Stores a picture as a list of drawElements and handles its output to * PostScript. *****/ #ifndef PICTURE_H #define PICTURE_H #include #include #include "drawelement.h" namespace camp { class picture : public gc { private: bool labels; size_t lastnumber; size_t lastnumber3; transform T; // Keep track of accumulative picture transform bbox b; bbox b_cached; // Cached bounding box boxvector labelbounds; bboxlist bboxstack; bool transparency; groupsmap groups; unsigned billboard; public: bbox3 b3; // 3D bounding box typedef mem::list nodelist; nodelist nodes; picture() : labels(false), lastnumber(0), lastnumber3(0), T(identity), transparency(false) {} // Destroy all of the owned picture objects. ~picture(); // Prepend an object to the picture. void prepend(drawElement *p); // Append an object to the picture. void append(drawElement *p); // Enclose each layer with begin and end. void enclose(drawElement *begin, drawElement *end); // Add the content of another picture. void add(picture &pic); void prepend(picture &pic); bool havelabels(); bool have3D(); bbox bounds(); bbox3 bounds3(); // Compute bounds on ratio (x,y)/z for 3d picture (not cached). pair ratio(double (*m)(double, double)); bool Transparency() { return transparency; } int epstopdf(const string& epsname, const string& pdfname); bool texprocess(const string& texname, const string& tempname, const string& prefix, const pair& bboxshift, bool svgformat); bool postprocess(const string& prename, const string& outname, const string& outputformat, double magnification, bool wait, bool view, bool pdftex, bool svgformat); // Ship the picture out to PostScript & TeX files. bool shipout(picture* preamble, const string& prefix, const string& format, double magnification=0.0, bool wait=false, bool view=true); void render(GLUnurbs *nurb, double size2, const triple &Min, const triple& Max, double perspective, bool lighton, bool transparent) const; bool shipout3(const string& prefix, const string& format, double width, double height, double angle, double zoom, const triple& m, const triple& M, const pair& shift, double *t, double *background, size_t nlights, triple *lights, double *diffuse, double *ambient, double *specular, bool viewportlighting, bool view); // PRC output bool shipout3(const string& prefix); bool reloadPDF(const string& Viewer, const string& outname) const; picture *transformed(const transform& t); picture *transformed(const vm::array& t); bool null() { return nodes.empty(); } }; inline picture *transformed(const transform& t, picture *p) { return p->transformed(t); } inline picture *transformed(const vm::array& t, picture *p) { return p->transformed(t); } void texinit(); int opentex(const string& texname, const string& prefix, bool dvi=false); const char *texpathmessage(); } //namespace camp #endif asymptote-2.37/pipestream.cc000066400000000000000000000115021265434602500161600ustar00rootroot00000000000000/* Pipestream: A simple C++ interface to UNIX pipes Copyright (C) 2005-2014 John C. Bowman, with contributions from Mojca Miklavec This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include "pipestream.h" #include "common.h" #include "errormsg.h" #include "settings.h" #include "util.h" #include "interact.h" #include "lexical.h" #include "camperror.h" #include "pen.h" void iopipestream::open(const mem::vector &command, const char *hint, const char *application, int out_fileno) { if(pipe(in) == -1) { ostringstream buf; buf << "in pipe failed: "; for(size_t i=0; i < command.size(); ++i) buf << command[i]; camp::reportError(buf); } if(pipe(out) == -1) { ostringstream buf; buf << "out pipe failed: "; for(size_t i=0; i < command.size(); ++i) buf << command[i]; camp::reportError(buf); } cout.flush(); // Flush stdout to avoid duplicate output. if((pid=fork()) < 0) { ostringstream buf; buf << "fork failed: "; for(size_t i=0; i < command.size(); ++i) buf << command[i]; camp::reportError(buf); } if(pid == 0) { if(interact::interactive) signal(SIGINT,SIG_IGN); close(in[1]); close(out[0]); close(STDIN_FILENO); close(out_fileno); dup2(in[0],STDIN_FILENO); dup2(out[1],out_fileno); close(in[0]); close(out[1]); char **argv=args(command); if(argv) execvp(argv[0],argv); execError(argv[0],hint,application); kill(0,SIGTERM); _exit(-1); } close(out[1]); close(in[0]); *buffer=0; pipeopen=true; pipein=true; Running=true; block(false,true); } void iopipestream::eof() { if(pipeopen && pipein) { close(in[1]); pipein=false; } } void iopipestream::pipeclose() { if(pipeopen) { kill(pid,SIGTERM); eof(); close(out[0]); Running=false; pipeopen=false; waitpid(pid,NULL,0); // Avoid zombies. } } void iopipestream::block(bool write, bool read) { if(pipeopen) { int w=fcntl(in[1],F_GETFL); int r=fcntl(out[0],F_GETFL); fcntl(in[1],F_SETFL,write ? w & ~O_NONBLOCK : w | O_NONBLOCK); fcntl(out[0],F_SETFL,read ? r & ~O_NONBLOCK : r | O_NONBLOCK); } } ssize_t iopipestream::readbuffer() { ssize_t nc; char *p=buffer; ssize_t size=BUFSIZE-1; errno=0; for(;;) { if((nc=read(out[0],p,size)) < 0) { if(errno == EAGAIN) {p[0]=0; break;} else camp::reportError("read from pipe failed"); nc=0; } p[nc]=0; if(nc == 0) { if(waitpid(pid,NULL,WNOHANG) == pid) Running=false; break; } if(nc > 0) { if(settings::verbose > 2) cerr << p; break; } } return nc; } bool iopipestream::tailequals(const char *buf, size_t len, const char *prompt, size_t plen) { const char *a=buf+len; const char *b=prompt+plen; while(b >= prompt) { if(a < buf) return false; if(*a != *b) return false; // Handle MSDOS incompatibility: if(a > buf && *a == '\n' && *(a-1) == '\r') --a; --a; --b; } return true; } string iopipestream::readline() { sbuffer.clear(); int nc; do { nc=readbuffer(); sbuffer.append(buffer); } while(buffer[nc-1] != '\n' && Running); return sbuffer; } void iopipestream::wait(const char *prompt) { sbuffer.clear(); size_t plen=strlen(prompt); do { readbuffer(); sbuffer.append(buffer); } while(!tailequals(sbuffer.c_str(),sbuffer.size(),prompt,plen)); } int iopipestream::wait() { for(;;) { int status; if (waitpid(pid,&status,0) == -1) { if (errno == ECHILD) return 0; if (errno != EINTR) { ostringstream buf; buf << "Process " << pid << " failed"; camp::reportError(buf); } } else { if(WIFEXITED(status)) return WEXITSTATUS(status); else { ostringstream buf; buf << "Process " << pid << " exited abnormally"; camp::reportError(buf); } } } } void iopipestream::Write(const string &s) { ssize_t size=s.length(); if(settings::verbose > 2) cerr << s; if(write(in[1],s.c_str(),size) != size) { camp::reportFatal("write to pipe failed"); } } asymptote-2.37/pipestream.h000066400000000000000000000051001265434602500160170ustar00rootroot00000000000000/* Pipestream: A simple C++ interface to UNIX pipes Version 0.05 Copyright (C) 2005-2014 John C. Bowman, with contributions from Mojca Miklavec This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef PIPESTREAM_H #define PIPESTREAM_H #include #include #include #include "common.h" // bidirectional stream for reading and writing to pipes class iopipestream { protected: int in[2]; int out[2]; static const int BUFSIZE=SHRT_MAX; char buffer[BUFSIZE]; string sbuffer; int pid; bool Running; bool pipeopen; bool pipein; public: void open(const mem::vector &command, const char *hint=NULL, const char *application="", int out_fileno=STDOUT_FILENO); bool isopen() {return pipeopen;} iopipestream(): pid(0), pipeopen(false) {} iopipestream(const mem::vector &command, const char *hint=NULL, const char *application="", int out_fileno=STDOUT_FILENO) : pid(0), pipeopen(false) { open(command,hint,application,out_fileno); } void eof(); virtual void pipeclose(); virtual ~iopipestream() { pipeclose(); } void block(bool write=false, bool read=true); ssize_t readbuffer(); string readline(); bool running() {return Running;} typedef iopipestream& (*imanip)(iopipestream&); iopipestream& operator << (imanip func) { return (*func)(*this); } iopipestream& operator >> (string& s) { readbuffer(); s=buffer; return *this; } bool tailequals(const char *buf, size_t len, const char *prompt, size_t plen); string getbuffer() {return sbuffer;} void wait(const char *prompt); int wait(); void Write(const string &s); iopipestream& operator << (const string& s) { Write(s); return *this; } template iopipestream& operator << (T x) { ostringstream os; os << x; Write(os.str()); return *this; } }; #endif asymptote-2.37/policy.h000066400000000000000000000047361265434602500151630ustar00rootroot00000000000000/***** * policy.h * Andy Hammerlindl 2011/09/03 * * Defines a low-level C interface for interacting with the interpreter and * its datatypes. *****/ // TODO: Wrap in namespace. typedef long long int_typ; typedef struct {} handle_base_typ; typedef handle_base_typ *handle_typ; typedef struct {} arguments_base_typ; typedef arguments_base_typ *arguments_typ; typedef struct {} state_base_typ; typedef state_base_typ *state_typ; typedef void (*function_typ)(state_typ, void *); typedef struct { const char *buf; size_t length; } string_typ; typedef void (*error_callback_typ)(string_typ); typedef long arg_rest_option; #define NORMAL_ARG 45000 #define REST_ARG 45001 typedef struct { int_typ version; handle_typ (*copyHandle)(handle_typ handle); void (*releaseHandle)(); handle_typ (*handleFromInt)(int_typ x); // For bool, O is false, 1 is true, and no other value is allowed. handle_typ (*handleFromBool)(int_typ x); handle_typ (*handleFromDouble)(double x); handle_typ (*handleFromString)(string_typ x); handle_typ (*handleFromFunction)(const char *signature, function_typ f, void *data); int_typ (*IntFromHandle)(handle_typ handle); int_typ (*boolFromHandle)(handle_typ handle); double (*doubleFromHandle)(handle_typ handle); // TODO: Note that a pointer and length are returned, but the pointer is // valid for a limited time only. string_typ (*stringFromHandle)(handle_typ handle); #if 0 bool (*handleIsOverloaded)(handle_typ handle); handle_typ (*signatureless)(handle_typ handle); #endif handle_typ (*getField)(handle_typ handle, const char *name); handle_typ (*getCell)(handle_typ handle, handle_typ index); // Adds a field to a datum (possibly a module) and sets it to an initial // value. // TODO: Change name to sig. void (*addField)(handle_typ handle, const char *name, handle_typ init); arguments_typ (*newArguments)(); void (*releaseArguments)(arguments_typ args); void (*addArgument)(arguments_typ args, const char *name, handle_typ handle, arg_rest_option at); handle_typ (*call)(handle_typ callee, arguments_typ args); handle_typ (*globals)(state_typ state); int_typ (*numParams)(state_typ state); handle_typ (*getParam)(state_typ state, int_typ index); void (*setReturnValue)(state_typ state, handle_typ handle); // Allows the user sets an error callback, which is called on any error. void (*setErrorCallback)(error_callback_typ callback); } policy_typ; asymptote-2.37/prc/000077500000000000000000000000001265434602500142655ustar00rootroot00000000000000asymptote-2.37/prc/Makefile000066400000000000000000000017161265434602500157320ustar00rootroot00000000000000# Makefile. CFLAGS = -O3 -g -Wall CXX = g++ MAKEDEPEND = $(CFLAGS) -O0 -M -DDEPEND FILES = PRCbitStream oPRCFile PRCdouble writePRC all: $(FILES:=.o) #test: $(FILES:=.o) test.o # $(CXX) $(CFLAGS) -o test $(FILES:=.o) test.o -lz #test_tess: $(FILES:=.o) test_tess.o # $(CXX) $(CFLAGS) -o test_tess $(FILES:=.o) test_tess.o -lz #test_mesh: $(FILES:=.o) test_mesh.o # $(CXX) $(CFLAGS) -o test_mesh $(FILES:=.o) test_mesh.o -lz .SUFFIXES: .c .cc .o .d .cc.o: $(CXX) $(CFLAGS) $(INCL) -o $@ -c $< .cc.d: @echo Creating $@; \ rm -f $@; \ ${CXX} $(MAKEDEPEND) $(INCL) $(MDOPTS) $< > $@.$$$$ 2>/dev/null && \ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ rm -f $@.$$$$ .c.d: @echo Creating $@; \ rm -f $@; \ ${CC} $(MAKEDEPEND) $(INCL) $(MDOPTS) $< > $@.$$$$ 2>/dev/null && \ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ rm -f $@.$$$$ ifeq (,$(findstring clean,${MAKECMDGOALS})) -include $(FILES:=.d) endif clean: rm -f *.o *.d test test_tess asymptote-2.37/prc/PRC.h000066400000000000000000000730001265434602500150620ustar00rootroot00000000000000#ifndef __PRC_H #define __PRC_H #ifdef _MSC_VER #if _MSC_VER >= 1600 #include #else typedef signed char int8_t; typedef signed short int16_t; typedef signed long int32_t; typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned long uint32_t; #endif // _MSC_VER >= 1600 #else #include #endif // _MSC_VER //const uint32_t PRCVersion=7094; // For Adobe Reader 8 or later const uint32_t PRCVersion=8137; // For Adobe Reader 9 or later // from Adobe's documentation #define PRC_TYPE_Unknown ( (uint32_t)-1 ) #define PRC_TYPE_ROOT 0 // This type does not correspond to any entity #define PRC_TYPE_ROOT_PRCBase ( PRC_TYPE_ROOT + 1 ) // Abstract root type for any PRC entity. #define PRC_TYPE_ROOT_PRCBaseWithGraphics ( PRC_TYPE_ROOT + 2 ) // Abstract root type for any PRC entity which can bear graphics. #define PRC_TYPE_CRV ( PRC_TYPE_ROOT + 10 ) // Types for PRC geometrical curves #define PRC_TYPE_SURF ( PRC_TYPE_ROOT + 75 ) // Types for PRC geometrical surfaces #define PRC_TYPE_TOPO ( PRC_TYPE_ROOT + 140 ) // Types for PRC topology #define PRC_TYPE_TESS ( PRC_TYPE_ROOT + 170 ) // Types for PRC tessellation #define PRC_TYPE_MISC ( PRC_TYPE_ROOT + 200 ) // Types for PRC global data #define PRC_TYPE_RI ( PRC_TYPE_ROOT + 230 ) // Types for PRC representation items #define PRC_TYPE_ASM ( PRC_TYPE_ROOT + 300 ) // Types for PRC assembly #define PRC_TYPE_MKP ( PRC_TYPE_ROOT + 500 ) // Types for PRC markup #define PRC_TYPE_GRAPH ( PRC_TYPE_ROOT + 700 ) // Types for PRC graphics #define PRC_TYPE_MATH ( PRC_TYPE_ROOT + 900 ) // Types for PRC mathematical operators #define PRC_TYPE_CRV_Base ( PRC_TYPE_CRV + 1 ) // Abstract type for all geometric curves. #define PRC_TYPE_CRV_Blend02Boundary ( PRC_TYPE_CRV + 2 ) // Boundary Curve. #define PRC_TYPE_CRV_NURBS ( PRC_TYPE_CRV + 3 ) // Non Uniform BSpline curve. #define PRC_TYPE_CRV_Circle ( PRC_TYPE_CRV + 4 ) // Circle. #define PRC_TYPE_CRV_Composite ( PRC_TYPE_CRV + 5 ) // Array of oriented curves. #define PRC_TYPE_CRV_OnSurf ( PRC_TYPE_CRV + 6 ) // Curve defined by a UV curve on a surface. #define PRC_TYPE_CRV_Ellipse ( PRC_TYPE_CRV + 7 ) // Ellipse. #define PRC_TYPE_CRV_Equation ( PRC_TYPE_CRV + 8 ) // curve described by specific law elements #define PRC_TYPE_CRV_Helix ( PRC_TYPE_CRV + 9 ) // Helix curve. #define PRC_TYPE_CRV_Hyperbola ( PRC_TYPE_CRV + 10 ) // Hyperbola. #define PRC_TYPE_CRV_Intersection ( PRC_TYPE_CRV + 11 ) // Intersection between 2 surfaces. #define PRC_TYPE_CRV_Line ( PRC_TYPE_CRV + 12 ) // Line. #define PRC_TYPE_CRV_Offset ( PRC_TYPE_CRV + 13 ) // Offset curve. #define PRC_TYPE_CRV_Parabola ( PRC_TYPE_CRV + 14 ) // Parabola. #define PRC_TYPE_CRV_PolyLine ( PRC_TYPE_CRV + 15 ) // Polyedric curve. #define PRC_TYPE_CRV_Transform ( PRC_TYPE_CRV + 16 ) // Transformed curve. #define PRC_TYPE_SURF_Base ( PRC_TYPE_SURF + 1 ) // Abstract type for all geometric surfaces. #define PRC_TYPE_SURF_Blend01 ( PRC_TYPE_SURF + 2 ) // Blend surface. #define PRC_TYPE_SURF_Blend02 ( PRC_TYPE_SURF + 3 ) // Blend Surface. #define PRC_TYPE_SURF_Blend03 ( PRC_TYPE_SURF + 4 ) // Blend Surface. #define PRC_TYPE_SURF_NURBS ( PRC_TYPE_SURF + 5 ) // Non Uniform BSpline surface. #define PRC_TYPE_SURF_Cone ( PRC_TYPE_SURF + 6 ) // Cone. #define PRC_TYPE_SURF_Cylinder ( PRC_TYPE_SURF + 7 ) // Cylinder. #define PRC_TYPE_SURF_Cylindrical ( PRC_TYPE_SURF + 8 ) // Surface who is defined in cylindrical space. #define PRC_TYPE_SURF_Offset ( PRC_TYPE_SURF + 9 ) // Offset surface. #define PRC_TYPE_SURF_Pipe ( PRC_TYPE_SURF + 10 ) // Pipe. #define PRC_TYPE_SURF_Plane ( PRC_TYPE_SURF + 11 ) // Plane. #define PRC_TYPE_SURF_Ruled ( PRC_TYPE_SURF + 12 ) // Ruled surface. #define PRC_TYPE_SURF_Sphere ( PRC_TYPE_SURF + 13 ) // Sphere. #define PRC_TYPE_SURF_Revolution ( PRC_TYPE_SURF + 14 ) // Surface of revolution. #define PRC_TYPE_SURF_Extrusion ( PRC_TYPE_SURF + 15 ) // Surface of extrusion. #define PRC_TYPE_SURF_FromCurves ( PRC_TYPE_SURF + 16 ) // Surface from two curves. #define PRC_TYPE_SURF_Torus ( PRC_TYPE_SURF + 17 ) // Torus. #define PRC_TYPE_SURF_Transform ( PRC_TYPE_SURF + 18 ) // Transformed surface. #define PRC_TYPE_SURF_Blend04 ( PRC_TYPE_SURF + 19 ) // defined for future use. #define PRC_TYPE_TOPO_Context ( PRC_TYPE_TOPO + 1 ) // Self-containing set of topological entities. #define PRC_TYPE_TOPO_Item ( PRC_TYPE_TOPO + 2 ) // Abstract root type for any topological entity (body or single item). #define PRC_TYPE_TOPO_MultipleVertex ( PRC_TYPE_TOPO + 3 ) // Vertex whose position is the average of all edges' extremity positions to whom it belongs. #define PRC_TYPE_TOPO_UniqueVertex ( PRC_TYPE_TOPO + 4 ) // Vertex with one set of coordinates (absolute position). #define PRC_TYPE_TOPO_WireEdge ( PRC_TYPE_TOPO + 5 ) // Edge belonging to a wire body / single wire body. #define PRC_TYPE_TOPO_Edge ( PRC_TYPE_TOPO + 6 ) // Edge belonging to a brep data. #define PRC_TYPE_TOPO_CoEdge ( PRC_TYPE_TOPO + 7 ) // Usage of an edge in a loop. #define PRC_TYPE_TOPO_Loop ( PRC_TYPE_TOPO + 8 ) // Array of co edges which delimits a face. #define PRC_TYPE_TOPO_Face ( PRC_TYPE_TOPO + 9 ) // Topological face delimiting a shell. #define PRC_TYPE_TOPO_Shell ( PRC_TYPE_TOPO + 10 ) // Topological shell (open or closed). #define PRC_TYPE_TOPO_Connex ( PRC_TYPE_TOPO + 11 ) // Topological region delimited by one or several shells. #define PRC_TYPE_TOPO_Body ( PRC_TYPE_TOPO + 12 ) // Abstract root type for any topological body. #define PRC_TYPE_TOPO_SingleWireBody ( PRC_TYPE_TOPO + 13 ) // Single wire body. #define PRC_TYPE_TOPO_BrepData ( PRC_TYPE_TOPO + 14 ) // Main entry to solid and surface topology (regular form). #define PRC_TYPE_TOPO_SingleWireBodyCompress ( PRC_TYPE_TOPO + 15 ) // Single wire body. (ultra compressed form). #define PRC_TYPE_TOPO_BrepDataCompress ( PRC_TYPE_TOPO + 16 ) // Main entry to solid and surface topology (ultra compressed form). #define PRC_TYPE_TOPO_WireBody ( PRC_TYPE_TOPO + 17 ) // This type is the main entry to wire topology. #define PRC_TYPE_TESS_Base ( PRC_TYPE_TESS + 1 ) // Abstract root type for any tessellated entity. #define PRC_TYPE_TESS_3D ( PRC_TYPE_TESS + 2 ) // Tessellated faceted data; regular form. #define PRC_TYPE_TESS_3D_Compressed ( PRC_TYPE_TESS + 3 ) // Tessellated faceted data; highly compressed form. #define PRC_TYPE_TESS_Face ( PRC_TYPE_TESS + 4 ) // Tessellated face. #define PRC_TYPE_TESS_3D_Wire ( PRC_TYPE_TESS + 5 ) // Tessellated wireframe. #define PRC_TYPE_TESS_Markup ( PRC_TYPE_TESS + 6 ) // Tessellated markup. #define PRC_TYPE_MISC_Attribute ( PRC_TYPE_MISC + 1 ) // Entity attribute. #define PRC_TYPE_MISC_CartesianTransformation ( PRC_TYPE_MISC + 2 ) // Cartesian transformation. #define PRC_TYPE_MISC_EntityReference ( PRC_TYPE_MISC + 3 ) // Entity reference. #define PRC_TYPE_MISC_MarkupLinkedItem ( PRC_TYPE_MISC + 4 ) // Link between a markup and an entity. #define PRC_TYPE_MISC_ReferenceOnPRCBase ( PRC_TYPE_MISC + 5 ) // Reference pointing on a regular entity (not topological). #define PRC_TYPE_MISC_ReferenceOnTopology ( PRC_TYPE_MISC + 6 ) // Reference pointing on a topological entity. #define PRC_TYPE_MISC_GeneralTransformation ( PRC_TYPE_MISC + 7 ) // General transformation. #define PRC_TYPE_RI_RepresentationItem ( PRC_TYPE_RI + 1 ) // Basic abstract type for representation items. #define PRC_TYPE_RI_BrepModel ( PRC_TYPE_RI + 2 ) // Basic type for surfaces and solids. #define PRC_TYPE_RI_Curve ( PRC_TYPE_RI + 3 ) // Basic type for curves. #define PRC_TYPE_RI_Direction ( PRC_TYPE_RI + 4 ) // Optional point + vector. #define PRC_TYPE_RI_Plane ( PRC_TYPE_RI + 5 ) // Construction plane, as opposed to planar surface. #define PRC_TYPE_RI_PointSet ( PRC_TYPE_RI + 6 ) // Set of points. #define PRC_TYPE_RI_PolyBrepModel ( PRC_TYPE_RI + 7 ) // Basic type to polyhedral surfaces and solids. #define PRC_TYPE_RI_PolyWire ( PRC_TYPE_RI + 8 ) // Polyedric wireframe entity. #define PRC_TYPE_RI_Set ( PRC_TYPE_RI + 9 ) // Logical grouping of arbitrary number of representation items. #define PRC_TYPE_RI_CoordinateSystem ( PRC_TYPE_RI + 10 ) // Coordinate system. #define PRC_TYPE_ASM_ModelFile ( PRC_TYPE_ASM + 1 ) // Basic entry type for PRC. #define PRC_TYPE_ASM_FileStructure ( PRC_TYPE_ASM + 2 ) // Basic structure for PRC files. #define PRC_TYPE_ASM_FileStructureGlobals ( PRC_TYPE_ASM + 3 ) // Basic structure for PRC files : globals. #define PRC_TYPE_ASM_FileStructureTree ( PRC_TYPE_ASM + 4 ) // Basic structure for PRC files : tree. #define PRC_TYPE_ASM_FileStructureTessellation ( PRC_TYPE_ASM + 5 ) // Basic structure for PRC files : tessellation. #define PRC_TYPE_ASM_FileStructureGeometry ( PRC_TYPE_ASM + 6 ) // Basic structure for PRC files : geometry. #define PRC_TYPE_ASM_FileStructureExtraGeometry ( PRC_TYPE_ASM + 7 ) // Basic structure for PRC files : extra geometry data. #define PRC_TYPE_ASM_ProductOccurence ( PRC_TYPE_ASM + 10 ) // Basic contruct for assemblies. #define PRC_TYPE_ASM_PartDefinition ( PRC_TYPE_ASM + 11 ) // Basic construct for parts. #define PRC_TYPE_ASM_Filter ( PRC_TYPE_ASM + 20 ) #define PRC_TYPE_MKP_View ( PRC_TYPE_MKP + 1 ) // Grouping of markup by views. #define PRC_TYPE_MKP_Markup ( PRC_TYPE_MKP + 2 ) // Basic type for simple markups. #define PRC_TYPE_MKP_Leader ( PRC_TYPE_MKP + 3 ) // basic type for markup leader #define PRC_TYPE_MKP_AnnotationItem ( PRC_TYPE_MKP + 4 ) // Usage of a markup. #define PRC_TYPE_MKP_AnnotationSet ( PRC_TYPE_MKP + 5 ) // Group of annotations. #define PRC_TYPE_MKP_AnnotationReference ( PRC_TYPE_MKP + 6 ) // Logical grouping of annotations for reference. #define PRC_TYPE_GRAPH_Style ( PRC_TYPE_GRAPH + 1 ) // Display style. #define PRC_TYPE_GRAPH_Material ( PRC_TYPE_GRAPH + 2 ) // Display material properties. #define PRC_TYPE_GRAPH_Picture ( PRC_TYPE_GRAPH + 3 ) // Picture. #define PRC_TYPE_GRAPH_TextureApplication ( PRC_TYPE_GRAPH + 11 ) // Texture application. #define PRC_TYPE_GRAPH_TextureDefinition ( PRC_TYPE_GRAPH + 12 ) // Texture definition. #define PRC_TYPE_GRAPH_TextureTransformation ( PRC_TYPE_GRAPH + 13 ) // Texture transformation. #define PRC_TYPE_GRAPH_LinePattern ( PRC_TYPE_GRAPH + 21 ) // One dimensional display style. #define PRC_TYPE_GRAPH_FillPattern ( PRC_TYPE_GRAPH + 22 ) // Abstract class for two-dimensional display style. #define PRC_TYPE_GRAPH_DottingPattern ( PRC_TYPE_GRAPH + 23 ) // Two-dimensional filling with dots. #define PRC_TYPE_GRAPH_HatchingPattern ( PRC_TYPE_GRAPH + 24 ) // Two-dimensional filling with hatches. #define PRC_TYPE_GRAPH_SolidPattern ( PRC_TYPE_GRAPH + 25 ) // Two-dimensional filling with particular style (color, material, texture). #define PRC_TYPE_GRAPH_VPicturePattern ( PRC_TYPE_GRAPH + 26 ) // Two-dimensional filling with vectorised picture. #define PRC_TYPE_GRAPH_AmbientLight ( PRC_TYPE_GRAPH + 31 ) // Scene ambient illumination. #define PRC_TYPE_GRAPH_PointLight ( PRC_TYPE_GRAPH + 32 ) // Scene point illumination. #define PRC_TYPE_GRAPH_DirectionalLight ( PRC_TYPE_GRAPH + 33 ) // Scene directional illumination. #define PRC_TYPE_GRAPH_SpotLight ( PRC_TYPE_GRAPH + 34 ) // Scene spot illumination. #define PRC_TYPE_GRAPH_SceneDisplayParameters ( PRC_TYPE_GRAPH + 41 ) // Parameters for scene visualisation. #define PRC_TYPE_GRAPH_Camera ( PRC_TYPE_GRAPH + 42 ) // #define PRC_TYPE_MATH_FCT_1D ( PRC_TYPE_MATH + 1 ) // Basic type for one degree equation object. #define PRC_TYPE_MATH_FCT_1D_Polynom ( PRC_TYPE_MATH_FCT_1D + 1 ) // Polynomial equation. #define PRC_TYPE_MATH_FCT_1D_Trigonometric ( PRC_TYPE_MATH_FCT_1D + 2 ) // Cosinus based equation. #define PRC_TYPE_MATH_FCT_1D_Fraction ( PRC_TYPE_MATH_FCT_1D + 3 ) // Fraction between 2 one degree equation object. #define PRC_TYPE_MATH_FCT_1D_ArctanCos ( PRC_TYPE_MATH_FCT_1D + 4 ) // Specific equation. #define PRC_TYPE_MATH_FCT_1D_Combination ( PRC_TYPE_MATH_FCT_1D + 5 ) // Combination of one degree equation object. #define PRC_TYPE_MATH_FCT_3D ( PRC_TYPE_MATH + 10 ) // Basic type for 3rd degree equation object. #define PRC_TYPE_MATH_FCT_3D_Linear ( PRC_TYPE_MATH_FCT_3D + 1 ) // Linear transformation ( with a matrix ). #define PRC_TYPE_MATH_FCT_3D_NonLinear ( PRC_TYPE_MATH_FCT_3D + 2 ) // Specific transformation. #define PRC_PRODUCT_FLAG_DEFAULT 0x0001 #define PRC_PRODUCT_FLAG_INTERNAL 0x0002 #define PRC_PRODUCT_FLAG_CONTAINER 0x0004 #define PRC_PRODUCT_FLAG_CONFIG 0x0008 #define PRC_PRODUCT_FLAG_VIEW 0x0010 #define PRC_TRANSFORMATION_Identity 0x00 #define PRC_TRANSFORMATION_Translate 0x01 #define PRC_TRANSFORMATION_Rotate 0x02 #define PRC_TRANSFORMATION_Mirror 0x04 #define PRC_TRANSFORMATION_Scale 0x08 #define PRC_TRANSFORMATION_NonUniformScale 0x10 #define PRC_TRANSFORMATION_NonOrtho 0x20 #define PRC_TRANSFORMATION_Homogeneous 0x40 #define PRC_FACETESSDATA_Polyface 0x0001 #define PRC_FACETESSDATA_Triangle 0x0002 #define PRC_FACETESSDATA_TriangleFan 0x0004 #define PRC_FACETESSDATA_TriangleStripe 0x0008 #define PRC_FACETESSDATA_PolyfaceOneNormal 0x0010 #define PRC_FACETESSDATA_TriangleOneNormal 0x0020 #define PRC_FACETESSDATA_TriangleFanOneNormal 0x0040 #define PRC_FACETESSDATA_TriangleStripeOneNormal 0x0080 #define PRC_FACETESSDATA_PolyfaceTextured 0x0100 #define PRC_FACETESSDATA_TriangleTextured 0x0200 #define PRC_FACETESSDATA_TriangleFanTextured 0x0400 #define PRC_FACETESSDATA_TriangleStripeTextured 0x0800 #define PRC_FACETESSDATA_PolyfaceOneNormalTextured 0x1000 #define PRC_FACETESSDATA_TriangleOneNormalTextured 0x2000 #define PRC_FACETESSDATA_TriangleFanOneNormalTextured 0x4000 #define PRC_FACETESSDATA_TriangleStripeOneNormalTextured 0x8000 #define PRC_FACETESSDATA_NORMAL_Single 0x40000000 #define PRC_FACETESSDATA_NORMAL_Mask 0x3FFFFFFF #define PRC_FACETESSDATA_WIRE_IsNotDrawn 0x4000 // Indicates that the edge should not be drawn (its neighbor will be drawn). #define PRC_FACETESSDATA_WIRE_IsClosing 0x8000 // Indicates that this is the last edge of a loop. #define PRC_3DWIRETESSDATA_IsClosing 0x10000000 // Indicates that the first point is implicitely repeated after the last one to close the wire edge. #define PRC_3DWIRETESSDATA_IsContinuous 0x20000000 // Indicates that the last point of the preceding wire should be linked with the first point of the current one. #define PRC_TEXTURE_MAPPING_DIFFUSE 0x0001 // Diffuse texture mapping attribute. Default value. #define PRC_TEXTURE_MAPPING_BUMP 0x0002 // Bump texture mapping attribute. #define PRC_TEXTURE_MAPPING_OPACITY 0x0004 // Opacity texture mapping attribute. #define PRC_TEXTURE_MAPPING_SPHERICAL_REFLECTION 0x0008 // Spherical reflection texture mapping attribute (used for environment mapping). #define PRC_TEXTURE_MAPPING_CUBICAL_REFLECTION 0x0010 // Cubical reflection texture mapping attribute (used for environment mapping). #define PRC_TEXTURE_MAPPING_REFRACTION 0x0020 // Refraction texture mapping attribute. #define PRC_TEXTURE_MAPPING_SPECULAR 0x0040 // Specular texture mapping attribute. #define PRC_TEXTURE_MAPPING_AMBIENT 0x0080 // Ambient texture mapping attribute. #define PRC_TEXTURE_MAPPING_EMISSION 0x0100 // Emission texture mapping attribute. #define PRC_TEXTURE_APPLYING_MODE_NONE 0x00 // let the application choose #define PRC_TEXTURE_APPLYING_MODE_LIGHTING 0x01 // use lighting mode #define PRC_TEXTURE_APPLYING_MODE_ALPHATEST 0x02 // use alpha test #define PRC_TEXTURE_APPLYING_MODE_VERTEXCOLOR 0x04 // combine a texture with one-color-per-vertex mode #define PRC_TEXTURE_MAPPING_COMPONENTS_RED 0x0001 // Red texture mapping component. #define PRC_TEXTURE_MAPPING_COMPONENTS_GREEN 0x0002 // Green texture mapping component. #define PRC_TEXTURE_MAPPING_COMPONENTS_BLUE 0x0004 // Blue texture mapping component. #define PRC_TEXTURE_MAPPING_COMPONENTS_RGB 0x0007 // RGB texture mapping component. #define PRC_TEXTURE_MAPPING_COMPONENTS_ALPHA 0x0008 // Alpha texture mapping component. #define PRC_TEXTURE_MAPPING_COMPONENTS_RGBA 0x000F // RGBA texture mapping component. enum EPRCModellerAttributeType { KEPRCModellerAttributeTypeNull = 0, KEPRCModellerAttributeTypeInt = 1, KEPRCModellerAttributeTypeReal = 2, KEPRCModellerAttributeTypeTime = 3, KEPRCModellerAttributeTypeString = 4 }; enum EPRCPictureDataFormat { KEPRCPicture_PNG, KEPRCPicture_JPG, KEPRCPicture_BITMAP_RGB_BYTE, KEPRCPicture_BITMAP_RGBA_BYTE, KEPRCPicture_BITMAP_GREY_BYTE, KEPRCPicture_BITMAP_GREYA_BYTE }; enum EPRCProductLoadStatus { KEPRCProductLoadStatus_Unknown = 0, KEPRCProductLoadStatus_Error, KEPRCProductLoadStatus_NotLoaded, KEPRCProductLoadStatus_NotLoadable, KEPRCProductLoadStatus_Loaded }; enum EPRCExtendType { KEPRCExtendTypeNone = 0, // Discontinuous position. KEPRCExtendTypeExt1 = 2, // Same as EPRCExtendTypeCInfinity. KEPRCExtendTypeExt2 = 4, // Same as EPRCExtendTypeG1R for surface, and EPRCExtendTypeG1 for curve. KEPRCExtendTypeG1 = 6, // Continuous in direction but not magnitude of first derivative. KEPRCExtendTypeG1R = 8, // Surface extended with a ruled surface that connects with G1-continuity. KEPRCExtendTypeG1_G2 = 10, // Extended by reflection, yielding a G2 continuous extension. KEPRCExtendTypeCInfinity = 12 // Unlimited continuity. }; enum EPRCKnotType { // Knot vector type KEPRCKnotTypeUniformKnots, // Uniform knot vector. KEPRCKnotTypeUnspecified, // Unspecified knot type. KEPRCKnotTypeQuasiUniformKnots, // Quasi-uniform knot vector. KEPRCKnotTypePiecewiseBezierKnots // Extrema with multiplicities of degree +1. }; // Note : this value is currently unused and should be set to KEPRCKnotTypeUnspecified. enum EPRCBSplineSurfaceForm { KEPRCBSplineSurfaceFormPlane, // Planar surface. KEPRCBSplineSurfaceFormCylindrical, // Cylindrical surface. KEPRCBSplineSurfaceFormConical, // Conical surface. KEPRCBSplineSurfaceFormSpherical, // Spherical surface. KEPRCBSplineSurfaceFormRevolution, // Surface of revolution. KEPRCBSplineSurfaceFormRuled, // Ruled surface. KEPRCBSplineSurfaceFormGeneralizedCone, // Cone. KEPRCBSplineSurfaceFormQuadric, // Quadric surface. KEPRCBSplineSurfaceFormLinearExtrusion, // Surface of extrusion. KEPRCBSplineSurfaceFormUnspecified, // Unspecified surface. KEPRCBSplineSurfaceFormPolynomial // Polynomial surface. }; enum EPRCBSplineCurveForm { // NURBS curve form KEPRCBSplineCurveFormUnspecified, // Unspecified curve form. KEPRCBSplineCurveFormPolyline, // Polygon. KEPRCBSplineCurveFormCircularArc, // Circle arc. KEPRCBSplineCurveFormEllipticArc, // Elliptical arc. KEPRCBSplineCurveFormParabolicArc, // Parabolic arc. KEPRCBSplineCurveFormHyperbolicArc // Hyperbolic arc. }; // Note : this value is currently unused and should be set to KEPRCBSplineCurveFormUnspecified. enum EPRCTextureMappingType { // Defines how to retrieve mapping coordinates. KEPRCTextureMappingType_Unknown, // Let the application choose. KEPRCTextureMappingType_Stored, // Use the mapping coordinates that are stored on a 3D tessellation object KEPRCTextureMappingType_Parametric, // Retrieve the UV coordinates on the surface as mapping coordinates KEPRCTextureMappingType_Operator // Use the defined Texture mapping operator to calculate mapping coordinates }; enum EPRCTextureFunction { // Defines how to paint a texture on the surface being rendered. KEPRCTextureFunction_Unknown, // Let the application choose. KEPRCTextureFunction_Modulate, // Combine lighting with texturing. This is the default value. KEPRCTextureFunction_Replace, // Replace the object color with texture color data. KEPRCTextureFunction_Blend, // Reserved for future use. KEPRCTextureFunction_Decal // Reserved for future use. }; enum EPRCTextureMappingOperator { // The operator to use when computing mapping coordinates. KEPRCTextureMappingOperator_Unknown, // Default value KEPRCTextureMappingOperator_Planar, // Reserved for future use KEPRCTextureMappingOperator_Cylindrical, // Reserved for future use KEPRCTextureMappingOperator_Spherical, // Reserved for future use KEPRCTextureMappingOperator_Cubical // Reserved for future use }; enum EPRCTextureBlendParameter { // Reserved for future use. Defines how to apply blending. KEPRCTextureBlendParameter_Unknown, // Default value. KEPRCTextureBlendParameter_Zero, // Reserved for future use. KEPRCTextureBlendParameter_One, // Reserved for future use. KEPRCTextureBlendParameter_SrcColor, // Reserved for future use. KEPRCTextureBlendParameter_OneMinusSrcColor, // Reserved for future use. KEPRCTextureBlendParameter_DstColor, // Reserved for future use. KEPRCTextureBlendParameter_OneMinusDstColor, // Reserved for future use. KEPRCTextureBlendParameter_SrcAlpha, // Reserved for future use. KEPRCTextureBlendParameter_OneMinusSrcAlpha, // Reserved for future use. KEPRCTextureBlendParameter_DstAlpha, // Reserved for future use. KEPRCTextureBlendParameter_OneMinusDstAlpha, // Reserved for future use. KEPRCTextureBlendParameter_SrcAlphaSaturate // Reserved for future use. }; enum EPRCTextureWrappingMode { // Defines repeating and clamping texture modes. KEPRCTextureWrappingMode_Unknown, // Let the application choose. KEPRCTextureWrappingMode_Repeat, // Display the repeated texture on the surface. KEPRCTextureWrappingMode_ClampToBorder, // Clamp the texture to the border. Display the surface color along the texture limits. KEPRCTextureWrappingMode_Clamp, // Reserved for future use. KEPRCTextureWrappingMode_ClampToEdge, // Reserved for future use. KEPRCTextureWrappingMode_MirroredRepeat // Reserved for future use. }; enum EPRCTextureAlphaTest { // Reserved for future use. Defines how to use a texture alpha test. KEPRCTextureAlphaTest_Unknown, // Default value. KEPRCTextureAlphaTest_Never, // Reserved for future use. KEPRCTextureAlphaTest_Less, // Reserved for future use. KEPRCTextureAlphaTest_Equal, // Reserved for future use. KEPRCTextureAlphaTest_Lequal, // Reserved for future use. KEPRCTextureAlphaTest_Greater, // Reserved for future use. KEPRCTextureAlphaTest_Notequal, // Reserved for future use. KEPRCTextureAlphaTest_Gequal, // Reserved for future use. KEPRCTextureAlphaTest_Always // Reserved for future use. }; // Bit field for graphics behavior #define PRC_GRAPHICS_Show 0x0001 // The entity is shown. #define PRC_GRAPHICS_SonHeritShow 0x0002 // Shown entity son inheritance. #define PRC_GRAPHICS_FatherHeritShow 0x0004 // Shown entity father inheritance. #define PRC_GRAPHICS_SonHeritColor 0x0008 // Color/material son inheritance. #define PRC_GRAPHICS_FatherHeritColor 0x0010 // Color/material father inheritance. #define PRC_GRAPHICS_SonHeritLayer 0x0020 // Layer son inheritance. #define PRC_GRAPHICS_FatherHeritLayer 0x0040 // Layer father inheritance. #define PRC_GRAPHICS_SonHeritTransparency 0x0080 // Transparency son inheritance. #define PRC_GRAPHICS_FatherHeritTransparency 0x0100 // Transparency father inheritance. #define PRC_GRAPHICS_SonHeritLinePattern 0x0200 // Line pattern son inheritance. #define PRC_GRAPHICS_FatherHeritLinePattern 0x0400 // Line pattern father inheritance. #define PRC_GRAPHICS_SonHeritLineWidth 0x0800 // Line width son inheritance. #define PRC_GRAPHICS_FatherHeritLineWidth 0x1000 // Line width father inheritance. #define PRC_GRAPHICS_Removed 0x2000 // The entity has been removed and no longer appears in the tree. enum EPRCMarkupType { KEPRCMarkupType_Unknown = 0, KEPRCMarkupType_Text, KEPRCMarkupType_Dimension, KEPRCMarkupType_Arrow, KEPRCMarkupType_Balloon, KEPRCMarkupType_CircleCenter, KEPRCMarkupType_Coordinate, KEPRCMarkupType_Datum, KEPRCMarkupType_Fastener, KEPRCMarkupType_Gdt, KEPRCMarkupType_Locator, KEPRCMarkupType_MeasurementPoint, KEPRCMarkupType_Roughness, KEPRCMarkupType_Welding, KEPRCMarkupType_Table, KEPRCMarkupType_Other }; enum EPRCMarkupSubType { KEPRCMarkupSubType_Unknown = 0, KEPRCMarkupSubType_EnumMax, KEPRCMarkupSubType_Datum_Ident = 1 , KEPRCMarkupSubType_Datum_EnumMax, KEPRCMarkupSubType_Dimension_Distance = 1, KEPRCMarkupSubType_Dimension_Radius_Tangent, KEPRCMarkupSubType_Dimension_Radius_Cylinder, KEPRCMarkupSubType_Dimension_Radius_Edge, KEPRCMarkupSubType_Dimension_Diameter, KEPRCMarkupSubType_Dimension_Diameter_Tangent, KEPRCMarkupSubType_Dimension_Diameter_Cylinder, KEPRCMarkupSubType_Dimension_Diameter_Edge, KEPRCMarkupSubType_Dimension_Diameter_Cone, KEPRCMarkupSubType_Dimension_Length, KEPRCMarkupSubType_Dimension_Length_Curvilinear, KEPRCMarkupSubType_Dimension_Length_Circular, KEPRCMarkupSubType_Dimension_Angle, KEPRCMarkupSubType_Dimension_EnumMax, KEPRCMarkupSubType_Gdt_Fcf = 1, KEPRCMarkupSubType_Gdt_EnumMax, KEPRCMarkupSubType_Welding_Line = 1, KEPRCMarkupSubType_Welding_EnumMax, KEPRCMarkupSubType_Other_Symbol_User = 1, KEPRCMarkupSubType_Other_EnumMax }; #define PRC_MARKUP_IsHidden 0x01 // The tessellation is hidden. #define PRC_MARKUP_HasFrame 0x02 // The tessellation has a frame. #define PRC_MARKUP_IsNotModifiable 0x04 // The tessellation is given and should not be modified. #define PRC_MARKUP_IsZoomable 0x08 // The tessellation has zoom capability. #define PRC_MARKUP_IsOnTop 0x10 // The tessellation is on top of the geometry. #define PRC_MARKUP_IsFlipable 0x20 // The text tessellation can be flipped to always be readable on screen. This value is currently unused. #define PRC_RENDERING_PARAMETER_SPECIAL_CULLING 0x0001 // special culling strategy to apply #define PRC_RENDERING_PARAMETER_FRONT_CULLING 0x0002 // apply front culling (ignored if no special culling strategy) #define PRC_RENDERING_PARAMETER_BACK_CULLING 0x0004 // apply back culling (ignored if no special culling strategy) #define PRC_RENDERING_PARAMETER_NO_LIGHT 0x0008 // if set, no light will apply on corresponding object #define PRC_MARKUP_IsMatrix 0x08000000 // Bit to denote that the current entity is a matrix. #define PRC_MARKUP_IsExtraData 0x04000000 // Bit to denote that the current entity is extra data (it is neither a matrix nor a polyline). #define PRC_MARKUP_IntegerMask 0xFFFFF // Integer mask to retrieve sizes. #define PRC_MARKUP_ExtraDataType 0x3E00000 // Mask to retrieve the integer type of the entity. #define PRC_MARKUP_ExtraDataType_Pattern (( 0<<21)|PRC_MARKUP_IsExtraData) #define PRC_MARKUP_ExtraDataType_Picture (( 1<<21)|PRC_MARKUP_IsExtraData) #define PRC_MARKUP_ExtraDataType_Triangles (( 2<<21)|PRC_MARKUP_IsExtraData) #define PRC_MARKUP_ExtraDataType_Quads (( 3<<21)|PRC_MARKUP_IsExtraData) #define PRC_MARKUP_ExtraDataType_FaceViewMode (( 6<<21)|PRC_MARKUP_IsExtraData) #define PRC_MARKUP_ExtraDataType_FrameDrawMode (( 7<<21)|PRC_MARKUP_IsExtraData) #define PRC_MARKUP_ExtraDataType_FixedSizeMode (( 8<<21)|PRC_MARKUP_IsExtraData) #define PRC_MARKUP_ExtraDataType_Symbol (( 9<<21)|PRC_MARKUP_IsExtraData) #define PRC_MARKUP_ExtraDataType_Cylinder ((10<<21)|PRC_MARKUP_IsExtraData) #define PRC_MARKUP_ExtraDataType_Color ((11<<21)|PRC_MARKUP_IsExtraData) #define PRC_MARKUP_ExtraDataType_LineStipple ((12<<21)|PRC_MARKUP_IsExtraData) #define PRC_MARKUP_ExtraDataType_Font ((13<<21)|PRC_MARKUP_IsExtraData) #define PRC_MARKUP_ExtraDataType_Text ((14<<21)|PRC_MARKUP_IsExtraData) #define PRC_MARKUP_ExtraDataType_Points ((15<<21)|PRC_MARKUP_IsExtraData) #define PRC_MARKUP_ExtraDataType_Polygon ((16<<21)|PRC_MARKUP_IsExtraData) #define PRC_MARKUP_ExtraDataType_LineWidth ((17<<21)|PRC_MARKUP_IsExtraData) enum EPRCCharSet { KEPRCCharsetUnknown = -1, KEPRCCharsetRoman = 0, KEPRCCharsetJapanese, KEPRCCharsetTraditionalChinese, KEPRCCharsetKorean, KEPRCCharsetArabic, KEPRCCharsetHebrew, KEPRCCharsetGreek, KEPRCCharsetCyrillic, KEPRCCharsetRightLeft, KEPRCCharsetDevanagari, KEPRCCharsetGurmukhi, KEPRCCharsetGujarati, KEPRCCharsetOriya, KEPRCCharsetBengali, KEPRCCharsetTamil, KEPRCCharsetTelugu, KEPRCCharsetKannada, KEPRCCharsetMalayalam, KEPRCCharsetSinhalese, KEPRCCharsetBurmese, KEPRCCharsetKhmer, KEPRCCharsetThai, KEPRCCharsetLaotian, KEPRCCharsetGeorgian, KEPRCCharsetArmenian, KEPRCCharsetSimplifiedChinese, KEPRCCharsetTibetan, KEPRCCharsetMongolian, KEPRCCharsetGeez, KEPRCCharsetEastEuropeanRoman, KEPRCCharsetVietnamese, KEPRCCharsetExtendedArabic }; #define PRC_Font_Bold 0x02 /*!< Bold. */ #define PRC_Font_Italic 0x04 /*!< Italic. */ #define PRC_Font_Underlined 0x08 /*!< Underlined. */ #define PRC_Font_StrikedOut 0x10 /*!< Striked-out. */ #define PRC_Font_Overlined 0x20 /*!< Overlined. */ #define PRC_Font_Streched 0x40 /*!< Streched. In case the font used is not the original font, it indicates that the text needs to be stretched to fit its bounding box. */ #define PRC_Font_Wired 0x80 /*!< Wired. Indicates that the original font is a wirefame font. */ #define PRC_Font_FixedWidth 0x100 /*!< Fixed width. Indicates that the original font is not proportional (each glyph has the same width). */ #define PRC_CONTEXT_OuterLoopFirst 0x0001 // Outer loops are always first loops (specific to PRC_TYPE_TOPO_BrepData). #define PRC_CONTEXT_NoClamp 0x0002 // UV curves are clamped on the surface (specific to PRC_TYPE_TOPO_BrepData). #define PRC_CONTEXT_NoSplit 0x0004 // Faces are split (specific to PRC_TYPE_TOPO_BrepData). #define PRC_BODY_BBOX_Evaluation 0x0001 // Bounding box based on geometry. #define PRC_BODY_BBOX_Precise 0x0002 // Bounding box based on tessellation. #define PRC_BODY_BBOX_CADData 0x0003 // Bounding box given by a CAD data file. #endif // __PRC_H asymptote-2.37/prc/PRCTools/000077500000000000000000000000001265434602500157325ustar00rootroot00000000000000asymptote-2.37/prc/PRCTools/Makefile000066400000000000000000000031721265434602500173750ustar00rootroot00000000000000CFLAGS = -O3 -Wall CXX = g++ makePRC: PRCbitStream oPRCFile PRCdouble writePRC makePRC.cc $(CXX) $(CFLAGS) -o makePRC PRCbitStream.o oPRCFile.o PRCdouble.o writePRC.o makePRC.cc -lz describePRC: bitData inflation PRCdouble iPRCFile describePRC.cc describeMain.cc $(CXX) $(CFLAGS) -o describePRC bitData.o inflation.o PRCdouble.o iPRCFile.o describePRC.cc describeMain.cc -lz bitSearchUI: bitSearchUI.cc bitData PRCdouble $(CXX) $(CFLAGS) -o bitSearchUI bitData.o PRCdouble.o bitSearchUI.cc bitSearchDouble: bitSearchDouble.cc bitData PRCdouble $(CXX) $(CFLAGS) -o bitSearchDouble bitData.o PRCdouble.o bitSearchDouble.cc extractSections: extractSections.cc iPRCFile inflation bitData PRCdouble $(CXX) $(CFLAGS) -o extractSections iPRCFile.o inflation.o bitData.o PRCdouble.o describePRC.cc extractSections.cc -lz inflateTest: inflation inflationMain.cc $(CXX) $(CFLAGS) -o inflateTest inflation.o inflationMain.cc -lz PRCdouble: ../PRCdouble.cc $(CXX) $(CFLAGS) -c ../PRCdouble.cc -o PRCdouble.o PRCbitStream: ../PRCbitStream.cc $(CXX) $(CFLAGS) -c ../PRCbitStream.cc -o PRCbitStream.o oPRCFile: ../oPRCFile.cc $(CXX) $(CFLAGS) -c ../oPRCFile.cc -o oPRCFile.o writePRC: ../writePRC.cc PRCbitStream $(CXX) $(CFLAGS) -c ../writePRC.cc -o writePRC.o bitData: bitData.cc $(CXX) $(CFLAGS) -c bitData.cc -o bitData.o inflation: inflation.cc $(CXX) $(CFLAGS) -c inflation.cc -o inflation.o iPRCFile: iPRCFile.cc $(CXX) $(CFLAGS) -c iPRCFile.cc -o iPRCFile.o all: makePRC describePRC bitSearchUI bitSearchDouble extractSections inflateTest tools: all clean: rm -f *.o describePRC bitSearchUI bitSearchDouble extractSections inflateTest asymptote-2.37/prc/PRCTools/bitData.cc000066400000000000000000000136051265434602500176160ustar00rootroot00000000000000/************ * * This file is part of a tool for reading 3D content in the PRC format. * Copyright (C) 2008 Orest Shardt * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * *************/ #include "../PRC.h" #include "../PRCdouble.h" #include "bitData.h" using std::cout; using std::endl; using std::hex; using std::cerr; BitPosition BitByBitData::getPosition() { BitPosition bp; bp.byteIndex = data - start; bp.bitIndex = 0; for(unsigned char temp = bitMask<<1; temp != 0; temp <<= 1) bp.bitIndex++; return bp; } void BitByBitData::setPosition(const BitPosition& bp) { if(bp.byteIndex < length) { data = start + bp.byteIndex; bitMask = 0x80 >> bp.bitIndex; // big-endian, zero based bit index (from 0 to 7) // so 0x80 => bit 0, 0x01 => bit 7 // Why? It is easy to see in a hex editor. failed = false; } else { failed = true; } } void BitByBitData::setPosition(unsigned int byte, unsigned int bit) { if(byte <= length) { data = start + byte; bitMask = 0x80 >> bit; // big-endian, zero based bit index (from 0 to 7) // so 0x80 => bit 0, 0x01 => bit 7 // Why? It is easy to see in a hex editor. failed = false; } else { failed = true; } } void BitByBitData::setShowBits(bool val) { showBits = val; } void BitByBitData::tellPosition() { BitPosition bp = getPosition(); cout << bp.byteIndex << ':' << bp.bitIndex << endl; } bool BitByBitData::readBit() { if(!failed) { bool val = *data & bitMask; if(showBits) cout << (val?'1':'0'); nextBit(); return val; } else return false; } unsigned char BitByBitData::readChar() { unsigned char dat = 0; dat |= readBit(); for(int a = 0; a < 7; ++a) { dat <<= 1; dat |= readBit(); } return dat; } unsigned int BitByBitData::readUnsignedInt() { unsigned int result = 0; unsigned int count = 0; while(readBit()) { result |= (static_cast(readChar()) << 8*count++); } if(showBits) cout << " " << result << endl; return result; } std::string BitByBitData::readString() { bool isNotNull = readBit(); std::string result; if(isNotNull) { unsigned int stringLength = readUnsignedInt(); char *buf = new char[stringLength+1]; buf[stringLength] = '\0'; for(unsigned int a = 0; a < stringLength; ++a) { buf[a] = readChar(); } result = buf; delete[] buf; } if(showBits) cout << " " << result << endl; return result; } int BitByBitData::readInt() { int result = 0; unsigned int count = 0; while(readBit()) { result |= (static_cast(readChar()) << 8*count++); } result <<= (4-count)*8; result >>= (4-count)*8; if(showBits) cout << " " << result << endl; return result; } // Thanks to Michail Vidiassov double BitByBitData::readDouble() { ieee754_double value; value.d = 0; sCodageOfFrequentDoubleOrExponent *pcofdoe; unsigned int ucofdoe = 0; for(int i = 1; i <= 22; ++i) { ucofdoe <<= 1; ucofdoe |= readBit(); if((pcofdoe = getcofdoe(ucofdoe,i)) != NULL) break; } value.d = pcofdoe->u2uod.Value; // check if zero if(pcofdoe->NumberOfBits==2 && pcofdoe->Bits==1 && pcofdoe->Type==VT_double) return value.d; value.ieee.negative = readBit(); // get sign if(pcofdoe->Type == VT_double) // double from list return value.d; if(readBit()==0) // no mantissa return value.d; // read the mantissa // read uppermost 4 bits of mantissa unsigned char b4 = 0; for(int i = 0; i < 4; ++i) { b4 <<= 1; b4 |= readBit(); } #ifdef WORDS_BIGENDIAN *(reinterpret_cast(&value)+1) |= b4; unsigned char *lastByte = reinterpret_cast(&value)+7; unsigned char *currentByte = reinterpret_cast(&value)+2; #else *(reinterpret_cast(&value)+6) |= b4; unsigned char *lastByte = reinterpret_cast(&value)+0; unsigned char *currentByte = reinterpret_cast(&value)+5; #endif for(;MOREBYTE(currentByte,lastByte); NEXTBYTE(currentByte)) { if(readBit()) { // new byte *currentByte = readChar(); } else { // get 3 bit offset unsigned int offset = 0; offset |= (readBit() << 2); offset |= (readBit() << 1); offset |= readBit(); if(offset == 0) { // fill remaining bytes in mantissa with previous byte unsigned char pByte = BYTEAT(currentByte,1); for(;MOREBYTE(currentByte,lastByte); NEXTBYTE(currentByte)) *currentByte = pByte; break; } else if(offset == 6) { // fill remaining bytes except last byte with previous byte unsigned char pByte = BYTEAT(currentByte,1); PREVIOUSBYTE(lastByte); for(;MOREBYTE(currentByte,lastByte); NEXTBYTE(currentByte)) *currentByte = pByte; *currentByte = readChar(); break; } else { // one repeated byte *currentByte = BYTEAT(currentByte,offset); } } } if(showBits) cout << " " << value.d << endl; return value.d; } void BitByBitData::nextBit() { bitMask >>= 1; if(bitMask == 0) { if(data < start+length) data++; else { failed = true; cout << "End of data."<< endl; } bitMask = 0x80; } } asymptote-2.37/prc/PRCTools/bitData.h000066400000000000000000000035041265434602500174550ustar00rootroot00000000000000/************ * * This file is part of a tool for reading 3D content in the PRC format. * Copyright (C) 2008 Orest Shardt * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * *************/ #ifndef __BITDATA_H #define __BITDATA_H #include #include struct BitPosition { unsigned int byteIndex; unsigned int bitIndex; }; class BitByBitData { public: BitByBitData(char* s,unsigned int l) : start(s),data(s),length(l), bitMask(0x80),showBits(false),failed(false) {} void tellPosition(); BitPosition getPosition(); void setPosition(const BitPosition&); void setPosition(unsigned int,unsigned int); void setShowBits(bool); bool readBit(); unsigned char readChar(); unsigned int readUnsignedInt(); std::string readString(); int readInt(); double readDouble(); private: char *start; // first byte so we know where we are char *data; // last byte read unsigned int length; unsigned char bitMask; // mask to read next bit of current byte bool showBits; // show each bit read? bool failed; void nextBit(); // shift bit mask and get next byte if needed }; #endif // __BITDATA_H asymptote-2.37/prc/PRCTools/bitSearchDouble.cc000066400000000000000000000036071265434602500213060ustar00rootroot00000000000000/************ * * This file is part of a tool for reading 3D content in the PRC format. * Copyright (C) 2008 Orest Shardt * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * *************/ #include #include #include #include "bitData.h" using namespace std; int main(int argc, char *argv[]) { if(argc < 2) { cerr << "Error: Input file not specified." << endl; return 1; } ifstream inFile(argv[1]); if(!inFile) { cerr << "Error: Cannot open input file." << endl; return 1; } inFile.seekg(0,ios::end); unsigned int length = inFile.tellg(); inFile.seekg(0,ios::beg); char *buf = new char[length]; inFile.read(buf,length); BitByBitData bbbd(buf,length); double dsf; cout << "double to search for: "; cin >> dsf; BitPosition currP; for(currP.byteIndex = 0; currP.byteIndex < length; ++currP.byteIndex) for(currP.bitIndex = 0; currP.bitIndex < 8; ++currP.bitIndex) { bbbd.setPosition(currP); if(bbbd.readDouble() == dsf) { BitPosition bp = bbbd.getPosition(); cout << "Found " << dsf << " at " << currP.byteIndex << ':' << currP.bitIndex << " to " << bp.byteIndex << ':' << bp.bitIndex << endl; } } delete[] buf; return 0; } asymptote-2.37/prc/PRCTools/bitSearchUI.cc000066400000000000000000000035071265434602500204100ustar00rootroot00000000000000/************ * * This file is part of a tool for reading 3D content in the PRC format. * Copyright (C) 2008 Orest Shardt * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * *************/ #include #include #include #include "bitData.h" using namespace std; int main(int argc, char *argv[]) { if(argc < 2) { cerr << "Error: Input file not specified." << endl; return 1; } ifstream inFile(argv[1]); if(!inFile) { cerr << "Error: Cannot open input file." << endl; return 1; } inFile.seekg(0,ios::end); unsigned int length = inFile.tellg(); inFile.seekg(0,ios::beg); char *buf = new char[length]; inFile.read(buf,length); BitByBitData bbbd(buf,length); unsigned int uisf; cout << "Unsigned int to search for: "; cin >> uisf; BitPosition currP; for(currP.byteIndex = 0; currP.byteIndex < length; ++currP.byteIndex) for(currP.bitIndex = 0; currP.bitIndex < 8; ++currP.bitIndex) { bbbd.setPosition(currP); if(bbbd.readUnsignedInt() == uisf) { cout << "Found " << uisf << " at " << currP.byteIndex << ':' << currP.bitIndex << endl; } } delete[] buf; return 0; } asymptote-2.37/prc/PRCTools/describeMain.cc000066400000000000000000000023351265434602500206310ustar00rootroot00000000000000/************ * * This file is part of a tool for reading 3D content in the PRC format. * Copyright (C) 2008 Orest Shardt * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * *************/ #include #include #include "iPRCFile.h" using namespace std; int main(int argc, char* argv[]) { if(argc < 2) { cerr << "Error: Input file not specified." << endl; return 1; } ifstream inFile(argv[1]); if(!inFile) { cerr << "Error: Cannot open input file." << endl; return 1; } iPRCFile myFile(inFile); myFile.describe(); return 0; } asymptote-2.37/prc/PRCTools/describePRC.cc000066400000000000000000002050361265434602500203740ustar00rootroot00000000000000/************ * * This file is part of a tool for reading 3D content in the PRC format. * Copyright (C) 2008 Orest Shardt * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * *************/ #include #include #include #include #include #include "../PRC.h" #include "describePRC.h" using std::ostringstream; using std::cout; using std::endl; using std::hex; using std::dec; using std::string; using std::setw; using std::setfill; // describe sections void describeGlobals(BitByBitData &mData) { mData.tellPosition(); cout << getIndent() << "--Globals--" << endl; if(!checkSectionCode(mData,PRC_TYPE_ASM_FileStructureGlobals)) return; indent(); describeContentPRCBase(mData,false); unsigned int numberOfReferencedFileStructures = mData.readUnsignedInt(); cout << getIndent() << "numberOfReferencedFileStructures " << numberOfReferencedFileStructures << endl; indent(); for(unsigned int i = 0; i < numberOfReferencedFileStructures; ++i) { describeCompressedUniqueID(mData); } dedent(); double tessellation_chord_height_ratio = mData.readDouble(); cout << getIndent() << "tessellation_chord_height_ratio " << tessellation_chord_height_ratio << endl; double tessellation_angle_degree = mData.readDouble(); cout << getIndent() << "tessellation_angle_degree " << tessellation_angle_degree << endl; string default_font_family_name = mData.readString(); cout << getIndent() << "default_font_family_name \"" << default_font_family_name << '\"' << endl; unsigned int number_of_fonts = mData.readUnsignedInt(); cout << getIndent() << "number_of_fonts " << number_of_fonts << endl; indent(); for(unsigned int q = 0; q < number_of_fonts; ++q) { string font_name = mData.readString(); cout << getIndent() << "font_name \"" << font_name << '\"' << endl; unsigned int char_set = mData.readUnsignedInt(); cout << getIndent() << "char_set " << char_set << endl; unsigned int number_of_font_keys = mData.readUnsignedInt(); cout << getIndent() << "number_of_font_keys " << number_of_font_keys << endl; indent(); for(unsigned int i = 0; i < number_of_font_keys; i++) { unsigned int font_size = mData.readUnsignedInt() - 1; cout << getIndent() << "font_size " << font_size << endl; unsigned char attributes = mData.readChar(); cout << getIndent() << "attributes " << static_cast(attributes) << endl; } dedent(); } dedent(); unsigned int number_of_colours = mData.readUnsignedInt(); cout << getIndent() << "number_of_colours " << number_of_colours << endl; indent(); for(unsigned int i = 0; i < number_of_colours; ++i) describeRGBColour(mData); dedent(); unsigned int number_of_pictures = mData.readUnsignedInt(); cout << getIndent() << "number_of_pictures " << number_of_pictures << endl; indent(); for(unsigned int i=0;i(mData.readChar()) << endl; unsigned int number_of_coedge = mData.readUnsignedInt(); cout << getIndent() << "number_of_coedge " << number_of_coedge << endl; indent(); for(unsigned int i = 0; i < number_of_coedge; ++i) { describeObject(mData); cout << getIndent() << "neigh_serial_index " << mData.readUnsignedInt() << endl; } dedent(); dedent(); } void describeTopoCoEdge(BitByBitData &mData) { cout << getIndent() << "--CoEdge--" << endl; indent(); describeBaseTopology(mData); describeObject(mData); // edge describeObject(mData); // uv_curve cout << getIndent() << "orientation_with_loop " << static_cast(mData.readChar()) << endl; cout << getIndent() << "orientation_uv_with_loop " << static_cast(mData.readChar()) << endl; dedent(); } void describeTopoEdge(BitByBitData &mData) { cout << getIndent() << "--Edge--" << endl; indent(); describeContentWireEdge(mData); describeObject(mData); // vertex_start describeObject(mData); // vertex_end bool have_tolerance = mData.readBit(); cout << getIndent() << "have_tolerance " << (have_tolerance?"yes":"no") << endl; if(have_tolerance) cout << getIndent() << "tolerance " << mData.readDouble() << endl; dedent(); } void describeTopoUniqueVertex(BitByBitData &mData) { cout << getIndent() << "--Unique Vertex--" << endl; indent(); describeBaseTopology(mData); describeVector3d(mData); bool have_tolerance = mData.readBit(); cout << getIndent() << "have_tolerance " << (have_tolerance?"yes":"no") << endl; if(have_tolerance) cout << getIndent() << "tolerance " << mData.readDouble() << endl; dedent(); } void describeTopoConnex(BitByBitData &mData) { cout << getIndent() << "--Connex--" << endl; indent(); describeBaseTopology(mData); unsigned int number_of_shells = mData.readUnsignedInt(); cout << getIndent() << "number_of_shells " << number_of_shells << endl; indent(); for(unsigned int i = 0; i < number_of_shells; ++i) { // NOTE: this does not check if the objects are actually shells! describeObject(mData); } dedent(); dedent(); } void describeTopoShell(BitByBitData &mData) { cout << getIndent() << "--Shell--" << endl; indent(); describeBaseTopology(mData); cout << getIndent() << "shell_is_closed " << (mData.readBit()?"yes":"no") << endl; unsigned int number_of_faces = mData.readUnsignedInt(); cout << getIndent() << "number_of_faces " << number_of_faces << endl; for(unsigned int i = 0; i < number_of_faces; ++i) { // NOTE: this does not check if the objects are actually faces! describeObject(mData); unsigned char orientation = mData.readChar(); cout << getIndent() << "orientation_surface_with_shell " << static_cast(orientation) << endl; } dedent(); } void describeObject(BitByBitData &mData) { cout << getIndent() << "--Object--" << endl; bool already_stored = mData.readBit(); cout << getIndent() << "already_stored " << (already_stored?"yes":"no") << endl; if(already_stored) // reverse of documentation? { cout << getIndent() << "index of stored item " << mData.readUnsignedInt() << endl; } else { unsigned int type = mData.readUnsignedInt(); switch(type) { case PRC_TYPE_ROOT: cout << getIndent() << "NULL Object" << endl; break; // topological items case PRC_TYPE_TOPO_Connex: describeTopoConnex(mData); break; case PRC_TYPE_TOPO_Shell: describeTopoShell(mData); break; case PRC_TYPE_TOPO_Face: describeTopoFace(mData); break; case PRC_TYPE_TOPO_Loop: describeTopoLoop(mData); break; case PRC_TYPE_TOPO_CoEdge: describeTopoCoEdge(mData); break; case PRC_TYPE_TOPO_Edge: describeTopoEdge(mData); break; case PRC_TYPE_TOPO_UniqueVertex: describeTopoUniqueVertex(mData); break; case PRC_TYPE_TOPO_WireEdge: describeContentWireEdge(mData); break; // curves case PRC_TYPE_CRV_Circle: describeCurvCircle(mData); break; case PRC_TYPE_CRV_NURBS: describeCurvNURBS(mData); break; case PRC_TYPE_CRV_PolyLine: describeCurvPolyLine(mData); break; case PRC_TYPE_CRV_Line: describeCurvLine(mData); break; // surfaces case PRC_TYPE_SURF_NURBS: describeSurfNURBS(mData); break; case PRC_TYPE_SURF_Cylinder: describeSurfCylinder(mData); break; case PRC_TYPE_SURF_Plane: describeSurfPlane(mData); break; // topological items case PRC_TYPE_TOPO_Item: case PRC_TYPE_TOPO_MultipleVertex: // curves case PRC_TYPE_CRV_Base: case PRC_TYPE_CRV_Blend02Boundary: case PRC_TYPE_CRV_Composite: case PRC_TYPE_CRV_OnSurf: case PRC_TYPE_CRV_Ellipse: case PRC_TYPE_CRV_Equation: case PRC_TYPE_CRV_Helix: case PRC_TYPE_CRV_Hyperbola: case PRC_TYPE_CRV_Intersection: case PRC_TYPE_CRV_Offset: case PRC_TYPE_CRV_Parabola: case PRC_TYPE_CRV_Transform: // surfaces case PRC_TYPE_SURF_Base: case PRC_TYPE_SURF_Blend01: case PRC_TYPE_SURF_Blend02: case PRC_TYPE_SURF_Blend03: case PRC_TYPE_SURF_Cone: case PRC_TYPE_SURF_Cylindrical: case PRC_TYPE_SURF_Offset: case PRC_TYPE_SURF_Pipe: case PRC_TYPE_SURF_Ruled: case PRC_TYPE_SURF_Sphere: case PRC_TYPE_SURF_Revolution: case PRC_TYPE_SURF_Extrusion: case PRC_TYPE_SURF_FromCurves: case PRC_TYPE_SURF_Torus: case PRC_TYPE_SURF_Transform: case PRC_TYPE_SURF_Blend04: cout << getIndent() << "TODO: Unhandled object of type " << type << endl; break; default: cout << getIndent() << "Invalid object of type " << type << endl; break; } } } void describeBaseTopology(BitByBitData &mData) { bool base_information = mData.readBit(); cout << getIndent() << "base_information " << (base_information?"yes":"no") << endl; if(base_information) { describeAttributes(mData); describeName(mData); cout << getIndent() << "identifier " << mData.readUnsignedInt() << endl; } } void describeBaseGeometry(BitByBitData &mData) { bool base_information = mData.readBit(); cout << getIndent() << "base_information " << (base_information?"yes":"no") << endl; if(base_information) { describeAttributes(mData); describeName(mData); cout << getIndent() << "identifier " << mData.readUnsignedInt() << endl; } } unsigned int describeContentBody(BitByBitData &mData) { describeBaseTopology(mData); unsigned int behaviour = static_cast(mData.readChar()); cout << getIndent() << "behaviour " << behaviour << endl; return behaviour; } void describeContentSurface(BitByBitData &mData) { describeBaseGeometry(mData); cout << getIndent() << "extend_info " << mData.readUnsignedInt() << endl; } void describeBody(BitByBitData &mData) { cout << getIndent() << "--Body--" << endl; unsigned int type = mData.readUnsignedInt(); switch(type) { case PRC_TYPE_TOPO_BrepData: { cout << getIndent() << "--PRC_TYPE_TOPO_BrepData--" << endl; unsigned int behaviour = describeContentBody(mData); unsigned int number_of_connex = mData.readUnsignedInt(); cout << getIndent() << "number_of_connex " << number_of_connex << endl; indent(); for(unsigned int i = 0; i < number_of_connex; ++i) { describeObject(mData); } dedent(); if(behaviour != 0) { cout << getIndent() << "bbox " << endl; indent(); describeExtent3d(mData); dedent(); } break; } case PRC_TYPE_TOPO_SingleWireBody: { cout << getIndent() << "--PRC_TYPE_TOPO_SingleWireBody--" << endl; // unsigned int behaviour = describeContentBody(mData); // TODO: is behaviour needed to get data about how to describe? describeContentBody(mData); describeObject(mData); // curve break; } case PRC_TYPE_TOPO_BrepDataCompress: case PRC_TYPE_TOPO_SingleWireBodyCompress: cout << getIndent() << "TODO: Unhandled body type " << type << endl; break; default: cout << getIndent() << "Invalid body type " << type << endl; break; } } void describeTopoContext(BitByBitData &mData) { cout << getIndent() << "--Topological Context--" << endl; if(!checkSectionCode(mData,PRC_TYPE_TOPO_Context)) return; indent(); describeContentPRCBase(mData,false); cout << getIndent() << "behaviour " << static_cast(mData.readChar()) << endl; cout << getIndent() << "granularity " << mData.readDouble() << endl; cout << getIndent() << "tolerance " << mData.readDouble() << endl; bool have_smallest_face_thickness = mData.readBit(); cout << getIndent() << "have_smallest_face_thickness " << (have_smallest_face_thickness?"yes":"no") << endl; if(have_smallest_face_thickness) cout << getIndent() << "smallest_thickness " << mData.readDouble() << endl; bool have_scale = mData.readBit(); cout << getIndent() << "have_scale " << (have_scale?"yes":"no") << endl; if(have_scale) cout << getIndent() << "scale " << mData.readDouble() << endl; dedent(); } void describeLineAttr(BitByBitData& mData) { cout << getIndent() << "index_of_line_style " << mData.readUnsignedInt()-1 << endl; } void describeArrayRGBA(BitByBitData& mData, int number_of_colours, int number_by_vector) { // bool new_colour = true; // not currently used for(int i = 0; i < number_by_vector; ++i) { cout << getIndent() << static_cast(mData.readChar()) << ' '; cout << static_cast(mData.readChar()) << ' '; cout << static_cast(mData.readChar()) << endl; //TODO: finish this } } void describeContentBaseTessData(BitByBitData &mData) { cout << getIndent() << "is_calculated " << (mData.readBit()?"yes":"no") << endl; unsigned int number_of_coordinates = mData.readUnsignedInt(); cout << getIndent() << "number_of_coordinates " << number_of_coordinates << endl; indent(); for(unsigned int i = 0; i < number_of_coordinates; ++i) { cout << getIndent() << mData.readDouble() << endl; } dedent(); } void describeTessFace(BitByBitData &mData) { cout << getIndent() << "--Tessellation Face--" << endl; if(!checkSectionCode(mData,PRC_TYPE_TESS_Face)) return; indent(); unsigned int size_of_line_attributes = mData.readUnsignedInt(); cout << getIndent() << "size_of_line_attributes " << size_of_line_attributes << endl; indent(); for(unsigned int i = 0; i < size_of_line_attributes; ++i) { describeLineAttr(mData); } dedent(); unsigned int start_wire = mData.readUnsignedInt(); cout << getIndent() << "start_wire " << start_wire << endl; unsigned int size_of_sizes_wire = mData.readUnsignedInt(); cout << getIndent() << "size_of_sizes_wire " << size_of_sizes_wire << endl; indent(); for(unsigned int i = 0; i < size_of_sizes_wire; ++i) { cout << getIndent() << mData.readUnsignedInt() << endl; } dedent(); unsigned int used_entities_flag = mData.readUnsignedInt(); cout << getIndent() << "used_entities_flag " << used_entities_flag << endl; unsigned int start_triangulated = mData.readUnsignedInt(); cout << getIndent() << "start_triangulated " << start_triangulated << endl; unsigned int size_of_sizes_triangulated = mData.readUnsignedInt(); cout << getIndent() << "size_of_sizes_triangulated " << size_of_sizes_triangulated << endl; indent(); for(unsigned int i = 0; i < size_of_sizes_triangulated; ++i) { cout << getIndent() << mData.readUnsignedInt() << endl; } dedent(); cout << getIndent() << "number_of_texture_coordinate_indexes " << mData.readUnsignedInt() << endl; bool has_vertex_colors = mData.readBit(); cout << getIndent() << "has_vertex_colors " << (has_vertex_colors?"yes":"no") << endl; indent(); if(has_vertex_colors) { bool is_rgba = mData.readBit(); cout << getIndent() << "is_rgba " << (is_rgba?"yes":"no") << endl; bool b_optimised = mData.readBit(); cout << getIndent() << "b_optimised " << (b_optimised?"yes":"no") << endl; if(!b_optimised) { indent(); //TODO: compute size of Array and pass it instead of 0 describeArrayRGBA(mData,0,(is_rgba ? 4 : 3)); dedent(); } else { // not described // what does this mean? that this should not happen? // or is omitted from the docs? } } dedent(); if(size_of_line_attributes) { cout << getIndent() << "behaviour " << mData.readUnsignedInt() << endl; } dedent(); } void describe3DTess(BitByBitData &mData) { cout << getIndent() << "--3D Tessellation--" << endl; indent(); describeContentBaseTessData(mData); cout << getIndent() << "has_faces " << (mData.readBit()?"yes":"no") << endl; cout << getIndent() << "has_loops " << (mData.readBit()?"yes":"no") << endl; bool must_recalculate_normals = mData.readBit(); cout << getIndent() << "must_recalculate_normals " << (must_recalculate_normals?"yes":"no") << endl; indent(); if(must_recalculate_normals) { cout << getIndent() << "Docs were wrong: must_recalculate_normals is true." << endl; cout << getIndent() << "normals_recalculation_flags " << static_cast(mData.readChar()) << endl; cout << getIndent() << "crease_angle " << mData.readDouble() << endl; } dedent(); unsigned int number_of_normal_coordinates = mData.readUnsignedInt(); cout << getIndent() << "number_of_normal_coordinates " << number_of_normal_coordinates << endl; indent(); for(unsigned int i = 0; i < number_of_normal_coordinates; ++i) { cout << getIndent() << mData.readDouble() << endl; } dedent(); unsigned int number_of_wire_indices = mData.readUnsignedInt(); cout << getIndent() << "number_of_wire_indices " << number_of_wire_indices << endl; indent(); for(unsigned int i = 0; i < number_of_wire_indices; ++i) { cout << getIndent() << mData.readUnsignedInt() << endl; } dedent(); unsigned int number_of_triangulated_indices = mData.readUnsignedInt(); cout << getIndent() << "number_of_triangulated_indices " << number_of_triangulated_indices << endl; indent(); for(unsigned int i = 0; i < number_of_triangulated_indices; ++i) { cout << getIndent() << mData.readUnsignedInt() << endl; } dedent(); unsigned int number_of_face_tessellation = mData.readUnsignedInt(); cout << getIndent() << "number_of_face_tessellation " << number_of_face_tessellation << endl; indent(); for(unsigned int i = 0; i < number_of_face_tessellation; ++i) { describeTessFace(mData); } dedent(); unsigned int number_of_texture_coordinates = mData.readUnsignedInt(); cout << getIndent() << "number_of_texture_coordinates " << number_of_texture_coordinates << endl; indent(); for(unsigned int i = 0; i < number_of_texture_coordinates; ++i) { cout << getIndent() << mData.readDouble() << endl; } dedent(); dedent(); } void describe3DWireTess(BitByBitData &mData) { //TODO } void describe3DMarkupTess(BitByBitData &mData) { //TODO } void describeHighlyCompressed3DTess(BitByBitData &mData) { //TODO } void describeSceneDisplayParameters(BitByBitData &mData) { cout << getIndent() << "--Scene Display Parameters--" << endl; if(!checkSectionCode(mData,PRC_TYPE_GRAPH_SceneDisplayParameters)) return; indent(); describeContentPRCBase(mData,true); cout << getIndent() << "is active? " << (mData.readBit()?"yes":"no") << endl; unsigned int number_of_lights = mData.readUnsignedInt(); cout << getIndent() << "number of lights " << number_of_lights << endl; indent(); for(unsigned int i = 0; i < number_of_lights; ++i) { describeLight(mData); } dedent(); bool camera = mData.readBit(); cout << getIndent() << "camera? " << (camera?"yes":"no") << endl; if(camera) describeCamera(mData); bool rotation_centre = mData.readBit(); cout << getIndent() << "rotation centre? " << (rotation_centre?"yes":"no") << endl; if(rotation_centre) describeVector3d(mData); unsigned int number_of_clipping_planes = mData.readUnsignedInt(); cout << getIndent() << "number of clipping planes " << number_of_clipping_planes << endl; indent(); for(unsigned int i = 0; i < number_of_clipping_planes; ++i) { cout << "Can't describe planes!!!" << endl; //describePlane(mData); } dedent(); cout << getIndent() << "Background line style index: " << mData.readUnsignedInt()-1 << endl; cout << getIndent() << "Default line style index: " << mData.readUnsignedInt()-1 << endl; unsigned int number_of_default_styles_per_type = mData.readUnsignedInt(); cout << getIndent() << "number_of_default_styles_per_type " << number_of_default_styles_per_type << endl; indent(); for(unsigned int i = 0; i < number_of_default_styles_per_type; ++i) { cout << getIndent() << "type " << mData.readUnsignedInt() << endl; cout << getIndent() << "line style index: " << mData.readUnsignedInt()-1 << endl; } dedent(); dedent(); } void describeCartesionTransformation3d(BitByBitData& mData) { cout << getIndent() << "--3d Cartesian Transformation--" << endl; if(!checkSectionCode(mData,PRC_TYPE_MISC_CartesianTransformation)) return; indent(); unsigned char behaviour = mData.readChar(); cout << getIndent() << "behaviour " << static_cast(behaviour) << endl; if((behaviour & PRC_TRANSFORMATION_Translate) != 0) { cout << getIndent() << "Translation" << endl; describeVector3d(mData); } if((behaviour & PRC_TRANSFORMATION_NonOrtho) != 0) { cout << getIndent() << "Non orthogonal transformation" << endl; cout << getIndent() << "X" << endl; describeVector3d(mData); cout << getIndent() << "Y" << endl; describeVector3d(mData); cout << getIndent() << "Z" << endl; describeVector3d(mData); } else if((behaviour & PRC_TRANSFORMATION_Rotate) != 0) { cout << getIndent() << "Rotation" << endl; cout << getIndent() << "X" << endl; describeVector3d(mData); cout << getIndent() << "Y" << endl; describeVector3d(mData); } // this is different from the docs!!! but it works... if ((behaviour & PRC_TRANSFORMATION_NonUniformScale) != 0) { cout << getIndent() << "Non-uniform scale by " << endl; describeVector3d(mData); } // this is different from the docs!!! but it works... if((behaviour & PRC_TRANSFORMATION_Scale) != 0) { cout << getIndent() << "Uniform Scale by " << mData.readDouble() << endl; } if((behaviour & PRC_TRANSFORMATION_Homogeneous) != 0) { cout << getIndent() << "transformation has homogenous values" << endl; cout << getIndent() << "x = " << mData.readDouble() << endl; cout << getIndent() << "y = " << mData.readDouble() << endl; cout << getIndent() << "z = " << mData.readDouble() << endl; cout << getIndent() << "w = " << mData.readDouble() << endl; } dedent(); } void describeTransformation3d(BitByBitData& mData) { cout << getIndent() << "--3d Transformation--" << endl; indent(); bool has_transformation = mData.readBit(); cout << getIndent() << "has_transformation " << (has_transformation?"yes":"no") << endl; if(has_transformation) { unsigned char behaviour = mData.readChar(); cout << getIndent() << "behaviour " << static_cast(behaviour) << endl; if((behaviour & PRC_TRANSFORMATION_Translate) != 0) { cout << getIndent() << "Translation" << endl; describeVector3d(mData); } if((behaviour & PRC_TRANSFORMATION_Rotate) != 0) { cout << getIndent() << "Rotation" << endl; cout << getIndent() << "X" << endl; describeVector3d(mData); cout << getIndent() << "Y" << endl; describeVector3d(mData); } if((behaviour & PRC_TRANSFORMATION_Scale) != 0) { cout << getIndent() << "Uniform Scale by " << mData.readDouble() << endl; } } dedent(); } void describeTransformation2d(BitByBitData& mData) { cout << getIndent() << "--2d Transformation--" << endl; indent(); bool has_transformation = mData.readBit(); cout << "has_transformation " << (has_transformation?"yes":"no") << endl; if(has_transformation) { unsigned char behaviour = mData.readChar(); cout << getIndent() << "behaviour " << static_cast(behaviour) << endl; if((behaviour & PRC_TRANSFORMATION_Translate) != 0) { cout << getIndent() << "Translation" << endl; describeVector2d(mData); } if((behaviour & PRC_TRANSFORMATION_Rotate) != 0) { cout << getIndent() << "Rotation" << endl; cout << getIndent() << "X" << endl; describeVector2d(mData); cout << getIndent() << "Y" << endl; describeVector2d(mData); } if((behaviour & PRC_TRANSFORMATION_Scale) != 0) { cout << getIndent() << "Uniform Scale by " << mData.readDouble() << endl; } } dedent(); } void describeFileStructureInternalData(BitByBitData &mData) { cout << getIndent() << "--File Structure Internal Data--" << endl; if(!checkSectionCode(mData,PRC_TYPE_ASM_FileStructure)) return; indent(); describeContentPRCBase(mData,false); cout << getIndent() << "next_available_index " << mData.readUnsignedInt() << endl; cout << getIndent() << "index_product_occurence " << mData.readUnsignedInt() << endl; dedent(); } void describeProductOccurrence(BitByBitData &mData) { cout << getIndent() << "--Product Occurrence--" << endl; if(!checkSectionCode(mData,PRC_TYPE_ASM_ProductOccurence)) return; indent(); describeContentPRCBaseWithGraphics(mData,true); cout << getIndent() << "index_part " << static_cast(mData.readUnsignedInt()-1) << endl; unsigned int index_prototype = mData.readUnsignedInt()-1; cout << getIndent() << "index_prototype " << static_cast(index_prototype) << endl; if(index_prototype+1 != 0) { bool prototype_in_same_file_structure = mData.readBit(); cout << getIndent() << "prototype_in_same_file_structure " << (prototype_in_same_file_structure?"yes":"no") << endl; if(!prototype_in_same_file_structure) describeCompressedUniqueID(mData); } unsigned int index_external_data = mData.readUnsignedInt()-1; cout << getIndent() << "index_external_data " << static_cast(index_external_data) << endl; if(index_external_data+1 != 0) { bool external_data_in_same_file_structure = mData.readBit(); cout << getIndent() << "external_data_in_same_file_structure " << (external_data_in_same_file_structure?"yes":"no") << endl; if(!external_data_in_same_file_structure) describeCompressedUniqueID(mData); } unsigned int number_of_son_product_occurences = mData.readUnsignedInt(); cout << getIndent() << "number_of_son_product_occurences " << number_of_son_product_occurences << endl; indent(); for(unsigned int i = 0; i < number_of_son_product_occurences; ++i) cout << getIndent() << mData.readUnsignedInt() << endl; dedent(); cout << getIndent() << "product_behaviour " << static_cast(mData.readChar()) << endl; describeUnit(mData); cout << getIndent() << "Product information flags " << static_cast(mData.readChar()) << endl; cout << getIndent() << "product_load_status " << mData.readUnsignedInt() << endl; bool has_location = mData.readBit(); cout << getIndent() << "has_location " << has_location << endl; if(has_location) { describeCartesionTransformation3d(mData); } unsigned int number_of_references = mData.readUnsignedInt(); cout << getIndent() << "number_of_references " << number_of_references << endl; indent(); for(unsigned int i = 0; i < number_of_references; ++i) { //TODO: describeReferenceToPRCBase(mData); } dedent(); describeMarkups(mData); unsigned int number_of_views = mData.readUnsignedInt(); cout << getIndent() << "number_of_views " << number_of_views << endl; indent(); for(unsigned int i = 0; i < number_of_views; ++i) { describeAnnotationView(mData); } dedent(); bool has_entity_filter = mData.readBit(); cout << getIndent() << "has_entity_filter " << (has_entity_filter?"yes":"no") << endl; if(has_entity_filter) { //TODO: describeEntityFilter(mData); } unsigned int number_of_display_filters = mData.readUnsignedInt(); cout << getIndent() << "number_of_display_filters " << number_of_display_filters << endl; indent(); for(unsigned int i = 0; i < number_of_display_filters; ++i) { //TODO: describeFilter(mData); } dedent(); unsigned int number_of_scene_display_parameters = mData.readUnsignedInt(); cout << getIndent() << "number_of_scene_display_parameters " << number_of_scene_display_parameters << endl; indent(); for(unsigned int i = 0; i < number_of_scene_display_parameters; ++i) { describeSceneDisplayParameters(mData); } dedent(); describeUserData(mData); dedent(); } void describeGraphics(BitByBitData &mData) { bool sameGraphicsAsCurrent = mData.readBit(); cout << getIndent() << "Same graphics as current graphics? " << (sameGraphicsAsCurrent?"yes":"no") << endl; if(!sameGraphicsAsCurrent) { layer_index = mData.readUnsignedInt()-1; cout << getIndent() << "layer_index " << layer_index << endl; index_of_line_style = mData.readUnsignedInt()-1; cout << getIndent() << "index_of_line_style " << index_of_line_style << endl; unsigned char c1 = mData.readChar(); unsigned char c2 = mData.readChar(); behaviour_bit_field = c1 | (static_cast(c2) << 8); cout << getIndent() << "behaviour_bit_field " << behaviour_bit_field << endl; } } void describeContentPRCBaseWithGraphics(BitByBitData &mData, bool efr) { describeContentPRCBase(mData,efr); describeGraphics(mData); } void describePartDefinition(BitByBitData &mData) { cout << getIndent() << "--Part Definition--" << endl; if(!checkSectionCode(mData,PRC_TYPE_ASM_PartDefinition)) return; indent(); describeContentPRCBaseWithGraphics(mData,true); describeExtent3d(mData); unsigned int number_of_representation_items = mData.readUnsignedInt(); cout << getIndent() << "number_of_representation_items " << number_of_representation_items << endl; indent(); for(unsigned int i = 0; i < number_of_representation_items; ++i) { describeRepresentationItem(mData); } dedent(); describeMarkups(mData); unsigned int number_of_views = mData.readUnsignedInt(); cout << getIndent() << "number_of_views " << number_of_views << endl; indent(); for(unsigned int i = 0; i < number_of_views; ++i) { describeAnnotationView(mData); } dedent(); describeUserData(mData); dedent(); } void describeMarkups(BitByBitData& mData) { cout << getIndent() << "--Markups--" << endl; indent(); unsigned int number_of_linked_items = mData.readUnsignedInt(); cout << getIndent() << "number_of_linked_items " << number_of_linked_items << endl; for(unsigned int i = 0; i < number_of_linked_items; ++i) { cout << "describe linked item!" << endl; } unsigned int number_of_leaders = mData.readUnsignedInt(); cout << getIndent() << "number_of_leaders " << number_of_leaders << endl; for(unsigned int i = 0; i < number_of_leaders; ++i) { cout << "describe leader!" << endl; } unsigned int number_of_markups = mData.readUnsignedInt(); cout << getIndent() << "number_of_markups " << number_of_markups << endl; for(unsigned int i=0; i < number_of_markups; ++i) { cout << "describe markup!" << endl; } unsigned int number_of_annotation_entities = mData.readUnsignedInt(); cout << getIndent() << "number_of_annotation_entities " << number_of_annotation_entities << endl; for(unsigned int i=0; i < number_of_annotation_entities; ++i) { cout << "describe annotation entity!" << endl; } dedent(); } void describeAnnotationView(BitByBitData &mData) { cout << getIndent() << "--Annotation View--" << endl; if(!checkSectionCode(mData,PRC_TYPE_MKP_View)) return; indent(); describeContentPRCBaseWithGraphics(mData,true); unsigned int number_of_annotations = mData.readUnsignedInt(); for(unsigned int i = 0; i < number_of_annotations; ++i) { //TODO: describeReferenceUniqueIdentifier(mData); } //TODO: describePlane(mData); bool scene_display_parameters = mData.readBit(); if(scene_display_parameters) { describeSceneDisplayParameters(mData); } describeUserData(mData); dedent(); } void describeExtent3d(BitByBitData &mData) { // I suspect the order of min/max should be flipped cout << getIndent() << "Minimum" << endl; indent(); describeVector3d(mData); dedent(); cout << getIndent() << "Maximum" << endl; indent(); describeVector3d(mData); dedent(); } void describeExtent1d(BitByBitData &mData) { cout << getIndent() << "Minimum " << mData.readDouble() << endl; cout << getIndent() << "Maximum " << mData.readDouble() << endl; } void describeExtent2d(BitByBitData &mData) { cout << getIndent() << "Minimum" << endl; indent(); describeVector2d(mData); dedent(); cout << getIndent() << "Maximum" << endl; indent(); describeVector2d(mData); dedent(); } void describeVector3d(BitByBitData &mData) { double x = mData.readDouble(); double y = mData.readDouble(); double z = mData.readDouble(); cout << getIndent() << '(' << x << ',' << y << ',' << z << ')' << endl; } void describeVector2d(BitByBitData &mData) { double x = mData.readDouble(); double y = mData.readDouble(); cout << getIndent() << '(' << x << ',' << y << ')' << endl; } void describePicture(BitByBitData &mData) { cout << getIndent() << "--Picture--" << endl; unsigned int sectionCode = mData.readUnsignedInt(); if(sectionCode != PRC_TYPE_GRAPH_Picture) { cout << getIndent() << "Invalid section code." << endl; } describeContentPRCBase(mData,false); int format = mData.readInt(); switch(format) { case KEPRCPicture_PNG: cout << getIndent() << "PNG format" << endl; break; case KEPRCPicture_JPG: cout << getIndent() << "JPG format" << endl; break; case KEPRCPicture_BITMAP_RGB_BYTE: cout << getIndent() << "gzipped pixel data (see PRC base compression). Each element is a RGB triple. (3 components)" << endl; break; case KEPRCPicture_BITMAP_RGBA_BYTE: cout << getIndent() << "gzipped pixel data (see PRC base compression). Each element is a complete RGBA element. (4 components)" << endl; break; case KEPRCPicture_BITMAP_GREY_BYTE: cout << getIndent() << "gzipped pixel data (see PRC base compression). Each element is a single luminance value. (1 components)" << endl; break; case KEPRCPicture_BITMAP_GREYA_BYTE: cout << getIndent() << "gzipped pixel data (see PRC base compression). Each element is a luminance/alpha pair. (2 components)" << endl; break; default: cout << getIndent() << "Invalid picture format." << endl; break; } cout << getIndent() << "uncompressed_file_index " << mData.readUnsignedInt()-1 << endl; cout << getIndent() << "pixel width " << mData.readUnsignedInt() << endl; cout << getIndent() << "pixel height " << mData.readUnsignedInt() << endl; } void describeTextureDefinition(BitByBitData &mData) { cout << getIndent() << "--Texture Definition--" << endl; if(!checkSectionCode(mData,PRC_TYPE_GRAPH_TextureDefinition)) return; cout << getIndent() << "TODO: Can't describe textures yet." << endl; } void describeMaterial(BitByBitData &mData) { cout << getIndent() << "--Material--" << endl; unsigned int code = mData.readUnsignedInt(); if(code == PRC_TYPE_GRAPH_Material) { describeContentPRCBase(mData,true); cout << getIndent() << "index of ambient color " << mData.readUnsignedInt() - 1 << endl; cout << getIndent() << "index of diffuse color " << mData.readUnsignedInt() - 1 << endl; cout << getIndent() << "index of emissive color " << mData.readUnsignedInt() - 1 << endl; cout << getIndent() << "index of specular color " << mData.readUnsignedInt() - 1 << endl; cout << getIndent() << "shininess " << mData.readDouble() << endl; cout << getIndent() << "ambient_alpha " << mData.readDouble() << endl; cout << getIndent() << "diffuse_alpha " << mData.readDouble() << endl; cout << getIndent() << "emissive_alpha " << mData.readDouble() << endl; cout << getIndent() << "specular_alpha " << mData.readDouble() << endl; } else if(code == PRC_TYPE_GRAPH_TextureApplication) { describeContentPRCBase(mData,true); cout << getIndent() << "material_generic_index " << mData.readUnsignedInt() - 1 << endl; cout << getIndent() << "texture_definition_index " << mData.readUnsignedInt() - 1 << endl; cout << getIndent() << "next_texture_index " << mData.readUnsignedInt() - 1 << endl; cout << getIndent() << "UV_coordinates_index " << mData.readUnsignedInt() - 1 << endl; } else { cout << getIndent() << "Invalid section code in material definition." << endl; } } void describeLinePattern(BitByBitData &mData) { cout << getIndent() << "--Line Pattern--" << endl; if(!checkSectionCode(mData,PRC_TYPE_GRAPH_LinePattern)) return; indent(); describeContentPRCBase(mData,true); unsigned int size_lengths = mData.readUnsignedInt(); cout << getIndent() << "size_lengths " << size_lengths << endl; indent(); for(unsigned int i=0;i(mData.readUnsignedInt()-1) << endl; cout << getIndent() << "is_material " << (mData.readBit()?"yes":"no") << endl; cout << getIndent() << "color_index / material_index " << static_cast(mData.readUnsignedInt()-1) << endl; bool is_transparency_defined = mData.readBit(); cout << getIndent() << "is_transparency_defined " << (is_transparency_defined?"yes":"no") << endl; if(is_transparency_defined) { indent(); cout << getIndent() << "transparency " << static_cast(mData.readChar()) << endl; dedent(); } bool is_additional_1_defined = mData.readBit(); cout << getIndent() << "is_additional_1_defined " << (is_additional_1_defined?"yes":"no") << endl; if(is_additional_1_defined) { indent(); cout << getIndent() << "additional_1 " << static_cast(mData.readChar()) << endl; dedent(); } bool is_additional_2_defined = mData.readBit(); cout << getIndent() << "is_additional_2_defined " << (is_additional_2_defined?"yes":"no") << endl; if(is_additional_2_defined) { indent(); cout << getIndent() << "additional_2 " << static_cast(mData.readChar()) << endl; dedent(); } bool is_additional_3_defined = mData.readBit(); cout << getIndent() << "is_additional_3_defined " << (is_additional_3_defined?"yes":"no") << endl; if(is_additional_3_defined) { indent(); cout << getIndent() << "additional_3 " << static_cast(mData.readChar()) << endl; dedent(); } dedent(); } void describeFillPattern(BitByBitData &mData) { cout << getIndent() << "--Fill Pattern--" << endl; unsigned int type = mData.readUnsignedInt(); cout << getIndent() << "type " << type << endl; switch(type) { //TODO: actually describe fill patterns default: cout << getIndent() << "Invalid fill pattern type " << type << endl; } } void describeRepresentationItemContent(BitByBitData &mData) { describeContentPRCBaseWithGraphics(mData,true); unsigned int index_local_coordinate_system = mData.readUnsignedInt()-1; unsigned int index_tessellation = mData.readUnsignedInt()-1; //cast to int will not be right for big indices cout << getIndent() << "index_local_coordinate_system " << static_cast(index_local_coordinate_system) << endl; cout << getIndent() << "index_tessellation " << static_cast(index_tessellation) << endl; } void describeRepresentationItem(BitByBitData &mData) { cout << getIndent() << "--Representation Item--" << endl; unsigned int type = mData.readUnsignedInt(); switch(type) { case PRC_TYPE_RI_Curve: { cout << getIndent() << "--PRC_TYPE_RI_Curve--" << endl; describeRepresentationItemContent(mData); bool has_wire_body = mData.readBit(); if(has_wire_body) { cout << getIndent() << "context_id " << mData.readUnsignedInt() << endl; cout << getIndent() << "body_id " << mData.readUnsignedInt() << endl; } describeUserData(mData); break; } case PRC_TYPE_RI_PolyBrepModel: { cout << getIndent() << "--PRC_TYPE_RI_PolyBrepModel--" << endl; describeRepresentationItemContent(mData); cout << getIndent() << "is_closed " << (mData.readBit()?"yes":"no") << endl; describeUserData(mData); break; } case PRC_TYPE_RI_BrepModel: { cout << getIndent() << "--PRC_TYPE_RI_BrepModel--" << endl; describeRepresentationItemContent(mData); bool has_brep_data = mData.readBit(); cout << getIndent() << "has_brep_data " << (has_brep_data?"yes":"no") << endl; if(has_brep_data) { cout << getIndent() << "context_id " << mData.readUnsignedInt() << endl; cout << getIndent() << "object_id " << mData.readUnsignedInt() << endl; } cout << getIndent() << "is_closed " << (mData.readBit()?"yes":"no") << endl; describeUserData(mData); break; } case PRC_TYPE_RI_Direction: case PRC_TYPE_RI_Plane: case PRC_TYPE_RI_CoordinateSystem: case PRC_TYPE_RI_PointSet: case PRC_TYPE_RI_Set: case PRC_TYPE_RI_PolyWire: cout << getIndent() << "TODO: Unhandled representation item " << type << endl; break; default: cout << getIndent() << "Invalid representation item type " << type << endl; break; } } void describeRGBColour(BitByBitData &mData) { cout << getIndent() << "R: " << mData.readDouble(); cout << " G: " << mData.readDouble(); cout << " B: " << mData.readDouble() << endl; } void describeSchema(BitByBitData &mData) { cout << getIndent() << "--Schema--" << endl; indent(); unsigned int numSchemas = mData.readUnsignedInt(); cout << getIndent() << "Number of Schemas " << numSchemas << endl; if(numSchemas != 0) { cout << "Error: Don't know how to handle multiple schemas." << endl; } dedent(); } string currentName; int layer_index; int index_of_line_style; unsigned short behaviour_bit_field; void resetCurrentGraphics() { layer_index = -1; index_of_line_style = -1; behaviour_bit_field = 1; } void unFlushSerialization() { currentName = ""; resetCurrentGraphics(); } void describeName(BitByBitData &mData) { bool sameNameAsCurrent = mData.readBit(); cout << getIndent() << "Same name as current name? " << (sameNameAsCurrent?"yes":"no") << endl; if(!sameNameAsCurrent) currentName = mData.readString(); cout << getIndent() << "Name \"" << currentName << '\"' << endl; } void describeUnit(BitByBitData &mData) { cout << getIndent() << "Unit is from CAD file? " << (mData.readBit()?"yes":"no") << endl; cout << getIndent() << "Unit is " << mData.readDouble() << " mm" << endl; } void describeAttributes(BitByBitData &mData) { cout << getIndent() << "--Attributes--" << endl; indent(); unsigned int numAttribs = mData.readUnsignedInt(); cout << getIndent() << "Number of Attributes " << numAttribs << endl; indent(); for(unsigned int i = 0; i < numAttribs; ++i) { cout << getIndent() << "PRC_TYPE_MISC_Attribute " << mData.readUnsignedInt() << endl; bool titleIsInt = mData.readBit(); cout << getIndent() << "Title is integer? " << (titleIsInt?"yes":"no") << endl; indent(); if(titleIsInt) { cout << getIndent() << "Title " << mData.readUnsignedInt() << endl; } else { cout << getIndent() << "Title \"" << mData.readString() << '\"' << endl; } unsigned int sizeOfAttributeKeys = mData.readUnsignedInt(); cout << getIndent() << "Size of Attribute Keys " << sizeOfAttributeKeys << endl; for(unsigned int a = 0; a < sizeOfAttributeKeys; ++a) { bool titleIsInt = mData.readBit(); cout << getIndent() << "Title is integer? " << (titleIsInt?"yes":"no") << endl; indent(); if(titleIsInt) { cout << getIndent() << "Title " << mData.readUnsignedInt() << endl; } else { cout << getIndent() << "Title \"" << mData.readString() << '\"' << endl; } dedent(); unsigned int attributeType = mData.readUnsignedInt(); cout << getIndent() << "Attribute Type " << attributeType << endl; switch(attributeType) { case KEPRCModellerAttributeTypeInt: cout << getIndent() << "Attribute Value (int) " << mData.readInt() << endl; break; case KEPRCModellerAttributeTypeReal: cout << getIndent() << "Attribute Value (double) " << mData.readDouble() << endl; break; case KEPRCModellerAttributeTypeTime: cout << getIndent() << "Attribute Value (time_t) " << mData.readUnsignedInt() << endl; break; case KEPRCModellerAttributeTypeString: cout << getIndent() << "Attribute Value (string) \"" << mData.readString() << '\"' << endl; break; default: break; } } dedent(); cout << endl; } dedent(); dedent(); } void describeContentPRCBase(BitByBitData &mData, bool typeEligibleForReference) { cout << getIndent() << "--ContentPRCBase--" << endl; indent(); describeAttributes(mData); describeName(mData); if(typeEligibleForReference) { cout << getIndent() << "CAD_identifier " << mData.readUnsignedInt() << endl; cout << getIndent() << "CAD_persistent_identifier " << mData.readUnsignedInt() << endl; cout << getIndent() << "PRC_unique_identifier " << mData.readUnsignedInt() << endl; } dedent(); } void describeCompressedUniqueID(BitByBitData &mData) { cout << getIndent() << "UUID: " << hex << setfill('0'); for(int i = 0; i < 4; ++i) cout << setw(8) << mData.readUnsignedInt() << ' '; cout << dec << setfill(' ') << endl; } void describeUserData(BitByBitData &mData) { unsigned int bits = mData.readUnsignedInt(); cout << getIndent() << bits << " bits of user data" << endl; indent(); for(unsigned int i = 0; i < bits; ++i) { if(i%64 == 0) cout << getIndent(); cout << mData.readBit(); if(i%64 == 63) cout << endl; } if(bits%64 != 0) cout << endl; dedent(); } bool checkSectionCode(BitByBitData &mData, unsigned int code) { unsigned int num = mData.readUnsignedInt(); if(code != num) { cout << getIndent() << "Invalid section code " << num << ". Expected " << code << " at "; mData.tellPosition(); return false; } else { cout << getIndent() << "Section code " << code << endl; return true; } } unsigned int currentIndent = 0; string getIndent() { ostringstream out; for(unsigned int i = 0; i < currentIndent; ++i) out << " "; return out.str(); } void indent() { ++currentIndent; } void dedent() { --currentIndent; } asymptote-2.37/prc/PRCTools/describePRC.h000066400000000000000000000103571265434602500202360ustar00rootroot00000000000000/************ * * This file is part of a tool for reading 3D content in the PRC format. * Copyright (C) 2008 Orest Shardt * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * *************/ #ifndef __DESCRIBE_PRC_H #define __DESCRIBE_PRC_H #include "iPRCFile.h" #include "bitData.h" void describeGlobals(BitByBitData&); void describeTree(BitByBitData&); void describeTessellation(BitByBitData&); void describeGeometry(BitByBitData&); void describeExtraGeometry(BitByBitData&); void describeModelFileData(BitByBitData&,unsigned int); void describePicture(BitByBitData&); void describeTextureDefinition(BitByBitData&); void describeMaterial(BitByBitData&); void describeLinePattern(BitByBitData&); void describeCategory1LineStyle(BitByBitData&); void describeFillPattern(BitByBitData&); void describeRepresentationItem(BitByBitData&); //void describe(BitByBitData&); void describeLight(BitByBitData&); void describeCamera(BitByBitData&); bool describeContentCurve(BitByBitData&); void describeCurvCircle(BitByBitData&); void describeCurvLine(BitByBitData&); void describeCurvNURBS(BitByBitData&); void describeCurvPolyLine(BitByBitData&); void describeContentWireEdge(BitByBitData&); bool isCompressedSerialType(unsigned int); void describeUVParametrization(BitByBitData&); void describeSurfNURBS(BitByBitData&); void describeSurfCylinder(BitByBitData&); void describeSurfPlane(BitByBitData&); void describeTopoFace(BitByBitData&); void describeTopoLoop(BitByBitData&); void describeTopoCoEdge(BitByBitData&); void describeTopoEdge(BitByBitData&); void describeTopoConnex(BitByBitData&); void describeTopoShell(BitByBitData&); void describeObject(BitByBitData&); void describeBaseTopology(BitByBitData&); void describeBaseGeometry(BitByBitData&); unsigned int describeContentBody(BitByBitData&); void describeContentSurface(BitByBitData&); void describeBody(BitByBitData&); void describeTopoContext(BitByBitData&); void describeLineAttr(BitByBitData&); void describeArrayRGBA(BitByBitData&,int,int); void describeContentBaseTessData(BitByBitData&); void describeTessFace(BitByBitData&); void describe3DTess(BitByBitData&); void describe3DWireTess(BitByBitData&); void describe3DMarkupTess(BitByBitData&); void describeHighlyCompressed3DTess(BitByBitData&); void describeSceneDisplayParameters(BitByBitData&); void describeCartesionTransformation3d(BitByBitData&); void describeTransformation3d(BitByBitData&); void describeTransformation2d(BitByBitData&); void describeFileStructureInternalData(BitByBitData&); void describeProductOccurrence(BitByBitData&); void describeRepresentationItemContent(BitByBitData&); void describeMarkups(BitByBitData&); void describeAnnotationView(BitByBitData&); void describeExtent3d(BitByBitData&); void describeExtent2d(BitByBitData&); void describeExtent1d(BitByBitData&); void describeVector3d(BitByBitData&); void describeVector2d(BitByBitData&); void describeContentPRCBaseWithGraphics(BitByBitData&,bool); void describeGraphics(BitByBitData&); void describePartDefinition(BitByBitData&); void describeRGBColour(BitByBitData&); void describeSchema(BitByBitData&); void describeName(BitByBitData&); void describeAttributes(BitByBitData&); void describeContentPRCBase(BitByBitData&,bool); void describeUnit(BitByBitData&); void describeCompressedUniqueID(BitByBitData&); void describeUserData(BitByBitData&); extern std::string currentName; extern int layer_index; extern int index_of_line_style; extern unsigned short behaviour_bit_field; void unFlushSerialization(); void resetCurrentGraphics(); bool checkSectionCode(BitByBitData&,unsigned int); std::string getIndent(); void indent(); void dedent(); #endif // __DESCRIBE_PRC_H asymptote-2.37/prc/PRCTools/extractSections.cc000066400000000000000000000024361265434602500214300ustar00rootroot00000000000000/************ * * This file is part of a tool for reading 3D content in the PRC format. * Copyright (C) 2008 Orest Shardt * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * *************/ #include #include #include "iPRCFile.h" using namespace std; int main(int argc, char* argv[]) { if(argc < 2) { cerr << "Error: Input file not specified." << endl; return 1; } ifstream inFile(argv[1]); if(!inFile) { cerr << "Error: Cannot open input file." << endl; return 1; } iPRCFile myFile(inFile); string name(argv[1]); myFile.dumpSections(name.substr(0,name.find(".")).c_str()); return 0; } asymptote-2.37/prc/PRCTools/iPRCFile.cc000066400000000000000000000211301265434602500176330ustar00rootroot00000000000000/************ * * This file is part of a tool for reading 3D content in the PRC format. * Copyright (C) 2008 Orest Shardt * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * *************/ #include "bitData.h" #include "iPRCFile.h" #include "describePRC.h" using std::vector; using std::istream; using std::ios; using std::cout; using std::endl; using std::cerr; using std::string; using std::ofstream; using std::ostringstream; void iPRCFile::dumpSections(string prefix) { ofstream out; for(unsigned int i = 0; i < fileStructures.size(); ++i) { ostringstream name; name << prefix << "Structure" << i; out.open((name.str()+"-Globals.bin").c_str()); out.write(fileStructures[i].sections[GLOBALS_SECTION],fileStructures[i].sectionLengths[GLOBALS_SECTION]); out.close(); out.open((name.str()+"-Tree.bin").c_str()); out.write(fileStructures[i].sections[TREE_SECTION],fileStructures[i].sectionLengths[TREE_SECTION]); out.close(); out.open((name.str()+"-Tessellation.bin").c_str()); out.write(fileStructures[i].sections[TESSELLATION_SECTION],fileStructures[i].sectionLengths[TESSELLATION_SECTION]); out.close(); out.open((name.str()+"-Geometry.bin").c_str()); out.write(fileStructures[i].sections[GEOMETRY_SECTION],fileStructures[i].sectionLengths[GEOMETRY_SECTION]); out.close(); out.open((name.str()+"-ExtraGeometry.bin").c_str()); out.write(fileStructures[i].sections[EXTRA_GEOMETRY_SECTION],fileStructures[i].sectionLengths[EXTRA_GEOMETRY_SECTION]); out.close(); } out.open((prefix+"-ModelFile.bin").c_str()); out.write(modelFileData,modelFileLength); out.close(); } void iPRCFile::describe() { /* for(int i = 0; i < modelFileLength; ++i) { cout << ' ' << std::hex << std::setw(2) << std::setfill('0') << static_cast(static_cast(mfd.readChar())); if(i%16 == 15) cout << endl; } cout << endl; */ unFlushSerialization(); for(unsigned int i = 0; i < fileStructures.size(); ++i) { cout << "File Structure " << i << ":" << endl; //describe header char *header = buffer + fileStructureInfos[i].offsets[0]; cout << "--Header Section--" << endl; cout << " Signature " << header[0] << header[1] << header[2] << endl; cout << " Minimal version for read " << *(unsigned int*)(header+3) << endl; cout << " Authoring version " << *(unsigned int*)(header+7) << endl; cout << std::hex; cout << " File structure UUID " << *(unsigned int*)(header+11) << ' ' << *(unsigned int*)(header+15) << ' ' << *(unsigned int*)(header+19) << ' ' << *(unsigned int*)(header+23) << endl; cout << " Application UUID " << *(unsigned int*)(header+27) << ' ' << *(unsigned int*)(header+31) << ' ' << *(unsigned int*)(header+35) << ' ' << *(unsigned int*)(header+39) << endl; cout << std::dec; // uncompressed files unsigned int numberOfUncompressedFiles = *(unsigned int*)(header+43); cout << "Number of uncompressed files " << numberOfUncompressedFiles << endl; char *position = header+47; for(unsigned int j = 0; j < numberOfUncompressedFiles; ++j) { cout << "Uncompressed file " << j << ":" << endl; unsigned int size = *(unsigned int*)position; cout << " size " << size << " bytes" << endl; position += size+sizeof(unsigned int); } BitByBitData fileStruct(fileStructures[i].sections[GLOBALS_SECTION],fileStructures[i].sectionLengths[GLOBALS_SECTION]); describeSchema(fileStruct); describeGlobals(fileStruct); unFlushSerialization(); fileStruct = BitByBitData(fileStructures[i].sections[TREE_SECTION],fileStructures[i].sectionLengths[TREE_SECTION]); describeTree(fileStruct); unFlushSerialization(); fileStruct = BitByBitData(fileStructures[i].sections[TESSELLATION_SECTION],fileStructures[i].sectionLengths[TESSELLATION_SECTION]); describeTessellation(fileStruct); unFlushSerialization(); fileStruct = BitByBitData(fileStructures[i].sections[GEOMETRY_SECTION],fileStructures[i].sectionLengths[GEOMETRY_SECTION]); describeGeometry(fileStruct); unFlushSerialization(); fileStruct = BitByBitData(fileStructures[i].sections[EXTRA_GEOMETRY_SECTION],fileStructures[i].sectionLengths[EXTRA_GEOMETRY_SECTION]); describeExtraGeometry(fileStruct); unFlushSerialization(); } BitByBitData mfd(modelFileData,modelFileLength); describeSchema(mfd); describeModelFileData(mfd,fileStructures.size()); unFlushSerialization(); } iPRCFile::iPRCFile(istream& in) { char PRC[3]; in.read(PRC,3); if(PRC[0] != 'P' || PRC[1] != 'R' || PRC[2] != 'C') { cerr << "Error: Invalid file format: PRC not found." << endl; } unsigned int versionForRead,authoringVersion; in.read((char*)&versionForRead,sizeof(versionForRead)); in.read((char*)&authoringVersion,sizeof(authoringVersion)); cout << "Version for reading " << versionForRead << endl; cout << "Authoring version " << authoringVersion << endl; unsigned int fileStructureUUID[4]; in.read((char*)fileStructureUUID,sizeof(fileStructureUUID)); //(void*) is for formatting cout << "File structure UUID " << (void*)(fileStructureUUID[0]) << ' ' << (void*)(fileStructureUUID[1]) << ' ' << (void*)(fileStructureUUID[2]) << ' ' << (void*)(fileStructureUUID[3]) << endl; unsigned int applicationUUID[4]; in.read((char*)applicationUUID,sizeof(applicationUUID)); cout << "Application UUID " << (void*)(applicationUUID[0]) << ' ' << (void*)(applicationUUID[1]) << ' ' << (void*)(applicationUUID[2]) << ' ' << (void*)(applicationUUID[3]) << endl; unsigned int numberOfFileStructures; in.read((char*)&numberOfFileStructures,sizeof(numberOfFileStructures)); cout << "number of file structures " << numberOfFileStructures << endl; // load fileStructureInformation for(unsigned int fsi = 0; fsi < numberOfFileStructures; ++fsi) { FileStructureInformation info; in.read((char*)&info.UUID,sizeof(info.UUID)); cout << "\tFile structure UUID " << (void*)(info.UUID[0]) << ' ' << (void*)(info.UUID[1]) << ' ' << (void*)(info.UUID[2]) << ' ' << (void*)(info.UUID[3]) << endl; in.read((char*)&info.reserved,sizeof(info.reserved)); cout << "\tReserved " << info.reserved << endl; unsigned int numberOfOffsets; in.read((char*)&numberOfOffsets,sizeof(numberOfOffsets)); cout << "\tNumber of Offsets " << numberOfOffsets << endl; for(unsigned int oi = 0; oi < numberOfOffsets; ++oi) { unsigned int offset; in.read((char*)&offset,sizeof(offset)); info.offsets.push_back(offset); cout << "\t\tOffset " << offset << endl; } fileStructureInfos.push_back(info); } in.read((char*)&modelFileOffset,sizeof(modelFileOffset)); cout << "Model file offset " << modelFileOffset << endl; in.read((char*)&fileSize,sizeof(fileSize)); // this is not documented cout << "File size " << fileSize << endl; in.read((char*)&numberOfUncompressedFiles,sizeof(numberOfUncompressedFiles)); cout << "Number of uncompressed files " << numberOfUncompressedFiles << endl; for(unsigned int ufi = 0; ufi < numberOfUncompressedFiles; ++ufi) { unsigned int size; in.read((char*)&size,sizeof(size)); in.seekg(size,ios::cur); } //read the whole file into memory in.seekg(0,ios::beg); buffer = new char[fileSize]; if(!buffer) cerr << "Couldn't get memory." << endl; in.read(buffer,fileSize); //decompress fileStructures for(unsigned int fs = 0; fs < fileStructureInfos.size(); ++fs) { fileStructures.push_back(FileStructure()); for(unsigned int i = 1; i < fileStructureInfos[fs].offsets.size(); ++i) // start at 1 since header is decompressed { fileStructures[fs].sections[i-1] = NULL; unsigned int offset = fileStructureInfos[fs].offsets[i]; fileStructures[fs].sectionLengths[i-1] = decompress(buffer+offset,fileSize-offset,fileStructures[fs].sections[i-1]); } } //decompress modelFileData modelFileData = NULL; modelFileLength = decompress(buffer+modelFileOffset,fileSize-modelFileOffset,modelFileData); } asymptote-2.37/prc/PRCTools/iPRCFile.h000066400000000000000000000044451265434602500175070ustar00rootroot00000000000000/************ * * This file is part of a tool for reading 3D content in the PRC format. * Copyright (C) 2008 Orest Shardt * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * *************/ #ifndef __READPRC_H #define __READPRC_H #include #include #include #include #include #include #include "../PRC.h" #include "inflation.h" struct FileStructureInformation { unsigned int UUID[4]; unsigned int reserved; std::vector offsets; }; const int GLOBALS_SECTION = 0; const int TREE_SECTION = 1; const int TESSELLATION_SECTION = 2; const int GEOMETRY_SECTION = 3; const int EXTRA_GEOMETRY_SECTION = 4; struct FileStructure { unsigned int readVersion; unsigned int authoringVersion; unsigned int fileUUID[4]; unsigned int appUUID[4]; char* sections[5]; unsigned int sectionLengths[5]; }; class iPRCFile { public: iPRCFile(std::istream&); ~iPRCFile() { for(unsigned int i = 0; i < fileStructures.size(); ++i) for(unsigned int j = 0; j < 5; ++j) if(fileStructures[i].sections[j] != NULL) free(fileStructures[i].sections[j]); if(modelFileData!=NULL) free(modelFileData); if(buffer != 0) delete[] buffer; } void describe(); void dumpSections(std::string); private: // header data std::vector fileStructureInfos; std::vector fileStructures; unsigned int modelFileOffset; char* modelFileData; unsigned int modelFileLength; char *buffer; unsigned int fileSize; unsigned int numberOfUncompressedFiles; }; #endif // __READPRC_H asymptote-2.37/prc/PRCTools/inflation.cc000066400000000000000000000043441265434602500202310ustar00rootroot00000000000000/************ * * This file is part of a tool for reading 3D content in the PRC format. * Copyright (C) 2008 Orest Shardt * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * *************/ #include "inflation.h" using std::istream; using std::ios; using std::cout; using std::cerr; using std::endl; using std::exit; int decompress(char* inb, int fileLength, char* &outb) { const int CHUNK = 16384; unsigned int resultSize = 0; outb = (char*) realloc(outb,CHUNK); z_stream strm; strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.avail_in = fileLength; strm.next_in = (unsigned char*)inb; strm.opaque = Z_NULL; int code = inflateInit(&strm); if(code != Z_OK) return -1; strm.next_out = (unsigned char*)outb; strm.avail_out = CHUNK; code = inflate(&strm,Z_NO_FLUSH); resultSize = CHUNK-strm.avail_out; unsigned int size = CHUNK; while(code == Z_OK) { outb = (char*) realloc(outb,2*size); if(outb == NULL) { cerr << "Ran out of memory while decompressing." << endl; exit(1); } strm.next_out = (Bytef*)(outb + resultSize); strm.avail_out += size; size *= 2; code = inflate(&strm,Z_NO_FLUSH); resultSize = size - strm.avail_out; } code = inflateEnd(&strm); if(code != Z_OK) { free(outb); return 0; } return resultSize; } int decompress(istream &input,char* &result) { input.seekg(0,ios::end); int fileLength = input.tellg(); input.seekg(0,ios::beg); char *inb = new char[fileLength]; input.read(inb,fileLength); int code = decompress(inb,fileLength,result); delete[] inb; return code; } asymptote-2.37/prc/PRCTools/inflation.h000066400000000000000000000020331265434602500200640ustar00rootroot00000000000000/************ * * This file is part of a tool for reading 3D content in the PRC format. * Copyright (C) 2008 Orest Shardt * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * *************/ #ifndef __INFLATION_H #define __INFLATION_H #include #include #include int decompress(std::istream&,char*&); int decompress(char*,int,char*&); #endif // __INFLATION_H asymptote-2.37/prc/PRCTools/inflationMain.cc000066400000000000000000000027071265434602500210370ustar00rootroot00000000000000/************ * * This file is part of a tool for reading 3D content in the PRC format. * Copyright (C) 2008 Orest Shardt * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * *************/ #include #include #include #include #include "inflation.h" using namespace std; int main(int argc, char *argv[]) { if(argc < 2) { cerr << "No file specified." << endl; return 1; } ifstream data(argv[1]); char *buff = NULL; int dataSize = decompress(data,buff); cout << hex; for(int i = 0; i < dataSize; ++i) { cout << ' ' << setw(2) << setfill('0') << static_cast(static_cast(buff[i])); if(i%16 == 15) cout << endl; } cout << endl << dec << dataSize << " bytes" << endl; free(buff); return 0; } asymptote-2.37/prc/PRCTools/makePRC.cc000066400000000000000000000111541265434602500175250ustar00rootroot00000000000000/************ * * This file is part of a tool for producing 3D content in the PRC format. * Copyright (C) 2008 Orest Shardt * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * *************/ #include #include #include #include #include #include "../oPRCFile.h" using namespace std; void readPoints(istream &is, unsigned int n, double p[][3]) { for(unsigned int i = 0; i < n; ++i) { is >> p[i][0] >> p[i][1] >> p[i][2]; } if(!is) { cerr << "Error reading list of points." << endl; exit(1); } } void readDoubles(istream &is, unsigned int n, double d[]) { for(unsigned int i = 0; i < n; ++i) { is >> d[i]; } if(!is) { cerr << "Error reading list of doubles." << endl; exit(1); } } int main(int argc, char **argv) { const char *oFileName = "output.prc"; int c; opterr = 0; while ((c = getopt (argc, argv, "o:")) != -1) switch (c) { case 'o': oFileName = optarg; break; case '?': if (optopt == 'o') cerr << "Option '-o' requires an argument, the filename." << endl; else cerr << "Unrecognized option '-" << (char)optopt << "'." << endl; exit(1); break; default: exit(1); } istream *ins = NULL; if(optind < argc) { ins = new ifstream(argv[optind]); if(!*ins) { cerr << "Error opening input file " << argv[optind] << endl; exit(1); } } else { ins = &cin; } ofstream outf(oFileName); if(!outf) { cerr << "Error opening output file " << oFileName << endl; exit(1); } oPRCFile oPRC(outf); string entityType; while(*ins) { *ins >> entityType; if(!*ins) break; if(entityType == "Line") { double r,g,b,a; unsigned int numberOfPoints; *ins >> r >> g >> b >> a >> numberOfPoints; if(!*ins) { cerr << "Error reading line data." << endl; exit(1); } else { double (*points)[3] = new double[numberOfPoints][3]; readPoints(*ins,numberOfPoints,points); oPRC.add(new PRCline(&oPRC,numberOfPoints,points, *new RGBAColour(r,g,b,a))); } } else if(entityType == "Curve") { double r,g,b,a; unsigned int numberOfPoints; unsigned int degree; *ins >> r >> g >> b >> a >> degree >> numberOfPoints; if(!*ins) { cerr << "Error reading curve data." << endl; exit(1); } else { double (*points)[3] = new double[numberOfPoints][3]; double *knots = new double[degree+numberOfPoints+1]; readPoints(*ins,numberOfPoints,points); readDoubles(*ins,degree+numberOfPoints+1,knots); oPRC.add(new PRCcurve(&oPRC,degree,numberOfPoints,points, knots,*new RGBAColour(r,g,b,a))); } } else if(entityType == "Surface") { double r,g,b,a; unsigned int numberOfPointsU,numberOfPointsV; unsigned int degreeU,degreeV; *ins >> r >> g >> b >> a >> degreeU >> degreeV >> numberOfPointsU >> numberOfPointsV; if(!*ins) { cerr << "Error reading surface data." << endl; exit(1); } else { double (*points)[3] = new double[numberOfPointsU*numberOfPointsV][3]; double *knotsU = new double[degreeU+numberOfPointsU+1]; double *knotsV = new double[degreeV+numberOfPointsV+1]; readPoints(*ins,numberOfPointsU*numberOfPointsV,points); readDoubles(*ins,degreeU+numberOfPointsU+1,knotsU); readDoubles(*ins,degreeV+numberOfPointsV+1,knotsV); oPRC.add(new PRCsurface(&oPRC,degreeU,degreeV,numberOfPointsU, numberOfPointsV,points,knotsU,knotsV, *new RGBAColour(r,g,b,a))); } } else { cerr << "Unrecognized entity type " << entityType << endl; exit(1); } } if(ins && ins != &cin) delete ins; oPRC.finish(); outf.close(); return 0; } asymptote-2.37/prc/PRCbitStream.cc000066400000000000000000000202631265434602500170760ustar00rootroot00000000000000/************ * * This file is part of a tool for producing 3D content in the PRC format. * Copyright (C) 2008 Orest Shardt and * Michail Vidiassov * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * *************/ #include #include #include #include #include #include "PRCbitStream.h" #include "PRCdouble.h" using std::string; using std::cerr; using std::endl; void PRCbitStream::compress() { const int CHUNK= 1024; // is this reasonable? compressedDataSize = 0; z_stream strm; strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL; if(deflateInit(&strm,Z_DEFAULT_COMPRESSION) != Z_OK) { cerr << "Compression initialization failed" << endl; return; } unsigned int sizeAvailable = deflateBound(&strm,getSize()); uint8_t *compressedData = (uint8_t*) malloc(sizeAvailable); strm.avail_in = getSize(); strm.next_in = (unsigned char*)data; strm.next_out = (unsigned char*)compressedData; strm.avail_out = sizeAvailable; int code; unsigned int chunks = 0; while((code = deflate(&strm,Z_FINISH)) == Z_OK) { ++chunks; // strm.avail_out should be 0 if we got Z_OK compressedDataSize = sizeAvailable - strm.avail_out; compressedData = (uint8_t*) realloc(compressedData,CHUNK*chunks); strm.next_out = (Bytef*)(compressedData + compressedDataSize); strm.avail_out += CHUNK; sizeAvailable += CHUNK; } compressedDataSize = sizeAvailable-strm.avail_out; if(code != Z_STREAM_END) { cerr << "Compression error" << endl; deflateEnd(&strm); free(compressedData); return; } compressed = true; free(data); data = compressedData; deflateEnd(&strm); } void PRCbitStream::write(std::ostream &out) const { if(compressed) { out.write((char*)data,compressedDataSize); } else { cerr << "Attempt to write stream before compression." << endl; exit(1); } } unsigned int PRCbitStream::getSize() const { if(compressed) return compressedDataSize; else return byteIndex+1; } uint8_t* PRCbitStream::getData() { return data; } PRCbitStream& PRCbitStream::operator <<(bool b) { writeBit(b); return *this; } PRCbitStream& PRCbitStream::operator <<(uint32_t u) { while(u != 0) { writeBit(1); writeByte(u & 0xFF); u >>= 8; } writeBit(0); return *this; } PRCbitStream& PRCbitStream::operator <<(uint8_t u) { writeByte(u); return *this; } PRCbitStream& PRCbitStream::operator <<(int32_t i) { uint8_t lastByte = 0; //while(!((current value is 0 and last byte was positive) OR (current value is -1 and last value was negative))) while(!(((i == 0)&&((lastByte & 0x80)==0))||((i == -1)&&((lastByte & 0x80) != 0)))) { writeBit(1); lastByte = i & 0xFF; writeByte(lastByte); i >>= 8; } writeBit(0); return *this; } PRCbitStream& PRCbitStream::operator <<(double value) { // write a double if(compressed) { cerr << "Cannot write to a stream that has been compressed." << endl; return *this; } union ieee754_double *pid=(union ieee754_double *)&value; int i, fSaveAtEnd; PRCbyte *pb, *pbStart, *pbStop, *pbEnd, *pbResult, bSaveAtEnd = 0; struct sCodageOfFrequentDoubleOrExponent cofdoe, *pcofdoe; cofdoe.u2uod.Value=value; pcofdoe = (struct sCodageOfFrequentDoubleOrExponent *)bsearch( &cofdoe, acofdoe, sizeof(acofdoe)/sizeof(pcofdoe[0]), sizeof(pcofdoe[0]), stCOFDOECompare); while(pcofdoe>acofdoe && EXPONENT(pcofdoe->u2uod.Value)==EXPONENT((pcofdoe-1)->u2uod.Value)) pcofdoe--; assert(pcofdoe); while(pcofdoe->Type==VT_double) { if(fabs(value)==pcofdoe->u2uod.Value) break; pcofdoe++; } for(i=1<<(pcofdoe->NumberOfBits-1);i>=1;i>>=1) writeBit((pcofdoe->Bits&i)!=0); if ( !memcmp(&value,stadwZero,sizeof(value)) || !memcmp(&value,stadwNegativeZero,sizeof(value)) ) return *this; writeBit(pid->ieee.negative); if(pcofdoe->Type==VT_double) return *this; if(pid->ieee.mantissa0==0 && pid->ieee.mantissa1==0) { writeBit(0); return *this; } writeBit(1); #ifdef WORDS_BIGENDIAN pb=((PRCbyte *)&value)+1; #else pb=((PRCbyte *)&value)+6; #endif //add_bits((*pb)&0x0f,4 STAT_V STAT_DOUBLE); writeBits((*pb)&0x0F,4); NEXTBYTE(pb); pbStart=pb; #ifdef WORDS_BIGENDIAN pbEnd= pbStop= ((PRCbyte *)(&value+1))-1; #else pbEnd= pbStop= ((PRCbyte *)&value); #endif if((fSaveAtEnd=(*pbStop!=*BEFOREBYTE(pbStop)))!=0) bSaveAtEnd=*pbEnd; PREVIOUSBYTE(pbStop); while(*pbStop==*BEFOREBYTE(pbStop)) PREVIOUSBYTE(pbStop); for(;MOREBYTE(pb,pbStop);NEXTBYTE(pb)) { if(pb!=pbStart && (pbResult=SEARCHBYTE(BEFOREBYTE(pb),*pb,DIFFPOINTERS(pb,pbStart)))!=NULL) { writeBit(0); writeBits(DIFFPOINTERS(pb,pbResult),3); } else { writeBit(1); writeByte(*pb); } } if(!MOREBYTE(BEFOREBYTE(pbEnd),pbStop)) { if(fSaveAtEnd) { writeBit(0); writeBits(6,3); writeByte(bSaveAtEnd); } else { writeBit(0); writeBits(0,3); } } else { if((pbResult=SEARCHBYTE(BEFOREBYTE(pb),*pb,DIFFPOINTERS(pb,pbStart)))!=NULL) { writeBit(0); writeBits(DIFFPOINTERS(pb,pbResult),3); } else { writeBit(1); writeByte(*pb); } } return *this; } PRCbitStream& PRCbitStream::operator <<(const char* s) { if (s == NULL) { writeBit(false); // string is NULL return *this; } string str(s); *this << str; return *this; } PRCbitStream& PRCbitStream::operator <<(const string& s) { if(s == "") { writeBit(false); // string is NULL return *this; } writeBit(true); size_t l = s.length(); *this << static_cast(l); for(size_t i = 0; i < l; ++i) writeByte(s[i]); return *this; } void PRCbitStream::writeBit(bool b) { if(compressed) { cerr << "Cannot write to a stream that has been compressed." << endl; return; } if(b) { data[byteIndex] |= (0x80 >> bitIndex); } nextBit(); } void PRCbitStream::writeBits(uint32_t u, uint8_t bits) { if(bits > 32) return; else { for(uint32_t mask = (1 << (bits-1)); mask != 0; mask >>= 1) { writeBit((u&mask) != 0); } } } void PRCbitStream::writeByte(uint8_t u) { if(compressed) { cerr << "Cannot write to a stream that has been compressed." << endl; return; } if(bitIndex == 0) { data[byteIndex] = u; nextByte(); } else { data[byteIndex] |= (u >> bitIndex); unsigned int obi = bitIndex; nextByte(); data[byteIndex] |= (u << (8-obi)); bitIndex = obi; // bit index is not changed by writing 8 bits } } void PRCbitStream::nextBit() { ++bitIndex; if(bitIndex == 8) { nextByte(); } } void PRCbitStream::nextByte() { ++byteIndex; if(byteIndex >= allocatedLength) getAChunk(); data[byteIndex] = 0; // clear the garbage data bitIndex = 0; } void PRCbitStream::getAChunk() { if(allocatedLength==0) data = (uint8_t*)realloc((void*)data,CHUNK_SIZE); else data = (uint8_t*)realloc((void*)data,2*allocatedLength); if(data != NULL) { if(allocatedLength==0) { allocatedLength = CHUNK_SIZE; *data = 0; // clear first byte } else allocatedLength *= 2; } else { // warn about memory problem! cerr << "Memory allocation error." << endl; exit(1); } } asymptote-2.37/prc/PRCbitStream.h000066400000000000000000000047261265434602500167460ustar00rootroot00000000000000/************ * * This file is part of a tool for producing 3D content in the PRC format. * Copyright (C) 2008 Orest Shardt and * Michail Vidiassov * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * *************/ #ifndef __PRC_BIT_STREAM_H #define __PRC_BIT_STREAM_H #ifdef _MSC_VER #include #if _MSC_VER >= 1600 #include #else typedef signed char int8_t; typedef signed short int16_t; typedef signed long int32_t; typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned long uint32_t; #endif // _MSC_VER >= 1600 #else #include #endif // _MSC_VER #include #include #include #define CHUNK_SIZE (1024) // Is this a reasonable initial size? class PRCbitStream { public: PRCbitStream(uint8_t*& buff, unsigned int l) : byteIndex(0), bitIndex(0), allocatedLength(l), data(buff), compressed(false) { if(data == 0) { getAChunk(); } } unsigned int getSize() const; uint8_t* getData(); PRCbitStream& operator <<(const std::string&); PRCbitStream& operator <<(bool); PRCbitStream& operator <<(uint32_t); PRCbitStream& operator <<(uint8_t); PRCbitStream& operator <<(int32_t); PRCbitStream& operator <<(double); PRCbitStream& operator <<(const char*); void compress(); void write(std::ostream &out) const; private: void writeBit(bool); void writeBits(uint32_t,uint8_t); void writeByte(uint8_t); void nextByte(); void nextBit(); void getAChunk(); // bitIndex is "big endian", zero based, location of next bit to write unsigned int byteIndex,bitIndex; unsigned int allocatedLength; uint8_t*& data; bool compressed; uint32_t compressedDataSize; }; #endif // __PRC_BIT_STREAM_H asymptote-2.37/prc/PRCdouble.cc000066400000000000000000005321361265434602500164250ustar00rootroot00000000000000#include "PRCdouble.h" // from Adobe's documentation PRCdword stadwZero[2]={DOUBLEWITHTWODWORD(0x00000000,0x00000000)}; PRCdword stadwNegativeZero[2]={DOUBLEWITHTWODWORD(0x80000000,0x00000000)}; struct sCodageOfFrequentDoubleOrExponent* getcofdoe(unsigned Bits, short NumberOfBits) { struct sCodageOfFrequentDoubleOrExponent *pcofdoe; for(pcofdoe=acofdoe; pcofdoe < acofdoe+NUMBEROFELEMENTINACOFDOE; ++pcofdoe) { if(pcofdoe->NumberOfBits == NumberOfBits && pcofdoe->Bits == Bits) return pcofdoe; } return NULL; } int stCOFDOECompare(const void* pcofdoe1,const void* pcofdoe2) { return(EXPONENT(((const struct sCodageOfFrequentDoubleOrExponent *)pcofdoe1)->u2uod.Value)- EXPONENT(((const struct sCodageOfFrequentDoubleOrExponent *)pcofdoe2)->u2uod.Value)); } #ifdef WORDS_BIGENDIAN #ifndef HAVE_MEMRCHR void *memrchr(const void *buf,int c,size_t count) { unsigned char *pcBuffer=(unsigned char *)buf, *pcBufferEnd=pcBuffer-count; for(;pcBuffer>pcBufferEnd;pcBuffer--) if(*pcBuffer==c) return(pcBuffer); return(NULL); } #endif #endif sCodageOfFrequentDoubleOrExponent acofdoe[NUMBEROFELEMENTINACOFDOE] = { {VT_double,2,0x1,{DOUBLEWITHTWODWORDINTREE(0x00000000,0x00000000)}}, {VT_exponent,22,0xd1d32,{DOUBLEWITHTWODWORDINTREE(0x00000000,0x00000000)}}, {VT_exponent,22,0xd1d33,{DOUBLEWITHTWODWORDINTREE(0x00100000,0x00000000)}}, {VT_exponent,22,0xf78d8,{DOUBLEWITHTWODWORDINTREE(0x00200000,0x00000000)}}, {VT_exponent,22,0xf78d9,{DOUBLEWITHTWODWORDINTREE(0x00300000,0x00000000)}}, {VT_exponent,22,0xf78da,{DOUBLEWITHTWODWORDINTREE(0x00400000,0x00000000)}}, {VT_exponent,22,0xf78db,{DOUBLEWITHTWODWORDINTREE(0x00500000,0x00000000)}}, {VT_exponent,22,0xf78dc,{DOUBLEWITHTWODWORDINTREE(0x00600000,0x00000000)}}, {VT_exponent,22,0xf78dd,{DOUBLEWITHTWODWORDINTREE(0x00700000,0x00000000)}}, {VT_exponent,22,0xf78de,{DOUBLEWITHTWODWORDINTREE(0x00800000,0x00000000)}}, {VT_exponent,22,0xf78df,{DOUBLEWITHTWODWORDINTREE(0x00900000,0x00000000)}}, {VT_exponent,22,0xf78e0,{DOUBLEWITHTWODWORDINTREE(0x00a00000,0x00000000)}}, {VT_exponent,22,0xf78e1,{DOUBLEWITHTWODWORDINTREE(0x00b00000,0x00000000)}}, {VT_exponent,22,0xf78e2,{DOUBLEWITHTWODWORDINTREE(0x00c00000,0x00000000)}}, {VT_exponent,22,0xf78e3,{DOUBLEWITHTWODWORDINTREE(0x00d00000,0x00000000)}}, {VT_exponent,22,0xf78e4,{DOUBLEWITHTWODWORDINTREE(0x00e00000,0x00000000)}}, {VT_exponent,22,0xf78e5,{DOUBLEWITHTWODWORDINTREE(0x00f00000,0x00000000)}}, {VT_exponent,22,0xf78e6,{DOUBLEWITHTWODWORDINTREE(0x01000000,0x00000000)}}, {VT_exponent,22,0xf78e7,{DOUBLEWITHTWODWORDINTREE(0x01100000,0x00000000)}}, {VT_exponent,22,0xf78e8,{DOUBLEWITHTWODWORDINTREE(0x01200000,0x00000000)}}, {VT_exponent,22,0xf78e9,{DOUBLEWITHTWODWORDINTREE(0x01300000,0x00000000)}}, {VT_exponent,22,0xf78ea,{DOUBLEWITHTWODWORDINTREE(0x01400000,0x00000000)}}, {VT_exponent,22,0xf78eb,{DOUBLEWITHTWODWORDINTREE(0x01500000,0x00000000)}}, {VT_exponent,22,0xf78ec,{DOUBLEWITHTWODWORDINTREE(0x01600000,0x00000000)}}, {VT_exponent,22,0xf78ed,{DOUBLEWITHTWODWORDINTREE(0x01700000,0x00000000)}}, {VT_exponent,22,0xf78ee,{DOUBLEWITHTWODWORDINTREE(0x01800000,0x00000000)}}, {VT_exponent,22,0xf78ef,{DOUBLEWITHTWODWORDINTREE(0x01900000,0x00000000)}}, {VT_exponent,22,0xf78f0,{DOUBLEWITHTWODWORDINTREE(0x01a00000,0x00000000)}}, {VT_exponent,22,0xf78f1,{DOUBLEWITHTWODWORDINTREE(0x01b00000,0x00000000)}}, {VT_exponent,22,0xf78f2,{DOUBLEWITHTWODWORDINTREE(0x01c00000,0x00000000)}}, {VT_exponent,22,0xf78f3,{DOUBLEWITHTWODWORDINTREE(0x01d00000,0x00000000)}}, {VT_exponent,22,0xf78f4,{DOUBLEWITHTWODWORDINTREE(0x01e00000,0x00000000)}}, {VT_exponent,22,0xf78f5,{DOUBLEWITHTWODWORDINTREE(0x01f00000,0x00000000)}}, {VT_exponent,22,0xf78f6,{DOUBLEWITHTWODWORDINTREE(0x02000000,0x00000000)}}, {VT_exponent,22,0xf78f7,{DOUBLEWITHTWODWORDINTREE(0x02100000,0x00000000)}}, {VT_exponent,22,0xf78f8,{DOUBLEWITHTWODWORDINTREE(0x02200000,0x00000000)}}, {VT_exponent,22,0xf78f9,{DOUBLEWITHTWODWORDINTREE(0x02300000,0x00000000)}}, {VT_exponent,22,0xf78fa,{DOUBLEWITHTWODWORDINTREE(0x02400000,0x00000000)}}, {VT_exponent,22,0xf78fb,{DOUBLEWITHTWODWORDINTREE(0x02500000,0x00000000)}}, {VT_exponent,22,0xf78fc,{DOUBLEWITHTWODWORDINTREE(0x02600000,0x00000000)}}, {VT_exponent,22,0xf78fd,{DOUBLEWITHTWODWORDINTREE(0x02700000,0x00000000)}}, {VT_exponent,22,0xf78fe,{DOUBLEWITHTWODWORDINTREE(0x02800000,0x00000000)}}, {VT_exponent,22,0xf78ff,{DOUBLEWITHTWODWORDINTREE(0x02900000,0x00000000)}}, {VT_exponent,22,0x3a8300,{DOUBLEWITHTWODWORDINTREE(0x02a00000,0x00000000)}}, {VT_exponent,22,0x3a8301,{DOUBLEWITHTWODWORDINTREE(0x02b00000,0x00000000)}}, {VT_exponent,22,0x3a8302,{DOUBLEWITHTWODWORDINTREE(0x02c00000,0x00000000)}}, {VT_exponent,22,0x3a8303,{DOUBLEWITHTWODWORDINTREE(0x02d00000,0x00000000)}}, {VT_exponent,22,0x3a8304,{DOUBLEWITHTWODWORDINTREE(0x02e00000,0x00000000)}}, {VT_exponent,22,0x3a8305,{DOUBLEWITHTWODWORDINTREE(0x02f00000,0x00000000)}}, {VT_exponent,22,0x3a8306,{DOUBLEWITHTWODWORDINTREE(0x03000000,0x00000000)}}, {VT_exponent,22,0x3a8307,{DOUBLEWITHTWODWORDINTREE(0x03100000,0x00000000)}}, {VT_exponent,22,0x3a8308,{DOUBLEWITHTWODWORDINTREE(0x03200000,0x00000000)}}, {VT_exponent,22,0x3a8309,{DOUBLEWITHTWODWORDINTREE(0x03300000,0x00000000)}}, {VT_exponent,22,0x3a830a,{DOUBLEWITHTWODWORDINTREE(0x03400000,0x00000000)}}, {VT_exponent,22,0x3a830b,{DOUBLEWITHTWODWORDINTREE(0x03500000,0x00000000)}}, {VT_exponent,22,0x3a830c,{DOUBLEWITHTWODWORDINTREE(0x03600000,0x00000000)}}, {VT_exponent,22,0x3a830d,{DOUBLEWITHTWODWORDINTREE(0x03700000,0x00000000)}}, {VT_exponent,22,0x3a830e,{DOUBLEWITHTWODWORDINTREE(0x03800000,0x00000000)}}, {VT_exponent,22,0x3a830f,{DOUBLEWITHTWODWORDINTREE(0x03900000,0x00000000)}}, {VT_exponent,22,0x3a8310,{DOUBLEWITHTWODWORDINTREE(0x03a00000,0x00000000)}}, {VT_exponent,22,0x3a8311,{DOUBLEWITHTWODWORDINTREE(0x03b00000,0x00000000)}}, {VT_exponent,22,0x3a8312,{DOUBLEWITHTWODWORDINTREE(0x03c00000,0x00000000)}}, {VT_exponent,22,0x3a8313,{DOUBLEWITHTWODWORDINTREE(0x03d00000,0x00000000)}}, {VT_exponent,22,0x3a8314,{DOUBLEWITHTWODWORDINTREE(0x03e00000,0x00000000)}}, {VT_exponent,22,0x3a8315,{DOUBLEWITHTWODWORDINTREE(0x03f00000,0x00000000)}}, {VT_exponent,22,0x3a8316,{DOUBLEWITHTWODWORDINTREE(0x04000000,0x00000000)}}, {VT_exponent,22,0x3a8317,{DOUBLEWITHTWODWORDINTREE(0x04100000,0x00000000)}}, {VT_exponent,22,0x3a8318,{DOUBLEWITHTWODWORDINTREE(0x04200000,0x00000000)}}, {VT_exponent,22,0x3a8319,{DOUBLEWITHTWODWORDINTREE(0x04300000,0x00000000)}}, {VT_exponent,22,0x3a831a,{DOUBLEWITHTWODWORDINTREE(0x04400000,0x00000000)}}, {VT_exponent,22,0x3a831b,{DOUBLEWITHTWODWORDINTREE(0x04500000,0x00000000)}}, {VT_exponent,22,0x3a831c,{DOUBLEWITHTWODWORDINTREE(0x04600000,0x00000000)}}, {VT_exponent,22,0x3a831d,{DOUBLEWITHTWODWORDINTREE(0x04700000,0x00000000)}}, {VT_exponent,22,0x3a831e,{DOUBLEWITHTWODWORDINTREE(0x04800000,0x00000000)}}, {VT_exponent,22,0x3a831f,{DOUBLEWITHTWODWORDINTREE(0x04900000,0x00000000)}}, {VT_exponent,22,0x3a8320,{DOUBLEWITHTWODWORDINTREE(0x04a00000,0x00000000)}}, {VT_exponent,22,0x3a8321,{DOUBLEWITHTWODWORDINTREE(0x04b00000,0x00000000)}}, {VT_exponent,22,0x3a8322,{DOUBLEWITHTWODWORDINTREE(0x04c00000,0x00000000)}}, {VT_exponent,22,0x3a8323,{DOUBLEWITHTWODWORDINTREE(0x04d00000,0x00000000)}}, {VT_exponent,22,0x3a8324,{DOUBLEWITHTWODWORDINTREE(0x04e00000,0x00000000)}}, {VT_exponent,22,0x3a8325,{DOUBLEWITHTWODWORDINTREE(0x04f00000,0x00000000)}}, {VT_exponent,22,0x3a8326,{DOUBLEWITHTWODWORDINTREE(0x05000000,0x00000000)}}, {VT_exponent,22,0x3a8327,{DOUBLEWITHTWODWORDINTREE(0x05100000,0x00000000)}}, {VT_exponent,22,0x3a8328,{DOUBLEWITHTWODWORDINTREE(0x05200000,0x00000000)}}, {VT_exponent,22,0x3a8329,{DOUBLEWITHTWODWORDINTREE(0x05300000,0x00000000)}}, {VT_exponent,22,0x3a832a,{DOUBLEWITHTWODWORDINTREE(0x05400000,0x00000000)}}, {VT_exponent,22,0x3a832b,{DOUBLEWITHTWODWORDINTREE(0x05500000,0x00000000)}}, {VT_exponent,22,0x3a832c,{DOUBLEWITHTWODWORDINTREE(0x05600000,0x00000000)}}, {VT_exponent,22,0x3a832d,{DOUBLEWITHTWODWORDINTREE(0x05700000,0x00000000)}}, {VT_exponent,22,0x3a832e,{DOUBLEWITHTWODWORDINTREE(0x05800000,0x00000000)}}, {VT_exponent,22,0x3a832f,{DOUBLEWITHTWODWORDINTREE(0x05900000,0x00000000)}}, {VT_exponent,22,0x3a8330,{DOUBLEWITHTWODWORDINTREE(0x05a00000,0x00000000)}}, {VT_exponent,22,0x3a8331,{DOUBLEWITHTWODWORDINTREE(0x05b00000,0x00000000)}}, {VT_exponent,22,0x3a8332,{DOUBLEWITHTWODWORDINTREE(0x05c00000,0x00000000)}}, {VT_exponent,22,0x3a8333,{DOUBLEWITHTWODWORDINTREE(0x05d00000,0x00000000)}}, {VT_exponent,22,0x3a8334,{DOUBLEWITHTWODWORDINTREE(0x05e00000,0x00000000)}}, {VT_exponent,22,0x3a8335,{DOUBLEWITHTWODWORDINTREE(0x05f00000,0x00000000)}}, {VT_exponent,22,0x3a8336,{DOUBLEWITHTWODWORDINTREE(0x06000000,0x00000000)}}, {VT_exponent,22,0x3a8337,{DOUBLEWITHTWODWORDINTREE(0x06100000,0x00000000)}}, {VT_exponent,22,0x3a8338,{DOUBLEWITHTWODWORDINTREE(0x06200000,0x00000000)}}, {VT_exponent,22,0x3a8339,{DOUBLEWITHTWODWORDINTREE(0x06300000,0x00000000)}}, {VT_exponent,22,0x3a833a,{DOUBLEWITHTWODWORDINTREE(0x06400000,0x00000000)}}, {VT_exponent,22,0x3a833b,{DOUBLEWITHTWODWORDINTREE(0x06500000,0x00000000)}}, {VT_exponent,22,0x3a833c,{DOUBLEWITHTWODWORDINTREE(0x06600000,0x00000000)}}, {VT_exponent,22,0x3a833d,{DOUBLEWITHTWODWORDINTREE(0x06700000,0x00000000)}}, {VT_exponent,22,0x3a833e,{DOUBLEWITHTWODWORDINTREE(0x06800000,0x00000000)}}, {VT_exponent,22,0x3a833f,{DOUBLEWITHTWODWORDINTREE(0x06900000,0x00000000)}}, {VT_exponent,22,0x3a8340,{DOUBLEWITHTWODWORDINTREE(0x06a00000,0x00000000)}}, {VT_exponent,22,0x3a8341,{DOUBLEWITHTWODWORDINTREE(0x06b00000,0x00000000)}}, {VT_exponent,22,0x3a8342,{DOUBLEWITHTWODWORDINTREE(0x06c00000,0x00000000)}}, {VT_exponent,22,0x3a8343,{DOUBLEWITHTWODWORDINTREE(0x06d00000,0x00000000)}}, {VT_exponent,22,0x3a8344,{DOUBLEWITHTWODWORDINTREE(0x06e00000,0x00000000)}}, {VT_exponent,22,0x3a8345,{DOUBLEWITHTWODWORDINTREE(0x06f00000,0x00000000)}}, {VT_exponent,22,0x3a8346,{DOUBLEWITHTWODWORDINTREE(0x07000000,0x00000000)}}, {VT_exponent,22,0x3a8347,{DOUBLEWITHTWODWORDINTREE(0x07100000,0x00000000)}}, {VT_exponent,22,0x3a8348,{DOUBLEWITHTWODWORDINTREE(0x07200000,0x00000000)}}, {VT_exponent,22,0x3a8349,{DOUBLEWITHTWODWORDINTREE(0x07300000,0x00000000)}}, {VT_exponent,22,0x3a834a,{DOUBLEWITHTWODWORDINTREE(0x07400000,0x00000000)}}, {VT_exponent,22,0x3a834b,{DOUBLEWITHTWODWORDINTREE(0x07500000,0x00000000)}}, {VT_exponent,22,0x3a834c,{DOUBLEWITHTWODWORDINTREE(0x07600000,0x00000000)}}, {VT_exponent,22,0x3a834d,{DOUBLEWITHTWODWORDINTREE(0x07700000,0x00000000)}}, {VT_exponent,22,0x3a834e,{DOUBLEWITHTWODWORDINTREE(0x07800000,0x00000000)}}, {VT_exponent,22,0x3a834f,{DOUBLEWITHTWODWORDINTREE(0x07900000,0x00000000)}}, {VT_exponent,22,0x3a8350,{DOUBLEWITHTWODWORDINTREE(0x07a00000,0x00000000)}}, {VT_exponent,22,0x3a8351,{DOUBLEWITHTWODWORDINTREE(0x07b00000,0x00000000)}}, {VT_exponent,22,0x3a8352,{DOUBLEWITHTWODWORDINTREE(0x07c00000,0x00000000)}}, {VT_exponent,22,0x3a8353,{DOUBLEWITHTWODWORDINTREE(0x07d00000,0x00000000)}}, {VT_exponent,22,0x3a8354,{DOUBLEWITHTWODWORDINTREE(0x07e00000,0x00000000)}}, {VT_exponent,22,0x3a8355,{DOUBLEWITHTWODWORDINTREE(0x07f00000,0x00000000)}}, {VT_exponent,22,0x3a8356,{DOUBLEWITHTWODWORDINTREE(0x08000000,0x00000000)}}, {VT_exponent,22,0x3a8357,{DOUBLEWITHTWODWORDINTREE(0x08100000,0x00000000)}}, {VT_exponent,22,0x3a8358,{DOUBLEWITHTWODWORDINTREE(0x08200000,0x00000000)}}, {VT_exponent,22,0x3a8359,{DOUBLEWITHTWODWORDINTREE(0x08300000,0x00000000)}}, {VT_exponent,22,0x3a835a,{DOUBLEWITHTWODWORDINTREE(0x08400000,0x00000000)}}, {VT_exponent,22,0x3a835b,{DOUBLEWITHTWODWORDINTREE(0x08500000,0x00000000)}}, {VT_exponent,22,0x3a835c,{DOUBLEWITHTWODWORDINTREE(0x08600000,0x00000000)}}, {VT_exponent,22,0x3a835d,{DOUBLEWITHTWODWORDINTREE(0x08700000,0x00000000)}}, {VT_exponent,22,0x3a835e,{DOUBLEWITHTWODWORDINTREE(0x08800000,0x00000000)}}, {VT_exponent,22,0x3a835f,{DOUBLEWITHTWODWORDINTREE(0x08900000,0x00000000)}}, {VT_exponent,22,0x3a8360,{DOUBLEWITHTWODWORDINTREE(0x08a00000,0x00000000)}}, {VT_exponent,22,0x3a8361,{DOUBLEWITHTWODWORDINTREE(0x08b00000,0x00000000)}}, {VT_exponent,22,0x3a8362,{DOUBLEWITHTWODWORDINTREE(0x08c00000,0x00000000)}}, {VT_exponent,22,0x3a8363,{DOUBLEWITHTWODWORDINTREE(0x08d00000,0x00000000)}}, {VT_exponent,22,0x3a8364,{DOUBLEWITHTWODWORDINTREE(0x08e00000,0x00000000)}}, {VT_exponent,22,0x3a8365,{DOUBLEWITHTWODWORDINTREE(0x08f00000,0x00000000)}}, {VT_exponent,22,0x3a8366,{DOUBLEWITHTWODWORDINTREE(0x09000000,0x00000000)}}, {VT_exponent,22,0x3a8367,{DOUBLEWITHTWODWORDINTREE(0x09100000,0x00000000)}}, {VT_exponent,22,0x3a8368,{DOUBLEWITHTWODWORDINTREE(0x09200000,0x00000000)}}, {VT_exponent,22,0x3a8369,{DOUBLEWITHTWODWORDINTREE(0x09300000,0x00000000)}}, {VT_exponent,22,0x3a836a,{DOUBLEWITHTWODWORDINTREE(0x09400000,0x00000000)}}, {VT_exponent,22,0x3a836b,{DOUBLEWITHTWODWORDINTREE(0x09500000,0x00000000)}}, {VT_exponent,22,0x3a836c,{DOUBLEWITHTWODWORDINTREE(0x09600000,0x00000000)}}, {VT_exponent,22,0x3a836d,{DOUBLEWITHTWODWORDINTREE(0x09700000,0x00000000)}}, {VT_exponent,22,0x3a836e,{DOUBLEWITHTWODWORDINTREE(0x09800000,0x00000000)}}, {VT_exponent,22,0x3a836f,{DOUBLEWITHTWODWORDINTREE(0x09900000,0x00000000)}}, {VT_exponent,22,0x3a8370,{DOUBLEWITHTWODWORDINTREE(0x09a00000,0x00000000)}}, {VT_exponent,22,0x3a8371,{DOUBLEWITHTWODWORDINTREE(0x09b00000,0x00000000)}}, {VT_exponent,22,0x3a8372,{DOUBLEWITHTWODWORDINTREE(0x09c00000,0x00000000)}}, {VT_exponent,22,0x3a8373,{DOUBLEWITHTWODWORDINTREE(0x09d00000,0x00000000)}}, {VT_exponent,22,0x3a8374,{DOUBLEWITHTWODWORDINTREE(0x09e00000,0x00000000)}}, {VT_exponent,22,0x3a8375,{DOUBLEWITHTWODWORDINTREE(0x09f00000,0x00000000)}}, {VT_exponent,22,0x3a8376,{DOUBLEWITHTWODWORDINTREE(0x0a000000,0x00000000)}}, {VT_exponent,22,0x3a8377,{DOUBLEWITHTWODWORDINTREE(0x0a100000,0x00000000)}}, {VT_exponent,22,0x3a8378,{DOUBLEWITHTWODWORDINTREE(0x0a200000,0x00000000)}}, {VT_exponent,22,0x3a8379,{DOUBLEWITHTWODWORDINTREE(0x0a300000,0x00000000)}}, {VT_exponent,22,0x3a837a,{DOUBLEWITHTWODWORDINTREE(0x0a400000,0x00000000)}}, {VT_exponent,22,0x3a837b,{DOUBLEWITHTWODWORDINTREE(0x0a500000,0x00000000)}}, {VT_exponent,22,0x3a837c,{DOUBLEWITHTWODWORDINTREE(0x0a600000,0x00000000)}}, {VT_exponent,22,0x3a837d,{DOUBLEWITHTWODWORDINTREE(0x0a700000,0x00000000)}}, {VT_exponent,22,0x3a837e,{DOUBLEWITHTWODWORDINTREE(0x0a800000,0x00000000)}}, {VT_exponent,22,0x3a837f,{DOUBLEWITHTWODWORDINTREE(0x0a900000,0x00000000)}}, {VT_exponent,22,0x3a8380,{DOUBLEWITHTWODWORDINTREE(0x0aa00000,0x00000000)}}, {VT_exponent,22,0x3a8381,{DOUBLEWITHTWODWORDINTREE(0x0ab00000,0x00000000)}}, {VT_exponent,22,0x3a8382,{DOUBLEWITHTWODWORDINTREE(0x0ac00000,0x00000000)}}, {VT_exponent,22,0x3a8383,{DOUBLEWITHTWODWORDINTREE(0x0ad00000,0x00000000)}}, {VT_exponent,22,0x3a8384,{DOUBLEWITHTWODWORDINTREE(0x0ae00000,0x00000000)}}, {VT_exponent,22,0x3a8385,{DOUBLEWITHTWODWORDINTREE(0x0af00000,0x00000000)}}, {VT_exponent,22,0x3a8386,{DOUBLEWITHTWODWORDINTREE(0x0b000000,0x00000000)}}, {VT_exponent,22,0x3a8387,{DOUBLEWITHTWODWORDINTREE(0x0b100000,0x00000000)}}, {VT_exponent,22,0x3a8388,{DOUBLEWITHTWODWORDINTREE(0x0b200000,0x00000000)}}, {VT_exponent,22,0x3a8389,{DOUBLEWITHTWODWORDINTREE(0x0b300000,0x00000000)}}, {VT_exponent,22,0x3a838a,{DOUBLEWITHTWODWORDINTREE(0x0b400000,0x00000000)}}, {VT_exponent,22,0x3a838b,{DOUBLEWITHTWODWORDINTREE(0x0b500000,0x00000000)}}, {VT_exponent,22,0x3a838c,{DOUBLEWITHTWODWORDINTREE(0x0b600000,0x00000000)}}, {VT_exponent,22,0x3a838d,{DOUBLEWITHTWODWORDINTREE(0x0b700000,0x00000000)}}, {VT_exponent,22,0x3a838e,{DOUBLEWITHTWODWORDINTREE(0x0b800000,0x00000000)}}, {VT_exponent,22,0x3a838f,{DOUBLEWITHTWODWORDINTREE(0x0b900000,0x00000000)}}, {VT_exponent,22,0x3a8390,{DOUBLEWITHTWODWORDINTREE(0x0ba00000,0x00000000)}}, {VT_exponent,22,0x3a8391,{DOUBLEWITHTWODWORDINTREE(0x0bb00000,0x00000000)}}, {VT_exponent,22,0x3a8392,{DOUBLEWITHTWODWORDINTREE(0x0bc00000,0x00000000)}}, {VT_exponent,22,0x3a8393,{DOUBLEWITHTWODWORDINTREE(0x0bd00000,0x00000000)}}, {VT_exponent,22,0x3a8394,{DOUBLEWITHTWODWORDINTREE(0x0be00000,0x00000000)}}, {VT_exponent,22,0x3a8395,{DOUBLEWITHTWODWORDINTREE(0x0bf00000,0x00000000)}}, {VT_exponent,22,0x3a8396,{DOUBLEWITHTWODWORDINTREE(0x0c000000,0x00000000)}}, {VT_exponent,22,0x3a8397,{DOUBLEWITHTWODWORDINTREE(0x0c100000,0x00000000)}}, {VT_exponent,22,0x3a8398,{DOUBLEWITHTWODWORDINTREE(0x0c200000,0x00000000)}}, {VT_exponent,22,0x3a8399,{DOUBLEWITHTWODWORDINTREE(0x0c300000,0x00000000)}}, {VT_exponent,22,0x3a839a,{DOUBLEWITHTWODWORDINTREE(0x0c400000,0x00000000)}}, {VT_exponent,22,0x3a839b,{DOUBLEWITHTWODWORDINTREE(0x0c500000,0x00000000)}}, {VT_exponent,22,0x3a839c,{DOUBLEWITHTWODWORDINTREE(0x0c600000,0x00000000)}}, {VT_exponent,22,0x3a839d,{DOUBLEWITHTWODWORDINTREE(0x0c700000,0x00000000)}}, {VT_exponent,22,0x3a839e,{DOUBLEWITHTWODWORDINTREE(0x0c800000,0x00000000)}}, {VT_exponent,22,0x3a839f,{DOUBLEWITHTWODWORDINTREE(0x0c900000,0x00000000)}}, {VT_exponent,22,0x3a83a0,{DOUBLEWITHTWODWORDINTREE(0x0ca00000,0x00000000)}}, {VT_exponent,22,0x3a83a1,{DOUBLEWITHTWODWORDINTREE(0x0cb00000,0x00000000)}}, {VT_exponent,22,0x3a83a2,{DOUBLEWITHTWODWORDINTREE(0x0cc00000,0x00000000)}}, {VT_exponent,22,0x3a83a3,{DOUBLEWITHTWODWORDINTREE(0x0cd00000,0x00000000)}}, {VT_exponent,22,0x3a83a4,{DOUBLEWITHTWODWORDINTREE(0x0ce00000,0x00000000)}}, {VT_exponent,22,0x3a83a5,{DOUBLEWITHTWODWORDINTREE(0x0cf00000,0x00000000)}}, {VT_exponent,22,0x3a83a6,{DOUBLEWITHTWODWORDINTREE(0x0d000000,0x00000000)}}, {VT_exponent,22,0x3a83a7,{DOUBLEWITHTWODWORDINTREE(0x0d100000,0x00000000)}}, {VT_exponent,22,0x3a83a8,{DOUBLEWITHTWODWORDINTREE(0x0d200000,0x00000000)}}, {VT_exponent,22,0x3a83a9,{DOUBLEWITHTWODWORDINTREE(0x0d300000,0x00000000)}}, {VT_exponent,22,0x3a83aa,{DOUBLEWITHTWODWORDINTREE(0x0d400000,0x00000000)}}, {VT_exponent,22,0x3a83ab,{DOUBLEWITHTWODWORDINTREE(0x0d500000,0x00000000)}}, {VT_exponent,22,0x3a83ac,{DOUBLEWITHTWODWORDINTREE(0x0d600000,0x00000000)}}, {VT_exponent,22,0x3a83ad,{DOUBLEWITHTWODWORDINTREE(0x0d700000,0x00000000)}}, {VT_exponent,22,0x3a83ae,{DOUBLEWITHTWODWORDINTREE(0x0d800000,0x00000000)}}, {VT_exponent,22,0x3a83af,{DOUBLEWITHTWODWORDINTREE(0x0d900000,0x00000000)}}, {VT_exponent,22,0x3a83b0,{DOUBLEWITHTWODWORDINTREE(0x0da00000,0x00000000)}}, {VT_exponent,22,0x3a83b1,{DOUBLEWITHTWODWORDINTREE(0x0db00000,0x00000000)}}, {VT_exponent,22,0x3a83b2,{DOUBLEWITHTWODWORDINTREE(0x0dc00000,0x00000000)}}, {VT_exponent,22,0x3a83b3,{DOUBLEWITHTWODWORDINTREE(0x0dd00000,0x00000000)}}, {VT_exponent,22,0x3a83b4,{DOUBLEWITHTWODWORDINTREE(0x0de00000,0x00000000)}}, {VT_exponent,22,0x3a83b5,{DOUBLEWITHTWODWORDINTREE(0x0df00000,0x00000000)}}, {VT_exponent,22,0x3a83b6,{DOUBLEWITHTWODWORDINTREE(0x0e000000,0x00000000)}}, {VT_exponent,22,0x3a83b7,{DOUBLEWITHTWODWORDINTREE(0x0e100000,0x00000000)}}, {VT_exponent,22,0x3a83b8,{DOUBLEWITHTWODWORDINTREE(0x0e200000,0x00000000)}}, {VT_exponent,22,0x3a83b9,{DOUBLEWITHTWODWORDINTREE(0x0e300000,0x00000000)}}, {VT_exponent,22,0x3a83ba,{DOUBLEWITHTWODWORDINTREE(0x0e400000,0x00000000)}}, {VT_exponent,22,0x3a83bb,{DOUBLEWITHTWODWORDINTREE(0x0e500000,0x00000000)}}, {VT_exponent,22,0x3a83bc,{DOUBLEWITHTWODWORDINTREE(0x0e600000,0x00000000)}}, {VT_exponent,22,0x3a83bd,{DOUBLEWITHTWODWORDINTREE(0x0e700000,0x00000000)}}, {VT_exponent,22,0x3a83be,{DOUBLEWITHTWODWORDINTREE(0x0e800000,0x00000000)}}, {VT_exponent,22,0x3a83bf,{DOUBLEWITHTWODWORDINTREE(0x0e900000,0x00000000)}}, {VT_exponent,22,0x3a83c0,{DOUBLEWITHTWODWORDINTREE(0x0ea00000,0x00000000)}}, {VT_exponent,22,0x3a83c1,{DOUBLEWITHTWODWORDINTREE(0x0eb00000,0x00000000)}}, {VT_exponent,22,0x3a83c2,{DOUBLEWITHTWODWORDINTREE(0x0ec00000,0x00000000)}}, {VT_exponent,22,0x3a83c3,{DOUBLEWITHTWODWORDINTREE(0x0ed00000,0x00000000)}}, {VT_exponent,22,0x3a83c4,{DOUBLEWITHTWODWORDINTREE(0x0ee00000,0x00000000)}}, {VT_exponent,22,0x3a83c5,{DOUBLEWITHTWODWORDINTREE(0x0ef00000,0x00000000)}}, {VT_exponent,22,0x3a83c6,{DOUBLEWITHTWODWORDINTREE(0x0f000000,0x00000000)}}, {VT_exponent,22,0x3a83c7,{DOUBLEWITHTWODWORDINTREE(0x0f100000,0x00000000)}}, {VT_exponent,22,0x3a83c8,{DOUBLEWITHTWODWORDINTREE(0x0f200000,0x00000000)}}, {VT_exponent,22,0x3a83c9,{DOUBLEWITHTWODWORDINTREE(0x0f300000,0x00000000)}}, {VT_exponent,22,0x3a83ca,{DOUBLEWITHTWODWORDINTREE(0x0f400000,0x00000000)}}, {VT_exponent,22,0x3a83cb,{DOUBLEWITHTWODWORDINTREE(0x0f500000,0x00000000)}}, {VT_exponent,22,0x3a83cc,{DOUBLEWITHTWODWORDINTREE(0x0f600000,0x00000000)}}, {VT_exponent,22,0x3a83cd,{DOUBLEWITHTWODWORDINTREE(0x0f700000,0x00000000)}}, {VT_exponent,22,0x3a83ce,{DOUBLEWITHTWODWORDINTREE(0x0f800000,0x00000000)}}, {VT_exponent,22,0x3a83cf,{DOUBLEWITHTWODWORDINTREE(0x0f900000,0x00000000)}}, {VT_exponent,22,0x3a83d0,{DOUBLEWITHTWODWORDINTREE(0x0fa00000,0x00000000)}}, {VT_exponent,22,0x3a83d1,{DOUBLEWITHTWODWORDINTREE(0x0fb00000,0x00000000)}}, {VT_exponent,22,0x3a83d2,{DOUBLEWITHTWODWORDINTREE(0x0fc00000,0x00000000)}}, {VT_exponent,22,0x3a83d3,{DOUBLEWITHTWODWORDINTREE(0x0fd00000,0x00000000)}}, {VT_exponent,22,0x3a83d4,{DOUBLEWITHTWODWORDINTREE(0x0fe00000,0x00000000)}}, {VT_exponent,22,0x3a83d5,{DOUBLEWITHTWODWORDINTREE(0x0ff00000,0x00000000)}}, {VT_exponent,22,0x3a83d6,{DOUBLEWITHTWODWORDINTREE(0x10000000,0x00000000)}}, {VT_exponent,22,0x3a83d7,{DOUBLEWITHTWODWORDINTREE(0x10100000,0x00000000)}}, {VT_exponent,22,0x3a83d8,{DOUBLEWITHTWODWORDINTREE(0x10200000,0x00000000)}}, {VT_exponent,22,0x3a83d9,{DOUBLEWITHTWODWORDINTREE(0x10300000,0x00000000)}}, {VT_exponent,22,0x3a83da,{DOUBLEWITHTWODWORDINTREE(0x10400000,0x00000000)}}, {VT_exponent,22,0x3a83db,{DOUBLEWITHTWODWORDINTREE(0x10500000,0x00000000)}}, {VT_exponent,22,0x3a83dc,{DOUBLEWITHTWODWORDINTREE(0x10600000,0x00000000)}}, {VT_exponent,22,0x3a83dd,{DOUBLEWITHTWODWORDINTREE(0x10700000,0x00000000)}}, {VT_exponent,22,0x3a83de,{DOUBLEWITHTWODWORDINTREE(0x10800000,0x00000000)}}, {VT_exponent,22,0x3a83df,{DOUBLEWITHTWODWORDINTREE(0x10900000,0x00000000)}}, {VT_exponent,22,0x3a83e0,{DOUBLEWITHTWODWORDINTREE(0x10a00000,0x00000000)}}, {VT_exponent,22,0x3a83e1,{DOUBLEWITHTWODWORDINTREE(0x10b00000,0x00000000)}}, {VT_exponent,22,0x3a83e2,{DOUBLEWITHTWODWORDINTREE(0x10c00000,0x00000000)}}, {VT_exponent,22,0x3a83e3,{DOUBLEWITHTWODWORDINTREE(0x10d00000,0x00000000)}}, {VT_exponent,22,0x3a83e4,{DOUBLEWITHTWODWORDINTREE(0x10e00000,0x00000000)}}, {VT_exponent,22,0x3a83e5,{DOUBLEWITHTWODWORDINTREE(0x10f00000,0x00000000)}}, {VT_exponent,22,0x3a83e6,{DOUBLEWITHTWODWORDINTREE(0x11000000,0x00000000)}}, {VT_exponent,22,0x3a83e7,{DOUBLEWITHTWODWORDINTREE(0x11100000,0x00000000)}}, {VT_exponent,22,0x3a83e8,{DOUBLEWITHTWODWORDINTREE(0x11200000,0x00000000)}}, {VT_exponent,22,0x3a83e9,{DOUBLEWITHTWODWORDINTREE(0x11300000,0x00000000)}}, {VT_exponent,22,0x3a83ea,{DOUBLEWITHTWODWORDINTREE(0x11400000,0x00000000)}}, {VT_exponent,22,0x3a83eb,{DOUBLEWITHTWODWORDINTREE(0x11500000,0x00000000)}}, {VT_exponent,22,0x3a83ec,{DOUBLEWITHTWODWORDINTREE(0x11600000,0x00000000)}}, {VT_exponent,22,0x3a83ed,{DOUBLEWITHTWODWORDINTREE(0x11700000,0x00000000)}}, {VT_exponent,22,0x3a83ee,{DOUBLEWITHTWODWORDINTREE(0x11800000,0x00000000)}}, {VT_exponent,22,0x3a83ef,{DOUBLEWITHTWODWORDINTREE(0x11900000,0x00000000)}}, {VT_exponent,22,0x3a83f0,{DOUBLEWITHTWODWORDINTREE(0x11a00000,0x00000000)}}, {VT_exponent,22,0x3a83f1,{DOUBLEWITHTWODWORDINTREE(0x11b00000,0x00000000)}}, {VT_exponent,22,0x3a83f2,{DOUBLEWITHTWODWORDINTREE(0x11c00000,0x00000000)}}, {VT_exponent,22,0x3a83f3,{DOUBLEWITHTWODWORDINTREE(0x11d00000,0x00000000)}}, {VT_exponent,22,0x3a83f4,{DOUBLEWITHTWODWORDINTREE(0x11e00000,0x00000000)}}, {VT_exponent,22,0x3a83f5,{DOUBLEWITHTWODWORDINTREE(0x11f00000,0x00000000)}}, {VT_exponent,22,0x3a83f6,{DOUBLEWITHTWODWORDINTREE(0x12000000,0x00000000)}}, {VT_exponent,22,0x3a83f7,{DOUBLEWITHTWODWORDINTREE(0x12100000,0x00000000)}}, {VT_exponent,22,0x3a83f8,{DOUBLEWITHTWODWORDINTREE(0x12200000,0x00000000)}}, {VT_exponent,22,0x3a83f9,{DOUBLEWITHTWODWORDINTREE(0x12300000,0x00000000)}}, {VT_exponent,22,0x3a83fa,{DOUBLEWITHTWODWORDINTREE(0x12400000,0x00000000)}}, {VT_exponent,22,0x3a83fb,{DOUBLEWITHTWODWORDINTREE(0x12500000,0x00000000)}}, {VT_exponent,22,0x3a83fc,{DOUBLEWITHTWODWORDINTREE(0x12600000,0x00000000)}}, {VT_exponent,22,0x3a83fd,{DOUBLEWITHTWODWORDINTREE(0x12700000,0x00000000)}}, {VT_exponent,22,0x3a83fe,{DOUBLEWITHTWODWORDINTREE(0x12800000,0x00000000)}}, {VT_exponent,22,0x3a83ff,{DOUBLEWITHTWODWORDINTREE(0x12900000,0x00000000)}}, {VT_exponent,22,0x3a8400,{DOUBLEWITHTWODWORDINTREE(0x12a00000,0x00000000)}}, {VT_exponent,22,0x3a8401,{DOUBLEWITHTWODWORDINTREE(0x12b00000,0x00000000)}}, {VT_exponent,22,0x3a8402,{DOUBLEWITHTWODWORDINTREE(0x12c00000,0x00000000)}}, {VT_exponent,22,0x3a8403,{DOUBLEWITHTWODWORDINTREE(0x12d00000,0x00000000)}}, {VT_exponent,22,0x3a8404,{DOUBLEWITHTWODWORDINTREE(0x12e00000,0x00000000)}}, {VT_exponent,22,0x3a8405,{DOUBLEWITHTWODWORDINTREE(0x12f00000,0x00000000)}}, {VT_exponent,22,0x3a8406,{DOUBLEWITHTWODWORDINTREE(0x13000000,0x00000000)}}, {VT_exponent,22,0x3a8407,{DOUBLEWITHTWODWORDINTREE(0x13100000,0x00000000)}}, {VT_exponent,22,0x3a8408,{DOUBLEWITHTWODWORDINTREE(0x13200000,0x00000000)}}, {VT_exponent,22,0x3a8409,{DOUBLEWITHTWODWORDINTREE(0x13300000,0x00000000)}}, {VT_exponent,22,0x3a840a,{DOUBLEWITHTWODWORDINTREE(0x13400000,0x00000000)}}, {VT_exponent,22,0x3a840b,{DOUBLEWITHTWODWORDINTREE(0x13500000,0x00000000)}}, {VT_exponent,22,0x3a840c,{DOUBLEWITHTWODWORDINTREE(0x13600000,0x00000000)}}, {VT_exponent,22,0x3a840d,{DOUBLEWITHTWODWORDINTREE(0x13700000,0x00000000)}}, {VT_exponent,22,0x3a840e,{DOUBLEWITHTWODWORDINTREE(0x13800000,0x00000000)}}, {VT_exponent,22,0x3a840f,{DOUBLEWITHTWODWORDINTREE(0x13900000,0x00000000)}}, {VT_exponent,22,0x3a8410,{DOUBLEWITHTWODWORDINTREE(0x13a00000,0x00000000)}}, {VT_exponent,22,0x3a8411,{DOUBLEWITHTWODWORDINTREE(0x13b00000,0x00000000)}}, {VT_exponent,22,0x3a8412,{DOUBLEWITHTWODWORDINTREE(0x13c00000,0x00000000)}}, {VT_exponent,22,0x3a8413,{DOUBLEWITHTWODWORDINTREE(0x13d00000,0x00000000)}}, {VT_exponent,22,0x3a8414,{DOUBLEWITHTWODWORDINTREE(0x13e00000,0x00000000)}}, {VT_exponent,22,0x3a8415,{DOUBLEWITHTWODWORDINTREE(0x13f00000,0x00000000)}}, {VT_exponent,22,0x3a8416,{DOUBLEWITHTWODWORDINTREE(0x14000000,0x00000000)}}, {VT_exponent,22,0x3a8417,{DOUBLEWITHTWODWORDINTREE(0x14100000,0x00000000)}}, {VT_exponent,22,0x3a8418,{DOUBLEWITHTWODWORDINTREE(0x14200000,0x00000000)}}, {VT_exponent,22,0x3a8419,{DOUBLEWITHTWODWORDINTREE(0x14300000,0x00000000)}}, {VT_exponent,22,0x3a841a,{DOUBLEWITHTWODWORDINTREE(0x14400000,0x00000000)}}, {VT_exponent,22,0x3a841b,{DOUBLEWITHTWODWORDINTREE(0x14500000,0x00000000)}}, {VT_exponent,22,0x3a841c,{DOUBLEWITHTWODWORDINTREE(0x14600000,0x00000000)}}, {VT_exponent,22,0x3a841d,{DOUBLEWITHTWODWORDINTREE(0x14700000,0x00000000)}}, {VT_exponent,22,0x3a841e,{DOUBLEWITHTWODWORDINTREE(0x14800000,0x00000000)}}, {VT_exponent,22,0x3a841f,{DOUBLEWITHTWODWORDINTREE(0x14900000,0x00000000)}}, {VT_exponent,22,0x3a8420,{DOUBLEWITHTWODWORDINTREE(0x14a00000,0x00000000)}}, {VT_exponent,22,0x3a8421,{DOUBLEWITHTWODWORDINTREE(0x14b00000,0x00000000)}}, {VT_exponent,22,0x3a8422,{DOUBLEWITHTWODWORDINTREE(0x14c00000,0x00000000)}}, {VT_exponent,22,0x3a8423,{DOUBLEWITHTWODWORDINTREE(0x14d00000,0x00000000)}}, {VT_exponent,22,0x3a8424,{DOUBLEWITHTWODWORDINTREE(0x14e00000,0x00000000)}}, {VT_exponent,22,0x3a8425,{DOUBLEWITHTWODWORDINTREE(0x14f00000,0x00000000)}}, {VT_exponent,22,0x3a8426,{DOUBLEWITHTWODWORDINTREE(0x15000000,0x00000000)}}, {VT_exponent,22,0x3a8427,{DOUBLEWITHTWODWORDINTREE(0x15100000,0x00000000)}}, {VT_exponent,22,0x3a8428,{DOUBLEWITHTWODWORDINTREE(0x15200000,0x00000000)}}, {VT_exponent,22,0x3a8429,{DOUBLEWITHTWODWORDINTREE(0x15300000,0x00000000)}}, {VT_exponent,22,0x3a842a,{DOUBLEWITHTWODWORDINTREE(0x15400000,0x00000000)}}, {VT_exponent,22,0x3a842b,{DOUBLEWITHTWODWORDINTREE(0x15500000,0x00000000)}}, {VT_exponent,22,0x3a842c,{DOUBLEWITHTWODWORDINTREE(0x15600000,0x00000000)}}, {VT_exponent,22,0x3a842d,{DOUBLEWITHTWODWORDINTREE(0x15700000,0x00000000)}}, {VT_exponent,22,0x3a842e,{DOUBLEWITHTWODWORDINTREE(0x15800000,0x00000000)}}, {VT_exponent,22,0x3a842f,{DOUBLEWITHTWODWORDINTREE(0x15900000,0x00000000)}}, {VT_exponent,22,0x3a8430,{DOUBLEWITHTWODWORDINTREE(0x15a00000,0x00000000)}}, {VT_exponent,22,0x3a8431,{DOUBLEWITHTWODWORDINTREE(0x15b00000,0x00000000)}}, {VT_exponent,22,0x3a8432,{DOUBLEWITHTWODWORDINTREE(0x15c00000,0x00000000)}}, {VT_exponent,22,0x3a8433,{DOUBLEWITHTWODWORDINTREE(0x15d00000,0x00000000)}}, {VT_exponent,22,0x3a8434,{DOUBLEWITHTWODWORDINTREE(0x15e00000,0x00000000)}}, {VT_exponent,22,0x3a8435,{DOUBLEWITHTWODWORDINTREE(0x15f00000,0x00000000)}}, {VT_exponent,22,0x3a8436,{DOUBLEWITHTWODWORDINTREE(0x16000000,0x00000000)}}, {VT_exponent,22,0x3a8437,{DOUBLEWITHTWODWORDINTREE(0x16100000,0x00000000)}}, {VT_exponent,22,0x3a8438,{DOUBLEWITHTWODWORDINTREE(0x16200000,0x00000000)}}, {VT_exponent,22,0x3a8439,{DOUBLEWITHTWODWORDINTREE(0x16300000,0x00000000)}}, {VT_exponent,22,0x3a843a,{DOUBLEWITHTWODWORDINTREE(0x16400000,0x00000000)}}, {VT_exponent,22,0x3a843b,{DOUBLEWITHTWODWORDINTREE(0x16500000,0x00000000)}}, {VT_exponent,22,0x3a843c,{DOUBLEWITHTWODWORDINTREE(0x16600000,0x00000000)}}, {VT_exponent,22,0x3a843d,{DOUBLEWITHTWODWORDINTREE(0x16700000,0x00000000)}}, {VT_exponent,22,0x3a843e,{DOUBLEWITHTWODWORDINTREE(0x16800000,0x00000000)}}, {VT_exponent,22,0x3a843f,{DOUBLEWITHTWODWORDINTREE(0x16900000,0x00000000)}}, {VT_exponent,22,0x3a8440,{DOUBLEWITHTWODWORDINTREE(0x16a00000,0x00000000)}}, {VT_exponent,22,0x3a8441,{DOUBLEWITHTWODWORDINTREE(0x16b00000,0x00000000)}}, {VT_exponent,22,0x3a8442,{DOUBLEWITHTWODWORDINTREE(0x16c00000,0x00000000)}}, {VT_exponent,22,0x3a8443,{DOUBLEWITHTWODWORDINTREE(0x16d00000,0x00000000)}}, {VT_exponent,22,0x3a8444,{DOUBLEWITHTWODWORDINTREE(0x16e00000,0x00000000)}}, {VT_exponent,22,0x3a8445,{DOUBLEWITHTWODWORDINTREE(0x16f00000,0x00000000)}}, {VT_exponent,22,0x3a8446,{DOUBLEWITHTWODWORDINTREE(0x17000000,0x00000000)}}, {VT_exponent,22,0x3a8447,{DOUBLEWITHTWODWORDINTREE(0x17100000,0x00000000)}}, {VT_exponent,22,0x3a8448,{DOUBLEWITHTWODWORDINTREE(0x17200000,0x00000000)}}, {VT_exponent,22,0x3a8449,{DOUBLEWITHTWODWORDINTREE(0x17300000,0x00000000)}}, {VT_exponent,22,0x3a844a,{DOUBLEWITHTWODWORDINTREE(0x17400000,0x00000000)}}, {VT_exponent,22,0x3a844b,{DOUBLEWITHTWODWORDINTREE(0x17500000,0x00000000)}}, {VT_exponent,22,0x3a844c,{DOUBLEWITHTWODWORDINTREE(0x17600000,0x00000000)}}, {VT_exponent,22,0x3a844d,{DOUBLEWITHTWODWORDINTREE(0x17700000,0x00000000)}}, {VT_exponent,22,0x3a844e,{DOUBLEWITHTWODWORDINTREE(0x17800000,0x00000000)}}, {VT_exponent,22,0x3a844f,{DOUBLEWITHTWODWORDINTREE(0x17900000,0x00000000)}}, {VT_exponent,22,0x3a8450,{DOUBLEWITHTWODWORDINTREE(0x17a00000,0x00000000)}}, {VT_exponent,22,0x3a8451,{DOUBLEWITHTWODWORDINTREE(0x17b00000,0x00000000)}}, {VT_exponent,22,0x3a8452,{DOUBLEWITHTWODWORDINTREE(0x17c00000,0x00000000)}}, {VT_exponent,22,0x3a8453,{DOUBLEWITHTWODWORDINTREE(0x17d00000,0x00000000)}}, {VT_exponent,22,0x3a8454,{DOUBLEWITHTWODWORDINTREE(0x17e00000,0x00000000)}}, {VT_exponent,22,0x3a8455,{DOUBLEWITHTWODWORDINTREE(0x17f00000,0x00000000)}}, {VT_exponent,22,0x3a8456,{DOUBLEWITHTWODWORDINTREE(0x18000000,0x00000000)}}, {VT_exponent,22,0x3a8457,{DOUBLEWITHTWODWORDINTREE(0x18100000,0x00000000)}}, {VT_exponent,22,0x3a8458,{DOUBLEWITHTWODWORDINTREE(0x18200000,0x00000000)}}, {VT_exponent,22,0x3a8459,{DOUBLEWITHTWODWORDINTREE(0x18300000,0x00000000)}}, {VT_exponent,22,0x3a845a,{DOUBLEWITHTWODWORDINTREE(0x18400000,0x00000000)}}, {VT_exponent,22,0x3a845b,{DOUBLEWITHTWODWORDINTREE(0x18500000,0x00000000)}}, {VT_exponent,22,0x3a845c,{DOUBLEWITHTWODWORDINTREE(0x18600000,0x00000000)}}, {VT_exponent,22,0x3a845d,{DOUBLEWITHTWODWORDINTREE(0x18700000,0x00000000)}}, {VT_exponent,22,0x3a845e,{DOUBLEWITHTWODWORDINTREE(0x18800000,0x00000000)}}, {VT_exponent,22,0x3a845f,{DOUBLEWITHTWODWORDINTREE(0x18900000,0x00000000)}}, {VT_exponent,22,0x3a8460,{DOUBLEWITHTWODWORDINTREE(0x18a00000,0x00000000)}}, {VT_exponent,22,0x3a8461,{DOUBLEWITHTWODWORDINTREE(0x18b00000,0x00000000)}}, {VT_exponent,22,0x3a8462,{DOUBLEWITHTWODWORDINTREE(0x18c00000,0x00000000)}}, {VT_exponent,22,0x3a8463,{DOUBLEWITHTWODWORDINTREE(0x18d00000,0x00000000)}}, {VT_exponent,22,0x3a8464,{DOUBLEWITHTWODWORDINTREE(0x18e00000,0x00000000)}}, {VT_exponent,22,0x3a8465,{DOUBLEWITHTWODWORDINTREE(0x18f00000,0x00000000)}}, {VT_exponent,22,0x3a8466,{DOUBLEWITHTWODWORDINTREE(0x19000000,0x00000000)}}, {VT_exponent,22,0x3a8467,{DOUBLEWITHTWODWORDINTREE(0x19100000,0x00000000)}}, {VT_exponent,22,0x3a8468,{DOUBLEWITHTWODWORDINTREE(0x19200000,0x00000000)}}, {VT_exponent,22,0x3a8469,{DOUBLEWITHTWODWORDINTREE(0x19300000,0x00000000)}}, {VT_exponent,22,0x3a846a,{DOUBLEWITHTWODWORDINTREE(0x19400000,0x00000000)}}, {VT_exponent,22,0x3a846b,{DOUBLEWITHTWODWORDINTREE(0x19500000,0x00000000)}}, {VT_exponent,22,0x3a846c,{DOUBLEWITHTWODWORDINTREE(0x19600000,0x00000000)}}, {VT_exponent,22,0x3a846d,{DOUBLEWITHTWODWORDINTREE(0x19700000,0x00000000)}}, {VT_exponent,22,0x3a846e,{DOUBLEWITHTWODWORDINTREE(0x19800000,0x00000000)}}, {VT_exponent,22,0x3a846f,{DOUBLEWITHTWODWORDINTREE(0x19900000,0x00000000)}}, {VT_exponent,22,0x3a8470,{DOUBLEWITHTWODWORDINTREE(0x19a00000,0x00000000)}}, {VT_exponent,22,0x3a8471,{DOUBLEWITHTWODWORDINTREE(0x19b00000,0x00000000)}}, {VT_exponent,22,0x3a8472,{DOUBLEWITHTWODWORDINTREE(0x19c00000,0x00000000)}}, {VT_exponent,22,0x3a8473,{DOUBLEWITHTWODWORDINTREE(0x19d00000,0x00000000)}}, {VT_exponent,22,0x3a8474,{DOUBLEWITHTWODWORDINTREE(0x19e00000,0x00000000)}}, {VT_exponent,22,0x3a8475,{DOUBLEWITHTWODWORDINTREE(0x19f00000,0x00000000)}}, {VT_exponent,22,0x3a8476,{DOUBLEWITHTWODWORDINTREE(0x1a000000,0x00000000)}}, {VT_exponent,22,0x3a8477,{DOUBLEWITHTWODWORDINTREE(0x1a100000,0x00000000)}}, {VT_exponent,22,0x3a8478,{DOUBLEWITHTWODWORDINTREE(0x1a200000,0x00000000)}}, {VT_exponent,22,0x3a8479,{DOUBLEWITHTWODWORDINTREE(0x1a300000,0x00000000)}}, {VT_exponent,22,0x3a847a,{DOUBLEWITHTWODWORDINTREE(0x1a400000,0x00000000)}}, {VT_exponent,22,0x3a847b,{DOUBLEWITHTWODWORDINTREE(0x1a500000,0x00000000)}}, {VT_exponent,22,0x3a847c,{DOUBLEWITHTWODWORDINTREE(0x1a600000,0x00000000)}}, {VT_exponent,22,0x3a847d,{DOUBLEWITHTWODWORDINTREE(0x1a700000,0x00000000)}}, {VT_exponent,22,0x3a847e,{DOUBLEWITHTWODWORDINTREE(0x1a800000,0x00000000)}}, {VT_exponent,22,0x3a847f,{DOUBLEWITHTWODWORDINTREE(0x1a900000,0x00000000)}}, {VT_exponent,22,0x3a8480,{DOUBLEWITHTWODWORDINTREE(0x1aa00000,0x00000000)}}, {VT_exponent,22,0x3a8481,{DOUBLEWITHTWODWORDINTREE(0x1ab00000,0x00000000)}}, {VT_exponent,22,0x3a8482,{DOUBLEWITHTWODWORDINTREE(0x1ac00000,0x00000000)}}, {VT_exponent,22,0x3a8483,{DOUBLEWITHTWODWORDINTREE(0x1ad00000,0x00000000)}}, {VT_exponent,22,0x3a8484,{DOUBLEWITHTWODWORDINTREE(0x1ae00000,0x00000000)}}, {VT_exponent,22,0x3a8485,{DOUBLEWITHTWODWORDINTREE(0x1af00000,0x00000000)}}, {VT_exponent,22,0x3a8486,{DOUBLEWITHTWODWORDINTREE(0x1b000000,0x00000000)}}, {VT_exponent,22,0x3a8487,{DOUBLEWITHTWODWORDINTREE(0x1b100000,0x00000000)}}, {VT_exponent,22,0x3a8488,{DOUBLEWITHTWODWORDINTREE(0x1b200000,0x00000000)}}, {VT_exponent,22,0x3a8489,{DOUBLEWITHTWODWORDINTREE(0x1b300000,0x00000000)}}, {VT_exponent,22,0x3a848a,{DOUBLEWITHTWODWORDINTREE(0x1b400000,0x00000000)}}, {VT_exponent,22,0x3a848b,{DOUBLEWITHTWODWORDINTREE(0x1b500000,0x00000000)}}, {VT_exponent,22,0x3a848c,{DOUBLEWITHTWODWORDINTREE(0x1b600000,0x00000000)}}, {VT_exponent,22,0x3a848d,{DOUBLEWITHTWODWORDINTREE(0x1b700000,0x00000000)}}, {VT_exponent,22,0x3a848e,{DOUBLEWITHTWODWORDINTREE(0x1b800000,0x00000000)}}, {VT_exponent,22,0x3a848f,{DOUBLEWITHTWODWORDINTREE(0x1b900000,0x00000000)}}, {VT_exponent,22,0x3a8490,{DOUBLEWITHTWODWORDINTREE(0x1ba00000,0x00000000)}}, {VT_exponent,22,0x3a8491,{DOUBLEWITHTWODWORDINTREE(0x1bb00000,0x00000000)}}, {VT_exponent,22,0x3a8492,{DOUBLEWITHTWODWORDINTREE(0x1bc00000,0x00000000)}}, {VT_exponent,22,0x3a8493,{DOUBLEWITHTWODWORDINTREE(0x1bd00000,0x00000000)}}, {VT_exponent,22,0x3a8494,{DOUBLEWITHTWODWORDINTREE(0x1be00000,0x00000000)}}, {VT_exponent,22,0x3a8495,{DOUBLEWITHTWODWORDINTREE(0x1bf00000,0x00000000)}}, {VT_exponent,22,0x3a8496,{DOUBLEWITHTWODWORDINTREE(0x1c000000,0x00000000)}}, {VT_exponent,22,0x3a8497,{DOUBLEWITHTWODWORDINTREE(0x1c100000,0x00000000)}}, {VT_exponent,22,0x3a8498,{DOUBLEWITHTWODWORDINTREE(0x1c200000,0x00000000)}}, {VT_exponent,22,0x3a8499,{DOUBLEWITHTWODWORDINTREE(0x1c300000,0x00000000)}}, {VT_exponent,22,0x3a849a,{DOUBLEWITHTWODWORDINTREE(0x1c400000,0x00000000)}}, {VT_exponent,22,0x3a849b,{DOUBLEWITHTWODWORDINTREE(0x1c500000,0x00000000)}}, {VT_exponent,22,0x3a849c,{DOUBLEWITHTWODWORDINTREE(0x1c600000,0x00000000)}}, {VT_exponent,22,0x3a849d,{DOUBLEWITHTWODWORDINTREE(0x1c700000,0x00000000)}}, {VT_exponent,22,0x3a849e,{DOUBLEWITHTWODWORDINTREE(0x1c800000,0x00000000)}}, {VT_exponent,22,0x3a849f,{DOUBLEWITHTWODWORDINTREE(0x1c900000,0x00000000)}}, {VT_exponent,22,0x3a84a0,{DOUBLEWITHTWODWORDINTREE(0x1ca00000,0x00000000)}}, {VT_exponent,22,0x3a84a1,{DOUBLEWITHTWODWORDINTREE(0x1cb00000,0x00000000)}}, {VT_exponent,22,0x3a84a2,{DOUBLEWITHTWODWORDINTREE(0x1cc00000,0x00000000)}}, {VT_exponent,22,0x3a84a3,{DOUBLEWITHTWODWORDINTREE(0x1cd00000,0x00000000)}}, {VT_exponent,22,0x3a84a4,{DOUBLEWITHTWODWORDINTREE(0x1ce00000,0x00000000)}}, {VT_exponent,22,0x3a84a5,{DOUBLEWITHTWODWORDINTREE(0x1cf00000,0x00000000)}}, {VT_exponent,22,0x3a84a6,{DOUBLEWITHTWODWORDINTREE(0x1d000000,0x00000000)}}, {VT_exponent,22,0x3a84a7,{DOUBLEWITHTWODWORDINTREE(0x1d100000,0x00000000)}}, {VT_exponent,22,0x3a84a8,{DOUBLEWITHTWODWORDINTREE(0x1d200000,0x00000000)}}, {VT_exponent,22,0x3a84a9,{DOUBLEWITHTWODWORDINTREE(0x1d300000,0x00000000)}}, {VT_exponent,22,0x3a84aa,{DOUBLEWITHTWODWORDINTREE(0x1d400000,0x00000000)}}, {VT_exponent,22,0x3a84ab,{DOUBLEWITHTWODWORDINTREE(0x1d500000,0x00000000)}}, {VT_exponent,22,0x3a84ac,{DOUBLEWITHTWODWORDINTREE(0x1d600000,0x00000000)}}, {VT_exponent,22,0x3a84ad,{DOUBLEWITHTWODWORDINTREE(0x1d700000,0x00000000)}}, {VT_exponent,22,0x3a84ae,{DOUBLEWITHTWODWORDINTREE(0x1d800000,0x00000000)}}, {VT_exponent,22,0x3a84af,{DOUBLEWITHTWODWORDINTREE(0x1d900000,0x00000000)}}, {VT_exponent,22,0x3a84b0,{DOUBLEWITHTWODWORDINTREE(0x1da00000,0x00000000)}}, {VT_exponent,22,0x3a84b1,{DOUBLEWITHTWODWORDINTREE(0x1db00000,0x00000000)}}, {VT_exponent,22,0x3a84b2,{DOUBLEWITHTWODWORDINTREE(0x1dc00000,0x00000000)}}, {VT_exponent,22,0x3a84b3,{DOUBLEWITHTWODWORDINTREE(0x1dd00000,0x00000000)}}, {VT_exponent,22,0x3a84b4,{DOUBLEWITHTWODWORDINTREE(0x1de00000,0x00000000)}}, {VT_exponent,22,0x3a84b5,{DOUBLEWITHTWODWORDINTREE(0x1df00000,0x00000000)}}, {VT_exponent,22,0x3a84b6,{DOUBLEWITHTWODWORDINTREE(0x1e000000,0x00000000)}}, {VT_exponent,22,0x3a84b7,{DOUBLEWITHTWODWORDINTREE(0x1e100000,0x00000000)}}, {VT_exponent,22,0x3a84b8,{DOUBLEWITHTWODWORDINTREE(0x1e200000,0x00000000)}}, {VT_exponent,22,0x3a84b9,{DOUBLEWITHTWODWORDINTREE(0x1e300000,0x00000000)}}, {VT_exponent,22,0x3a84ba,{DOUBLEWITHTWODWORDINTREE(0x1e400000,0x00000000)}}, {VT_exponent,22,0x3a84bb,{DOUBLEWITHTWODWORDINTREE(0x1e500000,0x00000000)}}, {VT_exponent,22,0x3a84bc,{DOUBLEWITHTWODWORDINTREE(0x1e600000,0x00000000)}}, {VT_exponent,22,0x3a84bd,{DOUBLEWITHTWODWORDINTREE(0x1e700000,0x00000000)}}, {VT_exponent,22,0x3a84be,{DOUBLEWITHTWODWORDINTREE(0x1e800000,0x00000000)}}, {VT_exponent,22,0x3a84bf,{DOUBLEWITHTWODWORDINTREE(0x1e900000,0x00000000)}}, {VT_exponent,22,0x3a84c0,{DOUBLEWITHTWODWORDINTREE(0x1ea00000,0x00000000)}}, {VT_exponent,22,0x3a84c1,{DOUBLEWITHTWODWORDINTREE(0x1eb00000,0x00000000)}}, {VT_exponent,22,0x3a84c2,{DOUBLEWITHTWODWORDINTREE(0x1ec00000,0x00000000)}}, {VT_exponent,22,0x3a84c3,{DOUBLEWITHTWODWORDINTREE(0x1ed00000,0x00000000)}}, {VT_exponent,22,0x3a84c4,{DOUBLEWITHTWODWORDINTREE(0x1ee00000,0x00000000)}}, {VT_exponent,22,0x3a84c5,{DOUBLEWITHTWODWORDINTREE(0x1ef00000,0x00000000)}}, {VT_exponent,22,0x3a84c6,{DOUBLEWITHTWODWORDINTREE(0x1f000000,0x00000000)}}, {VT_exponent,22,0x3a84c7,{DOUBLEWITHTWODWORDINTREE(0x1f100000,0x00000000)}}, {VT_exponent,22,0x3a84c8,{DOUBLEWITHTWODWORDINTREE(0x1f200000,0x00000000)}}, {VT_exponent,22,0x3a84c9,{DOUBLEWITHTWODWORDINTREE(0x1f300000,0x00000000)}}, {VT_exponent,22,0x3a84ca,{DOUBLEWITHTWODWORDINTREE(0x1f400000,0x00000000)}}, {VT_exponent,22,0x3a84cb,{DOUBLEWITHTWODWORDINTREE(0x1f500000,0x00000000)}}, {VT_exponent,22,0x3a84cc,{DOUBLEWITHTWODWORDINTREE(0x1f600000,0x00000000)}}, {VT_exponent,22,0x3a84cd,{DOUBLEWITHTWODWORDINTREE(0x1f700000,0x00000000)}}, {VT_exponent,22,0x3a84ce,{DOUBLEWITHTWODWORDINTREE(0x1f800000,0x00000000)}}, {VT_exponent,22,0x3a84cf,{DOUBLEWITHTWODWORDINTREE(0x1f900000,0x00000000)}}, {VT_exponent,22,0x3a84d0,{DOUBLEWITHTWODWORDINTREE(0x1fa00000,0x00000000)}}, {VT_exponent,22,0x3a84d1,{DOUBLEWITHTWODWORDINTREE(0x1fb00000,0x00000000)}}, {VT_exponent,22,0x3a84d2,{DOUBLEWITHTWODWORDINTREE(0x1fc00000,0x00000000)}}, {VT_exponent,22,0x3a84d3,{DOUBLEWITHTWODWORDINTREE(0x1fd00000,0x00000000)}}, {VT_exponent,22,0x3a84d4,{DOUBLEWITHTWODWORDINTREE(0x1fe00000,0x00000000)}}, {VT_exponent,22,0x3a84d5,{DOUBLEWITHTWODWORDINTREE(0x1ff00000,0x00000000)}}, {VT_exponent,22,0x3a84d6,{DOUBLEWITHTWODWORDINTREE(0x20000000,0x00000000)}}, {VT_exponent,22,0x3a84d7,{DOUBLEWITHTWODWORDINTREE(0x20100000,0x00000000)}}, {VT_exponent,22,0x3a84d8,{DOUBLEWITHTWODWORDINTREE(0x20200000,0x00000000)}}, {VT_exponent,22,0x3a84d9,{DOUBLEWITHTWODWORDINTREE(0x20300000,0x00000000)}}, {VT_exponent,22,0x3a84da,{DOUBLEWITHTWODWORDINTREE(0x20400000,0x00000000)}}, {VT_exponent,22,0x3a84db,{DOUBLEWITHTWODWORDINTREE(0x20500000,0x00000000)}}, {VT_exponent,22,0x3a84dc,{DOUBLEWITHTWODWORDINTREE(0x20600000,0x00000000)}}, {VT_exponent,22,0x3a84dd,{DOUBLEWITHTWODWORDINTREE(0x20700000,0x00000000)}}, {VT_exponent,22,0x3a84de,{DOUBLEWITHTWODWORDINTREE(0x20800000,0x00000000)}}, {VT_exponent,22,0x3a84df,{DOUBLEWITHTWODWORDINTREE(0x20900000,0x00000000)}}, {VT_exponent,22,0x3a84e0,{DOUBLEWITHTWODWORDINTREE(0x20a00000,0x00000000)}}, {VT_exponent,22,0x3a84e1,{DOUBLEWITHTWODWORDINTREE(0x20b00000,0x00000000)}}, {VT_exponent,22,0x3a84e2,{DOUBLEWITHTWODWORDINTREE(0x20c00000,0x00000000)}}, {VT_exponent,22,0x3a84e3,{DOUBLEWITHTWODWORDINTREE(0x20d00000,0x00000000)}}, {VT_exponent,22,0x3a84e4,{DOUBLEWITHTWODWORDINTREE(0x20e00000,0x00000000)}}, {VT_exponent,22,0x3a84e5,{DOUBLEWITHTWODWORDINTREE(0x20f00000,0x00000000)}}, {VT_exponent,22,0x3a84e6,{DOUBLEWITHTWODWORDINTREE(0x21000000,0x00000000)}}, {VT_exponent,22,0x3a84e7,{DOUBLEWITHTWODWORDINTREE(0x21100000,0x00000000)}}, {VT_exponent,22,0x3a84e8,{DOUBLEWITHTWODWORDINTREE(0x21200000,0x00000000)}}, {VT_exponent,22,0x3a84e9,{DOUBLEWITHTWODWORDINTREE(0x21300000,0x00000000)}}, {VT_exponent,22,0x3a84ea,{DOUBLEWITHTWODWORDINTREE(0x21400000,0x00000000)}}, {VT_exponent,22,0x3a84eb,{DOUBLEWITHTWODWORDINTREE(0x21500000,0x00000000)}}, {VT_exponent,22,0x3a84ec,{DOUBLEWITHTWODWORDINTREE(0x21600000,0x00000000)}}, {VT_exponent,22,0x3a84ed,{DOUBLEWITHTWODWORDINTREE(0x21700000,0x00000000)}}, {VT_exponent,22,0x3a84ee,{DOUBLEWITHTWODWORDINTREE(0x21800000,0x00000000)}}, {VT_exponent,22,0x3a84ef,{DOUBLEWITHTWODWORDINTREE(0x21900000,0x00000000)}}, {VT_exponent,22,0x3a84f0,{DOUBLEWITHTWODWORDINTREE(0x21a00000,0x00000000)}}, {VT_exponent,22,0x3a84f1,{DOUBLEWITHTWODWORDINTREE(0x21b00000,0x00000000)}}, {VT_exponent,22,0x3a84f2,{DOUBLEWITHTWODWORDINTREE(0x21c00000,0x00000000)}}, {VT_exponent,22,0x3a84f3,{DOUBLEWITHTWODWORDINTREE(0x21d00000,0x00000000)}}, {VT_exponent,22,0x3a84f4,{DOUBLEWITHTWODWORDINTREE(0x21e00000,0x00000000)}}, {VT_exponent,22,0x3a84f5,{DOUBLEWITHTWODWORDINTREE(0x21f00000,0x00000000)}}, {VT_exponent,22,0x3a84f6,{DOUBLEWITHTWODWORDINTREE(0x22000000,0x00000000)}}, {VT_exponent,22,0x3a84f7,{DOUBLEWITHTWODWORDINTREE(0x22100000,0x00000000)}}, {VT_exponent,22,0x3a84f8,{DOUBLEWITHTWODWORDINTREE(0x22200000,0x00000000)}}, {VT_exponent,22,0x3a84f9,{DOUBLEWITHTWODWORDINTREE(0x22300000,0x00000000)}}, {VT_exponent,22,0x3a84fa,{DOUBLEWITHTWODWORDINTREE(0x22400000,0x00000000)}}, {VT_exponent,22,0x3a84fb,{DOUBLEWITHTWODWORDINTREE(0x22500000,0x00000000)}}, {VT_exponent,22,0x3a84fc,{DOUBLEWITHTWODWORDINTREE(0x22600000,0x00000000)}}, {VT_exponent,22,0x3a84fd,{DOUBLEWITHTWODWORDINTREE(0x22700000,0x00000000)}}, {VT_exponent,22,0x3a84fe,{DOUBLEWITHTWODWORDINTREE(0x22800000,0x00000000)}}, {VT_exponent,22,0x3a84ff,{DOUBLEWITHTWODWORDINTREE(0x22900000,0x00000000)}}, {VT_exponent,22,0x3a8500,{DOUBLEWITHTWODWORDINTREE(0x22a00000,0x00000000)}}, {VT_exponent,22,0x3a8501,{DOUBLEWITHTWODWORDINTREE(0x22b00000,0x00000000)}}, {VT_exponent,22,0x3a8502,{DOUBLEWITHTWODWORDINTREE(0x22c00000,0x00000000)}}, {VT_exponent,22,0x3a8503,{DOUBLEWITHTWODWORDINTREE(0x22d00000,0x00000000)}}, {VT_exponent,22,0x3a8504,{DOUBLEWITHTWODWORDINTREE(0x22e00000,0x00000000)}}, {VT_exponent,22,0x3a8505,{DOUBLEWITHTWODWORDINTREE(0x22f00000,0x00000000)}}, {VT_exponent,22,0x3a8506,{DOUBLEWITHTWODWORDINTREE(0x23000000,0x00000000)}}, {VT_exponent,22,0x3a8507,{DOUBLEWITHTWODWORDINTREE(0x23100000,0x00000000)}}, {VT_exponent,22,0x3a8508,{DOUBLEWITHTWODWORDINTREE(0x23200000,0x00000000)}}, {VT_exponent,22,0x3a8509,{DOUBLEWITHTWODWORDINTREE(0x23300000,0x00000000)}}, {VT_exponent,22,0x3a850a,{DOUBLEWITHTWODWORDINTREE(0x23400000,0x00000000)}}, {VT_exponent,22,0x3a850b,{DOUBLEWITHTWODWORDINTREE(0x23500000,0x00000000)}}, {VT_exponent,22,0x3a850c,{DOUBLEWITHTWODWORDINTREE(0x23600000,0x00000000)}}, {VT_exponent,22,0x3a850d,{DOUBLEWITHTWODWORDINTREE(0x23700000,0x00000000)}}, {VT_exponent,22,0x3a850e,{DOUBLEWITHTWODWORDINTREE(0x23800000,0x00000000)}}, {VT_exponent,22,0x3a850f,{DOUBLEWITHTWODWORDINTREE(0x23900000,0x00000000)}}, {VT_exponent,22,0x3a8510,{DOUBLEWITHTWODWORDINTREE(0x23a00000,0x00000000)}}, {VT_exponent,22,0x3a8511,{DOUBLEWITHTWODWORDINTREE(0x23b00000,0x00000000)}}, {VT_exponent,22,0x3a8512,{DOUBLEWITHTWODWORDINTREE(0x23c00000,0x00000000)}}, {VT_exponent,22,0x3a8513,{DOUBLEWITHTWODWORDINTREE(0x23d00000,0x00000000)}}, {VT_exponent,22,0x3a8514,{DOUBLEWITHTWODWORDINTREE(0x23e00000,0x00000000)}}, {VT_exponent,22,0x3a8515,{DOUBLEWITHTWODWORDINTREE(0x23f00000,0x00000000)}}, {VT_exponent,22,0x3a8516,{DOUBLEWITHTWODWORDINTREE(0x24000000,0x00000000)}}, {VT_exponent,22,0x3a8517,{DOUBLEWITHTWODWORDINTREE(0x24100000,0x00000000)}}, {VT_exponent,22,0x3a8518,{DOUBLEWITHTWODWORDINTREE(0x24200000,0x00000000)}}, {VT_exponent,22,0x3a8519,{DOUBLEWITHTWODWORDINTREE(0x24300000,0x00000000)}}, {VT_exponent,22,0x3a851a,{DOUBLEWITHTWODWORDINTREE(0x24400000,0x00000000)}}, {VT_exponent,22,0x3a851b,{DOUBLEWITHTWODWORDINTREE(0x24500000,0x00000000)}}, {VT_exponent,22,0x3a851c,{DOUBLEWITHTWODWORDINTREE(0x24600000,0x00000000)}}, {VT_exponent,22,0x3a851d,{DOUBLEWITHTWODWORDINTREE(0x24700000,0x00000000)}}, {VT_exponent,22,0x3a851e,{DOUBLEWITHTWODWORDINTREE(0x24800000,0x00000000)}}, {VT_exponent,22,0x3a851f,{DOUBLEWITHTWODWORDINTREE(0x24900000,0x00000000)}}, {VT_exponent,22,0x3a8520,{DOUBLEWITHTWODWORDINTREE(0x24a00000,0x00000000)}}, {VT_exponent,22,0x3a8521,{DOUBLEWITHTWODWORDINTREE(0x24b00000,0x00000000)}}, {VT_exponent,22,0x3a8522,{DOUBLEWITHTWODWORDINTREE(0x24c00000,0x00000000)}}, {VT_exponent,22,0x3a8523,{DOUBLEWITHTWODWORDINTREE(0x24d00000,0x00000000)}}, {VT_exponent,22,0x3a8524,{DOUBLEWITHTWODWORDINTREE(0x24e00000,0x00000000)}}, {VT_exponent,22,0x3a8525,{DOUBLEWITHTWODWORDINTREE(0x24f00000,0x00000000)}}, {VT_exponent,22,0x3a8526,{DOUBLEWITHTWODWORDINTREE(0x25000000,0x00000000)}}, {VT_exponent,22,0x3a8527,{DOUBLEWITHTWODWORDINTREE(0x25100000,0x00000000)}}, {VT_exponent,22,0x3a8528,{DOUBLEWITHTWODWORDINTREE(0x25200000,0x00000000)}}, {VT_exponent,22,0x3a8529,{DOUBLEWITHTWODWORDINTREE(0x25300000,0x00000000)}}, {VT_exponent,22,0x3a852a,{DOUBLEWITHTWODWORDINTREE(0x25400000,0x00000000)}}, {VT_exponent,22,0x3a852b,{DOUBLEWITHTWODWORDINTREE(0x25500000,0x00000000)}}, {VT_exponent,22,0x3a852c,{DOUBLEWITHTWODWORDINTREE(0x25600000,0x00000000)}}, {VT_exponent,22,0x3a852d,{DOUBLEWITHTWODWORDINTREE(0x25700000,0x00000000)}}, {VT_exponent,22,0x3a852e,{DOUBLEWITHTWODWORDINTREE(0x25800000,0x00000000)}}, {VT_exponent,22,0x3a852f,{DOUBLEWITHTWODWORDINTREE(0x25900000,0x00000000)}}, {VT_exponent,22,0x3a8530,{DOUBLEWITHTWODWORDINTREE(0x25a00000,0x00000000)}}, {VT_exponent,22,0x3a8531,{DOUBLEWITHTWODWORDINTREE(0x25b00000,0x00000000)}}, {VT_exponent,22,0x3a8532,{DOUBLEWITHTWODWORDINTREE(0x25c00000,0x00000000)}}, {VT_exponent,22,0x3a8533,{DOUBLEWITHTWODWORDINTREE(0x25d00000,0x00000000)}}, {VT_exponent,22,0x3a8534,{DOUBLEWITHTWODWORDINTREE(0x25e00000,0x00000000)}}, {VT_exponent,22,0x3a8535,{DOUBLEWITHTWODWORDINTREE(0x25f00000,0x00000000)}}, {VT_exponent,22,0x3a8536,{DOUBLEWITHTWODWORDINTREE(0x26000000,0x00000000)}}, {VT_exponent,22,0x3a8537,{DOUBLEWITHTWODWORDINTREE(0x26100000,0x00000000)}}, {VT_exponent,22,0x3a8538,{DOUBLEWITHTWODWORDINTREE(0x26200000,0x00000000)}}, {VT_exponent,22,0x3a8539,{DOUBLEWITHTWODWORDINTREE(0x26300000,0x00000000)}}, {VT_exponent,22,0x3a853a,{DOUBLEWITHTWODWORDINTREE(0x26400000,0x00000000)}}, {VT_exponent,22,0x3a853b,{DOUBLEWITHTWODWORDINTREE(0x26500000,0x00000000)}}, {VT_exponent,22,0x3a853c,{DOUBLEWITHTWODWORDINTREE(0x26600000,0x00000000)}}, {VT_exponent,22,0x3a853d,{DOUBLEWITHTWODWORDINTREE(0x26700000,0x00000000)}}, {VT_exponent,22,0x3a853e,{DOUBLEWITHTWODWORDINTREE(0x26800000,0x00000000)}}, {VT_exponent,22,0x3a853f,{DOUBLEWITHTWODWORDINTREE(0x26900000,0x00000000)}}, {VT_exponent,22,0x3a8540,{DOUBLEWITHTWODWORDINTREE(0x26a00000,0x00000000)}}, {VT_exponent,22,0x3a8541,{DOUBLEWITHTWODWORDINTREE(0x26b00000,0x00000000)}}, {VT_exponent,22,0x3a8542,{DOUBLEWITHTWODWORDINTREE(0x26c00000,0x00000000)}}, {VT_exponent,22,0x3a8543,{DOUBLEWITHTWODWORDINTREE(0x26d00000,0x00000000)}}, {VT_exponent,22,0x3a8544,{DOUBLEWITHTWODWORDINTREE(0x26e00000,0x00000000)}}, {VT_exponent,22,0x3a8545,{DOUBLEWITHTWODWORDINTREE(0x26f00000,0x00000000)}}, {VT_exponent,22,0x3a8546,{DOUBLEWITHTWODWORDINTREE(0x27000000,0x00000000)}}, {VT_exponent,22,0x3a8547,{DOUBLEWITHTWODWORDINTREE(0x27100000,0x00000000)}}, {VT_exponent,22,0x3a8548,{DOUBLEWITHTWODWORDINTREE(0x27200000,0x00000000)}}, {VT_exponent,22,0x3a8549,{DOUBLEWITHTWODWORDINTREE(0x27300000,0x00000000)}}, {VT_exponent,22,0x3a854a,{DOUBLEWITHTWODWORDINTREE(0x27400000,0x00000000)}}, {VT_exponent,22,0x3a854b,{DOUBLEWITHTWODWORDINTREE(0x27500000,0x00000000)}}, {VT_exponent,22,0x3a854c,{DOUBLEWITHTWODWORDINTREE(0x27600000,0x00000000)}}, {VT_exponent,22,0x3a854d,{DOUBLEWITHTWODWORDINTREE(0x27700000,0x00000000)}}, {VT_exponent,22,0x3a854e,{DOUBLEWITHTWODWORDINTREE(0x27800000,0x00000000)}}, {VT_exponent,22,0x3a854f,{DOUBLEWITHTWODWORDINTREE(0x27900000,0x00000000)}}, {VT_exponent,22,0x3a8550,{DOUBLEWITHTWODWORDINTREE(0x27a00000,0x00000000)}}, {VT_exponent,22,0x3a8551,{DOUBLEWITHTWODWORDINTREE(0x27b00000,0x00000000)}}, {VT_exponent,22,0x3a8552,{DOUBLEWITHTWODWORDINTREE(0x27c00000,0x00000000)}}, {VT_exponent,22,0x3a8553,{DOUBLEWITHTWODWORDINTREE(0x27d00000,0x00000000)}}, {VT_exponent,22,0x3a8554,{DOUBLEWITHTWODWORDINTREE(0x27e00000,0x00000000)}}, {VT_exponent,22,0x3a8555,{DOUBLEWITHTWODWORDINTREE(0x27f00000,0x00000000)}}, {VT_exponent,22,0x3a8556,{DOUBLEWITHTWODWORDINTREE(0x28000000,0x00000000)}}, {VT_exponent,22,0x3a8557,{DOUBLEWITHTWODWORDINTREE(0x28100000,0x00000000)}}, {VT_exponent,22,0x3a8558,{DOUBLEWITHTWODWORDINTREE(0x28200000,0x00000000)}}, {VT_exponent,22,0x3a8559,{DOUBLEWITHTWODWORDINTREE(0x28300000,0x00000000)}}, {VT_exponent,22,0x3a855a,{DOUBLEWITHTWODWORDINTREE(0x28400000,0x00000000)}}, {VT_exponent,22,0x3a855b,{DOUBLEWITHTWODWORDINTREE(0x28500000,0x00000000)}}, {VT_exponent,22,0x3a855c,{DOUBLEWITHTWODWORDINTREE(0x28600000,0x00000000)}}, {VT_exponent,22,0x3a855d,{DOUBLEWITHTWODWORDINTREE(0x28700000,0x00000000)}}, {VT_exponent,22,0x3a855e,{DOUBLEWITHTWODWORDINTREE(0x28800000,0x00000000)}}, {VT_exponent,22,0x3a855f,{DOUBLEWITHTWODWORDINTREE(0x28900000,0x00000000)}}, {VT_exponent,22,0x3a8560,{DOUBLEWITHTWODWORDINTREE(0x28a00000,0x00000000)}}, {VT_exponent,22,0x3a8561,{DOUBLEWITHTWODWORDINTREE(0x28b00000,0x00000000)}}, {VT_exponent,22,0x3a8562,{DOUBLEWITHTWODWORDINTREE(0x28c00000,0x00000000)}}, {VT_exponent,22,0x3a8563,{DOUBLEWITHTWODWORDINTREE(0x28d00000,0x00000000)}}, {VT_exponent,22,0x3a8564,{DOUBLEWITHTWODWORDINTREE(0x28e00000,0x00000000)}}, {VT_exponent,22,0x3a8565,{DOUBLEWITHTWODWORDINTREE(0x28f00000,0x00000000)}}, {VT_exponent,22,0x3a8566,{DOUBLEWITHTWODWORDINTREE(0x29000000,0x00000000)}}, {VT_exponent,22,0x3a8567,{DOUBLEWITHTWODWORDINTREE(0x29100000,0x00000000)}}, {VT_exponent,22,0x3a8568,{DOUBLEWITHTWODWORDINTREE(0x29200000,0x00000000)}}, {VT_exponent,22,0x3a8569,{DOUBLEWITHTWODWORDINTREE(0x29300000,0x00000000)}}, {VT_exponent,22,0x3a856a,{DOUBLEWITHTWODWORDINTREE(0x29400000,0x00000000)}}, {VT_exponent,22,0x3a856b,{DOUBLEWITHTWODWORDINTREE(0x29500000,0x00000000)}}, {VT_exponent,22,0x3a856c,{DOUBLEWITHTWODWORDINTREE(0x29600000,0x00000000)}}, {VT_exponent,22,0x3a856d,{DOUBLEWITHTWODWORDINTREE(0x29700000,0x00000000)}}, {VT_exponent,22,0x3a856e,{DOUBLEWITHTWODWORDINTREE(0x29800000,0x00000000)}}, {VT_exponent,22,0x3a856f,{DOUBLEWITHTWODWORDINTREE(0x29900000,0x00000000)}}, {VT_exponent,22,0x3a8570,{DOUBLEWITHTWODWORDINTREE(0x29a00000,0x00000000)}}, {VT_exponent,22,0x3a8571,{DOUBLEWITHTWODWORDINTREE(0x29b00000,0x00000000)}}, {VT_exponent,22,0x3a8572,{DOUBLEWITHTWODWORDINTREE(0x29c00000,0x00000000)}}, {VT_exponent,22,0x3a8573,{DOUBLEWITHTWODWORDINTREE(0x29d00000,0x00000000)}}, {VT_exponent,22,0x3a8574,{DOUBLEWITHTWODWORDINTREE(0x29e00000,0x00000000)}}, {VT_exponent,22,0x3a8575,{DOUBLEWITHTWODWORDINTREE(0x29f00000,0x00000000)}}, {VT_exponent,22,0x3a8576,{DOUBLEWITHTWODWORDINTREE(0x2a000000,0x00000000)}}, {VT_exponent,22,0x3a8577,{DOUBLEWITHTWODWORDINTREE(0x2a100000,0x00000000)}}, {VT_exponent,22,0x3a8578,{DOUBLEWITHTWODWORDINTREE(0x2a200000,0x00000000)}}, {VT_exponent,22,0x3a8579,{DOUBLEWITHTWODWORDINTREE(0x2a300000,0x00000000)}}, {VT_exponent,22,0x3a857a,{DOUBLEWITHTWODWORDINTREE(0x2a400000,0x00000000)}}, {VT_exponent,22,0x3a857b,{DOUBLEWITHTWODWORDINTREE(0x2a500000,0x00000000)}}, {VT_exponent,22,0x3a857c,{DOUBLEWITHTWODWORDINTREE(0x2a600000,0x00000000)}}, {VT_exponent,22,0x3a857d,{DOUBLEWITHTWODWORDINTREE(0x2a700000,0x00000000)}}, {VT_exponent,22,0x3a857e,{DOUBLEWITHTWODWORDINTREE(0x2a800000,0x00000000)}}, {VT_exponent,22,0x3a857f,{DOUBLEWITHTWODWORDINTREE(0x2a900000,0x00000000)}}, {VT_exponent,22,0x3a8580,{DOUBLEWITHTWODWORDINTREE(0x2aa00000,0x00000000)}}, {VT_exponent,22,0x3a8581,{DOUBLEWITHTWODWORDINTREE(0x2ab00000,0x00000000)}}, {VT_exponent,22,0x3a8582,{DOUBLEWITHTWODWORDINTREE(0x2ac00000,0x00000000)}}, {VT_exponent,22,0x3a8583,{DOUBLEWITHTWODWORDINTREE(0x2ad00000,0x00000000)}}, {VT_exponent,22,0x3a8584,{DOUBLEWITHTWODWORDINTREE(0x2ae00000,0x00000000)}}, {VT_exponent,22,0x3a8585,{DOUBLEWITHTWODWORDINTREE(0x2af00000,0x00000000)}}, {VT_exponent,22,0x3a8586,{DOUBLEWITHTWODWORDINTREE(0x2b000000,0x00000000)}}, {VT_exponent,22,0x3a8587,{DOUBLEWITHTWODWORDINTREE(0x2b100000,0x00000000)}}, {VT_exponent,22,0x3a8588,{DOUBLEWITHTWODWORDINTREE(0x2b200000,0x00000000)}}, {VT_exponent,22,0x3a8589,{DOUBLEWITHTWODWORDINTREE(0x2b300000,0x00000000)}}, {VT_exponent,22,0x3a858a,{DOUBLEWITHTWODWORDINTREE(0x2b400000,0x00000000)}}, {VT_exponent,22,0x3a858b,{DOUBLEWITHTWODWORDINTREE(0x2b500000,0x00000000)}}, {VT_exponent,22,0x3a858c,{DOUBLEWITHTWODWORDINTREE(0x2b600000,0x00000000)}}, {VT_exponent,22,0x3a858d,{DOUBLEWITHTWODWORDINTREE(0x2b700000,0x00000000)}}, {VT_exponent,22,0x3a858e,{DOUBLEWITHTWODWORDINTREE(0x2b800000,0x00000000)}}, {VT_exponent,22,0x3a858f,{DOUBLEWITHTWODWORDINTREE(0x2b900000,0x00000000)}}, {VT_exponent,22,0x3a8590,{DOUBLEWITHTWODWORDINTREE(0x2ba00000,0x00000000)}}, {VT_exponent,22,0x3a8591,{DOUBLEWITHTWODWORDINTREE(0x2bb00000,0x00000000)}}, {VT_exponent,22,0x3a8592,{DOUBLEWITHTWODWORDINTREE(0x2bc00000,0x00000000)}}, {VT_exponent,22,0x3a8593,{DOUBLEWITHTWODWORDINTREE(0x2bd00000,0x00000000)}}, {VT_exponent,22,0x3a8594,{DOUBLEWITHTWODWORDINTREE(0x2be00000,0x00000000)}}, {VT_exponent,22,0x3a8595,{DOUBLEWITHTWODWORDINTREE(0x2bf00000,0x00000000)}}, {VT_exponent,22,0x3a8596,{DOUBLEWITHTWODWORDINTREE(0x2c000000,0x00000000)}}, {VT_exponent,22,0x3a8597,{DOUBLEWITHTWODWORDINTREE(0x2c100000,0x00000000)}}, {VT_exponent,22,0x3a8598,{DOUBLEWITHTWODWORDINTREE(0x2c200000,0x00000000)}}, {VT_exponent,22,0x3a8599,{DOUBLEWITHTWODWORDINTREE(0x2c300000,0x00000000)}}, {VT_exponent,22,0x3a859a,{DOUBLEWITHTWODWORDINTREE(0x2c400000,0x00000000)}}, {VT_exponent,22,0x3a859b,{DOUBLEWITHTWODWORDINTREE(0x2c500000,0x00000000)}}, {VT_exponent,22,0x3a859c,{DOUBLEWITHTWODWORDINTREE(0x2c600000,0x00000000)}}, {VT_exponent,22,0x3a859d,{DOUBLEWITHTWODWORDINTREE(0x2c700000,0x00000000)}}, {VT_exponent,22,0x3a859e,{DOUBLEWITHTWODWORDINTREE(0x2c800000,0x00000000)}}, {VT_exponent,22,0x3a859f,{DOUBLEWITHTWODWORDINTREE(0x2c900000,0x00000000)}}, {VT_exponent,22,0x3a85a0,{DOUBLEWITHTWODWORDINTREE(0x2ca00000,0x00000000)}}, {VT_exponent,22,0x3a85a1,{DOUBLEWITHTWODWORDINTREE(0x2cb00000,0x00000000)}}, {VT_exponent,22,0x3a85a2,{DOUBLEWITHTWODWORDINTREE(0x2cc00000,0x00000000)}}, {VT_exponent,22,0x3a85a3,{DOUBLEWITHTWODWORDINTREE(0x2cd00000,0x00000000)}}, {VT_exponent,22,0x3a85a4,{DOUBLEWITHTWODWORDINTREE(0x2ce00000,0x00000000)}}, {VT_exponent,22,0x3a85a5,{DOUBLEWITHTWODWORDINTREE(0x2cf00000,0x00000000)}}, {VT_exponent,22,0x3a85a6,{DOUBLEWITHTWODWORDINTREE(0x2d000000,0x00000000)}}, {VT_exponent,22,0x3a85a7,{DOUBLEWITHTWODWORDINTREE(0x2d100000,0x00000000)}}, {VT_exponent,22,0x3a85a8,{DOUBLEWITHTWODWORDINTREE(0x2d200000,0x00000000)}}, {VT_exponent,22,0x3a85a9,{DOUBLEWITHTWODWORDINTREE(0x2d300000,0x00000000)}}, {VT_exponent,22,0x3a85aa,{DOUBLEWITHTWODWORDINTREE(0x2d400000,0x00000000)}}, {VT_exponent,22,0x3a85ab,{DOUBLEWITHTWODWORDINTREE(0x2d500000,0x00000000)}}, {VT_exponent,22,0x3a85ac,{DOUBLEWITHTWODWORDINTREE(0x2d600000,0x00000000)}}, {VT_exponent,22,0x3a85ad,{DOUBLEWITHTWODWORDINTREE(0x2d700000,0x00000000)}}, {VT_exponent,22,0x3a85ae,{DOUBLEWITHTWODWORDINTREE(0x2d800000,0x00000000)}}, {VT_exponent,22,0x3a85af,{DOUBLEWITHTWODWORDINTREE(0x2d900000,0x00000000)}}, {VT_exponent,22,0x3a85b0,{DOUBLEWITHTWODWORDINTREE(0x2da00000,0x00000000)}}, {VT_exponent,22,0x3a85b1,{DOUBLEWITHTWODWORDINTREE(0x2db00000,0x00000000)}}, {VT_exponent,22,0x3a85b2,{DOUBLEWITHTWODWORDINTREE(0x2dc00000,0x00000000)}}, {VT_exponent,22,0x3a85b3,{DOUBLEWITHTWODWORDINTREE(0x2dd00000,0x00000000)}}, {VT_exponent,22,0x3a85b4,{DOUBLEWITHTWODWORDINTREE(0x2de00000,0x00000000)}}, {VT_exponent,22,0x3a85b5,{DOUBLEWITHTWODWORDINTREE(0x2df00000,0x00000000)}}, {VT_exponent,22,0x3a85b6,{DOUBLEWITHTWODWORDINTREE(0x2e000000,0x00000000)}}, {VT_exponent,22,0x3a85b7,{DOUBLEWITHTWODWORDINTREE(0x2e100000,0x00000000)}}, {VT_exponent,22,0x3a85b8,{DOUBLEWITHTWODWORDINTREE(0x2e200000,0x00000000)}}, {VT_exponent,22,0x3a85b9,{DOUBLEWITHTWODWORDINTREE(0x2e300000,0x00000000)}}, {VT_exponent,22,0x3a85ba,{DOUBLEWITHTWODWORDINTREE(0x2e400000,0x00000000)}}, {VT_exponent,22,0x3a85bb,{DOUBLEWITHTWODWORDINTREE(0x2e500000,0x00000000)}}, {VT_exponent,22,0x3a85bc,{DOUBLEWITHTWODWORDINTREE(0x2e600000,0x00000000)}}, {VT_exponent,22,0x3a85bd,{DOUBLEWITHTWODWORDINTREE(0x2e700000,0x00000000)}}, {VT_exponent,22,0x3a85be,{DOUBLEWITHTWODWORDINTREE(0x2e800000,0x00000000)}}, {VT_exponent,22,0x3a85bf,{DOUBLEWITHTWODWORDINTREE(0x2e900000,0x00000000)}}, {VT_exponent,22,0x3a85c0,{DOUBLEWITHTWODWORDINTREE(0x2ea00000,0x00000000)}}, {VT_exponent,22,0x3a85c1,{DOUBLEWITHTWODWORDINTREE(0x2eb00000,0x00000000)}}, {VT_exponent,22,0x3a85c2,{DOUBLEWITHTWODWORDINTREE(0x2ec00000,0x00000000)}}, {VT_exponent,22,0x3a85c3,{DOUBLEWITHTWODWORDINTREE(0x2ed00000,0x00000000)}}, {VT_exponent,22,0x3a85c4,{DOUBLEWITHTWODWORDINTREE(0x2ee00000,0x00000000)}}, {VT_exponent,22,0x3a85c5,{DOUBLEWITHTWODWORDINTREE(0x2ef00000,0x00000000)}}, {VT_exponent,22,0x3a85c6,{DOUBLEWITHTWODWORDINTREE(0x2f000000,0x00000000)}}, {VT_exponent,22,0x3a85c7,{DOUBLEWITHTWODWORDINTREE(0x2f100000,0x00000000)}}, {VT_exponent,22,0x3a85c8,{DOUBLEWITHTWODWORDINTREE(0x2f200000,0x00000000)}}, {VT_exponent,22,0x3a85c9,{DOUBLEWITHTWODWORDINTREE(0x2f300000,0x00000000)}}, {VT_exponent,22,0x3a85ca,{DOUBLEWITHTWODWORDINTREE(0x2f400000,0x00000000)}}, {VT_exponent,22,0x3a85cb,{DOUBLEWITHTWODWORDINTREE(0x2f500000,0x00000000)}}, {VT_exponent,22,0x3a85cc,{DOUBLEWITHTWODWORDINTREE(0x2f600000,0x00000000)}}, {VT_exponent,22,0x3a85cd,{DOUBLEWITHTWODWORDINTREE(0x2f700000,0x00000000)}}, {VT_exponent,22,0x3a85ce,{DOUBLEWITHTWODWORDINTREE(0x2f800000,0x00000000)}}, {VT_exponent,22,0x3a85cf,{DOUBLEWITHTWODWORDINTREE(0x2f900000,0x00000000)}}, {VT_exponent,22,0x3a85d0,{DOUBLEWITHTWODWORDINTREE(0x2fa00000,0x00000000)}}, {VT_exponent,22,0x3a85d1,{DOUBLEWITHTWODWORDINTREE(0x2fb00000,0x00000000)}}, {VT_exponent,22,0x3a85d2,{DOUBLEWITHTWODWORDINTREE(0x2fc00000,0x00000000)}}, {VT_exponent,22,0x3a85d3,{DOUBLEWITHTWODWORDINTREE(0x2fd00000,0x00000000)}}, {VT_exponent,22,0x3a85d4,{DOUBLEWITHTWODWORDINTREE(0x2fe00000,0x00000000)}}, {VT_exponent,22,0x3a85d5,{DOUBLEWITHTWODWORDINTREE(0x2ff00000,0x00000000)}}, {VT_exponent,22,0x3a85d6,{DOUBLEWITHTWODWORDINTREE(0x30000000,0x00000000)}}, {VT_exponent,22,0x3a85d7,{DOUBLEWITHTWODWORDINTREE(0x30100000,0x00000000)}}, {VT_exponent,22,0x3a85d8,{DOUBLEWITHTWODWORDINTREE(0x30200000,0x00000000)}}, {VT_exponent,22,0x3a85d9,{DOUBLEWITHTWODWORDINTREE(0x30300000,0x00000000)}}, {VT_exponent,22,0x3a85da,{DOUBLEWITHTWODWORDINTREE(0x30400000,0x00000000)}}, {VT_exponent,22,0x3a85db,{DOUBLEWITHTWODWORDINTREE(0x30500000,0x00000000)}}, {VT_exponent,22,0x3a85dc,{DOUBLEWITHTWODWORDINTREE(0x30600000,0x00000000)}}, {VT_exponent,22,0x3a85dd,{DOUBLEWITHTWODWORDINTREE(0x30700000,0x00000000)}}, {VT_exponent,22,0x3a85de,{DOUBLEWITHTWODWORDINTREE(0x30800000,0x00000000)}}, {VT_exponent,22,0x3a85df,{DOUBLEWITHTWODWORDINTREE(0x30900000,0x00000000)}}, {VT_exponent,22,0x3a85e0,{DOUBLEWITHTWODWORDINTREE(0x30a00000,0x00000000)}}, {VT_exponent,22,0x3a85e1,{DOUBLEWITHTWODWORDINTREE(0x30b00000,0x00000000)}}, {VT_exponent,22,0x3a85e2,{DOUBLEWITHTWODWORDINTREE(0x30c00000,0x00000000)}}, {VT_exponent,22,0x3a85e3,{DOUBLEWITHTWODWORDINTREE(0x30d00000,0x00000000)}}, {VT_exponent,22,0x3a85e4,{DOUBLEWITHTWODWORDINTREE(0x30e00000,0x00000000)}}, {VT_exponent,22,0x3a85e5,{DOUBLEWITHTWODWORDINTREE(0x30f00000,0x00000000)}}, {VT_exponent,22,0x3a85e6,{DOUBLEWITHTWODWORDINTREE(0x31000000,0x00000000)}}, {VT_exponent,22,0x3a85e7,{DOUBLEWITHTWODWORDINTREE(0x31100000,0x00000000)}}, {VT_exponent,22,0x3a85e8,{DOUBLEWITHTWODWORDINTREE(0x31200000,0x00000000)}}, {VT_exponent,22,0x3a85e9,{DOUBLEWITHTWODWORDINTREE(0x31300000,0x00000000)}}, {VT_exponent,22,0x3a85ea,{DOUBLEWITHTWODWORDINTREE(0x31400000,0x00000000)}}, {VT_exponent,22,0x3a85eb,{DOUBLEWITHTWODWORDINTREE(0x31500000,0x00000000)}}, {VT_exponent,22,0x3a85ec,{DOUBLEWITHTWODWORDINTREE(0x31600000,0x00000000)}}, {VT_exponent,22,0x3a85ed,{DOUBLEWITHTWODWORDINTREE(0x31700000,0x00000000)}}, {VT_exponent,22,0x3a85ee,{DOUBLEWITHTWODWORDINTREE(0x31800000,0x00000000)}}, {VT_exponent,22,0x3a85ef,{DOUBLEWITHTWODWORDINTREE(0x31900000,0x00000000)}}, {VT_exponent,22,0x3a85f0,{DOUBLEWITHTWODWORDINTREE(0x31a00000,0x00000000)}}, {VT_exponent,22,0x3a85f1,{DOUBLEWITHTWODWORDINTREE(0x31b00000,0x00000000)}}, {VT_exponent,22,0x3a85f2,{DOUBLEWITHTWODWORDINTREE(0x31c00000,0x00000000)}}, {VT_exponent,22,0x3a85f3,{DOUBLEWITHTWODWORDINTREE(0x31d00000,0x00000000)}}, {VT_exponent,22,0x3a85f4,{DOUBLEWITHTWODWORDINTREE(0x31e00000,0x00000000)}}, {VT_exponent,22,0x3a85f5,{DOUBLEWITHTWODWORDINTREE(0x31f00000,0x00000000)}}, {VT_exponent,22,0x3a85f6,{DOUBLEWITHTWODWORDINTREE(0x32000000,0x00000000)}}, {VT_exponent,22,0x3a85f7,{DOUBLEWITHTWODWORDINTREE(0x32100000,0x00000000)}}, {VT_exponent,22,0x3a85f8,{DOUBLEWITHTWODWORDINTREE(0x32200000,0x00000000)}}, {VT_exponent,22,0x3a85f9,{DOUBLEWITHTWODWORDINTREE(0x32300000,0x00000000)}}, {VT_exponent,22,0x3a85fa,{DOUBLEWITHTWODWORDINTREE(0x32400000,0x00000000)}}, {VT_exponent,22,0x3a85fb,{DOUBLEWITHTWODWORDINTREE(0x32500000,0x00000000)}}, {VT_exponent,22,0x3a85fc,{DOUBLEWITHTWODWORDINTREE(0x32600000,0x00000000)}}, {VT_exponent,22,0x3a85fd,{DOUBLEWITHTWODWORDINTREE(0x32700000,0x00000000)}}, {VT_exponent,22,0x3a85fe,{DOUBLEWITHTWODWORDINTREE(0x32800000,0x00000000)}}, {VT_exponent,22,0x3a85ff,{DOUBLEWITHTWODWORDINTREE(0x32900000,0x00000000)}}, {VT_exponent,22,0x3a8600,{DOUBLEWITHTWODWORDINTREE(0x32a00000,0x00000000)}}, {VT_exponent,22,0x3a8601,{DOUBLEWITHTWODWORDINTREE(0x32b00000,0x00000000)}}, {VT_exponent,22,0x3a8602,{DOUBLEWITHTWODWORDINTREE(0x32c00000,0x00000000)}}, {VT_exponent,22,0x3a8603,{DOUBLEWITHTWODWORDINTREE(0x32d00000,0x00000000)}}, {VT_exponent,22,0x3a8604,{DOUBLEWITHTWODWORDINTREE(0x32e00000,0x00000000)}}, {VT_exponent,22,0x3a8605,{DOUBLEWITHTWODWORDINTREE(0x32f00000,0x00000000)}}, {VT_exponent,22,0x3a8606,{DOUBLEWITHTWODWORDINTREE(0x33000000,0x00000000)}}, {VT_exponent,22,0x3a8607,{DOUBLEWITHTWODWORDINTREE(0x33100000,0x00000000)}}, {VT_exponent,22,0x3a8608,{DOUBLEWITHTWODWORDINTREE(0x33200000,0x00000000)}}, {VT_exponent,22,0x3a8609,{DOUBLEWITHTWODWORDINTREE(0x33300000,0x00000000)}}, {VT_exponent,22,0x3a860a,{DOUBLEWITHTWODWORDINTREE(0x33400000,0x00000000)}}, {VT_exponent,22,0x3a860b,{DOUBLEWITHTWODWORDINTREE(0x33500000,0x00000000)}}, {VT_exponent,22,0x3a860c,{DOUBLEWITHTWODWORDINTREE(0x33600000,0x00000000)}}, {VT_exponent,22,0x3a860d,{DOUBLEWITHTWODWORDINTREE(0x33700000,0x00000000)}}, {VT_exponent,22,0x3a860e,{DOUBLEWITHTWODWORDINTREE(0x33800000,0x00000000)}}, {VT_exponent,22,0x3a860f,{DOUBLEWITHTWODWORDINTREE(0x33900000,0x00000000)}}, {VT_exponent,22,0x3a8610,{DOUBLEWITHTWODWORDINTREE(0x33a00000,0x00000000)}}, {VT_exponent,22,0x3a8611,{DOUBLEWITHTWODWORDINTREE(0x33b00000,0x00000000)}}, {VT_exponent,22,0x3a8612,{DOUBLEWITHTWODWORDINTREE(0x33c00000,0x00000000)}}, {VT_exponent,22,0x3a8613,{DOUBLEWITHTWODWORDINTREE(0x33d00000,0x00000000)}}, {VT_exponent,22,0x3a8614,{DOUBLEWITHTWODWORDINTREE(0x33e00000,0x00000000)}}, {VT_exponent,22,0x3a8615,{DOUBLEWITHTWODWORDINTREE(0x33f00000,0x00000000)}}, {VT_exponent,22,0x3a8616,{DOUBLEWITHTWODWORDINTREE(0x34000000,0x00000000)}}, {VT_exponent,22,0x3a8617,{DOUBLEWITHTWODWORDINTREE(0x34100000,0x00000000)}}, {VT_exponent,22,0x3a8618,{DOUBLEWITHTWODWORDINTREE(0x34200000,0x00000000)}}, {VT_exponent,22,0x3a8619,{DOUBLEWITHTWODWORDINTREE(0x34300000,0x00000000)}}, {VT_exponent,22,0x3a861a,{DOUBLEWITHTWODWORDINTREE(0x34400000,0x00000000)}}, {VT_exponent,22,0x3a861b,{DOUBLEWITHTWODWORDINTREE(0x34500000,0x00000000)}}, {VT_exponent,22,0x3a861c,{DOUBLEWITHTWODWORDINTREE(0x34600000,0x00000000)}}, {VT_exponent,22,0x3a861d,{DOUBLEWITHTWODWORDINTREE(0x34700000,0x00000000)}}, {VT_exponent,22,0x3a861e,{DOUBLEWITHTWODWORDINTREE(0x34800000,0x00000000)}}, {VT_exponent,22,0x3a861f,{DOUBLEWITHTWODWORDINTREE(0x34900000,0x00000000)}}, {VT_exponent,22,0x3a8620,{DOUBLEWITHTWODWORDINTREE(0x34a00000,0x00000000)}}, {VT_exponent,22,0x3a8621,{DOUBLEWITHTWODWORDINTREE(0x34b00000,0x00000000)}}, {VT_exponent,22,0x3a8622,{DOUBLEWITHTWODWORDINTREE(0x34c00000,0x00000000)}}, {VT_exponent,22,0x3a8623,{DOUBLEWITHTWODWORDINTREE(0x34d00000,0x00000000)}}, {VT_exponent,22,0x3a8624,{DOUBLEWITHTWODWORDINTREE(0x34e00000,0x00000000)}}, {VT_exponent,22,0x3a8625,{DOUBLEWITHTWODWORDINTREE(0x34f00000,0x00000000)}}, {VT_exponent,22,0x3a8626,{DOUBLEWITHTWODWORDINTREE(0x35000000,0x00000000)}}, {VT_exponent,22,0x3a8627,{DOUBLEWITHTWODWORDINTREE(0x35100000,0x00000000)}}, {VT_exponent,22,0x3a8628,{DOUBLEWITHTWODWORDINTREE(0x35200000,0x00000000)}}, {VT_exponent,22,0x3a8629,{DOUBLEWITHTWODWORDINTREE(0x35300000,0x00000000)}}, {VT_exponent,18,0xf787,{DOUBLEWITHTWODWORDINTREE(0x35400000,0x00000000)}}, {VT_exponent,18,0xd1d4,{DOUBLEWITHTWODWORDINTREE(0x35500000,0x00000000)}}, {VT_exponent,19,0x77f9f,{DOUBLEWITHTWODWORDINTREE(0x35600000,0x00000000)}}, {VT_exponent,18,0x3b8fb,{DOUBLEWITHTWODWORDINTREE(0x35700000,0x00000000)}}, {VT_exponent,19,0x1ef1a,{DOUBLEWITHTWODWORDINTREE(0x35800000,0x00000000)}}, {VT_exponent,21,0x1d4315,{DOUBLEWITHTWODWORDINTREE(0x35900000,0x00000000)}}, {VT_exponent,16,0x3de2,{DOUBLEWITHTWODWORDINTREE(0x35a00000,0x00000000)}}, {VT_exponent,22,0x3a862c,{DOUBLEWITHTWODWORDINTREE(0x35b00000,0x00000000)}}, {VT_exponent,22,0x3a862d,{DOUBLEWITHTWODWORDINTREE(0x35c00000,0x00000000)}}, {VT_exponent,22,0x3a862e,{DOUBLEWITHTWODWORDINTREE(0x35d00000,0x00000000)}}, {VT_exponent,22,0x3a862f,{DOUBLEWITHTWODWORDINTREE(0x35e00000,0x00000000)}}, {VT_exponent,22,0x3a8630,{DOUBLEWITHTWODWORDINTREE(0x35f00000,0x00000000)}}, {VT_exponent,22,0x3a8631,{DOUBLEWITHTWODWORDINTREE(0x36000000,0x00000000)}}, {VT_exponent,22,0x3a8632,{DOUBLEWITHTWODWORDINTREE(0x36100000,0x00000000)}}, {VT_exponent,22,0x3a8633,{DOUBLEWITHTWODWORDINTREE(0x36200000,0x00000000)}}, {VT_exponent,22,0x3a8634,{DOUBLEWITHTWODWORDINTREE(0x36300000,0x00000000)}}, {VT_exponent,22,0x3a8635,{DOUBLEWITHTWODWORDINTREE(0x36400000,0x00000000)}}, {VT_exponent,22,0x3a8636,{DOUBLEWITHTWODWORDINTREE(0x36500000,0x00000000)}}, {VT_exponent,22,0x3a8637,{DOUBLEWITHTWODWORDINTREE(0x36600000,0x00000000)}}, {VT_exponent,22,0x3a8638,{DOUBLEWITHTWODWORDINTREE(0x36700000,0x00000000)}}, {VT_exponent,21,0x1d431d,{DOUBLEWITHTWODWORDINTREE(0x36800000,0x00000000)}}, {VT_exponent,22,0x3a8639,{DOUBLEWITHTWODWORDINTREE(0x36900000,0x00000000)}}, {VT_exponent,22,0x3a863c,{DOUBLEWITHTWODWORDINTREE(0x36a00000,0x00000000)}}, {VT_exponent,16,0x3de0,{DOUBLEWITHTWODWORDINTREE(0x36b00000,0x00000000)}}, {VT_exponent,18,0x3a95e,{DOUBLEWITHTWODWORDINTREE(0x36c00000,0x00000000)}}, {VT_exponent,21,0x1d431f,{DOUBLEWITHTWODWORDINTREE(0x36d00000,0x00000000)}}, {VT_exponent,22,0x3a863d,{DOUBLEWITHTWODWORDINTREE(0x36e00000,0x00000000)}}, {VT_exponent,22,0x3a8640,{DOUBLEWITHTWODWORDINTREE(0x36f00000,0x00000000)}}, {VT_exponent,20,0x34749,{DOUBLEWITHTWODWORDINTREE(0x37000000,0x00000000)}}, {VT_exponent,20,0x3474d,{DOUBLEWITHTWODWORDINTREE(0x37100000,0x00000000)}}, {VT_exponent,22,0x3a8641,{DOUBLEWITHTWODWORDINTREE(0x37200000,0x00000000)}}, {VT_exponent,22,0x3a8642,{DOUBLEWITHTWODWORDINTREE(0x37300000,0x00000000)}}, {VT_exponent,22,0x3a8643,{DOUBLEWITHTWODWORDINTREE(0x37400000,0x00000000)}}, {VT_exponent,22,0x3a8644,{DOUBLEWITHTWODWORDINTREE(0x37500000,0x00000000)}}, {VT_exponent,22,0x3a8645,{DOUBLEWITHTWODWORDINTREE(0x37600000,0x00000000)}}, {VT_exponent,22,0x3a8646,{DOUBLEWITHTWODWORDINTREE(0x37700000,0x00000000)}}, {VT_exponent,22,0x3a8647,{DOUBLEWITHTWODWORDINTREE(0x37800000,0x00000000)}}, {VT_exponent,22,0x3a8648,{DOUBLEWITHTWODWORDINTREE(0x37900000,0x00000000)}}, {VT_exponent,22,0x3a8649,{DOUBLEWITHTWODWORDINTREE(0x37a00000,0x00000000)}}, {VT_exponent,22,0x3a864a,{DOUBLEWITHTWODWORDINTREE(0x37b00000,0x00000000)}}, {VT_exponent,22,0x3a864b,{DOUBLEWITHTWODWORDINTREE(0x37c00000,0x00000000)}}, {VT_exponent,22,0x3a864c,{DOUBLEWITHTWODWORDINTREE(0x37d00000,0x00000000)}}, {VT_exponent,22,0x3a864d,{DOUBLEWITHTWODWORDINTREE(0x37e00000,0x00000000)}}, {VT_exponent,22,0x3a864e,{DOUBLEWITHTWODWORDINTREE(0x37f00000,0x00000000)}}, {VT_exponent,22,0x3a864f,{DOUBLEWITHTWODWORDINTREE(0x38000000,0x00000000)}}, {VT_exponent,22,0x3a8650,{DOUBLEWITHTWODWORDINTREE(0x38100000,0x00000000)}}, {VT_exponent,22,0x3a8651,{DOUBLEWITHTWODWORDINTREE(0x38200000,0x00000000)}}, {VT_exponent,22,0x3a8652,{DOUBLEWITHTWODWORDINTREE(0x38300000,0x00000000)}}, {VT_exponent,22,0x3a8653,{DOUBLEWITHTWODWORDINTREE(0x38400000,0x00000000)}}, {VT_exponent,22,0x3a8654,{DOUBLEWITHTWODWORDINTREE(0x38500000,0x00000000)}}, {VT_exponent,22,0x3a8655,{DOUBLEWITHTWODWORDINTREE(0x38600000,0x00000000)}}, {VT_exponent,22,0x3a8656,{DOUBLEWITHTWODWORDINTREE(0x38700000,0x00000000)}}, {VT_exponent,22,0x3a8657,{DOUBLEWITHTWODWORDINTREE(0x38800000,0x00000000)}}, {VT_exponent,22,0x3a8658,{DOUBLEWITHTWODWORDINTREE(0x38900000,0x00000000)}}, {VT_exponent,22,0x3a8659,{DOUBLEWITHTWODWORDINTREE(0x38a00000,0x00000000)}}, {VT_exponent,22,0x3a865a,{DOUBLEWITHTWODWORDINTREE(0x38b00000,0x00000000)}}, {VT_exponent,22,0x3a865b,{DOUBLEWITHTWODWORDINTREE(0x38c00000,0x00000000)}}, {VT_exponent,22,0x3a865c,{DOUBLEWITHTWODWORDINTREE(0x38d00000,0x00000000)}}, {VT_exponent,22,0x3a865d,{DOUBLEWITHTWODWORDINTREE(0x38e00000,0x00000000)}}, {VT_exponent,21,0x1d432f,{DOUBLEWITHTWODWORDINTREE(0x38f00000,0x00000000)}}, {VT_exponent,22,0x3a8660,{DOUBLEWITHTWODWORDINTREE(0x39000000,0x00000000)}}, {VT_exponent,22,0x3a8661,{DOUBLEWITHTWODWORDINTREE(0x39100000,0x00000000)}}, {VT_exponent,22,0x3a8662,{DOUBLEWITHTWODWORDINTREE(0x39200000,0x00000000)}}, {VT_exponent,21,0x1d4332,{DOUBLEWITHTWODWORDINTREE(0x39300000,0x00000000)}}, {VT_exponent,18,0xd1d5,{DOUBLEWITHTWODWORDINTREE(0x39400000,0x00000000)}}, {VT_exponent,18,0x3bfda,{DOUBLEWITHTWODWORDINTREE(0x39500000,0x00000000)}}, {VT_exponent,15,0x7528,{DOUBLEWITHTWODWORDINTREE(0x39600000,0x00000000)}}, {VT_exponent,15,0x7529,{DOUBLEWITHTWODWORDINTREE(0x39700000,0x00000000)}}, {VT_exponent,18,0x3a95f,{DOUBLEWITHTWODWORDINTREE(0x39800000,0x00000000)}}, {VT_exponent,17,0x1d434,{DOUBLEWITHTWODWORDINTREE(0x39900000,0x00000000)}}, {VT_exponent,19,0x750cd,{DOUBLEWITHTWODWORDINTREE(0x39a00000,0x00000000)}}, {VT_exponent,18,0x3a867,{DOUBLEWITHTWODWORDINTREE(0x39b00000,0x00000000)}}, {VT_exponent,19,0x771fd,{DOUBLEWITHTWODWORDINTREE(0x39c00000,0x00000000)}}, {VT_exponent,15,0x7764,{DOUBLEWITHTWODWORDINTREE(0x39d00000,0x00000000)}}, {VT_exponent,20,0xee3f9,{DOUBLEWITHTWODWORDINTREE(0x39e00000,0x00000000)}}, {VT_exponent,18,0x3bfdb,{DOUBLEWITHTWODWORDINTREE(0x39f00000,0x00000000)}}, {VT_exponent,16,0xeff7,{DOUBLEWITHTWODWORDINTREE(0x3a000000,0x00000000)}}, {VT_exponent,18,0xd1d6,{DOUBLEWITHTWODWORDINTREE(0x3a100000,0x00000000)}}, {VT_exponent,22,0x3a8663,{DOUBLEWITHTWODWORDINTREE(0x3a200000,0x00000000)}}, {VT_exponent,22,0x3a8666,{DOUBLEWITHTWODWORDINTREE(0x3a300000,0x00000000)}}, {VT_exponent,18,0x3b8fa,{DOUBLEWITHTWODWORDINTREE(0x3a400000,0x00000000)}}, {VT_exponent,17,0x1d435,{DOUBLEWITHTWODWORDINTREE(0x3a500000,0x00000000)}}, {VT_exponent,17,0x1dfe4,{DOUBLEWITHTWODWORDINTREE(0x3a600000,0x00000000)}}, {VT_exponent,19,0x750d8,{DOUBLEWITHTWODWORDINTREE(0x3a700000,0x00000000)}}, {VT_exponent,18,0x3a95b,{DOUBLEWITHTWODWORDINTREE(0x3a800000,0x00000000)}}, {VT_exponent,19,0x77f9e,{DOUBLEWITHTWODWORDINTREE(0x3a900000,0x00000000)}}, {VT_exponent,19,0x750d9,{DOUBLEWITHTWODWORDINTREE(0x3aa00000,0x00000000)}}, {VT_exponent,18,0xd1d7,{DOUBLEWITHTWODWORDINTREE(0x3ab00000,0x00000000)}}, {VT_exponent,18,0x3b8ff,{DOUBLEWITHTWODWORDINTREE(0x3ac00000,0x00000000)}}, {VT_exponent,17,0x1dc7c,{DOUBLEWITHTWODWORDINTREE(0x3ad00000,0x00000000)}}, {VT_exponent,19,0x750da,{DOUBLEWITHTWODWORDINTREE(0x3ae00000,0x00000000)}}, {VT_exponent,17,0x7bc2,{DOUBLEWITHTWODWORDINTREE(0x3af00000,0x00000000)}}, {VT_exponent,18,0x3bfca,{DOUBLEWITHTWODWORDINTREE(0x3b000000,0x00000000)}}, {VT_exponent,19,0x1a3a5,{DOUBLEWITHTWODWORDINTREE(0x3b100000,0x00000000)}}, {VT_exponent,17,0x1d4ac,{DOUBLEWITHTWODWORDINTREE(0x3b200000,0x00000000)}}, {VT_exponent,18,0x3a86e,{DOUBLEWITHTWODWORDINTREE(0x3b300000,0x00000000)}}, {VT_exponent,17,0x1d438,{DOUBLEWITHTWODWORDINTREE(0x3b400000,0x00000000)}}, {VT_exponent,18,0x3bfcb,{DOUBLEWITHTWODWORDINTREE(0x3b500000,0x00000000)}}, {VT_exponent,19,0x1a3a7,{DOUBLEWITHTWODWORDINTREE(0x3b600000,0x00000000)}}, {VT_exponent,17,0x1d4ae,{DOUBLEWITHTWODWORDINTREE(0x3b700000,0x00000000)}}, {VT_exponent,18,0x3bfce,{DOUBLEWITHTWODWORDINTREE(0x3b800000,0x00000000)}}, {VT_exponent,18,0xf78c,{DOUBLEWITHTWODWORDINTREE(0x3b900000,0x00000000)}}, {VT_exponent,17,0x1dfec,{DOUBLEWITHTWODWORDINTREE(0x3ba00000,0x00000000)}}, {VT_exponent,17,0x1d439,{DOUBLEWITHTWODWORDINTREE(0x3bb00000,0x00000000)}}, {VT_exponent,17,0x68e8,{DOUBLEWITHTWODWORDINTREE(0x3bc00000,0x00000000)}}, {VT_exponent,18,0xf786,{DOUBLEWITHTWODWORDINTREE(0x3bd00000,0x00000000)}}, {VT_exponent,15,0x771e,{DOUBLEWITHTWODWORDINTREE(0x3be00000,0x00000000)}}, {VT_exponent,17,0x1dfe6,{DOUBLEWITHTWODWORDINTREE(0x3bf00000,0x00000000)}}, {VT_exponent,15,0x77f8,{DOUBLEWITHTWODWORDINTREE(0x3c000000,0x00000000)}}, {VT_exponent,14,0x3bb3,{DOUBLEWITHTWODWORDINTREE(0x3c100000,0x00000000)}}, {VT_exponent,14,0x3b8e,{DOUBLEWITHTWODWORDINTREE(0x3c200000,0x00000000)}}, {VT_exponent,14,0x3a82,{DOUBLEWITHTWODWORDINTREE(0x3c300000,0x00000000)}}, {VT_exponent,14,0x3b96,{DOUBLEWITHTWODWORDINTREE(0x3c400000,0x00000000)}}, {VT_exponent,13,0x68f,{DOUBLEWITHTWODWORDINTREE(0x3c500000,0x00000000)}}, {VT_exponent,12,0x3d4,{DOUBLEWITHTWODWORDINTREE(0x3c600000,0x00000000)}}, {VT_exponent,13,0x1dca,{DOUBLEWITHTWODWORDINTREE(0x3c700000,0x00000000)}}, {VT_exponent,12,0x346,{DOUBLEWITHTWODWORDINTREE(0x3c800000,0x00000000)}}, {VT_exponent,12,0xee7,{DOUBLEWITHTWODWORDINTREE(0x3c900000,0x00000000)}}, {VT_exponent,12,0xeea,{DOUBLEWITHTWODWORDINTREE(0x3ca00000,0x00000000)}}, {VT_exponent,11,0x1ed,{DOUBLEWITHTWODWORDINTREE(0x3cb00000,0x00000000)}}, {VT_exponent,12,0x3df,{DOUBLEWITHTWODWORDINTREE(0x3cc00000,0x00000000)}}, {VT_exponent,11,0x1a2,{DOUBLEWITHTWODWORDINTREE(0x3cd00000,0x00000000)}}, {VT_exponent,11,0x56f,{DOUBLEWITHTWODWORDINTREE(0x3ce00000,0x00000000)}}, {VT_exponent,11,0xb9,{DOUBLEWITHTWODWORDINTREE(0x3cf00000,0x00000000)}}, {VT_exponent,13,0x7b2,{DOUBLEWITHTWODWORDINTREE(0x3d000000,0x00000000)}}, {VT_exponent,13,0x1dd8,{DOUBLEWITHTWODWORDINTREE(0x3d100000,0x00000000)}}, {VT_exponent,13,0x15ba,{DOUBLEWITHTWODWORDINTREE(0x3d200000,0x00000000)}}, {VT_exponent,12,0xee6,{DOUBLEWITHTWODWORDINTREE(0x3d300000,0x00000000)}}, {VT_exponent,13,0x15b8,{DOUBLEWITHTWODWORDINTREE(0x3d400000,0x00000000)}}, {VT_exponent,14,0xf79,{DOUBLEWITHTWODWORDINTREE(0x3d500000,0x00000000)}}, {VT_exponent,14,0x3a81,{DOUBLEWITHTWODWORDINTREE(0x3d600000,0x00000000)}}, {VT_exponent,14,0xd1c,{DOUBLEWITHTWODWORDINTREE(0x3d700000,0x00000000)}}, {VT_exponent,15,0x7765,{DOUBLEWITHTWODWORDINTREE(0x3d800000,0x00000000)}}, {VT_exponent,14,0xf54,{DOUBLEWITHTWODWORDINTREE(0x3d900000,0x00000000)}}, {VT_exponent,13,0x15b9,{DOUBLEWITHTWODWORDINTREE(0x3da00000,0x00000000)}}, {VT_exponent,13,0x7ab,{DOUBLEWITHTWODWORDINTREE(0x3db00000,0x00000000)}}, {VT_exponent,15,0x7500,{DOUBLEWITHTWODWORDINTREE(0x3dc00000,0x00000000)}}, {VT_exponent,15,0x1eaa,{DOUBLEWITHTWODWORDINTREE(0x3dd00000,0x00000000)}}, {VT_exponent,15,0x7501,{DOUBLEWITHTWODWORDINTREE(0x3de00000,0x00000000)}}, {VT_exponent,15,0x1eab,{DOUBLEWITHTWODWORDINTREE(0x3df00000,0x00000000)}}, {VT_exponent,14,0x3b97,{DOUBLEWITHTWODWORDINTREE(0x3e000000,0x00000000)}}, {VT_exponent,15,0x752a,{DOUBLEWITHTWODWORDINTREE(0x3e100000,0x00000000)}}, {VT_exponent,15,0x77fa,{DOUBLEWITHTWODWORDINTREE(0x3e200000,0x00000000)}}, {VT_double,10,0xf4,{DOUBLEWITHTWODWORDINTREE(0x3e35798e,0xe2308c3a)}}, {VT_exponent,14,0x3a93,{DOUBLEWITHTWODWORDINTREE(0x3e300000,0x00000000)}}, {VT_double,11,0x77c,{DOUBLEWITHTWODWORDINTREE(0x3e45798e,0xe2308c3a)}}, {VT_exponent,13,0x1dc6,{DOUBLEWITHTWODWORDINTREE(0x3e400000,0x00000000)}}, {VT_exponent,13,0x7bd,{DOUBLEWITHTWODWORDINTREE(0x3e500000,0x00000000)}}, {VT_exponent,13,0x1dff,{DOUBLEWITHTWODWORDINTREE(0x3e600000,0x00000000)}}, {VT_exponent,12,0xefe,{DOUBLEWITHTWODWORDINTREE(0x3e700000,0x00000000)}}, {VT_double,8,0xaf,{DOUBLEWITHTWODWORDINTREE(0x3e8ad7f2,0x9abcaf4a)}}, {VT_exponent,12,0xeed,{DOUBLEWITHTWODWORDINTREE(0x3e800000,0x00000000)}}, {VT_exponent,11,0xb8,{DOUBLEWITHTWODWORDINTREE(0x3e900000,0x00000000)}}, {VT_exponent,12,0x3d8,{DOUBLEWITHTWODWORDINTREE(0x3ea00000,0x00000000)}}, {VT_exponent,11,0x1eb,{DOUBLEWITHTWODWORDINTREE(0x3eb00000,0x00000000)}}, {VT_double,9,0x1d2,{DOUBLEWITHTWODWORDINTREE(0x3ec0c6f7,0xa0b5ed8e)}}, {VT_exponent,13,0x1d4b,{DOUBLEWITHTWODWORDINTREE(0x3ec00000,0x00000000)}}, {VT_exponent,13,0x7b3,{DOUBLEWITHTWODWORDINTREE(0x3ed00000,0x00000000)}}, {VT_exponent,10,0x5d,{DOUBLEWITHTWODWORDINTREE(0x3ee00000,0x00000000)}}, {VT_exponent,12,0xeeb,{DOUBLEWITHTWODWORDINTREE(0x3ef00000,0x00000000)}}, {VT_exponent,11,0x1ee,{DOUBLEWITHTWODWORDINTREE(0x3f000000,0x00000000)}}, {VT_exponent,10,0x5f,{DOUBLEWITHTWODWORDINTREE(0x3f100000,0x00000000)}}, {VT_exponent,10,0x2b6,{DOUBLEWITHTWODWORDINTREE(0x3f200000,0x00000000)}}, {VT_exponent,9,0x1de,{DOUBLEWITHTWODWORDINTREE(0x3f300000,0x00000000)}}, {VT_double,10,0xd0,{DOUBLEWITHTWODWORDINTREE(0x3f454c98,0x5f06f694)}}, {VT_double,6,0x9,{DOUBLEWITHTWODWORDINTREE(0x3f4a36e2,0xeb1c432d)}}, {VT_exponent,8,0xe8,{DOUBLEWITHTWODWORDINTREE(0x3f400000,0x00000000)}}, {VT_double,4,0xf,{DOUBLEWITHTWODWORDINTREE(0x3f50624d,0xd2f1a9fc)}}, {VT_exponent,8,0xae,{DOUBLEWITHTWODWORDINTREE(0x3f500000,0x00000000)}}, {VT_double,5,0x16,{DOUBLEWITHTWODWORDINTREE(0x3f60624d,0xd2f1a9fc)}}, {VT_exponent,7,0x1b,{DOUBLEWITHTWODWORDINTREE(0x3f600000,0x00000000)}}, {VT_exponent,7,0x76,{DOUBLEWITHTWODWORDINTREE(0x3f700000,0x00000000)}}, {VT_exponent,7,0xa,{DOUBLEWITHTWODWORDINTREE(0x3f800000,0x00000000)}}, {VT_exponent,6,0x8,{DOUBLEWITHTWODWORDINTREE(0x3f900000,0x00000000)}}, {VT_exponent,6,0xe,{DOUBLEWITHTWODWORDINTREE(0x3fa00000,0x00000000)}}, {VT_double,11,0x751,{DOUBLEWITHTWODWORDINTREE(0x3fbe69ad,0x42c3c9ee)}}, {VT_exponent,6,0x4,{DOUBLEWITHTWODWORDINTREE(0x3fb00000,0x00000000)}}, {VT_exponent,6,0xc,{DOUBLEWITHTWODWORDINTREE(0x3fc00000,0x00000000)}}, {VT_exponent,5,0x3,{DOUBLEWITHTWODWORDINTREE(0x3fd00000,0x00000000)}}, {VT_double,11,0x777,{DOUBLEWITHTWODWORDINTREE(0x3fe00000,0x00000000)}}, {VT_double,9,0x1d6,{DOUBLEWITHTWODWORDINTREE(0x3fefffff,0xf8000002)}}, {VT_exponent,4,0x8,{DOUBLEWITHTWODWORDINTREE(0x3fe00000,0x00000000)}}, {VT_double,4,0x0,{DOUBLEWITHTWODWORDINTREE(0x3ff00000,0x00000000)}}, {VT_exponent,5,0x13,{DOUBLEWITHTWODWORDINTREE(0x3ff00000,0x00000000)}}, {VT_exponent,5,0x1b,{DOUBLEWITHTWODWORDINTREE(0x40000000,0x00000000)}}, {VT_double,9,0x15a,{DOUBLEWITHTWODWORDINTREE(0x401921fb,0x54442d18)}}, {VT_exponent,5,0x17,{DOUBLEWITHTWODWORDINTREE(0x40100000,0x00000000)}}, {VT_exponent,5,0x12,{DOUBLEWITHTWODWORDINTREE(0x40200000,0x00000000)}}, {VT_double,11,0x774,{DOUBLEWITHTWODWORDINTREE(0x4035ee14,0x80000000)}}, {VT_exponent,5,0x19,{DOUBLEWITHTWODWORDINTREE(0x40300000,0x00000000)}}, {VT_double,9,0x1d3,{DOUBLEWITHTWODWORDINTREE(0x404ca5dc,0x1a63c1f8)}}, {VT_exponent,5,0x1a,{DOUBLEWITHTWODWORDINTREE(0x40400000,0x00000000)}}, {VT_double,11,0x77e,{DOUBLEWITHTWODWORDINTREE(0x405bb32f,0xe0000000)}}, {VT_double,10,0x5e,{DOUBLEWITHTWODWORDINTREE(0x405c332f,0xe0000000)}}, {VT_exponent,5,0x18,{DOUBLEWITHTWODWORDINTREE(0x40500000,0x00000000)}}, {VT_double,9,0x1d7,{DOUBLEWITHTWODWORDINTREE(0x40668000,0x00000000)}}, {VT_exponent,5,0x1c,{DOUBLEWITHTWODWORDINTREE(0x40600000,0x00000000)}}, {VT_double,9,0x1d5,{DOUBLEWITHTWODWORDINTREE(0x40768000,0x00000000)}}, {VT_exponent,5,0x14,{DOUBLEWITHTWODWORDINTREE(0x40700000,0x00000000)}}, {VT_double,11,0x77d,{DOUBLEWITHTWODWORDINTREE(0x408f4000,0x00000000)}}, {VT_exponent,5,0x5,{DOUBLEWITHTWODWORDINTREE(0x40800000,0x00000000)}}, {VT_double,10,0xd2,{DOUBLEWITHTWODWORDINTREE(0x409233ff,0xffffffff)}}, {VT_double,8,0x3c,{DOUBLEWITHTWODWORDINTREE(0x40923400,0x00000000)}}, {VT_double,11,0x753,{DOUBLEWITHTWODWORDINTREE(0x40923400,0x00000001)}}, {VT_double,10,0xd3,{DOUBLEWITHTWODWORDINTREE(0x4092abff,0xffffffff)}}, {VT_double,8,0x35,{DOUBLEWITHTWODWORDINTREE(0x4092ac00,0x00000000)}}, {VT_double,11,0x770,{DOUBLEWITHTWODWORDINTREE(0x4092ac00,0x00000001)}}, {VT_exponent,8,0x16,{DOUBLEWITHTWODWORDINTREE(0x40900000,0x00000000)}}, {VT_exponent,12,0xee2,{DOUBLEWITHTWODWORDINTREE(0x40a00000,0x00000000)}}, {VT_exponent,12,0xee4,{DOUBLEWITHTWODWORDINTREE(0x40b00000,0x00000000)}}, {VT_double,7,0x1f,{DOUBLEWITHTWODWORDINTREE(0x40c81c80,0x00000000)}}, {VT_exponent,8,0xac,{DOUBLEWITHTWODWORDINTREE(0x40c00000,0x00000000)}}, {VT_exponent,13,0x15bb,{DOUBLEWITHTWODWORDINTREE(0x40d00000,0x00000000)}}, {VT_exponent,22,0x3a8667,{DOUBLEWITHTWODWORDINTREE(0x40e00000,0x00000000)}}, {VT_exponent,22,0x3a86d8,{DOUBLEWITHTWODWORDINTREE(0x40f00000,0x00000000)}}, {VT_exponent,22,0x3a86d9,{DOUBLEWITHTWODWORDINTREE(0x41000000,0x00000000)}}, {VT_exponent,22,0x3a86da,{DOUBLEWITHTWODWORDINTREE(0x41100000,0x00000000)}}, {VT_exponent,17,0x1dc7e,{DOUBLEWITHTWODWORDINTREE(0x41200000,0x00000000)}}, {VT_exponent,22,0x3a86db,{DOUBLEWITHTWODWORDINTREE(0x41300000,0x00000000)}}, {VT_exponent,22,0x3a86dc,{DOUBLEWITHTWODWORDINTREE(0x41400000,0x00000000)}}, {VT_exponent,22,0x3a86dd,{DOUBLEWITHTWODWORDINTREE(0x41500000,0x00000000)}}, {VT_exponent,22,0x3a86de,{DOUBLEWITHTWODWORDINTREE(0x41600000,0x00000000)}}, {VT_exponent,22,0x3a86df,{DOUBLEWITHTWODWORDINTREE(0x41700000,0x00000000)}}, {VT_exponent,22,0x3a86f0,{DOUBLEWITHTWODWORDINTREE(0x41800000,0x00000000)}}, {VT_exponent,22,0x3a86f1,{DOUBLEWITHTWODWORDINTREE(0x41900000,0x00000000)}}, {VT_exponent,22,0x3a86f2,{DOUBLEWITHTWODWORDINTREE(0x41a00000,0x00000000)}}, {VT_exponent,22,0x3a86f3,{DOUBLEWITHTWODWORDINTREE(0x41b00000,0x00000000)}}, {VT_double,6,0x2a,{DOUBLEWITHTWODWORDINTREE(0x41cdcd64,0xff800000)}}, {VT_exponent,22,0x3a86f4,{DOUBLEWITHTWODWORDINTREE(0x41c00000,0x00000000)}}, {VT_exponent,22,0x3a86f5,{DOUBLEWITHTWODWORDINTREE(0x41d00000,0x00000000)}}, {VT_exponent,22,0x3a86f6,{DOUBLEWITHTWODWORDINTREE(0x41e00000,0x00000000)}}, {VT_exponent,22,0x3a86f7,{DOUBLEWITHTWODWORDINTREE(0x41f00000,0x00000000)}}, {VT_exponent,22,0x3a86f8,{DOUBLEWITHTWODWORDINTREE(0x42000000,0x00000000)}}, {VT_exponent,22,0x3a86f9,{DOUBLEWITHTWODWORDINTREE(0x42100000,0x00000000)}}, {VT_exponent,22,0x3a86fa,{DOUBLEWITHTWODWORDINTREE(0x42200000,0x00000000)}}, {VT_exponent,22,0x3a86fb,{DOUBLEWITHTWODWORDINTREE(0x42300000,0x00000000)}}, {VT_exponent,22,0x3a86fc,{DOUBLEWITHTWODWORDINTREE(0x42400000,0x00000000)}}, {VT_exponent,22,0x3a86fd,{DOUBLEWITHTWODWORDINTREE(0x42500000,0x00000000)}}, {VT_exponent,22,0x3a86fe,{DOUBLEWITHTWODWORDINTREE(0x42600000,0x00000000)}}, {VT_exponent,22,0x3a86ff,{DOUBLEWITHTWODWORDINTREE(0x42700000,0x00000000)}}, {VT_exponent,22,0x3a8740,{DOUBLEWITHTWODWORDINTREE(0x42800000,0x00000000)}}, {VT_exponent,22,0x3a8741,{DOUBLEWITHTWODWORDINTREE(0x42900000,0x00000000)}}, {VT_exponent,22,0x3a8742,{DOUBLEWITHTWODWORDINTREE(0x42a00000,0x00000000)}}, {VT_exponent,22,0x3a8743,{DOUBLEWITHTWODWORDINTREE(0x42b00000,0x00000000)}}, {VT_exponent,22,0x3a8744,{DOUBLEWITHTWODWORDINTREE(0x42c00000,0x00000000)}}, {VT_exponent,22,0x3a8745,{DOUBLEWITHTWODWORDINTREE(0x42d00000,0x00000000)}}, {VT_exponent,22,0x3a8746,{DOUBLEWITHTWODWORDINTREE(0x42e00000,0x00000000)}}, {VT_exponent,22,0x3a8747,{DOUBLEWITHTWODWORDINTREE(0x42f00000,0x00000000)}}, {VT_exponent,22,0x3a8748,{DOUBLEWITHTWODWORDINTREE(0x43000000,0x00000000)}}, {VT_exponent,22,0x3a8749,{DOUBLEWITHTWODWORDINTREE(0x43100000,0x00000000)}}, {VT_exponent,22,0x3a874a,{DOUBLEWITHTWODWORDINTREE(0x43200000,0x00000000)}}, {VT_exponent,22,0x3a874b,{DOUBLEWITHTWODWORDINTREE(0x43300000,0x00000000)}}, {VT_exponent,22,0x3a874c,{DOUBLEWITHTWODWORDINTREE(0x43400000,0x00000000)}}, {VT_exponent,22,0x3a874d,{DOUBLEWITHTWODWORDINTREE(0x43500000,0x00000000)}}, {VT_exponent,22,0x3a874e,{DOUBLEWITHTWODWORDINTREE(0x43600000,0x00000000)}}, {VT_exponent,22,0x3a874f,{DOUBLEWITHTWODWORDINTREE(0x43700000,0x00000000)}}, {VT_exponent,22,0x3a8750,{DOUBLEWITHTWODWORDINTREE(0x43800000,0x00000000)}}, {VT_exponent,22,0x3a8751,{DOUBLEWITHTWODWORDINTREE(0x43900000,0x00000000)}}, {VT_exponent,22,0x3a8752,{DOUBLEWITHTWODWORDINTREE(0x43a00000,0x00000000)}}, {VT_exponent,22,0x3a8753,{DOUBLEWITHTWODWORDINTREE(0x43b00000,0x00000000)}}, {VT_exponent,22,0x3a8754,{DOUBLEWITHTWODWORDINTREE(0x43c00000,0x00000000)}}, {VT_exponent,22,0x3a8755,{DOUBLEWITHTWODWORDINTREE(0x43d00000,0x00000000)}}, {VT_exponent,22,0x3a8756,{DOUBLEWITHTWODWORDINTREE(0x43e00000,0x00000000)}}, {VT_exponent,22,0x3a8757,{DOUBLEWITHTWODWORDINTREE(0x43f00000,0x00000000)}}, {VT_exponent,22,0x3a8758,{DOUBLEWITHTWODWORDINTREE(0x44000000,0x00000000)}}, {VT_exponent,15,0x1a3b,{DOUBLEWITHTWODWORDINTREE(0x44100000,0x00000000)}}, {VT_exponent,22,0x3a8759,{DOUBLEWITHTWODWORDINTREE(0x44200000,0x00000000)}}, {VT_exponent,22,0x3a875a,{DOUBLEWITHTWODWORDINTREE(0x44300000,0x00000000)}}, {VT_exponent,22,0x3a875b,{DOUBLEWITHTWODWORDINTREE(0x44400000,0x00000000)}}, {VT_exponent,22,0x3a875c,{DOUBLEWITHTWODWORDINTREE(0x44500000,0x00000000)}}, {VT_exponent,22,0x3a875d,{DOUBLEWITHTWODWORDINTREE(0x44600000,0x00000000)}}, {VT_exponent,22,0x3a875e,{DOUBLEWITHTWODWORDINTREE(0x44700000,0x00000000)}}, {VT_exponent,22,0x3a875f,{DOUBLEWITHTWODWORDINTREE(0x44800000,0x00000000)}}, {VT_exponent,22,0x3a8760,{DOUBLEWITHTWODWORDINTREE(0x44900000,0x00000000)}}, {VT_exponent,22,0x3a8761,{DOUBLEWITHTWODWORDINTREE(0x44a00000,0x00000000)}}, {VT_exponent,22,0x3a8762,{DOUBLEWITHTWODWORDINTREE(0x44b00000,0x00000000)}}, {VT_exponent,22,0x3a8763,{DOUBLEWITHTWODWORDINTREE(0x44c00000,0x00000000)}}, {VT_exponent,22,0x3a8764,{DOUBLEWITHTWODWORDINTREE(0x44d00000,0x00000000)}}, {VT_exponent,22,0x3a8765,{DOUBLEWITHTWODWORDINTREE(0x44e00000,0x00000000)}}, {VT_exponent,22,0x3a8766,{DOUBLEWITHTWODWORDINTREE(0x44f00000,0x00000000)}}, {VT_exponent,22,0x3a8767,{DOUBLEWITHTWODWORDINTREE(0x45000000,0x00000000)}}, {VT_exponent,22,0x3a8768,{DOUBLEWITHTWODWORDINTREE(0x45100000,0x00000000)}}, {VT_exponent,22,0x3a8769,{DOUBLEWITHTWODWORDINTREE(0x45200000,0x00000000)}}, {VT_exponent,22,0x3a876a,{DOUBLEWITHTWODWORDINTREE(0x45300000,0x00000000)}}, {VT_exponent,22,0x3a876b,{DOUBLEWITHTWODWORDINTREE(0x45400000,0x00000000)}}, {VT_exponent,22,0x3a876c,{DOUBLEWITHTWODWORDINTREE(0x45500000,0x00000000)}}, {VT_exponent,22,0x3a876d,{DOUBLEWITHTWODWORDINTREE(0x45600000,0x00000000)}}, {VT_exponent,22,0x3a876e,{DOUBLEWITHTWODWORDINTREE(0x45700000,0x00000000)}}, {VT_exponent,22,0x3a876f,{DOUBLEWITHTWODWORDINTREE(0x45800000,0x00000000)}}, {VT_exponent,22,0x3a8770,{DOUBLEWITHTWODWORDINTREE(0x45900000,0x00000000)}}, {VT_exponent,22,0x3a8771,{DOUBLEWITHTWODWORDINTREE(0x45a00000,0x00000000)}}, {VT_exponent,22,0x3a8772,{DOUBLEWITHTWODWORDINTREE(0x45b00000,0x00000000)}}, {VT_exponent,22,0x3a8773,{DOUBLEWITHTWODWORDINTREE(0x45c00000,0x00000000)}}, {VT_exponent,22,0x3a8774,{DOUBLEWITHTWODWORDINTREE(0x45d00000,0x00000000)}}, {VT_exponent,22,0x3a8775,{DOUBLEWITHTWODWORDINTREE(0x45e00000,0x00000000)}}, {VT_exponent,22,0x3a8776,{DOUBLEWITHTWODWORDINTREE(0x45f00000,0x00000000)}}, {VT_exponent,22,0x3a8777,{DOUBLEWITHTWODWORDINTREE(0x46000000,0x00000000)}}, {VT_exponent,22,0x3a8778,{DOUBLEWITHTWODWORDINTREE(0x46100000,0x00000000)}}, {VT_exponent,22,0x3a8779,{DOUBLEWITHTWODWORDINTREE(0x46200000,0x00000000)}}, {VT_exponent,22,0x3a877a,{DOUBLEWITHTWODWORDINTREE(0x46300000,0x00000000)}}, {VT_exponent,22,0x3a877b,{DOUBLEWITHTWODWORDINTREE(0x46400000,0x00000000)}}, {VT_exponent,22,0x3a877c,{DOUBLEWITHTWODWORDINTREE(0x46500000,0x00000000)}}, {VT_exponent,22,0x3a877d,{DOUBLEWITHTWODWORDINTREE(0x46600000,0x00000000)}}, {VT_exponent,22,0x3a877e,{DOUBLEWITHTWODWORDINTREE(0x46700000,0x00000000)}}, {VT_exponent,22,0x3a877f,{DOUBLEWITHTWODWORDINTREE(0x46800000,0x00000000)}}, {VT_exponent,22,0x3a8780,{DOUBLEWITHTWODWORDINTREE(0x46900000,0x00000000)}}, {VT_exponent,22,0x3a8781,{DOUBLEWITHTWODWORDINTREE(0x46a00000,0x00000000)}}, {VT_exponent,22,0x3a8782,{DOUBLEWITHTWODWORDINTREE(0x46b00000,0x00000000)}}, {VT_exponent,22,0x3a8783,{DOUBLEWITHTWODWORDINTREE(0x46c00000,0x00000000)}}, {VT_exponent,22,0x3a8784,{DOUBLEWITHTWODWORDINTREE(0x46d00000,0x00000000)}}, {VT_exponent,22,0x3a8785,{DOUBLEWITHTWODWORDINTREE(0x46e00000,0x00000000)}}, {VT_exponent,22,0x3a8786,{DOUBLEWITHTWODWORDINTREE(0x46f00000,0x00000000)}}, {VT_exponent,22,0x3a8787,{DOUBLEWITHTWODWORDINTREE(0x47000000,0x00000000)}}, {VT_exponent,22,0x3a8788,{DOUBLEWITHTWODWORDINTREE(0x47100000,0x00000000)}}, {VT_exponent,22,0x3a8789,{DOUBLEWITHTWODWORDINTREE(0x47200000,0x00000000)}}, {VT_exponent,22,0x3a878a,{DOUBLEWITHTWODWORDINTREE(0x47300000,0x00000000)}}, {VT_exponent,22,0x3a878b,{DOUBLEWITHTWODWORDINTREE(0x47400000,0x00000000)}}, {VT_exponent,22,0x3a878c,{DOUBLEWITHTWODWORDINTREE(0x47500000,0x00000000)}}, {VT_exponent,22,0x3a878d,{DOUBLEWITHTWODWORDINTREE(0x47600000,0x00000000)}}, {VT_exponent,22,0x3a878e,{DOUBLEWITHTWODWORDINTREE(0x47700000,0x00000000)}}, {VT_exponent,22,0x3a878f,{DOUBLEWITHTWODWORDINTREE(0x47800000,0x00000000)}}, {VT_exponent,22,0x3a8790,{DOUBLEWITHTWODWORDINTREE(0x47900000,0x00000000)}}, {VT_exponent,22,0x3a8791,{DOUBLEWITHTWODWORDINTREE(0x47a00000,0x00000000)}}, {VT_exponent,22,0x3a8792,{DOUBLEWITHTWODWORDINTREE(0x47b00000,0x00000000)}}, {VT_exponent,22,0x3a8793,{DOUBLEWITHTWODWORDINTREE(0x47c00000,0x00000000)}}, {VT_exponent,22,0x3a8794,{DOUBLEWITHTWODWORDINTREE(0x47d00000,0x00000000)}}, {VT_exponent,22,0x3a8795,{DOUBLEWITHTWODWORDINTREE(0x47e00000,0x00000000)}}, {VT_exponent,22,0x3a8796,{DOUBLEWITHTWODWORDINTREE(0x47f00000,0x00000000)}}, {VT_exponent,22,0x3a8797,{DOUBLEWITHTWODWORDINTREE(0x48000000,0x00000000)}}, {VT_exponent,22,0x3a8798,{DOUBLEWITHTWODWORDINTREE(0x48100000,0x00000000)}}, {VT_exponent,22,0x3a8799,{DOUBLEWITHTWODWORDINTREE(0x48200000,0x00000000)}}, {VT_exponent,22,0x3a879a,{DOUBLEWITHTWODWORDINTREE(0x48300000,0x00000000)}}, {VT_exponent,22,0x3a879b,{DOUBLEWITHTWODWORDINTREE(0x48400000,0x00000000)}}, {VT_exponent,22,0x3a879c,{DOUBLEWITHTWODWORDINTREE(0x48500000,0x00000000)}}, {VT_exponent,22,0x3a879d,{DOUBLEWITHTWODWORDINTREE(0x48600000,0x00000000)}}, {VT_exponent,22,0x3a879e,{DOUBLEWITHTWODWORDINTREE(0x48700000,0x00000000)}}, {VT_exponent,22,0x3a879f,{DOUBLEWITHTWODWORDINTREE(0x48800000,0x00000000)}}, {VT_exponent,22,0x3a87a0,{DOUBLEWITHTWODWORDINTREE(0x48900000,0x00000000)}}, {VT_exponent,22,0x3a87a1,{DOUBLEWITHTWODWORDINTREE(0x48a00000,0x00000000)}}, {VT_exponent,22,0x3a87a2,{DOUBLEWITHTWODWORDINTREE(0x48b00000,0x00000000)}}, {VT_exponent,22,0x3a87a3,{DOUBLEWITHTWODWORDINTREE(0x48c00000,0x00000000)}}, {VT_exponent,22,0x3a87a4,{DOUBLEWITHTWODWORDINTREE(0x48d00000,0x00000000)}}, {VT_exponent,22,0x3a87a5,{DOUBLEWITHTWODWORDINTREE(0x48e00000,0x00000000)}}, {VT_exponent,22,0x3a87a6,{DOUBLEWITHTWODWORDINTREE(0x48f00000,0x00000000)}}, {VT_exponent,22,0x3a87a7,{DOUBLEWITHTWODWORDINTREE(0x49000000,0x00000000)}}, {VT_exponent,22,0x3a87a8,{DOUBLEWITHTWODWORDINTREE(0x49100000,0x00000000)}}, {VT_exponent,22,0x3a87a9,{DOUBLEWITHTWODWORDINTREE(0x49200000,0x00000000)}}, {VT_exponent,22,0x3a87aa,{DOUBLEWITHTWODWORDINTREE(0x49300000,0x00000000)}}, {VT_exponent,22,0x3a87ab,{DOUBLEWITHTWODWORDINTREE(0x49400000,0x00000000)}}, {VT_exponent,22,0x3a87ac,{DOUBLEWITHTWODWORDINTREE(0x49500000,0x00000000)}}, {VT_exponent,22,0x3a87ad,{DOUBLEWITHTWODWORDINTREE(0x49600000,0x00000000)}}, {VT_exponent,22,0x3a87ae,{DOUBLEWITHTWODWORDINTREE(0x49700000,0x00000000)}}, {VT_exponent,22,0x3a87af,{DOUBLEWITHTWODWORDINTREE(0x49800000,0x00000000)}}, {VT_exponent,22,0x3a87b0,{DOUBLEWITHTWODWORDINTREE(0x49900000,0x00000000)}}, {VT_exponent,22,0x3a87b1,{DOUBLEWITHTWODWORDINTREE(0x49a00000,0x00000000)}}, {VT_exponent,22,0x3a87b2,{DOUBLEWITHTWODWORDINTREE(0x49b00000,0x00000000)}}, {VT_exponent,22,0x3a87b3,{DOUBLEWITHTWODWORDINTREE(0x49c00000,0x00000000)}}, {VT_exponent,22,0x3a87b4,{DOUBLEWITHTWODWORDINTREE(0x49d00000,0x00000000)}}, {VT_exponent,22,0x3a87b5,{DOUBLEWITHTWODWORDINTREE(0x49e00000,0x00000000)}}, {VT_exponent,22,0x3a87b6,{DOUBLEWITHTWODWORDINTREE(0x49f00000,0x00000000)}}, {VT_exponent,22,0x3a87b7,{DOUBLEWITHTWODWORDINTREE(0x4a000000,0x00000000)}}, {VT_exponent,22,0x3a87b8,{DOUBLEWITHTWODWORDINTREE(0x4a100000,0x00000000)}}, {VT_exponent,22,0x3a87b9,{DOUBLEWITHTWODWORDINTREE(0x4a200000,0x00000000)}}, {VT_exponent,22,0x3a87ba,{DOUBLEWITHTWODWORDINTREE(0x4a300000,0x00000000)}}, {VT_exponent,22,0x3a87bb,{DOUBLEWITHTWODWORDINTREE(0x4a400000,0x00000000)}}, {VT_exponent,22,0x3a87bc,{DOUBLEWITHTWODWORDINTREE(0x4a500000,0x00000000)}}, {VT_exponent,22,0x3a87bd,{DOUBLEWITHTWODWORDINTREE(0x4a600000,0x00000000)}}, {VT_exponent,22,0x3a87be,{DOUBLEWITHTWODWORDINTREE(0x4a700000,0x00000000)}}, {VT_exponent,22,0x3a87bf,{DOUBLEWITHTWODWORDINTREE(0x4a800000,0x00000000)}}, {VT_exponent,22,0x3a87c0,{DOUBLEWITHTWODWORDINTREE(0x4a900000,0x00000000)}}, {VT_exponent,22,0x3a87c1,{DOUBLEWITHTWODWORDINTREE(0x4aa00000,0x00000000)}}, {VT_exponent,22,0x3a87c2,{DOUBLEWITHTWODWORDINTREE(0x4ab00000,0x00000000)}}, {VT_exponent,22,0x3a87c3,{DOUBLEWITHTWODWORDINTREE(0x4ac00000,0x00000000)}}, {VT_exponent,22,0x3a87c4,{DOUBLEWITHTWODWORDINTREE(0x4ad00000,0x00000000)}}, {VT_exponent,22,0x3a87c5,{DOUBLEWITHTWODWORDINTREE(0x4ae00000,0x00000000)}}, {VT_exponent,22,0x3a87c6,{DOUBLEWITHTWODWORDINTREE(0x4af00000,0x00000000)}}, {VT_exponent,22,0x3a87c7,{DOUBLEWITHTWODWORDINTREE(0x4b000000,0x00000000)}}, {VT_exponent,22,0x3a87c8,{DOUBLEWITHTWODWORDINTREE(0x4b100000,0x00000000)}}, {VT_exponent,22,0x3a87c9,{DOUBLEWITHTWODWORDINTREE(0x4b200000,0x00000000)}}, {VT_exponent,22,0x3a87ca,{DOUBLEWITHTWODWORDINTREE(0x4b300000,0x00000000)}}, {VT_exponent,22,0x3a87cb,{DOUBLEWITHTWODWORDINTREE(0x4b400000,0x00000000)}}, {VT_exponent,22,0x3a87cc,{DOUBLEWITHTWODWORDINTREE(0x4b500000,0x00000000)}}, {VT_exponent,22,0x3a87cd,{DOUBLEWITHTWODWORDINTREE(0x4b600000,0x00000000)}}, {VT_exponent,22,0x3a87ce,{DOUBLEWITHTWODWORDINTREE(0x4b700000,0x00000000)}}, {VT_exponent,22,0x3a87cf,{DOUBLEWITHTWODWORDINTREE(0x4b800000,0x00000000)}}, {VT_exponent,22,0x3a87d0,{DOUBLEWITHTWODWORDINTREE(0x4b900000,0x00000000)}}, {VT_exponent,22,0x3a87d1,{DOUBLEWITHTWODWORDINTREE(0x4ba00000,0x00000000)}}, {VT_exponent,22,0x3a87d2,{DOUBLEWITHTWODWORDINTREE(0x4bb00000,0x00000000)}}, {VT_exponent,22,0x3a87d3,{DOUBLEWITHTWODWORDINTREE(0x4bc00000,0x00000000)}}, {VT_exponent,22,0x3a87d4,{DOUBLEWITHTWODWORDINTREE(0x4bd00000,0x00000000)}}, {VT_exponent,22,0x3a87d5,{DOUBLEWITHTWODWORDINTREE(0x4be00000,0x00000000)}}, {VT_exponent,22,0x3a87d6,{DOUBLEWITHTWODWORDINTREE(0x4bf00000,0x00000000)}}, {VT_exponent,22,0x3a87d7,{DOUBLEWITHTWODWORDINTREE(0x4c000000,0x00000000)}}, {VT_exponent,22,0x3a87d8,{DOUBLEWITHTWODWORDINTREE(0x4c100000,0x00000000)}}, {VT_exponent,22,0x3a87d9,{DOUBLEWITHTWODWORDINTREE(0x4c200000,0x00000000)}}, {VT_exponent,22,0x3a87da,{DOUBLEWITHTWODWORDINTREE(0x4c300000,0x00000000)}}, {VT_exponent,22,0x3a87db,{DOUBLEWITHTWODWORDINTREE(0x4c400000,0x00000000)}}, {VT_exponent,22,0x3a87dc,{DOUBLEWITHTWODWORDINTREE(0x4c500000,0x00000000)}}, {VT_exponent,22,0x3a87dd,{DOUBLEWITHTWODWORDINTREE(0x4c600000,0x00000000)}}, {VT_exponent,22,0x3a87de,{DOUBLEWITHTWODWORDINTREE(0x4c700000,0x00000000)}}, {VT_exponent,22,0x3a87df,{DOUBLEWITHTWODWORDINTREE(0x4c800000,0x00000000)}}, {VT_exponent,22,0x3a87e0,{DOUBLEWITHTWODWORDINTREE(0x4c900000,0x00000000)}}, {VT_exponent,22,0x3a87e1,{DOUBLEWITHTWODWORDINTREE(0x4ca00000,0x00000000)}}, {VT_exponent,22,0x3a87e2,{DOUBLEWITHTWODWORDINTREE(0x4cb00000,0x00000000)}}, {VT_exponent,22,0x3a87e3,{DOUBLEWITHTWODWORDINTREE(0x4cc00000,0x00000000)}}, {VT_exponent,22,0x3a87e4,{DOUBLEWITHTWODWORDINTREE(0x4cd00000,0x00000000)}}, {VT_exponent,22,0x3a87e5,{DOUBLEWITHTWODWORDINTREE(0x4ce00000,0x00000000)}}, {VT_exponent,22,0x3a87e6,{DOUBLEWITHTWODWORDINTREE(0x4cf00000,0x00000000)}}, {VT_exponent,22,0x3a87e7,{DOUBLEWITHTWODWORDINTREE(0x4d000000,0x00000000)}}, {VT_exponent,22,0x3a87e8,{DOUBLEWITHTWODWORDINTREE(0x4d100000,0x00000000)}}, {VT_exponent,22,0x3a87e9,{DOUBLEWITHTWODWORDINTREE(0x4d200000,0x00000000)}}, {VT_exponent,22,0x3a87ea,{DOUBLEWITHTWODWORDINTREE(0x4d300000,0x00000000)}}, {VT_exponent,22,0x3a87eb,{DOUBLEWITHTWODWORDINTREE(0x4d400000,0x00000000)}}, {VT_exponent,22,0x3a87ec,{DOUBLEWITHTWODWORDINTREE(0x4d500000,0x00000000)}}, {VT_exponent,22,0x3a87ed,{DOUBLEWITHTWODWORDINTREE(0x4d600000,0x00000000)}}, {VT_exponent,22,0x3a87ee,{DOUBLEWITHTWODWORDINTREE(0x4d700000,0x00000000)}}, {VT_exponent,22,0x3a87ef,{DOUBLEWITHTWODWORDINTREE(0x4d800000,0x00000000)}}, {VT_exponent,22,0x3a87f0,{DOUBLEWITHTWODWORDINTREE(0x4d900000,0x00000000)}}, {VT_exponent,22,0x3a87f1,{DOUBLEWITHTWODWORDINTREE(0x4da00000,0x00000000)}}, {VT_exponent,22,0x3a87f2,{DOUBLEWITHTWODWORDINTREE(0x4db00000,0x00000000)}}, {VT_exponent,22,0x3a87f3,{DOUBLEWITHTWODWORDINTREE(0x4dc00000,0x00000000)}}, {VT_exponent,22,0x3a87f4,{DOUBLEWITHTWODWORDINTREE(0x4dd00000,0x00000000)}}, {VT_exponent,22,0x3a87f5,{DOUBLEWITHTWODWORDINTREE(0x4de00000,0x00000000)}}, {VT_exponent,22,0x3a87f6,{DOUBLEWITHTWODWORDINTREE(0x4df00000,0x00000000)}}, {VT_exponent,22,0x3a87f7,{DOUBLEWITHTWODWORDINTREE(0x4e000000,0x00000000)}}, {VT_exponent,22,0x3a87f8,{DOUBLEWITHTWODWORDINTREE(0x4e100000,0x00000000)}}, {VT_exponent,22,0x3a87f9,{DOUBLEWITHTWODWORDINTREE(0x4e200000,0x00000000)}}, {VT_exponent,22,0x3a87fa,{DOUBLEWITHTWODWORDINTREE(0x4e300000,0x00000000)}}, {VT_exponent,22,0x3a87fb,{DOUBLEWITHTWODWORDINTREE(0x4e400000,0x00000000)}}, {VT_exponent,22,0x3a87fc,{DOUBLEWITHTWODWORDINTREE(0x4e500000,0x00000000)}}, {VT_exponent,22,0x3a87fd,{DOUBLEWITHTWODWORDINTREE(0x4e600000,0x00000000)}}, {VT_exponent,22,0x3a87fe,{DOUBLEWITHTWODWORDINTREE(0x4e700000,0x00000000)}}, {VT_exponent,22,0x3a87ff,{DOUBLEWITHTWODWORDINTREE(0x4e800000,0x00000000)}}, {VT_exponent,22,0x3a9000,{DOUBLEWITHTWODWORDINTREE(0x4e900000,0x00000000)}}, {VT_exponent,22,0x3a9001,{DOUBLEWITHTWODWORDINTREE(0x4ea00000,0x00000000)}}, {VT_exponent,22,0x3a9002,{DOUBLEWITHTWODWORDINTREE(0x4eb00000,0x00000000)}}, {VT_exponent,22,0x3a9003,{DOUBLEWITHTWODWORDINTREE(0x4ec00000,0x00000000)}}, {VT_exponent,22,0x3a9004,{DOUBLEWITHTWODWORDINTREE(0x4ed00000,0x00000000)}}, {VT_exponent,22,0x3a9005,{DOUBLEWITHTWODWORDINTREE(0x4ee00000,0x00000000)}}, {VT_exponent,22,0x3a9006,{DOUBLEWITHTWODWORDINTREE(0x4ef00000,0x00000000)}}, {VT_exponent,22,0x3a9007,{DOUBLEWITHTWODWORDINTREE(0x4f000000,0x00000000)}}, {VT_exponent,22,0x3a9008,{DOUBLEWITHTWODWORDINTREE(0x4f100000,0x00000000)}}, {VT_exponent,22,0x3a9009,{DOUBLEWITHTWODWORDINTREE(0x4f200000,0x00000000)}}, {VT_exponent,22,0x3a900a,{DOUBLEWITHTWODWORDINTREE(0x4f300000,0x00000000)}}, {VT_exponent,22,0x3a900b,{DOUBLEWITHTWODWORDINTREE(0x4f400000,0x00000000)}}, {VT_exponent,22,0x3a900c,{DOUBLEWITHTWODWORDINTREE(0x4f500000,0x00000000)}}, {VT_exponent,22,0x3a900d,{DOUBLEWITHTWODWORDINTREE(0x4f600000,0x00000000)}}, {VT_exponent,22,0x3a900e,{DOUBLEWITHTWODWORDINTREE(0x4f700000,0x00000000)}}, {VT_exponent,22,0x3a900f,{DOUBLEWITHTWODWORDINTREE(0x4f800000,0x00000000)}}, {VT_exponent,22,0x3a9010,{DOUBLEWITHTWODWORDINTREE(0x4f900000,0x00000000)}}, {VT_exponent,22,0x3a9011,{DOUBLEWITHTWODWORDINTREE(0x4fa00000,0x00000000)}}, {VT_exponent,22,0x3a9012,{DOUBLEWITHTWODWORDINTREE(0x4fb00000,0x00000000)}}, {VT_exponent,22,0x3a9013,{DOUBLEWITHTWODWORDINTREE(0x4fc00000,0x00000000)}}, {VT_exponent,22,0x3a9014,{DOUBLEWITHTWODWORDINTREE(0x4fd00000,0x00000000)}}, {VT_exponent,22,0x3a9015,{DOUBLEWITHTWODWORDINTREE(0x4fe00000,0x00000000)}}, {VT_exponent,22,0x3a9016,{DOUBLEWITHTWODWORDINTREE(0x4ff00000,0x00000000)}}, {VT_exponent,22,0x3a9017,{DOUBLEWITHTWODWORDINTREE(0x50000000,0x00000000)}}, {VT_exponent,22,0x3a9018,{DOUBLEWITHTWODWORDINTREE(0x50100000,0x00000000)}}, {VT_exponent,22,0x3a9019,{DOUBLEWITHTWODWORDINTREE(0x50200000,0x00000000)}}, {VT_exponent,22,0x3a901a,{DOUBLEWITHTWODWORDINTREE(0x50300000,0x00000000)}}, {VT_exponent,22,0x3a901b,{DOUBLEWITHTWODWORDINTREE(0x50400000,0x00000000)}}, {VT_exponent,22,0x3a901c,{DOUBLEWITHTWODWORDINTREE(0x50500000,0x00000000)}}, {VT_exponent,22,0x3a901d,{DOUBLEWITHTWODWORDINTREE(0x50600000,0x00000000)}}, {VT_exponent,22,0x3a901e,{DOUBLEWITHTWODWORDINTREE(0x50700000,0x00000000)}}, {VT_exponent,22,0x3a901f,{DOUBLEWITHTWODWORDINTREE(0x50800000,0x00000000)}}, {VT_exponent,22,0x3a9020,{DOUBLEWITHTWODWORDINTREE(0x50900000,0x00000000)}}, {VT_exponent,22,0x3a9021,{DOUBLEWITHTWODWORDINTREE(0x50a00000,0x00000000)}}, {VT_exponent,22,0x3a9022,{DOUBLEWITHTWODWORDINTREE(0x50b00000,0x00000000)}}, {VT_exponent,22,0x3a9023,{DOUBLEWITHTWODWORDINTREE(0x50c00000,0x00000000)}}, {VT_exponent,22,0x3a9024,{DOUBLEWITHTWODWORDINTREE(0x50d00000,0x00000000)}}, {VT_exponent,22,0x3a9025,{DOUBLEWITHTWODWORDINTREE(0x50e00000,0x00000000)}}, {VT_exponent,22,0x3a9026,{DOUBLEWITHTWODWORDINTREE(0x50f00000,0x00000000)}}, {VT_exponent,22,0x3a9027,{DOUBLEWITHTWODWORDINTREE(0x51000000,0x00000000)}}, {VT_exponent,22,0x3a9028,{DOUBLEWITHTWODWORDINTREE(0x51100000,0x00000000)}}, {VT_exponent,22,0x3a9029,{DOUBLEWITHTWODWORDINTREE(0x51200000,0x00000000)}}, {VT_exponent,22,0x3a902a,{DOUBLEWITHTWODWORDINTREE(0x51300000,0x00000000)}}, {VT_exponent,22,0x3a902b,{DOUBLEWITHTWODWORDINTREE(0x51400000,0x00000000)}}, {VT_exponent,22,0x3a902c,{DOUBLEWITHTWODWORDINTREE(0x51500000,0x00000000)}}, {VT_exponent,22,0x3a902d,{DOUBLEWITHTWODWORDINTREE(0x51600000,0x00000000)}}, {VT_exponent,22,0x3a902e,{DOUBLEWITHTWODWORDINTREE(0x51700000,0x00000000)}}, {VT_exponent,22,0x3a902f,{DOUBLEWITHTWODWORDINTREE(0x51800000,0x00000000)}}, {VT_exponent,22,0x3a9030,{DOUBLEWITHTWODWORDINTREE(0x51900000,0x00000000)}}, {VT_exponent,22,0x3a9031,{DOUBLEWITHTWODWORDINTREE(0x51a00000,0x00000000)}}, {VT_exponent,22,0x3a9032,{DOUBLEWITHTWODWORDINTREE(0x51b00000,0x00000000)}}, {VT_exponent,22,0x3a9033,{DOUBLEWITHTWODWORDINTREE(0x51c00000,0x00000000)}}, {VT_exponent,22,0x3a9034,{DOUBLEWITHTWODWORDINTREE(0x51d00000,0x00000000)}}, {VT_exponent,22,0x3a9035,{DOUBLEWITHTWODWORDINTREE(0x51e00000,0x00000000)}}, {VT_exponent,22,0x3a9036,{DOUBLEWITHTWODWORDINTREE(0x51f00000,0x00000000)}}, {VT_exponent,22,0x3a9037,{DOUBLEWITHTWODWORDINTREE(0x52000000,0x00000000)}}, {VT_exponent,22,0x3a9038,{DOUBLEWITHTWODWORDINTREE(0x52100000,0x00000000)}}, {VT_exponent,22,0x3a9039,{DOUBLEWITHTWODWORDINTREE(0x52200000,0x00000000)}}, {VT_exponent,22,0x3a903a,{DOUBLEWITHTWODWORDINTREE(0x52300000,0x00000000)}}, {VT_exponent,22,0x3a903b,{DOUBLEWITHTWODWORDINTREE(0x52400000,0x00000000)}}, {VT_exponent,22,0x3a903c,{DOUBLEWITHTWODWORDINTREE(0x52500000,0x00000000)}}, {VT_exponent,22,0x3a903d,{DOUBLEWITHTWODWORDINTREE(0x52600000,0x00000000)}}, {VT_exponent,22,0x3a903e,{DOUBLEWITHTWODWORDINTREE(0x52700000,0x00000000)}}, {VT_exponent,22,0x3a903f,{DOUBLEWITHTWODWORDINTREE(0x52800000,0x00000000)}}, {VT_exponent,22,0x3a9040,{DOUBLEWITHTWODWORDINTREE(0x52900000,0x00000000)}}, {VT_exponent,22,0x3a9041,{DOUBLEWITHTWODWORDINTREE(0x52a00000,0x00000000)}}, {VT_exponent,22,0x3a9042,{DOUBLEWITHTWODWORDINTREE(0x52b00000,0x00000000)}}, {VT_exponent,22,0x3a9043,{DOUBLEWITHTWODWORDINTREE(0x52c00000,0x00000000)}}, {VT_exponent,22,0x3a9044,{DOUBLEWITHTWODWORDINTREE(0x52d00000,0x00000000)}}, {VT_exponent,22,0x3a9045,{DOUBLEWITHTWODWORDINTREE(0x52e00000,0x00000000)}}, {VT_exponent,22,0x3a9046,{DOUBLEWITHTWODWORDINTREE(0x52f00000,0x00000000)}}, {VT_exponent,22,0x3a9047,{DOUBLEWITHTWODWORDINTREE(0x53000000,0x00000000)}}, {VT_exponent,22,0x3a9048,{DOUBLEWITHTWODWORDINTREE(0x53100000,0x00000000)}}, {VT_exponent,22,0x3a9049,{DOUBLEWITHTWODWORDINTREE(0x53200000,0x00000000)}}, {VT_exponent,22,0x3a904a,{DOUBLEWITHTWODWORDINTREE(0x53300000,0x00000000)}}, {VT_exponent,22,0x3a904b,{DOUBLEWITHTWODWORDINTREE(0x53400000,0x00000000)}}, {VT_exponent,22,0x3a904c,{DOUBLEWITHTWODWORDINTREE(0x53500000,0x00000000)}}, {VT_exponent,22,0x3a904d,{DOUBLEWITHTWODWORDINTREE(0x53600000,0x00000000)}}, {VT_exponent,22,0x3a904e,{DOUBLEWITHTWODWORDINTREE(0x53700000,0x00000000)}}, {VT_exponent,22,0x3a904f,{DOUBLEWITHTWODWORDINTREE(0x53800000,0x00000000)}}, {VT_exponent,22,0x3a9050,{DOUBLEWITHTWODWORDINTREE(0x53900000,0x00000000)}}, {VT_exponent,22,0x3a9051,{DOUBLEWITHTWODWORDINTREE(0x53a00000,0x00000000)}}, {VT_exponent,22,0x3a9052,{DOUBLEWITHTWODWORDINTREE(0x53b00000,0x00000000)}}, {VT_exponent,22,0x3a9053,{DOUBLEWITHTWODWORDINTREE(0x53c00000,0x00000000)}}, {VT_exponent,22,0x3a9054,{DOUBLEWITHTWODWORDINTREE(0x53d00000,0x00000000)}}, {VT_exponent,22,0x3a9055,{DOUBLEWITHTWODWORDINTREE(0x53e00000,0x00000000)}}, {VT_exponent,22,0x3a9056,{DOUBLEWITHTWODWORDINTREE(0x53f00000,0x00000000)}}, {VT_exponent,22,0x3a9057,{DOUBLEWITHTWODWORDINTREE(0x54000000,0x00000000)}}, {VT_exponent,22,0x3a9058,{DOUBLEWITHTWODWORDINTREE(0x54100000,0x00000000)}}, {VT_exponent,22,0x3a9059,{DOUBLEWITHTWODWORDINTREE(0x54200000,0x00000000)}}, {VT_exponent,22,0x3a905a,{DOUBLEWITHTWODWORDINTREE(0x54300000,0x00000000)}}, {VT_exponent,22,0x3a905b,{DOUBLEWITHTWODWORDINTREE(0x54400000,0x00000000)}}, {VT_exponent,22,0x3a905c,{DOUBLEWITHTWODWORDINTREE(0x54500000,0x00000000)}}, {VT_exponent,22,0x3a905d,{DOUBLEWITHTWODWORDINTREE(0x54600000,0x00000000)}}, {VT_exponent,22,0x3a905e,{DOUBLEWITHTWODWORDINTREE(0x54700000,0x00000000)}}, {VT_exponent,22,0x3a905f,{DOUBLEWITHTWODWORDINTREE(0x54800000,0x00000000)}}, {VT_exponent,22,0x3a9060,{DOUBLEWITHTWODWORDINTREE(0x54900000,0x00000000)}}, {VT_exponent,22,0x3a9061,{DOUBLEWITHTWODWORDINTREE(0x54a00000,0x00000000)}}, {VT_exponent,22,0x3a9062,{DOUBLEWITHTWODWORDINTREE(0x54b00000,0x00000000)}}, {VT_exponent,22,0x3a9063,{DOUBLEWITHTWODWORDINTREE(0x54c00000,0x00000000)}}, {VT_exponent,22,0x3a9064,{DOUBLEWITHTWODWORDINTREE(0x54d00000,0x00000000)}}, {VT_exponent,22,0x3a9065,{DOUBLEWITHTWODWORDINTREE(0x54e00000,0x00000000)}}, {VT_exponent,22,0x3a9066,{DOUBLEWITHTWODWORDINTREE(0x54f00000,0x00000000)}}, {VT_exponent,22,0x3a9067,{DOUBLEWITHTWODWORDINTREE(0x55000000,0x00000000)}}, {VT_exponent,22,0x3a9068,{DOUBLEWITHTWODWORDINTREE(0x55100000,0x00000000)}}, {VT_exponent,22,0x3a9069,{DOUBLEWITHTWODWORDINTREE(0x55200000,0x00000000)}}, {VT_exponent,22,0x3a906a,{DOUBLEWITHTWODWORDINTREE(0x55300000,0x00000000)}}, {VT_exponent,22,0x3a906b,{DOUBLEWITHTWODWORDINTREE(0x55400000,0x00000000)}}, {VT_exponent,22,0x3a906c,{DOUBLEWITHTWODWORDINTREE(0x55500000,0x00000000)}}, {VT_exponent,22,0x3a906d,{DOUBLEWITHTWODWORDINTREE(0x55600000,0x00000000)}}, {VT_exponent,22,0x3a906e,{DOUBLEWITHTWODWORDINTREE(0x55700000,0x00000000)}}, {VT_exponent,22,0x3a906f,{DOUBLEWITHTWODWORDINTREE(0x55800000,0x00000000)}}, {VT_exponent,22,0x3a9070,{DOUBLEWITHTWODWORDINTREE(0x55900000,0x00000000)}}, {VT_exponent,22,0x3a9071,{DOUBLEWITHTWODWORDINTREE(0x55a00000,0x00000000)}}, {VT_exponent,22,0x3a9072,{DOUBLEWITHTWODWORDINTREE(0x55b00000,0x00000000)}}, {VT_exponent,22,0x3a9073,{DOUBLEWITHTWODWORDINTREE(0x55c00000,0x00000000)}}, {VT_exponent,22,0x3a9074,{DOUBLEWITHTWODWORDINTREE(0x55d00000,0x00000000)}}, {VT_exponent,22,0x3a9075,{DOUBLEWITHTWODWORDINTREE(0x55e00000,0x00000000)}}, {VT_exponent,22,0x3a9076,{DOUBLEWITHTWODWORDINTREE(0x55f00000,0x00000000)}}, {VT_exponent,22,0x3a9077,{DOUBLEWITHTWODWORDINTREE(0x56000000,0x00000000)}}, {VT_exponent,22,0x3a9078,{DOUBLEWITHTWODWORDINTREE(0x56100000,0x00000000)}}, {VT_exponent,22,0x3a9079,{DOUBLEWITHTWODWORDINTREE(0x56200000,0x00000000)}}, {VT_exponent,22,0x3a907a,{DOUBLEWITHTWODWORDINTREE(0x56300000,0x00000000)}}, {VT_exponent,22,0x3a907b,{DOUBLEWITHTWODWORDINTREE(0x56400000,0x00000000)}}, {VT_exponent,22,0x3a907c,{DOUBLEWITHTWODWORDINTREE(0x56500000,0x00000000)}}, {VT_exponent,22,0x3a907d,{DOUBLEWITHTWODWORDINTREE(0x56600000,0x00000000)}}, {VT_exponent,22,0x3a907e,{DOUBLEWITHTWODWORDINTREE(0x56700000,0x00000000)}}, {VT_exponent,22,0x3a907f,{DOUBLEWITHTWODWORDINTREE(0x56800000,0x00000000)}}, {VT_exponent,22,0x3a9080,{DOUBLEWITHTWODWORDINTREE(0x56900000,0x00000000)}}, {VT_exponent,22,0x3a9081,{DOUBLEWITHTWODWORDINTREE(0x56a00000,0x00000000)}}, {VT_exponent,22,0x3a9082,{DOUBLEWITHTWODWORDINTREE(0x56b00000,0x00000000)}}, {VT_exponent,22,0x3a9083,{DOUBLEWITHTWODWORDINTREE(0x56c00000,0x00000000)}}, {VT_exponent,22,0x3a9084,{DOUBLEWITHTWODWORDINTREE(0x56d00000,0x00000000)}}, {VT_exponent,22,0x3a9085,{DOUBLEWITHTWODWORDINTREE(0x56e00000,0x00000000)}}, {VT_exponent,22,0x3a9086,{DOUBLEWITHTWODWORDINTREE(0x56f00000,0x00000000)}}, {VT_exponent,22,0x3a9087,{DOUBLEWITHTWODWORDINTREE(0x57000000,0x00000000)}}, {VT_exponent,22,0x3a9088,{DOUBLEWITHTWODWORDINTREE(0x57100000,0x00000000)}}, {VT_exponent,22,0x3a9089,{DOUBLEWITHTWODWORDINTREE(0x57200000,0x00000000)}}, {VT_exponent,22,0x3a908a,{DOUBLEWITHTWODWORDINTREE(0x57300000,0x00000000)}}, {VT_exponent,22,0x3a908b,{DOUBLEWITHTWODWORDINTREE(0x57400000,0x00000000)}}, {VT_exponent,22,0x3a908c,{DOUBLEWITHTWODWORDINTREE(0x57500000,0x00000000)}}, {VT_exponent,22,0x3a908d,{DOUBLEWITHTWODWORDINTREE(0x57600000,0x00000000)}}, {VT_exponent,22,0x3a908e,{DOUBLEWITHTWODWORDINTREE(0x57700000,0x00000000)}}, {VT_exponent,22,0x3a908f,{DOUBLEWITHTWODWORDINTREE(0x57800000,0x00000000)}}, {VT_exponent,22,0x3a9090,{DOUBLEWITHTWODWORDINTREE(0x57900000,0x00000000)}}, {VT_exponent,22,0x3a9091,{DOUBLEWITHTWODWORDINTREE(0x57a00000,0x00000000)}}, {VT_exponent,22,0x3a9092,{DOUBLEWITHTWODWORDINTREE(0x57b00000,0x00000000)}}, {VT_exponent,22,0x3a9093,{DOUBLEWITHTWODWORDINTREE(0x57c00000,0x00000000)}}, {VT_exponent,22,0x3a9094,{DOUBLEWITHTWODWORDINTREE(0x57d00000,0x00000000)}}, {VT_exponent,22,0x3a9095,{DOUBLEWITHTWODWORDINTREE(0x57e00000,0x00000000)}}, {VT_exponent,22,0x3a9096,{DOUBLEWITHTWODWORDINTREE(0x57f00000,0x00000000)}}, {VT_exponent,22,0x3a9097,{DOUBLEWITHTWODWORDINTREE(0x58000000,0x00000000)}}, {VT_exponent,22,0x3a9098,{DOUBLEWITHTWODWORDINTREE(0x58100000,0x00000000)}}, {VT_exponent,22,0x3a9099,{DOUBLEWITHTWODWORDINTREE(0x58200000,0x00000000)}}, {VT_exponent,22,0x3a909a,{DOUBLEWITHTWODWORDINTREE(0x58300000,0x00000000)}}, {VT_exponent,22,0x3a909b,{DOUBLEWITHTWODWORDINTREE(0x58400000,0x00000000)}}, {VT_exponent,22,0x3a909c,{DOUBLEWITHTWODWORDINTREE(0x58500000,0x00000000)}}, {VT_exponent,22,0x3a909d,{DOUBLEWITHTWODWORDINTREE(0x58600000,0x00000000)}}, {VT_exponent,22,0x3a909e,{DOUBLEWITHTWODWORDINTREE(0x58700000,0x00000000)}}, {VT_exponent,22,0x3a909f,{DOUBLEWITHTWODWORDINTREE(0x58800000,0x00000000)}}, {VT_exponent,22,0x3a90a0,{DOUBLEWITHTWODWORDINTREE(0x58900000,0x00000000)}}, {VT_exponent,22,0x3a90a1,{DOUBLEWITHTWODWORDINTREE(0x58a00000,0x00000000)}}, {VT_exponent,22,0x3a90a2,{DOUBLEWITHTWODWORDINTREE(0x58b00000,0x00000000)}}, {VT_exponent,22,0x3a90a3,{DOUBLEWITHTWODWORDINTREE(0x58c00000,0x00000000)}}, {VT_exponent,22,0x3a90a4,{DOUBLEWITHTWODWORDINTREE(0x58d00000,0x00000000)}}, {VT_exponent,22,0x3a90a5,{DOUBLEWITHTWODWORDINTREE(0x58e00000,0x00000000)}}, {VT_exponent,22,0x3a90a6,{DOUBLEWITHTWODWORDINTREE(0x58f00000,0x00000000)}}, {VT_exponent,22,0x3a90a7,{DOUBLEWITHTWODWORDINTREE(0x59000000,0x00000000)}}, {VT_exponent,22,0x3a90a8,{DOUBLEWITHTWODWORDINTREE(0x59100000,0x00000000)}}, {VT_exponent,22,0x3a90a9,{DOUBLEWITHTWODWORDINTREE(0x59200000,0x00000000)}}, {VT_exponent,22,0x3a90aa,{DOUBLEWITHTWODWORDINTREE(0x59300000,0x00000000)}}, {VT_exponent,22,0x3a90ab,{DOUBLEWITHTWODWORDINTREE(0x59400000,0x00000000)}}, {VT_exponent,22,0x3a90ac,{DOUBLEWITHTWODWORDINTREE(0x59500000,0x00000000)}}, {VT_exponent,22,0x3a90ad,{DOUBLEWITHTWODWORDINTREE(0x59600000,0x00000000)}}, {VT_exponent,22,0x3a90ae,{DOUBLEWITHTWODWORDINTREE(0x59700000,0x00000000)}}, {VT_exponent,22,0x3a90af,{DOUBLEWITHTWODWORDINTREE(0x59800000,0x00000000)}}, {VT_exponent,22,0x3a90b0,{DOUBLEWITHTWODWORDINTREE(0x59900000,0x00000000)}}, {VT_exponent,22,0x3a90b1,{DOUBLEWITHTWODWORDINTREE(0x59a00000,0x00000000)}}, {VT_exponent,22,0x3a90b2,{DOUBLEWITHTWODWORDINTREE(0x59b00000,0x00000000)}}, {VT_exponent,22,0x3a90b3,{DOUBLEWITHTWODWORDINTREE(0x59c00000,0x00000000)}}, {VT_exponent,22,0x3a90b4,{DOUBLEWITHTWODWORDINTREE(0x59d00000,0x00000000)}}, {VT_exponent,22,0x3a90b5,{DOUBLEWITHTWODWORDINTREE(0x59e00000,0x00000000)}}, {VT_exponent,22,0x3a90b6,{DOUBLEWITHTWODWORDINTREE(0x59f00000,0x00000000)}}, {VT_exponent,22,0x3a90b7,{DOUBLEWITHTWODWORDINTREE(0x5a000000,0x00000000)}}, {VT_exponent,22,0x3a90b8,{DOUBLEWITHTWODWORDINTREE(0x5a100000,0x00000000)}}, {VT_exponent,22,0x3a90b9,{DOUBLEWITHTWODWORDINTREE(0x5a200000,0x00000000)}}, {VT_exponent,22,0x3a90ba,{DOUBLEWITHTWODWORDINTREE(0x5a300000,0x00000000)}}, {VT_exponent,22,0x3a90bb,{DOUBLEWITHTWODWORDINTREE(0x5a400000,0x00000000)}}, {VT_exponent,22,0x3a90bc,{DOUBLEWITHTWODWORDINTREE(0x5a500000,0x00000000)}}, {VT_exponent,22,0x3a90bd,{DOUBLEWITHTWODWORDINTREE(0x5a600000,0x00000000)}}, {VT_exponent,22,0x3a90be,{DOUBLEWITHTWODWORDINTREE(0x5a700000,0x00000000)}}, {VT_exponent,22,0x3a90bf,{DOUBLEWITHTWODWORDINTREE(0x5a800000,0x00000000)}}, {VT_exponent,22,0x3a90c0,{DOUBLEWITHTWODWORDINTREE(0x5a900000,0x00000000)}}, {VT_exponent,22,0x3a90c1,{DOUBLEWITHTWODWORDINTREE(0x5aa00000,0x00000000)}}, {VT_exponent,22,0x3a90c2,{DOUBLEWITHTWODWORDINTREE(0x5ab00000,0x00000000)}}, {VT_exponent,22,0x3a90c3,{DOUBLEWITHTWODWORDINTREE(0x5ac00000,0x00000000)}}, {VT_exponent,22,0x3a90c4,{DOUBLEWITHTWODWORDINTREE(0x5ad00000,0x00000000)}}, {VT_exponent,22,0x3a90c5,{DOUBLEWITHTWODWORDINTREE(0x5ae00000,0x00000000)}}, {VT_exponent,22,0x3a90c6,{DOUBLEWITHTWODWORDINTREE(0x5af00000,0x00000000)}}, {VT_exponent,22,0x3a90c7,{DOUBLEWITHTWODWORDINTREE(0x5b000000,0x00000000)}}, {VT_exponent,22,0x3a90c8,{DOUBLEWITHTWODWORDINTREE(0x5b100000,0x00000000)}}, {VT_exponent,22,0x3a90c9,{DOUBLEWITHTWODWORDINTREE(0x5b200000,0x00000000)}}, {VT_exponent,22,0x3a90ca,{DOUBLEWITHTWODWORDINTREE(0x5b300000,0x00000000)}}, {VT_exponent,22,0x3a90cb,{DOUBLEWITHTWODWORDINTREE(0x5b400000,0x00000000)}}, {VT_exponent,22,0x3a90cc,{DOUBLEWITHTWODWORDINTREE(0x5b500000,0x00000000)}}, {VT_exponent,22,0x3a90cd,{DOUBLEWITHTWODWORDINTREE(0x5b600000,0x00000000)}}, {VT_exponent,22,0x3a90ce,{DOUBLEWITHTWODWORDINTREE(0x5b700000,0x00000000)}}, {VT_exponent,22,0x3a90cf,{DOUBLEWITHTWODWORDINTREE(0x5b800000,0x00000000)}}, {VT_exponent,22,0x3a90d0,{DOUBLEWITHTWODWORDINTREE(0x5b900000,0x00000000)}}, {VT_exponent,22,0x3a90d1,{DOUBLEWITHTWODWORDINTREE(0x5ba00000,0x00000000)}}, {VT_exponent,22,0x3a90d2,{DOUBLEWITHTWODWORDINTREE(0x5bb00000,0x00000000)}}, {VT_exponent,22,0x3a90d3,{DOUBLEWITHTWODWORDINTREE(0x5bc00000,0x00000000)}}, {VT_exponent,22,0x3a90d4,{DOUBLEWITHTWODWORDINTREE(0x5bd00000,0x00000000)}}, {VT_exponent,22,0x3a90d5,{DOUBLEWITHTWODWORDINTREE(0x5be00000,0x00000000)}}, {VT_exponent,22,0x3a90d6,{DOUBLEWITHTWODWORDINTREE(0x5bf00000,0x00000000)}}, {VT_exponent,22,0x3a90d7,{DOUBLEWITHTWODWORDINTREE(0x5c000000,0x00000000)}}, {VT_exponent,22,0x3a90d8,{DOUBLEWITHTWODWORDINTREE(0x5c100000,0x00000000)}}, {VT_exponent,22,0x3a90d9,{DOUBLEWITHTWODWORDINTREE(0x5c200000,0x00000000)}}, {VT_exponent,22,0x3a90da,{DOUBLEWITHTWODWORDINTREE(0x5c300000,0x00000000)}}, {VT_exponent,22,0x3a90db,{DOUBLEWITHTWODWORDINTREE(0x5c400000,0x00000000)}}, {VT_exponent,22,0x3a90dc,{DOUBLEWITHTWODWORDINTREE(0x5c500000,0x00000000)}}, {VT_exponent,22,0x3a90dd,{DOUBLEWITHTWODWORDINTREE(0x5c600000,0x00000000)}}, {VT_exponent,22,0x3a90de,{DOUBLEWITHTWODWORDINTREE(0x5c700000,0x00000000)}}, {VT_exponent,22,0x3a90df,{DOUBLEWITHTWODWORDINTREE(0x5c800000,0x00000000)}}, {VT_exponent,22,0x3a90e0,{DOUBLEWITHTWODWORDINTREE(0x5c900000,0x00000000)}}, {VT_exponent,22,0x3a90e1,{DOUBLEWITHTWODWORDINTREE(0x5ca00000,0x00000000)}}, {VT_exponent,22,0x3a90e2,{DOUBLEWITHTWODWORDINTREE(0x5cb00000,0x00000000)}}, {VT_exponent,22,0x3a90e3,{DOUBLEWITHTWODWORDINTREE(0x5cc00000,0x00000000)}}, {VT_exponent,22,0x3a90e4,{DOUBLEWITHTWODWORDINTREE(0x5cd00000,0x00000000)}}, {VT_exponent,22,0x3a90e5,{DOUBLEWITHTWODWORDINTREE(0x5ce00000,0x00000000)}}, {VT_exponent,22,0x3a90e6,{DOUBLEWITHTWODWORDINTREE(0x5cf00000,0x00000000)}}, {VT_exponent,22,0x3a90e7,{DOUBLEWITHTWODWORDINTREE(0x5d000000,0x00000000)}}, {VT_exponent,22,0x3a90e8,{DOUBLEWITHTWODWORDINTREE(0x5d100000,0x00000000)}}, {VT_exponent,22,0x3a90e9,{DOUBLEWITHTWODWORDINTREE(0x5d200000,0x00000000)}}, {VT_exponent,22,0x3a90ea,{DOUBLEWITHTWODWORDINTREE(0x5d300000,0x00000000)}}, {VT_exponent,22,0x3a90eb,{DOUBLEWITHTWODWORDINTREE(0x5d400000,0x00000000)}}, {VT_exponent,22,0x3a90ec,{DOUBLEWITHTWODWORDINTREE(0x5d500000,0x00000000)}}, {VT_exponent,22,0x3a90ed,{DOUBLEWITHTWODWORDINTREE(0x5d600000,0x00000000)}}, {VT_exponent,22,0x3a90ee,{DOUBLEWITHTWODWORDINTREE(0x5d700000,0x00000000)}}, {VT_exponent,22,0x3a90ef,{DOUBLEWITHTWODWORDINTREE(0x5d800000,0x00000000)}}, {VT_exponent,22,0x3a90f0,{DOUBLEWITHTWODWORDINTREE(0x5d900000,0x00000000)}}, {VT_exponent,22,0x3a90f1,{DOUBLEWITHTWODWORDINTREE(0x5da00000,0x00000000)}}, {VT_exponent,22,0x3a90f2,{DOUBLEWITHTWODWORDINTREE(0x5db00000,0x00000000)}}, {VT_exponent,22,0x3a90f3,{DOUBLEWITHTWODWORDINTREE(0x5dc00000,0x00000000)}}, {VT_exponent,22,0x3a90f4,{DOUBLEWITHTWODWORDINTREE(0x5dd00000,0x00000000)}}, {VT_exponent,22,0x3a90f5,{DOUBLEWITHTWODWORDINTREE(0x5de00000,0x00000000)}}, {VT_exponent,22,0x3a90f6,{DOUBLEWITHTWODWORDINTREE(0x5df00000,0x00000000)}}, {VT_exponent,22,0x3a90f7,{DOUBLEWITHTWODWORDINTREE(0x5e000000,0x00000000)}}, {VT_exponent,22,0x3a90f8,{DOUBLEWITHTWODWORDINTREE(0x5e100000,0x00000000)}}, {VT_exponent,22,0x3a90f9,{DOUBLEWITHTWODWORDINTREE(0x5e200000,0x00000000)}}, {VT_exponent,22,0x3a90fa,{DOUBLEWITHTWODWORDINTREE(0x5e300000,0x00000000)}}, {VT_exponent,22,0x3a90fb,{DOUBLEWITHTWODWORDINTREE(0x5e400000,0x00000000)}}, {VT_exponent,22,0x3a90fc,{DOUBLEWITHTWODWORDINTREE(0x5e500000,0x00000000)}}, {VT_exponent,22,0x3a90fd,{DOUBLEWITHTWODWORDINTREE(0x5e600000,0x00000000)}}, {VT_exponent,22,0x3a90fe,{DOUBLEWITHTWODWORDINTREE(0x5e700000,0x00000000)}}, {VT_exponent,22,0x3a90ff,{DOUBLEWITHTWODWORDINTREE(0x5e800000,0x00000000)}}, {VT_exponent,22,0x3a9100,{DOUBLEWITHTWODWORDINTREE(0x5e900000,0x00000000)}}, {VT_exponent,22,0x3a9101,{DOUBLEWITHTWODWORDINTREE(0x5ea00000,0x00000000)}}, {VT_exponent,22,0x3a9102,{DOUBLEWITHTWODWORDINTREE(0x5eb00000,0x00000000)}}, {VT_exponent,22,0x3a9103,{DOUBLEWITHTWODWORDINTREE(0x5ec00000,0x00000000)}}, {VT_exponent,22,0x3a9104,{DOUBLEWITHTWODWORDINTREE(0x5ed00000,0x00000000)}}, {VT_exponent,22,0x3a9105,{DOUBLEWITHTWODWORDINTREE(0x5ee00000,0x00000000)}}, {VT_exponent,22,0x3a9106,{DOUBLEWITHTWODWORDINTREE(0x5ef00000,0x00000000)}}, {VT_exponent,22,0x3a9107,{DOUBLEWITHTWODWORDINTREE(0x5f000000,0x00000000)}}, {VT_exponent,22,0x3a9108,{DOUBLEWITHTWODWORDINTREE(0x5f100000,0x00000000)}}, {VT_exponent,22,0x3a9109,{DOUBLEWITHTWODWORDINTREE(0x5f200000,0x00000000)}}, {VT_exponent,22,0x3a910a,{DOUBLEWITHTWODWORDINTREE(0x5f300000,0x00000000)}}, {VT_exponent,22,0x3a910b,{DOUBLEWITHTWODWORDINTREE(0x5f400000,0x00000000)}}, {VT_exponent,22,0x3a910c,{DOUBLEWITHTWODWORDINTREE(0x5f500000,0x00000000)}}, {VT_exponent,22,0x3a910d,{DOUBLEWITHTWODWORDINTREE(0x5f600000,0x00000000)}}, {VT_exponent,22,0x3a910e,{DOUBLEWITHTWODWORDINTREE(0x5f700000,0x00000000)}}, {VT_exponent,22,0x3a910f,{DOUBLEWITHTWODWORDINTREE(0x5f800000,0x00000000)}}, {VT_exponent,22,0x3a9110,{DOUBLEWITHTWODWORDINTREE(0x5f900000,0x00000000)}}, {VT_exponent,22,0x3a9111,{DOUBLEWITHTWODWORDINTREE(0x5fa00000,0x00000000)}}, {VT_exponent,22,0x3a9112,{DOUBLEWITHTWODWORDINTREE(0x5fb00000,0x00000000)}}, {VT_exponent,22,0x3a9113,{DOUBLEWITHTWODWORDINTREE(0x5fc00000,0x00000000)}}, {VT_exponent,22,0x3a9114,{DOUBLEWITHTWODWORDINTREE(0x5fd00000,0x00000000)}}, {VT_exponent,22,0x3a9115,{DOUBLEWITHTWODWORDINTREE(0x5fe00000,0x00000000)}}, {VT_exponent,22,0x3a9116,{DOUBLEWITHTWODWORDINTREE(0x5ff00000,0x00000000)}}, {VT_exponent,22,0x3a9117,{DOUBLEWITHTWODWORDINTREE(0x60000000,0x00000000)}}, {VT_exponent,22,0x3a9118,{DOUBLEWITHTWODWORDINTREE(0x60100000,0x00000000)}}, {VT_exponent,22,0x3a9119,{DOUBLEWITHTWODWORDINTREE(0x60200000,0x00000000)}}, {VT_exponent,22,0x3a911a,{DOUBLEWITHTWODWORDINTREE(0x60300000,0x00000000)}}, {VT_exponent,22,0x3a911b,{DOUBLEWITHTWODWORDINTREE(0x60400000,0x00000000)}}, {VT_exponent,22,0x3a911c,{DOUBLEWITHTWODWORDINTREE(0x60500000,0x00000000)}}, {VT_exponent,22,0x3a911d,{DOUBLEWITHTWODWORDINTREE(0x60600000,0x00000000)}}, {VT_exponent,22,0x3a911e,{DOUBLEWITHTWODWORDINTREE(0x60700000,0x00000000)}}, {VT_exponent,22,0x3a911f,{DOUBLEWITHTWODWORDINTREE(0x60800000,0x00000000)}}, {VT_exponent,22,0x3a9120,{DOUBLEWITHTWODWORDINTREE(0x60900000,0x00000000)}}, {VT_exponent,22,0x3a9121,{DOUBLEWITHTWODWORDINTREE(0x60a00000,0x00000000)}}, {VT_exponent,22,0x3a9122,{DOUBLEWITHTWODWORDINTREE(0x60b00000,0x00000000)}}, {VT_exponent,22,0x3a9123,{DOUBLEWITHTWODWORDINTREE(0x60c00000,0x00000000)}}, {VT_exponent,22,0x3a9124,{DOUBLEWITHTWODWORDINTREE(0x60d00000,0x00000000)}}, {VT_exponent,22,0x3a9125,{DOUBLEWITHTWODWORDINTREE(0x60e00000,0x00000000)}}, {VT_exponent,22,0x3a9126,{DOUBLEWITHTWODWORDINTREE(0x60f00000,0x00000000)}}, {VT_exponent,22,0x3a9127,{DOUBLEWITHTWODWORDINTREE(0x61000000,0x00000000)}}, {VT_exponent,22,0x3a9128,{DOUBLEWITHTWODWORDINTREE(0x61100000,0x00000000)}}, {VT_exponent,22,0x3a9129,{DOUBLEWITHTWODWORDINTREE(0x61200000,0x00000000)}}, {VT_exponent,22,0x3a912a,{DOUBLEWITHTWODWORDINTREE(0x61300000,0x00000000)}}, {VT_exponent,22,0x3a912b,{DOUBLEWITHTWODWORDINTREE(0x61400000,0x00000000)}}, {VT_exponent,22,0x3a912c,{DOUBLEWITHTWODWORDINTREE(0x61500000,0x00000000)}}, {VT_exponent,22,0x3a912d,{DOUBLEWITHTWODWORDINTREE(0x61600000,0x00000000)}}, {VT_exponent,22,0x3a912e,{DOUBLEWITHTWODWORDINTREE(0x61700000,0x00000000)}}, {VT_exponent,22,0x3a912f,{DOUBLEWITHTWODWORDINTREE(0x61800000,0x00000000)}}, {VT_exponent,22,0x3a9130,{DOUBLEWITHTWODWORDINTREE(0x61900000,0x00000000)}}, {VT_exponent,22,0x3a9131,{DOUBLEWITHTWODWORDINTREE(0x61a00000,0x00000000)}}, {VT_exponent,22,0x3a9132,{DOUBLEWITHTWODWORDINTREE(0x61b00000,0x00000000)}}, {VT_exponent,22,0x3a9133,{DOUBLEWITHTWODWORDINTREE(0x61c00000,0x00000000)}}, {VT_exponent,22,0x3a9134,{DOUBLEWITHTWODWORDINTREE(0x61d00000,0x00000000)}}, {VT_exponent,22,0x3a9135,{DOUBLEWITHTWODWORDINTREE(0x61e00000,0x00000000)}}, {VT_exponent,22,0x3a9136,{DOUBLEWITHTWODWORDINTREE(0x61f00000,0x00000000)}}, {VT_exponent,22,0x3a9137,{DOUBLEWITHTWODWORDINTREE(0x62000000,0x00000000)}}, {VT_exponent,22,0x3a9138,{DOUBLEWITHTWODWORDINTREE(0x62100000,0x00000000)}}, {VT_exponent,22,0x3a9139,{DOUBLEWITHTWODWORDINTREE(0x62200000,0x00000000)}}, {VT_exponent,22,0x3a913a,{DOUBLEWITHTWODWORDINTREE(0x62300000,0x00000000)}}, {VT_exponent,22,0x3a913b,{DOUBLEWITHTWODWORDINTREE(0x62400000,0x00000000)}}, {VT_exponent,22,0x3a913c,{DOUBLEWITHTWODWORDINTREE(0x62500000,0x00000000)}}, {VT_exponent,22,0x3a913d,{DOUBLEWITHTWODWORDINTREE(0x62600000,0x00000000)}}, {VT_exponent,22,0x3a913e,{DOUBLEWITHTWODWORDINTREE(0x62700000,0x00000000)}}, {VT_exponent,22,0x3a913f,{DOUBLEWITHTWODWORDINTREE(0x62800000,0x00000000)}}, {VT_exponent,22,0x3a9140,{DOUBLEWITHTWODWORDINTREE(0x62900000,0x00000000)}}, {VT_exponent,22,0x3a9141,{DOUBLEWITHTWODWORDINTREE(0x62a00000,0x00000000)}}, {VT_exponent,22,0x3a9142,{DOUBLEWITHTWODWORDINTREE(0x62b00000,0x00000000)}}, {VT_exponent,22,0x3a9143,{DOUBLEWITHTWODWORDINTREE(0x62c00000,0x00000000)}}, {VT_exponent,22,0x3a9144,{DOUBLEWITHTWODWORDINTREE(0x62d00000,0x00000000)}}, {VT_exponent,22,0x3a9145,{DOUBLEWITHTWODWORDINTREE(0x62e00000,0x00000000)}}, {VT_exponent,22,0x3a9146,{DOUBLEWITHTWODWORDINTREE(0x62f00000,0x00000000)}}, {VT_exponent,22,0x3a9147,{DOUBLEWITHTWODWORDINTREE(0x63000000,0x00000000)}}, {VT_exponent,22,0x3a9148,{DOUBLEWITHTWODWORDINTREE(0x63100000,0x00000000)}}, {VT_exponent,22,0x3a9149,{DOUBLEWITHTWODWORDINTREE(0x63200000,0x00000000)}}, {VT_exponent,22,0x3a914a,{DOUBLEWITHTWODWORDINTREE(0x63300000,0x00000000)}}, {VT_exponent,22,0x3a914b,{DOUBLEWITHTWODWORDINTREE(0x63400000,0x00000000)}}, {VT_exponent,22,0x3a914c,{DOUBLEWITHTWODWORDINTREE(0x63500000,0x00000000)}}, {VT_exponent,22,0x3a914d,{DOUBLEWITHTWODWORDINTREE(0x63600000,0x00000000)}}, {VT_exponent,22,0x3a914e,{DOUBLEWITHTWODWORDINTREE(0x63700000,0x00000000)}}, {VT_exponent,22,0x3a914f,{DOUBLEWITHTWODWORDINTREE(0x63800000,0x00000000)}}, {VT_exponent,22,0x3a9150,{DOUBLEWITHTWODWORDINTREE(0x63900000,0x00000000)}}, {VT_exponent,22,0x3a9151,{DOUBLEWITHTWODWORDINTREE(0x63a00000,0x00000000)}}, {VT_exponent,22,0x3a9152,{DOUBLEWITHTWODWORDINTREE(0x63b00000,0x00000000)}}, {VT_exponent,22,0x3a9153,{DOUBLEWITHTWODWORDINTREE(0x63c00000,0x00000000)}}, {VT_exponent,22,0x3a9154,{DOUBLEWITHTWODWORDINTREE(0x63d00000,0x00000000)}}, {VT_exponent,22,0x3a9155,{DOUBLEWITHTWODWORDINTREE(0x63e00000,0x00000000)}}, {VT_exponent,22,0x3a9156,{DOUBLEWITHTWODWORDINTREE(0x63f00000,0x00000000)}}, {VT_exponent,22,0x3a9157,{DOUBLEWITHTWODWORDINTREE(0x64000000,0x00000000)}}, {VT_exponent,22,0x3a9158,{DOUBLEWITHTWODWORDINTREE(0x64100000,0x00000000)}}, {VT_exponent,22,0x3a9159,{DOUBLEWITHTWODWORDINTREE(0x64200000,0x00000000)}}, {VT_exponent,22,0x3a915a,{DOUBLEWITHTWODWORDINTREE(0x64300000,0x00000000)}}, {VT_exponent,22,0x3a915b,{DOUBLEWITHTWODWORDINTREE(0x64400000,0x00000000)}}, {VT_exponent,22,0x3a915c,{DOUBLEWITHTWODWORDINTREE(0x64500000,0x00000000)}}, {VT_exponent,22,0x3a915d,{DOUBLEWITHTWODWORDINTREE(0x64600000,0x00000000)}}, {VT_exponent,22,0x3a915e,{DOUBLEWITHTWODWORDINTREE(0x64700000,0x00000000)}}, {VT_exponent,22,0x3a915f,{DOUBLEWITHTWODWORDINTREE(0x64800000,0x00000000)}}, {VT_exponent,22,0x3a9160,{DOUBLEWITHTWODWORDINTREE(0x64900000,0x00000000)}}, {VT_exponent,22,0x3a9161,{DOUBLEWITHTWODWORDINTREE(0x64a00000,0x00000000)}}, {VT_exponent,22,0x3a9162,{DOUBLEWITHTWODWORDINTREE(0x64b00000,0x00000000)}}, {VT_exponent,22,0x3a9163,{DOUBLEWITHTWODWORDINTREE(0x64c00000,0x00000000)}}, {VT_exponent,22,0x3a9164,{DOUBLEWITHTWODWORDINTREE(0x64d00000,0x00000000)}}, {VT_exponent,22,0x3a9165,{DOUBLEWITHTWODWORDINTREE(0x64e00000,0x00000000)}}, {VT_exponent,22,0x3a9166,{DOUBLEWITHTWODWORDINTREE(0x64f00000,0x00000000)}}, {VT_exponent,22,0x3a9167,{DOUBLEWITHTWODWORDINTREE(0x65000000,0x00000000)}}, {VT_exponent,22,0x3a9168,{DOUBLEWITHTWODWORDINTREE(0x65100000,0x00000000)}}, {VT_exponent,22,0x3a9169,{DOUBLEWITHTWODWORDINTREE(0x65200000,0x00000000)}}, {VT_exponent,22,0x3a916a,{DOUBLEWITHTWODWORDINTREE(0x65300000,0x00000000)}}, {VT_exponent,22,0x3a916b,{DOUBLEWITHTWODWORDINTREE(0x65400000,0x00000000)}}, {VT_exponent,22,0x3a916c,{DOUBLEWITHTWODWORDINTREE(0x65500000,0x00000000)}}, {VT_exponent,22,0x3a916d,{DOUBLEWITHTWODWORDINTREE(0x65600000,0x00000000)}}, {VT_exponent,22,0x3a916e,{DOUBLEWITHTWODWORDINTREE(0x65700000,0x00000000)}}, {VT_exponent,22,0x3a916f,{DOUBLEWITHTWODWORDINTREE(0x65800000,0x00000000)}}, {VT_exponent,22,0x3a9170,{DOUBLEWITHTWODWORDINTREE(0x65900000,0x00000000)}}, {VT_exponent,22,0x3a9171,{DOUBLEWITHTWODWORDINTREE(0x65a00000,0x00000000)}}, {VT_exponent,22,0x3a9172,{DOUBLEWITHTWODWORDINTREE(0x65b00000,0x00000000)}}, {VT_exponent,22,0x3a9173,{DOUBLEWITHTWODWORDINTREE(0x65c00000,0x00000000)}}, {VT_exponent,22,0x3a9174,{DOUBLEWITHTWODWORDINTREE(0x65d00000,0x00000000)}}, {VT_exponent,22,0x3a9175,{DOUBLEWITHTWODWORDINTREE(0x65e00000,0x00000000)}}, {VT_exponent,22,0x3a9176,{DOUBLEWITHTWODWORDINTREE(0x65f00000,0x00000000)}}, {VT_exponent,22,0x3a9177,{DOUBLEWITHTWODWORDINTREE(0x66000000,0x00000000)}}, {VT_exponent,22,0x3a9178,{DOUBLEWITHTWODWORDINTREE(0x66100000,0x00000000)}}, {VT_exponent,22,0x3a9179,{DOUBLEWITHTWODWORDINTREE(0x66200000,0x00000000)}}, {VT_exponent,22,0x3a917a,{DOUBLEWITHTWODWORDINTREE(0x66300000,0x00000000)}}, {VT_exponent,22,0x3a917b,{DOUBLEWITHTWODWORDINTREE(0x66400000,0x00000000)}}, {VT_exponent,22,0x3a917c,{DOUBLEWITHTWODWORDINTREE(0x66500000,0x00000000)}}, {VT_exponent,22,0x3a917d,{DOUBLEWITHTWODWORDINTREE(0x66600000,0x00000000)}}, {VT_exponent,22,0x3a917e,{DOUBLEWITHTWODWORDINTREE(0x66700000,0x00000000)}}, {VT_exponent,22,0x3a917f,{DOUBLEWITHTWODWORDINTREE(0x66800000,0x00000000)}}, {VT_exponent,22,0x3a9180,{DOUBLEWITHTWODWORDINTREE(0x66900000,0x00000000)}}, {VT_exponent,22,0x3a9181,{DOUBLEWITHTWODWORDINTREE(0x66a00000,0x00000000)}}, {VT_exponent,22,0x3a9182,{DOUBLEWITHTWODWORDINTREE(0x66b00000,0x00000000)}}, {VT_exponent,22,0x3a9183,{DOUBLEWITHTWODWORDINTREE(0x66c00000,0x00000000)}}, {VT_exponent,22,0x3a9184,{DOUBLEWITHTWODWORDINTREE(0x66d00000,0x00000000)}}, {VT_exponent,22,0x3a9185,{DOUBLEWITHTWODWORDINTREE(0x66e00000,0x00000000)}}, {VT_exponent,22,0x3a9186,{DOUBLEWITHTWODWORDINTREE(0x66f00000,0x00000000)}}, {VT_exponent,22,0x3a9187,{DOUBLEWITHTWODWORDINTREE(0x67000000,0x00000000)}}, {VT_exponent,22,0x3a9188,{DOUBLEWITHTWODWORDINTREE(0x67100000,0x00000000)}}, {VT_exponent,22,0x3a9189,{DOUBLEWITHTWODWORDINTREE(0x67200000,0x00000000)}}, {VT_exponent,22,0x3a918a,{DOUBLEWITHTWODWORDINTREE(0x67300000,0x00000000)}}, {VT_exponent,22,0x3a918b,{DOUBLEWITHTWODWORDINTREE(0x67400000,0x00000000)}}, {VT_exponent,22,0x3a918c,{DOUBLEWITHTWODWORDINTREE(0x67500000,0x00000000)}}, {VT_exponent,22,0x3a918d,{DOUBLEWITHTWODWORDINTREE(0x67600000,0x00000000)}}, {VT_exponent,22,0x3a918e,{DOUBLEWITHTWODWORDINTREE(0x67700000,0x00000000)}}, {VT_exponent,22,0x3a918f,{DOUBLEWITHTWODWORDINTREE(0x67800000,0x00000000)}}, {VT_exponent,22,0x3a9190,{DOUBLEWITHTWODWORDINTREE(0x67900000,0x00000000)}}, {VT_exponent,22,0x3a9191,{DOUBLEWITHTWODWORDINTREE(0x67a00000,0x00000000)}}, {VT_exponent,22,0x3a9192,{DOUBLEWITHTWODWORDINTREE(0x67b00000,0x00000000)}}, {VT_exponent,22,0x3a9193,{DOUBLEWITHTWODWORDINTREE(0x67c00000,0x00000000)}}, {VT_exponent,22,0x3a9194,{DOUBLEWITHTWODWORDINTREE(0x67d00000,0x00000000)}}, {VT_exponent,22,0x3a9195,{DOUBLEWITHTWODWORDINTREE(0x67e00000,0x00000000)}}, {VT_exponent,22,0x3a9196,{DOUBLEWITHTWODWORDINTREE(0x67f00000,0x00000000)}}, {VT_exponent,22,0x3a9197,{DOUBLEWITHTWODWORDINTREE(0x68000000,0x00000000)}}, {VT_exponent,22,0x3a9198,{DOUBLEWITHTWODWORDINTREE(0x68100000,0x00000000)}}, {VT_exponent,22,0x3a9199,{DOUBLEWITHTWODWORDINTREE(0x68200000,0x00000000)}}, {VT_exponent,22,0x3a919a,{DOUBLEWITHTWODWORDINTREE(0x68300000,0x00000000)}}, {VT_exponent,22,0x3a919b,{DOUBLEWITHTWODWORDINTREE(0x68400000,0x00000000)}}, {VT_exponent,22,0x3a919c,{DOUBLEWITHTWODWORDINTREE(0x68500000,0x00000000)}}, {VT_exponent,22,0x3a919d,{DOUBLEWITHTWODWORDINTREE(0x68600000,0x00000000)}}, {VT_exponent,22,0x3a919e,{DOUBLEWITHTWODWORDINTREE(0x68700000,0x00000000)}}, {VT_exponent,22,0x3a919f,{DOUBLEWITHTWODWORDINTREE(0x68800000,0x00000000)}}, {VT_exponent,22,0x3a91a0,{DOUBLEWITHTWODWORDINTREE(0x68900000,0x00000000)}}, {VT_exponent,22,0x3a91a1,{DOUBLEWITHTWODWORDINTREE(0x68a00000,0x00000000)}}, {VT_exponent,22,0x3a91a2,{DOUBLEWITHTWODWORDINTREE(0x68b00000,0x00000000)}}, {VT_exponent,22,0x3a91a3,{DOUBLEWITHTWODWORDINTREE(0x68c00000,0x00000000)}}, {VT_exponent,22,0x3a91a4,{DOUBLEWITHTWODWORDINTREE(0x68d00000,0x00000000)}}, {VT_exponent,22,0x3a91a5,{DOUBLEWITHTWODWORDINTREE(0x68e00000,0x00000000)}}, {VT_exponent,22,0x3a91a6,{DOUBLEWITHTWODWORDINTREE(0x68f00000,0x00000000)}}, {VT_exponent,22,0x3a91a7,{DOUBLEWITHTWODWORDINTREE(0x69000000,0x00000000)}}, {VT_exponent,22,0x3a91a8,{DOUBLEWITHTWODWORDINTREE(0x69100000,0x00000000)}}, {VT_exponent,22,0x3a91a9,{DOUBLEWITHTWODWORDINTREE(0x69200000,0x00000000)}}, {VT_exponent,22,0x3a91aa,{DOUBLEWITHTWODWORDINTREE(0x69300000,0x00000000)}}, {VT_exponent,22,0x3a91ab,{DOUBLEWITHTWODWORDINTREE(0x69400000,0x00000000)}}, {VT_exponent,22,0x3a91ac,{DOUBLEWITHTWODWORDINTREE(0x69500000,0x00000000)}}, {VT_exponent,22,0x3a91ad,{DOUBLEWITHTWODWORDINTREE(0x69600000,0x00000000)}}, {VT_exponent,22,0x3a91ae,{DOUBLEWITHTWODWORDINTREE(0x69700000,0x00000000)}}, {VT_exponent,22,0x3a91af,{DOUBLEWITHTWODWORDINTREE(0x69800000,0x00000000)}}, {VT_exponent,22,0x3a91b0,{DOUBLEWITHTWODWORDINTREE(0x69900000,0x00000000)}}, {VT_exponent,22,0x3a91b1,{DOUBLEWITHTWODWORDINTREE(0x69a00000,0x00000000)}}, {VT_exponent,22,0x3a91b2,{DOUBLEWITHTWODWORDINTREE(0x69b00000,0x00000000)}}, {VT_exponent,22,0x3a91b3,{DOUBLEWITHTWODWORDINTREE(0x69c00000,0x00000000)}}, {VT_exponent,22,0x3a91b4,{DOUBLEWITHTWODWORDINTREE(0x69d00000,0x00000000)}}, {VT_exponent,22,0x3a91b5,{DOUBLEWITHTWODWORDINTREE(0x69e00000,0x00000000)}}, {VT_exponent,22,0x3a91b6,{DOUBLEWITHTWODWORDINTREE(0x69f00000,0x00000000)}}, {VT_exponent,22,0x3a91b7,{DOUBLEWITHTWODWORDINTREE(0x6a000000,0x00000000)}}, {VT_exponent,22,0x3a91b8,{DOUBLEWITHTWODWORDINTREE(0x6a100000,0x00000000)}}, {VT_exponent,22,0x3a91b9,{DOUBLEWITHTWODWORDINTREE(0x6a200000,0x00000000)}}, {VT_exponent,22,0x3a91ba,{DOUBLEWITHTWODWORDINTREE(0x6a300000,0x00000000)}}, {VT_exponent,22,0x3a91bb,{DOUBLEWITHTWODWORDINTREE(0x6a400000,0x00000000)}}, {VT_exponent,22,0x3a91bc,{DOUBLEWITHTWODWORDINTREE(0x6a500000,0x00000000)}}, {VT_exponent,22,0x3a91bd,{DOUBLEWITHTWODWORDINTREE(0x6a600000,0x00000000)}}, {VT_exponent,22,0x3a91be,{DOUBLEWITHTWODWORDINTREE(0x6a700000,0x00000000)}}, {VT_exponent,22,0x3a91bf,{DOUBLEWITHTWODWORDINTREE(0x6a800000,0x00000000)}}, {VT_exponent,22,0x3a91c0,{DOUBLEWITHTWODWORDINTREE(0x6a900000,0x00000000)}}, {VT_exponent,22,0x3a91c1,{DOUBLEWITHTWODWORDINTREE(0x6aa00000,0x00000000)}}, {VT_exponent,22,0x3a91c2,{DOUBLEWITHTWODWORDINTREE(0x6ab00000,0x00000000)}}, {VT_exponent,22,0x3a91c3,{DOUBLEWITHTWODWORDINTREE(0x6ac00000,0x00000000)}}, {VT_exponent,22,0x3a91c4,{DOUBLEWITHTWODWORDINTREE(0x6ad00000,0x00000000)}}, {VT_exponent,22,0x3a91c5,{DOUBLEWITHTWODWORDINTREE(0x6ae00000,0x00000000)}}, {VT_exponent,22,0x3a91c6,{DOUBLEWITHTWODWORDINTREE(0x6af00000,0x00000000)}}, {VT_exponent,22,0x3a91c7,{DOUBLEWITHTWODWORDINTREE(0x6b000000,0x00000000)}}, {VT_exponent,22,0x3a91c8,{DOUBLEWITHTWODWORDINTREE(0x6b100000,0x00000000)}}, {VT_exponent,22,0x3a91c9,{DOUBLEWITHTWODWORDINTREE(0x6b200000,0x00000000)}}, {VT_exponent,22,0x3a91ca,{DOUBLEWITHTWODWORDINTREE(0x6b300000,0x00000000)}}, {VT_exponent,22,0x3a91cb,{DOUBLEWITHTWODWORDINTREE(0x6b400000,0x00000000)}}, {VT_exponent,22,0x3a91cc,{DOUBLEWITHTWODWORDINTREE(0x6b500000,0x00000000)}}, {VT_exponent,22,0x3a91cd,{DOUBLEWITHTWODWORDINTREE(0x6b600000,0x00000000)}}, {VT_exponent,22,0x3a91ce,{DOUBLEWITHTWODWORDINTREE(0x6b700000,0x00000000)}}, {VT_exponent,22,0x3a91cf,{DOUBLEWITHTWODWORDINTREE(0x6b800000,0x00000000)}}, {VT_exponent,22,0x3a91d0,{DOUBLEWITHTWODWORDINTREE(0x6b900000,0x00000000)}}, {VT_exponent,22,0x3a91d1,{DOUBLEWITHTWODWORDINTREE(0x6ba00000,0x00000000)}}, {VT_exponent,22,0x3a91d2,{DOUBLEWITHTWODWORDINTREE(0x6bb00000,0x00000000)}}, {VT_exponent,22,0x3a91d3,{DOUBLEWITHTWODWORDINTREE(0x6bc00000,0x00000000)}}, {VT_exponent,22,0x3a91d4,{DOUBLEWITHTWODWORDINTREE(0x6bd00000,0x00000000)}}, {VT_exponent,22,0x3a91d5,{DOUBLEWITHTWODWORDINTREE(0x6be00000,0x00000000)}}, {VT_exponent,22,0x3a91d6,{DOUBLEWITHTWODWORDINTREE(0x6bf00000,0x00000000)}}, {VT_exponent,22,0x3a91d7,{DOUBLEWITHTWODWORDINTREE(0x6c000000,0x00000000)}}, {VT_exponent,22,0x3a91d8,{DOUBLEWITHTWODWORDINTREE(0x6c100000,0x00000000)}}, {VT_exponent,22,0x3a91d9,{DOUBLEWITHTWODWORDINTREE(0x6c200000,0x00000000)}}, {VT_exponent,22,0x3a91da,{DOUBLEWITHTWODWORDINTREE(0x6c300000,0x00000000)}}, {VT_exponent,22,0x3a91db,{DOUBLEWITHTWODWORDINTREE(0x6c400000,0x00000000)}}, {VT_exponent,22,0x3a91dc,{DOUBLEWITHTWODWORDINTREE(0x6c500000,0x00000000)}}, {VT_exponent,22,0x3a91dd,{DOUBLEWITHTWODWORDINTREE(0x6c600000,0x00000000)}}, {VT_exponent,22,0x3a91de,{DOUBLEWITHTWODWORDINTREE(0x6c700000,0x00000000)}}, {VT_exponent,22,0x3a91df,{DOUBLEWITHTWODWORDINTREE(0x6c800000,0x00000000)}}, {VT_exponent,22,0x3a91e0,{DOUBLEWITHTWODWORDINTREE(0x6c900000,0x00000000)}}, {VT_exponent,22,0x3a91e1,{DOUBLEWITHTWODWORDINTREE(0x6ca00000,0x00000000)}}, {VT_exponent,22,0x3a91e2,{DOUBLEWITHTWODWORDINTREE(0x6cb00000,0x00000000)}}, {VT_exponent,22,0x3a91e3,{DOUBLEWITHTWODWORDINTREE(0x6cc00000,0x00000000)}}, {VT_exponent,22,0x3a91e4,{DOUBLEWITHTWODWORDINTREE(0x6cd00000,0x00000000)}}, {VT_exponent,22,0x3a91e5,{DOUBLEWITHTWODWORDINTREE(0x6ce00000,0x00000000)}}, {VT_exponent,22,0x3a91e6,{DOUBLEWITHTWODWORDINTREE(0x6cf00000,0x00000000)}}, {VT_exponent,22,0x3a91e7,{DOUBLEWITHTWODWORDINTREE(0x6d000000,0x00000000)}}, {VT_exponent,22,0x3a91e8,{DOUBLEWITHTWODWORDINTREE(0x6d100000,0x00000000)}}, {VT_exponent,22,0x3a91e9,{DOUBLEWITHTWODWORDINTREE(0x6d200000,0x00000000)}}, {VT_exponent,22,0x3a91ea,{DOUBLEWITHTWODWORDINTREE(0x6d300000,0x00000000)}}, {VT_exponent,22,0x3a91eb,{DOUBLEWITHTWODWORDINTREE(0x6d400000,0x00000000)}}, {VT_exponent,22,0x3a91ec,{DOUBLEWITHTWODWORDINTREE(0x6d500000,0x00000000)}}, {VT_exponent,22,0x3a91ed,{DOUBLEWITHTWODWORDINTREE(0x6d600000,0x00000000)}}, {VT_exponent,22,0x3a91ee,{DOUBLEWITHTWODWORDINTREE(0x6d700000,0x00000000)}}, {VT_exponent,22,0x3a91ef,{DOUBLEWITHTWODWORDINTREE(0x6d800000,0x00000000)}}, {VT_exponent,22,0x3a91f0,{DOUBLEWITHTWODWORDINTREE(0x6d900000,0x00000000)}}, {VT_exponent,22,0x3a91f1,{DOUBLEWITHTWODWORDINTREE(0x6da00000,0x00000000)}}, {VT_exponent,22,0x3a91f2,{DOUBLEWITHTWODWORDINTREE(0x6db00000,0x00000000)}}, {VT_exponent,22,0x3a91f3,{DOUBLEWITHTWODWORDINTREE(0x6dc00000,0x00000000)}}, {VT_exponent,22,0x3a91f4,{DOUBLEWITHTWODWORDINTREE(0x6dd00000,0x00000000)}}, {VT_exponent,22,0x3a91f5,{DOUBLEWITHTWODWORDINTREE(0x6de00000,0x00000000)}}, {VT_exponent,22,0x3a91f6,{DOUBLEWITHTWODWORDINTREE(0x6df00000,0x00000000)}}, {VT_exponent,22,0x3a91f7,{DOUBLEWITHTWODWORDINTREE(0x6e000000,0x00000000)}}, {VT_exponent,22,0x3a91f8,{DOUBLEWITHTWODWORDINTREE(0x6e100000,0x00000000)}}, {VT_exponent,22,0x3a91f9,{DOUBLEWITHTWODWORDINTREE(0x6e200000,0x00000000)}}, {VT_exponent,22,0x3a91fa,{DOUBLEWITHTWODWORDINTREE(0x6e300000,0x00000000)}}, {VT_exponent,22,0x3a91fb,{DOUBLEWITHTWODWORDINTREE(0x6e400000,0x00000000)}}, {VT_exponent,22,0x3a91fc,{DOUBLEWITHTWODWORDINTREE(0x6e500000,0x00000000)}}, {VT_exponent,22,0x3a91fd,{DOUBLEWITHTWODWORDINTREE(0x6e600000,0x00000000)}}, {VT_exponent,22,0x3a91fe,{DOUBLEWITHTWODWORDINTREE(0x6e700000,0x00000000)}}, {VT_exponent,22,0x3a91ff,{DOUBLEWITHTWODWORDINTREE(0x6e800000,0x00000000)}}, {VT_exponent,22,0x3a9200,{DOUBLEWITHTWODWORDINTREE(0x6e900000,0x00000000)}}, {VT_exponent,22,0x3a9201,{DOUBLEWITHTWODWORDINTREE(0x6ea00000,0x00000000)}}, {VT_exponent,22,0x3a9202,{DOUBLEWITHTWODWORDINTREE(0x6eb00000,0x00000000)}}, {VT_exponent,22,0x3a9203,{DOUBLEWITHTWODWORDINTREE(0x6ec00000,0x00000000)}}, {VT_exponent,22,0x3a9204,{DOUBLEWITHTWODWORDINTREE(0x6ed00000,0x00000000)}}, {VT_exponent,22,0x3a9205,{DOUBLEWITHTWODWORDINTREE(0x6ee00000,0x00000000)}}, {VT_exponent,22,0x3a9206,{DOUBLEWITHTWODWORDINTREE(0x6ef00000,0x00000000)}}, {VT_exponent,22,0x3a9207,{DOUBLEWITHTWODWORDINTREE(0x6f000000,0x00000000)}}, {VT_exponent,22,0x3a9208,{DOUBLEWITHTWODWORDINTREE(0x6f100000,0x00000000)}}, {VT_exponent,22,0x3a9209,{DOUBLEWITHTWODWORDINTREE(0x6f200000,0x00000000)}}, {VT_exponent,22,0x3a920a,{DOUBLEWITHTWODWORDINTREE(0x6f300000,0x00000000)}}, {VT_exponent,22,0x3a920b,{DOUBLEWITHTWODWORDINTREE(0x6f400000,0x00000000)}}, {VT_exponent,22,0x3a920c,{DOUBLEWITHTWODWORDINTREE(0x6f500000,0x00000000)}}, {VT_exponent,22,0x3a920d,{DOUBLEWITHTWODWORDINTREE(0x6f600000,0x00000000)}}, {VT_exponent,22,0x3a920e,{DOUBLEWITHTWODWORDINTREE(0x6f700000,0x00000000)}}, {VT_exponent,22,0x3a920f,{DOUBLEWITHTWODWORDINTREE(0x6f800000,0x00000000)}}, {VT_exponent,22,0x3a9210,{DOUBLEWITHTWODWORDINTREE(0x6f900000,0x00000000)}}, {VT_exponent,22,0x3a9211,{DOUBLEWITHTWODWORDINTREE(0x6fa00000,0x00000000)}}, {VT_exponent,22,0x3a9212,{DOUBLEWITHTWODWORDINTREE(0x6fb00000,0x00000000)}}, {VT_exponent,22,0x3a9213,{DOUBLEWITHTWODWORDINTREE(0x6fc00000,0x00000000)}}, {VT_exponent,22,0x3a9214,{DOUBLEWITHTWODWORDINTREE(0x6fd00000,0x00000000)}}, {VT_exponent,22,0x3a9215,{DOUBLEWITHTWODWORDINTREE(0x6fe00000,0x00000000)}}, {VT_exponent,22,0x3a9216,{DOUBLEWITHTWODWORDINTREE(0x6ff00000,0x00000000)}}, {VT_exponent,22,0x3a9217,{DOUBLEWITHTWODWORDINTREE(0x70000000,0x00000000)}}, {VT_exponent,22,0x3a9218,{DOUBLEWITHTWODWORDINTREE(0x70100000,0x00000000)}}, {VT_exponent,22,0x3a9219,{DOUBLEWITHTWODWORDINTREE(0x70200000,0x00000000)}}, {VT_exponent,22,0x3a921a,{DOUBLEWITHTWODWORDINTREE(0x70300000,0x00000000)}}, {VT_exponent,22,0x3a921b,{DOUBLEWITHTWODWORDINTREE(0x70400000,0x00000000)}}, {VT_exponent,22,0x3a921c,{DOUBLEWITHTWODWORDINTREE(0x70500000,0x00000000)}}, {VT_exponent,22,0x3a921d,{DOUBLEWITHTWODWORDINTREE(0x70600000,0x00000000)}}, {VT_exponent,22,0x3a921e,{DOUBLEWITHTWODWORDINTREE(0x70700000,0x00000000)}}, {VT_exponent,22,0x3a921f,{DOUBLEWITHTWODWORDINTREE(0x70800000,0x00000000)}}, {VT_exponent,22,0x3a9220,{DOUBLEWITHTWODWORDINTREE(0x70900000,0x00000000)}}, {VT_exponent,22,0x3a9221,{DOUBLEWITHTWODWORDINTREE(0x70a00000,0x00000000)}}, {VT_exponent,22,0x3a9222,{DOUBLEWITHTWODWORDINTREE(0x70b00000,0x00000000)}}, {VT_exponent,22,0x3a9223,{DOUBLEWITHTWODWORDINTREE(0x70c00000,0x00000000)}}, {VT_exponent,22,0x3a9224,{DOUBLEWITHTWODWORDINTREE(0x70d00000,0x00000000)}}, {VT_exponent,22,0x3a9225,{DOUBLEWITHTWODWORDINTREE(0x70e00000,0x00000000)}}, {VT_exponent,22,0x3a9226,{DOUBLEWITHTWODWORDINTREE(0x70f00000,0x00000000)}}, {VT_exponent,22,0x3a9227,{DOUBLEWITHTWODWORDINTREE(0x71000000,0x00000000)}}, {VT_exponent,22,0x3a9228,{DOUBLEWITHTWODWORDINTREE(0x71100000,0x00000000)}}, {VT_exponent,22,0x3a9229,{DOUBLEWITHTWODWORDINTREE(0x71200000,0x00000000)}}, {VT_exponent,22,0x3a922a,{DOUBLEWITHTWODWORDINTREE(0x71300000,0x00000000)}}, {VT_exponent,22,0x3a922b,{DOUBLEWITHTWODWORDINTREE(0x71400000,0x00000000)}}, {VT_exponent,22,0x3a922c,{DOUBLEWITHTWODWORDINTREE(0x71500000,0x00000000)}}, {VT_exponent,22,0x3a922d,{DOUBLEWITHTWODWORDINTREE(0x71600000,0x00000000)}}, {VT_exponent,22,0x3a922e,{DOUBLEWITHTWODWORDINTREE(0x71700000,0x00000000)}}, {VT_exponent,22,0x3a922f,{DOUBLEWITHTWODWORDINTREE(0x71800000,0x00000000)}}, {VT_exponent,22,0x3a9230,{DOUBLEWITHTWODWORDINTREE(0x71900000,0x00000000)}}, {VT_exponent,22,0x3a9231,{DOUBLEWITHTWODWORDINTREE(0x71a00000,0x00000000)}}, {VT_exponent,22,0x3a9232,{DOUBLEWITHTWODWORDINTREE(0x71b00000,0x00000000)}}, {VT_exponent,22,0x3a9233,{DOUBLEWITHTWODWORDINTREE(0x71c00000,0x00000000)}}, {VT_exponent,22,0x3a9234,{DOUBLEWITHTWODWORDINTREE(0x71d00000,0x00000000)}}, {VT_exponent,22,0x3a9235,{DOUBLEWITHTWODWORDINTREE(0x71e00000,0x00000000)}}, {VT_exponent,22,0x3a9236,{DOUBLEWITHTWODWORDINTREE(0x71f00000,0x00000000)}}, {VT_exponent,22,0x3a9237,{DOUBLEWITHTWODWORDINTREE(0x72000000,0x00000000)}}, {VT_exponent,22,0x3a9238,{DOUBLEWITHTWODWORDINTREE(0x72100000,0x00000000)}}, {VT_exponent,22,0x3a9239,{DOUBLEWITHTWODWORDINTREE(0x72200000,0x00000000)}}, {VT_exponent,22,0x3a923a,{DOUBLEWITHTWODWORDINTREE(0x72300000,0x00000000)}}, {VT_exponent,22,0x3a923b,{DOUBLEWITHTWODWORDINTREE(0x72400000,0x00000000)}}, {VT_exponent,22,0x3a923c,{DOUBLEWITHTWODWORDINTREE(0x72500000,0x00000000)}}, {VT_exponent,22,0x3a923d,{DOUBLEWITHTWODWORDINTREE(0x72600000,0x00000000)}}, {VT_exponent,22,0x3a923e,{DOUBLEWITHTWODWORDINTREE(0x72700000,0x00000000)}}, {VT_exponent,22,0x3a923f,{DOUBLEWITHTWODWORDINTREE(0x72800000,0x00000000)}}, {VT_exponent,22,0x3a9240,{DOUBLEWITHTWODWORDINTREE(0x72900000,0x00000000)}}, {VT_exponent,22,0x3a9241,{DOUBLEWITHTWODWORDINTREE(0x72a00000,0x00000000)}}, {VT_exponent,22,0x3a9242,{DOUBLEWITHTWODWORDINTREE(0x72b00000,0x00000000)}}, {VT_exponent,22,0x3a9243,{DOUBLEWITHTWODWORDINTREE(0x72c00000,0x00000000)}}, {VT_exponent,22,0x3a9244,{DOUBLEWITHTWODWORDINTREE(0x72d00000,0x00000000)}}, {VT_exponent,22,0x3a9245,{DOUBLEWITHTWODWORDINTREE(0x72e00000,0x00000000)}}, {VT_exponent,22,0x3a9246,{DOUBLEWITHTWODWORDINTREE(0x72f00000,0x00000000)}}, {VT_exponent,22,0x3a9247,{DOUBLEWITHTWODWORDINTREE(0x73000000,0x00000000)}}, {VT_exponent,22,0x3a9248,{DOUBLEWITHTWODWORDINTREE(0x73100000,0x00000000)}}, {VT_exponent,22,0x3a9249,{DOUBLEWITHTWODWORDINTREE(0x73200000,0x00000000)}}, {VT_exponent,22,0x3a924a,{DOUBLEWITHTWODWORDINTREE(0x73300000,0x00000000)}}, {VT_exponent,22,0x3a924b,{DOUBLEWITHTWODWORDINTREE(0x73400000,0x00000000)}}, {VT_exponent,22,0x3a924c,{DOUBLEWITHTWODWORDINTREE(0x73500000,0x00000000)}}, {VT_exponent,22,0x3a924d,{DOUBLEWITHTWODWORDINTREE(0x73600000,0x00000000)}}, {VT_exponent,22,0x3a924e,{DOUBLEWITHTWODWORDINTREE(0x73700000,0x00000000)}}, {VT_exponent,22,0x3a924f,{DOUBLEWITHTWODWORDINTREE(0x73800000,0x00000000)}}, {VT_exponent,22,0x3a9250,{DOUBLEWITHTWODWORDINTREE(0x73900000,0x00000000)}}, {VT_exponent,22,0x3a9251,{DOUBLEWITHTWODWORDINTREE(0x73a00000,0x00000000)}}, {VT_exponent,22,0x3a9252,{DOUBLEWITHTWODWORDINTREE(0x73b00000,0x00000000)}}, {VT_exponent,22,0x3a9253,{DOUBLEWITHTWODWORDINTREE(0x73c00000,0x00000000)}}, {VT_exponent,22,0x3a9254,{DOUBLEWITHTWODWORDINTREE(0x73d00000,0x00000000)}}, {VT_exponent,22,0x3a9255,{DOUBLEWITHTWODWORDINTREE(0x73e00000,0x00000000)}}, {VT_exponent,22,0x3a9256,{DOUBLEWITHTWODWORDINTREE(0x73f00000,0x00000000)}}, {VT_exponent,22,0x3a9257,{DOUBLEWITHTWODWORDINTREE(0x74000000,0x00000000)}}, {VT_exponent,22,0x3a9258,{DOUBLEWITHTWODWORDINTREE(0x74100000,0x00000000)}}, {VT_exponent,22,0x3a9259,{DOUBLEWITHTWODWORDINTREE(0x74200000,0x00000000)}}, {VT_exponent,22,0x3a925a,{DOUBLEWITHTWODWORDINTREE(0x74300000,0x00000000)}}, {VT_exponent,22,0x3a925b,{DOUBLEWITHTWODWORDINTREE(0x74400000,0x00000000)}}, {VT_exponent,22,0x3a925c,{DOUBLEWITHTWODWORDINTREE(0x74500000,0x00000000)}}, {VT_exponent,22,0x3a925d,{DOUBLEWITHTWODWORDINTREE(0x74600000,0x00000000)}}, {VT_exponent,22,0x3a925e,{DOUBLEWITHTWODWORDINTREE(0x74700000,0x00000000)}}, {VT_exponent,22,0x3a925f,{DOUBLEWITHTWODWORDINTREE(0x74800000,0x00000000)}}, {VT_exponent,22,0x3a9260,{DOUBLEWITHTWODWORDINTREE(0x74900000,0x00000000)}}, {VT_exponent,22,0x3a9261,{DOUBLEWITHTWODWORDINTREE(0x74a00000,0x00000000)}}, {VT_exponent,22,0x3a9262,{DOUBLEWITHTWODWORDINTREE(0x74b00000,0x00000000)}}, {VT_exponent,22,0x3a9263,{DOUBLEWITHTWODWORDINTREE(0x74c00000,0x00000000)}}, {VT_exponent,22,0x3a9264,{DOUBLEWITHTWODWORDINTREE(0x74d00000,0x00000000)}}, {VT_exponent,22,0x3a9265,{DOUBLEWITHTWODWORDINTREE(0x74e00000,0x00000000)}}, {VT_exponent,22,0x3a9266,{DOUBLEWITHTWODWORDINTREE(0x74f00000,0x00000000)}}, {VT_exponent,22,0x3a9267,{DOUBLEWITHTWODWORDINTREE(0x75000000,0x00000000)}}, {VT_exponent,22,0x3a9268,{DOUBLEWITHTWODWORDINTREE(0x75100000,0x00000000)}}, {VT_exponent,22,0x3a9269,{DOUBLEWITHTWODWORDINTREE(0x75200000,0x00000000)}}, {VT_exponent,22,0x3a926a,{DOUBLEWITHTWODWORDINTREE(0x75300000,0x00000000)}}, {VT_exponent,22,0x3a926b,{DOUBLEWITHTWODWORDINTREE(0x75400000,0x00000000)}}, {VT_exponent,22,0x3a926c,{DOUBLEWITHTWODWORDINTREE(0x75500000,0x00000000)}}, {VT_exponent,22,0x3a926d,{DOUBLEWITHTWODWORDINTREE(0x75600000,0x00000000)}}, {VT_exponent,22,0x3a926e,{DOUBLEWITHTWODWORDINTREE(0x75700000,0x00000000)}}, {VT_exponent,22,0x3a926f,{DOUBLEWITHTWODWORDINTREE(0x75800000,0x00000000)}}, {VT_exponent,22,0x3a9270,{DOUBLEWITHTWODWORDINTREE(0x75900000,0x00000000)}}, {VT_exponent,22,0x3a9271,{DOUBLEWITHTWODWORDINTREE(0x75a00000,0x00000000)}}, {VT_exponent,22,0x3a9272,{DOUBLEWITHTWODWORDINTREE(0x75b00000,0x00000000)}}, {VT_exponent,22,0x3a9273,{DOUBLEWITHTWODWORDINTREE(0x75c00000,0x00000000)}}, {VT_exponent,22,0x3a9274,{DOUBLEWITHTWODWORDINTREE(0x75d00000,0x00000000)}}, {VT_exponent,22,0x3a9275,{DOUBLEWITHTWODWORDINTREE(0x75e00000,0x00000000)}}, {VT_exponent,22,0x3a9276,{DOUBLEWITHTWODWORDINTREE(0x75f00000,0x00000000)}}, {VT_exponent,22,0x3a9277,{DOUBLEWITHTWODWORDINTREE(0x76000000,0x00000000)}}, {VT_exponent,22,0x3a9278,{DOUBLEWITHTWODWORDINTREE(0x76100000,0x00000000)}}, {VT_exponent,22,0x3a9279,{DOUBLEWITHTWODWORDINTREE(0x76200000,0x00000000)}}, {VT_exponent,22,0x3a927a,{DOUBLEWITHTWODWORDINTREE(0x76300000,0x00000000)}}, {VT_exponent,22,0x3a927b,{DOUBLEWITHTWODWORDINTREE(0x76400000,0x00000000)}}, {VT_exponent,22,0x3a927c,{DOUBLEWITHTWODWORDINTREE(0x76500000,0x00000000)}}, {VT_exponent,22,0x3a927d,{DOUBLEWITHTWODWORDINTREE(0x76600000,0x00000000)}}, {VT_exponent,22,0x3a927e,{DOUBLEWITHTWODWORDINTREE(0x76700000,0x00000000)}}, {VT_exponent,22,0x3a927f,{DOUBLEWITHTWODWORDINTREE(0x76800000,0x00000000)}}, {VT_exponent,22,0x3a9280,{DOUBLEWITHTWODWORDINTREE(0x76900000,0x00000000)}}, {VT_exponent,22,0x3a9281,{DOUBLEWITHTWODWORDINTREE(0x76a00000,0x00000000)}}, {VT_exponent,22,0x3a9282,{DOUBLEWITHTWODWORDINTREE(0x76b00000,0x00000000)}}, {VT_exponent,22,0x3a9283,{DOUBLEWITHTWODWORDINTREE(0x76c00000,0x00000000)}}, {VT_exponent,22,0x3a9284,{DOUBLEWITHTWODWORDINTREE(0x76d00000,0x00000000)}}, {VT_exponent,22,0x3a9285,{DOUBLEWITHTWODWORDINTREE(0x76e00000,0x00000000)}}, {VT_exponent,22,0x3a9286,{DOUBLEWITHTWODWORDINTREE(0x76f00000,0x00000000)}}, {VT_exponent,22,0x3a9287,{DOUBLEWITHTWODWORDINTREE(0x77000000,0x00000000)}}, {VT_exponent,22,0x3a9288,{DOUBLEWITHTWODWORDINTREE(0x77100000,0x00000000)}}, {VT_exponent,22,0x3a9289,{DOUBLEWITHTWODWORDINTREE(0x77200000,0x00000000)}}, {VT_exponent,22,0x3a928a,{DOUBLEWITHTWODWORDINTREE(0x77300000,0x00000000)}}, {VT_exponent,22,0x3a928b,{DOUBLEWITHTWODWORDINTREE(0x77400000,0x00000000)}}, {VT_exponent,22,0x3a928c,{DOUBLEWITHTWODWORDINTREE(0x77500000,0x00000000)}}, {VT_exponent,22,0x3a928d,{DOUBLEWITHTWODWORDINTREE(0x77600000,0x00000000)}}, {VT_exponent,22,0x3a928e,{DOUBLEWITHTWODWORDINTREE(0x77700000,0x00000000)}}, {VT_exponent,22,0x3a928f,{DOUBLEWITHTWODWORDINTREE(0x77800000,0x00000000)}}, {VT_exponent,22,0x3a9290,{DOUBLEWITHTWODWORDINTREE(0x77900000,0x00000000)}}, {VT_exponent,22,0x3a9291,{DOUBLEWITHTWODWORDINTREE(0x77a00000,0x00000000)}}, {VT_exponent,22,0x3a9292,{DOUBLEWITHTWODWORDINTREE(0x77b00000,0x00000000)}}, {VT_exponent,22,0x3a9293,{DOUBLEWITHTWODWORDINTREE(0x77c00000,0x00000000)}}, {VT_exponent,22,0x3a9294,{DOUBLEWITHTWODWORDINTREE(0x77d00000,0x00000000)}}, {VT_exponent,22,0x3a9295,{DOUBLEWITHTWODWORDINTREE(0x77e00000,0x00000000)}}, {VT_exponent,22,0x3a9296,{DOUBLEWITHTWODWORDINTREE(0x77f00000,0x00000000)}}, {VT_exponent,22,0x3a9297,{DOUBLEWITHTWODWORDINTREE(0x78000000,0x00000000)}}, {VT_exponent,22,0x3a9298,{DOUBLEWITHTWODWORDINTREE(0x78100000,0x00000000)}}, {VT_exponent,22,0x3a9299,{DOUBLEWITHTWODWORDINTREE(0x78200000,0x00000000)}}, {VT_exponent,22,0x3a929a,{DOUBLEWITHTWODWORDINTREE(0x78300000,0x00000000)}}, {VT_exponent,22,0x3a929b,{DOUBLEWITHTWODWORDINTREE(0x78400000,0x00000000)}}, {VT_exponent,22,0x3a929c,{DOUBLEWITHTWODWORDINTREE(0x78500000,0x00000000)}}, {VT_exponent,22,0x3a929d,{DOUBLEWITHTWODWORDINTREE(0x78600000,0x00000000)}}, {VT_exponent,22,0x3a929e,{DOUBLEWITHTWODWORDINTREE(0x78700000,0x00000000)}}, {VT_exponent,22,0x3a929f,{DOUBLEWITHTWODWORDINTREE(0x78800000,0x00000000)}}, {VT_exponent,22,0x3a92a0,{DOUBLEWITHTWODWORDINTREE(0x78900000,0x00000000)}}, {VT_exponent,22,0x3a92a1,{DOUBLEWITHTWODWORDINTREE(0x78a00000,0x00000000)}}, {VT_exponent,22,0x3a92a2,{DOUBLEWITHTWODWORDINTREE(0x78b00000,0x00000000)}}, {VT_exponent,22,0x3a92a3,{DOUBLEWITHTWODWORDINTREE(0x78c00000,0x00000000)}}, {VT_exponent,22,0x3a92a4,{DOUBLEWITHTWODWORDINTREE(0x78d00000,0x00000000)}}, {VT_exponent,22,0x3a92a5,{DOUBLEWITHTWODWORDINTREE(0x78e00000,0x00000000)}}, {VT_exponent,22,0x3a92a6,{DOUBLEWITHTWODWORDINTREE(0x78f00000,0x00000000)}}, {VT_exponent,22,0x3a92a7,{DOUBLEWITHTWODWORDINTREE(0x79000000,0x00000000)}}, {VT_exponent,22,0x3a92a8,{DOUBLEWITHTWODWORDINTREE(0x79100000,0x00000000)}}, {VT_exponent,22,0x3a92a9,{DOUBLEWITHTWODWORDINTREE(0x79200000,0x00000000)}}, {VT_exponent,22,0x3a92aa,{DOUBLEWITHTWODWORDINTREE(0x79300000,0x00000000)}}, {VT_exponent,22,0x3a92ab,{DOUBLEWITHTWODWORDINTREE(0x79400000,0x00000000)}}, {VT_exponent,22,0x3a92ac,{DOUBLEWITHTWODWORDINTREE(0x79500000,0x00000000)}}, {VT_exponent,22,0x3a92ad,{DOUBLEWITHTWODWORDINTREE(0x79600000,0x00000000)}}, {VT_exponent,22,0x3a92ae,{DOUBLEWITHTWODWORDINTREE(0x79700000,0x00000000)}}, {VT_exponent,22,0x3a92af,{DOUBLEWITHTWODWORDINTREE(0x79800000,0x00000000)}}, {VT_exponent,22,0x3a92b0,{DOUBLEWITHTWODWORDINTREE(0x79900000,0x00000000)}}, {VT_exponent,22,0x3a92b1,{DOUBLEWITHTWODWORDINTREE(0x79a00000,0x00000000)}}, {VT_exponent,22,0x3a92b2,{DOUBLEWITHTWODWORDINTREE(0x79b00000,0x00000000)}}, {VT_exponent,22,0x3a92b3,{DOUBLEWITHTWODWORDINTREE(0x79c00000,0x00000000)}}, {VT_exponent,22,0x3a92b4,{DOUBLEWITHTWODWORDINTREE(0x79d00000,0x00000000)}}, {VT_exponent,22,0x3a92b5,{DOUBLEWITHTWODWORDINTREE(0x79e00000,0x00000000)}}, {VT_exponent,22,0x3a92b6,{DOUBLEWITHTWODWORDINTREE(0x79f00000,0x00000000)}}, {VT_exponent,22,0x3a92b7,{DOUBLEWITHTWODWORDINTREE(0x7a000000,0x00000000)}}, {VT_exponent,22,0x3a92b8,{DOUBLEWITHTWODWORDINTREE(0x7a100000,0x00000000)}}, {VT_exponent,22,0x3a92b9,{DOUBLEWITHTWODWORDINTREE(0x7a200000,0x00000000)}}, {VT_exponent,22,0x3a92ba,{DOUBLEWITHTWODWORDINTREE(0x7a300000,0x00000000)}}, {VT_exponent,22,0x3a92bb,{DOUBLEWITHTWODWORDINTREE(0x7a400000,0x00000000)}}, {VT_exponent,22,0x3a92bc,{DOUBLEWITHTWODWORDINTREE(0x7a500000,0x00000000)}}, {VT_exponent,22,0x3a92bd,{DOUBLEWITHTWODWORDINTREE(0x7a600000,0x00000000)}}, {VT_exponent,22,0x3a92be,{DOUBLEWITHTWODWORDINTREE(0x7a700000,0x00000000)}}, {VT_exponent,22,0x3a92bf,{DOUBLEWITHTWODWORDINTREE(0x7a800000,0x00000000)}}, {VT_exponent,22,0x3a92c0,{DOUBLEWITHTWODWORDINTREE(0x7a900000,0x00000000)}}, {VT_exponent,22,0x3a92c1,{DOUBLEWITHTWODWORDINTREE(0x7aa00000,0x00000000)}}, {VT_exponent,22,0x3a92c2,{DOUBLEWITHTWODWORDINTREE(0x7ab00000,0x00000000)}}, {VT_exponent,22,0x3a92c3,{DOUBLEWITHTWODWORDINTREE(0x7ac00000,0x00000000)}}, {VT_exponent,22,0x3a92c4,{DOUBLEWITHTWODWORDINTREE(0x7ad00000,0x00000000)}}, {VT_exponent,22,0x3a92c5,{DOUBLEWITHTWODWORDINTREE(0x7ae00000,0x00000000)}}, {VT_exponent,22,0x3a92c6,{DOUBLEWITHTWODWORDINTREE(0x7af00000,0x00000000)}}, {VT_exponent,22,0x3a92c7,{DOUBLEWITHTWODWORDINTREE(0x7b000000,0x00000000)}}, {VT_exponent,22,0x3a92c8,{DOUBLEWITHTWODWORDINTREE(0x7b100000,0x00000000)}}, {VT_exponent,22,0x3a92c9,{DOUBLEWITHTWODWORDINTREE(0x7b200000,0x00000000)}}, {VT_exponent,22,0x3a92ca,{DOUBLEWITHTWODWORDINTREE(0x7b300000,0x00000000)}}, {VT_exponent,22,0x3a92cb,{DOUBLEWITHTWODWORDINTREE(0x7b400000,0x00000000)}}, {VT_exponent,22,0x3a92cc,{DOUBLEWITHTWODWORDINTREE(0x7b500000,0x00000000)}}, {VT_exponent,22,0x3a92cd,{DOUBLEWITHTWODWORDINTREE(0x7b600000,0x00000000)}}, {VT_exponent,22,0x3a92ce,{DOUBLEWITHTWODWORDINTREE(0x7b700000,0x00000000)}}, {VT_exponent,22,0x3a92cf,{DOUBLEWITHTWODWORDINTREE(0x7b800000,0x00000000)}}, {VT_exponent,22,0x3a92d0,{DOUBLEWITHTWODWORDINTREE(0x7b900000,0x00000000)}}, {VT_exponent,22,0x3a92d1,{DOUBLEWITHTWODWORDINTREE(0x7ba00000,0x00000000)}}, {VT_exponent,22,0x3a92d2,{DOUBLEWITHTWODWORDINTREE(0x7bb00000,0x00000000)}}, {VT_exponent,22,0x3a92d3,{DOUBLEWITHTWODWORDINTREE(0x7bc00000,0x00000000)}}, {VT_exponent,22,0x3a92d4,{DOUBLEWITHTWODWORDINTREE(0x7bd00000,0x00000000)}}, {VT_exponent,22,0x3a92d5,{DOUBLEWITHTWODWORDINTREE(0x7be00000,0x00000000)}}, {VT_exponent,22,0x3a92d6,{DOUBLEWITHTWODWORDINTREE(0x7bf00000,0x00000000)}}, {VT_exponent,22,0x3a92d7,{DOUBLEWITHTWODWORDINTREE(0x7c000000,0x00000000)}}, {VT_exponent,22,0x3a92d8,{DOUBLEWITHTWODWORDINTREE(0x7c100000,0x00000000)}}, {VT_exponent,22,0x3a92d9,{DOUBLEWITHTWODWORDINTREE(0x7c200000,0x00000000)}}, {VT_exponent,22,0x3a92da,{DOUBLEWITHTWODWORDINTREE(0x7c300000,0x00000000)}}, {VT_exponent,22,0x3a92db,{DOUBLEWITHTWODWORDINTREE(0x7c400000,0x00000000)}}, {VT_exponent,22,0x3a92dc,{DOUBLEWITHTWODWORDINTREE(0x7c500000,0x00000000)}}, {VT_exponent,22,0x3a92dd,{DOUBLEWITHTWODWORDINTREE(0x7c600000,0x00000000)}}, {VT_exponent,22,0x3a92de,{DOUBLEWITHTWODWORDINTREE(0x7c700000,0x00000000)}}, {VT_exponent,22,0x3a92df,{DOUBLEWITHTWODWORDINTREE(0x7c800000,0x00000000)}}, {VT_exponent,22,0x3a92e0,{DOUBLEWITHTWODWORDINTREE(0x7c900000,0x00000000)}}, {VT_exponent,22,0x3a92e1,{DOUBLEWITHTWODWORDINTREE(0x7ca00000,0x00000000)}}, {VT_exponent,22,0x3a92e2,{DOUBLEWITHTWODWORDINTREE(0x7cb00000,0x00000000)}}, {VT_exponent,22,0x3a92e3,{DOUBLEWITHTWODWORDINTREE(0x7cc00000,0x00000000)}}, {VT_exponent,22,0x3a92e4,{DOUBLEWITHTWODWORDINTREE(0x7cd00000,0x00000000)}}, {VT_exponent,22,0x3a92e5,{DOUBLEWITHTWODWORDINTREE(0x7ce00000,0x00000000)}}, {VT_exponent,22,0x3a92e6,{DOUBLEWITHTWODWORDINTREE(0x7cf00000,0x00000000)}}, {VT_exponent,22,0x3a92e7,{DOUBLEWITHTWODWORDINTREE(0x7d000000,0x00000000)}}, {VT_exponent,22,0x3a92e8,{DOUBLEWITHTWODWORDINTREE(0x7d100000,0x00000000)}}, {VT_exponent,22,0x3a92e9,{DOUBLEWITHTWODWORDINTREE(0x7d200000,0x00000000)}}, {VT_exponent,22,0x3a92ea,{DOUBLEWITHTWODWORDINTREE(0x7d300000,0x00000000)}}, {VT_exponent,22,0x3a92eb,{DOUBLEWITHTWODWORDINTREE(0x7d400000,0x00000000)}}, {VT_exponent,22,0x3a92ec,{DOUBLEWITHTWODWORDINTREE(0x7d500000,0x00000000)}}, {VT_exponent,22,0x3a92ed,{DOUBLEWITHTWODWORDINTREE(0x7d600000,0x00000000)}}, {VT_exponent,22,0x3a92ee,{DOUBLEWITHTWODWORDINTREE(0x7d700000,0x00000000)}}, {VT_exponent,22,0x3a92ef,{DOUBLEWITHTWODWORDINTREE(0x7d800000,0x00000000)}}, {VT_exponent,22,0x3a92f0,{DOUBLEWITHTWODWORDINTREE(0x7d900000,0x00000000)}}, {VT_exponent,22,0x3a92f1,{DOUBLEWITHTWODWORDINTREE(0x7da00000,0x00000000)}}, {VT_exponent,22,0x3a92f2,{DOUBLEWITHTWODWORDINTREE(0x7db00000,0x00000000)}}, {VT_exponent,22,0x3a92f3,{DOUBLEWITHTWODWORDINTREE(0x7dc00000,0x00000000)}}, {VT_exponent,22,0x3a92f4,{DOUBLEWITHTWODWORDINTREE(0x7dd00000,0x00000000)}}, {VT_exponent,22,0x3a92f5,{DOUBLEWITHTWODWORDINTREE(0x7de00000,0x00000000)}}, {VT_exponent,22,0x3a92f6,{DOUBLEWITHTWODWORDINTREE(0x7df00000,0x00000000)}}, {VT_exponent,22,0x3a92f7,{DOUBLEWITHTWODWORDINTREE(0x7e000000,0x00000000)}}, {VT_exponent,22,0x3a92f8,{DOUBLEWITHTWODWORDINTREE(0x7e100000,0x00000000)}}, {VT_exponent,22,0x3a92f9,{DOUBLEWITHTWODWORDINTREE(0x7e200000,0x00000000)}}, {VT_exponent,22,0x3a92fa,{DOUBLEWITHTWODWORDINTREE(0x7e300000,0x00000000)}}, {VT_exponent,22,0x3a92fb,{DOUBLEWITHTWODWORDINTREE(0x7e400000,0x00000000)}}, {VT_exponent,22,0x3a92fc,{DOUBLEWITHTWODWORDINTREE(0x7e500000,0x00000000)}}, {VT_exponent,22,0x3a92fd,{DOUBLEWITHTWODWORDINTREE(0x7e600000,0x00000000)}}, {VT_exponent,22,0x3a92fe,{DOUBLEWITHTWODWORDINTREE(0x7e700000,0x00000000)}}, {VT_exponent,22,0x3a92ff,{DOUBLEWITHTWODWORDINTREE(0x7e800000,0x00000000)}}, {VT_exponent,22,0x3a95a0,{DOUBLEWITHTWODWORDINTREE(0x7e900000,0x00000000)}}, {VT_exponent,22,0x3a95a1,{DOUBLEWITHTWODWORDINTREE(0x7ea00000,0x00000000)}}, {VT_exponent,22,0x3a95a2,{DOUBLEWITHTWODWORDINTREE(0x7eb00000,0x00000000)}}, {VT_exponent,22,0x3a95a3,{DOUBLEWITHTWODWORDINTREE(0x7ec00000,0x00000000)}}, {VT_exponent,22,0x3a95a4,{DOUBLEWITHTWODWORDINTREE(0x7ed00000,0x00000000)}}, {VT_exponent,22,0x3a95a5,{DOUBLEWITHTWODWORDINTREE(0x7ee00000,0x00000000)}}, {VT_exponent,22,0x3a95a6,{DOUBLEWITHTWODWORDINTREE(0x7ef00000,0x00000000)}}, {VT_exponent,22,0x3a95a7,{DOUBLEWITHTWODWORDINTREE(0x7f000000,0x00000000)}}, {VT_exponent,22,0x3a95a8,{DOUBLEWITHTWODWORDINTREE(0x7f100000,0x00000000)}}, {VT_exponent,22,0x3a95a9,{DOUBLEWITHTWODWORDINTREE(0x7f200000,0x00000000)}}, {VT_exponent,22,0x3a95aa,{DOUBLEWITHTWODWORDINTREE(0x7f300000,0x00000000)}}, {VT_exponent,22,0x3a95ab,{DOUBLEWITHTWODWORDINTREE(0x7f400000,0x00000000)}}, {VT_exponent,22,0x3a95ac,{DOUBLEWITHTWODWORDINTREE(0x7f500000,0x00000000)}}, {VT_exponent,22,0x3a95ad,{DOUBLEWITHTWODWORDINTREE(0x7f600000,0x00000000)}}, {VT_exponent,22,0x3a95ae,{DOUBLEWITHTWODWORDINTREE(0x7f700000,0x00000000)}}, {VT_exponent,22,0x3a95af,{DOUBLEWITHTWODWORDINTREE(0x7f800000,0x00000000)}}, {VT_exponent,22,0x3b8fe0,{DOUBLEWITHTWODWORDINTREE(0x7f900000,0x00000000)}}, {VT_exponent,22,0x3b8fe1,{DOUBLEWITHTWODWORDINTREE(0x7fa00000,0x00000000)}}, {VT_exponent,22,0x3b8fe2,{DOUBLEWITHTWODWORDINTREE(0x7fb00000,0x00000000)}}, {VT_exponent,22,0x3b8fe3,{DOUBLEWITHTWODWORDINTREE(0x7fc00000,0x00000000)}}, {VT_exponent,21,0x68e90,{DOUBLEWITHTWODWORDINTREE(0x7fd00000,0x00000000)}}, {VT_exponent,21,0x68e91,{DOUBLEWITHTWODWORDINTREE(0x7fe00000,0x00000000)}}, {VT_exponent,21,0x68e98,{DOUBLEWITHTWODWORDINTREE(0x7ff80000,0x00000000)}}, }; // End of acofdoe array asymptote-2.37/prc/PRCdouble.h000066400000000000000000000072651265434602500162670ustar00rootroot00000000000000#ifndef __PRC_DOUBLE_H #define __PRC_DOUBLE_H #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef BYTE_ORDER # undef WORDS_BIG_ENDIAN # undef WORDS_LITTLE_ENDIAN # if BYTE_ORDER == BIG_ENDIAN # define WORDS_BIG_ENDIAN 1 # endif # if BYTE_ORDER == LITTLE_ENDIAN # define WORDS_LITTLE_ENDIAN 1 # endif #endif // from Adobe's documentation union ieee754_double { double d; /* This is the IEEE 754 double-precision format. */ struct { #ifdef WORDS_BIGENDIAN unsigned int negative:1; unsigned int exponent:11; /* Together these comprise the mantissa. */ unsigned int mantissa0:20; unsigned int mantissa1:32; #else /* Together these comprise the mantissa. */ unsigned int mantissa1:32; unsigned int mantissa0:20; unsigned int exponent:11; unsigned int negative:1; #endif } ieee; }; union ieee754_float { float f; /* This is the IEEE 754 float-precision format. */ struct { #ifdef WORDS_BIGENDIAN unsigned int negative:1; unsigned int exponent:8; unsigned int mantissa:23; #else unsigned int mantissa:23; unsigned int exponent:8; unsigned int negative:1; #endif } ieee; }; enum ValueType {VT_double,VT_exponent}; struct sCodageOfFrequentDoubleOrExponent { short Type; short NumberOfBits; unsigned Bits; union { unsigned ul[2]; double Value; } u2uod; }; #ifdef WORDS_BIGENDIAN # define DOUBLEWITHTWODWORD(upper,lower) upper,lower # define UPPERPOWER (0) # define LOWERPOWER (!UPPERPOWER) # define NEXTBYTE(pbd) ((pbd)++) # define PREVIOUSBYTE(pbd) ((pbd)--) # define MOREBYTE(pbd,pbend) ((pbd)<=(pbend)) # define OFFSETBYTE(pbd,offset) ((pbd)+=offset) # define BEFOREBYTE(pbd) ((pbd)-1) # define DIFFPOINTERS(p1,p2) ((p1)-(p2)) # define SEARCHBYTE(pbstart,b,nb) (unsigned char *)memrchr((pbstart),(b),(nb)) # define BYTEAT(pb,i) *((pb)-(i)) #else # define DOUBLEWITHTWODWORD(upper,lower) lower,upper # define UPPERPOWER (1) # define LOWERPOWER (!UPPERPOWER) # define NEXTBYTE(pbd) ((pbd)--) # define PREVIOUSBYTE(pbd) ((pbd)++) # define MOREBYTE(pbd,pbend) ((pbd)>=(pbend)) # define OFFSETBYTE(pbd,offset) ((pbd)-=offset) # define BEFOREBYTE(pbd) ((pbd)+1) # define DIFFPOINTERS(p1,p2) ((unsigned)((p2)-(p1))) # define SEARCHBYTE(pbstart,b,nb) (unsigned char *)memchr((pbstart),(b),(nb)) # define BYTEAT(pb,i) *((pb)+(i)) #endif #define MAXLENGTHFORCOMPRESSEDTYPE ((22+1+1+4+6*(1+8))+7)/8 #define NEGATIVE(d) (((union ieee754_double *)&(d))->ieee.negative) #define EXPONENT(d) (((union ieee754_double *)&(d))->ieee.exponent) #define MANTISSA0(d) (((union ieee754_double *)&(d))->ieee.mantissa0) #define MANTISSA1(d) (((union ieee754_double *)&(d))->ieee.mantissa1) typedef unsigned char PRCbyte; typedef unsigned short PRCword; typedef unsigned PRCdword; extern PRCdword stadwZero[2],stadwNegativeZero[2]; #define NUMBEROFELEMENTINACOFDOE (2077) #ifdef WORDS_BIGENDIAN # define DOUBLEWITHTWODWORDINTREE(upper,lower) {upper,lower} #else # define DOUBLEWITHTWODWORDINTREE(upper,lower) {lower,upper} #endif extern sCodageOfFrequentDoubleOrExponent acofdoe[NUMBEROFELEMENTINACOFDOE]; struct sCodageOfFrequentDoubleOrExponent* getcofdoe(unsigned,short); #define STAT_V #define STAT_DOUBLE int stCOFDOECompare(const void*,const void*); #ifdef WORDS_BIGENDIAN #ifndef HAVE_MEMRCHR void *memrchr(const void *,int,size_t); #endif #endif #endif // __PRC_DOUBLE_H asymptote-2.37/prc/oPRCFile.cc000066400000000000000000002121371265434602500162050ustar00rootroot00000000000000/************ * * This file is part of a tool for producing 3D content in the PRC format. * Copyright (C) 2008 Orest Shardt and * Michail Vidiassov * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * *************/ #include "oPRCFile.h" #include #include #include #include #include #include #include namespace prc { #define WriteUnsignedInteger( value ) out << (uint32_t)(value); #define WriteInteger( value ) out << (int32_t)(value); #define WriteDouble( value ) out << (double)(value); #define WriteString( value ) out << (value); #define WriteUncompressedUnsignedInteger( value ) writeUncompressedUnsignedInteger(out, (uint32_t)(value)); #define WriteUncompressedBlock( value, count ) out.write((char *)(value),(count)); #define SerializeFileStructureUncompressedUniqueId( value ) (value).serializeFileStructureUncompressedUniqueId(out); #define SerializeCompressedUniqueId( value ) (value).serializeCompressedUniqueId(out); #define SerializeContentPRCBase write(out); #define SerializeRgbColor( value ) (value).serializeRgbColor(out); #define SerializePicture( value ) (value).serializePicture(out); #define SerializeTextureDefinition( value ) (value)->serializeTextureDefinition(out); #define SerializeMarkup( value ) (value)->serializeMarkup(out); #define SerializeAnnotationEntity( value ) (value)->serializeAnnotationEntity(out); #define SerializeFontKeysSameFont( value ) (value).serializeFontKeysSameFont(out); #define SerializeMaterial( value ) (value)->serializeMaterial(out); #define SerializeUserData UserData(0,0).write(out); #define SerializeEmptyContentPRCBase ContentPRCBase(PRC_TYPE_ROOT_PRCBase).serializeContentPRCBase(out); #define SerializeCategory1LineStyle( value ) (value)->serializeCategory1LineStyle(out); #define SerializeCoordinateSystem( value ) (value)->serializeCoordinateSystem(out); #define SerializeRepresentationItem( value ) (value)->serializeRepresentationItem(out); #define SerializePartDefinition( value ) (value)->serializePartDefinition(out); #define SerializeProductOccurrence( value ) (value)->serializeProductOccurrence(out); #define SerializeContextAndBodies( value ) (value)->serializeContextAndBodies(out); #define SerializeGeometrySummary( value ) (value)->serializeGeometrySummary(out); #define SerializeContextGraphics( value ) (value)->serializeContextGraphics(out); #define SerializeStartHeader serializeStartHeader(out); #define SerializeUncompressedFiles \ { \ const uint32_t number_of_uncompressed_files = uncompressed_files.size(); \ WriteUncompressedUnsignedInteger (number_of_uncompressed_files) \ for(PRCUncompressedFileList::const_iterator it = uncompressed_files.begin(); it != uncompressed_files.end(); it++) \ { \ WriteUncompressedUnsignedInteger ((*it)->file_size) \ WriteUncompressedBlock ((*it)->data, (*it)->file_size) \ } \ } #define SerializeModelFileData serializeModelFileData(modelFile_out); modelFile_out.compress(); #define SerializeUnit( value ) (value).serializeUnit(out); using namespace std; void PRCFileStructure::serializeFileStructureGlobals(PRCbitStream &out) { // even though this is technically not part of this section, // it is handled here for convenience const uint32_t number_of_schema = 0; WriteUnsignedInteger (number_of_schema) WriteUnsignedInteger (PRC_TYPE_ASM_FileStructureGlobals) PRCSingleAttribute sa((int32_t)PRCVersion); PRCAttribute a("__PRC_RESERVED_ATTRIBUTE_PRCInternalVersion"); a.addKey(sa); ContentPRCBase cb(PRC_TYPE_ROOT_PRCBase); cb.addAttribute(a); cb.serializeContentPRCBase(out); WriteUnsignedInteger (number_of_referenced_file_structures) // SerializeFileStructureInternalGlobalData WriteDouble (tessellation_chord_height_ratio) WriteDouble (tessellation_angle_degree) // SerializeMarkupSerializationHelper WriteString (default_font_family_name) const uint32_t number_of_fonts = font_keys_of_font.size(); WriteUnsignedInteger (number_of_fonts) for (uint32_t i=0;iunit_information.unit_from_CAD_file = true; product_occurrences[i]->unit_information.unit = unit; SerializeProductOccurrence (product_occurrences[i]) } // SerializeFileStructureInternalData WriteUnsignedInteger (PRC_TYPE_ASM_FileStructure) SerializeEmptyContentPRCBase const uint32_t next_available_index = makePRCID(); WriteUnsignedInteger (next_available_index) const uint32_t index_product_occurence = number_of_product_occurrences; // Asymptote (oPRCFile) specific - we write the root product last WriteUnsignedInteger (index_product_occurence) SerializeUserData } void PRCFileStructure::serializeFileStructureTessellation(PRCbitStream &out) { WriteUnsignedInteger (PRC_TYPE_ASM_FileStructureTessellation) SerializeEmptyContentPRCBase const uint32_t number_of_tessellations = tessellations.size(); WriteUnsignedInteger (number_of_tessellations) for (uint32_t i=0;iserializeBaseTessData(out); SerializeUserData } void PRCFileStructure::serializeFileStructureGeometry(PRCbitStream &out) { WriteUnsignedInteger (PRC_TYPE_ASM_FileStructureGeometry) SerializeEmptyContentPRCBase const uint32_t number_of_contexts = contexts.size(); WriteUnsignedInteger (number_of_contexts) for (uint32_t i=0;ifile_structure_uuid ) // index+1 out << (uint32_t)fileStructures[0]->product_occurrences.size(); // active out << true; out << (uint32_t)0; // index in model file SerializeUserData } void makeFileUUID(PRCUniqueId& UUID) { // make a UUID static uint32_t count = 0; ++count; // the minimum requirement on UUIDs is that all must be unique in the file UUID.id0 = 0x33595341; // some constant UUID.id1 = (uint32_t)time(NULL); // the time UUID.id2 = count; UUID.id3 = 0xa5a55a5a; // Something random, not seeded by the time, would be nice. But for now, a constant // maybe add something else to make it more unique // so multiple files can be combined // a hash of some data perhaps? } void makeAppUUID(PRCUniqueId& UUID) { UUID.id0 = UUID.id1 = UUID.id2 = UUID.id3 = 0; } void PRCUncompressedFile::write(ostream &out) const { if(data!=NULL) { WriteUncompressedUnsignedInteger (file_size) out.write((char*)data,file_size); } } uint32_t PRCUncompressedFile::getSize() const { return sizeof(file_size)+file_size; } void PRCStartHeader::serializeStartHeader(ostream &out) const { WriteUncompressedBlock ("PRC",3) WriteUncompressedUnsignedInteger (minimal_version_for_read) WriteUncompressedUnsignedInteger (authoring_version) SerializeFileStructureUncompressedUniqueId( file_structure_uuid ); SerializeFileStructureUncompressedUniqueId( application_uuid ); } uint32_t PRCStartHeader::getStartHeaderSize() const { return 3+(2+2*4)*sizeof(uint32_t); } void PRCFileStructure::write(ostream &out) { // SerializeFileStructureHeader SerializeStartHeader SerializeUncompressedFiles globals_out.write(out); tree_out.write(out); tessellations_out.write(out); geometry_out.write(out); extraGeometry_out.write(out); } #define SerializeFileStructureGlobals serializeFileStructureGlobals(globals_out); globals_out.compress(); sizes[1]=globals_out.getSize(); #define SerializeFileStructureTree serializeFileStructureTree(tree_out); tree_out.compress(); sizes[2]=tree_out.getSize(); #define SerializeFileStructureTessellation serializeFileStructureTessellation(tessellations_out); tessellations_out.compress(); sizes[3]=tessellations_out.getSize(); #define SerializeFileStructureGeometry serializeFileStructureGeometry(geometry_out); geometry_out.compress(); sizes[4]=geometry_out.getSize(); #define SerializeFileStructureExtraGeometry serializeFileStructureExtraGeometry(extraGeometry_out); extraGeometry_out.compress(); sizes[5]=extraGeometry_out.getSize(); #define FlushSerialization resetGraphicsAndName(); void PRCFileStructure::prepare() { uint32_t size = 0; size += getStartHeaderSize(); size += sizeof(uint32_t); for(PRCUncompressedFileList::const_iterator it = uncompressed_files.begin(); it != uncompressed_files.end(); it++) size += (*it)->getSize(); sizes[0]=size; SerializeFileStructureGlobals FlushSerialization SerializeFileStructureTree FlushSerialization SerializeFileStructureTessellation FlushSerialization SerializeFileStructureGeometry FlushSerialization SerializeFileStructureExtraGeometry FlushSerialization } uint32_t PRCFileStructure::getSize() { uint32_t size = 0; for(size_t i=0; i<6; i++) size += sizes[i]; return size; } void PRCFileStructureInformation::write(ostream &out) { SerializeFileStructureUncompressedUniqueId( UUID ); WriteUncompressedUnsignedInteger (reserved) WriteUncompressedUnsignedInteger (number_of_offsets) for(uint32_t i = 0; i < number_of_offsets; ++i) { WriteUncompressedUnsignedInteger (offsets[i]) } } uint32_t PRCFileStructureInformation::getSize() { return (4+2+number_of_offsets)*sizeof(uint32_t); } void PRCHeader::write(ostream &out) { SerializeStartHeader WriteUncompressedUnsignedInteger (number_of_file_structures) for(uint32_t i = 0; i < number_of_file_structures; ++i) { fileStructureInformation[i].write(out); } WriteUncompressedUnsignedInteger (model_file_offset) WriteUncompressedUnsignedInteger (file_size) SerializeUncompressedFiles } uint32_t PRCHeader::getSize() { uint32_t size = getStartHeaderSize() + sizeof(uint32_t); for(uint32_t i = 0; i < number_of_file_structures; ++i) size += fileStructureInformation[i].getSize(); size += 3*sizeof(uint32_t); for(PRCUncompressedFileList::const_iterator it = uncompressed_files.begin(); it != uncompressed_files.end(); it++) size += (*it)->getSize(); return size; } void oPRCFile::doGroup(PRCgroup& group) { const std::string& name = group.name; PRCProductOccurrence*& product_occurrence = group.product_occurrence; PRCProductOccurrence*& parent_product_occurrence = group.parent_product_occurrence; PRCPartDefinition*& part_definition = group.part_definition; PRCPartDefinition*& parent_part_definition = group.parent_part_definition; if(group.options.tess) { if(!group.lines.empty()) { for(PRCtesslineMap::const_iterator wit=group.lines.begin(); wit!=group.lines.end(); wit++) { bool same_color = true; const PRCtesslineList& lines = wit->second; const PRCRgbColor &color = lines.front().color; for(PRCtesslineList::const_iterator lit=lines.begin(); lit!=lines.end(); lit++) if(color!=lit->color) { same_color = false; break; } map points; PRC3DWireTess *tess = new PRC3DWireTess(); if(!same_color) { tess->is_segment_color = true; tess->is_rgba = false; } for(PRCtesslineList::const_iterator lit=lines.begin(); lit!=lines.end(); lit++) { tess->wire_indexes.push_back(lit->point.size()); for(uint32_t i=0; ipoint.size(); i++) { map::iterator pPoint = points.find(lit->point[i]); if(pPoint!=points.end()) tess->wire_indexes.push_back(pPoint->second); else { const uint32_t point_index = tess->coordinates.size(); points.insert(make_pair(lit->point[i],point_index)); tess->wire_indexes.push_back(point_index); tess->coordinates.push_back(lit->point[i].x); tess->coordinates.push_back(lit->point[i].y); tess->coordinates.push_back(lit->point[i].z); } if(!same_color && i>0) { tess->rgba_vertices.push_back(byte(lit->color.red)); tess->rgba_vertices.push_back(byte(lit->color.green)); tess->rgba_vertices.push_back(byte(lit->color.blue)); } } } const uint32_t tess_index = add3DWireTess(tess); PRCPolyWire *polyWire = new PRCPolyWire(); polyWire->index_tessellation = tess_index; if(same_color) polyWire->index_of_line_style = addColourWidth(RGBAColour(color.red,color.green,color.blue),wit->first); else polyWire->index_of_line_style = addColourWidth(RGBAColour(1,1,1),wit->first); part_definition->addPolyWire(polyWire); } } // make rectangles pairs of triangles in a tesselation if(!group.rectangles.empty()) { bool same_color = true; const uint32_t &style = group.rectangles.front().style; for(PRCtessrectangleList::const_iterator rit=group.rectangles.begin(); rit!=group.rectangles.end(); rit++) if(style!=rit->style) { same_color = false; break; } map points; PRC3DTess *tess = new PRC3DTess(); tess->crease_angle = group.options.crease_angle; PRCTessFace *tessFace = new PRCTessFace(); tessFace->used_entities_flag=PRC_FACETESSDATA_Triangle; uint32_t triangles = 0; for(PRCtessrectangleList::const_iterator rit=group.rectangles.begin(); rit!=group.rectangles.end(); rit++) { const bool degenerate = (rit->vertices[0]==rit->vertices[1]); uint32_t vertex_indices[4]; for(size_t i = (degenerate?1:0); i < 4; ++i) { map::const_iterator pPoint = points.find(rit->vertices[i]); if(pPoint!=points.end()) vertex_indices[i] = pPoint->second; else { points.insert(make_pair(rit->vertices[i],(vertex_indices[i] = tess->coordinates.size()))); tess->coordinates.push_back(rit->vertices[i].x); tess->coordinates.push_back(rit->vertices[i].y); tess->coordinates.push_back(rit->vertices[i].z); } } if(degenerate) { tess->triangulated_index.push_back(vertex_indices[1]); tess->triangulated_index.push_back(vertex_indices[2]); tess->triangulated_index.push_back(vertex_indices[3]); triangles++; if(!same_color) tessFace->line_attributes.push_back(rit->style); } else { tess->triangulated_index.push_back(vertex_indices[0]); tess->triangulated_index.push_back(vertex_indices[2]); tess->triangulated_index.push_back(vertex_indices[3]); triangles++; if(!same_color) tessFace->line_attributes.push_back(rit->style); tess->triangulated_index.push_back(vertex_indices[3]); tess->triangulated_index.push_back(vertex_indices[1]); tess->triangulated_index.push_back(vertex_indices[0]); triangles++; if(!same_color) tessFace->line_attributes.push_back(rit->style); } } tessFace->sizes_triangulated.push_back(triangles); tess->addTessFace(tessFace); const uint32_t tess_index = add3DTess(tess); PRCPolyBrepModel *polyBrepModel = new PRCPolyBrepModel(); polyBrepModel->index_tessellation = tess_index; polyBrepModel->is_closed = group.options.closed; if(same_color) polyBrepModel->index_of_line_style = style; part_definition->addPolyBrepModel(polyBrepModel); } } if(!group.quads.empty()) { map points; PRC3DTess *tess = new PRC3DTess(); tess->crease_angle = group.options.crease_angle; PRCTessFace *tessFace = new PRCTessFace(); tessFace->used_entities_flag=PRC_FACETESSDATA_Triangle; uint32_t triangles = 0; tessFace->is_rgba = false; for(PRCtessquadList::const_iterator qit=group.quads.begin(); qit!=group.quads.end(); qit++) { const RGBAColour* C = qit->colours; if(C[0].A != 1.0 || C[1].A != 1.0 || C[2].A != 1.0 || C[3].A != 1.0) { tessFace->is_rgba = true; break; } } bool same_colour = true; const RGBAColour& colour = group.quads.front().colours[0]; for(PRCtessquadList::const_iterator qit=group.quads.begin(); qit!=group.quads.end(); qit++) { const RGBAColour* C = qit->colours; if(colour!=C[0] || colour!=C[1] || colour!=C[2] || colour!=C[3]) { same_colour = false; break; } } for(PRCtessquadList::const_iterator qit=group.quads.begin(); qit!=group.quads.end(); qit++) { const RGBAColour* C = qit->colours; const bool degenerate = (qit->vertices[0]==qit->vertices[1]); uint32_t vertex_indices[4]; for(size_t i = (degenerate?1:0); i < 4; ++i) { map::const_iterator pPoint = points.find(qit->vertices[i]); if(pPoint!=points.end()) vertex_indices[i] = pPoint->second; else { points.insert(make_pair(qit->vertices[i],(vertex_indices[i] = tess->coordinates.size()))); tess->coordinates.push_back(qit->vertices[i].x); tess->coordinates.push_back(qit->vertices[i].y); tess->coordinates.push_back(qit->vertices[i].z); } } if(degenerate) { tess->triangulated_index.push_back(vertex_indices[1]); tess->triangulated_index.push_back(vertex_indices[2]); tess->triangulated_index.push_back(vertex_indices[3]); triangles++; if(!same_colour) { tessFace->rgba_vertices.push_back(byte(C[1].R)); tessFace->rgba_vertices.push_back(byte(C[1].G)); tessFace->rgba_vertices.push_back(byte(C[1].B)); if(tessFace->is_rgba) tessFace->rgba_vertices.push_back(byte(C[1].A)); tessFace->rgba_vertices.push_back(byte(C[2].R)); tessFace->rgba_vertices.push_back(byte(C[2].G)); tessFace->rgba_vertices.push_back(byte(C[2].B)); if(tessFace->is_rgba) tessFace->rgba_vertices.push_back(byte(C[2].A)); tessFace->rgba_vertices.push_back(byte(C[3].R)); tessFace->rgba_vertices.push_back(byte(C[3].G)); tessFace->rgba_vertices.push_back(byte(C[3].B)); if(tessFace->is_rgba) tessFace->rgba_vertices.push_back(byte(C[3].A)); } } else { tess->triangulated_index.push_back(vertex_indices[0]); tess->triangulated_index.push_back(vertex_indices[2]); tess->triangulated_index.push_back(vertex_indices[3]); triangles++; if(!same_colour) { tessFace->rgba_vertices.push_back(byte(C[0].R)); tessFace->rgba_vertices.push_back(byte(C[0].G)); tessFace->rgba_vertices.push_back(byte(C[0].B)); if(tessFace->is_rgba) tessFace->rgba_vertices.push_back(byte(C[0].A)); tessFace->rgba_vertices.push_back(byte(C[2].R)); tessFace->rgba_vertices.push_back(byte(C[2].G)); tessFace->rgba_vertices.push_back(byte(C[2].B)); if(tessFace->is_rgba) tessFace->rgba_vertices.push_back(byte(C[2].A)); tessFace->rgba_vertices.push_back(byte(C[3].R)); tessFace->rgba_vertices.push_back(byte(C[3].G)); tessFace->rgba_vertices.push_back(byte(C[3].B)); if(tessFace->is_rgba) tessFace->rgba_vertices.push_back(byte(C[3].A)); } tess->triangulated_index.push_back(vertex_indices[3]); tess->triangulated_index.push_back(vertex_indices[1]); tess->triangulated_index.push_back(vertex_indices[0]); triangles++; if(!same_colour) { tessFace->rgba_vertices.push_back(byte(C[3].R)); tessFace->rgba_vertices.push_back(byte(C[3].G)); tessFace->rgba_vertices.push_back(byte(C[3].B)); if(tessFace->is_rgba) tessFace->rgba_vertices.push_back(byte(C[3].A)); tessFace->rgba_vertices.push_back(byte(C[1].R)); tessFace->rgba_vertices.push_back(byte(C[1].G)); tessFace->rgba_vertices.push_back(byte(C[1].B)); if(tessFace->is_rgba) tessFace->rgba_vertices.push_back(byte(C[1].A)); tessFace->rgba_vertices.push_back(byte(C[0].R)); tessFace->rgba_vertices.push_back(byte(C[0].G)); tessFace->rgba_vertices.push_back(byte(C[0].B)); if(tessFace->is_rgba) tessFace->rgba_vertices.push_back(byte(C[0].A)); } } } tessFace->sizes_triangulated.push_back(triangles); tess->addTessFace(tessFace); const uint32_t tess_index = add3DTess(tess); PRCPolyBrepModel *polyBrepModel = new PRCPolyBrepModel(); polyBrepModel->index_tessellation = tess_index; polyBrepModel->is_closed = group.options.closed; if(same_colour) polyBrepModel->index_of_line_style = addColour(colour); part_definition->addPolyBrepModel(polyBrepModel); } if(!group.points.empty()) { for(PRCpointsetMap::const_iterator pit=group.points.begin(); pit!=group.points.end(); pit++) { PRCPointSet *pointset = new PRCPointSet(); pointset->index_of_line_style = pit->first; pointset->point = pit->second; part_definition->addPointSet(pointset); } } if(!group.pointsets.empty()) { for(std::vector::iterator pit=group.pointsets.begin(); pit!=group.pointsets.end(); pit++) { part_definition->addPointSet(*pit); } } if(!group.polymodels.empty()) { for(std::vector::iterator pit=group.polymodels.begin(); pit!=group.polymodels.end(); pit++) { (*pit)->is_closed = group.options.closed; part_definition->addPolyBrepModel(*pit); } } if(!group.polywires.empty()) { for(std::vector::iterator pit=group.polywires.begin(); pit!=group.polywires.end(); pit++) { part_definition->addPolyWire(*pit); } } if(!group.wires.empty()) { PRCTopoContext *wireContext = NULL; const uint32_t context_index = getTopoContext(wireContext); for(PRCwireList::iterator wit=group.wires.begin(); wit!=group.wires.end(); wit++) { PRCWireEdge *wireEdge = new PRCWireEdge; wireEdge->curve_3d = wit->curve; PRCSingleWireBody *wireBody = new PRCSingleWireBody; wireBody->setWireEdge(wireEdge); const uint32_t wire_body_index = wireContext->addSingleWireBody(wireBody); PRCWire *wire = new PRCWire(); wire->index_of_line_style = wit->style; wire->context_id = context_index; wire->body_id = wire_body_index; if(wit->transform) wire->index_local_coordinate_system = addTransform(wit->transform); part_definition->addWire(wire); } } PRCfaceList &faces = group.faces; if(!faces.empty()) { bool same_color = true; const uint32_t style = faces.front().style; for(PRCfaceList::const_iterator fit=faces.begin(); fit!=faces.end(); fit++) if(style!=fit->style) { same_color = false; break; } PRCTopoContext *context = NULL; const uint32_t context_index = getTopoContext(context); context->granularity = group.options.granularity; // Acrobat 9 also does the following: // context->tolerance = group.options.granularity; // context->have_smallest_face_thickness = true; // context->smallest_thickness = group.options.granularity; PRCShell *shell = new PRCShell; for(PRCfaceList::iterator fit=faces.begin(); fit!=faces.end(); fit++) { if(fit->transform || group.options.do_break || (fit->transparent && !group.options.no_break)) { PRCShell *shell = new PRCShell; shell->addFace(fit->face); PRCConnex *connex = new PRCConnex; connex->addShell(shell); PRCBrepData *body = new PRCBrepData; body->addConnex(connex); const uint32_t body_index = context->addBrepData(body); PRCBrepModel *brepmodel = new PRCBrepModel(); brepmodel->index_of_line_style = fit->style; brepmodel->context_id = context_index; brepmodel->body_id = body_index; brepmodel->is_closed = group.options.closed; brepmodel->index_local_coordinate_system = addTransform(fit->transform); part_definition->addBrepModel(brepmodel); } else { if(!same_color) fit->face->index_of_line_style = fit->style; shell->addFace(fit->face); } } if(shell->face.empty()) { delete shell; } else { PRCConnex *connex = new PRCConnex; connex->addShell(shell); PRCBrepData *body = new PRCBrepData; body->addConnex(connex); const uint32_t body_index = context->addBrepData(body); PRCBrepModel *brepmodel = new PRCBrepModel(); if(same_color) brepmodel->index_of_line_style = style; brepmodel->context_id = context_index; brepmodel->body_id = body_index; brepmodel->is_closed = group.options.closed; part_definition->addBrepModel(brepmodel); } } PRCcompfaceList &compfaces = group.compfaces; if(!compfaces.empty()) { bool same_color = true; const uint32_t style = compfaces.front().style; for(PRCcompfaceList::const_iterator fit=compfaces.begin(); fit!=compfaces.end(); fit++) if(style!=fit->style) { same_color = false; break; } PRCTopoContext *context = NULL; const uint32_t context_index = getTopoContext(context); PRCCompressedBrepData *body = new PRCCompressedBrepData; body->serial_tolerance=group.options.compression; body->brep_data_compressed_tolerance=0.1*group.options.compression; for(PRCcompfaceList::const_iterator fit=compfaces.begin(); fit!=compfaces.end(); fit++) { if(group.options.do_break || (fit->transparent && !group.options.no_break)) { PRCCompressedBrepData *body = new PRCCompressedBrepData; body->face.push_back(fit->face); body->serial_tolerance=group.options.compression; body->brep_data_compressed_tolerance=2.8346456* group.options.compression; const uint32_t body_index = context->addCompressedBrepData(body); PRCBrepModel *brepmodel = new PRCBrepModel(); brepmodel->index_of_line_style = fit->style; brepmodel->context_id = context_index; brepmodel->body_id = body_index; brepmodel->is_closed = group.options.closed; part_definition->addBrepModel(brepmodel); } else { if(!same_color) fit->face->index_of_line_style = fit->style; body->face.push_back(fit->face); } } if(body->face.empty()) { delete body; } else { const uint32_t body_index = context->addCompressedBrepData(body); PRCBrepModel *brepmodel = new PRCBrepModel(); if(same_color) brepmodel->index_of_line_style = style; brepmodel->context_id = context_index; brepmodel->body_id = body_index; brepmodel->is_closed = group.options.closed; part_definition->addBrepModel(brepmodel); } } // Simplify and reduce to as simple entities as possible // products with named representation items can not be reduced to sets, since // outside references are already set bool nonamedparts = true; for(PRCRepresentationItemList::const_iterator it=part_definition->representation_item.begin(); it!=part_definition->representation_item.end(); it++) { if (!(*it)->name.empty()) { nonamedparts = false; break; } } lastgroupname.clear(); lastgroupnames.clear(); // First option - reduce to one element in parent if (parent_part_definition && product_occurrence->index_son_occurrence.empty() && part_definition->representation_item.size() == 1 && ( name.empty() || part_definition->representation_item.front()->name.empty() ) && ( !group.transform || part_definition->representation_item.front()->index_local_coordinate_system==m1) ) { if(part_definition->representation_item.front()->name.empty() ) part_definition->representation_item.front()->name = name; if(part_definition->representation_item.front()->index_local_coordinate_system==m1) part_definition->representation_item.front()->index_local_coordinate_system = addTransform(group.transform); lastgroupname = calculate_unique_name(part_definition->representation_item.front(), parent_product_occurrence); parent_part_definition->addRepresentationItem(part_definition->representation_item.front()); part_definition->representation_item.clear(); delete product_occurrence; product_occurrence = NULL; delete part_definition; part_definition = NULL; } // Second option - reduce to a set else if (parent_part_definition && product_occurrence->index_son_occurrence.empty() && !part_definition->representation_item.empty() && !group.options.do_break && nonamedparts) { PRCSet *set = new PRCSet(name); set->index_local_coordinate_system = addTransform(group.transform); lastgroupname = calculate_unique_name(set, parent_product_occurrence); for(PRCRepresentationItemList::iterator it=part_definition->representation_item.begin(); it!=part_definition->representation_item.end(); it++) { lastgroupnames.push_back(calculate_unique_name(*it, parent_product_occurrence)); set->addRepresentationItem(*it); } part_definition->representation_item.clear(); parent_part_definition->addSet(set); delete product_occurrence; product_occurrence = NULL; delete part_definition; part_definition = NULL; } // Third option - create product else if ( !product_occurrence->index_son_occurrence.empty() || !part_definition->representation_item.empty()) { // if everything is enclosed in one group - drop the root group if (parent_product_occurrence == NULL && group.transform == NULL && part_definition->representation_item.empty() && product_occurrence->index_son_occurrence.size()==1) { delete part_definition; part_definition = NULL; delete product_occurrence; product_occurrence = NULL; } else { lastgroupname = calculate_unique_name(product_occurrence, NULL); if (part_definition->representation_item.empty()) { delete part_definition; part_definition = NULL; } else { for(PRCRepresentationItemList::const_iterator it=part_definition->representation_item.begin(); it!=part_definition->representation_item.end(); it++) if ((*it)->name.empty()) lastgroupnames.push_back(calculate_unique_name(*it, product_occurrence)); product_occurrence->index_part = addPartDefinition(part_definition); } if (group.transform) { product_occurrence->location = group.transform; group.transform = NULL; } if (parent_product_occurrence) { parent_product_occurrence->index_son_occurrence.push_back(addProductOccurrence(product_occurrence)); } else { addProductOccurrence(product_occurrence); } } } // Last case - absolutely nothing to do else { delete product_occurrence; product_occurrence = NULL; delete part_definition; part_definition = NULL; } } std::string oPRCFile::calculate_unique_name(const ContentPRCBase *prc_entity,const ContentPRCBase *prc_occurence) { std::stringstream ss (std::stringstream::in | std::stringstream::out); uint8_t *serialization_buffer = NULL; PRCbitStream serialization(serialization_buffer,0u); const PRCFileStructure *pfile_structure = fileStructures[0]; const PRCUniqueId& uuid = pfile_structure->file_structure_uuid; // ConvertUniqueIdentifierToString (prc_entity) // SerializeCompressedUniqueId (file_structure) serialization << uuid.id0 << uuid.id1 << uuid.id2 << uuid.id3; // WriteUnsignedInteger (type) serialization << prc_entity->getType(); // WriteUnsignedInteger (unique_identifier) serialization << prc_entity->getPRCID(); if (prc_occurence) { // serialization_buffer = Flush serialization (serialization) { const uint32_t size_serialization = serialization.getSize(); while(size_serialization == serialization.getSize()) serialization << false; } // ConvertUniqueIdentifierToString (prc_occurrence_unique_id) // SerializeCompressedUniqueId (file_structure) serialization << uuid.id0 << uuid.id1 << uuid.id2 << uuid.id3; // WriteUnsignedInteger (type) serialization << (uint32_t)PRC_TYPE_ASM_ProductOccurence; // WriteUnsignedInteger (unique_identifier) serialization << prc_occurence->getPRCID(); } ss << (prc_entity->name.empty()?"node":prc_entity->name) << '.'; const uint32_t size_serialization = serialization.getSize(); for(size_t j=0; jprepare(); SerializeModelFileData // create the header // fill out enough info so that sizes can be computed correctly header.number_of_file_structures = number_of_file_structures; header.fileStructureInformation = new PRCFileStructureInformation[number_of_file_structures]; for(uint32_t i = 0; i < number_of_file_structures; ++i) { header.fileStructureInformation[i].UUID = fileStructures[i]->file_structure_uuid; header.fileStructureInformation[i].reserved = 0; header.fileStructureInformation[i].number_of_offsets = 6; header.fileStructureInformation[i].offsets = new uint32_t[6]; } header.minimal_version_for_read = PRCVersion; header.authoring_version = PRCVersion; makeFileUUID(header.file_structure_uuid); makeAppUUID(header.application_uuid); header.file_size = getSize(); header.model_file_offset = header.file_size - modelFile_out.getSize(); uint32_t currentOffset = header.getSize(); for(uint32_t i = 0; i < number_of_file_structures; ++i) { for(size_t j=0; j<6; j++) { header.fileStructureInformation[i].offsets[j] = currentOffset; currentOffset += fileStructures[i]->sizes[j]; } } // write the data header.write(output); for(uint32_t i = 0; i < number_of_file_structures; ++i) { fileStructures[i]->write(output); } modelFile_out.write(output); output.flush(); for(uint32_t i = 0; i < number_of_file_structures; ++i) delete[] header.fileStructureInformation[i].offsets; delete[] header.fileStructureInformation; return true; } uint32_t oPRCFile::getSize() { uint32_t size = header.getSize(); for(uint32_t i = 0; i < number_of_file_structures; ++i) { size += fileStructures[i]->getSize(); } size += modelFile_out.getSize(); return size; } uint32_t PRCFileStructure::addPicture(EPRCPictureDataFormat format, uint32_t size, const uint8_t *p, uint32_t width, uint32_t height, std::string name) { uint8_t *data = NULL; uint32_t components=0; PRCPicture picture(name); if(size==0 || p==NULL) { cerr << "image not set" << endl; return m1; } PRCUncompressedFile* uncompressed_file = new PRCUncompressedFile; if(format==KEPRCPicture_PNG || format==KEPRCPicture_JPG) { data = new uint8_t[size]; memcpy(data, p, size); uncompressed_files.push_back(uncompressed_file); uncompressed_files.back()->file_size = size; uncompressed_files.back()->data = data; picture.format = format; picture.uncompressed_file_index = uncompressed_files.size()-1; picture.pixel_width = 0; // width and height are ignored for JPG and PNG pictures - but let us keep things clean picture.pixel_height = 0; pictures.push_back(picture); return pictures.size()-1; } switch(format) { case KEPRCPicture_BITMAP_RGB_BYTE: components = 3; break; case KEPRCPicture_BITMAP_RGBA_BYTE: components = 4; break; case KEPRCPicture_BITMAP_GREY_BYTE: components = 1; break; case KEPRCPicture_BITMAP_GREYA_BYTE: components = 2; break; default: { cerr << "unknown picture format" << endl; return m1; } } if(width==0 || height==0) { cerr << "width or height parameter not set" << endl; return m1; } if (size < width*height*components) { cerr << "image too small" << endl; return m1; } { uint32_t compressedDataSize = 0; const int CHUNK= 1024; // is this reasonable? z_stream strm; strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL; if(deflateInit(&strm,Z_DEFAULT_COMPRESSION) != Z_OK) { cerr << "Compression initialization failed" << endl; return m1; } unsigned int sizeAvailable = deflateBound(&strm,size); uint8_t *compressedData = (uint8_t*) malloc(sizeAvailable); strm.avail_in = size; strm.next_in = (unsigned char*)p; strm.next_out = (unsigned char*)compressedData; strm.avail_out = sizeAvailable; int code; unsigned int chunks = 0; while((code = deflate(&strm,Z_FINISH)) == Z_OK) { ++chunks; // strm.avail_out should be 0 if we got Z_OK compressedDataSize = sizeAvailable - strm.avail_out; compressedData = (uint8_t*) realloc(compressedData,CHUNK*chunks); strm.next_out = (Bytef*)(compressedData + compressedDataSize); strm.avail_out += CHUNK; sizeAvailable += CHUNK; } compressedDataSize = sizeAvailable-strm.avail_out; if(code != Z_STREAM_END) { deflateEnd(&strm); free(compressedData); { cerr << "Compression error" << endl; return m1; } } deflateEnd(&strm); size = compressedDataSize; data = new uint8_t[compressedDataSize]; memcpy(data, compressedData, compressedDataSize); free(compressedData); } uncompressed_files.push_back(uncompressed_file); uncompressed_files.back()->file_size = size; uncompressed_files.back()->data = data; picture.format = format; picture.uncompressed_file_index = uncompressed_files.size()-1; picture.pixel_width = width; picture.pixel_height = height; pictures.push_back(picture); return pictures.size()-1; } uint32_t PRCFileStructure::addTextureDefinition(PRCTextureDefinition*& pTextureDefinition) { texture_definitions.push_back(pTextureDefinition); pTextureDefinition = NULL; return texture_definitions.size()-1; } uint32_t PRCFileStructure::addRgbColor(const PRCRgbColor &color) { colors.push_back(color); return 3*(colors.size()-1); } uint32_t PRCFileStructure::addRgbColorUnique(const PRCRgbColor &color) { for(uint32_t i = 0; i < colors.size(); ++i) { if(colors[i] == color) return 3*i; } colors.push_back(color); return 3*(colors.size()-1); } uint32_t oPRCFile::addColor(const PRCRgbColor &color) { PRCcolorMap::const_iterator pColor = colorMap.find(color); if(pColor!=colorMap.end()) return pColor->second; // color_index = addRgbColorUnique(color); const uint32_t color_index = fileStructures[0]->addRgbColor(color); colorMap.insert(make_pair(color,color_index)); return color_index; } uint32_t oPRCFile::addColour(const RGBAColour &colour) { PRCcolourMap::const_iterator pColour = colourMap.find(colour); if(pColour!=colourMap.end()) return pColour->second; const uint32_t color_index = addColor(PRCRgbColor(colour.R, colour.G, colour.B)); PRCStyle *style = new PRCStyle(); style->line_width = 1.0; style->is_vpicture = false; style->line_pattern_vpicture_index = 0; style->is_material = false; style->color_material_index = color_index; style->is_transparency_defined = (colour.A < 1.0); style->transparency = (uint8_t)(colour.A * 256); style->additional = 0; const uint32_t style_index = fileStructures[0]->addStyle(style); colourMap.insert(make_pair(colour,style_index)); return style_index; } uint32_t oPRCFile::addColourWidth(const RGBAColour &colour, double width) { RGBAColourWidth colourwidth(colour.R, colour.G, colour.B, colour.A, width); PRCcolourwidthMap::const_iterator pColour = colourwidthMap.find(colourwidth); if(pColour!=colourwidthMap.end()) return pColour->second; const uint32_t color_index = addColor(PRCRgbColor(colour.R, colour.G, colour.B)); PRCStyle *style = new PRCStyle(); style->line_width = width; style->is_vpicture = false; style->line_pattern_vpicture_index = 0; style->is_material = false; style->color_material_index = color_index; style->is_transparency_defined = (colour.A < 1.0); style->transparency = (uint8_t)(colour.A * 256); style->additional = 0; const uint32_t style_index = fileStructures[0]->addStyle(style); colourwidthMap.insert(make_pair(colourwidth,style_index)); return style_index; } uint32_t oPRCFile::addTransform(PRCGeneralTransformation3d*& transform) { if(!transform) return m1; PRCtransformMap::const_iterator pTransform = transformMap.find(*transform); if(pTransform!=transformMap.end()) return pTransform->second; PRCCoordinateSystem *coordinateSystem = new PRCCoordinateSystem(); bool transform_replaced = false; if( transform->M(0,1)==0 && transform->M(0,2)==0 && transform->M(1,0)==0 && transform->M(1,2)==0 && transform->M(2,0)==0 && transform->M(2,1)==0 && transform->M(3,0)==0 && transform->M(3,1)==0 && transform->M(3,2)==0 && transform->M(3,3)==1 ) { transform_replaced = true; PRCCartesianTransformation3d *carttransform = new PRCCartesianTransformation3d; // if(transform->M(0,3)==0 && transform->M(1,3)==0 && transform->M(1,3)==0 && // transform->M(0,0)==1 && transform->M(1,1)==1 && transform->M(2,2)==1 ) // carttransform->behaviour = PRC_TRANSFORMATION_Identity; if(transform->M(0,3)!=0 || transform->M(1,3)!=0 || transform->M(2,3)!=0) { carttransform->behaviour |= PRC_TRANSFORMATION_Translate; carttransform->origin.Set(transform->M(0,3),transform->M(1,3),transform->M(2,3)); } if(transform->M(0,0)!=transform->M(1,1) || transform->M(0,0)!=transform->M(2,2)) { carttransform->behaviour |= PRC_TRANSFORMATION_NonUniformScale; carttransform->scale.Set(transform->M(0,0),transform->M(1,1),transform->M(2,2)); } else if(transform->M(0,0)!=1) { carttransform->behaviour |= PRC_TRANSFORMATION_Scale; carttransform->uniform_scale=transform->M(0,0); } coordinateSystem->axis_set = carttransform; } else coordinateSystem->axis_set = transform; const uint32_t coordinate_system_index = fileStructures[0]->addCoordinateSystem(coordinateSystem); transformMap.insert(make_pair(*transform,coordinate_system_index)); if(transform_replaced) delete transform; transform = NULL; return coordinate_system_index; } uint32_t oPRCFile::addTransform(const double* t) { if(!t) return m1; PRCGeneralTransformation3d* transform = new PRCGeneralTransformation3d(t); return addTransform(transform); } uint32_t oPRCFile::addTransform(const double origin[3], const double x_axis[3], const double y_axis[3], double scale) { PRCCartesianTransformation3d* transform = new PRCCartesianTransformation3d(origin, x_axis, y_axis, scale); if(transform->behaviour==PRC_TRANSFORMATION_Identity) return m1; PRCCoordinateSystem *coordinateSystem = new PRCCoordinateSystem(); coordinateSystem->axis_set = transform; const uint32_t coordinate_system_index = fileStructures[0]->addCoordinateSystem(coordinateSystem); return coordinate_system_index; } uint32_t oPRCFile::addMaterial(const PRCmaterial& m) { uint32_t material_index = m1; const PRCmaterialgeneric materialgeneric(m); PRCmaterialgenericMap::const_iterator pMaterialgeneric = materialgenericMap.find(materialgeneric); if(pMaterialgeneric!=materialgenericMap.end()) material_index = pMaterialgeneric->second; else { PRCMaterialGeneric *materialGeneric = new PRCMaterialGeneric(); const PRCRgbColor ambient(m.ambient.R, m.ambient.G, m.ambient.B); materialGeneric->ambient = addColor(ambient); const PRCRgbColor diffuse(m.diffuse.R, m.diffuse.G, m.diffuse.B); materialGeneric->diffuse = addColor(diffuse); const PRCRgbColor emissive(m.emissive.R, m.emissive.G, m.emissive.B); materialGeneric->emissive = addColor(emissive); const PRCRgbColor specular(m.specular.R, m.specular.G, m.specular.B); materialGeneric->specular = addColor(specular); materialGeneric->shininess = m.shininess; materialGeneric->ambient_alpha = m.ambient.A; materialGeneric->diffuse_alpha = m.diffuse.A; materialGeneric->emissive_alpha = m.emissive.A; materialGeneric->specular_alpha = m.specular.A; material_index = addMaterialGeneric(materialGeneric); materialgenericMap.insert(make_pair(materialgeneric,material_index)); } uint32_t color_material_index = m1; if(m.picture_data!=NULL) { uint32_t picture_index = m1; PRCpicture picture(m); PRCpictureMap::const_iterator pPicture = pictureMap.find(picture); if(pPicture!=pictureMap.end()) picture_index = pPicture->second; else { picture_index = addPicture(picture); uint8_t* data = new uint8_t[picture.size]; memcpy(data,picture.data,picture.size); picture.data = data; pictureMap.insert(make_pair(picture,picture_index)); } uint32_t texture_definition_index = m1; PRCtexturedefinition texturedefinition(picture_index, m); PRCtexturedefinitionMap::const_iterator pTexturedefinition = texturedefinitionMap.find(texturedefinition); if(pTexturedefinition!=texturedefinitionMap.end()) texture_definition_index = pTexturedefinition->second; else { PRCTextureDefinition *TextureDefinition = new PRCTextureDefinition; if (m.picture_size==216688 && m.picture_format==KEPRCPicture_JPG) TextureDefinition->texture_mapping_attribute=PRC_TEXTURE_MAPPING_OPACITY; TextureDefinition->picture_index = picture_index; TextureDefinition->texture_function = m.picture_replace ? KEPRCTextureFunction_Replace : KEPRCTextureFunction_Modulate; TextureDefinition->texture_wrapping_mode_S = m.picture_repeat ? KEPRCTextureWrappingMode_Repeat : KEPRCTextureWrappingMode_ClampToEdge; TextureDefinition->texture_wrapping_mode_T = m.picture_repeat ? KEPRCTextureWrappingMode_Repeat : KEPRCTextureWrappingMode_ClampToEdge; TextureDefinition->texture_mapping_attribute_components = (m.picture_format==KEPRCPicture_BITMAP_RGB_BYTE || m.picture_format==KEPRCPicture_JPG) ? PRC_TEXTURE_MAPPING_COMPONENTS_RGB : PRC_TEXTURE_MAPPING_COMPONENTS_RGBA; texture_definition_index = addTextureDefinition(TextureDefinition); texturedefinitionMap.insert(make_pair(texturedefinition,texture_definition_index)); } uint32_t texture_application_index = m1; const PRCtextureapplication textureapplication(material_index, texture_definition_index); PRCtextureapplicationMap::const_iterator pTextureapplication = textureapplicationMap.find(textureapplication); if(pTextureapplication!=textureapplicationMap.end()) texture_application_index = pTextureapplication->second; else { PRCTextureApplication *TextureApplication = new PRCTextureApplication; TextureApplication->material_generic_index = material_index; TextureApplication->texture_definition_index = texture_definition_index; texture_application_index = addTextureApplication(TextureApplication); textureapplicationMap.insert(make_pair(textureapplication,texture_application_index)); } color_material_index = texture_application_index; } else color_material_index = material_index; uint32_t style_index = m1; PRCstyle style(0,m.alpha,true,color_material_index); PRCstyleMap::const_iterator pStyle = styleMap.find(style); if(pStyle!=styleMap.end()) style_index = pStyle->second; else { PRCStyle *Style = new PRCStyle(); Style->line_width = 0.0; Style->is_vpicture = false; Style->line_pattern_vpicture_index = 0; Style->is_material = true; Style->is_transparency_defined = (m.alpha < 1.0); Style->transparency = (uint8_t)(m.alpha * 256); Style->additional = 0; Style->color_material_index = color_material_index; style_index = addStyle(Style); styleMap.insert(make_pair(style,style_index)); } // materialMap.insert(make_pair(material,style_index)); return style_index; } void oPRCFile::begingroup(const char *name, PRCoptions *options, const double* t) { const PRCgroup &parent_group = groups.top(); groups.push(PRCgroup()); PRCgroup &group = groups.top(); group.name=name; if(options) group.options=*options; if(t&&!isid(t)) group.transform = new PRCGeneralTransformation3d(t); group.product_occurrence = new PRCProductOccurrence(name); group.parent_product_occurrence = parent_group.product_occurrence; group.part_definition = new PRCPartDefinition; group.parent_part_definition = parent_group.part_definition; } void oPRCFile::endgroup() { if(groups.size()<2) { fputs("begingroup without matching endgroup",stderr); exit(1); } doGroup(groups.top()); groups.pop(); // std::cout << lastgroupname << std::endl; // for(std::vector::const_iterator it=lastgroupnames.begin(); it!=lastgroupnames.end(); it++) // std::cout << " " << *it << std::endl; } PRCgroup& oPRCFile::findGroup() { return groups.top(); } void oPRCFile::addPoints(uint32_t n, const double P[][3], const RGBAColour &c, double w) { if(n==0 || P==NULL) return; PRCgroup &group = findGroup(); PRCPointSet *pointset = new PRCPointSet(); group.pointsets.push_back(pointset); pointset->index_of_line_style = addColourWidth(c,w); pointset->point.reserve(n); for(uint32_t i=0; ipoint.push_back(PRCVector3d(P[i][0],P[i][1],P[i][2])); } void oPRCFile::useMesh(uint32_t tess_index, uint32_t style_index, const double origin[3], const double x_axis[3], const double y_axis[3], double scale) { PRCgroup &group = findGroup(); PRCPolyBrepModel *polyBrepModel = new PRCPolyBrepModel(); polyBrepModel->index_local_coordinate_system = addTransform(origin, x_axis, y_axis, scale); polyBrepModel->index_tessellation = tess_index; polyBrepModel->is_closed = group.options.closed; polyBrepModel->index_of_line_style = style_index; group.polymodels.push_back(polyBrepModel); } void oPRCFile::useMesh(uint32_t tess_index, uint32_t style_index, const double* t) { PRCgroup &group = findGroup(); PRCPolyBrepModel *polyBrepModel = new PRCPolyBrepModel(); polyBrepModel->index_local_coordinate_system = addTransform(t); polyBrepModel->index_tessellation = tess_index; polyBrepModel->is_closed = group.options.closed; polyBrepModel->index_of_line_style = style_index; group.polymodels.push_back(polyBrepModel); } void oPRCFile::useLines(uint32_t tess_index, uint32_t style_index, const double origin[3], const double x_axis[3], const double y_axis[3], double scale) { PRCgroup &group = findGroup(); PRCPolyWire *polyWire = new PRCPolyWire(); polyWire->index_local_coordinate_system = addTransform(origin, x_axis, y_axis, scale); polyWire->index_tessellation = tess_index; polyWire->index_of_line_style = style_index; group.polywires.push_back(polyWire); } void oPRCFile::useLines(uint32_t tess_index, uint32_t style_index, const double* t) { PRCgroup &group = findGroup(); PRCPolyWire *polyWire = new PRCPolyWire(); polyWire->index_local_coordinate_system = addTransform(t); polyWire->index_tessellation = tess_index; polyWire->index_of_line_style = style_index; group.polywires.push_back(polyWire); } void oPRCFile::addQuads(uint32_t nP, const double P[][3], uint32_t nI, const uint32_t PI[][4], const PRCmaterial &m, uint32_t nN, const double N[][3], const uint32_t NI[][4], uint32_t nT, const double T[][2], const uint32_t TI[][4], uint32_t nC, const RGBAColour C[], const uint32_t CI[][4], uint32_t nM, const PRCmaterial M[], const uint32_t MI[], double ca) { if(nP==0 || P==NULL || nI==0 || PI==NULL) return; const uint32_t tess_index = createQuadMesh(nP, P, nI, PI, m, nN, N, NI, nT, T, TI, nC, C, CI, nM, M, MI, ca); useMesh(tess_index,m1); } uint32_t oPRCFile::createQuadMesh(uint32_t nP, const double P[][3], uint32_t nI, const uint32_t PI[][4], uint32_t style_index, uint32_t nN, const double N[][3], const uint32_t NI[][4], uint32_t nT, const double T[][2], const uint32_t TI[][4], uint32_t nC, const RGBAColour C[], const uint32_t CI[][4], uint32_t nS, const uint32_t S[], const uint32_t SI[], double ca) { if(nP==0 || P==NULL || nI==0 || PI==NULL) return m1; const bool triangle_color = (nS != 0 && S != NULL && SI != NULL); const bool vertex_color = (nC != 0 && C != NULL && CI != NULL); const bool has_normals = (nN != 0 && N != NULL && NI != NULL); const bool textured = (nT != 0 && T != NULL && TI != NULL); PRC3DTess *tess = new PRC3DTess(); PRCTessFace *tessFace = new PRCTessFace(); tessFace->used_entities_flag = textured ? PRC_FACETESSDATA_TriangleTextured : PRC_FACETESSDATA_Triangle; tessFace->number_of_texture_coordinate_indexes = textured ? 1 : 0; tess->coordinates.reserve(3*nP); for(uint32_t i=0; icoordinates.push_back(P[i][0]); tess->coordinates.push_back(P[i][1]); tess->coordinates.push_back(P[i][2]); } if(has_normals) { tess->normal_coordinate.reserve(3*nN); for(uint32_t i=0; inormal_coordinate.push_back(N[i][0]); tess->normal_coordinate.push_back(N[i][1]); tess->normal_coordinate.push_back(N[i][2]); } } else tess->crease_angle = ca; if(textured) { tess->texture_coordinate.reserve(2*nT); for(uint32_t i=0; itexture_coordinate.push_back(T[i][0]); tess->texture_coordinate.push_back(T[i][1]); } } tess->triangulated_index.reserve(2*(3*nI+(has_normals?3:0)*nI+(textured?3:0)*nI)); for(uint32_t i=0; itriangulated_index.push_back(3*NI[i][0]); if(textured) tess->triangulated_index.push_back(2*TI[i][0]); tess->triangulated_index.push_back(3*PI[i][0]); if(has_normals) tess->triangulated_index.push_back(3*NI[i][1]); if(textured) tess->triangulated_index.push_back(2*TI[i][1]); tess->triangulated_index.push_back(3*PI[i][1]); if(has_normals) tess->triangulated_index.push_back(3*NI[i][3]); if(textured) tess->triangulated_index.push_back(2*TI[i][3]); tess->triangulated_index.push_back(3*PI[i][3]); // second triangle if(has_normals) tess->triangulated_index.push_back(3*NI[i][1]); if(textured) tess->triangulated_index.push_back(2*TI[i][1]); tess->triangulated_index.push_back(3*PI[i][1]); if(has_normals) tess->triangulated_index.push_back(3*NI[i][2]); if(textured) tess->triangulated_index.push_back(2*TI[i][2]); tess->triangulated_index.push_back(3*PI[i][2]); if(has_normals) tess->triangulated_index.push_back(3*NI[i][3]); if(textured) tess->triangulated_index.push_back(2*TI[i][3]); tess->triangulated_index.push_back(3*PI[i][3]); } tessFace->sizes_triangulated.push_back(2*nI); if(triangle_color) { tessFace->line_attributes.reserve(2*nI); for(uint32_t i=0; iline_attributes.push_back(SI[i]); tessFace->line_attributes.push_back(SI[i]); } } else { tessFace->line_attributes.push_back(style_index); } if(vertex_color) { tessFace->is_rgba=false; for(uint32_t i=0; iis_rgba=true; break; } tessFace->rgba_vertices.reserve(2*(tessFace->is_rgba?4:3)*3*nI); for(uint32_t i=0; irgba_vertices.push_back(byte(C[CI[i][0]].R)); tessFace->rgba_vertices.push_back(byte(C[CI[i][0]].G)); tessFace->rgba_vertices.push_back(byte(C[CI[i][0]].B)); if(tessFace->is_rgba) tessFace->rgba_vertices.push_back(byte(C[CI[i][0]].A)); tessFace->rgba_vertices.push_back(byte(C[CI[i][1]].R)); tessFace->rgba_vertices.push_back(byte(C[CI[i][1]].G)); tessFace->rgba_vertices.push_back(byte(C[CI[i][1]].B)); if(tessFace->is_rgba) tessFace->rgba_vertices.push_back(byte(C[CI[i][1]].A)); tessFace->rgba_vertices.push_back(byte(C[CI[i][3]].R)); tessFace->rgba_vertices.push_back(byte(C[CI[i][3]].G)); tessFace->rgba_vertices.push_back(byte(C[CI[i][3]].B)); if(tessFace->is_rgba) tessFace->rgba_vertices.push_back(byte(C[CI[i][3]].A)); // second triangle tessFace->rgba_vertices.push_back(byte(C[CI[i][1]].R)); tessFace->rgba_vertices.push_back(byte(C[CI[i][1]].G)); tessFace->rgba_vertices.push_back(byte(C[CI[i][1]].B)); if(tessFace->is_rgba) tessFace->rgba_vertices.push_back(byte(C[CI[i][1]].A)); tessFace->rgba_vertices.push_back(byte(C[CI[i][2]].R)); tessFace->rgba_vertices.push_back(byte(C[CI[i][2]].G)); tessFace->rgba_vertices.push_back(byte(C[CI[i][2]].B)); if(tessFace->is_rgba) tessFace->rgba_vertices.push_back(byte(C[CI[i][2]].A)); tessFace->rgba_vertices.push_back(byte(C[CI[i][3]].R)); tessFace->rgba_vertices.push_back(byte(C[CI[i][3]].G)); tessFace->rgba_vertices.push_back(byte(C[CI[i][3]].B)); if(tessFace->is_rgba) tessFace->rgba_vertices.push_back(byte(C[CI[i][3]].A)); } } tess->addTessFace(tessFace); const uint32_t tess_index = add3DTess(tess); return tess_index; } /* void oPRCFile::addTriangle(const double P[][3], const double T[][2], uint32_t style_index) { PRCgroup &group = findGroup(); group.triangles.push_back(PRCtesstriangle()); PRCtesstriangle &triangle = group.triangles.back(); for(size_t i = 0; i < 3; i++) { triangle.vertices[i].x = P[i][0]; triangle.vertices[i].y = P[i][1]; triangle.vertices[i].z = P[i][2]; triangle.texcoords[i].x = T[i][0]; triangle.texcoords[i].y = T[i][1]; } triangle.style = style_index; } */ void oPRCFile::addLines(uint32_t nP, const double P[][3], uint32_t nI, const uint32_t PI[], const RGBAColour& c, double w, bool segment_color, uint32_t nC, const RGBAColour C[], uint32_t nCI, const uint32_t CI[]) { if(nP==0 || P==NULL || nI==0 || PI==NULL) return; const uint32_t tess_index = createLines(nP, P, nI, PI, segment_color, nC, C, nCI, CI); useLines(tess_index, c, w); } uint32_t oPRCFile::createLines(uint32_t nP, const double P[][3], uint32_t nI, const uint32_t PI[], bool segment_color, uint32_t nC, const RGBAColour C[], uint32_t nCI, const uint32_t CI[]) { if(nP==0 || P==NULL || nI==0 || PI==NULL) return m1; const bool vertex_color = (nC != 0 && C != NULL && CI != NULL); PRC3DWireTess *tess = new PRC3DWireTess(); tess->coordinates.reserve(3*nP); for(uint32_t i=0; icoordinates.push_back(P[i][0]); tess->coordinates.push_back(P[i][1]); tess->coordinates.push_back(P[i][2]); } tess->wire_indexes.reserve(nI); for(uint32_t i=0; iwire_indexes.push_back(PI[i]); const uint32_t ni = i+PI[i]+1; for(i++; iwire_indexes.push_back(3*PI[i]); } if(vertex_color) { tess->is_segment_color = segment_color; tess->is_rgba=false; for(uint32_t i=0; iis_rgba=true; break; } tess->rgba_vertices.reserve((tess->is_rgba?4:3)*nCI); for(uint32_t i=0; irgba_vertices.push_back(byte(C[CI[i]].R)); tess->rgba_vertices.push_back(byte(C[CI[i]].G)); tess->rgba_vertices.push_back(byte(C[CI[i]].B)); if(tess->is_rgba) tess->rgba_vertices.push_back(byte(C[CI[i]].A)); } } const uint32_t tess_index = add3DWireTess(tess); return tess_index; } #define PRCFACETRANSFORM const double origin[3], const double x_axis[3], const double y_axis[3], double scale, const double* t void oPRCFile::addHemisphere(double radius, const PRCmaterial &m, PRCFACETRANSFORM) { ADDFACE(PRCSphere) SETTRANSF surface->uv_domain.min.x = 0; surface->uv_domain.max.x = 2*pi; surface->uv_domain.min.y = 0; surface->uv_domain.max.y = 0.5*pi; surface->radius = radius; } void oPRCFile::addSphere(double radius, const PRCmaterial &m, PRCFACETRANSFORM) { ADDFACE(PRCSphere) SETTRANSF surface->uv_domain.min.x = 0; surface->uv_domain.max.x = 2*pi; surface->uv_domain.min.y =-0.5*pi; surface->uv_domain.max.y = 0.5*pi; surface->radius = radius; } void oPRCFile::addDisk(double radius, const PRCmaterial &m, PRCFACETRANSFORM) { ADDFACE(PRCRuled) SETTRANSF PRCCircle *first_curve = new PRCCircle; first_curve->radius = radius; surface->first_curve = first_curve; PRCCircle *second_curve = new PRCCircle; second_curve->radius = 0; surface->second_curve = second_curve; surface->uv_domain.min.x = 0; surface->uv_domain.max.x = 1; surface->uv_domain.min.y = 0; surface->uv_domain.max.y = 2*pi; surface->parameterization_on_v_coeff_a = -1; surface->parameterization_on_v_coeff_b = 2*pi; } void oPRCFile::addCylinder(double radius, double height, const PRCmaterial &m, PRCFACETRANSFORM) { ADDFACE(PRCCylinder) SETTRANSF surface->uv_domain.min.x = 0; surface->uv_domain.max.x = 2*pi; surface->uv_domain.min.y = (height>0)?0:height; surface->uv_domain.max.y = (height>0)?height:0; surface->radius = radius; } void oPRCFile::addCone(double radius, double height, const PRCmaterial &m, PRCFACETRANSFORM) { ADDFACE(PRCCone) SETTRANSF surface->uv_domain.min.x = 0; surface->uv_domain.max.x = 2*pi; surface->uv_domain.min.y = (height>0)?0:height; surface->uv_domain.max.y = (height>0)?height:0; surface->bottom_radius = radius; surface->semi_angle = -atan(radius/height);; } void oPRCFile::addTorus(double major_radius, double minor_radius, double angle1, double angle2, const PRCmaterial &m, PRCFACETRANSFORM) { ADDFACE(PRCTorus) SETTRANSF surface->uv_domain.min.x = (angle1/180)*pi; surface->uv_domain.max.x = (angle2/180)*pi; surface->uv_domain.min.y = 0; surface->uv_domain.max.y = 2*pi; surface->major_radius = major_radius; surface->minor_radius = minor_radius; } #undef ADDWIRE #undef SETTRANSF uint32_t PRCFileStructure::addMaterialGeneric(PRCMaterialGeneric*& pMaterialGeneric) { materials.push_back(pMaterialGeneric); pMaterialGeneric = NULL; return materials.size()-1; } uint32_t PRCFileStructure::addTextureApplication(PRCTextureApplication*& pTextureApplication) { materials.push_back(pTextureApplication); pTextureApplication = NULL; return materials.size()-1; } uint32_t PRCFileStructure::addStyle(PRCStyle*& pStyle) { styles.push_back(pStyle); pStyle = NULL; return styles.size()-1; } uint32_t PRCFileStructure::addPartDefinition(PRCPartDefinition*& pPartDefinition) { part_definitions.push_back(pPartDefinition); pPartDefinition = NULL; return part_definitions.size()-1; } uint32_t PRCFileStructure::addProductOccurrence(PRCProductOccurrence*& pProductOccurrence) { product_occurrences.push_back(pProductOccurrence); pProductOccurrence = NULL; return product_occurrences.size()-1; } uint32_t PRCFileStructure::addTopoContext(PRCTopoContext*& pTopoContext) { contexts.push_back(pTopoContext); pTopoContext = NULL; return contexts.size()-1; } uint32_t PRCFileStructure::getTopoContext(PRCTopoContext*& pTopoContext) { pTopoContext = new PRCTopoContext; contexts.push_back(pTopoContext); return contexts.size()-1; } uint32_t PRCFileStructure::add3DTess(PRC3DTess*& p3DTess) { tessellations.push_back(p3DTess); p3DTess = NULL; return tessellations.size()-1; } uint32_t PRCFileStructure::add3DWireTess(PRC3DWireTess*& p3DWireTess) { tessellations.push_back(p3DWireTess); p3DWireTess = NULL; return tessellations.size()-1; } /* uint32_t PRCFileStructure::addMarkupTess(PRCMarkupTess*& pMarkupTess) { tessellations.push_back(pMarkupTess); pMarkupTess = NULL; return tessellations.size()-1; } uint32_t PRCFileStructure::addMarkup(PRCMarkup*& pMarkup) { markups.push_back(pMarkup); pMarkup = NULL; return markups.size()-1; } uint32_t PRCFileStructure::addAnnotationItem(PRCAnnotationItem*& pAnnotationItem) { annotation_entities.push_back(pAnnotationItem); pAnnotationItem = NULL; return annotation_entities.size()-1; } */ uint32_t PRCFileStructure::addCoordinateSystem(PRCCoordinateSystem*& pCoordinateSystem) { reference_coordinate_systems.push_back(pCoordinateSystem); pCoordinateSystem = NULL; return reference_coordinate_systems.size()-1; } uint32_t PRCFileStructure::addCoordinateSystemUnique(PRCCoordinateSystem*& pCoordinateSystem) { for(uint32_t i = 0; i < reference_coordinate_systems.size(); ++i) { if(*(reference_coordinate_systems[i])==*pCoordinateSystem) { pCoordinateSystem = NULL; return i; } } reference_coordinate_systems.push_back(pCoordinateSystem); pCoordinateSystem = NULL; return reference_coordinate_systems.size()-1; } } asymptote-2.37/prc/oPRCFile.h000066400000000000000000001443501265434602500160500ustar00rootroot00000000000000/************ * * This file is part of a tool for producing 3D content in the PRC format. * Copyright (C) 2008 Orest Shardt and * Michail Vidiassov * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * *************/ #ifndef __O_PRC_FILE_H #define __O_PRC_FILE_H #include #include #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "PRC.h" #include "PRCbitStream.h" #include "writePRC.h" namespace prc { class oPRCFile; class PRCFileStructure; // Map [0,1] to [0,255] inline uint8_t byte(double r) { if(r < 0.0) r=0.0; else if(r > 1.0) r=1.0; int a=(int)(256.0*r); if(a == 256) a=255; return a; } struct RGBAColour { RGBAColour(double r=0.0, double g=0.0, double b=0.0, double a=1.0) : R(r), G(g), B(b), A(a) {} double R,G,B,A; void Set(double r, double g, double b, double a=1.0) { R = r; G = g; B = b; A = a; } bool operator==(const RGBAColour &c) const { return (R==c.R && G==c.G && B==c.B && A==c.A); } bool operator!=(const RGBAColour &c) const { return !(R==c.R && G==c.G && B==c.B && A==c.A); } bool operator<(const RGBAColour &c) const { if(R!=c.R) return (R PRCcolourMap; struct RGBAColourWidth { RGBAColourWidth(double r=0.0, double g=0.0, double b=0.0, double a=1.0, double w=1.0) : R(r), G(g), B(b), A(a), W(w) {} double R,G,B,A,W; bool operator==(const RGBAColourWidth &c) const { return (R==c.R && G==c.G && B==c.B && A==c.A && W==c.W); } bool operator!=(const RGBAColourWidth &c) const { return !(R==c.R && G==c.G && B==c.B && A==c.A && W==c.W); } bool operator<(const RGBAColourWidth &c) const { if(R!=c.R) return (R PRCcolourwidthMap; typedef std::map PRCcolorMap; struct PRCmaterial { PRCmaterial() : alpha(1.0),shininess(1.0), picture_data(NULL), picture_format(KEPRCPicture_BITMAP_RGB_BYTE), picture_width(0), picture_height(0), picture_size(0), picture_replace(false), picture_repeat(false) {} PRCmaterial(const RGBAColour &a, const RGBAColour &d, const RGBAColour &e, const RGBAColour &s, double p, double h, const uint8_t* pic=NULL, EPRCPictureDataFormat picf=KEPRCPicture_BITMAP_RGB_BYTE, uint32_t picw=0, uint32_t pich=0, uint32_t pics=0, bool picreplace=false, bool picrepeat=false) : ambient(a), diffuse(d), emissive(e), specular(s), alpha(p), shininess(h), picture_data(pic), picture_format(picf), picture_width(picw), picture_height(pich), picture_size(pics), picture_replace(picreplace), picture_repeat(picrepeat) { if(picture_size==0) { if (picture_format==KEPRCPicture_BITMAP_RGB_BYTE) picture_size = picture_width*picture_height*3; if (picture_format==KEPRCPicture_BITMAP_RGBA_BYTE) picture_size = picture_width*picture_height*4; if (picture_format==KEPRCPicture_BITMAP_GREY_BYTE) picture_size = picture_width*picture_height*1; if (picture_format==KEPRCPicture_BITMAP_GREYA_BYTE) picture_size = picture_width*picture_height*2; } } RGBAColour ambient,diffuse,emissive,specular; double alpha,shininess; const uint8_t* picture_data; EPRCPictureDataFormat picture_format; uint32_t picture_width; uint32_t picture_height; uint32_t picture_size; bool picture_replace; // replace material color with texture color? if false - just modify bool picture_repeat; // repeat texture? if false - clamp to edge bool operator==(const PRCmaterial &m) const { return (ambient==m.ambient && diffuse==m.diffuse && emissive==m.emissive && specular==m.specular && alpha==m.alpha && shininess==m.shininess && picture_replace==m.picture_replace && picture_repeat==m.picture_repeat && picture_format==m.picture_format && picture_width==m.picture_width && picture_height==m.picture_height && picture_size==m.picture_size && (picture_data==m.picture_data || memcmp(picture_data,m.picture_data,picture_size)==0) ); } bool operator<(const PRCmaterial &m) const { if(ambient!=m.ambient) return (ambient PRCmaterialMap; struct PRCpicture { PRCpicture() : data(NULL), format(KEPRCPicture_BITMAP_RGB_BYTE), width(0), height(0), size(0) {} PRCpicture(const uint8_t* pic, EPRCPictureDataFormat picf, uint32_t picw, uint32_t pich, uint32_t pics=0) : data(pic), format(picf), width(picw), height(pich), size(pics) { if(size==0) { if (format==KEPRCPicture_BITMAP_RGB_BYTE) size = width*height*3; if (format==KEPRCPicture_BITMAP_RGBA_BYTE) size = width*height*4; if (format==KEPRCPicture_BITMAP_GREY_BYTE) size = width*height*1; if (format==KEPRCPicture_BITMAP_GREYA_BYTE) size = width*height*2; } } PRCpicture(const PRCmaterial& m) : data(m.picture_data), format(m.picture_format), width(m.picture_width), height(m.picture_height), size(m.picture_size) {} const uint8_t* data; EPRCPictureDataFormat format; uint32_t width; uint32_t height; uint32_t size; bool operator==(const PRCpicture& p) const { return ( format==p.format && width==p.width && height==p.height && size==p.size && (data==p.data || memcmp(data,p.data,size)==0) ); } bool operator<(const PRCpicture& p) const { if(format!=p.format) return (format PRCpictureMap; struct PRCmaterialgeneric { PRCmaterialgeneric() : alpha(1.0),shininess(1.0) {} PRCmaterialgeneric(const RGBAColour& a, const RGBAColour& d, const RGBAColour& e, const RGBAColour& s, double p, double h) : ambient(a), diffuse(d), emissive(e), specular(s), alpha(p), shininess(h) {} PRCmaterialgeneric(const PRCmaterial& m) : ambient(m.ambient), diffuse(m.diffuse), emissive(m.emissive), specular(m.specular), alpha(m.alpha), shininess(m.shininess) {} RGBAColour ambient,diffuse,emissive,specular; double alpha,shininess; bool operator==(const PRCmaterialgeneric& m) const { return (ambient==m.ambient && diffuse==m.diffuse && emissive==m.emissive && specular==m.specular && alpha==m.alpha && shininess==m.shininess); } bool operator<(const PRCmaterialgeneric& m) const { if(ambient!=m.ambient) return (ambient PRCmaterialgenericMap; struct PRCtexturedefinition { PRCtexturedefinition() : picture_index(m1), picture_replace(false), picture_repeat(false) {} PRCtexturedefinition(uint32_t picindex, bool picreplace=false, bool picrepeat=false) : picture_index(picindex), picture_replace(picreplace), picture_repeat(picrepeat) {} PRCtexturedefinition(uint32_t picindex, const PRCmaterial& m) : picture_index(picindex), picture_replace(m.picture_replace), picture_repeat(m.picture_repeat) {} uint32_t picture_index; bool picture_replace; // replace material color with texture color? if false - just modify bool picture_repeat; // repeat texture? if false - clamp to edge bool operator==(const PRCtexturedefinition& t) const { return (picture_index==t.picture_index && picture_replace==t.picture_replace && picture_repeat==t.picture_repeat); } bool operator<(const PRCtexturedefinition& t) const { if(picture_index!=t.picture_index) return (picture_index PRCtexturedefinitionMap; struct PRCtextureapplication { PRCtextureapplication() : material_generic_index(m1), texture_definition_index(m1) {} PRCtextureapplication(uint32_t matindex, uint32_t texindex) : material_generic_index(matindex), texture_definition_index(texindex) {} uint32_t material_generic_index; uint32_t texture_definition_index; bool operator==(const PRCtextureapplication& t) const { return (material_generic_index==t.material_generic_index && texture_definition_index==t.texture_definition_index); } bool operator<(const PRCtextureapplication& t) const { if(material_generic_index!=t.material_generic_index) return (material_generic_index PRCtextureapplicationMap; struct PRCstyle { PRCstyle() : line_width(0), alpha(1), is_material(false), color_material_index(m1) {} PRCstyle(double linewidth, double alph, bool ismat, uint32_t colindex=m1) : line_width(linewidth), alpha(alph), is_material(ismat), color_material_index(colindex) {} double line_width; double alpha; bool is_material; uint32_t color_material_index; bool operator==(const PRCstyle& s) const { return (line_width==s.line_width && alpha==s.alpha && is_material==s.is_material && color_material_index==s.color_material_index); } bool operator<(const PRCstyle& s) const { if(line_width!=s.line_width) return (line_width PRCstyleMap; struct PRCtessrectangle // rectangle { PRCVector3d vertices[4]; uint32_t style; }; typedef std::vector PRCtessrectangleList; struct PRCtessquad // rectangle { PRCVector3d vertices[4]; RGBAColour colours[4]; }; typedef std::vector PRCtessquadList; /* struct PRCtesstriangle // textured triangle { PRCtesstriangle() : style(m1) {} PRCVector3d vertices[3]; // PRCVector3d normals[3]; // RGBAColour colors[3]; PRCVector2d texcoords[3]; uint32_t style; }; typedef std::vector PRCtesstriangleList; */ struct PRCtessline // polyline { std::vector point; PRCRgbColor color; }; typedef std::list PRCtesslineList; typedef std::map PRCtesslineMap; struct PRCface { PRCface() : transform(NULL), face(NULL) {} uint32_t style; bool transparent; PRCGeneralTransformation3d* transform; PRCFace* face; }; typedef std::vector PRCfaceList; struct PRCcompface { PRCcompface() : face(NULL) {} uint32_t style; bool transparent; PRCCompressedFace* face; }; typedef std::vector PRCcompfaceList; struct PRCwire { PRCwire() : style(m1), transform(NULL), curve(NULL) {} uint32_t style; PRCGeneralTransformation3d* transform; PRCCurve* curve; }; typedef std::vector PRCwireList; typedef std::map > PRCpointsetMap; class PRCoptions { public: double compression; double granularity; bool closed; // render the surface as one-sided; may yield faster rendering bool tess; // use tessellated mesh to store straight patches bool do_break; // bool no_break; // do not render transparent patches as one-faced nodes double crease_angle; // crease angle for meshes PRCoptions(double compression=0.0, double granularity=0.0, bool closed=false, bool tess=false, bool do_break=true, bool no_break=false, double crease_angle=25.8419) : compression(compression), granularity(granularity), closed(closed), tess(tess), do_break(do_break), no_break(no_break), crease_angle(crease_angle) {} }; class PRCgroup { public: PRCgroup() : product_occurrence(NULL), parent_product_occurrence(NULL), part_definition(NULL), parent_part_definition(NULL), transform(NULL) {} PRCgroup(const std::string& name) : product_occurrence(NULL), parent_product_occurrence(NULL), part_definition(NULL), parent_part_definition(NULL), transform(NULL), name(name) {} PRCProductOccurrence *product_occurrence, *parent_product_occurrence; PRCPartDefinition *part_definition, *parent_part_definition; PRCfaceList faces; PRCcompfaceList compfaces; PRCtessrectangleList rectangles; // PRCtesstriangleList triangles; PRCtessquadList quads; PRCtesslineMap lines; PRCwireList wires; PRCpointsetMap points; std::vector pointsets; std::vector polymodels; std::vector polywires; PRCGeneralTransformation3d* transform; std::string name; PRCoptions options; }; void makeFileUUID(PRCUniqueId&); void makeAppUUID(PRCUniqueId&); class PRCUncompressedFile { public: PRCUncompressedFile() : file_size(0), data(NULL) {} PRCUncompressedFile(uint32_t fs, uint8_t *d) : file_size(fs), data(d) {} ~PRCUncompressedFile() { if(data != NULL) delete[] data; } uint32_t file_size; uint8_t *data; void write(std::ostream&) const; uint32_t getSize() const; }; typedef std::deque PRCUncompressedFileList; class PRCStartHeader { public: uint32_t minimal_version_for_read; // PRCVersion uint32_t authoring_version; // PRCVersion PRCUniqueId file_structure_uuid; PRCUniqueId application_uuid; // should be 0 PRCStartHeader() : minimal_version_for_read(PRCVersion), authoring_version(PRCVersion) {} void serializeStartHeader(std::ostream&) const; uint32_t getStartHeaderSize() const; }; class PRCFileStructure : public PRCStartHeader { public: uint32_t number_of_referenced_file_structures; double tessellation_chord_height_ratio; double tessellation_angle_degree; std::string default_font_family_name; std::vector colors; std::vector pictures; PRCUncompressedFileList uncompressed_files; PRCTextureDefinitionList texture_definitions; PRCMaterialList materials; PRCStyleList styles; PRCCoordinateSystemList reference_coordinate_systems; std::vector font_keys_of_font; PRCPartDefinitionList part_definitions; PRCProductOccurrenceList product_occurrences; // PRCMarkupList markups; // PRCAnnotationItemList annotation_entities; double unit; PRCTopoContextList contexts; PRCTessList tessellations; uint32_t sizes[6]; uint8_t *globals_data; PRCbitStream globals_out; // order matters: PRCbitStream must be initialized last uint8_t *tree_data; PRCbitStream tree_out; uint8_t *tessellations_data; PRCbitStream tessellations_out; uint8_t *geometry_data; PRCbitStream geometry_out; uint8_t *extraGeometry_data; PRCbitStream extraGeometry_out; ~PRCFileStructure () { for(PRCUncompressedFileList::iterator it=uncompressed_files.begin(); it!=uncompressed_files.end(); ++it) delete *it; for(PRCTextureDefinitionList::iterator it=texture_definitions.begin(); it!=texture_definitions.end(); ++it) delete *it; for(PRCMaterialList::iterator it=materials.begin(); it!=materials.end(); ++it) delete *it; for(PRCStyleList::iterator it=styles.begin(); it!=styles.end(); ++it) delete *it; for(PRCTopoContextList::iterator it=contexts.begin(); it!=contexts.end(); ++it) delete *it; for(PRCTessList::iterator it=tessellations.begin(); it!=tessellations.end(); ++it) delete *it; for(PRCPartDefinitionList::iterator it=part_definitions.begin(); it!=part_definitions.end(); ++it) delete *it; for(PRCProductOccurrenceList::iterator it=product_occurrences.begin(); it!=product_occurrences.end(); ++it) delete *it; for(PRCCoordinateSystemList::iterator it=reference_coordinate_systems.begin(); it!=reference_coordinate_systems.end(); it++) delete *it; free(globals_data); free(tree_data); free(tessellations_data); free(geometry_data); free(extraGeometry_data); } PRCFileStructure() : number_of_referenced_file_structures(0), tessellation_chord_height_ratio(2000.0),tessellation_angle_degree(40.0), default_font_family_name(""), unit(1), globals_data(NULL),globals_out(globals_data,0), tree_data(NULL),tree_out(tree_data,0), tessellations_data(NULL),tessellations_out(tessellations_data,0), geometry_data(NULL),geometry_out(geometry_data,0), extraGeometry_data(NULL),extraGeometry_out(extraGeometry_data,0) {} void write(std::ostream&); void prepare(); uint32_t getSize(); void serializeFileStructureGlobals(PRCbitStream&); void serializeFileStructureTree(PRCbitStream&); void serializeFileStructureTessellation(PRCbitStream&); void serializeFileStructureGeometry(PRCbitStream&); void serializeFileStructureExtraGeometry(PRCbitStream&); uint32_t addPicture(EPRCPictureDataFormat format, uint32_t size, const uint8_t *picture, uint32_t width=0, uint32_t height=0, std::string name=""); uint32_t addTextureDefinition(PRCTextureDefinition*& pTextureDefinition); uint32_t addRgbColor(const PRCRgbColor &color); uint32_t addRgbColorUnique(const PRCRgbColor &color); uint32_t addMaterialGeneric(PRCMaterialGeneric*& pMaterialGeneric); uint32_t addTextureApplication(PRCTextureApplication*& pTextureApplication); uint32_t addStyle(PRCStyle*& pStyle); uint32_t addPartDefinition(PRCPartDefinition*& pPartDefinition); uint32_t addProductOccurrence(PRCProductOccurrence*& pProductOccurrence); uint32_t addTopoContext(PRCTopoContext*& pTopoContext); uint32_t getTopoContext(PRCTopoContext*& pTopoContext); uint32_t add3DTess(PRC3DTess*& p3DTess); uint32_t add3DWireTess(PRC3DWireTess*& p3DWireTess); /* uint32_t addMarkupTess(PRCMarkupTess*& pMarkupTess); uint32_t addMarkup(PRCMarkup*& pMarkup); uint32_t addAnnotationItem(PRCAnnotationItem*& pAnnotationItem); */ uint32_t addCoordinateSystem(PRCCoordinateSystem*& pCoordinateSystem); uint32_t addCoordinateSystemUnique(PRCCoordinateSystem*& pCoordinateSystem); }; class PRCFileStructureInformation { public: PRCUniqueId UUID; uint32_t reserved; // 0 uint32_t number_of_offsets; uint32_t *offsets; void write(std::ostream&); uint32_t getSize(); }; class PRCHeader : public PRCStartHeader { public : uint32_t number_of_file_structures; PRCFileStructureInformation *fileStructureInformation; uint32_t model_file_offset; uint32_t file_size; // not documented PRCUncompressedFileList uncompressed_files; void write(std::ostream&); uint32_t getSize(); }; typedef std::map PRCtransformMap; inline double X(const double *v) {return v[0];} inline double Y(const double *v) {return v[1];} inline double Z(const double *v) {return v[2];} class oPRCFile { public: oPRCFile(std::ostream &os, double u=1, uint32_t n=1) : number_of_file_structures(n), fileStructures(new PRCFileStructure*[n]), unit(u), modelFile_data(NULL),modelFile_out(modelFile_data,0), fout(NULL),output(os) { for(uint32_t i = 0; i < number_of_file_structures; ++i) { fileStructures[i] = new PRCFileStructure(); fileStructures[i]->minimal_version_for_read = PRCVersion; fileStructures[i]->authoring_version = PRCVersion; makeFileUUID(fileStructures[i]->file_structure_uuid); makeAppUUID(fileStructures[i]->application_uuid); fileStructures[i]->unit = u; } groups.push(PRCgroup()); PRCgroup &group = groups.top(); group.name="root"; group.transform = NULL; group.product_occurrence = new PRCProductOccurrence(group.name); group.parent_product_occurrence = NULL; group.part_definition = new PRCPartDefinition; group.parent_part_definition = NULL; } oPRCFile(const std::string &name, double u=1, uint32_t n=1) : number_of_file_structures(n), fileStructures(new PRCFileStructure*[n]), unit(u), modelFile_data(NULL),modelFile_out(modelFile_data,0), fout(new std::ofstream(name.c_str(), std::ios::out|std::ios::binary|std::ios::trunc)), output(*fout) { for(uint32_t i = 0; i < number_of_file_structures; ++i) { fileStructures[i] = new PRCFileStructure(); fileStructures[i]->minimal_version_for_read = PRCVersion; fileStructures[i]->authoring_version = PRCVersion; makeFileUUID(fileStructures[i]->file_structure_uuid); makeAppUUID(fileStructures[i]->application_uuid); fileStructures[i]->unit = u; } groups.push(PRCgroup()); PRCgroup &group = groups.top(); group.name="root"; group.transform = NULL; group.product_occurrence = new PRCProductOccurrence(group.name); group.parent_product_occurrence = NULL; group.part_definition = new PRCPartDefinition; group.parent_part_definition = NULL; } ~oPRCFile() { for(uint32_t i = 0; i < number_of_file_structures; ++i) delete fileStructures[i]; delete[] fileStructures; if(fout != NULL) delete fout; free(modelFile_data); for(PRCpictureMap::iterator it=pictureMap.begin(); it!=pictureMap.end(); ++it) delete it->first.data; } void begingroup(const char *name, PRCoptions *options=NULL, const double* t=NULL); void endgroup(); std::string lastgroupname; std::vector lastgroupnames; std::string calculate_unique_name(const ContentPRCBase *prc_entity,const ContentPRCBase *prc_occurence); bool finish(); uint32_t getSize(); const uint32_t number_of_file_structures; PRCFileStructure **fileStructures; PRCHeader header; PRCUnit unit; uint8_t *modelFile_data; PRCbitStream modelFile_out; // order matters: PRCbitStream must be initialized last PRCcolorMap colorMap; PRCcolourMap colourMap; PRCcolourwidthMap colourwidthMap; PRCmaterialgenericMap materialgenericMap; PRCtexturedefinitionMap texturedefinitionMap; PRCtextureapplicationMap textureapplicationMap; PRCstyleMap styleMap; PRCpictureMap pictureMap; PRCgroup rootGroup; PRCtransformMap transformMap; std::stack groups; PRCgroup& findGroup(); void doGroup(PRCgroup& group); uint32_t addColor(const PRCRgbColor &color); uint32_t addColour(const RGBAColour &colour); uint32_t addColourWidth(const RGBAColour &colour, double width); uint32_t addLineMaterial(const RGBAColour& c, double width) { return addColourWidth(c,width); } uint32_t addMaterial(const PRCmaterial &material); uint32_t addTransform(PRCGeneralTransformation3d*& transform); uint32_t addTransform(const double* t); uint32_t addTransform(const double origin[3], const double x_axis[3], const double y_axis[3], double scale); template void addPoint(const V P, const RGBAColour &c, double w=1.0) { PRCgroup &group = findGroup(); group.points[addColourWidth(c,w)].push_back(PRCVector3d(X(P),Y(P),Z(P))); } void addPoints(uint32_t n, const double P[][3], const RGBAColour &c, double w=1.0); void addLines(uint32_t nP, const double P[][3], uint32_t nI, const uint32_t PI[], const RGBAColour& c, double w, bool segment_color, uint32_t nC, const RGBAColour C[], uint32_t nCI, const uint32_t CI[]); uint32_t createLines(uint32_t nP, const double P[][3], uint32_t nI, const uint32_t PI[], bool segment_color, uint32_t nC, const RGBAColour C[], uint32_t nCI, const uint32_t CI[]); template void addTriangles(uint32_t nP, const V P[], uint32_t nI, const uint32_t PI[][3], const PRCmaterial &m, uint32_t nN, const V N[], const uint32_t NI[][3], uint32_t nT, const double T[][2], const uint32_t TI[][3], uint32_t nC, const RGBAColour C[], const uint32_t CI[][3], uint32_t nM, const PRCmaterial M[], const uint32_t MI[], double ca) { if(nP==0 || P==NULL || nI==0 || PI==NULL) return; const uint32_t tess_index = createTriangleMesh(nP, P, nI, PI, m, nN, N, NI, nT, T, TI, nC, C, CI, nM, M, MI, ca); useMesh(tess_index,m1); } template uint32_t createTriangleMesh(uint32_t nP, const V P[], uint32_t nI, const uint32_t PI[][3], const PRCmaterial& m, uint32_t nN, const V N[], const uint32_t NI[][3], uint32_t nT, const double T[][2], const uint32_t TI[][3], uint32_t nC, const RGBAColour C[], const uint32_t CI[][3], uint32_t nM, const PRCmaterial M[], const uint32_t MI[], double ca) { const uint32_t style = addMaterial(m); if(M!=NULL && nM>0) { uint32_t* const styles = new uint32_t[nM]; for(uint32_t i=0; i uint32_t createTriangleMesh(uint32_t nP, const V P[], uint32_t nI, const uint32_t PI[][3], const uint32_t style_index, uint32_t nN, const V N[], const uint32_t NI[][3], uint32_t nT, const double T[][2], const uint32_t TI[][3], uint32_t nC, const RGBAColour C[], const uint32_t CI[][3], uint32_t nS, const uint32_t S[], const uint32_t SI[], double ca) { if(nP==0 || P==NULL || nI==0 || PI==NULL) return m1; const bool triangle_color = (nS != 0 && S != NULL && SI != NULL); const bool vertex_color = (nC != 0 && C != NULL && CI != NULL); const bool has_normals = (nN != 0 && N != NULL && NI != NULL); const bool textured = (nT != 0 && T != NULL && TI != NULL); PRC3DTess *tess = new PRC3DTess(); PRCTessFace *tessFace = new PRCTessFace(); tessFace->used_entities_flag = textured ? PRC_FACETESSDATA_TriangleTextured : PRC_FACETESSDATA_Triangle; tessFace->number_of_texture_coordinate_indexes = textured ? 1 : 0; tess->coordinates.reserve(3*nP); for(uint32_t i=0; icoordinates.push_back(X(P[i])); tess->coordinates.push_back(Y(P[i])); tess->coordinates.push_back(Z(P[i])); } if(has_normals) { tess->normal_coordinate.reserve(3*nN); for(uint32_t i=0; inormal_coordinate.push_back(X(N[i])); tess->normal_coordinate.push_back(Y(N[i])); tess->normal_coordinate.push_back(Z(N[i])); } } else tess->crease_angle = ca; if(textured) { tess->texture_coordinate.reserve(2*nT); for(uint32_t i=0; itexture_coordinate.push_back(T[i][0]); tess->texture_coordinate.push_back(T[i][1]); } } tess->triangulated_index.reserve(3*nI+(has_normals?3:0)*nI+(textured?3:0)*nI); for(uint32_t i=0; itriangulated_index.push_back(3*NI[i][0]); if(textured) tess->triangulated_index.push_back(2*TI[i][0]); tess->triangulated_index.push_back(3*PI[i][0]); if(has_normals) tess->triangulated_index.push_back(3*NI[i][1]); if(textured) tess->triangulated_index.push_back(2*TI[i][1]); tess->triangulated_index.push_back(3*PI[i][1]); if(has_normals) tess->triangulated_index.push_back(3*NI[i][2]); if(textured) tess->triangulated_index.push_back(2*TI[i][2]); tess->triangulated_index.push_back(3*PI[i][2]); } tessFace->sizes_triangulated.push_back(nI); if(triangle_color) { tessFace->line_attributes.reserve(nI); for(uint32_t i=0; iline_attributes.push_back(SI[i]); } else if (style_index != m1 ) { tessFace->line_attributes.push_back(style_index); } if(vertex_color) { tessFace->is_rgba=false; for(uint32_t i=0; iis_rgba=true; break; } tessFace->rgba_vertices.reserve((tessFace->is_rgba?4:3)*3*nI); for(uint32_t i=0; irgba_vertices.push_back(byte(C[CI[i][0]].R)); tessFace->rgba_vertices.push_back(byte(C[CI[i][0]].G)); tessFace->rgba_vertices.push_back(byte(C[CI[i][0]].B)); if(tessFace->is_rgba) tessFace->rgba_vertices.push_back(byte(C[CI[i][0]].A)); tessFace->rgba_vertices.push_back(byte(C[CI[i][1]].R)); tessFace->rgba_vertices.push_back(byte(C[CI[i][1]].G)); tessFace->rgba_vertices.push_back(byte(C[CI[i][1]].B)); if(tessFace->is_rgba) tessFace->rgba_vertices.push_back(byte(C[CI[i][1]].A)); tessFace->rgba_vertices.push_back(byte(C[CI[i][2]].R)); tessFace->rgba_vertices.push_back(byte(C[CI[i][2]].G)); tessFace->rgba_vertices.push_back(byte(C[CI[i][2]].B)); if(tessFace->is_rgba) tessFace->rgba_vertices.push_back(byte(C[CI[i][2]].A)); } } tess->addTessFace(tessFace); const uint32_t tess_index = add3DTess(tess); return tess_index; } void addQuads(uint32_t nP, const double P[][3], uint32_t nI, const uint32_t PI[][4], const PRCmaterial &m, uint32_t nN, const double N[][3], const uint32_t NI[][4], uint32_t nT, const double T[][2], const uint32_t TI[][4], uint32_t nC, const RGBAColour C[], const uint32_t CI[][4], uint32_t nM, const PRCmaterial M[], const uint32_t MI[], double ca); uint32_t createQuadMesh(uint32_t nP, const double P[][3], uint32_t nI, const uint32_t PI[][4], uint32_t style_index, uint32_t nN, const double N[][3], const uint32_t NI[][4], uint32_t nT, const double T[][2], const uint32_t TI[][4], uint32_t nC, const RGBAColour C[], const uint32_t CI[][4], uint32_t nS, const uint32_t S[], const uint32_t SI[], double ca); uint32_t createQuadMesh(uint32_t nP, const double P[][3], uint32_t nI, const uint32_t PI[][4], const PRCmaterial& m, uint32_t nN, const double N[][3], const uint32_t NI[][4], uint32_t nT, const double T[][2], const uint32_t TI[][4], uint32_t nC, const RGBAColour C[], const uint32_t CI[][4], uint32_t nM, const PRCmaterial M[], const uint32_t MI[], double ca) { const uint32_t style = addMaterial(m); if(M!=NULL && nM>0) { uint32_t* const styles = new uint32_t[nM]; for(uint32_t i=0; ibase_surface = surface; \ face.transparent = m.alpha < 1.0; \ face.style = addMaterial(m); #define ADDCOMPFACE \ PRCgroup &group = findGroup(); \ group.compfaces.push_back(PRCcompface()); \ PRCcompface& face = group.compfaces.back(); \ PRCCompressedFace *compface = new PRCCompressedFace; \ face.face = compface; \ face.transparent = m.alpha < 1.0; \ face.style = addMaterial(m); inline bool isid(const double* t) { return( t[0]==1 && t[1]==0 && t[2]==0 && t[3]==0 && t[4]==0 && t[5]==1 && t[6]==0 && t[7]==0 && t[8]==0 && t[9]==0 && t[10]==1 && t[11]==0 && t[12]==0 && t[13]==0 && t[14]==0 && t[15]==1); } #define SETTRANSF \ if(t&&!isid(t)) \ face.transform = new PRCGeneralTransformation3d(t); \ if(origin) surface->origin.Set(origin[0],origin[1],origin[2]); \ if(x_axis) surface->x_axis.Set(x_axis[0],x_axis[1],x_axis[2]); \ if(y_axis) surface->y_axis.Set(y_axis[0],y_axis[1],y_axis[2]); \ surface->scale = scale; \ surface->geometry_is_2D = false; \ if(surface->origin!=PRCVector3d(0.0,0.0,0.0)) \ surface->behaviour = surface->behaviour | PRC_TRANSFORMATION_Translate; \ if(surface->x_axis!=PRCVector3d(1.0,0.0,0.0)||surface->y_axis!=PRCVector3d(0.0,1.0,0.0)) \ surface->behaviour = surface->behaviour | PRC_TRANSFORMATION_Rotate; \ if(surface->scale!=1) \ surface->behaviour = surface->behaviour | PRC_TRANSFORMATION_Scale; \ surface->has_transformation = (surface->behaviour != PRC_TRANSFORMATION_Identity); void useMesh(uint32_t tess_index, uint32_t style_index, PRCGENTRANSFORM); void useMesh(uint32_t tess_index, const PRCmaterial& m, PRCGENTRANSFORM) { useMesh(tess_index,addMaterial(m),t); } void useMesh(uint32_t tess_index, uint32_t style_index, PRCCARTRANSFORM); void useMesh(uint32_t tess_index, const PRCmaterial& m, PRCCARTRANSFORM) { useMesh(tess_index,addMaterial(m),origin, x_axis, y_axis, scale); } void useLines(uint32_t tess_index, uint32_t style_index, PRCGENTRANSFORM); void useLines(uint32_t tess_index, const RGBAColour& c, double w, PRCGENTRANSFORM) { useLines(tess_index, addLineMaterial(c,w), t); } void useLines(uint32_t tess_index, uint32_t style_index, PRCCARTRANSFORM); void useLines(uint32_t tess_index, const RGBAColour& c, double w, PRCCARTRANSFORM) { useLines(tess_index,addLineMaterial(c,w),origin, x_axis, y_axis, scale); } // void addTriangle(const double P[][3], const double T[][2], uint32_t style_index); template void addLine(uint32_t n, const V P[], const RGBAColour &c, double w=1.0) { PRCgroup &group = findGroup(); if(group.options.tess) { group.lines[w].push_back(PRCtessline()); PRCtessline& line = group.lines[w].back(); line.color.red = c.R; line.color.green = c.G; line.color.blue = c.B; for(uint32_t i=0; ipoint.resize(n); for(uint32_t i=0; ipoint[i].Set(X(P[i]),Y(P[i]),Z(P[i])); curve->interval.min = 0; curve->interval.max = curve->point.size()-1; } } template void addBezierCurve(uint32_t n, const V cP[], const RGBAColour &c) { ADDWIRE(PRCNURBSCurve) curve->is_rational = false; curve->degree = 3; const size_t NUMBER_OF_POINTS = n; curve->control_point.resize(NUMBER_OF_POINTS); for(size_t i = 0; i < NUMBER_OF_POINTS; ++i) curve->control_point[i].Set(X(cP[i]),Y(cP[i]),Z(cP[i])); curve->knot.resize(3+NUMBER_OF_POINTS+1); curve->knot[0] = 1; for(size_t i = 1; i < 3+NUMBER_OF_POINTS; ++i) curve->knot[i] = (i+2)/3; // integer division is intentional curve->knot[3+NUMBER_OF_POINTS] = (3+NUMBER_OF_POINTS+1)/3; } template void addCurve(uint32_t d, uint32_t n, const V cP[], const double *k, const RGBAColour &c, const double w[]) { ADDWIRE(PRCNURBSCurve) curve->is_rational = (w!=NULL); curve->degree = d; curve->control_point.resize(n); for(uint32_t i = 0; i < n; i++) if(w) curve->control_point[i].Set(X(cP[i])*w[i],Y(cP[i])*w[i],Z(cP[i])*w[i], w[i]); else curve->control_point[i].Set(X(cP[i]),Y(cP[i]),Z(cP[i])); curve->knot.resize(d+n+1); for(uint32_t i = 0; i < d+n+1; i++) curve->knot[i] = k[i]; } template void addQuad(const V P[], const RGBAColour C[]) { PRCgroup &group = findGroup(); group.quads.push_back(PRCtessquad()); PRCtessquad &quad = group.quads.back(); for(size_t i = 0; i < 4; i++) { quad.vertices[i].x = X(P[i]); quad.vertices[i].y = Y(P[i]); quad.vertices[i].z = Z(P[i]); quad.colours[i] = C[i]; } } template void addRectangle(const V P[], const PRCmaterial &m) { PRCgroup &group = findGroup(); if(group.options.tess) { group.rectangles.push_back(PRCtessrectangle()); PRCtessrectangle &rectangle = group.rectangles.back(); rectangle.style = addMaterial(m); for(size_t i = 0; i < 4; i++) { rectangle.vertices[i].x = X(P[i]); rectangle.vertices[i].y = Y(P[i]); rectangle.vertices[i].z = Z(P[i]); } } else if(group.options.compression == 0.0) { ADDFACE(PRCNURBSSurface) surface->is_rational = false; surface->degree_in_u = 1; surface->degree_in_v = 1; surface->control_point.resize(4); for(size_t i = 0; i < 4; ++i) { surface->control_point[i].x = X(P[i]); surface->control_point[i].y = Y(P[i]); surface->control_point[i].z = Z(P[i]); } surface->knot_u.resize(4); surface->knot_v.resize(4); surface->knot_v[0] = surface->knot_u[0] = 1; surface->knot_v[1] = surface->knot_u[1] = 3; surface->knot_v[2] = surface->knot_u[2] = 4; surface->knot_v[3] = surface->knot_u[3] = 4; } else { ADDCOMPFACE compface->degree = 1; compface->control_point.resize(4); for(size_t i = 0; i < 4; ++i) { compface->control_point[i].x = X(P[i]); compface->control_point[i].y = Y(P[i]); compface->control_point[i].z = Z(P[i]); } } } template void addPatch(const V cP[], const PRCmaterial &m) { PRCgroup &group = findGroup(); if(group.options.compression == 0.0) { ADDFACE(PRCNURBSSurface) surface->is_rational = false; surface->degree_in_u = 3; surface->degree_in_v = 3; surface->control_point.resize(16); for(size_t i = 0; i < 16; ++i) { surface->control_point[i].x = X(cP[i]); surface->control_point[i].y = Y(cP[i]); surface->control_point[i].z = Z(cP[i]); } surface->knot_u.resize(8); surface->knot_v.resize(8); surface->knot_v[0] = surface->knot_u[0] = 1; surface->knot_v[1] = surface->knot_u[1] = 1; surface->knot_v[2] = surface->knot_u[2] = 1; surface->knot_v[3] = surface->knot_u[3] = 1; surface->knot_v[4] = surface->knot_u[4] = 2; surface->knot_v[5] = surface->knot_u[5] = 2; surface->knot_v[6] = surface->knot_u[6] = 2; surface->knot_v[7] = surface->knot_u[7] = 2; } else { ADDCOMPFACE compface->degree = 3; compface->control_point.resize(16); for(size_t i = 0; i < 16; ++i) { compface->control_point[i].x = X(cP[i]); compface->control_point[i].y = Y(cP[i]); compface->control_point[i].z = Z(cP[i]); } } } template void addSurface(uint32_t dU, uint32_t dV, uint32_t nU, uint32_t nV, const V cP[], const double *kU, const double *kV, const PRCmaterial &m, const double w[]) { ADDFACE(PRCNURBSSurface) surface->is_rational = (w!=NULL); surface->degree_in_u = dU; surface->degree_in_v = dV; surface->control_point.resize(nU*nV); for(size_t i = 0; i < nU*nV; i++) if(w) surface->control_point[i]=PRCControlPoint(X(cP[i])*w[i],Y(cP[i])*w[i],Z(cP[i])*w[i],w[i]); else surface->control_point[i]=PRCControlPoint(X(cP[i]),Y(cP[i]),Z(cP[i])); surface->knot_u.insert(surface->knot_u.end(), kU, kU+(dU+nU+1)); surface->knot_v.insert(surface->knot_v.end(), kV, kV+(dV+nV+1)); } template void addTube(uint32_t n, const V cP[], const V oP[], bool straight, const PRCmaterial &m, PRCTRANSFORM) { ADDFACE(PRCBlend01) SETTRANSF if(straight) { PRCPolyLine *center_curve = new PRCPolyLine; center_curve->point.resize(n); for(uint32_t i=0; ipoint[i].Set(X(cP[i]),Y(cP[i]),Z(cP[i])); center_curve->interval.min = 0; center_curve->interval.max = center_curve->point.size()-1; surface->center_curve = center_curve; PRCPolyLine *origin_curve = new PRCPolyLine; origin_curve->point.resize(n); for(uint32_t i=0; ipoint[i].Set(X(oP[i]),Y(oP[i]),Z(oP[i])); origin_curve->interval.min = 0; origin_curve->interval.max = origin_curve->point.size()-1; surface->origin_curve = origin_curve; surface->uv_domain.min.x = 0; surface->uv_domain.max.x = 2*pi; surface->uv_domain.min.y = 0; surface->uv_domain.max.y = n-1; } else { PRCNURBSCurve *center_curve = new PRCNURBSCurve; center_curve->is_rational = false; center_curve->degree = 3; const uint32_t CENTER_NUMBER_OF_POINTS = n; center_curve->control_point.resize(CENTER_NUMBER_OF_POINTS); for(uint32_t i = 0; i < CENTER_NUMBER_OF_POINTS; ++i) center_curve->control_point[i].Set(X(cP[i]),Y(cP[i]),Z(cP[i])); center_curve->knot.resize(3+CENTER_NUMBER_OF_POINTS+1); center_curve->knot[0] = 1; for(uint32_t i = 1; i < 3+CENTER_NUMBER_OF_POINTS; ++i) center_curve->knot[i] = (i+2)/3; // integer division is intentional center_curve->knot[3+CENTER_NUMBER_OF_POINTS] = (3+CENTER_NUMBER_OF_POINTS+1)/3; surface->center_curve = center_curve; PRCNURBSCurve *origin_curve = new PRCNURBSCurve; origin_curve->is_rational = false; origin_curve->degree = 3; const uint32_t ORIGIN_NUMBER_OF_POINTS = n; origin_curve->control_point.resize(ORIGIN_NUMBER_OF_POINTS); for(uint32_t i = 0; i < ORIGIN_NUMBER_OF_POINTS; ++i) origin_curve->control_point[i].Set(X(oP[i]),Y(oP[i]),Z(oP[i])); origin_curve->knot.resize(3+ORIGIN_NUMBER_OF_POINTS+1); origin_curve->knot[0] = 1; for(size_t i = 1; i < 3+ORIGIN_NUMBER_OF_POINTS; ++i) origin_curve->knot[i] = (i+2)/3; // integer division is intentional origin_curve->knot[3+ORIGIN_NUMBER_OF_POINTS] = (3+ORIGIN_NUMBER_OF_POINTS+1)/3; surface->origin_curve = origin_curve; surface->uv_domain.min.x = 0; surface->uv_domain.max.x = 2*pi; surface->uv_domain.min.y = 1; // first knot surface->uv_domain.max.y = (3+CENTER_NUMBER_OF_POINTS+1)/3; // last knot } } void addHemisphere(double radius, const PRCmaterial& m, PRCTRANSFORM); void addSphere(double radius, const PRCmaterial& m, PRCTRANSFORM); void addDisk(double radius, const PRCmaterial& m, PRCTRANSFORM); void addCylinder(double radius, double height, const PRCmaterial& m, PRCTRANSFORM); void addCone(double radius, double height, const PRCmaterial& m, PRCTRANSFORM); void addTorus(double major_radius, double minor_radius, double angle1, double angle2, const PRCmaterial& m, PRCTRANSFORM); #undef PRCTRANSFORM #undef PRCCARTRANSFORM #undef PRCGENTRANSFORM #undef ADDCOMPFACE uint32_t addPicture(EPRCPictureDataFormat format, uint32_t size, const uint8_t *picture, uint32_t width=0, uint32_t height=0, std::string name="", uint32_t fileStructure=0) { return fileStructures[fileStructure]->addPicture(format, size, picture, width, height, name); } uint32_t addPicture(const PRCpicture& pic, std::string name="", uint32_t fileStructure=0) { return fileStructures[fileStructure]->addPicture(pic.format, pic.size, pic.data, pic.width, pic.height, name); } uint32_t addTextureDefinition(PRCTextureDefinition*& pTextureDefinition, uint32_t fileStructure=0) { return fileStructures[fileStructure]->addTextureDefinition(pTextureDefinition); } uint32_t addTextureApplication(PRCTextureApplication*& pTextureApplication, uint32_t fileStructure=0) { return fileStructures[fileStructure]->addTextureApplication(pTextureApplication); } uint32_t addRgbColor(const PRCRgbColor &color, uint32_t fileStructure=0) { return fileStructures[fileStructure]->addRgbColor(color); } uint32_t addRgbColorUnique(const PRCRgbColor &color, uint32_t fileStructure=0) { return fileStructures[fileStructure]->addRgbColorUnique(color); } uint32_t addMaterialGeneric(PRCMaterialGeneric*& pMaterialGeneric, uint32_t fileStructure=0) { return fileStructures[fileStructure]->addMaterialGeneric(pMaterialGeneric); } uint32_t addStyle(PRCStyle*& pStyle, uint32_t fileStructure=0) { return fileStructures[fileStructure]->addStyle(pStyle); } uint32_t addPartDefinition(PRCPartDefinition*& pPartDefinition, uint32_t fileStructure=0) { return fileStructures[fileStructure]->addPartDefinition(pPartDefinition); } uint32_t addProductOccurrence(PRCProductOccurrence*& pProductOccurrence, uint32_t fileStructure=0) { return fileStructures[fileStructure]->addProductOccurrence(pProductOccurrence); } uint32_t addTopoContext(PRCTopoContext*& pTopoContext, uint32_t fileStructure=0) { return fileStructures[fileStructure]->addTopoContext(pTopoContext); } uint32_t getTopoContext(PRCTopoContext*& pTopoContext, uint32_t fileStructure=0) { return fileStructures[fileStructure]->getTopoContext(pTopoContext); } uint32_t add3DTess(PRC3DTess*& p3DTess, uint32_t fileStructure=0) { return fileStructures[fileStructure]->add3DTess(p3DTess); } uint32_t add3DWireTess(PRC3DWireTess*& p3DWireTess, uint32_t fileStructure=0) { return fileStructures[fileStructure]->add3DWireTess(p3DWireTess); } /* uint32_t addMarkupTess(PRCMarkupTess*& pMarkupTess, uint32_t fileStructure=0) { return fileStructures[fileStructure]->addMarkupTess(pMarkupTess); } uint32_t addMarkup(PRCMarkup*& pMarkup, uint32_t fileStructure=0) { return fileStructures[fileStructure]->addMarkup(pMarkup); } uint32_t addAnnotationItem(PRCAnnotationItem*& pAnnotationItem, uint32_t fileStructure=0) { return fileStructures[fileStructure]->addAnnotationItem(pAnnotationItem); } */ uint32_t addCoordinateSystem(PRCCoordinateSystem*& pCoordinateSystem, uint32_t fileStructure=0) { return fileStructures[fileStructure]->addCoordinateSystem(pCoordinateSystem); } uint32_t addCoordinateSystemUnique(PRCCoordinateSystem*& pCoordinateSystem, uint32_t fileStructure=0) { return fileStructures[fileStructure]->addCoordinateSystemUnique(pCoordinateSystem); } private: void serializeModelFileData(PRCbitStream&); std::ofstream *fout; std::ostream &output; }; } #endif // __O_PRC_FILE_H asymptote-2.37/prc/test.asy000066400000000000000000000001371265434602500157630ustar00rootroot00000000000000settings.outformat="pdf"; import embed; label(embed("test.prc","poster,3Droo=25",1500,500)); asymptote-2.37/prc/test.cc000066400000000000000000001066031265434602500155610ustar00rootroot00000000000000/************ * * This file is part of a tool for producing 3D content in the PRC format. * Copyright (C) 2008 Orest Shardt and * Michail Vidiassov * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * *************/ #include #include #include #include #include #include "oPRCFile.h" using namespace std; extern const double pi; int main() { // List of pictures used; keep track of memory allocated to free it in the end // shared pointers or garbage collector may be an alternative uint8_t *picture1 = NULL; uint8_t *picture2 = NULL; uint8_t *picture3 = NULL; uint8_t *picture4 = NULL; oPRCFile file("test.prc"); const size_t N_COLOURS = 32; RGBAColour colours[N_COLOURS]; for(size_t i = 0; i < N_COLOURS; ++i) { colours[i%N_COLOURS].R = 0.0; colours[i%N_COLOURS].G = (i%N_COLOURS)/static_cast(N_COLOURS); colours[i%N_COLOURS].B = 0.95; colours[i%N_COLOURS].A = 0.75; } PRCmaterial materials[N_COLOURS]; for(size_t i = 0; i < N_COLOURS; ++i) { materials[i%N_COLOURS].diffuse.R = 0.0; materials[i%N_COLOURS].diffuse.G = (i%N_COLOURS)/static_cast(N_COLOURS); materials[i%N_COLOURS].diffuse.B = 0.95; materials[i%N_COLOURS].diffuse.A = 0.75; materials[i%N_COLOURS].specular.R = 0.01*0.0; materials[i%N_COLOURS].specular.G = 0.01*(i%N_COLOURS)/static_cast(N_COLOURS); materials[i%N_COLOURS].specular.B = 0.01*0.95; materials[i%N_COLOURS].specular.A = 0.01*0.75; materials[i%N_COLOURS].emissive.R = 0.20*0.0; materials[i%N_COLOURS].emissive.G = 0.20*(i%N_COLOURS)/static_cast(N_COLOURS); materials[i%N_COLOURS].emissive.B = 0.20*0.95; materials[i%N_COLOURS].emissive.A = 0.20*0.75; materials[i%N_COLOURS].ambient.R = 0.05*0.0; materials[i%N_COLOURS].ambient.G = 0.05*(i%N_COLOURS)/static_cast(N_COLOURS); materials[i%N_COLOURS].ambient.B = 0.05*0.95; materials[i%N_COLOURS].ambient.A = 0.05*0.75; materials[i%N_COLOURS].alpha = 0.75; materials[i%N_COLOURS].shininess = 0.1; } if(1) { double knotsU[] = {1,1,1,1,2,2,2,2}; double knotsV[] = {1,1,1,1,2,2,2,2}; const size_t NUMBER_OF_PATCHES = 32; double controlPoints[NUMBER_OF_PATCHES][16][3] = { { // Patch 0 {1.4,0,2.4},{1.4,-0.784,2.4},{0.784,-1.4,2.4},{0,-1.4,2.4}, {1.3375,0,2.53125},{1.3375,-0.749,2.53125},{0.749,-1.3375,2.53125},{0,-1.3375,2.53125}, {1.4375,0,2.53125},{1.4375,-0.805,2.53125},{0.805,-1.4375,2.53125},{0,-1.4375,2.53125}, {1.5,0,2.4},{1.5,-0.84,2.4},{0.84,-1.5,2.4},{0,-1.5,2.4}, }, { // Patch 1 {0,-1.4,2.4},{-0.784,-1.4,2.4},{-1.4,-0.784,2.4},{-1.4,0,2.4}, {0,-1.3375,2.53125},{-0.749,-1.3375,2.53125},{-1.3375,-0.749,2.53125},{-1.3375,0,2.53125}, {0,-1.4375,2.53125},{-0.805,-1.4375,2.53125},{-1.4375,-0.805,2.53125},{-1.4375,0,2.53125}, {0,-1.5,2.4},{-0.84,-1.5,2.4},{-1.5,-0.84,2.4},{-1.5,0,2.4}, }, { // Patch 2 {-1.4,0,2.4},{-1.4,0.784,2.4},{-0.784,1.4,2.4},{0,1.4,2.4}, {-1.3375,0,2.53125},{-1.3375,0.749,2.53125},{-0.749,1.3375,2.53125},{0,1.3375,2.53125}, {-1.4375,0,2.53125},{-1.4375,0.805,2.53125},{-0.805,1.4375,2.53125},{0,1.4375,2.53125}, {-1.5,0,2.4},{-1.5,0.84,2.4},{-0.84,1.5,2.4},{0,1.5,2.4}, }, { // Patch 3 {0,1.4,2.4},{0.784,1.4,2.4},{1.4,0.784,2.4},{1.4,0,2.4}, {0,1.3375,2.53125},{0.749,1.3375,2.53125},{1.3375,0.749,2.53125},{1.3375,0,2.53125}, {0,1.4375,2.53125},{0.805,1.4375,2.53125},{1.4375,0.805,2.53125},{1.4375,0,2.53125}, {0,1.5,2.4},{0.84,1.5,2.4},{1.5,0.84,2.4},{1.5,0,2.4}, }, { // Patch 4 {1.5,0,2.4},{1.5,-0.84,2.4},{0.84,-1.5,2.4},{0,-1.5,2.4}, {1.75,0,1.875},{1.75,-0.98,1.875},{0.98,-1.75,1.875},{0,-1.75,1.875}, {2,0,1.35},{2,-1.12,1.35},{1.12,-2,1.35},{0,-2,1.35}, {2,0,0.9},{2,-1.12,0.9},{1.12,-2,0.9},{0,-2,0.9}, }, { // Patch 5 {0,-1.5,2.4},{-0.84,-1.5,2.4},{-1.5,-0.84,2.4},{-1.5,0,2.4}, {0,-1.75,1.875},{-0.98,-1.75,1.875},{-1.75,-0.98,1.875},{-1.75,0,1.875}, {0,-2,1.35},{-1.12,-2,1.35},{-2,-1.12,1.35},{-2,0,1.35}, {0,-2,0.9},{-1.12,-2,0.9},{-2,-1.12,0.9},{-2,0,0.9}, }, { // Patch 6 {-1.5,0,2.4},{-1.5,0.84,2.4},{-0.84,1.5,2.4},{0,1.5,2.4}, {-1.75,0,1.875},{-1.75,0.98,1.875},{-0.98,1.75,1.875},{0,1.75,1.875}, {-2,0,1.35},{-2,1.12,1.35},{-1.12,2,1.35},{0,2,1.35}, {-2,0,0.9},{-2,1.12,0.9},{-1.12,2,0.9},{0,2,0.9}, }, { // Patch 7 {0,1.5,2.4},{0.84,1.5,2.4},{1.5,0.84,2.4},{1.5,0,2.4}, {0,1.75,1.875},{0.98,1.75,1.875},{1.75,0.98,1.875},{1.75,0,1.875}, {0,2,1.35},{1.12,2,1.35},{2,1.12,1.35},{2,0,1.35}, {0,2,0.9},{1.12,2,0.9},{2,1.12,0.9},{2,0,0.9}, }, { // Patch 8 {2,0,0.9},{2,-1.12,0.9},{1.12,-2,0.9},{0,-2,0.9}, {2,0,0.45},{2,-1.12,0.45},{1.12,-2,0.45},{0,-2,0.45}, {1.5,0,0.225},{1.5,-0.84,0.225},{0.84,-1.5,0.225},{0,-1.5,0.225}, {1.5,0,0.15},{1.5,-0.84,0.15},{0.84,-1.5,0.15},{0,-1.5,0.15}, }, { // Patch 9 {0,-2,0.9},{-1.12,-2,0.9},{-2,-1.12,0.9},{-2,0,0.9}, {0,-2,0.45},{-1.12,-2,0.45},{-2,-1.12,0.45},{-2,0,0.45}, {0,-1.5,0.225},{-0.84,-1.5,0.225},{-1.5,-0.84,0.225},{-1.5,0,0.225}, {0,-1.5,0.15},{-0.84,-1.5,0.15},{-1.5,-0.84,0.15},{-1.5,0,0.15}, }, { // Patch 10 {-2,0,0.9},{-2,1.12,0.9},{-1.12,2,0.9},{0,2,0.9}, {-2,0,0.45},{-2,1.12,0.45},{-1.12,2,0.45},{0,2,0.45}, {-1.5,0,0.225},{-1.5,0.84,0.225},{-0.84,1.5,0.225},{0,1.5,0.225}, {-1.5,0,0.15},{-1.5,0.84,0.15},{-0.84,1.5,0.15},{0,1.5,0.15}, }, { // Patch 11 {0,2,0.9},{1.12,2,0.9},{2,1.12,0.9},{2,0,0.9}, {0,2,0.45},{1.12,2,0.45},{2,1.12,0.45},{2,0,0.45}, {0,1.5,0.225},{0.84,1.5,0.225},{1.5,0.84,0.225},{1.5,0,0.225}, {0,1.5,0.15},{0.84,1.5,0.15},{1.5,0.84,0.15},{1.5,0,0.15}, }, { // Patch 12 {-1.6,0,2.025},{-1.6,-0.3,2.025},{-1.5,-0.3,2.25},{-1.5,0,2.25}, {-2.3,0,2.025},{-2.3,-0.3,2.025},{-2.5,-0.3,2.25},{-2.5,0,2.25}, {-2.7,0,2.025},{-2.7,-0.3,2.025},{-3,-0.3,2.25},{-3,0,2.25}, {-2.7,0,1.8},{-2.7,-0.3,1.8},{-3,-0.3,1.8},{-3,0,1.8}, }, { // Patch 13 {-1.5,0,2.25},{-1.5,0.3,2.25},{-1.6,0.3,2.025},{-1.6,0,2.025}, {-2.5,0,2.25},{-2.5,0.3,2.25},{-2.3,0.3,2.025},{-2.3,0,2.025}, {-3,0,2.25},{-3,0.3,2.25},{-2.7,0.3,2.025},{-2.7,0,2.025}, {-3,0,1.8},{-3,0.3,1.8},{-2.7,0.3,1.8},{-2.7,0,1.8}, }, { // Patch 14 {-2.7,0,1.8},{-2.7,-0.3,1.8},{-3,-0.3,1.8},{-3,0,1.8}, {-2.7,0,1.575},{-2.7,-0.3,1.575},{-3,-0.3,1.35},{-3,0,1.35}, {-2.5,0,1.125},{-2.5,-0.3,1.125},{-2.65,-0.3,0.9375},{-2.65,0,0.9375}, {-2,0,0.9},{-2,-0.3,0.9},{-1.9,-0.3,0.6},{-1.9,0,0.6}, }, { // Patch 15 {-3,0,1.8},{-3,0.3,1.8},{-2.7,0.3,1.8},{-2.7,0,1.8}, {-3,0,1.35},{-3,0.3,1.35},{-2.7,0.3,1.575},{-2.7,0,1.575}, {-2.65,0,0.9375},{-2.65,0.3,0.9375},{-2.5,0.3,1.125},{-2.5,0,1.125}, {-1.9,0,0.6},{-1.9,0.3,0.6},{-2,0.3,0.9},{-2,0,0.9}, }, { // Patch 16 {1.7,0,1.425},{1.7,-0.66,1.425},{1.7,-0.66,0.6},{1.7,0,0.6}, {2.6,0,1.425},{2.6,-0.66,1.425},{3.1,-0.66,0.825},{3.1,0,0.825}, {2.3,0,2.1},{2.3,-0.25,2.1},{2.4,-0.25,2.025},{2.4,0,2.025}, {2.7,0,2.4},{2.7,-0.25,2.4},{3.3,-0.25,2.4},{3.3,0,2.4}, }, { // Patch 17 {1.7,0,0.6},{1.7,0.66,0.6},{1.7,0.66,1.425},{1.7,0,1.425}, {3.1,0,0.825},{3.1,0.66,0.825},{2.6,0.66,1.425},{2.6,0,1.425}, {2.4,0,2.025},{2.4,0.25,2.025},{2.3,0.25,2.1},{2.3,0,2.1}, {3.3,0,2.4},{3.3,0.25,2.4},{2.7,0.25,2.4},{2.7,0,2.4}, }, { // Patch 18 {2.7,0,2.4},{2.7,-0.25,2.4},{3.3,-0.25,2.4},{3.3,0,2.4}, {2.8,0,2.475},{2.8,-0.25,2.475},{3.525,-0.25,2.49375},{3.525,0,2.49375}, {2.9,0,2.475},{2.9,-0.15,2.475},{3.45,-0.15,2.5125},{3.45,0,2.5125}, {2.8,0,2.4},{2.8,-0.15,2.4},{3.2,-0.15,2.4},{3.2,0,2.4}, }, { // Patch 19 {3.3,0,2.4},{3.3,0.25,2.4},{2.7,0.25,2.4},{2.7,0,2.4}, {3.525,0,2.49375},{3.525,0.25,2.49375},{2.8,0.25,2.475},{2.8,0,2.475}, {3.45,0,2.5125},{3.45,0.15,2.5125},{2.9,0.15,2.475},{2.9,0,2.475}, {3.2,0,2.4},{3.2,0.15,2.4},{2.8,0.15,2.4},{2.8,0,2.4}, }, { // Patch 20 {0,0,3.15},{0,0,3.15},{0,0,3.15},{0,0,3.15}, {0.8,0,3.15},{0.8,-0.45,3.15},{0.45,-0.8,3.15},{0,-0.8,3.15}, {0,0,2.85},{0,0,2.85},{0,0,2.85},{0,0,2.85}, {0.2,0,2.7},{0.2,-0.112,2.7},{0.112,-0.2,2.7},{0,-0.2,2.7}, }, { // Patch 21 {0,0,3.15},{0,0,3.15},{0,0,3.15},{0,0,3.15}, {0,-0.8,3.15},{-0.45,-0.8,3.15},{-0.8,-0.45,3.15},{-0.8,0,3.15}, {0,0,2.85},{0,0,2.85},{0,0,2.85},{0,0,2.85}, {0,-0.2,2.7},{-0.112,-0.2,2.7},{-0.2,-0.112,2.7},{-0.2,0,2.7}, }, { // Patch 22 {0,0,3.15},{0,0,3.15},{0,0,3.15},{0,0,3.15}, {-0.8,0,3.15},{-0.8,0.45,3.15},{-0.45,0.8,3.15},{0,0.8,3.15}, {0,0,2.85},{0,0,2.85},{0,0,2.85},{0,0,2.85}, {-0.2,0,2.7},{-0.2,0.112,2.7},{-0.112,0.2,2.7},{0,0.2,2.7}, }, { // Patch 23 {0,0,3.15},{0,0,3.15},{0,0,3.15},{0,0,3.15}, {0,0.8,3.15},{0.45,0.8,3.15},{0.8,0.45,3.15},{0.8,0,3.15}, {0,0,2.85},{0,0,2.85},{0,0,2.85},{0,0,2.85}, {0,0.2,2.7},{0.112,0.2,2.7},{0.2,0.112,2.7},{0.2,0,2.7}, }, { // Patch 24 {0.2,0,2.7},{0.2,-0.112,2.7},{0.112,-0.2,2.7},{0,-0.2,2.7}, {0.4,0,2.55},{0.4,-0.224,2.55},{0.224,-0.4,2.55},{0,-0.4,2.55}, {1.3,0,2.55},{1.3,-0.728,2.55},{0.728,-1.3,2.55},{0,-1.3,2.55}, {1.3,0,2.4},{1.3,-0.728,2.4},{0.728,-1.3,2.4},{0,-1.3,2.4}, }, { // Patch 25 {0,-0.2,2.7},{-0.112,-0.2,2.7},{-0.2,-0.112,2.7},{-0.2,0,2.7}, {0,-0.4,2.55},{-0.224,-0.4,2.55},{-0.4,-0.224,2.55},{-0.4,0,2.55}, {0,-1.3,2.55},{-0.728,-1.3,2.55},{-1.3,-0.728,2.55},{-1.3,0,2.55}, {0,-1.3,2.4},{-0.728,-1.3,2.4},{-1.3,-0.728,2.4},{-1.3,0,2.4}, }, { // Patch 26 {-0.2,0,2.7},{-0.2,0.112,2.7},{-0.112,0.2,2.7},{0,0.2,2.7}, {-0.4,0,2.55},{-0.4,0.224,2.55},{-0.224,0.4,2.55},{0,0.4,2.55}, {-1.3,0,2.55},{-1.3,0.728,2.55},{-0.728,1.3,2.55},{0,1.3,2.55}, {-1.3,0,2.4},{-1.3,0.728,2.4},{-0.728,1.3,2.4},{0,1.3,2.4}, }, { // Patch 27 {0,0.2,2.7},{0.112,0.2,2.7},{0.2,0.112,2.7},{0.2,0,2.7}, {0,0.4,2.55},{0.224,0.4,2.55},{0.4,0.224,2.55},{0.4,0,2.55}, {0,1.3,2.55},{0.728,1.3,2.55},{1.3,0.728,2.55},{1.3,0,2.55}, {0,1.3,2.4},{0.728,1.3,2.4},{1.3,0.728,2.4},{1.3,0,2.4}, }, { // Patch 28 {0,0,0},{0,0,0},{0,0,0},{0,0,0}, {1.425,0,0},{1.425,0.798,0},{0.798,1.425,0},{0,1.425,0}, {1.5,0,0.075},{1.5,0.84,0.075},{0.84,1.5,0.075},{0,1.5,0.075}, {1.5,0,0.15},{1.5,0.84,0.15},{0.84,1.5,0.15},{0,1.5,0.15}, }, { // Patch 29 {0,0,0},{0,0,0},{0,0,0},{0,0,0}, {0,1.425,0},{-0.798,1.425,0},{-1.425,0.798,0},{-1.425,0,0}, {0,1.5,0.075},{-0.84,1.5,0.075},{-1.5,0.84,0.075},{-1.5,0,0.075}, {0,1.5,0.15},{-0.84,1.5,0.15},{-1.5,0.84,0.15},{-1.5,0,0.15}, }, { // Patch 30 {0,0,0},{0,0,0},{0,0,0},{0,0,0}, {-1.425,0,0},{-1.425,-0.798,0},{-0.798,-1.425,0},{0,-1.425,0}, {-1.5,0,0.075},{-1.5,-0.84,0.075},{-0.84,-1.5,0.075},{0,-1.5,0.075}, {-1.5,0,0.15},{-1.5,-0.84,0.15},{-0.84,-1.5,0.15},{0,-1.5,0.15}, }, { // Patch 31 {0,0,0},{0,0,0},{0,0,0},{0,0,0}, {0,-1.425,0},{0.798,-1.425,0},{1.425,-0.798,0},{1.425,0,0}, {0,-1.5,0.075},{0.84,-1.5,0.075},{1.5,-0.84,0.075},{1.5,0,0.075}, {0,-1.5,0.15},{0.84,-1.5,0.15},{1.5,-0.84,0.15},{1.5,0,0.15}, }, }; file.begingroup("Teapot"); for(size_t i = 0; i < NUMBER_OF_PATCHES; ++i) { if(1) file.addPatch(controlPoints[i],materials[i%N_COLOURS]); if(0) file.addSurface(3,3,4,4,controlPoints[i],knotsU,knotsV,materials[i%N_COLOURS],NULL); // use (too) general API for the same result as above } file.endgroup(); double t[4][4]; t[0][0]=1; t[0][1]=0; t[0][2]=0; t[0][3]=6; t[1][0]=0; t[1][1]=1; t[1][2]=0; t[1][3]=0; t[2][0]=0; t[2][1]=0; t[2][2]=1; t[2][3]=0; t[3][0]=0; t[3][1]=0; t[3][2]=0; t[3][3]=1; PRCoptions teapotopt; teapotopt.no_break = true; teapotopt.do_break = false; teapotopt.compression = 0.0001; // force joining together of patches, damaging transparency file.begingroup("Teapot rendered in the way of opaque surfaces and transferred",&teapotopt,t); for(size_t i = 0; i < NUMBER_OF_PATCHES; ++i) { file.addPatch(controlPoints[i],materials[i%N_COLOURS]); } file.endgroup(); } const size_t NUMBER_OF_POINTS = 31; double points[NUMBER_OF_POINTS][3]; for(size_t i = 0; i < NUMBER_OF_POINTS; ++i) { points[i][0] = 3.5*cos(3.0*i/NUMBER_OF_POINTS*2.0*pi); points[i][1] = 3.5*sin(3.0*i/NUMBER_OF_POINTS*2.0*pi); points[i][2] = 5.0*i/NUMBER_OF_POINTS-1.0; } const size_t NUMBER_OF_WIRES = 2; double shifted_points[NUMBER_OF_WIRES][NUMBER_OF_POINTS][3]; for(size_t wire = 0; wire < NUMBER_OF_WIRES; ++wire) for(size_t point = 0; point < NUMBER_OF_POINTS; ++point) { shifted_points[wire][point][0] = points[point][0]; shifted_points[wire][point][1] = points[point][1]; shifted_points[wire][point][2] = points[point][2]+0.1*wire+0.1; } double knots[3+NUMBER_OF_POINTS+1]; knots[0] = 1; for(size_t i = 1; i < 3+NUMBER_OF_POINTS; ++i) { knots[i] = (i+2)/3; // integer division is intentional } knots[3+NUMBER_OF_POINTS] = (3+NUMBER_OF_POINTS+1)/3; PRCoptions grpopt; grpopt.no_break = true; grpopt.do_break = false; grpopt.tess = true; if(1){ double point1[3] = {11,0,0}; double point2[3] = {12,0,0}; double points[2][3] = {{9,0,0},{10,0,0}}; file.begingroup("points",&grpopt); file.addPoint(point1, RGBAColour(1.0,0.0,0.0)); file.addPoint(point2, RGBAColour(1.0,0.0,0.0)); file.addPoints(2, points, RGBAColour(1.0,0.0,0.0,0.5),10); file.endgroup(); } if(1){ PRCoptions grpopt; grpopt.no_break = true; grpopt.do_break = false; grpopt.tess = true; grpopt.closed = true; double t[4][4]; const size_t nP = 5; double P[nP][3] = {{0,0,0},{1,0,0},{1,1,0},{0,1,0},{0,2,0}}; const size_t nI = 3; uint32_t PI[nI][3] = {{0,1,3},{1,2,3},{3,2,4}}; const size_t nM = 2; PRCmaterial M[nM]; M[0] = PRCmaterial( RGBAColour(0.0,0.0,0.18), RGBAColour(0.0,0.0,0.878431), RGBAColour(0.0,0.0,0.32), RGBAColour(0.0,0.0,0.072), 1.0,0.1); M[1] = PRCmaterial( RGBAColour(0.18,0.0,0.0), RGBAColour(0.878431,0.0,0.0), RGBAColour(0.32,0.0,0.0), RGBAColour(0.072,0.0,0.0), 0.5,0.1); uint32_t MI[nI] = {0,1,0}; const size_t nN = 2; double N[nN][3] = {{0,0,1},{0,0,-1}}; uint32_t NI[nI][3] = {{0,0,0},{0,0,0},{1,1,1}}; const uint32_t nC = 3; RGBAColour C[nC]; uint32_t CI[nI][3] = {{0,0,0},{1,1,1},{1,1,2}}; PRCmaterial materialGreen( RGBAColour(0.0,0.18,0.0), RGBAColour(0.0,0.878431,0.0), RGBAColour(0.0,0.32,0.0), RGBAColour(0.0,0.072,0.0), 1.0,0.1); if(1){ t[0][0]=1; t[0][1]=0; t[0][2]=0; t[0][3]=0; t[1][0]=0; t[1][1]=1; t[1][2]=0; t[1][3]=0; t[2][0]=0; t[2][1]=0; t[2][2]=1; t[2][3]=-1; t[3][0]=0; t[3][1]=0; t[3][2]=0; t[3][3]=1; file.begingroup("triangles_onecolor_with_normals",&grpopt,t); file.addTriangles(nP, P, nI, PI, materialGreen, nN, N, NI, 0, NULL, NULL, 0, NULL, NULL, 0, NULL, NULL); file.endgroup(); } if(1){ file.begingroup("triangles_onecolor",&grpopt); file.addTriangles(nP, P, nI, PI, materialGreen, 0, NULL, NULL, 0, NULL, NULL, 0, NULL, NULL, 0, NULL, NULL); file.endgroup(); } if(1){ t[0][0]=1; t[0][1]=0; t[0][2]=0; t[0][3]=0; t[1][0]=0; t[1][1]=1; t[1][2]=0; t[1][3]=0; t[2][0]=0; t[2][1]=0; t[2][2]=1; t[2][3]=1; t[3][0]=0; t[3][1]=0; t[3][2]=0; t[3][3]=1; file.begingroup("triangles_manymaterials",&grpopt,t); file.addTriangles(nP, P, nI, PI, materialGreen, 0, NULL, NULL, 0, NULL, NULL, 0, NULL, NULL, nM, M, MI); file.endgroup(); } if(1){ t[0][0]=1; t[0][1]=0; t[0][2]=0; t[0][3]=0; t[1][0]=0; t[1][1]=1; t[1][2]=0; t[1][3]=0; t[2][0]=0; t[2][1]=0; t[2][2]=1; t[2][3]=2; t[3][0]=0; t[3][1]=0; t[3][2]=0; t[3][3]=1; PRCmaterial materialBase( RGBAColour(0.1,0.1,0.1,1), RGBAColour(1,1,1,1), RGBAColour(0.1,0.1,0.1,1), RGBAColour(0.1,0.1,0.1,1), 1.0,0.1); C[0] = RGBAColour(1,0,0,0.1); C[1] = RGBAColour(0,1,0,0.5); C[2] = RGBAColour(0,0,1,0.9); file.begingroup("triangles_rgba_vertexcolors_on_opaque_a_component_of_vertexcolor_ignored",&grpopt,t); file.addTriangles(nP, P, nI, PI, materialBase, 0, NULL, NULL, 0, NULL, NULL, nC, C, CI, 0, NULL, NULL); file.endgroup(); t[0][0]=1; t[0][1]=0; t[0][2]=0; t[0][3]=0; t[1][0]=0; t[1][1]=1; t[1][2]=0; t[1][3]=0; t[2][0]=0; t[2][1]=0; t[2][2]=1; t[2][3]=3; t[3][0]=0; t[3][1]=0; t[3][2]=0; t[3][3]=1; PRCmaterial materialTransparent( RGBAColour(0.1,0.1,0.1,0.3), RGBAColour(1,1,1,0.3), RGBAColour(0.1,0.1,0.1,0.3), RGBAColour(0.1,0.1,0.1,0.3), 0.3,0.1); C[0] = RGBAColour(1,0,0,0.1); C[1] = RGBAColour(0,1,0,0.5); C[2] = RGBAColour(0,0,1,0.9); file.begingroup("triangles_rgba_vertexcolors_on_transparent_a_component_of_vertexcolor_ignored",&grpopt,t); file.addTriangles(nP, P, nI, PI, materialTransparent, 0, NULL, NULL, 0, NULL, NULL, nC, C, CI, 0, NULL, NULL); file.endgroup(); t[0][0]=1; t[0][1]=0; t[0][2]=0; t[0][3]=0; t[1][0]=0; t[1][1]=1; t[1][2]=0; t[1][3]=0; t[2][0]=0; t[2][1]=0; t[2][2]=1; t[2][3]=4; t[3][0]=0; t[3][1]=0; t[3][2]=0; t[3][3]=1; C[0] = RGBAColour(1,0,0,0.5); C[1] = RGBAColour(0,1,0,0.5); C[2] = RGBAColour(0,0,1,0.5); file.begingroup("triangles_rgb_vertexcolors_on_transparent_may_not_work_in_OpenGL",&grpopt,t); file.addTriangles(nP, P, nI, PI, materialTransparent, 0, NULL, NULL, 0, NULL, NULL, nC, C, CI, 0, NULL, NULL); file.endgroup(); } if(1){ t[0][0]=1; t[0][1]=0; t[0][2]=0; t[0][3]=0; t[1][0]=0; t[1][1]=1; t[1][2]=0; t[1][3]=0; t[2][0]=0; t[2][1]=0; t[2][2]=1; t[2][3]=5; t[3][0]=0; t[3][1]=0; t[3][2]=0; t[3][3]=1; const uint32_t picture_width=2; const uint32_t picture_height=2; const uint8_t picRGB[picture_width*picture_height*3] = {255,0,0, 0,255,0, 0,0,255, 0,0,0 }; // {255,255,0, 255,0,0, 255,0,0, 255,0,0 }; // { 255,0,0, 255,255,0, 255,255,0, 255,255,255 }; // {255,0,0, 0,255,0, 0,0,255, 0,0,0 }; const uint8_t picRGBA[picture_width*picture_height*4] = {255,0,0,255, 0,255,0,150, 0,0,255,150, 0,0,0,100 }; // (1,0) 2 3 (1,1) // (0,0) 0 1 (1,0) uint8_t *pictureRGB = new uint8_t[picture_width*picture_height*3]; for(size_t i=0; i and * Michail Vidiassov * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * *************/ #include "writePRC.h" #include #include // debug print includes #include #include #include #include #if !defined(__GNUC__) || defined(__clang__) #include #endif using namespace std; #ifndef __GNUC_PREREQ #define __GNUC_PREREQ(maj, min) (0) #endif // Count leading zeros. uint32_t CLZ(uint32_t a) { #if __GNUC_PREREQ(3,4) return __builtin_clz(a); #else // find the log base 2 of a 32-bit integer static const int MultiplyDeBruijnBitPosition[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 }; a |= a >> 1; // first round down to one less than a power of 2 a |= a >> 2; a |= a >> 4; a |= a >> 8; a |= a >> 16; return 31-MultiplyDeBruijnBitPosition[(uint32_t)(a * 0x07C4ACDDU) >> 27]; #endif } // Portable integer implementation of ceil(log2(x)). uint32_t Log2(uint32_t x) { assert(x != 0); uint32_t L=31-CLZ(x); return ((uint32_t) 1 << L == x) ? L : L+1; } #define WriteUnsignedInteger( value ) pbs << (uint32_t)(value); #define WriteInteger( value ) pbs << (int32_t)(value); #define WriteCharacter( value ) pbs << (uint8_t)(value); #define WriteDouble( value ) pbs << (double)(value); #define WriteBit( value ) pbs << (bool)(value); #define WriteBoolean( value ) pbs << (bool)(value); #define WriteString( value ) pbs << (value); #define SerializeContentPRCBase serializeContentPRCBase(pbs); #define SerializeGraphics serializeGraphics(pbs); #define SerializePRCBaseWithGraphics { serializeContentPRCBase(pbs); serializeGraphics(pbs); } #define SerializeRepresentationItemContent serializeRepresentationItemContent(pbs); #define SerializeRepresentationItem( value ) (value)->serializeRepresentationItem(pbs); #define SerializeMarkup( value ) (value).serializeMarkup(pbs); #define SerializeReferenceUniqueIdentifier( value ) (value).serializeReferenceUniqueIdentifier(pbs); #define SerializeContentBaseTessData serializeContentBaseTessData(pbs); #define SerializeTessFace( value ) (value)->serializeTessFace(pbs); #define SerializeUserData UserData(0,0).write(pbs); #define SerializeLineAttr( value ) pbs << (uint32_t)((value)+1); #define SerializeVector3d( value ) (value).serializeVector3d(pbs); #define SerializeVector2d( value ) (value).serializeVector2d(pbs); #define SerializeName( value ) writeName(pbs, (value)); #define SerializeInterval( value ) (value).serializeInterval(pbs); // #define SerializeBoundingBox( value ) (value).serializeBoundingBox(pbs); #define SerializeDomain( value ) (value).serializeDomain(pbs); #define SerializeParameterization serializeParameterization(pbs); #define SerializeUVParameterization serializeUVParameterization(pbs); #define SerializeTransformation serializeTransformation(pbs); #define SerializeBaseTopology serializeBaseTopology(pbs); #define SerializeBaseGeometry serializeBaseGeometry(pbs); #define SerializePtrCurve( value ) {WriteBoolean( false ); if((value)==NULL) pbs << (uint32_t)PRC_TYPE_ROOT; else (value)->serializeCurve(pbs);} #define SerializePtrSurface( value ) {WriteBoolean( false ); if((value)==NULL) pbs << (uint32_t)PRC_TYPE_ROOT; else (value)->serializeSurface(pbs);} #define SerializePtrTopology( value ) {WriteBoolean( false ); if((value)==NULL) pbs << (uint32_t)PRC_TYPE_ROOT; else (value)->serializeTopoItem(pbs);} #define SerializeContentCurve serializeContentCurve(pbs); #define SerializeContentWireEdge serializeContentWireEdge(pbs); #define SerializeContentBody serializeContentBody(pbs); #define SerializeTopoContext serializeTopoContext(pbs); #define SerializeContextAndBodies( value ) (value).serializeContextAndBodies(pbs); #define SerializeBody( value ) (value)->serializeBody(pbs); #define ResetCurrentGraphics resetGraphics(); #define SerializeContentSurface serializeContentSurface(pbs); #define SerializeCompressedUniqueId( value ) (value).serializeCompressedUniqueId(pbs); #define SerializeUnit( value ) (value).serializeUnit(pbs); #define SerializeBoundingBox serializeBoundingBox(pbs); #define SerializeAttributeEntry serializeAttributeEntry(pbs); #define SerializeContentSingleAttribute( value ) (value).serializeSingleAttribute(pbs); #define SerializeAttribute( value ) (value).serializeAttribute(pbs); #define SerializeAttributeData serializeAttributes(pbs); #define WriteUncompressedUnsignedInteger( value ) writeUncompressedUnsignedInteger(out, (uint32_t)(value)); #define SerializeFileStructureUncompressedUniqueId( value ) (value).serializeFileStructureUncompressedUniqueId(out); void writeUncompressedUnsignedInteger(ostream &out, uint32_t data) { #ifdef WORDS_BIGENDIAN out.write(((char*)&data)+3,1); out.write(((char*)&data)+2,1); out.write(((char*)&data)+1,1); out.write(((char*)&data)+0,1); #else out.write(((char*)&data)+0,1); out.write(((char*)&data)+1,1); out.write(((char*)&data)+2,1); out.write(((char*)&data)+3,1); #endif } double PRCVector3d::Length() { return sqrt(x*x+y*y+z*z); } bool PRCVector3d::Normalize() { double fLength=Length(); if(fLength < FLT_EPSILON) return false; double factor=1.0/fLength; x *= factor; y *= factor; z *= factor; return true; } double PRCVector2d::Length() { return sqrt(x*x+y*y); } bool PRCVector2d::Normalize() { double fLength=Length(); if(fLength < FLT_EPSILON) return false; double factor=1.0/fLength; x *= factor; y *= factor; return true; } void PRCVector2d::serializeVector2d(PRCbitStream &pbs) { WriteDouble (x) WriteDouble (y) } uint32_t makeCADID() { static uint32_t ID = 1; return ID++; } uint32_t makePRCID() { static uint32_t ID = 1; return ID++; } bool type_eligible_for_reference(uint32_t type) { if( type == PRC_TYPE_MISC_EntityReference || type == PRC_TYPE_MISC_MarkupLinkedItem || type == PRC_TYPE_RI_BrepModel || type == PRC_TYPE_RI_Curve || type == PRC_TYPE_RI_Direction || type == PRC_TYPE_RI_Plane || type == PRC_TYPE_RI_PointSet || type == PRC_TYPE_RI_PolyBrepModel || type == PRC_TYPE_RI_PolyWire || type == PRC_TYPE_RI_Set || type == PRC_TYPE_RI_CoordinateSystem || type == PRC_TYPE_ASM_ProductOccurence || type == PRC_TYPE_ASM_PartDefinition || type == PRC_TYPE_ASM_Filter || type == PRC_TYPE_MKP_View || type == PRC_TYPE_MKP_Markup || type == PRC_TYPE_MKP_Leader || type == PRC_TYPE_MKP_AnnotationItem || type == PRC_TYPE_MKP_AnnotationSet || type == PRC_TYPE_MKP_AnnotationReference || type == PRC_TYPE_GRAPH_Style || type == PRC_TYPE_GRAPH_Material || type == PRC_TYPE_GRAPH_TextureApplication || type == PRC_TYPE_GRAPH_TextureDefinition || type == PRC_TYPE_GRAPH_LinePattern || type == PRC_TYPE_GRAPH_DottingPattern || type == PRC_TYPE_GRAPH_HatchingPattern || type == PRC_TYPE_GRAPH_SolidPattern || type == PRC_TYPE_GRAPH_VPicturePattern || type == PRC_TYPE_GRAPH_AmbientLight || type == PRC_TYPE_GRAPH_PointLight || type == PRC_TYPE_GRAPH_DirectionalLight || type == PRC_TYPE_GRAPH_SpotLight || type == PRC_TYPE_GRAPH_SceneDisplayParameters || type == PRC_TYPE_GRAPH_Camera ) return true; else return false; } void UserData::write(PRCbitStream &pbs) { pbs << size; if(size > 0) { uint32_t quot=size/8; uint32_t rem=size-8*quot; for(uint32_t i = 0; i < quot; ++i) pbs << data[i]; for(uint32_t j = 0; j < rem; ++j) // 0-based, big endian bit counting pbs << (bool)((data[quot] & (0x80 >> j))!=0); } } void PRCAttributeEntry::serializeAttributeEntry(PRCbitStream &pbs) const { WriteBoolean (title_is_integer) if (title_is_integer) WriteUnsignedInteger (title_integer) else WriteString (title_text) } void PRCSingleAttribute::serializeSingleAttribute(PRCbitStream &pbs) const { SerializeAttributeEntry WriteUnsignedInteger (type) switch (type) { case KEPRCModellerAttributeTypeInt: WriteInteger (value.integer) break; case KEPRCModellerAttributeTypeReal: WriteDouble (value.real) break; case KEPRCModellerAttributeTypeTime: WriteUnsignedInteger (value.time) break; case KEPRCModellerAttributeTypeString: WriteString (value_text) break; default: break; } } void PRCAttribute::serializeAttribute(PRCbitStream &pbs) const { WriteUnsignedInteger (PRC_TYPE_MISC_Attribute) SerializeAttributeEntry const uint32_t size_of_attribute_keys = attribute_keys.size(); WriteUnsignedInteger (size_of_attribute_keys) for(uint32_t i=0;i 1) WriteInteger (texture_wrapping_mode_T) // Texture wrapping mode if (texture_dimension > 2 ) WriteInteger (texture_wrapping_mode_R) // Texture wrapping mode WriteBit (texture_transformation) // if (texture_transformation) // SerializeTextureTransformation (texture_transformation) } void PRCMaterialGeneric::serializeMaterialGeneric(PRCbitStream &pbs) { WriteUnsignedInteger (PRC_TYPE_GRAPH_Material) SerializeContentPRCBase WriteUnsignedInteger (ambient + 1) WriteUnsignedInteger (diffuse + 1) WriteUnsignedInteger (emissive + 1) WriteUnsignedInteger (specular + 1) WriteDouble (shininess) WriteDouble (ambient_alpha) WriteDouble (diffuse_alpha) WriteDouble (emissive_alpha) WriteDouble (specular_alpha) } void PRCTextureApplication::serializeTextureApplication(PRCbitStream &pbs) { WriteUnsignedInteger (PRC_TYPE_GRAPH_TextureApplication) SerializeContentPRCBase WriteUnsignedInteger (material_generic_index+1) WriteUnsignedInteger (texture_definition_index+1) WriteUnsignedInteger (next_texture_index+1) WriteUnsignedInteger (UV_coordinates_index+1) } void PRCLinePattern::serializeLinePattern(PRCbitStream &pbs) { uint32_t i = 0; WriteUnsignedInteger (PRC_TYPE_GRAPH_LinePattern) SerializeContentPRCBase const uint32_t size_lengths = lengths.size(); WriteUnsignedInteger (size_lengths) for (i=0;i>8)&0xFF); current_layer_index = l; current_index_of_line_style = i; current_behaviour_bit_field = b; } else pbs << true; } void writeGraphics(PRCbitStream &pbs,const PRCGraphics &graphics,bool force) { if(force || current_layer_index != graphics.layer_index || current_index_of_line_style != graphics.index_of_line_style || current_behaviour_bit_field != graphics.behaviour_bit_field) { pbs << false << (uint32_t)(graphics.layer_index+1) << (uint32_t)(graphics.index_of_line_style+1) << (uint8_t)(graphics.behaviour_bit_field&0xFF) << (uint8_t)((graphics.behaviour_bit_field>>8)&0xFF); current_layer_index = graphics.layer_index; current_index_of_line_style = graphics.index_of_line_style; current_behaviour_bit_field = graphics.behaviour_bit_field; } else pbs << true; } void PRCGraphics::serializeGraphics(PRCbitStream &pbs) { if(current_layer_index != this->layer_index || current_index_of_line_style != this->index_of_line_style || current_behaviour_bit_field != this->behaviour_bit_field) { pbs << false << (uint32_t)(this->layer_index+1) << (uint32_t)(this->index_of_line_style+1) << (uint8_t)(this->behaviour_bit_field&0xFF) << (uint8_t)((this->behaviour_bit_field>>8)&0xFF); current_layer_index = this->layer_index; current_index_of_line_style = this->index_of_line_style; current_behaviour_bit_field = this->behaviour_bit_field; } else pbs << true; } void PRCGraphics::serializeGraphicsForced(PRCbitStream &pbs) { pbs << false << (uint32_t)(this->layer_index+1) << (uint32_t)(this->index_of_line_style+1) << (uint8_t)(this->behaviour_bit_field&0xFF) << (uint8_t)((this->behaviour_bit_field>>8)&0xFF); current_layer_index = this->layer_index; current_index_of_line_style = this->index_of_line_style; current_behaviour_bit_field = this->behaviour_bit_field; } void resetGraphics() { current_layer_index = m1; current_index_of_line_style = m1; current_behaviour_bit_field = 1; } void resetGraphicsAndName() { resetGraphics(); resetName(); } void PRCMarkup::serializeMarkup(PRCbitStream &pbs) { WriteUnsignedInteger (PRC_TYPE_MKP_Markup) SerializeContentPRCBase SerializeGraphics WriteUnsignedInteger (type) WriteUnsignedInteger (sub_type) const uint32_t number_of_linked_items = 0; WriteUnsignedInteger (number_of_linked_items) // for (i=0;iserializeTransformation3d(pbs); SerializeUserData } void PRCFontKeysSameFont::serializeFontKeysSameFont(PRCbitStream &pbs) { uint32_t i=0; // universal index for PRC standart compatibility WriteString (font_name) WriteUnsignedInteger (char_set) const uint32_t number_of_font_keys = font_keys.size(); WriteUnsignedInteger (number_of_font_keys) for (i=0;i &rgba_vertices,const bool is_rgba, PRCbitStream &pbs) { uint32_t i = 0; uint32_t j = 0; // number_by_vector can be assigned a value of 3 (RGB) or 4 (RGBA). // number_of_vectors is equal to number_of_colors / number_by_vector. const uint32_t number_by_vector=is_rgba?4:3; const std::vector &vector_color = rgba_vertices; const uint32_t number_of_colors=vector_color.size(); const uint32_t number_of_vectors=number_of_colors / number_by_vector; // first one for (i=0;i= 1u<<(bit_number - 1 - i) ) { WriteBoolean (true) value -= 1u<<(bit_number - 1 - i); } else { WriteBoolean (false) } } } #define WriteUnsignedIntegerWithVariableBitNumber( value, bit_number ) writeUnsignedIntegerWithVariableBitNumber( pbs, (value), (bit_number) ); void writeIntegerWithVariableBitNumber(PRCbitStream &pbs, int32_t iValue, uint32_t uBitNumber) { WriteBoolean(iValue<0); WriteUnsignedIntegerWithVariableBitNumber(abs(iValue), uBitNumber - 1); } #define WriteIntegerWithVariableBitNumber( value, bit_number ) writeIntegerWithVariableBitNumber( pbs, (value), (bit_number) ); void writeDoubleWithVariableBitNumber(PRCbitStream &pbs, double dValue,double dTolerance, unsigned uBitNumber) { // calling functions must ensure no overflow int32_t iTempValue = (int32_t) ( dValue / dTolerance ); WriteIntegerWithVariableBitNumber(iTempValue, uBitNumber); } #define WriteDoubleWithVariableBitNumber( value, bit_number ) writeDoubleWithVariableBitNumber( pbs, (value), (bit_number) ); uint32_t GetNumberOfBitsUsedToStoreUnsignedInteger(uint32_t uValue) { uint32_t uNbBit=2; uint32_t uTemp = 2; while(uValue >= uTemp) { uTemp*=2; uNbBit++; } return uNbBit-1; } void writeNumberOfBitsThenUnsignedInteger(PRCbitStream &pbs, uint32_t unsigned_integer) { uint32_t number_of_bits = GetNumberOfBitsUsedToStoreUnsignedInteger( unsigned_integer ); WriteUnsignedIntegerWithVariableBitNumber ( number_of_bits, 5 ) WriteUnsignedIntegerWithVariableBitNumber ( unsigned_integer, number_of_bits ) } #define WriteNumberOfBitsThenUnsignedInteger( value ) writeNumberOfBitsThenUnsignedInteger( pbs, value ); uint32_t GetNumberOfBitsUsedToStoreInteger(int32_t iValue) { return GetNumberOfBitsUsedToStoreUnsignedInteger(abs(iValue))+1; } int32_t intdiv(double dValue, double dTolerance) { double ratio=fabs(dValue)/dTolerance; assert(ratio <= INT_MAX); int32_t iTempValue=(int32_t) ratio; if(ratio - iTempValue >= 0.5) iTempValue++; if(dValue < 0) return -iTempValue; else return iTempValue; } // round dValue to nearest multiple of dTolerance double roundto(double dValue, double dTolerance) { return intdiv(dValue, dTolerance) * dTolerance; } PRCVector3d roundto(PRCVector3d vec, double dTolerance) { PRCVector3d res; res.x = roundto(vec.x,dTolerance); res.y = roundto(vec.y,dTolerance); res.z = roundto(vec.z,dTolerance); return res; } uint32_t GetNumberOfBitsUsedToStoreDouble(double dValue, double dTolerance ) { return GetNumberOfBitsUsedToStoreInteger(intdiv(dValue,dTolerance)); } struct itriple { int32_t x; int32_t y; int32_t z; }; uint32_t GetNumberOfBitsUsedToStoreTripleInteger(const itriple &iTriple) { const uint32_t x_bits = GetNumberOfBitsUsedToStoreInteger(iTriple.x); const uint32_t y_bits = GetNumberOfBitsUsedToStoreInteger(iTriple.y); const uint32_t z_bits = GetNumberOfBitsUsedToStoreInteger(iTriple.z); uint32_t bits = x_bits; if(y_bits > bits) bits = y_bits; if(z_bits > bits) bits = z_bits; return bits; } itriple iroundto(PRCVector3d vec, double dTolerance) { itriple res; res.x = intdiv(vec.x, dTolerance); res.y = intdiv(vec.y, dTolerance); res.z = intdiv(vec.z, dTolerance); return res; } void PRCCompressedFace::serializeCompressedFace(PRCbitStream &pbs, double brep_data_compressed_tolerance) { serializeCompressedAnaNurbs( pbs, brep_data_compressed_tolerance ); } #define SerializeCompressedFace( value ) (value)->serializeCompressedFace( pbs, brep_data_compressed_tolerance ); void PRCCompressedFace::serializeContentCompressedFace(PRCbitStream &pbs) { WriteBoolean ( orientation_surface_with_shell ) const bool surface_is_trimmed = false; WriteBoolean ( surface_is_trimmed ) } void PRCCompressedFace::serializeCompressedAnaNurbs(PRCbitStream &pbs, double brep_data_compressed_tolerance) { // WriteCompressedEntityType ( PRC_HCG_AnaNurbs ) const bool is_a_curve = false; WriteBoolean ( is_a_curve ) WriteUnsignedIntegerWithVariableBitNumber (13 , 4) serializeContentCompressedFace( pbs ); serializeCompressedNurbs( pbs, brep_data_compressed_tolerance ); } void PRCCompressedFace::serializeCompressedNurbs(PRCbitStream &pbs, double brep_data_compressed_tolerance) { const double nurbs_tolerance = 0.2*brep_data_compressed_tolerance; const uint32_t degree_in_u = degree; const uint32_t degree_in_v = degree; WriteUnsignedIntegerWithVariableBitNumber ( degree_in_u, 5) WriteUnsignedIntegerWithVariableBitNumber ( degree_in_v, 5) const uint32_t number_of_knots_in_u = 4; // 0011 or 00001111 knot vector - just 2 spans WriteUnsignedIntegerWithVariableBitNumber (number_of_knots_in_u - 2, 16) uint32_t number_bit = degree_in_u ? Log2( degree_in_u + 2 ) : 2; WriteBoolean (false) // Multiplicity_is_already_stored - no WriteUnsignedIntegerWithVariableBitNumber( degree_in_u+1,number_bit) WriteBoolean (true) // Multiplicity_is_already_stored - yes const uint32_t number_of_knots_in_v = 4; // 0011 or 00001111 knot vector - just 2 spans WriteUnsignedIntegerWithVariableBitNumber (number_of_knots_in_v - 2, 16) number_bit = degree_in_v ? Log2( degree_in_v + 2 ) : 2; WriteBoolean (false) // Multiplicity_is_already_stored - no WriteUnsignedIntegerWithVariableBitNumber( degree_in_v+1,number_bit) WriteBoolean (true) // Multiplicity_is_already_stored - yes const bool is_closed_u = false; WriteBoolean ( is_closed_u ) const bool is_closed_v = false; WriteBoolean ( is_closed_v ) const uint32_t number_of_control_point_in_u = degree_in_u + 1; const uint32_t number_of_control_point_in_v = degree_in_v + 1; #if defined(__GNUC__) && !defined(__clang__) PRCVector3d P[number_of_control_point_in_u][number_of_control_point_in_v]; #else vector > P(number_of_control_point_in_u, vector(number_of_control_point_in_v)); #endif for(uint32_t i=0;i > compressed_control_point(number_of_control_point_in_u, vector(number_of_control_point_in_v)); vector > control_point_type(number_of_control_point_in_u, vector(number_of_control_point_in_v)); #endif uint32_t number_of_bits_for_isomin = 1; uint32_t number_of_bits_for_rest = 1; for(uint32_t j = 1; j < number_of_control_point_in_v; j++) { compressed_control_point[0][j] = iroundto(P[0][j]-P[0][j-1], nurbs_tolerance ); P[0][j] = P[0][j-1] + roundto(P[0][j]-P[0][j-1], nurbs_tolerance); uint32_t bit_size = GetNumberOfBitsUsedToStoreTripleInteger(compressed_control_point[0][j]); if (bit_size > number_of_bits_for_isomin) number_of_bits_for_isomin = bit_size; } for(uint32_t i = 1; i < number_of_control_point_in_u; i++) { compressed_control_point[i][0] = iroundto(P[i][0]-P[i-1][0], nurbs_tolerance ); P[i][0] = P[i-1][0] + roundto(P[i][0]-P[i-1][0], nurbs_tolerance); uint32_t bit_size = GetNumberOfBitsUsedToStoreTripleInteger(compressed_control_point[i][0]); if (bit_size > number_of_bits_for_isomin) number_of_bits_for_isomin = bit_size; } for(uint32_t i=1;i number_of_bits_for_rest) number_of_bits_for_rest = bit_size; } if( number_of_bits_for_rest == 2 ) number_of_bits_for_rest--; // really I think it must be unconditional, but so it seems to be done in Adobe Acrobat (9.3) WriteUnsignedIntegerWithVariableBitNumber ( number_of_bits_for_isomin, 20 ) WriteUnsignedIntegerWithVariableBitNumber ( number_of_bits_for_rest, 20 ) WriteDouble ( P[0][0].x ) WriteDouble ( P[0][0].y ) WriteDouble ( P[0][0].z ) for(uint32_t j = 1; j < number_of_control_point_in_v; j++) { WriteIntegerWithVariableBitNumber(compressed_control_point[0][j].x, number_of_bits_for_isomin+1) WriteIntegerWithVariableBitNumber(compressed_control_point[0][j].y, number_of_bits_for_isomin+1) WriteIntegerWithVariableBitNumber(compressed_control_point[0][j].z, number_of_bits_for_isomin+1) } for(uint32_t i = 1; i < number_of_control_point_in_u; i++) { WriteIntegerWithVariableBitNumber(compressed_control_point[i][0].x, number_of_bits_for_isomin+1) WriteIntegerWithVariableBitNumber(compressed_control_point[i][0].y, number_of_bits_for_isomin+1) WriteIntegerWithVariableBitNumber(compressed_control_point[i][0].z, number_of_bits_for_isomin+1) } for(uint32_t i = 1; i < number_of_control_point_in_u; i++) { for(uint32_t j = 1; j < number_of_control_point_in_v; j++) { WriteUnsignedIntegerWithVariableBitNumber ( control_point_type[i][j], 2 ) if(control_point_type[i][j] == 1) { WriteIntegerWithVariableBitNumber ( compressed_control_point[i][j].z, number_of_bits_for_rest+1 ) } else if(control_point_type[i][j] == 2) { WriteIntegerWithVariableBitNumber ( compressed_control_point[i][j].x, number_of_bits_for_rest+1 ) WriteIntegerWithVariableBitNumber ( compressed_control_point[i][j].y, number_of_bits_for_rest+1 ) } else if(control_point_type[i][j] == 3) { WriteIntegerWithVariableBitNumber ( compressed_control_point[i][j].x, number_of_bits_for_rest+1 ) WriteIntegerWithVariableBitNumber ( compressed_control_point[i][j].y, number_of_bits_for_rest+1 ) WriteIntegerWithVariableBitNumber ( compressed_control_point[i][j].z, number_of_bits_for_rest+1 ) } } } const uint32_t type_param_u = 0; WriteBoolean( type_param_u == 0 ) const uint32_t type_param_v = 0; WriteBoolean( type_param_v == 0 ) const bool is_rational = false; WriteBoolean( is_rational ) } void PRCCompressedBrepData::serializeCompressedShell(PRCbitStream &pbs) { uint32_t i; const uint32_t number_of_face = face.size(); WriteBoolean ( number_of_face == 1 ) if( number_of_face != 1 ) WriteNumberOfBitsThenUnsignedInteger (number_of_face) for( i=0; i < number_of_face; i++) SerializeCompressedFace ( face[i] ) const bool is_an_iso_face = false; for( i=0; i < number_of_face; i++) WriteBoolean ( is_an_iso_face ) } void PRCCompressedBrepData::serializeCompressedBrepData(PRCbitStream &pbs) { WriteUnsignedInteger ( PRC_TYPE_TOPO_BrepDataCompress ) SerializeContentBody WriteDouble ( brep_data_compressed_tolerance ) const uint32_t number_of_bits_to_store_reference = 1; WriteNumberOfBitsThenUnsignedInteger ( number_of_bits_to_store_reference ) const uint32_t number_vertex_iso = 0; WriteUnsignedIntegerWithVariableBitNumber ( number_vertex_iso, number_of_bits_to_store_reference ) const uint32_t number_edge_iso = 0; WriteUnsignedIntegerWithVariableBitNumber ( number_edge_iso, number_of_bits_to_store_reference ) const uint32_t number_of_shell = 1; const uint32_t number_of_connex = 1; WriteBoolean ( number_of_shell == 1 && number_of_connex == 1 ) serializeCompressedShell( pbs ); uint32_t i; const uint32_t number_of_faces = face.size(); for(i=0; i< number_of_faces; i++) face[i]->serializeBaseTopology( pbs ); } void PRCBlend01::serializeBlend01(PRCbitStream &pbs) { WriteUnsignedInteger (PRC_TYPE_SURF_Blend01) SerializeContentSurface SerializeTransformation SerializeUVParameterization SerializePtrCurve ( center_curve ) SerializePtrCurve ( origin_curve ) SerializePtrCurve ( tangent_curve ) } void PRCRuled::serializeRuled(PRCbitStream &pbs) { WriteUnsignedInteger (PRC_TYPE_SURF_Ruled) SerializeContentSurface SerializeTransformation SerializeUVParameterization SerializePtrCurve ( first_curve ) SerializePtrCurve ( second_curve ) } void PRCSphere::serializeSphere(PRCbitStream &pbs) { WriteUnsignedInteger (PRC_TYPE_SURF_Sphere) SerializeContentSurface SerializeTransformation SerializeUVParameterization WriteDouble ( radius ) } void PRCCone::serializeCone(PRCbitStream &pbs) { WriteUnsignedInteger (PRC_TYPE_SURF_Cone) SerializeContentSurface SerializeTransformation SerializeUVParameterization WriteDouble ( bottom_radius ) WriteDouble ( semi_angle ) } void PRCCylinder::serializeCylinder(PRCbitStream &pbs) { WriteUnsignedInteger (PRC_TYPE_SURF_Cylinder) SerializeContentSurface SerializeTransformation SerializeUVParameterization WriteDouble ( radius ) } void PRCTorus::serializeTorus(PRCbitStream &pbs) { WriteUnsignedInteger (PRC_TYPE_SURF_Torus) SerializeContentSurface SerializeTransformation SerializeUVParameterization WriteDouble ( major_radius ) WriteDouble ( minor_radius ) } void PRCFace::serializeFace(PRCbitStream &pbs) { uint32_t i = 0; WriteUnsignedInteger (PRC_TYPE_TOPO_Face) SerializeBaseTopology SerializePtrSurface ( base_surface ) WriteBit ( have_surface_trim_domain ) if ( have_surface_trim_domain ) SerializeDomain ( surface_trim_domain ) WriteBit ( have_tolerance ) if ( have_tolerance ) WriteDouble ( tolerance ) WriteUnsignedInteger ( number_of_loop ) WriteInteger ( outer_loop_index ) for (i=0;iserialType() ) if ( IsCompressedType(body[i]->serialType()) ) { WriteDouble ( body[i]->serialTolerance() ) } } } void PRCTopoContext::serializeContextGraphics(PRCbitStream &pbs) { uint32_t i=0, j=0, k=0, l=0; ResetCurrentGraphics uint32_t number_of_body = body.size(); PRCGraphicsList element; bool has_graphics = false; for (i=0;itopo_item_type == PRC_TYPE_TOPO_BrepData && dynamic_cast(body[i])) { PRCBrepData *body_i = dynamic_cast(body[i]); for (j=0;jconnex.size();j++) { for(k=0;kconnex[j]->shell.size();k++) { for( l=0;lconnex[j]->shell[k]->face.size();l++) { element.push_back( body_i->connex[j]->shell[k]->face[l] ); has_graphics = has_graphics || body_i->connex[j]->shell[k]->face[l]->has_graphics(); } } } } else if ( body[i]->topo_item_type == PRC_TYPE_TOPO_BrepDataCompress && dynamic_cast(body[i])) { PRCCompressedBrepData *body_i = dynamic_cast(body[i]); for( l=0;lface.size();l++) { element.push_back( body_i->face[l] ); has_graphics = has_graphics || body_i->face[l]->has_graphics(); } } } uint32_t number_of_treat_type = 0; if (has_graphics && !element.empty()) number_of_treat_type = 1; WriteUnsignedInteger (number_of_treat_type) for (i=0;ihas_graphics() ) if (element[j]->has_graphics()) { element[j]->serializeGraphics(pbs); } } } } uint32_t PRCTopoContext::addSingleWireBody(PRCSingleWireBody*& pSingleWireBody) { body.push_back(pSingleWireBody); pSingleWireBody = NULL; return body.size()-1; } uint32_t PRCTopoContext::addBrepData(PRCBrepData*& pBrepData) { body.push_back(pBrepData); pBrepData = NULL; return body.size()-1; } uint32_t PRCTopoContext::addCompressedBrepData(PRCCompressedBrepData*& pCompressedBrepData) { body.push_back(pCompressedBrepData); pCompressedBrepData = NULL; return body.size()-1; } void PRCSingleWireBody::serializeSingleWireBody(PRCbitStream &pbs) { WriteUnsignedInteger ( PRC_TYPE_TOPO_SingleWireBody) SerializeContentBody SerializePtrTopology ( wire_edge ) } void PRCUniqueId::serializeCompressedUniqueId(PRCbitStream &pbs) const { WriteUnsignedInteger (id0) WriteUnsignedInteger (id1) WriteUnsignedInteger (id2) WriteUnsignedInteger (id3) } void PRCUniqueId::serializeFileStructureUncompressedUniqueId(std::ostream& out) const { WriteUncompressedUnsignedInteger (id0) WriteUncompressedUnsignedInteger (id1) WriteUncompressedUnsignedInteger (id2) WriteUncompressedUnsignedInteger (id3) } void PRCUnit::serializeUnit(PRCbitStream &pbs) { WriteBoolean (unit_from_CAD_file) WriteDouble (unit) } void PRCProductOccurrence::serializeProductOccurrence(PRCbitStream &pbs) { WriteUnsignedInteger ( PRC_TYPE_ASM_ProductOccurence ) SerializePRCBaseWithGraphics // SerializeReferencesOfProductOccurrence WriteUnsignedInteger (index_part+1) WriteUnsignedInteger (index_prototype+1) if (index_prototype != m1) { WriteBoolean (prototype_in_same_file_structure) if (!prototype_in_same_file_structure) SerializeCompressedUniqueId (prototype_file_structure) } WriteUnsignedInteger(index_external_data+1) if (index_external_data != m1) { WriteBoolean (external_data_in_same_file_structure) if (!external_data_in_same_file_structure) SerializeCompressedUniqueId (external_data_file_structure) } const uint32_t number_of_son_product_occurrences = index_son_occurrence.size(); WriteUnsignedInteger (number_of_son_product_occurrences) for (uint32_t i=0;iserializeTransformation3d (pbs); WriteUnsignedInteger (0) // number_of_references // SerializeMarkups (markups) WriteUnsignedInteger (0) // number_of_linked_items WriteUnsignedInteger (0) // number_of_leaders WriteUnsignedInteger (0) // number_of_markups WriteUnsignedInteger (0) // number_of_annotation_entities WriteUnsignedInteger (0) // number_of_views WriteBit (false) // has_entity_filter WriteUnsignedInteger (0) // number_of_display_filters WriteUnsignedInteger (0) // number_of_scene_display_parameters SerializeUserData } uint32_t PRCPartDefinition::addBrepModel(PRCBrepModel*& pBrepModel) { representation_item.push_back(pBrepModel); pBrepModel = NULL; return representation_item.size()-1; } uint32_t PRCPartDefinition::addPolyBrepModel(PRCPolyBrepModel*& pPolyBrepModel) { representation_item.push_back(pPolyBrepModel); pPolyBrepModel = NULL; return representation_item.size()-1; } uint32_t PRCPartDefinition::addPointSet(PRCPointSet*& pPointSet) { representation_item.push_back(pPointSet); pPointSet = NULL; return representation_item.size()-1; } uint32_t PRCPartDefinition::addSet(PRCSet*& pSet) { representation_item.push_back(pSet); pSet = NULL; return representation_item.size()-1; } uint32_t PRCPartDefinition::addWire(PRCWire*& pWire) { representation_item.push_back(pWire); pWire = NULL; return representation_item.size()-1; } uint32_t PRCPartDefinition::addPolyWire(PRCPolyWire*& pPolyWire) { representation_item.push_back(pPolyWire); pPolyWire = NULL; return representation_item.size()-1; } uint32_t PRCPartDefinition::addRepresentationItem(PRCRepresentationItem*& pRepresentationItem) { representation_item.push_back(pRepresentationItem); pRepresentationItem = NULL; return representation_item.size()-1; } void PRCPartDefinition::serializePartDefinition(PRCbitStream &pbs) { WriteUnsignedInteger ( PRC_TYPE_ASM_PartDefinition ) SerializePRCBaseWithGraphics SerializeBoundingBox uint32_t number_of_representation_items = representation_item.size(); WriteUnsignedInteger (number_of_representation_items) for (uint32_t i=0;i and * Michail Vidiassov * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * *************/ #ifndef __WRITE_PRC_H #define __WRITE_PRC_H #include #include #include #include #include #include #include "PRCbitStream.h" #include "PRC.h" #include #include static const uint32_t m1=(uint32_t)-1; static const double pi=acos(-1.0); class PRCVector3d { public : double x; double y; double z; PRCVector3d() : x(0), y(0), z(0) {} PRCVector3d(double fx, double fy, double fz) : x(fx), y(fy), z(fz) {} PRCVector3d(const double c[], double fx=0, double fy=0, double fz=0) : x(c?c[0]:fx), y(c?c[1]:fy), z(c?c[2]:fz) {} PRCVector3d(const PRCVector3d& sVector3d) : x(sVector3d.x), y(sVector3d.y), z(sVector3d.z) {} void Set(double fx, double fy, double fz) { x = fx; y = fy; z = fz; } double Dot(const PRCVector3d & sPt) const { return(x*sPt.x)+(y*sPt.y)+(z*sPt.z); } double LengthSquared() { return(x*x+y*y+z*z); } friend PRCVector3d operator + (const PRCVector3d& a, const PRCVector3d& b) { return PRCVector3d(a.x+b.x,a.y+b.y,a.z+b.z); } friend PRCVector3d operator - (const PRCVector3d& a) { return PRCVector3d(-a.x,-a.y,-a.z); } friend PRCVector3d operator - (const PRCVector3d& a, const PRCVector3d& b) { return PRCVector3d(a.x-b.x,a.y-b.y,a.z-b.z); } friend PRCVector3d operator * (const PRCVector3d& a, const double d) { return PRCVector3d(a.x*d,a.y*d,a.z*d); } friend PRCVector3d operator * (const double d, const PRCVector3d& a) { return PRCVector3d(a.x*d,a.y*d,a.z*d); } friend PRCVector3d operator / (const PRCVector3d& a, const double d) { return PRCVector3d(a.x/d,a.y/d,a.z/d); } friend PRCVector3d operator * (const PRCVector3d& a, const PRCVector3d& b) { return PRCVector3d((a.y*b.z)-(a.z*b.y), (a.z*b.x)-(a.x*b.z), (a.x*b.y)-(a.y*b.x)); } void write(PRCbitStream &out) { out << x << y << z; } void serializeVector3d(PRCbitStream &pbs) const { pbs << x << y << z; } void serializeVector2d(PRCbitStream &pbs) const { pbs << x << y; } double Length(); bool Normalize(); bool operator==(const PRCVector3d &v) const { return x==v.x && y==v.y && z==v.z; } bool operator!=(const PRCVector3d &v) const { return !(x==v.x && y==v.y && z==v.z); } bool operator<(const PRCVector3d &v) const { if(x!=v.x) return (x attribute_keys; }; typedef std::list PRCAttributeList; class PRCAttributes { public: void serializeAttributes(PRCbitStream&) const; PRCAttribute& newAttribute() { attributes.push_front(PRCAttribute()); return attributes.front(); } void addAttribute(const PRCAttribute &attribute) { attributes.push_front(attribute); } PRCAttributeList attributes; }; bool type_eligible_for_reference(uint32_t type); uint32_t makeCADID(); uint32_t makePRCID(); class ContentPRCBase : public PRCAttributes { public: ContentPRCBase(uint32_t t, std::string n="") : type(t),name(n),CAD_identifier(0), CAD_persistent_identifier(0), PRC_unique_identifier(0) { if(type_eligible_for_reference(type)) { CAD_identifier = makeCADID(); PRC_unique_identifier = makePRCID(); } } void serializeContentPRCBase(PRCbitStream&) const; uint32_t getPRCID() const { return PRC_unique_identifier; } uint32_t getType() const { return type; } uint32_t type; std::string name; uint32_t CAD_identifier, CAD_persistent_identifier, PRC_unique_identifier; }; class PRCReferenceUniqueIdentifier { public: PRCReferenceUniqueIdentifier() : type(0), unique_identifier(m1) {} void serializeReferenceUniqueIdentifier(PRCbitStream&); uint32_t type; // bool reference_in_same_file_structure; // PRCUniqueId target_file_structure; uint32_t unique_identifier; }; extern std::string currentName; void writeName(PRCbitStream&,const std::string&); void resetName(); extern uint32_t current_layer_index; extern uint32_t current_index_of_line_style; extern uint16_t current_behaviour_bit_field; void writeGraphics(PRCbitStream&,uint32_t=m1,uint32_t=m1,uint16_t=1,bool=false); void resetGraphics(); void resetGraphicsAndName(); struct PRCRgbColor { PRCRgbColor(double r=0.0, double g=0.0, double b=0.0) : red(r), green(g), blue(b) {} double red,green,blue; void serializeRgbColor(PRCbitStream&); bool operator==(const PRCRgbColor &c) const { return (red==c.red && green==c.green && blue==c.blue); } bool operator!=(const PRCRgbColor &c) const { return !(red==c.red && green==c.green && blue==c.blue); } bool operator<(const PRCRgbColor &c) const { if(red!=c.red) return (red PRCTextureDefinitionList; class PRCMaterial { public: virtual ~PRCMaterial() {} virtual void serializeMaterial(PRCbitStream&) = 0; }; typedef std::deque PRCMaterialList; class PRCMaterialGeneric : public ContentPRCBase, public PRCMaterial { public: PRCMaterialGeneric(std::string n="") : ContentPRCBase(PRC_TYPE_GRAPH_Material,n), ambient(m1), diffuse(m1), emissive(m1), specular(m1), shininess(0.0), ambient_alpha(1.0), diffuse_alpha(1.0), emissive_alpha(1.0), specular_alpha(1.0) {} void serializeMaterialGeneric(PRCbitStream&); void serializeMaterial(PRCbitStream &pbs) { serializeMaterialGeneric(pbs); } uint32_t picture_index; uint32_t ambient; uint32_t diffuse; uint32_t emissive; uint32_t specular; double shininess; double ambient_alpha; double diffuse_alpha; double emissive_alpha; double specular_alpha; bool operator==(const PRCMaterialGeneric &m) const { return (ambient==m.ambient && diffuse==m.diffuse && emissive==m.emissive && specular==m.specular && shininess==m.shininess && ambient_alpha==m.ambient_alpha && diffuse_alpha==m.diffuse_alpha && emissive_alpha==m.emissive_alpha && specular_alpha==m.specular_alpha); } }; class PRCTextureApplication : public ContentPRCBase, public PRCMaterial { public: PRCTextureApplication(std::string n="") : ContentPRCBase(PRC_TYPE_GRAPH_TextureApplication,n), material_generic_index(m1), texture_definition_index(m1), next_texture_index(m1), UV_coordinates_index(0) {} void serializeTextureApplication(PRCbitStream&); void serializeMaterial(PRCbitStream &pbs) { serializeTextureApplication(pbs); } uint32_t material_generic_index; uint32_t texture_definition_index; uint32_t next_texture_index; uint32_t UV_coordinates_index; }; class PRCLinePattern : public ContentPRCBase { public: PRCLinePattern(std::string n="") : ContentPRCBase(PRC_TYPE_GRAPH_LinePattern,n), phase(0), is_real_length(false) {} void serializeLinePattern(PRCbitStream&); std::vector lengths; double phase; bool is_real_length; }; typedef std::deque PRCLinePatternList; class PRCStyle : public ContentPRCBase { public: PRCStyle(std::string n="") : ContentPRCBase(PRC_TYPE_GRAPH_Style,n), line_width(0.0), is_vpicture(false), line_pattern_vpicture_index(m1), is_material(false), color_material_index(m1), is_transparency_defined(false), transparency(255), additional(0) {} void serializeCategory1LineStyle(PRCbitStream&); double line_width; bool is_vpicture; uint32_t line_pattern_vpicture_index; bool is_material; uint32_t color_material_index; bool is_transparency_defined; uint8_t transparency; uint8_t additional; }; typedef std::deque PRCStyleList; class PRCTessFace { public: PRCTessFace() : start_wire(0), used_entities_flag(0), start_triangulated(0), number_of_texture_coordinate_indexes(0), is_rgba(false), behaviour(PRC_GRAPHICS_Show) {} void serializeTessFace(PRCbitStream&); std::vector line_attributes; uint32_t start_wire; // specifing bounding wire seems not to work as of Acrobat/Reader 9.2 std::vector sizes_wire; // specifing bounding wire seems not to work as of Acrobat/Reader 9.2 uint32_t used_entities_flag; uint32_t start_triangulated; std::vector sizes_triangulated; uint32_t number_of_texture_coordinate_indexes; bool is_rgba; std::vector rgba_vertices; uint32_t behaviour; }; typedef std::deque PRCTessFaceList; class PRCContentBaseTessData { public: PRCContentBaseTessData() : is_calculated(false) {} void serializeContentBaseTessData(PRCbitStream&); bool is_calculated; std::vector coordinates; }; class PRCTess : public PRCContentBaseTessData { public: virtual ~PRCTess() {} virtual void serializeBaseTessData(PRCbitStream &pbs) = 0; }; typedef std::deque PRCTessList; class PRC3DTess : public PRCTess { public: PRC3DTess() : has_faces(false), has_loops(false), crease_angle(25.8419) // arccos(0.9), default found in Acrobat output {} ~PRC3DTess() { for(PRCTessFaceList::iterator it=face_tessellation.begin(); it!=face_tessellation.end(); ++it) delete *it; } void serialize3DTess(PRCbitStream&); void serializeBaseTessData(PRCbitStream &pbs) { serialize3DTess(pbs); } void addTessFace(PRCTessFace*& pTessFace); bool has_faces; bool has_loops; double crease_angle; std::vector normal_coordinate; std::vector wire_index; // specifing bounding wire seems not to work as of Acrobat/Reader 9.2 std::vector triangulated_index; PRCTessFaceList face_tessellation; std::vector texture_coordinate; }; class PRC3DWireTess : public PRCTess { public: PRC3DWireTess() : is_rgba(false), is_segment_color(false) {} void serialize3DWireTess(PRCbitStream&); void serializeBaseTessData(PRCbitStream &pbs) { serialize3DWireTess(pbs); } bool is_rgba; bool is_segment_color; std::vector wire_indexes; std::vector rgba_vertices; }; class PRCMarkupTess : public PRCTess { public: PRCMarkupTess() : behaviour(0) {} void serializeMarkupTess(PRCbitStream&); void serializeBaseTessData(PRCbitStream &pbs) { serializeMarkupTess(pbs); } std::vector codes; std::vector texts; std::string label; uint8_t behaviour; }; class PRCGraphics { public: PRCGraphics() : layer_index(m1), index_of_line_style(m1), behaviour_bit_field(PRC_GRAPHICS_Show) {} void serializeGraphics(PRCbitStream&); void serializeGraphicsForced(PRCbitStream&); bool has_graphics() { return (index_of_line_style!=m1 || layer_index!=m1 || behaviour_bit_field!=PRC_GRAPHICS_Show) ; } uint32_t layer_index; uint32_t index_of_line_style; uint16_t behaviour_bit_field; }; typedef std::deque PRCGraphicsList; void writeGraphics(PRCbitStream&,const PRCGraphics&,bool=false); class PRCMarkup: public PRCGraphics, public ContentPRCBase { public: PRCMarkup(std::string n="") : ContentPRCBase(PRC_TYPE_MKP_Markup,n), type(KEPRCMarkupType_Unknown), sub_type(KEPRCMarkupSubType_Unknown), index_tessellation(m1) {} void serializeMarkup(PRCbitStream&); EPRCMarkupType type; EPRCMarkupSubType sub_type; // vector linked_items; // vector leaders; uint32_t index_tessellation; }; typedef std::deque PRCMarkupList; class PRCAnnotationItem: public PRCGraphics, public ContentPRCBase { public: PRCAnnotationItem(std::string n="") : ContentPRCBase(PRC_TYPE_MKP_AnnotationItem,n) {} void serializeAnnotationItem(PRCbitStream&); void serializeAnnotationEntity(PRCbitStream &pbs) { serializeAnnotationItem(pbs); } PRCReferenceUniqueIdentifier markup; }; typedef std::deque PRCAnnotationItemList; class PRCRepresentationItemContent: public PRCGraphics, public ContentPRCBase { public: PRCRepresentationItemContent(uint32_t t, std::string n="") : ContentPRCBase(t,n), index_local_coordinate_system(m1), index_tessellation(m1) {} void serializeRepresentationItemContent(PRCbitStream&); uint32_t index_local_coordinate_system; uint32_t index_tessellation; }; class PRCRepresentationItem : public PRCRepresentationItemContent { public: PRCRepresentationItem(uint32_t t, std::string n="") : PRCRepresentationItemContent(t,n) {} virtual ~PRCRepresentationItem() {} virtual void serializeRepresentationItem(PRCbitStream &pbs) = 0; }; typedef std::deque PRCRepresentationItemList; class PRCBrepModel : public PRCRepresentationItem { public: PRCBrepModel(std::string n="") : PRCRepresentationItem(PRC_TYPE_RI_BrepModel,n), has_brep_data(true), context_id(m1), body_id(m1), is_closed(false) {} void serializeBrepModel(PRCbitStream&); void serializeRepresentationItem(PRCbitStream &pbs) { serializeBrepModel(pbs); } bool has_brep_data; uint32_t context_id; uint32_t body_id; bool is_closed; }; class PRCPolyBrepModel : public PRCRepresentationItem { public: PRCPolyBrepModel(std::string n="") : PRCRepresentationItem(PRC_TYPE_RI_PolyBrepModel,n), is_closed(false) {} void serializePolyBrepModel(PRCbitStream&); void serializeRepresentationItem(PRCbitStream &pbs) { serializePolyBrepModel(pbs); } bool is_closed; }; class PRCPointSet : public PRCRepresentationItem { public: PRCPointSet(std::string n="") : PRCRepresentationItem(PRC_TYPE_RI_PointSet,n) {} void serializePointSet(PRCbitStream&); void serializeRepresentationItem(PRCbitStream &pbs) { serializePointSet(pbs); } std::vector point; }; class PRCWire : public PRCRepresentationItem { public: PRCWire(std::string n="") : PRCRepresentationItem(PRC_TYPE_RI_Curve,n), has_wire_body(true), context_id(m1), body_id(m1) {} void serializeWire(PRCbitStream&); void serializeRepresentationItem(PRCbitStream &pbs) { serializeWire(pbs); } bool has_wire_body; uint32_t context_id; uint32_t body_id; }; class PRCPolyWire : public PRCRepresentationItem { public: PRCPolyWire(std::string n="") : PRCRepresentationItem(PRC_TYPE_RI_PolyWire,n) {} void serializePolyWire(PRCbitStream&); void serializeRepresentationItem(PRCbitStream &pbs) { serializePolyWire(pbs); } }; class PRCSet : public PRCRepresentationItem { public: PRCSet(std::string n="") : PRCRepresentationItem(PRC_TYPE_RI_Set,n) {} ~PRCSet() { for(PRCRepresentationItemList::iterator it=elements.begin(); it!=elements.end(); ++it) delete *it; } void serializeSet(PRCbitStream&); void serializeRepresentationItem(PRCbitStream &pbs) { serializeSet(pbs); } uint32_t addBrepModel(PRCBrepModel*& pBrepModel); uint32_t addPolyBrepModel(PRCPolyBrepModel*& pPolyBrepModel); uint32_t addPointSet(PRCPointSet*& pPointSet); uint32_t addSet(PRCSet*& pSet); uint32_t addWire(PRCWire*& pWire); uint32_t addPolyWire(PRCPolyWire*& pPolyWire); uint32_t addRepresentationItem(PRCRepresentationItem*& pRepresentationItem); PRCRepresentationItemList elements; }; class PRCTransformation3d { public: virtual ~PRCTransformation3d() {} virtual void serializeTransformation3d(PRCbitStream&) const =0; }; typedef std::deque PRCTransformation3dList; class PRCGeneralTransformation3d : public PRCTransformation3d { public: PRCGeneralTransformation3d() { setidentity(); } PRCGeneralTransformation3d(const double t[]) { set(t); } void serializeGeneralTransformation3d(PRCbitStream&) const; void serializeTransformation3d(PRCbitStream& pbs) const { serializeGeneralTransformation3d(pbs); } double mat[4][4]; bool operator==(const PRCGeneralTransformation3d &t) const { for (size_t i=0;i<4;i++) for (size_t j=0;j<4;j++) if(mat[i][j]!=t.mat[i][j]) return false; return true; } bool operator<(const PRCGeneralTransformation3d &t) const { for (size_t i=0;i<4;i++) for (size_t j=0;j<4;j++) if(mat[i][j]!=t.mat[i][j]) { return (mat[i][j] PRCGeneralTransformation3dList; class PRCCartesianTransformation3d : public PRCTransformation3d { public: PRCCartesianTransformation3d() : behaviour(PRC_TRANSFORMATION_Identity), origin(0.0,0.0,0.0), X(1.0,0.0,0.0), Y(0.0,1.0,0.0), Z(0.0,0.0,1.0), scale(1.0,1.0,1.0), uniform_scale(1.0), X_homogeneous_coord(0.0), Y_homogeneous_coord(0.0), Z_homogeneous_coord(0.0), origin_homogeneous_coord(1.0) {} PRCCartesianTransformation3d(const double o[3], const double x[3], const double y[3], double sc) : behaviour(PRC_TRANSFORMATION_Identity), origin(o,0.0,0.0,0.0), X(x,1.0,0.0,0.0), Y(y,0.0,1.0,0.0), Z(0.0,0.0,1.0), scale(1.0,1.0,1.0), uniform_scale(sc), X_homogeneous_coord(0.0), Y_homogeneous_coord(0.0), Z_homogeneous_coord(0.0), origin_homogeneous_coord(1.0) { if(origin!=PRCVector3d(0.0,0.0,0.0)) behaviour = behaviour | PRC_TRANSFORMATION_Translate; if(X!=PRCVector3d(1.0,0.0,0.0) || Y!=PRCVector3d(0.0,1.0,0.0)) behaviour = behaviour | PRC_TRANSFORMATION_Rotate; if(uniform_scale!=1) behaviour = behaviour | PRC_TRANSFORMATION_Scale; } void serializeCartesianTransformation3d(PRCbitStream& pbs) const; void serializeTransformation3d(PRCbitStream& pbs) const { serializeCartesianTransformation3d(pbs); } uint8_t behaviour; PRCVector3d origin; PRCVector3d X; PRCVector3d Y; PRCVector3d Z; PRCVector3d scale; double uniform_scale; double X_homogeneous_coord; double Y_homogeneous_coord; double Z_homogeneous_coord; double origin_homogeneous_coord; bool operator==(const PRCCartesianTransformation3d &t) const { return behaviour==t.behaviour && origin==t.origin && X==t.X && Y==t.Y && Z==t.Z && scale==t.scale && uniform_scale==t.uniform_scale && X_homogeneous_coord==t.X_homogeneous_coord && Y_homogeneous_coord==t.Y_homogeneous_coord && Z_homogeneous_coord==t.Z_homogeneous_coord && origin_homogeneous_coord==t.origin_homogeneous_coord; } }; class PRCTransformation { public: PRCTransformation() : has_transformation(false), geometry_is_2D(false), behaviour(PRC_TRANSFORMATION_Identity), origin(0.0,0.0,0.0), x_axis(1.0,0.0,0.0), y_axis(0.0,1.0,0.0), scale(1) {} void serializeTransformation(PRCbitStream&); bool has_transformation; bool geometry_is_2D; uint8_t behaviour; PRCVector3d origin; PRCVector3d x_axis; PRCVector3d y_axis; double scale; }; class PRCCoordinateSystem : public PRCRepresentationItem { public: PRCCoordinateSystem(std::string n="") : PRCRepresentationItem(PRC_TYPE_RI_CoordinateSystem,n), axis_set(NULL) {} ~PRCCoordinateSystem() { delete axis_set; } void serializeCoordinateSystem(PRCbitStream&); void serializeRepresentationItem(PRCbitStream &pbs) { serializeCoordinateSystem(pbs); } void setAxisSet(PRCGeneralTransformation3d*& transform) { axis_set = transform; transform = NULL; } void setAxisSet(PRCCartesianTransformation3d*& transform) { axis_set = transform; transform = NULL; } PRCTransformation3d *axis_set; bool operator==(const PRCCoordinateSystem &t) const { if(index_local_coordinate_system!=t.index_local_coordinate_system) return false; PRCGeneralTransformation3d* axis_set_general = dynamic_cast(axis_set); PRCGeneralTransformation3d* t_axis_set_general = dynamic_cast(t.axis_set); PRCCartesianTransformation3d* axis_set_cartesian = dynamic_cast(axis_set); PRCCartesianTransformation3d* t_axis_set_cartesian = dynamic_cast(t.axis_set); if(axis_set_general!=NULL) return (t_axis_set_general!=NULL?(*axis_set_general==*t_axis_set_general):false); if(axis_set_cartesian!=NULL) return (t_axis_set_cartesian!=NULL?(*axis_set_cartesian==*t_axis_set_cartesian):false); return false; } }; typedef std::deque PRCCoordinateSystemList; struct PRCFontKey { uint32_t font_size; uint8_t attributes; }; class PRCFontKeysSameFont { public: void serializeFontKeysSameFont(PRCbitStream&); std::string font_name; uint32_t char_set; std::vector font_keys; }; // Topology class PRCBaseGeometry : public PRCAttributes { public: PRCBaseGeometry() : base_information(false), identifier(0) {} PRCBaseGeometry(std::string n, uint32_t id = 0) : base_information(true),name(n),identifier(id) {} void serializeBaseGeometry(PRCbitStream&); bool base_information; std::string name; uint32_t identifier; }; class PRCBoundingBox { public: PRCBoundingBox() : min(0.0,0.0,0.0), max(0.0,0.0,0.0) {} PRCBoundingBox(const PRCVector3d &m1, const PRCVector3d& m2) : min(m1),max(m2) {} void serializeBoundingBox(PRCbitStream &pbs); PRCVector3d min; PRCVector3d max; }; class PRCDomain { public: void serializeDomain(PRCbitStream &pbs); PRCVector2d min; PRCVector2d max; }; class PRCInterval { public: PRCInterval() : min(0), max(0) {} PRCInterval(double m, double M) : min(m), max(M) {} void serializeInterval(PRCbitStream &pbs); double min; double max; }; class PRCParameterization { public: PRCParameterization() : parameterization_coeff_a(1), parameterization_coeff_b(0) {} PRCParameterization(double min, double max) : interval(min, max), parameterization_coeff_a(1), parameterization_coeff_b(0) {} void serializeParameterization(PRCbitStream &pbs); PRCInterval interval; double parameterization_coeff_a; double parameterization_coeff_b; }; class PRCUVParameterization { public: PRCUVParameterization() : swap_uv(false), parameterization_on_u_coeff_a(1), parameterization_on_v_coeff_a(1), parameterization_on_u_coeff_b(0), parameterization_on_v_coeff_b(0) {} void serializeUVParameterization(PRCbitStream &pbs); bool swap_uv; PRCDomain uv_domain; double parameterization_on_u_coeff_a; double parameterization_on_v_coeff_a; double parameterization_on_u_coeff_b; double parameterization_on_v_coeff_b; }; class PRCControlPoint { public: PRCControlPoint() : x(0), y(0), z(0), w(1) {} PRCControlPoint(double X, double Y, double Z=0, double W=1) : x(X), y(Y), z(Z), w(W) {} PRCControlPoint(const PRCVector3d &v) : x(v.x), y(v.y), z(v.z), w(1) {} void Set(double fx, double fy, double fz, double fw=1) { x = fx; y = fy; z = fz; w = fw; } double x; double y; double z; double w; }; class PRCContentSurface: public PRCBaseGeometry { public: PRCContentSurface() : PRCBaseGeometry(), extend_info(KEPRCExtendTypeNone) {} PRCContentSurface(std::string n) : PRCBaseGeometry(n,makeCADID()),extend_info(KEPRCExtendTypeNone) {} void serializeContentSurface(PRCbitStream&); EPRCExtendType extend_info; }; class PRCSurface : public PRCContentSurface { public: PRCSurface() : PRCContentSurface() {} PRCSurface(std::string n) : PRCContentSurface(n) {} virtual ~PRCSurface() {} virtual void serializeSurface(PRCbitStream &pbs) = 0; }; class PRCNURBSSurface : public PRCSurface { public: PRCNURBSSurface() : PRCSurface(), knot_type(KEPRCKnotTypeUnspecified), surface_form(KEPRCBSplineSurfaceFormUnspecified) {} PRCNURBSSurface(std::string n) : PRCSurface(n), knot_type(KEPRCKnotTypeUnspecified), surface_form(KEPRCBSplineSurfaceFormUnspecified) {} void serializeNURBSSurface(PRCbitStream &pbs); void serializeSurface(PRCbitStream &pbs) { serializeNURBSSurface(pbs); } bool is_rational; uint32_t degree_in_u; uint32_t degree_in_v; std::vector control_point; std::vector knot_u; std::vector knot_v; const EPRCKnotType knot_type; const EPRCBSplineSurfaceForm surface_form; }; class PRCContentCurve: public PRCBaseGeometry { public: PRCContentCurve() : PRCBaseGeometry(), extend_info(KEPRCExtendTypeNone), is_3d(true) {} PRCContentCurve(std::string n) : PRCBaseGeometry(n,makeCADID()),extend_info(KEPRCExtendTypeNone), is_3d(true) {} void serializeContentCurve(PRCbitStream&); EPRCExtendType extend_info; bool is_3d; }; class PRCCurve : public PRCContentCurve { public: PRCCurve() : PRCContentCurve() {} PRCCurve(std::string n) : PRCContentCurve(n) {} virtual ~PRCCurve() {} virtual void serializeCurve(PRCbitStream &pbs) = 0; }; typedef std::deque PRCCurveList; class PRCNURBSCurve : public PRCCurve { public: PRCNURBSCurve() : PRCCurve(), knot_type(KEPRCKnotTypeUnspecified), curve_form(KEPRCBSplineCurveFormUnspecified) {} PRCNURBSCurve(std::string n) : PRCCurve(n), knot_type(KEPRCKnotTypeUnspecified), curve_form(KEPRCBSplineCurveFormUnspecified) {} void serializeNURBSCurve(PRCbitStream &pbs); void serializeCurve(PRCbitStream &pbs) { serializeNURBSCurve(pbs); } bool is_rational; uint32_t degree; std::vector control_point; std::vector knot; const EPRCKnotType knot_type; const EPRCBSplineCurveForm curve_form; }; class PRCPolyLine : public PRCCurve, public PRCTransformation, public PRCParameterization { public: PRCPolyLine() : PRCCurve() {} PRCPolyLine(std::string n) : PRCCurve(n) {} void serializePolyLine(PRCbitStream &pbs); void serializeCurve(PRCbitStream &pbs) { serializePolyLine(pbs); } std::vector point; }; class PRCCircle : public PRCCurve, public PRCTransformation, public PRCParameterization { public: PRCCircle() : PRCCurve(), PRCParameterization(0,2*pi) {} PRCCircle(std::string n) : PRCCurve(n), PRCParameterization(0,2*pi) {} void serializeCircle(PRCbitStream &pbs); void serializeCurve(PRCbitStream &pbs) { serializeCircle(pbs); } double radius; }; class PRCComposite : public PRCCurve, public PRCTransformation, public PRCParameterization { public: PRCComposite() : PRCCurve() {} PRCComposite(std::string n) : PRCCurve(n) {} void serializeComposite(PRCbitStream &pbs); void serializeCurve(PRCbitStream &pbs) { serializeComposite(pbs); } PRCCurveList base_curve; std::vector base_sense; bool is_closed; }; class PRCBlend01 : public PRCSurface, public PRCTransformation, public PRCUVParameterization { public: PRCBlend01() : PRCSurface(), center_curve(NULL), origin_curve(NULL), tangent_curve(NULL) {} PRCBlend01(std::string n) : PRCSurface(n), center_curve(NULL), origin_curve(NULL), tangent_curve(NULL) {} ~PRCBlend01() { delete center_curve; delete origin_curve; delete tangent_curve; } void serializeBlend01(PRCbitStream &pbs); void serializeSurface(PRCbitStream &pbs) { serializeBlend01(pbs); } // void setCenterCurve (PRCCurve*& curve) { center_curve = curve; curve = NULL; } // void setOriginCurve (PRCCurve*& curve) { origin_curve = curve; curve = NULL; } // void setTangentCurve(PRCCurve*& curve) { tangent_curve = curve; curve = NULL; } PRCCurve* center_curve; PRCCurve* origin_curve; PRCCurve* tangent_curve; }; class PRCRuled : public PRCSurface, public PRCTransformation, public PRCUVParameterization { public: PRCRuled() : PRCSurface(), first_curve(NULL), second_curve(NULL) {} PRCRuled(std::string n) : PRCSurface(n) {} ~PRCRuled() { delete first_curve; delete second_curve; } void serializeRuled(PRCbitStream &pbs); void serializeSurface(PRCbitStream &pbs) { serializeRuled(pbs); } // void setFirstCurve(PRCCurve*& curve) { first_curve = curve; curve = NULL; } // void setSecondCurve(PRCCurve*& curve) { second_curve = curve; curve = NULL; } PRCCurve* first_curve; PRCCurve* second_curve; }; class PRCSphere : public PRCSurface, public PRCTransformation, public PRCUVParameterization { public: PRCSphere() : PRCSurface() {} PRCSphere(std::string n) : PRCSurface(n) {} void serializeSphere(PRCbitStream &pbs); void serializeSurface(PRCbitStream &pbs) { serializeSphere(pbs); } double radius; }; class PRCCone : public PRCSurface, public PRCTransformation, public PRCUVParameterization { public: PRCCone() : PRCSurface() {} PRCCone(std::string n) : PRCSurface(n) {} void serializeCone(PRCbitStream &pbs); void serializeSurface(PRCbitStream &pbs) { serializeCone(pbs); } double bottom_radius; double semi_angle; }; class PRCCylinder : public PRCSurface, public PRCTransformation, public PRCUVParameterization { public: PRCCylinder() : PRCSurface() {} PRCCylinder(std::string n) : PRCSurface(n) {} void serializeCylinder(PRCbitStream &pbs); void serializeSurface(PRCbitStream &pbs) { serializeCylinder(pbs); } double radius; }; class PRCTorus : public PRCSurface, public PRCTransformation, public PRCUVParameterization { public: PRCTorus() : PRCSurface() {} PRCTorus(std::string n) : PRCSurface(n) {} void serializeTorus(PRCbitStream &pbs); void serializeSurface(PRCbitStream &pbs) { serializeTorus(pbs); } double major_radius; double minor_radius; }; class PRCBaseTopology : public PRCAttributes { public: PRCBaseTopology() : base_information(false),identifier(0) {} PRCBaseTopology(std::string n, uint32_t id = 0) : base_information(true),name(n),identifier(id) {} void serializeBaseTopology(PRCbitStream&); bool base_information; std::string name; uint32_t identifier; }; class PRCTopoItem { public: virtual ~PRCTopoItem() {} virtual void serializeTopoItem(PRCbitStream&)=0; }; class PRCContentBody: public PRCBaseTopology { public: PRCContentBody() : PRCBaseTopology(), behavior(0) {} PRCContentBody(std::string n) : PRCBaseTopology(n,makeCADID()), behavior(0) {} void serializeContentBody(PRCbitStream&); uint8_t behavior; }; class PRCBody : public PRCContentBody, public PRCTopoItem { public: PRCBody() : PRCContentBody(), topo_item_type(PRC_TYPE_ROOT) {} PRCBody(uint32_t tit) : PRCContentBody(), topo_item_type(tit) {} PRCBody(uint32_t tit, std::string n) : PRCContentBody(n), topo_item_type(tit) {} virtual ~PRCBody() {} virtual void serializeBody(PRCbitStream &pbs) = 0; void serializeTopoItem(PRCbitStream &pbs) { serializeBody(pbs); } uint32_t serialType() { return topo_item_type; } virtual double serialTolerance() { return 0; } const uint32_t topo_item_type; }; typedef std::deque PRCBodyList; class PRCContentWireEdge : public PRCBaseTopology { public: PRCContentWireEdge() : PRCBaseTopology(), curve_3d(NULL), has_curve_trim_interval(false) {} PRCContentWireEdge(std::string n) : PRCBaseTopology(n,makeCADID()), curve_3d(NULL), has_curve_trim_interval(false) {} ~PRCContentWireEdge() { delete curve_3d; } void serializeContentWireEdge(PRCbitStream &pbs); // void setCurve(PRCCurve*& curve) { curve_3d = curve; curve = NULL; } PRCCurve* curve_3d; bool has_curve_trim_interval; PRCInterval curve_trim_interval; }; class PRCWireEdge : public PRCContentWireEdge, public PRCTopoItem { public: void serializeWireEdge(PRCbitStream &pbs); void serializeTopoItem(PRCbitStream &pbs) { serializeWireEdge(pbs); } }; class PRCSingleWireBody : public PRCBody { public: PRCSingleWireBody() : PRCBody(PRC_TYPE_TOPO_SingleWireBody), wire_edge(NULL) {} PRCSingleWireBody(std::string n) : PRCBody(PRC_TYPE_TOPO_SingleWireBody, n), wire_edge(NULL) {} ~PRCSingleWireBody() { delete wire_edge; } void serializeSingleWireBody(PRCbitStream &pbs); void serializeBody(PRCbitStream &pbs) { serializeSingleWireBody(pbs); } void setWireEdge(PRCWireEdge*& wireEdge) { wire_edge = wireEdge; wireEdge = NULL; } PRCWireEdge* wire_edge; }; class PRCFace : public PRCBaseTopology, public PRCTopoItem, public PRCGraphics { public: PRCFace() : PRCBaseTopology(), base_surface(NULL), have_surface_trim_domain(false), have_tolerance(false), tolerance(0), number_of_loop(0), outer_loop_index(-1) {} PRCFace(std::string n) : PRCBaseTopology(n,makeCADID()), base_surface(NULL), have_surface_trim_domain(false), have_tolerance(false), tolerance(0), number_of_loop(0), outer_loop_index(-1) {} ~PRCFace() { delete base_surface; } void serializeFace(PRCbitStream &pbs); void serializeTopoItem(PRCbitStream &pbs) { serializeFace(pbs); } void setBaseSurface(PRCSurface*& surface) { base_surface = surface; surface = NULL; } PRCSurface *base_surface; const bool have_surface_trim_domain; PRCDomain surface_trim_domain; const bool have_tolerance; const double tolerance; const uint32_t number_of_loop; const int32_t outer_loop_index; // PRCLoopList loop; }; typedef std::deque PRCFaceList; class PRCShell : public PRCBaseTopology, public PRCTopoItem { public: PRCShell() : PRCBaseTopology(), shell_is_closed(false) {} PRCShell(std::string n) : PRCBaseTopology(n,makeCADID()), shell_is_closed(false) {} ~PRCShell() { for(PRCFaceList::iterator it=face.begin(); it!=face.end(); ++it) delete *it; } void serializeShell(PRCbitStream &pbs); void serializeTopoItem(PRCbitStream &pbs) { serializeShell(pbs); } void addFace(PRCFace*& pFace, uint8_t orientation=2); bool shell_is_closed; PRCFaceList face; std::vector orientation_surface_with_shell; }; typedef std::deque PRCShellList; class PRCConnex : public PRCBaseTopology, public PRCTopoItem { public: PRCConnex() : PRCBaseTopology() {} PRCConnex(std::string n) : PRCBaseTopology(n,makeCADID()) {} ~PRCConnex() { for(PRCShellList::iterator it=shell.begin(); it!=shell.end(); ++it) delete *it; } void serializeConnex(PRCbitStream &pbs); void serializeTopoItem(PRCbitStream &pbs) { serializeConnex(pbs); } void addShell(PRCShell*& pShell); PRCShellList shell; }; typedef std::deque PRCConnexList; class PRCBrepData : public PRCBody, public PRCBoundingBox { public: PRCBrepData() : PRCBody(PRC_TYPE_TOPO_BrepData) {} PRCBrepData(std::string n) : PRCBody(PRC_TYPE_TOPO_BrepData, n) {} ~PRCBrepData() { for(PRCConnexList::iterator it=connex.begin(); it!=connex.end(); ++it) delete *it; } void serializeBrepData(PRCbitStream &pbs); void serializeBody(PRCbitStream &pbs) { serializeBrepData(pbs); } void addConnex(PRCConnex*& pConnex); PRCConnexList connex; }; // For now - treat just the case of Bezier surfaces cubic 4x4 or linear 2x2 class PRCCompressedFace : public PRCBaseTopology, public PRCGraphics { public: PRCCompressedFace() : PRCBaseTopology(), orientation_surface_with_shell(true), degree(0) {} PRCCompressedFace(std::string n) : PRCBaseTopology(n,makeCADID()), orientation_surface_with_shell(true), degree(0) {} void serializeCompressedFace(PRCbitStream &pbs, double brep_data_compressed_tolerance); void serializeContentCompressedFace(PRCbitStream &pbs); void serializeCompressedAnaNurbs(PRCbitStream &pbs, double brep_data_compressed_tolerance); void serializeCompressedNurbs(PRCbitStream &pbs, double brep_data_compressed_tolerance); bool orientation_surface_with_shell; uint32_t degree; std::vector control_point; }; typedef std::deque PRCCompressedFaceList; // For now - treat just the case of one connex/one shell class PRCCompressedBrepData : public PRCBody { public: PRCCompressedBrepData() : PRCBody(PRC_TYPE_TOPO_BrepDataCompress), serial_tolerance(0), brep_data_compressed_tolerance(0) {} PRCCompressedBrepData(std::string n) : PRCBody(PRC_TYPE_TOPO_BrepDataCompress, n), serial_tolerance(0), brep_data_compressed_tolerance(0) {} ~PRCCompressedBrepData() { for(PRCCompressedFaceList::iterator it=face.begin(); it!=face.end(); ++it) delete *it; } void serializeCompressedBrepData(PRCbitStream &pbs); void serializeBody(PRCbitStream &pbs) { serializeCompressedBrepData(pbs); } void serializeCompressedShell(PRCbitStream &pbs); double serialTolerance() { return serial_tolerance; } double serial_tolerance; double brep_data_compressed_tolerance; PRCCompressedFaceList face; }; class PRCTopoContext : public ContentPRCBase { public: PRCTopoContext(std::string n="") : ContentPRCBase(PRC_TYPE_TOPO_Context,n), behaviour(0), granularity(1), tolerance(0), have_smallest_face_thickness(false), smallest_thickness(0), have_scale(false), scale(1) {} ~PRCTopoContext() { for(PRCBodyList::iterator it=body.begin(); it!=body.end(); ++it) delete *it; } void serializeTopoContext(PRCbitStream&); void serializeContextAndBodies(PRCbitStream&); void serializeGeometrySummary(PRCbitStream&); void serializeContextGraphics(PRCbitStream&); uint32_t addSingleWireBody(PRCSingleWireBody*& body); uint32_t addBrepData(PRCBrepData*& body); uint32_t addCompressedBrepData(PRCCompressedBrepData*& body); uint8_t behaviour; double granularity; double tolerance; bool have_smallest_face_thickness; double smallest_thickness; bool have_scale; double scale; PRCBodyList body; }; typedef std::deque PRCTopoContextList; class PRCUniqueId { public: PRCUniqueId() : id0(0), id1(0), id2(0), id3(0) {} void serializeCompressedUniqueId(PRCbitStream&) const; void serializeFileStructureUncompressedUniqueId(std::ostream& out) const; uint32_t id0; uint32_t id1; uint32_t id2; uint32_t id3; }; class PRCUnit { public: PRCUnit() : unit_from_CAD_file(false), unit(1) {} PRCUnit(double u, bool ufcf=true) : unit_from_CAD_file(ufcf), unit(u) {} void serializeUnit(PRCbitStream&); bool unit_from_CAD_file; double unit; }; class PRCProductOccurrence: public PRCGraphics, public ContentPRCBase { public: PRCProductOccurrence(std::string n="") : ContentPRCBase(PRC_TYPE_ASM_ProductOccurence,n), index_part(m1), index_prototype(m1), prototype_in_same_file_structure(true), index_external_data(m1), external_data_in_same_file_structure(true), product_behaviour(0), product_information_flags(0), product_load_status(KEPRCProductLoadStatus_Loaded), location(NULL) {} ~PRCProductOccurrence() { delete location; } void setLocation(PRCGeneralTransformation3d*& transform) { location = transform; transform = NULL; } void serializeProductOccurrence(PRCbitStream&); uint32_t index_part; uint32_t index_prototype; bool prototype_in_same_file_structure; PRCUniqueId prototype_file_structure; uint32_t index_external_data; bool external_data_in_same_file_structure; PRCUniqueId external_data_file_structure; std::vector index_son_occurrence; uint8_t product_behaviour; PRCUnit unit_information; uint8_t product_information_flags; EPRCProductLoadStatus product_load_status; PRCGeneralTransformation3d *location; }; typedef std::deque PRCProductOccurrenceList; class PRCPartDefinition: public PRCGraphics, public ContentPRCBase, public PRCBoundingBox { public: PRCPartDefinition(std::string n="") : ContentPRCBase(PRC_TYPE_ASM_PartDefinition,n) {} ~PRCPartDefinition() { for(PRCRepresentationItemList::iterator it=representation_item.begin(); it!=representation_item.end(); ++it) delete *it; } void serializePartDefinition(PRCbitStream&); uint32_t addBrepModel(PRCBrepModel*& pBrepModel); uint32_t addPolyBrepModel(PRCPolyBrepModel*& pPolyBrepModel); uint32_t addPointSet(PRCPointSet*& pPointSet); uint32_t addSet(PRCSet*& pSet); uint32_t addWire(PRCWire*& pWire); uint32_t addPolyWire(PRCPolyWire*& pPolyWire); uint32_t addRepresentationItem(PRCRepresentationItem*& pRepresentationItem); PRCRepresentationItemList representation_item; }; typedef std::deque PRCPartDefinitionList; #endif //__WRITE_PRC_H asymptote-2.37/prcfile.h000066400000000000000000000011751265434602500153020ustar00rootroot00000000000000#ifndef PRCFILE_H #define PRCFILE_H #include "memory.h" inline double X(const camp::triple &v) {return v.getx();} inline double Y(const camp::triple &v) {return v.gety();} inline double Z(const camp::triple &v) {return v.getz();} #include "prc/oPRCFile.h" namespace camp { inline prc::RGBAColour rgba(pen p) { p.convert(); p.torgb(); return prc::RGBAColour(p.red(),p.green(),p.blue(),p.opacity()); } static const double inches=72; static const double cm=inches/2.54; class prcfile : public prc::oPRCFile { public: prcfile(string name) : prc::oPRCFile(name.c_str(),10.0/cm) {} // Use bp. }; } //namespace camp #endif asymptote-2.37/predicates.cc000066400000000000000000003420131265434602500161360ustar00rootroot00000000000000/*****************************************************************************/ /* */ /* Routines for Arbitrary Precision Floating-point Arithmetic */ /* and Fast Robust Geometric Predicates */ /* (predicates.c) */ /* */ /* May 18, 1996 */ /* */ /* Placed in the public domain by */ /* Jonathan Richard Shewchuk */ /* School of Computer Science */ /* Carnegie Mellon University */ /* 5000 Forbes Avenue */ /* Pittsburgh, Pennsylvania 15213-3891 */ /* jrs@cs.cmu.edu */ /* */ /* This file contains C implementation of algorithms for exact addition */ /* and multiplication of floating-point numbers, and predicates for */ /* robustly performing the orientation and incircle tests used in */ /* computational geometry. The algorithms and underlying theory are */ /* described in Jonathan Richard Shewchuk. "Adaptive Precision Floating- */ /* Point Arithmetic and Fast Robust Geometric Predicates." Technical */ /* Report CMU-CS-96-140, School of Computer Science, Carnegie Mellon */ /* University, Pittsburgh, Pennsylvania, May 1996. (Submitted to */ /* Discrete & Computational Geometry.) */ /* */ /* This file, the paper listed above, and other information are available */ /* from the Web page http://www.cs.cmu.edu/~quake/robust.html . */ /* */ /*****************************************************************************/ /*****************************************************************************/ /* */ /* Using this code: */ /* */ /* First, read the short or long version of the paper (from the Web page */ /* above). */ /* */ /* Be sure to call exactinit() once, before calling any of the arithmetic */ /* functions or geometric predicates. Also be sure to turn on the */ /* optimizer when compiling this file. */ /* */ /* */ /* Several geometric predicates are defined. Their parameters are all */ /* points. Each point is an array of two or three floating-point */ /* numbers. The geometric predicates, described in the papers, are */ /* */ /* orient2d(pa, pb, pc) */ /* orient2dfast(pa, pb, pc) */ /* orient3d(pa, pb, pc, pd) */ /* orient3dfast(pa, pb, pc, pd) */ /* incircle(pa, pb, pc, pd) */ /* incirclefast(pa, pb, pc, pd) */ /* insphere(pa, pb, pc, pd, pe) */ /* inspherefast(pa, pb, pc, pd, pe) */ /* */ /* Those with suffix "fast" are approximate, non-robust versions. Those */ /* without the suffix are adaptive precision, robust versions. There */ /* are also versions with the suffices "exact" and "slow", which are */ /* non-adaptive, exact arithmetic versions, which I use only for timings */ /* in my arithmetic papers. */ /* */ /* */ /* An expansion is represented by an array of floating-point numbers, */ /* sorted from smallest to largest magnitude (possibly with interspersed */ /* zeros). The length of each expansion is stored as a separate integer, */ /* and each arithmetic function returns an integer which is the length */ /* of the expansion it created. */ /* */ /* Several arithmetic functions are defined. Their parameters are */ /* */ /* e, f Input expansions */ /* elen, flen Lengths of input expansions (must be >= 1) */ /* h Output expansion */ /* b Input scalar */ /* */ /* The arithmetic functions are */ /* */ /* grow_expansion(elen, e, b, h) */ /* grow_expansion_zeroelim(elen, e, b, h) */ /* expansion_sum(elen, e, flen, f, h) */ /* expansion_sum_zeroelim1(elen, e, flen, f, h) */ /* expansion_sum_zeroelim2(elen, e, flen, f, h) */ /* fast_expansion_sum(elen, e, flen, f, h) */ /* fast_expansion_sum_zeroelim(elen, e, flen, f, h) */ /* linear_expansion_sum(elen, e, flen, f, h) */ /* linear_expansion_sum_zeroelim(elen, e, flen, f, h) */ /* scale_expansion(elen, e, b, h) */ /* scale_expansion_zeroelim(elen, e, b, h) */ /* compress(elen, e, h) */ /* */ /* All of these are described in the long version of the paper; some are */ /* described in the short version. All return an integer that is the */ /* length of h. Those with suffix _zeroelim perform zero elimination, */ /* and are recommended over their counterparts. The procedure */ /* fast_expansion_sum_zeroelim() (or linear_expansion_sum_zeroelim() on */ /* processors that do not use the round-to-even tiebreaking rule) is */ /* recommended over expansion_sum_zeroelim(). Each procedure has a */ /* little note next to it (in the code below) that tells you whether or */ /* not the output expansion may be the same array as one of the input */ /* expansions. */ /* */ /* */ /* If you look around below, you'll also find macros for a bunch of */ /* simple unrolled arithmetic operations, and procedures for printing */ /* expansions (commented out because they don't work with all C */ /* compilers) and for generating random floating-point numbers whose */ /* significand bits are all random. Most of the macros have undocumented */ /* requirements that certain of their parameters should not be the same */ /* variable; for safety, better to make sure all the parameters are */ /* distinct variables. Feel free to send email to jrs@cs.cmu.edu if you */ /* have questions. */ /* */ /*****************************************************************************/ #include #include #include #include #include "predicates.h" /* FPU control. We MUST have only double precision (not extended precision) */ #include "rounding.h" /* On some machines, the exact arithmetic routines might be defeated by the */ /* use of internal extended precision floating-point registers. Sometimes */ /* this problem can be fixed by defining certain values to be volatile, */ /* thus forcing them to be stored to memory and rounded off. This isn't */ /* a great solution, though, as it slows the arithmetic down. */ /* */ /* To try this out, write "#define INEXACT volatile" below. Normally, */ /* however, INEXACT should be defined to be nothing. ("#define INEXACT".) */ #define INEXACT /* Nothing */ /* #define INEXACT volatile */ #define REAL double /* float or double */ #define REALPRINT doubleprint #define REALRAND doublerand #define NARROWRAND narrowdoublerand #define UNIFORMRAND uniformdoublerand /* Which of the following two methods of finding the absolute values is */ /* fastest is compiler-dependent. A few compilers can inline and optimize */ /* the fabs() call; but most will incur the overhead of a function call, */ /* which is disastrously slow. A faster way on IEEE machines might be to */ /* mask the appropriate bit, but that's difficult to do in C. */ /*#define Absolute(a) ((a) >= 0.0 ? (a) : -(a)) */ #define Absolute(a) fabs(a) /* Many of the operations are broken up into two pieces, a main part that */ /* performs an approximate operation, and a "tail" that computes the */ /* roundoff error of that operation. */ /* */ /* The operations Fast_Two_Sum(), Fast_Two_Diff(), Two_Sum(), Two_Diff(), */ /* Split(), and Two_Product() are all implemented as described in the */ /* reference. Each of these macros requires certain variables to be */ /* defined in the calling routine. The variables `bvirt', `c', `abig', */ /* `_i', `_j', `_k', `_l', `_m', and `_n' are declared `INEXACT' because */ /* they store the result of an operation that may incur roundoff error. */ /* The input parameter `x' (or the highest numbered `x_' parameter) must */ /* also be declared `INEXACT'. */ #define Fast_Two_Sum_Tail(a, b, x, y) \ bvirt = x - a; \ y = b - bvirt #define Fast_Two_Sum(a, b, x, y) \ x = (REAL) (a + b); \ Fast_Two_Sum_Tail(a, b, x, y) #define Fast_Two_Diff_Tail(a, b, x, y) \ bvirt = a - x; \ y = bvirt - b #define Fast_Two_Diff(a, b, x, y) \ x = (REAL) (a - b); \ Fast_Two_Diff_Tail(a, b, x, y) #define Two_Sum_Tail(a, b, x, y) \ bvirt = (REAL) (x - a); \ avirt = x - bvirt; \ bround = b - bvirt; \ around = a - avirt; \ y = around + bround #define Two_Sum(a, b, x, y) \ x = (REAL) (a + b); \ Two_Sum_Tail(a, b, x, y) #define Two_Diff_Tail(a, b, x, y) \ bvirt = (REAL) (a - x); \ avirt = x + bvirt; \ bround = bvirt - b; \ around = a - avirt; \ y = around + bround #define Two_Diff(a, b, x, y) \ x = (REAL) (a - b); \ Two_Diff_Tail(a, b, x, y) #define Split(a, ahi, alo) \ c = (REAL) (splitter * a); \ abig = (REAL) (c - a); \ ahi = c - abig; \ alo = a - ahi #define Two_Product_Tail(a, b, x, y) \ Split(a, ahi, alo); \ Split(b, bhi, blo); \ err1 = x - (ahi * bhi); \ err2 = err1 - (alo * bhi); \ err3 = err2 - (ahi * blo); \ y = (alo * blo) - err3 #define Two_Product(a, b, x, y) \ x = (REAL) (a * b); \ Two_Product_Tail(a, b, x, y) /* Two_Product_Presplit() is Two_Product() where one of the inputs has */ /* already been split. Avoids redundant splitting. */ #define Two_Product_Presplit(a, b, bhi, blo, x, y) \ x = (REAL) (a * b); \ Split(a, ahi, alo); \ err1 = x - (ahi * bhi); \ err2 = err1 - (alo * bhi); \ err3 = err2 - (ahi * blo); \ y = (alo * blo) - err3 /* Two_Product_2Presplit() is Two_Product() where both of the inputs have */ /* already been split. Avoids redundant splitting. */ #define Two_Product_2Presplit(a, ahi, alo, b, bhi, blo, x, y) \ x = (REAL) (a * b); \ err1 = x - (ahi * bhi); \ err2 = err1 - (alo * bhi); \ err3 = err2 - (ahi * blo); \ y = (alo * blo) - err3 /* Square() can be done more quickly than Two_Product(). */ #define Square_Tail(a, x, y) \ Split(a, ahi, alo); \ err1 = x - (ahi * ahi); \ err3 = err1 - ((ahi + ahi) * alo); \ y = (alo * alo) - err3 #define Square(a, x, y) \ x = (REAL) (a * a); \ Square_Tail(a, x, y) /* Macros for summing expansions of various fixed lengths. These are all */ /* unrolled versions of Expansion_Sum(). */ #define Two_One_Sum(a1, a0, b, x2, x1, x0) \ Two_Sum(a0, b , _i, x0); \ Two_Sum(a1, _i, x2, x1) #define Two_One_Diff(a1, a0, b, x2, x1, x0) \ Two_Diff(a0, b , _i, x0); \ Two_Sum( a1, _i, x2, x1) #define Two_Two_Sum(a1, a0, b1, b0, x3, x2, x1, x0) \ Two_One_Sum(a1, a0, b0, _j, _0, x0); \ Two_One_Sum(_j, _0, b1, x3, x2, x1) #define Two_Two_Diff(a1, a0, b1, b0, x3, x2, x1, x0) \ Two_One_Diff(a1, a0, b0, _j, _0, x0); \ Two_One_Diff(_j, _0, b1, x3, x2, x1) #define Four_One_Sum(a3, a2, a1, a0, b, x4, x3, x2, x1, x0) \ Two_One_Sum(a1, a0, b , _j, x1, x0); \ Two_One_Sum(a3, a2, _j, x4, x3, x2) #define Four_Two_Sum(a3, a2, a1, a0, b1, b0, x5, x4, x3, x2, x1, x0) \ Four_One_Sum(a3, a2, a1, a0, b0, _k, _2, _1, _0, x0); \ Four_One_Sum(_k, _2, _1, _0, b1, x5, x4, x3, x2, x1) #define Four_Four_Sum(a3, a2, a1, a0, b4, b3, b1, b0, x7, x6, x5, x4, x3, x2, \ x1, x0) \ Four_Two_Sum(a3, a2, a1, a0, b1, b0, _l, _2, _1, _0, x1, x0); \ Four_Two_Sum(_l, _2, _1, _0, b4, b3, x7, x6, x5, x4, x3, x2) #define Eight_One_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b, x8, x7, x6, x5, x4, \ x3, x2, x1, x0) \ Four_One_Sum(a3, a2, a1, a0, b , _j, x3, x2, x1, x0); \ Four_One_Sum(a7, a6, a5, a4, _j, x8, x7, x6, x5, x4) #define Eight_Two_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b1, b0, x9, x8, x7, \ x6, x5, x4, x3, x2, x1, x0) \ Eight_One_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b0, _k, _6, _5, _4, _3, _2, \ _1, _0, x0); \ Eight_One_Sum(_k, _6, _5, _4, _3, _2, _1, _0, b1, x9, x8, x7, x6, x5, x4, \ x3, x2, x1) #define Eight_Four_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b4, b3, b1, b0, x11, \ x10, x9, x8, x7, x6, x5, x4, x3, x2, x1, x0) \ Eight_Two_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b1, b0, _l, _6, _5, _4, _3, \ _2, _1, _0, x1, x0); \ Eight_Two_Sum(_l, _6, _5, _4, _3, _2, _1, _0, b4, b3, x11, x10, x9, x8, \ x7, x6, x5, x4, x3, x2) /* Macros for multiplying expansions of various fixed lengths. */ #define Two_One_Product(a1, a0, b, x3, x2, x1, x0) \ Split(b, bhi, blo); \ Two_Product_Presplit(a0, b, bhi, blo, _i, x0); \ Two_Product_Presplit(a1, b, bhi, blo, _j, _0); \ Two_Sum(_i, _0, _k, x1); \ Fast_Two_Sum(_j, _k, x3, x2) #define Four_One_Product(a3, a2, a1, a0, b, x7, x6, x5, x4, x3, x2, x1, x0) \ Split(b, bhi, blo); \ Two_Product_Presplit(a0, b, bhi, blo, _i, x0); \ Two_Product_Presplit(a1, b, bhi, blo, _j, _0); \ Two_Sum(_i, _0, _k, x1); \ Fast_Two_Sum(_j, _k, _i, x2); \ Two_Product_Presplit(a2, b, bhi, blo, _j, _0); \ Two_Sum(_i, _0, _k, x3); \ Fast_Two_Sum(_j, _k, _i, x4); \ Two_Product_Presplit(a3, b, bhi, blo, _j, _0); \ Two_Sum(_i, _0, _k, x5); \ Fast_Two_Sum(_j, _k, x7, x6) #define Two_Two_Product(a1, a0, b1, b0, x7, x6, x5, x4, x3, x2, x1, x0) \ Split(a0, a0hi, a0lo); \ Split(b0, bhi, blo); \ Two_Product_2Presplit(a0, a0hi, a0lo, b0, bhi, blo, _i, x0); \ Split(a1, a1hi, a1lo); \ Two_Product_2Presplit(a1, a1hi, a1lo, b0, bhi, blo, _j, _0); \ Two_Sum(_i, _0, _k, _1); \ Fast_Two_Sum(_j, _k, _l, _2); \ Split(b1, bhi, blo); \ Two_Product_2Presplit(a0, a0hi, a0lo, b1, bhi, blo, _i, _0); \ Two_Sum(_1, _0, _k, x1); \ Two_Sum(_2, _k, _j, _1); \ Two_Sum(_l, _j, _m, _2); \ Two_Product_2Presplit(a1, a1hi, a1lo, b1, bhi, blo, _j, _0); \ Two_Sum(_i, _0, _n, _0); \ Two_Sum(_1, _0, _i, x2); \ Two_Sum(_2, _i, _k, _1); \ Two_Sum(_m, _k, _l, _2); \ Two_Sum(_j, _n, _k, _0); \ Two_Sum(_1, _0, _j, x3); \ Two_Sum(_2, _j, _i, _1); \ Two_Sum(_l, _i, _m, _2); \ Two_Sum(_1, _k, _i, x4); \ Two_Sum(_2, _i, _k, x5); \ Two_Sum(_m, _k, x7, x6) /* An expansion of length two can be squared more quickly than finding the */ /* product of two different expansions of length two, and the result is */ /* guaranteed to have no more than six (rather than eight) components. */ #define Two_Square(a1, a0, x5, x4, x3, x2, x1, x0) \ Square(a0, _j, x0); \ _0 = a0 + a0; \ Two_Product(a1, _0, _k, _1); \ Two_One_Sum(_k, _1, _j, _l, _2, x1); \ Square(a1, _j, _1); \ Two_Two_Sum(_j, _1, _l, _2, x5, x4, x3, x2) /* 2^(-p), where p=DBL_MANT_DIG. Used to estimate roundoff errors. */ static const REAL epsilon=0.5*DBL_EPSILON; /* 2^ceiling(p/2) + 1. Used to split floats in half. */ static const REAL splitter=sqrt((DBL_MANT_DIG % 2 ? 2.0 : 1.0)/epsilon)+1.0; /* A set of coefficients used to calculate maximum roundoff errors. */ const REAL resulterrbound=(3.0 + 8.0 * epsilon) * epsilon; const REAL ccwerrboundA=(3.0 + 16.0 * epsilon) * epsilon; const REAL ccwerrboundB=(2.0 + 12.0 * epsilon) * epsilon; const REAL ccwerrboundC=(9.0 + 64.0 * epsilon) * epsilon * epsilon; const REAL o3derrboundA=(7.0 + 56.0 * epsilon) * epsilon; const REAL o3derrboundB=(3.0 + 28.0 * epsilon) * epsilon; const REAL o3derrboundC=(26.0 + 288.0 * epsilon) * epsilon * epsilon; const REAL iccerrboundA=(10.0 + 96.0 * epsilon) * epsilon; const REAL iccerrboundB=(4.0 + 48.0 * epsilon) * epsilon; const REAL iccerrboundC=(44.0 + 576.0 * epsilon) * epsilon * epsilon; const REAL isperrboundA=(16.0 + 224.0 * epsilon) * epsilon; const REAL isperrboundB=(5.0 + 72.0 * epsilon) * epsilon; const REAL isperrboundC=(71.0 + 1408.0 * epsilon) * epsilon * epsilon; /*****************************************************************************/ /* */ /* doubleprint() Print the bit representation of a double. */ /* */ /* Useful for debugging exact arithmetic routines. */ /* */ /*****************************************************************************/ /* void doubleprint(number) double number; { unsigned long long no; unsigned long long sign, expo; int exponent; int i, bottomi; no = *(unsigned long long *) &number; sign = no & 0x8000000000000000ll; expo = (no >> 52) & 0x7ffll; exponent = (int) expo; exponent = exponent - 1023; if (sign) { printf("-"); } else { printf(" "); } if (exponent == -1023) { printf( "0.0000000000000000000000000000000000000000000000000000_ ( )"); } else { printf("1."); bottomi = -1; for (i = 0; i < 52; i++) { if (no & 0x0008000000000000ll) { printf("1"); bottomi = i; } else { printf("0"); } no <<= 1; } printf("_%d (%d)", exponent, exponent - 1 - bottomi); } } */ /*****************************************************************************/ /* */ /* floatprint() Print the bit representation of a float. */ /* */ /* Useful for debugging exact arithmetic routines. */ /* */ /*****************************************************************************/ /* void floatprint(number) float number; { unsigned no; unsigned sign, expo; int exponent; int i, bottomi; no = *(unsigned *) &number; sign = no & 0x80000000; expo = (no >> 23) & 0xff; exponent = (int) expo; exponent = exponent - 127; if (sign) { printf("-"); } else { printf(" "); } if (exponent == -127) { printf("0.00000000000000000000000_ ( )"); } else { printf("1."); bottomi = -1; for (i = 0; i < 23; i++) { if (no & 0x00400000) { printf("1"); bottomi = i; } else { printf("0"); } no <<= 1; } printf("_%3d (%3d)", exponent, exponent - 1 - bottomi); } } */ /*****************************************************************************/ /* */ /* expansion_print() Print the bit representation of an expansion. */ /* */ /* Useful for debugging exact arithmetic routines. */ /* */ /*****************************************************************************/ /* void expansion_print(elen, e) int elen; REAL *e; { int i; for (i = elen - 1; i >= 0; i--) { REALPRINT(e[i]); if (i > 0) { printf(" +\n"); } else { printf("\n"); } } } */ /*****************************************************************************/ /* */ /* doublerand() Generate a double with random 53-bit significand and a */ /* random exponent in [0, 511]. */ /* */ /*****************************************************************************/ /* static double doublerand() { double result; double expo; long a, b, c; long i; a = random(); b = random(); c = random(); result = (double) (a - 1073741824) * 8388608.0 + (double) (b >> 8); for (i = 512, expo = 2; i <= 131072; i *= 2, expo = expo * expo) { if (c & i) { result *= expo; } } return result; } */ /*****************************************************************************/ /* */ /* narrowdoublerand() Generate a double with random 53-bit significand */ /* and a random exponent in [0, 7]. */ /* */ /*****************************************************************************/ /* static double narrowdoublerand() { double result; double expo; long a, b, c; long i; a = random(); b = random(); c = random(); result = (double) (a - 1073741824) * 8388608.0 + (double) (b >> 8); for (i = 512, expo = 2; i <= 2048; i *= 2, expo = expo * expo) { if (c & i) { result *= expo; } } return result; } */ /*****************************************************************************/ /* */ /* uniformdoublerand() Generate a double with random 53-bit significand. */ /* */ /*****************************************************************************/ /* static double uniformdoublerand() { double result; long a, b; a = random(); b = random(); result = (double) (a - 1073741824) * 8388608.0 + (double) (b >> 8); return result; } */ /*****************************************************************************/ /* */ /* floatrand() Generate a float with random 24-bit significand and a */ /* random exponent in [0, 63]. */ /* */ /*****************************************************************************/ /* static float floatrand() { float result; float expo; long a, c; long i; a = random(); c = random(); result = (float) ((a - 1073741824) >> 6); for (i = 512, expo = 2; i <= 16384; i *= 2, expo = expo * expo) { if (c & i) { result *= expo; } } return result; } */ /*****************************************************************************/ /* */ /* narrowfloatrand() Generate a float with random 24-bit significand and */ /* a random exponent in [0, 7]. */ /* */ /*****************************************************************************/ /* static float narrowfloatrand() { float result; float expo; long a, c; long i; a = random(); c = random(); result = (float) ((a - 1073741824) >> 6); for (i = 512, expo = 2; i <= 2048; i *= 2, expo = expo * expo) { if (c & i) { result *= expo; } } return result; } */ /*****************************************************************************/ /* */ /* uniformfloatrand() Generate a float with random 24-bit significand. */ /* */ /*****************************************************************************/ /* static float uniformfloatrand() { float result; long a; a = random(); result = (float) ((a - 1073741824) >> 6); return result; } */ /*****************************************************************************/ /* */ /* fast_expansion_sum_zeroelim() Sum two expansions, eliminating zero */ /* components from the output expansion. */ /* */ /* Sets h = e + f. See the long version of my paper for details. */ /* */ /* If round-to-even is used (as with IEEE 754), maintains the strongly */ /* nonoverlapping property. (That is, if e is strongly nonoverlapping, h */ /* will be also.) Does NOT maintain the nonoverlapping or nonadjacent */ /* properties. */ /* */ /*****************************************************************************/ static int fast_expansion_sum_zeroelim(int elen, REAL *e, int flen, REAL *f, REAL *h) /* h cannot be e or f. */ { REAL Q; INEXACT REAL Qnew; INEXACT REAL hh; INEXACT REAL bvirt; REAL avirt, bround, around; int eindex, findex, hindex; REAL enow, fnow; enow = e[0]; fnow = f[0]; eindex = findex = 0; if ((fnow > enow) == (fnow > -enow)) { Q = enow; enow = e[++eindex]; } else { Q = fnow; fnow = f[++findex]; } hindex = 0; if ((eindex < elen) && (findex < flen)) { if ((fnow > enow) == (fnow > -enow)) { Fast_Two_Sum(enow, Q, Qnew, hh); enow = e[++eindex]; } else { Fast_Two_Sum(fnow, Q, Qnew, hh); fnow = f[++findex]; } Q = Qnew; if (hh != 0.0) { h[hindex++] = hh; } while ((eindex < elen) && (findex < flen)) { if ((fnow > enow) == (fnow > -enow)) { Two_Sum(Q, enow, Qnew, hh); enow = e[++eindex]; } else { Two_Sum(Q, fnow, Qnew, hh); fnow = f[++findex]; } Q = Qnew; if (hh != 0.0) { h[hindex++] = hh; } } } while (eindex < elen) { Two_Sum(Q, enow, Qnew, hh); enow = e[++eindex]; Q = Qnew; if (hh != 0.0) { h[hindex++] = hh; } } while (findex < flen) { Two_Sum(Q, fnow, Qnew, hh); fnow = f[++findex]; Q = Qnew; if (hh != 0.0) { h[hindex++] = hh; } } if ((Q != 0.0) || (hindex == 0)) { h[hindex++] = Q; } return hindex; } /*****************************************************************************/ /* */ /* scale_expansion_zeroelim() Multiply an expansion by a scalar, */ /* eliminating zero components from the */ /* output expansion. */ /* */ /* Sets h = be. See either version of my paper for details. */ /* */ /* Maintains the nonoverlapping property. If round-to-even is used (as */ /* with IEEE 754), maintains the strongly nonoverlapping and nonadjacent */ /* properties as well. (That is, if e has one of these properties, so */ /* will h.) */ /* */ /*****************************************************************************/ static int scale_expansion_zeroelim(int elen, REAL *e, REAL b, REAL *h) /* e and h cannot be the same. */ { INEXACT REAL Q, sum; REAL hh; INEXACT REAL product1; REAL product0; int eindex, hindex; REAL enow; INEXACT REAL bvirt; REAL avirt, bround, around; INEXACT REAL c; INEXACT REAL abig; REAL ahi, alo, bhi, blo; REAL err1, err2, err3; Split(b, bhi, blo); Two_Product_Presplit(e[0], b, bhi, blo, Q, hh); hindex = 0; if (hh != 0) { h[hindex++] = hh; } for (eindex = 1; eindex < elen; eindex++) { enow = e[eindex]; Two_Product_Presplit(enow, b, bhi, blo, product1, product0); Two_Sum(Q, product0, sum, hh); if (hh != 0) { h[hindex++] = hh; } Fast_Two_Sum(product1, sum, Q, hh); if (hh != 0) { h[hindex++] = hh; } } if ((Q != 0.0) || (hindex == 0)) { h[hindex++] = Q; } return hindex; } /*****************************************************************************/ /* */ /* estimate() Produce a one-word estimate of an expansion's value. */ /* */ /* See either version of my paper for details. */ /* */ /*****************************************************************************/ static REAL estimate(int elen, REAL *e) { REAL Q; int eindex; Q = e[0]; for (eindex = 1; eindex < elen; eindex++) { Q += e[eindex]; } return Q; } /*****************************************************************************/ /* */ /* orient2dfast() Approximate 2D orientation test. Nonrobust. */ /* orient2dexact() Exact 2D orientation test. Robust. */ /* orient2dslow() Another exact 2D orientation test. Robust. */ /* orient2d() Adaptive exact 2D orientation test. Robust. */ /* */ /* Return a positive value if the points pa, pb, and pc occur */ /* in counterclockwise order; a negative value if they occur */ /* in clockwise order; and zero if they are collinear. The */ /* result is also a rough approximation of twice the signed */ /* area of the triangle defined by the three points. */ /* */ /* Only the first and last routine should be used; the middle two are for */ /* timings. */ /* */ /* The last three use exact arithmetic to ensure a correct answer. The */ /* result returned is the determinant of a matrix. In orient2d() only, */ /* this determinant is computed adaptively, in the sense that exact */ /* arithmetic is used only to the degree it is needed to ensure that the */ /* returned value has the correct sign. Hence, orient2d() is usually quite */ /* fast, but will run more slowly when the input points are collinear or */ /* nearly so. */ /* */ /*****************************************************************************/ REAL orient2dadapt(REAL *pa, REAL *pb, REAL *pc, REAL detsum) { INEXACT REAL acx, acy, bcx, bcy; REAL acxtail, acytail, bcxtail, bcytail; INEXACT REAL detleft, detright; REAL detlefttail, detrighttail; REAL det, errbound; REAL B[4], C1[8], C2[12], D[16]; INEXACT REAL B3; int C1length, C2length, Dlength; REAL u[4]; INEXACT REAL u3; INEXACT REAL s1, t1; REAL s0, t0; INEXACT REAL bvirt; REAL avirt, bround, around; INEXACT REAL c; INEXACT REAL abig; REAL ahi, alo, bhi, blo; REAL err1, err2, err3; INEXACT REAL _i, _j; REAL _0; acx = (REAL) (pa[0] - pc[0]); bcx = (REAL) (pb[0] - pc[0]); acy = (REAL) (pa[1] - pc[1]); bcy = (REAL) (pb[1] - pc[1]); Two_Product(acx, bcy, detleft, detlefttail); Two_Product(acy, bcx, detright, detrighttail); Two_Two_Diff(detleft, detlefttail, detright, detrighttail, B3, B[2], B[1], B[0]); B[3] = B3; det = estimate(4, B); errbound = ccwerrboundB * detsum; if ((det >= errbound) || (-det >= errbound)) { return det; } Two_Diff_Tail(pa[0], pc[0], acx, acxtail); Two_Diff_Tail(pb[0], pc[0], bcx, bcxtail); Two_Diff_Tail(pa[1], pc[1], acy, acytail); Two_Diff_Tail(pb[1], pc[1], bcy, bcytail); if ((acxtail == 0.0) && (acytail == 0.0) && (bcxtail == 0.0) && (bcytail == 0.0)) { return det; } errbound = ccwerrboundC * detsum + resulterrbound * Absolute(det); det += (acx * bcytail + bcy * acxtail) - (acy * bcxtail + bcx * acytail); if ((det >= errbound) || (-det >= errbound)) { return det; } Two_Product(acxtail, bcy, s1, s0); Two_Product(acytail, bcx, t1, t0); Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); u[3] = u3; C1length = fast_expansion_sum_zeroelim(4, B, 4, u, C1); Two_Product(acx, bcytail, s1, s0); Two_Product(acy, bcxtail, t1, t0); Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); u[3] = u3; C2length = fast_expansion_sum_zeroelim(C1length, C1, 4, u, C2); Two_Product(acxtail, bcytail, s1, s0); Two_Product(acytail, bcxtail, t1, t0); Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); u[3] = u3; Dlength = fast_expansion_sum_zeroelim(C2length, C2, 4, u, D); return(D[Dlength - 1]); } REAL orient2d(REAL *pa, REAL *pb, REAL *pc) { REAL detleft, detright, det; REAL detsum, errbound; REAL orient; FPU_ROUND_DOUBLE; detleft = (pa[0] - pc[0]) * (pb[1] - pc[1]); detright = (pa[1] - pc[1]) * (pb[0] - pc[0]); det = detleft - detright; if (detleft > 0.0) { if (detright <= 0.0) { FPU_RESTORE; return det; } else { detsum = detleft + detright; } } else if (detleft < 0.0) { if (detright >= 0.0) { FPU_RESTORE; return det; } else { detsum = -detleft - detright; } } else { FPU_RESTORE; return det; } errbound = ccwerrboundA * detsum; if ((det >= errbound) || (-det >= errbound)) { FPU_RESTORE; return det; } orient = orient2dadapt(pa, pb, pc, detsum); FPU_RESTORE; return orient; } REAL orient2d(REAL ax, REAL ay, REAL bx, REAL by, REAL cx, REAL cy) { REAL detleft, detright, det; REAL detsum, errbound; REAL orient; FPU_ROUND_DOUBLE; detleft = (ax - cx) * (by - cy); detright = (ay - cy) * (bx - cx); det = detleft - detright; if (detleft > 0.0) { if (detright <= 0.0) { FPU_RESTORE; return det; } else { detsum = detleft + detright; } } else if (detleft < 0.0) { if (detright >= 0.0) { FPU_RESTORE; return det; } else { detsum = -detleft - detright; } } else { FPU_RESTORE; return det; } errbound = ccwerrboundA * detsum; if ((det >= errbound) || (-det >= errbound)) { FPU_RESTORE; return det; } REAL pa[]={ax,ay}; REAL pb[]={bx,by}; REAL pc[]={cx,cy}; orient = orient2dadapt(pa, pb, pc, detsum); FPU_RESTORE; return orient; } /*****************************************************************************/ /* */ /* orient3dfast() Approximate 3D orientation test. Nonrobust. */ /* orient3dexact() Exact 3D orientation test. Robust. */ /* orient3dslow() Another exact 3D orientation test. Robust. */ /* orient3d() Adaptive exact 3D orientation test. Robust. */ /* */ /* Return a positive value if the point pd lies below the */ /* plane passing through pa, pb, and pc; "below" is defined so */ /* that pa, pb, and pc appear in counterclockwise order when */ /* viewed from above the plane. Returns a negative value if */ /* pd lies above the plane. Returns zero if the points are */ /* coplanar. The result is also a rough approximation of six */ /* times the signed volume of the tetrahedron defined by the */ /* four points. */ /* */ /* Only the first and last routine should be used; the middle two are for */ /* timings. */ /* */ /* The last three use exact arithmetic to ensure a correct answer. The */ /* result returned is the determinant of a matrix. In orient3d() only, */ /* this determinant is computed adaptively, in the sense that exact */ /* arithmetic is used only to the degree it is needed to ensure that the */ /* returned value has the correct sign. Hence, orient3d() is usually quite */ /* fast, but will run more slowly when the input points are coplanar or */ /* nearly so. */ /* */ /*****************************************************************************/ static REAL orient3dadapt(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL permanent) { INEXACT REAL adx, bdx, cdx, ady, bdy, cdy, adz, bdz, cdz; REAL det, errbound; INEXACT REAL bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1; REAL bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0; REAL bc[4], ca[4], ab[4]; INEXACT REAL bc3, ca3, ab3; REAL adet[8], bdet[8], cdet[8]; int alen, blen, clen; REAL abdet[16]; int ablen; REAL *finnow, *finother, *finswap; REAL fin1[192], fin2[192]; int finlength; REAL adxtail, bdxtail, cdxtail; REAL adytail, bdytail, cdytail; REAL adztail, bdztail, cdztail; INEXACT REAL at_blarge, at_clarge; INEXACT REAL bt_clarge, bt_alarge; INEXACT REAL ct_alarge, ct_blarge; REAL at_b[4], at_c[4], bt_c[4], bt_a[4], ct_a[4], ct_b[4]; int at_blen, at_clen, bt_clen, bt_alen, ct_alen, ct_blen; INEXACT REAL bdxt_cdy1, cdxt_bdy1, cdxt_ady1; INEXACT REAL adxt_cdy1, adxt_bdy1, bdxt_ady1; REAL bdxt_cdy0, cdxt_bdy0, cdxt_ady0; REAL adxt_cdy0, adxt_bdy0, bdxt_ady0; INEXACT REAL bdyt_cdx1, cdyt_bdx1, cdyt_adx1; INEXACT REAL adyt_cdx1, adyt_bdx1, bdyt_adx1; REAL bdyt_cdx0, cdyt_bdx0, cdyt_adx0; REAL adyt_cdx0, adyt_bdx0, bdyt_adx0; REAL bct[8], cat[8], abt[8]; int bctlen, catlen, abtlen; INEXACT REAL bdxt_cdyt1, cdxt_bdyt1, cdxt_adyt1; INEXACT REAL adxt_cdyt1, adxt_bdyt1, bdxt_adyt1; REAL bdxt_cdyt0, cdxt_bdyt0, cdxt_adyt0; REAL adxt_cdyt0, adxt_bdyt0, bdxt_adyt0; REAL u[4], v[12], w[16]; INEXACT REAL u3; int vlength, wlength; REAL negate; INEXACT REAL bvirt; REAL avirt, bround, around; INEXACT REAL c; INEXACT REAL abig; REAL ahi, alo, bhi, blo; REAL err1, err2, err3; INEXACT REAL _i, _j, _k; REAL _0; adx = (REAL) (pa[0] - pd[0]); bdx = (REAL) (pb[0] - pd[0]); cdx = (REAL) (pc[0] - pd[0]); ady = (REAL) (pa[1] - pd[1]); bdy = (REAL) (pb[1] - pd[1]); cdy = (REAL) (pc[1] - pd[1]); adz = (REAL) (pa[2] - pd[2]); bdz = (REAL) (pb[2] - pd[2]); cdz = (REAL) (pc[2] - pd[2]); Two_Product(bdx, cdy, bdxcdy1, bdxcdy0); Two_Product(cdx, bdy, cdxbdy1, cdxbdy0); Two_Two_Diff(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0, bc3, bc[2], bc[1], bc[0]); bc[3] = bc3; alen = scale_expansion_zeroelim(4, bc, adz, adet); Two_Product(cdx, ady, cdxady1, cdxady0); Two_Product(adx, cdy, adxcdy1, adxcdy0); Two_Two_Diff(cdxady1, cdxady0, adxcdy1, adxcdy0, ca3, ca[2], ca[1], ca[0]); ca[3] = ca3; blen = scale_expansion_zeroelim(4, ca, bdz, bdet); Two_Product(adx, bdy, adxbdy1, adxbdy0); Two_Product(bdx, ady, bdxady1, bdxady0); Two_Two_Diff(adxbdy1, adxbdy0, bdxady1, bdxady0, ab3, ab[2], ab[1], ab[0]); ab[3] = ab3; clen = scale_expansion_zeroelim(4, ab, cdz, cdet); ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); finlength = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, fin1); det = estimate(finlength, fin1); errbound = o3derrboundB * permanent; if ((det >= errbound) || (-det >= errbound)) { return det; } Two_Diff_Tail(pa[0], pd[0], adx, adxtail); Two_Diff_Tail(pb[0], pd[0], bdx, bdxtail); Two_Diff_Tail(pc[0], pd[0], cdx, cdxtail); Two_Diff_Tail(pa[1], pd[1], ady, adytail); Two_Diff_Tail(pb[1], pd[1], bdy, bdytail); Two_Diff_Tail(pc[1], pd[1], cdy, cdytail); Two_Diff_Tail(pa[2], pd[2], adz, adztail); Two_Diff_Tail(pb[2], pd[2], bdz, bdztail); Two_Diff_Tail(pc[2], pd[2], cdz, cdztail); if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0) && (adytail == 0.0) && (bdytail == 0.0) && (cdytail == 0.0) && (adztail == 0.0) && (bdztail == 0.0) && (cdztail == 0.0)) { return det; } errbound = o3derrboundC * permanent + resulterrbound * Absolute(det); det += (adz * ((bdx * cdytail + cdy * bdxtail) - (bdy * cdxtail + cdx * bdytail)) + adztail * (bdx * cdy - bdy * cdx)) + (bdz * ((cdx * adytail + ady * cdxtail) - (cdy * adxtail + adx * cdytail)) + bdztail * (cdx * ady - cdy * adx)) + (cdz * ((adx * bdytail + bdy * adxtail) - (ady * bdxtail + bdx * adytail)) + cdztail * (adx * bdy - ady * bdx)); if ((det >= errbound) || (-det >= errbound)) { return det; } finnow = fin1; finother = fin2; if (adxtail == 0.0) { if (adytail == 0.0) { at_b[0] = 0.0; at_blen = 1; at_c[0] = 0.0; at_clen = 1; } else { negate = -adytail; Two_Product(negate, bdx, at_blarge, at_b[0]); at_b[1] = at_blarge; at_blen = 2; Two_Product(adytail, cdx, at_clarge, at_c[0]); at_c[1] = at_clarge; at_clen = 2; } } else { if (adytail == 0.0) { Two_Product(adxtail, bdy, at_blarge, at_b[0]); at_b[1] = at_blarge; at_blen = 2; negate = -adxtail; Two_Product(negate, cdy, at_clarge, at_c[0]); at_c[1] = at_clarge; at_clen = 2; } else { Two_Product(adxtail, bdy, adxt_bdy1, adxt_bdy0); Two_Product(adytail, bdx, adyt_bdx1, adyt_bdx0); Two_Two_Diff(adxt_bdy1, adxt_bdy0, adyt_bdx1, adyt_bdx0, at_blarge, at_b[2], at_b[1], at_b[0]); at_b[3] = at_blarge; at_blen = 4; Two_Product(adytail, cdx, adyt_cdx1, adyt_cdx0); Two_Product(adxtail, cdy, adxt_cdy1, adxt_cdy0); Two_Two_Diff(adyt_cdx1, adyt_cdx0, adxt_cdy1, adxt_cdy0, at_clarge, at_c[2], at_c[1], at_c[0]); at_c[3] = at_clarge; at_clen = 4; } } if (bdxtail == 0.0) { if (bdytail == 0.0) { bt_c[0] = 0.0; bt_clen = 1; bt_a[0] = 0.0; bt_alen = 1; } else { negate = -bdytail; Two_Product(negate, cdx, bt_clarge, bt_c[0]); bt_c[1] = bt_clarge; bt_clen = 2; Two_Product(bdytail, adx, bt_alarge, bt_a[0]); bt_a[1] = bt_alarge; bt_alen = 2; } } else { if (bdytail == 0.0) { Two_Product(bdxtail, cdy, bt_clarge, bt_c[0]); bt_c[1] = bt_clarge; bt_clen = 2; negate = -bdxtail; Two_Product(negate, ady, bt_alarge, bt_a[0]); bt_a[1] = bt_alarge; bt_alen = 2; } else { Two_Product(bdxtail, cdy, bdxt_cdy1, bdxt_cdy0); Two_Product(bdytail, cdx, bdyt_cdx1, bdyt_cdx0); Two_Two_Diff(bdxt_cdy1, bdxt_cdy0, bdyt_cdx1, bdyt_cdx0, bt_clarge, bt_c[2], bt_c[1], bt_c[0]); bt_c[3] = bt_clarge; bt_clen = 4; Two_Product(bdytail, adx, bdyt_adx1, bdyt_adx0); Two_Product(bdxtail, ady, bdxt_ady1, bdxt_ady0); Two_Two_Diff(bdyt_adx1, bdyt_adx0, bdxt_ady1, bdxt_ady0, bt_alarge, bt_a[2], bt_a[1], bt_a[0]); bt_a[3] = bt_alarge; bt_alen = 4; } } if (cdxtail == 0.0) { if (cdytail == 0.0) { ct_a[0] = 0.0; ct_alen = 1; ct_b[0] = 0.0; ct_blen = 1; } else { negate = -cdytail; Two_Product(negate, adx, ct_alarge, ct_a[0]); ct_a[1] = ct_alarge; ct_alen = 2; Two_Product(cdytail, bdx, ct_blarge, ct_b[0]); ct_b[1] = ct_blarge; ct_blen = 2; } } else { if (cdytail == 0.0) { Two_Product(cdxtail, ady, ct_alarge, ct_a[0]); ct_a[1] = ct_alarge; ct_alen = 2; negate = -cdxtail; Two_Product(negate, bdy, ct_blarge, ct_b[0]); ct_b[1] = ct_blarge; ct_blen = 2; } else { Two_Product(cdxtail, ady, cdxt_ady1, cdxt_ady0); Two_Product(cdytail, adx, cdyt_adx1, cdyt_adx0); Two_Two_Diff(cdxt_ady1, cdxt_ady0, cdyt_adx1, cdyt_adx0, ct_alarge, ct_a[2], ct_a[1], ct_a[0]); ct_a[3] = ct_alarge; ct_alen = 4; Two_Product(cdytail, bdx, cdyt_bdx1, cdyt_bdx0); Two_Product(cdxtail, bdy, cdxt_bdy1, cdxt_bdy0); Two_Two_Diff(cdyt_bdx1, cdyt_bdx0, cdxt_bdy1, cdxt_bdy0, ct_blarge, ct_b[2], ct_b[1], ct_b[0]); ct_b[3] = ct_blarge; ct_blen = 4; } } bctlen = fast_expansion_sum_zeroelim(bt_clen, bt_c, ct_blen, ct_b, bct); wlength = scale_expansion_zeroelim(bctlen, bct, adz, w); finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, finother); finswap = finnow; finnow = finother; finother = finswap; catlen = fast_expansion_sum_zeroelim(ct_alen, ct_a, at_clen, at_c, cat); wlength = scale_expansion_zeroelim(catlen, cat, bdz, w); finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, finother); finswap = finnow; finnow = finother; finother = finswap; abtlen = fast_expansion_sum_zeroelim(at_blen, at_b, bt_alen, bt_a, abt); wlength = scale_expansion_zeroelim(abtlen, abt, cdz, w); finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, finother); finswap = finnow; finnow = finother; finother = finswap; if (adztail != 0.0) { vlength = scale_expansion_zeroelim(4, bc, adztail, v); finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v, finother); finswap = finnow; finnow = finother; finother = finswap; } if (bdztail != 0.0) { vlength = scale_expansion_zeroelim(4, ca, bdztail, v); finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v, finother); finswap = finnow; finnow = finother; finother = finswap; } if (cdztail != 0.0) { vlength = scale_expansion_zeroelim(4, ab, cdztail, v); finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v, finother); finswap = finnow; finnow = finother; finother = finswap; } if (adxtail != 0.0) { if (bdytail != 0.0) { Two_Product(adxtail, bdytail, adxt_bdyt1, adxt_bdyt0); Two_One_Product(adxt_bdyt1, adxt_bdyt0, cdz, u3, u[2], u[1], u[0]); u[3] = u3; finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother); finswap = finnow; finnow = finother; finother = finswap; if (cdztail != 0.0) { Two_One_Product(adxt_bdyt1, adxt_bdyt0, cdztail, u3, u[2], u[1], u[0]); u[3] = u3; finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother); finswap = finnow; finnow = finother; finother = finswap; } } if (cdytail != 0.0) { negate = -adxtail; Two_Product(negate, cdytail, adxt_cdyt1, adxt_cdyt0); Two_One_Product(adxt_cdyt1, adxt_cdyt0, bdz, u3, u[2], u[1], u[0]); u[3] = u3; finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother); finswap = finnow; finnow = finother; finother = finswap; if (bdztail != 0.0) { Two_One_Product(adxt_cdyt1, adxt_cdyt0, bdztail, u3, u[2], u[1], u[0]); u[3] = u3; finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother); finswap = finnow; finnow = finother; finother = finswap; } } } if (bdxtail != 0.0) { if (cdytail != 0.0) { Two_Product(bdxtail, cdytail, bdxt_cdyt1, bdxt_cdyt0); Two_One_Product(bdxt_cdyt1, bdxt_cdyt0, adz, u3, u[2], u[1], u[0]); u[3] = u3; finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother); finswap = finnow; finnow = finother; finother = finswap; if (adztail != 0.0) { Two_One_Product(bdxt_cdyt1, bdxt_cdyt0, adztail, u3, u[2], u[1], u[0]); u[3] = u3; finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother); finswap = finnow; finnow = finother; finother = finswap; } } if (adytail != 0.0) { negate = -bdxtail; Two_Product(negate, adytail, bdxt_adyt1, bdxt_adyt0); Two_One_Product(bdxt_adyt1, bdxt_adyt0, cdz, u3, u[2], u[1], u[0]); u[3] = u3; finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother); finswap = finnow; finnow = finother; finother = finswap; if (cdztail != 0.0) { Two_One_Product(bdxt_adyt1, bdxt_adyt0, cdztail, u3, u[2], u[1], u[0]); u[3] = u3; finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother); finswap = finnow; finnow = finother; finother = finswap; } } } if (cdxtail != 0.0) { if (adytail != 0.0) { Two_Product(cdxtail, adytail, cdxt_adyt1, cdxt_adyt0); Two_One_Product(cdxt_adyt1, cdxt_adyt0, bdz, u3, u[2], u[1], u[0]); u[3] = u3; finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother); finswap = finnow; finnow = finother; finother = finswap; if (bdztail != 0.0) { Two_One_Product(cdxt_adyt1, cdxt_adyt0, bdztail, u3, u[2], u[1], u[0]); u[3] = u3; finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother); finswap = finnow; finnow = finother; finother = finswap; } } if (bdytail != 0.0) { negate = -cdxtail; Two_Product(negate, bdytail, cdxt_bdyt1, cdxt_bdyt0); Two_One_Product(cdxt_bdyt1, cdxt_bdyt0, adz, u3, u[2], u[1], u[0]); u[3] = u3; finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother); finswap = finnow; finnow = finother; finother = finswap; if (adztail != 0.0) { Two_One_Product(cdxt_bdyt1, cdxt_bdyt0, adztail, u3, u[2], u[1], u[0]); u[3] = u3; finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother); finswap = finnow; finnow = finother; finother = finswap; } } } if (adztail != 0.0) { wlength = scale_expansion_zeroelim(bctlen, bct, adztail, w); finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, finother); finswap = finnow; finnow = finother; finother = finswap; } if (bdztail != 0.0) { wlength = scale_expansion_zeroelim(catlen, cat, bdztail, w); finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, finother); finswap = finnow; finnow = finother; finother = finswap; } if (cdztail != 0.0) { wlength = scale_expansion_zeroelim(abtlen, abt, cdztail, w); finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, finother); finswap = finnow; finnow = finother; finother = finswap; } return finnow[finlength - 1]; } REAL orient3d(REAL *pa, REAL *pb, REAL *pc, REAL *pd) { REAL adx, bdx, cdx, ady, bdy, cdy, adz, bdz, cdz; REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady; REAL det; REAL permanent, errbound; REAL orient; FPU_ROUND_DOUBLE; adx = pa[0] - pd[0]; bdx = pb[0] - pd[0]; cdx = pc[0] - pd[0]; ady = pa[1] - pd[1]; bdy = pb[1] - pd[1]; cdy = pc[1] - pd[1]; adz = pa[2] - pd[2]; bdz = pb[2] - pd[2]; cdz = pc[2] - pd[2]; bdxcdy = bdx * cdy; cdxbdy = cdx * bdy; cdxady = cdx * ady; adxcdy = adx * cdy; adxbdy = adx * bdy; bdxady = bdx * ady; det = adz * (bdxcdy - cdxbdy) + bdz * (cdxady - adxcdy) + cdz * (adxbdy - bdxady); permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * Absolute(adz) + (Absolute(cdxady) + Absolute(adxcdy)) * Absolute(bdz) + (Absolute(adxbdy) + Absolute(bdxady)) * Absolute(cdz); errbound = o3derrboundA * permanent; if ((det > errbound) || (-det > errbound)) { FPU_RESTORE; return det; } orient = orient3dadapt(pa, pb, pc, pd, permanent); FPU_RESTORE; return orient; } /*****************************************************************************/ /* */ /* incirclefast() Approximate 2D incircle test. Nonrobust. */ /* incircleexact() Exact 2D incircle test. Robust. */ /* incircleslow() Another exact 2D incircle test. Robust. */ /* incircle() Adaptive exact 2D incircle test. Robust. */ /* */ /* Return a positive value if the point pd lies inside the */ /* circle passing through pa, pb, and pc; a negative value if */ /* it lies outside; and zero if the four points are cocircular.*/ /* The points pa, pb, and pc must be in counterclockwise */ /* order, or the sign of the result will be reversed. */ /* */ /* Only the first and last routine should be used; the middle two are for */ /* timings. */ /* */ /* The last three use exact arithmetic to ensure a correct answer. The */ /* result returned is the determinant of a matrix. In incircle() only, */ /* this determinant is computed adaptively, in the sense that exact */ /* arithmetic is used only to the degree it is needed to ensure that the */ /* returned value has the correct sign. Hence, incircle() is usually quite */ /* fast, but will run more slowly when the input points are cocircular or */ /* nearly so. */ /* */ /*****************************************************************************/ static REAL incircleadapt(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL permanent) { INEXACT REAL adx, bdx, cdx, ady, bdy, cdy; REAL det, errbound; INEXACT REAL bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1; REAL bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0; REAL bc[4], ca[4], ab[4]; INEXACT REAL bc3, ca3, ab3; REAL axbc[8], axxbc[16], aybc[8], ayybc[16], adet[32]; int axbclen, axxbclen, aybclen, ayybclen, alen; REAL bxca[8], bxxca[16], byca[8], byyca[16], bdet[32]; int bxcalen, bxxcalen, bycalen, byycalen, blen; REAL cxab[8], cxxab[16], cyab[8], cyyab[16], cdet[32]; int cxablen, cxxablen, cyablen, cyyablen, clen; REAL abdet[64]; int ablen; REAL fin1[1152], fin2[1152]; REAL *finnow, *finother, *finswap; int finlength; REAL adxtail, bdxtail, cdxtail, adytail, bdytail, cdytail; INEXACT REAL adxadx1, adyady1, bdxbdx1, bdybdy1, cdxcdx1, cdycdy1; REAL adxadx0, adyady0, bdxbdx0, bdybdy0, cdxcdx0, cdycdy0; REAL aa[4], bb[4], cc[4]; INEXACT REAL aa3, bb3, cc3; INEXACT REAL ti1, tj1; REAL ti0, tj0; REAL u[4], v[4]; INEXACT REAL u3, v3; REAL temp8[8], temp16a[16], temp16b[16], temp16c[16]; REAL temp32a[32], temp32b[32], temp48[48], temp64[64]; int temp8len, temp16alen, temp16blen, temp16clen; int temp32alen, temp32blen, temp48len, temp64len; REAL axtbb[8], axtcc[8], aytbb[8], aytcc[8]; int axtbblen, axtcclen, aytbblen, aytcclen; REAL bxtaa[8], bxtcc[8], bytaa[8], bytcc[8]; int bxtaalen, bxtcclen, bytaalen, bytcclen; REAL cxtaa[8], cxtbb[8], cytaa[8], cytbb[8]; int cxtaalen, cxtbblen, cytaalen, cytbblen; REAL axtbc[8], aytbc[8], bxtca[8], bytca[8], cxtab[8], cytab[8]; int axtbclen = 0, aytbclen = 0; int bxtcalen = 0, bytcalen = 0; int cxtablen = 0, cytablen = 0; REAL axtbct[16], aytbct[16], bxtcat[16], bytcat[16], cxtabt[16], cytabt[16]; int axtbctlen, aytbctlen, bxtcatlen, bytcatlen, cxtabtlen, cytabtlen; REAL axtbctt[8], aytbctt[8], bxtcatt[8]; REAL bytcatt[8], cxtabtt[8], cytabtt[8]; int axtbcttlen, aytbcttlen, bxtcattlen, bytcattlen, cxtabttlen, cytabttlen; REAL abt[8], bct[8], cat[8]; int abtlen, bctlen, catlen; REAL abtt[4], bctt[4], catt[4]; int abttlen, bcttlen, cattlen; INEXACT REAL abtt3, bctt3, catt3; REAL negate; INEXACT REAL bvirt; REAL avirt, bround, around; INEXACT REAL c; INEXACT REAL abig; REAL ahi, alo, bhi, blo; REAL err1, err2, err3; INEXACT REAL _i, _j; REAL _0; adx = (REAL) (pa[0] - pd[0]); bdx = (REAL) (pb[0] - pd[0]); cdx = (REAL) (pc[0] - pd[0]); ady = (REAL) (pa[1] - pd[1]); bdy = (REAL) (pb[1] - pd[1]); cdy = (REAL) (pc[1] - pd[1]); Two_Product(bdx, cdy, bdxcdy1, bdxcdy0); Two_Product(cdx, bdy, cdxbdy1, cdxbdy0); Two_Two_Diff(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0, bc3, bc[2], bc[1], bc[0]); bc[3] = bc3; axbclen = scale_expansion_zeroelim(4, bc, adx, axbc); axxbclen = scale_expansion_zeroelim(axbclen, axbc, adx, axxbc); aybclen = scale_expansion_zeroelim(4, bc, ady, aybc); ayybclen = scale_expansion_zeroelim(aybclen, aybc, ady, ayybc); alen = fast_expansion_sum_zeroelim(axxbclen, axxbc, ayybclen, ayybc, adet); Two_Product(cdx, ady, cdxady1, cdxady0); Two_Product(adx, cdy, adxcdy1, adxcdy0); Two_Two_Diff(cdxady1, cdxady0, adxcdy1, adxcdy0, ca3, ca[2], ca[1], ca[0]); ca[3] = ca3; bxcalen = scale_expansion_zeroelim(4, ca, bdx, bxca); bxxcalen = scale_expansion_zeroelim(bxcalen, bxca, bdx, bxxca); bycalen = scale_expansion_zeroelim(4, ca, bdy, byca); byycalen = scale_expansion_zeroelim(bycalen, byca, bdy, byyca); blen = fast_expansion_sum_zeroelim(bxxcalen, bxxca, byycalen, byyca, bdet); Two_Product(adx, bdy, adxbdy1, adxbdy0); Two_Product(bdx, ady, bdxady1, bdxady0); Two_Two_Diff(adxbdy1, adxbdy0, bdxady1, bdxady0, ab3, ab[2], ab[1], ab[0]); ab[3] = ab3; cxablen = scale_expansion_zeroelim(4, ab, cdx, cxab); cxxablen = scale_expansion_zeroelim(cxablen, cxab, cdx, cxxab); cyablen = scale_expansion_zeroelim(4, ab, cdy, cyab); cyyablen = scale_expansion_zeroelim(cyablen, cyab, cdy, cyyab); clen = fast_expansion_sum_zeroelim(cxxablen, cxxab, cyyablen, cyyab, cdet); ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); finlength = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, fin1); det = estimate(finlength, fin1); errbound = iccerrboundB * permanent; if ((det >= errbound) || (-det >= errbound)) { return det; } Two_Diff_Tail(pa[0], pd[0], adx, adxtail); Two_Diff_Tail(pa[1], pd[1], ady, adytail); Two_Diff_Tail(pb[0], pd[0], bdx, bdxtail); Two_Diff_Tail(pb[1], pd[1], bdy, bdytail); Two_Diff_Tail(pc[0], pd[0], cdx, cdxtail); Two_Diff_Tail(pc[1], pd[1], cdy, cdytail); if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0) && (adytail == 0.0) && (bdytail == 0.0) && (cdytail == 0.0)) { return det; } errbound = iccerrboundC * permanent + resulterrbound * Absolute(det); det += ((adx * adx + ady * ady) * ((bdx * cdytail + cdy * bdxtail) - (bdy * cdxtail + cdx * bdytail)) + 2.0 * (adx * adxtail + ady * adytail) * (bdx * cdy - bdy * cdx)) + ((bdx * bdx + bdy * bdy) * ((cdx * adytail + ady * cdxtail) - (cdy * adxtail + adx * cdytail)) + 2.0 * (bdx * bdxtail + bdy * bdytail) * (cdx * ady - cdy * adx)) + ((cdx * cdx + cdy * cdy) * ((adx * bdytail + bdy * adxtail) - (ady * bdxtail + bdx * adytail)) + 2.0 * (cdx * cdxtail + cdy * cdytail) * (adx * bdy - ady * bdx)); if ((det >= errbound) || (-det >= errbound)) { return det; } finnow = fin1; finother = fin2; if ((bdxtail != 0.0) || (bdytail != 0.0) || (cdxtail != 0.0) || (cdytail != 0.0)) { Square(adx, adxadx1, adxadx0); Square(ady, adyady1, adyady0); Two_Two_Sum(adxadx1, adxadx0, adyady1, adyady0, aa3, aa[2], aa[1], aa[0]); aa[3] = aa3; } if ((cdxtail != 0.0) || (cdytail != 0.0) || (adxtail != 0.0) || (adytail != 0.0)) { Square(bdx, bdxbdx1, bdxbdx0); Square(bdy, bdybdy1, bdybdy0); Two_Two_Sum(bdxbdx1, bdxbdx0, bdybdy1, bdybdy0, bb3, bb[2], bb[1], bb[0]); bb[3] = bb3; } if ((adxtail != 0.0) || (adytail != 0.0) || (bdxtail != 0.0) || (bdytail != 0.0)) { Square(cdx, cdxcdx1, cdxcdx0); Square(cdy, cdycdy1, cdycdy0); Two_Two_Sum(cdxcdx1, cdxcdx0, cdycdy1, cdycdy0, cc3, cc[2], cc[1], cc[0]); cc[3] = cc3; } if (adxtail != 0.0) { axtbclen = scale_expansion_zeroelim(4, bc, adxtail, axtbc); temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, 2.0 * adx, temp16a); axtcclen = scale_expansion_zeroelim(4, cc, adxtail, axtcc); temp16blen = scale_expansion_zeroelim(axtcclen, axtcc, bdy, temp16b); axtbblen = scale_expansion_zeroelim(4, bb, adxtail, axtbb); temp16clen = scale_expansion_zeroelim(axtbblen, axtbb, -cdy, temp16c); temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a); temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); finswap = finnow; finnow = finother; finother = finswap; } if (adytail != 0.0) { aytbclen = scale_expansion_zeroelim(4, bc, adytail, aytbc); temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, 2.0 * ady, temp16a); aytbblen = scale_expansion_zeroelim(4, bb, adytail, aytbb); temp16blen = scale_expansion_zeroelim(aytbblen, aytbb, cdx, temp16b); aytcclen = scale_expansion_zeroelim(4, cc, adytail, aytcc); temp16clen = scale_expansion_zeroelim(aytcclen, aytcc, -bdx, temp16c); temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a); temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); finswap = finnow; finnow = finother; finother = finswap; } if (bdxtail != 0.0) { bxtcalen = scale_expansion_zeroelim(4, ca, bdxtail, bxtca); temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, 2.0 * bdx, temp16a); bxtaalen = scale_expansion_zeroelim(4, aa, bdxtail, bxtaa); temp16blen = scale_expansion_zeroelim(bxtaalen, bxtaa, cdy, temp16b); bxtcclen = scale_expansion_zeroelim(4, cc, bdxtail, bxtcc); temp16clen = scale_expansion_zeroelim(bxtcclen, bxtcc, -ady, temp16c); temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a); temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); finswap = finnow; finnow = finother; finother = finswap; } if (bdytail != 0.0) { bytcalen = scale_expansion_zeroelim(4, ca, bdytail, bytca); temp16alen = scale_expansion_zeroelim(bytcalen, bytca, 2.0 * bdy, temp16a); bytcclen = scale_expansion_zeroelim(4, cc, bdytail, bytcc); temp16blen = scale_expansion_zeroelim(bytcclen, bytcc, adx, temp16b); bytaalen = scale_expansion_zeroelim(4, aa, bdytail, bytaa); temp16clen = scale_expansion_zeroelim(bytaalen, bytaa, -cdx, temp16c); temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a); temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); finswap = finnow; finnow = finother; finother = finswap; } if (cdxtail != 0.0) { cxtablen = scale_expansion_zeroelim(4, ab, cdxtail, cxtab); temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, 2.0 * cdx, temp16a); cxtbblen = scale_expansion_zeroelim(4, bb, cdxtail, cxtbb); temp16blen = scale_expansion_zeroelim(cxtbblen, cxtbb, ady, temp16b); cxtaalen = scale_expansion_zeroelim(4, aa, cdxtail, cxtaa); temp16clen = scale_expansion_zeroelim(cxtaalen, cxtaa, -bdy, temp16c); temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a); temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); finswap = finnow; finnow = finother; finother = finswap; } if (cdytail != 0.0) { cytablen = scale_expansion_zeroelim(4, ab, cdytail, cytab); temp16alen = scale_expansion_zeroelim(cytablen, cytab, 2.0 * cdy, temp16a); cytaalen = scale_expansion_zeroelim(4, aa, cdytail, cytaa); temp16blen = scale_expansion_zeroelim(cytaalen, cytaa, bdx, temp16b); cytbblen = scale_expansion_zeroelim(4, bb, cdytail, cytbb); temp16clen = scale_expansion_zeroelim(cytbblen, cytbb, -adx, temp16c); temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a); temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); finswap = finnow; finnow = finother; finother = finswap; } if ((adxtail != 0.0) || (adytail != 0.0)) { if ((bdxtail != 0.0) || (bdytail != 0.0) || (cdxtail != 0.0) || (cdytail != 0.0)) { Two_Product(bdxtail, cdy, ti1, ti0); Two_Product(bdx, cdytail, tj1, tj0); Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); u[3] = u3; negate = -bdy; Two_Product(cdxtail, negate, ti1, ti0); negate = -bdytail; Two_Product(cdx, negate, tj1, tj0); Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); v[3] = v3; bctlen = fast_expansion_sum_zeroelim(4, u, 4, v, bct); Two_Product(bdxtail, cdytail, ti1, ti0); Two_Product(cdxtail, bdytail, tj1, tj0); Two_Two_Diff(ti1, ti0, tj1, tj0, bctt3, bctt[2], bctt[1], bctt[0]); bctt[3] = bctt3; bcttlen = 4; } else { bct[0] = 0.0; bctlen = 1; bctt[0] = 0.0; bcttlen = 1; } if (adxtail != 0.0) { temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, adxtail, temp16a); axtbctlen = scale_expansion_zeroelim(bctlen, bct, adxtail, axtbct); temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, 2.0 * adx, temp32a); temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); finswap = finnow; finnow = finother; finother = finswap; if (bdytail != 0.0) { temp8len = scale_expansion_zeroelim(4, cc, adxtail, temp8); temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail, temp16a); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a, finother); finswap = finnow; finnow = finother; finother = finswap; } if (cdytail != 0.0) { temp8len = scale_expansion_zeroelim(4, bb, -adxtail, temp8); temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail, temp16a); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a, finother); finswap = finnow; finnow = finother; finother = finswap; } temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, adxtail, temp32a); axtbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adxtail, axtbctt); temp16alen = scale_expansion_zeroelim(axtbcttlen, axtbctt, 2.0 * adx, temp16a); temp16blen = scale_expansion_zeroelim(axtbcttlen, axtbctt, adxtail, temp16b); temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32b); temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother); finswap = finnow; finnow = finother; finother = finswap; } if (adytail != 0.0) { temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, adytail, temp16a); aytbctlen = scale_expansion_zeroelim(bctlen, bct, adytail, aytbct); temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, 2.0 * ady, temp32a); temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); finswap = finnow; finnow = finother; finother = finswap; temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, adytail, temp32a); aytbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adytail, aytbctt); temp16alen = scale_expansion_zeroelim(aytbcttlen, aytbctt, 2.0 * ady, temp16a); temp16blen = scale_expansion_zeroelim(aytbcttlen, aytbctt, adytail, temp16b); temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32b); temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother); finswap = finnow; finnow = finother; finother = finswap; } } if ((bdxtail != 0.0) || (bdytail != 0.0)) { if ((cdxtail != 0.0) || (cdytail != 0.0) || (adxtail != 0.0) || (adytail != 0.0)) { Two_Product(cdxtail, ady, ti1, ti0); Two_Product(cdx, adytail, tj1, tj0); Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); u[3] = u3; negate = -cdy; Two_Product(adxtail, negate, ti1, ti0); negate = -cdytail; Two_Product(adx, negate, tj1, tj0); Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); v[3] = v3; catlen = fast_expansion_sum_zeroelim(4, u, 4, v, cat); Two_Product(cdxtail, adytail, ti1, ti0); Two_Product(adxtail, cdytail, tj1, tj0); Two_Two_Diff(ti1, ti0, tj1, tj0, catt3, catt[2], catt[1], catt[0]); catt[3] = catt3; cattlen = 4; } else { cat[0] = 0.0; catlen = 1; catt[0] = 0.0; cattlen = 1; } if (bdxtail != 0.0) { temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, bdxtail, temp16a); bxtcatlen = scale_expansion_zeroelim(catlen, cat, bdxtail, bxtcat); temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, 2.0 * bdx, temp32a); temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); finswap = finnow; finnow = finother; finother = finswap; if (cdytail != 0.0) { temp8len = scale_expansion_zeroelim(4, aa, bdxtail, temp8); temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail, temp16a); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a, finother); finswap = finnow; finnow = finother; finother = finswap; } if (adytail != 0.0) { temp8len = scale_expansion_zeroelim(4, cc, -bdxtail, temp8); temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail, temp16a); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a, finother); finswap = finnow; finnow = finother; finother = finswap; } temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, bdxtail, temp32a); bxtcattlen = scale_expansion_zeroelim(cattlen, catt, bdxtail, bxtcatt); temp16alen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, 2.0 * bdx, temp16a); temp16blen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, bdxtail, temp16b); temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32b); temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother); finswap = finnow; finnow = finother; finother = finswap; } if (bdytail != 0.0) { temp16alen = scale_expansion_zeroelim(bytcalen, bytca, bdytail, temp16a); bytcatlen = scale_expansion_zeroelim(catlen, cat, bdytail, bytcat); temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, 2.0 * bdy, temp32a); temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); finswap = finnow; finnow = finother; finother = finswap; temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, bdytail, temp32a); bytcattlen = scale_expansion_zeroelim(cattlen, catt, bdytail, bytcatt); temp16alen = scale_expansion_zeroelim(bytcattlen, bytcatt, 2.0 * bdy, temp16a); temp16blen = scale_expansion_zeroelim(bytcattlen, bytcatt, bdytail, temp16b); temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32b); temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother); finswap = finnow; finnow = finother; finother = finswap; } } if ((cdxtail != 0.0) || (cdytail != 0.0)) { if ((adxtail != 0.0) || (adytail != 0.0) || (bdxtail != 0.0) || (bdytail != 0.0)) { Two_Product(adxtail, bdy, ti1, ti0); Two_Product(adx, bdytail, tj1, tj0); Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); u[3] = u3; negate = -ady; Two_Product(bdxtail, negate, ti1, ti0); negate = -adytail; Two_Product(bdx, negate, tj1, tj0); Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); v[3] = v3; abtlen = fast_expansion_sum_zeroelim(4, u, 4, v, abt); Two_Product(adxtail, bdytail, ti1, ti0); Two_Product(bdxtail, adytail, tj1, tj0); Two_Two_Diff(ti1, ti0, tj1, tj0, abtt3, abtt[2], abtt[1], abtt[0]); abtt[3] = abtt3; abttlen = 4; } else { abt[0] = 0.0; abtlen = 1; abtt[0] = 0.0; abttlen = 1; } if (cdxtail != 0.0) { temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, cdxtail, temp16a); cxtabtlen = scale_expansion_zeroelim(abtlen, abt, cdxtail, cxtabt); temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, 2.0 * cdx, temp32a); temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); finswap = finnow; finnow = finother; finother = finswap; if (adytail != 0.0) { temp8len = scale_expansion_zeroelim(4, bb, cdxtail, temp8); temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail, temp16a); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a, finother); finswap = finnow; finnow = finother; finother = finswap; } if (bdytail != 0.0) { temp8len = scale_expansion_zeroelim(4, aa, -cdxtail, temp8); temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail, temp16a); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a, finother); finswap = finnow; finnow = finother; finother = finswap; } temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, cdxtail, temp32a); cxtabttlen = scale_expansion_zeroelim(abttlen, abtt, cdxtail, cxtabtt); temp16alen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, 2.0 * cdx, temp16a); temp16blen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, cdxtail, temp16b); temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32b); temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother); finswap = finnow; finnow = finother; finother = finswap; } if (cdytail != 0.0) { temp16alen = scale_expansion_zeroelim(cytablen, cytab, cdytail, temp16a); cytabtlen = scale_expansion_zeroelim(abtlen, abt, cdytail, cytabt); temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, 2.0 * cdy, temp32a); temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); finswap = finnow; finnow = finother; finother = finswap; temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, cdytail, temp32a); cytabttlen = scale_expansion_zeroelim(abttlen, abtt, cdytail, cytabtt); temp16alen = scale_expansion_zeroelim(cytabttlen, cytabtt, 2.0 * cdy, temp16a); temp16blen = scale_expansion_zeroelim(cytabttlen, cytabtt, cdytail, temp16b); temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32b); temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother); finswap = finnow; finnow = finother; finother = finswap; } } return finnow[finlength - 1]; } REAL incircle(REAL *pa, REAL *pb, REAL *pc, REAL *pd) { REAL adx, bdx, cdx, ady, bdy, cdy; REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady; REAL alift, blift, clift; REAL det; REAL permanent, errbound; REAL inc; FPU_ROUND_DOUBLE; adx = pa[0] - pd[0]; bdx = pb[0] - pd[0]; cdx = pc[0] - pd[0]; ady = pa[1] - pd[1]; bdy = pb[1] - pd[1]; cdy = pc[1] - pd[1]; bdxcdy = bdx * cdy; cdxbdy = cdx * bdy; alift = adx * adx + ady * ady; cdxady = cdx * ady; adxcdy = adx * cdy; blift = bdx * bdx + bdy * bdy; adxbdy = adx * bdy; bdxady = bdx * ady; clift = cdx * cdx + cdy * cdy; det = alift * (bdxcdy - cdxbdy) + blift * (cdxady - adxcdy) + clift * (adxbdy - bdxady); permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * alift + (Absolute(cdxady) + Absolute(adxcdy)) * blift + (Absolute(adxbdy) + Absolute(bdxady)) * clift; errbound = iccerrboundA * permanent; if ((det > errbound) || (-det > errbound)) { FPU_RESTORE; return det; } inc = incircleadapt(pa, pb, pc, pd, permanent); FPU_RESTORE; return inc; } REAL incircle(REAL ax, REAL ay, REAL bx, REAL by, REAL cx, REAL cy, REAL dx, REAL dy) { REAL adx, bdx, cdx, ady, bdy, cdy; REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady; REAL alift, blift, clift; REAL det; REAL permanent, errbound; REAL inc; FPU_ROUND_DOUBLE; adx = ax - dx; bdx = bx - dx; cdx = cx - dx; ady = ay - dy; bdy = by - dy; cdy = cy - dy; bdxcdy = bdx * cdy; cdxbdy = cdx * bdy; alift = adx * adx + ady * ady; cdxady = cdx * ady; adxcdy = adx * cdy; blift = bdx * bdx + bdy * bdy; adxbdy = adx * bdy; bdxady = bdx * ady; clift = cdx * cdx + cdy * cdy; det = alift * (bdxcdy - cdxbdy) + blift * (cdxady - adxcdy) + clift * (adxbdy - bdxady); permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * alift + (Absolute(cdxady) + Absolute(adxcdy)) * blift + (Absolute(adxbdy) + Absolute(bdxady)) * clift; errbound = iccerrboundA * permanent; if ((det > errbound) || (-det > errbound)) { FPU_RESTORE; return det; } REAL pa[]={ax,ay}; REAL pb[]={bx,by}; REAL pc[]={cx,cy}; REAL pd[]={dx,dy}; inc = incircleadapt(pa, pb, pc, pd, permanent); FPU_RESTORE; return inc; } /*****************************************************************************/ /* */ /* inspherefast() Approximate 3D insphere test. Nonrobust. */ /* insphereexact() Exact 3D insphere test. Robust. */ /* insphereslow() Another exact 3D insphere test. Robust. */ /* insphere() Adaptive exact 3D insphere test. Robust. */ /* */ /* Return a positive value if the point pe lies inside the */ /* sphere passing through pa, pb, pc, and pd; a negative value */ /* if it lies outside; and zero if the five points are */ /* cospherical. The points pa, pb, pc, and pd must be ordered */ /* so that they have a positive orientation (as defined by */ /* orient3d()), or the sign of the result will be reversed. */ /* */ /* Only the first and last routine should be used; the middle two are for */ /* timings. */ /* */ /* The last three use exact arithmetic to ensure a correct answer. The */ /* result returned is the determinant of a matrix. In insphere() only, */ /* this determinant is computed adaptively, in the sense that exact */ /* arithmetic is used only to the degree it is needed to ensure that the */ /* returned value has the correct sign. Hence, insphere() is usually quite */ /* fast, but will run more slowly when the input points are cospherical or */ /* nearly so. */ /* */ /*****************************************************************************/ static REAL insphereexact(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe) { INEXACT REAL axby1, bxcy1, cxdy1, dxey1, exay1; INEXACT REAL bxay1, cxby1, dxcy1, exdy1, axey1; INEXACT REAL axcy1, bxdy1, cxey1, dxay1, exby1; INEXACT REAL cxay1, dxby1, excy1, axdy1, bxey1; REAL axby0, bxcy0, cxdy0, dxey0, exay0; REAL bxay0, cxby0, dxcy0, exdy0, axey0; REAL axcy0, bxdy0, cxey0, dxay0, exby0; REAL cxay0, dxby0, excy0, axdy0, bxey0; REAL ab[4], bc[4], cd[4], de[4], ea[4]; REAL ac[4], bd[4], ce[4], da[4], eb[4]; REAL temp8a[8], temp8b[8], temp16[16]; int temp8alen, temp8blen, temp16len; REAL abc[24], bcd[24], cde[24], dea[24], eab[24]; REAL abd[24], bce[24], cda[24], deb[24], eac[24]; int abclen, bcdlen, cdelen, dealen, eablen; int abdlen, bcelen, cdalen, deblen, eaclen; REAL temp48a[48], temp48b[48]; int temp48alen, temp48blen; REAL abcd[96], bcde[96], cdea[96], deab[96], eabc[96]; int abcdlen, bcdelen, cdealen, deablen, eabclen; REAL temp192[192]; REAL det384x[384], det384y[384], det384z[384]; int xlen, ylen, zlen; REAL detxy[768]; int xylen; REAL adet[1152], bdet[1152], cdet[1152], ddet[1152], edet[1152]; int alen, blen, clen, dlen, elen; REAL abdet[2304], cddet[2304], cdedet[3456]; int ablen, cdlen; REAL deter[5760]; int deterlen; int i; INEXACT REAL bvirt; REAL avirt, bround, around; INEXACT REAL c; INEXACT REAL abig; REAL ahi, alo, bhi, blo; REAL err1, err2, err3; INEXACT REAL _i, _j; REAL _0; Two_Product(pa[0], pb[1], axby1, axby0); Two_Product(pb[0], pa[1], bxay1, bxay0); Two_Two_Diff(axby1, axby0, bxay1, bxay0, ab[3], ab[2], ab[1], ab[0]); Two_Product(pb[0], pc[1], bxcy1, bxcy0); Two_Product(pc[0], pb[1], cxby1, cxby0); Two_Two_Diff(bxcy1, bxcy0, cxby1, cxby0, bc[3], bc[2], bc[1], bc[0]); Two_Product(pc[0], pd[1], cxdy1, cxdy0); Two_Product(pd[0], pc[1], dxcy1, dxcy0); Two_Two_Diff(cxdy1, cxdy0, dxcy1, dxcy0, cd[3], cd[2], cd[1], cd[0]); Two_Product(pd[0], pe[1], dxey1, dxey0); Two_Product(pe[0], pd[1], exdy1, exdy0); Two_Two_Diff(dxey1, dxey0, exdy1, exdy0, de[3], de[2], de[1], de[0]); Two_Product(pe[0], pa[1], exay1, exay0); Two_Product(pa[0], pe[1], axey1, axey0); Two_Two_Diff(exay1, exay0, axey1, axey0, ea[3], ea[2], ea[1], ea[0]); Two_Product(pa[0], pc[1], axcy1, axcy0); Two_Product(pc[0], pa[1], cxay1, cxay0); Two_Two_Diff(axcy1, axcy0, cxay1, cxay0, ac[3], ac[2], ac[1], ac[0]); Two_Product(pb[0], pd[1], bxdy1, bxdy0); Two_Product(pd[0], pb[1], dxby1, dxby0); Two_Two_Diff(bxdy1, bxdy0, dxby1, dxby0, bd[3], bd[2], bd[1], bd[0]); Two_Product(pc[0], pe[1], cxey1, cxey0); Two_Product(pe[0], pc[1], excy1, excy0); Two_Two_Diff(cxey1, cxey0, excy1, excy0, ce[3], ce[2], ce[1], ce[0]); Two_Product(pd[0], pa[1], dxay1, dxay0); Two_Product(pa[0], pd[1], axdy1, axdy0); Two_Two_Diff(dxay1, dxay0, axdy1, axdy0, da[3], da[2], da[1], da[0]); Two_Product(pe[0], pb[1], exby1, exby0); Two_Product(pb[0], pe[1], bxey1, bxey0); Two_Two_Diff(exby1, exby0, bxey1, bxey0, eb[3], eb[2], eb[1], eb[0]); temp8alen = scale_expansion_zeroelim(4, bc, pa[2], temp8a); temp8blen = scale_expansion_zeroelim(4, ac, -pb[2], temp8b); temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, temp16); temp8alen = scale_expansion_zeroelim(4, ab, pc[2], temp8a); abclen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, abc); temp8alen = scale_expansion_zeroelim(4, cd, pb[2], temp8a); temp8blen = scale_expansion_zeroelim(4, bd, -pc[2], temp8b); temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, temp16); temp8alen = scale_expansion_zeroelim(4, bc, pd[2], temp8a); bcdlen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, bcd); temp8alen = scale_expansion_zeroelim(4, de, pc[2], temp8a); temp8blen = scale_expansion_zeroelim(4, ce, -pd[2], temp8b); temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, temp16); temp8alen = scale_expansion_zeroelim(4, cd, pe[2], temp8a); cdelen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, cde); temp8alen = scale_expansion_zeroelim(4, ea, pd[2], temp8a); temp8blen = scale_expansion_zeroelim(4, da, -pe[2], temp8b); temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, temp16); temp8alen = scale_expansion_zeroelim(4, de, pa[2], temp8a); dealen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, dea); temp8alen = scale_expansion_zeroelim(4, ab, pe[2], temp8a); temp8blen = scale_expansion_zeroelim(4, eb, -pa[2], temp8b); temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, temp16); temp8alen = scale_expansion_zeroelim(4, ea, pb[2], temp8a); eablen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, eab); temp8alen = scale_expansion_zeroelim(4, bd, pa[2], temp8a); temp8blen = scale_expansion_zeroelim(4, da, pb[2], temp8b); temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, temp16); temp8alen = scale_expansion_zeroelim(4, ab, pd[2], temp8a); abdlen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, abd); temp8alen = scale_expansion_zeroelim(4, ce, pb[2], temp8a); temp8blen = scale_expansion_zeroelim(4, eb, pc[2], temp8b); temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, temp16); temp8alen = scale_expansion_zeroelim(4, bc, pe[2], temp8a); bcelen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, bce); temp8alen = scale_expansion_zeroelim(4, da, pc[2], temp8a); temp8blen = scale_expansion_zeroelim(4, ac, pd[2], temp8b); temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, temp16); temp8alen = scale_expansion_zeroelim(4, cd, pa[2], temp8a); cdalen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, cda); temp8alen = scale_expansion_zeroelim(4, eb, pd[2], temp8a); temp8blen = scale_expansion_zeroelim(4, bd, pe[2], temp8b); temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, temp16); temp8alen = scale_expansion_zeroelim(4, de, pb[2], temp8a); deblen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, deb); temp8alen = scale_expansion_zeroelim(4, ac, pe[2], temp8a); temp8blen = scale_expansion_zeroelim(4, ce, pa[2], temp8b); temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, temp16); temp8alen = scale_expansion_zeroelim(4, ea, pc[2], temp8a); eaclen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, eac); temp48alen = fast_expansion_sum_zeroelim(cdelen, cde, bcelen, bce, temp48a); temp48blen = fast_expansion_sum_zeroelim(deblen, deb, bcdlen, bcd, temp48b); for (i = 0; i < temp48blen; i++) { temp48b[i] = -temp48b[i]; } bcdelen = fast_expansion_sum_zeroelim(temp48alen, temp48a, temp48blen, temp48b, bcde); xlen = scale_expansion_zeroelim(bcdelen, bcde, pa[0], temp192); xlen = scale_expansion_zeroelim(xlen, temp192, pa[0], det384x); ylen = scale_expansion_zeroelim(bcdelen, bcde, pa[1], temp192); ylen = scale_expansion_zeroelim(ylen, temp192, pa[1], det384y); zlen = scale_expansion_zeroelim(bcdelen, bcde, pa[2], temp192); zlen = scale_expansion_zeroelim(zlen, temp192, pa[2], det384z); xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy); alen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, adet); temp48alen = fast_expansion_sum_zeroelim(dealen, dea, cdalen, cda, temp48a); temp48blen = fast_expansion_sum_zeroelim(eaclen, eac, cdelen, cde, temp48b); for (i = 0; i < temp48blen; i++) { temp48b[i] = -temp48b[i]; } cdealen = fast_expansion_sum_zeroelim(temp48alen, temp48a, temp48blen, temp48b, cdea); xlen = scale_expansion_zeroelim(cdealen, cdea, pb[0], temp192); xlen = scale_expansion_zeroelim(xlen, temp192, pb[0], det384x); ylen = scale_expansion_zeroelim(cdealen, cdea, pb[1], temp192); ylen = scale_expansion_zeroelim(ylen, temp192, pb[1], det384y); zlen = scale_expansion_zeroelim(cdealen, cdea, pb[2], temp192); zlen = scale_expansion_zeroelim(zlen, temp192, pb[2], det384z); xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy); blen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, bdet); temp48alen = fast_expansion_sum_zeroelim(eablen, eab, deblen, deb, temp48a); temp48blen = fast_expansion_sum_zeroelim(abdlen, abd, dealen, dea, temp48b); for (i = 0; i < temp48blen; i++) { temp48b[i] = -temp48b[i]; } deablen = fast_expansion_sum_zeroelim(temp48alen, temp48a, temp48blen, temp48b, deab); xlen = scale_expansion_zeroelim(deablen, deab, pc[0], temp192); xlen = scale_expansion_zeroelim(xlen, temp192, pc[0], det384x); ylen = scale_expansion_zeroelim(deablen, deab, pc[1], temp192); ylen = scale_expansion_zeroelim(ylen, temp192, pc[1], det384y); zlen = scale_expansion_zeroelim(deablen, deab, pc[2], temp192); zlen = scale_expansion_zeroelim(zlen, temp192, pc[2], det384z); xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy); clen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, cdet); temp48alen = fast_expansion_sum_zeroelim(abclen, abc, eaclen, eac, temp48a); temp48blen = fast_expansion_sum_zeroelim(bcelen, bce, eablen, eab, temp48b); for (i = 0; i < temp48blen; i++) { temp48b[i] = -temp48b[i]; } eabclen = fast_expansion_sum_zeroelim(temp48alen, temp48a, temp48blen, temp48b, eabc); xlen = scale_expansion_zeroelim(eabclen, eabc, pd[0], temp192); xlen = scale_expansion_zeroelim(xlen, temp192, pd[0], det384x); ylen = scale_expansion_zeroelim(eabclen, eabc, pd[1], temp192); ylen = scale_expansion_zeroelim(ylen, temp192, pd[1], det384y); zlen = scale_expansion_zeroelim(eabclen, eabc, pd[2], temp192); zlen = scale_expansion_zeroelim(zlen, temp192, pd[2], det384z); xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy); dlen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, ddet); temp48alen = fast_expansion_sum_zeroelim(bcdlen, bcd, abdlen, abd, temp48a); temp48blen = fast_expansion_sum_zeroelim(cdalen, cda, abclen, abc, temp48b); for (i = 0; i < temp48blen; i++) { temp48b[i] = -temp48b[i]; } abcdlen = fast_expansion_sum_zeroelim(temp48alen, temp48a, temp48blen, temp48b, abcd); xlen = scale_expansion_zeroelim(abcdlen, abcd, pe[0], temp192); xlen = scale_expansion_zeroelim(xlen, temp192, pe[0], det384x); ylen = scale_expansion_zeroelim(abcdlen, abcd, pe[1], temp192); ylen = scale_expansion_zeroelim(ylen, temp192, pe[1], det384y); zlen = scale_expansion_zeroelim(abcdlen, abcd, pe[2], temp192); zlen = scale_expansion_zeroelim(zlen, temp192, pe[2], det384z); xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy); elen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, edet); ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); cdlen = fast_expansion_sum_zeroelim(clen, cdet, dlen, ddet, cddet); cdelen = fast_expansion_sum_zeroelim(cdlen, cddet, elen, edet, cdedet); deterlen = fast_expansion_sum_zeroelim(ablen, abdet, cdelen, cdedet, deter); return deter[deterlen - 1]; } static REAL insphereadapt(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe, REAL permanent) { INEXACT REAL aex, bex, cex, dex, aey, bey, cey, dey, aez, bez, cez, dez; REAL det, errbound; INEXACT REAL aexbey1, bexaey1, bexcey1, cexbey1; INEXACT REAL cexdey1, dexcey1, dexaey1, aexdey1; INEXACT REAL aexcey1, cexaey1, bexdey1, dexbey1; REAL aexbey0, bexaey0, bexcey0, cexbey0; REAL cexdey0, dexcey0, dexaey0, aexdey0; REAL aexcey0, cexaey0, bexdey0, dexbey0; REAL ab[4], bc[4], cd[4], da[4], ac[4], bd[4]; INEXACT REAL ab3, bc3, cd3, da3, ac3, bd3; REAL abeps, bceps, cdeps, daeps, aceps, bdeps; REAL temp8a[8], temp8b[8], temp8c[8], temp16[16], temp24[24], temp48[48]; int temp8alen, temp8blen, temp8clen, temp16len, temp24len, temp48len; REAL xdet[96], ydet[96], zdet[96], xydet[192]; int xlen, ylen, zlen, xylen; REAL adet[288], bdet[288], cdet[288], ddet[288]; int alen, blen, clen, dlen; REAL abdet[576], cddet[576]; int ablen, cdlen; REAL fin1[1152]; int finlength; REAL aextail, bextail, cextail, dextail; REAL aeytail, beytail, ceytail, deytail; REAL aeztail, beztail, ceztail, deztail; INEXACT REAL bvirt; REAL avirt, bround, around; INEXACT REAL c; INEXACT REAL abig; REAL ahi, alo, bhi, blo; REAL err1, err2, err3; INEXACT REAL _i, _j; REAL _0; aex = (REAL) (pa[0] - pe[0]); bex = (REAL) (pb[0] - pe[0]); cex = (REAL) (pc[0] - pe[0]); dex = (REAL) (pd[0] - pe[0]); aey = (REAL) (pa[1] - pe[1]); bey = (REAL) (pb[1] - pe[1]); cey = (REAL) (pc[1] - pe[1]); dey = (REAL) (pd[1] - pe[1]); aez = (REAL) (pa[2] - pe[2]); bez = (REAL) (pb[2] - pe[2]); cez = (REAL) (pc[2] - pe[2]); dez = (REAL) (pd[2] - pe[2]); Two_Product(aex, bey, aexbey1, aexbey0); Two_Product(bex, aey, bexaey1, bexaey0); Two_Two_Diff(aexbey1, aexbey0, bexaey1, bexaey0, ab3, ab[2], ab[1], ab[0]); ab[3] = ab3; Two_Product(bex, cey, bexcey1, bexcey0); Two_Product(cex, bey, cexbey1, cexbey0); Two_Two_Diff(bexcey1, bexcey0, cexbey1, cexbey0, bc3, bc[2], bc[1], bc[0]); bc[3] = bc3; Two_Product(cex, dey, cexdey1, cexdey0); Two_Product(dex, cey, dexcey1, dexcey0); Two_Two_Diff(cexdey1, cexdey0, dexcey1, dexcey0, cd3, cd[2], cd[1], cd[0]); cd[3] = cd3; Two_Product(dex, aey, dexaey1, dexaey0); Two_Product(aex, dey, aexdey1, aexdey0); Two_Two_Diff(dexaey1, dexaey0, aexdey1, aexdey0, da3, da[2], da[1], da[0]); da[3] = da3; Two_Product(aex, cey, aexcey1, aexcey0); Two_Product(cex, aey, cexaey1, cexaey0); Two_Two_Diff(aexcey1, aexcey0, cexaey1, cexaey0, ac3, ac[2], ac[1], ac[0]); ac[3] = ac3; Two_Product(bex, dey, bexdey1, bexdey0); Two_Product(dex, bey, dexbey1, dexbey0); Two_Two_Diff(bexdey1, bexdey0, dexbey1, dexbey0, bd3, bd[2], bd[1], bd[0]); bd[3] = bd3; temp8alen = scale_expansion_zeroelim(4, cd, bez, temp8a); temp8blen = scale_expansion_zeroelim(4, bd, -cez, temp8b); temp8clen = scale_expansion_zeroelim(4, bc, dez, temp8c); temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, temp16); temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c, temp16len, temp16, temp24); temp48len = scale_expansion_zeroelim(temp24len, temp24, aex, temp48); xlen = scale_expansion_zeroelim(temp48len, temp48, -aex, xdet); temp48len = scale_expansion_zeroelim(temp24len, temp24, aey, temp48); ylen = scale_expansion_zeroelim(temp48len, temp48, -aey, ydet); temp48len = scale_expansion_zeroelim(temp24len, temp24, aez, temp48); zlen = scale_expansion_zeroelim(temp48len, temp48, -aez, zdet); xylen = fast_expansion_sum_zeroelim(xlen, xdet, ylen, ydet, xydet); alen = fast_expansion_sum_zeroelim(xylen, xydet, zlen, zdet, adet); temp8alen = scale_expansion_zeroelim(4, da, cez, temp8a); temp8blen = scale_expansion_zeroelim(4, ac, dez, temp8b); temp8clen = scale_expansion_zeroelim(4, cd, aez, temp8c); temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, temp16); temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c, temp16len, temp16, temp24); temp48len = scale_expansion_zeroelim(temp24len, temp24, bex, temp48); xlen = scale_expansion_zeroelim(temp48len, temp48, bex, xdet); temp48len = scale_expansion_zeroelim(temp24len, temp24, bey, temp48); ylen = scale_expansion_zeroelim(temp48len, temp48, bey, ydet); temp48len = scale_expansion_zeroelim(temp24len, temp24, bez, temp48); zlen = scale_expansion_zeroelim(temp48len, temp48, bez, zdet); xylen = fast_expansion_sum_zeroelim(xlen, xdet, ylen, ydet, xydet); blen = fast_expansion_sum_zeroelim(xylen, xydet, zlen, zdet, bdet); temp8alen = scale_expansion_zeroelim(4, ab, dez, temp8a); temp8blen = scale_expansion_zeroelim(4, bd, aez, temp8b); temp8clen = scale_expansion_zeroelim(4, da, bez, temp8c); temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, temp16); temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c, temp16len, temp16, temp24); temp48len = scale_expansion_zeroelim(temp24len, temp24, cex, temp48); xlen = scale_expansion_zeroelim(temp48len, temp48, -cex, xdet); temp48len = scale_expansion_zeroelim(temp24len, temp24, cey, temp48); ylen = scale_expansion_zeroelim(temp48len, temp48, -cey, ydet); temp48len = scale_expansion_zeroelim(temp24len, temp24, cez, temp48); zlen = scale_expansion_zeroelim(temp48len, temp48, -cez, zdet); xylen = fast_expansion_sum_zeroelim(xlen, xdet, ylen, ydet, xydet); clen = fast_expansion_sum_zeroelim(xylen, xydet, zlen, zdet, cdet); temp8alen = scale_expansion_zeroelim(4, bc, aez, temp8a); temp8blen = scale_expansion_zeroelim(4, ac, -bez, temp8b); temp8clen = scale_expansion_zeroelim(4, ab, cez, temp8c); temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, temp16); temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c, temp16len, temp16, temp24); temp48len = scale_expansion_zeroelim(temp24len, temp24, dex, temp48); xlen = scale_expansion_zeroelim(temp48len, temp48, dex, xdet); temp48len = scale_expansion_zeroelim(temp24len, temp24, dey, temp48); ylen = scale_expansion_zeroelim(temp48len, temp48, dey, ydet); temp48len = scale_expansion_zeroelim(temp24len, temp24, dez, temp48); zlen = scale_expansion_zeroelim(temp48len, temp48, dez, zdet); xylen = fast_expansion_sum_zeroelim(xlen, xdet, ylen, ydet, xydet); dlen = fast_expansion_sum_zeroelim(xylen, xydet, zlen, zdet, ddet); ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); cdlen = fast_expansion_sum_zeroelim(clen, cdet, dlen, ddet, cddet); finlength = fast_expansion_sum_zeroelim(ablen, abdet, cdlen, cddet, fin1); det = estimate(finlength, fin1); errbound = isperrboundB * permanent; if ((det >= errbound) || (-det >= errbound)) { return det; } Two_Diff_Tail(pa[0], pe[0], aex, aextail); Two_Diff_Tail(pa[1], pe[1], aey, aeytail); Two_Diff_Tail(pa[2], pe[2], aez, aeztail); Two_Diff_Tail(pb[0], pe[0], bex, bextail); Two_Diff_Tail(pb[1], pe[1], bey, beytail); Two_Diff_Tail(pb[2], pe[2], bez, beztail); Two_Diff_Tail(pc[0], pe[0], cex, cextail); Two_Diff_Tail(pc[1], pe[1], cey, ceytail); Two_Diff_Tail(pc[2], pe[2], cez, ceztail); Two_Diff_Tail(pd[0], pe[0], dex, dextail); Two_Diff_Tail(pd[1], pe[1], dey, deytail); Two_Diff_Tail(pd[2], pe[2], dez, deztail); if ((aextail == 0.0) && (aeytail == 0.0) && (aeztail == 0.0) && (bextail == 0.0) && (beytail == 0.0) && (beztail == 0.0) && (cextail == 0.0) && (ceytail == 0.0) && (ceztail == 0.0) && (dextail == 0.0) && (deytail == 0.0) && (deztail == 0.0)) { return det; } errbound = isperrboundC * permanent + resulterrbound * Absolute(det); abeps = (aex * beytail + bey * aextail) - (aey * bextail + bex * aeytail); bceps = (bex * ceytail + cey * bextail) - (bey * cextail + cex * beytail); cdeps = (cex * deytail + dey * cextail) - (cey * dextail + dex * ceytail); daeps = (dex * aeytail + aey * dextail) - (dey * aextail + aex * deytail); aceps = (aex * ceytail + cey * aextail) - (aey * cextail + cex * aeytail); bdeps = (bex * deytail + dey * bextail) - (bey * dextail + dex * beytail); det += (((bex * bex + bey * bey + bez * bez) * ((cez * daeps + dez * aceps + aez * cdeps) + (ceztail * da3 + deztail * ac3 + aeztail * cd3)) + (dex * dex + dey * dey + dez * dez) * ((aez * bceps - bez * aceps + cez * abeps) + (aeztail * bc3 - beztail * ac3 + ceztail * ab3))) - ((aex * aex + aey * aey + aez * aez) * ((bez * cdeps - cez * bdeps + dez * bceps) + (beztail * cd3 - ceztail * bd3 + deztail * bc3)) + (cex * cex + cey * cey + cez * cez) * ((dez * abeps + aez * bdeps + bez * daeps) + (deztail * ab3 + aeztail * bd3 + beztail * da3)))) + 2.0 * (((bex * bextail + bey * beytail + bez * beztail) * (cez * da3 + dez * ac3 + aez * cd3) + (dex * dextail + dey * deytail + dez * deztail) * (aez * bc3 - bez * ac3 + cez * ab3)) - ((aex * aextail + aey * aeytail + aez * aeztail) * (bez * cd3 - cez * bd3 + dez * bc3) + (cex * cextail + cey * ceytail + cez * ceztail) * (dez * ab3 + aez * bd3 + bez * da3))); if ((det >= errbound) || (-det >= errbound)) { return det; } return insphereexact(pa, pb, pc, pd, pe); } REAL insphere(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe) { REAL aex, bex, cex, dex; REAL aey, bey, cey, dey; REAL aez, bez, cez, dez; REAL aexbey, bexaey, bexcey, cexbey, cexdey, dexcey, dexaey, aexdey; REAL aexcey, cexaey, bexdey, dexbey; REAL alift, blift, clift, dlift; REAL ab, bc, cd, da, ac, bd; REAL abc, bcd, cda, dab; REAL aezplus, bezplus, cezplus, dezplus; REAL aexbeyplus, bexaeyplus, bexceyplus, cexbeyplus; REAL cexdeyplus, dexceyplus, dexaeyplus, aexdeyplus; REAL aexceyplus, cexaeyplus, bexdeyplus, dexbeyplus; REAL det; REAL permanent, errbound; REAL ins; FPU_ROUND_DOUBLE; aex = pa[0] - pe[0]; bex = pb[0] - pe[0]; cex = pc[0] - pe[0]; dex = pd[0] - pe[0]; aey = pa[1] - pe[1]; bey = pb[1] - pe[1]; cey = pc[1] - pe[1]; dey = pd[1] - pe[1]; aez = pa[2] - pe[2]; bez = pb[2] - pe[2]; cez = pc[2] - pe[2]; dez = pd[2] - pe[2]; aexbey = aex * bey; bexaey = bex * aey; ab = aexbey - bexaey; bexcey = bex * cey; cexbey = cex * bey; bc = bexcey - cexbey; cexdey = cex * dey; dexcey = dex * cey; cd = cexdey - dexcey; dexaey = dex * aey; aexdey = aex * dey; da = dexaey - aexdey; aexcey = aex * cey; cexaey = cex * aey; ac = aexcey - cexaey; bexdey = bex * dey; dexbey = dex * bey; bd = bexdey - dexbey; abc = aez * bc - bez * ac + cez * ab; bcd = bez * cd - cez * bd + dez * bc; cda = cez * da + dez * ac + aez * cd; dab = dez * ab + aez * bd + bez * da; alift = aex * aex + aey * aey + aez * aez; blift = bex * bex + bey * bey + bez * bez; clift = cex * cex + cey * cey + cez * cez; dlift = dex * dex + dey * dey + dez * dez; det = (dlift * abc - clift * dab) + (blift * cda - alift * bcd); aezplus = Absolute(aez); bezplus = Absolute(bez); cezplus = Absolute(cez); dezplus = Absolute(dez); aexbeyplus = Absolute(aexbey); bexaeyplus = Absolute(bexaey); bexceyplus = Absolute(bexcey); cexbeyplus = Absolute(cexbey); cexdeyplus = Absolute(cexdey); dexceyplus = Absolute(dexcey); dexaeyplus = Absolute(dexaey); aexdeyplus = Absolute(aexdey); aexceyplus = Absolute(aexcey); cexaeyplus = Absolute(cexaey); bexdeyplus = Absolute(bexdey); dexbeyplus = Absolute(dexbey); permanent = ((cexdeyplus + dexceyplus) * bezplus + (dexbeyplus + bexdeyplus) * cezplus + (bexceyplus + cexbeyplus) * dezplus) * alift + ((dexaeyplus + aexdeyplus) * cezplus + (aexceyplus + cexaeyplus) * dezplus + (cexdeyplus + dexceyplus) * aezplus) * blift + ((aexbeyplus + bexaeyplus) * dezplus + (bexdeyplus + dexbeyplus) * aezplus + (dexaeyplus + aexdeyplus) * bezplus) * clift + ((bexceyplus + cexbeyplus) * aezplus + (cexaeyplus + aexceyplus) * bezplus + (aexbeyplus + bexaeyplus) * cezplus) * dlift; errbound = isperrboundA * permanent; if ((det > errbound) || (-det > errbound)) { FPU_RESTORE; return det; } ins = insphereadapt(pa, pb, pc, pd, pe, permanent); FPU_RESTORE; return ins; } asymptote-2.37/predicates.h000066400000000000000000000014431265434602500157770ustar00rootroot00000000000000#ifndef PREDICATES_H #define PREDICATES_H double orient2d(double* pa, double* pb, double* pc); double orient2d(double ax, double ay, double bx, double by, double cx, double cy); double orient2dadapt(double *pa, double *pb, double *pc, double detsum); double orient3d(double* pa, double* pb, double* pc, double* pd); double incircle(double* pa, double* pb, double* pc, double* pd); double incircle(double ax, double ay, double bx, double by, double cx, double cy, double dx, double dy); double insphere(double* pa, double* pb, double* pc, double* pd, double* pe); extern const double resulterrbound,ccwerrboundA,ccwerrboundB,ccwerrboundC, o3derrboundA,o3derrboundB,o3derrboundC,iccerrboundA,iccerrboundB, iccerrboundC,isperrboundA,isperrboundB,isperrboundC; #endif asymptote-2.37/primitives.h000066400000000000000000000023221265434602500160440ustar00rootroot00000000000000/***** * primitives.h * Andy Hammerlindl 2007/04/27 * * A list of the primative types in Asymptote, defined using the * PRIMITIVE(name,Name,asyName) macro. This macro should be defined in by the * code including this file for the context at hand. * * name - the name of the type in C++ code ex: boolean * Name - the same name capitalized ex: Boolean * asyName - the name in Asymptote code ex: bool * *****/ // No ifndef because this file may be included multiple times in different // contexts. PRIMITIVE(void,Void,void) PRIMITIVE(inferred,Inferred,var) /* null is not a primitive type. */ #ifdef PRIMERROR PRIMITIVE(error,Error,) #endif PRIMITIVE(boolean,Boolean,bool) PRIMITIVE(Int,Int,int) PRIMITIVE(real,Real,real) PRIMITIVE(string,String,string) PRIMITIVE(pair,Pair,pair) PRIMITIVE(triple,Triple,triple) PRIMITIVE(transform,Transform,transform) PRIMITIVE(guide,Guide,guide) PRIMITIVE(path,Path,path) PRIMITIVE(path3,Path3,path3) PRIMITIVE(cycleToken,CycleToken,cycleToken) PRIMITIVE(tensionSpecifier,TensionSpecifier,tensionSpecifier) PRIMITIVE(curlSpecifier,CurlSpecifier,curlSpecifier) PRIMITIVE(pen,Pen,pen) PRIMITIVE(picture,Picture,frame) PRIMITIVE(file,File,file) PRIMITIVE(code,Code,code) asymptote-2.37/process.cc000066400000000000000000000601171265434602500154730ustar00rootroot00000000000000/***** * process.cc * Andy Hammerlindl 2006/08/19 * * Handles processing blocks of code (including files, strings, and the * interactive prompt, for listing and parse-only modes as well as actually * running it. *****/ #include "types.h" #include "errormsg.h" #include "genv.h" #include "stm.h" #include "settings.h" #include "vm.h" #include "program.h" #include "interact.h" #include "envcompleter.h" #include "parser.h" #include "fileio.h" #include "stack.h" #include "runtime.h" #include "texfile.h" #include "process.h" namespace camp { pen& defaultpen() { return processData().defaultpen; } } namespace run { void cleanup(); void exitFunction(vm::stack *Stack); void updateFunction(vm::stack *Stack); void purge(Int divisor=0); } namespace vm { bool indebugger; } using namespace settings; using absyntax::file; using trans::genv; using trans::coenv; using trans::env; using trans::coder; using types::record; using interact::interactive; using interact::uptodate; using absyntax::runnable; using absyntax::block; mem::stack processDataStack; // Exception-safe way to push and pop the process data. class withProcessData { // Do not let this object be dynamically allocated. void *operator new(size_t); processDataStruct *pd_ptr; public: withProcessData(processDataStruct *pd_ptr) : pd_ptr(pd_ptr) { processDataStack.push(pd_ptr); } ~withProcessData() { assert(processDataStack.top() == pd_ptr); processDataStack.pop(); } }; processDataStruct &processData() { assert(!processDataStack.empty()); return *processDataStack.top(); } // A process environment. Basically this just serves as short-hand to start a // new global environment (genv) and new process data at the same time. When // it goes out of scope, the process data is popped off the stack. This also // ensures that the data is popped even if an exception is thrown. class penv { genv *_ge; processDataStruct _pd; // Do not let this object be dynamically allocated. void *operator new(size_t); public: penv() : _ge(0), _pd() { // Push the processData first, as it needs to be on the stack before genv // is initialized. processDataStack.push(&_pd); _ge = new genv; } virtual ~penv() { processDataStack.pop(); delete _ge; } genv &ge() { return *_ge; } processDataStruct *pd() { return &_pd; } }; void init(bool resetpath=true) { vm::indebugger=false; uptodate=false; if(resetpath) setPath(""); /* On second and subsequent calls, sets the path to what it was when the program started. */ } // This helper class does nothing but call the interactiveTrans method of the // base object in place of trans, so that the runnable can exhibit special // behaviour when run at the interactive prompt. class interactiveRunnable : public runnable { runnable *base; public: interactiveRunnable(runnable *base) : runnable(base->getPos()), base(base) {} void prettyprint(ostream &out, Int indent) { absyntax::prettyname(out, "interactiveRunnable", indent); base->prettyprint(out, indent+1); } void trans(coenv &e) { base->interactiveTrans(e); } void transAsField(coenv &e, types::record *r) { // There is no interactiveTransAsField, as fields aren't declared at the top // level of the interactive prompt. base->transAsField(e, r); } }; enum transMode { TRANS_INTERACTIVE, TRANS_NORMAL }; // How to run a runnable in runnable-at-a-time mode. bool runRunnable(runnable *r, coenv &e, istack &s, transMode tm=TRANS_NORMAL) { e.e.beginScope(); lambda *codelet= tm==TRANS_INTERACTIVE ? interactiveRunnable(r).transAsCodelet(e) : r->transAsCodelet(e); em.sync(); if(!em.errors()) { if(getSetting("translate")) print(cout,codelet->code); s.run(codelet); // Commits the changes made to the environment. e.e.collapseScope(); } else { e.e.endScope(); // Remove any changes to the environment. // Should an interactive error hurt the status? em.statusError(); return false; } return true; } void runAutoplain(coenv &e, istack &s) { absyntax::runnable *r=absyntax::autoplainRunnable(); runRunnable(r,e,s); } // Abstract base class for the core object being run in line-at-a-time mode, it // may be a block of code, file, or interactive prompt. struct icore { virtual ~icore() {} virtual void doParse() = 0; virtual void doList() = 0; public: // preRun and postRun are the optional activities that take place before and // after running the code specified. They can be overridden by a derived // class that wishes different behaviour. virtual void preRun(coenv &e, istack &s) { if(getSetting("autoplain")) runAutoplain(e,s); } virtual void run(coenv &e, istack &s, transMode tm=TRANS_NORMAL) = 0; virtual void postRun(coenv &, istack &s) { run::exitFunction(&s); } virtual void doRun(bool purge=false, transMode tm=TRANS_NORMAL) { em.sync(); if(em.errors()) return; try { if(purge) run::purge(); penv pe; env base_env(pe.ge()); coder base_coder(nullPos, "icore::doRun"); coenv e(base_coder,base_env); vm::interactiveStack s; s.setInitMap(pe.ge().getInitMap()); s.setEnvironment(&e); preRun(e,s); if(purge) run::purge(); // Now that everything is set up, run the core. run(e,s,tm); postRun(e,s); } catch(std::bad_alloc&) { outOfMemory(); } catch(quit) { // Exception to quit running the current code. Nothing more to do. } catch(handled_error) { em.statusError(); } run::cleanup(); em.clear(); } virtual void process(bool purge=false) { if (!interactive && getSetting("parseonly")) doParse(); else if (getSetting("listvariables")) doList(); else doRun(purge); } }; // Abstract base class for one-time processing of an abstract syntax tree. class itree : public icore { string name; block *cachedTree; public: itree(string name="") : name(name), cachedTree(0) {} // Build the tree, possibly throwing a handled_error if it cannot be built. virtual block *buildTree() = 0; virtual block *getTree() { if (cachedTree==0) { try { cachedTree=buildTree(); } catch(handled_error) { em.statusError(); return 0; } } return cachedTree; } virtual string getName() { return name; } void doParse() { block *tree=getTree(); em.sync(); if(tree && !em.errors()) tree->prettyprint(cout, 0); } void doList() { block *tree=getTree(); if (tree) { penv pe; record *r=tree->transAsFile(pe.ge(), symbol::trans(getName())); r->e.list(r); } } void run(coenv &e, istack &s, transMode tm=TRANS_NORMAL) { block *tree=getTree(); if (tree) { for(mem::list::iterator r=tree->stms.begin(); r != tree->stms.end(); ++r) if(!em.errors() || getSetting("debug")) runRunnable(*r,e,s,tm); } } void doExec(transMode tm=TRANS_NORMAL) { // Don't prepare an environment to run the code if there isn't any code. if (getTree()) icore::doRun(false,tm); } }; class icode : public itree { block *tree; public: icode(block *tree, string name="") : itree(name), tree(tree) {} block *buildTree() { return tree; } }; class istring : public itree { string str; public: istring(const string& str, string name="") : itree(name), str(str) {} block *buildTree() { return parser::parseString(str, getName()); } }; void printGreeting(bool interactive) { if(!getSetting("quiet")) { cout << "Welcome to " << PROGRAM << " version " << REVISION; if(interactive) cout << " (to view the manual, type help)"; cout << endl; } } class ifile : public itree { string filename; string outname; string outname_save; public: ifile(const string& filename) : itree(filename), filename(filename), outname((string) (filename == "-" ? settings::outname() : stripDir(stripExt(string(filename), suffix)))) {} block *buildTree() { return !filename.empty() ? parser::parseFile(filename,"Loading") : 0; } void preRun(coenv& e, istack& s) { outname_save=getSetting("outname"); if(stripDir(outname_save).empty()) Setting("outname")=outname_save+outname; itree::preRun(e, s); } void postRun(coenv &e, istack& s) { itree::postRun(e, s); Setting("outname")=outname_save; } void process(bool purge=false) { if(verbose > 1) printGreeting(false); try { init(); } catch(handled_error) { } if (verbose >= 1) cout << "Processing " << outname << endl; try { icore::process(purge); } catch(handled_error) { em.statusError(); } } }; // Add a semi-colon terminator, if one is not there. string terminateLine(const string line) { return (!line.empty() && *(line.rbegin())!=';') ? (line+";") : line; } // cleanLine changes a C++ style comment (//) into a C-style comment (/* */) so // that comments don't absorb subsequent lines of code when multiline input is // collapsed to a single line in the history. // // ex. if (x==1) // test x // x=2; // becomes // if (x==1) /* test x */ x=2 (all on one line) // // cleanLine is a mess because we have to check that the // is not in a string // or c-style comment, which entails re-inventing much of the lexer. The // routine handles most cases, but multiline strings lose their newlines when // recorded in the history. typedef string::size_type size_type; const size_type npos=string::npos; inline size_type min(size_type a, size_type b) { return a < b ? a : b; } // If start is an offset somewhere within a string, this returns the first // offset outside of the string. sym is the character used to start the string, // ' or ". size_type endOfString(const char sym, const string line, size_type start) { size_type endString=line.find(sym, start); if (endString == npos) return npos; size_type escapeInString=min(line.find(string("\\")+sym, start), line.find("\\\\", start)); if (endString < escapeInString) return endString+1; else return endOfString(sym, line, escapeInString+2); } // If start is an offset somewhere within a C-style comment, this returns the // first offset outside of the comment. size_type endOfComment(const string line, size_type start) { size_type endComment=line.find("*/", start); if (endComment == npos) return npos; else return endComment+2; } // Find the start of a string literal in the line. size_type stringPos(const string line, size_type start) { if (start == npos) return npos; size_type pos=line.find_first_of("\'\"", start); if (pos == npos) return npos; // Skip over comments /* */ and ignore anything after // size_type startComment=line.find("/*", start); size_type startLineComment=line.find("//", start); if (min(startComment,startLineComment) < pos) return stringPos(line, startComment < startLineComment ? endOfComment(line, startComment+2) : npos); else // Nothing to skip over - the symbol actually starts a string. return pos; } // A multiline string should retain its newlines when collapsed to a single // line. This converts // 'hello // there' // to // 'hello\nthere' // and // "hello // there" // to // "hello" '\n' "there" // If the line doesn't end mid-string, this adds a space to the end to preserve // whitespace, since it is the last function to touch the line. string endString(const string line, size_type start) { assert(start!=npos); size_type pos=stringPos(line, start); if (pos==npos) // String ends in normal code. return line+" "; else { char sym=line[pos]; size_type eos=endOfString(sym, line, pos+1); if (eos==npos) { // Line ends while in a string, attach a newline symbol. switch (line[pos]) { case '\'': return line+"\\n"; case '\"': return line+"\" \'\\n\' \""; default: assert(False); return line; } } else { return endString(line, eos+1); } } } // Find the first // that isn't in a C-style comment or a string. size_type slashPos(const string line, size_type start) { if (start == npos) return npos; size_type pos=line.find("//", start); if (pos == npos) return npos; // Skip over comments /* */ and strings both " " and ' ' size_type startComment=line.find("/*", start); size_type startString=line.find_first_of("\'\"", start); if (min(startComment,startString) < pos) return slashPos(line, startComment < startString ? endOfComment(line, startComment+2) : endOfString(line[startString], line, startString+1)); else // Nothing to skip over - the // actually starts a comment. return pos; } string endCommentOrString(const string line) { size_type pos=slashPos(line, 0); if (pos == npos) return endString(line, 0); else { string sub=line; // Replace the first // by /* sub[pos+1]='*'; // Replace any */ in the comment by *! while ((pos = line.find("*/", pos+2)) != npos) sub[pos+1]='!'; // Tack on a */ at the end. sub.append(" */ "); return sub; } } bool isSlashed(const string line) { // NOTE: This doesn't fully handle escaped slashed in a string literal. return line[line.size()-1]=='\\'; } string deslash(const string line) { return isSlashed(line) ? line.substr(0,line.size()-1) : line; } // This transforms a line in to the history, so that when more code is added // after it, the code behaves the same as if there was a newline between the // two lines. This involves changing // style comments to /* */ style comments, // and adding explicit newlines to multiline strings. string cleanLine(const string line) { // First remove a trailing slash, if there is one. return endCommentOrString(deslash(line)); } class iprompt : public icore { // Flag that is set to false to signal the prompt to exit. bool running; // Flag that is set to restart the main loop once it has exited. bool restart; // Code ran at start-up. string startline; void postRun(coenv &, istack &) { } // Commands are chopped into the starting word and the rest of the line. struct commandLine { string line; string word; string rest; commandLine(string line) : line(line) { string::iterator c=line.begin(); // Skip leading whitespace while (c != line.end() && isspace(*c)) ++c; // Only handle identifiers starting with a letter. if (c != line.end() && isalpha(*c)) { // Store the command name. while (c != line.end() && (isalnum(*c) || *c=='_')) { word.push_back(*c); ++c; } } // Copy the rest to rest. while (c != line.end()) { rest.push_back(*c); ++c; } #if 0 cerr << "line: " << line << endl; cerr << "word: " << word << endl; cerr << "rest: " << rest << endl; cerr << "simple: " << simple() << endl; #endif } // Simple commands have at most spaces or semicolons after the command word. bool simple() { for (string::iterator c=rest.begin(); c != rest.end(); ++c) if (!isspace(*c) && *c != ';') return false; return true; } }; // The interactive prompt has special functions that cannot be implemented as // normal functions. These special funtions take a commandLine as an argument // and return true if they can handle the command. If false is returned, the // line is treated as a normal line of code. // commands is a map of command names to methods which implement the commands. typedef bool (iprompt::*command)(coenv &, istack &, commandLine); typedef mem::map commandMap; commandMap commands; bool exit(coenv &, istack &, commandLine cl) { if (cl.simple()) { // Don't store exit commands in the history file. interact::deleteLastLine(); running=false; return true; } else return false; } bool q(coenv &e, istack &s, commandLine cl) { if(e.e.ve.getType(symbol::trans("q"))) return false; return exit(e,s,cl); } bool reset(coenv &, istack &, commandLine cl) { if (cl.simple()) { running=false; restart=true; startline=""; run::purge(); return true; } else return false; } bool help(coenv &, istack &, commandLine cl) { if (cl.simple()) { popupHelp(); return true; } else return false; } bool erase(coenv &e, istack &s, commandLine cl) { if (cl.simple()) { runLine(e,s,"erase();"); return true; } else return false; } bool input(coenv &, istack &, commandLine cl) { running=false; restart=true; startline="include "+cl.rest; return true; } void initCommands() { #define ADDCOMMAND(name, func) \ commands[#name]=&iprompt::func // keywords.pl looks for ADDCOMMAND to identify special commands in the // auto-completion. ADDCOMMAND(quit,exit); ADDCOMMAND(q,q); ADDCOMMAND(exit,exit); ADDCOMMAND(reset,reset); ADDCOMMAND(erase,erase); ADDCOMMAND(help,help); ADDCOMMAND(input,input); #undef ADDCOMMAND } bool handleCommand(coenv &e, istack &s, string line) { commandLine cl(line); if (cl.word != "") { commandMap::iterator p=commands.find(cl.word); if (p != commands.end()) { // Execute the command. command &com=p->second; return (this->*com)(e,s,cl); } else return false; } else return false; } void addToHistory(string line) { interact::addToHistory(line); } void addToLastLine(string line) { // Here we clean a line at the last possible point, when we know that more // code is going to be appended to it. string last=interact::getLastHistoryLine(); interact::setLastHistoryLine(cleanLine(last)+line); } void terminateLastHistoryLine() { string last=interact::getLastHistoryLine(); interact::setLastHistoryLine(terminateLine(last)); } // Get input from the interactive prompt. Such input may be over several // user-typed lines if he/she ends a line a with backslash to continue input // on the next line. If continuation is true, the input started on a previous // line and is being continued (either because of a backslash or the parser // detecting it in multiline mode). string getline(bool continuation) { string prompt=getSetting(continuation ? "prompt2" : "prompt"); string line=interact::simpleline(prompt); if (continuation) addToLastLine(line); else addToHistory(line); // If the line ends in a slash, get more input. return isSlashed(line) ? line+"\n"+getline(true) : line; } // Continue taking input for a line until it properly parses, or a syntax // error occurs. Returns the parsed code on success, and throws a // handled_error exception on failure. block *parseExtendableLine(string line) { block *code=parser::parseString(line, "-", true); if (code) { return code; } else { string nextline=getline(true); return parseExtendableLine(line+"\n"+nextline); } } void runLine(coenv &e, istack &s, string line) { try { if (getSetting("multiline")) { block *code=parseExtendableLine(line); icode i(code); i.run(e,s,TRANS_INTERACTIVE); } else { // Add a semi-colon to the end of the line if one is not there. Do this // to the history as well, so the transcript can be run as regular asy // code. This also makes the history work correctly if the multiline // setting is changed within an interactive session. // It is added to the history at the last possible moment to avoid // tampering with other features, such as using a slash to extend a // line. terminateLastHistoryLine(); istring i(terminateLine(line), "-"); i.run(e,s,TRANS_INTERACTIVE); } run::updateFunction(&s); uptodate=false; } catch(handled_error) { vm::indebugger=false; } catch(interrupted&) { // Turn off the interrupted flag. em.Interrupt(false); uptodate=true; cout << endl; } catch(quit&) { } // Ignore errors from this line when trying to run subsequent lines. em.clear(); } void runStartCode(coenv &e, istack &s) { if (!startline.empty()) runLine(e, s, startline); } public: iprompt() : running(false), restart(false), startline("") { initCommands(); } void doParse() {} void doList() {} void run(coenv &e, istack &s, transMode=TRANS_NORMAL) { running=true; interact::setCompleter(new trans::envCompleter(e.e)); runStartCode(e, s); while (running) { // Read a line from the prompt. string line=getline(false); // Check if it is a special command. if (handleCommand(e,s,line)) continue; else runLine(e, s, line); } } void process(bool purge=false) { printGreeting(true); interact::init_interactive(); try { setPath("",true); } catch(handled_error) { } do { try { init(false); restart=false; icore::process(); } catch(interrupted&) { em.Interrupt(false); restart=true; } catch(eof&) { restart=false; } } while(restart); interact::cleanup_interactive(); } }; void processCode(absyntax::block *code) { icode(code).process(); } void processFile(const string& filename, bool purge) { ifile(filename).process(purge); } void processPrompt() { iprompt().process(); } void runCode(absyntax::block *code) { icode(code).doExec(); } void runString(const string& s, bool interactiveWrite) { istring(s).doExec(interactiveWrite ? TRANS_INTERACTIVE : TRANS_NORMAL); } void runFile(const string& filename) { ifile(filename).doExec(); } void runPrompt() { iprompt().doRun(); } void runCodeEmbedded(absyntax::block *code, trans::coenv &e, istack &s) { icode(code).run(e,s); } void runStringEmbedded(const string& str, trans::coenv &e, istack &s) { istring(str).run(e,s); } void runPromptEmbedded(trans::coenv &e, istack &s) { iprompt().run(e,s); } void doUnrestrictedList() { penv pe; env base_env(pe.ge()); coder base_coder(nullPos, "doUnrestictedList"); coenv e(base_coder,base_env); if (getSetting("autoplain")) absyntax::autoplainRunnable()->trans(e); e.e.list(0); } // Environment class used by external programs linking to the shared library. class fullenv : public gc { penv pe; env base_env; coder base_coder; coenv e; vm::interactiveStack s; public: fullenv() : pe(), base_env(pe.ge()), base_coder(nullPos, "fullenv"), e(base_coder, base_env), s() { s.setInitMap(pe.ge().getInitMap()); s.setEnvironment(&e); // TODO: Add way to not run autoplain. runAutoplain(e, s); } coenv &getCoenv() { return e; } void runRunnable(runnable *r) { assert(!em.errors()); // TODO: Decide how to handle prior errors. try { { withProcessData token(pe.pd()); ::runRunnable(r, e, s, TRANS_INTERACTIVE); } } catch(std::bad_alloc&) { // TODO: give calling application useful message. cerr << "out of memory" << endl; } catch (quit) { // I'm not sure whether this counts as successfully running the code or // not. cerr << "quit exception" << endl; } catch (handled_error) { // Normally, this is the result of an error that changes the return code // of the free-standing asymptote program. // An error should probably be reported to the application calling the // asymptote library. cerr << "handled error" << endl; } em.clear(); } }; fullenv &getFullEnv() { static fullenv fe; return fe; } coenv &coenvInOngoingProcess() { return getFullEnv().getCoenv(); } void runInOngoingProcess(runnable *r) { getFullEnv().runRunnable(r); } asymptote-2.37/process.h000066400000000000000000000051721265434602500153350ustar00rootroot00000000000000/***** * process.h * Andy Hammerlindl 2006/08/19 * * Handles processing blocks of code (including files, strings, and the * interactive prompt, for listing and parse-only modes as well as actually * running it. *****/ #ifndef PROCESS_H #define PROCESS_H #include "common.h" #include "stm.h" #include "stack.h" #include "pipestream.h" #include "callable.h" #include "pen.h" #ifdef HAVE_RPC_RPC_H #include "xstream.h" #endif // Process the code respecting the parseonly and listvariables flags of // settings. void processCode(absyntax::block *code); void processFile(const string& filename, bool purge=false); void processPrompt(); // Run the code in its own environment. void runCode(absyntax::block *code); void runString(const string& s, bool interactiveWrite=false); void runFile(const string& filename); void runPrompt(); // Run the code in a given run-time environment. typedef vm::interactiveStack istack; void runCodeEmbedded(absyntax::block *code, trans::coenv &e, istack &s); void runStringEmbedded(const string& str, trans::coenv &e, istack &s); void runPromptEmbedded(trans::coenv &e, istack &s); // Basic listing. void doUnrestrictedList(); template class terminator { public: typedef mem::vector Pointer; Pointer pointer; // Return first available index size_t available() { size_t index=0; for(typename Pointer::iterator p=pointer.begin(); p != pointer.end(); ++p) { if(*p == NULL) {return index;} ++index; } pointer.push_back(NULL); return index; } size_t add(T *p) { size_t index=available(); pointer[index]=p; return index; } void remove(size_t index) { pointer[index]=NULL; } ~terminator() { for(typename Pointer::iterator p=pointer.begin(); p != pointer.end(); ++p) { if(*p != NULL) { (*p)->~T(); (*p)=NULL; } } } }; class texstream : public iopipestream { public: ~texstream(); }; struct processDataStruct { texstream tex; // Bi-directional pipe to latex (to find label bbox) mem::list TeXpipepreamble; mem::list TeXpreamble; vm::callable *atExitFunction; vm::callable *atUpdateFunction; vm::callable *atBreakpointFunction; camp::pen defaultpen; camp::pen currentpen; terminator ofile; terminator ifile; #ifdef HAVE_RPC_RPC_H terminator ixfile; terminator oxfile; #endif processDataStruct() { atExitFunction=NULL; atUpdateFunction=NULL; atBreakpointFunction=NULL; defaultpen=camp::pen::initialpen(); currentpen=camp::pen(); } }; processDataStruct &processData(); #endif asymptote-2.37/profile.py000066400000000000000000000044431265434602500155200ustar00rootroot00000000000000import sys from pprint import pprint # Unused line numbers required by kcachegrind. POS = '1' def nameFromNode(tree): name = tree['name'] pos = tree['pos'] if pos.endswith(": "): pos = pos[:-2] return (name, pos) def addFuncNames(tree, s): s.add(nameFromNode(tree)) for child in tree['children']: addFuncNames(child, s) def funcNames(tree): s = set() addFuncNames(tree, s) return s def computeTotals(tree): for child in tree['children']: computeTotals(child) tree['instTotal'] = (tree['instructions'] + sum(child['instTotal'] for child in tree['children'])) tree['nsecsTotal'] = (tree['nsecs'] + sum(child['nsecsTotal'] for child in tree['children'])) def printName(name, prefix=''): print prefix+"fl=", name[1] print prefix+"fn=", name[0] class Arc: def __init__(self): self.calls = 0 self.instTotal = 0 self.nsecsTotal = 0 def add(self, tree): self.calls += tree['calls'] self.instTotal += tree['instTotal'] self.nsecsTotal += tree['nsecsTotal'] class Func: def __init__(self): self.instructions = 0 self.nsecs = 0 self.arcs = {} def addChildTime(self, tree): arc = self.arcs.setdefault(nameFromNode(tree), Arc()) arc.add(tree) def analyse(self, tree): self.instructions += tree['instructions'] self.nsecs += tree['nsecs'] for child in tree['children']: self.addChildTime(child) def dump(self): print POS, self.instructions, self.nsecs for name in self.arcs: printName(name, prefix='c') arc = self.arcs[name] print "calls="+str(arc.calls), POS print POS, arc.instTotal, arc.nsecsTotal print def analyse(funcs, tree): funcs[nameFromNode(tree)].analyse(tree) for child in tree['children']: analyse(funcs, child) def dump(funcs): print "events: Instructions Nanoseconds" for name in funcs: printName(name) funcs[name].dump() rawdata = __import__("asyprof") profile = rawdata.profile computeTotals(profile) names = funcNames(profile) funcs = {} for name in names: funcs[name] = Func() analyse(funcs, profile) dump(funcs) #pprint(names) asymptote-2.37/profiler.h000066400000000000000000000232441265434602500155010ustar00rootroot00000000000000/***** * profiler.h * Andy Hammerlindl 2010/07/24 * * Profiler for the execution of the virtual machine bytecode. *****/ #ifndef PROFILER_H #define PROFILER_H #include #include #include "inst.h" namespace vm { #ifdef DEBUG_BLTIN string lookupBltin(bltin b); #endif inline position positionFromLambda(lambda *func) { if (func == 0) return position(); program& code = *func->code; // Check for empty program. if (code.begin() == code.end()) return position(); return code.begin()->pos; } inline void printNameFromLambda(ostream& out, lambda *func) { if (!func) { out << ""; return; } #ifdef DEBUG_FRAME string name = func->name; #else string name = ""; #endif // If unnamed, use the pointer address. if (name.empty()) out << func; else out << name; out << " at "; positionFromLambda(func).printTerse(out); } inline void printNameFromBltin(ostream& out, bltin b) { #ifdef DEBUG_BLTIN string name = lookupBltin(b); #else string name = ""; #endif if (!name.empty()) out << name << " "; out << "(builtin at " << (void *)b << ")"; } class profiler : public gc { // To do call graph analysis, each call stack that occurs in practice is // represented by a node. For instance, if f and g are functions, then // f -> g -> g // is represented by a node and // g -> f -> g // is represented by a different one. struct node { // The top-level function of the call stack. It is either an asymptote // function with a given lambda, or a builtin function, with a given // bltin. lambda *func; bltin cfunc; // The number of times the top-level function has been called resulting in // this specific call stack. int calls; // The number of bytecode instructions executed with this exact call stack. // It does not include time spent in called function. int instructions; // Number of instructions spent in this function or its children. This is // computed by computeTotals. int instTotal; // The number of real-time nanoseconds spent in this node. WARNING: May // be wildly inaccurate. long long nsecs; // Total including children. long long nsecsTotal; // Call stacks resulting from calls during this call stack. mem::vector children; node() : func(0), cfunc(0), calls(0), instructions(0), instTotal(0), nsecs(0), nsecsTotal(0) {} node(lambda *func) : func(func), cfunc(0), calls(0), instructions(0), instTotal(0), nsecs(0), nsecsTotal(0) {} node(bltin b) : func(0), cfunc(b), calls(0), instructions(0), instTotal(0), nsecs(0), nsecsTotal(0) {} // Return the call stack resulting from a call to func when this call // stack is current. node *getChild(lambda *func) { size_t n = children.size(); for (size_t i = 0; i < n; ++i) if (children[i].func == func) return &children[i]; // Not found, create a new one. children.push_back(node(func)); return &children.back(); } node *getChild(bltin func) { size_t n = children.size(); for (size_t i = 0; i < n; ++i) if (children[i].cfunc == func) return &children[i]; // Not found, create a new one. children.push_back(node(func)); return &children.back(); } void computeTotals() { instTotal = instructions; nsecsTotal = nsecs; size_t n = children.size(); for (size_t i = 0; i < n; ++i) { children[i].computeTotals(); instTotal += children[i].instTotal; nsecsTotal += children[i].nsecsTotal; } } void pydump(ostream& out) { #ifdef DEBUG_FRAME string name = func ? func->name : ""; #else string name = ""; #endif out << "dict(\n" << " name = '" << name << " " << func << "',\n" << " pos = '" << positionFromLambda(func) << "',\n" << " calls = " << calls << ",\n" << " instructions = " << instructions << ",\n" << " nsecs = " << nsecs << ",\n" << " children = [\n"; size_t n = children.size(); for (size_t i = 0; i < n; ++i) { children[i].pydump(out); out << ",\n"; } out << " ])\n"; } }; // An empty call stack. node emptynode; // All of the callstacks. std::stack callstack; node &topnode() { return *callstack.top(); } // Arc representing one function calling another. Used only for building // the output for kcachegrind. struct arc : public gc { int calls; int instTotal; long long nsecsTotal; arc() : calls(0), instTotal(0), nsecsTotal(0) {} void add(node& n) { calls += n.calls; instTotal += n.instTotal; nsecsTotal += n.nsecsTotal; } }; // Representing one function and its calls to other functions. struct fun : public gc { int instructions; long long nsecs; mem::map arcs; mem::map carcs; fun() : instructions(0), nsecs(0) {} void addChildTime(node& n) { if (n.cfunc) carcs[n.cfunc].add(n); else arcs[n.func].add(n); } void analyse(node& n) { instructions += n.instructions; nsecs += n.nsecs; size_t numChildren = n.children.size(); for (size_t i = 0; i < numChildren; ++i) addChildTime(n.children[i]); } void dump(ostream& out) { // The unused line number needed by kcachegrind. static const string POS = "1"; out << POS << " " << instructions << " " << nsecs << "\n"; for (mem::map::iterator i = arcs.begin(); i != arcs.end(); ++i) { lambda *l = i->first; arc& a = i->second; out << "cfl=" << positionFromLambda(l) << "\n"; out << "cfn="; printNameFromLambda(out, l); out << "\n"; out << "calls=" << a.calls << " " << POS << "\n"; out << POS << " " << a.instTotal << " " << a.nsecsTotal << "\n"; } for (mem::map::iterator i = carcs.begin(); i != carcs.end(); ++i) { bltin b = i->first; arc& a = i->second; out << "cfl=C++ code" << endl; out << "cfn="; printNameFromBltin(out, b); out << "\n"; out << "calls=" << a.calls << " " << POS << "\n"; out << POS << " " << a.instTotal << " " << a.nsecsTotal << "\n"; } } }; // The data for each asymptote function. mem::map funs; // The data for each C++ function. mem::map cfuns; void analyseNode(node& n) { fun& f = n.cfunc ? cfuns[n.cfunc] : funs[n.func]; f.analyse(n); size_t numChildren = n.children.size(); for (size_t i = 0; i < numChildren; ++i) analyseNode(n.children[i]); } // Convert data in the tree of callstack nodes into data for each function. void analyseData() { emptynode.computeTotals(); analyseNode(emptynode); } // Timing data. struct timeval timestamp; void startLap() { gettimeofday(×tamp, 0); } long long timeAndResetLap() { struct timeval now; gettimeofday(&now, 0); long long nsecs = 1000000000LL * (now.tv_sec - timestamp.tv_sec) + 1000LL * (now.tv_usec - timestamp.tv_usec); timestamp = now; return nsecs; } // Called whenever the stack is about to change, in order to record the time // duration for the current node. void recordTime() { topnode().nsecs += timeAndResetLap(); } public: profiler(); void beginFunction(lambda *func); void endFunction(lambda *func); void beginFunction(bltin func); void endFunction(bltin func); void recordInstruction(); // TODO: Add position, type of instruction info to profiling. // Dump all of the data out in a format that can be read into Python. void pydump(ostream &out); // Dump all of the data in a format for kcachegrind. void dump(ostream& out); }; inline profiler::profiler() : emptynode() { callstack.push(&emptynode); startLap(); } inline void profiler::beginFunction(lambda *func) { assert(func); assert(!callstack.empty()); recordTime(); callstack.push(topnode().getChild(func)); ++topnode().calls; } inline void profiler::endFunction(lambda *func) { assert(func); assert(!callstack.empty()); assert(topnode().func == func); recordTime(); callstack.pop(); } inline void profiler::beginFunction(bltin cfunc) { assert(cfunc); assert(!callstack.empty()); recordTime(); callstack.push(topnode().getChild(cfunc)); ++topnode().calls; } inline void profiler::endFunction(bltin cfunc) { assert(cfunc); assert(!callstack.empty()); assert(topnode().cfunc == cfunc); recordTime(); callstack.pop(); } inline void profiler::recordInstruction() { assert(!callstack.empty()); ++topnode().instructions; } inline void profiler::pydump(ostream& out) { out << "profile = "; emptynode.pydump(out); } inline void profiler::dump(ostream& out) { analyseData(); out << "events: Instructions Nanoseconds\n"; for (mem::map::iterator i = funs.begin(); i != funs.end(); ++i) { lambda *l = i->first; fun& f = i->second; out << "fl=" << positionFromLambda(l) << "\n"; out << "fn="; printNameFromLambda(out, l); out << "\n"; f.dump(out); } for (mem::map::iterator i = cfuns.begin(); i != cfuns.end(); ++i) { bltin b = i->first; fun& f = i->second; out << "fl=C++ code\n"; out << "fn="; printNameFromBltin(out, b); out << "\n"; f.dump(out); } } } // namespace vm #endif // PROFILER_H asymptote-2.37/program.cc000066400000000000000000000063131265434602500154620ustar00rootroot00000000000000/***** * program.cc * Tom Prince * * The list of instructions used by the virtual machine. *****/ #include #include "util.h" #include "callable.h" #include "program.h" namespace vm { static const char* opnames[] = { #define OPCODE(name, type) #name, #include "opcodes.h" #undef OPCODE }; static const Int numOps = (Int)(sizeof(opnames)/sizeof(char *)); static const char optypes[] = { #define OPCODE(name, type) type, #include "opcodes.h" #undef OPCODE }; #ifdef DEBUG_BLTIN mem::map bltinRegistry; void registerBltin(bltin b, string s) { bltinRegistry[b] = s; } string lookupBltin(bltin b) { return bltinRegistry[b]; } #endif ostream& operator<< (ostream& out, const item& i) { if (i.empty()) return out << "empty"; if (isdefault(i)) return out << "default"; #if COMPACT // TODO: Try to guess the type from the value. Int n = get(i); double x = get(i); void *p = get(i); if (n == BoolTruthValue) return out << "true"; if (n == BoolFalseValue) return out << "false"; if (std::abs(n) < 1000000) return out << n; if (fabs(x) < 1e30 and fabs(x) > 1e-30) return out << x; return out << ""; #else // TODO: Make a data structure mapping typeids to print functions. else if (i.type() == typeid(Int)) out << "Int, value = " << get(i); else if (i.type() == typeid(double)) out << "real, value = " << get(i); else if (i.type() == typeid(string)) out << "string, value = " << get(i); else if (i.type() == typeid(callable)) out << *(get(i)); else if (i.type() == typeid(frame)) { out << "frame"; # ifdef DEBUG_FRAME { frame *f = get(i); if (f) out << " " << f->getName(); else out << " "; } # endif } else out << "type " << demangle(i.type().name()); #endif return out; } void printInst(ostream& out, const program::label& code, const program::label& base) { out.width(4); out << offset(base,code) << " "; Int i = (Int)code->op; if (i < 0 || i >= numOps) { out << "<>" << i; return; } out << opnames[i]; switch (optypes[i]) { case 'n': { out << " " << get(*code); break; } case 't': { item c = code->ref; out << " " << c; break; } case 'b': { #ifdef DEBUG_BLTIN string s=lookupBltin(get(*code)); out << " " << (!s.empty() ? s : "") << " "; #endif break; } case 'o': { char f = out.fill('0'); out << " i"; out.width(4); out << offset(base,get(*code)); out.fill(f); break; } case 'l': { #ifdef DEBUG_FRAME out << " " << get(*code)->name << " "; #endif break; } default: { /* nothing else to do */ break; } }; } void print(ostream& out, program *base) { program::label code = base->begin(); bool active = true; while (active) { if (code->op == inst::ret || code->op < 0 || code->op >= numOps) active = false; printInst(out, code, base->begin()); out << '\n'; ++code; } } } // namespace vm asymptote-2.37/program.h000066400000000000000000000050021265434602500153160ustar00rootroot00000000000000/***** * program.h * Tom Prince * * The list of instructions used by the virtual machine. *****/ #ifndef PROGRAM_H #define PROGRAM_H #include // for ptrdiff_t #include "common.h" #include "inst.h" using std::ptrdiff_t; namespace vm { struct inst; class program : public gc { public: class label; program(); void encode(inst i); label begin(); label end(); inst &back(); void pop_back(); private: friend class label; typedef mem::vector code_t; code_t code; inst& operator[](size_t); }; class program::label { public: // interface label() : where(0), code() {} public: //interface label& operator++(); label& operator--(); bool defined() const; bool operator==(const label& right) const; bool operator!=(const label& right) const; inst& operator*() const; inst* operator->() const; friend ptrdiff_t offset(const label& left, const label& right); private: label (size_t where, program* code) : where(where), code(code) {} size_t where; program* code; friend class program; }; // Prints one instruction (including arguments). void printInst(std::ostream& out, const program::label& code, const program::label& base); // Prints code until a ret opcode is printed. void print(std::ostream& out, program *base); // Inline forwarding functions for vm::program inline program::program() : code() {} inline program::label program::end() { return label(code.size(), this); } inline program::label program::begin() { return label(0, this); } inline inst& program::back() { return code.back(); } inline void program::pop_back() { return code.pop_back(); } inline void program::encode(inst i) { code.push_back(i); } inline inst& program::operator[](size_t n) { return code[n]; } inline program::label& program::label::operator++() { ++where; return *this; } inline program::label& program::label::operator--() { --where; return *this; } inline bool program::label::defined() const { return (code != 0); } inline bool program::label::operator==(const label& right) const { return (code == right.code) && (where == right.where); } inline bool program::label::operator!=(const label& right) const { return !(*this == right); } inline inst& program::label::operator*() const { return (*code)[where]; } inline inst* program::label::operator->() const { return &**this; } inline ptrdiff_t offset(const program::label& left, const program::label& right) { return right.where - left.where; } } // namespace vm #endif // PROGRAM_H asymptote-2.37/psfile.cc000066400000000000000000000447461265434602500153110ustar00rootroot00000000000000/***** * psfile.cc * Andy Hammerlindl 2002/06/10 * * Encapsulates the writing of commands to a PostScript file. * Allows identification and removal of redundant commands. *****/ #include #include #include #include #include "psfile.h" #include "settings.h" #include "errormsg.h" #include "array.h" #include "stack.h" using std::ofstream; using std::setw; using vm::array; using vm::read; using vm::stack; using vm::callable; using vm::pop; namespace camp { void checkColorSpace(ColorSpace colorspace) { switch(colorspace) { case DEFCOLOR: case INVISIBLE: reportError("Cannot shade with invisible pen"); case PATTERN: reportError("Cannot shade with pattern"); break; default: break; } } psfile::psfile(const string& filename, bool pdfformat) : filename(filename), pdfformat(pdfformat), pdf(false), transparency(false), buffer(NULL), out(NULL) { if(filename.empty()) out=&cout; else out=new ofstream(filename.c_str()); out->setf(std::ios::boolalpha); if(!out || !*out) reportError("Cannot write to "+filename); } static const char *inconsistent="inconsistent colorspaces"; static const char *rectangular="matrix is not rectangular"; void psfile::writefromRGB(unsigned char r, unsigned char g, unsigned char b, ColorSpace colorspace, size_t ncomponents) { static const double factor=1.0/255.0; pen p(r*factor,g*factor,b*factor); p.convert(); if(!p.promote(colorspace)) reportError(inconsistent); write(&p,ncomponents); } inline unsigned char average(unsigned char *a, size_t dx, size_t dy) { return ((unsigned) a[0]+(unsigned) a[dx]+(unsigned) a[dy]+ (unsigned) a[dx+dy])/4; } void psfile::dealias(unsigned char *a, size_t width, size_t height, size_t n, bool convertrgb, ColorSpace colorspace) { // Dealias all but the last row and column of pixels. size_t istop=width-1; size_t jstop=height-1; if(convertrgb) { size_t nwidth=3*width; for(size_t j=0; j < height; ++j) { unsigned char *aj=a+nwidth*j; for(size_t i=0; i < width; ++i) { unsigned char *ai=aj+3*i; if(i < istop && j < jstop) writefromRGB(average(ai,3,nwidth), average(ai+1,3,nwidth), average(ai+2,3,nwidth),colorspace,n); else writefromRGB(ai[0],ai[1],ai[2],colorspace,n); } } } else { size_t nwidth=n*width; for(size_t j=0; j < jstop; ++j) { unsigned char *aj=a+nwidth*j; for(size_t i=0; i < istop; ++i) { unsigned char *ai=aj+n*i; for(size_t k=0; k < n; ++k) ai[k]=average(ai+k,n,nwidth); } } } } void psfile::writeCompressed(const unsigned char *a, size_t size) { uLongf compressedSize=compressBound(size); Bytef *compressed=new Bytef[compressedSize]; if(compress(compressed,&compressedSize,a,size) != Z_OK) reportError("image compression failed"); encode85 e(out); for(size_t i=0; i < compressedSize; ++i) e.put(compressed[i]); } void psfile::close() { if(out) { out->flush(); if(!filename.empty()) { #ifdef __MSDOS__ chmod(filename.c_str(),~settings::mask & 0777); #endif if(!out->good()) // Don't call reportError since this may be called on handled_error. reportFatal("Cannot write to "+filename); delete out; out=NULL; } } } psfile::~psfile() { close(); } void psfile::header() { Int level=settings::getSetting("level"); *out << "%!PS-Adobe-" << level << ".0 EPSF-" << level << ".0" << newl; } void psfile::prologue(const bbox& box) { header(); BoundingBox(box); *out << "%%Creator: " << settings::PROGRAM << " " << settings::VERSION << REVISION << newl; time_t t; time(&t); struct tm *tt = localtime(&t); char prev = out->fill('0'); *out << "%%CreationDate: " << tt->tm_year + 1900 << "." << setw(2) << tt->tm_mon+1 << "." << setw(2) << tt->tm_mday << " " << setw(2) << tt->tm_hour << ":" << setw(2) << tt->tm_min << ":" << setw(2) << tt->tm_sec << newl; out->fill(prev); *out << "%%Pages: 1" << newl; *out << "%%Page: 1 1" << newl; if(!pdfformat) *out << "/Setlinewidth {0 exch dtransform dup abs 1 lt {pop 0}{round} ifelse" << newl << "idtransform setlinewidth pop} bind def" << newl; } void psfile::epilogue() { *out << "showpage" << newl; *out << "%%EOF" << newl; } void psfile::setcolor(const pen& p, const string& begin="", const string& end="") { if(p.cmyk() && (!lastpen.cmyk() || (p.cyan() != lastpen.cyan() || p.magenta() != lastpen.magenta() || p.yellow() != lastpen.yellow() || p.black() != lastpen.black()))) { *out << begin << p.cyan() << " " << p.magenta() << " " << p.yellow() << " " << p.black() << (pdf ? " k" : " setcmykcolor") << end << newl; } else if(p.rgb() && (!lastpen.rgb() || (p.red() != lastpen.red() || p.green() != lastpen.green() || p.blue() != lastpen.blue()))) { *out << begin << p.red() << " " << p.green() << " " << p.blue() << (pdf ? " rg" : " setrgbcolor") << end << newl; } else if(p.grayscale() && (!lastpen.grayscale() || p.gray() != lastpen.gray())) { *out << begin << p.gray() << (pdf ? " g" : " setgray") << end << newl; } } void psfile::setopacity(const pen& p) { if(p.blend() != lastpen.blend()) { *out << "/" << p.blend() << " .setblendmode" << newl; transparency=true; } if(p.opacity() != lastpen.opacity()) { *out << p.opacity() << " .setopacityalpha" << newl; transparency=true; } lastpen.settransparency(p); } void psfile::setpen(pen p) { p.convert(); setopacity(p); if(!p.fillpattern().empty() && p.fillpattern() != lastpen.fillpattern()) *out << p.fillpattern() << " setpattern" << newl; else setcolor(p); // Defer dynamic linewidth until stroke time in case currentmatrix changes. if(p.width() != lastpen.width()) *out << p.width() << (pdfformat ? " setlinewidth" : " Setlinewidth") << newl; if(p.cap() != lastpen.cap()) *out << p.cap() << " setlinecap" << newl; if(p.join() != lastpen.join()) *out << p.join() << " setlinejoin" << newl; if(p.miter() != lastpen.miter()) *out << p.miter() << " setmiterlimit" << newl; const LineType *linetype=p.linetype(); const LineType *lastlinetype=lastpen.linetype(); if(!(linetype->pattern == lastlinetype->pattern) || linetype->offset != lastlinetype->offset) { out->setf(std::ios::fixed); *out << linetype->pattern << " " << linetype->offset << " setdash" << newl; out->unsetf(std::ios::fixed); } lastpen=p; } void psfile::write(const pen& p) { if(p.cmyk()) *out << p.cyan() << " " << p.magenta() << " " << p.yellow() << " " << p.black(); else if(p.rgb()) *out << p.red() << " " << p.green() << " " << p.blue(); else if(p.grayscale()) *out << p.gray(); } void psfile::write(path p, bool newPath) { Int n = p.size(); assert(n != 0); if(newPath) newpath(); pair z0=p.point((Int) 0); // Draw points moveto(z0); for(Int i = 1; i < n; i++) { if(p.straight(i-1)) lineto(p.point(i)); else curveto(p.postcontrol(i-1),p.precontrol(i),p.point(i)); } if(p.cyclic()) { if(p.straight(n-1)) lineto(z0); else curveto(p.postcontrol(n-1),p.precontrol((Int) 0),z0); closepath(); } else { if(n == 1) lineto(z0); } } void psfile::latticeshade(const vm::array& a, const transform& t) { checkLevel(); size_t n=a.size(); if(n == 0) return; array *a0=read(a,0); size_t m=a0->size(); setfirstopacity(*a0); ColorSpace colorspace=maxcolorspace2(a); checkColorSpace(colorspace); size_t ncomponents=ColorComponents[colorspace]; *out << "<< /ShadingType 1" << newl << "/Matrix "; write(t); *out << newl; *out << "/ColorSpace /Device" << ColorDeviceSuffix[colorspace] << newl << "/Function" << newl << "<< /FunctionType 0" << newl << "/Order 1" << newl << "/Domain [0 1 0 1]" << newl << "/Range ["; for(size_t i=0; i < ncomponents; ++i) *out << "0 1 "; *out << "]" << newl << "/Decode ["; for(size_t i=0; i < ncomponents; ++i) *out << "0 1 "; *out << "]" << newl; *out << "/BitsPerSample 8" << newl; *out << "/Size [" << m << " " << n << "]" << newl << "/DataSource <" << newl; for(size_t i=n; i > 0;) { array *ai=read(a,--i); checkArray(ai); size_t aisize=ai->size(); if(aisize != m) reportError(rectangular); for(size_t j=0; j < m; j++) { pen *p=read(ai,j); p->convert(); if(!p->promote(colorspace)) reportError(inconsistent); *out << p->hex() << newl; } } *out << ">" << newl << ">>" << newl << ">>" << newl << "shfill" << newl; } // Axial and radial shading void psfile::gradientshade(bool axial, ColorSpace colorspace, const pen& pena, const pair& a, double ra, bool extenda, const pen& penb, const pair& b, double rb, bool extendb) { checkLevel(); endclip(pena); setopacity(pena); checkColorSpace(colorspace); *out << "<< /ShadingType " << (axial ? "2" : "3") << newl << "/ColorSpace /Device" << ColorDeviceSuffix[colorspace] << newl << "/Coords ["; write(a); if(!axial) write(ra); write(b); if(!axial) write(rb); *out << "]" << newl << "/Extend [" << extenda << " " << extendb << "]" << newl << "/Function" << newl << "<< /FunctionType 2" << newl << "/Domain [0 1]" << newl << "/C0 ["; write(pena); *out << "]" << newl << "/C1 ["; write(penb); *out << "]" << newl << "/N 1" << newl << ">>" << newl << ">>" << newl << "shfill" << newl; } void psfile::gouraudshade(const pen& pentype, const array& pens, const array& vertices, const array& edges) { checkLevel(); endclip(pentype); size_t size=pens.size(); if(size == 0) return; setfirstopacity(pens); ColorSpace colorspace=maxcolorspace(pens); *out << "<< /ShadingType 4" << newl << "/ColorSpace /Device" << ColorDeviceSuffix[colorspace] << newl << "/DataSource [" << newl; for(size_t i=0; i < size; i++) { write(read(edges,i)); write(read(vertices,i)); pen *p=read(pens,i); p->convert(); if(!p->promote(colorspace)) reportError(inconsistent); *out << " "; write(*p); *out << newl; } *out << "]" << newl << ">>" << newl << "shfill" << newl; } void psfile::vertexpen(array *pi, int j, ColorSpace colorspace) { pen *p=read(pi,j); p->convert(); if(!p->promote(colorspace)) reportError(inconsistent); *out << " "; write(*p); } // Tensor-product patch shading void psfile::tensorshade(const pen& pentype, const array& pens, const array& boundaries, const array& z) { checkLevel(); endclip(pentype); size_t size=pens.size(); if(size == 0) return; size_t nz=z.size(); array *p0=read(pens,0); if(checkArray(p0) != 4) reportError("4 pens required"); setfirstopacity(*p0); ColorSpace colorspace=maxcolorspace2(pens); checkColorSpace(colorspace); *out << "<< /ShadingType 7" << newl << "/ColorSpace /Device" << ColorDeviceSuffix[colorspace] << newl << "/DataSource [" << newl; for(size_t i=0; i < size; i++) { // Only edge flag 0 (new patch) is implemented since the 32% data // compression (for RGB) afforded by other edge flags really isn't worth // the trouble or confusion for the user. write(0); path g=read(boundaries,i); if(!(g.cyclic() && g.size() == 4)) reportError("specify cyclic path of length 4"); for(Int j=4; j > 0; --j) { write(g.point(j)); write(g.precontrol(j)); write(g.postcontrol(j-1)); } if(nz == 0) { // Coons patch static double nineth=1.0/9.0; for(Int j=0; j < 4; ++j) { write(nineth*(-4.0*g.point(j)+6.0*(g.precontrol(j)+g.postcontrol(j)) -2.0*(g.point(j-1)+g.point(j+1)) +3.0*(g.precontrol(j-1)+g.postcontrol(j+1)) -g.point(j+2))); } } else { array *zi=read(z,i); if(checkArray(zi) != 4) reportError("specify 4 internal control points for each path"); write(read(zi,0)); write(read(zi,3)); write(read(zi,2)); write(read(zi,1)); } array *pi=read(pens,i); if(checkArray(pi) != 4) reportError("specify 4 pens for each path"); vertexpen(pi,0,colorspace); vertexpen(pi,3,colorspace); vertexpen(pi,2,colorspace); vertexpen(pi,1,colorspace); *out << newl; } *out << "]" << newl << ">>" << newl << "shfill" << newl; } void psfile::write(pen *p, size_t ncomponents) { switch(ncomponents) { case 0: break; case 1: writeByte(byte(p->gray())); break; case 3: writeByte(byte(p->red())); writeByte(byte(p->green())); writeByte(byte(p->blue())); break; case 4: writeByte(byte(p->cyan())); writeByte(byte(p->magenta())); writeByte(byte(p->yellow())); writeByte(byte(p->black())); default: break; } } string filter() { return settings::getSetting("level") >= 3 ? "1 (~>) /SubFileDecode filter /ASCII85Decode filter\n/FlateDecode" : "1 (~>) /SubFileDecode filter /ASCII85Decode"; } void psfile::imageheader(size_t width, size_t height, ColorSpace colorspace) { size_t ncomponents=ColorComponents[colorspace]; *out << "/Device" << ColorDeviceSuffix[colorspace] << " setcolorspace" << newl << "<<" << newl << "/ImageType 1" << newl << "/Width " << width << newl << "/Height " << height << newl << "/BitsPerComponent 8" << newl << "/Decode ["; for(size_t i=0; i < ncomponents; ++i) *out << "0 1 "; *out << "]" << newl << "/ImageMatrix [" << width << " 0 0 " << height << " 0 0]" << newl << "/DataSource currentfile " << filter() << " filter" << newl << ">>" << newl << "image" << newl; } void psfile::image(const array& a, const array& P, bool antialias) { size_t asize=a.size(); size_t Psize=P.size(); if(asize == 0 || Psize == 0) return; array *a0=read(a,0); size_t a0size=a0->size(); if(a0size == 0) return; setfirstopacity(P); ColorSpace colorspace=maxcolorspace(P); checkColorSpace(colorspace); size_t ncomponents=ColorComponents[colorspace]; imageheader(a0size,asize,colorspace); double min=read(a0,0); double max=min; for(size_t i=0; i < asize; i++) { array *ai=read(a,i); size_t size=ai->size(); if(size != a0size) reportError(rectangular); for(size_t j=0; j < size; j++) { double val=read(ai,j); if(val > max) max=val; else if(val < min) min=val; } } double step=(max == min) ? 0.0 : (Psize-1)/(max-min); beginImage(ncomponents*a0size*asize); for(size_t i=0; i < asize; i++) { array *ai=read(a,i); for(size_t j=0; j < a0size; j++) { double val=read(ai,j); size_t index=(size_t) ((val-min)*step+0.5); pen *p=read(P,index < Psize ? index : Psize-1); p->convert(); if(!p->promote(colorspace)) reportError(inconsistent); write(p,ncomponents); } } endImage(antialias,a0size,asize,ncomponents); } void psfile::image(const array& a, bool antialias) { size_t asize=a.size(); if(asize == 0) return; array *a0=read(a,0); size_t a0size=a0->size(); if(a0size == 0) return; setfirstopacity(*a0); ColorSpace colorspace=maxcolorspace2(a); checkColorSpace(colorspace); size_t ncomponents=ColorComponents[colorspace]; imageheader(a0size,asize,colorspace); beginImage(ncomponents*a0size*asize); for(size_t i=0; i < asize; i++) { array *ai=read(a,i); size_t size=ai->size(); if(size != a0size) reportError(rectangular); for(size_t j=0; j < size; j++) { pen *p=read(ai,j); p->convert(); if(!p->promote(colorspace)) reportError(inconsistent); write(p,ncomponents); } } endImage(antialias,a0size,asize,ncomponents); } void psfile::image(stack *Stack, callable *f, Int width, Int height, bool antialias) { if(width <= 0 || height <= 0) return; Stack->push(0); Stack->push(0); f->call(Stack); pen p=pop(Stack); setopacity(p); ColorSpace colorspace=p.colorspace(); checkColorSpace(colorspace); size_t ncomponents=ColorComponents[colorspace]; imageheader(width,height,colorspace); beginImage(ncomponents*width*height); for(Int j=0; j < height; j++) { for(Int i=0; i < width; i++) { Stack->push(j); Stack->push(i); f->call(Stack); pen p=pop(Stack); p.convert(); if(!p.promote(colorspace)) reportError(inconsistent); write(&p,ncomponents); } } endImage(antialias,width,height,ncomponents); } void psfile::outImage(bool antialias, size_t width, size_t height, size_t ncomponents) { if(antialias) dealias(buffer,width,height,ncomponents); if(settings::getSetting("level") >= 3) writeCompressed(buffer,count); else { encode85 e(out); for(size_t i=0; i < count; ++i) e.put(buffer[i]); } } void psfile::rawimage(unsigned char *a, size_t width, size_t height, bool antialias) { pen p(0.0,0.0,0.0); p.convert(); ColorSpace colorspace=p.colorspace(); checkColorSpace(colorspace); size_t ncomponents=ColorComponents[colorspace]; imageheader(width,height,colorspace); count=ncomponents*width*height; if(colorspace == RGB) { buffer=a; outImage(antialias,width,height,ncomponents); } else { beginImage(count); if(antialias) dealias(a,width,height,ncomponents,true,colorspace); else { size_t height3=3*height; for(size_t i=0; i < width; ++i) { unsigned char *ai=a+height3*i; for(size_t j=0; j < height; ++j) { unsigned char *aij=ai+3*j; writefromRGB(aij[0],aij[1],aij[2],colorspace,ncomponents); } } } endImage(false,width,height,ncomponents); } } } //namespace camp asymptote-2.37/psfile.h000066400000000000000000000221141265434602500151340ustar00rootroot00000000000000/***** * psfile.h * Andy Hammerlindl 2002/06/10 * * Encapsulates the writing of commands to a PostScript file. * Allows identification and removal of redundant commands. *****/ #ifndef PSFILE_H #define PSFILE_H #include #include #include #include "pair.h" #include "path.h" #include "bbox.h" #include "pen.h" #include "array.h" #include "callable.h" namespace camp { inline void BoundingBox(std::ostream& s, const bbox& box) { s << "%%BoundingBox: " << std::setprecision(0) << std::fixed << box.LowRes() << newl; s.unsetf(std::ios::fixed); s << "%%HiResBoundingBox: " << std::setprecision(9) << box << newl; } // An ASCII85Encode filter. class encode85 { ostream *out; int tuple; int pos; int count; static const int width=72; public: encode85(ostream *out) : out(out), tuple(0), pos(0), count(0) {} ~encode85() { if(count > 0) encode(tuple, count); if(pos+2 > width) *out << '\n'; *out << "~>\n"; } private: void encode(unsigned int tuple, int count) { unsigned char buf[5], *s=buf; int i=5; do { *s++=tuple % 85; tuple /= 85; } while(--i > 0); i=count; do { *out << (unsigned char) (*--s + '!'); if(pos++ >= width) { pos=0; *out << '\n'; } } while(i-- > 0); } public: void put(unsigned char c) { switch (count++) { case 0: tuple |= (c << 24); break; case 1: tuple |= (c << 16); break; case 2: tuple |= (c << 8); break; case 3: tuple |= c; if(tuple == 0) { *out << 'z'; if(pos++ >= width) { pos=0; *out << '\n'; } } else encode(tuple, count); tuple=0; count=0; break; } } }; class psfile { protected: mem::stack pens; public: string filename; bool pdfformat; // Is final output format PDF? bool pdf; // Output direct PDF? bool transparency; // Is transparency used? unsigned char *buffer; size_t count; void write(pen *p, size_t ncomponents); void writefromRGB(unsigned char r, unsigned char g, unsigned char b, ColorSpace colorspace, size_t ncomponents); void writeCompressed(const unsigned char *a, size_t size); void dealias(unsigned char *a, size_t width, size_t height, size_t n, bool convertrgb=false, ColorSpace colorspace=DEFCOLOR); void beginImage(size_t n) { buffer=new unsigned char[n]; count=0; } void outImage(bool antialias, size_t width, size_t height, size_t ncomponents); void endImage(bool antialias, size_t width, size_t height, size_t ncomponents) { outImage(antialias,width,height,ncomponents); delete[] buffer; } void writeByte(unsigned char n) { buffer[count++]=n; } protected: pen lastpen; std::ostream *out; public: psfile(const string& filename, bool pdfformat); psfile() {pdf=settings::pdf(settings::getSetting("tex"));} virtual ~psfile(); void BoundingBox(const bbox& box) { camp::BoundingBox(*out,box); } void prologue(const bbox& box); void epilogue(); void header(); void close(); void write(double x) { *out << " " << x; } void writenewl() { *out << newl; } bool Transparency() { return transparency; } void write(pair z) { *out << " " << z.getx() << " " << z.gety(); } void write(transform t) { if(!pdf) *out << "["; *out << " " << t.getxx() << " " << t.getyx() << " " << t.getxy() << " " << t.getyy() << " " << t.getx() << " " << t.gety(); if(!pdf) *out << "]"; } void resetpen() { lastpen=pen(initialpen); lastpen.convert(); } void setcolor(const pen& p, const string& begin, const string& end); void setopacity(const pen& p); virtual void setpen(pen p); void write(const pen& p); void write(path p, bool newPath=true); virtual void writeclip(path p, bool newPath=true) { write(p,newPath); } virtual void dot(path p, pen, bool newPath=true) { write(p,newPath); } virtual void newpath() { if(!pdf) *out << "newpath"; } virtual void moveto(pair z) { write(z); if(pdf) *out << " m" << newl; else *out << " moveto" << newl; } virtual void lineto(pair z) { write(z); if(pdf) *out << " l" << newl; else *out << " lineto" << newl; } virtual void curveto(pair zp, pair zm, pair z1) { write(zp); write(zm); write(z1); if(pdf) *out << " c" << newl; else *out << " curveto" << newl; } virtual void closepath() { if(pdf) *out << "h" << newl; else *out << "closepath" << newl; } virtual void stroke(const pen &p, bool dot=false) { if(pdf) *out << "S" << newl; else *out << "stroke" << newl; } virtual void strokepath() { if(pdf) reportError("PDF does not support strokepath"); else *out << "strokepath" << newl; } virtual void fill(const pen &p) { if(p.evenodd()) { if(pdf) *out << "f*" << newl; else *out << "eofill" << newl; } else { if(pdf) *out << "f" << newl; else *out << "fill" << newl; } } virtual void beginclip() { newpath(); } virtual void endclip(const pen &p) { if(p.evenodd()) { if(pdf) *out << "W* n" << newl; else *out << "eoclip" << newl; } else { if(pdf) *out << "W n" << newl; else *out << "clip" << newl; } } virtual void endpsclip(const pen &p) {endclip(p);} void checkLevel() { int n=settings::getSetting("level"); if(n < 3) reportError("PostScript shading requires -level 3"); } virtual void beginlatticeshade(const vm::array& a, const bbox& b) {} virtual void latticeshade(const vm::array& a, const transform& t); virtual void begingradientshade(bool axial, ColorSpace colorspace, const pen& pena, const pair& a, double ra, const pen& penb, const pair& b, double rb) {} virtual void gradientshade(bool axial, ColorSpace colorspace, const pen& pena, const pair& a, double ra, bool extenda, const pen& penb, const pair& b, double rb, bool extendb); virtual void begingouraudshade(const vm::array& pens, const vm::array& vertices, const vm::array& edges) {} virtual void gouraudshade(const pen& pentype, const vm::array& pens, const vm::array& vertices, const vm::array& edges); virtual void begintensorshade(const vm::array& pens, const vm::array& boundaries, const vm::array& z) {} virtual void tensorshade(const pen& pentype, const vm::array& pens, const vm::array& boundaries, const vm::array& z); void vertexpen(vm::array *pi, int j, ColorSpace colorspace); void imageheader(size_t width, size_t height, ColorSpace colorspace); void image(const vm::array& a, const vm::array& p, bool antialias); void image(const vm::array& a, bool antialias); void image(vm::stack *Stack, vm::callable *f, Int width, Int height, bool antialias); void rawimage(unsigned char *a, size_t width, size_t height, bool antialias); virtual void gsave(bool tex=false) { if(pdf) *out << "q"; else *out << "gsave"; if(!tex) *out << newl; pens.push(lastpen); } virtual void grestore(bool tex=false) { if(pens.size() < 1) reportError("grestore without matching gsave"); lastpen=pens.top(); pens.pop(); if(pdf) *out << "Q"; else *out << "grestore"; if(!tex) *out << newl; } virtual void translate(pair z) { if(z == pair(0.0,0.0)) return; if(pdf) *out << " 1 0 0 1 " << newl; write(z); if(pdf) *out << " cm" << newl; *out << " translate" << newl; } // Multiply on a transform to the transformation matrix. virtual void concat(transform t) { if(t.isIdentity()) return; write(t); if(pdf) *out << " cm" << newl; else *out << " concat" << newl; } void verbatimline(const string& s) { *out << s << newl; } void verbatim(const string& s) { *out << s; } // Determine shading and image transparency based on first pen. void setfirstopacity(const vm::array& pens) { if(pens.size() > 0) { pen *p=vm::read(pens,0); setopacity(*p); } } ColorSpace maxcolorspace(const vm::array& pens) { ColorSpace colorspace=DEFCOLOR; size_t size=pens.size(); for(size_t i=0; i < size; i++) { pen *p=vm::read(pens,i); p->convert(); colorspace=max(colorspace,p->colorspace()); } return colorspace; } ColorSpace maxcolorspace2(const vm::array& penarray) { ColorSpace colorspace=DEFCOLOR; size_t size=penarray.size(); for(size_t i=0; i < size; i++) colorspace=max(colorspace, maxcolorspace(vm::read(penarray,i))); return colorspace; } }; } //namespace camp #endif asymptote-2.37/quaternion.cc000066400000000000000000000135131265434602500162000ustar00rootroot00000000000000/*********************************************************************** quaternion.cc - A quaternion class ------------------------------------------------------------------- GLUI User Interface Toolkit (LGPL) Copyright (c) 1998 Paul Rademacher WWW: http://sourceforge.net/projects/glui/ Forums: http://sourceforge.net/forum/?group_id=92496 This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ Feb 1998, Paul Rademacher (rademach@cs.unc.edu) Oct 2003, Nigel Stewart - GLUI Code Cleaning ************************************************************************/ #include "quaternion.h" #include /******************************************* constructors **************/ quat::quat() { *this = quat_identity(); } quat::quat(const float x, const float y, const float z, const float w) { v.set( x, y, z ); s = w; } quat::quat(const vec3 &_v, const float _s) { set( _v, _s ); } quat::quat(const float _s, const vec3 &_v) { set( _v, _s ); } quat::quat(const float *d) { v[0] = d[0]; v[1] = d[1]; v[2] = d[2]; s = d[3]; } quat::quat(const double *d) { v[0] = (float) d[0]; v[1] = (float) d[1]; v[2] = (float) d[2]; s = (float) d[3]; } quat::quat(const quat &q) { v = q.v; s = q.s; } void quat::set(const vec3 &_v, const float _s) { v = _v; s = _s; } quat &quat::operator=(const quat &q) { v = q.v; s = q.s; return *this; } /******** quat friends ************/ quat operator + (const quat &a, const quat &b) { return quat( a.s+b.s, a.v+b.v ); } quat operator - (const quat &a, const quat &b) { return quat( a.s-b.s, a.v-b.v ); } quat operator - (const quat &a ) { return quat( -a.s, -a.v ); } quat operator * ( const quat &a, const quat &b) { return quat( a.s*b.s - a.v*b.v, a.s*b.v + b.s*a.v + (a.v^b.v) ); } quat operator * ( const quat &a, const float t) { return quat( a.v * t, a.s * t ); } quat operator * ( const float t, const quat &a ) { return quat( a.v * t, a.s * t ); } mat4 quat::to_mat4() const { float xs, ys, zs, wx, wy, wz, xx, xy, xz, yy, yz, zz; float t = 2.0f / (v*v + s*s); xs = v[VX]*t; ys = v[VY]*t; zs = v[VZ]*t; wx = s*xs; wy = s*ys; wz = s*zs; xx = v[VX]*xs; xy = v[VX]*ys; xz = v[VX]*zs; yy = v[VY]*ys; yz = v[VY]*zs; zz = v[VZ]*zs; mat4 matrix( 1.0f-(yy+zz), xy+wz, xz-wy, 0.0f, xy-wz, 1.0f-(xx+zz), yz+wx, 0.0f, xz+wy, yz-wx, 1.0f-(xx+yy), 0.0f, 0.0f, 0.0f, 0.0f, 1.0f ); return matrix; } /************************************************* quat_identity() *****/ /* Returns quaternion identity element */ quat quat_identity() { return quat( vec3( 0.0, 0.0, 0.0 ), 1.0 ); } /************************************************ quat_slerp() ********/ /* Quaternion spherical interpolation */ quat quat_slerp(const quat &from, const quat &to, float t) { quat to1; float omega, cosom, sinom, scale0, scale1; /* calculate cosine */ cosom = from.v * to.v + from.s + to.s; /* Adjust signs (if necessary) */ if ( cosom < 0.0 ) { cosom = -cosom; to1 = -to; } else { to1 = to; } /* Calculate coefficients */ if ((1.0 - cosom) > FUDGE ) { /* standard case (slerp) */ omega = (float) acos( cosom ); sinom = (float) sin( omega ); scale0 = (float) sin((1.0 - t) * omega) / sinom; scale1 = (float) sin(t * omega) / sinom; } else { /* 'from' and 'to' are very close - just do linear interpolation */ scale0 = 1.0f - t; scale1 = t; } return scale0 * from + scale1 * to1; } /********************************************** set_angle() ************/ /* set rot angle (degrees) */ void quat::set_angle(float f) { vec3 axis = get_axis(); static const double halfradians=acos(-1.0)/360.0; f *= halfradians; s = (float) cos( f ); v = axis * (float) sin( f ); } /********************************************** scale_angle() ************/ /* scale rot angle (degrees) */ void quat::scale_angle(float f) { set_angle( f * get_angle() ); } /********************************************** get_angle() ************/ /* get rot angle (degrees). Assumes s is between -1 and 1 */ float quat::get_angle() const { static const double degrees2=360.0/acos(-1.0); return (float) (acos( s ) * degrees2); } /********************************************* get_axis() **************/ vec3 quat::get_axis() const { float scale = (float) sin( acos( s ) ); if ( scale < FUDGE && scale > -FUDGE ) return vec3( 0.0, 0.0, 0.0 ); else return v / scale; } /******************************************* quat::print() ************/ void quat::print(FILE *dest, const char *name) const { fprintf( dest, "%s: v:<%3.2f %3.2f %3.2f> s:%3.2f\n", name, v[0], v[1], v[2], s ); } asymptote-2.37/quaternion.h000066400000000000000000000115411265434602500160410ustar00rootroot00000000000000/**************************************************************************** quaternion.h - A quaternion class GLUI User Interface Toolkit (LGPL) Copyright (c) 1998 Paul Rademacher --------------------------------------------------------------------- WWW: http://sourceforge.net/projects/glui/ Forums: http://sourceforge.net/forum/?group_id=92496 This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *****************************************************************************/ #ifndef GLUI_QUATERNION_H #define GLUI_QUATERNION_H #include "algebra3.h" #include /* this line defines a new type: pointer to a function which returns a */ /* float and takes as argument a float */ typedef float (*V_FCT_PTR)(float); /**************************************************************** * Quaternion * ****************************************************************/ class quat { /*protected: */ public: vec3 v; /* vector component */ float s; /* scalar component */ /*public: */ /* Constructors */ quat(); quat(float x, float y, float z, float w); quat(const vec3 &v, float s); quat(float s, const vec3 &v); quat(const float *d); /* copy from four-element float array */ quat(const double *f); /* copy from four-element double array */ quat(const quat &q); /* copy from other quat */ /* Assignment operators */ quat &operator = (const quat &v); /* assignment of a quat */ quat &operator += (const quat &v); /* incrementation by a quat */ quat &operator -= (const quat &v); /* decrementation by a quat */ quat &operator *= (float d); /* multiplication by a constant */ quat &operator /= (float d); /* division by a constant */ /* special functions */ float length() const; /* length of a quat */ float length2() const; /* squared length of a quat */ quat &normalize(); /* normalize a quat */ quat &apply(V_FCT_PTR fct); /* apply a func. to each component */ vec3 xform(const vec3 &v ); /* q*v*q-1 */ mat4 to_mat4() const; void set_angle(float f); /* set rot angle (degrees) */ void scale_angle(float f); /* scale rot angle (degrees) */ float get_angle() const; /* set rot angle (degrees) */ vec3 get_axis() const; /* get axis */ void print( FILE *file, const char *name ) const; /* print to a file */ float &operator [] (int i); /* indexing */ const float &operator [] (int i) const; /* indexing */ void set(float x, float y, float z); /* set quat */ void set(const vec3 &v, float s); /* set quat */ /* friends */ friend quat operator - (const quat &v); /* -q1 */ friend quat operator + (const quat &a, const quat &b); /* q1 + q2 */ friend quat operator - (const quat &a, const quat &b); /* q1 - q2 */ friend quat operator * (const quat &a, float d); /* q1 * 3.0 */ friend quat operator * (float d, const quat &a); /* 3.0 * q1 */ friend quat operator * (const quat &a, const quat &b); /* q1 * q2 */ friend quat operator / (const quat &a, float d); /* q1 / 3.0 */ friend int operator == (const quat &a, const quat &b); /* q1 == q2 ? */ friend int operator != (const quat &a, const quat &b); /* q1 != q2 ? */ friend void swap(quat &a, quat &b); /* swap q1 &q2 */ /*friend quat min(const quat &a, const quat &b); -- min(q1, q2) */ /*friend quat max(const quat &a, const quat &b); -- max(q1, q2) */ friend quat prod(const quat &a, const quat &b); /* term by term mult*/ }; /* Utility functions */ quat quat_identity(); /* Returns quaternion identity element */ quat quat_slerp(const quat &from, const quat &to, float t); #endif asymptote-2.37/record.cc000066400000000000000000000032501265434602500152660ustar00rootroot00000000000000/***** * record.cc * Tom Prince 2004/07/15 * * The type for records and modules in the language. *****/ #include "record.h" #include "inst.h" #include "runtime.h" #include "coder.h" namespace types { record::record(symbol name, frame *level) : ty(ty_record), name(name), level(level), init(new vm::lambda), e() { assert(init); #ifdef DEBUG_FRAME init->name = "struct "+string(name); #endif } record::~record() {} record *record::newRecord(symbol id, bool statically) { frame *underlevel = getLevel(statically); assert(underlevel); frame *level = new frame(id, underlevel, 0); record *r = new record(id, level); return r; } // Initialize to null by default. trans::access *record::initializer() { static trans::bltinAccess a(run::pushNullRecord); return &a; } dummyRecord::dummyRecord(symbol name) : record(name, new frame(name, 0,0)) { // Encode the instructions to put an placeholder instance of the record // on the stack. trans::coder c(nullPos, this, 0); c.closeRecord(); } dummyRecord::dummyRecord(string s) : record (symbol::trans(s), new frame(s,0,0)) { // Encode the instructions to put an placeholder instance of the record // on the stack. trans::coder c(nullPos, this, 0); c.closeRecord(); } void dummyRecord::add(string name, ty *t, trans::access *a, trans::permission perm) { e.addVar(symbol::trans(name), new trans::varEntry(t, a, perm, this, this, position())); } void dummyRecord::add(string name, function *t, vm::bltin f, trans::permission perm) { REGISTER_BLTIN(f, name); add(name, t, new trans::bltinAccess(f), perm); } } // namespace types asymptote-2.37/record.h000066400000000000000000000052621265434602500151350ustar00rootroot00000000000000/***** * record.h * Andy Hammerlindl 2003/07/09 * * The type for records and modules in the language. *****/ #ifndef RECORD_H #define RECORD_H #include "types.h" #include "env.h" #include "frame.h" #include "access.h" namespace vm { struct lambda; } using trans::frame; using trans::protoenv; using trans::varEntry; using trans::tyEntry; namespace types { class record : public ty { // The base name of this type. symbol name; // The frame. Like a frame for a function, it allocates the accesses // for fields and specifies the size of the record. frame *level; // The runtime representation of the record used by the virtual machine. vm::lambda *init; public: // The name bindings for fields of the record. protoenv e; // These are name bindings that should be added to the enclosing environment // after translation of the record is completed. Constructors implicitly // defined by "operator init" are stored here. protoenv postdefenv; record(symbol name, frame *level); ~record(); symbol getName() { return name; } bool isReference() { return true; } size_t hash() const { // Use the pointer, as two records are equivalent only if they are the // same object. return (size_t)this; } // Initialize to null by default. trans::access *initializer(); frame *getLevel(bool statically = false) { if (statically) { frame *f=level->getParent(); return f ? f : level; } else return level; } vm::lambda *getInit() { return init; } // Allocates a new dynamic field in the record. trans::access *allocField(bool statically) { frame *underlevel = getLevel(statically); assert(underlevel); return underlevel->allocLocal(); } // Create a statically enclosed record from this record. record *newRecord(symbol id, bool statically); void print(ostream& out) const { out << name; } void debug(ostream& out) const { out << "struct " << name << endl; out << "types:" << endl; out << "re-implement" << endl; //out << te; out << "fields: " << endl; out << "re-implement" << endl; //out << ve; } }; // A record that is being used just for its fields and types, and has no real // initializer. This is for modules such as settings that are built into the // language. class dummyRecord : public record { public: dummyRecord(symbol name); dummyRecord(string s); // Convenient functions for adding fields. void add(string name, ty *t, trans::access *a, trans::permission perm=trans::PUBLIC); void add(string name, function *t, vm::bltin f, trans::permission perm=trans::PUBLIC); }; } //namespace types #endif asymptote-2.37/refaccess.cc000066400000000000000000000021121265434602500157420ustar00rootroot00000000000000/***** * refaccess.cc * Andy Hammerlindl 2005/11/28 * * An access which refers to a variable or other object in C++. *****/ #include "refaccess.h" namespace trans { using vm::item; using vm::stack; using vm::pop; /* itemRefAccess */ void itemPointerRead(stack *s) { item *p=pop(s); s->push(*p); } void itemPointerWrite(stack *s) { item *p=pop(s); item value=pop(s); *p=value; s->push(value); } void itemRefAccess::encode(action act, position, coder &e) { REGISTER_BLTIN(itemPointerRead, "itemPointerRead"); REGISTER_BLTIN(itemPointerWrite, "itemPointerWrite"); e.encode(inst::constpush, (item)ref); switch (act) { case READ: e.encode(inst::builtin, itemPointerRead); break; case WRITE: e.encode(inst::builtin, itemPointerWrite); break; case CALL: e.encode(inst::builtin, itemPointerRead); e.encode(inst::popcall); break; }; } void itemRefAccess::encode(action act, position pos, coder &e, frame *) { // Get rid of the useless top frame. e.encode(inst::pop); encode(act, pos, e); } } asymptote-2.37/refaccess.h000066400000000000000000000036201265434602500156110ustar00rootroot00000000000000/***** * refaccess.h * Andy Hammerlindl 2003/12/03 * * An access which refers to a variable or other object in C++. *****/ #ifndef REFACCESS_H #define REFACCESS_H #include "access.h" #include "inst.h" #include "coder.h" #include "stack.h" namespace trans { // Access refers to a piece of data, represented by an item, somewhere in the // C++ code. class itemRefAccess : public access { vm::item *ref; public: itemRefAccess(vm::item *ref) : ref(ref) {} void encode(action act, position pos, coder &e); void encode(action act, position pos, coder &e, frame *); }; // Access refers to an arbitrary piece of data of type T. template class refAccess : public access { T *ref; public: refAccess(T *ref) : ref(ref) {} void encode(action act, position pos, coder &e); void encode(action act, position pos, coder &e, frame *); }; template void pointerRead(vm::stack *s) { T *ptr=vm::pop(s); s->push(*ptr); } template void pointerWrite(vm::stack *s) { T *ptr=vm::pop(s); T value=vm::pop(s); *ptr=value; s->push(value); } template void refAccess::encode(action act, position, coder &e) { // You may be able to use typeid(T).name() to get a better label. REGISTER_BLTIN((bltin) pointerRead, "pointerRead"); REGISTER_BLTIN((bltin) pointerWrite, "pointerWrite"); e.encode(vm::inst::constpush, (vm::item)ref); switch (act) { case READ: e.encode(vm::inst::builtin, (bltin) pointerRead); break; case WRITE: e.encode(vm::inst::builtin, (bltin) pointerWrite); break; case CALL: e.encode(vm::inst::builtin, (bltin) pointerRead); e.encode(vm::inst::popcall); break; }; } template void refAccess::encode(action act, position pos, coder &e, frame *) { // Get rid of the useless top frame. e.encode(vm::inst::pop); encode(act, pos, e); } } #endif asymptote-2.37/rounding.h000066400000000000000000000067411265434602500155070ustar00rootroot00000000000000/* GTS - Library for the manipulation of triangulated surfaces * Copyright (C) 1999 Stéphane Popinet * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_FPU_CONTROL_H # include # ifdef _FPU_EXTENDED # if !defined(__alpha__) || !defined(__GLIBC__) # if defined(__arm__) static fpu_control_t fpu_round_double = _FPU_DEFAULT; # else static fpu_control_t fpu_round_double = (_FPU_DEFAULT & ~ _FPU_EXTENDED)|_FPU_DOUBLE; # endif static fpu_control_t fpu_init; # define FPU_ROUND_DOUBLE { _FPU_GETCW(fpu_init);\ _FPU_SETCW(fpu_round_double); } # define FPU_RESTORE {_FPU_SETCW(fpu_init);} # else /* __alpha__ && __GLIBC__ */ # define FPU_ROUND_DOUBLE # define FPU_RESTORE # endif /* __alpha__ && __GLIBC__ */ # else /* not FPU_EXTENDED */ # define FPU_ROUND_DOUBLE # define FPU_RESTORE # endif /* not FPU_EXTENDED */ #else /* not HAVE_FPU_CONTROL_H */ # ifdef __FreeBSD__ # include # define FPU_ROUND_DOUBLE (fpsetprec(FP_PD)) # define FPU_RESTORE (fpsetprec(FP_PE)) # else /* not __FreeBSD__ */ # ifdef WIN32 # ifdef _MSC_VER # include static unsigned int fpu_init; # define FPU_ROUND_DOUBLE (fpu_init = _controlfp (0, 0),\ _controlfp (_PC_53, MCW_PC)) # define FPU_RESTORE (_controlfp (fpu_init, 0xfffff)) # elif __MINGW32__ # include static unsigned int fpu_init; # define FPU_ROUND_DOUBLE (fpu_init = _controlfp (0, 0),\ _controlfp (_PC_53, _MCW_PC)) # define FPU_RESTORE (_controlfp (fpu_init, 0xfffff)) # else /* not _MSC_VER or __MINGW32__ */ # error "You need MSVC or MinGW for the Win32 version" # endif /* not _MSC_VER or __MINGW32__ */ # else /* not WIN32 */ # ifdef __CYGWIN__ typedef unsigned int fpu_control_t __attribute__ ((__mode__ (__HI__))); static fpu_control_t fpu_round_double = 0x027f; static fpu_control_t fpu_init; # define _FPU_GETCW(cw) __asm__ ("fnstcw %0" : "=m" (*&cw)) # define _FPU_SETCW(cw) __asm__ ("fldcw %0" : : "m" (*&cw)) # define FPU_ROUND_DOUBLE { _FPU_GETCW(fpu_init);\ _FPU_SETCW(fpu_round_double); } # define FPU_RESTORE { _FPU_SETCW(fpu_init);} # else /* not __CYGWIN__ */ # ifdef CPP_HAS_WARNING # warning "Unknown CPU: assuming default double precision rounding" # endif /* CPP_HAS_WARNING */ # define FPU_ROUND_DOUBLE # define FPU_RESTORE # endif /* not __CYGWIN__ */ # endif /* not WIN32 */ # endif /* not __FreeBSD__ */ #endif /* not HAVE_FPU_CONTROL_H */ asymptote-2.37/runarray.in000066400000000000000000001225471265434602500157070ustar00rootroot00000000000000/***** * runarray.in * * Runtime functions for array operations. * *****/ pair => primPair() triple => primTriple() boolarray* => booleanArray() Intarray* => IntArray() Intarray2* => IntArray2() realarray* => realArray() realarray2* => realArray2() pairarray* => pairArray() pairarray2* => pairArray2() triplearray2* => tripleArray2() callableReal* => realRealFunction() #include "array.h" #include "arrayop.h" #include "triple.h" #include "path3.h" #include "Delaunay.h" #include "glrender.h" #ifdef HAVE_LIBFFTW3 #include "fftw++.h" #endif using namespace camp; using namespace vm; namespace run { extern pair zero; } typedef array boolarray; typedef array Intarray; typedef array Intarray2; typedef array realarray; typedef array realarray2; typedef array pairarray; typedef array pairarray2; typedef array triplearray2; using types::booleanArray; using types::IntArray; using types::IntArray2; using types::realArray; using types::realArray2; using types::pairArray; using types::pairArray2; using types::tripleArray2; typedef callable callableReal; void outOfBounds(const char *op, size_t len, Int n) { ostringstream buf; buf << op << " array of length " << len << " with out-of-bounds index " << n; error(buf); } inline item& arrayRead(array *a, Int n) { size_t len=checkArray(a); bool cyclic=a->cyclic(); if(cyclic && len > 0) n=imod(n,len); else if(n < 0 || n >= (Int) len) outOfBounds("reading",len,n); return (*a)[(unsigned) n]; } // Helper function to create deep arrays. static array* deepArray(Int depth, Int *dims) { assert(depth > 0); if (depth == 1) { return new array(dims[0]); } else { Int length = dims[0]; depth--; dims++; array *a = new array(length); for (Int index = 0; index < length; index++) { (*a)[index] = deepArray(depth, dims); } return a; } } namespace run { array *Identity(Int n) { size_t N=(size_t) n; array *c=new array(N); for(size_t i=0; i < N; ++i) { array *ci=new array(N); (*c)[i]=ci; for(size_t j=0; j < N; ++j) (*ci)[j]=0.0; (*ci)[i]=1.0; } return c; } } static const char *incommensurate="Incommensurate matrices"; static const char *singular="Singular matrix"; static const char *invalidarraylength="Invalid array length: "; static size_t *pivot,*Row,*Col; bound_double *bounddouble(int N) { if(N == 16) return bound; if(N == 10) return boundtri; ostringstream buf; buf << invalidarraylength << " " << N; error(buf); return NULL; } bound_triple *boundtriple(int N) { if(N == 16) return bound; if(N == 10) return boundtri; ostringstream buf; buf << invalidarraylength << " " << N; error(buf); return NULL; } static inline void inverseAllocate(size_t n) { pivot=new size_t[n]; Row=new size_t[n]; Col=new size_t[n]; } static inline void inverseDeallocate() { delete[] pivot; delete[] Row; delete[] Col; } namespace run { array *copyArray(array *a) { size_t size=checkArray(a); array *c=new array(size); for(size_t i=0; i < size; i++) (*c)[i]=(*a)[i]; return c; } array *copyArray2(array *a) { size_t size=checkArray(a); array *c=new array(size); for(size_t i=0; i < size; i++) { array *ai=read(a,i); size_t aisize=checkArray(ai); array *ci=new array(aisize); (*c)[i]=ci; for(size_t j=0; j < aisize; j++) (*ci)[j]=(*ai)[j]; } return c; } double *copyTripleArray2Components(array *a, size_t &N, GCPlacement placement) { size_t n=checkArray(a); N=0; for(size_t i=0; i < n; i++) N += checkArray(read(a,i)); double *A=(placement == NoGC) ? new double [3*N] : new(placement) double[3*N]; double *p=A; for(size_t i=0; i < n; i++) { array *ai=read(a,i); size_t m=checkArray(ai); for(size_t j=0; j < m; j++) { triple v=read(ai,j); *p=v.getx(); *(p+N)=v.gety(); *(p+2*N)=v.getz(); ++p; } } return A; } triple *copyTripleArray2C(array *a, size_t &N, GCPlacement placement) { size_t n=checkArray(a); N=0; for(size_t i=0; i < n; i++) N += checkArray(read(a,i)); triple *A=(placement == NoGC) ? new triple [N] : new(placement) triple[N]; triple *p=A; for(size_t i=0; i < n; i++) { array *ai=read(a,i); size_t m=checkArray(ai); for(size_t j=0; j < m; j++) *(p++)=read(ai,j); } return A; } triple operator *(const array& t, const triple& v) { size_t n=checkArray(&t); if(n != 4) error(incommensurate); array *t0=read(t,0); array *t1=read(t,1); array *t2=read(t,2); array *t3=read(t,3); if(checkArray(t0) != 4 || checkArray(t1) != 4 || checkArray(t2) != 4 || checkArray(t3) != 4) error(incommensurate); double x=v.getx(); double y=v.gety(); double z=v.getz(); double f=read(t3,0)*x+read(t3,1)*y+read(t3,2)*z+ read(t3,3); if(f == 0.0) run::dividebyzero(); f=1.0/f; return triple((read(t0,0)*x+read(t0,1)*y+read(t0,2)*z+ read(t0,3))*f, (read(t1,0)*x+read(t1,1)*y+read(t1,2)*z+ read(t1,3))*f, (read(t2,0)*x+read(t2,1)*y+read(t2,2)*z+ read(t2,3))*f); } template array *mult(array *a, array *b) { size_t n=checkArray(a); size_t nb=checkArray(b); size_t na0=n == 0 ? 0 : checkArray(read(a,0)); if(na0 != nb) error(incommensurate); size_t nb0=nb == 0 ? 0 : checkArray(read(b,0)); array *c=new array(n); T *A,*B; copyArray2C(A,a,false); copyArray2C(B,b,false); for(size_t i=0; i < n; ++i) { T *Ai=A+i*nb; array *ci=new array(nb0); (*c)[i]=ci; for(size_t j=0; j < nb0; ++j) { T sum=T(); size_t kj=j; for(size_t k=0; k < nb; ++k, kj += nb0) sum += Ai[k]*B[kj]; (*ci)[j]=sum; } } delete[] B; delete[] A; return c; } // Compute transpose(A)*A where A is an n x m matrix. template array *AtA(array *a) { size_t n=checkArray(a); size_t m=n == 0 ? 0 : checkArray(read(a,0)); array *c=new array(m); T *A; copyArray2C(A,a,false); for(size_t i=0; i < m; ++i) { array *ci=new array(m); (*c)[i]=ci; for(size_t j=0; j < m; ++j) { T sum=T(); size_t kj=j; size_t ki=i; for(size_t k=0; k < n; ++k, kj += m, ki += m) sum += A[ki]*A[kj]; (*ci)[j]=sum; } } delete[] A; return c; } double norm(double *a, size_t n) { if(n == 0) return 0.0; double M=fabs(a[0]); for(size_t i=1; i < n; ++i) M=::max(M,fabs(a[i])); return M; } double norm(triple *a, size_t n) { if(n == 0) return 0.0; double M=a[0].abs2(); for(size_t i=1; i < n; ++i) M=::max(M,a[i].abs2()); return sqrt(M); } // Transpose an n x n matrix in place. void transpose(double *a, size_t n) { for(size_t i=1; i < n; i++) { for(size_t j=0; j < i; j++) { size_t ij=n*i+j; size_t ji=n*j+i; double temp=a[ij]; a[ij]=a[ji]; a[ji]=temp; } } } // Invert an n x n array in place. void inverse(double *a, size_t n) { inverseAllocate(n); for(size_t i=0; i < n; i++) pivot[i]=0; size_t col=0, row=0; // This is the main loop over the columns to be reduced. for(size_t i=0; i < n; i++) { real big=0.0; // This is the outer loop of the search for a pivot element. for(size_t j=0; j < n; j++) { double *aj=a+n*j; if(pivot[j] != 1) { for(size_t k=0; k < n; k++) { if(pivot[k] == 0) { real temp=fabs(aj[k]); if(temp >= big) { big=temp; row=j; col=k; } } else if(pivot[k] > 1) { inverseDeallocate(); error(singular); } } } } ++(pivot[col]); // Interchange rows, if needed, to put the pivot element on the diagonal. double *acol=a+n*col; if(row != col) { double *arow=a+n*row; for(size_t k=0; k < n; k++) { real temp=arow[k]; arow[k]=acol[k]; acol[k]=temp; } } Row[i]=row; Col[i]=col; // Divide the pivot row by the pivot element. real denom=acol[col]; if(denom == 0.0) { inverseDeallocate(); error(singular); } real pivinv=1.0/denom; acol[col]=1.0; for(size_t k=0; k < n; k++) acol[k]=acol[k]*pivinv; // Reduce all rows except for the pivoted one. for(size_t k=0; k < n; k++) { if(k != col) { double *ak=a+n*k; real akcol=ak[col]; ak[col]=0.0; for(size_t j=0; j < n; j++) ak[j] -= acol[j]*akcol; } } } // Unscramble the inverse matrix in view of the column interchanges. for(size_t k=n; k > 0;) { k--; size_t r=Row[k]; size_t c=Col[k]; if(r != c) { for(size_t j=0; j < n; j++) { double *aj=a+n*j; real temp=aj[r]; aj[r]=aj[c]; aj[c]=temp; } } } inverseDeallocate(); } } callable *Func; stack *FuncStack; double wrapFunction(double x) { FuncStack->push(x); Func->call(FuncStack); return pop(FuncStack); } callable *compareFunc; bool compareFunction(const vm::item& i, const vm::item& j) { FuncStack->push(i); FuncStack->push(j); compareFunc->call(FuncStack); return pop(FuncStack); } // Crout's algorithm for computing the LU decomposition of a square matrix. // cf. routine ludcmp (Press et al., Numerical Recipes, 1991). Int LUdecompose(double *a, size_t n, size_t* index, bool warn=true) { double *vv=new double[n]; Int swap=1; for(size_t i=0; i < n; ++i) { double big=0.0; double *ai=a+i*n; for(size_t j=0; j < n; ++j) { double temp=fabs(ai[j]); if(temp > big) big=temp; } if(big == 0.0) { delete[] vv; if(warn) error(singular); else return 0; } vv[i]=1.0/big; } for(size_t j=0; j < n; ++j) { for(size_t i=0; i < j; ++i) { double *ai=a+i*n; double sum=ai[j]; for(size_t k=0; k < i; ++k) { sum -= ai[k]*a[k*n+j]; } ai[j]=sum; } double big=0.0; size_t imax=j; for(size_t i=j; i < n; ++i) { double *ai=a+i*n; double sum=ai[j]; for(size_t k=0; k < j; ++k) sum -= ai[k]*a[k*n+j]; ai[j]=sum; double temp=vv[i]*fabs(sum); if(temp >= big) { big=temp; imax=i; } } double *aj=a+j*n; double *aimax=a+imax*n; if(j != imax) { for(size_t k=0; k < n; ++k) { double temp=aimax[k]; aimax[k]=aj[k]; aj[k]=temp; } swap *= -1; vv[imax]=vv[j]; } if(index) index[j]=imax; if(j != n) { double denom=aj[j]; if(denom == 0.0) { delete[] vv; if(warn) error(singular); else return 0; } for(size_t i=j+1; i < n; ++i) a[i*n+j] /= denom; } } delete[] vv; return swap; } namespace run { void dividebyzero(size_t i) { ostringstream buf; if(i > 0) buf << "array element " << i << ": "; buf << "Divide by zero"; error(buf); } void integeroverflow(size_t i) { ostringstream buf; if(i > 0) buf << "array element " << i << ": "; buf << "Integer overflow"; error(buf); } } // Autogenerated routines: // Create an empty array. array* :emptyArray() { return new array(0); } // Create a new array (technically a vector). // This array will be multidimensional. First the number of dimensions // is popped off the stack, followed by each dimension in reverse order. // The array itself is technically a one dimensional array of one // dimension arrays and so on. array* :newDeepArray(Int depth) { assert(depth > 0); Int *dims = new Int[depth]; for (Int index = depth-1; index >= 0; index--) { Int i=pop(Stack); if(i < 0) error("cannot create a negative length array"); dims[index]=i; } array *a=deepArray(depth, dims); delete[] dims; return a; } // Creates an array with elements already specified. First, the number // of elements is popped off the stack, followed by each element in // reverse order. array* :newInitializedArray(Int n) { assert(n >= 0); array *a = new array(n); for (Int index = n-1; index >= 0; index--) (*a)[index] = pop(Stack); return a; } // Similar to newInitializedArray, but after the n elements, append another // array to it. array* :newAppendedArray(array* tail, Int n) { assert(n >= 0); array *a = new array(n); for (Int index = n-1; index >= 0; index--) (*a)[index] = pop(Stack); copy(tail->begin(), tail->end(), back_inserter(*a)); return a; } // Produce an array of n deep copies of value. // typeDepth is the true depth of the array determined at compile-time when the // operations for the array type are added. This typeDepth argument is // automatically pushed on the stack and is not visible to the user. array* :copyArrayValue(Int n, item value, Int depth=Int_MAX, Int typeDepth) { if(n < 0) error("cannot create a negative length array"); if(depth < 0) error("cannot copy to a negative depth"); if(depth > typeDepth) depth=typeDepth; return new array((size_t) n, value, depth); } // Deep copy of array. // typeDepth is the true depth of the array determined at compile-time when the // operations for the array type are added. This typeDepth argument is // automatically pushed on the stack and is not visible to the user. array* :copyArray(array *a, Int depth=Int_MAX, Int typeDepth) { if(depth < 0) error("cannot copy to a negative depth"); if(depth > typeDepth) depth=typeDepth; return a->copyToDepth(depth); } // Read an element from an array. Checks for initialization & bounds. item :arrayRead(array *a, Int n) { item& i=arrayRead(a,n); if (i.empty()) { ostringstream buf; buf << "read uninitialized value from array at index " << n; error(buf); } return i; } // Slice a substring from an array. item :arraySliceRead(array *a, Int left, Int right) { checkArray(a); return a->slice(left, right); } // Slice a substring from an array. This implements the cases a[i:] and a[:] // where the endpoint is not given, and assumed to be the length of the array. item :arraySliceReadToEnd(array *a, Int left) { size_t len=checkArray(a); return a->slice(left, (Int)len); } // Read an element from an array of arrays. Check bounds and initialize // as necessary. item :arrayArrayRead(array *a, Int n) { item& i=arrayRead(a,n); if (i.empty()) i=new array(0); return i; } // Write an element to an array. Increase size if necessary. // TODO: Add arrayWriteAndPop item :arrayWrite(array *a, Int n, item value) { size_t len=checkArray(a); bool cyclic=a->cyclic(); if(cyclic && len > 0) n=imod(n,len); else { if(cyclic) outOfBounds("writing cyclic",len,n); if(n < 0) outOfBounds("writing",len,n); if(len <= (size_t) n) a->resize(n+1); } (*a)[n] = value; return value; } array * :arraySliceWrite(array *dest, Int left, Int right, array *src) { checkArray(src); checkArray(dest); dest->setSlice(left, right, src); return src; } array * :arraySliceWriteToEnd(array *dest, Int left, array *src) { checkArray(src); size_t len=checkArray(dest); dest->setSlice(left, (Int) len, src); return src; } // Returns the length of an array. Int :arrayLength(array *a) { return (Int) checkArray(a); } // Returns an array of integers representing the keys of the array. array * :arrayKeys(array *a) { size_t size=checkArray(a); array *keys=new array(); for (size_t i=0; ipush((Int)i); } return keys; } // Return the cyclic flag for an array. bool :arrayCyclicFlag(array *a) { checkArray(a); return a->cyclic(); } bool :arraySetCyclicFlag(bool b, array *a) { checkArray(a); a->cyclic(b); return b; } // Check to see if an array element is initialized. bool :arrayInitializedHelper(Int n, array *a) { size_t len=checkArray(a); bool cyclic=a->cyclic(); if(cyclic && len > 0) n=imod(n,len); else if(n < 0 || n >= (Int) len) return false; item&i=(*a)[(unsigned) n]; return !i.empty(); } // Returns the initialize method for an array. callable* :arrayInitialized(array *a) { return new thunk(new bfunc(arrayInitializedHelper),a); } // The helper function for the cyclic method that sets the cyclic flag. void :arrayCyclicHelper(bool b, array *a) { checkArray(a); a->cyclic(b); } // Set the cyclic flag for an array. callable* :arrayCyclic(array *a) { return new thunk(new bfunc(arrayCyclicHelper),a); } // The helper function for the push method that does the actual operation. item :arrayPushHelper(item x, array *a) { checkArray(a); a->push(x); return x; } // Returns the push method for an array. callable* :arrayPush(array *a) { return new thunk(new bfunc(arrayPushHelper),a); } // The helper function for the append method that appends b to a. void :arrayAppendHelper(array *b, array *a) { checkArray(a); size_t size=checkArray(b); for(size_t i=0; i < size; i++) a->push((*b)[i]); } // Returns the append method for an array. callable* :arrayAppend(array *a) { return new thunk(new bfunc(arrayAppendHelper),a); } // The helper function for the pop method. item :arrayPopHelper(array *a) { size_t asize=checkArray(a); if(asize == 0) error("cannot pop element from empty array"); return a->pop(); } // Returns the pop method for an array. callable* :arrayPop(array *a) { return new thunk(new bfunc(arrayPopHelper),a); } // The helper function for the insert method. item :arrayInsertHelper(Int i, array *x, array *a) { size_t asize=checkArray(a); checkArray(x); if(a->cyclic() && asize > 0) i=imod(i,asize); if(i < 0 || i > (Int) asize) outOfBounds("inserting",asize,i); (*a).insert((*a).begin()+i,(*x).begin(),(*x).end()); } // Returns the insert method for an array. callable* :arrayInsert(array *a) { return new thunk(new bfunc(arrayInsertHelper),a); } // Returns the delete method for an array. callable* :arrayDelete(array *a) { return new thunk(new bfunc(arrayDeleteHelper),a); } bool :arrayAlias(array *a, array *b) { return a==b; } // Return array formed by indexing array a with elements of integer array b array* :arrayIntArray(array *a, array *b) { size_t asize=checkArray(a); size_t bsize=checkArray(b); array *r=new array(bsize); bool cyclic=a->cyclic(); for(size_t i=0; i < bsize; i++) { Int index=read(b,i); if(cyclic && asize > 0) index=imod(index,asize); else if(index < 0 || index >= (Int) asize) outOfBounds("reading",asize,index); (*r)[i]=(*a)[index]; } return r; } // returns the complement of the integer array a in {0,2,...,n-1}, // so that b[complement(a,b.length)] yields the complement of b[a]. Intarray* complement(Intarray *a, Int n) { size_t asize=checkArray(a); array *r=new array(0); bool *keep=new bool[n]; for(Int i=0; i < n; ++i) keep[i]=true; for(size_t i=0; i < asize; ++i) { Int j=read(a,i); if(j >= 0 && j < n) keep[j]=false; } for(Int i=0; i < n; i++) if(keep[i]) r->push(i); delete[] keep; return r; } // Generate the sequence {f(i) : i=0,1,...n-1} given a function f and integer n Intarray* :arraySequence(callable *f, Int n) { if(n < 0) n=0; array *a=new array(n); for(Int i=0; i < n; ++i) { Stack->push(i); f->call(Stack); (*a)[i]=pop(Stack); } return a; } // Return the array {0,1,...n-1} Intarray *sequence(Int n) { if(n < 0) n=0; array *a=new array(n); for(Int i=0; i < n; ++i) { (*a)[i]=i; } return a; } // Apply a function to each element of an array array* :arrayFunction(callable *f, array *a) { size_t size=checkArray(a); array *b=new array(size); for(size_t i=0; i < size; ++i) { Stack->push((*a)[i]); f->call(Stack); (*b)[i]=pop(Stack); } return b; } array* :arraySort(array *a, callable *less) { array *c=copyArray(a); compareFunc=less; FuncStack=Stack; stable_sort(c->begin(),c->end(),compareFunction); return c; } Int :arraySearch(array *a, item key, callable *less) { size_t size=a->size(); compareFunc=less; FuncStack=Stack; if(size == 0 || compareFunction(key,(*a)[0])) return -1; size_t u=size-1; if(!compareFunction(key,(*a)[u])) return Intcast(u); size_t l=0; while (l < u) { size_t i=(l+u)/2; if(compareFunction(key,(*a)[i])) u=i; else if(compareFunction(key,(*a)[i+1])) return Intcast(i); else l=i+1; } return 0; } bool all(boolarray *a) { size_t size=checkArray(a); bool c=true; for(size_t i=0; i < size; i++) if(!get((*a)[i])) {c=false; break;} return c; } boolarray* !(boolarray* a) { size_t size=checkArray(a); array *c=new array(size); for(size_t i=0; i < size; i++) (*c)[i]=!read(a,i); return c; } Int sum(boolarray *a) { size_t size=checkArray(a); Int sum=0; for(size_t i=0; i < size; i++) sum += read(a,i) ? 1 : 0; return sum; } array* :arrayConcat(array *a) { // a is an array of arrays to be concatenated together. // The signature is // T[] concat(... T[][] a); size_t numArgs=checkArray(a); size_t resultSize=0; for (size_t i=0; i < numArgs; ++i) { resultSize += checkArray(a->read(i)); } array *result=new array(resultSize); size_t ri=0; for (size_t i=0; i < numArgs; ++i) { array *arg=a->read(i); size_t size=checkArray(arg); for (size_t j=0; j < size; ++j) { (*result)[ri]=(*arg)[j]; ++ri; } } return result; } array* :array2Transpose(array *a) { size_t asize=checkArray(a); array *c=new array(0); for(size_t i=0; i < asize; i++) { size_t ip=i+1; array *ai=read(a,i); size_t aisize=checkArray(ai); size_t csize=checkArray(c); if(csize < aisize) { c->resize(aisize); for(size_t j=csize; j < aisize; j++) { (*c)[j]=new array(ip); } } for(size_t j=0; j < aisize; j++) { array *cj=read(c,j); if(checkArray(cj) < ip) cj->resize(ip); (*cj)[i]=(*ai)[j]; } } return c; } // a is a rectangular 3D array; perm is an Int array indicating the type of // permutation (021 or 120, etc; original is 012). // Transpose by sending respective members to the permutated locations: // return the array obtained by putting a[i][j][k] into position perm{ijk}. array* :array3Transpose(array *a, array *perm) { const size_t DIM=3; if(checkArray(perm) != DIM) { ostringstream buf; buf << "permutation array must have length " << DIM; error(buf); } size_t* size=new size_t[DIM]; for(size_t i=0; i < DIM; ++i) size[i]=DIM; for(size_t i=0; i < DIM; ++i) { Int p=read(perm,i); size_t P=(size_t) p; if(p < 0 || P >= DIM) { ostringstream buf; buf << "permutation index out of range: " << p; error(buf); } size[P]=P; } for(size_t i=0; i < DIM; ++i) if(size[i] == DIM) error("permutation indices must be distinct"); static const char *rectangular= "3D transpose implemented for rectangular matrices only"; size_t isize=size[0]=checkArray(a); array *a0=read(a,0); size[1]=checkArray(a0); array *a00=read(a0,0); size[2]=checkArray(a00); for(size_t i=0; i < isize; i++) { array *ai=read(a,i); size_t jsize=checkArray(ai); if(jsize != size[1]) error(rectangular); for(size_t j=0; j < jsize; j++) { array *aij=read(ai,j); if(checkArray(aij) != size[2]) error(rectangular); } } size_t perm0=(size_t) read(perm,0); size_t perm1=(size_t) read(perm,1); size_t perm2=(size_t) read(perm,2); size_t sizep0=size[perm0]; size_t sizep1=size[perm1]; size_t sizep2=size[perm2]; array *c=new array(sizep0); for(size_t i=0; i < sizep0; ++i) { array *ci=new array(sizep1); (*c)[i]=ci; for(size_t j=0; j < sizep1; ++j) { array *cij=new array(sizep2); (*ci)[j]=cij; } } size_t* i=new size_t[DIM]; for(i[0]=0; i[0] < size[0]; ++i[0]) { array *a0=read(a,i[0]); for(i[1]=0; i[1] < size[1]; ++i[1]) { array *a1=read(a0,i[1]); for(i[2]=0; i[2] < size[2]; ++i[2]) { array *c0=read(c,i[perm0]); array *c1=read(c0,i[perm1]); (*c1)[i[perm2]]=read(a1,i[2]); } } } delete[] i; delete[] size; return c; } // In a boolean array, find the index of the nth true value or -1 if not found // If n is negative, search backwards. Int find(boolarray *a, Int n=1) { size_t size=checkArray(a); Int j=-1; if(n > 0) for(size_t i=0; i < size; i++) if(read(a,i)) { n--; if(n == 0) {j=(Int) i; break;} } if(n < 0) for(size_t i=size; i > 0;) if(read(a,--i)) { n++; if(n == 0) {j=(Int) i; break;} } return j; } // construct vector obtained by replacing those elements of b for which the // corresponding elements of a are false by the corresponding element of c. array* :arrayConditional(array *a, array *b, array *c) { size_t size=checkArray(a); array *r=new array(size); if(b && c) { checkArrays(a,b); checkArrays(b,c); for(size_t i=0; i < size; i++) (*r)[i]=read(a,i) ? (*b)[i] : (*c)[i]; } else { r->clear(); if(b) { checkArrays(a,b); for(size_t i=0; i < size; i++) if(read(a,i)) r->push((*b)[i]); } else if(c) { checkArrays(a,c); for(size_t i=0; i < size; i++) if(!read(a,i)) r->push((*c)[i]); } } return r; } // Return an n x n identity matrix. realarray2 *identity(Int n) { return Identity(n); } // Return the inverse of an n x n matrix a using Gauss-Jordan elimination. realarray2 *inverse(realarray2 *a) { size_t n=checkArray(a); double *A; copyArray2C(A,a,true,0,NoGC); inverse(A,n); a=copyCArray2(n,n,A); delete[] A; return a; } // Solve the linear equation ax=b by LU decomposition, returning the // solution x, where a is an n x n matrix and b is an array of length n. // If no solution exists, return an empty array. realarray *solve(realarray2 *a, realarray *b, bool warn=true) { size_t n=checkArray(a); if(n == 0) return new array(0); size_t m=checkArray(b); if(m != n) error(incommensurate); real *A; copyArray2C(A,a); size_t *index=new size_t[n]; if(LUdecompose(A,n,index,warn) == 0) return new array(0); array *x=new array(n); real *B; copyArrayC(B,b); for(size_t i=0; i < n; ++i) { size_t ip=index[i]; real sum=B[ip]; B[ip]=B[i]; real *Ai=A+i*n; for(size_t j=0; j < i; ++j) sum -= Ai[j]*B[j]; B[i]=sum; } for(size_t i=n; i > 0;) { --i; real sum=B[i]; real *Ai=A+i*n; for(size_t j=i+1; j < n; ++j) sum -= Ai[j]*B[j]; B[i]=sum/Ai[i]; } for(size_t i=0; i < n; ++i) (*x)[i]=B[i]; delete[] index; delete[] B; delete[] A; return x; } // Solve the linear equation ax=b by LU decomposition, returning the // solution x, where a is an n x n matrix and b is an n x m matrix. // If no solution exists, return an empty array. realarray2 *solve(realarray2 *a, realarray2 *b, bool warn=true) { size_t n=checkArray(a); if(n == 0) return new array(0); if(checkArray(b) != n) error(incommensurate); size_t m=checkArray(read(b,0)); real *A,*B; copyArray2C(A,a); copyArray2C(B,b,false); size_t *index=new size_t[n]; if(LUdecompose(A,n,index,warn) == 0) return new array(0); array *x=new array(n); for(size_t i=0; i < n; ++i) { real *Ai=A+i*n; real *Bi=B+i*m; real *Bip=B+index[i]*m; for(size_t k=0; k < m; ++k) { real sum=Bip[k]; Bip[k]=Bi[k]; size_t jk=k; for(size_t j=0; j < i; ++j, jk += m) sum -= Ai[j]*B[jk]; Bi[k]=sum; } } for(size_t i=n; i > 0;) { --i; real *Ai=A+i*n; real *Bi=B+i*m; for(size_t k=0; k < m; ++k) { real sum=Bi[k]; size_t jk=(i+1)*m+k; for(size_t j=i+1; j < n; ++j, jk += m) sum -= Ai[j]*B[jk]; Bi[k]=sum/Ai[i]; } } for(size_t i=0; i < n; ++i) { real *Bi=B+i*m; array *xi=new array(m); (*x)[i]=xi; for(size_t j=0; j < m; ++j) (*xi)[j]=Bi[j]; } delete[] index; delete[] B; delete[] A; return x; } // Compute the determinant of an n x n matrix. real determinant(realarray2 *a) { real *A; copyArray2C(A,a); size_t n=checkArray(a); real det=LUdecompose(A,n,NULL,false); size_t n1=n+1; for(size_t i=0; i < n; ++i) det *= A[i*n1]; delete[] A; return det; } realarray *Operator *(realarray2 *a, realarray *b) { size_t n=checkArray(a); size_t m=checkArray(b); array *c=new array(n); real *B; copyArrayC(B,b); for(size_t i=0; i < n; ++i) { array *ai=read(a,i); if(checkArray(ai) != m) error(incommensurate); real sum=0.0; for(size_t j=0; j < m; ++j) sum += read(ai,j)*B[j]; (*c)[i]=sum; } delete[] B; return c; } realarray *Operator *(realarray *a, realarray2 *b) { size_t n=checkArray(a); if(n != checkArray(b)) error(incommensurate); real *A; copyArrayC(A,a); array **B=new array*[n]; array *bk=read(b,0); B[0]=bk; size_t m=bk->size(); for(size_t k=1; k < n; k++) { array *bk=read(b,k); if(bk->size() != m) error(incommensurate); B[k]=bk; } array *c=new array(m); for(size_t i=0; i < m; ++i) { real sum=0.0; for(size_t k=0; k < n; ++k) sum += A[k]*read(B[k],i); (*c)[i]=sum; } delete[] B; delete[] A; return c; } Intarray2 *Operator *(Intarray2 *a, Intarray2 *b) { return mult(a,b); } realarray2 *Operator *(realarray2 *a, realarray2 *b) { return mult(a,b); } pairarray2 *Operator *(pairarray2 *a, pairarray2 *b) { return mult(a,b); } triple Operator *(realarray2 *t, triple v) { return *t*v; } realarray2 *AtA(realarray2 *a) { return AtA(a); } pair project(triple v, realarray2 *t) { size_t n=checkArray(t); if(n != 4) error(incommensurate); array *t0=read(t,0); array *t1=read(t,1); array *t3=read(t,3); if(checkArray(t0) != 4 || checkArray(t1) != 4 || checkArray(t3) != 4) error(incommensurate); real x=v.getx(); real y=v.gety(); real z=v.getz(); real f=read(t3,0)*x+read(t3,1)*y+read(t3,2)*z+ read(t3,3); if(f == 0.0) dividebyzero(); f=1.0/f; return pair((read(t0,0)*x+read(t0,1)*y+read(t0,2)*z+ read(t0,3))*f, (read(t1,0)*x+read(t1,1)*y+read(t1,2)*z+ read(t1,3))*f); } // Compute the dot product of vectors a and b. real dot(realarray *a, realarray *b) { size_t n=checkArrays(a,b); real sum=0.0; for(size_t i=0; i < n; ++i) sum += read(a,i)*read(b,i); return sum; } // Compute the complex dot product of vectors a and b. pair dot(pairarray *a, pairarray *b) { size_t n=checkArrays(a,b); pair sum=zero; for(size_t i=0; i < n; ++i) sum += read(a,i)*conj(read(b,i)); return sum; } // Solve the problem L\inv f, where f is an n vector and L is the n x n matrix // // [ b[0] c[0] a[0] ] // [ a[1] b[1] c[1] ] // [ a[2] b[2] c[2] ] // [ ... ] // [ c[n-1] a[n-1] b[n-1] ] realarray *tridiagonal(realarray *a, realarray *b, realarray *c, realarray *f) { size_t n=checkArrays(a,b); checkEqual(n,checkArray(c)); checkEqual(n,checkArray(f)); array *up=new array(n); array& u=*up; if(n == 0) return up; // Special case: zero Dirichlet boundary conditions if(read(a,0) == 0.0 && read(c,n-1) == 0.0) { real temp=read(b,0); if(temp == 0.0) dividebyzero(); temp=1.0/temp; real *work=new real[n]; u[0]=read(f,0)*temp; work[0]=-read(c,0)*temp; for(size_t i=1; i < n; i++) { real temp=(read(b,i)+read(a,i)*work[i-1]); if(temp == 0.0) {delete[] work; dividebyzero();} temp=1.0/temp; u[i]=(read(f,i)-read(a,i)*read(u,i-1))*temp; work[i]=-read(c,i)*temp; } for(size_t i=n-1; i >= 1; i--) u[i-1]=read(u,i-1)+work[i-1]*read(u,i); delete[] work; return up; } real binv=read(b,0); if(binv == 0.0) dividebyzero(); binv=1.0/binv; if(n == 1) {u[0]=read(f,0)*binv; return up;} if(n == 2) { real factor=(read(b,0)*read(b,1)- read(a,0)*read(c,1)); if(factor== 0.0) dividebyzero(); factor=1.0/factor; real temp=(read(b,0)*read(f,1)- read(c,1)*read(f,0))*factor; u[0]=(read(b,1)*read(f,0)- read(a,0)*read(f,1))*factor; u[1]=temp; return up; } real *gamma=new real[n-2]; real *delta=new real[n-2]; gamma[0]=read(c,0)*binv; delta[0]=read(a,0)*binv; u[0]=read(f,0)*binv; real beta=read(c,n-1); real fn=read(f,n-1)-beta*read(u,0); real alpha=read(b,n-1)-beta*delta[0]; for(size_t i=1; i <= n-3; i++) { real alphainv=read(b,i)-read(a,i)*gamma[i-1]; if(alphainv == 0.0) {delete[] gamma; delete[] delta; dividebyzero();} alphainv=1.0/alphainv; beta *= -gamma[i-1]; gamma[i]=read(c,i)*alphainv; u[i]=(read(f,i)-read(a,i)*read(u,i-1))*alphainv; fn -= beta*read(u,i); delta[i]=-read(a,i)*delta[i-1]*alphainv; alpha -= beta*delta[i]; } real alphainv=read(b,n-2)-read(a,n-2)*gamma[n-3]; if(alphainv == 0.0) {delete[] gamma; delete[] delta; dividebyzero();} alphainv=1.0/alphainv; u[n-2]=(read(f,n-2)-read(a,n-2)*read(u,n-3)) *alphainv; beta=read(a,n-1)-beta*gamma[n-3]; real dnm1=(read(c,n-2)-read(a,n-2)*delta[n-3])*alphainv; real temp=alpha-beta*dnm1; if(temp == 0.0) {delete[] gamma; delete[] delta; dividebyzero();} u[n-1]=temp=(fn-beta*read(u,n-2))/temp; u[n-2]=read(u,n-2)-dnm1*temp; for(size_t i=n-2; i >= 1; i--) u[i-1]=read(u,i-1)-gamma[i-1]*read(u,i)-delta[i-1]*temp; delete[] delta; delete[] gamma; return up; } // Root solve by Newton-Raphson real newton(Int iterations=100, callableReal *f, callableReal *fprime, real x, bool verbose=false) { static const real fuzz=1000.0*DBL_EPSILON; Int i=0; size_t oldPrec=0; if(verbose) oldPrec=cout.precision(DBL_DIG); real diff=DBL_MAX; real lastdiff; do { real x0=x; Stack->push(x); fprime->call(Stack); real dfdx=pop(Stack); if(dfdx == 0.0) { x=DBL_MAX; break; } Stack->push(x); f->call(Stack); real fx=pop(Stack); x -= fx/dfdx; lastdiff=diff; if(verbose) cout << "Newton-Raphson: " << x << endl; diff=fabs(x-x0); if(++i == iterations) { x=DBL_MAX; break; } } while (diff != 0.0 && (diff < lastdiff || diff > fuzz*fabs(x))); if(verbose) cout.precision(oldPrec); return x; } // Root solve by Newton-Raphson bisection // cf. routine rtsafe (Press et al., Numerical Recipes, 1991). real newton(Int iterations=100, callableReal *f, callableReal *fprime, real x1, real x2, bool verbose=false) { static const real fuzz=1000.0*DBL_EPSILON; size_t oldPrec=0; if(verbose) oldPrec=cout.precision(DBL_DIG); Stack->push(x1); f->call(Stack); real f1=pop(Stack); if(f1 == 0.0) return x1; Stack->push(x2); f->call(Stack); real f2=pop(Stack); if(f2 == 0.0) return x2; if((f1 > 0.0 && f2 > 0.0) || (f1 < 0.0 && f2 < 0.0)) { ostringstream buf; buf << "root not bracketed, f(x1)=" << f1 << ", f(x2)=" << f2 << endl; error(buf); } real x=0.5*(x1+x2); real dxold=fabs(x2-x1); if(f1 > 0.0) { real temp=x1; x1=x2; x2=temp; } if(verbose) cout << "midpoint: " << x << endl; real dx=dxold; Stack->push(x); f->call(Stack); real y=pop(Stack); Stack->push(x); fprime->call(Stack); real dy=pop(Stack); Int j; for(j=0; j < iterations; j++) { if(((x-x2)*dy-y)*((x-x1)*dy-y) >= 0.0 || fabs(2.0*y) > fabs(dxold*dy)) { dxold=dx; dx=0.5*(x2-x1); x=x1+dx; if(verbose) cout << "bisection: " << x << endl; if(x1 == x) return x; } else { dxold=dx; dx=y/dy; real temp=x; x -= dx; if(verbose) cout << "Newton-Raphson: " << x << endl; if(temp == x) return x; } if(fabs(dx) < fuzz*fabs(x)) return x; Stack->push(x); f->call(Stack); y=pop(Stack); Stack->push(x); fprime->call(Stack); dy=pop(Stack); if(y < 0.0) x1=x; else x2=x; } if(verbose) cout.precision(oldPrec); return (j == iterations) ? DBL_MAX : x; } real simpson(callableReal *f, real a, real b, real acc=DBL_EPSILON, real dxmax=0) { real integral; if(dxmax <= 0) dxmax=fabs(b-a); callable *oldFunc=Func; Func=f; FuncStack=Stack; if(!simpson(integral,wrapFunction,a,b,acc,dxmax)) error("nesting capacity exceeded in simpson"); Func=oldFunc; return integral; } // Compute the fast Fourier transform of a pair array pairarray* fft(pairarray *a, Int sign=1) { #ifdef HAVE_LIBFFTW3 unsigned n=(unsigned) checkArray(a); array *c=new array(n); if(n) { Complex *f=utils::ComplexAlign(n); fftwpp::fft1d Forward(n,intcast(sign),f); for(size_t i=0; i < n; i++) { pair z=read(a,i); f[i]=Complex(z.getx(),z.gety()); } Forward.fft(f); for(size_t i=0; i < n; i++) { Complex z=f[i]; (*c)[i]=pair(z.real(),z.imag()); } utils::deleteAlign(f); } #else unused(&sign); array *c=new array(0); error("Please install fftw3, run ./configure, and recompile"); #endif // HAVE_LIBFFTW3 return c; } Intarray2 *triangulate(pairarray *z) { size_t nv=checkArray(z); // Call robust version of Gilles Dumoulin's port of Paul Bourke's // triangulation code. XYZ *pxyz=new XYZ[nv+3]; ITRIANGLE *V=new ITRIANGLE[4*nv]; for(size_t i=0; i < nv; ++i) { pair w=read(z,i); pxyz[i].p[0]=w.getx(); pxyz[i].p[1]=w.gety(); pxyz[i].i=(Int) i; } Int ntri; Triangulate((Int) nv,pxyz,V,ntri,true,false); size_t nt=(size_t) ntri; array *t=new array(nt); for(size_t i=0; i < nt; ++i) { array *ti=new array(3); (*t)[i]=ti; ITRIANGLE *Vi=V+i; (*ti)[0]=pxyz[Vi->p1].i; (*ti)[1]=pxyz[Vi->p2].i; (*ti)[2]=pxyz[Vi->p3].i; } delete[] V; delete[] pxyz; return t; } real norm(realarray *a) { size_t n=checkArray(a); real M=0.0; for(size_t i=0; i < n; ++i) { real x=fabs(vm::read(a,i)); if(x > M) M=x; } return M; } real norm(realarray2 *a) { size_t n=checkArray(a); real M=0.0; for(size_t i=0; i < n; ++i) { vm::array *ai=vm::read(a,i); size_t m=checkArray(ai); for(size_t j=0; j < m; ++j) { real a=fabs(vm::read(ai,j)); if(a > M) M=a; } } return M; } real norm(triplearray2 *a) { size_t n=checkArray(a); real M=0.0; for(size_t i=0; i < n; ++i) { vm::array *ai=vm::read(a,i); size_t m=checkArray(ai); for(size_t j=0; j < m; ++j) { real a=vm::read(ai,j).abs2(); if(a > M) M=a; } } return sqrt(M); } real change2(triplearray2 *a) { size_t n=checkArray(a); if(n == 0) return 0.0; vm::array *a0=vm::read(a,0); size_t m=checkArray(a0); if(m == 0) return 0.0; triple a00=vm::read(a0,0); real M=0.0; for(size_t i=0; i < n; ++i) { vm::array *ai=vm::read(a,i); size_t m=checkArray(ai); for(size_t j=0; j < m; ++j) { real a=(vm::read(ai,j)-a00).abs2(); if(a > M) M=a; } } return M; } triple minbezier(triplearray2 *P, triple b) { size_t N; real *A=copyTripleArray2Components(P,N); bound_double *B=bounddouble(N); b=triple(B(A,::min,b.getx(),sqrtFuzz*norm(A,N),maxdepth), B(A+N,::min,b.gety(),sqrtFuzz*norm(A+N,N),maxdepth), B(A+2*N,::min,b.getz(),sqrtFuzz*norm(A+2*N,N),maxdepth)); delete[] A; return b; } triple maxbezier(triplearray2 *P, triple b) { size_t N; real *A=copyTripleArray2Components(P,N); bound_double *B=bounddouble(N); b=triple(B(A,::max,b.getx(),sqrtFuzz*norm(A,N),maxdepth), B(A+N,::max,b.gety(),sqrtFuzz*norm(A+N,N),maxdepth), B(A+2*N,::max,b.getz(),sqrtFuzz*norm(A+2*N,N),maxdepth)); delete[] A; return b; } pair minratio(triplearray2 *P, pair b) { size_t N; triple *A=copyTripleArray2C(P,N); real fuzz=sqrtFuzz*norm(A,N); bound_triple *B=boundtriple(N); b=pair(B(A,::min,xratio,b.getx(),fuzz,maxdepth), B(A,::min,yratio,b.gety(),fuzz,maxdepth)); delete[] A; return b; } pair maxratio(triplearray2 *P, pair b) { size_t N; triple *A=copyTripleArray2C(P,N); bound_triple *B=boundtriple(N); real fuzz=sqrtFuzz*norm(A,N); b=pair(B(A,::max,xratio,b.getx(),fuzz,maxdepth), B(A,::max,yratio,b.gety(),fuzz,maxdepth)); delete[] A; return b; } realarray *_projection() { #ifdef HAVE_GL array *a=new array(14); gl::projection P=gl::camera(); size_t k=0; (*a)[k++]=P.orthographic ? 1.0 : 0.0; triple camera=P.camera; (*a)[k++]=camera.getx(); (*a)[k++]=camera.gety(); (*a)[k++]=camera.getz(); triple up=P.up; (*a)[k++]=up.getx(); (*a)[k++]=up.gety(); (*a)[k++]=up.getz(); triple target=P.target; (*a)[k++]=target.getx(); (*a)[k++]=target.gety(); (*a)[k++]=target.getz(); (*a)[k++]=P.zoom; (*a)[k++]=P.angle; (*a)[k++]=P.viewportshift.getx(); (*a)[k++]=P.viewportshift.gety(); #endif return new array(0); } asymptote-2.37/runbacktrace.in000066400000000000000000000015011265434602500164720ustar00rootroot00000000000000/***** * backtrace.in * Andy Hammerlindl 2009/07/28 * * Runtime functions for printing garbage collector backtraces. * *****/ // No extra types defined. // No extra code for .cc file. // Autogenerated routines: void generate_random_backtrace() { #if defined(USEGC) && defined(GC_DEBUG) && defined(GC_BACKTRACE) GC_generate_random_backtrace(); #else error("generate_random_backtrace() requires ./configure --enable-gc-debug"); #endif } void print_random_addresses(Int n=1) { #if defined(USEGC) && defined(GC_DEBUG) && defined(GC_BACKTRACE) GC_gcollect(); for (Int i=0; i < n; ++i) GC_debug_print_heap_obj_proc(GC_base(GC_generate_random_valid_address())); #else error("print_random_addresses() requires ./configure --enable-gc-debug"); unused(&n); // Avoid unused variable warning message. #endif } asymptote-2.37/runfile.in000066400000000000000000000134441265434602500155030ustar00rootroot00000000000000/***** * runfile.in * * Runtime functions for file operations. * *****/ file* => primFile() #include "fileio.h" #include "callable.h" #include "triple.h" #include "array.h" #ifdef __CYGWIN__ extern "C" int mkstemp(char *c); #endif using namespace camp; using namespace settings; using namespace vm; string commentchar="#"; // Autogenerated routines: bool ==(file *a, file *b) { return a == b; } bool !=(file *a, file *b) { return a != b; } file* :nullFile() { return &camp::nullfile; } file* input(string name=emptystring, bool check=true, string comment=commentchar, string mode=emptystring) { file *f=NULL; if(mode == "binary") { f=new ibfile(name,check); } else if(mode == "xdr") { #ifdef HAVE_RPC_RPC_H f=new ixfile(name,check); #else ostringstream buf; buf << name << ": XDR read support not enabled"; error(buf); #endif } else if(mode == "") { char c=comment.empty() ? (char) 0 : comment[0]; f=new ifile(name,c,check); } else { f=NULL; ostringstream buf; buf << name << ": invalid file mode '" << mode << "'"; error(buf); } f->open(); return f; } file* output(string name=emptystring, bool update=false, string comment=commentchar, string mode=emptystring) { file *f=NULL; if(mode == "pipe") { f=new opipe(name); } else if(mode == "binary") { if(update) f=new iobfile(name); else f=new obfile(name); } else if(mode == "xdr") { #ifdef HAVE_RPC_RPC_H if(update) f=new ioxfile(name); else f=new oxfile(name); #else ostringstream buf; buf << name << ": XDR write support not enabled"; error(buf); #endif } else if(mode == "") { if(update) { char c=comment.empty() ? (char) 0 : comment[0]; f=new iofile(name,c); } else f=new ofile(name); } else { f=NULL; ostringstream buf; buf << name << ": invalid file mode '" << mode << "'"; error(buf); } f->open(); if(update) f->seek(0,false); return f; } bool eof(file *f) { return f->eof(); } bool eol(file *f) { return f->eol(); } bool error(file *f) { return f->error(); } void clear(file *f) { f->clear(); } void close(file *f) { f->close(); } Int precision(file *f=NULL, Int digits=0) { if(f == 0) f=&camp::Stdout; return f->precision(digits); } void flush(file *f) { f->flush(); } string getc(file *f) { char c=0; if(f->isOpen()) f->read(c); static char str[1]; str[0]=c; return string(str); } Int tell(file *f) { return f->tell(); } void seek(file *f, Int pos) { f->seek(pos,pos >= 0); } void seekeof(file *f) { f->seek(0,false); } string :namePart(file f) { return f.filename(); } string :modePart(file f) { return f.FileMode(); } // Set file dimensions file* :dimensionSetHelper(Int nx=-1, Int ny=-1, Int nz=-1, file *f) { f->dimension(nx,ny,nz); return f; } callable* :dimensionSet(file *f) { return new thunk(new bfunc(dimensionSetHelper),f); } array * :dimensionPart(file f) { array *a=new array(3); (*a)[0]=f.Nx(); (*a)[1]=f.Ny(); (*a)[2]=f.Nz(); return a; } // Set file f to read arrays in line-at-a-time mode file* :lineSetHelper(bool b=true, file *f) { f->LineMode(b); return f; } callable* :lineSet(file *f) { return new thunk(new bfunc(lineSetHelper),f); } bool :linePart(file f) { return f.LineMode(); } // Set file to read comma-separated values file* :csvSetHelper(bool b=true, file *f) { f->CSVMode(b); return f; } callable* :csvSet(file *f) { return new thunk(new bfunc(csvSetHelper),f); } bool :csvPart(file f) { return f.CSVMode(); } // Set file to read whitespace-separated values file* :wordSetHelper(bool b=true, file *f) { f->WordMode(b); return f; } callable* :wordSet(file *f) { return new thunk(new bfunc(wordSetHelper),f); } bool :wordPart(file f) { return f.WordMode(); } // Set file to read/write single precision real XDR values. file* :singlerealSetHelper(bool b=true, file *f) { f->SingleReal(b); return f; } callable* :singlerealSet(file *f) { return new thunk(new bfunc(singlerealSetHelper),f); } bool :singlerealPart(file f) { return f.SingleReal(); } // Set file to read/write single precision int XDR values. file* :singleintSetHelper(bool b=true, file *f) { f->SingleInt(b); return f; } callable* :singleintSet(file *f) { return new thunk(new bfunc(singleintSetHelper),f); } bool :singleintPart(file f) { return f.SingleInt(); } // Set file to read/write signed int XDR values. file* :signedintSetHelper(bool b=true, file *f) { f->SignedInt(b); return f; } callable* :signedintSet(file *f) { return new thunk(new bfunc(signedintSetHelper),f); } bool :signedintPart(file f) { return f.SignedInt(); } // Set file to read an arrayi (i int sizes followed by an i-dimensional array) file* :readSetHelper(Int i, file *f) { switch(i) { case 1: f->dimension(-2); break; case 2: f->dimension(-2,-2); break; case 3: f->dimension(-2,-2,-2); break; default: f->dimension(); } return f; } callable* :readSet(file *f) { return new thunk(new bfunc(readSetHelper),f); } // Delete file named s. Int delete(string s) { s=outpath(s); Int rc=unlink(s.c_str()); if(rc == 0 && verbose > 0) cout << "Deleted " << s << endl; return rc; } // Rename file "from" to file "to". Int rename(string from, string to) { from=outpath(from); to=outpath(to); Int rc=rename(from.c_str(),to.c_str()); if(rc == 0 && verbose > 0) cout << "Renamed " << from << " to " << to << endl; return rc; } // Create a unique temporary file name. string mktemp(string s) { char *S=Strdup(s+"XXXXXX"); int fd=mkstemp(S); if(fd < 0) { ostringstream buf; buf << "Could not create unique temporary filename based on " << s; error(buf); } return S; } asymptote-2.37/runhistory.in000066400000000000000000000117771265434602500162740ustar00rootroot00000000000000/***** * runhistory.in * * Runtime functions for history operations. * *****/ pair => primPair() picture* => primPicture() stringarray* => stringArray() #include "array.h" #include "mathop.h" #include "builtin.h" using namespace camp; using namespace settings; using namespace vm; using namespace run; typedef array stringarray; using types::stringArray; #if defined(HAVE_LIBREADLINE) && defined(HAVE_LIBCURSES) #include #include struct historyState { bool store; HISTORY_STATE state; }; typedef mem::map historyMap_t; historyMap_t historyMap; static HISTORY_STATE history_save; // Store a deep copy of the current readline history in dest. void store_history(HISTORY_STATE *dest) { HISTORY_STATE *src=history_get_history_state(); if(src) { *dest=*src; for(Int i=0; i < src->length; ++i) dest->entries[i]=src->entries[i]; free(src); } } stringarray* get_history(Int n) { int N=intcast(n); if(N <= 0) N=history_length; else N=Min(N,history_length); array *a=new array((size_t) N); int offset=history_length-N+1; for(int i=0; i < N; ++i) { HIST_ENTRY *last=history_get(offset+i); string s=last ? last->line : ""; (*a)[i]=s; } return a; } string historyfilename(const string &name) { return historyname+"_"+name; } #endif namespace run { extern string emptystring; #if defined(HAVE_LIBREADLINE) && defined(HAVE_LIBCURSES) void init_readline(bool tabcompletion) { rl_bind_key('\t',tabcompletion ? rl_complete : rl_insert); } #endif void cleanup() { #if defined(HAVE_LIBREADLINE) && defined(HAVE_LIBCURSES) store_history(&history_save); int nlines=intcast(getSetting("historylines")); for(historyMap_t::iterator h=historyMap.begin(); h != historyMap.end(); ++h) { history_set_history_state(&h->second.state); if(h->second.store) { stifle_history(nlines); write_history(historyfilename(h->first).c_str()); unstifle_history(); } } history_set_history_state(&history_save); #endif #ifdef HAVE_LIBGSL trans::GSLrngFree(); #endif } } // Autogenerated routines: // Return the last n lines of the history named name. stringarray* history(string name, Int n=1) { #if defined(HAVE_LIBREADLINE) && defined(HAVE_LIBCURSES) bool newhistory=historyMap.find(name) == historyMap.end(); string filename; if(newhistory) { filename=historyfilename(name); std::ifstream exists(filename.c_str()); if(!exists) return new array(0); } store_history(&history_save); HISTORY_STATE& history=historyMap[name].state; history_set_history_state(&history); if(newhistory) read_history(filename.c_str()); array *a=get_history(n); store_history(&history); history_set_history_state(&history_save); return a; #else unused(&n); return new array(0); #endif } // Return the last n lines of the interactive history. stringarray* history(Int n=0) { #if defined(HAVE_LIBREADLINE) && defined(HAVE_LIBCURSES) return get_history(n); #else unused(&n); return new array(0); #endif } // Prompt for a string using prompt, the GNU readline library, and a // local history named name. string readline(string prompt=emptystring, string name=emptystring, bool tabcompletion=false) { if(!(isatty(STDIN_FILENO) || getSetting("inpipe") >= 0)) return emptystring; #if defined(HAVE_LIBREADLINE) && defined(HAVE_LIBCURSES) init_readline(tabcompletion); store_history(&history_save); bool newhistory=historyMap.find(name) == historyMap.end(); historyState& h=historyMap[name]; HISTORY_STATE& history=h.state; history_set_history_state(&history); if(newhistory) read_history(historyfilename(name).c_str()); static char *line=NULL; /* Return the memory to the free pool if the buffer has already been allocated. */ if(line) { free(line); line=NULL; } /* Get a line from the user. */ line=readline(prompt.c_str()); if(!line) cout << endl; history_set_history_state(&history_save); return line ? string(line) : emptystring; #else cout << prompt; string s; getline(cin,s); unused(&tabcompletion); // Avoid unused variable warning message. return s; #endif } // Save a string in a local history named name. // If store=true, store the local history in the file historyfilename(name). void saveline(string name, string value, bool store=true) { #if defined(HAVE_LIBREADLINE) && defined(HAVE_LIBCURSES) store_history(&history_save); bool newhistory=historyMap.find(name) == historyMap.end(); historyState& h=historyMap[name]; h.store=store; HISTORY_STATE& history=h.state; history_set_history_state(&history); if(newhistory) read_history(historyfilename(name).c_str()); if(value != "") { add_history(value.c_str()); if(store) { std::ofstream hout(historyfilename(name).c_str(),std::ios::app); hout << value << endl; } } store_history(&history); history_set_history_state(&history_save); #else unused(&store); #endif } asymptote-2.37/runlabel.in000066400000000000000000000307161265434602500156440ustar00rootroot00000000000000/***** * 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, bool pdf=false, 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 cmd; cmd.push_back(getSetting("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 cmd.push_back("-sDEVICE=eps2write"); 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; if(!pdf) gs << newl; // Workaround broken stringstream container in MacOS 10.9 libc++. #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__ ) 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 nodes; solvedKnot node; bool cyclic=false; 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': { if(active) { if(cyclic) { 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); } } else { node.post=node.point; node.straight=false; nodes.push_back(node); } if(cyclic) // Discard noncyclic paths. P->push(path(nodes,nodes.size(),cyclic)); nodes.clear(); } active=false; cyclic=false; 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': { cyclic=true; 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("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("tex"); bool xe=settings::xe(texengine) || settings::context(texengine); texfile tex(texname,b,true); tex.miniprologue(); for(size_t i=0; i < n; ++i) { tex.setfont(read(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(s,i)+"\\ %"); } tex.epilogue(true); tex.close(); int status=opentex(texname,prefix,!xe); string pdfname,pdfname2,psname2; bool keep=getSetting("keep"); if(!status) { if(xe) { pdfname=auxname(prefix,"pdf"); pdfname2=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 pcmd; pcmd.push_back(getSetting("gs")); pcmd.push_back("-q"); pcmd.push_back("-dNOCACHE"); pcmd.push_back("-dNOPAUSE"); pcmd.push_back("-dBATCH"); if(safe) pcmd.push_back("-dSAFER"); pcmd.push_back("-sDEVICE=pdfwrite"); pcmd.push_back("-sOutputFile="+pdfname2); pcmd.push_back(pdfname); status=System(pcmd,0,true,"gs"); if(status == 0) { mem::vector cmd; cmd.push_back(getSetting("gs")); cmd.push_back("-q"); cmd.push_back("-dNOCACHE"); cmd.push_back("-dNOPAUSE"); cmd.push_back("-dBATCH"); if(safe) cmd.push_back("-dSAFER"); cmd.push_back("-sDEVICE=eps2write"); // Work around eps2write bug that forces all postscript to first page. cmd.push_back("-sOutputFile="+psname2+"%d"); cmd.push_back(pdfname2); status=System(cmd,0,true,"gs"); for(unsigned int i=1; i <= n ; ++i) { ostringstream buf; buf << psname2.c_str() << i; const char *name=buf.str().c_str(); std::ifstream in(name,std::ios::binary); ps << in.rdbuf(); ps << "(>\n) print flush\n"; in.close(); if(!keep) unlink(name); } ps.close(); } } else { if(!fs::exists(dviname)) return new array(n); mem::vector dcmd; dcmd.push_back(getSetting("dvips")); dcmd.push_back("-R"); dcmd.push_back("-Pdownload35"); dcmd.push_back("-D600"); push_split(dcmd,getSetting("dvipsOptions")); if(verbose <= 2) dcmd.push_back("-q"); dcmd.push_back("-o"+psname); dcmd.push_back(dviname); status=System(dcmd,0,true,"dvips"); } } if(status != 0) error("texpath failed"); if(!keep) { // Delete temporary files. unlink(texname.c_str()); if(!getSetting("keepaux")) unlink(auxname(prefix,"aux").c_str()); unlink(auxname(prefix,"log").c_str()); if(xe) { unlink(pdfname.c_str()); unlink(pdfname2.c_str()); } else unlink(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,true,0.1) : readpath(psname,keep,false,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("textoutformat")); string textname=auxname(prefix,getSetting("textextension")); std::ofstream text(textname.c_str()); if(!text) cannotwrite(textname); for(size_t i=0; i < n; ++i) { text << getSetting("textprologue") << newl << read(p,i).Font() << newl << read(s,i) << newl << getSetting("textepilogue") << endl; } text.close(); string psname=auxname(prefix,"ps"); std::ofstream ps(psname.c_str()); if(!ps) cannotwrite(psname); showpath(ps); mem::vector cmd; cmd.push_back(getSetting("textcommand")); push_split(cmd,getSetting("textcommandOptions")); cmd.push_back(textname); iopipestream typesetter(cmd); typesetter.block(true,false); mem::vector cmd2; cmd2.push_back(getSetting("gs")); cmd2.push_back("-q"); cmd2.push_back("-dNOCACHE"); cmd2.push_back("-dNOPAUSE"); cmd2.push_back("-dBATCH"); cmd2.push_back("-P"); if(safe) cmd2.push_back("-dSAFER"); cmd2.push_back("-sDEVICE=eps2write"); cmd2.push_back("-sOutputFile=-"); cmd2.push_back("-"); iopipestream gs(cmd2,"gs","Ghostscript"); gs.block(false,false); // TODO: Simplify by connecting the pipes directly. while(true) { 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("keep"); if(!keep) // Delete temporary files. unlink(textname.c_str()); return readpath(psname,keep,false,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("keep")); return a->size() > 0 ? read(a,0) : a; } asymptote-2.37/runmath.in000066400000000000000000000113641265434602500155140ustar00rootroot00000000000000/***** * runmath.in * * Runtime functions for math operations. * *****/ pair => primPair() realarray* => realArray() pairarray* => pairArray() #include #include "mathop.h" #include "path.h" using namespace camp; typedef array realarray; typedef array pairarray; using types::realArray; using types::pairArray; using run::integeroverflow; using vm::frame; const char *invalidargument="invalid argument"; extern uint32_t CLZ(uint32_t a); // Return the factorial of a non-negative integer using a lookup table. Int factorial(Int n) { static Int *table; static Int size=0; if(size == 0) { Int f=1; size=2; while(f <= Int_MAX/size) f *= (size++); table=new Int[size]; table[0]=f=1; for(Int i=1; i < size; ++i) { f *= i; table[i]=f; } } if(n >= size) integeroverflow(0); return table[n]; } static inline Int Round(double x) { return Int(x+((x >= 0) ? 0.5 : -0.5)); } inline Int sgn(double x) { return (x > 0.0 ? 1 : (x < 0.0 ? -1 : 0)); } static bool initializeRandom=true; void Srand(Int seed) { initializeRandom=false; const int n=256; static char state[n]; initstate(intcast(seed),state,n); } // Autogenerated routines: real ^(real x, Int y) { return pow(x,y); } pair ^(pair z, Int y) { return pow(z,y); } Int quotient(Int x, Int y) { if(y == 0) dividebyzero(); if(y == -1) return Negate(x); // Implementation-independent definition of integer division: round down return (x-portableMod(x,y))/y; } Int abs(Int x) { return Abs(x); } Int sgn(real x) { return sgn(x); } Int rand() { if(initializeRandom) Srand(1); return random(); } void srand(Int seed) { Srand(seed); } // a random number uniformly distributed in the interval [0,1] real unitrand() { return ((real) random())/RANDOM_MAX; } Int ceil(real x) { return Intcast(ceil(x)); } Int floor(real x) { return Intcast(floor(x)); } Int round(real x) { if(validInt(x)) return Round(x); integeroverflow(0); } Int Ceil(real x) { return Ceil(x); } Int Floor(real x) { return Floor(x); } Int Round(real x) { return Round(Intcap(x)); } real fmod(real x, real y) { if (y == 0.0) dividebyzero(); return fmod(x,y); } real atan2(real y, real x) { return atan2(y,x); } real hypot(real x, real y) { return hypot(x,y); } real remainder(real x, real y) { return remainder(x,y); } real Jn(Int n, real x) { return jn(n,x); } real Yn(Int n, real x) { return yn(n,x); } real erf(real x) { return erf(x); } real erfc(real x) { return erfc(x); } Int factorial(Int n) { if(n < 0) error(invalidargument); return factorial(n); } Int choose(Int n, Int k) { if(n < 0 || k < 0 || k > n) error(invalidargument); Int f=1; Int r=n-k; for(Int i=n; i > r; --i) { if(f > Int_MAX/i) integeroverflow(0); f=(f*i)/(n-i+1); } return f; } real gamma(real x) { #ifdef HAVE_TGAMMA return tgamma(x); #else real lg = lgamma(x); return signgam*exp(lg); #endif } realarray *quadraticroots(real a, real b, real c) { quadraticroots q(a,b,c); array *roots=new array(q.roots); if(q.roots >= 1) (*roots)[0]=q.t1; if(q.roots == 2) (*roots)[1]=q.t2; return roots; } pairarray *quadraticroots(explicit pair a, explicit pair b, explicit pair c) { Quadraticroots q(a,b,c); array *roots=new array(q.roots); if(q.roots >= 1) (*roots)[0]=q.z1; if(q.roots == 2) (*roots)[1]=q.z2; return roots; } realarray *cubicroots(real a, real b, real c, real d) { cubicroots q(a,b,c,d); array *roots=new array(q.roots); if(q.roots >= 1) (*roots)[0]=q.t1; if(q.roots >= 2) (*roots)[1]=q.t2; if(q.roots == 3) (*roots)[2]=q.t3; return roots; } // Logical operations bool !(bool b) { return !b; } bool :boolMemEq(frame *a, frame *b) { return a == b; } bool :boolMemNeq(frame *a, frame *b) { return a != b; } bool :boolFuncEq(callable *a, callable *b) { return a->compare(b); } bool :boolFuncNeq(callable *a, callable *b) { return !(a->compare(b)); } // Bit operations Int AND(Int a, Int b) { return a & b; } Int OR(Int a, Int b) { return a | b; } Int XOR(Int a, Int b) { return a ^ b; } Int NOT(Int a) { return ~a; } Int CLZ(Int a) { if((uint32_t) a > 0xFFFFFFFF) return -1; return CLZ((uint32_t) a); } Int CTZ(Int a) { if((uint32_t) a > 0xFFFFFFFF) return -1; #if __GNUC__ return __builtin_ctz(a); #else // find the number of trailing zeros in a 32-bit number static const int MultiplyDeBruijnBitPosition[32] = { 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 }; return MultiplyDeBruijnBitPosition[((uint32_t)((a & -a) * 0x077CB531U)) >> 27]; #endif } asymptote-2.37/runpair.in000066400000000000000000000102261265434602500155120ustar00rootroot00000000000000/***** * runpair.in * * Runtime functions for pair operations. * *****/ pair => primPair() #include "pair.h" using namespace camp; namespace run { extern pair zero; } pair sin(pair z) { return pair(sin(z.getx())*cosh(z.gety()),cos(z.getx())*sinh(z.gety())); } pair exp(pair z) { return exp(z.getx())*expi(z.gety()); } pair gamma(pair z) { static double p[]={0.99999999999980993,676.5203681218851,-1259.1392167224028, 771.32342877765313,-176.61502916214059,12.507343278686905, -0.13857109526572012,9.9843695780195716e-6, 1.5056327351493116e-7}; static int n=sizeof(p)/sizeof(double); static double root2pi=sqrt(2*PI); if(z.getx() < 0.5) return PI/(sin(PI*z)*gamma(1.0-z)); z -= 1.0; pair x=p[0]; for(int i=1; i < n; ++i) x += p[i]/(z+i); pair t=n-1.5+z; return root2pi*pow(t,z+0.5)*exp(-t)*x; } // Autogenerated routines: pair :pairZero() { return zero; } pair :realRealToPair(real x, real y) { return pair(x,y); } pair :pairNegate(pair z) { return -z; } real xpart:pairXPart(pair z) { return z.getx(); } real ypart:pairYPart(pair z) { return z.gety(); } real length(pair z) { return z.length(); } real abs(pair z) { return z.length(); } pair sqrt(explicit pair z) { return Sqrt(z); } // Return the angle of z in radians. real angle(pair z, bool warn=true) { if(!warn && z.getx() == 0.0 && z.gety() == 0.0) return 0.0; return z.angle(); } // Return the angle of z in degrees in the interval [0,360). real degrees(pair z, bool warn=true) { if(!warn && z.getx() == 0.0 && z.gety() == 0.0) return 0.0; return principalBranch(degrees(z.angle())); } // Convert degrees to radians. real radians(real degrees) { return radians(degrees); } // Convert radians to degrees. real degrees(real radians) { return degrees(radians); } // Convert radians to degrees in [0,360). real Degrees(real radians) { return principalBranch(degrees(radians)); } real Sin(real deg) { int n=(int) (deg/90.0); if(deg == n*90.0) { int m=n % 4; if(m < 0) m += 4; if(m == 1) return 1; if(m == 3) return -1; return 0.0; } return sin(radians(deg)); } real Cos(real deg) { int n=(int) (deg/90.0); if(deg == n*90.0) { int m=n % 4; if(m < 0) m += 4; if(m == 0) return 1; if(m == 2) return -1; return 0.0; } return cos(radians(deg)); } real Tan(real deg) { int n=(int) (deg/90.0); if(deg == n*90.0) { int m=n % 4; if(m < 0) m += 4; if(m == 1) return HUGE_VAL; if(m == 3) return -HUGE_VAL; return 0.0; } return tan(radians(deg)); } real aSin(real x) { return degrees(asin(x)); } real aCos(real x) { return degrees(acos(x)); } real aTan(real x) { return degrees(atan(x)); } pair unit(pair z) { return unit(z); } pair dir(real degrees) { return expi(radians(degrees)); } pair dir(explicit pair z) { return unit(z); } pair expi(real angle) { return expi(angle); } pair exp(explicit pair z) { return exp(z); } pair log(explicit pair z) { return pair(log(z.length()),z.angle()); } pair sin(explicit pair z) { return sin(z); } pair cos(explicit pair z) { return pair(cos(z.getx())*cosh(z.gety()),-sin(z.getx())*sinh(z.gety())); } // Complex Gamma function pair gamma(explicit pair z) { return gamma(z); } pair conj(pair z) { return conj(z); } pair realmult(pair z, pair w) { return pair(z.getx()*w.getx(),z.gety()*w.gety()); } // To avoid confusion, a dot product requires explicit pair arguments. real dot(explicit pair z, explicit pair w) { return dot(z,w); } // Return the 2D scalar cross product z.x*w.y-z.y*w.x. real cross(explicit pair z, explicit pair w) { return cross(z,w); } pair bezier(pair a, pair b, pair c, pair d, real t) { real onemt=1-t; real onemt2=onemt*onemt; return onemt2*onemt*a+t*(3.0*(onemt2*b+t*onemt*c)+t*t*d); } pair bezierP(pair a, pair b, pair c, pair d, real t) { return 3.0*(t*t*(d-a+3.0*(b-c))+t*(2.0*(a+c)-4.0*b)+b-a); } pair bezierPP(pair a, pair b, pair c, pair d, real t) { return 6.0*(t*(d-a+3.0*(b-c))+a+c-2.0*b); } pair bezierPPP(pair a, pair b, pair c, pair d) { return 6.0*(d-a+3.0*(b-c)); } asymptote-2.37/runpath.in000066400000000000000000000202601265434602500155120ustar00rootroot00000000000000/***** * runpicture.in * * Runtime functions for picture operations. * *****/ pen => primPen() pair => primPair() path => primPath() transform => primTransform() realarray* => realArray() realarray2* => realArray2() patharray* => pathArray() penarray* => penArray() #include "path.h" #include "arrayop.h" #include "predicates.h" using namespace camp; using namespace vm; typedef array realarray; typedef array realarray2; typedef array patharray; using types::realArray; using types::realArray2; using types::pathArray; Int windingnumber(array *p, camp::pair z) { size_t size=checkArray(p); Int count=0; for(size_t i=0; i < size; i++) count += read(p,i)->windingnumber(z); return count; } // Autogenerated routines: path :nullPath() { return nullpath; } bool ==(path a, path b) { return a == b; } bool !=(path a, path b) { return !(a == b); } pair point(path p, Int t) { return p.point((Int) t); } pair point(path p, real t) { return p.point(t); } pair precontrol(path p, Int t) { return p.precontrol((Int) t); } pair precontrol(path p, real t) { return p.precontrol(t); } pair postcontrol(path p, Int t) { return p.postcontrol((Int) t); } pair postcontrol(path p, real t) { return p.postcontrol(t); } pair dir(path p, Int t, Int sign=0, bool normalize=true) { return p.dir(t,sign,normalize); } pair dir(path p, real t, bool normalize=true) { return p.dir(t,normalize); } pair accel(path p, Int t, Int sign=0) { return p.accel(t,sign); } pair accel(path p, real t) { return p.accel(t); } real radius(path p, real t) { pair v=p.dir(t,false); pair a=p.accel(t); real d=dot(a,v); real v2=v.abs2(); real a2=a.abs2(); real denom=v2*a2-d*d; real r=v2*sqrt(v2); return denom > 0 ? r/sqrt(denom) : 0.0; } path reverse(path p) { return p.reverse(); } path subpath(path p, Int a, Int b) { return p.subpath((Int) a, (Int) b); } path subpath(path p, real a, real b) { return p.subpath(a,b); } path nurb(pair z0, pair z1, pair z2, pair z3, real w0, real w1, real w2, real w3, Int m) { return nurb(z0,z1,z2,z3,w0,w1,w2,w3,m); } Int length(path p) { return p.length(); } bool cyclic(path p) { return p.cyclic(); } bool straight(path p, Int t) { return p.straight(t); } path unstraighten(path p) { return p.unstraighten(); } bool piecewisestraight(path p) { return p.piecewisestraight(); } real arclength(path p) { return p.arclength(); } real arctime(path p, real L) { return p.arctime(L); } real dirtime(path p, pair z) { return p.directiontime(z); } realarray* intersect(path p, path q, real fuzz=-1) { bool exact=fuzz <= 0.0; if(fuzz < 0) fuzz=BigFuzz*::max(::max(length(p.max()),length(p.min())), ::max(length(q.max()),length(q.min()))); std::vector S,T; real s,t; if(intersections(s,t,S,T,p,q,fuzz,true,exact)) { array *V=new array(2); (*V)[0]=s; (*V)[1]=t; return V; } return new array(0); } realarray2* intersections(path p, path q, real fuzz=-1) { bool exact=fuzz <= 0.0; if(fuzz < 0.0) fuzz=BigFuzz*::max(::max(length(p.max()),length(p.min())), ::max(length(q.max()),length(q.min()))); real s,t; std::vector S,T; intersections(s,t,S,T,p,q,fuzz,false,true); size_t n=S.size(); if(n == 0 && !exact) { if(intersections(s,t,S,T,p,q,fuzz,true,false)) { array *V=new array(1); array *Vi=new array(2); (*V)[0]=Vi; (*Vi)[0]=s; (*Vi)[1]=t; return V; } } array *V=new array(n); for(size_t i=0; i < n; ++i) { array *Vi=new array(2); (*V)[i]=Vi; (*Vi)[0]=S[i]; (*Vi)[1]=T[i]; } stable_sort(V->begin(),V->end(),run::compare2()); return V; } realarray* intersections(path p, explicit pair a, explicit pair b, real fuzz=-1) { if(fuzz < 0) fuzz=BigFuzz*::max(::max(length(p.max()),length(p.min())), ::max(length(a),length(b))); std::vector S; intersections(S,p,a,b,fuzz); sort(S.begin(),S.end()); size_t n=S.size(); array *V=new array(n); for(size_t i=0; i < n; ++i) (*V)[i]=S[i]; return V; } // Return the intersection point of the extensions of the line segments // PQ and pq. pair extension(pair P, pair Q, pair p, pair q) { pair ac=P-Q; pair bd=q-p; real det=ac.getx()*bd.gety()-ac.gety()*bd.getx(); if(det == 0) return pair(infinity,infinity); return P+((p.getx()-P.getx())*bd.gety()-(p.gety()-P.gety())*bd.getx())*ac/det; } Int size(path p) { return p.size(); } path &(path p, path q) { return camp::concat(p,q); } pair min(explicit path p) { return p.min(); } pair max(explicit path p) { return p.max(); } Int size(patharray *p) { size_t size=checkArray(p); Int count=0; for (size_t i = 0; i < size; i++) count += read(p,i)->size(); return count; } pair min(patharray *p) { size_t size=checkArray(p); if(size == 0) error(nopoints); path *g = p->read(0); pair z = g->min(); double minx = z.getx(), miny = z.gety(); for (size_t i = 1; i < size; ++i) { path *g = p->read(i); pair z = g->min(); double x = z.getx(), y = z.gety(); if (x < minx) minx = x; if (y < miny) miny = y; } return pair(minx, miny); } pair max(patharray *p) { size_t size=checkArray(p); if(size == 0) error(nopoints); path *g = p->read(0); pair z = g->max(); double maxx = z.getx(), maxy = z.gety(); for (size_t i = 1; i < size; ++i) { path *g = p->read(i); pair z = g->max(); double x = z.getx(), y = z.gety(); if (x > maxx) maxx = x; if (y > maxy) maxy = y; } return pair(maxx, maxy); } pair minAfterTransform(transform t, patharray *p) { size_t size=checkArray(p); if(size == 0) error(nopoints); path g = p->read(0)->transformed(t); pair z = g.min(); double minx = z.getx(), miny = z.gety(); for (size_t i = 1; i < size; ++i) { path g = p->read(i)->transformed(t); pair z = g.min(); double x = z.getx(), y = z.gety(); if (x < minx) minx = x; if (y < miny) miny = y; } return pair(minx, miny); } pair maxAfterTransform(transform t, patharray *p) { size_t size=checkArray(p); if(size == 0) error(nopoints); path g = p->read(0)->transformed(t); pair z = g.max(); double maxx = z.getx(), maxy = z.gety(); for (size_t i = 1; i < size; ++i) { path g = p->read(i)->transformed(t); pair z = g.max(); double x = z.getx(), y = z.gety(); if (x > maxx) maxx = x; if (y > maxy) maxy = y; } return pair(maxx, maxy); } realarray *mintimes(path p) { array *V=new array(2); pair z=p.mintimes(); (*V)[0]=z.getx(); (*V)[1]=z.gety(); return V; } realarray *maxtimes(path p) { array *V=new array(2); pair z=p.maxtimes(); (*V)[0]=z.getx(); (*V)[1]=z.gety(); return V; } real relativedistance(real theta, real phi, real t, bool atleast) { return camp::velocity(theta,phi,tension(t,atleast)); } Int windingnumber(patharray *p, pair z) { return windingnumber(p,z); } bool inside(explicit patharray *g, pair z, pen fillrule=CURRENTPEN) { return fillrule.inside(windingnumber(g,z)); } bool inside(path g, pair z, pen fillrule=CURRENTPEN) { return fillrule.inside(g.windingnumber(z)); } // Return a positive (negative) value if a--b--c--cycle is oriented // counterclockwise (clockwise) or zero if all three points are colinear. // Equivalently, return a positive (negative) value if c lies to the // left (right) of the line through a and b or zero if c lies on this line. // The value returned is the determinant // |a.x a.y 1| // |b.x b.y 1| // |c.x c.y 1| // real orient(pair a, pair b, pair c) { return orient2d(a,b,c); } // Return a positive (negative) value if d lies inside (outside) // the circle passing through the counterclockwise-oriented points a,b,c // or zero if d lies on this circle. // The value returned is the determinant // |a.x a.y a.x^2+a.y^2 1| // |b.x b.y b.x^2+b.y^2 1| // |c.x c.y c.x^2+c.y^2 1| // |d.x d.y d.x^2+d.y^2 1| real incircle(pair a, pair b, pair c, pair d) { return incircle(a.getx(),a.gety(),b.getx(),b.gety(),c.getx(),c.gety(), d.getx(),d.gety()); } asymptote-2.37/runpath3d.in000066400000000000000000000175631265434602500157550ustar00rootroot00000000000000/***** * runpath3.in * * Runtime functions for path3 operations. * *****/ pair => primPair() triple => primTriple() path3 => primPath3() boolarray* => booleanArray() realarray* => realArray() realarray2* => realArray2() triplearray* => tripleArray() triplearray2* => tripleArray2() #include "path3.h" #include "array.h" #include "drawsurface.h" #include "predicates.h" using namespace camp; using namespace vm; typedef array boolarray; typedef array realarray; typedef array realarray2; typedef array triplearray; typedef array triplearray2; using types::booleanArray; using types::realArray; using types::realArray2; using types::tripleArray; using types::tripleArray2; // Autogenerated routines: path3 path3(triplearray *pre, triplearray *point, triplearray *post, boolarray *straight, bool cyclic) { size_t n=checkArrays(pre,point); checkEqual(n,checkArray(post)); checkEqual(n,checkArray(straight)); mem::vector nodes(n); for(size_t i=0; i < n; ++i) { nodes[i].pre=read(pre,i); nodes[i].point=read(point,i); nodes[i].post=read(post,i); nodes[i].straight=read(straight,i); } return path3(nodes,(Int) n,cyclic); } path3 :nullPath3() { return nullpath3; } bool ==(path3 a, path3 b) { return a == b; } bool !=(path3 a, path3 b) { return !(a == b); } triple point(path3 p, Int t) { return p.point((Int) t); } triple point(path3 p, real t) { return p.point(t); } triple precontrol(path3 p, Int t) { return p.precontrol((Int) t); } triple precontrol(path3 p, real t) { return p.precontrol(t); } triple postcontrol(path3 p, Int t) { return p.postcontrol((Int) t); } triple postcontrol(path3 p, real t) { return p.postcontrol(t); } triple dir(path3 p, Int t, Int sign=0, bool normalize=true) { return p.dir(t,sign,normalize); } triple dir(path3 p, real t, bool normalize=true) { return p.dir(t,normalize); } triple accel(path3 p, Int t, Int sign=0) { return p.accel(t,sign); } triple accel(path3 p, real t) { return p.accel(t); } real radius(path3 p, real t) { triple v=p.dir(t,false); triple a=p.accel(t); real d=dot(a,v); real v2=v.abs2(); real a2=a.abs2(); real denom=v2*a2-d*d; real r=v2*sqrt(v2); return denom > 0 ? r/sqrt(denom) : 0.0; } real radius(triple z0, triple c0, triple c1, triple z1, real t) { triple v=(3.0*(z1-z0)+9.0*(c0-c1))*t*t+(6.0*(z0+c1)-12.0*c0)*t+3.0*(c0-z0); triple a=6.0*(z1-z0+3.0*(c0-c1))*t+6.0*(z0+c1)-12.0*c0; real d=dot(a,v); real v2=v.abs2(); real a2=a.abs2(); real denom=v2*a2-d*d; real r=v2*sqrt(v2); return denom > 0 ? r/sqrt(denom) : 0.0; } path3 reverse(path3 p) { return p.reverse(); } path3 subpath(path3 p, Int a, Int b) { return p.subpath((Int) a, (Int) b); } path3 subpath(path3 p, real a, real b) { return p.subpath(a,b); } Int length(path3 p) { return p.length(); } bool cyclic(path3 p) { return p.cyclic(); } bool straight(path3 p, Int t) { return p.straight(t); } path3 unstraighten(path3 p) { return p.unstraighten(); } // Return the maximum perpendicular deviation of segment i of path3 g // from a straight line. real straightness(path3 p, Int t) { if(p.straight(t)) return 0; triple z0=p.point(t); triple u=unit(p.point(t+1)-z0); return ::max(length(perp(p.postcontrol(t)-z0,u)), length(perp(p.precontrol(t+1)-z0,u))); } // Return the maximum perpendicular deviation of z0..controls c0 and c1..z1 // from a straight line. real straightness(triple z0, triple c0, triple c1, triple z1) { triple u=unit(z1-z0); return ::max(length(perp(c0-z0,u)),length(perp(c1-z0,u))); } bool piecewisestraight(path3 p) { return p.piecewisestraight(); } real arclength(path3 p) { return p.arclength(); } real arctime(path3 p, real dval) { return p.arctime(dval); } realarray* intersect(path3 p, path3 q, real fuzz=-1) { bool exact=fuzz <= 0.0; if(fuzz < 0) fuzz=BigFuzz*::max(::max(length(p.max()),length(p.min())), ::max(length(q.max()),length(q.min()))); std::vector S,T; real s,t; if(intersections(s,t,S,T,p,q,fuzz,true,exact)) { array *V=new array(2); (*V)[0]=s; (*V)[1]=t; return V; } else return new array(0); } realarray2* intersections(path3 p, path3 q, real fuzz=-1) { bool exact=fuzz <= 0.0; if(fuzz < 0) fuzz=BigFuzz*::max(::max(length(p.max()),length(p.min())), ::max(length(q.max()),length(q.min()))); bool single=!exact; real s,t; std::vector S,T; bool found=intersections(s,t,S,T,p,q,fuzz,single,exact); if(!found) return new array(0); array *V; if(single) { V=new array(1); array *Vi=new array(2); (*V)[0]=Vi; (*Vi)[0]=s; (*Vi)[1]=t; } else { size_t n=S.size(); V=new array(n); for(size_t i=0; i < n; ++i) { array *Vi=new array(2); (*V)[i]=Vi; (*Vi)[0]=S[i]; (*Vi)[1]=T[i]; } } stable_sort(V->begin(),V->end(),run::compare2()); return V; } realarray* intersect(path3 p, triplearray2 *P, real fuzz=-1) { triple *A; copyArray2C(A,P,true,4); if(fuzz <= 0) fuzz=BigFuzz*::max(::max(length(p.max()),length(p.min())), norm(A,16)); std::vector T,U,V; bool found=intersections(T,U,V,p,A,fuzz,true); delete[] A; if(found) { array *W=new array(3); (*W)[0]=T[0]; (*W)[1]=U[0]; (*W)[2]=V[0]; return W; } else return new array(0); } realarray2* intersections(path3 p, triplearray2 *P, real fuzz=-1) { triple *A; copyArray2C(A,P,true,4); if(fuzz <= 0) fuzz=BigFuzz*::max(::max(length(p.max()),length(p.min())), norm(A,16)); std::vector T,U,V; intersections(T,U,V,p,A,fuzz,false); delete[] A; size_t n=T.size(); array *W=new array(n); for(size_t i=0; i < n; ++i) { array *Wi=new array(3); (*W)[i]=Wi; (*Wi)[0]=T[i]; (*Wi)[1]=U[i]; (*Wi)[2]=V[i]; } return W; // Sorting will done in asy. } Int size(path3 p) { return p.size(); } path3 &(path3 p, path3 q) { return camp::concat(p,q); } triple min(path3 p) { return p.min(); } triple max(path3 p) { return p.max(); } realarray *mintimes(path3 p) { array *V=new array(3); triple v=p.mintimes(); (*V)[0]=v.getx(); (*V)[1]=v.gety(); (*V)[2]=v.getz(); return V; } realarray *maxtimes(path3 p) { array *V=new array(3); triple v=p.maxtimes(); (*V)[0]=v.getx(); (*V)[1]=v.gety(); (*V)[2]=v.getz(); return V; } path3 Operator *(realarray2 *t, path3 g) { return transformed(*t,g); } pair minratio(path3 g) { return g.ratio(::min); } pair maxratio(path3 g) { return g.ratio(::max); } // Return a negative (positive) value if a--b--c--cycle is oriented // counterclockwise (clockwise) when viewed from d or zero if all four // points are coplanar. // The value returned is the determinant // |a.x a.y a.z 1| // |b.x b.y b.z 1| // |c.x c.y c.z 1| // |d.x d.y d.z 1| real orient(triple a, triple b, triple c, triple d) { real A[]={a.getx(),a.gety(),a.getz()}; real B[]={b.getx(),b.gety(),b.getz()}; real C[]={c.getx(),c.gety(),c.getz()}; real D[]={d.getx(),d.gety(),d.getz()}; return orient3d(A,B,C,D); } // Return a positive (negative) value if e lies inside (outside) // the sphere passing through the points a,b,c,d oriented so that // a--b--c--cycle appears in clockwise order when viewed from d // or zero if all five points are cospherical. // The value returned is the determinant // |a.x a.y a.z a.x^2+a.y^2+a.z^2 1| // |b.x b.y b.z b.x^2+b.y^2+b.z^2 1| // |c.x c.y c.z c.x^2+c.y^2+c.z^2 1| // |d.x d.y d.z d.x^2+d.y^2+d.z^2 1| // |e.x e.y e.z e.x^2+e.y^2+e.z^2 1| real insphere(triple a, triple b, triple c, triple d, triple e) { real A[]={a.getx(),a.gety(),a.getz()}; real B[]={b.getx(),b.gety(),b.getz()}; real C[]={c.getx(),c.gety(),c.getz()}; real D[]={d.getx(),d.gety(),d.getz()}; real E[]={e.getx(),e.gety(),e.getz()}; return insphere(A,B,C,D,E); } asymptote-2.37/runpicture.in000066400000000000000000000464701265434602500162440ustar00rootroot00000000000000/***** * runpicture.in * * Runtime functions for picture operations. * *****/ pen => primPen() pair => primPair() triple => primTriple() path => primPath() path3 => primPath3() picture* => primPicture() Intarray* => IntArray() Intarray2* => IntArray2() realarray* => realArray() realarray2* => realArray2() patharray* => pathArray() penarray* => penArray() penarray2* => penArray2() pairarray* => pairArray() pairarray2* => pairArray2() triplearray* => tripleArray() triplearray2* => tripleArray2() transform => primTransform() callableTransform* => transformFunction() callablePen* => penFunction() #include "picture.h" #include "drawelement.h" #include "path.h" #include "array.h" #include "arrayop.h" #include "drawpath.h" #include "drawfill.h" #include "drawclipbegin.h" #include "drawclipend.h" #include "drawgsave.h" #include "drawgrestore.h" #include "drawgroup.h" #include "drawverbatim.h" #include "drawlabel.h" #include "drawlayer.h" #include "drawimage.h" #include "drawpath3.h" #include "drawsurface.h" using namespace camp; using namespace settings; using namespace vm; typedef array Intarray; typedef array Intarray2; typedef array realarray; typedef array realarray2; typedef array pairarray; typedef array pairarray2; typedef array triplearray; typedef array triplearray2; typedef array patharray; typedef array penarray; typedef array penarray2; typedef callable callableTransform; typedef callable callablePen; using types::IntArray; using types::IntArray2; using types::realArray; using types::realArray2; using types::pairArray; using types::pairArray2; using types::tripleArray; using types::tripleArray2; using types::pathArray; using types::penArray; using types::penArray2; function *transformFunction() { return new function(primTransform()); } function *penFunction() { return new function(primPen(),primInt(),primInt()); } // Ignore unclosed begingroups but not spurious endgroups. const char *nobegin="endgroup without matching begingroup"; array *emptyarray=new array(0); array *nop(array *a) { return a; } triple Zero; // Autogenerated routines: picture* :newPicture() { return new picture(); } bool empty(picture *f) { return f->null(); } void erase(picture *f) { f->nodes.clear(); } pair min(picture *f) { return f->bounds().Min(); } pair max(picture *f) { return f->bounds().Max(); } pair size(picture *f) { bbox b=f->bounds(); return b.Max()-b.Min(); } void _draw(picture *f, path g, pen p) { f->append(new drawPath(g,p)); } void fill(picture *f, patharray *g, pen p=CURRENTPEN, bool copy=true) { array *(*copyarray)(array *a)=copy ? copyArray: nop; f->append(new drawFill(*copyarray(g),false,p)); } void latticeshade(picture *f, patharray *g, bool stroke=false, pen fillrule=CURRENTPEN, penarray2 *p, transform t=identity, bool copy=true) { array *(*copyarray)(array *a)=copy ? copyArray: nop; f->append(new drawLatticeShade(*copyarray(g),stroke,fillrule,*copyarray(p), t)); } void axialshade(picture *f, patharray *g, bool stroke=false, pen pena, pair a, bool extenda=true, pen penb, pair b, bool extendb=true, bool copy=true) { array *(*copyarray)(array *a)=copy ? copyArray: nop; f->append(new drawAxialShade(*copyarray(g),stroke,pena,a,extenda,penb,b, extendb)); } void radialshade(picture *f, patharray *g, bool stroke=false, pen pena, pair a, real ra, bool extenda=true, pen penb, pair b, real rb, bool extendb=true, bool copy=true) { array *(*copyarray)(array *a)=copy ? copyArray: nop; f->append(new drawRadialShade(*copyarray(g),stroke,pena,a,ra,extenda, penb,b,rb,extendb)); } void gouraudshade(picture *f, patharray *g, bool stroke=false, pen fillrule=CURRENTPEN, penarray *p, pairarray *z, Intarray *edges, bool copy=true) { array *(*copyarray)(array *a)=copy ? copyArray: nop; checkArrays(p,z); checkArrays(z,edges); f->append(new drawGouraudShade(*copyarray(g),stroke,fillrule,*copyarray(p), *copyarray(z),*copyarray(edges))); } void gouraudshade(picture *f, patharray *g, bool stroke=false, pen fillrule=CURRENTPEN, penarray *p, Intarray *edges, bool copy=true) { array *(*copyarray)(array *a)=copy ? copyArray: nop; size_t n=checkArrays(p,edges); size_t m=checkArray(g); array *z=new array(n); Int k=0; Int in=(Int) n; for(size_t j=0; j < m; ++j) { path *P=read(g,j); assert(P); Int stop=Min(P->size(),in-k); mem::vector& nodes=P->Nodes(); for(Int i=0; i < stop; ++i) (*z)[k++]=nodes[i].point; } checkArrays(p,z); f->append(new drawGouraudShade(*copyarray(g),stroke,fillrule,*copyarray(p), *z,*copyarray(edges))); } void tensorshade(picture *f, patharray *g, bool stroke=false, pen fillrule=CURRENTPEN, penarray2 *p, patharray *b=NULL, pairarray2 *z=emptyarray, bool copy=true) { array *(*copyarray)(array *a)=copy ? copyArray: nop; array *(*copyarray2)(array *a)=copy ? copyArray2: nop; if(b == NULL) b=g; size_t n=checkArrays(p,b); size_t nz=checkArray(z); if(nz != 0) checkEqual(nz,n); f->append(new drawTensorShade(*copyarray(g),stroke,fillrule,*copyarray2(p), *copyarray(b),*copyarray2(z))); } void functionshade(picture *f, patharray *g, bool stroke=false, pen fillrule=CURRENTPEN, string shader=emptystring, bool copy=true) { array *(*copyarray)(array *a)=copy ? copyArray: nop; f->append(new drawFunctionShade(*copyarray(g),stroke,fillrule,shader)); } // Clip a picture to a superpath using the given fill rule. // Subsequent additions to the picture will not be affected by the clipping. void clip(picture *f, patharray *g, bool stroke=false, pen fillrule=CURRENTPEN, bool copy=true) { array *(*copyarray)(array *a)=copy ? copyArray: nop; drawClipBegin *begin=new drawClipBegin(*copyarray(g),stroke,fillrule,true); f->enclose(begin,new drawClipEnd(true,begin)); } void beginclip(picture *f, patharray *g, bool stroke=false, pen fillrule=CURRENTPEN, bool copy=true) { array *(*copyarray)(array *a)=copy ? copyArray: nop; f->append(new drawClipBegin(*copyarray(g),stroke,fillrule,false)); } void endclip(picture *f) { f->append(new drawClipEnd(false)); } void gsave(picture *f) { f->append(new drawGsave()); } void grestore(picture *f) { f->append(new drawGrestore()); } void begingroup(picture *f) { f->append(new drawBegin()); } void endgroup(picture *f) { f->append(new drawEnd()); } void _begingroup3(picture *f, string name, real compression, real granularity, bool closed, bool tessellate, bool dobreak, bool nobreak, triple center, Int interaction) { f->append(new drawBegin3(name,compression,granularity, closed,tessellate,dobreak,nobreak, center,(Interaction) intcast(interaction))); } void endgroup3(picture *f) { f->append(new drawEnd3()); } void add(picture *dest, picture *src) { dest->add(*src); } void prepend(picture *dest, picture *src) { dest->prepend(*src); } void postscript(picture *f, string s) { f->append(new drawVerbatim(PostScript,s)); } void tex(picture *f, string s) { f->append(new drawVerbatim(TeX,s)); } void postscript(picture *f, string s, pair min, pair max) { f->append(new drawVerbatim(PostScript,s,min,max)); } void tex(picture *f, string s, pair min, pair max) { f->append(new drawVerbatim(TeX,s,min,max)); } void texpreamble(string s) { string t=s+"\n"; processDataStruct &pd=processData(); pd.TeXpipepreamble.push_back(t); pd.TeXpreamble.push_back(t); } void deletepreamble() { if(getSetting("inlinetex")) { unlink(buildname(outname(),"pre").c_str()); } } void _labelpath(picture *f, string s, string size, path g, string justify, pair offset, pen p) { f->append(new drawLabelPath(s,size,g,justify,offset,p)); } void texreset() { processDataStruct &pd=processData(); pd.TeXpipepreamble.clear(); pd.TeXpreamble.clear(); pd.tex.pipeclose(); } void layer(picture *f) { f->append(new drawLayer()); } void newpage(picture *f) { f->append(new drawNewPage()); } void _image(picture *f, realarray2 *data, pair initial, pair final, penarray *palette=NULL, transform t=identity, bool copy=true, bool antialias=false) { array *(*copyarray)(array *a)=copy ? copyArray: nop; array *(*copyarray2)(array *a)=copy ? copyArray2: nop; f->append(new drawPaletteImage(*copyarray2(data),*copyarray(palette), t*matrix(initial,final),antialias)); } void _image(picture *f, penarray2 *data, pair initial, pair final, transform t=identity, bool copy=true, bool antialias=false) { array *(*copyarray2)(array *a)=copy ? copyArray2: nop; f->append(new drawNoPaletteImage(*copyarray2(data),t*matrix(initial,final), antialias)); } void _image(picture *f, callablePen *F, Int width, Int height, pair initial, pair final, transform t=identity, bool antialias=false) { f->append(new drawFunctionImage(Stack,F,width,height, t*matrix(initial,final),antialias)); } string nativeformat() { return nativeformat(); } bool latex() { return latex(getSetting("tex")); } bool pdf() { return pdf(getSetting("tex")); } void shipout(string prefix=emptystring, picture *f, picture *preamble=NULL, string format=emptystring, bool wait=false, bool view=true, callableTransform *xform) { if(prefix.empty()) prefix=outname(); picture *result=new picture; unsigned level=0; picture::nodelist::iterator p; // If null is given as an xform, just use the identity transformation. bool xformIsNull = xform == nullfunc::instance(); for(p = f->nodes.begin(); p != f->nodes.end(); ++p) { if (!xformIsNull) xform->call(Stack); transform t=xformIsNull ? camp::identity : pop(Stack); static transform Zero=transform(0.0,0.0,0.0,0.0,0.0,0.0); bool Delete=(t == Zero); picture *group=new picture; assert(*p); if((*p)->endgroup()) error(nobegin); if((*p)->begingroup()) { ++level; while(p != f->nodes.end() && level) { if(!Delete) { drawElement *e=t.isIdentity() ? *p : (*p)->transformed(t); group->append(e); } ++p; if(p == f->nodes.end()) break; assert(*p); if((*p)->begingroup()) ++level; if((*p)->endgroup()) { if(level) --level; else error(nobegin); } } } if(p == f->nodes.end()) break; assert(*p); if(!Delete) { drawElement *e=t.isIdentity() ? *p : (*p)->transformed(t); group->append(e); result->add(*group); } } result->shipout(preamble,prefix,format,0.0,wait,view); } void shipout3(string prefix, picture *f, string format=emptystring, real width, real height, real angle, real zoom, triple m, triple M, pair shift, realarray2 *t, realarray *background, triplearray *lights, realarray2 *diffuse, realarray2 *ambient, realarray2 *specular, bool viewportlighting, bool view=true) { size_t n=checkArrays(lights,diffuse); checkEqual(n,checkArray(ambient)); checkEqual(n,checkArray(specular)); real *T,*Background,*Diffuse,*Ambient,*Specular; triple *Lights; copyArray2C(T,t,true,4); copyArrayC(Background,background); copyArrayC(Lights,lights); copyArray2C(Diffuse,diffuse,false,4,UseGC); copyArray2C(Ambient,ambient,false,4,UseGC); copyArray2C(Specular,specular,false,4,UseGC); f->shipout3(prefix,format,width,height,angle,zoom,m,M,shift,T,Background,n, Lights,Diffuse,Ambient,Specular,viewportlighting,view); delete[] Background; delete[] T; } void shipout3(string prefix, picture *f) { f->shipout3(prefix); } void deconstruct(picture *f, picture *preamble=NULL, real magnification=1, callableTransform *xform) { unsigned level=0; unsigned n=0; string prefix=outname(); const string xformat="png"; static long arg_max=sysconf(_SC_ARG_MAX); const unsigned maxargs=::min(arg_max/(prefix.size()+xformat.size()+25ul), 256ul); openpipeout(); fprintf(pipeout,"%d\n",maxargs); fflush(pipeout); string preformat=nativeformat(); const string Done="Done"; const string Error="Error"; mem::vector cmd; // Enforce ghostscript limitations. magnification=::max(magnification,0.0001); real res=::min(::max(magnification*72.0,2.0),8192.0); const char *converter=NULL, *hint=NULL; if(magnification > 0.0) { mem::list nameStack; string outname; unsigned arg=0; unsigned batch=0; for(picture::nodelist::iterator p=f->nodes.begin();;) { if(p == f->nodes.end()) break; if(arg == 0) { cmd.clear(); ostringstream buf; buf << batch << "_"; outname=buildname(prefix+buf.str()+"%d",xformat,""); converter="gs"; hint="Ghostscript"; cmd.push_back(getSetting(converter)); cmd.push_back("-q"); cmd.push_back("-dNOPAUSE"); cmd.push_back("-dBATCH"); cmd.push_back("-sDEVICE=pngalpha"); cmd.push_back("-dEPSCrop"); if(safe) cmd.push_back("-dSAFER"); cmd.push_back("-r"+String(res)+"x"+String(res)); cmd.push_back("-sOutputFile="+outname); } picture *group=new picture; xform->call(Stack); transform t=pop(Stack); assert(*p); if((*p)->endgroup()) { fprintf(pipeout,"%s\n",Error.c_str()); fflush(pipeout); error(nobegin); } if((*p)->begingroup()) { ++level; while(p != f->nodes.end() && level) { drawElement *e=t.isIdentity() ? *p : (*p)->transformed(t); group->append(e); ++p; if(p == f->nodes.end()) break; assert(*p); if((*p)->begingroup()) ++level; if((*p)->endgroup()) { if(level) --level; else { fprintf(pipeout,"%s\n",Error.c_str()); fflush(pipeout); error(nobegin); } } } } if(p != f->nodes.end()) { assert(*p); drawElement *e=t.isIdentity() ? *p : (*p)->transformed(t); group->append(e); bbox b; ostringstream buf; buf << prefix << "_" << n; group->shipout(preamble,buf.str(),preformat,magnification,false,false); string Preformat=group->Transparency() ? "pdf" : preformat; string name=buildname(buf.str(),Preformat); nameStack.push_back(name); cmd.push_back(name); b=group->bounds(); b *= magnification; const char *oldlocale=setlocale(LC_NUMERIC,NULL); bool override=oldlocale && strcmp(oldlocale,"C") != 0; if(override) { oldlocale=StrdupNoGC(oldlocale); setlocale(LC_NUMERIC,"C"); } fprintf(pipeout,"%g %g %g %g\n",b.left,b.right,b.bottom,b.top); if(override) { setlocale(LC_NUMERIC,oldlocale); delete[] oldlocale; } fflush(pipeout); ++n; ++p; ++arg; } if(p == f->nodes.end() || arg >= maxargs) { arg=0; ++batch; fflush(pipeout); int status=System(cmd,0,true,converter,hint); if(status) { fprintf(pipeout,"%s\n",Error.c_str()); fflush(pipeout); error("deconstruct failed"); } } } if(!getSetting("keep")) { for(mem::list::iterator p=nameStack.begin(); p != nameStack.end(); ++p) unlink(p->c_str()); } fprintf(pipeout,"%s\n",Done.c_str()); fflush(pipeout); } } // Three-dimensional picture and surface operations // Bezier curve void _draw(picture *f, path3 g, triple center=Zero, pen p, Int interaction=0) { if(g.size() > 0) f->append(new drawPath3(g,center,p,(Interaction) intcast(interaction))); } // Bezier patch void draw(picture *f, triplearray2 *P, triple center, bool straight, penarray *p, real opacity, real shininess, real PRCshininess, triple normal, penarray *colors, Int interaction, bool prc=true) { f->append(new drawSurface(*P,center,straight,*p,opacity,shininess, PRCshininess,normal,*colors, (Interaction) intcast(interaction),prc)); } // Bezier triangle void drawbeziertriangle(picture *f, triplearray2 *P, triple center, bool straight, penarray *p, real opacity, real shininess, real PRCshininess, penarray *colors, Int interaction, bool prc=true) { f->append(new drawBezierTriangle(*P,center,straight,*p,opacity,shininess, PRCshininess,*colors, (Interaction) intcast(interaction),prc)); } // General NURBS curve void draw(picture *f, triplearray *P, realarray *knot, realarray *weights=emptyarray, pen p) { f->append(new drawNurbsPath3(*P,knot,weights,p)); } // General NURBS surface void draw(picture *f, triplearray2 *P, realarray *uknot, realarray *vknot, realarray2 *weights=emptyarray, penarray *p, real opacity, real shininess, real PRCshininess, penarray *colors) { f->append(new drawNurbs(*P,uknot,vknot,weights,*p,opacity,shininess, PRCshininess,*colors)); } // PRC unit sphere void drawPRCsphere(picture *f, realarray2 *t, bool half=false, penarray *p, real opacity, real shininess, Int type) { f->append(new drawSphere(*t,half,*p,opacity,shininess,intcast(type))); } // PRC unit cylinder void drawPRCcylinder(picture *f, realarray2 *t, penarray *p, real opacity, real shininess) { f->append(new drawCylinder(*t,*p,opacity,shininess)); } // PRC unit disk void drawPRCdisk(picture *f, realarray2 *t, penarray *p, real opacity, real shininess) { f->append(new drawDisk(*t,*p,opacity,shininess)); } // General PRC tube void drawPRCtube(picture *f, path3 center, path3 g, penarray *p, real opacity, real shininess) { f->append(new drawTube(center,g,*p,opacity,shininess)); } // Draw pixel void drawpixel(picture *f, triple v, pen p, real width=1.0) { f->append(new drawPixel(v,p,width)); } // Draw triangles void draw(picture *f, triplearray *v, Intarray2 *vi, triplearray *n, Intarray2 *ni, penarray *p, real opacity, real shininess, real PRCshininess, penarray *c=emptyarray, Intarray2 *ci=emptyarray) { f->append(new drawTriangles(*v,*vi,*n,*ni,*p,opacity,shininess,PRCshininess, *c,*ci)); } triple min3(picture *f) { return f->bounds3().Min(); } triple max3(picture *f) { return f->bounds3().Max(); } triple size3(picture *f) { bbox3 b=f->bounds3(); return b.Max()-b.Min(); } pair minratio(picture *f) { return f->ratio(::min); } pair maxratio(picture *f) { return f->ratio(::max); } bool is3D(picture *f) { return f->have3D(); } asymptote-2.37/runstring.in000066400000000000000000000220171265434602500160660ustar00rootroot00000000000000/***** * runstring.in * * Runtime functions for string operations. * *****/ stringarray2* => stringArray2() #include #include #include #include "array.h" using namespace camp; using namespace vm; using namespace settings; typedef array stringarray; typedef array stringarray2; using types::stringArray; using types::stringArray2; namespace types { extern const char *names[]; } namespace run { extern string emptystring; } static const string defaulttimeformat=string("%a %b %d %T %Z %Y"); #ifdef HAVE_STRFTIME static const size_t nTime=256; static char Time[nTime]; #endif void checkformat(const char *ptr, bool intformat) { while(*ptr != '\0') { if(*ptr != '%') /* While we have regular characters, print them. */ ptr++; else { /* We've got a format specifier. */ ptr++; while(*ptr && strchr ("-+ #0'I", *ptr)) /* Move past flags. */ ptr++; if(*ptr == '*') ptr++; else while(isdigit(*ptr)) /* Handle explicit numeric value. */ ptr++; if(*ptr == '.') { ptr++; /* Go past the period. */ if(*ptr == '*') { ptr++; } else while(isdigit(*ptr)) /* Handle explicit numeric value. */ ptr++; } while(*ptr && strchr ("hlL", *ptr)) ptr++; if(*ptr == '%') ++ptr; else if(*ptr != '\0') { if(intformat) { switch(*ptr) { case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': case 'c': break; default: ostringstream buf; buf << "Invalid format '" << *ptr << "' for type " << types::names[types::ty_Int]; error(buf); break; } } else { switch(*ptr) { case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': break; default: ostringstream buf; buf << "Invalid format '" << *ptr << "' for type " << types::names[types::ty_real]; error(buf); break; } } } } /* End of else statement */ } } // Autogenerated routines: // String operations string :emptyString() { return emptystring; } Int length(string *s) { return (Int) s->length(); } Int find(string *s, string t, Int pos=0) { size_t n=s->find(t,pos); return n == string::npos ? (Int) -1 : (Int) n; } Int rfind(string *s, string t, Int pos=-1) { size_t n=s->rfind(t,pos); return n == string::npos ? (Int) -1 : (Int) n; } string reverse(string s) { reverse(s.begin(),s.end()); return s; } string insert(string s, Int pos, string t) { if ((size_t) pos < s.length()) return s.insert(pos,t); return s; } string substr(string* s, Int pos, Int n=-1) { if ((size_t) pos < s->length()) return s->substr(pos,n); return emptystring; } string erase(string s, Int pos, Int n) { if ((size_t) pos < s.length()) return s.erase(pos,n); return s; } string downcase(string s) { std::transform(s.begin(),s.end(),s.begin(),tolower); return s; } string upcase(string s) { std::transform(s.begin(),s.end(),s.begin(),toupper); return s; } // returns a string constructed by translating all occurrences of the string // from in an array of string pairs {from,to} to the string to in string s. string replace(string *S, stringarray2 *translate) { size_t size=checkArray(translate); for(size_t i=0; i < size; i++) { array *a=read(translate,i); checkArray(a); } const char *p=S->c_str(); ostringstream buf; while(*p) { for(size_t i=0; i < size;) { array *a=read(translate,i); size_t size2=checkArray(a); if(size2 != 2) error("translation table entry must be an array of length 2"); string* from=read(a,0); size_t len=from->length(); if(strncmp(p,from->c_str(),len) != 0) {i++; continue;} buf << read(a,1); p += len; if(*p == 0) return buf.str(); i=0; } buf << *(p++); } return buf.str(); } string format(string *format, Int x, string locale=emptystring) { const char *f=format->c_str(); checkformat(f,true); const char *oldlocale=NULL; if(!locale.empty()) { oldlocale=setlocale(LC_ALL,NULL); if(oldlocale) oldlocale=StrdupNoGC(oldlocale); setlocale(LC_ALL,locale.c_str()); } Int size=snprintf(NULL,0,f,x)+1; if(size < 1) size=255; // Workaround for non-C99 compliant systems. char *buf=new char[size]; snprintf(buf,size,f,x); string s=string(buf); delete[] buf; if(oldlocale) { setlocale(LC_ALL,oldlocale); delete[] oldlocale; } return s; } string format(string *format, string separator, real x, string locale=emptystring) { bool tex=getSetting("tex") != "none"; bool texify=false; ostringstream out; checkformat(format->c_str(),false); const char *phantom="\\phantom{+}"; const char *p0=format->c_str(); const char *p=p0; const char *start=NULL; char prev=0; while(*p != 0) { char curr=*p; if(tex && curr == '$' && prev != '\\') texify=true; prev=curr; if(curr == '%') { p++; if(*p != '%') {start=p-1; break;} } out << *(p++); } if(!start) return out.str(); // Allow at most 1 argument while(*p != 0) { if(*p == '*' || *p == '$') return out.str(); if(isupper(*p) || islower(*p)) {p++; break;} p++; } const char *tail=p; string f=format->substr(start-p0,tail-start); const char *oldlocale=NULL; if(!locale.empty()) { oldlocale=setlocale(LC_ALL,NULL); if(oldlocale) oldlocale=StrdupNoGC(oldlocale); setlocale(LC_ALL,locale.c_str()); } Int size=snprintf(NULL,0,f.c_str(),x)+1; if(size < 1) size=255; // Workaround for non-C99 compliant systems. char *buf=new char[size]; snprintf(buf,size,f.c_str(),x); bool trailingzero=f.find("#") < string::npos; bool plus=f.find("+") < string::npos; bool space=f.find(" ") < string::npos; char *q=buf; // beginning of formatted number if(*q == ' ' && texify) { out << phantom; q++; } const char decimal=*(localeconv()->decimal_point); // Remove any spurious sign if(*q == '-' || *q == '+') { p=q+1; bool zero=true; while(*p != 0) { if(!isdigit(*p) && *p != decimal) break; if(isdigit(*p) && *p != '0') {zero=false; break;} p++; } if(zero) { q++; if((plus || space) && texify) out << phantom; } } const char *r=p=q; bool dp=false; while(*r != 0 && (isspace(*r) || isdigit(*r) || *r == decimal \ || *r == '+' || *r == '-')) { if(*r == decimal) dp=true; r++; } if(dp) { // Remove trailing zeros and/or decimal point r--; unsigned n=0; while(r > q && *r == '0') {r--; n++;} if(*r == decimal) {r--; n++;} while(q <= r) out << *(q++); if(!trailingzero) q += n; } bool zero=(r == p && *r == '0') && !trailingzero; // Translate "E+/E-/e+/e-" exponential notation to TeX while(*q != 0) { if(texify && (*q == 'E' || *q == 'e') && (*(q+1) == '+' || *(q+1) == '-')) { if(!zero) out << separator << "10^{"; bool plus=(*(q+1) == '+'); q++; if(plus) q++; if(*q == '-') out << *(q++); while(*q == '0' && (zero || isdigit(*(q+1)))) q++; while(isdigit(*q)) out << *(q++); if(!zero) out << "}"; break; } out << *(q++); } while(*tail != 0) out << *(tail++); delete[] buf; if(oldlocale) { setlocale(LC_ALL,oldlocale); delete[] oldlocale; } return out.str(); } Int hex(string s) { istringstream is(s); is.setf(std::ios::hex,std::ios::basefield); Int value; if(is && is >> value && ((is >> std::ws).eof())) return value; ostringstream buf; buf << "invalid hexidecimal cast from string \"" << s << "\""; error(buf); } Int ascii(string s) { return s.empty() ? -1 : (unsigned char) s[0]; } string string(Int x) { ostringstream buf; buf << x; return buf.str(); } string string(real x, Int digits=DBL_DIG) { ostringstream buf; buf.precision(digits); buf << x; return buf.str(); } string time(string format=defaulttimeformat) { #ifdef HAVE_STRFTIME const time_t bintime=time(NULL); if(!strftime(Time,nTime,format.c_str(),localtime(&bintime))) return ""; return Time; #else return format; #endif } string time(Int seconds, string format=defaulttimeformat) { #ifdef HAVE_STRFTIME const time_t bintime=seconds; if(!strftime(Time,nTime,format.c_str(),localtime(&bintime))) return ""; return Time; #else // Avoid unused variable warning messages unused(&seconds); return format; #endif } Int seconds(string t=emptystring, string format=emptystring) { #if defined(HAVE_STRPTIME) const time_t bintime=time(NULL); tm tm=*localtime(&bintime); if(t != "" && !strptime(t.c_str(),format.c_str(),&tm)) return -1; return (Int) mktime(&tm); #else return -1; #endif } asymptote-2.37/runsystem.in000066400000000000000000000117521265434602500161100ustar00rootroot00000000000000/***** * runsystem.in * * Runtime functions for system operations. * *****/ callable* => voidFunction() callableBp* => breakpointFunction() runnable* => primCode() #include "process.h" #include "stack.h" #include "locate.h" using namespace camp; using namespace settings; using vm::bpinfo; using vm::bplist; using vm::getPos; using vm::Default; using vm::nullfunc; using vm::item; using absyntax::runnable; typedef callable callableBp; namespace run { extern string emptystring; } function *voidFunction() { return new function(primVoid()); } function *breakpointFunction() { return new function(primString(),primString(),primInt(),primInt(), primCode()); } void clear(string file, Int line, bool warn=false) { bpinfo bp(file,line); for(mem::list::iterator p=bplist.begin(); p != bplist.end(); ++p) { if(*p == bp) { cout << "cleared breakpoint at " << file << ": " << line << endl; bplist.remove(bp); return; } } if(warn) cout << "No such breakpoint at " << file << ": " << line << endl; } namespace run { void breakpoint(stack *Stack, runnable *r) { callable *atBreakpointFunction=processData().atBreakpointFunction; if(atBreakpointFunction && !nullfunc::instance()->compare(atBreakpointFunction)) { position curPos=getPos(); Stack->push(curPos.filename()); Stack->push((Int) curPos.Line()); Stack->push((Int) curPos.Column()); Stack->push(r ? r : vm::Default); atBreakpointFunction->call(Stack); // returns a string } else Stack->push(""); } } string convertname(string name, const string& format) { if(name.empty()) return buildname(outname(),format,""); name=outpath(name); return format.empty() ? name : format+":"+name; } namespace run { void purge(Int divisor=0) { #ifdef USEGC if(divisor > 0) GC_set_free_space_divisor((GC_word) divisor); GC_gcollect(); #endif } void updateFunction(stack *Stack) { callable *atUpdateFunction=processData().atUpdateFunction; if(atUpdateFunction && !nullfunc::instance()->compare(atUpdateFunction)) atUpdateFunction->call(Stack); } void exitFunction(stack *Stack) { callable *atExitFunction=processData().atExitFunction; if(atExitFunction && !nullfunc::instance()->compare(atExitFunction)) atExitFunction->call(Stack); } } // Autogenerated routines: string outname() { return outname(); } void atupdate(callable *f) { processData().atUpdateFunction=f; } callable *atupdate() { return processData().atUpdateFunction; } void atexit(callable *f) { processData().atExitFunction=f; } callable *atexit() { return processData().atExitFunction; } void atbreakpoint(callableBp *f) { processData().atBreakpointFunction=f; } void breakpoint(runnable *s=NULL) { breakpoint(Stack,s); } string locatefile(string file) { return locateFile(file); } void stop(string file, Int line, runnable *s=NULL) { file=locateFile(file); clear(file,line); cout << "setting breakpoint at " << file << ": " << line << endl; bplist.push_back(bpinfo(file,line,s)); } void breakpoints() { for(mem::list::iterator p=bplist.begin(); p != bplist.end(); ++p) cout << p->f.name() << ": " << p->f.line() << endl; } void clear(string file, Int line) { file=locateFile(file); clear(file,line,true); } void clear() { bplist.clear(); } void warn(string s) { Warn(s); } void nowarn(string s) { noWarn(s); } void warning(string s, string t, bool position=false) { if(settings::warn(s)) { em.warning(position ? getPos() : nullPos,s); em << t; } } // Strip directory from string string stripdirectory(string *s) { return stripDir(*s); } // Strip directory from string string stripfile(string *s) { return stripFile(*s); } // Strip file extension from string string stripextension(string *s) { return stripExt(*s); } // Call ImageMagick convert. Int convert(string args=emptystring, string file=emptystring, string format=emptystring) { string name=convertname(file,format); mem::vector cmd; cmd.push_back(getSetting("convert")); push_split(cmd,args); cmd.push_back(name); bool quiet=verbose <= 1; char *oldPath=NULL; string dir=stripFile(outname()); if(!dir.empty()) { oldPath=getPath(); setPath(dir.c_str()); } Int ret=System(cmd,quiet ? 1 : 0,true,"convert", "your ImageMagick convert utility"); if(oldPath != NULL) setPath(oldPath); if(ret == 0 && verbose > 0) cout << "Wrote " << (file.empty() ? name : file) << endl; return ret; } // Call ImageMagick animate. Int animate(string args=emptystring, string file=emptystring, string format=emptystring) { #ifndef __MSDOS__ string name=convertname(file,format); if(view()) { mem::vector cmd; cmd.push_back(getSetting("animate")); push_split(cmd,args); cmd.push_back(name); return System(cmd,0,false,"animate","your animated GIF viewer"); } #endif return 0; } void purge(Int divisor=0) { purge(divisor); } asymptote-2.37/runtime.in000066400000000000000000000475371265434602500155340ustar00rootroot00000000000000/***** * runtime.in * Tom Prince 2005/4/15 * * Generate the runtime functions used by the vm::stack machine. * *****/ /* Autogenerated routines are specified like this (separated by a formfeed): type asyname:cname(cparams) { C code } */ // Use Void f() instead of void f() to force an explicit Stack argument. pen => primPen() pair => primPair() triple => primTriple() path => primPath() path3 => primPath3() guide* => primGuide() cycleToken => primCycleToken() tensionSpecifier => primTensionSpecifier() curlSpecifier => primCurlSpecifier() file* => primFile() picture* => primPicture() transform => primTransform() callable* => voidFunction() callableBp* => breakpointFunction() callableReal* => realRealFunction() callableTransform* => transformFunction() runnable* => primCode() boolarray* => booleanArray() Intarray* => IntArray() Intarray2* => IntArray2() realarray* => realArray() realarray2* => realArray2() pairarray* => pairArray() pairarray2* => pairArray2() triplearray* => tripleArray() triplearray2* => tripleArray2() patharray* => pathArray() patharray2* => pathArray2() guidearray* => guideArray() transformarray* => transformArray() penarray* => penArray() penarray2* => penArray2() stringarray* => stringArray() stringarray2* => stringArray2() #include #include #include #include #include #include #include "angle.h" #include "pair.h" #include "triple.h" #include "transform.h" #include "path.h" #include "path3.h" #include "pen.h" #include "drawpath.h" #include "guide.h" #include "picture.h" #include "fileio.h" #include "genv.h" #include "builtin.h" #include "texfile.h" #include "pipestream.h" #include "parser.h" #include "stack.h" #include "util.h" #include "locate.h" #include "mathop.h" #include "callable.h" #include "stm.h" #include "lexical.h" #include "process.h" #include "arrayop.h" #ifdef __APPLE__ extern "C" int isnan(double); #endif #if defined(USEGC) && defined(GC_DEBUG) && defined(GC_BACKTRACE) extern "C" { void *GC_generate_random_valid_address(void); void GC_debug_print_heap_obj_proc(void *); } #endif using namespace vm; using namespace camp; using namespace settings; #undef OUT #undef IN namespace run { using camp::pair; using vm::array; using vm::frame; using vm::stack; using camp::transform; using absyntax::runnable; typedef array boolarray; typedef array Intarray; typedef array Intarray2; typedef array realarray; typedef array realarray2; typedef array pairarray; typedef array pairarray2; typedef array triplearray; typedef array triplearray2; typedef array patharray; typedef array patharray2; typedef array guidearray; typedef array transformarray; typedef array penarray; typedef array penarray2; typedef array stringarray; typedef array stringarray2; typedef callable callableBp; typedef callable callableReal; typedef callable callableTransform; } using vm::array; using types::function; #define PRIMITIVE(name,Name,asyName) using types::prim##Name; #include #undef PRIMITIVE using types::booleanArray; using types::IntArray; using types::IntArray2; using types::realArray; using types::realArray2; using types::pairArray; using types::pairArray2; using types::tripleArray; using types::tripleArray2; using types::pathArray; using types::pathArray2; using types::guideArray; using types::transformArray; using types::penArray; using types::penArray2; using types::stringArray; using types::stringArray2; using types::formal; function *realRealFunction() { return new function(primReal(),primReal()); } function *realTripleFunction() { return new function(primReal(),primTriple()); } const size_t camp::ColorComponents[]={0,0,1,3,4,0}; namespace vm { #if COMPACT const Int DefaultValue=0x7fffffffffffffffLL; const Int Undefined=0x7ffffffffffffffeLL; const Int BoolTruthValue=0xABABABABABABABACLL; const Int BoolFalseValue=0xABABABABABABABABLL; const item Default=DefaultValue; #else const item Default=item(default_t()); #endif } namespace run { const char *arrayempty="cannot take min or max of empty array"; const char *noruntime="no runtime environment for embedded eval"; void writestring(stack *s) { callable *suffix=pop(s,NULL); string S=pop(s); vm::item it=pop(s); bool defaultfile=isdefault(it); camp::file *f=defaultfile ? &camp::Stdout : vm::get(it); if(!f->isOpen()) return; if(S != "") f->write(S); if(f->text()) { if(suffix) { s->push(f); suffix->call(s); } else if(defaultfile) f->writeline(); } } string emptystring; pair zero; } static string defaulttransparency=string("Compatible"); void unused(void *) { } // Autogenerated routines: // Initializers Int :IntZero() { return 0; } real :realZero() { return 0.0; } bool :boolFalse() { return false; } bool isnan(real x) { return std::isnan(x); } array* :pushNullArray() { return 0; } frame* :pushNullRecord() { return 0; } item :pushNullFunction() { return nullfunc::instance(); } // Default operations // Put the default value token on the stack (in place of an argument when // making a function call). item :pushDefault() { return Default; } // Test if the value on the stack is the default value token. bool :isDefault(item i) { return isdefault(i); } // Casts guide* :pairToGuide(pair z) { return new pairguide(z); } guide* :pathToGuide(path p) { return new pathguide(p); } path :guideToPath(guide *g) { return g->solve(); } // Pen operations pen :newPen() { return pen(); } bool ==(pen a, pen b) { return a == b; } bool !=(pen a, pen b) { return a != b; } pen +(pen a, pen b) { return a+b; } pen Operator *(real a, pen b) { return a*b; } pen Operator *(pen a, real b) { return b*a; } pair max(pen p) { return p.bounds().Max(); } pair min(pen p) { return p.bounds().Min(); } // Reset the meaning of pen default attributes. void resetdefaultpen() { processData().defaultpen=camp::pen::initialpen(); } void defaultpen(pen p) { processData().defaultpen=pen(resolvepen,p); } pen defaultpen() { return processData().defaultpen; } bool invisible(pen p) { return p.invisible(); } pen invisible() { return pen(invisiblepen); } pen gray(pen p) { p.togrey(); return p; } pen rgb(pen p) { p.torgb(); return p; } pen cmyk(pen p) { p.tocmyk(); return p; } pen interp(pen a, pen b, real t) { return interpolate(a,b,t); } pen rgb(real r, real g, real b) { return pen(r,g,b); } pen cmyk(real c, real m, real y, real k) { return pen(c,m,y,k); } pen gray(real gray) { return pen(gray); } realarray *colors(pen p) { size_t n=ColorComponents[p.colorspace()]; array *a=new array(n); switch(n) { case 0: break; case 1: (*a)[0]=p.gray(); break; case 3: (*a)[0]=p.red(); (*a)[1]=p.green(); (*a)[2]=p.blue(); break; case 4: (*a)[0]=p.cyan(); (*a)[1]=p.magenta(); (*a)[2]=p.yellow(); (*a)[3]=p.black(); break; default: break; } return a; } string hex(pen p) { return p.hex(); } Int byte(real x) { return camp::byte(x); } string colorspace(pen p) { string s=ColorDeviceSuffix[p.colorspace()]; std::transform(s.begin(),s.end(),s.begin(),tolower); return s; } pen pattern(string *s) { return pen(setpattern,*s); } string pattern(pen p) { return p.fillpattern(); } pen fillrule(Int n) { return pen(n >= 0 && n < nFill ? (FillRule) n : DEFFILL); } Int fillrule(pen p) { return p.Fillrule(); } pen opacity(real opacity=1.0, string blend=defaulttransparency) { for(Int i=0; i < nBlendMode; ++i) if(blend == BlendMode[i]) return pen(Transparency(blend,opacity)); ostringstream buf; buf << "Unknown blend mode: " << "'" << blend << "'"; error(buf); } real opacity(pen p) { return p.opacity(); } string blend(pen p) { return p.blend(); } pen linetype(realarray *pattern, real offset=0, bool scale=true, bool adjust=true) { size_t size=checkArray(pattern); array *a=new array(size); for(size_t i=0; i < size; ++i) (*a)[i]=::max(vm::read(pattern,i),0.0); return pen(LineType(*a,offset,scale,adjust)); } realarray *linetype(pen p=CURRENTPEN) { array a=p.linetype()->pattern; return copyArray(&a); } real offset(pen p) { return p.linetype()->offset; } bool scale(pen p) { return p.linetype()->scale; } bool adjust(pen p) { return p.linetype()->adjust; } pen adjust(pen p, real arclength, bool cyclic) { return adjustdash(p,arclength,cyclic); } pen linecap(Int n) { return pen(setlinecap,n >= 0 && n < nCap ? n : DEFCAP); } Int linecap(pen p=CURRENTPEN) { return p.cap(); } pen linejoin(Int n) { return pen(setlinejoin,n >= 0 && n < nJoin ? n : DEFJOIN); } Int linejoin(pen p=CURRENTPEN) { return p.join(); } pen miterlimit(real x) { return pen(setmiterlimit,x >= 1.0 ? x : DEFJOIN); } real miterlimit(pen p=CURRENTPEN) { return p.miter(); } pen linewidth(real x) { return pen(setlinewidth,x >= 0.0 ? x : DEFWIDTH); } real linewidth(pen p=CURRENTPEN) { return p.width(); } pen fontcommand(string *s) { return pen(setfont,*s); } string font(pen p=CURRENTPEN) { return p.Font(); } pen fontsize(real size, real lineskip) { return pen(setfontsize,size > 0.0 ? size : 0.0, lineskip > 0.0 ? lineskip : 0.0); } real fontsize(pen p=CURRENTPEN) { return p.size(); } real lineskip(pen p=CURRENTPEN) { return p.Lineskip(); } pen overwrite(Int n) { return pen(setoverwrite,n >= 0 && n < nOverwrite ? (overwrite_t) n : DEFWRITE); } Int overwrite(pen p=CURRENTPEN) { return p.Overwrite(); } pen basealign(Int n) { return pen(n >= 0 && n < nBaseLine ? (BaseLine) n : DEFBASE); } Int basealign(pen p=CURRENTPEN) { return p.Baseline(); } transform transform(pen p) { return p.getTransform(); } path nib(pen p) { return p.Path(); } pen makepen(path p) { return pen(p); } pen colorless(pen p) { p.colorless(); return p; } // Interactive mode bool interactive() { return interact::interactive; } bool uptodate() { return interact::uptodate; } // System commands Int system(stringarray *s) { if(safe) error("system() call disabled; override with option -nosafe"); size_t size=checkArray(s); if(size == 0) return 0; mem::vector cmd; for(size_t i=0; i < size; ++i) cmd.push_back(read(s,i)); return System(cmd); } bool view() { return view(); } string asydir() { return systemDir; } string locale(string s=emptystring) { char *L=setlocale(LC_ALL,s.empty() ? NULL : s.c_str()); return L != NULL ? string(L) : ""; } void abort(string s=emptystring) { if(s.empty()) throw handled_error(); error(s.c_str()); } void exit() { throw quit(); } void assert(bool b, string s=emptystring) { flush(cout); if(!b) { ostringstream buf; buf << "assert FAILED"; if(s != "") buf << ": " << s; error(buf); } } void sleep(Int seconds) { if(seconds <= 0) return; sleep(seconds); } void usleep(Int microseconds) { if(microseconds <= 0) return; usleep((unsigned long) microseconds); } void _eval(string *s, bool embedded, bool interactiveWrite=false) { if(embedded) { trans::coenv *e=Stack->getEnvironment(); vm::interactiveStack *is=dynamic_cast(Stack); if(e && is) runStringEmbedded(*s, *e, *is); else error(noruntime); } else runString(*s,interactiveWrite); } void _eval(runnable *s, bool embedded) { absyntax::block *ast=new absyntax::block(s->getPos(), false); ast->add(s); if(embedded) { trans::coenv *e=Stack->getEnvironment(); vm::interactiveStack *is=dynamic_cast(Stack); if(e && is) runCodeEmbedded(ast, *e, *is); else error(noruntime); } else runCode(ast); } string location() { ostringstream buf; buf << getPos(); return buf.str(); } // Wrapper for the stack::load() method. void :loadModule(string *index) { Stack->load(*index); } string cd(string s=emptystring) { if(!s.empty() && !globalwrite()) { string outname=getSetting("outname"); string dir=stripDir(outname); if(dir.empty()) Setting("outname")=getPath()+dirsep+outname; } return setPath(s.c_str()); } void list(string *s, bool imports=false) { if(*s == "-") return; trans::genv ge; symbol name=symbol::trans(*s); record *r=ge.getModule(name,*s); r->e.list(imports ? 0 : r); } // Guide operations guide* :nullGuide() { return new pathguide(path()); } guide* :dotsGuide(guidearray *a) { guidevector v; size_t size=checkArray(a); for (size_t i=0; i < size; ++i) v.push_back(a->read(i)); return new multiguide(v); } guide* :dashesGuide(guidearray *a) { static camp::curlSpec curly; static camp::specguide curlout(&curly, camp::OUT); static camp::specguide curlin(&curly, camp::IN); size_t n=checkArray(a); // a--b is equivalent to a{curl 1}..{curl 1}b guidevector v; if (n > 0) v.push_back(a->read(0)); if (n==1) { v.push_back(&curlout); v.push_back(&curlin); } else for (size_t i=1; iread(i)); } return new multiguide(v); } cycleToken :newCycleToken() { return cycleToken(); } guide *operator cast(cycleToken tok) { // Avoid unused variable warning messages. unused(&tok); return new cycletokguide(); } guide* operator spec(pair z, Int p) { camp::side d=(camp::side) p; camp::dirSpec *sp=new camp::dirSpec(z); return new specguide(sp,d); } curlSpecifier operator curl(real gamma, Int p) { camp::side s=(camp::side) p; return curlSpecifier(gamma,s); } real :curlSpecifierValuePart(curlSpecifier spec) { return spec.getValue(); } Int :curlSpecifierSidePart(curlSpecifier spec) { return spec.getSide(); } guide *operator cast(curlSpecifier spec) { return new specguide(spec); } tensionSpecifier operator tension(real tout, real tin, bool atleast) { return tensionSpecifier(tout, tin, atleast); } real :tensionSpecifierOutPart(tensionSpecifier t) { return t.getOut(); } real :tensionSpecifierInPart(tensionSpecifier t) { return t.getIn(); } bool :tensionSpecifierAtleastPart(tensionSpecifier t) { return t.getAtleast(); } guide *operator cast(tensionSpecifier t) { return new tensionguide(t); } guide* operator controls(pair zout, pair zin) { return new controlguide(zout, zin); } Int size(guide *g) { flatguide f; g->flatten(f,false); return f.size(); } Int length(guide *g) { flatguide f; g->flatten(f,false); return g->cyclic() ? f.size() : f.size()-1; } bool cyclic(guide *g) { flatguide f; g->flatten(f,false); return g->cyclic(); } pair point(guide *g, Int t) { flatguide f; g->flatten(f,false); return f.Nodes(adjustedIndex(t,f.size(),g->cyclic())).z; } pairarray *dirSpecifier(guide *g, Int t) { flatguide f; g->flatten(f,false); Int n=f.size(); if(!g->cyclic() && (t < 0 || t >= n-1)) return new array(0); array *c=new array(2); (*c)[0]=f.Nodes(t).out->dir(); (*c)[1]=f.Nodes(t+1).in->dir(); return c; } pairarray *controlSpecifier(guide *g, Int t) { flatguide f; g->flatten(f,false); Int n=f.size(); if(!g->cyclic() && (t < 0 || t >= n-1)) return new array(0); knot curr=f.Nodes(t); knot next=f.Nodes(t+1); if(curr.out->controlled()) { assert(next.in->controlled()); array *c=new array(2); (*c)[0]=curr.out->control(); (*c)[1]=next.in->control(); return c; } else return new array(0); } tensionSpecifier tensionSpecifier(guide *g, Int t) { flatguide f; g->flatten(f,false); Int n=f.size(); if(!g->cyclic() && (t < 0 || t >= n-1)) return tensionSpecifier(1.0,1.0,false); knot curr=f.Nodes(t); return tensionSpecifier(curr.tout.val,f.Nodes(t+1).tin.val,curr.tout.atleast); } realarray *curlSpecifier(guide *g, Int t) { flatguide f; g->flatten(f,false); Int n=f.size(); if(!g->cyclic() && (t < 0 || t >= n-1)) return new array(0); array *c=new array(2); real c0=f.Nodes(t).out->curl(); real c1=f.Nodes(t+1).in->curl(); (*c)[0]=c0 >= 0.0 ? c0 : 1.0; (*c)[1]=c1 >= 0.0 ? c1 : 1.0; return c; } guide *reverse(guide *g) { flatguide f; g->flatten(f,false); if(f.precyclic()) return new pathguide(g->solve().reverse()); size_t n=f.size(); bool cyclic=g->cyclic(); guidevector v; size_t start=cyclic ? n : n-1; knot curr=f.Nodes(start); knot next; for(size_t i=start; i > 0; --i) { next=f.Nodes(i-1); v.push_back(new pairguide(curr.z)); if(next.out->controlled()) { assert(curr.in->controlled()); v.push_back(new controlguide(curr.in->control(),next.out->control())); } else { pair d=curr.in->dir(); if(d != zero) v.push_back(new specguide(new dirSpec(-d),camp::OUT)); else { real C=curr.in->curl(); if(C >= 0.0) v.push_back(new specguide(new curlSpec(C),camp::OUT)); } real tout=curr.tin.val; real tin=next.tout.val; bool atleast=next.tout.atleast; if(tout != 1.0 || tin != 1.0 || next.tout.atleast) v.push_back(new tensionguide(tensionSpecifier(tout,tin,atleast))); d=next.out->dir(); if(d != zero) v.push_back(new specguide(new dirSpec(-d),camp::IN)); else { real C=next.out->curl(); if(C >= 0.0) v.push_back(new specguide(new curlSpec(C),camp::IN)); } } curr=next; } if(cyclic) v.push_back(new cycletokguide()); else v.push_back(new pairguide(next.z)); return new multiguide(v); } realarray *_cputime() { static const real ticktime=1.0/sysconf(_SC_CLK_TCK); struct tms buf; ::times(&buf); array *t=new array(4); (*t)[0] = ((real) buf.tms_utime)*ticktime; (*t)[1] = ((real) buf.tms_stime)*ticktime; (*t)[2] = ((real) buf.tms_cutime)*ticktime; (*t)[3] = ((real) buf.tms_cstime)*ticktime; return t; } // Transforms bool ==(transform a, transform b) { return a == b; } bool !=(transform a, transform b) { return a != b; } transform +(transform a, transform b) { return a+b; } transform Operator *(transform a, transform b) { return a*b; } pair Operator *(transform t, pair z) { return t*z; } path Operator *(transform t, path g) { return transformed(t,g); } pen Operator *(transform t, pen p) { return transformed(t,p); } picture * Operator *(transform t, picture *f) { return transformed(t,f); } picture * Operator *(realarray2 *t, picture *f) { return transformed(*t,f); } transform ^(transform t, Int n) { transform T; if(n < 0) { n=-n; t=inverse(t); } for(Int i=0; i < n; i++) T=T*t; return T; } real :transformXPart(transform t) { return t.getx(); } real :transformYPart(transform t) { return t.gety(); } real :transformXXPart(transform t) { return t.getxx(); } real :transformXYPart(transform t) { return t.getxy(); } real :transformYXPart(transform t) { return t.getyx(); } real :transformYYPart(transform t) { return t.getyy(); } transform :real6ToTransform(real x, real y, real xx, real xy, real yx, real yy) { return transform(x,y,xx,xy,yx,yy); } transform shift(transform t) { return transform(t.getx(),t.gety(),0,0,0,0); } transform shiftless(transform t) { return transform(0,0,t.getxx(),t.getxy(),t.getyx(),t.getyy()); } transform identity:transformIdentity() { return identity; } transform inverse(transform t) { return inverse(t); } transform shift(pair z) { return shift(z); } transform shift(real x, real y) { return shift(pair(x,y)); } transform xscale(real x) { return xscale(x); } transform yscale(real y) { return yscale(y); } transform scale(real x) { return scale(x); } transform scale(real x, real y) { return scale(x,y); } transform slant(real s) { return slant(s); } transform rotate(real angle, pair z=0) { return rotatearound(z,radians(angle)); } transform reflect(pair a, pair b) { return reflectabout(a,b); } asymptote-2.37/runtime.pl000077500000000000000000000160761265434602500155360ustar00rootroot00000000000000#!/usr/bin/env perl ###### # runtime.pl # Tom Prince 2004/4/15 # # Generate the runtime functions used by the vm::stack machine. # ##### $prefix = shift(@ARGV); if (not $prefix) { print STDERR "usage: ./runtime.pl module_name\n"; exit(1); } $stack = "Stack"; my $errors = 0; sub report_error { my $filename = shift; my $line = shift; my $error = shift; print STDERR "$filename:$line: $error\n"; $errors = 1; } sub assoc_error { my $filename = shift; my $line = shift; my $type = shift; report_error($filename, $line, "no asy type associated to '$type'"); } sub clean_type { for (@_) { s/\s//g; } } sub clean_params { for (@_) { s/\n//g; } } my %type_map; sub read_types { my @types = split /\n/, shift; my $filename = shift; my $line = shift; for (@types) { ++$line; # Remove // comments. s/\/\/.*//g; # Skip blank lines. next if /^\s*$/; my ($type,$code) = m|(\w*(?:\s*\*)?) \s*=>\s* (.*) |x; if (not $type) { report_error($filename, $line, "bad type declaration"); } clean_type($type); $type_map{$type} = $code; } } # Scrape the symbol names of the operators from opsymbols.h. my %opsymbols = (); open(opsyms, "opsymbols.h") || die("Couldn't open opsymbols.h"); while () { if (m/^OPSYMBOL\(\"(.*)\", ([A-Za-z_]+)\);/) { $opsymbols{ $1 } = $2; } } # Turn a name into a symbol. sub symbolize { my $name = shift; if ($name =~ /^[A-Za-z0-9_]+$/) { return "SYM($name)"; } if ($opsymbols{ $name }) { return $opsymbols{ $name }; } if ($name =~ /operator (\w+)/ && $opsymbols{ $1 }) { return $opsymbols{ $1 } } return "symbol::trans(\"" . $name . "\")" } sub asy_params { my $params = shift; my @params = split m/,\s*/, $params; my $filename = shift; my $line = shift; for (@params) { my ($explicit, $type, $name, $default) = m|^\s* (explicit)*\s*(\w*(?:\s*\*)?) \s* (\w*)(=*)|xs; clean_type($type); if (not $type_map{$type}) { assoc_error($filename, $line, $type); } $_ = "formal(" . $type_map{$type} . ", " . symbolize(lc($name)) . ", " . ($default ? "true" : "false") . ", " . ($explicit ? "true" : "false") . ")"; } return @params; } sub c_params { my @params = @_; for (@params) { my ($explicit, $type, $name, $default, $value) = m|^\s* (explicit)*\s*(\w*(?:\s*\*)?) \s* (\w*)(=*)([\w.+\-]*)|xs; $_ = " $type $name=vm::pop" . ($type =~ /^item$/ ? "" : "<$type>") . "($stack" . ($default ? "," . $value : "") . ");\n"; } reverse @params; } $/ = "\f\n"; open STDIN, "<$prefix.in" or die "can't open input file $prefix.in"; open BASE, "$prefix.cc" or die "can't open output file $prefix.cc"; my $autogenerated= "/***** Autogenerated from $prefix.in; changes will be overwritten *****/\n\n"; my $base_source_line = 1; my $source_line = 1; print $autogenerated; print "#line $base_source_line \"runtimebase.in\"\n"; $baseheader = ; print $baseheader; $basesource_line += ($baseheader =~ tr/\n//);; my $basesource_type_line = $basesource_line; print "#line $source_line \"$prefix.in\"\n"; $header = <>; print $header; $source_line += ($header =~ tr/\n//);; my $source_type_line = $source_line; $basetypes = ; $basesource_line += ($basetypes =~ tr/\n//);; $types = <>; $source_line += ($types =~ tr/\n//);; print "#line $base_source_line \"runtimebase.in\"\n"; $baseheader = ; print $baseheader; $basesource_line += ($baseheader =~ tr/\n//);; print "#line $source_line \"$prefix.in\"\n"; $header = <>; print $header; $source_line += ($header =~ tr/\n//);; print "\n#ifndef NOSYM"; print "\n#include \"$prefix.symbols.h\"\n"; print "\n#endif"; print "\nnamespace run {\n"; read_types($basetypes, "runtimebase.in", $basesource_type_line); read_types($types, "$prefix.in", $source_type_line); ### Begining of `$prefix.h' push @header, $autogenerated; # TODO: Capitalize prefix push @header, "#ifndef " . $prefix . "_H\n"; push @header, "#define " . $prefix . "_H\n"; push @header, "namespace run {\n"; my $count = 0; while (<>) { my ($comments,$type,$name,$cname,$params,$code) = m|^((?:\s*//[^\n]*\n)*) # comment lines \s* (\w*(?:\s*\*)?) # return type \s* ([^(:]*)\:*([^(]*) # function name \s* \(([\w\s*,=.+\-]*)\) # parameters \s* \{(.*)} # body |xs; if (not $type) { report_error("$prefix.in", $source_line, "bad function definition"); } if($cname) {push @header, "void $cname(vm::stack *);\n";} else {$cname="gen_$prefix${count}";} # Unique C++ function name clean_type($type); my @params = split m/,\s*/, $params; # Build addFunc call for asymptote if($name) { $name =~ s/Operator\s*//; if (not $type_map{$type}) { assoc_error("$prefix.in", $source_line, $type); } my @asy_params = asy_params($params, "$prefix.in", $source_line); push @builtin, "#line $source_line \"$prefix.in\"\n" . " addFunc(ve, run::" . $cname . ", " . $type_map{$type} . ", " . symbolize($name) . ( @params ? ", " . join(", ",@asy_params) : "" ) . ");\n"; } # Build REGISTER_BLTIN command for builtin functions which are not added to # the environment. if (not $name and $cname) { push @builtin, "#line $source_line \"$prefix.in\"\n" . " REGISTER_BLTIN(run::" . $cname . ',"' . $cname . '"' . ");\n"; } # Handle marshalling of values to/from stack $qualifier = ($type eq "item" ? "" : "<$type>"); $code =~ s/\breturn ([^;]*);/{$stack->push$qualifier($1); return;}/g; $args = join("",c_params(@params)); print $comments; $ncomments = ($comments =~ tr/\n//); $source_line += $ncomments; print "#line $source_line \"$prefix.in\"\n"; my $prototype=$type . " " . $name . "(" . $params . ");"; $nprototype = ($prototype =~ tr/\n//)+1; $source_line += $nprototype; if($name) { clean_params($prototype); print "// $prototype\n"; } print "void $cname(stack *"; if($type ne "void" or $params ne "") {print $stack;} print ")\n{\n$args"; print "#line $source_line \"$prefix.in\""; print "$code}\n\n"; $source_line -= $ncomments+$nprototype; $source_line += ($_ =~ tr/\n//); ++$count; } print "} // namespace run\n"; print "\nnamespace trans {\n\n"; print "void gen_${prefix}_venv(venv &ve)\n{\n"; print @builtin; print "}\n\n"; print "} // namespace trans\n"; ### End of `header.h' push @header, "}\n\n"; push @header, "#endif // ". $prefix . "_H\n"; undef $/; open HEADER, "<", "$prefix.h"; $orig_header =

    ; $new_header = join "", @header; if ($new_header ne $orig_header) { open HEADER, ">", "$prefix.h"; print HEADER $new_header; } if ($errors) { unlink("$prefix.h"); unlink("$prefix.cc"); } exit($errors); asymptote-2.37/runtimebase.in000066400000000000000000000024771265434602500163610ustar00rootroot00000000000000/***** * runtimebase.in * Andy Hammerlindl 2009/07/28 * * Common declarations needed for all code-generating .in files. * *****/ // Basic types need by almost all .in files. // Use Void f() instead of void f() to force an explicit Stack argument. void => primVoid() Void => primVoid() Int => primInt() bool => primBoolean() double => primReal() real => primReal() string* => primString() string => primString() #include "stack.h" #include "types.h" #include "builtin.h" #include "entry.h" #include "errormsg.h" #include "array.h" #include "triple.h" #include "callable.h" #include "opsymbols.h" using vm::stack; using vm::error; using vm::array; using vm::read; using vm::callable; using types::formal; using types::function; using camp::triple; #define PRIMITIVE(name,Name,asyName) using types::prim##Name; #include #undef PRIMITIVE typedef double real; void unused(void *); namespace run { array *copyArray(array *a); array *copyArray2(array *a); array *copyArray3(array *a); double *copyTripleArray2Components(array *a, size_t &N, GCPlacement placement=NoGC); triple *copyTripleArray2C(array *a, size_t &N, GCPlacement placement=NoGC); } function *realRealFunction(); #define CURRENTPEN processData().currentpen asymptote-2.37/runtriple.in000066400000000000000000000052451265434602500160630ustar00rootroot00000000000000/***** * runtriple.in * * Runtime functions for triple operations. * *****/ triple => primTriple() #include "triple.h" #include "path3.h" using namespace camp; // Autogenerated routines: triple :tripleZero() { static triple zero; return zero; } triple :realRealRealToTriple(real x, real y, real z) { return triple(x,y,z); } real xpart:tripleXPart(triple v) { return v.getx(); } real ypart:tripleYPart(triple v) { return v.gety(); } real zpart:tripleZPart(triple v) { return v.getz(); } triple Operator *(real x, triple v) { return x*v; } triple Operator *(triple v, real x) { return v*x; } triple /(triple v, real x) { return v/x; } real length(triple v) { return v.length(); } real abs(triple v) { return v.length(); } real polar(triple v, bool warn=true) { if(!warn && v.getx() == 0.0 && v.gety() == 0.0 && v.getz() == 0.0) return 0.0; return v.polar(); } real azimuth(triple v, bool warn=true) { if(!warn && v.getx() == 0.0 && v.gety() == 0.0) return 0.0; return v.azimuth(); } real colatitude(triple v, bool warn=true) { if(!warn && v.getx() == 0.0 && v.gety() == 0.0 && v.getz() == 0.0) return 0.0; return degrees(v.polar()); } real latitude(triple v, bool warn=true) { if(!warn && v.getx() == 0.0 && v.gety() == 0.0 && v.getz() == 0.0) return 0.0; return 90.0-degrees(v.polar()); } // Return the longitude of v in [0,360). real longitude(triple v, bool warn=true) { if(!warn && v.getx() == 0.0 && v.gety() == 0.0) return 0.0; return principalBranch(degrees(v.azimuth())); } triple unit(triple v) { return unit(v); } real dot(triple u, triple v) { return dot(u,v); } triple cross(triple u, triple v) { return cross(u,v); } triple dir(explicit triple z) { return unit(z); } triple expi(real polar, real azimuth) { return expi(polar,azimuth); } triple dir(real colatitude, real longitude) { return expi(radians(colatitude),radians(longitude)); } triple realmult(triple u, triple v) { return triple (u.getx()*v.getx(),u.gety()*v.gety(),u.getz()*v.getz()); } // Return the component of vector v perpendicular to a unit vector u. triple perp(triple v, triple u) { return perp(v,u); } triple bezier(triple a, triple b, triple c, triple d, real t) { real onemt=1-t; real onemt2=onemt*onemt; return onemt2*onemt*a+t*(3.0*(onemt2*b+t*onemt*c)+t*t*d); } triple bezierP(triple a, triple b, triple c, triple d, real t) { return 3.0*(t*t*(d-a+3.0*(b-c))+t*(2.0*(a+c)-4.0*b)+b-a); } triple bezierPP(triple a, triple b, triple c, triple d, real t) { return 6.0*(t*(d-a+3.0*(b-c))+a+c-2.0*b); } triple bezierPPP(triple a, triple b, triple c, triple d) { return 6.0*(d-a+3.0*(b-c)); } asymptote-2.37/seconds.h000066400000000000000000000041011265434602500153040ustar00rootroot00000000000000#ifndef __seconds_h__ #define __seconds_h__ 1 #ifdef _WIN32 #include #include #include #include #if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 #else #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL #endif struct timezone { int tz_minuteswest; /* minutes W of Greenwich */ int tz_dsttime; /* type of dst correction */ }; // Definition of a gettimeofday function inline int gettimeofday(struct timeval *tv, struct timezone *tz) { // Define a structure to receive the current Windows filetime FILETIME ft; // Initialize the present time to 0 and the timezone to UTC unsigned __int64 tmpres = 0; static int tzflag = 0; if (NULL != tv) { GetSystemTimeAsFileTime(&ft); // The GetSystemTimeAsFileTime returns the number of 100 nanosecond // intervals since Jan 1, 1601 in a structure. Copy the high bits to // the 64 bit tmpres, shift it left by 32 then or in the low 32 bits. tmpres |= ft.dwHighDateTime; tmpres <<= 32; tmpres |= ft.dwLowDateTime; // Convert to microseconds by dividing by 10 tmpres /= 10; // The Unix epoch starts on Jan 1 1970. Need to subtract the difference // in seconds from Jan 1 1601. tmpres -= DELTA_EPOCH_IN_MICROSECS; // Finally change microseconds to seconds and place in the seconds value. // The modulus picks up the microseconds. tv->tv_sec = (long)(tmpres / 1000000UL); tv->tv_usec = (long)(tmpres % 1000000UL); } if (NULL != tz) { if (!tzflag) { _tzset(); tzflag++; } // Adjust for the timezone west of Greenwich tz->tz_minuteswest = _timezone / 60; tz->tz_dsttime = _daylight; } return 0; } #else #include #endif namespace utils { inline double totalseconds() { timeval tv; gettimeofday(&tv,NULL); return tv.tv_sec+tv.tv_usec/1000000.0; } inline double seconds() { static double lastseconds=totalseconds(); double t=totalseconds(); double seconds=t-lastseconds; lastseconds=t; return seconds; } } #endif asymptote-2.37/settings.cc000066400000000000000000001357741265434602500156710ustar00rootroot00000000000000/***** * settings.cc * Andy Hammerlindl 2004/05/10 * * Declares a list of global variables that act as settings in the system. *****/ #include #include #include #include #include #include #include #include #include #include "common.h" #if HAVE_GNU_GETOPT_H #include #else #include "getopt.h" #endif #include "util.h" #include "settings.h" #include "interact.h" #include "locate.h" #include "lexical.h" #include "record.h" #include "env.h" #include "item.h" #include "refaccess.h" #include "pipestream.h" #include "array.h" #ifdef HAVE_LIBCURSES extern "C" { #ifdef HAVE_NCURSES_CURSES_H #include #include #elif HAVE_NCURSES_H #include #include #elif HAVE_CURSES_H #include #include #endif } #endif // Workaround broken curses.h files: #ifdef clear #undef clear #endif // Workaround broken header file on i386-solaris with g++ 3.4.3. #ifdef erase #undef erase #endif using vm::item; using trans::itemRefAccess; using trans::refAccess; using trans::varEntry; using vm::array; void runFile(const string& filename); namespace settings { using camp::pair; #ifdef HAVE_GL const bool havegl=true; #else const bool havegl=false; #endif mode_t mask; string systemDir=ASYMPTOTE_SYSDIR; #ifndef __MSDOS__ bool msdos=false; string HOME="HOME"; string docdir=ASYMPTOTE_DOCDIR; const char pathSeparator=':'; string defaultPSViewer="gv"; #ifdef __APPLE__ string defaultPDFViewer="open"; #else string defaultPDFViewer="acroread"; #endif string defaultGhostscript="gs"; string defaultGhostscriptLibrary="/usr/lib/libgs.so"; string defaultDisplay="display"; string defaultAnimate="animate"; void queryRegistry() {} const string dirsep="/"; #else bool msdos=true; string HOME="USERPROFILE"; string docdir="c:\\Program Files\\Asymptote"; const char pathSeparator=';'; //string defaultPSViewer="gsview32.exe"; string defaultPSViewer="cmd"; //string defaultPDFViewer="AcroRd32.exe"; string defaultPDFViewer="cmd"; string defaultGhostscript; string defaultGhostscriptLibrary; //string defaultDisplay="imdisplay"; string defaultDisplay="cmd"; //string defaultAnimate="animate"; string defaultAnimate="cmd"; const string dirsep="\\"; #include // Use key to look up an entry in the MSWindows registry, respecting wild cards string getEntry(const string& location, const string& key) { string path="/proc/registry"+location+key; size_t star; string head; while((star=path.find("*")) < string::npos) { string prefix=path.substr(0,star); string suffix=path.substr(star+1); size_t slash=suffix.find("/"); if(slash < string::npos) { path=suffix.substr(slash); suffix=suffix.substr(0,slash); } else { path=suffix; suffix=""; } string directory=head+stripFile(prefix); string file=stripDir(prefix); DIR *dir=opendir(directory.c_str()); if(dir == NULL) return ""; dirent *p; string rsuffix=suffix; reverse(rsuffix.begin(),rsuffix.end()); while((p=readdir(dir)) != NULL) { string dname=p->d_name; string rdname=dname; reverse(rdname.begin(),rdname.end()); if(dname != "." && dname != ".." && dname.substr(0,file.size()) == file && rdname.substr(0,suffix.size()) == rsuffix) { head=directory+p->d_name; break; } } if(p == NULL) return ""; } std::ifstream fin((head+path).c_str()); if(fin) { string s; getline(fin,s); size_t end=s.find('\0'); if(end < string::npos) return s.substr(0,end); } return ""; } // Use key to look up an entry in the MSWindows registry, respecting wild cards string getEntry(const string& key) { string entry=getEntry("64/HKEY_CURRENT_USER/Software/",key); if(entry.empty()) entry=getEntry("64/HKEY_LOCAL_MACHINE/SOFTWARE/",key); if(entry.empty()) entry=getEntry("/HKEY_CURRENT_USER/Software/",key); if(entry.empty()) entry=getEntry("/HKEY_LOCAL_MACHINE/SOFTWARE/",key); return entry; } void queryRegistry() { defaultGhostscriptLibrary=getEntry("GPL Ghostscript/*/GS_DLL"); if(defaultGhostscriptLibrary.empty()) defaultGhostscriptLibrary=getEntry("AFPL Ghostscript/*/GS_DLL"); string gslib=stripDir(defaultGhostscriptLibrary); defaultGhostscript=stripFile(defaultGhostscriptLibrary)+ ((gslib.empty() || gslib.substr(5,2) == "32") ? "gswin32c.exe" : "gswin64c.exe"); if(defaultPDFViewer != "cmd") defaultPDFViewer=getEntry("Adobe/Acrobat Reader/*/InstallPath/@")+"\\"+ defaultPDFViewer; if(defaultPSViewer != "cmd") defaultPSViewer=getEntry("Ghostgum/GSview/*")+"\\gsview\\"+defaultPSViewer; string s; s=getEntry("Microsoft/Windows/CurrentVersion/App Paths/Asymptote/Path"); if(!s.empty()) docdir=s; // An empty systemDir indicates a TeXLive build if(!systemDir.empty() && !docdir.empty()) systemDir=docdir; } #endif const char PROGRAM[]=PACKAGE_NAME; const char VERSION[]=PACKAGE_VERSION; const char BUGREPORT[]=PACKAGE_BUGREPORT; // The name of the program (as called). Used when displaying help info. char *argv0; // The verbosity setting, a global variable. Int verbose; // Conserve memory at the expense of speed. bool compact; // Colorspace conversion flags (stored in global variables for efficiency). bool gray; bool bw; bool rgb; bool cmyk; // Disable system calls. bool safe=true; // Enable writing to (or changing to) other directories bool globaloption=false; bool globalwrite() {return globaloption || !safe;} const string suffix="asy"; const string guisuffix="gui"; const string standardprefix="out"; string initdir; string historyname; // Local versions of the argument list. int argCount = 0; char **argList = 0; typedef ::option c_option; types::dummyRecord *settingsModule; types::record *getSettingsModule() { return settingsModule; } void noWarn(const string& s) { array *Warn=getSetting("suppress"); size_t size=checkArray(Warn); if(s.empty()) return; for(size_t i=0; i < size; i++) if(vm::read(Warn,i) == s) return; Warn->push(s); } void Warn(const string& s) { array *Warn=getSetting("suppress"); size_t size=checkArray(Warn); for(size_t i=0; i < size; i++) if(vm::read(Warn,i) == s) (*Warn).erase((*Warn).begin()+i,(*Warn).begin()+i+1); } bool warn(const string& s) { if(getSetting("debug")) return true; array *Warn=getSetting("suppress"); size_t size=checkArray(Warn); for(size_t i=0; i < size; i++) if(vm::read(Warn,i) == s) return false; return true; } // The dictionaries of long options and short options. struct option; typedef mem::map optionsMap_t; optionsMap_t optionsMap; typedef mem::map codeMap_t; codeMap_t codeMap; struct option : public gc { string name; char code; // Command line option, i.e. 'V' for -V. bool argument; // If it takes an argument on the command line. This is set // based on whether argname is empty. string argname; // The argument name for printing the description. string desc; // One line description of what the option does. bool cmdlineonly; // If it is only available on the command line. string Default; // A string containing an optional default value. option(string name, char code, string argname, string desc, bool cmdlineonly=false, string Default="") : name(name), code(code), argument(!argname.empty()), argname(argname), desc(desc), cmdlineonly(cmdlineonly), Default(Default) {} virtual ~option() {} // Builds this option's contribution to the optstring argument of get_opt(). virtual string optstring() { if (code) { string base; base.push_back(code); if(argument) base.push_back(':'); return base; } else return ""; } // Sets the contribution to the longopt array. virtual void longopt(c_option &o) { o.name=name.c_str(); o.has_arg=argument ? 1 : 0; o.flag=0; o.val=0; } // Add to the dictionaries of options. virtual void add() { optionsMap[name]=this; if (code) codeMap[code]=this; } // Set the option from the command-line argument. Return true if the option // was correctly parsed. virtual bool getOption() = 0; void error(string msg) { cerr << endl << argv0 << ": "; if (code) cerr << "-" << code << " "; cerr << "(-" << name << ") " << msg << endl; } // The "-f,-outformat format" part of the option. virtual string describeStart() { ostringstream ss; if (code) ss << "-" << code << ","; ss << "-" << name; if (argument) ss << " " << argname; return ss.str(); } // Outputs description of the command for the -help option. virtual void describe() { // Don't show the option if it has no desciption. if (!desc.empty()) { const unsigned WIDTH=22; string start=describeStart(); cerr << std::left << std::setw(WIDTH) << start; if (start.size() >= WIDTH) { cerr << endl; cerr << std::left << std::setw(WIDTH) << ""; } cerr << " " << desc; if(cmdlineonly) cerr << "; command-line only"; if(Default != "") cerr << " [" << Default << "]"; cerr << endl; } } virtual void reset() { } }; const string noarg; struct setting : public option { types::ty *t; private: trans::permission perm; bool added; // Flag the setting as secure, so that it can only be set on the command-line, // though it can still be read in Asymptote code. void secure() { assert(!added); perm = trans::RESTRICTED; } public: setting(string name, char code, string argname, string desc, types::ty *t, string Default) : option(name, code, argname, desc, false,Default), t(t), perm(trans::PUBLIC), added(false) {} void reset() = 0; virtual trans::access *buildAccess() = 0; // Add to the dictionaries of options and to the settings module. virtual void add() { assert(!added); option::add(); settingsModule->add(name, t, buildAccess(), perm); added=true; } friend void addSecureSetting(setting *s) { s->secure(); s->add(); } }; struct itemSetting : public setting { item defaultValue; item value; itemSetting(string name, char code, string argname, string desc, types::ty *t, item defaultValue, string Default="") : setting(name, code, argname, desc, t, Default), defaultValue(defaultValue) {reset();} void reset() { value=defaultValue; } trans::access *buildAccess() { return new itemRefAccess(&(value)); } }; item& Setting(string name) { itemSetting *s=dynamic_cast(optionsMap[name]); if(!s) { cerr << "Cannot find setting named '" << name << "'" << endl; exit(-1); } return s->value; } struct boolSetting : public itemSetting { boolSetting(string name, char code, string desc, bool defaultValue=false) : itemSetting(name, code, noarg, desc, types::primBoolean(), (item)defaultValue, defaultValue ? "true" : "false") {} bool getOption() { value=(item)true; return true; } option *negation(string name) { struct negOption : public option { boolSetting &base; negOption(boolSetting &base, string name) : option(name, 0, noarg, ""), base(base) {} bool getOption() { base.value=(item)false; return true; } }; return new negOption(*this, name); } void add() { setting::add(); negation("no"+name)->add(); if (code) { string nocode="no"; nocode.push_back(code); negation(nocode)->add(); } } // Set several related boolean options at once. Used for view and trap which // have batch and interactive settings. struct multiOption : public option { typedef mem::list setlist; setlist set; multiOption(string name, char code, string desc) : option(name, code, noarg, desc, true) {} void add(boolSetting *s) { set.push_back(s); } void setValue(bool value) { for (setlist::iterator s=set.begin(); s!=set.end(); ++s) (*s)->value=(item)value; } bool getOption() { setValue(true); return true; } option *negation(string name) { struct negOption : public option { multiOption &base; negOption(multiOption &base, string name) : option(name, 0, noarg, ""), base(base) {} bool getOption() { base.setValue(false); return true; } }; return new negOption(*this, name); } void add() { option::add(); negation("no"+name)->add(); if (code) { string nocode="no"; nocode.push_back(code); negation(nocode)->add(); } for (multiOption::setlist::iterator s=set.begin(); s!=set.end(); ++s) (*s)->add(); } }; }; typedef boolSetting::multiOption multiOption; struct argumentSetting : public itemSetting { argumentSetting(string name, char code, string argname, string desc, types::ty *t, item defaultValue) : itemSetting(name, code, argname, desc, t, defaultValue) { assert(!argname.empty()); } }; struct stringSetting : public argumentSetting { stringSetting(string name, char code, string argname, string desc, string defaultValue="") : argumentSetting(name, code, argname, desc.empty() ? "" : desc+(defaultValue.empty() ? "" : " ["+defaultValue+"]"), types::primString(), (item)defaultValue) {} bool getOption() { value=(item)(string)optarg; return true; } }; struct userSetting : public argumentSetting { userSetting(string name, char code, string argname, string desc, string defaultValue="") : argumentSetting(name, code, argname, desc, types::primString(), (item)defaultValue) {} bool getOption() { string s=vm::get(value)+string(optarg); s.push_back(';'); value=(item) s; return true; } }; struct warnSetting : public option { warnSetting(string name, char code, string argname, string desc) : option(name, code, argname, desc, true) {} bool getOption() { Warn(string(optarg)); return true; } option *negation(string name) { struct negOption : public option { warnSetting &base; negOption(warnSetting &base, string name, string argname) : option(name, 0, argname, ""), base(base) {} bool getOption() { noWarn(string(optarg)); return true; } }; return new negOption(*this, name, argname); } void add() { option::add(); negation("no"+name)->add(); if (code) { string nocode="no"; nocode.push_back(code); negation(nocode)->add(); } } }; string GetEnv(string s, string Default) { transform(s.begin(), s.end(), s.begin(), toupper); string t=Getenv(("ASYMPTOTE_"+s).c_str(),msdos); return t.empty() ? Default : t; } struct envSetting : public stringSetting { envSetting(string name, string Default) : stringSetting(name, 0, " ", "", GetEnv(name,Default)) {} }; template struct dataSetting : public argumentSetting { string text; dataSetting(const char *text, string name, char code, string argname, string desc, types::ty *type, T defaultValue) : argumentSetting(name, code, argname, desc, type, (item)defaultValue), text(text) {} bool getOption() { try { value=(item)lexical::cast(optarg); } catch (lexical::bad_cast&) { error("option requires " + text + " as an argument"); return false; } return true; } }; template string description(string desc, T defaultValue) { return desc.empty() ? "" : desc+" ["+String(defaultValue)+"]"; } struct IntSetting : public dataSetting { IntSetting(string name, char code, string argname, string desc, Int defaultValue=0) : dataSetting("an int", name, code, argname, description(desc,defaultValue), types::primInt(), defaultValue) {} }; struct realSetting : public dataSetting { realSetting(string name, char code, string argname, string desc, double defaultValue=0.0) : dataSetting("a real", name, code, argname, description(desc,defaultValue), types::primReal(), defaultValue) {} }; struct pairSetting : public dataSetting { pairSetting(string name, char code, string argname, string desc, pair defaultValue=0.0) : dataSetting("a pair", name, code, argname, description(desc,defaultValue), types::primPair(), defaultValue) {} }; // For setting the alignment of a figure on the page. struct alignSetting : public argumentSetting { alignSetting(string name, char code, string argname, string desc, string defaultValue) : argumentSetting(name, code, argname, description(desc,defaultValue), types::primString(), (item)defaultValue) {} bool getOption() { string str=optarg; if(str == "C" || str == "T" || str == "B" || str == "Z") { value=str; return true; } error("invalid argument for option"); return false; } }; struct stringArraySetting : public itemSetting { stringArraySetting(string name, array *defaultValue) : itemSetting(name, 0, "", "", types::stringArray(), (item) defaultValue) {} bool getOption() {return true;} }; struct engineSetting : public argumentSetting { engineSetting(string name, char code, string argname, string desc, string defaultValue) : argumentSetting(name, code, argname, description(desc,defaultValue), types::primString(), (item)defaultValue) {} bool getOption() { string str=optarg; if(str == "latex" || str == "pdflatex" || str == "xelatex" || str == "tex" || str == "pdftex" || str == "luatex" || str == "lualatex" || str == "context" || str == "none") { value=str; return true; } error("invalid argument for option"); return false; } }; template string stringCast(T x) { ostringstream buf; buf.precision(DBL_DIG); buf.setf(std::ios::boolalpha); buf << x; return string(buf.str()); } template struct refSetting : public setting { T *ref; T defaultValue; string text; refSetting(string name, char code, string argname, string desc, types::ty *t, T *ref, T defaultValue, const char *text="") : setting(name, code, argname, desc, t, stringCast(defaultValue)), ref(ref), defaultValue(defaultValue), text(text) { reset(); } virtual bool getOption() { try { *ref=lexical::cast(optarg); } catch (lexical::bad_cast&) { error("option requires " + text + " as an argument"); return false; } return true; } virtual void reset() { *ref=defaultValue; } trans::access *buildAccess() { return new refAccess(ref); } }; struct boolrefSetting : public refSetting { boolrefSetting(string name, char code, string desc, bool *ref, bool Default=false) : refSetting(name, code, noarg, desc, types::primBoolean(), ref, Default) {} virtual bool getOption() { *ref=true; return true; } virtual option *negation(string name) { struct negOption : public option { boolrefSetting &base; negOption(boolrefSetting &base, string name) : option(name, 0, noarg, ""), base(base) {} bool getOption() { *(base.ref)=false; return true; } }; return new negOption(*this, name); } void add() { setting::add(); negation("no"+name)->add(); if (code) { string nocode="no"; nocode.push_back(code); negation(nocode)->add(); } } }; struct compactSetting : public boolrefSetting { compactSetting(string name, char code, string desc, bool *ref, bool Default=false) : boolrefSetting(name,code,desc,ref,Default) {} bool getOption() { mem::compact(1); return boolrefSetting::getOption(); } option *negation(string name) { mem::compact(0); return boolrefSetting::negation(name); } }; struct incrementSetting : public refSetting { incrementSetting(string name, char code, string desc, Int *ref) : refSetting(name, code, noarg, desc, types::primInt(), ref, 0) {} bool getOption() { // Increment the value. ++(*ref); return true; } option *negation(string name) { struct negOption : public option { incrementSetting &base; negOption(incrementSetting &base, string name) : option(name, 0, noarg, ""), base(base) {} bool getOption() { if(*base.ref) --(*base.ref); return true; } }; return new negOption(*this, name); } void add() { setting::add(); negation("no"+name)->add(); if (code) { string nocode="no"; nocode.push_back(code); negation(nocode)->add(); } } }; struct incrementOption : public option { Int *ref; Int level; incrementOption(string name, char code, string desc, Int *ref, Int level=1) : option(name, code, noarg, desc, true), ref(ref), level(level) {} bool getOption() { // Increment the value. (*ref) += level; return true; } }; void addOption(option *o) { o->add(); } void version() { cerr << PROGRAM << " version " << REVISION << " [(C) 2004 Andy Hammerlindl, John C. Bowman, Tom Prince]" << endl; } void usage(const char *program) { version(); cerr << "\t\t\t" << "http://asymptote.sourceforge.net/" << endl << "Usage: " << program << " [options] [file ...]" << endl; } void reportSyntax() { cerr << endl; usage(argv0); cerr << endl << "Type '" << argv0 << " -h' for a description of options." << endl; exit(1); } void displayOptions() { cerr << endl; cerr << "Options (negate by replacing - with -no): " << endl << endl; for (optionsMap_t::iterator opt=optionsMap.begin(); opt!=optionsMap.end(); ++opt) opt->second->describe(); } struct helpOption : public option { helpOption(string name, char code, string desc) : option(name, code, noarg, desc, true) {} bool getOption() { usage(argv0); displayOptions(); cerr << endl; exit(0); // Unreachable code. return true; } }; struct versionOption : public option { versionOption(string name, char code, string desc) : option(name, code, noarg, desc, true) {} bool getOption() { version(); exit(0); // Unreachable code. return true; } }; struct divisorOption : public option { divisorOption(string name, char code, string argname, string desc) : option(name, code, argname, desc) {} bool getOption() { try { #ifdef USEGC Int n=lexical::cast(optarg); if(n > 0) GC_set_free_space_divisor((GC_word) n); #endif } catch (lexical::bad_cast&) { error("option requires an int as an argument"); return false; } return true; } }; // For security reasons, these options aren't fields of the settings module. struct stringOption : public option { char **variable; stringOption(string name, char code, string argname, string desc, char **variable) : option(name, code, argname, desc, true), variable(variable) {} bool getOption() { *variable=optarg; return true; } }; string build_optstring() { string s; for (codeMap_t::iterator p=codeMap.begin(); p !=codeMap.end(); ++p) s +=p->second->optstring(); return s; } c_option *build_longopts() { size_t n=optionsMap.size(); c_option *longopts=new(UseGC) c_option[n+1]; Int i=0; for (optionsMap_t::iterator p=optionsMap.begin(); p !=optionsMap.end(); ++p, ++i) p->second->longopt(longopts[i]); longopts[n].name=NULL; longopts[n].has_arg=0; longopts[n].flag=NULL; longopts[n].val=0; return longopts; } void resetOptions() { for(optionsMap_t::iterator opt=optionsMap.begin(); opt != optionsMap.end(); ++opt) if(opt->first != "config" && opt->first != "dir" && opt->first != "sysdir") opt->second->reset(); } void getOptions(int argc, char *argv[]) { bool syntax=false; optind=0; string optstring=build_optstring(); //cerr << "optstring: " << optstring << endl; c_option *longopts=build_longopts(); int long_index = 0; errno=0; for(;;) { int c = getopt_long_only(argc,argv, optstring.c_str(), longopts, &long_index); if (c == -1) break; if (c == 0) { const char *name=longopts[long_index].name; //cerr << "long option: " << name << endl; if (!optionsMap[name]->getOption()) syntax=true; } else if (codeMap.find((char)c) != codeMap.end()) { //cerr << "char option: " << (char)c << endl; if (!codeMap[(char)c]->getOption()) syntax=true; } else { syntax=true; } errno=0; } if (syntax) reportSyntax(); } #ifdef USEGC void no_GCwarn(char *, GC_word) { } #endif array* stringArray(const char **s) { size_t count=0; while(s[count]) ++count; array *a=new array(count); for(size_t i=0; i < count; ++i) (*a)[i]=string(s[i]); return a; } void initSettings() { static bool initialize=true; if(initialize) { queryRegistry(); initialize=false; } settingsModule=new types::dummyRecord(symbol::trans("settings")); // Default mouse bindings // LEFT: rotate // SHIFT LEFT: zoom // CTRL LEFT: shift // ALT LEFT: pan const char *leftbutton[]={"rotate","zoom","shift","pan",NULL}; // MIDDLE: menu (must be unmodified; ignores Shift, Ctrl, and Alt) const char *middlebutton[]={"menu",NULL}; // RIGHT: zoom/menu (must be unmodified) // SHIFT RIGHT: rotateX // CTRL RIGHT: rotateY // ALT RIGHT: rotateZ const char *rightbutton[]={"zoom/menu","rotateX","rotateY","rotateZ",NULL}; // WHEEL_UP: zoomin const char *wheelup[]={"zoomin",NULL}; // WHEEL_DOWN: zoomout const char *wheeldown[]={"zoomout",NULL}; addOption(new stringArraySetting("leftbutton", stringArray(leftbutton))); addOption(new stringArraySetting("middlebutton", stringArray(middlebutton))); addOption(new stringArraySetting("rightbutton", stringArray(rightbutton))); addOption(new stringArraySetting("wheelup", stringArray(wheelup))); addOption(new stringArraySetting("wheeldown", stringArray(wheeldown))); addOption(new stringArraySetting("suppress", new array)); addOption(new warnSetting("warn", 0, "string", "Enable warning")); multiOption *view=new multiOption("View", 'V', "View output"); view->add(new boolSetting("batchView", 0, "View output in batch mode", msdos)); view->add(new boolSetting("multipleView", 0, "View output from multiple batch-mode files", false)); view->add(new boolSetting("interactiveView", 0, "View output in interactive mode", true)); addOption(view); addOption(new stringSetting("outformat", 'f', "format", "Convert each output file to specified format", "")); addOption(new boolSetting("svgemulation", 0, "Emulate unimplemented SVG shading", false)); addOption(new boolSetting("prc", 0, "Embed 3D PRC graphics in PDF output", true)); addOption(new boolSetting("toolbar", 0, "Show 3D toolbar in PDF output", true)); addOption(new boolSetting("axes3", 0, "Show 3D axes in PDF output", true)); addOption(new realSetting("render", 0, "n", "Render 3D graphics using n pixels per bp (-1=auto)", havegl ? -1.0 : 0.0)); addOption(new IntSetting("antialias", 0, "n", "Antialiasing width for rasterized output", 2)); addOption(new IntSetting("multisample", 0, "n", "Multisampling width for screen images", 4)); addOption(new boolSetting("offscreen", 0, "Use offscreen rendering",false)); addOption(new boolSetting("twosided", 0, "Use two-sided 3D lighting model for rendering", true)); addOption(new pairSetting("position", 0, "pair", "Initial 3D rendering screen position")); addOption(new pairSetting("maxviewport", 0, "pair", "Maximum viewport size",pair(2048,2048))); addOption(new pairSetting("maxtile", 0, "pair", "Maximum rendering tile size",pair(1024,768))); addOption(new boolSetting("iconify", 0, "Iconify rendering window", false)); addOption(new boolSetting("thick", 0, "Render thick 3D lines", true)); addOption(new boolSetting("thin", 0, "Render thin 3D lines", true)); addOption(new boolSetting("autobillboard", 0, "3D labels always face viewer by default", true)); addOption(new boolSetting("threads", 0, "Use POSIX threads for 3D rendering", !msdos)); addOption(new boolSetting("fitscreen", 0, "Fit rendered image to screen", true)); addOption(new boolSetting("interactiveWrite", 0, "Write expressions entered at the prompt to stdout", true)); addOption(new helpOption("help", 'h', "Show summary of options")); addOption(new versionOption("version", 0, "Show version")); addOption(new pairSetting("offset", 'O', "pair", "PostScript offset")); addOption(new pairSetting("aligndir", 0, "pair", "Directional page alignment (overrides align)")); addOption(new alignSetting("align", 'a', "C|B|T|Z", "Center, Bottom, Top, or Zero page alignment", "C")); addOption(new boolSetting("debug", 'd', "Enable debugging messages")); addOption(new incrementSetting("verbose", 'v', "Increase verbosity level (can specify multiple times)", &verbose)); // Resolve ambiguity with --version addOption(new incrementOption("vv", 0,"", &verbose,2)); addOption(new incrementOption("novv", 0,"", &verbose,-2)); addOption(new boolSetting("keep", 'k', "Keep intermediate files")); addOption(new boolSetting("keepaux", 0, "Keep intermediate LaTeX .aux files")); addOption(new engineSetting("tex", 0, "engine", "latex|pdflatex|xelatex|lualatex|tex|pdftex|luatex|context|none", "latex")); addOption(new boolSetting("twice", 0, "Run LaTeX twice (to resolve references)")); addOption(new boolSetting("inlinetex", 0, "Generate inline TeX code")); addOption(new boolSetting("embed", 0, "Embed rendered preview image", true)); addOption(new boolSetting("auto3D", 0, "Automatically activate 3D scene", true)); addOption(new boolSetting("autoplay", 0, "Autoplay 3D animations", false)); addOption(new boolSetting("loop", 0, "Loop 3D animations", false)); addOption(new boolSetting("interrupt", 0, "", false)); addOption(new boolSetting("animating", 0, "", false)); addOption(new boolSetting("reverse", 0, "reverse 3D animations", false)); addOption(new boolSetting("inlineimage", 0, "Generate inline embedded image")); addOption(new boolSetting("parseonly", 'p', "Parse file")); addOption(new boolSetting("translate", 's', "Show translated virtual machine code")); addOption(new boolSetting("tabcompletion", 0, "Interactive prompt auto-completion", true)); addOption(new boolSetting("listvariables", 'l', "List available global functions and variables")); addOption(new boolSetting("where", 0, "Show where listed variables are declared")); multiOption *mask=new multiOption("mask", 'm', "Mask fpu exceptions"); mask->add(new boolSetting("batchMask", 0, "Mask fpu exceptions in batch mode", false)); mask->add(new boolSetting("interactiveMask", 0, "Mask fpu exceptions in interactive mode", true)); addOption(mask); addOption(new boolrefSetting("bw", 0, "Convert all colors to black and white",&bw)); addOption(new boolrefSetting("gray", 0, "Convert all colors to grayscale", &gray)); addOption(new boolrefSetting("rgb", 0, "Convert cmyk colors to rgb",&rgb)); addOption(new boolrefSetting("cmyk", 0, "Convert rgb colors to cmyk",&cmyk)); addSecureSetting(new boolrefSetting("safe", 0, "Disable system call", &safe, true)); addSecureSetting(new boolrefSetting("globalwrite", 0, "Allow write to other directory", &globaloption, false)); addSecureSetting(new stringSetting("outname", 'o', "name", "Alternative output directory/filename")); addOption(new stringOption("cd", 0, "directory", "Set current directory", &startpath)); #ifdef USEGC addOption(new compactSetting("compact", 0, "Conserve memory at the expense of speed", &compact)); addOption(new divisorOption("divisor", 0, "n", "Garbage collect using purge(divisor=n) [2]")); #endif addOption(new stringSetting("prompt", 0,"string","Prompt","> ")); addOption(new stringSetting("prompt2", 0,"string", "Continuation prompt for multiline input ", "..")); addOption(new boolSetting("multiline", 0, "Input code over multiple lines at the prompt")); addOption(new boolSetting("wait", 0, "Wait for child processes to finish before exiting")); addOption(new IntSetting("inpipe", 0, "n","",-1)); addOption(new IntSetting("outpipe", 0, "n","",-1)); addOption(new boolSetting("exitonEOF", 0, "Exit interactive mode on EOF", true)); addOption(new boolSetting("quiet", 'q', "Suppress welcome message")); addOption(new boolSetting("localhistory", 0, "Use a local interactive history file")); addOption(new IntSetting("historylines", 0, "n", "Retain n lines of history",1000)); addOption(new IntSetting("scroll", 0, "n", "Scroll standard output n lines at a time",0)); addOption(new IntSetting("level", 0, "n", "Postscript level",3)); addOption(new boolSetting("autoplain", 0, "Enable automatic importing of plain", true)); addOption(new boolSetting("autorotate", 0, "Enable automatic PDF page rotation", false)); addOption(new boolSetting("pdfreload", 0, "Automatically reload document in pdfviewer", false)); addOption(new IntSetting("pdfreloaddelay", 0, "usec", "Delay before attempting initial pdf reload" ,750000)); addOption(new stringSetting("autoimport", 0, "string", "Module to automatically import")); addOption(new userSetting("command", 'c', "string", "Command to autoexecute")); addOption(new userSetting("user", 'u', "string", "General purpose user string")); addOption(new realSetting("zoomfactor", 0, "factor", "Zoom step factor", 1.05)); addOption(new realSetting("zoomstep", 0, "step", "Mouse motion zoom step", 0.1)); addOption(new realSetting("spinstep", 0, "deg/s", "Spin speed", 60.0)); addOption(new realSetting("framerate", 0, "frames/s", "Animation speed", 30.0)); addOption(new realSetting("framedelay", 0, "ms", "Additional frame delay", 0.0)); addOption(new realSetting("arcballradius", 0, "pixels", "Arcball radius", 750.0)); addOption(new realSetting("resizestep", 0, "step", "Resize step", 1.2)); addOption(new IntSetting("doubleclick", 0, "ms", "Emulated double-click timeout", 200)); addOption(new realSetting("paperwidth", 0, "bp", "")); addOption(new realSetting("paperheight", 0, "bp", "")); addOption(new stringSetting("dvipsOptions", 0, "string", "")); addOption(new stringSetting("dvisvgmOptions", 0, "string", "")); addOption(new stringSetting("convertOptions", 0, "string", "")); addOption(new stringSetting("gsOptions", 0, "string", "")); addOption(new stringSetting("psviewerOptions", 0, "string", "")); addOption(new stringSetting("pdfviewerOptions", 0, "string", "")); addOption(new stringSetting("pdfreloadOptions", 0, "string", "")); addOption(new stringSetting("glOptions", 0, "string", "")); addOption(new stringSetting("hyperrefOptions", 0, "str", "","setpagesize=false,unicode,pdfborder=0 0 0")); addOption(new envSetting("config","config."+suffix)); addOption(new envSetting("pdfviewer", defaultPDFViewer)); addOption(new envSetting("psviewer", defaultPSViewer)); addOption(new envSetting("gs", defaultGhostscript)); addOption(new envSetting("libgs", defaultGhostscriptLibrary)); addOption(new envSetting("texpath", "")); addOption(new envSetting("texcommand", "")); addOption(new envSetting("dvips", "dvips")); addOption(new envSetting("dvisvgm", "dvisvgm")); addOption(new envSetting("convert", "convert")); addOption(new envSetting("display", defaultDisplay)); addOption(new envSetting("animate", defaultAnimate)); addOption(new envSetting("papertype", "letter")); addOption(new envSetting("dir", "")); addOption(new envSetting("sysdir", systemDir)); addOption(new envSetting("textcommand","groff")); addOption(new envSetting("textcommandOptions","-e -P -b16")); addOption(new envSetting("textextension", "roff")); addOption(new envSetting("textoutformat", "ps")); addOption(new envSetting("textprologue", ".EQ\ndelim $$\n.EN")); addOption(new envSetting("textinitialfont", ".fam T\n.ps 12")); addOption(new envSetting("textepilogue", ".bp")); } // Access the arguments once options have been parsed. int numArgs() { return argCount; } char *getArg(int n) { return argList[n]; } void setInteractive() { if(numArgs() == 0 && !getSetting("listvariables") && getSetting("command").empty() && (isatty(STDIN_FILENO) || getSetting("inpipe") >= 0)) interact::interactive=true; if(getSetting("localhistory")) historyname=string(getPath())+dirsep+"."+suffix+"_history"; else { if(mkdir(initdir.c_str(),0777) != 0 && errno != EEXIST) cerr << "failed to create directory "+initdir+"." << endl; historyname=initdir+"/history"; } if(verbose > 1) cerr << "Using history " << historyname << endl; } bool view() { if (interact::interactive) return getSetting("interactiveView"); else return getSetting("batchView") && (numArgs() == 1 || getSetting("multipleView")); } bool trap() { if (interact::interactive) return !getSetting("interactiveMask"); else return !getSetting("batchMask"); } string outname() { string name=getSetting("outname"); if(name.empty() && interact::interactive) return standardprefix; if(msdos) backslashToSlash(name); return name; } string lookup(const string& symbol) { string s; mem::vector cmd; cmd.push_back("kpsewhich"); cmd.push_back("--var-value="+symbol); iopipestream pipe(cmd); pipe >> s; size_t n=s.find('\r'); if(n != string::npos) s.erase(n,1); n=s.find('\n'); if(n != string::npos) s.erase(n,1); return s; } void initDir() { if(getSetting("sysdir").empty()) { string s=lookup("TEXMFMAIN"); if(s.size() > 1) { string texmf=s+dirsep; docdir=texmf+"doc"+dirsep+"asymptote"; Setting("sysdir")=texmf+"asymptote"; s=lookup("ASYMPTOTE_HOME"); if(s.size() > 1) initdir=s; } } if(initdir.empty()) initdir=Getenv("ASYMPTOTE_HOME",msdos); if(initdir.empty()) initdir=Getenv(HOME.c_str(),msdos)+dirsep+"."+suffix; #ifdef __MSDOS__ mask=umask(0); if(mask == 0) mask=0027; umask(mask); #endif if(access(initdir.c_str(),F_OK) == 0) { if(verbose > 1) cerr << "Using configuration directory " << initdir << endl; } } void setPath() { searchPath.clear(); searchPath.push_back("."); string asydir=getSetting("dir"); if(asydir != "") { size_t p,i=0; while((p=asydir.find(pathSeparator,i)) < string::npos) { if(p > i) searchPath.push_back(asydir.substr(i,p-i)); i=p+1; } if(i < asydir.length()) searchPath.push_back(asydir.substr(i)); } if(access(initdir.c_str(),F_OK) == 0) searchPath.push_back(initdir); string sysdir=getSetting("sysdir"); if(sysdir != "") searchPath.push_back(sysdir); } void SetPageDimensions() { string paperType=getSetting("papertype"); if(paperType.empty() && getSetting("paperwidth") != 0.0 && getSetting("paperheight") != 0.0) return; if(paperType == "letter") { Setting("paperwidth")=8.5*inches; Setting("paperheight")=11.0*inches; } else { Setting("paperwidth")=21.0*cm; Setting("paperheight")=29.7*cm; if(paperType != "a4") { cerr << "Unknown paper size \'" << paperType << "\'; assuming a4." << endl; Setting("papertype")=string("a4"); } } } bool xe(const string& texengine) { return texengine == "xelatex"; } bool context(const string& texengine) { return texengine == "context"; } bool pdf(const string& texengine) { return texengine == "pdflatex" || texengine == "pdftex" || xe(texengine) || texengine == "luatex" || texengine == "lualatex" || context(texengine); } bool latex(const string& texengine) { return texengine == "latex" || texengine == "pdflatex" || texengine == "xelatex" || texengine == "lualatex"; } string nativeformat() { return pdf(getSetting("tex")) ? "pdf" : "eps"; } string defaultformat() { string format=getSetting("outformat"); return (format.empty()) ? nativeformat() : format; } // TeX special command to set up currentmatrix for typesetting labels. const char *beginlabel(const string& texengine) { if(pdf(texengine)) return xe(texengine) ? "\\special{pdf:literal q #5 0 0 cm}" : "\\special{pdf:q #5 0 0 cm}"; else return "\\special{ps:gsave currentpoint currentpoint translate [#5 0 0] " "concat neg exch neg exch translate}"; } // TeX special command to restore currentmatrix after typesetting labels. const char *endlabel(const string& texengine) { if(pdf(texengine)) return xe(texengine) ? "\\special{pdf:literal Q}" : "\\special{pdf:Q}"; else return "\\special{ps:currentpoint grestore moveto}"; } // TeX macro to typeset raw postscript code const char *rawpostscript(const string& texengine) { if(pdf(texengine)) return "\\def\\ASYraw#1{#1}"; else return "\\def\\ASYraw#1{\n" "currentpoint currentpoint translate matrix currentmatrix\n" "100 12 div -100 12 div scale\n" "#1\n" "setmatrix neg exch neg exch translate}"; } // TeX macro to begin picture const char *beginpicture(const string& texengine) { if(latex(texengine)) return "\\begin{picture}"; if(context(texengine)) return ""; else return "\\picture"; } // TeX macro to end picture const char *endpicture(const string& texengine) { if(latex(texengine)) return "\\end{picture}%"; else if(context(texengine)) return "%"; else return "\\endpicture%"; } // Begin TeX special command. const char *beginspecial(const string& texengine) { if(pdf(texengine)) return xe(texengine) ? "\\special{pdf:literal " : "\\special{pdf:"; else return "\\special{ps:"; } // End TeX special command. const char *endspecial() { return "}%"; } string texcommand() { string command=getSetting("texcommand"); return command.empty() ? getSetting("tex") : command; } string texprogram() { string path=getSetting("texpath"); string engine=texcommand(); return path.empty() ? engine : (string) (path+"/"+engine); } Int getScroll() { Int scroll=settings::getSetting("scroll"); #ifdef HAVE_LIBCURSES if(scroll < 0) { static char *terminal=NULL; if(!terminal) terminal=getenv("TERM"); if(terminal) { #ifndef __MSDOS__ int error=setupterm(terminal,1,&error); if(error == 0) scroll=lines > 2 ? lines-1 : 1; else #endif scroll=0; } else scroll=0; } #endif return scroll; } void doConfig(string file) { bool autoplain=getSetting("autoplain"); bool listvariables=getSetting("listvariables"); if(autoplain) Setting("autoplain")=false; // Turn off for speed. if(listvariables) Setting("listvariables")=false; runFile(file); if(autoplain) Setting("autoplain")=true; if(listvariables) Setting("listvariables")=true; } void setOptions(int argc, char *argv[]) { argv0=argv[0]; cout.precision(DBL_DIG); // Build settings module. initSettings(); // Read command-line options initially to obtain config, dir, sysdir, verbose. getOptions(argc,argv); // Make configuration and history directory initDir(); Int Verbose=verbose; string sysdir=getSetting("sysdir"); resetOptions(); // Read user configuration file. setPath(); string filename=getSetting("config"); if(!filename.empty()) { string file=locateFile(filename); if(!file.empty()) { if(Verbose > 1) cerr << "Loading " << filename << " from " << file << endl; doConfig(file); } } // Read command-line options again to override configuration file defaults. getOptions(argc,argv); if(getSetting("outpipe") == 2) // Redirect cerr to cout std::cerr.rdbuf(std::cout.rdbuf()); Setting("sysdir")=sysdir; if(docdir.empty()) docdir=getSetting("dir"); #ifdef USEGC if(verbose == 0 && !getSetting("debug")) GC_set_warn_proc(no_GCwarn); #endif if(setlocale (LC_ALL, "") == NULL && getSetting("debug")) perror("setlocale"); // Set variables for the file arguments. argCount = argc - optind; argList = argv + optind; // Recompute search path. setPath(); if(getSetting("paperwidth") != 0.0 && getSetting("paperheight") != 0.0) Setting("papertype")=string(""); SetPageDimensions(); setInteractive(); } } asymptote-2.37/settings.h000066400000000000000000000045311265434602500155150ustar00rootroot00000000000000/***** * settings.h * Andy Hammerlindl 2004/05/10 * * Declares a list of global variables that act as settings in the system. *****/ #ifndef SETTINGS_H #define SETTINGS_H #include #include #include "common.h" #include "pair.h" #include "item.h" namespace types { class record; } namespace camp { void glrenderWrapper(); } namespace gl { extern bool glthread; extern bool initialize; #ifdef HAVE_PTHREAD extern pthread_t mainthread; extern pthread_cond_t initSignal; extern pthread_mutex_t initLock; extern pthread_cond_t readySignal; extern pthread_mutex_t readyLock; void wait(pthread_cond_t& signal, pthread_mutex_t& lock); void endwait(pthread_cond_t& signal, pthread_mutex_t& lock); #endif } namespace settings { extern const char PROGRAM[]; extern const char VERSION[]; extern const char BUGREPORT[]; extern char *argv0; void Warn(const string& s); void noWarn(const string& s); bool warn(const string& s); extern string systemDir; extern string docdir; extern const string dirsep; extern bool safe; bool globalwrite(); extern const string suffix; extern const string guisuffix; extern const string standardprefix; extern string historyname; void SetPageDimensions(); types::record *getSettingsModule(); vm::item& Setting(string name); template inline T getSetting(string name) { return vm::get(Setting(name)); } extern Int verbose; extern bool compact; extern bool gray; extern bool bw; extern bool rgb; extern bool cmyk; bool view(); bool trap(); string outname(); void setOptions(int argc, char *argv[]); // Access the arguments once options have been parsed. int numArgs(); char *getArg(int n); Int getScroll(); extern mode_t mask; bool xe(const string& texengine); bool pdf(const string& texengine); bool latex(const string& texengine); bool context(const string& texengine); string nativeformat(); string defaultformat(); const char *beginlabel(const string& texengine); const char *endlabel(const string& texengine); const char *rawpostscript(const string& texengine); const char *beginpicture(const string& texengine); const char *endpicture(const string& texengine); const char *beginspecial(const string& texengine); const char *endspecial(); string texcommand(); string texprogram(); const double inches=72; const double cm=inches/2.54; } extern const char *REVISION; #endif asymptote-2.37/simpson.cc000066400000000000000000000150041265434602500155000ustar00rootroot00000000000000#include #include #include // Compute a numerical approximation to an integral via adaptive Simpson's Rule // This routine ignores underflow. const int nest=DBL_MANT_DIG; typedef struct { bool left; // left interval? double psum, f1t, f2t, f3t, dat, estr; } TABLE; bool // Returns true iff successful. simpson(double& integral, // Approximate value of the integral. double (*f)(double), // Pointer to function to be integrated. double a, double b, // Lower, upper limits of integration. double acc, // Desired relative accuracy of integral. // Try to make |error| <= acc*abs(integral). double dxmax) // Maximum limit on the width of a subinterval // For periodic functions, dxmax should be // set to the period or smaller to prevent // premature convergence of Simpson's rule. { double diff,area,estl,estr,alpha,da,dx,wt,est,fv[5]; TABLE table[nest],*p,*pstop; static const double sixth=1.0/6.0; bool success=true; p=table; pstop=table+nest-1; p->left=true; p->psum=0.0; alpha=a; da=b-a; fv[0]=(*f)(alpha); fv[2]=(*f)(alpha+0.5*da); fv[4]=(*f)(alpha+da); wt=sixth*da; est=wt*(fv[0]+4.0*fv[2]+fv[4]); area=est; // Have estimate est of integral on (alpha, alpha+da). // Bisect and compute estimates on left and right half intervals. // integral is the best value for the integral. for(;;) { dx=0.5*da; double arg=alpha+0.5*dx; fv[1]=(*f)(arg); fv[3]=(*f)(arg+dx); wt=sixth*dx; estl=wt*(fv[0]+4.0*fv[1]+fv[2]); estr=wt*(fv[2]+4.0*fv[3]+fv[4]); integral=estl+estr; diff=est-integral; area -= diff; if(p >= pstop) success=false; if(!success || (fabs(diff) <= acc*fabs(area) && da <= dxmax)) { // Accept approximate integral. // If it was a right interval, add results to finish at this level. // If it was a left interval, process right interval. for(;;) { if(p->left == false) { // process right-half interval alpha += da; p->left=true; p->psum=integral; fv[0]=p->f1t; fv[2]=p->f2t; fv[4]=p->f3t; da=p->dat; est=p->estr; break; } integral += p->psum; if(--p <= table) return success; } } else { // Raise level and store information for processing right-half interval. ++p; da=dx; est=estl; p->left=false; p->f1t=fv[2]; p->f2t=fv[3]; p->f3t=fv[4]; p->dat=dx; p->estr=estr; fv[4]=fv[2]; fv[2]=fv[1]; } } } // Use adaptive Simpson integration to determine the upper limit of // integration required to make the definite integral of a continuous // non-negative function close to a user specified sum. // This routine ignores underflow. bool // Returns true iff successful. unsimpson(double integral, // Given value for the integral. double (*f)(double), // Pointer to function to be integrated. double a, double& b, // Lower, upper limits of integration (a <= b). // The value of b provided on entry is used // as an initial guess; somewhat faster if the // given value is an underestimation. double acc, // Desired relative accuracy of b. // Try to make |integral-area| <= acc*integral. double& area, // Computed integral of f(x) on [a,b]. double dxmax, // Maximum limit on the width of a subinterval // For periodic functions, dxmax should be // set to the period or smaller to prevent // premature convergence of Simpson's rule. double dxmin=0) // Lower limit on sampling width. { double diff,estl,estr,alpha,da,dx,wt,est,fv[5]; double sum,parea,pdiff,b2; TABLE table[nest],*p,*pstop; static const double sixth=1.0/6.0; p=table; pstop=table+nest-1; p->psum=0.0; alpha=a; parea=0.0; pdiff=0.0; for(;;) { p->left=true; da=b-alpha; fv[0]=(*f)(alpha); fv[2]=(*f)(alpha+0.5*da); fv[4]=(*f)(alpha+da); wt=sixth*da; est=wt*(fv[0]+4.0*fv[2]+fv[4]); area=est; // Have estimate est of integral on (alpha, alpha+da). // Bisect and compute estimates on left and right half intervals. // Sum is better value for integral. bool cont=true; while(cont) { dx=0.5*da; double arg=alpha+0.5*dx; fv[1]=(*f)(arg); fv[3]=(*f)(arg+dx); wt=sixth*dx; estl=wt*(fv[0]+4.0*fv[1]+fv[2]); estr=wt*(fv[2]+4.0*fv[3]+fv[4]); sum=estl+estr; diff=est-sum; assert(sum >= 0.0); area=parea+sum; b2=alpha+da; if(fabs(fabs(integral-area)-fabs(pdiff))+fabs(diff) <= fv[4]*acc*(b2-a)){ b=b2; return true; } if(fabs(integral-area) > fabs(pdiff+diff)) { if(integral <= area) { p=table; p->left=true; p->psum=parea; } else { if((fabs(diff) <= fv[4]*acc*da || dx <= dxmin) && da <= dxmax) { // Accept approximate integral sum. // If it was a right interval, add results to finish at this level. // If it was a left interval, process right interval. pdiff += diff; for(;;) { if(p->left == false) { // process right-half interval parea += sum; alpha += da; p->left=true; p->psum=sum; fv[0]=p->f1t; fv[2]=p->f2t; fv[4]=p->f3t; da=p->dat; est=p->estr; break; } sum += p->psum; parea -= p->psum; if(--p <= table) { p=table; p->psum=parea=sum; alpha += da; b += b-a; cont=false; break; } } continue; } } } if(p >= pstop) return false; // Raise level and store information for processing right-half interval. ++p; da=dx; est=estl; p->psum=0.0; p->left=false; p->f1t=fv[2]; p->f2t=fv[3]; p->f3t=fv[4]; p->dat=dx; p->estr=estr; fv[4]=fv[2]; fv[2]=fv[1]; } } } asymptote-2.37/stack.cc000066400000000000000000000336701265434602500151260ustar00rootroot00000000000000/***** * stack.cc * Andy Hammerlindl 2002/06/27 * * The general stack machine used to run compiled camp code. *****/ #include #include #include "stack.h" #include "program.h" #include "callable.h" #include "errormsg.h" #include "util.h" #include "runtime.h" #include "profiler.h" #ifdef DEBUG_STACK #include namespace vm { void draw(ostream& out, frame *v); } #endif namespace run { void breakpoint(vm::stack *Stack, absyntax::runnable *r); } namespace vm { mem::list bplist; namespace { position curPos = nullPos; const program::label nulllabel; } inline stack::vars_t base_frame( size_t size, size_t parentIndex, stack::vars_t closure #ifdef DEBUG_FRAME , string name #endif ) { stack::vars_t vars; #ifdef SIMPLE_FRAME vars = new item[size]; vars[parentIndex] = closure; #else # ifdef DEBUG_FRAME assert(!name.empty()); vars = new frame(name, parentIndex, size); # else vars = new frame(size); # endif (*vars)[parentIndex] = closure; #endif // TODO: Re-factor closure. return vars; } #ifdef DEBUG_FRAME #define BASEFRAME(s,p,c,n) (base_frame((s), (p), (c), (n))) #else #define BASEFRAME(s,p,c,n) (base_frame((s), (p), (c))) #endif // Abstractions needed. //accessor(frame_handle) // operator[] for accessor inline stack::vars_t make_frame(lambda *l, stack::vars_t closure) { return BASEFRAME(l->framesize, l->parentIndex, closure, l->name); } inline stack::vars_t make_pushframe(size_t size, stack::vars_t closure) { assert(size >= 1); return BASEFRAME(size, 0, closure, ""); } stack::vars_t make_dummyframe(string name) { return BASEFRAME(1, 0, 0, ""); } inline stack::vars_t make_globalframe(size_t size) { assert(size > 0); #if SIMPLE_FRAME // The global frame is an indirect frame. It holds one item, which is the // link to another frame. stack::vars_t direct = new item[1]; stack::vars_t indirect = new item[size]; direct[0] = indirect; return direct; #else return BASEFRAME(size, 0, 0, ""); #if 0 #ifdef DEBUG_FRAME stack::vars_t vars = new frame("", 0, size); #else stack::vars_t vars = new frame(size); #endif return vars; #endif #endif } inline void resize_frame(frame *f, size_t oldsize, size_t newsize) { //assert("Need to fix this" == 0); assert(newsize > oldsize); #if SIMPLE_FRAME frame *old_indirect = get(f[0]); frame *new_indirect = new item[newsize]; std::copy(old_indirect, old_indirect+oldsize, new_indirect); f[0] = new_indirect; #else f->extend(newsize); #endif } void run(lambda *l) { func f; f.body = l; stack s; s.run(&f); } // Move arguments from stack to frame. void stack::marshall(size_t args, stack::vars_t vars) { for (size_t i = args; i > 0; --i) #if SIMPLE_FRAME vars[i-1] = pop(); #else (*vars)[i-1] = pop(); #endif } #ifdef PROFILE #ifndef DEBUG_FRAME #warning "profiler needs DEBUG_FRAME for function names" #endif #ifndef DEBUG_BLTIN #warning "profiler needs DEBUG_BLTIN for builtin function names" #endif profiler prof; void dumpProfile() { std::ofstream out("asyprof"); if (!out.fail()) prof.dump(out); } #endif void assessClosure(lambda *body) { // If we have already determined if it needs closure, just return. if (body->closureReq != lambda::MAYBE_NEEDS_CLOSURE) return; for (program::label l = body->code->begin(); l != body->code->end(); ++l) if (l->op == inst::pushclosure || l->op == inst::pushframe) { body->closureReq = lambda::NEEDS_CLOSURE; return; } body->closureReq = lambda::DOESNT_NEED_CLOSURE; } void stack::run(func *f) { lambda *body = f->body; #ifdef PROFILE prof.beginFunction(body); #endif #ifdef DEBUG_STACK #ifdef DEBUG_FRAME cout << "running lambda " + body->name + ": \n"; #else cout << "running lambda: \n"; #endif print(cout, body->code); cout << endl; #endif runWithOrWithoutClosure(body, 0, f->closure); #ifdef PROFILE prof.endFunction(body); #endif } void stack::breakpoint(absyntax::runnable *r) { lastPos=curPos; indebugger=true; ::run::breakpoint(this,r); string s=vm::pop(this); debugOp=(s.length() > 0) ? s[0] : (char) 0; indebugger=false; } void stack::debug() { if(!curPos) return; if(indebugger) {em.clear(); return;} switch(debugOp) { case 'i': // inst breakpoint(); break; case 's': // step if((!curPos.match(lastPos.filename()) || !curPos.match(lastPos.Line()))) breakpoint(); break; case 'n': // next if(curPos.match(lastPos.filename()) && !curPos.match(lastPos.Line())) breakpoint(); break; case 'f': // file if(!curPos.match(lastPos.filename())) breakpoint(); break; case 'r': // return if(curPos.match(breakPos.filename())) breakpoint(); break; case 'c': // continue default: for(mem::list::iterator p=bplist.begin(); p != bplist.end(); ++p) { if(curPos.match(p->f.name()) && curPos.match(p->f.line()) && (newline || !curPos.match(breakPos.filename()) || !curPos.match(breakPos.Line()))) { breakPos=curPos; breakpoint(p->r); newline=false; break; } if(!newline && (curPos.match(lastPos.filename()) && !curPos.match(lastPos.Line()))) newline=true; } break; } } void stack::runWithOrWithoutClosure(lambda *l, vars_t vars, vars_t parent) { // The size of the frame (when running without closure). size_t frameSize = l->parentIndex; #ifdef SIMPLE_FRAME // Link to the variables, be they in a closure or on the stack. frame *varlink; # define SET_VARLINK assert(vars); varlink = vars; # define VAR(n) ( (varlink)[(n) + frameStart] ) # define FRAMEVAR(frame,n) (frame[(n)]) #else // Link to the variables, be they in a closure or on the stack. mem::vector *varlink=NULL; # define SET_VARLINK assert(vars); varlink = &vars->vars # define VAR(n) ( (*varlink)[(n) + frameStart] ) # define FRAMEVAR(frame,n) ((*frame)[(n)]) #endif size_t frameStart = 0; // Set up the closure, if necessary. if (vars == 0) { #ifndef SIMPLE_FRAME assessClosure(l); if (l->closureReq == lambda::NEEDS_CLOSURE) #endif { /* make new activation record */ vars = vm::make_frame(l, parent); assert(vars); } #ifndef SIMPLE_FRAME else { assert(l->closureReq == lambda::DOESNT_NEED_CLOSURE); // Use the stack to store variables. varlink = &theStack; // Record where the parameters start on the stack. frameStart = theStack.size() - frameSize; // Add the parent's closure to the frame. push(parent); ++frameSize; size_t newFrameSize = (size_t)l->framesize; if (newFrameSize > frameSize) { theStack.resize(frameStart + newFrameSize); frameSize = newFrameSize; } } #endif } if (vars) { marshall(l->parentIndex, vars); SET_VARLINK; } /* start the new function */ program::label ip = l->code->begin(); try { for (;;) { const inst &i = *ip; curPos = i.pos; #ifdef PROFILE prof.recordInstruction(); #endif #ifdef DEBUG_STACK printInst(cout, ip, l->code->begin()); cout << " ("; i.pos.printTerse(cout); cout << ")\n"; #endif if(settings::verbose > 4) em.trace(curPos); if(!bplist.empty()) debug(); if(errorstream::interrupt) throw interrupted(); switch (i.op) { case inst::varpush: push(VAR(get(i))); break; case inst::varsave: VAR(get(i)) = top(); break; #ifdef COMBO case inst::varpop: VAR(get(i)) = pop(); break; #endif case inst::ret: { if (vars == 0) // Delete the frame from the stack. // TODO: Optimize for common cases. theStack.erase(theStack.begin() + frameStart, theStack.begin() + frameStart + frameSize); return; } case inst::pushframe: { assert(vars); Int size = get(i); vars=make_pushframe(size, vars); SET_VARLINK; break; } case inst::popframe: { assert(vars); vars=get(VAR(0)); SET_VARLINK; break; } case inst::pushclosure: assert(vars); push(vars); break; case inst::nop: break; case inst::pop: pop(); break; case inst::intpush: case inst::constpush: push(i.ref); break; case inst::fieldpush: { vars_t frame = pop(); if (!frame) error("dereference of null pointer"); push(FRAMEVAR(frame, get(i))); break; } case inst::fieldsave: { vars_t frame = pop(); if (!frame) error("dereference of null pointer"); FRAMEVAR(frame, get(i)) = top(); break; } #if COMBO case inst::fieldpop: { #error NOT REIMPLEMENTED vars_t frame = pop(); if (!frame) error("dereference of null pointer"); FRAMEVAR(get(i)) = pop(); break; } #endif case inst::builtin: { bltin func = get(i); #ifdef PROFILE prof.beginFunction(func); #endif func(this); #ifdef PROFILE prof.endFunction(func); #endif break; } case inst::jmp: ip = get(i); continue; case inst::cjmp: if (pop()) { ip = get(i); continue; } break; case inst::njmp: if (!pop()) { ip = get(i); continue; } break; case inst::jump_if_not_default: if (!isdefault(pop())) { ip = get(i); continue; } break; #ifdef COMBO case inst::gejmp: { Int y = pop(); Int x = pop(); if (x>=y) { ip = get(i); continue; } break; } #if 0 case inst::jump_if_func_eq: { callable * b=pop(); callable * a=pop(); if (a->compare(b)) { ip = get(i); continue; } break; } case inst::jump_if_func_neq: { callable * b=pop(); callable * a=pop(); if (!a->compare(b)) { ip = get(i); continue; } break; } #endif #endif case inst::push_default: push(Default); break; case inst::popcall: { /* get the function reference off of the stack */ callable* f = pop(); f->call(this); break; } case inst::makefunc: { func *f = new func; f->closure = pop(); f->body = get(i); push((callable*)f); break; } default: error("Internal VM error: Bad stack operand"); } #ifdef DEBUG_STACK draw(cerr); vm::draw(cerr,vars); cerr << "\n"; #endif ++ip; } } catch (bad_item_value&) { error("Trying to use uninitialized value."); } #undef SET_VARLINK #undef VAR #undef FRAMEVAR } void stack::load(string index) { frame *inst=instMap[index]; if (inst) push(inst); else { func f; assert(initMap); f.body=(*initMap)[index]; assert(f.body); run(&f); instMap[index]=get(top()); } } #ifdef DEBUG_STACK const size_t MAX_ITEMS=20; void stack::draw(ostream& out) { // out.setf(out.hex); out << "operands:"; stack_t::const_iterator left = theStack.begin(); if (theStack.size() > MAX_ITEMS) { left = theStack.end()-MAX_ITEMS; out << " ..."; } else out << " "; while (left != theStack.end()) { if (left != theStack.begin()) out << " | " ; out << *left; left++; } out << "\n"; } void draw(ostream& out, frame* v) { out << "vars:" << endl; while (!!v) { item link=(*v)[v->getParentIndex()]; out << " " << v->getName() << ": "; for (size_t i = 0; i < MAX_ITEMS && i < v->size(); i++) { if (i > 0) out << " | "; out << i << ": "; if (i == v->getParentIndex()) { try { frame *parent = get(link); out << (parent ? "link" : "----"); } catch (bad_item_value&) { out << "non-link " << (*v)[0]; } } else { out << (*v)[i]; } } if (v->size() > MAX_ITEMS) out << "..."; out << "\n"; frame *parent; try { parent = get(link); } catch (bad_item_value&) { parent = 0; } v = parent; } } #endif // DEBUG_STACK position getPos() { return curPos; } void errornothrow(const char* message) { em.error(curPos); em << message; em.sync(); } void error(const char* message) { errornothrow(message); throw handled_error(); } void error(const ostringstream& message) { error(message.str().c_str()); } const size_t STARTING_GLOBALS_SIZE = 1; interactiveStack::interactiveStack() : globals(make_globalframe(STARTING_GLOBALS_SIZE)), globals_size(STARTING_GLOBALS_SIZE) {} void interactiveStack::run(lambda *codelet) { if (globals_size < codelet->framesize) { resize_frame(globals, globals_size, codelet->framesize); globals_size = codelet->framesize; } stack::runWithOrWithoutClosure(codelet, globals, 0); } } // namespace vm asymptote-2.37/stack.h000066400000000000000000000064001265434602500147570ustar00rootroot00000000000000/***** * stack.h * Andy Hammerlindl 2002/06/27 * * The general stack machine used to run compiled camp code. *****/ #ifndef STACK_H #define STACK_H #include #include "errormsg.h" #include "vm.h" #include "item.h" #include "absyn.h" namespace vm { struct func; class program; struct lambda; class importInitMap; struct bpinfo : public gc { fileinfo f; absyntax::runnable *r; bpinfo(const string& filename, size_t lineNum, absyntax::runnable *r=NULL) : f(fileinfo(filename,lineNum)), r(r) {} }; inline bool operator == (const bpinfo& a, const bpinfo& b) { return a.f == b.f; } extern mem::list bplist; class runnable; extern bool indebugger; class stack { public: typedef frame* vars_t; struct importInitMap { virtual ~importInitMap() {} virtual lambda *operator[](string) = 0; }; private: // stack for operands typedef mem::vector stack_t; stack_t theStack; void draw(ostream& out); // The initializer functions for imports, indexed by name. importInitMap *initMap; // The stack stores a map of initialized imported modules by name, so that // each module is initialized only once and each import refers to the same // instance. typedef mem::map importInstanceMap; importInstanceMap instMap; // One can associate an environment to embedded code while running. trans::coenv *e; // Debugger variables: char debugOp; position lastPos, breakPos; bool newline; // Move arguments from stack to frame. void marshall(size_t args, stack::vars_t vars); public: stack() : e(0), debugOp(0), lastPos(nullPos), breakPos(nullPos), newline(false) {}; virtual ~stack() {}; void setInitMap(importInitMap *i) { initMap=i; } void setEnvironment(trans::coenv *e) { this->e=e; } trans::coenv *getEnvironment() { return e; } // Runs a lambda. If vars is non-null, it is used to store the variables of // the lambda. Otherwise, the method allocates a closure only if needed. void runWithOrWithoutClosure(lambda *l, vars_t vars, vars_t parent); // Executes a function on top of the stack. void run(func *f); void breakpoint(absyntax::runnable *r=NULL); void debug(); // Put an import (indexed by name) on top of the stack, initializing it if // necessary. void load(string index); // These are so that built-in functions can easily manipulate the stack void push(item next) { theStack.push_back(next); } template void push(T next) { push((item)next); } item top() { return theStack.back(); } item pop() { item ret = theStack.back(); theStack.pop_back(); return ret; } template T pop() { return get(pop()); } }; inline item pop(stack* s) { return s->pop(); } template inline T pop(stack* s) { return get(pop(s)); } template inline T pop(stack* s, T defval) { item it=pop(s); return isdefault(it) ? defval : get(it); } class interactiveStack : public stack { vars_t globals; size_t globals_size; public: interactiveStack(); // Run a codelet, a small piece of code that uses globals as its frame. void run(lambda *codelet); }; } // namespace vm #endif // STACK_H asymptote-2.37/statistics.h000066400000000000000000000016531265434602500160510ustar00rootroot00000000000000#ifndef __statistics_h__ #define __statistics_h__ 1 namespace utils { class statistics { unsigned int N; double A; double varL; double varH; public: statistics() : N(0), A(0.0), varL(0.0), varH(0.0) {} double count() {return N;} double mean() {return A;} void add(double t) { ++N; double diff=t-A; A += diff/N; double v=diff*(t-A); if(diff < 0.0) varL += v; else varH += v; } double stdev(double var, double f) { double factor=N > f ? f/(N-f) : 0.0; return sqrt(var*factor); } double stdev() { return stdev(varL+varH,1.0); } double stdevL() { return stdev(varL,2.0); } double stdevH() { return stdev(varH,2.0); } void output(const char *text, unsigned int m) { std::cout << text << ":\n" << m << "\t" << A << "\t" << stdevL() << "\t" << stdevH() << std::endl; } }; } #endif asymptote-2.37/stm.cc000066400000000000000000000275071265434602500146260ustar00rootroot00000000000000/***** * stm.cc * Andy Hammerlindl 2002/8/30 * * Statements are everything in the language that do something on their * own. Statements are different from declarations in that statements * do not modify the environment. Translation of a statement puts the * stack code to run it into the instruction stream. *****/ #include #include "errormsg.h" #include "settings.h" #include "coenv.h" #include "exp.h" #include "stm.h" #include "symbol.h" #include "opsymbols.h" namespace absyntax { using namespace trans; using namespace types; void stm::prettyprint(ostream &out, Int indent) { prettyname(out,"stm",indent); } void emptyStm::prettyprint(ostream &out, Int indent) { prettyname(out,"emptyStm",indent); } void blockStm::prettyprint(ostream &out, Int indent) { prettyname(out,"blockStm",indent); base->prettyprint(out, indent+1); } void expStm::prettyprint(ostream &out, Int indent) { prettyname(out,"expStm",indent); body->prettyprint(out, indent+1); } void baseExpTrans(coenv &e, exp *expr) { types::ty_kind kind = expr->trans(e)->kind; if (kind != types::ty_void) // Remove any value it puts on the stack. e.c.encodePop(); } void expStm::trans(coenv &e) { baseExpTrans(e, body); } // For an object such as currentpicture, write 'picture currentpicture' to // give some information. Only do this when the object has a name. void tryToWriteTypeOfExp(types::ty *t, exp *body) { symbol name=body->getName(); if (!name) return; overloaded *set = dynamic_cast(t); if (set) for(ty_vector::iterator ot=set->sub.begin(); ot!=set->sub.end(); ++ot) tryToWriteTypeOfExp(*ot, body); else { cout << "<"; t->printVar(cout, name); cout << ">" << endl; } } // From dec.cc: varEntry *makeVarEntry(position pos, coenv &e, record *r, types::ty *t); void storeExp(coenv &e, types::ty *t, exp *expr) { assert(t->kind != ty_error); assert(t->kind != ty_void); assert(t->kind != ty_overloaded); expr->transAsType(e, t); // Store the value in a new variable of the proper type. varEntry *v = makeVarEntry(expr->getPos(), e, 0, t); e.e.addVar(symbol::trans("operator answer"), v); v->getLocation()->encode(WRITE, expr->getPos(), e.c); e.c.encodePop(); } void storeAndWriteExp(coenv &e, types::ty *t, exp *expr) { storeExp(e, t, expr); position pos=expr->getPos(); baseExpTrans(e, new callExp(pos, new nameExp(pos, "write"), new nameExp(pos, "operator answer"))); } void tryToWriteExp(coenv &e, exp *expr) { position pos=expr->getPos(); types::ty *t=expr->cgetType(e); if(!t) return; // If the original expression is bad, just print the errors. // If it is a function which returns void, just call the function. if (t->kind == ty_error || t->kind == ty_void) { baseExpTrans(e, expr); return; } exp *callee=new nameExp(pos, symbol::trans("write")); exp *call=new callExp(pos, callee, expr); types::ty *ct=call->getType(e); if (ct->kind == ty_error || ct->kind == ty_overloaded) { if (t->kind == ty_overloaded) { // Translate the expr in order to print the ambiguity error first. expr->trans(e); em.sync(); assert(em.errors()); // Then, write out all of the types. tryToWriteTypeOfExp(t, expr); } else { // Write the type of the expression and, since it is unique, assign it to // 'operator answer' even though its value isn't printed. tryToWriteTypeOfExp(t, expr); storeExp(e, t, expr); } } else if (t->kind == ty_overloaded) { // If the exp is overloaded, but the act of writing makes it // unambiguous, add a suffix to the output to warn the user of this. exp *suffix=new nameExp(pos, symbol::trans("overloadedMessage")); exp *callWithSuffix=new callExp(pos, callee, expr, suffix); if (callWithSuffix->getType(e)->kind != ty_error) baseExpTrans(e, callWithSuffix); else baseExpTrans(e, call); } else { // Interactive writing can proceed normally. storeAndWriteExp(e, t, expr); } } void expStm::interactiveTrans(coenv &e) { // First check if it is the kind of expression that should be written. if (body->writtenToPrompt() && settings::getSetting("interactiveWrite")) tryToWriteExp(e, body); else baseExpTrans(e, body); } void ifStm::prettyprint(ostream &out, Int indent) { prettyname(out,"ifStm",indent); test->prettyprint(out, indent+1); onTrue->prettyprint(out, indent+1); if (onFalse) onFalse->prettyprint(out, indent+1); } void ifStm::trans(coenv &e) { label elseLabel = e.c.fwdLabel(); label end = e.c.fwdLabel(); test->transConditionalJump(e, false, elseLabel); onTrue->markTrans(e); if (onFalse) { // Encode the jump around the 'else' clause at the end of the 'if' clause e.c.useLabel(inst::jmp,end); e.c.defLabel(elseLabel); onFalse->markTrans(e); } else { e.c.defLabel(elseLabel); } e.c.defLabel(end); } void transLoopBody(coenv &e, stm *body) { // The semantics of the language are defined so that any variable declared // inside a loop are new variables for each iteration of the loop. For // instance, the code // // int f(); // for (int i = 0; i < 10; ++i) { // int j=10*i; // if (i == 5) // f = new int() { return j; }; // } // write(f()); // // will write 50. This is implemented by allocating a new frame for each // iteration. However, this can have a big performance hit, so we first // translate the code without the frame, check if it needed the closure, and // rewrite the code if necessary. label start = e.c.defNewLabel(); // Encode a no-op, in case we need to jump over the default implementation // to a special case. e.c.encode(inst::nop); body->markTrans(e); // Don't re-translate if there were errors. if (em.errors()) return; if (e.c.usesClosureSinceLabel(start)){ // Jump over the old section. label end = e.c.defNewLabel(); e.c.encodePatch(start, end); // Let coder know that break and continue need to pop the frame. e.c.loopPushesFrame(); e.c.encodePushFrame(); body->markTrans(e); e.c.encodePopFrame(); } } void whileStm::prettyprint(ostream &out, Int indent) { prettyname(out,"whileStm",indent); test->prettyprint(out, indent+1); body->prettyprint(out, indent+1); } void whileStm::trans(coenv &e) { label end = e.c.fwdLabel(); label start = e.c.defNewLabel(); e.c.pushLoop(start, end); test->transConditionalJump(e, false, end); transLoopBody(e,body); e.c.useLabel(inst::jmp,start); e.c.defLabel(end); e.c.popLoop(); } void doStm::prettyprint(ostream &out, Int indent) { prettyname(out,"doStm",indent); body->prettyprint(out, indent+1); test->prettyprint(out, indent+1); } void doStm::trans(coenv &e) { label testLabel = e.c.fwdLabel(); label end = e.c.fwdLabel(); e.c.pushLoop(testLabel, end); label start = e.c.defNewLabel(); transLoopBody(e,body); e.c.defLabel(testLabel); test->transConditionalJump(e, true, start); e.c.defLabel(end); e.c.popLoop(); } void forStm::prettyprint(ostream &out, Int indent) { prettyname(out,"forStm",indent); if (init) init->prettyprint(out, indent+1); if (test) test->prettyprint(out, indent+1); if (update) update->prettyprint(out, indent+1); body->prettyprint(out, indent+1); } void forStm::trans(coenv &e) { // Any vardec in the initializer needs its own scope. e.e.beginScope(); if (init) init->markTrans(e); label ctarget = e.c.fwdLabel(); label end = e.c.fwdLabel(); e.c.pushLoop(ctarget, end); label start = e.c.defNewLabel(); if(test) { test->transConditionalJump(e, false, end); } transLoopBody(e,body); e.c.defLabel(ctarget); if (update) update->markTrans(e); e.c.useLabel(inst::jmp,start); e.c.defLabel(end); e.c.popLoop(); e.e.endScope(); } void extendedForStm::prettyprint(ostream &out, Int indent) { prettyindent(out, indent); out << "extendedForStm: '" << var << "'\n"; start->prettyprint(out, indent+1); set->prettyprint(out, indent+1); body->prettyprint(out, indent+1); } void extendedForStm::trans(coenv &e) { // Translate into the syntax: // // start[] a = set; // for (int i=0; i < a.length; ++i) { // start var=a[i]; // body // } position pos=getPos(); // Use gensyms for the variable names so as not to pollute the namespace. symbol a=symbol::gensym("a"); symbol i=symbol::gensym("i"); // Get the start type. Handle type inference as a special case. types::ty *t = start->trans(e, true); if (t->kind == types::ty_inferred) { // First ensure the array expression is an unambiguous array. types::ty *at = set->cgetType(e); if (at->kind != ty_array) { em.error(set->getPos()); em << "expression is not an array of inferable type"; // On failure, don't bother trying to translate the loop. return; } // var a=set; tyEntryTy tet(pos, primInferred()); decid dec1(pos, new decidstart(pos, a), set); vardec(pos, &tet, &dec1).trans(e); } else { // start[] a=set; arrayTy at(pos, start, new dimensions(pos)); decid dec1(pos, new decidstart(pos, a), set); vardec(pos, &at, &dec1).trans(e); } // { start var=a[i]; body } block b(pos); decid dec2(pos, new decidstart(pos, var), new subscriptExp(pos, new nameExp(pos, a), new nameExp(pos, i))); b.add(new vardec(pos, start, &dec2)); b.add(body); // for (int i=0; i < a.length; ++i) // forStm(pos, new vardec(pos, new tyEntryTy(pos, primInt()), new decid(pos, new decidstart(pos, i), new intExp(pos, 0))), new binaryExp(pos, new nameExp(pos, i), SYM_LT, new nameExp(pos, new qualifiedName(pos, new simpleName(pos, a), symbol::trans("length")))), new expStm(pos, new prefixExp(pos, new nameExp(pos, i), SYM_PLUS)), new blockStm(pos, &b)).trans(e); } void breakStm::prettyprint(ostream &out, Int indent) { prettyname(out,"breakStm",indent); } void breakStm::trans(coenv &e) { if (!e.c.encodeBreak()) { em.error(getPos()); em << "break statement outside of a loop"; } } void continueStm::prettyprint(ostream &out, Int indent) { prettyname(out,"continueStm",indent); } void continueStm::trans(coenv &e) { if (!e.c.encodeContinue()) { em.error(getPos()); em << "continue statement outside of a loop"; } } void returnStm::prettyprint(ostream &out, Int indent) { prettyname(out, "returnStm",indent); if (value) value->prettyprint(out, indent+1); } void returnStm::trans(coenv &e) { types::ty *t = e.c.getReturnType(); if (t->kind == ty_void) { if (value) { em.error(getPos()); em << "function cannot return a value"; } if (e.c.isRecord()) e.c.encode(inst::pushclosure); } else { if (value) { value->transToType(e, t); } else { em.error(getPos()); em << "function must return a value"; } } // NOTE: Currently, a return statement in a module definition will end // the initializer. Should this be allowed? e.c.encode(inst::ret); } void stmExpList::prettyprint(ostream &out, Int indent) { prettyname(out, "stmExpList",indent); for (mem::list::iterator p = stms.begin(); p != stms.end(); ++p) (*p)->prettyprint(out, indent+1); } void stmExpList::trans(coenv &e) { for (mem::list::iterator p = stms.begin(); p != stms.end(); ++p) (*p)->markTrans(e); } } // namespace absyntax asymptote-2.37/stm.h000066400000000000000000000104601265434602500144560ustar00rootroot00000000000000/***** * stm.h * Andy Hammerlindl 2002/8/30 * * Statements are objects in the language that do something on their * own. Statements are different from declarations in that statements * do not modify the environment. Translation of a statements puts the * stack code to run it into the instruction stream. *****/ #ifndef STM_H #define STM_H #include "types.h" #include "symbol.h" #include "dec.h" namespace trans { class coenv; } namespace absyntax { using trans::coenv; using sym::symbol; class stm : public runnable { public: stm(position pos) : runnable(pos) {} void prettyprint(ostream &out, Int indent); void transAsField(coenv &e, record *) { // Ignore the record. trans(e); } void trans(coenv &e) = 0; }; class emptyStm : public stm { public: emptyStm(position pos) : stm(pos) {} void prettyprint(ostream &out, Int indent); void trans(coenv &) {} }; // Wrapper around a block to use it as a statement. class blockStm : public stm { block *base; public: blockStm(position pos, block *base) : stm(pos), base(base) {} void prettyprint(ostream &out, Int indent); void trans(coenv &e) { return base->trans(e); } // A block is guaranteed to return iff its last statement is // guaranteed to return. bool returns() { return base->returns(); } }; // A statement that consist of a single expression to evaluate. class expStm : public stm { exp *body; public: expStm(position pos, exp *body) : stm(pos), body(body) {} void prettyprint(ostream &out, Int indent); void trans(coenv &e); // Should be called when running an expStm at the interactive prompt. // The code will "write" the value of the expression at the prompt if // possible. void interactiveTrans(coenv &e); }; class ifStm : public stm { exp *test; stm *onTrue; stm *onFalse; public: ifStm(position pos, exp *test, stm* onTrue, stm* onFalse = 0) : stm(pos), test(test), onTrue(onTrue), onFalse(onFalse) {} void prettyprint(ostream &out, Int indent); void trans(coenv &e); // An if statement is guaranteed to return iff both its pieces are // guaranteed to return. bool returns() { if (onTrue == 0 || onFalse == 0) return false; return onTrue->returns() && onFalse->returns(); } }; class whileStm : public stm { exp *test; stm *body; public: whileStm(position pos, exp *test, stm *body) : stm(pos), test(test), body(body) {} void prettyprint(ostream &out, Int indent); void trans(coenv &e); }; class doStm : public stm { stm *body; exp *test; public: doStm(position pos, stm *body, exp *test) : stm(pos), body(body), test(test) {} void prettyprint(ostream &out, Int indent); void trans(coenv &e); }; class forStm : public stm { runnable *init; exp *test; runnable *update; stm *body; public: forStm(position pos, runnable *init, exp *test, runnable *update, stm *body) : stm(pos), init(init), test(test), update(update), body(body) {} void prettyprint(ostream &out, Int indent); void trans(coenv &e); }; class extendedForStm : public stm { ty *start; symbol var; exp *set; stm *body; public: extendedForStm(position pos, ty *start, symbol var, exp *set, stm *body) : stm(pos), start(start), var(var), set(set), body(body) {} void prettyprint(ostream &out, Int indent); void trans(coenv &e); }; class breakStm : public stm { public: breakStm(position pos) : stm(pos) {} void prettyprint(ostream &out, Int indent); void trans(coenv &e); }; class continueStm : public stm { public: continueStm(position pos) : stm(pos) {} void prettyprint(ostream &out, Int indent); void trans(coenv &e); }; class returnStm : public stm { exp *value; public: returnStm(position pos, exp *value = 0) : stm(pos), value(value) {} void prettyprint(ostream &out, Int indent); void trans(coenv &e); // A return statement is, of course, guaranteed to return. bool returns() { return true; } }; // Used at the start of for loops. class stmExpList : public stm { mem::list stms; public: stmExpList(position pos) : stm(pos) {} // To ensure list deallocates properly. virtual ~stmExpList() {} void add(stm *s) { stms.push_back(s); } void prettyprint(ostream &out, Int indent); void trans(coenv &e); }; } // namespace absyntax #endif asymptote-2.37/symbol.cc000066400000000000000000000213201265434602500153130ustar00rootroot00000000000000/***** * symbol.cc * Andy Hammerlindl 2002/06/18 * * Creates symbols from strings so that multiple calls for a symbol of * the same string will return an identical object. *****/ #include #include using std::strlen; #include "settings.h" #include "symbol.h" namespace sym { const char USED = 1; const char SKIP = 2; struct symbolRecord { // When a symbol is entered into the table, its hash is computed. If the // corresponding entry in the table is full, this value is incremented until // an empty slot is found. hashplus stores the end value. // Each symbol has a unique hashplus value, even if there is a collision in // the original hashing function. uint hashplus; // Whether the cell of the table is empty, in use, or a "skip" entry due to // a resizing of the table. unsigned char flag; // Pointer to a copy of the string (allocated on the heap). This string // will never be deallocated. Symbols, in essence, last forever. char *s; }; // The table size must be a power of two so that (h % tableSize) can be // replaced by (h & tableMask). 1 << 15 was chosen based on the number of // unique symbols (roughly 4000) which occured in all of the base modules. const size_t SYMBOL_TABLE_BASE_CAPACITY = 1 << 15; symbolRecord baseSymbolTable[SYMBOL_TABLE_BASE_CAPACITY]; symbolRecord *table = baseSymbolTable; size_t tableCapacity = SYMBOL_TABLE_BASE_CAPACITY; uint tableMask = 0; size_t tableSize = 0; symbolRecord &recordByHashplus(uint h) { return table[h & tableMask]; } GCInit symbol::initialize; symbol symbol::nullsym; symbol symbol::initsym; symbol symbol::castsym; symbol symbol::ecastsym; const char *nullsymstr = ""; void initTable() { tableMask = (uint)(tableCapacity - 1); tableSize = 0; // Set every entry to empty. (Is this faster than memsetting the whole // thing?) for (size_t i = 0; i < tableCapacity; ++i) table[i].flag = 0; // The zeroth entry is reserved for the "null" symbol. if (table == baseSymbolTable) { table[0].flag = USED; table[0].s = new char[strlen(nullsymstr) + 1]; strcpy(table[0].s, nullsymstr); ++tableSize; symbol::nullsym.hashplus = 0; symbol::initsym = symbol::opTrans("init"); symbol::castsym = symbol::opTrans("cast"); symbol::ecastsym = symbol::opTrans("ecast"); } } // Hashing constants found experimentally to reduce collision (a little). const uint A = 25191, B = 16342, C = 1746, D = 18326; // Hash the string into an integer. Experimental testing has shown that // hashing only the first few letters seems to be faster than hashing deeper // into the string, even though this approach causes more hash collisions. uint hash(const char *s, size_t len) { uint h = s[0]; if (len == 2) return h; h += A*s[1]; if (len == 3) return h; h += B*s[2]; if (len == 4) return h; h += C*s[3]; if (len == 5) return h; h += D*s[4]; return h+len; } /* Under normal circumstances, the initial table should be large enough for * all of the symbols used and will never be resized. Just in case the * program encounters a large number of distinct symbols, we implement * resizing of the table. */ void resizeTable() { symbolRecord *oldTable = table; size_t oldSize = tableSize; size_t oldCapacity = tableCapacity; tableCapacity *= 4; table = new symbolRecord[tableCapacity]; initTable(); // The null symbol is a special case. table[0] = oldTable[0]; ++tableSize; #if 0 printf("old:\n"); for (size_t i = 0; i < oldCapacity; ++i) { symbolRecord &r = oldTable[i]; if (r.flag != USED) continue; printf(" %u -> %s\n", r.hashplus, r.s); } #endif for (size_t i = 1; i < oldCapacity; ++i) { symbolRecord &r = oldTable[i]; if (r.flag != USED) continue; // Entries that were skipped over when this symbol was entered into the // old hash table may not appear in the same spot in the new hash table. // Put "SKIP" entries in their place, so that the symbol will still be // found. for (uint h = hash(r.s, strlen(r.s)+1); h < r.hashplus; ++h) { symbolRecord &skipr = recordByHashplus(h); if (skipr.flag == 0) skipr.flag = SKIP; } // Enter the symbol in its spot. symbolRecord &newr = recordByHashplus(r.hashplus); assert(newr.flag != USED); newr.flag = USED; newr.hashplus = r.hashplus; newr.s = r.s; ++tableSize; } #if 0 printf("new:\n"); for (size_t i = 0; i < tableCapacity; ++i) { symbolRecord &r = table[i]; if (r.flag != USED) continue; printf(" %u -> %s\n", r.hashplus, r.s); } #endif assert(tableSize == oldSize); // Debugging resize. for (size_t i = 1; i < oldCapacity; ++i) { symbolRecord &r = oldTable[i]; if (r.flag != USED) continue; symbolRecord &newr = recordByHashplus(r.hashplus); assert(newr.hashplus == r.hashplus); assert(newr.flag != 0); assert(newr.flag != SKIP); assert(newr.flag == USED); assert(newr.s = r.s); if (strncmp(r.s, "gensym", 6) != 0) assert(symbol::rawTrans(r.s, strlen(r.s)+1).hashplus == r.hashplus); } #if 0 // Diagnostics. uint empty=0, used=0, skip=0; for (size_t i = 0; i < tableCapacity; ++i) { symbolRecord &r = table[i]; if (r.flag == 0) ++empty; else if (r.flag == USED) ++used; else if (r.flag == SKIP) ++skip; else assert("Unknown flag" == 0); } cout << "Resized symbol table. " << "empty: " << empty << "used: " << used << "skip: " << skip << endl; #endif } symbol symbolize(uint h) { symbol s; s.hashplus = h; return s; } // Handles the insertion of a new symbol into a table the has been resized (or // needs resizing). symbol advancedInsert(const char *s, size_t len) { if (2*tableSize >= tableCapacity) resizeTable(); uint hashplus = hash(s, len); #if 1 assert(s != 0); assert(len > 0); assert(2*tableSize <= tableCapacity); #endif // We know the symbol is not in the table. Just search for the first unused // entry (either empty or a skip entry) and insert there. for (;;) { symbolRecord &r = recordByHashplus(hashplus); if (r.flag != USED) { r.flag = USED; r.s = new char[len]; memcpy(r.s, s, len); assert(r.s[len-1] == '\0'); r.hashplus = hashplus; ++tableSize; assert(2*tableSize <= tableCapacity); return symbolize(hashplus); } ++hashplus; } assert("Unreachable code" == 0); return symbol::nullsym; } symbol symbol::gensym(string s) { // Gensym can be inserted as if it were a normal string not already in the // table. advancedInsert handles this. s = "gensym " + s; return advancedInsert(s.c_str(), s.size() + 1); } symbol symbol::rawTrans(const char *s, size_t len) { uint hashplus = sym::hash(s, len); #if 1 assert(s != 0); assert(len > 0); assert(2*tableSize <= tableCapacity); #endif // Search through the table till we find the symbol already translated or // an empty field. for (;;) { symbolRecord &r = recordByHashplus(hashplus); // Translating pre-existing symbols is more common, so check for it first. if (r.hashplus == hashplus && r.flag == USED && strncmp(r.s, s, len) == 0) { return symbolize(hashplus); } // Then check for an empty entry, in which case the entry is added. if (r.flag == 0) { // Test if the table needs resizing before entering a new symbol, or if // the table has already been resized. In either case, the symbol will // be added to a resized table which may contain skip entries, and a // more involved insertion routine is needed. if (2*tableSize >= SYMBOL_TABLE_BASE_CAPACITY) return advancedInsert(s, len); r.flag = USED; r.s = new char[len]; memcpy(r.s, s, len); assert(r.s[len-1] == '\0'); r.hashplus = hashplus; ++tableSize; assert(2*tableSize <= tableCapacity); return symbolize(hashplus); } // A case where a different symbol is in the spot, continue along the // table. ++hashplus; } assert("Unreachable code" == 0); return symbol::nullsym; } symbol::operator string () const { symbolRecord &r = recordByHashplus(this->hashplus); return (string)r.s; } ostream& operator<< (ostream& out, const symbol sym) { symbolRecord &r = recordByHashplus(sym.hashplus); return out << r.s; } } // end namespace sym /* Define all of operator symbols SYM_PLUS, etc. */ #define OPSYMBOL(str, name) \ sym::symbol name = sym::symbol::opTrans(str) #include "opsymbols.h" #undef OPSYMBOL /* Define all of the symbols of the type SYM(name) in selected files. */ #define ADDSYMBOL(name) \ sym::symbol PRETRANSLATED_SYMBOL_##name = sym::symbol::literalTrans(#name) #include "allsymbols.h" #undef ADDSYMBOL asymptote-2.37/symbol.h000066400000000000000000000051461265434602500151650ustar00rootroot00000000000000/***** * symbol.h * Andy Hammerlindl 2002/06/18 * * Creates symbols from strings so that multiple calls for a symbol of * the same string will return an identical object. *****/ #ifndef SYMBOL_H #define SYMBOL_H #include #include #include "common.h" using std::ostream; namespace sym { void initTable(); struct GCInit { #ifdef _AIX typedef char * GC_PTR; #endif GCInit() { #ifdef USEGC GC_set_free_space_divisor(2); mem::compact(0); GC_INIT(); #endif // Put the symbol table into a state where symbols can be translated. initTable(); } }; typedef unsigned int uint; /* The symbol class, just a wrapper around the augmented hash value. This * wrapper is so that * cout << s << endl; * prints the symbol name instead of a meaningless integer. * * This is a lightweight class and should have no virtual functions for speed * reasons. */ struct symbol { // Is there any particular reason why this is in symbol? static GCInit initialize; uint hashplus; #if 0 symbol() {} symbol(uint h) : hashplus(h) {} #endif static symbol nullsym; static symbol initsym; static symbol castsym; static symbol ecastsym; bool special() const { return *this == initsym || *this == castsym || *this == ecastsym; } bool notSpecial() const { return !special(); } // Translate a string into a unique symbol, such that two strings are equal // if and only if their resulting symbols are equal. // len should be equal to strlen(s)+1 static symbol rawTrans(const char *s, size_t len); static symbol literalTrans(string s) { return rawTrans(s.c_str(), s.size() + 1); } static symbol opTrans(string s) { return literalTrans("operator "+s); } static symbol trans(string s) { // Figure out whether it's an operator or an identifier by looking at the // first character. char c=s[0]; return isalpha(c) || c == '_' ? literalTrans(s) : opTrans(s); } // Make a symbol that is guaranteed to be unique. It will not match any other // symbol in the namespace. static symbol gensym(string s); size_t hash() const { return (size_t)this->hashplus; } friend bool operator== (symbol s1, symbol s2) { return s1.hashplus == s2.hashplus; } friend bool operator!= (symbol s1, symbol s2) { return s1.hashplus != s2.hashplus; } friend bool operator< (symbol s1, symbol s2) { return s1.hashplus < s2.hashplus; } operator bool () const { return this->hashplus != 0; } operator string () const; friend ostream& operator<< (ostream& out, const symbol sym); }; } // end namespace #endif // SYMBOL_H asymptote-2.37/table.h000066400000000000000000000052111265434602500147400ustar00rootroot00000000000000/***** * table.h * Andy Hammerlindl 2002/06/18 * * Table used to bind symbols to vars and types in a namespace. *****/ #ifndef TABLE_H #define TABLE_H #include #include #include "symbol.h" #include "common.h" namespace sym { template class table; template std::ostream& operator<< (std::ostream& out, const table& t); template class table { protected: typedef mem::multimap scope_t; typedef typename scope_t::iterator scope_iterator; typedef mem::list scopes_t; typedef mem::list name_t; typedef typename name_t::iterator name_iterator; typedef mem::map names_t; typedef typename names_t::iterator names_iterator; scopes_t scopes; names_t names; void remove(symbol key); public : table(); void enter(symbol key, B value); B look(symbol key); // Allows scoping and overloading of symbols of the same name void beginScope(); void endScope(); // Copies all bindings in the top scope to the scope underneath it, and // removes the the top scope. void collapseScope(); // Adds to l, all names prefixed by start. void completions(mem::list& l, string start); friend std::ostream& operator<< (std::ostream& out, const table& t); }; template inline table::table() { beginScope(); } template inline void table::enter(symbol key, B value) { scopes.front().insert(std::make_pair(key,value)); names[key].push_front(value); } template inline B table::look(symbol key) { if (!names[key].empty()) return names[key].front(); return 0; } template inline void table::beginScope() { scopes.push_front(scope_t()); } template inline void table::remove(symbol key) { if (!names[key].empty()) names[key].pop_front(); } template inline void table::endScope() { scope_t &scope = scopes.front(); for (scope_iterator p = scope.begin(); p != scope.end(); ++p) remove(p->first); scopes.pop_front(); } template inline void table::collapseScope() { scope_t scope = scopes.front(); scopes.pop_front(); scopes.front().insert(scope.begin(), scope.end()); } // Returns true if start is a prefix for name; eg, mac is a prefix of machine. inline bool prefix(string start, string name) { return equal(start.begin(), start.end(), name.begin()); } template inline void table::completions(mem::list& l, string start) { for (names_iterator p = names.begin(); p != names.end(); ++p) if (prefix(start, p->first) && !p->second.empty()) l.push_back(p->first); } } // namespace sym #endif asymptote-2.37/tests/000077500000000000000000000000001265434602500146435ustar00rootroot00000000000000asymptote-2.37/tests/Makefile000066400000000000000000000004641265434602500163070ustar00rootroot00000000000000.NOTPARALLEL: TESTDIRS = string arith frames types imp array pic gs EXTRADIRS = gsl output test: $(TESTDIRS) all: $(TESTDIRS) $(EXTRADIRS) $(TESTDIRS):: @echo ../asy -dir ../base $@/*.asy $(EXTRADIRS):: @echo ../asy -dir ../base $@/*.asy clean: FORCE rm -f *.eps distclean: FORCE clean FORCE: asymptote-2.37/tests/TestLib.asy000066400000000000000000000003561265434602500167330ustar00rootroot00000000000000bool close(pair a, pair b) { real norm=(b == 0) ? 1 : max(abs(a),abs(b)); return abs(a-b) <= 100*realEpsilon*norm; } void StartTest(string desc) { write("Testing " + desc + "...",flush); } void EndTest() { write("PASSED."); } asymptote-2.37/tests/arith/000077500000000000000000000000001265434602500157525ustar00rootroot00000000000000asymptote-2.37/tests/arith/integer.asy000066400000000000000000000011541265434602500201260ustar00rootroot00000000000000// Integer arithmetic. import TestLib; StartTest("integer addition"); assert(1+1==2); EndTest(); StartTest("integer subtraction"); assert(2-1==1); EndTest(); StartTest("integer multiplication"); assert(2*2==4); EndTest(); StartTest("integer division"); assert(4/2==2); EndTest(); StartTest("integer self ops"); { int x = 3; assert(++x==4); assert(x==4); } { int x = 3; assert(--x==2); assert(x==2); } { int x = 3; assert((x+=7) == 10); assert(x==10); } { int x = 3; assert((x-=7) == -4); assert(x==-4); } { int x = 3; assert((x*=7) == 21); assert(x==21); } { int x = 10; assert((x%=4) == 2); assert(x==2); } EndTest(); asymptote-2.37/tests/arith/pair.asy000066400000000000000000000007011265434602500174210ustar00rootroot00000000000000import TestLib; StartTest("complex addition"); assert((1,0)+(0,1)==(1,1)); EndTest(); StartTest("complex subtraction"); assert((1,0)-(0,1)==(1,-1)); EndTest(); StartTest("complex multiplication"); assert((1,2)*(2,1)==(0,5)); EndTest(); StartTest("complex division"); assert((0,5)/(2,1)==(1,2)); EndTest(); StartTest("length(pair)"); assert(length((0.0,1.0)) == 1.0); EndTest(); StartTest("conj()"); assert(conj((0.0,1.0))==(0.0, -1.0)); EndTest(); asymptote-2.37/tests/arith/random.asy000066400000000000000000000003011265434602500177420ustar00rootroot00000000000000import TestLib; StartTest("random"); bool bit32=false; for(int i=0; i < 1000; ++i) { real x=unitrand(); if(x > 0.5) bit32=true; assert(x >= 0.0 && x <= 1.0); } assert(bit32); EndTest(); asymptote-2.37/tests/arith/real.asy000066400000000000000000000005771265434602500174240ustar00rootroot00000000000000// Real arithmetic. import TestLib; StartTest("real error"); assert((1.0-1.0) < realEpsilon); EndTest(); StartTest("real addition"); assert((1.0+1.0) == (2.0)); EndTest(); StartTest("real subtraction"); assert((2.0-1.0) == (1.0)); EndTest(); StartTest("real multiplication"); assert((2.0*2.0) == (4.0)); EndTest(); StartTest("real division"); assert((4.0/2.0) == (2.0)); EndTest(); asymptote-2.37/tests/arith/roots.asy000066400000000000000000000032561265434602500176440ustar00rootroot00000000000000// Roots. import TestLib; real x; real[] r; StartTest("quadratic roots"); r=quadraticroots(1,0,-8); assert(r.length == 2); r=sort(r); x=2sqrt(2); assert(close(r[0],-x)); assert(close(r[1],x)); r=quadraticroots(1,2,1); assert(r.length == 2); assert(close(r[0],-1)); assert(close(r[1],-1)); r=quadraticroots(1,0,8); assert(r.length == 0); r=quadraticroots(0,2,3); assert(r.length == 1); assert(close(r[0],-3/2)); EndTest(); StartTest("cubic roots"); r=cubicroots(1,0,0,-8); assert(r.length == 1); assert(close(r[0],2)); real[] r=cubicroots(1,3,3,1); assert(r.length == 3); assert(close(r[0],-1)); assert(close(r[1],-1)); assert(close(r[2],-1)); real[] r=cubicroots(1,-3,3,-1); assert(r.length == 3); assert(close(r[0],1)); assert(close(r[1],1)); assert(close(r[2],1)); r=cubicroots(1,0,0,0); assert(r.length == 3); assert(r[0] == 0); assert(r[1] == 0); assert(r[2] == 0); r=cubicroots(1,0,-15,-4); assert(r.length == 3); r=sort(r); assert(close(r[0],-2-sqrt(3))); assert(close(r[1],-2+sqrt(3))); assert(close(r[2],4)); r=cubicroots(1,0,-15,4); assert(r.length == 3); r=sort(r); assert(close(r[0],-4)); assert(close(r[1],2-sqrt(3))); assert(close(r[2],2+sqrt(3))); r=cubicroots(1,0,-15,0); assert(r.length == 3); r=sort(r); x=sqrt(15); assert(close(r[0],-x)); assert(r[1] == 0); assert(close(r[2],x)); r=cubicroots(1,1,1,0); assert(r.length == 1); assert(r[0] == 0); r=cubicroots(1,0,20,-4); assert(r.length == 1); x=cbrt(54+6sqrt(6081)); assert(close(r[0],x/3-20/x)); EndTest(); StartTest("newton"); real f(real x) {return cos(x);} real dfdx(real x) {return -sin(x);} assert(close(newton(f,dfdx,1),pi/2)); assert(newton(f,dfdx,0) == realMax); assert(newton(f,dfdx,0,2) == pi/2); EndTest(); asymptote-2.37/tests/arith/transform.asy000066400000000000000000000011771265434602500205110ustar00rootroot00000000000000import TestLib; pair x = (1, 2); StartTest("identity transform"); assert(identity()*x == x); EndTest(); StartTest("shift transform"); assert(shift((1,1))*x == (2, 3)); assert(shift(1,1)*x == (2, 3)); EndTest(); StartTest("scaling transforms"); assert(xscale(2)*x == (2, 2)); assert(yscale(2)*x == (1, 4)); assert(scale(2)*x == (2, 4)); EndTest(); StartTest("slant transform"); assert(slant(1)*x == (3, 2)); EndTest(); StartTest("rotation transform"); assert(length((rotate(90)*x) - (-2,1)) <= realEpsilon); assert(rotate(90, x)*x == x); EndTest(); StartTest("reflect transform"); assert(reflect((-1, -1), (1, 1))*x == (2, 1)); EndTest(); asymptote-2.37/tests/arith/triple.asy000066400000000000000000000003641265434602500177720ustar00rootroot00000000000000import TestLib; triple t = (1,0,0); StartTest("polar()"); assert(polar(t) == (pi / 2.0) ); EndTest(); StartTest("azimuth()"); assert(azimuth(t) < realEpsilon); EndTest(); StartTest("unit()"); assert(length(t-unit(t)) < realEpsilon); EndTest(); asymptote-2.37/tests/array/000077500000000000000000000000001265434602500157615ustar00rootroot00000000000000asymptote-2.37/tests/array/array.asy000066400000000000000000000016501265434602500176170ustar00rootroot00000000000000import TestLib; StartTest("array"); { int[] x=array(10, 7); assert(x.length == 10); for (int i=0; i= 0 && k < 3)); } { int[] z; for (int i=0; i<10; ++i) { for (int k = 0; k <= 100; ++k) { assert(z.length == k); z.push(k*k+3k+1); assert(z.length == k+1); } for (int k = 100; k >= 0; --k) { assert(z.length == k+1); assert(z.pop() == k*k+3k+1); assert(z.length == k); } } z.cyclic=true; for (int i=0; i<10; ++i) { for (int k = 0; k <= 100; ++k) { assert(z.length == k); z.push(k*k+3k+1); assert(z.length == k+1); } for (int k = 100; k >= 0; --k) { assert(z.length == k+1); z.delete(quotient(k,2)); assert(z.length == k); } } } { int[] base={4,5,9,5,0,2,3}; int[] z; for (int i=0; i<9; ++i) { assert(z.length == i*base.length); for (int j : z.keys) assert(z[j] == base[j%base.length]); z.append(base); } } { int[] z = {1,2,3,4,6,7,8,9}; assert(z.length == 8); z.insert(4, 5); assert(z.length == 9); z.insert(0, 0); assert(z.length == 10); for (int i=0; i<10; ++i) assert(z[i] == i); z.insert(7, 100, 101, 102, 103); assert(z.length == 14); // TODO: Test inserting/deleting lengths more seriously. } { // Test extended for. int[] a = {1,4,6,2,7,4,8,9,1,3,-1}; int i = 0; for (int x : a) { assert(x == a[i]); ++i; } assert(i == a.length); } { // Test extended for. int[] a = {1,4,6,2,7,4,8,9,1,3,-1}; int i = 0; for (var x : a) { assert(x == a[i]); ++i; } assert(i == a.length); } EndTest(); asymptote-2.37/tests/array/slice.asy000066400000000000000000000113511265434602500175770ustar00rootroot00000000000000import TestLib; StartTest("slice"); int[] x={0,1,2,3,4,5,6,7,8,9}; // Non-cyclic cases. assert(all(x[:] == x)); assert(!alias(x[:],x)); assert(all(x[0:4] == new int[] {0,1,2,3} )); assert(all(x[2:4] == new int[] {2,3} )); assert(all(x[5:] == new int[] {5,6,7,8,9} )); assert(all(x[:5] == new int[] {0,1,2,3,4} )); assert(all(x[3:3] == new int[] {} )); assert(all(x[3:4] == new int[] {3} )); assert(all(x[98:99] == new int[] {} )); assert(x[:].cyclic == false); assert(x[2:].cyclic == false); assert(x[:7].cyclic == false); assert(x[3:3].cyclic == false); assert(x[2:9].cyclic == false); // Cyclic cases x.cyclic=true; assert(all(x[:] == new int[] {0,1,2,3,4,5,6,7,8,9} )); assert(all(x[0:4] == new int[] {0,1,2,3} )); assert(all(x[2:4] == new int[] {2,3} )); assert(all(x[5:] == new int[] {5,6,7,8,9} )); assert(all(x[-5:] == new int[] {5,6,7,8,9,0,1,2,3,4,5,6,7,8,9} )); assert(all(x[:5] == new int[] {0,1,2,3,4} )); assert(all(x[3:3] == new int[] {} )); assert(all(x[3:4] == new int[] {3} )); assert(all(x[-1:1] == new int[] {9,0} )); assert(all(x[9:11] == new int[] {9,0} )); assert(all(x[9:21] == new int[] {9,0,1,2,3,4,5,6,7,8,9,0} )); assert(all(x[-15:15] == new int[] {5,6,7,8,9,0,1,2,3,4,5,6,7,8,9, 0,1,2,3,4,5,6,7,8,9,0,1,2,3,4})); assert(all(x[6728:6729] == new int[] {8} )); assert(all(x[-6729:-6728] == new int[] {1} )); assert(x[:].cyclic == false); assert(x[2:].cyclic == false); assert(x[:7].cyclic == false); assert(x[3:3].cyclic == false); assert(x[2:9].cyclic == false); assert(x[5:100].cyclic == false); pair[] z={(1,2), (3,4), (5,6)}; assert(all(z[1:1] == new pair[] {})); assert(all(z[:1] == new pair[] {(1,2)})); assert(all(z[1:] == new pair[] {(3,4), (5,6)})); assert(all(z[:] == z)); assert(all(z[1:2] == new pair[] {(3,4)})); // Writing tests. { int[] y={0,1,2,3,4,5,6,7,8,9}; int[] z={56,67,78}; y[:] = z; assert(all(y == z)); assert(!alias(y,z)); } { int[] y={0,1,2,3,4,5,6,7,8,9}; int[] z={56,67,78}; z.cyclic=true; y[:] = z; assert(all(y == z)); assert(!alias(y,z)); assert(y.cyclic == false); } { int[] y={0,1,2,3,4,5,6,7,8,9}; y[2:3] = y[5:6] = new int[] {77}; assert(all(y == new int[] {0,1,77,3,4,77,6,7,8,9})); } { int[] y={0,1,2,3,4,5,6,7,8,9}; y[:3] = y[7:] = new int[] {}; assert(all(y == new int[] {3,4,5,6})); } { int[] y={0,1,2,3,4,5,6,7,8,9}; y[3:5] = new int[] {13,14,15,16,17}; assert(all(y == new int[] {0,1,2,13,14,15,16,17,5,6,7,8,9})); } { int[] y={0,1,2,3,4,5,6,7,8,9}; y.cyclic=true; int[] z={56,67,78}; y[:] = z; assert(all(y == z)); assert(!alias(y,z)); assert(y.cyclic == true); } { int[] y={0,1,2,3,4,5,6,7,8,9}; y.cyclic=true; int[] z={56,67,78}; z.cyclic=true; y[:] = z; assert(all(y == z)); assert(!alias(y,z)); assert(y.cyclic == true); } { int[] y={0,1,2,3,4,5,6,7,8,9}; y.cyclic=true; y[2:3] = y[5:6] = new int[] {77}; assert(all(y == new int[] {0,1,77,3,4,77,6,7,8,9})); } { int[] y={0,1,2,3,4,5,6,7,8,9}; y.cyclic=true; y[:3] = y[7:] = new int[] {}; assert(all(y == new int[] {3,4,5,6})); } { int[] y={0,1,2,3,4,5,6,7,8,9}; y.cyclic=true; y[8:] = new int[] {18,19,20,21,22}; assert(all(y == new int[] {0,1,2,3,4,5,6,7,18,19,20,21,22})); } { int[] y={0,1,2,3,4,5,6,7,8,9}; y.cyclic=true; y[-2:0] = new int[] {18,19,20,21,22}; assert(all(y == new int[] {0,1,2,3,4,5,6,7,18,19,20,21,22})); } { int[] y={0,1,2,3,4,5,6,7,8,9}; y.cyclic=true; y[18:20] = new int[] {18,19,20,21,22}; assert(all(y == new int[] {0,1,2,3,4,5,6,7,18,19,20,21,22})); } { int[] y={0,1,2,3,4,5,6,7,8,9}; y.cyclic=true; y[3:5] = new int[] {13,14,15,16,17}; assert(all(y == new int[] {0,1,2,13,14,15,16,17,5,6,7,8,9})); } { int[] y={0,1,2,3,4,5,6,7,8,9}; y.cyclic=true; y[13:15] = new int[] {13,14,15,16,17}; assert(all(y == new int[] {0,1,2,13,14,15,16,17,5,6,7,8,9})); } { int[] y={0,1,2,3,4,5,6,7,8,9}; y.cyclic=true; y[3-10:5-10] = new int[] {13,14,15,16,17}; assert(all(y == new int[] {0,1,2,13,14,15,16,17,5,6,7,8,9})); } { int[] y={0,1,2,3,4,5,6,7,8,9}; y.cyclic=true; y[8:12] = new int[] {18,19,20,21}; assert(all(y == new int[] {20,21,2,3,4,5,6,7,18,19})); } { int[] y={0,1,2,3,4,5,6,7,8,9}; y.cyclic=true; y[-2:2] = new int[] {18,19,20,21}; assert(all(y == new int[] {20,21,2,3,4,5,6,7,18,19})); } // Side Effect Test { int state=0; int[] x={0,1,2,3,4,5,6,7,8,9}; int[] a() { assert(state==0); ++state; return x; } int l() { assert(state==1); ++state; return 2; } int r() { assert(state==2); ++state; return 6; } int[] b() { assert(state==3); ++state; return new int[] {77,77}; } assert(state==0); a()[l():r()]=b(); assert(state==4); assert(all(x == new int[] {0,1,77,77,6,7,8,9})); } EndTest(); asymptote-2.37/tests/array/solve.asy000066400000000000000000000017061265434602500176330ustar00rootroot00000000000000import TestLib; StartTest("solve"); real[][] a=new real[][] {{1,1,1},{1,2,2},{0,0,1}}; real[][] b=new real[][] {{3,9},{5,11},{1,3}}; real[][] x=new real[][] {{1,7},{1,-1,},{1,3}}; real[][] c=solve(a,b); for(int i=0; i < c.length; ++i) for(int j=0; j < c[i].length; ++j) assert(close(c[i][j],x[i][j])); real[][] a={{1,-2,3,0},{4,-5,6,2},{-7,-8,10,5},{1,50,1,-2}}; real[] b={7,19,33,3}; real[] x=solve(a,b); real[] c=a*x; for(int i=0; i < c.length; ++i) assert(close(c[i],b[i])); EndTest(); StartTest("inverse"); real[][] a=new real[][] {{1,1,1},{1,2,2},{0,0,1}}; real[][] ainverse=new real[][] {{2,-1,0},{-1,1,-1},{0,0,1}}; real[][] d=inverse(a); real[][] l=d*a; real[][] r=a*d; real[][] I=identity(a.length); for(int i=0; i < d.length; ++i) { for(int j=0; j < d[i].length; ++j) { assert(close(d[i][j],ainverse[i][j])); assert(I[i][j] == (i == j ? 1 : 0)); assert(close(l[i][j],I[i][j])); assert(close(r[i][j],I[i][j])); } } EndTest(); asymptote-2.37/tests/array/sort.asy000066400000000000000000000013521265434602500174670ustar00rootroot00000000000000import TestLib; import math; string[] a={"bob","alice","pete","alice"}; string[] b={"alice","alice","bob","pete"}; StartTest("sort"); assert(all(sort(a) == b)); EndTest(); StartTest("search"); assert(search(b,"a") == -1); assert(search(b,"bob") == 2); assert(search(b,"z") == b.length-1); EndTest(); StartTest("sort2"); string[][] a={{"bob","9"},{"alice","5"},{"pete","7"},{"alice","4"}}; string[][] b={{"alice","4"},{"alice","5"},{"bob","9"},{"pete","7"}}; assert(sort(a) == b); EndTest(); pair[] a={(2,1),(0,0),(1,1),(1,0)}; pair[] b={(0,0),(1,0),(1,1),(2,1)}; StartTest("lexicographical sort"); assert(all(sort(a,lexorder) == b)); EndTest(); StartTest("lexicographical search"); assert(search(b,(1,0),lexorder) == 1); EndTest(); asymptote-2.37/tests/array/transpose.asy000066400000000000000000000021101265434602500205070ustar00rootroot00000000000000import TestLib; import math; StartTest("transpose"); int n=3; real[][] a=new real[n][n]; real[][] b=new real[n][n]; for(int i=0; i < n; ++i) { for(int j=0; j < n; ++j) { a[i][j]=b[j][i]=rand(); } } bool operator == (real[][] a, real[][] b) { int n=a.length; for(int i=0; i < n; ++i) if(!all(a[i] == b[i])) return false; return true; } bool operator == (real[][][] a, real[][][] b) { int n=a.length; for(int i=0; i < n; ++i) { real[][] ai=a[i]; real[][] bi=b[i]; int m=ai.length; for(int j=0; j < m; ++j) { if(!all(ai[j] == bi[j])) return false; } } return true; } assert(a == transpose(b)); int n=3; real[][][] a=new real[n][n][n]; real[][][] b=new real[n][n][n]; real[][][] c=new real[n][n][n]; real[][][] d=new real[n][n][n]; for(int i=0; i < n; ++i) { for(int j=0; j < n; ++j) { for(int k=0; k < n; ++k) { a[i][j][k]=b[j][i][k]=c[i][k][j]=d[k][j][i]=rand(); } } } assert(a == transpose(b,new int[] {1,0,2})); assert(a == transpose(c,new int[] {0,2,1})); assert(a == transpose(d,new int[] {2,1,0})); EndTest(); asymptote-2.37/tests/bench/000077500000000000000000000000001265434602500157225ustar00rootroot00000000000000asymptote-2.37/tests/bench/6000circles.asy000066400000000000000000000004241265434602500203720ustar00rootroot00000000000000size(0,100); import math; import stats; currentpen=magenta; // A centered random number real crand() {return unitrand()*5;} real r1; pair pcenter; for(int i=0; i < 6000; ++i) { r1 = unitrand()/10; pcenter = ( crand(), crand()); Draw(circle(pcenter,r1)); } asymptote-2.37/tests/frames/000077500000000000000000000000001265434602500161205ustar00rootroot00000000000000asymptote-2.37/tests/frames/loop.asy000066400000000000000000000042561265434602500176160ustar00rootroot00000000000000import TestLib; StartTest("loop"); int f(); for (int i=0; i<10; ++i) { int x=i; for (int j=0; j<10; ++j) { int y=j; if (i==5 && j==7) { f = new int () { return x*y; }; } } } assert(f()==35); int f(); for (int i=0; i<10; ++i) { int x=i; for (int j=0; j<10; ++j) { int y=j; if (i==5 && j==7) { f = new int () { return i*y; }; } } } assert(f()==70); { int y = 3; int z = 0; for (int i = 0; i < 7; ++i) { ++z; continue; y = 4; } assert(y == 3); assert(z == 7); } { int y = 3; int z = 0; for (int i = 0; i < 7; ++i) { ++z; break; y = 4; } assert(y == 3); assert(z == 1); } { int y = 3; int z = 0; for (int i = 0; i < 7; ++i) { void g() {} ++z; continue; y = 4; } assert(y == 3); assert(z == 7); } { int y = 3; int z = 0; for (int i = 0; i < 7; ++i) { void g() {} ++z; break; y = 4; } assert(y == 3); assert(z == 1); } // While loops { int y = 7; int z = 0; while (z < 10) { ++z; continue; ++y; } assert(z == 10); assert(y == 7); } { int y = 7; int z = 0; while (z < 10) { void g() {} ++z; continue; ++y; } assert(z == 10); assert(y == 7); } { int y = 7; int z = 0; while (z < 10) { ++z; break; ++y; } assert(z == 1); assert(y == 7); } { int y = 7; int z = 0; while (z < 10) { void g() {} ++z; break; ++y; } assert(z == 1); assert(y == 7); } { int y = 7; int z = 0; while (z < 10) { ++z; continue; ++y; } assert(z == 10); assert(y == 7); } // Do loops { int y = 7; int z = 0; do { void g() {} ++z; continue; ++y; } while (z < 10); assert(z == 10); assert(y == 7); } { int y = 7; int z = 0; do { ++z; break; ++y; } while (z < 10); assert(z == 1); assert(y == 7); } { int y = 7; int z = 0; do { void g() {} ++z; break; ++y; } while (z < 10); assert(z == 1); assert(y == 7); } { int x = 456; do { x = 123; } while (false); assert(x == 123); } { int x = 456; do { void g() {} x = 123; } while (false); assert(x == 123); } EndTest(); asymptote-2.37/tests/frames/stat.asy000066400000000000000000000002361265434602500176120ustar00rootroot00000000000000import TestLib; StartTest("stat"); struct T { int x; static void f(T t) { t.x=2; } } T t=new T; assert(t.x==0); T.f(t); assert(t.x==2); EndTest(); asymptote-2.37/tests/frames/stat2.asy000066400000000000000000000003121265434602500176670ustar00rootroot00000000000000import TestLib; StartTest("stat2"); struct T { int x; static void f(T t) { static void g(T t) { t.x=2; } g(t); } } T t=new T; assert(t.x==0); T.f(t); assert(t.x==2); EndTest(); asymptote-2.37/tests/gc/000077500000000000000000000000001265434602500152345ustar00rootroot00000000000000asymptote-2.37/tests/gc/array.asy000066400000000000000000000000761265434602500170730ustar00rootroot00000000000000real[] a; for (int i = 0; i < 1e7; ++i) { a=new real[10]; } asymptote-2.37/tests/gc/file.asy000066400000000000000000000001461265434602500166720ustar00rootroot00000000000000for (int i = 0; i < 1e5; ++i) { file a=output("out/"+(string) i); write(a,i,endl); close(a); } asymptote-2.37/tests/gc/funcall.asy000066400000000000000000000000661265434602500174000ustar00rootroot00000000000000void g() {} for (int i = 0; i < 1e7; ++i) { g(); } asymptote-2.37/tests/gc/guide.asy000066400000000000000000000001011265434602500170370ustar00rootroot00000000000000guide a=(0,0); for (int i = 0; i < 1e7; ++i) { guide b=a--a; } asymptote-2.37/tests/gc/label.asy000066400000000000000000000002101265434602500170220ustar00rootroot00000000000000guide a; for (int i = 0; i < 1e7; ++i) { picture pic; size(pic,10cm,20cm); draw(pic,"a",scale(2)*(0,0)--(1,1)); shipout(pic); } asymptote-2.37/tests/gc/path.asy000066400000000000000000000001741265434602500167100ustar00rootroot00000000000000guide a; for (int i = 0; i < 1e7; ++i) { // guide a=a--(1.0,2.0); path p=(1.0,2.0); path q=(3.0,4.0); path a=p--q; } asymptote-2.37/tests/gc/pen.asy000066400000000000000000000001101265434602500165240ustar00rootroot00000000000000for (int i = 0; i < 1e7; ++i) { pen p = linetype(new real[] {1,2}); } asymptote-2.37/tests/gc/shipout.asy000066400000000000000000000002721265434602500174460ustar00rootroot00000000000000guide a; for (int i = 0; i < 1e7; ++i) { picture pic; size(pic,10cm,20cm); path p=(1.0,2.0); path q=(3.0,4.0); path a=p..q..(3,5); draw(pic,a,blue+dashed); shipout(pic); } asymptote-2.37/tests/gc/string.asy000066400000000000000000000001151265434602500172550ustar00rootroot00000000000000string a="abc"; for (int i = 0; i < 1e7; ++i) { "a"+"b"; a=reverse(a); } asymptote-2.37/tests/gc/struct.asy000066400000000000000000000001721265434602500172760ustar00rootroot00000000000000for (int i = 0; i < 1e7; ++i) { picture pic; unitsize(pic, 0.02mm, 0.04mm); draw(pic,unitcircle); shipout(pic); } asymptote-2.37/tests/gc/transform.asy000066400000000000000000000001061265434602500177620ustar00rootroot00000000000000path p=unitsquare; for (int i = 0; i < 1e7; ++i) { scale(2.0)*p; } asymptote-2.37/tests/gs/000077500000000000000000000000001265434602500152545ustar00rootroot00000000000000asymptote-2.37/tests/gs/ghostscript.asy000066400000000000000000000003411265434602500203410ustar00rootroot00000000000000import TestLib; StartTest("Ghostscript"); bool uptodate=texpath("A").length != 0; if(!uptodate) { write(); write(); write("Please install Ghostscript version 9.14 or later."); write(); } assert(uptodate); EndTest(); asymptote-2.37/tests/gsl/000077500000000000000000000000001265434602500154305ustar00rootroot00000000000000asymptote-2.37/tests/gsl/random.asy000066400000000000000000000272031265434602500174320ustar00rootroot00000000000000import TestLib; import gsl; StartTest("random number generators"); rng_init(); assert(rng_min() == 0); assert(rng_max() == 4294967295); assert(rng_get() == 4293858116); rng_init("taus2"); assert(rng_min() == 0); assert(rng_max() == 4294967295); assert(rng_get() == 802792108); rng_init("gfsr4"); assert(rng_min() == 0); assert(rng_max() == 4294967295); assert(rng_get() == 2901276280); string[] list = rng_list(); for(string name: list) { rng_init(name); rng_min(); rng_max(); rng_get(); } assert(list.length >= 62); rng_init(); rng_set(1); assert(rng_get() == 1791095845); rng_set(1); assert(rng_get() == 1791095845); EndTest(); StartTest("Bernoulli distribution"); assert(close(pdf_bernoulli(0,0.3), 0.7)); assert(close(pdf_bernoulli(1,0.3), 0.3)); //rng_init(); //assert(rng_bernoulli(0.3) == 0); EndTest(); StartTest("beta distribution"); assert(close(cdf_beta_P(0.3,5,5), 0.09880866)); assert(close(cdf_beta_Q(0.3,5,5) + cdf_beta_P(0.3,5,5), 1)); assert(close(cdf_beta_Pinv(cdf_beta_P(0.3,5,5),5,5), 0.3)); assert(close(cdf_beta_Qinv(cdf_beta_Q(0.3,5,5),5,5), 0.3)); assert(close(pdf_beta(0.3,5,5), 1.2252303)); //rng_init(); //assert(close(rng_beta(5,5), 0.533021338130471)); EndTest(); StartTest("binomial distribution"); assert(close(cdf_binomial_P(5,0.3,10), 0.9526510126)); assert(close(cdf_binomial_P(5,0.3,10) + cdf_binomial_Q(5,0.3,10), 1)); assert(close(pdf_binomial(5,0.3,10), 0.1029193452)); //rng_init(); //assert(rng_binomial(0.3,10) == 8); EndTest(); StartTest("bivariate Gaussian distribution"); assert(close(pdf_bivariate_gaussian((1,1),(0,2),(4,6),0.5), 0.00675758392382108)); //rng_init(); //pair z = (-0.260388644979556,2.50057001628669); //pair r = rng_bivariate_gaussian((0,2),(4,6),0.5); //assert(close(length(r - z), 0)); EndTest(); StartTest("cauchy distribution"); assert(close(cdf_cauchy_P(1,3), 0.602416382349567)); assert(close(cdf_cauchy_P(1,3) + cdf_cauchy_Q(1,3), 1)); assert(close(cdf_cauchy_Pinv(cdf_cauchy_P(1,3),3), 1)); assert(close(cdf_cauchy_Qinv(cdf_cauchy_Q(1,3),3), 1)); assert(close(pdf_cauchy(1,3), 0.0954929658551372)); //rng_init(); //assert(close(rng_cauchy(3), -0.0024339597467863)); EndTest(); StartTest("chi-squared distribution"); assert(close(cdf_chisq_P(4,6), 0.323323583816936)); assert(close(cdf_chisq_P(4,6) + cdf_chisq_Q(4, 6), 1)); assert(close(cdf_chisq_Pinv(cdf_chisq_P(4,6),6), 4)); assert(close(cdf_chisq_Qinv(cdf_chisq_Q(4,6),6), 4)); assert(close(pdf_chisq(4,6), 0.135335283236613)); //rng_init(); //assert(close(rng_chisq(6), 8.24171826270279)); EndTest(); StartTest("Dirichlet distribution"); real[] alpha = {1,2,3,4}; real[] theta = {0.1,0.2,0.3,0.4}; assert(close(pdf_dirichlet(alpha,theta), 34.83648)); //rng_init(); //real[] z = {0.124480735441317, // 0.191823537067349, // 0.460543885448264, // 0.22315184204307}; //real[] r = rng_dirichlet(alpha); //assert(close(norm(r - z), 0)); EndTest(); StartTest("exponential distribution"); assert(close(cdf_exponential_P(2,3), 0.486582880967408)); assert(close(cdf_exponential_P(2,3) + cdf_exponential_Q(2,3), 1)); assert(close(cdf_exponential_Pinv(cdf_exponential_P(2,3),3), 2)); assert(close(cdf_exponential_Qinv(cdf_exponential_Q(2,3),3), 2)); assert(close(pdf_exponential(2,3), 0.171139039677531)); //rng_init(); //assert(close(rng_exponential(3), 24.7847346491112)); EndTest(); StartTest("exponential power distribution"); assert(close(cdf_exppow_P(2,3,2), 0.82711070692442)); assert(close(cdf_exppow_P(2,3,2) + cdf_exppow_Q(2,3,2), 1)); assert(close(pdf_exppow(2,3,2), 0.120582432109095)); //rng_init(); //assert(close(rng_exppow(3,2), 0.284084267783339)); EndTest(); StartTest("F-distribution"); assert(close(cdf_fdist_P(1,5,4), 0.485657196759213)); assert(close(cdf_fdist_P(1,5,4) + cdf_fdist_Q(1,5,4), 1)); //rng_init(); //assert(close(rng_fdist(5,4), 1.20570928490019)); EndTest(); StartTest("flat (uniform) distribution"); assert(close(cdf_flat_P(2,0,5), 0.4)); assert(close(cdf_flat_P(2,0,5) + cdf_flat_Q(2,0,5), 1)); assert(close(cdf_flat_Pinv(cdf_flat_P(2,0,5),0,5), 2)); assert(close(cdf_flat_Qinv(cdf_flat_Q(2,0,5),0,5), 2)); assert(close(pdf_flat(2,0,5), 0.2)); //rng_init(); //assert(close(rng_flat(0,5), 4.99870874453336)); EndTest(); StartTest("Gamma-distribution"); assert(close(cdf_gamma_P(6,5,1), 0.71494349968337)); assert(close(cdf_gamma_P(6,5,1) + cdf_gamma_Q(6,5,1), 1)); assert(close(cdf_gamma_Pinv(cdf_gamma_P(6,5,1),5,1), 6)); assert(close(cdf_gamma_Qinv(cdf_gamma_Q(6,5,1),5,1), 6)); assert(close(pdf_gamma(6,5,1), 0.133852617539983)); //rng_init(); //assert(close(rng_gamma(5,1), 6.52166444209317)); //assert(close(rng_gamma(5,1,"mt"), 5.71361391461836)); //assert(close(rng_gamma(5,1,"knuth"), 1.53054227085541)); EndTest(); StartTest("Gaussian distribution"); assert(close(cdf_gaussian_P(1,0,1), 0.841344746068543)); assert(close(cdf_gaussian_P(1,0,1) + cdf_gaussian_Q(1,0,1), 1)); assert(close(cdf_gaussian_Pinv(cdf_gaussian_P(1,0,1),0,1), 1)); assert(close(cdf_gaussian_Qinv(cdf_gaussian_Q(1,0,1),0,1), 1)); assert(close(pdf_gaussian(1,0,1), 0.241970724519143)); //rng_init(); //assert(close(rng_gaussian(0,1), 0.133918608118676)); //assert(close(rng_gaussian(1,2,"ziggurat"), 1.90467233084303)); //assert(close(rng_gaussian(1,2,"ratio"), 4.04779517509342)); //assert(close(rng_gaussian(1,2,"polar"), 1.54245166575101)); EndTest(); StartTest("Gaussian tail distribution"); assert(close(pdf_gaussian_tail(2,1,1), 0.34030367841782)); //rng_init(); //assert(close(rng_gaussian_tail(1,1), 1.0528474462339)); EndTest(); StartTest("geometric distribution"); assert(close(cdf_geometric_P(6,0.1), 0.468559)); assert(close(cdf_geometric_P(6,0.1) + cdf_geometric_Q(6,0.1), 1)); assert(close(pdf_geometric(6,0.1), 0.059049)); //rng_init(); //assert(rng_geometric(0.1) == 1); EndTest(); StartTest("Gumbel1 distribution"); assert(close(cdf_gumbel1_P(1,3,8), 0.671462877871127)); assert(close(cdf_gumbel1_P(1,3,8) + cdf_gumbel1_Q(1,3,8), 1)); assert(close(cdf_gumbel1_Pinv(cdf_gumbel1_P(1,3,8),3,8), 1)); assert(close(cdf_gumbel1_Qinv(cdf_gumbel1_Q(1,3,8),3,8), 1)); assert(close(pdf_gumbel1(1,3,8), 0.80232403696926)); //rng_init(); //assert(close(rng_gumbel1(3,8), 3.44696353953564)); EndTest(); StartTest("Gumbel2 distribution"); assert(close(cdf_gumbel2_P(2,2,3), 0.472366552741015)); assert(close(cdf_gumbel2_P(2,2,3) + cdf_gumbel2_Q(2,2,3), 1)); assert(close(cdf_gumbel2_Pinv(cdf_gumbel2_P(2,2,3),2,3), 2)); assert(close(cdf_gumbel2_Qinv(cdf_gumbel2_Q(2,2,3),2,3), 2)); assert(close(pdf_gumbel2(2,2,3), 0.354274914555761)); //rng_init(); //assert(close(rng_gumbel2(2,3), 107.773379309453)); EndTest(); StartTest("hypergeometric distribution"); assert(close(cdf_hypergeometric_P(4,10,10,8), 0.675041676589664)); assert(close(cdf_hypergeometric_P(4,10,10,8) + cdf_hypergeometric_Q(4,10,10,8), 1)); assert(close(pdf_hypergeometric(4,10,10,8), 0.350083353179329)); //rng_init(); //assert(rng_hypergeometric(10,10,8) == 3); EndTest(); StartTest("Laplace distribution"); assert(close(cdf_laplace_P(1,2), 0.696734670143683)); assert(close(cdf_laplace_P(1,2) + cdf_laplace_Q(1,2), 1)); assert(close(cdf_laplace_Pinv(cdf_laplace_P(1,2),2), 1)); assert(close(cdf_laplace_Qinv(cdf_laplace_Q(1,2),2), 1)); assert(close(pdf_laplace(1,2), 0.151632664928158)); //rng_init(); //assert(close(rng_laplace(2), 0.00103327123971616)); EndTest(); StartTest("Landau distribution"); assert(close(pdf_landau(1), 0.145206637130862)); //rng_init(); //assert(close(rng_landau(), 3880.0374262546)); EndTest(); //StartTest("Levy stable distribution"); //rng_init(); //assert(close(rng_levy(1,1,0), 1232.55941432972)); //assert(close(rng_levy(1,1,1), -0.13781830409645)); //EndTest(); StartTest("logistic distribution"); assert(close(cdf_logistic_P(1,2), 0.622459331201855)); assert(close(cdf_logistic_P(1,2) + cdf_logistic_Q(1,2), 1)); assert(close(cdf_logistic_Pinv(cdf_logistic_P(1,2),2), 1)); assert(close(cdf_logistic_Qinv(cdf_logistic_Q(1,2),2), 1)); assert(close(pdf_logistic(1,2), 0.117501856100797)); //rng_init(); //assert(close(rng_logistic(2), 16.522639863849)); EndTest(); StartTest("lognormal distribution"); assert(close(cdf_lognormal_P(6,2,1), 0.417520581602749)); assert(close(cdf_lognormal_P(6,2,1) + cdf_lognormal_Q(6,2,1), 1)); assert(close(cdf_lognormal_Pinv(cdf_lognormal_P(6,2,1),2,1), 6)); assert(close(cdf_lognormal_Qinv(cdf_lognormal_Q(6,2,1),2,1), 6)); assert(close(pdf_lognormal(6,2,1), 0.0650642483079156)); //rng_init(); //assert(close(rng_lognormal(2,1), 6.92337133931968)); EndTest(); StartTest("multinomial distribution"); real[] p = {0.1,0.2,0.3,0.4}; int[] n = {1,2,3,4}; assert(close(pdf_multinomial(p,n), 0.03483648)); //rng_init(); //int[] r = {5, 0, 1, 4}; //assert(all(rng_multinomial(10,p) == r)); EndTest(); StartTest("negative binomial distribution"); assert(close(cdf_negative_binomial_P(6,0.5,10), 0.227249145507813)); assert(close(cdf_negative_binomial_P(6,0.5,10) + cdf_negative_binomial_Q(6,0.5,10), 1)); assert(close(pdf_negative_binomial(6,0.5,10), 0.076370239257812)); //rng_init(); //assert(rng_negative_binomial(0.5,10) == 15); EndTest(); StartTest("Pareto distribution"); assert(close(cdf_pareto_P(4,2,2), 0.75)); assert(close(cdf_pareto_P(4,2,2) + cdf_pareto_Q(4,2,2), 1)); assert(close(cdf_pareto_Pinv(cdf_pareto_P(4,2,2),2,2), 4)); assert(close(cdf_pareto_Qinv(cdf_pareto_Q(4,2,2),2,2), 4)); assert(close(pdf_pareto(4,2,2), 0.125)); //rng_init(); //assert(close(rng_pareto(2,2), 2.00025830112432)); EndTest(); StartTest("Poisson distribution"); assert(close(cdf_poisson_P(5,6), 0.445679641364611)); assert(close(cdf_poisson_P(5,6) + cdf_poisson_Q(5,6), 1)); assert(close(pdf_poisson(5,6), 0.16062314104798)); //rng_init(); //assert(rng_poisson(6) == 8); EndTest(); StartTest("Rayleigh distribution"); assert(close(cdf_rayleigh_P(3,2), 0.67534753264165)); assert(close(cdf_rayleigh_P(3,2) + cdf_rayleigh_Q(3,2), 1)); assert(close(cdf_rayleigh_Pinv(cdf_rayleigh_P(3,2),2), 3)); assert(close(cdf_rayleigh_Qinv(cdf_rayleigh_Q(3,2),2), 3)); assert(close(pdf_rayleigh(3,2), 0.243489350518762)); //rng_init(); //assert(close(rng_rayleigh(2), 0.0454563039310455)); EndTest(); StartTest("Rayleigh tail distribution"); assert(close(pdf_rayleigh_tail(5,4,1), 0.0555449826912115)); //rng_init(); //assert(close(rng_rayleigh_tail(4,1), 4.0000645705903)); EndTest(); //StartTest("spherical distributions"); //rng_init(); //pair z = (-0.617745613497854,-0.786377998804748); //pair r = rng_dir2d(); //assert(close(length(r - z), 0)); //pair z = (0.993748310886084,0.111643605329884); //pair r = rng_dir2d("neumann"); //assert(close(length(r - z), 0)); //pair z = (0.964519203132591,-0.264012701945327); //pair r = rng_dir2d("trig"); //assert(close(length(r - z), 0)); //triple z = (0.849028025629996,0.139162687752509,-0.509691237939527); //triple r = rng_dir3d(); //assert(close(length(r - z), 0)); //real[] z = {0.420990368676528, // -0.626782975357296, // 0.0441585572224004, // -0.0458388920727644, // -0.652578753164271}; //real[] r = rng_dir(5); //assert(close(norm(r - z), 0)); //EndTest(); StartTest("t-distribution"); assert(close(cdf_tdist_P(0.6,2), 0.695283366471236)); assert(close(cdf_tdist_P(0.6,2) + cdf_tdist_Q(0.6,2), 1)); assert(close(cdf_tdist_Pinv(cdf_tdist_P(0.6,2),2), 0.6)); assert(close(cdf_tdist_Qinv(cdf_tdist_Q(0.6,2),2), 0.6)); assert(close(pdf_tdist(0.6,2), 0.275823963942424)); //rng_init(); //assert(close(rng_tdist(2), 0.127201714006725)); EndTest(); StartTest("Weibull distribution"); assert(close(cdf_weibull_P(1,2,2), 0.221199216928595)); assert(close(cdf_weibull_P(1,2,2) + cdf_weibull_Q(1,2,2), 1)); assert(close(cdf_weibull_Pinv(cdf_weibull_P(1,2,2),2,2), 1)); assert(close(cdf_weibull_Qinv(cdf_weibull_Q(1,2,2),2,2), 1)); assert(close(pdf_weibull(1,2,2), 0.389400391535702)); //rng_init(); //assert(close(rng_weibull(2,2), 0.032142460757319)); EndTest(); asymptote-2.37/tests/imp/000077500000000000000000000000001265434602500154305ustar00rootroot00000000000000asymptote-2.37/tests/imp/unravel.asy000066400000000000000000000022711265434602500176240ustar00rootroot00000000000000import TestLib; StartTest("unravel"); { struct A { int x=1, y=2, z=3; int y() { return 7; } } A a=new A; unravel a; assert(x==1); assert(y==2); assert(z==3); assert(y()==7); } { struct A { private int x=1; int y=2, z=3; int y() { return 7; } } int x=5; A a=new A; unravel a; assert(x==5); assert(y==2); assert(z==3); } { struct A { public int x=1; int y=2, z=3; int y() { return 7; } } int z=5; A a=new A; from a unravel x,y; assert(x==1); assert(y==2); assert(z==5); assert(y()==7); } { struct A { public int x=1; int y=2, z=3; int y() { return 7; } } int y=4; int z=5; A a=new A; from a unravel x,y as blah; assert(x==1); assert(y==4); assert(blah==2); assert(z==5); assert(blah()==7); } { struct A { struct B { static int x=4; } } A a=new A; int x=3; from a.B unravel x; assert(x==4); } { struct A { struct B { static int x=4; } } A a=new A; A.B b=new a.B; int x=3; from b unravel x; assert(x==4); } { struct A { static struct B { static int x=4; } } int x=3; from A.B unravel x; assert(x==4); } EndTest(); asymptote-2.37/tests/output/000077500000000000000000000000001265434602500162035ustar00rootroot00000000000000asymptote-2.37/tests/output/Makefile000066400000000000000000000024041265434602500176430ustar00rootroot00000000000000# Automated testing to see if the output of Asymptote scripts changes when the # program is modified. # How to call asy from the tests/output/name.out directory ASY=../../../asy TESTS=$(basename $(wildcard *.asy)) # This command performs the testing on all scripts. diff: $(TESTS:=.diff) # This builds the reference copies of the output using a trusted version of asy ref: $(TESTS:=.ref) $(TESTS:=.ref) $(TESTS:=.out): %: @echo Generating $@ @rm -rf $@ @mkdir $@ @cd $@; \ $(ASY) -keep ../$(basename $@) \ >$(basename $@).stdout 2>$(basename $@).stderr; \ ls >$(basename $@).ls; \ rm -f *.dvi *.pdf *.gif *.jpg *.jpeg *.png # Ignore lines with timestamps of the form hh:mm, since the time changes between # runs. This regex is fairly broad and it may need to be narrowed. $(TESTS:=.diff): %.diff: %.out diff -I "[0-9][0-9]:[0-9][0-9]" -u $(@:.diff=.ref) $(@:.diff=.out) clean: rm -rf *.out # The reference copies should only be built at the start, or when the behaviour # of Asymptote is intentionally changed, so they are not usually removed by make # clean. veryclean: clean rm -rf *.ref # This tells make to build every dependency from scratch, ignoring the dates on # files. .PHONY: $(TESTS:=.ref) $(TESTS:=.out) $(TESTS:=.diff) diff ref clean veryclean asymptote-2.37/tests/output/circle.asy000066400000000000000000000000221265434602500201540ustar00rootroot00000000000000draw(unitcircle); asymptote-2.37/tests/output/line.asy000066400000000000000000000000261265434602500176460ustar00rootroot00000000000000draw((0,0)--(100,0)); asymptote-2.37/tests/pic/000077500000000000000000000000001265434602500154165ustar00rootroot00000000000000asymptote-2.37/tests/pic/trans.asy000066400000000000000000000025501265434602500172650ustar00rootroot00000000000000import TestLib; StartTest("trans"); // Ensure the same test each time. srand(3456); pair randompair() { return (unitrand(),unitrand()); } path randombox() { return box(randompair(), randompair()); } // For now, only tests transforms which take axes to axes. transform randomtrans() { return rotate(90 * (rand() % 4)) * shift(unitrand(), unitrand()); } real tolerance = 1e-4; void testpic(int objs, int trans) { path[] pp; picture orig; for (int i = 0; i < objs; ++i) { pp.push(randombox()); fill(orig, pp[i]); } picture pic = orig; transform t = identity(); for (int i = 0; i < trans; ++i) { transform tt = randomtrans(); pic = tt * pic; t = tt * t; } pair m = pic.userMin2(), M = pic.userMax2(); pair pm = min(t * pp), pM = max(t * pp); assert(abs(m-pm) < tolerance); assert(abs(M-pM) < tolerance); } for (int i = 0; i < 100; ++i) testpic(1,1); for (int i = 0; i < 100; ++i) testpic(1,1); for (int i = 0; i < 100; ++i) testpic(3,1); for (int i = 0; i < 100; ++i) testpic(1,2); for (int i = 0; i < 100; ++i) testpic(2,2); for (int i = 0; i < 100; ++i) testpic(3,2); for (int i = 0; i < 100; ++i) testpic(3,4); for (int i = 0; i < 100; ++i) testpic(1,4); for (int i = 0; i < 100; ++i) testpic(2,4); for (int i = 0; i < 100; ++i) testpic(3,4); for (int i = 0; i < 100; ++i) testpic(3,4); EndTest(); asymptote-2.37/tests/string/000077500000000000000000000000001265434602500161515ustar00rootroot00000000000000asymptote-2.37/tests/string/erase.asy000066400000000000000000000003541265434602500177700ustar00rootroot00000000000000import TestLib; StartTest("erase"); string s = "abcdef"; assert(erase(s,2,2) == "abef"); assert(erase(s,-1,2) == "abcdef"); assert(erase(s,7,1) == "abcdef"); assert(erase(s,3,0) == "abcdef"); assert(erase(s,5,2) == "abcde"); EndTest(); asymptote-2.37/tests/string/find.asy000066400000000000000000000002661265434602500176130ustar00rootroot00000000000000import TestLib; StartTest("find"); string s = "abcdefab"; assert(find(s,"cd") == 2); assert(find(s,"cd",3) == -1); assert(find(s,"ab") == 0); assert(find(s,"ab",1) == 6); EndTest(); asymptote-2.37/tests/string/insert.asy000066400000000000000000000001551265434602500201740ustar00rootroot00000000000000import TestLib; StartTest("insert"); string sub = insert("abef",2,"cd"); assert(sub == "abcdef"); EndTest(); asymptote-2.37/tests/string/length.asy000066400000000000000000000002041265434602500201440ustar00rootroot00000000000000import TestLib; StartTest("length"); assert(length("") == 0); assert(length("abc") == 3); assert(length("abcdef") == 6); EndTest(); asymptote-2.37/tests/string/rfind.asy000066400000000000000000000002731265434602500177730ustar00rootroot00000000000000import TestLib; StartTest("rfind"); string s = "abcdefab"; assert(rfind(s,"cd") == 2); assert(rfind(s,"cd",1) == -1); assert(rfind(s,"ab") == 6); assert(rfind(s,"ab",5) == 0); EndTest(); asymptote-2.37/tests/string/substr.asy000066400000000000000000000001661265434602500202140ustar00rootroot00000000000000import TestLib; StartTest("substr"); string s = "abcdef"; string sub = substr(s,2,2); assert(sub == "cd"); EndTest(); asymptote-2.37/tests/types/000077500000000000000000000000001265434602500160075ustar00rootroot00000000000000asymptote-2.37/tests/types/cast.asy000066400000000000000000000002371265434602500174610ustar00rootroot00000000000000import TestLib; StartTest("cast"); struct A { public int x; } A operator cast(int x) { A a=new A; a.x=x; return a; } A a=7; assert(a.x==7); EndTest(); asymptote-2.37/tests/types/constructor.asy000066400000000000000000000145471265434602500211250ustar00rootroot00000000000000import TestLib; StartTest("constructor"); { // Basic usage. {{{1 struct Foo { int x; int y; void operator init() { x=2; y=3; } void operator init(int x, int y=2x) { this.x=x; this.y=y; } void operator init(string s ... int[] vals) { for (int i=0; i= 0; --i, ++j) assert(point(p, j) == (i,i^2)); EndTest(); asymptote-2.37/tests/types/init.asy000066400000000000000000000003401265434602500174650ustar00rootroot00000000000000import TestLib; StartTest("init"); int operator init() { return 7; } int x; assert(x==7); struct A { int x=3; } A a; assert(a!=null); assert(a.x==3); A operator init() { return null; } A aa; assert(aa==null); EndTest(); asymptote-2.37/tests/types/keyword.asy000066400000000000000000000102221265434602500202060ustar00rootroot00000000000000import TestLib; StartTest("keyword"); { int f(int keyword x) { return 2*x; } assert(f(x=17) == 34); } { int f(int keyword x = 10) { return 2*x; } assert(f() == 20); } { int f(int keyword x = 10, int keyword y = 20) { return 2x+y; } assert(f(x=1,y=2) == 4); assert(f(y=1,x=2) == 5); assert(f(x=1) == 22); assert(f(y=7) == 27); assert(f() == 40); } { int f(int keyword x, int keyword y = 20) { return x+y; } assert(f(x=1,y=2) == 3); assert(f(x=1) == 21); } { int f(int keyword x = 10, int keyword y) { return x+y; } assert(f(x=1,y=2) == 3); assert(f(y=2) == 12); } { int f(int keyword x, int keyword y) { return x+y; } assert(f(x=1,y=2) == 3); } { int f(int x, int keyword y) { return 2x+y; } assert(f(x=1,y=2) == 4); assert(f(1,y=2) == 4); assert(f(y=2,1) == 4); assert(f(y=2,x=1) == 4); } { int f(... int[] nums, int keyword r) { return r; } assert(f(r=3) == 3); assert(f(1,r=3) == 3); assert(f(1,2, r=3) == 3); assert(f(1,2,4,5,6, r=3) == 3); assert(f(r=3, 10, 20, 30) == 3); assert(f(4, 5, r=3, 10, 20, 30) == 3); assert(f(4, 5, r=3, 10, 20, 30 ... new int[] {40,50,60}) == 3); assert(f(r=3, 10, 20, 30 ... new int[] {40,50,60}) == 3); assert(f(r=3, 10, 20, 30 ... new int[] {40,50,60}) == 3); assert(f(... new int[] {40,50,60}, r=3) == 3); assert(f(... new int[] {40,50,60}, r=3) == 3); } { int f(... int[] nums, int keyword r=77) { return r; } assert(f(r=3) == 3); assert(f(1,r=3) == 3); assert(f(1,2, r=3) == 3); assert(f(1,2,4,5,6, r=3) == 3); assert(f(r=3, 10, 20, 30) == 3); assert(f(4, 5, r=3, 10, 20, 30) == 3); assert(f(4, 5, r=3, 10, 20, 30 ... new int[] {40,50,60}) == 3); assert(f(r=3, 10, 20, 30 ... new int[] {40,50,60}) == 3); assert(f(r=3, 10, 20, 30 ... new int[] {40,50,60}) == 3); assert(f(... new int[] {40,50,60}, r=3) == 3); assert(f(... new int[] {40,50,60}, r=3) == 3); assert(f() == 77); assert(f(1) == 77); assert(f(1,2) == 77); assert(f(1,2,4,5,6) == 77); assert(f(10, 20, 30) == 77); assert(f(4, 5, 10, 20, 30) == 77); assert(f(4, 5, 10, 20, 30 ... new int[] {40,50,60}) == 77); assert(f(10, 20, 30 ... new int[] {40,50,60}) == 77); assert(f(10, 20, 30 ... new int[] {40,50,60}) == 77); assert(f(... new int[] {40,50,60}) == 77); assert(f(... new int[] {40,50,60}) == 77); } { int f(int x ... int[] nums, int keyword r=77) { return r; } assert(f(345,r=3) == 3); assert(f(345,1,r=3) == 3); assert(f(345,1,2, r=3) == 3); assert(f(345,1,2,4,5,6, r=3) == 3); assert(f(345,r=3, 10, 20, 30) == 3); assert(f(345,4, 5, r=3, 10, 20, 30) == 3); assert(f(345,4, 5, r=3, 10, 20, 30 ... new int[] {40,50,60}) == 3); assert(f(345,r=3, 10, 20, 30 ... new int[] {40,50,60}) == 3); assert(f(345,r=3, 10, 20, 30 ... new int[] {40,50,60}) == 3); assert(f(345 ... new int[] {40,50,60}, r=3) == 3); assert(f(345 ... new int[] {40,50,60}, r=3) == 3); assert(f(345) == 77); assert(f(345,1) == 77); assert(f(345,1,2) == 77); assert(f(345,1,2,4,5,6) == 77); assert(f(345,10, 20, 30) == 77); assert(f(345,4, 5, 10, 20, 30) == 77); assert(f(345,4, 5, 10, 20, 30 ... new int[] {40,50,60}) == 77); assert(f(345,10, 20, 30 ... new int[] {40,50,60}) == 77); assert(f(345,10, 20, 30 ... new int[] {40,50,60}) == 77); assert(f(345 ... new int[] {40,50,60}) == 77); assert(f(345 ... new int[] {40,50,60}) == 77); } { int sqr(int x=7) { return x*x; } int f(int keyword x) = sqr; int g(int keyword x=666) = sqr; assert(f(x=5) == 25); assert(g(x=5) == 25); assert(g() == 49); } { int sqr(int n=7) { return n*n; } int f(int keyword x) = sqr; int g(int keyword x=666) = sqr; assert(f(x=5) == 25); assert(g(x=5) == 25); assert(g() == 49); } { int sqr(int keyword x=7) { return x*x; } int f(int x) = sqr; int g(int x=666) = sqr; assert(f(x=5) == 25); assert(g(x=5) == 25); assert(f(5) == 25); assert(g(5) == 25); assert(g() == 49); } { int sqr(int keyword n=7) { return n*n; } int f(int x) = sqr; int g(int x=666) = sqr; assert(f(x=5) == 25); assert(g(x=5) == 25); assert(f(5) == 25); assert(g(5) == 25); assert(g() == 49); } EndTest(); asymptote-2.37/tests/types/order.asy000066400000000000000000000077501265434602500176510ustar00rootroot00000000000000import TestLib; StartTest("order"); // Ordering tests. int counter = 0; int step(int n) { ++counter; assert(counter == n); return n; } int[] stepArray(int n) { return new int[] {step(n)}; } void reset() { counter = 0; } { reset(); assert(step(1) + step(2) == step(3)); step(4); } { reset(); assert(step(1) == 0 || step(2) == 2); step(3); } { reset(); step(1) == 0 && step(999) == step(456); step(2); } { reset(); int x = step(1), y = step(2); step(3); int x = step(4), y = step(5); step(6); } { void f(int x, int y) {} reset(); f(step(1), step(2)); step(3); reset(); f(x=step(1), y=step(2)); step(3); reset(); f(y=step(1), x=step(2)); step(3); reset(); f(x=step(1), step(2)); step(3); reset(); f(y=step(1), step(2)); step(3); reset(); f(step(1), x=step(2)); step(3); reset(); f(step(1), y=step(2)); step(3); } { void f(int x, int y ... int[] z) {} reset(); f(step(1), step(2)); step(3); reset(); f(x=step(1), y=step(2)); step(3); reset(); f(y=step(1), x=step(2)); step(3); reset(); f(x=step(1), step(2)); step(3); reset(); f(y=step(1), step(2)); step(3); reset(); f(step(1), x=step(2)); step(3); reset(); f(step(1), y=step(2)); step(3); reset(); f(step(1), step(2), step(3)); step(4); reset(); f(x=step(1), y=step(2), step(3)); step(4); reset(); f(y=step(1), x=step(2), step(3)); step(4); reset(); f(x=step(1), step(2), step(3)); step(4); reset(); f(y=step(1), step(2), step(3)); step(4); reset(); f(step(1), x=step(2), step(3)); step(4); reset(); f(step(1), y=step(2), step(3)); step(4); reset(); f(step(1), step(2), step(3), step(4)); step(5); reset(); f(x=step(1), y=step(2), step(3), step(4)); step(5); reset(); f(y=step(1), x=step(2), step(3), step(4)); step(5); reset(); f(x=step(1), step(2), step(3), step(4)); step(5); reset(); f(y=step(1), step(2), step(3), step(4)); step(5); reset(); f(step(1), x=step(2), step(3), step(4)); step(5); reset(); f(step(1), y=step(2), step(3), step(4)); step(5); reset(); f(step(1), step(2), step(3)); step(4); reset(); f(x=step(1), step(2), y=step(3)); step(4); reset(); f(y=step(1), step(2), x=step(3)); step(4); reset(); f(x=step(1), step(2), step(3)); step(4); reset(); f(y=step(1), step(2), step(3)); step(4); reset(); f(step(1), step(2), x=step(3)); step(4); reset(); f(step(1), step(2), y=step(3)); step(4); reset(); f(step(1), step(2), step(3), step(4)); step(5); reset(); f(x=step(1), step(2), y=step(3), step(4)); step(5); reset(); f(y=step(1), step(2), x=step(3), step(4)); step(5); reset(); f(x=step(1), step(2), step(3), step(4)); step(5); reset(); f(y=step(1), step(2), step(3), step(4)); step(5); reset(); f(step(1), step(2), x=step(3), step(4)); step(5); reset(); f(step(1), step(2), y=step(3), step(4)); step(5); reset(); f(step(1), step(2), step(3), step(4)... stepArray(5)); step(6); reset(); f(x=step(1), step(2), y=step(3), step(4)... stepArray(5)); step(6); reset(); f(y=step(1), step(2), x=step(3), step(4)... stepArray(5)); step(6); reset(); f(x=step(1), step(2), step(3), step(4)... stepArray(5)); step(6); reset(); f(y=step(1), step(2), step(3), step(4)... stepArray(5)); step(6); reset(); f(step(1), step(2), x=step(3), step(4)... stepArray(5)); step(6); reset(); f(step(1), step(2), y=step(3), step(4)... stepArray(5)); step(6); reset(); f(...stepArray(1), x=step(2), y=step(3)); step(4); reset(); f(...stepArray(1), y=step(2), x=step(3)); step(4); reset(); f(step(1)...stepArray(2), x=step(3), y=step(4)); step(5); reset(); f(step(1)...stepArray(2), y=step(3), x=step(4)); step(5); reset(); f(step(1),step(2)...stepArray(3), y=step(4), x=step(5)); step(6); reset(); f(step(1),step(2)...stepArray(3), y=step(4), x=step(5)); step(6); reset(); f(step(1),step(2),x=step(3)...stepArray(4), y=step(5)); step(6); reset(); f(step(1),step(2),x=step(3)...stepArray(4), y=step(5)); step(6); } // TODO: Add packing vs. casting tests. EndTest(); asymptote-2.37/tests/types/resolve.asy000066400000000000000000000052531265434602500202110ustar00rootroot00000000000000import TestLib; StartTest("resolve"); struct A {} struct B {} struct C {} int f(B, real) { return 1; } int f(C, int) { return 2; } B operator cast(A) { return new B; } assert(f(new A, 3) == 1); C operator cast(A) { return new C; } assert(f(new A, 3) == 2); int givex(int x, int y) { return x; } assert(givex(2002,3) == 2002); assert(givex(2002,2002) == 2002); assert(givex(-2005,2005) == -2005); assert(givex(x=-77,205) == -77); assert(givex(-77,y=205) == -77); assert(givex(-77,x=205) == 205); assert(givex(x=-77,y=205) == -77); assert(givex(y=-77,x=205) == 205); int g(real x, real y) { return 7; } int g(int x, real y) { return 8; } assert(g(4, 4) == 8); assert(g(4, 4.4) == 8); assert(g(4.4, 4) == 7); assert(g(4.4, 4.4) == 7); assert(g(x=4, y=4) == 8); assert(g(x=4, y=4.4) == 8); assert(g(x=4.4, y=4) == 7); assert(g(x=4.4, y=4.4) == 7); assert(g(x=4, 4) == 8); assert(g(x=4, 4.4) == 8); assert(g(x=4.4, 4) == 7); assert(g(x=4.4, 4.4) == 7); assert(g(4, y=4) == 8); assert(g(4, y=4.4) == 8); assert(g(4.4, y=4) == 7); assert(g(4.4, y=4.4) == 7); assert(g(y=4, x=4) == 8); assert(g(y=4, x=4.4) == 7); assert(g(y=4.4, x=4) == 8); assert(g(y=4.4, x=4.4) == 7); assert(g(4, x=4) == 8); assert(g(4, x=4.4) == 7); assert(g(4.4, x=4) == 8); assert(g(4.4, x=4.4) == 7); assert(g(y=4, 4) == 8); assert(g(y=4, 4.4) == 7); assert(g(y=4.4, 4) == 8); assert(g(y=4.4, 4.4) == 7); // Test exact matching over casting. { void f(int x, real y=0.0, int z=0) { assert(x==1); assert(y==2.0); assert(z==0); } f(1,2); } { void f() { assert(false); } void f(int x, real y=0.0, int z=0) { assert(x==1); assert(y==2.0); assert(z==0); } f(1,2); } { void f() { assert(false); } void f(int x, int y) { assert(x==1); assert(y==2); } void f(int x, real y=0.0, int z=0) { assert(false); } f(1,2); } { struct A {} struct B {} struct C {} void f(B); void g(B); // Should resolve to void (B). assert(f == g); assert(g == f); assert(!(f != g)); assert(!(g != f)); } { struct A {} struct B {} struct C {} void f(A), f(B); void g(B), g(C); // Should resolve to void (B). assert(f == g); assert(g == f); assert(!(f != g)); assert(!(g != f)); } { struct A {} struct B {} struct C {} void f(B); void g(B), g(C); // Should resolve to void (B). assert(f == g); assert(g == f); assert(!(f != g)); assert(!(g != f)); } { struct A {} struct B {} struct C {} void f(B); void g(B), g(C); // Should resolve to void (B). assert(f == g); assert(g == f); assert(!(f != g)); assert(!(g != f)); } { void foo() {} assert((foo == null ? 5 : 8) == 8); } // TODO: Add packing vs. casting tests. EndTest(); asymptote-2.37/tests/types/shadow.asy000066400000000000000000000004641265434602500200160ustar00rootroot00000000000000import TestLib; StartTest("shadow"); int x = 1; int getX() { return x; } void setX(int value) { x=value; } // Shadow x with another int, but x should still be in memory. int x = 2; assert(x==2); assert(getX()==1); x = 4; assert(x==4); assert(getX()==1); setX(7); assert(x==4); assert(getX()==7); EndTest(); asymptote-2.37/tests/types/spec.asy000066400000000000000000000024631265434602500174640ustar00rootroot00000000000000import TestLib; StartTest("spec"); // Test if the cycle keyword can be used in different contexts. { int operator cast(cycleToken) { return 55; } int x=cycle; assert(x==55); } // Test the tensionSpecifier type. { tensionSpecifier operator ..(string a, tensionSpecifier t, string b) { return t; } tensionSpecifier t="hello" .. tension 2 .. "joe"; assert(t.out==2); assert(t.in==2); assert(t.atLeast==false); tensionSpecifier t="hello" .. tension 3 and 2 .. "joe"; assert(t.out==3); assert(t.in==2); assert(t.atLeast==false); tensionSpecifier t="hello" .. tension atleast 7 .. "joe"; assert(t.out==7); assert(t.in==7); assert(t.atLeast==true); tensionSpecifier t="hello" .. tension atleast 3 and 2 .. "joe"; assert(t.out==3); assert(t.in==2); assert(t.atLeast==true); } // Test the curlSpecifier type. { curlSpecifier operator ..(curlSpecifier spec, string b) { return spec; } curlSpecifier operator ..(string a, curlSpecifier spec) { return spec; } curlSpecifier operator ..(string a, curlSpecifier spec, string b) { return spec; } curlSpecifier spec="hello"{curl 3}.."joe"; assert(spec.value==3); assert(spec.side==JOIN_OUT); curlSpecifier spec="hello"..{curl 7}"joe"; assert(spec.value==7); assert(spec.side==JOIN_IN); } EndTest(); asymptote-2.37/tests/types/var.asy000066400000000000000000000022451265434602500173200ustar00rootroot00000000000000import TestLib; StartTest("var"); var x = 4; assert(x + x == 8); assert(x^2 == 16); assert((real)x == 4.0); var y = x; assert(y + y == 8); assert(x + y == 8); assert(y^2 == 16); assert((real)y == 4.0); var z = 2 * x; assert(z + z == 16); assert(x + z == 12); assert(z^2 == 64); assert((real)z == 8.0); var t = sin(0); assert(t == 0.0); assert(2t == 0.0); struct A { int x; }; A a; a.x = 3; var b = a; assert(a == b); assert(a.x == 3); A func(int x, int y) { return a; } var c = func(2,3); assert(a == b); assert(a.x == 3); int f(int x) { return x*x; } var g = f; assert(g == f); for (int i = 0; i < 100; ++i) assert(g(i) == i*i); /* var can be replaced with a normal type. */ { typedef int var; var x; assert(x == 0); var v = 14; assert(v == 14); } { struct var { int x; } var n = null; assert(n == null); var a; assert(a != null); assert(a.x == 0); a.x = 11; assert(a.x == 11); } // Test for single evaluation of the initializer. { int x = 3; assert(x == 3); var y = ++x; assert(x == 4); assert(y == 4); } { int f = 4, f() = null; var x = (int)f; assert(x == 4); } EndTest(); asymptote-2.37/texfile.cc000066400000000000000000000473251265434602500154630ustar00rootroot00000000000000/***** * texfile.cc * John Bowman 2003/03/14 * * Encapsulates the writing of commands to a TeX file. *****/ #include #include #include "texfile.h" #include "errormsg.h" using std::ofstream; using settings::getSetting; using vm::array; using vm::read; namespace camp { texfile::texfile(const string& texname, const bbox& box, bool pipe) : box(box) { texengine=getSetting("tex"); inlinetex=getSetting("inlinetex"); Hoffset=inlinetex ? box.right : box.left; out=new ofstream(texname.c_str()); if(!out || !*out) reportError("Cannot write to "+texname); out->setf(std::ios::fixed); out->precision(6); texdocumentclass(*out,pipe); resetpen(); level=0; } texfile::~texfile() { if(out) { delete out; out=NULL; } } void texfile::miniprologue() { texpreamble(*out,processData().TeXpreamble,false); if(settings::latex(texengine)) { *out << "\\pagestyle{empty}" << newl << "\\textheight=2048pt" << newl << "\\textwidth=2048pt" << newl << "\\begin{document}" << newl; latexfontencoding(*out); } else if(settings::context(texengine)) { *out << "\\setuppagenumbering[location=]" << newl << "\\usetypescript[modern]" << newl << "\\starttext\\hbox{%" << newl; } else *out << "\\nopagenumbers" << newl; } void texfile::prologue() { if(inlinetex) { string prename=buildname(settings::outname(),"pre"); std::ofstream *outpreamble=new std::ofstream(prename.c_str()); texpreamble(*outpreamble,processData().TeXpreamble); outpreamble->close(); } texdefines(*out,processData().TeXpreamble,false); double width=box.right-box.left; double height=box.top-box.bottom; if(!inlinetex) { if(settings::context(texengine)) { *out << "\\definepapersize[asy][width=" << width << "bp,height=" << height << "bp]" << newl << "\\setuppapersize[asy][asy]" << newl; } else if(settings::pdf(texengine)) { double voffset=0.0; if(settings::latex(texengine)) { if(height < 12.0) voffset=height-12.0; } else if(height < 10.0) voffset=height-10.0; if(width > 0) *out << "\\pdfpagewidth=" << width << "bp" << newl; *out << "\\ifx\\pdfhorigin\\undefined" << newl << "\\hoffset=-1in" << newl << "\\voffset=" << voffset-72.0 << "bp" << newl; if(height > 0) *out << "\\pdfpageheight=" << height << "bp" << newl; *out << "\\else" << newl << "\\pdfhorigin=0bp" << newl << "\\pdfvorigin=" << voffset << "bp" << newl; if(height > 0) *out << "\\pdfpageheight=" << height << "bp" << newl; *out << "\\fi" << newl; } } if(settings::xe(texengine) && !inlinetex) *out << "\\usepackage{everypage}%" << newl; if(settings::latex(texengine)) { *out << "\\setlength{\\unitlength}{1pt}" << newl; if(!inlinetex) { *out << "\\pagestyle{empty}" << newl << "\\textheight=" << height+18.0 << "bp" << newl << "\\textwidth=" << width+18.0 << "bp" << newl; if(settings::pdf(texengine)) *out << "\\oddsidemargin=-17.61pt" << newl << "\\evensidemargin=\\oddsidemargin" << newl << "\\topmargin=-37.01pt" << newl; *out << "\\begin{document}" << newl; } latexfontencoding(*out); } else { if(!inlinetex) { if(settings::context(texengine)) { *out << "\\setuplayout[" << "backspace=0pt,topspace=0pt," << "header=0pt,headerdistance=0pt,footer=0pt]" << newl << "\\setuppagenumbering[location=]" << endl << "\\usetypescript[modern]" << newl << "\\starttext\\hbox{%" << newl; } else { *out << "\\footline={}" << newl; if(settings::pdf(texengine)) { *out << "\\hoffset=-20pt" << newl << "\\voffset=0pt" << newl; } else { *out << "\\hoffset=36.6pt" << newl << "\\voffset=54.0pt" << newl; } } } } beginpage(); } void texfile::beginlayer(const string& psname, bool postscript) { if(box.right > box.left && box.top > box.bottom) { if(postscript) { if(settings::context(texengine)) *out << "\\externalfigure[" << psname << "]%" << newl; else { *out << "{\\catcode`\"=12%" << newl << "\\includegraphics"; bool pdf=settings::pdf(texengine); string quote; string name=stripExt(psname); if(inlinetex) { size_t pos=name.rfind("-"); if(pos < string::npos) name="\\ASYprefix\\jobname"+name.substr(pos); } else { name=pdf ? stripExt(psname) : psname; if(stripDir(name) != name) quote="\""; } if(pdf) *out << "{" << quote << name << quote << ".pdf}%" << newl; else { *out << "[bb=" << box.left << " " << box.bottom << " " << box.right << " " << box.top << "]" << "{" << quote << name << quote << "}%" << newl; } *out << "}%" << newl; } if(!inlinetex) *out << "\\kern " << (box.left-box.right)*ps2tex << "pt%" << newl; } else { *out << "\\leavevmode\\vbox to " << (box.top-box.bottom)*ps2tex << "pt{}%" << newl; if(inlinetex) *out << "\\kern " << (box.right-box.left)*ps2tex << "pt%" << newl; } } } void texfile::endlayer() { if(inlinetex && (box.right > box.left && box.top > box.bottom)) *out << "\\kern " << (box.left-box.right)*ps2tex << "pt%" << newl; } void texfile::writeshifted(path p, bool newPath) { write(p.transformed(shift(pair(-Hoffset,-box.bottom))),newPath); } void texfile::setlatexcolor(pen p) { if(p.cmyk() && (!lastpen.cmyk() || (p.cyan() != lastpen.cyan() || p.magenta() != lastpen.magenta() || p.yellow() != lastpen.yellow() || p.black() != lastpen.black()))) { *out << "\\definecolor{ASYcolor}{cmyk}{" << p.cyan() << "," << p.magenta() << "," << p.yellow() << "," << p.black() << "}\\color{ASYcolor}" << newl; } else if(p.rgb() && (!lastpen.rgb() || (p.red() != lastpen.red() || p.green() != lastpen.green() || p.blue() != lastpen.blue()))) { *out << "\\definecolor{ASYcolor}{rgb}{" << p.red() << "," << p.green() << "," << p.blue() << "}\\color{ASYcolor}" << newl; } else if(p.grayscale() && (!lastpen.grayscale() || p.gray() != lastpen.gray())) { *out << "\\definecolor{ASYcolor}{gray}{" << p.gray() << "}\\color{ASYcolor}" << newl; } } void texfile::setfont(pen p) { bool latex=settings::latex(texengine); if(latex) setlatexfont(*out,p,lastpen); settexfont(*out,p,lastpen,latex); lastpen.setfont(p); } void texfile::setpen(pen p) { bool latex=settings::latex(texengine); p.convert(); if(p == lastpen) return; if(latex) setlatexcolor(p); else setcolor(p,settings::beginspecial(texengine),settings::endspecial()); setfont(p); } void texfile::beginpicture(const bbox& b) { verbatim(settings::beginpicture(texengine)); if(!settings::context(texengine)) { verbatim("("); double width=b.right-b.left; double height=b.top-b.bottom; write(width*ps2tex); verbatim(","); write(height*ps2tex); verbatim(")"); } verbatimline("%"); } void texfile::endpicture(const bbox& b) { verbatimline(settings::endpicture(texengine)); verbatim("\\kern"); double width=b.right-b.left; write(-width*ps2tex); verbatimline("pt%"); } void texfile::gsave(bool) { *out << settings::beginspecial(texengine); psfile::gsave(true); *out << settings::endspecial() << newl; } void texfile::grestore(bool) { *out << settings::beginspecial(texengine); psfile::grestore(true); *out << settings::endspecial() << newl; } void texfile::beginspecial() { *out << settings::beginspecial(texengine); } void texfile::endspecial() { *out << settings::endspecial() << newl; } void texfile::beginraw() { *out << "\\ASYraw{" << newl; } void texfile::endraw() { *out << "}%" << newl; } void texfile::put(const string& label, const transform& T, const pair& z, const pair& align) { double sign=settings::pdf(texengine) ? 1.0 : -1.0; if(label.empty()) return; bool trans=!T.isIdentity(); *out << "\\ASYalign"; if(trans) *out << "T"; *out << "(" << (z.getx()-Hoffset)*ps2tex << "," << (z.gety()-box.bottom)*ps2tex << ")(" << align.getx() << "," << align.gety() << ")"; if(trans) *out << "{" << T.getxx() << " " << sign*T.getyx() << " " << sign*T.getxy() << " " << T.getyy() << "}"; *out << "{" << label << "}%" << newl; } void texfile::epilogue(bool pipe) { endpage(); if(settings::latex(texengine)) *out << "\\end{document}" << newl; else if(settings::context(texengine)) *out << "}\\stoptext" << newl; else *out << "\\bye" << newl; out->flush(); } string svgtexfile::nl="{?nl}%\n"; void svgtexfile::beginspecial() { inspecial=true; out->unsetf(std::ios::fixed); *out << "\\catcode`\\#=11%" << newl << "\\special{dvisvgm:raw" << nl; } void svgtexfile::endspecial() { inspecial=false; *out << "}\\catcode`\\#=6%" << newl; out->setf(std::ios::fixed); } void svgtexfile::begintransform() { *out << "" << nl; } void svgtexfile::endtransform() { *out << ""; } void svgtexfile::gsave(bool) { if(clipstack.size() < 1) clipstack.push(0); else clipstack.push(clipcount); *out << "\\special{dvisvgm:raw }%" << newl; pens.push(lastpen); } void svgtexfile::grestore(bool) { if(pens.size() < 1 || clipstack.size() < 1) reportError("grestore without matching gsave"); lastpen=pens.top(); pens.pop(); clipstack.pop(); *out << "\\special{dvisvgm:raw }%" << newl; } void svgtexfile::clippath() { if(clipstack.size() > 0) { size_t count=clipstack.top(); if(count > 0) *out << "clip-path='url(#clip" << count << ")' "; } } void svgtexfile::beginpath() { *out << "" << nl; beginpath(); if(clipstack.size() > 0) clipstack.pop(); clipstack.push(clipcount); } void svgtexfile::endclip0(const pen &p) { *out << "'"; fillrule(p,"clip"); endpath(); *out << "" << nl; } void svgtexfile::endclip(const pen &p) { endclip0(p); endtransform(); endspecial(); } void svgtexfile::fillrule(const pen& p, const string& type) { if(p.Fillrule() != lastpen.Fillrule()) *out << " " << type << "-rule='" << (p.evenodd() ? "evenodd" : "nonzero") << "'"; lastpen.setfillrule(p); } void svgtexfile::color(const pen &p, const string& type) { *out << "' " << type << "='#" << rgbhex(p) << "'"; double opacity=p.opacity(); if(opacity != 1.0) *out << " opacity='" << opacity << "'"; } void svgtexfile::fill(const pen &p) { color(p,"fill"); fillrule(p); endpath(); endtransform(); endspecial(); } void svgtexfile::properties(const pen& p) { if(p.cap() != lastpen.cap()) *out << " stroke-linecap='" << PSCap[p.cap()] << "'"; if(p.join() != lastpen.join()) *out << " stroke-linejoin='" << Join[p.join()] << "'"; if(p.miter() != lastpen.miter()) *out << " stroke-miterlimit='" << p.miter()*ps2tex << "'"; if(p.width() != lastpen.width()) *out << " stroke-width='" << p.width()*ps2tex << "'"; const LineType *linetype=p.linetype(); const LineType *lastlinetype=lastpen.linetype(); if(!(linetype->pattern == lastlinetype->pattern)) { size_t n=linetype->pattern.size(); if(n > 0) { *out << " stroke-dasharray='"; *out << vm::read(linetype->pattern,0)*ps2tex; for(size_t i=1; i < n; ++i) *out << "," << vm::read(linetype->pattern,i)*ps2tex; *out << "'"; } } if(linetype->offset != lastlinetype->offset) *out << " stroke-dashoffset='" << linetype->offset*ps2tex << "'"; lastpen=p; } void svgtexfile::stroke(const pen &p, bool dot) { if(dot) color(p,"fill"); else { color(p,"fill='none' stroke"); properties(p); } endpath(); endtransform(); endspecial(); } void svgtexfile::strokepath() { reportWarning("SVG does not support strokepath"); } void svgtexfile::begingradientshade(bool axial, ColorSpace colorspace, const pen& pena, const pair& a, double ra, const pen& penb, const pair& b, double rb) { string type=axial ? "linear" : "radial"; beginspecial(); *out << "<" << type << "Gradient id='grad" << gradientcount; if(axial) { *out << "' x1='" << a.getx()*ps2tex << "' y1='" << -a.gety()*ps2tex << "' x2='" << b.getx()*ps2tex << "' y2='" << -b.gety()*ps2tex; } else { *out << "' cx='" << b.getx()*ps2tex << "' cy='" << -b.gety()*ps2tex << "' r='" << rb*ps2tex; } *out <<"' gradientUnits='userSpaceOnUse'>" << nl << "" << nl << "" << nl << "" << nl; begintransform(); beginpath(); } void svgtexfile::gradientshade(bool axial, ColorSpace colorspace, const pen& pena, const pair& a, double ra, bool, const pen& penb, const pair& b, double rb, bool) { *out << "' fill='url(#grad" << gradientcount << ")'"; fillrule(pena); endpath(); ++gradientcount; endtransform(); endspecial(); } // Return the point on the line through p and q that is closest to z. pair closest(pair p, pair q, pair z) { pair u=q-p; double denom=dot(u,u); return denom == 0.0 ? p : p+dot(z-p,u)/denom*u; } void svgtexfile::gouraudshade(const pen& p0, const pair& z0, const pen& p1, const pair& z1, const pen& p2, const pair& z2) { string hex[]={rgbhex(p0),rgbhex(p1),rgbhex(p2)}; pair Z[]={z0,z1,z2}; *out << "" << nl << "" << nl << "" << nl << ""; for(size_t k=0; k < 3; ++k) { pair z=Z[k]; pair opp=closest(Z[(k+1) % 3],Z[(k+2) % 3],z); *out << "" << nl << "" << nl << "" << nl << "" << nl; } *out << "" << nl << "" << nl; *out << "" << nl << "" << nl << "" << nl; ++gouraudcount; } void svgtexfile::begingouraudshade(const vm::array& pens, const vm::array& vertices, const vm::array& edges) { size_t size=pens.size(); if(size == 0) return; beginclip(); } void svgtexfile::gouraudshade(const pen& pentype, const array& pens, const array& vertices, const array& edges) { size_t size=pens.size(); if(size == 0) return; endclip0(pentype); pen *p0=NULL,*p1=NULL,*p2=NULL; pair z0,z1,z2; for(size_t i=0; i < size; i++) { Int edge=read(edges,i); switch(edge) { case 0: p0=read(pens,i); z0=read(vertices,i); ++i; if(i < size) { p1=read(pens,i); z1=read(vertices,i); ++i; if(i < size) { p2=read(pens,i); z2=read(vertices,i); } } break; case 1: p0=read(pens,i); z0=read(vertices,i); break; case 2: p1=read(pens,i); z1=read(vertices,i); break; default: break; } if(p0 == NULL || p1 == NULL || p2 == NULL) reportError("invalid edge flag"); gouraudshade(*p0,z0,*p1,z1,*p2,z2); } endtransform(); endspecial(); } void svgtexfile::begintensorshade(const vm::array& pens, const vm::array& boundaries, const vm::array& z) { beginspecial(); *out << "" << nl; path g=read(boundaries,0); pair Z[]={g.point((Int) 0),g.point((Int) 3),g.point((Int) 2), g.point((Int) 1)}; array *pi=read(pens,0); if(checkArray(pi) != 4) reportError("specify 4 pens for each path"); string hex[]={rgbhex(read(pi,0)),rgbhex(read(pi,3)), rgbhex(read(pi,2)),rgbhex(read(pi,1))}; *out << "" << nl << "" << nl << ""; pair mean=0.25*(Z[0]+Z[1]+Z[2]+Z[3]); for(size_t k=0; k < 4; ++k) { pair opp=(k % 2 == 0) ? Z[(k+2) % 4] : mean; *out << "" << nl << "" << nl << "" << nl << "" << nl; } beginpath(); } void svgtexfile::tensorshade(const pen& pentype, const vm::array& pens, const vm::array& boundaries, const vm::array& z) { *out << "' id='path" << tensorcount << "'"; fillrule(pentype); endpath(); *out << "" << nl; begintransform(); *out << "" << nl << "" << nl << "" << nl << "" << nl; ++tensorcount; endspecial(); } } //namespace camp asymptote-2.37/texfile.h000066400000000000000000000245211265434602500153160ustar00rootroot00000000000000/***** * texfile.h * John Bowman 2003/03/14 * * Encapsulates the writing of commands to a TeX file. *****/ #ifndef TEXFILE_H #define TEXFILE_H #include #include #include #include "common.h" #include "pair.h" #include "bbox.h" #include "pen.h" #include "util.h" #include "interact.h" #include "path.h" #include "array.h" #include "psfile.h" #include "settings.h" #include "process.h" namespace camp { template void texdocumentclass(T& out, bool pipe=false) { if(settings::latex(settings::getSetting("tex")) && (pipe || !settings::getSetting("inlinetex"))) out << "\\documentclass[12pt]{article}" << newl; } template void texuserpreamble(T& out, mem::list& preamble=processData().TeXpreamble) { for(mem::list::iterator p=preamble.begin(); p != preamble.end(); ++p) out << stripblanklines(*p); } template void latexfontencoding(T& out) { out << "\\makeatletter%" << newl << "\\let\\ASYencoding\\f@encoding%" << newl << "\\let\\ASYfamily\\f@family%" << newl << "\\let\\ASYseries\\f@series%" << newl << "\\let\\ASYshape\\f@shape%" << newl << "\\makeatother%" << newl; } template void texpreamble(T& out, mem::list& preamble=processData().TeXpreamble, bool ASYalign=true) { texuserpreamble(out,preamble); string texengine=settings::getSetting("tex"); if(settings::context(texengine)) out << "\\disabledirectives[system.errorcontext]%" << newl; out << "\\def\\ASYprefix{" << stripFile(settings::outname()) << "}" << newl << "\\newbox\\ASYbox" << newl << "\\newdimen\\ASYdimen" << newl << "\\long\\def\\ASYbase#1#2{\\leavevmode\\setbox\\ASYbox=\\hbox{#1}%" << "\\ASYdimen=\\ht\\ASYbox%" << newl << "\\setbox\\ASYbox=\\hbox{#2}\\lower\\ASYdimen\\box\\ASYbox}" << newl; if(ASYalign) out << "\\long\\def\\ASYaligned(#1,#2)(#3,#4)#5#6#7{\\leavevmode%" << newl << "\\setbox\\ASYbox=\\hbox{#7}%" << newl << "\\setbox\\ASYbox\\hbox{\\ASYdimen=\\ht\\ASYbox%" << newl << "\\advance\\ASYdimen by\\dp\\ASYbox\\kern#3\\wd\\ASYbox" << "\\raise#4\\ASYdimen\\box\\ASYbox}%" << newl << "\\setbox\\ASYbox=\\hbox{#5\\wd\\ASYbox 0pt\\dp\\ASYbox 0pt\\ht\\ASYbox 0pt\\box\\ASYbox#6}%" << newl << "\\hbox to 0pt{\\kern#1pt\\raise#2pt\\box\\ASYbox\\hss}}%" << newl << "\\long\\def\\ASYalignT(#1,#2)(#3,#4)#5#6{%" << newl << "\\ASYaligned(#1,#2)(#3,#4){%" << newl << settings::beginlabel(texengine) << "%" << newl << "}{%" << newl << settings::endlabel(texengine) << "%" << newl << "}{#6}}" << newl << "\\long\\def\\ASYalign(#1,#2)(#3,#4)#5{" << "\\ASYaligned(#1,#2)(#3,#4){}{}{#5}}" << newl << settings::rawpostscript(texengine) << newl; } // Work around bug in dvips.def: allow spaces in file names. template void dvipsfix(T &out) { if(!settings::pdf(settings::getSetting("tex"))) { out << "\\makeatletter" << newl << "\\def\\Ginclude@eps#1{%" << newl << " \\message{<#1>}%" << newl << " \\bgroup" << newl << " \\def\\@tempa{!}%" << newl << " \\dimen@\\Gin@req@width" << newl << " \\dimen@ii.1bp%" << newl << " \\divide\\dimen@\\dimen@ii" << newl << " \\@tempdima\\Gin@req@height" << newl << " \\divide\\@tempdima\\dimen@ii" << newl << " \\special{PSfile=#1\\space" << newl << " llx=\\Gin@llx\\space" << newl << " lly=\\Gin@lly\\space" << newl << " urx=\\Gin@urx\\space" << newl << " ury=\\Gin@ury\\space" << newl << " \\ifx\\Gin@scalex\\@tempa\\else rwi=\\number\\dimen@\\space\\fi" << newl << " \\ifx\\Gin@scaley\\@tempa\\else rhi=\\number\\@tempdima\\space\\fi" << newl << " \\ifGin@clip clip\\fi}%" << newl << " \\egroup}" << newl << "\\makeatother" << newl; } } template void texdefines(T& out, mem::list& preamble=processData().TeXpreamble, bool pipe=false) { if(pipe || !settings::getSetting("inlinetex")) texpreamble(out,preamble,!pipe); if(pipe) { // Make tex pipe aware of a previously generated aux file. string name=auxname(settings::outname(),"aux"); std::ifstream fin(name.c_str()); if(fin) { std::ofstream fout("texput.aux"); string s; while(getline(fin,s)) fout << s << endl; } } string texengine=settings::getSetting("tex"); if(settings::latex(texengine)) { if(pipe || !settings::getSetting("inlinetex")) { out << "\\usepackage{graphicx}" << newl; if(!pipe) { dvipsfix(out); out << "\\usepackage{color}" << newl; } } if(pipe) { out << "\\begin{document}" << newl; latexfontencoding(out); } } else if(!settings::context(texengine)) { out << "\\input graphicx" << newl // Fix miniltx path parsing bug: << "\\makeatletter" << newl << "\\def\\filename@parse#1{%" << newl << " \\let\\filename@area\\@empty" << newl << " \\expandafter\\filename@path#1/\\\\}" << newl << "\\def\\filename@path#1/#2\\\\{%" << newl << " \\ifx\\\\#2\\\\%" << newl << " \\def\\reserved@a{\\filename@simple#1.\\\\}%" << newl << " \\else" << newl << " \\edef\\filename@area{\\filename@area#1/}%" << newl << " \\def\\reserved@a{\\filename@path#2\\\\}%" << newl << " \\fi" << newl << " \\reserved@a}" << newl << "\\makeatother" << newl; dvipsfix(out); if(!pipe) out << "\\input picture" << newl; } } template bool setlatexfont(T& out, const pen& p, const pen& lastpen) { if(p.size() != lastpen.size() || p.Lineskip() != lastpen.Lineskip()) { out << "\\fontsize{" << p.size()*ps2tex << "}{" << p.Lineskip()*ps2tex << "}\\selectfont\n"; return true; } return false; } template bool settexfont(T& out, const pen& p, const pen& lastpen, bool latex) { string font=p.Font(); if(font != lastpen.Font() || (!latex && p.size() != lastpen.size())) { out << font << "%" << newl; return true; } return false; } class texfile : public psfile { protected: bbox box; bool inlinetex; double Hoffset; int level; public: string texengine; texfile(const string& texname, const bbox& box, bool pipe=false); virtual ~texfile(); void prologue(); virtual void beginpage() {} void epilogue(bool pipe=false); virtual void endpage() {} void setlatexcolor(pen p); void setpen(pen p); void setfont(pen p); void gsave(bool tex=true); void grestore(bool tex=true); void beginspecial(); void endspecial(); void beginraw(); void endraw(); void begingroup() {++level;} void endgroup() {--level;} bool toplevel() {return level == 0;} void beginpicture(const bbox& b); void endpicture(const bbox& b); void writepair(pair z) { *out << z; } void miniprologue(); void writeshifted(path p, bool newPath=true); double hoffset() {return Hoffset;} // Draws label transformed by T at position z. void put(const string& label, const transform& T, const pair& z, const pair& Align); void beginlayer(const string& psname, bool postscript); void endlayer(); }; class svgtexfile : public texfile { mem::stack clipstack; size_t clipcount; size_t gradientcount; size_t gouraudcount; size_t tensorcount; bool inspecial; static string nl; public: svgtexfile(const string& texname, const bbox& box, bool pipe=false) : texfile(texname,box,pipe) { clipcount=0; gradientcount=0; gouraudcount=0; tensorcount=0; inspecial=false; } void writeclip(path p, bool newPath=true) { write(p,false); } void dot(path p, pen, bool newPath=true); void writeshifted(pair z) { write(conj(z)*ps2tex); } void translate(pair z) {} void concat(transform t) {} void beginspecial(); void endspecial(); // Prevent unwanted page breaks. void beginpage() { beginpicture(box); } void endpage() { endpicture(box); } void begintransform(); void endtransform(); void clippath(); void beginpath(); void endpath(); void newpath() { beginspecial(); begintransform(); beginpath(); } void moveto(pair z) { *out << "M"; writeshifted(z); } void lineto(pair z) { *out << "L"; writeshifted(z); } void curveto(pair zp, pair zm, pair z1) { *out << "C"; writeshifted(zp); writeshifted(zm); writeshifted(z1); } void closepath() { *out << "Z"; } string rgbhex(pen p) { p.torgb(); return p.hex(); } void properties(const pen& p); void color(const pen &p, const string& type); void stroke(const pen &p, bool dot=false); void strokepath(); void fillrule(const pen& p, const string& type="fill"); void fill(const pen &p); void begingradientshade(bool axial, ColorSpace colorspace, const pen& pena, const pair& a, double ra, const pen& penb, const pair& b, double rb); void gradientshade(bool axial, ColorSpace colorspace, const pen& pena, const pair& a, double ra, bool extenda, const pen& penb, const pair& b, double rb, bool extendb); void gouraudshade(const pen& p0, const pair& z0, const pen& p1, const pair& z1, const pen& p2, const pair& z2); void begingouraudshade(const vm::array& pens, const vm::array& vertices, const vm::array& edges); void gouraudshade(const pen& pentype, const vm::array& pens, const vm::array& vertices, const vm::array& edges); void begintensorshade(const vm::array& pens, const vm::array& boundaries, const vm::array& z); void tensorshade(const pen& pentype, const vm::array& pens, const vm::array& boundaries, const vm::array& z); void beginclip(); void endclip0(const pen &p); void endclip(const pen &p); void endpsclip(const pen &p) {} void setpen(pen p) {if(!inspecial) texfile::setpen(p);} void gsave(bool tex=false); void grestore(bool tex=false); }; } //namespace camp #endif asymptote-2.37/tr.cc000066400000000000000000000277241265434602500144510ustar00rootroot00000000000000/* This file is released under version 2 of the GNU Library General Public * License (see the files LICENSE.LIBRARY and LICENSE). */ /* $Id: tr.c,v 1.9 1998/01/29 16:56:54 brianp Exp $ */ /* * $Log: tr.c,v $ * Revision 1.9 1998/01/29 16:56:54 brianp * allow trOrtho() and trFrustum() to be called at any time, minor clean-up * * Revision 1.8 1998/01/28 19:47:39 brianp * minor clean-up for C++ * * Revision 1.7 1997/07/21 17:34:38 brianp * added tile borders * * Revision 1.6 1997/07/21 15:47:35 brianp * renamed all "near" and "far" variables * * Revision 1.5 1997/04/26 21:23:25 brianp * added trRasterPos3f function * * Revision 1.4 1997/04/26 19:59:36 brianp * set CurrentTile to -1 before first tile and after last tile * * Revision 1.3 1997/04/22 23:51:15 brianp * added WIN32 header stuff, removed tabs * * Revision 1.2 1997/04/19 23:26:10 brianp * many API changes * * Revision 1.1 1997/04/18 21:53:05 brianp * Initial revision * */ /* * Tiled Rendering library * Version 1.1 * Copyright (C) Brian Paul */ #include "common.h" #ifdef HAVE_GL #include #include #include #include #ifdef WIN32 #include #endif #ifdef __APPLE__ #include #include #else #include #include #endif #include "tr.h" #define DEFAULT_TILE_WIDTH 256 #define DEFAULT_TILE_HEIGHT 256 #define DEFAULT_TILE_BORDER 0 struct _TRctx { /* Final image parameters */ GLint ImageWidth, ImageHeight; GLenum ImageFormat, ImageType; GLvoid *ImageBuffer; /* Tile parameters */ GLint TileWidth, TileHeight; GLint TileWidthNB, TileHeightNB; GLint TileBorder; GLenum TileFormat, TileType; GLvoid *TileBuffer; /* Projection parameters */ GLboolean Perspective; GLdouble Left; GLdouble Right; GLdouble Bottom; GLdouble Top; GLdouble Near; GLdouble Far; /* Misc */ TRenum RowOrder; GLint Rows, Columns; GLint CurrentTile; GLint CurrentTileWidth, CurrentTileHeight; GLint CurrentRow, CurrentColumn; GLint ViewportSave[4]; }; /* * Misc setup including computing number of tiles (rows and columns). */ static void Setup(TRcontext *tr) { if (!tr) return; tr->Columns = (tr->ImageWidth + tr->TileWidthNB - 1) / tr->TileWidthNB; tr->Rows = (tr->ImageHeight + tr->TileHeightNB - 1) / tr->TileHeightNB; tr->CurrentTile = 0; assert(tr->Columns >= 0); assert(tr->Rows >= 0); } TRcontext *trNew(void) { TRcontext *tr = (TRcontext *) calloc(1, sizeof(TRcontext)); if (tr) { tr->TileWidth = DEFAULT_TILE_WIDTH; tr->TileHeight = DEFAULT_TILE_HEIGHT; tr->TileBorder = DEFAULT_TILE_BORDER; tr->RowOrder = TR_BOTTOM_TO_TOP; tr->CurrentTile = -1; } return (TRcontext *) tr; } void trDelete(TRcontext *tr) { if (tr) free(tr); } void trTileSize(TRcontext *tr, GLint width, GLint height, GLint border) { if (!tr) return; assert(border >= 0); assert(width >= 1); assert(height >= 1); assert(width >= 2*border); assert(height >= 2*border); tr->TileBorder = border; tr->TileWidth = width; tr->TileHeight = height; tr->TileWidthNB = width - 2 * border; tr->TileHeightNB = height - 2 * border; Setup(tr); } void trTileBuffer(TRcontext *tr, GLenum format, GLenum type, GLvoid *image) { if (!tr) return; tr->TileFormat = format; tr->TileType = type; tr->TileBuffer = image; } void trImageSize(TRcontext *tr, GLint width, GLint height) { if (!tr) return; tr->ImageWidth = width; tr->ImageHeight = height; Setup(tr); } void trImageBuffer(TRcontext *tr, GLenum format, GLenum type, GLvoid *image) { if (!tr) return; tr->ImageFormat = format; tr->ImageType = type; tr->ImageBuffer = image; } GLint trGet(TRcontext *tr, TRenum param) { if (!tr) return 0; switch (param) { case TR_TILE_WIDTH: return tr->TileWidth; case TR_TILE_HEIGHT: return tr->TileHeight; case TR_TILE_BORDER: return tr->TileBorder; case TR_IMAGE_WIDTH: return tr->ImageWidth; case TR_IMAGE_HEIGHT: return tr->ImageHeight; case TR_ROWS: return tr->Rows; case TR_COLUMNS: return tr->Columns; case TR_CURRENT_ROW: if (tr->CurrentTile<0) return -1; else return tr->CurrentRow; case TR_CURRENT_COLUMN: if (tr->CurrentTile<0) return -1; else return tr->CurrentColumn; case TR_CURRENT_TILE_WIDTH: return tr->CurrentTileWidth; case TR_CURRENT_TILE_HEIGHT: return tr->CurrentTileHeight; case TR_ROW_ORDER: return (GLint) tr->RowOrder; default: return 0; } } void trRowOrder(TRcontext *tr, TRenum order) { if (!tr) return; if (order==TR_TOP_TO_BOTTOM || order==TR_BOTTOM_TO_TOP) tr->RowOrder = order; } void trOrtho(TRcontext *tr, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar) { if (!tr) return; tr->Perspective = GL_FALSE; tr->Left = left; tr->Right = right; tr->Bottom = bottom; tr->Top = top; tr->Near = zNear; tr->Far = zFar; } void trFrustum(TRcontext *tr, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar) { if (!tr) return; tr->Perspective = GL_TRUE; tr->Left = left; tr->Right = right; tr->Bottom = bottom; tr->Top = top; tr->Near = zNear; tr->Far = zFar; } void trPerspective(TRcontext *tr, GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar ) { GLdouble xmin, xmax, ymin, ymax; static const double halfradians=acos(-1.0)/360.0; ymax = zNear * tan(fovy * halfradians); ymin = -ymax; xmin = ymin * aspect; xmax = ymax * aspect; trFrustum(tr, xmin, xmax, ymin, ymax, zNear, zFar); } void trBeginTile(TRcontext *tr) { GLint matrixMode; GLint tileWidth, tileHeight, border; GLdouble left, right, bottom, top; if (!tr) return; if (tr->CurrentTile <= 0) { Setup(tr); /* Save user's viewport, will be restored after last tile rendered */ glGetIntegerv(GL_VIEWPORT, tr->ViewportSave); } /* which tile (by row and column) we're about to render */ if (tr->RowOrder==TR_BOTTOM_TO_TOP) { tr->CurrentRow = tr->CurrentTile / tr->Columns; tr->CurrentColumn = tr->CurrentTile % tr->Columns; } else if (tr->RowOrder==TR_TOP_TO_BOTTOM) { tr->CurrentRow = tr->Rows - (tr->CurrentTile / tr->Columns) - 1; tr->CurrentColumn = tr->CurrentTile % tr->Columns; } else { /* This should never happen */ abort(); } assert(tr->CurrentRow < tr->Rows); assert(tr->CurrentColumn < tr->Columns); border = tr->TileBorder; /* Compute actual size of this tile with border */ if (tr->CurrentRow < tr->Rows-1) tileHeight = tr->TileHeight; else tileHeight = tr->ImageHeight - (tr->Rows-1) * (tr->TileHeightNB) + 2 * border; if (tr->CurrentColumn < tr->Columns-1) tileWidth = tr->TileWidth; else tileWidth = tr->ImageWidth - (tr->Columns-1) * (tr->TileWidthNB) + 2 * border; /* Save tile size, with border */ tr->CurrentTileWidth = tileWidth; tr->CurrentTileHeight = tileHeight; glViewport(0, 0, tileWidth, tileHeight); /* tile size including border */ /* save current matrix mode */ glGetIntegerv(GL_MATRIX_MODE, &matrixMode); glMatrixMode(GL_PROJECTION); glLoadIdentity(); /* compute projection parameters */ left = tr->Left + (tr->Right - tr->Left) * (tr->CurrentColumn * tr->TileWidthNB - border) / tr->ImageWidth; right = left + (tr->Right - tr->Left) * tileWidth / tr->ImageWidth; bottom = tr->Bottom + (tr->Top - tr->Bottom) * (tr->CurrentRow * tr->TileHeightNB - border) / tr->ImageHeight; top = bottom + (tr->Top - tr->Bottom) * tileHeight / tr->ImageHeight; if (tr->Perspective) glFrustum(left, right, bottom, top, tr->Near, tr->Far); else glOrtho(left, right, bottom, top, tr->Near, tr->Far); /* restore user's matrix mode */ glMatrixMode(matrixMode); } int trEndTile(TRcontext *tr) { GLint prevRowLength, prevSkipRows, prevSkipPixels; if (!tr) return 0; assert(tr->CurrentTile>=0); /* be sure OpenGL rendering is finished */ glFlush(); /* save current glPixelStore values */ glGetIntegerv(GL_PACK_ROW_LENGTH, &prevRowLength); glGetIntegerv(GL_PACK_SKIP_ROWS, &prevSkipRows); glGetIntegerv(GL_PACK_SKIP_PIXELS, &prevSkipPixels); /*glGetIntegerv(GL_PACK_ALIGNMENT, &prevAlignment);*/ if (tr->TileBuffer) { GLint srcX = tr->TileBorder; GLint srcY = tr->TileBorder; GLint srcWidth = tr->TileWidthNB; GLint srcHeight = tr->TileHeightNB; glReadPixels(srcX, srcY, srcWidth, srcHeight, tr->TileFormat, tr->TileType, tr->TileBuffer); } if (tr->ImageBuffer) { GLint srcX = tr->TileBorder; GLint srcY = tr->TileBorder; GLint srcWidth = tr->CurrentTileWidth - 2 * tr->TileBorder; GLint srcHeight = tr->CurrentTileHeight - 2 * tr->TileBorder; GLint destX = tr->TileWidthNB * tr->CurrentColumn; GLint destY = tr->TileHeightNB * tr->CurrentRow; /* setup pixel store for glReadPixels */ glPixelStorei(GL_PACK_ROW_LENGTH, tr->ImageWidth); glPixelStorei(GL_PACK_SKIP_ROWS, destY); glPixelStorei(GL_PACK_SKIP_PIXELS, destX); /*glPixelStorei(GL_PACK_ALIGNMENT, 1);*/ /* read the tile into the final image */ glReadPixels(srcX, srcY, srcWidth, srcHeight, tr->ImageFormat, tr->ImageType, tr->ImageBuffer); } /* restore previous glPixelStore values */ glPixelStorei(GL_PACK_ROW_LENGTH, prevRowLength); glPixelStorei(GL_PACK_SKIP_ROWS, prevSkipRows); glPixelStorei(GL_PACK_SKIP_PIXELS, prevSkipPixels); /*glPixelStorei(GL_PACK_ALIGNMENT, prevAlignment);*/ /* increment tile counter, return 1 if more tiles left to render */ tr->CurrentTile++; if (tr->CurrentTile >= tr->Rows * tr->Columns) { /* restore user's viewport */ glViewport(tr->ViewportSave[0], tr->ViewportSave[1], tr->ViewportSave[2], tr->ViewportSave[3]); tr->CurrentTile = -1; /* all done */ return 0; } else return 1; } /* * Replacement for glRastePos3f() which avoids the problem with invalid * raster pos. */ void trRasterPos3f(TRcontext *tr, GLfloat x, GLfloat y, GLfloat z) { if (tr->CurrentTile<0) { /* not doing tile rendering right now. Let OpenGL do this. */ glRasterPos3f(x, y, z); } else { GLdouble modelview[16], proj[16]; GLint viewport[4]; GLdouble winX, winY, winZ; /* Get modelview, projection and viewport */ glGetDoublev(GL_MODELVIEW_MATRIX, modelview); glGetDoublev(GL_PROJECTION_MATRIX, proj); viewport[0] = 0; viewport[1] = 0; viewport[2] = tr->CurrentTileWidth; viewport[3] = tr->CurrentTileHeight; /* Project object coord to window coordinate */ if (gluProject(x, y, z, modelview, proj, viewport, &winX, &winY, &winZ)){ /* set raster pos to window coord (0,0) */ glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0.0, tr->CurrentTileWidth, 0.0, tr->CurrentTileHeight, 0.0, 1.0); glRasterPos3f(0.0, 0.0, -winZ); /* Now use empty bitmap to adjust raster position to (winX,winY) */ { GLubyte bitmap[1] = {0}; glBitmap(1, 1, 0.0, 0.0, winX, winY, bitmap); } /* restore original matrices */ glPopMatrix(); /*proj*/ glMatrixMode(GL_MODELVIEW); glPopMatrix(); } #ifdef DEBUG if (glGetError()) printf("GL error!\n"); #endif } } #endif asymptote-2.37/tr.h000066400000000000000000000067671265434602500143170ustar00rootroot00000000000000/* This file is released under version 2 of the GNU Library General Public * License (see the files LICENSE.LIBRARY and LICENSE). */ /* $Id: tr.h,v 1.5 1997/07/21 17:34:07 brianp Exp $ */ /* * $Log: tr.h,v $ * Revision 1.5 1997/07/21 17:34:07 brianp * added tile borders, incremented version to 1.1 * * Revision 1.4 1997/07/21 15:47:35 brianp * renamed all "near" and "far" variables * * Revision 1.3 1997/04/26 21:23:25 brianp * added trRasterPos3f function * * Revision 1.2 1997/04/19 23:26:10 brianp * many API changes * * Revision 1.1 1997/04/18 21:53:05 brianp * Initial revision * */ /* * Tiled Rendering library * Version 1.1 * Copyright (C) Brian Paul * * * This library allows one to render arbitrarily large images with OpenGL. * The basic idea is to break the image into tiles which are rendered one * at a time. The tiles are assembled together to form the final, large * image. Tiles and images can be of any size. * * Basic usage: * * 1. Allocate a tile rendering context: * TRcontext t = trNew(); * * 2. Specify the final image buffer and tile size: * GLubyte image[W][H][4] * trImageSize(t, W, H); * trImageBuffer(t, GL_RGBA, GL_UNSIGNED_BYTE, (GLubyte *) image); * * 3. Setup your projection: * trFrustum(t, left, right, bottom top, near, far); * or * trOrtho(t, left, right, bottom top, near, far); * or * trPerspective(t, fovy, aspect, near, far); * * 4. Render the tiles: * do { * trBeginTile(t); * DrawMyScene(); * } while (trEndTile(t)); * * You provide the DrawMyScene() function which calls glClear() and * draws all your stuff. * * 5. The image array is now complete. Display it, write it to a file, etc. * * 6. Delete the tile rendering context when finished: * trDelete(t); * */ #ifndef TR_H #define TR_H #ifdef __APPLE__ #include #else #include #endif #ifdef __cplusplus extern "C" { #endif #define TR_VERSION "1.1" #define TR_MAJOR_VERSION 1 #define TR_MINOR_VERSION 1 typedef struct _TRctx TRcontext; typedef enum { TR_TILE_WIDTH = 100, TR_TILE_HEIGHT, TR_TILE_BORDER, TR_IMAGE_WIDTH, TR_IMAGE_HEIGHT, TR_ROWS, TR_COLUMNS, TR_CURRENT_ROW, TR_CURRENT_COLUMN, TR_CURRENT_TILE_WIDTH, TR_CURRENT_TILE_HEIGHT, TR_ROW_ORDER, TR_TOP_TO_BOTTOM, TR_BOTTOM_TO_TOP } TRenum; extern TRcontext *trNew(void); extern void trDelete(TRcontext *tr); extern void trTileSize(TRcontext *tr, GLint width, GLint height, GLint border); extern void trTileBuffer(TRcontext *tr, GLenum format, GLenum type, GLvoid *image); extern void trImageSize(TRcontext *tr, GLint width, GLint height); extern void trImageBuffer(TRcontext *tr, GLenum format, GLenum type, GLvoid *image); extern void trRowOrder(TRcontext *tr, TRenum order); extern GLint trGet(TRcontext *tr, TRenum param); extern void trOrtho(TRcontext *tr, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); extern void trFrustum(TRcontext *tr, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); extern void trPerspective(TRcontext *tr, GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar ); extern void trBeginTile(TRcontext *tr); extern int trEndTile(TRcontext *tr); extern void trRasterPos3f(TRcontext *tr, GLfloat x, GLfloat y, GLfloat z); #ifdef __cplusplus } #endif #endif asymptote-2.37/transform.h000066400000000000000000000140511265434602500156660ustar00rootroot00000000000000/***** * transform.h * Andy Hammerlindl 2002/05/22 * * The transform datatype stores an affine transformation on the plane * The datamembers are x, y, xx, xy, yx, and yy. A pair (x,y) is * transformed as * x' = t.x + t.xx * x + t.xy * y * y' = t.y + t.yx * x + t.yy * y *****/ #ifndef TRANSFORM_H #define TRANSFORM_H #include #include "pair.h" namespace camp { class transform : public gc { double x; double y; double xx; double xy; double yx; double yy; public: transform() : x(0.0), y(0.0), xx(1.0), xy(0.0), yx(0.0), yy(1.0) {} virtual ~transform() {} transform(double x, double y, double xx, double xy, double yx, double yy) : x(x), y(y), xx(xx), xy(xy), yx(yx), yy(yy) {} double getx() const { return x; } double gety() const { return y; } double getxx() const { return xx; } double getxy() const { return xy; } double getyx() const { return yx; } double getyy() const { return yy; } friend transform operator+ (const transform& t, const transform& s) { return transform(t.x + s.x, t.y + s.y, t.xx + s.xx, t.xy + s.xy, t.yx + s.yx, t.yy + s.yy); } friend transform operator- (const transform& t, const transform& s) { return transform(t.x - s.x, t.y - s.y, t.xx - s.xx, t.xy - s.xy, t.yx - s.yx, t.yy - s.yy); } friend transform operator- (const transform& t) { return transform(-t.x, -t.y, -t.xx, -t.xy, -t.yx, -t.yy); } friend pair operator* (const transform& t, const pair& z) { double x = z.getx(), y = z.gety(); return pair(t.x + t.xx * x + t.xy * y, t.y + t.yx * x + t.yy * y); } // Calculates the composition of t and s, so for a pair, z, // t * (s * z) == (t * s) * z // Can be thought of as matrix multiplication. friend transform operator* (const transform& t, const transform& s) { return transform(t.x + t.xx * s.x + t.xy * s.y, t.y + t.yx * s.x + t.yy * s.y, t.xx * s.xx + t.xy * s.yx, t.xx * s.xy + t.xy * s.yy, t.yx * s.xx + t.yy * s.yx, t.yx * s.xy + t.yy * s.yy); } friend bool operator== (const transform& t1, const transform& t2) { return t1.x == t2.x && t1.y == t2.y && t1.xx == t2.xx && t1.xy == t2.xy && t1.yx == t2.yx && t1.yy == t2.yy; } friend bool operator!= (const transform& t1, const transform& t2) { return !(t1 == t2); } bool isIdentity() const { return x == 0.0 && y == 0.0 && xx == 1.0 && xy == 0.0 && yx == 0.0 && yy == 1.0; } bool isNull() const { return x == 0.0 && y == 0.0 && xx == 0.0 && xy == 0.0 && yx == 0.0 && yy == 0.0; } // Calculates the determinant, as if it were a matrix. friend double det(const transform& t) { return t.xx * t.yy - t.xy * t.yx; } // Tells if the transformation is invertible (bijective). bool invertible() const { return det(*this) != 0.0; } friend transform inverse(const transform& t) { double d = det(t); if (d == 0.0) reportError("inverting singular transform"); d=1.0/d; return transform((t.xy * t.y - t.yy * t.x)*d, (t.yx * t.x - t.xx * t.y)*d, t.yy*d, -t.xy*d, -t.yx*d, t.xx*d); } friend ostream& operator<< (ostream& out, const transform& t) { return out << "(" << t.x << "," << t.y << "," << t.xx << "," << t.xy << "," << t.yx << "," << t.yy << ")"; } }; // The common transforms static const transform identity; inline transform shift(pair z) { return transform (z.getx(), z.gety(), 1.0, 0.0, 0.0, 1.0); } inline transform xscale(double s) { return transform (0.0, 0.0, s, 0.0, 0.0, 1.0); } inline transform yscale(double s) { return transform (0.0, 0.0, 1.0, 0.0, 0.0, s); } inline transform scale(double s) { return transform (0.0, 0.0, s, 0.0, 0.0, s); } inline transform scale(double x, double y) { return transform (0.0, 0.0, x, 0.0, 0.0, y); } inline transform scale(pair z) { // Equivalent to multiplication by z. double x = z.getx(), y = z.gety(); return transform (0.0, 0.0, x, -y, y, x); } inline transform slant(double s) { return transform (0.0, 0.0, 1.0, s, 0.0, 1.0); } inline transform rotate(double theta) { double s = sin(theta), c = cos(theta); return transform (0.0, 0.0, c, -s, s, c); } // return rotate(angle(v)) if z != (0,0); otherwise return identity. inline transform rotate(pair z) { double d=z.length(); if(d == 0.0) return identity; d=1.0/d; return transform (0.0, 0.0, d*z.getx(), -d*z.gety(), d*z.gety(), d*z.getx()); } inline transform rotatearound(pair z, double theta) { // Notice the operators are applied from right to left. // Could be optimized. return shift(z) * rotate(theta) * shift(-z); } inline transform reflectabout(pair z, pair w) { if (z == w) reportError("points determining line to reflect about must be distinct"); // Also could be optimized. transform basis = shift(z) * scale(w-z); transform flip = yscale(-1.0); return basis * flip * inverse(basis); } // Return the rotational part of t. inline transform rotation(transform t) { pair z(2.0*t.getxx()*t.getyy(),t.getyx()*t.getyy()-t.getxx()*t.getxy()); if(t.getxx() < 0) z=-z; return rotate(atan2(z.gety(),z.getx())); } // Remove the x and y components, so that the new transform maps zero to zero. inline transform shiftless(transform t) { return transform(0, 0, t.getxx(), t.getxy(), t.getyx(), t.getyy()); } // Return the translational component of t. inline transform shift(transform t) { return transform(t.getx(), t.gety(), 1.0, 0, 0, 1.0); } // Return the translational pair of t. inline pair shiftpair(transform t) { return pair(t.getx(), t.gety()); } inline transform matrix(pair lb, pair rt) { pair size=rt-lb; return transform(lb.getx(),lb.gety(),size.getx(),0,0,size.gety()); } } //namespace camp GC_DECLARE_PTRFREE(camp::transform); #endif asymptote-2.37/triple.h000066400000000000000000000146021265434602500151540ustar00rootroot00000000000000/***** * triple.h * John Bowman * * Stores a three-dimensional point. * *****/ #ifndef TRIPLE_H #define TRIPLE_H #include #include #include #include #include "common.h" #include "angle.h" #include "pair.h" namespace run { void transpose(double *a, size_t n); void inverse(double *a, size_t n); } namespace camp { typedef double Triple[3]; class triple; bool isIdTransform3(const double* t); void copyTransform3(double*& d, const double* s, GCPlacement placement=NoGC); void multiplyTransform3(double*& t, const double* s, const double* r); void boundstriples(double& x, double& y, double& z, double& X, double& Y, double& Z, size_t n, const triple* v); class triple : virtual public gc { double x; double y; double z; public: triple() : x(0.0), y(0.0), z(0.0) {} triple(double x, double y=0.0, double z=0.0) : x(x), y(y), z(z) {} triple(const Triple& v) : x(v[0]), y(v[1]), z(v[2]) {} virtual ~triple() {} void set(double X, double Y=0.0, double Z=0.0) { x=X; y=Y; z=Z; } double getx() const { return x; } double gety() const { return y; } double getz() const { return z; } // transform by row-major matrix friend triple operator* (const double* t, const triple& v) { if(t == NULL) return v; double f=t[12]*v.x+t[13]*v.y+t[14]*v.z+t[15]; if(f == 0.0) reportError("division by 0 in transform of a triple"); f=1.0/f; return triple((t[0]*v.x+t[1]*v.y+t[2]*v.z+t[3])*f, (t[4]*v.x+t[5]*v.y+t[6]*v.z+t[7])*f, (t[8]*v.x+t[9]*v.y+t[10]*v.z+t[11])*f); } friend triple transformNormal(const double* t, const triple& v) { if(t == NULL) return v; double T[16]; memcpy(T,t,sizeof(double)*16); T[3]=T[7]=T[11]=0.0; run::inverse(T,4); run::transpose(T,4); triple V=T*v; return unit(V); } friend void transformtriples(const double* t, size_t n, triple* d, const triple* s) { if(n == 0 || d == NULL || s == NULL) return; for(size_t i=0; i < n; i++) d[i]=t*s[i]; } friend void copytriples(size_t n, triple* d, const triple* s) { if(d == NULL || s == NULL) return; for(size_t i=0; i < n; i++) d[i]=s[i]; } friend void boundstriples(triple& Min, triple& Max, size_t n, const triple* v) { if(n==0 || v==NULL) return; double x,y,z; double X,Y,Z; X=x=v[0].getx(); Y=y=v[0].gety(); Z=z=v[0].getz(); for(size_t i=1; i < n; ++i) { const double vx=v[i].getx(); x=fmin(x,vx); X=fmax(X,vx); const double vy=v[i].gety(); y=fmin(y,vy); Y=fmax(Y,vy); const double vz=v[i].getz(); z=fmin(z,vz); Z=fmax(Z,vz); } Min.set(x,y,z); Max.set(X,Y,Z); } friend void ratiotriples(pair &b, double (*m)(double, double), bool &first, size_t n, const triple* v) { if(n==0 || v==NULL) return; if(first) { first=false; const triple& v0=v[0]; b=pair(v0.x/v0.z,v0.y/v0.z); } double x=b.getx(); double y=b.gety(); for(size_t i=0; i < n; ++i) { const triple& vi = v[i]; x=m(x,vi.x/vi.z); y=m(y,vi.y/vi.z); } b=pair(x,y); } friend triple operator+ (const triple& z, const triple& w) { return triple(z.x + w.x, z.y + w.y, z.z + w.z); } friend triple operator- (const triple& z, const triple& w) { return triple(z.x - w.x, z.y - w.y, z.z - w.z); } friend triple operator- (const triple& z) { return triple(-z.x, -z.y, -z.z); } friend triple operator* (double s, const triple& z) { return triple(s*z.x, s*z.y, s*z.z); } friend triple operator* (const triple& z, double s) { return triple(z.x*s, z.y*s, z.z*s); } friend triple operator/ (const triple& z, double s) { if (s == 0.0) reportError("division by 0"); s=1.0/s; return triple(z.x*s, z.y*s, z.z*s); } const triple& operator+= (const triple& w) { x += w.x; y += w.y; z += w.z; return *this; } const triple& operator-= (const triple& w) { x -= w.x; y -= w.y; z -= w.z; return *this; } friend bool operator== (const triple& z, const triple& w) { return z.x == w.x && z.y == w.y && z.z == w.z; } friend bool operator!= (const triple& z, const triple& w) { return z.x != w.x || z.y != w.y || z.z != w.z; } double abs2() const { return x*x+y*y+z*z; } friend double abs2(const triple &v) { return v.abs2(); } double length() const /* r */ { return sqrt(abs2()); } friend double length(const triple& v) { return v.length(); } double polar() const /* theta */ { double r=length(); if (r == 0.0) reportError("taking polar angle of (0,0,0)"); return acos(z/r); } double azimuth() const /* phi */ { return angle(x,y); } friend triple unit(const triple& v) { double scale=v.length(); if(scale == 0.0) return v; scale=1.0/scale; return triple(v.x*scale,v.y*scale,v.z*scale); } friend double dot(const triple& u, const triple& v) { return u.x*v.x+u.y*v.y+u.z*v.z; } friend triple cross(const triple& u, const triple& v) { return triple(u.y*v.z-u.z*v.y, u.z*v.x-u.x*v.z, u.x*v.y-u.y*v.x); } // Returns a unit triple in the direction (theta,phi), in radians. friend triple expi(double theta, double phi) { double sintheta=sin(theta); return triple(sintheta*cos(phi),sintheta*sin(phi),cos(theta)); } friend istream& operator >> (istream& s, triple& z) { char c; s >> std::ws; bool paren=s.peek() == '('; // parenthesis are optional if(paren) s >> c; s >> z.x >> std::ws; if(s.peek() == ',') s >> c >> z.y; else z.y=0.0; if(s.peek() == ',') s >> c >> z.z; else z.z=0.0; if(paren) { s >> std::ws; if(s.peek() == ')') s >> c; } return s; } friend ostream& operator << (ostream& out, const triple& z) { out << "(" << z.x << "," << z.y << "," << z.z << ")"; return out; } }; triple expi(double theta, double phi); // Return the component of vector v perpendicular to a unit vector u. inline triple perp(triple v, triple u) { return v-dot(v,u)*u; } double xratio(const triple& v); double yratio(const triple& v); } //namespace camp GC_DECLARE_PTRFREE(camp::triple); #endif asymptote-2.37/types.cc000066400000000000000000000330741265434602500151630ustar00rootroot00000000000000/***** * types.cc * Andy Hammerlindl 2002/06/24 * * Used by the compiler as a way to keep track of the type of a variable * or expression. *****/ #include #include #include "entry.h" #include "types.h" #include "runtime.h" #include "runarray.h" #include "runfile.h" #include "runpair.h" #include "runtriple.h" #include "access.h" #include "virtualfieldaccess.h" namespace run { void arrayDeleteHelper(vm::stack *Stack); } // For pre-translated symbols. #ifndef NOSYM #include "types.symbols.h" #endif namespace types { /* Base types */ #define PRIMITIVE(name,Name,asyName) \ primitiveTy p##Name(ty_##name); \ ty *prim##Name() { return &p##Name; } \ array name##Array_(prim##Name()); \ ty *name##Array() { return &name##Array_; } \ array name##Array2_(name##Array()); \ ty *name##Array2() { return &name##Array2_; } \ array name##Array3_(name##Array2()); \ ty *name##Array3() { return &name##Array3_; } #define PRIMERROR #include "primitives.h" #undef PRIMERROR #undef PRIMITIVE nullTy pNull; ty *primNull() { return &pNull; } const char *names[] = { "null", "", "", "", #define PRIMITIVE(name,Name,asyName) #asyName, #define PRIMERROR #include "primitives.h" #undef PRIMERROR #undef PRIMITIVE "" }; ty::~ty() {} void ty::print(ostream& out) const { out << names[kind]; } // Used for primitive virtual fields and array virtual fields. #define FIELD(Type, name, func) \ if (sig == 0 && id == name) { \ static trans::virtualFieldAccess a(run::func); \ static trans::varEntry v(Type(), &a, 0, position()); \ return &v; \ } #define RWFIELD(Type, name, getter, setter) \ if (sig == 0 && id == name) { \ static trans::virtualFieldAccess a(run::getter, run::setter); \ static trans::varEntry v(Type(), &a, 0, position()); \ return &v; \ } #define SIGFIELD(Type, name, func) \ if (id == name && \ equivalent(sig, Type()->getSignature())) \ { \ static trans::virtualFieldAccess a(run::func, 0, run::func##Helper); \ static trans::varEntry v(Type(), &a, 0, position()); \ return &v; \ } #define DSIGFIELD(name, sym, func) \ if (id == sym && \ equivalent(sig, name##Type()->getSignature())) \ { \ static trans::virtualFieldAccess a(run::func, 0, run::func##Helper); \ /* for some fields, v needs to be dynamic */ \ /* e.g. when the function type depends on an array type. */ \ trans::varEntry *v = \ new trans::varEntry(name##Type(), &a, 0, position()); \ return v; \ } #define FILEFIELD(GetType, SetType, name, sym) \ FIELD(GetType,sym,name##Part); \ SIGFIELD(SetType,sym,name##Set); ty *dimensionType() { return new function(primFile(), formal(primInt(),SYM(nx),true), formal(primInt(),SYM(ny),true), formal(primInt(),SYM(nz),true)); } ty *modeType() { return new function(primFile(),formal(primBoolean(),SYM(b), true)); } ty *readType() { return new function(primFile(), formal(primInt(), SYM(i))); } trans::varEntry *primitiveTy::virtualField(symbol id, signature *sig) { switch (kind) { case ty_pair: FIELD(primReal,SYM(x),pairXPart); FIELD(primReal,SYM(y),pairYPart); break; case ty_triple: FIELD(primReal,SYM(x),tripleXPart); FIELD(primReal,SYM(y),tripleYPart); FIELD(primReal,SYM(z),tripleZPart); break; case ty_transform: FIELD(primReal,SYM(x),transformXPart); FIELD(primReal,SYM(y),transformYPart); FIELD(primReal,SYM(xx),transformXXPart); FIELD(primReal,SYM(xy),transformXYPart); FIELD(primReal,SYM(yx),transformYXPart); FIELD(primReal,SYM(yy),transformYYPart); break; case ty_tensionSpecifier: FIELD(primReal,SYM(out),tensionSpecifierOutPart); FIELD(primReal,SYM(in),tensionSpecifierInPart); FIELD(primBoolean,SYM(atLeast),tensionSpecifierAtleastPart); break; case ty_curlSpecifier: FIELD(primReal,SYM(value),curlSpecifierValuePart); FIELD(primInt,SYM(side),curlSpecifierSidePart); break; case ty_file: FIELD(primString,SYM(name),namePart); FIELD(primString,SYM(mode),modePart); FILEFIELD(IntArray,dimensionType,dimension,SYM(dimension)); FILEFIELD(primBoolean,modeType,line,SYM(line)); FILEFIELD(primBoolean,modeType,csv,SYM(csv)); FILEFIELD(primBoolean,modeType,word,SYM(word)); FILEFIELD(primBoolean,modeType,singlereal,SYM(singlereal)); FILEFIELD(primBoolean,modeType,singleint,SYM(singleint)); FILEFIELD(primBoolean,modeType,signedint,SYM(signedint)); SIGFIELD(readType,SYM(read),readSet); break; default: break; } return 0; } ty *overloadedDimensionType() { overloaded *o=new overloaded; o->add(dimensionType()); o->add(IntArray()); return o; } ty *overloadedModeType() { overloaded *o=new overloaded; o->add(modeType()); o->add(primBoolean()); return o; } ty *ty::virtualFieldGetType(symbol id) { trans::varEntry *v = virtualField(id, 0); return v ? v->getType() : 0; } ty *primitiveTy::virtualFieldGetType(symbol id) { if(kind == ty_file) { if (id == SYM(dimension)) return overloadedDimensionType(); if (id == SYM(line) || id == SYM(csv) || id == SYM(word) || id == SYM(singlereal) || id == SYM(singleint) || id == SYM(signedint)) return overloadedModeType(); if (id == SYM(read)) return readType(); } trans::varEntry *v = virtualField(id, 0); return v ? v->getType() : 0; } #define RETURN_STATIC_BLTIN(func) \ { \ static trans::bltinAccess a(run::func); \ return &a; \ } trans::access *nullTy::castTo(ty *target, caster &) { switch (target->kind) { case ty_array: { RETURN_STATIC_BLTIN(pushNullArray); } case ty_record: { RETURN_STATIC_BLTIN(pushNullRecord); } case ty_function: { RETURN_STATIC_BLTIN(pushNullFunction); } default: return 0; } } trans::access *array::initializer() { RETURN_STATIC_BLTIN(emptyArray) } ty *array::pushType() { if (pushtype == 0) pushtype = new function(celltype,formal(celltype,SYM(x))); return pushtype; } ty *array::popType() { if (poptype == 0) poptype = new function(celltype); return poptype; } ty *array::appendType() { if (appendtype == 0) appendtype = new function(primVoid(),formal(this,SYM(a))); return appendtype; } ty *array::insertType() { if (inserttype == 0) { function *f=new function(primVoid(),formal(primInt(),SYM(i))); f->addRest(this); inserttype = f; } return inserttype; } ty *array::deleteType() { if (deletetype == 0) deletetype = new function(primVoid(),formal(primInt(),SYM(i),true), formal(primInt(),SYM(j),true)); return deletetype; } ty *initializedType() { return new function(primBoolean(),formal(primInt(),SYM(i))); } #define SIGFIELDLIST \ ASIGFIELD(initialized, SYM(initialized), arrayInitialized); \ ASIGFIELD(push, SYM(push), arrayPush); \ ASIGFIELD(pop, SYM(pop), arrayPop); \ ASIGFIELD(append, SYM(append), arrayAppend); \ ASIGFIELD(insert, SYM(insert), arrayInsert); \ ASIGFIELD(delete, SYM(delete), arrayDelete); \ ty *array::virtualFieldGetType(symbol id) { #define ASIGFIELD(name, sym, func) \ if (id == sym) \ return name##Type(); SIGFIELDLIST #undef ASIGFIELD return ty::virtualFieldGetType(id); } trans::varEntry *array::virtualField(symbol id, signature *sig) { FIELD(primInt, SYM(length), arrayLength); FIELD(IntArray, SYM(keys), arrayKeys); RWFIELD(primBoolean, SYM(cyclic), arrayCyclicFlag, arraySetCyclicFlag); #define ASIGFIELD(name, sym, func) DSIGFIELD(name, sym, func) SIGFIELDLIST #undef ASIGFIELD // Fall back on base class to handle no match. return ty::virtualField(id, sig); } #undef SIGFIELDLIST void printFormal(ostream& out, const formal& f, bool keywordOnly) { if (f.Explicit) out << "explicit "; if (f.name) f.t->printVar(out, keywordOnly ? "keyword "+(string)(f.name) : f.name); else f.t->print(out); if (f.defval) out << "="; } ostream& operator<< (ostream& out, const formal& f) { #if 0 if (f.Explicit) out << "explicit "; if (f.name) f.t->printVar(out,f.name); else f.t->print(out); if (f.defval) out << "="; #endif printFormal(out, f, false); return out; } bool equivalent(const formal& f1, const formal& f2) { // Just test the types. // This cannot be used on rest formal with types equal to NULL. return equivalent(f1.t,f2.t); } bool argumentEquivalent(const formal &f1, const formal& f2) { if (f1.name == f2.name) { if (f1.t == 0) return f2.t == 0; else if (f2.t == 0) return false; return f1.t->kind != ty_overloaded && f2.t->kind != ty_overloaded && equivalent(f1.t, f2.t); } else return false; } ostream& operator<< (ostream& out, const signature& s) { if (s.isOpen) { out << "()"; return out; } out << "("; for (size_t i = 0; i < s.formals.size(); ++i) { if (i > 0) out << ", "; printFormal(out, s.getFormal(i), s.formalIsKeywordOnly(i)); } if (s.rest.t) { if (!s.formals.empty()) out << " "; out << "... " << s.rest; } out << ")"; return out; } // Equivalence by design does not look at the presence of default values. bool equivalent(const signature *s1, const signature *s2) { if (s1 == s2) return true; // Handle null signature if (s1 == 0 || s2 == 0) return false; // Two open signatures are always equivalent, as the formals are ignored. if (s1->isOpen) return s2->isOpen; else if (s2->isOpen) return false; if (s1->formals.size() != s2->formals.size()) return false; if (!std::equal(s1->formals.begin(),s1->formals.end(),s2->formals.begin(), (bool (*)(const formal&,const formal&)) equivalent)) return false; if (s1->rest.t) return s2->rest.t && equivalent(s1->rest, s2->rest); else return s2->rest.t == 0; } bool argumentEquivalent(const signature *s1, const signature *s2) { // Handle null signature if (s1 == 0) return s2 == 0; else if (s2 == 0) return false; if (s1->formals.size() != s2->formals.size()) return false; return std::equal(s1->formals.begin(),s1->formals.end(),s2->formals.begin(), (bool (*)(const formal&,const formal&)) argumentEquivalent) && argumentEquivalent(s1->rest, s2->rest); } size_t signature::hash() const { size_t x=2038; for (formal_vector::const_iterator i=formals.begin(); i!=formals.end(); ++i) x=x*0xFAEC+i->t->hash(); if (rest.t) x=x*0xACED +rest.t->hash(); return x; } trans::access *function::initializer() { RETURN_STATIC_BLTIN(pushNullFunction); } #if 0 ty *function::stripDefaults() { function *f = new function(result); Int n = sig.getNumFormals(); for (Int i = 0; i < n; ++i) f->add(sig.getFormal(i), 0); return f; } #endif // Only add a type with a signature distinct from the ones currently // in the overloaded type. void overloaded::addDistinct(ty *t, bool special) { if (t->kind == ty_overloaded) { overloaded *ot = (overloaded *)t; for (ty_vector::iterator st = ot->sub.begin(); st != ot->sub.end(); ++st) { this->addDistinct(*st, special); } } else { for (ty_vector::iterator st = this->sub.begin(); st != this->sub.end(); ++st) { if (equivalent(t, *st, special)) return; } // Nonequivalent in signature - add it. this->add(t); } } ty *overloaded::signatureless() { for(ty_vector::iterator t = sub.begin(); t != sub.end(); ++t) if ((*t)->getSignature()==0) return *t; return 0; } bool overloaded::castable(ty *target, caster &c) { for(ty_vector::iterator s = sub.begin(); s != sub.end(); ++s) if (c.castable(target,*s)) return true; return false; } bool equivalent(const ty *t1, const ty *t2) { // The same pointer must point to the same type. if (t1 == t2) return true; // Ensure if an overloaded type is compared to a non-overloaded one, that the // overloaded type's method is called. if (t2->kind == ty_overloaded) return t2->equiv(t1); if (t1->kind == ty_overloaded) return t1->equiv(t2); // Outside of overloaded types, different kinds mean different types. if (t1->kind != t2->kind) return false; return t1->equiv(t2); } bool equivalent(const ty *t1, const ty *t2, bool special) { return special ? equivalent(t1, t2) : equivalent(t1->getSignature(), t2->getSignature()); } #undef FIELD #undef RWFIELD #undef SIGFIELD #undef DSIGFIELD } // namespace types asymptote-2.37/types.h000066400000000000000000000360141265434602500150220ustar00rootroot00000000000000/***** * types.h * Andy Hammerlindl 2002/06/20 * * Used by the compiler as a way to keep track of the type of a variable * or expression. * *****/ #ifndef TYPES_H #define TYPES_H #include #include #include #include "errormsg.h" #include "symbol.h" #include "common.h" #include "util.h" using std::ostream; using sym::symbol; // Forward declaration. namespace trans { class access; class varEntry; } namespace absyntax { class varinit; extern varinit *Default; } namespace types { enum ty_kind { ty_null, ty_record, // "struct" in Asymptote language ty_function, ty_overloaded, #define PRIMITIVE(name,Name,asyName) ty_##name, #define PRIMERROR #include "primitives.h" #undef PRIMERROR #undef PRIMITIVE ty_array }; // Forward declarations. class ty; struct signature; typedef mem::vector ty_vector; typedef ty_vector::iterator ty_iterator; // Checks if two types are equal in the sense of the language. // That is primitive types are equal if they are the same kind. // Structures are equal if they come from the same struct definition. // Arrays are equal if their cell types are equal. bool equivalent(const ty *t1, const ty *t2); // If special is true, this is the same as above. If special is false, just the // signatures are compared. bool equivalent(const ty *t1, const ty *t2, bool special); class caster { public: virtual ~caster() {} virtual trans::access *operator() (ty *target, ty *source) = 0; virtual bool castable(ty *target, ty *source) = 0; }; class ty : public gc { public: const ty_kind kind; ty(ty_kind kind) : kind(kind) {} virtual ~ty(); virtual void print (ostream& out) const; virtual void printVar (ostream& out, string name) const { print(out); out << " " << name; } // Returns true if the type is a user-defined type or the null type. // While the pair, path, etc. are stored by reference, this is // transparent to the user. virtual bool isReference() { return true; } virtual signature *getSignature() { return 0; } virtual const signature *getSignature() const { return 0; } virtual bool primitive() { return false; } bool isError() const { return kind == ty_error; } bool isNotError() const { return !isError(); } // The following are only used by the overloaded type, but it is so common // to test for an overloaded type then iterate over its types, that this // allows the code: // if (t->isOverloaded()) { // for (ty_iterator i = t->begin(); i != t->end(); ++i) { // ... // } // } // For speed reasons, only begin has an assert to test if t is overloaded. bool isOverloaded() const { return kind == ty_overloaded; } bool isNotOverloaded() const { return !isOverloaded(); } ty_iterator begin(); ty_iterator end(); // If a default initializer is not stored in the environment, the abstract // syntax asks the type if it has a "default" default initializer, by calling // this method. virtual trans::access *initializer() { return 0; } // If a cast function is not stored in the environment, ask the type itself. // This handles null->record casting, and the like. The caster is used as a // callback to the environment for casts of subtypes. virtual trans::access *castTo(ty *, caster &) { return 0; } // Just checks if a cast is possible. virtual bool castable(ty *target, caster &c) { return castTo(target, c); } // For pair's x and y, and array's length, this is a special type of // "field". // In actually, it returns a function which takes the object as its // parameter and returns the necessary result. // These should not have public permission, as modifying them would // have strange results. virtual trans::varEntry *virtualField(symbol, signature *) { return 0; } // varGetType for virtual fields. // Unless you are using functions for virtual fields, the base implementation // should work fine. virtual ty *virtualFieldGetType(symbol id); #if 0 // Returns the type. In case of functions, return the equivalent type // but with no default values for parameters. virtual ty *stripDefaults() { return this; } #endif // Returns true if the other type is equivalent to this one. // The general function equivalent should be preferably used, as it properly // handles overloaded type comparisons. virtual bool equiv(const ty *other) const { return this==other; } // Returns a number for the type for use in a hash table. Equivalent types // must yield the same number. virtual size_t hash() const = 0; }; class primitiveTy : public ty { public: primitiveTy(ty_kind kind) : ty(kind) {} bool primitive() { return true; } bool isReference() { return false; } ty *virtualFieldGetType(symbol ); trans::varEntry *virtualField(symbol, signature *); bool equiv(const ty *other) const { return this->kind==other->kind; } size_t hash() const { return (size_t)kind + 47; } }; class nullTy : public primitiveTy { public: nullTy() : primitiveTy(ty_null) {} bool isReference() { return true; } trans::access *castTo(ty *target, caster &); size_t hash() const { return (size_t)kind + 47; } }; // Ostream output, just defer to print. inline ostream& operator<< (ostream& out, const ty& t) { t.print(out); return out; } struct array : public ty { ty *celltype; ty *pushtype; ty *poptype; ty *appendtype; ty *inserttype; ty *deletetype; array(ty *celltype) : ty(ty_array), celltype(celltype), pushtype(0), poptype(0), appendtype(0), inserttype(0), deletetype(0) {} virtual bool isReference() { return true; } bool equiv(const ty *other) const { return other->kind==ty_array && equivalent(this->celltype,((array *)other)->celltype); } size_t hash() const { return 1007 * celltype->hash(); } Int depth() { if (array *cell=dynamic_cast(celltype)) return cell->depth() + 1; else return 1; } void print(ostream& out) const { out << *celltype << "[]"; } ty *pushType(); ty *popType(); ty *appendType(); ty *insertType(); ty *deleteType(); // Initialize to an empty array by default. trans::access *initializer(); // NOTE: General vectorization of casts would be here. // Add length and push as virtual fields. ty *virtualFieldGetType(symbol id); trans::varEntry *virtualField(symbol id, signature *sig); }; /* Base types */ #define PRIMITIVE(name,Name,asyName) \ ty *prim##Name(); \ ty *name##Array(); \ ty *name##Array2(); \ ty *name##Array3(); #define PRIMERROR #include "primitives.h" #undef PRIMERROR #undef PRIMITIVE ty *primNull(); struct formal { ty *t; symbol name; bool defval; bool Explicit; formal(ty *t, symbol name=symbol::nullsym, bool optional=false, bool Explicit=false) : t(t), name(name), defval(optional), Explicit(Explicit) {} // string->symbol translation is costly if done too many times. This // constructor has been disabled to make this cost more visible to the // programmer. #if 0 formal(ty *t, const char *name, bool optional=false, bool Explicit=false) : t(t), name(symbol::trans(name)), defval(optional ? absyntax::Default : 0), Explicit(Explicit) {} #endif friend ostream& operator<< (ostream& out, const formal& f); }; bool equivalent(const formal& f1, const formal& f2); bool argumentEquivalent(const formal &f1, const formal& f2); typedef mem::vector formal_vector; // Holds the parameters of a function and if they have default values // (only applicable in some cases). struct signature : public gc { formal_vector formals; // The number of keyword-only formals. These formals always come after the // regular formals. size_t numKeywordOnly; // Formal for the rest parameter. If there is no rest parameter, then the // type is null. formal rest; bool isOpen; signature() : numKeywordOnly(0), rest(0), isOpen(false) {} static const struct OPEN_t {} OPEN; explicit signature(OPEN_t) : numKeywordOnly(0), rest(0), isOpen(true) {} signature(signature &sig) : formals(sig.formals), numKeywordOnly(sig.numKeywordOnly), rest(sig.rest), isOpen(sig.isOpen) {} virtual ~signature() {} void add(formal f) { formals.push_back(f); } void addKeywordOnly(formal f) { add(f); ++numKeywordOnly; } void addRest(formal f) { rest=f; } bool hasRest() const { return rest.t; } size_t getNumFormals() const { return rest.t ? formals.size() + 1 : formals.size(); } formal& getFormal(size_t n) { assert(n < formals.size()); return formals[n]; } const formal& getFormal(size_t n) const { assert(n < formals.size()); return formals[n]; } formal& getRest() { return rest; } const formal& getRest() const { return rest; } bool formalIsKeywordOnly(size_t n) const { assert(n < formals.size()); return n >= formals.size() - numKeywordOnly; } friend ostream& operator<< (ostream& out, const signature& s); friend bool equivalent(const signature *s1, const signature *s2); // Check if a signature of argument types (as opposed to formal parameters) // are equivalent. Here, the arguments, if named, must have the same names, // and (for simplicity) no overloaded arguments are allowed. friend bool argumentEquivalent(const signature *s1, const signature *s2); #if 0 friend bool castable(signature *target, signature *source); friend Int numFormalsMatch(signature *s1, signature *s2); #endif size_t hash() const; }; struct function : public ty { ty *result; signature sig; function(ty *result) : ty(ty_function), result(result) {} function(ty *result, signature::OPEN_t) : ty(ty_function), result(result), sig(signature::OPEN) {} function(ty *result, signature *sig) : ty(ty_function), result(result), sig(*sig) {} function(ty *result, formal f1) : ty(ty_function), result(result) { add(f1); } function(ty *result, formal f1, formal f2) : ty(ty_function), result(result) { add(f1); add(f2); } function(ty *result, formal f1, formal f2, formal f3) : ty(ty_function), result(result) { add(f1); add(f2); add(f3); } function(ty *result, formal f1, formal f2, formal f3, formal f4) : ty(ty_function), result(result) { add(f1); add(f2); add(f3); add(f4); } virtual ~function() {} void add(formal f) { sig.add(f); } void addRest(formal f) { sig.addRest(f); } virtual bool isReference() { return true; } bool equiv(const ty *other) const { if (other->kind==ty_function) { function *that=(function *)other; return equivalent(this->result,that->result) && equivalent(&this->sig,&that->sig); } else return false; } size_t hash() const { return sig.hash()*0x1231+result->hash(); } void print(ostream& out) const { out << *result << sig; } void printVar (ostream& out, string name) const { result->printVar(out,name); out << sig; } ty *getResult() { return result; } signature *getSignature() { return &sig; } const signature *getSignature() const { return &sig; } #if 0 ty *stripDefaults(); #endif // Initialized to null. trans::access *initializer(); }; // This is used in getType expressions when an overloaded variable is accessed. class overloaded : public ty { public: ty_vector sub; // Warning: The venv endScope routine relies heavily on the current // implementation of overloaded. public: overloaded() : ty(ty_overloaded) {} overloaded(ty *t) : ty(ty_overloaded) { add(t); } virtual ~overloaded() {} bool equiv(const ty *other) const { for(ty_vector::const_iterator i=sub.begin();i!=sub.end();++i) if (equivalent(*i,other)) return true; return false; } size_t hash() const { // Overloaded types should not be hashed. assert(False); return 0; } void add(ty *t) { if (t->kind == ty_overloaded) { overloaded *ot = (overloaded *)t; copy(ot->sub.begin(), ot->sub.end(), inserter(this->sub, this->sub.end())); } else sub.push_back(t); } // Only add a type distinct from the ones currently in the overloaded type. // If special is false, just the distinct signatures are added. void addDistinct(ty *t, bool special=false); // If there are less than two overloaded types, the type isn't really // overloaded. This gives a more appropriate type in this case. ty *simplify() { switch (sub.size()) { case 0: return 0; case 1: { return sub.front(); } default: return new overloaded(*this); } } // Returns the signature-less type of the set. ty *signatureless(); // True if one of the subtypes is castable. bool castable(ty *target, caster &c); size_t size() const { return sub.size(); } // Use default printing for now. }; inline ty_iterator ty::begin() { assert(this->isOverloaded()); return ((overloaded *)this)->sub.begin(); } inline ty_iterator ty::end() { return ((overloaded *)this)->sub.end(); } // This is used to encapsulate iteration over the subtypes of an overloaded // type. The base method need only be implemented to handle non-overloaded // types. class collector { public: virtual ~collector() {} virtual ty *base(ty *target, ty *source) = 0; virtual ty *collect(ty *target, ty *source) { if (overloaded *o=dynamic_cast(target)) { ty_vector &sub=o->sub; overloaded *oo=new overloaded; for(ty_vector::iterator x = sub.begin(); x != sub.end(); ++x) { types::ty *t=collect(*x, source); if (t) oo->add(t); } return oo->simplify(); } else if (overloaded *o=dynamic_cast(source)) { ty_vector &sub=o->sub; overloaded *oo=new overloaded; for(ty_vector::iterator y = sub.begin(); y != sub.end(); ++y) { // NOTE: A possible speed optimization would be to replace this with a // call to base(), but this is only correct if we can guarantee that an // overloaded type has no overloaded sub-types. types::ty *t=collect(target, *y); if (t) oo->add(t); } return oo->simplify(); } else return base(target, source); } }; class tester { public: virtual ~tester() {} virtual bool base(ty *target, ty *source) = 0; virtual bool test(ty *target, ty *source) { if (overloaded *o=dynamic_cast(target)) { ty_vector &sub=o->sub; for(ty_vector::iterator x = sub.begin(); x != sub.end(); ++x) if (test(*x, source)) return true; return false; } else if (overloaded *o=dynamic_cast(source)) { ty_vector &sub=o->sub; for(ty_vector::iterator y = sub.begin(); y != sub.end(); ++y) if (base(target, *y)) return true; return false; } else return base(target, source); } }; } // namespace types GC_DECLARE_PTRFREE(types::primitiveTy); GC_DECLARE_PTRFREE(types::nullTy); #endif asymptote-2.37/util.cc000066400000000000000000000227441265434602500147760ustar00rootroot00000000000000/***** * util.cc * John Bowman * * A place for useful utility functions. *****/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "util.h" #include "settings.h" #include "errormsg.h" #include "camperror.h" #include "interact.h" using namespace settings; bool False=false; namespace vm { void error(const char* message); } #if __GNUC__ #include string demangle(const char *s) { int status; char *demangled = abi::__cxa_demangle(s,NULL,NULL,&status); if (status == 0 && demangled) { string str(demangled); free(demangled); return str; } else if (status == -2) { free(demangled); return s; } else { free(demangled); return string("Unknown(") + s + ")"; } } #else string demangle(const char* s) { return s; } #endif char *Strdup(string s) { size_t size=s.size()+1; char *dest=new(UseGC) char[size]; std::memcpy(dest,s.c_str(),size*sizeof(char)); return dest; } char *StrdupNoGC(string s) { size_t size=s.size()+1; char *dest=new char[size]; std::memcpy(dest,s.c_str(),size*sizeof(char)); return dest; } char *StrdupMalloc(string s) { size_t size=s.size()+1; char *dest=(char *) std::malloc(size); std::memcpy(dest,s.c_str(),size*sizeof(char)); return dest; } string stripDir(string name) { size_t p; #ifdef __MSDOS__ p=name.rfind('\\'); if(p < string::npos) name.erase(0,p+1); #endif p=name.rfind('/'); if(p < string::npos) name.erase(0,p+1); return name; } string stripFile(string name) { size_t p; bool dir=false; #ifdef __MSDOS__ p=name.rfind('\\'); if(p < string::npos) { dir=true; while(p > 0 && name[p-1] == '\\') --p; name.erase(p+1); } #endif p=name.rfind('/'); if(p < string::npos) { dir=true; while(p > 0 && name[p-1] == '/') --p; name.erase(p+1); } return dir ? name : ""; } string stripExt(string name, const string& ext) { string suffix="."+ext; size_t p=name.rfind(suffix); size_t n=suffix.length(); if(n == 1 || p == name.length()-n) return name.substr(0,p); else return name; } void backslashToSlash(string& s) { size_t p; while((p=s.find('\\')) < string::npos) s[p]='/'; } void spaceToUnderscore(string& s) { size_t p; while((p=s.find(' ')) < string::npos) s[p]='_'; } string Getenv(const char *name, bool msdos) { char *s=getenv(name); if(!s) return ""; string S=string(s); if(msdos) backslashToSlash(S); return S; } void writeDisabled() { camp::reportError("Write to other directories disabled; override with option -globalwrite"); } string cleanpath(string name) { string dir=stripFile(name); name=stripDir(name); spaceToUnderscore(name); return dir+name; } string outpath(string name) { bool global=globalwrite(); string dir=stripFile(name); if(global && !dir.empty()) return name; string outdir=stripFile(outname()); if(!(global || dir.empty() || dir == outdir)) writeDisabled(); return outdir+stripDir(name); } string buildname(string name, string suffix, string aux) { name=stripExt(outpath(name),defaultformat())+aux; if(!suffix.empty()) name += "."+suffix; return name; } string auxname(string filename, string suffix) { return buildname(filename,suffix,"_"); } sighandler_t Signal(int signum, sighandler_t handler) { struct sigaction action,oldaction; action.sa_handler=handler; sigemptyset(&action.sa_mask); action.sa_flags=0; return sigaction(signum,&action,&oldaction) == 0 ? oldaction.sa_handler : SIG_ERR; } void push_split(mem::vector& a, const string& S) { const char *p=S.c_str(); string s; char c; while((c=*(p++))) { if(c == ' ') { if(s.size() > 0) { a.push_back(s); s.clear(); } } else s += c; } if(s.size() > 0) a.push_back(s); } char **args(const mem::vector& s, bool quiet) { size_t count=s.size(); char **argv=NULL; argv=new char*[count+1]; for(size_t i=0; i < count; ++i) argv[i]=StrdupNoGC(s[i]); if(!quiet && settings::verbose > 1) { cerr << argv[0]; for(size_t i=1; i < count; ++i) cerr << " " << argv[i]; cerr << endl; } argv[count]=NULL; return argv; } void execError(const char *command, const char *hint, const char *application) { cerr << "Cannot execute " << command << endl; if(*application == 0) application=hint; if(hint) { string s=string(hint); transform(s.begin(), s.end(), s.begin(), toupper); cerr << "Please put in a file " << getSetting("config") << ": " << endl << endl << "import settings;" << endl << hint << "=\"LOCATION\";" << endl << endl << "where LOCATION specifies the location of " << application << "." << endl << endl << "Alternatively, set the environment variable ASYMPTOTE_" << s << endl << "or use the command line option -" << hint << "=\"LOCATION\". For further details, see" << endl << "http://asymptote.sourceforge.net/doc/Configuring.html" << endl << "http://asymptote.sourceforge.net/doc/Search-paths.html" << endl; } } // quiet: 0=none; 1=suppress stdout; 2=suppress stdout+stderr. int System(const mem::vector &command, int quiet, bool wait, const char *hint, const char *application, int *ppid) { int status; cout.flush(); // Flush stdout to avoid duplicate output. char **argv=args(command); int pid=fork(); if(pid == -1) camp::reportError("Cannot fork process"); if(pid == 0) { if(interact::interactive) signal(SIGINT,SIG_IGN); if(quiet) { static int null=creat("/dev/null",O_WRONLY); close(STDOUT_FILENO); dup2(null,STDOUT_FILENO); if(quiet == 2) { close(STDERR_FILENO); dup2(null,STDERR_FILENO); } } if(argv) { execvp(argv[0],argv); execError(argv[0],hint,application); _exit(-1); } } if(ppid) *ppid=pid; for(;;) { if(waitpid(pid, &status, wait ? 0 : WNOHANG) == -1) { if(errno == ECHILD) return 0; if(errno != EINTR) { if(quiet < 2) { ostringstream msg; msg << "Command failed: "; for(size_t i=0; i < command.size(); ++i) msg << command[i] << " "; camp::reportError(msg); } } } else { if(!wait) return 0; if(WIFEXITED(status)) { if(argv) { char **p=argv; char *s; while((s=*(p++)) != NULL) delete [] s; delete [] argv; } return WEXITSTATUS(status); } else { if(quiet < 2) { ostringstream msg; msg << "Command exited abnormally: "; for(size_t i=0; i < command.size(); ++i) msg << command[i] << " "; camp::reportError(msg); } } } } } string stripblanklines(const string& s) { string S=string(s); bool blank=true; const char *t=S.c_str(); size_t len=S.length(); for(size_t i=0; i < len; i++) { if(t[i] == '\n') { if(blank) S[i]=' '; else blank=true; } else if(t[i] != '\t' && t[i] != ' ') blank=false; } return S; } char *startpath=NULL; void noPath() { camp::reportError("Cannot get current path"); } char *getPath(char *p) { #ifdef MAXPATHLEN static size_t size = MAXPATHLEN; #else static size_t size = 1024; #endif if(!p) p=new(UseGC) char[size]; if(!p) noPath(); else while(getcwd(p,size) == NULL) { if(errno == ERANGE) { size *= 2; p=new(UseGC) char[size]; } else {noPath(); p=NULL;} } return p; } const char *setPath(const char *s, bool quiet) { if(startpath == NULL) startpath=getPath(startpath); if(s == NULL || *s == 0) s=startpath; int rc=chdir(s); if(rc != 0) { ostringstream buf; buf << "Cannot change to directory '" << s << "'"; camp::reportError(buf); } char *p=getPath(); if(p && (!interact::interactive || quiet) && verbose > 1) cout << "cd " << p << endl; return p; } void push_command(mem::vector& a, const string& s) { a.push_back(s); #ifdef __MSDOS__ if(s == "cmd") { a.push_back("/c"); a.push_back("start"); a.push_back("\"\""); } #endif } void popupHelp() { // If the popped-up help is already running, pid stores the pid of the viewer. static int pid=0; // Status is ignored. static int status=0; // If the help viewer isn't running (or its last run has termined), launch the // viewer again. if (pid==0 || (waitpid(pid, &status, WNOHANG) == pid)) { mem::vector cmd; push_command(cmd,getSetting("pdfviewer")); string viewerOptions=getSetting("pdfviewerOptions"); if(!viewerOptions.empty()) cmd.push_back(viewerOptions); cmd.push_back(docdir+dirsep+"asymptote.pdf"); status=System(cmd,0,false,"pdfviewer","your PDF viewer",&pid); } } const char *intrange="integer argument is outside valid range"; const char *uintrange="integer argument is outside valid unsigned range"; unsigned unsignedcast(Int n) { if(n < 0 || n/2 > INT_MAX) vm::error(uintrange); return (unsigned) n; } unsignedInt unsignedIntcast(Int n) { if(n < 0) vm::error(uintrange); return (unsignedInt) n; } int intcast(Int n) { if(Abs(n) > INT_MAX) vm::error(intrange); return (int) n; } Int Intcast(unsignedInt n) { if(n > (unsignedInt) Int_MAX) vm::error(intrange); return (Int) n; } asymptote-2.37/util.h000066400000000000000000000102471265434602500146330ustar00rootroot00000000000000/***** * util.h * Andy Hammerlindl 2004/05/10 * * A place for useful utility functions. *****/ #ifndef UTIL_H #define UTIL_H #include #include #include #include #include "common.h" #include // Demangle a typeid name (if the proper library is installed. string demangle(const char *s); // Duplicate a string. char *Strdup(string s); char *StrdupNoGC(string s); char *StrdupMalloc(string s); // Strip the directory from a filename. string stripDir(string name); // Strip the file from a filename, returning the directory. string stripFile(string name); // Strip the extension from a filename. string stripExt(string name, const string& suffix=""); void writeDisabled(); // Replace spaces in file part of name with underscores. string cleanpath(string name); // Construct the full output path. string outpath(string name); // Construct a filename from the original, adding aux at the end, and // changing the suffix. string buildname(string filename, string suffix="", string aux=""); // Construct an alternate filename for a temporary file in the current // directory. string auxname(string filename, string suffix=""); // Cast argument to a string. template string String(T x) { ostringstream buf; buf << x; return buf.str(); } typedef void (*sighandler_t)(int); // Portable signal (sigaction wrapper). sighandler_t Signal(int signum, sighandler_t handler); // Split string S and push the pieces onto vector a. void push_split(mem::vector& a, const string& S); // Wrapper to append /c start "" to MSDOS cmd. void push_command(mem::vector& a, const string& s); // Return an argv array corresponding to the fields in command delimited // by spaces not within matching single quotes. char **args(const mem::vector &args, bool quiet=false); // Similar to the standard system call except allows interrupts and does // not invoke a shell. int System(const mem::vector &command, int quiet=0, bool wait=true, const char *hint=NULL, const char *application="", int *pid=NULL); #if defined(__DECCXX_LIBCXX_RH70) extern "C" int kill(pid_t pid, Int sig) throw(); extern "C" char *strsignal(Int sig); extern "C" double asinh(double x); extern "C" double acosh(double x); extern "C" double atanh(double x); extern "C" double cbrt(double x); extern "C" double erf(double x); extern "C" double erfc(double x); extern "C" double tgamma(double x); extern "C" double remainder(double x, double y); extern "C" double hypot(double x, double y) throw(); extern "C" double jn(Int n, double x); extern "C" double yn(Int n, double x); #endif #if defined(__DECCXX_LIBCXX_RH70) || defined(__CYGWIN__) extern "C" int snprintf(char *str, size_t size, const char *format,...); extern "C" int isnan(double); #include extern "C" FILE *fdopen(int fd, const char *mode); extern "C" int fileno(FILE *); extern "C" char *strptime(const char *s, const char *format, struct tm *tm); extern "C" int setenv(const char *name, const char *value, int overwrite); extern "C" int unsetenv(const char *name); #endif extern bool False; // Strip blank lines (which would break the bidirectional TeX pipe) string stripblanklines(const string& s); const char *startPath(); const char* setPath(const char *s, bool quiet=false); const char *changeDirectory(const char *s); extern char *startpath; void backslashToSlash(string& s); void spaceToUnderscore(string& s); string Getenv(const char *name, bool msdos); char *getPath(char *p=NULL); void execError(const char *command, const char *hint, const char *application); // This invokes a viewer to display the manual. Subsequent calls will only // pop-up a new viewer if the old one has been closed. void popupHelp(); #ifdef __CYGWIN__ inline long long llabs(long long x) {return x >= 0 ? x : -x;} extern "C" char *initstate (unsigned seed, char *state, size_t size); extern "C" long random (void); #endif inline Int Abs(Int x) { #ifdef HAVE_LONG_LONG return llabs(x); #else #ifdef HAVE_LONG return labs(x); #else return abs(x); #endif #endif } unsigned unsignedcast(Int n); unsignedInt unsignedIntcast(Int n); int intcast(Int n); Int Intcast(unsignedInt n); #endif asymptote-2.37/varinit.cc000066400000000000000000000036721265434602500154740ustar00rootroot00000000000000/***** * varinit.cc * Andy Hammerlindl 2005/07/01 * * Variable initializer are syntax that finish code such as * int var = ... * As such, they are translated to yield a certain type, the type of the * variable. Expressions are a special case that can be translated without an * associated variable or its type. *****/ #include "varinit.h" #include "coenv.h" #include "runtime.h" #include "runarray.h" namespace absyntax { using namespace types; using namespace trans; void definit::prettyprint(ostream &out, Int indent) { prettyname(out, "definit",indent); } void definit::transToType(coenv &e, types::ty *target) { if (target->kind != ty_error) { access *a=e.e.lookupInitializer(target); if (a) a->encode(CALL, getPos(), e.c); else { em.error(getPos()); em << "no default initializer for type '" << *target << "'"; } } } void arrayinit::prettyprint(ostream &out, Int indent) { prettyname(out, "arrayinit",indent); for (mem::list::iterator p = inits.begin(); p != inits.end(); ++p) (*p)->prettyprint(out, indent+2); if (rest) rest->prettyprint(out, indent+1); } void arrayinit::transMaker(coenv &e, Int size, bool rest) { // Push the number of cells and call the array maker. e.c.encode(inst::intpush, size); e.c.encode(inst::builtin, rest ? run::newAppendedArray : run::newInitializedArray); } void arrayinit::transToType(coenv &e, types::ty *target) { types::ty *celltype; if (target->kind != types::ty_array) { em.error(getPos()); em << "array initializer used for non-array"; celltype = types::primError(); } else { celltype = ((types::array *)target)->celltype; } // Push the values on the stack. for (mem::list::iterator p = inits.begin(); p != inits.end(); ++p) (*p)->transToType(e, celltype); if (rest) rest->transToType(e, target); transMaker(e, (Int)inits.size(), (bool)rest); } } // namespace absyntax asymptote-2.37/varinit.h000066400000000000000000000037351265434602500153360ustar00rootroot00000000000000/***** * varinit.h * Andy Hammerlindl 2005/07/01 * * Variable initializers are syntax that finish code such as * Int var = ... * As such, they are translated to yield a certain type, the type of the * variable. Expressions are a special case that can be translated without an * associated variable or its type. *****/ #ifndef VARINIT_H #define VARINIT_H #include "types.h" #include "symbol.h" #include "absyn.h" namespace absyntax { using trans::coenv; using trans::access; using sym::symbol; using types::array; class varinit : public absyn { public: varinit(position pos) : absyn(pos) {} // This determines what instruction are needed to put the associated // value onto the stack, then adds those instructions to the current // lambda in e. // In some expressions and initializers, the target type needs to be // known in order to translate properly. For most expressions, this is // kept to a minimum. // For expression, this also allows an implicit cast, hence the name. virtual void transToType(coenv &e, types::ty *target) = 0; }; // A default initializer. For example: // int a; // is in some sense equivalent to // int a=0; // where the definit for Int is a function that returns 0. class definit : public varinit { public: definit(position pos) : varinit(pos) {} void prettyprint(ostream &out, Int indent); void transToType(coenv &e, types::ty *target); }; class arrayinit : public varinit { mem::list inits; varinit *rest; public: arrayinit(position pos) : varinit(pos), rest(0) {} virtual ~arrayinit() {} void prettyprint(ostream &out, Int indent); // Encodes the instructions to make an array from size elements on the stack. static void transMaker(coenv &e, Int size, bool rest); void transToType(coenv &e, types::ty *target); void add(varinit *init) { inits.push_back(init); } void addRest(varinit *init) { rest=init; } friend class joinExp; }; } // namespace absyntax #endif asymptote-2.37/virtualfieldaccess.cc000066400000000000000000000016051265434602500176660ustar00rootroot00000000000000/***** * virtualfieldaccess.cc * Andy Hammerlindl 2009/07/23 * * Implements the access subclass used to read and write virtual fields. *****/ #include "virtualfieldaccess.h" #include "coder.h" namespace trans { void virtualFieldAccess::encode(action act, position pos, coder &e) { switch(act) { case CALL: if (caller) { caller->encode(CALL, pos, e); } else { this->encode(READ, pos, e); e.encode(inst::popcall); } return; case READ: assert(getter); getter->encode(CALL, pos, e); return; case WRITE: if (setter) setter->encode(CALL, pos, e); else { em.error(pos); em << "virtual field is read-only"; } return; } } void virtualFieldAccess::encode(action act, position pos, coder &e, frame *) { e.encode(inst::pop); encode(act, pos, e); } } // namespace trans asymptote-2.37/virtualfieldaccess.h000066400000000000000000000044301265434602500175270ustar00rootroot00000000000000/***** * virtualfieldaccess.h * Andy Hammerlindl 2009/07/23 * * Implements the access subclass used to read and write virtual fields. *****/ #include "access.h" namespace trans { // In code such as // pair z; write(z.x); // to evaluate the expression z.x, first z is pushed onto the stack, then as // it is not a record, instead of accessing its field in the usual way for a // record, a builtin function is called which pops z off the stack and // replaces it with z.x. virtualFieldAccess provides the access for the // virtualField 'x', and 'getter' is the access to the builtin function which // replaces z with z.x. // // If the virtual field z.x were mutable, then setter would access a builtin // function, which pops a real number and then z off of the stack, sets the // z.x to that new value, and puts the value back on the stack. In this case, // pairs are immutable, but other virtual fields may not be. // // Some virtual fields are functions, such as a.push for an array a. In rare // cases, code such as // void f(int) = a.push; // requires an object representing a.push, and so a getter for the field must // be provided. Most of the time, however, these fields are just called. // As an optimization, a caller access can be provided. If this access is // given, then a call to the virtualFieldAccess just translates into a call to // caller. class virtualFieldAccess : public access { access *getter; access *setter; access *caller; public: virtualFieldAccess(access *getter, access *setter = 0, access *caller = 0) : getter(getter), setter(setter) {} virtualFieldAccess(vm::bltin getter, vm::bltin setter = 0, vm::bltin caller = 0) : getter(new bltinAccess(getter)), setter(setter ? new bltinAccess(setter) : 0), caller(caller ? new bltinAccess(caller) : 0) {} void encode(action act, position pos, coder &e); void encode(action act, position pos, coder &e, frame *); // Attempting to WRITE a read-only field will give an error, but if the // error is caught at a higher level, a better error message (including the // name of the field) can be given. This function allows such handling. bool readonly() { return (bool)setter; } }; } // namespace trans asymptote-2.37/vm.h000066400000000000000000000013551265434602500143000ustar00rootroot00000000000000/***** * vm.h * Tom Prince 2005/06/17 * * Interface to the virtual machine. *****/ #ifndef VM_H #define VM_H #include "errormsg.h" namespace vm { struct lambda; class stack; typedef void (*bltin)(stack *s); #ifdef DEBUG_BLTIN // This associates names to bltin functions, so that the output of 'asy -s' // can print the names of the bltin functions that appear in the bytecode. void registerBltin(bltin b, string s); string lookupBltin(bltin b); #define REGISTER_BLTIN(b, s) \ registerBltin((b), (s)) #else #define REGISTER_BLTIN(b, s) #endif void run(lambda *l); position getPos(); void errornothrow(const char* message); void error(const char* message); void error(const ostringstream& message); } // namespace vm #endif // VM_H asymptote-2.37/wce000077500000000000000000000003161265434602500142050ustar00rootroot00000000000000#!/bin/sh echo -n "Testing errors..." ./asy -noautoplain -debug errortest 2> errors.temp result=`diff errors.temp errors` if [ "$result" = "" ]; then echo PASSED. else echo FAILED. echo "$result" exit 1 fi asymptote-2.37/xstream.h000066400000000000000000000144211265434602500153370ustar00rootroot00000000000000/* C++ interface to the XDR External Data Representation I/O routines Version 1.46 Copyright (C) 1999-2007 John C. Bowman This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __xstream_h__ #define __xstream_h__ 1 #ifndef _ALL_SOURCE #define _ALL_SOURCE 1 #endif #include #include #include #define quad_t long long #define u_quad_t unsigned long long #ifdef __CYGWIN__ extern "C" int fseeko(FILE *, off_t, int); extern "C" off_t ftello(FILE *); #define xdr_longlong_t xdr_int64_t #define xdr_u_longlong_t xdr_uint64_t #endif #ifdef _POSIX_SOURCE #undef _POSIX_SOURCE #include #define _POSIX_SOURCE #else #include #endif namespace xdr { class xbyte { unsigned char c; public: xbyte() {} xbyte(unsigned char c0) : c(c0) {} xbyte(int c0) : c((unsigned char) c0) {} xbyte(unsigned int c0) : c((unsigned char) c0) {} int byte() const {return c;} operator unsigned char () const {return c;} }; class xios { public: enum io_state {goodbit=0, eofbit=1, failbit=2, badbit=4}; enum open_mode {in=1, out=2, app=8, trunc=16}; enum seekdir {beg=SEEK_SET, cur=SEEK_CUR, end=SEEK_END}; private: int _state; public: int good() const { return _state == 0; } int eof() const { return _state & eofbit; } int fail() const { return !good();} int bad() const { return _state & badbit; } void clear(int state = 0) {_state=state;} void set(int flag) {_state |= flag;} operator void*() const { return fail() ? (void*)0 : (void*)(-1); } int operator!() const { return fail(); } }; class xstream : public xios { protected: FILE *buf; public: virtual ~xstream() {} xstream() {buf=NULL;} void precision(int) {} xstream& seek(off_t pos, seekdir dir=beg) { if(buf) { clear(); if(fseeko(buf,pos,dir) != 0) set(failbit); } return *this; } off_t tell() { return ftello(buf); } }; #define IXSTREAM(T,N) ixstream& operator >> (T& x) \ {if(!xdr_##N(&xdri, &x)) set(eofbit); return *this;} #define OXSTREAM(T,N) oxstream& operator << (T x) \ {if(!xdr_##N(&xdro, &x)) set(badbit); return *this;} class ixstream : virtual public xstream { protected: XDR xdri; public: void open(const char *filename, open_mode=in) { clear(); buf=fopen(filename,"r"); if(buf) xdrstdio_create(&xdri,buf,XDR_DECODE); else set(badbit); } void close() { if(buf) { #ifndef _CRAY xdr_destroy(&xdri); #endif fclose(buf); buf=NULL; } } ixstream() {} ixstream(const char *filename) {open(filename);} ixstream(const char *filename, open_mode mode) {open(filename,mode);} virtual ~ixstream() {close();} typedef ixstream& (*imanip)(ixstream&); ixstream& operator >> (imanip func) { return (*func)(*this); } IXSTREAM(int,int); IXSTREAM(unsigned int,u_int); IXSTREAM(long,long); IXSTREAM(unsigned long,u_long); IXSTREAM(long long,longlong_t); IXSTREAM(unsigned long long,u_longlong_t); IXSTREAM(short,short); IXSTREAM(unsigned short,u_short); IXSTREAM(char,char); #ifndef _CRAY IXSTREAM(unsigned char,u_char); #endif IXSTREAM(float,float); IXSTREAM(double,double); ixstream& operator >> (xbyte& x) { x=fgetc(buf); if(x.byte() == EOF) set(eofbit); return *this; } }; class oxstream : virtual public xstream { protected: XDR xdro; public: void open(const char *filename, open_mode mode=trunc) { clear(); buf=fopen(filename,(mode & app) ? "a" : "w"); if(buf) xdrstdio_create(&xdro,buf,XDR_ENCODE); else set(badbit); } void close() { if(buf) { #ifndef _CRAY xdr_destroy(&xdro); #endif fclose(buf); buf=NULL; } } oxstream() {} oxstream(const char *filename) {open(filename);} oxstream(const char *filename, open_mode mode) {open(filename,mode);} virtual ~oxstream() {close();} oxstream& flush() {if(buf) fflush(buf); return *this;} typedef oxstream& (*omanip)(oxstream&); oxstream& operator << (omanip func) { return (*func)(*this); } OXSTREAM(int,int); OXSTREAM(unsigned int,u_int); OXSTREAM(long,long); OXSTREAM(unsigned long,u_long); OXSTREAM(long long,longlong_t); OXSTREAM(unsigned long long,u_longlong_t); OXSTREAM(short,short); OXSTREAM(unsigned short,u_short); OXSTREAM(char,char); #ifndef _CRAY OXSTREAM(unsigned char,u_char); #endif OXSTREAM(float,float); OXSTREAM(double,double); oxstream& operator << (xbyte x) { if(fputc(x.byte(),buf) == EOF) set(badbit); return *this; } }; class ioxstream : public ixstream, public oxstream { public: void open(const char *filename, open_mode mode=out) { clear(); if(mode & app) buf=fopen(filename,"a+"); else if(mode & trunc) buf=fopen(filename,"w+"); else if(mode & out) { buf=fopen(filename,"r+"); if(!buf) buf=fopen(filename,"w+"); } else buf=fopen(filename,"r"); if(buf) { xdrstdio_create(&xdri,buf,XDR_DECODE); xdrstdio_create(&xdro,buf,XDR_ENCODE); } else set(badbit); } void close() { if(buf) { #ifndef _CRAY xdr_destroy(&xdri); xdr_destroy(&xdro); #endif fclose(buf); buf=NULL; } } ioxstream() {} ioxstream(const char *filename) {open(filename);} ioxstream(const char *filename, open_mode mode) {open(filename,mode);} virtual ~ioxstream() {close();} }; inline oxstream& endl(oxstream& s) {s.flush(); return s;} inline oxstream& flush(oxstream& s) {s.flush(); return s;} #undef IXSTREAM #undef OXSTREAM } #undef quad_t #endif