第5講:建立自己的C函數庫,js調用自己寫的C/C++函數,并包含依賴C/C++第三方靜態庫。

在javascript中,Array有很多內置的功能,比如Array.map,Array.filter,Array.find等等,能用內置的功能就用內置的功能,最好不要自己實現一套,因為底層調用的可能壓根就不是js語言本身,底層的實現可能由C/C++實現的。如果我們要做的一些功能,需要高性能密集計算,但是JavaScript內置函數無法滿足我們要求的時候,這時候我們就要自己用C/C++編寫一個程序,然后封裝成wasm文件給JavaScript調用了,此時wasm還包含了.a文件這樣的第三方庫。

我們這里有個需求,就是在地球上有兩艘船,船A和船B在某個經緯度位置觸發,以某個航向、速度行駛,求它們間最小距離是多少,達到最小距離的時候,經過時間是多少秒?
首先這個功能用C/C++來編寫,并且還要用到開源第三方庫。
下圖的紅圈注釋里面有幾個參數,分別表示經度、緯度、速度、航向,當然getCPA最后一個參數6.5表示6.5分鐘的時間長度。表示計算6.5分鐘以內,兩船最小距離是多少,并且到達最小距離時,經過時間是多少。
在這里插入圖片描述

打開Visual Studio 2022,新建一個cmake工程,項目名稱為GeoCompute。這僅僅是一個測試項目,如果測試通過,沒有問題了,就把該代碼交給emcc或者em++去編譯。
CMakeLists.txt文件內容如下:
在這里,我采用vcpkg來安裝GeographicLib庫
可以執行如下命令安裝。

vcpkg install GeographicLib:x64-windows
# CMakeList.txt: GeoCompute 的 CMake 項目,在此處包括源代碼并定義
# 項目特定的邏輯。
#
cmake_minimum_required (VERSION 3.8)
set(VCPKG_ROOT "D:/CppPkg/WinVcpkg/vcpkg" CACHE PATH "")
set(CMAKE_TOOLCHAIN_FILE "${VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake")
# Enable Hot Reload for MSVC compilers if supported.
if (POLICY CMP0141)cmake_policy(SET CMP0141 NEW)set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<IF:$<AND:$<C_COMPILER_ID:MSVC>,$<CXX_COMPILER_ID:MSVC>>,$<$<CONFIG:Debug,RelWithDebInfo>:EditAndContinue>,$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>>")
endif()project ("GeoCompute")# 將源代碼添加到此項目的可執行文件。
add_executable (GeoCompute "GeoCompute.cpp"  )find_package (GeographicLib CONFIG REQUIRED)
target_link_libraries (GeoCompute PRIVATE ${GeographicLib_LIBRARIES})if (CMAKE_VERSION VERSION_GREATER 3.12)set_property(TARGET GeoCompute PROPERTY CXX_STANDARD 20)
endif()# TODO: 如有需要,請添加測試并安裝目標。

然后編寫一個GeoCompute.cpp文件

#include <iostream>
#include <GeographicLib/Geodesic.hpp>
#include <GeographicLib/Constants.hpp>
#include <cmath>
#include <vector>const double EARTH_RADIUS = 6377830.0;  // 地球的平均半徑,單位為千米
const double M_PI = 3.14159265359;struct LatLon {double first;double second;
};double deg2rad(double deg) {return deg * M_PI / 180.0;
}double haversine_distance(double lat1, double lon1, double lat2, double lon2) {double dlat = deg2rad(lat2 - lat1);double dlon = deg2rad(lon2 - lon1);double a = std::sin(dlat / 2) * std::sin(dlat / 2) +std::cos(deg2rad(lat1)) * std::cos(deg2rad(lat2)) *std::sin(dlon / 2) * std::sin(dlon / 2);double c = 2 * std::atan2(std::sqrt(a), std::sqrt(1 - a));return EARTH_RADIUS * c;
}LatLon new_position_with_geolib(double lat, double lon, double speed, double cog, double T) {const GeographicLib::Geodesic& geod = GeographicLib::Geodesic::WGS84();double s12 = speed * T;double lat2, lon2;// Direct method gives the destination point given start point, initial azimuth, and distancegeod.Direct(lat, lon, cog, s12, lat2, lon2);return { lat2, lon2 };
}double new_distance(double T, double latA, double lonA, double speedA, double cogA, double latB, double lonB, double speedB, double cogB) {auto resA = new_position_with_geolib(latA, lonA, speedA, cogA, T);auto resB = new_position_with_geolib(latB, lonB, speedB, cogB, T);return haversine_distance(resA.first, resA.second, resB.first, resB.second);
}LatLon getCPA(double latA, double lonA, double speedA, double cogA, double latB, double lonB, double speedB, double cogB, double tcpa) {double RES_TCPA = INFINITY;double RES_DCPA = INFINITY;double prev_dist = INFINITY;double cur_dist = INFINITY;std::vector<int> status;int t_lim = tcpa * 60;int step = 1;if (t_lim > 600) {step = int(double(t_lim) / 300.0);}for (int t = 0;t < t_lim; t += step) {prev_dist = new_distance(t, latA, lonA, speedA, cogA, latB, lonB, speedB, cogB);cur_dist = new_distance(t + step, latA, lonA, speedA, cogA, latB, lonB, speedB, cogB);if (prev_dist < RES_DCPA) {RES_DCPA = prev_dist;}if (cur_dist - prev_dist <= 0) {if (status.size() == 0) {status.emplace_back(-1);}}else {if (status.size() == 0) {status.emplace_back(1);break;}else {if (status[0] == -1) {status.emplace_back(1);}}}if (status.size() == 2 && status[0] == -1 && status[1] == 1) {RES_TCPA = t;break;}}return { RES_TCPA, RES_DCPA };
}//1.  一開始距離就變大
// 2. 從0時刻到指定tcpa一直減小
// 3. 從0時刻到指定tcpa,先減小后增大
int main() {double lat = 40, lon = 100, speed = 10, cog = 45, T = 3600;auto result = new_position_with_geolib(lat, lon, speed, cog, T);std::cout << "New Latitude: " << result.first << ", New Longitude: " << result.second << std::endl;/*latA, lonA, speedA, cogA = 21.3058, 109.1014, 15.12, 187.13latB, lonB, speedB, cogB = 21.288205, 109.118725, 3.909777, 254.42*/int i = 0;while (true) {// 先減小后增大auto res_ = getCPA(21.3058, 109.1014, 15.12, 187.13, 21.288205, 109.118725, 3.909777, 254.42, 6.5);//auto res_ = getCPA(22.3058, 108.1014, 15.12, 187.13, 21.288205, 109.118725, 3.909777, 254.42, 6.0);//auto res_ = getCPA(0.0, 0.0, 15.12, 225.0, 0.0000001, 0.0000001, 3.909777, 45.0, 6.0);std::cout << res_.first << " --- " << res_.second << std::endl;i++;printf("%d\n", i);}return 0;
}

好了,如果代碼測試完成了。現在我們創建一個cmake工程,項目名為EmscriptenTest,這是用來生成wasm文件和js文件來給JavaScript調用的。

由于JavaScript運行在瀏覽器,不能直接支持windows的lib靜態庫,所以想辦法得到.a庫。
首先從github拉取geographiclib庫的源碼

 git clone https://github.com/geographiclib/geographiclib.git

然后進入到根目錄:

cd geographiclib

最后用emcmake和emmake命令編譯代碼(前提是要安裝emsdk:官網有教程說明:https://emscripten.org/docs/getting_started/downloads.html)

emcmake cmake .
emmake make

編譯完成之后:
![(https://img-blog.csdnimg.cn/direct/3e76d9aba3834e01b2894e163ee5fcc8.png)

轉到目錄geographiclib/src
找到libGeographicLib.a文件,然后把該文件拷貝到EmscriptenTest項目的lib目錄下(如果沒有lib目錄則自己新建)

然后是CMakeLists.txt文件:

# CMakeList.txt: EmscriptenTest 的 CMake 項目,在此處包括源代碼并定義
# 項目特定的邏輯。
#
cmake_minimum_required (VERSION 3.8)
set(CMAKE_TOOLCHAIN_FILE "D:/CppPkg/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake")
# 手動設置GeographicLib的路徑
set(GEOGRAPHICLIB_INCLUDE_DIR "/path/to/vcpkg/installed/x64-windows/include")
#set(GEOGRAPHICLIB_LIB_DIR "/path/to/vcpkg/installed/x64-windows/lib")
set(GEOGRAPHICLIB_LIB_DIR "填寫你的EmscriptenTest/lib目錄的絕對路徑")# Enable Hot Reload for MSVC compilers if supported.
if (POLICY CMP0141)cmake_policy(SET CMP0141 NEW)set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<IF:$<AND:$<C_COMPILER_ID:MSVC>,$<CXX_COMPILER_ID:MSVC>>,$<$<CONFIG:Debug,RelWithDebInfo>:EditAndContinue>,$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>>")
endif()project ("EmscriptenTest")# 將源代碼添加到此項目的可執行文件。
add_executable (EmscriptenTest "GeoCompute.cpp")include_directories(D:/CppPkg/WinVcpkg/vcpkg/installed/x64-windows/include )
target_link_libraries(EmscriptenTest ${GEOGRAPHICLIB_LIB_DIR}/libGeographicLib.a)add_library(GeoCompute STATIC GeoCompute.cpp)
set_target_properties(GeoCompute PROPERTIES SUFFIX ".wasm")
set_target_properties(GeoCompute PROPERTIES LINK_FLAGS "--bind -s WASM=1 -s MODULARIZE=1 -s EXPORT_NAME='GeoComputeModule' -s EXPORTED_FUNCTIONS='[\"getCPA\"]'")if (CMAKE_VERSION VERSION_GREATER 3.12)set_property(TARGET EmscriptenTest PROPERTY CXX_STANDARD 20)
endif()# TODO: 如有需要,請添加測試并安裝目標。

這個EmscriptenTest.cpp沒什么用,里面寫個main函數,直接return 0;就完事兒了。
在項目根目錄下新建GeoCompute.cpp文件
GeoCompute.cpp文件的內容:
可能會提示報錯,但是如果點擊重新生成,生成成功的話,是沒事兒的。
在這個文件中,我修改了getCPA函數的返回類型為double* , 因為直接返回TDCPA結構體,JavaScript是無法識別的,一定要返回一個指針。

#include <iostream>
#include <GeographicLib/Geodesic.hpp>
#include <GeographicLib/Constants.hpp>
#include <cmath>
#include <vector>
#include <emscripten/emscripten.h>
const double EARTH_RADIUS = 6377830.0;  // 地球的平均半徑,單位為千米
const double _M_PI = 3.14159265359;struct LatLon {double lat;double lon;
};struct TDCPA {double res_tcpa;double res_dcpa;
};extern "C" {EMSCRIPTEN_KEEPALIVEdouble deg2rad(double deg) {return deg * _M_PI / 180.0;}EMSCRIPTEN_KEEPALIVEdouble haversine_distance(double lat1, double lon1, double lat2, double lon2) {double dlat = deg2rad(lat2 - lat1);double dlon = deg2rad(lon2 - lon1);double a = std::sin(dlat / 2) * std::sin(dlat / 2) +std::cos(deg2rad(lat1)) * std::cos(deg2rad(lat2)) *std::sin(dlon / 2) * std::sin(dlon / 2);double c = 2 * std::atan2(std::sqrt(a), std::sqrt(1 - a));return EARTH_RADIUS * c;}EMSCRIPTEN_KEEPALIVELatLon new_position_with_geolib(double lat, double lon, double speed, double cog, double T) {const GeographicLib::Geodesic& geod = GeographicLib::Geodesic::WGS84();double s12 = speed * T;double lat2, lon2;// Direct method gives the destination point given start point, initial azimuth, and distancegeod.Direct(lat, lon, cog, s12, lat2, lon2);return { lat2, lon2 };}EMSCRIPTEN_KEEPALIVEdouble new_distance(double T, double latA, double lonA, double speedA, double cogA, double latB, double lonB, double speedB, double cogB) {auto resA = new_position_with_geolib(latA, lonA, speedA, cogA, T);auto resB = new_position_with_geolib(latB, lonB, speedB, cogB, T);return haversine_distance(resA.lat, resA.lon, resB.lat, resB.lon);}EMSCRIPTEN_KEEPALIVEdouble* getCPA(double latA, double lonA, double speedA, double cogA, double latB, double lonB, double speedB, double cogB, double tcpa) {double RES_TCPA = INFINITY;double RES_DCPA = INFINITY;double prev_dist = INFINITY;double cur_dist = INFINITY;double* tdcpaPtr = new double[2];std::vector<int> status;int t_lim = tcpa * 60;int step = 1;if (t_lim > 600) {step = int(double(t_lim) / 300.0);}for (int t = 0; t < t_lim; t += step) {prev_dist = new_distance(t, latA, lonA, speedA, cogA, latB, lonB, speedB, cogB);cur_dist = new_distance(t + step, latA, lonA, speedA, cogA, latB, lonB, speedB, cogB);if (prev_dist < RES_DCPA) {RES_DCPA = prev_dist;}if (cur_dist - prev_dist <= 0) {if (status.size() == 0) {status.emplace_back(-1);}}else {if (status.size() == 0) {status.emplace_back(1);break;}else {if (status[0] == -1) {status.emplace_back(1);}}}if (status.size() == 2 && status[0] == -1 && status[1] == 1) {RES_TCPA = t;break;}}tdcpaPtr[0] = RES_TCPA;tdcpaPtr[1] = RES_DCPA;return tdcpaPtr;}}

好了,現在就測試全部重新生成。如果沒有報錯,則通過測試。通過測試之后。證明可以大膽使用em++命令直接編譯GeoCompute.cpp為wasm文件了。

打開cmd進入到EmscriptenTest工程根目錄。

em++ GeoCompute.cpp -O1 -o libGeoCompute.js -s WASM=1 -s MODULARIZE=1 -s EXPORT_NAME="GeoComputeModule" -s "EXPORTED_FUNCTIONS=['_deg2rad', '_haversine_distance', '_new_position_with_geolib', '_new_distance', '_getCPA']" -s "EXPORTED_RUNTIME_METHODS=['ccall', 'cwrap']" -I D:/CppPkg/WinVcpkg/vcpkg/installed/x64-windows/include -L D:/HighPerformanceProjects/CppProjects/EmscriptenTest/lib -lGeographicLib

我這里導出了所有的函數,函數前面要加上下劃線。但是在cmakelists.txt中不需要加下劃線。
執行完成命令之后,會生成libGeoCompute.js和libGeoCompute.wasm文件。

在這里插入圖片描述

現在可以使用npm創建一個原生的JavaScript項目。
這是工程目錄結構:
在這里插入圖片描述
最重要是main.js的寫法:

const fs = require('fs');
const path = require('path');// 加載 Emscripten 生成的模塊
const Module = require('./libGeoCompute.js');async function main() {try {const instance = await Module({locateFile: (filename) => path.join(__dirname, filename),});console.log('Module instance:', instance);console.log(typeof instance.cwrap)// await new Promise((resolve) => {//   console.log('Waiting for runtime initialization...');//   instance.onRuntimeInitialized = () => {//     console.log('Runtime initialized.');//     resolve();//   };// });// 使用 cwrap 包裝 getCPA 函數const getCPA = instance.cwrap('getCPA', 'number', ['number', 'number', 'number', 'number', 'number', 'number', 'number', 'number', 'number']);console.log(typeof getCPA)// 調用導出的 getCPA 函數const resultPtr = getCPA(21.3058, 109.1014, 15.12, 187.13, 21.288205, 109.118725, 3.909777, 254.42, 6.5);console.log(typeof resultPtr)// 解析返回值(假設返回指向結構體的指針)const res_tcpa = instance.HEAPF64[resultPtr >> 3]; // 讀取double指針的第0個元素const res_dcpa = instance.HEAPF64[(resultPtr >> 3) + 1]; // 讀取地址偏移量+1console.log('TCPA:', res_tcpa);console.log('DCPA:', res_dcpa);console.log('Continuing after runtime initialization.');// 繼續下面的邏輯...} catch (error) {console.error('Error:', error);}
}main();

index.html的內容:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Blank Window</title>
</head>
<body><!-- 這里可以添加窗體的內容 -->
</body>
</html>

package.json的內容:

{"name": "nodedevtest","version": "1.0.0","description": "A minimal Electron application","main": "main.js","scripts": {"start": "node main.js"},"keywords": [],"author": "","license": "ISC","dependencies": {"axios": "^1.6.8","electron": "^30.0.1","pixi.js": "^8.1.0","request": "^2.88.2"}
}

得出的結果:
在這里插入圖片描述

得出的結果是154和1519.5687501879786
表示經過154秒以后,兩船達到最小距離,并且最小距離為1519米多。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/37226.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/37226.shtml
英文地址,請注明出處:http://en.pswp.cn/web/37226.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

[AIGC] awk 和 sed

在Unix系統中&#xff0c;有兩種強大的用于文本操作的命令工具&#xff0c;它們就是awk和sed。這兩個命令工具是每個Linux用戶必備的知識之一&#xff0c;尤其對于需要進行文本處理或數據抽取的開發者來說&#xff0c;更加重要。 在實際開發過程中&#xff0c;我們常常需要處理…

JavaScript中的hasOwnProperty方法詳解

JavaScript中的hasOwnProperty方法詳解 大家好&#xff0c;我是免費搭建查券返利機器人省錢賺傭金就用微賺淘客系統3.0的小編&#xff0c;也是冬天不穿秋褲&#xff0c;天冷也要風度的程序猿&#xff01; 什么是hasOwnProperty方法&#xff1f; 在JavaScript中&#xff0c;h…

Wails 安裝初體驗

文章目錄 Wails 安裝說明1. 系統要求2. 安裝步驟3. 構建應用 結論 Wails 安裝說明 Wails 是一個用于構建桌面應用的 Go 框架&#xff0c;結合了現代前端技術。以下是安裝步驟&#xff1a; 1. 系統要求 Go 1.16 或更高版本Node.js 和 npm可選&#xff1a;適用于 Windows、mac…

【機器學習】機器學習的重要方法——強化學習:理論,方法與實踐

目錄 一、強化學習的核心概念 二、強化學習算法的分類與示例代碼 三.強化學習的優勢 四.強化學習的應用與挑戰 五、總結與展望 強化學習&#xff1a;理論&#xff0c;方法和實踐 在人工智能的廣闊領域中&#xff0c;強化學習&#xff08;Reinforcement Learning, RL&…

轉自羅翔老師的畢業寄語(二)

其實我很想祝大家一帆風順&#xff0c;可是我覺得這不現實。 智者說人這一生至少有三件事是無法避免的&#xff0c;一個是苦難&#xff0c;一個是邪惡&#xff0c;還有一個是人生的終點。所以真的愿我們每時每刻都在當下存儲足夠美好的記憶去對抗人生不期而至的苦楚&#xff0c…

基于源碼詳解ThreadPoolExecutor實現原理

個人博客地址 基于源碼詳解ThreadPoolExecutor實現原理 | iwts’s blog 內容拆分 這里算是一個總集&#xff0c;內容太多&#xff0c;拆分成幾個比較重要的小的模塊&#xff1a; ThreadPoolExecutor基于ctl變量的聲明周期管理 | iwts’s blog ThreadPoolExecutor 工作線程…

模板方法模式在金融業務中的應用及其框架實現

引言 模板方法模式&#xff08;Template Method Pattern&#xff09;是一種行為設計模式&#xff0c;它在一個方法中定義一個算法的框架&#xff0c;而將一些步驟的實現延遲到子類中。模板方法允許子類在不改變算法結構的情況下重新定義算法的某些步驟。在金融業務中&#xff…

可信和可解釋的大語言模型推理-RoG

大型語言模型&#xff08;LLM&#xff09;在復雜任務中表現出令人印象深刻的推理能力。然而&#xff0c;LLM在推理過程中缺乏最新的知識和經驗&#xff0c;這可能導致不正確的推理過程&#xff0c;降低他們的表現和可信度。知識圖譜(Knowledge graphs, KGs)以結構化的形式存儲了…

基于lightgbm hyperopt的旋轉機械故障診斷(Python)

前置文章&#xff1a; 將一維機械振動信號構造為訓練集和測試集&#xff08;Python&#xff09; https://mp.weixin.qq.com/s/DTKjBo6_WAQ7bUPZEdB1TA 旋轉機械振動信號特征提取&#xff08;Python&#xff09; https://mp.weixin.qq.com/s/VwvzTzE-pacxqb9rs8hEVw import…

Python變量的命名規則與賦值方式

第二章&#xff1a;Python 基礎語法 第一節&#xff1a;變量的命名規則與賦值方式 2.1.1 引言 在編程中&#xff0c;變量是存儲數據的基本單元。變量的命名和賦值是編程語言中表達和操作數據的基礎。了解和遵循變量命名規則對于編寫清晰、可維護的代碼至關重要。 2.1.2 變量…

【linux】網絡基礎(1)

文章目錄 網絡基本概念網絡的定義網絡的類型局域網&#xff08;LAN&#xff09;廣域網&#xff08;WAN&#xff09; 網絡協議OSI七層模型TCP/IP模型TCP/IP模型的結構 網絡傳輸的基本流程計算機與計算機之間的通信計算機的信息處理封裝報頭 網絡基本概念 網絡的定義 1.網絡是指…

專題一: Spring生態初探

咱們先從整體脈絡上看下Spring有哪些模塊&#xff0c;重要的概念有個直觀印象。 從Spring框架的整體架構和組成對整體框架有個認知。 Spring框架基礎概念 Spring基礎 - Spring和Spring框架組成 上圖是從官網4.2.x獲取的原圖&#xff0c;目前我們使用最廣法的版本應該都是5.x&am…

GitHub每日最火火火項目(6.30)

項目名稱&#xff1a;modelscope / DiffSynth - Studio 項目介紹&#xff1a;該項目致力于讓用戶體驗擴散模型的神奇魅力。擴散模型是一種具有廣泛應用前景的技術&#xff0c;在圖像生成、音頻處理等領域展現出了強大的能力。通過DiffSynth - Studio&#xff0c;用戶可以深入探…

Arrays.asList 和 java.util.ArrayList 區別

理解 Java 中的 Arrays.asList 和 java.util.ArrayList 的區別 在 Java 編程中&#xff0c;Arrays.asList 方法和 java.util.ArrayList 是兩種常用的處理列表數據的方式。雖然它們在功能上看起來相似&#xff0c;但在內部實現和使用上有著本質的不同。本文將探討這兩種方式的區…

一區算法MPA|海洋捕食者算法原理及其代碼實現(Matlab/Python))

Matlab/Python&#xff1a; 本文KAU將介紹一個2020年發表在1區期刊ESWA上的優化算法——海洋捕食者算法 (Marine Predators Algorithm&#xff0c;MPA)[1] 該算法由Faramarzi等于2020年提出&#xff0c;其靈感來源于海洋捕食者之間不同的覓食策略、最佳相遇概率策略、海洋記…

【Linux】IO多路復用——select,poll,epoll的概念和使用,三種模型的特點和優缺點,epoll的工作模式

文章目錄 Linux多路復用1. select1.1 select的概念1.2 select的函數使用1.3 select的優缺點 2. poll2.1 poll的概念2.2 poll的函數使用2.3 poll的優缺點 3. epoll3.1 epoll的概念3.2 epoll的函數使用3.3 epoll的優點3.4 epoll工作模式 Linux多路復用 IO多路復用是一種操作系統的…

MCU復位時GPIO是什么狀態?

大家一定遇到過上電或者復位時外部的MOS電路或者芯片使能信號意外開啟&#xff0c;至此有經驗的工程師就會經常關心一個問題&#xff0c;MCU復位時GPIO是什么狀態&#xff1f;什么電路需要外部加上下拉&#xff1f; MCU從上電到啟動&#xff0c;實際可分為復位前和復位后、初始…

【WPF】Windows系統桌面應用程序編程開發新手入門-打造自己的小工具

電腦Windows系統上的桌面程序通常是用Visual Studio 開發工具編寫出來的&#xff0c;有兩種開發方式供選擇&#xff0c;一種是WindowForm&#xff0c;簡稱WinForm&#xff0c;另一種是Windows Presentation Foundation&#xff0c;簡稱WPF&#xff0c;這里將學習WPF項目。 文章…

大物3錯題整理

平衡位置&#xff1a;在O點上的位置 相位&#xff1a; 當N很大的時候&#xff0c;wxwywz。因此&#xff0c;平均平動動能除以3&#xff0c;就是能量均分定理。 W F在x上的積分 Π時無單位 180&#xff0c;就是單位 1rad&#xff0c;rad就是單位 左手定則、右手定則、安培定…

C++模板類與繼承

1&#xff09;模板類繼承普通類&#xff08;常見&#xff09;。 2&#xff09;普通類繼承模板類的實例化版本。 3&#xff09;普通類繼承模板類。(常見) 4&#xff09;模板類繼承模板類。 5&#xff09;模板類繼承模板參數給出的基類&#xff08;不能是模板類&#xff09;。 示…