Random with Weighted results

Hi All,

I was wondering if anyone knew how to write the statement for a weighted random generator. 

I have a series of polygons that I am changing the colour of using just a simple Random(1,6) which appears to give random results between 1 and 5. I thenuse this to select the colour number. 

What we would like to do is weight the random results a bit to give say more of one colour. 

For example:

colour 1 80%

colour 2 5%

colour 3 5%

colour 4 5%

colour 5 5%

another question would be how to set the seed so you could replicate or fix the outcome so it was repeatable. Maybe then connect this to a slider for testing options. 

Thanks

Wayne

Parents
  • Hi Wayne,

    That's a cool question.

    What I would do in this case is to generate random numbers from 1 to 100 (for 100%). If the random number is from 1 to 80 then I'd assign color 1, 81 through 85 for color 2, etc. In some cases it may make sense to generate a larger range of random numbers and scale them to the target range in the model, e.g. 1 to 1000 and use 1 through 800 for color 1, etc.

    Traditional random number generators are not truly random. The SetRandomSeed(N) function can be used to make the random number results predictably reproducible. For each integer seed N the sequence of "randomly" generated numbers will be the same. This permits to create reproducible results while still allowing to vary the results by changing the random seed. Note that if the SetRandomSeed(N) function call has no dependency to the rest of the GC model, a manual Update Model command may be required to see the effects of a changed seed N reflected in the geometry. If the seed N is set through a slider it may make sense to hook that slider up to some part of the model that will trigger an update of the affected geometry, even if that dependency's only purpose is to force the update and is otherwise ineffective --only indirectly via the random seed and the change in random number sequence.

    I hope this makes sense.

    Good success with your experiments!

         Volker

       

  • Hi Volker,

    That is a great approach.

    I have created a sample file for some tile example.

    I am having an issue with the SetRandomSeed(N) it appears to just return a result that has one colour. 

    I have attached the DGN sample and code below, I have commented out the see at the moment.

    This is my function at the moment:

    function (Polygon InputPoly, int RandomPool, double Ratio1, double Ratio2, double Ratio3, double Ratio4, double Ratio5)
    {

        Polygon TilePoly = {};
        Polygon TilePolyArray = {};
        int TileColour = 1;
       
        for (int i = 0; i < InputPoly.Count; ++i)
        {
             Polygon TilePolylist= {};
            for (int j = 0; j < InputPoly[i].Count; ++j)
               
                {
             //   SetRandomSeed(5);
                int RNumber = Random(1,RandomPool);
     
    //select from the random numbers a weighted colour
     if(RNumber <= (RandomPool*Ratio1))
            {
              TileColour = 1;
            }
     if(RNumber > (RandomPool*Ratio1) && RNumber <= (RandomPool*(Ratio1+Ratio2)))
            {
              TileColour = 2;
            }
     if(RNumber > (RandomPool*(Ratio1+Ratio2)) && RNumber <= (RandomPool*(Ratio1+Ratio2+Ratio3)))
            {
              TileColour = 3;
            }
     if(RNumber > (RandomPool*(Ratio1+Ratio2+Ratio3)) && RNumber <= (RandomPool*(Ratio1+Ratio2+Ratio3+Ratio4)))
            {
              TileColour = 4;
            }
     if(RNumber > (RandomPool*(Ratio1+Ratio2+Ratio3+Ratio4)) && RNumber <= (RandomPool*(Ratio1+Ratio2+Ratio3+Ratio4+Ratio5)))
            {
              TileColour = 5;
            }
                TilePoly = new Polygon();
                TilePoly.ByVertices({InputPoly[i][j].Vertices[0], InputPoly[i][j].Vertices[1], InputPoly[i][j].Vertices[2],InputPoly[i][j].Vertices[3]});
                TilePoly.Color = TileColour;
                TilePolylist.Add(TilePoly);
                        }
               TilePolyArray.Add(TilePolylist);
              
        }
        return TilePolyArray;

    }

    Thanks

    Wayne

    GC_Tiles-small-test.dgn

  • This looks great. If you move SetRandomSeed( ) up outside of the loop in your function, then you'll get a consistent pattern.

       

    Answer Verified By: Wayne Dickerson 

  • Thanks Volker, works perfectly.

    just to finish this off, I am trying to thicken selected colours to a solid.

    I have this script that works on all panels but if I include an "if" statement it breaks down giving me a warning I am doing something that is not allowed.

    "the control expression must not resolve to a single bool value BUGID:1119732476"

    any thoughts on what I did wrong?

    function (Polygon InputPoly, double SolidThickness)
    {
        Solid TileSolid = {};
        Solid TileSolidList = {};
        Solid TileSolidArray = {};
       
        for (int i = 0; i < InputPoly.Count; ++i)
        {
            for (int j = 0; j < InputPoly[i].Count; ++j)
                {
                if (InputPoly[i][j].Color == color(1))
                {
                TileSolid = new Solid();
                TileSolid.OffsetFromClosedCurve(InputPoly[i][j],SolidThickness,0);
                }
                 TileSolidlist.Add(TileSolid);
                }
       TileSolidArray.Add(TileSolidlist);
        }
    return TileSolidArray;
    }
    Thanks
    Wayne
  • Hi Wayne,

    In the conditional color is a type; therefore, color(1) is an unsupported expression. If you used color numbers in your polygon properties, then it will most likely work here to compare InputPoly[i][j].Color directly to that number, e.g. InputPoly[i][j].Color == 1.

    As briefly discussed on the phone, move the declaration Solid TileSolidList = {}; into the outer loop, so that TileSolidList is reset for each iteration of the i-loop and accumulates only one full j-cycle before the next i-loop iteration clears out the list.

    Regards,

        Volker

       

  • Hi Volker,

    Thanks for the identifying the TileSolidList error, I spent some time trying to work out why I was getting additional items. now works perfectly.

    With the Color I changed it to the suggestion above but it returns an error of:

    Exception: Invalid operation

    in the debugger.

    Looking at a watch and the input polygons I drilled down to a target polygon and even though I set it with a colortable number it is listed as an rgb value. (see attached image)

    hence I think the ==1 will probably not work.

    So I tried this

    if (InputPoly[i][j].Color == color(r=38,g=214,b=6))

    this works!!!!

    Excellent.

    Thanks again for your tips

    Wayne

  • Hi All,

    Just as a summary of where this got to. I have attached a DGN file with the script and a sample area of polygons (in an array) that I have randomly coloured with 5 different colours.

    This is then converted into solids by selecting by colour, this gave us 5 solid nodes (one for each colour) I changed the levelname for each of the solid nodes and then exported to a new DGN.

    We did this for a tile on a façade so we can apply a specific material in 5 variations.

    I can see however that you could use the random colour script to randomly colour a polygon façade breakup and then apply slightly different façade panels (via GNT) based on colours.

    To make it a bit more controllable I have locked the Random seed but also given variables to allow you to weight one colour over another. you can see this in the node inputs. Please note I haven't included any checks so you will have to make sure the values add up to 1 (100%). it still works if you break this rule but you will not get a spread of colours.

    If you would like any more info let me know.

    They 2 key scripts are included below.

    Thanks

    Wayne

    Random Polygon Script (with an offset for the tile joint)

    function (Polygon InputPoly, int RandomPool, double Ratio1, double Ratio2, double Ratio3, double Ratio4, double Ratio5, double TileOffSet)
    {

        Polygon TilePoly = {};
        Point CentrePoint = {};
        Polygon TilePolyArray = {};
        int TileColour = 1;
        SetRandomSeed(5);
       
        for (int i = 0; i < InputPoly.Count; ++i)
        {
             Polygon TilePolylist= {};
            for (int j = 0; j < InputPoly[i].Count; ++j)
               
                {
            
                int RNumber = Random(1,RandomPool);
     
    //select from the random numbers a weighted colour
     if(RNumber <= (RandomPool*Ratio1))
            {
              TileColour = 1;
            }
     if(RNumber > (RandomPool*Ratio1) && RNumber <= (RandomPool*(Ratio1+Ratio2)))
            {
              TileColour = 2;
     
            }
     if(RNumber > (RandomPool*(Ratio1+Ratio2)) && RNumber <= (RandomPool*(Ratio1+Ratio2+Ratio3)))
            {
              TileColour = 3;
     
            }
     if(RNumber > (RandomPool*(Ratio1+Ratio2+Ratio3)) && RNumber <= (RandomPool*(Ratio1+Ratio2+Ratio3+Ratio4)))
            {
              TileColour = 4;
     
            }
     if(RNumber > (RandomPool*(Ratio1+Ratio2+Ratio3+Ratio4)) && RNumber <= (RandomPool*(Ratio1+Ratio2+Ratio3+Ratio4+Ratio5)))
            {
              TileColour = 5;
     
            }
     
                TilePoly = new Polygon();
                CentrePoint = new Point();
                CentrePoint.CentroidOfSet(InputPoly[i][j].Vertices);
                TilePoly.Offset(InputPoly[i][j],OffsetMethod.ByDistance,CentrePoint,TileOffSet);
                TilePoly.Color = TileColour;
                TilePolylist.Add(TilePoly);
                        }
               TilePolyArray.Add(TilePolylist);
              
        }
        return TilePolyArray;
    }

    New Solid select by colour

    function (Polygon InputPoly, double SolidThickness, int RedValue, int GreenValue, int BlueValue)
    {
        Solid TileSolid = {};
        Solid TileSolidArray = {};
       
        for (int i = 0; i < InputPoly.Count; ++i)
        {
            Solid TileSolidList = {};
            for (int j = 0; j < InputPoly[i].Count; ++j)
                {
                if (InputPoly[i][j].Color == color(r=RedValue,g=GreenValue,b=BlueValue))
                          {
                           TileSolid = new Solid();
                           TileSolid.OffsetFromClosedCurve(InputPoly[i][j],SolidThickness,0); 
                          }
                          else
                          {
                          TileSolid = {};
                          }         
                 TileSolidList.Add(TileSolid);
                }
       TileSolidArray.Add(TileSolidList);
        }

    return TileSolidArray;

    }

    7380.GC_Tiles-small-test.dgn

    Answer Verified By: Mueller 

Reply
  • Hi All,

    Just as a summary of where this got to. I have attached a DGN file with the script and a sample area of polygons (in an array) that I have randomly coloured with 5 different colours.

    This is then converted into solids by selecting by colour, this gave us 5 solid nodes (one for each colour) I changed the levelname for each of the solid nodes and then exported to a new DGN.

    We did this for a tile on a façade so we can apply a specific material in 5 variations.

    I can see however that you could use the random colour script to randomly colour a polygon façade breakup and then apply slightly different façade panels (via GNT) based on colours.

    To make it a bit more controllable I have locked the Random seed but also given variables to allow you to weight one colour over another. you can see this in the node inputs. Please note I haven't included any checks so you will have to make sure the values add up to 1 (100%). it still works if you break this rule but you will not get a spread of colours.

    If you would like any more info let me know.

    They 2 key scripts are included below.

    Thanks

    Wayne

    Random Polygon Script (with an offset for the tile joint)

    function (Polygon InputPoly, int RandomPool, double Ratio1, double Ratio2, double Ratio3, double Ratio4, double Ratio5, double TileOffSet)
    {

        Polygon TilePoly = {};
        Point CentrePoint = {};
        Polygon TilePolyArray = {};
        int TileColour = 1;
        SetRandomSeed(5);
       
        for (int i = 0; i < InputPoly.Count; ++i)
        {
             Polygon TilePolylist= {};
            for (int j = 0; j < InputPoly[i].Count; ++j)
               
                {
            
                int RNumber = Random(1,RandomPool);
     
    //select from the random numbers a weighted colour
     if(RNumber <= (RandomPool*Ratio1))
            {
              TileColour = 1;
            }
     if(RNumber > (RandomPool*Ratio1) && RNumber <= (RandomPool*(Ratio1+Ratio2)))
            {
              TileColour = 2;
     
            }
     if(RNumber > (RandomPool*(Ratio1+Ratio2)) && RNumber <= (RandomPool*(Ratio1+Ratio2+Ratio3)))
            {
              TileColour = 3;
     
            }
     if(RNumber > (RandomPool*(Ratio1+Ratio2+Ratio3)) && RNumber <= (RandomPool*(Ratio1+Ratio2+Ratio3+Ratio4)))
            {
              TileColour = 4;
     
            }
     if(RNumber > (RandomPool*(Ratio1+Ratio2+Ratio3+Ratio4)) && RNumber <= (RandomPool*(Ratio1+Ratio2+Ratio3+Ratio4+Ratio5)))
            {
              TileColour = 5;
     
            }
     
                TilePoly = new Polygon();
                CentrePoint = new Point();
                CentrePoint.CentroidOfSet(InputPoly[i][j].Vertices);
                TilePoly.Offset(InputPoly[i][j],OffsetMethod.ByDistance,CentrePoint,TileOffSet);
                TilePoly.Color = TileColour;
                TilePolylist.Add(TilePoly);
                        }
               TilePolyArray.Add(TilePolylist);
              
        }
        return TilePolyArray;
    }

    New Solid select by colour

    function (Polygon InputPoly, double SolidThickness, int RedValue, int GreenValue, int BlueValue)
    {
        Solid TileSolid = {};
        Solid TileSolidArray = {};
       
        for (int i = 0; i < InputPoly.Count; ++i)
        {
            Solid TileSolidList = {};
            for (int j = 0; j < InputPoly[i].Count; ++j)
                {
                if (InputPoly[i][j].Color == color(r=RedValue,g=GreenValue,b=BlueValue))
                          {
                           TileSolid = new Solid();
                           TileSolid.OffsetFromClosedCurve(InputPoly[i][j],SolidThickness,0); 
                          }
                          else
                          {
                          TileSolid = {};
                          }         
                 TileSolidList.Add(TileSolid);
                }
       TileSolidArray.Add(TileSolidList);
        }

    return TileSolidArray;

    }

    7380.GC_Tiles-small-test.dgn

    Answer Verified By: Mueller 

Children
No Data