mirror of
https://github.com/mickael-kerjean/filestash
synced 2025-12-06 08:22:24 +01:00
chore (plugin): revamp frontend plugin
This commit is contained in:
parent
fb29c7b6c2
commit
f4a99c4ad6
45 changed files with 179 additions and 18787 deletions
|
|
@ -1,5 +1,6 @@
|
|||
import rxjs from "../lib/rx.js";
|
||||
import ajax from "../lib/ajax.js";
|
||||
import { join } from "../lib/path.js";
|
||||
|
||||
let LNG = {};
|
||||
|
||||
|
|
@ -42,7 +43,7 @@ export async function init() {
|
|||
return Promise.resolve();
|
||||
}
|
||||
return ajax({
|
||||
url: "assets/locales/" + selectedLanguage + ".json",
|
||||
url: join(import.meta.url, selectedLanguage + ".json"),
|
||||
}).pipe(rxjs.tap(({ responseHeaders, response }) => {
|
||||
const contentType = responseHeaders["content-type"].trim();
|
||||
if (contentType === "application/json") {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import ctrlError from "../ctrl_error.js";
|
|||
import componentDownloader, { init as initDownloader } from "./application_downloader.js";
|
||||
import { renderMenubar, buttonDownload } from "./component_menubar.js";
|
||||
|
||||
import * as THREE from "../../../lib/vendor/three/three.module.js";
|
||||
import * as THREE from "../../lib/vendor/three/three.module.js";
|
||||
import setup3D from "./application_3d/init.js";
|
||||
import withLight from "./application_3d/scene_light.js";
|
||||
import withCube from "./application_3d/scene_cube.js";
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { createElement, onDestroy } from "../../../lib/skeleton/index.js";
|
||||
import { OrbitControls } from "../../../../lib/vendor/three/OrbitControls.js";
|
||||
import { OrbitControls } from "../../../lib/vendor/three/OrbitControls.js";
|
||||
|
||||
export default function({ THREE, $page, $menubar, mesh, refresh, is2D }) {
|
||||
// setup the dom
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { onDestroy } from "../../../lib/skeleton/index.js";
|
||||
import { ViewCubeGizmo, SimpleCameraControls, ObjectPosition } from "../../../../lib/vendor/three/viewcube.js";
|
||||
import { ViewCubeGizmo, SimpleCameraControls, ObjectPosition } from "../../../lib/vendor/three/viewcube.js";
|
||||
|
||||
export default function({ camera, renderer, refresh, controls }) {
|
||||
const viewCubeGizmo = new ViewCubeGizmo(camera, renderer, {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { settings_get } from "../../../lib/settings.js";
|
||||
import * as THREE from "../../../../lib/vendor/three/three.module.js";
|
||||
import * as THREE from "../../../lib/vendor/three/three.module.js";
|
||||
|
||||
const LIGHT_COLOR = 0xf5f5f5;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { createElement } from "../../../lib/skeleton/index.js";
|
||||
import { qs } from "../../../lib/dom.js";
|
||||
import * as THREE from "../../../../lib/vendor/three/three.module.js";
|
||||
import * as THREE from "../../../lib/vendor/three/three.module.js";
|
||||
|
||||
export default function(render, { camera, controls, mesh, $menubar, $toolbar, is2D }) {
|
||||
if (mesh.children.length <= 1) return;
|
||||
|
|
|
|||
|
|
@ -6,10 +6,10 @@ import t from "../../locales/index.js";
|
|||
import ctrlError from "../ctrl_error.js";
|
||||
|
||||
import { transition } from "./common.js";
|
||||
import { renderMenubar } from "./component_menubar.js";
|
||||
import "../../components/icon.js";
|
||||
import "./component_menubar.js";
|
||||
|
||||
export default async function(render, { acl$, getFilename, getDownloadUrl, hasMenubar = true }) {
|
||||
export default async function(render, { acl$, $menubar, getFilename, getDownloadUrl, hasMenubar = true }) {
|
||||
const $page = createElement(`
|
||||
<div class="component_filedownloader">
|
||||
<component-menubar filename="${getFilename()}" class="${!hasMenubar && "hidden"}"></component-menubar>
|
||||
|
|
@ -20,6 +20,7 @@ export default async function(render, { acl$, getFilename, getDownloadUrl, hasMe
|
|||
</div>
|
||||
`);
|
||||
render(transition($page));
|
||||
renderMenubar(qs($page, "component-menubar"));
|
||||
|
||||
const $link = qs($page, "a");
|
||||
const $loading = qs($page, "component-icon");
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import rxjs, { effect } from "../../lib/rx.js";
|
|||
import { animate, slideXIn, opacityOut } from "../../lib/animate.js";
|
||||
import { qs } from "../../lib/dom.js";
|
||||
import { get as getConfig } from "../../model/config.js";
|
||||
import { load as loadPlugin } from "../../model/plugin.js";
|
||||
import { createLoader } from "../../components/loader.js";
|
||||
import { createModal, MODAL_RIGHT_BUTTON } from "../../components/modal.js";
|
||||
import { loadCSS, loadJS } from "../../helpers/loader.js";
|
||||
|
|
@ -21,7 +22,9 @@ import "../../components/icon.js";
|
|||
|
||||
const TIME_BEFORE_ABORT_EDIT = 5000;
|
||||
|
||||
export default async function(render, { acl$, getFilename, getDownloadUrl }) {
|
||||
class IEditor {}
|
||||
|
||||
export default async function(render, { acl$, getFilename, getDownloadUrl, mime }) {
|
||||
const $page = createElement(`
|
||||
<div class="component_ide">
|
||||
<component-menubar filename="${getFilename()}" class="hidden"></component-menubar>
|
||||
|
|
@ -107,6 +110,11 @@ export default async function(render, { acl$, getFilename, getDownloadUrl }) {
|
|||
rxjs.tap((editor) => requestAnimationFrame(() => editor.refresh())),
|
||||
);
|
||||
}),
|
||||
rxjs.mergeMap(async (editor) => {
|
||||
const loader = await loadPlugin(mime);
|
||||
if (loader) new (await loader(IEditor, { mime, $menubar: $dom.menubar(), getFilename, getDownloadUrl }))(editor);
|
||||
return editor;
|
||||
}),
|
||||
rxjs.catchError(ctrlError()),
|
||||
rxjs.share(),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -40,8 +40,8 @@ export default async function(render, { mime, getDownloadUrl = nop, getFilename
|
|||
catch (err) { componentDownloader(render, { mime, acl$, getFilename, getDownloadUrl }); }
|
||||
return rxjs.EMPTY;
|
||||
}
|
||||
const mapImpl = new (await loader(IMap))(response, {
|
||||
map, $page, $menubar, L: window.L,
|
||||
const mapImpl = new (await loader(IMap, { mime, getDownloadUrl, getFilename, $menubar }))(response, {
|
||||
map, $page, L: window.L,
|
||||
});
|
||||
loadGeoJSON(map, await mapImpl.toGeoJSON());
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { loadCSS } from "../../helpers/loader.js";
|
|||
import { createLoader } from "../../components/loader.js";
|
||||
import ctrlError from "../ctrl_error.js";
|
||||
import componentDownloader, { init as initDownloader } from "./application_downloader.js";
|
||||
import { renderMenubar } from "./component_menubar.js";
|
||||
|
||||
export default function(render, { mime, getFilename, getDownloadUrl, acl$, hasMenubar = true }) {
|
||||
const $page = createElement(`
|
||||
|
|
@ -15,7 +16,7 @@ export default function(render, { mime, getFilename, getDownloadUrl, acl$, hasMe
|
|||
</div>
|
||||
`);
|
||||
render($page);
|
||||
const $menubar = qs($page, "component-menubar");
|
||||
const $menubar = renderMenubar(qs($page, "component-menubar"));
|
||||
const $container = qs($page, ".component_skeleton_container");
|
||||
const removeLoader = createLoader($container);
|
||||
effect(rxjs.from(loadPlugin(mime)).pipe(
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ export default async function(render, { mime, getDownloadUrl = nop, getFilename
|
|||
if (!loader) throw new TypeError(`unsupported mimetype "${mime}"`);
|
||||
const [, url] = loader;
|
||||
const module = await import(url);
|
||||
let table = new (await module.default(ITable))(response, { $menubar });
|
||||
let table = new (await module.default(ITable, { $menubar }))(response);
|
||||
if (typeof table.then === "function") table = await table;
|
||||
STATE.header = table.getHeader();
|
||||
STATE.body = table.getBody();
|
||||
|
|
|
|||
|
|
@ -37,11 +37,12 @@ self.addEventListener("activate", (event) => {
|
|||
})());
|
||||
});
|
||||
|
||||
self.addEventListener("fetch", (event) => {
|
||||
self.addEventListener("fetch", async (event) => {
|
||||
if (!event.request.url.startsWith(location.origin + "/assets/")) return;
|
||||
|
||||
event.respondWith((async() => {
|
||||
const cachedResponse = await caches.match(event.request);
|
||||
const cache = await caches.open(CACHENAME);
|
||||
const cachedResponse = await cache.match(event.request);
|
||||
if (cachedResponse) return cachedResponse;
|
||||
return fetch(event.request);
|
||||
})());
|
||||
|
|
@ -55,37 +56,36 @@ self.addEventListener("message", (event) => {
|
|||
);
|
||||
});
|
||||
|
||||
const handlePreloadMessage = (() => {
|
||||
return async(chunks, resolve, reject, id) => {
|
||||
const cleanup = [];
|
||||
try {
|
||||
caches.delete(CACHENAME);
|
||||
const cache = await caches.open(CACHENAME);
|
||||
await Promise.all(chunks.map((urls) => {
|
||||
return preload({ urls, cache, cleanup });
|
||||
}));
|
||||
resolve();
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
} finally {
|
||||
cleanup.forEach((fn) => fn());
|
||||
}
|
||||
};
|
||||
})();
|
||||
async function handlePreloadMessage(chunks, resolve, reject, id) {
|
||||
const cleanup = [];
|
||||
try {
|
||||
await caches.delete(CACHENAME);
|
||||
const cache = await caches.open(CACHENAME);
|
||||
await Promise.all(chunks.map((urls) => {
|
||||
return preload({ urls, cache, cleanup });
|
||||
}));
|
||||
resolve();
|
||||
} catch (err) {
|
||||
console.log("ERR", err);
|
||||
reject(err);
|
||||
} finally {
|
||||
cleanup.forEach((fn) => fn());
|
||||
}
|
||||
};
|
||||
|
||||
async function preload({ urls, cache, cleanup }) {
|
||||
const evtsrc = new self.EventSource("/assets/bundle?" + urls.map((url) => `url=${url}`).join("&"));
|
||||
cleanup.push(() => evtsrc.close());
|
||||
|
||||
let i = 0;
|
||||
const messageHandler = (resolve, event, decoder) => {
|
||||
const messageHandler = async (resolve, event, decoder) => {
|
||||
const url = event.lastEventId;
|
||||
let mime = "application/octet-stream";
|
||||
if (url.endsWith(".css")) mime = "text/css";
|
||||
else if (url.endsWith(".js")) mime = "application/javascript";
|
||||
|
||||
i += 1;
|
||||
cache.put(
|
||||
await cache.put(
|
||||
location.origin + url,
|
||||
new Response(
|
||||
decoder(new Blob([Uint8Array.from(atob(event.data), (c) => c.charCodeAt(0))]).stream()),
|
||||
|
|
@ -111,6 +111,9 @@ async function preload({ urls, cache, cleanup }) {
|
|||
event,
|
||||
(stream) => stream.pipeThrough(new DecompressionStream("gzip")),
|
||||
));
|
||||
evtsrc.onerror = (err) => errorHandler(reject, err);
|
||||
evtsrc.onerror = (err) => {
|
||||
if (i === urls.length) return;
|
||||
errorHandler(reject, err);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,129 +38,16 @@
|
|||
<script type="module" src="./assets/{{ .version }}/components/notification.js" defer></script>
|
||||
</template>
|
||||
|
||||
<script id="preload" type="application/json">{{ .preload }}</script>
|
||||
|
||||
<script type="module">
|
||||
function boot() {
|
||||
document.head.appendChild(document.querySelector("template#head").content);
|
||||
document.body.appendChild(document.querySelector("template#body").content);
|
||||
}
|
||||
|
||||
const URLS = [
|
||||
[
|
||||
"/assets/{{ .version }}/lib/vendor/rxjs/rxjs.min.js",
|
||||
"/assets/{{ .version }}/lib/vendor/rxjs/rxjs-ajax.min.js",
|
||||
"/assets/{{ .version }}/lib/vendor/rxjs/rxjs-shared.min.js",
|
||||
],
|
||||
[
|
||||
"/assets/{{ .version }}/boot/ctrl_boot_frontoffice.js",
|
||||
"/assets/{{ .version }}/locales/index.js",
|
||||
"/assets/{{ .version }}/css/designsystem.css",
|
||||
"/assets/{{ .version }}/css/designsystem_input.css",
|
||||
"/assets/{{ .version }}/css/designsystem_textarea.css",
|
||||
"/assets/{{ .version }}/css/designsystem_inputgroup.css",
|
||||
"/assets/{{ .version }}/css/designsystem_checkbox.css",
|
||||
"/assets/{{ .version }}/css/designsystem_formbuilder.css",
|
||||
"/assets/{{ .version }}/css/designsystem_button.css",
|
||||
"/assets/{{ .version }}/css/designsystem_icon.css",
|
||||
"/assets/{{ .version }}/css/designsystem_dropdown.css",
|
||||
"/assets/{{ .version }}/css/designsystem_container.css",
|
||||
"/assets/{{ .version }}/css/designsystem_box.css",
|
||||
"/assets/{{ .version }}/css/designsystem_darkmode.css",
|
||||
"/assets/{{ .version }}/css/designsystem_skeleton.css",
|
||||
"/assets/{{ .version }}/css/designsystem_utils.css",
|
||||
"/assets/{{ .version }}/css/designsystem_alert.css",
|
||||
"/assets/{{ .version }}/components/loader.js",
|
||||
"/assets/{{ .version }}/components/modal.js",
|
||||
"/assets/{{ .version }}/components/modal.css",
|
||||
"/assets/{{ .version }}/components/notification.js",
|
||||
"/assets/{{ .version }}/components/notification.css",
|
||||
"/assets/{{ .version }}/boot/router_frontoffice.js",
|
||||
"/assets/{{ .version }}/helpers/loader.js",
|
||||
"/assets/{{ .version }}/lib/skeleton/index.js",
|
||||
"/assets/{{ .version }}/lib/rx.js",
|
||||
"/assets/{{ .version }}/lib/ajax.js",
|
||||
"/assets/{{ .version }}/lib/animate.js",
|
||||
"/assets/{{ .version }}/lib/assert.js",
|
||||
"/assets/{{ .version }}/lib/dom.js",
|
||||
"/assets/{{ .version }}/lib/skeleton/router.js",
|
||||
"/assets/{{ .version }}/lib/skeleton/lifecycle.js",
|
||||
"/assets/{{ .version }}/lib/error.js",
|
||||
"/assets/{{ .version }}/model/config.js",
|
||||
"/assets/{{ .version }}/model/plugin.js",
|
||||
"/assets/{{ .version }}/model/chromecast.js",
|
||||
"/assets/{{ .version }}/model/session.js",
|
||||
"/assets/{{ .version }}/helpers/log.js",
|
||||
"/assets/{{ .version }}/boot/common.js",
|
||||
"/assets/{{ .version }}/helpers/sdk.js",
|
||||
|
||||
"/assets/{{ .version }}/components/breadcrumb.js",
|
||||
"/assets/{{ .version }}/components/breadcrumb.css",
|
||||
"/assets/{{ .version }}/components/form.js",
|
||||
"/assets/{{ .version }}/components/sidebar.js",
|
||||
"/assets/{{ .version }}/components/sidebar.css",
|
||||
"/assets/{{ .version }}/components/dropdown.js",
|
||||
"/assets/{{ .version }}/components/icon.js",
|
||||
"/assets/{{ .version }}/lib/store.js",
|
||||
"/assets/{{ .version }}/lib/random.js",
|
||||
"/assets/{{ .version }}/lib/form.js",
|
||||
"/assets/{{ .version }}/lib/path.js",
|
||||
|
||||
"/assets/{{ .version }}/components/decorator_shell_filemanager.js",
|
||||
"/assets/{{ .version }}/components/decorator_shell_filemanager.css",
|
||||
"/assets/{{ .version }}/pages/ctrl_error.js",
|
||||
],
|
||||
[
|
||||
"/assets/{{ .version }}/pages/ctrl_connectpage.js",
|
||||
"/assets/{{ .version }}/pages/connectpage/ctrl_form.js",
|
||||
"/assets/{{ .version }}/pages/connectpage/ctrl_forkme.js",
|
||||
"/assets/{{ .version }}/pages/connectpage/ctrl_poweredby.js",
|
||||
"/assets/{{ .version }}/lib/path.js",
|
||||
"/assets/{{ .version }}/lib/form.js",
|
||||
"/assets/{{ .version }}/lib/settings.js",
|
||||
"/assets/{{ .version }}/components/form.js",
|
||||
"/assets/{{ .version }}/model/session.js",
|
||||
"/assets/{{ .version }}/pages/ctrl_error.js",
|
||||
"/assets/{{ .version }}/pages/connectpage/model_backend.js",
|
||||
"/assets/{{ .version }}/pages/connectpage/model_config.js",
|
||||
"/assets/{{ .version }}/pages/connectpage/ctrl_form_state.js",
|
||||
"/assets/{{ .version }}/lib/random.js",
|
||||
"/assets/{{ .version }}/components/icon.js",
|
||||
|
||||
"/assets/{{ .version }}/pages/ctrl_connectpage.css",
|
||||
"/assets/{{ .version }}/pages/connectpage/ctrl_form.css",
|
||||
],
|
||||
[
|
||||
"/assets/{{ .version }}/pages/ctrl_filespage.js",
|
||||
"/assets/{{ .version }}/pages/ctrl_filespage.css",
|
||||
"/assets/{{ .version }}/pages/filespage/ctrl_filesystem.js",
|
||||
"/assets/{{ .version }}/pages/filespage/ctrl_submenu.js",
|
||||
"/assets/{{ .version }}/pages/filespage/ctrl_newitem.js",
|
||||
"/assets/{{ .version }}/pages/filespage/ctrl_upload.js",
|
||||
"/assets/{{ .version }}/pages/filespage/cache.js",
|
||||
"/assets/{{ .version }}/pages/filespage/state_config.js",
|
||||
"/assets/{{ .version }}/pages/filespage/thing.js",
|
||||
"/assets/{{ .version }}/pages/filespage/state_newthing.js",
|
||||
"/assets/{{ .version }}/pages/filespage/helper.js",
|
||||
"/assets/{{ .version }}/pages/filespage/model_files.js",
|
||||
"/assets/{{ .version }}/pages/filespage/model_virtual_layer.js",
|
||||
"/assets/{{ .version }}/pages/filespage/modal_share.js",
|
||||
"/assets/{{ .version }}/pages/filespage/modal_tag.js",
|
||||
"/assets/{{ .version }}/pages/filespage/modal_rename.js",
|
||||
"/assets/{{ .version }}/pages/filespage/modal_delete.js",
|
||||
"/assets/{{ .version }}/pages/filespage/state_selection.js",
|
||||
"/assets/{{ .version }}/pages/filespage/model_acl.js",
|
||||
|
||||
"/assets/{{ .version }}/pages/filespage/ctrl_filesystem.css",
|
||||
"/assets/{{ .version }}/pages/filespage/thing.css",
|
||||
"/assets/{{ .version }}/pages/filespage/modal.css",
|
||||
"/assets/{{ .version }}/pages/filespage/ctrl_submenu.css",
|
||||
"/assets/{{ .version }}/pages/filespage/modal_share.css",
|
||||
"/assets/{{ .version }}/pages/filespage/modal_tag.css",
|
||||
"/assets/{{ .version }}/pages/filespage/ctrl_newitem.css",
|
||||
"/assets/{{ .version }}/pages/filespage/ctrl_upload.css",
|
||||
],
|
||||
];
|
||||
|
||||
if ("serviceWorker" in navigator) {
|
||||
const URLS = JSON.parse(document.getElementById("preload").textContent);
|
||||
try {
|
||||
const register = await navigator.serviceWorker.register("sw.js");
|
||||
await new Promise((resolve) => {
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ func PluginExportHandler(ctx *App, res http.ResponseWriter, req *http.Request) {
|
|||
}
|
||||
plgExports[module["mime"]] = []string{
|
||||
module["application"],
|
||||
WithBase(JoinPath("/plugin/", filepath.Join(name, index))),
|
||||
WithBase(JoinPath("/assets/"+BUILD_REF+"/plugin/", filepath.Join(name+".zip", index))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"bytes"
|
||||
_ "embed"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
|
|
@ -233,11 +234,6 @@ func ServeFile(chroot string) func(*App, http.ResponseWriter, *http.Request) {
|
|||
)
|
||||
head := res.Header()
|
||||
|
||||
if filePath == "/assets/bundle" {
|
||||
ServeBundle(ctx, res, req)
|
||||
return
|
||||
}
|
||||
|
||||
// case: patch must be apply because of a "StaticPatch" plugin
|
||||
if f := applyPatch(filePath); f != nil {
|
||||
head.Set("Content-Type", GetMimeType(filepath.Ext(filePath)))
|
||||
|
|
@ -311,13 +307,13 @@ func ServeIndex(indexPath string) func(*App, http.ResponseWriter, *http.Request)
|
|||
}
|
||||
head.Set("Content-Type", "text/html")
|
||||
res.WriteHeader(http.StatusOK)
|
||||
|
||||
tmpl := template.Must(template.New(indexPath).Parse(string(b)))
|
||||
tmpl = template.Must(tmpl.Parse(string(TmplLoader)))
|
||||
tmpl.Execute(res, map[string]any{
|
||||
"base": WithBase("/"),
|
||||
"version": BUILD_REF,
|
||||
"license": LICENSE,
|
||||
"preload": preload(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -429,3 +425,123 @@ func InitPluginList(code []byte) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func preload() string {
|
||||
out, _ := json.Marshal([][]string{
|
||||
{
|
||||
"/assets/" + BUILD_REF + "/lib/vendor/rxjs/rxjs.min.js",
|
||||
"/assets/" + BUILD_REF + "/lib/vendor/rxjs/rxjs-ajax.min.js",
|
||||
"/assets/" + BUILD_REF + "/lib/vendor/rxjs/rxjs-shared.min.js",
|
||||
},
|
||||
{
|
||||
"/assets/" + BUILD_REF + "/boot/ctrl_boot_frontoffice.js",
|
||||
"/assets/" + BUILD_REF + "/locales/index.js",
|
||||
"/assets/" + BUILD_REF + "/css/designsystem.css",
|
||||
"/assets/" + BUILD_REF + "/css/designsystem_input.css",
|
||||
"/assets/" + BUILD_REF + "/css/designsystem_textarea.css",
|
||||
"/assets/" + BUILD_REF + "/css/designsystem_inputgroup.css",
|
||||
"/assets/" + BUILD_REF + "/css/designsystem_checkbox.css",
|
||||
"/assets/" + BUILD_REF + "/css/designsystem_formbuilder.css",
|
||||
"/assets/" + BUILD_REF + "/css/designsystem_button.css",
|
||||
"/assets/" + BUILD_REF + "/css/designsystem_icon.css",
|
||||
"/assets/" + BUILD_REF + "/css/designsystem_dropdown.css",
|
||||
"/assets/" + BUILD_REF + "/css/designsystem_container.css",
|
||||
"/assets/" + BUILD_REF + "/css/designsystem_box.css",
|
||||
"/assets/" + BUILD_REF + "/css/designsystem_darkmode.css",
|
||||
"/assets/" + BUILD_REF + "/css/designsystem_skeleton.css",
|
||||
"/assets/" + BUILD_REF + "/css/designsystem_utils.css",
|
||||
"/assets/" + BUILD_REF + "/css/designsystem_alert.css",
|
||||
"/assets/" + BUILD_REF + "/components/loader.js",
|
||||
"/assets/" + BUILD_REF + "/components/modal.js",
|
||||
"/assets/" + BUILD_REF + "/components/modal.css",
|
||||
"/assets/" + BUILD_REF + "/components/notification.js",
|
||||
"/assets/" + BUILD_REF + "/components/notification.css",
|
||||
"/assets/" + BUILD_REF + "/boot/router_frontoffice.js",
|
||||
"/assets/" + BUILD_REF + "/helpers/loader.js",
|
||||
"/assets/" + BUILD_REF + "/lib/skeleton/index.js",
|
||||
"/assets/" + BUILD_REF + "/lib/rx.js",
|
||||
"/assets/" + BUILD_REF + "/lib/ajax.js",
|
||||
"/assets/" + BUILD_REF + "/lib/animate.js",
|
||||
"/assets/" + BUILD_REF + "/lib/assert.js",
|
||||
"/assets/" + BUILD_REF + "/lib/dom.js",
|
||||
"/assets/" + BUILD_REF + "/lib/skeleton/router.js",
|
||||
"/assets/" + BUILD_REF + "/lib/skeleton/lifecycle.js",
|
||||
"/assets/" + BUILD_REF + "/lib/error.js",
|
||||
"/assets/" + BUILD_REF + "/model/config.js",
|
||||
"/assets/" + BUILD_REF + "/model/plugin.js",
|
||||
"/assets/" + BUILD_REF + "/model/chromecast.js",
|
||||
"/assets/" + BUILD_REF + "/model/session.js",
|
||||
"/assets/" + BUILD_REF + "/helpers/log.js",
|
||||
"/assets/" + BUILD_REF + "/boot/common.js",
|
||||
"/assets/" + BUILD_REF + "/helpers/sdk.js",
|
||||
|
||||
"/assets/" + BUILD_REF + "/components/breadcrumb.js",
|
||||
"/assets/" + BUILD_REF + "/components/breadcrumb.css",
|
||||
"/assets/" + BUILD_REF + "/components/form.js",
|
||||
"/assets/" + BUILD_REF + "/components/sidebar.js",
|
||||
"/assets/" + BUILD_REF + "/components/sidebar.css",
|
||||
"/assets/" + BUILD_REF + "/components/dropdown.js",
|
||||
"/assets/" + BUILD_REF + "/components/icon.js",
|
||||
"/assets/" + BUILD_REF + "/lib/store.js",
|
||||
"/assets/" + BUILD_REF + "/lib/random.js",
|
||||
"/assets/" + BUILD_REF + "/lib/form.js",
|
||||
"/assets/" + BUILD_REF + "/lib/path.js",
|
||||
|
||||
"/assets/" + BUILD_REF + "/components/decorator_shell_filemanager.js",
|
||||
"/assets/" + BUILD_REF + "/components/decorator_shell_filemanager.css",
|
||||
"/assets/" + BUILD_REF + "/pages/ctrl_error.js",
|
||||
},
|
||||
{
|
||||
"/assets/" + BUILD_REF + "/pages/ctrl_connectpage.js",
|
||||
"/assets/" + BUILD_REF + "/pages/ctrl_connectpage.css",
|
||||
"/assets/" + BUILD_REF + "/pages/connectpage/ctrl_form.js",
|
||||
"/assets/" + BUILD_REF + "/pages/connectpage/ctrl_forkme.js",
|
||||
"/assets/" + BUILD_REF + "/pages/connectpage/ctrl_poweredby.js",
|
||||
"/assets/" + BUILD_REF + "/pages/connectpage/ctrl_form.css",
|
||||
|
||||
"/assets/" + BUILD_REF + "/lib/path.js",
|
||||
"/assets/" + BUILD_REF + "/lib/form.js",
|
||||
"/assets/" + BUILD_REF + "/lib/settings.js",
|
||||
"/assets/" + BUILD_REF + "/components/form.js",
|
||||
"/assets/" + BUILD_REF + "/model/session.js",
|
||||
"/assets/" + BUILD_REF + "/pages/ctrl_error.js",
|
||||
"/assets/" + BUILD_REF + "/pages/connectpage/model_backend.js",
|
||||
"/assets/" + BUILD_REF + "/pages/connectpage/model_config.js",
|
||||
"/assets/" + BUILD_REF + "/pages/connectpage/ctrl_form_state.js",
|
||||
"/assets/" + BUILD_REF + "/lib/random.js",
|
||||
"/assets/" + BUILD_REF + "/components/icon.js",
|
||||
|
||||
"/assets/" + BUILD_REF + "/pages/filespage/ctrl_filesystem.css",
|
||||
"/assets/" + BUILD_REF + "/pages/filespage/thing.css",
|
||||
"/assets/" + BUILD_REF + "/pages/filespage/ctrl_filesystem.js",
|
||||
"/assets/" + BUILD_REF + "/pages/filespage/thing.js",
|
||||
"/assets/" + BUILD_REF + "/pages/filespage/state_newthing.js",
|
||||
},
|
||||
{
|
||||
"/assets/" + BUILD_REF + "/pages/ctrl_filespage.js",
|
||||
"/assets/" + BUILD_REF + "/pages/ctrl_filespage.css",
|
||||
"/assets/" + BUILD_REF + "/pages/filespage/ctrl_submenu.js",
|
||||
"/assets/" + BUILD_REF + "/pages/filespage/ctrl_newitem.js",
|
||||
"/assets/" + BUILD_REF + "/pages/filespage/ctrl_upload.js",
|
||||
"/assets/" + BUILD_REF + "/pages/filespage/cache.js",
|
||||
"/assets/" + BUILD_REF + "/pages/filespage/state_config.js",
|
||||
"/assets/" + BUILD_REF + "/pages/filespage/helper.js",
|
||||
"/assets/" + BUILD_REF + "/pages/filespage/model_files.js",
|
||||
"/assets/" + BUILD_REF + "/pages/filespage/model_virtual_layer.js",
|
||||
"/assets/" + BUILD_REF + "/pages/filespage/modal_share.js",
|
||||
"/assets/" + BUILD_REF + "/pages/filespage/modal_tag.js",
|
||||
"/assets/" + BUILD_REF + "/pages/filespage/modal_rename.js",
|
||||
"/assets/" + BUILD_REF + "/pages/filespage/modal_delete.js",
|
||||
"/assets/" + BUILD_REF + "/pages/filespage/state_selection.js",
|
||||
"/assets/" + BUILD_REF + "/pages/filespage/model_acl.js",
|
||||
|
||||
"/assets/" + BUILD_REF + "/pages/filespage/modal.css",
|
||||
"/assets/" + BUILD_REF + "/pages/filespage/ctrl_submenu.css",
|
||||
"/assets/" + BUILD_REF + "/pages/filespage/modal_share.css",
|
||||
"/assets/" + BUILD_REF + "/pages/filespage/modal_tag.css",
|
||||
"/assets/" + BUILD_REF + "/pages/filespage/ctrl_newitem.css",
|
||||
"/assets/" + BUILD_REF + "/pages/filespage/ctrl_upload.css",
|
||||
},
|
||||
})
|
||||
return string(out)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
all:
|
||||
make install
|
||||
|
||||
install:
|
||||
zip -r application_3d.zip .
|
||||
mv application_3d.zip ../../../dist/data/state/plugins/application_3d.zip
|
||||
|
||||
deps_mesh:
|
||||
[ -d vendor ] || mkdir vendor
|
||||
curl https://gist.githubusercontent.com/mickael-kerjean/9a517f95112410fcacaad8563c1ba314/raw/ab483b38aebb7048832aad7b342f9161dd928e49/gistfile1.txt > vendor/MeshLoader.js
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
export default async function(I3D, { THREE }) {
|
||||
const module = await import("./vendor/FBXLoader.js");
|
||||
|
||||
return class Impl extends I3D {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
load(url, onLoad, onProgress, onError) {
|
||||
return (new module.FBXLoader()).load(url, onLoad, onProgress, onError);
|
||||
}
|
||||
|
||||
transform(obj) {
|
||||
obj.name = "All";
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
export default async function(I3D, { THREE }) {
|
||||
const module = await import("./vendor/GLTFLoader.js");
|
||||
|
||||
return class Impl extends I3D {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
load(url, onLoad, onProgress, onError) {
|
||||
return new module.GLTFLoader().load(url, onLoad, onProgress, onError);
|
||||
}
|
||||
|
||||
transform(gltf) {
|
||||
const mesh = gltf.scene;
|
||||
mesh.animations = gltf.animations;
|
||||
return mesh;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
export default async function(I3D, { THREE }) {
|
||||
const module = await import("./vendor/MeshLoader.js");
|
||||
|
||||
return class Impl extends I3D {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
load(url, onLoad, onProgress, onError) {
|
||||
return (new module.MeshLoader()).load(url, onLoad, onProgress, onError);
|
||||
}
|
||||
|
||||
transform(obj) {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
import { toCreasedNormals } from "./vendor/utils/BufferGeometryUtils.js";
|
||||
|
||||
export default async function(I3D, { THREE }) {
|
||||
const module = await import("./vendor/OBJLoader.js");
|
||||
|
||||
return class Impl extends I3D {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
load(url, onLoad, onProgress, onError) {
|
||||
return (new module.OBJLoader()).load(url, onLoad, onProgress, onError);
|
||||
}
|
||||
|
||||
transform(obj) {
|
||||
obj.name = "All";
|
||||
obj.traverse((child) => {
|
||||
if (child.isMesh) {
|
||||
child.material = new THREE.MeshPhongMaterial({
|
||||
color: 0x40464b,
|
||||
emissive: 0x40464b,
|
||||
specular: 0xf9f9fa,
|
||||
shininess: 10,
|
||||
transparent: true,
|
||||
});
|
||||
// smooth the edges: https://discourse.threejs.org/t/how-to-smooth-an-obj-with-threejs/3950/16
|
||||
child.geometry = toCreasedNormals(child.geometry, (30 / 180) * Math.PI);
|
||||
}
|
||||
});
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,102 +0,0 @@
|
|||
import { loadJS } from "../../assets/helpers/loader.js";
|
||||
|
||||
await loadJS("https://cdn.jsdelivr.net", "/npm/occt-import-js@0.0.22/dist/occt-import-js.min.js");
|
||||
|
||||
async function LoadGeometry(url) {
|
||||
const occt = await occtimportjs()
|
||||
let fileUrl = "https://raw.githubusercontent.com/kovacsv/occt-import-js/main/test/testfiles/cax-if/as1_pe_203.stp"
|
||||
// let response = await fetch(fileUrl)
|
||||
let response = await fetch(url)
|
||||
let buffer = await response.arrayBuffer()
|
||||
let fileBuffer = new Uint8Array(buffer)
|
||||
return occt.ReadStepFile(fileBuffer, null);
|
||||
}
|
||||
|
||||
export default async function(I3D, { THREE }) {
|
||||
return class Impl extends I3D {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
load(url, onLoad, onProgress, onError) {
|
||||
LoadGeometry(url)
|
||||
.then(({ success, ...obj }) => {
|
||||
if (success === false) throw new Error("NOT SUPPORTED");
|
||||
onLoad(obj);
|
||||
})
|
||||
.catch((err) => onError(err));
|
||||
}
|
||||
|
||||
transform({ root, meshes }) {
|
||||
const group = new THREE.Group();
|
||||
|
||||
const recurse = ({ meshes: m, children, name}) => {
|
||||
if (m.length > 0) {
|
||||
const obj = new THREE.Object3D();
|
||||
obj.name = name;
|
||||
for (let i=0; i<m.length; i++) {
|
||||
const resultMesh = meshes[m[i]];
|
||||
console.log(name, resultMesh);
|
||||
let geometry = new THREE.BufferGeometry()
|
||||
geometry.setAttribute(
|
||||
"position",
|
||||
new THREE.Float32BufferAttribute(resultMesh.attributes.position.array, 3),
|
||||
)
|
||||
if (resultMesh.attributes.normal) geometry.setAttribute(
|
||||
"normal",
|
||||
new THREE.Float32BufferAttribute(resultMesh.attributes.normal.array, 3),
|
||||
);
|
||||
geometry.setIndex(new THREE.BufferAttribute(
|
||||
Uint32Array.from(resultMesh.index.array),
|
||||
1,
|
||||
));
|
||||
let material = null
|
||||
if (resultMesh.color) material = new THREE.MeshPhongMaterial({ color: new THREE.Color(
|
||||
resultMesh.color[0],
|
||||
resultMesh.color[1],
|
||||
resultMesh.color[2],
|
||||
)});
|
||||
else material = new THREE.MeshPhongMaterial({ color: 0xcccccc });
|
||||
obj.add(new THREE.Mesh(geometry, material));
|
||||
}
|
||||
group.add(obj);
|
||||
}
|
||||
if (children.length > 0) children.forEach((obj) => recurse(obj));
|
||||
}
|
||||
root.children.forEach(recurse);
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
transformOld({ meshes, root }) {
|
||||
console.log(meshes, root)
|
||||
const targetObject = new THREE.Object3D();
|
||||
for (let resultMesh of meshes) {
|
||||
let geometry = new THREE.BufferGeometry()
|
||||
geometry.setAttribute(
|
||||
"position",
|
||||
new THREE.Float32BufferAttribute(resultMesh.attributes.position.array, 3),
|
||||
)
|
||||
if (resultMesh.attributes.normal) geometry.setAttribute(
|
||||
"normal",
|
||||
new THREE.Float32BufferAttribute(resultMesh.attributes.normal.array, 3),
|
||||
);
|
||||
geometry.setIndex(new THREE.BufferAttribute(
|
||||
Uint32Array.from(resultMesh.index.array),
|
||||
1,
|
||||
));
|
||||
|
||||
let material = null
|
||||
if (resultMesh.color) material = new THREE.MeshPhongMaterial({ color: new THREE.Color(
|
||||
resultMesh.color[0],
|
||||
resultMesh.color[1],
|
||||
resultMesh.color[2],
|
||||
)});
|
||||
else material = new THREE.MeshPhongMaterial({ color: 0xcccccc });
|
||||
|
||||
targetObject.add(new THREE.Mesh(geometry, material));
|
||||
}
|
||||
return targetObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
export default async function(I3D, { THREE }) {
|
||||
const module = await import("./vendor/STLLoader.js");
|
||||
|
||||
return class Impl extends I3D {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
load(url, onLoad, onProgress, onError) {
|
||||
return (new module.STLLoader()).load(url, onLoad, onProgress, onError);
|
||||
}
|
||||
|
||||
transform(geometry) {
|
||||
const material = new THREE.MeshPhongMaterial({
|
||||
emissive: 0x40464b,
|
||||
specular: 0xf9f9fa,
|
||||
shininess: 15,
|
||||
transparent: true,
|
||||
});
|
||||
if (geometry.hasColors) material.vertexColors = true;
|
||||
else material.color = material.emissive;
|
||||
return new THREE.Mesh(geometry, material);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
export default async function(I3D, { THREE }) {
|
||||
const module = await import("./vendor/SVGLoader.js");
|
||||
|
||||
const threecolor = (color) => {
|
||||
if (color && color.substr && color.substr(0, 4) === "RGB(") {
|
||||
function componentToHex(c) {
|
||||
const hex = c.toString(16);
|
||||
return hex.length === 1 ? "0" + hex : hex;
|
||||
}
|
||||
const [r, g, b] = color.replace(/^RGB\(/, "").replace(/\)/, "").split(",").map((i) => parseInt(i));
|
||||
return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
|
||||
}
|
||||
return color;
|
||||
};
|
||||
|
||||
const createMaterial = (color, opacity = 1) => new THREE.MeshBasicMaterial({
|
||||
color: new THREE.Color().setStyle(color),
|
||||
opacity,
|
||||
transparent: true,
|
||||
side: THREE.DoubleSide,
|
||||
depthWrite: false,
|
||||
wireframe: false,
|
||||
});
|
||||
|
||||
return class Impl extends I3D {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
load(url, onLoad, onProgress, onError) {
|
||||
return (new module.SVGLoader()).load(url, onLoad, onProgress, onError);
|
||||
}
|
||||
|
||||
transform(data) {
|
||||
const group = new THREE.Group();
|
||||
group.name = "All";
|
||||
group.scale.y *= -1;
|
||||
let renderOrder = 0;
|
||||
for (const path of data.paths) {
|
||||
const fillColor = threecolor(path.userData.style.fill);
|
||||
if (fillColor !== undefined && fillColor !== "none") {
|
||||
const material = createMaterial(
|
||||
fillColor,
|
||||
path.userData.style.fillOpacity,
|
||||
);
|
||||
const shapes = module.SVGLoader.createShapes(path);
|
||||
for (const shape of shapes) {
|
||||
const mesh = new THREE.Mesh(
|
||||
new THREE.ShapeGeometry(shape),
|
||||
material,
|
||||
);
|
||||
mesh.renderOrder = renderOrder++;
|
||||
group.add(mesh);
|
||||
}
|
||||
}
|
||||
const strokeColor = threecolor(path.userData.style.stroke);
|
||||
if (strokeColor !== undefined && strokeColor !== "none") {
|
||||
const material = createMaterial(strokeColor);
|
||||
for (const subPath of path.subPaths) {
|
||||
const geometry = module.SVGLoader.pointsToStroke(subPath.getPoints(), path.userData.style);
|
||||
if (geometry) {
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
mesh.renderOrder = renderOrder++;
|
||||
group.add(mesh);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return group;
|
||||
}
|
||||
|
||||
is2D() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
{
|
||||
"author": "Filestash Pty Ltd",
|
||||
"version": "v0.0",
|
||||
"modules": [
|
||||
{
|
||||
"type": "xdg-open",
|
||||
"mime": "application/fbx",
|
||||
"entrypoint": "/index_fbx.js",
|
||||
"application": "3d"
|
||||
},
|
||||
{
|
||||
"type": "xdg-open",
|
||||
"mime": "model/gltf-binary",
|
||||
"entrypoint": "/index_gltf.js",
|
||||
"application": "3d"
|
||||
},
|
||||
{
|
||||
"type": "xdg-open",
|
||||
"mime": "application/object",
|
||||
"entrypoint": "/index_obj.js",
|
||||
"application": "3d"
|
||||
},
|
||||
{
|
||||
"type": "xdg-open",
|
||||
"mime": "model/stl",
|
||||
"entrypoint": "/index_stl.js",
|
||||
"application": "3d"
|
||||
},
|
||||
{
|
||||
"type": "xdg-open",
|
||||
"mime": "image/svg+xml",
|
||||
"entrypoint": "/index_svg.js",
|
||||
"application": "3d"
|
||||
},
|
||||
{
|
||||
"type": "xdg-open",
|
||||
"mime": "model/step",
|
||||
"entrypoint": "/index_step.js",
|
||||
"application": "3d"
|
||||
},
|
||||
{
|
||||
"type": "xdg-open",
|
||||
"mime": "model/mesh",
|
||||
"entrypoint": "/index_mesh.js",
|
||||
"application": "3d"
|
||||
}
|
||||
]
|
||||
}
|
||||
4315
server/plugin/plg_application_3d/vendor/FBXLoader.js
vendored
4315
server/plugin/plg_application_3d/vendor/FBXLoader.js
vendored
File diff suppressed because it is too large
Load diff
4664
server/plugin/plg_application_3d/vendor/GLTFLoader.js
vendored
4664
server/plugin/plg_application_3d/vendor/GLTFLoader.js
vendored
File diff suppressed because it is too large
Load diff
906
server/plugin/plg_application_3d/vendor/OBJLoader.js
vendored
906
server/plugin/plg_application_3d/vendor/OBJLoader.js
vendored
|
|
@ -1,906 +0,0 @@
|
|||
// @ts-nocheck
|
||||
import {
|
||||
BufferGeometry,
|
||||
FileLoader,
|
||||
Float32BufferAttribute,
|
||||
Group,
|
||||
LineBasicMaterial,
|
||||
LineSegments,
|
||||
Loader,
|
||||
Material,
|
||||
Mesh,
|
||||
MeshPhongMaterial,
|
||||
Points,
|
||||
PointsMaterial,
|
||||
Vector3,
|
||||
Color
|
||||
} from '../../../assets/lib/vendor/three/three.module.js';
|
||||
|
||||
// o object_name | g group_name
|
||||
const _object_pattern = /^[og]\s*(.+)?/;
|
||||
// mtllib file_reference
|
||||
const _material_library_pattern = /^mtllib /;
|
||||
// usemtl material_name
|
||||
const _material_use_pattern = /^usemtl /;
|
||||
// usemap map_name
|
||||
const _map_use_pattern = /^usemap /;
|
||||
const _face_vertex_data_separator_pattern = /\s+/;
|
||||
|
||||
const _vA = new Vector3();
|
||||
const _vB = new Vector3();
|
||||
const _vC = new Vector3();
|
||||
|
||||
const _ab = new Vector3();
|
||||
const _cb = new Vector3();
|
||||
|
||||
const _color = new Color();
|
||||
|
||||
function ParserState() {
|
||||
|
||||
const state = {
|
||||
objects: [],
|
||||
object: {},
|
||||
|
||||
vertices: [],
|
||||
normals: [],
|
||||
colors: [],
|
||||
uvs: [],
|
||||
|
||||
materials: {},
|
||||
materialLibraries: [],
|
||||
|
||||
startObject: function ( name, fromDeclaration ) {
|
||||
|
||||
// If the current object (initial from reset) is not from a g/o declaration in the parsed
|
||||
// file. We need to use it for the first parsed g/o to keep things in sync.
|
||||
if ( this.object && this.object.fromDeclaration === false ) {
|
||||
|
||||
this.object.name = name;
|
||||
this.object.fromDeclaration = ( fromDeclaration !== false );
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
const previousMaterial = ( this.object && typeof this.object.currentMaterial === 'function' ? this.object.currentMaterial() : undefined );
|
||||
|
||||
if ( this.object && typeof this.object._finalize === 'function' ) {
|
||||
|
||||
this.object._finalize( true );
|
||||
|
||||
}
|
||||
|
||||
this.object = {
|
||||
name: name || '',
|
||||
fromDeclaration: ( fromDeclaration !== false ),
|
||||
|
||||
geometry: {
|
||||
vertices: [],
|
||||
normals: [],
|
||||
colors: [],
|
||||
uvs: [],
|
||||
hasUVIndices: false
|
||||
},
|
||||
materials: [],
|
||||
smooth: true,
|
||||
|
||||
startMaterial: function ( name, libraries ) {
|
||||
|
||||
const previous = this._finalize( false );
|
||||
|
||||
// New usemtl declaration overwrites an inherited material, except if faces were declared
|
||||
// after the material, then it must be preserved for proper MultiMaterial continuation.
|
||||
if ( previous && ( previous.inherited || previous.groupCount <= 0 ) ) {
|
||||
|
||||
this.materials.splice( previous.index, 1 );
|
||||
|
||||
}
|
||||
|
||||
const material = {
|
||||
index: this.materials.length,
|
||||
name: name || '',
|
||||
mtllib: ( Array.isArray( libraries ) && libraries.length > 0 ? libraries[ libraries.length - 1 ] : '' ),
|
||||
smooth: ( previous !== undefined ? previous.smooth : this.smooth ),
|
||||
groupStart: ( previous !== undefined ? previous.groupEnd : 0 ),
|
||||
groupEnd: - 1,
|
||||
groupCount: - 1,
|
||||
inherited: false,
|
||||
|
||||
clone: function ( index ) {
|
||||
|
||||
const cloned = {
|
||||
index: ( typeof index === 'number' ? index : this.index ),
|
||||
name: this.name,
|
||||
mtllib: this.mtllib,
|
||||
smooth: this.smooth,
|
||||
groupStart: 0,
|
||||
groupEnd: - 1,
|
||||
groupCount: - 1,
|
||||
inherited: false
|
||||
};
|
||||
cloned.clone = this.clone.bind( cloned );
|
||||
return cloned;
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
this.materials.push( material );
|
||||
|
||||
return material;
|
||||
|
||||
},
|
||||
|
||||
currentMaterial: function () {
|
||||
|
||||
if ( this.materials.length > 0 ) {
|
||||
|
||||
return this.materials[ this.materials.length - 1 ];
|
||||
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
||||
},
|
||||
|
||||
_finalize: function ( end ) {
|
||||
|
||||
const lastMultiMaterial = this.currentMaterial();
|
||||
if ( lastMultiMaterial && lastMultiMaterial.groupEnd === - 1 ) {
|
||||
|
||||
lastMultiMaterial.groupEnd = this.geometry.vertices.length / 3;
|
||||
lastMultiMaterial.groupCount = lastMultiMaterial.groupEnd - lastMultiMaterial.groupStart;
|
||||
lastMultiMaterial.inherited = false;
|
||||
|
||||
}
|
||||
|
||||
// Ignore objects tail materials if no face declarations followed them before a new o/g started.
|
||||
if ( end && this.materials.length > 1 ) {
|
||||
|
||||
for ( let mi = this.materials.length - 1; mi >= 0; mi -- ) {
|
||||
|
||||
if ( this.materials[ mi ].groupCount <= 0 ) {
|
||||
|
||||
this.materials.splice( mi, 1 );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Guarantee at least one empty material, this makes the creation later more straight forward.
|
||||
if ( end && this.materials.length === 0 ) {
|
||||
|
||||
this.materials.push( {
|
||||
name: '',
|
||||
smooth: this.smooth
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
return lastMultiMaterial;
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
// Inherit previous objects material.
|
||||
// Spec tells us that a declared material must be set to all objects until a new material is declared.
|
||||
// If a usemtl declaration is encountered while this new object is being parsed, it will
|
||||
// overwrite the inherited material. Exception being that there was already face declarations
|
||||
// to the inherited material, then it will be preserved for proper MultiMaterial continuation.
|
||||
|
||||
if ( previousMaterial && previousMaterial.name && typeof previousMaterial.clone === 'function' ) {
|
||||
|
||||
const declared = previousMaterial.clone( 0 );
|
||||
declared.inherited = true;
|
||||
this.object.materials.push( declared );
|
||||
|
||||
}
|
||||
|
||||
this.objects.push( this.object );
|
||||
|
||||
},
|
||||
|
||||
finalize: function () {
|
||||
|
||||
if ( this.object && typeof this.object._finalize === 'function' ) {
|
||||
|
||||
this.object._finalize( true );
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
parseVertexIndex: function ( value, len ) {
|
||||
|
||||
const index = parseInt( value, 10 );
|
||||
return ( index >= 0 ? index - 1 : index + len / 3 ) * 3;
|
||||
|
||||
},
|
||||
|
||||
parseNormalIndex: function ( value, len ) {
|
||||
|
||||
const index = parseInt( value, 10 );
|
||||
return ( index >= 0 ? index - 1 : index + len / 3 ) * 3;
|
||||
|
||||
},
|
||||
|
||||
parseUVIndex: function ( value, len ) {
|
||||
|
||||
const index = parseInt( value, 10 );
|
||||
return ( index >= 0 ? index - 1 : index + len / 2 ) * 2;
|
||||
|
||||
},
|
||||
|
||||
addVertex: function ( a, b, c ) {
|
||||
|
||||
const src = this.vertices;
|
||||
const dst = this.object.geometry.vertices;
|
||||
|
||||
dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
|
||||
dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] );
|
||||
dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] );
|
||||
|
||||
},
|
||||
|
||||
addVertexPoint: function ( a ) {
|
||||
|
||||
const src = this.vertices;
|
||||
const dst = this.object.geometry.vertices;
|
||||
|
||||
dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
|
||||
|
||||
},
|
||||
|
||||
addVertexLine: function ( a ) {
|
||||
|
||||
const src = this.vertices;
|
||||
const dst = this.object.geometry.vertices;
|
||||
|
||||
dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
|
||||
|
||||
},
|
||||
|
||||
addNormal: function ( a, b, c ) {
|
||||
|
||||
const src = this.normals;
|
||||
const dst = this.object.geometry.normals;
|
||||
|
||||
dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
|
||||
dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] );
|
||||
dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] );
|
||||
|
||||
},
|
||||
|
||||
addFaceNormal: function ( a, b, c ) {
|
||||
|
||||
const src = this.vertices;
|
||||
const dst = this.object.geometry.normals;
|
||||
|
||||
_vA.fromArray( src, a );
|
||||
_vB.fromArray( src, b );
|
||||
_vC.fromArray( src, c );
|
||||
|
||||
_cb.subVectors( _vC, _vB );
|
||||
_ab.subVectors( _vA, _vB );
|
||||
_cb.cross( _ab );
|
||||
|
||||
_cb.normalize();
|
||||
|
||||
dst.push( _cb.x, _cb.y, _cb.z );
|
||||
dst.push( _cb.x, _cb.y, _cb.z );
|
||||
dst.push( _cb.x, _cb.y, _cb.z );
|
||||
|
||||
},
|
||||
|
||||
addColor: function ( a, b, c ) {
|
||||
|
||||
const src = this.colors;
|
||||
const dst = this.object.geometry.colors;
|
||||
|
||||
if ( src[ a ] !== undefined ) dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
|
||||
if ( src[ b ] !== undefined ) dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] );
|
||||
if ( src[ c ] !== undefined ) dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] );
|
||||
|
||||
},
|
||||
|
||||
addUV: function ( a, b, c ) {
|
||||
|
||||
const src = this.uvs;
|
||||
const dst = this.object.geometry.uvs;
|
||||
|
||||
dst.push( src[ a + 0 ], src[ a + 1 ] );
|
||||
dst.push( src[ b + 0 ], src[ b + 1 ] );
|
||||
dst.push( src[ c + 0 ], src[ c + 1 ] );
|
||||
|
||||
},
|
||||
|
||||
addDefaultUV: function () {
|
||||
|
||||
const dst = this.object.geometry.uvs;
|
||||
|
||||
dst.push( 0, 0 );
|
||||
dst.push( 0, 0 );
|
||||
dst.push( 0, 0 );
|
||||
|
||||
},
|
||||
|
||||
addUVLine: function ( a ) {
|
||||
|
||||
const src = this.uvs;
|
||||
const dst = this.object.geometry.uvs;
|
||||
|
||||
dst.push( src[ a + 0 ], src[ a + 1 ] );
|
||||
|
||||
},
|
||||
|
||||
addFace: function ( a, b, c, ua, ub, uc, na, nb, nc ) {
|
||||
|
||||
const vLen = this.vertices.length;
|
||||
|
||||
let ia = this.parseVertexIndex( a, vLen );
|
||||
let ib = this.parseVertexIndex( b, vLen );
|
||||
let ic = this.parseVertexIndex( c, vLen );
|
||||
|
||||
this.addVertex( ia, ib, ic );
|
||||
this.addColor( ia, ib, ic );
|
||||
|
||||
// normals
|
||||
|
||||
if ( na !== undefined && na !== '' ) {
|
||||
|
||||
const nLen = this.normals.length;
|
||||
|
||||
ia = this.parseNormalIndex( na, nLen );
|
||||
ib = this.parseNormalIndex( nb, nLen );
|
||||
ic = this.parseNormalIndex( nc, nLen );
|
||||
|
||||
this.addNormal( ia, ib, ic );
|
||||
|
||||
} else {
|
||||
|
||||
this.addFaceNormal( ia, ib, ic );
|
||||
|
||||
}
|
||||
|
||||
// uvs
|
||||
|
||||
if ( ua !== undefined && ua !== '' ) {
|
||||
|
||||
const uvLen = this.uvs.length;
|
||||
|
||||
ia = this.parseUVIndex( ua, uvLen );
|
||||
ib = this.parseUVIndex( ub, uvLen );
|
||||
ic = this.parseUVIndex( uc, uvLen );
|
||||
|
||||
this.addUV( ia, ib, ic );
|
||||
|
||||
this.object.geometry.hasUVIndices = true;
|
||||
|
||||
} else {
|
||||
|
||||
// add placeholder values (for inconsistent face definitions)
|
||||
|
||||
this.addDefaultUV();
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
addPointGeometry: function ( vertices ) {
|
||||
|
||||
this.object.geometry.type = 'Points';
|
||||
|
||||
const vLen = this.vertices.length;
|
||||
|
||||
for ( let vi = 0, l = vertices.length; vi < l; vi ++ ) {
|
||||
|
||||
const index = this.parseVertexIndex( vertices[ vi ], vLen );
|
||||
|
||||
this.addVertexPoint( index );
|
||||
this.addColor( index );
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
addLineGeometry: function ( vertices, uvs ) {
|
||||
|
||||
this.object.geometry.type = 'Line';
|
||||
|
||||
const vLen = this.vertices.length;
|
||||
const uvLen = this.uvs.length;
|
||||
|
||||
for ( let vi = 0, l = vertices.length; vi < l; vi ++ ) {
|
||||
|
||||
this.addVertexLine( this.parseVertexIndex( vertices[ vi ], vLen ) );
|
||||
|
||||
}
|
||||
|
||||
for ( let uvi = 0, l = uvs.length; uvi < l; uvi ++ ) {
|
||||
|
||||
this.addUVLine( this.parseUVIndex( uvs[ uvi ], uvLen ) );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
state.startObject( '', false );
|
||||
|
||||
return state;
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
class OBJLoader extends Loader {
|
||||
|
||||
constructor( manager ) {
|
||||
|
||||
super( manager );
|
||||
|
||||
this.materials = null;
|
||||
|
||||
}
|
||||
|
||||
load( url, onLoad, onProgress, onError ) {
|
||||
|
||||
const scope = this;
|
||||
|
||||
const loader = new FileLoader( this.manager );
|
||||
loader.setPath( this.path );
|
||||
loader.setRequestHeader( this.requestHeader );
|
||||
loader.setWithCredentials( this.withCredentials );
|
||||
loader.load( url, function ( text ) {
|
||||
|
||||
try {
|
||||
|
||||
onLoad( scope.parse( text ) );
|
||||
|
||||
} catch ( e ) {
|
||||
|
||||
if ( onError ) {
|
||||
|
||||
onError( e );
|
||||
|
||||
} else {
|
||||
|
||||
console.error( e );
|
||||
|
||||
}
|
||||
|
||||
scope.manager.itemError( url );
|
||||
|
||||
}
|
||||
|
||||
}, onProgress, onError );
|
||||
|
||||
}
|
||||
|
||||
setMaterials( materials ) {
|
||||
|
||||
this.materials = materials;
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
parse( text ) {
|
||||
|
||||
const state = new ParserState();
|
||||
|
||||
if ( text.indexOf( '\r\n' ) !== - 1 ) {
|
||||
|
||||
// This is faster than String.split with regex that splits on both
|
||||
text = text.replace( /\r\n/g, '\n' );
|
||||
|
||||
}
|
||||
|
||||
if ( text.indexOf( '\\\n' ) !== - 1 ) {
|
||||
|
||||
// join lines separated by a line continuation character (\)
|
||||
text = text.replace( /\\\n/g, '' );
|
||||
|
||||
}
|
||||
|
||||
const lines = text.split( '\n' );
|
||||
let result = [];
|
||||
|
||||
for ( let i = 0, l = lines.length; i < l; i ++ ) {
|
||||
|
||||
const line = lines[ i ].trimStart();
|
||||
|
||||
if ( line.length === 0 ) continue;
|
||||
|
||||
const lineFirstChar = line.charAt( 0 );
|
||||
|
||||
// @todo invoke passed in handler if any
|
||||
if ( lineFirstChar === '#' ) continue; // skip comments
|
||||
|
||||
if ( lineFirstChar === 'v' ) {
|
||||
|
||||
const data = line.split( _face_vertex_data_separator_pattern );
|
||||
|
||||
switch ( data[ 0 ] ) {
|
||||
|
||||
case 'v':
|
||||
state.vertices.push(
|
||||
parseFloat( data[ 1 ] ),
|
||||
parseFloat( data[ 2 ] ),
|
||||
parseFloat( data[ 3 ] )
|
||||
);
|
||||
if ( data.length >= 7 ) {
|
||||
|
||||
_color.setRGB(
|
||||
parseFloat( data[ 4 ] ),
|
||||
parseFloat( data[ 5 ] ),
|
||||
parseFloat( data[ 6 ] )
|
||||
).convertSRGBToLinear();
|
||||
|
||||
state.colors.push( _color.r, _color.g, _color.b );
|
||||
|
||||
} else {
|
||||
|
||||
// if no colors are defined, add placeholders so color and vertex indices match
|
||||
|
||||
state.colors.push( undefined, undefined, undefined );
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
case 'vn':
|
||||
state.normals.push(
|
||||
parseFloat( data[ 1 ] ),
|
||||
parseFloat( data[ 2 ] ),
|
||||
parseFloat( data[ 3 ] )
|
||||
);
|
||||
break;
|
||||
case 'vt':
|
||||
state.uvs.push(
|
||||
parseFloat( data[ 1 ] ),
|
||||
parseFloat( data[ 2 ] )
|
||||
);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
} else if ( lineFirstChar === 'f' ) {
|
||||
|
||||
const lineData = line.slice( 1 ).trim();
|
||||
const vertexData = lineData.split( _face_vertex_data_separator_pattern );
|
||||
const faceVertices = [];
|
||||
|
||||
// Parse the face vertex data into an easy to work with format
|
||||
|
||||
for ( let j = 0, jl = vertexData.length; j < jl; j ++ ) {
|
||||
|
||||
const vertex = vertexData[ j ];
|
||||
|
||||
if ( vertex.length > 0 ) {
|
||||
|
||||
const vertexParts = vertex.split( '/' );
|
||||
faceVertices.push( vertexParts );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Draw an edge between the first vertex and all subsequent vertices to form an n-gon
|
||||
|
||||
const v1 = faceVertices[ 0 ];
|
||||
|
||||
for ( let j = 1, jl = faceVertices.length - 1; j < jl; j ++ ) {
|
||||
|
||||
const v2 = faceVertices[ j ];
|
||||
const v3 = faceVertices[ j + 1 ];
|
||||
|
||||
state.addFace(
|
||||
v1[ 0 ], v2[ 0 ], v3[ 0 ],
|
||||
v1[ 1 ], v2[ 1 ], v3[ 1 ],
|
||||
v1[ 2 ], v2[ 2 ], v3[ 2 ]
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
} else if ( lineFirstChar === 'l' ) {
|
||||
|
||||
const lineParts = line.substring( 1 ).trim().split( ' ' );
|
||||
let lineVertices = [];
|
||||
const lineUVs = [];
|
||||
|
||||
if ( line.indexOf( '/' ) === - 1 ) {
|
||||
|
||||
lineVertices = lineParts;
|
||||
|
||||
} else {
|
||||
|
||||
for ( let li = 0, llen = lineParts.length; li < llen; li ++ ) {
|
||||
|
||||
const parts = lineParts[ li ].split( '/' );
|
||||
|
||||
if ( parts[ 0 ] !== '' ) lineVertices.push( parts[ 0 ] );
|
||||
if ( parts[ 1 ] !== '' ) lineUVs.push( parts[ 1 ] );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
state.addLineGeometry( lineVertices, lineUVs );
|
||||
|
||||
} else if ( lineFirstChar === 'p' ) {
|
||||
|
||||
const lineData = line.slice( 1 ).trim();
|
||||
const pointData = lineData.split( ' ' );
|
||||
|
||||
state.addPointGeometry( pointData );
|
||||
|
||||
} else if ( ( result = _object_pattern.exec( line ) ) !== null ) {
|
||||
|
||||
// o object_name
|
||||
// or
|
||||
// g group_name
|
||||
|
||||
// WORKAROUND: https://bugs.chromium.org/p/v8/issues/detail?id=2869
|
||||
// let name = result[ 0 ].slice( 1 ).trim();
|
||||
const name = ( ' ' + result[ 0 ].slice( 1 ).trim() ).slice( 1 );
|
||||
|
||||
state.startObject( name );
|
||||
|
||||
} else if ( _material_use_pattern.test( line ) ) {
|
||||
|
||||
// material
|
||||
|
||||
state.object.startMaterial( line.substring( 7 ).trim(), state.materialLibraries );
|
||||
|
||||
} else if ( _material_library_pattern.test( line ) ) {
|
||||
|
||||
// mtl file
|
||||
|
||||
state.materialLibraries.push( line.substring( 7 ).trim() );
|
||||
|
||||
} else if ( _map_use_pattern.test( line ) ) {
|
||||
|
||||
// the line is parsed but ignored since the loader assumes textures are defined MTL files
|
||||
// (according to https://www.okino.com/conv/imp_wave.htm, 'usemap' is the old-style Wavefront texture reference method)
|
||||
|
||||
console.warn( 'THREE.OBJLoader: Rendering identifier "usemap" not supported. Textures must be defined in MTL files.' );
|
||||
|
||||
} else if ( lineFirstChar === 's' ) {
|
||||
|
||||
result = line.split( ' ' );
|
||||
|
||||
// smooth shading
|
||||
|
||||
// @todo Handle files that have varying smooth values for a set of faces inside one geometry,
|
||||
// but does not define a usemtl for each face set.
|
||||
// This should be detected and a dummy material created (later MultiMaterial and geometry groups).
|
||||
// This requires some care to not create extra material on each smooth value for "normal" obj files.
|
||||
// where explicit usemtl defines geometry groups.
|
||||
// Example asset: examples/models/obj/cerberus/Cerberus.obj
|
||||
|
||||
/*
|
||||
* http://paulbourke.net/dataformats/obj/
|
||||
*
|
||||
* From chapter "Grouping" Syntax explanation "s group_number":
|
||||
* "group_number is the smoothing group number. To turn off smoothing groups, use a value of 0 or off.
|
||||
* Polygonal elements use group numbers to put elements in different smoothing groups. For free-form
|
||||
* surfaces, smoothing groups are either turned on or off; there is no difference between values greater
|
||||
* than 0."
|
||||
*/
|
||||
if ( result.length > 1 ) {
|
||||
|
||||
const value = result[ 1 ].trim().toLowerCase();
|
||||
state.object.smooth = ( value !== '0' && value !== 'off' );
|
||||
|
||||
} else {
|
||||
|
||||
// ZBrush can produce "s" lines #11707
|
||||
state.object.smooth = true;
|
||||
|
||||
}
|
||||
|
||||
const material = state.object.currentMaterial();
|
||||
if ( material ) material.smooth = state.object.smooth;
|
||||
|
||||
} else {
|
||||
|
||||
// Handle null terminated files without exception
|
||||
if ( line === '\0' ) continue;
|
||||
|
||||
console.warn( 'THREE.OBJLoader: Unexpected line: "' + line + '"' );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
state.finalize();
|
||||
|
||||
const container = new Group();
|
||||
container.materialLibraries = [].concat( state.materialLibraries );
|
||||
|
||||
const hasPrimitives = ! ( state.objects.length === 1 && state.objects[ 0 ].geometry.vertices.length === 0 );
|
||||
|
||||
if ( hasPrimitives === true ) {
|
||||
|
||||
for ( let i = 0, l = state.objects.length; i < l; i ++ ) {
|
||||
|
||||
const object = state.objects[ i ];
|
||||
const geometry = object.geometry;
|
||||
const materials = object.materials;
|
||||
const isLine = ( geometry.type === 'Line' );
|
||||
const isPoints = ( geometry.type === 'Points' );
|
||||
let hasVertexColors = false;
|
||||
|
||||
// Skip o/g line declarations that did not follow with any faces
|
||||
if ( geometry.vertices.length === 0 ) continue;
|
||||
|
||||
const buffergeometry = new BufferGeometry();
|
||||
|
||||
buffergeometry.setAttribute( 'position', new Float32BufferAttribute( geometry.vertices, 3 ) );
|
||||
|
||||
if ( geometry.normals.length > 0 ) {
|
||||
|
||||
buffergeometry.setAttribute( 'normal', new Float32BufferAttribute( geometry.normals, 3 ) );
|
||||
|
||||
}
|
||||
|
||||
if ( geometry.colors.length > 0 ) {
|
||||
|
||||
hasVertexColors = true;
|
||||
buffergeometry.setAttribute( 'color', new Float32BufferAttribute( geometry.colors, 3 ) );
|
||||
|
||||
}
|
||||
|
||||
if ( geometry.hasUVIndices === true ) {
|
||||
|
||||
buffergeometry.setAttribute( 'uv', new Float32BufferAttribute( geometry.uvs, 2 ) );
|
||||
|
||||
}
|
||||
|
||||
// Create materials
|
||||
|
||||
const createdMaterials = [];
|
||||
|
||||
for ( let mi = 0, miLen = materials.length; mi < miLen; mi ++ ) {
|
||||
|
||||
const sourceMaterial = materials[ mi ];
|
||||
const materialHash = sourceMaterial.name + '_' + sourceMaterial.smooth + '_' + hasVertexColors;
|
||||
let material = state.materials[ materialHash ];
|
||||
|
||||
if ( this.materials !== null ) {
|
||||
|
||||
material = this.materials.create( sourceMaterial.name );
|
||||
|
||||
// mtl etc. loaders probably can't create line materials correctly, copy properties to a line material.
|
||||
if ( isLine && material && ! ( material instanceof LineBasicMaterial ) ) {
|
||||
|
||||
const materialLine = new LineBasicMaterial();
|
||||
Material.prototype.copy.call( materialLine, material );
|
||||
materialLine.color.copy( material.color );
|
||||
material = materialLine;
|
||||
|
||||
} else if ( isPoints && material && ! ( material instanceof PointsMaterial ) ) {
|
||||
|
||||
const materialPoints = new PointsMaterial( { size: 10, sizeAttenuation: false } );
|
||||
Material.prototype.copy.call( materialPoints, material );
|
||||
materialPoints.color.copy( material.color );
|
||||
materialPoints.map = material.map;
|
||||
material = materialPoints;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( material === undefined ) {
|
||||
|
||||
if ( isLine ) {
|
||||
|
||||
material = new LineBasicMaterial();
|
||||
|
||||
} else if ( isPoints ) {
|
||||
|
||||
material = new PointsMaterial( { size: 1, sizeAttenuation: false } );
|
||||
|
||||
} else {
|
||||
|
||||
material = new MeshPhongMaterial();
|
||||
|
||||
}
|
||||
|
||||
material.name = sourceMaterial.name;
|
||||
material.flatShading = sourceMaterial.smooth ? false : true;
|
||||
material.vertexColors = hasVertexColors;
|
||||
|
||||
state.materials[ materialHash ] = material;
|
||||
|
||||
}
|
||||
|
||||
createdMaterials.push( material );
|
||||
|
||||
}
|
||||
|
||||
// Create mesh
|
||||
|
||||
let mesh;
|
||||
|
||||
if ( createdMaterials.length > 1 ) {
|
||||
|
||||
for ( let mi = 0, miLen = materials.length; mi < miLen; mi ++ ) {
|
||||
|
||||
const sourceMaterial = materials[ mi ];
|
||||
buffergeometry.addGroup( sourceMaterial.groupStart, sourceMaterial.groupCount, mi );
|
||||
|
||||
}
|
||||
|
||||
if ( isLine ) {
|
||||
|
||||
mesh = new LineSegments( buffergeometry, createdMaterials );
|
||||
|
||||
} else if ( isPoints ) {
|
||||
|
||||
mesh = new Points( buffergeometry, createdMaterials );
|
||||
|
||||
} else {
|
||||
|
||||
mesh = new Mesh( buffergeometry, createdMaterials );
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if ( isLine ) {
|
||||
|
||||
mesh = new LineSegments( buffergeometry, createdMaterials[ 0 ] );
|
||||
|
||||
} else if ( isPoints ) {
|
||||
|
||||
mesh = new Points( buffergeometry, createdMaterials[ 0 ] );
|
||||
|
||||
} else {
|
||||
|
||||
mesh = new Mesh( buffergeometry, createdMaterials[ 0 ] );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
mesh.name = object.name;
|
||||
|
||||
container.add( mesh );
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// if there is only the default parser state object with no geometry data, interpret data as point cloud
|
||||
|
||||
if ( state.vertices.length > 0 ) {
|
||||
|
||||
const material = new PointsMaterial( { size: 1, sizeAttenuation: false } );
|
||||
|
||||
const buffergeometry = new BufferGeometry();
|
||||
|
||||
buffergeometry.setAttribute( 'position', new Float32BufferAttribute( state.vertices, 3 ) );
|
||||
|
||||
if ( state.colors.length > 0 && state.colors[ 0 ] !== undefined ) {
|
||||
|
||||
buffergeometry.setAttribute( 'color', new Float32BufferAttribute( state.colors, 3 ) );
|
||||
material.vertexColors = true;
|
||||
|
||||
}
|
||||
|
||||
const points = new Points( buffergeometry, material );
|
||||
container.add( points );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return container;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export { OBJLoader };
|
||||
411
server/plugin/plg_application_3d/vendor/STLLoader.js
vendored
411
server/plugin/plg_application_3d/vendor/STLLoader.js
vendored
|
|
@ -1,411 +0,0 @@
|
|||
// @ts-nocheck
|
||||
import {
|
||||
BufferAttribute,
|
||||
BufferGeometry,
|
||||
Color,
|
||||
FileLoader,
|
||||
Float32BufferAttribute,
|
||||
Loader,
|
||||
Vector3
|
||||
} from '../../../assets/lib/vendor/three/three.module.js';
|
||||
|
||||
/**
|
||||
* Description: A THREE loader for STL ASCII files, as created by Solidworks and other CAD programs.
|
||||
*
|
||||
* Supports both binary and ASCII encoded files, with automatic detection of type.
|
||||
*
|
||||
* The loader returns a non-indexed buffer geometry.
|
||||
*
|
||||
* Limitations:
|
||||
* Binary decoding supports "Magics" color format (http://en.wikipedia.org/wiki/STL_(file_format)#Color_in_binary_STL).
|
||||
* There is perhaps some question as to how valid it is to always assume little-endian-ness.
|
||||
* ASCII decoding assumes file is UTF-8.
|
||||
*
|
||||
* Usage:
|
||||
* const loader = new STLLoader();
|
||||
* loader.load( './models/stl/slotted_disk.stl', function ( geometry ) {
|
||||
* scene.add( new THREE.Mesh( geometry ) );
|
||||
* });
|
||||
*
|
||||
* For binary STLs geometry might contain colors for vertices. To use it:
|
||||
* // use the same code to load STL as above
|
||||
* if (geometry.hasColors) {
|
||||
* material = new THREE.MeshPhongMaterial({ opacity: geometry.alpha, vertexColors: true });
|
||||
* } else { .... }
|
||||
* const mesh = new THREE.Mesh( geometry, material );
|
||||
*
|
||||
* For ASCII STLs containing multiple solids, each solid is assigned to a different group.
|
||||
* Groups can be used to assign a different color by defining an array of materials with the same length of
|
||||
* geometry.groups and passing it to the Mesh constructor:
|
||||
*
|
||||
* const mesh = new THREE.Mesh( geometry, material );
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* const materials = [];
|
||||
* const nGeometryGroups = geometry.groups.length;
|
||||
*
|
||||
* const colorMap = ...; // Some logic to index colors.
|
||||
*
|
||||
* for (let i = 0; i < nGeometryGroups; i++) {
|
||||
*
|
||||
* const material = new THREE.MeshPhongMaterial({
|
||||
* color: colorMap[i],
|
||||
* wireframe: false
|
||||
* });
|
||||
*
|
||||
* }
|
||||
*
|
||||
* materials.push(material);
|
||||
* const mesh = new THREE.Mesh(geometry, materials);
|
||||
*/
|
||||
|
||||
|
||||
class STLLoader extends Loader {
|
||||
|
||||
constructor( manager ) {
|
||||
|
||||
super( manager );
|
||||
|
||||
}
|
||||
|
||||
load( url, onLoad, onProgress, onError ) {
|
||||
|
||||
const scope = this;
|
||||
|
||||
const loader = new FileLoader( this.manager );
|
||||
loader.setPath( this.path );
|
||||
loader.setResponseType( 'arraybuffer' );
|
||||
loader.setRequestHeader( this.requestHeader );
|
||||
loader.setWithCredentials( this.withCredentials );
|
||||
|
||||
loader.load( url, function ( text ) {
|
||||
|
||||
try {
|
||||
|
||||
onLoad( scope.parse( text ) );
|
||||
|
||||
} catch ( e ) {
|
||||
|
||||
if ( onError ) {
|
||||
|
||||
onError( e );
|
||||
|
||||
} else {
|
||||
|
||||
console.error( e );
|
||||
|
||||
}
|
||||
|
||||
scope.manager.itemError( url );
|
||||
|
||||
}
|
||||
|
||||
}, onProgress, onError );
|
||||
|
||||
}
|
||||
|
||||
parse( data ) {
|
||||
|
||||
function isBinary( data ) {
|
||||
|
||||
const reader = new DataView( data );
|
||||
const face_size = ( 32 / 8 * 3 ) + ( ( 32 / 8 * 3 ) * 3 ) + ( 16 / 8 );
|
||||
const n_faces = reader.getUint32( 80, true );
|
||||
const expect = 80 + ( 32 / 8 ) + ( n_faces * face_size );
|
||||
|
||||
if ( expect === reader.byteLength ) {
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
// An ASCII STL data must begin with 'solid ' as the first six bytes.
|
||||
// However, ASCII STLs lacking the SPACE after the 'd' are known to be
|
||||
// plentiful. So, check the first 5 bytes for 'solid'.
|
||||
|
||||
// Several encodings, such as UTF-8, precede the text with up to 5 bytes:
|
||||
// https://en.wikipedia.org/wiki/Byte_order_mark#Byte_order_marks_by_encoding
|
||||
// Search for "solid" to start anywhere after those prefixes.
|
||||
|
||||
// US-ASCII ordinal values for 's', 'o', 'l', 'i', 'd'
|
||||
|
||||
const solid = [ 115, 111, 108, 105, 100 ];
|
||||
|
||||
for ( let off = 0; off < 5; off ++ ) {
|
||||
|
||||
// If "solid" text is matched to the current offset, declare it to be an ASCII STL.
|
||||
|
||||
if ( matchDataViewAt( solid, reader, off ) ) return false;
|
||||
|
||||
}
|
||||
|
||||
// Couldn't find "solid" text at the beginning; it is binary STL.
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
function matchDataViewAt( query, reader, offset ) {
|
||||
|
||||
// Check if each byte in query matches the corresponding byte from the current offset
|
||||
|
||||
for ( let i = 0, il = query.length; i < il; i ++ ) {
|
||||
|
||||
if ( query[ i ] !== reader.getUint8( offset + i ) ) return false;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
function parseBinary( data ) {
|
||||
|
||||
const reader = new DataView( data );
|
||||
const faces = reader.getUint32( 80, true );
|
||||
|
||||
let r, g, b, hasColors = false, colors;
|
||||
let defaultR, defaultG, defaultB, alpha;
|
||||
|
||||
// process STL header
|
||||
// check for default color in header ("COLOR=rgba" sequence).
|
||||
|
||||
for ( let index = 0; index < 80 - 10; index ++ ) {
|
||||
|
||||
if ( ( reader.getUint32( index, false ) == 0x434F4C4F /*COLO*/ ) &&
|
||||
( reader.getUint8( index + 4 ) == 0x52 /*'R'*/ ) &&
|
||||
( reader.getUint8( index + 5 ) == 0x3D /*'='*/ ) ) {
|
||||
|
||||
hasColors = true;
|
||||
colors = new Float32Array( faces * 3 * 3 );
|
||||
|
||||
defaultR = reader.getUint8( index + 6 ) / 255;
|
||||
defaultG = reader.getUint8( index + 7 ) / 255;
|
||||
defaultB = reader.getUint8( index + 8 ) / 255;
|
||||
alpha = reader.getUint8( index + 9 ) / 255;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const dataOffset = 84;
|
||||
const faceLength = 12 * 4 + 2;
|
||||
|
||||
const geometry = new BufferGeometry();
|
||||
|
||||
const vertices = new Float32Array( faces * 3 * 3 );
|
||||
const normals = new Float32Array( faces * 3 * 3 );
|
||||
|
||||
const color = new Color();
|
||||
|
||||
for ( let face = 0; face < faces; face ++ ) {
|
||||
|
||||
const start = dataOffset + face * faceLength;
|
||||
const normalX = reader.getFloat32( start, true );
|
||||
const normalY = reader.getFloat32( start + 4, true );
|
||||
const normalZ = reader.getFloat32( start + 8, true );
|
||||
|
||||
if ( hasColors ) {
|
||||
|
||||
const packedColor = reader.getUint16( start + 48, true );
|
||||
|
||||
if ( ( packedColor & 0x8000 ) === 0 ) {
|
||||
|
||||
// facet has its own unique color
|
||||
|
||||
r = ( packedColor & 0x1F ) / 31;
|
||||
g = ( ( packedColor >> 5 ) & 0x1F ) / 31;
|
||||
b = ( ( packedColor >> 10 ) & 0x1F ) / 31;
|
||||
|
||||
} else {
|
||||
|
||||
r = defaultR;
|
||||
g = defaultG;
|
||||
b = defaultB;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for ( let i = 1; i <= 3; i ++ ) {
|
||||
|
||||
const vertexstart = start + i * 12;
|
||||
const componentIdx = ( face * 3 * 3 ) + ( ( i - 1 ) * 3 );
|
||||
|
||||
vertices[ componentIdx ] = reader.getFloat32( vertexstart, true );
|
||||
vertices[ componentIdx + 1 ] = reader.getFloat32( vertexstart + 4, true );
|
||||
vertices[ componentIdx + 2 ] = reader.getFloat32( vertexstart + 8, true );
|
||||
|
||||
normals[ componentIdx ] = normalX;
|
||||
normals[ componentIdx + 1 ] = normalY;
|
||||
normals[ componentIdx + 2 ] = normalZ;
|
||||
|
||||
if ( hasColors ) {
|
||||
|
||||
color.set( r, g, b ).convertSRGBToLinear();
|
||||
|
||||
colors[ componentIdx ] = color.r;
|
||||
colors[ componentIdx + 1 ] = color.g;
|
||||
colors[ componentIdx + 2 ] = color.b;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
geometry.setAttribute( 'position', new BufferAttribute( vertices, 3 ) );
|
||||
geometry.setAttribute( 'normal', new BufferAttribute( normals, 3 ) );
|
||||
|
||||
if ( hasColors ) {
|
||||
|
||||
geometry.setAttribute( 'color', new BufferAttribute( colors, 3 ) );
|
||||
geometry.hasColors = true;
|
||||
geometry.alpha = alpha;
|
||||
|
||||
}
|
||||
|
||||
return geometry;
|
||||
|
||||
}
|
||||
|
||||
function parseASCII( data ) {
|
||||
|
||||
const geometry = new BufferGeometry();
|
||||
const patternSolid = /solid([\s\S]*?)endsolid/g;
|
||||
const patternFace = /facet([\s\S]*?)endfacet/g;
|
||||
const patternName = /solid\s(.+)/;
|
||||
let faceCounter = 0;
|
||||
|
||||
const patternFloat = /[\s]+([+-]?(?:\d*)(?:\.\d*)?(?:[eE][+-]?\d+)?)/.source;
|
||||
const patternVertex = new RegExp( 'vertex' + patternFloat + patternFloat + patternFloat, 'g' );
|
||||
const patternNormal = new RegExp( 'normal' + patternFloat + patternFloat + patternFloat, 'g' );
|
||||
|
||||
const vertices = [];
|
||||
const normals = [];
|
||||
const groupNames = [];
|
||||
|
||||
const normal = new Vector3();
|
||||
|
||||
let result;
|
||||
|
||||
let groupCount = 0;
|
||||
let startVertex = 0;
|
||||
let endVertex = 0;
|
||||
|
||||
while ( ( result = patternSolid.exec( data ) ) !== null ) {
|
||||
|
||||
startVertex = endVertex;
|
||||
|
||||
const solid = result[ 0 ];
|
||||
|
||||
const name = ( result = patternName.exec( solid ) ) !== null ? result[ 1 ] : '';
|
||||
groupNames.push( name );
|
||||
|
||||
while ( ( result = patternFace.exec( solid ) ) !== null ) {
|
||||
|
||||
let vertexCountPerFace = 0;
|
||||
let normalCountPerFace = 0;
|
||||
|
||||
const text = result[ 0 ];
|
||||
|
||||
while ( ( result = patternNormal.exec( text ) ) !== null ) {
|
||||
|
||||
normal.x = parseFloat( result[ 1 ] );
|
||||
normal.y = parseFloat( result[ 2 ] );
|
||||
normal.z = parseFloat( result[ 3 ] );
|
||||
normalCountPerFace ++;
|
||||
|
||||
}
|
||||
|
||||
while ( ( result = patternVertex.exec( text ) ) !== null ) {
|
||||
|
||||
vertices.push( parseFloat( result[ 1 ] ), parseFloat( result[ 2 ] ), parseFloat( result[ 3 ] ) );
|
||||
normals.push( normal.x, normal.y, normal.z );
|
||||
vertexCountPerFace ++;
|
||||
endVertex ++;
|
||||
|
||||
}
|
||||
|
||||
// every face have to own ONE valid normal
|
||||
|
||||
if ( normalCountPerFace !== 1 ) {
|
||||
|
||||
console.error( 'THREE.STLLoader: Something isn\'t right with the normal of face number ' + faceCounter );
|
||||
|
||||
}
|
||||
|
||||
// each face have to own THREE valid vertices
|
||||
|
||||
if ( vertexCountPerFace !== 3 ) {
|
||||
|
||||
console.error( 'THREE.STLLoader: Something isn\'t right with the vertices of face number ' + faceCounter );
|
||||
|
||||
}
|
||||
|
||||
faceCounter ++;
|
||||
|
||||
}
|
||||
|
||||
const start = startVertex;
|
||||
const count = endVertex - startVertex;
|
||||
|
||||
geometry.userData.groupNames = groupNames;
|
||||
|
||||
geometry.addGroup( start, count, groupCount );
|
||||
groupCount ++;
|
||||
|
||||
}
|
||||
|
||||
geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
|
||||
geometry.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
|
||||
|
||||
return geometry;
|
||||
|
||||
}
|
||||
|
||||
function ensureString( buffer ) {
|
||||
|
||||
if ( typeof buffer !== 'string' ) {
|
||||
|
||||
return new TextDecoder().decode( buffer );
|
||||
|
||||
}
|
||||
|
||||
return buffer;
|
||||
|
||||
}
|
||||
|
||||
function ensureBinary( buffer ) {
|
||||
|
||||
if ( typeof buffer === 'string' ) {
|
||||
|
||||
const array_buffer = new Uint8Array( buffer.length );
|
||||
for ( let i = 0; i < buffer.length; i ++ ) {
|
||||
|
||||
array_buffer[ i ] = buffer.charCodeAt( i ) & 0xff; // implicitly assumes little-endian
|
||||
|
||||
}
|
||||
|
||||
return array_buffer.buffer || array_buffer;
|
||||
|
||||
} else {
|
||||
|
||||
return buffer;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// start
|
||||
|
||||
const binData = ensureBinary( data );
|
||||
|
||||
return isBinary( binData ) ? parseBinary( binData ) : parseASCII( ensureString( data ) );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export { STLLoader };
|
||||
3174
server/plugin/plg_application_3d/vendor/SVGLoader.js
vendored
3174
server/plugin/plg_application_3d/vendor/SVGLoader.js
vendored
File diff suppressed because it is too large
Load diff
|
|
@ -1,81 +0,0 @@
|
|||
// @ts-nocheck
|
||||
import {
|
||||
Curve,
|
||||
Vector3,
|
||||
Vector4
|
||||
} from '../../../../assets/lib/vendor/three/three.module.js';
|
||||
import * as NURBSUtils from './NURBSUtils.js';
|
||||
|
||||
/**
|
||||
* NURBS curve object
|
||||
*
|
||||
* Derives from Curve, overriding getPoint and getTangent.
|
||||
*
|
||||
* Implementation is based on (x, y [, z=0 [, w=1]]) control points with w=weight.
|
||||
*
|
||||
**/
|
||||
|
||||
class NURBSCurve extends Curve {
|
||||
|
||||
constructor(
|
||||
degree,
|
||||
knots /* array of reals */,
|
||||
controlPoints /* array of Vector(2|3|4) */,
|
||||
startKnot /* index in knots */,
|
||||
endKnot /* index in knots */
|
||||
) {
|
||||
|
||||
super();
|
||||
|
||||
this.degree = degree;
|
||||
this.knots = knots;
|
||||
this.controlPoints = [];
|
||||
// Used by periodic NURBS to remove hidden spans
|
||||
this.startKnot = startKnot || 0;
|
||||
this.endKnot = endKnot || ( this.knots.length - 1 );
|
||||
|
||||
for ( let i = 0; i < controlPoints.length; ++ i ) {
|
||||
|
||||
// ensure Vector4 for control points
|
||||
const point = controlPoints[ i ];
|
||||
this.controlPoints[ i ] = new Vector4( point.x, point.y, point.z, point.w );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
getPoint( t, optionalTarget = new Vector3() ) {
|
||||
|
||||
const point = optionalTarget;
|
||||
|
||||
const u = this.knots[ this.startKnot ] + t * ( this.knots[ this.endKnot ] - this.knots[ this.startKnot ] ); // linear mapping t->u
|
||||
|
||||
// following results in (wx, wy, wz, w) homogeneous point
|
||||
const hpoint = NURBSUtils.calcBSplinePoint( this.degree, this.knots, this.controlPoints, u );
|
||||
|
||||
if ( hpoint.w !== 1.0 ) {
|
||||
|
||||
// project to 3D space: (wx, wy, wz, w) -> (x, y, z, 1)
|
||||
hpoint.divideScalar( hpoint.w );
|
||||
|
||||
}
|
||||
|
||||
return point.set( hpoint.x, hpoint.y, hpoint.z );
|
||||
|
||||
}
|
||||
|
||||
getTangent( t, optionalTarget = new Vector3() ) {
|
||||
|
||||
const tangent = optionalTarget;
|
||||
|
||||
const u = this.knots[ 0 ] + t * ( this.knots[ this.knots.length - 1 ] - this.knots[ 0 ] );
|
||||
const ders = NURBSUtils.calcNURBSDerivatives( this.degree, this.knots, this.controlPoints, u, 1 );
|
||||
tangent.copy( ders[ 1 ] ).normalize();
|
||||
|
||||
return tangent;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export { NURBSCurve };
|
||||
|
|
@ -1,488 +0,0 @@
|
|||
// @ts-nocheck
|
||||
import {
|
||||
Vector3,
|
||||
Vector4
|
||||
} from '../../../../assets/lib/vendor/three/three.module.js';
|
||||
|
||||
/**
|
||||
* NURBS utils
|
||||
*
|
||||
* See NURBSCurve and NURBSSurface.
|
||||
**/
|
||||
|
||||
|
||||
/**************************************************************
|
||||
* NURBS Utils
|
||||
**************************************************************/
|
||||
|
||||
/*
|
||||
Finds knot vector span.
|
||||
|
||||
p : degree
|
||||
u : parametric value
|
||||
U : knot vector
|
||||
|
||||
returns the span
|
||||
*/
|
||||
function findSpan( p, u, U ) {
|
||||
|
||||
const n = U.length - p - 1;
|
||||
|
||||
if ( u >= U[ n ] ) {
|
||||
|
||||
return n - 1;
|
||||
|
||||
}
|
||||
|
||||
if ( u <= U[ p ] ) {
|
||||
|
||||
return p;
|
||||
|
||||
}
|
||||
|
||||
let low = p;
|
||||
let high = n;
|
||||
let mid = Math.floor( ( low + high ) / 2 );
|
||||
|
||||
while ( u < U[ mid ] || u >= U[ mid + 1 ] ) {
|
||||
|
||||
if ( u < U[ mid ] ) {
|
||||
|
||||
high = mid;
|
||||
|
||||
} else {
|
||||
|
||||
low = mid;
|
||||
|
||||
}
|
||||
|
||||
mid = Math.floor( ( low + high ) / 2 );
|
||||
|
||||
}
|
||||
|
||||
return mid;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Calculate basis functions. See The NURBS Book, page 70, algorithm A2.2
|
||||
|
||||
span : span in which u lies
|
||||
u : parametric point
|
||||
p : degree
|
||||
U : knot vector
|
||||
|
||||
returns array[p+1] with basis functions values.
|
||||
*/
|
||||
function calcBasisFunctions( span, u, p, U ) {
|
||||
|
||||
const N = [];
|
||||
const left = [];
|
||||
const right = [];
|
||||
N[ 0 ] = 1.0;
|
||||
|
||||
for ( let j = 1; j <= p; ++ j ) {
|
||||
|
||||
left[ j ] = u - U[ span + 1 - j ];
|
||||
right[ j ] = U[ span + j ] - u;
|
||||
|
||||
let saved = 0.0;
|
||||
|
||||
for ( let r = 0; r < j; ++ r ) {
|
||||
|
||||
const rv = right[ r + 1 ];
|
||||
const lv = left[ j - r ];
|
||||
const temp = N[ r ] / ( rv + lv );
|
||||
N[ r ] = saved + rv * temp;
|
||||
saved = lv * temp;
|
||||
|
||||
}
|
||||
|
||||
N[ j ] = saved;
|
||||
|
||||
}
|
||||
|
||||
return N;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Calculate B-Spline curve points. See The NURBS Book, page 82, algorithm A3.1.
|
||||
|
||||
p : degree of B-Spline
|
||||
U : knot vector
|
||||
P : control points (x, y, z, w)
|
||||
u : parametric point
|
||||
|
||||
returns point for given u
|
||||
*/
|
||||
function calcBSplinePoint( p, U, P, u ) {
|
||||
|
||||
const span = findSpan( p, u, U );
|
||||
const N = calcBasisFunctions( span, u, p, U );
|
||||
const C = new Vector4( 0, 0, 0, 0 );
|
||||
|
||||
for ( let j = 0; j <= p; ++ j ) {
|
||||
|
||||
const point = P[ span - p + j ];
|
||||
const Nj = N[ j ];
|
||||
const wNj = point.w * Nj;
|
||||
C.x += point.x * wNj;
|
||||
C.y += point.y * wNj;
|
||||
C.z += point.z * wNj;
|
||||
C.w += point.w * Nj;
|
||||
|
||||
}
|
||||
|
||||
return C;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Calculate basis functions derivatives. See The NURBS Book, page 72, algorithm A2.3.
|
||||
|
||||
span : span in which u lies
|
||||
u : parametric point
|
||||
p : degree
|
||||
n : number of derivatives to calculate
|
||||
U : knot vector
|
||||
|
||||
returns array[n+1][p+1] with basis functions derivatives
|
||||
*/
|
||||
function calcBasisFunctionDerivatives( span, u, p, n, U ) {
|
||||
|
||||
const zeroArr = [];
|
||||
for ( let i = 0; i <= p; ++ i )
|
||||
zeroArr[ i ] = 0.0;
|
||||
|
||||
const ders = [];
|
||||
|
||||
for ( let i = 0; i <= n; ++ i )
|
||||
ders[ i ] = zeroArr.slice( 0 );
|
||||
|
||||
const ndu = [];
|
||||
|
||||
for ( let i = 0; i <= p; ++ i )
|
||||
ndu[ i ] = zeroArr.slice( 0 );
|
||||
|
||||
ndu[ 0 ][ 0 ] = 1.0;
|
||||
|
||||
const left = zeroArr.slice( 0 );
|
||||
const right = zeroArr.slice( 0 );
|
||||
|
||||
for ( let j = 1; j <= p; ++ j ) {
|
||||
|
||||
left[ j ] = u - U[ span + 1 - j ];
|
||||
right[ j ] = U[ span + j ] - u;
|
||||
|
||||
let saved = 0.0;
|
||||
|
||||
for ( let r = 0; r < j; ++ r ) {
|
||||
|
||||
const rv = right[ r + 1 ];
|
||||
const lv = left[ j - r ];
|
||||
ndu[ j ][ r ] = rv + lv;
|
||||
|
||||
const temp = ndu[ r ][ j - 1 ] / ndu[ j ][ r ];
|
||||
ndu[ r ][ j ] = saved + rv * temp;
|
||||
saved = lv * temp;
|
||||
|
||||
}
|
||||
|
||||
ndu[ j ][ j ] = saved;
|
||||
|
||||
}
|
||||
|
||||
for ( let j = 0; j <= p; ++ j ) {
|
||||
|
||||
ders[ 0 ][ j ] = ndu[ j ][ p ];
|
||||
|
||||
}
|
||||
|
||||
for ( let r = 0; r <= p; ++ r ) {
|
||||
|
||||
let s1 = 0;
|
||||
let s2 = 1;
|
||||
|
||||
const a = [];
|
||||
for ( let i = 0; i <= p; ++ i ) {
|
||||
|
||||
a[ i ] = zeroArr.slice( 0 );
|
||||
|
||||
}
|
||||
|
||||
a[ 0 ][ 0 ] = 1.0;
|
||||
|
||||
for ( let k = 1; k <= n; ++ k ) {
|
||||
|
||||
let d = 0.0;
|
||||
const rk = r - k;
|
||||
const pk = p - k;
|
||||
|
||||
if ( r >= k ) {
|
||||
|
||||
a[ s2 ][ 0 ] = a[ s1 ][ 0 ] / ndu[ pk + 1 ][ rk ];
|
||||
d = a[ s2 ][ 0 ] * ndu[ rk ][ pk ];
|
||||
|
||||
}
|
||||
|
||||
const j1 = ( rk >= - 1 ) ? 1 : - rk;
|
||||
const j2 = ( r - 1 <= pk ) ? k - 1 : p - r;
|
||||
|
||||
for ( let j = j1; j <= j2; ++ j ) {
|
||||
|
||||
a[ s2 ][ j ] = ( a[ s1 ][ j ] - a[ s1 ][ j - 1 ] ) / ndu[ pk + 1 ][ rk + j ];
|
||||
d += a[ s2 ][ j ] * ndu[ rk + j ][ pk ];
|
||||
|
||||
}
|
||||
|
||||
if ( r <= pk ) {
|
||||
|
||||
a[ s2 ][ k ] = - a[ s1 ][ k - 1 ] / ndu[ pk + 1 ][ r ];
|
||||
d += a[ s2 ][ k ] * ndu[ r ][ pk ];
|
||||
|
||||
}
|
||||
|
||||
ders[ k ][ r ] = d;
|
||||
|
||||
const j = s1;
|
||||
s1 = s2;
|
||||
s2 = j;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
let r = p;
|
||||
|
||||
for ( let k = 1; k <= n; ++ k ) {
|
||||
|
||||
for ( let j = 0; j <= p; ++ j ) {
|
||||
|
||||
ders[ k ][ j ] *= r;
|
||||
|
||||
}
|
||||
|
||||
r *= p - k;
|
||||
|
||||
}
|
||||
|
||||
return ders;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Calculate derivatives of a B-Spline. See The NURBS Book, page 93, algorithm A3.2.
|
||||
|
||||
p : degree
|
||||
U : knot vector
|
||||
P : control points
|
||||
u : Parametric points
|
||||
nd : number of derivatives
|
||||
|
||||
returns array[d+1] with derivatives
|
||||
*/
|
||||
function calcBSplineDerivatives( p, U, P, u, nd ) {
|
||||
|
||||
const du = nd < p ? nd : p;
|
||||
const CK = [];
|
||||
const span = findSpan( p, u, U );
|
||||
const nders = calcBasisFunctionDerivatives( span, u, p, du, U );
|
||||
const Pw = [];
|
||||
|
||||
for ( let i = 0; i < P.length; ++ i ) {
|
||||
|
||||
const point = P[ i ].clone();
|
||||
const w = point.w;
|
||||
|
||||
point.x *= w;
|
||||
point.y *= w;
|
||||
point.z *= w;
|
||||
|
||||
Pw[ i ] = point;
|
||||
|
||||
}
|
||||
|
||||
for ( let k = 0; k <= du; ++ k ) {
|
||||
|
||||
const point = Pw[ span - p ].clone().multiplyScalar( nders[ k ][ 0 ] );
|
||||
|
||||
for ( let j = 1; j <= p; ++ j ) {
|
||||
|
||||
point.add( Pw[ span - p + j ].clone().multiplyScalar( nders[ k ][ j ] ) );
|
||||
|
||||
}
|
||||
|
||||
CK[ k ] = point;
|
||||
|
||||
}
|
||||
|
||||
for ( let k = du + 1; k <= nd + 1; ++ k ) {
|
||||
|
||||
CK[ k ] = new Vector4( 0, 0, 0 );
|
||||
|
||||
}
|
||||
|
||||
return CK;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Calculate "K over I"
|
||||
|
||||
returns k!/(i!(k-i)!)
|
||||
*/
|
||||
function calcKoverI( k, i ) {
|
||||
|
||||
let nom = 1;
|
||||
|
||||
for ( let j = 2; j <= k; ++ j ) {
|
||||
|
||||
nom *= j;
|
||||
|
||||
}
|
||||
|
||||
let denom = 1;
|
||||
|
||||
for ( let j = 2; j <= i; ++ j ) {
|
||||
|
||||
denom *= j;
|
||||
|
||||
}
|
||||
|
||||
for ( let j = 2; j <= k - i; ++ j ) {
|
||||
|
||||
denom *= j;
|
||||
|
||||
}
|
||||
|
||||
return nom / denom;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Calculate derivatives (0-nd) of rational curve. See The NURBS Book, page 127, algorithm A4.2.
|
||||
|
||||
Pders : result of function calcBSplineDerivatives
|
||||
|
||||
returns array with derivatives for rational curve.
|
||||
*/
|
||||
function calcRationalCurveDerivatives( Pders ) {
|
||||
|
||||
const nd = Pders.length;
|
||||
const Aders = [];
|
||||
const wders = [];
|
||||
|
||||
for ( let i = 0; i < nd; ++ i ) {
|
||||
|
||||
const point = Pders[ i ];
|
||||
Aders[ i ] = new Vector3( point.x, point.y, point.z );
|
||||
wders[ i ] = point.w;
|
||||
|
||||
}
|
||||
|
||||
const CK = [];
|
||||
|
||||
for ( let k = 0; k < nd; ++ k ) {
|
||||
|
||||
const v = Aders[ k ].clone();
|
||||
|
||||
for ( let i = 1; i <= k; ++ i ) {
|
||||
|
||||
v.sub( CK[ k - i ].clone().multiplyScalar( calcKoverI( k, i ) * wders[ i ] ) );
|
||||
|
||||
}
|
||||
|
||||
CK[ k ] = v.divideScalar( wders[ 0 ] );
|
||||
|
||||
}
|
||||
|
||||
return CK;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Calculate NURBS curve derivatives. See The NURBS Book, page 127, algorithm A4.2.
|
||||
|
||||
p : degree
|
||||
U : knot vector
|
||||
P : control points in homogeneous space
|
||||
u : parametric points
|
||||
nd : number of derivatives
|
||||
|
||||
returns array with derivatives.
|
||||
*/
|
||||
function calcNURBSDerivatives( p, U, P, u, nd ) {
|
||||
|
||||
const Pders = calcBSplineDerivatives( p, U, P, u, nd );
|
||||
return calcRationalCurveDerivatives( Pders );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Calculate rational B-Spline surface point. See The NURBS Book, page 134, algorithm A4.3.
|
||||
|
||||
p1, p2 : degrees of B-Spline surface
|
||||
U1, U2 : knot vectors
|
||||
P : control points (x, y, z, w)
|
||||
u, v : parametric values
|
||||
|
||||
returns point for given (u, v)
|
||||
*/
|
||||
function calcSurfacePoint( p, q, U, V, P, u, v, target ) {
|
||||
|
||||
const uspan = findSpan( p, u, U );
|
||||
const vspan = findSpan( q, v, V );
|
||||
const Nu = calcBasisFunctions( uspan, u, p, U );
|
||||
const Nv = calcBasisFunctions( vspan, v, q, V );
|
||||
const temp = [];
|
||||
|
||||
for ( let l = 0; l <= q; ++ l ) {
|
||||
|
||||
temp[ l ] = new Vector4( 0, 0, 0, 0 );
|
||||
for ( let k = 0; k <= p; ++ k ) {
|
||||
|
||||
const point = P[ uspan - p + k ][ vspan - q + l ].clone();
|
||||
const w = point.w;
|
||||
point.x *= w;
|
||||
point.y *= w;
|
||||
point.z *= w;
|
||||
temp[ l ].add( point.multiplyScalar( Nu[ k ] ) );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const Sw = new Vector4( 0, 0, 0, 0 );
|
||||
for ( let l = 0; l <= q; ++ l ) {
|
||||
|
||||
Sw.add( temp[ l ].multiplyScalar( Nv[ l ] ) );
|
||||
|
||||
}
|
||||
|
||||
Sw.divideScalar( Sw.w );
|
||||
target.set( Sw.x, Sw.y, Sw.z );
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
export {
|
||||
findSpan,
|
||||
calcBasisFunctions,
|
||||
calcBSplinePoint,
|
||||
calcBasisFunctionDerivatives,
|
||||
calcBSplineDerivatives,
|
||||
calcKoverI,
|
||||
calcRationalCurveDerivatives,
|
||||
calcNURBSDerivatives,
|
||||
calcSurfacePoint,
|
||||
};
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,15 +0,0 @@
|
|||
all:
|
||||
make build
|
||||
make install
|
||||
make clean
|
||||
|
||||
build:
|
||||
emcc -O2 -c loader_symbol.c
|
||||
emcc --no-entry loader_symbol.o -o loader_symbol.wasm
|
||||
|
||||
install:
|
||||
zip -r application_dev.zip .
|
||||
mv application_dev.zip ../../../dist/data/state/plugins/
|
||||
|
||||
clean:
|
||||
rm *.o *.wasm
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
import assert from "../../assets/lib/assert.js";
|
||||
import loadWASM, { writeFS, readFS } from "../../assets/helpers/loader_wasm.js";
|
||||
|
||||
export default async function(ITable) {
|
||||
const { instance } = await loadWASM(import.meta.url, "./loader_symbol.wasm");
|
||||
|
||||
return class TableImpl extends ITable {
|
||||
constructor(response) {
|
||||
super();
|
||||
const fdIn = writeFS(new Uint8Array(response));
|
||||
const fdOut = writeFS(new Uint8Array([]));
|
||||
const res = assert.truthy(instance.exports["execute"])(fdIn, fdOut);
|
||||
if (res !== 0) throw new Error(`WASM exited with code=${res}`);
|
||||
const buffer = readFS(fdOut);
|
||||
|
||||
this.header = [
|
||||
{ name: "Mode", size: 3 },
|
||||
{ name: "Timestamp", size: 6 },
|
||||
{ name: "Size", size: 4 },
|
||||
{ name: "Owner", size: 6 },
|
||||
{ name: "Group", size: 6 },
|
||||
{ name: "Object", size: 40 },
|
||||
];
|
||||
this.rows = new TextDecoder().decode(buffer).trimRight().split("\n").map((line) => {
|
||||
const row = line.split(",");
|
||||
return {
|
||||
"Object": row[0],
|
||||
"Timestamp": row[1],
|
||||
"Size": row[5],
|
||||
"Mode": row[4],
|
||||
"Owner": row[2],
|
||||
"Group": row[3],
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
getHeader() {
|
||||
return this.header;
|
||||
}
|
||||
|
||||
getBody() {
|
||||
return this.rows;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <emscripten/emscripten.h>
|
||||
|
||||
#define ARMAG "!<arch>\n"
|
||||
#define SARMAG sizeof(ARMAG) - 1
|
||||
#define AR_HDR_SIZE 60
|
||||
|
||||
struct ar_hdr {
|
||||
char name[16];
|
||||
char timestamp[12];
|
||||
char owner[6];
|
||||
char group[6];
|
||||
char mode[8];
|
||||
char size[10];
|
||||
char fmag[2];
|
||||
};
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE int execute(int fdinput, int fdoutput) {
|
||||
if (fdinput == 0) {
|
||||
fprintf(stderr, "ERROR - missing input %d\n", fdinput);
|
||||
return 1;
|
||||
}
|
||||
if (fdoutput == 0) {
|
||||
fprintf(stderr, "ERROR - missing input %d\n", fdoutput);
|
||||
return 1;
|
||||
}
|
||||
|
||||
FILE* finput = fdopen(fdinput, "rb");
|
||||
if (!finput) {
|
||||
fprintf(stderr, "ERROR - cannot open input file\n");
|
||||
return 1;
|
||||
}
|
||||
FILE* foutput = fdopen(fdoutput, "wb");
|
||||
if (!foutput) {
|
||||
fprintf(stderr, "ERROR - cannot open output file\n");
|
||||
fclose(finput);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char magic[SARMAG];
|
||||
size_t c = fread(magic, 1, SARMAG, finput);
|
||||
if (c == 0) {
|
||||
fprintf(stderr, "ERROR count=%zu error=%d\n", c, ferror(finput));
|
||||
fclose(finput);
|
||||
fclose(foutput);
|
||||
return 1;
|
||||
}
|
||||
if (strncmp(magic, ARMAG, SARMAG) != 0) {
|
||||
fprintf(stderr, "ERROR bad magic value");
|
||||
fclose(finput);
|
||||
fclose(foutput);
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct ar_hdr header;
|
||||
while (fread(&header, 1, AR_HDR_SIZE, finput) == AR_HDR_SIZE) {
|
||||
if (strncmp(header.fmag, "`\n", 2) != 0) {
|
||||
fprintf(stderr, "Invalid header format.\n");
|
||||
break;
|
||||
}
|
||||
long size = strtol(header.size, NULL, 10);
|
||||
char filename[17] = {0};
|
||||
strncpy(filename, header.name, 16);
|
||||
for (int i = strlen(filename) - 1; i >= 0; i--) {
|
||||
if (filename[i] == ' ' || filename[i] == '/') {
|
||||
filename[i] = '\0';
|
||||
}
|
||||
}
|
||||
if (strlen(filename) > 0) fprintf(
|
||||
foutput,
|
||||
"%.16s,%ld,%ld,%ld,%ld,%ld\n",
|
||||
filename,
|
||||
strtol(header.timestamp, NULL, 10),
|
||||
strtol(header.owner, NULL, 10),
|
||||
strtol(header.group, NULL, 10),
|
||||
strtol(header.mode, NULL, 10),
|
||||
size,
|
||||
);
|
||||
fseek(finput, (size + 1) & ~1, SEEK_CUR);
|
||||
}
|
||||
|
||||
fprintf(stdout, "hello world!\n");
|
||||
fflush(foutput);
|
||||
fclose(foutput);
|
||||
fclose(finput);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
{
|
||||
"author": "Filestash Pty Ltd",
|
||||
"version": "v0.0",
|
||||
"modules": [
|
||||
{
|
||||
"type": "xdg-open",
|
||||
"mime": "application/x-archive",
|
||||
"application": "table"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
all:
|
||||
make install
|
||||
|
||||
install:
|
||||
zip -r application_map.zip .
|
||||
mv application_map.zip ../../../dist/data/state/plugins/
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
export const PLUGINS = [
|
||||
"plugin_grayscale",
|
||||
];
|
||||
export const DEFAULT_TILE_SERVER = "https://tile.openstreetmap.org/{z}/{x}/{y}.png";
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
import { PLUGINS, DEFAULT_TILE_SERVER } from "./constant.js";
|
||||
|
||||
export default async function(IMap) {
|
||||
const plugins = await Promise.all(PLUGINS.map((name) => import(`./plugins/${name}.js`)));
|
||||
|
||||
return class MapImpl extends IMap {
|
||||
constructor(response, { map, $page }) {
|
||||
super();
|
||||
this.response = JSON.parse(new TextDecoder().decode(response));
|
||||
|
||||
window.L.tileLayer(DEFAULT_TILE_SERVER, { maxZoom: 21 }).addTo(map);
|
||||
plugins.forEach((plugin) => plugin.default({ map, $page }));
|
||||
}
|
||||
|
||||
async toGeoJSON() {
|
||||
return this.response;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,128 +0,0 @@
|
|||
import { PLUGINS, DEFAULT_TILE_SERVER } from "./constant.js";
|
||||
|
||||
export default async function(IMap) {
|
||||
const plugins = await Promise.all(PLUGINS.map((name) => import(`./plugins/${name}.js`)));
|
||||
|
||||
return class MapImpl extends IMap {
|
||||
constructor(response, { L, map, $page }) {
|
||||
super();
|
||||
const xmlDoc = new DOMParser().parseFromString(
|
||||
new TextDecoder().decode(response),
|
||||
"application/xml",
|
||||
);
|
||||
this.xmlDoc = xmlDoc;
|
||||
L.tileLayer(DEFAULT_TILE_SERVER, { maxZoom: 21 }).addTo(map);
|
||||
plugins.forEach((plugin) => plugin.default({ map, $page }));
|
||||
}
|
||||
|
||||
async toGeoJSON() {
|
||||
let geoJSON = {
|
||||
type: "FeatureCollection",
|
||||
features: [],
|
||||
};
|
||||
this.xmlDoc.querySelectorAll("wpt").forEach((wayPoint) => {
|
||||
geoJSON.features.push({
|
||||
type: "Feature",
|
||||
geometry: {
|
||||
type: "Point",
|
||||
coordinates: [
|
||||
Number(wayPoint.getAttribute("lon")),
|
||||
Number(wayPoint.getAttribute("lat")),
|
||||
],
|
||||
},
|
||||
properties: {
|
||||
group: "waypoint",
|
||||
"popup::type": "html",
|
||||
"popup::content": createLegendFromXML(wayPoint),
|
||||
},
|
||||
});
|
||||
});
|
||||
this.xmlDoc.querySelectorAll("rte").forEach((route) => {
|
||||
const coordinates = [];
|
||||
route.querySelectorAll("rtept").forEach((point) => {
|
||||
const lon = Number(point.getAttribute("lon"));
|
||||
const lat = Number(point.getAttribute("lat"));
|
||||
if (!isNaN(lon) && !isNaN(lat)) {
|
||||
coordinates.push([lon, lat]);
|
||||
}
|
||||
});
|
||||
if (coordinates.length > 0) geoJSON.features.push({
|
||||
type: "Feature",
|
||||
geometry: {
|
||||
type: "LineString",
|
||||
coordinates: coordinates,
|
||||
},
|
||||
properties: {
|
||||
group: "path",
|
||||
weight: 5,
|
||||
name: route.querySelector("name").textContent,
|
||||
},
|
||||
});
|
||||
});
|
||||
this.xmlDoc.querySelectorAll("trk").forEach((track) => {
|
||||
track.querySelectorAll("trkseg").forEach((segment) => {
|
||||
const group = "Track: " + track.querySelector("name").textContent;
|
||||
const coordinates = [];
|
||||
segment.querySelectorAll("trkpt").forEach((point) => {
|
||||
const lon = Number(point.getAttribute("lon"));
|
||||
const lat = Number(point.getAttribute("lat"));
|
||||
if (!isNaN(lon) && !isNaN(lat)) {
|
||||
coordinates.push([lon, lat]);
|
||||
}
|
||||
});
|
||||
if (coordinates.length > 0) {
|
||||
geoJSON.features.push({
|
||||
type: "Feature",
|
||||
geometry: {
|
||||
type: "LineString",
|
||||
coordinates: coordinates,
|
||||
},
|
||||
properties: {
|
||||
group,
|
||||
color: "brown",
|
||||
weight: 3,
|
||||
name: track.querySelector("name").textContent,
|
||||
},
|
||||
});
|
||||
geoJSON.features.push({
|
||||
type: "Feature",
|
||||
geometry: {
|
||||
type: "Point",
|
||||
coordinates: coordinates[0],
|
||||
},
|
||||
properties: {
|
||||
group,
|
||||
color: "green",
|
||||
name: "Start: " + group,
|
||||
},
|
||||
});
|
||||
geoJSON.features.push({
|
||||
type: "Feature",
|
||||
geometry: {
|
||||
type: "Point",
|
||||
coordinates: coordinates.slice(-1)[0],
|
||||
},
|
||||
properties: {
|
||||
group,
|
||||
color: "red",
|
||||
name: "Arrival: " + group,
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
return geoJSON;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createLegendFromXML(point) {
|
||||
return [...point.children]
|
||||
.map((tag) => `
|
||||
<div class="ellipsis" style="line-height: 1rem;">
|
||||
<strong style="text-transform: capitalize;">${tag.tagName}: </strong>
|
||||
${tag.textContent || "N/A"}
|
||||
</div>
|
||||
`)
|
||||
.join("");
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
import { PLUGINS, DEFAULT_TILE_SERVER } from "./constant.js";
|
||||
|
||||
export default async function(IMap) {
|
||||
let modules = await Promise.all(PLUGINS.map((name) => import(`./plugins/${name}.js`)));
|
||||
|
||||
return class MapImpl extends IMap {
|
||||
constructor(response, { map, $page }) {
|
||||
super();
|
||||
for (let i=0; i<PLUGINS.length; i++) {
|
||||
modules.forEach((module) => module.default({ map, $page }));
|
||||
}
|
||||
const xmlDoc = new DOMParser().parseFromString(
|
||||
new TextDecoder().decode(response),
|
||||
"application/xml",
|
||||
);
|
||||
const svcURL = (function() {
|
||||
const svc = xmlDoc.querySelector("Capability OnlineResource");
|
||||
if (!svc) return "";
|
||||
return svc.getAttribute("xlink:href");
|
||||
}());
|
||||
let _layer = "";
|
||||
const baseLayers = {};
|
||||
xmlDoc.querySelectorAll("Layer").forEach((layer) => {
|
||||
_layer = layer.querySelector("Name").textContent;
|
||||
baseLayers[layer.querySelector("Title").textContent] = window.L.tileLayer.wms(svcURL, {
|
||||
layers: _layer,
|
||||
});
|
||||
});
|
||||
map.setView([0, 0], 1);
|
||||
window.L.tileLayer.wms(svcURL, { layers: _layer }).addTo(map);
|
||||
window.L.control.layers(baseLayers, {}).addTo(map);
|
||||
}
|
||||
|
||||
async toGeoJSON() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
{
|
||||
"author": "Filestash Pty Ltd",
|
||||
"version": "v0.0",
|
||||
"modules": [
|
||||
{
|
||||
"type": "xdg-open",
|
||||
"mime": "application/geo+json",
|
||||
"entrypoint": "/index_geojson.js",
|
||||
"application": "map"
|
||||
},
|
||||
{
|
||||
"type": "xdg-open",
|
||||
"mime": "application/vnd.ogc.wms_xml",
|
||||
"entrypoint": "/index_wms.js",
|
||||
"application": "map"
|
||||
},
|
||||
{
|
||||
"type": "xdg-open",
|
||||
"mime": "application/gpx+xml",
|
||||
"entrypoint": "/index_gpx.js",
|
||||
"application": "map"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
import { createElement } from "../../../assets/lib/skeleton/index.js";
|
||||
|
||||
const PERCENT = "85%";
|
||||
|
||||
export default async function({ $page }) {
|
||||
$page.appendChild(createElement(`
|
||||
<style>#map img.leaflet-tile { filter: grayscale(${PERCENT}); }</style>
|
||||
`));
|
||||
}
|
||||
|
|
@ -87,11 +87,12 @@ func Build(r *mux.Router, a App) {
|
|||
r.HandleFunc(WithBase("/api/plugin"), NewMiddlewareChain(PluginExportHandler, append(middlewares, PublicCORS), a)).Methods("GET", "OPTIONS")
|
||||
r.HandleFunc(WithBase("/api/config"), NewMiddlewareChain(PublicConfigHandler, append(middlewares, PublicCORS), a)).Methods("GET", "OPTIONS")
|
||||
middlewares = []Middleware{StaticHeaders, SecureHeaders, PublicCORS, PluginInjector}
|
||||
r.PathPrefix(WithBase("/assets")).Handler(http.HandlerFunc(NewMiddlewareChain(ServeFile("/"), middlewares, a))).Methods("GET", "OPTIONS")
|
||||
r.HandleFunc(WithBase("/assets/"+BUILD_REF+"/plugin/{name}.zip/{path:.+}"), NewMiddlewareChain(PluginStaticHandler, middlewares, a)).Methods("GET", "OPTIONS")
|
||||
r.HandleFunc(WithBase("/assets/"+BUILD_REF+"/plugin/{name}.zip"), NewMiddlewareChain(PluginDownloadHandler, middlewares, a)).Methods("GET")
|
||||
r.PathPrefix(WithBase("/assets/"+BUILD_REF)).Handler(http.HandlerFunc(NewMiddlewareChain(ServeFile("/"), middlewares, a))).Methods("GET", "OPTIONS")
|
||||
r.PathPrefix(WithBase("/assets/bundle")).Handler(http.HandlerFunc(NewMiddlewareChain(ServeBundle, middlewares, a))).Methods("GET", "OPTIONS")
|
||||
r.HandleFunc(WithBase("/sw.js"), http.HandlerFunc(NewMiddlewareChain(ServeFile("/assets/"), middlewares, a))).Methods("GET")
|
||||
r.HandleFunc(WithBase("/favicon.ico"), NewMiddlewareChain(ServeFavicon, middlewares, a)).Methods("GET")
|
||||
r.HandleFunc(WithBase("/plugin/{name}/{path:.+}"), NewMiddlewareChain(PluginStaticHandler, middlewares, a)).Methods("GET")
|
||||
r.HandleFunc(WithBase("/plugin/{name}.zip"), NewMiddlewareChain(PluginDownloadHandler, middlewares, a)).Methods("GET")
|
||||
|
||||
// Other endpoints
|
||||
middlewares = []Middleware{ApiHeaders, PluginInjector, PublicCORS}
|
||||
|
|
|
|||
Loading…
Reference in a new issue