void SupervoxelGeneratorRegionGrowing::recenterSupervoxels(const AppParameters ¶meters, const Video &v) { const UINT clusterMinSizeCutoff = 20; UINT teleportCount = 0; Vector<vec3i> seeds; for(Supervoxel &p : _supervoxels) { vec3i newSeed; if(p.voxels.size() < clusterMinSizeCutoff) { newSeed = vec3i(rand() % _dimensions.x, rand() % _dimensions.y, rand() % _dimensions.z); while(seeds.contains(newSeed)) newSeed = vec3i(rand() % _dimensions.x, rand() % _dimensions.y, rand() % _dimensions.z); teleportCount++; p.resetColor(v.frames[newSeed.z](newSeed.y, newSeed.x)); } else { newSeed = p.massCentroid(); p.computeColor(v); } p.reset(v, newSeed); seeds.pushBack(newSeed); } }
void StructuredVolume::getVolumeFromMemory() { //! Create the equivalent ISPC volume container and allocate memory for voxel data. createEquivalentISPC(); //! Get a pointer to the source voxel data. const Data *voxelData = getParamData("voxelData", NULL); exitOnCondition(voxelData == NULL, "no voxel data specified"); const uint8 *data = (const uint8 *) voxelData->data; //! The dimensions of the source voxel data and target volume must match. exitOnCondition(size_t(volumeDimensions.x) * volumeDimensions.y * volumeDimensions.z != voxelData->numItems, "unexpected source voxel data dimensions"); //! The source and target voxel types must match. exitOnCondition(getVoxelType() != voxelData->type, "unexpected source voxel type"); //! Size of a volume slice in bytes. size_t sliceSizeInBytes = volumeDimensions.x * volumeDimensions.y * getVoxelSizeInBytes(); //! Copy voxel data into the volume in slices to avoid overflow in ISPC offset calculations. for (size_t z=0 ; z < volumeDimensions.z ; z++) setRegion(&data[z * sliceSizeInBytes], vec3i(0, 0, z), vec3i(volumeDimensions.x, volumeDimensions.y, 1)); }
/// Tesselate Mesh one time /// @param mesh The Mesh to tesselate /// @return The tesselated Mesh Mesh* _tesselate_mesh_once(Mesh* mesh) { auto tesselation = new Mesh(); // Set up the hashtable for adjacency auto adj = EdgeHashTable(mesh->triangle, mesh->quad); // Add vertices to the tessellation tesselation->pos = mesh->pos; // tesselation->norm = mesh->norm; // tesselation->texcoord = mesh->texcoord; // Add edge vertices to the tessellation int evo = tesselation->pos.size(); for(auto e : adj.edges) { tesselation->pos.push_back(mesh->pos[e.x]*0.5+mesh->pos[e.y]*0.5); // if(not tesselation->norm.empty()) tesselation->norm.push_back(normalize(mesh->norm[e.x]*0.5+mesh->norm[e.y]*0.5)); // if(not tesselation->texcoord.empty()) tesselation->texcoord.push_back(mesh->texcoord[e.x]*0.5+mesh->texcoord[e.y]*0.5); } // Add face vertices to the tessellation int fvo = tesselation->pos.size(); for(auto f : mesh->quad) { tesselation->pos.push_back(mesh->pos[f.x]*0.25+mesh->pos[f.y]*0.25+mesh->pos[f.z]*0.25+mesh->pos[f.w]*0.25); // if(not tesselation->texcoord.empty()) tesselation->texcoord.push_back(mesh->texcoord[f.x]*0.25+mesh->texcoord[f.y]*0.25+mesh->texcoord[f.z]*0.25+mesh->texcoord[f.w]*0.25); } // Add triangles to the tessellation for(auto f : mesh->triangle) { auto ve = vec3i(adj.edge(f.x, f.y),adj.edge(f.y, f.z),adj.edge(f.z, f.x))+vec3i(evo,evo,evo); tesselation->triangle.push_back(vec3i(f.x,ve.x,ve.z)); tesselation->triangle.push_back(vec3i(f.y,ve.y,ve.x)); tesselation->triangle.push_back(vec3i(f.z,ve.z,ve.y)); tesselation->triangle.push_back(ve); } // Add quads to the tessellation for(int fid = 0; fid < mesh->quad.size(); fid ++) { auto f = mesh->quad[fid]; auto ve = vec4i(adj.edge(f.x, f.y),adj.edge(f.y, f.z),adj.edge(f.z, f.w),adj.edge(f.w, f.x))+vec4i(evo,evo,evo,evo); auto vf = fid+fvo; tesselation->quad.push_back(vec4i(f.x,ve.x,vf,ve.w)); tesselation->quad.push_back(vec4i(f.y,ve.y,vf,ve.x)); tesselation->quad.push_back(vec4i(f.z,ve.z,vf,ve.y)); tesselation->quad.push_back(vec4i(f.w,ve.w,vf,ve.z)); } // Add lines to the tessellation if(mesh->_tesselation_lines.size() > 0) { for(auto l : mesh->_tesselation_lines) { int ve = adj.edge(l.x, l.y)+evo; tesselation->_tesselation_lines.push_back(vec2i(l.x,ve)); tesselation->_tesselation_lines.push_back(vec2i(ve,l.y)); } } return tesselation; }
QPair<int, int> Mesh::outLayers() const { QPair<int, int> out_layers = { 0, 0 }; QPair<int, int> out_layers_price = { Int::max(), Int::min() }; // вспомогательная переменная, оценивает можность слоя for (int i = 0; i < layers_.size(); ++i) { auto layer = layers_[i]; if (layer.second - layer.first < 3) continue; auto f = vec3i(vert(layer.first)).to<double>(); auto s = vec3i(vert(layer.first + 1)).to<double>(); auto ray_start = layerCenter(layer); if (f.dist(ray_start) < 2.5 && f.dist(s) < 2.5 && s.dist(ray_start) < 2.5) { // то это слой, в котором точки практически слиты в одну continue; } Plane<double> plane(f, s, ray_start); vec3d ray_normal = plane.normal().normalize(); int counter[2] = { 0, 0 }; // сколько плоскостей пересекает нормаль и инверированная нормаль текущего слоя for (auto other : layers_) { if (other == layer) continue; if (other.second - other.first < 3) continue; auto f = vec3i(vert(other.first)).to<double>(); auto s = vec3i(vert(other.first + 1)).to<double>(); auto t = layerCenter(other); if (f.dist(t) < 2.5 && f.dist(s) < 2.5 && s.dist(t) < 2.5) { continue; // очень `плотный` слой } Plane<double> other_plane(f, s, t); if (other_plane.intersect(ray_start, ray_normal)) counter[0] += 1; if (other_plane.intersect(ray_start, ray_normal * -1.0)) counter[1] += 1; } int price = counter[0] - counter[1]; if (price < out_layers_price.first) { out_layers_price.first = price; out_layers.first = i; } if (price > out_layers_price.second) { out_layers_price.second = price; out_layers.second = i; } } if (layerCenter(layers_[out_layers.first]).y > layerCenter(layers_[out_layers.second]).y) { std::swap(out_layers.first, out_layers.second); } return out_layers; }
void TestInterpolation<T>::testCollectInterpolants() { USING_NK_NS USING_NKHIVE_NS // construct volume T default_val(1); vec3d res(1.0); vec3d kernel_offset(0.5); typename Volume<T>::shared_ptr volume( new Volume<T>(1, 2, default_val, res, kernel_offset)); // easy to track values i32 value=0; for (i32 z=0; z<4; ++z) { for (i32 y=0; y<4; ++y) { for (i32 x=0; x<4; ++x) { volume->set(x,y,z,value++); } } } vec3i min_indices(0,0,0); vec3i max_indices(3,3,3); CubicInterpolation<T> cubic_interp(volume); // test interior typename CubicInterpolation<T>::calc_type interpolants[64]; cubic_interp.collectInterpolants(min_indices, max_indices, interpolants); for (i32 i=0; i<64; ++i) { CPPUNIT_ASSERT(interpolants[i] == typename CubicInterpolation<T>::calc_type(i)); } // test boundary min_indices = vec3i(0,0,1); max_indices = vec3i(3,3,4); cubic_interp.collectInterpolants(min_indices, max_indices, interpolants); for (i32 i=0; i<48; ++i) { CPPUNIT_ASSERT(interpolants[i] == typename CubicInterpolation<T>::calc_type(i + 16)); } for (i32 i=0; i<16; ++i) { CPPUNIT_ASSERT(interpolants[i + 48] == typename CubicInterpolation<T>::calc_type(1)); } }
/*! initialize an internal brick representation from input brickinfo and corresponding input data pointer */ AMRData::Brick::Brick(const BrickInfo &info, const float *data) { this->box = info.box; this->level = info.level; this->cellWidth = info.cellWidth; this->value = data; this->dims = this->box.size() + vec3i(1); this->gridToWorldScale = 1.f/this->cellWidth; this->worldBounds = box3f(vec3f(this->box.lower) * this->cellWidth, vec3f(this->box.upper+vec3i(1)) * this->cellWidth); this->worldToGridScale = rcp(this->worldBounds.size()); this->f_dims = vec3f(this->dims); }
vec3i Material::getParam(const char *name, vec3i defaultVal) { ParamMap::iterator it = params.find(name); if (it != params.end()) { assert( it->second->type == Param::INT_3 && "Param type mismatch" ); return vec3i(it->second->i[0], it->second->i[1], it->second->i[2]); } return defaultVal; }
void TestLocalXform::test() { USING_NK_NS USING_NKHIVE_NS LocalXform xform; CPPUNIT_ASSERT(xform.res() == vec3d(1, 1, 1)); LocalXform xform2(vec3d(1, 2, 3)); CPPUNIT_ASSERT(xform2.res() == vec3d(1,2,3)); CPPUNIT_ASSERT(xform.voxelToIndex(vec3d(1.1, 2.5, 3.8)) == vec3i(1, 2, 3)); CPPUNIT_ASSERT(xform.indexToVoxel(vec3i(1, 2, 3)) == vec3d(1, 2, 3)); CPPUNIT_ASSERT( xform.voxelToIndex(vec3d(-0.2, -1.1, -0.8)) == vec3i(-1, -2, -1)); }
void OSPObjectFile::importAttributeInteger3(const tinyxml2::XMLNode *node, OSPObject parent) { //! The attribute value is encoded in a string. const char *text = node->ToElement()->GetText(); vec3i value = vec3i(0); char guard[8]; //! Get the attribute value. exitOnCondition(sscanf(text, "%d %d %d %7s", &value.x, &value.y, &value.z, guard) != 3, "malformed XML element '" + std::string(node->ToElement()->Name()) + "'"); //! Set the attribute on the parent object. ospSetVec3i(parent, node->ToElement()->Name(), value); }
ISBI2012( std::string const & fname, vec3i const & sz, vec3i const & in_sz, vec3i const & out_sz) : size_(sz) , in_sz_(in_sz) , out_sz_(out_sz) { image = load<double, real>(fname + ".image", sz); label = load<double, real>(fname + ".label", sz); half_in_sz_ = in_sz_/vec3i(2,2,2); half_out_sz_ = out_sz_/vec3i(2,2,2); // margin consideration for even-sized input margin_sz_ = half_in_sz_; if ( in_sz_[0] % 2 == 0 ) --(margin_sz_[0]); if ( in_sz_[1] % 2 == 0 ) --(margin_sz_[1]); if ( in_sz_[2] % 2 == 0 ) --(margin_sz_[2]); set_sz_ = size_ - margin_sz_ - half_in_sz_; }
std::pair<cube_p<real>, cube_p<real>> get_sample() { vec3i loc = vec3i( half_in_sz_[0] + (rand() % set_sz_[0]), half_in_sz_[1] + (rand() % set_sz_[1]), half_in_sz_[2] + (rand() % set_sz_[2])); std::pair<cube_p<real>,cube_p<real>> ret; ret.first = crop(*image, loc - half_in_sz_, in_sz_); ret.second = crop(*label, loc - half_out_sz_, out_sz_); return ret; }
TriangleMesh* _tesselate_trianglemesh_once(TriangleMesh* mesh) { auto tesselation = new TriangleMesh(); // adjacency auto adj = EdgeHashTable(mesh->triangle,vector<vec4i>()); // add vertices tesselation->pos = mesh->pos; tesselation->norm = mesh->norm; tesselation->texcoord = mesh->texcoord; // add edge vertices int evo = tesselation->pos.size(); for(auto e : adj.edges) { tesselation->pos.push_back(mesh->pos[e.x]*0.5+mesh->pos[e.y]*0.5); if(not tesselation->norm.empty()) tesselation->norm.push_back(normalize(mesh->norm[e.x]*0.5+mesh->norm[e.y]*0.5)); if(not tesselation->texcoord.empty()) tesselation->texcoord.push_back(mesh->texcoord[e.x]*0.5+mesh->texcoord[e.y]*0.5); } // add triangles for(auto f : mesh->triangle) { auto ve = vec3i(adj.edge(f.x, f.y),adj.edge(f.y, f.z),adj.edge(f.z, f.x))+vec3i(evo,evo,evo); tesselation->triangle.push_back(vec3i(f.x,ve.x,ve.z)); tesselation->triangle.push_back(vec3i(f.y,ve.y,ve.x)); tesselation->triangle.push_back(vec3i(f.z,ve.z,ve.y)); tesselation->triangle.push_back(ve); } // add lines if(mesh->_tesselation_lines.size() > 0) { for(auto l : mesh->_tesselation_lines) { int ve = adj.edge(l.x, l.y)+evo; tesselation->_tesselation_lines.push_back(vec2i(l.x,ve)); tesselation->_tesselation_lines.push_back(vec2i(ve,l.y)); } } return tesselation; }
void SupervoxelGeneratorRegionGrowing::initializeSupervoxels(const AppParameters ¶meters, const Video &v) { Vector<vec3i> seeds; for(Supervoxel &p : _supervoxels) { vec3i randomSeed(rand() % _dimensions.x, rand() % _dimensions.y, rand() % _dimensions.z); while(seeds.contains(randomSeed)) randomSeed = vec3i(rand() % _dimensions.x, rand() % _dimensions.y, rand() % _dimensions.z); p.resetColor(v.frames[randomSeed.z](randomSeed.y, randomSeed.x)); p.reset(v, randomSeed); seeds.pushBack(randomSeed); } }
void VoxelGrid::integrate(const mat4f& intrinsic, const mat4f& cameraToWorld, const DepthImage32& depthImage, const BaseImage<unsigned short>& semantics) { const mat4f worldToCamera = cameraToWorld.getInverse(); BoundingBox3<int> voxelBounds = computeFrustumBounds(intrinsic, cameraToWorld, depthImage.getWidth(), depthImage.getHeight()); for (int k = voxelBounds.getMinZ(); k <= voxelBounds.getMaxZ(); k++) { for (int j = voxelBounds.getMinY(); j <= voxelBounds.getMaxY(); j++) { for (int i = voxelBounds.getMinX(); i <= voxelBounds.getMaxX(); i++) { //transform to current frame vec3f p = worldToCamera * voxelToWorld(vec3i(i, j, k)); //project into depth image p = skeletonToDepth(intrinsic, p); vec3i pi = math::round(p); if (pi.x >= 0 && pi.y >= 0 && pi.x < (int)depthImage.getWidth() && pi.y < (int)depthImage.getHeight()) { const float d = depthImage(pi.x, pi.y); const unsigned short sem = semantics(pi.x, pi.y); //check for a valid depth range if (d != depthImage.getInvalidValue() && d >= m_depthMin && d <= m_depthMax) { //update free space counter if voxel is in front of observation if (p.z < d) { (*this)(i, j, k).freeCtr++; } //compute signed distance; positive in front of the observation float sdf = d - p.z; float truncation = getTruncation(d); if (sdf > -truncation) { Voxel& v = (*this)(i, j, k); if (std::abs(sdf) <= std::abs(v.sdf)) { if (sdf >= 0.0f || v.sdf <= 0.0f) { v.sdf = sdf; v.color[0] = sem & 0xff; //ushort to vec2uc v.color[1] = (sem >> 8) & 0xff; v.weight = 1; } } //std::cout << "v: " << v.sdf << " " << (int)v.weight << std::endl; } } } } }
Metadata::Metadata(const string &fpath) { ifstream meta(fpath.c_str()); if (!meta) { std::cout << "cannot read meta file: " << fpath << std::endl; exit(EXIT_FAILURE); } std::string line; while (getline(meta, line)) { size_t pos = line.find('='); if (pos == line.npos) { continue; } std::string value = util::trim(line.substr(pos+1)); if (line.find("start") != line.npos) { start_ = atoi(value.c_str()); } else if (line.find("end") != line.npos) { end_ = atoi(value.c_str()); } else { // remove leading & trailing chars () or "" value = value.substr(1, value.size()-2); if (line.find("prefix") != line.npos) { prefix_ = value; } else if (line.find("suffix") != line.npos) { suffix_ = value; } else if (line.find("path") != line.npos) { path_ = value; } else if (line.find("tfPath") != line.npos) { tfPath_ = value; } else if (line.find("timeFormat") != line.npos) { timeFormat_ = value; } else if (line.find("volumeDim") != line.npos) { std::vector<int> dim; size_t pos = 0; while ((pos = value.find(',')) != value.npos) { dim.push_back(atoi(util::trim(value.substr(0, pos)).c_str())); value.erase(0, pos+1); } dim.push_back(atoi(util::trim(value).c_str())); if (dim.size() != 3) { std::cout << "incorrect volumeDim format" << std::endl; exit(EXIT_FAILURE); } volumeDim_ = vec3i(dim[0], dim[1], dim[2]); } } } }
void UpdateRiversTask::getTilesToUpdate(TerrainInfo &terrain, ptr<TerrainQuad> q) { if (q->visible == SceneManager::INVISIBLE) { return; } if (q->isLeaf() == false) { getTilesToUpdate(terrain, q->children[0]); getTilesToUpdate(terrain, q->children[1]); getTilesToUpdate(terrain, q->children[2]); getTilesToUpdate(terrain, q->children[3]); return; } vec3i v = vec3i(q->level, q->tx, q->ty); vec3f f = vec3f(q->ox, q->oy, q->l); terrain.displayedTiles.push_back(make_pair(v, f)); }
void GhostBlockBrickedVolume::createEquivalentISPC() { // Get the voxel type. voxelType = getParamString("voxelType", "unspecified"); exitOnCondition(getVoxelType() == OSP_UNKNOWN, "unrecognized voxel type (must be set before calling " "ospSetRegion())"); // Get the volume dimensions. this->dimensions = getParam3i("dimensions", vec3i(0)); exitOnCondition(reduce_min(this->dimensions) <= 0, "invalid volume dimensions (must be set before calling " "ospSetRegion())"); // Create an ISPC GhostBlockBrickedVolume object and assign type-specific // function pointers. ispcEquivalent = ispc::GBBV_createInstance(this, (int)getVoxelType(), (const ispc::vec3i &)this->dimensions); }
void forward( cube<real>& in, cube<complex>& out ) { ZI_ASSERT(size(out)==fft_complex_size(in)); ZI_ASSERT(size(in)==sz); fft_plan plan = fft_plans.get_forward( vec3i(in.shape()[0],in.shape()[1],in.shape()[2])); MKL_LONG status; # ifdef MEASURE_FFT_RUNTIME zi::wall_timer wt; # endif status = DftiComputeForward(*plan, reinterpret_cast<real*>(in.data()), reinterpret_cast<real*>(out.data())); # ifdef MEASURE_FFT_RUNTIME fft_stats.add(wt.elapsed<real>()); # endif }
void BlockBrickedVolume::createEquivalentISPC() { //! Get the voxel type. voxelType = getParamString("voxelType", "unspecified"); exitOnCondition(getVoxelType() == OSP_UNKNOWN, "unrecognized voxel type"); //! Create an ISPC BlockBrickedVolume object and assign type-specific function pointers. ispcEquivalent = ispc::BlockBrickedVolume_createInstance((int) getVoxelType()); //! Get the volume dimensions. volumeDimensions = getParam3i("dimensions", vec3i(0)); exitOnCondition(reduce_min(volumeDimensions) <= 0, "invalid volume dimensions"); //! Get the transfer function. transferFunction = (TransferFunction *) getParamObject("transferFunction", NULL); exitOnCondition(transferFunction == NULL, "no transfer function specified"); //! Get the value range. //! Voxel range not used for now. // vec2f voxelRange = getParam2f("voxelRange", vec2f(0.0f)); exitOnCondition(voxelRange == vec2f(0.0f), "no voxel range specified"); //! Get the gamma correction coefficient and exponent. vec2f gammaCorrection = getParam2f("gammaCorrection", vec2f(1.0f)); //! Set the volume dimensions. ispc::BlockBrickedVolume_setVolumeDimensions(ispcEquivalent, (const ispc::vec3i &) volumeDimensions); //! Set the value range (must occur before setting the transfer function). //ispc::BlockBrickedVolume_setValueRange(ispcEquivalent, (const ispc::vec2f &) voxelRange); //! Set the transfer function. ispc::BlockBrickedVolume_setTransferFunction(ispcEquivalent, transferFunction->getEquivalentISPC()); //! Set the recommended sampling rate for ray casting based renderers. ispc::BlockBrickedVolume_setSamplingRate(ispcEquivalent, getParam1f("samplingRate", 1.0f)); //! Set the gamma correction coefficient and exponent. ispc::BlockBrickedVolume_setGammaCorrection(ispcEquivalent, (const ispc::vec2f &) gammaCorrection); //! Allocate memory for the voxel data in the ISPC object. ispc::BlockBrickedVolume_allocateMemory(ispcEquivalent); }
static void backward( cube<complex>& in, cube<real>& out ) { ZI_ASSERT(in.shape()[0]==out.shape()[0]); ZI_ASSERT(in.shape()[1]==out.shape()[1]); ZI_ASSERT((out.shape()[2]/2+1)==in.shape()[2]); fft_plan plan = fft_plans.get_backward( vec3i(out.shape()[0],out.shape()[1],out.shape()[2])); MKL_LONG status; # ifdef MEASURE_FFT_RUNTIME zi::wall_timer wt; # endif status = DftiComputeBackward(*plan, reinterpret_cast<real*>(in.data()), reinterpret_cast<real*>(out.data())); # ifdef MEASURE_FFT_RUNTIME fft_stats.add(wt.elapsed<real>()); # endif }
void loadVTKFile(const FileName &fileName) { vtkDataSet *dataSet = readVTKFile<TReader>(fileName); int numberOfCells = dataSet->GetNumberOfCells(); int numberOfPoints = dataSet->GetNumberOfPoints(); double point[3]; for (int i = 0; i < numberOfPoints; i++) { dataSet->GetPoint(i, point); vertices->push_back(vec3f(point[0], point[1], point[2])); } for (int i = 0; i < numberOfCells; i++) { vtkCell *cell = dataSet->GetCell(i); if (cell->GetCellType() == VTK_TRIANGLE) { indices->push_back(vec3i(cell->GetPointId(0), cell->GetPointId(1), cell->GetPointId(2))); } } }
KdTreeText1 () { // build scene data list<SLCNode*> nodes; SLCSceneNode scene ("test_scene"); SLCMaterial* mat_layer = new SLCMaterial ("layer_material"); mat_layer->foreground_color = vec3i(155, 0, 0); mat_layer->background_color = vec3i(0, 0, 155); mat_layer->linetype = 0xFFFF;//SLCMaterial::LINETYPE_SOLID; mat_layer->linewidth = 0; SLCMaterial* mat = new SLCMaterial ( "mat" ); mat->foreground_color = vec3i(55, 0, 0); mat->background_color = vec3i(0, 44, 155); mat->linetype = 0xFFFF;//SLCMaterial::LINETYPE_DASH; mat->linewidth = 1; mat->fontfilename = "simsun.ttc"; SLCLayerNode* layer = new SLCLayerNode ( "layer1", mat_layer ); SLCLODNode* lod = new SLCLODNode(); SLCLODPageNode* lodpage = new SLCLODPageNode(); lodpage->delayloading = false; lodpage->imposter = true; SLCTextNode* txt = new SLCTextNode ( mat ); txt->text = "china"; txt->pos.xy ( 0, 0 ); SLCLODPageNode* lodpage2 = new SLCLODPageNode(); lodpage2->delayloading = true; lodpage2->imposter = false; scene.addChild ( mat_layer ); scene.addChild ( mat ); scene.addChild ( layer ); layer->addChild ( lod ); lod->addChild ( lodpage ); lod->addChild ( lodpage2 ); lodpage->addChild ( txt ); nodes.push_back ( mat_layer ); nodes.push_back ( mat ); nodes.push_back ( layer ); nodes.push_back ( lod ); nodes.push_back ( lodpage ); nodes.push_back ( txt ); nodes.push_back ( lodpage2 ); node2lc = new SLCNode2LC ( &scene ); _lc = node2lc->generateLC (); for ( list<SLCNode*>::iterator pp=nodes.begin(); pp!=nodes.end(); ++pp ) delete *pp; // update bbox BBox2dUpdater::forward_update ( *_lc ); // lc2kdtree KdTree<int> tmpkdt; LC2KDT::collectPrimitive ( _lc->getType(), _lc->getGIndex(), tmpkdt ); LC2KDT::traverse ( *_lc, tmpkdt ); // buildKdTree GetPrimitiveCenter getPrimitiveCenter; GetPrimitiveMinMax getPrimitiveMinMax; getPrimitiveCenter.init ( _lc ); getPrimitiveMinMax.init ( _lc ); option.targetnumperleaf = 1; option.maxlevel = 32; option.getPrimitiveCenter = getPrimitiveCenter; option.getPrimitiveMinMax = getPrimitiveMinMax; _buildkdt = new BuildLCKdTree ( tmpkdt, option ); _buildkdt->build (); tmpkdt.save ( "test.idx" ); _kdt = new KdTree<int>(); _kdt->load ( "test.idx" ); }
ion::Scene::CSimpleMesh * MarchingCubes(SMarchingCubesVolume & Volume) { CalculateGradient(Volume); ion::Scene::CSimpleMesh * Mesh = new ion::Scene::CSimpleMesh(); int CurrentBuffer = 0; Mesh->Vertices.reserve(1 << 14); Mesh->Triangles.reserve(1 << 11); ion::Scene::CSimpleMesh::SVertex Vertices[12]; vec3i VertexIndices[8] = { vec3i(0, 0, 0), vec3i(1, 0, 0), vec3i(1, 0, 1), vec3i(0, 0, 1), vec3i(0, 1, 0), vec3i(1, 1, 0), vec3i(1, 1, 1), vec3i(0, 1, 1), }; for (s32 z = 0; z < Volume.Dimensions.Z - 1; ++ z) for (s32 y = 0; y < Volume.Dimensions.Y - 1; ++ y) for (s32 x = 0; x < Volume.Dimensions.X - 1; ++ x) { int Lookup = 0; if ((Volume.Get(vec3i(x, y, z) + VertexIndices[0]).Value <= 0)) Lookup |= 1; if ((Volume.Get(vec3i(x, y, z) + VertexIndices[1]).Value <= 0)) Lookup |= 2; if ((Volume.Get(vec3i(x, y, z) + VertexIndices[2]).Value <= 0)) Lookup |= 4; if ((Volume.Get(vec3i(x, y, z) + VertexIndices[3]).Value <= 0)) Lookup |= 8; if ((Volume.Get(vec3i(x, y, z) + VertexIndices[4]).Value <= 0)) Lookup |= 16; if ((Volume.Get(vec3i(x, y, z) + VertexIndices[5]).Value <= 0)) Lookup |= 32; if ((Volume.Get(vec3i(x, y, z) + VertexIndices[6]).Value <= 0)) Lookup |= 64; if ((Volume.Get(vec3i(x, y, z) + VertexIndices[7]).Value <= 0)) Lookup |= 128; auto Interpolate = [&](vec3i const & v1, vec3i const & v2) -> ion::Scene::CSimpleMesh::SVertex { //static CColorTable ColorTable; ion::Scene::CSimpleMesh::SVertex v; f32 const d1 = Volume.Get(v1).Value; f32 const d2 = Volume.Get(v2).Value; f32 ratio = d1 / (d2 - d1); if (ratio <= 0.f) ratio += 1.f; v.Position = vec3f(v1) * (ratio) + vec3f(v2) * (1.f - ratio); //v.Color = ColorTable.Get( // Volume.Get(v1x, v1y, v1z).Color * (ratio) + // Volume.Get(v2x, v2y, v2z).Color * (1.f - ratio)); v.Normal = Normalize(Volume.Get(v1).Gradient) * (ratio) + Normalize(Volume.Get(v2).Gradient) * (1.f - ratio); //f32 const valp1 = Volume.Get(v1).Value; //f32 const valp2 = Volume.Get(v2).Value; //vec3f p1 = vec3f(v1); //vec3f p2 = vec3f(v2); //float mu; //if (abs(0 - valp1) < 0.00001) // return(p1); //if (abs(0 - valp2) < 0.00001) // return(p2); //if (abs(valp1 - valp2) < 0.00001) // return(p1); //mu = (0 - valp1) / (valp2 - valp1); //v.Position.X = p1.X + mu * (p2.X - p1.X); //v.Position.Y = p1.Y + mu * (p2.Y - p1.Y); //v.Position.Z = p1.Z + mu * (p2.Z - p1.Z); return v; }; u32 EdgeTableLookup = EdgeTable[Lookup]; if (EdgeTable[Lookup] != 0) { if (EdgeTable[Lookup] & 1) Vertices[0] = Interpolate(vec3i(x, y, z) + VertexIndices[0], vec3i(x, y, z) + VertexIndices[1]); if (EdgeTable[Lookup] & 2) Vertices[1] = Interpolate(vec3i(x, y, z) + VertexIndices[1], vec3i(x, y, z) + VertexIndices[2]); if (EdgeTable[Lookup] & 4) Vertices[2] = Interpolate(vec3i(x, y, z) + VertexIndices[2], vec3i(x, y, z) + VertexIndices[3]); if (EdgeTable[Lookup] & 8) Vertices[3] = Interpolate(vec3i(x, y, z) + VertexIndices[3], vec3i(x, y, z) + VertexIndices[0]); if (EdgeTable[Lookup] & 16) Vertices[4] = Interpolate(vec3i(x, y, z) + VertexIndices[4], vec3i(x, y, z) + VertexIndices[5]); if (EdgeTable[Lookup] & 32) Vertices[5] = Interpolate(vec3i(x, y, z) + VertexIndices[5], vec3i(x, y, z) + VertexIndices[6]); if (EdgeTable[Lookup] & 64) Vertices[6] = Interpolate(vec3i(x, y, z) + VertexIndices[6], vec3i(x, y, z) + VertexIndices[7]); if (EdgeTable[Lookup] & 128) Vertices[7] = Interpolate(vec3i(x, y, z) + VertexIndices[7], vec3i(x, y, z) + VertexIndices[4]); if (EdgeTable[Lookup] & 256) Vertices[8] = Interpolate(vec3i(x, y, z) + VertexIndices[0], vec3i(x, y, z) + VertexIndices[4]); if (EdgeTable[Lookup] & 512) Vertices[9] = Interpolate(vec3i(x, y, z) + VertexIndices[1], vec3i(x, y, z) + VertexIndices[5]); if (EdgeTable[Lookup] & 1024) Vertices[10] = Interpolate(vec3i(x, y, z) + VertexIndices[2], vec3i(x, y, z) + VertexIndices[6]); if (EdgeTable[Lookup] & 2048) Vertices[11] = Interpolate(vec3i(x, y, z) + VertexIndices[3], vec3i(x, y, z) + VertexIndices[7]); for (u32 i = 0; TriTable[Lookup][i] != -1; i += 3) { for (u32 j = i; j < (i+3); ++ j) Mesh->Vertices.push_back(Vertices[TriTable[Lookup][j]]); ion::Scene::CSimpleMesh::STriangle Tri; Tri.Indices[0] = (uint) Mesh->Vertices.size() - 3; Tri.Indices[1] = (uint) Mesh->Vertices.size() - 2; Tri.Indices[2] = (uint) Mesh->Vertices.size() - 1; Mesh->Triangles.push_back(Tri); } } } return Mesh; }
INLINE pair<vec3i,int> getedge(const vec3i &start, const vec3i &end) { const auto lower = select(le(start,end), start, end); const auto delta = select(eq(start,end), vec3i(zero), vec3i(one)); assert(reduceadd(delta) == 1); return makepair(lower, delta.y+2*delta.z); }
static std::shared_ptr<cube<T>> get( size_t x, size_t y, size_t z ) { return instance.get( vec3i(x,y,z) ); }
void meshsurf3::buildSurface( std::vector<vec3d> &vertices, std::vector<vec3d> &normals, std::vector<vec3i> &faces, const levelset3 *fluid, const levelset3 *solid, bool enclose, FLOAT64 dpx, uint iteration, bool doFit ) { // Save a reference to the mesher const mesher3 &g = *this->g; tick(); dump("Computing levelset for %d nodes...", g.nodes.size()); values.clear(); values.resize(g.nodes.size()); if( values.empty() ) { email::print("Mesher Uninitialized !\n"); email::send(); exit(0); } // Compute levelset for each node PARALLEL_FOR for( uint n=0; n<g.nodes.size(); n++ ) { FLOAT64 phi = fluid->evalLevelset(g.nodes[n]); if( enclose ) phi = fmax(phi,-dpx-solid->evalLevelset(g.nodes[n])); values[n] = phi; } dump("Done. Took %s.\n",stock("meshsurf_levelset_sample")); // Fill holes fillHoles(values,solid,g.nodes,g.elements,g.node2node,fluid->dx); // Calculate intersections on edges tick(); dump("Computing cut edges for each tet..."); std::vector<vec3d> cutpoints(g.edges.size()); std::vector<int> cutIndices(g.edges.size()); uint index = 0; for( int n=0; n<g.edges.size(); n++ ) { FLOAT64 levelsets[2]; for( uint m=0; m<2; m++ ) levelsets[m] = values[g.edges[n][m]]; if( copysign(1.0,levelsets[0]) * copysign(1.0,levelsets[1]) <= 0 ) { FLOAT64 det = levelsets[0]-levelsets[1]; if( fabs(det) < 1e-16 ) det = copysign(1e-16,det); FLOAT64 a = fmin(0.99,fmax(0.01,levelsets[0]/det)); vec3d p = (1.0-a)*g.nodes[g.edges[n][0]]+a*g.nodes[g.edges[n][1]]; cutpoints[n] = p; cutIndices[n] = index++; } else { cutIndices[n] = -1; } } // Copy them to packed array vertices.clear(); vertices.resize(index); index = 0; for( uint n=0; n<cutIndices.size(); n++ ) { if( cutIndices[n] >= 0 ) vertices[index++] = cutpoints[n]; } dump("Done. Took %s.\n",stock()); // Stitch faces (marching tet) tick(); dump("Stitching edges..."); std::vector<std::vector<uint> > node_faces; node_faces.resize(g.nodes.size()); faces.clear(); for( uint n=0; n<g.elements.size(); n++ ) { std::vector<uint> nv; for( uint m=0; m<g.element_edges[n].size(); m++ ) { uint idx = g.element_edges[n][m]; if( cutIndices[idx] >= 0 ) { nv.push_back(cutIndices[idx]); } } if( nv.size() == 4 ) { // Triangulate the veritces int idx0 = -1; int idx1 = -1; for( uint m=0; m<g.element_edges[n].size(); m++ ) { if( cutIndices[g.element_edges[n][m]] >= 0 ) { idx0 = g.element_edges[n][m]; break; } } // If found one intersection edge if( idx0 >= 0 ) { for( uint m=0; m<g.element_edges[n].size(); m++ ) { uint opID = g.element_edges[n][m]; if( cutIndices[opID] >= 0 && isOpEdge(idx0,opID)) { idx1 = opID; break; } } // If found opposite intersection edge if( idx1 >= 0 ) { vec3i v; v[0] = cutIndices[idx0]; v[1] = cutIndices[idx1]; for( uint m=0; m<g.element_edges[n].size(); m++ ) { uint idx2 = g.element_edges[n][m]; if( cutIndices[idx2] >= 0 && idx2 != idx0 && idx2 != idx1 ) { v[2] = cutIndices[idx2]; faces.push_back(v); for( uint m=0; m<g.elements[n].size(); m++ ) { node_faces[g.elements[n][m]].push_back(faces.size()-1); } } } } else { dump( "Opposite edge was not found !\n"); exit(0); } } else { dump( "Ground edge was not found !\n"); exit(0); } } else if( nv.size() == 3 ) { faces.push_back(vec3i(nv[0],nv[1],nv[2])); for( uint m=0; m<g.elements[n].size(); m++ ) { node_faces[g.elements[n][m]].push_back(faces.size()-1); } } else if( nv.size() == 0 ) { // Empty surface. Do nothing... } else { dump( "\nBad stitch encounrtered: Element - edge count = %d.\n", g.element_edges[n].size() ); dump( "Unknown set found N(%e,%e,%e,%e) = %d.\n", values[g.elements[n][0]], values[g.elements[n][1]], values[g.elements[n][2]], values[g.elements[n][3]], nv.size()); for( uint k=0; k<g.element_edges[n].size(); k++ ) { uint vidx[2] = { g.edges[g.element_edges[n][k]][0], g.edges[g.element_edges[n][k]][1] }; dump( "Edge info[%d] = edge(%d,%d) = (%e,%e) = (%f,%f)\n", k, vidx[0], vidx[1], values[vidx[0]], values[vidx[1]], copysign(1.0,values[vidx[0]]), copysign(1.0,values[vidx[1]]) ); } } } dump("Done. Took %s.\n",stock("meshsurf_stitch_mesh")); // Find closest position tick(); dump("Finding closest surface position at surface tets..."); surfacePos.clear(); surfacePos.resize(g.nodes.size()); for( uint n=0; n<g.nodes.size(); n++ ) { FLOAT64 dist = 1e8; vec3d p = g.nodes[n]; for( uint m=0; m<node_faces[n].size(); m++ ) { vec3d p0 = vertices[faces[node_faces[n][m]][0]]; vec3d p1 = vertices[faces[node_faces[n][m]][1]]; vec3d p2 = vertices[faces[node_faces[n][m]][2]]; vec3d out = g.nodes[n]; vec3d src = out; FLOAT64 d = fmax(1e-8,point_triangle_distance(src,p0,p1,p2,out)); if( d < dist ) { p = out; dist = d; } } if( dist < 1.0 ) { values[n] = (values[n]>=0 ? 1.0 : -1.0) * dist; surfacePos[n].push_back(g.nodes[n]); surfacePos[n].push_back(p); } else { values[n] = (values[n]>=0 ? 1.0 : -1.0) * 1e8; } } dump("Done. Took %s.\n",stock("meshsurf_find_close_pos1")); if( extrapolate_dist ) { // Fast march tick(); std::vector<fastmarch3<FLOAT64>::node3 *> fnodes(g.nodes.size()); for( uint n=0; n<g.nodes.size(); n++ ) fnodes[n] = new fastmarch3<FLOAT64>::node3; for( uint n=0; n<g.nodes.size(); n++ ) { vec3d p = g.nodes[n]; bool fixed = fabs(values[n]) < 1.0; fnodes[n]->p = p; fnodes[n]->fixed = fixed; fnodes[n]->levelset = values[n]; fnodes[n]->value = 0.0; fnodes[n]->p2p.resize(g.node2node[n].size()); for( uint m=0; m<g.node2node[n].size(); m++ ) { fnodes[n]->p2p[m] = fnodes[g.node2node[n][m]]; } } fastmarch3<FLOAT64>::fastMarch(fnodes,extrapolate_dist,-extrapolate_dist,1); // Pick up values for( uint n=0; n<g.nodes.size(); n++ ) { values[n] = fnodes[n]->levelset; delete fnodes[n]; } stock("meshsurf_fastmarch"); } // Compute normal tick(); dump("Computing normals..."); computeNormals(vertices,normals,faces,cutIndices); dump("Done. Took %s.\n",stock("meshsurf_normal")); // Flip facet rotation if necessary flipFacet(vertices,normals,faces,0.1*fluid->dx); #if 1 // Fit surface if( doFit ) { tick(); dump("Fitting %d surface vertices...", vertices.size() ); for( uint k=0; k<1; k++ ) { smoothMesh(vertices,normals,faces,solid,dpx,1); PARALLEL_FOR for( uint n=0; n<vertices.size(); n++ ) { vec3d out = vertices[n]; if( solid->evalLevelset(out) > dpx && fluid->getClosestSurfacePos(out) ) { vertices[n] = out; } } } dump("Done. Took %s.\n",stock("meshsurf_fit")); } #endif // Smooth mesh #if 1 tick(); dump("Smoothing faces..."); smoothMesh(vertices,normals,faces,solid,dpx,iteration); dump("Done. Took %s.\n",stock("meshsurf_smooth")); #endif // Find closest position again tick(); dump("Finding closest surface position at surface tets again..."); surfacePos.clear(); surfacePos.resize(g.nodes.size()); for( uint n=0; n<g.nodes.size(); n++ ) { FLOAT64 dist = 1e8; vec3d p = g.nodes[n]; for( uint m=0; m<node_faces[n].size(); m++ ) { vec3d p0 = vertices[faces[node_faces[n][m]][0]]; vec3d p1 = vertices[faces[node_faces[n][m]][1]]; vec3d p2 = vertices[faces[node_faces[n][m]][2]]; vec3d out = g.nodes[n]; vec3d src = out; FLOAT64 d = fmax(1e-8,point_triangle_distance(src,p0,p1,p2,out)); if( d < dist ) { p = out; dist = d; } } if( dist < 1.0 ) { values[n] = (values[n]>=0 ? 1.0 : -1.0) * dist; } } dump("Done. Took %s.\n",stock("meshsurf_find_close_pos2")); // Flip again flipFacet(vertices,normals,faces,0.1*fluid->dx); }
void TestInterpolation<T>::testGetIndexBounds() { USING_NK_NS USING_NKHIVE_NS // construct volume T default_val(1); vec3d res(1.0); vec3d kernel_offset(0.5); typename Volume<T>::shared_ptr volume( new Volume<T>(1, 2, default_val, res, kernel_offset)); // create interpolator CubicInterpolation<T> cubic_interp(volume); // test interior point on a cell boundary vec3d voxel_coords(2.0,2.0,2.0); vec3i voxel_indices(2,2,2); vec3i min_indices, max_indices; cubic_interp.getIndexBounds(voxel_coords, voxel_indices, min_indices, max_indices); CPPUNIT_ASSERT(min_indices == vec3i(0,0,0)); CPPUNIT_ASSERT(max_indices == vec3i(3,3,3)); // test interior point voxel_coords = vec3d(2.15,2.2,2.1); voxel_indices = vec3i(2,2,2); cubic_interp.getIndexBounds(voxel_coords, voxel_indices, min_indices, max_indices); CPPUNIT_ASSERT(min_indices == vec3i(0,0,0)); CPPUNIT_ASSERT(max_indices == vec3i(3,3,3)); // test interior point rounded up voxel_coords = vec3d(2.75,2.8,2.9); voxel_indices = vec3i(2,2,2); cubic_interp.getIndexBounds(voxel_coords, voxel_indices, min_indices, max_indices); CPPUNIT_ASSERT(min_indices == vec3i(1,1,1)); CPPUNIT_ASSERT(max_indices == vec3i(4,4,4)); // test an arbitrary point voxel_coords = vec3d(1.9,1.2,3.2); voxel_indices = vec3i(1,1,3); cubic_interp.getIndexBounds(voxel_coords, voxel_indices, min_indices, max_indices); CPPUNIT_ASSERT(min_indices == vec3i(0,-1,1)); CPPUNIT_ASSERT(max_indices == vec3i(3,2,4)); }
void TestLinAlg() { // Instantiate templates, check sizes, make sure operators compile etc. static_assert(sizeof(Vec2f) == 8 , "Vec2f size test failed" ); static_assert(sizeof(Vec3f) == 12 , "Vec3f size test failed" ); static_assert(sizeof(Vec4f) == 16 , "Vec4f size test failed" ); static_assert(sizeof(Vec2d) == 16 , "Vec2d size test failed" ); static_assert(sizeof(Vec3d) == 24 , "Vec3d size test failed" ); static_assert(sizeof(Vec4d) == 32 , "Vec4d size test failed" ); static_assert(sizeof(Vec2i) == 8 , "Vec2i size test failed" ); static_assert(sizeof(Vec3i) == 12 , "Vec3i size test failed" ); static_assert(sizeof(Vec4i) == 16 , "Vec4i size test failed" ); static_assert(sizeof(Vec2ui) == 8 , "Vec2ui size test failed" ); static_assert(sizeof(Vec3ui) == 12 , "Vec3ui size test failed" ); static_assert(sizeof(Vec4ui) == 16 , "Vec4ui size test failed" ); static_assert(sizeof(Matrix44f) == 64 , "Matrix44f size test failed"); static_assert(sizeof(Matrix44d) == 128, "Matrix44d size test failed"); Vec2f vec2f(0.0f, 0.0f); Vec3f vec3f(0.0f, 0.0f, 0.0f); Vec4f vec4f(0.0f, 0.0f, 0.0f, 0.0f); Vec2d vec2d(0.0, 0.0); Vec3d vec3d(0.0, 0.0, 0.0); Vec4d vec4d(0.0, 0.0, 0.0, 0.0); Vec2i vec2i(-1, -1); Vec3i vec3i(-1, -1, -1); Vec4i vec4i(-1, -1, -1, -1); Vec2ui vec2ui(0, 0); Vec3ui vec3ui(0, 0, 0); Vec4ui vec4ui(0, 0, 0, 0); float f = 0.0f; bool b = false; b = (vec3f == vec3f); b = (vec3f != vec3f); vec3f = Vec3f(1.0f) + Vec3f(2.0f); vec3f = Vec3f(1.0f) - Vec3f(2.0f); vec3f = Vec3f(1.0f) * Vec3f(2.0f); vec3f = Vec3f(1.0f) / Vec3f(2.0f); vec3f = Vec3f(1.0f) * f; vec3f = f * Vec3f(1.0f); vec3f = Vec3f(1.0f) / f; vec3f = -Vec3f(1.0f); vec3f += Vec3f(1.0f); vec3f -= Vec3f(1.0f); vec3f *= Vec3f(1.0f); vec3f /= Vec3f(1.0f); vec3f *= f; vec3f /= f; f = vec3f[0]; vec3f[0] = f; f = Length(vec3f); f = LengthSquared(vec3f); vec3f = Normalize(vec3f); f = Dot(Vec3f(1.0f), Vec3f(2.0f)); vec3f = Vec3f(1.0f) ^ Vec3f(2.0f); Matrix44f matf; matf.Identity(); Matrix44d matd; matf.RotationX(1); matf.RotationY(1); matf.RotationZ(1); matf.Scaling(1); b = matf == matf; matf = matf * matf; matf.BuildLookAtMatrix(Vec3f(0.0f, 10.0f, 10.0f), Vec3f(0.0f)); matf.BuildProjection(90.0f, 4.0f / 3.0f, 1.0f, 1000.0f); Vec3f out; matf.Transf3x3(vec3f, out); matf.Transf4x4(vec3f, out); matf.Transpose3x3(); matf.Transpose4x4(); matf.Invert(); }
void SupervoxelGeneratorRegionGrowing::extract(const AppParameters ¶meters, const Video &v, Vector<Supervoxel> &supervoxelsOut, Vector< Grid<UINT> > &assignmentsOut) { ComponentTimer timer( "segmenting video: " + Convert::toString(v.width) + "x" + Convert::toString(v.height) + ", " + Convert::toString(v.frames.size()) + " frames" ); _dimensions = vec3i(v.width, v.height, (int)v.frames.size()); _assignments.resize(v.frames.size()); for (UINT i = 0; i < v.frames.size(); i++) _assignments[i].allocate(_dimensions.y, _dimensions.x); _supervoxels.resize(parameters.supervoxelCount); initializeSupervoxels(parameters, v); const UINT vizFrameCount = Math::min(parameters.supervoxelVisualizationFrameCount, (UINT)v.frames.size()); auto vizHelper = [vizFrameCount](int iteration, int frameIndex, const std::string &descriptor) { std::string iterationDesc = "_i" + Convert::toString(iteration); if(iteration == -1) iterationDesc = "Final"; std::string frameDesc = "_f" + Convert::toString(frameIndex); if(vizFrameCount == 1) frameDesc = ""; return "supervoxel" + descriptor + iterationDesc + frameDesc + ".png"; }; for(UINT iterationIndex = 0; iterationIndex < parameters.regionGrowingIterations; iterationIndex++) { Console::log("starting supervoxel iteration " + Convert::toString(iterationIndex)); //ComponentTimer timer( "Iteration " + std::string(iterationIndex) ); growSupervoxels(parameters, v); if(parameters.visualizeIntermediateSupervoxels) { Video clusterVid0, clusterVid1; drawSupervoxelIDs(clusterVid0, 0, vizFrameCount); drawSupervoxelColors(v, clusterVid1, 0, vizFrameCount); for (UINT frameIndex = 0; frameIndex < vizFrameCount; frameIndex++) { LodePNG::save(clusterVid0.frames[frameIndex], vizHelper(iterationIndex, frameIndex, "Clusters")); LodePNG::save(clusterVid1.frames[frameIndex], vizHelper(iterationIndex, frameIndex, "Colors")); } } recenterSupervoxels(parameters, v); } growSupervoxels(parameters, v); for(Supervoxel &p : _supervoxels) p.computeColor(v); if(parameters.visualizeFinalSupervoxels) { Video clusterVid0, clusterVid1; drawSupervoxelIDs(clusterVid0, 0, vizFrameCount); drawSupervoxelColors(v, clusterVid1, 0, vizFrameCount); for (UINT frameIndex = 0; frameIndex < vizFrameCount; frameIndex++) { LodePNG::save(clusterVid0.frames[frameIndex], vizHelper(-1, frameIndex, "Clusters")); LodePNG::save(clusterVid1.frames[frameIndex], vizHelper(-1, frameIndex, "Colors")); } } supervoxelsOut = std::move(_supervoxels); assignmentsOut = std::move(_assignments); }
/// Apply subdivision surface rules on subdiv /// @param subdiv The mesh to subdivide /// @return The subdivided mesh Subdiv* _tesselate_subdiv_once(Subdiv* subdiv) { auto tesselation = new Subdiv(); // linear subdivision like triangle mesh // adjacency auto adj = EdgeHashTable(subdiv->triangle,subdiv->quad); // add vertices tesselation->pos = subdiv->pos; tesselation->texcoord = subdiv->texcoord; // add edge vertices int evo = tesselation->pos.size(); for(auto e : adj.edges) { tesselation->pos.push_back(subdiv->pos[e.x]*0.5+subdiv->pos[e.y]*0.5); if(not tesselation->texcoord.empty()) tesselation->texcoord.push_back(subdiv->texcoord[e.x]*0.5+subdiv->texcoord[e.y]*0.5); } // add face vertices int fvo = tesselation->pos.size(); for(auto f : subdiv->quad) { tesselation->pos.push_back(subdiv->pos[f.x]*0.25+subdiv->pos[f.y]*0.25+subdiv->pos[f.z]*0.25+subdiv->pos[f.w]*0.25); if(not tesselation->texcoord.empty()) tesselation->texcoord.push_back(subdiv->texcoord[f.x]*0.25+subdiv->texcoord[f.y]*0.25+subdiv->texcoord[f.z]*0.25+subdiv->texcoord[f.w]*0.25); } // add triangles for(auto f : subdiv->triangle) { auto ve = vec3i(adj.edge(f.x, f.y),adj.edge(f.y, f.z),adj.edge(f.z, f.x))+vec3i(evo,evo,evo); tesselation->triangle.push_back(vec3i(f.x,ve.x,ve.z)); tesselation->triangle.push_back(vec3i(f.y,ve.y,ve.x)); tesselation->triangle.push_back(vec3i(f.z,ve.z,ve.y)); tesselation->triangle.push_back(ve); } // add quads for(int fid = 0; fid < subdiv->quad.size(); fid ++) { auto f = subdiv->quad[fid]; auto ve = vec4i(adj.edge(f.x, f.y),adj.edge(f.y, f.z),adj.edge(f.z, f.w),adj.edge(f.w, f.x))+vec4i(evo,evo,evo,evo); auto vf = fid+fvo; tesselation->quad.push_back(vec4i(f.x,ve.x,vf,ve.w)); tesselation->quad.push_back(vec4i(f.y,ve.y,vf,ve.x)); tesselation->quad.push_back(vec4i(f.z,ve.z,vf,ve.y)); tesselation->quad.push_back(vec4i(f.w,ve.w,vf,ve.z)); } // creases tesselation->crease_vertex = subdiv->crease_vertex; for(auto e : subdiv->crease_edge) { tesselation->crease_edge.push_back({e.x,evo+adj.edge(e.x, e.y)}); tesselation->crease_edge.push_back({evo+adj.edge(e.x, e.y),e.y}); } // add lines if(subdiv->_tesselation_lines.size() > 0) { for(auto l : subdiv->_tesselation_lines) { int ve = adj.edge(l.x, l.y)+evo; tesselation->_tesselation_lines.push_back(vec2i(l.x,ve)); tesselation->_tesselation_lines.push_back(vec2i(ve,l.y)); } } // mark creases auto cvertex = vector<bool>(tesselation->pos.size(),false); auto cedge = vector<bool>(tesselation->pos.size(),false); for(auto vid : tesselation->crease_vertex) cvertex[vid] = true; for(auto e : tesselation->crease_edge) for(auto vid : e) cedge[vid] = true; // averaging auto npos = vector<vec3f>(tesselation->pos.size(),zero3f); auto ntexcoord = vector<vec2f>(tesselation->texcoord.size(),zero2f); auto weight = vector<float>(tesselation->pos.size(),0); auto nquad = vector<int>(tesselation->pos.size(),0); auto ntriangle = vector<int>(tesselation->pos.size(),0); for(auto f : tesselation->quad) { for(auto vid : f) { if(cedge[vid] or cvertex[vid]) continue; auto w = pi/2; npos[vid] += (tesselation->pos[f.x]+tesselation->pos[f.y]+tesselation->pos[f.z]+tesselation->pos[f.w])*w/4; if(not ntexcoord.empty()) ntexcoord[vid] += (tesselation->texcoord[f.x]+tesselation->texcoord[f.y]+tesselation->texcoord[f.z]+tesselation->texcoord[f.w])*w/4; weight[vid] += w; nquad[vid] ++; } } for(auto f : tesselation->triangle) { for(int i = 0; i < 3; i ++) { auto vid = f[i]; auto vid1 = f[(i+1)%3]; auto vid2 = f[(i+2)%3]; if(cedge[vid] or cvertex[vid]) continue; auto w = pi/3; npos[vid] += (tesselation->pos[vid]/4+tesselation->pos[vid1]*(3/8.0)+tesselation->pos[vid2]*(3/8.0))*w; if(not ntexcoord.empty()) ntexcoord[vid] += (tesselation->texcoord[vid]/4+tesselation->texcoord[vid1]*(3/8.0)+tesselation->texcoord[vid2]*(3/8.0))*w; weight[vid] += w; ntriangle[vid] ++; } } // handle creases for(auto e : tesselation->crease_edge) { for(auto vid : e) { if(cvertex[vid]) continue; npos[vid] += (tesselation->pos[e.x]+tesselation->pos[e.y])/2; if(not ntexcoord.empty()) ntexcoord[vid] += (tesselation->texcoord[vid]+tesselation->texcoord[vid])/2; weight[vid] += 1; } } for(auto vid : tesselation->crease_vertex) { npos[vid] += tesselation->pos[vid]; if(not ntexcoord.empty()) ntexcoord[vid] += tesselation->texcoord[vid]; weight[vid] += 1; } // normalization for(auto i : range(tesselation->pos.size())) { npos[i] /= weight[i]; if(not ntexcoord.empty()) ntexcoord[i] /= weight[i]; } // correction for(auto i : range(tesselation->pos.size())) { if(cedge[i] or cvertex[i]) continue; float w = 0; if(tesselation->quad.empty()) w = 5/3.0 - (8/3.0)*pow(3/8.0+1/4.0*cos(2*pi/ntriangle[i]),2); else if(tesselation->triangle.empty()) w = 4.0f / nquad[i]; else w = (nquad[i] == 0 and ntriangle[i] == 3) ? 1.5f : 12.0f / (3 * nquad[i] + 2 * ntriangle[i]); npos[i] = tesselation->pos[i] + (npos[i] - tesselation->pos[i])*w; if(not ntexcoord.empty()) ntexcoord[i] = tesselation->texcoord[i] + (ntexcoord[i] - tesselation->texcoord[i])*w; } // set tesselation back tesselation->pos = npos; tesselation->texcoord = ntexcoord; return tesselation; }