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