f674161dff
git-svn-id: https://triangle.svn.codeplex.com/svn@75300 0e2699bc-83d4-4a8f-98e7-55e24ab8c7a5
406 lines
13 KiB
C#
406 lines
13 KiB
C#
// -----------------------------------------------------------------------
|
|
// <copyright file="AdjacencyMatrix.cs" company="">
|
|
// Original Matlab code by John Burkardt, Florida State University
|
|
// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
|
|
// </copyright>
|
|
// -----------------------------------------------------------------------
|
|
|
|
namespace TriangleNet.Tools
|
|
{
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
|
|
/// <summary>
|
|
/// The adjacency matrix of the mesh.
|
|
/// </summary>
|
|
public class AdjacencyMatrix
|
|
{
|
|
// Number of nodes in the mesh.
|
|
int node_num;
|
|
|
|
// Number of adjacency entries.
|
|
int adj_num;
|
|
|
|
// Pointers into the actual adjacency structure adj. Information about row k is
|
|
// stored in entries adj_row(k) through adj_row(k+1)-1 of adj. Size: node_num + 1
|
|
int[] adj_row;
|
|
|
|
// The adjacency structure. For each row, it contains the column indices
|
|
// of the nonzero entries. Size: adj_num
|
|
int[] adj;
|
|
|
|
public int[] AdjacencyRow
|
|
{
|
|
get { return adj_row; }
|
|
}
|
|
|
|
public int[] Adjacency
|
|
{
|
|
get { return adj; }
|
|
}
|
|
|
|
public AdjacencyMatrix(Mesh mesh)
|
|
{
|
|
this.node_num = mesh.vertices.Count;
|
|
|
|
// Set up the adj_row adjacency pointer array.
|
|
this.adj_row = AdjacencyCount(mesh);
|
|
this.adj_num = adj_row[node_num] - 1;
|
|
|
|
// Set up the adj adjacency array.
|
|
this.adj = AdjacencySet(mesh, this.adj_row);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Computes the bandwidth of an adjacency matrix.
|
|
/// </summary>
|
|
/// <returns>Bandwidth of the adjacency matrix.</returns>
|
|
public int Bandwidth()
|
|
{
|
|
int band_hi;
|
|
int band_lo;
|
|
int col;
|
|
int i, j;
|
|
|
|
band_lo = 0;
|
|
band_hi = 0;
|
|
|
|
for (i = 0; i < node_num; i++)
|
|
{
|
|
for (j = adj_row[i]; j <= adj_row[i + 1] - 1; j++)
|
|
{
|
|
col = adj[j - 1];
|
|
band_lo = Math.Max(band_lo, i - col);
|
|
band_hi = Math.Max(band_hi, col - i);
|
|
}
|
|
}
|
|
|
|
return band_lo + 1 + band_hi;
|
|
}
|
|
|
|
#region Adjacency matrix
|
|
|
|
/// <summary>
|
|
/// Counts adjacencies in a triangulation.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This routine is called to count the adjacencies, so that the
|
|
/// appropriate amount of memory can be set aside for storage when
|
|
/// the adjacency structure is created.
|
|
///
|
|
/// The triangulation is assumed to involve 3-node triangles.
|
|
///
|
|
/// Two nodes are "adjacent" if they are both nodes in some triangle.
|
|
/// Also, a node is considered to be adjacent to itself.
|
|
///
|
|
/// Diagram:
|
|
///
|
|
/// 3
|
|
/// s |\
|
|
/// i | \
|
|
/// d | \
|
|
/// e | \ side 1
|
|
/// | \
|
|
/// 2 | \
|
|
/// | \
|
|
/// 1-------2
|
|
///
|
|
/// side 3
|
|
/// </remarks>
|
|
int[] AdjacencyCount(Mesh mesh)
|
|
{
|
|
int i;
|
|
int node;
|
|
int n1, n2, n3;
|
|
int tri_id;
|
|
int neigh_id;
|
|
|
|
int[] adj_rows = new int[node_num + 1];
|
|
|
|
// Set every node to be adjacent to itself.
|
|
for (node = 0; node < node_num; node++)
|
|
{
|
|
adj_rows[node] = 1;
|
|
}
|
|
|
|
// Examine each triangle.
|
|
foreach (var tri in mesh.triangles.Values)
|
|
{
|
|
tri_id = tri.id;
|
|
|
|
n1 = tri.vertices[0].id;
|
|
n2 = tri.vertices[1].id;
|
|
n3 = tri.vertices[2].id;
|
|
|
|
// Add edge (1,2) if this is the first occurrence, that is, if
|
|
// the edge (1,2) is on a boundary (nid <= 0) or if this triangle
|
|
// is the first of the pair in which the edge occurs (tid < nid).
|
|
neigh_id = tri.neighbors[2].tri.id;
|
|
|
|
if (neigh_id < 0 || tri_id < neigh_id)
|
|
{
|
|
adj_rows[n1] += 1;
|
|
adj_rows[n2] += 1;
|
|
}
|
|
|
|
// Add edge (2,3).
|
|
neigh_id = tri.neighbors[0].tri.id;
|
|
|
|
if (neigh_id < 0 || tri_id < neigh_id)
|
|
{
|
|
adj_rows[n2] += 1;
|
|
adj_rows[n3] += 1;
|
|
}
|
|
|
|
// Add edge (3,1).
|
|
neigh_id = tri.neighbors[1].tri.id;
|
|
|
|
if (neigh_id < 0 || tri_id < neigh_id)
|
|
{
|
|
adj_rows[n3] += 1;
|
|
adj_rows[n1] += 1;
|
|
}
|
|
}
|
|
|
|
// We used ADJ_COL to count the number of entries in each column.
|
|
// Convert it to pointers into the ADJ array.
|
|
for (node = node_num; 1 <= node; node--)
|
|
{
|
|
adj_rows[node] = adj_rows[node - 1];
|
|
}
|
|
|
|
adj_rows[0] = 1;
|
|
for (i = 1; i <= node_num; i++)
|
|
{
|
|
adj_rows[i] = adj_rows[i - 1] + adj_rows[i];
|
|
}
|
|
|
|
return adj_rows;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets adjacencies in a triangulation.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This routine can be used to create the compressed column storage
|
|
/// for a linear triangle finite element discretization of Poisson's
|
|
/// equation in two dimensions.
|
|
/// </remarks>
|
|
int[] AdjacencySet(Mesh mesh, int[] rows)
|
|
{
|
|
// Output list, stores the actual adjacency information.
|
|
int[] list;
|
|
|
|
// Copy of the adjacency rows input.
|
|
int[] rowsCopy = new int[node_num];
|
|
Array.Copy(rows, rowsCopy, node_num);
|
|
|
|
int i, n = rows[node_num] - 1;
|
|
|
|
list = new int[n];
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
list[i] = -1;
|
|
}
|
|
|
|
// Set every node to be adjacent to itself.
|
|
for (i = 0; i < node_num; i++)
|
|
{
|
|
list[rowsCopy[i] - 1] = i;
|
|
rowsCopy[i] += 1;
|
|
}
|
|
|
|
int n1, n2, n3; // Vertex numbers.
|
|
int tid, nid; // Triangle and neighbor id.
|
|
|
|
// Examine each triangle.
|
|
foreach (var tri in mesh.triangles.Values)
|
|
{
|
|
tid = tri.id;
|
|
|
|
n1 = tri.vertices[0].id;
|
|
n2 = tri.vertices[1].id;
|
|
n3 = tri.vertices[2].id;
|
|
|
|
// Add edge (1,2) if this is the first occurrence, that is, if
|
|
// the edge (1,2) is on a boundary (nid <= 0) or if this triangle
|
|
// is the first of the pair in which the edge occurs (tid < nid).
|
|
nid = tri.neighbors[2].tri.id;
|
|
|
|
if (nid < 0 || tid < nid)
|
|
{
|
|
list[rowsCopy[n1] - 1] = n2;
|
|
rowsCopy[n1] += 1;
|
|
list[rowsCopy[n2] - 1] = n1;
|
|
rowsCopy[n2] += 1;
|
|
}
|
|
|
|
// Add edge (2,3).
|
|
nid = tri.neighbors[0].tri.id;
|
|
|
|
if (nid < 0 || tid < nid)
|
|
{
|
|
list[rowsCopy[n2] - 1] = n3;
|
|
rowsCopy[n2] += 1;
|
|
list[rowsCopy[n3] - 1] = n2;
|
|
rowsCopy[n3] += 1;
|
|
}
|
|
|
|
// Add edge (3,1).
|
|
nid = tri.neighbors[1].tri.id;
|
|
|
|
if (nid < 0 || tid < nid)
|
|
{
|
|
list[rowsCopy[n1] - 1] = n3;
|
|
rowsCopy[n1] += 1;
|
|
list[rowsCopy[n3] - 1] = n1;
|
|
rowsCopy[n3] += 1;
|
|
}
|
|
}
|
|
|
|
int k1, k2;
|
|
|
|
// Ascending sort the entries for each node.
|
|
for (i = 0; i < node_num; i++)
|
|
{
|
|
k1 = rows[i];
|
|
k2 = rows[i + 1] - 1;
|
|
HeapSort(list, k1 - 1, k2 + 1 - k1);
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Heap sort
|
|
|
|
/// <summary>
|
|
/// Reorders an array of integers into a descending heap.
|
|
/// </summary>
|
|
/// <param name="size">the size of the input array.</param>
|
|
/// <param name="a">an unsorted array.</param>
|
|
/// <remarks>
|
|
/// A heap is an array A with the property that, for every index J,
|
|
/// A[J] >= A[2*J+1] and A[J] >= A[2*J+2], (as long as the indices
|
|
/// 2*J+1 and 2*J+2 are legal).
|
|
///
|
|
/// Diagram:
|
|
///
|
|
/// A(0)
|
|
/// / \
|
|
/// A(1) A(2)
|
|
/// / \ / \
|
|
/// A(3) A(4) A(5) A(6)
|
|
/// / \ / \
|
|
/// A(7) A(8) A(9) A(10)
|
|
/// </remarks>
|
|
private void CreateHeap(int[] a, int offset, int size)
|
|
{
|
|
int i;
|
|
int ifree;
|
|
int key;
|
|
int m;
|
|
|
|
// Only nodes (N/2)-1 down to 0 can be "parent" nodes.
|
|
for (i = (size / 2) - 1; 0 <= i; i--)
|
|
{
|
|
// Copy the value out of the parent node.
|
|
// Position IFREE is now "open".
|
|
key = a[offset + i];
|
|
ifree = i;
|
|
|
|
for (; ; )
|
|
{
|
|
// Positions 2*IFREE + 1 and 2*IFREE + 2 are the descendants of position
|
|
// IFREE. (One or both may not exist because they equal or exceed N.)
|
|
m = 2 * ifree + 1;
|
|
|
|
// Does the first position exist?
|
|
if (size <= m)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// Does the second position exist?
|
|
if (m + 1 < size)
|
|
{
|
|
// If both positions exist, take the larger of the two values,
|
|
// and update M if necessary.
|
|
if (a[offset + m] < a[offset + m + 1])
|
|
{
|
|
m = m + 1;
|
|
}
|
|
}
|
|
|
|
// If the large descendant is larger than KEY, move it up,
|
|
// and update IFREE, the location of the free position, and
|
|
// consider the descendants of THIS position.
|
|
if (key < a[offset + m])
|
|
{
|
|
a[offset + ifree] = a[offset + m];
|
|
ifree = m;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// When you have stopped shifting items up, return the item you
|
|
// pulled out back to the heap.
|
|
a[offset + ifree] = key;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// ascending sorts an array of integers using heap sort.
|
|
/// </summary>
|
|
/// <param name="size">Number of entries in the array.</param>
|
|
/// <param name="a">Array to be sorted;</param>
|
|
private void HeapSort(int[] a, int offset, int size)
|
|
{
|
|
int n1;
|
|
int temp;
|
|
|
|
if (size <= 1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// 1: Put A into descending heap form.
|
|
CreateHeap(a, offset, size);
|
|
|
|
// 2: Sort A.
|
|
// The largest object in the heap is in A[0].
|
|
// Move it to position A[N-1].
|
|
temp = a[offset];
|
|
a[offset] = a[offset + size - 1];
|
|
a[offset + size - 1] = temp;
|
|
|
|
// Consider the diminished heap of size N1.
|
|
for (n1 = size - 1; 2 <= n1; n1--)
|
|
{
|
|
// Restore the heap structure of the initial N1 entries of A.
|
|
CreateHeap(a, offset, n1);
|
|
|
|
// Take the largest object from A[0] and move it to A[N1-1].
|
|
temp = a[offset];
|
|
a[offset] = a[offset + n1 - 1];
|
|
a[offset + n1 - 1] = temp;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|