/* jCAE stand for Java Computer Aided Engineering. Features are : Small CAD modeler, Finite element mesher, Plugin architecture. Copyright (C) 2004,2005,2006, by EADS CRC Copyright (C) 2007, by EADS France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jcae.mesh.amibe.ds; /** * A triangular element of the mesh. Instances of this class carry up * all topological information required for adjacency relations. Their * vertices are contained in a {@link Vertex} array, and by convention * the local number of an edge is the index of its opposite vertex. A * <code>TriangleVH</code> instance has a pointer to its three neighbours * through its edges, and knows the local number of opposite edges in * their respective triangles. It also stores as a byte array attributes * of its three edges. * * <p> * As local numbers are integers between 0 and 2, a packed representation * is wanted to save space. They can be stored within 6 bits, edge 0 * is stored in the two least significant bits, edge 1 in next two and edge * 2 in next two, so <code>adjPos=(localNumberSymEdge0<<0)+(localNumberSymEdge1<<2)+(localNumberSymEdge2<<4)</code>. * </p> * * <p align="center"><img src="doc-files/TriangleVH-1.png" alt="[Image showing adjacency symmetric edges]"/></p> * <p> * Vertices data are colored in black, edges in red and triangles in blue. * Triangle <code>a</code> contains these members: * </p> * <ul> * <li><code>a.vertex = { A, B, C }</code></li> * <li><code>a.adjacentTriangles = { c, d, b }</code></li> * <li><code>a.adjPos = (0 << 0) + (1 << 2) + (0 << 0) = 2</li> * </ul> * * <p> * There are two special cases: * </p> * <ul> * <li>Boundary edges; a virtual Triangle(outerVertex, v1, v2) is created, * and linked to this edge. This triangle has an {@link AbstractHalfEdge#OUTER} * attribute, and boundary edges have a {@link AbstractHalfEdge#BOUNDARY} attribute.</li> * <li>Non-manifold edges; a virtual Triangle(outerVertex, v1, v2) is * also created, and linked to this edge. This triangle has an * {@link AbstractHalfEdge#OUTER} attribute, non-manifold edge and its symmetric edge * have a {@link AbstractHalfEdge#NONMANIFOLD} attribute, and other two edges are used * to build a circular doubly-linked list of all symmetric edges.</li> * </ul> */ public class TriangleVH extends Triangle { private static final long serialVersionUID = 1023860512255791477L; /** * Pointers to adjacent elements through edges. */ private final TriangleVH [] adjacentTriangles = new TriangleVH[3]; /** * Packed representation of adjacent edge local numbers. * adjPos contains the local number of opposite edges in * their respective triangles: * <ul> * <li>bits 0-1: local number for matte edge 0</li> * <li>bits 2-3: local number for matte edge 1</li> * <li>bits 4-5: local number for matte edge 2</li> * </ul> */ private byte adjPos = 0; /** * Edge attributes. */ private final byte [] edgeAttributes = new byte[3]; /** * Constructor. */ public TriangleVH(Vertex v0, Vertex v1, Vertex v2) { super(v0, v1, v2); } @Override public final void copy(Triangle that) { super.copy(that); TriangleVH src = (TriangleVH) that; System.arraycopy(src.adjacentTriangles, 0, adjacentTriangles, 0, 3); adjPos = src.adjPos; edgeAttributes[0] = src.edgeAttributes[0]; edgeAttributes[1] = src.edgeAttributes[1]; edgeAttributes[2] = src.edgeAttributes[2]; } /** * Gets a <code>VirtualHalfEdge</code> instance bound to this triangle. * This method allocates a new {@link VirtualHalfEdge} instance and binds * it to this triangle. * @return a new <code>VirtualHalfEdge</code> instance bound to this triangle */ @Override public VirtualHalfEdge getAbstractHalfEdge() { VirtualHalfEdge ot = new VirtualHalfEdge(); ot.bind(this); return ot; } /** * Gets a <code>VirtualHalfEdge</code> instance bound to this triangle. * If argument is null, this method behaves as if no argument was passed. * Otherwise, argument is an existing {@link VirtualHalfEdge} instance * which is bound to this triangle and returned. * @param that either <code>null</code> or an existing <code>VirtualHalfEdge</code> * instance which is modified * @return a <code>VirtualHalfEdge</code> instance bound to this triangle */ @Override public VirtualHalfEdge getAbstractHalfEdge(AbstractHalfEdge that) { if (that == null) that = new VirtualHalfEdge(); VirtualHalfEdge ot = (VirtualHalfEdge) that; ot.bind(this); return ot; } /** * Returns the adjacent TriangleVH through an edge. * * @param num the local number of this edge. * @return the adjacent TriangleVH */ final TriangleVH getAdj(int num) { return adjacentTriangles[num]; } /** * Sets TriangleVH adjacent to an edge. * * @param num the local number of this edge * @param link adjacent TriangleVH */ final void setAdj(int num, TriangleVH link) { adjacentTriangles[num] = link; } /** * Gets local number of a symmetric edge. * * @param num edge local number * @return local number of this symmetric edge */ final int getAdjLocalNumber(int num) { return (adjPos >> (2*num)) & 3; } /** * Sets local number of a symmetric edge. * * @param num edge local number * @param pos local number of symmetric edge */ final void setAdjLocalNumber(int num, int pos) { // Clear previous adjacent position ... adjPos &= ~(3 << (2*num)); // ... and set it right adjPos |= (pos << (2*num)); } /** * Gets attributes of edge <code>num</code>. * * @param num local edge number * @return attributes of this edge */ final int getEdgeAttributes(int num) { return edgeAttributes[num]; } /** * Sets attributes of edge <code>num</code>. * * @param num local edge number * @param attr attributes to set on this edge */ final void setEdgeAttributes(int num, int attr) { edgeAttributes[num] = (byte) attr; } // Helper functions /** * Sets attributes for all edges of this triangle. * * @param attr attributes to set on edges */ @Override public final void setAttributes(int attr) { edgeAttributes[0] |= attr; edgeAttributes[1] |= attr; edgeAttributes[2] |= attr; } /** * Resets attributes for all edges of this triangle. * * @param attr attributes to reset on edges */ @Override public void clearAttributes(int attr) { edgeAttributes[0] &= ~attr; edgeAttributes[1] &= ~attr; edgeAttributes[2] &= ~attr; } /** * Checks if some attributes of this triangle are set. * * @param attr attributes to check * @return <code>true</code> if any edge of this triangle has * one of these attributes set, <code>false</code> otherwise */ @Override public final boolean hasAttributes(int attr) { return ((edgeAttributes[0] | edgeAttributes[1] | edgeAttributes[2]) & attr) != 0; } private String showAdj(int num) { if (adjacentTriangles[num] == null) return "N/A"; return adjacentTriangles[num].hashCode()+"["+getAdjLocalNumber(num)+"]"; } @Override public final String toString() { StringBuilder r = new StringBuilder(super.toString()); r.append("\nAdjacency: ").append(showAdj(0)).append(" ").append(showAdj(1)).append(" ").append(showAdj(2)); r.append("\nEdge attributes:"); for (int i = 0; i < 3; i++) r.append(" ").append(edgeAttributes[i]); return r.toString(); } }