Na sequência da apresentação do artigo Measuring Urban Renewal: a dual kernel density estimation to assess the intensity of building renovation no 4th International Symposium Formal Methods in Architecture 2018 no Porto, decidi partilhar as ferramentas que desenvolvi para realizar estimativas de densidade kernel (KDE) no Grasshopper para Rhinoceros. Estimativa de Densidade Kernel ou Kernel Density Estimation (KDE) é um método de estimar a função contínua de densidades de probabilidade com base em dados aleatórios. A estimativa é realizada sobre uma amostra finita dos dados. Matthew Conlen explica de uma forma simples e interactiva (em inglês) como a escolha da função kernel ou da janela da análise influencia a forma da função de estimativa. Para uma introdução mais aprofundada, Yen-Chi Chen escreveu o tutorial Kernel Density Estimation and Recent Advances disponível em https://arxiv.org/abs/1704.03924.

A definição no Grasshopper

A imagem acima é um exemplo de uma estimativa KDE. Para produzir uma estimativa com o Grasshopper são necessários dois inputs: uma superfície e os pontos a analisar, a amostra. O algoritmo calcula uma estimativa para cada vértice da mesh. A definição da estimativa é determinada pelo número de vértices da mesh, e o componente Custom Mesh Settings subdivide a mesh em polígonos com arestas menores do que a definição. Consequentemente, quanto mais vértices tiver maior será o tempo de computação necessário para calcular todas as estimativas. Portanto, deve-se começar com um valor alto na definição, reduzindo-o até a qualidade ser aceitável. O segundo parâmetro é a largura da janela. É o factor de suavização da estimativa e determina o raio da função kernel (Epanechnikov no nosso caso). Valores maiores irão suavizar mais as estimativas, enquanto que valores mais baixos vão captar mais ruído local. A escala é um parâmetro opcional, útil para visualizações tridimensionais da estimativa.

Código C#

O código foi desenvolvido para o componente C# do Grasshopper. A primeira secção deverá ser colocada no primeiro espaço do editor, e a segunda secção no último espaço do editor. O cabeçalho (private void…) é disponibilizado para clarificar os inputs que são esperados pelo script. Estes devem ser preenchidos no componente C# da forma normal. Os inputs devem ser nomeados correctamente, os tipos devem ser definidos para o tipo de objecto correspondente (mesh, Point3d, double respectivamente). O input dos pontos deves ser definido como list access.

private void RunScript(Mesh mesh, List<Point3d> pts, double window, ref object A)
  {
    //beginning of the first section
    var rtnlist = new List<double>();
    for(int i = 0; i < mesh.Vertices.Count; i++)
    {
      double tempval = 0.0;
      double kde = 0.0;
      Point3d v = new Point3d(mesh.Vertices[i]);
      for(int j = pts.Count - 1; j > 0; j--)
      {
        var pt = pts[j];
        Vector3d vt = new Vector3d(v - pt);
        tempval += kernel(vt / window);
      }
      kde = 1 / (pts.Count * window * window) * tempval;
      rtnlist.Add(kde);
    }
    A = rtnlist;
   //end of first section
  }

//beginning of the second section
public double kernel(Vector3d input)
  {
    //Epanechnikov Kernel
    double k = Vector3d.Multiply(input, input);
    if ( k < 1)
    {
      return 3 * (1 / Math.PI) * (1 - k) * (1 - k);
    }else{
      return 0;
    }
  }

O último passo é colorir a mesh de acordo com uma escala de cores baseada nas estimativas. Opcionalmente, é possível escalar a mesh para a melhor representar em 3D.


Leave a Reply

O seu endereço de email não será publicado. Campos obrigatórios marcados com *

seven + twelve =


@