Resources Numerical accuracy Calculation policy

2D drawing on screen

Draws the drawing, the grid and the cursor aids on the two canvases of the 2D view.

How the precision is kept

Screen positions are computed in 64-bit numbers and handed to the browser's canvas. The cached paths of a drawing are stored relative to the middle of its extents, and a point is brought to the screen by subtracting the view center before multiplying by the zoom, so a drawing far from the origin is not drawn from large coordinates. Nothing in these functions is written back to the drawing.

Calculations under this policy

4 calculations in 1 source file. The code is read from the released app when this page loads. It is the calculation people run, not a copy kept for this page.

view.js CadCraft 0.8.2 32-bit, display only 4 calculations Reviewed

Tests bin/test-cadcraft.mjs

Drawing coordinates to screen position

32-bit, display only

Where a drawing point is on screen, in CSS pixels of the active pane.

sx = (x − cx)·zoom + w ÷ 2; sy = h ÷ 2 − (y − cy)·zoom (with a turn: the difference is rotated first)

The view center is subtracted before the multiplication by the zoom, so the digits of a large coordinate are spent on the difference and not on the product. Used for markers, grips and rubber bands on the overlay canvas.

  • view.js
  • lines 395 to 399
  • CadCraft 0.8.2
toScreen(x, y) {
  if (!this.tw) return { x: (x - this.cx) * this.zoom + this.w / 2, y: this.h / 2 - (y - this.cy) * this.zoom };
  const c = Math.cos(this.tw), s = Math.sin(this.tw), dx = x - this.cx, dy = y - this.cy;
  return { x: this.w / 2 + this.zoom * (c * dx + s * dy), y: this.h / 2 - this.zoom * (-s * dx + c * dy) };
}

Origin of the cached paths

32-bit, display only

The point the cached drawing paths are stored relative to.

origin = middle of the extents of the visible objects; path point = point − origin

The subtraction is done in 64-bit numbers before the coordinates go into the browser's Path2D objects, which keeps the values given to the canvas small for a drawing far from the origin.

  • view.js
  • line 667
  • CadCraft 0.8.2
const origin = validBounds(ext) ? { x: (ext.minX + ext.maxX) / 2, y: (ext.minY + ext.maxY) / 2 } : { x: 0, y: 0 };

Grid spacing

32-bit, display only

The spacing of the background grid: 1, 2 or 5 times a power of ten, at least 14 pixels apart.

target = 14 ÷ zoom; p = 10^⌊log₁₀ target⌋; step = first of p, 2p, 5p, 10p that is ≥ target; major = 5 × step

The power of ten comes from Math.log10 and Math.pow; for negative exponents the result is a 64-bit number close to 0.1, 0.01 and so on, and Math.pow is not required to round it correctly. The step is used to draw grid lines only; it is stored on the view but nothing else in the app reads it.

  • view.js
  • lines 895 to 898
  • CadCraft 0.8.2
const target = 14 / this.zoom;
const p10 = Math.pow(10, Math.floor(Math.log10(target)));
const step = [1, 2, 5, 10].map((k) => k * p10).find((s) => s >= target);
const major = step * 5;

Pixels per paper millimeter

32-bit, display only

How many CSS pixels one millimeter of the sheet takes, used to draw lineweights at their paper width.

√(T₀² + T₁²) ÷ (25.4 when the paper is in inches, else 1)

The scale of the view matrix by Math.hypot, divided by 25.4 for a sheet set up in inches. 25.4 is the exact number of millimeters in an inch.

  • view.js
  • lines 635 to 640
  • CadCraft 0.8.2
/** CSS px per paper mm on the open sheet (viewports included), 0 in the model. */
paperPxPerMm() {
  const lay = this.spaceLayout !== undefined ? this.spaceLayout : this.doc.layout;   // the space being drawn (split screen)
  if (!lay) return 0;
  return Math.hypot(this.T[0], this.T[1]) / (lay.paper?.unit === 'in' ? 25.4 : 1);
}

In detail

Method
screen = (world − view center) × zoom + pane ÷ 2, with y flipped and an optional turn; one cached path per color, lineweight and transparency.
Number types
64-bit numbers passed to the canvas 2D context; how the browser rasterizes them is outside this code.
Tolerances
Consecutive line pieces are joined in one path when their ends agree within 1e-12, arcs within 1e-9 (absolute). The grid is not drawn when it would have more than 4000 lines across the view.
Limits
The grid and the on-screen lineweights are for the eye only; the grid step is not used to place points.

Approach: Display only

Computed to draw the screen, often in 32-bit on the graphics processor. No number a person reads, saves or exports comes from it.

Every policy that takes this approach