sclass OnePath { new ByteBuffer steps; *() {} *(S path) { int n = l(path); steps.allocate(n); for i to n: steps.add(parseDigit(path, i)); } *(OnePath path) { steps = new ByteBuffer(path.steps); } // uses first point as origin, so there will be l(points)-1 steps. // Unless you set close to true, then it adds the first point at the end again. *(Iterable points, bool close) { fromPoints(points, close); } void fromPoints(Iterable points, bool close) { var it = iterator(points); if (empty(it)) ret; Pt firstPoint = it.next(), p = firstPoint; while (it.hasNext()) { Pt p2 = it.next(); steps.add(ptToDigit(ptMinus(p2, p))); p = p2; } if (close) steps.add(ptToDigit(ptMinus(firstPoint, p))); } int size aka length aka nSteps() { ret steps.size(); } toString { ret pathString(); } S pathString() { ret singleDigitBytesToString(steps); } // includes first point, so returns length()+1 points in total ItIt pointIterator(Pt startPt default origin()) { ret new ItIt { int i = 0, n = length(); Pt p = startPt; public bool hasNext() { ret i <= n; } public Pt next() { var p = this.p; if (i < n) this.p = translatePt(this.p, getStepAsPt(i)); ++i; ret p; } }; } L pointList aka pointsList() { ret ptBuffer(pointIterator()); } int getStep(int i) { ret steps.get(i); } Pt getStepAsPt(int i) { ret onePathDirections()[steps.get(i)]; } static int ptToDigit(Pt p) { ret p.y < 0 ? p.x < 0 ? 1 : p.x == 0 ? 2 : 3 : p.y == 0 ? p.x < 0 ? 8 : p.x == 0 ? 0 : 4 : p.x < 0 ? 7 : p.x == 0 ? 6 : 5; } Pt origin() { ret main origin(); } Pt endPoint() { ret last(pointIterator()); } Pt drift() { ret ptMinus(endPoint(), origin()); } void addStep(Pt etc p) { int step = onePathLookupDirection(p); if (step < 0) fail("Invalid one path step: " + p); addStep(step); } void addStep(int step) { assertBetween(0, 8, step); steps.add(step); } void insertStep(int idx, Pt etc p) { int step = onePathLookupDirection(p); if (step < 0) fail("Invalid one path step: " + p); insertStep(idx, step); } void insertStep(int idx, int step) { assertBetween(0, 8, step); steps.add(idx, step); } Rect bounds() { ret boundsOfPts(pointIterator()); } }