00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include <vlVolume/MarchingCubes.hpp>
00035 #include <vlCore/Time.hpp>
00036 #include <vlGraphics/DoubleVertexRemover.hpp>
00037
00038 using namespace vl;
00039
00059
00060 MarchingCubes::MarchingCubes()
00061 {
00062 mVertsArray = new ArrayFloat3;
00063 mNormsArray = new ArrayFloat3;
00064 mColorArray = new ArrayFloat4;
00065
00066
00067 #if defined(VL_OPENGL)
00068 mDrawElements = new DrawElementsUInt(PT_TRIANGLES);
00069 #else
00070 mDrawElements = new DrawElementsUShort(PT_TRIANGLES);
00071 #endif
00072 mVolumeInfo.setAutomaticDelete(false);
00073 mHighQualityNormals = true;
00074 }
00075
00076
00077
00078 void MarchingCubes::computeEdges(Volume* vol, float threshold)
00079 {
00080
00081 mEdges.resize(vol->slices().x() * vol->slices().y() * vol->slices().z());
00082 mCubes.clear();
00083 mCubes.reserve(1024);
00084
00086
00087
00088
00089
00091
00092 const float dx = vol->cellSize().x() * 0.25f;
00093 const float dy = vol->cellSize().y() * 0.25f;
00094 const float dz = vol->cellSize().z() * 0.25f;
00095 float v0, v1, v2, v3, t;
00096 int iedge = 0;
00097 int w = vol->slices().x() -1;
00098 int h = vol->slices().y() -1;
00099 int d = vol->slices().z() -1;
00100 for(unsigned short z = 0; z < vol->slices().z(); ++z)
00101 {
00102 for(unsigned short y = 0; y < vol->slices().y(); ++y)
00103 {
00104 for(unsigned short x = 0; x < vol->slices().x(); ++x, ++iedge)
00105 {
00106 if (x != w && y != h && z != d)
00107 {
00108 if (vol->cube(x,y,z).includes(threshold))
00109 {
00110 if (mCubes.capacity()-mCubes.size() == 0)
00111 mCubes.reserve(mCubes.size()*2);
00112 mCubes.push_back( usvec3(x,y,z) );
00113 }
00114 else
00115 continue;
00116 }
00117
00118 if (mVerts.capacity() - mVerts.size() == 0)
00119 {
00120 mVerts.reserve( mVerts.size() * 2 );
00121 mNorms.reserve( mNorms.size() * 2 );
00122 }
00123
00124 v0 = vol->value( x,y,z );
00125 fvec3 v0_coord = vol->coordinate(x, y, z);
00126
00127 if (x != w)
00128 {
00129 v1 = vol->value( x + 1, y, z );
00130 if (v1!=v0)
00131 {
00132
00133 if ( (threshold>=v0 && threshold<=v1) || (threshold>=v1 && threshold<=v0) )
00134 {
00135 t = (threshold-v0)/(v1-v0);
00136 VL_CHECK(t>=-0.001f && t<=1.001f)
00137
00138 mEdges[iedge].mX = (int)mVerts.size();
00139
00140 mVerts.push_back( v0_coord * (1.0f-t) + vol->coordinate(x + 1, y, z) * t );
00141 if (mHighQualityNormals)
00142 {
00143 fvec3 n;
00144 vol->normalHQ(n, mVerts.back(), dx, dy, dz);
00145 mNorms.push_back(n);
00146 }
00147 }
00148 }
00149 }
00150 if (y != h)
00151 {
00152 v2 = vol->value( x, y + 1, z );
00153 if (v2!=v0)
00154 {
00155
00156 if ( (threshold>=v0 && threshold<=v2) || (threshold>=v2 && threshold<=v0) )
00157 {
00158 t = (threshold-v0)/(v2-v0);
00159 VL_CHECK(t>=-0.001f && t<=1.001f)
00160
00161 mEdges[iedge].mY = (int)mVerts.size();
00162
00163 mVerts.push_back( v0_coord * (1.0f-t) + vol->coordinate(x, y + 1, z) * t );
00164 if (mHighQualityNormals)
00165 {
00166 fvec3 n;
00167 vol->normalHQ(n, mVerts.back(), dx, dy, dz);
00168 mNorms.push_back(n);
00169 }
00170 }
00171 }
00172 }
00173 if (z != d)
00174 {
00175 v3 = vol->value( x, y, z + 1 );
00176 if (v3!=v0)
00177 {
00178
00179 if ( (threshold>=v0 && threshold<=v3) || (threshold>=v3 && threshold<=v0) )
00180 {
00181 t = (threshold-v0)/(v3-v0);
00182 VL_CHECK(t>=-0.001f && t<=1.001f)
00183
00184 mEdges[iedge].mZ = (int)mVerts.size();
00185
00186 mVerts.push_back( v0_coord * (1.0f-t) + vol->coordinate(x, y, z + 1) * t );
00187 if (mHighQualityNormals)
00188 {
00189 fvec3 n;
00190 vol->normalHQ(n, mVerts.back(), dx, dy, dz);
00191 mNorms.push_back(n);
00192 }
00193 }
00194 }
00195 }
00196 }
00197 }
00198 }
00199 }
00200
00201 void MarchingCubes::processCube(int x, int y, int z, Volume* vol, float threshold)
00202 {
00203 int inner_corners = 0;
00204
00205 if ( vol->value( x, y, z ) < threshold ) inner_corners += 1;
00206 if ( vol->value( x + 1, y, z ) < threshold ) inner_corners += 2;
00207 if ( vol->value( x + 1, y + 1, z ) < threshold ) inner_corners += 4;
00208 if ( vol->value( x, y + 1, z ) < threshold ) inner_corners += 8;
00209 if ( vol->value( x, y, z + 1 ) < threshold ) inner_corners += 16;
00210 if ( vol->value( x + 1, y, z + 1 ) < threshold ) inner_corners += 32;
00211 if ( vol->value( x + 1, y + 1, z + 1 ) < threshold ) inner_corners += 64;
00212 if ( vol->value( x, y + 1, z + 1 ) < threshold ) inner_corners += 128;
00213
00214 int cut_edges = mCubeEdgeFlags[inner_corners];
00215
00216 if(cut_edges == 0)
00217 return;
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229 int z0 = z * vol->slices().x()*vol->slices().y();
00230 int z1 = (z+1) * vol->slices().x()*vol->slices().y();
00231 int y0 = y * vol->slices().x();
00232 int y1 = (y+1) * vol->slices().x();
00233
00234 int cell0 = x + y0 + z0;
00235 int cell1 = (x+1) + y0 + z0;
00236 int cell2 = (x+1) + y0 + z1;
00237 int cell3 = x + y0 + z1;
00238 int cell4 = (x+1) + y1 + z0;
00239 int cell5 = x + y1 + z0;
00240 int cell6 = x + y1 + z1;
00241
00242 int edge_ivert[12] =
00243 {
00244 mEdges[cell0].mX,
00245 mEdges[cell1].mY,
00246 mEdges[cell5].mX,
00247 mEdges[cell0].mY,
00248
00249 mEdges[cell3].mX,
00250 mEdges[cell2].mY,
00251 mEdges[cell6].mX,
00252 mEdges[cell3].mY,
00253
00254 mEdges[cell0].mZ,
00255 mEdges[cell1].mZ,
00256 mEdges[cell4].mZ,
00257 mEdges[cell5].mZ,
00258 };
00259
00260 int ivertex;
00261 for(int icorner = 0; mTriangleConnectionTable[inner_corners][icorner]>=0; icorner+=3)
00262 {
00263 if (mIndices.capacity() - mIndices.size() == 0)
00264 mIndices.reserve( mIndices.size()*2 );
00265
00266 ivertex = mTriangleConnectionTable[inner_corners][icorner+0];
00267 int a = edge_ivert[ivertex];
00268
00269 ivertex = mTriangleConnectionTable[inner_corners][icorner+1];
00270 int b = edge_ivert[ivertex];
00271
00272 ivertex = mTriangleConnectionTable[inner_corners][icorner+2];
00273 int c = edge_ivert[ivertex];
00274
00275 if (a<0 || b<0 || c<0)
00276 continue;
00277
00278
00279 if (a==b||b==c||c==a)
00280 continue;
00281
00282 #if 0
00283
00284 fvec3 v0 = mVerts[a];
00285 fvec3 v1 = mVerts[b] - v0;
00286 fvec3 v2 = mVerts[c] - v1;
00287 if (cross(v2,v1).isNull())
00288 continue;
00289 #endif
00290
00291 mIndices.push_back((IndexType)a);
00292 mIndices.push_back((IndexType)b);
00293 mIndices.push_back((IndexType)c);
00294 }
00295 }
00296
00297 void MarchingCubes::reset()
00298 {
00299 mVertsArray->clear();
00300 mNormsArray->clear();
00301 mColorArray->clear();
00302 mDrawElements->indexBuffer()->clear();
00303 mIndices.clear();
00304 mVerts.clear();
00305 mNorms.clear();
00306 mColors.clear();
00307 mCubes.clear();
00308 mEdges.clear();
00309 mVolumeInfo.clear();
00310 }
00311
00312 void MarchingCubes::run(bool generate_colors)
00313 {
00314 mVerts.clear();
00315 mNorms.clear();
00316 mIndices.clear();
00317 mVerts.reserve(1024);
00318 mNorms.reserve(1024);
00319 mColors.reserve(1024);
00320 mIndices.reserve(1024);
00321
00322
00323
00324 for(int ivol=0; ivol<mVolumeInfo.size(); ++ivol)
00325 {
00326 Volume* vol = mVolumeInfo.at(ivol)->volume();
00327 float threshold = mVolumeInfo.at(ivol)->threshold();
00328 int start = (int)mVerts.size();
00329
00330 if (vol->dataIsDirty())
00331 vol->setupInternalData();
00332
00333
00334 computeEdges(vol, threshold);
00335
00336
00338
00339
00340
00341
00342
00343
00344 for(unsigned int i=0; i<mCubes.size(); ++i)
00345 processCube(mCubes[i].x(), mCubes[i].y(), mCubes[i].z(), vol, threshold);
00346
00347 int count = (int)mVerts.size() - start;
00348 mVolumeInfo.at(ivol)->setVert0(start);
00349 mVolumeInfo.at(ivol)->setVertC(count);
00350
00351
00352 if (generate_colors)
00353 {
00354 mColors.resize( mVerts.size() );
00355 for(int i=start; i<start+count; ++i)
00356 mColors[i] = mVolumeInfo.at(ivol)->color();
00357 }
00358 }
00359
00360 mVertsArray->resize(mVerts.size());
00361 mVertsArray->setBufferObjectDirty();
00362 if (mVerts.size())
00363 memcpy(mVertsArray->ptr(), &mVerts[0], sizeof(mVerts[0]) * mVerts.size());
00364
00365 mNormsArray->resize(mNorms.size());
00366 mNormsArray->setBufferObjectDirty();
00367 if (mNorms.size())
00368 memcpy(mNormsArray->ptr(), &mNorms[0], sizeof(mNorms[0]) * mNorms.size());
00369
00370 if (generate_colors)
00371 {
00372 mColorArray->resize(mColors.size());
00373 mColorArray->setBufferObjectDirty();
00374 if (mColors.size())
00375 memcpy(mColorArray->ptr(), &mColors[0], sizeof(mColors[0]) * mColors.size());
00376 }
00377 else
00378 mColorArray->clear();
00379
00380 mDrawElements->indexBuffer()->resize(mIndices.size());
00381 mDrawElements->indexBuffer()->setBufferObjectDirty(true);
00382 if (mIndices.size())
00383 memcpy(mDrawElements->indexBuffer()->ptr(), &mIndices[0], sizeof(mIndices[0]) * mIndices.size());
00384
00385 if (!mHighQualityNormals)
00386 {
00387 ref<Geometry> geom = new Geometry;
00388 geom->setVertexArray(mVertsArray.get());
00389 geom->drawCalls()->push_back(mDrawElements.get());
00390
00391 geom->computeNormals();
00392 mNormsArray->resize( geom->normalArray()->size() );
00393 mNormsArray->setBufferObjectDirty();
00394 memcpy(mNormsArray->ptr(), geom->normalArray()->ptr(), sizeof(mNormsArray->at(0)) * mNormsArray->size());
00395 }
00396 }
00397
00398 void MarchingCubes::updateColor(const fvec3& color, int volume_index)
00399 {
00400 if(volume_index>=mVolumeInfo.size())
00401 {
00402 Log::error( Say("updateColor() volume index (%n) out of range.\n") << volume_index);
00403 return;
00404 }
00405 int start = mVolumeInfo.at(volume_index)->vert0();
00406 int count = mVolumeInfo.at(volume_index)->vertC();
00407 if (start+count > (int)mColorArray->size())
00408 {
00409 Log::error("updateColor() color array not preset.\n");
00410 return;
00411 }
00412 for(int i=start; i<start+count; ++i)
00413 {
00414 mColorArray->at(i).r() = color.r();
00415 mColorArray->at(i).g() = color.g();
00416 mColorArray->at(i).b() = color.b();
00417 }
00418 }
00419
00420 void MarchingCubes::updateColor(const fvec4& color, int volume_index)
00421 {
00422 if(volume_index>=mVolumeInfo.size())
00423 {
00424 Log::error( Say("updateColor() volume index (%n) out of range.\n") << volume_index);
00425 return;
00426 }
00427 int start = mVolumeInfo.at(volume_index)->vert0();
00428 int count = mVolumeInfo.at(volume_index)->vertC();
00429 if (start+count > (int)mColorArray->size())
00430 {
00431 Log::error("updateColor() color array not preset.\n");
00432 return;
00433 }
00434 for(int i=start; i<start+count; ++i)
00435 mColorArray->at(i) = color;
00436 }
00437
00438 void MarchingCubes::updateAlpha(float alpha, int volume_index)
00439 {
00440 if(volume_index>=mVolumeInfo.size())
00441 {
00442 Log::error( Say("updateColor() volume index (%n) out of range.\n") << volume_index);
00443 return;
00444 }
00445 int start = mVolumeInfo.at(volume_index)->vert0();
00446 int count = mVolumeInfo.at(volume_index)->vertC();
00447 if (start+count > (int)mColorArray->size())
00448 {
00449 Log::error("updateColor() color array not preset.\n");
00450 return;
00451 }
00452 for(int i=start; i<start+count; ++i)
00453 mColorArray->at(i).a() = alpha;
00454 }
00455
00456
00457
00458 Volume::Volume()
00459 {
00460 VL_DEBUG_SET_OBJECT_NAME()
00461 setup(NULL, false, false, fvec3(0,0,0), fvec3(1.0f,1.0f,1.0f), ivec3(50,50,50));
00462 }
00463
00464 ref<Volume> Volume::downsample() const
00465 {
00466 ref<Volume> vol = new Volume;
00467 int w = mSlices.x() / 2;
00468 int h = mSlices.y() / 2;
00469 int d = mSlices.z() / 2;
00470 if (w<1) w = 1;
00471 if (h<1) h = 1;
00472 if (d<1) d = 1;
00473
00474 vol->setup(NULL, false, false, bottomLeft(), topRight(), ivec3(w,h,d));
00475
00476 for(int z=0; z<d; ++z)
00477 {
00478 int z1=z*2;
00479 int z2=z*2+1;
00480 for(int y=0; y<h; ++y)
00481 {
00482 int y1=y*2;
00483 int y2=y*2+1;
00484 for(int x=0; x<w; ++x)
00485 {
00486 int x1 = x*2;
00487 int x2 = x*2+1;
00488 float v0 = value(x1,y1,z1);
00489 float v1 = value(x1,y1,z2);
00490 float v2 = value(x1,y2,z1);
00491 float v3 = value(x1,y2,z2);
00492 float v4 = value(x2,y1,z1);
00493 float v5 = value(x2,y1,z2);
00494 float v6 = value(x2,y2,z1);
00495 float v7 = value(x2,y2,z2);
00496 vol->value(x,y,z) = (v0+v1+v2+v3+v4+v5+v6+v7) * (1.0f/8.0f);
00497 }
00498 }
00499 }
00500
00501 return vol;
00502 }
00503
00504 void Volume::setupInternalData()
00505 {
00506 mDataIsDirty = false;
00507 int w = slices().x() -1;
00508 int h = slices().y() -1;
00509 int d = slices().z() -1;
00510 mCubes.resize(w*h*d);
00511 for(int z = 0; z < d; ++z)
00512 {
00513 for(int y = 0; y < h; ++y)
00514 {
00515 for(int x = 0; x < w; ++x)
00516 {
00517 float v[] =
00518 {
00519 value(x+0,y+0,z+0),
00520 value(x+0,y+0,z+1),
00521 value(x+0,y+1,z+0),
00522 value(x+0,y+1,z+1),
00523 value(x+1,y+0,z+0),
00524 value(x+1,y+0,z+1),
00525 value(x+1,y+1,z+0),
00526 value(x+1,y+1,z+1)
00527 };
00528 int icube = x+w*y+w*h*z;
00529 mCubes[icube].mMin = v[0];
00530 mCubes[icube].mMax = v[0];
00531 for(int i=1; i<8; ++i)
00532 {
00533 if (mCubes[icube].mMin > v[i]) mCubes[icube].mMin = v[i];
00534 if (mCubes[icube].mMax < v[i]) mCubes[icube].mMax = v[i];
00535 }
00536 }
00537 }
00538 }
00539 }
00540
00541 void Volume::setup( float* data, bool use_directly, bool copy_data, const fvec3& bottom_left, const fvec3& top_right, const ivec3& slices )
00542 {
00543 fvec3 size = top_right-bottom_left;
00544
00545 if (use_directly)
00546 {
00547 VL_CHECK(data);
00548
00549 std::vector<float>().swap( mInternalValues );
00550 mValues = data;
00551 }
00552 else
00553 {
00554
00555 mInternalValues.resize( slices.x() * slices.y() * slices.z() );
00556 mValues = &mInternalValues[0];
00557 if (copy_data)
00558 memcpy( mValues, data, slices.x() * slices.y() * slices.z() * sizeof(float) );
00559 }
00560
00561 mBottomLeft = bottom_left;
00562 mTopRight = top_right;
00563 mSize = topRight()-bottomLeft();
00564 mSlices = slices;
00565 mCellSize.x() = size.x() / (slices.x()-1);
00566 mCellSize.y() = size.y() / (slices.y()-1);
00567 mCellSize.z() = size.z() / (slices.z()-1);
00568
00569 mMinimum = +1;
00570 mMaximum = -1;
00571 mAverage = 0;
00572 mDataIsDirty = true;
00573 }
00574
00575 void Volume::setup(const Volume& volume)
00576 {
00577 *this = volume;
00578 mMinimum = +1;
00579 mMaximum = -1;
00580 mAverage = 0;
00581 mDataIsDirty = true;
00582 }
00583
00584 float Volume::sampleNearest(float x, float y, float z) const
00585 {
00586 x = (x - mBottomLeft.x()) / mSize.x();
00587 y = (y - mBottomLeft.y()) / mSize.y();
00588 z = (z - mBottomLeft.z()) / mSize.z();
00589 if (x<0 || y<0 || z<0) return 0;
00590 if (x>1.0001 || y>1.0001 || z>1.0001) return 0;
00591 if (x > 0.9999f) x = 0.9999f;
00592 if (y > 0.9999f) y = 0.9999f;
00593 if (z > 0.9999f) z = 0.9999f;
00594 float xt = x * (mSlices.x()-1);
00595 float yt = y * (mSlices.y()-1);
00596 float zt = z * (mSlices.z()-1);
00597 int ix = int(xt);
00598 int iy = int(yt);
00599 int iz = int(zt);
00600 return value(ix , iy, iz);
00601 }
00602
00603 float Volume::sampleSmooth(float x, float y, float z) const
00604 {
00605 x = (x - mBottomLeft.x()) / mSize.x();
00606 y = (y - mBottomLeft.y()) / mSize.y();
00607 z = (z - mBottomLeft.z()) / mSize.z();
00608 if (x<0 || y<0 || z<0) return 0;
00609 if (x>1.0f || y>1.0f || z>1.0f) return 0;
00610 if (x > 0.9999f) x = 0.9999f;
00611 if (y > 0.9999f) y = 0.9999f;
00612 if (z > 0.9999f) z = 0.9999f;
00613 float xt = x * (mSlices.x()-1);
00614 float yt = y * (mSlices.y()-1);
00615 float zt = z * (mSlices.z()-1);
00616 int ix = int(xt); xt -= ix;
00617 int iy = int(yt); yt -= iy;
00618 int iz = int(zt); zt -= iz;
00619 float val0 = value(ix , iy, iz);
00620 float val1 = value(ix+1, iy, iz);
00621 float val2 = value(ix+1, iy+1, iz);
00622 float val3 = value(ix, iy+1, iz);
00623 float val4 = value(ix , iy, iz+1);
00624 float val5 = value(ix+1, iy, iz+1);
00625 float val6 = value(ix+1, iy+1, iz+1);
00626 float val7 = value(ix, iy+1, iz+1);
00627 float xt1 = 1-xt;
00628 float yt1 = 1-yt;
00629 float zt1 = 1-zt;
00630 float v1 = val0*(yt1) + val3*yt;
00631 float v2 = val1*(yt1) + val2*yt;
00632 float a = v1*(xt1) + v2*xt;
00633 v1 = val4*(yt1) + val7*yt;
00634 v2 = val5*(yt1) + val6*yt;
00635 float b = v1*(xt1) + v2*xt;
00636 return a*(zt1) + b*zt;
00637 }
00638
00639 void Volume::normalHQ(fvec3 &normal, const fvec3& v, float dx, float dy, float dz)
00640 {
00642
00644 normal.x() = sampleSmooth(v.x()-dx, v.y(), v.z()) - sampleSmooth(v.x()+dx, v.y(), v.z());
00645 normal.y() = sampleSmooth(v.x(), v.y()-dy, v.z()) - sampleSmooth(v.x(), v.y()+dy, v.z());
00646 normal.z() = sampleSmooth(v.x(), v.y(), v.z()-dz) - sampleSmooth(v.x(), v.y(), v.z()+dz);
00647 normal.normalize();
00648 }
00649
00650 void Volume::normalLQ(fvec3 &normal, const fvec3& v, float dx, float dy, float dz)
00651 {
00652
00653
00654 float v0 = sampleSmooth(v.x(), v.y(), v.z());
00655 normal.x() = v0 - sampleSmooth(v.x()+dx, v.y(), v.z());
00656 normal.y() = v0 - sampleSmooth(v.x(), v.y()+dy, v.z());
00657 normal.z() = v0 - sampleSmooth(v.x(), v.y(), v.z()+dz);
00658 normal.normalize();
00659 }
00660
00661 float Volume::computeMinimum() const
00662 {
00663 if (!mValues)
00664 return 0;
00665 float lowest = mValues[0];
00666 int val_count = mSlices.x() * mSlices.y() * mSlices.z();
00667 for(int i=1; i<val_count; ++i)
00668 if (mValues[i] < lowest)
00669 lowest = mValues[i];
00670 return lowest;
00671 }
00672
00673 float Volume::computeMaximum() const
00674 {
00675 if (!mValues)
00676 return 0;
00677 float highest = mValues[0];
00678 int val_count = mSlices.x() * mSlices.y() * mSlices.z();
00679 for(int i=1; i<val_count; ++i)
00680 if (mValues[i] > highest)
00681 highest = mValues[i];
00682 return highest;
00683 }
00684
00685 float Volume::computeAverage() const
00686 {
00687 if (!mValues)
00688 return 0;
00689 double average = 0;
00690 int val_count = mSlices.x() * mSlices.y() * mSlices.z();
00691 for(int i=0; i<val_count; ++i)
00692 average += mValues[i];
00693 average /= (double)val_count;
00694 return (float)average;
00695 }
00696
00697 const int MarchingCubes::mCubeEdgeFlags[256]=
00698 {
00699 0x000, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
00700 0x190, 0x099, 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
00701 0x230, 0x339, 0x033, 0x13a, 0x636, 0x73f, 0x435, 0x53c, 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
00702 0x3a0, 0x2a9, 0x1a3, 0x0aa, 0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
00703 0x460, 0x569, 0x663, 0x76a, 0x066, 0x16f, 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
00704 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0x0ff, 0x3f5, 0x2fc, 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
00705 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x055, 0x15c, 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
00706 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0x0cc, 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
00707 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 0x0cc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
00708 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 0x15c, 0x055, 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
00709 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 0x2fc, 0x3f5, 0x0ff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
00710 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x066, 0x76a, 0x663, 0x569, 0x460,
00711 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 0x4ac, 0x5a5, 0x6af, 0x7a6, 0x0aa, 0x1a3, 0x2a9, 0x3a0,
00712 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x033, 0x339, 0x230,
00713 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x099, 0x190,
00714 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x000
00715 };
00716
00717 const int MarchingCubes::mTriangleConnectionTable[256][16] =
00718 {
00719 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00720 {0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00721 {0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00722 {1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00723 {1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00724 {0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00725 {9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00726 {2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1},
00727 {3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00728 {0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00729 {1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00730 {1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1},
00731 {3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00732 {0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1},
00733 {3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1},
00734 {9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00735 {4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00736 {4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00737 {0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00738 {4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1},
00739 {1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00740 {3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1},
00741 {9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
00742 {2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1},
00743 {8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00744 {11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1},
00745 {9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
00746 {4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1},
00747 {3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1},
00748 {1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1},
00749 {4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1},
00750 {4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1},
00751 {9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00752 {9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00753 {0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00754 {8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1},
00755 {1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00756 {3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
00757 {5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1},
00758 {2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1},
00759 {9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00760 {0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
00761 {0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
00762 {2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1},
00763 {10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1},
00764 {4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1},
00765 {5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1},
00766 {5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1},
00767 {9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00768 {9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1},
00769 {0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1},
00770 {1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00771 {9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1},
00772 {10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1},
00773 {8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1},
00774 {2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1},
00775 {7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1},
00776 {9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1},
00777 {2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1},
00778 {11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1},
00779 {9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1},
00780 {5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1},
00781 {11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1},
00782 {11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00783 {10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00784 {0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00785 {9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00786 {1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
00787 {1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00788 {1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1},
00789 {9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1},
00790 {5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1},
00791 {2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00792 {11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
00793 {0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
00794 {5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1},
00795 {6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1},
00796 {0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1},
00797 {3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1},
00798 {6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1},
00799 {5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00800 {4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1},
00801 {1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
00802 {10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1},
00803 {6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1},
00804 {1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1},
00805 {8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1},
00806 {7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1},
00807 {3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
00808 {5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1},
00809 {0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1},
00810 {9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1},
00811 {8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1},
00812 {5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1},
00813 {0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1},
00814 {6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1},
00815 {10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00816 {4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1},
00817 {10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1},
00818 {8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1},
00819 {1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1},
00820 {3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1},
00821 {0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00822 {8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1},
00823 {10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1},
00824 {0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1},
00825 {3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1},
00826 {6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1},
00827 {9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1},
00828 {8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1},
00829 {3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1},
00830 {6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00831 {7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1},
00832 {0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1},
00833 {10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1},
00834 {10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1},
00835 {1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1},
00836 {2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1},
00837 {7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1},
00838 {7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00839 {2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1},
00840 {2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1},
00841 {1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1},
00842 {11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1},
00843 {8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1},
00844 {0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00845 {7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1},
00846 {7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00847 {7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00848 {3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00849 {0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00850 {8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
00851 {10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00852 {1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
00853 {2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
00854 {6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1},
00855 {7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00856 {7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1},
00857 {2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1},
00858 {1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1},
00859 {10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1},
00860 {10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1},
00861 {0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1},
00862 {7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1},
00863 {6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00864 {3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1},
00865 {8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1},
00866 {9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1},
00867 {6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1},
00868 {1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1},
00869 {4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1},
00870 {10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1},
00871 {8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1},
00872 {0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00873 {1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1},
00874 {1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1},
00875 {8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1},
00876 {10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1},
00877 {4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1},
00878 {10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00879 {4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00880 {0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
00881 {5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
00882 {11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1},
00883 {9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
00884 {6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1},
00885 {7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1},
00886 {3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1},
00887 {7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1},
00888 {9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1},
00889 {3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1},
00890 {6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1},
00891 {9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1},
00892 {1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1},
00893 {4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1},
00894 {7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1},
00895 {6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1},
00896 {3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1},
00897 {0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1},
00898 {6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1},
00899 {1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1},
00900 {0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1},
00901 {11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1},
00902 {6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1},
00903 {5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1},
00904 {9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1},
00905 {1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1},
00906 {1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00907 {1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1},
00908 {10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1},
00909 {0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00910 {10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00911 {11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00912 {11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1},
00913 {5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1},
00914 {10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1},
00915 {11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1},
00916 {0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1},
00917 {9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1},
00918 {7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1},
00919 {2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1},
00920 {8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1},
00921 {9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1},
00922 {9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1},
00923 {1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00924 {0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1},
00925 {9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1},
00926 {9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00927 {5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1},
00928 {5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1},
00929 {0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1},
00930 {10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1},
00931 {2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1},
00932 {0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1},
00933 {0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1},
00934 {9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00935 {2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1},
00936 {5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1},
00937 {3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1},
00938 {5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1},
00939 {8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1},
00940 {0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00941 {8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1},
00942 {9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00943 {4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1},
00944 {0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1},
00945 {1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1},
00946 {3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1},
00947 {4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1},
00948 {9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1},
00949 {11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1},
00950 {11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1},
00951 {2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1},
00952 {9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1},
00953 {3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1},
00954 {1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00955 {4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1},
00956 {4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1},
00957 {4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00958 {4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00959 {9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00960 {3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1},
00961 {0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1},
00962 {3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00963 {1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1},
00964 {3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1},
00965 {0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00966 {3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00967 {2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1},
00968 {9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00969 {2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1},
00970 {1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00971 {1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00972 {0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00973 {0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
00974 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}
00975 };
00976