ソースを参照

Merge branch 'master' of http://face3d.4dage.com:7005/4dkankan/4dkankan_bim

bill 2 年 前
コミット
4ad8b1506c

+ 1 - 1
public/smart-bim.html

@@ -28,6 +28,6 @@
             <strong>We're sorry but doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
         </noscript>
         <div id="app"></div>
-        <script src="https://static.bimface.com/api/BimfaceSDKLoader/BimfaceSDKLoader@latest-release.js"></script>
+        <script src="https://4dkk.4dage.com/bim/jssdk/BimfaceSDKLoader@latest-release.js"></script>
     </body>
 </html>

+ 2 - 1
public/smart-laser-bim.html

@@ -4,7 +4,8 @@
         <title>BIM</title>
         <meta charset="utf-8" />
         <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0" />
-        <link rel="stylesheet" href="<%= BASE_URL %><%= VUE_APP_STATIC_DIR %>/lib/iconfont/iconfont.css" />
+        <link rel="stylesheet" href="<%= VUE_APP_STATIC_DIR %>/lib/iconfont/iconfont.css" />
+        <script src="<%= VUE_APP_STATIC_DIR %>/lib/three.js/build/three.min.js"></script>
     </head>
     <body>
         <noscript>

+ 539 - 0
public/static/lib/iconfont/demo.css

@@ -0,0 +1,539 @@
+/* Logo 字体 */
+@font-face {
+  font-family: "iconfont logo";
+  src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
+  src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
+}
+
+.logo {
+  font-family: "iconfont logo";
+  font-size: 160px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+/* tabs */
+.nav-tabs {
+  position: relative;
+}
+
+.nav-tabs .nav-more {
+  position: absolute;
+  right: 0;
+  bottom: 0;
+  height: 42px;
+  line-height: 42px;
+  color: #666;
+}
+
+#tabs {
+  border-bottom: 1px solid #eee;
+}
+
+#tabs li {
+  cursor: pointer;
+  width: 100px;
+  height: 40px;
+  line-height: 40px;
+  text-align: center;
+  font-size: 16px;
+  border-bottom: 2px solid transparent;
+  position: relative;
+  z-index: 1;
+  margin-bottom: -1px;
+  color: #666;
+}
+
+
+#tabs .active {
+  border-bottom-color: #f00;
+  color: #222;
+}
+
+.tab-container .content {
+  display: none;
+}
+
+/* 页面布局 */
+.main {
+  padding: 30px 100px;
+  width: 960px;
+  margin: 0 auto;
+}
+
+.main .logo {
+  color: #333;
+  text-align: left;
+  margin-bottom: 30px;
+  line-height: 1;
+  height: 110px;
+  margin-top: -50px;
+  overflow: hidden;
+  *zoom: 1;
+}
+
+.main .logo a {
+  font-size: 160px;
+  color: #333;
+}
+
+.helps {
+  margin-top: 40px;
+}
+
+.helps pre {
+  padding: 20px;
+  margin: 10px 0;
+  border: solid 1px #e7e1cd;
+  background-color: #fffdef;
+  overflow: auto;
+}
+
+.icon_lists {
+  width: 100% !important;
+  overflow: hidden;
+  *zoom: 1;
+}
+
+.icon_lists li {
+  width: 100px;
+  margin-bottom: 10px;
+  margin-right: 20px;
+  text-align: center;
+  list-style: none !important;
+  cursor: default;
+}
+
+.icon_lists li .code-name {
+  line-height: 1.2;
+}
+
+.icon_lists .icon {
+  display: block;
+  height: 100px;
+  line-height: 100px;
+  font-size: 42px;
+  margin: 10px auto;
+  color: #333;
+  -webkit-transition: font-size 0.25s linear, width 0.25s linear;
+  -moz-transition: font-size 0.25s linear, width 0.25s linear;
+  transition: font-size 0.25s linear, width 0.25s linear;
+}
+
+.icon_lists .icon:hover {
+  font-size: 100px;
+}
+
+.icon_lists .svg-icon {
+  /* 通过设置 font-size 来改变图标大小 */
+  width: 1em;
+  /* 图标和文字相邻时,垂直对齐 */
+  vertical-align: -0.15em;
+  /* 通过设置 color 来改变 SVG 的颜色/fill */
+  fill: currentColor;
+  /* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
+      normalize.css 中也包含这行 */
+  overflow: hidden;
+}
+
+.icon_lists li .name,
+.icon_lists li .code-name {
+  color: #666;
+}
+
+/* markdown 样式 */
+.markdown {
+  color: #666;
+  font-size: 14px;
+  line-height: 1.8;
+}
+
+.highlight {
+  line-height: 1.5;
+}
+
+.markdown img {
+  vertical-align: middle;
+  max-width: 100%;
+}
+
+.markdown h1 {
+  color: #404040;
+  font-weight: 500;
+  line-height: 40px;
+  margin-bottom: 24px;
+}
+
+.markdown h2,
+.markdown h3,
+.markdown h4,
+.markdown h5,
+.markdown h6 {
+  color: #404040;
+  margin: 1.6em 0 0.6em 0;
+  font-weight: 500;
+  clear: both;
+}
+
+.markdown h1 {
+  font-size: 28px;
+}
+
+.markdown h2 {
+  font-size: 22px;
+}
+
+.markdown h3 {
+  font-size: 16px;
+}
+
+.markdown h4 {
+  font-size: 14px;
+}
+
+.markdown h5 {
+  font-size: 12px;
+}
+
+.markdown h6 {
+  font-size: 12px;
+}
+
+.markdown hr {
+  height: 1px;
+  border: 0;
+  background: #e9e9e9;
+  margin: 16px 0;
+  clear: both;
+}
+
+.markdown p {
+  margin: 1em 0;
+}
+
+.markdown>p,
+.markdown>blockquote,
+.markdown>.highlight,
+.markdown>ol,
+.markdown>ul {
+  width: 80%;
+}
+
+.markdown ul>li {
+  list-style: circle;
+}
+
+.markdown>ul li,
+.markdown blockquote ul>li {
+  margin-left: 20px;
+  padding-left: 4px;
+}
+
+.markdown>ul li p,
+.markdown>ol li p {
+  margin: 0.6em 0;
+}
+
+.markdown ol>li {
+  list-style: decimal;
+}
+
+.markdown>ol li,
+.markdown blockquote ol>li {
+  margin-left: 20px;
+  padding-left: 4px;
+}
+
+.markdown code {
+  margin: 0 3px;
+  padding: 0 5px;
+  background: #eee;
+  border-radius: 3px;
+}
+
+.markdown strong,
+.markdown b {
+  font-weight: 600;
+}
+
+.markdown>table {
+  border-collapse: collapse;
+  border-spacing: 0px;
+  empty-cells: show;
+  border: 1px solid #e9e9e9;
+  width: 95%;
+  margin-bottom: 24px;
+}
+
+.markdown>table th {
+  white-space: nowrap;
+  color: #333;
+  font-weight: 600;
+}
+
+.markdown>table th,
+.markdown>table td {
+  border: 1px solid #e9e9e9;
+  padding: 8px 16px;
+  text-align: left;
+}
+
+.markdown>table th {
+  background: #F7F7F7;
+}
+
+.markdown blockquote {
+  font-size: 90%;
+  color: #999;
+  border-left: 4px solid #e9e9e9;
+  padding-left: 0.8em;
+  margin: 1em 0;
+}
+
+.markdown blockquote p {
+  margin: 0;
+}
+
+.markdown .anchor {
+  opacity: 0;
+  transition: opacity 0.3s ease;
+  margin-left: 8px;
+}
+
+.markdown .waiting {
+  color: #ccc;
+}
+
+.markdown h1:hover .anchor,
+.markdown h2:hover .anchor,
+.markdown h3:hover .anchor,
+.markdown h4:hover .anchor,
+.markdown h5:hover .anchor,
+.markdown h6:hover .anchor {
+  opacity: 1;
+  display: inline-block;
+}
+
+.markdown>br,
+.markdown>p>br {
+  clear: both;
+}
+
+
+.hljs {
+  display: block;
+  background: white;
+  padding: 0.5em;
+  color: #333333;
+  overflow-x: auto;
+}
+
+.hljs-comment,
+.hljs-meta {
+  color: #969896;
+}
+
+.hljs-string,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-strong,
+.hljs-emphasis,
+.hljs-quote {
+  color: #df5000;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-type {
+  color: #a71d5d;
+}
+
+.hljs-literal,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-attribute {
+  color: #0086b3;
+}
+
+.hljs-section,
+.hljs-name {
+  color: #63a35c;
+}
+
+.hljs-tag {
+  color: #333333;
+}
+
+.hljs-title,
+.hljs-attr,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-selector-attr,
+.hljs-selector-pseudo {
+  color: #795da3;
+}
+
+.hljs-addition {
+  color: #55a532;
+  background-color: #eaffea;
+}
+
+.hljs-deletion {
+  color: #bd2c00;
+  background-color: #ffecec;
+}
+
+.hljs-link {
+  text-decoration: underline;
+}
+
+/* 代码高亮 */
+/* PrismJS 1.15.0
+https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
+/**
+ * prism.js default theme for JavaScript, CSS and HTML
+ * Based on dabblet (http://dabblet.com)
+ * @author Lea Verou
+ */
+code[class*="language-"],
+pre[class*="language-"] {
+  color: black;
+  background: none;
+  text-shadow: 0 1px white;
+  font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
+  text-align: left;
+  white-space: pre;
+  word-spacing: normal;
+  word-break: normal;
+  word-wrap: normal;
+  line-height: 1.5;
+
+  -moz-tab-size: 4;
+  -o-tab-size: 4;
+  tab-size: 4;
+
+  -webkit-hyphens: none;
+  -moz-hyphens: none;
+  -ms-hyphens: none;
+  hyphens: none;
+}
+
+pre[class*="language-"]::-moz-selection,
+pre[class*="language-"] ::-moz-selection,
+code[class*="language-"]::-moz-selection,
+code[class*="language-"] ::-moz-selection {
+  text-shadow: none;
+  background: #b3d4fc;
+}
+
+pre[class*="language-"]::selection,
+pre[class*="language-"] ::selection,
+code[class*="language-"]::selection,
+code[class*="language-"] ::selection {
+  text-shadow: none;
+  background: #b3d4fc;
+}
+
+@media print {
+
+  code[class*="language-"],
+  pre[class*="language-"] {
+    text-shadow: none;
+  }
+}
+
+/* Code blocks */
+pre[class*="language-"] {
+  padding: 1em;
+  margin: .5em 0;
+  overflow: auto;
+}
+
+:not(pre)>code[class*="language-"],
+pre[class*="language-"] {
+  background: #f5f2f0;
+}
+
+/* Inline code */
+:not(pre)>code[class*="language-"] {
+  padding: .1em;
+  border-radius: .3em;
+  white-space: normal;
+}
+
+.token.comment,
+.token.prolog,
+.token.doctype,
+.token.cdata {
+  color: slategray;
+}
+
+.token.punctuation {
+  color: #999;
+}
+
+.namespace {
+  opacity: .7;
+}
+
+.token.property,
+.token.tag,
+.token.boolean,
+.token.number,
+.token.constant,
+.token.symbol,
+.token.deleted {
+  color: #905;
+}
+
+.token.selector,
+.token.attr-name,
+.token.string,
+.token.char,
+.token.builtin,
+.token.inserted {
+  color: #690;
+}
+
+.token.operator,
+.token.entity,
+.token.url,
+.language-css .token.string,
+.style .token.string {
+  color: #9a6e3a;
+  background: hsla(0, 0%, 100%, .5);
+}
+
+.token.atrule,
+.token.attr-value,
+.token.keyword {
+  color: #07a;
+}
+
+.token.function,
+.token.class-name {
+  color: #DD4A68;
+}
+
+.token.regex,
+.token.important,
+.token.variable {
+  color: #e90;
+}
+
+.token.important,
+.token.bold {
+  font-weight: bold;
+}
+
+.token.italic {
+  font-style: italic;
+}
+
+.token.entity {
+  cursor: help;
+}

ファイルの差分が大きいため隠しています
+ 3385 - 0
public/static/lib/iconfont/demo_index.html


+ 571 - 0
public/static/lib/iconfont/iconfont.css

@@ -0,0 +1,571 @@
+@font-face {
+  font-family: "iconfont"; /* Project id 2596172 */
+  src: url('iconfont.woff2?t=1659061669448') format('woff2'),
+       url('iconfont.woff?t=1659061669448') format('woff'),
+       url('iconfont.ttf?t=1659061669448') format('truetype');
+}
+
+.iconfont {
+  font-family: "iconfont" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+.icon-show_share:before {
+  content: "\e690";
+}
+
+.icon-show_more_ruler:before {
+  content: "\e67b";
+}
+
+.icon-transparency:before {
+  content: "\e6d7";
+}
+
+.icon-mosaic_e:before {
+  content: "\e6d2";
+}
+
+.icon-eraser:before {
+  content: "\e6d3";
+}
+
+.icon-video2:before {
+  content: "\e6d4";
+}
+
+.icon-down:before {
+  content: "\e6d5";
+}
+
+.icon-qingkong-copy-copy:before {
+  content: "\e68f";
+}
+
+.icon-_qq:before {
+  content: "\e64b";
+}
+
+.icon-_friend:before {
+  content: "\e64c";
+}
+
+.icon-link1:before {
+  content: "\e6ff";
+}
+
+.icon-icon_share_facebook:before {
+  content: "\e745";
+}
+
+.icon-icon_share_whatsapp:before {
+  content: "\e746";
+}
+
+.icon-_wechat:before {
+  content: "\e64a";
+}
+
+.icon-watermark:before {
+  content: "\e6cb";
+}
+
+.icon-camera_h:before {
+  content: "\e6c7";
+}
+
+.icon-a-1V1:before {
+  content: "\e6c8";
+}
+
+.icon-hengbiaoEN:before {
+  content: "\e6b9";
+}
+
+.icon-hot_spot:before {
+  content: "\e6b8";
+}
+
+.icon-foot:before {
+  content: "\e6ba";
+}
+
+.icon-music-t:before {
+  content: "\e6b7";
+}
+
+.icon-yes:before {
+  content: "\e6b5";
+}
+
+.icon-no:before {
+  content: "\e6b6";
+}
+
+.icon-floor_rename:before {
+  content: "\e75b";
+}
+
+.icon-play_stop:before {
+  content: "\e6b4";
+}
+
+.icon-scene_auto:before {
+  content: "\e721";
+}
+
+.icon-compass:before {
+  content: "\e6b3";
+}
+
+.icon-h-d:before {
+  content: "\e6b2";
+}
+
+.icon-scene_screen:before {
+  content: "\e717";
+}
+
+.icon-scene_full:before {
+  content: "\e712";
+}
+
+.icon-scene_window:before {
+  content: "\e713";
+}
+
+.icon-_back:before {
+  content: "\e609";
+}
+
+.icon-show_back:before {
+  content: "\e678";
+}
+
+.icon-show_more_share:before {
+  content: "\e680";
+}
+
+.icon-show_more_finish:before {
+  content: "\e67a";
+}
+
+.icon-show_more_music:before {
+  content: "\e67c";
+}
+
+.icon-show_map_collect:before {
+  content: "\e679";
+}
+
+.icon-data-j:before {
+  content: "\e6b1";
+}
+
+.icon-cancel:before {
+  content: "\e688";
+}
+
+.icon-affirm:before {
+  content: "\e689";
+}
+
+.icon-checkbox_p:before {
+  content: "\e6b0";
+}
+
+.icon-left:before {
+  content: "\e6ae";
+}
+
+.icon-right:before {
+  content: "\e6af";
+}
+
+.icon-_loading_:before {
+  content: "\e627";
+}
+
+.icon-show_function_collect:before {
+  content: "\e687";
+}
+
+.icon-show_more:before {
+  content: "\e67e";
+}
+
+.icon-d-r:before {
+  content: "\e68d";
+}
+
+.icon-up-a:before {
+  content: "\e68e";
+}
+
+.icon-fanzhuan:before {
+  content: "\e6fa";
+}
+
+.icon-cad-neiqiang:before {
+  content: "\e698";
+}
+
+.icon-cad-waiqiang:before {
+  content: "\e69a";
+}
+
+.icon-cad-shuangkaimen:before {
+  content: "\e69b";
+}
+
+.icon-cad-zimumen:before {
+  content: "\e69c";
+}
+
+.icon-cad-men:before {
+  content: "\e69d";
+}
+
+.icon-cad-yimen:before {
+  content: "\e69e";
+}
+
+.icon-cad-zhediemen:before {
+  content: "\e69f";
+}
+
+.icon-cad-luodichuang:before {
+  content: "\e6a0";
+}
+
+.icon-cad-chuang:before {
+  content: "\e6a1";
+}
+
+.icon-cad-piaochuang:before {
+  content: "\e6a2";
+}
+
+.icon-cad-uxingchuang:before {
+  content: "\e6a4";
+}
+
+.icon-cad-lxingchuang:before {
+  content: "\e6a5";
+}
+
+.icon-cad-lpiaochuang:before {
+  content: "\e6a6";
+}
+
+.icon-cad-upiaochuang:before {
+  content: "\e6a7";
+}
+
+.icon-cad-liang:before {
+  content: "\e6a8";
+}
+
+.icon-cad-yandao:before {
+  content: "\e6a9";
+}
+
+.icon-cad-zhuzi:before {
+  content: "\e6aa";
+}
+
+.icon-cad-dianti:before {
+  content: "\e6ab";
+}
+
+.icon-cad-loudao:before {
+  content: "\e6ac";
+}
+
+.icon-cad-dange:before {
+  content: "\e6ad";
+}
+
+.icon-cad-yakou:before {
+  content: "\e699";
+}
+
+.icon-more:before {
+  content: "\e600";
+}
+
+.icon-mosaic1:before {
+  content: "\e697";
+}
+
+.icon-hengbiaoCN:before {
+  content: "\e6a3";
+}
+
+.icon-nor:before {
+  content: "\e696";
+}
+
+.icon-checkbox1:before {
+  content: "\e65d";
+}
+
+.icon-rotate:before {
+  content: "\e695";
+}
+
+.icon-adapt:before {
+  content: "\e692";
+}
+
+.icon-recover:before {
+  content: "\e693";
+}
+
+.icon-repeal:before {
+  content: "\e694";
+}
+
+.icon-reset:before {
+  content: "\e65a";
+}
+
+.icon-course1:before {
+  content: "\e68c";
+}
+
+.icon-publish:before {
+  content: "\e68a";
+}
+
+.icon-save:before {
+  content: "\e68b";
+}
+
+.icon-checkbox:before {
+  content: "\e649";
+}
+
+.icon-mosaic:before {
+  content: "\e646";
+}
+
+.icon-media:before {
+  content: "\e647";
+}
+
+.icon-pic:before {
+  content: "\e648";
+}
+
+.icon-eye_f:before {
+  content: "\e644";
+}
+
+.icon-eye_c:before {
+  content: "\e645";
+}
+
+.icon-size-o:before {
+  content: "\e640";
+}
+
+.icon-size-f:before {
+  content: "\e641";
+}
+
+.icon-magnify:before {
+  content: "\e642";
+}
+
+.icon-reduce:before {
+  content: "\e643";
+}
+
+.icon-video1:before {
+  content: "\e63b";
+}
+
+.icon-uploading_s:before {
+  content: "\e63c";
+}
+
+.icon-path:before {
+  content: "\e63d";
+}
+
+.icon-record:before {
+  content: "\e63e";
+}
+
+.icon-clear:before {
+  content: "\e63f";
+}
+
+.icon-pause:before {
+  content: "\e636";
+}
+
+.icon-preview:before {
+  content: "\e63a";
+}
+
+.icon-full:before {
+  content: "\e638";
+}
+
+.icon-add:before {
+  content: "\e631";
+}
+
+.icon-del:before {
+  content: "\e632";
+}
+
+.icon-close:before {
+  content: "\e633";
+}
+
+.icon-web:before {
+  content: "\e635";
+}
+
+.icon-music:before {
+  content: "\e637";
+}
+
+.icon-uploading1:before {
+  content: "\e639";
+}
+
+.icon-state_e:before {
+  content: "\e624";
+}
+
+.icon-state_f:before {
+  content: "\e625";
+}
+
+.icon-state_s:before {
+  content: "\e626";
+}
+
+.icon-vip_uploading:before {
+  content: "\e623";
+}
+
+.icon-eye-n:before {
+  content: "\e621";
+}
+
+.icon-eye-s:before {
+  content: "\e622";
+}
+
+.icon-course:before {
+  content: "\e620";
+}
+
+.icon-edit:before {
+  content: "\e61f";
+}
+
+.icon-help:before {
+  content: "\e615";
+}
+
+.icon-rule:before {
+  content: "\e617";
+}
+
+.icon-link:before {
+  content: "\e618";
+}
+
+.icon-uploading:before {
+  content: "\e619";
+}
+
+.icon-vr:before {
+  content: "\e61a";
+}
+
+.icon-complete:before {
+  content: "\e61b";
+}
+
+.icon-download:before {
+  content: "\e61c";
+}
+
+.icon-pull-down:before {
+  content: "\e61d";
+}
+
+.icon-pull-up:before {
+  content: "\e61e";
+}
+
+.icon-updown:before {
+  content: "\e613";
+}
+
+.icon-scene:before {
+  content: "\e614";
+}
+
+.icon-message:before {
+  content: "\e60c";
+}
+
+.icon-basic:before {
+  content: "\e60d";
+}
+
+.icon-hotspot:before {
+  content: "\e60e";
+}
+
+.icon-guide:before {
+  content: "\e60f";
+}
+
+.icon-wander:before {
+  content: "\e610";
+}
+
+.icon-house:before {
+  content: "\e611";
+}
+
+.icon-video:before {
+  content: "\e612";
+}
+
+.icon-show_3d_normal:before {
+  content: "\e677";
+}
+
+.icon-show_plane_normal:before {
+  content: "\e67d";
+}
+
+.icon-show_roaming_selected:before {
+  content: "\e682";
+}
+
+.icon-show_plane_selected:before {
+  content: "\e684";
+}
+
+.icon-show_3d_selected:before {
+  content: "\e685";
+}
+
+.icon-show_roaming_normal:before {
+  content: "\e686";
+}
+

ファイルの差分が大きいため隠しています
+ 1 - 0
public/static/lib/iconfont/iconfont.js


+ 982 - 0
public/static/lib/iconfont/iconfont.json

@@ -0,0 +1,982 @@
+{
+  "id": "2596172",
+  "name": "四维看看编辑器V4",
+  "font_family": "iconfont",
+  "css_prefix_text": "icon-",
+  "description": "四维看看编辑器设计优化",
+  "glyphs": [
+    {
+      "icon_id": "20600368",
+      "name": "show_share",
+      "font_class": "show_share",
+      "unicode": "e690",
+      "unicode_decimal": 59024
+    },
+    {
+      "icon_id": "19543928",
+      "name": "show_more_ruler",
+      "font_class": "show_more_ruler",
+      "unicode": "e67b",
+      "unicode_decimal": 59003
+    },
+    {
+      "icon_id": "30499411",
+      "name": "transparency",
+      "font_class": "transparency",
+      "unicode": "e6d7",
+      "unicode_decimal": 59095
+    },
+    {
+      "icon_id": "30490892",
+      "name": "mosaic_e",
+      "font_class": "mosaic_e",
+      "unicode": "e6d2",
+      "unicode_decimal": 59090
+    },
+    {
+      "icon_id": "30490893",
+      "name": "eraser",
+      "font_class": "eraser",
+      "unicode": "e6d3",
+      "unicode_decimal": 59091
+    },
+    {
+      "icon_id": "30490894",
+      "name": "video",
+      "font_class": "video2",
+      "unicode": "e6d4",
+      "unicode_decimal": 59092
+    },
+    {
+      "icon_id": "30490946",
+      "name": "down",
+      "font_class": "down",
+      "unicode": "e6d5",
+      "unicode_decimal": 59093
+    },
+    {
+      "icon_id": "3141534",
+      "name": "清空",
+      "font_class": "qingkong-copy-copy",
+      "unicode": "e68f",
+      "unicode_decimal": 59023
+    },
+    {
+      "icon_id": "7878582",
+      "name": "QQ",
+      "font_class": "_qq",
+      "unicode": "e64b",
+      "unicode_decimal": 58955
+    },
+    {
+      "icon_id": "7878584",
+      "name": "朋友",
+      "font_class": "_friend",
+      "unicode": "e64c",
+      "unicode_decimal": 58956
+    },
+    {
+      "icon_id": "14887802",
+      "name": "link",
+      "font_class": "link1",
+      "unicode": "e6ff",
+      "unicode_decimal": 59135
+    },
+    {
+      "icon_id": "26296900",
+      "name": "icon_share_facebook",
+      "font_class": "icon_share_facebook",
+      "unicode": "e745",
+      "unicode_decimal": 59205
+    },
+    {
+      "icon_id": "26296901",
+      "name": "icon_share_whatsapp",
+      "font_class": "icon_share_whatsapp",
+      "unicode": "e746",
+      "unicode_decimal": 59206
+    },
+    {
+      "icon_id": "7878583",
+      "name": "微信",
+      "font_class": "_wechat",
+      "unicode": "e64a",
+      "unicode_decimal": 58954
+    },
+    {
+      "icon_id": "30230568",
+      "name": "watermark",
+      "font_class": "watermark",
+      "unicode": "e6cb",
+      "unicode_decimal": 59083
+    },
+    {
+      "icon_id": "30230353",
+      "name": "camera_h",
+      "font_class": "camera_h",
+      "unicode": "e6c7",
+      "unicode_decimal": 59079
+    },
+    {
+      "icon_id": "30230374",
+      "name": "1V1",
+      "font_class": "a-1V1",
+      "unicode": "e6c8",
+      "unicode_decimal": 59080
+    },
+    {
+      "icon_id": "12324810",
+      "name": "横标EN",
+      "font_class": "hengbiaoEN",
+      "unicode": "e6b9",
+      "unicode_decimal": 59065
+    },
+    {
+      "icon_id": "22788718",
+      "name": "hot_spot",
+      "font_class": "hot_spot",
+      "unicode": "e6b8",
+      "unicode_decimal": 59064
+    },
+    {
+      "icon_id": "29982018",
+      "name": "foot",
+      "font_class": "foot",
+      "unicode": "e6ba",
+      "unicode_decimal": 59066
+    },
+    {
+      "icon_id": "29365471",
+      "name": "music-t",
+      "font_class": "music-t",
+      "unicode": "e6b7",
+      "unicode_decimal": 59063
+    },
+    {
+      "icon_id": "29346730",
+      "name": "yes",
+      "font_class": "yes",
+      "unicode": "e6b5",
+      "unicode_decimal": 59061
+    },
+    {
+      "icon_id": "29346731",
+      "name": "no",
+      "font_class": "no",
+      "unicode": "e6b6",
+      "unicode_decimal": 59062
+    },
+    {
+      "icon_id": "20764383",
+      "name": "floor_rename",
+      "font_class": "floor_rename",
+      "unicode": "e75b",
+      "unicode_decimal": 59227
+    },
+    {
+      "icon_id": "29255507",
+      "name": "play_stop",
+      "font_class": "play_stop",
+      "unicode": "e6b4",
+      "unicode_decimal": 59060
+    },
+    {
+      "icon_id": "16303117",
+      "name": "scene_auto",
+      "font_class": "scene_auto",
+      "unicode": "e721",
+      "unicode_decimal": 59169
+    },
+    {
+      "icon_id": "28895680",
+      "name": "compass",
+      "font_class": "compass",
+      "unicode": "e6b3",
+      "unicode_decimal": 59059
+    },
+    {
+      "icon_id": "28351771",
+      "name": "h-d",
+      "font_class": "h-d",
+      "unicode": "e6b2",
+      "unicode_decimal": 59058
+    },
+    {
+      "icon_id": "16270567",
+      "name": "scene_screen",
+      "font_class": "scene_screen",
+      "unicode": "e717",
+      "unicode_decimal": 59159
+    },
+    {
+      "icon_id": "15936377",
+      "name": "scene_full",
+      "font_class": "scene_full",
+      "unicode": "e712",
+      "unicode_decimal": 59154
+    },
+    {
+      "icon_id": "15936378",
+      "name": "scene_window",
+      "font_class": "scene_window",
+      "unicode": "e713",
+      "unicode_decimal": 59155
+    },
+    {
+      "icon_id": "7857935",
+      "name": "返回",
+      "font_class": "_back",
+      "unicode": "e609",
+      "unicode_decimal": 58889
+    },
+    {
+      "icon_id": "20066553",
+      "name": "show_back",
+      "font_class": "show_back",
+      "unicode": "e678",
+      "unicode_decimal": 59000
+    },
+    {
+      "icon_id": "20066555",
+      "name": "show_more_share",
+      "font_class": "show_more_share",
+      "unicode": "e680",
+      "unicode_decimal": 59008
+    },
+    {
+      "icon_id": "19543927",
+      "name": "show_more_finish",
+      "font_class": "show_more_finish",
+      "unicode": "e67a",
+      "unicode_decimal": 59002
+    },
+    {
+      "icon_id": "19543929",
+      "name": "show_more_music",
+      "font_class": "show_more_music",
+      "unicode": "e67c",
+      "unicode_decimal": 59004
+    },
+    {
+      "icon_id": "19543926",
+      "name": "show_map_collect",
+      "font_class": "show_map_collect",
+      "unicode": "e679",
+      "unicode_decimal": 59001
+    },
+    {
+      "icon_id": "27985200",
+      "name": "data-j",
+      "font_class": "data-j",
+      "unicode": "e6b1",
+      "unicode_decimal": 59057
+    },
+    {
+      "icon_id": "26690641",
+      "name": "cancel",
+      "font_class": "cancel",
+      "unicode": "e688",
+      "unicode_decimal": 59016
+    },
+    {
+      "icon_id": "26690677",
+      "name": "affirm",
+      "font_class": "affirm",
+      "unicode": "e689",
+      "unicode_decimal": 59017
+    },
+    {
+      "icon_id": "27896904",
+      "name": "checkbox_p",
+      "font_class": "checkbox_p",
+      "unicode": "e6b0",
+      "unicode_decimal": 59056
+    },
+    {
+      "icon_id": "27765016",
+      "name": "left",
+      "font_class": "left",
+      "unicode": "e6ae",
+      "unicode_decimal": 59054
+    },
+    {
+      "icon_id": "27765017",
+      "name": "right",
+      "font_class": "right",
+      "unicode": "e6af",
+      "unicode_decimal": 59055
+    },
+    {
+      "icon_id": "7858065",
+      "name": "loading",
+      "font_class": "_loading_",
+      "unicode": "e627",
+      "unicode_decimal": 58919
+    },
+    {
+      "icon_id": "20066572",
+      "name": "show_function_collect",
+      "font_class": "show_function_collect",
+      "unicode": "e687",
+      "unicode_decimal": 59015
+    },
+    {
+      "icon_id": "19543931",
+      "name": "show_more",
+      "font_class": "show_more",
+      "unicode": "e67e",
+      "unicode_decimal": 59006
+    },
+    {
+      "icon_id": "26914809",
+      "name": "d-r",
+      "font_class": "d-r",
+      "unicode": "e68d",
+      "unicode_decimal": 59021
+    },
+    {
+      "icon_id": "26914810",
+      "name": "up-a",
+      "font_class": "up-a",
+      "unicode": "e68e",
+      "unicode_decimal": 59022
+    },
+    {
+      "icon_id": "14510564",
+      "name": "edit_mirror",
+      "font_class": "fanzhuan",
+      "unicode": "e6fa",
+      "unicode_decimal": 59130
+    },
+    {
+      "icon_id": "27294582",
+      "name": "neiqiang",
+      "font_class": "cad-neiqiang",
+      "unicode": "e698",
+      "unicode_decimal": 59032
+    },
+    {
+      "icon_id": "27294583",
+      "name": "waiqiang",
+      "font_class": "cad-waiqiang",
+      "unicode": "e69a",
+      "unicode_decimal": 59034
+    },
+    {
+      "icon_id": "27294616",
+      "name": "shuangkaimen",
+      "font_class": "cad-shuangkaimen",
+      "unicode": "e69b",
+      "unicode_decimal": 59035
+    },
+    {
+      "icon_id": "27294617",
+      "name": "zimumen",
+      "font_class": "cad-zimumen",
+      "unicode": "e69c",
+      "unicode_decimal": 59036
+    },
+    {
+      "icon_id": "27294618",
+      "name": "men",
+      "font_class": "cad-men",
+      "unicode": "e69d",
+      "unicode_decimal": 59037
+    },
+    {
+      "icon_id": "27294620",
+      "name": "yimen",
+      "font_class": "cad-yimen",
+      "unicode": "e69e",
+      "unicode_decimal": 59038
+    },
+    {
+      "icon_id": "27294621",
+      "name": "zhediemen",
+      "font_class": "cad-zhediemen",
+      "unicode": "e69f",
+      "unicode_decimal": 59039
+    },
+    {
+      "icon_id": "27294699",
+      "name": "luodichuang",
+      "font_class": "cad-luodichuang",
+      "unicode": "e6a0",
+      "unicode_decimal": 59040
+    },
+    {
+      "icon_id": "27294700",
+      "name": "chuang",
+      "font_class": "cad-chuang",
+      "unicode": "e6a1",
+      "unicode_decimal": 59041
+    },
+    {
+      "icon_id": "27294701",
+      "name": "piaochuang",
+      "font_class": "cad-piaochuang",
+      "unicode": "e6a2",
+      "unicode_decimal": 59042
+    },
+    {
+      "icon_id": "27294702",
+      "name": "uxingchuang",
+      "font_class": "cad-uxingchuang",
+      "unicode": "e6a4",
+      "unicode_decimal": 59044
+    },
+    {
+      "icon_id": "27294703",
+      "name": "lxingchuang",
+      "font_class": "cad-lxingchuang",
+      "unicode": "e6a5",
+      "unicode_decimal": 59045
+    },
+    {
+      "icon_id": "27294704",
+      "name": "lpiaochuang",
+      "font_class": "cad-lpiaochuang",
+      "unicode": "e6a6",
+      "unicode_decimal": 59046
+    },
+    {
+      "icon_id": "27294705",
+      "name": "upiaochuang",
+      "font_class": "cad-upiaochuang",
+      "unicode": "e6a7",
+      "unicode_decimal": 59047
+    },
+    {
+      "icon_id": "27294743",
+      "name": "liang",
+      "font_class": "cad-liang",
+      "unicode": "e6a8",
+      "unicode_decimal": 59048
+    },
+    {
+      "icon_id": "27294744",
+      "name": "yandao",
+      "font_class": "cad-yandao",
+      "unicode": "e6a9",
+      "unicode_decimal": 59049
+    },
+    {
+      "icon_id": "27294745",
+      "name": "zhuzi",
+      "font_class": "cad-zhuzi",
+      "unicode": "e6aa",
+      "unicode_decimal": 59050
+    },
+    {
+      "icon_id": "27294746",
+      "name": "dianti",
+      "font_class": "cad-dianti",
+      "unicode": "e6ab",
+      "unicode_decimal": 59051
+    },
+    {
+      "icon_id": "27294747",
+      "name": "loudao",
+      "font_class": "cad-loudao",
+      "unicode": "e6ac",
+      "unicode_decimal": 59052
+    },
+    {
+      "icon_id": "27297593",
+      "name": "dange",
+      "font_class": "cad-dange",
+      "unicode": "e6ad",
+      "unicode_decimal": 59053
+    },
+    {
+      "icon_id": "27294584",
+      "name": "yakou",
+      "font_class": "cad-yakou",
+      "unicode": "e699",
+      "unicode_decimal": 59033
+    },
+    {
+      "icon_id": "11304931",
+      "name": "more read",
+      "font_class": "more",
+      "unicode": "e600",
+      "unicode_decimal": 58880
+    },
+    {
+      "icon_id": "27264933",
+      "name": "mosaic",
+      "font_class": "mosaic1",
+      "unicode": "e697",
+      "unicode_decimal": 59031
+    },
+    {
+      "icon_id": "12324809",
+      "name": "横标CN",
+      "font_class": "hengbiaoCN",
+      "unicode": "e6a3",
+      "unicode_decimal": 59043
+    },
+    {
+      "icon_id": "27200779",
+      "name": "nor",
+      "font_class": "nor",
+      "unicode": "e696",
+      "unicode_decimal": 59030
+    },
+    {
+      "icon_id": "25671886",
+      "name": "checkbox",
+      "font_class": "checkbox1",
+      "unicode": "e65d",
+      "unicode_decimal": 58973
+    },
+    {
+      "icon_id": "27198807",
+      "name": "rotate",
+      "font_class": "rotate",
+      "unicode": "e695",
+      "unicode_decimal": 59029
+    },
+    {
+      "icon_id": "27198774",
+      "name": "adapt",
+      "font_class": "adapt",
+      "unicode": "e692",
+      "unicode_decimal": 59026
+    },
+    {
+      "icon_id": "27198776",
+      "name": "recover",
+      "font_class": "recover",
+      "unicode": "e693",
+      "unicode_decimal": 59027
+    },
+    {
+      "icon_id": "27198777",
+      "name": "repeal",
+      "font_class": "repeal",
+      "unicode": "e694",
+      "unicode_decimal": 59028
+    },
+    {
+      "icon_id": "25654903",
+      "name": "reset",
+      "font_class": "reset",
+      "unicode": "e65a",
+      "unicode_decimal": 58970
+    },
+    {
+      "icon_id": "26971297",
+      "name": "course",
+      "font_class": "course1",
+      "unicode": "e68c",
+      "unicode_decimal": 59020
+    },
+    {
+      "icon_id": "26950708",
+      "name": "publish",
+      "font_class": "publish",
+      "unicode": "e68a",
+      "unicode_decimal": 59018
+    },
+    {
+      "icon_id": "26950711",
+      "name": "save",
+      "font_class": "save",
+      "unicode": "e68b",
+      "unicode_decimal": 59019
+    },
+    {
+      "icon_id": "23842269",
+      "name": "sel",
+      "font_class": "checkbox",
+      "unicode": "e649",
+      "unicode_decimal": 58953
+    },
+    {
+      "icon_id": "23786361",
+      "name": "mosaic",
+      "font_class": "mosaic",
+      "unicode": "e646",
+      "unicode_decimal": 58950
+    },
+    {
+      "icon_id": "23786362",
+      "name": "media",
+      "font_class": "media",
+      "unicode": "e647",
+      "unicode_decimal": 58951
+    },
+    {
+      "icon_id": "23786363",
+      "name": "pic",
+      "font_class": "pic",
+      "unicode": "e648",
+      "unicode_decimal": 58952
+    },
+    {
+      "icon_id": "23783948",
+      "name": "eye_f",
+      "font_class": "eye_f",
+      "unicode": "e644",
+      "unicode_decimal": 58948
+    },
+    {
+      "icon_id": "23783949",
+      "name": "eye_c",
+      "font_class": "eye_c",
+      "unicode": "e645",
+      "unicode_decimal": 58949
+    },
+    {
+      "icon_id": "23783512",
+      "name": "size-o",
+      "font_class": "size-o",
+      "unicode": "e640",
+      "unicode_decimal": 58944
+    },
+    {
+      "icon_id": "23783513",
+      "name": "size-f",
+      "font_class": "size-f",
+      "unicode": "e641",
+      "unicode_decimal": 58945
+    },
+    {
+      "icon_id": "23783514",
+      "name": "magnify",
+      "font_class": "magnify",
+      "unicode": "e642",
+      "unicode_decimal": 58946
+    },
+    {
+      "icon_id": "23783515",
+      "name": "reduce",
+      "font_class": "reduce",
+      "unicode": "e643",
+      "unicode_decimal": 58947
+    },
+    {
+      "icon_id": "23781429",
+      "name": "video",
+      "font_class": "video1",
+      "unicode": "e63b",
+      "unicode_decimal": 58939
+    },
+    {
+      "icon_id": "23781430",
+      "name": "uploading_s",
+      "font_class": "uploading_s",
+      "unicode": "e63c",
+      "unicode_decimal": 58940
+    },
+    {
+      "icon_id": "23781431",
+      "name": "path",
+      "font_class": "path",
+      "unicode": "e63d",
+      "unicode_decimal": 58941
+    },
+    {
+      "icon_id": "23781432",
+      "name": "record",
+      "font_class": "record",
+      "unicode": "e63e",
+      "unicode_decimal": 58942
+    },
+    {
+      "icon_id": "23781433",
+      "name": "clear",
+      "font_class": "clear",
+      "unicode": "e63f",
+      "unicode_decimal": 58943
+    },
+    {
+      "icon_id": "23773343",
+      "name": "pause",
+      "font_class": "pause",
+      "unicode": "e636",
+      "unicode_decimal": 58934
+    },
+    {
+      "icon_id": "23773344",
+      "name": "preview",
+      "font_class": "preview",
+      "unicode": "e63a",
+      "unicode_decimal": 58938
+    },
+    {
+      "icon_id": "23773141",
+      "name": "full",
+      "font_class": "full",
+      "unicode": "e638",
+      "unicode_decimal": 58936
+    },
+    {
+      "icon_id": "23773068",
+      "name": "add",
+      "font_class": "add",
+      "unicode": "e631",
+      "unicode_decimal": 58929
+    },
+    {
+      "icon_id": "23773069",
+      "name": "del",
+      "font_class": "del",
+      "unicode": "e632",
+      "unicode_decimal": 58930
+    },
+    {
+      "icon_id": "23773070",
+      "name": "close",
+      "font_class": "close",
+      "unicode": "e633",
+      "unicode_decimal": 58931
+    },
+    {
+      "icon_id": "23773072",
+      "name": "web",
+      "font_class": "web",
+      "unicode": "e635",
+      "unicode_decimal": 58933
+    },
+    {
+      "icon_id": "23773074",
+      "name": "music",
+      "font_class": "music",
+      "unicode": "e637",
+      "unicode_decimal": 58935
+    },
+    {
+      "icon_id": "23773076",
+      "name": "uploading",
+      "font_class": "uploading1",
+      "unicode": "e639",
+      "unicode_decimal": 58937
+    },
+    {
+      "icon_id": "22132762",
+      "name": "state_e",
+      "font_class": "state_e",
+      "unicode": "e624",
+      "unicode_decimal": 58916
+    },
+    {
+      "icon_id": "22132763",
+      "name": "state_f",
+      "font_class": "state_f",
+      "unicode": "e625",
+      "unicode_decimal": 58917
+    },
+    {
+      "icon_id": "22132764",
+      "name": "state_s",
+      "font_class": "state_s",
+      "unicode": "e626",
+      "unicode_decimal": 58918
+    },
+    {
+      "icon_id": "22130256",
+      "name": "vip_uploading",
+      "font_class": "vip_uploading",
+      "unicode": "e623",
+      "unicode_decimal": 58915
+    },
+    {
+      "icon_id": "22099675",
+      "name": "eye-n",
+      "font_class": "eye-n",
+      "unicode": "e621",
+      "unicode_decimal": 58913
+    },
+    {
+      "icon_id": "22099676",
+      "name": "eye-s",
+      "font_class": "eye-s",
+      "unicode": "e622",
+      "unicode_decimal": 58914
+    },
+    {
+      "icon_id": "22099634",
+      "name": "course",
+      "font_class": "course",
+      "unicode": "e620",
+      "unicode_decimal": 58912
+    },
+    {
+      "icon_id": "22099525",
+      "name": "edit",
+      "font_class": "edit",
+      "unicode": "e61f",
+      "unicode_decimal": 58911
+    },
+    {
+      "icon_id": "22099475",
+      "name": "help",
+      "font_class": "help",
+      "unicode": "e615",
+      "unicode_decimal": 58901
+    },
+    {
+      "icon_id": "22099478",
+      "name": "rule",
+      "font_class": "rule",
+      "unicode": "e617",
+      "unicode_decimal": 58903
+    },
+    {
+      "icon_id": "22099479",
+      "name": "link",
+      "font_class": "link",
+      "unicode": "e618",
+      "unicode_decimal": 58904
+    },
+    {
+      "icon_id": "22099480",
+      "name": "uploading",
+      "font_class": "uploading",
+      "unicode": "e619",
+      "unicode_decimal": 58905
+    },
+    {
+      "icon_id": "22099481",
+      "name": "vr",
+      "font_class": "vr",
+      "unicode": "e61a",
+      "unicode_decimal": 58906
+    },
+    {
+      "icon_id": "22099484",
+      "name": "complete",
+      "font_class": "complete",
+      "unicode": "e61b",
+      "unicode_decimal": 58907
+    },
+    {
+      "icon_id": "22099499",
+      "name": "download",
+      "font_class": "download",
+      "unicode": "e61c",
+      "unicode_decimal": 58908
+    },
+    {
+      "icon_id": "22099518",
+      "name": "pull-down",
+      "font_class": "pull-down",
+      "unicode": "e61d",
+      "unicode_decimal": 58909
+    },
+    {
+      "icon_id": "22099519",
+      "name": "pull-up",
+      "font_class": "pull-up",
+      "unicode": "e61e",
+      "unicode_decimal": 58910
+    },
+    {
+      "icon_id": "22099070",
+      "name": "updown",
+      "font_class": "updown",
+      "unicode": "e613",
+      "unicode_decimal": 58899
+    },
+    {
+      "icon_id": "22099071",
+      "name": "scene",
+      "font_class": "scene",
+      "unicode": "e614",
+      "unicode_decimal": 58900
+    },
+    {
+      "icon_id": "22099025",
+      "name": "message",
+      "font_class": "message",
+      "unicode": "e60c",
+      "unicode_decimal": 58892
+    },
+    {
+      "icon_id": "22099028",
+      "name": "basic",
+      "font_class": "basic",
+      "unicode": "e60d",
+      "unicode_decimal": 58893
+    },
+    {
+      "icon_id": "22099032",
+      "name": "hotspot",
+      "font_class": "hotspot",
+      "unicode": "e60e",
+      "unicode_decimal": 58894
+    },
+    {
+      "icon_id": "22099035",
+      "name": "guide",
+      "font_class": "guide",
+      "unicode": "e60f",
+      "unicode_decimal": 58895
+    },
+    {
+      "icon_id": "22099060",
+      "name": "wander",
+      "font_class": "wander",
+      "unicode": "e610",
+      "unicode_decimal": 58896
+    },
+    {
+      "icon_id": "22099068",
+      "name": "house",
+      "font_class": "house",
+      "unicode": "e611",
+      "unicode_decimal": 58897
+    },
+    {
+      "icon_id": "22099069",
+      "name": "video",
+      "font_class": "video",
+      "unicode": "e612",
+      "unicode_decimal": 58898
+    },
+    {
+      "icon_id": "20066551",
+      "name": "show_3d_normal",
+      "font_class": "show_3d_normal",
+      "unicode": "e677",
+      "unicode_decimal": 58999
+    },
+    {
+      "icon_id": "20066554",
+      "name": "show_plane_normal",
+      "font_class": "show_plane_normal",
+      "unicode": "e67d",
+      "unicode_decimal": 59005
+    },
+    {
+      "icon_id": "20066556",
+      "name": "show_roaming_selected",
+      "font_class": "show_roaming_selected",
+      "unicode": "e682",
+      "unicode_decimal": 59010
+    },
+    {
+      "icon_id": "20066557",
+      "name": "show_plane_selected",
+      "font_class": "show_plane_selected",
+      "unicode": "e684",
+      "unicode_decimal": 59012
+    },
+    {
+      "icon_id": "20066558",
+      "name": "show_3d_selected",
+      "font_class": "show_3d_selected",
+      "unicode": "e685",
+      "unicode_decimal": 59013
+    },
+    {
+      "icon_id": "20066559",
+      "name": "show_roaming_normal",
+      "font_class": "show_roaming_normal",
+      "unicode": "e686",
+      "unicode_decimal": 59014
+    }
+  ]
+}

BIN
public/static/lib/iconfont/iconfont.ttf


BIN
public/static/lib/iconfont/iconfont.woff


BIN
public/static/lib/iconfont/iconfont.woff2


ファイルの差分が大きいため隠しています
+ 1 - 1
public/static/lib/potree/potree.js.map


+ 48 - 12
src/pages/Bim.vue

@@ -4,40 +4,62 @@
 <script setup>
 import { onMounted } from 'vue'
 
-let viewToken = 'fe69c34c232047989b3619489027d9df'
+let viewToken = 'c34b3bf046e140968d1d3a30bdc229f4'
 // 声明Viewer及App
 let app
 let viewer3D
 let viewAdded = false
 
 // 加载成功回调函数
-const successCallback = viewMetaData => {
+const successCallback1 = viewMetaData => {
     let dom4Show = document.getElementById('domId')
     // 设置WebApplication3D的配置项
     let webAppConfig = new Glodon.Bimface.Application.WebApplicationRfaConfig()
     webAppConfig.domElement = dom4Show
     webAppConfig.EnableFamilyList = false
     // 设置模型爆炸配置项
-    webAppConfig.enableExplosion = true
+    webAppConfig.enableExplosion = false
     // 创建WebApplication3D,用以显示模型
     app = new Glodon.Bimface.Application.WebApplicationRfa(webAppConfig)
-    app.addView(viewToken)
+
     viewer3D = app.getViewer()
+    viewer3D.loadModel({ viewMetaData })
     // 监听添加view完成的事件
     viewer3D.addEventListener(Glodon.Bimface.Viewer.Viewer3DEvent.ViewAdded, function () {
         //自适应屏幕大小
         window.onresize = function () {
-            viewer3D.resize(document.documentElement.clientWidth, document.documentElement.clientHeight - 40)
+            viewer3D.resize(document.documentElement.clientWidth, document.documentElement.clientHeight /* - 40*/)
         }
         viewAdded = true
         // 渲染3D模型
         viewer3D.render()
+
+        window.loaded.resolve(viewer3D)
     })
+}
 
-    // viewer3D.addEventListener(Glodon.Bimface.Viewer.ViewerDrawingEvent.MouseClicked, function (objectdata) {
-    //     // 调用viewerDrawing对象的Method,可以继续扩展功能
-    //     alert('objectId : ' + JSON.stringify(objectdata.objectId) + '\n' + 'worldPosition : ' + JSON.stringify(objectdata.worldPosition))
-    // })
+const successCallback2 = viewMetaData => {
+    var view = document.getElementById('domId')
+    var config = new Glodon.Bimface.Application.WebApplicationRfaConfig()
+    config.domElement = view
+    config.EnableFamilyList = false
+    // 设置模型爆炸配置项
+    config.enableExplosion = false
+    var eventManager = Glodon.Bimface.Application.WebApplication3DEvent
+    app = new Glodon.Bimface.Application.WebApplicationRfa(config)
+    viewer3D = app.getViewer()
+    viewer3D.loadModel({ viewMetaData })
+    viewer3D.addEventListener(Glodon.Bimface.Viewer.Viewer3DEvent.ViewAdded, function () {
+        //自适应屏幕大小
+        window.onresize = function () {
+            viewer3D.resize(document.documentElement.clientWidth, document.documentElement.clientHeight /* - 40*/)
+        }
+        viewAdded = true
+        // 渲染3D模型
+        viewer3D.render()
+
+        window.loaded.resolve(viewer3D)
+    })
 }
 
 // 加载失败回调函数
@@ -46,9 +68,15 @@ const failureCallback = error => {
 }
 
 onMounted(() => {
-    let loaderConfig = new BimfaceSDKLoaderConfig()
-    loaderConfig.viewToken = viewToken
-    BimfaceSDKLoader.load(loaderConfig, successCallback, failureCallback)
+    // let loaderConfig = new BimfaceSDKLoaderConfig()
+    // loaderConfig.viewToken = viewToken
+    // BimfaceSDKLoader.load(loaderConfig, successCallback1, failureCallback)
+
+    let BimfaceLoaderConfig = new BimfaceSDKLoaderConfig()
+    BimfaceLoaderConfig.dataEnvType = BimfaceEnvOption.Local
+    BimfaceLoaderConfig.sdkPath = 'https://4dkk.4dage.com/bim/jssdk'
+    BimfaceLoaderConfig.path = 'https://4dkk.4dage.com/bim/project-1/viewToken.json'
+    BimfaceSDKLoader.load(BimfaceLoaderConfig, successCallback2, failureCallback)
 })
 </script>
 <style lang="scss" scoped>
@@ -57,3 +85,11 @@ onMounted(() => {
     height: 100%;
 }
 </style>
+<style lang="scss">
+.bf-loading .bf-loading-gif {
+    width: 80px !important;
+    height: 80px !important;
+    background-size: contain;
+    background-repeat: no-repeat
+}
+</style>

+ 88 - 72
src/pages/LaserBim.vue

@@ -8,8 +8,8 @@
                 <iframe ref="sourceFrame" :src="`smart-laser.html?m=${source.num}&dev`" frameborder="0" @load="onLoadSource"></iframe>
                 <div class="tools">
                     <div class="item-mode">
-                        <div class="iconfont icon-show_roaming_normal" @click="onModeChange('panorama')"></div>
-                        <div class="iconfont icon-show_more" @click="onModeChange('cloud')"></div>
+                        <div class="iconfont icon-show_roaming_normal" :class="{ active: mode == 0 }" @click="onModeChange(0)"></div>
+                        <div class="iconfont icon-show_more" :class="{ active: mode == 1 }" @click="onModeChange(1)"></div>
                     </div>
                     <div class="item-date" v-if="target">
                         <span class="prev" @click="onPrevDate('source')"><i class="iconfont icon-show_back"></i></span>
@@ -45,13 +45,16 @@
 import Datepicker from 'vuejs3-datepicker'
 import { ref, onActivated, onDeactivated, reactive, onMounted, computed } from 'vue'
 import ConvertViews from '@/utils/ConvertViews'
-let sourceApp = null
+ 
+let sourceApp = null, sourceSceneName
 let targetApp = null
+
 const views = new ConvertViews()
 const datepickName = ref(null)
 const datepickValue = ref(null)
 const sourceFrame = ref(null)
 const targetFrame = ref(null)
+const mode = ref(0)
 const source = ref(null)
 const target = ref(null)
 const project = ref(null)
@@ -60,7 +63,7 @@ const scenes = reactive([
     { pid: '001', num: 'SS-t-bFMqa1dqUU', date: '2022-09-01' },
     { pid: '001', num: 'SS-t-xp9BDKfzhR', date: '2022-09-03' },
     { pid: '001', num: 'SS-t-lc5OWhZPaC', date: '2022-09-05' },
-    { pid: '001', num: 'SS-t-Y6gLRFwxE5', date: '2022-09-10' }
+    { pid: '001', num: 'SS-t-Y6gLRFwxE5', date: '2022-09-10' },
 ])
 const highlighted = computed(() => {
     let dates = []
@@ -68,50 +71,89 @@ const highlighted = computed(() => {
         dates = scenes.map(item => item.date.toDate())
     }
     return {
-        dates: dates
+        dates: dates,
     }
 })
 
-const onLoadSource = () => {
-    sourceApp = sourceFrame.value.contentWindow.app
-    // sourceApp.Scene.on('loaded', () => {
-    //     sourceApp.Camera.setCompassDisplay(false)
-    //     sourceApp.Connect.sync.start()
-    //     sourceApp.VRScreenSYNC = false
+const getView = ()=>{
+    let camera = sourceApp.viewer.mainViewport.camera
+    return {
+        position : camera.position,
+        quaternion : camera.quaternion, 
+        fov : camera.fov
+    }
+} 
 
-    //     console.log('sourceApp.Scene loaded')
-    //     views.KanKan = sourceFrame.value.contentWindow.KanKan
-    //     views.bind({ sourceApp })
-    //     targetApp && targetApp.Connect.sync.sync()
-    // })
-    // sourceApp.Connect.sync.on('data', data => {
-    //     if (targetApp) {
-    //         views.applyDiff(targetApp, data)
-    //         targetApp.Connect.sync.receive(data)
-    //     }
-    // })
+const initConvertView = (noNeedBindEvent) => {
+    if(sourceApp && targetApp ){
+        views.init(sourceApp, targetApp , sourceApp.viewer.inputHandler.domElement, 'laser', getView(), 
+                    sourceApp.viewer.images360.panos.slice(0,2)  )
+    }
+}
+const syn = (e)=>{
+    targetApp && views.receive( getView() )
+}
+views.addEventListener('needsSyn',syn)
+window.views = views
+const onLoadSource = () => {
+    
+    if(views.loaded){
+        views.clear({dontClearTarget:true})   
+    }
+    
+    sourceApp = sourceFrame.value.contentWindow
+    sourceApp.loaded.then(sdk => {
+        if (mode.value != 0) {
+            sdk.scene.changeMode(mode.value)
+        }
+        
+        window.viewer1 = sourceApp.viewer 
+        window.app1 = sourceApp
+        viewer1.mainViewport.view.minPitch+=0.01//防止bim垂直视角上的闪烁(似乎是因 up 要乘以某矩阵导致微小偏差所致)
+        viewer1.mainViewport.view.minPitch-=0.01
+        sourceApp.Potree.settings.rotAroundPoint = false
+        viewer1.images360.panos.forEach(pano=>{
+            viewer1.updateVisible(pano.label2, 'notDisplay', true)
+            pano.dispatchEvent({type:'changeMarkerTex',name:'ring'})
+        }) 
+        initConvertView()
+        sourceSceneName = sourceApp.Potree.settings.number
+         
+        sourceApp.viewer.addEventListener('camera_changed', syn) 
+             
+        
+    }) 
+    
+    sourceApp.canChangePos = ()=>{
+        return sourceApp.Potree.settings.displayMode != 'showPanos'
+    }
+    
 }
-const onLoadTarget = () => {
-    targetApp = targetFrame.value.contentWindow.app
-    // targetApp.Scene.on('loaded', () => {
-    //     targetApp.Camera.setCompassDisplay(false)
-    //     targetApp.Connect.sync.start()
-    //     targetApp.VRScreenSYNC = false
-    //     console.log('targetApp.Scene loaded')
+const onLoadTarget = () => { 
+ 
+    targetApp = targetFrame.value.contentWindow
+    window.app2 = targetApp
+    targetApp.loaded.then(viewer=>{
+        window.viewer2 = targetApp.viewer
+        initConvertView() 
+    })
 
-    //     views.bind({ targetApp })
-    //     sourceApp && sourceApp.Connect.sync.sync()
-    // })
-    // targetApp.Connect.sync.on('data', data => {
-    //     if (sourceApp) {
-    //         views.applyDiff(sourceApp, data)
-    //         sourceApp.Connect.sync.receive(data)
-    //     }
-    // })
 }
-const onModeChange = mode => {
+
+
+views.addEventListener('sendCameraData',(e)=>{ //同步右侧数据
+    sourceApp.viewer.mainViewport.view.position.copy(e.data.position)
+    sourceApp.viewer.mainViewport.view.lookAt(e.data.target)
+    
+})
+
+
+
+
+const onModeChange = targetMode => {
     if (sourceApp) {
-        
+        sourceApp.loaded.then(sdk => sdk.scene.changeMode(targetMode))
+        mode.value = targetMode
     }
 }
 const onPickDate = name => {
@@ -161,6 +203,7 @@ const onCompare = () => {
     if (target.value) {
         target.value = null
         targetApp = null
+        views.clear()
         return
     }
     let index = scenes.findIndex(item => item.num == source.value.num)
@@ -174,9 +217,6 @@ const onCompare = () => {
 }
 
 const onPrevDate = name => {
-    if (!scene) {
-        scene = source
-    }
     let scene = null
     if (!name || name == 'source') {
         scene = source
@@ -191,20 +231,6 @@ const onPrevDate = name => {
         index = scenes.length - 1
     }
 
-    // if (name) {
-    //     if (name == 'source') {
-    //         if (scenes[index].num == target.value.num) {
-    //             index--
-    //         }
-    //     } else {
-    //         if (scenes[index].num == source.value.num) {
-    //             index--
-    //         }
-    //     }
-    // }
-    // if (index == -1) {
-    //     index = scenes.length - 1
-    // }
     scene.value = scenes[index]
 }
 const onNextDate = name => {
@@ -221,27 +247,14 @@ const onNextDate = name => {
     if (++index > scenes.length - 1) {
         index = 0
     }
-    // if (name) {
-    //     if (name == 'source') {
-    //         if (scenes[index].num == target.value.num) {
-    //             index++
-    //         }
-    //     } else {
-    //         if (scenes[index].num == source.value.num) {
-    //             index++
-    //         }
-    //     }
-    // }
-    // if (index > scenes.length - 1) {
-    //     index = 0
-    // }
+   
     scene.value = scenes[index]
 }
 
 onMounted(() => {
     project.value = projects[0]
     if (project.value) {
-        source.value = scenes[2] //scenes.find(item => item.num == project.value.num)
+        source.value = scenes[0] //scenes.find(item => item.num == project.value.num)
     }
 })
 </script>
@@ -327,6 +340,9 @@ main {
                     margin-left: 20px;
                     margin-right: 20px;
                     cursor: pointer;
+                    &.active {
+                        color: #00c8af;
+                    }
                 }
                 i {
                     font-size: 18px;

+ 2 - 0
src/pages/bim.js

@@ -1,4 +1,6 @@
 import { createApp } from 'vue'
 import App from './Bim.vue'
+import Deferred from '@/utils/Deferred'
+window.loaded = Deferred()
 const app = (window.__app = createApp(App))
 app.mount('#app')

+ 512 - 41
src/utils/ConvertViews.js

@@ -1,59 +1,249 @@
-export default class ConvertViews {
+import math from './math.js'
+let Bimface
+const belowHeight = 0.4
+const isEdit = true
+
+
+
+let texLoader = new THREE.TextureLoader()  
+export default class ConvertViews extends THREE.EventDispatcher{
     constructor() {
+        super()
         this.sourceApp = null
         this.targetApp = null
-        this.player1 = null
-        this.player2 = null
-        this.KanKan = null
+        this.sourceType = null
+        
     }
 
-    bind(options = { sourceApp: null, targetApp: null }) {
-        if (options.sourceApp) {
-            this.sourceApp = options.sourceApp
-            this.player1 = this.sourceApp.core.get('Player')
-            //this.player1.model.addEventListener('gotPanos', this.init.bind(this))
-        } else if (options.targetApp) {
-            this.targetApp = options.targetApp
-            this.player2 = this.targetApp.core.get('Player')
-            //this.player2.model.addEventListener('gotPanos', this.init.bind(this))
-        }
-        if (this.sourceApp && this.targetApp) {
-            // 两个实例都加载完了,可以进行特性处理
-            this.init()
-            this.applyDiff(options.sourceApp || options.targetApp)
+     
+    clear(o={}){
+        this.loaded = false;
+        this.sourceApp = null;
+        if(!o.dontClearTarget){
+            this.targetApp = null
+        } 
+    }
+    
+    init(sourceApp, targetApp, sourceDom, sourceType, cameraData, sourcePano) {
+        //if (!this.player1.model.panos.list.length || !this.player2.model.panos.list.length) return
+        
+        if(this.loaded || !targetApp ) return 
+        let needBindEvent = !this.targetApp // 若targetApp存在表明targetApp的dom未换掉,事件还存在
+        this.sourceApp = sourceApp
+        this.targetApp = targetApp
+        this.sourceDom = sourceDom
+        this.sourceType = sourceType
+        this.sourcePano = sourcePano
+        this.targetPano = [
+            {position: new THREE.Vector3( -5.313605730801787,  -4.889868407960505,  1.237447893355817),},
+            {position: new THREE.Vector3( -5.337403524084278,  -2.5012228235167737, 1.2808838933558175),} 
+        ]
+        let viewer = this.viewer = targetApp.viewer 
+        //viewer.THREE = targetApp.THREE
+        this.needConvertAxis = sourceType == '4dkk' // Y朝上需要转换
+        Bimface = targetApp.Glodon.Bimface
+        this.lastCamStatus = viewer.getCameraStatus()
+        this.computeShift(sourcePano)
+        if(isEdit){
+            this.createPanoPannel()
         }
+        viewer.setNavigationMode( Bimface.Viewer.NavigationMode3D.Walk)
+        viewer.setFlySpeedRate(5)
+        viewer.getViewer().setTransitionAnimationState(false) //setCameraStatus瞬间变化相机 ,or setCameraAnimation?
+         
+        needBindEvent && viewer.addEventListener('Rendered', (e)=>{//反向改变左侧相机
+            if(this.synPaused)return  
+            let info = viewer.getCameraStatus() 
+            let poseChanged = !math.closeTo(this.lastCamStatus.position, info.position)
+                || !math.closeTo(this.lastCamStatus.target, info.target)
+                || !math.closeTo(this.lastCamStatus.fov, info.fov)
+            
+            if(poseChanged){
+                if(sourceApp.canChangePos()){ 
+                    
+                    this.send(info)
+                    this.lastCamStatus = info 
+                }  
+            }  
+        })  
+        //this.addMesh(cameraData)
+        
+        /* viewer.addEventListener( Bimface.Viewer.Viewer3DEvent.ViewAdded,
+            ()=>{
+                this.loaded = true
+                if(this.firstData){
+                    this.receive(this.firstData)
+                }
+            }
+        ) */
+        this.loaded = true
+        this.receive(cameraData)
+        needBindEvent && this.bindCamEvent() 
+        
+        
+        
+        
     }
+ 
+
+    receive(data){
+        this.dispatchEvent({type:'updateBtnState'})   
+        if(this.synPaused)return
+        if(!this.loaded){
+            return this.firstData = data
+        }
+         
+        let position = new THREE.Vector3, target = new THREE.Vector3
+        let currStatus = this.viewer.getCameraStatus()
+        if(data.position){
+            position = new THREE.Vector3().copy(data.position)
+        } 
+         
+        
+        if(!data.target){
+            if(data.quaternion){   
+                let dir = new THREE.Vector3(0, 0, -1).applyQuaternion(data.quaternion) 
+                target.copy(position).add(dir) 
+            }
+        }else{
+            if(this.needConvertAxis){
+                target = math.convertVector.YupToZup(target)
+            }else{
+                target.copy(data.target)
+            } 
+        }
+        
+        if(this.needConvertAxis){
+            position = math.convertVector.YupToZup(position)
+            target = math.convertVector.YupToZup(target)
+        }
+
+        position.applyMatrix4(this.convertMatrix)
+        target.applyMatrix4(this.convertMatrix)
 
-    init() {
-        if (!this.player1.model.panos.list.length || !this.player2.model.panos.list.length) return
 
-        this.diffLon = this.computeAveDiffLon()
-        this.diffQuaternion = new this.KanKan.THREE.Quaternion().setFromAxisAngle(new this.KanKan.THREE.Vector3(0, 1, 0), this.diffLon)
-        this.diffQuaternionInvert = this.diffQuaternion.clone().invert()
+        let msg = {
+            position,
+            target,
+            up: new THREE.Vector3(0,0,1),
+            //前三个缺一不可  
+            fov: data.fov ,      //fov 用setCameraStatus 无效
+        }
+        
+        
+         
+        this.viewer.setCameraStatus(msg)    
+        this.lastCamStatus = msg //记录下来,防止反向传输
+        
+        let camera = this.viewer.getViewer().camera
+        if(camera.fov != data.fov){
+            camera.fov = data.fov
+            camera.updateProjectionMatrix()
+        }
+         
+        //fov, near,  far
+        /*   aspect: 0.7879440258342304
+            coordinateSystem: "world"
+            far: 11485.989363357028
+            fov: 45
+            name: "persp"
+            near: 1.1852000000072447
+            position: {x: -1130.0432094639486, y: -6058.569138159733, z: 2265.9284566100446}
+            target: {x: 310.3968263091223, y: -66.0595010237127, z: 1477.7045866099475}
+            up: {x: 0, y: 1.534753124827774e-13, z: 1}
+            version: 1
+            zoom: 0 */
+    
+        /* this.plane.quaternion.copy(camera.quaternion)
+        this.plane.updateMatrix()
+        this.plane.updateMatrixWorld() 
+        
+        let matrix = new THREE.Matrix4()
+        matrix.makeRotationFromQuaternion(camera.quaternion)
+        
+        extObjMng.setTransformation(this.plane.name, matrix)*/
     }
 
-    computeAveDiffLon() {
-        //获取两个场景的lon偏差值
-        //需要点的个数>1, 且两个场景点一一对应,位置接近且顺序一致
 
+    send(info){ 
+        let camera = this.viewer.getViewer().camera
+        
+        let data = { 
+            position : new THREE.Vector3().copy(info.position).applyMatrix4(this.convertMatrixInvert),
+            //quaternion : camera.quaternion.clone().applyMatrix4(this.convertMatrix),
+            target : new THREE.Vector3().copy(info.target).applyMatrix4(this.convertMatrixInvert),
+        }  
+        
+        if(this.needConvertAxis){
+            data.position = math.convertVector.ZupToYup(data.position)
+            data.target = math.convertVector.ZupToYup(data.target)
+        }
+        this.dispatchEvent({
+            type: 'sendCameraData',
+            data
+        })
+    } 
+
+
+
+    computeShift(sourcePano) { //获取两个场景的旋转和位移偏差值
+        //需要点的个数>1, 且两个场景点一一对应,位置接近且顺序一致
+        //pick两个点来计算
         let diffLonAve = 0,
             diffLons = []
 
-        let panoPos1 = this.player1.model.panos.list.map(e => e.position)
-        let panoPos2 = this.player2.model.panos.list.map(e => e.position)
+        /* let panoPos1 = [//4dkk   SS-t-lc5OWhZPaC 
+            new THREE.Vector3( 2.1985836955069153,  -0.7253820937020852,  -0.01348725),
+            new THREE.Vector3( 4.07288387528266,  1.8350265362839944, 0.04772775)
+        ] */
+        
+        let panoPos1 = this.sourcePano.map(e=>e.position) 
+        let panoPos2 = this.targetPano.map(e=>e.position)
+        
         let length = panoPos1.length
+        
+        if(this.needConvertAxis){
+            panoPos1 = panoPos1.map(e=>math.convertVector.YupToZup(e))
+        }
+
+
+        var vec1 = new THREE.Vector3().subVectors(panoPos1[0], panoPos1[1]) //旧的向量
+        var vec2 = new THREE.Vector3().subVectors(panoPos2[0], panoPos2[1])//新的向量
+   
+        var angle = math.getAngle(vec1, vec2, 'z')
+
+
+        //var scale = vec2.length()/vec1.length() 
+        //var scaleMatrix = new THREE.Matrix4().makeScale(scale,scale,scale)   //默认为1, 但由于坐标暂时是自己采集的,所以结果会是第一个点附近比较正确,越远偏差越大
+        var matrix = new THREE.Matrix4().setPosition(panoPos1[0].clone().negate())//先以点0为基准平移到000
+        //matrix.premultiply(scaleMatrix)//再缩放
+        var rotateMatrix = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(0,0,1), angle );
+        matrix.premultiply(rotateMatrix)//和旋转
+        var moveBackMatrix = new THREE.Matrix4().setPosition(panoPos2[0])
+        matrix.premultiply(moveBackMatrix)//再移动到realPosition的点0处
+
+        //由于是以第一个点来平移,所以只有第一个点看起来最同步,其他点若误差大,飞到这些点时会看到标记不在这个位置上。
+
+        this.convertMatrix = matrix
+        this.convertMatrixInvert = matrix.clone().invert()
+        
+        /* var pos = panoPos1.map(e=>{ 
+            return e.clone().applyMatrix4(matrix)
+        })
+        console.log(pos) */
 
-        //挑选连续的两个点为向量来计算,如有123个漫游点,则选取12 23 31作为向量
 
-        let index = 0
+        //挑选连续的两个点为向量来计算,如有123个漫游点,则选取12 23 31作为向量
+            
+        /* let index = 0
         while (index < length) {
-            let pos11 = new this.KanKan.THREE.Vector3().copy(panoPos1[index])
-            let pos12 = new this.KanKan.THREE.Vector3().copy(panoPos1[(index + 1) % length])
-            let pos21 = new this.KanKan.THREE.Vector3().copy(panoPos2[index])
-            let pos22 = new this.KanKan.THREE.Vector3().copy(panoPos2[(index + 1) % length])
-            let vec1 = new this.KanKan.THREE.Vector3().subVectors(pos11, pos12).setY(0)
-            let vec2 = new this.KanKan.THREE.Vector3().subVectors(pos21, pos22).setY(0)
-            let diffLon = this.KanKan.Utils.math.getAngle(vec1, vec2, 'z')
+            let pos11 = new THREE.Vector3().copy(panoPos1[index])
+            let pos12 = new THREE.Vector3().copy(panoPos1[(index + 1) % length])
+            let pos21 = new THREE.Vector3().copy(panoPos2[index])
+            let pos22 = new THREE.Vector3().copy(panoPos2[(index + 1) % length])
+            let vec1 = new THREE.Vector3().subVectors(pos11, pos12).setZ(0)
+            let vec2 = new THREE.Vector3().subVectors(pos21, pos22).setZ(0)
+            let diffLon = math.getAngle(vec1, vec2, 'z')
             diffLons.push(diffLon)
             diffLonAve += diffLon
             index++
@@ -62,10 +252,278 @@ export default class ConvertViews {
         console.log('diffLons', diffLons)
         diffLonAve /= length
         console.log('diffLonAve', diffLonAve)
-        return /* KanKan.THREE.MathUtils.radToDeg( */ diffLonAve /* ) */
+        
+        this.diffQuaternion = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0),  diffLonAve)
+        this.diffQuaternionInvert = this.diffQuaternion.clone().invert() */
+
+    }
+    
+    
+    
+    bindCamEvent(){//传递到另一边的dom 
+        this.lockCamera(true)
+        
+        
+        /* this.viewer.addEventListener( Bimface.Viewer.Viewer3DEvent.MouseClicked,(e)=>{
+            console.log('MouseClicked',e)
+        }); */
+        
+        
+        let getEvent = (type, e)=>{
+            let dom = this.viewer.getDomElement()
+            let clientWidth1 = this.sourceDom.clientWidth
+            let clientHeight1 = this.sourceDom.clientHeight
+            let clientWidth2 = dom.clientWidth
+            let clientHeight2 = dom.clientHeight
+            return new MouseEvent(type, {
+                bubbles: false,//?
+                cancelable: true,
+                view: this.sourceApp,
+                
+                /* clientX: e.clientX, 
+                clientY: e.clientY, */ 
+                clientX: clientWidth1 * e.clientX / clientWidth2 , //鼠标在右屏的比例的左屏的相同,针对右屏全屏等左右不对称的情况
+                clientY: clientHeight1 * e.clientY / clientHeight2,
+                button: e.button, buttons: e.buttons,  which: e.which,
+                altKey: e.altKey, ctrlKey: e.ctrlKey, shiftKey:e.shiftKey, metaKey: e.metaKey, 
+                detail:e.detail, 
+                //target :  dom2  
+            });
+            
+        }  
+        
+        let dom1 = this.viewer.getDomElement() 
+        //let pointerDownPos = new THREE.Vector2
+        dom1.addEventListener('mousedown',(e)=>{
+            if(this.synPaused || !this.sourceApp)return
+            let event = getEvent('mousedown', e)
+            this.sourceDom.dispatchEvent(event)  
+            //pointerDownPos.set(e.clientX,e.clientY)
+        })
+        dom1.addEventListener('mousemove',(e)=>{
+            if(this.synPaused || !this.sourceApp)return
+            let event = getEvent('mousemove', e)
+            this.sourceDom.dispatchEvent(event)  
+        })
+        dom1.addEventListener('mouseup',(e)=>{  
+            if(this.synPaused || !this.sourceApp)return
+            let event = getEvent('mouseup', e)
+            event.unableClick = true //最好禁止右侧点击行走。否则和点击效果冲突
+            this.sourceApp.dispatchEvent(event)   //mouseup 在laser中加在window上的 
+        })
+        dom1.addEventListener('mousewheel',(e)=>{
+            if(this.synPaused || !this.sourceApp)return
+            let event = getEvent('mousewheel', e)
+            event.wheelDelta = e.wheelDelta  //wheelDelta没法在getEvent参数中赋值
+            this.sourceDom.dispatchEvent(event)  
+        })
+        let stop = (e)=>{ //drag到另一边时停止旋转, 防止转到另一边
+            if(/* this.synPaused || */ !this.sourceApp)return
+            let event = getEvent('mouseup', e)
+            this.sourceApp.dispatchEvent(event)   
+        }
+        dom1.addEventListener('mouseout',stop)
+        dom1.addEventListener('mouseover',stop)
+    
+        
+    }
+
+    lockCamera(locked){//禁止操作改变相机
+        this.locked = locked 
+        this.updateCtrlEnable() 
+    }
+
+    setPanoMode(state){
+        this.isPanoMode = state
+        this.updateCtrlEnable()
+    }
+
+    updateCtrlEnable(){
+        this.viewer.camera3D.enableRotate(this.locked ? false : true)
+        this.viewer.enableShortcutKey((this.locked || this.isPanoMode) ? false : true) //键盘移动
+    }
+
+    
+    createPanoPannel(){//修改对照pano,左侧修改选择的pano,右边修改对应的具体位置
+        let that = this
+        
+        let createPannel = (mainIndex)=>{
+            let pannel = document.createElement('div') 
+            pannel.style.top = 0
+            pannel.style.left = mainIndex == 0 ? 0 : "50%"
+            pannel.style.position = 'fixed';
+            pannel.style.background = 'rgba(255,255,255,0.9)';
+            pannel.style.color = 'black'
+            pannel.style['text-align'] = 'center'
+            
+            let createRow = function(index){
+                let row = document.createElement('div') 
+                let btnStr = mainIndex == 0 ? '选取当前漫游点' : '点击解锁'
+                row.innerHTML = `<div>pano${index}</div> <div name="state" style="width:100px"></div><div name="pick">${btnStr}</div> ` 
+                row.style.height = row.style['lineHeight'] = '30px';
+                row.style.display = 'flex'
+                
+                row.children[2].style.cursor = 'pointer' 
+                row.children[2].addEventListener('click',()=>{
+                    if(mainIndex == 0){//左侧
+                        //let another = this.sourcePano[(index+1)%2]  
+                        let curr = that.sourceApp.viewer.images360.currentPano
+                        if(that.sourcePano[0] == curr || that.sourcePano[1] == curr){
+                            return console.error('已经选择过当前点')
+                        }
+                        let sprite = that.sourcePano[index].sprite
+                        that.sourcePano[index] = curr
+                        that.sourcePano[index].sprite = sprite
+                        sprite.position.copy(curr.position)
+                        sprite.position.z -= belowHeight
+                        sprite.update()
+                    }else{//右侧
+                        if(that.synPaused){
+                            that.dispatchEvent({type:'addTag',   index}) 
+                            that.lockCamera(true)
+                            changeWords('点击解锁')
+                        }else{
+                            that.synPaused = true;
+                            that.lockCamera(false)
+                            changeWords('点击使用此相机点作为漫游点')
+                        } 
+                    }
+                })
+                
+                return row
+            }
+            
+            let row0 = createRow(0)
+            let row1 = createRow(1)
+            
+            let changeWords = function(words){
+                row0.children[2].innerText = words
+                row1.children[2].innerText = words
+            }
+            if(mainIndex == 0){
+                this.addEventListener('updateBtnState',()=>{
+                    let opacity = this.sourceApp.viewer.images360.isAtPano() ? 1 : 0.5;
+                    [row0,row1].forEach(row=>{
+                        row.children[2].style.opacity = opacity
+                        row.children[2].style.opacity = opacity
+                        row.children[2].style['pointer-events'] = opacity == 1 ? 'auto' : 'none'
+                    }) 
+                })
+            }
+           
+            pannel.appendChild(row0)
+            pannel.appendChild(row1)
+            
+            
+            document.getElementById('app').appendChild(pannel);
+            return pannel   
+        }
+        
+        this.pannels = [createPannel(0),createPannel(1)]
+        
+        this.initTagAdd()
+        this.sourcePano.forEach((pano,i)=>{
+            let sprite = this.sourceApp.viewer.addSprite({text:i}) 
+            sprite.position.copy(pano.position)
+            sprite.position.z -= belowHeight
+            this.sourceApp.viewer.scene.scene.add(sprite)
+            sprite.scale.set(0.4,0.4,0.4)
+            pano.sprite = sprite
+        })
+        this.targetPano.forEach((pano,index)=>{
+            that.dispatchEvent({type:'addTag',  position:pano.position, index}) 
+        })
+        
+    }
+    
+    updatePanoMatch(position, index ){//更新且应用
+        if(this.targetPano.length == 2){ 
+            this.targetPano[index].position = position 
+            this.computeShift()
+            this.synPaused = false
+            this.dispatchEvent({type:'needsSyn' })//使发送同步 
+        } 
+    }
+
+    initTagAdd(){ 
+        let markerConfig = new Bimface.Plugins.Marker3D.Marker3DContainerConfig();
+        markerConfig.viewer = this.viewer;
+        let tags = new Bimface.Plugins.Marker3D.Marker3DContainer(markerConfig);
+        console.log('tags',tags)
+        
+        this.addEventListener('addTag',(e)=>{
+            if(this.targetPano[e.index].tag){
+                tags.removeItemById(this.targetPano[e.index].tag.id)
+            }
+            let position = new THREE.Vector3
+            if(e.position){
+                position.copy(e.position)
+            }else{
+                let currStatus = this.viewer.getCameraStatus()
+                position.copy(currStatus.position)
+            } 
+            
+            
+            
+            let marker3dConfig = new Bimface.Plugins.Marker3D.Marker3DConfig();
+             
+            marker3dConfig.src = 'images/hotpoint'+ e.index +'.png'//"http://static.bimface.com/resources/3DMarker/warner/warner_red.png";
+            
+            marker3dConfig.worldPosition = new THREE.Vector3().copy(position) 
+            marker3dConfig.worldPosition.z -= belowHeight
+            marker3dConfig.tooltip = '此为漫游点'+e.index //三维标签的提示
+            let tag = new Bimface.Plugins.Marker3D.Marker3D(marker3dConfig);
+            tags.addItem(tag);
+            this.viewer.clearSelectedComponents();
+            this.viewer.render();
+            this.targetPano[e.index].tag = tag
+            this.updatePanoMatch(position, e.index )
+        })
+        /* this.viewer.addEventListener( Bimface.Viewer.Viewer3DEvent.MouseClicked, (objectData)=>{
+            
+            if(window.forbitAddTag )return
+            let position = objectData.worldPosition.clone().add({x:0,y:0,z:height});
+            let marker3dConfig = new Bimface.Plugins.Marker3D.Marker3DConfig();
+             
+            marker3dConfig.src = "http://static.bimface.com/resources/3DMarker/warner/warner_red.png";
+            
+            marker3dConfig.worldPosition = position;
+            //三维标签的提示
+            marker3dConfig.tooltip = "This is 3DMarker.";
+            let marker3d = new Bimface.Plugins.Marker3D.Marker3D(marker3dConfig);
+            marker3d.onClick(function (item) {
+                 
+            })
+            marker.addItem(marker3d);
+            this.viewer.clearSelectedComponents();
+            this.viewer.render();
+            
+        }); */
+        
+        
     }
+ 
+
+    /* addMesh(cameraData){
+         
+        var mesh = new Bimface.Plugins.Geometry.Plane({
+            type:'rectangle', points:[{x:-0.1,y:-0.1,z:0},{x:0.1,y:0.1,z:0}]
+        });
+            
+        var extObjMng = new Bimface.Plugins.ExternalObject.ExternalObjectManager(viewer2);            
+        extObjMng.loadObject({ name: 'plane', object: mesh});//作为外部构件添加到场景中
+
+        //mesh.children[0].position.copy(cameraData.position).setZ(0.5)
+        mesh.children[0].up.set(0,0,1) 
+        mesh.children[0].rotation.set(0,0,Math.PI/2)
+        
+        this.plane = mesh
+        window.extObjMng = extObjMng
+         
+        
+    } */
 
-    applyDiff(app) {
+    /* applyDiff(app) {
         //sourcePlayer -> targetPlayer
         if (!this.player1 || !this.player2 || this.targetApp.config.num == this.sourceApp.config.num) return //场景码相同的话返回
         if (this.player1.mode != this.player2.mode) return
@@ -103,14 +561,14 @@ export default class ConvertViews {
             control1.target.addVectors(player1.model.panos.list[0].position, vec)
             player1.target.copy(control1.target)
             //修改position,保证方向一样
-            let dir = new this.KanKan.THREE.Vector3().subVectors(control2.camera.position /* player2.position */, control2.target)
+            let dir = new this.KanKan.THREE.Vector3().subVectors(control2.camera.position , control2.target)
             dir.applyQuaternion(quaternion)
             player1.position = new this.KanKan.THREE.Vector3().addVectors(control1.target, dir)
 
             control1.camera.position.copy(player1.position)
         }
         control1.camera.quaternion.copy(player1.quaternion)
-    }
+    } */
 
     /* applyDiff(app, data) {
         //sourcePlayer -> targetPlayer
@@ -147,3 +605,16 @@ export default class ConvertViews {
         //位置参照第一个漫游点。保持相机相对第一个漫游点的位移和
     } */
 }
+
+
+
+/* 
+
+note:
+
+
+旋转只能通过target设置, 不能直接改camera.quaternion
+当且仅当发送方相机属性变化后才传递过来,就不在这里判断是否变化了。
+(所以只需要实时检测相机是否改变, hasChanged后发送)
+
+ */

+ 374 - 0
src/utils/Deferred.js

@@ -0,0 +1,374 @@
+function isArray(arr) {
+    return Object.prototype.toString.call(arr) === '[object Array]'
+}
+
+function foreach(arr, handler) {
+    if (isArray(arr)) {
+        for (var i = 0; i < arr.length; i++) {
+            handler(arr[i])
+        }
+    } else handler(arr)
+}
+
+function D(fn) {
+    var status = 'pending',
+        doneFuncs = [],
+        failFuncs = [],
+        progressFuncs = [],
+        resultArgs = null,
+        promise = {
+            done: function () {
+                for (var i = 0; i < arguments.length; i++) {
+                    // skip any undefined or null arguments
+                    if (!arguments[i]) {
+                        continue
+                    }
+
+                    if (isArray(arguments[i])) {
+                        var arr = arguments[i]
+                        for (var j = 0; j < arr.length; j++) {
+                            // immediately call the function if the deferred has been resolved
+                            if (status === 'resolved') {
+                                arr[j].apply(this, resultArgs)
+                            }
+
+                            doneFuncs.push(arr[j])
+                        }
+                    } else {
+                        // immediately call the function if the deferred has been resolved
+                        if (status === 'resolved') {
+                            arguments[i].apply(this, resultArgs)
+                        }
+
+                        doneFuncs.push(arguments[i])
+                    }
+                }
+
+                return this
+            },
+
+            fail: function () {
+                for (var i = 0; i < arguments.length; i++) {
+                    // skip any undefined or null arguments
+                    if (!arguments[i]) {
+                        continue
+                    }
+
+                    if (isArray(arguments[i])) {
+                        var arr = arguments[i]
+                        for (var j = 0; j < arr.length; j++) {
+                            // immediately call the function if the deferred has been resolved
+                            if (status === 'rejected') {
+                                arr[j].apply(this, resultArgs)
+                            }
+
+                            failFuncs.push(arr[j])
+                        }
+                    } else {
+                        // immediately call the function if the deferred has been resolved
+                        if (status === 'rejected') {
+                            arguments[i].apply(this, resultArgs)
+                        }
+
+                        failFuncs.push(arguments[i])
+                    }
+                }
+
+                return this
+            },
+
+            always: function () {
+                return this.done.apply(this, arguments).fail.apply(this, arguments)
+            },
+
+            progress: function () {
+                for (var i = 0; i < arguments.length; i++) {
+                    // skip any undefined or null arguments
+                    if (!arguments[i]) {
+                        continue
+                    }
+
+                    if (isArray(arguments[i])) {
+                        var arr = arguments[i]
+                        for (var j = 0; j < arr.length; j++) {
+                            // immediately call the function if the deferred has been resolved
+                            if (status === 'pending') {
+                                progressFuncs.push(arr[j])
+                            }
+                        }
+                    } else {
+                        // immediately call the function if the deferred has been resolved
+                        if (status === 'pending') {
+                            progressFuncs.push(arguments[i])
+                        }
+                    }
+                }
+
+                return this
+            },
+
+            then: function (done, fail, progress) {
+                /*
+                // fail callbacks
+                if (arguments.length > 1 && arguments[1]) {
+                    this.fail(arguments[1])
+                }
+
+                // done callbacks
+                if (arguments.length > 0 && arguments[0]) {
+                    this.done(arguments[0])
+                }
+
+                // notify callbacks
+                if (arguments.length > 2 && arguments[2]) {
+                    this.progress(arguments[2])
+                }
+
+                return this
+                */
+
+                return D(function (def) {
+                    foreach(done, function (func) {
+                        // filter function
+                        if (typeof func === 'function') {
+                            deferred.done(function () {
+                                var returnval = func.apply(this, arguments)
+                                // if a new deferred/promise is returned, its state is passed to the current deferred/promise
+                                if (returnval && typeof returnval === 'function') {
+                                    returnval.promise().then(def.resolve, def.reject, def.notify)
+                                } else {
+                                    // if new return val is passed, it is passed to the piped done
+                                    def.resolve(returnval)
+                                }
+                            })
+                        } else {
+                            deferred.done(def.resolve)
+                        }
+                    })
+
+                    foreach(fail, function (func) {
+                        if (typeof func === 'function') {
+                            deferred.fail(function () {
+                                var returnval = func.apply(this, arguments)
+
+                                if (returnval && typeof returnval === 'function') {
+                                    returnval.promise().then(def.resolve, def.reject, def.notify)
+                                } else {
+                                    def.reject(returnval)
+                                }
+                            })
+                        } else {
+                            deferred.fail(def.reject)
+                        }
+                    })
+                }).promise()
+            },
+            catch: function () {
+                for (var i = 0; i < arguments.length; i++) {
+                    // skip any undefined or null arguments
+                    if (!arguments[i]) {
+                        continue
+                    }
+
+                    if (isArray(arguments[i])) {
+                        var arr = arguments[i]
+                        for (var j = 0; j < arr.length; j++) {
+                            // immediately call the function if the deferred has been resolved
+                            if (status === 'rejected') {
+                                arr[j].apply(this, resultArgs)
+                            }
+
+                            failFuncs.push(arr[j])
+                        }
+                    } else {
+                        // immediately call the function if the deferred has been resolved
+                        if (status === 'rejected') {
+                            arguments[i].apply(this, resultArgs)
+                        }
+
+                        failFuncs.push(arguments[i])
+                    }
+                }
+
+                return this
+            },
+
+            promise: function (obj) {
+                if (obj == null) {
+                    return promise
+                } else {
+                    for (var i in promise) {
+                        obj[i] = promise[i]
+                    }
+                    return obj
+                }
+            },
+
+            state: function () {
+                return status
+            },
+
+            debug: function () {
+                console.log('[debug]', doneFuncs, failFuncs, status)
+            },
+
+            isRejected: function () {
+                return status === 'rejected'
+            },
+
+            isResolved: function () {
+                return status === 'resolved'
+            },
+
+            pipe: function (done, fail, progress) {
+                return D(function (def) {
+                    foreach(done, function (func) {
+                        // filter function
+                        if (typeof func === 'function') {
+                            deferred.done(function () {
+                                var returnval = func.apply(this, arguments)
+                                // if a new deferred/promise is returned, its state is passed to the current deferred/promise
+                                if (returnval && typeof returnval === 'function') {
+                                    returnval.promise().then(def.resolve, def.reject, def.notify)
+                                } else {
+                                    // if new return val is passed, it is passed to the piped done
+                                    def.resolve(returnval)
+                                }
+                            })
+                        } else {
+                            deferred.done(def.resolve)
+                        }
+                    })
+
+                    foreach(fail, function (func) {
+                        if (typeof func === 'function') {
+                            deferred.fail(function () {
+                                var returnval = func.apply(this, arguments)
+
+                                if (returnval && typeof returnval === 'function') {
+                                    returnval.promise().then(def.resolve, def.reject, def.notify)
+                                } else {
+                                    def.reject(returnval)
+                                }
+                            })
+                        } else {
+                            deferred.fail(def.reject)
+                        }
+                    })
+                }).promise()
+            },
+        },
+        deferred = {
+            resolveWith: function (context) {
+                if (status === 'pending') {
+                    status = 'resolved'
+                    var args = (resultArgs = arguments.length > 1 ? arguments[1] : [])
+                    for (var i = 0; i < doneFuncs.length; i++) {
+                        doneFuncs[i].apply(context, args)
+                    }
+                }
+                return this
+            },
+
+            rejectWith: function (context) {
+                if (status === 'pending') {
+                    status = 'rejected'
+                    var args = (resultArgs = arguments.length > 1 ? arguments[1] : [])
+                    for (var i = 0; i < failFuncs.length; i++) {
+                        failFuncs[i].apply(context, args)
+                    }
+                }
+                return this
+            },
+
+            notifyWith: function (context) {
+                if (status === 'pending') {
+                    var args = (resultArgs = arguments.length > 1 ? arguments[1] : [])
+                    for (var i = 0; i < progressFuncs.length; i++) {
+                        progressFuncs[i].apply(context, args)
+                    }
+                }
+                return this
+            },
+
+            resolve: function () {
+                return this.resolveWith(this, arguments)
+            },
+
+            reject: function () {
+                return this.rejectWith(this, arguments)
+            },
+
+            notify: function () {
+                return this.notifyWith(this, arguments)
+            },
+        }
+
+    var obj = promise.promise(deferred)
+
+    if (fn) {
+        fn.apply(obj, [obj])
+    }
+
+    return obj
+}
+
+D.when = function () {
+    if (arguments.length < 2) {
+        var obj = arguments.length ? arguments[0] : undefined
+        if (obj && typeof obj.isResolved === 'function' && typeof obj.isRejected === 'function') {
+            return obj.promise()
+        } else {
+            return D().resolve(obj).promise()
+        }
+    } else {
+        return (function (args) {
+            var df = D(),
+                size = args.length,
+                done = 0,
+                rp = new Array(size) // resolve params: params of each resolve, we need to track down them to be able to pass them in the correct order if the master needs to be resolved
+
+            for (var i = 0; i < args.length; i++) {
+                ;(function (j) {
+                    var obj = null
+
+                    if (args[j].done) {
+                        args[j]
+                            .done(function () {
+                                rp[j] = arguments.length < 2 ? arguments[0] : arguments
+                                if (++done == size) {
+                                    df.resolve.apply(df, rp)
+                                }
+                            })
+                            .fail(function () {
+                                df.reject(arguments)
+                            })
+                    } else {
+                        obj = args[j]
+                        args[j] = new Deferred()
+
+                        args[j]
+                            .done(function () {
+                                rp[j] = arguments.length < 2 ? arguments[0] : arguments
+                                if (++done == size) {
+                                    df.resolve.apply(df, rp)
+                                }
+                            })
+                            .fail(function () {
+                                df.reject(arguments)
+                            })
+                            .resolve(obj)
+                    }
+                })(i)
+            }
+
+            return df.promise()
+        })(arguments)
+    }
+}
+
+export const Defer = D
+
+export default function () {
+    return new D()
+}

+ 1 - 5
src/utils/math.js

@@ -1,7 +1,5 @@
 
-import * as THREE from "../../libs/three.js/build/three.module.js";
-import searchRings from "./searchRings.js";
-
+import * as THREE from "../../public/static/lib/three.js/build/three.module.js";
 
 
 var math = {
@@ -594,8 +592,6 @@ var math = {
 
 };
 
- 
-Potree.math = math
 
 
 export default math

+ 1 - 1
vue.config.js

@@ -28,7 +28,7 @@ const devServer = {
 
 const config = {
     assetsDir: 'static',
-    publicPath: process.env.VUE_APP_CDN_URL,
+    publicPath: '',
     outputDir: 'dist',//isDev ? 'dist' : path.resolve('../../dist/siter'),
     productionSourceMap: isDev,
     pages: {