-
Notifications
You must be signed in to change notification settings - Fork 0
/
content.json
1 lines (1 loc) · 282 KB
/
content.json
1
{"meta":{"title":"桀士","subtitle":"『桀士』","description":"我们追逐的绝不是别人的起点,而是每一个未知的明天!","author":"Jackie Tang(唐浩桀)","url":"https://tanghaojie.github.io","root":"/"},"pages":[{"title":"friends","date":"2018-12-12T13:25:30.000Z","updated":"2022-12-23T12:44:16.648Z","comments":true,"path":"friends/index.html","permalink":"https://tanghaojie.github.io/friends/index.html","excerpt":"","text":""},{"title":"categories","date":"2018-09-30T09:25:30.000Z","updated":"2022-12-23T12:44:16.647Z","comments":true,"path":"categories/index.html","permalink":"https://tanghaojie.github.io/categories/index.html","excerpt":"","text":""},{"title":"about","date":"2018-09-30T09:25:30.000Z","updated":"2022-12-23T12:44:16.647Z","comments":true,"path":"about/index.html","permalink":"https://tanghaojie.github.io/about/index.html","excerpt":"","text":""},{"title":"contact","date":"2018-09-30T09:25:30.000Z","updated":"2022-12-23T12:44:16.647Z","comments":true,"path":"contact/index.html","permalink":"https://tanghaojie.github.io/contact/index.html","excerpt":"","text":""},{"title":"tags","date":"2018-09-30T10:23:38.000Z","updated":"2022-12-23T12:44:16.717Z","comments":true,"path":"tags/index.html","permalink":"https://tanghaojie.github.io/tags/index.html","excerpt":"","text":""}],"posts":[{"title":"线性代数复习","slug":"2022-2022-03-04-linear-algebra-review","date":"2022-03-04T13:43:23.000Z","updated":"2022-12-23T12:44:16.646Z","comments":true,"path":"2022/03/04/2022-2022-03-04-linear-algebra-review/","link":"","permalink":"https://tanghaojie.github.io/2022/03/04/2022-2022-03-04-linear-algebra-review/","excerpt":"","text":"序最近 GIS 很火啊,各种应用和引擎呈百花齐放的形式,之前的重心方向:地理信息框架、底层数据组织、业务应用模式都接触很多了,自己也做了简单的开源 Web GIS 应用以做代学,详情可见Github 仓库,后续的目标应该会集中在:显卡编程、GLSL、图形学上面,更偏底层一些,涉及到业务的更少,但能开拓的东西更多。 这块目标上随时都会涉及到线性代数的知识点,大学时候学习的线性代数这么多年没怎么用,已经基本还给老师了,所以很有必要进行一系列的回顾。故开此篇。 向量向量的基础内容博客以前写过了,就不重新写了,详见:基础内容和延伸内容 矩阵 矩阵向量表示我们可以用一个矩阵来表示向量,如一个二维向量可以这样表示: $ A = \\begin{pmatrix} x \\\\ y \\end{pmatrix} $ $ A^T = \\begin{pmatrix} x & y \\end{pmatrix} $ 转置矩阵 注:一般习惯用列向量来表示,用行向量表示也可以,本质上没有区别 叉乘的性质$\\vec{x} \\times \\vec{y} = +\\vec{z}$$\\vec{y} \\times \\vec{x} = -\\vec{z}$$\\vec{y} \\times \\vec{z} = +\\vec{x}$$\\vec{z} \\times \\vec{y} = -\\vec{x}$$\\vec{z} \\times \\vec{x} = +\\vec{y}$$\\vec{x} \\times \\vec{z} = -\\vec{y}$ 以上常用于定坐标系。 $\\vec{a} \\times \\vec{b} = -\\vec{b} \\times \\vec{a}$ $\\vec{a} \\times \\vec{a} = 0$ $\\vec{a} \\times (\\vec{b} + \\vec{c})= \\vec{a} \\times \\vec{b} + \\vec{a} \\times \\vec{c}$ $\\vec{a} \\times (k \\vec{b})= k(\\vec{a} \\times \\vec{b})$ 矩阵表示一个 m $\\times$ n 的数组 $(m :rows, n :columns)$,例: $ \\begin{pmatrix} 1 & 3 \\\\ 5 & 2 \\\\ 0 & 4 \\end{pmatrix} $ 矩阵相乘必须满足:$(M \\times {\\color{red}{N}}) ({\\color{red}{N}} \\times P) = (M \\times P)$ 如何计算结果矩阵的元素 (i, j) 是,A 矩阵的第 i 行和 B 矩阵的第 j 列 点乘的结果。 $$\\begin{pmatrix} 1&3 \\\\ 5&2 \\\\ 0&4 \\end{pmatrix} \\begin{pmatrix} 3&6&9&4 \\\\ 2&7&8&3 \\end{pmatrix} = \\begin{pmatrix} 9&27&33&13 \\\\ 19&44&61&26 \\\\ 8&28&32&12 \\end{pmatrix}$$ 矩阵乘法属性 不满足交换律$AB \\neq BA$ 结合律和分配率可用$(AB)C = A(BC)$$A(B+C) = AB + AC$$(A+B)C = AC + BC$ 变换缩放 Scale$$\\begin{bmatrix} x’ \\\\ y’ \\end{bmatrix} = \\begin{bmatrix} S_x&0 \\\\ 0&S_y \\end{bmatrix} \\begin{bmatrix} x \\\\ y\\end{bmatrix}$$ 剪切变换 Shear Matrix$$\\begin{bmatrix} x’ \\\\ y’ \\end{bmatrix} = \\begin{bmatrix} 1&a \\\\ b&1 \\end{bmatrix} \\begin{bmatrix} x \\\\ y\\end{bmatrix}$$ 旋转 Rotate一切旋转不作特别说明的,都是以原点$(0,0)$为轴,逆时针(CCW)进行旋转。 $$\\begin{bmatrix} x’ \\\\ y’ \\end{bmatrix} = \\begin{bmatrix} \\cos \\theta & -\\sin \\theta \\\\ \\sin \\theta & \\cos \\theta \\end{bmatrix} \\begin{bmatrix} x \\\\ y\\end{bmatrix}$$ 以上形式,我们称为线性变换$ x’ = ax + by $$ y’ = cx + dy $ $ \\begin{bmatrix} x’ \\\\ y’ \\end{bmatrix} = \\begin{bmatrix} a&b \\\\ c&d \\end{bmatrix} \\begin{bmatrix} x \\\\ y\\end{bmatrix} $ $ x’ = M x $ 平移 Translation平移 $(t_x, t_y)$的距离,则: $ x’ = x + t_x $$ y’ = y + t_y $ $ \\begin{bmatrix} x’ \\\\ y’ \\end{bmatrix} = \\begin{bmatrix} a&b \\\\ c&d \\end{bmatrix} \\begin{bmatrix} x \\\\ y\\end{bmatrix} + \\begin{bmatrix} t_x \\\\ t_y \\end{bmatrix} $ $ {\\color{red}{这是一个非线性变换}} $ 为了解决平移非线性变换的问题,使所有变换能统一计算。引入 齐次坐标 Homogenous Coordinates 齐次坐标 Homogenous Coordinates添加一个坐标,称为:w-coordinate 对于二维来说: 2D point = $ (x, y, {\\color{red}{1}})^T $ 2D vector = $ (x, y, {\\color{red}{0}})^T $ 通过 w-coordinate 的结果是 1 或 0,来验证 vector + vector = vector point - point = vector point + vector = point point + point = center point 在齐次坐标中,如果 $ \\begin{pmatrix} x \\\\ y \\\\ w \\end{pmatrix} $ 是一个 2D 点,我们可以把 w-coordinate 归一,$ \\begin{pmatrix} x/w \\\\ y/w \\\\ 1 \\end{pmatrix} $, $ w \\neq 0 $ 平移有了齐次坐标,平移就可以表示为: $ \\begin{pmatrix} x’ \\\\ y’ \\\\ w’ \\end{pmatrix} = \\begin{pmatrix} 1&0&t_x \\\\ 0&1&t_y \\\\ 0&0&1 \\end{pmatrix} \\cdot \\begin{pmatrix} x \\\\ y \\\\ 1 \\end{pmatrix} = \\begin{pmatrix} x+t_x \\\\ y+t_y \\\\ 1 \\end{pmatrix} $ 仿射变换 Affine Transformations仿射变换 = 线性变换 + 平移变换 $ \\begin{pmatrix} x’ \\\\ y’ \\end{pmatrix} = \\begin{pmatrix} a&b \\\\ c&d \\end{pmatrix} \\cdot \\begin{pmatrix} x \\\\ y \\end{pmatrix} + \\begin{pmatrix} x’ \\\\ y’ \\end{pmatrix} $ 使用齐次坐标 $ \\begin{pmatrix} x’ \\\\ y’ \\\\ 1 \\end{pmatrix} = \\begin{pmatrix} a&b&t_x \\\\ c&d&t_y \\\\ 0&0&1 \\end{pmatrix} \\cdot \\begin{pmatrix} x \\\\ y \\\\ 1 \\end{pmatrix} $ 可以看出变换矩阵的最后一行,始终是 0 0 1 组合变换 Composite Transform可以想象,使用旋转矩阵 R 和平移矩阵 T。先进行平移 T,再做旋转 R;和先进行旋转 R,再做平移 T,结果肯定是不一样的,既:$ RT \\neq TR $。 这也证明了,矩阵不满足交换律。(记住:旋转默认情况下以原点,逆时针进行) 一个复杂的组合变换: $ \\begin{pmatrix} x’ \\\\ y’ \\\\ 1 \\end{pmatrix} = A_n \\cdot \\cdot \\cdot A_2 \\cdot A_1 \\cdot \\begin{pmatrix} x \\\\ y \\\\ 1 \\end{pmatrix} $ 其中,$ A_n \\cdot \\cdot \\cdot A_2 \\cdot A_1 $,是多个变换矩阵。 由于矩阵乘法满足分配律,且这些矩阵相乘,最终还是一个矩阵,所以,组合变换用一个矩阵就可以进行表示。 3D 变换还是使用齐次坐标: 3D point = $ (x, y, z, {\\color{red}{1}})^T $ 3D vector = $ (x, y, z, {\\color{red}{0}})^T $ 一般地,$ (x, y, z, w) (w \\neq 0) $ ,代表 3 维坐标点:$ (x/w, y/w, z/w) $ 3D 的仿射变换,使用 $ 4 \\times 4 $矩阵表示: $ \\begin{pmatrix} x’ \\\\ y’ \\\\ z’ \\\\ 1 \\end{pmatrix} = \\begin{pmatrix} a&b&c&t_x \\\\ d&e&f&t_y \\\\ g&h&i&t_z \\\\ 0&0&0&1 \\end{pmatrix} \\cdot \\begin{pmatrix} x \\\\ y \\\\ z \\\\ 1 \\end{pmatrix} $ 顺序从上面文章中平移的公式: $ \\begin{bmatrix} x’ \\\\ y’ \\end{bmatrix} = \\begin{bmatrix} a&b \\\\ c&d \\end{bmatrix} \\begin{bmatrix} x \\\\ y\\end{bmatrix} + \\begin{bmatrix} t_x \\\\ t_y \\end{bmatrix} $ 可以看出,先做线性变换,再做平移。 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[],"tags":[],"author":null},{"title":"docker 安装部署 onlyoffice","slug":"2021-2021-12-16-docker-onlyoffce","date":"2021-12-16T08:49:09.000Z","updated":"2022-12-23T12:44:16.642Z","comments":true,"path":"2021/12/16/2021-2021-12-16-docker-onlyoffce/","link":"","permalink":"https://tanghaojie.github.io/2021/12/16/2021-2021-12-16-docker-onlyoffce/","excerpt":"","text":"安装 docker volume create onlyoffice_logs docker volume create onlyoffice_data docker run -itd -p 60081:80 -p 60441:443 --name onlyoffice --restart always -v onlyoffice_logs:/var/log/onlyoffice -v onlyoffice_data:/var/www/onlyoffice/Data onlyoffice/documentserver 启动 SSL将申请的证书命名为:onlyoffice.key 和 onlyoffice.crt 。 然后在上面创建的onlyoffice_data这个 volume 中创建certs文件夹,把这两个证书文件放进去。 把证书文件设置为只读 chmod 400 /app/onlyoffice/DocumentServer/data/certs/onlyoffice.key 重启容器就好了。 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[],"tags":[],"author":null},{"title":"国内git clone速度缓慢的解决办法汇总","slug":"2021-2021-12-15-gfw-git-clone-slow","date":"2021-12-15T13:10:48.000Z","updated":"2022-12-23T12:44:16.642Z","comments":true,"path":"2021/12/15/2021-2021-12-15-gfw-git-clone-slow/","link":"","permalink":"https://tanghaojie.github.io/2021/12/15/2021-2021-12-15-gfw-git-clone-slow/","excerpt":"","text":"改本地 host在网站 https://www.ipaddress.com 分别查询这两个域名所对应的最快 IP 地址: github.global.ssl.fastly.netgithub.com 然后在 host 里面做一下映射。 增大缓存大小 git config –global http.postBuffer 524288000 使用代理后面对应你代理软件的ip和端口 git config –global https.proxy http://127.0.0.1:1080git config –global https.proxy https://127.0.0.1:1080git config –global http.proxy ‘socks5://127.0.0.1:1080’git config –global https.proxy ‘socks5://127.0.0.1:1080’ 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[],"tags":[],"author":null},{"title":"nginx反向代理nextcloud开启ssl","slug":"2021-2021-12-14-nginx-nextcloud-ssl","date":"2021-12-14T12:57:27.000Z","updated":"2022-12-23T12:44:16.642Z","comments":true,"path":"2021/12/14/2021-2021-12-14-nginx-nextcloud-ssl/","link":"","permalink":"https://tanghaojie.github.io/2021/12/14/2021-2021-12-14-nginx-nextcloud-ssl/","excerpt":"","text":"docker nginx 安装 docker pull nginxdocker volume create nginx_configdocker run --name nginx-for-nextcloud --restart=always -p 8443:443 -p 8080:80 -v nginx_config:/etc/nginx -d nginx 拷贝证书到 nginx_config/_data 文件夹下对于 nginx 来说,是两个文件 *.key 和 *.crt 修改 nginx 代理配置upstream nextcloud { server 192.168.6.2:9000; } server { listen 80; listen 443 ssl; server_name jackietang.dynv6.net; ssl_certificate ./jackietang.dynv6.net_chain.crt; ssl_certificate_key ./jackietang.dynv6.net_key.key; location / { proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://nextcloud; proxy_redirect http:// https://; } } 修改 nextcloud 配置添加 'overwriteprotocol' => 'https', ,保证 nextcloud 协议正确性 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[],"tags":[],"author":null},{"title":"读取大疆照片中XMP元数据的RtkFlag信息","slug":"2021-2021-11-19-DJI-photo-xmp-data-rtkflag-reader","date":"2021-11-19T14:19:00.000Z","updated":"2022-12-23T12:44:16.641Z","comments":true,"path":"2021/11/19/2021-2021-11-19-DJI-photo-xmp-data-rtkflag-reader/","link":"","permalink":"https://tanghaojie.github.io/2021/11/19/2021-2021-11-19-DJI-photo-xmp-data-rtkflag-reader/","excerpt":"","text":"import os from PIL import Image from xml.dom.minidom import parseString def readXMPRtkFlag(filename): with Image.open(filename) as im: for segment, content in im.applist: if segment != 'APP1': continue marker, body = content.rsplit(b'\\x00', 1) if marker != b'http://ns.adobe.com/xap/1.0/': continue strBody = str(body, encoding='utf-8') doc = parseString(strBody) docRoot = doc.documentElement ele = docRoot.getElementsByTagName(\"rdf:Description\")[0] return ele.getAttribute('drone-dji:RtkFlag') return '' def main(): root = './' subs = os.listdir(root) with open('result.txt', 'w') as f: for sub in subs: path = os.path.join(root, sub) if not os.path.isfile(path): continue if not path.upper().endswith('JPG'): continue flag = readXMPRtkFlag(path) f.write(path + '\\t' + flag + '\\n') main() 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[],"tags":[],"author":null},{"title":"windows docker 安装部署 nextcloud","slug":"2021-2021-10-15-win-docker-nextcloud","date":"2021-10-15T14:44:14.000Z","updated":"2022-12-23T12:44:16.641Z","comments":true,"path":"2021/10/15/2021-2021-10-15-win-docker-nextcloud/","link":"","permalink":"https://tanghaojie.github.io/2021/10/15/2021-2021-10-15-win-docker-nextcloud/","excerpt":"","text":"拉取镜像 docker pull nextcloud 创建容器 docker run -d -p 9000:80 --restart always -v /mnt/d/docker/win-mount/nextcloud-data:/var/www/html/data -v nextcloud:/var/www/html --name nextcloud nextcloud 然后直接访问就行了。 手动添加文件后重新扫描命令 docker exec -u www-data nextcloud php occ files:scan --all 手动添加文件后 nextcloud 没有编辑权限 docker exec -u root nextcloud chown -R www-data /var/www/html/data 中文目录问题 docker exec -it nextcloud env LANG=C.UTF-8 /bin/bash 手动安装应用后设置权限 chown -R www-data:root maps # maps=应用名 配置后台任务 cron在宿主机执行: docker exec -u www-data -i nextcloud php -f /var/www/html/cron.php 测试是否能成功执行。 之后还是在宿主机,使用 crontab 创建定时任务: crontab -e 在文本编辑器中输入(以下代表每五分钟执行一次): */5 * * * * docker exec --user www-data -i nextcloud php -f /var/www/html/cron.php 查看定时任务: crontab -l 地图应用安装后手动全局扫描图片 docker exec -u www-data nextcloud php occ maps:scan-photos 设置缩略图容器内安装 ffmpeg: apt install ffmpeg -y 修改 config.php 文件,添加: 'enable_previews' => true, 'enabledPreviewProviders' => array ( 0 => 'OC\\\\Preview\\\\Image', 1 => 'OC\\\\Preview\\\\Movie', 2 => 'OC\\\\Preview\\\\TXT', ), 电子邮件服务器先去 QQ 邮箱-设置-账户-开启 SMTP 服务 然后去 nextcloud 设置: 来自地址:你的 QQ 邮箱认证方法:登录,勾上需要认证服务器地址:smtp.qq.com : 465证书:你的 QQ 邮箱,密码是开启 SMTP 服务时给你的密钥 重启容器 wsl 开启 cron.log sudo vim /etc/rsyslog.d/50-default.conf 将 cron 前面的注释符去掉后,重启相关服务 sudo service rsyslog restart sudo service cron restart 之后在/var/log下面,就有cron.log文件了 您的安装没有设置默认的电话区域config.pho添加一行:'default_phone_region' => 'CN', 此实例中的 php-imagick 模块不支持 SVG 进入容器 apt search libmagickcore- #查找包 apt install libmagickcore-6.q16-6-extra #安装包 退出容器,重启 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[],"tags":[],"author":null},{"title":"windows docker 安装部署 postgres","slug":"2021-2021-10-15-win-docker-postgres","date":"2021-10-15T13:49:27.000Z","updated":"2022-12-23T12:44:16.641Z","comments":true,"path":"2021/10/15/2021-2021-10-15-win-docker-postgres/","link":"","permalink":"https://tanghaojie.github.io/2021/10/15/2021-2021-10-15-win-docker-postgres/","excerpt":"","text":"拉取镜像 docker pull postgres 创建 data volume docker volume create postgres-data windows 版本的 docker,默认 volume 存放位置在:\\\\wsl$\\docker-desktop-data\\version-pack-data\\community\\docker\\volumes实际位置一般在C:\\Users\\UserName\\AppData\\Roaming\\Microsoft\\Windows\\Network Shortcuts\\docker volumes 创建容器 docker run -it --name postgres --restart always -e POSTGRES_PASSWORD='abc123' -e ALLOW_IP_RANGE=0.0.0.0/0 -v postgres-data:/var/lib/postgresql/data -p 5432:5432 -d postgres (可选)进入 postgres 容器 docker exec -it postgres bash (可选)切换用户,登录数据库 su postgrespsql -U postgres -W 配置数据库很多种办法: 1.直接去 windows 映射的 volumeC:\\Users\\UserName\\AppData\\Roaming\\Microsoft\\Windows\\Network Shortcuts\\docker volumes\\docker-desktop-data\\version-pack-data\\community\\docker\\volumes\\postgres-data\\_data\\ 2.命令行到/var/lib/postgresql/data 下面的pg_hba.conf文件: # IPv4 local connections: host all all 127.0.0.1/32 trust host all all 0.0.0.0/0 trust 添加任何 ip 地址可以访问 重启容器 docker restart postgres 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[],"tags":[],"author":null},{"title":"Cesium 相关概念速记","slug":"2021-cesium-2021-09-16-cesium-concepts-shrthand","date":"2021-09-16T13:04:49.000Z","updated":"2022-12-23T12:44:16.646Z","comments":true,"path":"2021/09/16/2021-cesium-2021-09-16-cesium-concepts-shrthand/","link":"","permalink":"https://tanghaojie.github.io/2021/09/16/2021-cesium-2021-09-16-cesium-concepts-shrthand/","excerpt":"","text":"深度检测viewer.scene.globe.depthTestAgainstTerrain:渲染时确保不同远近物体的透视关系;如果不启用深度检测,物体的叠加顺序取决于先后的渲染顺序。 多视锥渲染Cesium 原来的多视锥体实现是使用 3 个视锥体,其分割距离分别是 [1, 1000],[1000, 100w], [100w, 10e] 米。这些视锥体从后到前(相对于相机)的顺序进行渲染,并且在每个视锥体深度缓存中被清除。渲染开始时,根据绘制命令(DrawCommands)的包裹范围(boundingVolume),将绘制命令放置在一个或多个圆锥体中。在两个视锥边界的绘制命令则两边都会绘制一次,为了优化重复绘制,Cesium 从视点触发,根据最近和最远的包裹范围计算合适的近平面和远平面距离,以最大程度减少视锥。 对数深度viewer.scene.logarithmicDepthFarToNearRatio:对数深度是因为 cesium 的坐标范围过大,渲染的时候深度缓冲的精度不够(距离越远误差越多,非线性),cesium 既要保证近处可见,也要保证远处的东西深度覆盖正确,这就是一个两难的选择。对数深度是一种技术,可以把深度的递减修改为对数变化,这样有利满足上面说的效果,当然它也有弊端,过大的平面容易被裁减。 优化随笔数据:模型优化,精简、lod 层级设置、硬件:提高网速、提升显卡代码:设置最大屏幕空间误差、启用 indexDB 、降低分辨率 dpr 优化、加上跳跃层次细节、关闭阴影、设置加载 3dtiles 的最大最小层级、设置瓦片的请求范围、开启背面剔除等一系列措施搞上去。 通视分析(射线法)https://sandcastle.cesium.com/?src=development%2FPick%20From%20Ray.html&label=Development Primitives.remove 后不默认执行 destroyviewer.scene.primitives.destroyPrimitives = false 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[],"tags":[],"author":null},{"title":"docker-kms-server","slug":"2021-2021-09-13-docker-kms-server","date":"2021-09-13T11:40:31.000Z","updated":"2022-12-23T12:44:16.641Z","comments":true,"path":"2021/09/13/2021-2021-09-13-docker-kms-server/","link":"","permalink":"https://tanghaojie.github.io/2021/09/13/2021-2021-09-13-docker-kms-server/","excerpt":"","text":"安装 docker vlmscd docker pull mikolatero/vlmcsddocker run -d -p 1688:1688 –restart=always –name=”vlmcsd” mikolatero/vlmcsd 打开防火墙和映射 1688 端口查找对应的 GVLK微软官方 GVLK 列表: Windows:中文:https://docs.microsoft.com/zh-cn/windows-server/get-started/kms-client-activation-keys 英文:https://docs.microsoft.com/en-us/windows-server/get-started/kms-client-activation-keys Officehttps://docs.microsoft.com/zh-cn/DeployOffice/vlactivation/gvlks?redirectedfrom=MSDN 激活 windows管理员运行 Power shell # 这是 win10 专业版的 GVLKslmgr /ipk W269N-WFGWX-YVC9B-4J6C9-T83GXslmgr /skms ip:portslmgr /ato 激活 Office管理员运行 Power shell x86: cd c:\\Program Files (x86)\\Microsoft Office\\Office16 x86_64: cd c:\\Program Files\\Microsoft Office\\Office16 然后: cscript ospp.vbs /sethst:ipcscript ospp.vbs /setprt:portcscript ospp.vbs /inpkey:xxxxx-xxxxx-xxxxx-xxxxx-xxxxxcscript ospp.vbs /act 可以把以上命令保存为.bat文件,当激活过期以后再次用管理员运行就好了 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[],"tags":[],"author":null},{"title":"ss快速部署","slug":"2021-2021-08-16-ss-deploy","date":"2021-08-16T13:17:52.000Z","updated":"2022-12-23T12:44:16.641Z","comments":true,"path":"2021/08/16/2021-2021-08-16-ss-deploy/","link":"","permalink":"https://tanghaojie.github.io/2021/08/16/2021-2021-08-16-ss-deploy/","excerpt":"","text":"安装```bash#!/usr/bin/env bashPATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/binexport PATH#=================================================================# System Required: CentOS 6+, Debian 7+, Ubuntu 12+Description: One click Install Shadowsocks-Python serverAuthor: Teddysun i@teddysun.comThanks: @clowwindy https://twitter.com/clowwindyIntro: https://teddysun.com/342.html#=================================================================# clearechoecho “#############################################################”echo “# One click Install Shadowsocks-Python server #”echo “# Intro: https://teddysun.com/342.html #”echo “# Author: Teddysun i@teddysun.com #”echo “# Github: https://github.com/shadowsocks/shadowsocks #”echo “#############################################################”echo libsodium_file=”libsodium-1.0.18”libsodium_url=”https://github.com/jedisct1/libsodium/releases/download/1.0.18-RELEASE/libsodium-1.0.18.tar.gz“ Current foldercur_dir=pwd Stream Ciphersciphers=(aes-256-gcmaes-192-gcmaes-128-gcmaes-256-ctraes-192-ctraes-128-ctraes-256-cfbaes-192-cfbaes-128-cfbcamellia-128-cfbcamellia-192-cfbcamellia-256-cfbchacha20-ietf-poly1305chacha20-ietfchacha20rc4-md5) Colorred=’\\033[0;31m’green=’\\033[0;32m’yellow=’\\033[0;33m’plain=’\\033[0m’ Make sure only root can run our script[[ $EUID -ne 0 ]] && echo -e “[${red}Error${plain}] This script must be run as root!” && exit 1 Disable selinuxdisable_selinux(){ if [ -s /etc/selinux/config ] && grep ‘SELINUX=enforcing’ /etc/selinux/config; then sed -i ‘s/SELINUX=enforcing/SELINUX=disabled/g’ /etc/selinux/config setenforce 0 fi} #Check systemcheck_sys(){ local checkType=$1 local value=$2 local release='' local systemPackage='' if [[ -f /etc/redhat-release ]]; then release=\"centos\" systemPackage=\"yum\" elif grep -Eqi \"debian|raspbian\" /etc/issue; then release=\"debian\" systemPackage=\"apt\" elif grep -Eqi \"ubuntu\" /etc/issue; then release=\"ubuntu\" systemPackage=\"apt\" elif grep -Eqi \"centos|red hat|redhat\" /etc/issue; then release=\"centos\" systemPackage=\"yum\" elif grep -Eqi \"debian|raspbian\" /proc/version; then release=\"debian\" systemPackage=\"apt\" elif grep -Eqi \"ubuntu\" /proc/version; then release=\"ubuntu\" systemPackage=\"apt\" elif grep -Eqi \"centos|red hat|redhat\" /proc/version; then release=\"centos\" systemPackage=\"yum\" fi if [[ \"${checkType}\" == \"sysRelease\" ]]; then if [ \"${value}\" == \"${release}\" ]; then return 0 else return 1 fi elif [[ \"${checkType}\" == \"packageManager\" ]]; then if [ \"${value}\" == \"${systemPackage}\" ]; then return 0 else return 1 fi fi } Get versiongetversion(){ if [[ -s /etc/redhat-release ]]; then grep -oE “[0-9.]+” /etc/redhat-release else grep -oE “[0-9.]+” /etc/issue fi} CentOS versioncentosversion(){ if check_sys sysRelease centos; then local code=$1 local version=”$(getversion)” local main_ver=${version%%.*} if [ “$main_ver” == “$code” ]; then return 0 else return 1 fi else return 1 fi} Get public IP addressget_ip(){ local IP=$( ip addr | egrep -o ‘[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}’ | egrep -v “^192.168|^172.1[6-9].|^172.2[0-9].|^172.3[0-2].|^10.|^127.|^255.|^0.“ | head -n 1 ) [ -z ${IP} ] && IP=$( wget -qO- -t1 -T2 ipv4.icanhazip.com ) [ -z ${IP} ] && IP=$( wget -qO- -t1 -T2 ipinfo.io/ip ) [ ! -z ${IP} ] && echo ${IP} || echo} get_char(){ SAVEDSTTY=stty -g stty -echo stty cbreak dd if=/dev/tty bs=1 count=1 2> /dev/null stty -raw stty echo stty $SAVEDSTTY} Pre-installation settingspre_install(){ if check_sys packageManager yum || check_sys packageManager apt; then # Not support CentOS 5 if centosversion 5; then echo -e “$[{red}Error${plain}] Not supported CentOS 5, please change to CentOS 6+/Debian 7+/Ubuntu 12+ and try again.” exit 1 fi else echo -e “[${red}Error${plain}] Your OS is not supported. please change OS to CentOS/Debian/Ubuntu and try again.” exit 1 fi # Set shadowsocks config password echo “Please enter password for shadowsocks-python” read -p “(Default password: teddysun.com):” shadowsockspwd [ -z “${shadowsockspwd}” ] && shadowsockspwd=”teddysun.com” echo echo “—————————“ echo “password = ${shadowsockspwd}” echo “—————————“ echo # Set shadowsocks config port while true do dport=$(shuf -i 9000-19999 -n 1) echo “Please enter a port for shadowsocks-python [1-65535]” read -p “(Default port: ${dport}):” shadowsocksport [ -z “$shadowsocksport” ] && shadowsocksport=${dport} expr ${shadowsocksport} + 1 &>/dev/null if [ $? -eq 0 ]; then if [ ${shadowsocksport} -ge 1 ] && [ ${shadowsocksport} -le 65535 ] && [ ${shadowsocksport:0:1} != 0 ]; then echo echo “—————————“ echo “port = ${shadowsocksport}” echo “—————————“ echo break fi fi echo -e “[${red}Error${plain}] Please enter a correct number [1-65535]” done # Set shadowsocks config stream ciphers while true do echo -e \"Please select stream cipher for shadowsocks-python:\" for ((i=1;i<=$","categories":[],"tags":[],"author":null},{"title":"Windows中的wsl重置密码","slug":"2021-2021-07-14-wsl-reset-password","date":"2021-07-14T09:05:20.000Z","updated":"2022-12-23T12:44:16.640Z","comments":true,"path":"2021/07/14/2021-2021-07-14-wsl-reset-password/","link":"","permalink":"https://tanghaojie.github.io/2021/07/14/2021-2021-07-14-wsl-reset-password/","excerpt":"","text":"wsl 中的用户名同步 windows 的用户名,但是密码不同步,默认密码也不知道,所以,重置吧。 首先进 wsl 记下你的 Linux 用户名,输入whoami就行,或者到 home 里面自己看; 然后关闭所有 ubuntu/linux 的 Bash; 在 Windows 中,以管理员运行命令提示符,输入: ubuntu config –default-user root 如果是 Ubuntu18.04,则命令为: ubuntu1804 config –default-user root 切换到默认用 root 登录以后,进入 ubuntu/linux 的 Bash,修改密码: passwd your_username 修改完成以后,关闭 Bash,回到 Windows,切换回默认普通用户: ubuntu config –default-user your_username 大功告成~ 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[],"tags":[],"author":null},{"title":"vue3+cesium+typescript踩坑之路","slug":"2021-cesium-2021-06-13-vue3-cesium","date":"2021-06-13T15:41:38.000Z","updated":"2022-12-23T12:44:16.646Z","comments":true,"path":"2021/06/13/2021-cesium-2021-06-13-vue3-cesium/","link":"","permalink":"https://tanghaojie.github.io/2021/06/13/2021-cesium-2021-06-13-vue3-cesium/","excerpt":"","text":"源码地址https://github.com/tanghaojie/vue3-cesium-typescript-start-up-template cesium 对象挂载到全局 window新建global-cesium.d.ts,文件,文件名随意(以.d.ts结尾就行),然后输入: /* eslint-disable */ declare namespace globalThis { import('cesium') import * as Cesium from 'cesium' interface Window { viewer: Cesium.Viewer } } 即可在 window 上挂载 viewer 对象了,要挂载其他属性,请自行扩展。 vue 全局挂载 cesium 对象新建cesium-vue.ts文件,写入代码: import { App } from 'vue' import * as Cesium from 'cesium' declare module '@vue/runtime-core' { interface CesiumVue { viewer: Cesium.Viewer | null viewerContainer: HTMLElement | null } interface ComponentCustomProperties { readonly $vc: CesiumVue } } export default { install: function (app: App<Element>): void { app.config.globalProperties.$vc = { viewer: null, viewerContainer: null, } }, } 在main.ts中: import cesiumVue from './libs/cesium-vue' const app = createApp(App) app.use(cesiumVue) @vue/runtime-core声明只能写在.ts文件中,至于为什么官方也没说,官方讨论 interface CesiumVue是我自己定义的数据类型,方便后续扩展更多的属性上去,然后就可以全局通过this.$vc进行访问了。比之前 vue2 的时候,挂载到根组件上的方式更灵活更好。 重要提醒: 记得在合适的运行时初始化$vc中的viewer,否则他就一直都是null。重要提醒: $vc是readonly属性,所以记得永远不要再次初始化$vc。当然,严格模式的 ts 会在二次赋值时提醒你,但就怕用的非严格模式。 vue 的 ref 数据类型如果在普通的 DOM 元素上使用,数据类型为:HTMLElement;如果用在子组件上,数据类型为:ComponentPublicInstance。 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[],"tags":[],"author":null},{"title":"js任意string转随机颜色","slug":"2021-2021-06-01-js-string-to-rgb","date":"2021-06-01T02:47:09.000Z","updated":"2022-12-23T12:44:16.640Z","comments":true,"path":"2021/06/01/2021-2021-06-01-js-string-to-rgb/","link":"","permalink":"https://tanghaojie.github.io/2021/06/01/2021-2021-06-01-js-string-to-rgb/","excerpt":"","text":"function hashCode(str) { // java String#hashCode var hash = 0 for (var i = 0; i < str.length; i++) { hash = str.charCodeAt(i) + ((hash << 5) - hash) } return hash } function intToRGB(i) { return (i & 0x00ffffff).toString(16).padStart(6, '0') } 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[],"tags":[],"author":null},{"title":"3D Tiles样式数据格式标准规范","slug":"2021-3d-tiles-2021-04-23-3d-tiles-styling-specification","date":"2021-04-23T14:10:34.000Z","updated":"2022-12-23T12:44:16.645Z","comments":true,"path":"2021/04/23/2021-3d-tiles-2021-04-23-3d-tiles-styling-specification/","link":"","permalink":"https://tanghaojie.github.io/2021/04/23/2021-3d-tiles-2021-04-23-3d-tiles-styling-specification/","excerpt":"","text":"导航 引 概述 概念 要素样式 条件表达式 定义变量 元属性 表达式 语法 运算符 数据类型 Number String vec Color RegExp 运算规则 类型转换 字符转换 常量 变量 内置函数 特殊说明 点云 文件扩展名和 MIME 类型 属性参考 引官网文档 概述3D Tiles 样式为 tileset 要素提供了简洁的声明式样式。样式通常基于存储在图块的批处理表(Batch Table)中的特征属性来定义表达式,以评定要素的显示表达,例如 color(RGB 和半透明)和 show 属性。 样式可以应用于不包含要素的图块,在这种情况下,图块被视为没有属性的隐式单个要素。 尽管可以为数据集创建样式并参考数据集的属性,但是样式独立于数据集,因此任何样式都可以应用于任何数据集。 样式使用 JSON 定义,并使用一部分 JavaScript 的表达式进行了增强扩展。此外,样式语言提供了一组内置函数来支持常见的数学运算。 以下示例根据建筑物高度分配颜色。 { \"show\": \"${Area} > 0\", \"color\": { \"conditions\": [ [\"${Height} < 60\", \"color('#13293D')\"], [\"${Height} < 120\", \"color('#1B98E0')\"], [\"true\", \"color('#E8F1F2', 0.5)\"] ] } } 概念 要素样式用于要素样式的视觉属性是 show 属性,该属性的赋值表达式将评估为确定要素是否可见的布尔值,而 color 属性的赋值表达式将赋值为一个 Color 对象(RGB 和半透明)的属性来确定要素显示的颜色。 以下样式将默认的显示和颜色属性分配给每个要素: { \"show\": \"true\", \"color\": \"color('#ffffff')\" } show可以依赖于要素属性的表达式进行显示,而不是显示所有要素,例如,以下表达式将仅显示 zip code 为 19341 的要素: { \"show\": \"${ZipCode} === '19341'\" } show也可以用于更复杂的查询;例如,此处使用复合条件和正则表达式来仅显示County以'Chest'开始,且其YearBuilt大于或等于 1970 的要素: { \"show\": \"(regExp('^Chest').test(${County})) && (${YearBuilt} >= 1970)\" } 颜色也可以通过要素属性的表达式来定义。例如,以下表达式为温度高于 90 的特征为红色,其余为白色: { \"color\": \"(${Temperature} > 90) ? color('red') : color('white')\" } 颜色的 Alpha 部分定义了要素的不透明度。例如,以下内容根据要素的属性设置要素的 RGB 颜色部分,并使体积大于 100 的要素透明: { \"color\": \"rgba(${red}, ${green}, ${blue}, (${volume} > 100 ? 0.5 : 1.0))\" } 条件表达式(Conditions)除了包含表达式的字符串外,color和show可以定义一系列条件的数组(类似于if...else语句)。例如,可以使用条件制作具有任何类型的包含/排除间隔的颜色图和颜色渐变。 例如,以下表达式将 ID 属性映射到颜色。按条件顺序求值,因此如果${id}不是'1'或'2',则\"true\"条件返回白色。如果不满足任何条件,则要是的颜色将为undefined: { \"color\": { \"conditions\": [ [\"${id} === '1'\", \"color('#FF0000')\"], [\"${id} === '2'\", \"color('#00FF00')\"], [\"true\", \"color('#FFFFFF')\"] ] } } 下一个示例显示如何使用条件使用包含下限值和上限值的间隔来创建色带: \"color\" : { \"conditions\" : [ [\"(${Height} >= 1.0) && (${Height} < 10.0)\", \"color('#FF00FF')\"], [\"(${Height} >= 10.0) && (${Height} < 30.0)\", \"color('#FF0000')\"], [\"(${Height} >= 30.0) && (${Height} < 50.0)\", \"color('#FFFF00')\"], [\"(${Height} >= 50.0) && (${Height} < 70.0)\", \"color('#00FF00')\"], [\"(${Height} >= 70.0) && (${Height} < 100.0)\", \"color('#00FFFF')\"], [\"(${Height} >= 100.0)\", \"color('#0000FF')\"] ] } 由于条件是按顺序判断的,因此以上内容可以写得更简洁: \"color\" : { \"conditions\" : [ [\"(${Height} >= 100.0)\", \"color('#0000FF')\"], [\"(${Height} >= 70.0)\", \"color('#00FFFF')\"], [\"(${Height} >= 50.0)\", \"color('#00FF00')\"], [\"(${Height} >= 30.0)\", \"color('#FFFF00')\"], [\"(${Height} >= 10.0)\", \"color('#FF0000')\"], [\"(${Height} >= 1.0)\", \"color('#FF00FF')\"] ] } 定义变量常用的表达式可以以defines变量名作为键存储在对象中。如果变量引用了已定义表达式的名称,则将其替换为所引用的求值表达式的结果: { \"defines\": { \"NewHeight\": \"clamp((${Height} - 0.5) / 2.0, 1.0, 255.0)\", \"HeightColor\": \"rgb(${Height}, ${Height}, ${Height})\" }, \"color\": { \"conditions\": [ [\"(${NewHeight} >= 100.0)\", \"color('#0000FF') * ${HeightColor}\"], [\"(${NewHeight} >= 50.0)\", \"color('#00FF00') * ${HeightColor}\"], [\"(${NewHeight} >= 1.0)\", \"color('#FF0000') * ${HeightColor}\"] ] }, \"show\": \"${NewHeight} < 200.0\" } 定义表达式不能引用其他定义。但是,它可能引用具有相同名称的要素属性。在下面的样式中,高度为 150 的要素将获得红色: { \"defines\": { \"Height\": \"${Height}/2.0}\" }, \"color\": { \"conditions\": [ [\"(${Height} >= 100.0)\", \"color('#0000FF')\"], [\"(${Height} >= 1.0)\", \"color('#FF0000')\"] ] } } 元属性可以使用meta属性定义要素的非可视属性。例如,以下设置元属性的一个description为包含要素名称的字符串: { \"meta\": { \"description\": \"'Hello, ${featureName}.'\" } } 元属性表达式可以求值为任何类型。例如: { \"meta\": { \"featureColor\": \"rgb(${red}, ${green}, ${blue})\", \"featureVolume\": \"${height} * ${width} * ${depth}\" } } 表达式表达式语言是 JavaScript(EMCAScript 5)的一小部分,外加本机向量和正则表达式类型,并以只读变量的形式访问 tileset 要素属性。 注意: CesiumJS 使用jsep JavaScript 表达式解析器库将样式表达式解析为抽象语法树(AST)。 语法点号用于按名称访问属性,例如building.name。 括号([])也用于访问属性,例如building['name'],或数组,例如temperatures[1]。 函数用括号(())调用,逗号分隔参数,例如(isNaN(0.0),color('cyan', 0.5))。 运算符支持以下运算符,其语义和优先级与 JavaScript 相同。 一元运算符:+, -, ! 不支持: ~ 二元运算符:||, &&, ===, !==, <, >, <=, >=, +, -, *, /, %, =~, !~ 不支持:|,^,&,<<,>>,和>>> 三元运算符: ? : (和)同样也支持对表达式进行分组以提高清晰度和优先级。 逻辑运算符||并&&实现短路;true || expression不评估右侧的表达式,false && expression也不评估右侧的表达式。 同样,true ? leftExpression : rightExpression仅执行左侧表达式,并且false ? leftExpression : rightExpression仅执行右侧表达式。 数据类型支持以下类型: Boolean Null Undefined Number String Array vec2 vec3 vec4 RegExp 除vec2,vec3,vec4,RegExp外的所有类型,具有 JavaScript 相同的语法和运行时行为。 vec2,vec3和vec4是从 GLSL 向量派生的,类似于 JavaScript Object(请参见vec)。颜色从CSS3颜色派生并实现为vec4。RegExp从 JavaScript 派生并在RegExp描述。 各个类型的示例包括以下内容: true, false null undefined 1.0, NaN, Infinity 'Cesium', \"Cesium\" [0, 1, 2] vec2(1.0, 2.0) vec3(1.0, 2.0, 3.0) vec4(1.0, 2.0, 3.0, 4.0) color('#00FFFF') regExp('^Chest')) Number和 JavaScript 中一样,数字可以是NaN或Infinity。支持以下检测方法: isNaN(testValue : Number) : Boolean isFinite(testValue : Number) : Boolean String字符串以 UTF-8 编码。 向量样式语言包括 2,2,3 和 4 维数组浮点矢量类型:vec2,vec3,和vec4。向量构造器与 GLSL 使用相同的规则: vec2 vec2(xy : Number) - 用数字初始化每个组件 vec2(x : Number, y : Number) -用两个数字初始化 vec2(xy : vec2) - 用另一个 vec2初始化 vec2(xyz : vec3) - 删除 vec3的第三部分 vec2(xyzw : vec4) - 删除 vec4的第三、四部分 vec3 vec3(xyz : Number) -用数字初始化每个组件 vec3(x : Number, y : Number, z : Number) -用三个数字初始化 vec3(xyz : vec3) -用另一个 vec3初始化 vec3(xyzw : vec4) -删除 vec4的第四部分 vec3(xy : vec2, z : Number)-用vec2和数字初始化 vec3(x : Number, yz : vec2)-用vec2和数字初始化 vec4 vec4(xyzw : Number) -用数字初始化每个组件 vec4(x : Number, y : Number, z : Number, w : Number) -用四个数字初始化 vec4(xyzw : vec4) -用另一个 vec4初始化 vec4(xy : vec2, z : Number, w : Number)-用vec2和两个数字初始化 vec4(x : Number, yz : vec2, w : Number)-用vec2和两个数字初始化 vec4(x : Number, y : Number, zw : vec2)-用vec2和两个数字初始化 vec4(xyz : vec3, w : Number)-用vec3和数字初始化 vec4(x : Number, yzw : vec3)-用vec3和数字初始化 向量用法vec2 组件可以通过以下方式访问 .x, .y .r, .g [0], [1] vec3 组件可以通过以下方式访问 .x, .y, .z .r, .g, .b [0], [1], [2] vec4 组件可以通过以下方式访问 .x, .y, .z, .w .r, .g, .b, .a [0], [1], [2], [3] 与 GLSL 不同,样式语言不支持滚动。例如,vec3(1.0).xy不支持。 向量支持以下一元运算符:-,+。 向量通过执行基于组件的运算来支持以下二元运算符:===,!==,+,-,*,/,和%。例如vec4(1.0) === vec4(1.0)为true,因为x,_y_,z和w分量相等,就成立了。本质上是对vec2,vec3和vec4的运算符进行了重载。 vec2,vec3和vec4具有toString的方法,在显式(隐式)的变换为字符串,以'(x, y)','(x, y, z)'和'(x, y, z, w)'的格式。 toString() : String vec2,vec3和vec4不暴露其他任何方法或prototype对象。 Color颜色实现为vec4,并可以通过以下方法之一创建: color() color(keyword : String, [alpha : Number]) color(6-digit-hex : String, [alpha : Number]) color(3-digit-hex : String, [alpha : Number]) rgb(red : Number, green : Number, blue : Number) rgba(red : Number, green : Number, blue : Number, alpha : Number) hsl(hue : Number, saturation : Number, lightness : Number) hsla(hue : Number, saturation : Number, lightness : Number, alpha : Number) color()不带参数的调用与调用color('#FFFFFF')相同。 由大小写不敏感的关键字(例如'cyan')或十六进制 rgb 定义的颜色将作为字符串传递给color函数。例如: color('cyan') color('#00FFFF') color('#0FF') color函数有一个可选的第二参数,它是用于定义 alpha 部分的不透明度,其中0.0完全透明而1.0完全不透明。例如: color('cyan', 0.5) 十进制 RGB 或 HSL 的颜色定义,以rgb和hsl创建,如同 CSS 一样(特别地,百分比范围从0.0到1.0表示从0%到100%)。例如: rgb(100, 255, 190) hsl(1.0, 0.6, 0.7) rgb部分的范围从0到255。对于hsl,色相、饱和度、亮度从0.0到1.0。 rgba或hsla具有第四个参数定义的颜色,它是用于定义不透明度的 alpha 分量,其中0.0完全透明且1.0完全不透明。例如: rgba(100, 255, 190, 0.25) hsla(1.0, 0.6, 0.7, 0.75) 颜色与vec4类型相同,并且具有相同的方法,运算符和组件访问器。颜色分量存储在范围0.0到1.0中。 例如: color('red').x,color('red').r和color('red')[0]所有取值为1.0。 color('red').toString() 结果为(1.0, 0.0, 0.0, 1.0) color('red') * vec4(0.5) 相当于 vec4(0.5, 0.0, 0.0, 0.5) RegExp使用以下方法创建正则表达式,类似于 JavaScriptRegExp构造函数: regExp() regExp(pattern : String, [flags : String]) regExp()不带参数的调用与调用regExp('(?:)')相同。 如果指定,则flags可以具有以下值的任意组合: g -全局匹配 i -忽略大小写 m -多行匹配 u -匹配 unicode y-sticky 匹配 正则表达式支持以下方法: test(string : String) : Boolean -测试指定的字符串是否匹配。 exec(string : String) : String-在指定的字符串中搜索匹配项。如果搜索成功,则返回已捕获的第一个实例String。如果搜索失败,则返回null。 例如: { \"Name\": \"Building 1\" } regExp('a').test('abc') === true regExp('a(.)', 'i').exec('Abc') === 'b' regExp('Building\\s(\\d)').exec(${Name}) === '1' 正则表达式具有toString方法显式(隐式)转换为'pattern'格式的字符串: toString() : String 正则表达式不会暴露任何其他函数或prototype对象。 运算符=~和!~对正则表达式进行了重载。=~运算符的行为匹配test方法,并测试匹配指定的字符串。它返回true找到一个,false找不到。!~是=~的逆操作。返回true如果找不到匹配项,返回false找到匹配项。两个运算符都是可交换的。 例如,以下表达式求值均为 true: regExp('a') =~ 'abc' 'abc' =~ regExp('a') regExp('a') !~ 'bcd' 'bcd' !~ regExp('a') 运算规则 一元运算符+,-仅对数字和向量表达式进行运算。 一元运算符!仅对布尔表达式进行运算。 二元运算符<,<=,>,和>=仅对数字表达式进行操作。 二元运算符||,&&仅对布尔表达式进行运算。 二元运算符+对以下表达式进行操作: 数字表达式 相同类型的向量表达式 如果至少一个表达式是字符串,则另一个表达式将进行字符串转换之后转换为字符串,并且该操作将返回一个串联的字符串,例如,\"name\" + 10求值为\"name10\" 二进制运算符-对以下表达式进行操作: 数字表达式 相同类型的向量表达式 二进制运算符*对以下表达式进行操作: 数字表达式 相同类型的向量表达式 数字表达式和矢量表达式的混合,例如3 * vec3(1.0)和vec2(1.0) * 3 二进制运算符/对以下表达式进行操作: 数字表达式 相同类型的向量表达式 矢量表达式后跟数字表达式,例如vec3(1.0) / 3 二进制运算符%对以下表达式进行操作: 数字表达式 相同类型的向量表达式 二进制相等运算符===,可!==对任何表达式进行运算。false如果表达式类型不匹配,则操作返回。 二进制regExp运算符=~,!~要求一个参数是字符串表达式,另一个参数是RegExp表达式。 三元运算符? :条件参数必须是布尔表达式。 类型转换基本类型之间的转换使用Boolean,Number和String方法来处理。 Boolean(value : Any) : Boolean Number(value : Any) : Number String(value : Any) : String 例如: Boolean(1) === true Number('1') === 1 String(1) === '1' Boolean和Number遵循 JavaScript 约定。String遵循字符串转换。 这些本质上是强制类型转换,而不是构造函数。 除非上面另有说明,否则样式语言不允许进行隐式类型转换。像vec3(1.0) === vec4(1.0)和\"5\" < 6这样的表达式无效。 字符转换vec2,vec3,vec4,和RegExp表达式转换为使用他们的字符串toString的方法。所有其他类型均遵循 JavaScript 规则。 true – \"true\" false – \"false\" null – \"null\" undefined – \"undefined\" 5.0 – \"5\" NaN – \"NaN\" Infinity – \"Infinity\" \"name\" – \"name\" [0, 1, 2] – \"[0, 1, 2]\" vec2(1, 2) – \"(1, 2)\" vec3(1, 2, 3) – \"(1, 2, 3)\" vec4(1, 2, 3, 4) – \"(1, 2, 3, 4)\" RegExp('a') – \"/a/\" 常量样式语言支持以下常量: Math.PI Math.E PI数学常数 PI 为圆的周长除以其直径,约3.14159。 { “ show ”:“ cos($ {Angle} + Math.PI)<0 ” } E欧拉常数和自然对数的底数,约2.71828。 { “ color ”:“ color()* pow(Math.E / 2.0,$ {Temperature})” } 变量变量用于检索图块集中各个要素的属性值。使用 ES 6(ECMAScript 2015)模板文字语法(如${feature.identifier}、${feature['identifier']})标识变量,其中标识符是区分大小写的属性名称。变量名称以 UTF-8 编码。feature是隐式的,在大多数情况下可以省略。如果标识符包含非字母数字字符,例如:,-,#,或空格,则应当使用${feature['identifier']}形式。 可以在任何接受有效表达式的地方使用变量,但在其他变量标识符中除外。例如,不允许以下内容: ${foo[${bar}]} 如果要素没有具有指定名称的属性,则该变量的值为undefined。请注意,如果属性是为某个属性显式存储的,null则该属性也可能是null。 变量可以是任何受支持的原生 JavaScript 类型: Boolean Null Undefined Number String Array 例如: { \"enabled\" : true, \"description\" : null, \"order\" : 1, \"name\" : \"Feature name\" } ${enabled} === true ${description} === null ${order} === 1 ${name} === 'Feature name' 此外,存储在批处理表(Batch Table)二进制文件中矢量属性的变量被视为矢量类型: componentType variable type \"VEC2\" vec2 \"VEC3\" vec3 \"VEC4\" 变量可用于构造颜色或向量。例如: rgba(${red}, ${green}, ${blue}, ${alpha}) vec4(${temperature}) 点或括号符号用于访问要素子属性。例如: { \"address.street\": \"Maple Street\", \"address\": { \"street\": \"Oak Street\" } } ${address.street} === `Example street` ${address['street']} === `Example street` ${address.city} === `Example city` ${address['city']} === `Example city` 括号表示法仅支持字符串文字。 可以显式使用feature关键字的括号表示法访问顶级属性。例如: { \"address.street\": \"Maple Street\", \"address\": { \"street\": \"Oak Street\" } } ${address.street} === `Oak Street` ${feature.address.street} === `Oak Street` ${feature['address'].street} === `Oak Street` ${feature['address.street']} === `Maple Street` 要访问名为feature的要素,请使用变量${feature}。这等效于访问${feature.feature} { \"feature\": \"building\" } ${feature} === `building` ${feature.feature} === `building` 也可以在用反引号定义的字符串内替换变量,例如: { \"order\": 1, \"name\": \"Feature name\" } `Name is ${name}, order is ${order}` 括号符号用于访问要素子属性或数组。例如: { \"temperatures\": { \"scale\": \"fahrenheit\", \"values\": [70, 80, 90] } } ${temperatures['scale']} === 'fahrenheit' ${temperatures.values[0]} === 70 ${temperatures['values'][0]} === 70 // Same as (temperatures[values])[0] and temperatures.values[0] 内置函数 abs sqrt cos sin tan acos asin atan atan2 radians degrees sign floor ceil round exp log exp2 log2 fract pow min max clamp mix length distance normalize dot cross 许多内置函数都将标量或向量作为参数。对于向量参数,将按组件方式应用该函数,并返回结果向量。 absabs(x : Number) : Number abs(x : vec2) : vec2 abs(x : vec3) : vec3 abs(x : vec4) : vec4 返回x的绝对值。 { \"show\" : \"abs(${temperature}) > 20.0\" } sqrtsqrt(x : Number) : Number sqrt(x : vec2) : vec2 sqrt(x : vec3) : vec3 sqrt(x : vec4) : vec4 当x >= 0时,返回x的平方根。当x < 0时返回NaN。 { \"color\" : { \"conditions\" : [ [\"${temperature} >= 0.5\", \"color('#00FFFF')\"], [\"${temperature} >= 0.0\", \"color('#FF00FF')\"] ] } } coscos(angle : Number) : Number cos(angle : vec2) : vec2 cos(angle : vec3) : vec3 cos(angle : vec4) : vec4 返回angle弧度的余弦值。 { \"show\" : \"cos(${Angle}) > 0.0\" } sinsin(angle : Number) : Number sin(angle : vec2) : vec2 sin(angle : vec3) : vec3 sin(angle : vec4) : vec4 返回angle弧度的正弦值。 { \"show\" : \"sin(${Angle}) > 0.0\" } tantan(angle : Number) : Number tan(angle : vec2) : vec2 tan(angle : vec3) : vec3 tan(angle : vec4) : vec4 返回angle弧度的正切值。 { \"show\" : \"tan(${Angle}) > 0.0\" } acosacos(angle : Number) : Number acos(angle : vec2) : vec2 acos(angle : vec3) : vec3 acos(angle : vec4) : vec4 返回angle弧度的反余弦值。 { \"show\" : \"acos(${Angle}) > 0.0\" } asinasin(angle : Number) : Number asin(angle : vec2) : vec2 asin(angle : vec3) : vec3 asin(angle : vec4) : vec4 返回angle弧度的反正弦值。 { \"show\" : \"asin(${Angle}) > 0.0\" } atanatan(angle : Number) : Number atan(angle : vec2) : vec2 atan(angle : vec3) : vec3 atan(angle : vec4) : vec4 返回angle弧度的反正切值。 { \"show\" : \"atan(${Angle}) > 0.0\" } atan2atan2(y : Number, x : Number) : Number atan2(y : vec2, x : vec2) : vec2 atan2(y : vec3, x : vec3) : vec3 atan2(y : vec4, x : vec4) : vec4 返回y和x商的反正切值。 { \"show\" : \"atan2(${GridY}, ${GridX}) > 0.0\" } radiansradians(angle : Number) : Number radians(angle : vec2) : vec2 radians(angle : vec3) : vec3 radians(angle : vec4) : vec4 angle从度转换为弧度。 { \"show\" : \"radians(${Angle}) > 0.5\" } degreesdegrees(angle : Number) : Number degrees(angle : vec2) : vec2 degrees(angle : vec3) : vec3 degrees(angle : vec4) : vec4 angle从弧度转换为度。 { \"show\" : \"degrees(${Angle}) > 45.0\" } signsign(x : Number) : Number sign(x : vec2) : vec2 sign(x : vec3) : vec3 sign(x : vec4) : vec4 当x正数时返回 1.0 ,当x零时返回 0.0 ,当x负数时返回-1.0 。 { \"show\" : \"sign(${Temperature}) * sign(${Velocity}) === 1.0\" } floorfloor(x : Number) : Number floor(x : vec2) : vec2 floor(x : vec3) : vec3 floor(x : vec4) : vec4 返回小于或等于x的最接近的整数。 { \"show\" : \"floor(${Position}) === 0\" } ceilceil(x : Number) : Number ceil(x : vec2) : vec2 ceil(x : vec3) : vec3 ceil(x : vec4) : vec4 返回大于或等于x的最接近的整数。 { \"show\" : \"ceil(${Position}) === 1\" } roundround(x : Number) : Number round(x : vec2) : vec2 round(x : vec3) : vec3 round(x : vec4) : vec4 返回最接近x的整数。小数为 0.5 的数字将按实现定义的方向四舍五入。 { \"show\" : \"round(${Position}) === 1\" } expexp(x : Number) : Number exp(x : vec2) : vec2 exp(x : vec3) : vec3 exp(x : vec4) : vec4 返回e的x次幂,其中e欧拉常数,约为2.71828。 { \"show\" : \"exp(${Density}) > 1.0\" } loglog(x : Number) : Number log(x : vec2) : vec2 log(x : vec3) : vec3 log(x : vec4) : vec4 返回自然数为底(e)x的对数。 { \"show\" : \"log(${Density}) > 1.0\" } exp2exp2(x : Number) : Number exp2(x : vec2) : vec2 exp2(x : vec3) : vec3 exp2(x : vec4) : vec4 返回 2 的x次幂。 { \"show\" : \"exp2(${Density}) > 1.0\" } log2log2(x : Number) : Number log2(x : vec2) : vec2 log2(x : vec3) : vec3 log2(x : vec4) : vec4 返回的以 2 为底x的对数。 { \"show\" : \"log2(${Density}) > 1.0\" } fractfract(x : Number) : Number fract(x : vec2) : vec2 fract(x : vec3) : vec3 fract(x : vec4) : vec4 返回x的小数部分。等同于x - floor(x)。 { \"color\" : \"color() * fract(${Density})\" } powpow(base : Number, exponent : Number) : Number pow(base : vec2, exponent : vec2) : vec2 pow(base : vec3, exponent : vec3) : vec3 pow(base : vec4, exponent : vec4) : vec4 返回基数base的exponent次幂。 { \"show\" : \"pow(${Density}, ${Temperature}) > 1.0\" } minmin(x : Number, y : Number) : Number min(x : vec2, y : vec2) : vec2 min(x : vec3, y : vec3) : vec3 min(x : vec4, y : vec4) : vec4 min(x : Number, y : Number) : Number min(x : vec2, y : Number) : vec2 min(x : vec3, y : Number) : vec3 min(x : vec4, y : Number) : vec4 返回x和y中小的数。 { \"show\" : \"min(${Width}, ${Height}) > 10.0\" } maxmax(x : Number, y : Number) : Number max(x : vec2, y : vec2) : vec2 max(x : vec3, y : vec3) : vec3 max(x : vec4, y : vec4) : vec4 max(x : Number, y : Number) : Number max(x : vec2, y : Number) : vec2 max(x : vec3, y : Number) : vec3 max(x : vec4, y : Number) : vec4 返回x和y中大的数。 { \"show\" : \"max(${Width}, ${Height}) > 10.0\" } clampclamp(x : Number, min : Number, max : Number) : Number clamp(x : vec2, min : vec2, max : vec2) : vec2 clamp(x : vec3, min : vec3, max : vec3) : vec3 clamp(x : vec4, min : vec4, max : vec4) : vec4 clamp(x : Number, min : Number, max : Number) : Number clamp(x : vec2, min : Number, max : Number) : vec2 clamp(x : vec3, min : Number, max : Number) : vec3 clamp(x : vec4, min : Number, max : Number) : vec4 约束x位于min和之间max。 { \"color\" : \"color() * clamp(${temperature}, 0.1, 0.2)\" } mixmix(x : Number, y : Number, a : Number) : Number mix(x : vec2, y : vec2, a : vec2) : vec2 mix(x : vec3, y : vec3, a : vec3) : vec3 mix(x : vec4, y : vec4, a : vec4) : vec4 mix(x : Number, y : Number, a : Number) : Number mix(x : vec2, y : vec2, a : Number) : vec2 mix(x : vec3, y : vec3, a : Number) : vec3 mix(x : vec4, y : vec4, a : Number) : vec4 计算x和y的线性内插。 { \"show\" : \"mix(20.0, ${Angle}, 0.5) > 25.0\" } lengthlength(x : Number) : Number length(x : vec2) : vec2 length(x : vec3) : vec3 length(x : vec4) : vec4 计算向量的长度x,即分量平方之和的平方根。如果x是数字,则length返回x。 { \"show\" : \"length(${Dimensions}) > 10.0\" } distancedistance(x : Number, y : Number) : Number distance(x : vec2, y : vec2) : vec2 distance(x : vec3, y : vec3) : vec3 distance(x : vec4, y : vec4) : vec4 计算两个点之间的距离x和y,即length(x - y)。 { \"show\" : \"distance(${BottomRight}, ${UpperLeft}) > 50.0\" } normalizenormalize(x : Number) : Number normalize(x : vec2) : vec2 normalize(x : vec3) : vec3 normalize(x : vec4) : vec4 返回长度为 1.0 的向量,该向量与x平行。当x为数字时,normalize返回 1.0。 { \"show\" : \"normalize(${RightVector}, ${UpVector}) > 0.5\" } dotdot(x : Number, y : Number) : Number dot(x : vec2, y : vec2) : vec2 dot(x : vec3, y : vec3) : vec3 dot(x : vec4, y : vec4) : vec4 计算x和y的点积。 { \"show\" : \"dot(${RightVector}, ${UpVector}) > 0.5\" } crosscross(x : vec3, y : vec3) : vec3 计算x和y的叉积。该函数仅接受vec3参数。 { \"color\" : \"vec4(cross(${RightVector}, ${UpVector}), 1.0)\" } 特殊说明不支持注释。 点云点云 (Point Cloud)数据集可以像其他要素一样设计样式。除了点的color和show属性,点云的样式可以设置为pointSize,或每个像素点的大小。默认pointSize值为1.0。 { \"color\": \"color('red')\", \"pointSize\": \"${Temperature} * 0.5\" } 实现时,可以限制pointSize在系统支持的点大小范围内。例如,当POINTS渲染时,WebGL 渲染器可能会查询ALIASED_POINT_SIZE_RANGE以获取系统限制。pointSize为1.0必须得到支持。 点云样式还可以引用点云要素表语法,包括位置,颜色和法线,以允许对源数据进行更灵活的样式设置。 ${POSITION}在RTC_CENTER和平铺变换应用之前,以vec3存储 xyz 直角坐标系的点坐标。量化位置时,${POSITION}在QUANTIZED_VOLUME_SCALE应用后,但QUANTIZED_VOLUME_OFFSET应用前指定位置。 ${POSITION_ABSOLUTE}在RTC_CENTER和 tile 变换应用之后,以vec3存储 xyz 直角坐标系的点坐标。量化位置时,${POSITION_ABSOLUTE}在QUANTIZED_VOLUME_SCALE、QUANTIZED_VOLUME_OFFSET和瓦片变换应用后,指定位置。 ${COLOR}为该点存储Color的 rgba 颜色。当要素表的颜色语义为RGB或RGB565时,${COLOR}.alpha为1.0。如果未定义颜色语义,则${COLOR}求值为特定应用程序的默认颜色。 ${NORMAL}在应用 tile 变换之前,以vec3存储点的法线(以笛卡尔坐标表示)。当法线被八进制编码时,${NORMAL}引用解码后的法线。如果在要素表中未定义法线,则${NORMAL}的结果为undefined。 例如: { \"color\": \"${COLOR} * color('red')'\", \"show\": \"${POSITION}.x > 0.5\", \"pointSize\": \"${NORMAL}.x > 0 ? 2 : 1\" } 实施注意:点云样式引擎可能经常使用着色器(GLSL)实现,但是在纯 GLSL 实现中,表达语言的某些功能是不可能的。其中一些功能包括: 求isNaN和isFinite(GLSL 2.0+支撑isnan和isinf分别用于这些功能) null和undefined类型 字符串,包括访问对象属性(color()['r'])和批处理表值 正则表达式 长度不是 2、3 或 4 的数组 类型比较不匹配(例如1.0 === false) 数组索引超出范围 文件扩展名和 MIME 类型Tileset 样式使用.json扩展名和application/jsonmime 类型。 属性参考 样式 布尔表达式 颜色表达式 多条件 条件 表达式 元 数字表达式 点云样式 样式3D Tiles 样式 类型 描述 是否必需 defines object 表达式映射到变量名称键的字符串的字典对象,在整个样式中都可以引用该对象。如果表达式引用定义的变量,则将其替换为相应表达式的求值结果。 不 show boolean,string,object 布尔表达式或多条件属性,它确定是否应该显示的特征。 否,默认值: true color string, object 颜色表达式或多条件属性,它确定颜色混合与特征的固有颜色。 否,默认值: color('#FFFFFF') meta object 元,其确定所述特征的非可视属性的值的对象。 布尔表达式具有 3D Tiles 样式表达式的布尔值或字符串,其值为布尔值。请参阅表达式。 颜色表达式3D Tiles 颜色样式的表达式。请参阅表达式。 多条件一系列条件按顺序求值,例如一系列 if … else 语句,这些表达式导致对表达式进行求值。 特性 类型 描述 是否必需 conditions array [] 一系列布尔条件按顺序求值。对于第一个计算结果为 true 的值,将计算并返回其值“结果”(也是一个表达式)。结果表达式必须全部为同一类型。如果没有条件得出的结果为 true,则结果为undefined。当条件为undefined,null或为空对象时,结果为undefined。 No 不允许使用其他属性。 条件表达式作为条件为真的结果进行的评估。两个表达式的数组。如果对第一个表达式求值并且结果为true,则对第二个表达式求值并作为条件的结果返回。 表达式有效的 3D Tiles 样式表达式。请参阅表达式。 元一系列属性名称和表达式用于评估该属性的值。 允许其他属性。 数字表达式3D Tiles 样式表达式,其计算结果为数字。请参阅表达式。 点云样式具有点云附加属性的 3D Tiles 样式。 类型 描述 是否必须 defines object 表达式映射到变量名称键的字符串的字典对象,在整个样式中都可以引用该对象。如果表达式引用定义的变量,则将其替换为相应表达式的求值结果。 No show boolean, string, object 布尔表达式或多条件属性,它确定是否应该显示的特征。 No, default: true color string, object 颜色表达式或多条件属性,它确定颜色混合与特征的固有颜色。 No, default: color('#FFFFFF') meta object 元,其确定所述特征的非可视属性的值的对象。 No pointSize number, string, object 数字表达式或多条件属性,用于确定点的大小(以像素为单位)。 No, default: 1 不允许使用其他属性。 未完 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"3D Tiles","slug":"3D-Tiles","permalink":"https://tanghaojie.github.io/categories/3D-Tiles/"},{"name":"specification","slug":"3D-Tiles/specification","permalink":"https://tanghaojie.github.io/categories/3D-Tiles/specification/"}],"tags":[{"name":"specification","slug":"specification","permalink":"https://tanghaojie.github.io/tags/specification/"},{"name":"3D Tiles","slug":"3D-Tiles","permalink":"https://tanghaojie.github.io/tags/3D-Tiles/"}],"author":null},{"title":"3D Tiles批处理表(Batch Table)数据格式标准规范","slug":"2021-3d-tiles-2021-04-23-3d-tiles-batch-table-specification","date":"2021-04-23T13:45:35.000Z","updated":"2022-12-23T12:44:16.643Z","comments":true,"path":"2021/04/23/2021-3d-tiles-2021-04-23-3d-tiles-batch-table-specification/","link":"","permalink":"https://tanghaojie.github.io/2021/04/23/2021-3d-tiles-2021-04-23-3d-tiles-batch-table-specification/","excerpt":"","text":"导航 引 概述 文件结构 结构填充 JSON 头 二进制体 实例 属性参考 引官网文档 概述批处理表是瓦片二进制体的一个组成部分,包含瓦片中每个要素的应用程序特定属性。在运行时查询这些属性以声明样式和任何应用程序特定的用法,例如填充 UI 或发出 REST API 请求。一些示例批处理表属性是建筑物高度,地理坐标和数据库主键。 批处理表用于以下数据格式: 批处理 3D 模型 (Batched 3D Model (b3dm)) 实例 3D 模型 (Instanced 3D Model (i3dm)) 点云 (Point Cloud (pnts)) 文件结构批处理表由两部分组成:JSON 头和可选的小端字节序二进制主体。JSON 描述了属性,这些属性的值可以直接在 JSON 中定义为数组,也可以引用二进制主体中的部分。将长数字数组存储在二进制体中的效率更高。下图显示了批处理表布局: 当瓦片数据包含批处理表时,批处理表将紧随瓦片的要素表之后。文件头还将包含 batchTableJSONByteLength 和 batchTableBinaryByteLength 的 uint32 字段,可用于提取批处理表的各个部分。 结构填充JSON 头必须以 8 个字节为界结束,否则,在 JSON 头尾部填充空格(0x20)以满足此要求。 二进制体必须以 8 个字节为界开始和结束。为了满足此要求,可以用任意值填充空白部分。 二进制属性必须以一个字节偏移量开始,该字节偏移量是必须是属性隐含类型大小的倍数。例如,组件的某个元素有 4 个字节长度的属性 FLOAT ,因此必须以 4 的倍数计算偏移量。为了满足此要求,可以用任意值填充空白部分。 JSON 头批处理表值可以两种不同的方式在 JSON 标头中表示: 值的数组,例如,\"name\" : ['name1', 'name2', 'name3']或\"height\" : [10.0, 20.0, 15.0]。 数组元素可以是任何有效的 JSON 数据类型,包括对象和数组。元素可能是null。 每个数组的长度等于 batchLength,以每种数据格式指定。这是数据中要素的数量。例如,batchLength 可以是 b3dm 数据中的模型数,i3dm 数据中的实例数,或 pnts 数据中的点数(或对象数)。 引用数据的二进制体,通过byteOffset表示对象,componentType 和 type 属性,例如,\"height\" : { \"byteOffset\" : 24, \"componentType\" : \"FLOAT\", \"type\" : \"SCALAR\"}。 byteOffset 指定相对于二进制主体从零开始的偏移量。 byteOffset 的值必须是该属性componentType字节大小的倍数 ,例如,属性具有组件类型 FLOAT 的 byteOffset 的值必须是4的倍数。 componentType 是组件特定的数据类型。允许的值是\"BYTE\",\"UNSIGNED_BYTE\",\"SHORT\",\"UNSIGNED_SHORT\",\"INT\",\"UNSIGNED_INT\",\"FLOAT\",和\"DOUBLE\"。 type 指定属性是标量还是向量。允许的值是\"SCALAR\",\"VEC2\",\"VEC3\",和\"VEC4\"。 批处理表 JSON 是 UTF-8 的 JSON 字符串。 注意:在 JavaScript 中,可以使用ArrayBuffer的TextDecoderJavaScript API 来提取 Batch Table JSON,并使用JSON.parse转换为 JavaScript 对象。 batchId用于访问每个数组中的元素并提取相应的属性。例如,以下批处理表有两个要素的一批属性: { \"id\": [\"unique id\", \"another unique id\"], \"displayName\": [\"Building name\", \"Another building name\"], \"yearBuilt\": [1999, 2015], \"address\": [ { \"street\": \"Main Street\", \"houseNumber\": \"1\" }, { \"street\": \"Main Street\", \"houseNumber\": \"2\" } ] } 要素batchId = 0的属性是: id[0] = 'unique id' displayName[0] = 'Building name' yearBuilt[0] = 1999 address[0] = { street: 'Main Street', houseNumber: '1' } 要素batchId = 1的属性是: id[1] = 'another unique id' displayName[1] = 'Another building name' yearBuilt[1] = 2015 address[1] = { street: 'Main Street', houseNumber: '2' } 完整的 JSON 头定义,详见属性参考。以下是一个完整的 JSON 格式。 JSON: { \"$schema\": \"http://json-schema.org/draft-04/schema\", \"id\": \"batchTable.schema.json\", \"title\": \"Batch Table\", \"type\": \"object\", \"description\": \"A set of properties defining application-specific metadata for features in a tile.\", \"properties\": { \"extensions\": { \"$ref\": \"extension.schema.json\" }, \"extras\": { \"$ref\": \"extras.schema.json\" } }, \"additionalProperties\": { \"$ref\": \"#/definitions/property\" }, \"definitions\": { \"binaryBodyReference\": { \"title\": \"BinaryBodyReference\", \"type\": \"object\", \"description\": \"An object defining the reference to a section of the binary body of the batch table where the property values are stored if not defined directly in the JSON.\", \"properties\": { \"byteOffset\": { \"type\": \"number\", \"description\": \"The offset into the buffer in bytes.\", \"minimum\": 0 }, \"componentType\": { \"type\": \"string\", \"description\": \"The datatype of components in the property.\", \"enum\": [ \"BYTE\", \"UNSIGNED_BYTE\", \"SHORT\", \"UNSIGNED_SHORT\", \"INT\", \"UNSIGNED_INT\", \"FLOAT\", \"DOUBLE\" ] }, \"type\": { \"type\": \"string\", \"description\": \"Specifies if the property is a scalar or vector.\", \"enum\": [\"SCALAR\", \"VEC2\", \"VEC3\", \"VEC4\"] } }, \"required\": [\"byteOffset\", \"componentType\", \"type\"] }, \"property\": { \"title\": \"Property\", \"description\": \"A user-defined property which specifies per-feature application-specific metadata in a tile. Values either can be defined directly in the JSON as an array, or can refer to sections in the binary body with a `BinaryBodyReference` object.\", \"oneOf\": [ { \"$ref\": \"#/definitions/binaryBodyReference\" }, { \"type\": \"array\" } ] } } } 二进制体当 JSON 头包含对二进制部分的引用时,所提供的 byteOffset 用于索引数据,如下图所示: 可以使用要素长度来数据值batchLength;所需的批量表 IDbatchId; componentType 和 type 定义在 JSON 头中。 下表可用于计算属性的字节大小。 componentType 字节大小 \"BYTE\" 1 \"UNSIGNED_BYTE\" 1 \"SHORT\" 2 \"UNSIGNED_SHORT\" 2 \"INT\" 4 \"UNSIGNED_INT\" 4 \"FLOAT\" 4 \"DOUBLE\" 8 type 部件数 \"SCALAR\" 1 \"VEC2\" 2 \"VEC3\" 3 \"VEC4\" 4 扩展以下扩展可以应用于批处理表。 3DTILES_batch_table_hierarchy 实例本节是非规范性的 以下示例访问批处理表 JSON 的\"height\"和\"geographic\"的值batchLength的长度是 10: { \"height\": { \"byteOffset\": 0, \"componentType\": \"FLOAT\", \"type\": \"SCALAR\" }, \"geographic\": { \"byteOffset\": 40, \"componentType\": \"DOUBLE\", \"type\": \"VEC3\" } } 获得\"height\"的值: var height = batchTableJSON.height var byteOffset = height.byteOffset var componentType = height.componentType var type = height.type var heightArrayByteLength = batchLength * sizeInBytes(componentType) * numberOfComponents(type) // 10 * 4 * 1 var heightArray = new Float32Array( batchTableBinary.buffer, byteOffset, heightArrayByteLength ) var heightOfFeature = heightArray[batchId] 获得\"geographic\"的值: var geographic = batchTableJSON.geographic var byteOffset = geographic.byteOffset var componentType = geographic.componentType var type = geographic.type var componentSizeInBytes = sizeInBytes(componentType) var numberOfComponents = numberOfComponents(type) var geographicArrayByteLength = batchLength * componentSizeInBytes * numberOfComponents // 10 * 8 * 3 var geographicArray = new Float64Array( batchTableBinary.buffer, byteOffset, geographicArrayByteLength ) var geographicOfFeature = positionArray.subarray( batchId * numberOfComponents, batchId * numberOfComponents + numberOfComponents ) // Using subarray creates a view into the array, and not a new array. CesiumJS 的 3D Tiles 实现了读取批量表的功能,Cesium3DTileBatchTable.js。 属性参考批处理表二进制体引用属性 批处理表一组属性,用于定义数据中要素的应用程序特定元数据。 类型 描述 是否必须 extensions object 特定扩展对象的字典对象 No extras any 应用程序的特定数据 No 允许其他属性。 二进制体引用一个对象,用于定义对要素表的二进制主体部分的引用,如果未在 JSON 头中直接定义属性值,则在该部分存储。 类型 描述 是否必须 byteOffset number 缓冲区的偏移量(以字节为单位) ✅ Yes componentType string 属性所属部分的数据类型 ✅ Yes type string 指定属性是标量还是向量 ✅ Yes 允许其他属性。 属性用户定义的属性,用于在数据中指定每个功能的特定于应用程序的元数据。值可以直接在 JSON 中定义为数组,也可以使用 二进制体引用 对象引用二进制主体中的部分。 JSON 参考,见上面。 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"3D Tiles","slug":"3D-Tiles","permalink":"https://tanghaojie.github.io/categories/3D-Tiles/"},{"name":"specification","slug":"3D-Tiles/specification","permalink":"https://tanghaojie.github.io/categories/3D-Tiles/specification/"}],"tags":[{"name":"specification","slug":"specification","permalink":"https://tanghaojie.github.io/tags/specification/"},{"name":"3D Tiles","slug":"3D-Tiles","permalink":"https://tanghaojie.github.io/tags/3D-Tiles/"}],"author":null},{"title":"3D Tiles要素表(Feature Table)数据格式标准规范","slug":"2021-3d-tiles-2021-04-23-3d-tiles-feature-table-specification","date":"2021-04-23T13:45:23.000Z","updated":"2022-12-23T12:44:16.644Z","comments":true,"path":"2021/04/23/2021-3d-tiles-2021-04-23-3d-tiles-feature-table-specification/","link":"","permalink":"https://tanghaojie.github.io/2021/04/23/2021-3d-tiles-2021-04-23-3d-tiles-feature-table-specification/","excerpt":"","text":"导航 引 概述 文件结构 结构填充 JSON 头 二进制体 实例 属性参考 引官网文档 概述要素表(Feature Table)是瓦片的实例二进制组件,用户描述每一个瓦片在 渲染 时的位置和外观属性。而批处理表(Batch Table),只用于包含应用程序特定的 属性,在渲染时不是必须的。 要素表可以被所有瓦片格式使用,例如批处理 3D 模型 (Batched 3D Model (b3dm)),每一个模型是一个要素;点云 (Point Cloud (pnts)),每一个点是一个要素。 每个要素的属性是由每种数据格式规范所定义的特定语法。例如,实例 3D 模型,SCALE_NON_UNIFORM 定义每个 3D 模型实例的非均匀比例。 文件结构要素表由两部分组成:JSON 头和可选的小端字节序二进制主体。JSON 属性名称是数据格式特定的语法,并且它们的值可以直接在 JSON 中定义,也可以引用二进制主体部分。将长数字数组存储在二进制体中的效率更高。下图显示了要素表布局: 当一种数据包括要素表时,要素表紧随在若干个字节的文件头后。文件头还要包含 featureTableJSONByteLength 和 featureTableBinaryByteLength 的 uint32 字段,可用于表示要素表的各个部分。 结构填充JSON 头必须以 8 个字节为界结束,否则,在 JSON 头尾部填充空格(0x20)以满足此要求。 二进制体必须以 8 个字节为界开始和结束。为了满足此要求,可以用任意值填充空白部分。 二进制属性必须以一个字节偏移量开始,该字节偏移量是必须是属性隐含类型大小的倍数。例如,组件的某个元素有 4 个字节长度的属性 FLOAT ,因此必须以 4 的倍数计算偏移量。为了满足此要求,可以用任意值填充空白部分。 这里如果看不懂,先把后面看完再回头来看,应该就懂了。 JSON 头可以通过以下三种方式在 JSON 标中表示要素表的值: 单个值或对象,如,\"INSTANCES_LENGTH\": 4。 这用于全局定义,如,\"INSTANCES_LENGTH\",它定义了实例化 3D 模型数据中的模型实例数。 数组,如,\"POSITION\" : [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]。 这用于按要素定义,如,实例 3D 模型中的\"POSITION\"。如上面的数组,每个都 POSITION 对应 float32[3] 数据类型,因此有三个要素:要素 0's position= (1.0, 0.0, 0.0),要素 1's position= (0.0, 1.0, 0.0),要素 2's position= (0.0, 0.0, 1.0)。 一个指向二进制体中数据的引用,由具有 byteOffset 属性的对象表示,例如\"SCALE\" : { \"byteOffset\" : 24}。 byteOffset 指定相对于二进制体从零开始的偏移量。byteOffset 的值必须是属性隐含类型大小(以字节为单位)的倍数,例如,\"POSITION\"属性的数据类型是 FLOAT(4 个字节),因此 byteOffset的值必须是 4 的倍数 。 语法定义了允许的数据类型。例如,实例 3D 模型的\"POSITION\"属性从二进制体中引用时,属性类型为FLOAT,属性长度为3。 有些语法允许覆盖(override)属性隐含的类型。这些情况以每种图块格式指定,如,\"BATCH_ID\" : { \"byteOffset\" : 24, \"componentType\" : \"UNSIGNED_BYTE\"}。JSON 头中有效的属性是各个数据格式预定义的,以及可选的 extras 和 extensions 属性。应用程序特定的数据应存储在批处理表(Batch Table)中。 完整的 JSON 头定义,详见属性参考。以下是一个完整的 JSON 格式。 JSON: { \"$schema\": \"http://json-schema.org/draft-04/schema\", \"id\": \"featureTable.schema.json\", \"title\": \"Feature Table\", \"type\": \"object\", \"description\": \"A set of semantics containing per-tile and per-feature values defining the position and appearance properties for features in a tile.\", \"definitions\": { \"binaryBodyReference\": { \"title\": \"BinaryBodyReference\", \"type\": \"object\", \"description\": \"An object defining the reference to a section of the binary body of the features table where the property values are stored if not defined directly in the JSON.\", \"properties\": { \"byteOffset\": { \"type\": \"number\", \"description\": \"The offset into the buffer in bytes.\", \"minimum\": 0 }, \"componentType\": { \"type\": \"number\", \"description\": \"The datatype of components in the property. This is defined only if the semantic allows for overriding the implicit component type. These cases are specified in each tile format.\", \"enum\": [ \"BYTE\", \"UNSIGNED_BYTE\", \"SHORT\", \"UNSIGNED_SHORT\", \"INT\", \"UNSIGNED_INT\", \"FLOAT\", \"DOUBLE\" ] } }, \"required\": [\"byteOffset\"] }, \"numericArray\": { \"type\": \"array\", \"items\": { \"type\": \"number\" } }, \"property\": { \"title\": \"Property\", \"description\": \"A user-defined property which specifies per-feature application-specific metadata in a tile. Values either can be defined directly in the JSON as an array, or can refer to sections in the binary body with a `BinaryBodyReference` object.\", \"oneOf\": [ { \"$ref\": \"#/definitions/binaryBodyReference\" }, { \"type\": \"array\", \"items\": { \"type\": \"number\" } }, { \"type\": \"number\" } ] }, \"globalPropertyBoolean\": { \"title\": \"GlobalPropertyBoolean\", \"description\": \"An object defining a global boolean property value for all features.\", \"type\": \"boolean\" }, \"globalPropertyScalar\": { \"title\": \"GlobalPropertyScalar\", \"description\": \"An object defining a global numeric property value for all features.\", \"oneOf\": [ { \"type\": \"object\", \"properties\": { \"byteOffset\": { \"type\": \"number\", \"description\": \"The offset into the buffer in bytes.\", \"minimum\": 0 } }, \"required\": [\"byteOffset\"] }, { \"type\": \"array\", \"items\": { \"type\": \"number\" }, \"minItems\": 1, \"maxItems\": 1 }, { \"type\": \"number\", \"minimum\": 0 } ] }, \"globalPropertyCartesian3\": { \"title\": \"GlobalPropertyCartesian3\", \"description\": \"An object defining a global 3-component numeric property values for all features.\", \"oneOf\": [ { \"type\": \"object\", \"properties\": { \"byteOffset\": { \"type\": \"number\", \"description\": \"The offset into the buffer in bytes.\", \"minimum\": 0 } }, \"required\": [\"byteOffset\"] }, { \"type\": \"array\", \"items\": { \"type\": \"number\" }, \"minItems\": 3, \"maxItems\": 3 } ] }, \"globalPropertyCartesian4\": { \"title\": \"GlobalPropertyCartesian4\", \"description\": \"An object defining a global 4-component numeric property values for all features.\", \"oneOf\": [ { \"type\": \"object\", \"properties\": { \"byteOffset\": { \"type\": \"number\", \"description\": \"The offset into the buffer in bytes.\", \"minimum\": 0 } }, \"required\": [\"byteOffset\"] }, { \"type\": \"array\", \"items\": { \"type\": \"number\" }, \"minItems\": 4, \"maxItems\": 4 } ] } }, \"properties\": { \"extensions\": { \"$ref\": \"extension.schema.json\" }, \"extras\": { \"$ref\": \"extras.schema.json\" } }, \"additionalProperties\": { \"$ref\": \"#/definitions/property\" } } 二进制体当 JSON 头包含对二进制文件的引用时,所提供的byteOffset内容将用于索引数据。下图显示了如何在要素表二进制体中索引数据: 使用要素数量来检索值,featuresLength;要素 ID,featureId;以及要素定义的其他数据类型(属性类型和长度)。 实例本节是非规范性的 以下示例使用POSITION访问 position 属性,POSITION是float32[3]的类型: var byteOffset = featureTableJSON.POSITION.byteOffset var positionArray = new Float32Array( featureTableBinary.buffer, byteOffset, featuresLength * 3 ) // There are three components for each POSITION feature. var position = positionArray.subarray(featureId * 3, featureId * 3 + 3) // Using subarray creates a view into the array, and not a new array. CesiumJS 的 3D Tiles 实现了读取要素表的功能,Cesium3DTileFeatureTable.js。 属性参考要素表 二进制体引用 属性 要素表一组语法定义,用于为瓦片中的要素提供每个瓦片每个要素的位置和属性的定义。 类型 描述 是否必须 extensions object 具有扩展特定对象的字典对象 No extras any 应用特定数据 No 允许其他属性。 二进制体引用一个对象,用于定义对要素表的二进制主体部分的引用,如果未在 JSON 头中直接定义属性值,则在该部分存储。 类型 描述 是否必须 byteOffset number 缓冲区的偏移量(以字节为单位) ✅ Yes 允许其他属性。 属性用户定义的属性,用于在数据中指定每个功能的特定于应用程序的元数据。值可以直接在 JSON 中定义为数组,也可以使用 二进制体引用 对象引用二进制主体中的部分。 JSON 参考,见上面。 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"3D Tiles","slug":"3D-Tiles","permalink":"https://tanghaojie.github.io/categories/3D-Tiles/"},{"name":"specification","slug":"3D-Tiles/specification","permalink":"https://tanghaojie.github.io/categories/3D-Tiles/specification/"}],"tags":[{"name":"specification","slug":"specification","permalink":"https://tanghaojie.github.io/tags/specification/"},{"name":"3D Tiles","slug":"3D-Tiles","permalink":"https://tanghaojie.github.io/tags/3D-Tiles/"}],"author":null},{"title":"3D Tiles复合对象(Composite)数据格式标准规范","slug":"2021-3d-tiles-2021-04-23-3d-tiles-c1om2posite-specification","date":"2021-04-23T13:44:17.000Z","updated":"2022-12-23T12:44:16.644Z","comments":true,"path":"2021/04/23/2021-3d-tiles-2021-04-23-3d-tiles-c1om2posite-specification/","link":"","permalink":"https://tanghaojie.github.io/2021/04/23/2021-3d-tiles-2021-04-23-3d-tiles-c1om2posite-specification/","excerpt":"","text":"导航 引 概述 文件结构 结构填充 文件头 内部瓦片 文件扩展名和 MIME 类型 实现示例 引官网文档 概述复合对象格式允许拼接的不同格式的数据变成一个区块。 3D 瓦片和复合对象瓦片为流式异构数据集提供了灵活性。例如,建筑物和树木可以存储在两个单独的“批处理 3D 模型”和“实例化 3D 模型”图块中,或者可以使用“复合”图块进行组合。 支持瓦片间(同一数据集中不同格式的不同瓦片)和瓦片内(同一复合图块中不同格式的瓦片)选项的异构数据集,使转换工具可以在多个请求之间进行权衡,优化特定类型的细分方式,以及可见/隐藏层的流式传输方式。 复合数据是小端字节序的二进制 Blob。 文件结构复合数据的文件结构(破折号表示可选字段): 结构填充数据 byteLength 必须以 8 个字节进行边界对齐。包含的所有数据也必须对齐 8 个字节的边界。 文件头16 字节的文件头包含以下字段: 字段名 类型 描述 magic 4 字节 ANSI 字符串 \"cmpt\" version uint32 版本。现在是1 byteLength uint32 整个复合数据的长度(包括标头和每个内部数据),以字节为单位 tilesLength uint32 复合中的图块数 内部瓦片内部瓦片字段紧跟在文件头部分之后。以下信息描述了复合图块读取器可能利用其来查找内部图块边界的所有图块格式的一般特征: 每个图块均以 4 字节 ANSI 字符串开头,该字符串 magic 可用于确定图块格式以进行进一步解析。有关可能格式的列表,请参见瓦片格式规范。复合图块可以包含复合图块。 每个图块的标头包含一个 uint32 byteLength,用于定义内部图块的长度(包括其标头),以字节为单位。这可用于遍历内部瓦片。 对于任何版本为 1 的图块格式,所有图块的前 12 个字节为以下字段: 字段名 类型 描述 magic 4 字节 ANSI 字符串 表示图块格式 version uint32 1 byteLength uint32 整个图块的长度(以字节为单位) 有关更多详细信息,请参考每种图块格式的规范。 文件扩展名和 MIME 类型复合图块使用.cmpt扩展名和application/octet-streamMIME 类型。 显式文件扩展名是可选的。有效的实现可能会忽略它,并通过 magic 其标头中的字段标识内容的格式。 实现示例本节是非规范性的 Python gltf2glb 工具集中的 packcmpt 工具包含用于将一个或多个“批处理 3D 模型”或“实例化 3D 模型”图块组合到单个“复合”图块文件中的代码。 可以在 3D Tiles 的 CesiumJS 实现 Composite3DTileContent.js 中找到用于读取文件头的代码 。 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"3D Tiles","slug":"3D-Tiles","permalink":"https://tanghaojie.github.io/categories/3D-Tiles/"},{"name":"specification","slug":"3D-Tiles/specification","permalink":"https://tanghaojie.github.io/categories/3D-Tiles/specification/"}],"tags":[{"name":"specification","slug":"specification","permalink":"https://tanghaojie.github.io/tags/specification/"},{"name":"3D Tiles","slug":"3D-Tiles","permalink":"https://tanghaojie.github.io/tags/3D-Tiles/"}],"author":null},{"title":"3D Tiles点云(Point Cloud)数据格式标准规范","slug":"2021-3d-tiles-2021-04-23-3d-tiles-point-cloud-specification","date":"2021-04-23T13:44:04.000Z","updated":"2022-12-23T12:44:16.645Z","comments":true,"path":"2021/04/23/2021-3d-tiles-2021-04-23-3d-tiles-point-cloud-specification/","link":"","permalink":"https://tanghaojie.github.io/2021/04/23/2021-3d-tiles-2021-04-23-3d-tiles-point-cloud-specification/","excerpt":"","text":"导航 引 概述 文件结构 结构填充 文件头 要素表 语法定义 点语法 全局语法 点位置 坐标系 RTC_CENTER 量化位置 点颜色 点法线 八进制编码的法向向量 批处理点 例子 仅位置 位置和颜色 量化位置和八进制编码法线 批处理点 每个点的属性 批量表 扩展 文件扩展名和 MIME 类型 实现示例 属性参考 引官网文档 概述点云瓦片格式支持大规模的点云三维可视化的高效数据流。每个点都由位置和可选的外观属性定义(例如颜色和法线)以及可选的定义特定于应用程序的元数据属性。 使用 3D Tiles 术语,每个点都是一个要是。 点云数据是小端字节序的二进制 Blob。 文件结构数据由文件头部分和紧随其后的二进制主体组成。下图显示了实例化 3D 模型的布局(破折号表示可选字段): 结构填充数据 byteLength 必须以 8 个字节进行边界对齐。包含的要素表(Feature Table)和批处理表(Batch Table)必须符合其各自的填充要求。 文件头28 字节的文件头包含以下字段: 字段名 数据类型 描述 magic 4-byte ANSI string \"pnts\" version uint32 版本。现在是1 byteLength uint32 整个数据的长度(包括文件头)(以字节为单位) featureTableJSONByteLength uint32 要素表 JSON 部分的长度(以字节为单位) featureTableBinaryByteLength uint32 要素表二进制部分的长度(以字节为单位) batchTableJSONByteLength uint32 批处理表 JSON 部分的长度(以字节为单位),零表示没有批处理表 batchTableBinaryByteLength uint32 批处理表二进制部分的长度(以字节为单位),如果batchTableJSONByteLength为零,则也将为零 主体部分紧着文件头,并且由Feature Table,Batch Table组成。 要素表包含每块和每点的值,这些值定义在何处以及如何渲染点。详见要素表(Feature Table)。 pnts 要素表模式的属性参考。完整的 JSON 模式可以在 pnts.featureTable.schema.json 中找到。 语法定义 点语法这些语法映射定义每个点的一组要素值数组。对于所有语法定义,这些数组的长度必须相同,并且等于点数。每个点语法的值必须是对要素表二进制主体的引用;它们不能嵌入要素表的 JSON 头中。 如果一个语法依赖于另一个语法,则必须定义该语法。如果同时为点定义 POSITION 和 POSITION_QUANTIZED ,POSITION 将使用更高精度的值。如果同时为点定义 NORMAL 和 NORMAL_OCT16P ,NORMAL 将使用更高精度的值。 语法 数据类型 描述 是否必须 POSITION float32[3] 由三部分组成的数组,包含点的笛卡尔坐标系x,y和z的位置 ✅ Yes, 是,除非定义了 POSITION_QUANTIZED POSITION_QUANTIZED uint16[3] 由三部分组成的数组,包含点的量化笛卡尔坐标系x,y和z的位置 ✅ Yes, 是,除非定义了 POSITION RGBA uint8[4] 由四部分组成的数组,包含点的RGBA颜色值 🔴 No. RGB uint8[3] 由三部分组成的数组,包含点的RGB颜色值 🔴 No. RGB565 uint16 一种有损压缩的颜色格式,将RGB颜色打包为 16 位,其中红色 5 位,绿色 6 位和蓝色 5 位 🔴 No. NORMAL float32[3] 定义点法线的单位向量 🔴 No. NORMAL_OCT16P uint8[2] 具有 16 位精度的八进制编码单位向量,用于定义点的法线 🔴 No. BATCH_ID uint8, uint16 (默认), or uint32 batchId用于从Batch Table检索点的元数据 🔴 No. 全局语法这些语法定义了所有点的全局属性。 语法 数据类型 描述 是否必须 POINTS_LENGTH uint32 渲染的点数。点定义的每个数组值的长度应等于此长度 ✅ Yes. RTC_CENTER float32[3] 由三部分组成的数组,包含当点相对于中心定义时的位置 🔴 No. QUANTIZED_VOLUME_OFFSET float32[3] 由三部分组成的数组,定义量化体积的偏移量 🔴 No, unless POSITION_QUANTIZED is defined. QUANTIZED_VOLUME_SCALE float32[3] 由三部分组成的数组,定义量化体积的比例。 🔴 No, unless POSITION_QUANTIZED is defined. CONSTANT_RGBA uint8[4] 由四部分组成的数组,定义所有点的RGBA颜色值 🔴 No. BATCH_LENGTH uint32 唯一的BATCH_ID值的数量 🔴 No, unless BATCH_ID is defined. 使用这些语法的示例可以在下面的实现示例中找到。 点位置POSITION 在应用任何图块转换之前定义点的位置。 坐标系3D Tiles 局部坐标系统使用右手 3 轴(x,y,z)直角坐标系;x 和 y 的叉积得出 z 。3D Tiles 定义 z 轴向上。 RTC_CENTER可以相对于中心位置定义以进行高精度渲染,参见 Precisions,Precisions。如果定义,则 RTC_CENTER 指定中心位置,并将所有点位置都视为相对于该值的位置。 量化位置如果 POSITION 未定义,则位置可以存储在POSITION_QUANTIZED中,该位置定义了相对于量化体积的点位置。如果 POSITION 和 POSITION_QUANTIZED 都未定义,则不需要渲染数据。 量化体积由offset和scale定义量化位置到本地空间位置的映射。下图显示了基于 offset 和 scale的量化体积: offset保存在全局语义QUANTIZED_VOLUME_OFFSET中,scale保存在全局语义QUANTIZED_VOLUME_SCALE中。如果这些全局语义未定义,POSITION_QUANTIZED 无法使用。 可以使用以下公式将量化位置映射到本地空间位置: POSITION = POSITION_QUANTIZED * QUANTIZED_VOLUME_SCALE / 65535.0 + QUANTIZED_VOLUME_OFFSET 点颜色如果定义多种颜色,则优先顺序是 RGBA,RGB,RGB565,CONSTANT_RGBA。例如,如果图块的要素表同时包含 RGBA 和 CONSTANT_RGBA 属性,则运行时使用RGBA 对每个点颜色进行渲染 。 如果没有颜色定义,则运行时可以使用特定于应用程序的默认颜色来自由设置点颜色。 任何情况下,运行时都可以使用 3D Tiles 样式 更改最终渲染的颜色和其他视觉属性。 点法线每个点的法线是一个可选属性,可以通过启用照明、隐藏的表面移除(hidden surface removal)和其他渲染技术来帮助改善点的视觉质量。使用平铺变换的逆转置来变换法线。 八进制编码的法向向量在独立单位向量的有效表示法中描述的八进制编码。八进制编码的值存储在无符号的非归一化范围([0, 255])中,然后在运行时映射到有符号的规范化范围([-1.0, 1.0])。 在 CesiumJS 的AttributeCompression模块中可以找到对这些单位矢量进行编码和解码的实现。 批处理点使用BATCH_ID可以将点云特定功能的点批处理在一起。例如,组成房屋门的所有点可以分配相同的BATCH_ID,而组成窗户的所有点分配不同的BATCH_ID。这对于按对象选择和存储应用程序特定的元数据以进行样式声明和特定于应用程序的用例(例如,填充 UI 或基于每个对象而不是基于每个点发出 REST API 请求)很有用。 BATCH_ID语义可以有一个 componentType 的 UNSIGNED_BYTE,UNSIGNED_SHORT 或 UNSIGNED_INT。当 componentType 不存在时,使用 UNSIGNED_SHORT。全局语义 BATCH_LENGTH 定义唯一 batchId 值的数量,类似于 Batched 3D Model 标头中的 batchLength 字段。 例子本节是非规范性的 这些示例说明如何为要素表生成 JSON 和二进制缓冲区。 仅位置这个最小示例在单位长度正方形的角上有四个点: var featureTableJSON = { \"POINTS_LENGTH\" : 4, \"POSITION\" : { \"byteOffset\" : 0 } }; var featureTableBinary = new Buffer(new Float32Array([ 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0 ]).buffer); 位置和颜色以下示例在地球上方有四个点(红,绿,蓝和黄)。它们的位置是相对于中心定义的: var featureTableJSON = { \"POINTS_LENGTH\" : 4, \"RTC_CENTER\" : [1215013.8, -4736316.7, 4081608.4], \"POSITION\" : { \"byteOffset\" : 0 }, \"RGB\" : { \"byteOffset\" : 48 } }; var positionBinary = new Buffer(new Float32Array([ 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0 ]).buffer); var colorBinary = new Buffer(new Uint8Array([ 255, 0, 0, 0, 255, 0, 0, 0, 255, 255, 255, 0, ]).buffer); var featureTableBinary = Buffer.concat([positionBinary, colorBinary]); 量化位置和八进制编码法线在此示例中,四个点的法线以八进制编码格式指向朝上[0.0, 1.0, 0.0],并且将它们放置在量化体积的角上,在x和z方向上的跨度为-250.0 到 250.0 个单位: var featureTableJSON = { \"POINTS_LENGTH\" : 4, \"QUANTIZED_VOLUME_OFFSET\" : [-250.0, 0.0, -250.0], \"QUANTIZED_VOLUME_SCALE\" : [500.0, 0.0, 500.0], \"POSITION_QUANTIZED \": { \"byteOffset\" : 0 }, \"NORMAL_OCT16P\" : { \"byteOffset\" : 24 } }; var positionQuantizedBinary = new Buffer(new Uint16Array([ 0, 0, 0, 65535, 0, 0, 0, 0, 65535, 65535, 0, 65535 ]).buffer); var normalOct16PBinary = new Buffer(new Uint8Array([ 128, 255, 128, 255, 128, 255, 128, 255 ]).buffer); var featureTableBinary = Buffer.concat([positionQuantizedBinary, normalOct16PBinary]); 批处理点在此示例中,前两个点的batchId为0,后两个点的batchId 为1。请注意,批处理表只有两个名称: var featureTableJSON = { \"POINTS_LENGTH\" : 4, \"BATCH_LENGTH\" : 2, \"POSITION\" : { \"byteOffset\" : 0 }, BATCH_ID : { \"byteOffset\" : 48, \"componentType\" : \"UNSIGNED_BYTE\" } }; var positionBinary = new Buffer(new Float32Array([ 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0 ]).buffer); var batchIdBinary = new Buffer(new Uint8Array([ 0, 0, 1, 1 ]).buffer); var featureTableBinary = Buffer.concat([positionBinary, batchIdBinary]); var batchTableJSON = { \"names\" : ['object1', 'object2'] }; 每个点的属性在此示例中,这 4 个点中的每个点都将元数据存储在 Batch Table JSON 和二进制文件中。 var featureTableJSON = { \"POINTS_LENGTH \": 4, \"POSITION\" : { \"byteOffset\" : 0 } }; var featureTableBinary = new Buffer(new Float32Array([ 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0 ]).buffer); var batchTableJSON = { \"names\" : ['point1', 'point2', 'point3', 'point4'] }; 批量表批处理表包含应用程序特定的元数据,通过batchId进行索引,可被用于声明式样式和应用特定的用例如填充 UI 或者发出 REST API 请求。 如果BATCH_ID定义,则批处理表将存储每个元数据batchId,并且批处理表数组的长度将等于BATCH_LENGTH。 如果BATCH_ID未定义,则批处理表将存储每个点的元数据,并且批处理表数组的长度将等于POINTS_LENGTH。 更多信息,请参见批处理表(Batch Table)。 扩展以下扩展可以应用于点云瓦片。 3DTILES_draco_point_compression 文件扩展名和 MIME 类型点云瓦片使用.pnts 扩展名和 application/octet-stream MIME 类型。 显式文件扩展名是可选的。有效的实现可能会忽略它,并通过 magic 其标头中的字段标识内容的格式。 实现示例本节是非规范性的 可以在 3D Tiles 的 CesiumJS 实现PointCloud3DModelTileContent.js中找到用于读取标头的代码。 属性参考 点云要素表 二进制体引用 全局笛卡尔 3 坐标系属性 全局笛卡尔 4 坐标系属性 全局标量属性 属性 点云要素表一组点云语义,其中包含定义图块中点的位置和外观属性的值。 类型 描述 是否必须 extensions object 扩展特定的字典对象 No extras any 应用特定数据 No POSITION object 二进制体引用 对象,定义存储了属性值的二进制体部分的引用。查看相应属性的定义语法定义 No POSITION_QUANTIZED object 二进制体引用 对象,定义存储了属性值的二进制体部分的引用。查看相应属性的定义语法定义 No RGBA object 二进制体引用 对象,定义存储了属性值的二进制体部分的引用。查看相应属性的定义语法定义 No RGB object 二进制体引用 对象,定义存储了属性值的二进制体部分的引用。查看相应属性的定义语法定义 No RGB565 object 二进制体引用 对象,定义存储了属性值的二进制体部分的引用。查看相应属性的定义语法定义 No NORMAL object 二进制体引用 对象,定义存储了属性值的二进制体部分的引用。查看相应属性的定义语法定义 No NORMAL_OCT16P object 二进制体引用 对象,定义存储了属性值的二进制体部分的引用。查看相应属性的定义语法定义 No BATCH_ID object 二进制体引用 对象,定义存储了属性值的二进制体部分的引用。查看相应属性的定义语法定义 No POINTS_LENGTH object, number [1], number 全局标量属性 对象,定义所有要素的数量。查看相应属性的定义语法定义 ✅ Yes RTC_CENTER object, number [3] 全局笛卡尔 3 坐标系属性 对象,定义所有要素的数量。查看相应属性的定义语法定义 No QUANTIZED_VOLUME_OFFSET object, number [3] 全局笛卡尔 3 坐标系属性 对象,定义所有要素的数量。查看相应属性的定义语法定义 No QUANTIZED_VOLUME_SCALE object, number [3] 全局笛卡尔 3 坐标系属性 对象,定义所有要素的数量。查看相应属性的定义语法定义 No CONSTANT_RGBA object, number [4] 全局笛卡尔 4 坐标系属性 对象,定义所有要素的数量。查看相应属性的定义语法定义 No BATCH_LENGTH object, number [1], number 全局标量属性 对象,定义所有要素的数量。查看相应属性的定义语法定义 No 允许其他属性。 二进制体引用一个对象,用于定义对要素表的二进制主体部分的引用,如果未在 JSON 中直接定义属性值,则在该部分存储属性值。 类型 描述 是否必须 byteOffset number 缓冲区的偏移量(以字节为单位) ✅ Yes 全局笛卡尔 3 坐标系属性为所有要素定义全局 3 组分数值属性值的对象。 全局笛卡尔 4 坐标系属性为所有要素定义全局 4 组分数值属性值的对象。 全局标量属性为所有要素定义全局数值属性值的对象。 属性用户自定义的属性,用来在数据中指定每个要素的应用程序特定的元数据。值可以直接在 JSON 中定义为数组,也可以引用二进制体中的部分。 JSON 定义示例 { \"$schema\": \"http://json-schema.org/draft-04/schema\", \"id\": \"featureTable.schema.json\", \"title\": \"Feature Table\", \"type\": \"object\", \"description\": \"A set of semantics containing per-tile and per-feature values defining the position and appearance properties for features in a tile.\", \"definitions\": { \"binaryBodyReference\": { \"title\": \"BinaryBodyReference\", \"type\": \"object\", \"description\": \"An object defining the reference to a section of the binary body of the features table where the property values are stored if not defined directly in the JSON.\", \"properties\": { \"byteOffset\": { \"type\": \"number\", \"description\": \"The offset into the buffer in bytes.\", \"minimum\": 0 }, \"componentType\": { \"type\": \"number\", \"description\": \"The datatype of components in the property. This is defined only if the semantic allows for overriding the implicit component type. These cases are specified in each tile format.\", \"enum\": [ \"BYTE\", \"UNSIGNED_BYTE\", \"SHORT\", \"UNSIGNED_SHORT\", \"INT\", \"UNSIGNED_INT\", \"FLOAT\", \"DOUBLE\" ] } }, \"required\": [\"byteOffset\"] }, \"numericArray\": { \"type\": \"array\", \"items\": { \"type\": \"number\" } }, \"property\": { \"title\": \"Property\", \"description\": \"A user-defined property which specifies per-feature application-specific metadata in a tile. Values either can be defined directly in the JSON as an array, or can refer to sections in the binary body with a `BinaryBodyReference` object.\", \"oneOf\": [ { \"$ref\": \"#/definitions/binaryBodyReference\" }, { \"type\": \"array\", \"items\": { \"type\": \"number\" } }, { \"type\": \"number\" } ] }, \"globalPropertyBoolean\": { \"title\": \"GlobalPropertyBoolean\", \"description\": \"An object defining a global boolean property value for all features.\", \"type\": \"boolean\" }, \"globalPropertyScalar\": { \"title\": \"GlobalPropertyScalar\", \"description\": \"An object defining a global numeric property value for all features.\", \"oneOf\": [ { \"type\": \"object\", \"properties\": { \"byteOffset\": { \"type\": \"number\", \"description\": \"The offset into the buffer in bytes.\", \"minimum\": 0 } }, \"required\": [\"byteOffset\"] }, { \"type\": \"array\", \"items\": { \"type\": \"number\" }, \"minItems\": 1, \"maxItems\": 1 }, { \"type\": \"number\", \"minimum\": 0 } ] }, \"globalPropertyCartesian3\": { \"title\": \"GlobalPropertyCartesian3\", \"description\": \"An object defining a global 3-component numeric property values for all features.\", \"oneOf\": [ { \"type\": \"object\", \"properties\": { \"byteOffset\": { \"type\": \"number\", \"description\": \"The offset into the buffer in bytes.\", \"minimum\": 0 } }, \"required\": [\"byteOffset\"] }, { \"type\": \"array\", \"items\": { \"type\": \"number\" }, \"minItems\": 3, \"maxItems\": 3 } ] }, \"globalPropertyCartesian4\": { \"title\": \"GlobalPropertyCartesian4\", \"description\": \"An object defining a global 4-component numeric property values for all features.\", \"oneOf\": [ { \"type\": \"object\", \"properties\": { \"byteOffset\": { \"type\": \"number\", \"description\": \"The offset into the buffer in bytes.\", \"minimum\": 0 } }, \"required\": [\"byteOffset\"] }, { \"type\": \"array\", \"items\": { \"type\": \"number\" }, \"minItems\": 4, \"maxItems\": 4 } ] } }, \"properties\": { \"extensions\": { \"$ref\": \"extension.schema.json\" }, \"extras\": { \"$ref\": \"extras.schema.json\" } }, \"additionalProperties\": { \"$ref\": \"#/definitions/property\" } } 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"3D Tiles","slug":"3D-Tiles","permalink":"https://tanghaojie.github.io/categories/3D-Tiles/"},{"name":"specification","slug":"3D-Tiles/specification","permalink":"https://tanghaojie.github.io/categories/3D-Tiles/specification/"}],"tags":[{"name":"specification","slug":"specification","permalink":"https://tanghaojie.github.io/tags/specification/"},{"name":"3D Tiles","slug":"3D-Tiles","permalink":"https://tanghaojie.github.io/tags/3D-Tiles/"}],"author":null},{"title":"3D Tiles实例3D模型(Instanced 3D Model)数据格式标准规范","slug":"2021-3d-tiles-2021-04-23-3d-tiles-instanced-3d-model-specification","date":"2021-04-23T13:43:49.000Z","updated":"2022-12-23T12:44:16.644Z","comments":true,"path":"2021/04/23/2021-3d-tiles-2021-04-23-3d-tiles-instanced-3d-model-specification/","link":"","permalink":"https://tanghaojie.github.io/2021/04/23/2021-3d-tiles-2021-04-23-3d-tiles-instanced-3d-model-specification/","excerpt":"","text":"导航 引 概述 文件结构 结构填充 文件头 要素表 语法定义 实例语法 全局语法 实例方向 八进制编码的法向向量 默认方向 实例位置 RTC_CENTER 量化位置 实例缩放 例子 仅位置 量化位置和八进制编码法线 批处理表 glTF 坐标系 文件扩展名和 MIME 类型 属性参考 引官网文档 概述实例 3D 模型是一种切片数据格式,用于高效地流式传输和渲染大数据量的模型,称为实例,但会稍有变化。在最简单的情况下,例如,同一棵树模型可能会放置在多个地方(实例化)。每个实例都引用相同的模型,但每个实例都有属性,例如位置。使用 core 3D Tiles 规范语言,每个实例是一个要素。 除树木外,实例 3D 模型还可用于表面特征(例如消火栓,下水道盖,灯和交通信号灯),以及用于内部 CAD 特征(例如螺栓,阀门和电源插座)。 实例化 3D 模型数据是小端字节序的二进制 Blob。 实现提示:复合对象 (Composite)可以通过组合不同类型的实例模型来创建,例如,通过合并两个实例化 3D 模型图块来绘制树木和交通信号灯。 实现提示:实例化 3D 模型可以很好地映射到 ANGLE_instanced_arrays 扩展,以便使用 WebGL 进行高效渲染。 文件结构数据由文件头部分和紧随其后的二进制主体组成。下图显示了实例化 3D 模型的布局(破折号表示可选字段): 结构填充数据 byteLength 必须以 8 个字节进行边界对齐。包含的要素表(Feature Table)和批处理表(Batch Table)必须符合其各自的填充要求。 二进制 glTF (如果存在)的开始和结束位置必须以 8 个字节进行边界对齐,以便满足 glTF 的字节对齐要求。这可以通过填充功能表或批处理表(如果存在)来实现。 否则,如果 glTF 字段是 UTF-8 字符串,则必须用尾随空格字符(0x20)填充它,以满足数据的对齐要求,在请求 glTF 数据之前,必须在运行时将其删除。 文件头32 字节的文件头包含以下字段: Field name Data type Description magic 4-byte ANSI string \"i3dm\"。用于将内容标识为“实例 3D 模型” version uint32 版本。现在是1 byteLength uint32 整个数据的长度(包括文件头),以字节为单位 featureTableJSONByteLength uint32 要素表 JSON 部分的长度(以字节为单位) featureTableBinaryByteLength uint32 要素表二进制部分的长度(以字节为单位) batchTableJSONByteLength uint32 批处理表 JSON 部分的长度(以字节为单位),零表示没有批处理表 batchTableBinaryByteLength uint32 批处理表二进制部分的长度(以字节为单位),如果batchTableJSONByteLength为零,则也将为零 gltfFormat uint32 指示主体的 glTF 字段的格式。 0表示它是一个 uri,1表示它是嵌入式二进制 glTF。请参阅下面的 glTF 部分。 主体部分紧着文件头,并且由三个字段组成:Feature Table,Batch Table,和glTF。 要素表要素表包含i3dm用于创建实例模型的语法值。更多信息请查看要素表(Feature Table)规范。 在属性参考 查看i3dm 要素表的参考。完整 JSON 定义i3dm.featureTable.schema.json。 { \"$schema\": \"http://json-schema.org/draft-04/schema\", \"id\": \"i3dm.featureTable.schema.json\", \"title\": \"Instanced 3D Model Feature Table\", \"type\": \"object\", \"description\": \"A set of Instanced 3D Model semantics that contains values defining the position and appearance properties for instanced models in a tile.\", \"allOf\": [ { \"$ref\": \"featureTable.schema.json\" }, { \"properties\": { \"POSITION\": { \"description\": \"A `BinaryBodyReference` object defining the reference to a section of the binary body where the property values are stored. See the corresponding property semantic in [Semantics](/specification/TileFormats/Instanced3DModel/README.md#semantics).\", \"allOf\": [ { \"$ref\": \"featureTable.schema.json#/definitions/binaryBodyReference\" } ] }, \"POSITION_QUANTIZED\": { \"description\": \"A `BinaryBodyReference` object defining the reference to a section of the binary body where the property values are stored. See the corresponding property semantic in [Semantics](/specification/TileFormats/Instanced3DModel/README.md#semantics).\", \"allOf\": [ { \"$ref\": \"featureTable.schema.json#/definitions/binaryBodyReference\" } ] }, \"NORMAL_UP\": { \"description\": \"A `BinaryBodyReference` object defining the reference to a section of the binary body where the property values are stored. See the corresponding property semantic in [Semantics](/specification/TileFormats/Instanced3DModel/README.md#semantics).\", \"allOf\": [ { \"$ref\": \"featureTable.schema.json#/definitions/binaryBodyReference\" } ] }, \"NORMAL_RIGHT\": { \"description\": \"A `BinaryBodyReference` object defining the reference to a section of the binary body where the property values are stored. See the corresponding property semantic in [Semantics](/specification/TileFormats/Instanced3DModel/README.md#semantics).\", \"allOf\": [ { \"$ref\": \"featureTable.schema.json#/definitions/binaryBodyReference\" } ] }, \"NORMAL_UP_OCT32P\": { \"description\": \"A `BinaryBodyReference` object defining the reference to a section of the binary body where the property values are stored. See the corresponding property semantic in [Semantics](/specification/TileFormats/Instanced3DModel/README.md#semantics).\", \"allOf\": [ { \"$ref\": \"featureTable.schema.json#/definitions/binaryBodyReference\" } ] }, \"NORMAL_RIGHT_OCT32P\": { \"description\": \"A `BinaryBodyReference` object defining the reference to a section of the binary body where the property values are stored. See the corresponding property semantic in [Semantics](/specification/TileFormats/Instanced3DModel/README.md#semantics).\", \"allOf\": [ { \"$ref\": \"featureTable.schema.json#/definitions/binaryBodyReference\" } ] }, \"SCALE\": { \"description\": \"A `BinaryBodyReference` object defining the reference to a section of the binary body where the property values are stored. See the corresponding property semantic in [Semantics](/specification/TileFormats/Instanced3DModel/README.md#semantics).\", \"allOf\": [ { \"$ref\": \"featureTable.schema.json#/definitions/binaryBodyReference\" } ] }, \"SCALE_NON_UNIFORM\": { \"description\": \"A `BinaryBodyReference` object defining the reference to a section of the binary body where the property values are stored. See the corresponding property semantic in [Semantics](/specification/TileFormats/Instanced3DModel/README.md#semantics).\", \"allOf\": [ { \"$ref\": \"featureTable.schema.json#/definitions/binaryBodyReference\" } ] }, \"BATCH_ID\": { \"description\": \"A `BinaryBodyReference` object defining the reference to a section of the binary body where the property values are stored. See the corresponding property semantic in [Semantics](/specification/TileFormats/Instanced3DModel/README.md#semantics).\", \"allOf\": [ { \"$ref\": \"featureTable.schema.json#/definitions/binaryBodyReference\" } ] }, \"INSTANCES_LENGTH\": { \"description\": \"A `GlobalPropertyScalar` object defining a numeric property for all features. See the corresponding property semantic in [Semantics](/specification/TileFormats/Instanced3DModel/README.md#semantics).\", \"allOf\": [ { \"$ref\": \"featureTable.schema.json#/definitions/globalPropertyScalar\" } ] }, \"RTC_CENTER\": { \"description\": \"A `GlobalPropertyCartesian3` object defining a 3-component numeric property for all features. See the corresponding property semantic in [Semantics](/specification/TileFormats/Instanced3DModel/README.md#semantics).\", \"allOf\": [ { \"$ref\": \"featureTable.schema.json#/definitions/globalPropertyCartesian3\" } ] }, \"QUANTIZED_VOLUME_OFFSET\": { \"description\": \"A `GlobalPropertyCartesian3` object defining a 3-component numeric property for all features. See the corresponding property semantic in [Semantics](/specification/TileFormats/Instanced3DModel/README.md#semantics).\", \"allOf\": [ { \"$ref\": \"featureTable.schema.json#/definitions/globalPropertyCartesian3\" } ] }, \"QUANTIZED_VOLUME_SCALE\": { \"description\": \"A `GlobalPropertyCartesian3` object defining a 3-component numeric property for all features. See the corresponding property semantic in [Semantics](/specification/TileFormats/Instanced3DModel/README.md#semantics).\", \"allOf\": [ { \"$ref\": \"featureTable.schema.json#/definitions/globalPropertyCartesian3\" } ] }, \"EAST_NORTH_UP\": { \"description\": \"A `GlobalPropertyBoolean` object defining a boolean property for all features. See the corresponding property semantic in [Semantics](/specification/TileFormats/Instanced3DModel/README.md#semantics).\", \"allOf\": [ { \"$ref\": \"featureTable.schema.json#/definitions/globalPropertyBoolean\" } ] }, \"extensions\": { \"$ref\": \"extension.schema.json\" }, \"extras\": { \"$ref\": \"extras.schema.json\" } }, \"oneOf\": [ { \"required\": [\"POSITION\"] }, { \"required\": [\"POSITION_QUANTIZED\"] } ], \"dependencies\": { \"POSITION_QUANTIZED\": [ \"QUANTIZED_VOLUME_OFFSET\", \"QUANTIZED_VOLUME_SCALE\" ], \"NORMAL_UP\": [\"NORMAL_RIGHT\"], \"NORMAL_RIGHT\": [\"NORMAL_UP\"], \"NORMAL_UP_OCT32P\": [\"NORMAL_RIGHT_OCT32P\"], \"NORMAL_RIGHT_OCT32P\": [\"NORMAL_UP_OCT32P\"] }, \"required\": [\"INSTANCES_LENGTH\"] } ] } 语法定义 实例语法语法映射到要素值的数组,用于创建实例的。对于语法,这些数组的长度必须相同,并且必须等于实例数。每个实例的值必须是对要素表二进制主体的引用;它们不能嵌入要素表的 JSON 头中。 如果一个语法依赖于另一个语法,则必须定义该语法。如果实例同时定义了 SCALE 和 SCALE_NON_UNIFORM,则将应用两个缩放操作。如果实例同时定义了 POSITION 和 POSITION_QUANTIZED,更高精度的POSITION 将被使用。如果实例同时定义了 NORMAL_UP,NORMAL_RIGHT,NORMAL_UP_OCT32P,和 NORMAL_RIGHT_OCT32P,更高精度的 NORMAL_UP 和 NORMAL_RIGHT 将被使用。 语法 数据类型 描述 是否必须 POSITION float32[3] 3 个部分的数组包含x,y以及z的笛卡尔坐标表示实例的位置 ✅ Yes, 除非定义了 POSITION_QUANTIZED POSITION_QUANTIZED uint16[3] 3 个部分的数组包含x,y以及z的量化笛卡尔坐标(quantized Cartesian coordinates)表示实例的位置 ✅ Yes, 除非定义了 POSITION NORMAL_UP float32[3] 定义实例up方向的单位向量 🔴 No, 除非定义了 NORMAL_RIGHT NORMAL_RIGHT float32[3] 定义实例right方向的单位向量,必须与up方向正交 🔴 No, 除非定义了 NORMAL_UP NORMAL_UP_OCT32P uint16[2] 32 位精度的八进制编码的单位矢量,up用于定义实例定向的方向 🔴 No, 除非定义了 NORMAL_RIGHT_OCT32P NORMAL_RIGHT_OCT32P uint16[2] 32 位精度的八进制编码的单位矢量,right用于定义实例定向的方向,必须与up方向正交 🔴 No, 除非定义了 NORMAL_UP_OCT32P SCALE float32 一个数字用于定义实例所有轴的比例 🔴 No. SCALE_NON_UNIFORM float32[3] 3 个部分数组的比例数字,定义实例x,y以及z轴的比例 🔴 No. BATCH_ID uint8, uint16 (default), or uint32 实例的batchId用于从Batch Table检索元数据 🔴 No. 全局语法这些语法定义了所有实例的全局属性。 语法 数据类型 描述 是否必须 INSTANCES_LENGTH uint32 要生成的实例数。实例语义的每个数组值的长度应等于此长度 ✅ Yes. RTC_CENTER float32[3] 当实例位置相对于中心定义时,由三部分组成的数字数组定义中心位. 🔴 No. QUANTIZED_VOLUME_OFFSET float32[3] 由三部分组成的数字数组,用于定义量化体积的偏移量 🔴 No, 除非定义了 POSITION_QUANTIZED QUANTIZED_VOLUME_SCALE float32[3] 由三部分组成的数字数组,用于定义量化体积的比例 🔴 No, 除非定义了 POSITION_QUANTIZED EAST_NORTH_UP boolean 当true未定义按实例的方向时,每个实例将默认为椭球east/north/up上参考框架的方向WGS84 🔴 No. 实例方向实例的方向由up和right矢量创建的正交基准定义。方向将通过瓦片变换 进行。 x标准基向量在变换时映射到right基向量,y向量映射到up向量。z向量映射到forward向量,但它忽略,因为它总是right和up的正交。 在标准坐标轴中的盒子 经过旋转变换的盒子 八进制编码的法向向量如果NORMAL_UP与NORMAL_RIGHT不被实例所定义,其取向可以被存储为八进制编码的法向NORMAL_UP_OCT32P和NORMAL_RIGHT_OCT32P。它们定义up和right使用独立单位向量的有效表示法中描述的八进制编码。八进制编码的值存储在无符号的非规范化范围([0, 65535])中,然后在运行时映射到有符号([-1.0, 1.0])的规范化范围。 在 CesiumJS 的AttributeCompression模块中可以找到对这些单位矢量进行编码和解码的实现。 默认方向如果不存在NORMAL_UP和NORMAL_RIGHT或NORMAL_UP_OCT32P和NORMAL_RIGHT_OCT32P,则实例将没有自定义方向。如果EAST_NORTH_UP为 true,则假定该实例位于WGS84椭球体上,并且其方向将默认为east/north/up参考框架在其制图位置处的位置。这适用于诸如树木之类的实例模型,其方向始终从其在椭球表面上的位置朝上。 实例位置POSITION定义实例的位置,在应用任何变换之前。 RTC_CENTER可以相对于中心定义位置以进行高精度渲染,请参见Precisions,Precisions。如果定义,则 RTC_CENTER 指定中心位置,并且所有实例位置均相对于此值。 量化位置如果没有为实例定义POSITION,则其位置可以存储在POSITION_QUANTIZED中,其定义了相对于量化体的实例位置。如果没有 POSITION 或 POSITION_QUANTIZED 定义,实例将不会被创建。 量化体由offset和scale定义,并将量化的位置映射到局部空间,如下图所示: offset全局语义存储在QUANTIZED_VOLUME_OFFSET,scale全局语义存储在QUANTIZED_VOLUME_SCALE。如果未定义这些全局语义,则POSITION_QUANTIZED无法使用。 可以使用以下公式将量化的位置映射到本地空间: POSITION = POSITION_QUANTIZED \\* QUANTIZED_VOLUME_SCALE / 65535.0 + QUANTIZED_VOLUME_OFFSET 实例缩放缩放可以使用SCALE和SCALE_NON_UNIFORM语义应用于实例。 SCALE沿着所有轴应用统一的缩放,SCALE_NON_UNIFORM分别在x,y和z轴应用独立的缩放。 例子这些示例说明如何为要素表生成 JSON 和二进制缓冲区。 仅位置在这个最小的示例中,我们将四个实例以默认方向放置在单位长度正方形的角上: var featureTableJSON = { INSTANCES_LENGTH: 4, POSITION: { byteOffset: 0 } } var featureTableBinary = new Buffer( new Float32Array([ 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0 ]).buffer ) 量化位置和八进制编码法线在此示例中,四个实例会被放置在up方向为[0.0, 1.0, 0.0],right 为[1.0, 0.0, 0.0]的八进制编码格式,并且将它们放置在量化体积的角上,该量化体积在x和z方向上跨度为-250.0 到 250.0 个单位: var featureTableJSON = { INSTANCES_LENGTH: 4, QUANTIZED_VOLUME_OFFSET: [-250.0, 0.0, -250.0], QUANTIZED_VOLUME_SCALE: [500.0, 0.0, 500.0], POSITION_QUANTIZED: { byteOffset: 0 }, NORMAL_UP_OCT32P: { byteOffset: 24 }, NORMAL_RIGHT_OCT32P: { byteOffset: 40 } } var positionQuantizedBinary = new Buffer( new Uint16Array([0, 0, 0, 65535, 0, 0, 0, 0, 65535, 65535, 0, 65535]).buffer ) var normalUpOct32PBinary = new Buffer( new Uint16Array([ 32768, 65535, 32768, 65535, 32768, 65535, 32768, 65535 ]).buffer ) var normalRightOct32PBinary = new Buffer( new Uint16Array([ 65535, 32768, 65535, 32768, 65535, 32768, 65535, 32768 ]).buffer ) var featureTableBinary = Buffer.concat([ positionQuantizedBinary, normalUpOct32PBinary, normalRightOct32PBinary ]) 批处理表包含由batchId组成的元数据,可用于样式声明。有关更多信息,请参见批处理表(Batch Table)。 glTF实例化 3D 模型嵌入了包含模型几何和纹理信息的 glTF 2.0。 glTF 资源存储在要素表和批处理表之后。它可能嵌入了所有的几何,纹理和动画,或者可能引用了某些或所有这些数据的外部来源。 header.gltfFormat 确定 glTF 字段的格式 当 header.gltfFormat 的值是 0, glTF 字段是 UTF-8 字符串,其包含 glTF 或二进制 glTF 模型的内容的 URI。 当 header.gltfFormat 的值是 1,glTF 字段是包含二进制 glTF 的二进制 blob 。 坐标系默认情况下,glTF 使用右手坐标系,其中 y 轴朝上。为了与 3D Tiles 的 z 向上坐标系保持一致,必须在运行时转换 glTF。有关更多详细信息,请参见glTF 变换 。 文件扩展名和 MIME 类型实例化 3D 模型使用.i3dm 扩展名和 application/octet-stream MIME 类型。 显式文件扩展名是可选的。有效的实现可能会忽略它,并通过 magic 其标头中的字段标识内容的格式。 属性参考 实例化 3D 模型要素表 二进制体引用 全局笛卡尔坐标系属性 全局标量属性 全局布尔属性 属性 实例化 3D 模型要素表一组实例化 3D 模型语义,其中包含定义图块中实例化模型的位置和外观属性的值。 类型 描述 是否必须 extensions object 扩展特定的字典对象 No extras any 应用特定数据 No POSITION object 二进制体引用 对象,定义存储了属性值的二进制体部分的引用。查看相应属性的定义语法 No POSITION_QUANTIZED object 二进制体引用 对象,定义存储了属性值的二进制体部分的引用。查看相应属性的定义语法 No NORMAL_UP object 二进制体引用 对象,定义存储了属性值的二进制体部分的引用。查看相应属性的定义语法 No NORMAL_RIGHT object 二进制体引用 对象,定义存储了属性值的二进制体部分的引用。查看相应属性的定义语法 No NORMAL_UP_OCT32P object 二进制体引用 对象,定义存储了属性值的二进制体部分的引用。查看相应属性的定义语法 No NORMAL_RIGHT_OCT32P object 二进制体引用 对象,定义存储了属性值的二进制体部分的引用。查看相应属性的定义语法 No SCALE object 二进制体引用 对象,定义存储了属性值的二进制体部分的引用。查看相应属性的定义语法 No SCALE_NON_UNIFORM object 二进制体引用 对象,定义存储了属性值的二进制体部分的引用。查看相应属性的定义语法 No BATCH_ID object 二进制体引用 对象,定义存储了属性值的二进制体部分的引用。查看相应属性的定义语法 No INSTANCES_LENGTH object, number [1], number 全局标量属性 对象,定义所有要素的数量。查看相应属性的定义语法 ✅ Yes RTC_CENTER object, number [3] 全局笛卡尔坐标系属性 对象,定义所有要素的 3 部分数值属性。查看相应属性的定义语法 No QUANTIZED_VOLUME_OFFSET object, number [3] 全局笛卡尔坐标系属性 对象,定义所有要素的 3 部分数值属性。查看相应属性的定义语法 No QUANTIZED_VOLUME_SCALE object, number [3] 全局笛卡尔坐标系属性 对象,定义所有要素的 3 部分数值属性。查看相应属性的定义语法 No EAST_NORTH_UP boolean 全局布尔属性 对象,定义所有要素的布尔值属性。查看相应属性的定义语法 No 允许其他属性。 二进制体引用一个对象,用于定义对要素表的二进制主体部分的引用,如果未在 JSON 中直接定义属性值,则在该部分存储属性值。 类型 描述 是否必须 byteOffset number 缓冲区的偏移量(以字节为单位) ✅ Yes 允许其他属性。 全局笛卡尔坐标系属性为所有要素定义全局 3 组分数值属性值的对象。 全局标量属性为所有要素定义全局数值属性值的对象。 全局布尔属性为所有要素定义全局布尔属性值的对象。 属性用户自定义的属性,用来在数据中指定每个要素的应用程序特定的元数据。值可以直接在 JSON 中定义为数组,也可以引用二进制体中的部分。 JSON 定义示例 { \"$schema\": \"http://json-schema.org/draft-04/schema\", \"id\": \"featureTable.schema.json\", \"title\": \"Feature Table\", \"type\": \"object\", \"description\": \"A set of semantics containing per-tile and per-feature values defining the position and appearance properties for features in a tile.\", \"definitions\": { \"binaryBodyReference\": { \"title\": \"BinaryBodyReference\", \"type\": \"object\", \"description\": \"An object defining the reference to a section of the binary body of the features table where the property values are stored if not defined directly in the JSON.\", \"properties\": { \"byteOffset\": { \"type\": \"number\", \"description\": \"The offset into the buffer in bytes.\", \"minimum\": 0 }, \"componentType\": { \"type\": \"number\", \"description\": \"The datatype of components in the property. This is defined only if the semantic allows for overriding the implicit component type. These cases are specified in each tile format.\", \"enum\": [ \"BYTE\", \"UNSIGNED_BYTE\", \"SHORT\", \"UNSIGNED_SHORT\", \"INT\", \"UNSIGNED_INT\", \"FLOAT\", \"DOUBLE\" ] } }, \"required\": [\"byteOffset\"] }, \"numericArray\": { \"type\": \"array\", \"items\": { \"type\": \"number\" } }, \"property\": { \"title\": \"Property\", \"description\": \"A user-defined property which specifies per-feature application-specific metadata in a tile. Values either can be defined directly in the JSON as an array, or can refer to sections in the binary body with a `BinaryBodyReference` object.\", \"oneOf\": [ { \"$ref\": \"#/definitions/binaryBodyReference\" }, { \"type\": \"array\", \"items\": { \"type\": \"number\" } }, { \"type\": \"number\" } ] }, \"globalPropertyBoolean\": { \"title\": \"GlobalPropertyBoolean\", \"description\": \"An object defining a global boolean property value for all features.\", \"type\": \"boolean\" }, \"globalPropertyScalar\": { \"title\": \"GlobalPropertyScalar\", \"description\": \"An object defining a global numeric property value for all features.\", \"oneOf\": [ { \"type\": \"object\", \"properties\": { \"byteOffset\": { \"type\": \"number\", \"description\": \"The offset into the buffer in bytes.\", \"minimum\": 0 } }, \"required\": [\"byteOffset\"] }, { \"type\": \"array\", \"items\": { \"type\": \"number\" }, \"minItems\": 1, \"maxItems\": 1 }, { \"type\": \"number\", \"minimum\": 0 } ] }, \"globalPropertyCartesian3\": { \"title\": \"GlobalPropertyCartesian3\", \"description\": \"An object defining a global 3-component numeric property values for all features.\", \"oneOf\": [ { \"type\": \"object\", \"properties\": { \"byteOffset\": { \"type\": \"number\", \"description\": \"The offset into the buffer in bytes.\", \"minimum\": 0 } }, \"required\": [\"byteOffset\"] }, { \"type\": \"array\", \"items\": { \"type\": \"number\" }, \"minItems\": 3, \"maxItems\": 3 } ] }, \"globalPropertyCartesian4\": { \"title\": \"GlobalPropertyCartesian4\", \"description\": \"An object defining a global 4-component numeric property values for all features.\", \"oneOf\": [ { \"type\": \"object\", \"properties\": { \"byteOffset\": { \"type\": \"number\", \"description\": \"The offset into the buffer in bytes.\", \"minimum\": 0 } }, \"required\": [\"byteOffset\"] }, { \"type\": \"array\", \"items\": { \"type\": \"number\" }, \"minItems\": 4, \"maxItems\": 4 } ] } }, \"properties\": { \"extensions\": { \"$ref\": \"extension.schema.json\" }, \"extras\": { \"$ref\": \"extras.schema.json\" } }, \"additionalProperties\": { \"$ref\": \"#/definitions/property\" } } 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"3D Tiles","slug":"3D-Tiles","permalink":"https://tanghaojie.github.io/categories/3D-Tiles/"},{"name":"specification","slug":"3D-Tiles/specification","permalink":"https://tanghaojie.github.io/categories/3D-Tiles/specification/"}],"tags":[{"name":"specification","slug":"specification","permalink":"https://tanghaojie.github.io/tags/specification/"},{"name":"3D Tiles","slug":"3D-Tiles","permalink":"https://tanghaojie.github.io/tags/3D-Tiles/"}],"author":null},{"title":"3D Tiles批处理3D模型 (Batched 3D Model)数据格式标准规范","slug":"2021-3d-tiles-2021-04-23-3d-tiles-batched-3d-model-specification","date":"2021-04-23T13:43:25.000Z","updated":"2022-12-23T12:44:16.643Z","comments":true,"path":"2021/04/23/2021-3d-tiles-2021-04-23-3d-tiles-batched-3d-model-specification/","link":"","permalink":"https://tanghaojie.github.io/2021/04/23/2021-3d-tiles-2021-04-23-3d-tiles-batched-3d-model-specification/","excerpt":"","text":"导航 引 概述 文件结构 结构填充 文件头 要素表 语法定义 要素语法 全局语法 批处理表 二进制 glTF 坐标系 扩展名和 MIME 类型 实例 属性参考 引官网文档 概述批处理 3D 模型允许离线批处理混合的 3D 模型(例如城市中的各个建筑物),高效地以流式传输到 Web 客户端进行渲染和交互。在单个请求中传输多个模型,并使用最少数量的 WebGL 调用来渲染以提供高效率。使用 3D Tiles core 规范语言,每个模型都是一个要素。 每个模型的属性(例如 ID)都可以在运行时识别和更新,例如显示/隐藏,高亮颜色等。属性可以用于通过 Web 服务查询访问元数据,例如传递建筑物的 ID 以获取其地址,动态修改引用的属性以更改模型的外观,基于属性值更改高亮颜色等等。 批处理 3D 模型数据是小端字节序的二进制 Blob。 文件结构数据由两部分组成:文件头和紧随其后的主体。下图显示了“批处理 3D 模型”文件结构(虚线表示可选字段): 结构填充数据 byteLength 必须以 8 个字节进行边界对齐。包含的要素表(Feature Table)和批处理表(Batch Table)必须符合其各自的填充要求。 二进制 glTF 的开始和结束位置必须以 8 个字节进行边界对齐,以便满足 glTF 的字节对齐要求。这可以通过填充功能表或批处理表(如果存在)来实现。 文件头28 字节的文件头包含以下字段: 字段名 数据类型 描述 magic 4-byte ANSI string \"b3dm\". 用于标识为“批处理 3D 模型” version uint32 版本。现在是1 byteLength uint32 整个数据的长度(包括文件头),以字节为单位 featureTableJSONByteLength uint32 要素表 JSON 部分的长度(以字节为单位) featureTableBinaryByteLength uint32 要素表二进制部分的长度(以字节为单位) batchTableJSONByteLength uint32 批处理表 JSON 部分的长度(以字节为单位)。零表示没有批处理表 batchTableBinaryByteLength uint32 批处理表二进制部分的长度(以字节为单位)。如果batchTableJSONByteLength为零,则也将为零。 文件主体部分紧跟着文件头,并且由三个字段组成:Feature Table,Batch Table,和Binary glTF。 要素表包含b3dm语法。 要素表(Feature Table) 查看更多信息。 属性参考 查看 b3dm 要素表的更多参考。 完整 JSON 定义: { \"$schema\": \"http://json-schema.org/draft-04/schema\", \"id\": \"b3dm.featureTable.schema.json\", \"title\": \"Batched 3D Model Feature Table\", \"type\": \"object\", \"description\": \"A set of Batched 3D Model semantics that contain additional information about features in a tile.\", \"allOf\": [ { \"$ref\": \"featureTable.schema.json\" }, { \"properties\": { \"BATCH_LENGTH\": { \"description\": \"A `GlobalPropertyScalar` object defining a numeric property for all features. See the corresponding property semantic in [Semantics](/specification/TileFormats/Batched3DModel/README.md#semantics).\", \"allOf\": [ { \"$ref\": \"featureTable.schema.json#/definitions/globalPropertyScalar\" } ] }, \"RTC_CENTER\": { \"description\": \"A `GlobalPropertyCartesian3` object defining a 3-component numeric property for all features. See the corresponding property semantic in [Semantics](/specification/TileFormats/Batched3DModel/README.md#semantics).\", \"allOf\": [ { \"$ref\": \"featureTable.schema.json#/definitions/globalPropertyCartesian3\" } ] }, \"extensions\": { \"$ref\": \"extension.schema.json\" }, \"extras\": { \"$ref\": \"extras.schema.json\" } }, \"required\": [\"BATCH_LENGTH\"] } ] } 语法定义 要素语法当前没有按要素的语法。 全局语法以下语法定义了所有要素的全局属性。 语法 数据类型 描述 是否必须 BATCH_LENGTH uint32 数据中可区分模型(要素)的数量。如果 Binary glTF 没有batchId属性,则此字段必须为0。 ✅ Yes. RTC_CENTER float32[3] 当位置相对于中心定义时,由三维数组定义的中心位置(请参阅坐标系)。 🔴 No. 批处理表批处理表包含每一模型的应用特定属性,通过batchId索引,可被用于声明样式和应用特定的使用,如填充 UI 或者进行 REST API 请求。在二进制 glTF 部分,每个顶点都有一个 batchId 的数值属性,整型数组范围内[0, number of models in the batch - 1]。batchId 指示该顶点所属的模型。这样可以将模型整合在一起(batched together),并且仍然可以识别。 更多相关信息,请参见批处理表(Batch Table)。 二进制 glTF批处理 3D 模型嵌入了包含模型几何和纹理信息的glTF 2.0。 二进制 glTF 紧随要素表和批处理表。它可能嵌入了其所有的几何,纹理和动画,或者可能引用了某些或所有这些数据的外部来源。 如上所述,每个顶点具有 batchId 指示其所属模型的属性。例如,具有三个模型的批处理的顶点可能看起来像这样: batchId: [0, 0, 0, ..., 1, 1, 1, ..., 2, 2, 2, ...] position: [xyz, xyz, xyz, ..., xyz, xyz, xyz, ..., xyz, xyz, xyz, ...] normal: [xyz, xyz, xyz, ..., xyz, xyz, xyz, ..., xyz, xyz, xyz, ...] 顶点是必须以batchId排序的,因此以下形式也可以: batchId: [0, 1, 2, ..., 2, 1, 0, ..., 1, 2, 0, ...] position: [xyz, xyz, xyz, ..., xyz, xyz, xyz, ..., xyz, xyz, xyz, ...] normal: [xyz, xyz, xyz, ..., xyz, xyz, xyz, ..., xyz, xyz, xyz, ...] 注意,一个顶点不能属于多个模型。在这种情况下,需要复制顶点,以便batchIds 可以分配。 batchId 参数是在 glTF 图元中通过设置_BATCHID 属性定义的,batchId的值对应 accessor 的顺序索引。例如, \"primitives\": [ { \"attributes\": { \"_BATCHID\": 0 } } ] { \"accessors\": [ { \"bufferView\": 1, \"byteOffset\": 0, \"componentType\": 5126, \"count\": 4860, \"max\": [2], \"min\": [0], \"type\": \"SCALAR\" } ] } accessor.type的值必须是\"SCALAR\"。所有其他属性必须符合 glTF 模式,但没有其他额外要求。 当批处理表存在或BATCH_LENGTH属性大于0时,_BATCHID属性为必填;否则,可以不填。 坐标系默认情况下,嵌入式 glTF 使用右手坐标系,其中 y 轴朝上。为了与 3D Tiles 的 z 向上坐标系保持一致,必须在运行时转换 glTF。详细信息,请参考glTF 转换。 可以相对于中心定义顶点位置以进行高精度渲染,请参见Precisions,Precisions。如果定义,则 RTC_CENTER 指定在应用坐标系变换和 glTF 节点层次结构变换之后,所有顶点位置都相对于其的中心位置。 扩展名和 MIME 类型批处理 3D 模型数据使用.b3dm扩展名和application/octet-stream的 MIME 类型。 显式文件扩展名是可选的。有些实现可能会忽略它,并通过 magic 其标头中的字段标识内容的格式。 实例本节是非规范性的 可以在 CesiumJS 的 3D Tiles 实现中找到读取文件头的代码 Batched3DModelTileContent.js 。 属性参考 批处理 3D 模型要素表 二进制体引用 全局笛卡尔坐标系属性 全局标量属性 属性 批处理 3D 模型要素表一组批处理 3D 模型定义,其中包含有关数据中要素的额外信息。 类型 描述 是否必须 extensions object 扩展特定的字典对象 No extras any 应用程序特定数据 No BATCH_LENGTH object, number [1], number 一个全局标量属性对象定义所有要素得数据属性,查看相应语法定义 ✅ Yes RTC_CENTER object, number [3] 一个全局笛卡尔坐标系属性对象定义的所有要素的 3 个数值属性,查看相应语法定义 No 允许其他属性。 二进制体引用一个对象,定义对要素表的二进制主体的引用部分,如果未在 JSON 中直接定义属性值,则在该部分储存。 类型 描述 是否必须 byteOffset number 缓冲区的偏移量(以字节为单位) ✅ Yes 允许其他属性。 全局笛卡尔坐标系属性定义所有要素的全局三维数组属性对象。 全局标量属性定义所有要素的全局数值属性对象。 属性用户自定义的属性,用来在数据中指定每个要素的应用程序特定的元数据。值可以直接在 JSON 中定义为数组,也可以引用二进制体中的部分。 JSON 定义示例 { \"$schema\": \"http://json-schema.org/draft-04/schema\", \"id\": \"featureTable.schema.json\", \"title\": \"Feature Table\", \"type\": \"object\", \"description\": \"A set of semantics containing per-tile and per-feature values defining the position and appearance properties for features in a tile.\", \"definitions\": { \"binaryBodyReference\": { \"title\": \"BinaryBodyReference\", \"type\": \"object\", \"description\": \"An object defining the reference to a section of the binary body of the features table where the property values are stored if not defined directly in the JSON.\", \"properties\": { \"byteOffset\": { \"type\": \"number\", \"description\": \"The offset into the buffer in bytes.\", \"minimum\": 0 }, \"componentType\": { \"type\": \"number\", \"description\": \"The datatype of components in the property. This is defined only if the semantic allows for overriding the implicit component type. These cases are specified in each tile format.\", \"enum\": [ \"BYTE\", \"UNSIGNED_BYTE\", \"SHORT\", \"UNSIGNED_SHORT\", \"INT\", \"UNSIGNED_INT\", \"FLOAT\", \"DOUBLE\" ] } }, \"required\": [\"byteOffset\"] }, \"numericArray\": { \"type\": \"array\", \"items\": { \"type\": \"number\" } }, \"property\": { \"title\": \"Property\", \"description\": \"A user-defined property which specifies per-feature application-specific metadata in a tile. Values either can be defined directly in the JSON as an array, or can refer to sections in the binary body with a `BinaryBodyReference` object.\", \"oneOf\": [ { \"$ref\": \"#/definitions/binaryBodyReference\" }, { \"type\": \"array\", \"items\": { \"type\": \"number\" } }, { \"type\": \"number\" } ] }, \"globalPropertyBoolean\": { \"title\": \"GlobalPropertyBoolean\", \"description\": \"An object defining a global boolean property value for all features.\", \"type\": \"boolean\" }, \"globalPropertyScalar\": { \"title\": \"GlobalPropertyScalar\", \"description\": \"An object defining a global numeric property value for all features.\", \"oneOf\": [ { \"type\": \"object\", \"properties\": { \"byteOffset\": { \"type\": \"number\", \"description\": \"The offset into the buffer in bytes.\", \"minimum\": 0 } }, \"required\": [\"byteOffset\"] }, { \"type\": \"array\", \"items\": { \"type\": \"number\" }, \"minItems\": 1, \"maxItems\": 1 }, { \"type\": \"number\", \"minimum\": 0 } ] }, \"globalPropertyCartesian3\": { \"title\": \"GlobalPropertyCartesian3\", \"description\": \"An object defining a global 3-component numeric property values for all features.\", \"oneOf\": [ { \"type\": \"object\", \"properties\": { \"byteOffset\": { \"type\": \"number\", \"description\": \"The offset into the buffer in bytes.\", \"minimum\": 0 } }, \"required\": [\"byteOffset\"] }, { \"type\": \"array\", \"items\": { \"type\": \"number\" }, \"minItems\": 3, \"maxItems\": 3 } ] }, \"globalPropertyCartesian4\": { \"title\": \"GlobalPropertyCartesian4\", \"description\": \"An object defining a global 4-component numeric property values for all features.\", \"oneOf\": [ { \"type\": \"object\", \"properties\": { \"byteOffset\": { \"type\": \"number\", \"description\": \"The offset into the buffer in bytes.\", \"minimum\": 0 } }, \"required\": [\"byteOffset\"] }, { \"type\": \"array\", \"items\": { \"type\": \"number\" }, \"minItems\": 4, \"maxItems\": 4 } ] } }, \"properties\": { \"extensions\": { \"$ref\": \"extension.schema.json\" }, \"extras\": { \"$ref\": \"extras.schema.json\" } }, \"additionalProperties\": { \"$ref\": \"#/definitions/property\" } } 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"3D Tiles","slug":"3D-Tiles","permalink":"https://tanghaojie.github.io/categories/3D-Tiles/"},{"name":"specification","slug":"3D-Tiles/specification","permalink":"https://tanghaojie.github.io/categories/3D-Tiles/specification/"}],"tags":[{"name":"specification","slug":"specification","permalink":"https://tanghaojie.github.io/tags/specification/"},{"name":"3D Tiles","slug":"3D-Tiles","permalink":"https://tanghaojie.github.io/tags/3D-Tiles/"}],"author":null},{"title":"文章中超链接打开方式target修改","slug":"2021-2021-04-23-artical-a-target-default","date":"2021-04-23T11:52:15.000Z","updated":"2022-12-23T12:44:16.639Z","comments":true,"path":"2021/04/23/2021-2021-04-23-artical-a-target-default/","link":"","permalink":"https://tanghaojie.github.io/2021/04/23/2021-2021-04-23-artical-a-target-default/","excerpt":"","text":"问题hexo-theme-matery主题默认配置了所有链接都是从新窗口中打开,但自己写的文章锚点,我们肯定希望直接页面内直接跳转就行了,否则的话打开的页面就太多了。 原理修改配置的话,在/themes/hexo-theme-matery/source/js/matery.js这个文件下面的: /*文章内容详情的一些初始化特性*/ let articleInit = function () { $('#articleContent a').attr('target', '_blank') ... } 优化修改这里的_blank到_self,就可以把默认配置从新页面打开修改为当前页打开了。 但是修改默认值这种方式会影响到全局,可能引入不必要的错误,所以这里推荐一种更好用的方式。 在下面添加一行,写上: /*文章内容详情的一些初始化特性*/ let articleInit = function () { $('#articleContent a').attr('target', '_blank') $('#articleContent a.self').attr('target', '_self') ... } 之前写的文章会继续按照默认的方式运行,如果想在当前页内跳转的话,就使用 <a class=\"self\" href=\"跳转的地址\">跳转按钮</a>,这样的写法,重点是class=\"self\",就会在当前页内跳转了。 如何设置锚点设置锚点的话,就是在你想跳转到的地方,插入: <a id=\"自己取一个唯一的名字作为id\" name=\"和左边id里面填写一样的值\"></a> 其实设置锚点,只用设置<a>标签里面name属性的值,但是 HTML4.0 修改了标准,任何标签添加了id属性以后,都可以作为锚点来使用。但是注意:matery 主题用其他任意标签设置锚点是能够自动跳转的,但是由于解析后的大小问题,样式有一些问题。所以还是建议使用a标签作为锚点,但同时设置id和name属性来保证兼容性。 例子当前文章目录 问题(页内跳转) 原理(页内跳转) 优化(页内跳转) 如何设置锚点(打开新页面) 例子(打开新页面) 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"other","slug":"other","permalink":"https://tanghaojie.github.io/categories/other/"}],"tags":[{"name":"other","slug":"other","permalink":"https://tanghaojie.github.io/tags/other/"}],"author":null},{"title":"glTF 数据格式标准规范","slug":"2021-2021-04-23-glTF-specification","date":"2021-04-23T05:13:21.000Z","updated":"2022-12-23T12:44:16.640Z","comments":true,"path":"2021/04/23/2021-2021-04-23-glTF-specification/","link":"","permalink":"https://tanghaojie.github.io/2021/04/23/2021-2021-04-23-glTF-specification/","excerpt":"","text":"引glTF (GL Transmission Format) 的创建目的,是为 3D 内容工具和服务定义了一种可扩展的通用发布格式。 官网文档 注意:glTF 已经有版本分支了 To do 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"glTF","slug":"glTF","permalink":"https://tanghaojie.github.io/categories/glTF/"},{"name":"specification","slug":"glTF/specification","permalink":"https://tanghaojie.github.io/categories/glTF/specification/"}],"tags":[{"name":"glTF","slug":"glTF","permalink":"https://tanghaojie.github.io/tags/glTF/"},{"name":"specification","slug":"specification","permalink":"https://tanghaojie.github.io/tags/specification/"}],"author":null},{"title":"3D Tiles数据格式标准规范","slug":"2021-3d-tiles-2021-04-21-3d-tiles-specification","date":"2021-04-21T12:12:57.000Z","updated":"2022-12-23T12:44:16.643Z","comments":true,"path":"2021/04/21/2021-3d-tiles-2021-04-21-3d-tiles-specification/","link":"","permalink":"https://tanghaojie.github.io/2021/04/21/2021-3d-tiles-2021-04-21-3d-tiles-specification/","excerpt":"","text":"导航 写在前面 引子 glTF 简介 文件扩展名和 MIME 类型 JSON 编码 URIs 单位 坐标参考系统(CRS) 概念 Tiles 几何误差(Geometric error) 细化/优化(Refinement) 边界盒/边界体(Bounding Volumes) 边界盒(Box) 边界球(Sphere) 边界区(Region) 观察请求盒/体(Viewer Request Volume) 变换(Transforms) 瓦片变换(Tile Transforms) glTF 变换(glTF Transforms) 实例 瓦片 JSON Tileset JSON 外部数据集(External Tilesets) 边界体空间连续性(Bounding volume spatial coherence) 空间数据结构(Spatial data structures) 四叉树(Quadtrees) K-d 树(K-dtrees,K 维树) 八叉树(Octrees) 网格(Grids) 扩展和附加功能 扩展 附加功能 瓦片格式规范 声明式样式规范 属性参考 写在前面经常要用 3D Tiles 数据格式,官方文档只有英文的版本,看官网文档对于我这个英渣来说太慢太费时了,还是中文看着最顺眼。故准备翻译归纳总结一个中文版的 3D Tiles 数据格式规范,留着以后查询使用。 有疑问、异议的地方,还是建议去官网文档看原版的更加准确。 3D Tiles 官网文档 写到这的时候,官网文档的版本:_Version 1.0, June 6th, 2018_ 引子 glTF3D Tiles 规范重点在于解决三维模型 Tile(瓦片、切片)的问题,实际模型是基于 glTF 来构建的,所以了解 3D Tiles 就要先了解 glTF。 glTF (GL Transmission Format) 的创建目的,是为 3D 内容工具和服务定义了一种可扩展的通用发布格式。具体规范又是一大片文章了,这里先埋坑了,后面再补。 glTF 数据格式标准规范 注意:glTF 已经有版本分支了 简介3D Tiles 专为流式传输和渲染大量 3D 地理空间内容而设计,例如摄影测量、3D 建筑、BIM / CAD、要素实例和点云。它定义了分层的数据结构和一组可传递渲染内容的切片格式。3D Tiles 没有为可视化的内容明确的定义规则。客户可以视其需要可视化 3D Tiles 的数据。 在 3D Tiles 中,tileset 是按空间数据结构(tree)组织的一组瓦片(Tile)。tileset 是由至少一个 tileset JSON 文件构成,包括 tileset 元数据和 瓦片(Tile) 对象树,其中每个可渲染内容对象都是以下格式之一: 格式 用途 批处理 3D 模型 (Batched 3D Model (b3dm)) 异构 3D 模型。例如带纹理的地形和表面,3D 建筑外部和内部,大型模型。 实例 3D 模型 (Instanced 3D Model (i3dm)) 3D 模型实例。例如树木,风车,螺栓。 点云 (Point Cloud (pnts)) 大量的点。 复合对象 (Composite (cmpt)) 将不同格式的图块合并为一个图块。 瓦片(Tile)(瓦片格式的一个单独实例)是一个二进制 blob,具有特定的组件格式,包括要素表(Feature Table)和批处理表(Batch Table)。 内容引用了一组要素,例如表示建筑物/树木的 3D 模型或点云中的点。每个要素的位置和外观属性都存储在瓦片(Tile)的要素表(Feature Table)中,额外附加或应用特定(additional application-specific)的属性存储在批处理表(Batch Table)中。客户端可以在运行时选择要素,并获取其属性以进行可视化或分析。 批处理 3D 模型(Batched 3D Model)和实例 3D 模型(Instanced 3D Model)格式基于 glTF 构建,glTF 是一个为高效传输 3D 内容而设计的开放规范。这些格式的瓦片内容嵌入 glTF 资源的二进制主体中,其中包含模型几何和纹理信息。点云格式未嵌入 glTF。 瓦片(Tile)以树形结构组织,其中结合了详细层次结构(HLOD:Hierarchical Level of Detail)的概念,以实现空间数据的最佳渲染呈现。每个图块都有一个边界盒(bounding volume),即一个对象,该对象定义了一个完全包围其内容的空间范围。树具有空间连贯性; 子瓦片的内容完整的包含在父级的边界盒之内。 切片集可以使用类似于栅格和矢量切片(如 Web 地图切片服务(WMTS)或 XYZ 方案)的 2D 空间切片方案,该二维空间切片方案以多级别(LOD)(或缩放级别)提供预定义的切片。但是,由于切片集的内容通常是不一致的,很难仅在二维上组织,因此树可以是具有空间一致性的任何空间数据结构,包括 k-d 树,四叉树,八叉树和网格。 可选地,可以将3D Tiles 样式或 style 应用于 tileset。样式由表达式来定义其中的每一个要素显示方式。 文件扩展名和 MIME 类型3D Tiles 使用以下文件扩展名和 MIME 类型。 Tileset 文件使用 .json 扩展名和 application/json MIME 类型。 切片内容文件使用特定于其切片格式规范的文件类型和 MIME 格式。 Tileset 样式文件使用 .json 扩展名和 application/json MIME 类型。显式文件扩展名是可选的。有效的实现可能会忽略它,并通过其头中的 magic 字段标识内容的格式。 JSON 编码3D Tiles 对 JSON 格式和编码具有以下限制。 JSON 必须使用没有 BOM 的 UTF-8 编码。 本规范中定义的所有字符串(属性名称,枚举)仅使用 ASCII 字符集,并且必须以纯文本形式编写。 JSON 对象中的名称(键)必须唯一,即不允许重复的键。 URIs3D Tiles 使用 URI 来引用 tile 内容。这些 URI 可以指向相对外部引用(RFC3986),也可以是将资源嵌入 JSON 的数据 URI。嵌入式资源使用“数据” URI 方案(RFC2397)。 如果 URI 是相对的,则其根始终相对于引用的 tileet JSON 文件。 客户端实现需要支持相对的外部引用和嵌入式资源。可选地,客户端实现可以支持其他方案(例如 http://)。所有 URI 必须有效且可解析。 单位所有线性距离的单位是米。 所有角度均以弧度为单位。 坐标参考系统(CRS)3D Tiles 使用右手笛卡尔坐标系;也就是说,x 和 y 的叉积得出 z。3D Tiles 将 z 轴定义为局部笛卡尔坐标系的上方向。一个数据集的全局坐标系通常位于 WGS 84 以地球为中心,固定于地球(ECEF)的参考系(EPSG 4978)中,但不必须如此,例如,一个发电厂可以定义在其局部坐标系内,而不使用空间数据内容,仅仅使用模型工具。 可以应用额外的数据变换(tile transform)来将瓦片的局部坐标系变换为父瓦片的坐标系。 边界区(Region)使用地理坐标系(纬度,经度,高度)指定边界,详情 EPSG 4979。 概念 Tiles瓦片(Tiles)由元数据组成,用于定义瓦片(tile)是否渲染,可渲染内容的引用,以及子瓦片的数组。 几何误差(Geometric error)瓦片是树形结构合并构成的详细层次结构Hierarchical Level of Detail (HLOD),以便客户端在运行时实现 瓦片 是否完全渲染 , 以及瓦片的内容是否应由高质量的子瓦片来依次完成。一种实现是考虑最大屏幕允许空间误差Screen-Space Error (SSE),该误差以像素为单位。 瓦片的几何误差定义了该瓦片的选择指标。它的值是一个非负数,来指定瓦片几何图形的最简化表示时的误差(单位:米)。根图块是源几何图形的最简化版本,其几何误差最大。然后,每个连续级别的子级将具有比其父级低的几何误差,而叶子图块的几何误差为 0 或接近 0。 在客户端实现中,几何误差与其他屏幕空间指标一起使用(例如,瓦片到相机的距离,屏幕大小和分辨率),以计算当瓦片被渲染而子瓦片不需要渲染时需要引入的几何误差(SSE)。如果引入的几何误差(SSE)超过了所允许的最大值,则将优化瓦片并考虑渲染其子级。 几何误差是根据诸如点密度,米为单位的瓦片大小,或该图块特有的其他因素之类的度量标准制定的。通常,较高的几何误差意味着更积极地细化图块,并且将更快地加载和渲染子图块。 细化/优化(Refinement)优化决定了较低分辨率的父瓦片被选择渲染的子级时渲染的过程。允许的细化类型为替换(\"REPLACE\")和添加(\"ADD\")。如果瓦片具有“替换”的细化配置,则将渲染子瓦片代替父瓦片,即不再渲染父瓦片。如果瓦片具有“添加”的细化配置,则除了父瓦片之外,还将渲染子瓦片。 区块集可以仅使用替换优化,仅添加改进或添加和替换优化的任意组合。 Tileset 的根图块需要细化类型;对于所有其他磁贴,它是可选的。如果省略,则 tile 会继承其父级的优化类型。 边界盒/边界体(Bounding volumes)边界盒定义了包围图块或图块内容的空间范围。为了支持各种数据集的紧密拟合体积,例如规则划分的地形,未与纬度或经度线对齐的城市,或任意点云,边界盒类型包括有向边界框,边界球,和由最小、最大纬度,经度和高度定义的边界区。 边界盒(Box)boundingVolume.box属性是由 12 个数字组成的数组,在右手 3 轴(x,y,z)笛卡尔坐标系中定义的一个有向包围盒,其中 z 轴是。前三个元素定义框中心的 x,y 和 z 值。接下来的三个元素(索引为 3、4 和 5)定义了 x 轴方向和一半长度(half-length)。接下来的三个元素(索引 6、7 和 8)定义 y 轴方向和一半长度(half-length)。最后三个元素(索引 9、10 和 11)定义 z 轴方向和一半长度(half-length)。 \"boundingVolume\": { \"box\": [ 0, 0, 10, 100, 0, 0, 0, 100, 0, 0, 0, 10 ] } 边界球(Sphere)boundingVolume.sphere属性是由 4 个数字组成的数组定义的边界球。前三个元素在右手 3 轴(x,y,z)笛卡尔坐标系中定义球体中心的 x,y 和 z 值,其中 z 轴朝上。最后一个元素(索引为 3)以米为单位定义半径。 \"boundingVolume\": { \"sphere\": [ 0, 0, 10, 141.4214 ] } 边界区(Region)boundingVolume.region属性是一个由 6 个数字组成的数组,定义了由纬度,经度和高度坐标的地理边界区,使用[west, south, east, north, minimum height, maximum height]的顺序。纬度和经度是在 EPSG 4979 中定义的 WGS 84 基准,以弧度表示。高度在 WGS 84 椭球上方(或下方)以米为单位。 \"boundingVolume\": { \"region\": [ -1.3197004795898053, 0.6988582109, -1.3196595204101946, 0.6988897891, 0, 20 ] } 观察请求盒/体(Viewer request volume)瓦片的 观察请求盒/体(Viewer request volume) 可以用于组合异构数据集,也可以与外部数据集组合。 以下示例是一个在b3dm瓦片中的建筑物,并在建筑物中包含了在pnts瓦片中的点云。点云瓦片的boundingVolume是半径为 1.25 的边界球。它还有一个更大的,半径为 15 的viewerRequestVolume边界球配置。由于 geometricError 值为零,因此当观察者位于由viewerRequestVolume所定义的大的边界球内时,始终会渲染点云的内容。 简单来说,viewerRequestVolume是一个比boundingVolume优先级更高的显示配置,当视角进入viewerRequestVolume中是,瓦片就会显示,就不必须通过boundingVolume和geometricError来配置了。 { \"children\": [ { \"transform\": [ 4.843178171884396, 1.2424271388626869, 0, 0, -0.7993325488216595, 3.1159251367235608, 3.8278032889280675, 0, 0.9511533376784163, -3.7077466670407433, 3.2168186118075526, 0, 1215001.7612985559, -4736269.697480114, 4081650.708604793, 1 ], \"boundingVolume\": { \"box\": [0, 0, 6.701, 3.738, 0, 0, 0, 3.72, 0, 0, 0, 13.402] }, \"geometricError\": 32, \"content\": { \"uri\": \"building.b3dm\" } }, { \"transform\": [ 0.968635634376879, 0.24848542777253732, 0, 0, -0.15986650990768783, 0.6231850279035362, 0.7655606573007809, 0, 0.19023066741520941, -0.7415493329385225, 0.6433637229384295, 0, 1215002.0371330238, -4736270.772726648, 4081651.6414821907, 1 ], \"viewerRequestVolume\": { \"sphere\": [0, 0, 0, 15] }, \"boundingVolume\": { \"sphere\": [0, 0, 0, 1.25] }, \"geometricError\": 0, \"content\": { \"uri\": \"points.pnts\" } } ] } 变换(Transforms) 瓦片变换(Tile transforms)为了支持局部坐标系(例如,可以在城市数据集内部加载自定义坐标系的建筑数据集,并建筑数据集内部加载自定义坐标系的点云数据集),每个数据都有可选的transform属性。 transform 属性是一个 4x4 仿射变换矩阵(affine transformation matrix),以列优先顺序存储,从数据的本地坐标系转换到父数据的坐标系,或者到数据集根数据的变换。 *仿射变换:保持原来的线共点、点共线的关系不变,保持原来相互平行的线仍然平行,保持原来的中点仍然是中点,保持原来在一条直线上各个线段之间的比例关系不变。但是仿射变换不能保持原来的线段长度不变,也不能保持原来的夹角角度不变。 transform属性适用于 tile.content 每个要素的位置。 每个要素的法线均应通过逆转置的左上 3x3 矩阵进行变换,以在使用 scale 时 transform 考虑正确的矢量变换。(Each feature’s normal should be transformed by the top-left 3x3 matrix of the inverse-transpose of transform to account for correct vector transforms when scale is used.) tile.boundingVolume,但 tile.boundingVolume.region 类型定义除外,该类型以 EPSG:4979 坐标系为准。 tile.boundingVolume,但 tile.boundingVolume.region 类型定义除外,该类型以 EPSG:4979 坐标系为准。 tile.viewerRequestVolume,但 tile.viewerRequestVolume.region 类型定义除外,该类型以 EPSG:4979 坐标系为准。 transform属性不适用于geometricError,例如,由transform定义的比例缩放(scale)不会缩放几何误差的值,几何误差始终以米为单位定义。 当transform没有定义,则默认为单位矩阵: [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] 从每个数据的局部坐标系到数据集全局坐标系的转换是通过对数据集自上而下的遍历,将子transform 和父transform 进行后乘(post-multiplying)运算得到的(例如计算机图形学中的传统场景图或节点层次结构)。 glTF 变换(glTF transforms)批处理 3D 模型(Batched 3D Model)和实例 3D 模型(Instanced 3D Model) 数据嵌入在 glTF 中,glTF 有其自己的节点层次结构,并使用 y 轴朝上的坐标系。所有指定于数据(a tile format)和tile.transform属性的转换都会被应用。 glTF 节点层次结构(glTF node hierarchy) 首先,根据glTF 规范应用 glTF 节点层次结构转换。 y 轴向上到 z 轴向上 接下来,为了与 3D Tiles 坐标系的 z 轴保持一致,必须在运行时将 glTF 从 y 轴朝上转换为 z 轴朝上。这是通过将模型绕 x 轴旋转 π/ 2 弧度来完成的。等效地,应用以下矩阵变换(此处为行优先顺序): [ 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] 总的来说,变换的顺序为: glTF 节点层次结构(glTF node hierarchy) y 轴向上到 z 轴向上 任何数据类型特定的变换。 批处理 3D 模型要素表可以定义RTC_CENTER用于转换模型的顶点。 实例化 3D 模型要素表定义了每个实例的位置,法线和比例。用于创建按实例的 4x4 仿射变换矩阵,来应用于每个实例。 瓦片变换 实现说明:使用固定的 z 轴向上的源数据,例如 WGS 84 坐标或 z 轴向上自定义坐标系中的数据源时,常见的工作流程是:包括位置和法线的表面数据(Mesh data)不做修改,仍保持 z 向上。根节点矩阵指定了列优先的从到 z 轴向上到 y 轴向上的变换。y 轴向上的 glTF 坐标系要求使用此类变化。在运行时,glTF 被上面的变换转回。转换抵消了。(At runtime the glTF is transformed back from y-up to z-up with the matrix above. Effectively the transforms cancel out.)glTF 根节点示例: \"nodes\": [ { \"matrix\": [1,0,0,0,0,0,-1,0,0,1,0,0,0,0,0,1], \"mesh\": 0, \"name\": \"rootNode\" } ] 实例为数据集计算变换的例子: 每个 Tile 的变换为: TO: [T0] T1: [T0][T1] T2: [T0][T2] T3: [T0][T1][T3] T4: [T0][T1][T4] 在变换之前, Tile 内容中的位置和法线也可以有 Tile 指定的转换来应用,(之前表示应用仿射变换之前)。例: b3dm和i3dm嵌入 glTF,glTF 定义了自己的节点层次结构和坐标系。tile.transform在这些变换之后执行。 i3dm的要素表定义了每个实例的位置,法线和比例。用于每个实例按照 4x4 仿射变换矩阵创建,这些变换在tile.transform之前。 压缩的属性,如i3dm和pnts要素表中的POSITION_QUANTIZED,pnts中的NORMAL_OCT16P会在应用任何其他变换之前被解压缩。 因此,以上示例的完整计算转换为: TO: [T0] T1: [T0][T1] T2: [T0][T2][pnts-specific transform, including RTC_CENTER (if defined)] T3: [T0][T1][T3][b3dm-specific transform, including RTC_CENTER (if defined), coordinate system transform, and glTF node hierarchy] T4: [T0][T1][T4][i3dm-specific transform, including per-instance transform, coordinate system transform, and glTF node hierarchy] 瓦片 JSON瓦片 JSON 对象由以下属性组成。 以下示例展示了一个非叶子瓦片。 { \"boundingVolume\": { \"region\": [ -1.2419052957251926, 0.7395016240301894, -1.2415404171917719, 0.7396563300150859, 0, 20.4 ] }, \"geometricError\": 43.88464075650763, \"refine\" : \"ADD\", \"content\": { \"boundingVolume\": { \"region\": [ -1.2418882438584018, 0.7395016240301894, -1.2415422846940714, 0.7396461198389616, 0, 19.4 ] }, \"uri\": \"2/0/0.b3dm\" }, \"children\": [...] } boundingVolume定义瓦片的封闭体,并且被用来确定哪些瓦片在运行时进行渲染。上面的示例使用一个region边界体,也可以使用其他边界体,例如box或sphere。 geometricError属性是一个非负数,用于定义误差(以米为单位),用来决定渲染此瓦片但不渲染其子瓦片。在运行时,几何误差用于计算屏幕空间误差(SSE),即以像素为单位的误差。SSE 确定某个瓦片是否对于当前视图足够详细,或者是否应考虑渲染其子视图。详见几何误差。 可选viewerRequestVolume属性(上面未显示)使用与boundingVolume配置参数,在执行瓦片内容的请求前,观察者位于viewerRequestVolume内,并且viewerRequestVolume优先于geometricError。详见观察请求盒/体。 refine 属性是一个字符串,用\"REPLACE\"或\"ADD\"。数据集(tileset)的根图块需要设置;对于其他瓦片,它是可选的。数据集可以使用添加和替换的任意组合。refine 省略该属性时,从父瓦片继承的。详见细化/优化。 content 属性是一个对象,其中包含有关瓦片渲染内容的元数据。 content.uri 是一个 uri,指向瓦片的二进制内容(规范的文件类型),或另一个数据集 JSON 以创建数据集(tileset)的数据集(tileset)(外部数据集)。 content.uri中的文件扩展名不是必须的。瓦片内容格式由文件头中的magic字段指定,或者为 JSON,将其指定为外部数据集。 content.boundingVolume属性定义一个可选的边界体,类似于顶级的boundingVolume属性。但是与顶级boundingVolume属性不同,content.boundingVolume是一个包裹瓦片内容的紧密封闭的包围体。boundingVolume提供空间连续性,content.boundingVolume实现严格地视图视锥剔除(view frustum culling),排除可能不在视域范围内的内容。如果未定义,则瓦片的边界体仍用于剔除(请参见网格)。 下面的截图显示了 Canary Wharf 的根图块的边界体积。 boundingVolume 以红色显示,将整个区域的数据集包围起来;content.boundingVolume 以蓝色显示,仅将根图块中的四个要素(模型)封闭起来。 可选的 transform 属性(上面列出)定义 4×4 的仿射变换矩阵,该矩阵变换瓦片的 content,boundingVolume 和 viewerRequestVolume。 children属性是定义一组子瓦片的对象数组。每个子瓦片的内容都被其父瓦片的boundingVolume 完全包围,通常 geometricError 小于其父级的 geometricError。对于叶瓦片,此数组的长度为零,children 可以不定义。请参阅下面的Tileset JSON部分。 完整的 json 定义 { \"$schema\": \"http://json-schema.org/draft-04/schema\", \"id\": \"tile.schema.json\", \"title\": \"Tile\", \"type\": \"object\", \"description\": \"A tile in a 3D Tiles tileset.\", \"properties\": { \"boundingVolume\": { \"description\": \"The bounding volume that encloses the tile.\", \"$ref\": \"boundingVolume.schema.json\" }, \"viewerRequestVolume\": { \"description\": \"Optional bounding volume that defines the volume the viewer must be inside of before the tile's content will be requested and before the tile will be refined based on geometricError.\", \"$ref\": \"boundingVolume.schema.json\" }, \"geometricError\": { \"type\": \"number\", \"description\": \"The error, in meters, introduced if this tile is rendered and its children are not. At runtime, the geometric error is used to compute screen space error (SSE), i.e., the error measured in pixels.\", \"minimum\": 0 }, \"refine\": { \"type\": \"string\", \"description\": \"Specifies if additive or replacement refinement is used when traversing the tileset for rendering. This property is required for the root tile of a tileset; it is optional for all other tiles. The default is to inherit from the parent tile.\", \"enum\": [\"ADD\", \"REPLACE\"] }, \"transform\": { \"type\": \"array\", \"description\": \"A floating-point 4x4 affine transformation matrix, stored in column-major order, that transforms the tile's content--i.e., its features as well as content.boundingVolume, boundingVolume, and viewerRequestVolume--from the tile's local coordinate system to the parent tile's coordinate system, or, in the case of a root tile, from the tile's local coordinate system to the tileset's coordinate system. transform does not apply to geometricError, nor does it apply any volume property when the volume is a region, defined in EPSG:4979 coordinates.\", \"items\": { \"type\": \"number\" }, \"minItems\": 16, \"maxItems\": 16, \"default\": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, \"content\": { \"description\": \"Metadata about the tile's content and a link to the content. When this is omitted the tile is just used for culling. This is required for leaf tiles.\", \"$ref\": \"tile.content.schema.json\" }, \"children\": { \"type\": \"array\", \"description\": \"An array of objects that define child tiles. Each child tile content is fully enclosed by its parent tile's bounding volume and, generally, has a geometricError less than its parent tile's geometricError. For leaf tiles, the length of this array is zero, and children may not be defined.\", \"items\": { \"$ref\": \"tile.schema.json\" }, \"uniqueItems\": true }, \"extensions\": { \"$ref\": \"extension.schema.json\" }, \"extras\": { \"$ref\": \"extras.schema.json\" } }, \"required\": [\"boundingVolume\", \"geometricError\"], \"additionalProperties\": false } Tileset JSON3D Tiles 使用一个主 tileset JSON 文件作为定义数据集(Tileset)的入口。入口和外部 tileset JSON 文件都不需要遵循任何命名规则。 这是一个 tileset JSON 的数据集 { \"asset\" : { \"version\": \"1.0\", \"tilesetVersion\": \"e575c6f1-a45b-420a-b172-6449fa6e0a59\", }, \"properties\": { \"Height\": { \"minimum\": 1, \"maximum\": 241.6 } }, \"geometricError\": 494.50961650991815, \"root\": { \"boundingVolume\": { \"region\": [ -0.0005682966577418737, 0.8987233516605286, 0.00011646582098558159, 0.8990603398325034, 0, 241.6 ] }, \"geometricError\": 268.37878244706053, \"refine\": \"ADD\", \"content\": { \"uri\": \"0/0/0.b3dm\", \"boundingVolume\": { \"region\": [ -0.0004001690908972599, 0.8988700116775743, 0.00010096729722787196, 0.8989625664878067, 0, 241.6 ] } }, \"children\": [..] } } Tilset JSON 有四个顶级属性:asset,properties,geometricError,和root。 asset 是一个包含有关整个数据集的元数据对象。asset.version 属性是一个定义 3D Tiles 版本的字符串,指定 tilset 的 JSON 模式和基本的 tile 格式。 tilesetVersion 属性是一个可选字符串,用于定义特定应用程序的 tileset 版本,例如,表示 tilset 是否被更新。 properties 是一个对象,包含数据集中每个要素属性。这个 tileet JSON 代码段适用于 3D 建筑物,因此每个瓦片均具有建筑物模型,并且每个建筑物模型均具有 Height 属性(详见批处理表(Batch Table))。properties中的名称与每个要素的属性名称匹配,其定义 minimum 和 maximum 的数字值,这些值对于创建样式色带非常有用。 geometricError 是一个非负数,用于定义误差(以米为单位),该值确定是否渲染图块。在运行时,几何误差用于计算屏幕空间误差(SSE),即以像素为单位的误差。如果 SSE 不超过所需的最小值,则不会渲染数据集,并且不会对其瓦片进行渲染。详见几何误差(Geometric error)。 root 是一个使用上一节中描述的瓦片 JSON 定义根图块的对象。root.geometricError与 tilset 顶级的geometricError不同。geometricError在运行时根据 SSE 决定根瓦片是否渲染;root.geometricError在运行时根据 SSE 决定根瓦片的子集是否渲染。 外部数据集(External tilesets)创建树的子节点,数据的content.uri可以指向一个外部数据集(另一个 数据集 JSON 文件的 uri)。例如,可以将每个城市存储在一个数据集中,然后组成一个全球数据集。 当瓦片指向外部数据集时,瓦片: 不能有子级;tile.children 必须为 undefined 或空数组。 不能有循环,例如,通过指向包含该图块的同一图块文件或指向另一个图块集文件,然后再指向包含该图块的初始文件,来创建循环。 会同时通过瓦片的 transform 和根瓦片的transform进行变换。例如,在下面的数据集引用外部数据集,T3 计算变换为 [T0][T1][T2][T3]。 边界体空间连续性(Bounding volume spatial coherence)如上所述,树具有空间连贯性。每个瓦片都有一个完全包围其内容的边界体,子瓦片的内容完全位于父级的边界体之内。但这并不意味着子级的边界体完全在其父级的边界体之内。例如: 空间数据结构(Spatial data structures)3D Tiles 结合了详细层次结构(HLOD)的概念,以实现空间数据的最佳呈现。数据集由树结构组成,由root定义,并递归其children瓦片组成,并可以按不同类型的空间数据结构进行组织。 运行时引擎是通用的,可以渲染 tilset 定义的任何树。任意组合的瓦片格式和优化(refinement)方法组合都可以使用,从而可以灵活地支持异构数据集。详见细化/优化(Refinement)。 数据集可以使用类似于栅格和矢量切片方案的 2D 空间切片方案(例如 Web 地图切片服务(WMTS)或 XYZ 方案),该二维空间切片方案以多级别(LOD)(或缩放级别)提供预定义的切片。但是,由于数据集的内容通常是不一致的,或者可能不容易仅在二维上组织,因此其他空间数据结构可能更理想。 下面包括对 3D Tiles 如何表示各种空间数据结构的简要说明。 四叉树(Quadtrees)当每个瓦片具有四个统一细分的子级(例如,使用中心纬度和经度)时,将创建一个四叉树,类似于典型的 2D 地理空间切片方案。空的子图块可以省略。 3D Tiles 可以使用四叉树变体,例如非均匀细分和非紧密的边界体(例如,与边界不同,对稀疏数据集来说,父级的 25%是浪费的)。 3D Tiles 还支持其他四叉树变形,例如松散四叉树,其中子瓦片相互重叠,但仍保持空间连贯性,即,父瓦片完全包围了其所有子级。这种方法对于避免在瓦片之间分割要素(例如 3D 模型)很有用。 K-d 树(K-d trees,K 维树)当瓦片具有两个由平行于 x,y 或 z 轴(或纬度,经度,高度)的分割面分隔的子代时,会创建 kd 树。随着树级别的递增,拆分轴通常是循环旋转的(可以参考平衡 K-d 树理解),可以选择中位数,表面积启发法(surface area heuristics)或其他方法来选择拆分平面。 注意,k-d 树不像典型的 2D 地理空间切片方案那样具有统一的均匀细分,因此可以为稀疏和非均匀分布的数据集创建更加平衡的树。 3D Tiles 支持 k-d 树变体,例如多路 kd 树,其中树的每个叶子上有多个拆分轴。这样就有n个子级,而不是每个瓦片有两个。 八叉树(Octrees)八叉树通过扩展四叉树使用三个正交拆分平面将图块细分为八个子级。像四叉树一样,3D Tiles 允许对八叉树变体,例如不均匀的细分,非紧密的边界体和重叠的子代。 网格(Grids)3D Tiles 通过支持任意数量的子瓦片来实现均匀,不均匀和重叠的网格。例如,这是剑桥的不均匀重叠网格的俯视图: 3D Tiles 利用了空瓦片:那些具有边界体但没有内容的瓦片。由于瓦片的content不必须要被定义的属性,因此可以使用空的非叶子节点的瓦片来分层剔除,以加速非均匀网格。本质上,这会创建一个四叉树或八叉树,而没有层次的详细信息(HLOD)。 扩展和附加功能(Specifying extensions and application specific extras)3D Tiles 定义了扩展,以允许新功能扩展基本规范,包括附加应用程序特定元数据。 扩展扩展允许使用新功能扩展基本规范。可以将可选的 extensions 字典属性添加到任何 3D Tiles JSON 对象,该对象包含扩展名和扩展特定的对象。 { \"transform\": [ 4.843178171884396, 1.2424271388626869, 0, 0, -0.7993325488216595, 3.1159251367235608, 3.8278032889280675, 0, 0.9511533376784163, -3.7077466670407433, 3.2168186118075526, 0, 1215001.7612985559, -4736269.697480114, 4081650.708604793, 1 ], \"boundingVolume\": { \"box\": [0, 0, 6.701, 3.738, 0, 0, 0, 3.72, 0, 0, 0, 13.402] }, \"geometricError\": 32, \"content\": { \"uri\": \"building.b3dm\" }, \"extensions\": { \"VENDOR_collision_volume\": { \"box\": [0, 0, 6.8, 3.8, 0, 0, 0, 3.8, 0, 0, 0, 13.5] } } } 数据集或子级的外部数据集中使用的所有扩展,都必须在入口 tileset JSON 的顶级extensionsUsed数组属性中列出,例如: { \"extensionsUsed\": [\"VENDOR_collision_volume\"] } 所有扩展中,需要加载和渲染数据集或子级的外部数据集时,也必须在入口 tileset JSON 的顶级extensionsRequired数组属性中列出,extensionsRequired数组是extensionsUsed数组的子级。extensionsRequired中列出的值在extensionsUsed中也必须存在。 附加功能extras属性允许将特定于应用程序的元数据添加到任何 3D Tiles JSON 对象。以下示例显示了一个具有附加应用程序特定名称属性的 tile 对象。 { \"transform\": [ 4.843178171884396, 1.2424271388626869, 0, 0, -0.7993325488216595, 3.1159251367235608, 3.8278032889280675, 0, 0.9511533376784163, -3.7077466670407433, 3.2168186118075526, 0, 1215001.7612985559, -4736269.697480114, 4081650.708604793, 1 ], \"boundingVolume\": { \"box\": [0, 0, 6.701, 3.738, 0, 0, 0, 3.72, 0, 0, 0, 13.402] }, \"geometricError\": 32, \"content\": { \"uri\": \"building.b3dm\" }, \"extras\": { \"name\": \"Empire State Building\" } } 瓦片格式规范每个瓦片的content.uri属性可以是 uri 二进制 blob,其中包含用于渲染瓦片的 3D 内容的信息。内容是下表中列出的一种格式的实例。 格式 用途 批处理 3D 模型 (Batched 3D Model (b3dm)) 异构 3D 模型。例如带纹理的地形和表面,3D 建筑外部和内部,大型模型。 实例 3D 模型 (Instanced 3D Model (i3dm)) 3D 模型实例。例如树木,风车,螺栓。 点云 (Point Cloud (pnts)) 大量的点。 复合对象 (Composite (cmpt)) 将不同格式的图块合并为一个图块。 tilset 可以包含 tile 格式的任意组合。3D Tiles 还支持不同格式在一个 Composite 瓦片中的组合。 声明式样式规范3D Tiles 包含使用 JSON 定义的简洁声明式样式以及用一部分 JavaScript 增强的样式编写表达式。 样式定义要素如何显示,例如 show 和 color(RGB 和透明度),在要素属性上使用表达式。 下面的示例将高度超过 90 的要素涂为红色,将其他涂为白色。 { \"color\": \"(${Height} > 90) ? color('red') : color('white')\" } 更多内容,详见3D Tiles 样式规范。 属性参考 Tileset Asset Bounding Volume Extension Extras Properties Tile Content Tileset一个 3D Tiles 数据集。 属性 类型 描述 是否必须 asset object 整个数据集的元数据 tileset. ✅ Yes properties any 功能属性的元数据字典对象 No geometricError number 决定是否渲染此瓦片的误差值,以米为单位。在运行时,用于计算屏幕空间误差(SSE),以像素为单位 ✅ Yes root object 3D Tiles 数据集中的一个瓦片 ✅ Yes extensionsUsed string [1-*] 在此数据集中某处使用的 3D Tiles 扩展名 No extensionsRequired string [1-*] 需要加载的数据集的 3D Tiles 扩展名 No extensions object 具有扩展名的特定对象的字典对象 No extras any 附加于应用程序的数据 No 不允许使用其他属性。 Asset整个数据集的元数据 属性 类型 描述 是否必须 version string 3D Tiles 版本。该版本定义了数据集 JSON 的 JSON 模式和瓦片格式的基本集合 ✅ Yes tilesetVersion string 此瓦片的特定于应用程序的版本,例如,用于更新现有瓦片的标识 No extensions object 具有扩展的特定对象的字典对象 No extras any 应用程序的附加数据 No 不允许使用其他属性。 Bounding Volume包围瓦片或其内容的包围盒。有且需要一个box,region或sphere属性。 属性 类型 描述 是否必须 box number [12] 由 12 个数字组成的数组,在右手 3 轴(x,y,z)笛卡尔坐标系中定义的一个有向包围盒,其中 z 轴是。前三个元素定义框中心的 x,y 和 z 值。接下来的三个元素(索引为 3、4 和 5)定义了 x 轴方向和一半长度(half-length)。接下来的三个元素(索引 6、7 和 8)定义 y 轴方向和一半长度(half-length)。最后三个元素(索引 9、10 和 11)定义 z 轴方向和一半长度(half-length) No region number [6] 由 6 个数字组成的数组,定义了由纬度,经度和高度坐标的地理边界区,使用[west, south, east, north, minimum height, maximum height]的顺序。纬度和经度是在 EPSG 4979 中定义的 WGS 84 基准,以弧度表示。高度在 WGS 84 椭球上方(或下方)以米为单位 No sphere number [4] 由 4 个数字组成的数组定义的边界球。前三个元素在右手 3 轴(x,y,z)笛卡尔坐标系中定义球体中心的 x,y 和 z 值,其中 z 轴朝上。最后一个元素(索引为 3)以米为单位定义半径 No extensions object 具有扩展的特定对象的字典对象 No extras any 应用程序的附加数据 No 不允许使用其他属性。 Extension具有扩展的特定对象的字典对象。 允许其他属性。 属性类型:object Extras应用程序的附加数据。 JSON 样式: { \"$schema\": \"http://json-schema.org/draft-04/schema\", \"title\": \"Extras\", \"description\": \"Application-specific data.\" } Properties功能属性的元数据字典对象。 属性 类型 描述 是否必须 maximum number 数据集中所有要素此属性的最大值 ✅ Yes minimum number 数据集中所有要素此属性的最小值 ✅ Yes extensions object 具有扩展的特定对象的字典对象 No extras any 应用程序的附加数据 No 不允许使用其他属性。 Tile3D Tiles 数据集中的一个瓦片。 属性(上面有一章专门讲这些属性,就不翻译了) 类型 描述 是否必须 boundingVolume object A bounding volume that encloses a tile or its content. Exactly one box, region, or sphere property is required. ✅ Yes viewerRequestVolume object A bounding volume that encloses a tile or its content. Exactly one box, region, or sphere property is required. No geometricError number The error, in meters, introduced if this tile is rendered and its children are not. At runtime, the geometric error is used to compute screen space error (SSE), i.e., the error measured in pixels. ✅ Yes refine string Specifies if additive or replacement refinement is used when traversing the tileset for rendering. This property is required for the root tile of a tileset; it is optional for all other tiles. The default is to inherit from the parent tile. No transform number [16] A floating-point 4x4 affine transformation matrix, stored in column-major order, that transforms the tile’s content–i.e., its features as well as content.boundingVolume, boundingVolume, and viewerRequestVolume–from the tile’s local coordinate system to the parent tile’s coordinate system, or, in the case of a root tile, from the tile’s local coordinate system to the tileset’s coordinate system. transform does not apply to geometricError, nor does it apply any volume property when the volume is a region, defined in EPSG:4979 coordinates. No, default: [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1] content object Metadata about the tile’s content and a link to the content. No children array[] An array of objects that define child tiles. Each child tile content is fully enclosed by its parent tile’s bounding volume and, generally, has a geometricError less than its parent tile’s geometricError. For leaf tiles, the length of this array is zero, and children may not be defined. No extensions object Dictionary object with extension-specific objects. No extras any Application-specific data. No Tile Content有关瓦片内容和该内容链接的元数据。 属性 类型 描述 是否必须 boundingVolume object 包围瓦片或其内容的包围盒。有且需要一个box,region或sphere属性 No uri string 指向图块内容的 uri。如果 uri 是相对的,则它是相对于引用的 tilset JSON 文件 ✅ Yes extensions object 具有扩展的特定对象的字典对象 No extras any 应用程序的附加数据 No 不允许使用其他属性。 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"3D Tiles","slug":"3D-Tiles","permalink":"https://tanghaojie.github.io/categories/3D-Tiles/"},{"name":"specification","slug":"3D-Tiles/specification","permalink":"https://tanghaojie.github.io/categories/3D-Tiles/specification/"}],"tags":[{"name":"specification","slug":"specification","permalink":"https://tanghaojie.github.io/tags/specification/"},{"name":"3D Tiles","slug":"3D-Tiles","permalink":"https://tanghaojie.github.io/tags/3D-Tiles/"}],"author":null},{"title":"Cesium+Vue加载大型场景和大量3DTile数据示例","slug":"2021-cesium-2021-02-03-cesium-vue-big-model-example","date":"2021-02-03T08:05:29.000Z","updated":"2022-12-23T12:44:16.646Z","comments":true,"path":"2021/02/03/2021-cesium-2021-02-03-cesium-vue-big-model-example/","link":"","permalink":"https://tanghaojie.github.io/2021/02/03/2021-cesium-2021-02-03-cesium-vue-big-model-example/","excerpt":"","text":"点击跳转 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"vue","slug":"vue","permalink":"https://tanghaojie.github.io/categories/vue/"},{"name":"cesium","slug":"vue/cesium","permalink":"https://tanghaojie.github.io/categories/vue/cesium/"},{"name":"3D Tiles","slug":"vue/cesium/3D-Tiles","permalink":"https://tanghaojie.github.io/categories/vue/cesium/3D-Tiles/"}],"tags":[{"name":"vue","slug":"vue","permalink":"https://tanghaojie.github.io/tags/vue/"},{"name":"3D Tiles","slug":"3D-Tiles","permalink":"https://tanghaojie.github.io/tags/3D-Tiles/"},{"name":"cesium","slug":"cesium","permalink":"https://tanghaojie.github.io/tags/cesium/"}],"author":null},{"title":"网页开启设计模式 [ 速记 ]","slug":"2021-2021-01-07-web-design-mode","date":"2021-01-07T04:13:50.000Z","updated":"2022-12-23T12:44:16.639Z","comments":true,"path":"2021/01/07/2021-2021-01-07-web-design-mode/","link":"","permalink":"https://tanghaojie.github.io/2021/01/07/2021-2021-01-07-web-design-mode/","excerpt":"","text":"document.designMode = 'off' 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"shorthand","slug":"shorthand","permalink":"https://tanghaojie.github.io/categories/shorthand/"}],"tags":[{"name":"shorthand","slug":"shorthand","permalink":"https://tanghaojie.github.io/tags/shorthand/"}],"author":null},{"title":"科普-海平面高、GPS高、基准面高的区别和定义","slug":"2020-2020-11-26-Mean-SeaLevel-GPS-TheGeoid","date":"2020-11-25T14:35:49.000Z","updated":"2022-12-23T12:44:16.639Z","comments":true,"path":"2020/11/25/2020-2020-11-26-Mean-SeaLevel-GPS-TheGeoid/","link":"","permalink":"https://tanghaojie.github.io/2020/11/25/2020-2020-11-26-Mean-SeaLevel-GPS-TheGeoid/","excerpt":"","text":"从业这么久了,很多很多(包括行业内)人,根本搞不清楚海平面高、GPS 高、基准面高的区别,这里翻译和补充说明一下。 声明原文出自https://www.esri.com/news/arcuser/0703/geoid1of3.html,我只是进行了翻译和针对国内情况的补充。原文作者:Witold Fraczek, Esri Applications Prototype Lab。以下正文: 通常,研究和技术的努力会带来意外的积极成果。当欧洲探险家开始寻找通向印度的捷径时,他们发现了新世界。当葡萄球菌细菌培养物被普通霉菌错误地污染时,霉菌和细菌菌落之间的空白区域会得出结论,即霉菌青霉素会产生抑制细菌生长的化合物。这一偶然发现促进了青霉素的发展。 众所周知,地球上没有完美的几何形状,大地水准面用来描述地球独特且不规则的形状。但是,直到最近(原文发表时间:2003 年 7 月)才观察到由全球平均海平面(MSL:the global mean sea level)造成的海面有更明显的不规则性。这些不规则性比专家的预测高出一个数量级。受地球引力的控制,这些不规则现象形成了非常平缓但又庞大的“丘陵”和“山谷”。这一惊人发现是通过使用 GPS 来实现的,GPS 是美国国防部设计的一项技术,旨在彻底改变美国海军和空军的导航技术。GPS 已经做到了,而且还能做到更多。 什么是平均海平面?几代人以来,表达地形或测深标高的唯一方法是将其与海平面相关联。大地测量学家曾经认为,海洋与地球的重力平衡,并形成了完美的规则图形。MSL 通常被描述为潮汐数据,它是在特定的 19 年周期内观察到的每小时水位升高的算术平均值。该定义将月球和太阳引力变化影响引起的潮汐高潮和低潮进行平均。 MSL 定义为局部区域的零海拔。高程引用的零表面称为垂直基准。对于地图制作者来说不幸的是,海平面并不是一个简单的表面。由于海面符合地球的重力场,因此 MSL 的丘陵和山谷与陆地表面相似,但更平滑。但是,西班牙定义的零海拔与加拿大定义的零海拔不同,这就是为什么本地定义的垂直基准彼此不同的原因。 MSL 表面处于重力平衡状态。它可以看作是在各大洲下延伸,是大地水准面的近似值。根据定义,大地水准面描述了地球的不规则形状,并且是用于测量高程的真正零表面。由于无法直接观察到大地水准面,因此无法直接测量大地水准面上方或下方的高度,并且无法通过进行重力测量和对表面进行数学建模来推断。以前,无法精确测量大地水准面,因此 MSL 可以粗略地估算它。尽管出于实际目的,假定在海岸线处的大地水准面和 MSL 表面基本相同,但在某些地点,大地水准面实际上可能与 MSL 相差几米。 不同的测量值GPS 改变了任何地点的高度测量方式。GPS 在其水平和垂直基准面上均使用椭球坐标系,椭球体或扁平的球体用于表示地球的几何模型。 从概念上讲,这种精确计算的椭球体(称为扁圆椭球体)旨在复制 MSL 作为主要的大地测量参考或垂直基准。如果使用此椭球垂直基准,则椭球上方的高度将与 MSL 不同,并且大多数位置的直接高程读数都将很尴尬。造成这种情况的部分原因是,GPS 的海拔高度定义不涉及 MSL,而是涉及称为参考椭球的重力表面。由于参考椭球旨在紧密接近 MSL,因此当两个数字相差很大时,令人惊讶。 TOPEX / POSEIDON 卫星于 1992 年发射,专门设计用于执行非常精确的高空观测。这些测量结果表明,人为误差和 GPS 错误都不是造成椭球和 MSL 测量值之间有时存在重大差异的原因。实际上,由地球海平面产生的三维表面在几何上是不正确的,并且无法通过数学方法计算出其明显的不规则性。这解释了基于椭球的 GPS 高程读数与精确地形图上显示的高程之间的区别。 对加利福尼亚州雷德兰兹市 Esri 总部的海拔读数进行了简短检查,就证明了这些差异。坎普斯高程显示在地形四边形地图和高分辨率数字高程模型(DEM)上,该区域位于 MSL 上方约 400 米处。但是,对于相同位置的精确测量后,未经调整的 GPS 读数通常显示海拔为 368 米。 为什么相距 32 米?GPS 接收器使用由世界大地测量系统(WGS84)椭球估计的理论海平面,它并不完全遵循理论 MSL。用椭圆形近似的 MSL 与重力或地球的质心有关。WGS84 椭球和大地水准面之间的差异随位置而异。继续此示例,尤卡帕(Yucaipa)(位于雷德兰兹以东不到 10 英里的城市)的海拔读数相差 31.5 米。 (补充)中国国内根据目前的经验值来看,这个差异也在 30 米左右。 大地水准面和椭球体随着大地水准面的波动起伏相交。波动起伏是由几种现象引起的,其中最重要的是地球非均质性引起的重力异常的存在。地壳中的岩浆密度分布不 均匀。在密度较大的区域,它可能会更高,因此会变凉。密度较小的区域相应地较低且较热。稠密的岩浆施加更强的拉力,导致水团的堆积。对于这些卷是否移动或移动速度知之甚少。如果这些位置确实移动,它们的移动将与其他地质事件的移动速度相同(即非常缓慢)。 从太空获得的精确测量值将应用于 GPS 读数。这些测量基于椭球表面,该椭球表面是从三维笛卡尔坐标系获得的数学上生成的地球模型。GPS 接收器只能提供椭圆(几何)高度。 但是,大多数用户期望与 MSL 相关的准确的海拔读数。因此,较新的 GPS 设备基于使用地理坐标作为输入的公式,表格和矩阵的组合,将“正交”(地理)高度测量结果输出为“幕后”计算结果。提供了从粗糙或精细 DEM 矩阵中获取的地理位置的适当高度,而不是 z 值(或高度)的实际测量值。一些接收器使用大地水准面高度的近似值,以根据椭球高度估算正高。还有一些单位,使用较旧的技术作业,提供基于椭球体的 z 值改正读数。 全球大地水准面定义-Geoid99GPS 需要一个全球定义的大地水准面,以便 GPS 接收器可以计算所需的正确 z 值作为全局垂直基准的参考面。(美国)国家大地测量局(National Geodetic Survey)开发了 Geoid99,这是一种具有亚米级精度的模型。它被用作零表面以在全球范围内建立一致且准确的高程。但是,尽管达到了令人印象深刻的准确性水平,但由于重力效应,Geoid99 的某些部分仍偏离了 MSL。 由美国国家航空航天局戈达德太空飞行中心,美国国家影像和制图局(NIMA)和俄亥俄州立大学合作开发的地球大地测量模型(EGM96)已用于计算精确度优于一米的大地水准面波动(除缺乏准确的表面重力数据的区域)。该表面的值显示每个位置的 MSL 与用作 GPS 高程读数参考的椭圆形之间的差值。换句话说,EGM96 显示出海洋表面的引力确实是多么不均匀。大地水准面相对于 WGS84 椭球的最大起伏范围为 192 米。最大的异常现象是在印度东南部发现的,该大地水准面位于椭球以下 105 米,并且在印度尼西亚东部发现了最大的膨胀。 “如何”模拟如果没有重力异常,大陆海岸线将如何变化?简短的答案是,它们看起来就像地球是椭球一样。最大的起伏集中在印度洋北部和印度尼西亚群岛内。因此,将出现目前在澳大利亚北部的阿拉法拉海和卡彭特里亚湾所覆盖的地区。相反,其他地区,如恒河和雅鲁藏布江等南亚主要河流三角洲形成的低地,以及印度河,伊洛瓦底江和湄公河的三角洲,也将下沉。 作为一项智力练习,请想象一下地球是一个椭球体和一个椭球体的几何完美形状。为了可视化这些“假设”场景,使用表示距地球中心的距离的栅格生成了计算机模拟,并使用 ArcGIS Spatial Analyst 扩展程序中的栅格计算器生成了该模拟。通过删除 EGM96 识别出的重力异常来修改地球仪的标准数字高程模型。椭球和椭球的这些几何上正确的表示被用于生成称为 SPHEROID DEM 和 ELLIPSOID DEM 的 GIS 模拟。随附的插图显示了这些形状以及其他场景对陆地和海洋分布的影响。 SPHEROID DEM(球形 DEM)SPHEROID DEM 是基于以下假设创建的:地球的形状,或更准确地说,以 MSL 表示的地球表面的形状是球形。换句话说,连接质心和假设的等势引力表面的地球半径在地球上各处都相同。半径设置为 6,367,473 米,这是从纬度为 45 度的椭圆参考面到地球中心的距离。 这种几何形状改变为重力改变后的椭球形会导致全球海洋发生变化。极地带距离地球中心相对较远,而这些新的更高的海拔高度将迫使海水流向赤道。同样,赤道区域将相对更靠近地球中心,并且会受到重力的强烈影响。赤道带重力的增加会把海水拉向赤道,形成一个全球性的赤道海洋。 ELLIPSOID DEM(椭球 DEM)ELLIPSOID DEM 将地球描述为椭球。尽管沿着每个纬度从椭球表面到地球中心的距离都是相同的,但是每个纬度都有其自己的唯一值,即从每个极点到赤道逐渐增加。为了从另一个角度看待这个椭圆形的地球(其物理形状以表面上任何点到地球质量中心的距离为特征),使用 WGS84 基准定义生成了一个网格。每个网格单元值代表从表面到地球质心的距离(以米为单位)。应用了三角函数的复杂组合来创建椭球的表示形式。然后将代表地球当前浮雕的 DEM 添加到椭圆形栅格中。 WGS84 椭球的长轴和短轴之间的差为 42,770 米。赤道半径与两极之一的半径长度之差为 21,385 米-仅占半径的 0.33%。从几何学上讲,地球的“扁平化”相对来说微不足道,但是就地理而言,它具有巨大的影响。 如果地球静止不动如果地球停止自转并且离心作用不再迫使海洋在赤道周围积聚,将会发生什么?看来世界海洋将分裂为两个极地海洋,而赤道区域将完全干燥。为了对此假设建模,指定了 6,371,146 米的值(距地球中心的距离表示参考椭球上的海平面的近似高度),以将水与土地分开。对于此“假设假设”模拟,海平面的升高是基于这样的假设,即海水量将与今天的水平大致相同。 冰川融化回到地球的大地水准面表示法,再进行一次模拟,模拟所有冰川融化的地球。如果全球变暖导致南极和格陵兰的大型冰川(目前覆盖所有土地的大约 10%)融化,那么该模拟可能会预测未来只有几百年的距离。如果这些冰川中的水全部释放,MSL 将比当前水位上升约 80 米。 结论GIS 使探索地球形状的不同概念化的影响以及对各种全球条件进行建模成为可能。 理论结论GPS 高=椭球高=大地高:点到椭球面的距离。大地水准面高=正高:点到大地水准面的距离,大地水准面=重力等位面,无法全部测量。似大地水准面高=正常高:点到似大地水准面的距离,由于大地水准面无法测量,只能尽可能多的选点进行测量,生成似大地水准面。在海面上可以认为似大地水准面和大地水准面重合,而越是起伏大的地区,地球质量越不均匀,差异就越大,需要更多的控制点校正。 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"GIS","slug":"GIS","permalink":"https://tanghaojie.github.io/categories/GIS/"}],"tags":[{"name":"GIS","slug":"GIS","permalink":"https://tanghaojie.github.io/tags/GIS/"}],"author":null},{"title":"DJI照片元数据主要信息列表","slug":"2020-2020-11-26-DJI-XMP-Meta-Data-Info-Explain","date":"2020-11-25T12:34:21.000Z","updated":"2022-12-23T12:44:16.639Z","comments":true,"path":"2020/11/25/2020-2020-11-26-DJI-XMP-Meta-Data-Info-Explain/","link":"","permalink":"https://tanghaojie.github.io/2020/11/25/2020-2020-11-26-DJI-XMP-Meta-Data-Info-Explain/","excerpt":"","text":"字段 说明 ModifyDate=”2018-08-09” 照片修改日期 CreateDate=”2018-08-09” 照片创建日期 Make=”DJI” 制造商 Model=”FC6310R” 相机型号 format=”image/jpg” 照片格式 AbsoluteAltitude=”+150.09” 相机的绝对高度,基于使用的椭球模型(通常为 WGS84 或 CGCS2000)。 RelativeAltitude=”+109.86” 基于原点(起飞点)的摄像机的相对高度。 GpsLatitude=”22.63093244” 相机位置的纬度,在北正南负,单位:度。 GpsLongtitude=”113.93793694” 相机位置的经度,单位:度。 GimbalRollDegree=”+0.00” 云台侧倾角(在东北地面框架中,北为真北) GimbalYawDegree=”-38.00” 云台偏航角(在东北地面框架中,北为真北) GimbalPitchDegree=”-89.90” 云台俯仰角(在东北地面框架中,北为真北) FlightRollDegree=”+4.70” 无人机侧倾角(在东北地面框架中,北为真北 FlightYawDegree=”-36.10” 无人机偏航角(在东北地面框架中,北为真北) FlightPitchDegree=”+0.80” 无人机云台俯仰角(在东北地面框架中,北为真北) FlightXSpeed=”+6.60” 北方地面速度(m / s) FlightYSpeed=”-5.20” 东方地面速度(m / s) FlightZSpeed=”+0.00” 垂直地面速度(m / s) CalibratedFocalLength=”3666.666504” 镜头的设计焦距,单位:像素。 CalibratedOpticalCenterX=”2736.000000” 光学设计位置的 X 轴坐标中心,单位:像素。 CalibratedOpticalCenterY=”1824.000000” 光学设计位置的 Y 轴坐标中心,单位:像素。 RtkFlag=”50” RTK 状态。(前面文章有说明)大疆/千寻卫星后处理解算信息说明 RtkStdLon=”0.01160” 照片记录的标准偏差(以米为单位)在经度方向上的位置。当标准图像的偏差大于 0.1,为建议不要使用此照片。 RtkStdLat=”0.01095” 照片记录的标准偏差(以米为单位)在纬度方向上的位置。当标准图像的偏差大于 0.1,为建议不要使用此照片。 RtkStdHgt=”0.02918” 照片记录的标准偏差(以米为单位)在高度方向上的位置。当标准图像的偏差大于 0.1,为建议不要使用此照片。 DewarpData= “… …” 畸变纠正参数。(前面文章有说明)相机内参和畸变校正参数说明 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"specification","slug":"specification","permalink":"https://tanghaojie.github.io/categories/specification/"}],"tags":[{"name":"specification","slug":"specification","permalink":"https://tanghaojie.github.io/tags/specification/"}],"author":null},{"title":"metashape-cluster","slug":"2020-2020-11-10-metashape-cluster","date":"2020-11-10T13:23:19.000Z","updated":"2022-12-23T12:44:16.638Z","comments":true,"path":"2020/11/10/2020-2020-11-10-metashape-cluster/","link":"","permalink":"https://tanghaojie.github.io/2020/11/10/2020-2020-11-10-metashape-cluster/","excerpt":"","text":"1.所有电脑在同一局域网,设置固定 IP 地址,使用千兆交换机(如果只有两台设备,可以采用网线直连)。 2.共享网络文件夹,右键需共享的工程目录文件夹,选择属性-共享,选择 everyone,点击共享。选择高级共享,打勾共享文件夹,点击权限,选择 everyone,权限选择完全控制。 3.打开软件,菜单栏工具——偏好设置——网络,勾选 network,填入服务端 IP 地址(不能使用 127.0.0.1)和项目所在目录(就是上面共享的目录)。 4.作为服务端的电脑,打开 cmd,输入(不能出现中文字符):“C\\Program Files\\Agisoft\\Metashape Pro\\Metashape.exe” --server --control 192.168.0.1:5840 --dispatch 192.168.0.1:5841。也可以把这段话保存成:server.bat 文件,打开就自动执行了。 5.作为节点的电脑,打开 cmd,输入(不能出现中文字符):\"C:\\Program Files\\Agisoft\\Metashape Pro\\Metashape.exe\" --node --dispatch 192.168.0.1:5841 --root \\\\DESKTOP-PC\\Cluster,–dispatch 参数要一样,–root 就是保存项目所有文件的共享文件夹,共享目录名用计算机名的形式,别用 ip 形式。同样也可以保存成:node.bat,方便使用。 6.打开 Agisoft Network Monitor,输入主机的 ip 和端口,点击 connect,就可以查看连接的电脑了。 7.打开软件,按照正常流程创建工程后保存,一定要保存到共享目录下面。之后进行运算的时候软件会询问是否通过集群进行计算。 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[],"tags":[],"author":null},{"title":"Agisoft photoscan/metashape 使用教程","slug":"2020-2020-11-10-metashape-workflow","date":"2020-11-10T11:51:49.000Z","updated":"2022-12-23T12:44:16.638Z","comments":true,"path":"2020/11/10/2020-2020-11-10-metashape-workflow/","link":"","permalink":"https://tanghaojie.github.io/2020/11/10/2020-2020-11-10-metashape-workflow/","excerpt":"","text":"Photoscan,新版本改名叫 Metashape 了,相较于 context capture(smart3d)进行空三计算效果更好,速度更快,配置更灵活,空三结果可以导入 context capture 进行三维重建。因此,我经常使用 Metashape 进行空三处理和 DOM 生成,然后再用 cc 进行三维重建,可以显著提高处理速度。而且两个软件都支持集群处理,所需环境保持一致也不会冲突。下面开始作业流程。 导入照片,POS,准确性调整1.如果您在 EXIF 标签中存储了位置精度:转到“工具”菜单->“首选项…”->“高级”选项卡,然后选中“从 XMP 元数据加载相机位置精度”。 2.在 Metashape 中添加照片:“工作流程”->“添加照片…”。 3.如果是没有 POS 的照片:导入相机位置。通过单击“参考”窗口中的“导入”按钮导入 POS。确保为文件选择正确的列。如果文件包含角度数据,请选中“加载角度”复选框,然后选择右列。选择存储相机位置的坐标系。如果您有精度估算,也可以加载它们。 4.如果您的相机相对无人机机头存在旋转,则需要在“工具”->“相机校准…”下指定。在“GPS/INS 偏移”标签下,将“偏转(度)” 指定为 90 或您旋转的角度。 5.检查设置。单击“参考”窗口中的“设置”按钮。如果您使用的是方向数据,但尚未导入方向精度,则建议您在不确定是否具有比其更好的精度的情况下,将精度提高到 10-20 度。 照片质量1.Metashape 可以自动估计照片质量。建议禁用质量值小于 0.5 个单位的图像,并将其排除在摄影测量处理之外。 2.通过在参考窗口中右键单击照片,选择“估计图像质量…”,然后选择“所有相机”,可以估计图像质量。 3.要显示照片的估计图像质量,请在“照片”窗格中将查看模式更改为“详细信息”。 4.您现在可以按“质量”列进行排序。选择质量低于 0.5 的照片并将其禁用。 对齐照片1.对齐您的照片:“工作流程”->“对齐照片…”。将“精度”设置为“高”(只需要 DOM、DSM、DEM,不需要高精度模型的时候,用“低”就完全够了),将“成对预选”设置为“参考”。您也可以使用“最高”,但是会花费更长的时间。阅读手册中的准确度等级是什么意思。可能有必要调整“关键点”和“联系点”限制,以加快处理速度。“自适应相机模型拟合”将使 Metashape 根据其可靠性估算值来选择应包含在调整中的相机参数。 2.对齐完成后,浏览照片,然后依次取消选中和禁用照片块。完成此操作后,运行“优化摄像机…”。勾选:f,cx,cy,k1,k2,k3,p1,p2。 3.在继续之前,请复制您的块。如果在以下步骤中出现问题,则可以返回到副本。 4.使用手动选择工具删除稀疏点云中明显的离群点。然后运行“优化相机…”(勾选:f,cx,cy,k1,k2,k3,p1,p2)。 5.使用“模型”菜单下的“逐步选择…”。向过滤器推荐一定的值是很困难的,最好的方法是遍历这些过滤器以实现误差很小的点云。指定的值应视为建议值,并且取决于数据的质量。使用以下过滤器: 图像计数。如果您的数据应该覆盖两张以上的照片(例如,打开的区域和清晰的区域),请使用此选项。然后,您可以使用图像计数=2,对于地面植被比较多的数据,请跳过这一步。使用与以前相同的参数运行“优化摄像机…”。 重建不确定性(几何形状)。使用滑块调整合适的值以选择不确定性高的点。推荐值:50 到 25。按 OK,然后按键盘上的 Delete 删除点。使用与以前相同的参数运行“优化摄像机…”。重复至少 2 次。 投影精度(像素匹配误差)。使用滑块调整合适的值以选择不确定性高的点。推荐值:10 到 8。按 OK,然后按键盘上的 Delete 删除点。使用与以前相同的参数运行“优化摄像机…”。重复此过滤器和优化过程至少 2 次。 选中所有参数后,“优化相机…”。 如果您有地面控制点(GCP),请先将其导入,然后再继续进行下一步(重新投影错误)。请参阅下文,了解如何导入 GCP。 重投影误差(像素残留误差)。使用滑块调整合适的值以选择不确定性高的点。推荐值:1 到 0.5。按 OK,然后通过按键盘上的 Delete 删除点。选中所有参数,运行“优化摄像机…”。重复至少 2 次。 地面控制点(GCP)仅当您已采集地面控制点时才执行此步骤。 1.如果地面控制点(GCP)与图像位于不同的坐标系中,则现在需要在导入之前将项目转换为与 GCP 相同的坐标系。单击“参考”窗口中的“转换”按钮即可完成此操作。(新版本已经支持照片、地面控制点采用各自独立的坐标系) 2.通过单击“参考”窗口中的“导入”按钮导入 GCP。 3.每个 GCP(甚至照片)的精度可以通过三种不同的方式设置:x,y 和 z 的精度为 0.1m:0.1。x 和 y 的精度为 0.1m,z 精度为 0.5m:0.1/0.5。x 的精度为 0.1m,y 的精度为 0.2m,z 的精度为 0.5m:0.1/0.2/0.5。 4.刺点。您可以右键单击 GCP,然后选择“按选择过滤照片…”。您可以使用“向上翻页”和“向下翻页”键在照片之间切换。将每个标记至少放置在两张照片中。时常运行“优化相机…”以改善未放置标记的位置。 5.“优化相机…”。如果您的 GCP 精度很高,则应先取消选中所有照片,然后再单击“优化相机…”。确保已检查所有要使用的 GCP,并且它们具有正确的精度设置。对于使用 DJI 无人驾驶飞机拍摄的照片,其海拔质量不佳,因此,在运行“优化相机…”并进行处理之前,应始终取消选中照片(至少适用于 2018 年之前的 DJI 无人机)。 6.完成上述步骤后,GCP 中的误差应该很小(如果使用 RTK GNSS 接收器,则误差约为 5-20 厘米)。 密集点云和正射照片1.现在,您可以执行以下命令来执行批处理脚本,也可以一个接一个地运行它们。 2.建立密集的云(如果不进行模型重建可以不进行这一步)。使用“高”质量(很少使用“超高”,因为它需要很长时间,并且通常照片的质量不高。请阅读手册中的更多内容)。将深度过滤设置为“轻微”。 3.构建网格(通常从稀疏云中生成)。 4.平滑网格(工具->网格->平滑网格)。 5.使用稀疏云中的网格创建正射照片。 6.例如,将正照片导出为 tif。 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[],"tags":[],"author":null},{"title":"大疆/千寻卫星后处理解算信息说明","slug":"2020-2020-11-05-DJI-PPK-Format-Meaning","date":"2020-11-05T13:01:37.000Z","updated":"2022-12-23T12:44:16.638Z","comments":true,"path":"2020/11/05/2020-2020-11-05-DJI-PPK-Format-Meaning/","link":"","permalink":"https://tanghaojie.github.io/2020/11/05/2020-2020-11-05-DJI-PPK-Format-Meaning/","excerpt":"","text":"大疆 PPK 文件也是用的千寻解算,格式一样。 列字段 单位 说明 Station - 轨迹点序列 Timestamp(ms) 毫秒 UTC 时间戳 GPSWeek - GPS 周 TOW(s) 秒 周内秒 Latitude(deg) 度 纬度 Longitude(deg) 度 经度 H-Ell(m) 米 椭球高程 X(m) 米 高斯平面坐标系 X(如果指定『中央子午线』则有此输出字段) Y(m) 米 高斯平面坐标系 Y(如果指定『中央子午线』则有此输出字段) SDNorth(m) 米 北方向标准差 SDEast(m) 米 东方向标准差 SDHeight(m) 米 高程标准差 Q - 解算质量标志位:1:固定解(大疆:50);2:浮点解(大疆:34);3:单点解(大疆:16);4:未解出(大疆:0); 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"specification","slug":"specification","permalink":"https://tanghaojie.github.io/categories/specification/"}],"tags":[{"name":"specification","slug":"specification","permalink":"https://tanghaojie.github.io/tags/specification/"}],"author":null},{"title":"相机内参和畸变校正参数说明","slug":"2020-2020-09-29-camera-calibrate","date":"2020-09-29T10:31:25.000Z","updated":"2022-12-23T12:44:16.637Z","comments":true,"path":"2020/09/29/2020-2020-09-29-camera-calibrate/","link":"","permalink":"https://tanghaojie.github.io/2020/09/29/2020-2020-09-29-camera-calibrate/","excerpt":"","text":"以大疆 Phantom4RTK 为例,以记事本方式打开任意一张照片,搜索DewarpData,可以看到校正参数:drone-dji:DewarpData=\" 2020-05-13;3714.070000000000,3707.070000000000,-8.280000000000,-17.520000000000,-0.279234000000,0.125598000000,0.001187790000,-0.000255019000,-0.041078200000\" 值顺序为:calibrate_date;fx,fy,cx,cy,k1,k2,p1,p2,k3 分别的意思: 字段 说明 calibrate_date 校正时间 fx 以像素为单位标定出的焦距 x 坐标 相机像素焦距则为: (fx + fy) / 2 像素 fy 以像素为单位标定出的焦距 y 坐标 相机毫米焦距则为:(Phantom4rtk 一像元尺寸 2.4 微米)(fx + fy) / 2 _ (2.4 _ 0.001) 毫米 cx 以像素为单位标定出的像主点(原点为影像中心)x 坐标 建图软件(Pix4D、Context Capture 等)默认原点为影像左上角,所以要换算到影像中心。以 Phantom4rtk 为例,若照片比例为 3:2,则像素为 5472 _ 3648。(4:3 同理,像素为 4864 _ 3648) cy 以像素为单位标定出的像主点(原点为影像中心)y 坐标 像主点 x = 5472 / 2 + cx;像主点 y = 3648 / 2 + cy。 k1 径向畸变校正参数 k1 k2 径向畸变校正参数 k2 k3 径向畸变校正参数 k3 p1 切向畸变校正参数 p1 p2 切向畸变校正参数 p2 在线畸变参数计算器 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"tools","slug":"tools","permalink":"https://tanghaojie.github.io/categories/tools/"}],"tags":[{"name":"tools","slug":"tools","permalink":"https://tanghaojie.github.io/tags/tools/"}],"author":null},{"title":"DJI大疆PPK后差分处理文件导入像控预处理","slug":"2020-2020-09-22-dji-ppk-file-process","date":"2020-09-22T11:08:38.000Z","updated":"2022-12-23T12:44:16.637Z","comments":true,"path":"2020/09/22/2020-2020-09-22-dji-ppk-file-process/","link":"","permalink":"https://tanghaojie.github.io/2020/09/22/2020-2020-09-22-dji-ppk-file-process/","excerpt":"","text":"影像文件名前缀 选择大疆PPK原始文件[result.csv] function handleUpload(e) { var file = e.target.files[0] fileReader.readAsText(file) } function handleCsv(csv) { let lines = csv.split(/[\\n]/) let count = lines.length let output = [] let prefix = document.querySelector('#prefix').value for (let i = 1; i < count; i++) { let line = lines[i] if (line === '' || line === null || line === undefined) { break } let datas = line.split(',') let id = datas[0] let latitude = datas[3] let longitude = datas[4] let height = datas[5] let Q = datas[9] if (Q !== '50') { alert('Some data not fixed!') } output.push(id) output.push(',') output.push(latitude) output.push(',') output.push(longitude) output.push(',') output.push(height) output.push(',') output.push(prefix) output.push(id.padStart(4, '0')) output.push('.JPG') output.push('\\r\\n') } return output.join('') } function saveFile(data, filename) { var file = new Blob([data]) console.log(file) if (window.navigator.msSaveOrOpenBlob) { // IE10+ window.navigator.msSaveOrOpenBlob(file, filename) } else { // Others var a = document.createElement('a'), url = URL.createObjectURL(file) a.href = url a.download = filename document.body.appendChild(a) a.click() setTimeout(function () { document.body.removeChild(a) window.URL.revokeObjectURL(url) }, 0) } } let fileReader = new FileReader() fileReader.onload = function () { let result = this.result let newCsv = handleCsv(result) let nowDate = new Date() let year = nowDate.getFullYear() let month = (nowDate.getMonth() + 1).toString().padStart(2, '0') let day = nowDate.getDate().toString().padStart(2, '0') let dateStr = year + '-' + month + '-' + day saveFile(newCsv, 'result_JTEdited' + dateStr + '.csv') } let contained = document.querySelector('#contained') contained.addEventListener('change', handleUpload) 显示效果不好,点击下面打开单独的网页 独立网页的版本 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"tools","slug":"tools","permalink":"https://tanghaojie.github.io/categories/tools/"}],"tags":[{"name":"tools","slug":"tools","permalink":"https://tanghaojie.github.io/tags/tools/"}],"author":null},{"title":"QGIS将文件夹中的所有Esri Shape转换为KML文件的python处理代码","slug":"2020-2020-09-22-qgis-shp2kml-py","date":"2020-09-22T11:07:42.000Z","updated":"2022-12-23T12:44:16.637Z","comments":true,"path":"2020/09/22/2020-2020-09-22-qgis-shp2kml-py/","link":"","permalink":"https://tanghaojie.github.io/2020/09/22/2020-2020-09-22-qgis-shp2kml-py/","excerpt":"","text":"import os dir = r'C:\\Users\\YourFolderPathContainShapefile' toDir = r'C:\\Users\\YourFolderPathKMLWillOutput' crs = QgsCoordinateReferenceSystem(4326) list = os.listdir(dir) for l in list: if not l.endswith('.shp'): continue inPath = os.path.join(dir, l) vl = QgsVectorLayer(inPath, l, 'ogr') valid = vl.isValid() if not vl.isValid(): print(inPath) print('invalid') continue toFile = os.path.join(toDir, l.replace('.shp', '.kml')) QgsVectorFileWriter.writeAsVectorFormat(vl, toFile, 'utf-8', crs, 'kml') 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"QGIS","slug":"QGIS","permalink":"https://tanghaojie.github.io/categories/QGIS/"},{"name":"python","slug":"QGIS/python","permalink":"https://tanghaojie.github.io/categories/QGIS/python/"}],"tags":[{"name":"python","slug":"python","permalink":"https://tanghaojie.github.io/tags/python/"},{"name":"QGIS","slug":"QGIS","permalink":"https://tanghaojie.github.io/tags/QGIS/"}],"author":null},{"title":"QGIS添加各大地图服务的插件","slug":"2020-2020-09-22-qgis-add-map-services","date":"2020-09-22T10:43:43.000Z","updated":"2022-12-23T12:44:16.637Z","comments":true,"path":"2020/09/22/2020-2020-09-22-qgis-add-map-services/","link":"","permalink":"https://tanghaojie.github.io/2020/09/22/2020-2020-09-22-qgis-add-map-services/","excerpt":"","text":"在插件中搜索并安装QuickMapServices插件,然后打开插件的Settings -> More Services,点击Get contributed pack获得所有服务,就可以用添加添加各种地图服务了。 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"QGIS","slug":"QGIS","permalink":"https://tanghaojie.github.io/categories/QGIS/"}],"tags":[{"name":"QGIS","slug":"QGIS","permalink":"https://tanghaojie.github.io/tags/QGIS/"}],"author":null},{"title":"华测、中海达等用RTK进行PPK后差分解算测量","slug":"2020-2020-09-04-rtk-ppk","date":"2020-09-04T13:27:39.000Z","updated":"2022-12-23T12:44:16.636Z","comments":true,"path":"2020/09/04/2020-2020-09-04-rtk-ppk/","link":"","permalink":"https://tanghaojie.github.io/2020/09/04/2020-2020-09-04-rtk-ppk/","excerpt":"","text":"华测、中海达等这些厂商都开始提供 PPK 后差分解算软件了。使用很简单,先得到 1 个(3 个最好)的已知点,然后 RTK 设置为静态模式架设不动。无人机或者其他设备用 PPK 模型进行测绘,之后就可以用软件解算了。 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[],"tags":[],"author":null},{"title":"大疆精灵Phantom4RTK PPK文件说明","slug":"2020-2020-09-04-phantom4RTK-ppk-file-formate","date":"2020-09-04T12:48:40.000Z","updated":"2022-12-23T12:44:16.636Z","comments":true,"path":"2020/09/04/2020-2020-09-04-phantom4RTK-ppk-file-formate/","link":"","permalink":"https://tanghaojie.github.io/2020/09/04/2020-2020-09-04-phantom4RTK-ppk-file-formate/","excerpt":"","text":"EVENTLOG.bin 二进制格式的曝光时间戳记录文件 PPKRAW.bin RTCM3.2MSM5 格式的移动端卫星观测值数据及星历数据 PPKRAW.sig 官方没解释,猜测是 signature。身份校验文件,用于校验是否为该飞行器生成的数据,如为非该飞行器生成的数据将无法加载。 Rinex.obs 实施转码出的 Rinex 观测值文件 Timestamps.MRK ASCII 格式的明码曝光时间戳,每张照片拍照时刻定位结果,拍照时刻定位状态,定位标准差,拍照时刻等记录文件。格式说明:第一列照片的编号第二列每张照片曝光时刻的 UTC 时间,以 GPS 时间格式表示时的周内秒部分。第三列每张照片曝光时刻的 UTC 时间,以 GPS 时间格式表示时的 GPS 周部分。第四列每张照片曝光时刻瞬间天线相位中心到相机 CMOS 传感器中心的在北方向(N)的偏差,单位为毫米,CMOS 中心在天线相位中心偏北方向为正,偏南方向为负。第五列每张照片曝光时刻瞬间天线相位中心到相机 CMOS 传感器中心的在东方向(E)的偏差,单位为毫米,CMOS 中心在天线相位中心偏东方向为正,偏西方向为负。第六列每张照片曝光时刻瞬间天线相位中心到相机 CMOS 传感器中心的在垂直方向(V)的偏差,单位为毫米,CMOS 中心在天线相位中心偏下为正,偏上为负。第七列曝光时刻获取的 CMOS 中心的实时位置纬度(Lat),单位为度。当飞机定位处于 RTK 模式下时,此时的位置为 RTK 位置加上曝光时刻天线相位中心到 CMOS 中心的位置,精度为 RTK 精度(厘米级);当飞机定位处于 GPS 模式下时,此时的位置为 GPS 单点定位位置加上曝光时刻天线相位中心到 CMOS 中心的位置,精度为 GPS 单点定位的精度(米级)第八列曝光时刻获取的 CMOS 中心的实时位置经度(Lon),单位为度。第九列曝光时刻获取的 CMOS 中心的实时高度,单位为米。该高度为大地高(俗称椭球高),(用户自行定义其椭球模型,默认为 WGS84,用户可以通过接入不同的 CORS 站系统/基准,设定其为其他椭球,如 CGCS2000)表面的高度。注意,此高度并非基于国家 85 高程基准或 56 高程基准(正常高),也并非基于全球范围内比较通用的 EGM96/2008 高程基准(正高)。第十至十二列北、东、天三个方向定位结果的标准差,表征在三个方向上定位的相对精度。单位为米第十三列(很常用)RTK 状态位: 0-无定位 16-单点定位模式 34-RTK 浮点解 50-RTK 固定解当某张照片标志位不为 50 的时候,不推荐使用此照片直接进行建图。 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"specification","slug":"specification","permalink":"https://tanghaojie.github.io/categories/specification/"}],"tags":[{"name":"specification","slug":"specification","permalink":"https://tanghaojie.github.io/tags/specification/"}],"author":null},{"title":"无人机多层航线建模失败解决方案","slug":"2020-2020-09-04-uav-multi-height-route","date":"2020-09-04T12:27:05.000Z","updated":"2022-12-23T12:44:16.636Z","comments":true,"path":"2020/09/04/2020-2020-09-04-uav-multi-height-route/","link":"","permalink":"https://tanghaojie.github.io/2020/09/04/2020-2020-09-04-uav-multi-height-route/","excerpt":"","text":"&emsp;&emsp;无人机航测的过程中,经常会碰到空中环境太恶劣,无法正常飞行的情况。一般的做法都是先做一个超高空飞行,保证覆盖范围和整体约束,然后对特征地物、居民地、建筑物等,进行超低空飞行作为补充,这样就避开了空中混乱的位置。但问题是超高空和超低空之间重叠率很难保证,导致建模的时候经常遇到问题。最常见的就是只使用高空照片做特征点匹配,低空的高清晰度照片被抛弃;或者高低空照片混用,一块模糊一块清晰,成像不统一。针对这种情况,一般有几种解决方案: 1.建模时从高空照片中剔除低空覆盖的部分。(边缘还是要留下,保证有重叠率来识别) 2.条件允许时扩大低空航线范围,提高低空重叠率。 3.高低空照片分别建模,建模完成以后再合模。 4.如果用 context capture 建模,手动添加连接点强制匹配。 5.如果用 context capture 建模,建模参数设置为高特征点匹配。 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[],"tags":[],"author":null},{"title":"地面采样距离(GSD)计算器","slug":"2020-2020-08-14-gsd-calculator","date":"2020-08-14T07:39:31.000Z","updated":"2022-12-23T12:44:16.636Z","comments":true,"path":"2020/08/14/2020-2020-08-14-gsd-calculator/","link":"","permalink":"https://tanghaojie.github.io/2020/08/14/2020-2020-08-14-gsd-calculator/","excerpt":"","text":"独立网页的版本 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"tools","slug":"tools","permalink":"https://tanghaojie.github.io/categories/tools/"}],"tags":[{"name":"tools","slug":"tools","permalink":"https://tanghaojie.github.io/tags/tools/"}],"author":null},{"title":"qgis速记","slug":"2020-2020-08-12-post","date":"2020-08-12T14:15:05.000Z","updated":"2022-12-23T12:44:16.635Z","comments":true,"path":"2020/08/12/2020-2020-08-12-post/","link":"","permalink":"https://tanghaojie.github.io/2020/08/12/2020-2020-08-12-post/","excerpt":"","text":"按照几何位置排序,其中 45 代表东北方向,其他方向排序可以自己指定,y 正轴(北)方向为 0 度,顺时针旋转 sin(45) * x(centroid($geometry)) + cos(45) * y(centroid($geometry)) 字段长度不足补 0,3 是长度,0 是不足的左侧补 0 lpad(\"你的字段名\", 3, '0') 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"QGIS","slug":"QGIS","permalink":"https://tanghaojie.github.io/categories/QGIS/"}],"tags":[{"name":"QGIS","slug":"QGIS","permalink":"https://tanghaojie.github.io/tags/QGIS/"}],"author":null},{"title":"jenkins从github拉取nuxt项目部署到docker, windows平台","slug":"2020-2020-06-10-nuxt-docker","date":"2020-06-10T14:15:05.000Z","updated":"2022-12-23T12:44:16.635Z","comments":true,"path":"2020/06/10/2020-2020-06-10-nuxt-docker/","link":"","permalink":"https://tanghaojie.github.io/2020/06/10/2020-2020-06-10-nuxt-docker/","excerpt":"","text":"准备环境 开发环境:win10 服务器 docker 宿主环境:win10 docker 环境:linux jenkins 部署环境:docker 配置 jenkins 插件:github、git、publish over ssh。提前要在全局工具配置里面配置 git,系统配置里面配置 github server、publish over SSH。这常用工具网上都有教程,不单独说了。有一个坑是,publish over SSH 连接 OpenSSH for windows,我用 key 始终不行, 点下面高级,用户名密码模式搞定的。 服务器 win10:OpenSSH for windows这个需要在你的 win10 服务器上配置,网上很多,我也是照着网上做的。 docker:node 镜像我用的 node 官方镜像生产的自己的镜像,你可以用自己习惯的。把 node 容器运行起来,docker exec -it YourName /bin/bash进入容器,执行npm install -g cnpm --registry=https://registry.npm.taobao.org配置淘宝源,新建 /app文件夹,之后代码构建和发布就都放这里了。然后把这个容器打包成镜像,名字随便,就叫mynode:latest(仓库:版本)。 开始 jenkins:1.新建任务。2.勾选 github 项目:填写地址:git@github.com:YourName/YourProject.git。3.源码管理:选择 git,url 和上面一样,设置 Credentials,如果是 public 项目就不用设置。4.轮询 SCM 或者 GitHub hook 自己看着办。5.构建:选择执行 shell,命令写:tar -zcvf frontend.tar.gz *,意思是把所有代码打包到frontend.tar.gz。6.构建:选择 Send files or execute commands over SSH。6.1 SSH Server 选择之前配置好的。6.2 Source files:frontend.tar.gz。6.3 Remote directory:/(注意这个根目录是你之前配置好的 SSH Server 连接到的目录,比如你之前配置的/d:/docker/,那么这里就会把 frontend.tar.gz 上传到 d:/docker/frontend.tar.gz。windows SSH 连接 D 盘就是这么写的/D:/前面有个/)6.4 Exec command:frontend.bat。意思就是执行远端 windows 服务器上的frontend.bat文件,所以去远端服务器的C:\\Users\\Administrator下新建这个frontend.bat文件,Administrator 是你登录的用户名。连接默认就固定这个目录,我尝试了几个办法想把文件放 D 盘执行的,但一直不行,放弃了,frontend.bat里面写什么下面说。7.保存。 nuxt 项目:1.上传代码的时候忽略.nuxt node_modules 等等这些文件,没啥好说的。2.根目录添加Dockerfile。写入: FROM mynode:latest WORKDIR /app COPY . /app RUN cnpm install \\ && npm run build EXPOSE 3000 CMD [\"npm\", \"run\", \"start\"] 简单解释一下,用 mynode (上面准备工作弄好了的)构建新镜像,设置工作目录/app,把当前所有文件拷贝到/app,(在工作目录)执行cnpm install 和 npm run build, 对外访问端口 3000,容器开始运行后(在工作目录)执行npm run start。这里构建发布容器,设置依赖,运行就弄好了。之后就是去 windows 服务器上执行脚本,每次构建之前删除旧的,运行新的。 服务器脚本(frontend.bat):直接上内容: d: # 切换到d盘 cd docker # 到d:/docker这个文件夹 rd /S /Q frontend # 删除d:/docker下,frontend这个文件夹 mkdir frontend # 新建 frontend 文件夹 tar -xvf frontend.tar.gz -C ./frontend # 解压jenkins打包上传过来的文件到frontend文件夹 cd frontend # 到d:/docker/frontend这个文件夹 docker stop frontend # 停止已运行容器 docker rm -v frontend # 删除已存在容器 docker image rm frontend # 删除镜像 docker build -t frontend:latest . # 运行Dockerfile打包生成新镜像:frontend:latest,注意最后有一个点,表示用当前目录下的Dockerfile来执行的 docker run -itd --restart=always --name frontend -p 3000:3000 frontend:latest # 运行容器 到这里就全部完成了。去 jenkins 立即构建就 ok 了。 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"other","slug":"other","permalink":"https://tanghaojie.github.io/categories/other/"}],"tags":[{"name":"other","slug":"other","permalink":"https://tanghaojie.github.io/tags/other/"}],"author":null},{"title":"git commit规范化,设置Commitizen,符合Angular的规范","slug":"2020-2020-05-15-git-commitizen","date":"2020-05-15T12:24:09.000Z","updated":"2022-12-23T12:44:16.635Z","comments":true,"path":"2020/05/15/2020-2020-05-15-git-commitizen/","link":"","permalink":"https://tanghaojie.github.io/2020/05/15/2020-2020-05-15-git-commitizen/","excerpt":"","text":"安装配置commitizen 地址cz-conventional-changelo 地址:规范要求,不同的适配器要求不同conventional-changelog 地址:生成 changelog.md npm install -g commitizen npm install -g cz-conventional-changelog npm install -g conventional-changelog-cli commitizen init cz-conventional-changelog --save-dev --save-exact 如果已经有其他适配器了,会报错,用 --force 替换掉,即: commitizen init cz-conventional-changelog --save-dev --save-exact --force 使用以后提交代码就用git cz -m替代git commit -m就好了,或者不输入 message 跟着提示走就没问题。type 值: 值 描述 feat 新增一个功能 fix 修复一个 Bug docs 文档变更 style 代码格式(不影响功能,例如空格、分号等格式修正) refactor 代码重构 perf 改善性能 test 测试 build 变更项目构建或外部依赖(例如 scopes: webpack、gulp、npm 等) ci 更改持续集成软件的配置文件和 package 中的 scripts 命令,例如 scopes: Travis, Circle 等 chore 变更构建流程或辅助工具 revert 代码回退 生成 changelog:conventional-changelog -p angular -i CHANGELOG.md -s 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"git","slug":"git","permalink":"https://tanghaojie.github.io/categories/git/"},{"name":"other","slug":"git/other","permalink":"https://tanghaojie.github.io/categories/git/other/"}],"tags":[{"name":"other","slug":"other","permalink":"https://tanghaojie.github.io/tags/other/"},{"name":"git","slug":"git","permalink":"https://tanghaojie.github.io/tags/git/"}],"author":null},{"title":"docker速查表","slug":"2020-2020-05-15-docker-cheat-sheet","date":"2020-05-14T16:50:41.000Z","updated":"2022-12-23T12:44:16.635Z","comments":true,"path":"2020/05/15/2020-2020-05-15-docker-cheat-sheet/","link":"","permalink":"https://tanghaojie.github.io/2020/05/15/2020-2020-05-15-docker-cheat-sheet/","excerpt":"","text":"容器(Container)生命周期 docker create 创建容器但不启动它。 docker rename 用于重命名容器。 docker run 一键创建并同时启动该容器。 docker rm 删除容器。 docker update 调整容器的资源限制。 常用参数docker run --rm 临时容器,容器停止之后删除它。docker run -d container_id,-d 表示自动将容器与终端分离(也就是说在后台运行容器,并输出容器 ID)docker run -p container_id,-p 表示指定端口映射,格式:主机(宿主)端口:容器端口 启动和停止 docker start 启动已存在的容器。 docker stop 停止运行中的容器。 docker restart 重启容器。 docker pause 暂停运行中的容器,将其「冻结」在当前状态。 docker unpause 结束容器暂停状态。 docker wait 阻塞地等待某个运行中的容器直到停止。 docker kill 向运行中的容器发送 SIGKILL 指令。 docker attach 连接到运行中的容器。 信息 docker ps 查看运行中的所有容器。 docker logs 从容器中读取日志。(你也可以使用自定义日志驱动,不过在 1.10 中,它只支持 json-file 和 journald)。 docker inspect 查看某个容器的所有信息(包括 IP 地址)。 docker events 从容器中获取事件 (events)。 docker port 查看容器的公开端口。 docker top 查看容器中活动进程。 docker stats 查看容器的资源使用量统计信息。 docker diff 查看容器文件系统中存在改动的文件。 常用参数docker ps -a 显示所有容器,包括运行中和已停止的。docker stats --all 同样将显示所有容器,默认仅显示运行中的容器。 导入 / 导出 docker cp 在容器和本地文件系统之间复制文件或目录。 docker export 将容器的文件系统打包为归档文件流 (tarball archive stream) 并输出至标准输出 (STDOUT)。 执行命令 docker exec 在容器内执行命令。 例如,进入正在运行的 foo 容器,并连接 (attach) 到一个新的 Shell 进程:docker exec -it foo /bin/bash。 镜像(Images)生命周期 docker images 查看所有镜像。 docker import 从归档文件创建镜像。 docker build 从 Dockerfile 创建镜像。 docker commit 为容器创建镜像,如果容器正在运行则会临时暂停。 docker rmi 删除镜像。 docker load 从标准输入 (STDIN) 加载归档包 (tar archive) 作为镜像,包括镜像本身和标签 (tags, 0.7 起)。 docker save 将镜像打包为归档包,并输出至标准输出 (STDOUT),包括所有的父层、标签和版本 (parent layers, tags, versions, 0.7 起)。 其它信息 docker history 查看镜像的历史记录。 docker tag 给镜像打标签命名(本地或者仓库均可)。 网络(Networks)生命周期 docker network create docker network rm 其它信息 docker network ls docker network inspect 建立连接 docker network connect docker network disconnect 仓库(Repository) docker login 登入仓管中心。 docker logout 登出仓管中心。 docker search 从仓管中心检索镜像。 docker pull 从仓管中心拉取镜像到本地。 docker push 从本地推送镜像到仓管中心。 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"docker","slug":"docker","permalink":"https://tanghaojie.github.io/categories/docker/"},{"name":"cheat sheet","slug":"docker/cheat-sheet","permalink":"https://tanghaojie.github.io/categories/docker/cheat-sheet/"}],"tags":[{"name":"docker","slug":"docker","permalink":"https://tanghaojie.github.io/tags/docker/"},{"name":"cheat sheet","slug":"cheat-sheet","permalink":"https://tanghaojie.github.io/tags/cheat-sheet/"}],"author":null},{"title":"git速查表","slug":"2020-2020-05-14-git-cheat-sheet","date":"2020-05-14T08:20:07.000Z","updated":"2022-12-23T12:44:16.634Z","comments":true,"path":"2020/05/14/2020-2020-05-14-git-cheat-sheet/","link":"","permalink":"https://tanghaojie.github.io/2020/05/14/2020-2020-05-14-git-cheat-sheet/","excerpt":"","text":"git 从远程拉取代码、推代码的步骤 如果是几个人共同管理项目,并且你的队友在你之前推过代码,那你就需要 git pull 一下,把代码拉到本地,解决一下冲突,再执行以下步骤,将本地代码推到远程仓库。 git status #git 仓库状态 git add * #更新的代码添加到暂存区 git commit -m “msg” #将暂存区的更新提交到仓库区 git pull #先 git pull,拉取远程仓库所有分支更新并合并到本地 git push origin master #将本地分支的更新全部推送到远程仓库 git reset –mixed [哈希码] #回滚到这个哈希码,将本地归档区和缓冲区也进行回滚 git reset –hard [哈希码] #使用强制还原这个哈希码 git reset –soft [哈希码] #回滚到这个哈希码,只将本地归档区回滚 git revert [哈希码] #只是针对这个哈希码版本进行删除回滚操作 git log #查看日志 git reflog #查看操作记录,能找到之前的操作记录和哈希码 多分支开发 git branch -v #查看我们当前有哪些分支? git branch [name] #创建 name 分支 git checkout [name] #切换到 name 分支 git checkout -b [name] #创建并切换到 name 分支 git merge [name] 将 name 分支合并到 master 分支 查看远端 git remove -v 添加多个远端 git remote set-url –add origin http://xxxxx/xxx/adsdsdsdcelery-demo.git 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"git","slug":"git","permalink":"https://tanghaojie.github.io/categories/git/"},{"name":"cheat sheet","slug":"git/cheat-sheet","permalink":"https://tanghaojie.github.io/categories/git/cheat-sheet/"}],"tags":[{"name":"cheat sheet","slug":"cheat-sheet","permalink":"https://tanghaojie.github.io/tags/cheat-sheet/"},{"name":"git","slug":"git","permalink":"https://tanghaojie.github.io/tags/git/"}],"author":null},{"title":"几何算法延伸","slug":"2020-2020-05-10-spatial-calculate-extend","date":"2020-05-10T07:10:26.000Z","updated":"2022-12-23T12:44:16.634Z","comments":true,"path":"2020/05/10/2020-2020-05-10-spatial-calculate-extend/","link":"","permalink":"https://tanghaojie.github.io/2020/05/10/2020-2020-05-10-spatial-calculate-extend/","excerpt":"","text":"线平行$$A_xB_y = A_yB_x$$ $$\\frac{A_x}{A_y} = \\frac{B_x}{B_y}$$ $$\\frac{A_x}{A_y} = \\frac{B_x}{B_y} = \\frac{B_z}{B_z}$$ 线垂直$$A_xB_x + A_yB_y = 0$$ $$A_xB_x + A_yB_y + A_zB_z = 0$$ 向量 $\\vec A$ $\\vec B$ 夹角方向(叉乘)$\\vec A$ $\\times$ $\\vec B$ > 0 , $\\vec A$在$\\vec B$的顺时针方向。$\\vec A$ $\\times$ $\\vec B$ < 0 , $\\vec A$在$\\vec B$的逆时针方向。$\\vec A$ $\\times$ $\\vec B$ = 0 , $\\vec A$ $\\vec B$共线。 判断凸多边形根据上面方向的性质,可以推论出来。以多边形相邻两条边为向量进行叉积和,如果全部大于零则是凸多边形,如果全部为零则共线,否则就是凹多边形。 计算任意多边形面积计算三角形面积根据上一篇几何基础,向量叉乘结果为带符号的平行四边形面积,那么三角形的面积为:$$Area = \\frac{\\vec {AB} \\times \\vec {AC}}{2}$$面积结果为带符号的值,正面积则ABC成左手系,负面积则ABC成右手系。 计算任意凹凸多边形面积计算多边形面积就是把多边形切分为多个三角形计算就好了。由于面积计算的结果是带符号的,因此,此结果对于凹凸多边形都是有效。甚至可以选取多边形外的一个点,来构建三角形计算,也是同样有效的,像这样:当然一般不会选择外部的点。 计算带孔多边形的面积当多边形存在“孔洞”时, 第一层孔洞的环序是与外环序一定是相反的,因此孔洞的面积和外环的面积结果也是相反的,直接相加即可。多层孔洞当然也是一样的道理。注意 环序是很重要的,同一层环进行面积计算的时候,要始终保持同一个方向的环序进行计算。 不同文件格式要求的最外部环序是不一样的,因此不要认为外环总是和大部分情况一样是逆时针的。 扩展1.ESRI shapefile:外层环序为顺时针。2.OGC规范:此标准未定义多边形旋转;实际的多边形旋转可以沿顺时针或逆时针方向进行。3.Oracle:Exterior ring boundaries must be oriented counterclockwise, and interior ring boundaries must be oriented clockwise.(外部环边界必须逆时针定向,而内部环边界必须顺时针定向。)4.SQL Server: If SQL Server finds outer rings oriented in a clockwise direction, it will re-orient such rings to counter-clockwise - the direction required for outer rings in the Geography data type. The same goes for inner rings (holes), which SQL Server will orient to clockwise.(如果SQL Server找到沿顺时针方向定向的外环,则它将重新定位此类环为逆时针方向-Geography数据类型中外环所需的方向。内环(孔)也是如此,SQL Server会将其定位为顺时针方向。)5.PostGIS:Forces the orientation of the vertices in a polygon to follow a Right-Hand-Rule, in which the area that is bounded by the polygon is to the right of the boundary. In particular, the exterior ring is orientated in a clockwise direction and the interior rings in a counter-clockwise direction.(强制多边形中顶点的方向遵循“右手规则”,其中多边形所包围的区域在边界的右边。特别地,外环沿顺时针方向定向,而内环沿逆时针方向定向。) 判断多边形的环序面积法多边形面积为正:逆时针;面积为负:顺时针; 凸多边形任取一点叉乘:$$\\vec {AB} \\times \\vec{BC}$$值为正:逆时针;值为负:顺时针。 极点法选择多边形上的某个极点(x最大、x最小、y最大、y最小),这个极点则一定在凸包上,计算叉积得到环序方向,和上面凸多边形算法结论一致。 计算多边形质心三角形三角形 $\\triangle ABC$ 质心计算公式:$$Centroid_x = \\frac{A_x + B_x + C_x}{3}$$$$Centroid_y = \\frac{A_y + B_y + C_y}{3}$$ 任意多边形任意平面多边形,若能被拆分为 $i$个简单图形,每个简单图形的质心为:$C_i$,面积为:$A_i$。则质心Centroid的坐标$(Centroid_x, Centroid_y)$,满足以下公式:$$Centroid_x = \\frac{\\sum {C_i}_x A_i}{\\sum A_i}$$$$Centroid_y = \\frac{\\sum {C_i}_y A_i}{\\sum A_i}$$ 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"other","slug":"other","permalink":"https://tanghaojie.github.io/categories/other/"}],"tags":[{"name":"other","slug":"other","permalink":"https://tanghaojie.github.io/tags/other/"}],"author":null},{"title":"几何算法基础","slug":"2020-2020-05-10-spatial-calculate-basic","date":"2020-05-10T04:24:04.000Z","updated":"2022-12-23T12:44:16.634Z","comments":true,"path":"2020/05/10/2020-2020-05-10-spatial-calculate-basic/","link":"","permalink":"https://tanghaojie.github.io/2020/05/10/2020-2020-05-10-spatial-calculate-basic/","excerpt":"","text":"加$$\\vec A + \\vec B = (A_x + B_x, A_y + B_y, A_z + B_z)$$ 减$$\\vec A - \\vec B = (A_x - B_x, A_y - B_y, A_z - B_z)$$ 模$$\\left| \\vec A \\right| = \\sqrt[]{ A_x^2 + A_y^2 + A_z^2 }$$ 数乘(伸缩,换向)$$k \\vec A = (kA_x, kA_y, kA_z)$$ 点乘$$\\vec A \\cdot \\vec B = \\sum A_i B_i = A_xB_x + A_yB_y + A_zB_z$$ $$\\vec A \\cdot \\vec B = \\left| \\vec A \\right| \\left| \\vec B \\right| \\cos \\theta$$ 结果是一个标量(数)几何意义:1.降维,2.$\\vec B$在$\\vec A$上的投影 $$\\left| \\vec B \\right| \\cos \\theta$$ 点乘延伸:$$\\left| \\vec A \\cdot \\vec B \\right| \\le \\left| \\vec A \\right| \\left| \\vec B \\right|$$ 等号只在$\\vec A$与$\\vec B$共线时成立. $$\\vec A \\cdot \\vec B = \\vec B \\cdot \\vec A$$ $\\vec A \\cdot \\vec B > 0$,夹角在 $0^\\circ$ 到 $90^\\circ$ 之间$\\vec A \\cdot \\vec B = 0$,垂直$\\vec A \\cdot \\vec B < 0$,夹角在 $90^\\circ$ 到 $180^\\circ$ 之间 叉乘$$\\vec A \\times \\vec B = \\left| \\vec A \\right| \\left| \\vec B \\right| \\sin \\theta$$ 二维: $$\\vec A \\times \\vec B = A_xB_y - B_xA_y$$ 三维: $$\\vec A \\times \\vec B = A_yB_z- B_yA_z + A_zB_x - A_xB_z+ A_xB_y - A_yB_x$$ 几何意义:二维:$(0,0) \\quad (A_x, A_y) \\quad (B_x, B_y) \\quad ((A+B)_x, (A+B)_y)$构成的平行四边形带符号的面积三维:$\\vec A \\times \\vec B$ 结果的向量,垂直于 $\\vec A$ 和 $\\vec B$ 构成的平面 叉乘延伸:$$\\left| \\vec A \\times \\vec B \\right| = \\left| \\vec A \\right| \\left| \\vec B \\right| \\sin \\theta$$ $$\\vec A \\times \\vec B = - \\vec B \\times \\vec A$$ 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"other","slug":"other","permalink":"https://tanghaojie.github.io/categories/other/"}],"tags":[{"name":"other","slug":"other","permalink":"https://tanghaojie.github.io/tags/other/"}],"author":null},{"title":"Hexo添加数学公式支持","slug":"2020-2020-05-10-hexo-LaTex","date":"2020-05-10T03:50:01.000Z","updated":"2022-12-23T12:44:16.633Z","comments":true,"path":"2020/05/10/2020-2020-05-10-hexo-LaTex/","link":"","permalink":"https://tanghaojie.github.io/2020/05/10/2020-2020-05-10-hexo-LaTex/","excerpt":"","text":"为后面的文档做准备,添加数学公式的支持。网上一堆更新渲染插件的办法,我都准备用了。幸好先看完了文章,后面要改 node_modules 里面的源码,这怎么可能!我不能把 node_modules 上传到 github 吧,不上传又怎么同步呢。后来看了一下,hexo-theme-matery 做好了插件,那就简单了:themes/hexo-theme-matery/_config.yml 中: mathjax: enable: true 完工~就是这么简单,然后每篇要用到公式的文档,头上修改mathjax: true就好了。 示例$\\cos$ $x_i^2$ $|x+y|$ $\\sqrt[3]{x+y}$ $\\int_{r=1}^\\infty$ $\\frac{\\partial x}{\\partial y}$ $$\\Gamma(z) = \\int_0^\\infty t^{z-1}e^{-t}dt,.$$ $\\alpha$ $\\beta$ $\\theta$ $\\sum_{r=1}^n$ $\\prod_{i=1}^{K}$ $$\\begin{bmatrix} a & b & c & d & e\\\\ f & g & h & i & j \\\\ k & l & m & n & o \\\\ p & q & r & s & t \\end{bmatrix}$$ 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"other","slug":"other","permalink":"https://tanghaojie.github.io/categories/other/"}],"tags":[{"name":"other","slug":"other","permalink":"https://tanghaojie.github.io/tags/other/"}],"author":null},{"title":"全国甲乙丙级测绘资质单位名单","slug":"2020-2020-05-09-surveying-qualification","date":"2020-05-09T15:01:28.000Z","updated":"2022-12-23T12:44:16.633Z","comments":true,"path":"2020/05/09/2020-2020-05-09-surveying-qualification/","link":"","permalink":"https://tanghaojie.github.io/2020/05/09/2020-2020-05-09-surveying-qualification/","excerpt":"","text":"全国甲乙丙级测绘资质单位名单:甲级:1326 个 乙级:5081 个 丙级:8790 个 点击查看和下载 详细信息压缩包解压密码:关注公众号[桀士],回复“资质”获取密码。 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[],"tags":[],"author":null},{"title":"Scrapy爬虫使用","slug":"2020-2020-05-09-scrapy-tutorial","date":"2020-05-09T13:20:01.000Z","updated":"2022-12-23T12:44:16.633Z","comments":true,"path":"2020/05/09/2020-2020-05-09-scrapy-tutorial/","link":"","permalink":"https://tanghaojie.github.io/2020/05/09/2020-2020-05-09-scrapy-tutorial/","excerpt":"","text":"飞速起步 安装 scrapypip install Scrapy(_类 unix 记得加 sudo_)安装完成以后,到命令行输入Scrapy,查看是否安装成功。 准备和配置 scrapy startproject [name]创建项目。 项目文件说明 items.py:数据模型,类似于 dto、orm 中的 modelspiders:爬虫程序middlewares.py:模型中的中间件pipelines.py:管道,对 item 进行处理,类似于很多服务器的请求管道settings.py:程序设置,主要是一些优先级设置,优先级越高,值越小scrapy.cfg:配置 基础设置settings.py 中,找到ROBOTSTXT_OBEY = True,改为ROBOTSTXT_OBEY = False或者把他注释了这东西的意思是:每个网站可以在根目录下放一个 robots.txt 的文件,文件里面告诉了爬虫哪些网址是可以爬的,当然这就是个君子协议,靠你自己选择是不是要遵守。 设置 UTF-8:settings.py 中,添加一行:FEED_EXPORT_ENCODING = 'utf-8' 生成爬虫命令行输入:scrapy genspider [文件名] [网址],生成爬虫文件。可以在 spiders 文件夹下面看到。 开始代码 item:自己写一个 item class yourItem(scrapy.Item): info1 = scrapy.Field() info2 = scrapy.Field() info1、info2,就是数据模型对应的字段,看 scrapy.Item 的源码,实际上就是个 dict所以可以这样理解: { \"info1\": None, \"info2\": None } spider from name.items import yourItem class YourSpider(scrapy.Spider): name = 'yourname' allowed_domains = ['xxx.com'] start_urls = ['http://xxx.com/yyy/zzz'] def parse(self, response): info1 = response.xpath('//div/a/text()').extract_first() #第一个 info2 = response.xpath('//div/a/text()').extract() #extract 永远返回一个数组 item = yourItem() item['info1'] = info1 item['info2'] = info2 yield item 没啥好说的,就是爬取信息,然后设置 item 的属性就好。 可以爬了!!命令行输入:scrapy crawl yourname -o filename.csv,yourname 对应 YourSpider 这个类的 name 变量值。就会爬取数据放到 filename.csv 中,还有其他格式,自己研究。 pipelines如果你不想用 scrapy 默认的保存文件方法,那么就自定义一个保存文件的管道: class YourPipeline(object): def process_item(self, item, spider): # 伪代码 # open file # file.write(item.info1) # file.write(item.info2) # save and close file return item 之后到 settings.py,输入: ITEM_PIPELINES = { 'name.pipelines.YourPipeline': 300, } 启动当前管道配置优先级,数字越小,优先级越靠前,然后就只需要输入scrapy crawl yourname就可以运行和保存了 调试我用万能 vscode:新建调试配置文件,输入 { \"version\": \"0.2.0\", \"configurations\": [ { \"name\": \"Scrapy\", \"type\": \"python\", \"request\": \"launch\", \"module\": \"scrapy\", \"args\": [\"crawl\", \"yourname\"] } ] } 搞定! 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"scrapy","slug":"scrapy","permalink":"https://tanghaojie.github.io/categories/scrapy/"},{"name":"python","slug":"scrapy/python","permalink":"https://tanghaojie.github.io/categories/scrapy/python/"}],"tags":[{"name":"scrapy","slug":"scrapy","permalink":"https://tanghaojie.github.io/tags/scrapy/"},{"name":"python","slug":"python","permalink":"https://tanghaojie.github.io/tags/python/"}],"author":null},{"title":"QGIS plugin开发使用","slug":"2020-2020-04-13-qgis-plugin","date":"2020-04-12T02:17:00.000Z","updated":"2022-12-23T12:44:16.633Z","comments":true,"path":"2020/04/12/2020-2020-04-13-qgis-plugin/","link":"","permalink":"https://tanghaojie.github.io/2020/04/12/2020-2020-04-13-qgis-plugin/","excerpt":"","text":"起步1.刚来就不建议看文档手动创建 plugin 了,python 很熟悉的人可以看文档试试,否则还是别手动创建了,几乎所有的开发者都是通过Plugin Builder这个 Plugin 来创建的 Plugin,安装好了以后,打开 Plugin Builder,根据提示输入内容,一直下一步就创建好了。 2.用 pyrcc5 -o resources.py resources.qrc命令,把 resources.qrc 资源文件转换成 py 文件,主程序 test.py 文件中已经自动引入了。如果没有pyrcc5命令,执行pip install PyQt5安装 PyQt。 3.把整个生成的文件夹,拷贝到,~\\AppData\\Roaming\\QGIS\\QGIS3\\profiles\\default\\python\\plugins 下面,所有的 plugin 其实都在这里。 4.打开 qgis 插件–已安装,勾选 test 插件,就可以看到菜单上多了按钮,点击就能打开了。 以上最原始的 demo 就能够看见了,下面说说怎么自己写代码5.插件有一个 test*dialog.py 文件,里面最关键的一句代码应该是FORM_CLASS, * = uic.loadUiType(os.path.join(os.path.dirname(**file**), 'Test_dialog_base.ui')),这就是加载转换.ui文件给pyqt用的。 6.生成的插件文件,包含了Test_dialog_base.ui,就是界面文件。安装QGIS的时候自带了Qt Designer,用Designer就可以打开就能看到和编辑了,这里从左边拖一个Push Button进去,后面用。编辑完成界面,去QGIS里面,取消勾选,在重新选中,就重新加载插件了,能够看出来结果。这里推荐一个插件 Plugin Reloader,不用每次去取消重勾选,它可以帮我们重加载插件。 7.点击事件,在.ui文件对应的.py文件的构造函数,**init**中,加上self.pushButton.clicked.connect(self.pushButtonClicked),文件头导入from PyQt5.QtWidgets import QMessageBox然后定义方法: def pushButtonClicked(self): QMessageBox.warning(None, 'info', '测试') 8.去 QGIS 里面 reload 插件,点击按钮就能看到结果了。 9.更多的东西就自己尝试咯,你已经入门了。 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"QGIS","slug":"QGIS","permalink":"https://tanghaojie.github.io/categories/QGIS/"},{"name":"python","slug":"QGIS/python","permalink":"https://tanghaojie.github.io/categories/QGIS/python/"}],"tags":[{"name":"python","slug":"python","permalink":"https://tanghaojie.github.io/tags/python/"},{"name":"QGIS","slug":"QGIS","permalink":"https://tanghaojie.github.io/tags/QGIS/"}],"author":null},{"title":"uniapp快速实践","slug":"2020-2020-04-10-fast-uniapp","date":"2020-04-09T17:29:03.000Z","updated":"2022-12-23T12:44:16.632Z","comments":true,"path":"2020/04/10/2020-2020-04-10-fast-uniapp/","link":"","permalink":"https://tanghaojie.github.io/2020/04/10/2020-2020-04-10-fast-uniapp/","excerpt":"","text":"介绍之前给文保局做了 GIS 系统和物联网监控系统效果不错,现在想弄个 erp,问了一下业务规模,几乎约等于“零”。咋办,单一业务线走到底呗。本来说最近一直在搞 flutter,就用 flutter 给他们弄一个,app 和 web(beta)一套直接就生成了。方便快速(省事)。结果呢,人家要用微信小程序…哎,甲方是爸爸。结合已有技术经验和业务规模(如果有的话{笑}),还要考虑可能出现的业务平台变更这种吊炸天需求,调研了几个平台,这里我列一下: 1.微信小程序原生:难用的 ide,技术栈就是 web 变种。2.H5+app:原生代码少不了,Android 和 iOS 要单独适配,涉及到兼容性的问题。3.mpvue:美团搞的,基于 Vue.js 的小程序开发框架,小程序和 H5 一套搞定型。4.uni-app:Dcloud 搞的,也是基于 Vue.js 的框架,iOS、Android、H5、各种小程序一套搞定型。 对比了一下,微信小程序原生、H5+app,我直接就放弃了,微信小程序那个 IDE 简直不要太难用,而且改平台就是重写代码;H5+app 一个人弄太费事不说,缺少优化可能效果也一般,虽然有原生 app 的超高天花板,但是谁叫咱就一个人,还要快速出活呢;mpvue 本来我是准备选的,小程序+H5,基本上都能干了,后面要改原生 app 的话,我就套 webview 的壳,关键是开源免费,怪就怪在开源吧,我上 github 看了下 commits 和 issues,最近的 commit 是八个月前了…issues 也有点混乱的感觉,加上之前爆出美团的 KPI 事件,我觉得为了我的 KPI 和头发,还是算了吧。都说到这了,还有的选吗?最开始我是觉得 uniapp 商业话太严重(推广),加上不开源,还是有些顾虑的,但是好像现在是(部分)开源了?推广说明官方很重视,那。。还说什么呢,淦 淦因为微信小程序和 uniapp 都没搞过,花时间分别看了下文档,都是 web 变种,会 web 就会开发。主要是熟悉下整体的框架,为啥这样设计,有哪些个组件分别能干啥事,有哪些 API。细节千万别看,太花时间,而且你肯定记不住,所以就直接上手吧。uniapp 支持 Weex,在 app 端,用 vue 页面的话就是用 webview 渲染的,用 nvue 的话就是用原生渲染。(。・∀・)ノ゙嗨,等于说码量还是不小啊,坑还是多啊。不过 uniapp 支持#ifdef #endif条件编译语法,这个没啥好说的,写后端的都知道,赞一个。然后就是写项目了,如果看了微信小程序文档和 uniapp 的文档,你就会发现,其实就是个 web 前端的东西,无非就是语法变了一点,配置文件针对多端合并重封装了,写代码的时候要注意兼容,一个 ui 组件把几个端都同时考虑进来,用条件编译。就行了,就是这么简单,快速实践就介绍完了(其实是不知道说啥了)。(逃) 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"uniapp","slug":"uniapp","permalink":"https://tanghaojie.github.io/categories/uniapp/"}],"tags":[{"name":"uniapp","slug":"uniapp","permalink":"https://tanghaojie.github.io/tags/uniapp/"}],"author":null},{"title":"网页插件","slug":"2020-2020-04-03-weatherPlugin","date":"2020-04-03T13:47:44.000Z","updated":"2022-12-23T12:44:16.631Z","comments":true,"path":"2020/04/03/2020-2020-04-03-weatherPlugin/","link":"","permalink":"https://tanghaojie.github.io/2020/04/03/2020-2020-04-03-weatherPlugin/","excerpt":"","text":"天气中国天气网:https://cj.weather.com.cn/plugin/pc生成插件放到: themes/matery/layout/layout.ejs 动态诗词今日诗词:https://www.jinrishici.com/一言: https://hitokoto.cn/ 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"other","slug":"other","permalink":"https://tanghaojie.github.io/categories/other/"}],"tags":[{"name":"other","slug":"other","permalink":"https://tanghaojie.github.io/tags/other/"}],"author":null},{"title":"我的博客地址","slug":"2020-2020-04-03-myblogaddress","date":"2020-04-03T12:43:56.000Z","updated":"2022-12-23T12:44:16.630Z","comments":true,"path":"2020/04/03/2020-2020-04-03-myblogaddress/","link":"","permalink":"https://tanghaojie.github.io/2020/04/03/2020-2020-04-03-myblogaddress/","excerpt":"","text":"由于众所周知的原因,单纯把博客部署到一个地方,很可能访问不到,或者访问很慢,所以这里同时部署到 github 和 gitee,提高访问速度 [手动狗头] 前置条件:你会搭博客(网站) 示例我的两个博客地址:https://tanghaojie.github.io/http://jackie_tang.gitee.io/ gitee pages 的一个坑每次远程部署以后,需要手动到 gitee pages 服务里面去,手动点击更新按钮才能自动更新博客。(想自动更新?gitee pages pro 了解一下) 从 github 同步方式部署 在 gitee 新建仓库:注意点:1.仓库名用 gitee 给你分配的个人地址名,可以到 个人中心–>个人空间地址 中看到,不一定是你的用户名,比如我的地址是:Jackie_Tang,我的用户名是:JackieTang。因为我改过名。。。2.下面选择导入已有仓库,然后填入 github 地址以后,仓库名会自动变成 github 仓库名,所以又需要你自己去上面改一次 点击 创建,等待 gitee 自动导入 github 仓库。 导入完成如图配置注意点:1.选择使用 Https,否则会跨域 以上步骤就完成了,你的博客地址为:{个人地址名}.gitee.io,以后要同步 github 的数据,只需要这样操作: 同步上传我用的 hexo,在 _config.yml 文件: deploy: type: git repo: github: https://github.com/tanghaojie/tanghaojie.github.io.git gitee: https://gitee.com/Jackie_Tang/Jackie_Tang.git branch: master 加两个 repo 就好 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"other","slug":"other","permalink":"https://tanghaojie.github.io/categories/other/"}],"tags":[{"name":"other","slug":"other","permalink":"https://tanghaojie.github.io/tags/other/"}],"author":null},{"title":"中华人民共和国省级行政区域界线标注的小tip","slug":"2020-2020-04-01-provincial-boundary","date":"2020-04-01T13:45:29.000Z","updated":"2022-12-23T12:44:16.630Z","comments":true,"path":"2020/04/01/2020-2020-04-01-provincial-boundary/","link":"","permalink":"https://tanghaojie.github.io/2020/04/01/2020-2020-04-01-provincial-boundary/","excerpt":"","text":"如果大段以河道(或其他水体)为省界的,全部以实线标注会影响河流水体的连续呈现时,则用断续线表示。如晋陕、晋豫黄河省界段,川藏、川滇(东段)长江省界段。 说明我本人没有找到这个规定的出处,是否是国家规范不做保证。但是百度地图现在看已经是这样做标注了。 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"GIS","slug":"GIS","permalink":"https://tanghaojie.github.io/categories/GIS/"}],"tags":[{"name":"GIS","slug":"GIS","permalink":"https://tanghaojie.github.io/tags/GIS/"}],"author":null},{"title":"flutter定位插件location","slug":"2020-2020-03-31-flutter-location","date":"2020-03-31T12:31:11.000Z","updated":"2022-12-23T12:44:16.630Z","comments":true,"path":"2020/03/31/2020-2020-03-31-flutter-location/","link":"","permalink":"https://tanghaojie.github.io/2020/03/31/2020-2020-03-31-flutter-location/","excerpt":"","text":"iOS 没测试,Android 需要用到 GMS 来辅助定位,所以国内不能用!不能用!!不能用!!! 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"flutter","slug":"flutter","permalink":"https://tanghaojie.github.io/categories/flutter/"}],"tags":[{"name":"flutter","slug":"flutter","permalink":"https://tanghaojie.github.io/tags/flutter/"}],"author":null},{"title":"flutter加载地图的几种方式对比[测试]","slug":"2020-2020-03-31-flutter-load-map","date":"2020-03-31T12:14:47.000Z","updated":"2022-12-23T12:44:16.630Z","comments":true,"path":"2020/03/31/2020-2020-03-31-flutter-load-map/","link":"","permalink":"https://tanghaojie.github.io/2020/03/31/2020-2020-03-31-flutter-load-map/","excerpt":"","text":"1.flutter_map:Leaflet 用 Flutter 的实现,主要用于加载瓦片地图和简单注记,复杂的几何要素可以用插件的形式,但要自己实现代码。没有自带定位的功能,要自己处理。综合来看,只用瓦片地图,定位这些基础功能的话,可以选这个,团队强大的话,复杂功能也可以自己搞插件。天花板挺高的。 2.webview_flutter:fluter 官方出品的 webview 插件,没什么好说的,网页能干的事他都能干。最大的问题是目前还是预览版,官方说因为用了新的机制,具体什么机制我也没看,能不能实现官方没说,deadline 也没说,有点不让人放心。 3.flutter_webview_plugin:网上综合推荐比较多的一个插件了,就是调用 native webview,稳定性,兼容性肯定没问题。但是由于接入原生,导致 webview 始终在最上层,会覆盖在所有 Flutter widget 之上,灵活性牺牲很大。最新的说明里写了,要把这个插件合并到上面提到的官方插件里面去了。所以基本上不用选了。 4.其他库:比如说高德 amap,百度地图,这类就局限平台了。 目前就测试了这几种地图使用方式,总的来说,有团队,有时间,能自己研发的,可以上。不然的话还是用混合开发吧,flutter 还需要给他些时间来成熟。 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"flutter","slug":"flutter","permalink":"https://tanghaojie.github.io/categories/flutter/"}],"tags":[{"name":"flutter","slug":"flutter","permalink":"https://tanghaojie.github.io/tags/flutter/"}],"author":null},{"title":"Flutter Doctor:Android license status unknown","slug":"2020-2020-03-27-post","date":"2020-03-27T10:22:12.000Z","updated":"2022-12-23T12:44:16.629Z","comments":true,"path":"2020/03/27/2020-2020-03-27-post/","link":"","permalink":"https://tanghaojie.github.io/2020/03/27/2020-2020-03-27-post/","excerpt":"","text":"执行: flutter doctor --android-licenses 之后一路同意就好了。 如果显示: > Android sdkmanager tool not found (PATH) 1.打开 Android SDK Manager 2.选 SDK Tools 3.把下面的,Hide Obsolete Packages,取消勾选 4.打勾 Android SDK Tools (Obsolete) 5.确定安装 Flutter 团队知道这个问题,官方建议就是这么处理,后续版本会解决的。 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"flutter","slug":"flutter","permalink":"https://tanghaojie.github.io/categories/flutter/"}],"tags":[{"name":"flutter","slug":"flutter","permalink":"https://tanghaojie.github.io/tags/flutter/"}],"author":null},{"title":"office2016零售版转VOL版","slug":"2020-2020-03-19-office2016ToVol","date":"2020-03-19T11:06:57.000Z","updated":"2022-12-23T12:44:16.629Z","comments":true,"path":"2020/03/19/2020-2020-03-19-office2016ToVol/","link":"","permalink":"https://tanghaojie.github.io/2020/03/19/2020-2020-03-19-office2016ToVol/","excerpt":"","text":"以下代码复制为:.bat 文件 @ECHO OFF&PUSHD %~DP0 setlocal EnableDelayedExpansion&color 3e & cd /d \"%~dp0\" title office2016 retail转换vol版 %1 %2 mshta vbscript:createobject(\"shell.application\").shellexecute(\"%~s0\",\"goto :runas\",\"\",\"runas\",1)(window.close)&goto :eof :runas if exist \"%ProgramFiles%\\Microsoft Office\\Office16\\ospp.vbs\" cd /d \"%ProgramFiles%\\Microsoft Office\\Office16\" if exist \"%ProgramFiles(x86)%\\Microsoft Office\\Office16\\ospp.vbs\" cd /d \"%ProgramFiles(x86)%\\Microsoft Office\\Office16\" :WH cls echo. echo 选择需要转化的office版本序号 echo. echo -------------------------------------------------------------------------------- echo 1. 零售版 Office Pro Plus 2016 转化为VOL版 echo. echo 2. 零售版 Office Visio Pro 2016 转化为VOL版 echo. echo 3. 零售版 Office Project Pro 2016 转化为VOL版 echo. echo. -------------------------------------------------------------------------------- set /p tsk=\"请输入需要转化的office版本序号【回车】确认(1-3): \" if not defined tsk goto:err if %tsk%==1 goto:1 if %tsk%==2 goto:2 if %tsk%==3 goto:3 :err goto:WH :1 cls echo 正在安装 KMS 许可证... for /f %%x in ('dir /b ..\\root\\Licenses16\\proplusvl_kms*.xrm-ms') do cscript ospp.vbs /inslic:\"..\\root\\Licenses16\\%%x\" >nul echo 正在安装 MAK 许可证... for /f %%x in ('dir /b ..\\root\\Licenses16\\proplusvl_mak*.xrm-ms') do cscript ospp.vbs /inslic:\"..\\root\\Licenses16\\%%x\" >nul set /p y=请输入激活密钥,按回车确定: cscript ospp.vbs /inpkey:%y% goto :e :2 cls echo 正在安装 KMS 许可证... for /f %%x in ('dir /b ..\\root\\Licenses16\\visio???vl_kms*.xrm-ms') do cscript ospp.vbs /inslic:\"..\\root\\Licenses16\\%%x\" >nul echo 正在安装 MAK 许可证... for /f %%x in ('dir /b ..\\root\\Licenses16\\visio???vl_mak*.xrm-ms') do cscript ospp.vbs /inslic:\"..\\root\\Licenses16\\%%x\" >nul set /p y=请输入激活密钥,按回车确定: cscript ospp.vbs /inpkey:%y% goto :e :3 cls echo 正在安装 KMS 许可证... for /f %%x in ('dir /b ..\\root\\Licenses16\\project???vl_kms*.xrm-ms') do cscript ospp.vbs /inslic:\"..\\root\\Licenses16\\%%x\" >nul echo 正在安装 MAK 许可证... for /f %%x in ('dir /b ..\\root\\Licenses16\\project???vl_mak*.xrm-ms') do cscript ospp.vbs /inslic:\"..\\root\\Licenses16\\%%x\" >nul set /p y=请输入激活密钥,按回车确定: cscript ospp.vbs /inpkey:%y% goto :e :e echo. echo 转化完成,按任意键退出! pause >nul exit 让填写秘钥时,输入 XQNVK-8JYDB-WJ9W3-YJ8YR-WFG99 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"other","slug":"other","permalink":"https://tanghaojie.github.io/categories/other/"}],"tags":[{"name":"other","slug":"other","permalink":"https://tanghaojie.github.io/tags/other/"}],"author":null},{"title":"vue use video.js support flash rtmp","slug":"2020-2020-03-12-vueVideo","date":"2020-03-12T13:06:17.000Z","updated":"2022-12-23T12:44:16.629Z","comments":true,"path":"2020/03/12/2020-2020-03-12-vueVideo/","link":"","permalink":"https://tanghaojie.github.io/2020/03/12/2020-2020-03-12-vueVideo/","excerpt":"","text":"在 Vue 中使用 video.js,兼容 flash 视频,研究了一天,简单记录一下。 1.包安装 npm install --save videojs npm install --save videojs-flash //如果需要用flash的话 2.实现 vue-video.vue 文件 <template> <div> <video ref=\"videoPlayer\" class=\"video-js\"></video> </div> </template> <script> import videojs from 'video.js' import 'videojs-flash' // if use flash import SWF_PATH from 'videojs-swf/dist/video-js.swf' // if use flash import 'video.js/dist/video-js.min.css' export default { props: { options: { type: Object, default() { return {} } } }, data() { return { player: null } }, mounted() { this.options.flash = {} // if use flash this.options.flash.swf = SWF_PATH // if use flash this.player = videojs(this.$refs.videoPlayer, this.options) }, beforeDestroy() { if (this.player) { this.player.dispose() } } } </script> 3.使用 <template> <div id=\"app\"> <vue-video :options=\"videoOptions\" /> </div> </template> <script> import vueVideo from './path/to/vue-video.vue' export default { name: 'App', components: { vueVideo }, data() { return { // videoOptions标准参考 https://docs.videojs.com/ videoOptions: { autoplay: true, controls: false, language: 'zh', width: 100, height: 200, sources: [ { src: 'rtmp://*************/live/qq', type: 'rtmp/flv' } ] // techOrder: ['flash'] } } } } </script> rtmp、mp4 已测试没有问题,其他格式就没测试了。需要发布才能进行测试,类似 file://C:/test.html 这种文件形式的是无法使用的 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":"vue","slug":"vue","permalink":"https://tanghaojie.github.io/categories/vue/"}],"tags":[{"name":"vue","slug":"vue","permalink":"https://tanghaojie.github.io/tags/vue/"}],"author":null},{"title":"Postgis和EntityFrameworkCore的关系映射,几何字段映射","slug":"2019-2019-12-12-entityframeworkcorewithpostgis","date":"2019-12-12T13:02:03.000Z","updated":"2022-12-23T12:44:16.628Z","comments":true,"path":"2019/12/12/2019-2019-12-12-entityframeworkcorewithpostgis/","link":"","permalink":"https://tanghaojie.github.io/2019/12/12/2019-2019-12-12-entityframeworkcorewithpostgis/","excerpt":"","text":"这篇文章主要讨论Code First模式,其他模式我不怎么用的,不敢保证 &emsp;&emsp;现在搞开发数据库操作基本上都用 Orm 了吧,但是我们搞 GIS 的,因为涉及到空间几何字段、空间拓扑运算操作的情况,很多时候传统的 Orm 就解决不了了,所以很多时候要么就直接用 odbc 原生 Sql 操作了;或者是业务部分 EF+空间几何 Sql 这么来操作。这两个方案实现起来确实没什么问题,但前者用起来实在麻烦,很多简单的东西就搞复杂了,要么统一封装一下的话就又回到 Orm 的路子上;后者是最灵活的一种方案了,任何需求都可以用这个办法来解决,但问题就是整个软件的框架会显得很混乱,新人来了经常问为啥要这样搞,思维切换起来很麻烦,如果要改需求还涉及到空间几何的话,那只能打一架好了… &emsp;&emsp;之前的 DotnetFramework+Npgsql+EF 是不支持使用 PostGIS 扩展的,官方一直也没明确表态后续规划什么的,直到最近在 github 上看到开发者说以后应该不会支持了,会把重心放到 EF Core 上。因此,想要直接映射几何字段几乎变成了不可能的事情。 网上有用 SharpMap 做映射的解决方案,但是我一直没有测试成功过 > 官方的数据类型映射表里面也写了 System.Data.Spatial.DbGeometry 可以映射到 Geometry 类型。这个能在 CodeFirst 下识别,但生成的字段类型并不是 Geometry,而是 Byte[],我也不知道哪错了,诶 &emsp;&emsp;直到最近我打算把平台切换到.NetCore,然后去研究了一下,整个人就豁然开朗了啊。1.微软官方明确表态实现几何类型的字段。2.Npgsql 的 Core 版本确实在实现 Postgis 的东西,而且进度神速。那么,就用呗~ 依赖很简单,就两个包: 1.Npgsql.EntityFrameworkCore.PostgreSQL 2.Npgsql.EntityFrameworkCore.PostgreSQL.NetTopologySuite 然后是配置,首先数据库里面要启用 Postgis,简单:Create Extension Postgis;EFCore 框架: dbContextOptions.UseNpgsql(connectionString, o => o.UseNetTopologySuite()); //这在哪自己找一下 //这在你的DbContext里面 protected override void OnModelCreating(ModelBuilder builder) { builder.HasPostgresExtension(\"postgis\"); //启用postgis扩展,需要手动写扩展名也是有原因的哦 } 齐活了,就这么简单。使用的话就很简单了: using NetTopologySuite.Geometries; public class TestGeometry{ [Column(TypeName = \"geometry (MultiLineString)\")] //可以指定类型、维度、坐标系 public MultiLineString Geom { get; set; } } 有了这个后续的操作就简单多了: Geom.Area //面积 Geom.AsBinary() //转wkb Geom.AsText() //同ToString(),转wkt ... ... 就不一一列举了,官方文档很全面的。 _ 补充一下其他的坑吧,转 .Net Core 以后,Gdal 会成为一个很大的问题,这个需要好好的评估一下,Gdal 目前还没有官方做 Core 的适配,这个影响挺大的。当然 Gdal 的功能也有相应各个独立的库能替换的,但始终不会像 Gdal 这么得心应手,一定要注意评估这一点!!! _ 版权声明:除非注明,本博文章均为原创,转载请以链接形式标明本文地址。","categories":[{"name":".net core","slug":"net-core","permalink":"https://tanghaojie.github.io/categories/net-core/"},{"name":"GIS","slug":"net-core/GIS","permalink":"https://tanghaojie.github.io/categories/net-core/GIS/"}],"tags":[{"name":"GIS","slug":"GIS","permalink":"https://tanghaojie.github.io/tags/GIS/"},{"name":".net core","slug":"net-core","permalink":"https://tanghaojie.github.io/tags/net-core/"}],"author":null},{"title":"网站收录","slug":"2019-2019-10-12-website","date":"2019-10-12T08:22:48.000Z","updated":"2022-12-23T12:44:16.628Z","comments":true,"path":"2019/10/12/2019-2019-10-12-website/","link":"","permalink":"https://tanghaojie.github.io/2019/10/12/2019-2019-10-12-website/","excerpt":"","text":"Google 探索实验室","categories":[{"name":"website","slug":"website","permalink":"https://tanghaojie.github.io/categories/website/"}],"tags":[{"name":"website","slug":"website","permalink":"https://tanghaojie.github.io/tags/website/"}],"author":null},{"title":"地理信息相关标准","slug":"2019-2019-10-12-gisstandard","date":"2019-10-12T07:58:36.000Z","updated":"2022-12-23T12:44:16.628Z","comments":true,"path":"2019/10/12/2019-2019-10-12-gisstandard/","link":"","permalink":"https://tanghaojie.github.io/2019/10/12/2019-2019-10-12-gisstandard/","excerpt":"","text":"OGC 开放地理空间信息联盟(Open Geospatial Consortium),是一个非盈利的国际标准组织,它制定了数据和服务的一系列标准,GIS 厂商按照这个标准进行开发可保证空间数据的互操作。 Spatial reference 坐标系统收录、查询、上传、教育。 GDal GDAL(Geospatial Data Abstraction Library)是一个在 X/MIT 许可协议下的开源栅格空间数据转换库。它利用抽象数据模型来表达所支持的各种文件格式。它还有一系列命令行工具来进行数据转换和处理。OGR 是 GDAL 项目的一个分支,功能与 GDAL 类似,只不过它提供对矢量数据的支持。 epsg 全球坐标系统","categories":[{"name":"GIS","slug":"GIS","permalink":"https://tanghaojie.github.io/categories/GIS/"}],"tags":[{"name":"GIS","slug":"GIS","permalink":"https://tanghaojie.github.io/tags/GIS/"}],"author":null},{"title":"地理地图数据提供网站","slug":"2019-2019-10-12-gisdatawebsites","date":"2019-10-12T07:51:21.000Z","updated":"2022-12-23T12:44:16.623Z","comments":true,"path":"2019/10/12/2019-2019-10-12-gisdatawebsites/","link":"","permalink":"https://tanghaojie.github.io/2019/10/12/2019-2019-10-12-gisdatawebsites/","excerpt":"","text":"OSGeo 中国 开放地理空间信息科学:技术、数据、知识共享。 spatial hadoop 一个为空间数据设计的 map reduce 框架,有很多超大的数据集提供下载。 全国地理信息资源目录服务 国家基础地理信息中心提供的资源查询和下载服务。","categories":[{"name":"GIS","slug":"GIS","permalink":"https://tanghaojie.github.io/categories/GIS/"},{"name":"data","slug":"GIS/data","permalink":"https://tanghaojie.github.io/categories/GIS/data/"}],"tags":[{"name":"GIS","slug":"GIS","permalink":"https://tanghaojie.github.io/tags/GIS/"},{"name":"data","slug":"data","permalink":"https://tanghaojie.github.io/tags/data/"}],"author":null},{"title":"一些好玩的地理网站","slug":"2019-2019-10-12-gisForFunWebsites","date":"2019-10-12T06:57:09.000Z","updated":"2022-12-23T12:44:16.623Z","comments":true,"path":"2019/10/12/2019-2019-10-12-gisForFunWebsites/","link":"","permalink":"https://tanghaojie.github.io/2019/10/12/2019-2019-10-12-gisForFunWebsites/","excerpt":"","text":"Open Street Map 人人都可编辑的世界地图,一个网上地图协作计划的产物。 Land Lines Google Creative Lab 提交的一个 Chrome Experiments 项目,基于深度学习。 GeoGuessr 这是一个真实的「情景判断游戏」。开局就是随便把玩家落在 Google 街景中的某一处,你可以在街景地图中一路游走,然后根据周遭信息,判断出身处何处。 The WebGL Globe The WebGL Globe 是一个使数据地理可视化的平台。利用这个项目提供的开源代码,我们可以制作属于自己的数据地球。在项目网站上有不少网友提交的实验,根据人口变化、火山活动、各地维基百科篇目等方方面面的数据产生不同的可视化地球。 Ghost Map Ghost Map 收录了各个城市的街道路线,将其隐藏在黑暗中。通过移动鼠标,光亮像细流入川一般流淌到附近街道上,灯火明亮,车水马龙,勾勒出这座城市的建筑与街道规划。当鼠标指针停止移动,万物歇息,一切又沉入黑暗。 SNAZZY MAPS 在线 Google Maps 配图。自带多种风格自由选择,而且都可以自定义。 Pixel Map 在线像素地图生成。 地图慧 在线地图制作,上传自己的数据,可以做热力图、流向图等等各种专题地图。 stamen 地图与制图、数据可视化。 Map Box 在线地图制图。 Map Stack 使设计地图免费,简单,有趣。 CAD Mapper cad su 等格式的模型下载。 发现中国 中国历史地图、古地图。","categories":[{"name":"GIS","slug":"GIS","permalink":"https://tanghaojie.github.io/categories/GIS/"}],"tags":[{"name":"GIS","slug":"GIS","permalink":"https://tanghaojie.github.io/tags/GIS/"}],"author":null}],"categories":[{"name":"3D Tiles","slug":"3D-Tiles","permalink":"https://tanghaojie.github.io/categories/3D-Tiles/"},{"name":"specification","slug":"3D-Tiles/specification","permalink":"https://tanghaojie.github.io/categories/3D-Tiles/specification/"},{"name":"other","slug":"other","permalink":"https://tanghaojie.github.io/categories/other/"},{"name":"glTF","slug":"glTF","permalink":"https://tanghaojie.github.io/categories/glTF/"},{"name":"specification","slug":"glTF/specification","permalink":"https://tanghaojie.github.io/categories/glTF/specification/"},{"name":"vue","slug":"vue","permalink":"https://tanghaojie.github.io/categories/vue/"},{"name":"cesium","slug":"vue/cesium","permalink":"https://tanghaojie.github.io/categories/vue/cesium/"},{"name":"3D Tiles","slug":"vue/cesium/3D-Tiles","permalink":"https://tanghaojie.github.io/categories/vue/cesium/3D-Tiles/"},{"name":"shorthand","slug":"shorthand","permalink":"https://tanghaojie.github.io/categories/shorthand/"},{"name":"GIS","slug":"GIS","permalink":"https://tanghaojie.github.io/categories/GIS/"},{"name":"specification","slug":"specification","permalink":"https://tanghaojie.github.io/categories/specification/"},{"name":"tools","slug":"tools","permalink":"https://tanghaojie.github.io/categories/tools/"},{"name":"QGIS","slug":"QGIS","permalink":"https://tanghaojie.github.io/categories/QGIS/"},{"name":"python","slug":"QGIS/python","permalink":"https://tanghaojie.github.io/categories/QGIS/python/"},{"name":"git","slug":"git","permalink":"https://tanghaojie.github.io/categories/git/"},{"name":"other","slug":"git/other","permalink":"https://tanghaojie.github.io/categories/git/other/"},{"name":"docker","slug":"docker","permalink":"https://tanghaojie.github.io/categories/docker/"},{"name":"cheat sheet","slug":"docker/cheat-sheet","permalink":"https://tanghaojie.github.io/categories/docker/cheat-sheet/"},{"name":"cheat sheet","slug":"git/cheat-sheet","permalink":"https://tanghaojie.github.io/categories/git/cheat-sheet/"},{"name":"scrapy","slug":"scrapy","permalink":"https://tanghaojie.github.io/categories/scrapy/"},{"name":"python","slug":"scrapy/python","permalink":"https://tanghaojie.github.io/categories/scrapy/python/"},{"name":"uniapp","slug":"uniapp","permalink":"https://tanghaojie.github.io/categories/uniapp/"},{"name":"flutter","slug":"flutter","permalink":"https://tanghaojie.github.io/categories/flutter/"},{"name":".net core","slug":"net-core","permalink":"https://tanghaojie.github.io/categories/net-core/"},{"name":"GIS","slug":"net-core/GIS","permalink":"https://tanghaojie.github.io/categories/net-core/GIS/"},{"name":"website","slug":"website","permalink":"https://tanghaojie.github.io/categories/website/"},{"name":"data","slug":"GIS/data","permalink":"https://tanghaojie.github.io/categories/GIS/data/"}],"tags":[{"name":"specification","slug":"specification","permalink":"https://tanghaojie.github.io/tags/specification/"},{"name":"3D Tiles","slug":"3D-Tiles","permalink":"https://tanghaojie.github.io/tags/3D-Tiles/"},{"name":"other","slug":"other","permalink":"https://tanghaojie.github.io/tags/other/"},{"name":"glTF","slug":"glTF","permalink":"https://tanghaojie.github.io/tags/glTF/"},{"name":"vue","slug":"vue","permalink":"https://tanghaojie.github.io/tags/vue/"},{"name":"cesium","slug":"cesium","permalink":"https://tanghaojie.github.io/tags/cesium/"},{"name":"shorthand","slug":"shorthand","permalink":"https://tanghaojie.github.io/tags/shorthand/"},{"name":"GIS","slug":"GIS","permalink":"https://tanghaojie.github.io/tags/GIS/"},{"name":"tools","slug":"tools","permalink":"https://tanghaojie.github.io/tags/tools/"},{"name":"python","slug":"python","permalink":"https://tanghaojie.github.io/tags/python/"},{"name":"QGIS","slug":"QGIS","permalink":"https://tanghaojie.github.io/tags/QGIS/"},{"name":"git","slug":"git","permalink":"https://tanghaojie.github.io/tags/git/"},{"name":"docker","slug":"docker","permalink":"https://tanghaojie.github.io/tags/docker/"},{"name":"cheat sheet","slug":"cheat-sheet","permalink":"https://tanghaojie.github.io/tags/cheat-sheet/"},{"name":"scrapy","slug":"scrapy","permalink":"https://tanghaojie.github.io/tags/scrapy/"},{"name":"uniapp","slug":"uniapp","permalink":"https://tanghaojie.github.io/tags/uniapp/"},{"name":"flutter","slug":"flutter","permalink":"https://tanghaojie.github.io/tags/flutter/"},{"name":".net core","slug":"net-core","permalink":"https://tanghaojie.github.io/tags/net-core/"},{"name":"website","slug":"website","permalink":"https://tanghaojie.github.io/tags/website/"},{"name":"data","slug":"data","permalink":"https://tanghaojie.github.io/tags/data/"}]}