private PenDrawingPath pathForBoxDBUG(Box2f box) { PenDrawingPath pp = new PenDrawingPath(); pp.Add(new PenMove() { destination = box.min * viewBoxToPaperScale, color = Color.red }); pp.Add(new PenMove() { destination = box.lowerRight * viewBoxToPaperScale }); pp.Add(new PenMove() { destination = box.max * viewBoxToPaperScale }); pp.Add(new PenMove() { destination = box.upperLeft * viewBoxToPaperScale }); pp.Add(new PenMove() { destination = box.min * viewBoxToPaperScale, color = Color.black }); return(pp); }
void FillTri(PenDrawingPath pdPath, float imageToPaperScale, float toolDiam) { //TODO: add some notion of pixel to pen diameter? float dark = Mathf.Clamp(.01f, .999f, (float)tri.onlineNormalEstimator.mean() * (1f - tri.Filled)); Vector2f closest, a, b; tri.ClosestPoint(entryPoint, out closest, out a, out b); closest *= imageToPaperScale; a *= imageToPaperScale; b *= imageToPaperScale; Vector2f dA = a - closest, dB = b - closest; float length = tri.dims.x * imageToPaperScale; float incr = toolDiam + 5f * toolDiam * dark; // length * dark; incr = Mathf.Max(toolDiam, incr); int zigs = (int)(length / incr); Vector2f m, n; for (int i = 0; i < zigs * 2; i += 2) { m = dA * i / (float)zigs; pdPath.addDrawMove(closest + m); n = dB * (i + 1) / (float)zigs; pdPath.addDrawMove(closest + n); } // move to exit pdPath.addDrawMove(exitPoint * imageToPaperScale); }
public override IEnumerable <PenDrawingPath> generate() { PenDrawingPath pdPath = new PenDrawingPath(); SolveTriTree(pdPath); //DoTestTris(pdPath); yield return(pdPath); }
private PenDrawingPath twoPointPenPath(Vector2f start, Vector2f end, Matrix2f rot, Color c) { PenDrawingPath pp = new PenDrawingPath(); pp.addDownUpDrawMove((rot * start) * viewBoxToPaperScale, (rot * end) * viewBoxToPaperScale, c); //pp.Add(new PenMove() { destination = (rot * start) * viewBoxToPaperScale, up = false, color = c }); //pp.Add(new PenMove() { destination = (rot * end) * viewBoxToPaperScale, up = true }); return(pp); }
public void makeMoves(PenDrawingPath path) { PenUpdate pu = new PenUpdate(path); foreach (var sub in subscribers) { sub(pu); } //foreach(PenMove iter in path.GetMoves()) { // setPosition(iter); //} }
public void AddDrawPoints(PenDrawingPath pdPath, float imageBoxToPaperScale, float toolDiam) { var borders = tri.Border(); ientry = 0; iexit = 1; exitPoint = borders[1]; entryPoint = borders[0]; bool touchingLast = false; if (last != null) { touchingLast = last.adjacentExitPoint; if (touchingLast) { entryPoint = last.exitPoint; } ientry = tri.ClosestBorderIndex(last.exitPoint); } if (next != null) { Vector2f _exit; if (tri.IsTouching(next.tri, out _exit)) { adjacentExitPoint = true; exitPoint = _exit; iexit = tri.ClosestBorderIndex(_exit); } } if (!touchingLast) { pdPath.addTravelMove(entryPoint * imageBoxToPaperScale, ColorUtil.fuschia); } //if (tri.dims.x < toolDiam) //{ // pdPath.addDrawMove(tri.center * imageBoxToPaperScale); //} //else { //FillTri(pdPath, imageBoxToPaperScale, toolDiam); //TraceTri(pdPath, imageBoxToPaperScale, toolDiam); DrawTriSpiral(pdPath, ientry, iexit); } // CONSIDER: fill tris based on grayscale and populatedness // keep track of spread-out-ness of data within tris? }
void DoTestTris(PenDrawingPath pdPath) { Vector2f off = Vector2f.One * 4f; float size = 40f; DebugDrawTestTri( pdPath, off + Vector2f.Zero, 0, 1, size: size, dark: .1f, inverted: false); DebugDrawTestTri( pdPath, off + Vector2f.AxisX * (size * 1.05f), 2, 0, size: size, dark: .2f, inverted: false); DebugDrawTestTri( pdPath, off + Vector2f.AxisX * (size * 1.05f * .5f) + Vector2f.AxisY * size, 0, 0, size: size, dark: .3f, inverted: true); DebugDrawTestTri( pdPath, off + Vector2f.AxisX * (size * 1.05f * .5f) + Vector2f.AxisY * size, 0, 0, size: size, dark: .4f, inverted: false); DebugDrawTestTri( pdPath, off + Vector2f.AxisX * (size * 3.0125f * .5f) + Vector2f.AxisY * size, 0, 0, size: size, dark: .5f, inverted: false); }
public override IEnumerable <PenDrawingPath> generate() { if (pointSets != null) { for (int i = 0; i < pointSets.Count; ++i) { PenDrawingPath pdPath = new PenDrawingPath(); var points = pointSets[i]; foreach (var p in points) { pdPath.addDrawMove(p * viewBoxToPaperScale); } yield return(pdPath); } } }
void DebugDrawTestTri(PenDrawingPath pdPath, Vector2f offset, int ientry, int iexit, float size = 50f, float dark = .5f, bool inverted = false) { IsoTriangle <PixelTriData> tri = new IsoTriangle <PixelTriData> { _base = offset + Vector2f.AxisX * size / 2f, dims = new Vector2f(size, size * TriUtil.RootThree / 2f), inverted = inverted }; tri.Add(new PixelTriData(new PixelV { pos = tri.Centroid, color = new Color(dark, dark, dark, 1f) })); var triCross = new TriCrosshatch <PixelTriData>(this, tri); triCross.DrawTriSpiral(pdPath, ientry, iexit); }
private PenDrawingPath arrowToNextDBUG(int i, PathData pdata, Matrix2f rot) { var pp = new PenDrawingPath(); Vector2f last = Vector2f.Zero; foreach (var v in pdata.arrowFromThisToNext(i)) { last = (rot * v) * viewBoxToPaperScale; pp.Add(new PenMove() { destination = last }); } pp.Add(new PenMove() { destination = last, up = true }); return(pp); }
void TraceTri(PenDrawingPath pdPath, float imageToPaperScale, float toolDiam) { Vector2f closest, a, b; tri.ClosestPoint(entryPoint, out closest, out a, out b); if ((a - exitPoint).LengthSquared < (b - exitPoint).LengthSquared) { Vector2f temp = a; a = b; b = temp; } closest *= imageToPaperScale; a *= imageToPaperScale; b *= imageToPaperScale; pdPath.addDrawMove(closest, adjacentExitPoint ? Color.blue : Color.yellow); pdPath.addDrawMove(a, ColorUtil.powderBlue); pdPath.addDrawMove(b, adjacentExitPoint ? ColorUtil.aqua : ColorUtil.pink); }
PenDrawingPath fromTSP(TSPLibProblem tsp, List <Vector2f> points) { PenDrawingPath pdpath = new PenDrawingPath(); bool success = tsp.setIndicesFromOutputFile(); Debug.Log("TSP success? " + success); if (success) { for (int i = 0; i < points.Count; ++i) { pdpath.addDrawMove(points[tsp.indexAt(i)] * viewBoxToPaperScale); } } else { Debug.LogWarning("tsp encountered an error"); } Debug.Log("after add pts "); return(pdpath); }
private PenDrawingPath dotAtDBUG(Vector2f v, Matrix2f rot, Color c, float size = 5f) { var pp = new PenDrawingPath(); v = rot * v; Box2f box = new Box2f() { min = v, max = v + Vector2f.One * size }; foreach (Vector2f l in box.getHorizontalLines()) { pp.Add(new PenMove() { destination = l * viewBoxToPaperScale, color = c }); } pp.Add(new PenMove() { destination = v * viewBoxToPaperScale, up = true }); return(pp); }
internal void DrawTriSpiral(PenDrawingPath pdPath, int ientry, int iexit) { int origExit = iexit; if (ientry == iexit) { iexit = (ientry + 1) % 3; } int iother = (ientry + 1) % 3; if (iother == iexit) { iother = (ientry + 2) % 3; } var border = tri.Border(); var lookup = new int[] { ientry, iother, iexit }; bool ccw; { Vector3 a = (border[iother] - border[ientry]).ToVector3(0f); Vector3 b = (border[iexit] - border[ientry]).ToVector3(0f); ccw = Vector3.Cross(a, b).z > 0f; } var centroid = tri.Centroid; var radii = new Vector2f[3]; for (int i = 0; i < 3; ++i) { radii[lookup[i]] = border[lookup[i]] - centroid; } float maxLoops = generator.generatorConfig.SkewMaxLoops * tri.InnerRadius / ((float)generator.machineConfig.toolDiameterMM / generator.viewBoxToPaperScale); maxLoops *= .5f; float loopsF = maxLoops * (float)(1d - (generator.generatorConfig.SkewTriPixelMean.Evaluate((float)tri.onlineNormalEstimator.mean()))); int loops = Mathf.CeilToInt(loopsF); float incr = 1f / loopsF; float halfIncr = incr / 2f; float thirdIncr = incr / 3f; float sixthIncr = incr / 6f; float rad; Vector2f move; pdPath.addDrawMove(border[ientry] * generator.viewBoxToPaperScale, Color.magenta); rad = 1f - halfIncr; for (int i = loops - 1; i >= 0; --i) { for (int jj = 0; jj < 3; ++jj) { if (rad > 0f) { int j = ccw ? (2 - jj) : jj; move = centroid + radii[lookup[j]] * rad; pdPath.addDrawMove(move * generator.viewBoxToPaperScale, jj == 2 ? Color.cyan : Color.blue); } rad -= thirdIncr; } } rad += thirdIncr + halfIncr; for (int i = 1; i <= loops; ++i) { for (int jj = 2; jj >= 0; --jj) { if (rad > 0f) { int j = ccw ? (2 - jj) : jj; move = centroid + radii[lookup[j]] * rad; pdPath.addDrawMove(move * generator.viewBoxToPaperScale, jj == 0 ? ColorUtil.pink : ColorUtil.fuschia); } rad += thirdIncr; } } pdPath.addDrawMove(border[origExit] * generator.viewBoxToPaperScale, ColorUtil.aqua); }
IEnumerable <PenDrawingPath> crosshatches(StripedPath stripedPath) { Matrix2f inverseRotation; PathData pdata; for (var stripeField = stripedPath.stripeField; stripeField != null; stripeField = stripeField.next) { inverseRotation = stripeField.rotation.Inverse(); if (dbugSettings.dontRotateBackFinalPenPaths) { inverseRotation = Matrix2f.Identity; } pdata = new PathData(SvgParser.SvgPath.RotatedClone(stripedPath.path, stripeField.rotation), _svgFileData.isYAxisInverted); int lastEnterEdgeIndex = -100; foreach (int i in pdata.enterFromLeftEdgeIndices) { Vector2f edgeLower = pdata.areEnterLeftEdgesPosDelta ? pdata[i] : pdata.nextPoint(i); Vector2f edgeUpper = pdata.areEnterLeftEdgesPosDelta ? pdata.nextPoint(i) : pdata[i]; Assert.IsTrue(edgeLower.y < edgeUpper.y, "something wrong at index: " + i); Edge2f leftEdge = new Edge2f(edgeLower, edgeUpper); Vector2f leftIntersection; // foreach y: find exit edges that span the y, find closest intersecion point float y = stripeField.nextStripeYPosAbove(edgeLower.y); for (; y < stripeField.nextStripeYPosAbove(edgeUpper.y); y += stripeField.interval) { if (!leftEdge.intersectionPointWithY(y, out leftIntersection)) { continue; //break; // want? } float closestXDelta = float.MaxValue; for (int j = 0; j < pdata.exitFromLeftEdgeIndices.Count; ++j) { int jV = pdata.exitFromLeftEdgeIndices[j]; Edge2f jEdge = pdata.edgeAt(jV); Vector2f intrsection; if (jEdge.intersectionPointWithY(y, out intrsection)) { float dif = intrsection.x - leftIntersection.x; if (dif > 0f && dif < closestXDelta) { closestXDelta = dif; } } } if (closestXDelta < float.MaxValue) { PenDrawingPath penPath = new PenDrawingPath(); penPath.addDownUpDrawMove( (inverseRotation * leftIntersection) * viewBoxToPaperScale, (inverseRotation * new Vector2f(leftIntersection.x + closestXDelta, y)) * viewBoxToPaperScale, Color.black); yield return(penPath); } } lastEnterEdgeIndex = i; } } }
void SolveTriTree(PenDrawingPath pdPath) { //CONSIDER: two passes // 1.) Dark very detailed // 2.) mid to light don't sweat the details as much //split tri tree leaves if not sufficiently populated if (generatorConfig.ShouldSplitUnderFilledTris) { triTree.root.SplitUnderPopulatedLeaves(generatorConfig.TriFilledThreshold, generatorConfig.MaxSplitToFillRecursionDepth); } triTree.root.CullDataWithMaxMean(bitMapPointGenerator.MaxGrayScale); List <IsoTriangle <PixelTriData> > subTrees; // split tree into max cities sub trees subTrees = triTree.root.NonEmptyChildrenWithMaxLeaves(generatorConfig.MaxTSPTriangleCities); //DEBUG var meshGO = MeshUtil.MakeGameObject(triTree.getMesh(), "CrosshatchTriTree"); var pool = new CMDProcessPool(generatorConfig.MaxTSPThreads); var subLeaves = new List <IsoTriangle <PixelTriData> > [subTrees.Count]; var tsps = new TSPLibProblem[subTrees.Count]; //DEBUG delete any previously generated files TSPLibProblem.GetDeleteAllCommand(BaseFileName + "*").ToCMDProcess().run(); for (int i = 0; i < subTrees.Count; ++i) { var tree = subTrees[i]; //get leaf centers var leaves = tree.GetLeaves(true); var centers = new List <Vector2f>(leaves.Count); for (int j = 0; j < leaves.Count; ++j) { centers.Add(leaves[j].center); } // solve each sub tree var tsp = TSPLibProblem.FromPoints(centers.GetEnumerator(), BaseFileName + ".tri." + i); if (!tsp.OutputFileExists()) { pool.Add(tsp.GetTSPCommand()); } subLeaves[i] = leaves; tsps[i] = tsp; } pool.run(); for (int i = 0; i < subTrees.Count; ++i) { // crosshatch sub trees var tsp = tsps[i]; if (!tsp.setIndicesFromOutputFile()) { Debug.LogWarning("no tsp indices"); continue; //TODO: handle more gracefully } var leaves = subLeaves[i]; TriCrosshatch <PixelTriData> tch = null, last = null; for (int j = 0; j < leaves.Count; ++j) { tch = new TriCrosshatch <PixelTriData>(this, leaves[tsp.indexAt(j)]); tch.last = last; tch.next = j == leaves.Count - 1 ? null : new TriCrosshatch <PixelTriData>(this, leaves[tsp.indexAt(j + 1)]); tch.AddDrawPoints(pdPath, viewBoxToPaperScale, (float)machineConfig.toolDiameterMM); last = tch; } } }
public PenUpdate(PenDrawingPath path) { drawPath = path; } // PenMove from, PenMove to) { this.from = from; this.to = to; }