Files
Yajbir Singh f1b860b25c
check / markdownlint (push) Has been cancelled
check / spellchecker (push) Has been cancelled
updated
2025-12-11 19:03:17 +05:30

2749 lines
92 KiB
JavaScript

/*
* (c) Copyright Ascensio System SIA 2010-2024
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)
* version 3 as published by the Free Software Foundation. In accordance with
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
* that Ascensio System SIA expressly excludes the warranty of non-infringement
* of any third-party rights.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish
* street, Riga, Latvia, EU, LV-1050.
*
* The interactive user interfaces in modified source and object code versions
* of the Program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU AGPL version 3.
*
* Pursuant to Section 7(b) of the License you must retain the original Product
* logo when distributing the program. Pursuant to Section 7(e) we decline to
* grant you any rights under trademark law for use of our trademarks.
*
* All the Product's GUI elements, including illustrations and icon sets, as
* well as technical writing content are licensed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
*
*/
"use strict";
(/**
* @param {Window} window
* @param {undefined} undefined
*/
function (window, undefined) {
// Import
let ORIENTATION_MIN_MAX = AscFormat.ORIENTATION_MIN_MAX;
let globalBasePercent = 100;
let global3DPersperctive = 30; // ToDo а нужна ли она в ChartsDrawer ?
let c_oChartFloorPosition = {
None: 0, Left: 1, Right: 2, Bottom: 3, Top: 4
};
/** @constructor */
function Processor3D(width, height, left, right, bottom, top, chartSpace, chartsDrawer) {
this.widthCanvas = width;
this.heightCanvas = height;
this.left = left ? left : 0;
this.right = right ? right : 0;
this.bottom = bottom ? bottom : 0;
this.top = top ? top : 0;
this.cameraDiffZ = 0;
this.cameraDiffX = 0;
this.cameraDiffY = 0;
this.scaleY = 1;
this.scaleX = 1;
this.scaleZ = 1;
this.aspectRatioY = 1;
this.aspectRatioX = 1;
this.aspectRatioZ = 1;
this.specialStandardScaleX = 1;
this.view3D = chartSpace.chart.getView3d();
this.chartSpace = chartSpace;
this.chartsDrawer = chartsDrawer;
this.rPerspective = 0;
this.hPercent = null;
this.angleOx = this.view3D && this.view3D.rotX ? (-this.view3D.rotX / 360) * (Math.PI * 2) : 0;
this.angleOy = this.view3D && this.view3D.rotY ? (-this.view3D.rotY / 360) * (Math.PI * 2) : 0;
//this.angleOz = this.view3D && this.view3D.rotZ ? (- this.view3D.rotZ / 360) * (Math.PI * 2) : 0;
if (!this.view3D.getRAngAx() && AscFormat.c_oChartTypes.Pie === this.chartsDrawer.calcProp.type) {
this.angleOy = 0;
}
this.orientationCatAx = null;
this.orientationValAx = null;
this.matrixRotateOx = null;
this.matrixRotateOy = null;
this.matrixRotateAllAxis = null;
this.matrixShearXY = null;
this.projectMatrix = null;
}
Processor3D.prototype.calaculate3DProperties = function (baseDepth, gapDepth, bIsCheck) {
this.calculateCommonOptions();
//TODO baseDepth - не универсальный параметр, позже переделать
this._calculateAutoHPercent();
//рассчёт коэффициэнта отношения ширины / высоты
this._calcAspectRatio();
//TODO рассчёт коэффицианты для диаграмм типа standard. позже необходимо отказаться
//this._calcSpecialStandardScaleX();
//глубина
this.depthPerspective = this.view3D.getRAngAx() ? this._calculateDepth() : this._calculateDepthPerspective();
//угол перспективы
this._calculatePerspective(this.view3D);
//после рассчета глубины меняются пропорции ширины и высоты
if (this.view3D.getRAngAx()) {
this._calculateScaleFromDepth();
}
//сдвиг камеры для того, чтобы попали все линии
if (!bIsCheck) {
this._calculateCameraDiff();
if (this.view3D.getRAngAx()) {
this._recalculateScaleWithMaxWidth();
}
}
if (AscFormat.c_oChartTypes.Pie === this.chartsDrawer.calcProp.type && !this.view3D.getRAngAx()) {
//TODO пересмотреть функцию
this.tempChangeAspectRatioForPie();
}
};
Processor3D.prototype.tempChangeAspectRatioForPie = function () {
let perspectiveDepth = this.depthPerspective;
let widthCanvas = this.widthCanvas;
let originalWidthChart = widthCanvas - this.left - this.right;
let heightCanvas = this.heightCanvas;
let heightChart = heightCanvas - this.top - this.bottom;
let points = [], faces = [];
points.push(new Point3D(this.left + originalWidthChart / 2, this.top, perspectiveDepth, this));
points.push(new Point3D(this.left, this.top, perspectiveDepth / 2, this));
points.push(new Point3D(this.left + originalWidthChart, this.top, perspectiveDepth / 2, this));
points.push(new Point3D(this.left + originalWidthChart / 2, this.top, 0, this));
points.push(new Point3D(this.left + originalWidthChart / 2, this.top + heightChart, perspectiveDepth, this));
points.push(new Point3D(this.left, this.top + heightChart, perspectiveDepth / 2, this));
points.push(new Point3D(this.left + originalWidthChart, this.top + heightChart, perspectiveDepth / 2, this));
points.push(new Point3D(this.left + originalWidthChart / 2, this.top + heightChart, 0, this));
faces.push([0, 1, 2, 3]);
faces.push([2, 5, 4, 3]);
faces.push([1, 6, 7, 0]);
faces.push([6, 5, 4, 7]);
faces.push([7, 4, 3, 0]);
faces.push([1, 6, 2, 5]);
let minMaxOx = this._getMinMaxOx(points, faces);
let minMaxOy = this._getMinMaxOy(points, faces);
let kF = ((minMaxOx.right - minMaxOx.left) / originalWidthChart);
if ((minMaxOy.bottom - minMaxOy.top) / kF > heightChart) {
kF = ((minMaxOy.bottom - minMaxOy.top) / heightChart);
}
this.aspectRatioX = this.aspectRatioX * kF;
this.aspectRatioY = this.aspectRatioY * kF;
this.aspectRatioZ = this.aspectRatioZ * kF;
};
Processor3D.prototype.calculateCommonOptions = function () {
this.orientationCatAx = this.chartSpace && this.chartSpace.chart.plotArea.catAx ? this.chartSpace.chart.plotArea.catAx.getOrientation() : ORIENTATION_MIN_MAX;
this.orientationValAx = this.chartSpace && this.chartSpace.chart.plotArea.valAx ? this.chartSpace.chart.plotArea.valAx.getOrientation() : ORIENTATION_MIN_MAX;
};
Processor3D.prototype._calculateAutoHPercent = function () {
let widthLine = this.widthCanvas - (this.left + this.right);
let heightLine = this.heightCanvas - (this.top + this.bottom);
if (this.hPercent == null) {
this.hPercent = this.view3D.hPercent === null ? (heightLine / widthLine) : this.view3D.hPercent / 100;
if (this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.HBar &&
((this.view3D.hPercent === null && this.view3D.getRAngAx()) || (this.view3D.hPercent !== null && !this.view3D.getRAngAx()))) {
this.hPercent = 1 / this.hPercent;
}
if (AscFormat.c_oChartTypes.Pie === this.chartsDrawer.calcProp.type) {
this.hPercent = 0.12;
//this.view3D.depthPercent = 180;
}
}
};
Processor3D.prototype._recalculateScaleWithMaxWidth = function () {
let widthLine = this.widthCanvas - (this.left + this.right);
let heightLine = this.heightCanvas - (this.top + this.bottom);
let widthCanvas = this.widthCanvas;
//todo оптимальную ширину нужно пересмотреть
//оптимальная ширина - ширина при которой не происходит масштабирования по ширине
let optimalWidth = heightLine * 10;
let subType = this.chartsDrawer.calcProp.subType;
let type = this.chartsDrawer.calcProp.type;
let isStandardType = subType === "standard" || type === AscFormat.c_oChartTypes.Line || (type === AscFormat.c_oChartTypes.Area && subType === "normal") || type ===
AscFormat.c_oChartTypes.Surface;
let optimalWidthLine, kF;
if (!isStandardType) {
this.widthCanvas = optimalWidth + (this.left + this.right);
this._calculateScaleNStandard();
optimalWidthLine = Math.abs(this.depthPerspective * Math.sin(-this.angleOy)) + ((this.widthCanvas - (this.left + this.right)) / this.aspectRatioX) / this.scaleX;
kF = optimalWidthLine / widthLine;
if (optimalWidthLine < widthLine) {
this.widthCanvas = widthCanvas;
this._calculateScaleNStandard();
} else {
this.aspectRatioX = widthLine / ((optimalWidthLine - Math.abs(this.depthPerspective * Math.sin(-this.angleOy))) / kF);
this.scaleY = this.scaleY * kF;
this.scaleZ = this.scaleZ * kF;
this.widthCanvas = widthCanvas;
}
this._recalculateCameraDiff();
} else {
let scaleX = this.scaleX;
let scaleY = this.scaleY;
let scaleZ = this.scaleZ;
let aspectRatioX = this.aspectRatioX;
let aspectRatioY = this.aspectRatioY;
let aspectRatioZ = this.aspectRatioZ;
//если будут проблемы с поворотом standard диграмм, раскомментровать!
//TODO протестировать, и если не будет проблем, то убрать if-else
if (Math.abs(this.angleOy) > Math.PI) {
//рассчитываем параметры диаграммы при оптимальной ширине
this.widthCanvas = optimalWidth + (this.left + this.right);
this.calaculate3DProperties(null, null, true);
let newDepth = Math.abs(this.depthPerspective * Math.sin(-this.angleOy));
optimalWidthLine = newDepth + ((this.widthCanvas - (this.left + this.right)) / this.aspectRatioX) / this.scaleX;
kF = optimalWidthLine / widthLine;
if (optimalWidthLine < widthLine) {
this.widthCanvas = widthCanvas;
this.scaleX = scaleX;
this.scaleY = scaleY;
this.scaleZ = scaleZ;
this.aspectRatioX = aspectRatioX;
this.aspectRatioY = aspectRatioY;
this.aspectRatioZ = aspectRatioZ;
return;
}
this.aspectRatioX = widthLine / ((optimalWidthLine - newDepth) / kF);
this.scaleY = this.scaleY * kF;
this.scaleZ = this.scaleZ * kF;
this.widthCanvas = widthCanvas;
this._recalculateCameraDiff();
} else {
//рассчитываем параметры диаграммы при оптимальной ширине
this.widthCanvas = optimalWidth + (this.left + this.right);
this.calaculate3DProperties(null, null, true);
optimalWidthLine = this.depthPerspective * Math.sin(-this.angleOy) + ((this.widthCanvas - (this.left + this.right)) / this.aspectRatioX) / this.scaleX;
if (optimalWidthLine < widthLine) {
this.widthCanvas = widthCanvas;
this.scaleX = scaleX;
this.scaleY = scaleY;
this.scaleZ = scaleZ;
this.aspectRatioX = aspectRatioX;
this.aspectRatioY = aspectRatioY;
this.aspectRatioZ = aspectRatioZ;
return;
}
kF = optimalWidthLine / widthLine;
this.aspectRatioX = widthLine / ((optimalWidthLine - this.depthPerspective * Math.sin(-this.angleOy)) / kF);
this.scaleY = this.scaleY * kF;
this.scaleZ = this.scaleZ * kF;
this.widthCanvas = widthCanvas;
this._recalculateCameraDiff();
}
}
};
Processor3D.prototype._calculateScaleNStandard = function () {
let seriesProps = this.chartsDrawer.calculateFirstChartCountSeries();
let ptCount = seriesProps.points;
let widthLine = this.widthCanvas - (this.left + this.right);
let heightLine = this.heightCanvas - (this.top + this.bottom);
let trueDepth = Math.abs(this.depthPerspective * Math.sin(-this.angleOx));
let mustHeight = heightLine - trueDepth;
let mustWidth = this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.HBar ? mustHeight * this.hPercent : mustHeight / this.hPercent;
let areaStackedKf = this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.Area && this.chartsDrawer.calcProp.subType !== "normal" ? (ptCount / ((ptCount - 1))) : 1;
//без маштабирования
if (this.angleOy === 0) {
this.aspectRatioX = ((this.widthCanvas - (this.left + this.right)) / mustWidth) / areaStackedKf;
this.scaleX = 1;
this.scaleY = 1;
this.aspectRatioY = heightLine / mustHeight;
} else {
this.aspectRatioX = ((this.widthCanvas - (this.left + this.right)) / mustWidth) / areaStackedKf;
this.scaleX = 1;
this.scaleY = 1;
this.aspectRatioY = heightLine / mustHeight;
}
let optimalWidthLine = (widthLine / this.aspectRatioX) / this.scaleX;
if (optimalWidthLine < widthLine) {
return;
}
let kF = optimalWidthLine / (widthLine);
this.aspectRatioX = kF * this.aspectRatioX;
this.scaleY = this.scaleY * kF;
this.scaleZ = this.scaleZ * kF;
};
Processor3D.prototype._recalculateCameraDiff = function () {
this.cameraDiffX = 0;
this.cameraDiffY = 0;
this.cameraDiffZ = 0;
this._calculateCameraDiff();
};
Processor3D.prototype.calculateZPositionValAxis = function () {
let result = 0;
if (!this.view3D.getRAngAx()) {
result = this.orientationCatAx !== ORIENTATION_MIN_MAX ? this.depthPerspective : 0;
if (this.chartsDrawer.calcProp.type !== AscFormat.c_oChartTypes.HBar) {
let angleOyAbs = Math.abs(this.angleOy);
if ((angleOyAbs >= Math.PI / 2 && angleOyAbs < Math.PI) || (angleOyAbs >= 3 * Math.PI / 2 && angleOyAbs < 2 * Math.PI)) {
result = this.orientationCatAx !== ORIENTATION_MIN_MAX ? 0 : this.depthPerspective;
}
} else {
if (this.orientationCatAx !== ORIENTATION_MIN_MAX) {
result = Math.cos(this.angleOy) > 0 ? this.depthPerspective : 0;
} else {
result = Math.cos(this.angleOy) > 0 ? 0 : this.depthPerspective;
}
}
} else if (this.chartsDrawer.calcProp.type !== AscFormat.c_oChartTypes.HBar && this.orientationCatAx !== ORIENTATION_MIN_MAX && this.depthPerspective !== undefined) {
result = this.depthPerspective;
} else if (this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.HBar && this.orientationCatAx !== ORIENTATION_MIN_MAX && this.depthPerspective !== undefined) {
//if(this.chartSpace.chart.plotArea.valAx && this.chartSpace.chart.plotArea.valAx.yPoints && this.chartSpace.chart.plotArea.catAx.posY === this.chartSpace.chart.plotArea.valAx.yPoints[0].pos)
result = this.depthPerspective;
}
return result;
};
Processor3D.prototype.calculateZPositionCatAxis = function () {
let result = 0;
if (!this.view3D.getRAngAx()) {
if (this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.HBar && this.orientationValAx !== ORIENTATION_MIN_MAX) {
result = Math.cos(this.angleOy) > 0 ? this.depthPerspective : 0;
} else {
result = Math.cos(this.angleOy) > 0 ? 0 : this.depthPerspective;
}
} else if (this.chartsDrawer.calcProp.type !== AscFormat.c_oChartTypes.HBar && this.orientationValAx !== ORIENTATION_MIN_MAX && this.depthPerspective !== undefined) {
if (this.chartSpace.chart.plotArea.valAx && this.chartSpace.chart.plotArea.valAx.yPoints && this.chartSpace.chart.plotArea.catAx.posY ===
this.chartSpace.chart.plotArea.valAx.yPoints[0].pos) {
result = this.depthPerspective;
}
} else if (this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.HBar && this.orientationValAx !== ORIENTATION_MIN_MAX && this.depthPerspective !== undefined) {
result = this.depthPerspective;
}
return result;
};
Processor3D.prototype.calculateXPositionSerAxis = function () {
if (!this.view3D.getRAngAx()) {
return Math.sin(this.angleOy) > 0;
}
};
Processor3D.prototype.calculateFloorPosition = function () {
let res, absOy;
if (this.view3D.getRAngAx()) {
if (this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.HBar) {
absOy = Math.abs(this.angleOy);
res = c_oChartFloorPosition.Left;
if (absOy > Math.PI) {
res = c_oChartFloorPosition.Right;
}
} else {
res = c_oChartFloorPosition.Bottom;
if (this.angleOx > 0) {
res = c_oChartFloorPosition.None;
}
}
} else {
if (this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.HBar) {
absOy = Math.abs(this.angleOy);
res = c_oChartFloorPosition.Left;
if (absOy > Math.PI) {
res = c_oChartFloorPosition.Right;
}
} else {
res = c_oChartFloorPosition.Bottom;
if (this.angleOx > 0) {
res = c_oChartFloorPosition.None;
}
}
}
return res;
};
//***functions for complete transformation point***
Processor3D.prototype.convertAndTurnPoint = function (x, y, z, isNScale, isNRotate, isNProject) {
let res = null;
if (this.view3D.getRAngAx()) {
res = this.convertAndTurnPointRAngAx(x, y, z);
} else {
res = this.convertAndTurnPointPerspective(x, y, z, isNScale, isNRotate, isNProject);
}
return res;
};
Processor3D.prototype.convertAndTurnPointRAngAx = function (x, y, z) {
let heightChart = this.heightCanvas - this.top - this.bottom;
let point3D = new Point3D(x, y, z, this);
this.scale(point3D);
//diff
let centerXDiff = heightChart / 2 + this.left / 2;
let centerYDiff = heightChart / 2 + this.top;
let centerZDiff = this.depthPerspective / 2;
point3D.offset(-centerXDiff, -centerYDiff, -centerZDiff);
//rotate
let matrixRotateAllAxis = this._shearXY();
point3D.multiplyPointOnMatrix1(matrixRotateAllAxis);
// diff camera for charts write into rect
point3D.offset(this.cameraDiffX, this.cameraDiffY, this.cameraDiffZ);
//undiff
let specialReverseDiff = this.widthCanvas / 2 + (this.left - this.right) / 2;
point3D.offset(specialReverseDiff, centerYDiff, centerZDiff);
return {x: point3D.x, y: point3D.y, z: z};
};
Processor3D.prototype.convertAndTurnPointPerspective = function (x, y, z, isNScale, isNRotate, isNProject) {
let point3D = new Point3D(x, y, z, this);
if (!isNScale) {
this.scale(point3D);
}
if (!isNRotate) {
this.rotatePerspective(point3D);
}
if (!isNProject) {
this.projectPerspective(point3D);
}
return {x: point3D.x, y: point3D.y, z: point3D.z};
};
Processor3D.prototype.scale = function (point3D) {
//aspectRatio
point3D.x = point3D.x / this.aspectRatioX;
point3D.y = point3D.y / this.aspectRatioY;
point3D.x = point3D.x / this.scaleX;
point3D.y = point3D.y / this.scaleY;
point3D.z = point3D.z / this.scaleZ;
};
Processor3D.prototype.rotatePerspective = function (point3D) {
//diff
point3D.offset((-this.widthCanvas / 2) / this.aspectRatioX, (-this.heightCanvas / 2) / this.aspectRatioY, 0);
//rotate
let matrixRotateAllAxis = this._getMatrixRotateAllAxis();
point3D.multiplyPointOnMatrix1(matrixRotateAllAxis);
point3D.offset((this.widthCanvas / 2) / this.aspectRatioX, (this.heightCanvas / 2) / this.aspectRatioY, 0);
};
Processor3D.prototype.projectPerspective = function (point3D) {
//diff
point3D.offset((-this.widthCanvas / 2) / this.aspectRatioX, (-this.heightCanvas / 2) / this.aspectRatioY /** aspectRatio*/, 0);
// diff camera for charts write into rect
point3D.offset(this.cameraDiffX, this.cameraDiffY, this.cameraDiffZ);
//project
let projectiveMatrix = this._getPerspectiveProjectionMatrix(1 / (this.rPerspective));
point3D.project(projectiveMatrix);
//undiff
let specialReverseDiffX = this.widthCanvas / 2 + (this.left - this.right) / 2;
let specialReverseDiffY = this.heightCanvas / 2 + (this.top - this.bottom) / 2;
point3D.offset(specialReverseDiffX, specialReverseDiffY, 0);
};
//functions for step transformation point
Processor3D.prototype.calculatePointManual = function (x, y, z, diffX, diffY, diffZ) {
diffX = diffX !== undefined ? diffX : this.cameraDiffX;
diffY = diffY !== undefined ? diffY : this.cameraDiffY;
diffZ = diffZ !== undefined ? diffZ : this.cameraDiffZ;
let diffAndScalePoints = this.diffAndScale(x, y, z);
let x11 = diffAndScalePoints.x;
let y11 = diffAndScalePoints.y;
let z11 = diffAndScalePoints.z;
let rotatePoints = this.rotate(x11, y11, z11);
let x111 = rotatePoints.x;
let y111 = rotatePoints.y;
let z111 = rotatePoints.z;
let x1111 = x111 + diffX;
let y1111 = y111 + diffY;
let z1111 = z111 + diffZ;
let projectPoints = this.project(x1111, y1111, z1111);
let x11111 = projectPoints.x;
let y11111 = projectPoints.y;
return {x: x11111, y: y11111};
};
Processor3D.prototype.diffAndScale = function (x, y, z) {
let aRX = this.aspectRatioX;
let aRY = this.aspectRatioY;
let w = this.widthCanvas;
let h = this.heightCanvas;
let x1 = x / aRX;
let x11 = x1 - (w / 2) / aRX;
let z11 = z;
let y1 = y / aRY;
let y11 = y1 - (h / 2) / aRY;
return {x: x11, y: y11, z: z11};
};
Processor3D.prototype.rotate = function (x11, y11, z11) {
let sinOY = Math.sin(-this.angleOy);
let cosOY = Math.cos(-this.angleOy);
let sinOX = Math.sin(-this.angleOx);
let cosOX = Math.cos(-this.angleOx);
let x111 = z11 * sinOY + x11 * cosOY;
let y111 = x11 * sinOX * sinOY + y11 * cosOX - z11 * sinOX * cosOY;
let z111 = -x11 * sinOY * cosOX + y11 * sinOX + z11 * (cosOY * cosOX);
return {x: x111, y: y111, z: z111};
};
Processor3D.prototype.project = function (x1111, y1111, z1111) {
let fov = 1 / this.rPerspective;
let w = this.widthCanvas;
let h = this.heightCanvas;
let x11111 = (fov * x1111) / (z1111 + fov) + w / 2;
let y11111 = (fov * y1111) / (z1111 + fov) + h / 2;
return {x: x11111, y: y11111};
};
//exception for pie charts
Processor3D.prototype.convertAndTurnPointForPie = function (x, y, z) {
let heightChart = this.heightCanvas - this.top - this.bottom;
let point3D = new Point3D(x, y, z, this);
//diff
let centerXDiff = heightChart / 2 + this.left / 2;
let centerYDiff = heightChart / 2 + this.top;
let centerZDiff = this.depthPerspective / 2;
point3D.offset(-centerXDiff, -centerYDiff, -centerZDiff);
//rotate
let matrixRotateAllAxis;
if (!this.view3D.getRAngAx()) {
matrixRotateAllAxis = this._getMatrixRotateAllAxis();
} else {
matrixRotateAllAxis = this._shearXY();
}
point3D.multiplyPointOnMatrix1(matrixRotateAllAxis);
// diff camera for charts write into rect
point3D.offset(this.cameraDiffX, this.cameraDiffY, this.cameraDiffZ);
//project
let projectionPoint = point3D;
if (!this.view3D.getRAngAx()) {
let projectiveMatrix = this._getPerspectiveProjectionMatrix(1 / (this.rPerspective));
projectionPoint = point3D.project(projectiveMatrix);
}
//undiff
let specialReverseDiff = this.widthCanvas / 2 + (this.left - this.right) / 2;
projectionPoint.offset(specialReverseDiff, centerYDiff, centerZDiff);
//console.log(" this.aspectRatioX: " + this.aspectRatioX + " this.aspectRatioY: " + this.aspectRatioY + " this.scaleX: " + this.scaleX + " this.scaleY: " + this.scaleY);
return {x: projectionPoint.x, y: projectionPoint.y};
};
Processor3D.prototype.calculatePropertiesForPieCharts = function () {
let sinAngleOx = Math.sin(-this.angleOx);
let cosAngleOx = Math.cos(-this.angleOx);
let widthCharts = this.widthCanvas - this.left - this.right;
let heightCharts = this.heightCanvas - this.bottom - this.top;
let radius1 = widthCharts / 2;
let radius2 = radius1 * sinAngleOx;
let depth = ((widthCharts + 4.89) / 8.37) * cosAngleOx;
if ((radius2 * 2 + depth) > heightCharts) {
let kF = (radius2 * 2 + depth) / heightCharts;
radius1 = radius1 / kF;
radius2 = radius2 / kF;
depth = depth / kF;
}
//ToDo временная правка для круговой диграммы с углом поворота 0 градусов
if (0 === radius2) {
radius2 = 1;
}
return {radius1: radius1, radius2: radius2, depth: depth};
};
//***functions for matrix transformation***
Processor3D.prototype._shearXY = function () {
if (null === this.matrixShearXY) {
this.matrixShearXY = new Matrix4D();
this.matrixShearXY.a31 = Math.sin(-this.angleOy);
this.matrixShearXY.a32 = Math.sin(this.angleOx);
this.matrixShearXY.a33 = 0;
this.matrixShearXY.a44 = 0;
}
return this.matrixShearXY;
};
Processor3D.prototype._shearXY2 = function () {
if (null === this.matrixShearXY) {
this.matrixShearXY = [[1, 0, 0, 0], [0, 1, 0, 0], [Math.sin(-this.angleOy), Math.sin(this.angleOx), 0, 0], [0, 0, 0, 0]];
}
return this.matrixShearXY;
};
Processor3D.prototype._getMatrixRotateAllAxis = function () {
let matrixRotateOY = this._getMatrixRotateOy();
let matrixRotateOX = this._getMatrixRotateOx();
/*result matrix
|cosOy 0 sinOy 0|
|sinOx * sinOy cosOx -sinOx * cosOy 0|
|-sinOy * cosOx sinOx cosOy * cosOx 0|
|-sinOy 0 (cosOy + 1) 1|*/
if (null === this.matrixRotateAllAxis) {
this.matrixRotateAllAxis = matrixRotateOY.multiply(matrixRotateOX);
}
return this.matrixRotateAllAxis;
};
Processor3D.prototype._getMatrixRotateOx = function () {
//todo array -> Float32Array ?
if (null === this.matrixRotateOx) {
this.matrixRotateOx =
new Matrix4D()/*[[1, 0, 0, 0], [0, Math.cos(-this.angleOx), Math.sin(-this.angleOx), 0], [0, - Math.sin(-this.angleOx), Math.cos(-this.angleOx), 1], [0, 0, 0, 1]]*/;
let cos = Math.cos(-this.angleOx);
let sin = Math.sin(-this.angleOx);
this.matrixRotateOx.a22 = cos;
this.matrixRotateOx.a23 = sin;
this.matrixRotateOx.a32 = -sin;
this.matrixRotateOx.a33 = cos;
this.matrixRotateOx.a34 = 1;
}
return this.matrixRotateOx;
};
Processor3D.prototype._getMatrixRotateOy = function () {
if (null === this.matrixRotateOy) {
this.matrixRotateOy =
new Matrix4D()/*[[Math.cos(-this.angleOy), 0, -Math.sin(-this.angleOy), 0], [0, 1, 0, 0], [Math.sin(-this.angleOy), 0, Math.cos(-this.angleOy), 1], [0, 0, 0, 1]]*/;
let cos = Math.cos(-this.angleOy);
let sin = Math.sin(-this.angleOy);
this.matrixRotateOy.a11 = cos;
this.matrixRotateOy.a13 = -sin;
this.matrixRotateOy.a31 = sin;
this.matrixRotateOy.a33 = cos;
this.matrixRotateOy.a34 = 1;
}
return this.matrixRotateOy;
};
Processor3D.prototype._getMatrixRotateOz = function () {
return [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 0, 1]];
};
Processor3D.prototype._getPerspectiveProjectionMatrix = function (fov) {
/*let zf = this.rPerspective + this.depthPerspective;
let zn = this.rPerspective;
let q = zf / (zf - zn);
return [[1 / Math.tan(this.rPerspective / 2), 0, 0, 0], [0, 1 / Math.tan(this.rPerspective / 2), 0, 0], [0, 0, q, 1], [0, 0, -q * zn, 0]];*/
//[[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1 / fov], [0, 0, 0, 1]]
if (null === this.projectMatrix) {
this.projectMatrix = new Matrix4D();
this.projectMatrix.a33 = 0;
this.projectMatrix.a34 = 1 / fov;
}
return this.projectMatrix;
};
Processor3D.prototype.correctPointsPosition = function (chartSpace) {
if (this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.Pie) {
return;
}
let pxToMM = 1 / AscCommon.g_dKoef_pix_to_mm;
let t = this;
//коррективы для подписей
let xPoints = chartSpace.chart.plotArea && chartSpace.chart.plotArea.catAx ? chartSpace.chart.plotArea.catAx.xPoints : null;
if (!xPoints) {
xPoints = chartSpace.chart.plotArea && chartSpace.chart.plotArea.valAx ? chartSpace.chart.plotArea.valAx.xPoints : null;
}
let coordYAxisOx = chartSpace.chart.plotArea.catAx && chartSpace.chart.plotArea.catAx.posY;
if (!coordYAxisOx && chartSpace.chart.plotArea.valAx) {
coordYAxisOx = chartSpace.chart.plotArea.valAx.posY != undefined ? chartSpace.chart.plotArea.valAx.posY : chartSpace.chart.plotArea.valAx.posY;
}
let yPoints = chartSpace.chart.plotArea && chartSpace.chart.plotArea.valAx ? chartSpace.chart.plotArea.valAx.yPoints : null;
if (!yPoints) {
yPoints = chartSpace.chart.plotArea && chartSpace.chart.plotArea.catAx ? chartSpace.chart.plotArea.catAx.yPoints : null;
}
let coordXAxisOy;
if (chartSpace.chart.plotArea.catAx) {
coordXAxisOy = chartSpace.chart.plotArea.catAx.posX ? chartSpace.chart.plotArea.catAx.posX : chartSpace.chart.plotArea.catAx.xPos;
}
if (!coordXAxisOy && chartSpace.chart.plotArea.valAx) {
coordXAxisOy = chartSpace.chart.plotArea.valAx.posX != undefined ? chartSpace.chart.plotArea.valAx.posX : null;
}
let correctPointsOx = function () {
let z = t.calculateZPositionCatAxis();
let valCatAx = chartSpace.chart.plotArea.catAx;
if (!valCatAx.transformXPoints) {
valCatAx.transformXPoints = [];
}
for (let i = 0; i < xPoints.length; i++) {
let widthText = 0;
if (valCatAx && valCatAx.labels && t.orientationValAx !== ORIENTATION_MIN_MAX) {
widthText = valCatAx.labels.extY * pxToMM;
}
let point = t.convertAndTurnPoint(xPoints[i].pos * pxToMM, coordYAxisOx * pxToMM - widthText, z);
valCatAx.transformXPoints[i] = {x: point.x / pxToMM, y: point.y / pxToMM};
}
};
let correctPointsOxHBar = function () {
let z = t.calculateZPositionValAxis();
let valCatAx = chartSpace.chart.plotArea.valAx;
if (!valCatAx.transformXPoints) {
valCatAx.transformXPoints = [];
}
for (let i = 0; i < xPoints.length; i++) {
let widthText = 0;
if (t.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.HBar && valCatAx && valCatAx.labels && t.orientationCatAx !== ORIENTATION_MIN_MAX) {
widthText = valCatAx.labels.extY * pxToMM;
}
let point = t.convertAndTurnPoint(xPoints[i].pos * pxToMM, coordYAxisOx * pxToMM - widthText, z);
valCatAx.transformXPoints[i] = {x: point.x / pxToMM, y: point.y / pxToMM};
}
};
let correctPointsOy = function () {
let zPosition = t.calculateZPositionValAxis();
let valCatAx = chartSpace.chart.plotArea.valAx;
if (!valCatAx.transformYPoints) {
valCatAx.transformYPoints = [];
}
for (let i = 0; i < yPoints.length; i++) {
let point = t.convertAndTurnPoint(coordXAxisOy * pxToMM, yPoints[i].pos * (pxToMM), zPosition);
//TODO значения высчитать
let widthText = 5;
if (valCatAx && valCatAx.labels) {
widthText = valCatAx.labels.extX * pxToMM;
}
if (t.orientationCatAx !== ORIENTATION_MIN_MAX) {
widthText = 0;
}
let diffXText = 0;
let angleOyAbs = Math.abs(t.angleOy);
if (!t.view3D.getRAngAx() && (angleOyAbs >= Math.PI / 2 && angleOyAbs < 3 * Math.PI / 2)) {
diffXText = -diffXText;
}
valCatAx.transformYPoints[i] = {
x: (point.x - (diffXText + widthText)) / pxToMM, y: point.y / pxToMM
};
}
};
let correctPointsOyHBar = function () {
let zPosition = t.calculateZPositionCatAxis();
let valCatAx = chartSpace.chart.plotArea.catAx;
if (!valCatAx.transformYPoints) {
valCatAx.transformYPoints = [];
}
for (let i = 0; i < yPoints.length; i++) {
let point = t.convertAndTurnPoint(coordXAxisOy * pxToMM, yPoints[i].pos * (pxToMM), zPosition);
//TODO значения высчитать
let widthText = 0;
if (valCatAx && valCatAx.labels) {
widthText = valCatAx.labels.extX * pxToMM;
}
if (t.orientationValAx !== ORIENTATION_MIN_MAX) {
widthText -= 10;
} else {
widthText += 5;
}
valCatAx.transformYPoints[i] = {x: (point.x - widthText) / pxToMM, y: point.y / pxToMM};
}
};
if (xPoints) {
if (this.chartsDrawer.calcProp.type !== AscFormat.c_oChartTypes.HBar) {
correctPointsOx(xPoints);
} else {
correctPointsOxHBar(xPoints);
}
}
if (yPoints) {
if (this.chartsDrawer.calcProp.type !== AscFormat.c_oChartTypes.HBar) {
correctPointsOy(yPoints);
} else {
correctPointsOyHBar(yPoints);
}
}
};
Processor3D.prototype._calculatePerspective = function (view3D) {
let heightLine = this.heightCanvas - (this.top + this.bottom);
let perspective = view3D && view3D.perspective ? view3D.perspective : global3DPersperctive;
if (view3D && 0 === view3D.perspective && this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.Surface) {
perspective = 1;
}
let alpha = perspective / 4;//в xml проиходит двойной угол(в параметрах ms стоит 40, приходит в xml 80)
//TODO this.top - this.bottom пересмотреть
let catt = ((heightLine / 2 + (Math.abs(this.top - this.bottom)))) / Math.tan((alpha / 360) * (Math.PI * 2));
let rPerspective;
if (catt === 0) {
rPerspective = 0;
} else {
rPerspective = 1 / catt;
}
this.rPerspective = rPerspective;
};
Processor3D.prototype._calculateDepth = function () {
let widthOriginalChart = this.widthCanvas - (this.left + this.right);
let heightOriginalChart = this.heightCanvas - (this.top + this.bottom);
let subType = this.chartsDrawer.calcProp.subType;
let type = this.chartsDrawer.calcProp.type;
let defaultOverlap = (subType === "stacked" || subType === "stackedPer" || subType === "standard" || type === AscFormat.c_oChartTypes.Line || type ===
AscFormat.c_oChartTypes.Area || type === AscFormat.c_oChartTypes.Surface) ? 100 : 0;
let overlap = AscFormat.isRealNumber(this.chartSpace.chart.plotArea.chart.overlap) ? (this.chartSpace.chart.plotArea.chart.overlap / 100) : (defaultOverlap / 100);
let gapWidth = this.chartSpace.chart.plotArea.chart.gapWidth != null ? (this.chartSpace.chart.plotArea.chart.gapWidth / 100) : (150 / 100);
let gapDepth = this.chartSpace.chart.plotArea.chart.gapDepth != null ? (this.chartSpace.chart.plotArea.chart.gapDepth / 100) :
type === AscFormat.c_oChartTypes.Area && subType !== "normal" ? 1 : (150 / 100);
let seriesProps = this.chartsDrawer.calculateFirstChartCountSeries();
let seriesCount = seriesProps.series;
let ptCount = seriesProps.points;
let sinOx = Math.abs(Math.sin(-this.angleOx));
let sinOy = Math.sin(-this.angleOy);
let hPercent = type === AscFormat.c_oChartTypes.HBar ? 1 : this.hPercent;
let depthPercent = this._getDepthPercent();
let t = this;
let areaStackedKf = (type === AscFormat.c_oChartTypes.Area && subType !== "normal") || type === AscFormat.c_oChartTypes.Surface ? (ptCount / (2 * (ptCount - 1))) : 1;
let depth = 0;
let chartWidth = 0;
let standardType = false;
if (subType === "standard" || type === AscFormat.c_oChartTypes.Line || (type === AscFormat.c_oChartTypes.Area && subType === "normal") ||
(type === AscFormat.c_oChartTypes.Surface)) {
standardType = true;
}
let heightHPercent = heightOriginalChart / hPercent;
let angleOxKf;
if (!standardType) {
let widthOneBar = ((heightHPercent / seriesCount) / (ptCount - (ptCount - 1) * (overlap) + gapWidth)) * sinOy;
let a, b;
if (this.angleOx === 0 && this.angleOy === 0)//withoutAngleNoAuto + withoutAngleAuto
{
chartWidth = widthOneBar + heightHPercent;
} else if (this.angleOx !== 0)//AngleOYNoAut + AngleOYNoAutPerHeight + (ANGLEOX+ANGLEOY) + AngleOYOXNoAut + ANGLEOXANGLEOYHPerDPer(ANGLEOX+ANGLEOY HPercent)
{
//если выставить ширину 255 будет так же, как и в документе с расчётами
b = (seriesCount - (seriesCount - 1) * overlap + gapWidth);
a = (depthPercent / (ptCount * b)) / hPercent;
let width = heightOriginalChart * areaStackedKf;
depth = (width * a + gapDepth * width * a) / (1 / sinOx + (gapDepth) * a + a);
chartWidth = heightHPercent - depth;
} else if (this.angleOy !== 0)//angleOxNoAuto
{
//если выставить ширину = 321.25 будет так же, как и в документе с расчётам
//TODO глубина с некоторыми графиками имеет различия, пересчитать!
let widthChart = (widthOriginalChart / t.aspectRatioX) / t.specialStandardScaleX;
b = (seriesCount - (seriesCount - 1) * overlap + gapWidth);
if (subType === "standard" || type === AscFormat.c_oChartTypes.Line || type === AscFormat.c_oChartTypes.Area || type === AscFormat.c_oChartTypes.Surface) {
b = b / seriesCount;
}
angleOxKf = sinOx === 0 ? 1 : sinOx;
a = depthPercent / (ptCount * b);
depth = (widthChart * a + gapDepth * widthChart * a) / (1 / angleOxKf + (gapDepth) * a + a);
depth = depth / angleOxKf;
}
} else//allStandardDepth
{
angleOxKf = sinOx === 0 ? 0 : sinOx;
if (type === AscFormat.c_oChartTypes.Area) {
depth =
(depthPercent / (angleOxKf * depthPercent + ((ptCount + (Math.floor((seriesCount - ptCount) / 2 - 0.5))) / seriesCount * hPercent))) * (heightOriginalChart);
} else {
depth = (depthPercent / (angleOxKf * depthPercent + ((ptCount + (Math.floor((seriesCount - ptCount) / 2))) / seriesCount * hPercent))) * (heightOriginalChart);
}
if ((this.angleOx !== 0)) {
depth = depth * Math.sin(-this.angleOx);
}
}
return sinOx !== 0 ? Math.abs(depth / sinOx) : Math.abs(depth);
};
Processor3D.prototype._calculateDepthPerspective = function () {
let widthCanvas = this.widthCanvas;
let widthOriginalChart = widthCanvas - (this.left + this.right);
let aspectRatio = this.aspectRatioX / (this.specialStandardScaleX);
let widthChart = widthOriginalChart / aspectRatio;
widthChart = widthChart / this.scaleX;
let countSeries = this.chartsDrawer.calculateFirstChartCountSeries();
let seriesCount = countSeries.series;
let ptCount = countSeries.points;
let width = widthChart / ptCount;
let isNormalArea = (this.chartsDrawer.calcProp.subType === "normal" && this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.Area) ||
this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.Surface;
let defaultOverlap = (this.chartsDrawer.calcProp.subType === "stacked" || this.chartsDrawer.calcProp.subType === "stackedPer" || this.chartsDrawer.calcProp.subType ===
"standard" || this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.Line || isNormalArea) ? 100 : 0;
let overlap = AscFormat.isRealNumber(this.chartSpace.chart.plotArea.chart.overlap) ? (this.chartSpace.chart.plotArea.chart.overlap / 100) : (defaultOverlap / 100);
let gapWidth = this.chartSpace.chart.plotArea.chart.gapWidth != null ? (this.chartSpace.chart.plotArea.chart.gapWidth / 100) : (150 / 100);
let gapDepth = this.chartSpace.chart.plotArea.chart.gapDepth != null ? (this.chartSpace.chart.plotArea.chart.gapDepth / 100) : (150 / 100);
if (AscFormat.c_oChartTypes.Area === this.chartsDrawer.calcProp.type || AscFormat.c_oChartTypes.Surface === this.chartsDrawer.calcProp.type) {
gapWidth = 0;
gapDepth = 0;
}
let baseDepth = width / (seriesCount - (seriesCount - 1) * overlap + gapWidth);
if (this.chartsDrawer.calcProp.subType === "standard" || this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.Line || isNormalArea) {
baseDepth = (width / (seriesCount - (seriesCount - 1) * overlap + gapWidth)) * seriesCount;
}
let basePercent = this._getDepthPercent();
let depth = baseDepth * basePercent;
depth = depth + depth * gapDepth;
if (this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.HBar && this.hPercent !== null) {
depth = this.hPercent * depth;
}
//TODO глубина в некоторых случаях отличается(тип Standard)
if (this.chartsDrawer.calcProp.subType === "standard" || this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.Line || isNormalArea) {
let b = 1 / seriesCount;
let sinOx = Math.sin(-this.angleOx);
let angleOxKf = 1;
let a = basePercent / (ptCount * b);
depth = (widthChart * a + widthChart * a) / (1 / angleOxKf + a);
depth = depth / angleOxKf;
}
return depth;
};
Processor3D.prototype._calcSpecialStandardScaleX = function () {
let type = this.chartsDrawer.calcProp.type;
let subType = this.chartsDrawer.calcProp.subType;
if (!(subType === "standard" || type === AscFormat.c_oChartTypes.Line || (type === AscFormat.c_oChartTypes.Area && subType === "normal") || type ===
AscFormat.c_oChartTypes.Surface)) {
return;
}
let countSeries = this.chartsDrawer.calculateFirstChartCountSeries();
let seriesCount = countSeries.series;
let ptCount = countSeries.points;
//calculate width in 3d standard charts with rAngAx
let n = Math.floor((seriesCount + ptCount) / 2);
let kf = ptCount / n;
this.specialStandardScaleX = 1 / kf;
};
Processor3D.prototype._calculateScaleFromDepth = function (/*isSkip*/) {
//***Calculate scaleY***
if (this.view3D.getRAngAx() && this.aspectRatioY === 1) {
let heightCanvas = this.heightCanvas;
let heightChart = heightCanvas - this.top - this.bottom;
this.scaleY = heightChart / (-this.depthPerspective * Math.sin(Math.abs(this.angleOx)) + heightChart);
let subType = this.chartsDrawer.calcProp.subType;
let newDepth, newWidth;
if (!(subType === "standard" || this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.Line || this.chartsDrawer.calcProp.type ===
AscFormat.c_oChartTypes.Surface || (this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.Area && subType === "normal"))) {
newDepth = this.depthPerspective * Math.sin(-this.angleOx);
newWidth = heightChart - newDepth;
this.scaleX = heightChart / newWidth;
}
}
};
Processor3D.prototype._calculateCameraDiff = function (/*isSkip*/) {
//глубина по OZ
let perspectiveDepth = this.depthPerspective;
let widthCanvas = this.widthCanvas;
let originalWidthChart = widthCanvas - this.left - this.right;
let heightCanvas = this.heightCanvas;
let heightChart = heightCanvas - this.top - this.bottom;
//add test points for parallelepiped rect
let points = [];
let faces = [];
/*if(AscFormat.c_oChartTypes.Pie === this.chartsDrawer.calcProp.type)
{
points.push(new Point3D(this.left + originalWidthChart / 2, this.top, perspectiveDepth, this));
points.push(new Point3D(this.left, this.top, perspectiveDepth / 2, this));
points.push(new Point3D(this.left + originalWidthChart, this.top, perspectiveDepth / 2, this));
points.push(new Point3D(this.left + originalWidthChart / 2, this.top, 0, this));
points.push(new Point3D(this.left + originalWidthChart / 2, this.top + heightChart, perspectiveDepth, this));
points.push(new Point3D(this.left, this.top + heightChart, perspectiveDepth / 2, this));
points.push(new Point3D(this.left + originalWidthChart, this.top + heightChart, perspectiveDepth / 2, this));
points.push(new Point3D(this.left + originalWidthChart / 2, this.top + heightChart, 0, this));
}
else
{*/
points.push(new Point3D(this.left, this.top, perspectiveDepth, this));
points.push(new Point3D(this.left, heightChart + this.top, perspectiveDepth, this));
points.push(new Point3D(originalWidthChart + this.left, heightChart + this.top, perspectiveDepth, this));
points.push(new Point3D(originalWidthChart + this.left, this.top, perspectiveDepth, this));
points.push(new Point3D(originalWidthChart + this.left, this.top, 0, this));
points.push(new Point3D(originalWidthChart + this.left, heightChart + this.top, 0, this));
points.push(new Point3D(this.left, heightChart + this.top, 0, this));
points.push(new Point3D(this.left, this.top, 0, this));
//}
faces.push([0, 1, 2, 3]);
faces.push([2, 5, 4, 3]);
faces.push([1, 6, 7, 0]);
faces.push([6, 5, 4, 7]);
faces.push([7, 4, 3, 0]);
faces.push([1, 6, 2, 5]);
//***Calculate cameraDiffZ***
if (!this.view3D.getRAngAx()) {
//быстрая функция поиска сдвигов камеры
//console.time("sdf");
this._calculateCameraDiffZX(points, faces);
//console.timeEnd("sdf");
}
//***Calculate cameraDiffX***
if (this.view3D.getRAngAx()) {
let minMaxOx = this._getMinMaxOx(points, faces);
this._calculateCameraDiffX(minMaxOx);
//***Calculate cameraDiffY***
let minMaxOy = this._getMinMaxOy(points, faces);
this._calculateCameraDiffY(minMaxOy.top, minMaxOy.bottom);
}
};
Processor3D.prototype._calculateCameraDiffZX = function (newPoints) {
let heightChart = this.heightCanvas - this.top - this.bottom;
let widthOriginalChart = this.widthCanvas - this.left - this.right;
let heightOriginalChart = heightChart;
let minX = null;
let maxX = null;
let minZ = null;
let aspectRatio = (widthOriginalChart) / (heightOriginalChart);
for (let i = 0; i < newPoints.length; i++) {
let point3D = new Point3D(newPoints[i].x, newPoints[i].y, newPoints[i].z, this);
point3D.scale(aspectRatio, 1, 1);
point3D.offset((-this.widthCanvas / 2) / aspectRatio, (-this.heightCanvas / 2), 0);
//rotate
let matrixRotateAllAxis = this._getMatrixRotateAllAxis();
point3D.multiplyPointOnMatrix1(matrixRotateAllAxis);
if (minZ === null || point3D.z < minZ) {
minZ = point3D.z;
}
if (minX === null || point3D.x < minX) {
minX = point3D.x;
}
if (maxX === null || point3D.x > maxX) {
maxX = point3D.x;
}
}
//get min and max point's and diffX
/*if(-t.angleOx === 0)
{
let minMaxOx = this._getMinMaxOxPoints(newPoints, minZ);
this.cameraDiffZ = - minZ;
this.cameraDiffX = - minMaxOx.diffX;
let x111 = this.convertAndTurnPoint(minMaxOx.tempX1, minMaxOx.tempY1, minMaxOx.tempZ1);
let x222 = this.convertAndTurnPoint(minMaxOx.tempX2, minMaxOx.tempY2, minMaxOx.tempZ2);
if(Math.abs(x222.x - x111.x) > widthOriginalChart)
{
let correctOffset;
if(x222.x > x111.x)
{
correctOffset = this._correctZPosition4(minMaxOx.tempX1, minMaxOx.tempX2, minMaxOx.tempZ1, minMaxOx.tempZ2, minZ, minMaxOx.tempY1, minMaxOx.tempY2);
}
else
{
correctOffset = this._correctZPosition4(minMaxOx.tempX1, minMaxOx.tempX2, minMaxOx.tempZ1, minMaxOx.tempZ2, minZ, minMaxOx.tempY1, minMaxOx.tempY2);
}
this.cameraDiffZ = Math.abs(correctOffset.minZ);
this.cameraDiffX = correctOffset.diffX;
}
}
else if(-t.angleOy === 0 && -t.angleOx !== 0)
{
let minMaxOy = this._getMinMaxOyPoints(newPoints, minZ);
this.cameraDiffZ = - minZ;
this.cameraDiffY = -minMaxOy.diffY;
let y111 = this.convertAndTurnPoint(minMaxOy.tempX1, minMaxOy.tempY1, minMaxOy.tempZ1);
let y222 = this.convertAndTurnPoint(minMaxOy.tempX2, minMaxOy.tempY2, minMaxOy.tempZ2);
if(Math.abs(y111.y - y222.y) < heightOriginalChart)
{
let minMaxOx = this._getMinMaxOxPoints(newPoints, minZ);
let x111 = this.convertAndTurnPoint(minMaxOx.tempX1, minMaxOx.tempY1, minMaxOx.tempZ1);
let x222 = this.convertAndTurnPoint(minMaxOx.tempX2, minMaxOx.tempY2, minMaxOx.tempZ2);
let correctOffset;
if(x222.x > x111.x)
{
correctOffset = this._correctZPosition4(minMaxOx.tempX1, minMaxOx.tempX2, minMaxOx.tempZ1, minMaxOx.tempZ2, minZ, minMaxOx.tempY1, minMaxOx.tempY2);
}
else
{
correctOffset = this._correctZPosition4(minMaxOx.tempX1, minMaxOx.tempX2, minMaxOx.tempZ1, minMaxOx.tempZ2, minZ, minMaxOx.tempY1, minMaxOx.tempY2);
}
this.cameraDiffZ = Math.abs(correctOffset.minZ);
this.cameraDiffX = correctOffset.diffX;
let minMaxOy = this._getMinMaxOyPoints(newPoints, 0);
//this.cameraDiffZ = - minZ;
this.cameraDiffY = -minMaxOy.diffY;
}
}*/
/*else if(-t.angleOy !== 0 && -t.angleOx !== 0)
{
let minMaxOx = this._getMinMaxOxPoints(newPoints, minZ);
let x111 = this.convertAndTurnPoint(minMaxOx.tempX1, minMaxOx.tempY1, minMaxOx.tempZ1);
let x222 = this.convertAndTurnPoint(minMaxOx.tempX2, minMaxOx.tempY2, minMaxOx.tempZ2);
let correctOffset;
if(x222.x > x111.x)
{
correctOffset = this._correctZPosition4(minMaxOx.tempX1, minMaxOx.tempX2, minMaxOx.tempZ1, minMaxOx.tempZ2, minZ, minMaxOx.tempY1, minMaxOx.tempY2);
}
else
{
correctOffset = this._correctZPosition4(minMaxOx.tempX2, minMaxOx.tempX1, minMaxOx.tempZ2, minMaxOx.tempZ1, minZ, minMaxOx.tempY2, minMaxOx.tempY1);
}
this.cameraDiffZ = correctOffset.minZ;
this.cameraDiffX = correctOffset.diffX;
let minMaxOy = this._getMinMaxOyPoints2(newPoints, this.cameraDiffZ);
this.cameraDiffY = minMaxOy.diffY;
console.log(" tempX1: " + minMaxOy.tempX1 + " tempX2: " + minMaxOy.tempX2 + " tempY1: " + minMaxOy.tempY1 + " tempY2: " + minMaxOy.tempY2 + " tempZ1: " + minMaxOy.tempZ1 + " tempZ2: " + minMaxOy.tempZ2);
let y111 = this.convertAndTurnPoint(minMaxOy.tempX1, minMaxOy.tempY1, minMaxOy.tempZ1);
let y222 = this.convertAndTurnPoint(minMaxOy.tempX2, minMaxOy.tempY2, minMaxOy.tempZ2);
if(y111.y < this.top || y222.y > this.top + heightOriginalChart)
{
//correctOffset = this._correctZPositionOY(minMaxOy.tempX1, minMaxOy.tempX2, minMaxOy.tempZ1, minMaxOy.tempZ2, minZ, minMaxOy.tempY1, minMaxOy.tempY2);
this.cameraDiffZ = minMaxOy.diffZ;
//this.cameraDiffY = minMaxOy.diffY;
let minMaxOx = this._getMinMaxOxPoints(newPoints, -this.cameraDiffZ);
//correctOffset = this._correctZPosition4(minMaxOx.tempX1, minMaxOx.tempX2, minMaxOx.tempZ1, minMaxOx.tempZ2, -this.cameraDiffZ, minMaxOx.tempY1, minMaxOx.tempY2);
this.cameraDiffX = -minMaxOx.diffX;
}
//TODO пока включаю для поворотов по OX + по OY checkOutSideArea(медленная функция), затем нужно переделать, используя закомментированный код сверху
this.cameraDiffZ = -minZ;
//this.cameraDiffX = -minMaxOx.diffX;
this.checkOutSideArea(newPoints);
}*/
//TODO пока включаю для ВСЕГО checkOutSideArea(медленная функция), затем нужно переделать, используя закомментированный код сверху
this.cameraDiffZ = -minZ;
this.checkOutSideArea2(newPoints);
};
//TODO если будут проблемы при маштабировании, вернуть функцию checkOutSideArea2 вместо checkOutSideArea
Processor3D.prototype.checkOutSideArea2 = function (newPoints) {
let i = 0;
let maxI = 1000;
let t = this;
let heightChart = this.heightCanvas - this.top - this.bottom;
let widthChart = this.widthCanvas - this.left - this.right;
let calculateZ = function (step) {
let minMaxOx = t._getMinMaxOxPoints(newPoints, -t.cameraDiffZ);
t.cameraDiffX = -minMaxOx.diffX;
let x111 = t.convertAndTurnPoint(minMaxOx.tempX1, minMaxOx.tempY1, minMaxOx.tempZ1);
let x222 = t.convertAndTurnPoint(minMaxOx.tempX2, minMaxOx.tempY2, minMaxOx.tempZ2);
let diffX = Math.abs(x222.x - x111.x);
let minMaxOy = t._getMinMaxOyPoints(newPoints, t.cameraDiffZ);
t.cameraDiffY = -minMaxOy.diffY;
let y111 = t.convertAndTurnPoint(minMaxOy.tempX1, minMaxOy.tempY1, minMaxOy.tempZ1);
let y222 = t.convertAndTurnPoint(minMaxOy.tempX2, minMaxOy.tempY2, minMaxOy.tempZ2);
let diffY = Math.abs(y222.y - y111.y);
if (diffX < widthChart && diffY < heightChart)//if size less then width or height
{
while (diffX < widthChart && diffY < heightChart) {
t.cameraDiffZ -= step;
i++;
minMaxOx = t._getMinMaxOxPoints(newPoints, -t.cameraDiffZ);
t.cameraDiffX = -minMaxOx.diffX;
x111 = t.convertAndTurnPoint(minMaxOx.tempX1, minMaxOx.tempY1, minMaxOx.tempZ1);
x222 = t.convertAndTurnPoint(minMaxOx.tempX2, minMaxOx.tempY2, minMaxOx.tempZ2);
diffX = Math.abs(x222.x - x111.x);
minMaxOy = t._getMinMaxOyPoints(newPoints, t.cameraDiffZ);
t.cameraDiffY = -minMaxOy.diffY;
y111 = t.convertAndTurnPoint(minMaxOy.tempX1, minMaxOy.tempY1, minMaxOy.tempZ1);
y222 = t.convertAndTurnPoint(minMaxOy.tempX2, minMaxOy.tempY2, minMaxOy.tempZ2);
diffY = Math.abs(y222.y - y111.y);
if (i > maxI) {
break;
}
}
} else if (diffX > widthChart || diffY > heightChart)//if size more then width or height
{
while (diffX > widthChart || diffY > heightChart) {
t.cameraDiffZ += step;
i++;
minMaxOx = t._getMinMaxOxPoints(newPoints, -t.cameraDiffZ);
t.cameraDiffX = -minMaxOx.diffX;
x111 = t.convertAndTurnPoint(minMaxOx.tempX1, minMaxOx.tempY1, minMaxOx.tempZ1);
x222 = t.convertAndTurnPoint(minMaxOx.tempX2, minMaxOx.tempY2, minMaxOx.tempZ2);
diffX = Math.abs(x222.x - x111.x);
minMaxOy = t._getMinMaxOyPoints(newPoints, t.cameraDiffZ);
t.cameraDiffY = -minMaxOy.diffY;
y111 = t.convertAndTurnPoint(minMaxOy.tempX1, minMaxOy.tempY1, minMaxOy.tempZ1);
y222 = t.convertAndTurnPoint(minMaxOy.tempX2, minMaxOy.tempY2, minMaxOy.tempZ2);
diffY = Math.abs(y222.y - y111.y);
if (i > maxI) {
break;
}
}
}
};
calculateZ(100);
calculateZ(10);
calculateZ(1);
};
Processor3D.prototype.checkOutSideArea = function (newPoints) {
let t = this;
let heightChart = this.heightCanvas - this.top - this.bottom;
let widthChart = this.widthCanvas - this.left - this.right;
let DELTA = 3;
let maxCount = 1000;
let calculateZ = function () {
let minMaxOx = t._getMinMaxOxPoints(newPoints, -t.cameraDiffZ);
t.cameraDiffX = -minMaxOx.diffX;
let x111 = t.convertAndTurnPoint(minMaxOx.tempX1, minMaxOx.tempY1, minMaxOx.tempZ1);
let x222 = t.convertAndTurnPoint(minMaxOx.tempX2, minMaxOx.tempY2, minMaxOx.tempZ2);
let diffX = Math.abs(x222.x - x111.x);
let minMaxOy = t._getMinMaxOyPoints(newPoints, t.cameraDiffZ);
t.cameraDiffY = -minMaxOy.diffY;
let y111 = t.convertAndTurnPoint(minMaxOy.tempX1, minMaxOy.tempY1, minMaxOy.tempZ1);
let y222 = t.convertAndTurnPoint(minMaxOy.tempX2, minMaxOy.tempY2, minMaxOy.tempZ2);
let diffY = Math.abs(y222.y - y111.y);
if (diffX <= widthChart && diffY <= heightChart && ((widthChart - diffX) < DELTA || (heightChart - diffY) < DELTA)) {
return;
}
let count = 0;
let fStart = t.cameraDiffZ ? t.cameraDiffZ : 1;
let fLeftDiffZ, fRightDiffZ;
if (diffX < widthChart && diffY < heightChart) {
fLeftDiffZ = 0;
fRightDiffZ = t.cameraDiffZ;
} else {
fLeftDiffZ = t.cameraDiffZ;
while (diffX >= widthChart || diffY >= heightChart) {
count++;
t.cameraDiffZ += fStart / 2;
minMaxOx = t._getMinMaxOxPoints(newPoints, -t.cameraDiffZ);
t.cameraDiffX = -minMaxOx.diffX;
x111 = t.convertAndTurnPoint(minMaxOx.tempX1, minMaxOx.tempY1, minMaxOx.tempZ1);
x222 = t.convertAndTurnPoint(minMaxOx.tempX2, minMaxOx.tempY2, minMaxOx.tempZ2);
diffX = Math.abs(x222.x - x111.x);
minMaxOy = t._getMinMaxOyPoints(newPoints, t.cameraDiffZ);
t.cameraDiffY = -minMaxOy.diffY;
y111 = t.convertAndTurnPoint(minMaxOy.tempX1, minMaxOy.tempY1, minMaxOy.tempZ1);
y222 = t.convertAndTurnPoint(minMaxOy.tempX2, minMaxOy.tempY2, minMaxOy.tempZ2);
diffY = Math.abs(y222.y - y111.y);
if (count > maxCount) {
return;
}
}
if (diffX <= widthChart && diffY <= heightChart && ((widthChart - diffX) < DELTA || (heightChart - diffY) < DELTA)) {
return;
}
fRightDiffZ = t.cameraDiffZ;
}
while ((diffX > widthChart || diffY > heightChart) || (fRightDiffZ - fLeftDiffZ) > DELTA) {
t.cameraDiffZ = fLeftDiffZ + ((fRightDiffZ - fLeftDiffZ) / 2);
count++;
minMaxOx = t._getMinMaxOxPoints(newPoints, -t.cameraDiffZ);
t.cameraDiffX = -minMaxOx.diffX;
let x111 = t.convertAndTurnPoint(minMaxOx.tempX1, minMaxOx.tempY1, minMaxOx.tempZ1);
let x222 = t.convertAndTurnPoint(minMaxOx.tempX2, minMaxOx.tempY2, minMaxOx.tempZ2);
let diffX = Math.abs(x222.x - x111.x);
let minMaxOy = t._getMinMaxOyPoints(newPoints, t.cameraDiffZ);
t.cameraDiffY = -minMaxOy.diffY;
let y111 = t.convertAndTurnPoint(minMaxOy.tempX1, minMaxOy.tempY1, minMaxOy.tempZ1);
let y222 = t.convertAndTurnPoint(minMaxOy.tempX2, minMaxOy.tempY2, minMaxOy.tempZ2);
let diffY = Math.abs(y222.y - y111.y);
if (diffX < widthChart && diffY < heightChart) {
if (((widthChart - diffX) < DELTA) || ((heightChart - diffY) < DELTA)) {
break;
}
fRightDiffZ = t.cameraDiffZ;
} else {
fLeftDiffZ = t.cameraDiffZ;
}
if (count > maxCount) {
return;
}
}
};
calculateZ();
};
Processor3D.prototype._getMinMaxOxPoints = function (points, minZ) {
let fov = 1 / this.rPerspective;
let t = this;
let aspectRatioX = this.aspectRatioX;
let aspectRatioY = this.aspectRatioY;
let diffAndRotatePoint = function (point) {
let point3D = new Point3D(point.x, point.y, point.z, t);
point3D.scale(aspectRatioX, aspectRatioY, 1);
point3D.offset((-t.widthCanvas / 2) / aspectRatioX, (-t.heightCanvas / 2) / aspectRatioY /** aspectRatio*/, 0);
//rotate
let matrixRotateAllAxis = t._getMatrixRotateAllAxis();
point3D.multiplyPointOnMatrix1(matrixRotateAllAxis);
return point3D;
};
let calculateDiffX = function (x1, x2, z1, z2, minZ, y1, y2) {
let diffAndScalePoints1 = t.diffAndScale(x1, y1, z1);
x1 = diffAndScalePoints1.x;
y1 = diffAndScalePoints1.y;
z1 = diffAndScalePoints1.z;
let rotatePoints1 = t.rotate(x1, y1, z1);
let a1 = rotatePoints1.x;
//let x1S = a1 - diffX;
let z1S = rotatePoints1.z - minZ;
//let x1SS = (fov * x1S / (z1S + fov)) + w / 2;
let diffAndScalePoints2 = t.diffAndScale(x2, y2, z2);
x2 = diffAndScalePoints2.x;
y2 = diffAndScalePoints2.y;
z2 = diffAndScalePoints2.z;
let rotatePoints2 = t.rotate(x2, y2, z2);
let a2 = rotatePoints2.x;
//let x2S = a2 - diffX;
let z2S = rotatePoints2.z - minZ;
//let x2SS = (fov * x2S / (z2S + fov)) + w / 2;
return (-a1 * z2S - a1 * fov - a2 * z1S - a2 * fov) / (-z2S - fov - z1S - fov);
};
let w = t.widthCanvas;
let tempArray = this._getArrayAllVergeCube(points);
let diffX;
let x11, x22, y11, y22, z11, z22;
let tempX1, tempY1, tempZ1, tempX2, tempY2, tempZ2, start, end;
for (let i = 0; i < tempArray.length - 1; i++) {
start = i;
end = i + 1;
x11 = tempArray[start].x - (t.widthCanvas / 2);
x22 = tempArray[end].x - (t.widthCanvas / 2);
y11 = tempArray[start].y - (t.heightCanvas / 2);
y22 = tempArray[end].y - (t.heightCanvas / 2);
z11 = tempArray[start].z;
z22 = tempArray[end].z;
tempX1 = tempArray[start].x;
tempY1 = tempArray[start].y;
tempZ1 = tempArray[start].z;
tempX2 = tempArray[end].x;
tempY2 = tempArray[end].y;
tempZ2 = tempArray[end].z;
if (x11 > x22) {
start = i + 1;
end = i;
x11 = tempArray[start].x - (t.widthCanvas / 2);
x22 = tempArray[end].x - (t.widthCanvas / 2);
y11 = tempArray[start].y - (t.heightCanvas / 2);
y22 = tempArray[end].y - (t.heightCanvas / 2);
z11 = tempArray[start].z;
z22 = tempArray[end].z;
tempX1 = tempArray[start].x;
tempY1 = tempArray[start].y;
tempZ1 = tempArray[start].z;
tempX2 = tempArray[end].x;
tempY2 = tempArray[end].y;
tempZ2 = tempArray[end].z;
}
diffX = calculateDiffX(tempX1, tempX2, tempZ1, tempZ2, minZ, tempY1, tempY2);
let projectiveMatrix = t._getPerspectiveProjectionMatrix(1 / (t.rPerspective));
let rotatePoint1 = diffAndRotatePoint(tempArray[start]);
rotatePoint1.offset(-diffX, 0, -minZ);
rotatePoint1 = rotatePoint1.project(projectiveMatrix);
let x1 = Math.floor(rotatePoint1.x + t.widthCanvas / 2);
let rotatePoint2 = diffAndRotatePoint(tempArray[end]);
rotatePoint2.offset(-diffX, 0, -minZ);
rotatePoint2 = rotatePoint2.project(projectiveMatrix);
let x2 = Math.floor(rotatePoint2.x + t.widthCanvas / 2);
let leftMargin = x1;
let rightMargin = Math.floor(w - x2);
if (!((leftMargin >= rightMargin - 1) && (leftMargin <= rightMargin + 1))) {
continue;
}
let isTrue = true;
for (let l = 0; l < tempArray.length - 1; l++) {
let rotatePoint = diffAndRotatePoint(tempArray[l]);
rotatePoint.offset(-diffX, 0, -minZ);
rotatePoint = rotatePoint.project(projectiveMatrix);
let tempX11 = Math.floor(rotatePoint.x + t.widthCanvas / 2);
if (x1 < x2) {
if (tempX11 < x1 || tempX11 > x2) {
isTrue = false;
break;
}
} else {
if (tempX11 > x1 || tempX11 < x2) {
isTrue = false;
break;
}
}
}
if (isTrue) {
break;
}
}
return {
diffX: diffX, tempX1: tempX1, tempY1: tempY1, tempZ1: tempZ1, tempX2: tempX2, tempY2: tempY2, tempZ2: tempZ2, x11: x11, z11: z11, x22: x22, z22: z22, y11: y11, y22: y22
};
};
Processor3D.prototype._getMinMaxOyPoints = function (points, minZ) {
let fov = 1 / this.rPerspective;
let t = this;
let h = t.heightCanvas;
let calculateDiffY = function (x1, x2, y1, y2, z1, z2, minZ) {
//let cos1 = Math.cos(-t.angleOy);
//let sin1 = Math.sin(-t.angleOy);
let diffY = 0;
let diffAndScalePoints = t.diffAndScale(x1, y1, z1);
x1 = diffAndScalePoints.x;
y1 = diffAndScalePoints.y;
z1 = diffAndScalePoints.z;
let rotatePoints = t.rotate(x1, y1, z1);
let a1 = rotatePoints.y;
//let y1S = (a1 - diffY);
let z1S = rotatePoints.z + minZ;
//let x1SS = (fov * y1S / (z1S + fov)) + h / 2;
diffAndScalePoints = t.diffAndScale(x2, y2, z2);
x2 = diffAndScalePoints.x;
y2 = diffAndScalePoints.y;
z2 = diffAndScalePoints.z;
rotatePoints = t.rotate(x2, y2, z2);
let a2 = rotatePoints.y;
//let y2S = (a2 - diffY);
let z2S = rotatePoints.z + minZ;
//let x2SS = (fov * y2S / (z2S + fov)) + h / 2;
//let topMargin = (fov * y1S / (z1S + fov)) + h / 2;
//let bottomMargin = h - ((fov * y2S / (z2S + fov)) + h / 2);
//((a1 - diffY) / (z1S + fov)) = - (((a2 - diffY) / (z2S + fov)))
/*(a1 - diffY) * (z2S + fov) = -(z1S + fov) * (a2 - diffY)
a1 * z2S + a1 * fov - diffY * z2S - diffY * fov = -z1S * a2 + z1S * diffY - fov * a2 + fov * diffY
a1 * z2S + a1 * fov + fov * a2 + z1S * a2= diffY * z2S + diffY * fov + z1S * diffY + fov * diffY*/
diffY = (a1 * z2S + a1 * fov + fov * a2 + z1S * a2) / (z2S + fov + z1S + fov);
//let diffY = (-a1 * z2S - a1 * fov - a2 * z1S -a2 * fov) / ( -z2S - fov - z1S - fov);
return diffY;
};
let tempArray = this._getArrayAllVergeCube(points);
let diffY;
let tempX1, tempY1, tempZ1, tempX2, tempY2, tempZ2;
for (let i = 0; i < tempArray.length - 1; i++) {
let start = i;
let end = i + 1;
tempX1 = tempArray[start].x;
tempY1 = tempArray[start].y;
tempZ1 = tempArray[start].z;
tempX2 = tempArray[end].x;
tempY2 = tempArray[end].y;
tempZ2 = tempArray[end].z;
if (tempY1 > tempY2) {
start = i + 1;
end = i;
tempX1 = tempArray[start].x;
tempY1 = tempArray[start].y;
tempZ1 = tempArray[start].z;
tempX2 = tempArray[end].x;
tempY2 = tempArray[end].y;
tempZ2 = tempArray[end].z;
}
diffY = calculateDiffY(tempX1, tempX2, tempY1, tempY2, tempZ1, tempZ2, minZ);
let rotatePoint1 = this.calculatePointManual(tempX1, tempY1, tempZ1, this.cameraDiffX, -diffY, minZ);
let y1 = rotatePoint1.y;
let rotatePoint2 = this.calculatePointManual(tempX2, tempY2, tempZ2, this.cameraDiffX, -diffY, minZ);
let y2 = rotatePoint2.y;
let topMargin = y1;
let bottomMargin = Math.floor(h - y2);
if (!((topMargin >= bottomMargin - 1) && (topMargin <= bottomMargin + 1))) {
continue;
}
let isTrue = true;
for (let l = 0; l < tempArray.length - 1; l++) {
let rotatePoint = this.calculatePointManual(tempArray[l].x, tempArray[l].y, tempArray[l].z, this.cameraDiffX, -diffY, minZ);
let tempY11 = rotatePoint.y;
if (y1 < y2) {
if (tempY11 < y1 || tempY11 > y2) {
isTrue = false;
break;
}
} else {
if (tempY11 > y1 || tempY11 < y2) {
isTrue = false;
break;
}
}
}
if (isTrue) {
break;
}
}
return {
diffY: diffY, tempX1: tempX1, tempY1: tempY1, tempZ1: tempZ1, tempX2: tempX2, tempY2: tempY2, tempZ2: tempZ2
};
};
Processor3D.prototype._getArrayAllVergeCube = function (points) {
let res = [];
res[0] = points[0];
res[1] = points[1];
res[2] = points[2];
res[3] = points[3];
res[4] = points[0];
res[5] = points[4];
res[6] = points[7];
res[7] = points[6];
res[8] = points[5];
res[9] = points[2];
res[10] = points[6];
res[11] = points[1];
res[12] = points[7];
res[13] = points[0];
res[14] = points[5];
res[15] = points[1];
res[16] = points[4];
res[17] = points[3];
res[18] = points[6];
res[19] = points[0];
res[20] = points[2];
res[21] = points[7];
res[22] = points[3];
res[23] = points[5];
res[24] = points[7];
res[25] = points[4];
res[26] = points[2];
res[27] = points[3];
res[28] = points[1];
res[29] = points[4];
res[30] = points[5];
res[31] = points[6];
res[32] = points[4];
/*for(let i = 0; i < points.length; i++)
{
for(let j = 0; j < points.length; j++)
{
res.push(points[i]);
res.push(points[j]);
}
}*/
return res;
};
Processor3D.prototype._getMinMaxOyPoints2 = function (points, minZ) {
let t = this;
let h = t.heightCanvas;
let tempArray = [];
tempArray[0] = points[0];//leftNear
tempArray[1] = points[1];//leftFar
tempArray[2] = points[2];//rightFar
tempArray[3] = points[3];//rightNear
tempArray[4] = points[4];//leftNear
tempArray[5] = points[5];//leftFar
tempArray[6] = points[6];//leftFar
tempArray[7] = points[7];//leftFar
tempArray[8] = points[4];//leftFar
tempArray[9] = points[1];//leftFar
tempArray[10] = points[3];//leftFar
tempArray[11] = points[0];//leftFar
tempArray[12] = points[7];//leftFar
tempArray[13] = points[2];//leftFar
tempArray[14] = points[0];//leftFar
tempArray[15] = points[6];//leftFar
tempArray[16] = points[5];//leftFar
tempArray[17] = points[0];//leftFar
tempArray[18] = points[4];//leftFar
let tempX1, tempY1, tempZ1, tempX2, tempY2, tempZ2;
for (let i = 0; i < tempArray.length - 1; i++) {
let start = i;
let end = i + 1;
tempX1 = tempArray[start].x;
tempY1 = tempArray[start].y;
tempZ1 = tempArray[start].z;
tempX2 = tempArray[end].x;
tempY2 = tempArray[end].y;
tempZ2 = tempArray[end].z;
if (tempY1 > tempY2) {
start = i + 1;
end = i;
tempX1 = tempArray[start].x;
tempY1 = tempArray[start].y;
tempZ1 = tempArray[start].z;
tempX2 = tempArray[end].x;
tempY2 = tempArray[end].y;
tempZ2 = tempArray[end].z;
}
//let diffY = calculateDiffY(tempX1, tempX2, tempY1, tempY2, tempZ1, tempZ2, minZ);
let correctOffset = this._correctZPositionOY(tempX1, tempX2, tempZ1, tempZ2, minZ, tempY1, tempY2);
let diffZ = correctOffset.minZ;
let diffY = correctOffset.diffY;
let rotatePoint1 = this.calculatePointManual(tempX1, tempY1, tempZ1, this.cameraDiffX, diffY, diffZ);
let y1 = rotatePoint1.y;
let rotatePoint2 = this.calculatePointManual(tempX2, tempY2, tempZ2, this.cameraDiffX, diffY, diffZ);
let y2 = rotatePoint2.y;
let topMargin = y1;
let bottomMargin = Math.floor(h - y2);
if (!((topMargin >= bottomMargin - 1) && (topMargin <= bottomMargin + 1))) {
continue;
}
let isTrue = true;
for (let l = 0; l < tempArray.length - 1; l++) {
let rotatePoint = this.calculatePointManual(tempArray[l].x, tempArray[l].y, tempArray[l].z, this.cameraDiffX, diffY, diffZ);
let tempY11 = rotatePoint.y;
if (y1 < y2) {
if (tempY11 < y1 || tempY11 > y2) {
isTrue = false;
break;
}
} else {
if (tempY11 > y1 || tempY11 < y2) {
isTrue = false;
break;
}
}
}
if (isTrue) {
break;
}
}
return {
tempX1: tempX1, tempY1: tempY1, tempZ1: tempZ1, tempX2: tempX2, tempY2: tempY2, tempZ2: tempZ2
};
};
Processor3D.prototype._correctZPosition4 = function (x1, x2, z1, z2, minZ, y1, y2) {
let t = this;
let getDiffXZ3 = function (x1, x2, z1, z2, y1, y2) {
let w = t.widthCanvas;
let fov = 1 / t.rPerspective;
let diffAndScalePoints = t.diffAndScale(x1, y1, z1);
let x11 = diffAndScalePoints.x;
let y11 = diffAndScalePoints.y;
let z11 = diffAndScalePoints.z;
let rotatePoints = t.rotate(x11, y11, z11);
let x111 = rotatePoints.x;
let z111 = rotatePoints.z;
/*let x1111 = x111 + diffX;
let y1111 = y111 + diffY;
let z1111 = z111 + diffZ;
let x11111 = (fov * x1111) / (z1111 + fov) + w / 2;
let y11111 = (fov * y1111) / (z1111 + fov) + h / 2;*/
//(fov * x1111) / (z1111 + fov) + w / 2 = t.left
//(fov * (x111 + diffX)) / ((z111 + diffZ) + fov) + w / 2 = t.left
let wL = t.left - w / 2;
//fov * (x111 + diffX) = wL * ((z111 + diffZ) + fov)
//fov * x111 + fov * diffX = wL * z111 + wL * diffZ + wL * fov
diffAndScalePoints = t.diffAndScale(x2, y2, z2);
let x22 = diffAndScalePoints.x;
let y22 = diffAndScalePoints.y;
let z22 = diffAndScalePoints.z;
rotatePoints = t.rotate(x22, y22, z22);
let x222 = rotatePoints.x;
let z222 = rotatePoints.z;
/*let x1111 = x111 + diffX;
let y1111 = y111 + diffY;
let z1111 = z111 + diffZ;
let x11111 = (fov * x1111) / (z1111 + fov) + w / 2;
let y11111 = (fov * y1111) / (z1111 + fov) + h / 2;*/
let wR = w / 2 - t.left;
//fov * (x222 + diffX) = wR * ((z222 + diffZ) + fov)
//fov * x222 + fov * diffX = wR * z222 + wR * diffZ + wR * fov
//итого
//fov * x111 + fov * diffX = wL * z111 + wL * diffZ + wL * fov
//fov * x222 + fov * diffX = wR * z222 + wR * diffZ + wR * fov
/*diffX = (wL * z111 + wL * diffZ + wL * fov - fov * x111) / fov;
fov * x222 + wL * z111 + wL * diffZ + wL * fov - fov * x111 = wR * z222 + wR * diffZ + wR * fov
fov * x222 + wL * z111 + wL * fov - fov * x111 - wR * z222 - wR * fov = wR * diffZ - wL * diffZ*/
let diffZ = (fov * x222 + wL * z111 + wL * fov - fov * x111 - wR * z222 - wR * fov) / (wR - wL);
let diffX = (wL * z111 + wL * diffZ + wL * fov - fov * x111) / fov;
return {minZ: diffZ, diffX: diffX};
};
let diffXZ3 = getDiffXZ3(x1, x2, z1, z2, y1, y2);
return {minZ: diffXZ3.minZ, diffX: diffXZ3.diffX};
};
Processor3D.prototype._correctZPositionOY = function (x1, x2, z1, z2, minZ, y1, y2) {
let t = this;
let getDiffXZ3 = function (x1, x2, z1, z2, y1, y2) {
let h = t.heightCanvas;
let fov = 1 / t.rPerspective;
let diffAndScalePoints = t.diffAndScale(x1, y1, z1);
let x11 = diffAndScalePoints.x;
let y11 = diffAndScalePoints.y;
let z11 = diffAndScalePoints.z;
let rotatePoints = t.rotate(x11, y11, z11);
let y111 = rotatePoints.y;
let z111 = rotatePoints.z;
/*let x1111 = x111 + diffX;
let y1111 = y111 + diffY;
let z1111 = z111 + diffZ;
let x11111 = (fov * x1111) / (z1111 + fov) + w / 2;
let y11111 = (fov * y1111) / (z1111 + fov) + h / 2;*/
//(fov * x1111) / (z1111 + fov) + w / 2 = t.left
//(fov * (x111 + diffX)) / ((z111 + diffZ) + fov) + w / 2 = t.left
//let wL = t.left - w / 2;
//fov * (x111 + diffX) = wL * ((z111 + diffZ) + fov)
//fov * x111 + fov * diffX = wL * z111 + wL * diffZ + wL * fov
diffAndScalePoints = t.diffAndScale(x2, y2, z2);
let x22 = diffAndScalePoints.x;
let y22 = diffAndScalePoints.y;
let z22 = diffAndScalePoints.z;
rotatePoints = t.rotate(x22, y22, z22);
let y222 = rotatePoints.y;
let z222 = rotatePoints.z;
/*let x1111 = x111 + diffX;
let y1111 = y111 + diffY;
let z1111 = z111 + diffZ;
let x11111 = (fov * x1111) / (z1111 + fov) + w / 2;
let y11111 = (fov * y1111) / (z1111 + fov) + h / 2;*/
//(fov * (y111 + diffY)) / ((z111 + diffZ) + fov) + h / 2 = t.top
//(fov * (y222 + diffY)) / ((z222 + diffZ) + fov) + h / 2 = h - t.bottom
let wL = t.top - h / 2;
let wR = h / 2 - t.bottom;
/*(fov * (y111 + diffY)) / ((z111 + diffZ) + fov) = wL
(fov * (y222 + diffY)) / ((z222 + diffZ) + fov) = wR
fov * (y111 + diffY) = wL * ((z111 + diffZ) + fov)
fov * y111 + fov * diffY = wL * z111 + wL * diffZ + wL * fov
fov * y222 + fov * diffY = wR * z222 + wR * diffZ + wR * fov
diffY = (wR * z222 + wR * diffZ + wR * fov - fov * y222) / fov
fov * y111 + wR * z222 + wR * diffZ + wR * fov - fov * y222 = wL * z111 + wL * diffZ + wL * fov
fov * y111 + wR * z222 + wR * fov - fov * y222 - wL * z111 - wL * fov = wL * diffZ - wR * diffZ*/
let diffZ = (fov * y111 + wR * z222 + wR * fov - fov * y222 - wL * z111 - wL * fov) / (wL - wR);
let diffY = (wR * z222 + wR * diffZ + wR * fov - fov * y222) / fov;
//let diffZ = (fov * x222 + wL * z111 + wL * fov - fov * x111 - wR * z222 - wR * fov) / (wR - wL);
//let diffX = (wL * z111 + wL * diffZ + wL * fov - fov * x111) / fov;
return {minZ: diffZ, diffY: diffY};
};
let diffXZ3 = getDiffXZ3(x1, x2, z1, z2, y1, y2);
return {minZ: diffXZ3.minZ, diffY: diffXZ3.diffY};
};
Processor3D.prototype._calculateCameraDiffX = function (minMaxOx) {
//test ровно по центру, но циклом
let maxLeftPoint = minMaxOx.left;
let maxRightPoint = minMaxOx.right;
//так ближе к тому, как смещает excel
let widthCanvas = this.widthCanvas;
let originalWidthChart = widthCanvas - this.left - this.right;
let diffLeft = maxLeftPoint - this.left;
let diffRight = (this.left + originalWidthChart) - maxRightPoint;
this.cameraDiffX = (((diffRight - diffLeft) / 2) * (1 / (this.rPerspective) + this.cameraDiffZ)) / (1 / (this.rPerspective));
};
Processor3D.prototype._calculateCameraDiffY = function (maxTopPoint, maxBottomPoint) {
let top = this.top;
let bottom = this.bottom;
let heightCanvas = this.heightCanvas;
let heightChart = heightCanvas - top - bottom;
let diffTop = maxTopPoint - top;
let diffBottom = (heightChart + top) - maxBottomPoint;
//this.cameraDiffY = this.top - minMaxOy.top; - для rAngAx
this.cameraDiffY = (diffBottom - diffTop) / 2;
};
Processor3D.prototype._getMinMaxOx = function (points, faces) {
let mostLeftPointX;
let mostRightPointX;
let xRight;
let xLeft;
for (let i = 0; i < faces.length - 1; i++) {
for (let k = 0; k <= 3; k++) {
let point1 = this.convertAndTurnPoint(points[faces[i][k]].x, points[faces[i][k]].y, points[faces[i][k]].z);
//let point2 = this.convertAndTurnPoint(points[faces[i][k + 1]].x, points[faces[i][k + 1]].y, points[faces[i][k + 1]].z, true);
let x1 = point1.x;
//let x2 = point2.x;
if (!xLeft) {
xLeft = x1;
mostLeftPointX = new Point3D(points[faces[i][k]].x, points[faces[i][k]].y, points[faces[i][k]].z, this.cChartDrawer);
xRight = x1;
mostRightPointX = new Point3D(points[faces[i][k]].x, points[faces[i][k]].y, points[faces[i][k]].z, this.cChartDrawer);
} else {
if (x1 < xLeft) {
xLeft = x1;
mostLeftPointX = new Point3D(points[faces[i][k]].x, points[faces[i][k]].y, points[faces[i][k]].z, this.cChartDrawer);
}
if (x1 > xRight) {
xRight = x1;
mostRightPointX = new Point3D(points[faces[i][k]].x, points[faces[i][k]].y, points[faces[i][k]].z, this.cChartDrawer);
}
}
}
}
return {left: xLeft, right: xRight, mostLeftPointX: mostLeftPointX, mostRightPointX: mostRightPointX};
};
Processor3D.prototype._getMinMaxOy = function (points, faces) {
let mostTopPointY;
let mostBottomPointY;
let xTop = this.top + this.heightCanvas;
let xBottom = 0;
for (let i = 0; i < faces.length - 1; i++) {
for (let k = 0; k < 3; k++) {
let point1 = this.convertAndTurnPoint(points[faces[i][k]].x, points[faces[i][k]].y, points[faces[i][k]].z);
let point2 = this.convertAndTurnPoint(points[faces[i][k + 1]].x, points[faces[i][k + 1]].y, points[faces[i][k + 1]].z);
let y1 = point1.y;
let y2 = point2.y;
if (y1 <= xTop) {
xTop = y1;
mostTopPointY = new Point3D(points[faces[i][k]].x, points[faces[i][k]].y, points[faces[i][k]].z, this.cChartDrawer);
}
if (y2 <= xTop) {
xTop = y2;
mostTopPointY = new Point3D(points[faces[i][k + 1]].x, points[faces[i][k + 1]].y, points[faces[i][k + 1]].z, this.cChartDrawer);
}
if (y1 >= xBottom) {
xBottom = y1;
mostBottomPointY = new Point3D(points[faces[i][k]].x, points[faces[i][k]].y, points[faces[i][k]].z, this.cChartDrawer);
}
if (y2 >= xBottom) {
xBottom = y2;
mostBottomPointY = new Point3D(points[faces[i][k + 1]].x, points[faces[i][k + 1]].y, points[faces[i][k + 1]].z, this.cChartDrawer);
}
}
}
return {top: xTop, bottom: xBottom, mostTopPointY: mostTopPointY, mostBottomPointY: mostBottomPointY};
};
Processor3D.prototype._calcAspectRatio = function () {
//return width / height
let widthOriginalChart = this.widthCanvas - (this.left + this.right);
let heightOriginalChart = this.heightCanvas - (this.top + this.bottom);
//auto scale if hPercent == null
let hPercent = this.hPercent;
let depthPercent = this._getDepthPercent();
let aspectRatioX = 1;
let aspectRatioY = 1;
let countSeries = this.chartsDrawer.calculateFirstChartCountSeries();
let seriesCount = countSeries.series;
let ptCount = countSeries.points;
let subType = this.chartsDrawer.calcProp.subType;
if ((subType === "standard" || this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.Line ||
(this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.Area && subType === "normal") || this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.Surface) &&
!this.view3D.getRAngAx()) {
this._calcSpecialStandardScaleX();
aspectRatioX = (widthOriginalChart / (heightOriginalChart / hPercent)) * this.specialStandardScaleX;
} else if (subType === "standard" || this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.Line || this.chartsDrawer.calcProp.type ===
AscFormat.c_oChartTypes.Surface) {
let depth = this.view3D.getRAngAx() ? this._calculateDepth() : this._calculateDepthPerspective();
let width = (depth / depthPercent) * (ptCount / seriesCount);
aspectRatioX = (widthOriginalChart) / width;
} else if (hPercent !== null)//auto scale height
{
aspectRatioX = widthOriginalChart / (heightOriginalChart / hPercent);
}
if (aspectRatioX < 1 && this.view3D.getRAngAx()) {
aspectRatioY = 1 / aspectRatioX;
aspectRatioX = 1;
}
this.aspectRatioX = aspectRatioX;
this.aspectRatioY = aspectRatioY;
};
Processor3D.prototype._getDepthPercent = function () {
if (AscFormat.c_oChartTypes.Pie === this.chartsDrawer.calcProp.type) {
return globalBasePercent / 100;
}
return this.view3D && this.view3D.depthPercent ? this.view3D.depthPercent / 100 : globalBasePercent / 100;
};
function Point3D(x, y, z, chartsDrawer) {
this.x = x;
this.y = y;
this.z = z;
this.t = 1;
if (chartsDrawer) {
this.chartProp = chartsDrawer.calcProp;
this.cChartDrawer = chartsDrawer;
this.cChartSpace = chartsDrawer.cChartSpace;
}
}
Point3D.prototype = {
constructor: Point3D,
rotate: function (angleOx, angleOy, angleOz) {
let x = this.x;
let y = this.y;
let z = this.z;
let cosy = Math.cos(angleOy);
let siny = Math.sin(angleOy);
let cosx = Math.cos(angleOx);
let sinx = Math.sin(angleOx);
let cosz = Math.cos(angleOz);
let sinz = Math.sin(angleOz);
let newX = cosy * (sinz * y + cosz * x) - siny * z;
let newY = sinx * (cosy * z + siny * (sinz * y + cosz * x)) + cosx * (cosz * y - sinz * x);
let newZ = cosx * (cosy * z + siny * (sinz * y + cosz * x)) - sinx * (cosz * y - sinz * x);
this.x = newX;
this.y = newY;
this.z = newZ;
return this;
},
project: function (matrix) {
//умножаем
let projectPoint = matrix.multiplyPoint(this);
//делим на 4 коэффициэнт
let newX = projectPoint.x / projectPoint.t;
let newY = projectPoint.y / projectPoint.t;
this.x = newX;
this.y = newY;
return this;
},
offset: function (offsetX, offsetY, offsetZ) {
this.x = this.x + offsetX;
this.y = this.y + offsetY;
this.z = this.z + offsetZ;
return this;
},
scale: function (aspectRatioOx, aspectRatioOy, aspectRatioOz) {
this.x = this.x / aspectRatioOx;
this.y = this.y / aspectRatioOy;
this.z = this.z / aspectRatioOz;
return this;
},
multiplyPointOnMatrix1: function (matrix) {
let multiplyMatrix = matrix.multiplyPoint(this);
this.x = multiplyMatrix.x;
this.y = multiplyMatrix.y;
this.z = multiplyMatrix.z;
}
};
function Matrix4D() {
this.a11 = 1.0;
this.a12 = 0.0;
this.a13 = 0.0;
this.a14 = 0.0;
this.a21 = 0.0;
this.a22 = 1.0;
this.a23 = 0.0;
this.a24 = 0.0;
this.a31 = 0.0;
this.a32 = 0.0;
this.a33 = 1.0;
this.a34 = 0.0;
this.a41 = 0.0;
this.a42 = 0.0;
this.a43 = 0.0;
this.a44 = 1.0;
return this;
}
Matrix4D.prototype.reset = function () {
this.a11 = 1.0;
this.a12 = 0.0;
this.a13 = 0.0;
this.a14 = 0.0;
this.a21 = 0.0;
this.a22 = 1.0;
this.a23 = 0.0;
this.a24 = 0.0;
this.a31 = 0.0;
this.a32 = 0.0;
this.a33 = 1.0;
this.a34 = 0.0;
this.a41 = 0.0;
this.a42 = 0.0;
this.a43 = 0.0;
this.a44 = 1.0;
};
Matrix4D.prototype.multiply = function (m) {
let res = new Matrix4D();
res.a11 = this.a11 * m.a11 + this.a12 * m.a21 + this.a13 * m.a31 + this.a14 * m.a41;
res.a12 = this.a11 * m.a12 + this.a12 * m.a22 + this.a13 * m.a32 + this.a14 * m.a42;
res.a13 = this.a11 * m.a13 + this.a12 * m.a23 + this.a13 * m.a33 + this.a14 * m.a43;
res.a14 = this.a11 * m.a14 + this.a12 * m.a24 + this.a13 * m.a34 + this.a14 * m.a44;
res.a21 = this.a21 * m.a11 + this.a22 * m.a21 + this.a23 * m.a31 + this.a24 * m.a41;
res.a22 = this.a21 * m.a12 + this.a22 * m.a22 + this.a23 * m.a32 + this.a24 * m.a42;
res.a23 = this.a21 * m.a13 + this.a22 * m.a23 + this.a23 * m.a33 + this.a24 * m.a43;
res.a24 = this.a21 * m.a14 + this.a22 * m.a24 + this.a23 * m.a34 + this.a24 * m.a44;
res.a31 = this.a31 * m.a11 + this.a32 * m.a21 + this.a33 * m.a31 + this.a34 * m.a41;
res.a32 = this.a31 * m.a12 + this.a32 * m.a22 + this.a33 * m.a32 + this.a34 * m.a42;
res.a33 = this.a31 * m.a13 + this.a32 * m.a23 + this.a33 * m.a33 + this.a34 * m.a43;
res.a34 = this.a31 * m.a14 + this.a32 * m.a24 + this.a33 * m.a34 + this.a34 * m.a44;
res.a41 = this.a41 * m.a11 + this.a42 * m.a21 + this.a43 * m.a31 + this.a44 * m.a41;
res.a42 = this.a41 * m.a12 + this.a42 * m.a22 + this.a43 * m.a32 + this.a44 * m.a42;
res.a43 = this.a41 * m.a13 + this.a42 * m.a23 + this.a43 * m.a33 + this.a44 * m.a43;
res.a44 = this.a41 * m.a14 + this.a42 * m.a24 + this.a43 * m.a34 + this.a44 * m.a44;
return res;
};
Matrix4D.prototype.multiplyPoint = function (p) {
let res = new Point3D();
res.x = p.x * this.a11 + p.y * this.a21 + p.z * this.a31 + this.a41;
res.y = p.x * this.a12 + p.y * this.a22 + p.z * this.a32 + this.a42;
res.z = p.x * this.a13 + p.y * this.a23 + p.z * this.a33 + this.a43;
res.t = p.x * this.a14 + p.y * this.a24 + p.z * this.a34 + this.a44;
return res;
};
//sort parallalepiped faces
function CSortFaces(cChartDrawer, centralViewPoint) {
this.cChartDrawer = cChartDrawer;
this.chartProp = cChartDrawer.calcProp;
this.centralViewPoint = null;
this._initProperties(centralViewPoint)
}
CSortFaces.prototype = {
constructor: CSortFaces,
_initProperties: function (centralViewPoint) {
if (!centralViewPoint) {
let top = this.chartProp.chartGutter._top;
let bottom = this.chartProp.chartGutter._bottom;
let left = this.chartProp.chartGutter._left;
let right = this.chartProp.chartGutter._right;
let widthCanvas = this.chartProp.widthCanvas;
let heightCanvas = this.chartProp.heightCanvas;
let heightChart = heightCanvas - top - bottom;
let widthChart = widthCanvas - left - right;
let centerChartY = top + heightChart / 2;
let centerChartX = left + widthChart / 2;
let diffX = centerChartX;
let diffY = centerChartY;
let diffZ = -1 / this.cChartDrawer.processor3D.rPerspective;
//TODO протестировать на bar и затем сделать для всех перспективных диаграмм данный сдвиг
if (!this.cChartDrawer.processor3D.view3D.getRAngAx() && this.chartProp.type === AscFormat.c_oChartTypes.Bar) {
diffX -= this.cChartDrawer.processor3D.cameraDiffX;
diffY -= this.cChartDrawer.processor3D.cameraDiffY;
diffZ -= this.cChartDrawer.processor3D.cameraDiffZ;
}
//TODO пересмотреть правку!
if (diffZ > 0 && this.chartProp.type === AscFormat.c_oChartTypes.Bar && this.cChartDrawer.processor3D.view3D.getRAngAx() &&
(this.chartProp.subType === "stackedPer" || this.chartProp.subType === "stacked")) {
diffZ -= 500;
}
this.centralViewPoint = {x: diffX, y: diffY, z: diffZ};
} else {
this.centralViewPoint = centralViewPoint;
}
},
sortParallelepipeds: function (parallelepipeds) {
if (!parallelepipeds) {
return null;
}
let intersectionsParallelepipeds = this._getIntersectionsParallelepipeds(parallelepipeds);
let revIntersections = intersectionsParallelepipeds.reverseIntersections;
let countIntersection = intersectionsParallelepipeds.countIntersection;
let startIndexes = [];
for (let i = 0; i < countIntersection.length; i++) {
if (countIntersection[i] === 0) {
startIndexes.push({index: parseInt(i)});
}
}
if (startIndexes.length === 0) {
//TODO сделано для графиков типа stacked, когда пересечения найдены всех параллалеп.
return this._getSortZIndexArray(parallelepipeds);
}
let g = revIntersections;
let color = {}; // цвет вершины (0, 1, или 2)
let time_in = {}, time_out = {}; // "времена" захода и выхода из вершины
let dfs_timer = 0;
let dfs = function (v) {
time_in[v] = dfs_timer++;
color[v] = 1;
for (let i in g[v]) {
if (!color[i]) {
dfs(i);
}
}
color[v] = 2;
time_out[v] = dfs_timer++;
};
let getMax = function () {
let max = 0;
let res = null;
for (let i in time_out) {
if (!addIndexes[i] && time_out[i] > max) {
max = time_out[i];
res = i;
}
}
return res;
};
for (let i = 0; i < startIndexes.length; i++) {
dfs(startIndexes[i].index);
}
let addIndexes = {};
let res = [];
while (true) {
let index = getMax();
if (null === index) {
break;
}
res.push({nextIndex: index});
addIndexes[index] = 1;
}
if (res.length < parallelepipeds.length) {
return this._getSortZIndexArray(parallelepipeds);
}
return res.reverse();
},
_getSortZIndexArray: function (arr) {
arr.sort(function sortArr(a, b) {
return b.z - a.z;
});
let result = [];
for (let i = 0; i < arr.length; i++) {
result.push({nextIndex: i});
}
return result;
},
_getIntersectionsParallelepipeds: function (parallelepipeds) {
//TODO нужно по максимуму оптимизировать, при большом количестве значений работает медленно
let usuallyIntersect = {};
let usuallyIntersectRev = {};
let intersections = [];
let reverseIntersections = [];
let countIntersection = [];
for (let i = 0; i < parallelepipeds.length; i++) {
//из каждой точки данного параллалепипеда строим прямые до точки наблюдателя
let fromParallalepiped = parallelepipeds[i];
countIntersection[i] = 0;
for (let m = 0; m < parallelepipeds.length; m++) {
if (m === i || usuallyIntersect[i] === m || usuallyIntersectRev[i] === m) {
continue;
}
if (parallelepipeds[m].isValZero && this.cChartDrawer.calcProp.subType !== "normal") {
continue;
}
for (let l = 0; l < fromParallalepiped.arrPoints.length; l++) {
//перебираем точки параллалепипеда FROM
let point = fromParallalepiped.arrPoints[l];
//перебираем грани параллалепипеда TO и проверяем на пересечения с прямыми из параллалепипеда FROM
let toParallalepiped = parallelepipeds[m];
for (let n = 0; n < toParallalepiped.faces.length; n++) {
let toVerge = toParallalepiped.faces[n];
let lineEqucation = this.cChartDrawer.getLineEquation(point, this.centralViewPoint);
let intersection = this._isIntersectionFaceAndLine(toVerge, lineEqucation, point);
if (intersection) {
usuallyIntersect[i] = m;
usuallyIntersectRev[m] = i;
if (!intersections[i]) {
intersections[i] = [];
}
if (!reverseIntersections[m]) {
reverseIntersections[m] = [];
}
countIntersection[i]++;
intersections[i][m] = 1;
reverseIntersections[m][i] = 1;
l = point.length;
//console.log("fromParallalepiped: " + i + " toParallalepiped " + m + " x: " + intersection.x + " y: " + intersection.y + " z: " + intersection.z);
break;
}
}
}
}
}
return {
intersections: intersections, reverseIntersections: reverseIntersections, countIntersection: countIntersection
};
},
//смотрим есть ли пересечения точек, выходящих из вершин данной грани, с другими гранями
_isIntersectionFacesPointLines: function (plainVerge, i, sortZIndexPaths) {
let res = false;
let t = this;
for (let j = 0; j < plainVerge.points.length; j++) {
let pointFromVerge = plainVerge.points[j];
let lineEqucation = t.cChartDrawer.getLineEquation(pointFromVerge, this.centralViewPoint);
//пересечение грани и прямой
if (t._isIntersectionFacesAndLine(lineEqucation, pointFromVerge, i, j, sortZIndexPaths)) {
res = true;
break;
}
}
return res;
},
//пересечение прямой с другими гранями
_isIntersectionFacesAndLine: function (lineEqucation, pointFromVerge, i, j, sortZIndexPaths) {
let res = false;
for (let k = 0; k < sortZIndexPaths.length; k++) {
if (k === i) {
continue;
}
if (this._isIntersectionFaceAndLine(sortZIndexPaths[k], lineEqucation, pointFromVerge, i, j, k)) {
res = true;
break;
}
}
return res;
},
//пересечение прямой гранью
_isIntersectionFaceAndLine: function (plain, lineEquation, pointFromVerge) {
let res = false;
let t = this;
//get intersection
let nIntersectionPlainAndLine = t.cChartDrawer.isIntersectionPlainAndLine(plain.plainEquation, lineEquation);
if (null === nIntersectionPlainAndLine) {
return res;
}
let iSX = nIntersectionPlainAndLine.x;
let iSY = nIntersectionPlainAndLine.y;
let iSZ = nIntersectionPlainAndLine.z;
if (Math.round(iSZ * 1000) / 1000 < Math.round(pointFromVerge.z * 1000) / 1000) {
let minMaxpoints = t.cChartDrawer.getMinMaxPoints(plain.points);
let minX = minMaxpoints.minX, maxX = minMaxpoints.maxX, minY = minMaxpoints.minY, maxY = minMaxpoints.maxY, minZ = minMaxpoints.minZ, maxZ = minMaxpoints.maxZ;
let isBeetwenX = t._isBetweenPoint(iSX, minX, maxX);
let isBeetwenY = t._isBetweenPoint(iSY, minY, maxY);
let isBeetwenZ = t._isBetweenPoint(iSZ, minZ, maxZ);
if (isBeetwenX && isBeetwenY && isBeetwenZ) {
let point0 = plain.points2[0];
let point1 = plain.points2[1];
let point2 = plain.points2[2];
let point3 = plain.points2[3];
let projectIntersection = nIntersectionPlainAndLine;
if (!this.cChartDrawer.processor3D.view3D.getRAngAx()) {
projectIntersection =
t.cChartDrawer._convertAndTurnPoint(nIntersectionPlainAndLine.x, nIntersectionPlainAndLine.y, nIntersectionPlainAndLine.z, true, true);
}
let areaQuadrilateral = plain.plainArea;
let areaTriangle1 = t.cChartDrawer.getAreaTriangle(point0, projectIntersection, point1);
let areaTriangle2 = t.cChartDrawer.getAreaTriangle(point1, projectIntersection, point2);
let areaTriangle3 = t.cChartDrawer.getAreaTriangle(point2, projectIntersection, point3);
let areaTriangle4 = t.cChartDrawer.getAreaTriangle(point3, projectIntersection, point0);
if (parseInt(areaQuadrilateral) === parseInt(areaTriangle1 + areaTriangle2 + areaTriangle3 + areaTriangle4)) {
//let pointFromVergeProject = t.cChartDrawer._convertAndTurnPoint(pointFromVerge.x, pointFromVerge.y, pointFromVerge.z, true, true);
//console.log("x: " + projectIntersection.x + " ;y: " + projectIntersection.y + " ;fromX:" + pointFromVergeProject.x + " ;fromY:" + pointFromVergeProject.y);
res = nIntersectionPlainAndLine;
}
}
}
return res;
},
_isBetweenPoint: function (point, start, end) {
//TODO округление пересмотреть
let res = false;
point = Math.round(point * 100) / 100;
start = Math.round(start * 100) / 100;
end = Math.round(end * 100) / 100;
if (point >= start && point <= end) {
res = true;
}
return res;
},
_isEqualPoints: function (point1, point2) {
//TODO округление пересмотреть
let res = false;
if (parseInt(point1.x) === parseInt(point2.x) && parseInt(point1.y) === parseInt(point2.y) && parseInt(point1.y) === parseInt(point2.y)) {
res = true;
}
return res;
}
};
//----------------------------------------------------------export----------------------------------------------------
window['AscFormat'] = window['AscFormat'] || {};
window['AscFormat'].Processor3D = Processor3D;
window['AscFormat'].Point3D = Point3D;
window['AscFormat'].CSortFaces = CSortFaces;
window['AscFormat'].global3DPersperctive = global3DPersperctive;
window['AscFormat'].globalBasePercent = globalBasePercent;
window['AscCommon'].c_oChartFloorPosition = c_oChartFloorPosition;
})(window);