|
1 | 1 |
|
2 | 2 | /* spellchecker: disable */
|
3 | 3 |
|
4 |
| -import { mat4, vec2, vec3 } from 'gl-matrix'; |
| 4 | +import { mat4, vec2, vec3, vec4 } from 'gl-matrix'; |
5 | 5 |
|
6 | 6 | import { assert } from '../auxiliaries';
|
7 | 7 | import { v3 } from '../gl-matrix-extensions';
|
@@ -216,7 +216,6 @@ export class Typesetter {
|
216 | 216 | switch (label.elide) {
|
217 | 217 | case Label.Elide.Right:
|
218 | 218 | return [label.lineWidth - ellipsisWidth, 0.0];
|
219 |
| - break; |
220 | 219 | case Label.Elide.Middle:
|
221 | 220 | const threshold = label.lineWidth / 2 - ellipsisWidth / 2;
|
222 | 221 | return [threshold, threshold];
|
@@ -323,6 +322,71 @@ export class Typesetter {
|
323 | 322 | }
|
324 | 323 | }
|
325 | 324 |
|
| 325 | + /** |
| 326 | + * @param currentRectangle - [minX, minY, minZ, maxX, maxY, maxZ] is updated in-place |
| 327 | + * @param newRectangle - [minX, minY, minZ, maxX, maxY, maxZ] used to update currentRectangle |
| 328 | + */ |
| 329 | + private static updateRectangleMinMax(currentRectangle: number[], newRectangle: number[]): void { |
| 330 | + assert(currentRectangle.length === 6 && newRectangle.length === 6, `expected the rectangles to have 6 values!`); |
| 331 | + |
| 332 | + let i = 0; |
| 333 | + for (; i < 3; i++) { |
| 334 | + currentRectangle[i] = Math.min(currentRectangle[i], newRectangle[i]); |
| 335 | + } |
| 336 | + for (; i < 6; i++) { |
| 337 | + currentRectangle[i] = Math.max(currentRectangle[i], newRectangle[i]); |
| 338 | + } |
| 339 | + } |
| 340 | + |
| 341 | + /** |
| 342 | + * Returns a vec2 [min, max] containing the minimum and the maximum of the given values. |
| 343 | + * @param currentMin - the current minimum (e.g., initialized to +Infinity) |
| 344 | + * @param currentMax - the current maximum (e.g., initialized to -Infinity) |
| 345 | + * @param values - find the maximum and minimum of the given values |
| 346 | + */ |
| 347 | + private static minMax(currentMin: number, currentMax: number, values: number[]): vec2 { |
| 348 | + const min = Math.min(currentMin, ...values); |
| 349 | + const max = Math.max(currentMax, ...values); |
| 350 | + return vec2.fromValues(min, max); |
| 351 | + } |
| 352 | + |
| 353 | + /** |
| 354 | + * Returns [minX, minY, minZ, maxX, maxY, maxZ] of the vertices coordinates, i.e., origins, |
| 355 | + * origins + tangents, origins + ups, from which a bounding rectangle can be calculated. |
| 356 | + * @param vertices - Glyph vertices to be transformed (expected untransformed, in typesetting space). |
| 357 | + * @param begin - Vertex index to start alignment at. |
| 358 | + * @param end - Vertex index to stop alignment at. |
| 359 | + */ |
| 360 | + private static getMinMaxVertices(vertices: GlyphVertices, begin: number, end: number) |
| 361 | + : [number, number, number, number, number, number] { |
| 362 | + |
| 363 | + let minX = Number.POSITIVE_INFINITY; |
| 364 | + let maxX = Number.NEGATIVE_INFINITY; |
| 365 | + let minY = Number.POSITIVE_INFINITY; |
| 366 | + let maxY = Number.NEGATIVE_INFINITY; |
| 367 | + let minZ = Number.POSITIVE_INFINITY; |
| 368 | + let maxZ = Number.NEGATIVE_INFINITY; |
| 369 | + |
| 370 | + for (let i: number = begin; i < end; ++i) { |
| 371 | + const x = Typesetter.minMax(minX, maxX, [vertices.origin(i)[0], vertices.origin(i)[0] + vertices.up(i)[0], |
| 372 | + vertices.origin(i)[0] + vertices.tangent(i)[0]]); |
| 373 | + minX = x[0]; |
| 374 | + maxX = x[1]; |
| 375 | + |
| 376 | + const y = Typesetter.minMax(minY, maxY, [vertices.origin(i)[1], vertices.origin(i)[1] + vertices.up(i)[1], |
| 377 | + vertices.origin(i)[1] + vertices.tangent(i)[1]]); |
| 378 | + minY = y[0]; |
| 379 | + maxY = y[1]; |
| 380 | + |
| 381 | + const z = Typesetter.minMax(minZ, maxZ, [vertices.origin(i)[2], vertices.origin(i)[2] + vertices.up(i)[2], |
| 382 | + vertices.origin(i)[2] + vertices.tangent(i)[2]]); |
| 383 | + minZ = z[0]; |
| 384 | + maxZ = z[1]; |
| 385 | + } |
| 386 | + |
| 387 | + return [minX, minY, minZ, maxX, maxY, maxZ]; |
| 388 | + } |
| 389 | + |
326 | 390 | /**
|
327 | 391 | * Adjusts the vertices for a line after typesetting (done due to line feed, word wrap, or end of line) w.r.t.
|
328 | 392 | * the targeted line alignment.
|
@@ -356,10 +420,32 @@ export class Typesetter {
|
356 | 420 | * @param lines - Indices of glyph vertices on same lines to apply line-based transformations.
|
357 | 421 | */
|
358 | 422 | private static transform(label: Label, vertices: GlyphVertices, lines: Array<Line>): void {
|
| 423 | + |
| 424 | + const boundingRectangle = [ |
| 425 | + Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, |
| 426 | + Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY]; |
| 427 | + |
359 | 428 | for (const line of lines) {
|
360 | 429 | Typesetter.transformAlignment(line[2], label.alignment, vertices, line[0], line[1]);
|
| 430 | + |
| 431 | + Typesetter.updateRectangleMinMax(boundingRectangle, |
| 432 | + Typesetter.getMinMaxVertices(vertices, line[0], line[1])); |
| 433 | + |
361 | 434 | Typesetter.transformVertices(label.staticTransform, vertices, line[0], line[1]);
|
362 | 435 | }
|
| 436 | + |
| 437 | + // transform extent from Typesetting Space to the label's fontUnitSize space (depending on the label, e.g. |
| 438 | + // screen space (px) or world space) |
| 439 | + const width = boundingRectangle[3] - boundingRectangle[0]; |
| 440 | + const height = boundingRectangle[4] - boundingRectangle[1]; |
| 441 | + |
| 442 | + const ll = vec4.transformMat4(vec4.create(), vec4.fromValues(0, 0, 0, 1), label.staticTransform); |
| 443 | + const lr = vec4.transformMat4(vec4.create(), vec4.fromValues(width, 0, 0, 1), label.staticTransform); |
| 444 | + const ul = vec4.transformMat4(vec4.create(), vec4.fromValues(0, height, 0, 1), label.staticTransform); |
| 445 | + |
| 446 | + const extent = vec2.fromValues(vec4.distance(lr, ll), vec4.distance(ul, ll)); |
| 447 | + |
| 448 | + label.extent = [extent[0], extent[1]]; |
363 | 449 | }
|
364 | 450 |
|
365 | 451 |
|
|
0 commit comments