Missing Nulls! Flip Data Matrix Custom C# output Error

I am working on creating custom Flip Data Matrix Function, which will divide an input tree into subTree of similar path indices i.e; {0;} as one tree and {1;} as another and so on. I tested the Custom flip data function on one of the subTree and it works. But when I iterate the whole function over the subTrees it fails to generate the nulls. Here is the snippet from the GH-Canvas.

Here is the Code of the complete process of Split tree & Flip Data Matrix

using System;
using System.Collections;
using System.Collections.Generic;

using Rhino;
using Rhino.Geometry;

using Grasshopper;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Data;
using Grasshopper.Kernel.Types;



/// <summary>
/// This class will be instantiated on demand by the Script component.
/// </summary>
public class Script_Instance : GH_ScriptInstance
{
#region Utility functions
  /// <summary>Print a String to the [Out] Parameter of the Script component.</summary>
  /// <param name="text">String to print.</param>
  private void Print(string text) { /* Implementation hidden. */ }
  /// <summary>Print a formatted String to the [Out] Parameter of the Script component.</summary>
  /// <param name="format">String format.</param>
  /// <param name="args">Formatting parameters.</param>
  private void Print(string format, params object[] args) { /* Implementation hidden. */ }
  /// <summary>Print useful information about an object instance to the [Out] Parameter of the Script component. </summary>
  /// <param name="obj">Object instance to parse.</param>
  private void Reflect(object obj) { /* Implementation hidden. */ }
  /// <summary>Print the signatures of all the overloads of a specific method to the [Out] Parameter of the Script component. </summary>
  /// <param name="obj">Object instance to parse.</param>
  private void Reflect(object obj, string method_name) { /* Implementation hidden. */ }
#endregion

#region Members
  /// <summary>Gets the current Rhino document.</summary>
  private readonly RhinoDoc RhinoDocument;
  /// <summary>Gets the Grasshopper document that owns this script.</summary>
  private readonly GH_Document GrasshopperDocument;
  /// <summary>Gets the Grasshopper script component that owns this script.</summary>
  private readonly IGH_Component Component;
  /// <summary>
  /// Gets the current iteration count. The first call to RunScript() is associated with Iteration==0.
  /// Any subsequent call within the same solution will increment the Iteration count.
  /// </summary>
  private readonly int Iteration;
#endregion

  /// <summary>
  /// This procedure contains the user code. Input parameters are provided as regular arguments,
  /// Output parameters as ref arguments. You don't have to assign output parameters,
  /// they will have a default value.
  /// </summary>
  private void RunScript(DataTree<Point3d> pts, ref object A)
  {
    GH_Structure<GH_Point> sortedData = new GH_Structure<GH_Point>();
    GH_Structure<GH_Point> outData = new GH_Structure<GH_Point>();
    List<int> pathIndices = new List<int>();
    DataTree<int> pathTree = new DataTree<int>();
    GH_Structure<GH_Point> ghStructure = new GH_Structure<GH_Point>();
    GH_Structure<GH_Point> ghStructureOut = new GH_Structure<GH_Point>();
    DataTree<GH_Point> ptsShow = new DataTree<GH_Point>();



    for(int i = 0; i < pts.BranchCount;i++)
    {
      var branch = pts.Branch(i);
      var path = pts.Path(i);

      for(int j = 0; j < branch.Count;j++)
      {
        GH_Point myPts = new GH_Point(branch[j]);
        sortedData.Append(myPts, path);
      }
    }


    for (int a = 0; a < pts.BranchCount;a++)
    {
      var branches = pts.Branches[a];
      var paths = pts.Paths;
      for (int b = 0; b < paths.Count; b++)
      {
        if(paths[b].Indices[0] == a)
        {
          pathIndices.Add(a);
        }
      }
    }
    var uniqueItems = new HashSet<int>(pathIndices);

    DataTree<GH_Path> sortedPaths = new DataTree<GH_Path>();

    for (int j = 0; j < uniqueItems.Count; j++)
    {
      for(int i = 0; i < pts.BranchCount;i++)
      {
        var path = pts.Paths[i];
        if(j == path.Indices[0])
        {
          sortedPaths.Add(path, new GH_Path(j));
        }
      }
    }

    for (int a = 0; a < sortedPaths.BranchCount;a++)
    {
      var branches = sortedPaths.Branch(a);


      for (int b = 0; b < branches.Count; b++)
      {
        int i1 = 0, i2 = 0;
        if (branches[b].Indices[0] == a)
        {
          sortedData.PathIndex(branches[b], ref i1, ref i2);
          outData.AppendRange(sortedData.Branches[i1], branches[b]);
        }

        //Flip Data Matrix Function Runs here inside the Loop
        int length = outData.Paths[0].Length;
        int num1 = outData.PathCount - 1;
        for (int index = 1; index <= num1; ++index)
        {
          if (outData.Paths[index].Length != length)
          {
            Component.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "All paths must have the same length");
            return;
          }
        }
        int index1 = -1;
        if (outData.PathCount == 1)
        {
          index1 = length - 1;
        }
        else
        {
          int num2 = outData.PathCount - 1;
          for (int index2 = 1; index2 <= num2; ++index2)
          {
            int num3 = length - 1;
            for (int index3 = 0; index3 <= num3; ++index3)
            {
              if (outData.Paths[0][index3] != outData.Paths[index2][index3])
              {
                if (index1 < 0 || index1 == index3)
                {
                  index1 = index3;
                }
                else
                {
                  Component.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "All paths may only differ at a single Position");
                  return;
                }
              }
            }
          }
        }

        int index4 = 0;
        do
        {
          List<GH_Point> ghGooList = new List<GH_Point>();
          GH_Path path = new GH_Path(outData.Paths[0]);
          path[index1] = index4;
          bool flag = false;
          int num2 = outData.PathCount - 1;
          for (int index2 = 0; index2 <= num2; ++index2)
          {
            if (index4 < outData.Branches[index2].Count)
            {
              ghGooList.Add(outData.Branches[index2][index4]);
              flag = true;
            }
            else
              ghGooList.Add(null);
          }


          if (flag)
          {
            ghStructure.AppendRange(ghGooList, path);

            ++index4;
          }
          else
            break;
        }
        while (index4 <= int.MaxValue);

        //Flip Data Matrix Function Ends Here
        outData.Clear();
      }

      ghStructureOut.MergeStructure(ghStructure);
      ghStructure.Clear();
    }


    for (int i = 0; i < ghStructureOut.PathCount;i++)
    {
      var branch = ghStructureOut.Branches[i];
      var path = ghStructureOut.Paths[i];
      ptsShow.AddRange(branch, path);
    }
    A = ptsShow;



  }

  // <Custom additional code> 

  // </Custom additional code> 
}

Also Attached is the GH Script. Here : SubTree & FlipDataMatrix-V2.gh (18.6 KB)

Anyone can you help, what could be wrong?

Point3d is a structure and can never be null. You will not be able to detect nulls if your input hint is a valuetype.

You can try using object hints instead, but you may not be able to do this at all in a script component.

Hi @DavidRutten Thanks for the clarification. When you say its not possible with Script component, you mean that I should try making plugin component using VS?

Oh, but if you see that first component, which says " Flip Matrix Function" It is implementing the same code but runs on only one sub-tree, there it does generate ‘nulls’. Point3d definitely doesnot allow nulls, but as I implemented GH_Point, it did allow to store nulls there, as you can see in the output. Any thoughts on that?

How about Point3d.Unset? Or another property like that that I do not recall?

Yes. Even when you set the input hint to System.Object you won’t get any nulls. Try this script:

  private void RunScript(DataTree<System.Object> pts, ref object A)
  {
    int nullCount = 0;
    int itemCount = 0;

    foreach (var branch in pts.Branches)
      for (int i = 0; i < branch.Count; i++)
        if (branch[i] == null)
          nullCount++;
        else
          itemCount++;

    A = string.Format("Tree contains {0} values and {1} nulls.", itemCount, nullCount);
  }

The output is "Tree contains 347 values and 0 nulls."

Hi @DavidRutten, This I am aware of counting and checking for nulls & items.
I guess you misunderstood what I meant in the post. I have been trying to create custom script to flip Data Matrix. the Current “Flip Data Matrix” component inside Grasshopper, only works for Data tree with only one different locus point. But in my Case, I have a data Tree that has multiple locii based on the {0;}, {1;}, and so on which can be seen as I did first with the grasshopper components the section inside the black rectangle . What I am trying to do here is to create “Sub Tree” for each of the Path masks i.e; {0;*} as a separate tree and iterate to perform the flip Matrix function as you can see in the first post here:

The problem I have is that the output Data Structure is missing nulls, which it should have generated as shown in “Panel 3”.
What could be the problem?
If I extract only the partial code from the script and run it as separate component it works, which is shown as output in “Panel 2”.
I hope I explained it better than last time. :wink: .