/* Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University Copyright Equnior ASA This file is part of the Open Porous Media project (OPM). OPM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OPM 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 General Public License for more details. You should have received a copy of the GNU General Public License along with OPM. If not, see . */ #ifndef pmmc_INC #define pmmc_INC #include #include #include #include #include #include "common/Array.h" #include "PointList.h" #include "common/Utilities.h" using namespace std; static int edgeTable[256] = { 0x0, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00, 0x190, 0x99, 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90, 0x230, 0x339, 0x33, 0x13a, 0x636, 0x73f, 0x435, 0x53c, 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30, 0x3a0, 0x2a9, 0x1a3, 0xaa, 0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0, 0x460, 0x569, 0x663, 0x76a, 0x66, 0x16f, 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60, 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff, 0x3f5, 0x2fc, 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0, 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55, 0x15c, 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950, 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc, 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0, 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 0xcc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0, 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 0x15c, 0x55, 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650, 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 0x2fc, 0x3f5, 0xff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0, 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x66, 0x76a, 0x663, 0x569, 0x460, 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa, 0x1a3, 0x2a9, 0x3a0, 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33, 0x339, 0x230, 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99, 0x190, 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0}; static signed char triTable[256][16] = { {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1}, {3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1}, {3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1}, {3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1}, {9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1}, {1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1}, {9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1}, {2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1}, {8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1}, {9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1}, {4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1}, {3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1}, {1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1}, {4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1}, {4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1}, {9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1}, {1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1}, {5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1}, {2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1}, {9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1}, {0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1}, {2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1}, {10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1}, {4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1}, {5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1}, {5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1}, {9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1}, {0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1}, {1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1}, {10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1}, {8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1}, {2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1}, {7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1}, {9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1}, {2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1}, {11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1}, {9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1}, {5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1}, {11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1}, {11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1}, {1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1}, {9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1}, {5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1}, {2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1}, {0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1}, {5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1}, {6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1}, {0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1}, {3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1}, {6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1}, {5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1}, {1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1}, {10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1}, {6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1}, {1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1}, {8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1}, {7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1}, {3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1}, {5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1}, {0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1}, {9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1}, {8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1}, {5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1}, {0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1}, {6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1}, {10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1}, {10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1}, {8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1}, {1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1}, {3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1}, {0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1}, {10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1}, {0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1}, {3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1}, {6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1}, {9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1}, {8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1}, {3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1}, {6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1}, {0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1}, {10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1}, {10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1}, {1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1}, {2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1}, {7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1}, {7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1}, {2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1}, {1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1}, {11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1}, {8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1}, {0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1}, {7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1}, {10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1}, {2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1}, {6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1}, {7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1}, {2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1}, {1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1}, {10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1}, {10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1}, {0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1}, {7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1}, {6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1}, {8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1}, {9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1}, {6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1}, {1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1}, {4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1}, {10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1}, {8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1}, {0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1}, {1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1}, {8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1}, {10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1}, {4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1}, {10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1}, {5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1}, {11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1}, {9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1}, {6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1}, {7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1}, {3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1}, {7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1}, {9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1}, {3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1}, {6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1}, {9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1}, {1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1}, {4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1}, {7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1}, {6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1}, {3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1}, {0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1}, {6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1}, {1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1}, {0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1}, {11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1}, {6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1}, {5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1}, {9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1}, {1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1}, {1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1}, {10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1}, {0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1}, {5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1}, {10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1}, {11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1}, {0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1}, {9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1}, {7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1}, {2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1}, {8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1}, {9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1}, {9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1}, {1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1}, {9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1}, {9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1}, {5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1}, {0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1}, {10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1}, {2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1}, {0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1}, {0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1}, {9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1}, {5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1}, {3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1}, {5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1}, {8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1}, {0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1}, {9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1}, {0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1}, {1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1}, {3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1}, {4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1}, {9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1}, {11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1}, {11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1}, {2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1}, {9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1}, {3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1}, {1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1}, {4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1}, {4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1}, {0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1}, {3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1}, {3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1}, {0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1}, {9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1}, {1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}; //-------------------------------------------------------------------------------------------------------- class TriLinPoly { /* Compute a tri-linear polynomial within a given cube (i,j,k) x (i+1,j+1,k+1) * Values are provided at the corners in CubeValues * x,y,z must be defined on [0,1] where the length of the cube edge is one */ int ic, jc, kc; double a, b, c, d, e, f, g, h; double x, y, z; public: DoubleArray Corners; TriLinPoly() { Corners.resize(2, 2, 2); } ~TriLinPoly() {} // Assign the polynomial within a cube from a mesh void assign(DoubleArray &A, int i, int j, int k) { // Save the cube indices ic = i; jc = j; kc = k; // local copy of the cube values Corners(0, 0, 0) = A(i, j, k); Corners(1, 0, 0) = A(i + 1, j, k); Corners(0, 1, 0) = A(i, j + 1, k); Corners(1, 1, 0) = A(i + 1, j + 1, k); Corners(0, 0, 1) = A(i, j, k + 1); Corners(1, 0, 1) = A(i + 1, j, k + 1); Corners(0, 1, 1) = A(i, j + 1, k + 1); Corners(1, 1, 1) = A(i + 1, j + 1, k + 1); // coefficients of the tri-linear approximation a = Corners(0, 0, 0); b = Corners(1, 0, 0) - a; c = Corners(0, 1, 0) - a; d = Corners(0, 0, 1) - a; e = Corners(1, 1, 0) - a - b - c; f = Corners(1, 0, 1) - a - b - d; g = Corners(0, 1, 1) - a - c - d; h = Corners(1, 1, 1) - a - b - c - d - e - f - g; } // Assign polynomial based on values manually assigned to Corners void assign() { ic = 0; jc = 0; kc = 0; // coefficients of the tri-linear approximation a = Corners(0, 0, 0); b = Corners(1, 0, 0) - a; c = Corners(0, 1, 0) - a; d = Corners(0, 0, 1) - a; e = Corners(1, 1, 0) - a - b - c; f = Corners(1, 0, 1) - a - b - d; g = Corners(0, 1, 1) - a - c - d; h = Corners(1, 1, 1) - a - b - c - d - e - f - g; } // Evaluate the polynomial at a point double eval(Point P) { double returnValue; x = P.x - 1.0 * ic; y = P.y - 1.0 * jc; z = P.z - 1.0 * kc; returnValue = a + b * x + c * y + d * z + e * x * y + f * x * z + g * y * z + h * x * y * z; return returnValue; } }; //-------------------------------------------------------------------------------------------------- /* inline DoubleArray SOLVE( DoubleArray &A, DoubleArray &b) { // solves the system A*x = b exactly DoubleArray AA = A.Copy(); long int n = A.n; long int nrhs =1; IntArray piv(2*n); DoubleArray solution = b.Copy(); long int info = 0; int ret = dgesv_(&n,&nrhs,AA.Pointer(),&n,(long int *)piv.Pointer(),solution.Pointer(),&n,&info); // DTErrorMessage("Computation", string("Error=")+ DTInt2String(ret) + "info = " + DTInt2String(info)); return solution; } //----------------------------------------------------------------------------- inline Point NEWTON(Point x0, DoubleArray &F, double &v,DoubleArray &S, int i, int j, int k, int &newton_steps) { Point pt; // Performs a Newton iteration to compute the point x from initial guess x0 double tol = 0.001; double dist = 1; // Map x0 into unit coordinates Point X0 = x0; x0.x = x0.x - i; x0.y = x0.y - j; x0.z = x0.z - k; // Compute coefficients for tri-linear approximations to the functions F and S // coefficients for F double Af, Bf, Cf, Df, Ef, Ff, Gf, Hf; Af = F(i,j,k); Bf = F(i+1,j,k)-Af; Cf = F(i,j+1,k)-Af; Df = F(i,j,k+1)-Af; Ef = F(i+1,j+1,k)-Af-Bf-Cf; Ff = F(i+1,j,k+1)-Af-Bf-Df; Gf = F(i,j+1,k+1)-Af-Cf-Df; Hf = F(i+1,j+1,k+1)-Af-Bf-Cf-Df-Ef-Ff-Gf; // coefficients for S double As, Bs, Cs, Ds, Es, Fs, Gs, Hs; As = S(i,j,k); Bs = S(i+1,j,k)-As; Cs = S(i,j+1,k)-As; Ds = S(i,j,k+1)-As; Es = S(i+1,j+1,k)-As-Bs-Cs; Fs = S(i+1,j,k+1)-As-Bs-Ds; Gs = S(i,j+1,k+1)-As-Cs-Ds; Hs = S(i+1,j+1,k+1)-As-Bs-Cs-Ds-Es-Fs-Gs; // Compute coefficients for plane in direction of grad F, grad S at point x0 // Compute grad u = grad F , v = grad S int count; int number; count = 0; number = int(floor(newton_steps)); //number = 2; pt = x0; bool pt_on_cube_leg = 0; // Compute the u = grad F, v = grad S and the normal vector N = u x v double u1, u2, u3, v1, v2, v3; u1 = Bf+Ef*x0.y+Ff*x0.z+Hf*x0.y*x0.z; u2 = Cf+Ef*x0.x+Gf*x0.z+Hf*x0.x*x0.z; u3 = Df+Ff*x0.x+Gf*x0.y+Hf*x0.x*x0.y; v1 = Bs+Es*x0.y+Fs*x0.z+Hs*x0.y*x0.z; v2 = Cs+Es*x0.x+Gs*x0.z+Hs*x0.x*x0.z; v3 = Ds+Fs*x0.x+Gs*x0.y+Hs*x0.x*x0.y; // Compute the normal vector N Point N; if (x0.x == 0 || x0.x == 1){ if (x0.y == 0 || x0.y == 1){ // on a cube leg pt_on_cube_leg = 1; } else if (x0.z == 0 || x0.z == 1){ // on a cube leg pt_on_cube_leg = 1; } else { // use this cube face as the normal N.x = 1; N.y = 0; N.z = 0; } } else if (x0.y == 0 || x0.y == 1){ if (x0.z == 0 || x0.z == 1){ // on a cube leg pt_on_cube_leg = 1; } else { // use this cube face as the normal N.x = 0; N.y = 1; N.z = 0; } } else if (x0.z == 0 || x0.z == 1){ // use this cube face as the normal N.x = 0; N.y = 0; N.z = 1; } else { // Compute N = u x v N.x = u2*v3 - u3*v2; N.y = u3*v1 - u1*v3; N.z = u1*v2 - u2*v1; } if ( pt_on_cube_leg == 1){ // return x0 pt = x0; } else { while (count < number ){ // Construct the Jacobean Matrix J DoubleArray J(3,3); J(0,0) = u1; J(0,1) = u2; J(0,2) = u3; J(1,0) = v1; J(1,1) = v2; J(1,2) = v3; J(2,0) = N.x; J(2,1) = N.y; J(2,2) = N.z; // Evaluate the vector M(x0) DoubleArray M(3); M(0) = -(Af+Bf*x0.x+Cf*x0.y+Df*x0.z+Ef*x0.x*x0.y+Ff*x0.x*x0.z+Gf*x0.y*x0.z+Hf*x0.x*x0.y*x0.z - v); M(1) = -(As+Bs*x0.x+Cs*x0.y+Ds*x0.z+Es*x0.x*x0.y+Fs*x0.x*x0.z+Gs*x0.y*x0.z+Hs*x0.x*x0.y*x0.z); M(2) = 0; // Compute the update to x0 using Newton's method Point dX; DoubleArray d = SOLVE(J,M); dX.x = d(0); dX.y = d(1); dX.z = d(2); if ( dX.x > 0.1 || dX.y > 0.1 || dX.z > 0.1 || dX.x < -0.1 || dX.y < -0.1 || dX.z < -0.1){ count = number; } else { pt = x0+dX; x0 = pt; } M(0) = -(Af+Bf*x0.x+Cf*x0.y+Df*x0.z+Ef*x0.x*x0.y+Ff*x0.x*x0.z+Gf*x0.y*x0.z+Hf*x0.x*x0.y*x0.z - v); M(1) = -(As+Bs*x0.x+Cs*x0.y+Ds*x0.z+Es*x0.x*x0.y+Fs*x0.x*x0.z+Gs*x0.y*x0.z+Hs*x0.x*x0.y*x0.z); M(2) = 0; dist = sqrt(M(0)*M(0)+M(1)*M(1)+M(2)*M(2)); // Compute u, v at new x0 u1 = Bf+Ef*x0.y+Ff*x0.z+Hf*x0.y*x0.z; u2 = Cf+Ef*x0.x+Gf*x0.z+Hf*x0.x*x0.z; u3 = Df+Ff*x0.x+Gf*x0.y+Hf*x0.x*x0.y; v1 = Bs+Es*x0.y+Fs*x0.z+Hs*x0.y*x0.z; v2 = Cs+Es*x0.x+Gs*x0.z+Hs*x0.x*x0.z; v3 = Ds+Fs*x0.x+Gs*x0.y+Hs*x0.x*x0.y; count++; } } // map pt back to original coordinates pt.x = pt.x+i; pt.y = pt.y+j; pt.z = pt.z+k; return pt; } */ //-------------------------------------------------------------------------------------------------- inline bool vertexcheck(Point &P, int n, int pos, DTMutableList &cellvertices) { // returns true if P is a new vertex (one previously unencountered bool V = 1; int i = pos - n; for (i = pos - n; i < pos; i++) { if (P == cellvertices(i)) { V = 0; } } return V; } //-------------------------------------------------------------------------------------------------- inline bool ShareSide(Point &A, Point &B) { // returns true if points A and B share an x,y, or z coordinate bool l = 0; if (A.x != B.x && A.y != B.y && A.z != B.z) { l = 0; } else { if (floor(A.x) == A.x && floor(B.x) == B.x && A.x == B.x) { l = 1; } if (floor(A.y) == A.y && floor(B.y) == B.y && A.y == B.y) { l = 1; } if (floor(A.z) == A.z && floor(B.z) == B.z && A.z == B.z) { l = 1; } } return l; } //-------------------------------------------------------------------------------------------------- inline bool Interface(DoubleArray &A, const double v, int i, int j, int k) { // returns true if grid cell i, j, k contains a section of the interface bool Y = 0; if ((A(i, j, k) - v) * (A(i + 1, j, k) - v) < 0) { Y = 1; } // 2 if ((A(i + 1, j, k) - v) * (A(i + 1, j + 1, k) - v) < 0) { Y = 1; } //3 if ((A(i + 1, j + 1, k) - v) * (A(i, j + 1, k) - v) < 0) { Y = 1; } //4 if ((A(i, j + 1, k) - v) * (A(i, j, k) - v) < 0) { Y = 1; } //5 if ((A(i, j, k) - v) * (A(i, j, k + 1) - v) < 0) { Y = 1; } //6 if ((A(i + 1, j, k) - v) * (A(i + 1, j, k + 1) - v) < 0) { Y = 1; } //7 if ((A(i + 1, j + 1, k) - v) * (A(i + 1, j + 1, k + 1) - v) < 0) { Y = 1; } //8 if ((A(i, j + 1, k) - v) * (A(i, j + 1, k + 1) - v) < 0) { Y = 1; } //9 if ((A(i, j, k + 1) - v) * (A(i + 1, j, k + 1) - v) < 0) { Y = 1; } //10 if ((A(i + 1, j, k + 1) - v) * (A(i + 1, j + 1, k + 1) - v) < 0) { Y = 1; } //11 if ((A(i + 1, j + 1, k + 1) - v) * (A(i, j + 1, k + 1) - v) < 0) { Y = 1; } //12 if ((A(i, j + 1, k + 1) - v) * (A(i, j, k + 1) - v) < 0) { Y = 1; } return Y; } //-------------------------------------------------------------------------------------------------- inline bool Fluid_Interface(DoubleArray &A, DoubleArray &S, const double v, int i, int j, int k) { // returns true if grid cell i, j, k contains a section of the interface bool Y = 0; if ((A(i, j, k) - v) * (A(i + 1, j, k) - v) < 0 && S(i, j, k) > 0 && S(i + 1, j, k) > 0) { Y = 1; } // 2 if ((A(i + 1, j, k) - v) * (A(i + 1, j + 1, k) - v) < 0 && S(i + 1, j, k) > 0 && S(i + 1, j + 1, k) > 0) { Y = 1; } //3 if ((A(i + 1, j + 1, k) - v) * (A(i, j + 1, k) - v) < 0 && S(i + 1, j + 1, k) > 0 && S(i, j + 1, k) > 0) { Y = 1; } //4 if ((A(i, j + 1, k) - v) * (A(i, j, k) - v) < 0 && S(i, j, k) > 0 && S(i, j + 1, k) > 0) { Y = 1; } //5 if ((A(i, j, k) - v) * (A(i, j, k + 1) - v) < 0 && S(i, j, k) > 0 && S(i, j, k + 1) > 0) { Y = 1; } //6 if ((A(i + 1, j, k) - v) * (A(i + 1, j, k + 1) - v) < 0 && S(i + 1, j, k) > 0 && S(i + 1, j, k + 1) > 0) { Y = 1; } //7 if ((A(i + 1, j + 1, k) - v) * (A(i + 1, j + 1, k + 1) - v) < 0 && S(i + 1, j + 1, k) > 0 && S(i + 1, j + 1, k + 1) > 0) { Y = 1; } //8 if ((A(i, j + 1, k) - v) * (A(i, j + 1, k + 1) - v) < 0 && S(i, j + 1, k) > 0 && S(i, j + 1, k + 1) > 0) { Y = 1; } //9 if ((A(i, j, k + 1) - v) * (A(i + 1, j, k + 1) - v) < 0 && S(i, j, k + 1) > 0 && S(i + 1, j, k + 1) > 0) { Y = 1; } //10 if ((A(i + 1, j, k + 1) - v) * (A(i + 1, j + 1, k + 1) - v) < 0 && S(i + 1, j, k + 1) > 0 && S(i + 1, j + 1, k + 1) > 0) { Y = 1; } //11 if ((A(i + 1, j + 1, k + 1) - v) * (A(i, j + 1, k + 1) - v) < 0 && S(i + 1, j + 1, k + 1) > 0 && S(i, j + 1, k + 1) > 0) { Y = 1; } //12 if ((A(i, j + 1, k + 1) - v) * (A(i, j, k + 1) - v) < 0 && S(i, j, k + 1) > 0 && S(i, j + 1, k + 1) > 0) { Y = 1; } return Y; } //-------------------------------------------------------------------------------------------------- inline bool Solid(DoubleArray &A, int i, int j, int k) { bool X = 0; // return 0 if there is no solid phase in grid cell i,j,k if (A(i, j, k) == 0) { X = 1; } if (A(i + 1, j, k) == 0) { X = 1; } if (A(i, j + 1, k) == 0) { X = 1; } if (A(i, j, k + 1) == 0) { X = 1; } if (A(i + 1, j + 1, k) == 0) { X = 1; } if (A(i + 1, j, k + 1) == 0) { X = 1; } if (A(i, j + 1, k + 1) == 0) { X = 1; } if (A(i + 1, j + 1, k + 1) == 0) { X = 1; } return X; } //------------------------------------------------------------------------------- inline Point VertexInterp(const Point &p1, const Point &p2, double valp1, double valp2) { return (p1 + (-valp1 / (valp2 - valp1)) * (p2 - p1)); } //------------------------------------------------------------------------------- inline void SolidMarchingCubes(DoubleArray &A, const double &v, DoubleArray &B, const double &isovalue, int i, int j, int k, int m, int n, int o, DTMutableList &cellvertices, int &lengthvertices, IntArray &Triangles, int &nTris, DoubleArray &values) { NULL_USE(isovalue); NULL_USE(m); NULL_USE(n); NULL_USE(o); // THIS SUBROUTINE COMPUTES THE VERTICES FOR THE SOLID PHASE IN // A PARTICULAR GRID CELL, THEN ARRANGES THEM INTO TRIANGLES // ALSO ORGANIZES THE LIST OF VALUES TO CORRESPOND WITH VERTEX LIST NULL_USE(v); //int N = 0; Point P, Q; Point PlaceHolder; //int pos = lengthvertices; double temp; Point C0, C1, C2, C3, C4, C5, C6, C7; int TriangleCount; int NewVertexCount; int CubeIndex; Point VertexList[12]; Point NewVertexList[12]; double ValueList[12]; double NewValueList[12]; int LocalRemap[12]; // int m; int n; int o; //int p; int q; // Values from array 'A' at the cube corners double CubeValues[8]; CubeValues[0] = A(i, j, k); CubeValues[1] = A(i + 1, j, k); CubeValues[2] = A(i + 1, j + 1, k); CubeValues[3] = A(i, j + 1, k); CubeValues[4] = A(i, j, k + 1); CubeValues[5] = A(i + 1, j, k + 1); CubeValues[6] = A(i + 1, j + 1, k + 1); CubeValues[7] = A(i, j + 1, k + 1); // Values from array 'B' at the cube corners double CubeValues_B[8]; CubeValues_B[0] = B(i, j, k); CubeValues_B[1] = B(i + 1, j, k); CubeValues_B[2] = B(i + 1, j + 1, k); CubeValues_B[3] = B(i, j + 1, k); CubeValues_B[4] = B(i, j, k + 1); CubeValues_B[5] = B(i + 1, j, k + 1); CubeValues_B[6] = B(i + 1, j + 1, k + 1); CubeValues_B[7] = B(i, j + 1, k + 1); // Points corresponding to cube corners C0.x = 0.0; C0.y = 0.0; C0.z = 0.0; C1.x = 1.0; C1.y = 0.0; C1.z = 0.0; C2.x = 1.0; C2.y = 1.0; C2.z = 0.0; C3.x = 0.0; C3.y = 1.0; C3.z = 0.0; C4.x = 0.0; C4.y = 0.0; C4.z = 1.0; C5.x = 1.0; C5.y = 0.0; C5.z = 1.0; C6.x = 1.0; C6.y = 1.0; C6.z = 1.0; C7.x = 0.0; C7.y = 1.0; C7.z = 1.0; //Determine the index into the edge table which //tells us which vertices are inside of the surface CubeIndex = 0; if (CubeValues[0] < 0.0f) CubeIndex |= 1; if (CubeValues[1] < 0.0f) CubeIndex |= 2; if (CubeValues[2] < 0.0f) CubeIndex |= 4; if (CubeValues[3] < 0.0f) CubeIndex |= 8; if (CubeValues[4] < 0.0f) CubeIndex |= 16; if (CubeValues[5] < 0.0f) CubeIndex |= 32; if (CubeValues[6] < 0.0f) CubeIndex |= 64; if (CubeValues[7] < 0.0f) CubeIndex |= 128; //Find the vertices where the surface intersects the cube if (edgeTable[CubeIndex] & 1) { P = VertexInterp(C0, C1, CubeValues[0], CubeValues[1]); VertexList[0] = P; Q = C0; temp = sqrt((P.x - Q.x) * (P.x - Q.x) + (P.y - Q.y) * (P.y - Q.y) + (P.z - Q.z) * (P.z - Q.z)); ValueList[0] = CubeValues_B[0] + temp * (CubeValues_B[1] - CubeValues_B[0]); } if (edgeTable[CubeIndex] & 2) { P = VertexInterp(C1, C2, CubeValues[1], CubeValues[2]); VertexList[1] = P; Q = C1; temp = sqrt((P.x - Q.x) * (P.x - Q.x) + (P.y - Q.y) * (P.y - Q.y) + (P.z - Q.z) * (P.z - Q.z)); ValueList[1] = CubeValues_B[1] + temp * (CubeValues_B[2] - CubeValues_B[1]); } if (edgeTable[CubeIndex] & 4) { P = VertexInterp(C2, C3, CubeValues[2], CubeValues[3]); VertexList[2] = P; Q = C2; temp = sqrt((P.x - Q.x) * (P.x - Q.x) + (P.y - Q.y) * (P.y - Q.y) + (P.z - Q.z) * (P.z - Q.z)); ValueList[2] = CubeValues_B[2] + temp * (CubeValues_B[3] - CubeValues_B[2]); } if (edgeTable[CubeIndex] & 8) { P = VertexInterp(C3, C0, CubeValues[3], CubeValues[0]); VertexList[3] = P; Q = C3; temp = sqrt((P.x - Q.x) * (P.x - Q.x) + (P.y - Q.y) * (P.y - Q.y) + (P.z - Q.z) * (P.z - Q.z)); ValueList[3] = CubeValues_B[3] + temp * (CubeValues_B[0] - CubeValues_B[3]); } if (edgeTable[CubeIndex] & 16) { P = VertexInterp(C4, C5, CubeValues[4], CubeValues[5]); VertexList[4] = P; Q = C4; temp = sqrt((P.x - Q.x) * (P.x - Q.x) + (P.y - Q.y) * (P.y - Q.y) + (P.z - Q.z) * (P.z - Q.z)); ValueList[4] = CubeValues_B[4] + temp * (CubeValues_B[5] - CubeValues_B[4]); } if (edgeTable[CubeIndex] & 32) { P = VertexInterp(C5, C6, CubeValues[5], CubeValues[6]); VertexList[5] = P; Q = C5; temp = sqrt((P.x - Q.x) * (P.x - Q.x) + (P.y - Q.y) * (P.y - Q.y) + (P.z - Q.z) * (P.z - Q.z)); ValueList[5] = CubeValues_B[5] + temp * (CubeValues_B[6] - CubeValues_B[5]); } if (edgeTable[CubeIndex] & 64) { P = VertexInterp(C6, C7, CubeValues[6], CubeValues[7]); VertexList[6] = P; Q = C6; temp = sqrt((P.x - Q.x) * (P.x - Q.x) + (P.y - Q.y) * (P.y - Q.y) + (P.z - Q.z) * (P.z - Q.z)); ValueList[6] = CubeValues_B[6] + temp * (CubeValues_B[7] - CubeValues_B[6]); } if (edgeTable[CubeIndex] & 128) { P = VertexInterp(C7, C4, CubeValues[7], CubeValues[4]); VertexList[7] = P; Q = C7; temp = sqrt((P.x - Q.x) * (P.x - Q.x) + (P.y - Q.y) * (P.y - Q.y) + (P.z - Q.z) * (P.z - Q.z)); ValueList[7] = CubeValues_B[7] + temp * (CubeValues_B[4] - CubeValues_B[7]); } if (edgeTable[CubeIndex] & 256) { P = VertexInterp(C0, C4, CubeValues[0], CubeValues[4]); VertexList[8] = P; Q = C0; temp = sqrt((P.x - Q.x) * (P.x - Q.x) + (P.y - Q.y) * (P.y - Q.y) + (P.z - Q.z) * (P.z - Q.z)); ValueList[8] = CubeValues_B[0] + temp * (CubeValues_B[4] - CubeValues_B[0]); } if (edgeTable[CubeIndex] & 512) { P = VertexInterp(C1, C5, CubeValues[1], CubeValues[5]); VertexList[9] = P; Q = C1; temp = sqrt((P.x - Q.x) * (P.x - Q.x) + (P.y - Q.y) * (P.y - Q.y) + (P.z - Q.z) * (P.z - Q.z)); ValueList[9] = CubeValues_B[1] + temp * (CubeValues_B[5] - CubeValues_B[1]); } if (edgeTable[CubeIndex] & 1024) { P = VertexInterp(C2, C6, CubeValues[2], CubeValues[6]); VertexList[10] = P; Q = C2; temp = sqrt((P.x - Q.x) * (P.x - Q.x) + (P.y - Q.y) * (P.y - Q.y) + (P.z - Q.z) * (P.z - Q.z)); ValueList[10] = CubeValues_B[2] + temp * (CubeValues_B[6] - CubeValues_B[2]); } if (edgeTable[CubeIndex] & 2048) { P = VertexInterp(C3, C7, CubeValues[3], CubeValues[7]); VertexList[11] = P; Q = C3; temp = sqrt((P.x - Q.x) * (P.x - Q.x) + (P.y - Q.y) * (P.y - Q.y) + (P.z - Q.z) * (P.z - Q.z)); ValueList[11] = CubeValues_B[3] + temp * (CubeValues_B[7] - CubeValues_B[3]); } NewVertexCount = 0; for (int idx = 0; idx < 12; idx++) LocalRemap[idx] = -1; for (int idx = 0; triTable[CubeIndex][idx] != -1; idx++) { if (LocalRemap[triTable[CubeIndex][idx]] == -1) { NewVertexList[NewVertexCount] = VertexList[triTable[CubeIndex][idx]]; NewValueList[NewVertexCount] = ValueList[triTable[CubeIndex][idx]]; LocalRemap[triTable[CubeIndex][idx]] = NewVertexCount; NewVertexCount++; } } for (int idx = 0; idx < NewVertexCount; idx++) { P = NewVertexList[idx]; P.x += i; P.y += j; P.z += k; cellvertices(idx) = P; values(idx) = NewValueList[idx]; } lengthvertices = NewVertexCount; TriangleCount = 0; for (int idx = 0; triTable[CubeIndex][idx] != -1; idx += 3) { Triangles(0, TriangleCount) = LocalRemap[triTable[CubeIndex][idx + 0]]; Triangles(1, TriangleCount) = LocalRemap[triTable[CubeIndex][idx + 1]]; Triangles(2, TriangleCount) = LocalRemap[triTable[CubeIndex][idx + 2]]; TriangleCount++; } nTris = TriangleCount; // * * * ARRANGE VERTICES SO THAT NEIGHBORS SHARE A FACE * * * // * * * PERFORM SAME OPERATIONS TO THE LIST OF VALUES * * * /* pos = N = lengthvertices; for (q = pos-N; q < pos-2; q++) { for (o = q+2; o < pos-1; o++) { if (ShareSide(cellvertices(q), cellvertices(o)) == 1) { PlaceHolder = cellvertices(q+1); cellvertices(q+1) = cellvertices(o); cellvertices(o) = PlaceHolder; temp = values(q+1); values(q+1) = values(o); values(o) = temp; // Swap the triangle lists as needed for (int idx=0; idx &cellvertices, int &lengthvertices, IntArray &Tlist, int &nTris, DoubleArray &values) { NULL_USE(isovalue); NULL_USE(m); NULL_USE(n); NULL_USE(o); // THIS SUBROUTINE COMPUTES THE VERTICES FOR THE SOLID PHASE IN // A PARTICULAR GRID CELL, THEN ARRANGES THEM INTO TRIANGLES // ALSO ORGANIZES THE LIST OF VALUES TO CORRESPOND WITH VERTEX LIST int N = 0; Point P; Point PlaceHolder; int pos = lengthvertices; float temp; // int m; int n; int o; int p; int q; // for each leg of the triangle, see if a vertex exists // if so, find the vertex, and perform an extrapolation // Go over each corner -- check to see if the corners are themselves vertices //1 if (A(i, j, k) == v) { P.x = i; P.y = j; P.z = k; values(pos) = B(i, j, k); cellvertices(pos++) = P; N++; } //2 if (A(i + 1, j, k) == v) { P.x = i + 1; P.y = j; P.z = k; values(pos) = B(i + 1, j, k); cellvertices(pos++) = P; N++; } //3 if (A(i + 1, j + 1, k) == v) { P.x = i + 1; P.y = j + 1; P.z = k; values(pos) = B(i + 1, j + 1, k); cellvertices(pos++) = P; N++; } //4 if (A(i, j + 1, k) == v) { P.x = i; P.y = j + 1; P.z = k; values(pos) = B(i, j + 1, k); cellvertices(pos++) = P; N++; } //5 if (A(i, j, k + 1) == v) { P.x = i; P.y = j; P.z = k + 1; values(pos) = B(i, j, k + 1); cellvertices(pos++) = P; N++; } //6 if (A(i + 1, j, k + 1) == v) { P.x = i + 1; P.y = j; P.z = k + 1; values(pos) = B(i + 1, j, k + 1); cellvertices(pos++) = P; N++; } //7 if (A(i + 1, j + 1, k + 1) == v) { P.x = i + 1; P.y = j + 1; P.z = k + 1; values(pos) = B(i + 1, j + 1, k + 1); cellvertices(pos++) = P; N++; } //8 if (A(i, j + 1, k + 1) == v) { P.x = i; P.y = j + 1; P.z = k + 1; values(pos) = B(i, j + 1, k + 1); cellvertices(pos++) = P; N++; } // Go through each side, compute P for sides of box spiraling up if ((A(i, j, k) - v) * (A(i + 1, j, k) - v) < 0) { P.x = i + (A(i, j, k) - v) / (A(i, j, k) - A(i + 1, j, k)); P.y = j; P.z = k; // compute extrapolated fluid value at P // if ( A(i,j,k) > v){ // values(pos) = EXTRAP(B, isovalue, i,j,k,4, P); // } // else{ // values(pos) = EXTRAP(B,isovalue, i+1,j,k, 1, P); // } // Interpolate value at P using padded mesh B values(pos) = B(i, j, k) * (1 - P.x + i) + B(i + 1, j, k) * (P.x - i); cellvertices(pos++) = P; N++; } // 2 if ((A(i + 1, j, k) - v) * (A(i + 1, j + 1, k) - v) < 0) { P.x = i + 1; P.y = j + (A(i + 1, j, k) - v) / (A(i + 1, j, k) - A(i + 1, j + 1, k)); P.z = k; if (vertexcheck(P, N, pos, cellvertices) == 1) { // P is a new vertex (not counted twice) // compute extrapolated fluid value at P // if ( A(i+1,j,k) > v){ // values(pos) = EXTRAP(B,isovalue, i+1,j,k, 5, P); // } // else{ // values(pos) = EXTRAP(B,isovalue, i+1,j+1,k, 2, P); // } // Interpolate value at P using padded mesh B values(pos) = B(i + 1, j, k) * (1 - P.y + j) + B(i + 1, j + 1, k) * (P.y - j); cellvertices(pos++) = P; N++; } } //3 if ((A(i + 1, j + 1, k) - v) * (A(i, j + 1, k) - v) < 0) { P.x = i + (A(i, j + 1, k) - v) / (A(i, j + 1, k) - A(i + 1, j + 1, k)); P.y = j + 1; P.z = k; if (vertexcheck(P, N, pos, cellvertices) == 1) { // P is a new vertex (not counted twice) // compute extrapolated fluid value at P // if ( A(i+1,j+1,k) > v){ // values(pos) = EXTRAP(B,isovalue, i+1,j+1,k, 1, P); // } // else{ // values(pos) = EXTRAP(B,isovalue, i,j+1,k, 4, P); // } // Interpolate value at P using padded mesh B values(pos) = B(i, j + 1, k) * (1 - P.x + i) + B(i + 1, j + 1, k) * (P.x - i); cellvertices(pos++) = P; N++; } } //4 if ((A(i, j + 1, k) - v) * (A(i, j, k) - v) < 0) { P.x = i; P.y = j + (A(i, j, k) - v) / (A(i, j, k) - A(i, j + 1, k)); P.z = k; if (vertexcheck(P, N, pos, cellvertices) == 1) { // P is a new vertex (not counted twice) // compute extrapolated fluid value at P // if ( A(i,j,k) > v){ // values(pos) = EXTRAP(B,isovalue, i,j,k, 5, P); // } // else{ // values(pos) = EXTRAP(B,isovalue, i,j+1,k, 2, P); // } // Interpolate value at P using padded mesh B values(pos) = B(i, j, k) * (1 - P.y + j) + B(i, j + 1, k) * (P.y - j); cellvertices(pos++) = P; N++; } } //5 if ((A(i, j, k) - v) * (A(i, j, k + 1) - v) < 0) { P.x = i; P.y = j; P.z = k + (A(i, j, k) - v) / (A(i, j, k) - A(i, j, k + 1)); if (vertexcheck(P, N, pos, cellvertices) == 1) { // P is a new vertex (not counted twice) // compute extrapolated fluid value at P // if ( A(i,j,k) > v){ // values(pos) = EXTRAP(B,isovalue, i,j,k, 6, P); // } // else{ // values(pos) = EXTRAP(B,isovalue, i,j,k+1, 3, P); // } // Interpolate value at P using padded mesh B values(pos) = B(i, j, k) * (1 - P.z + k) + B(i, j, k + 1) * (P.z - k); cellvertices(pos++) = P; N++; } } //6 if ((A(i + 1, j, k) - v) * (A(i + 1, j, k + 1) - v) < 0) { P.x = i + 1; P.y = j; P.z = k + (A(i + 1, j, k) - v) / (A(i + 1, j, k) - A(i + 1, j, k + 1)); if (vertexcheck(P, N, pos, cellvertices) == 1) { // P is a new vertex (not counted twice) // compute extrapolated fluid value at P // if ( A(i+1,j,k) > v){ // values(pos) = EXTRAP(B,isovalue, i+1,j,k, 6, P); // } // else{ // values(pos) = EXTRAP(B,isovalue, i+1,j,k+1, 3, P); // } // Interpolate value at P using padded mesh B values(pos) = B(i + 1, j, k) * (1 - P.z + k) + B(i + 1, j, k + 1) * (P.z - k); cellvertices(pos++) = P; N++; } } //7 if ((A(i + 1, j + 1, k) - v) * (A(i + 1, j + 1, k + 1) - v) < 0) { P.x = i + 1; P.y = j + 1; P.z = k + (A(i + 1, j + 1, k) - v) / (A(i + 1, j + 1, k) - A(i + 1, j + 1, k + 1)); if (vertexcheck(P, N, pos, cellvertices) == 1) { // P is a new vertex (not counted twice) // compute extrapolated fluid value at P // if ( A(i+1,j+1,k) > v){ // values(pos) = EXTRAP(B,isovalue, i+1,j+1,k, 6, P); // } // else{ // values(pos) = EXTRAP(B,isovalue, i+1,j+1,k+1, 3, P); // } // Interpolate value at P using padded mesh B values(pos) = B(i + 1, j + 1, k) * (1 - P.z + k) + B(i + 1, j + 1, k + 1) * (P.z - k); cellvertices(pos++) = P; N++; } } //8 if ((A(i, j + 1, k) - v) * (A(i, j + 1, k + 1) - v) < 0) { P.x = i; P.y = j + 1; P.z = k + (A(i, j + 1, k) - v) / (A(i, j + 1, k) - A(i, j + 1, k + 1)); if (vertexcheck(P, N, pos, cellvertices) == 1) { // P is a new vertex (not counted twice) // compute extrapolated fluid value at P // if ( A(i,j+1,k) > v){ // values(pos) = EXTRAP(B,isovalue, i,j+1,k, 6, P); // } // else{ // values(pos) = EXTRAP(B,isovalue, i,j+1,k+1, 3, P); // } // Interpolate value at P using padded mesh B values(pos) = B(i, j + 1, k) * (1 - P.z + k) + B(i, j + 1, k + 1) * (P.z - k); cellvertices(pos++) = P; N++; } } //9 if ((A(i, j, k + 1) - v) * (A(i + 1, j, k + 1) - v) < 0) { P.x = i + (A(i, j, k + 1) - v) / (A(i, j, k + 1) - A(i + 1, j, k + 1)); P.y = j; P.z = k + 1; if (vertexcheck(P, N, pos, cellvertices) == 1) { // P is a new vertex (not counted twice) // compute extrapolated fluid value at P // if ( A(i,j,k+1) > v){ // values(pos) = EXTRAP(B,isovalue, i,j,k+1, 4, P); // } // else{ // values(pos) = EXTRAP(B,isovalue, i+1,j,k+1, 1, P); // } // Interpolate value at P using padded mesh B values(pos) = B(i, j, k + 1) * (1 - P.x + i) + B(i + 1, j, k + 1) * (P.x - i); cellvertices(pos++) = P; N++; } } //10 if ((A(i + 1, j, k + 1) - v) * (A(i + 1, j + 1, k + 1) - v) < 0) { P.x = i + 1; P.y = j + (A(i + 1, j, k + 1) - v) / (A(i + 1, j, k + 1) - A(i + 1, j + 1, k + 1)); P.z = k + 1; if (vertexcheck(P, N, pos, cellvertices) == 1) { // P is a new vertex (not counted twice) // compute extrapolated fluid value at P // if ( A(i+1,j,k+1) > v){ // values(pos) = EXTRAP(B,isovalue, i+1,j,k+1, 5, P); // } // else{ // values(pos) = EXTRAP(B,isovalue, i+1,j+1,k+1, 2, P); // } // Interpolate value at P using padded mesh B values(pos) = B(i + 1, j, k + 1) * (1 - P.y + j) + B(i + 1, j + 1, k + 1) * (P.y - j); cellvertices(pos++) = P; N++; } } //11 if ((A(i + 1, j + 1, k + 1) - v) * (A(i, j + 1, k + 1) - v) < 0) { P.x = i + (A(i, j + 1, k + 1) - v) / (A(i, j + 1, k + 1) - A(i + 1, j + 1, k + 1)); P.y = j + 1; P.z = k + 1; if (vertexcheck(P, N, pos, cellvertices) == 1) { // P is a new vertex (not counted twice) // compute extrapolated fluid value at P // if ( A(i,j+1,k+1) > v){ // values(pos) = EXTRAP(B,isovalue, i,j+1,k+1, 4, P); // } // else{ // values(pos) = EXTRAP(B,isovalue, i+1,j+1,k+1, 1, P); // } // Interpolate value at P using padded mesh B values(pos) = B(i, j + 1, k + 1) * (1 - P.x + i) + B(i + 1, j + 1, k + 1) * (P.x - i); cellvertices(pos++) = P; N++; } } //12 if ((A(i, j + 1, k + 1) - v) * (A(i, j, k + 1) - v) < 0) { P.x = i; P.y = j + (A(i, j, k + 1) - v) / (A(i, j, k + 1) - A(i, j + 1, k + 1)); P.z = k + 1; if (vertexcheck(P, N, pos, cellvertices) == 1) { // P is a new vertex (not counted twice) // compute extrapolated fluid value at P // if ( A(i,j,k+1) > v){ // values(pos) = EXTRAP(B,isovalue, i,j,k+1, 5, P); // } // else{ // values(pos) = EXTRAP(B,isovalue, i,j+1,k+1, 2, P); // } // Interpolate value at P using padded mesh B values(pos) = B(i, j, k + 1) * (1 - P.y + j) + B(i, j + 1, k + 1) * (P.y - j); cellvertices(pos++) = P; N++; } } lengthvertices = pos; // * * * ARRANGE VERTICES SO THAT NEIGHBORS SHARE A FACE * * * // * * * PERFORM SAME OPERATIONS TO THE LIST OF VALUES * * * for (q = pos - N; q < pos - 2; q++) { for (o = q + 2; o < pos - 1; o++) { if (ShareSide(cellvertices(q), cellvertices(o)) == 1) { PlaceHolder = cellvertices(q + 1); cellvertices(q + 1) = cellvertices(o); cellvertices(o) = PlaceHolder; temp = values(q + 1); values(q + 1) = values(o); values(o) = temp; } } // make sure other neighbor of vertex 1 is in last spot if (q == pos - N) { for (p = q + 2; p < pos - 1; p++) { if (ShareSide(cellvertices(q), cellvertices(p)) == 1) { PlaceHolder = cellvertices(pos - 1); cellvertices(pos - 1) = cellvertices(p); cellvertices(p) = PlaceHolder; temp = values(pos - 1); values(pos - 1) = values(p); values(p) = temp; } } } if (ShareSide(cellvertices(pos - 2), cellvertices(pos - 3)) != 1) { if (ShareSide(cellvertices(pos - 3), cellvertices(pos - 1)) == 1 && ShareSide(cellvertices(pos - N), cellvertices(pos - 2)) == 1) { PlaceHolder = cellvertices(pos - 2); cellvertices(pos - 2) = cellvertices(pos - 1); cellvertices(pos - 1) = PlaceHolder; temp = values(pos - 2); values(pos - 2) = values(pos - 1); values(pos - 1) = temp; } } if (ShareSide(cellvertices(pos - 1), cellvertices(pos - 2)) != 1) { if (ShareSide(cellvertices(pos - 3), cellvertices(pos - 1)) == 1 && ShareSide(cellvertices(pos - 4), cellvertices(pos - 2)) == 1) { PlaceHolder = cellvertices(pos - 3); cellvertices(pos - 3) = cellvertices(pos - 2); cellvertices(pos - 2) = PlaceHolder; temp = values(pos - 3); values(pos - 3) = values(pos - 2); values(pos - 2) = temp; } if (ShareSide(cellvertices(pos - N + 1), cellvertices(pos - 3)) == 1 && ShareSide(cellvertices(pos - 1), cellvertices(pos - N + 1)) == 1) { PlaceHolder = cellvertices(pos - 2); cellvertices(pos - 2) = cellvertices(pos - N + 1); cellvertices(pos - N + 1) = PlaceHolder; temp = values(pos - 2); values(pos - 2) = values(pos - N + 1); values(pos - N + 1) = temp; } } if (ShareSide(cellvertices(pos - N), cellvertices(pos - N + 1)) != 1) { if (ShareSide(cellvertices(pos - N), cellvertices(pos - 2)) == 1 && ShareSide(cellvertices(pos - 1), cellvertices(pos - N + 1)) == 1) { PlaceHolder = cellvertices(pos - 1); cellvertices(pos - 1) = cellvertices(pos - N); cellvertices(pos - N) = PlaceHolder; temp = values(pos - 1); values(pos - 1) = values(pos - N); values(pos - N) = temp; } } } // * * * ESTABLISH TRIANGLE CONNECTIONS * * * for (p = pos - N + 2; p < pos; p++) { Tlist(0, nTris) = pos - N; Tlist(1, nTris) = p - 1; Tlist(2, nTris) = p; nTris++; } } //------------------------------------------------------------------------------- /*inline void TRIM(DTMutableList &local_sol_pts, int &n_local_sol_pts, double isovalue, IntArray &local_sol_tris, int &n_local_sol_tris, DTMutableList &ns_pts, int &n_ns_pts, IntArray &ns_tris, int &n_ns_tris, DTMutableList &ws_pts, int &n_ws_pts, IntArray &ws_tris, int &n_ws_tris, DoubleArray &values, DTMutableList &local_nws_pts, int &n_local_nws_pts, DoubleArray &fluid_pad, DoubleArray &S, int &i, int &j, int &k, int &newton_steps) inline void TRIM(DTMutableList &local_sol_pts, int &n_local_sol_pts, double isovalue, DTMutableIntArray &local_sol_tris, int &n_local_sol_tris, DTMutableList &ns_pts, int &n_ns_pts, DTMutableIntArray &ns_tris, int &n_ns_tris, DTMutableList &ws_pts, int &n_ws_pts, DTMutableIntArray &ws_tris, int &n_ws_tris, DTFloatArray &values, DTMutableList &local_nws_pts, int &n_local_nws_pts) */ //------------------------------------------------------------------------------- inline void TRIM(DTMutableList &local_sol_pts, int &n_local_sol_pts, double isovalue, IntArray &local_sol_tris, int &n_local_sol_tris, DTMutableList &ns_pts, int &n_ns_pts, IntArray &ns_tris, int &n_ns_tris, DTMutableList &ws_pts, int &n_ws_pts, IntArray &ws_tris, int &n_ws_tris, DoubleArray &values, DTMutableList &local_nws_pts, int &n_local_nws_pts) { // Trim the local solid surface int map_ws; int map_ns; int p; int q; int a; int b; int c; Point A; Point B; Point C; Point D; Point E; Point P; bool all_to_ns = 1; // Check to see if all triangles in the cell are in ns_surface for (q = 0; q < n_local_sol_pts; q++) { if (values(q) < isovalue && all_to_ns == 1) { all_to_ns = 0; } } bool all_to_ws = 1; // Check to see if all triangles in the cell are in ws surface for (q = 0; q < n_local_sol_pts; q++) { if (values(q) > isovalue && all_to_ws == 1) { all_to_ws = 0; } } if (all_to_ws == 1) { map_ws = n_ws_pts; map_ws = 0; for (p = 0; p < n_local_sol_pts; p++) { ws_pts(n_ws_pts++) = local_sol_pts(p); } for (p = 0; p < n_local_sol_tris; p++) { ws_tris(0, n_ws_tris) = local_sol_tris(0, p) + map_ws; ws_tris(1, n_ws_tris) = local_sol_tris(1, p) + map_ws; ws_tris(2, n_ws_tris) = local_sol_tris(2, p) + map_ws; n_ws_tris++; } } else if (all_to_ns == 1) { map_ns = n_ns_pts; map_ns = 0; for (p = 0; p < n_local_sol_pts; p++) { ns_pts(n_ns_pts++) = local_sol_pts(p); } for (p = 0; p < n_local_sol_tris; p++) { ns_tris(0, n_ns_tris) = local_sol_tris(0, p) + map_ns; ns_tris(1, n_ns_tris) = local_sol_tris(1, p) + map_ns; ns_tris(2, n_ns_tris) = local_sol_tris(2, p) + map_ns; n_ns_tris++; } } else { // this section of surface contains a common line map_ns = n_ns_tris; map_ws = n_ws_tris; // Go through all triangles for (p = 0; p < n_local_sol_tris; p++) { a = local_sol_tris(0, p); b = local_sol_tris(1, p); c = local_sol_tris(2, p); A = local_sol_pts(a); B = local_sol_pts(b); C = local_sol_pts(c); if (values(a) > isovalue && values(b) > isovalue && values(c) > isovalue) { // Triangle is in ns surface // Add points ns_pts(n_ns_pts++) = A; ns_pts(n_ns_pts++) = B; ns_pts(n_ns_pts++) = C; // Add triangles ns_tris(0, n_ns_tris) = n_ns_pts - 3; ns_tris(1, n_ns_tris) = n_ns_pts - 2; ns_tris(2, n_ns_tris) = n_ns_pts - 1; n_ns_tris++; } else if (values(a) < isovalue && values(b) < isovalue && values(c) < isovalue) { // Triangle is in ws surface // Add points ws_pts(n_ws_pts++) = A; ws_pts(n_ws_pts++) = B; ws_pts(n_ws_pts++) = C; // Add triangles ws_tris(0, n_ws_tris) = n_ws_pts - 3; ws_tris(1, n_ws_tris) = n_ws_pts - 2; ws_tris(2, n_ws_tris) = n_ws_pts - 1; n_ws_tris++; } else { // Triangle contains common line //////////////////////////////////////// ///////// FIND THE COMMON LINE ///////// //////////////////////////////////////// if ((values(a) - isovalue) * (values(b) - isovalue) < 0) { // compute common line vertex // P = A + (values(a) - isovalue)/(values(a)-values(b))*(B-A); P.x = A.x + (values(a) - isovalue) / (values(a) - values(b)) * (B.x - A.x); P.y = A.y + (values(a) - isovalue) / (values(a) - values(b)) * (B.y - A.y); P.z = A.z + (values(a) - isovalue) / (values(a) - values(b)) * (B.z - A.z); local_nws_pts(n_local_nws_pts++) = P; /* if ( n_local_nws_pts == 0 ){ local_nws_pts(n_local_nws_pts++) = P; } else if ( P != local_nws_pts(n_local_nws_pts-1) ){ local_nws_pts(n_local_nws_pts++) = P; } */ } if ((values(b) - isovalue) * (values(c) - isovalue) < 0) { // compute common line vertex // P = B + (values(b) - isovalue)/(values(b)-values(c))*(C-B); P.x = B.x + (values(b) - isovalue) / (values(b) - values(c)) * (C.x - B.x); P.y = B.y + (values(b) - isovalue) / (values(b) - values(c)) * (C.y - B.y); P.z = B.z + (values(b) - isovalue) / (values(b) - values(c)) * (C.z - B.z); local_nws_pts(n_local_nws_pts++) = P; /* if ( n_local_nws_pts == 0 ){ local_nws_pts(n_local_nws_pts++) = P; } else if ( P != local_nws_pts(n_local_nws_pts-1) ){ local_nws_pts(n_local_nws_pts++) = P; } */ } if ((values(a) - isovalue) * (values(c) - isovalue) < 0) { // compute common line vertex // P = A + (values(a) - isovalue)/(values(a)-values(c))*(C-A); P.x = A.x + (values(a) - isovalue) / (values(a) - values(c)) * (C.x - A.x); P.y = A.y + (values(a) - isovalue) / (values(a) - values(c)) * (C.y - A.y); P.z = A.z + (values(a) - isovalue) / (values(a) - values(c)) * (C.z - A.z); local_nws_pts(n_local_nws_pts++) = P; } // Store common line points as D and E D = local_nws_pts(n_local_nws_pts - 2); E = local_nws_pts(n_local_nws_pts - 1); // Construct the new triangles if ((values(a) - isovalue) * (values(b) - isovalue) < 0 && (values(b) - isovalue) * (values(c) - isovalue) < 0) { if (values(b) > isovalue) { // Points ns_pts(n_ns_pts++) = B; ns_pts(n_ns_pts++) = D; ns_pts(n_ns_pts++) = E; // Triangles ns_tris(0, n_ns_tris) = n_ns_pts - 3; // B ns_tris(1, n_ns_tris) = n_ns_pts - 2; // D ns_tris(2, n_ns_tris) = n_ns_pts - 1; // E n_ns_tris++; // Points ws_pts(n_ws_pts++) = A; ws_pts(n_ws_pts++) = C; ws_pts(n_ws_pts++) = D; ws_pts(n_ws_pts++) = E; // Triangles (A,C,D),(C,D,E) ws_tris(0, n_ws_tris) = n_ws_pts - 4; // A ws_tris(1, n_ws_tris) = n_ws_pts - 3; // C ws_tris(2, n_ws_tris) = n_ws_pts - 2; // D n_ws_tris++; ws_tris(0, n_ws_tris) = n_ws_pts - 3; // C ws_tris(1, n_ws_tris) = n_ws_pts - 2; // D ws_tris(2, n_ws_tris) = n_ws_pts - 1; // E n_ws_tris++; } else { // Points ws_pts(n_ws_pts++) = B; ws_pts(n_ws_pts++) = D; ws_pts(n_ws_pts++) = E; // Triangles ws_tris(0, n_ws_tris) = n_ws_pts - 3; // B ws_tris(1, n_ws_tris) = n_ws_pts - 2; // D ws_tris(2, n_ws_tris) = n_ws_pts - 1; // E n_ws_tris++; // Points ns_pts(n_ns_pts++) = A; ns_pts(n_ns_pts++) = C; ns_pts(n_ns_pts++) = D; ns_pts(n_ns_pts++) = E; // Triangles (A,C,D),(C,D,E) ns_tris(0, n_ns_tris) = n_ns_pts - 4; // A ns_tris(1, n_ns_tris) = n_ns_pts - 3; // C ns_tris(2, n_ns_tris) = n_ns_pts - 2; // D n_ns_tris++; ns_tris(0, n_ns_tris) = n_ns_pts - 3; // C ns_tris(1, n_ns_tris) = n_ns_pts - 1; // E ns_tris(2, n_ns_tris) = n_ns_pts - 2; // D n_ns_tris++; } } else if ((values(a) - isovalue) * (values(b) - isovalue) < 0 && (values(a) - isovalue) * (values(c) - isovalue) < 0) { if (values(a) > isovalue) { // Points ns_pts(n_ns_pts++) = A; ns_pts(n_ns_pts++) = D; ns_pts(n_ns_pts++) = E; // Triangles ns_tris(0, n_ns_tris) = n_ns_pts - 3; // A ns_tris(1, n_ns_tris) = n_ns_pts - 2; // D ns_tris(2, n_ns_tris) = n_ns_pts - 1; // E n_ns_tris++; // Points ws_pts(n_ws_pts++) = B; ws_pts(n_ws_pts++) = C; ws_pts(n_ws_pts++) = D; ws_pts(n_ws_pts++) = E; // Triangles (B,C,D),(C,D,E) ws_tris(0, n_ws_tris) = n_ws_pts - 4; // B ws_tris(1, n_ws_tris) = n_ws_pts - 2; // D ws_tris(2, n_ws_tris) = n_ws_pts - 3; // C n_ws_tris++; ws_tris(0, n_ws_tris) = n_ws_pts - 3; // C ws_tris(1, n_ws_tris) = n_ws_pts - 2; // D ws_tris(2, n_ws_tris) = n_ws_pts - 1; // E n_ws_tris++; } else { // Points ws_pts(n_ws_pts++) = A; ws_pts(n_ws_pts++) = D; ws_pts(n_ws_pts++) = E; // Triangles ws_tris(0, n_ws_tris) = n_ws_pts - 3; // A ws_tris(1, n_ws_tris) = n_ws_pts - 2; // D ws_tris(2, n_ws_tris) = n_ws_pts - 1; // E n_ws_tris++; // Points ns_pts(n_ns_pts++) = B; ns_pts(n_ns_pts++) = C; ns_pts(n_ns_pts++) = D; ns_pts(n_ns_pts++) = E; // Triangles (B,C,D),(C,D,E) ns_tris(0, n_ns_tris) = n_ns_pts - 4; // B ns_tris(1, n_ns_tris) = n_ns_pts - 3; // C ns_tris(2, n_ns_tris) = n_ns_pts - 2; // D n_ns_tris++; ns_tris(0, n_ns_tris) = n_ns_pts - 3; // C ns_tris(1, n_ns_tris) = n_ns_pts - 1; // E ns_tris(2, n_ns_tris) = n_ns_pts - 2; // D n_ns_tris++; } } else { if (values(c) > isovalue) { // Points ns_pts(n_ns_pts++) = C; ns_pts(n_ns_pts++) = D; ns_pts(n_ns_pts++) = E; // Triangles ns_tris(0, n_ns_tris) = n_ns_pts - 3; // C ns_tris(1, n_ns_tris) = n_ns_pts - 2; // D ns_tris(2, n_ns_tris) = n_ns_pts - 1; // E n_ns_tris++; // Points ws_pts(n_ws_pts++) = A; ws_pts(n_ws_pts++) = B; ws_pts(n_ws_pts++) = D; ws_pts(n_ws_pts++) = E; // Triangles (A,B,D),(A,D,E) ws_tris(0, n_ws_tris) = n_ws_pts - 4; // A ws_tris(1, n_ws_tris) = n_ws_pts - 3; // B ws_tris(2, n_ws_tris) = n_ws_pts - 2; // D n_ws_tris++; ws_tris(0, n_ws_tris) = n_ws_pts - 4; // A ws_tris(1, n_ws_tris) = n_ws_pts - 2; // D ws_tris(2, n_ws_tris) = n_ws_pts - 1; // E n_ws_tris++; } else { // Points ws_pts(n_ws_pts++) = C; ws_pts(n_ws_pts++) = D; ws_pts(n_ws_pts++) = E; // Triangles ws_tris(0, n_ws_tris) = n_ws_pts - 3; // C ws_tris(1, n_ws_tris) = n_ws_pts - 2; // D ws_tris(2, n_ws_tris) = n_ws_pts - 1; // E n_ws_tris++; // Points ns_pts(n_ns_pts++) = A; ns_pts(n_ns_pts++) = B; ns_pts(n_ns_pts++) = D; ns_pts(n_ns_pts++) = E; // Triangles (A,B,D),(A,D,E) ns_tris(0, n_ns_tris) = n_ns_pts - 4; // A ns_tris(1, n_ns_tris) = n_ns_pts - 3; // B ns_tris(2, n_ns_tris) = n_ns_pts - 2; // D n_ns_tris++; ns_tris(0, n_ns_tris) = n_ns_pts - 4; // A ns_tris(1, n_ns_tris) = n_ns_pts - 2; // D ns_tris(2, n_ns_tris) = n_ns_pts - 1; // E n_ns_tris++; } } } } } } inline double geomavg_MarchingCubes(DoubleArray &A, double &v, int &i, int &j, int &k, DTMutableList &nw_pts, int &n_nw_pts, IntArray &nw_tris, int &n_nw_tris) { int N = 0; // n will be the number of vertices in this grid cell only Point P; Point pt; Point PlaceHolder; int m; int o; int p; // Go over each corner -- check to see if the corners are themselves vertices //1 if (A(i, j, k) == v) { P.x = i; P.y = j; P.z = k; nw_pts(n_nw_pts++) = P; N++; } //2 if (A(i + 1, j, k) == v) { P.x = i + 1; P.y = j; P.z = k; nw_pts(n_nw_pts++) = P; N++; } //3 if (A(i + 1, j + 1, k) == v) { P.x = i + 1; P.y = j + 1; P.z = k; nw_pts(n_nw_pts++) = P; N++; } //4 if (A(i, j + 1, k) == v) { P.x = i; P.y = j + 1; P.z = k; nw_pts(n_nw_pts++) = P; N++; } //5 if (A(i, j, k + 1) == v) { P.x = i; P.y = j; P.z = k + 1; nw_pts(n_nw_pts++) = P; N++; } //6 if (A(i + 1, j, k + 1) == v) { P.x = i + 1; P.y = j; P.z = k + 1; nw_pts(n_nw_pts++) = P; N++; } //7 if (A(i + 1, j + 1, k + 1) == v) { P.x = i + 1; P.y = j + 1; P.z = k + 1; nw_pts(n_nw_pts++) = P; N++; } //8 if (A(i, j + 1, k + 1) == v) { P.x = i; P.y = j + 1; P.z = k + 1; nw_pts(n_nw_pts++) = P; N++; } // Go through each side, compute P for sides of box spiraling up // float val; if ((A(i, j, k) - v) * (A(i + 1, j, k) - v) < 0) { // If both points are in the fluid region if (A(i, j, k) != 0 && A(i + 1, j, k) != 0) { P.x = i + (A(i, j, k) - v) / (A(i, j, k) - A(i + 1, j, k)); P.y = j; P.z = k; nw_pts(n_nw_pts++) = P; N++; } } if ((A(i + 1, j, k) - v) * (A(i + 1, j + 1, k) - v) < 0) { if (A(i + 1, j, k) != 0 && A(i + 1, j + 1, k) != 0) { P.x = i + 1; P.y = j + (A(i + 1, j, k) - v) / (A(i + 1, j, k) - A(i + 1, j + 1, k)); P.z = k; if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { // P is a new vertex (not counted twice) nw_pts(n_nw_pts++) = P; N++; } } } if ((A(i + 1, j + 1, k) - v) * (A(i, j + 1, k) - v) < 0) { if (A(i + 1, j + 1, k) != 0 && A(i, j + 1, k) != 0) { P.x = i + (A(i, j + 1, k) - v) / (A(i, j + 1, k) - A(i + 1, j + 1, k)); P.y = j + 1; P.z = k; if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { // P is a new vertex (not counted twice) nw_pts(n_nw_pts++) = P; N++; } } } //4 if ((A(i, j + 1, k) - v) * (A(i, j, k) - v) < 0) { if (A(i, j + 1, k) != 0 && A(i, j, k) != 0) { P.x = i; P.y = j + (A(i, j, k) - v) / (A(i, j, k) - A(i, j + 1, k)); P.z = k; if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { // P is a new vertex (not counted twice) nw_pts(n_nw_pts++) = P; N++; } } } //5 if ((A(i, j, k) - v) * (A(i, j, k + 1) - v) < 0) { if (A(i, j, k) != 0 && A(i, j, k + 1) != 0) { P.x = i; P.y = j; P.z = k + (A(i, j, k) - v) / (A(i, j, k) - A(i, j, k + 1)); if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { // P is a new vertex (not counted twice) nw_pts(n_nw_pts++) = P; N++; } } } //6 if ((A(i + 1, j, k) - v) * (A(i + 1, j, k + 1) - v) < 0) { if (A(i + 1, j, k) != 0 && A(i + 1, j, k + 1) != 0) { P.x = i + 1; P.y = j; P.z = k + (A(i + 1, j, k) - v) / (A(i + 1, j, k) - A(i + 1, j, k + 1)); if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { nw_pts(n_nw_pts++) = P; N++; } } } //7 if ((A(i + 1, j + 1, k) - v) * (A(i + 1, j + 1, k + 1) - v) < 0) { if (A(i + 1, j + 1, k) != 0 && A(i + 1, j + 1, k + 1) != 0) { P.x = i + 1; P.y = j + 1; P.z = k + (A(i + 1, j + 1, k) - v) / (A(i + 1, j + 1, k) - A(i + 1, j + 1, k + 1)); if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { nw_pts(n_nw_pts++) = P; N++; } } } //8 if ((A(i, j + 1, k) - v) * (A(i, j + 1, k + 1) - v) < 0) { if (A(i, j + 1, k) != 0 && A(i, j + 1, k + 1) != 0) { P.x = i; P.y = j + 1; P.z = k + (A(i, j + 1, k) - v) / (A(i, j + 1, k) - A(i, j + 1, k + 1)); if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { nw_pts(n_nw_pts++) = P; N++; } } } //9 if ((A(i, j, k + 1) - v) * (A(i + 1, j, k + 1) - v) < 0) { if (A(i, j, k + 1) != 0 && A(i + 1, j, k + 1) != 0) { P.x = i + (A(i, j, k + 1) - v) / (A(i, j, k + 1) - A(i + 1, j, k + 1)); P.y = j; P.z = k + 1; if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { nw_pts(n_nw_pts++) = P; N++; } } } //10 if ((A(i + 1, j, k + 1) - v) * (A(i + 1, j + 1, k + 1) - v) < 0) { if (A(i + 1, j, k + 1) != 0 && A(i + 1, j + 1, k + 1) != 0) { P.x = i + 1; P.y = j + (A(i + 1, j, k + 1) - v) / (A(i + 1, j, k + 1) - A(i + 1, j + 1, k + 1)); P.z = k + 1; if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { nw_pts(n_nw_pts++) = P; N++; } } } //11 if ((A(i + 1, j + 1, k + 1) - v) * (A(i, j + 1, k + 1) - v) < 0) { if (A(i + 1, j + 1, k + 1) != 0 && A(i, j + 1, k + 1) != 0) { P.x = i + (A(i, j + 1, k + 1) - v) / (A(i, j + 1, k + 1) - A(i + 1, j + 1, k + 1)); P.y = j + 1; P.z = k + 1; if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { nw_pts(n_nw_pts++) = P; N++; } } } //12 if ((A(i, j + 1, k + 1) - v) * (A(i, j, k + 1) - v) < 0) { if (A(i, j + 1, k + 1) != 0 && A(i, j, k + 1) != 0) { P.x = i; P.y = j + (A(i, j, k + 1) - v) / (A(i, j, k + 1) - A(i, j + 1, k + 1)); P.z = k + 1; if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { nw_pts(n_nw_pts++) = P; N++; } } } // Assemble the triangles as long as points are found if (N > 0) { for (m = n_nw_pts - N; m < n_nw_pts - 2; m++) { for (o = m + 2; o < n_nw_pts - 1; o++) { if (ShareSide(nw_pts(m), nw_pts(o)) == 1) { PlaceHolder = nw_pts(m + 1); nw_pts(m + 1) = nw_pts(o); nw_pts(o) = PlaceHolder; } } // make sure other neighbor of vertex 1 is in last spot if (m == n_nw_pts - N) { for (p = m + 2; p < n_nw_pts - 1; p++) { if (ShareSide(nw_pts(m), nw_pts(p)) == 1) { PlaceHolder = nw_pts(n_nw_pts - 1); nw_pts(n_nw_pts - 1) = nw_pts(p); nw_pts(p) = PlaceHolder; } } } if (ShareSide(nw_pts(n_nw_pts - 2), nw_pts(n_nw_pts - 3)) != 1) { if (ShareSide(nw_pts(n_nw_pts - 3), nw_pts(n_nw_pts - 1)) == 1 && ShareSide(nw_pts(n_nw_pts - N), nw_pts(n_nw_pts - 2)) == 1) { PlaceHolder = nw_pts(n_nw_pts - 2); nw_pts(n_nw_pts - 2) = nw_pts(n_nw_pts - 1); nw_pts(n_nw_pts - 1) = PlaceHolder; } } if (ShareSide(nw_pts(n_nw_pts - 1), nw_pts(n_nw_pts - 2)) != 1) { if (ShareSide(nw_pts(n_nw_pts - 3), nw_pts(n_nw_pts - 1)) == 1 && ShareSide(nw_pts(n_nw_pts - 4), nw_pts(n_nw_pts - 2)) == 1) { PlaceHolder = nw_pts(n_nw_pts - 3); nw_pts(n_nw_pts - 3) = nw_pts(n_nw_pts - 2); nw_pts(n_nw_pts - 2) = PlaceHolder; } if (ShareSide(nw_pts(n_nw_pts - N + 1), nw_pts(n_nw_pts - 3)) == 1 && ShareSide(nw_pts(n_nw_pts - 1), nw_pts(n_nw_pts - N + 1)) == 1) { PlaceHolder = nw_pts(n_nw_pts - 2); nw_pts(n_nw_pts - 2) = nw_pts(n_nw_pts - N + 1); nw_pts(n_nw_pts - N + 1) = PlaceHolder; } } if (ShareSide(nw_pts(n_nw_pts - N), nw_pts(n_nw_pts - N + 1)) != 1) { if (ShareSide(nw_pts(n_nw_pts - N), nw_pts(n_nw_pts - 2)) == 1 && ShareSide(nw_pts(n_nw_pts - 1), nw_pts(n_nw_pts - N + 1)) == 1) { PlaceHolder = nw_pts(n_nw_pts - 1); nw_pts(n_nw_pts - 1) = nw_pts(n_nw_pts - N); nw_pts(n_nw_pts - N) = PlaceHolder; } } } // * * * ESTABLISH TRIANGLE CONNECTIONS * * * for (p = n_nw_pts - N + 2; p < n_nw_pts; p++) { nw_tris(0, n_nw_tris) = n_nw_pts - N; nw_tris(1, n_nw_tris) = p - 1; nw_tris(2, n_nw_tris) = p; n_nw_tris++; } } // Compute the Interfacial Area double s1, s2, s3, s; Point pA, pB, pC; double area = 0.0; for (int r = 0; r < n_nw_tris; r++) { pA = nw_pts(nw_tris(0, r)); pB = nw_pts(nw_tris(1, r)); pC = nw_pts(nw_tris(2, r)); // Compute length of sides (assume dx=dy=dz) s1 = sqrt((pA.x - pB.x) * (pA.x - pB.x) + (pA.y - pB.y) * (pA.y - pB.y) + (pA.z - pB.z) * (pA.z - pB.z)); s2 = sqrt((pA.x - pC.x) * (pA.x - pC.x) + (pA.y - pC.y) * (pA.y - pC.y) + (pA.z - pC.z) * (pA.z - pC.z)); s3 = sqrt((pB.x - pC.x) * (pB.x - pC.x) + (pB.y - pC.y) * (pB.y - pC.y) + (pB.z - pC.z) * (pB.z - pC.z)); s = 0.5 * (s1 + s2 + s3); area += sqrt(s * (s - s1) * (s - s2) * (s - s3)); } return area; } //------------------------------------------------------------------------------- inline void MC(DoubleArray &A, double &v, DoubleArray &solid, int &i, int &j, int &k, DTMutableList &nw_pts, int &n_nw_pts, IntArray &nw_tris, int &n_nw_tris) { int N = 0; // n will be the number of vertices in this grid cell only Point P; Point pt; DoubleArray TEST(3); Point PlaceHolder; int m; int o; int p; // Go over each corner -- check to see if the corners are themselves vertices //1 if (A(i, j, k) == v) { P.x = i; P.y = j; P.z = k; nw_pts(n_nw_pts++) = P; N++; } //2 if (A(i + 1, j, k) == v) { P.x = i + 1; P.y = j; P.z = k; nw_pts(n_nw_pts++) = P; N++; } //3 if (A(i + 1, j + 1, k) == v) { P.x = i + 1; P.y = j + 1; P.z = k; nw_pts(n_nw_pts++) = P; N++; } //4 if (A(i, j + 1, k) == v) { P.x = i; P.y = j + 1; P.z = k; nw_pts(n_nw_pts++) = P; N++; } //5 if (A(i, j, k + 1) == v) { P.x = i; P.y = j; P.z = k + 1; nw_pts(n_nw_pts++) = P; N++; } //6 if (A(i + 1, j, k + 1) == v) { P.x = i + 1; P.y = j; P.z = k + 1; nw_pts(n_nw_pts++) = P; N++; } //7 if (A(i + 1, j + 1, k + 1) == v) { P.x = i + 1; P.y = j + 1; P.z = k + 1; nw_pts(n_nw_pts++) = P; N++; } //8 if (A(i, j + 1, k + 1) == v) { P.x = i; P.y = j + 1; P.z = k + 1; nw_pts(n_nw_pts++) = P; N++; } // Go through each side, compute P for sides of box spiraling up // float val; if ((A(i, j, k) - v) * (A(i + 1, j, k) - v) < 0) { // If both points are in the fluid region if (A(i, j, k) != 0 && A(i + 1, j, k) != 0) { P.x = i + (A(i, j, k) - v) / (A(i, j, k) - A(i + 1, j, k)); P.y = j; P.z = k; // Evaluate the function S at the new point if (solid(i, j, k) * (1 - P.x + i) + solid(i + 1, j, k) * (P.x - i) > 0) { // This point is in the fluid region nw_pts(n_nw_pts++) = P; N++; } } } if ((A(i + 1, j, k) - v) * (A(i + 1, j + 1, k) - v) < 0) { if (A(i + 1, j, k) != 0 && A(i + 1, j + 1, k) != 0) { P.x = i + 1; P.y = j + (A(i + 1, j, k) - v) / (A(i + 1, j, k) - A(i + 1, j + 1, k)); P.z = k; // Evaluate the function S at the new point if (solid(i + 1, j, k) * (1 - P.y + j) + solid(i + 1, j + 1, k) * (P.y - j) > 0) { // This point is in the fluid region if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { // P is a new vertex (not counted twice) nw_pts(n_nw_pts++) = P; N++; } } } } if ((A(i + 1, j + 1, k) - v) * (A(i, j + 1, k) - v) < 0) { if (A(i + 1, j + 1, k) != 0 && A(i, j + 1, k) != 0) { P.x = i + (A(i, j + 1, k) - v) / (A(i, j + 1, k) - A(i + 1, j + 1, k)); P.y = j + 1; P.z = k; // Evaluate the function S at the new point if (solid(i, j + 1, k) * (1 - P.x + i) + solid(i + 1, j + 1, k) * (P.x - i) > 0) { // This point is in the fluid region if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { // P is a new vertex (not counted twice) nw_pts(n_nw_pts++) = P; N++; } } } } //4 if ((A(i, j + 1, k) - v) * (A(i, j, k) - v) < 0) { if (A(i, j + 1, k) != 0 && A(i, j, k) != 0) { P.x = i; P.y = j + (A(i, j, k) - v) / (A(i, j, k) - A(i, j + 1, k)); P.z = k; // Evaluate the function S at the new point if (solid(i, j, k) * (1 - P.y + j) + solid(i, j + 1, k) * (P.y - j) > 0) { // This point is in the fluid region if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { // P is a new vertex (not counted twice) nw_pts(n_nw_pts++) = P; N++; } } } } //5 if ((A(i, j, k) - v) * (A(i, j, k + 1) - v) < 0) { if (A(i, j, k) != 0 && A(i, j, k + 1) != 0) { P.x = i; P.y = j; P.z = k + (A(i, j, k) - v) / (A(i, j, k) - A(i, j, k + 1)); // Evaluate the function S at the new point if (solid(i, j, k) * (1 - P.z + k) + solid(i, j, k + 1) * (P.z - k) > 0) { // This point is in the fluid region if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { // P is a new vertex (not counted twice) nw_pts(n_nw_pts++) = P; N++; } } } } //6 if ((A(i + 1, j, k) - v) * (A(i + 1, j, k + 1) - v) < 0) { if (A(i + 1, j, k) != 0 && A(i + 1, j, k + 1) != 0) { P.x = i + 1; P.y = j; P.z = k + (A(i + 1, j, k) - v) / (A(i + 1, j, k) - A(i + 1, j, k + 1)); // Evaluate the function S at the new point if (solid(i + 1, j, k) * (1 - P.z + k) + solid(i + 1, j, k + 1) * (P.z - k) > 0) { // This point is in the fluid region if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { nw_pts(n_nw_pts++) = P; N++; } } } } //7 if ((A(i + 1, j + 1, k) - v) * (A(i + 1, j + 1, k + 1) - v) < 0) { if (A(i + 1, j + 1, k) != 0 && A(i + 1, j + 1, k + 1) != 0) { P.x = i + 1; P.y = j + 1; P.z = k + (A(i + 1, j + 1, k) - v) / (A(i + 1, j + 1, k) - A(i + 1, j + 1, k + 1)); // Evaluate the function S at the new point if (solid(i + 1, j + 1, k) * (1 - P.z + k) + solid(i + 1, j + 1, k + 1) * (P.z - k) > 0) { // This point is in the fluid region if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { nw_pts(n_nw_pts++) = P; N++; } } } } //8 if ((A(i, j + 1, k) - v) * (A(i, j + 1, k + 1) - v) < 0) { if (A(i, j + 1, k) != 0 && A(i, j + 1, k + 1) != 0) { P.x = i; P.y = j + 1; P.z = k + (A(i, j + 1, k) - v) / (A(i, j + 1, k) - A(i, j + 1, k + 1)); // Evaluate the function S at the new point if (solid(i, j + 1, k) * (1 - P.z + k) + solid(i, j + 1, k + 1) * (P.z - k) > 0) { // This point is in the fluid region if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { nw_pts(n_nw_pts++) = P; N++; } } } } //9 if ((A(i, j, k + 1) - v) * (A(i + 1, j, k + 1) - v) < 0) { if (A(i, j, k + 1) != 0 && A(i + 1, j, k + 1) != 0) { P.x = i + (A(i, j, k + 1) - v) / (A(i, j, k + 1) - A(i + 1, j, k + 1)); P.y = j; P.z = k + 1; // Evaluate the function S at the new point if (solid(i, j, k + 1) * (1 - P.x + i) + solid(i + 1, j, k + 1) * (P.x - i) > 0) { // This point is in the fluid region if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { nw_pts(n_nw_pts++) = P; N++; } } } } //10 if ((A(i + 1, j, k + 1) - v) * (A(i + 1, j + 1, k + 1) - v) < 0) { if (A(i + 1, j, k + 1) != 0 && A(i + 1, j + 1, k + 1) != 0) { P.x = i + 1; P.y = j + (A(i + 1, j, k + 1) - v) / (A(i + 1, j, k + 1) - A(i + 1, j + 1, k + 1)); P.z = k + 1; // Evaluate the function S at the new point if (solid(i + 1, j, k + 1) * (1 - P.y + j) + solid(i + 1, j + 1, k + 1) * (P.y - j) > 0) { // This point is in the fluid region if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { nw_pts(n_nw_pts++) = P; N++; } } } } //11 if ((A(i + 1, j + 1, k + 1) - v) * (A(i, j + 1, k + 1) - v) < 0) { if (A(i + 1, j + 1, k + 1) != 0 && A(i, j + 1, k + 1) != 0) { P.x = i + (A(i, j + 1, k + 1) - v) / (A(i, j + 1, k + 1) - A(i + 1, j + 1, k + 1)); P.y = j + 1; P.z = k + 1; // Evaluate the function S at the new point if (solid(i, j + 1, k + 1) * (1 - P.x + i) + solid(i + 1, j + 1, k + 1) * (P.x - i) > 0) { // This point is in the fluid region if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { nw_pts(n_nw_pts++) = P; N++; } } } } //12 if ((A(i, j + 1, k + 1) - v) * (A(i, j, k + 1) - v) < 0) { if (A(i, j + 1, k + 1) != 0 && A(i, j, k + 1) != 0) { P.x = i; P.y = j + (A(i, j, k + 1) - v) / (A(i, j, k + 1) - A(i, j + 1, k + 1)); P.z = k + 1; // Evaluate the function S at the new point if (solid(i, j, k + 1) * (1 - P.y + j) + solid(i, j + 1, k + 1) * (P.y - j) > 0) { // This point is in the fluid region if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { nw_pts(n_nw_pts++) = P; N++; } } } } // sort vertices so that they are connected to "neighbors" // DTMatlabDataFile("/tmp/Dump.mat",DTFile::NewReadWrite); // n_nw_pts = number of vertices in total (location n_nw_pts is first unfilled position) // n = number of vertices in this grid cell // Assemble the triangles as long as points are found if (N > 0) { for (m = n_nw_pts - N; m < n_nw_pts - 2; m++) { for (o = m + 2; o < n_nw_pts - 1; o++) { if (ShareSide(nw_pts(m), nw_pts(o)) == 1) { PlaceHolder = nw_pts(m + 1); nw_pts(m + 1) = nw_pts(o); nw_pts(o) = PlaceHolder; } } // make sure other neighbor of vertex 1 is in last spot if (m == n_nw_pts - N) { for (p = m + 2; p < n_nw_pts - 1; p++) { if (ShareSide(nw_pts(m), nw_pts(p)) == 1) { PlaceHolder = nw_pts(n_nw_pts - 1); nw_pts(n_nw_pts - 1) = nw_pts(p); nw_pts(p) = PlaceHolder; } } } if (ShareSide(nw_pts(n_nw_pts - 2), nw_pts(n_nw_pts - 3)) != 1) { if (ShareSide(nw_pts(n_nw_pts - 3), nw_pts(n_nw_pts - 1)) == 1 && ShareSide(nw_pts(n_nw_pts - N), nw_pts(n_nw_pts - 2)) == 1) { PlaceHolder = nw_pts(n_nw_pts - 2); nw_pts(n_nw_pts - 2) = nw_pts(n_nw_pts - 1); nw_pts(n_nw_pts - 1) = PlaceHolder; } } if (ShareSide(nw_pts(n_nw_pts - 1), nw_pts(n_nw_pts - 2)) != 1) { if (ShareSide(nw_pts(n_nw_pts - 3), nw_pts(n_nw_pts - 1)) == 1 && ShareSide(nw_pts(n_nw_pts - 4), nw_pts(n_nw_pts - 2)) == 1) { PlaceHolder = nw_pts(n_nw_pts - 3); nw_pts(n_nw_pts - 3) = nw_pts(n_nw_pts - 2); nw_pts(n_nw_pts - 2) = PlaceHolder; } if (ShareSide(nw_pts(n_nw_pts - N + 1), nw_pts(n_nw_pts - 3)) == 1 && ShareSide(nw_pts(n_nw_pts - 1), nw_pts(n_nw_pts - N + 1)) == 1) { PlaceHolder = nw_pts(n_nw_pts - 2); nw_pts(n_nw_pts - 2) = nw_pts(n_nw_pts - N + 1); nw_pts(n_nw_pts - N + 1) = PlaceHolder; } } if (ShareSide(nw_pts(n_nw_pts - N), nw_pts(n_nw_pts - N + 1)) != 1) { if (ShareSide(nw_pts(n_nw_pts - N), nw_pts(n_nw_pts - 2)) == 1 && ShareSide(nw_pts(n_nw_pts - 1), nw_pts(n_nw_pts - N + 1)) == 1) { PlaceHolder = nw_pts(n_nw_pts - 1); nw_pts(n_nw_pts - 1) = nw_pts(n_nw_pts - N); nw_pts(n_nw_pts - N) = PlaceHolder; } } } // * * * ESTABLISH TRIANGLE CONNECTIONS * * * for (p = n_nw_pts - N + 2; p < n_nw_pts; p++) { nw_tris(0, n_nw_tris) = n_nw_pts - N; nw_tris(1, n_nw_tris) = p - 1; nw_tris(2, n_nw_tris) = p; n_nw_tris++; } } } //------------------------------------------------------------------------------- inline void EDGE(DoubleArray &A, double &v, DoubleArray &solid, int &i, int &j, int &k, int &m, int &n, int &o, DTMutableList &nw_pts, int &n_nw_pts, IntArray &nw_tris, int &n_nw_tris, DTMutableList &local_nws_pts, int &n_local_nws_pts) { NULL_USE(m); NULL_USE(n); NULL_USE(o); // FIND THE POINTS ON THE nw SURFACE THAT ARE ON THE EDGE (COMMON LINE WITH SOLID PHASE) // function A is the fluid data padded (so that it has values inside the solid phase) int N = 0; // n will be the number of vertices in this grid cell only Point P; Point temp; int p; int q; int r; // Add common line points to nw_pts for (p = 0; p < n_local_nws_pts; p++) { nw_pts(n_nw_pts++) = local_nws_pts(p); } // Go over each corner -- check to see if the corners are themselves vertices //1 if (A(i, j, k) == v) { P.x = i; P.y = j; P.z = k; nw_pts(n_nw_pts++) = P; N++; } //2 if (A(i + 1, j, k) == v) { P.x = i + 1; P.y = j; P.z = k; nw_pts(n_nw_pts++) = P; N++; } //3 if (A(i + 1, j + 1, k) == v) { P.x = i + 1; P.y = j + 1; P.z = k; nw_pts(n_nw_pts++) = P; N++; } //4 if (A(i, j + 1, k) == v) { P.x = i; P.y = j + 1; P.z = k; nw_pts(n_nw_pts++) = P; N++; } //5 if (A(i, j, k + 1) == v) { P.x = i; P.y = j; P.z = k + 1; nw_pts(n_nw_pts++) = P; N++; } //6 if (A(i + 1, j, k + 1) == v) { P.x = i + 1; P.y = j; P.z = k + 1; nw_pts(n_nw_pts++) = P; N++; } //7 if (A(i + 1, j + 1, k + 1) == v) { P.x = i + 1; P.y = j + 1; P.z = k + 1; nw_pts(n_nw_pts++) = P; N++; } //8 if (A(i, j + 1, k + 1) == v) { P.x = i; P.y = j + 1; P.z = k + 1; nw_pts(n_nw_pts++) = P; N++; } // Go through each side, compute P for sides of box spiraling up // float val; Point pt; // 1 if ((A(i, j, k) - v) * (A(i + 1, j, k) - v) < 0) { // If both points are in the fluid region if (A(i, j, k) != 0 && A(i + 1, j, k) != 0) { P.x = i + (A(i, j, k) - v) / (A(i, j, k) - A(i + 1, j, k)); P.y = j; P.z = k; // Evaluate the function S at the new point if (solid(i, j, k) * (1 - P.x + i) + solid(i + 1, j, k) * (P.x - i) > 0) { // This point is in the fluid region nw_pts(n_nw_pts++) = P; N++; } } } // 2 if ((A(i + 1, j, k) - v) * (A(i + 1, j + 1, k) - v) < 0) { if (A(i + 1, j, k) != 0 && A(i + 1, j + 1, k) != 0) { P.x = i + 1; P.y = j + (A(i + 1, j, k) - v) / (A(i + 1, j, k) - A(i + 1, j + 1, k)); P.z = k; // Evaluate the function S at the new point if (solid(i + 1, j, k) * (1 - P.y + j) + solid(i + 1, j + 1, k) * (P.y - j) > 0) { // This point is in the fluid region if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { // P is a new vertex (not counted twice) nw_pts(n_nw_pts++) = P; N++; } } } } //3 if ((A(i + 1, j + 1, k) - v) * (A(i, j + 1, k) - v) < 0) { if (A(i + 1, j + 1, k) != 0 && A(i, j + 1, k) != 0) { P.x = i + (A(i, j + 1, k) - v) / (A(i, j + 1, k) - A(i + 1, j + 1, k)); P.y = j + 1; P.z = k; // Evaluate the function S at the new point if (solid(i, j + 1, k) * (1 - P.x + i) + solid(i + 1, j + 1, k) * (P.x - i) > 0) { // This point is in the fluid region if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { // P is a new vertex (not counted twice) nw_pts(n_nw_pts++) = P; N++; } } } } //4 if ((A(i, j + 1, k) - v) * (A(i, j, k) - v) < 0) { if (A(i, j + 1, k) != 0 && A(i, j, k) != 0) { P.x = i; P.y = j + (A(i, j, k) - v) / (A(i, j, k) - A(i, j + 1, k)); P.z = k; // Evaluate the function S at the new point if (solid(i, j, k) * (1 - P.y + j) + solid(i, j + 1, k) * (P.y - j) > 0) { // This point is in the fluid region if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { // P is a new vertex (not counted twice) nw_pts(n_nw_pts++) = P; N++; } } } } //5 if ((A(i, j, k) - v) * (A(i, j, k + 1) - v) < 0) { if (A(i, j, k) != 0 && A(i, j, k + 1) != 0) { P.x = i; P.y = j; P.z = k + (A(i, j, k) - v) / (A(i, j, k) - A(i, j, k + 1)); // Evaluate the function S at the new point if (solid(i, j, k) * (1 - P.z + k) + solid(i, j, k + 1) * (P.z - k) > 0) { // This point is in the fluid region if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { // P is a new vertex (not counted twice) nw_pts(n_nw_pts++) = P; N++; } } } } //6 if ((A(i + 1, j, k) - v) * (A(i + 1, j, k + 1) - v) < 0) { if (A(i + 1, j, k) != 0 && A(i + 1, j, k + 1) != 0) { P.x = i + 1; P.y = j; P.z = k + (A(i + 1, j, k) - v) / (A(i + 1, j, k) - A(i + 1, j, k + 1)); // Evaluate the function S at the new point if (solid(i + 1, j, k) * (1 - P.z + k) + solid(i + 1, j, k + 1) * (P.z - k) > 0) { // This point is in the fluid region if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { nw_pts(n_nw_pts++) = P; N++; } } } } //7 if ((A(i + 1, j + 1, k) - v) * (A(i + 1, j + 1, k + 1) - v) < 0) { if (A(i + 1, j + 1, k) != 0 && A(i + 1, j + 1, k + 1) != 0) { P.x = i + 1; P.y = j + 1; P.z = k + (A(i + 1, j + 1, k) - v) / (A(i + 1, j + 1, k) - A(i + 1, j + 1, k + 1)); // Evaluate the function S at the new point if (solid(i + 1, j + 1, k) * (1 - P.z + k) + solid(i + 1, j + 1, k + 1) * (P.z - k) > 0) { // This point is in the fluid region if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { nw_pts(n_nw_pts++) = P; N++; } } } } //8 if ((A(i, j + 1, k) - v) * (A(i, j + 1, k + 1) - v) < 0) { if (A(i, j + 1, k) != 0 && A(i, j + 1, k + 1) != 0) { P.x = i; P.y = j + 1; P.z = k + (A(i, j + 1, k) - v) / (A(i, j + 1, k) - A(i, j + 1, k + 1)); // Evaluate the function S at the new point if (solid(i, j + 1, k) * (1 - P.z + k) + solid(i, j + 1, k + 1) * (P.z - k) > 0) { // This point is in the fluid region if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { nw_pts(n_nw_pts++) = P; N++; } } } } //9 if ((A(i, j, k + 1) - v) * (A(i + 1, j, k + 1) - v) < 0) { if (A(i, j, k + 1) != 0 && A(i + 1, j, k + 1) != 0) { P.x = i + (A(i, j, k + 1) - v) / (A(i, j, k + 1) - A(i + 1, j, k + 1)); P.y = j; P.z = k + 1; // Evaluate the function S at the new point if (solid(i, j, k + 1) * (1 - P.x + i) + solid(i + 1, j, k + 1) * (P.x - i) > 0) { // This point is in the fluid region if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { nw_pts(n_nw_pts++) = P; N++; } } } } //10 if ((A(i + 1, j, k + 1) - v) * (A(i + 1, j + 1, k + 1) - v) < 0) { if (A(i + 1, j, k + 1) != 0 && A(i + 1, j + 1, k + 1) != 0) { P.x = i + 1; P.y = j + (A(i + 1, j, k + 1) - v) / (A(i + 1, j, k + 1) - A(i + 1, j + 1, k + 1)); P.z = k + 1; // Evaluate the function S at the new point if (solid(i + 1, j, k + 1) * (1 - P.y + j) + solid(i + 1, j + 1, k + 1) * (P.y - j) > 0) { // This point is in the fluid region if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { nw_pts(n_nw_pts++) = P; N++; } } } } //11 if ((A(i + 1, j + 1, k + 1) - v) * (A(i, j + 1, k + 1) - v) < 0) { if (A(i + 1, j + 1, k + 1) != 0 && A(i, j + 1, k + 1) != 0) { P.x = i + (A(i, j + 1, k + 1) - v) / (A(i, j + 1, k + 1) - A(i + 1, j + 1, k + 1)); P.y = j + 1; P.z = k + 1; // Evaluate the function S at the new point if (solid(i, j + 1, k + 1) * (1 - P.x + i) + solid(i + 1, j + 1, k + 1) * (P.x - i) > 0) { // This point is in the fluid region if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { nw_pts(n_nw_pts++) = P; N++; } } } } //12 if ((A(i, j + 1, k + 1) - v) * (A(i, j, k + 1) - v) < 0) { if (A(i, j + 1, k + 1) != 0 && A(i, j, k + 1) != 0) { P.x = i; P.y = j + (A(i, j, k + 1) - v) / (A(i, j, k + 1) - A(i, j + 1, k + 1)); P.z = k + 1; // Evaluate the function S at the new point if (solid(i, j, k + 1) * (1 - P.y + j) + solid(i, j + 1, k + 1) * (P.y - j) > 0) { // This point is in the fluid region if (vertexcheck(P, N, n_nw_pts, nw_pts) == 1) { nw_pts(n_nw_pts++) = P; N++; } } } } //////////////////////////////////////////////// ////// SORT VERTICES SO THAT THEY CONNECT ////// ////// TO ALL "NEIGHBORS" ////// //////////////////////////////////////////////// // First common line point should connect to last MC point for (q = n_nw_pts - N; q < n_nw_pts - 1; q++) { if (ShareSide(nw_pts(n_nw_pts - N - n_local_nws_pts), nw_pts(n_nw_pts - 1)) == 0 && ShareSide(nw_pts(n_nw_pts - N - n_local_nws_pts), nw_pts(q)) == 1) { // Switch point q with point n_nw_pts-N-n_local_nws_pts temp = nw_pts(n_nw_pts - 1); nw_pts(n_nw_pts - 1) = nw_pts(q); nw_pts(q) = temp; } } // Last common line point should connect to first MC point for (q = n_nw_pts - N + 1; q < n_nw_pts - 1; q++) { if (ShareSide(nw_pts(n_nw_pts - N - 1), nw_pts(n_nw_pts - N)) == 0 && ShareSide(nw_pts(n_nw_pts - N - 1), nw_pts(q)) == 1) { // Switch these points temp = nw_pts(n_nw_pts - N); nw_pts(n_nw_pts - N) = nw_pts(q); nw_pts(q) = temp; } } // All MC points should connect to their neighbors for (q = n_nw_pts - N; q < n_nw_pts - 2; q++) { if (ShareSide(nw_pts(q), nw_pts(q + 1)) == 0) { for (r = q + 2; r < n_nw_pts - 1; r++) { if (ShareSide(nw_pts(q), nw_pts(q + 1)) == 0 && ShareSide(nw_pts(q), nw_pts(r)) == 1) { // Switch r and q+1 temp = nw_pts(q + 1); nw_pts(q + 1) = nw_pts(r); nw_pts(r) = temp; } } } } // * * * ESTABLISH TRIANGLE CONNECTIONS * * * for (p = n_nw_pts - N - n_local_nws_pts; p < n_nw_pts - 2; p++) { nw_tris(0, n_nw_tris) = n_nw_pts - 1; nw_tris(1, n_nw_tris) = p; nw_tris(2, n_nw_tris) = p + 1; n_nw_tris++; } // for (p=n_nw_pts-N-n_local_nws_pts+2; p vF) int cube[8][3] = {{0, 0, 0}, {1, 0, 0}, {0, 1, 0}, {1, 1, 0}, {0, 0, 1}, {1, 0, 1}, {0, 1, 1}, {1, 1, 1}}; // cube corners // int count_in=0,count_out=0; // int nodx,nody,nodz; // initialize lists for vertices for surfaces, common line DTMutableList nw_pts(20); DTMutableList ns_pts(20); DTMutableList ws_pts(20); DTMutableList nws_pts(20); // initialize triangle lists for surfaces IntArray nw_tris(3, 20); IntArray ns_tris(3, 20); IntArray ws_tris(3, 20); // initialize list for line segments IntArray nws_seg(2, 20); DTMutableList tmp(20); // IntArray store; int i, j, k, p, q, r; int n_nw_pts = 0, n_ns_pts = 0, n_ws_pts = 0, n_nws_pts = 0, map = 0; int n_nw_tris = 0, n_ns_tris = 0, n_ws_tris = 0, n_nws_seg = 0; double s, s1, s2, s3; // Triangle sides (lengths) Point A, B, C, P; // double area; // Initialize arrays for local solid surface DTMutableList local_sol_pts(20); int n_local_sol_pts = 0; IntArray local_sol_tris(3, 18); int n_local_sol_tris; DoubleArray values(20); DTMutableList local_nws_pts(20); int n_local_nws_pts; int n_nw_tris_beg, n_ns_tris_beg, n_ws_tris_beg; int c; // int newton_steps = 0; // double blob_volume; /* **************************************************************** RUN PMMC ON EACH BLOB ****************************************************************** */ // printf("Running the PMMC Algorithm \n"); // printf("The number of blobs is %i \n",nblobs); // Store beginning points for surfaces for blob p n_nw_tris_beg = n_nw_tris; n_ns_tris_beg = n_ns_tris; n_ws_tris_beg = n_ws_tris; // n_nws_seg_beg = n_nws_seg; // Loop over all cubes blob_volume = 0; // Initialize the volume for blob a to zero for (c = start; c < finish; c++) { // Get cube from the list i = cubeList(0, c); j = cubeList(1, c); k = cubeList(2, c); // printf("somewhere inside %i \n",c); /* // Compute the volume for (p=0;p<8;p++){ if ( indicator(i+cube[p][0],j+cube[p][1],k+cube[p][2]) > -1){ blob_volume += 0.125; } } */ for (p = 0; p < 8; p++) { if (F(i + cube[p][0], j + cube[p][1], k + cube[p][2]) > 0 && S(i + cube[p][0], j + cube[p][1], k + cube[p][2]) > 0) { blob_volume += 0.125; } } // Run PMMC n_local_sol_tris = 0; n_local_sol_pts = 0; n_local_nws_pts = 0; // if there is a solid phase interface in the grid cell if (Interface(S, vS, i, j, k) == 1) { ///////////////////////////////////////// /// CONSTRUCT THE LOCAL SOLID SURFACE /// ///////////////////////////////////////// // find the local solid surface SOL_SURF(S, 0, F, vF, i, j, k, Nx, Ny, Nz, local_sol_pts, n_local_sol_pts, local_sol_tris, n_local_sol_tris, values); ///////////////////////////////////////// //////// TRIM THE SOLID SURFACE ///////// ///////////////////////////////////////// /* TRIM(local_sol_pts, n_local_sol_pts, fluid_isovalue,local_sol_tris, n_local_sol_tris, ns_pts, n_ns_pts, ns_tris, n_ns_tris, ws_pts, n_ws_pts, ws_tris, n_ws_tris, values, local_nws_pts, n_local_nws_pts, Phase, SignDist, i, j, k, newton_steps); */ TRIM(local_sol_pts, n_local_sol_pts, vF, local_sol_tris, n_local_sol_tris, ns_pts, n_ns_pts, ns_tris, n_ns_tris, ws_pts, n_ws_pts, ws_tris, n_ws_tris, values, local_nws_pts, n_local_nws_pts); ///////////////////////////////////////// //////// WRITE COMMON LINE POINTS /////// //////// TO MAIN ARRAYS /////// ///////////////////////////////////////// map = n_nws_pts; for (p = 0; p < n_local_nws_pts; p++) { nws_pts(n_nws_pts++) = local_nws_pts(p); } for (q = 0; q < n_local_nws_pts - 1; q++) { nws_seg(0, n_nws_seg) = map + q; nws_seg(1, n_nws_seg) = map + q + 1; n_nws_seg++; } ///////////////////////////////////////// ////// CONSTRUCT THE nw SURFACE ///////// ///////////////////////////////////////// if (n_local_nws_pts > 0) { EDGE(F, vF, S, i, j, k, Nx, Ny, Nz, nw_pts, n_nw_pts, nw_tris, n_nw_tris, local_nws_pts, n_local_nws_pts); } else { MC(F, vF, S, i, j, k, nw_pts, n_nw_pts, nw_tris, n_nw_tris); } } ///////////////////////////////////////// ////// CONSTRUCT THE nw SURFACE ///////// ///////////////////////////////////////// else if (Fluid_Interface(F, S, vF, i, j, k) == 1) { MC(F, vF, S, i, j, k, nw_pts, n_nw_pts, nw_tris, n_nw_tris); } //******END OF BLOB PMMC********************************************* //******************************************************************* // Compute the Interfacial Areas, Common Line length for blob p // nw surface for (r = n_nw_tris_beg; r < n_nw_tris; r++) { A = nw_pts(nw_tris(0, r)); B = nw_pts(nw_tris(1, r)); C = nw_pts(nw_tris(2, r)); // Compute length of sides (assume dx=dy=dz) s1 = sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y) + (A.z - B.z) * (A.z - B.z)); s2 = sqrt((A.x - C.x) * (A.x - C.x) + (A.y - C.y) * (A.y - C.y) + (A.z - C.z) * (A.z - C.z)); s3 = sqrt((B.x - C.x) * (B.x - C.x) + (B.y - C.y) * (B.y - C.y) + (B.z - C.z) * (B.z - C.z)); s = 0.5 * (s1 + s2 + s3); awn = awn + sqrt(s * (s - s1) * (s - s2) * (s - s3)); } for (r = n_ns_tris_beg; r < n_ns_tris; r++) { A = ns_pts(ns_tris(0, r)); B = ns_pts(ns_tris(1, r)); C = ns_pts(ns_tris(2, r)); // Compute length of sides (assume dx=dy=dz) s1 = sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y) + (A.z - B.z) * (A.z - B.z)); s2 = sqrt((A.x - C.x) * (A.x - C.x) + (A.y - C.y) * (A.y - C.y) + (A.z - C.z) * (A.z - C.z)); s3 = sqrt((B.x - C.x) * (B.x - C.x) + (B.y - C.y) * (B.y - C.y) + (B.z - C.z) * (B.z - C.z)); s = 0.5 * (s1 + s2 + s3); ans = ans + sqrt(s * (s - s1) * (s - s2) * (s - s3)); } for (r = n_ws_tris_beg; r < n_ws_tris; r++) { A = ws_pts(ws_tris(0, r)); B = ws_pts(ws_tris(1, r)); C = ws_pts(ws_tris(2, r)); // Compute length of sides (assume dx=dy=dz) s1 = sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y) + (A.z - B.z) * (A.z - B.z)); s2 = sqrt((A.x - C.x) * (A.x - C.x) + (A.y - C.y) * (A.y - C.y) + (A.z - C.z) * (A.z - C.z)); s3 = sqrt((B.x - C.x) * (B.x - C.x) + (B.y - C.y) * (B.y - C.y) + (B.z - C.z) * (B.z - C.z)); s = 0.5 * (s1 + s2 + s3); aws = aws + sqrt(s * (s - s1) * (s - s2) * (s - s3)); } //******************************************************************* // Reset the triangle counts to zero n_nw_pts = 0, n_ns_pts = 0, n_ws_pts = 0, n_nws_pts = 0, map = 0; n_nw_tris = 0, n_ns_tris = 0, n_ws_tris = 0, n_nws_seg = 0; n_nw_tris_beg = n_nw_tris; n_ns_tris_beg = n_ns_tris; n_ws_tris_beg = n_ws_tris; // n_nws_seg_beg = n_nws_seg; //******************************************************************* } } //-------------------------------------------------------------------------------------------------------- inline void pmmc_ConstructLocalCube( DoubleArray &SignDist, DoubleArray &Phase, double solid_isovalue, double fluid_isovalue, DTMutableList &nw_pts, IntArray &nw_tris, DoubleArray &values, DTMutableList &ns_pts, IntArray &ns_tris, DTMutableList &ws_pts, IntArray &ws_tris, DTMutableList &local_nws_pts, DTMutableList &nws_pts, IntArray &nws_seg, DTMutableList &local_sol_pts, IntArray &local_sol_tris, int &n_local_sol_tris, int &n_local_sol_pts, int &n_nw_pts, int &n_nw_tris, int &n_ws_pts, int &n_ws_tris, int &n_ns_tris, int &n_ns_pts, int &n_local_nws_pts, int &n_nws_pts, int &n_nws_seg, int i, int j, int k, int Nx, int Ny, int Nz) { int p, q, map; Point A, B, C, P; // Only the local values are constructed and retained! (set counts to zero to force this) n_local_sol_tris = 0; n_local_sol_pts = 0; n_local_nws_pts = 0; n_nw_pts = 0, n_ns_pts = 0, n_ws_pts = 0, n_nws_pts = 0, map = 0; n_nw_tris = 0, n_ns_tris = 0, n_ws_tris = 0, n_nws_seg = 0; // if there is a solid phase interface in the grid cell if (Interface(SignDist, solid_isovalue, i, j, k) == 1) { ///////////////////////////////////////// /// CONSTRUCT THE LOCAL SOLID SURFACE /// ///////////////////////////////////////// // find the local solid surface using the regular Marching Cubes algorithm SolidMarchingCubes(SignDist, 0.0, Phase, fluid_isovalue, i, j, k, Nx, Ny, Nz, local_sol_pts, n_local_sol_pts, local_sol_tris, n_local_sol_tris, values); ///////////////////////////////////////// //////// TRIM THE SOLID SURFACE ///////// ///////////////////////////////////////// TRIM(local_sol_pts, n_local_sol_pts, fluid_isovalue, local_sol_tris, n_local_sol_tris, ns_pts, n_ns_pts, ns_tris, n_ns_tris, ws_pts, n_ws_pts, ws_tris, n_ws_tris, values, local_nws_pts, n_local_nws_pts); ///////////////////////////////////////// //////// WRITE COMMON LINE POINTS /////// //////// TO MAIN ARRAYS /////// ///////////////////////////////////////// // SORT THE LOCAL COMMON LINE POINTS ///////////////////////////////////////// // Make sure the first common line point is on a face // Common curve points are located pairwise and must // be searched and rearranged accordingly if (n_local_nws_pts > 0) { for (p = 0; p < n_local_nws_pts - 1; p++) { P = local_nws_pts(p); if (P.x == 1.0 * i || P.x == 1.0 * (i + 1) || P.y == 1.0 * j || P.y == 1.0 * (j + 1) || P.z == 1.0 * k || P.z == 1.0 * (k + 1)) { if (p % 2 == 0) { // even points // Swap the pair of points local_nws_pts(p) = local_nws_pts(0); local_nws_pts(0) = P; P = local_nws_pts(p + 1); local_nws_pts(p + 1) = local_nws_pts(1); local_nws_pts(1) = P; p = n_local_nws_pts; } else { // odd points - flip the order local_nws_pts(p) = local_nws_pts(p - 1); local_nws_pts(p - 1) = P; p -= 2; } // guarantee exit from the loop } } // Two common curve points per triangle // 0-(1=2)-(3=4)-... for (p = 1; p < n_local_nws_pts - 1; p += 2) { A = local_nws_pts(p); for (q = p + 1; q < n_local_nws_pts; q++) { B = local_nws_pts(q); if (A.x == B.x && A.y == B.y && A.z == B.z) { if (q % 2 == 0) { // even points // Swap the pair of points local_nws_pts(q) = local_nws_pts(p + 1); local_nws_pts(p + 1) = B; B = local_nws_pts(q + 1); local_nws_pts(q + 1) = local_nws_pts(p + 2); local_nws_pts(p + 2) = B; q = n_local_nws_pts; } else { // odd points - flip the order local_nws_pts(q) = local_nws_pts(q - 1); local_nws_pts(q - 1) = B; q -= 2; } } } } map = n_nws_pts = 0; nws_pts(n_nws_pts++) = local_nws_pts(0); for (p = 2; p < n_local_nws_pts; p += 2) { nws_pts(n_nws_pts++) = local_nws_pts(p); } nws_pts(n_nws_pts++) = local_nws_pts(n_local_nws_pts - 1); for (q = 0; q < n_nws_pts - 1; q++) { nws_seg(0, n_nws_seg) = map + q; nws_seg(1, n_nws_seg) = map + q + 1; n_nws_seg++; } // End of the common line sorting algorithm ///////////////////////////////////////// } ///////////////////////////////////////// ////// CONSTRUCT THE nw SURFACE ///////// ///////////////////////////////////////// if (n_local_nws_pts > 0) { n_nw_tris = 0; EDGE(Phase, fluid_isovalue, SignDist, i, j, k, Nx, Ny, Nz, nw_pts, n_nw_pts, nw_tris, n_nw_tris, nws_pts, n_nws_pts); } else { MC(Phase, fluid_isovalue, SignDist, i, j, k, nw_pts, n_nw_pts, nw_tris, n_nw_tris); } } ///////////////////////////////////////// ////// CONSTRUCT THE nw SURFACE ///////// ///////////////////////////////////////// else if (Fluid_Interface(Phase, SignDist, fluid_isovalue, i, j, k) == 1) { MC(Phase, fluid_isovalue, SignDist, i, j, k, nw_pts, n_nw_pts, nw_tris, n_nw_tris); } } //-------------------------------------------------------------------------------------------------------- inline void pmmc_MeshGradient(DoubleArray &f, DoubleArray &fx, DoubleArray &fy, DoubleArray &fz, int Nx, int Ny, int Nz) { int i, j, k; // Compute the Gradient everywhere except the halo region for (k = 1; k < Nz - 1; k++) { for (j = 1; j < Ny - 1; j++) { for (i = 1; i < Nx - 1; i++) { // Compute all of the derivatives using finite differences fx(i, j, k) = 0.5 * (f(i + 1, j, k) - f(i - 1, j, k)); fy(i, j, k) = 0.5 * (f(i, j + 1, k) - f(i, j - 1, k)); fz(i, j, k) = 0.5 * (f(i, j, k + 1) - f(i, j, k - 1)); } } } } //-------------------------------------------------------------------------------------------------------- inline void pmmc_MeshCurvature(DoubleArray &f, DoubleArray &MeanCurvature, DoubleArray &GaussCurvature, int Nx, int Ny, int Nz) { // Mesh spacing is taken to be one to simplify the calculation int i, j, k; double denominator; double fxx, fyy, fzz, fxy, fxz, fyz, fx, fy, fz; // Compute the curvature everywhere except the halo region for (k = 1; k < Nz - 1; k++) { for (j = 1; j < Ny - 1; j++) { for (i = 1; i < Nx - 1; i++) { // Compute all of the derivatives using finite differences fx = 0.5 * (f(i + 1, j, k) - f(i - 1, j, k)); fy = 0.5 * (f(i, j + 1, k) - f(i, j - 1, k)); fz = 0.5 * (f(i, j, k + 1) - f(i, j, k - 1)); fxx = f(i + 1, j, k) - 2.0 * f(i, j, k) + f(i - 1, j, k); fyy = f(i, j + 1, k) - 2.0 * f(i, j, k) + f(i, j - 1, k); fzz = f(i, j, k + 1) - 2.0 * f(i, j, k) + f(i, j, k - 1); fxy = 0.25 * (f(i + 1, j + 1, k) - f(i + 1, j - 1, k) - f(i - 1, j + 1, k) + f(i - 1, j - 1, k)); fxz = 0.25 * (f(i + 1, j, k + 1) - f(i + 1, j, k - 1) - f(i - 1, j, k + 1) + f(i - 1, j, k - 1)); fyz = 0.25 * (f(i, j + 1, k + 1) - f(i, j + 1, k - 1) - f(i, j - 1, k + 1) + f(i, j - 1, k - 1)); // Evaluate the Mean Curvature denominator = pow(sqrt(fx * fx + fy * fy + fz * fz), 3); if (denominator == 0.0) { MeanCurvature(i, j, k) = 0.0; } else { MeanCurvature(i, j, k) = (1.0 / denominator) * ((fyy + fzz) * fx * fx + (fxx + fzz) * fy * fy + (fxx + fyy) * fz * fz - 2.0 * fx * fy * fxy - 2.0 * fx * fz * fxz - 2.0 * fy * fz * fyz); } // Evaluate the Gaussian Curvature denominator = pow(fx * fx + fy * fy + fz * fz, 2); if (denominator == 0.0) { GaussCurvature(i, j, k) = 0.0; } else { GaussCurvature(i, j, k) = (1.0 / denominator) * (fx * fx * (fyy * fzz - fyz * fyz) + fy * fy * (fxx * fzz - fxz * fxz) + fz * fz * (fxx * fyy - fxy * fxy) + 2.0 * (fx * fy * (fxz * fyz - fxy * fzz) + fy * fz * (fxy * fxz - fyz * fxx) + fx * fz * (fxy * fyz - fxz * fyy))); } } } } } //-------------------------------------------------------------------------------------------------------- inline int pmmc_CubeListFromMesh(IntArray &cubeList, int ncubes, int Nx, int Ny, int Nz) { NULL_USE(ncubes); int i, j, k, nc; nc = 0; //........................................................................... // Set up the cube list (very regular in this case due to lack of blob-ID) for (k = 1; k < Nz - 2; k++) { for (j = 1; j < Ny - 2; j++) { for (i = 1; i < Nx - 2; i++) { cubeList(0, nc) = i; cubeList(1, nc) = j; cubeList(2, nc) = k; nc++; } } } return nc; } //-------------------------------------------------------------------------------------------------------- inline void pmmc_CubeListFromBlobs() {} //-------------------------------------------------------------------------------------------------------- inline double pmmc_CubeSurfaceArea(DTMutableList &Points, IntArray &Triangles, int ntris) { int r; double temp, area, s, s1, s2, s3; Point A, B, C; area = 0.0; for (r = 0; r < ntris; r++) { A = Points(Triangles(0, r)); B = Points(Triangles(1, r)); C = Points(Triangles(2, r)); // Compute length of sides (assume dx=dy=dz) s1 = sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y) + (A.z - B.z) * (A.z - B.z)); s2 = sqrt((A.x - C.x) * (A.x - C.x) + (A.y - C.y) * (A.y - C.y) + (A.z - C.z) * (A.z - C.z)); s3 = sqrt((B.x - C.x) * (B.x - C.x) + (B.y - C.y) * (B.y - C.y) + (B.z - C.z) * (B.z - C.z)); s = 0.5 * (s1 + s2 + s3); temp = s * (s - s1) * (s - s2) * (s - s3); if (temp > 0.0) area += sqrt(temp); } return area; } //-------------------------------------------------------------------------------------------------------- inline double pmmc_CubeCurveLength(DTMutableList &Points, int npts) { int p; double s, lwns; Point A, B; lwns = 0.0; for (p = 0; p < npts - 1; p++) { // Extract the line segment A = Points(p); B = Points(p + 1); // Compute the length of the segment s = sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y) + (A.z - B.z) * (A.z - B.z)); // Add the length to the common line lwns += s; } return lwns; } //-------------------------------------------------------------------------------------------------------- inline void pmmc_CubeTrimSurfaceInterpValues( DoubleArray &CubeValues, DoubleArray &MeshValues, DoubleArray &SignDist, DTMutableList &Points, IntArray &Triangles, DoubleArray &SurfaceValues, DoubleArray &DistanceValues, int i, int j, int k, int npts, int ntris, double mindist, double &area, double &integral) { // mindist - minimum distance to consider in the average (in voxel lengths) Point A, B, C; int p; double vA, vB, vC; double dA, dB, dC; double x, y, z; double s, s1, s2, s3, temp; double a, b, c, d, e, f, g, h; // Copy the curvature values for the cube CubeValues(0, 0, 0) = MeshValues(i, j, k); CubeValues(1, 0, 0) = MeshValues(i + 1, j, k); CubeValues(0, 1, 0) = MeshValues(i, j + 1, k); CubeValues(1, 1, 0) = MeshValues(i + 1, j + 1, k); CubeValues(0, 0, 1) = MeshValues(i, j, k + 1); CubeValues(1, 0, 1) = MeshValues(i + 1, j, k + 1); CubeValues(0, 1, 1) = MeshValues(i, j + 1, k + 1); CubeValues(1, 1, 1) = MeshValues(i + 1, j + 1, k + 1); // trilinear coefficients: f(x,y,z) = a+bx+cy+dz+exy+fxz+gyz+hxyz // Evaluate the coefficients a = CubeValues(0, 0, 0); b = CubeValues(1, 0, 0) - a; c = CubeValues(0, 1, 0) - a; d = CubeValues(0, 0, 1) - a; e = CubeValues(1, 1, 0) - a - b - c; f = CubeValues(1, 0, 1) - a - b - d; g = CubeValues(0, 1, 1) - a - c - d; h = CubeValues(1, 1, 1) - a - b - c - d - e - f - g; for (p = 0; p < npts; p++) { A = Points(p); x = A.x - 1.0 * i; y = A.y - 1.0 * j; z = A.z - 1.0 * k; SurfaceValues(p) = a + b * x + c * y + d * z + e * x * y + f * x * z + g * y * z + h * x * y * z; } // Copy the signed distance values for the cube CubeValues(0, 0, 0) = SignDist(i, j, k); CubeValues(1, 0, 0) = SignDist(i + 1, j, k); CubeValues(0, 1, 0) = SignDist(i, j + 1, k); CubeValues(1, 1, 0) = SignDist(i + 1, j + 1, k); CubeValues(0, 0, 1) = SignDist(i, j, k + 1); CubeValues(1, 0, 1) = SignDist(i + 1, j, k + 1); CubeValues(0, 1, 1) = SignDist(i, j + 1, k + 1); CubeValues(1, 1, 1) = SignDist(i + 1, j + 1, k + 1); // trilinear coefficients: f(x,y,z) = a+bx+cy+dz+exy+fxz+gyz+hxyz // Evaluate the coefficients a = CubeValues(0, 0, 0); b = CubeValues(1, 0, 0) - a; c = CubeValues(0, 1, 0) - a; d = CubeValues(0, 0, 1) - a; e = CubeValues(1, 1, 0) - a - b - c; f = CubeValues(1, 0, 1) - a - b - d; g = CubeValues(0, 1, 1) - a - c - d; h = CubeValues(1, 1, 1) - a - b - c - d - e - f - g; for (p = 0; p < npts; p++) { A = Points(p); x = A.x - 1.0 * i; y = A.y - 1.0 * j; z = A.z - 1.0 * k; DistanceValues(p) = a + b * x + c * y + d * z + e * x * y + f * x * z + g * y * z + h * x * y * z; } for (int r = 0; r < ntris; r++) { A = Points(Triangles(0, r)); B = Points(Triangles(1, r)); C = Points(Triangles(2, r)); vA = SurfaceValues(Triangles(0, r)); vB = SurfaceValues(Triangles(1, r)); vC = SurfaceValues(Triangles(2, r)); dA = DistanceValues(Triangles(0, r)); dB = DistanceValues(Triangles(1, r)); dC = DistanceValues(Triangles(2, r)); // Compute length of sides (assume dx=dy=dz) s1 = sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y) + (A.z - B.z) * (A.z - B.z)); s2 = sqrt((A.x - C.x) * (A.x - C.x) + (A.y - C.y) * (A.y - C.y) + (A.z - C.z) * (A.z - C.z)); s3 = sqrt((B.x - C.x) * (B.x - C.x) + (B.y - C.y) * (B.y - C.y) + (B.z - C.z) * (B.z - C.z)); s = 0.5 * (s1 + s2 + s3); temp = s * (s - s1) * (s - s2) * (s - s3); if (temp > 0.0) { if (dA > mindist) { integral += sqrt(temp) * 0.33333333333333333 * (vA); area += sqrt(temp) * 0.33333333333333333; } if (dB > mindist) { integral += sqrt(temp) * 0.33333333333333333 * (vB); area += sqrt(temp) * 0.33333333333333333; } if (dC > mindist) { integral += sqrt(temp) * 0.33333333333333333 * (vC); area += sqrt(temp) * 0.33333333333333333; } } } } inline void pmmc_CubeTrimSurfaceInterpInverseValues( DoubleArray &CubeValues, DoubleArray &MeshValues, DoubleArray &SignDist, DTMutableList &Points, IntArray &Triangles, DoubleArray &SurfaceValues, DoubleArray &DistanceValues, int i, int j, int k, int npts, int ntris, double mindist, double &area, double &integral) { // mindist - minimum distance to consider in the average (in voxel lengths) Point A, B, C; int p; double vA, vB, vC; double dA, dB, dC; double x, y, z; double s, s1, s2, s3, temp; double a, b, c, d, e, f, g, h; // Copy the curvature values for the cube CubeValues(0, 0, 0) = MeshValues(i, j, k); CubeValues(1, 0, 0) = MeshValues(i + 1, j, k); CubeValues(0, 1, 0) = MeshValues(i, j + 1, k); CubeValues(1, 1, 0) = MeshValues(i + 1, j + 1, k); CubeValues(0, 0, 1) = MeshValues(i, j, k + 1); CubeValues(1, 0, 1) = MeshValues(i + 1, j, k + 1); CubeValues(0, 1, 1) = MeshValues(i, j + 1, k + 1); CubeValues(1, 1, 1) = MeshValues(i + 1, j + 1, k + 1); // trilinear coefficients: f(x,y,z) = a+bx+cy+dz+exy+fxz+gyz+hxyz // Evaluate the coefficients a = CubeValues(0, 0, 0); b = CubeValues(1, 0, 0) - a; c = CubeValues(0, 1, 0) - a; d = CubeValues(0, 0, 1) - a; e = CubeValues(1, 1, 0) - a - b - c; f = CubeValues(1, 0, 1) - a - b - d; g = CubeValues(0, 1, 1) - a - c - d; h = CubeValues(1, 1, 1) - a - b - c - d - e - f - g; for (p = 0; p < npts; p++) { A = Points(p); x = A.x - 1.0 * i; y = A.y - 1.0 * j; z = A.z - 1.0 * k; SurfaceValues(p) = a + b * x + c * y + d * z + e * x * y + f * x * z + g * y * z + h * x * y * z; } // Copy the signed distance values for the cube CubeValues(0, 0, 0) = SignDist(i, j, k); CubeValues(1, 0, 0) = SignDist(i + 1, j, k); CubeValues(0, 1, 0) = SignDist(i, j + 1, k); CubeValues(1, 1, 0) = SignDist(i + 1, j + 1, k); CubeValues(0, 0, 1) = SignDist(i, j, k + 1); CubeValues(1, 0, 1) = SignDist(i + 1, j, k + 1); CubeValues(0, 1, 1) = SignDist(i, j + 1, k + 1); CubeValues(1, 1, 1) = SignDist(i + 1, j + 1, k + 1); // trilinear coefficients: f(x,y,z) = a+bx+cy+dz+exy+fxz+gyz+hxyz // Evaluate the coefficients a = CubeValues(0, 0, 0); b = CubeValues(1, 0, 0) - a; c = CubeValues(0, 1, 0) - a; d = CubeValues(0, 0, 1) - a; e = CubeValues(1, 1, 0) - a - b - c; f = CubeValues(1, 0, 1) - a - b - d; g = CubeValues(0, 1, 1) - a - c - d; h = CubeValues(1, 1, 1) - a - b - c - d - e - f - g; for (p = 0; p < npts; p++) { A = Points(p); x = A.x - 1.0 * i; y = A.y - 1.0 * j; z = A.z - 1.0 * k; DistanceValues(p) = a + b * x + c * y + d * z + e * x * y + f * x * z + g * y * z + h * x * y * z; } for (int r = 0; r < ntris; r++) { A = Points(Triangles(0, r)); B = Points(Triangles(1, r)); C = Points(Triangles(2, r)); vA = SurfaceValues(Triangles(0, r)); vB = SurfaceValues(Triangles(1, r)); vC = SurfaceValues(Triangles(2, r)); dA = DistanceValues(Triangles(0, r)); dB = DistanceValues(Triangles(1, r)); dC = DistanceValues(Triangles(2, r)); // Compute length of sides (assume dx=dy=dz) s1 = sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y) + (A.z - B.z) * (A.z - B.z)); s2 = sqrt((A.x - C.x) * (A.x - C.x) + (A.y - C.y) * (A.y - C.y) + (A.z - C.z) * (A.z - C.z)); s3 = sqrt((B.x - C.x) * (B.x - C.x) + (B.y - C.y) * (B.y - C.y) + (B.z - C.z) * (B.z - C.z)); s = 0.5 * (s1 + s2 + s3); temp = s * (s - s1) * (s - s2) * (s - s3); if (temp > 0.0) { if (dA > mindist && vA != 0.0) { integral += sqrt(temp) * 0.33333333333333333 * (1.0 / vA); area += sqrt(temp) * 0.33333333333333333; } if (dB > mindist && vB != 0.0) { integral += sqrt(temp) * 0.33333333333333333 * (1.0 / vB); area += sqrt(temp) * 0.33333333333333333; } if (dC > mindist && vC != 0.0) { integral += sqrt(temp) * 0.33333333333333333 * (1.0 / vC); area += sqrt(temp) * 0.33333333333333333; } } } } inline double pmmc_CubeSurfaceInterpValue(DoubleArray &CubeValues, DoubleArray &MeshValues, DTMutableList &Points, IntArray &Triangles, DoubleArray &SurfaceValues, int i, int j, int k, int npts, int ntris) { Point A, B, C; int p; double vA, vB, vC; double x, y, z; double s, s1, s2, s3, temp; double a, b, c, d, e, f, g, h; double integral; // Copy the curvature values for the cube CubeValues(0, 0, 0) = MeshValues(i, j, k); CubeValues(1, 0, 0) = MeshValues(i + 1, j, k); CubeValues(0, 1, 0) = MeshValues(i, j + 1, k); CubeValues(1, 1, 0) = MeshValues(i + 1, j + 1, k); CubeValues(0, 0, 1) = MeshValues(i, j, k + 1); CubeValues(1, 0, 1) = MeshValues(i + 1, j, k + 1); CubeValues(0, 1, 1) = MeshValues(i, j + 1, k + 1); CubeValues(1, 1, 1) = MeshValues(i + 1, j + 1, k + 1); // trilinear coefficients: f(x,y,z) = a+bx+cy+dz+exy+fxz+gyz+hxyz // Evaluate the coefficients a = CubeValues(0, 0, 0); b = CubeValues(1, 0, 0) - a; c = CubeValues(0, 1, 0) - a; d = CubeValues(0, 0, 1) - a; e = CubeValues(1, 1, 0) - a - b - c; f = CubeValues(1, 0, 1) - a - b - d; g = CubeValues(0, 1, 1) - a - c - d; h = CubeValues(1, 1, 1) - a - b - c - d - e - f - g; for (p = 0; p < npts; p++) { A = Points(p); x = A.x - 1.0 * i; y = A.y - 1.0 * j; z = A.z - 1.0 * k; SurfaceValues(p) = a + b * x + c * y + d * z + e * x * y + f * x * z + g * y * z + h * x * y * z; } integral = 0.0; for (int r = 0; r < ntris; r++) { A = Points(Triangles(0, r)); B = Points(Triangles(1, r)); C = Points(Triangles(2, r)); vA = SurfaceValues(Triangles(0, r)); vB = SurfaceValues(Triangles(1, r)); vC = SurfaceValues(Triangles(2, r)); // Compute length of sides (assume dx=dy=dz) s1 = sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y) + (A.z - B.z) * (A.z - B.z)); s2 = sqrt((A.x - C.x) * (A.x - C.x) + (A.y - C.y) * (A.y - C.y) + (A.z - C.z) * (A.z - C.z)); s3 = sqrt((B.x - C.x) * (B.x - C.x) + (B.y - C.y) * (B.y - C.y) + (B.z - C.z) * (B.z - C.z)); s = 0.5 * (s1 + s2 + s3); temp = s * (s - s1) * (s - s2) * (s - s3); if (temp > 0.0) integral += sqrt(temp) * 0.33333333333333333 * (vA + vB + vC); } return integral; } //-------------------------------------------------------------------------------------------------------- inline double pmmc_CubeCurveInterpValue(DoubleArray &CubeValues, DoubleArray &CurveValues, DTMutableList &Points, int i, int j, int k, int npts) { int p; Point A, B; double vA, vB; double x, y, z; // double s,s1,s2,s3,temp; double a, b, c, d, e, f, g, h; double integral; double length; // trilinear coefficients: f(x,y,z) = a+bx+cy+dz+exy+fxz+gyz+hxyz // Evaluate the coefficients a = CubeValues(0, 0, 0); b = CubeValues(1, 0, 0) - a; c = CubeValues(0, 1, 0) - a; d = CubeValues(0, 0, 1) - a; e = CubeValues(1, 1, 0) - a - b - c; f = CubeValues(1, 0, 1) - a - b - d; g = CubeValues(0, 1, 1) - a - c - d; h = CubeValues(1, 1, 1) - a - b - c - d - e - f - g; for (p = 0; p < npts; p++) { A = Points(p); x = A.x - 1.0 * i; y = A.y - 1.0 * j; z = A.z - 1.0 * k; CurveValues(p) = a + b * x + c * y + d * z + e * x * y + f * x * z + g * y * z + h * x * y * z; } integral = 0.0; for (p = 0; p < npts - 1; p++) { // Extract the line segment A = Points(p); B = Points(p + 1); vA = CurveValues(p); vB = CurveValues(p + 1); // Compute the length of the segment length = sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y) + (A.z - B.z) * (A.z - B.z)); integral += 0.5 * length * (vA + vB); } return integral; } //-------------------------------------------------------------------------------------------------------- inline double pmmc_CubeContactAngle(DoubleArray &CubeValues, DoubleArray &CurveValues, DoubleArray &Fx, DoubleArray &Fy, DoubleArray &Fz, DoubleArray &Sx, DoubleArray &Sy, DoubleArray &Sz, DTMutableList &Points, int i, int j, int k, int npts) { int p; Point A, B; double vA, vB; double x, y, z; // double s,s1,s2,s3,temp; double a, b, c, d, e, f, g, h; double integral; double length; double denom; // theta = acos ( -(gradF*gradS) / (|gradF| |gradS|) ) denom = sqrt(pow(Fx(i, j, k), 2) + pow(Fy(i, j, k), 2) + pow(Fz(i, j, k), 2)) * sqrt(pow(Sx(i, j, k), 2) + pow(Sy(i, j, k), 2) + pow(Sz(i, j, k), 2)); if (denom == 0.0) denom = 1.0; CubeValues(0, 0, 0) = -(Fx(i, j, k) * Sx(i, j, k) + Fy(i, j, k) * Sy(i, j, k) + Fz(i, j, k) * Sz(i, j, k)) / (denom); denom = sqrt(pow(Fx(i + 1, j, k), 2) + pow(Fy(i + 1, j, k), 2) + pow(Fz(i + 1, j, k), 2)) * sqrt(pow(Sx(i + 1, j, k), 2) + pow(Sy(i + 1, j, k), 2) + pow(Sz(i + 1, j, k), 2)); if (denom == 0.0) denom = 1.0; CubeValues(1, 0, 0) = -(Fx(i + 1, j, k) * Sx(i + 1, j, k) + Fy(i + 1, j, k) * Sy(i + 1, j, k) + Fz(i + 1, j, k) * Sz(i + 1, j, k)) / (denom); denom = sqrt(pow(Fx(i, j + 1, k), 2) + pow(Fy(i, j + 1, k), 2) + pow(Fz(i, j + 1, k), 2)) * sqrt(pow(Sx(i, j + 1, k), 2) + pow(Sy(i, j + 1, k), 2) + pow(Sz(i, j + 1, k), 2)); if (denom == 0.0) denom = 1.0; CubeValues(0, 1, 0) = -(Fx(i, j + 1, k) * Sx(i, j + 1, k) + Fy(i, j + 1, k) * Sy(i, j + 1, k) + Fz(i, j + 1, k) * Sz(i, j + 1, k)) / (denom); denom = sqrt(pow(Fx(i, j, k + 1), 2) + pow(Fy(i, j, k + 1), 2) + pow(Fz(i, j, k + 1), 2)) * sqrt(pow(Sx(i, j, k + 1), 2) + pow(Sy(i, j, k + 1), 2) + pow(Sz(i, j, k + 1), 2)); if (denom == 0.0) denom = 1.0; CubeValues(0, 0, 1) = -(Fx(i, j, k + 1) * Sx(i, j, k + 1) + Fy(i, j, k + 1) * Sy(i, j, k + 1) + Fz(i, j, k + 1) * Sz(i, j, k + 1)) / (denom); denom = sqrt(pow(Fx(i + 1, j + 1, k), 2) + pow(Fy(i + 1, j + 1, k), 2) + pow(Fz(i + 1, j + 1, k), 2)) * sqrt(pow(Sx(i + 1, j + 1, k), 2) + pow(Sy(i + 1, j + 1, k), 2) + pow(Sz(i + 1, j + 1, k), 2)); if (denom == 0.0) denom = 1.0; CubeValues(1, 1, 0) = -(Fx(i + 1, j + 1, k) * Sx(i + 1, j + 1, k) + Fy(i + 1, j + 1, k) * Sy(i + 1, j + 1, k) + Fz(i + 1, j + 1, k) * Sz(i + 1, j + 1, k)) / (denom); denom = sqrt(pow(Fx(i + 1, j, k + 1), 2) + pow(Fy(i + 1, j, k + 1), 2) + pow(Fz(i + 1, j, k + 1), 2)) * sqrt(pow(Sx(i + 1, j, k + 1), 2) + pow(Sy(i + 1, j, k + 1), 2) + pow(Sz(i + 1, j, k + 1), 2)); if (denom == 0.0) denom = 1.0; CubeValues(1, 0, 1) = -(Fx(i + 1, j, k + 1) * Sx(i + 1, j, k + 1) + Fy(i + 1, j, k + 1) * Sy(i + 1, j, k + 1) + Fz(i + 1, j, k + 1) * Sz(i + 1, j, k + 1)) / (denom); denom = sqrt(pow(Fx(i, j + 1, k + 1), 2) + pow(Fy(i, j + 1, k + 1), 2) + pow(Fz(i, j + 1, k + 1), 2)) * sqrt(pow(Sx(i, j + 1, k + 1), 2) + pow(Sy(i, j + 1, k + 1), 2) + pow(Sz(i, j + 1, k + 1), 2)); if (denom == 0.0) denom = 1.0; CubeValues(0, 1, 1) = -(Fx(i, j + 1, k + 1) * Sx(i, j + 1, k + 1) + Fy(i, j + 1, k + 1) * Sy(i, j + 1, k + 1) + Fz(i, j + 1, k + 1) * Sz(i, j + 1, k + 1)) / (denom); denom = sqrt(pow(Fx(i + 1, j + 1, k + 1), 2) + pow(Fy(i + 1, j + 1, k + 1), 2) + pow(Fz(i + 1, j + 1, k + 1), 2)) * sqrt(pow(Sx(i + 1, j + 1, k + 1), 2) + pow(Sy(i + 1, j + 1, k + 1), 2) + pow(Sz(i + 1, j + 1, k + 1), 2)); if (denom == 0.0) denom = 1.0; CubeValues(1, 1, 1) = -(Fx(i + 1, j + 1, k + 1) * Sx(i + 1, j + 1, k + 1) + Fy(i + 1, j + 1, k + 1) * Sy(i + 1, j + 1, k + 1) + Fz(i + 1, j + 1, k + 1) * Sz(i + 1, j + 1, k + 1)) / (denom); // trilinear coefficients: f(x,y,z) = a+bx+cy+dz+exy+fxz+gyz+hxyz // Evaluate the coefficients a = CubeValues(0, 0, 0); b = CubeValues(1, 0, 0) - a; c = CubeValues(0, 1, 0) - a; d = CubeValues(0, 0, 1) - a; e = CubeValues(1, 1, 0) - a - b - c; f = CubeValues(1, 0, 1) - a - b - d; g = CubeValues(0, 1, 1) - a - c - d; h = CubeValues(1, 1, 1) - a - b - c - d - e - f - g; for (p = 0; p < npts; p++) { A = Points(p); x = A.x - 1.0 * i; y = A.y - 1.0 * j; z = A.z - 1.0 * k; CurveValues(p) = a + b * x + c * y + d * z + e * x * y + f * x * z + g * y * z + h * x * y * z; // printf("grad F = %f \n", sqrt(pow(Fx(i,j,k),2)+pow(Fy(i,j,k),2)+pow(Fz(i,j,k),2))); } integral = 0.0; for (p = 0; p < npts - 1; p++) { // Extract the line segment A = Points(p); B = Points(p + 1); vA = CurveValues(p); vB = CurveValues(p + 1); // Compute the length of the segment length = sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y) + (A.z - B.z) * (A.z - B.z)); integral += 0.5 * length * (vA + vB); } return integral; } //-------------------------------------------------------------------------------------------------------- inline void pmmc_CubeSurfaceInterpVector(DoubleArray &Vec_x, DoubleArray &Vec_y, DoubleArray &Vec_z, DoubleArray &CubeValues, DTMutableList &Points, IntArray &Triangles, DoubleArray &SurfaceVector, DoubleArray &VecAvg, int i, int j, int k, int npts, int ntris) { Point A, B, C; int p; double vA, vB, vC; double x, y, z; double s, s1, s2, s3, temp; double a, b, c, d, e, f, g, h; // ................x component ............................. // Copy the curvature values for the cube CubeValues(0, 0, 0) = Vec_x(i, j, k); CubeValues(1, 0, 0) = Vec_x(i + 1, j, k); CubeValues(0, 1, 0) = Vec_x(i, j + 1, k); CubeValues(1, 1, 0) = Vec_x(i + 1, j + 1, k); CubeValues(0, 0, 1) = Vec_x(i, j, k + 1); CubeValues(1, 0, 1) = Vec_x(i + 1, j, k + 1); CubeValues(0, 1, 1) = Vec_x(i, j + 1, k + 1); CubeValues(1, 1, 1) = Vec_x(i + 1, j + 1, k + 1); // trilinear coefficients: f(x,y,z) = a+bx+cy+dz+exy+fxz+gyz+hxyz a = CubeValues(0, 0, 0); b = CubeValues(1, 0, 0) - a; c = CubeValues(0, 1, 0) - a; d = CubeValues(0, 0, 1) - a; e = CubeValues(1, 1, 0) - a - b - c; f = CubeValues(1, 0, 1) - a - b - d; g = CubeValues(0, 1, 1) - a - c - d; h = CubeValues(1, 1, 1) - a - b - c - d - e - f - g; for (p = 0; p < npts; p++) { A = Points(p); x = A.x - 1.0 * i; y = A.y - 1.0 * j; z = A.z - 1.0 * k; SurfaceVector(p) = a + b * x + c * y + d * z + e * x * y + f * x * z + g * y * z + h * x * y * z; } // ................y component ............................. // Copy the curvature values for the cube CubeValues(0, 0, 0) = Vec_y(i, j, k); CubeValues(1, 0, 0) = Vec_y(i + 1, j, k); CubeValues(0, 1, 0) = Vec_y(i, j + 1, k); CubeValues(1, 1, 0) = Vec_y(i + 1, j + 1, k); CubeValues(0, 0, 1) = Vec_y(i, j, k + 1); CubeValues(1, 0, 1) = Vec_y(i + 1, j, k + 1); CubeValues(0, 1, 1) = Vec_y(i, j + 1, k + 1); CubeValues(1, 1, 1) = Vec_y(i + 1, j + 1, k + 1); // trilinear coefficients: f(x,y,z) = a+bx+cy+dz+exy+fxz+gyz+hxyz a = CubeValues(0, 0, 0); b = CubeValues(1, 0, 0) - a; c = CubeValues(0, 1, 0) - a; d = CubeValues(0, 0, 1) - a; e = CubeValues(1, 1, 0) - a - b - c; f = CubeValues(1, 0, 1) - a - b - d; g = CubeValues(0, 1, 1) - a - c - d; h = CubeValues(1, 1, 1) - a - b - c - d - e - f - g; for (p = 0; p < npts; p++) { A = Points(p); x = A.x - 1.0 * i; y = A.y - 1.0 * j; z = A.z - 1.0 * k; SurfaceVector(npts + p) = a + b * x + c * y + d * z + e * x * y + f * x * z + g * y * z + h * x * y * z; } // ................z component ............................. // Copy the curvature values for the cube CubeValues(0, 0, 0) = Vec_z(i, j, k); CubeValues(1, 0, 0) = Vec_z(i + 1, j, k); CubeValues(0, 1, 0) = Vec_z(i, j + 1, k); CubeValues(1, 1, 0) = Vec_z(i + 1, j + 1, k); CubeValues(0, 0, 1) = Vec_z(i, j, k + 1); CubeValues(1, 0, 1) = Vec_z(i + 1, j, k + 1); CubeValues(0, 1, 1) = Vec_z(i, j + 1, k + 1); CubeValues(1, 1, 1) = Vec_z(i + 1, j + 1, k + 1); // trilinear coefficients: f(x,y,z) = a+bx+cy+dz+exy+fxz+gyz+hxyz a = CubeValues(0, 0, 0); b = CubeValues(1, 0, 0) - a; c = CubeValues(0, 1, 0) - a; d = CubeValues(0, 0, 1) - a; e = CubeValues(1, 1, 0) - a - b - c; f = CubeValues(1, 0, 1) - a - b - d; g = CubeValues(0, 1, 1) - a - c - d; h = CubeValues(1, 1, 1) - a - b - c - d - e - f - g; for (p = 0; p < npts; p++) { A = Points(p); x = A.x - 1.0 * i; y = A.y - 1.0 * j; z = A.z - 1.0 * k; SurfaceVector(2 * npts + p) = a + b * x + c * y + d * z + e * x * y + f * x * z + g * y * z + h * x * y * z; } //............................................................................. for (int r = 0; r < ntris; r++) { A = Points(Triangles(0, r)); B = Points(Triangles(1, r)); C = Points(Triangles(2, r)); // Compute length of sides (assume dx=dy=dz) s1 = sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y) + (A.z - B.z) * (A.z - B.z)); s2 = sqrt((A.x - C.x) * (A.x - C.x) + (A.y - C.y) * (A.y - C.y) + (A.z - C.z) * (A.z - C.z)); s3 = sqrt((B.x - C.x) * (B.x - C.x) + (B.y - C.y) * (B.y - C.y) + (B.z - C.z) * (B.z - C.z)); s = 0.5 * (s1 + s2 + s3); temp = s * (s - s1) * (s - s2) * (s - s3); if (temp > 0.0) { // Increment the averaged values // x component vA = SurfaceVector(Triangles(0, r)); vB = SurfaceVector(Triangles(1, r)); vC = SurfaceVector(Triangles(2, r)); VecAvg(0) += sqrt(temp) * 0.33333333333333333 * (vA + vB + vC); // y component vA = SurfaceVector(npts + Triangles(0, r)); vB = SurfaceVector(npts + Triangles(1, r)); vC = SurfaceVector(npts + Triangles(2, r)); VecAvg(1) += sqrt(temp) * 0.33333333333333333 * (vA + vB + vC); // z component vA = SurfaceVector(2 * npts + Triangles(0, r)); vB = SurfaceVector(2 * npts + Triangles(1, r)); vC = SurfaceVector(2 * npts + Triangles(2, r)); VecAvg(2) += sqrt(temp) * 0.33333333333333333 * (vA + vB + vC); } } } //-------------------------------------------------------------------------------------------------------- inline double pmmc_CubeSurfaceOrientation(DoubleArray &Orientation, DTMutableList &Points, IntArray &Triangles, int ntris) { int r; double temp, area, s, s1, s2, s3; double nx, ny, nz, normsq; Point A, B, C; area = 0.0; for (r = 0; r < ntris; r++) { A = Points(Triangles(0, r)); B = Points(Triangles(1, r)); C = Points(Triangles(2, r)); // Compute the triangle normal vector nx = (B.y - A.y) * (C.z - A.z) - (B.z - A.z) * (C.y - A.y); ny = (B.z - A.z) * (C.x - A.x) - (B.x - A.x) * (C.z - A.z); nz = (B.x - A.x) * (C.y - A.y) - (B.y - A.y) * (C.x - A.x); normsq = 1.0 / (nx * nx + ny * ny + nz * nz); // Compute length of sides (assume dx=dy=dz) s1 = sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y) + (A.z - B.z) * (A.z - B.z)); s2 = sqrt((A.x - C.x) * (A.x - C.x) + (A.y - C.y) * (A.y - C.y) + (A.z - C.z) * (A.z - C.z)); s3 = sqrt((B.x - C.x) * (B.x - C.x) + (B.y - C.y) * (B.y - C.y) + (B.z - C.z) * (B.z - C.z)); s = 0.5 * (s1 + s2 + s3); temp = s * (s - s1) * (s - s2) * (s - s3); if (temp > 0.0) { temp = sqrt(temp); area += temp; Orientation(0) += temp * nx * nx * normsq; // Gxx Orientation(1) += temp * ny * ny * normsq; // Gyy Orientation(2) += temp * nz * nz * normsq; // Gzz Orientation(3) += temp * nx * ny * normsq; // Gxy Orientation(4) += temp * nx * nz * normsq; // Gxz Orientation(5) += temp * ny * nz * normsq; // Gyz } } return area; } //-------------------------------------------------------------------------------------------------------- inline double pmmc_CommonCurveSpeed(DoubleArray &CubeValues, DoubleArray &dPdt, DoubleArray &ReturnVector, DoubleArray &Fx, DoubleArray &Fy, DoubleArray &Fz, DoubleArray &Sx, DoubleArray &Sy, DoubleArray &Sz, DTMutableList &Points, int i, int j, int k, int npts) { NULL_USE(CubeValues); int p; double s, lwns, norm; double zeta; double tangent_x, tangent_y, tangent_z; double ns_x, ns_y, ns_z; double nwn_x, nwn_y, nwn_z; double nwns_x, nwns_y, nwns_z; Point P, A, B; lwns = 0.0; double ReturnValue = 0; NULL_USE(lwns); TriLinPoly Px, Py, Pz, SDx, SDy, SDz, Pt; Px.assign(Fx, i, j, k); Py.assign(Fy, i, j, k); Pz.assign(Fz, i, j, k); SDx.assign(Sx, i, j, k); SDy.assign(Sy, i, j, k); SDz.assign(Sz, i, j, k); Pt.assign(dPdt, i, j, k); for (p = 0; p < npts - 1; p++) { // Extract the line segment A = Points(p); B = Points(p + 1); // Midpoint of the line P.x = 0.5 * (A.x + B.x); P.y = 0.5 * (A.y + B.y); P.z = 0.5 * (A.z + B.z); // Compute the curve tangent tangent_x = A.x - B.x; tangent_y = A.y - B.y; tangent_z = A.z - B.z; // Get the normal to the solid surface ns_x = SDx.eval(P); ns_y = SDy.eval(P); ns_z = SDz.eval(P); norm = ns_x * ns_x + ns_y * ns_y + ns_z * ns_z; if (norm > 0.0) { ns_x /= norm; ns_y /= norm; ns_z /= norm; } // Get the Color gradient nwn_x = Px.eval(P); nwn_y = Py.eval(P); nwn_z = Pz.eval(P); // to compute zeta, consider the change only in the plane of the solid surface norm = nwn_x * ns_x + nwn_y * ns_y + nwn_z * ns_z; // component of color gradient aligned with solid nwns_x = nwn_x - norm * ns_x; nwns_y = nwn_y - norm * ns_y; nwns_z = nwn_z - norm * ns_z; // now {nwns_x, nwns_y, nwns_z} is the color gradient confined to the solid plane norm = sqrt(nwns_x * nwns_x + nwns_y * nwns_y + nwns_z * nwns_z); zeta = -Pt.eval(P) / norm; // normalize the normal to the common curve within the solid surface if (norm > 0.0) { nwns_x /= norm; nwns_y /= norm; nwns_z /= norm; } /* // normal to the wn interface norm = nwn_x*nwn_x + nwn_y*nwn_y + nwn_z*nwn_z; // Compute the interface speed if (norm > 0.0){ nwn_x /= norm; nwn_y /= norm; nwn_z /= norm; } // Compute the normal to the common curve (vector product of tangent and solid normal) nwns_x = ns_y*tangent_z - ns_z*tangent_y; nwns_y = ns_z*tangent_x - ns_x*tangent_z; nwns_z = ns_x*tangent_y - ns_y*tangent_x; // dot product of nwns and nwn should be positive if (nwn_x*nwns_x+nwn_y*nwns_y+nwn_z*nwns_z < 0.0){ nwns_x = -nwns_x; nwns_y = -nwns_y; nwns_z = -nwns_z; } // normalize the common curve normal norm = sqrt(nwns_x*nwns_x + nwns_y*nwns_y + nwns_z*nwns_z); if (norm > 0.0){ nwns_x /= norm; nwns_y /= norm; nwns_z /= norm; } */ // Compute the length of the segment s = sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y) + (A.z - B.z) * (A.z - B.z)); // Add the length to the common line // lwns += s; // Compute the common curve velocity if (norm > 0.0) { ReturnVector(0) += zeta * nwns_x * s; ReturnVector(1) += zeta * nwns_y * s; ReturnVector(2) += zeta * nwns_z * s; ReturnValue += zeta * s; } } NULL_USE(tangent_x); NULL_USE(tangent_y); NULL_USE(tangent_z); return ReturnValue; } inline void pmmc_CurveOrientation(DoubleArray &Orientation, DTMutableList &Points, int npts, int i, int j, int k) { double twnsx, twnsy, twnsz, length; // tangent, norm Point P, A, B; for (int p = 0; p < npts - 1; p++) { // Extract the line segment A = Points(p); B = Points(p + 1); P.x = 0.5 * (A.x + B.x) - 1.0 * i; P.y = 0.5 * (A.y + B.y) - 1.0 * j; P.z = 0.5 * (A.z + B.z) - 1.0 * k; A.x -= 1.0 * i; A.y -= 1.0 * j; A.z -= 1.0 * k; B.x -= 1.0 * i; B.y -= 1.0 * j; B.z -= 1.0 * k; length = sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y) + (A.z - B.z) * (A.z - B.z)); // tangent vector twnsx = (B.x - A.x) / length; twnsy = (B.y - A.y) / length; twnsz = (B.z - A.z) / length; Orientation(0) += (1.0 - twnsx * twnsx) * length; // Gxx Orientation(1) += (1.0 - twnsy * twnsy) * length; // Gyy Orientation(2) += (1.0 - twnsz * twnsz) * length; // Gzz Orientation(3) += (0.0 - twnsx * twnsy) * length; // Gxy Orientation(4) += (0.0 - twnsx * twnsz) * length; // Gxz Orientation(5) += (0.0 - twnsy * twnsz) * length; // Gyz } } inline void pmmc_CurveCurvature(DoubleArray &f, DoubleArray &s, DoubleArray &f_x, DoubleArray &f_y, DoubleArray &f_z, DoubleArray &s_x, DoubleArray &s_y, DoubleArray &s_z, DoubleArray &KN, DoubleArray &KG, double &KNavg, double &KGavg, DTMutableList &Points, int npts, int ic, int jc, int kc) { NULL_USE(f); NULL_USE(s); NULL_USE(KN); NULL_USE(KG); int p, i, j, k; double length; double fxx, fyy, fzz, fxy, fxz, fyz, fx, fy, fz; double sxx, syy, szz, sxy, sxz, syz, sx, sy, sz; // double Axx,Axy,Axz,Ayx,Ayy,Ayz,Azx,Azy,Azz; // double Tx[8],Ty[8],Tz[8]; // Tangent vector // double Nx[8],Ny[8],Nz[8]; // Principle normal double twnsx, twnsy, twnsz, nwnsx, nwnsy, nwnsz, K; // tangent,normal and curvature double nsx, nsy, nsz, norm; double nwx, nwy, nwz; double nwsx, nwsy, nwsz; double nwnx, nwny, nwnz; Point P, A, B; // Local trilinear approximation for tangent and normal vector TriLinPoly Tx, Ty, Tz, Nx, Ny, Nz, Sx, Sy, Sz; // Loop over the cube and compute the derivatives for (k = kc; k < kc + 2; k++) { for (j = jc; j < jc + 2; j++) { for (i = ic; i < ic + 2; i++) { sx = s_x(i, j, k); sy = s_y(i, j, k); sz = s_z(i, j, k); fx = f_x(i, j, k); fy = f_y(i, j, k); fz = f_z(i, j, k); // Normal to fluid surface Nx.Corners(i - ic, j - jc, k - kc) = fx; Ny.Corners(i - ic, j - jc, k - kc) = fy; Nz.Corners(i - ic, j - jc, k - kc) = fz; // Normal to solid surface Sx.Corners(i - ic, j - jc, k - kc) = sx; Sy.Corners(i - ic, j - jc, k - kc) = sy; Sz.Corners(i - ic, j - jc, k - kc) = sz; // Compute the tangent vector norm = sqrt((sy * fz - sz * fy) * (sy * fz - sz * fy) + (sz * fx - sx * fz) * (sz * fx - sx * fz) + (sx * fy - sy * fx) * (sx * fy - sy * fx)); if (norm == 0.0) norm = 1.0; Tx.Corners(i - ic, j - jc, k - kc) = (sy * fz - sz * fy) / norm; Ty.Corners(i - ic, j - jc, k - kc) = (sz * fx - sx * fz) / norm; Tz.Corners(i - ic, j - jc, k - kc) = (sx * fy - sy * fx) / norm; } } } // Assign the tri-linear polynomial coefficients Sx.assign(); Sy.assign(); Sz.assign(); Tx.assign(); Ty.assign(); Tz.assign(); Nx.assign(); Ny.assign(); Nz.assign(); double tax, tay, taz, tbx, tby, tbz; for (p = 0; p < npts - 1; p++) { // Extract the line segment A = Points(p); B = Points(p + 1); P.x = 0.5 * (A.x + B.x) - 1.0 * i; P.y = 0.5 * (A.y + B.y) - 1.0 * j; P.z = 0.5 * (A.z + B.z) - 1.0 * k; A.x -= 1.0 * i; A.y -= 1.0 * j; A.z -= 1.0 * k; B.x -= 1.0 * i; B.y -= 1.0 * j; B.z -= 1.0 * k; length = sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y) + (A.z - B.z) * (A.z - B.z)); // tangent vector twnsx = B.x - A.x; twnsy = B.y - A.y; twnsz = B.z - A.z; norm = sqrt(twnsx * twnsx + twnsy * twnsy + twnsz * twnsz); if (norm == 0.0) norm = 1.0; twnsx /= norm; twnsy /= norm; twnsz /= norm; // ***************************************************** // Compute tangent vector at A and B and normalize tax = Tx.eval(A); tay = Ty.eval(A); taz = Tz.eval(A); norm = sqrt(tax * tax + tay * tay + taz * taz); if (norm == 0.0) norm = 1.0; tax /= norm; tay /= norm; taz /= norm; tbx = Tx.eval(B); tby = Ty.eval(B); tbz = Tz.eval(B); norm = sqrt(tbx * tbx + tby * tby + tbz * tbz); if (norm == 0.0) norm = 1.0; tbx /= norm; tby /= norm; tbz /= norm; // ***************************************************** // ***************************************************** // Compute the divergence of the tangent vector nwnsx = (tax - tbx) / length; nwnsy = (tay - tby) / length; nwnsz = (taz - tbz) / length; K = sqrt(nwnsx * nwnsx + nwnsy * nwnsy + nwnsz * nwnsz); if (K == 0.0) K = 1.0; nwnsx /= K; nwnsy /= K; nwnsz /= K; // ***************************************************** // Normal vector to the solid surface nsx = Sx.eval(P); nsy = Sy.eval(P); nsz = Sz.eval(P); norm = sqrt(nsx * nsx + nsy * nsy + nsz * nsz); if (norm == 0.0) norm = 1.0; nsx /= norm; nsy /= norm; nsz /= norm; // Normal vector to the fluid surface nwx = Nx.eval(P); nwy = Ny.eval(P); nwz = Nz.eval(P); norm = sqrt(nwx * nwx + nwy * nwy + nwz * nwz); if (norm == 0.0) norm = 1.0; nwx /= norm; nwy /= norm; nwz /= norm; // common curve normal in the solid surface tangent plane (rel. geodesic curvature) nwsx = twnsy * nsz - twnsz * nsy; nwsy = twnsz * nsx - twnsx * nsz; nwsz = twnsx * nsy - twnsy * nsx; norm = sqrt(nwsx * nwsx + nwsy * nwsy + nwsz * nwsz); if (norm == 0.0) norm = 1.0; nwsx /= norm; nwsy /= norm; nwsz /= norm; /* normal to ws interface boundary should point into fluid (same direction as gradient) */ if (nwx * nwsx + nwy * nwsy + nwz * nwsz < 0.0) { nwsx = -nwsx; nwsy = -nwsy; nwsz = -nwsz; } // common curve normal in the fluid surface tangent plane (rel. geodesic curvature) nwnx = twnsy * nwz - twnsz * nwy; nwny = twnsz * nwx - twnsx * nwz; nwnz = twnsx * nwy - twnsy * nwx; norm = sqrt(nwnx * nwnx + nwny * nwny + nwnz * nwnz); if (norm == 0.0) norm = 1.0; nwnx /= norm; nwny /= norm; nwnz /= norm; /* normal to wn interface boundary should point into the solid */ if (nsx * nwnx + nsy * nwny + nsz * nwnz > 0.0) { nwnx = -nwnx; nwny = -nwny; nwnz = -nwnz; } if (length > 0.0) { // normal curvature component in the direction of the solid surface //KNavg += K * (nsx * nwnsx + nsy * nwnsy + nsz * nwnsz) * length; KNavg += K * (nwnx * nwnsx + nwny * nwnsy + nwnz * nwnsz) * length; //geodesic curvature KGavg += K * (nwsx * nwnsx + nwsy * nwnsy + nwsz * nwnsz) * length; } } NULL_USE(fxx); NULL_USE(fyy); NULL_USE(fzz); NULL_USE(fxy); NULL_USE(fxz); NULL_USE(fyz); NULL_USE(fx); NULL_USE(fy); NULL_USE(fz); NULL_USE(sxx); NULL_USE(syy); NULL_USE(szz); NULL_USE(sxy); NULL_USE(sxz); NULL_USE(syz); NULL_USE(sx); NULL_USE(sy); NULL_USE(sz); } //-------------------------------------------------------------------------------------------------------- inline double pmmc_InterfaceSpeed( DoubleArray &dPdt, DoubleArray &P_x, DoubleArray &P_y, DoubleArray &P_z, DoubleArray &CubeValues, DTMutableList &Points, IntArray &Triangles, DoubleArray &SurfaceVector, DoubleArray &AvgSpeed, DoubleArray &AvgVel, int i, int j, int k, int npts, int ntris) { NULL_USE(CubeValues); NULL_USE(SurfaceVector); NULL_USE(npts); Point A, B, C, P; double x, y, z; double s, s1, s2, s3, area; double norm, zeta; double ReturnValue = 0.0; TriLinPoly Px, Py, Pz, Pt; Px.assign(P_x, i, j, k); Py.assign(P_y, i, j, k); Pz.assign(P_z, i, j, k); Pt.assign(dPdt, i, j, k); //............................................................................. // Compute the average speed of the interface for (int r = 0; r < ntris; r++) { A = Points(Triangles(0, r)); B = Points(Triangles(1, r)); C = Points(Triangles(2, r)); // Compute length of sides (assume dx=dy=dz) s1 = sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y) + (A.z - B.z) * (A.z - B.z)); s2 = sqrt((A.x - C.x) * (A.x - C.x) + (A.y - C.y) * (A.y - C.y) + (A.z - C.z) * (A.z - C.z)); s3 = sqrt((B.x - C.x) * (B.x - C.x) + (B.y - C.y) * (B.y - C.y) + (B.z - C.z) * (B.z - C.z)); s = 0.5 * (s1 + s2 + s3); area = sqrt(s * (s - s1) * (s - s2) * (s - s3)); // Compute the centroid P P.x = 0.33333333333333333 * (A.x + B.x + C.x); P.y = 0.33333333333333333 * (A.y + B.y + C.y); P.z = 0.33333333333333333 * (A.z + B.z + C.z); if (area > 0.0) { x = Px.eval(P); y = Py.eval(P); z = Pz.eval(P); norm = sqrt(x * x + y * y + z * z); if (norm == 0.0) norm = 1.0; // Compute the interface speed from time derivative and gradient (Level Set Equation) zeta = -Pt.eval(P) / norm; // Normalize the normal vector x /= norm; y /= norm; z /= norm; // Compute the average AvgVel(0) += area * zeta * x; AvgVel(1) += area * zeta * y; AvgVel(2) += area * zeta * z; AvgSpeed(r) = zeta * area; ReturnValue += zeta * area; } } return ReturnValue; //............................................................................. } //-------------------------------------------------------------------------------------------------------- inline double geomavg_EulerCharacteristic(DTMutableList &Points, IntArray &Triangles, int &npts, int &ntris, int &i, int &j, int &k) { NULL_USE(Points); NULL_USE(Triangles); NULL_USE(npts); NULL_USE(ntris); NULL_USE(i); NULL_USE(j); NULL_USE(k); /* REFERENCE * Huang, Liu, Lee, Yang, Tsang * On concise 3-D simple point comparisons: a marching cubes paradigm * IEEE Transactions on Medical Imaging, Vol. 28, No. 1 * January 2009 */ // Compute the Euler characteristic for triangles in a cube /* bool graph[3][3]; double CountSideExternal=0; double ShareSideInternal=0; // Exclude edges and vertices shared with between multiple cubes for (int p=0; p 0) EulerChar = (0.25 * nvert - nside_intern - 0.5 * nside_extern + nface); return EulerChar; } inline double mink_phase_epc6(IntArray &PhaseID, DoubleArray &CubeValues, int PhaseLabel, int &i, int &j, int &k) { /* * Compute the Euler Poincare characteristic for a phase based on 6 adjacency * compute the local contribution within the specified cube must sum to get total * PhaseID -- label of phases on a mesh * PhaseLabel -- label assigned to phase that we are computing * i,j,k -- identifies the local cube */ double epc_ncubes, epc_nface, epc_nedge, epc_nvert; epc_ncubes = epc_nface = epc_nedge = epc_nvert = 0; // Assign CubeValues to be phase indicator for for (int kk = 0; kk < 2; kk++) { for (int jj = 0; jj < 2; jj++) { for (int ii = 0; ii < 2; ii++) { if (PhaseID(i + ii, j + jj, k + kk) == PhaseLabel) CubeValues(ii, jj, kk) = 1; else CubeValues(ii, jj, kk) = 0; } } } // update faces edges and cubes for NWP epc_ncubes += CubeValues(0, 0, 0) * CubeValues(1, 0, 0) * CubeValues(0, 1, 0) * CubeValues(0, 0, 1) * CubeValues(1, 1, 0) * CubeValues(1, 0, 1) * CubeValues(0, 1, 1) * CubeValues(1, 1, 1); // three faces (others shared by other cubes) epc_nface += CubeValues(1, 0, 0) * CubeValues(1, 1, 0) * CubeValues(1, 0, 1) * CubeValues(1, 1, 1); epc_nface += CubeValues(0, 1, 0) * CubeValues(1, 1, 0) * CubeValues(0, 1, 1) * CubeValues(1, 1, 1); epc_nface += CubeValues(0, 0, 1) * CubeValues(0, 1, 1) * CubeValues(1, 0, 1) * CubeValues(1, 1, 1); // six of twelve edges (others shared by other cubes) epc_nedge += CubeValues(1, 1, 1) * CubeValues(1, 1, 0); epc_nedge += CubeValues(1, 1, 1) * CubeValues(1, 0, 1); epc_nedge += CubeValues(1, 1, 1) * CubeValues(0, 1, 1); epc_nedge += CubeValues(1, 0, 1) * CubeValues(1, 0, 0); epc_nedge += CubeValues(1, 0, 1) * CubeValues(0, 0, 1); epc_nedge += CubeValues(0, 1, 1) * CubeValues(0, 0, 1); // four of eight vertices epc_nvert += CubeValues(1, 1, 0); epc_nvert += CubeValues(1, 0, 1); epc_nvert += CubeValues(0, 1, 1); epc_nvert += CubeValues(1, 1, 1); double chi = epc_nvert - epc_nedge + epc_nface - epc_ncubes; return chi; } inline double mink_EulerCharacteristic(DTMutableList &Points, IntArray &Triangles, DoubleArray &CubeValues, int &npts, int &ntris, int &i, int &j, int &k) { NULL_USE(CubeValues); // Compute the Euler characteristic for triangles in a cube // Exclude edges and vertices shared with between multiple cubes double EulerChar; int nvert = npts; int nside = 2 * nvert - 3; int nface = nvert - 2; //if (ntris != nface){ // nface = ntris; // nside = //} //........................................................... // Check that this point is not on a previously computed face // Note direction that the marching cubes algorithm marches // In parallel, other sub-domains fill in the lower boundary for (int p = 0; p < npts; p++) { Point PT = Points(p); if (PT.x - double(i) < 1e-12) nvert -= 1; else if (PT.y - double(j) < 1e-12) nvert -= 1; else if (PT.z - double(k) < 1e-12) nvert -= 1; } // Remove redundantly computed edges (shared by two cubes across a cube face) for (int p = 0; p < ntris; p++) { Point A = Points(Triangles(0, p)); Point B = Points(Triangles(1, p)); Point C = Points(Triangles(2, p)); // Check side A-B bool newside = true; if (A.x - double(i) < 1e-12 && B.x - double(i) < 1e-12) newside = false; if (A.y - double(j) < 1e-12 && B.y - double(j) < 1e-12) newside = false; if (A.z - double(k) < 1e-12 && B.z - double(k) < 1e-12) newside = false; if (!newside) nside -= 1; // Check side A-C newside = true; if (A.x - double(i) < 1e-12 && C.x - double(i) < 1e-12) newside = false; if (A.y - double(j) < 1e-12 && C.y - double(j) < 1e-12) newside = false; if (A.z - double(k) < 1e-12 && C.z - double(k) < 1e-12) newside = false; if (!newside) nside -= 1; // Check side B-C newside = true; if (B.x - double(i) < 1e-12 && C.x - double(i) < 1e-12) newside = false; if (B.y - double(j) < 1e-12 && C.y - double(j) < 1e-12) newside = false; if (B.z - double(k) < 1e-12 && C.z - double(k) < 1e-12) newside = false; if (!newside) nside -= 1; } EulerChar = 1.0 * (nvert - nside + nface); return EulerChar; } #endif