public void ComputeOnBackgroundThread()
        {
            Deviation = null;

            DebugUtil.Log(SO.GetToolpathStats());

            ToolpathSet      paths  = SO.GetToolpaths();
            PlanarSliceStack slices = SO.GetSlices();
            var settings            = SO.GetSettings();

            // AAHHH
            double   bed_width  = settings.Machine.BedSizeXMM;
            double   bed_height = settings.Machine.BedSizeYMM;
            Vector3d origin     = new Vector3d(-bed_width / 2, -bed_height / 2, 0);

            if (settings is gs.info.MakerbotSettings)
            {
                origin = Vector3d.Zero;
            }

            List <DeviationPt>   points       = new List <DeviationPt>();
            SpinLock             pointsLock   = new SpinLock();
            Action <DeviationPt> appendPointF = (pt) => {
                bool entered = false;
                pointsLock.Enter(ref entered);
                points.Add(pt);
                pointsLock.Exit();
            };

            double tolerance = settings.Machine.NozzleDiamMM * 0.5 + DeviationToleranceMM;

            gParallel.ForEach(Interval1i.Range(slices.Count), (slicei) => {
                PlanarSlice slice = slices[slicei];

                //Interval1d zrange = (slicei < slices.Count - 1) ?
                //    new Interval1d(slice.Z, slices[slicei + 1].Z - 0.5*settings.LayerHeightMM) :
                //    new Interval1d(slice.Z, slice.Z + 0.5*settings.LayerHeightMM);
                double dz         = 0.5 * settings.LayerHeightMM;
                Interval1d zrange = new Interval1d(slice.Z - dz, slice.Z + dz);

                double cellSize = 2.0f;

                ToolpathsLayerGrid grid = new ToolpathsLayerGrid();
                grid.Build(paths, zrange, cellSize);

                foreach (GeneralPolygon2d poly in slice.Solids)
                {
                    measure_poly(poly.Outer, slice.Z, grid, tolerance, appendPointF);
                    foreach (var hole in poly.Holes)
                    {
                        measure_poly(poly.Outer, slice.Z, grid, tolerance, appendPointF);
                    }
                }
            });

            int N = points.Count;

            for (int k = 0; k < N; ++k)
            {
                DeviationPt pt = points[k];
                Vector3d    v  = origin + pt.pos;
                v         = MeshTransforms.ConvertZUpToYUp(v);
                pt.pos    = MeshTransforms.FlipLeftRightCoordSystems(v);
                points[k] = pt;
            }

            Deviation = new DeviationData();
            Deviation.DeviationPoints = points;
            OnGeometryUpdateRequired?.Invoke(this);
        }
        public IEnumerator UpdateGeometryOnMainThread()
        {
            if (Deviation == null)
            {
                yield break;
            }
            if (Deviation.DeviationPoints.Count == 0)
            {
                yield break;
            }
            if (is_disconnected)
            {
                yield break;
            }

            if (internalSO == null)
            {
                internalSO = new GOWrapperSO();
                internalSO.Create(GameObjectFactory.CreateParentGO("toolpath_deviation_so"));
                CC.ActiveScene.AddSceneObject(internalSO);
                internalSO.SetLocalFrame(SO.GetLocalFrame(CoordSpace.SceneCoords), CoordSpace.SceneCoords);
                SOFrameLink link = new SOFrameLink(internalSO, SO);
                CC.ActiveScene.LinkManager.AddLink(link);
            }

            var    settings   = SO.GetSettings();
            double nozzleDiam = settings.Machine.NozzleDiamMM;
            double tolerance  = nozzleDiam * 0.5 + DeviationToleranceMM;

            float layerHeight = (float)settings.LayerHeightMM;
            float ptWidth     = (float)nozzleDiam * 0.5f;

            // probably should just make a mesh for all these...
            int counter = 0;
            int N       = Deviation.DeviationPoints.Count;

            for (int i = 0; i < N; ++i)
            {
                if (is_disconnected)
                {
                    yield break;
                }
                DeviationPt pt          = Deviation.DeviationPoints[i];
                fMaterial   useMaterial = HighDeviationMaterial;
                if (pt.dist < tolerance * 1.5)
                {
                    useMaterial = LowDeviationMaterial;
                }
                //else if (pt.dist < tolerance * 1.2)
                //    useMaterial = LowDeviationMaterial;

                fGameObject go = GameObjectFactory.CreateBoxGO("deviation", ptWidth, layerHeight, ptWidth, useMaterial, true, false);
                go.SetLocalPosition((Vector3f)pt.pos);
                internalSO.AppendNewGO(go, internalSO.RootGameObject, false);
                go.SetLayer(FPlatform.WidgetOverlayLayer);
                PointGOs.Add(go);
                if (counter++ == 10)
                {
                    counter = 0;
                    yield return(null);
                }
            }
        }