public override void DrawViewportWires(IGH_PreviewArgs args)
        {
            if (autoColor)
            {
                gradientList = new System.Drawing.Color[_plan.getCells().Count];

                for (int i = 0; i < gradientList.Length; i++)
                {
                    var multiplier = sunAccess[i];

                    var gColor = new ColorHSL(multiplier, multiplier, 0, multiplier);
                    var rgb    = gColor.ToArgbColor();
                    gradientList[i] = (rgb);
                }
                for (int i = 0; i < rectangles.Count; i++)
                {
                    Rhino.Display.DisplayMaterial mat = new Rhino.Display.DisplayMaterial(gradientList[i]);
                    mat.Shine = 0.25;
                    {
                        var curve = rectangles[i].ToNurbsCurve();
                        var pts   = rectangles[i].ToPolyline();
                        args.Display.DrawPolyline(pts, gradientList[i], 1);
                        var mesh = Mesh.CreateFromPlanarBoundary(curve, Rhino.Geometry.MeshingParameters.FastRenderMesh, 0.01);
                        args.Display.DrawMeshShaded(mesh, mat);
                    }
                }
            }
        }
        private List <Color> GenerateGroupColors(int groupIndex, int groupSize, int groupsCount)
        {
            // Here are want to create a rectangularly shaped matrix to try and maximise contrast
            // Given an area of X, we want to find x/y lengths given an 2:1 ratio
            var ratio  = groupsCount / 2.0;
            var square = Math.Sqrt(ratio);
            var xMax   = (int)Math.Floor(square * 2.0) + 1;
            var yMax   = (int)Math.Floor(square * 1.0);

            // Once we have the lengths we go from the index to the x/y position
            int x;

            if (groupIndex == 0)
            {
                x = 0;
            }
            else
            {
                x = groupIndex % xMax; // Get position on x axis
            }
            int y;

            if (groupIndex == 0)
            {
                y = 0;
            }
            else
            {
                double yPos = groupIndex / xMax;
                y = (int)Math.Floor(yPos);  // Get position on y axis
            }

            //Print("{2}: {0} {1} maxes: {3} {4}", x.ToString(), y.ToString(), groupIndex.ToString(), xMax.ToString(), yMax.ToString());

            // Create a color from within a given range (set bounds to ensure things are relatively bright/distinct)
            var hue        = ColorDistributionInRange(0.0, 1.0, x, xMax); // Not -1 as 0.0 and 1.0 are equivalent
            var saturation = 1.0;                                         // Maximise contrast
            var luminance  =
                ColorDistributionInRange(0.2, 0.6, y, yMax - 1);          // -1 as we want to use the full range or 0.2-0.6
            var groupColorHSL = new ColorHSL(hue, saturation, luminance);

            // Convert to RGB and make a list with a color for each item in the branch
            var groupColorARGB = groupColorHSL.ToArgbColor();
            var groupColors    = Enumerable.Repeat(groupColorARGB, groupSize).ToList();

            return(groupColors);
        }
        /// <summary>
        /// This is the method that actually does the work.
        /// </summary>
        /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param>
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            colors = new List <System.Drawing.Color>();
            pNames = new List <string>();
            pAreas = new List <double>();
            List <Rectangle3d>       rects = new List <Rectangle3d>();
            GH_Structure <GH_Number> pData;
            GH_Structure <GH_Number> pWeights;
            List <Point3d>           points = new List <Point3d>();

            DataTree <double> mod_pData;
            DataTree <double> mod_pWeights;
            string            message = "nothing";
            bool optimized            = false;
            int  numMetrics           = -1;


            DA.GetData(IN_numMetrics, ref numMetrics);
            DA.GetData(IN_reset, ref reset);
            DA.GetData(IN_run, ref run);
            DA.GetData(IN_mode, ref optimized);
            DA.GetDataList(IN_programNames, pNames);
            DA.GetDataList(IN_programAreas, pAreas);
            DA.GetDataTree(IN_programData, out pData);
            DA.GetDataList(IN_programColors, colors);
            DA.GetDataList(IN_pRects, rects);
            DA.GetDataTree(IN_pWeights, out pWeights);
            DA.GetData(IN_resolution, ref _resolution);
            DA.GetData(IN_radMultiplier, ref radiusMultiplier);
            DA.GetData(IN_showSOM, ref showSOM);
            DA.GetData(IN_SOMDisplay, ref display);
            DA.GetData(IN_DisplayLabels, ref displayText);

            if (run)
            {
                isRunning = true;
            }
            else
            {
                isRunning = false;
            }

            if (isRunning)
            {
                ExpireSolution(true);
            }

            var simpleNameTree = new DataTree <string>();

            try
            {
                if (reset || SOM == null)
                {
                    circles = new List <Polyline>();
                    points  = new List <Point3d>();

                    radii        = new List <double>();
                    gradientList = new List <System.Drawing.Color>();

                    for (int i = 0; i < rects.Count; i++)
                    {
                        points.Add(rects[i].Center);
                    }

                    for (int i = 0; i < pAreas.Count; i++)
                    {
                        var rad = Math.Sqrt(pAreas[i] / Math.PI);
                        radii.Add(rad * radiusMultiplier);
                    }

                    mod_pData    = new DataTree <double>();
                    mod_pWeights = new DataTree <double>();


                    for (int i = 0; i < pData.Paths.Count; i++)
                    {
                        var path = pData.get_Branch(i);
                        for (int j = 0; j < path.Count; j++)
                        {
                            var p    = new GH_Path(i);
                            var prog = pData.get_DataItem(p, j).Value;
                            mod_pData.Add(prog, new GH_Path(i));
                        }
                    }
                    for (int i = 0; i < pWeights.Paths.Count; i++)
                    {
                        var path = pWeights.get_Branch(i);
                        for (int j = 0; j < path.Count; j++)
                        {
                            var p      = new GH_Path(i);
                            var weight = pWeights.get_DataItem(p, j).Value;
                            mod_pWeights.Add(weight, new GH_Path(i));
                        }
                    }

                    //DA.SetDataTree(OUT_nodeWeights,mod_pWeights);
                    SOM = new KMap(mod_pData, points, _resolution, mod_pWeights, numMetrics, 0.12, radii, 1.0, maximumIterations);

                    SOM.applyProgramInputs(pNames.Count);
                    SOM.outputNodesXY();
                    reset = false;
                }


                if (SOM.iter < maximumIterations)
                {
                    if (InPreSolve)
                    {
                        Task <SolveResults> task = Task.Run(() => ComputeSOM(SOM), CancelToken);
                        TaskList.Add(task);
                        return;
                    }

                    if (!GetSolveResults(DA, out SolveResults result))
                    {
                        result = ComputeSOM(SOM);
                        SOM    = result.Value;
                    }

                    message = string.Format("Runnning...{0}/{1} iterations", SOM.iter, maximumIterations);
                }
                else
                {
                    message   = "Done.";
                    isRunning = false;
                    run       = false;
                    ClearData();
                }

                if (showSOM)
                {
                    var nL = new List <double>();
                    SOM.nodeWeights.Clear();
                    for (int i = 0; i < SOM.nodeW.BranchCount; i++)
                    {
                        GH_Path path         = SOM.nodeW.Path(i);
                        int     elementCount = SOM.nodeW.Branch(i).Count;
                        double  average      = 0;

                        for (int j = 0; j < elementCount; j++)
                        {
                            average += SOM.nodeW[path, j];
                        }

                        average /= elementCount;

                        nL.Add(average); //average value of all dims of a node
                    }

                    SOM.nodeWeights = nL;

                    Remapper re = new Remapper(SOM.nodeWeights, SOM.nodePoints, pNames, pAreas, _resolution, optimized);


                    var n     = re.nodes;
                    var _tree = re.programTree;


                    ///silly name tree output as requested..
                    for (int i = 0; i < _tree.BranchCount; i++)
                    {
                        simpleNameTree.Add(_tree.Branch(i)[0].name.Split('_')[0], new GH_Path(i));
                    }


                    //'tree' below is the sorted nodes corresponding to each program based on their BMU
                    var tempTree = new DataTree <sNode>();

                    for (int i = 0; i < _tree.BranchCount; i++)
                    {
                        int localBCount = _tree.Branch(i).Count;

                        var orderedBranch = _tree.Branch(i).OrderBy(c => c.multiplierStrength).ToList();
                        tempTree.AddRange(orderedBranch, new GH_Path(i));
                    }

                    SOM.tree.Clear();
                    for (int i = 0; i < tempTree.BranchCount; i++)
                    {
                        var fPath       = tempTree.Path(i);
                        int localBCount = tempTree.Branch(i).Count;

                        for (int j = 0; j < localBCount; j++)
                        {
                            Plane    plane = new Plane(tempTree.Branch(i)[j].pos, Vector3d.ZAxis);
                            Interval inter = new Interval(-_resolution * 0.5, _resolution * 0.5);
                            var      rect  = new Rectangle3d(plane, inter, inter);
                            var      poly  = rect.ToPolyline();
                            //circles.Add(poly);

                            SOM.tree.Add(poly, new GH_Path(fPath));
                        }
                    }

                    //data for visualization

                    var _points = new List <Point3d>();
                    SOM.m_pNames = new List <string>();
                    for (int i = 0; i < n.Count; i++)
                    {
                        var p          = n[i].pos;
                        var name       = n[i].name;
                        var multiplier = n[i].multiplierStrength;
                        _points.Add(p);
                        SOM.m_pNames.Add(name);
                    }


                    //color by gradient colors
                    // for (int i = 0; i < nodeWeights.Count; i++)

                    if (display == 1)
                    {
                        gradientList = new List <System.Drawing.Color>();
                        for (int i = 0; i < n.Count; i++)
                        {
                            var multiplier = n[i].multiplierStrength;
                            var gColor     = new ColorHSL(multiplier, 0, multiplier);

                            var rgb = gColor.ToArgbColor();
                            gradientList.Add(rgb);
                        }
                    }

                    else if (display == 2)
                    {
                        gradientList = new List <System.Drawing.Color>();
                        for (int i = 0; i < n.Count; i++)
                        {
                            var gColor = new ColorHSL(SOM.nodeWeights[i], SOM.nodeWeights[i], SOM.nodeWeights[i], SOM.nodeWeights[i]);

                            var rgb = gColor.ToArgbColor();
                            gradientList.Add(rgb);
                        }
                    }


                    for (int i = 0; i < SOM.m_pNames.Count; i++)
                    {
                        for (int j = 0; j < pNames.Count; j++)
                        {
                            var strippedName = SOM.RemoveNumbersSymbols(SOM.m_pNames[i]);
                            if (strippedName == pNames[j])
                            {
                                SOM.discreteCol.Add(colors[j]);
                            }
                        }
                    }
                    SOM.drawingPolys.Clear();
                    SOM.drawCircles();

                    circles = SOM.drawingPolys;
                }
            }
            catch (Exception e)
            {
                AddRuntimeMessage(GH_RuntimeMessageLevel.Error, e.ToString());
            }

            DA.SetData(OUT_RunFeedback, message);
            DA.SetDataList(OUT_nodeWeights, SOM.nodeWeights);
            DA.SetDataTree(OUT_programTree, SOM.tree);
            DA.SetDataTree(OUT_programNames, simpleNameTree);
        }