//---------------------------------------------------------------------------- void ConvexHull2D::GenerateHull2D () { // Generate random points. mNumVertices = 256; delete1(mVertices); mVertices = new1<Vector2f>(mNumVertices); for (int i = 0; i < mNumVertices; ++i) { mVertices[i].X() = Mathf::UnitRandom(); mVertices[i].Y() = Mathf::UnitRandom(); } RegenerateHull(); assertion(mHull->GetDimension() == 2, "Incorrect dimension.\n"); }
//---------------------------------------------------------------------------- void ConvexHull2D::GenerateHull0D () { mNumVertices = 8; delete1(mVertices); mVertices = new1<Vector2f>(mNumVertices); mVertices[0].X() = Mathf::UnitRandom(); mVertices[0].Y() = Mathf::UnitRandom(); for (int i = 1; i < mNumVertices; ++i) { float sign = (Mathf::SymmetricRandom() > 0.0f ? 1.0f : -1.0f); mVertices[i].X() = mVertices[0].X() + sign*0.00001f; mVertices[i].Y() = mVertices[0].Y() + sign*0.00001f; } RegenerateHull(); assertion(mHull->GetDimension() == 0, "Incorrect dimension.\n"); }
//---------------------------------------------------------------------------- void ConvexHull2D::GenerateHullManyCollinear () { // Generate a lot of nearly collinear points. mNumVertices = 128; delete1(mVertices); mVertices = new1<Vector2f>(mNumVertices); Vector2f center(0.5f, 0.5f); Vector2f U0(Mathf::SymmetricRandom(), Mathf::SymmetricRandom()); U0.Normalize(); Vector2f U1 = U0.Perp(); float e0 = 0.5f*Mathf::UnitRandom(); float e1 = 0.5f*Mathf::UnitRandom(); float t; int i; for (i = 0; i < mNumVertices/4; ++i) { t = i/(mNumVertices/4.0f); mVertices[i] = center - e0*U0 - e1*U1 + 2.0f*e0*t*U0; } for (i = 0; i < mNumVertices/4; i++) { t = i/(mNumVertices/4.0f); mVertices[i + mNumVertices/4] = center + e0*U0 - e1*U1 + 2.0f*e1*t*U1; } for (i = 0; i < mNumVertices/4; i++) { t = i/(mNumVertices/4.0f); mVertices[i + mNumVertices/2] = center + e0*U0 + e1*U1 - 2.0f*e0*t*U0; } for (i = 0; i < mNumVertices/4; i++) { t = i/(mNumVertices/4.0f); mVertices[i + 3*mNumVertices/4] = center - e0*U0 + e1*U1 - 2.0f*e1*t*U1; } RegenerateHull(); assertion(mHull->GetDimension() == 2, "Incorrect dimension.\n"); }
//---------------------------------------------------------------------------- void ConvexHull2D::GenerateHull1D () { mNumVertices = 32; delete1(mVertices); mVertices = new1<Vector2f>(mNumVertices); int qm1 = mNumVertices - 1; mVertices[0].X() = Mathf::UnitRandom(); mVertices[0].Y() = Mathf::UnitRandom(); mVertices[qm1].X() = Mathf::UnitRandom(); mVertices[qm1].Y() = Mathf::UnitRandom(); for (int i = 1; i < qm1; ++i) { float sign = (Mathf::SymmetricRandom() > 0.0f ? 1.0f : -1.0f); float t = Mathf::UnitRandom(); mVertices[i] = (1.0f - t)*mVertices[0] + t*mVertices[qm1]; mVertices[i].X() += sign*0.00001f; mVertices[i].Y() += sign*0.00001f; } RegenerateHull(); assertion(mHull->GetDimension() == 1, "Incorrect dimension.\n"); }
//---------------------------------------------------------------------------- void ConvexHull3D::CreateHull () { int numVertices = mLimitedQuantity; VertexFormat* vformat = VertexFormat::Create(2, VertexFormat::AU_POSITION, VertexFormat::AT_FLOAT3, 0, VertexFormat::AU_COLOR, VertexFormat::AT_FLOAT3, 0); int vstride = vformat->GetStride(); VertexBuffer* vbuffer = new0 VertexBuffer(numVertices, vstride); VertexBufferAccessor vba(vformat, vbuffer); int i; for (i = 0; i < numVertices; ++i) { vba.Position<Vector3f>(i) = mVertices[i]; vba.Color<Float3>(0, i) = mColors[i]; } RegenerateHull(); int numTriangles = 0; TriMesh* mesh = 0; switch (mHull->GetDimension()) { case 0: sprintf(mFooter, "point: v = %d, t = %d", numVertices, numTriangles); return; case 1: sprintf(mFooter, "linear: v = %d, t = %d", numVertices, numTriangles); return; case 2: { numTriangles = mHull->GetNumSimplices() - 2; const int* hullIndices = mHull->GetIndices(); IndexBuffer* ibuffer = new0 IndexBuffer(3*numTriangles, sizeof(int)); int* indices = (int*)ibuffer->GetData(); for (int t = 0, i0 = 1, i1 = 2; t < numTriangles; ++t, ++i0, ++i1) { *indices++ = hullIndices[0]; *indices++ = hullIndices[i0]; *indices++ = hullIndices[i1]; } mesh = new0 TriMesh(vformat, vbuffer, ibuffer); mesh->SetEffectInstance(VertexColor3Effect::CreateUniqueInstance()); sprintf(mFooter, "planar: v = %d, t = %d", numVertices, numTriangles); break; } case 3: numTriangles = mHull->GetNumSimplices(); const int* hullIndices = mHull->GetIndices(); IndexBuffer* ibuffer = new0 IndexBuffer(3*numTriangles, sizeof(int)); int* indices = (int*)ibuffer->GetData(); memcpy(indices, hullIndices, 3*numTriangles*sizeof(int)); mesh = new0 TriMesh(vformat, vbuffer, ibuffer); mesh->SetEffectInstance(VertexColor3Effect::CreateUniqueInstance()); sprintf(mFooter, "spatial: v = %d, t = %d", numVertices, numTriangles); break; } // Translate to center of mass. Vector3f center = mVertices[0]; for (i = 1; i < mLimitedQuantity; ++i) { center += mVertices[i]; } center /= (float)mLimitedQuantity; mesh->LocalTransform.SetTranslate(-center); mTrnNode->SetChild(0, mesh); for (i = 2; i < mLimitedQuantity + 2; ++i) { mTrnNode->SetChild(i, CreateSphere()); } TriMesh* sphere = StaticCast<TriMesh>(mTrnNode->GetChild(1)); sphere->LocalTransform.SetTranslate( mVertices[mLimitedQuantity - 1] - center); // Update the scene, center-and-fit to frustum. mScene->Update(); mTrnNode->LocalTransform.SetTranslate(-mScene->WorldBound.GetCenter()); APoint camPosition = APoint::ORIGIN - 2.5f*mScene->WorldBound.GetRadius()*mCamera->GetDVector(); mCamera->SetPosition(camPosition); mCuller.ComputeVisibleSet(mScene); }
//---------------------------------------------------------------------------- bool ConvexHull3D::OnKeyDown (unsigned char key, int x, int y) { switch (key) { // load a new data set case 'd': case 'D': if (++mCurrentFile == mFileQuantity) { mCurrentFile = 1; } LoadData(); return true; // query type INT64 case 'n': case 'N': mQueryType = Query::QT_INT64; strcpy(mHeader, "query type = INT64"); RegenerateHull(); return true; // query type INTEGER case 'i': case 'I': mQueryType = Query::QT_INTEGER; strcpy(mHeader, "query type = INTEGER"); RegenerateHull(); return true; // query type RATIONAL case 'r': case 'R': mQueryType = Query::QT_RATIONAL; strcpy(mHeader, "query type = RATIONAL"); RegenerateHull(); return true; // query type REAL (float) case 'f': case 'F': mQueryType = Query::QT_REAL; strcpy(mHeader, "query type = REAL"); RegenerateHull(); return true; // query type FILTERED case 'c': case 'C': mQueryType = Query::QT_FILTERED; strcpy(mHeader, "query type = FILTERED"); RegenerateHull(); return true; case 'w': case 'W': mWireState->Enabled = !mWireState->Enabled; return true; // Read the notes in ConvexHul3D.h about how to use mLimitedQuantity. case '+': case '=': if (mLimitedQuantity < mNumVertices) { for (int i = 2; i < mLimitedQuantity + 2; ++i) { mTrnNode->DetachChildAt(i); } ++mLimitedQuantity; CreateHull(); } return true; case '-': case '_': if (mLimitedQuantity > 3) { for (int i = 2; i < mLimitedQuantity + 2; ++i) { mTrnNode->DetachChildAt(i); } --mLimitedQuantity; CreateHull(); } return true; } return WindowApplication::OnKeyDown(key, x, y); }
//---------------------------------------------------------------------------- bool ConvexHull2D::OnKeyDown (unsigned char key, int x, int y) { if (WindowApplication2::OnKeyDown(key, x, y)) { return true; } switch (key) { // Generate points that are nearly the same point. case '0': GenerateHull0D(); OnDisplay(); return true; // Generate points that are nearly collinear. case '1': GenerateHull1D(); OnDisplay(); return true; // Generate points that have a convex polygon hull. case '2': GenerateHull2D(); OnDisplay(); return true; // Lots of collinear points that lead to a convex polygon hull. case 'l': case 'L': GenerateHullManyCollinear(); OnDisplay(); return true; // query type INT64 case 'n': case 'N': mQueryType = Query::QT_INT64; RegenerateHull(); OnDisplay(); return true; // query type INTEGER case 'i': case 'I': mQueryType = Query::QT_INTEGER; RegenerateHull(); OnDisplay(); return true; // query type RATIONAL case 'r': case 'R': mQueryType = Query::QT_RATIONAL; RegenerateHull(); OnDisplay(); return true; // query type REAL (float) case 'f': case 'F': mQueryType = Query::QT_REAL; RegenerateHull(); OnDisplay(); return true; // query type FILTERED case 'c': case 'C': mQueryType = Query::QT_FILTERED; RegenerateHull(); OnDisplay(); return true; } return false; }