diff --git a/docs/content/inference.md b/docs/content/inference.md index 78540d43..0158b878 100644 --- a/docs/content/inference.md +++ b/docs/content/inference.md @@ -685,7 +685,8 @@ before anything else looks at the mask. **A polygon is the piece you pointed at, not the biggest one on the frame.** Which of the survivors you meant is a question only the points can answer, so the choice is made from the prompt: a point inside a piece picks that piece; several points inside several pieces pick the -largest of *those*, because two positives describe one object rather than propose two; and a +largest of *those*, because two positives describe one object rather than propose two, and two +pieces of exactly the same size answer with the one whose earliest run comes first; and a point inside none of them picks the piece nearest to it, since a mask need not cover the exact pixel you clicked. Negative points never select - they say what the shape is not, and a piece is chosen before its shape is known. diff --git a/frontend/annotator/src/core/geometry/simplify.ts b/frontend/annotator/src/core/geometry/simplify.ts index e31bf000..4b1eb8a2 100644 --- a/frontend/annotator/src/core/geometry/simplify.ts +++ b/frontend/annotator/src/core/geometry/simplify.ts @@ -16,11 +16,20 @@ * keeps it current, and neither half shares a toolchain with the other. * * **Exact equality is achievable and is what the gate asserts.** Both languages - * hold IEEE-754 doubles, `Math.sqrt` and Python's `** 0.5` are the same - * correctly-rounded operation, and every expression below is in the same order - * as the Python it mirrors. Keeping that order is not style: the algorithm's - * output is decided by comparisons, so a re-association that moves a value by - * one unit in the last place can move a vertex. + * hold IEEE-754 doubles, and every expression below is in the same order as the + * Python it mirrors — that ordering is what the parity actually depends on. + * Keeping it is not style: the algorithm's output is decided by comparisons, so + * a re-association that moves a value by one unit in the last place can move a + * vertex. + * + * `Math.sqrt` and Python's `** 0.5` are *not* quite the same operation, though: + * CPython routes `** 0.5` through libm `pow`, which is not correctly rounded, + * and it disagrees with a correctly-rounded square root by one ulp on roughly a + * tenth of a percent of inputs. The mask pipeline avoids carrying that + * difference into nearest-piece selection by comparing squared distances there; + * `closingRadius` absorbs it through truncation. The existing simplification + * fixture continues to assert exact output for its covered contours. Making + * Python's side call `math.sqrt` would be a separate semantic change. * * ## Why a contour is the input rather than a mask * diff --git a/frontend/annotator/src/core/mask/binaryMask.test.ts b/frontend/annotator/src/core/mask/binaryMask.test.ts new file mode 100644 index 00000000..be7194ef --- /dev/null +++ b/frontend/annotator/src/core/mask/binaryMask.test.ts @@ -0,0 +1,33 @@ +import { describe, expect, it } from "vitest"; + +import { pythonRound } from "./binaryMask"; + +describe("pythonRound", () => { + it("rounds a half to the even neighbour, as Python does", () => { + expect(pythonRound(0.5)).toBe(0); + expect(pythonRound(1.5)).toBe(2); + expect(pythonRound(2.5)).toBe(2); + expect(pythonRound(3.5)).toBe(4); + }); + + it("disagrees with Math.round on exactly the halves that decide a component", () => { + for (const half of [0.5, 2.5, 4.5, 6.5]) { + expect(pythonRound(half)).not.toBe(Math.round(half)); + } + }); + + it("rounds a negative half to even too, and never to -0", () => { + expect(pythonRound(-0.5)).toBe(0); + expect(Object.is(pythonRound(-0.5), -0)).toBe(false); + expect(pythonRound(-1.5)).toBe(-2); + expect(pythonRound(-2.5)).toBe(-2); + }); + + it("rounds anything that is not a half to the nearest whole number", () => { + expect(pythonRound(0.4)).toBe(0); + expect(pythonRound(0.6)).toBe(1); + expect(pythonRound(-0.4)).toBe(0); + expect(pythonRound(-0.6)).toBe(-1); + expect(pythonRound(7)).toBe(7); + }); +}); diff --git a/frontend/annotator/src/core/mask/binaryMask.ts b/frontend/annotator/src/core/mask/binaryMask.ts new file mode 100644 index 00000000..cb72d65b --- /dev/null +++ b/frontend/annotator/src/core/mask/binaryMask.ts @@ -0,0 +1,59 @@ +/** + * What a segmenter answers with, in the asset's own pixels. + * + * ## The seam, and why it is structural rather than a dependency + * + * `@visionset/browser-inference` stops at a mask: model execution, an image + * embedding, a grid of bytes and a confidence. Turning that grid into a box or + * a polygon is a product decision — which pieces count as the object, how big a + * gap is an artefact, where the boundary of a pixel is — and it belongs here, + * beside the rest of the asset-pixel arithmetic, for the reason + * `visionset.inference.masks` lives above the segmentation adapter rather than + * inside it: it runs once for every model there will ever be. + * + * So `RawSegmentation` is *structurally* assignable to this type and neither + * package imports the other. A host composes them. + */ +export interface BinaryMask { + readonly width: number; + readonly height: number; + /** + * Row-major, `width * height` bytes, each **exactly 0 or 1**. + * + * Not "any non-zero is lit": the authoritative Python reads a row through + * `index(True)` and `index(False)`, which match the bytes 1 and 0 and nothing + * else, so a 255 already breaks the scan there. The contract is the contract + * rather than a convention this side is free to widen. + */ + readonly mask: Uint8Array; +} + +/** + * One connected piece of a mask, cropped to its own extent. + * + * `x` and `y` are where the crop sits in the asset, and every coordinate finally + * emitted has them added back. Cropped rather than carried at full size, which + * is what keeps a plural answer affordable: a 4K mask is eight million bytes, + * and one of those per piece would cost more than the forward pass. + */ +export interface Piece { + readonly x: number; + readonly y: number; + readonly mask: BinaryMask; +} + +/** + * Python's `round()`: halves go to the even neighbour. + * + * `Math.round` takes them upward, and answers `-0` for `-0.5`. The difference + * decides which component a click at a half-pixel coordinate selects, and every + * test written at integer coordinates passes under either — which is exactly + * what makes it worth a function with a name. + */ +export function pythonRound(value: number): number { + const low = Math.floor(value); + const rest = value - low; + if (rest > 0.5) return low + 1; + if (rest < 0.5) return low; + return low % 2 === 0 ? low : low + 1; +} diff --git a/frontend/annotator/src/core/mask/closing.test.ts b/frontend/annotator/src/core/mask/closing.test.ts new file mode 100644 index 00000000..53af99d8 --- /dev/null +++ b/frontend/annotator/src/core/mask/closing.test.ts @@ -0,0 +1,149 @@ +import { describe, expect, it } from "vitest"; + +import { closingRadius, filled } from "./closing"; +import { bboxFrom, maskOf, runs } from "./runs"; +import type { Run } from "./runs"; + +const lit = (mask: { width: number; mask: Uint8Array }): number => + mask.mask.reduce((total: number, byte) => total + (byte === 0 ? 0 : 1), 0); + +/** A solid square with a one-row bite `depth` pixels deep, cut in from the right. */ +const notched = (depth: number, size = 64) => { + const runsOf: Run[] = []; + for (let y = 0; y < size; y += 1) { + if (y === Math.floor(size / 2) && depth > 0) runsOf.push([y, 0, size - depth - 1]); + else runsOf.push([y, 0, size - 1]); + } + return maskOf(size, size, runsOf); +}; + +/** + * A 64x64 square with an 8x8 bite out of its right edge. + * + * Wide in *both* directions, which is what makes it a bay rather than a notch: + * a one-row bite closes at radius 1 however deep it is, because the dimension + * the close has to bridge is its height. + */ +const bayed = () => { + const runsOf: Run[] = []; + for (let y = 0; y < 64; y += 1) { + if (y >= 28 && y < 36) runsOf.push([y, 0, 55]); + else runsOf.push([y, 0, 63]); + } + return maskOf(64, 64, runsOf); +}; + +/** + * A 64x64 square with a 2-px notch, inside an 80x80 canvas. + * + * Framed so background survives the close: `notched(2)` is the whole canvas but + * for two pixels, and closing it leaves nothing unlit at all. + */ +const framedNotch = () => { + const runsOf: Run[] = []; + for (let y = 8; y < 72; y += 1) { + if (y === 40) runsOf.push([y, 8, 69]); + else runsOf.push([y, 8, 71]); + } + return maskOf(80, 80, runsOf); +}; + +/** A 64x64 square with a centred square hole `hole` pixels on a side. */ +const holed = (hole: number, size = 64) => { + const low = Math.floor(size / 2) - Math.floor(hole / 2); + const runsOf: Run[] = []; + for (let y = 0; y < size; y += 1) { + if (y >= low && y < low + hole) { + runsOf.push([y, 0, low - 1], [y, low + hole, size - 1]); + } else { + runsOf.push([y, 0, size - 1]); + } + } + return maskOf(size, size, runsOf); +}; + +/** A `size`x`size` solid square, placed at the origin of a `canvas`x`canvas` frame. */ +const solidSquareIn = (canvas: number, size: number) => + maskOf(canvas, canvas, Array.from({ length: size }, (_, y): Run => [y, 0, size - 1])); + +describe("closingRadius", () => { + it("scales with the piece's own area, not the frame", () => { + expect(closingRadius(solidSquareIn(64, 64))).toBe(closingRadius(solidSquareIn(200, 64))); + expect(closingRadius(notched(0, 200))).toBeGreaterThan(closingRadius(notched(0, 64))); + }); + + it("reaches nothing at all on a piece too small to have artefacts", () => { + expect(closingRadius(maskOf(8, 8, [[3, 3, 4]]))).toBe(0); + }); + + it("stops at the cap however large the piece", () => { + expect( + closingRadius(maskOf(800, 800, Array.from({ length: 800 }, (_, y): Run => [y, 0, 799]))), + ).toBe(6); + }); + + it("truncates rather than rounding, as Python's int() does", () => { + // 14400 lit pixels -> sqrt(28.8) / 2 = 2.6832..., which truncates to 2 and + // would round to 3. This is the assertion that catches a Math.round port. + expect( + closingRadius(maskOf(120, 120, Array.from({ length: 120 }, (_, y): Run => [y, 0, 119]))), + ).toBe(2); + }); +}); + +describe("filled", () => { + it("hands back the very same mask when the reach works out at nothing", () => { + const small = maskOf(8, 8, [[3, 3, 4]]); + expect(filled(small)).toBe(small); + }); + + it("hands back the very same mask when the close changes nothing", () => { + const clean = notched(0); + expect(filled(clean)).toBe(clean); + }); + + it("closes a notch narrower than the reach", () => { + const narrow = notched(2); + const after = filled(narrow); + expect(after).not.toBe(narrow); + expect(lit(after)).toBeGreaterThan(lit(narrow)); + }); + + it("leaves a bay wider than the reach alone", () => { + const wide = bayed(); + expect(filled(wide)).toBe(wide); + }); + + it("closes a one-row bite however deep it is, because its height is the gap", () => { + const deep = notched(40); + expect(filled(deep)).not.toBe(deep); + }); + + it("fills a small enclosed hole", () => { + const withHole = holed(2); + expect(lit(withHole)).toBe(64 * 64 - 4); + expect(lit(filled(withHole))).toBe(64 * 64); + }); + + it("never moves the extent", () => { + for (const mask of [notched(2), notched(5), holed(2)]) { + expect(bboxFrom(filled(mask))).toEqual(bboxFrom(mask)); + } + }); + + it("keeps the mask's own dimensions", () => { + const after = filled(notched(2)); + expect(after.width).toBe(64); + expect(after.height).toBe(64); + expect(after.mask.length).toBe(64 * 64); + }); + + it("answers only 0 and 1", () => { + expect(new Set(filled(framedNotch()).mask)).toEqual(new Set([0, 1])); + }); + + it("leaves runs it did not need to touch exactly where they were", () => { + const after = filled(notched(2)); + expect(runs(after)[0]).toEqual([0, 0, 63]); + }); +}); diff --git a/frontend/annotator/src/core/mask/closing.ts b/frontend/annotator/src/core/mask/closing.ts new file mode 100644 index 00000000..7436fd4d --- /dev/null +++ b/frontend/annotator/src/core/mask/closing.ts @@ -0,0 +1,149 @@ +/** + * Step 2 — close the small gaps in a piece, wherever they are. + * + * A morphological close: grow the shape, then shrink it back by the same amount. + * Anything narrower than the reach is bridged on the way out and not re-opened + * on the way back, and everything wider is left exactly as it was. + * + * ## Why bitsets, and why `BigInt` + * + * The two passes are whole-row shifts and ORs. Written as nested loops over + * pixels they would be a step per pixel per radius step, on the path somebody is + * waiting on after a click. `BigInt` rather than a number mask because a mask + * wider than 32 pixels would silently lose its top bits — and because Python's + * `int` and JavaScript's `BigInt` are the same arbitrary-precision + * two's-complement under `&`, `|`, `~`, `<<` and `>>`, which is what lets this + * be a port rather than a rewrite. + */ + +import type { BinaryMask } from "./binaryMask"; +import { runs } from "./runs"; + +/** The largest gap closed, as a share of the piece's own lit area. */ +export const CLOSING_REACH = 0.002; + +/** However large the piece, the reach stops here. */ +export const MAXIMUM_CLOSING_RADIUS = 6; + +/** The mask as one integer per row, offset by `pad` on every side. */ +export function bits(mask: BinaryMask, pad: number): { rows: bigint[]; width: number } { + const width = mask.width + 2 * pad; + const rows = new Array(mask.height + 2 * pad).fill(0n); + for (const [y, first, last] of runs(mask)) { + const span = (1n << BigInt(last - first + 1)) - 1n; + rows[y + pad] = rows[y + pad]! | (span << BigInt(first + pad)); + } + return { rows, width }; +} + +function joined(rows: readonly bigint[]): bigint { + let all = 0n; + for (const row of rows) all |= row; + return all; +} + +function met(rows: readonly bigint[]): bigint { + let all = rows[0]!; + for (let index = 1; index < rows.length; index += 1) all &= rows[index]!; + return all; +} + +/** Every lit pixel spread by `radius` in each direction — a square dilation. */ +function grown(rows: readonly bigint[], radius: number, width: number): bigint[] { + const frame = (1n << BigInt(width)) - 1n; + const across: bigint[] = []; + for (const row of rows) { + let spread = row; + for (let step = 1; step <= radius; step += 1) { + const shift = BigInt(step); + spread |= (row << shift) | (row >> shift); + } + across.push(spread & frame); + } + const height = rows.length; + const out: bigint[] = []; + for (let y = 0; y < height; y += 1) { + out.push(joined(across.slice(Math.max(0, y - radius), Math.min(height, y + radius + 1)))); + } + return out; +} + +/** + * The dual: a pixel survives only with its whole square neighbourhood lit. + * + * Outside the frame counts as unlit, which the shifts give for free — bits move + * off the end and zeros arrive — and which is right here because the frame was + * padded wide enough that nothing real sits against its edge. + */ +function shrunk(rows: readonly bigint[], radius: number, width: number): bigint[] { + const frame = (1n << BigInt(width)) - 1n; + const across: bigint[] = []; + for (const row of rows) { + let kept = row; + for (let step = 1; step <= radius; step += 1) { + const shift = BigInt(step); + kept &= (row << shift) & (row >> shift) & frame; + } + across.push(kept & frame); + } + const height = rows.length; + const out: bigint[] = []; + for (let y = 0; y < height; y += 1) { + out.push( + radius <= y && y < height - radius + ? met(across.slice(Math.max(0, y - radius), Math.min(height, y + radius + 1))) + : 0n, + ); + } + return out; +} + +/** + * How far to reach, for a piece of this size. + * + * A hole of area `a` needs a reach of about `sqrt(a) / 2` to be bridged, so the + * radius comes from the piece's own lit area rather than from a pixel count. + * Truncated — `Math.trunc` mirrors Python's `int()` — so the smallest shapes get + * no closing at all rather than one that would swallow a feature. That + * truncation is also what absorbs the one-ulp difference between `Math.sqrt` + * and Python's `** 0.5`: it never survives to change the truncated result. + */ +export function closingRadius(mask: BinaryMask): number { + let alight = 0; + for (const [, first, last] of runs(mask)) alight += last - first + 1; + return Math.min(Math.trunc(Math.sqrt(alight * CLOSING_REACH) / 2), MAXIMUM_CLOSING_RADIUS); +} + +/** + * The piece with its narrow gaps closed. + * + * Returns the mask unchanged — the same object — when the reach works out at + * nothing or the shape has no gap that narrow, which is the common case and + * saves rebuilding a grid to say so. + * + * A close only ever adds pixels whose whole neighbourhood was already reachable, + * so it cannot push an edge outward and the extent does not move. That is why + * the box branch skips this step entirely. + */ +export function filled(mask: BinaryMask): BinaryMask { + const radius = closingRadius(mask); + if (radius < 1) return mask; + const { rows: before, width } = bits(mask, radius); + const after = shrunk(grown(before, radius, width), radius, width); + if (after.every((row, index) => row === before[index])) return mask; + + const data = new Uint8Array(mask.width * mask.height); + for (let y = 0; y < mask.height; y += 1) { + // One binary rendering per row rather than a shift per pixel: reading bit + // `x` out of a wide BigInt costs the whole word, and a 4K row is 3840 of + // them. This is Python's `format(word, "0Nb")[::-1]` without the reversal. + const text = after[y + radius]!.toString(2); + const top = text.length - 1; + const base = y * mask.width; + for (let x = 0; x < mask.width; x += 1) { + const at = top - (x + radius); + data[base + x] = at >= 0 && text.charCodeAt(at) === 49 ? 1 : 0; + } + } + return { width: mask.width, height: mask.height, mask: data }; +} diff --git a/frontend/annotator/src/core/mask/components.test.ts b/frontend/annotator/src/core/mask/components.test.ts new file mode 100644 index 00000000..3b8c5e1f --- /dev/null +++ b/frontend/annotator/src/core/mask/components.test.ts @@ -0,0 +1,114 @@ +import { describe, expect, it } from "vitest"; + +import { components } from "./components"; +import { maskOf } from "./runs"; +import type { Run } from "./runs"; + +/** A 1-px speck in the topmost row and a 36-px object below-left. */ +const speckled = () => { + const lit: Run[] = [[0, 9, 9]]; + for (let y = 3; y < 9; y += 1) lit.push([y, 1, 6]); + return maskOf(10, 10, lit); +}; + +/** 25 px on the left, 16 px on the right, far apart. */ +const islands = () => { + const lit: Run[] = []; + for (let y = 2; y < 7; y += 1) lit.push([y, 1, 5]); + for (let y = 3; y < 7; y += 1) lit.push([y, 14, 17]); + return maskOf(24, 12, lit); +}; + +/** Two five-pixel components rooted at run indices 3 and 8 — the tie case. */ +const tied = () => { + const lit: Run[] = []; + for (const x of [0, 4, 8, 12, 16, 20, 24]) lit.push([0, x, x]); + lit.push([1, 0, 0], [1, 2, 2]); + for (const y of [1, 2, 3, 4]) lit.push([y, 12, 12]); + for (const y of [2, 3, 4, 5]) lit.push([y, 2, 2]); + return maskOf(30, 7, lit); +}; + +describe("components", () => { + it("has nothing to say about an empty mask", () => { + expect(components(maskOf(8, 8, []))).toEqual([]); + }); + + it("drops a speck before anything else looks at the mask", () => { + const pieces = components(speckled()); + expect(pieces).toHaveLength(1); + expect(pieces[0]!.x).toBe(1); + expect(pieces[0]!.y).toBe(3); + }); + + it("leads with the piece under the click, not the topmost-leftmost one", () => { + expect(components(speckled(), [[3, 5]])[0]!.x).toBe(1); + }); + + it("leads with the pointed piece even when it is not the biggest", () => { + expect(components(islands(), [[15, 4]])[0]!.x).toBe(14); + }); + + it("falls back to the nearest piece for a click that is inside none", () => { + expect(components(islands(), [[20, 4]])[0]!.x).toBe(14); + }); + + it("compares squared distances when square roots would tie", () => { + // The second pixel is geometrically closer, although the two Math.sqrt + // results round equal on this input. Selection must not depend on that + // rounding tie or on the first run's reading order. + const nearTie = maskOf(64, 64, [ + [12, 11, 11], + [26, 44, 44], + ]); + const pieces = components(nearTie, [[27.660028289416932, 18.62279046066009]]); + expect([pieces[0]!.x, pieces[0]!.y]).toEqual([44, 26]); + }); + + it("prefers the largest of the pieces several points land in", () => { + expect( + components(islands(), [ + [15, 4], + [3, 4], + ])[0]!.x, + ).toBe(1); + }); + + it("settles an equal-area tie by reading order, whichever way the points arrive", () => { + expect(components(tied(), [[12, 2], [2, 3]])[0]!.x).toBe(12); + expect(components(tied(), [[2, 3], [12, 2]])[0]!.x).toBe(12); + }); + + it("returns every survivor biggest-first behind the pointed one", () => { + const pieces = components(islands(), [[15, 4]]); + expect(pieces.map((piece) => piece.x)).toEqual([14, 1]); + }); + + it("joins pixels that touch only at a corner", () => { + const diagonal = maskOf(4, 4, [ + [1, 1, 1], + [2, 2, 2], + ]); + expect(components(diagonal)).toHaveLength(1); + }); + + it("selects the component Python's rounding points at, not Math.round's", () => { + // A single half-pixel click cannot tell the two roundings apart: the two + // candidate pixels are either one run or 8-connected, so they share a + // component, and a rounding that lands on nothing falls back to the piece + // the click is nearly inside anyway. It takes a *second* point, so that the + // largest-wins rule has something to choose between. + // + // A is 12 px across rows 1-2; B is 4 px, well away. The first point sits at + // y = 2.5: Python's half-to-even reads row 2, which is A, so `under` holds + // both and the larger wins. Math.round reads row 3, which is empty, so + // `under` holds only B and the answer is B. + const two = maskOf(12, 8, [ + [1, 0, 5], + [2, 0, 5], + [1, 8, 9], + [2, 8, 9], + ]); + expect(components(two, [[2, 2.5], [8, 1]])[0]!.x).toBe(0); + }); +}); diff --git a/frontend/annotator/src/core/mask/components.ts b/frontend/annotator/src/core/mask/components.ts new file mode 100644 index 00000000..0386e698 --- /dev/null +++ b/frontend/annotator/src/core/mask/components.ts @@ -0,0 +1,201 @@ +/** + * Step 1 — which pieces of a mask are worth turning into shapes. + * + * Union-find over *runs* rather than a flood fill over pixels, and the ordering + * at the end is the whole difference between the two geometries: a polygon + * takes the head of this list because a click asks about one object, and a + * box takes the union of all of it because a mask arriving in several pieces + * is nearly always one object seen around an occlusion. + */ + +import type { Point } from "../types"; +import { pythonRound, type BinaryMask, type Piece } from "./binaryMask"; +import { runs, type Run } from "./runs"; + +/** + * How big a piece has to be, against the biggest one, to survive the noise + * filter. Relative to the largest piece rather than to the frame, so it means + * the same thing on a mask covering everything and a mask covering a corner. + */ +export const MINIMUM_FRAGMENT_SHARE = 0.05; + +/** Do two runs on neighbouring rows touch, counting diagonals? */ +function adjacent(one: Run, other: Run): boolean { + return one[1] <= other[2] + 1 && other[1] <= one[2] + 1; +} + +/** One label per run: which piece it belongs to, 8-connected. */ +function labelled(found: readonly Run[]): number[] { + const parent = found.map((_, index) => index); + const root = (index: number): number => { + let at = index; + while (parent[at] !== at) { + parent[at] = parent[parent[at]!]!; + at = parent[at]!; + } + return at; + }; + const join = (left: number, right: number): void => { + const one = root(left); + const other = root(right); + // The earlier run wins, so a label is always its piece's first run. + if (one !== other) parent[Math.max(one, other)] = Math.min(one, other); + }; + + const rows = new Map(); + found.forEach((run, index) => { + const here = rows.get(run[0]); + if (here) here.push(index); + else rows.set(run[0], [index]); + }); + for (const [y, here] of rows) { + const above = rows.get(y - 1); + if (!above) continue; + let mine = 0; + let prior = 0; + while (mine < here.length && prior < above.length) { + const ours = found[here[mine]!]!; + const theirs = found[above[prior]!]!; + if (adjacent(ours, theirs)) join(here[mine]!, above[prior]!); + if (ours[2] < theirs[2]) mine += 1; + else prior += 1; + } + } + return found.map((_, index) => root(index)); +} + +/** Squared distance from a point to a run, which is a horizontal segment of pixels. */ +function squaredGap(point: Point, run: Run): number { + const [x, y] = point; + const [row, first, last] = run; + const across = Math.max(0, first - x, x - last); + return across * across + (row - y) * (row - y); +} + +/** Lit pixels per label, summed off the runs rather than counted. */ +function areas(found: readonly Run[], labels: readonly number[]): Map { + const size = new Map(); + found.forEach((run, index) => { + const label = labels[index]!; + size.set(label, (size.get(label) ?? 0) + run[2] - run[1] + 1); + }); + return size; +} + +/** + * The label of the piece the prompt asks about. + * + * A point inside a piece picks that piece; several points inside several pieces + * pick the largest of them, and two of the same size pick the lowest label — + * the piece whose earliest run comes first, which is the `(-size, label)` order + * applied to the rest of the list below. A point inside none of them picks the + * piece nearest the point. Without any point the topmost-leftmost piece wins. + * Negatives never select: they say what the shape is not, and a piece is chosen + * before its shape is known. + */ +function pointedAt( + found: readonly Run[], + labels: readonly number[], + size: ReadonlyMap, + at: readonly Point[], +): number { + if (at.length === 0) return labels[0]!; + + const under = new Set(); + for (const point of at) { + const x = pythonRound(point[0]); + const y = pythonRound(point[1]); + found.forEach((run, index) => { + if (run[0] === y && run[1] <= x && x <= run[2]) under.add(labels[index]!); + }); + } + if (under.size > 0) { + let best = -1; + for (const label of under) { + if (best < 0) { + best = label; + continue; + } + const ours = size.get(label)!; + const theirs = size.get(best)!; + if (ours > theirs || (ours === theirs && label < best)) best = label; + } + return best; + } + + let nearest = 0; + let closest = Infinity; + found.forEach((run, index) => { + let ours = Infinity; + for (const point of at) { + const found_ = squaredGap(point, run); + if (found_ < ours) ours = found_; + } + if (ours < closest) { + closest = ours; + nearest = index; + } + }); + return labels[nearest]!; +} + +/** That label's runs, painted into a mask the size of their own extent. */ +function cropped(label: number, found: readonly Run[], labels: readonly number[]): Piece { + const mine = found.filter((_, index) => labels[index] === label); + const top = mine[0]![0]; + const bottom = mine[mine.length - 1]![0]; + let left = Infinity; + let right = -Infinity; + for (const [, first, last] of mine) { + if (first < left) left = first; + if (last > right) right = last; + } + const width = right - left + 1; + const height = bottom - top + 1; + const data = new Uint8Array(width * height); + for (const [row, first, last] of mine) { + const base = (row - top) * width; + for (let x = first - left; x <= last - left; x += 1) data[base + x] = 1; + } + return { x: left, y: top, mask: { width, height, mask: data } }; +} + +/** + * The pieces of the mask worth turning into shapes. + * + * Everything below {@link MINIMUM_FRAGMENT_SHARE} of the largest piece is + * dropped as noise, first and unconditionally. What survives is ordered with the + * piece the prompt points at at the head and the rest biggest-first behind it, + * ties by the lowest label, so the answer is stable for a given mask. + * + * An empty mask answers with no pieces, which is an ordinary answer and not an + * error — the click landed on sky. + */ +export function components(mask: BinaryMask, at: readonly Point[] = []): Piece[] { + const found = runs(mask); + if (found.length === 0) return []; + const labels = labelled(found); + const size = areas(found, labels); + + let largest = 0; + for (const area of size.values()) if (area > largest) largest = area; + const floor = largest * MINIMUM_FRAGMENT_SHARE; + + const survived = new Set(); + for (const [label, area] of size) if (area >= floor) survived.add(label); + + const keptRuns: Run[] = []; + const keptLabels: number[] = []; + found.forEach((run, index) => { + if (survived.has(labels[index]!)) { + keptRuns.push(run); + keptLabels.push(labels[index]!); + } + }); + + const first = pointedAt(keptRuns, keptLabels, size, at); + const rest = [...survived] + .filter((label) => label !== first) + .sort((one, other) => size.get(other)! - size.get(one)! || one - other); + return [first, ...rest].map((label) => cropped(label, found, labels)); +} diff --git a/frontend/annotator/src/core/mask/maskGeometry.test.ts b/frontend/annotator/src/core/mask/maskGeometry.test.ts new file mode 100644 index 00000000..b9b72a8a --- /dev/null +++ b/frontend/annotator/src/core/mask/maskGeometry.test.ts @@ -0,0 +1,195 @@ +/** + * The TypeScript half of the mask-to-geometry parity gate. + * + * `tests/fixtures/mask_geometry.json` is written by `visionset.inference.masks` + * and kept current by `tests/inference/test_mask_geometry_fixture.py`. This + * proves the port reproduces it — every stage, exactly — which is what lets a + * host run a model in the browser and get the shapes the server would have + * given. + * + * **Exact equality, deliberately.** A tolerance on the comparison would let a + * genuine divergence through: the two implementations either run the same + * arithmetic in the same order or they will disagree about a vertex somewhere, + * and "somewhere" is what a golden fixture exists to find. + * + * The stages are asserted separately from the shapes so a failure says *which* + * step diverged rather than only that the answers differ. + */ + +import { readFileSync } from "node:fs"; +import { describe, expect, it } from "vitest"; + +import { DEFAULT_TOLERANCE, MINIMUM_TOLERANCE } from "../geometry/simplify"; +import type { Point } from "../types"; +import { CLOSING_REACH, MAXIMUM_CLOSING_RADIUS, closingRadius, filled } from "./closing"; +import { MINIMUM_FRAGMENT_SHARE, components } from "./components"; +import { contour, outline } from "./outline"; +import { maskOf, runs, type Run } from "./runs"; +import { shapesFromMask } from "./shapes"; +import type { BinaryMask } from "./binaryMask"; +import type { GeometryType } from "../types"; + +interface Grid { + readonly width: number; + readonly height: number; + readonly runs: readonly (readonly number[])[]; +} + +interface Cropped extends Grid { + readonly x: number; + readonly y: number; +} + +interface Shaped { + readonly geometry: Record; + readonly contour: readonly (readonly number[])[]; +} + +interface Case { + readonly name: string; + readonly mask: Grid; + readonly at: readonly (readonly number[])[]; + readonly components: readonly Cropped[]; + readonly closing_radius: number | null; + readonly filled: Grid | null; + readonly outline: readonly (readonly number[])[] | null; + readonly contour: readonly (readonly number[])[] | null; + readonly shapes: Readonly>>>; +} + +interface Fixture { + readonly minimum_fragment_share: number; + readonly closing_reach: number; + readonly maximum_closing_radius: number; + readonly minimum_tolerance: number; + readonly default_tolerance: number; + readonly tolerances: readonly number[]; + readonly cases: readonly Case[]; +} + +const FIXTURE_URL = new URL("../../../../../tests/fixtures/mask_geometry.json", import.meta.url); +const fixture = JSON.parse(readFileSync(FIXTURE_URL, "utf8")) as Fixture; + +/** The fixture keys a tolerance by Python's spelling of the float: `1.0`, not `1`. */ +const keyed = (tolerance: number): string => + Number.isInteger(tolerance) ? `${tolerance}.0` : String(tolerance); + +const rebuilt = (grid: Grid): BinaryMask => + maskOf(grid.width, grid.height, grid.runs.map((run) => [run[0]!, run[1]!, run[2]!] as Run)); + +const points = (rows: readonly (readonly number[])[]): Point[] => + rows.map((row) => [row[0]!, row[1]!] as Point); + +const plain = (runsOf: readonly Run[]): number[][] => runsOf.map((run) => [run[0], run[1], run[2]]); + +describe("the constants travel rather than being restated", () => { + it("holds the noise floor, the reach, the cap and the tolerances where the kernel does", () => { + expect(MINIMUM_FRAGMENT_SHARE).toBe(fixture.minimum_fragment_share); + expect(CLOSING_REACH).toBe(fixture.closing_reach); + expect(MAXIMUM_CLOSING_RADIUS).toBe(fixture.maximum_closing_radius); + expect(MINIMUM_TOLERANCE).toBe(fixture.minimum_tolerance); + expect(DEFAULT_TOLERANCE).toBe(fixture.default_tolerance); + }); +}); + +describe.each(fixture.cases)("$name", (found) => { + const mask = rebuilt(found.mask); + const at = points(found.at); + + it("reconstructs the same pixels the fixture describes", () => { + expect(plain(runs(mask))).toEqual(found.mask.runs); + }); + + it("survives the noise filter with the same pieces, in the same order", () => { + const pieces = components(mask, at); + expect( + pieces.map((piece) => ({ + x: piece.x, + y: piece.y, + width: piece.mask.width, + height: piece.mask.height, + runs: plain(runs(piece.mask)), + })), + ).toEqual( + found.components.map((piece) => ({ + x: piece.x, + y: piece.y, + width: piece.width, + height: piece.height, + runs: piece.runs.map((run) => [...run]), + })), + ); + }); + + it("reaches the same distance into the head piece", () => { + const pieces = components(mask, at); + expect(pieces.length === 0 ? null : closingRadius(pieces[0]!.mask)).toBe(found.closing_radius); + }); + + it("closes the head piece into the same pixels", () => { + const pieces = components(mask, at); + if (found.filled === null) { + expect(pieces).toHaveLength(0); + return; + } + const whole = filled(pieces[0]!.mask); + expect(whole.width).toBe(found.filled.width); + expect(whole.height).toBe(found.filled.height); + expect(plain(runs(whole))).toEqual(found.filled.runs.map((run) => [...run])); + }); + + it("traces the same boundary, corner for corner", () => { + const pieces = components(mask, at); + if (found.outline === null) { + expect(pieces).toHaveLength(0); + return; + } + expect(outline(filled(pieces[0]!.mask))).toEqual(points(found.outline)); + }); + + it("reduces to the same canonical contour, point for point", () => { + const pieces = components(mask, at); + if (found.contour === null) { + expect(pieces).toHaveLength(0); + return; + } + expect(contour(filled(pieces[0]!.mask))).toEqual(points(found.contour)); + }); + + describe.each(Object.keys(found.shapes))("allowed=%s", (key) => { + const allowed = key.split(",") as GeometryType[]; + it.each([...fixture.tolerances])("proposes the same shapes at %s px", (tolerance) => { + const expected = found.shapes[key]![keyed(tolerance)]; + expect(expected).toBeDefined(); + const actual = shapesFromMask(mask, { allowed, tolerance, at }); + expect(actual).toEqual( + expected!.map((shape) => ({ + geometry: + shape.geometry["type"] === "polygon" + ? { type: "polygon", points: points(shape.geometry["points"] as number[][]) } + : shape.geometry, + contour: points(shape.contour), + })), + ); + }); + }); +}); + +describe("the gate would notice a port that ignored its input", () => { + it("has a case with more than one surviving component", () => { + expect(fixture.cases.some((found) => found.components.length > 1)).toBe(true); + }); + + it("has a case whose click is at a half pixel", () => { + expect( + fixture.cases.some((found) => + found.at.some((point) => point.some((value) => !Number.isInteger(value))), + ), + ).toBe(true); + }); + + it("has a case the closing changes and a case it leaves alone", () => { + const withReach = fixture.cases.filter((found) => (found.closing_radius ?? 0) > 0); + expect(withReach.length).toBeGreaterThan(1); + }); +}); diff --git a/frontend/annotator/src/core/mask/outline.test.ts b/frontend/annotator/src/core/mask/outline.test.ts new file mode 100644 index 00000000..0846e78a --- /dev/null +++ b/frontend/annotator/src/core/mask/outline.test.ts @@ -0,0 +1,133 @@ +import { describe, expect, it } from "vitest"; + +import { MINIMUM_TOLERANCE, simplified } from "../geometry/simplify"; +import { contour, outline, smoothed } from "./outline"; +import { maskOf } from "./runs"; +import type { Run } from "./runs"; + +const square = (size: number, at = 0) => + maskOf(size + at * 2, size + at * 2, Array.from({ length: size }, (_, y): Run => [y + at, at, at + size - 1])); + +describe("outline", () => { + it("is the pixels' edges, not their centres", () => { + expect(outline(maskOf(3, 3, [[1, 1, 1]]))).toEqual([ + [1, 1], + [2, 1], + [2, 2], + [1, 2], + ]); + }); + + it("walks a rectangle's four corners clockwise from its top-left", () => { + expect(outline(square(3))).toEqual([ + [0, 0], + [1, 0], + [2, 0], + [3, 0], + [3, 1], + [3, 2], + [3, 3], + [2, 3], + [1, 3], + [0, 3], + [0, 2], + [0, 1], + ]); + }); + + it("makes one ring of two pixels touching only at a corner", () => { + // Eight corners with only seven distinct: the shared corner (2,2) is + // visited twice, which is precisely what the left-turn-first rule produces + // — it crosses onto the second pixel rather than closing round the first. + // Asserting the sequence pins that rule; asserting distinctness would be + // false, and asserting a length would not tell the two turns apart. + expect(outline(maskOf(4, 4, [ + [1, 1, 1], + [2, 2, 2], + ]))).toEqual([ + [1, 1], + [2, 1], + [2, 2], + [3, 2], + [3, 3], + [2, 3], + [2, 2], + [1, 2], + ]); + }); + + it("never reaches an enclosed hole", () => { + const withHole = maskOf(5, 5, [ + [1, 1, 3], + [2, 1, 1], + [2, 3, 3], + [3, 1, 3], + ]); + expect(outline(withHole)).toEqual(outline(maskOf(5, 5, [ + [1, 1, 3], + [2, 1, 3], + [3, 1, 3], + ]))); + }); + + it("has nothing to say about an empty mask", () => { + expect(outline(maskOf(4, 4, []))).toEqual([]); + }); +}); + +describe("smoothed", () => { + it("cuts every corner at a quarter and three quarters of its edges", () => { + expect(smoothed([ + [0, 0], + [2, 0], + [0, 2], + ])).toEqual([ + [0.5, 0], + [1.5, 0], + [1.5, 0.5], + [0.5, 1.5], + [0, 1.5], + [0, 0.5], + ]); + }); + + it("leaves anything shorter than a ring alone, as a copy", () => { + const pair: [number, number][] = [ + [0, 0], + [1, 1], + ]; + expect(smoothed(pair)).toEqual(pair); + expect(smoothed(pair)).not.toBe(pair); + }); + + it("never leaves the ring it was given", () => { + const ring = outline(square(6)); + for (const [x, y] of smoothed(ring)) { + expect(x).toBeGreaterThanOrEqual(0); + expect(x).toBeLessThanOrEqual(6); + expect(y).toBeGreaterThanOrEqual(0); + expect(y).toBeLessThanOrEqual(6); + } + }); +}); + +describe("contour", () => { + it("is the smoothed trace reduced once at the floor", () => { + const mask = square(12); + expect(contour(mask)).toEqual(simplified(smoothed(outline(mask)), MINIMUM_TOLERANCE)); + }); + + it("turns a staircase into one straight edge", () => { + const stair = maskOf(8, 8, [ + [1, 1, 1], + [2, 1, 2], + [3, 1, 3], + [4, 1, 4], + ]); + expect(contour(stair).length).toBeLessThan(outline(stair).length); + }); + + it("has nothing to say about an empty mask", () => { + expect(contour(maskOf(4, 4, []))).toEqual([]); + }); +}); diff --git a/frontend/annotator/src/core/mask/outline.ts b/frontend/annotator/src/core/mask/outline.ts new file mode 100644 index 00000000..4a775764 --- /dev/null +++ b/frontend/annotator/src/core/mask/outline.ts @@ -0,0 +1,131 @@ +/** + * Step 3 — the canonical boundary: traced along the pixels' edges, smoothed + * once, reduced once at the floor. + * + * The reduction is part of the definition rather than an optimisation: + * Douglas-Peucker is not nested — reducing at a quarter pixel and then at five + * does not give what reducing once at five gives — so the editor and the kernel + * can only be proved to agree if both start from the same points. + */ + +import { MINIMUM_TOLERANCE, simplified } from "../geometry/simplify"; +import type { Point } from "../types"; +import type { BinaryMask } from "./binaryMask"; +import { bits } from "./closing"; +import { runs } from "./runs"; + +type Corner = readonly [number, number]; + +/** The indices of a non-negative integer's set bits, lowest first. */ +function* setBits(value: bigint): Generator { + if (value <= 0n) return; + const text = value.toString(2); + const top = text.length - 1; + for (let index = top; index >= 0; index -= 1) { + if (text.charCodeAt(index) === 49) yield top - index; + } +} + +/** + * Which way out of a corner that has more than one, left turn first. + * + * A corner with two ways out is where two lit pixels touch only diagonally. The + * left turn crosses onto the other pixel and keeps the 8-connected piece one + * ring; the right turn would close round the first pixel alone and cut the piece + * in two, which is not what `components` said the piece was. + */ +function turned(options: Corner[], at: Corner, heading: Corner): Corner { + const left: Corner = [heading[1], -heading[0]]; + const right: Corner = [-heading[1], heading[0]]; + for (const wanted of [left, heading, right]) { + for (let index = 0; index < options.length; index += 1) { + const candidate = options[index]!; + if (candidate[0] - at[0] === wanted[0] && candidate[1] - at[1] === wanted[1]) { + return options.splice(index, 1)[0]!; + } + } + } + throw new Error("a corner's ways out are its own edges"); +} + +/** + * The boundary of the piece this mask holds, along the pixels' edges. + * + * Vertices sit at pixel corners, so a lone lit pixel comes back as its unit + * square. Clockwise, starting at the top-left corner of the topmost-leftmost lit + * pixel — a corner with exactly one way in and one way out, which is what lets + * the walk stop on reaching it again. + * + * Only boundary pixels are ever visited, so the walk is linear in the perimeter + * rather than in the area. Holes have rings of their own and it never reaches + * them. + */ +export function outline(mask: BinaryMask): Point[] { + const found = runs(mask); + if (found.length === 0) return []; + const { rows } = bits(mask, 0); + const height = rows.length; + const stride = mask.width + 2; + const edges = new Map(); + const add = (sx: number, sy: number, ex: number, ey: number): void => { + const at = sy * stride + sx; + const here = edges.get(at); + if (here) here.push([ex, ey]); + else edges.set(at, [[ex, ey]]); + }; + + for (let y = 0; y < height; y += 1) { + const row = rows[y]!; + if (row === 0n) continue; + const above = y > 0 ? rows[y - 1]! : 0n; + const below = y + 1 < height ? rows[y + 1]! : 0n; + for (const x of setBits(row & ~above)) add(x, y, x + 1, y); + for (const x of setBits(row & ~(row >> 1n))) add(x + 1, y, x + 1, y + 1); + for (const x of setBits(row & ~below)) add(x + 1, y + 1, x, y + 1); + for (const x of setBits(row & ~(row << 1n))) add(x, y + 1, x, y); + } + + const start: Corner = [found[0]![1], found[0]![0]]; + const ring: Corner[] = [start]; + let current = start; + let heading: Corner = [1, 0]; + for (;;) { + const options = edges.get(current[1] * stride + current[0]); + if (options === undefined || options.length === 0) { + throw new Error("the outline walk left the piece it started in"); + } + const following = options.length === 1 ? options.pop()! : turned(options, current, heading); + heading = [following[0] - current[0], following[1] - current[1]]; + if (following[0] === start[0] && following[1] === start[1]) break; + ring.push(following); + current = following; + } + return ring.map(([x, y]): Point => [x, y]); +} + +/** + * One pass of corner cutting over a closed ring. + * + * Every edge is replaced by the two points a quarter and three quarters of the + * way along it. On the unit-edge ring {@link outline} produces, that turns a + * staircase into a straight or gently curved line while moving no corner by more + * than half a pixel. Run on a ring whose straight runs had already been merged + * it would round the real corners of a rectangle, which is why it comes before + * any reduction. + */ +export function smoothed(ring: readonly Point[]): Point[] { + if (ring.length < 3) return [...ring]; + const out: Point[] = []; + for (let index = 0; index < ring.length; index += 1) { + const [px, py] = ring[index]!; + const [qx, qy] = ring[(index + 1) % ring.length]!; + out.push([0.75 * px + 0.25 * qx, 0.75 * py + 0.25 * qy]); + out.push([0.25 * px + 0.75 * qx, 0.25 * py + 0.75 * qy]); + } + return out; +} + +/** The canonical boundary: traced, smoothed, reduced once at the floor. */ +export function contour(mask: BinaryMask): Point[] { + return simplified(smoothed(outline(mask)), MINIMUM_TOLERANCE); +} diff --git a/frontend/annotator/src/core/mask/runs.test.ts b/frontend/annotator/src/core/mask/runs.test.ts new file mode 100644 index 00000000..217262f2 --- /dev/null +++ b/frontend/annotator/src/core/mask/runs.test.ts @@ -0,0 +1,98 @@ +import { describe, expect, it } from "vitest"; + +import { bboxFrom, maskOf, runs, spans } from "./runs"; + +describe("runs", () => { + it("finds every maximal run in reading order", () => { + const mask = maskOf(6, 3, [ + [0, 1, 2], + [0, 4, 5], + [2, 0, 0], + ]); + expect(runs(mask)).toEqual([ + [0, 1, 2], + [0, 4, 5], + [2, 0, 0], + ]); + }); + + it("ends a run at the row's edge when the row ends lit", () => { + expect(runs(maskOf(4, 1, [[0, 2, 3]]))).toEqual([[0, 2, 3]]); + }); + + it("has nothing to say about an empty mask", () => { + expect(runs(maskOf(4, 4, []))).toEqual([]); + }); +}); + +describe("spans", () => { + it("gives one entry per row, from its first lit pixel to its last", () => { + const mask = maskOf(6, 2, [ + [0, 1, 1], + [0, 4, 5], + [1, 3, 3], + ]); + expect(spans(mask)).toEqual([ + [0, 1, 5], + [1, 3, 3], + ]); + }); +}); + +describe("bboxFrom", () => { + it("is the pixels' outer edge, so one lit pixel is one unit across", () => { + expect(bboxFrom(maskOf(5, 5, [[2, 3, 3]]))).toEqual({ + type: "bbox", + x: 3, + y: 2, + width: 1, + height: 1, + }); + }); + + it("spans every row it was given", () => { + const mask = maskOf(10, 10, [ + [2, 1, 4], + [3, 6, 8], + ]); + expect(bboxFrom(mask)).toEqual({ type: "bbox", x: 1, y: 2, width: 8, height: 2 }); + }); + + it("answers nothing for an empty mask rather than raising", () => { + expect(bboxFrom(maskOf(4, 4, []))).toBeNull(); + }); +}); + +describe("contract: Python index(True)/index(False) asymmetry", () => { + // runs() uses index(True) to find start (advances while byte !== 1) and + // index(False) to find end (advances while byte !== 0). This asymmetry + // means out-of-contract bytes (e.g. 255) are treated differently: they + // never start a run, but they extend a run. spans() uses index(True) for + // both directions, so it only counts 1 as lit. These tests pin that + // distinction — without them, the next reader will "simplify" back. + + it("runs(): 255 inside a run extends the run", () => { + const mask = { width: 5, height: 1, mask: new Uint8Array([0, 1, 255, 1, 0]) }; + expect(runs(mask)).toEqual([[0, 1, 3]]); + }); + + it("runs(): 255 alone never starts a run", () => { + const mask = { width: 2, height: 1, mask: new Uint8Array([255, 0]) }; + expect(runs(mask)).toEqual([]); + }); + + it("runs(): run extends through 255 to row end", () => { + const mask = { width: 3, height: 1, mask: new Uint8Array([1, 1, 255]) }; + expect(runs(mask)).toEqual([[0, 0, 2]]); + }); + + it("spans(): stops at the last actual 1, ignoring trailing 255", () => { + const mask = { width: 3, height: 1, mask: new Uint8Array([1, 1, 255]) }; + expect(spans(mask)).toEqual([[0, 0, 1]]); + }); + + it("spans(): 255 alone is not a row", () => { + const mask = { width: 2, height: 1, mask: new Uint8Array([255, 0]) }; + expect(spans(mask)).toEqual([]); + }); +}); diff --git a/frontend/annotator/src/core/mask/runs.ts b/frontend/annotator/src/core/mask/runs.ts new file mode 100644 index 00000000..e8201df5 --- /dev/null +++ b/frontend/annotator/src/core/mask/runs.ts @@ -0,0 +1,97 @@ +/** + * A mask read as runs rather than pixels. + * + * Runs are what make every step after this one affordable on the interactive + * path: a megapixel mask of one clean object is a few hundred runs, and the + * loops below go round once per colour change in a row rather than once per + * pixel. This is the authoritative Python's own choice, kept — see + * `src/visionset/inference/masks.py`. + */ + +import type { BinaryMask } from "./binaryMask"; +import type { BboxGeometry } from "../types"; + +/** One maximal run of lit pixels: `[row, first, last]`, inclusive at both ends. */ +export type Run = readonly [y: number, first: number, last: number]; + +/** Paint lit runs into a mask — the fixture's representation, and the tests'. */ +export function maskOf(width: number, height: number, lit: readonly Run[]): BinaryMask { + const data = new Uint8Array(width * height); + for (const [y, first, last] of lit) { + const base = y * width; + for (let x = first; x <= last; x += 1) data[base + x] = 1; + } + return { width, height, mask: data }; +} + +/** Every maximal run of lit pixels, in reading order. */ +export function runs(mask: BinaryMask): Run[] { + const found: Run[] = []; + const { width, height } = mask; + const data = mask.mask; + for (let y = 0; y < height; y += 1) { + const base = y * width; + let at = 0; + while (at < width) { + let first = at; + while (first < width && data[base + first] !== 1) first += 1; + if (first === width) break; + let cursor = first; + while (cursor < width && data[base + cursor] !== 0) cursor += 1; + const last = cursor - 1; + found.push([y, first, last]); + // +2 rather than +1: the pixel that ended the run is known unlit. + at = last + 2; + } + } + return found; +} + +/** `[row, first, last]` for every row holding anything — the row's whole extent. */ +export function spans(mask: BinaryMask): Run[] { + const found: Run[] = []; + const { width, height } = mask; + const data = mask.mask; + for (let y = 0; y < height; y += 1) { + const base = y * width; + let first = -1; + for (let x = 0; x < width; x += 1) { + if (data[base + x] === 1) { + first = x; + break; + } + } + if (first < 0) continue; + let last = first; + for (let x = width - 1; x > first; x -= 1) { + if (data[base + x] === 1) { + last = x; + break; + } + } + found.push([y, first, last]); + } + return found; +} + +/** + * The mask's extent, or `null` if it holds nothing. + * + * `null` rather than a throw: an empty mask is an ordinary answer from a model + * asked about an empty patch of sky, and the caller turns it into "no + * suggestion". The box is the pixels' outer edge, so a single lit pixel is one + * wide and one tall rather than zero. + */ +export function bboxFrom(mask: BinaryMask): BboxGeometry | null { + const rows = spans(mask); + if (rows.length === 0) return null; + const top = rows[0]![0]; + const bottom = rows[rows.length - 1]![0]; + let left = Infinity; + let right = -Infinity; + for (const [, first, last] of rows) { + if (first < left) left = first; + if (last > right) right = last; + } + return { type: "bbox", x: left, y: top, width: right - left + 1, height: bottom - top + 1 }; +} diff --git a/frontend/annotator/src/core/mask/shapes.test.ts b/frontend/annotator/src/core/mask/shapes.test.ts new file mode 100644 index 00000000..acd60d0e --- /dev/null +++ b/frontend/annotator/src/core/mask/shapes.test.ts @@ -0,0 +1,83 @@ +import { describe, expect, it } from "vitest"; + +import { maskOf } from "./runs"; +import type { Run } from "./runs"; +import { shapesFromMask } from "./shapes"; + +/** 25 px on the left, 16 px on the right, far apart. */ +const islands = () => { + const lit: Run[] = []; + for (let y = 2; y < 7; y += 1) lit.push([y, 1, 5]); + for (let y = 3; y < 7; y += 1) lit.push([y, 14, 17]); + return maskOf(24, 12, lit); +}; + +const square = (size: number, at: number) => + maskOf(size + at * 2, size + at * 2, Array.from({ length: size }, (_, y): Run => [y + at, at, at + size - 1])); + +describe("shapesFromMask", () => { + it("prefers a polygon wherever the class admits one", () => { + const shaped = shapesFromMask(square(12, 4), { allowed: ["bbox", "polygon"] }); + expect(shaped[0]!.geometry.type).toBe("polygon"); + }); + + it("does not let the caller's ordering decide the kind", () => { + const one = shapesFromMask(square(12, 4), { allowed: ["bbox", "polygon"] }); + const other = shapesFromMask(square(12, 4), { allowed: ["polygon", "bbox"] }); + expect(one).toEqual(other); + }); + + it("gives a box where that is all the class holds", () => { + const shaped = shapesFromMask(square(12, 4), { allowed: ["bbox"] }); + expect(shaped[0]!.geometry).toEqual({ type: "bbox", x: 4, y: 4, width: 12, height: 12 }); + }); + + it("offers nothing to a class admitting neither kind", () => { + expect(shapesFromMask(square(12, 4), { allowed: ["polyline", "keypoints"] })).toEqual([]); + }); + + it("carries the contour a polygon was reduced from, and nothing for a box", () => { + const polygon = shapesFromMask(square(12, 4), { allowed: ["polygon"] }); + expect(polygon[0]!.contour.length).toBeGreaterThan(0); + const box = shapesFromMask(square(12, 4), { allowed: ["bbox"] }); + expect(box[0]!.contour).toEqual([]); + }); + + it("unions every surviving piece for a box and traces only one for a polygon", () => { + const box = shapesFromMask(islands(), { allowed: ["bbox"], at: [[3, 4]] }); + expect(box[0]!.geometry).toEqual({ type: "bbox", x: 1, y: 2, width: 17, height: 5 }); + const polygon = shapesFromMask(islands(), { allowed: ["polygon"], at: [[3, 4]] }); + const xs = (polygon[0]!.geometry as { points: readonly (readonly number[])[] }).points.map((p) => p[0]!); + expect(Math.max(...xs)).toBeLessThan(14); + }); + + it("does not move a box when the tolerance moves", () => { + const shapes = [0.25, 0.5, 1, 2, 4, 8, 16].map((tolerance) => + shapesFromMask(islands(), { allowed: ["bbox"], tolerance, at: [[3, 4]] }), + ); + for (const shaped of shapes) expect(shaped).toEqual(shapes[0]); + }); + + it("proposes nothing for a mask with nothing in it", () => { + expect(shapesFromMask(maskOf(8, 8, []), { allowed: ["polygon"] })).toEqual([]); + expect(shapesFromMask(maskOf(8, 8, []), { allowed: ["bbox"] })).toEqual([]); + }); + + it("refuses a piece too thin to have three distinct corners at a coarse tolerance", () => { + // 16 wide and one tall. The length matters: a 36-wide strip still keeps a + // vertex at this tolerance, because its cut-open ring deviates further from + // the closing chord than 16 px. Verified against the real Python. + const thin = maskOf(20, 8, [[3, 2, 17]]); + expect(shapesFromMask(thin, { allowed: ["polygon"], tolerance: 16 })).toEqual([]); + }); + + it("rejects a mask whose byte count does not match width times height", () => { + const malformed = { width: 4, height: 4, mask: new Uint8Array(8) }; + expect(() => shapesFromMask(malformed, { allowed: ["bbox", "polygon"] })).toThrow(Error); + }); + + it("still answers normally for a well-formed mask", () => { + const shaped = shapesFromMask(square(12, 4), { allowed: ["bbox", "polygon"] }); + expect(shaped[0]!.geometry.type).toBe("polygon"); + }); +}); diff --git a/frontend/annotator/src/core/mask/shapes.ts b/frontend/annotator/src/core/mask/shapes.ts new file mode 100644 index 00000000..46a7f494 --- /dev/null +++ b/frontend/annotator/src/core/mask/shapes.ts @@ -0,0 +1,144 @@ +/** + * A binary mask in, VisionSet geometry out. + * + * ## Where this sits + * + * Model execution stops at a binary mask. Everything below — which pieces of it + * count as the object, how big a gap is an artefact, where the boundary of a + * pixel is, whether the answer is a box or an outline — is a product decision in + * the asset's own pixels, and it runs once for every model there will ever be. + * That is why it lives here rather than in a runtime package, and why nothing + * here knows what produced the mask. + * + * `src/visionset/inference/masks.py` is authoritative. This reproduces it, and + * `tests/fixtures/mask_geometry.json` is what makes "they agree" a fact rather + * than a hope. + * + * ## The pipeline is fixed and its order is not configurable + * + * 1. `components` — which pieces of the mask survive the noise filter. + * 2. `filled` — the gaps in them narrower than a reach, closed. + * 3. `contour` — the boundary of what is left, traced, smoothed and reduced at + * the floor. + * 4. `polygonAt` — that boundary, within a pixel tolerance somebody chose. + * + * The geometry branch happens after step 1: a polygon class takes steps 2–4 on + * the piece the prompt points at, a box class takes one extent over *every* + * surviving piece. **A box therefore does not depend on the tolerance.** + */ + +import { DEFAULT_TOLERANCE, polygonAt } from "../geometry/simplify"; +import type { BboxGeometry, GeometryType, Point, PolygonGeometry } from "../types"; +import type { BinaryMask, Piece } from "./binaryMask"; +import { filled } from "./closing"; +import { components } from "./components"; +import { contour } from "./outline"; +import { bboxFrom } from "./runs"; + +export type { BinaryMask } from "./binaryMask"; + +/** + * One proposal: the geometry, and the contour it was reduced from. + * + * `contour` is empty for a box, because a box is not reduced from anything — it + * is the pieces' extent, and there is nothing a client could re-derive from a + * different setting. + */ +export interface ShapedGeometry { + readonly geometry: BboxGeometry | PolygonGeometry; + readonly contour: readonly Point[]; +} + +/** + * The kind an answer for that class will come back in. + * + * Polygon where a class admits it, because it is the more informative shape and + * a box can always be read off it; a box where that is all there is; nothing at + * all for a class that holds no shape. It reads a set, so the caller's ordering + * cannot change it. + */ +function targetKind(allowed: readonly GeometryType[]): "bbox" | "polygon" | null { + const kinds = new Set(allowed); + if (kinds.has("polygon")) return "polygon"; + if (kinds.has("bbox")) return "bbox"; + return null; +} + +/** A cropped piece's coordinates put back where the asset has them. */ +function shifted(points: readonly Point[], piece: Piece): Point[] { + return points.map(([x, y]): Point => [x + piece.x, y + piece.y]); +} + +/** The piece's extent, in the asset's coordinates. */ +function boxed(piece: Piece): BboxGeometry | null { + const box = bboxFrom(piece.mask); + if (box === null) return null; + return { ...box, x: box.x + piece.x, y: box.y + piece.y }; +} + +/** + * One box over every piece, or `null` if none of them holds anything. + * + * The answer to a point prompt is *this object*, and a mask arriving in several + * pieces is nearly always one object seen around an occlusion — a railing across + * an animal, a post in front of a car. The largest piece alone would cut the + * object off at the occlusion, and a box per piece would annotate one thing + * twice. + */ +function unionOf(pieces: readonly Piece[]): BboxGeometry | null { + const boxes = pieces.map(boxed).filter((box): box is BboxGeometry => box !== null); + if (boxes.length === 0) return null; + let left = Infinity; + let top = Infinity; + let right = -Infinity; + let bottom = -Infinity; + for (const box of boxes) { + if (box.x < left) left = box.x; + if (box.y < top) top = box.y; + if (box.x + box.width > right) right = box.x + box.width; + if (box.y + box.height > bottom) bottom = box.y + box.height; + } + return { type: "bbox", x: left, y: top, width: right - left, height: bottom - top }; +} + +/** + * The whole pipeline: a mask and a class's geometries in, proposals out. + * + * `at` is the prompt's **positive** points, and only those — negatives say what + * the shape is not, and a piece is chosen before its shape is known. + * + * A list, though today it holds at most one: an empty list is how "nothing to + * propose" is already said, and accepting part of a plural proposal is work + * somebody is tracking. + */ +export function shapesFromMask( + mask: BinaryMask, + options: { + readonly allowed: readonly GeometryType[]; + readonly tolerance?: number; + readonly at?: readonly Point[]; + }, +): readonly ShapedGeometry[] { + if (mask.mask.length !== mask.width * mask.height) { + throw new Error( + `mask carries ${mask.mask.length} bytes for a ${mask.width}x${mask.height} extent`, + ); + } + const { allowed, tolerance = DEFAULT_TOLERANCE, at = [] } = options; + const kind = targetKind(allowed); + if (kind === null) return []; + + const pieces = components(mask, at); + if (pieces.length === 0) return []; + + if (kind === "bbox") { + const box = unionOf(pieces); + return box === null ? [] : [{ geometry: box, contour: [] }]; + } + + const pointed = pieces[0]!; + const whole: Piece = { x: pointed.x, y: pointed.y, mask: filled(pointed.mask) }; + const traced = shifted(contour(whole.mask), whole); + const points = polygonAt(traced, tolerance); + return points === null ? [] : [{ geometry: { type: "polygon", points }, contour: traced }]; +} diff --git a/frontend/annotator/src/index.ts b/frontend/annotator/src/index.ts index eaae5ca2..a0fe7e86 100644 --- a/frontend/annotator/src/index.ts +++ b/frontend/annotator/src/index.ts @@ -114,6 +114,12 @@ export { toleranceInAssetPixels, type Tolerances, } from "./core/geometry/tolerance"; +// Mask -> geometry: the kernel's pipeline, held to it by tests/fixtures/mask_geometry.json +export { + shapesFromMask, + type BinaryMask, + type ShapedGeometry, +} from "./core/mask/shapes"; // Interaction — the state machine: states, events, effects, and the runner export { IDLE, diff --git a/scripts/export_mask_geometry_fixtures.py b/scripts/export_mask_geometry_fixtures.py new file mode 100644 index 00000000..8bb231af --- /dev/null +++ b/scripts/export_mask_geometry_fixtures.py @@ -0,0 +1,287 @@ +"""Export mask-to-geometry golden cases to tests/fixtures/mask_geometry.json. + +`visionset.inference.masks` turns a segmenter's mask into this domain's +geometry, and `@visionset/annotator` reproduces it so a host that runs a model +in the browser gets the same shapes as one that runs it on the server. Those are +two implementations of one pipeline, and the only thing that makes "they agree" +a fact rather than a hope is a set of inputs both are held to. + +Two gates, sharing no toolchain, exactly like `simplification.json`: +`tests/inference/test_mask_geometry_fixture.py` keeps this file matching the +Python; `frontend/annotator/src/core/mask/maskGeometry.test.ts` keeps the +TypeScript matching this file. The frontend CI job installs no Python and reads +only what is committed. + +It carries **masks rather than contours**, because the mask is where these two +implementations meet: `simplification.json` already owns everything from the +contour onward, and what is unproven until this file exists is that the contour +fed into `polygon_at` is the same contour. + +Masks travel as lit runs — `[y, first, last]`, inclusive — which both languages +reconstruct into identical pixels and a reviewer can read. + +Written compact rather than indented, which is the one place this diverges from +`simplification.json`. That file is 101 KB indented and fits; this one carries a +mask, five pipeline stages and thirty-five shape answers per case, and indented it +runs to 886 KB — past the tracked-file size ceiling in +`tests/architecture/test_tracked_file_sizes.py`, which exists to keep media out of +git. Nothing is lost: a golden fixture regenerated wholesale by a script is read +through the tests that consume it, never line by line, and `sort_keys` keeps it +deterministic either way. + +Usage: uv run python scripts/export_mask_geometry_fixtures.py +""" + +from __future__ import annotations + +import json +from pathlib import Path +from typing import Any + +from visionset.inference.masks import ( + CLOSING_REACH, + MAXIMUM_CLOSING_RADIUS, + MINIMUM_FRAGMENT_SHARE, + closing_radius, + components, + contour, + filled, + outline, + runs, + shapes_from, +) +from visionset.kernel.domain import DEFAULT_TOLERANCE, MINIMUM_TOLERANCE, GeometryType + +REPO_ROOT = Path(__file__).resolve().parent.parent +OUTPUT_PATH = "tests/fixtures/mask_geometry.json" + +TOLERANCES: list[float] = [0.25, 0.5, 1.0, 2.0, 4.0, 8.0, 16.0] + +ALLOWED: list[list[GeometryType]] = [ + [GeometryType.BBOX], + [GeometryType.POLYGON], + # Both orders, deliberately: the kind must come from the set and not from + # the caller's ordering, and two keys is how the fixture can say so. + [GeometryType.BBOX, GeometryType.POLYGON], + [GeometryType.POLYGON, GeometryType.BBOX], + # A class holding neither: the answer is nothing, and nothing is widened. + [GeometryType.POLYLINE], +] + +Mask = list[list[int]] + + +def blank(width: int, height: int) -> Mask: + return [[0] * width for _ in range(height)] + + +def painted(width: int, height: int, lit: list[tuple[int, int, int]]) -> Mask: + mask = blank(width, height) + for y, first, last in lit: + for x in range(first, last + 1): + mask[y][x] = 1 + return mask + + +def rect(width: int, height: int, x0: int, y0: int, x1: int, y1: int) -> Mask: + return painted(width, height, [(y, x0, x1) for y in range(y0, y1 + 1)]) + + +def disc(radius: int) -> Mask: + size = 2 * radius + 8 + centre = size // 2 + return [ + [1 if (x - centre) ** 2 + (y - centre) ** 2 <= radius * radius else 0 for x in range(size)] + for y in range(size) + ] + + +def notched(depth: int, size: int = 64) -> Mask: + mask = rect(size, size, 0, 0, size - 1, size - 1) + for x in range(size - depth, size): + mask[size // 2][x] = 0 + return mask + + +def holed(hole: int, size: int = 64) -> Mask: + mask = rect(size, size, 0, 0, size - 1, size - 1) + low = size // 2 - hole // 2 + for y in range(low, low + hole): + for x in range(low, low + hole): + mask[y][x] = 0 + return mask + + +def speckled() -> Mask: + mask = blank(10, 10) + mask[0][9] = 1 # a 1-px speck owning the topmost-leftmost pixel + for y in range(3, 9): + for x in range(1, 7): + mask[y][x] = 1 # the real object, 36 px + return mask + + +def islands() -> Mask: + mask = blank(24, 12) + for y in range(2, 7): + for x in range(1, 6): + mask[y][x] = 1 # 5x5 = 25 + for y in range(3, 7): + for x in range(14, 18): + mask[y][x] = 1 # 4x4 = 16 + return mask + + +def tied() -> Mask: + """Two five-pixel components rooted at run indices 3 and 8.""" + mask = blank(30, 7) + for x in (0, 4, 8, 12, 16, 20, 24): + mask[0][x] = 1 + mask[1][0] = 1 + mask[1][2] = 1 + for y in (1, 2, 3, 4): + mask[y][12] = 1 + for y in (2, 3, 4, 5): + mask[y][2] = 1 + return mask + + +def halved() -> Mask: + """The half-pixel rounding case, and it takes two points to be one. + + A *single* half-pixel click cannot tell the two roundings apart: the two + candidate pixels are either one run or 8-connected, so they are the same + piece, and a rounding that lands on nothing falls back to the piece the + click is nearly inside anyway. Both spellings answer the same. + + So there are two points. ``A`` is 12 px, ``B`` is 4 px and far away. The + first point sits at ``y = 2.5``: Python reads row 2, which is ``A``, so both + labels are under the prompt and the larger wins. `Math.round` reads row 3, + which is empty, so only ``B`` is under it and ``B`` is the answer. Two + different pieces, and therefore two different shapes. + """ + return painted(12, 8, [(1, 0, 5), (2, 0, 5), (1, 8, 9), (2, 8, 9)]) + + +def bayed() -> Mask: + """A 64x64 square with an 8x8 bite out of its right edge. + + Wide in *both* directions, which is what makes it a bay rather than a notch: + a one-row bite closes at radius 1 however deep it is, because the dimension + the close has to bridge is its height, not its depth. + """ + mask = rect(64, 64, 0, 0, 63, 63) + for y in range(28, 36): + for x in range(56, 64): + mask[y][x] = 0 + return mask + + +def diagonal() -> Mask: + """Two pixels touching only at a corner: one 8-connected piece, one ring.""" + return painted(4, 4, [(1, 1, 1), (2, 2, 2)]) + + +def squared_distance_near_tie() -> Mask: + """Two one-pixel pieces whose squared distances differ below sqrt precision.""" + return painted(64, 64, [(12, 11, 11), (26, 44, 44)]) + + +CASES: list[tuple[str, Mask, list[tuple[float, float]]]] = [ + ("empty", blank(20, 20), []), + ("single-pixel", painted(5, 5, [(2, 3, 3)]), []), + ("rectangle", rect(40, 40, 6, 6, 30, 24), []), + ("disc", disc(20), []), + ("speck-and-object", speckled(), []), + ("two-islands", islands(), [(3.0, 4.0)]), + ("point-picks-the-smaller-island", islands(), [(15.0, 4.0)]), + ("points-across-components", islands(), [(15.0, 4.0), (3.0, 4.0)]), + ("equal-area-tie", tied(), [(12.0, 2.0), (2.0, 3.0)]), + ("equal-area-tie-reversed", tied(), [(2.0, 3.0), (12.0, 2.0)]), + ("click-outside", islands(), [(20.0, 4.0)]), + ("half-pixel-click", halved(), [(2.0, 2.5), (8.0, 1.0)]), + ( + "squared-distance-near-tie", + squared_distance_near_tie(), + [(27.660028289416932, 18.62279046066009)], + ), + ("diagonal-touch", diagonal(), []), + ("narrow-notch", notched(2), []), + ("deep-one-row-notch", notched(40), []), + ("wide-bay", bayed(), []), + # The cap, and the only case that reaches it. Below about 98,000 lit pixels + # the reach never grows past six, so every other case here would pass a port + # that dropped the cap altogether rather than merely changing it. + ("capped-reach", rect(320, 320, 0, 0, 319, 319), []), + ("enclosed-hole", holed(2), []), + # A polygon at the floor and refused at the ceiling. 16 wide and one tall: + # a longer strip keeps a vertex at 16 px however thin it is. + ("thin", rect(20, 8, 2, 3, 17, 3), []), +] + + +def _runs(mask: Mask) -> list[list[int]]: + return [list(run) for run in runs(mask)] + + +def _grid(mask: Mask) -> dict[str, Any]: + return {"width": len(mask[0]), "height": len(mask), "runs": _runs(mask)} + + +def _shaped(shape: Any) -> dict[str, Any]: + return { + "geometry": json.loads(shape.geometry.model_dump_json()), + "contour": [list(point) for point in shape.contour], + } + + +def _key(allowed: list[GeometryType]) -> str: + return ",".join(str(kind.value) for kind in allowed) + + +def _case(name: str, mask: Mask, at: list[tuple[float, float]]) -> dict[str, Any]: + pieces = components(mask, at=at) + head = pieces[0] if pieces else None + whole = filled(head.mask) if head is not None else None + return { + "name": name, + "mask": _grid(mask), + "at": [list(point) for point in at], + "components": [{"x": piece.x, "y": piece.y, **_grid(list(piece.mask))} for piece in pieces], + "closing_radius": None if head is None else closing_radius(head.mask), + "filled": None if whole is None else _grid([list(row) for row in whole]), + "outline": None if whole is None else [list(point) for point in outline(whole)], + "contour": None if whole is None else [list(point) for point in contour(whole)], + "shapes": { + _key(allowed): { + str(tolerance): [ + _shaped(shape) + for shape in shapes_from(mask, allowed=allowed, tolerance=tolerance, at=at) + ] + for tolerance in TOLERANCES + } + for allowed in ALLOWED + }, + } + + +def build_fixture() -> dict[str, Any]: + return { + "minimum_fragment_share": MINIMUM_FRAGMENT_SHARE, + "closing_reach": CLOSING_REACH, + "maximum_closing_radius": MAXIMUM_CLOSING_RADIUS, + "minimum_tolerance": MINIMUM_TOLERANCE, + "default_tolerance": DEFAULT_TOLERANCE, + "tolerances": TOLERANCES, + "cases": [_case(name, mask, at) for name, mask, at in CASES], + } + + +def main() -> None: + out = REPO_ROOT / OUTPUT_PATH + out.write_text(json.dumps(build_fixture(), separators=(",", ":"), sort_keys=True) + "\n") + print(f"wrote {out}") + + +if __name__ == "__main__": + main() diff --git a/scripts/verify_npm_packages.sh b/scripts/verify_npm_packages.sh index 6ec94008..cce4d3cb 100755 --- a/scripts/verify_npm_packages.sh +++ b/scripts/verify_npm_packages.sh @@ -172,6 +172,7 @@ done echo "no dependency resolved back into the workspace" cat > esm-check.mjs <<'JS' +import assert from "node:assert"; import "@visionset/annotator"; import "@visionset/ui-core"; // The core entrypoint on its own: plain Node has no browser globals, so an @@ -183,8 +184,18 @@ import "@visionset/media"; import "@visionset/browser-inference"; import { EFFICIENT_SAM_TI } from "@visionset/browser-inference"; if (EFFICIENT_SAM_TI.maxPoints !== 6) throw new Error("core entry lost the model constants"); + +// Mask -> geometry: a real call, not just a resolved symbol — proves the +// kernel's pipeline still runs correctly from the packed tarball in plain Node. +const { shapesFromMask } = await import("@visionset/annotator"); +const mask = { width: 3, height: 3, mask: Uint8Array.from([0, 0, 0, 0, 1, 1, 0, 1, 1]) }; +const shaped = shapesFromMask(mask, { allowed: ["bbox"] }); +assert.deepEqual(shaped, [{ geometry: { type: "bbox", x: 1, y: 1, width: 2, height: 2 }, contour: [] }]); +const outlined = shapesFromMask(mask, { allowed: ["polygon"], tolerance: 1 }); +assert.equal(outlined[0].geometry.type, "polygon"); + console.log( - "Node ESM import OK: @visionset/annotator, @visionset/ui-core, @visionset/media (core), @visionset/browser-inference (core, EFFICIENT_SAM_TI)", + "Node ESM import OK: @visionset/annotator (core, shapesFromMask), @visionset/ui-core, @visionset/media (core), @visionset/browser-inference (core, EFFICIENT_SAM_TI)", ); JS node esm-check.mjs @@ -210,7 +221,7 @@ cat > tsconfig.json <<'JSON' JSON cat > ts-check.ts <<'TS' -import "@visionset/annotator"; +import { shapesFromMask, type BinaryMask, type ShapedGeometry } from "@visionset/annotator"; import "@visionset/ui-core"; import "@visionset/media"; import type { MediabunnyVideoMaterializer } from "@visionset/media/mediabunny"; @@ -233,7 +244,21 @@ export type { PixelImage, PointPrompt, PreparedImage, PromptableSegmentationRuntime, RawSegmentation, }; export type CreateEfficientSamRuntime = typeof createEfficientSamRuntime; + +const packedMask: BinaryMask = { width: 1, height: 1, mask: new Uint8Array([1]) }; +const packedShaped: readonly ShapedGeometry[] = shapesFromMask(packedMask, { allowed: ["bbox"] }); +void packedShaped; + +type Equal = + (() => Value extends Left ? 1 : 2) extends + (() => Value extends Right ? 1 : 2) + ? true + : false; +type Assert = Condition; +type _ShapesFromMaskReturnsReadonly = Assert< + Equal, readonly ShapedGeometry[]> +>; TS pnpm exec tsc -p tsconfig.json -echo "TypeScript consumer resolved @visionset/annotator, @visionset/ui-core, @visionset/media, @visionset/media/mediabunny, @visionset/browser-inference, @visionset/browser-inference/browser and the EfficientSAM model surface under nodenext OK" +echo "TypeScript consumer resolved @visionset/annotator (shapesFromMask, BinaryMask, ShapedGeometry), @visionset/ui-core, @visionset/media, @visionset/media/mediabunny, @visionset/browser-inference, @visionset/browser-inference/browser and the EfficientSAM model surface under nodenext OK" diff --git a/src/visionset/inference/masks.py b/src/visionset/inference/masks.py index e23cbf9d..026f3078 100644 --- a/src/visionset/inference/masks.py +++ b/src/visionset/inference/masks.py @@ -266,12 +266,17 @@ def join(left: int, right: int) -> None: return [root(index) for index in range(len(found))] -def _gap(point: Point, run: tuple[int, int, int]) -> float: - """Distance from a point to a run, which is a horizontal segment of pixels.""" +def _squared_gap(point: Point, run: tuple[int, int, int]) -> float: + """Squared distance from a point to a run, which is a horizontal segment of pixels. + + The square root cannot change which run is nearest, and leaving it out keeps + a one-ulp libm rounding difference from turning a geometric ordering into a + reading-order tie. + """ x, y = point row, first, last = run across = max(0.0, first - x, x - last) - return (across * across + (row - y) * (row - y)) ** 0.5 + return across * across + (row - y) * (row - y) def _areas(found: Sequence[tuple[int, int, int]], labels: Sequence[int]) -> dict[int, int]: @@ -296,8 +301,15 @@ def _pointed_at( rather than of what was clicked. Three cases, in order. A point inside a piece picks that piece; several - points inside several pieces pick the largest of them, because two positives - are a caller describing one object rather than proposing two. A point inside + points inside several pieces pick the largest of them, because two + positives are a caller describing one object rather than proposing two — + and two of the same size pick the lowest label, which is the piece whose + earliest run comes first. That last clause is not a new preference: it is + the ``(-size, label)`` order :func:`components` already applies to every + piece behind the head, written where it was missing. It has to be written + somewhere, because the alternative was ``max`` over a *set* of labels, and a + set's iteration order is an interpreter's hash-table layout rather than a + rule a second implementation could hold to. A point inside none of them — the model's mask need not cover the exact pixel clicked — picks the piece nearest the point, which is still an answer about where the user pointed. Negatives never select: they say what the shape is not, and a @@ -315,9 +327,9 @@ def _pointed_at( if row == round(point[1]) and first <= round(point[0]) <= last } if under: - return max(under, key=lambda label: size[label]) + return min(under, key=lambda label: (-size[label], label)) nearest = min( - range(len(found)), key=lambda index: min(_gap(point, found[index]) for point in at) + range(len(found)), key=lambda index: min(_squared_gap(point, found[index]) for point in at) ) return labels[nearest] diff --git a/tests/fixtures/mask_geometry.json b/tests/fixtures/mask_geometry.json new file mode 100644 index 00000000..b05bc7b0 --- /dev/null +++ b/tests/fixtures/mask_geometry.json @@ -0,0 +1 @@ +{"cases":[{"at":[],"closing_radius":null,"components":[],"contour":null,"filled":null,"mask":{"height":20,"runs":[],"width":20},"name":"empty","outline":null,"shapes":{"bbox":{"0.25":[],"0.5":[],"1.0":[],"16.0":[],"2.0":[],"4.0":[],"8.0":[]},"bbox,polygon":{"0.25":[],"0.5":[],"1.0":[],"16.0":[],"2.0":[],"4.0":[],"8.0":[]},"polygon":{"0.25":[],"0.5":[],"1.0":[],"16.0":[],"2.0":[],"4.0":[],"8.0":[]},"polygon,bbox":{"0.25":[],"0.5":[],"1.0":[],"16.0":[],"2.0":[],"4.0":[],"8.0":[]},"polyline":{"0.25":[],"0.5":[],"1.0":[],"16.0":[],"2.0":[],"4.0":[],"8.0":[]}}},{"at":[],"closing_radius":0,"components":[{"height":1,"runs":[[0,0,0]],"width":1,"x":3,"y":2}],"contour":[[0.25,0.0],[0.75,0.0],[1.0,0.75],[0.25,1.0],[0.0,0.25]],"filled":{"height":1,"runs":[[0,0,0]],"width":1},"mask":{"height":5,"runs":[[2,3,3]],"width":5},"name":"single-pixel","outline":[[0.0,0.0],[1.0,0.0],[1.0,1.0],[0.0,1.0]],"shapes":{"bbox":{"0.25":[{"contour":[],"geometry":{"height":1.0,"type":"bbox","width":1.0,"x":3.0,"y":2.0}}],"0.5":[{"contour":[],"geometry":{"height":1.0,"type":"bbox","width":1.0,"x":3.0,"y":2.0}}],"1.0":[{"contour":[],"geometry":{"height":1.0,"type":"bbox","width":1.0,"x":3.0,"y":2.0}}],"16.0":[{"contour":[],"geometry":{"height":1.0,"type":"bbox","width":1.0,"x":3.0,"y":2.0}}],"2.0":[{"contour":[],"geometry":{"height":1.0,"type":"bbox","width":1.0,"x":3.0,"y":2.0}}],"4.0":[{"contour":[],"geometry":{"height":1.0,"type":"bbox","width":1.0,"x":3.0,"y":2.0}}],"8.0":[{"contour":[],"geometry":{"height":1.0,"type":"bbox","width":1.0,"x":3.0,"y":2.0}}]},"bbox,polygon":{"0.25":[{"contour":[[3.25,2.0],[3.75,2.0],[4.0,2.75],[3.25,3.0],[3.0,2.25]],"geometry":{"points":[[3.25,2.0],[3.75,2.0],[4.0,2.75],[3.25,3.0]],"type":"polygon"}}],"0.5":[{"contour":[[3.25,2.0],[3.75,2.0],[4.0,2.75],[3.25,3.0],[3.0,2.25]],"geometry":{"points":[[3.25,2.0],[4.0,2.75],[3.25,3.0]],"type":"polygon"}}],"1.0":[{"contour":[[3.25,2.0],[3.75,2.0],[4.0,2.75],[3.25,3.0],[3.0,2.25]],"geometry":{"points":[[3.25,2.0],[4.0,2.75],[3.0,2.25]],"type":"polygon"}}],"16.0":[],"2.0":[],"4.0":[],"8.0":[]},"polygon":{"0.25":[{"contour":[[3.25,2.0],[3.75,2.0],[4.0,2.75],[3.25,3.0],[3.0,2.25]],"geometry":{"points":[[3.25,2.0],[3.75,2.0],[4.0,2.75],[3.25,3.0]],"type":"polygon"}}],"0.5":[{"contour":[[3.25,2.0],[3.75,2.0],[4.0,2.75],[3.25,3.0],[3.0,2.25]],"geometry":{"points":[[3.25,2.0],[4.0,2.75],[3.25,3.0]],"type":"polygon"}}],"1.0":[{"contour":[[3.25,2.0],[3.75,2.0],[4.0,2.75],[3.25,3.0],[3.0,2.25]],"geometry":{"points":[[3.25,2.0],[4.0,2.75],[3.0,2.25]],"type":"polygon"}}],"16.0":[],"2.0":[],"4.0":[],"8.0":[]},"polygon,bbox":{"0.25":[{"contour":[[3.25,2.0],[3.75,2.0],[4.0,2.75],[3.25,3.0],[3.0,2.25]],"geometry":{"points":[[3.25,2.0],[3.75,2.0],[4.0,2.75],[3.25,3.0]],"type":"polygon"}}],"0.5":[{"contour":[[3.25,2.0],[3.75,2.0],[4.0,2.75],[3.25,3.0],[3.0,2.25]],"geometry":{"points":[[3.25,2.0],[4.0,2.75],[3.25,3.0]],"type":"polygon"}}],"1.0":[{"contour":[[3.25,2.0],[3.75,2.0],[4.0,2.75],[3.25,3.0],[3.0,2.25]],"geometry":{"points":[[3.25,2.0],[4.0,2.75],[3.0,2.25]],"type":"polygon"}}],"16.0":[],"2.0":[],"4.0":[],"8.0":[]},"polyline":{"0.25":[],"0.5":[],"1.0":[],"16.0":[],"2.0":[],"4.0":[],"8.0":[]}}},{"at":[],"closing_radius":0,"components":[{"height":19,"runs":[[0,0,24],[1,0,24],[2,0,24],[3,0,24],[4,0,24],[5,0,24],[6,0,24],[7,0,24],[8,0,24],[9,0,24],[10,0,24],[11,0,24],[12,0,24],[13,0,24],[14,0,24],[15,0,24],[16,0,24],[17,0,24],[18,0,24]],"width":25,"x":6,"y":6}],"contour":[[0.25,0.0],[24.75,0.0],[25.0,18.75],[0.25,19.0],[0.0,0.25]],"filled":{"height":19,"runs":[[0,0,24],[1,0,24],[2,0,24],[3,0,24],[4,0,24],[5,0,24],[6,0,24],[7,0,24],[8,0,24],[9,0,24],[10,0,24],[11,0,24],[12,0,24],[13,0,24],[14,0,24],[15,0,24],[16,0,24],[17,0,24],[18,0,24]],"width":25},"mask":{"height":40,"runs":[[6,6,30],[7,6,30],[8,6,30],[9,6,30],[10,6,30],[11,6,30],[12,6,30],[13,6,30],[14,6,30],[15,6,30],[16,6,30],[17,6,30],[18,6,30],[19,6,30],[20,6,30],[21,6,30],[22,6,30],[23,6,30],[24,6,30]],"width":40},"name":"rectangle","outline":[[0.0,0.0],[1.0,0.0],[2.0,0.0],[3.0,0.0],[4.0,0.0],[5.0,0.0],[6.0,0.0],[7.0,0.0],[8.0,0.0],[9.0,0.0],[10.0,0.0],[11.0,0.0],[12.0,0.0],[13.0,0.0],[14.0,0.0],[15.0,0.0],[16.0,0.0],[17.0,0.0],[18.0,0.0],[19.0,0.0],[20.0,0.0],[21.0,0.0],[22.0,0.0],[23.0,0.0],[24.0,0.0],[25.0,0.0],[25.0,1.0],[25.0,2.0],[25.0,3.0],[25.0,4.0],[25.0,5.0],[25.0,6.0],[25.0,7.0],[25.0,8.0],[25.0,9.0],[25.0,10.0],[25.0,11.0],[25.0,12.0],[25.0,13.0],[25.0,14.0],[25.0,15.0],[25.0,16.0],[25.0,17.0],[25.0,18.0],[25.0,19.0],[24.0,19.0],[23.0,19.0],[22.0,19.0],[21.0,19.0],[20.0,19.0],[19.0,19.0],[18.0,19.0],[17.0,19.0],[16.0,19.0],[15.0,19.0],[14.0,19.0],[13.0,19.0],[12.0,19.0],[11.0,19.0],[10.0,19.0],[9.0,19.0],[8.0,19.0],[7.0,19.0],[6.0,19.0],[5.0,19.0],[4.0,19.0],[3.0,19.0],[2.0,19.0],[1.0,19.0],[0.0,19.0],[0.0,18.0],[0.0,17.0],[0.0,16.0],[0.0,15.0],[0.0,14.0],[0.0,13.0],[0.0,12.0],[0.0,11.0],[0.0,10.0],[0.0,9.0],[0.0,8.0],[0.0,7.0],[0.0,6.0],[0.0,5.0],[0.0,4.0],[0.0,3.0],[0.0,2.0],[0.0,1.0]],"shapes":{"bbox":{"0.25":[{"contour":[],"geometry":{"height":19.0,"type":"bbox","width":25.0,"x":6.0,"y":6.0}}],"0.5":[{"contour":[],"geometry":{"height":19.0,"type":"bbox","width":25.0,"x":6.0,"y":6.0}}],"1.0":[{"contour":[],"geometry":{"height":19.0,"type":"bbox","width":25.0,"x":6.0,"y":6.0}}],"16.0":[{"contour":[],"geometry":{"height":19.0,"type":"bbox","width":25.0,"x":6.0,"y":6.0}}],"2.0":[{"contour":[],"geometry":{"height":19.0,"type":"bbox","width":25.0,"x":6.0,"y":6.0}}],"4.0":[{"contour":[],"geometry":{"height":19.0,"type":"bbox","width":25.0,"x":6.0,"y":6.0}}],"8.0":[{"contour":[],"geometry":{"height":19.0,"type":"bbox","width":25.0,"x":6.0,"y":6.0}}]},"bbox,polygon":{"0.25":[{"contour":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0],[6.0,6.25]],"geometry":{"points":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0]],"type":"polygon"}}],"0.5":[{"contour":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0],[6.0,6.25]],"geometry":{"points":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0]],"type":"polygon"}}],"1.0":[{"contour":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0],[6.0,6.25]],"geometry":{"points":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0]],"type":"polygon"}}],"16.0":[{"contour":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0],[6.0,6.25]],"geometry":{"points":[[6.25,6.0],[31.0,24.75],[6.0,6.25]],"type":"polygon"}}],"2.0":[{"contour":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0],[6.0,6.25]],"geometry":{"points":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0]],"type":"polygon"}}],"4.0":[{"contour":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0],[6.0,6.25]],"geometry":{"points":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0]],"type":"polygon"}}],"8.0":[{"contour":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0],[6.0,6.25]],"geometry":{"points":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0]],"type":"polygon"}}]},"polygon":{"0.25":[{"contour":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0],[6.0,6.25]],"geometry":{"points":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0]],"type":"polygon"}}],"0.5":[{"contour":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0],[6.0,6.25]],"geometry":{"points":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0]],"type":"polygon"}}],"1.0":[{"contour":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0],[6.0,6.25]],"geometry":{"points":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0]],"type":"polygon"}}],"16.0":[{"contour":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0],[6.0,6.25]],"geometry":{"points":[[6.25,6.0],[31.0,24.75],[6.0,6.25]],"type":"polygon"}}],"2.0":[{"contour":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0],[6.0,6.25]],"geometry":{"points":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0]],"type":"polygon"}}],"4.0":[{"contour":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0],[6.0,6.25]],"geometry":{"points":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0]],"type":"polygon"}}],"8.0":[{"contour":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0],[6.0,6.25]],"geometry":{"points":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0]],"type":"polygon"}}]},"polygon,bbox":{"0.25":[{"contour":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0],[6.0,6.25]],"geometry":{"points":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0]],"type":"polygon"}}],"0.5":[{"contour":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0],[6.0,6.25]],"geometry":{"points":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0]],"type":"polygon"}}],"1.0":[{"contour":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0],[6.0,6.25]],"geometry":{"points":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0]],"type":"polygon"}}],"16.0":[{"contour":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0],[6.0,6.25]],"geometry":{"points":[[6.25,6.0],[31.0,24.75],[6.0,6.25]],"type":"polygon"}}],"2.0":[{"contour":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0],[6.0,6.25]],"geometry":{"points":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0]],"type":"polygon"}}],"4.0":[{"contour":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0],[6.0,6.25]],"geometry":{"points":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0]],"type":"polygon"}}],"8.0":[{"contour":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0],[6.0,6.25]],"geometry":{"points":[[6.25,6.0],[30.75,6.0],[31.0,24.75],[6.25,25.0]],"type":"polygon"}}]},"polyline":{"0.25":[],"0.5":[],"1.0":[],"16.0":[],"2.0":[],"4.0":[],"8.0":[]}}},{"at":[],"closing_radius":0,"components":[{"height":41,"runs":[[0,20,20],[1,14,26],[2,12,28],[3,10,30],[4,8,32],[5,7,33],[6,6,34],[7,5,35],[8,4,36],[9,4,36],[10,3,37],[11,3,37],[12,2,38],[13,2,38],[14,1,39],[15,1,39],[16,1,39],[17,1,39],[18,1,39],[19,1,39],[20,0,40],[21,1,39],[22,1,39],[23,1,39],[24,1,39],[25,1,39],[26,1,39],[27,2,38],[28,2,38],[29,3,37],[30,3,37],[31,4,36],[32,4,36],[33,5,35],[34,6,34],[35,7,33],[36,8,32],[37,10,30],[38,12,28],[39,14,26],[40,20,20]],"width":41,"x":4,"y":4}],"contour":[[20.25,0.0],[20.75,0.0],[21.25,1.0],[26.75,1.0],[27.25,2.0],[28.75,2.0],[29.25,3.0],[30.75,3.0],[31.25,4.0],[32.75,4.0],[33.0,4.75],[33.75,5.0],[34.0,5.75],[34.75,6.0],[35.0,6.75],[37.0,8.25],[37.0,9.75],[38.0,10.25],[38.0,11.75],[39.0,12.25],[39.0,13.75],[40.0,14.25],[40.0,19.75],[41.0,20.25],[41.0,20.75],[40.0,21.25],[40.0,26.75],[39.0,27.25],[39.0,28.75],[38.0,29.25],[38.0,30.75],[37.0,31.25],[37.0,32.75],[36.25,33.0],[36.0,33.75],[35.25,34.0],[35.0,34.75],[34.25,35.0],[32.75,37.0],[31.25,37.0],[30.75,38.0],[29.25,38.0],[28.75,39.0],[27.25,39.0],[26.75,40.0],[21.25,40.0],[20.75,41.0],[20.25,41.0],[19.75,40.0],[14.25,40.0],[13.75,39.0],[12.25,39.0],[11.75,38.0],[10.25,38.0],[9.75,37.0],[8.25,37.0],[8.0,36.25],[7.25,36.0],[7.0,35.25],[6.25,35.0],[6.0,34.25],[4.0,32.75],[4.0,31.25],[3.0,30.75],[3.0,29.25],[2.0,28.75],[2.0,27.25],[1.0,26.75],[1.0,21.25],[0.0,20.75],[0.0,20.25],[1.0,19.75],[1.0,14.25],[2.0,13.75],[2.0,12.25],[3.0,11.75],[3.0,10.25],[4.0,9.75],[4.0,8.25],[4.75,8.0],[5.0,7.25],[5.75,7.0],[6.0,6.25],[6.75,6.0],[8.25,4.0],[9.75,4.0],[10.25,3.0],[11.75,3.0],[12.25,2.0],[13.75,2.0],[14.25,1.0],[19.75,1.0],[20.0,0.25]],"filled":{"height":41,"runs":[[0,20,20],[1,14,26],[2,12,28],[3,10,30],[4,8,32],[5,7,33],[6,6,34],[7,5,35],[8,4,36],[9,4,36],[10,3,37],[11,3,37],[12,2,38],[13,2,38],[14,1,39],[15,1,39],[16,1,39],[17,1,39],[18,1,39],[19,1,39],[20,0,40],[21,1,39],[22,1,39],[23,1,39],[24,1,39],[25,1,39],[26,1,39],[27,2,38],[28,2,38],[29,3,37],[30,3,37],[31,4,36],[32,4,36],[33,5,35],[34,6,34],[35,7,33],[36,8,32],[37,10,30],[38,12,28],[39,14,26],[40,20,20]],"width":41},"mask":{"height":48,"runs":[[4,24,24],[5,18,30],[6,16,32],[7,14,34],[8,12,36],[9,11,37],[10,10,38],[11,9,39],[12,8,40],[13,8,40],[14,7,41],[15,7,41],[16,6,42],[17,6,42],[18,5,43],[19,5,43],[20,5,43],[21,5,43],[22,5,43],[23,5,43],[24,4,44],[25,5,43],[26,5,43],[27,5,43],[28,5,43],[29,5,43],[30,5,43],[31,6,42],[32,6,42],[33,7,41],[34,7,41],[35,8,40],[36,8,40],[37,9,39],[38,10,38],[39,11,37],[40,12,36],[41,14,34],[42,16,32],[43,18,30],[44,24,24]],"width":48},"name":"disc","outline":[[20.0,0.0],[21.0,0.0],[21.0,1.0],[22.0,1.0],[23.0,1.0],[24.0,1.0],[25.0,1.0],[26.0,1.0],[27.0,1.0],[27.0,2.0],[28.0,2.0],[29.0,2.0],[29.0,3.0],[30.0,3.0],[31.0,3.0],[31.0,4.0],[32.0,4.0],[33.0,4.0],[33.0,5.0],[34.0,5.0],[34.0,6.0],[35.0,6.0],[35.0,7.0],[36.0,7.0],[36.0,8.0],[37.0,8.0],[37.0,9.0],[37.0,10.0],[38.0,10.0],[38.0,11.0],[38.0,12.0],[39.0,12.0],[39.0,13.0],[39.0,14.0],[40.0,14.0],[40.0,15.0],[40.0,16.0],[40.0,17.0],[40.0,18.0],[40.0,19.0],[40.0,20.0],[41.0,20.0],[41.0,21.0],[40.0,21.0],[40.0,22.0],[40.0,23.0],[40.0,24.0],[40.0,25.0],[40.0,26.0],[40.0,27.0],[39.0,27.0],[39.0,28.0],[39.0,29.0],[38.0,29.0],[38.0,30.0],[38.0,31.0],[37.0,31.0],[37.0,32.0],[37.0,33.0],[36.0,33.0],[36.0,34.0],[35.0,34.0],[35.0,35.0],[34.0,35.0],[34.0,36.0],[33.0,36.0],[33.0,37.0],[32.0,37.0],[31.0,37.0],[31.0,38.0],[30.0,38.0],[29.0,38.0],[29.0,39.0],[28.0,39.0],[27.0,39.0],[27.0,40.0],[26.0,40.0],[25.0,40.0],[24.0,40.0],[23.0,40.0],[22.0,40.0],[21.0,40.0],[21.0,41.0],[20.0,41.0],[20.0,40.0],[19.0,40.0],[18.0,40.0],[17.0,40.0],[16.0,40.0],[15.0,40.0],[14.0,40.0],[14.0,39.0],[13.0,39.0],[12.0,39.0],[12.0,38.0],[11.0,38.0],[10.0,38.0],[10.0,37.0],[9.0,37.0],[8.0,37.0],[8.0,36.0],[7.0,36.0],[7.0,35.0],[6.0,35.0],[6.0,34.0],[5.0,34.0],[5.0,33.0],[4.0,33.0],[4.0,32.0],[4.0,31.0],[3.0,31.0],[3.0,30.0],[3.0,29.0],[2.0,29.0],[2.0,28.0],[2.0,27.0],[1.0,27.0],[1.0,26.0],[1.0,25.0],[1.0,24.0],[1.0,23.0],[1.0,22.0],[1.0,21.0],[0.0,21.0],[0.0,20.0],[1.0,20.0],[1.0,19.0],[1.0,18.0],[1.0,17.0],[1.0,16.0],[1.0,15.0],[1.0,14.0],[2.0,14.0],[2.0,13.0],[2.0,12.0],[3.0,12.0],[3.0,11.0],[3.0,10.0],[4.0,10.0],[4.0,9.0],[4.0,8.0],[5.0,8.0],[5.0,7.0],[6.0,7.0],[6.0,6.0],[7.0,6.0],[7.0,5.0],[8.0,5.0],[8.0,4.0],[9.0,4.0],[10.0,4.0],[10.0,3.0],[11.0,3.0],[12.0,3.0],[12.0,2.0],[13.0,2.0],[14.0,2.0],[14.0,1.0],[15.0,1.0],[16.0,1.0],[17.0,1.0],[18.0,1.0],[19.0,1.0],[20.0,1.0]],"shapes":{"bbox":{"0.25":[{"contour":[],"geometry":{"height":41.0,"type":"bbox","width":41.0,"x":4.0,"y":4.0}}],"0.5":[{"contour":[],"geometry":{"height":41.0,"type":"bbox","width":41.0,"x":4.0,"y":4.0}}],"1.0":[{"contour":[],"geometry":{"height":41.0,"type":"bbox","width":41.0,"x":4.0,"y":4.0}}],"16.0":[{"contour":[],"geometry":{"height":41.0,"type":"bbox","width":41.0,"x":4.0,"y":4.0}}],"2.0":[{"contour":[],"geometry":{"height":41.0,"type":"bbox","width":41.0,"x":4.0,"y":4.0}}],"4.0":[{"contour":[],"geometry":{"height":41.0,"type":"bbox","width":41.0,"x":4.0,"y":4.0}}],"8.0":[{"contour":[],"geometry":{"height":41.0,"type":"bbox","width":41.0,"x":4.0,"y":4.0}}]},"bbox,polygon":{"0.25":[{"contour":[[24.25,4.0],[24.75,4.0],[25.25,5.0],[30.75,5.0],[31.25,6.0],[32.75,6.0],[33.25,7.0],[34.75,7.0],[35.25,8.0],[36.75,8.0],[37.0,8.75],[37.75,9.0],[38.0,9.75],[38.75,10.0],[39.0,10.75],[41.0,12.25],[41.0,13.75],[42.0,14.25],[42.0,15.75],[43.0,16.25],[43.0,17.75],[44.0,18.25],[44.0,23.75],[45.0,24.25],[45.0,24.75],[44.0,25.25],[44.0,30.75],[43.0,31.25],[43.0,32.75],[42.0,33.25],[42.0,34.75],[41.0,35.25],[41.0,36.75],[40.25,37.0],[40.0,37.75],[39.25,38.0],[39.0,38.75],[38.25,39.0],[36.75,41.0],[35.25,41.0],[34.75,42.0],[33.25,42.0],[32.75,43.0],[31.25,43.0],[30.75,44.0],[25.25,44.0],[24.75,45.0],[24.25,45.0],[23.75,44.0],[18.25,44.0],[17.75,43.0],[16.25,43.0],[15.75,42.0],[14.25,42.0],[13.75,41.0],[12.25,41.0],[12.0,40.25],[11.25,40.0],[11.0,39.25],[10.25,39.0],[10.0,38.25],[8.0,36.75],[8.0,35.25],[7.0,34.75],[7.0,33.25],[6.0,32.75],[6.0,31.25],[5.0,30.75],[5.0,25.25],[4.0,24.75],[4.0,24.25],[5.0,23.75],[5.0,18.25],[6.0,17.75],[6.0,16.25],[7.0,15.75],[7.0,14.25],[8.0,13.75],[8.0,12.25],[8.75,12.0],[9.0,11.25],[9.75,11.0],[10.0,10.25],[10.75,10.0],[12.25,8.0],[13.75,8.0],[14.25,7.0],[15.75,7.0],[16.25,6.0],[17.75,6.0],[18.25,5.0],[23.75,5.0],[24.0,4.25]],"geometry":{"points":[[24.25,4.0],[24.75,4.0],[25.25,5.0],[30.75,5.0],[31.25,6.0],[32.75,6.0],[33.25,7.0],[34.75,7.0],[35.25,8.0],[36.75,8.0],[37.0,8.75],[37.75,9.0],[38.0,9.75],[38.75,10.0],[39.0,10.75],[41.0,12.25],[41.0,13.75],[42.0,14.25],[42.0,15.75],[43.0,16.25],[43.0,17.75],[44.0,18.25],[44.0,23.75],[45.0,24.25],[45.0,24.75],[44.0,25.25],[44.0,30.75],[43.0,31.25],[43.0,32.75],[42.0,33.25],[42.0,34.75],[41.0,35.25],[41.0,36.75],[40.25,37.0],[40.0,37.75],[39.25,38.0],[39.0,38.75],[38.25,39.0],[36.75,41.0],[35.25,41.0],[34.75,42.0],[33.25,42.0],[32.75,43.0],[31.25,43.0],[30.75,44.0],[25.25,44.0],[24.75,45.0],[24.25,45.0],[23.75,44.0],[18.25,44.0],[17.75,43.0],[16.25,43.0],[15.75,42.0],[14.25,42.0],[13.75,41.0],[12.25,41.0],[12.0,40.25],[11.25,40.0],[11.0,39.25],[10.25,39.0],[10.0,38.25],[8.0,36.75],[8.0,35.25],[7.0,34.75],[7.0,33.25],[6.0,32.75],[6.0,31.25],[5.0,30.75],[5.0,25.25],[4.0,24.75],[4.0,24.25],[5.0,23.75],[5.0,18.25],[6.0,17.75],[6.0,16.25],[7.0,15.75],[7.0,14.25],[8.0,13.75],[8.0,12.25],[8.75,12.0],[9.0,11.25],[9.75,11.0],[10.0,10.25],[10.75,10.0],[12.25,8.0],[13.75,8.0],[14.25,7.0],[15.75,7.0],[16.25,6.0],[17.75,6.0],[18.25,5.0],[23.75,5.0]],"type":"polygon"}}],"0.5":[{"contour":[[24.25,4.0],[24.75,4.0],[25.25,5.0],[30.75,5.0],[31.25,6.0],[32.75,6.0],[33.25,7.0],[34.75,7.0],[35.25,8.0],[36.75,8.0],[37.0,8.75],[37.75,9.0],[38.0,9.75],[38.75,10.0],[39.0,10.75],[41.0,12.25],[41.0,13.75],[42.0,14.25],[42.0,15.75],[43.0,16.25],[43.0,17.75],[44.0,18.25],[44.0,23.75],[45.0,24.25],[45.0,24.75],[44.0,25.25],[44.0,30.75],[43.0,31.25],[43.0,32.75],[42.0,33.25],[42.0,34.75],[41.0,35.25],[41.0,36.75],[40.25,37.0],[40.0,37.75],[39.25,38.0],[39.0,38.75],[38.25,39.0],[36.75,41.0],[35.25,41.0],[34.75,42.0],[33.25,42.0],[32.75,43.0],[31.25,43.0],[30.75,44.0],[25.25,44.0],[24.75,45.0],[24.25,45.0],[23.75,44.0],[18.25,44.0],[17.75,43.0],[16.25,43.0],[15.75,42.0],[14.25,42.0],[13.75,41.0],[12.25,41.0],[12.0,40.25],[11.25,40.0],[11.0,39.25],[10.25,39.0],[10.0,38.25],[8.0,36.75],[8.0,35.25],[7.0,34.75],[7.0,33.25],[6.0,32.75],[6.0,31.25],[5.0,30.75],[5.0,25.25],[4.0,24.75],[4.0,24.25],[5.0,23.75],[5.0,18.25],[6.0,17.75],[6.0,16.25],[7.0,15.75],[7.0,14.25],[8.0,13.75],[8.0,12.25],[8.75,12.0],[9.0,11.25],[9.75,11.0],[10.0,10.25],[10.75,10.0],[12.25,8.0],[13.75,8.0],[14.25,7.0],[15.75,7.0],[16.25,6.0],[17.75,6.0],[18.25,5.0],[23.75,5.0],[24.0,4.25]],"geometry":{"points":[[24.25,4.0],[25.25,5.0],[30.75,5.0],[31.25,6.0],[32.75,6.0],[33.25,7.0],[36.75,8.0],[41.0,12.25],[41.0,13.75],[42.0,14.25],[42.0,15.75],[44.0,18.25],[44.0,23.75],[45.0,24.25],[44.0,25.25],[44.0,30.75],[43.0,31.25],[43.0,32.75],[42.0,33.25],[41.0,36.75],[36.75,41.0],[35.25,41.0],[34.75,42.0],[33.25,42.0],[30.75,44.0],[25.25,44.0],[24.75,45.0],[23.75,44.0],[18.25,44.0],[17.75,43.0],[16.25,43.0],[15.75,42.0],[12.25,41.0],[8.0,36.75],[8.0,35.25],[7.0,34.75],[7.0,33.25],[5.0,30.75],[5.0,25.25],[4.0,24.75],[5.0,23.75],[5.0,18.25],[6.0,17.75],[6.0,16.25],[7.0,15.75],[8.0,12.25],[12.25,8.0],[13.75,8.0],[14.25,7.0],[15.75,7.0],[18.25,5.0],[23.75,5.0]],"type":"polygon"}}],"1.0":[{"contour":[[24.25,4.0],[24.75,4.0],[25.25,5.0],[30.75,5.0],[31.25,6.0],[32.75,6.0],[33.25,7.0],[34.75,7.0],[35.25,8.0],[36.75,8.0],[37.0,8.75],[37.75,9.0],[38.0,9.75],[38.75,10.0],[39.0,10.75],[41.0,12.25],[41.0,13.75],[42.0,14.25],[42.0,15.75],[43.0,16.25],[43.0,17.75],[44.0,18.25],[44.0,23.75],[45.0,24.25],[45.0,24.75],[44.0,25.25],[44.0,30.75],[43.0,31.25],[43.0,32.75],[42.0,33.25],[42.0,34.75],[41.0,35.25],[41.0,36.75],[40.25,37.0],[40.0,37.75],[39.25,38.0],[39.0,38.75],[38.25,39.0],[36.75,41.0],[35.25,41.0],[34.75,42.0],[33.25,42.0],[32.75,43.0],[31.25,43.0],[30.75,44.0],[25.25,44.0],[24.75,45.0],[24.25,45.0],[23.75,44.0],[18.25,44.0],[17.75,43.0],[16.25,43.0],[15.75,42.0],[14.25,42.0],[13.75,41.0],[12.25,41.0],[12.0,40.25],[11.25,40.0],[11.0,39.25],[10.25,39.0],[10.0,38.25],[8.0,36.75],[8.0,35.25],[7.0,34.75],[7.0,33.25],[6.0,32.75],[6.0,31.25],[5.0,30.75],[5.0,25.25],[4.0,24.75],[4.0,24.25],[5.0,23.75],[5.0,18.25],[6.0,17.75],[6.0,16.25],[7.0,15.75],[7.0,14.25],[8.0,13.75],[8.0,12.25],[8.75,12.0],[9.0,11.25],[9.75,11.0],[10.0,10.25],[10.75,10.0],[12.25,8.0],[13.75,8.0],[14.25,7.0],[15.75,7.0],[16.25,6.0],[17.75,6.0],[18.25,5.0],[23.75,5.0],[24.0,4.25]],"geometry":{"points":[[24.25,4.0],[30.75,5.0],[36.75,8.0],[41.0,12.25],[45.0,24.25],[44.0,30.75],[41.0,36.75],[36.75,41.0],[24.75,45.0],[18.25,44.0],[12.25,41.0],[8.0,36.75],[4.0,24.75],[5.0,18.25],[8.0,12.25],[12.25,8.0],[18.25,5.0]],"type":"polygon"}}],"16.0":[{"contour":[[24.25,4.0],[24.75,4.0],[25.25,5.0],[30.75,5.0],[31.25,6.0],[32.75,6.0],[33.25,7.0],[34.75,7.0],[35.25,8.0],[36.75,8.0],[37.0,8.75],[37.75,9.0],[38.0,9.75],[38.75,10.0],[39.0,10.75],[41.0,12.25],[41.0,13.75],[42.0,14.25],[42.0,15.75],[43.0,16.25],[43.0,17.75],[44.0,18.25],[44.0,23.75],[45.0,24.25],[45.0,24.75],[44.0,25.25],[44.0,30.75],[43.0,31.25],[43.0,32.75],[42.0,33.25],[42.0,34.75],[41.0,35.25],[41.0,36.75],[40.25,37.0],[40.0,37.75],[39.25,38.0],[39.0,38.75],[38.25,39.0],[36.75,41.0],[35.25,41.0],[34.75,42.0],[33.25,42.0],[32.75,43.0],[31.25,43.0],[30.75,44.0],[25.25,44.0],[24.75,45.0],[24.25,45.0],[23.75,44.0],[18.25,44.0],[17.75,43.0],[16.25,43.0],[15.75,42.0],[14.25,42.0],[13.75,41.0],[12.25,41.0],[12.0,40.25],[11.25,40.0],[11.0,39.25],[10.25,39.0],[10.0,38.25],[8.0,36.75],[8.0,35.25],[7.0,34.75],[7.0,33.25],[6.0,32.75],[6.0,31.25],[5.0,30.75],[5.0,25.25],[4.0,24.75],[4.0,24.25],[5.0,23.75],[5.0,18.25],[6.0,17.75],[6.0,16.25],[7.0,15.75],[7.0,14.25],[8.0,13.75],[8.0,12.25],[8.75,12.0],[9.0,11.25],[9.75,11.0],[10.0,10.25],[10.75,10.0],[12.25,8.0],[13.75,8.0],[14.25,7.0],[15.75,7.0],[16.25,6.0],[17.75,6.0],[18.25,5.0],[23.75,5.0],[24.0,4.25]],"geometry":{"points":[[24.25,4.0],[41.0,36.75],[8.0,36.75]],"type":"polygon"}}],"2.0":[{"contour":[[24.25,4.0],[24.75,4.0],[25.25,5.0],[30.75,5.0],[31.25,6.0],[32.75,6.0],[33.25,7.0],[34.75,7.0],[35.25,8.0],[36.75,8.0],[37.0,8.75],[37.75,9.0],[38.0,9.75],[38.75,10.0],[39.0,10.75],[41.0,12.25],[41.0,13.75],[42.0,14.25],[42.0,15.75],[43.0,16.25],[43.0,17.75],[44.0,18.25],[44.0,23.75],[45.0,24.25],[45.0,24.75],[44.0,25.25],[44.0,30.75],[43.0,31.25],[43.0,32.75],[42.0,33.25],[42.0,34.75],[41.0,35.25],[41.0,36.75],[40.25,37.0],[40.0,37.75],[39.25,38.0],[39.0,38.75],[38.25,39.0],[36.75,41.0],[35.25,41.0],[34.75,42.0],[33.25,42.0],[32.75,43.0],[31.25,43.0],[30.75,44.0],[25.25,44.0],[24.75,45.0],[24.25,45.0],[23.75,44.0],[18.25,44.0],[17.75,43.0],[16.25,43.0],[15.75,42.0],[14.25,42.0],[13.75,41.0],[12.25,41.0],[12.0,40.25],[11.25,40.0],[11.0,39.25],[10.25,39.0],[10.0,38.25],[8.0,36.75],[8.0,35.25],[7.0,34.75],[7.0,33.25],[6.0,32.75],[6.0,31.25],[5.0,30.75],[5.0,25.25],[4.0,24.75],[4.0,24.25],[5.0,23.75],[5.0,18.25],[6.0,17.75],[6.0,16.25],[7.0,15.75],[7.0,14.25],[8.0,13.75],[8.0,12.25],[8.75,12.0],[9.0,11.25],[9.75,11.0],[10.0,10.25],[10.75,10.0],[12.25,8.0],[13.75,8.0],[14.25,7.0],[15.75,7.0],[16.25,6.0],[17.75,6.0],[18.25,5.0],[23.75,5.0],[24.0,4.25]],"geometry":{"points":[[24.25,4.0],[41.0,12.25],[45.0,24.25],[41.0,36.75],[24.75,45.0],[8.0,36.75],[4.0,24.75],[5.0,18.25],[12.25,8.0]],"type":"polygon"}}],"4.0":[{"contour":[[24.25,4.0],[24.75,4.0],[25.25,5.0],[30.75,5.0],[31.25,6.0],[32.75,6.0],[33.25,7.0],[34.75,7.0],[35.25,8.0],[36.75,8.0],[37.0,8.75],[37.75,9.0],[38.0,9.75],[38.75,10.0],[39.0,10.75],[41.0,12.25],[41.0,13.75],[42.0,14.25],[42.0,15.75],[43.0,16.25],[43.0,17.75],[44.0,18.25],[44.0,23.75],[45.0,24.25],[45.0,24.75],[44.0,25.25],[44.0,30.75],[43.0,31.25],[43.0,32.75],[42.0,33.25],[42.0,34.75],[41.0,35.25],[41.0,36.75],[40.25,37.0],[40.0,37.75],[39.25,38.0],[39.0,38.75],[38.25,39.0],[36.75,41.0],[35.25,41.0],[34.75,42.0],[33.25,42.0],[32.75,43.0],[31.25,43.0],[30.75,44.0],[25.25,44.0],[24.75,45.0],[24.25,45.0],[23.75,44.0],[18.25,44.0],[17.75,43.0],[16.25,43.0],[15.75,42.0],[14.25,42.0],[13.75,41.0],[12.25,41.0],[12.0,40.25],[11.25,40.0],[11.0,39.25],[10.25,39.0],[10.0,38.25],[8.0,36.75],[8.0,35.25],[7.0,34.75],[7.0,33.25],[6.0,32.75],[6.0,31.25],[5.0,30.75],[5.0,25.25],[4.0,24.75],[4.0,24.25],[5.0,23.75],[5.0,18.25],[6.0,17.75],[6.0,16.25],[7.0,15.75],[7.0,14.25],[8.0,13.75],[8.0,12.25],[8.75,12.0],[9.0,11.25],[9.75,11.0],[10.0,10.25],[10.75,10.0],[12.25,8.0],[13.75,8.0],[14.25,7.0],[15.75,7.0],[16.25,6.0],[17.75,6.0],[18.25,5.0],[23.75,5.0],[24.0,4.25]],"geometry":{"points":[[24.25,4.0],[41.0,12.25],[41.0,36.75],[24.75,45.0],[8.0,36.75],[5.0,18.25]],"type":"polygon"}}],"8.0":[{"contour":[[24.25,4.0],[24.75,4.0],[25.25,5.0],[30.75,5.0],[31.25,6.0],[32.75,6.0],[33.25,7.0],[34.75,7.0],[35.25,8.0],[36.75,8.0],[37.0,8.75],[37.75,9.0],[38.0,9.75],[38.75,10.0],[39.0,10.75],[41.0,12.25],[41.0,13.75],[42.0,14.25],[42.0,15.75],[43.0,16.25],[43.0,17.75],[44.0,18.25],[44.0,23.75],[45.0,24.25],[45.0,24.75],[44.0,25.25],[44.0,30.75],[43.0,31.25],[43.0,32.75],[42.0,33.25],[42.0,34.75],[41.0,35.25],[41.0,36.75],[40.25,37.0],[40.0,37.75],[39.25,38.0],[39.0,38.75],[38.25,39.0],[36.75,41.0],[35.25,41.0],[34.75,42.0],[33.25,42.0],[32.75,43.0],[31.25,43.0],[30.75,44.0],[25.25,44.0],[24.75,45.0],[24.25,45.0],[23.75,44.0],[18.25,44.0],[17.75,43.0],[16.25,43.0],[15.75,42.0],[14.25,42.0],[13.75,41.0],[12.25,41.0],[12.0,40.25],[11.25,40.0],[11.0,39.25],[10.25,39.0],[10.0,38.25],[8.0,36.75],[8.0,35.25],[7.0,34.75],[7.0,33.25],[6.0,32.75],[6.0,31.25],[5.0,30.75],[5.0,25.25],[4.0,24.75],[4.0,24.25],[5.0,23.75],[5.0,18.25],[6.0,17.75],[6.0,16.25],[7.0,15.75],[7.0,14.25],[8.0,13.75],[8.0,12.25],[8.75,12.0],[9.0,11.25],[9.75,11.0],[10.0,10.25],[10.75,10.0],[12.25,8.0],[13.75,8.0],[14.25,7.0],[15.75,7.0],[16.25,6.0],[17.75,6.0],[18.25,5.0],[23.75,5.0],[24.0,4.25]],"geometry":{"points":[[24.25,4.0],[41.0,12.25],[41.0,36.75],[24.75,45.0],[8.0,36.75],[5.0,18.25]],"type":"polygon"}}]},"polygon":{"0.25":[{"contour":[[24.25,4.0],[24.75,4.0],[25.25,5.0],[30.75,5.0],[31.25,6.0],[32.75,6.0],[33.25,7.0],[34.75,7.0],[35.25,8.0],[36.75,8.0],[37.0,8.75],[37.75,9.0],[38.0,9.75],[38.75,10.0],[39.0,10.75],[41.0,12.25],[41.0,13.75],[42.0,14.25],[42.0,15.75],[43.0,16.25],[43.0,17.75],[44.0,18.25],[44.0,23.75],[45.0,24.25],[45.0,24.75],[44.0,25.25],[44.0,30.75],[43.0,31.25],[43.0,32.75],[42.0,33.25],[42.0,34.75],[41.0,35.25],[41.0,36.75],[40.25,37.0],[40.0,37.75],[39.25,38.0],[39.0,38.75],[38.25,39.0],[36.75,41.0],[35.25,41.0],[34.75,42.0],[33.25,42.0],[32.75,43.0],[31.25,43.0],[30.75,44.0],[25.25,44.0],[24.75,45.0],[24.25,45.0],[23.75,44.0],[18.25,44.0],[17.75,43.0],[16.25,43.0],[15.75,42.0],[14.25,42.0],[13.75,41.0],[12.25,41.0],[12.0,40.25],[11.25,40.0],[11.0,39.25],[10.25,39.0],[10.0,38.25],[8.0,36.75],[8.0,35.25],[7.0,34.75],[7.0,33.25],[6.0,32.75],[6.0,31.25],[5.0,30.75],[5.0,25.25],[4.0,24.75],[4.0,24.25],[5.0,23.75],[5.0,18.25],[6.0,17.75],[6.0,16.25],[7.0,15.75],[7.0,14.25],[8.0,13.75],[8.0,12.25],[8.75,12.0],[9.0,11.25],[9.75,11.0],[10.0,10.25],[10.75,10.0],[12.25,8.0],[13.75,8.0],[14.25,7.0],[15.75,7.0],[16.25,6.0],[17.75,6.0],[18.25,5.0],[23.75,5.0],[24.0,4.25]],"geometry":{"points":[[24.25,4.0],[24.75,4.0],[25.25,5.0],[30.75,5.0],[31.25,6.0],[32.75,6.0],[33.25,7.0],[34.75,7.0],[35.25,8.0],[36.75,8.0],[37.0,8.75],[37.75,9.0],[38.0,9.75],[38.75,10.0],[39.0,10.75],[41.0,12.25],[41.0,13.75],[42.0,14.25],[42.0,15.75],[43.0,16.25],[43.0,17.75],[44.0,18.25],[44.0,23.75],[45.0,24.25],[45.0,24.75],[44.0,25.25],[44.0,30.75],[43.0,31.25],[43.0,32.75],[42.0,33.25],[42.0,34.75],[41.0,35.25],[41.0,36.75],[40.25,37.0],[40.0,37.75],[39.25,38.0],[39.0,38.75],[38.25,39.0],[36.75,41.0],[35.25,41.0],[34.75,42.0],[33.25,42.0],[32.75,43.0],[31.25,43.0],[30.75,44.0],[25.25,44.0],[24.75,45.0],[24.25,45.0],[23.75,44.0],[18.25,44.0],[17.75,43.0],[16.25,43.0],[15.75,42.0],[14.25,42.0],[13.75,41.0],[12.25,41.0],[12.0,40.25],[11.25,40.0],[11.0,39.25],[10.25,39.0],[10.0,38.25],[8.0,36.75],[8.0,35.25],[7.0,34.75],[7.0,33.25],[6.0,32.75],[6.0,31.25],[5.0,30.75],[5.0,25.25],[4.0,24.75],[4.0,24.25],[5.0,23.75],[5.0,18.25],[6.0,17.75],[6.0,16.25],[7.0,15.75],[7.0,14.25],[8.0,13.75],[8.0,12.25],[8.75,12.0],[9.0,11.25],[9.75,11.0],[10.0,10.25],[10.75,10.0],[12.25,8.0],[13.75,8.0],[14.25,7.0],[15.75,7.0],[16.25,6.0],[17.75,6.0],[18.25,5.0],[23.75,5.0]],"type":"polygon"}}],"0.5":[{"contour":[[24.25,4.0],[24.75,4.0],[25.25,5.0],[30.75,5.0],[31.25,6.0],[32.75,6.0],[33.25,7.0],[34.75,7.0],[35.25,8.0],[36.75,8.0],[37.0,8.75],[37.75,9.0],[38.0,9.75],[38.75,10.0],[39.0,10.75],[41.0,12.25],[41.0,13.75],[42.0,14.25],[42.0,15.75],[43.0,16.25],[43.0,17.75],[44.0,18.25],[44.0,23.75],[45.0,24.25],[45.0,24.75],[44.0,25.25],[44.0,30.75],[43.0,31.25],[43.0,32.75],[42.0,33.25],[42.0,34.75],[41.0,35.25],[41.0,36.75],[40.25,37.0],[40.0,37.75],[39.25,38.0],[39.0,38.75],[38.25,39.0],[36.75,41.0],[35.25,41.0],[34.75,42.0],[33.25,42.0],[32.75,43.0],[31.25,43.0],[30.75,44.0],[25.25,44.0],[24.75,45.0],[24.25,45.0],[23.75,44.0],[18.25,44.0],[17.75,43.0],[16.25,43.0],[15.75,42.0],[14.25,42.0],[13.75,41.0],[12.25,41.0],[12.0,40.25],[11.25,40.0],[11.0,39.25],[10.25,39.0],[10.0,38.25],[8.0,36.75],[8.0,35.25],[7.0,34.75],[7.0,33.25],[6.0,32.75],[6.0,31.25],[5.0,30.75],[5.0,25.25],[4.0,24.75],[4.0,24.25],[5.0,23.75],[5.0,18.25],[6.0,17.75],[6.0,16.25],[7.0,15.75],[7.0,14.25],[8.0,13.75],[8.0,12.25],[8.75,12.0],[9.0,11.25],[9.75,11.0],[10.0,10.25],[10.75,10.0],[12.25,8.0],[13.75,8.0],[14.25,7.0],[15.75,7.0],[16.25,6.0],[17.75,6.0],[18.25,5.0],[23.75,5.0],[24.0,4.25]],"geometry":{"points":[[24.25,4.0],[25.25,5.0],[30.75,5.0],[31.25,6.0],[32.75,6.0],[33.25,7.0],[36.75,8.0],[41.0,12.25],[41.0,13.75],[42.0,14.25],[42.0,15.75],[44.0,18.25],[44.0,23.75],[45.0,24.25],[44.0,25.25],[44.0,30.75],[43.0,31.25],[43.0,32.75],[42.0,33.25],[41.0,36.75],[36.75,41.0],[35.25,41.0],[34.75,42.0],[33.25,42.0],[30.75,44.0],[25.25,44.0],[24.75,45.0],[23.75,44.0],[18.25,44.0],[17.75,43.0],[16.25,43.0],[15.75,42.0],[12.25,41.0],[8.0,36.75],[8.0,35.25],[7.0,34.75],[7.0,33.25],[5.0,30.75],[5.0,25.25],[4.0,24.75],[5.0,23.75],[5.0,18.25],[6.0,17.75],[6.0,16.25],[7.0,15.75],[8.0,12.25],[12.25,8.0],[13.75,8.0],[14.25,7.0],[15.75,7.0],[18.25,5.0],[23.75,5.0]],"type":"polygon"}}],"1.0":[{"contour":[[24.25,4.0],[24.75,4.0],[25.25,5.0],[30.75,5.0],[31.25,6.0],[32.75,6.0],[33.25,7.0],[34.75,7.0],[35.25,8.0],[36.75,8.0],[37.0,8.75],[37.75,9.0],[38.0,9.75],[38.75,10.0],[39.0,10.75],[41.0,12.25],[41.0,13.75],[42.0,14.25],[42.0,15.75],[43.0,16.25],[43.0,17.75],[44.0,18.25],[44.0,23.75],[45.0,24.25],[45.0,24.75],[44.0,25.25],[44.0,30.75],[43.0,31.25],[43.0,32.75],[42.0,33.25],[42.0,34.75],[41.0,35.25],[41.0,36.75],[40.25,37.0],[40.0,37.75],[39.25,38.0],[39.0,38.75],[38.25,39.0],[36.75,41.0],[35.25,41.0],[34.75,42.0],[33.25,42.0],[32.75,43.0],[31.25,43.0],[30.75,44.0],[25.25,44.0],[24.75,45.0],[24.25,45.0],[23.75,44.0],[18.25,44.0],[17.75,43.0],[16.25,43.0],[15.75,42.0],[14.25,42.0],[13.75,41.0],[12.25,41.0],[12.0,40.25],[11.25,40.0],[11.0,39.25],[10.25,39.0],[10.0,38.25],[8.0,36.75],[8.0,35.25],[7.0,34.75],[7.0,33.25],[6.0,32.75],[6.0,31.25],[5.0,30.75],[5.0,25.25],[4.0,24.75],[4.0,24.25],[5.0,23.75],[5.0,18.25],[6.0,17.75],[6.0,16.25],[7.0,15.75],[7.0,14.25],[8.0,13.75],[8.0,12.25],[8.75,12.0],[9.0,11.25],[9.75,11.0],[10.0,10.25],[10.75,10.0],[12.25,8.0],[13.75,8.0],[14.25,7.0],[15.75,7.0],[16.25,6.0],[17.75,6.0],[18.25,5.0],[23.75,5.0],[24.0,4.25]],"geometry":{"points":[[24.25,4.0],[30.75,5.0],[36.75,8.0],[41.0,12.25],[45.0,24.25],[44.0,30.75],[41.0,36.75],[36.75,41.0],[24.75,45.0],[18.25,44.0],[12.25,41.0],[8.0,36.75],[4.0,24.75],[5.0,18.25],[8.0,12.25],[12.25,8.0],[18.25,5.0]],"type":"polygon"}}],"16.0":[{"contour":[[24.25,4.0],[24.75,4.0],[25.25,5.0],[30.75,5.0],[31.25,6.0],[32.75,6.0],[33.25,7.0],[34.75,7.0],[35.25,8.0],[36.75,8.0],[37.0,8.75],[37.75,9.0],[38.0,9.75],[38.75,10.0],[39.0,10.75],[41.0,12.25],[41.0,13.75],[42.0,14.25],[42.0,15.75],[43.0,16.25],[43.0,17.75],[44.0,18.25],[44.0,23.75],[45.0,24.25],[45.0,24.75],[44.0,25.25],[44.0,30.75],[43.0,31.25],[43.0,32.75],[42.0,33.25],[42.0,34.75],[41.0,35.25],[41.0,36.75],[40.25,37.0],[40.0,37.75],[39.25,38.0],[39.0,38.75],[38.25,39.0],[36.75,41.0],[35.25,41.0],[34.75,42.0],[33.25,42.0],[32.75,43.0],[31.25,43.0],[30.75,44.0],[25.25,44.0],[24.75,45.0],[24.25,45.0],[23.75,44.0],[18.25,44.0],[17.75,43.0],[16.25,43.0],[15.75,42.0],[14.25,42.0],[13.75,41.0],[12.25,41.0],[12.0,40.25],[11.25,40.0],[11.0,39.25],[10.25,39.0],[10.0,38.25],[8.0,36.75],[8.0,35.25],[7.0,34.75],[7.0,33.25],[6.0,32.75],[6.0,31.25],[5.0,30.75],[5.0,25.25],[4.0,24.75],[4.0,24.25],[5.0,23.75],[5.0,18.25],[6.0,17.75],[6.0,16.25],[7.0,15.75],[7.0,14.25],[8.0,13.75],[8.0,12.25],[8.75,12.0],[9.0,11.25],[9.75,11.0],[10.0,10.25],[10.75,10.0],[12.25,8.0],[13.75,8.0],[14.25,7.0],[15.75,7.0],[16.25,6.0],[17.75,6.0],[18.25,5.0],[23.75,5.0],[24.0,4.25]],"geometry":{"points":[[24.25,4.0],[41.0,36.75],[8.0,36.75]],"type":"polygon"}}],"2.0":[{"contour":[[24.25,4.0],[24.75,4.0],[25.25,5.0],[30.75,5.0],[31.25,6.0],[32.75,6.0],[33.25,7.0],[34.75,7.0],[35.25,8.0],[36.75,8.0],[37.0,8.75],[37.75,9.0],[38.0,9.75],[38.75,10.0],[39.0,10.75],[41.0,12.25],[41.0,13.75],[42.0,14.25],[42.0,15.75],[43.0,16.25],[43.0,17.75],[44.0,18.25],[44.0,23.75],[45.0,24.25],[45.0,24.75],[44.0,25.25],[44.0,30.75],[43.0,31.25],[43.0,32.75],[42.0,33.25],[42.0,34.75],[41.0,35.25],[41.0,36.75],[40.25,37.0],[40.0,37.75],[39.25,38.0],[39.0,38.75],[38.25,39.0],[36.75,41.0],[35.25,41.0],[34.75,42.0],[33.25,42.0],[32.75,43.0],[31.25,43.0],[30.75,44.0],[25.25,44.0],[24.75,45.0],[24.25,45.0],[23.75,44.0],[18.25,44.0],[17.75,43.0],[16.25,43.0],[15.75,42.0],[14.25,42.0],[13.75,41.0],[12.25,41.0],[12.0,40.25],[11.25,40.0],[11.0,39.25],[10.25,39.0],[10.0,38.25],[8.0,36.75],[8.0,35.25],[7.0,34.75],[7.0,33.25],[6.0,32.75],[6.0,31.25],[5.0,30.75],[5.0,25.25],[4.0,24.75],[4.0,24.25],[5.0,23.75],[5.0,18.25],[6.0,17.75],[6.0,16.25],[7.0,15.75],[7.0,14.25],[8.0,13.75],[8.0,12.25],[8.75,12.0],[9.0,11.25],[9.75,11.0],[10.0,10.25],[10.75,10.0],[12.25,8.0],[13.75,8.0],[14.25,7.0],[15.75,7.0],[16.25,6.0],[17.75,6.0],[18.25,5.0],[23.75,5.0],[24.0,4.25]],"geometry":{"points":[[24.25,4.0],[41.0,12.25],[45.0,24.25],[41.0,36.75],[24.75,45.0],[8.0,36.75],[4.0,24.75],[5.0,18.25],[12.25,8.0]],"type":"polygon"}}],"4.0":[{"contour":[[24.25,4.0],[24.75,4.0],[25.25,5.0],[30.75,5.0],[31.25,6.0],[32.75,6.0],[33.25,7.0],[34.75,7.0],[35.25,8.0],[36.75,8.0],[37.0,8.75],[37.75,9.0],[38.0,9.75],[38.75,10.0],[39.0,10.75],[41.0,12.25],[41.0,13.75],[42.0,14.25],[42.0,15.75],[43.0,16.25],[43.0,17.75],[44.0,18.25],[44.0,23.75],[45.0,24.25],[45.0,24.75],[44.0,25.25],[44.0,30.75],[43.0,31.25],[43.0,32.75],[42.0,33.25],[42.0,34.75],[41.0,35.25],[41.0,36.75],[40.25,37.0],[40.0,37.75],[39.25,38.0],[39.0,38.75],[38.25,39.0],[36.75,41.0],[35.25,41.0],[34.75,42.0],[33.25,42.0],[32.75,43.0],[31.25,43.0],[30.75,44.0],[25.25,44.0],[24.75,45.0],[24.25,45.0],[23.75,44.0],[18.25,44.0],[17.75,43.0],[16.25,43.0],[15.75,42.0],[14.25,42.0],[13.75,41.0],[12.25,41.0],[12.0,40.25],[11.25,40.0],[11.0,39.25],[10.25,39.0],[10.0,38.25],[8.0,36.75],[8.0,35.25],[7.0,34.75],[7.0,33.25],[6.0,32.75],[6.0,31.25],[5.0,30.75],[5.0,25.25],[4.0,24.75],[4.0,24.25],[5.0,23.75],[5.0,18.25],[6.0,17.75],[6.0,16.25],[7.0,15.75],[7.0,14.25],[8.0,13.75],[8.0,12.25],[8.75,12.0],[9.0,11.25],[9.75,11.0],[10.0,10.25],[10.75,10.0],[12.25,8.0],[13.75,8.0],[14.25,7.0],[15.75,7.0],[16.25,6.0],[17.75,6.0],[18.25,5.0],[23.75,5.0],[24.0,4.25]],"geometry":{"points":[[24.25,4.0],[41.0,12.25],[41.0,36.75],[24.75,45.0],[8.0,36.75],[5.0,18.25]],"type":"polygon"}}],"8.0":[{"contour":[[24.25,4.0],[24.75,4.0],[25.25,5.0],[30.75,5.0],[31.25,6.0],[32.75,6.0],[33.25,7.0],[34.75,7.0],[35.25,8.0],[36.75,8.0],[37.0,8.75],[37.75,9.0],[38.0,9.75],[38.75,10.0],[39.0,10.75],[41.0,12.25],[41.0,13.75],[42.0,14.25],[42.0,15.75],[43.0,16.25],[43.0,17.75],[44.0,18.25],[44.0,23.75],[45.0,24.25],[45.0,24.75],[44.0,25.25],[44.0,30.75],[43.0,31.25],[43.0,32.75],[42.0,33.25],[42.0,34.75],[41.0,35.25],[41.0,36.75],[40.25,37.0],[40.0,37.75],[39.25,38.0],[39.0,38.75],[38.25,39.0],[36.75,41.0],[35.25,41.0],[34.75,42.0],[33.25,42.0],[32.75,43.0],[31.25,43.0],[30.75,44.0],[25.25,44.0],[24.75,45.0],[24.25,45.0],[23.75,44.0],[18.25,44.0],[17.75,43.0],[16.25,43.0],[15.75,42.0],[14.25,42.0],[13.75,41.0],[12.25,41.0],[12.0,40.25],[11.25,40.0],[11.0,39.25],[10.25,39.0],[10.0,38.25],[8.0,36.75],[8.0,35.25],[7.0,34.75],[7.0,33.25],[6.0,32.75],[6.0,31.25],[5.0,30.75],[5.0,25.25],[4.0,24.75],[4.0,24.25],[5.0,23.75],[5.0,18.25],[6.0,17.75],[6.0,16.25],[7.0,15.75],[7.0,14.25],[8.0,13.75],[8.0,12.25],[8.75,12.0],[9.0,11.25],[9.75,11.0],[10.0,10.25],[10.75,10.0],[12.25,8.0],[13.75,8.0],[14.25,7.0],[15.75,7.0],[16.25,6.0],[17.75,6.0],[18.25,5.0],[23.75,5.0],[24.0,4.25]],"geometry":{"points":[[24.25,4.0],[41.0,12.25],[41.0,36.75],[24.75,45.0],[8.0,36.75],[5.0,18.25]],"type":"polygon"}}]},"polygon,bbox":{"0.25":[{"contour":[[24.25,4.0],[24.75,4.0],[25.25,5.0],[30.75,5.0],[31.25,6.0],[32.75,6.0],[33.25,7.0],[34.75,7.0],[35.25,8.0],[36.75,8.0],[37.0,8.75],[37.75,9.0],[38.0,9.75],[38.75,10.0],[39.0,10.75],[41.0,12.25],[41.0,13.75],[42.0,14.25],[42.0,15.75],[43.0,16.25],[43.0,17.75],[44.0,18.25],[44.0,23.75],[45.0,24.25],[45.0,24.75],[44.0,25.25],[44.0,30.75],[43.0,31.25],[43.0,32.75],[42.0,33.25],[42.0,34.75],[41.0,35.25],[41.0,36.75],[40.25,37.0],[40.0,37.75],[39.25,38.0],[39.0,38.75],[38.25,39.0],[36.75,41.0],[35.25,41.0],[34.75,42.0],[33.25,42.0],[32.75,43.0],[31.25,43.0],[30.75,44.0],[25.25,44.0],[24.75,45.0],[24.25,45.0],[23.75,44.0],[18.25,44.0],[17.75,43.0],[16.25,43.0],[15.75,42.0],[14.25,42.0],[13.75,41.0],[12.25,41.0],[12.0,40.25],[11.25,40.0],[11.0,39.25],[10.25,39.0],[10.0,38.25],[8.0,36.75],[8.0,35.25],[7.0,34.75],[7.0,33.25],[6.0,32.75],[6.0,31.25],[5.0,30.75],[5.0,25.25],[4.0,24.75],[4.0,24.25],[5.0,23.75],[5.0,18.25],[6.0,17.75],[6.0,16.25],[7.0,15.75],[7.0,14.25],[8.0,13.75],[8.0,12.25],[8.75,12.0],[9.0,11.25],[9.75,11.0],[10.0,10.25],[10.75,10.0],[12.25,8.0],[13.75,8.0],[14.25,7.0],[15.75,7.0],[16.25,6.0],[17.75,6.0],[18.25,5.0],[23.75,5.0],[24.0,4.25]],"geometry":{"points":[[24.25,4.0],[24.75,4.0],[25.25,5.0],[30.75,5.0],[31.25,6.0],[32.75,6.0],[33.25,7.0],[34.75,7.0],[35.25,8.0],[36.75,8.0],[37.0,8.75],[37.75,9.0],[38.0,9.75],[38.75,10.0],[39.0,10.75],[41.0,12.25],[41.0,13.75],[42.0,14.25],[42.0,15.75],[43.0,16.25],[43.0,17.75],[44.0,18.25],[44.0,23.75],[45.0,24.25],[45.0,24.75],[44.0,25.25],[44.0,30.75],[43.0,31.25],[43.0,32.75],[42.0,33.25],[42.0,34.75],[41.0,35.25],[41.0,36.75],[40.25,37.0],[40.0,37.75],[39.25,38.0],[39.0,38.75],[38.25,39.0],[36.75,41.0],[35.25,41.0],[34.75,42.0],[33.25,42.0],[32.75,43.0],[31.25,43.0],[30.75,44.0],[25.25,44.0],[24.75,45.0],[24.25,45.0],[23.75,44.0],[18.25,44.0],[17.75,43.0],[16.25,43.0],[15.75,42.0],[14.25,42.0],[13.75,41.0],[12.25,41.0],[12.0,40.25],[11.25,40.0],[11.0,39.25],[10.25,39.0],[10.0,38.25],[8.0,36.75],[8.0,35.25],[7.0,34.75],[7.0,33.25],[6.0,32.75],[6.0,31.25],[5.0,30.75],[5.0,25.25],[4.0,24.75],[4.0,24.25],[5.0,23.75],[5.0,18.25],[6.0,17.75],[6.0,16.25],[7.0,15.75],[7.0,14.25],[8.0,13.75],[8.0,12.25],[8.75,12.0],[9.0,11.25],[9.75,11.0],[10.0,10.25],[10.75,10.0],[12.25,8.0],[13.75,8.0],[14.25,7.0],[15.75,7.0],[16.25,6.0],[17.75,6.0],[18.25,5.0],[23.75,5.0]],"type":"polygon"}}],"0.5":[{"contour":[[24.25,4.0],[24.75,4.0],[25.25,5.0],[30.75,5.0],[31.25,6.0],[32.75,6.0],[33.25,7.0],[34.75,7.0],[35.25,8.0],[36.75,8.0],[37.0,8.75],[37.75,9.0],[38.0,9.75],[38.75,10.0],[39.0,10.75],[41.0,12.25],[41.0,13.75],[42.0,14.25],[42.0,15.75],[43.0,16.25],[43.0,17.75],[44.0,18.25],[44.0,23.75],[45.0,24.25],[45.0,24.75],[44.0,25.25],[44.0,30.75],[43.0,31.25],[43.0,32.75],[42.0,33.25],[42.0,34.75],[41.0,35.25],[41.0,36.75],[40.25,37.0],[40.0,37.75],[39.25,38.0],[39.0,38.75],[38.25,39.0],[36.75,41.0],[35.25,41.0],[34.75,42.0],[33.25,42.0],[32.75,43.0],[31.25,43.0],[30.75,44.0],[25.25,44.0],[24.75,45.0],[24.25,45.0],[23.75,44.0],[18.25,44.0],[17.75,43.0],[16.25,43.0],[15.75,42.0],[14.25,42.0],[13.75,41.0],[12.25,41.0],[12.0,40.25],[11.25,40.0],[11.0,39.25],[10.25,39.0],[10.0,38.25],[8.0,36.75],[8.0,35.25],[7.0,34.75],[7.0,33.25],[6.0,32.75],[6.0,31.25],[5.0,30.75],[5.0,25.25],[4.0,24.75],[4.0,24.25],[5.0,23.75],[5.0,18.25],[6.0,17.75],[6.0,16.25],[7.0,15.75],[7.0,14.25],[8.0,13.75],[8.0,12.25],[8.75,12.0],[9.0,11.25],[9.75,11.0],[10.0,10.25],[10.75,10.0],[12.25,8.0],[13.75,8.0],[14.25,7.0],[15.75,7.0],[16.25,6.0],[17.75,6.0],[18.25,5.0],[23.75,5.0],[24.0,4.25]],"geometry":{"points":[[24.25,4.0],[25.25,5.0],[30.75,5.0],[31.25,6.0],[32.75,6.0],[33.25,7.0],[36.75,8.0],[41.0,12.25],[41.0,13.75],[42.0,14.25],[42.0,15.75],[44.0,18.25],[44.0,23.75],[45.0,24.25],[44.0,25.25],[44.0,30.75],[43.0,31.25],[43.0,32.75],[42.0,33.25],[41.0,36.75],[36.75,41.0],[35.25,41.0],[34.75,42.0],[33.25,42.0],[30.75,44.0],[25.25,44.0],[24.75,45.0],[23.75,44.0],[18.25,44.0],[17.75,43.0],[16.25,43.0],[15.75,42.0],[12.25,41.0],[8.0,36.75],[8.0,35.25],[7.0,34.75],[7.0,33.25],[5.0,30.75],[5.0,25.25],[4.0,24.75],[5.0,23.75],[5.0,18.25],[6.0,17.75],[6.0,16.25],[7.0,15.75],[8.0,12.25],[12.25,8.0],[13.75,8.0],[14.25,7.0],[15.75,7.0],[18.25,5.0],[23.75,5.0]],"type":"polygon"}}],"1.0":[{"contour":[[24.25,4.0],[24.75,4.0],[25.25,5.0],[30.75,5.0],[31.25,6.0],[32.75,6.0],[33.25,7.0],[34.75,7.0],[35.25,8.0],[36.75,8.0],[37.0,8.75],[37.75,9.0],[38.0,9.75],[38.75,10.0],[39.0,10.75],[41.0,12.25],[41.0,13.75],[42.0,14.25],[42.0,15.75],[43.0,16.25],[43.0,17.75],[44.0,18.25],[44.0,23.75],[45.0,24.25],[45.0,24.75],[44.0,25.25],[44.0,30.75],[43.0,31.25],[43.0,32.75],[42.0,33.25],[42.0,34.75],[41.0,35.25],[41.0,36.75],[40.25,37.0],[40.0,37.75],[39.25,38.0],[39.0,38.75],[38.25,39.0],[36.75,41.0],[35.25,41.0],[34.75,42.0],[33.25,42.0],[32.75,43.0],[31.25,43.0],[30.75,44.0],[25.25,44.0],[24.75,45.0],[24.25,45.0],[23.75,44.0],[18.25,44.0],[17.75,43.0],[16.25,43.0],[15.75,42.0],[14.25,42.0],[13.75,41.0],[12.25,41.0],[12.0,40.25],[11.25,40.0],[11.0,39.25],[10.25,39.0],[10.0,38.25],[8.0,36.75],[8.0,35.25],[7.0,34.75],[7.0,33.25],[6.0,32.75],[6.0,31.25],[5.0,30.75],[5.0,25.25],[4.0,24.75],[4.0,24.25],[5.0,23.75],[5.0,18.25],[6.0,17.75],[6.0,16.25],[7.0,15.75],[7.0,14.25],[8.0,13.75],[8.0,12.25],[8.75,12.0],[9.0,11.25],[9.75,11.0],[10.0,10.25],[10.75,10.0],[12.25,8.0],[13.75,8.0],[14.25,7.0],[15.75,7.0],[16.25,6.0],[17.75,6.0],[18.25,5.0],[23.75,5.0],[24.0,4.25]],"geometry":{"points":[[24.25,4.0],[30.75,5.0],[36.75,8.0],[41.0,12.25],[45.0,24.25],[44.0,30.75],[41.0,36.75],[36.75,41.0],[24.75,45.0],[18.25,44.0],[12.25,41.0],[8.0,36.75],[4.0,24.75],[5.0,18.25],[8.0,12.25],[12.25,8.0],[18.25,5.0]],"type":"polygon"}}],"16.0":[{"contour":[[24.25,4.0],[24.75,4.0],[25.25,5.0],[30.75,5.0],[31.25,6.0],[32.75,6.0],[33.25,7.0],[34.75,7.0],[35.25,8.0],[36.75,8.0],[37.0,8.75],[37.75,9.0],[38.0,9.75],[38.75,10.0],[39.0,10.75],[41.0,12.25],[41.0,13.75],[42.0,14.25],[42.0,15.75],[43.0,16.25],[43.0,17.75],[44.0,18.25],[44.0,23.75],[45.0,24.25],[45.0,24.75],[44.0,25.25],[44.0,30.75],[43.0,31.25],[43.0,32.75],[42.0,33.25],[42.0,34.75],[41.0,35.25],[41.0,36.75],[40.25,37.0],[40.0,37.75],[39.25,38.0],[39.0,38.75],[38.25,39.0],[36.75,41.0],[35.25,41.0],[34.75,42.0],[33.25,42.0],[32.75,43.0],[31.25,43.0],[30.75,44.0],[25.25,44.0],[24.75,45.0],[24.25,45.0],[23.75,44.0],[18.25,44.0],[17.75,43.0],[16.25,43.0],[15.75,42.0],[14.25,42.0],[13.75,41.0],[12.25,41.0],[12.0,40.25],[11.25,40.0],[11.0,39.25],[10.25,39.0],[10.0,38.25],[8.0,36.75],[8.0,35.25],[7.0,34.75],[7.0,33.25],[6.0,32.75],[6.0,31.25],[5.0,30.75],[5.0,25.25],[4.0,24.75],[4.0,24.25],[5.0,23.75],[5.0,18.25],[6.0,17.75],[6.0,16.25],[7.0,15.75],[7.0,14.25],[8.0,13.75],[8.0,12.25],[8.75,12.0],[9.0,11.25],[9.75,11.0],[10.0,10.25],[10.75,10.0],[12.25,8.0],[13.75,8.0],[14.25,7.0],[15.75,7.0],[16.25,6.0],[17.75,6.0],[18.25,5.0],[23.75,5.0],[24.0,4.25]],"geometry":{"points":[[24.25,4.0],[41.0,36.75],[8.0,36.75]],"type":"polygon"}}],"2.0":[{"contour":[[24.25,4.0],[24.75,4.0],[25.25,5.0],[30.75,5.0],[31.25,6.0],[32.75,6.0],[33.25,7.0],[34.75,7.0],[35.25,8.0],[36.75,8.0],[37.0,8.75],[37.75,9.0],[38.0,9.75],[38.75,10.0],[39.0,10.75],[41.0,12.25],[41.0,13.75],[42.0,14.25],[42.0,15.75],[43.0,16.25],[43.0,17.75],[44.0,18.25],[44.0,23.75],[45.0,24.25],[45.0,24.75],[44.0,25.25],[44.0,30.75],[43.0,31.25],[43.0,32.75],[42.0,33.25],[42.0,34.75],[41.0,35.25],[41.0,36.75],[40.25,37.0],[40.0,37.75],[39.25,38.0],[39.0,38.75],[38.25,39.0],[36.75,41.0],[35.25,41.0],[34.75,42.0],[33.25,42.0],[32.75,43.0],[31.25,43.0],[30.75,44.0],[25.25,44.0],[24.75,45.0],[24.25,45.0],[23.75,44.0],[18.25,44.0],[17.75,43.0],[16.25,43.0],[15.75,42.0],[14.25,42.0],[13.75,41.0],[12.25,41.0],[12.0,40.25],[11.25,40.0],[11.0,39.25],[10.25,39.0],[10.0,38.25],[8.0,36.75],[8.0,35.25],[7.0,34.75],[7.0,33.25],[6.0,32.75],[6.0,31.25],[5.0,30.75],[5.0,25.25],[4.0,24.75],[4.0,24.25],[5.0,23.75],[5.0,18.25],[6.0,17.75],[6.0,16.25],[7.0,15.75],[7.0,14.25],[8.0,13.75],[8.0,12.25],[8.75,12.0],[9.0,11.25],[9.75,11.0],[10.0,10.25],[10.75,10.0],[12.25,8.0],[13.75,8.0],[14.25,7.0],[15.75,7.0],[16.25,6.0],[17.75,6.0],[18.25,5.0],[23.75,5.0],[24.0,4.25]],"geometry":{"points":[[24.25,4.0],[41.0,12.25],[45.0,24.25],[41.0,36.75],[24.75,45.0],[8.0,36.75],[4.0,24.75],[5.0,18.25],[12.25,8.0]],"type":"polygon"}}],"4.0":[{"contour":[[24.25,4.0],[24.75,4.0],[25.25,5.0],[30.75,5.0],[31.25,6.0],[32.75,6.0],[33.25,7.0],[34.75,7.0],[35.25,8.0],[36.75,8.0],[37.0,8.75],[37.75,9.0],[38.0,9.75],[38.75,10.0],[39.0,10.75],[41.0,12.25],[41.0,13.75],[42.0,14.25],[42.0,15.75],[43.0,16.25],[43.0,17.75],[44.0,18.25],[44.0,23.75],[45.0,24.25],[45.0,24.75],[44.0,25.25],[44.0,30.75],[43.0,31.25],[43.0,32.75],[42.0,33.25],[42.0,34.75],[41.0,35.25],[41.0,36.75],[40.25,37.0],[40.0,37.75],[39.25,38.0],[39.0,38.75],[38.25,39.0],[36.75,41.0],[35.25,41.0],[34.75,42.0],[33.25,42.0],[32.75,43.0],[31.25,43.0],[30.75,44.0],[25.25,44.0],[24.75,45.0],[24.25,45.0],[23.75,44.0],[18.25,44.0],[17.75,43.0],[16.25,43.0],[15.75,42.0],[14.25,42.0],[13.75,41.0],[12.25,41.0],[12.0,40.25],[11.25,40.0],[11.0,39.25],[10.25,39.0],[10.0,38.25],[8.0,36.75],[8.0,35.25],[7.0,34.75],[7.0,33.25],[6.0,32.75],[6.0,31.25],[5.0,30.75],[5.0,25.25],[4.0,24.75],[4.0,24.25],[5.0,23.75],[5.0,18.25],[6.0,17.75],[6.0,16.25],[7.0,15.75],[7.0,14.25],[8.0,13.75],[8.0,12.25],[8.75,12.0],[9.0,11.25],[9.75,11.0],[10.0,10.25],[10.75,10.0],[12.25,8.0],[13.75,8.0],[14.25,7.0],[15.75,7.0],[16.25,6.0],[17.75,6.0],[18.25,5.0],[23.75,5.0],[24.0,4.25]],"geometry":{"points":[[24.25,4.0],[41.0,12.25],[41.0,36.75],[24.75,45.0],[8.0,36.75],[5.0,18.25]],"type":"polygon"}}],"8.0":[{"contour":[[24.25,4.0],[24.75,4.0],[25.25,5.0],[30.75,5.0],[31.25,6.0],[32.75,6.0],[33.25,7.0],[34.75,7.0],[35.25,8.0],[36.75,8.0],[37.0,8.75],[37.75,9.0],[38.0,9.75],[38.75,10.0],[39.0,10.75],[41.0,12.25],[41.0,13.75],[42.0,14.25],[42.0,15.75],[43.0,16.25],[43.0,17.75],[44.0,18.25],[44.0,23.75],[45.0,24.25],[45.0,24.75],[44.0,25.25],[44.0,30.75],[43.0,31.25],[43.0,32.75],[42.0,33.25],[42.0,34.75],[41.0,35.25],[41.0,36.75],[40.25,37.0],[40.0,37.75],[39.25,38.0],[39.0,38.75],[38.25,39.0],[36.75,41.0],[35.25,41.0],[34.75,42.0],[33.25,42.0],[32.75,43.0],[31.25,43.0],[30.75,44.0],[25.25,44.0],[24.75,45.0],[24.25,45.0],[23.75,44.0],[18.25,44.0],[17.75,43.0],[16.25,43.0],[15.75,42.0],[14.25,42.0],[13.75,41.0],[12.25,41.0],[12.0,40.25],[11.25,40.0],[11.0,39.25],[10.25,39.0],[10.0,38.25],[8.0,36.75],[8.0,35.25],[7.0,34.75],[7.0,33.25],[6.0,32.75],[6.0,31.25],[5.0,30.75],[5.0,25.25],[4.0,24.75],[4.0,24.25],[5.0,23.75],[5.0,18.25],[6.0,17.75],[6.0,16.25],[7.0,15.75],[7.0,14.25],[8.0,13.75],[8.0,12.25],[8.75,12.0],[9.0,11.25],[9.75,11.0],[10.0,10.25],[10.75,10.0],[12.25,8.0],[13.75,8.0],[14.25,7.0],[15.75,7.0],[16.25,6.0],[17.75,6.0],[18.25,5.0],[23.75,5.0],[24.0,4.25]],"geometry":{"points":[[24.25,4.0],[41.0,12.25],[41.0,36.75],[24.75,45.0],[8.0,36.75],[5.0,18.25]],"type":"polygon"}}]},"polyline":{"0.25":[],"0.5":[],"1.0":[],"16.0":[],"2.0":[],"4.0":[],"8.0":[]}}},{"at":[],"closing_radius":0,"components":[{"height":6,"runs":[[0,0,5],[1,0,5],[2,0,5],[3,0,5],[4,0,5],[5,0,5]],"width":6,"x":1,"y":3}],"contour":[[0.25,0.0],[5.75,0.0],[6.0,5.75],[0.25,6.0],[0.0,0.25]],"filled":{"height":6,"runs":[[0,0,5],[1,0,5],[2,0,5],[3,0,5],[4,0,5],[5,0,5]],"width":6},"mask":{"height":10,"runs":[[0,9,9],[3,1,6],[4,1,6],[5,1,6],[6,1,6],[7,1,6],[8,1,6]],"width":10},"name":"speck-and-object","outline":[[0.0,0.0],[1.0,0.0],[2.0,0.0],[3.0,0.0],[4.0,0.0],[5.0,0.0],[6.0,0.0],[6.0,1.0],[6.0,2.0],[6.0,3.0],[6.0,4.0],[6.0,5.0],[6.0,6.0],[5.0,6.0],[4.0,6.0],[3.0,6.0],[2.0,6.0],[1.0,6.0],[0.0,6.0],[0.0,5.0],[0.0,4.0],[0.0,3.0],[0.0,2.0],[0.0,1.0]],"shapes":{"bbox":{"0.25":[{"contour":[],"geometry":{"height":6.0,"type":"bbox","width":6.0,"x":1.0,"y":3.0}}],"0.5":[{"contour":[],"geometry":{"height":6.0,"type":"bbox","width":6.0,"x":1.0,"y":3.0}}],"1.0":[{"contour":[],"geometry":{"height":6.0,"type":"bbox","width":6.0,"x":1.0,"y":3.0}}],"16.0":[{"contour":[],"geometry":{"height":6.0,"type":"bbox","width":6.0,"x":1.0,"y":3.0}}],"2.0":[{"contour":[],"geometry":{"height":6.0,"type":"bbox","width":6.0,"x":1.0,"y":3.0}}],"4.0":[{"contour":[],"geometry":{"height":6.0,"type":"bbox","width":6.0,"x":1.0,"y":3.0}}],"8.0":[{"contour":[],"geometry":{"height":6.0,"type":"bbox","width":6.0,"x":1.0,"y":3.0}}]},"bbox,polygon":{"0.25":[{"contour":[[1.25,3.0],[6.75,3.0],[7.0,8.75],[1.25,9.0],[1.0,3.25]],"geometry":{"points":[[1.25,3.0],[6.75,3.0],[7.0,8.75],[1.25,9.0]],"type":"polygon"}}],"0.5":[{"contour":[[1.25,3.0],[6.75,3.0],[7.0,8.75],[1.25,9.0],[1.0,3.25]],"geometry":{"points":[[1.25,3.0],[6.75,3.0],[7.0,8.75],[1.25,9.0]],"type":"polygon"}}],"1.0":[{"contour":[[1.25,3.0],[6.75,3.0],[7.0,8.75],[1.25,9.0],[1.0,3.25]],"geometry":{"points":[[1.25,3.0],[6.75,3.0],[7.0,8.75],[1.25,9.0]],"type":"polygon"}}],"16.0":[],"2.0":[{"contour":[[1.25,3.0],[6.75,3.0],[7.0,8.75],[1.25,9.0],[1.0,3.25]],"geometry":{"points":[[1.25,3.0],[6.75,3.0],[7.0,8.75],[1.25,9.0]],"type":"polygon"}}],"4.0":[{"contour":[[1.25,3.0],[6.75,3.0],[7.0,8.75],[1.25,9.0],[1.0,3.25]],"geometry":{"points":[[1.25,3.0],[7.0,8.75],[1.25,9.0]],"type":"polygon"}}],"8.0":[{"contour":[[1.25,3.0],[6.75,3.0],[7.0,8.75],[1.25,9.0],[1.0,3.25]],"geometry":{"points":[[1.25,3.0],[7.0,8.75],[1.0,3.25]],"type":"polygon"}}]},"polygon":{"0.25":[{"contour":[[1.25,3.0],[6.75,3.0],[7.0,8.75],[1.25,9.0],[1.0,3.25]],"geometry":{"points":[[1.25,3.0],[6.75,3.0],[7.0,8.75],[1.25,9.0]],"type":"polygon"}}],"0.5":[{"contour":[[1.25,3.0],[6.75,3.0],[7.0,8.75],[1.25,9.0],[1.0,3.25]],"geometry":{"points":[[1.25,3.0],[6.75,3.0],[7.0,8.75],[1.25,9.0]],"type":"polygon"}}],"1.0":[{"contour":[[1.25,3.0],[6.75,3.0],[7.0,8.75],[1.25,9.0],[1.0,3.25]],"geometry":{"points":[[1.25,3.0],[6.75,3.0],[7.0,8.75],[1.25,9.0]],"type":"polygon"}}],"16.0":[],"2.0":[{"contour":[[1.25,3.0],[6.75,3.0],[7.0,8.75],[1.25,9.0],[1.0,3.25]],"geometry":{"points":[[1.25,3.0],[6.75,3.0],[7.0,8.75],[1.25,9.0]],"type":"polygon"}}],"4.0":[{"contour":[[1.25,3.0],[6.75,3.0],[7.0,8.75],[1.25,9.0],[1.0,3.25]],"geometry":{"points":[[1.25,3.0],[7.0,8.75],[1.25,9.0]],"type":"polygon"}}],"8.0":[{"contour":[[1.25,3.0],[6.75,3.0],[7.0,8.75],[1.25,9.0],[1.0,3.25]],"geometry":{"points":[[1.25,3.0],[7.0,8.75],[1.0,3.25]],"type":"polygon"}}]},"polygon,bbox":{"0.25":[{"contour":[[1.25,3.0],[6.75,3.0],[7.0,8.75],[1.25,9.0],[1.0,3.25]],"geometry":{"points":[[1.25,3.0],[6.75,3.0],[7.0,8.75],[1.25,9.0]],"type":"polygon"}}],"0.5":[{"contour":[[1.25,3.0],[6.75,3.0],[7.0,8.75],[1.25,9.0],[1.0,3.25]],"geometry":{"points":[[1.25,3.0],[6.75,3.0],[7.0,8.75],[1.25,9.0]],"type":"polygon"}}],"1.0":[{"contour":[[1.25,3.0],[6.75,3.0],[7.0,8.75],[1.25,9.0],[1.0,3.25]],"geometry":{"points":[[1.25,3.0],[6.75,3.0],[7.0,8.75],[1.25,9.0]],"type":"polygon"}}],"16.0":[],"2.0":[{"contour":[[1.25,3.0],[6.75,3.0],[7.0,8.75],[1.25,9.0],[1.0,3.25]],"geometry":{"points":[[1.25,3.0],[6.75,3.0],[7.0,8.75],[1.25,9.0]],"type":"polygon"}}],"4.0":[{"contour":[[1.25,3.0],[6.75,3.0],[7.0,8.75],[1.25,9.0],[1.0,3.25]],"geometry":{"points":[[1.25,3.0],[7.0,8.75],[1.25,9.0]],"type":"polygon"}}],"8.0":[{"contour":[[1.25,3.0],[6.75,3.0],[7.0,8.75],[1.25,9.0],[1.0,3.25]],"geometry":{"points":[[1.25,3.0],[7.0,8.75],[1.0,3.25]],"type":"polygon"}}]},"polyline":{"0.25":[],"0.5":[],"1.0":[],"16.0":[],"2.0":[],"4.0":[],"8.0":[]}}},{"at":[[3.0,4.0]],"closing_radius":0,"components":[{"height":5,"runs":[[0,0,4],[1,0,4],[2,0,4],[3,0,4],[4,0,4]],"width":5,"x":1,"y":2},{"height":4,"runs":[[0,0,3],[1,0,3],[2,0,3],[3,0,3]],"width":4,"x":14,"y":3}],"contour":[[0.25,0.0],[4.75,0.0],[5.0,4.75],[0.25,5.0],[0.0,0.25]],"filled":{"height":5,"runs":[[0,0,4],[1,0,4],[2,0,4],[3,0,4],[4,0,4]],"width":5},"mask":{"height":12,"runs":[[2,1,5],[3,1,5],[3,14,17],[4,1,5],[4,14,17],[5,1,5],[5,14,17],[6,1,5],[6,14,17]],"width":24},"name":"two-islands","outline":[[0.0,0.0],[1.0,0.0],[2.0,0.0],[3.0,0.0],[4.0,0.0],[5.0,0.0],[5.0,1.0],[5.0,2.0],[5.0,3.0],[5.0,4.0],[5.0,5.0],[4.0,5.0],[3.0,5.0],[2.0,5.0],[1.0,5.0],[0.0,5.0],[0.0,4.0],[0.0,3.0],[0.0,2.0],[0.0,1.0]],"shapes":{"bbox":{"0.25":[{"contour":[],"geometry":{"height":5.0,"type":"bbox","width":17.0,"x":1.0,"y":2.0}}],"0.5":[{"contour":[],"geometry":{"height":5.0,"type":"bbox","width":17.0,"x":1.0,"y":2.0}}],"1.0":[{"contour":[],"geometry":{"height":5.0,"type":"bbox","width":17.0,"x":1.0,"y":2.0}}],"16.0":[{"contour":[],"geometry":{"height":5.0,"type":"bbox","width":17.0,"x":1.0,"y":2.0}}],"2.0":[{"contour":[],"geometry":{"height":5.0,"type":"bbox","width":17.0,"x":1.0,"y":2.0}}],"4.0":[{"contour":[],"geometry":{"height":5.0,"type":"bbox","width":17.0,"x":1.0,"y":2.0}}],"8.0":[{"contour":[],"geometry":{"height":5.0,"type":"bbox","width":17.0,"x":1.0,"y":2.0}}]},"bbox,polygon":{"0.25":[{"contour":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0],[1.0,2.25]],"geometry":{"points":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0]],"type":"polygon"}}],"0.5":[{"contour":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0],[1.0,2.25]],"geometry":{"points":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0]],"type":"polygon"}}],"1.0":[{"contour":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0],[1.0,2.25]],"geometry":{"points":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0]],"type":"polygon"}}],"16.0":[],"2.0":[{"contour":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0],[1.0,2.25]],"geometry":{"points":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0]],"type":"polygon"}}],"4.0":[{"contour":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0],[1.0,2.25]],"geometry":{"points":[[1.25,2.0],[6.0,6.75],[1.0,2.25]],"type":"polygon"}}],"8.0":[]},"polygon":{"0.25":[{"contour":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0],[1.0,2.25]],"geometry":{"points":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0]],"type":"polygon"}}],"0.5":[{"contour":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0],[1.0,2.25]],"geometry":{"points":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0]],"type":"polygon"}}],"1.0":[{"contour":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0],[1.0,2.25]],"geometry":{"points":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0]],"type":"polygon"}}],"16.0":[],"2.0":[{"contour":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0],[1.0,2.25]],"geometry":{"points":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0]],"type":"polygon"}}],"4.0":[{"contour":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0],[1.0,2.25]],"geometry":{"points":[[1.25,2.0],[6.0,6.75],[1.0,2.25]],"type":"polygon"}}],"8.0":[]},"polygon,bbox":{"0.25":[{"contour":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0],[1.0,2.25]],"geometry":{"points":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0]],"type":"polygon"}}],"0.5":[{"contour":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0],[1.0,2.25]],"geometry":{"points":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0]],"type":"polygon"}}],"1.0":[{"contour":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0],[1.0,2.25]],"geometry":{"points":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0]],"type":"polygon"}}],"16.0":[],"2.0":[{"contour":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0],[1.0,2.25]],"geometry":{"points":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0]],"type":"polygon"}}],"4.0":[{"contour":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0],[1.0,2.25]],"geometry":{"points":[[1.25,2.0],[6.0,6.75],[1.0,2.25]],"type":"polygon"}}],"8.0":[]},"polyline":{"0.25":[],"0.5":[],"1.0":[],"16.0":[],"2.0":[],"4.0":[],"8.0":[]}}},{"at":[[15.0,4.0]],"closing_radius":0,"components":[{"height":4,"runs":[[0,0,3],[1,0,3],[2,0,3],[3,0,3]],"width":4,"x":14,"y":3},{"height":5,"runs":[[0,0,4],[1,0,4],[2,0,4],[3,0,4],[4,0,4]],"width":5,"x":1,"y":2}],"contour":[[0.25,0.0],[3.75,0.0],[4.0,3.75],[0.25,4.0],[0.0,0.25]],"filled":{"height":4,"runs":[[0,0,3],[1,0,3],[2,0,3],[3,0,3]],"width":4},"mask":{"height":12,"runs":[[2,1,5],[3,1,5],[3,14,17],[4,1,5],[4,14,17],[5,1,5],[5,14,17],[6,1,5],[6,14,17]],"width":24},"name":"point-picks-the-smaller-island","outline":[[0.0,0.0],[1.0,0.0],[2.0,0.0],[3.0,0.0],[4.0,0.0],[4.0,1.0],[4.0,2.0],[4.0,3.0],[4.0,4.0],[3.0,4.0],[2.0,4.0],[1.0,4.0],[0.0,4.0],[0.0,3.0],[0.0,2.0],[0.0,1.0]],"shapes":{"bbox":{"0.25":[{"contour":[],"geometry":{"height":5.0,"type":"bbox","width":17.0,"x":1.0,"y":2.0}}],"0.5":[{"contour":[],"geometry":{"height":5.0,"type":"bbox","width":17.0,"x":1.0,"y":2.0}}],"1.0":[{"contour":[],"geometry":{"height":5.0,"type":"bbox","width":17.0,"x":1.0,"y":2.0}}],"16.0":[{"contour":[],"geometry":{"height":5.0,"type":"bbox","width":17.0,"x":1.0,"y":2.0}}],"2.0":[{"contour":[],"geometry":{"height":5.0,"type":"bbox","width":17.0,"x":1.0,"y":2.0}}],"4.0":[{"contour":[],"geometry":{"height":5.0,"type":"bbox","width":17.0,"x":1.0,"y":2.0}}],"8.0":[{"contour":[],"geometry":{"height":5.0,"type":"bbox","width":17.0,"x":1.0,"y":2.0}}]},"bbox,polygon":{"0.25":[{"contour":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0],[14.0,3.25]],"geometry":{"points":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0]],"type":"polygon"}}],"0.5":[{"contour":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0],[14.0,3.25]],"geometry":{"points":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0]],"type":"polygon"}}],"1.0":[{"contour":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0],[14.0,3.25]],"geometry":{"points":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0]],"type":"polygon"}}],"16.0":[],"2.0":[{"contour":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0],[14.0,3.25]],"geometry":{"points":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0]],"type":"polygon"}}],"4.0":[{"contour":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0],[14.0,3.25]],"geometry":{"points":[[14.25,3.0],[18.0,6.75],[14.0,3.25]],"type":"polygon"}}],"8.0":[]},"polygon":{"0.25":[{"contour":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0],[14.0,3.25]],"geometry":{"points":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0]],"type":"polygon"}}],"0.5":[{"contour":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0],[14.0,3.25]],"geometry":{"points":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0]],"type":"polygon"}}],"1.0":[{"contour":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0],[14.0,3.25]],"geometry":{"points":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0]],"type":"polygon"}}],"16.0":[],"2.0":[{"contour":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0],[14.0,3.25]],"geometry":{"points":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0]],"type":"polygon"}}],"4.0":[{"contour":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0],[14.0,3.25]],"geometry":{"points":[[14.25,3.0],[18.0,6.75],[14.0,3.25]],"type":"polygon"}}],"8.0":[]},"polygon,bbox":{"0.25":[{"contour":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0],[14.0,3.25]],"geometry":{"points":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0]],"type":"polygon"}}],"0.5":[{"contour":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0],[14.0,3.25]],"geometry":{"points":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0]],"type":"polygon"}}],"1.0":[{"contour":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0],[14.0,3.25]],"geometry":{"points":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0]],"type":"polygon"}}],"16.0":[],"2.0":[{"contour":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0],[14.0,3.25]],"geometry":{"points":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0]],"type":"polygon"}}],"4.0":[{"contour":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0],[14.0,3.25]],"geometry":{"points":[[14.25,3.0],[18.0,6.75],[14.0,3.25]],"type":"polygon"}}],"8.0":[]},"polyline":{"0.25":[],"0.5":[],"1.0":[],"16.0":[],"2.0":[],"4.0":[],"8.0":[]}}},{"at":[[15.0,4.0],[3.0,4.0]],"closing_radius":0,"components":[{"height":5,"runs":[[0,0,4],[1,0,4],[2,0,4],[3,0,4],[4,0,4]],"width":5,"x":1,"y":2},{"height":4,"runs":[[0,0,3],[1,0,3],[2,0,3],[3,0,3]],"width":4,"x":14,"y":3}],"contour":[[0.25,0.0],[4.75,0.0],[5.0,4.75],[0.25,5.0],[0.0,0.25]],"filled":{"height":5,"runs":[[0,0,4],[1,0,4],[2,0,4],[3,0,4],[4,0,4]],"width":5},"mask":{"height":12,"runs":[[2,1,5],[3,1,5],[3,14,17],[4,1,5],[4,14,17],[5,1,5],[5,14,17],[6,1,5],[6,14,17]],"width":24},"name":"points-across-components","outline":[[0.0,0.0],[1.0,0.0],[2.0,0.0],[3.0,0.0],[4.0,0.0],[5.0,0.0],[5.0,1.0],[5.0,2.0],[5.0,3.0],[5.0,4.0],[5.0,5.0],[4.0,5.0],[3.0,5.0],[2.0,5.0],[1.0,5.0],[0.0,5.0],[0.0,4.0],[0.0,3.0],[0.0,2.0],[0.0,1.0]],"shapes":{"bbox":{"0.25":[{"contour":[],"geometry":{"height":5.0,"type":"bbox","width":17.0,"x":1.0,"y":2.0}}],"0.5":[{"contour":[],"geometry":{"height":5.0,"type":"bbox","width":17.0,"x":1.0,"y":2.0}}],"1.0":[{"contour":[],"geometry":{"height":5.0,"type":"bbox","width":17.0,"x":1.0,"y":2.0}}],"16.0":[{"contour":[],"geometry":{"height":5.0,"type":"bbox","width":17.0,"x":1.0,"y":2.0}}],"2.0":[{"contour":[],"geometry":{"height":5.0,"type":"bbox","width":17.0,"x":1.0,"y":2.0}}],"4.0":[{"contour":[],"geometry":{"height":5.0,"type":"bbox","width":17.0,"x":1.0,"y":2.0}}],"8.0":[{"contour":[],"geometry":{"height":5.0,"type":"bbox","width":17.0,"x":1.0,"y":2.0}}]},"bbox,polygon":{"0.25":[{"contour":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0],[1.0,2.25]],"geometry":{"points":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0]],"type":"polygon"}}],"0.5":[{"contour":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0],[1.0,2.25]],"geometry":{"points":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0]],"type":"polygon"}}],"1.0":[{"contour":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0],[1.0,2.25]],"geometry":{"points":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0]],"type":"polygon"}}],"16.0":[],"2.0":[{"contour":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0],[1.0,2.25]],"geometry":{"points":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0]],"type":"polygon"}}],"4.0":[{"contour":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0],[1.0,2.25]],"geometry":{"points":[[1.25,2.0],[6.0,6.75],[1.0,2.25]],"type":"polygon"}}],"8.0":[]},"polygon":{"0.25":[{"contour":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0],[1.0,2.25]],"geometry":{"points":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0]],"type":"polygon"}}],"0.5":[{"contour":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0],[1.0,2.25]],"geometry":{"points":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0]],"type":"polygon"}}],"1.0":[{"contour":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0],[1.0,2.25]],"geometry":{"points":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0]],"type":"polygon"}}],"16.0":[],"2.0":[{"contour":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0],[1.0,2.25]],"geometry":{"points":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0]],"type":"polygon"}}],"4.0":[{"contour":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0],[1.0,2.25]],"geometry":{"points":[[1.25,2.0],[6.0,6.75],[1.0,2.25]],"type":"polygon"}}],"8.0":[]},"polygon,bbox":{"0.25":[{"contour":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0],[1.0,2.25]],"geometry":{"points":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0]],"type":"polygon"}}],"0.5":[{"contour":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0],[1.0,2.25]],"geometry":{"points":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0]],"type":"polygon"}}],"1.0":[{"contour":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0],[1.0,2.25]],"geometry":{"points":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0]],"type":"polygon"}}],"16.0":[],"2.0":[{"contour":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0],[1.0,2.25]],"geometry":{"points":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0]],"type":"polygon"}}],"4.0":[{"contour":[[1.25,2.0],[5.75,2.0],[6.0,6.75],[1.25,7.0],[1.0,2.25]],"geometry":{"points":[[1.25,2.0],[6.0,6.75],[1.0,2.25]],"type":"polygon"}}],"8.0":[]},"polyline":{"0.25":[],"0.5":[],"1.0":[],"16.0":[],"2.0":[],"4.0":[],"8.0":[]}}},{"at":[[12.0,2.0],[2.0,3.0]],"closing_radius":0,"components":[{"height":5,"runs":[[0,0,0],[1,0,0],[2,0,0],[3,0,0],[4,0,0]],"width":1,"x":12,"y":0},{"height":5,"runs":[[0,0,0],[1,0,0],[2,0,0],[3,0,0],[4,0,0]],"width":1,"x":2,"y":1},{"height":2,"runs":[[0,0,0],[1,0,0]],"width":1,"x":0,"y":0},{"height":1,"runs":[[0,0,0]],"width":1,"x":4,"y":0},{"height":1,"runs":[[0,0,0]],"width":1,"x":8,"y":0},{"height":1,"runs":[[0,0,0]],"width":1,"x":16,"y":0},{"height":1,"runs":[[0,0,0]],"width":1,"x":20,"y":0},{"height":1,"runs":[[0,0,0]],"width":1,"x":24,"y":0}],"contour":[[0.25,0.0],[1.0,0.25],[1.0,4.75],[0.0,4.75],[0.0,0.25]],"filled":{"height":5,"runs":[[0,0,0],[1,0,0],[2,0,0],[3,0,0],[4,0,0]],"width":1},"mask":{"height":7,"runs":[[0,0,0],[0,4,4],[0,8,8],[0,12,12],[0,16,16],[0,20,20],[0,24,24],[1,0,0],[1,2,2],[1,12,12],[2,2,2],[2,12,12],[3,2,2],[3,12,12],[4,2,2],[4,12,12],[5,2,2]],"width":30},"name":"equal-area-tie","outline":[[0.0,0.0],[1.0,0.0],[1.0,1.0],[1.0,2.0],[1.0,3.0],[1.0,4.0],[1.0,5.0],[0.0,5.0],[0.0,4.0],[0.0,3.0],[0.0,2.0],[0.0,1.0]],"shapes":{"bbox":{"0.25":[{"contour":[],"geometry":{"height":6.0,"type":"bbox","width":25.0,"x":0.0,"y":0.0}}],"0.5":[{"contour":[],"geometry":{"height":6.0,"type":"bbox","width":25.0,"x":0.0,"y":0.0}}],"1.0":[{"contour":[],"geometry":{"height":6.0,"type":"bbox","width":25.0,"x":0.0,"y":0.0}}],"16.0":[{"contour":[],"geometry":{"height":6.0,"type":"bbox","width":25.0,"x":0.0,"y":0.0}}],"2.0":[{"contour":[],"geometry":{"height":6.0,"type":"bbox","width":25.0,"x":0.0,"y":0.0}}],"4.0":[{"contour":[],"geometry":{"height":6.0,"type":"bbox","width":25.0,"x":0.0,"y":0.0}}],"8.0":[{"contour":[],"geometry":{"height":6.0,"type":"bbox","width":25.0,"x":0.0,"y":0.0}}]},"bbox,polygon":{"0.25":[{"contour":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75],[12.0,0.25]],"geometry":{"points":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75]],"type":"polygon"}}],"0.5":[{"contour":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75],[12.0,0.25]],"geometry":{"points":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75]],"type":"polygon"}}],"1.0":[{"contour":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75],[12.0,0.25]],"geometry":{"points":[[12.25,0.0],[13.0,4.75],[12.0,0.25]],"type":"polygon"}}],"16.0":[],"2.0":[{"contour":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75],[12.0,0.25]],"geometry":{"points":[[12.25,0.0],[13.0,4.75],[12.0,0.25]],"type":"polygon"}}],"4.0":[],"8.0":[]},"polygon":{"0.25":[{"contour":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75],[12.0,0.25]],"geometry":{"points":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75]],"type":"polygon"}}],"0.5":[{"contour":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75],[12.0,0.25]],"geometry":{"points":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75]],"type":"polygon"}}],"1.0":[{"contour":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75],[12.0,0.25]],"geometry":{"points":[[12.25,0.0],[13.0,4.75],[12.0,0.25]],"type":"polygon"}}],"16.0":[],"2.0":[{"contour":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75],[12.0,0.25]],"geometry":{"points":[[12.25,0.0],[13.0,4.75],[12.0,0.25]],"type":"polygon"}}],"4.0":[],"8.0":[]},"polygon,bbox":{"0.25":[{"contour":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75],[12.0,0.25]],"geometry":{"points":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75]],"type":"polygon"}}],"0.5":[{"contour":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75],[12.0,0.25]],"geometry":{"points":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75]],"type":"polygon"}}],"1.0":[{"contour":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75],[12.0,0.25]],"geometry":{"points":[[12.25,0.0],[13.0,4.75],[12.0,0.25]],"type":"polygon"}}],"16.0":[],"2.0":[{"contour":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75],[12.0,0.25]],"geometry":{"points":[[12.25,0.0],[13.0,4.75],[12.0,0.25]],"type":"polygon"}}],"4.0":[],"8.0":[]},"polyline":{"0.25":[],"0.5":[],"1.0":[],"16.0":[],"2.0":[],"4.0":[],"8.0":[]}}},{"at":[[2.0,3.0],[12.0,2.0]],"closing_radius":0,"components":[{"height":5,"runs":[[0,0,0],[1,0,0],[2,0,0],[3,0,0],[4,0,0]],"width":1,"x":12,"y":0},{"height":5,"runs":[[0,0,0],[1,0,0],[2,0,0],[3,0,0],[4,0,0]],"width":1,"x":2,"y":1},{"height":2,"runs":[[0,0,0],[1,0,0]],"width":1,"x":0,"y":0},{"height":1,"runs":[[0,0,0]],"width":1,"x":4,"y":0},{"height":1,"runs":[[0,0,0]],"width":1,"x":8,"y":0},{"height":1,"runs":[[0,0,0]],"width":1,"x":16,"y":0},{"height":1,"runs":[[0,0,0]],"width":1,"x":20,"y":0},{"height":1,"runs":[[0,0,0]],"width":1,"x":24,"y":0}],"contour":[[0.25,0.0],[1.0,0.25],[1.0,4.75],[0.0,4.75],[0.0,0.25]],"filled":{"height":5,"runs":[[0,0,0],[1,0,0],[2,0,0],[3,0,0],[4,0,0]],"width":1},"mask":{"height":7,"runs":[[0,0,0],[0,4,4],[0,8,8],[0,12,12],[0,16,16],[0,20,20],[0,24,24],[1,0,0],[1,2,2],[1,12,12],[2,2,2],[2,12,12],[3,2,2],[3,12,12],[4,2,2],[4,12,12],[5,2,2]],"width":30},"name":"equal-area-tie-reversed","outline":[[0.0,0.0],[1.0,0.0],[1.0,1.0],[1.0,2.0],[1.0,3.0],[1.0,4.0],[1.0,5.0],[0.0,5.0],[0.0,4.0],[0.0,3.0],[0.0,2.0],[0.0,1.0]],"shapes":{"bbox":{"0.25":[{"contour":[],"geometry":{"height":6.0,"type":"bbox","width":25.0,"x":0.0,"y":0.0}}],"0.5":[{"contour":[],"geometry":{"height":6.0,"type":"bbox","width":25.0,"x":0.0,"y":0.0}}],"1.0":[{"contour":[],"geometry":{"height":6.0,"type":"bbox","width":25.0,"x":0.0,"y":0.0}}],"16.0":[{"contour":[],"geometry":{"height":6.0,"type":"bbox","width":25.0,"x":0.0,"y":0.0}}],"2.0":[{"contour":[],"geometry":{"height":6.0,"type":"bbox","width":25.0,"x":0.0,"y":0.0}}],"4.0":[{"contour":[],"geometry":{"height":6.0,"type":"bbox","width":25.0,"x":0.0,"y":0.0}}],"8.0":[{"contour":[],"geometry":{"height":6.0,"type":"bbox","width":25.0,"x":0.0,"y":0.0}}]},"bbox,polygon":{"0.25":[{"contour":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75],[12.0,0.25]],"geometry":{"points":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75]],"type":"polygon"}}],"0.5":[{"contour":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75],[12.0,0.25]],"geometry":{"points":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75]],"type":"polygon"}}],"1.0":[{"contour":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75],[12.0,0.25]],"geometry":{"points":[[12.25,0.0],[13.0,4.75],[12.0,0.25]],"type":"polygon"}}],"16.0":[],"2.0":[{"contour":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75],[12.0,0.25]],"geometry":{"points":[[12.25,0.0],[13.0,4.75],[12.0,0.25]],"type":"polygon"}}],"4.0":[],"8.0":[]},"polygon":{"0.25":[{"contour":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75],[12.0,0.25]],"geometry":{"points":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75]],"type":"polygon"}}],"0.5":[{"contour":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75],[12.0,0.25]],"geometry":{"points":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75]],"type":"polygon"}}],"1.0":[{"contour":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75],[12.0,0.25]],"geometry":{"points":[[12.25,0.0],[13.0,4.75],[12.0,0.25]],"type":"polygon"}}],"16.0":[],"2.0":[{"contour":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75],[12.0,0.25]],"geometry":{"points":[[12.25,0.0],[13.0,4.75],[12.0,0.25]],"type":"polygon"}}],"4.0":[],"8.0":[]},"polygon,bbox":{"0.25":[{"contour":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75],[12.0,0.25]],"geometry":{"points":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75]],"type":"polygon"}}],"0.5":[{"contour":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75],[12.0,0.25]],"geometry":{"points":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75]],"type":"polygon"}}],"1.0":[{"contour":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75],[12.0,0.25]],"geometry":{"points":[[12.25,0.0],[13.0,4.75],[12.0,0.25]],"type":"polygon"}}],"16.0":[],"2.0":[{"contour":[[12.25,0.0],[13.0,0.25],[13.0,4.75],[12.0,4.75],[12.0,0.25]],"geometry":{"points":[[12.25,0.0],[13.0,4.75],[12.0,0.25]],"type":"polygon"}}],"4.0":[],"8.0":[]},"polyline":{"0.25":[],"0.5":[],"1.0":[],"16.0":[],"2.0":[],"4.0":[],"8.0":[]}}},{"at":[[20.0,4.0]],"closing_radius":0,"components":[{"height":4,"runs":[[0,0,3],[1,0,3],[2,0,3],[3,0,3]],"width":4,"x":14,"y":3},{"height":5,"runs":[[0,0,4],[1,0,4],[2,0,4],[3,0,4],[4,0,4]],"width":5,"x":1,"y":2}],"contour":[[0.25,0.0],[3.75,0.0],[4.0,3.75],[0.25,4.0],[0.0,0.25]],"filled":{"height":4,"runs":[[0,0,3],[1,0,3],[2,0,3],[3,0,3]],"width":4},"mask":{"height":12,"runs":[[2,1,5],[3,1,5],[3,14,17],[4,1,5],[4,14,17],[5,1,5],[5,14,17],[6,1,5],[6,14,17]],"width":24},"name":"click-outside","outline":[[0.0,0.0],[1.0,0.0],[2.0,0.0],[3.0,0.0],[4.0,0.0],[4.0,1.0],[4.0,2.0],[4.0,3.0],[4.0,4.0],[3.0,4.0],[2.0,4.0],[1.0,4.0],[0.0,4.0],[0.0,3.0],[0.0,2.0],[0.0,1.0]],"shapes":{"bbox":{"0.25":[{"contour":[],"geometry":{"height":5.0,"type":"bbox","width":17.0,"x":1.0,"y":2.0}}],"0.5":[{"contour":[],"geometry":{"height":5.0,"type":"bbox","width":17.0,"x":1.0,"y":2.0}}],"1.0":[{"contour":[],"geometry":{"height":5.0,"type":"bbox","width":17.0,"x":1.0,"y":2.0}}],"16.0":[{"contour":[],"geometry":{"height":5.0,"type":"bbox","width":17.0,"x":1.0,"y":2.0}}],"2.0":[{"contour":[],"geometry":{"height":5.0,"type":"bbox","width":17.0,"x":1.0,"y":2.0}}],"4.0":[{"contour":[],"geometry":{"height":5.0,"type":"bbox","width":17.0,"x":1.0,"y":2.0}}],"8.0":[{"contour":[],"geometry":{"height":5.0,"type":"bbox","width":17.0,"x":1.0,"y":2.0}}]},"bbox,polygon":{"0.25":[{"contour":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0],[14.0,3.25]],"geometry":{"points":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0]],"type":"polygon"}}],"0.5":[{"contour":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0],[14.0,3.25]],"geometry":{"points":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0]],"type":"polygon"}}],"1.0":[{"contour":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0],[14.0,3.25]],"geometry":{"points":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0]],"type":"polygon"}}],"16.0":[],"2.0":[{"contour":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0],[14.0,3.25]],"geometry":{"points":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0]],"type":"polygon"}}],"4.0":[{"contour":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0],[14.0,3.25]],"geometry":{"points":[[14.25,3.0],[18.0,6.75],[14.0,3.25]],"type":"polygon"}}],"8.0":[]},"polygon":{"0.25":[{"contour":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0],[14.0,3.25]],"geometry":{"points":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0]],"type":"polygon"}}],"0.5":[{"contour":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0],[14.0,3.25]],"geometry":{"points":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0]],"type":"polygon"}}],"1.0":[{"contour":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0],[14.0,3.25]],"geometry":{"points":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0]],"type":"polygon"}}],"16.0":[],"2.0":[{"contour":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0],[14.0,3.25]],"geometry":{"points":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0]],"type":"polygon"}}],"4.0":[{"contour":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0],[14.0,3.25]],"geometry":{"points":[[14.25,3.0],[18.0,6.75],[14.0,3.25]],"type":"polygon"}}],"8.0":[]},"polygon,bbox":{"0.25":[{"contour":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0],[14.0,3.25]],"geometry":{"points":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0]],"type":"polygon"}}],"0.5":[{"contour":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0],[14.0,3.25]],"geometry":{"points":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0]],"type":"polygon"}}],"1.0":[{"contour":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0],[14.0,3.25]],"geometry":{"points":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0]],"type":"polygon"}}],"16.0":[],"2.0":[{"contour":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0],[14.0,3.25]],"geometry":{"points":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0]],"type":"polygon"}}],"4.0":[{"contour":[[14.25,3.0],[17.75,3.0],[18.0,6.75],[14.25,7.0],[14.0,3.25]],"geometry":{"points":[[14.25,3.0],[18.0,6.75],[14.0,3.25]],"type":"polygon"}}],"8.0":[]},"polyline":{"0.25":[],"0.5":[],"1.0":[],"16.0":[],"2.0":[],"4.0":[],"8.0":[]}}},{"at":[[2.0,2.5],[8.0,1.0]],"closing_radius":0,"components":[{"height":2,"runs":[[0,0,5],[1,0,5]],"width":6,"x":0,"y":1},{"height":2,"runs":[[0,0,1],[1,0,1]],"width":2,"x":8,"y":1}],"contour":[[0.25,0.0],[5.75,0.0],[6.0,1.75],[0.25,2.0],[0.0,0.25]],"filled":{"height":2,"runs":[[0,0,5],[1,0,5]],"width":6},"mask":{"height":8,"runs":[[1,0,5],[1,8,9],[2,0,5],[2,8,9]],"width":12},"name":"half-pixel-click","outline":[[0.0,0.0],[1.0,0.0],[2.0,0.0],[3.0,0.0],[4.0,0.0],[5.0,0.0],[6.0,0.0],[6.0,1.0],[6.0,2.0],[5.0,2.0],[4.0,2.0],[3.0,2.0],[2.0,2.0],[1.0,2.0],[0.0,2.0],[0.0,1.0]],"shapes":{"bbox":{"0.25":[{"contour":[],"geometry":{"height":2.0,"type":"bbox","width":10.0,"x":0.0,"y":1.0}}],"0.5":[{"contour":[],"geometry":{"height":2.0,"type":"bbox","width":10.0,"x":0.0,"y":1.0}}],"1.0":[{"contour":[],"geometry":{"height":2.0,"type":"bbox","width":10.0,"x":0.0,"y":1.0}}],"16.0":[{"contour":[],"geometry":{"height":2.0,"type":"bbox","width":10.0,"x":0.0,"y":1.0}}],"2.0":[{"contour":[],"geometry":{"height":2.0,"type":"bbox","width":10.0,"x":0.0,"y":1.0}}],"4.0":[{"contour":[],"geometry":{"height":2.0,"type":"bbox","width":10.0,"x":0.0,"y":1.0}}],"8.0":[{"contour":[],"geometry":{"height":2.0,"type":"bbox","width":10.0,"x":0.0,"y":1.0}}]},"bbox,polygon":{"0.25":[{"contour":[[0.25,1.0],[5.75,1.0],[6.0,2.75],[0.25,3.0],[0.0,1.25]],"geometry":{"points":[[0.25,1.0],[5.75,1.0],[6.0,2.75],[0.25,3.0]],"type":"polygon"}}],"0.5":[{"contour":[[0.25,1.0],[5.75,1.0],[6.0,2.75],[0.25,3.0],[0.0,1.25]],"geometry":{"points":[[0.25,1.0],[5.75,1.0],[6.0,2.75],[0.25,3.0]],"type":"polygon"}}],"1.0":[{"contour":[[0.25,1.0],[5.75,1.0],[6.0,2.75],[0.25,3.0],[0.0,1.25]],"geometry":{"points":[[0.25,1.0],[5.75,1.0],[6.0,2.75],[0.25,3.0]],"type":"polygon"}}],"16.0":[],"2.0":[{"contour":[[0.25,1.0],[5.75,1.0],[6.0,2.75],[0.25,3.0],[0.0,1.25]],"geometry":{"points":[[0.25,1.0],[6.0,2.75],[0.0,1.25]],"type":"polygon"}}],"4.0":[{"contour":[[0.25,1.0],[5.75,1.0],[6.0,2.75],[0.25,3.0],[0.0,1.25]],"geometry":{"points":[[0.25,1.0],[6.0,2.75],[0.0,1.25]],"type":"polygon"}}],"8.0":[]},"polygon":{"0.25":[{"contour":[[0.25,1.0],[5.75,1.0],[6.0,2.75],[0.25,3.0],[0.0,1.25]],"geometry":{"points":[[0.25,1.0],[5.75,1.0],[6.0,2.75],[0.25,3.0]],"type":"polygon"}}],"0.5":[{"contour":[[0.25,1.0],[5.75,1.0],[6.0,2.75],[0.25,3.0],[0.0,1.25]],"geometry":{"points":[[0.25,1.0],[5.75,1.0],[6.0,2.75],[0.25,3.0]],"type":"polygon"}}],"1.0":[{"contour":[[0.25,1.0],[5.75,1.0],[6.0,2.75],[0.25,3.0],[0.0,1.25]],"geometry":{"points":[[0.25,1.0],[5.75,1.0],[6.0,2.75],[0.25,3.0]],"type":"polygon"}}],"16.0":[],"2.0":[{"contour":[[0.25,1.0],[5.75,1.0],[6.0,2.75],[0.25,3.0],[0.0,1.25]],"geometry":{"points":[[0.25,1.0],[6.0,2.75],[0.0,1.25]],"type":"polygon"}}],"4.0":[{"contour":[[0.25,1.0],[5.75,1.0],[6.0,2.75],[0.25,3.0],[0.0,1.25]],"geometry":{"points":[[0.25,1.0],[6.0,2.75],[0.0,1.25]],"type":"polygon"}}],"8.0":[]},"polygon,bbox":{"0.25":[{"contour":[[0.25,1.0],[5.75,1.0],[6.0,2.75],[0.25,3.0],[0.0,1.25]],"geometry":{"points":[[0.25,1.0],[5.75,1.0],[6.0,2.75],[0.25,3.0]],"type":"polygon"}}],"0.5":[{"contour":[[0.25,1.0],[5.75,1.0],[6.0,2.75],[0.25,3.0],[0.0,1.25]],"geometry":{"points":[[0.25,1.0],[5.75,1.0],[6.0,2.75],[0.25,3.0]],"type":"polygon"}}],"1.0":[{"contour":[[0.25,1.0],[5.75,1.0],[6.0,2.75],[0.25,3.0],[0.0,1.25]],"geometry":{"points":[[0.25,1.0],[5.75,1.0],[6.0,2.75],[0.25,3.0]],"type":"polygon"}}],"16.0":[],"2.0":[{"contour":[[0.25,1.0],[5.75,1.0],[6.0,2.75],[0.25,3.0],[0.0,1.25]],"geometry":{"points":[[0.25,1.0],[6.0,2.75],[0.0,1.25]],"type":"polygon"}}],"4.0":[{"contour":[[0.25,1.0],[5.75,1.0],[6.0,2.75],[0.25,3.0],[0.0,1.25]],"geometry":{"points":[[0.25,1.0],[6.0,2.75],[0.0,1.25]],"type":"polygon"}}],"8.0":[]},"polyline":{"0.25":[],"0.5":[],"1.0":[],"16.0":[],"2.0":[],"4.0":[],"8.0":[]}}},{"at":[[27.660028289416932,18.62279046066009]],"closing_radius":0,"components":[{"height":1,"runs":[[0,0,0]],"width":1,"x":44,"y":26},{"height":1,"runs":[[0,0,0]],"width":1,"x":11,"y":12}],"contour":[[0.25,0.0],[0.75,0.0],[1.0,0.75],[0.25,1.0],[0.0,0.25]],"filled":{"height":1,"runs":[[0,0,0]],"width":1},"mask":{"height":64,"runs":[[12,11,11],[26,44,44]],"width":64},"name":"squared-distance-near-tie","outline":[[0.0,0.0],[1.0,0.0],[1.0,1.0],[0.0,1.0]],"shapes":{"bbox":{"0.25":[{"contour":[],"geometry":{"height":15.0,"type":"bbox","width":34.0,"x":11.0,"y":12.0}}],"0.5":[{"contour":[],"geometry":{"height":15.0,"type":"bbox","width":34.0,"x":11.0,"y":12.0}}],"1.0":[{"contour":[],"geometry":{"height":15.0,"type":"bbox","width":34.0,"x":11.0,"y":12.0}}],"16.0":[{"contour":[],"geometry":{"height":15.0,"type":"bbox","width":34.0,"x":11.0,"y":12.0}}],"2.0":[{"contour":[],"geometry":{"height":15.0,"type":"bbox","width":34.0,"x":11.0,"y":12.0}}],"4.0":[{"contour":[],"geometry":{"height":15.0,"type":"bbox","width":34.0,"x":11.0,"y":12.0}}],"8.0":[{"contour":[],"geometry":{"height":15.0,"type":"bbox","width":34.0,"x":11.0,"y":12.0}}]},"bbox,polygon":{"0.25":[{"contour":[[44.25,26.0],[44.75,26.0],[45.0,26.75],[44.25,27.0],[44.0,26.25]],"geometry":{"points":[[44.25,26.0],[44.75,26.0],[45.0,26.75],[44.25,27.0]],"type":"polygon"}}],"0.5":[{"contour":[[44.25,26.0],[44.75,26.0],[45.0,26.75],[44.25,27.0],[44.0,26.25]],"geometry":{"points":[[44.25,26.0],[45.0,26.75],[44.25,27.0]],"type":"polygon"}}],"1.0":[{"contour":[[44.25,26.0],[44.75,26.0],[45.0,26.75],[44.25,27.0],[44.0,26.25]],"geometry":{"points":[[44.25,26.0],[45.0,26.75],[44.0,26.25]],"type":"polygon"}}],"16.0":[],"2.0":[],"4.0":[],"8.0":[]},"polygon":{"0.25":[{"contour":[[44.25,26.0],[44.75,26.0],[45.0,26.75],[44.25,27.0],[44.0,26.25]],"geometry":{"points":[[44.25,26.0],[44.75,26.0],[45.0,26.75],[44.25,27.0]],"type":"polygon"}}],"0.5":[{"contour":[[44.25,26.0],[44.75,26.0],[45.0,26.75],[44.25,27.0],[44.0,26.25]],"geometry":{"points":[[44.25,26.0],[45.0,26.75],[44.25,27.0]],"type":"polygon"}}],"1.0":[{"contour":[[44.25,26.0],[44.75,26.0],[45.0,26.75],[44.25,27.0],[44.0,26.25]],"geometry":{"points":[[44.25,26.0],[45.0,26.75],[44.0,26.25]],"type":"polygon"}}],"16.0":[],"2.0":[],"4.0":[],"8.0":[]},"polygon,bbox":{"0.25":[{"contour":[[44.25,26.0],[44.75,26.0],[45.0,26.75],[44.25,27.0],[44.0,26.25]],"geometry":{"points":[[44.25,26.0],[44.75,26.0],[45.0,26.75],[44.25,27.0]],"type":"polygon"}}],"0.5":[{"contour":[[44.25,26.0],[44.75,26.0],[45.0,26.75],[44.25,27.0],[44.0,26.25]],"geometry":{"points":[[44.25,26.0],[45.0,26.75],[44.25,27.0]],"type":"polygon"}}],"1.0":[{"contour":[[44.25,26.0],[44.75,26.0],[45.0,26.75],[44.25,27.0],[44.0,26.25]],"geometry":{"points":[[44.25,26.0],[45.0,26.75],[44.0,26.25]],"type":"polygon"}}],"16.0":[],"2.0":[],"4.0":[],"8.0":[]},"polyline":{"0.25":[],"0.5":[],"1.0":[],"16.0":[],"2.0":[],"4.0":[],"8.0":[]}}},{"at":[],"closing_radius":0,"components":[{"height":2,"runs":[[0,0,0],[1,1,1]],"width":2,"x":1,"y":1}],"contour":[[0.25,0.0],[0.75,0.0],[1.0,0.75],[2.0,1.25],[2.0,1.75],[1.25,2.0],[1.0,1.25],[0.0,0.75],[0.0,0.25]],"filled":{"height":2,"runs":[[0,0,0],[1,1,1]],"width":2},"mask":{"height":4,"runs":[[1,1,1],[2,2,2]],"width":4},"name":"diagonal-touch","outline":[[0.0,0.0],[1.0,0.0],[1.0,1.0],[2.0,1.0],[2.0,2.0],[1.0,2.0],[1.0,1.0],[0.0,1.0]],"shapes":{"bbox":{"0.25":[{"contour":[],"geometry":{"height":2.0,"type":"bbox","width":2.0,"x":1.0,"y":1.0}}],"0.5":[{"contour":[],"geometry":{"height":2.0,"type":"bbox","width":2.0,"x":1.0,"y":1.0}}],"1.0":[{"contour":[],"geometry":{"height":2.0,"type":"bbox","width":2.0,"x":1.0,"y":1.0}}],"16.0":[{"contour":[],"geometry":{"height":2.0,"type":"bbox","width":2.0,"x":1.0,"y":1.0}}],"2.0":[{"contour":[],"geometry":{"height":2.0,"type":"bbox","width":2.0,"x":1.0,"y":1.0}}],"4.0":[{"contour":[],"geometry":{"height":2.0,"type":"bbox","width":2.0,"x":1.0,"y":1.0}}],"8.0":[{"contour":[],"geometry":{"height":2.0,"type":"bbox","width":2.0,"x":1.0,"y":1.0}}]},"bbox,polygon":{"0.25":[{"contour":[[1.25,1.0],[1.75,1.0],[2.0,1.75],[3.0,2.25],[3.0,2.75],[2.25,3.0],[2.0,2.25],[1.0,1.75],[1.0,1.25]],"geometry":{"points":[[1.25,1.0],[1.75,1.0],[2.0,1.75],[3.0,2.25],[3.0,2.75],[2.25,3.0],[2.0,2.25],[1.0,1.75]],"type":"polygon"}}],"0.5":[{"contour":[[1.25,1.0],[1.75,1.0],[2.0,1.75],[3.0,2.25],[3.0,2.75],[2.25,3.0],[2.0,2.25],[1.0,1.75],[1.0,1.25]],"geometry":{"points":[[1.25,1.0],[3.0,2.75],[2.25,3.0]],"type":"polygon"}}],"1.0":[{"contour":[[1.25,1.0],[1.75,1.0],[2.0,1.75],[3.0,2.25],[3.0,2.75],[2.25,3.0],[2.0,2.25],[1.0,1.75],[1.0,1.25]],"geometry":{"points":[[1.25,1.0],[3.0,2.75],[1.0,1.25]],"type":"polygon"}}],"16.0":[],"2.0":[{"contour":[[1.25,1.0],[1.75,1.0],[2.0,1.75],[3.0,2.25],[3.0,2.75],[2.25,3.0],[2.0,2.25],[1.0,1.75],[1.0,1.25]],"geometry":{"points":[[1.25,1.0],[3.0,2.75],[1.0,1.25]],"type":"polygon"}}],"4.0":[],"8.0":[]},"polygon":{"0.25":[{"contour":[[1.25,1.0],[1.75,1.0],[2.0,1.75],[3.0,2.25],[3.0,2.75],[2.25,3.0],[2.0,2.25],[1.0,1.75],[1.0,1.25]],"geometry":{"points":[[1.25,1.0],[1.75,1.0],[2.0,1.75],[3.0,2.25],[3.0,2.75],[2.25,3.0],[2.0,2.25],[1.0,1.75]],"type":"polygon"}}],"0.5":[{"contour":[[1.25,1.0],[1.75,1.0],[2.0,1.75],[3.0,2.25],[3.0,2.75],[2.25,3.0],[2.0,2.25],[1.0,1.75],[1.0,1.25]],"geometry":{"points":[[1.25,1.0],[3.0,2.75],[2.25,3.0]],"type":"polygon"}}],"1.0":[{"contour":[[1.25,1.0],[1.75,1.0],[2.0,1.75],[3.0,2.25],[3.0,2.75],[2.25,3.0],[2.0,2.25],[1.0,1.75],[1.0,1.25]],"geometry":{"points":[[1.25,1.0],[3.0,2.75],[1.0,1.25]],"type":"polygon"}}],"16.0":[],"2.0":[{"contour":[[1.25,1.0],[1.75,1.0],[2.0,1.75],[3.0,2.25],[3.0,2.75],[2.25,3.0],[2.0,2.25],[1.0,1.75],[1.0,1.25]],"geometry":{"points":[[1.25,1.0],[3.0,2.75],[1.0,1.25]],"type":"polygon"}}],"4.0":[],"8.0":[]},"polygon,bbox":{"0.25":[{"contour":[[1.25,1.0],[1.75,1.0],[2.0,1.75],[3.0,2.25],[3.0,2.75],[2.25,3.0],[2.0,2.25],[1.0,1.75],[1.0,1.25]],"geometry":{"points":[[1.25,1.0],[1.75,1.0],[2.0,1.75],[3.0,2.25],[3.0,2.75],[2.25,3.0],[2.0,2.25],[1.0,1.75]],"type":"polygon"}}],"0.5":[{"contour":[[1.25,1.0],[1.75,1.0],[2.0,1.75],[3.0,2.25],[3.0,2.75],[2.25,3.0],[2.0,2.25],[1.0,1.75],[1.0,1.25]],"geometry":{"points":[[1.25,1.0],[3.0,2.75],[2.25,3.0]],"type":"polygon"}}],"1.0":[{"contour":[[1.25,1.0],[1.75,1.0],[2.0,1.75],[3.0,2.25],[3.0,2.75],[2.25,3.0],[2.0,2.25],[1.0,1.75],[1.0,1.25]],"geometry":{"points":[[1.25,1.0],[3.0,2.75],[1.0,1.25]],"type":"polygon"}}],"16.0":[],"2.0":[{"contour":[[1.25,1.0],[1.75,1.0],[2.0,1.75],[3.0,2.25],[3.0,2.75],[2.25,3.0],[2.0,2.25],[1.0,1.75],[1.0,1.25]],"geometry":{"points":[[1.25,1.0],[3.0,2.75],[1.0,1.25]],"type":"polygon"}}],"4.0":[],"8.0":[]},"polyline":{"0.25":[],"0.5":[],"1.0":[],"16.0":[],"2.0":[],"4.0":[],"8.0":[]}}},{"at":[],"closing_radius":1,"components":[{"height":64,"runs":[[0,0,63],[1,0,63],[2,0,63],[3,0,63],[4,0,63],[5,0,63],[6,0,63],[7,0,63],[8,0,63],[9,0,63],[10,0,63],[11,0,63],[12,0,63],[13,0,63],[14,0,63],[15,0,63],[16,0,63],[17,0,63],[18,0,63],[19,0,63],[20,0,63],[21,0,63],[22,0,63],[23,0,63],[24,0,63],[25,0,63],[26,0,63],[27,0,63],[28,0,63],[29,0,63],[30,0,63],[31,0,63],[32,0,61],[33,0,63],[34,0,63],[35,0,63],[36,0,63],[37,0,63],[38,0,63],[39,0,63],[40,0,63],[41,0,63],[42,0,63],[43,0,63],[44,0,63],[45,0,63],[46,0,63],[47,0,63],[48,0,63],[49,0,63],[50,0,63],[51,0,63],[52,0,63],[53,0,63],[54,0,63],[55,0,63],[56,0,63],[57,0,63],[58,0,63],[59,0,63],[60,0,63],[61,0,63],[62,0,63],[63,0,63]],"width":64,"x":0,"y":0}],"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"filled":{"height":64,"runs":[[0,0,63],[1,0,63],[2,0,63],[3,0,63],[4,0,63],[5,0,63],[6,0,63],[7,0,63],[8,0,63],[9,0,63],[10,0,63],[11,0,63],[12,0,63],[13,0,63],[14,0,63],[15,0,63],[16,0,63],[17,0,63],[18,0,63],[19,0,63],[20,0,63],[21,0,63],[22,0,63],[23,0,63],[24,0,63],[25,0,63],[26,0,63],[27,0,63],[28,0,63],[29,0,63],[30,0,63],[31,0,63],[32,0,63],[33,0,63],[34,0,63],[35,0,63],[36,0,63],[37,0,63],[38,0,63],[39,0,63],[40,0,63],[41,0,63],[42,0,63],[43,0,63],[44,0,63],[45,0,63],[46,0,63],[47,0,63],[48,0,63],[49,0,63],[50,0,63],[51,0,63],[52,0,63],[53,0,63],[54,0,63],[55,0,63],[56,0,63],[57,0,63],[58,0,63],[59,0,63],[60,0,63],[61,0,63],[62,0,63],[63,0,63]],"width":64},"mask":{"height":64,"runs":[[0,0,63],[1,0,63],[2,0,63],[3,0,63],[4,0,63],[5,0,63],[6,0,63],[7,0,63],[8,0,63],[9,0,63],[10,0,63],[11,0,63],[12,0,63],[13,0,63],[14,0,63],[15,0,63],[16,0,63],[17,0,63],[18,0,63],[19,0,63],[20,0,63],[21,0,63],[22,0,63],[23,0,63],[24,0,63],[25,0,63],[26,0,63],[27,0,63],[28,0,63],[29,0,63],[30,0,63],[31,0,63],[32,0,61],[33,0,63],[34,0,63],[35,0,63],[36,0,63],[37,0,63],[38,0,63],[39,0,63],[40,0,63],[41,0,63],[42,0,63],[43,0,63],[44,0,63],[45,0,63],[46,0,63],[47,0,63],[48,0,63],[49,0,63],[50,0,63],[51,0,63],[52,0,63],[53,0,63],[54,0,63],[55,0,63],[56,0,63],[57,0,63],[58,0,63],[59,0,63],[60,0,63],[61,0,63],[62,0,63],[63,0,63]],"width":64},"name":"narrow-notch","outline":[[0.0,0.0],[1.0,0.0],[2.0,0.0],[3.0,0.0],[4.0,0.0],[5.0,0.0],[6.0,0.0],[7.0,0.0],[8.0,0.0],[9.0,0.0],[10.0,0.0],[11.0,0.0],[12.0,0.0],[13.0,0.0],[14.0,0.0],[15.0,0.0],[16.0,0.0],[17.0,0.0],[18.0,0.0],[19.0,0.0],[20.0,0.0],[21.0,0.0],[22.0,0.0],[23.0,0.0],[24.0,0.0],[25.0,0.0],[26.0,0.0],[27.0,0.0],[28.0,0.0],[29.0,0.0],[30.0,0.0],[31.0,0.0],[32.0,0.0],[33.0,0.0],[34.0,0.0],[35.0,0.0],[36.0,0.0],[37.0,0.0],[38.0,0.0],[39.0,0.0],[40.0,0.0],[41.0,0.0],[42.0,0.0],[43.0,0.0],[44.0,0.0],[45.0,0.0],[46.0,0.0],[47.0,0.0],[48.0,0.0],[49.0,0.0],[50.0,0.0],[51.0,0.0],[52.0,0.0],[53.0,0.0],[54.0,0.0],[55.0,0.0],[56.0,0.0],[57.0,0.0],[58.0,0.0],[59.0,0.0],[60.0,0.0],[61.0,0.0],[62.0,0.0],[63.0,0.0],[64.0,0.0],[64.0,1.0],[64.0,2.0],[64.0,3.0],[64.0,4.0],[64.0,5.0],[64.0,6.0],[64.0,7.0],[64.0,8.0],[64.0,9.0],[64.0,10.0],[64.0,11.0],[64.0,12.0],[64.0,13.0],[64.0,14.0],[64.0,15.0],[64.0,16.0],[64.0,17.0],[64.0,18.0],[64.0,19.0],[64.0,20.0],[64.0,21.0],[64.0,22.0],[64.0,23.0],[64.0,24.0],[64.0,25.0],[64.0,26.0],[64.0,27.0],[64.0,28.0],[64.0,29.0],[64.0,30.0],[64.0,31.0],[64.0,32.0],[64.0,33.0],[64.0,34.0],[64.0,35.0],[64.0,36.0],[64.0,37.0],[64.0,38.0],[64.0,39.0],[64.0,40.0],[64.0,41.0],[64.0,42.0],[64.0,43.0],[64.0,44.0],[64.0,45.0],[64.0,46.0],[64.0,47.0],[64.0,48.0],[64.0,49.0],[64.0,50.0],[64.0,51.0],[64.0,52.0],[64.0,53.0],[64.0,54.0],[64.0,55.0],[64.0,56.0],[64.0,57.0],[64.0,58.0],[64.0,59.0],[64.0,60.0],[64.0,61.0],[64.0,62.0],[64.0,63.0],[64.0,64.0],[63.0,64.0],[62.0,64.0],[61.0,64.0],[60.0,64.0],[59.0,64.0],[58.0,64.0],[57.0,64.0],[56.0,64.0],[55.0,64.0],[54.0,64.0],[53.0,64.0],[52.0,64.0],[51.0,64.0],[50.0,64.0],[49.0,64.0],[48.0,64.0],[47.0,64.0],[46.0,64.0],[45.0,64.0],[44.0,64.0],[43.0,64.0],[42.0,64.0],[41.0,64.0],[40.0,64.0],[39.0,64.0],[38.0,64.0],[37.0,64.0],[36.0,64.0],[35.0,64.0],[34.0,64.0],[33.0,64.0],[32.0,64.0],[31.0,64.0],[30.0,64.0],[29.0,64.0],[28.0,64.0],[27.0,64.0],[26.0,64.0],[25.0,64.0],[24.0,64.0],[23.0,64.0],[22.0,64.0],[21.0,64.0],[20.0,64.0],[19.0,64.0],[18.0,64.0],[17.0,64.0],[16.0,64.0],[15.0,64.0],[14.0,64.0],[13.0,64.0],[12.0,64.0],[11.0,64.0],[10.0,64.0],[9.0,64.0],[8.0,64.0],[7.0,64.0],[6.0,64.0],[5.0,64.0],[4.0,64.0],[3.0,64.0],[2.0,64.0],[1.0,64.0],[0.0,64.0],[0.0,63.0],[0.0,62.0],[0.0,61.0],[0.0,60.0],[0.0,59.0],[0.0,58.0],[0.0,57.0],[0.0,56.0],[0.0,55.0],[0.0,54.0],[0.0,53.0],[0.0,52.0],[0.0,51.0],[0.0,50.0],[0.0,49.0],[0.0,48.0],[0.0,47.0],[0.0,46.0],[0.0,45.0],[0.0,44.0],[0.0,43.0],[0.0,42.0],[0.0,41.0],[0.0,40.0],[0.0,39.0],[0.0,38.0],[0.0,37.0],[0.0,36.0],[0.0,35.0],[0.0,34.0],[0.0,33.0],[0.0,32.0],[0.0,31.0],[0.0,30.0],[0.0,29.0],[0.0,28.0],[0.0,27.0],[0.0,26.0],[0.0,25.0],[0.0,24.0],[0.0,23.0],[0.0,22.0],[0.0,21.0],[0.0,20.0],[0.0,19.0],[0.0,18.0],[0.0,17.0],[0.0,16.0],[0.0,15.0],[0.0,14.0],[0.0,13.0],[0.0,12.0],[0.0,11.0],[0.0,10.0],[0.0,9.0],[0.0,8.0],[0.0,7.0],[0.0,6.0],[0.0,5.0],[0.0,4.0],[0.0,3.0],[0.0,2.0],[0.0,1.0]],"shapes":{"bbox":{"0.25":[{"contour":[],"geometry":{"height":64.0,"type":"bbox","width":64.0,"x":0.0,"y":0.0}}],"0.5":[{"contour":[],"geometry":{"height":64.0,"type":"bbox","width":64.0,"x":0.0,"y":0.0}}],"1.0":[{"contour":[],"geometry":{"height":64.0,"type":"bbox","width":64.0,"x":0.0,"y":0.0}}],"16.0":[{"contour":[],"geometry":{"height":64.0,"type":"bbox","width":64.0,"x":0.0,"y":0.0}}],"2.0":[{"contour":[],"geometry":{"height":64.0,"type":"bbox","width":64.0,"x":0.0,"y":0.0}}],"4.0":[{"contour":[],"geometry":{"height":64.0,"type":"bbox","width":64.0,"x":0.0,"y":0.0}}],"8.0":[{"contour":[],"geometry":{"height":64.0,"type":"bbox","width":64.0,"x":0.0,"y":0.0}}]},"bbox,polygon":{"0.25":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"0.5":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"1.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"16.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"2.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"4.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"8.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}]},"polygon":{"0.25":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"0.5":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"1.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"16.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"2.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"4.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"8.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}]},"polygon,bbox":{"0.25":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"0.5":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"1.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"16.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"2.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"4.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"8.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}]},"polyline":{"0.25":[],"0.5":[],"1.0":[],"16.0":[],"2.0":[],"4.0":[],"8.0":[]}}},{"at":[],"closing_radius":1,"components":[{"height":64,"runs":[[0,0,63],[1,0,63],[2,0,63],[3,0,63],[4,0,63],[5,0,63],[6,0,63],[7,0,63],[8,0,63],[9,0,63],[10,0,63],[11,0,63],[12,0,63],[13,0,63],[14,0,63],[15,0,63],[16,0,63],[17,0,63],[18,0,63],[19,0,63],[20,0,63],[21,0,63],[22,0,63],[23,0,63],[24,0,63],[25,0,63],[26,0,63],[27,0,63],[28,0,63],[29,0,63],[30,0,63],[31,0,63],[32,0,23],[33,0,63],[34,0,63],[35,0,63],[36,0,63],[37,0,63],[38,0,63],[39,0,63],[40,0,63],[41,0,63],[42,0,63],[43,0,63],[44,0,63],[45,0,63],[46,0,63],[47,0,63],[48,0,63],[49,0,63],[50,0,63],[51,0,63],[52,0,63],[53,0,63],[54,0,63],[55,0,63],[56,0,63],[57,0,63],[58,0,63],[59,0,63],[60,0,63],[61,0,63],[62,0,63],[63,0,63]],"width":64,"x":0,"y":0}],"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"filled":{"height":64,"runs":[[0,0,63],[1,0,63],[2,0,63],[3,0,63],[4,0,63],[5,0,63],[6,0,63],[7,0,63],[8,0,63],[9,0,63],[10,0,63],[11,0,63],[12,0,63],[13,0,63],[14,0,63],[15,0,63],[16,0,63],[17,0,63],[18,0,63],[19,0,63],[20,0,63],[21,0,63],[22,0,63],[23,0,63],[24,0,63],[25,0,63],[26,0,63],[27,0,63],[28,0,63],[29,0,63],[30,0,63],[31,0,63],[32,0,63],[33,0,63],[34,0,63],[35,0,63],[36,0,63],[37,0,63],[38,0,63],[39,0,63],[40,0,63],[41,0,63],[42,0,63],[43,0,63],[44,0,63],[45,0,63],[46,0,63],[47,0,63],[48,0,63],[49,0,63],[50,0,63],[51,0,63],[52,0,63],[53,0,63],[54,0,63],[55,0,63],[56,0,63],[57,0,63],[58,0,63],[59,0,63],[60,0,63],[61,0,63],[62,0,63],[63,0,63]],"width":64},"mask":{"height":64,"runs":[[0,0,63],[1,0,63],[2,0,63],[3,0,63],[4,0,63],[5,0,63],[6,0,63],[7,0,63],[8,0,63],[9,0,63],[10,0,63],[11,0,63],[12,0,63],[13,0,63],[14,0,63],[15,0,63],[16,0,63],[17,0,63],[18,0,63],[19,0,63],[20,0,63],[21,0,63],[22,0,63],[23,0,63],[24,0,63],[25,0,63],[26,0,63],[27,0,63],[28,0,63],[29,0,63],[30,0,63],[31,0,63],[32,0,23],[33,0,63],[34,0,63],[35,0,63],[36,0,63],[37,0,63],[38,0,63],[39,0,63],[40,0,63],[41,0,63],[42,0,63],[43,0,63],[44,0,63],[45,0,63],[46,0,63],[47,0,63],[48,0,63],[49,0,63],[50,0,63],[51,0,63],[52,0,63],[53,0,63],[54,0,63],[55,0,63],[56,0,63],[57,0,63],[58,0,63],[59,0,63],[60,0,63],[61,0,63],[62,0,63],[63,0,63]],"width":64},"name":"deep-one-row-notch","outline":[[0.0,0.0],[1.0,0.0],[2.0,0.0],[3.0,0.0],[4.0,0.0],[5.0,0.0],[6.0,0.0],[7.0,0.0],[8.0,0.0],[9.0,0.0],[10.0,0.0],[11.0,0.0],[12.0,0.0],[13.0,0.0],[14.0,0.0],[15.0,0.0],[16.0,0.0],[17.0,0.0],[18.0,0.0],[19.0,0.0],[20.0,0.0],[21.0,0.0],[22.0,0.0],[23.0,0.0],[24.0,0.0],[25.0,0.0],[26.0,0.0],[27.0,0.0],[28.0,0.0],[29.0,0.0],[30.0,0.0],[31.0,0.0],[32.0,0.0],[33.0,0.0],[34.0,0.0],[35.0,0.0],[36.0,0.0],[37.0,0.0],[38.0,0.0],[39.0,0.0],[40.0,0.0],[41.0,0.0],[42.0,0.0],[43.0,0.0],[44.0,0.0],[45.0,0.0],[46.0,0.0],[47.0,0.0],[48.0,0.0],[49.0,0.0],[50.0,0.0],[51.0,0.0],[52.0,0.0],[53.0,0.0],[54.0,0.0],[55.0,0.0],[56.0,0.0],[57.0,0.0],[58.0,0.0],[59.0,0.0],[60.0,0.0],[61.0,0.0],[62.0,0.0],[63.0,0.0],[64.0,0.0],[64.0,1.0],[64.0,2.0],[64.0,3.0],[64.0,4.0],[64.0,5.0],[64.0,6.0],[64.0,7.0],[64.0,8.0],[64.0,9.0],[64.0,10.0],[64.0,11.0],[64.0,12.0],[64.0,13.0],[64.0,14.0],[64.0,15.0],[64.0,16.0],[64.0,17.0],[64.0,18.0],[64.0,19.0],[64.0,20.0],[64.0,21.0],[64.0,22.0],[64.0,23.0],[64.0,24.0],[64.0,25.0],[64.0,26.0],[64.0,27.0],[64.0,28.0],[64.0,29.0],[64.0,30.0],[64.0,31.0],[64.0,32.0],[64.0,33.0],[64.0,34.0],[64.0,35.0],[64.0,36.0],[64.0,37.0],[64.0,38.0],[64.0,39.0],[64.0,40.0],[64.0,41.0],[64.0,42.0],[64.0,43.0],[64.0,44.0],[64.0,45.0],[64.0,46.0],[64.0,47.0],[64.0,48.0],[64.0,49.0],[64.0,50.0],[64.0,51.0],[64.0,52.0],[64.0,53.0],[64.0,54.0],[64.0,55.0],[64.0,56.0],[64.0,57.0],[64.0,58.0],[64.0,59.0],[64.0,60.0],[64.0,61.0],[64.0,62.0],[64.0,63.0],[64.0,64.0],[63.0,64.0],[62.0,64.0],[61.0,64.0],[60.0,64.0],[59.0,64.0],[58.0,64.0],[57.0,64.0],[56.0,64.0],[55.0,64.0],[54.0,64.0],[53.0,64.0],[52.0,64.0],[51.0,64.0],[50.0,64.0],[49.0,64.0],[48.0,64.0],[47.0,64.0],[46.0,64.0],[45.0,64.0],[44.0,64.0],[43.0,64.0],[42.0,64.0],[41.0,64.0],[40.0,64.0],[39.0,64.0],[38.0,64.0],[37.0,64.0],[36.0,64.0],[35.0,64.0],[34.0,64.0],[33.0,64.0],[32.0,64.0],[31.0,64.0],[30.0,64.0],[29.0,64.0],[28.0,64.0],[27.0,64.0],[26.0,64.0],[25.0,64.0],[24.0,64.0],[23.0,64.0],[22.0,64.0],[21.0,64.0],[20.0,64.0],[19.0,64.0],[18.0,64.0],[17.0,64.0],[16.0,64.0],[15.0,64.0],[14.0,64.0],[13.0,64.0],[12.0,64.0],[11.0,64.0],[10.0,64.0],[9.0,64.0],[8.0,64.0],[7.0,64.0],[6.0,64.0],[5.0,64.0],[4.0,64.0],[3.0,64.0],[2.0,64.0],[1.0,64.0],[0.0,64.0],[0.0,63.0],[0.0,62.0],[0.0,61.0],[0.0,60.0],[0.0,59.0],[0.0,58.0],[0.0,57.0],[0.0,56.0],[0.0,55.0],[0.0,54.0],[0.0,53.0],[0.0,52.0],[0.0,51.0],[0.0,50.0],[0.0,49.0],[0.0,48.0],[0.0,47.0],[0.0,46.0],[0.0,45.0],[0.0,44.0],[0.0,43.0],[0.0,42.0],[0.0,41.0],[0.0,40.0],[0.0,39.0],[0.0,38.0],[0.0,37.0],[0.0,36.0],[0.0,35.0],[0.0,34.0],[0.0,33.0],[0.0,32.0],[0.0,31.0],[0.0,30.0],[0.0,29.0],[0.0,28.0],[0.0,27.0],[0.0,26.0],[0.0,25.0],[0.0,24.0],[0.0,23.0],[0.0,22.0],[0.0,21.0],[0.0,20.0],[0.0,19.0],[0.0,18.0],[0.0,17.0],[0.0,16.0],[0.0,15.0],[0.0,14.0],[0.0,13.0],[0.0,12.0],[0.0,11.0],[0.0,10.0],[0.0,9.0],[0.0,8.0],[0.0,7.0],[0.0,6.0],[0.0,5.0],[0.0,4.0],[0.0,3.0],[0.0,2.0],[0.0,1.0]],"shapes":{"bbox":{"0.25":[{"contour":[],"geometry":{"height":64.0,"type":"bbox","width":64.0,"x":0.0,"y":0.0}}],"0.5":[{"contour":[],"geometry":{"height":64.0,"type":"bbox","width":64.0,"x":0.0,"y":0.0}}],"1.0":[{"contour":[],"geometry":{"height":64.0,"type":"bbox","width":64.0,"x":0.0,"y":0.0}}],"16.0":[{"contour":[],"geometry":{"height":64.0,"type":"bbox","width":64.0,"x":0.0,"y":0.0}}],"2.0":[{"contour":[],"geometry":{"height":64.0,"type":"bbox","width":64.0,"x":0.0,"y":0.0}}],"4.0":[{"contour":[],"geometry":{"height":64.0,"type":"bbox","width":64.0,"x":0.0,"y":0.0}}],"8.0":[{"contour":[],"geometry":{"height":64.0,"type":"bbox","width":64.0,"x":0.0,"y":0.0}}]},"bbox,polygon":{"0.25":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"0.5":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"1.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"16.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"2.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"4.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"8.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}]},"polygon":{"0.25":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"0.5":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"1.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"16.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"2.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"4.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"8.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}]},"polygon,bbox":{"0.25":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"0.5":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"1.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"16.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"2.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"4.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"8.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}]},"polyline":{"0.25":[],"0.5":[],"1.0":[],"16.0":[],"2.0":[],"4.0":[],"8.0":[]}}},{"at":[],"closing_radius":1,"components":[{"height":64,"runs":[[0,0,63],[1,0,63],[2,0,63],[3,0,63],[4,0,63],[5,0,63],[6,0,63],[7,0,63],[8,0,63],[9,0,63],[10,0,63],[11,0,63],[12,0,63],[13,0,63],[14,0,63],[15,0,63],[16,0,63],[17,0,63],[18,0,63],[19,0,63],[20,0,63],[21,0,63],[22,0,63],[23,0,63],[24,0,63],[25,0,63],[26,0,63],[27,0,63],[28,0,55],[29,0,55],[30,0,55],[31,0,55],[32,0,55],[33,0,55],[34,0,55],[35,0,55],[36,0,63],[37,0,63],[38,0,63],[39,0,63],[40,0,63],[41,0,63],[42,0,63],[43,0,63],[44,0,63],[45,0,63],[46,0,63],[47,0,63],[48,0,63],[49,0,63],[50,0,63],[51,0,63],[52,0,63],[53,0,63],[54,0,63],[55,0,63],[56,0,63],[57,0,63],[58,0,63],[59,0,63],[60,0,63],[61,0,63],[62,0,63],[63,0,63]],"width":64,"x":0,"y":0}],"contour":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"filled":{"height":64,"runs":[[0,0,63],[1,0,63],[2,0,63],[3,0,63],[4,0,63],[5,0,63],[6,0,63],[7,0,63],[8,0,63],[9,0,63],[10,0,63],[11,0,63],[12,0,63],[13,0,63],[14,0,63],[15,0,63],[16,0,63],[17,0,63],[18,0,63],[19,0,63],[20,0,63],[21,0,63],[22,0,63],[23,0,63],[24,0,63],[25,0,63],[26,0,63],[27,0,63],[28,0,55],[29,0,55],[30,0,55],[31,0,55],[32,0,55],[33,0,55],[34,0,55],[35,0,55],[36,0,63],[37,0,63],[38,0,63],[39,0,63],[40,0,63],[41,0,63],[42,0,63],[43,0,63],[44,0,63],[45,0,63],[46,0,63],[47,0,63],[48,0,63],[49,0,63],[50,0,63],[51,0,63],[52,0,63],[53,0,63],[54,0,63],[55,0,63],[56,0,63],[57,0,63],[58,0,63],[59,0,63],[60,0,63],[61,0,63],[62,0,63],[63,0,63]],"width":64},"mask":{"height":64,"runs":[[0,0,63],[1,0,63],[2,0,63],[3,0,63],[4,0,63],[5,0,63],[6,0,63],[7,0,63],[8,0,63],[9,0,63],[10,0,63],[11,0,63],[12,0,63],[13,0,63],[14,0,63],[15,0,63],[16,0,63],[17,0,63],[18,0,63],[19,0,63],[20,0,63],[21,0,63],[22,0,63],[23,0,63],[24,0,63],[25,0,63],[26,0,63],[27,0,63],[28,0,55],[29,0,55],[30,0,55],[31,0,55],[32,0,55],[33,0,55],[34,0,55],[35,0,55],[36,0,63],[37,0,63],[38,0,63],[39,0,63],[40,0,63],[41,0,63],[42,0,63],[43,0,63],[44,0,63],[45,0,63],[46,0,63],[47,0,63],[48,0,63],[49,0,63],[50,0,63],[51,0,63],[52,0,63],[53,0,63],[54,0,63],[55,0,63],[56,0,63],[57,0,63],[58,0,63],[59,0,63],[60,0,63],[61,0,63],[62,0,63],[63,0,63]],"width":64},"name":"wide-bay","outline":[[0.0,0.0],[1.0,0.0],[2.0,0.0],[3.0,0.0],[4.0,0.0],[5.0,0.0],[6.0,0.0],[7.0,0.0],[8.0,0.0],[9.0,0.0],[10.0,0.0],[11.0,0.0],[12.0,0.0],[13.0,0.0],[14.0,0.0],[15.0,0.0],[16.0,0.0],[17.0,0.0],[18.0,0.0],[19.0,0.0],[20.0,0.0],[21.0,0.0],[22.0,0.0],[23.0,0.0],[24.0,0.0],[25.0,0.0],[26.0,0.0],[27.0,0.0],[28.0,0.0],[29.0,0.0],[30.0,0.0],[31.0,0.0],[32.0,0.0],[33.0,0.0],[34.0,0.0],[35.0,0.0],[36.0,0.0],[37.0,0.0],[38.0,0.0],[39.0,0.0],[40.0,0.0],[41.0,0.0],[42.0,0.0],[43.0,0.0],[44.0,0.0],[45.0,0.0],[46.0,0.0],[47.0,0.0],[48.0,0.0],[49.0,0.0],[50.0,0.0],[51.0,0.0],[52.0,0.0],[53.0,0.0],[54.0,0.0],[55.0,0.0],[56.0,0.0],[57.0,0.0],[58.0,0.0],[59.0,0.0],[60.0,0.0],[61.0,0.0],[62.0,0.0],[63.0,0.0],[64.0,0.0],[64.0,1.0],[64.0,2.0],[64.0,3.0],[64.0,4.0],[64.0,5.0],[64.0,6.0],[64.0,7.0],[64.0,8.0],[64.0,9.0],[64.0,10.0],[64.0,11.0],[64.0,12.0],[64.0,13.0],[64.0,14.0],[64.0,15.0],[64.0,16.0],[64.0,17.0],[64.0,18.0],[64.0,19.0],[64.0,20.0],[64.0,21.0],[64.0,22.0],[64.0,23.0],[64.0,24.0],[64.0,25.0],[64.0,26.0],[64.0,27.0],[64.0,28.0],[63.0,28.0],[62.0,28.0],[61.0,28.0],[60.0,28.0],[59.0,28.0],[58.0,28.0],[57.0,28.0],[56.0,28.0],[56.0,29.0],[56.0,30.0],[56.0,31.0],[56.0,32.0],[56.0,33.0],[56.0,34.0],[56.0,35.0],[56.0,36.0],[57.0,36.0],[58.0,36.0],[59.0,36.0],[60.0,36.0],[61.0,36.0],[62.0,36.0],[63.0,36.0],[64.0,36.0],[64.0,37.0],[64.0,38.0],[64.0,39.0],[64.0,40.0],[64.0,41.0],[64.0,42.0],[64.0,43.0],[64.0,44.0],[64.0,45.0],[64.0,46.0],[64.0,47.0],[64.0,48.0],[64.0,49.0],[64.0,50.0],[64.0,51.0],[64.0,52.0],[64.0,53.0],[64.0,54.0],[64.0,55.0],[64.0,56.0],[64.0,57.0],[64.0,58.0],[64.0,59.0],[64.0,60.0],[64.0,61.0],[64.0,62.0],[64.0,63.0],[64.0,64.0],[63.0,64.0],[62.0,64.0],[61.0,64.0],[60.0,64.0],[59.0,64.0],[58.0,64.0],[57.0,64.0],[56.0,64.0],[55.0,64.0],[54.0,64.0],[53.0,64.0],[52.0,64.0],[51.0,64.0],[50.0,64.0],[49.0,64.0],[48.0,64.0],[47.0,64.0],[46.0,64.0],[45.0,64.0],[44.0,64.0],[43.0,64.0],[42.0,64.0],[41.0,64.0],[40.0,64.0],[39.0,64.0],[38.0,64.0],[37.0,64.0],[36.0,64.0],[35.0,64.0],[34.0,64.0],[33.0,64.0],[32.0,64.0],[31.0,64.0],[30.0,64.0],[29.0,64.0],[28.0,64.0],[27.0,64.0],[26.0,64.0],[25.0,64.0],[24.0,64.0],[23.0,64.0],[22.0,64.0],[21.0,64.0],[20.0,64.0],[19.0,64.0],[18.0,64.0],[17.0,64.0],[16.0,64.0],[15.0,64.0],[14.0,64.0],[13.0,64.0],[12.0,64.0],[11.0,64.0],[10.0,64.0],[9.0,64.0],[8.0,64.0],[7.0,64.0],[6.0,64.0],[5.0,64.0],[4.0,64.0],[3.0,64.0],[2.0,64.0],[1.0,64.0],[0.0,64.0],[0.0,63.0],[0.0,62.0],[0.0,61.0],[0.0,60.0],[0.0,59.0],[0.0,58.0],[0.0,57.0],[0.0,56.0],[0.0,55.0],[0.0,54.0],[0.0,53.0],[0.0,52.0],[0.0,51.0],[0.0,50.0],[0.0,49.0],[0.0,48.0],[0.0,47.0],[0.0,46.0],[0.0,45.0],[0.0,44.0],[0.0,43.0],[0.0,42.0],[0.0,41.0],[0.0,40.0],[0.0,39.0],[0.0,38.0],[0.0,37.0],[0.0,36.0],[0.0,35.0],[0.0,34.0],[0.0,33.0],[0.0,32.0],[0.0,31.0],[0.0,30.0],[0.0,29.0],[0.0,28.0],[0.0,27.0],[0.0,26.0],[0.0,25.0],[0.0,24.0],[0.0,23.0],[0.0,22.0],[0.0,21.0],[0.0,20.0],[0.0,19.0],[0.0,18.0],[0.0,17.0],[0.0,16.0],[0.0,15.0],[0.0,14.0],[0.0,13.0],[0.0,12.0],[0.0,11.0],[0.0,10.0],[0.0,9.0],[0.0,8.0],[0.0,7.0],[0.0,6.0],[0.0,5.0],[0.0,4.0],[0.0,3.0],[0.0,2.0],[0.0,1.0]],"shapes":{"bbox":{"0.25":[{"contour":[],"geometry":{"height":64.0,"type":"bbox","width":64.0,"x":0.0,"y":0.0}}],"0.5":[{"contour":[],"geometry":{"height":64.0,"type":"bbox","width":64.0,"x":0.0,"y":0.0}}],"1.0":[{"contour":[],"geometry":{"height":64.0,"type":"bbox","width":64.0,"x":0.0,"y":0.0}}],"16.0":[{"contour":[],"geometry":{"height":64.0,"type":"bbox","width":64.0,"x":0.0,"y":0.0}}],"2.0":[{"contour":[],"geometry":{"height":64.0,"type":"bbox","width":64.0,"x":0.0,"y":0.0}}],"4.0":[{"contour":[],"geometry":{"height":64.0,"type":"bbox","width":64.0,"x":0.0,"y":0.0}}],"8.0":[{"contour":[],"geometry":{"height":64.0,"type":"bbox","width":64.0,"x":0.0,"y":0.0}}]},"bbox,polygon":{"0.25":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"0.5":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"1.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"16.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"2.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"4.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"8.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}]},"polygon":{"0.25":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"0.5":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"1.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"16.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"2.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"4.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"8.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}]},"polygon,bbox":{"0.25":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"0.5":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"1.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"16.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"2.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"4.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"8.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,27.75],[56.25,28.0],[56.0,35.75],[64.0,36.25],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}]},"polyline":{"0.25":[],"0.5":[],"1.0":[],"16.0":[],"2.0":[],"4.0":[],"8.0":[]}}},{"at":[],"closing_radius":6,"components":[{"height":320,"runs":[[0,0,319],[1,0,319],[2,0,319],[3,0,319],[4,0,319],[5,0,319],[6,0,319],[7,0,319],[8,0,319],[9,0,319],[10,0,319],[11,0,319],[12,0,319],[13,0,319],[14,0,319],[15,0,319],[16,0,319],[17,0,319],[18,0,319],[19,0,319],[20,0,319],[21,0,319],[22,0,319],[23,0,319],[24,0,319],[25,0,319],[26,0,319],[27,0,319],[28,0,319],[29,0,319],[30,0,319],[31,0,319],[32,0,319],[33,0,319],[34,0,319],[35,0,319],[36,0,319],[37,0,319],[38,0,319],[39,0,319],[40,0,319],[41,0,319],[42,0,319],[43,0,319],[44,0,319],[45,0,319],[46,0,319],[47,0,319],[48,0,319],[49,0,319],[50,0,319],[51,0,319],[52,0,319],[53,0,319],[54,0,319],[55,0,319],[56,0,319],[57,0,319],[58,0,319],[59,0,319],[60,0,319],[61,0,319],[62,0,319],[63,0,319],[64,0,319],[65,0,319],[66,0,319],[67,0,319],[68,0,319],[69,0,319],[70,0,319],[71,0,319],[72,0,319],[73,0,319],[74,0,319],[75,0,319],[76,0,319],[77,0,319],[78,0,319],[79,0,319],[80,0,319],[81,0,319],[82,0,319],[83,0,319],[84,0,319],[85,0,319],[86,0,319],[87,0,319],[88,0,319],[89,0,319],[90,0,319],[91,0,319],[92,0,319],[93,0,319],[94,0,319],[95,0,319],[96,0,319],[97,0,319],[98,0,319],[99,0,319],[100,0,319],[101,0,319],[102,0,319],[103,0,319],[104,0,319],[105,0,319],[106,0,319],[107,0,319],[108,0,319],[109,0,319],[110,0,319],[111,0,319],[112,0,319],[113,0,319],[114,0,319],[115,0,319],[116,0,319],[117,0,319],[118,0,319],[119,0,319],[120,0,319],[121,0,319],[122,0,319],[123,0,319],[124,0,319],[125,0,319],[126,0,319],[127,0,319],[128,0,319],[129,0,319],[130,0,319],[131,0,319],[132,0,319],[133,0,319],[134,0,319],[135,0,319],[136,0,319],[137,0,319],[138,0,319],[139,0,319],[140,0,319],[141,0,319],[142,0,319],[143,0,319],[144,0,319],[145,0,319],[146,0,319],[147,0,319],[148,0,319],[149,0,319],[150,0,319],[151,0,319],[152,0,319],[153,0,319],[154,0,319],[155,0,319],[156,0,319],[157,0,319],[158,0,319],[159,0,319],[160,0,319],[161,0,319],[162,0,319],[163,0,319],[164,0,319],[165,0,319],[166,0,319],[167,0,319],[168,0,319],[169,0,319],[170,0,319],[171,0,319],[172,0,319],[173,0,319],[174,0,319],[175,0,319],[176,0,319],[177,0,319],[178,0,319],[179,0,319],[180,0,319],[181,0,319],[182,0,319],[183,0,319],[184,0,319],[185,0,319],[186,0,319],[187,0,319],[188,0,319],[189,0,319],[190,0,319],[191,0,319],[192,0,319],[193,0,319],[194,0,319],[195,0,319],[196,0,319],[197,0,319],[198,0,319],[199,0,319],[200,0,319],[201,0,319],[202,0,319],[203,0,319],[204,0,319],[205,0,319],[206,0,319],[207,0,319],[208,0,319],[209,0,319],[210,0,319],[211,0,319],[212,0,319],[213,0,319],[214,0,319],[215,0,319],[216,0,319],[217,0,319],[218,0,319],[219,0,319],[220,0,319],[221,0,319],[222,0,319],[223,0,319],[224,0,319],[225,0,319],[226,0,319],[227,0,319],[228,0,319],[229,0,319],[230,0,319],[231,0,319],[232,0,319],[233,0,319],[234,0,319],[235,0,319],[236,0,319],[237,0,319],[238,0,319],[239,0,319],[240,0,319],[241,0,319],[242,0,319],[243,0,319],[244,0,319],[245,0,319],[246,0,319],[247,0,319],[248,0,319],[249,0,319],[250,0,319],[251,0,319],[252,0,319],[253,0,319],[254,0,319],[255,0,319],[256,0,319],[257,0,319],[258,0,319],[259,0,319],[260,0,319],[261,0,319],[262,0,319],[263,0,319],[264,0,319],[265,0,319],[266,0,319],[267,0,319],[268,0,319],[269,0,319],[270,0,319],[271,0,319],[272,0,319],[273,0,319],[274,0,319],[275,0,319],[276,0,319],[277,0,319],[278,0,319],[279,0,319],[280,0,319],[281,0,319],[282,0,319],[283,0,319],[284,0,319],[285,0,319],[286,0,319],[287,0,319],[288,0,319],[289,0,319],[290,0,319],[291,0,319],[292,0,319],[293,0,319],[294,0,319],[295,0,319],[296,0,319],[297,0,319],[298,0,319],[299,0,319],[300,0,319],[301,0,319],[302,0,319],[303,0,319],[304,0,319],[305,0,319],[306,0,319],[307,0,319],[308,0,319],[309,0,319],[310,0,319],[311,0,319],[312,0,319],[313,0,319],[314,0,319],[315,0,319],[316,0,319],[317,0,319],[318,0,319],[319,0,319]],"width":320,"x":0,"y":0}],"contour":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0],[0.0,0.25]],"filled":{"height":320,"runs":[[0,0,319],[1,0,319],[2,0,319],[3,0,319],[4,0,319],[5,0,319],[6,0,319],[7,0,319],[8,0,319],[9,0,319],[10,0,319],[11,0,319],[12,0,319],[13,0,319],[14,0,319],[15,0,319],[16,0,319],[17,0,319],[18,0,319],[19,0,319],[20,0,319],[21,0,319],[22,0,319],[23,0,319],[24,0,319],[25,0,319],[26,0,319],[27,0,319],[28,0,319],[29,0,319],[30,0,319],[31,0,319],[32,0,319],[33,0,319],[34,0,319],[35,0,319],[36,0,319],[37,0,319],[38,0,319],[39,0,319],[40,0,319],[41,0,319],[42,0,319],[43,0,319],[44,0,319],[45,0,319],[46,0,319],[47,0,319],[48,0,319],[49,0,319],[50,0,319],[51,0,319],[52,0,319],[53,0,319],[54,0,319],[55,0,319],[56,0,319],[57,0,319],[58,0,319],[59,0,319],[60,0,319],[61,0,319],[62,0,319],[63,0,319],[64,0,319],[65,0,319],[66,0,319],[67,0,319],[68,0,319],[69,0,319],[70,0,319],[71,0,319],[72,0,319],[73,0,319],[74,0,319],[75,0,319],[76,0,319],[77,0,319],[78,0,319],[79,0,319],[80,0,319],[81,0,319],[82,0,319],[83,0,319],[84,0,319],[85,0,319],[86,0,319],[87,0,319],[88,0,319],[89,0,319],[90,0,319],[91,0,319],[92,0,319],[93,0,319],[94,0,319],[95,0,319],[96,0,319],[97,0,319],[98,0,319],[99,0,319],[100,0,319],[101,0,319],[102,0,319],[103,0,319],[104,0,319],[105,0,319],[106,0,319],[107,0,319],[108,0,319],[109,0,319],[110,0,319],[111,0,319],[112,0,319],[113,0,319],[114,0,319],[115,0,319],[116,0,319],[117,0,319],[118,0,319],[119,0,319],[120,0,319],[121,0,319],[122,0,319],[123,0,319],[124,0,319],[125,0,319],[126,0,319],[127,0,319],[128,0,319],[129,0,319],[130,0,319],[131,0,319],[132,0,319],[133,0,319],[134,0,319],[135,0,319],[136,0,319],[137,0,319],[138,0,319],[139,0,319],[140,0,319],[141,0,319],[142,0,319],[143,0,319],[144,0,319],[145,0,319],[146,0,319],[147,0,319],[148,0,319],[149,0,319],[150,0,319],[151,0,319],[152,0,319],[153,0,319],[154,0,319],[155,0,319],[156,0,319],[157,0,319],[158,0,319],[159,0,319],[160,0,319],[161,0,319],[162,0,319],[163,0,319],[164,0,319],[165,0,319],[166,0,319],[167,0,319],[168,0,319],[169,0,319],[170,0,319],[171,0,319],[172,0,319],[173,0,319],[174,0,319],[175,0,319],[176,0,319],[177,0,319],[178,0,319],[179,0,319],[180,0,319],[181,0,319],[182,0,319],[183,0,319],[184,0,319],[185,0,319],[186,0,319],[187,0,319],[188,0,319],[189,0,319],[190,0,319],[191,0,319],[192,0,319],[193,0,319],[194,0,319],[195,0,319],[196,0,319],[197,0,319],[198,0,319],[199,0,319],[200,0,319],[201,0,319],[202,0,319],[203,0,319],[204,0,319],[205,0,319],[206,0,319],[207,0,319],[208,0,319],[209,0,319],[210,0,319],[211,0,319],[212,0,319],[213,0,319],[214,0,319],[215,0,319],[216,0,319],[217,0,319],[218,0,319],[219,0,319],[220,0,319],[221,0,319],[222,0,319],[223,0,319],[224,0,319],[225,0,319],[226,0,319],[227,0,319],[228,0,319],[229,0,319],[230,0,319],[231,0,319],[232,0,319],[233,0,319],[234,0,319],[235,0,319],[236,0,319],[237,0,319],[238,0,319],[239,0,319],[240,0,319],[241,0,319],[242,0,319],[243,0,319],[244,0,319],[245,0,319],[246,0,319],[247,0,319],[248,0,319],[249,0,319],[250,0,319],[251,0,319],[252,0,319],[253,0,319],[254,0,319],[255,0,319],[256,0,319],[257,0,319],[258,0,319],[259,0,319],[260,0,319],[261,0,319],[262,0,319],[263,0,319],[264,0,319],[265,0,319],[266,0,319],[267,0,319],[268,0,319],[269,0,319],[270,0,319],[271,0,319],[272,0,319],[273,0,319],[274,0,319],[275,0,319],[276,0,319],[277,0,319],[278,0,319],[279,0,319],[280,0,319],[281,0,319],[282,0,319],[283,0,319],[284,0,319],[285,0,319],[286,0,319],[287,0,319],[288,0,319],[289,0,319],[290,0,319],[291,0,319],[292,0,319],[293,0,319],[294,0,319],[295,0,319],[296,0,319],[297,0,319],[298,0,319],[299,0,319],[300,0,319],[301,0,319],[302,0,319],[303,0,319],[304,0,319],[305,0,319],[306,0,319],[307,0,319],[308,0,319],[309,0,319],[310,0,319],[311,0,319],[312,0,319],[313,0,319],[314,0,319],[315,0,319],[316,0,319],[317,0,319],[318,0,319],[319,0,319]],"width":320},"mask":{"height":320,"runs":[[0,0,319],[1,0,319],[2,0,319],[3,0,319],[4,0,319],[5,0,319],[6,0,319],[7,0,319],[8,0,319],[9,0,319],[10,0,319],[11,0,319],[12,0,319],[13,0,319],[14,0,319],[15,0,319],[16,0,319],[17,0,319],[18,0,319],[19,0,319],[20,0,319],[21,0,319],[22,0,319],[23,0,319],[24,0,319],[25,0,319],[26,0,319],[27,0,319],[28,0,319],[29,0,319],[30,0,319],[31,0,319],[32,0,319],[33,0,319],[34,0,319],[35,0,319],[36,0,319],[37,0,319],[38,0,319],[39,0,319],[40,0,319],[41,0,319],[42,0,319],[43,0,319],[44,0,319],[45,0,319],[46,0,319],[47,0,319],[48,0,319],[49,0,319],[50,0,319],[51,0,319],[52,0,319],[53,0,319],[54,0,319],[55,0,319],[56,0,319],[57,0,319],[58,0,319],[59,0,319],[60,0,319],[61,0,319],[62,0,319],[63,0,319],[64,0,319],[65,0,319],[66,0,319],[67,0,319],[68,0,319],[69,0,319],[70,0,319],[71,0,319],[72,0,319],[73,0,319],[74,0,319],[75,0,319],[76,0,319],[77,0,319],[78,0,319],[79,0,319],[80,0,319],[81,0,319],[82,0,319],[83,0,319],[84,0,319],[85,0,319],[86,0,319],[87,0,319],[88,0,319],[89,0,319],[90,0,319],[91,0,319],[92,0,319],[93,0,319],[94,0,319],[95,0,319],[96,0,319],[97,0,319],[98,0,319],[99,0,319],[100,0,319],[101,0,319],[102,0,319],[103,0,319],[104,0,319],[105,0,319],[106,0,319],[107,0,319],[108,0,319],[109,0,319],[110,0,319],[111,0,319],[112,0,319],[113,0,319],[114,0,319],[115,0,319],[116,0,319],[117,0,319],[118,0,319],[119,0,319],[120,0,319],[121,0,319],[122,0,319],[123,0,319],[124,0,319],[125,0,319],[126,0,319],[127,0,319],[128,0,319],[129,0,319],[130,0,319],[131,0,319],[132,0,319],[133,0,319],[134,0,319],[135,0,319],[136,0,319],[137,0,319],[138,0,319],[139,0,319],[140,0,319],[141,0,319],[142,0,319],[143,0,319],[144,0,319],[145,0,319],[146,0,319],[147,0,319],[148,0,319],[149,0,319],[150,0,319],[151,0,319],[152,0,319],[153,0,319],[154,0,319],[155,0,319],[156,0,319],[157,0,319],[158,0,319],[159,0,319],[160,0,319],[161,0,319],[162,0,319],[163,0,319],[164,0,319],[165,0,319],[166,0,319],[167,0,319],[168,0,319],[169,0,319],[170,0,319],[171,0,319],[172,0,319],[173,0,319],[174,0,319],[175,0,319],[176,0,319],[177,0,319],[178,0,319],[179,0,319],[180,0,319],[181,0,319],[182,0,319],[183,0,319],[184,0,319],[185,0,319],[186,0,319],[187,0,319],[188,0,319],[189,0,319],[190,0,319],[191,0,319],[192,0,319],[193,0,319],[194,0,319],[195,0,319],[196,0,319],[197,0,319],[198,0,319],[199,0,319],[200,0,319],[201,0,319],[202,0,319],[203,0,319],[204,0,319],[205,0,319],[206,0,319],[207,0,319],[208,0,319],[209,0,319],[210,0,319],[211,0,319],[212,0,319],[213,0,319],[214,0,319],[215,0,319],[216,0,319],[217,0,319],[218,0,319],[219,0,319],[220,0,319],[221,0,319],[222,0,319],[223,0,319],[224,0,319],[225,0,319],[226,0,319],[227,0,319],[228,0,319],[229,0,319],[230,0,319],[231,0,319],[232,0,319],[233,0,319],[234,0,319],[235,0,319],[236,0,319],[237,0,319],[238,0,319],[239,0,319],[240,0,319],[241,0,319],[242,0,319],[243,0,319],[244,0,319],[245,0,319],[246,0,319],[247,0,319],[248,0,319],[249,0,319],[250,0,319],[251,0,319],[252,0,319],[253,0,319],[254,0,319],[255,0,319],[256,0,319],[257,0,319],[258,0,319],[259,0,319],[260,0,319],[261,0,319],[262,0,319],[263,0,319],[264,0,319],[265,0,319],[266,0,319],[267,0,319],[268,0,319],[269,0,319],[270,0,319],[271,0,319],[272,0,319],[273,0,319],[274,0,319],[275,0,319],[276,0,319],[277,0,319],[278,0,319],[279,0,319],[280,0,319],[281,0,319],[282,0,319],[283,0,319],[284,0,319],[285,0,319],[286,0,319],[287,0,319],[288,0,319],[289,0,319],[290,0,319],[291,0,319],[292,0,319],[293,0,319],[294,0,319],[295,0,319],[296,0,319],[297,0,319],[298,0,319],[299,0,319],[300,0,319],[301,0,319],[302,0,319],[303,0,319],[304,0,319],[305,0,319],[306,0,319],[307,0,319],[308,0,319],[309,0,319],[310,0,319],[311,0,319],[312,0,319],[313,0,319],[314,0,319],[315,0,319],[316,0,319],[317,0,319],[318,0,319],[319,0,319]],"width":320},"name":"capped-reach","outline":[[0.0,0.0],[1.0,0.0],[2.0,0.0],[3.0,0.0],[4.0,0.0],[5.0,0.0],[6.0,0.0],[7.0,0.0],[8.0,0.0],[9.0,0.0],[10.0,0.0],[11.0,0.0],[12.0,0.0],[13.0,0.0],[14.0,0.0],[15.0,0.0],[16.0,0.0],[17.0,0.0],[18.0,0.0],[19.0,0.0],[20.0,0.0],[21.0,0.0],[22.0,0.0],[23.0,0.0],[24.0,0.0],[25.0,0.0],[26.0,0.0],[27.0,0.0],[28.0,0.0],[29.0,0.0],[30.0,0.0],[31.0,0.0],[32.0,0.0],[33.0,0.0],[34.0,0.0],[35.0,0.0],[36.0,0.0],[37.0,0.0],[38.0,0.0],[39.0,0.0],[40.0,0.0],[41.0,0.0],[42.0,0.0],[43.0,0.0],[44.0,0.0],[45.0,0.0],[46.0,0.0],[47.0,0.0],[48.0,0.0],[49.0,0.0],[50.0,0.0],[51.0,0.0],[52.0,0.0],[53.0,0.0],[54.0,0.0],[55.0,0.0],[56.0,0.0],[57.0,0.0],[58.0,0.0],[59.0,0.0],[60.0,0.0],[61.0,0.0],[62.0,0.0],[63.0,0.0],[64.0,0.0],[65.0,0.0],[66.0,0.0],[67.0,0.0],[68.0,0.0],[69.0,0.0],[70.0,0.0],[71.0,0.0],[72.0,0.0],[73.0,0.0],[74.0,0.0],[75.0,0.0],[76.0,0.0],[77.0,0.0],[78.0,0.0],[79.0,0.0],[80.0,0.0],[81.0,0.0],[82.0,0.0],[83.0,0.0],[84.0,0.0],[85.0,0.0],[86.0,0.0],[87.0,0.0],[88.0,0.0],[89.0,0.0],[90.0,0.0],[91.0,0.0],[92.0,0.0],[93.0,0.0],[94.0,0.0],[95.0,0.0],[96.0,0.0],[97.0,0.0],[98.0,0.0],[99.0,0.0],[100.0,0.0],[101.0,0.0],[102.0,0.0],[103.0,0.0],[104.0,0.0],[105.0,0.0],[106.0,0.0],[107.0,0.0],[108.0,0.0],[109.0,0.0],[110.0,0.0],[111.0,0.0],[112.0,0.0],[113.0,0.0],[114.0,0.0],[115.0,0.0],[116.0,0.0],[117.0,0.0],[118.0,0.0],[119.0,0.0],[120.0,0.0],[121.0,0.0],[122.0,0.0],[123.0,0.0],[124.0,0.0],[125.0,0.0],[126.0,0.0],[127.0,0.0],[128.0,0.0],[129.0,0.0],[130.0,0.0],[131.0,0.0],[132.0,0.0],[133.0,0.0],[134.0,0.0],[135.0,0.0],[136.0,0.0],[137.0,0.0],[138.0,0.0],[139.0,0.0],[140.0,0.0],[141.0,0.0],[142.0,0.0],[143.0,0.0],[144.0,0.0],[145.0,0.0],[146.0,0.0],[147.0,0.0],[148.0,0.0],[149.0,0.0],[150.0,0.0],[151.0,0.0],[152.0,0.0],[153.0,0.0],[154.0,0.0],[155.0,0.0],[156.0,0.0],[157.0,0.0],[158.0,0.0],[159.0,0.0],[160.0,0.0],[161.0,0.0],[162.0,0.0],[163.0,0.0],[164.0,0.0],[165.0,0.0],[166.0,0.0],[167.0,0.0],[168.0,0.0],[169.0,0.0],[170.0,0.0],[171.0,0.0],[172.0,0.0],[173.0,0.0],[174.0,0.0],[175.0,0.0],[176.0,0.0],[177.0,0.0],[178.0,0.0],[179.0,0.0],[180.0,0.0],[181.0,0.0],[182.0,0.0],[183.0,0.0],[184.0,0.0],[185.0,0.0],[186.0,0.0],[187.0,0.0],[188.0,0.0],[189.0,0.0],[190.0,0.0],[191.0,0.0],[192.0,0.0],[193.0,0.0],[194.0,0.0],[195.0,0.0],[196.0,0.0],[197.0,0.0],[198.0,0.0],[199.0,0.0],[200.0,0.0],[201.0,0.0],[202.0,0.0],[203.0,0.0],[204.0,0.0],[205.0,0.0],[206.0,0.0],[207.0,0.0],[208.0,0.0],[209.0,0.0],[210.0,0.0],[211.0,0.0],[212.0,0.0],[213.0,0.0],[214.0,0.0],[215.0,0.0],[216.0,0.0],[217.0,0.0],[218.0,0.0],[219.0,0.0],[220.0,0.0],[221.0,0.0],[222.0,0.0],[223.0,0.0],[224.0,0.0],[225.0,0.0],[226.0,0.0],[227.0,0.0],[228.0,0.0],[229.0,0.0],[230.0,0.0],[231.0,0.0],[232.0,0.0],[233.0,0.0],[234.0,0.0],[235.0,0.0],[236.0,0.0],[237.0,0.0],[238.0,0.0],[239.0,0.0],[240.0,0.0],[241.0,0.0],[242.0,0.0],[243.0,0.0],[244.0,0.0],[245.0,0.0],[246.0,0.0],[247.0,0.0],[248.0,0.0],[249.0,0.0],[250.0,0.0],[251.0,0.0],[252.0,0.0],[253.0,0.0],[254.0,0.0],[255.0,0.0],[256.0,0.0],[257.0,0.0],[258.0,0.0],[259.0,0.0],[260.0,0.0],[261.0,0.0],[262.0,0.0],[263.0,0.0],[264.0,0.0],[265.0,0.0],[266.0,0.0],[267.0,0.0],[268.0,0.0],[269.0,0.0],[270.0,0.0],[271.0,0.0],[272.0,0.0],[273.0,0.0],[274.0,0.0],[275.0,0.0],[276.0,0.0],[277.0,0.0],[278.0,0.0],[279.0,0.0],[280.0,0.0],[281.0,0.0],[282.0,0.0],[283.0,0.0],[284.0,0.0],[285.0,0.0],[286.0,0.0],[287.0,0.0],[288.0,0.0],[289.0,0.0],[290.0,0.0],[291.0,0.0],[292.0,0.0],[293.0,0.0],[294.0,0.0],[295.0,0.0],[296.0,0.0],[297.0,0.0],[298.0,0.0],[299.0,0.0],[300.0,0.0],[301.0,0.0],[302.0,0.0],[303.0,0.0],[304.0,0.0],[305.0,0.0],[306.0,0.0],[307.0,0.0],[308.0,0.0],[309.0,0.0],[310.0,0.0],[311.0,0.0],[312.0,0.0],[313.0,0.0],[314.0,0.0],[315.0,0.0],[316.0,0.0],[317.0,0.0],[318.0,0.0],[319.0,0.0],[320.0,0.0],[320.0,1.0],[320.0,2.0],[320.0,3.0],[320.0,4.0],[320.0,5.0],[320.0,6.0],[320.0,7.0],[320.0,8.0],[320.0,9.0],[320.0,10.0],[320.0,11.0],[320.0,12.0],[320.0,13.0],[320.0,14.0],[320.0,15.0],[320.0,16.0],[320.0,17.0],[320.0,18.0],[320.0,19.0],[320.0,20.0],[320.0,21.0],[320.0,22.0],[320.0,23.0],[320.0,24.0],[320.0,25.0],[320.0,26.0],[320.0,27.0],[320.0,28.0],[320.0,29.0],[320.0,30.0],[320.0,31.0],[320.0,32.0],[320.0,33.0],[320.0,34.0],[320.0,35.0],[320.0,36.0],[320.0,37.0],[320.0,38.0],[320.0,39.0],[320.0,40.0],[320.0,41.0],[320.0,42.0],[320.0,43.0],[320.0,44.0],[320.0,45.0],[320.0,46.0],[320.0,47.0],[320.0,48.0],[320.0,49.0],[320.0,50.0],[320.0,51.0],[320.0,52.0],[320.0,53.0],[320.0,54.0],[320.0,55.0],[320.0,56.0],[320.0,57.0],[320.0,58.0],[320.0,59.0],[320.0,60.0],[320.0,61.0],[320.0,62.0],[320.0,63.0],[320.0,64.0],[320.0,65.0],[320.0,66.0],[320.0,67.0],[320.0,68.0],[320.0,69.0],[320.0,70.0],[320.0,71.0],[320.0,72.0],[320.0,73.0],[320.0,74.0],[320.0,75.0],[320.0,76.0],[320.0,77.0],[320.0,78.0],[320.0,79.0],[320.0,80.0],[320.0,81.0],[320.0,82.0],[320.0,83.0],[320.0,84.0],[320.0,85.0],[320.0,86.0],[320.0,87.0],[320.0,88.0],[320.0,89.0],[320.0,90.0],[320.0,91.0],[320.0,92.0],[320.0,93.0],[320.0,94.0],[320.0,95.0],[320.0,96.0],[320.0,97.0],[320.0,98.0],[320.0,99.0],[320.0,100.0],[320.0,101.0],[320.0,102.0],[320.0,103.0],[320.0,104.0],[320.0,105.0],[320.0,106.0],[320.0,107.0],[320.0,108.0],[320.0,109.0],[320.0,110.0],[320.0,111.0],[320.0,112.0],[320.0,113.0],[320.0,114.0],[320.0,115.0],[320.0,116.0],[320.0,117.0],[320.0,118.0],[320.0,119.0],[320.0,120.0],[320.0,121.0],[320.0,122.0],[320.0,123.0],[320.0,124.0],[320.0,125.0],[320.0,126.0],[320.0,127.0],[320.0,128.0],[320.0,129.0],[320.0,130.0],[320.0,131.0],[320.0,132.0],[320.0,133.0],[320.0,134.0],[320.0,135.0],[320.0,136.0],[320.0,137.0],[320.0,138.0],[320.0,139.0],[320.0,140.0],[320.0,141.0],[320.0,142.0],[320.0,143.0],[320.0,144.0],[320.0,145.0],[320.0,146.0],[320.0,147.0],[320.0,148.0],[320.0,149.0],[320.0,150.0],[320.0,151.0],[320.0,152.0],[320.0,153.0],[320.0,154.0],[320.0,155.0],[320.0,156.0],[320.0,157.0],[320.0,158.0],[320.0,159.0],[320.0,160.0],[320.0,161.0],[320.0,162.0],[320.0,163.0],[320.0,164.0],[320.0,165.0],[320.0,166.0],[320.0,167.0],[320.0,168.0],[320.0,169.0],[320.0,170.0],[320.0,171.0],[320.0,172.0],[320.0,173.0],[320.0,174.0],[320.0,175.0],[320.0,176.0],[320.0,177.0],[320.0,178.0],[320.0,179.0],[320.0,180.0],[320.0,181.0],[320.0,182.0],[320.0,183.0],[320.0,184.0],[320.0,185.0],[320.0,186.0],[320.0,187.0],[320.0,188.0],[320.0,189.0],[320.0,190.0],[320.0,191.0],[320.0,192.0],[320.0,193.0],[320.0,194.0],[320.0,195.0],[320.0,196.0],[320.0,197.0],[320.0,198.0],[320.0,199.0],[320.0,200.0],[320.0,201.0],[320.0,202.0],[320.0,203.0],[320.0,204.0],[320.0,205.0],[320.0,206.0],[320.0,207.0],[320.0,208.0],[320.0,209.0],[320.0,210.0],[320.0,211.0],[320.0,212.0],[320.0,213.0],[320.0,214.0],[320.0,215.0],[320.0,216.0],[320.0,217.0],[320.0,218.0],[320.0,219.0],[320.0,220.0],[320.0,221.0],[320.0,222.0],[320.0,223.0],[320.0,224.0],[320.0,225.0],[320.0,226.0],[320.0,227.0],[320.0,228.0],[320.0,229.0],[320.0,230.0],[320.0,231.0],[320.0,232.0],[320.0,233.0],[320.0,234.0],[320.0,235.0],[320.0,236.0],[320.0,237.0],[320.0,238.0],[320.0,239.0],[320.0,240.0],[320.0,241.0],[320.0,242.0],[320.0,243.0],[320.0,244.0],[320.0,245.0],[320.0,246.0],[320.0,247.0],[320.0,248.0],[320.0,249.0],[320.0,250.0],[320.0,251.0],[320.0,252.0],[320.0,253.0],[320.0,254.0],[320.0,255.0],[320.0,256.0],[320.0,257.0],[320.0,258.0],[320.0,259.0],[320.0,260.0],[320.0,261.0],[320.0,262.0],[320.0,263.0],[320.0,264.0],[320.0,265.0],[320.0,266.0],[320.0,267.0],[320.0,268.0],[320.0,269.0],[320.0,270.0],[320.0,271.0],[320.0,272.0],[320.0,273.0],[320.0,274.0],[320.0,275.0],[320.0,276.0],[320.0,277.0],[320.0,278.0],[320.0,279.0],[320.0,280.0],[320.0,281.0],[320.0,282.0],[320.0,283.0],[320.0,284.0],[320.0,285.0],[320.0,286.0],[320.0,287.0],[320.0,288.0],[320.0,289.0],[320.0,290.0],[320.0,291.0],[320.0,292.0],[320.0,293.0],[320.0,294.0],[320.0,295.0],[320.0,296.0],[320.0,297.0],[320.0,298.0],[320.0,299.0],[320.0,300.0],[320.0,301.0],[320.0,302.0],[320.0,303.0],[320.0,304.0],[320.0,305.0],[320.0,306.0],[320.0,307.0],[320.0,308.0],[320.0,309.0],[320.0,310.0],[320.0,311.0],[320.0,312.0],[320.0,313.0],[320.0,314.0],[320.0,315.0],[320.0,316.0],[320.0,317.0],[320.0,318.0],[320.0,319.0],[320.0,320.0],[319.0,320.0],[318.0,320.0],[317.0,320.0],[316.0,320.0],[315.0,320.0],[314.0,320.0],[313.0,320.0],[312.0,320.0],[311.0,320.0],[310.0,320.0],[309.0,320.0],[308.0,320.0],[307.0,320.0],[306.0,320.0],[305.0,320.0],[304.0,320.0],[303.0,320.0],[302.0,320.0],[301.0,320.0],[300.0,320.0],[299.0,320.0],[298.0,320.0],[297.0,320.0],[296.0,320.0],[295.0,320.0],[294.0,320.0],[293.0,320.0],[292.0,320.0],[291.0,320.0],[290.0,320.0],[289.0,320.0],[288.0,320.0],[287.0,320.0],[286.0,320.0],[285.0,320.0],[284.0,320.0],[283.0,320.0],[282.0,320.0],[281.0,320.0],[280.0,320.0],[279.0,320.0],[278.0,320.0],[277.0,320.0],[276.0,320.0],[275.0,320.0],[274.0,320.0],[273.0,320.0],[272.0,320.0],[271.0,320.0],[270.0,320.0],[269.0,320.0],[268.0,320.0],[267.0,320.0],[266.0,320.0],[265.0,320.0],[264.0,320.0],[263.0,320.0],[262.0,320.0],[261.0,320.0],[260.0,320.0],[259.0,320.0],[258.0,320.0],[257.0,320.0],[256.0,320.0],[255.0,320.0],[254.0,320.0],[253.0,320.0],[252.0,320.0],[251.0,320.0],[250.0,320.0],[249.0,320.0],[248.0,320.0],[247.0,320.0],[246.0,320.0],[245.0,320.0],[244.0,320.0],[243.0,320.0],[242.0,320.0],[241.0,320.0],[240.0,320.0],[239.0,320.0],[238.0,320.0],[237.0,320.0],[236.0,320.0],[235.0,320.0],[234.0,320.0],[233.0,320.0],[232.0,320.0],[231.0,320.0],[230.0,320.0],[229.0,320.0],[228.0,320.0],[227.0,320.0],[226.0,320.0],[225.0,320.0],[224.0,320.0],[223.0,320.0],[222.0,320.0],[221.0,320.0],[220.0,320.0],[219.0,320.0],[218.0,320.0],[217.0,320.0],[216.0,320.0],[215.0,320.0],[214.0,320.0],[213.0,320.0],[212.0,320.0],[211.0,320.0],[210.0,320.0],[209.0,320.0],[208.0,320.0],[207.0,320.0],[206.0,320.0],[205.0,320.0],[204.0,320.0],[203.0,320.0],[202.0,320.0],[201.0,320.0],[200.0,320.0],[199.0,320.0],[198.0,320.0],[197.0,320.0],[196.0,320.0],[195.0,320.0],[194.0,320.0],[193.0,320.0],[192.0,320.0],[191.0,320.0],[190.0,320.0],[189.0,320.0],[188.0,320.0],[187.0,320.0],[186.0,320.0],[185.0,320.0],[184.0,320.0],[183.0,320.0],[182.0,320.0],[181.0,320.0],[180.0,320.0],[179.0,320.0],[178.0,320.0],[177.0,320.0],[176.0,320.0],[175.0,320.0],[174.0,320.0],[173.0,320.0],[172.0,320.0],[171.0,320.0],[170.0,320.0],[169.0,320.0],[168.0,320.0],[167.0,320.0],[166.0,320.0],[165.0,320.0],[164.0,320.0],[163.0,320.0],[162.0,320.0],[161.0,320.0],[160.0,320.0],[159.0,320.0],[158.0,320.0],[157.0,320.0],[156.0,320.0],[155.0,320.0],[154.0,320.0],[153.0,320.0],[152.0,320.0],[151.0,320.0],[150.0,320.0],[149.0,320.0],[148.0,320.0],[147.0,320.0],[146.0,320.0],[145.0,320.0],[144.0,320.0],[143.0,320.0],[142.0,320.0],[141.0,320.0],[140.0,320.0],[139.0,320.0],[138.0,320.0],[137.0,320.0],[136.0,320.0],[135.0,320.0],[134.0,320.0],[133.0,320.0],[132.0,320.0],[131.0,320.0],[130.0,320.0],[129.0,320.0],[128.0,320.0],[127.0,320.0],[126.0,320.0],[125.0,320.0],[124.0,320.0],[123.0,320.0],[122.0,320.0],[121.0,320.0],[120.0,320.0],[119.0,320.0],[118.0,320.0],[117.0,320.0],[116.0,320.0],[115.0,320.0],[114.0,320.0],[113.0,320.0],[112.0,320.0],[111.0,320.0],[110.0,320.0],[109.0,320.0],[108.0,320.0],[107.0,320.0],[106.0,320.0],[105.0,320.0],[104.0,320.0],[103.0,320.0],[102.0,320.0],[101.0,320.0],[100.0,320.0],[99.0,320.0],[98.0,320.0],[97.0,320.0],[96.0,320.0],[95.0,320.0],[94.0,320.0],[93.0,320.0],[92.0,320.0],[91.0,320.0],[90.0,320.0],[89.0,320.0],[88.0,320.0],[87.0,320.0],[86.0,320.0],[85.0,320.0],[84.0,320.0],[83.0,320.0],[82.0,320.0],[81.0,320.0],[80.0,320.0],[79.0,320.0],[78.0,320.0],[77.0,320.0],[76.0,320.0],[75.0,320.0],[74.0,320.0],[73.0,320.0],[72.0,320.0],[71.0,320.0],[70.0,320.0],[69.0,320.0],[68.0,320.0],[67.0,320.0],[66.0,320.0],[65.0,320.0],[64.0,320.0],[63.0,320.0],[62.0,320.0],[61.0,320.0],[60.0,320.0],[59.0,320.0],[58.0,320.0],[57.0,320.0],[56.0,320.0],[55.0,320.0],[54.0,320.0],[53.0,320.0],[52.0,320.0],[51.0,320.0],[50.0,320.0],[49.0,320.0],[48.0,320.0],[47.0,320.0],[46.0,320.0],[45.0,320.0],[44.0,320.0],[43.0,320.0],[42.0,320.0],[41.0,320.0],[40.0,320.0],[39.0,320.0],[38.0,320.0],[37.0,320.0],[36.0,320.0],[35.0,320.0],[34.0,320.0],[33.0,320.0],[32.0,320.0],[31.0,320.0],[30.0,320.0],[29.0,320.0],[28.0,320.0],[27.0,320.0],[26.0,320.0],[25.0,320.0],[24.0,320.0],[23.0,320.0],[22.0,320.0],[21.0,320.0],[20.0,320.0],[19.0,320.0],[18.0,320.0],[17.0,320.0],[16.0,320.0],[15.0,320.0],[14.0,320.0],[13.0,320.0],[12.0,320.0],[11.0,320.0],[10.0,320.0],[9.0,320.0],[8.0,320.0],[7.0,320.0],[6.0,320.0],[5.0,320.0],[4.0,320.0],[3.0,320.0],[2.0,320.0],[1.0,320.0],[0.0,320.0],[0.0,319.0],[0.0,318.0],[0.0,317.0],[0.0,316.0],[0.0,315.0],[0.0,314.0],[0.0,313.0],[0.0,312.0],[0.0,311.0],[0.0,310.0],[0.0,309.0],[0.0,308.0],[0.0,307.0],[0.0,306.0],[0.0,305.0],[0.0,304.0],[0.0,303.0],[0.0,302.0],[0.0,301.0],[0.0,300.0],[0.0,299.0],[0.0,298.0],[0.0,297.0],[0.0,296.0],[0.0,295.0],[0.0,294.0],[0.0,293.0],[0.0,292.0],[0.0,291.0],[0.0,290.0],[0.0,289.0],[0.0,288.0],[0.0,287.0],[0.0,286.0],[0.0,285.0],[0.0,284.0],[0.0,283.0],[0.0,282.0],[0.0,281.0],[0.0,280.0],[0.0,279.0],[0.0,278.0],[0.0,277.0],[0.0,276.0],[0.0,275.0],[0.0,274.0],[0.0,273.0],[0.0,272.0],[0.0,271.0],[0.0,270.0],[0.0,269.0],[0.0,268.0],[0.0,267.0],[0.0,266.0],[0.0,265.0],[0.0,264.0],[0.0,263.0],[0.0,262.0],[0.0,261.0],[0.0,260.0],[0.0,259.0],[0.0,258.0],[0.0,257.0],[0.0,256.0],[0.0,255.0],[0.0,254.0],[0.0,253.0],[0.0,252.0],[0.0,251.0],[0.0,250.0],[0.0,249.0],[0.0,248.0],[0.0,247.0],[0.0,246.0],[0.0,245.0],[0.0,244.0],[0.0,243.0],[0.0,242.0],[0.0,241.0],[0.0,240.0],[0.0,239.0],[0.0,238.0],[0.0,237.0],[0.0,236.0],[0.0,235.0],[0.0,234.0],[0.0,233.0],[0.0,232.0],[0.0,231.0],[0.0,230.0],[0.0,229.0],[0.0,228.0],[0.0,227.0],[0.0,226.0],[0.0,225.0],[0.0,224.0],[0.0,223.0],[0.0,222.0],[0.0,221.0],[0.0,220.0],[0.0,219.0],[0.0,218.0],[0.0,217.0],[0.0,216.0],[0.0,215.0],[0.0,214.0],[0.0,213.0],[0.0,212.0],[0.0,211.0],[0.0,210.0],[0.0,209.0],[0.0,208.0],[0.0,207.0],[0.0,206.0],[0.0,205.0],[0.0,204.0],[0.0,203.0],[0.0,202.0],[0.0,201.0],[0.0,200.0],[0.0,199.0],[0.0,198.0],[0.0,197.0],[0.0,196.0],[0.0,195.0],[0.0,194.0],[0.0,193.0],[0.0,192.0],[0.0,191.0],[0.0,190.0],[0.0,189.0],[0.0,188.0],[0.0,187.0],[0.0,186.0],[0.0,185.0],[0.0,184.0],[0.0,183.0],[0.0,182.0],[0.0,181.0],[0.0,180.0],[0.0,179.0],[0.0,178.0],[0.0,177.0],[0.0,176.0],[0.0,175.0],[0.0,174.0],[0.0,173.0],[0.0,172.0],[0.0,171.0],[0.0,170.0],[0.0,169.0],[0.0,168.0],[0.0,167.0],[0.0,166.0],[0.0,165.0],[0.0,164.0],[0.0,163.0],[0.0,162.0],[0.0,161.0],[0.0,160.0],[0.0,159.0],[0.0,158.0],[0.0,157.0],[0.0,156.0],[0.0,155.0],[0.0,154.0],[0.0,153.0],[0.0,152.0],[0.0,151.0],[0.0,150.0],[0.0,149.0],[0.0,148.0],[0.0,147.0],[0.0,146.0],[0.0,145.0],[0.0,144.0],[0.0,143.0],[0.0,142.0],[0.0,141.0],[0.0,140.0],[0.0,139.0],[0.0,138.0],[0.0,137.0],[0.0,136.0],[0.0,135.0],[0.0,134.0],[0.0,133.0],[0.0,132.0],[0.0,131.0],[0.0,130.0],[0.0,129.0],[0.0,128.0],[0.0,127.0],[0.0,126.0],[0.0,125.0],[0.0,124.0],[0.0,123.0],[0.0,122.0],[0.0,121.0],[0.0,120.0],[0.0,119.0],[0.0,118.0],[0.0,117.0],[0.0,116.0],[0.0,115.0],[0.0,114.0],[0.0,113.0],[0.0,112.0],[0.0,111.0],[0.0,110.0],[0.0,109.0],[0.0,108.0],[0.0,107.0],[0.0,106.0],[0.0,105.0],[0.0,104.0],[0.0,103.0],[0.0,102.0],[0.0,101.0],[0.0,100.0],[0.0,99.0],[0.0,98.0],[0.0,97.0],[0.0,96.0],[0.0,95.0],[0.0,94.0],[0.0,93.0],[0.0,92.0],[0.0,91.0],[0.0,90.0],[0.0,89.0],[0.0,88.0],[0.0,87.0],[0.0,86.0],[0.0,85.0],[0.0,84.0],[0.0,83.0],[0.0,82.0],[0.0,81.0],[0.0,80.0],[0.0,79.0],[0.0,78.0],[0.0,77.0],[0.0,76.0],[0.0,75.0],[0.0,74.0],[0.0,73.0],[0.0,72.0],[0.0,71.0],[0.0,70.0],[0.0,69.0],[0.0,68.0],[0.0,67.0],[0.0,66.0],[0.0,65.0],[0.0,64.0],[0.0,63.0],[0.0,62.0],[0.0,61.0],[0.0,60.0],[0.0,59.0],[0.0,58.0],[0.0,57.0],[0.0,56.0],[0.0,55.0],[0.0,54.0],[0.0,53.0],[0.0,52.0],[0.0,51.0],[0.0,50.0],[0.0,49.0],[0.0,48.0],[0.0,47.0],[0.0,46.0],[0.0,45.0],[0.0,44.0],[0.0,43.0],[0.0,42.0],[0.0,41.0],[0.0,40.0],[0.0,39.0],[0.0,38.0],[0.0,37.0],[0.0,36.0],[0.0,35.0],[0.0,34.0],[0.0,33.0],[0.0,32.0],[0.0,31.0],[0.0,30.0],[0.0,29.0],[0.0,28.0],[0.0,27.0],[0.0,26.0],[0.0,25.0],[0.0,24.0],[0.0,23.0],[0.0,22.0],[0.0,21.0],[0.0,20.0],[0.0,19.0],[0.0,18.0],[0.0,17.0],[0.0,16.0],[0.0,15.0],[0.0,14.0],[0.0,13.0],[0.0,12.0],[0.0,11.0],[0.0,10.0],[0.0,9.0],[0.0,8.0],[0.0,7.0],[0.0,6.0],[0.0,5.0],[0.0,4.0],[0.0,3.0],[0.0,2.0],[0.0,1.0]],"shapes":{"bbox":{"0.25":[{"contour":[],"geometry":{"height":320.0,"type":"bbox","width":320.0,"x":0.0,"y":0.0}}],"0.5":[{"contour":[],"geometry":{"height":320.0,"type":"bbox","width":320.0,"x":0.0,"y":0.0}}],"1.0":[{"contour":[],"geometry":{"height":320.0,"type":"bbox","width":320.0,"x":0.0,"y":0.0}}],"16.0":[{"contour":[],"geometry":{"height":320.0,"type":"bbox","width":320.0,"x":0.0,"y":0.0}}],"2.0":[{"contour":[],"geometry":{"height":320.0,"type":"bbox","width":320.0,"x":0.0,"y":0.0}}],"4.0":[{"contour":[],"geometry":{"height":320.0,"type":"bbox","width":320.0,"x":0.0,"y":0.0}}],"8.0":[{"contour":[],"geometry":{"height":320.0,"type":"bbox","width":320.0,"x":0.0,"y":0.0}}]},"bbox,polygon":{"0.25":[{"contour":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0]],"type":"polygon"}}],"0.5":[{"contour":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0]],"type":"polygon"}}],"1.0":[{"contour":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0]],"type":"polygon"}}],"16.0":[{"contour":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0]],"type":"polygon"}}],"2.0":[{"contour":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0]],"type":"polygon"}}],"4.0":[{"contour":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0]],"type":"polygon"}}],"8.0":[{"contour":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0]],"type":"polygon"}}]},"polygon":{"0.25":[{"contour":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0]],"type":"polygon"}}],"0.5":[{"contour":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0]],"type":"polygon"}}],"1.0":[{"contour":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0]],"type":"polygon"}}],"16.0":[{"contour":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0]],"type":"polygon"}}],"2.0":[{"contour":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0]],"type":"polygon"}}],"4.0":[{"contour":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0]],"type":"polygon"}}],"8.0":[{"contour":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0]],"type":"polygon"}}]},"polygon,bbox":{"0.25":[{"contour":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0]],"type":"polygon"}}],"0.5":[{"contour":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0]],"type":"polygon"}}],"1.0":[{"contour":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0]],"type":"polygon"}}],"16.0":[{"contour":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0]],"type":"polygon"}}],"2.0":[{"contour":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0]],"type":"polygon"}}],"4.0":[{"contour":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0]],"type":"polygon"}}],"8.0":[{"contour":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[319.75,0.0],[320.0,319.75],[0.25,320.0]],"type":"polygon"}}]},"polyline":{"0.25":[],"0.5":[],"1.0":[],"16.0":[],"2.0":[],"4.0":[],"8.0":[]}}},{"at":[],"closing_radius":1,"components":[{"height":64,"runs":[[0,0,63],[1,0,63],[2,0,63],[3,0,63],[4,0,63],[5,0,63],[6,0,63],[7,0,63],[8,0,63],[9,0,63],[10,0,63],[11,0,63],[12,0,63],[13,0,63],[14,0,63],[15,0,63],[16,0,63],[17,0,63],[18,0,63],[19,0,63],[20,0,63],[21,0,63],[22,0,63],[23,0,63],[24,0,63],[25,0,63],[26,0,63],[27,0,63],[28,0,63],[29,0,63],[30,0,63],[31,0,30],[31,33,63],[32,0,30],[32,33,63],[33,0,63],[34,0,63],[35,0,63],[36,0,63],[37,0,63],[38,0,63],[39,0,63],[40,0,63],[41,0,63],[42,0,63],[43,0,63],[44,0,63],[45,0,63],[46,0,63],[47,0,63],[48,0,63],[49,0,63],[50,0,63],[51,0,63],[52,0,63],[53,0,63],[54,0,63],[55,0,63],[56,0,63],[57,0,63],[58,0,63],[59,0,63],[60,0,63],[61,0,63],[62,0,63],[63,0,63]],"width":64,"x":0,"y":0}],"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"filled":{"height":64,"runs":[[0,0,63],[1,0,63],[2,0,63],[3,0,63],[4,0,63],[5,0,63],[6,0,63],[7,0,63],[8,0,63],[9,0,63],[10,0,63],[11,0,63],[12,0,63],[13,0,63],[14,0,63],[15,0,63],[16,0,63],[17,0,63],[18,0,63],[19,0,63],[20,0,63],[21,0,63],[22,0,63],[23,0,63],[24,0,63],[25,0,63],[26,0,63],[27,0,63],[28,0,63],[29,0,63],[30,0,63],[31,0,63],[32,0,63],[33,0,63],[34,0,63],[35,0,63],[36,0,63],[37,0,63],[38,0,63],[39,0,63],[40,0,63],[41,0,63],[42,0,63],[43,0,63],[44,0,63],[45,0,63],[46,0,63],[47,0,63],[48,0,63],[49,0,63],[50,0,63],[51,0,63],[52,0,63],[53,0,63],[54,0,63],[55,0,63],[56,0,63],[57,0,63],[58,0,63],[59,0,63],[60,0,63],[61,0,63],[62,0,63],[63,0,63]],"width":64},"mask":{"height":64,"runs":[[0,0,63],[1,0,63],[2,0,63],[3,0,63],[4,0,63],[5,0,63],[6,0,63],[7,0,63],[8,0,63],[9,0,63],[10,0,63],[11,0,63],[12,0,63],[13,0,63],[14,0,63],[15,0,63],[16,0,63],[17,0,63],[18,0,63],[19,0,63],[20,0,63],[21,0,63],[22,0,63],[23,0,63],[24,0,63],[25,0,63],[26,0,63],[27,0,63],[28,0,63],[29,0,63],[30,0,63],[31,0,30],[31,33,63],[32,0,30],[32,33,63],[33,0,63],[34,0,63],[35,0,63],[36,0,63],[37,0,63],[38,0,63],[39,0,63],[40,0,63],[41,0,63],[42,0,63],[43,0,63],[44,0,63],[45,0,63],[46,0,63],[47,0,63],[48,0,63],[49,0,63],[50,0,63],[51,0,63],[52,0,63],[53,0,63],[54,0,63],[55,0,63],[56,0,63],[57,0,63],[58,0,63],[59,0,63],[60,0,63],[61,0,63],[62,0,63],[63,0,63]],"width":64},"name":"enclosed-hole","outline":[[0.0,0.0],[1.0,0.0],[2.0,0.0],[3.0,0.0],[4.0,0.0],[5.0,0.0],[6.0,0.0],[7.0,0.0],[8.0,0.0],[9.0,0.0],[10.0,0.0],[11.0,0.0],[12.0,0.0],[13.0,0.0],[14.0,0.0],[15.0,0.0],[16.0,0.0],[17.0,0.0],[18.0,0.0],[19.0,0.0],[20.0,0.0],[21.0,0.0],[22.0,0.0],[23.0,0.0],[24.0,0.0],[25.0,0.0],[26.0,0.0],[27.0,0.0],[28.0,0.0],[29.0,0.0],[30.0,0.0],[31.0,0.0],[32.0,0.0],[33.0,0.0],[34.0,0.0],[35.0,0.0],[36.0,0.0],[37.0,0.0],[38.0,0.0],[39.0,0.0],[40.0,0.0],[41.0,0.0],[42.0,0.0],[43.0,0.0],[44.0,0.0],[45.0,0.0],[46.0,0.0],[47.0,0.0],[48.0,0.0],[49.0,0.0],[50.0,0.0],[51.0,0.0],[52.0,0.0],[53.0,0.0],[54.0,0.0],[55.0,0.0],[56.0,0.0],[57.0,0.0],[58.0,0.0],[59.0,0.0],[60.0,0.0],[61.0,0.0],[62.0,0.0],[63.0,0.0],[64.0,0.0],[64.0,1.0],[64.0,2.0],[64.0,3.0],[64.0,4.0],[64.0,5.0],[64.0,6.0],[64.0,7.0],[64.0,8.0],[64.0,9.0],[64.0,10.0],[64.0,11.0],[64.0,12.0],[64.0,13.0],[64.0,14.0],[64.0,15.0],[64.0,16.0],[64.0,17.0],[64.0,18.0],[64.0,19.0],[64.0,20.0],[64.0,21.0],[64.0,22.0],[64.0,23.0],[64.0,24.0],[64.0,25.0],[64.0,26.0],[64.0,27.0],[64.0,28.0],[64.0,29.0],[64.0,30.0],[64.0,31.0],[64.0,32.0],[64.0,33.0],[64.0,34.0],[64.0,35.0],[64.0,36.0],[64.0,37.0],[64.0,38.0],[64.0,39.0],[64.0,40.0],[64.0,41.0],[64.0,42.0],[64.0,43.0],[64.0,44.0],[64.0,45.0],[64.0,46.0],[64.0,47.0],[64.0,48.0],[64.0,49.0],[64.0,50.0],[64.0,51.0],[64.0,52.0],[64.0,53.0],[64.0,54.0],[64.0,55.0],[64.0,56.0],[64.0,57.0],[64.0,58.0],[64.0,59.0],[64.0,60.0],[64.0,61.0],[64.0,62.0],[64.0,63.0],[64.0,64.0],[63.0,64.0],[62.0,64.0],[61.0,64.0],[60.0,64.0],[59.0,64.0],[58.0,64.0],[57.0,64.0],[56.0,64.0],[55.0,64.0],[54.0,64.0],[53.0,64.0],[52.0,64.0],[51.0,64.0],[50.0,64.0],[49.0,64.0],[48.0,64.0],[47.0,64.0],[46.0,64.0],[45.0,64.0],[44.0,64.0],[43.0,64.0],[42.0,64.0],[41.0,64.0],[40.0,64.0],[39.0,64.0],[38.0,64.0],[37.0,64.0],[36.0,64.0],[35.0,64.0],[34.0,64.0],[33.0,64.0],[32.0,64.0],[31.0,64.0],[30.0,64.0],[29.0,64.0],[28.0,64.0],[27.0,64.0],[26.0,64.0],[25.0,64.0],[24.0,64.0],[23.0,64.0],[22.0,64.0],[21.0,64.0],[20.0,64.0],[19.0,64.0],[18.0,64.0],[17.0,64.0],[16.0,64.0],[15.0,64.0],[14.0,64.0],[13.0,64.0],[12.0,64.0],[11.0,64.0],[10.0,64.0],[9.0,64.0],[8.0,64.0],[7.0,64.0],[6.0,64.0],[5.0,64.0],[4.0,64.0],[3.0,64.0],[2.0,64.0],[1.0,64.0],[0.0,64.0],[0.0,63.0],[0.0,62.0],[0.0,61.0],[0.0,60.0],[0.0,59.0],[0.0,58.0],[0.0,57.0],[0.0,56.0],[0.0,55.0],[0.0,54.0],[0.0,53.0],[0.0,52.0],[0.0,51.0],[0.0,50.0],[0.0,49.0],[0.0,48.0],[0.0,47.0],[0.0,46.0],[0.0,45.0],[0.0,44.0],[0.0,43.0],[0.0,42.0],[0.0,41.0],[0.0,40.0],[0.0,39.0],[0.0,38.0],[0.0,37.0],[0.0,36.0],[0.0,35.0],[0.0,34.0],[0.0,33.0],[0.0,32.0],[0.0,31.0],[0.0,30.0],[0.0,29.0],[0.0,28.0],[0.0,27.0],[0.0,26.0],[0.0,25.0],[0.0,24.0],[0.0,23.0],[0.0,22.0],[0.0,21.0],[0.0,20.0],[0.0,19.0],[0.0,18.0],[0.0,17.0],[0.0,16.0],[0.0,15.0],[0.0,14.0],[0.0,13.0],[0.0,12.0],[0.0,11.0],[0.0,10.0],[0.0,9.0],[0.0,8.0],[0.0,7.0],[0.0,6.0],[0.0,5.0],[0.0,4.0],[0.0,3.0],[0.0,2.0],[0.0,1.0]],"shapes":{"bbox":{"0.25":[{"contour":[],"geometry":{"height":64.0,"type":"bbox","width":64.0,"x":0.0,"y":0.0}}],"0.5":[{"contour":[],"geometry":{"height":64.0,"type":"bbox","width":64.0,"x":0.0,"y":0.0}}],"1.0":[{"contour":[],"geometry":{"height":64.0,"type":"bbox","width":64.0,"x":0.0,"y":0.0}}],"16.0":[{"contour":[],"geometry":{"height":64.0,"type":"bbox","width":64.0,"x":0.0,"y":0.0}}],"2.0":[{"contour":[],"geometry":{"height":64.0,"type":"bbox","width":64.0,"x":0.0,"y":0.0}}],"4.0":[{"contour":[],"geometry":{"height":64.0,"type":"bbox","width":64.0,"x":0.0,"y":0.0}}],"8.0":[{"contour":[],"geometry":{"height":64.0,"type":"bbox","width":64.0,"x":0.0,"y":0.0}}]},"bbox,polygon":{"0.25":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"0.5":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"1.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"16.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"2.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"4.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"8.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}]},"polygon":{"0.25":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"0.5":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"1.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"16.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"2.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"4.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"8.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}]},"polygon,bbox":{"0.25":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"0.5":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"1.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"16.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"2.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"4.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}],"8.0":[{"contour":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0],[0.0,0.25]],"geometry":{"points":[[0.25,0.0],[63.75,0.0],[64.0,63.75],[0.25,64.0]],"type":"polygon"}}]},"polyline":{"0.25":[],"0.5":[],"1.0":[],"16.0":[],"2.0":[],"4.0":[],"8.0":[]}}},{"at":[],"closing_radius":0,"components":[{"height":1,"runs":[[0,0,15]],"width":16,"x":2,"y":3}],"contour":[[0.25,0.0],[15.75,0.0],[16.0,0.75],[0.25,1.0],[0.0,0.25]],"filled":{"height":1,"runs":[[0,0,15]],"width":16},"mask":{"height":8,"runs":[[3,2,17]],"width":20},"name":"thin","outline":[[0.0,0.0],[1.0,0.0],[2.0,0.0],[3.0,0.0],[4.0,0.0],[5.0,0.0],[6.0,0.0],[7.0,0.0],[8.0,0.0],[9.0,0.0],[10.0,0.0],[11.0,0.0],[12.0,0.0],[13.0,0.0],[14.0,0.0],[15.0,0.0],[16.0,0.0],[16.0,1.0],[15.0,1.0],[14.0,1.0],[13.0,1.0],[12.0,1.0],[11.0,1.0],[10.0,1.0],[9.0,1.0],[8.0,1.0],[7.0,1.0],[6.0,1.0],[5.0,1.0],[4.0,1.0],[3.0,1.0],[2.0,1.0],[1.0,1.0],[0.0,1.0]],"shapes":{"bbox":{"0.25":[{"contour":[],"geometry":{"height":1.0,"type":"bbox","width":16.0,"x":2.0,"y":3.0}}],"0.5":[{"contour":[],"geometry":{"height":1.0,"type":"bbox","width":16.0,"x":2.0,"y":3.0}}],"1.0":[{"contour":[],"geometry":{"height":1.0,"type":"bbox","width":16.0,"x":2.0,"y":3.0}}],"16.0":[{"contour":[],"geometry":{"height":1.0,"type":"bbox","width":16.0,"x":2.0,"y":3.0}}],"2.0":[{"contour":[],"geometry":{"height":1.0,"type":"bbox","width":16.0,"x":2.0,"y":3.0}}],"4.0":[{"contour":[],"geometry":{"height":1.0,"type":"bbox","width":16.0,"x":2.0,"y":3.0}}],"8.0":[{"contour":[],"geometry":{"height":1.0,"type":"bbox","width":16.0,"x":2.0,"y":3.0}}]},"bbox,polygon":{"0.25":[{"contour":[[2.25,3.0],[17.75,3.0],[18.0,3.75],[2.25,4.0],[2.0,3.25]],"geometry":{"points":[[2.25,3.0],[17.75,3.0],[18.0,3.75],[2.25,4.0]],"type":"polygon"}}],"0.5":[{"contour":[[2.25,3.0],[17.75,3.0],[18.0,3.75],[2.25,4.0],[2.0,3.25]],"geometry":{"points":[[2.25,3.0],[17.75,3.0],[18.0,3.75],[2.25,4.0]],"type":"polygon"}}],"1.0":[{"contour":[[2.25,3.0],[17.75,3.0],[18.0,3.75],[2.25,4.0],[2.0,3.25]],"geometry":{"points":[[2.25,3.0],[18.0,3.75],[2.0,3.25]],"type":"polygon"}}],"16.0":[],"2.0":[{"contour":[[2.25,3.0],[17.75,3.0],[18.0,3.75],[2.25,4.0],[2.0,3.25]],"geometry":{"points":[[2.25,3.0],[18.0,3.75],[2.0,3.25]],"type":"polygon"}}],"4.0":[{"contour":[[2.25,3.0],[17.75,3.0],[18.0,3.75],[2.25,4.0],[2.0,3.25]],"geometry":{"points":[[2.25,3.0],[18.0,3.75],[2.0,3.25]],"type":"polygon"}}],"8.0":[{"contour":[[2.25,3.0],[17.75,3.0],[18.0,3.75],[2.25,4.0],[2.0,3.25]],"geometry":{"points":[[2.25,3.0],[18.0,3.75],[2.0,3.25]],"type":"polygon"}}]},"polygon":{"0.25":[{"contour":[[2.25,3.0],[17.75,3.0],[18.0,3.75],[2.25,4.0],[2.0,3.25]],"geometry":{"points":[[2.25,3.0],[17.75,3.0],[18.0,3.75],[2.25,4.0]],"type":"polygon"}}],"0.5":[{"contour":[[2.25,3.0],[17.75,3.0],[18.0,3.75],[2.25,4.0],[2.0,3.25]],"geometry":{"points":[[2.25,3.0],[17.75,3.0],[18.0,3.75],[2.25,4.0]],"type":"polygon"}}],"1.0":[{"contour":[[2.25,3.0],[17.75,3.0],[18.0,3.75],[2.25,4.0],[2.0,3.25]],"geometry":{"points":[[2.25,3.0],[18.0,3.75],[2.0,3.25]],"type":"polygon"}}],"16.0":[],"2.0":[{"contour":[[2.25,3.0],[17.75,3.0],[18.0,3.75],[2.25,4.0],[2.0,3.25]],"geometry":{"points":[[2.25,3.0],[18.0,3.75],[2.0,3.25]],"type":"polygon"}}],"4.0":[{"contour":[[2.25,3.0],[17.75,3.0],[18.0,3.75],[2.25,4.0],[2.0,3.25]],"geometry":{"points":[[2.25,3.0],[18.0,3.75],[2.0,3.25]],"type":"polygon"}}],"8.0":[{"contour":[[2.25,3.0],[17.75,3.0],[18.0,3.75],[2.25,4.0],[2.0,3.25]],"geometry":{"points":[[2.25,3.0],[18.0,3.75],[2.0,3.25]],"type":"polygon"}}]},"polygon,bbox":{"0.25":[{"contour":[[2.25,3.0],[17.75,3.0],[18.0,3.75],[2.25,4.0],[2.0,3.25]],"geometry":{"points":[[2.25,3.0],[17.75,3.0],[18.0,3.75],[2.25,4.0]],"type":"polygon"}}],"0.5":[{"contour":[[2.25,3.0],[17.75,3.0],[18.0,3.75],[2.25,4.0],[2.0,3.25]],"geometry":{"points":[[2.25,3.0],[17.75,3.0],[18.0,3.75],[2.25,4.0]],"type":"polygon"}}],"1.0":[{"contour":[[2.25,3.0],[17.75,3.0],[18.0,3.75],[2.25,4.0],[2.0,3.25]],"geometry":{"points":[[2.25,3.0],[18.0,3.75],[2.0,3.25]],"type":"polygon"}}],"16.0":[],"2.0":[{"contour":[[2.25,3.0],[17.75,3.0],[18.0,3.75],[2.25,4.0],[2.0,3.25]],"geometry":{"points":[[2.25,3.0],[18.0,3.75],[2.0,3.25]],"type":"polygon"}}],"4.0":[{"contour":[[2.25,3.0],[17.75,3.0],[18.0,3.75],[2.25,4.0],[2.0,3.25]],"geometry":{"points":[[2.25,3.0],[18.0,3.75],[2.0,3.25]],"type":"polygon"}}],"8.0":[{"contour":[[2.25,3.0],[17.75,3.0],[18.0,3.75],[2.25,4.0],[2.0,3.25]],"geometry":{"points":[[2.25,3.0],[18.0,3.75],[2.0,3.25]],"type":"polygon"}}]},"polyline":{"0.25":[],"0.5":[],"1.0":[],"16.0":[],"2.0":[],"4.0":[],"8.0":[]}}}],"closing_reach":0.002,"default_tolerance":1.0,"maximum_closing_radius":6,"minimum_fragment_share":0.05,"minimum_tolerance":0.25,"tolerances":[0.25,0.5,1.0,2.0,4.0,8.0,16.0]} diff --git a/tests/inference/test_mask_geometry_fixture.py b/tests/inference/test_mask_geometry_fixture.py new file mode 100644 index 00000000..ebb5c5ac --- /dev/null +++ b/tests/inference/test_mask_geometry_fixture.py @@ -0,0 +1,191 @@ +"""The Python half of the mask-to-geometry parity gate. + +`tests/fixtures/mask_geometry.json` is a committed artifact and the only thing +carrying this pipeline across the language boundary: the `frontend` CI job +installs no Python and reads what is in the repository. + +So it needs two independent links. This is the first — the fixture is the +application's own output, and this module fails when it drifts. The second is +`frontend/annotator/src/core/mask/maskGeometry.test.ts`. + +The tests after the staleness check are about the fixture rather than the code: +a golden fixture that never reaches a branch is not a gate, so each one names a +branch and fails if no case exercises it. +""" + +from __future__ import annotations + +import json +from pathlib import Path +from typing import Any + +import pytest +from scripts.export_mask_geometry_fixtures import ALLOWED, OUTPUT_PATH, TOLERANCES, build_fixture + +from visionset.inference.masks import ( + CLOSING_REACH, + MAXIMUM_CLOSING_RADIUS, + MINIMUM_FRAGMENT_SHARE, +) +from visionset.kernel.domain import DEFAULT_TOLERANCE, MINIMUM_TOLERANCE + +REPO_ROOT = Path(__file__).resolve().parents[2] + + +def committed() -> dict[str, Any]: + payload: dict[str, Any] = json.loads((REPO_ROOT / OUTPUT_PATH).read_text()) + return payload + + +def named(name: str) -> dict[str, Any]: + return next(case for case in committed()["cases"] if case["name"] == name) + + +def test_the_committed_fixture_matches_the_application() -> None: + assert committed() == build_fixture(), ( + "tests/fixtures/mask_geometry.json is stale — run " + "`uv run python scripts/export_mask_geometry_fixtures.py` and commit the result." + ) + + +def test_the_fixture_carries_the_constants_the_port_needs() -> None: + """The TypeScript reads these rather than restating them, so they have to travel.""" + payload = committed() + assert payload["minimum_fragment_share"] == MINIMUM_FRAGMENT_SHARE + assert payload["closing_reach"] == CLOSING_REACH + assert payload["maximum_closing_radius"] == MAXIMUM_CLOSING_RADIUS + assert payload["minimum_tolerance"] == MINIMUM_TOLERANCE + assert payload["default_tolerance"] == DEFAULT_TOLERANCE + assert payload["tolerances"] == TOLERANCES + + +def test_every_case_covers_every_allowed_set_and_every_tolerance() -> None: + keys = {",".join(str(kind.value) for kind in allowed) for allowed in ALLOWED} + for case in committed()["cases"]: + assert set(case["shapes"]) == keys + for shapes in case["shapes"].values(): + assert set(shapes) == {str(tolerance) for tolerance in TOLERANCES} + + +def test_a_case_has_more_than_one_surviving_component() -> None: + assert [case for case in committed()["cases"] if len(case["components"]) > 1] + + +def test_a_case_points_at_something_other_than_the_default_head() -> None: + """Without one, a port that took the first component would pass the whole gate.""" + moved = [ + case + for case in committed()["cases"] + if case["at"] + and len(case["components"]) > 1 + and case["components"][0]["x"] > case["components"][1]["x"] + ] + assert moved, "no case proves the prompt moves the head" + + +def test_a_case_has_two_pointed_components_of_equal_area() -> None: + """The tie `_pointed_at` settles by reading order — an interpreter cannot decide it.""" + case = named("equal-area-tie") + assert case["components"][0]["x"] == 12 + assert named("equal-area-tie-reversed")["components"][0]["x"] == 12 + + +def _head_runs(case: dict[str, Any]) -> list[list[int]]: + """The head piece's own runs, before the close touched it.""" + return list(case["components"][0]["runs"]) + + +def test_a_case_is_changed_by_the_closing_and_another_is_not() -> None: + """Both halves, or the step is only half proved. + + A fixture holding no closed gap would pass a port that skipped the close + entirely; one holding nothing the close leaves alone would pass a port that + closed everything, at any radius. + """ + reaching = [case for case in committed()["cases"] if case["closing_radius"]] + changed = [case for case in reaching if case["filled"]["runs"] != _head_runs(case)] + unchanged = [case for case in reaching if case["filled"]["runs"] == _head_runs(case)] + assert changed, "no case is changed by the close" + assert unchanged, "no case with a reach is left alone by the close" + + +def test_a_case_clicks_at_a_half_pixel() -> None: + """The coordinate where Python's rounding and JavaScript's disagree.""" + halves = [ + case + for case in committed()["cases"] + if any(value != int(value) for point in case["at"] for value in point) + ] + assert halves, "no case tells the two roundings apart" + + +def test_a_case_touches_only_diagonally() -> None: + case = named("diagonal-touch") + assert len(case["components"]) == 1, "a diagonal touch is one 8-connected piece" + assert len(case["outline"]) == 8, "and one ring round both unit squares" + + +def test_a_case_boxes_more_than_its_polygon_traces() -> None: + """The branch that is the whole point of keeping the two geometries apart.""" + wider = [] + for case in committed()["cases"]: + box = case["shapes"]["bbox"]["1.0"] + polygon = case["shapes"]["polygon"]["1.0"] + if not box or not polygon: + continue + span = max(point[0] for point in polygon[0]["geometry"]["points"]) - min( + point[0] for point in polygon[0]["geometry"]["points"] + ) + if box[0]["geometry"]["width"] > span + 1: + wider.append(case) + assert wider, "no case shows a box spanning more than its polygon" + + +def test_a_case_moves_its_vertex_count_across_the_ladder() -> None: + moving = [ + case + for case in committed()["cases"] + if len( + { + len(shapes[0]["geometry"]["points"]) + for shapes in case["shapes"]["polygon"].values() + if shapes and shapes[0]["geometry"]["type"] == "polygon" + } + ) + >= 3 + ] + assert moving, "no case tells the tolerances apart" + + +def test_a_box_is_the_same_box_at_every_tolerance() -> None: + for case in committed()["cases"]: + answers = [shapes for shapes in case["shapes"]["bbox"].values()] + assert all(answer == answers[0] for answer in answers), case["name"] + + +def test_the_two_orderings_of_one_allowed_set_agree() -> None: + for case in committed()["cases"]: + assert case["shapes"]["bbox,polygon"] == case["shapes"]["polygon,bbox"], case["name"] + + +def test_a_class_admitting_neither_kind_is_offered_nothing() -> None: + for case in committed()["cases"]: + for shapes in case["shapes"]["polyline"].values(): + assert shapes == [] + + +def test_a_case_proposes_nothing_at_all() -> None: + empty = [ + case + for case in committed()["cases"] + if all(not shapes for shapes in case["shapes"]["polygon"].values()) + ] + assert empty, "no case is below what a shape can be" + + +@pytest.mark.parametrize("case", committed()["cases"], ids=lambda c: str(c["name"])) +def test_a_mask_is_lit_runs_inside_its_own_frame(case: dict[str, Any]) -> None: + grid = case["mask"] + for y, first, last in grid["runs"]: + assert 0 <= y < grid["height"] + assert 0 <= first <= last < grid["width"] diff --git a/tests/inference/test_masks.py b/tests/inference/test_masks.py index 2869b4f7..370ff760 100644 --- a/tests/inference/test_masks.py +++ b/tests/inference/test_masks.py @@ -163,12 +163,68 @@ def test_a_click_just_off_the_piece_falls_back_to_the_nearest_one() -> None: assert (pieces[0].x, pieces[0].y) == (1, 3) +def test_nearest_piece_compares_squared_distances_without_a_square_root_tie() -> None: + """The smaller geometric distance wins even when its square roots round equal. + + These two one-pixel pieces are separate survivors. Their squared distances + from the in-frame point differ by one ulp, while their square roots can + round equal on a platform. Comparing the squared values keeps the answer + the actual nearer piece rather than letting a libm tie fall back to reading + order. + """ + mask = [[0] * 64 for _ in range(64)] + mask[12][11] = 1 + mask[26][44] = 1 + + pieces = components(mask, at=[(27.660028289416932, 18.62279046066009)]) + + assert (pieces[0].x, pieces[0].y) == (44, 26) + + def test_several_points_spanning_pieces_prefer_the_largest_of_them() -> None: """Two positives can straddle two pieces; the bigger one is the better answer.""" pieces = components(speckled(), at=[(9.0, 0.0), (3.0, 5.0)]) assert (pieces[0].x, pieces[0].y) == (1, 3), "the 36-px object beats the 1-px speck" +def tied() -> list[list[int]]: + """Two five-pixel components, rooted at run indices 3 and 8. + + The row of specks is what puts the roots at those indices, and 3 and 8 are + what make the tie visible: a set holding them iterates ``[8, 3]``, because + ``8 & 7`` is 0 and lands in an earlier bucket, so ``max`` over the set used + to answer with the *later* component. + """ + mask = [[0] * 30 for _ in range(7)] + for x in (0, 4, 8, 12, 16, 20, 24): + mask[0][x] = 1 # run indices 0..6 + mask[1][0] = 1 # run index 7, joins the component rooted at 0 + mask[1][2] = 1 # run index 8, a new component + for y in (1, 2, 3, 4): + mask[y][12] = 1 # the component rooted at run index 3 + for y in (2, 3, 4, 5): + mask[y][2] = 1 # the component rooted at run index 8 + return mask + + +def test_two_equally_large_pointed_pieces_are_settled_by_reading_order() -> None: + """The tie the module never stated, and the one a port cannot guess. + + A set's iteration order is an interpreter's hash-table layout, not a rule, so + the answer here is fixed the way `components` already fixes it for every + other piece: biggest first, ties by the lowest label — the piece whose + earliest run comes first. + """ + pieces = components(tied(), at=[(12.0, 2.0), (2.0, 3.0)]) + assert pieces[0].x == 12, "the earlier component leads when the areas are equal" + + +def test_the_tie_is_broken_by_reading_order_whichever_way_the_points_arrive() -> None: + """Point order is not a tie-break either — only the pieces decide.""" + reversed_points = components(tied(), at=[(2.0, 3.0), (12.0, 2.0)]) + assert reversed_points[0].x == 12 + + def test_without_a_point_the_noise_filter_still_answers_with_the_object() -> None: """Nothing outside a point prompt has an opinion — but the speck is gone first.