UNPKG

@itwin/core-frontend

Version:
191 lines • 8.6 kB
/*--------------------------------------------------------------------------------------------- * 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 */ import { PolylineTypeFlags, QPoint3dList } from "@itwin/core-common"; import { VertexIndices } from "./VertexIndices"; import { Vector3d } from "@itwin/core-geometry"; import { assert } from "@itwin/core-bentley"; import { VertexTableBuilder } from "./VertexTableBuilder"; export 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 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.fromArray(this._vertIndex); const prevIndex = 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.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 = Vector3d.createStartEnd(this._position[v.prevIndex], pos); const nextDir = 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 */ export function tesselatePolyline(polylines, points, doJointTriangles) { const tesselator = new PolylineTesselator(polylines, points, doJointTriangles); return tesselator.tesselate(); } /** @internal */ export function createPolylineParams(args, maxDimension) { assert(!args.flags.isDisjoint); const vertices = 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 ?? PolylineTypeFlags.Normal, weight: args.width, linePixels: args.linePixels, }; } /** @internal */ export 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