first commit.
This commit is contained in:
1035
src/g3d.ts
Normal file
1035
src/g3d.ts
Normal file
File diff suppressed because it is too large
Load Diff
616
src/m3d.ts
Normal file
616
src/m3d.ts
Normal file
@ -0,0 +1,616 @@
|
||||
export interface M3DHeader {
|
||||
magic: number;
|
||||
x: number;
|
||||
y: number;
|
||||
z: number;
|
||||
filename: string;
|
||||
subject: string;
|
||||
direction: string;
|
||||
date: number;
|
||||
fov: number;
|
||||
weight: number;
|
||||
ax: number;
|
||||
ay: number;
|
||||
az: number;
|
||||
ox: number;
|
||||
oy: number;
|
||||
oz: number;
|
||||
dlen: number;
|
||||
dth: number;
|
||||
memo: string;
|
||||
}
|
||||
|
||||
interface M3DImageRenderingContext {
|
||||
a1: number;
|
||||
a2: number;
|
||||
a3: number;
|
||||
b1: number;
|
||||
b2: number;
|
||||
b3: number;
|
||||
c1: number;
|
||||
c2: number;
|
||||
c3: number;
|
||||
d1: number;
|
||||
d2: number;
|
||||
d3: number;
|
||||
ra1: number;
|
||||
ra1_2: number;
|
||||
ra2: number;
|
||||
ra2_2: number;
|
||||
ra3: number;
|
||||
ra3_2: number;
|
||||
rb1: number;
|
||||
rb1_2: number;
|
||||
rb2: number;
|
||||
rb2_2: number;
|
||||
rb3: number;
|
||||
rb3_2: number;
|
||||
rc1: number;
|
||||
rc1_2: number;
|
||||
rc2: number;
|
||||
rc2_2: number;
|
||||
rc3: number;
|
||||
rc3_2: number;
|
||||
rd1: number;
|
||||
rd2: number;
|
||||
rd3: number;
|
||||
}
|
||||
|
||||
/* MeshLength unit is same as fov unit */
|
||||
const MeshLength = 10;
|
||||
enum DrawingLineType {
|
||||
VLine = 0,
|
||||
VDottedLine = 1,
|
||||
HLine = 2,
|
||||
HDottedLine = 3,
|
||||
}
|
||||
const LineBrightness = 200;
|
||||
const DottedLineBrightness = 128;
|
||||
const EXACTSWITCH: 0 | 1 = 1;
|
||||
const MaxIntensity = 200;
|
||||
|
||||
class M3D {
|
||||
private data: ArrayBuffer;
|
||||
private header: M3DHeader | null = null;
|
||||
private xposView: Int32Array | null = null;
|
||||
private zposView: Int32Array | null = null;
|
||||
private yposView: Int32Array | null = null;
|
||||
private img3dView: Uint8ClampedArray | null = null;
|
||||
private imageSize = 0; // imagesize size : max (size_x, size_y, size_z)
|
||||
private centerX = 0; // camera coordinates origin : x
|
||||
private centerY = 0; // camera coordinates origin : y
|
||||
private centerZ = 0; // camera coordinates origin : z
|
||||
private ox = 0; // object coordinates origin : x
|
||||
private oy = 0; // object coordinates origin : y
|
||||
private oz = 0; // object coordinates origin : z
|
||||
|
||||
constructor(data: ArrayBuffer) {
|
||||
this.data = data;
|
||||
this._initialize();
|
||||
}
|
||||
|
||||
isBigEndian(): boolean {
|
||||
return new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x11;
|
||||
}
|
||||
|
||||
getHeader(): M3DHeader | null {
|
||||
return this.header;
|
||||
}
|
||||
|
||||
drawImage(canvas: HTMLCanvasElement, ax: number, ay: number, az: number, cutdepth: number, th: number, is3d: boolean, mesh: boolean): boolean {
|
||||
const irc: M3DImageRenderingContext = {
|
||||
a1: 0,
|
||||
a2: 0,
|
||||
a3: 0,
|
||||
b1: 0,
|
||||
b2: 0,
|
||||
b3: 0,
|
||||
c1: 0,
|
||||
c2: 0,
|
||||
c3: 0,
|
||||
d1: 0,
|
||||
d2: 0,
|
||||
d3: 0,
|
||||
ra1: 0,
|
||||
ra1_2: 0,
|
||||
ra2: 0,
|
||||
ra2_2: 0,
|
||||
ra3: 0,
|
||||
ra3_2: 0,
|
||||
rb1: 0,
|
||||
rb1_2: 0,
|
||||
rb2: 0,
|
||||
rb2_2: 0,
|
||||
rb3: 0,
|
||||
rb3_2: 0,
|
||||
rc1: 0,
|
||||
rc1_2: 0,
|
||||
rc2: 0,
|
||||
rc2_2: 0,
|
||||
rc3: 0,
|
||||
rc3_2: 0,
|
||||
rd1: 0,
|
||||
rd2: 0,
|
||||
rd3: 0,
|
||||
};
|
||||
// console.log(ax, ay, az, cutdepth, th, dim, mesh)
|
||||
if (this.header === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
canvas.width = this.imageSize;
|
||||
canvas.height = this.imageSize;
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (ctx === null) {
|
||||
return false;
|
||||
}
|
||||
ctx.fillStyle = 'rgb(0, 0, 0)';
|
||||
ctx.fillRect(0, 0, this.imageSize, this.imageSize);
|
||||
const img = ctx.getImageData(0, 0, this.imageSize, this.imageSize);
|
||||
|
||||
this._setMatrix(ax, ay, az, irc);
|
||||
if (is3d) {
|
||||
const ddimg = [...Array<number>(this.imageSize * this.imageSize)].map(() => 0);
|
||||
this._makeDIMG(img, cutdepth, th, ddimg, irc);
|
||||
this._makeShadingImage(img, ddimg);
|
||||
} else {
|
||||
this._makeSliceImage(img, cutdepth, irc);
|
||||
}
|
||||
if (mesh) {
|
||||
this._drawMesh(img, irc);
|
||||
}
|
||||
ctx.putImageData(img, 0, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
private _makeDIMG(img: ImageData, cutdepth: number, th: number, ddimg: number[], irc: M3DImageRenderingContext) {
|
||||
if (this.header === null) {
|
||||
return;
|
||||
}
|
||||
const pdimg = [...Array<number>(this.imageSize * this.imageSize)].map(() => 0);
|
||||
const sw = th > this.header.dth ? 1 : th < this.header.dth ? 2 : EXACTSWITCH;
|
||||
switch (sw) {
|
||||
case 0: {
|
||||
this._transSurface(cutdepth, pdimg, irc);
|
||||
let pos = 0;
|
||||
for (let j = 0; j < this.imageSize; j++) {
|
||||
for (let i = 0; i < this.imageSize; i++, pos++) {
|
||||
ddimg[pos] = pdimg[pos];
|
||||
const pix = this._getPixel(i, j, cutdepth, irc);
|
||||
if (pix > th) {
|
||||
this._drawPixel(img, pos, pix, pix, pix);
|
||||
ddimg[pos] = cutdepth;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
this._transSurface(cutdepth, pdimg, irc);
|
||||
let pos = 0;
|
||||
for (let y = 0; y < this.imageSize; y++) {
|
||||
for (let x = 0; x < this.imageSize; x++, pos++) {
|
||||
let pdPos = (ddimg[pos] = pdimg[pos]);
|
||||
if (pdPos === 0) {
|
||||
continue;
|
||||
}
|
||||
const pix = this._getPixel(x, y, cutdepth, irc);
|
||||
if (pix > th) {
|
||||
this._drawPixel(img, pos, pix, pix, pix);
|
||||
ddimg[pos] = cutdepth;
|
||||
continue;
|
||||
}
|
||||
if (pdPos < cutdepth) {
|
||||
pdPos = cutdepth;
|
||||
}
|
||||
ddimg[pos] = 0;
|
||||
for (let z = pdPos; z < this.imageSize; z++) {
|
||||
const pix = this._getPixel(x, y, z, irc);
|
||||
if (pix > th) {
|
||||
ddimg[pos] = z;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
let pos = 0;
|
||||
for (let y = 0; y < this.imageSize; y++) {
|
||||
for (let x = 0; x < this.imageSize; x++, pos++) {
|
||||
ddimg[pos] = 0;
|
||||
for (let z = cutdepth; z < this.imageSize; z++) {
|
||||
const pix = this._getPixel(x, y, z, irc);
|
||||
if (pix > th) {
|
||||
if (z === cutdepth) {
|
||||
this._drawPixel(img, pos, pix, pix, pix);
|
||||
} else {
|
||||
ddimg[pos] = z;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _makeShadingImage(img: ImageData, ddimg: number[]) {
|
||||
let pos = 0;
|
||||
for (let x = 0; x < this.imageSize; x++) {
|
||||
for (let y = 0; y < this.imageSize; y++, pos++) {
|
||||
const base = pos * 4;
|
||||
if (img.data[base] === 0) {
|
||||
let timg2d = 0;
|
||||
if (x < this.imageSize - 2 && y < this.imageSize - 2) {
|
||||
if (ddimg[pos] !== 0) {
|
||||
const nx = (ddimg[pos] + ddimg[pos + this.imageSize] - ddimg[pos + 2] - ddimg[pos + 2 + this.imageSize]) / 4.0;
|
||||
const ny = (ddimg[pos] + ddimg[pos + 1] - ddimg[pos + this.imageSize * 2] - ddimg[pos + 1 + this.imageSize * 2]) / 4.0;
|
||||
const n = Math.sqrt(nx * nx + ny * ny + 1);
|
||||
timg2d = Math.round(MaxIntensity / n);
|
||||
}
|
||||
}
|
||||
this._drawPixel(img, pos, timg2d, timg2d, timg2d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _makeSliceImage(img: ImageData, cutdepth: number, irc: M3DImageRenderingContext) {
|
||||
let pos = 0;
|
||||
for (let y = 0; y < this.imageSize; y++) {
|
||||
for (let x = 0; x < this.imageSize; x++, pos++) {
|
||||
const pix = this._getPixel(x, y, cutdepth, irc);
|
||||
this._drawPixel(img, pos, pix, pix, pix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _drawMesh(img: ImageData, irc: M3DImageRenderingContext) {
|
||||
let origx: number;
|
||||
let origy: number;
|
||||
if (this.header === null) {
|
||||
return;
|
||||
}
|
||||
if (this.header.ox !== 0 && this.header.oy !== 0) {
|
||||
origx = this.header.ox * irc.ra1 + this.header.oy * irc.rb1 + this.header.oz * irc.rc1 + irc.rd1;
|
||||
origy = this.header.ox * irc.ra2 + this.header.oy * irc.rb2 + this.header.oz * irc.rc2 + irc.rd2;
|
||||
} else {
|
||||
origx = this.centerX;
|
||||
origy = this.centerY;
|
||||
}
|
||||
origx = this._fround(origx, 5);
|
||||
origy = this._fround(origy, 5);
|
||||
|
||||
const band = (this.header.x * MeshLength) / this.header.fov;
|
||||
const r = 0;
|
||||
const g = 0;
|
||||
const b = LineBrightness;
|
||||
const sr = 0;
|
||||
const sg = 0;
|
||||
const sb = DottedLineBrightness;
|
||||
this._drawLine(img, Math.round(origx), r, g, b, DrawingLineType.VLine);
|
||||
this._drawLine(img, Math.round(origy), r, g, b, DrawingLineType.HLine);
|
||||
for (let pos = Math.round(origx) + band; pos < this.imageSize; pos += band) {
|
||||
this._drawLine(img, Math.round(pos), sr, sg, sb, DrawingLineType.VDottedLine);
|
||||
}
|
||||
for (let pos = Math.round(origx) - band; pos >= 0; pos -= band) {
|
||||
this._drawLine(img, Math.round(pos), sr, sg, sb, DrawingLineType.VDottedLine);
|
||||
}
|
||||
for (let pos = Math.round(origy) + band; pos < this.imageSize; pos += band) {
|
||||
this._drawLine(img, Math.round(pos), sr, sg, sb, DrawingLineType.HDottedLine);
|
||||
}
|
||||
for (let pos = Math.round(origy) - band; pos >= 0; pos -= band) {
|
||||
this._drawLine(img, Math.round(pos), sr, sg, sb, DrawingLineType.HDottedLine);
|
||||
}
|
||||
}
|
||||
|
||||
private _drawLine(img: ImageData, value: number, r: number, g: number, b: number, type: DrawingLineType) {
|
||||
switch (type) {
|
||||
case DrawingLineType.VLine: {
|
||||
let pos = value;
|
||||
for (let y = 0; y < this.imageSize; y++, pos += this.imageSize) {
|
||||
this._drawPixel(img, pos, r, g, b);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DrawingLineType.VDottedLine: {
|
||||
let pos = value;
|
||||
for (let y = 0; y < this.imageSize; y += 2, pos += this.imageSize * 2) {
|
||||
this._drawPixel(img, pos, r, g, b);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DrawingLineType.HLine: {
|
||||
let pos = value * this.imageSize;
|
||||
for (let x = 0; x < this.imageSize; x++, pos++) {
|
||||
this._drawPixel(img, pos, r, g, b);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DrawingLineType.HDottedLine: {
|
||||
let pos = value * this.imageSize;
|
||||
for (let x = 0; x < this.imageSize; x += 2, pos += 2) {
|
||||
this._drawPixel(img, pos, r, g, b);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private _drawPixel(img: ImageData, pos: number, r: number, g: number, b: number) {
|
||||
let base = pos * 4;
|
||||
img.data[base++] = r;
|
||||
img.data[base++] = g;
|
||||
img.data[base++] = b;
|
||||
img.data[base] = 255;
|
||||
}
|
||||
|
||||
private _getPixel(x: number, y: number, z: number, irc: M3DImageRenderingContext): number {
|
||||
const len = [...Array<number>(8)].map(() => 0);
|
||||
const ratio = [...Array<number>(8)].map(() => 0);
|
||||
|
||||
const tx = x * irc.a1 + y * irc.b1 + z * irc.c1 + irc.d1;
|
||||
const ty = x * irc.a2 + y * irc.b2 + z * irc.c2 + irc.d2;
|
||||
const tz = x * irc.a3 + y * irc.b3 + z * irc.c3 + irc.d3;
|
||||
|
||||
let ix = Math.floor(tx);
|
||||
let iy = Math.floor(ty);
|
||||
let iz = Math.floor(tz);
|
||||
|
||||
if (this.header === null || this.img3dView === null) {
|
||||
return 0;
|
||||
}
|
||||
if (ix < 0 || ix + 1 >= this.header.x || iy < 0 || iy + 1 >= this.header.y || iz < 0 || iz + 1 >= this.header.z) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const ax1 = Math.abs(tx - ix);
|
||||
const ax2 = Math.abs(1 - ax1);
|
||||
const ay1 = Math.abs(ty - iy);
|
||||
const ay2 = Math.abs(1 - ay1);
|
||||
const az1 = Math.abs(tz - iz);
|
||||
const az2 = Math.abs(1 - az1);
|
||||
|
||||
let sumlen1 = 0;
|
||||
for (let i = 0; i < 8; i++) {
|
||||
len[i] = i & 1 ? ax2 : ax1;
|
||||
len[i] += i & 2 ? ay2 : ay1;
|
||||
len[i] += i & 4 ? az2 : az1;
|
||||
if (len[i] < 0.001) {
|
||||
ix += i & 1 ? 1 : 0;
|
||||
iy += i & 2 ? 1 : 0;
|
||||
iz += i & 4 ? 1 : 0;
|
||||
return this.img3dView[ix + iy * this.header.x + iz * this.header.x * this.header.y];
|
||||
}
|
||||
sumlen1 += ratio[i] = 1 / len[i];
|
||||
}
|
||||
let pos = ix + iy * this.header.x + iz * this.header.x * this.header.y;
|
||||
let sumlen2 = this.img3dView[pos] * ratio[0];
|
||||
sumlen2 += this.img3dView[pos + 1] * ratio[1];
|
||||
sumlen2 += this.img3dView[pos + this.header.x] * ratio[2];
|
||||
sumlen2 += this.img3dView[pos + 1 + this.header.x] * ratio[3];
|
||||
pos += this.header.x * this.header.y;
|
||||
sumlen2 += this.img3dView[pos] * ratio[4];
|
||||
sumlen2 += this.img3dView[pos + 1] * ratio[5];
|
||||
sumlen2 += this.img3dView[pos + this.header.x] * ratio[6];
|
||||
sumlen2 += this.img3dView[pos + 1 + this.header.x] * ratio[7];
|
||||
|
||||
return Math.round(sumlen2 / sumlen1);
|
||||
}
|
||||
|
||||
private _transSurface(cutdepth: number, pdimg: number[], irc: M3DImageRenderingContext) {
|
||||
if (this.header === null || this.xposView === null || this.yposView === null || this.zposView === null) {
|
||||
return;
|
||||
}
|
||||
const ix = [...Array<number>(8)].map(() => 0);
|
||||
const iy = [...Array<number>(8)].map(() => 0);
|
||||
const iz = [...Array<number>(8)].map(() => 0);
|
||||
for (let i = 0; i < this.header.dlen; i++) {
|
||||
const x = this.xposView[i];
|
||||
const y = this.yposView[i];
|
||||
const z = this.zposView[i];
|
||||
ix[0] = x * irc.ra1 + y * irc.rb1 + z * irc.rc1 + irc.rd1;
|
||||
iy[0] = x * irc.ra2 + y * irc.rb2 + z * irc.rc2 + irc.rd2;
|
||||
iz[0] = x * irc.ra3 + y * irc.rb3 + z * irc.rc3 + irc.rd3;
|
||||
ix[1] = ix[0] + irc.ra1_2;
|
||||
iy[1] = iy[0] + irc.ra2_2;
|
||||
iz[1] = iz[0] + irc.ra3_2;
|
||||
ix[2] = ix[0] + irc.rb1_2;
|
||||
iy[2] = iy[0] + irc.rb2_2;
|
||||
iz[2] = iz[0] + irc.rb3_2;
|
||||
ix[3] = ix[0] + irc.rc1_2;
|
||||
iy[3] = iy[0] + irc.rc2_2;
|
||||
iz[3] = iz[0] + irc.rc3_2;
|
||||
ix[4] = ix[1] + irc.rb1_2;
|
||||
iy[4] = iy[1] + irc.rb2_2;
|
||||
iz[4] = iz[1] + irc.rb3_2;
|
||||
ix[5] = ix[1] + irc.rc1_2;
|
||||
iy[5] = iy[1] + irc.rc2_2;
|
||||
iz[5] = iz[1] + irc.rc3_2;
|
||||
ix[6] = ix[2] + irc.rc1_2;
|
||||
iy[6] = iy[2] + irc.rc2_2;
|
||||
iz[6] = iz[2] + irc.rc3_2;
|
||||
ix[7] = ix[4] + irc.rc1_2;
|
||||
iy[7] = iy[4] + irc.rc2_2;
|
||||
iz[7] = iz[4] + irc.rc3_2;
|
||||
for (let j = 0; j < 8; j++) {
|
||||
const xi = Math.round(ix[j]);
|
||||
const yi = Math.round(iy[j]);
|
||||
if (xi < 0 || xi >= this.imageSize || yi < 0 || yi >= this.imageSize || iz[j] < cutdepth || iz[j] >= this.imageSize) {
|
||||
continue;
|
||||
}
|
||||
const pos = xi + yi * this.imageSize;
|
||||
if (pdimg[pos] === 0 || pdimg[pos] > iz[j]) {
|
||||
pdimg[pos] = iz[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _setMatrix(x: number, y: number, z: number, irc: M3DImageRenderingContext) {
|
||||
const xtr = [...Array<number>(9)].map(() => 0);
|
||||
const ytr = [...Array<number>(9)].map(() => 0);
|
||||
const ztr = [...Array<number>(9)].map(() => 0);
|
||||
const tmp = [...Array<number>(9)].map(() => 0);
|
||||
const tr = [...Array<number>(9)].map(() => 0);
|
||||
this._setXtr(xtr, (x * Math.PI) / 180.0);
|
||||
this._setYtr(ytr, (y * Math.PI) / 180.0);
|
||||
this._setZtr(ztr, (z * Math.PI) / 180.0);
|
||||
this._multi(ytr, xtr, tmp);
|
||||
this._multi(ztr, tmp, tr);
|
||||
irc.a1 = tr[0];
|
||||
irc.b1 = tr[1];
|
||||
irc.c1 = tr[2];
|
||||
irc.a2 = tr[3];
|
||||
irc.b2 = tr[4];
|
||||
irc.c2 = tr[5];
|
||||
irc.a3 = tr[6];
|
||||
irc.b3 = tr[7];
|
||||
irc.c3 = tr[8];
|
||||
irc.d1 = -irc.a1 * this.centerX - irc.b1 * this.centerY - irc.c1 * this.centerZ + this.ox;
|
||||
irc.d2 = -irc.a2 * this.centerX - irc.b2 * this.centerY - irc.c2 * this.centerZ + this.oy;
|
||||
irc.d3 = -irc.a3 * this.centerX - irc.b3 * this.centerY - irc.c3 * this.centerZ + this.oz;
|
||||
|
||||
this._setXtr(xtr, (-x * Math.PI) / 180.0);
|
||||
this._setYtr(ytr, (-y * Math.PI) / 180.0);
|
||||
this._setZtr(ztr, (-z * Math.PI) / 180.0);
|
||||
this._multi(ytr, ztr, tmp);
|
||||
this._multi(xtr, tmp, tr);
|
||||
irc.ra1 = tr[0];
|
||||
irc.rb1 = tr[1];
|
||||
irc.rc1 = tr[2];
|
||||
irc.ra2 = tr[3];
|
||||
irc.rb2 = tr[4];
|
||||
irc.rc2 = tr[5];
|
||||
irc.ra3 = tr[6];
|
||||
irc.rb3 = tr[7];
|
||||
irc.rc3 = tr[8];
|
||||
irc.rd1 = -irc.ra1 * this.ox - irc.rb1 * this.oy - irc.rc1 * this.oz + this.centerX;
|
||||
irc.rd2 = -irc.ra2 * this.ox - irc.rb2 * this.oy - irc.rc2 * this.oz + this.centerY;
|
||||
irc.rd3 = -irc.ra3 * this.ox - irc.rb3 * this.oy - irc.rc3 * this.oz + this.centerZ;
|
||||
irc.ra1_2 = irc.ra1 / 2;
|
||||
irc.rb1_2 = irc.rb1 / 2;
|
||||
irc.rc1_2 = irc.rc1 / 2;
|
||||
irc.ra2_2 = irc.ra2 / 2;
|
||||
irc.rb2_2 = irc.rb2 / 2;
|
||||
irc.rc2_2 = irc.rc2 / 2;
|
||||
irc.ra3_2 = irc.ra3 / 2;
|
||||
irc.rb3_2 = irc.rb3 / 2;
|
||||
irc.rc3_2 = irc.rc3 / 2;
|
||||
}
|
||||
|
||||
private _setXtr(xtr: number[], ang: number) {
|
||||
xtr[0] = 1;
|
||||
xtr[1] = 0;
|
||||
xtr[2] = 0;
|
||||
xtr[3] = 0;
|
||||
xtr[4] = Math.cos(ang);
|
||||
xtr[5] = -Math.sin(ang);
|
||||
xtr[6] = 0;
|
||||
xtr[7] = Math.sin(ang);
|
||||
xtr[8] = Math.cos(ang);
|
||||
}
|
||||
|
||||
private _setYtr(ytr: number[], ang: number) {
|
||||
ytr[0] = Math.cos(ang);
|
||||
ytr[1] = 0;
|
||||
ytr[2] = Math.sin(ang);
|
||||
ytr[3] = 0;
|
||||
ytr[4] = 1;
|
||||
ytr[5] = 0;
|
||||
ytr[6] = -Math.sin(ang);
|
||||
ytr[7] = 0;
|
||||
ytr[8] = Math.cos(ang);
|
||||
}
|
||||
|
||||
private _setZtr(ztr: number[], ang: number) {
|
||||
ztr[0] = Math.cos(ang);
|
||||
ztr[1] = -Math.sin(ang);
|
||||
ztr[2] = 0;
|
||||
ztr[3] = Math.sin(ang);
|
||||
ztr[4] = Math.cos(ang);
|
||||
ztr[5] = 0;
|
||||
ztr[6] = 0;
|
||||
ztr[7] = 0;
|
||||
ztr[8] = 1;
|
||||
}
|
||||
|
||||
private _multi(l: number[], r: number[], a: number[]) {
|
||||
a[0] = l[0] * r[0] + l[1] * r[3] + l[2] * r[6];
|
||||
a[3] = l[3] * r[0] + l[4] * r[3] + l[5] * r[6];
|
||||
a[6] = l[6] * r[0] + l[7] * r[3] + l[8] * r[6];
|
||||
a[1] = l[0] * r[1] + l[1] * r[4] + l[2] * r[7];
|
||||
a[4] = l[3] * r[1] + l[4] * r[4] + l[5] * r[7];
|
||||
a[7] = l[6] * r[1] + l[7] * r[4] + l[8] * r[7];
|
||||
a[2] = l[0] * r[2] + l[1] * r[5] + l[2] * r[8];
|
||||
a[5] = l[3] * r[2] + l[4] * r[5] + l[5] * r[8];
|
||||
a[8] = l[6] * r[2] + l[7] * r[5] + l[8] * r[8];
|
||||
}
|
||||
|
||||
private _fround(x: number, n: number) {
|
||||
return Math.round(x * Math.pow(10, n)) / Math.pow(10, n);
|
||||
}
|
||||
|
||||
private _initialize(): void {
|
||||
const view = new DataView(this.data);
|
||||
const magic = view.getInt32(0, true);
|
||||
const isLittleEndianFile = magic === 0x4d523344;
|
||||
if (!isLittleEndianFile && magic !== 0x4433524d) {
|
||||
console.log('invalid data format, this data is not m3d format');
|
||||
return;
|
||||
}
|
||||
let offset = 0;
|
||||
const decoder = new TextDecoder('utf-8');
|
||||
this.header = {
|
||||
magic: view.getInt32(offset, isLittleEndianFile),
|
||||
x: view.getInt32((offset += 4), isLittleEndianFile),
|
||||
y: view.getInt32((offset += 4), isLittleEndianFile),
|
||||
z: view.getInt32((offset += 4), isLittleEndianFile),
|
||||
filename: decoder.decode(new Uint8Array(this.data, (offset += 4), 256)).replace(/\0+$/, ''),
|
||||
subject: decoder.decode(new Uint8Array(this.data, (offset += 256), 256)).replace(/\0+$/, ''),
|
||||
direction: decoder.decode(new Uint8Array(this.data, (offset += 256), 4)).replace(/\0+$/, ''),
|
||||
date: view.getUint32((offset += 4), isLittleEndianFile),
|
||||
fov: view.getFloat64((offset += 4), isLittleEndianFile),
|
||||
weight: view.getFloat64((offset += 8), isLittleEndianFile),
|
||||
ax: view.getFloat64((offset += 8), isLittleEndianFile),
|
||||
ay: view.getFloat64((offset += 8), isLittleEndianFile),
|
||||
az: view.getFloat64((offset += 8), isLittleEndianFile),
|
||||
ox: view.getFloat64((offset += 8), isLittleEndianFile),
|
||||
oy: view.getFloat64((offset += 8), isLittleEndianFile),
|
||||
oz: view.getFloat64((offset += 8), isLittleEndianFile),
|
||||
dlen: view.getInt32((offset += 8), isLittleEndianFile),
|
||||
dth: view.getInt32((offset += 4), isLittleEndianFile),
|
||||
memo: decoder.decode(new Uint8Array(this.data, (offset += 4), 256)).replace(/\0+$/, ''),
|
||||
};
|
||||
// swap byte order if endian is not matched
|
||||
if ((this.isBigEndian() && isLittleEndianFile) || (!this.isBigEndian() && !isLittleEndianFile)) {
|
||||
const start = 864;
|
||||
const end = start + this.header.dlen * 4 * 3;
|
||||
for (let i = start; i < end; i += 4) {
|
||||
const data = new Uint8Array(this.data, i, 4);
|
||||
data.reverse();
|
||||
}
|
||||
}
|
||||
this.xposView = new Int32Array(this.data, 864, this.header.dlen);
|
||||
this.yposView = new Int32Array(this.data, 864 + this.header.dlen * 4, this.header.dlen);
|
||||
this.zposView = new Int32Array(this.data, 864 + this.header.dlen * 8, this.header.dlen);
|
||||
this.img3dView = new Uint8ClampedArray(this.data, 864 + this.header.dlen * 12, this.header.x * this.header.y * this.header.z);
|
||||
// set image generation offset
|
||||
this.imageSize = Math.ceil(Math.max(this.header.x, this.header.y, this.header.z) * Math.sqrt(3.0)) + 1;
|
||||
this.centerX = (this.imageSize - 1) / 2.0;
|
||||
this.centerY = (this.imageSize - 1) / 2.0;
|
||||
this.centerZ = (this.imageSize - 1) / 2.0;
|
||||
this.ox = (this.header.x - 1) / 2.0;
|
||||
this.oy = (this.header.y - 1) / 2.0;
|
||||
this.oz = (this.header.z - 1) / 2.0;
|
||||
}
|
||||
}
|
||||
|
||||
export default M3D;
|
Reference in New Issue
Block a user