<div class="preview">
  <p>2D straight skeleton after post processing preview</p>
  <canvas id="canvas2d"></canvas>
</div>
import { Vector2 } from "https://esm.sh/three";

// Result of the skeleton and skeletonBox get on previous codepen https://codepen.io/TANK2003/pen/NPKvOqM

const skeleton = {
  vertices: [
    [259521.140625, 6253168, 0],
    [259606.34375, 6253192.5, 0],
    [259590.5625, 6253248, 0],
    [259505.3125, 6253223.5, 0],
    [259570.71875, 6253212.5, 28.852020263671875],
    [259540.953125, 6253203.5, 28.85428237915039]
  ],
  polygons: [
    [0, 5, 3],
    [1, 4, 5, 0],
    [2, 4, 1],
    [3, 5, 4, 2]
  ]
};

const skeletonBox = {
  maxX: 259606.34375,
  maxY: 6253248,
  minX: 259505.3125,
  minY: 6253168
};

export class StraightSkeletonResult {
  vertices: Vector2[];
  polygons: {
    vertices: Vector2[];
    edgeStart: Vector2;
    edgeEnd: Vector2;
  }[];

  constructor(source) {
    this.vertices = source.vertices.map((v) => new Vector2(v[0], v[1]));
    this.polygons = source.polygons.map((p) => {
      const vertices = p.map((v) => this.vertices[v]);

      return {
        vertices: vertices,
        edgeStart: vertices[vertices.length - 1],
        edgeEnd: vertices[0]
      };
    });
  }
}

const skeletonResult = new StraightSkeletonResult(skeleton);

const draw2d = (skeletonBox, skeletonResult) => {
  // 2D canvas
  const canvas2d = document.getElementById("canvas2d");
  const ctx = canvas2d.getContext("2d");

  canvas2d.width = canvas2d.clientWidth * window.devicePixelRatio;
  canvas2d.height = canvas2d.clientHeight * window.devicePixelRatio;

  ctx.fillStyle = "#eee";
  ctx.fillRect(0, 0, canvas2d.width, canvas2d.height);

  const padding = 15 * window.devicePixelRatio;
  const scale = Math.min(
    (canvas2d.width - padding * 2) / (skeletonBox.maxX - skeletonBox.minX),
    (canvas2d.height - padding * 2) / (skeletonBox.maxY - skeletonBox.minY)
  );
  const offsetX =
    (canvas2d.width - (skeletonBox.maxX - skeletonBox.minX) * scale) / 2;
  const offsetY =
    (canvas2d.height - (skeletonBox.maxY - skeletonBox.minY) * scale) / 2;

  ctx.strokeStyle = "#000";
  ctx.lineWidth = window.devicePixelRatio;
  ctx.fillStyle = "#ffb6e9";

  for (const polygon of skeletonResult.polygons) {
    ctx.beginPath();

    for (let i = 0; i < polygon.vertices.length; i++) {
      const vertex = polygon.vertices[i];
      const x = (vertex.x - skeletonBox.minX) * scale + offsetX;
      const y = (vertex.y - skeletonBox.minY) * scale + offsetY;

      if (i === 0) {
        ctx.moveTo(x, y);
      } else {
        ctx.lineTo(x, y);
      }
    }

    ctx.closePath();
    ctx.stroke();
    ctx.fill();
  }
};

for (let i = 0; i < skeletonResult.polygons.length; i++) {
  const polygon = skeletonResult.polygons[i];

  // Pour les polygone roses (ceux dont on doit conserver uniquement les sommets de fins et de debut)
  // On recherchera les polygones rouges du skeleton adjacents à leurs extrémités
  if (polygon.vertices.length === 3) {
    // Polygone de notre skeleton adjacent au sommet du debut
    const prevPolygon = skeletonResult.polygons.find(
      (p) => p.edgeEnd.equals(polygon.edgeStart) && p.vertices.length > 3
    );
    // Polygone de notre skeleton adjacent au sommet de fin
    const nextPolygon = skeletonResult.polygons.find(
      (p) => p.edgeStart.equals(polygon.edgeEnd) && p.vertices.length > 3
    );

    if (prevPolygon && nextPolygon) {
      // Projection des polygones rouges adjacents à notre polygone rose

      // Le seul sommet de notre polygone rose qui est ni sa fin, ni son debut
      const extrudedPoint = polygon.vertices.find((p) => {
        return !p.equals(polygon.edgeStart) && !p.equals(polygon.edgeEnd);
      });

      // Le sommet de nos polygones rouges qui sont à projeter
      const prevPolygonExtrudedPoint = prevPolygon.vertices.find((v) =>
        v.equals(extrudedPoint)
      );
      const nextPolygonExtrudedPoint = nextPolygon.vertices.find((v) =>
        v.equals(extrudedPoint)
      );

      // Le sommet situé au milieu du segment[sommet debut, sommet fin] de notre polygone rose
      // Qui correspond au sommet souhaité pour notre projection
      const middle = new Vector2()
        .addVectors(polygon.edgeStart, polygon.edgeEnd)
        .multiplyScalar(0.5);
      prevPolygonExtrudedPoint.x = nextPolygonExtrudedPoint.x = middle.x;
      prevPolygonExtrudedPoint.y = nextPolygonExtrudedPoint.y = middle.y;

      // Projection faite, on conserve uniquement les sommets de debut et fin de notre polygone rose
      polygon.vertices = [];
    }
  }
}

draw2d(skeletonBox, skeletonResult);

console.log(JSON.stringify(skeletonResult));
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.