Интерполяция 2d данных, которые кусочно постоянны на гранях - PullRequest
3 голосов
/ 20 февраля 2010

У меня неправильная сетка, которая описывается двумя переменными: массив граней, в котором хранятся индексы вершин, составляющих каждую грань, и массив вершин, в котором хранятся координаты каждой вершины. У меня также есть функция, которая предполагается кусочно постоянной для каждой грани, и она сохраняется в виде массива значений для грани.

Я ищу способ построить функцию f из этих данных. Что-то вроде следующего:

faces = [[0,1,2], [1,2,3], [2,3,4] ...]
verts = [[0,0], [0,1], [1,0], [1,1],....]
vals = [0.0, 1.0, 0.5, 3.0,....]

f = interpolate(faces, verts, vals)

f(0.2, 0.2) = 0.0 # point inside face [0,1,2]
f(0.6, 0.6) = 1.0 # point inside face [1,2,3]

Ручной способ оценки f(x,y) состоит в том, чтобы найти соответствующее лицо, в котором лежит точка x,y, и вернуть значение, которое хранится на этом лице. Есть ли функция, которая уже реализует это в Scipy (или в Matlab)?

Ответы [ 5 ]

1 голос
/ 08 марта 2010

В MATLAB нет встроенной функции, которая будет делать то, что вы хотите. Скорее всего, вы могли бы построить свой собственный алгоритм, используя функцию INPOLYGON как , предложенную Джонасом , но вы можете самостоятельно создать более быструю реализацию, используя некоторые стандартные алгоритмы для определения, находится ли точка в пределах полигон.

Некоторое время назад я написал свой собственный код для нахождения точек пересечения между отрезком и набором треугольных поверхностей в 3-D и обнаружил, что эта ссылка для софтсерфера наиболее полезна для реализации. алгоритм. Мой случай был более сложным, чем ваш. Поскольку вы работаете в 2D, вы можете игнорировать первый раздел ссылки о поиске точки, где отрезок пересекает плоскость треугольника.

Я включил упрощенную версию моего кода MATLAB ниже для вас, чтобы использовать. Функция interpolate примет ваши матрицы faces, vertices и values в качестве входных данных и вернет дескриптор функции f, который можно оценить в заданной точке (x, y), чтобы получить кусочное значение в пределах ограничивающий треугольник. Вот несколько особенностей этого кода:

  • Обработка, которая будет выполняться при оценке f, содержится во вложенной функции evaluate_function. Эта функция имеет доступ к другим переменным в interpolate, поэтому ряд переменных, необходимых для теста в треугольнике, предварительно вычисляется, так что evaluate_function выполняется максимально быстро.
  • В тех случаях, когда у вас много треугольников, проверка того, находится ли ваша точка внутри, может оказаться дорогостоящей. Следовательно, код сначала находит треугольники, которые находятся в пределах заданного радиуса (т.е. длины самого длинного участка треугольника) от вашей точки. Только эти соседние треугольники проверяются, чтобы определить, находится ли точка внутри них.
  • Если точка не попадает в какую-либо треугольную область, значение NaN возвращается f.

Есть некоторые вещи, которые не включены в код, которые вы можете добавить в зависимости от того, для чего вы его используете:

  • Проверка ввода: В настоящее время в коде предполагается, что faces является матрицей N-3, vertices является матрицей M-2, а values является вектором длины N , Возможно, вы захотите добавить проверку ошибок, чтобы убедиться, что входные данные соответствуют этим требованиям, и выдать ошибку, указывающую, когда один или несколько из них неверны.
  • Проверка вырожденного треугольника: Возможно, что один или несколько треугольников, определенных вашими входами faces и vertices, могут быть вырожденными (т.е. они могут иметь площадь 0). Это происходит, когда две или более вершин треугольников являются одной и той же точной точкой, или когда все три вершины треугольника лежат на одной прямой. Вы, вероятно, захотите добавить проверку, которая будет игнорировать такие треугольники, когда дело доходит до оценки f.
  • Обработка краевых случаев: Возможно, что точка может оказаться на краю двух или более треугольных областей. Поэтому вам нужно будет решить, какое значение примет точка (то есть наибольшее из номиналов, среднее значение номиналов и т. Д.). Для таких случаев, как этот, приведенный ниже код автоматически выберет значение лица, которое ближе к началу списка лиц в вашей переменной faces.

Наконец, вот код:

function f = interpolate(faces,vertices,values)

  %# Precompute some data (helps increase speed):

  triVertex = vertices(faces(:,2),:);              %# Triangles main vertices
  triLegLeft = vertices(faces(:,1),:)-triVertex;   %# Triangles left legs
  triLegRight = vertices(faces(:,3),:)-triVertex;  %# Triangles right legs
  C1 = sum(triLegLeft.*triLegRight,2);  %# Dot product of legs
  C2 = sum(triLegLeft.^2,2);            %# Squared length of left leg
  C3 = sum(triLegRight.^2,2);           %# Squared length of right leg
  triBoundary = max(C2,C3);             %# Squared radius of triangle boundary
  scale = C1.^2-C2.*C3;
  C1 = C1./scale;
  C2 = C2./scale;
  C3 = C3./scale;

  %# Return a function handle to the nested function:

  f = @evaluate_function;

  %# The nested evaluation function:

  function val = evaluate_function(x,y)

    w = [x-triVertex(:,1) y-triVertex(:,2)];
    nearIndex = find(sum(w.^2,2) <= triBoundary);  %# Find nearby triangles
    if isempty(nearIndex)
      val = NaN;           %# Return NaN if no triangles are nearby
      return
    end
    w = w(nearIndex,:);
    wdotu = sum(w.*triLegLeft(nearIndex,:),2);
    wdotv = sum(w.*triLegRight(nearIndex,:),2);
    C = C1(nearIndex);
    s = C.*wdotv-C3(nearIndex).*wdotu;
    t = C.*wdotu-C2(nearIndex).*wdotv;
    inIndex = find((s >= 0) & (t >= 0) & (s+t <= 1),1);
    if isempty(inIndex)
      val = NaN;         %# Return NaN if point is outside all triangles
    else
      val = values(nearIndex(inIndex));
    end

  end

end
1 голос
/ 07 марта 2010

Взгляните на matplotlib.delaunay.interpolate, который является хорошо документированной оболочкой для кода C.
(Однако class LinearInterpolator там говорит «В настоящее время для интерполяции поддерживаются только правильные прямоугольные сетки.»)

1 голос
/ 20 февраля 2010

вы можете использовать модуль bridge CGAL-python ; Если я правильно помню, CGAL предоставляет функциональность для поиска треугольников. Это, вероятно, работает наиболее эффективно, если вы построите триангуляцию постепенно, используя их встроенное представление. Для быстрого и грязного вы можете просто найти ближайшую вершину сетки к точке запроса, либо по диаграмме Вороного (функциональность для этого в Matlab невелика), либо для одного запроса вычислить все расстояния и нахождение минимума, затем ищите все треугольники с этой вершиной.

1 голос
/ 20 февраля 2010

Matlab имеет встроенную функцию inpolygon , которая позволяет вам проверить, находитесь ли вы внутри треугольника. Я не знаю функции, которая бы определяла, внутри какого лица вы находитесь.

Если бы вы написали такую ​​функцию, я бы сначала проверил, к какой вершине ваша точка ближе всего, а затем оценил бы inpolygon для всех граней, которые разделяют вершину, пока вы не найдете соответствие. Это должно быть достаточно быстро.

1 голос
/ 20 февраля 2010

Для меня это не так похоже на интерполяцию, как нахождение треугольной грани, к которой относится точка. Проверьте этот сайт на способ проверить каждую треугольную грань. Ваша функция просто определит, какая грань находится внутри, и вернет соответствующее значение. Конечно, если у вас много граней или вы делаете это много, вы захотите найти способы оптимизировать это (сохранить самые дальние точки + и - для каждого треугольника в направлениях x и y и сохранить например, с лицом. Если точка не находится внутри этой ограничительной рамки, то вы также можете не проверять, находится ли она внутри треугольника).

Я действительно сомневаюсь, что вы найдете что-то встроенное в Matlab или scipy, чтобы делать то, что вы хотите, но я могу ошибаться.

...