void SupervoxelGeneratorRegionGrowing::recenterSupervoxels(const AppParameters &parameters, 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);
	}
}
Example #2
0
  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;
}
Example #4
0
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;
}
Example #5
0
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));
    }
}
Example #6
0
    /*! 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);
    }
Example #7
0
    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;
    }
Example #8
0
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));
}
Example #9
0
  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);

  }
Example #10
0
    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_;
    }
Example #11
0
    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 &parameters, 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);
	}
}
Example #14
0
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;
						}
					}
				}

			}
		}
Example #15
0
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]);
            }
        }
    }
}
Example #16
0
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);
  }
Example #18
0
        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
        }
Example #19
0
  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);

  }
Example #20
0
    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
    }
Example #21
0
      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)));
          }
        }
      }
Example #22
0
    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" );
    }
Example #23
0
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;
}
Example #24
0
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) );
 }
Example #26
0
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);
}
Example #27
0
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 &parameters, 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;
}