generative_pioneers_2 · mohr_p159d
P-159 D (Mohr)
Manfred Mohr's 'P-159 D' (1969, Vincennes) sits in the P-159 family that the artist developed from his earlier P-021 / P-036 line-arrangement programs. The algorithmic kernel is exactly the kind of operation Mohr called an 'aesthetical filter' — divide the canvas into an N×N grid of bounded cells, in each cell generate a candidate set of straight lines between two random points, then thin the field by removing a fraction of the lines (the parity-based 'keep' rule), and finally mark each genuine intersection between two surviving lines in a different ink. The result is a quasi-random, two-ink plane where the underlying cell grid never quite disappears: order survives as periodicity, but within every cell the eye reads noise. Mohr made these drawings in 1969 with the help of Jean-Pierre Hébert and others in the Vincennes AI lab, on a Benson flatbed plotter attached to the Météorologie Nationale IBM 1130.
Original: https://www.emohr.com/ManfredMohr_50YearCelebration_TimeLine.html
▶ Try the live demo (JS port) ▶ Run reference.py via Pyodide 10 formulas have instant JS ports. The Pyodide path runs the actual Python in your browser — first load is ~6 MB, then instant.
Math essence
For each cell (ri, ci) sample N endpoints uniformly in the cell rectangle, form a line per pair, drop each line with probability (1 − keep_prob), clip the survivors to the cell with Liang-Barsky, then for every pair of surviving segments (s_i, s_j) that come from cells of opposite parity (ri+ci) mod 2, compute the segment intersection via the standard 2D cross-ratio test and mark the crossing with a small red dot. The cell-grid periodicity plus the parity-gated intersection layer is the P-159 D kernel.
Parameters
| Name | Type | Default | Range | Description |
|---|---|---|---|---|
dim | int | 512 | 200–1200 | Square canvas side length |
cells | int | 4 | 2–12 | Cells per side (canvas is cells×cells) |
lines_per_cell | int | 14 | 4–60 | Candidate lines per cell before thinning |
margin | float | 0.06 | 0–0.3 | Outer margin (fraction of dim) |
line_jitter | float | 0.45 | 0–1 | Endpoint jitter (fraction of cell size) |
keep_prob | float | 0.5 | 0.05–1 | Survival probability per candidate line |
thickness | float | 1.2 | 0.5–3 | Ink thickness |
bg_color | tuple | 240,235,222 | null–null | Background RGB |
line_color | tuple | 12,12,18 | null–null | Ink RGB |
seed | int | null | 0–999999 | RNG seed |
Reference
First 60 lines of reference.py. Full source:
library_external/generative_pioneers_2/mohr_p159d/reference.py
from __future__ import annotations
from typing import ClassVar
import imageio.v2 as imageio
import numpy as np
class MohrP159D:
family: ClassVar[str] = "generative_pioneers_2"
sketch: ClassVar[str] = "mohr_p159d"
def __init__(
self,
dim: int = 512,
cells: int = 4,
lines_per_cell: int = 14,
margin: float = 0.06,
line_jitter: float = 0.45,
keep_prob: float = 0.5,
thickness: float = 1.2,
bg_color: tuple[int, int, int] = (240, 235, 222),
line_color: tuple[int, int, int] = (12, 12, 18),
seed: int | None = None,
) -> None:
self.dim = dim
self.cells = cells
self.lines_per_cell = lines_per_cell
self.margin = margin
self.line_jitter = line_jitter
self.keep_prob = keep_prob
self.thickness = thickness
self.bg_color = np.array(bg_color, dtype=np.uint8)
self.line_color = np.array(line_color, dtype=np.uint8)
self._seed = seed
self.rng = np.random.default_rng(seed)
self.canvas = np.full((dim, dim, 3), self.bg_color, dtype=np.uint8)
self.time = 0
self._dirty = True
def reset(self, seed: int | None = None) -> None:
if seed is not None:
self._seed = seed
self.rng = np.random.default_rng(self._seed)
self.canvas = np.full((self.dim, self.dim, 3), self.bg_color, dtype=np.uint8)
self.time = 0
self._dirty = True
def _stroke(
self,
x0: float,
y0: float,
x1: float,
y1: float,
color: np.ndarray,
) -> None:
d = float(np.hypot(x1 - x0, y1 - y0))
if d < 0.5:
return
steps = max(2, int(d)) Try running it locally
The reference implementation is self-contained Python with numpy. Install the package and run:
python library_external/generative_pioneers_2/mohr_p159d/reference.py Need help? See Learn for the standard environment setup, or Playground for an in-browser sketchbook.
More from generative_pioneers_2
Computer-Aided Painting (Schwartz)
generative_pioneers_2 · lillian_schwartz
Lillian Schwartz, who worked at Bell Labs from 1968 to 2001 with Kenneth C.
Hypertransformations (Molnár)
generative_pioneers_2 · molnar_hypertransformations
Vera Molnár's 'Hypertransformations' (1974-1976), executed on the IBM 360 with a CRT 2250 display and output on a Benson plotter.
Raster Sequence (Nake)
generative_pioneers_2 · nake_raster_sequence
Frieder Nake's 'Walk-through-Raster' / 'Raster Sequence' (1966) is the first non-stationary Markov chain in computer art history.
Structure Computer (Cohen / AARON)
generative_pioneers_2 · cohen_structure_computer
Harold Cohen's AARON, begun at UCSD in 1967-1973 and continuously developed until Cohen's death in 2016, is the longest-running art-making AI in history.
Text Rain (Utterback & Achituv)
generative_pioneers_2 · utterback_text_rain
Camille Utterback and Romy Achituv's 'Text Rain' (1999) is one of the canonical interactive installations of the late-1990s computer-vision era, and the piece that won them a US patent (US 6,928,313) in 2005.
Wall Drawings (LeWitt)
generative_pioneers_2 · sol_lewitt_wall_drawings
Sol LeWitt's wall drawings (1968-2007) are the canonical example of conceptual-art-as-algorithm: the work is the set of written instructions, and any number of draftspeople can execute them with different results that all satisfy the same rule.