cloud compare二次外掛化功能開發詳細步驟(一)

蔡不菜和他的uU们發表於2024-08-17

點雲處理,有一個出名的處理軟體,cloud compare,簡稱 cc,將自己實現的功能以外掛形式整合到 CC 裡,方便使用

前提

環境:cc 2.13,qt 5.15,cmake 3.18,vs2019【其他組合也可,本文基於此展開】

能力要求:能夠使用 cmake 成功編譯 cc 並安裝

有問題,歡迎留言、進群討論或私聊:【群號:392784757】

CC 外掛概述

CC 提供了一種外掛化的二次開發方式,以外掛的形式,避免了核心程式碼的修改,利用提供的介面,完成我們需要功能的二次開發

組織結構

image-20240814165218429

cc 中的外掛全都放在 原始碼 plugins 資料夾下

core 是 cc 已經實現的外掛功能

example 是 cc 提供給我們的示例,本文也基於其中的示例進行開發我們的外掛

其中 core 資料夾下,又對外掛進行了劃分

  • GL,基於 gl 視覺化外掛
  • IO ,涉及 IO 處理的外掛
  • Standard ,大部分外掛都屬於這種

example 資料夾下也對應提供了 相應的示例外掛

  • ExampleGLPlugin
  • ExampleIOPlugin
  • ExamplePlugin

本文基於其中的 ExamplePlugin 外掛,也就是標準外掛型別,實現一個 PCA 功能,並視覺化

ExamplePlugin

image-20240814170233699

images 中放置的是 icon.png

include 涉及的標頭檔案,自己的功能標頭檔案和用到的其他第三方的標頭檔案

src 功能程式碼

ExamplePlugin.qrc,qt 組織資源的方式,提供資源的路徑給程式碼使用

info. json,外掛的描述,涉及的相關資源路徑,以及開發者資訊、相關資料

{
	"type": "Standard",
	"name": "MyTest (Standard Plugin)",
	"icon": ":/CC/plugin/MyTestPlugin/images/icon.png",
	"description": "This is a description of the marvelous Example plugin. It does nothing.",
	"authors": [
		{
			"name": "xxx",
			"email": "xxx"
		}
	],
	"maintainers": [
		{
			"name": "yyy,
			"email": "yyy@gmail.com"
		},
		{
			"name": "zzz"
		}
	],
	"references": [
		{
			"text": "xx references",
			"url": "http://www.bmj.com/content/333/7582/1285"
		},
		{
			"text": "a test plugin"
		}
	]
}

cmake 組織

基礎的結構講完,cc 是如何透過某種方式將外掛組織起來的,答案就是 cmake

從高到低涉及的 cmakelists.txt 完成了這一任務【下面或區分兩條不同路徑情況,一個是放在 core\standard ,另一個是放在 example】

D:\06-source_code\CloudCompare-2.13\CMakeLists.txt

# ...

# Plugins
add_subdirectory( plugins )

# ...

D:\06-source_code\CloudCompare-2.13\plugins\CMakeLists.txt

# ...

add_subdirectory( core )
add_subdirectory( example )

# ...

D:\06-source_code\CloudCompare-2.13\plugins\core\CMakeLists.txt 【D:\06-source_code\CloudCompare-2.13\plugins\example\CMakeLists.txt】

add_subdirectory( GL )
add_subdirectory( IO )
add_subdirectory( Standard )

add_subdirectory( ${CMAKE_CURRENT_SOURCE_DIR}/ExampleGLPlugin )
add_subdirectory( ${CMAKE_CURRENT_SOURCE_DIR}/ExampleIOPlugin )
add_subdirectory( ${CMAKE_CURRENT_SOURCE_DIR}/ExamplePlugin )

D:\06-source_code\CloudCompare-2.13\plugins\core\Standard\CMakeLists.txt

add_subdirectory( qAnimation )
add_subdirectory( qBroom )
add_subdirectory( qCanupo )
add_subdirectory( qCloudLayers )
add_subdirectory( qCompass )
add_subdirectory( qCork )
add_subdirectory( qCSF )
add_subdirectory( qFacets )
add_subdirectory( qHoughNormals )
add_subdirectory( qHPR )
add_subdirectory( qM3C2 )
add_subdirectory( qPCL )
add_subdirectory( qPCV )
add_subdirectory( qPoissonRecon )
add_subdirectory( qRANSAC_SD )
add_subdirectory( qSRA )
add_subdirectory( qMeshBoolean )

#plugins integrated as submodules
set( submod_plugins
		${CMAKE_CURRENT_SOURCE_DIR}/qColorimetricSegmenter
		${CMAKE_CURRENT_SOURCE_DIR}/qMasonry
		${CMAKE_CURRENT_SOURCE_DIR}/qMPlane
		${CMAKE_CURRENT_SOURCE_DIR}/qJSonRPCPlugin
		${CMAKE_CURRENT_SOURCE_DIR}/qTreeIso
		${CMAKE_CURRENT_SOURCE_DIR}/q3DMASC
)

foreach( dir ${submod_plugins} )
    if( IS_DIRECTORY ${dir} AND EXISTS ${dir}/CMakeLists.txt )
		message( STATUS "Found submodule plugin: " ${dir} )
		add_subdirectory( ${dir} )
	endif()
endforeach()

具體外掛的 CMakeLists.txt

【D:\06-source_code\CloudCompare-2.13\plugins\core\Standard\qPCA\CMakeLists.txt】或【D:\06-source_code\CloudCompare-2.13\plugins\example\ExamplePlugin\CMakeLists.txt】

# ...

# CloudCompare example for standard plugins

# REPLACE ALL 'ExamplePlugin' OCCURENCES BY YOUR PLUGIN NAME
# AND ADAPT THE CODE BELOW TO YOUR OWN NEEDS!

# Add an option to CMake to control whether we build this plugin or not
option( PLUGIN_EXAMPLE_STANDARD "Install example plugin" OFF )

if ( PLUGIN_EXAMPLE_STANDARD )
	project( ExamplePlugin )

	AddPlugin( NAME ${PROJECT_NAME} )

	add_subdirectory( include )
	add_subdirectory( src )

	# set dependencies to necessary libraries
	# target_link_libraries( ${PROJECT_NAME} LIB1 )
endif()

具體開發前修改

info.json

{
	"type": "Standard",
	"name": "PCA (Standard Plugin)",
	"icon": ":/CC/plugin/qPCA/images/icon.png",
	"description": "This is a description of the PCA plugin. It does nothing.",
	"authors": [
		{
			"name": "xxx",
			"email": "xxx"
		}
	],
	"maintainers": [
		{
			"name": "yyy,
			"email": "yyy@gmail.com"
		},
		{
			"name": "zzz"
		}
	],
	"references": [
		{
			"text": "xx references",
			"url": "http://www.bmj.com/content/333/7582/1285"
		},
		{
			"text": "a PCA plugin"
		}
	]
}

具體外掛上一級的 CMakeLists.txt,這裡是 Standard\CMakeLists.txt

add_subdirectory( qAnimation )
add_subdirectory( qBroom )
add_subdirectory( qCanupo )
add_subdirectory( qCloudLayers )
add_subdirectory( qCompass )
add_subdirectory( qCork )
add_subdirectory( qCSF )
add_subdirectory( qFacets )
add_subdirectory( qHoughNormals )
add_subdirectory( qHPR )
add_subdirectory( qM3C2 )
add_subdirectory( qPCL )
add_subdirectory( qPCV )
add_subdirectory( qPoissonRecon )
add_subdirectory( qRANSAC_SD )
add_subdirectory( qSRA )
add_subdirectory( qMeshBoolean )

# --------------------
add_subdirectory( qPCA )
# --------------------

#plugins integrated as submodules
set( submod_plugins
		${CMAKE_CURRENT_SOURCE_DIR}/qColorimetricSegmenter
		${CMAKE_CURRENT_SOURCE_DIR}/qMasonry
		${CMAKE_CURRENT_SOURCE_DIR}/qMPlane
		${CMAKE_CURRENT_SOURCE_DIR}/qJSonRPCPlugin
		${CMAKE_CURRENT_SOURCE_DIR}/qTreeIso
		${CMAKE_CURRENT_SOURCE_DIR}/q3DMASC
)

foreach( dir ${submod_plugins} )
    if( IS_DIRECTORY ${dir} AND EXISTS ${dir}/CMakeLists.txt )
		message( STATUS "Found submodule plugin: " ${dir} )
		add_subdirectory( ${dir} )
	endif()
endforeach()

具體外掛的 CMakeLists.txt, qPCA/CMakeLists.txt

# CloudCompare example for standard plugins

# REPLACE ALL 'ExamplePlugin' OCCURENCES BY YOUR PLUGIN NAME
# AND ADAPT THE CODE BELOW TO YOUR OWN NEEDS!

# Add an option to CMake to control whether we build this plugin or not
# option( PLUGIN_EXAMPLE_STANDARD "Install example plugin" OFF )
option( PLUGIN_qPCA "Install example plugin" OFF )

# if ( PLUGIN_EXAMPLE_STANDARD )
if ( PLUGIN_qPCA )
	# project( ExamplePlugin )
	project( QPCA_PLUGIN ) # 全部大寫

	AddPlugin( NAME ${PROJECT_NAME} )

	add_subdirectory( include )
	add_subdirectory( src )

	# 新增其他需要的庫 set dependencies to necessary libraries
	# target_link_libraries( ${PROJECT_NAME} LIB1 )
endif()

更新 ExamplePlugin 中的檔名為新外掛對應的名稱

ExamplePlugin.qrc ---> qPCA.qrc

ExamplePlugin.h ---> qPCA.h

ExamplePlugin.cpp ---> qPCA.cpp

src include 下的 CMakeLists.txt 更新檔名

src/CMakeLists.txt

target_sources( ${PROJECT_NAME}
	PRIVATE
		${CMAKE_CURRENT_LIST_DIR}/ActionA.cpp
		# ${CMAKE_CURRENT_LIST_DIR}/ExamplePlugin.cpp
		${CMAKE_CURRENT_LIST_DIR}/qPCA.cpp
		# 其他新加檔案
)

include/CMakeLists.txt

target_sources( ${PROJECT_NAME}
	PRIVATE
		${CMAKE_CURRENT_LIST_DIR}/ActionA.h
		# ${CMAKE_CURRENT_LIST_DIR}/ExamplePlugin.h
		${CMAKE_CURRENT_LIST_DIR}/qPCA.h
		# 候選其他標頭檔案也要在這新增
)

target_include_directories( ${PROJECT_NAME}
	PRIVATE
		${CMAKE_CURRENT_SOURCE_DIR}
)

更新 ExamplePlugin.qrc,更新資源路徑

直接用 vscode 開啟 修改

<RCC>
    <qresource prefix="/CC/plugin/ExamplePlugin">
        <file>images/icon.png</file>
        <file>info.json</file>
    </qresource>
</RCC>

修改後

image-20240814190146241

此圖片為後面生成 project 後在 vs 中修改

image-20240814190024700

主檔案修改

修改 qPCA.cpp

# #include "ExamplePlugin.h" 改為
#include "qPCA.h"

# ,ccStdPluginInterface( ":/CC/plugin/ExamplePlugin/info.json" )

,ccStdPluginInterface( ":/CC/plugin/qPCA/info.json" )

修改 qPCA.h

# Q_PLUGIN_METADATA( IID "cccorp.cloudcompare.plugin.Example" FILE "../info.json" )
Q_PLUGIN_METADATA( IID "cccorp.cloudcompare.plugin.qPCA" FILE "../info.json" )

cmake 構建

image-20240814205307575

可以看到我們的 qPCA 外掛選項,選中

然後生成 project

執行

image-20240814202916848

image-20240814203105623

下一篇,我們來實現具體的 PCA 邏輯和視覺化效果

有問題,歡迎留言、進群討論或私聊:【群號:392784757】

相關文章