include compiled sources

allowCeilingPlacement
MrPlatnum 2025-09-05 16:05:03 +02:00
parent 55caed4388
commit 5ce6d73279
16 changed files with 135096 additions and 5 deletions

1
.gitignore vendored
View File

@ -3,5 +3,4 @@
.DS_Store
lib
node_modules
dist
.idea

View File

@ -1,7 +1,5 @@
renderers/*
node_modules/*
shared-assets
dist/*
lib/*
**/*.sw*
.DS_Store

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

80896
packages/model-viewer/dist/model-viewer.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
<script type="module" src="./dist/model-viewer.js"></script>
<model-viewer src="./shared-assets/models/Astronaut.glb" ar camera-controls touch-action="pan-y"
<model-viewer src="./Astronaut.glb" ar camera-controls touch-action="pan-y"
alt="A 3D model of an astronaut" shadow-intensity="2"
ar-placement="ceiling"
ios-src="../../shared-assets/models/Astronaut.usdz" xr-environment></model-viewer>
ios-src="./Astronaut.usdz" xr-environment></model-viewer>

View File

@ -0,0 +1 @@
../shared-assets

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,240 @@
(function () {
'use strict';
/* @license ISC
* @see LICENSE
*/
// NOTE(cdata): This is an adapted subset of the original pixelmatch library.
// The top-level API of the original library has been omitted, as we only make
// use of the lower-level features that aren't actually exported by the upstream
// module.
// calculate color difference according to the paper "Measuring perceived color
// difference using YIQ NTSC transmission color space in mobile applications" by
// Y. Kotsarenko and F. Ramos
function colorDelta(img1, img2, k, m, yOnly = false) {
var a1 = img1[k + 3] / 255, a2 = img2[m + 3] / 255, r1 = blend(img1[k + 0], a1), g1 = blend(img1[k + 1], a1), b1 = blend(img1[k + 2], a1), r2 = blend(img2[m + 0], a2), g2 = blend(img2[m + 1], a2), b2 = blend(img2[m + 2], a2), y = rgb2y(r1, g1, b1) - rgb2y(r2, g2, b2);
if (yOnly)
return y; // brightness difference only
var i = rgb2i(r1, g1, b1) - rgb2i(r2, g2, b2), q = rgb2q(r1, g1, b1) - rgb2q(r2, g2, b2);
return 0.5053 * y * y + 0.299 * i * i + 0.1957 * q * q;
}
function rgb2y(r, g, b) {
return r * 0.29889531 + g * 0.58662247 + b * 0.11448223;
}
function rgb2i(r, g, b) {
return r * 0.59597799 - g * 0.27417610 - b * 0.32180189;
}
function rgb2q(r, g, b) {
return r * 0.21147017 - g * 0.52261711 + b * 0.31114694;
}
// blend semi-transparent color with white
function blend(c, a) {
return 255 + (c - 255) * a;
}
/* @license
* Copyright 2019 Google LLC. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const COMPONENTS_PER_PIXEL = 4;
// 35215 is the maximum possible value for the YIQ difference metric
// @see https://github.com/mapbox/pixelmatch/blob/master/index.js#L14
// @see http://www.progmat.uaem.mx:8080/artVol2Num2/Articulo3Vol2Num2.pdf
const MAX_COLOR_DISTANCE = 35215;
class ImageComparator {
constructor(candidateImage, goldenImage, dimensions) {
this.candidateImage = candidateImage;
this.goldenImage = goldenImage;
this.dimensions = dimensions;
const { width, height } = dimensions;
this.imagePixels = width * height;
}
drawPixel(image, position, r, g, b, a = 255) {
image[position + 0] = r;
image[position + 1] = g;
image[position + 2] = b;
image[position + 3] = a;
}
generateVisuals(threshold) {
const { candidateImage, goldenImage } = this;
const { width, height } = this.dimensions;
const blackWhiteImage = new Uint8ClampedArray(this.imagePixels * COMPONENTS_PER_PIXEL);
const deltaImage = new Uint8ClampedArray(this.imagePixels * COMPONENTS_PER_PIXEL);
const thresholdSquared = threshold * threshold;
let maximumDeltaIntensity = 0;
if (candidateImage.length != goldenImage.length) {
throw new Error(`Image sizes do not match (candidate: ${candidateImage.length}, golden: ${goldenImage.length})`);
}
for (let y = 0; y < height; ++y) {
for (let x = 0; x < width; ++x) {
const index = y * width + x;
const position = index * COMPONENTS_PER_PIXEL;
const delta = colorDelta(candidateImage, goldenImage, position, position);
const exactlyMatched = (delta <= thresholdSquared ? 1 : 0) * 255;
const thresholdDelta = Math.max(0, delta - thresholdSquared);
const deltaIntensity = Math.round(255 * thresholdDelta / MAX_COLOR_DISTANCE);
maximumDeltaIntensity = Math.max(deltaIntensity, maximumDeltaIntensity);
this.drawPixel(blackWhiteImage, position, exactlyMatched, exactlyMatched, exactlyMatched);
this.drawPixel(deltaImage, position, 255, 255 - deltaIntensity, 255 - deltaIntensity);
}
}
for (let y = 0; y < height; ++y) {
for (let x = 0; x < width; ++x) {
const index = y * width + x;
const position = index * COMPONENTS_PER_PIXEL;
const absoluteDeltaIntensity = 255 - deltaImage[position + 1];
const relativeDeltaIntensity = Math.round(255 - 255 * (absoluteDeltaIntensity / maximumDeltaIntensity));
this.drawPixel(deltaImage, position, 255, relativeDeltaIntensity, relativeDeltaIntensity);
}
}
return {
imageBuffers: { delta: deltaImage.buffer, blackWhite: blackWhiteImage.buffer }
};
}
analyze() {
const { candidateImage, goldenImage } = this;
const { width, height } = this.dimensions;
let squareSum = 0;
if (candidateImage.length != goldenImage.length) {
throw new Error(`Image sizes do not match (candidate: ${candidateImage.length}, golden: ${goldenImage.length})`);
}
let modelPixelCount = 0;
let colorlessPixelCount = 0;
for (let y = 0; y < height; ++y) {
for (let x = 0; x < width; ++x) {
const index = y * width + x;
// image's pixel data is stored in an 1-D array, 1st row sequentialy,
// then 2nd row, .. for each pixel, its data is stored by order of r, g,
// b, a. here position is the index for current pixel's r , position+3
// is index for its alpha
const position = index * COMPONENTS_PER_PIXEL;
// alpha is in range 0~255 here, map it to 0~1
const alpha = candidateImage[position + 3] / 255;
let isWhitePixel = true;
let isBlackPixel = true;
for (let i = 0; i < 3; i++) {
const colorComponent = candidateImage[position + i] * alpha;
if (colorComponent != 255) {
isWhitePixel = false;
}
if (colorComponent != 0) {
isBlackPixel = false;
}
}
if (isBlackPixel || isWhitePixel) {
colorlessPixelCount++;
}
if (alpha === 0) {
continue;
}
const delta = colorDelta(candidateImage, goldenImage, position, position);
squareSum += delta * delta;
modelPixelCount++;
}
}
const imagePixelCount = width * height;
if (colorlessPixelCount === imagePixelCount) {
throw new Error('Candidate image is colorless!');
}
const rmsDistanceRatio = Math.sqrt(squareSum / modelPixelCount) / MAX_COLOR_DISTANCE;
return { analysis: { rmsDistanceRatio } };
}
}
/* @license
* Copyright 2019 Google LLC. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class ImageComparisonWorker {
constructor() {
this.analyzer = null;
this.candidateCanvas = null;
this.candidateContext = null;
this.goldenCanvas = null;
this.goldenContext = null;
this.blackWhiteCanvas = null;
this.blackWhiteContext = null;
this.deltaCanvas = null;
this.deltaContext = null;
self.onmessage = (event) => this.onGlobalMessage(event);
}
onMessage(event, port) {
const data = event.data;
switch (data.type) {
case 'canvases-ready': {
const { candidateCanvas, goldenCanvas, blackWhiteCanvas, deltaCanvas } = data;
this.candidateCanvas = candidateCanvas;
this.candidateContext = candidateCanvas.getContext('2d');
this.goldenCanvas = goldenCanvas;
this.goldenContext = goldenCanvas.getContext('2d');
this.blackWhiteCanvas = blackWhiteCanvas;
this.blackWhiteContext = blackWhiteCanvas.getContext('2d');
this.deltaCanvas = deltaCanvas;
this.deltaContext = deltaCanvas.getContext('2d');
break;
}
case 'images-assigned': {
const { candidateImageBuffer, goldenImageBuffer, dimensions } = data;
if (this.candidateCanvas == null || this.goldenCanvas == null ||
this.blackWhiteCanvas == null || this.deltaCanvas == null) {
console.warn('Images assigned before canvases are available!');
}
this.candidateCanvas.width = this.goldenCanvas.width =
this.blackWhiteCanvas.width = this.deltaCanvas.width =
dimensions.width;
this.candidateCanvas.height = this.goldenCanvas.height =
this.blackWhiteCanvas.height = this.deltaCanvas.height =
dimensions.height;
const candidateArray = new Uint8ClampedArray(candidateImageBuffer);
const goldenArray = new Uint8ClampedArray(goldenImageBuffer);
const { width, height } = dimensions;
this.analyzer =
new ImageComparator(candidateArray, goldenArray, dimensions);
this.candidateContext.putImageData(new ImageData(candidateArray, width, height), 0, 0);
this.goldenContext.putImageData(new ImageData(goldenArray, width, height), 0, 0);
break;
}
case 'threshold-changed': {
const { threshold } = data;
const { analyzer } = this;
if (analyzer == null) {
console.warn(`Analyzer not created!`);
return;
}
const { width, height } = this.analyzer.dimensions;
const result = analyzer.generateVisuals(threshold);
this.blackWhiteContext.putImageData(new ImageData(new Uint8ClampedArray(result.imageBuffers.blackWhite), width, height), 0, 0);
this.deltaContext.putImageData(new ImageData(new Uint8ClampedArray(result.imageBuffers.delta), width, height), 0, 0);
port.postMessage({ type: 'analysis-completed', result });
break;
}
}
}
onGlobalMessage(event) {
event.ports.forEach(port => port.onmessage = (event) => this.onMessage(event, port));
}
}
self.imageComparisonWorker = new ImageComparisonWorker();
})();
//# sourceMappingURL=image-comparison-worker.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long