• 【autodesk】浏览器中渲染rvt模型


    使用Forge完成渲染

    Forge是什么 为什么能够渲染出来rvt模型

    • Forge是由Autodesk开发的一套云端开发平台和工具集。
    • 在Forge平台中,有一个名为"Model Derivative"的服务,它可以将包括RVT(Revit)在内的多种BIM(Building Information Modeling)文件格式转换为可在Web上浏览和渲染的格式。
    • 具体来说,"Model Derivative"服务可以将RVT(Revit)文件转换为SVF(Scalable Vector Graphics)格式。
    • SVF是一种基于Web的轻量级3D模型表示格式,可以实现高性能的3D模型渲染和交互。通过将RVT文件转换为SVF格式,可以在Web端使用Forge提供的Viewer组件加载和展示RVT模型

    Forge与Autodesk的关系

    • Autodesk是一家设计软件公司,Forge可以视为Autodesk的云端扩展

    渲染步骤:

    首先要注册autodesk平台,并创建项目 获取自己的client_id与client_secret

    官网地址:Autodesk Platform Services (formerly Forge)

    如下图:

    配置postman环境 

    下面我们演示通过postman上传模型到Forge云端,然后配置Forge的js渲染出来

    post环境文件:

    BIM.postman collection.json

    1. {
    2. "info": {
    3. "_postman_id": "aedeb5db-ab5a-4b0e-ba31-d329f6ef66ba",
    4. "name": "Beijing-Workshop",
    5. "schema": "https://schema.getpostman.com/json/collection/v2.0.0/collection.json",
    6. "_exporter_id": "24665034"
    7. },
    8. "item": [
    9. {
    10. "name": "1获取access token",
    11. "event": [
    12. {
    13. "listen": "test",
    14. "script": {
    15. "exec": [
    16. "var data = JSON.parse(responseBody);",
    17. "postman.setEnvironmentVariable(\"access_token\", data.access_token);",
    18. "postman.setEnvironmentVariable(\"expires_in\", data.expires_in);",
    19. "postman.setEnvironmentVariable(\"token_type\", data.token_type);"
    20. ],
    21. "type": "text/javascript"
    22. }
    23. }
    24. ],
    25. "request": {
    26. "method": "POST",
    27. "header": [
    28. {
    29. "key": "Content-Type",
    30. "value": "application/x-www-form-urlencoded"
    31. }
    32. ],
    33. "body": {
    34. "mode": "urlencoded",
    35. "urlencoded": [
    36. {
    37. "key": "client_id",
    38. "value": "{{client_id}}",
    39. "type": "text"
    40. },
    41. {
    42. "key": "client_secret",
    43. "value": "{{client_secret}}",
    44. "type": "text"
    45. },
    46. {
    47. "key": "grant_type",
    48. "value": "client_credentials",
    49. "type": "text"
    50. },
    51. {
    52. "key": "scope",
    53. "value": "data:read data:write bucket:create bucket:read",
    54. "type": "text"
    55. },
    56. {
    57. "key": "expires_in",
    58. "value": "360000",
    59. "type": "text"
    60. }
    61. ]
    62. },
    63. "url": "{{base_domain}}/authentication/v1/authenticate"
    64. },
    65. "response": []
    66. },
    67. {
    68. "name": "2创建的存储桶(bucket)",
    69. "event": [
    70. {
    71. "listen": "prerequest",
    72. "script": {
    73. "exec": [
    74. "if (request.data) {",
    75. " var requestData = JSON.parse(request.data);",
    76. " postman.setEnvironmentVariable(\"bucketKey\", requestData.bucketKey);",
    77. " postman.setEnvironmentVariable(\"bucketPolicy\", requestData.policyKey);",
    78. "}"
    79. ],
    80. "type": "text/javascript"
    81. }
    82. }
    83. ],
    84. "request": {
    85. "method": "POST",
    86. "header": [
    87. {
    88. "key": "Authorization",
    89. "value": "Bearer {{access_token}}"
    90. },
    91. {
    92. "key": "Content-Type",
    93. "value": "application/json"
    94. }
    95. ],
    96. "body": {
    97. "mode": "raw",
    98. "raw": "{\n \"bucketKey\":\"ac-persistent-bucket-test8\",\n \"policyKey\":\"persistent\"\n}"
    99. },
    100. "url": "{{base_domain}}/oss/v2/buckets"
    101. },
    102. "response": []
    103. },
    104. {
    105. "name": "3 查看bucket是否创建成功",
    106. "request": {
    107. "method": "GET",
    108. "header": [
    109. {
    110. "key": "Authorization",
    111. "value": "Bearer {{access_token}}"
    112. }
    113. ],
    114. "url": {
    115. "raw": "{{base_domain}}/oss/v2/buckets?limit=10",
    116. "host": [
    117. "{{base_domain}}"
    118. ],
    119. "path": [
    120. "oss",
    121. "v2",
    122. "buckets"
    123. ],
    124. "query": [
    125. {
    126. "key": "limit",
    127. "value": "10"
    128. }
    129. ]
    130. }
    131. },
    132. "response": []
    133. },
    134. {
    135. "name": "4往bucket里放置object模型",
    136. "event": [
    137. {
    138. "listen": "test",
    139. "script": {
    140. "exec": [
    141. "if (responseCode.code === 200) {",
    142. " var data = JSON.parse(responseBody);",
    143. " postman.setEnvironmentVariable(\"urn\", data.objectId);",
    144. " postman.setEnvironmentVariable(\"urnBase64\", window.btoa(data.objectId));",
    145. " postman.setEnvironmentVariable(\"file_location\", data.location);",
    146. "}",
    147. ""
    148. ],
    149. "type": "text/javascript"
    150. }
    151. }
    152. ],
    153. "request": {
    154. "method": "PUT",
    155. "header": [
    156. {
    157. "key": "Authorization",
    158. "value": "Bearer {{access_token}}"
    159. }
    160. ],
    161. "body": {
    162. "mode": "file",
    163. "file": {
    164. "src": "/C:/Users/ac135/Desktop/rvtText/data/textOne.rvt"
    165. }
    166. },
    167. "url": "{{base_domain}}/oss/v2/buckets/{{bucketKey}}/objects/aggregate-1.rvt"
    168. },
    169. "response": []
    170. },
    171. {
    172. "name": "5检查对象模型是否成功上传",
    173. "request": {
    174. "method": "GET",
    175. "header": [
    176. {
    177. "key": "Authorization",
    178. "value": "Bearer {{access_token}}"
    179. }
    180. ],
    181. "url": "{{base_domain}}/oss/v2/buckets/{{bucketKey}}/objects"
    182. },
    183. "response": []
    184. },
    185. {
    186. "name": "6将模型在云端转换成SVF格式",
    187. "event": [
    188. {
    189. "listen": "test",
    190. "script": {
    191. "exec": [
    192. "var data = JSON.parse(responseBody);",
    193. "",
    194. "var setEnvVar = function (tar, src) {",
    195. " if (!src) {",
    196. " return;",
    197. " }",
    198. " postman.setEnvironmentVariable(tar, src);",
    199. "}",
    200. "",
    201. "if (data) {",
    202. " if (data.urn) {",
    203. " setEnvVar(\"urnBase64\", data.urn);",
    204. " }",
    205. "}"
    206. ],
    207. "type": "text/javascript"
    208. }
    209. }
    210. ],
    211. "request": {
    212. "method": "POST",
    213. "header": [
    214. {
    215. "key": "Authorization",
    216. "value": "Bearer {{access_token}}"
    217. },
    218. {
    219. "key": "Content-Type",
    220. "value": "application/json"
    221. },
    222. {
    223. "key": "x-ads-force",
    224. "value": "true"
    225. }
    226. ],
    227. "body": {
    228. "mode": "raw",
    229. "raw": "{\n \"input\": {\n \"urn\": \"{{urnBase64}}\" \n },\n \"output\": {\n \"destination\": {\n \"region\": \"us\"\n },\n \"formats\": [\n {\n \"type\": \"svf\",\n \"views\":[\"2d\", \"3d\"]\n }]\n }\n}"
    230. },
    231. "url": "{{base_domain}}/modelderivative/v2/designdata/job"
    232. },
    233. "response": []
    234. },
    235. {
    236. "name": "7检查模型是否转化完成",
    237. "request": {
    238. "method": "GET",
    239. "header": [
    240. {
    241. "key": "Authorization",
    242. "value": "Bearer {{access_token}}"
    243. },
    244. {
    245. "key": "Accept",
    246. "value": "application/vnd.api+json,application/json"
    247. }
    248. ],
    249. "url": "{{base_domain}}/modelderivative/v2/designdata/{{urnBase64}}/manifest"
    250. },
    251. "response": []
    252. },
    253. {
    254. "name": "04-POST job",
    255. "event": [
    256. {
    257. "listen": "test",
    258. "script": {
    259. "type": "text/javascript",
    260. "exec": [
    261. "var data = JSON.parse(responseBody);",
    262. "",
    263. "",
    264. "if (data) {",
    265. " if (data.urn) {",
    266. " postman.setEnvironmentVariable(\"urnBase64\", data.urn);",
    267. " }",
    268. "}"
    269. ]
    270. }
    271. }
    272. ],
    273. "request": {
    274. "method": "POST",
    275. "header": [
    276. {
    277. "key": "Authorization",
    278. "value": "Bearer {{access_token}}"
    279. },
    280. {
    281. "key": "Content-Type",
    282. "value": "application/json"
    283. },
    284. {
    285. "key": "x-ads-force",
    286. "value": "true"
    287. }
    288. ],
    289. "body": {
    290. "mode": "raw",
    291. "raw": "{\n \"input\": {\n \"urn\": \"{{urnBase64}}\" \n },\n \"output\": {\n \"destination\": {\n \"region\": \"us\"\n },\n \"formats\": [\n {\n \"type\": \"svf\",\n \"views\":[\"2d\", \"3d\"]\n }]\n }\n}"
    292. },
    293. "url": "{{base_domain}}/modelderivative/v2/designdata/job"
    294. },
    295. "response": []
    296. },
    297. {
    298. "name": "06-GET metadata",
    299. "request": {
    300. "method": "GET",
    301. "header": [
    302. {
    303. "key": "Authorization",
    304. "value": "Bearer {{access_token}}"
    305. }
    306. ],
    307. "url": "{{base_domain}}/modelderivative/v2/designdata/{{urnBase64}}/metadata"
    308. },
    309. "response": []
    310. },
    311. {
    312. "name": "07-GET metadata/​:guid",
    313. "request": {
    314. "method": "GET",
    315. "header": [
    316. {
    317. "key": "Authorization",
    318. "value": "Bearer {{access_token}}"
    319. },
    320. {
    321. "key": "Accept-Encoding",
    322. "value": "gzip"
    323. }
    324. ],
    325. "url": "{{base_domain}}/modelderivative/v2/designdata/{{urnBase64}}/metadata/{{metadata_guid}}"
    326. },
    327. "response": []
    328. },
    329. {
    330. "name": "08-GET :urn/metadata/:guid/properties",
    331. "request": {
    332. "method": "GET",
    333. "header": [
    334. {
    335. "key": "Authorization",
    336. "value": "Bearer {{access_token}}"
    337. }
    338. ],
    339. "url": "{{base_domain}}/modelderivative/v2/designdata/{{urnBase64}}/metadata/{{metadata_guid}}/properties"
    340. },
    341. "response": []
    342. },
    343. {
    344. "name": "09-bucket details",
    345. "event": [
    346. {
    347. "listen": "test",
    348. "script": {
    349. "type": "text/javascript",
    350. "exec": [
    351. "if (responseCode.code === 200 && responseBody) {",
    352. " var data = JSON.parse(responseBody);",
    353. " postman.setEnvironmentVariable(\"bucketKey\", data.bucketKey);",
    354. "}"
    355. ]
    356. }
    357. }
    358. ],
    359. "request": {
    360. "method": "GET",
    361. "header": [
    362. {
    363. "key": "Authorization",
    364. "value": "Bearer {{access_token}}"
    365. }
    366. ],
    367. "url": "{{base_domain}}/oss/v2/buckets/{{bucketKey}}/details"
    368. },
    369. "response": []
    370. },
    371. {
    372. "name": "12-GET formats",
    373. "request": {
    374. "method": "GET",
    375. "header": [
    376. {
    377. "key": "Authorization",
    378. "value": "Bearer {{access_token}}"
    379. }
    380. ],
    381. "url": "{{base_domain}}/modelderivative/v2/designdata/formats"
    382. },
    383. "response": []
    384. }
    385. ]
    386. }

    BIM.postman environment,.json

    1. {
    2. "id": "63cf71cf-bae6-411f-8e53-7319cf62fd9a",
    3. "name": "Beijing-Workshop",
    4. "values": [
    5. {
    6. "key": "base_domain",
    7. "value": "https://developer.api.autodesk.com",
    8. "type": "text",
    9. "enabled": true
    10. },
    11. {
    12. "key": "client_id",
    13. "value": "xxxxxxxxx",
    14. "type": "text",
    15. "enabled": true
    16. },
    17. {
    18. "key": "client_secret",
    19. "value": "xxxxxxxxxxx",
    20. "type": "text",
    21. "enabled": true
    22. },
    23. {
    24. "key": "urnBase64",
    25. "value": "dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6YWMtcGVyc2lzdGVudC1idWNrZXQtdGVzdDMvYWdncmVnYXRlLTEucnZ0",
    26. "type": "text",
    27. "enabled": true
    28. },
    29. {
    30. "key": "access_token",
    31. "value": "eyJhbGciOiJIUzI1NiIsImtpZCI6Imp3dF9zeW1tZXRyaWNfa2V5In0.eyJjbGllbnRfaWQiOiJNbDhXdWJFdW52WVRaRk1za2xpQ200YnZCM0dkREVibyIsImV4cCI6MTUyNjExNDc3OCwic2NvcGUiOlsiZGF0YTpyZWFkIiwiZGF0YTp3cml0ZSIsImJ1Y2tldDpjcmVhdGUiLCJidWNrZXQ6cmVhZCJdLCJhdWQiOiJodHRwczovL2F1dG9kZXNrLmNvbS9hdWQvand0ZXhwNjAiLCJqdGkiOiIxMEV2aEVpcGhQMGszTm9FNkFOa2NnR1pKOVJUaUhDazA3dXhWMDFFc1R1M2twS2tVNnB4a2d5d3A5QXBFakpDIn0.prPXmCc9e1oxZcPFSEgPOlonHG8po16RdzDciborQlg",
    32. "type": "text",
    33. "enabled": true
    34. },
    35. {
    36. "key": "guid",
    37. "value": "57873878-6d98-b389-aa22-fead1053823f",
    38. "type": "text",
    39. "enabled": true
    40. },
    41. {
    42. "key": "bucketKey",
    43. "value": "xiaodong-persistent-bucket-test8",
    44. "type": "text",
    45. "enabled": true
    46. },
    47. {
    48. "key": "guid",
    49. "value": "e22cc916-cabd-4b97-9ccd-1ab1e613f707",
    50. "type": "text",
    51. "enabled": true
    52. },
    53. {
    54. "key": "objectKey",
    55. "value": "RevitNative.rvt",
    56. "type": "text",
    57. "enabled": true
    58. },
    59. {
    60. "key": "expires_in",
    61. "value": "3599",
    62. "type": "text",
    63. "enabled": true
    64. },
    65. {
    66. "key": "token_type",
    67. "value": "Bearer",
    68. "type": "text",
    69. "enabled": true
    70. },
    71. {
    72. "key": "bucketPolicy",
    73. "value": "persistent",
    74. "type": "text",
    75. "enabled": true
    76. },
    77. {
    78. "key": "urn",
    79. "value": "urn:adsk.objects:os.object:xiaodong-persistent-bucket-test8/workshop-2.rvt",
    80. "type": "text",
    81. "enabled": true
    82. },
    83. {
    84. "key": "file_location",
    85. "value": "https://developer.api.autodesk.com/oss/v2/buckets/xiaodong-persistent-bucket-test8/objects/workshop-2.rvt",
    86. "type": "text",
    87. "enabled": true
    88. }
    89. ],
    90. "_postman_variable_scope": "environment",
    91. "_postman_exported_at": "2023-07-15T15:06:21.850Z",
    92. "_postman_exported_using": "Postman/10.16.0"
    93. }

     client_secret与client_id记住改成自己的,然后就开始用postman请求上传了

    获取access token

    https://developer.api.autodesk.com/authentication/v1/authenticate

    是用于获取 Autodesk API 的访问令牌(access token)的认证

    请求中包含必要的认证信息

    • 客户端 ID(client_id)
    • 客户端密钥(client_secret) 
    • grant_type:授权类型,通常为 "client_credentials"(客户端凭据模式)
    • scope:请求的权限范围,用空格分隔多个权限(如 "data:read data:write")
    • expires_in:设置合适的过期时间,单位毫秒

    响应结果:

    创建 Autodesk Forge 中的存储桶(bucket) 

    https://developer.api.autodesk.com/oss/v2/buckets

    请求中包含必要的认证信息:

    • Authorization:Authorization: Bearer {{access_token}}
    • bucketKey:存储桶的唯一标识符,它必须是全局唯一的。可以使用小写字母、数字、连字符 - 和下划线 _ 来命名。长度应在3到128个字符之间。
    • policyKey:存储桶的访问策略。默认为 transient,表示存储桶中的对象在30天后过期; persistent,表示永久保存

     响应结果:

     查看bucket是否创建成功

    https://developer.api.autodesk.com/oss/v2/buckets

    请求中包含必要的认证信息:

    • Authorization:Authorization: Bearer {{access_token}}

    请求可选的参数信息:

    • limit:指定要返回的存储桶数量的限制。例如,返回最多 10 个存储桶,默认为 10

     响应结果:

     往bucket里放置object模型

    https://developer.api.autodesk.com/oss/v2/buckets/{bucketKey}/objects/{objectName}

     请求中包含必要的认证信息:

    • Authorization:Authorization: Bearer {{access_token}}
    • 选择需要放置的rvt模型
    • objectName:每个文件在存储桶中都有一个唯一的标识符

     响应结果:

     检查对象模型是否成功上传到 Autodesk Forge 存储桶(bucket)中

    https://developer.api.autodesk.com/oss/v2/buckets/{{bucketKey}}/objects

    请求中包含必要的认证信息:

    • Authorization:Authorization: Bearer {{access_token}}
    • bucketKey:查询的存储桶的实际标识符

     响应结果:

    将模型在云端转换成SVF格式 

    https://developer.api.autodesk.com/modelderivative/v2/designdata/job

    请求中包含必要的认证信息:

    • Authorization:Authorization: Bearer {{access_token}}
    • input:指定要转换的对象的 URN(Uniform Resource Name)。将 object_id 的 URN 作为输入。
    • output:指定要生成的输出格式和文件类型。在这里,你可以指定 SVF 格式作为输出。例如,{"formats": [{"type": "svf", "views": ["2d", "3d"]}]}

    备注:input中的urn是 objectId转化为Base64格式

    响应结果:

    检查模型是否转化完成

    https://developer.api.autodesk.com/modelderivative/v2/designdata/{base64_urn}/manifest

    请求中包含必要的认证信息:

    • Authorization:Authorization: Bearer {{access_token}}
    • base64_urn:经过 Base64 编码的 URN

    响应结果:

     图一表示进度,图二代表成功

    浏览器渲染:

    html渲染模板   将accessToken与documentId替换掉就行

    1. html>
    2. <html>
    3. <head>
    4. <title>Autodesk Forge: 3D Viewer App Sampletitle>
    5. <meta http-equiv="cache-control" content="max-age=0" />
    6. <meta http-equiv="cache-control" content="no-cache" />
    7. <meta http-equiv="expires" content="0" />
    8. <meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
    9. <meta http-equiv="pragma" content="no-cache" />
    10. <script src="https://code.jquery.com/jquery-3.3.1.min.js">script>
    11. <link rel="stylesheet" href="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.51/style.min.css"
    12. type="text/css">
    13. <script src="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.51/viewer3D.min.js">script>
    14. <style>
    15. /** Just simple CSS styling to make this page a little nicer **/
    16. body {
    17. margin: 0;
    18. padding: 0;
    19. }
    20. style>
    21. head>
    22. <body>
    23. <div id="MyViewerDiv">div>
    24. <script>
    25. var viewer;
    26. var options = {
    27. env: 'AutodeskProduction',
    28. api: 'derivativeV2', // TODO: for models uploaded to EMEA change this option to 'derivativeV2_EU'
    29. // getAccessToken: getForgeToken
    30. accessToken: 'eyJhbGciOiJSUzI1NiIsImtpZCI6IlU3c0dGRldUTzlBekNhSzBqZURRM2dQZXBURVdWN2VhIiwicGkuYXRtIjoiN3ozaCJ9.eyJzY29wZSI6WyJkYXRhOnJlYWQiLCJkYXRhOndyaXRlIiwiYnVja2V0OmNyZWF0ZSIsImJ1Y2tldDpyZWFkIl0sImNsaWVudF9pZCI6IkpCcldjc3p3RVZCQ0dNMm5sY1J6N0tIZXZTbXpYUXM0IiwiYXVkIjoiaHR0cHM6Ly9hdXRvZGVzay5jb20vYXVkL2Fqd3RleHA2MCIsImp0aSI6ImJjWXBRalcwekh5aTZyUEd3QU1kNjdjamlWS1Q2dDZIYXNqcjFmOXR4OUExeGhZY05JWkhINVlibkdDeHVaTWoiLCJleHAiOjE2ODk5MTI0ODB9.JdpIFQAmWmsGc-t2g3tpU677G1Y11RwF4ndTxbwSa4hE5tOjYtLsMK7pR-jGGWIHAEHUkScvDixQWFIUG_o5UWpwhAdH7r06126QhGFNk_Wf1d8OvoDknqdKt9aXns_1xvxucOdPs3VkJ8BWH6j65B3fxZ7GB5jub3zeF7sGuYd1zBL9FdAcQ5_uQUBpEXh8uP4yZ_Y3yDe_mnTx2OxTMyRXsHw7quWjtxXDQXweGq0xDn3ENayOTkYnsru3_GJmGXUE4b-Zl1csHENJyyegkDqrfbaLbMeKagCWxY-RnCikmg80iWDqOd6KvIejRbQdqpjdQWz4i3Qx6Wnj6Lzf4w'
    31. };
    32. // var documentId = 'urn:' + getUrlParameter('urn');
    33. var documentId = 'urn:dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6YWMtcGVyc2lzdGVudC1idWNrZXQtdGVzdDMvYWdncmVnYXRlLTEucnZ0'
    34. // 初始化和加载文档的部分
    35. Autodesk.Viewing.Initializer(options, function onInitialized() {
    36. // Find the element where the 3d viewer will live.
    37. var htmlElement = document.getElementById('MyViewerDiv');
    38. if (htmlElement) {
    39. // Create and start the viewer in that element
    40. viewer = new Autodesk.Viewing.GuiViewer3D(htmlElement);
    41. viewer.start();
    42. // Load the document into the viewer.
    43. Autodesk.Viewing.Document.load(documentId, onDocumentLoadSuccess, onDocumentLoadFailure);
    44. $('.adsk-viewing-viewer').css('height', '80%')
    45. $('.adsk-viewing-viewer').css('width', '42%')
    46. }
    47. });
    48. /**
    49. * 加载模型的回调函数
    50. */
    51. function onDocumentLoadSuccess(doc) {
    52. // Load the default viewable geometry into the viewer.
    53. // Using the doc, we have access to the root BubbleNode,
    54. // which references the root node of a graph that wraps each object from the Manifest JSON.
    55. var viewable = doc.getRoot().getDefaultGeometry();
    56. if (viewable) {
    57. viewer.loadDocumentNode(doc, viewable).then(function (result) {
    58. console.log('Viewable Loaded!');
    59. }).catch(function (err) {
    60. console.log('Viewable failed to load.');
    61. console.log(err);
    62. }
    63. )
    64. }
    65. }
    66. /**
    67. * 文档加载失败时的回调函数
    68. */
    69. function onDocumentLoadFailure(viewerErrorCode) {
    70. console.error('onDocumentLoadFailure() - errorCode: ' + viewerErrorCode);
    71. jQuery('#MyViewerDiv').html('

      Translation in progress... Please try refreshing the page.

      '
      );
    72. }
    73. script>
    74. body>
    75. html>

    效果图如下:

    其他资源分享:

    视频教程:通过Forge十分钟实现Web端3D模型浏览_哔哩哔哩_bilibili

    有其他问题可以留言 或者私信 

  • 相关阅读:
    find 查找 Bazel 构建覆盖率文件的一个☝️坑
    Redis篇---第八篇
    [C#]C#调用cplex
    【做题小技巧】乘法得出的数超过int怎么办
    【ADI低功耗2k代码】基于ADuCM4050的ADXL363、TMP75的加速度、温度检测及串口打印、蜂鸣器播放音乐(孤勇者)
    stl_stack_queue的模拟实现
    EasyAR使用
    无限猴子 歌唱王国 题解
    数据库&SQL
    【C#语音文字互转】.NET的TTS文本转语音合成
  • 原文地址:https://blog.csdn.net/weixin_52479803/article/details/131740763