CloudCompare源码分析_八叉树(Octree)算法基础CC中的八叉树结构

2023-05-16

官方参考地址:CloudCompare octree - CloudCompareWiki

CC的octree算法主要体现在DgmOctree.h和DgmOctree.cpp中,他采用了一种分级的结构,最大支持21级,如下,

static const int MAX_OCTREE_LEVEL = 21;

然后,会事先计算得到一个分级表,

预先计算好的数据表

CC这么做的原因是,把事先能计算好的数据先存储起来,用空间换时间的办法,来加速运算速度。

(1) PRE_COMPUTED_BIT_SHIFT_VALUES

//! Pre-computed bit shift values (one for each level)
struct BitShiftValues
{
    //! Default initialization
    BitShiftValues()
    {
        //we compute all possible values
        for (unsigned char level = 0; level <= DgmOctree::MAX_OCTREE_LEVEL; ++level)
        {
            values[level] = (3 * (DgmOctree::MAX_OCTREE_LEVEL - level));
        }
    }

    //! Values
    unsigned char values[DgmOctree::MAX_OCTREE_LEVEL+1];
};
static BitShiftValues PRE_COMPUTED_BIT_SHIFT_VALUES;

unsigned char DgmOctree::GET_BIT_SHIFT(unsigned char level)
{
    //return (3 * (DgmOctree::MAX_OCTREE_LEVEL - level));
    return PRE_COMPUTED_BIT_SHIFT_VALUES.values[level];
}

所以这个value实际相当于这样一个表,

[0]    63
[1]    60
[2]    57
[3]    54
[4]    51
[5]    48
[6]    45
[7]    42
[8]    39
[9]    36
[10]    33
[11]    30
[12]    27
[13]    24
[14]    21
[15]    18
[16]    15
[17]    12
[18]    9
[19]    6
[20]    3
[21]    0

(2) PRE_COMPUTED_POS_CODES

static const int MAX_OCTREE_LENGTH = (1 << MAX_OCTREE_LEVEL);

//! Pre-computed cell codes for all potential cell positions (along a unique dimension)
struct MonoDimensionalCellCodes
{
    //! Total number of positions/values
    /** There are 1024 possible values at level 10, and 2M. at level 21.
        \warning Never pass a 'constant initializer' by reference
    **/
    static const int VALUE_COUNT = DgmOctree::MAX_OCTREE_LENGTH;

    //! Default initialization
    MonoDimensionalCellCodes()
    {
        //we compute all possible values for cell codes
        //(along a unique dimension, the other ones are just shifted)
        for (int value = 0; value < VALUE_COUNT; ++value)
        {
            int mask = VALUE_COUNT;
            DgmOctree::CellCode code = 0;
            for (unsigned char k = 0; k < DgmOctree::MAX_OCTREE_LEVEL; k++)
            {
                mask >>= 1;
                code <<= 3;
                if (value & mask)
                {
                    code |= 1;
                }
            }
            values[value] = code;
        }

        //we compute all possible masks as well! (all dimensions)
        //DgmOctree::CellCode baseMask = (1 << (3 * DgmOctree::MAX_OCTREE_LEVEL));
        //for (int level = DgmOctree::MAX_OCTREE_LEVEL; level >= 0; --level)
        //{
        //    masks[level] = baseMask - 1;
        //    baseMask >>= 3;
        //}
    }

    //! Mono-dimensional cell codes
    DgmOctree::CellCode values[VALUE_COUNT];

    //! Mono-dimensional cell masks
    //DgmOctree::CellCode masks[DgmOctree::MAX_OCTREE_LEVEL + 1];
};
static MonoDimensionalCellCodes PRE_COMPUTED_POS_CODES;

这里,MAX_OCTREE_LENGTH == (1<<21) == 2097152 == 0x200000 ,是一个位置的极限值,这个表实际上相当于,

[0]    0
[1]    1
[2]    8
[3]    9
[4]    64
[5]    65
[6]    72
[7]    73
[8]    512
[9]    513
[10]    520
[11]    521
[12]    576
[13]    577
[14]    584
[15]    585
[16]    4096
[17]    4097
[18]    4104
[19]    4105
[20]    4160
[21]    4161
[22]    4168
[23]    4169
[24]    4608
[25]    4609
[26]    4616
[27]    4617
[28]    4672
[29]    4673
[30]    4680
[31]    4681
......

计算基础之cellCode

在设计算法之前,我们需要了解一下OcTree层级的概念。

比如我的所有点都在一个64x64x64的立方体内,那第0层级的边长就是64,也就是最大的cube框的边长,那么一个立方体包含8个cube框,下一级第1层级框的边长大小就是64/2,依此类推,再下一级就是64/4,64/8......

另外,给一个相关讲解的参考地址,

参考:数据立方体_点云空间数据组织——八叉树-白红宇的个人博客

作者对八叉树进行了讲解,我摘录了其中的一点。如下,

八叉树将空间分割成八块,根据2进制, 3位2进制即可表示8个数字,3位中的顺序:zyx ,顺序区分,从小递增到大,如: 011,即z为0,x为1,y为 1的块位置。所以 64位操作系统最多可分割为64/3 = 21级32位操作系统最多可分割为32/3 = 10级

建立单维索引( CellCode)

将原有的1位2进制转为3位,如:001转为000 000 001,010 转为 000 001 000,以此类推。另外两个维度的code分别左移1位和2位即可。

软件初始化时就计算完了所有CellCode。

具体可参考前面讲到的结构体
static MonoDimensionalCellCodes PRE_COMPUTED_POS_CODES;

好了,前面的这个要怎么理解和使用呢?

比如,我计算得到cellPos=(2,2,2),那
PRE_COMPUTED_POS_CODES.values[2] == 8 == 000 001 000
假设对应的层级也是21,那么,GenerateTruncatedCellCode中,返回的数据结果就是

return    (
     PRE_COMPUTED_POS_CODES.values[cellPos.x << shift]
|    (PRE_COMPUTED_POS_CODES.values[cellPos.y << shift] << 1)
|    (PRE_COMPUTED_POS_CODES.values[cellPos.z << shift] << 2)
) >> GET_BIT_SHIFT(level);

具体可以参考DgmOctree::GenerateTruncatedCellCode函数。
也就是
000 001 000 | 000 001 000 << 1 | 000 001 000 << 2 == 000 111 000

再比如,我计算得到cellPos=(3,3,3),那
PRE_COMPUTED_POS_CODES.values[3] == 9 == 000 001 001
那么,在21级,相应的cellcode就是
000 001 001 | 000 001 001 << 1 | 000 001 001 << 2 == 000 111 111

又比如,我计算得到cellPos=(4,4,4),那
PRE_COMPUTED_POS_CODES.values[3] == 64 == 001 000 000
那么,在21级,相应的cellcode就是
001 000 000 | 001 000 000 << 1 | 001 000 000 << 2 == 111 000 000

看出规律了吗?

作者的意思,就是要设计一个像c++中std::map这样的一个结构,能够迅速通过这个cellCode,找到任意层级的cellPos。

例如,前面在第21层级的cellPos=(4,4,4),到了第20层级,就要右移3位,因为

GET_BIT_SHIFT(20) == 3

不难判断,这个cellCode对应的cellPos正是(2,2,2)。

好了,有了这些相关基础知识之后, 我们开始讲解点云的八叉树算法的架构与原理。

ccPointCloud : ccGenericPointCloud

class QCC_DB_LIB_API ccPointCloud : public CCCoreLib::PointCloudTpl<ccGenericPointCloud, QString>
{
}

这里,ccGenericPointCloud的父类是GenericIndexedCloudPersist

class QCC_DB_LIB_API ccGenericPointCloud : public ccShiftedObject,  public CCCoreLib::GenericIndexedCloudPersist
{
    friend class ccMesh;

这是一个纯虚类,GenericIndexedCloudPersist,其所有的上级父类也都是纯虚类,或者说是接口,包括GenericIndexedCloud,GenericIndexedCloud, 以及GenericCloud,

class CC_CORE_LIB_API GenericIndexedCloudPersist : virtual public GenericIndexedCloud
{
    ......
}

class CC_CORE_LIB_API GenericIndexedCloud : virtual public GenericCloud {
    ......
}

class CC_CORE_LIB_API GenericCloud{
    ......
}

计算过程(程序结构)

当在CloudCompare中按下Edit-->Octree-->Compute之后,就会启动ocTree的计算,

void MainWindow::doActionComputeOctree()
{
    if ( !ccEntityAction::computeOctree(m_selectedEntities, this) )
        return;

    refreshAll();
    updateUI();
}

computeOctree会对所有选中的实际进行计算,在该函数中,先是得到entity的点云clouds,然后逐个对其进行计算,octree = cloud->computeOctree(..),或者直接生成octree = ccOctree::Shared(new ccOctree(cloud)),

bool computeOctree(const ccHObject::Container &selectedEntities, QWidget* parent)
{

    for (ccHObject* ent : selectedEntities)
    {
        ......
        ccGenericPointCloud* cloud = ccHObjectCaster::ToGenericPointCloud(ent, &lockedVertices);
        ......
        clouds.insert(cloud);
        ......
    }

    .......
    for (const auto cloud : clouds)
    {
        ......
        switch (coDlg.getMode())
        {
        case ccComputeOctreeDlg::DEFAULT:
            octree = cloud->computeOctree(&pDlg);
            break;
        case ccComputeOctreeDlg::MIN_CELL_SIZE:
        case ccComputeOctreeDlg::CUSTOM_BBOX:
        {
            ......
            octree = ccOctree::Shared(new ccOctree(cloud));
            ......
        }
        break;
        }
    }
    ......
}

接下,调用ccGenericPointCloud::computeOctree,

ccOctree::Shared ccGenericPointCloud::computeOctree(CCCoreLib::GenericProgressCallback* progressCb, bool autoAddChild/*=true*/)
{
    deleteOctree();

    ccOctree::Shared octree = ccOctree::Shared(new ccOctree(this));
    if (octree->build(progressCb) > 0)
    {
        setOctree(octree, autoAddChild);
    }
    else
    {
        octree.clear();
    }

    return octree;
}

在这里面,会先new出一个ccOcTree,并把this也就是ccGenericPointCloud传入进去给m_theAssociatedCloud,然后通过build进行octree的计算,

int DgmOctree::build(GenericProgressCallback* progressCb)
{
    if (!m_theAssociatedCloud)
    {
        assert(false);
        return -1;
    }

    if (!m_thePointsAndTheirCellCodes.empty())
    {
        clear();
    }

    m_theAssociatedCloud->getBoundingBox(m_pointsMin, m_pointsMax);

    m_dimMin = m_pointsMin;
    m_dimMax = m_pointsMax;

    //we make this bounding-box cubical (+0.1% growth to avoid round-off issues when projecting points in the octree)
    CCMiscTools::MakeMinAndMaxCubical(m_dimMin, m_dimMax, 0.001);

    return genericBuild(progressCb);
}

这里要注意,ccOctree的父类正是DgmOctree,

class QCC_DB_LIB_API ccOctree : public QObject, public CCCoreLib::DgmOctree

计算OcTree

结构体IndexAndCode中,给出的是点的index和所在的cube的code,大体上是这样定义的,

    struct IndexAndCode
    {
        //! index
        unsigned theIndex;
        //! cell code
        CellCode theCode;
        ......
    }

    using cellsContainer = std::vector<IndexAndCode>;

    //! The coded octree structure
    cellsContainer m_thePointsAndTheirCellCodes;

接下来我们看一下DgmOctree::genericBuild函数的主体,

int DgmOctree::genericBuild(GenericProgressCallback* progressCb)
{
    ......
    try
    {
        m_thePointsAndTheirCellCodes.resize(pointCount); 
    }
    ......

    updateCellSizeTable();


    //for all points
    cellsContainer::iterator it = m_thePointsAndTheirCellCodes.begin();
    for (unsigned i = 0; i < pointCount; i++)
    {
        const CCVector3* P = m_theAssociatedCloud->getPoint(i);

        //does the point falls in the 'accepted points' box?
        //(potentially different from the octree box - see DgmOctree::build)
        if (    (P->x >= m_pointsMin[0]) && (P->x <= m_pointsMax[0])
            &&    (P->y >= m_pointsMin[1]) && (P->y <= m_pointsMax[1])
            &&    (P->z >= m_pointsMin[2]) && (P->z <= m_pointsMax[2]) )
        {
            //compute the position of the cell that includes this point
            Tuple3i cellPos;
            getTheCellPosWhichIncludesThePoint(P, cellPos);

            ......

            it->theIndex = i;
            it->theCode = GenerateTruncatedCellCode(cellPos, MAX_OCTREE_LEVEL);
            ......

            ++it;
            ++m_numberOfProjectedPoints;
        }

    ......

    //we sort the 'cells' by ascending code order
    ParallelSort(m_thePointsAndTheirCellCodes.begin(), m_thePointsAndTheirCellCodes.end(), IndexAndCode::codeComp);

    //update the pre-computed 'number of cells per level of subdivision' array
    updateCellCountTable();

    ......    
}

下面我们来看这个函数是如何计算octree的,

(1) 函数中先是通过m_thePointsAndTheirCellCodes.resize分配内存,

m_thePointsAndTheirCellCodes.resize(pointCount); 

(2)然后,通过updateCellSizeTable不断分割尺寸,得到每一级cube框的大小,例如,假设最大的框的边长为64,那么一个立方体包含8个cube框,下一级框的边长大小就是64/2,依此类推,再下一级就是64/4,64/8......

void DgmOctree::updateCellSizeTable()
{
    //update the cell dimension for each subdivision level
    m_cellSize[0] = m_dimMax.x - m_dimMin.x;

    unsigned long long d = 1;
    for (int k = 1; k <= MAX_OCTREE_LEVEL; k++)
    {
        d <<= 1;
        m_cellSize[k] = m_cellSize[0] / d;
    }
}

然后,函数开始逐个点逐个点地计算。

(3) 通过getTheCellPosWhichIncludesThePoint计算点的cellPos。这里的cellPos是指最小的cube的序号,和前面的讲解一样,假设0级cell大小是64,那么第20级的cell大小就是cs = 64/2^20 = 0.00006103515625,那么在某个维度上其序号就是(x-xmin)/cs,如下,

//! Type of the coordinates of a (N-D) point
using PointCoordinateType = float;

//! Returns the position FOR THE DEEPEST LEVEL OF SUBDIVISION of the cell that includes a given point
    /** The cell coordinates can be negative or greater than 2^MAX_OCTREE_LEVEL-1
    as the point can lie outside the octree bounding-box.
    \param thePoint the query point
    \param cellPos the computed position
    **/
inline void getTheCellPosWhichIncludesThePoint(const CCVector3* thePoint, Tuple3i& cellPos) const
{
    const PointCoordinateType& cs = getCellSize(MAX_OCTREE_LEVEL);
    //DGM: if we admit that cs >= 0, then the 'floor' operator is useless (int cast = truncation)
    cellPos.x = static_cast<int>(/*floor*/(thePoint->x - m_dimMin.x) / cs);
    cellPos.y = static_cast<int>(/*floor*/(thePoint->y - m_dimMin.y) / cs);
    cellPos.z = static_cast<int>(/*floor*/(thePoint->z - m_dimMin.z) / cs);
}

(4) 获取点的cellCode,

这个,是我们在基础部分讲过的函数DgmOctree::GenerateTruncatedCellCode,

DgmOctree::CellCode DgmOctree::GenerateTruncatedCellCode(const Tuple3i& cellPos, unsigned char level)
{
    assert(cellPos.x >= 0 && cellPos.x < MonoDimensionalCellCodes::VALUE_COUNT
    &&cellPos.y >= 0 && cellPos.y < MonoDimensionalCellCodes::VALUE_COUNT
    &&cellPos.z >= 0 && cellPos.z < MonoDimensionalCellCodes::VALUE_COUNT);

    const unsigned char shift = MAX_OCTREE_LEVEL - level;

    return(PRE_COMPUTED_POS_CODES.values[cellPos.x << shift]
          |(PRE_COMPUTED_POS_CODES.values[cellPos.y << shift] << 1)
          |(PRE_COMPUTED_POS_CODES.values[cellPos.z << shift] << 2)
    ) >> GET_BIT_SHIFT(level);
}

(5)按cellCode大小排序

ParallelSort(m_thePointsAndTheirCellCodes.begin(), m_thePointsAndTheirCellCodes.end(), IndexAndCode::codeComp);

值得说明的是,在函数中,对变量m_fillIndexes也进行了计算,因为源码比较简单,一目了然,这里就不展开讲了。

本文结束。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CloudCompare源码分析_八叉树(Octree)算法基础CC中的八叉树结构 的相关文章

  • QThread必须要了解的几个函数

    概述 如果想对Qt中的QThread有个更加深刻的了解 xff0c 必须要知道这几个重要的函数 xff0c 现在就一一介绍下 函数介绍 属性返回值函数体功能staticQThread QThread currentThread 返回当前线程
  • codeforces 766C Mahmoud and a Message

    题意 xff1a 给你一个长度为n的仅包括小写字母的字符串 xff0c 每个小写字母能在一个长度不超过a i xff08 i是小写字母序号如a为0 xff09 的子串中 问 xff1a 1 有多少种分隔方法 2 所有分割方法中最长的子串有多
  • 结构体对齐详解

    1 结构体基础知识 a 认识结构体 结构体是一些值的集合 这些值称为成员变量 结构体的每个成员可以是不同类型的变量 声明一个结构体类型 声明一个学生类型 Stu就是你对这个结构体的称呼 struct Stu char name 20 cha
  • gitlab搬迁到其它服务器

    由于一些因素 xff0c 需要把gitlab从A服务器搬迁到B服务器 xff0c 现记录步骤如下 xff1a 1 查看A服务器的gitlab版本号 xff1a cat opt gitlab embedded service gitlab r
  • 深度学习在图像超分辨率重建中的应用

    同步更新于知乎 xff1a https zhuanlan zhihu com p 25532538 超分辨率技术 xff08 Super Resolution xff09 是指从观测到的低分辨率图像重建出相应的高分辨率图像 xff0c 在监
  • Xorg 的认识

    1 什么是X Window服务器 xff1f 一种图形用户界面只不过是运行在系统上的一个应用程序 它不是 Linux内核的一部分 xff0c 也没有 集成在你的系统里 它是一个可以为你的工作站提供图形化工作界面的强大工具 由于标准的重要性
  • 利用Python获取带合并单元格的表格数据

    由于在日常运维中经常出现一些合并单元格的表格 xff0c 如果要获取数据比较麻烦 xff0c 现将将封装成类 xff0c 并通过调用list excel data 获取列表形式的数据 dict excel data xff1a 获取字典格式
  • 输出不重复的数组元素

    include lt stdio h gt include lt stdlib h gt include lt math h gt int main int n int f 61 1 scanf 34 d 34 amp n int a n
  • UDP编程之windows socket 缓冲区默认大小

    笔者遇到下位机发过来的几百k的文件 xff0c 为了调试方便 xff0c 一开始并没有加协议 后面发现在OnRecv的回调中打印消息时 xff0c 居然UDP丢包了 后面经过多次分析 xff0c 才发现windows默认的socket缓冲区
  • Wmmem占用内存、CPU过多

    Wmmem占用内存 CPU过多 1 问题描述2 解释 2 1 Vmmem是啥2 2 解决办法 1 问题描述 Windows10中 xff0c 没跑啥软件 xff0c 就看见内存满了 Vmmem占用最多 2 解释 2 1 Vmmem是啥 wi
  • Java基础篇:反射机制详解

    一 什么是反射 xff1a xff08 1 xff09 Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息 xff0c 从而操作类或对象的属性和方法 本质是JVM得到class对象之后 xff0c 再通过class对象进行反编
  • 使用linux裁剪树莓派完整sd卡镜像

    解决了最小镜像的制作问题以后 xff0c 就发现手里已经积攒了不少用Win32DiskImager制作的完整sd卡镜像 虽然压缩过了以后很小 xff0c 但是在恢复镜像时32G大小的写入速度简直慢到龟速 xff0c 所以我通过Ubuntu来
  • Arch 安装中文输入法

    推荐安装小狼毫输入法 安装 从官方仓库安装ibus软件包 xff1a span class hljs comment pacman S ibus span 此外 xff0c 为了启动ibus的Qt应用程序支持 安装ibus qt软件库 xf
  • angular11报错Can‘t bind to ‘ngForOf‘ since it isn‘t a known property of ‘tr‘. 三种排查办法以及解决方案

    当你遇到Can t bind to ngForOf since it isn t a known property of tr 34 无法绑定到 ngforof xff0c 因为它不是 tr 的已知属性 xff08 可能问题一 xff1a
  • 如何禁止DELETE、PUT、OPTIONS、TRACE、HEAD等协议访问应用程序

    简介 WebDAV xff08 Web based Distributed Authoring and Versioning xff09 是基于 HTTP 1 1 的一个通信协议 它为 HTTP 1 1 添加了一些扩展 xff08 就是在
  • c++对象模型系列

    一 指针与引用 一 概括 指针和引用 xff0c 在C 43 43 的软件开发中非常常见 xff0c 如果能恰当的使用它们能够极大的提 高整个软件的效率 xff0c 但是很多的C 43 43 学习者对它们的各种使用情况并不是都了解 xff0
  • ProxmoxVE 6.4-13 (PVE)安装 OpenWrt

    创建虚拟机没什么好说的 xff0c 和大多数教程一样 xff0c 主要记录下我遇到的问题 img2kvm报错 storage 39 vm 103 disk 0 39 does not exist 吐槽 xff1a 这玩意官网打不开 xff0
  • IOS学习笔记8—UITableViewController

    UITableViewController是IOS开发中一个比较重要的试图控制器 xff0c 是集成了UITableView视图的控制器 xff0c 在实际开发中经常用到 xff0c 功能非常强大 xff0c 可定制性也很高 xff0c 下
  • nanodet阅读:(2)正负样本定义(ATSS)

    一 前言 本篇博客主要是ATSS部分 xff0c 这部分个人认为是核心之一 xff0c 毕竟正负样本的选择很重要 xff0c ATSS论文证实 xff0c anchor based和anchor free性能差异的根本原因在于正负样本的定义
  • nanodet阅读:(3)Loss计算及推理部分

    一 前言 loss的计算是一个AI工程代码的核心之一 xff0c nanodet的损失函数与yolo v3 5系列有很大不同 xff0c 具体见Generalized Focal Loss xff0c 说实话一开始看这个损失函数博客 xff

随机推荐

  • nanodet阅读:(1)概述

    一 前言 出于某些需要 xff0c 阅读一下anchor free模型的代码 xff0c 因为之前用过nanodet xff0c 对其印象深刻 xff0c 所以重温一下代码 好记性不如烂笔头 xff0c 多记录 多总结 多分享 正如作者博客
  • c++循环引用

    虽然C 43 43 11引入了智能指针的 xff0c 但是开发人员在与内存的斗争问题上并没有解放 xff0c 如果我们使用 不当仍然有内存泄漏问题 xff0c 其中智能指针的循环引用缺陷是最大的问题 main cpp test Create
  • JupyterLab使用教程

    JupyterLab使用教程 一 Jupyter简介1 用户接口2 架构原理1 xff09 IPython Kernel2 xff09 Jupyter Notebook接口3 xff09 Notebook导出为其它格式4 xff09 Pro
  • Python虚拟环境(pipenv、venv、conda一网打尽)

    Python虚拟环境详解 一 什么是虚拟环境1 什么是Python环境2 什么是虚拟环境3 常用工具 二 pipenv1 安装pipenv2 命令概览3 pipenv基本使用1 xff09 创建虚拟环境2 xff09 激活虚拟环境3 xff
  • MERGE INTO用法更新和插入多条子记录

    lt update id 61 34 addMarkChild 34 parameterType 61 34 java util HashMap 34 gt MERGE INTO t kpi simu detail person dp US
  • 51 nod 1255 字典序最小的子序列

    http www 51nod com onlineJudge questionCode html problemId 61 1255 思路 xff1a 分三种情况 xff1a 1 xff1a 栈空 xff0c 直接将字母压入 2 xff1a
  • C++ thread.join 与 terminate

    C 43 43 11 std thread join 主要函数注意事项原因解决方案 std thread 是C 43 43 11的新特性 xff0c 对于windows来说 xff0c 取代了原来的静态方法的创建方式 DWORD WINAP
  • 算法-计算无向图中两个节点之间所有的路径

    图论 寻找节点间所有路径 最近在论文中 xff0c 要获得节点间的路由 xff0c 由此又开始继续去年的算法学习 下面的就关于寻找两个节点之间所有的路径 因为是在获得路径后 xff0c 再加上权重 xff0c 所以不能将那些求最短路径的算法
  • 算法-图论_关键节点的判断

    无向图的关节点 概述 xff1a 在网络中关节点的判断将成为影响网络连通性的主要因素 节点之间通过关键点传递信息 xff0c 如在我们以太网中的网关 当网关节点失效 xff0c 那么两个网络之间的节点就不能够进行通信 在无线传感器网络中 x
  • Mongodb锁机制

    Mongodb锁机制 Mongodb使用读写锁来允许很多用户同时去读一个资源 xff0c 比如数据库或者集合 读采用的是共享锁 xff0c 写采用的是排它锁 对于大部分的读写操作 xff0c WiredTiger使用的都是乐观锁 xff0c
  • 利用pycharm创建第一个django项目

    利用pycharm创建第一个django项目 最近把python的基本语法还有一些绘图chart学习完了 xff0c 开始django学习之路 xff0c 它是个免费的强大的开源web框架 安装好python 下载pycharm之后 xff
  • VSCode中调试nodejs

    VSCode中调试nodejs 项目中用node去编译脚本 xff0c 尝试调试 1 下载nodejs 下载网址 xff1a https nodejs org zh cn 我是安装在windows环境中 xff0c 所以选择 2 启动VS
  • Bilateral Upsample

    bilateral的原理和方法已经了解过 xff0c 借鉴Bilateral的方法进行上采样 xff0c 可以使用输入的图像作为先验 xff0c 引导低分辨图像恢复成原分辨的图像 xff0c 这里简要介绍如下 xff1a 1 首先看一下联合
  • 注册表

    1 概述 是微软的一个数据库 xff0c 用于存储系统和应用程序的设置信息 参数包括控制windows的启动 xff0c 硬件驱动及windows应用程序的运行 非常重要 xff0c 谨慎操作 数据结构 注册表由键 xff0c 子键 xff
  • VS以管理员权限打开

    描述 在VS进行debug的时候 xff0c 会提示使用管理员的权限进行调试 经常出现重新打开程序的问题 xff0c 所以干脆将VS直接设置为默认管理员的角色运行 1 找到程序目录 C Program Files x86 Microsoft
  • ABAQUS仿真结果云图不对称问题

    问题描述 xff1a 在某次使用ABAQUS进行冲压仿真的过程中 xff0c 本应产生基本对称的应力应变云图 xff0c 但是结果显示并不对称 解决方法 xff1a 设置幅值曲线 ABAQUS幅值曲线介绍 在ABAQUS中 xff0c 通过
  • GreenHills基本操作:调试

    1 编译 1 1 整体编译 1 2 编译是否优化选项 或 2 调试 2 1 进入调式 2 2 调试下载 2 3 跳转至具体行 2 4 函数调用过程查看 2 5 通过文件树查找指定文件 2 6 快速查看所需函数 xff0c 设置断点
  • ROS2 humble + windows10,如何安装调试rplidar a1激光扫描传感器

    玩ROS一直是在ubuntu xff0c 最近因为各种原因 xff0c 在windows10上调试ROS2 这一典型的问题是 xff0c 很多硬件都是没有库文件的支持 xff0c 国内的很多硬件也大多只支持ROS1 完全不调试源码直接使用各
  • CloudCompare源码分析_显示渲染的程序架构

    这一讲介绍一下CloudCompare的大致绘制流程或者说绘图框架的结构 根据前面一篇对CloudCompare读取PLY文件的介绍 xff0c 很容易找出当cloudcompare读取到mesh文件 xff08 newGroup xff0
  • CloudCompare源码分析_八叉树(Octree)算法基础CC中的八叉树结构

    官方参考地址 xff1a CloudCompare octree CloudCompareWiki CC的octree算法主要体现在DgmOctree h和DgmOctree cpp中 xff0c 他采用了一种分级的结构 xff0c 最大支