MetaPost
MetaPost is a descriptive programming language designed for generating high-quality, scalable vector graphics, particularly for technical and mathematical illustrations in documents.[1] Developed by John D. Hobby and publicly released in January 1995, it adapts the concepts of Donald E. Knuth's Metafont system to produce Encapsulated PostScript (EPS) output rather than bitmap fonts, enabling precise control over shapes via mathematical equations and geometric primitives.[2][1]
The language's core strength lies in its ability to define pictures declaratively, using types such as numbers, coordinate pairs (pairs), paths (including cubic splines), pictures, strings, and booleans, while solving systems of linear equations to position elements automatically based on constraints.[1] It incorporates programming features like variables, expressions, loops, conditionals, and macro definitions, allowing users to create parametric and reusable graphics components in an edit-compile-debug workflow.[1] Unlike Metafont, MetaPost omits font-specific primitives but adds support for PostScript capabilities such as clipping, dashing, shading, and color, with options to output SVG or PNG formats as well.[1]
Hobby's motivation for MetaPost stemmed from challenges in producing mathematical figures for research papers during his work at AT&T Bell Labs, where manual coordinate calculations proved cumbersome; the project began in 1990 after consultation with Knuth, evolving over five years with additions like graph-drawing primitives before its release.[2] Since then, maintenance has been handled by a community team led by Taco Hoekwater, including a 2007 restructuring into frontend and backend libraries (MPlib) for better integration with modern TeX engines like LuaTeX, which allows inline execution without external file generation.[3] This evolution has made MetaPost a staple for creating diagrams in scientific publishing, with ongoing enhancements distributed through the TeX Users Group (TUG).[3]
Overview
Definition and Purpose
MetaPost is a specialized programming language and interpreter for creating precise, scalable vector graphics derived from mathematical descriptions. Developed by John Hobby as an adaptation of Donald Knuth's Metafont system, it shifts the focus from bitmap font generation to producing vector-based output suitable for high-resolution rendering.[1] Unlike general-purpose graphics tools, MetaPost allows shapes and positions to be defined through equations rather than manual pixel placement, enabling reproducible and mathematically consistent results.[4]
The primary purpose of MetaPost is to generate high-quality figures for seamless integration into TeX and LaTeX documents, prioritizing geometric and algebraic specifications over raster-based images. This makes it ideal for technical documentation where precision and scalability are essential, as the output can be embedded directly without loss of quality during typesetting.[3] By leveraging TeX's typesetting engine for labels and text, MetaPost ensures that graphics align perfectly with surrounding content, facilitating the creation of professional publications.[1]
At its core, MetaPost employs parametric descriptions of shapes using equations, such as those for Bézier curves and paths, which permit automatic adjustments for uniformity in style and proportions. This approach allows users to define illustrations by solving systems of equations to determine optimal layouts and intersections.[4] Consequently, it is designed specifically for technical illustrations like diagrams, charts, and schematics in academic and scientific publishing, where exact control over visual elements enhances clarity and fidelity to underlying mathematical concepts.[1]
Key Characteristics
MetaPost employs an imperative programming paradigm, enabling users to define variables of types such as numeric, pair, path, and color, while supporting control structures like for loops, forever loops, conditional if-then-else statements, and macros defined via def or vardef for subroutine-like functionality.[4] This approach allows for algorithmic generation of graphics, where commands sequentially build and manipulate geometric elements.[1]
The system relies on fixed-point arithmetic in its scaled number representation, using 32 bits by default for calculations that provide approximately 10 decimal digits of precision, ensuring reproducible results without floating-point rounding errors.[1] Since version 1.8, an optional 64-bit double-precision floating-point mode has been available, enhancing accuracy for complex computations while maintaining compatibility with the traditional fixed-point model.[1]
MetaPost supports both RGB and CMYK color models, with colors specified as triples or quadruples of numeric values in the range [0,1], allowing for filled paths using commands like fill and withcolor.[1] Text labels can be incorporated via integration with TeX, where labels are typeset externally and positioned within the graphic.[1]
A core strength lies in its mathematical expressiveness, where the system automatically solves linear equations to determine unknowns in path definitions, such as coordinates or tensions in Bézier curves for smooth connections.[1] For instance, path intersections are computed using operators like intersectiontimes, which return parametric times along curves, enabling precise geometric constructions without manual iteration.[4]
MetaPost generates device-independent vector graphics, primarily in Encapsulated PostScript (EPS) format, with options for Scalable Vector Graphics (SVG) since version 1.200 and PNG bitmap output since 1.800, thereby avoiding the resolution limitations inherent in raster-based tools.[1]
Historical Development
MetaPost traces its conceptual foundations to Donald Knuth's Metafont, a programming language developed in the late 1970s and early 1980s specifically for parametric font design in conjunction with the TeX typesetting system.[5] Metafont enables the creation of scalable raster fonts through mathematical descriptions, employing cubic spline curves to define glyph outlines and tension parameters to control the smoothness and curvature of these curves, allowing fonts to adapt parametrically to variations in style, such as weight or slant. This approach emphasized algorithmic generation of letterforms, producing bitmapped output optimized for TeX's rendering needs, and was detailed in Knuth's 1986 book The METAFONTbook.
John Hobby adapted Metafont's core ideas for MetaPost to overcome its limitations in generating scalable graphics beyond font glyphs, shifting the output from bitmap fonts to vector-based PostScript code suitable for illustrations and diagrams.[6] Developed during Hobby's time at AT&T Bell Laboratories starting in 1990, MetaPost was designed to produce high-quality, parametric vector graphics for PostScript printers and devices, addressing the awkwardness of manually computing coordinates for complex figures in research papers.[6] This adaptation expanded Metafont's font-centric focus to general-purpose graphics, incorporating PostScript primitives for features like clipping and shading while retaining the declarative, equation-based programming style.[7]
Central to this lineage are shared concepts in path construction and rendering. Both languages define paths using knots—explicit points—and controls for Bézier cubic splines to create smooth curves, as in Metafont's spline specifications that MetaPost directly borrows for outline generation.[7] Randomization mechanisms, such as Metafont's uniformdeviate and normaldeviate for introducing variations in font instances, persist in MetaPost to enable probabilistic elements in illustrations.[7] Additionally, pen strokes for line styles, controlled by parameters like pencircle in Metafont, are mirrored in MetaPost's pickup and draw commands, allowing customizable stroke widths and shapes to simulate artistic effects.[7] Hobby implemented MetaPost in 1994, publicly releasing it in 1995, to fulfill the need for a Metafont-like tool tailored to vector graphics production.[6]
Creation and Initial Release
MetaPost was developed by John D. Hobby at AT&T Bell Laboratories in the late 1980s and early 1990s, driven by the need for a programmable tool to create precise vector graphics for inclusion in TeX-based documents, especially mathematical illustrations that were challenging to produce with existing methods.[2] Hobby, who had contributed to the original Metafont algorithms alongside Donald Knuth, sought to adapt Metafont's descriptive power for PostScript output, overcoming the limitations of raster-based graphics in high-resolution printing workflows.[8] This motivation arose from practical difficulties in generating complex figures for research papers, where TeX's typesetting strengths needed complementary vector capabilities.[2]
The system's foundational concepts were introduced in Hobby's 1989 article in TUGboat, the newsletter of the TeX Users Group (TUG), which outlined a Metafont-like language producing PostScript code.[8] A comprehensive user's manual followed in 1992 as AT&T Bell Laboratories Computing Science Technical Report 162, providing detailed guidance on implementation. After limited distribution under nondisclosure agreements from 1990 to 1992, MetaPost saw its initial public release in January 1995, distributed freely through TUG and placed in the public domain to encourage adoption within the TeX community.[2] This debut included enhancements like a graph-drawing package, expanding its utility for scientific visualization.[2]
Among its early features, MetaPost offered robust path manipulation with cubic splines for defining smooth, continuous curves that could be joined, filled, or drawn using PostScript-compatible commands such as withpen for ellipse-shaped strokes and withcolor for tinting.[8] It incorporated Metafont's equation-solving mechanisms, allowing linear systems to be resolved implicitly for tasks like computing intersection points between paths via numerical methods, enabling automated adjustments in layouts.[1] TeX label integration was supported through the label command and infont operator, which pulled metrics from TeX font files (TFM) to position text precisely alongside graphics, ensuring typographic consistency with surrounding documents.[8] As a standalone system, it generated encapsulated PostScript (EPS) files directly, facilitating seamless embedding in TeX-generated PDFs or printouts.[9]
Technical Features
Programming Paradigm and Syntax
MetaPost employs a procedural programming paradigm, where programs consist of imperative statements that define variables, perform computations, and generate graphics through sequential execution. This approach, inherited from Metafont, allows users to script vector graphics using structured code rather than interactive drawing tools, emphasizing precision and reproducibility in technical illustrations.[1] The language supports core control structures such as conditional if statements (e.g., if known x then ... fi) and iterative for loops (e.g., for i=1 upto 5: ... endfor), enabling modular and repeatable constructions like grids or patterns.[1]
At its foundation, MetaPost defines several primitive data types to handle geometric and visual elements: numerics for scalar values using fixed-point arithmetic; pairs for 2D coordinates (e.g., (x, y)); paths as parametric curves composed of point sequences; and colors represented in RGB or CMYK models with components ranging from 0 to 1.[1] Variables are declared with type specifiers like numeric x; or path p;, followed by assignments using the := operator (e.g., x := 1;), which supports both initialization and reassignment.[1] Expressions leverage arithmetic operators such as +, -, *, and / for numerics and pairs, with specialized operations like .. for concatenating path segments (e.g., (0,0)..(1,1)).[1]
Path definitions form a cornerstone of the syntax, specifying curves via sequences of points and optional control points for Bézier splines, such as (0,0)..controls (1,1) and (2,0)..cycle to create a closed shape.[1] For code reuse, MetaPost provides macro definitions through vardef for parameterizable procedures with local variables (e.g., vardef sample(x, y) = ... enddef) or def for simpler expansions, facilitating the creation of custom functions like geometric transformations.[1]
A distinctive feature is the built-in equation-solving mechanism, which treats assignments as constraints in linear systems and resolves them declaratively within a block, such as numeric a, b; a + b = 3; 2a = b + 3; solve(a, b);, yielding a=2 and b=1 after execution.[1] Overall, MetaPost's syntax closely parallels Metafont's, adapting its declarative and procedural elements while incorporating PostScript-oriented commands for rendering.[1]
Graphic Primitives and Operations
MetaPost provides a set of fundamental primitives for constructing and manipulating vector graphics, enabling precise control over shapes and their rendering. Paths form the core building blocks, defined as sequences of points connected by straight lines or curves. A path begins with a point and extends using operators such as -- for straight-line segments or .. for cubic Bézier curves, where control points can be implicitly computed or explicitly specified with the controls keyword to adjust curvature tension.[1] For closed shapes, the cycle operator connects the final point back to the starting point, forming polygons or smooth loops.[1] Intersection calculations are supported through functions like intersectiontimes or intersectionpoint, which determine points where two paths cross, facilitating complex constructions such as trimming or joining shapes.[1]
Drawing operations apply these paths to the output picture. The draw command renders a path as an outline, while fill shades the interior of a closed path to create solid regions.[1] Styling options include dashing patterns, achieved via dashed evenly for uniform dash-gap ratios or custom dashpattern specifications like on 3bp off 3bp for precise control.[1] Line width and endpoint shapes are modified using pens, such as pencircle scaled 0.5bp for rounded lines or pensquare scaled 1bp for squared caps, applied through the withpen modifier.[1]
Transformations allow geometric manipulations of paths or entire pictures. The shift operator translates an object by a pair of coordinates, rotate turns it by a specified angle in degrees around the origin, and scale enlarges or reduces it by a uniform factor or anisotropic pairs.[1] These can be composed, such as rotated 45 shifted (1,0), and applied to individual elements or the currentpicture for global effects.[1]
Randomization introduces variability for generating diverse diagrams. The randomseed procedure initializes the pseudorandom number generator with a numeric value, ensuring reproducible sequences, while uniformdeviate(x) produces a random real number between 0 and x for stochastic adjustments in positions or sizes.[1]
Clipping and layering enhance composition. The clip command restricts subsequent drawing to the interior of a cyclic path, masking outlying elements for focused views.[1] Layering is managed through modifiers like withcolor to set fill or stroke hues (e.g., withcolor red) and withpen for stylistic overlays, allowing additive construction onto the currentpicture without explicit z-ordering.[1]
Integration and Output
Compatibility with TeX Systems
MetaPost integrates seamlessly with TeX-based systems by leveraging TeX for typesetting text labels within graphics, enabling high-quality, scalable figures that can be embedded directly into documents. The label and dotlabel commands place text at specified positions relative to paths or points, with the text processed by TeX to ensure typographic consistency. For instance, simple labels use string expressions delimited by dollar signs, such as label("$text$", position), which invokes TeX's typesetting engine.[1] More complex labels, including LaTeX commands or math, employ the btex ... etex construct, like label(btex $\alpha + \beta$ etex, (0,0)), where the content between btex and etex is extracted, typeset by TeX into a DVI file, and converted back into MetaPost via the dvitomp program to generate positioning commands in a .mpx auxiliary file.[1] This process can be configured for LaTeX via the mpost --tex=latex command, which sets the appropriate TeX format and preamble, often using the MPTEXPRE environment variable for custom setups like font selections.[1]
The standard workflow involves compiling a .mp file with the mpost command, which processes the code, handles label typesetting, and outputs PostScript files (e.g., figure.1, figure.2) suitable for inclusion. These files are then incorporated into TeX or LaTeX documents using \includegraphics{figure.1} from the graphicx package in LaTeX or \epsfbox{figure.1} in plain TeX, allowing the graphics to be scaled and positioned within the document flow.[1] MetaPost operates in batch mode by default, enabling the generation of multiple figures from a single run—each enclosed in a beginfig block—producing sequentially numbered output files that can reference unique identifiers, such as labels formatted with numeric counters like label("$Figure " & [decimal](/page/Decimal)(1), [position](/page/Position)) for the first figure, facilitating cross-references in the final document.[1]
MetaPost is compatible with modern TeX engines including pdfTeX, XeTeX, and LuaTeX, which handle the inclusion of PostScript outputs natively or via conversion to PDF. With pdfTeX and XeTeX, the traditional external compilation workflow applies, while LuaTeX offers enhanced inline processing through the luamplib package, allowing MetaPost code to be embedded directly in LuaTeX documents and executed during the TeX run without separate mpost invocations. In ConTeXt, integration is further enhanced by the MetaFun module, which provides advanced inline capabilities such as \startMPpage ... \stopMPpage for embedding graphics directly in the source, dynamic dimension passing from TeX (e.g., \overlaywidth), and seamless color and font synchronization between ConTeXt and MetaPost environments.[10] This module extends MetaPost's primitives for features like text along paths and adaptive scaling, making it particularly suited for complex document layouts in ConTeXt.[10]
MetaPost's primary output format is Encapsulated PostScript (EPS), a vector graphics format generated as PostScript code, which is well-suited for high-quality printing and inclusion in documents.[1] This default format ensures scalability without loss of detail, and files are produced with bounding box information for precise placement.[1]
For modern applications, MetaPost supports Scalable Vector Graphics (SVG) natively since version 1.200, allowing direct generation of web-friendly vector files.[1] Bitmap output in Portable Network Graphics (PNG) format became available starting with version 1.800, using the Cairo library for rendering at 72 dpi with options for RGBA, grayscale, and anti-aliasing.[1] Prior to this, rasterization required external tools such as Ghostscript (gs) for conversion from EPS to PNG, while SVG could be obtained via extensions like mpsvg or post-processing.[11] PDF output is achieved through integration with TeX systems, such as pdfTeX and the mptopdf bundle, which convert EPS files on-the-fly during document processing.[1]
In multi-picture mode, MetaPost generates a series of separate output files for batch production, using the beginfig macro to define each picture; the numeric argument determines the filename, resulting in numbered EPS files such as figure.1, figure.2, and so on, customizable via the outputtemplate variable (default: %j.%c).[1]
Since version 1.0, MetaPost has supported color profiles including RGB (default), CMYK, and grayscale models, enabling versatile color handling in outputs without native color management but with built-in conversions.[1] Although PNG provides direct bitmap capability today, MetaPost does not natively output other raster formats and continues to rely on external tools for additional rasterization needs beyond EPS, SVG, or PNG.[1]
Versions and Maintenance
Release History
MetaPost was first released in version 1.0 in January 1995 by John D. Hobby as a PostScript-oriented counterpart to Metafont.[2]
Following Hobby's initial development, Taco Hoekwater became the primary author, with assistance from Hans Hagen and others, while Luigi Scarso has served as the current maintainer.
In 2007, the project was restructured into frontend and backend libraries known as MPlib to facilitate better integration with modern TeX engines.[3]
The project saw several updates leading to stable release 1.8 on June 17, 2013, which introduced support for 64-bit IEEE floating-point arithmetic as the core numeric type, a new PNG output format, and a direct C API for solving path control points.[7]
A preview release, version 2.0rc2, appeared on February 19, 2018, incorporating experimental Lua bindings for integration with LuaTeX and various performance optimizations.[7]
No stable version 2.0 has been issued as of 2025, and while major development for this version has remained stalled since the 2018 preview, routine maintenance continues.[12]
Current Status and Development
As of 2025, MetaPost remains actively maintained as part of the TeX Live distribution, with its source code hosted in the official TeX Live repositories on GitLab at gitlab.lisn.upsaclay.fr/texlive/metapost, where synchronization with the TeX Live 2025 release occurred in early 2025.[13][14] This setup ensures ongoing integration and stability, with the previous GitHub mirror at github.com/reviczky/metapost serving primarily as an inactive archive since development shifted to GitLab in November 2022.[15]
The MetaPost community centers around the TeX Users Group (TUG), with active discussions occurring on the [email protected] mailing list, which saw posts in multiple months of 2025, including March, April, June, July, and October.[16] Contributions are coordinated through TUG, emphasizing bug fixes and minor enhancements to maintain compatibility rather than introducing new features.[3]
Key challenges include the absence of a stable MetaPost 2.0 release, despite internal preparations and bug fixes incorporated into TeX Live 2025.[13] Additionally, MetaPost faces competition from the TikZ/PGF package within the LaTeX ecosystem, which offers more seamless integration for vector graphics.[17]
Overall, MetaPost's development in 2025 prioritizes reliability and backward compatibility, as evidenced by its inclusion in TeX Live 2025 without major architectural changes since preview work on version 2.0 began years earlier, underscoring a focus on stability over rapid innovation.[13][18]
Practical Usage
Installation and Availability
MetaPost is readily available through major TeX distributions, making installation straightforward for users already employing these systems. In TeX Live, the full installation includes MetaPost by default, while users with a basic or custom setup can install it using the TeX Live Manager (tlmgr) with the command tlmgr install metapost.[19] MiKTeX bundles MetaPost as a package that can be added via its integrated package manager, accessible through the MiKTeX Console or command line.[20] For macOS users, MacTeX—the native distribution of TeX Live—provides MetaPost in its complete installation, ensuring seamless integration with the TeX ecosystem.
For those preferring a standalone setup without a full TeX distribution, MetaPost source code can be obtained from the Comprehensive TeX Archive Network (CTAN) at ctan.org/pkg/metapost or the TeX Users Group (TUG) website.[18][3] Compilation from source requires the web2c tools, a standard TeX implementation framework that converts the literate programming sources into executables. This approach allows customization but typically demands familiarity with build environments like those using Make or CMake.
MetaPost is cross-platform, with precompiled binaries supporting Windows, Linux, and macOS, enabling deployment across diverse operating systems.[3] While it can operate independently for generating graphics, full functionality—particularly for incorporating typeset text—often requires a compatible TeX engine such as pdfTeX or LuaTeX.[21]
As free and open-source software licensed under the GNU Lesser General Public License version 3 or later, MetaPost is freely distributable and modifiable.[18] Version 2.11 serves as the default in most TeX Live 2025 installations, providing robust support for modern graphics generation needs.[21]
Typical Workflows
The typical workflow for creating graphics with MetaPost begins with writing a source file using the .mp extension, containing MetaPost code structured around beginfig(n); and endfig; blocks to define individual figures, where n is a unique integer identifier for each figure.[1] To process the file, the mpost command is executed from the terminal, such as mpost filename.mp, which compiles the code and generates output files in Encapsulated PostScript (EPS) format by default, named according to the jobname and figure number (e.g., filename.1).[1]
For documents requiring multiple figures, MetaPost supports batch processing within a single .mp file by enclosing each figure in sequential beginfig(n); ... endfig; pairs, resulting in correspondingly numbered output files (e.g., filename.1, filename.2) that can be referenced independently.[1] These EPS files are then incorporated into LaTeX documents using the graphicx package; a common setup involves declaring a graphics rule with \DeclareGraphicsRule{*.mps}{eps}{}{} to handle any intermediate .mps files produced during TeX label processing, followed by inclusion via \includegraphics{filename.1} in the LaTeX source.[1]
Debugging in MetaPost workflows often involves enabling verbose output to monitor execution, such as setting tracingonline := 1; within the code or invoking mpost with the --mem=report option to track memory usage and identify resource-intensive operations.[1] For figures incorporating text labels via btex ... etex constructs, errors in label typesetting are resolved through interaction with the TeX engine, which processes these into .mpx files during the mpost run.[1]
MetaPost is widely employed in academic publishing for generating consistent, high-quality technical diagrams due to its parametric and programmable nature, ensuring precise control over vector graphics that integrate seamlessly with TeX-based documents.[1] In larger projects, workflows are frequently automated using tools like Makefiles or shell scripts to chain mpost compilation with LaTeX processing, streamlining the production of figures across multiple files or revisions.[1]
Examples and Tutorials
Basic Example
A fundamental introduction to MetaPost can be achieved through a simple program that draws a filled circle with a label.[1]
The following code snippet defines a path for a circle, scales it to a diameter of 2 cm, fills and outlines it, and adds a centered TeX label:
metapost
beginfig(1);
path c;
c = fullcircle scaled 2cm;
fill c;
[draw](/page/Draw) c;
[label](/page/Label)("$Circle$", center c);
endfig(1);
beginfig(1);
path c;
c = fullcircle scaled 2cm;
fill c;
[draw](/page/Draw) c;
[label](/page/Label)("$Circle$", center c);
endfig(1);
In this example, fullcircle is a predefined closed path representing a circle of unit diameter centered at the origin.[1] The scaled 2cm operator transforms the path to a diameter of 2 cm (radius 1 cm).[1] The fill command shades the interior with the default color, and draw adds a thin black outline using the default pen.[1] The label command positions the math-mode text "Circle" at the path's center point.[1]
Running this code with the mpost command on a file named example.mp produces an Encapsulated PostScript file example.1.eps containing the 2 cm diameter filled circle with centered text.[1] This minimal program exemplifies a complete, executable MetaPost figure ready for inclusion in LaTeX documents using the graphicx package.[1]
Advanced Example
An advanced example of MetaPost's capabilities involves constructing and manipulating complex paths using custom macros, arrays of points and directions, and conditional direction adjustments to create smoothed outlines and offsets. This demonstrates features such as path expressions, loop iterations, and picture transformations, which are essential for generating intricate graphics like smoothed polygons or glyph-like shapes. The following code, adapted from the official MetaPost manual, defines two macros—getmid and joinup—to process a base path, extract midpoints and offsets along its directions, and join them into new paths for drawing.[1]
metapost
def getmid(suffix p) = pair p.mid[], p.off[], p.dir[];
for i=0 upto 36: p.dir[i] = dir(5*i); p.mid[i]+p.off[i] = directionpoint p.dir[i] of p;
p.mid[i]-p.off[i] = directionpoint -p.dir[i] of p; endfor enddef;
def joinup(suffix pt, d)(expr n) = begingroup save res, g; path res;
res = pt[0]{d[0]}; for i=1 upto n: g:= if (pt[i]-pt[i-1]) dotprod d[i] <0: - fi 1;
res := res{g*d[i-1]}...{g*d[i]}pt[i]; endfor res endgroup enddef;
beginfig(45)
path p, q;
p = ((5,2)...(3,4)...(1,3)...(-2,-3)...(0,-5)...(3,-4)...(5,-3)...cycle) scaled .3cm shifted (0,5cm);
getmid(p); draw p;
draw joinup(p.mid, p.dir, 36)..cycle;
q = joinup(p.off, p.dir, 36); draw q..(q rotated 180)..cycle;
drawoptions(dashed evenly);
for i=0 upto 3: draw p.mid[9i]-p.off[9i]..p.mid[9i]+p.off[9i];
draw -p.off[9i]..p.off[9i]; endfor
endfig;
def getmid(suffix p) = pair p.mid[], p.off[], p.dir[];
for i=0 upto 36: p.dir[i] = dir(5*i); p.mid[i]+p.off[i] = directionpoint p.dir[i] of p;
p.mid[i]-p.off[i] = directionpoint -p.dir[i] of p; endfor enddef;
def joinup(suffix pt, d)(expr n) = begingroup save res, g; path res;
res = pt[0]{d[0]}; for i=1 upto n: g:= if (pt[i]-pt[i-1]) dotprod d[i] <0: - fi 1;
res := res{g*d[i-1]}...{g*d[i]}pt[i]; endfor res endgroup enddef;
beginfig(45)
path p, q;
p = ((5,2)...(3,4)...(1,3)...(-2,-3)...(0,-5)...(3,-4)...(5,-3)...cycle) scaled .3cm shifted (0,5cm);
getmid(p); draw p;
draw joinup(p.mid, p.dir, 36)..cycle;
q = joinup(p.off, p.dir, 36); draw q..(q rotated 180)..cycle;
drawoptions(dashed evenly);
for i=0 upto 3: draw p.mid[9i]-p.off[9i]..p.mid[9i]+p.off[9i];
draw -p.off[9i]..p.off[9i]; endfor
endfig;
In this code, the getmid macro initializes arrays for directions (p.dir[]), midpoints (p.mid[]), and offsets (p.off[]) along a path p, using a loop to compute 37 points (from 0 to 36) based on evenly spaced directions every 5 degrees via dir(5*i). The directionpoint operator returns the first point on the path where the tangent direction matches the specified direction vector. In this code, it locates such points for evenly spaced directions to compute midpoints as their average with opposite-direction points and offsets as half the difference vector. The joinup macro then connects these points into a new path res, incorporating a conditional (if) to flip the direction vector g if the dot product between consecutive point differences and the next direction is negative, ensuring smooth Bézier joins with explicit curl controls {g*d[i-1]}...{g*d[i]}. The base path p is a scaled and shifted cycle of control points connected by splines (...), drawn directly. The midpoints form an inner smoothed outline via joinup(p.mid, p.dir, 36)..cycle, while offsets create an outer shape q that is rotated 180 degrees and cycled for symmetry. Dashed lines illustrate offsets at every 9th index (0, 9, 18, 27) using another loop. This example produces a figure with a central irregular polygon, an inner parallel curve, an outer rotated envelope, and connecting dashed segments, highlighting MetaPost's power for algorithmic curve offsetting and path smoothing in technical illustrations.[1]
Such techniques extend to more sophisticated applications, like font glyph decomposition or calligraphic effects, but this path manipulation showcases core advanced constructs including suffix arrays, local variables via begingroup/endgroup, and vector operations for geometric precision.[1]