@itwin/core-frontend
Version:
iTwin.js frontend components
197 lines • 9 kB
JavaScript
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
* @module Rendering
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.tesselatePolylineList = tesselatePolylineList;
exports.tesselatePolyline = tesselatePolyline;
exports.createPolylineParams = createPolylineParams;
exports.wantJointTriangles = wantJointTriangles;
const core_common_1 = require("@itwin/core-common");
const VertexIndices_1 = require("./VertexIndices");
const core_geometry_1 = require("@itwin/core-geometry");
const core_bentley_1 = require("@itwin/core-bentley");
const VertexTableBuilder_1 = require("./VertexTableBuilder");
function tesselatePolylineList(args) {
const tesselator = PolylineTesselator.create(args);
return tesselator.tesselate();
}
class PolylineVertex {
isSegmentStart = false;
isPolylineStartOrEnd = false;
vertexIndex = 0;
prevIndex = 0;
nextIndex = 0;
constructor() { }
init(isSegmentStart, isPolylineStartOrEnd, vertexIndex, prevIndex, nextIndex) {
this.isSegmentStart = isSegmentStart;
this.isPolylineStartOrEnd = isPolylineStartOrEnd;
this.vertexIndex = vertexIndex;
this.prevIndex = prevIndex;
this.nextIndex = nextIndex;
}
computeParam(negatePerp, adjacentToJoint = false, joint = false, noDisplacement = false) {
if (joint)
return 12 /* PolylineParam.kJointBase */;
let param;
if (noDisplacement)
param = 96 /* PolylineParam.kNoneAdjustWeight */; // prevent getting tossed before width adjustment
else if (adjacentToJoint)
param = 9 /* PolylineParam.kMiterInsideOnly */;
else
param = this.isPolylineStartOrEnd ? 3 /* PolylineParam.kSquare */ : 6 /* PolylineParam.kMiter */;
let adjust = 0;
if (negatePerp)
adjust = 24 /* PolylineParam.kNegatePerp */;
if (!this.isSegmentStart)
adjust += 48 /* PolylineParam.kNegateAlong */;
return param + adjust;
}
}
class PolylineTesselator {
_polylines;
_doJoints;
_numIndices = 0;
_vertIndex = [];
_prevIndex = [];
_nextIndex = [];
_nextParam = [];
_position = [];
constructor(polylines, points, doJointTriangles) {
this._polylines = polylines;
if (points instanceof core_common_1.QPoint3dList) {
for (const p of points.list)
this._position.push(p.unquantize(points.params));
}
else {
this._position = points;
}
this._doJoints = doJointTriangles;
}
static fromPolyline(args) {
return new PolylineTesselator(args.polylines, args.points, wantJointTriangles(args.width, !!args.flags.is2d));
}
static create(args) {
return new PolylineTesselator(args.polylines.map((x) => x.indices), args.points, wantJointTriangles(args.width, args.is2d));
}
tesselate() {
this._tesselate();
const vertIndex = VertexIndices_1.VertexIndices.fromArray(this._vertIndex);
const prevIndex = VertexIndices_1.VertexIndices.fromArray(this._prevIndex);
const nextIndexAndParam = new Uint8Array(this._numIndices * 4);
for (let i = 0; i < this._numIndices; i++) {
const index = this._nextIndex[i];
const j = i * 4;
VertexIndices_1.VertexIndices.encodeIndex(index, nextIndexAndParam, j);
nextIndexAndParam[j + 3] = this._nextParam[i] & 0x000000ff;
}
return {
indices: vertIndex,
prevIndices: prevIndex,
nextIndicesAndParams: nextIndexAndParam,
};
}
_tesselate() {
const v0 = new PolylineVertex(), v1 = new PolylineVertex();
const maxJointDot = -0.7;
for (const line of this._polylines) {
if (line.length < 2)
continue;
const last = line.length - 1;
const isClosed = line[0] === line[last];
for (let i = 0; i < last; ++i) {
const idx0 = line[i];
const idx1 = line[i + 1];
const isStart = (0 === i);
const isEnd = (last - 1 === i);
const prevIdx0 = isStart ? (isClosed ? line[last - 1] : idx0) : line[i - 1];
const nextIdx1 = isEnd ? (isClosed ? line[1] : idx1) : line[i + 2];
v0.init(true, isStart && !isClosed, idx0, prevIdx0, idx1);
v1.init(false, isEnd && !isClosed, idx1, nextIdx1, idx0);
const jointAt0 = this._doJoints && (isClosed || !isStart) && this._dotProduct(v0) > maxJointDot;
const jointAt1 = this._doJoints && (isClosed || !isEnd) && this._dotProduct(v1) > maxJointDot;
if (jointAt0 || jointAt1) {
this._addVertex(v0, v0.computeParam(true, jointAt0, false, false));
this._addVertex(v1, v1.computeParam(false, jointAt1, false, false));
this._addVertex(v0, v0.computeParam(false, jointAt0, false, true));
this._addVertex(v0, v0.computeParam(false, jointAt0, false, true));
this._addVertex(v1, v1.computeParam(false, jointAt1, false, false));
this._addVertex(v1, v1.computeParam(false, jointAt1, false, true));
this._addVertex(v0, v0.computeParam(false, jointAt0, false, true));
this._addVertex(v1, v1.computeParam(false, jointAt1, false, true));
this._addVertex(v0, v0.computeParam(false, jointAt0, false, false));
this._addVertex(v0, v0.computeParam(false, jointAt0, false, false));
this._addVertex(v1, v1.computeParam(false, jointAt1, false, true));
this._addVertex(v1, v1.computeParam(true, jointAt1, false, false));
if (jointAt0)
this.addJointTriangles(v0, v0.computeParam(false, true, false, true), v0);
if (jointAt1)
this.addJointTriangles(v1, v1.computeParam(false, true, false, true), v1);
}
else {
this._addVertex(v0, v0.computeParam(true));
this._addVertex(v1, v1.computeParam(false));
this._addVertex(v0, v0.computeParam(false));
this._addVertex(v0, v0.computeParam(false));
this._addVertex(v1, v1.computeParam(false));
this._addVertex(v1, v1.computeParam(true));
}
}
}
}
addJointTriangles(v0, p0, v1) {
const param = v1.computeParam(false, false, true);
for (let i = 0; i < 3; i++) {
this._addVertex(v0, p0);
this._addVertex(v1, param + i + 1);
this._addVertex(v1, param + i);
}
}
_dotProduct(v) {
const pos = this._position[v.vertexIndex];
const prevDir = core_geometry_1.Vector3d.createStartEnd(this._position[v.prevIndex], pos);
const nextDir = core_geometry_1.Vector3d.createStartEnd(this._position[v.nextIndex], pos);
return prevDir.dotProduct(nextDir);
}
_addVertex(vertex, param) {
this._vertIndex[this._numIndices] = vertex.vertexIndex;
this._prevIndex[this._numIndices] = vertex.prevIndex;
this._nextIndex[this._numIndices] = vertex.nextIndex;
this._nextParam[this._numIndices] = param;
this._numIndices++;
}
}
/** Strictly for tests. @internal */
function tesselatePolyline(polylines, points, doJointTriangles) {
const tesselator = new PolylineTesselator(polylines, points, doJointTriangles);
return tesselator.tesselate();
}
/** @internal */
function createPolylineParams(args, maxDimension) {
(0, core_bentley_1.assert)(!args.flags.isDisjoint);
const vertices = VertexTableBuilder_1.VertexTableBuilder.buildFromPolylines(args, maxDimension);
if (undefined === vertices)
return undefined;
const tesselator = PolylineTesselator.fromPolyline(args);
if (undefined === tesselator)
return undefined;
return {
vertices,
polyline: tesselator.tesselate(),
isPlanar: !!args.flags.isPlanar,
type: args.flags.type ?? core_common_1.PolylineTypeFlags.Normal,
weight: args.width,
linePixels: args.linePixels,
};
}
/** @internal */
function wantJointTriangles(weight, is2d) {
// Joints are incredibly expensive. In 3d, only generate them if the line is sufficiently wide for them to be noticeable.
const jointWidthThreshold = 3;
return is2d || weight >= jointWidthThreshold;
}
//# sourceMappingURL=PolylineParams.js.map