1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872 |
- // David Eberly, Geometric Tools, Redmond WA 98052
- // Copyright (c) 1998-2020
- // Distributed under the Boost Software License, Version 1.0.
- // https://www.boost.org/LICENSE_1_0.txt
- // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
- // Version: 4.0.2020.01.08
- #pragma once
- #include <Mathematics/Logger.h>
- #include <Mathematics/Array2.h>
- #include <Mathematics/Math.h>
- #include <Mathematics/TriangleKey.h>
- #include <map>
- #include <memory>
- #include <ostream>
- // Extract level surfaces using an adaptive approach to reduce the triangle
- // count. The implementation is for the algorithm described in the paper
- // Multiresolution Isosurface Extraction with Adaptive Skeleton Climbing
- // Tim Poston, Tien-Tsin Wong and Pheng-Ann Heng
- // Computer Graphics forum, volume 17, issue 3, September 1998
- // pages 137-147
- // https://onlinelibrary.wiley.com/doi/abs/10.1111/1467-8659.00261
- namespace WwiseGTE
- {
- // The image type T must be one of the integer types: int8_t, int16_t,
- // int32_t, uint8_t, uint16_t or uint32_t. Internal integer computations
- // are performed using int64_t. The type Real is for extraction to
- // floating-point vertices.
- template <typename T, typename Real>
- class AdaptiveSkeletonClimbing3
- {
- public:
- // Construction and destruction. The input image is assumed to
- // contain (2^N+1)-by-(2^N+1)-by-(2^N+1) elements where N >= 0.
- // The organization is lexicographic order for (x,y,z). When
- // 'fixBoundary' is set to 'true', image boundary voxels are not
- // allowed to merge with any other voxels. This forces highest
- // level of detail on the boundary. The idea is that an image too
- // large to process by itself can be partitioned into smaller
- // subimages and the adaptive skeleton climbing applied to each
- // subimage. By forcing highest resolution on the boundary,
- // adjacent subimages will not have any cracking problems.
- AdaptiveSkeletonClimbing3(int N, T const* inputVoxels,
- bool fixBoundary = false)
- :
- mTwoPowerN(1 << N),
- mSize(mTwoPowerN + 1),
- mSizeSqr(mSize * mSize),
- mInputVoxels(inputVoxels),
- mLevel((Real)0),
- mFixBoundary(fixBoundary),
- mXMerge(mSize, mSize),
- mYMerge(mSize, mSize),
- mZMerge(mSize, mSize)
- {
- static_assert(std::is_integral<T>::value && sizeof(T) <= 4,
- "Type T must be int{8,16,32}_t or uint{8,16,32}_t.");
- if (N <= 0 || mInputVoxels == nullptr)
- {
- LogError("Invalid input.");
- }
- for (int i = 0; i < mSize; ++i)
- {
- for (int j = 0; j < mSize; ++j)
- {
- mXMerge[i][j] = std::make_shared<LinearMergeTree>(N);
- mYMerge[i][j] = std::make_shared<LinearMergeTree>(N);
- mZMerge[i][j] = std::make_shared<LinearMergeTree>(N);
- }
- }
- }
- // TODO: Refactor this class to have base class SurfaceExtractor.
- typedef std::array<Real, 3> Vertex;
- typedef std::array<int, 2> Edge;
- typedef TriangleKey<true> Triangle;
- void Extract(Real level, int depth,
- std::vector<Vertex>& vertices, std::vector<Triangle>& triangles)
- {
- std::vector<Vertex> localVertices;
- std::vector<Triangle> localTriangles;
- mBoxes.clear();
- mLevel = level;
- Merge(depth);
- Tessellate(localVertices, localTriangles);
- vertices = std::move(localVertices);
- triangles = std::move(localTriangles);
- }
- void MakeUnique(std::vector<Vertex>& vertices,
- std::vector<Triangle>& triangles)
- {
- size_t numVertices = vertices.size();
- size_t numTriangles = triangles.size();
- if (numVertices == 0 || numTriangles == 0)
- {
- return;
- }
- // Compute the map of unique vertices and assign to them new and
- // unique indices.
- std::map<Vertex, int> vmap;
- int nextVertex = 0;
- for (size_t v = 0; v < numVertices; ++v)
- {
- // Keep only unique vertices.
- auto result = vmap.insert(std::make_pair(vertices[v], nextVertex));
- if (result.second)
- {
- ++nextVertex;
- }
- }
- // Compute the map of unique triangles and assign to them new and
- // unique indices.
- std::map<Triangle, int> tmap;
- int nextTriangle = 0;
- for (size_t t = 0; t < numTriangles; ++t)
- {
- Triangle& triangle = triangles[t];
- for (int i = 0; i < 3; ++i)
- {
- auto iter = vmap.find(vertices[triangle.V[i]]);
- LogAssert(iter != vmap.end(), "Expecting the vertex to be in the vmap.");
- triangle.V[i] = iter->second;
- }
- // Keep only unique triangles.
- auto result = tmap.insert(std::make_pair(triangle, nextTriangle));
- if (result.second)
- {
- ++nextTriangle;
- }
- }
- // Pack the vertices into an array.
- vertices.resize(vmap.size());
- for (auto const& element : vmap)
- {
- vertices[element.second] = element.first;
- }
- // Pack the triangles into an array.
- triangles.resize(tmap.size());
- for (auto const& element : tmap)
- {
- triangles[element.second] = element.first;
- }
- }
- void OrientTriangles(std::vector<Vertex>& vertices,
- std::vector<Triangle>& triangles, bool sameDir)
- {
- for (auto& triangle : triangles)
- {
- // Get the triangle vertices.
- std::array<Real, 3> v0 = vertices[triangle.V[0]];
- std::array<Real, 3> v1 = vertices[triangle.V[1]];
- std::array<Real, 3> v2 = vertices[triangle.V[2]];
- // Construct the triangle normal based on the current
- // orientation.
- std::array<Real, 3> edge1, edge2, normal;
- for (int i = 0; i < 3; ++i)
- {
- edge1[i] = v1[i] - v0[i];
- edge2[i] = v2[i] - v0[i];
- }
- normal[0] = edge1[1] * edge2[2] - edge1[2] * edge2[1];
- normal[1] = edge1[2] * edge2[0] - edge1[0] * edge2[2];
- normal[2] = edge1[0] * edge2[1] - edge1[1] * edge2[0];
- // Get the image gradient at the vertices.
- std::array<Real, 3> grad0 = GetGradient(v0);
- std::array<Real, 3> grad1 = GetGradient(v1);
- std::array<Real, 3> grad2 = GetGradient(v2);
- // Compute the average gradient.
- std::array<Real, 3> gradAvr;
- for (int i = 0; i < 3; ++i)
- {
- gradAvr[i] = (grad0[i] + grad1[i] + grad2[i]) / (Real)3;
- }
- // Compute the dot product of normal and average gradient.
- Real dot = gradAvr[0] * normal[0] + gradAvr[1] * normal[1] + gradAvr[2] * normal[2];
- // Choose triangle orientation based on gradient direction.
- if (sameDir)
- {
- if (dot < (Real)0)
- {
- // Wrong orientation, reorder it.
- std::swap(triangle.V[1], triangle.V[2]);
- }
- }
- else
- {
- if (dot > (Real)0)
- {
- // Wrong orientation, reorder it.
- std::swap(triangle.V[1], triangle.V[2]);
- }
- }
- }
- }
- void ComputeNormals(std::vector<Vertex> const& vertices,
- std::vector<Triangle> const& triangles,
- std::vector<std::array<Real, 3>>& normals)
- {
- // Compute a vertex normal to be area-weighted sums of the normals
- // to the triangles that share that vertex.
- std::array<Real, 3> const zero{ (Real)0, (Real)0, (Real)0 };
- normals.resize(vertices.size());
- std::fill(normals.begin(), normals.end(), zero);
- for (auto const& triangle : triangles)
- {
- // Get the triangle vertices.
- std::array<Real, 3> v0 = vertices[triangle.V[0]];
- std::array<Real, 3> v1 = vertices[triangle.V[1]];
- std::array<Real, 3> v2 = vertices[triangle.V[2]];
- // Construct the triangle normal.
- std::array<Real, 3> edge1, edge2, normal;
- for (int i = 0; i < 3; ++i)
- {
- edge1[i] = v1[i] - v0[i];
- edge2[i] = v2[i] - v0[i];
- }
- normal[0] = edge1[1] * edge2[2] - edge1[2] * edge2[1];
- normal[1] = edge1[2] * edge2[0] - edge1[0] * edge2[2];
- normal[2] = edge1[0] * edge2[1] - edge1[1] * edge2[0];
- // Maintain the sum of normals at each vertex.
- for (int i = 0; i < 3; ++i)
- {
- for (int j = 0; j < 3; ++j)
- {
- normals[triangle.V[i]][j] += normal[j];
- }
- }
- }
- // The normal vector storage was used to accumulate the sum of
- // triangle normals. Now these vectors must be rescaled to be
- // unit length.
- for (auto& normal : normals)
- {
- Real sqrLength = normal[0] * normal[0] + normal[1] * normal[1] + normal[2] * normal[2];
- Real length = std::sqrt(sqrLength);
- if (length > (Real)0)
- {
- for (int i = 0; i < 3; ++i)
- {
- normal[i] /= length;
- }
- }
- else
- {
- for (int i = 0; i < 3; ++i)
- {
- normal[i] = (Real)0;
- }
- }
- }
- }
- // Support for debugging.
- void PrintBoxes(std::ostream& output)
- {
- output << mBoxes.size() << std::endl;
- for (size_t i = 0; i < mBoxes.size(); ++i)
- {
- OctBox const& box = mBoxes[i];
- output << "box " << i << ": ";
- output << "x0 = " << box.x0 << ", ";
- output << "y0 = " << box.y0 << ", ";
- output << "z0 = " << box.z0 << ", ";
- output << "dx = " << box.dx << ", ";
- output << "dy = " << box.dy << ", ";
- output << "dz = " << box.dz << std::endl;
- }
- }
- private:
- // Helper classes for the skeleton climbing.
- struct OctBox
- {
- OctBox(int inX0, int inY0, int inZ0, int inDX, int inDY, int inDZ,
- int inLX, int inLY, int inLZ)
- :
- x0(inX0), y0(inY0), z0(inZ0),
- x1(inX0 + inDX), y1(inY0 + inDY), z1(inZ0 + inDZ),
- dx(inDX), dy(inDY), dz(inDZ),
- LX(inLX), LY(inLY), LZ(inLZ)
- {
- }
- int x0, y0, z0, x1, y1, z1, dx, dy, dz, LX, LY, LZ;
- };
- struct MergeBox
- {
- MergeBox(int stride)
- :
- xStride(stride), yStride(stride), zStride(stride),
- valid(true)
- {
- }
- int xStride, yStride, zStride;
- bool valid;
- };
- class LinearMergeTree
- {
- public:
- LinearMergeTree(int N)
- :
- mTwoPowerN(1 << N),
- mNodes(2 * mTwoPowerN - 1),
- mZeroBases(2 * mTwoPowerN - 1)
- {
- }
- enum
- {
- CFG_NONE = 0,
- CFG_INCR = 1,
- CFG_DECR = 2,
- CFG_MULT = 3,
- CFG_ROOT_MASK = 3,
- CFG_EDGE = 4,
- CFG_ZERO_SUBEDGE = 8
- };
- bool IsNone(int i) const
- {
- return (mNodes[i] & CFG_ROOT_MASK) == CFG_NONE;
- }
- int GetRootType(int i) const
- {
- return mNodes[i] & CFG_ROOT_MASK;
- }
- int GetZeroBase(int i) const
- {
- return mZeroBases[i];
- }
- void SetEdge(int i)
- {
- mNodes[i] |= CFG_EDGE;
- // Inform all predecessors whether they have a zero subedge.
- if (mZeroBases[i] >= 0)
- {
- while (i > 0)
- {
- i = (i - 1) / 2;
- mNodes[i] |= CFG_ZERO_SUBEDGE;
- }
- }
- }
- bool IsZeroEdge(int i) const
- {
- return mNodes[i] == (CFG_EDGE | CFG_INCR)
- || mNodes[i] == (CFG_EDGE | CFG_DECR);
- }
- bool HasZeroSubedge(int i) const
- {
- return (mNodes[i] & CFG_ZERO_SUBEDGE) != 0;
- }
- void SetLevel(Real level, T const* data, int offset, int stride)
- {
- // Assert: The 'level' is not an image value. Because T is
- // an integer type, choose 'level' to be a Real-valued number
- // that does not represent an integer.
- // Determine the sign changes between pairs of consecutive
- // samples.
- int firstLeaf = mTwoPowerN - 1;
- for (int i = 0, leaf = firstLeaf; i < mTwoPowerN; ++i, ++leaf)
- {
- int base = offset + stride * i;
- Real value0 = static_cast<Real>(data[base]);
- Real value1 = static_cast<Real>(data[base + stride]);
- if (value0 > level)
- {
- if (value1 > level)
- {
- mNodes[leaf] = CFG_NONE;
- mZeroBases[leaf] = -1;
- }
- else
- {
- mNodes[leaf] = CFG_DECR;
- mZeroBases[leaf] = i;
- }
- }
- else // value0 < level
- {
- if (value1 > level)
- {
- mNodes[leaf] = CFG_INCR;
- mZeroBases[leaf] = i;
- }
- else
- {
- mNodes[leaf] = CFG_NONE;
- mZeroBases[leaf] = -1;
- }
- }
- }
- // Propagate the sign change information up the binary tree.
- for (int i = firstLeaf - 1; i >= 0; --i)
- {
- int twoIp1 = 2 * i + 1, twoIp2 = twoIp1 + 1;
- int value0 = mNodes[twoIp1];
- int value1 = mNodes[twoIp2];
- int combine = (value0 | value1);
- mNodes[i] = combine;
- if (combine == CFG_INCR)
- {
- if (value0 == CFG_INCR)
- {
- mZeroBases[i] = mZeroBases[twoIp1];
- }
- else
- {
- mZeroBases[i] = mZeroBases[twoIp2];
- }
- }
- else if (combine == CFG_DECR)
- {
- if (value0 == CFG_DECR)
- {
- mZeroBases[i] = mZeroBases[twoIp1];
- }
- else
- {
- mZeroBases[i] = mZeroBases[twoIp2];
- }
- }
- else
- {
- mZeroBases[i] = -1;
- }
- }
- }
- private:
- int mTwoPowerN;
- std::vector<int> mNodes;
- std::vector<int> mZeroBases;
- };
- class VETable
- {
- public:
- VETable()
- :
- mVertices(18)
- {
- }
- bool IsValidVertex(int i) const
- {
- return mVertices[i].valid;
- }
- int GetNumVertices() const
- {
- return static_cast<int>(mVertices.size());
- }
- Vertex const& GetVertex(int i) const
- {
- return mVertices[i].position;
- }
- void Insert(int i, Real x, Real y, Real z)
- {
- TVertex& vertex = mVertices[i];
- vertex.position = Vertex{ x, y, z };
- vertex.valid = true;
- }
- void Insert(Vertex const& position)
- {
- mVertices.push_back(TVertex(position));
- }
- void InsertEdge(int v0, int v1)
- {
- TVertex& vertex0 = mVertices[v0];
- TVertex& vertex1 = mVertices[v1];
- vertex0.adjacent[vertex0.adjQuantity] = v1;
- ++vertex0.adjQuantity;
- vertex1.adjacent[vertex1.adjQuantity] = v0;
- ++vertex1.adjQuantity;
- }
- void RemoveTrianglesEC(std::vector<Vertex>& positions,
- std::vector<Triangle>& triangles)
- {
- // Ear-clip the wireframe to get the triangles.
- Triangle triangle;
- while (RemoveEC(triangle))
- {
- int v0 = static_cast<int>(positions.size());
- int v1 = v0 + 1;
- int v2 = v1 + 1;
- triangles.push_back(Triangle(v0, v1, v2));
- positions.push_back(mVertices[triangle.V[0]].position);
- positions.push_back(mVertices[triangle.V[1]].position);
- positions.push_back(mVertices[triangle.V[2]].position);
- }
- }
- void RemoveTrianglesSE(std::vector<Vertex>& positions,
- std::vector<Triangle>& triangles)
- {
- // Compute centroid of vertices.
- Vertex centroid = { (Real)0, (Real)0, (Real)0 };
- int const vmax = static_cast<int>(mVertices.size());
- int i, j, quantity = 0;
- for (i = 0; i < vmax; i++)
- {
- TVertex const& vertex = mVertices[i];
- if (vertex.valid)
- {
- for (j = 0; j < 3; ++j)
- {
- centroid[j] += vertex.position[j];
- }
- ++quantity;
- }
- }
- for (j = 0; j < 3; ++j)
- {
- centroid[j] /= static_cast<Real>(quantity);
- }
- int v0 = static_cast<int>(positions.size());
- positions.push_back(centroid);
- int i1 = 18;
- int v1 = v0 + 1;
- positions.push_back(mVertices[i1].position);
- int i2 = mVertices[i1].adjacent[1], v2;
- for (i = 0; i < quantity - 1; ++i)
- {
- v2 = v1 + 1;
- positions.push_back(mVertices[i2].position);
- triangles.push_back(Triangle(v0, v1, v2));
- if (mVertices[i2].adjacent[1] != i1)
- {
- i1 = i2;
- i2 = mVertices[i2].adjacent[1];
- }
- else
- {
- i1 = i2;
- i2 = mVertices[i2].adjacent[0];
- }
- v1 = v2;
- }
- v2 = v0 + 1;
- triangles.push_back(Triangle(v0, v1, v2));
- }
- protected:
- void RemoveVertex(int i)
- {
- TVertex& vertex0 = mVertices[i];
- int a0 = vertex0.adjacent[0];
- int a1 = vertex0.adjacent[1];
- TVertex& adjVertex0 = mVertices[a0];
- TVertex& adjVertex1 = mVertices[a1];
- int j;
- for (j = 0; j < adjVertex0.adjQuantity; j++)
- {
- if (adjVertex0.adjacent[j] == i)
- {
- adjVertex0.adjacent[j] = a1;
- break;
- }
- }
- for (j = 0; j < adjVertex1.adjQuantity; j++)
- {
- if (adjVertex1.adjacent[j] == i)
- {
- adjVertex1.adjacent[j] = a0;
- break;
- }
- }
- vertex0.valid = false;
- if (adjVertex0.adjQuantity == 2)
- {
- if (adjVertex0.adjacent[0] == adjVertex0.adjacent[1])
- {
- adjVertex0.valid = false;
- }
- }
- if (adjVertex1.adjQuantity == 2)
- {
- if (adjVertex1.adjacent[0] == adjVertex1.adjacent[1])
- {
- adjVertex1.valid = false;
- }
- }
- }
- // ear clipping
- bool RemoveEC(Triangle& triangle)
- {
- int numVertices = static_cast<int>(mVertices.size());
- for (int i = 0; i < numVertices; ++i)
- {
- TVertex const& vertex = mVertices[i];
- if (vertex.valid && vertex.adjQuantity == 2)
- {
- triangle.V[0] = i;
- triangle.V[1] = vertex.adjacent[0];
- triangle.V[2] = vertex.adjacent[1];
- RemoveVertex(i);
- return true;
- }
- }
- return false;
- }
- class TVertex
- {
- public:
- TVertex()
- :
- adjQuantity(0),
- valid(false)
- {
- }
- TVertex(Vertex const& inPosition)
- :
- position(inPosition),
- adjQuantity(0),
- valid(true)
- {
- }
- Vertex position;
- int adjQuantity;
- std::array<int, 4> adjacent;
- bool valid;
- };
- std::vector<TVertex> mVertices;
- };
- private:
- // Support for merging monoboxes.
- void Merge(int depth)
- {
- int x, y, z, offset, stride;
- for (y = 0; y < mSize; ++y)
- {
- for (z = 0; z < mSize; ++z)
- {
- offset = mSize * (y + mSize * z);
- stride = 1;
- mXMerge[y][z]->SetLevel(mLevel, mInputVoxels, offset, stride);
- }
- }
- for (x = 0; x < mSize; ++x)
- {
- for (z = 0; z < mSize; ++z)
- {
- offset = x + mSizeSqr * z;
- stride = mSize;
- mYMerge[x][z]->SetLevel(mLevel, mInputVoxels, offset, stride);
- }
- }
- for (x = 0; x < mSize; ++x)
- {
- for (y = 0; y < mSize; ++y)
- {
- offset = x + mSize * y;
- stride = mSizeSqr;
- mZMerge[x][y]->SetLevel(mLevel, mInputVoxels, offset, stride);
- }
- }
- Merge(0, 0, 0, 0, 0, 0, 0, mTwoPowerN, depth);
- }
- bool Merge(int v, int LX, int LY, int LZ, int x0, int y0, int z0, int stride, int depth)
- {
- if (stride > 1) // internal nodes
- {
- int hStride = stride / 2;
- int vBase = 8 * v;
- int v000 = vBase + 1;
- int v100 = vBase + 2;
- int v010 = vBase + 3;
- int v110 = vBase + 4;
- int v001 = vBase + 5;
- int v101 = vBase + 6;
- int v011 = vBase + 7;
- int v111 = vBase + 8;
- int LX0 = 2 * LX + 1, LX1 = LX0 + 1;
- int LY0 = 2 * LY + 1, LY1 = LY0 + 1;
- int LZ0 = 2 * LZ + 1, LZ1 = LZ0 + 1;
- int x1 = x0 + hStride, y1 = y0 + hStride, z1 = z0 + hStride;
- int dm1 = depth - 1;
- bool m000 = Merge(v000, LX0, LY0, LZ0, x0, y0, z0, hStride, dm1);
- bool m100 = Merge(v100, LX1, LY0, LZ0, x1, y0, z0, hStride, dm1);
- bool m010 = Merge(v010, LX0, LY1, LZ0, x0, y1, z0, hStride, dm1);
- bool m110 = Merge(v110, LX1, LY1, LZ0, x1, y1, z0, hStride, dm1);
- bool m001 = Merge(v001, LX0, LY0, LZ1, x0, y0, z1, hStride, dm1);
- bool m101 = Merge(v101, LX1, LY0, LZ1, x1, y0, z1, hStride, dm1);
- bool m011 = Merge(v011, LX0, LY1, LZ1, x0, y1, z1, hStride, dm1);
- bool m111 = Merge(v111, LX1, LY1, LZ1, x1, y1, z1, hStride, dm1);
- MergeBox r000(hStride), r100(hStride), r010(hStride), r110(hStride);
- MergeBox r001(hStride), r101(hStride), r011(hStride), r111(hStride);
- if (depth <= 0)
- {
- if (m000 && m001)
- {
- DoZMerge(r000, r001, x0, y0, LZ);
- }
- if (m100 && m101)
- {
- DoZMerge(r100, r101, x1, y0, LZ);
- }
- if (m010 && m011)
- {
- DoZMerge(r010, r011, x0, y1, LZ);
- }
- if (m110 && m111)
- {
- DoZMerge(r110, r111, x1, y1, LZ);
- }
- if (m000 && m010)
- {
- DoYMerge(r000, r010, x0, LY, z0);
- }
- if (m100 && m110)
- {
- DoYMerge(r100, r110, x1, LY, z0);
- }
- if (m001 && m011)
- {
- DoYMerge(r001, r011, x0, LY, z1);
- }
- if (m101 && m111)
- {
- DoYMerge(r101, r111, x1, LY, z1);
- }
- if (m000 && m100)
- {
- DoXMerge(r000, r100, LX, y0, z0);
- }
- if (m010 && m110)
- {
- DoXMerge(r010, r110, LX, y1, z0);
- }
- if (m001 && m101)
- {
- DoXMerge(r001, r101, LX, y0, z1);
- }
- if (m011 && m111)
- {
- DoXMerge(r011, r111, LX, y1, z1);
- }
- }
- if (depth <= 1)
- {
- if (r000.valid)
- {
- if (r000.xStride == stride)
- {
- if (r000.yStride == stride)
- {
- if (r000.zStride == stride)
- {
- return true;
- }
- else
- {
- AddBox(x0, y0, z0, stride, stride, hStride, LX, LY, LZ0);
- }
- }
- else
- {
- if (r000.zStride == stride)
- {
- AddBox(x0, y0, z0, stride, hStride, stride, LX, LY0, LZ);
- }
- else
- {
- AddBox(x0, y0, z0, stride, hStride, hStride, LX, LY0, LZ0);
- }
- }
- }
- else
- {
- if (r000.yStride == stride)
- {
- if (r000.zStride == stride)
- {
- AddBox(x0, y0, z0, hStride, stride, stride, LX0, LY, LZ);
- }
- else
- {
- AddBox(x0, y0, z0, hStride, stride, hStride, LX0, LY, LZ0);
- }
- }
- else
- {
- if (r000.zStride == stride)
- {
- AddBox(x0, y0, z0, hStride, hStride, stride, LX0, LY0, LZ);
- }
- else if (m000)
- {
- AddBox(x0, y0, z0, hStride, hStride, hStride, LX0, LY0, LZ0);
- }
- }
- }
- }
- if (r100.valid)
- {
- if (r100.yStride == stride)
- {
- if (r100.zStride == stride)
- {
- AddBox(x1, y0, z0, hStride, stride, stride, LX1, LY, LZ);
- }
- else
- {
- AddBox(x1, y0, z0, hStride, stride, hStride, LX1, LY, LZ0);
- }
- }
- else
- {
- if (r100.zStride == stride)
- {
- AddBox(x1, y0, z0, hStride, hStride, stride, LX1, LY0, LZ);
- }
- else if (m100)
- {
- AddBox(x1, y0, z0, hStride, hStride, hStride, LX1, LY0, LZ0);
- }
- }
- }
- if (r010.valid)
- {
- if (r010.xStride == stride)
- {
- if (r010.zStride == stride)
- {
- AddBox(x0, y1, z0, stride, hStride, stride, LX, LY1, LZ);
- }
- else
- {
- AddBox(x0, y1, z0, stride, hStride, hStride, LX, LY1, LZ0);
- }
- }
- else
- {
- if (r010.zStride == stride)
- {
- AddBox(x0, y1, z0, hStride, hStride, stride, LX0, LY1, LZ);
- }
- else if (m010)
- {
- AddBox(x0, y1, z0, hStride, hStride, hStride, LX0, LY1, LZ0);
- }
- }
- }
- if (r001.valid)
- {
- if (r001.xStride == stride)
- {
- if (r001.yStride == stride)
- {
- AddBox(x0, y0, z1, stride, stride, hStride, LX, LY, LZ1);
- }
- else
- {
- AddBox(x0, y0, z1, stride, hStride, hStride, LX, LY0, LZ1);
- }
- }
- else
- {
- if (r001.yStride == stride)
- {
- AddBox(x0, y0, z1, hStride, stride, hStride, LX0, LY, LZ1);
- }
- else if (m001)
- {
- AddBox(x0, y0, z1, hStride, hStride, hStride, LX0, LY0, LZ1);
- }
- }
- }
- if (r110.valid)
- {
- if (r110.zStride == stride)
- {
- AddBox(x1, y1, z0, hStride, hStride, stride, LX1, LY1, LZ);
- }
- else if (m110)
- {
- AddBox(x1, y1, z0, hStride, hStride, hStride, LX1, LY1, LZ0);
- }
- }
- if (r101.valid)
- {
- if (r101.yStride == stride)
- {
- AddBox(x1, y0, z1, hStride, stride, hStride, LX1, LY, LZ1);
- }
- else if (m101)
- {
- AddBox(x1, y0, z1, hStride, hStride, hStride, LX1, LY0, LZ1);
- }
- }
- if (r011.valid)
- {
- if (r011.xStride == stride)
- {
- AddBox(x0, y1, z1, stride, hStride, hStride, LX, LY1, LZ1);
- }
- else if (m011)
- {
- AddBox(x0, y1, z1, hStride, hStride, hStride, LX0, LY1, LZ1);
- }
- }
- if (r111.valid && m111)
- {
- AddBox(x1, y1, z1, hStride, hStride, hStride, LX1, LY1, LZ1);
- }
- }
- return false;
- }
- else // leaf nodes
- {
- if (mFixBoundary)
- {
- // Do not allow boundary voxels to merge with any other
- // voxels.
- AddBox(x0, y0, z0, 1, 1, 1, LX, LY, LZ);
- return false;
- }
- // A leaf box is mergeable with neighbors as long as all its
- // faces have 0 or 2 sign changes on the edges. That is, a
- // face may not have sign changes on all four edges. If it
- // does, the resulting box for tessellating is 1x1x1 and is
- // handled separately from boxes of larger dimensions.
- // xmin face
- int z1 = z0 + 1;
- int rt0 = mYMerge[x0][z0]->GetRootType(LY);
- int rt1 = mYMerge[x0][z1]->GetRootType(LY);
- if ((rt0 | rt1) == LinearMergeTree::CFG_MULT)
- {
- AddBox(x0, y0, z0, 1, 1, 1, LX, LY, LZ);
- return false;
- }
- // xmax face
- int x1 = x0 + 1;
- rt0 = mYMerge[x1][z0]->GetRootType(LY);
- rt1 = mYMerge[x1][z1]->GetRootType(LY);
- if ((rt0 | rt1) == LinearMergeTree::CFG_MULT)
- {
- AddBox(x0, y0, z0, 1, 1, 1, LX, LY, LZ);
- return false;
- }
- // ymin face
- rt0 = mZMerge[x0][y0]->GetRootType(LZ);
- rt1 = mZMerge[x1][y0]->GetRootType(LZ);
- if ((rt0 | rt1) == LinearMergeTree::CFG_MULT)
- {
- AddBox(x0, y0, z0, 1, 1, 1, LX, LY, LZ);
- return false;
- }
- // ymax face
- int y1 = y0 + 1;
- rt0 = mZMerge[x0][y1]->GetRootType(LZ);
- rt1 = mZMerge[x1][y1]->GetRootType(LZ);
- if ((rt0 | rt1) == LinearMergeTree::CFG_MULT)
- {
- AddBox(x0, y0, z0, 1, 1, 1, LX, LY, LZ);
- return false;
- }
- // zmin face
- rt0 = mXMerge[y0][z0]->GetRootType(LX);
- rt1 = mXMerge[y1][z0]->GetRootType(LX);
- if ((rt0 | rt1) == LinearMergeTree::CFG_MULT)
- {
- AddBox(x0, y0, z0, 1, 1, 1, LX, LY, LZ);
- return false;
- }
- // zmax face
- rt0 = mXMerge[y0][z1]->GetRootType(LX);
- rt1 = mXMerge[y1][z1]->GetRootType(LX);
- if ((rt0 | rt1) == LinearMergeTree::CFG_MULT)
- {
- AddBox(x0, y0, z0, 1, 1, 1, LX, LY, LZ);
- return false;
- }
- return true;
- }
- }
- bool DoXMerge(MergeBox& r0, MergeBox& r1, int LX, int y0, int z0)
- {
- if (!r0.valid || !r1.valid || r0.yStride != r1.yStride || r0.zStride != r1.zStride)
- {
- return false;
- }
- // Boxes are potentially x-mergeable.
- int y1 = y0 + r0.yStride, z1 = z0 + r0.zStride;
- int incr = 0, decr = 0;
- for (int y = y0; y <= y1; ++y)
- {
- for (int z = z0; z <= z1; ++z)
- {
- switch (mXMerge[y][z]->GetRootType(LX))
- {
- case LinearMergeTree::CFG_MULT:
- return false;
- case LinearMergeTree::CFG_INCR:
- ++incr;
- break;
- case LinearMergeTree::CFG_DECR:
- ++decr;
- break;
- }
- }
- }
- if (incr != 0 && decr != 0)
- {
- return false;
- }
- // Strongly mono, x-merge the boxes.
- r0.xStride *= 2;
- r1.valid = false;
- return true;
- }
- bool DoYMerge(MergeBox& r0, MergeBox& r1, int x0, int LY, int z0)
- {
- if (!r0.valid || !r1.valid || r0.xStride != r1.xStride || r0.zStride != r1.zStride)
- {
- return false;
- }
- // Boxes are potentially y-mergeable.
- int x1 = x0 + r0.xStride, z1 = z0 + r0.zStride;
- int incr = 0, decr = 0;
- for (int x = x0; x <= x1; ++x)
- {
- for (int z = z0; z <= z1; ++z)
- {
- switch (mYMerge[x][z]->GetRootType(LY))
- {
- case LinearMergeTree::CFG_MULT:
- return false;
- case LinearMergeTree::CFG_INCR:
- ++incr;
- break;
- case LinearMergeTree::CFG_DECR:
- ++decr;
- break;
- }
- }
- }
- if (incr != 0 && decr != 0)
- {
- return false;
- }
- // Strongly mono, y-merge the boxes.
- r0.yStride *= 2;
- r1.valid = false;
- return true;
- }
- bool DoZMerge(MergeBox& r0, MergeBox& r1, int x0, int y0, int LZ)
- {
- if (!r0.valid || !r1.valid || r0.xStride != r1.xStride || r0.yStride != r1.yStride)
- {
- return false;
- }
- // Boxes are potentially z-mergeable.
- int x1 = x0 + r0.xStride, y1 = y0 + r0.yStride;
- int incr = 0, decr = 0;
- for (int x = x0; x <= x1; ++x)
- {
- for (int y = y0; y <= y1; ++y)
- {
- switch (mZMerge[x][y]->GetRootType(LZ))
- {
- case LinearMergeTree::CFG_MULT:
- return false;
- case LinearMergeTree::CFG_INCR:
- ++incr;
- break;
- case LinearMergeTree::CFG_DECR:
- ++decr;
- break;
- }
- }
- }
- if (incr != 0 && decr != 0)
- {
- return false;
- }
- // Strongly mono, z-merge the boxes.
- r0.zStride *= 2;
- r1.valid = false;
- return true;
- }
- void AddBox(int x0, int y0, int z0, int dx, int dy, int dz, int LX, int LY, int LZ)
- {
- OctBox box(x0, y0, z0, dx, dy, dz, LX, LY, LZ);
- mBoxes.push_back(box);
- // Mark box edges in linear merge trees. This information will be
- // used later for extraction.
- mXMerge[box.y0][box.z0]->SetEdge(box.LX);
- mXMerge[box.y0][box.z1]->SetEdge(box.LX);
- mXMerge[box.y1][box.z0]->SetEdge(box.LX);
- mXMerge[box.y1][box.z1]->SetEdge(box.LX);
- mYMerge[box.x0][box.z0]->SetEdge(box.LY);
- mYMerge[box.x0][box.z1]->SetEdge(box.LY);
- mYMerge[box.x1][box.z0]->SetEdge(box.LY);
- mYMerge[box.x1][box.z1]->SetEdge(box.LY);
- mZMerge[box.x0][box.y0]->SetEdge(box.LZ);
- mZMerge[box.x0][box.y1]->SetEdge(box.LZ);
- mZMerge[box.x1][box.y0]->SetEdge(box.LZ);
- mZMerge[box.x1][box.y1]->SetEdge(box.LZ);
- }
- // Support for tessellating monoboxes.
- void Tessellate(std::vector<Vertex>& positions, std::vector<Triangle>& triangles)
- {
- for (size_t i = 0; i < mBoxes.size(); ++i)
- {
- OctBox const& box = mBoxes[i];
- // Get vertices on edges of box.
- VETable table;
- unsigned int type;
- GetVertices(box, type, table);
- if (type == 0)
- {
- continue;
- }
- // Add wireframe edges to table, add face-vertices if
- // necessary.
- if (box.dx > 1 || box.dy > 1 || box.dz > 1)
- {
- // Box is larger than voxel, each face has at most one
- // edge.
- GetXMinEdgesM(box, type, table);
- GetXMaxEdgesM(box, type, table);
- GetYMinEdgesM(box, type, table);
- GetYMaxEdgesM(box, type, table);
- GetZMinEdgesM(box, type, table);
- GetZMaxEdgesM(box, type, table);
- if (table.GetNumVertices() > 18)
- {
- table.RemoveTrianglesSE(positions, triangles);
- }
- else
- {
- table.RemoveTrianglesEC(positions, triangles);
- }
- }
- else
- {
- // The box is a 1x1x1 voxel. Do the full edge analysis
- // but no splitting is required.
- GetXMinEdgesS(box, type, table);
- GetXMaxEdgesS(box, type, table);
- GetYMinEdgesS(box, type, table);
- GetYMaxEdgesS(box, type, table);
- GetZMinEdgesS(box, type, table);
- GetZMaxEdgesS(box, type, table);
- table.RemoveTrianglesEC(positions, triangles);
- }
- }
- }
- Real GetXInterp(int x, int y, int z) const
- {
- int index = x + mSize * (y + mSize * z);
- Real f0 = static_cast<Real>(mInputVoxels[index]);
- ++index;
- Real f1 = static_cast<Real>(mInputVoxels[index]);
- return static_cast<Real>(x) + (mLevel - f0) / (f1 - f0);
- }
- Real GetYInterp(int x, int y, int z) const
- {
- int index = x + mSize * (y + mSize * z);
- Real f0 = static_cast<Real>(mInputVoxels[index]);
- index += mSize;
- Real f1 = static_cast<Real>(mInputVoxels[index]);
- return static_cast<Real>(y) + (mLevel - f0) / (f1 - f0);
- }
- Real GetZInterp(int x, int y, int z) const
- {
- int index = x + mSize * (y + mSize * z);
- Real f0 = static_cast<Real>(mInputVoxels[index]);
- index += mSizeSqr;
- Real f1 = static_cast<Real>(mInputVoxels[index]);
- return static_cast<Real>(z) + (mLevel - f0) / (f1 - f0);
- }
- void GetVertices(OctBox const& box, unsigned int& type, VETable& table)
- {
- int root;
- type = 0;
- // xmin-ymin edge
- root = mZMerge[box.x0][box.y0]->GetZeroBase(box.LZ);
- if (root != -1)
- {
- type |= EB_XMIN_YMIN;
- table.Insert(EI_XMIN_YMIN,
- static_cast<float>(box.x0),
- static_cast<float>(box.y0),
- GetZInterp(box.x0, box.y0, root));
- }
- // xmin-ymax edge
- root = mZMerge[box.x0][box.y1]->GetZeroBase(box.LZ);
- if (root != -1)
- {
- type |= EB_XMIN_YMAX;
- table.Insert(EI_XMIN_YMAX,
- static_cast<float>(box.x0),
- static_cast<float>(box.y1),
- GetZInterp(box.x0, box.y1, root));
- }
- // xmax-ymin edge
- root = mZMerge[box.x1][box.y0]->GetZeroBase(box.LZ);
- if (root != -1)
- {
- type |= EB_XMAX_YMIN;
- table.Insert(EI_XMAX_YMIN,
- static_cast<float>(box.x1),
- static_cast<float>(box.y0),
- GetZInterp(box.x1, box.y0, root));
- }
- // xmax-ymax edge
- root = mZMerge[box.x1][box.y1]->GetZeroBase(box.LZ);
- if (root != -1)
- {
- type |= EB_XMAX_YMAX;
- table.Insert(EI_XMAX_YMAX,
- static_cast<float>(box.x1),
- static_cast<float>(box.y1),
- GetZInterp(box.x1, box.y1, root));
- }
- // xmin-zmin edge
- root = mYMerge[box.x0][box.z0]->GetZeroBase(box.LY);
- if (root != -1)
- {
- type |= EB_XMIN_ZMIN;
- table.Insert(EI_XMIN_ZMIN,
- static_cast<float>(box.x0),
- GetYInterp(box.x0, root, box.z0),
- static_cast<float>(box.z0));
- }
- // xmin-zmax edge
- root = mYMerge[box.x0][box.z1]->GetZeroBase(box.LY);
- if (root != -1)
- {
- type |= EB_XMIN_ZMAX;
- table.Insert(EI_XMIN_ZMAX,
- static_cast<float>(box.x0),
- GetYInterp(box.x0, root, box.z1),
- static_cast<float>(box.z1));
- }
- // xmax-zmin edge
- root = mYMerge[box.x1][box.z0]->GetZeroBase(box.LY);
- if (root != -1)
- {
- type |= EB_XMAX_ZMIN;
- table.Insert(EI_XMAX_ZMIN,
- static_cast<float>(box.x1),
- GetYInterp(box.x1, root, box.z0),
- static_cast<float>(box.z0));
- }
- // xmax-zmax edge
- root = mYMerge[box.x1][box.z1]->GetZeroBase(box.LY);
- if (root != -1)
- {
- type |= EB_XMAX_ZMAX;
- table.Insert(EI_XMAX_ZMAX,
- static_cast<float>(box.x1),
- GetYInterp(box.x1, root, box.z1),
- static_cast<float>(box.z1));
- }
- // ymin-zmin edge
- root = mXMerge[box.y0][box.z0]->GetZeroBase(box.LX);
- if (root != -1)
- {
- type |= EB_YMIN_ZMIN;
- table.Insert(EI_YMIN_ZMIN,
- GetXInterp(root, box.y0, box.z0),
- static_cast<float>(box.y0),
- static_cast<float>(box.z0));
- }
- // ymin-zmax edge
- root = mXMerge[box.y0][box.z1]->GetZeroBase(box.LX);
- if (root != -1)
- {
- type |= EB_YMIN_ZMAX;
- table.Insert(EI_YMIN_ZMAX,
- GetXInterp(root, box.y0, box.z1),
- static_cast<float>(box.y0),
- static_cast<float>(box.z1));
- }
- // ymax-zmin edge
- root = mXMerge[box.y1][box.z0]->GetZeroBase(box.LX);
- if (root != -1)
- {
- type |= EB_YMAX_ZMIN;
- table.Insert(EI_YMAX_ZMIN,
- GetXInterp(root, box.y1, box.z0),
- static_cast<float>(box.y1),
- static_cast<float>(box.z0));
- }
- // ymax-zmax edge
- root = mXMerge[box.y1][box.z1]->GetZeroBase(box.LX);
- if (root != -1)
- {
- type |= EB_YMAX_ZMAX;
- table.Insert(EI_YMAX_ZMAX,
- GetXInterp(root, box.y1, box.z1),
- static_cast<float>(box.y1),
- static_cast<float>(box.z1));
- }
- }
- // Edge extraction for single boxes (1x1x1).
- void GetXMinEdgesS(OctBox const& box, unsigned int type, VETable& table)
- {
- unsigned int faceType = 0;
- if (type & EB_XMIN_YMIN)
- {
- faceType |= 0x01;
- }
- if (type & EB_XMIN_YMAX)
- {
- faceType |= 0x02;
- }
- if (type & EB_XMIN_ZMIN)
- {
- faceType |= 0x04;
- }
- if (type & EB_XMIN_ZMAX)
- {
- faceType |= 0x08;
- }
- switch (faceType)
- {
- case 0:
- return;
- case 3:
- table.InsertEdge(EI_XMIN_YMIN, EI_XMIN_YMAX);
- break;
- case 5:
- table.InsertEdge(EI_XMIN_YMIN, EI_XMIN_ZMIN);
- break;
- case 6:
- table.InsertEdge(EI_XMIN_YMAX, EI_XMIN_ZMIN);
- break;
- case 9:
- table.InsertEdge(EI_XMIN_YMIN, EI_XMIN_ZMAX);
- break;
- case 10:
- table.InsertEdge(EI_XMIN_YMAX, EI_XMIN_ZMAX);
- break;
- case 12:
- table.InsertEdge(EI_XMIN_ZMIN, EI_XMIN_ZMAX);
- break;
- case 15:
- {
- // Four vertices, one per edge, need to disambiguate.
- int i = box.x0 + mSize * (box.y0 + mSize * box.z0);
- // F(x,y,z)
- int64_t f00 = static_cast<int64_t>(mInputVoxels[i]);
- i += mSize;
- // F(x,y+1,z)
- int64_t f10 = static_cast<int64_t>(mInputVoxels[i]);
- i += mSizeSqr;
- // F(x,y+1,z+1)
- int64_t f11 = static_cast<int64_t>(mInputVoxels[i]);
- i -= mSize;
- // F(x,y,z+1)
- int64_t f01 = static_cast<int64_t>(mInputVoxels[i]);
- int64_t det = f00 * f11 - f01 * f10;
- if (det > 0)
- {
- // Disjoint hyperbolic segments, pair <P0,P2>, <P1,P3>.
- table.InsertEdge(EI_XMIN_YMIN, EI_XMIN_ZMIN);
- table.InsertEdge(EI_XMIN_YMAX, EI_XMIN_ZMAX);
- }
- else if (det < 0)
- {
- // Disjoint hyperbolic segments, pair <P0,P3>, <P1,P2>.
- table.InsertEdge(EI_XMIN_YMIN, EI_XMIN_ZMAX);
- table.InsertEdge(EI_XMIN_YMAX, EI_XMIN_ZMIN);
- }
- else
- {
- // Plus-sign configuration, add branch point to
- // tessellation.
- table.Insert(FI_XMIN,
- table.GetVertex(EI_XMIN_ZMIN)[0],
- table.GetVertex(EI_XMIN_ZMIN)[1],
- table.GetVertex(EI_XMIN_YMIN)[2]);
- // Add edges sharing the branch point.
- table.InsertEdge(EI_XMIN_YMIN, FI_XMIN);
- table.InsertEdge(EI_XMIN_YMAX, FI_XMIN);
- table.InsertEdge(EI_XMIN_ZMIN, FI_XMIN);
- table.InsertEdge(EI_XMIN_ZMAX, FI_XMIN);
- }
- break;
- }
- default:
- LogError("The level value cannot be an exact integer.");
- }
- }
- void GetXMaxEdgesS(OctBox const& box, unsigned int type, VETable& table)
- {
- unsigned int faceType = 0;
- if (type & EB_XMAX_YMIN)
- {
- faceType |= 0x01;
- }
- if (type & EB_XMAX_YMAX)
- {
- faceType |= 0x02;
- }
- if (type & EB_XMAX_ZMIN)
- {
- faceType |= 0x04;
- }
- if (type & EB_XMAX_ZMAX)
- {
- faceType |= 0x08;
- }
- switch (faceType)
- {
- case 0:
- return;
- case 3:
- table.InsertEdge(EI_XMAX_YMIN, EI_XMAX_YMAX);
- break;
- case 5:
- table.InsertEdge(EI_XMAX_YMIN, EI_XMAX_ZMIN);
- break;
- case 6:
- table.InsertEdge(EI_XMAX_YMAX, EI_XMAX_ZMIN);
- break;
- case 9:
- table.InsertEdge(EI_XMAX_YMIN, EI_XMAX_ZMAX);
- break;
- case 10:
- table.InsertEdge(EI_XMAX_YMAX, EI_XMAX_ZMAX);
- break;
- case 12:
- table.InsertEdge(EI_XMAX_ZMIN, EI_XMAX_ZMAX);
- break;
- case 15:
- {
- // Four vertices, one per edge, need to disambiguate.
- int i = box.x1 + mSize * (box.y0 + mSize * box.z0);
- // F(x,y,z)
- int64_t f00 = static_cast<int64_t>(mInputVoxels[i]);
- i += mSize;
- // F(x,y+1,z)
- int64_t f10 = static_cast<int64_t>(mInputVoxels[i]);
- i += mSizeSqr;
- // F(x,y+1,z+1)
- int64_t f11 = static_cast<int64_t>(mInputVoxels[i]);
- i -= mSize;
- // F(x,y,z+1)
- int64_t f01 = static_cast<int64_t>(mInputVoxels[i]);
- int64_t det = f00 * f11 - f01 * f10;
- if (det > 0)
- {
- // Disjoint hyperbolic segments, pair <P0,P2>, <P1,P3>.
- table.InsertEdge(EI_XMAX_YMIN, EI_XMAX_ZMIN);
- table.InsertEdge(EI_XMAX_YMAX, EI_XMAX_ZMAX);
- }
- else if (det < 0)
- {
- // Disjoint hyperbolic segments, pair <P0,P3>, <P1,P2>.
- table.InsertEdge(EI_XMAX_YMIN, EI_XMAX_ZMAX);
- table.InsertEdge(EI_XMAX_YMAX, EI_XMAX_ZMIN);
- }
- else
- {
- // Plus-sign configuration, add branch point to
- // tessellation.
- table.Insert(FI_XMAX,
- table.GetVertex(EI_XMAX_ZMIN)[0],
- table.GetVertex(EI_XMAX_ZMIN)[1],
- table.GetVertex(EI_XMAX_YMIN)[2]);
- // Add edges sharing the branch point.
- table.InsertEdge(EI_XMAX_YMIN, FI_XMAX);
- table.InsertEdge(EI_XMAX_YMAX, FI_XMAX);
- table.InsertEdge(EI_XMAX_ZMIN, FI_XMAX);
- table.InsertEdge(EI_XMAX_ZMAX, FI_XMAX);
- }
- break;
- }
- default:
- LogError("The level value cannot be an exact integer.");
- }
- }
- void GetYMinEdgesS(OctBox const& box, unsigned int type, VETable& table)
- {
- unsigned int faceType = 0;
- if (type & EB_XMIN_YMIN)
- {
- faceType |= 0x01;
- }
- if (type & EB_XMAX_YMIN)
- {
- faceType |= 0x02;
- }
- if (type & EB_YMIN_ZMIN)
- {
- faceType |= 0x04;
- }
- if (type & EB_YMIN_ZMAX)
- {
- faceType |= 0x08;
- }
- switch (faceType)
- {
- case 0:
- return;
- case 3:
- table.InsertEdge(EI_XMIN_YMIN, EI_XMAX_YMIN);
- break;
- case 5:
- table.InsertEdge(EI_XMIN_YMIN, EI_YMIN_ZMIN);
- break;
- case 6:
- table.InsertEdge(EI_XMAX_YMIN, EI_YMIN_ZMIN);
- break;
- case 9:
- table.InsertEdge(EI_XMIN_YMIN, EI_YMIN_ZMAX);
- break;
- case 10:
- table.InsertEdge(EI_XMAX_YMIN, EI_YMIN_ZMAX);
- break;
- case 12:
- table.InsertEdge(EI_YMIN_ZMIN, EI_YMIN_ZMAX);
- break;
- case 15:
- {
- // Four vertices, one per edge, need to disambiguate.
- int i = box.x0 + mSize * (box.y0 + mSize * box.z0);
- // F(x,y,z)
- int64_t f00 = static_cast<int64_t>(mInputVoxels[i]);
- ++i;
- // F(x+1,y,z)
- int64_t f10 = static_cast<int64_t>(mInputVoxels[i]);
- i += mSizeSqr;
- // F(x+1,y,z+1)
- int64_t f11 = static_cast<int64_t>(mInputVoxels[i]);
- --i;
- // F(x,y,z+1)
- int64_t f01 = static_cast<int64_t>(mInputVoxels[i]);
- int64_t det = f00 * f11 - f01 * f10;
- if (det > 0)
- {
- // Disjoint hyperbolic segments, pair <P0,P2>, <P1,P3>.
- table.InsertEdge(EI_XMIN_YMIN, EI_YMIN_ZMIN);
- table.InsertEdge(EI_XMAX_YMIN, EI_YMIN_ZMAX);
- }
- else if (det < 0)
- {
- // Disjoint hyperbolic segments, pair <P0,P3>, <P1,P2>.
- table.InsertEdge(EI_XMIN_YMIN, EI_YMIN_ZMAX);
- table.InsertEdge(EI_XMAX_YMIN, EI_YMIN_ZMIN);
- }
- else
- {
- // Plus-sign configuration, add branch point to
- // tessellation.
- table.Insert(FI_YMIN,
- table.GetVertex(EI_YMIN_ZMIN)[0],
- table.GetVertex(EI_XMIN_YMIN)[1],
- table.GetVertex(EI_XMIN_YMIN)[2]);
- // Add edges sharing the branch point.
- table.InsertEdge(EI_XMIN_YMIN, FI_YMIN);
- table.InsertEdge(EI_XMAX_YMIN, FI_YMIN);
- table.InsertEdge(EI_YMIN_ZMIN, FI_YMIN);
- table.InsertEdge(EI_YMIN_ZMAX, FI_YMIN);
- }
- break;
- }
- default:
- LogError("The level value cannot be an exact integer.");
- }
- }
- void GetYMaxEdgesS(OctBox const& box, unsigned int type, VETable& table)
- {
- unsigned int faceType = 0;
- if (type & EB_XMIN_YMAX)
- {
- faceType |= 0x01;
- }
- if (type & EB_XMAX_YMAX)
- {
- faceType |= 0x02;
- }
- if (type & EB_YMAX_ZMIN)
- {
- faceType |= 0x04;
- }
- if (type & EB_YMAX_ZMAX)
- {
- faceType |= 0x08;
- }
- switch (faceType)
- {
- case 0:
- return;
- case 3:
- table.InsertEdge(EI_XMIN_YMAX, EI_XMAX_YMAX);
- break;
- case 5:
- table.InsertEdge(EI_XMIN_YMAX, EI_YMAX_ZMIN);
- break;
- case 6:
- table.InsertEdge(EI_XMAX_YMAX, EI_YMAX_ZMIN);
- break;
- case 9:
- table.InsertEdge(EI_XMIN_YMAX, EI_YMAX_ZMAX);
- break;
- case 10:
- table.InsertEdge(EI_XMAX_YMAX, EI_YMAX_ZMAX);
- break;
- case 12:
- table.InsertEdge(EI_YMAX_ZMIN, EI_YMAX_ZMAX);
- break;
- case 15:
- {
- // Four vertices, one per edge, need to disambiguate.
- int i = box.x0 + mSize * (box.y1 + mSize * box.z0);
- // F(x,y,z)
- int64_t f00 = static_cast<int64_t>(mInputVoxels[i]);
- ++i;
- // F(x+1,y,z)
- int64_t f10 = static_cast<int64_t>(mInputVoxels[i]);
- i += mSizeSqr;
- // F(x+1,y,z+1)
- int64_t f11 = static_cast<int64_t>(mInputVoxels[i]);
- --i;
- // F(x,y,z+1)
- int64_t f01 = static_cast<int64_t>(mInputVoxels[i]);
- int64_t det = f00 * f11 - f01 * f10;
- if (det > 0)
- {
- // Disjoint hyperbolic segments, pair <P0,P2>, <P1,P3>.
- table.InsertEdge(EI_XMIN_YMAX, EI_YMAX_ZMIN);
- table.InsertEdge(EI_XMAX_YMAX, EI_YMAX_ZMAX);
- }
- else if (det < 0)
- {
- // Disjoint hyperbolic segments, pair <P0,P3>, <P1,P2>.
- table.InsertEdge(EI_XMIN_YMAX, EI_YMAX_ZMAX);
- table.InsertEdge(EI_XMAX_YMAX, EI_YMAX_ZMIN);
- }
- else
- {
- // Plus-sign configuration, add branch point to
- // tessellation.
- table.Insert(FI_YMAX,
- table.GetVertex(EI_YMAX_ZMIN)[0],
- table.GetVertex(EI_XMIN_YMAX)[1],
- table.GetVertex(EI_XMIN_YMAX)[2]);
- // Add edges sharing the branch point.
- table.InsertEdge(EI_XMIN_YMAX, FI_YMAX);
- table.InsertEdge(EI_XMAX_YMAX, FI_YMAX);
- table.InsertEdge(EI_YMAX_ZMIN, FI_YMAX);
- table.InsertEdge(EI_YMAX_ZMAX, FI_YMAX);
- }
- break;
- }
- default:
- LogError("The level value cannot be an exact integer.");
- }
- }
- void GetZMinEdgesS(OctBox const& box, unsigned int type, VETable& table)
- {
- unsigned int faceType = 0;
- if (type & EB_XMIN_ZMIN)
- {
- faceType |= 0x01;
- }
- if (type & EB_XMAX_ZMIN)
- {
- faceType |= 0x02;
- }
- if (type & EB_YMIN_ZMIN)
- {
- faceType |= 0x04;
- }
- if (type & EB_YMAX_ZMIN)
- {
- faceType |= 0x08;
- }
- switch (faceType)
- {
- case 0:
- return;
- case 3:
- table.InsertEdge(EI_XMIN_ZMIN, EI_XMAX_ZMIN);
- break;
- case 5:
- table.InsertEdge(EI_XMIN_ZMIN, EI_YMIN_ZMIN);
- break;
- case 6:
- table.InsertEdge(EI_XMAX_ZMIN, EI_YMIN_ZMIN);
- break;
- case 9:
- table.InsertEdge(EI_XMIN_ZMIN, EI_YMAX_ZMIN);
- break;
- case 10:
- table.InsertEdge(EI_XMAX_ZMIN, EI_YMAX_ZMIN);
- break;
- case 12:
- table.InsertEdge(EI_YMIN_ZMIN, EI_YMAX_ZMIN);
- break;
- case 15:
- {
- // Four vertices, one per edge, need to disambiguate.
- int i = box.x0 + mSize * (box.y0 + mSize * box.z0);
- // F(x,y,z)
- int64_t f00 = static_cast<int64_t>(mInputVoxels[i]);
- ++i;
- // F(x+1,y,z)
- int64_t f10 = static_cast<int64_t>(mInputVoxels[i]);
- i += mSize;
- // F(x+1,y+1,z)
- int64_t f11 = static_cast<int64_t>(mInputVoxels[i]);
- --i;
- // F(x,y+1,z)
- int64_t f01 = static_cast<int64_t>(mInputVoxels[i]);
- int64_t det = f00 * f11 - f01 * f10;
- if (det > 0)
- {
- // Disjoint hyperbolic segments, pair <P0,P2>, <P1,P3>.
- table.InsertEdge(EI_XMIN_ZMIN, EI_YMIN_ZMIN);
- table.InsertEdge(EI_XMAX_ZMIN, EI_YMAX_ZMIN);
- }
- else if (det < 0)
- {
- // Disjoint hyperbolic segments, pair <P0,P3>, <P1,P2>.
- table.InsertEdge(EI_XMIN_ZMIN, EI_YMAX_ZMIN);
- table.InsertEdge(EI_XMAX_ZMIN, EI_YMIN_ZMIN);
- }
- else
- {
- // Plus-sign configuration, add branch point to
- // tessellation.
- table.Insert(FI_ZMIN,
- table.GetVertex(EI_YMIN_ZMIN)[0],
- table.GetVertex(EI_XMIN_ZMIN)[1],
- table.GetVertex(EI_XMIN_ZMIN)[2]);
- // Add edges sharing the branch point.
- table.InsertEdge(EI_XMIN_ZMIN, FI_ZMIN);
- table.InsertEdge(EI_XMAX_ZMIN, FI_ZMIN);
- table.InsertEdge(EI_YMIN_ZMIN, FI_ZMIN);
- table.InsertEdge(EI_YMAX_ZMIN, FI_ZMIN);
- }
- break;
- }
- default:
- LogError("The level value cannot be an exact integer.");
- }
- }
- void GetZMaxEdgesS(const OctBox& box, unsigned int type, VETable& table)
- {
- unsigned int faceType = 0;
- if (type & EB_XMIN_ZMAX)
- {
- faceType |= 0x01;
- }
- if (type & EB_XMAX_ZMAX)
- {
- faceType |= 0x02;
- }
- if (type & EB_YMIN_ZMAX)
- {
- faceType |= 0x04;
- }
- if (type & EB_YMAX_ZMAX)
- {
- faceType |= 0x08;
- }
- switch (faceType)
- {
- case 0:
- return;
- case 3:
- table.InsertEdge(EI_XMIN_ZMAX, EI_XMAX_ZMAX);
- break;
- case 5:
- table.InsertEdge(EI_XMIN_ZMAX, EI_YMIN_ZMAX);
- break;
- case 6:
- table.InsertEdge(EI_XMAX_ZMAX, EI_YMIN_ZMAX);
- break;
- case 9:
- table.InsertEdge(EI_XMIN_ZMAX, EI_YMAX_ZMAX);
- break;
- case 10:
- table.InsertEdge(EI_XMAX_ZMAX, EI_YMAX_ZMAX);
- break;
- case 12:
- table.InsertEdge(EI_YMIN_ZMAX, EI_YMAX_ZMAX);
- break;
- case 15:
- {
- // Four vertices, one per edge, need to disambiguate.
- int i = box.x0 + mSize * (box.y0 + mSize * box.z1);
- // F(x,y,z)
- int64_t f00 = static_cast<int64_t>(mInputVoxels[i]);
- i++;
- // F(x+1,y,z)
- int64_t f10 = static_cast<int64_t>(mInputVoxels[i]);
- i += mSize;
- // F(x+1,y+1,z)
- int64_t f11 = static_cast<int64_t>(mInputVoxels[i]);
- i--;
- // F(x,y+1,z)
- int64_t f01 = static_cast<int64_t>(mInputVoxels[i]);
- int64_t det = f00 * f11 - f01 * f10;
- if (det > 0)
- {
- // Disjoint hyperbolic segments, pair <P0,P2>, <P1,P3>.
- table.InsertEdge(EI_XMIN_ZMAX, EI_YMIN_ZMAX);
- table.InsertEdge(EI_XMAX_ZMAX, EI_YMAX_ZMAX);
- }
- else if (det < 0)
- {
- // Disjoint hyperbolic segments, pair <P0,P3>, <P1,P2>.
- table.InsertEdge(EI_XMIN_ZMAX, EI_YMAX_ZMAX);
- table.InsertEdge(EI_XMAX_ZMAX, EI_YMIN_ZMAX);
- }
- else
- {
- // Plus-sign configuration, add branch point to
- // tessellation.
- table.Insert(FI_ZMAX,
- table.GetVertex(EI_YMIN_ZMAX)[0],
- table.GetVertex(EI_XMIN_ZMAX)[1],
- table.GetVertex(EI_XMIN_ZMAX)[2]);
- // Add edges sharing the branch point.
- table.InsertEdge(EI_XMIN_ZMAX, FI_ZMAX);
- table.InsertEdge(EI_XMAX_ZMAX, FI_ZMAX);
- table.InsertEdge(EI_YMIN_ZMAX, FI_ZMAX);
- table.InsertEdge(EI_YMAX_ZMAX, FI_ZMAX);
- }
- break;
- }
- default:
- LogError("The level value cannot be an exact integer.");
- }
- }
- // Edge extraction for merged boxes.
- class Sort0
- {
- public:
- bool operator()(Vertex const& arg0, Vertex const& arg1) const
- {
- if (arg0[0] < arg1[0])
- {
- return true;
- }
- if (arg0[0] > arg1[0])
- {
- return false;
- }
- if (arg0[1] < arg1[1])
- {
- return true;
- }
- if (arg0[1] > arg1[1])
- {
- return false;
- }
- return arg0[2] < arg1[2];
- }
- };
- class Sort1
- {
- public:
- bool operator()(Vertex const& arg0, Vertex const& arg1) const
- {
- if (arg0[2] < arg1[2])
- {
- return true;
- }
- if (arg0[2] > arg1[2])
- {
- return false;
- }
- if (arg0[0] < arg1[0])
- {
- return true;
- }
- if (arg0[0] > arg1[0])
- {
- return false;
- }
- return arg0[1] < arg1[1];
- }
- };
- class Sort2
- {
- public:
- bool operator()(Vertex const& arg0, Vertex const& arg1) const
- {
- if (arg0[1] < arg1[1])
- {
- return true;
- }
- if (arg0[1] > arg1[1])
- {
- return false;
- }
- if (arg0[2] < arg1[2])
- {
- return true;
- }
- if (arg0[2] > arg1[2])
- {
- return false;
- }
- return arg0[0] < arg1[0];
- }
- };
- void GetZMinEdgesM(OctBox const& box, unsigned int type, VETable& table)
- {
- unsigned int faceType = 0;
- if (type & EB_XMIN_ZMIN)
- {
- faceType |= 0x01;
- }
- if (type & EB_XMAX_ZMIN)
- {
- faceType |= 0x02;
- }
- if (type & EB_YMIN_ZMIN)
- {
- faceType |= 0x04;
- }
- if (type & EB_YMAX_ZMIN)
- {
- faceType |= 0x08;
- }
- int end0 = 0, end1 = 0;
- switch (faceType)
- {
- case 0:
- return;
- case 3:
- end0 = EI_XMIN_ZMIN;
- end1 = EI_XMAX_ZMIN;
- break;
- case 5:
- end0 = EI_XMIN_ZMIN;
- end1 = EI_YMIN_ZMIN;
- break;
- case 6:
- end0 = EI_YMIN_ZMIN;
- end1 = EI_XMAX_ZMIN;
- break;
- case 9:
- end0 = EI_XMIN_ZMIN;
- end1 = EI_YMAX_ZMIN;
- break;
- case 10:
- end0 = EI_YMAX_ZMIN;
- end1 = EI_XMAX_ZMIN;
- break;
- case 12:
- end0 = EI_YMIN_ZMIN;
- end1 = EI_YMAX_ZMIN;
- break;
- default:
- LogError("The level value cannot be an exact integer.");
- }
- std::set<Vertex, Sort0> vSet;
- for (int x = box.x0 + 1; x < box.x1; ++x)
- {
- auto const& merge = mYMerge[x][box.z0];
- if (merge->IsZeroEdge(box.LY) || merge->HasZeroSubedge(box.LY))
- {
- int root = merge->GetZeroBase(box.LY);
- vSet.insert(Vertex{
- static_cast<Real>(x),
- GetYInterp(x, root, box.z0),
- static_cast<Real>(box.z0) });
- }
- }
- for (int y = box.y0 + 1; y < box.y1; ++y)
- {
- auto const& merge = mXMerge[y][box.z0];
- if (merge->IsZeroEdge(box.LX) || merge->HasZeroSubedge(box.LX))
- {
- int root = merge->GetZeroBase(box.LX);
- vSet.insert(Vertex{
- GetXInterp(root, y, box.z0),
- static_cast<Real>(y),
- static_cast<Real>(box.z0) });
- }
- }
- // Add subdivision.
- if (vSet.size() == 0)
- {
- table.InsertEdge(end0, end1);
- return;
- }
- Real v0x = std::floor((*vSet.begin())[0]);
- Real v1x = std::floor((*vSet.rbegin())[0]);
- Real e0x = std::floor(table.GetVertex(end0)[0]);
- Real e1x = std::floor(table.GetVertex(end1)[0]);
- if (e1x <= v0x && v1x <= e0x)
- {
- std::swap(end0, end1);
- }
- // Add vertices.
- int v0 = table.GetNumVertices(), v1 = v0;
- for (auto const& position : vSet)
- {
- table.Insert(position);
- }
- // Add edges.
- table.InsertEdge(end0, v1);
- ++v1;
- int const imax = static_cast<int>(vSet.size());
- for (int i = 1; i < imax; ++i, ++v0, ++v1)
- {
- table.InsertEdge(v0, v1);
- }
- table.InsertEdge(v0, end1);
- }
- void GetZMaxEdgesM(OctBox const& box, unsigned int type, VETable& table)
- {
- unsigned int faceType = 0;
- if (type & EB_XMIN_ZMAX)
- {
- faceType |= 0x01;
- }
- if (type & EB_XMAX_ZMAX)
- {
- faceType |= 0x02;
- }
- if (type & EB_YMIN_ZMAX)
- {
- faceType |= 0x04;
- }
- if (type & EB_YMAX_ZMAX)
- {
- faceType |= 0x08;
- }
- int end0 = 0, end1 = 0;
- switch (faceType)
- {
- case 0:
- return;
- case 3:
- end0 = EI_XMIN_ZMAX;
- end1 = EI_XMAX_ZMAX;
- break;
- case 5:
- end0 = EI_XMIN_ZMAX;
- end1 = EI_YMIN_ZMAX;
- break;
- case 6:
- end0 = EI_YMIN_ZMAX;
- end1 = EI_XMAX_ZMAX;
- break;
- case 9:
- end0 = EI_XMIN_ZMAX;
- end1 = EI_YMAX_ZMAX;
- break;
- case 10:
- end0 = EI_YMAX_ZMAX;
- end1 = EI_XMAX_ZMAX;
- break;
- case 12:
- end0 = EI_YMIN_ZMAX;
- end1 = EI_YMAX_ZMAX;
- break;
- default:
- LogError("The level value cannot be an exact integer.");
- }
- std::set<Vertex, Sort0> vSet;
- for (int x = box.x0 + 1; x < box.x1; ++x)
- {
- auto const& merge = mYMerge[x][box.z1];
- if (merge->IsZeroEdge(box.LY) || merge->HasZeroSubedge(box.LY))
- {
- int root = merge->GetZeroBase(box.LY);
- vSet.insert(Vertex{
- static_cast<Real>(x),
- GetYInterp(x, root, box.z1),
- static_cast<Real>(box.z1) });
- }
- }
- for (int y = box.y0 + 1; y < box.y1; ++y)
- {
- auto const& merge = mXMerge[y][box.z1];
- if (merge->IsZeroEdge(box.LX) || merge->HasZeroSubedge(box.LX))
- {
- int root = merge->GetZeroBase(box.LX);
- vSet.insert(Vertex{
- GetXInterp(root, y, box.z1),
- static_cast<Real>(y),
- static_cast<Real>(box.z1) });
- }
- }
- // Add subdivision.
- int v0 = table.GetNumVertices(), v1 = v0;
- if (vSet.size() == 0)
- {
- table.InsertEdge(end0, end1);
- return;
- }
- Real v0x = std::floor((*vSet.begin())[0]);
- Real v1x = std::floor((*vSet.rbegin())[0]);
- Real e0x = std::floor(table.GetVertex(end0)[0]);
- Real e1x = std::floor(table.GetVertex(end1)[0]);
- if (e1x <= v0x && v1x <= e0x)
- {
- std::swap(end0, end1);
- }
- // Add vertices.
- for (auto const& position : vSet)
- {
- table.Insert(position);
- }
- // Add edges.
- table.InsertEdge(end0, v1);
- ++v1;
- int const imax = static_cast<int>(vSet.size());
- for (int i = 1; i < imax; ++i, ++v0, ++v1)
- {
- table.InsertEdge(v0, v1);
- }
- table.InsertEdge(v0, end1);
- }
- void GetYMinEdgesM(OctBox const& box, unsigned int type, VETable& table)
- {
- unsigned int faceType = 0;
- if (type & EB_XMIN_YMIN)
- {
- faceType |= 0x01;
- }
- if (type & EB_XMAX_YMIN)
- {
- faceType |= 0x02;
- }
- if (type & EB_YMIN_ZMIN)
- {
- faceType |= 0x04;
- }
- if (type & EB_YMIN_ZMAX)
- {
- faceType |= 0x08;
- }
- int end0 = 0, end1 = 0;
- switch (faceType)
- {
- case 0:
- return;
- case 3:
- end0 = EI_XMIN_YMIN;
- end1 = EI_XMAX_YMIN;
- break;
- case 5:
- end0 = EI_XMIN_YMIN;
- end1 = EI_YMIN_ZMIN;
- break;
- case 6:
- end0 = EI_YMIN_ZMIN;
- end1 = EI_XMAX_YMIN;
- break;
- case 9:
- end0 = EI_XMIN_YMIN;
- end1 = EI_YMIN_ZMAX;
- break;
- case 10:
- end0 = EI_YMIN_ZMAX;
- end1 = EI_XMAX_YMIN;
- break;
- case 12:
- end0 = EI_YMIN_ZMIN;
- end1 = EI_YMIN_ZMAX;
- break;
- default:
- LogError("The level value cannot be an exact integer.");
- }
- std::set<Vertex, Sort1> vSet;
- for (int x = box.x0 + 1; x < box.x1; ++x)
- {
- auto const& merge = mZMerge[x][box.y0];
- if (merge->IsZeroEdge(box.LZ) || merge->HasZeroSubedge(box.LZ))
- {
- int root = merge->GetZeroBase(box.LZ);
- vSet.insert(Vertex{
- static_cast<Real>(x),
- static_cast<Real>(box.y0),
- GetZInterp(x, box.y0, root) });
- }
- }
- for (int z = box.z0 + 1; z < box.z1; ++z)
- {
- auto const& merge = mXMerge[box.y0][z];
- if (merge->IsZeroEdge(box.LX) || merge->HasZeroSubedge(box.LX))
- {
- int root = merge->GetZeroBase(box.LX);
- vSet.insert(Vertex{
- GetXInterp(root, box.y0, z),
- static_cast<Real>(box.y0),
- static_cast<Real>(z) });
- }
- }
- // Add subdivision.
- int v0 = table.GetNumVertices(), v1 = v0;
- if (vSet.size() == 0)
- {
- table.InsertEdge(end0, end1);
- return;
- }
- Real v0z = std::floor((*vSet.begin())[2]);
- Real v1z = std::floor((*vSet.rbegin())[2]);
- Real e0z = std::floor(table.GetVertex(end0)[2]);
- Real e1z = std::floor(table.GetVertex(end1)[2]);
- if (e1z <= v0z && v1z <= e0z)
- {
- std::swap(end0, end1);
- }
- // Add vertices.
- for (auto const& position : vSet)
- {
- table.Insert(position);
- }
- // Add edges.
- table.InsertEdge(end0, v1);
- ++v1;
- int const imax = static_cast<int>(vSet.size());
- for (int i = 1; i < imax; ++i, ++v0, ++v1)
- {
- table.InsertEdge(v0, v1);
- }
- table.InsertEdge(v0, end1);
- }
- void GetYMaxEdgesM(OctBox const& box, unsigned int type, VETable& table)
- {
- unsigned int faceType = 0;
- if (type & EB_XMIN_YMAX)
- {
- faceType |= 0x01;
- }
- if (type & EB_XMAX_YMAX)
- {
- faceType |= 0x02;
- }
- if (type & EB_YMAX_ZMIN)
- {
- faceType |= 0x04;
- }
- if (type & EB_YMAX_ZMAX)
- {
- faceType |= 0x08;
- }
- int end0 = 0, end1 = 0;
- switch (faceType)
- {
- case 0:
- return;
- case 3:
- end0 = EI_XMIN_YMAX;
- end1 = EI_XMAX_YMAX;
- break;
- case 5:
- end0 = EI_XMIN_YMAX;
- end1 = EI_YMAX_ZMIN;
- break;
- case 6:
- end0 = EI_YMAX_ZMIN;
- end1 = EI_XMAX_YMAX;
- break;
- case 9:
- end0 = EI_XMIN_YMAX;
- end1 = EI_YMAX_ZMAX;
- break;
- case 10:
- end0 = EI_YMAX_ZMAX;
- end1 = EI_XMAX_YMAX;
- break;
- case 12:
- end0 = EI_YMAX_ZMIN;
- end1 = EI_YMAX_ZMAX;
- break;
- default:
- LogError("The level value cannot be an exact integer.");
- }
- std::set<Vertex, Sort1> vSet;
- for (int x = box.x0 + 1; x < box.x1; ++x)
- {
- auto const& merge = mZMerge[x][box.y1];
- if (merge->IsZeroEdge(box.LZ) || merge->HasZeroSubedge(box.LZ))
- {
- int root = merge->GetZeroBase(box.LZ);
- vSet.insert(Vertex{
- static_cast<Real>(x),
- static_cast<Real>(box.y1),
- GetZInterp(x, box.y1, root) });
- }
- }
- for (int z = box.z0 + 1; z < box.z1; ++z)
- {
- auto const& merge = mXMerge[box.y1][z];
- if (merge->IsZeroEdge(box.LX) || merge->HasZeroSubedge(box.LX))
- {
- int root = merge->GetZeroBase(box.LX);
- vSet.insert(Vertex{
- GetXInterp(root, box.y1, z),
- static_cast<Real>(box.y1),
- static_cast<Real>(z) });
- }
- }
- // Add subdivision.
- if (vSet.size() == 0)
- {
- table.InsertEdge(end0, end1);
- return;
- }
- Real v0z = std::floor((*vSet.begin())[2]);
- Real v1z = std::floor((*vSet.rbegin())[2]);
- Real e0z = std::floor(table.GetVertex(end0)[2]);
- Real e1z = std::floor(table.GetVertex(end1)[2]);
- if (e1z <= v0z && v1z <= e0z)
- {
- std::swap(end0, end1);
- }
- // Add vertices.
- int v0 = table.GetNumVertices(), v1 = v0;
- for (auto const& position : vSet)
- {
- table.Insert(position);
- }
- // Add edges.
- table.InsertEdge(end0, v1);
- ++v1;
- int const imax = static_cast<int>(vSet.size());
- for (int i = 1; i < imax; ++i, ++v0, ++v1)
- {
- table.InsertEdge(v0, v1);
- }
- table.InsertEdge(v0, end1);
- }
- void GetXMinEdgesM(OctBox const& box, unsigned int type, VETable& table)
- {
- unsigned int faceType = 0;
- if (type & EB_XMIN_YMIN)
- {
- faceType |= 0x01;
- }
- if (type & EB_XMIN_YMAX)
- {
- faceType |= 0x02;
- }
- if (type & EB_XMIN_ZMIN)
- {
- faceType |= 0x04;
- }
- if (type & EB_XMIN_ZMAX)
- {
- faceType |= 0x08;
- }
- int end0 = 0, end1 = 0;
- switch (faceType)
- {
- case 0:
- return;
- case 3:
- end0 = EI_XMIN_YMIN;
- end1 = EI_XMIN_YMAX;
- break;
- case 5:
- end0 = EI_XMIN_YMIN;
- end1 = EI_XMIN_ZMIN;
- break;
- case 6:
- end0 = EI_XMIN_ZMIN;
- end1 = EI_XMIN_YMAX;
- break;
- case 9:
- end0 = EI_XMIN_YMIN;
- end1 = EI_XMIN_ZMAX;
- break;
- case 10:
- end0 = EI_XMIN_ZMAX;
- end1 = EI_XMIN_YMAX;
- break;
- case 12:
- end0 = EI_XMIN_ZMIN;
- end1 = EI_XMIN_ZMAX;
- break;
- default:
- LogError("The level value cannot be an exact integer.");
- }
- std::set<Vertex, Sort2> vSet;
- for (int z = box.z0 + 1; z < box.z1; ++z)
- {
- auto const& merge = mYMerge[box.x0][z];
- if (merge->IsZeroEdge(box.LY) || merge->HasZeroSubedge(box.LY))
- {
- int root = merge->GetZeroBase(box.LY);
- vSet.insert(Vertex{
- static_cast<Real>(box.x0),
- GetYInterp(box.x0, root, z),
- static_cast<Real>(z) });
- }
- }
- for (int y = box.y0 + 1; y < box.y1; ++y)
- {
- auto const& merge = mZMerge[box.x0][y];
- if (merge->IsZeroEdge(box.LZ) || merge->HasZeroSubedge(box.LZ))
- {
- int root = merge->GetZeroBase(box.LZ);
- vSet.insert(Vertex{
- static_cast<Real>(box.x0),
- static_cast<Real>(y),
- GetZInterp(box.x0, y, root) });
- }
- }
- // Add subdivision.
- int v0 = table.GetNumVertices(), v1 = v0;
- if (vSet.size() == 0)
- {
- table.InsertEdge(end0, end1);
- return;
- }
- Real v0y = std::floor((*vSet.begin())[1]);
- Real v1y = std::floor((*vSet.rbegin())[1]);
- Real e0y = std::floor(table.GetVertex(end0)[1]);
- Real e1y = std::floor(table.GetVertex(end1)[1]);
- if (e1y <= v0y && v1y <= e0y)
- {
- std::swap(end0, end1);
- }
- // Add vertices.
- for (auto const& position : vSet)
- {
- table.Insert(position);
- }
- // Add edges.
- table.InsertEdge(end0, v1);
- ++v1;
- int const imax = static_cast<int>(vSet.size());
- for (int i = 1; i < imax; ++i, ++v0, ++v1)
- {
- table.InsertEdge(v0, v1);
- }
- table.InsertEdge(v0, end1);
- }
- void GetXMaxEdgesM(OctBox const& box, unsigned int type, VETable& table)
- {
- unsigned int faceType = 0;
- if (type & EB_XMAX_YMIN)
- {
- faceType |= 0x01;
- }
- if (type & EB_XMAX_YMAX)
- {
- faceType |= 0x02;
- }
- if (type & EB_XMAX_ZMIN)
- {
- faceType |= 0x04;
- }
- if (type & EB_XMAX_ZMAX)
- {
- faceType |= 0x08;
- }
- int end0 = 0, end1 = 0;
- switch (faceType)
- {
- case 0:
- return;
- case 3:
- end0 = EI_XMAX_YMIN;
- end1 = EI_XMAX_YMAX;
- break;
- case 5:
- end0 = EI_XMAX_YMIN;
- end1 = EI_XMAX_ZMIN;
- break;
- case 6:
- end0 = EI_XMAX_ZMIN;
- end1 = EI_XMAX_YMAX;
- break;
- case 9:
- end0 = EI_XMAX_YMIN;
- end1 = EI_XMAX_ZMAX;
- break;
- case 10:
- end0 = EI_XMAX_ZMAX;
- end1 = EI_XMAX_YMAX;
- break;
- case 12:
- end0 = EI_XMAX_ZMIN;
- end1 = EI_XMAX_ZMAX;
- break;
- default:
- LogError("The level value cannot be an exact integer.");
- }
- std::set<Vertex, Sort2> vSet;
- for (int z = box.z0 + 1; z < box.z1; ++z)
- {
- auto const& merge = mYMerge[box.x1][z];
- if (merge->IsZeroEdge(box.LY) || merge->HasZeroSubedge(box.LY))
- {
- int root = merge->GetZeroBase(box.LY);
- vSet.insert(Vertex{
- static_cast<Real>(box.x1),
- GetYInterp(box.x1, root, z),
- static_cast<Real>(z) });
- }
- }
- for (int y = box.y0 + 1; y < box.y1; y++)
- {
- auto const& merge = mZMerge[box.x1][y];
- if (merge->IsZeroEdge(box.LZ) || merge->HasZeroSubedge(box.LZ))
- {
- int root = merge->GetZeroBase(box.LZ);
- vSet.insert(Vertex{
- static_cast<Real>(box.x1),
- static_cast<Real>(y),
- GetZInterp(box.x1, y, root) });
- }
- }
- // Add subdivision.
- if (vSet.size() == 0)
- {
- table.InsertEdge(end0, end1);
- return;
- }
- Real v0y = std::floor((*vSet.begin())[1]);
- Real v1y = std::floor((*vSet.rbegin())[1]);
- Real e0y = std::floor(table.GetVertex(end0)[1]);
- Real e1y = std::floor(table.GetVertex(end1)[1]);
- if (e1y <= v0y && v1y <= e0y)
- {
- std::swap(end0, end1);
- }
- // Add vertices.
- int v0 = table.GetNumVertices(), v1 = v0;
- for (auto const& position : vSet)
- {
- table.Insert(position);
- }
- // Add edges.
- table.InsertEdge(end0, v1);
- ++v1;
- int const imax = static_cast<int>(vSet.size());
- for (int i = 1; i < imax; ++i, ++v0, ++v1)
- {
- table.InsertEdge(v0, v1);
- }
- table.InsertEdge(v0, end1);
- }
- // Support for normal vector calculations.
- Vertex GetGradient(Vertex const& position) const
- {
- Vertex vzero = { (Real)0, (Real)0, (Real)0 };
- int x = static_cast<int>(position[0]);
- if (x < 0 || x >= mTwoPowerN)
- {
- return vzero;
- }
- int y = static_cast<int>(position[1]);
- if (y < 0 || y >= mTwoPowerN)
- {
- return vzero;
- }
- int z = static_cast<int>(position[2]);
- if (z < 0 || z >= mTwoPowerN)
- {
- return vzero;
- }
- int i000 = x + mSize * (y + mSize * z);
- int i100 = i000 + 1;
- int i010 = i000 + mSize;
- int i110 = i100 + mSize;
- int i001 = i000 + mSizeSqr;
- int i101 = i100 + mSizeSqr;
- int i011 = i010 + mSizeSqr;
- int i111 = i110 + mSizeSqr;
- Real f000 = static_cast<Real>(mInputVoxels[i000]);
- Real f100 = static_cast<Real>(mInputVoxels[i100]);
- Real f010 = static_cast<Real>(mInputVoxels[i010]);
- Real f110 = static_cast<Real>(mInputVoxels[i110]);
- Real f001 = static_cast<Real>(mInputVoxels[i001]);
- Real f101 = static_cast<Real>(mInputVoxels[i101]);
- Real f011 = static_cast<Real>(mInputVoxels[i011]);
- Real f111 = static_cast<Real>(mInputVoxels[i111]);
- Real fx = position[0] - static_cast<Real>(x);
- Real fy = position[1] - static_cast<Real>(y);
- Real fz = position[2] - static_cast<Real>(z);
- Real oneMinusX = (Real)1 - fx;
- Real oneMinusY = (Real)1 - fy;
- Real oneMinusZ = (Real)1 - fz;
- Real tmp0, tmp1;
- Vertex gradient;
- tmp0 = oneMinusY * (f100 - f000) + fy * (f110 - f010);
- tmp1 = oneMinusY * (f101 - f001) + fy * (f111 - f011);
- gradient[0] = oneMinusZ * tmp0 + fz * tmp1;
- tmp0 = oneMinusX * (f010 - f000) + fx * (f110 - f100);
- tmp1 = oneMinusX * (f011 - f001) + fx * (f111 - f101);
- gradient[1] = oneMinusZ * tmp0 + fz * tmp1;
- tmp0 = oneMinusX * (f001 - f000) + fx * (f101 - f100);
- tmp1 = oneMinusX * (f011 - f010) + fx * (f111 - f110);
- gradient[2] = oneMinusY * tmp0 + oneMinusY * tmp1;
- return gradient;
- }
- enum
- {
- EI_XMIN_YMIN = 0,
- EI_XMIN_YMAX = 1,
- EI_XMAX_YMIN = 2,
- EI_XMAX_YMAX = 3,
- EI_XMIN_ZMIN = 4,
- EI_XMIN_ZMAX = 5,
- EI_XMAX_ZMIN = 6,
- EI_XMAX_ZMAX = 7,
- EI_YMIN_ZMIN = 8,
- EI_YMIN_ZMAX = 9,
- EI_YMAX_ZMIN = 10,
- EI_YMAX_ZMAX = 11,
- FI_XMIN = 12,
- FI_XMAX = 13,
- FI_YMIN = 14,
- FI_YMAX = 15,
- FI_ZMIN = 16,
- FI_ZMAX = 17,
- I_QUANTITY = 18,
- EB_XMIN_YMIN = 1 << EI_XMIN_YMIN,
- EB_XMIN_YMAX = 1 << EI_XMIN_YMAX,
- EB_XMAX_YMIN = 1 << EI_XMAX_YMIN,
- EB_XMAX_YMAX = 1 << EI_XMAX_YMAX,
- EB_XMIN_ZMIN = 1 << EI_XMIN_ZMIN,
- EB_XMIN_ZMAX = 1 << EI_XMIN_ZMAX,
- EB_XMAX_ZMIN = 1 << EI_XMAX_ZMIN,
- EB_XMAX_ZMAX = 1 << EI_XMAX_ZMAX,
- EB_YMIN_ZMIN = 1 << EI_YMIN_ZMIN,
- EB_YMIN_ZMAX = 1 << EI_YMIN_ZMAX,
- EB_YMAX_ZMIN = 1 << EI_YMAX_ZMIN,
- EB_YMAX_ZMAX = 1 << EI_YMAX_ZMAX,
- FB_XMIN = 1 << FI_XMIN,
- FB_XMAX = 1 << FI_XMAX,
- FB_YMIN = 1 << FI_YMIN,
- FB_YMAX = 1 << FI_YMAX,
- FB_ZMIN = 1 << FI_ZMIN,
- FB_ZMAX = 1 << FI_ZMAX
- };
- // image data
- int mTwoPowerN, mSize, mSizeSqr;
- T const* mInputVoxels;
- Real mLevel;
- bool mFixBoundary;
- // Trees for linear merging.
- Array2<std::shared_ptr<LinearMergeTree>> mXMerge, mYMerge, mZMerge;
- // monoboxes
- std::vector<OctBox> mBoxes;
- };
- }
|