🎨 format

This commit is contained in:
Rune Harlyk
2025-10-11 10:42:32 +02:00
parent 4d51b9f556
commit 91a7b170fe
139 changed files with 6645 additions and 6317 deletions
+12 -12
View File
@@ -1,15 +1,15 @@
export class throttler {
private _throttlePause: boolean;
constructor() {
this._throttlePause = false;
}
throttle = (callback: Function, time: number) => {
if (this._throttlePause) return;
private _throttlePause: boolean
constructor() {
this._throttlePause = false
}
throttle = (callback: Function, time: number) => {
if (this._throttlePause) return
this._throttlePause = true;
setTimeout(() => {
callback();
this._throttlePause = false;
}, time);
};
this._throttlePause = true
setTimeout(() => {
callback()
this._throttlePause = false
}, time)
}
}
+5 -5
View File
@@ -1,6 +1,6 @@
export const daisyColor = (name: string, opacity: number = 100) => {
const color = getComputedStyle(document.documentElement).getPropertyValue(name).trim();
if (opacity >= 100) return color;
const alpha = Math.min(Math.max(opacity, 0), 100) / 100;
return `${color.replace(/(\/\s*\d+(\.\d+)?\))|\)$/, '')} / ${alpha})`;
};
const color = getComputedStyle(document.documentElement).getPropertyValue(name).trim()
if (opacity >= 100) return color
const alpha = Math.min(Math.max(opacity, 0), 100) / 100
return `${color.replace(/(\/\s*\d+(\.\d+)?\))|\)$/, '')} / ${alpha})`
}
+9 -9
View File
@@ -1,9 +1,9 @@
export * from './result';
export * from './string-utilities';
export * from './svelte-utilities';
export * from './math-utilities';
export * from './buffer-utilities';
export * from './model-utilities';
export * from './position-utilities';
export * from './string-utilities';
export * from './color-utilities';
export * from './result'
export * from './string-utilities'
export * from './svelte-utilities'
export * from './math-utilities'
export * from './buffer-utilities'
export * from './model-utilities'
export * from './position-utilities'
export * from './string-utilities'
export * from './color-utilities'
+13 -13
View File
@@ -1,18 +1,18 @@
export const toUint8 = (number: number, min: number, max: number) => {
number = Math.max(min, Math.min(max, number));
let scaled = ((number - min) / (max - min)) * 255;
return Math.round(scaled) & 0xff;
};
number = Math.max(min, Math.min(max, number))
let scaled = ((number - min) / (max - min)) * 255
return Math.round(scaled) & 0xff
}
export const toInt8 = (number: number, min: number, max: number) => {
number = Math.max(min, Math.min(max, number));
let scaled = ((number - min) / (max - min)) * 255 - 128;
return Math.max(-128, Math.min(127, Math.round(scaled))) | 0;
};
number = Math.max(min, Math.min(max, number))
let scaled = ((number - min) / (max - min)) * 255 - 128
return Math.max(-128, Math.min(127, Math.round(scaled))) | 0
}
export const fromInt8 = (int8: number, min: number, max: number) => {
int8 = Math.max(-128, Math.min(127, int8));
const scaled = (int8 + 128) / 255;
const number = scaled * (max - min) + min;
return number;
};
int8 = Math.max(-128, Math.min(127, int8))
const scaled = (int8 + 128) / 255
const number = scaled * (max - min) + min
return number
}
+58 -57
View File
@@ -10,84 +10,85 @@ import { get } from 'svelte/store'
let model_xml: XMLDocument
export const populateModelCache = async () => {
await cacheModelFiles()
const modelRes = await loadModel(get(currentVariant).model)
if (modelRes.isOk()) {
const [urdf, JOINT_NAME] = modelRes.inner
jointNames.set(JOINT_NAME)
model.set(urdf)
} else {
console.error(modelRes.inner, { exception: modelRes.exception })
}
await cacheModelFiles()
const modelRes = await loadModel(get(currentVariant).model)
if (modelRes.isOk()) {
const [urdf, JOINT_NAME] = modelRes.inner
jointNames.set(JOINT_NAME)
model.set(urdf)
} else {
console.error(modelRes.inner, { exception: modelRes.exception })
}
}
export const cacheModelFiles = async () => {
const data = await fetch(get(currentVariant).stl)
const data = await fetch(get(currentVariant).stl)
const files = uzip.parse(await data.arrayBuffer())
const files = uzip.parse(await data.arrayBuffer())
for (const [path, data] of Object.entries(files) as [path: string, data: Uint8Array][]) {
const url = new URL(path, window.location.href)
fileService?.saveFile(url.toString(), data)
}
for (const [path, data] of Object.entries(files) as [path: string, data: Uint8Array][]) {
const url = new URL(path, window.location.href)
fileService?.saveFile(url.toString(), data)
}
}
export const loadModel = async (url: string): Promise<Result<[URDFRobot, string[]], string>> => {
const urdfLoader = new URDFLoader()
urdfLoader.workingPath = LoaderUtils.extractUrlBase(url)
const urdfLoader = new URDFLoader()
urdfLoader.workingPath = LoaderUtils.extractUrlBase(url)
let xml = url.endsWith('.xacro') ? await loadXacro(url) : await fetch(url).then(res => res.text())
let xml =
url.endsWith('.xacro') ? await loadXacro(url) : await fetch(url).then(res => res.text())
if (typeof xml === 'string') {
xml = new window.DOMParser().parseFromString(xml, 'text/xml')
}
return new Promise(resolve => {
model_xml = xml
try {
const model = urdfLoader.parse(xml)
setupRobot(model)
const joints = Object.entries(model.joints)
.filter(joint => joint[1].jointType !== 'fixed')
.map(joint => joint[0])
resolve(Result.ok([model, joints]))
} catch (error) {
resolve(Result.err('Failed to load model', error))
if (typeof xml === 'string') {
xml = new window.DOMParser().parseFromString(xml, 'text/xml')
}
})
return new Promise(resolve => {
model_xml = xml
try {
const model = urdfLoader.parse(xml)
setupRobot(model)
const joints = Object.entries(model.joints)
.filter(joint => joint[1].jointType !== 'fixed')
.map(joint => joint[0])
resolve(Result.ok([model, joints]))
} catch (error) {
resolve(Result.err('Failed to load model', error))
}
})
}
const loadXacro = async (url: string): Promise<XMLDocument> =>
new Promise((resolve, reject) => {
new XacroLoader().load(url, resolve, reject)
})
new Promise((resolve, reject) => {
new XacroLoader().load(url, resolve, reject)
})
function setupRobot(robot: URDFRobot) {
robot.rotation.x = -Math.PI / 2
robot.rotation.z = Math.PI / 2
robot.scale.setScalar(10)
robot.traverse(c => (c.castShadow = true))
robot.updateMatrixWorld(true)
robot.rotation.x = -Math.PI / 2
robot.rotation.z = Math.PI / 2
robot.scale.setScalar(10)
robot.traverse(c => (c.castShadow = true))
robot.updateMatrixWorld(true)
}
export function getToeWorldPositions(robot: URDFRobot): Vector3[] {
const toes: Vector3[] = []
robot.traverse(c => {
if (c.name.includes('toe') && !c.name.includes('_link'))
toes.push(c.getWorldPosition(new Vector3()))
})
return toes
const toes: Vector3[] = []
robot.traverse(c => {
if (c.name.includes('toe') && !c.name.includes('_link'))
toes.push(c.getWorldPosition(new Vector3()))
})
return toes
}
export const extractFootColor = () => {
const colorElem = model_xml.querySelector('material[name=foot_color] > color') as Element
const colorAttrStr = colorElem.getAttribute('rgba') as string
const colorStr = colorAttrStr
.split(' ')
.slice(0, 3)
.map(val => Math.floor(+val * 255))
.join(', ')
const colorElem = model_xml.querySelector('material[name=foot_color] > color') as Element
const colorAttrStr = colorElem.getAttribute('rgba') as string
const colorStr = colorAttrStr
.split(' ')
.slice(0, 3)
.map(val => Math.floor(+val * 255))
.join(', ')
return new Color(`rgb(${colorStr})`)
return new Color(`rgb(${colorStr})`)
}
+75 -73
View File
@@ -1,84 +1,86 @@
class SunCalculator {
calculateSunElevation(lat: number = 55, lon: number = 12) {
const now = new Date();
const JD = this.getJulianDate(now);
const solarDec = this.getSolarDeclination(JD);
const solarTime = this.getSolarTime(now, lon);
calculateSunElevation(lat: number = 55, lon: number = 12) {
const now = new Date()
const JD = this.getJulianDate(now)
const solarDec = this.getSolarDeclination(JD)
const solarTime = this.getSolarTime(now, lon)
const hourAngle = (solarTime - 12) * 15;
const elevation = Math.asin(
Math.sin(this.degToRad(lat)) * Math.sin(solarDec) +
Math.cos(this.degToRad(lat)) * Math.cos(solarDec) * Math.cos(this.degToRad(hourAngle))
);
const hourAngle = (solarTime - 12) * 15
const elevation = Math.asin(
Math.sin(this.degToRad(lat)) * Math.sin(solarDec) +
Math.cos(this.degToRad(lat)) *
Math.cos(solarDec) *
Math.cos(this.degToRad(hourAngle))
)
return this.radToDeg(elevation);
}
return this.radToDeg(elevation)
}
getJulianDate(date: Date) {
const Y = date.getUTCFullYear();
const M = date.getUTCMonth() + 1;
const D =
date.getUTCDate() +
date.getUTCHours() / 24 +
date.getUTCMinutes() / 1440 +
date.getUTCSeconds() / 86400;
const A = Math.floor((14 - M) / 12);
const Y1 = Y + 4800 - A;
const M1 = M + 12 * A - 3;
return (
D +
Math.floor((153 * M1 + 2) / 5) +
365 * Y1 +
Math.floor(Y1 / 4) -
Math.floor(Y1 / 100) +
Math.floor(Y1 / 400) -
32045
);
}
getJulianDate(date: Date) {
const Y = date.getUTCFullYear()
const M = date.getUTCMonth() + 1
const D =
date.getUTCDate() +
date.getUTCHours() / 24 +
date.getUTCMinutes() / 1440 +
date.getUTCSeconds() / 86400
const A = Math.floor((14 - M) / 12)
const Y1 = Y + 4800 - A
const M1 = M + 12 * A - 3
return (
D +
Math.floor((153 * M1 + 2) / 5) +
365 * Y1 +
Math.floor(Y1 / 4) -
Math.floor(Y1 / 100) +
Math.floor(Y1 / 400) -
32045
)
}
getSolarDeclination(JulianDate: number) {
const n = JulianDate - 2451545;
const L = (280.46 + 0.9856474 * n) % 360;
const g = this.degToRad((357.528 + 0.9856003 * n) % 360);
const lambda = this.degToRad(L + 1.915 * Math.sin(g) + 0.02 * Math.sin(2 * g));
return Math.asin(Math.sin(lambda) * Math.sin(this.degToRad(23.44)));
}
getSolarDeclination(JulianDate: number) {
const n = JulianDate - 2451545
const L = (280.46 + 0.9856474 * n) % 360
const g = this.degToRad((357.528 + 0.9856003 * n) % 360)
const lambda = this.degToRad(L + 1.915 * Math.sin(g) + 0.02 * Math.sin(2 * g))
return Math.asin(Math.sin(lambda) * Math.sin(this.degToRad(23.44)))
}
getSolarTime(date: Date, lon: number) {
const EoT = this.getEquationOfTime(date);
const offset = date.getTimezoneOffset() / 60;
const standardMeridian = Math.round(lon / 15) * 15;
const solarTime =
date.getUTCHours() +
(date.getUTCMinutes() + (4 * (standardMeridian - lon) + EoT)) / 60 -
offset;
return (solarTime + 24) % 24;
}
getSolarTime(date: Date, lon: number) {
const EoT = this.getEquationOfTime(date)
const offset = date.getTimezoneOffset() / 60
const standardMeridian = Math.round(lon / 15) * 15
const solarTime =
date.getUTCHours() +
(date.getUTCMinutes() + (4 * (standardMeridian - lon) + EoT)) / 60 -
offset
return (solarTime + 24) % 24
}
getEquationOfTime(date: Date) {
const JD = this.getJulianDate(date);
const n = JD - 2451545;
const g = this.degToRad((357.528 + 0.9856003 * n) % 360);
const q = this.degToRad((280.46 + 0.9856474 * n) % 360);
return (
4 *
this.radToDeg(
0.000075 +
0.001868 * Math.cos(q) -
0.032077 * Math.sin(g) -
0.014615 * Math.cos(2 * q) -
0.040849 * Math.sin(2 * g)
)
);
}
getEquationOfTime(date: Date) {
const JD = this.getJulianDate(date)
const n = JD - 2451545
const g = this.degToRad((357.528 + 0.9856003 * n) % 360)
const q = this.degToRad((280.46 + 0.9856474 * n) % 360)
return (
4 *
this.radToDeg(
0.000075 +
0.001868 * Math.cos(q) -
0.032077 * Math.sin(g) -
0.014615 * Math.cos(2 * q) -
0.040849 * Math.sin(2 * g)
)
)
}
degToRad(deg: number) {
return deg * (Math.PI / 180);
}
degToRad(deg: number) {
return deg * (Math.PI / 180)
}
radToDeg(rad: number) {
return rad * (180 / Math.PI);
}
radToDeg(rad: number) {
return rad * (180 / Math.PI)
}
}
export const sunCalculator = new SunCalculator();
export const sunCalculator = new SunCalculator()
+34 -34
View File
@@ -1,42 +1,42 @@
export class Err<T, U> {
#inner: T;
#exception?: U;
#inner: T
#exception?: U
constructor(inner: T, exception?: U) {
this.#inner = inner;
this.#exception = exception;
}
constructor(inner: T, exception?: U) {
this.#inner = inner
this.#exception = exception
}
get inner(): T {
return this.#inner;
}
get inner(): T {
return this.#inner
}
get exception(): U | undefined {
return this.#exception;
}
get exception(): U | undefined {
return this.#exception
}
/**
* Type guard for `Ok`
* @returns `true` if `Ok`; `false` if `Err`
*/
isOk(): false {
return false;
}
/**
* Type guard for `Ok`
* @returns `true` if `Ok`; `false` if `Err`
*/
isOk(): false {
return false
}
/**
* Type guard for `Err`
* @returns `true` if `Err`; `false` if `Ok`
*/
isErr(): this is Err<T, U> {
return true;
}
/**
* Type guard for `Err`
* @returns `true` if `Err`; `false` if `Ok`
*/
isErr(): this is Err<T, U> {
return true
}
/**
* Create an `Err`
* @param inner
* @returns `Err(inner)`
*/
static new<E, F>(inner: E, exception: F): Err<E, F> {
return new Err<E, F>(inner, exception);
}
/**
* Create an `Err`
* @param inner
* @returns `Err(inner)`
*/
static new<E, F>(inner: E, exception: F): Err<E, F> {
return new Err<E, F>(inner, exception)
}
}
+3 -3
View File
@@ -1,3 +1,3 @@
export * from './err';
export * from './ok';
export * from './result';
export * from './err'
export * from './ok'
export * from './result'
+36 -36
View File
@@ -1,44 +1,44 @@
export class Ok<T> {
#inner: T;
#inner: T
constructor(inner: T) {
this.#inner = inner;
}
constructor(inner: T) {
this.#inner = inner
}
get inner(): T {
return this.#inner;
}
get inner(): T {
return this.#inner
}
/**
* Type guard for `Ok`
* @returns `true` if `Ok`; `false` if `Err`
*/
isOk(): this is Ok<T> {
return true;
}
/**
* Type guard for `Ok`
* @returns `true` if `Ok`; `false` if `Err`
*/
isOk(): this is Ok<T> {
return true
}
/**
* Type guard for `Err`
* @returns `true` if `Err`; `false` if `Ok`
*/
isErr(): false {
return false;
}
/**
* Type guard for `Err`
* @returns `true` if `Err`; `false` if `Ok`
*/
isErr(): false {
return false
}
/**
* Create an `Ok`
* @param inner
* @returns `Ok(inner)`
*/
static new<T>(inner: T): Ok<T> {
return new Ok<T>(inner);
}
/**
* Create an `Ok`
* @param inner
* @returns `Ok(inner)`
*/
static new<T>(inner: T): Ok<T> {
return new Ok<T>(inner)
}
/**
* Create an empty `Ok`
* @returns `Ok(void)`
*/
static void(): Ok<void> {
return new Ok(undefined);
}
/**
* Create an empty `Ok`
* @returns `Ok(void)`
*/
static void(): Ok<void> {
return new Ok(undefined)
}
}
+15 -15
View File
@@ -1,20 +1,20 @@
import { Err } from './err';
import { Ok } from './ok';
import { Err } from './err'
import { Ok } from './ok'
export type Result<T = unknown, E = unknown, F = unknown> = Ok<T> | Err<E, F>;
export type Result<T = unknown, E = unknown, F = unknown> = Ok<T> | Err<E, F>
export namespace Result {
/**
* @returns `Ok<T>`
*/
export function ok<T = unknown>(value: T) {
return Ok.new(value);
}
/**
* @returns `Ok<T>`
*/
export function ok<T = unknown>(value: T) {
return Ok.new(value)
}
/**
* @returns `Err<E, F>`
*/
export function err<E = unknown, F = unknown>(error: E, exception?: F) {
return Err.new(error, exception);
}
/**
* @returns `Err<E, F>`
*/
export function err<E = unknown, F = unknown>(error: E, exception?: F) {
return Err.new(error, exception)
}
}
+32 -32
View File
@@ -1,47 +1,47 @@
export const humanFileSize = (size: number): string => {
const units = ['B', 'kB', 'MB', 'GB', 'TB']
const i = size == 0 ? 0 : Math.floor(Math.log(size) / Math.log(1024))
return Number((size / Math.pow(1024, i)).toFixed(2)) * 1 + units[i]
const units = ['B', 'kB', 'MB', 'GB', 'TB']
const i = size == 0 ? 0 : Math.floor(Math.log(size) / Math.log(1024))
return Number((size / Math.pow(1024, i)).toFixed(2)) * 1 + units[i]
}
export const capitalize = (str: string): string => {
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase()
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase()
}
export const convertSeconds = (seconds: number) => {
// Calculate the number of seconds, minutes, hours, and days
let minutes = Math.floor(seconds / 60)
let hours = Math.floor(minutes / 60)
const days = Math.floor(hours / 24)
// Calculate the number of seconds, minutes, hours, and days
let minutes = Math.floor(seconds / 60)
let hours = Math.floor(minutes / 60)
const days = Math.floor(hours / 24)
// Calculate the remaining hours, minutes, and seconds
hours = hours % 24
minutes = minutes % 60
seconds = seconds % 60
// Calculate the remaining hours, minutes, and seconds
hours = hours % 24
minutes = minutes % 60
seconds = seconds % 60
// Create the formatted string
let result = ''
if (days > 0) {
result += days + ' day' + (days > 1 ? 's' : '') + ' '
}
if (hours > 0) {
result += hours + ' hour' + (hours > 1 ? 's' : '') + ' '
}
if (minutes > 0) {
result += minutes + ' minute' + (minutes > 1 ? 's' : '') + ' '
}
result += seconds + ' second' + (seconds > 1 ? 's' : '')
// Create the formatted string
let result = ''
if (days > 0) {
result += days + ' day' + (days > 1 ? 's' : '') + ' '
}
if (hours > 0) {
result += hours + ' hour' + (hours > 1 ? 's' : '') + ' '
}
if (minutes > 0) {
result += minutes + ' minute' + (minutes > 1 ? 's' : '') + ' '
}
result += seconds + ' second' + (seconds > 1 ? 's' : '')
return result
return result
}
export const compareIp = (ip1: string, ip2: string) => {
const ip1Parts = ip1.split('.').map(Number)
const ip2Parts = ip2.split('.').map(Number)
for (let i = 0; i < 4; i++) {
if (ip1Parts[i] !== ip2Parts[i]) {
return ip1Parts[i] > ip2Parts[i] ? 1 : -1
const ip1Parts = ip1.split('.').map(Number)
const ip2Parts = ip2.split('.').map(Number)
for (let i = 0; i < 4; i++) {
if (ip1Parts[i] !== ip2Parts[i]) {
return ip1Parts[i] > ip2Parts[i] ? 1 : -1
}
}
}
return 0
return 0
}
+11 -11
View File
@@ -1,16 +1,16 @@
import { writable } from 'svelte/store';
import { browser } from '$app/environment';
import { writable } from 'svelte/store'
import { browser } from '$app/environment'
export const persistentStore = <T>(key: string, initialValue: T) => {
const savedValue = browser ? localStorage.getItem(key) : null;
const data: T = savedValue !== null ? JSON.parse(savedValue) : initialValue;
const store = writable<T>();
const savedValue = browser ? localStorage.getItem(key) : null
const data: T = savedValue !== null ? JSON.parse(savedValue) : initialValue
const store = writable<T>()
store.subscribe(value => {
if (browser) localStorage.setItem(key, JSON.stringify(value));
});
store.subscribe(value => {
if (browser) localStorage.setItem(key, JSON.stringify(value))
})
store.set(data);
store.set(data)
return store;
};
return store
}