Получить площадь поверхности многогранника (3D-объекта)

У меня есть трехмерная поверхность (подумайте о плоскости xy). Самолет может быть наклонным. (подумайте о дороге с уклоном).

Имея список трехмерных координат, определяющих поверхность (Point3D1X, Point3D1Y, Point3D1Z, Point3D12X, Point3D2Y, Point3D2Z, Point3D3X, Point3D3Y, Point3D3Z и т. Д.), Как рассчитать площадь поверхности?

Обратите внимание, что мой вопрос здесь аналогичен поиску области в 2D-плоскости. В 2D-плоскости у нас есть список точек, определяющий многоугольник, и с помощью этого списка точек мы можем найти площадь многоугольника. Теперь предположим, что все эти точки имеют z значения таким образом, что они приподняты в 3D, чтобы сформировать поверхность. Мой вопрос в том, как найти площадь этой трехмерной поверхности?


person Graviton    schedule 28.02.2010    source источник
comment
Самолет имеет бесконечную площадь. Может ты не про самолет имел в виду?   -  person John Saunders    schedule 28.02.2010
comment
Самолеты вообще бесконечны по площади. Вам нужно будет лучше определить свою форму, чтобы определить область.   -  person Gabe    schedule 28.02.2010
comment
@John, я имею в виду ограниченную плоскость с как минимум 3 точками, которые ограничивают ее площадь, правильная ли терминология - поверхность?   -  person Graviton    schedule 28.02.2010
comment
Похоже, вам нужно найти площадь выпуклой оболочки нескольких точек на плоскости.   -  person Gabe    schedule 28.02.2010
comment
Вы имеете в виду, что у вас есть поверхность, которая содержится в плоскости в трехмерном пространстве, или это трехмерная поверхность, для которой у вас есть параметризация?   -  person jmbr    schedule 28.02.2010
comment
@jmbr, параметризация есть только у 3D линий, у поверхности нет. Я имею в виду, что у меня есть поверхность, которая находится в плоскости (которая может быть наклонной)   -  person Graviton    schedule 28.02.2010
comment
Это может помочь softsurfer.com/Archive/algorithm_0101/algorithm_0101.htm   -  person stacker    schedule 28.02.2010
comment
@Ngu Soon Hui: поверхности действительно имеют параметризацию (см. Книгу по дифференциальной геометрии).   -  person jmbr    schedule 28.02.2010
comment
Ваши точки определяют многоугольник, или могут быть точки посередине, которые не являются вершинами формы?   -  person Gabe    schedule 28.02.2010
comment
@gabe: мои точки определяют многоугольник   -  person Graviton    schedule 28.02.2010
comment
Вы хотите, чтобы ваша область находилась в локальном пространстве или на экране? - Я предполагаю первое   -  person zebrabox    schedule 28.02.2010
comment
@zebrabox, в чем разница? А что они означают?   -  person Graviton    schedule 28.02.2010


Ответы (7)


Поскольку вы говорите, что это многогранник, ссылка укладчика (http://softsurfer.com/Archive/algorithm_0101/algorithm_0101.htm).

Вот мой примерный перевод кода C на C # для вашей ситуации:

// NOTE: The original code contained the following notice:
// ---------------------------------------
// Copyright 2000 softSurfer, 2012 Dan Sunday
// This code may be freely used and modified for any purpose
// providing that this copyright notice is included with it.
// iSurfer.org makes no warranty for this code, and cannot be held
// liable for any real or imagined damage resulting from its use.
// Users of this code must verify correctness for their application.
// ---------------------------------------
// area3D_Polygon(): computes the area of a 3D planar polygon
//    Input:  int n = the number of vertices in the polygon
//            Point[] V = an array of n+2 vertices in a plane
//                       with V[n]=V[0] and V[n+1]=V[1]
//            Point N = unit normal vector of the polygon's plane
//    Return: the (float) area of the polygon
static float
area3D_Polygon( int n, Point3D[] V, Point3D N )
{
    float area = 0;
    float an, ax, ay, az;  // abs value of normal and its coords
    int   coord;           // coord to ignore: 1=x, 2=y, 3=z
    int   i, j, k;         // loop indices

    // select largest abs coordinate to ignore for projection
    ax = (N.x>0 ? N.x : -N.x);     // abs x-coord
    ay = (N.y>0 ? N.y : -N.y);     // abs y-coord
    az = (N.z>0 ? N.z : -N.z);     // abs z-coord

    coord = 3;                     // ignore z-coord
    if (ax > ay) {
        if (ax > az) coord = 1;    // ignore x-coord
    }
    else if (ay > az) coord = 2;   // ignore y-coord

    // compute area of the 2D projection
    for (i=1, j=2, k=0; i<=n; i++, j++, k++)
        switch (coord) {
        case 1:
            area += (V[i].y * (V[j].z - V[k].z));
            continue;
        case 2:
            area += (V[i].x * (V[j].z - V[k].z));
            continue;
        case 3:
            area += (V[i].x * (V[j].y - V[k].y));
            continue;
        }

    // scale to get area before projection
    an = Math.Sqrt( ax*ax + ay*ay + az*az);  // length of normal vector
    switch (coord) {
    case 1:
        area *= (an / (2*ax));
        break;
    case 2:
        area *= (an / (2*ay));
        break;
    case 3:
        area *= (an / (2*az));
        break;
    }
    return area;
}
person Gabe    schedule 28.02.2010
comment
Многогранник * (многоугольник 2D) - person Albert Renshaw; 23.05.2013

Я проголосовал за несколько ответы, которые я считаю правильными. Но я думаю, что самый простой способ сделать это - независимо от того, в 2D он или в 3D, - использовать следующую формулу:

area = sum(V(i+1) × V(i))/2;

Где × - это векторный крест.

Код для этого:

    public double Area(List<Point3D> PtList)
    {

        int nPts = PtList.Count;
        Point3D a;
        int j = 0;

        for (int i = 0; i < nPts; ++i)
        {
            j = (i + 1) % nPts;
            a += Point3D.Cross(PtList[i], PtList[j]);
        }
        a /= 2;
        return Point3D.Distance(a,default(Point3D));
    }

    public static Point3D Cross(Point3D v0, Point3D v1)
    {
        return new Point3D(v0.Y * v1.Z - v0.Z * v1.Y,
            v0.Z * v1.X - v0.X * v1.Z,
            v0.X * v1.Y - v0.Y * v1.X);
    }

Обратите внимание, что решение не зависит от проекции на плоскость x, что я считаю неуклюжим.

Что вы думаете?

person Graviton    schedule 28.02.2010
comment
Другие решения (например, я опубликовал) выполняют меньше математических операций (1 умножение, 1 вычитание) на точку. Ваш делает 6 умножений и 3 вычитания за очко. Если у вас не так много очков или вам не нужно делать это достаточно часто, используйте способ, который кажется более простым. В противном случае, если один достаточно быстр, чтобы заметить разницу, используйте более быстрый. - person Gabe; 28.02.2010
comment
@gabe: Предложенное вами решение требует проекции, что мне не нравится. В противном случае это хороший вариант. - person Graviton; 28.02.2010
comment
@Graviton: Вы уверены, что это правильно? Я считаю, что это неверно в общем случае. Вы суммируете площадь каждого треугольника по списку точек. Вы полагаете, что этот список точек на самом деле представляет собой выпуклый многоугольник? В любом случае я не понимаю, как это может привести к получению правильной области поверхности, поскольку (1) у вас будут перекрывающиеся треугольники и (2) вы пропустите области. - person Chris; 07.12.2012
comment
Если вы предполагаете, что упорядоченный список точек приводит к выпуклому многоугольнику, я предполагаю, что вы захотите правильно выполнить триангуляцию - в этом случае не следует использовать PtList [i], PtList [j], а оставить один (например, первый) точечная константа. Это означает: вам не нужно использовать i, и вычисление локальной области будет выглядеть так: Point3D.Cross (PtList [0], PtList [j]); - person Chris; 07.12.2012
comment
@Chris, это прямое расширение формулы 2D площади. А в 2D эквивалентной формуле все равно, выпуклый вы или вогнутый. - person Graviton; 07.12.2012

Вы имеете в виду Площадь трехмерных плоских многоугольников?

  1. http://softsurfer.com/Archive/algorithm_0101/algorithm_0101.htm
  2. http://local.wasp.uwa.edu.au/%7Epbourke/geometry/area3d/
  3. http://thebuildingcoder.typepad.com/blog/2008/12/3d-polygon-areas.html
person Pratik Deoghare    schedule 28.02.2010

Я не знаю, как оптимизировать этот метод (я раньше не делал этого в коде), но математический подход к нему состоит в том, чтобы разделить вашу фигуру на треугольники, площадь которых затем легко вычисляется и суммируется. (Помните: площадь треугольника равна ширине * высоте * 0,5 - вам нужно рассчитать высоту непрямых треугольников.)

Выполнение этого в 3D обычно означает, что на каждом этапе требуется еще один расчет. Например, в 2D расстояние между двумя точками (длина стороны вашей фигуры) рассчитывается примерно так (псевдокод, потому что у меня нет VS на этой машине):

double DistanceBetween(Point a, Point b)
{
   double dx = a.x - b.x;
   double dy = a.y - b.y;
   return SquareRoot(dx*dx + dy*dy);
}

В трех измерениях это становится:

double DistanceBetween(Point3d a, Point3d b)
{
   double dx = a.x - b.x;
   double dy = a.y - b.y;
   double dz = a.z - b.z;
   return SquareRoot(dx*dx + dy*dy + dz*dz);
}

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

person Dan Puzey    schedule 28.02.2010

Другое решение, которое не потребует от вас создания сетки из многоугольников, - это сделать контурный интеграл по периметру. Вы используете теорему Грина для преобразования интеграла площади в контурный интеграл, а затем используете что-то простое, например квадратура Гаусса для интегрирования и суммирования каждого вклада. У вас обязательно должно быть определение периметра.

Этот процесс может работать с 2D-фигурами, в которых также есть отверстия. Вам просто нужно определить разрез, который проходит от внешнего периметра к отверстию, объединяется вокруг отверстия, а затем возвращается к периметру.

person duffymo    schedule 28.02.2010

@Graviton Я не могу комментировать ответ выше, поэтому отправлю новый.

Возможно, я не знаком с синтаксисом C #, но я считаю, что в вашем ответе отсутствует скалярное произведение с единичным вектором нормали. Формула должна быть такой:

area = n.sum( V(i+1) x V(i) )/2;

где n относится к единичному вектору нормали к плоскости, . к скалярному произведению и x перекрестному произведению.

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

n = (V1-V0)x(V2-V0)/magnitude((V1-V0)x(V2-V0))

Вот реализация javascript с использованием библиотеки Vector.js:

  function getArea (vecs) {
    var area = 0;
    var vecs = [];
    var j = 0;
    var a = new Vector(0,0,0);

    for (var i = 0; i < vecs.length; i++) {
      j = (i + 1) % vecs.length;
      a = a.add( vecs[i].cross(vecs[j]) );
    }
    a = a.divide(2);
    var v1 = vecs[1].subtract(vecs[0]);
    var v2 = vecs[2].subtract(vecs[0]);
    var normal = v1.cross(v2);
    normal = normal.unit();
    // area = a.length()/10000; // convert to m2
    area = (normal.dot(a))/10000;
    return area;
  };
person winkerVSbecks    schedule 23.05.2013

Вы можете получить решение в терминах 2D-решения.

Рассмотрим многоугольник, составленный из кучи меньших треугольников.

Спроецируйте каждый треугольник обратно в плоскость XY. Вы можете показать, что площадь исходного треугольника в 1 / (n.k) умножена на площадь проецируемого треугольника. (Здесь n - единичная нормаль к плоскости, содержащей многоугольник, а k - единичный вектор в направлении z)

Таким образом, общая площадь оригинала равна 1 / (n.k), ​​умноженному на площадь многоугольника, спроецированного на плоскость XY. Что вы можете решить, используя существующую 2D-формулу.

Вы можете вычислить n как (e1 x e2) / || e1 x e2 || где e1 и e2 - любые 2 непараллельных ребра многоугольника.

Конечно, вы можете получить лучшие (более точные) результаты, проецируя на плоскость XZ или YZ .. вы должны выбрать тот, нормаль которого наиболее близка к вашей плоскости.

person Michael Anderson    schedule 28.02.2010
comment
Как вы собираетесь обобщить формулу до списка точек, состоящего всего из трех точек? - person Graviton; 28.02.2010