Files
Triangle.NET/Triangle.NET/Triangle/Tools/AdjacencyMatrix.cs
T
SND\wo80_cp 9e3d316df1 Some minor changes for Beta 3
git-svn-id: https://triangle.svn.codeplex.com/svn@70649 0e2699bc-83d4-4a8f-98e7-55e24ab8c7a5
2012-10-30 20:46:02 +00:00

405 lines
13 KiB
C#

// -----------------------------------------------------------------------
// <copyright file="AdjacencyMatrix.cs" company="">
// 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].triangle.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].triangle.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].triangle.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].triangle.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].triangle.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].triangle.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
}
}