/* 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; import org.jcae.mesh.amibe.traits.TriangleTraitsBuilder; import java.util.Iterator; import java.util.ConcurrentModificationException; import java.util.NoSuchElementException; import java.io.Serializable; import java.util.Collection; /** * A triangle containing adjacency relations. */ public class Triangle implements Serializable { private static final long serialVersionUID = 3698940897637489316L; // User-defined traits //protected final Traits traits; /** * Three vertices. */ protected Vertex v0, v1, v2; // Group id private int groupId = -1; private boolean readable = true; private boolean writable = true; // We sometimes need to process lists of triangles before mesh // connectivity has been set up. This can be achieved efficiently // with a singly linked list. // Reference to the next element in the singly linked list. private Triangle listNext; public Triangle(Vertex v0, Vertex v1, Vertex v2) { this.v0 = v0; this.v1 = v1; this.v2 = v2; } public void copy(Triangle src) { v0 = src.v0; v1 = src.v1; v2 = src.v2; readable = src.readable; writable = src.writable; groupId = src.groupId; } /** * Sets attributes for all edges of this triangle. * * @param attr attributes to set on edges */ public void setAttributes(int attr) { throw new RuntimeException(); } /** * Resets attributes for all edges of this triangle. * * @param attr attributes to reset on edges */ public void clearAttributes(int attr) { throw new RuntimeException(); } /** * 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 */ public boolean hasAttributes(int attr) { return false; } /** * Gets an <code>AbstractHalfEdge</code> instance bound to this triangle. */ public AbstractHalfEdge getAbstractHalfEdge() { throw new RuntimeException(); } /** * Gets an <code>AbstractHalfEdge</code> instance bound to this triangle. */ public AbstractHalfEdge getAbstractHalfEdge(AbstractHalfEdge that) { throw new RuntimeException(); } /** * Return the group identifier of this triangle. * * @return the group identifier of this triangle. */ public final int getGroupId() { return groupId; } /** * Set the group identifier of this triangle. * * @param g the group identifier of this triangle. */ public final void setGroupId(int g) { groupId = g; } public final void setReadable(boolean b) { readable = b; } public final void setWritable(boolean b) { writable = b; } public boolean isReadable() { return readable; } public final boolean isWritable() { return writable; } @Override public String toString() { StringBuilder r = new StringBuilder(); r.append("hashcode: ").append(hashCode()); if (!readable) r.append(" !r"); if (!writable) r.append(" !w"); if (groupId >= 0) r.append("\nGroup: ").append(groupId); r.append("\nVertices:"); r.append("\n ").append(v0); r.append("\n ").append(v1); r.append("\n ").append(v2); if (listNext != null) r.append("\nLink next: ").append(listNext.hashCode()); return r.toString(); } /** * Singly linked list of triangles. * We sometimes need to process lists of triangles before mesh * connectivity has been set up. This can be achieved efficiently * with a singly linked list, but there are few caveats. * <ul> * <li>A Triangle can appear in one list only, trying to insert it * twice will throw a ConcurrentModificationException exception.</li> * <li>Lists have to be cleared out by calling the {@link #clear} method * before being freed, otherwise Triangle can not be inserted into * other lists.</li> * </ul> * <p> * Here is an example: * </p> * <pre> * // Begin a new list * Triangle.List tList = new Triangle.List(); * ... * // In a loop, add triangles to this list. * tList.{@link List#add}(tri); * // Check whether a triangle is contained in this list. * // This is very fast because it tests if its link pointer * // is <code>null</code> or not. * if (tList.{@link List#contains}(tri)) { * ... * } * // Loop over collected triangles. * for (Iterator<Triangle> it = tList.{@link List#iterator}; it.hasNext(); ) * { * Triangle t = it.next(); * ... * } * // When finished, remove all links between triangles * tList.{@link List#clear}; * </pre> * <p> * New elements are added at the end of the list so that {@link List#add} can * be called while {@link List#iterator} is in action. * </p> */ public static class List { // Head of the list. Triangles are linked from this instance. private final Triangle listHead = new Triangle(null, null, null); // Sentinel. This triangle is always the last triangle of the list. private final Triangle listSentinel = new Triangle(null, null, null); // Reference to the last collected triangle. private Triangle listTail = listHead; // Number of collected items (for debugging purpose, can be removed). private int listSize = 0; /** * Initialize a triangle linked list. */ public List() { listTail.listNext = listSentinel; } /** * Unmark triangles. This method must be called before freeing * the list. */ public final void clear() { Triangle next; for (Triangle start = listHead; start != listSentinel; start = next) { next = start.listNext; start.listNext = null; listSize--; } listSize++; assert listSize == 0; listTail = listHead; listTail.listNext = listSentinel; } /** * Add the current triangle to the end of the list. * @throws ConcurrentModificationException if this element is * already linked. */ public final void add(Triangle o) { assert listTail != null; assert listTail.listNext == listSentinel : listTail; if (o.listNext != null) throw new ConcurrentModificationException(o.toString()); listTail.listNext = o; listTail = o; o.listNext = listSentinel; listSize++; } /** * Add the current triangle to the end of the list. This method * does nothing if this element is already linked. */ public final void addAllowDuplicates(Triangle o) { assert listTail != null; assert listTail.listNext == listSentinel : listTail; if (o.listNext == null) { listTail.listNext = o; listTail = o; o.listNext = listSentinel; listSize++; } } /** * Check whether this element appears in the list. */ public final boolean contains(Triangle o) { return o.listNext != null; } /** * Get list size. */ public final int size() { return listSize; } /** * Check whether this list is empty. */ public final boolean isEmpty() { return listTail == listHead && listTail.listNext == listSentinel; } /** * Create an iterator over linked triangles. Note that the list * can be extended while iterating over elements. */ public final Iterator<Triangle> iterator() { return new Iterator<Triangle>() { private Triangle curr = listHead; private Triangle prev = listHead; public boolean hasNext() { return curr.listNext != listSentinel; } public Triangle next() { if (!hasNext()) throw new NoSuchElementException(); prev = curr; curr = curr.listNext; return curr; } public void remove() { if (listTail == curr) listTail = prev; prev.listNext = curr.listNext; curr.listNext = null; curr = prev; listSize--; } }; } } public Vertex getV0() { return v0; } public Vertex getV1() { return v1; } public Vertex getV2() { return v2; } public Vertex getV(int i) { switch(i) { case 0: return v0; case 1: return v1; case 2: return v2; default: throw new IllegalArgumentException(); } } public int vertexNumber() { return 3; } public void addVertexTo(Collection<Vertex> vertex) { vertex.add(v0); vertex.add(v1); vertex.add(v2); } public void setV(int i, Vertex v) { switch(i) { case 0: v0 = v; break; case 1: v1 = v; break; case 2: v2 = v; break; default: throw new IllegalArgumentException(); } } }