Как сортировать края в специальной сетке поверхности - PullRequest
0 голосов
/ 20 октября 2011

Вот функция, использующая предложение из ответа на вопрос, который я задал несколько дней назад. Давайте создадим объект Graphics3D в Mathematica. Я использую данные трехмерной геометрии от здесь .

cd = Import[NotebookDirectory[] <> "withwake.obj"];
vertices = cd[[1, 2, 1]];
polygons = Flatten[cd[[1, 2, 2, 1]] /. Polygon -> List, 2];
Graphics3D[GraphicsComplex[vertices, Polygon[polygons]]]

enter image description here

Для каждого многоугольника мы создаем список чисел, указывающих на его вершины и сопровождаемых числами, указывающими на многоугольники, с которыми связан каждый из ребер. Важно отметить, что поверхность нормальная; порядок узлов, определяющих панели, должен быть против часовой стрелки. По правилу правой руки, если пальцы согнуты, чтобы следовать нумерации, большой палец покажет нормальный вектор, который должен указывать «наружу» геометрию.

Вот функция, которая создает такой список, если все многоугольники в объекте Graphics3D являются треугольниками.

EdgeSorting[vertices_, polygons_] := 
Block[{triangleEdges, singleEdges, edgesNeighbors, relations, n, n1,
 n2, trires, triangleNeigbours, TriangleMaker, polygonArea, tring},
(*Split every triangle in 3 edges,with nodes in each edge sorted*)   
triangleEdges = (Sort /@ Subsets[#, {2}]) & /@ polygons;
(*Generate a list of edges*)
singleEdges = Union[Flatten[triangleEdges, 1]];
(*Define a function which,given an edge (node number list),
returns the bordering*)
(*triangle numbers.It's done by working through each of the \
triangles' edges*)
edgesNeighbors[_] = {};
MapIndexed[(edgesNeighbors[#1[[1]]] = 
   Flatten[{edgesNeighbors[#1[[1]]], #2[[1]]}];
  edgesNeighbors[#1[[2]]] = 
   Flatten[{edgesNeighbors[#1[[2]]], #2[[1]]}];
  edgesNeighbors[#1[[3]]] = 
   Flatten[{edgesNeighbors[#1[[3]]], #2[[1]]}];) &, triangleEdges];
(*Build a triangle relation table.Each'1' indicates a triangle \
relation*)
relations = 
ConstantArray[
 0, {triangleEdges // Length, triangleEdges // Length}];
Scan[(n = edgesNeighbors[##];
  If[Length[n] == 2, {n1, n2} = n;
   relations[[n1, n2]] = 1; relations[[n2, n1]] = 1];) &, 
singleEdges];
Print[MatrixPlot[relations]];
(*Build a neighborhood list*)
triangleNeigbours = 
Table[Flatten[Position[relations[[i]], 1]], {i, 
  triangleEdges // Length}];
trires = 
Table[Flatten[{polygons[[i]], triangleNeigbours[[i]]}], {i, 1, 
  Length@polygons}];
TriangleMaker[{a_, b_, c_}] := {vertices[[a]], vertices[[b]], 
 vertices[[c]]};
{trires}
];

Я не совсем понимаю, как работает эта функция. И я не могу понять, как добиться следующего.

  1. Для каждого из треугольников и четырехугольника как формировать списков , как уже упоминалось ранее.
  2. Сетка строгального станка от 3D подводного крыла называется панелью следа. Для каждой четырехугольной панели пробуждения / многоугольника нам нужно сформировать список чисел, указывающих на его вершины, за которыми следуют числа, указывающие на два многоугольника , которые разделяют его единственный край, который соединяет четырехугольник пробуждения панель / полигон с основной геометрией подводных крыльев.

1 Ответ

5 голосов
/ 20 октября 2011

Чтобы создать список всех полигонов и их соседей, вы можете сделать что-то вроде этого:

neighbours[polygons_] := {#, 
  Flatten@Position[polygons, 
    a_List /; Length[Intersection[a, #]] == 2]} & /@ polygons;

Затем neighbours[polygons] создает список, в котором i -ая запись состоит из polygons[[i]] и индексов соседей polygons[[i]].

Для второй части вашего вопроса, вы можете сделать что-то вроде

wake[polygons_] := 
 Module[{edges, boundaries, wakelist, body}, 
  edges[polylist_] := Flatten[Map[Partition[#, 2, 1, 1] &, polylist], 1];
  boundaries = Cases[Tally[
     edges[polygons], (Sort[#1] == Sort[#2]) &], {a_, b_} /; b == 1 :> a];
  wakelist = 
   DeleteDuplicates[
    Map[Cases[polygons, a_ /; (Length[Intersection[a, #]] == 2)][[1]] &,
      boundaries]];
  {#, Flatten@Position[polygons, a_List /; (Length[Intersection[#, a]] == 2 && 
          Not[MemberQ[wakelist, a]])]} & /@ wakelist]

В wake полигон считается панелью следа, если он содержит ребро, у которого нет соседних полигонов. Я не знаю, всегда ли это верно, но, похоже, это работает для примера в вопросе.

Редактировать Чтобы разделить полный список полигонов по полигонам следа и тела, вы можете сделать что-то вроде

split[polygons_] := Module[{edges, boundaries, wakelist}, 
   edges[polylist_] := Flatten[Map[Partition[#, 2, 1, 1] &, polygons], 1];
   boundaries = Cases[Tally[edges[polygons], 
       (Sort[#1] == Sort[#2]) &], {a_, b_} /; b == 1 :> a];
   wakelist = DeleteDuplicates[Map[Cases[polygons, 
        a_ /; (Length[Intersection[a, #]] == 2)][[1]] &, boundaries]];
   {wakelist, Complement[polygons, wakelist]}];

Затем split[polygons] создаст список из двух подсписков. Первый подсписок содержит все полигоны, принадлежащие следу, а второй - все полигоны, принадлежащие телу. Поскольку split уже отделяет след от тела, мы можем переписать wake в соответствии с

wake2[wakelist_, bodylist_] := {#, Flatten@Position[bodylist,
      a_List /; (Length[Intersection[#, a]] == 2)]} & /@ wakelist

Затем, чтобы найти список многоугольников тела плюс индексы их соседей, и список многоугольников следа плюс индексы соседних многоугольников тела, которые вы можете сделать

{wakepols, bodypols} = split[polygons];
bodylist = neighbours[bodypols];
wakelist = wake[wakepols, bodypols];

Обратите внимание, что индексы полигонов в bodylist и wakelist теперь относятся к полигонам в bodypols, а не к полному списку polygons.

...