欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

threejs 根据svg创建

程序员文章站 2022-03-26 19:33:28
...
import {Shape, Vector2, MeshBasicMaterial, BoxGeometry, Mesh, Geometry} from 'three';

export default class Wall {
  constructor (result) {
    this.DEGS_TO_RADS = Math.PI / 180;
    this.DIGIT_0 = 48;
    this.DIGIT_9 = 57;
    this.COMMA = 44;
    this.SPACE = 32;
    this.PERIOD = 46;
    this.MINUS = 45;
    this.idx = 1;
    this.len = result.getAttribute('d').length;
    this.pathStr = result.getAttribute('d');
    this.Geometry = [];
    this.getWall = this.getWall.bind(this);
  }
  transformSVGPath () {
    let paths = [];
    let path = new Shape();
    let x = 0;
    let y = 0;
    let nx = 0;
    let ny = 0;
    let firstX = null;
    let firstY = null;
    let x1 = 0;
    let x2 = 0;
    let y1 = 0;
    let y2 = 0;
    let rx = 0;
    let ry = 0;
    let xar = 0;
    let laf = 0;
    let sf = 0;
    let cx;
    let cy;
    let canRepeat;
    let enteredSub = false;
    let zSeen = false;
    let activeCmd = this.pathStr[0];
    while (this.idx <= this.len) {
      canRepeat = true;
      switch (activeCmd) {
        case 'M':
          enteredSub = false;
          x = this.getIndex();
          y = this.getIndex();
          path.moveTo(x, y);
          activeCmd = 'L';
          break;
        case 'm':
          x += this.getIndex();
          y += this.getIndex();
          path.moveTo(x, y);
          activeCmd = 'l';
          break;
        case 'Z':
        case 'z':
          canRepeat = false;
          if (x !== firstX || y !== firstY) path.lineTo(firstX, firstY);
          paths.push(path);
          firstX = null;
          firstY = null;
          enteredSub = true;
          path = new Shape();
          zSeen = true;
          break;
        case 'L':
        case 'H':
        case 'V':
          nx = (activeCmd === 'V') ? x : this.getIndex();
          ny = (activeCmd === 'H') ? y : this.getIndex();
          path.lineTo(nx, ny);
          x = nx;
          y = ny;
          break;
        case 'l':
        case 'h':
        case 'v':
          nx = (activeCmd === 'v') ? x : (x + this.getIndex());
          ny = (activeCmd === 'h') ? y : (y + this.getIndex());
          path.lineTo(nx, ny);
          x = nx;
          y = ny;
          break;
        case 'C':
          x1 = this.getIndex();
          y1 = this.getIndex();
        case 'S':
          if (activeCmd === 'S') {
            x1 = 2 * x - x2; y1 = 2 * y - y2;
          }
          x2 = this.getIndex();
          y2 = this.getIndex();
          nx = this.getIndex();
          ny = this.getIndex();
          path.bezierCurveTo(x1, y1, x2, y2, nx, ny);
          x = nx; y = ny;
          break;
        case 'c':
          x1 = x + this.getIndex();
          y1 = y + this.getIndex();
        case 's':
          if (activeCmd === 's') {
            x1 = 2 * x - x2;
            y1 = 2 * y - y2;
          }
          x2 = x + this.getIndex();
          y2 = y + this.getIndex();
          nx = x + this.getIndex();
          ny = y + this.getIndex();
          path.bezierCurveTo(x1, y1, x2, y2, nx, ny);
          x = nx; y = ny;
          break;
        case 'Q':
          x1 = this.getIndex();
          y1 = this.getIndex();
        case 'T':
          if (activeCmd === 'T') {
            x1 = 2 * x - x1;
            y1 = 2 * y - y1;
          }
          nx = this.getIndex();
          ny = this.getIndex();
          path.quadraticCurveTo(x1, y1, nx, ny);
          x = nx;
          y = ny;
          break;
        case 'q':
          x1 = x + this.getIndex();
          y1 = y + this.getIndex();
        case 't':
          if (activeCmd === 't') {
            x1 = 2 * x - x1;
            y1 = 2 * y - y1;
          }
          nx = x + this.getIndex();
          ny = y + this.getIndex();
          path.quadraticCurveTo(x1, y1, nx, ny);
          x = nx; y = ny;
          break;
        case 'A':
          rx = this.getIndex();
          ry = this.getIndex();
          xar = this.getIndex() * this.DEGS_TO_RADS;
          laf = this.getIndex();
          sf = this.getIndex();
          nx = this.getIndex();
          ny = this.getIndex();
          if (rx !== ry) {
            console.warn('Forcing elliptical arc to be a circular one :(',
              rx, ry);
          }
          x1 = Math.cos(xar) * (x - nx) / 2 + Math.sin(xar) * (y - ny) / 2;
          y1 = -Math.sin(xar) * (x - nx) / 2 + Math.cos(xar) * (y - ny) / 2;
          let norm = Math.sqrt(
            (rx * rx * ry * ry - rx * rx * y1 * y1 - ry * ry * x1 * x1) /
            (rx * rx * y1 * y1 + ry * ry * x1 * x1));
          if (laf === sf) {
            norm = -norm;
          }
          x2 = norm * rx * y1 / ry;
          y2 = norm * -ry * x1 / rx;
          cx = Math.cos(xar) * x2 - Math.sin(xar) * y2 + (x + nx) / 2;
          cy = Math.sin(xar) * x2 + Math.cos(xar) * y2 + (y + ny) / 2;
          let u = new Vector2(1, 0);
          let v = new Vector2((x1 - x2) / rx, (y1 - y2) / ry);
          let startAng = Math.acos(u.dot(v) / u.length() / v.length());
          if (u.x * v.y - u.y * v.x < 0) startAng = -startAng;
          u.x = (-x1 - x2) / rx;
          u.y = (-y1 - y2) / ry;
          let deltaAng = Math.acos(v.dot(u) / v.length() / u.length());
          if (v.x * u.y - v.y * u.x < 0) deltaAng = -deltaAng;
          if (!sf && deltaAng > 0) deltaAng -= Math.PI * 2;
          if (sf && deltaAng < 0) deltaAng += Math.PI * 2;
          path.absarc(cx, cy, rx, startAng, startAng + deltaAng, sf);
          x = nx;
          y = ny;
          break;
        case ' ':
          break;
        default:
          throw new Error('weird path command: ' + activeCmd);
      }
      if (firstX === null && !enteredSub) {
        firstX = x;
        firstY = y;
      }
      if (canRepeat && this.nextIsNum()) continue;
      activeCmd = this.pathStr[this.idx++];
    }
    if (zSeen) {
      return paths;
    } else {
      paths.push(path);
      return paths;
    }
  }
  getIndex () {
    let index;
    let c;
    let isFloat = false;
    let s;
    while (this.idx < this.len) {
      c = this.pathStr.charCodeAt(this.idx);
      if (c !== this.COMMA && c !== this.SPACE) break;
      this.idx++;
    }
    if (c === this.MINUS) {
      index = this.idx++;
    } else {
      index = this.idx;
    }
    while (this.idx < this.len) {
      c = this.pathStr.charCodeAt(this.idx);
      if (this.DIGIT_0 <= c && c <= this.DIGIT_9) {
        this.idx++;
        continue;
      } else if (c === this.PERIOD) {
        this.idx++;
        isFloat = true;
        continue;
      }
      s = this.pathStr.substring(index, this.idx);
      return isFloat ? parseFloat(s) : parseInt(s);
    }
    s = this.pathStr.substring(index);
    return isFloat ? parseFloat(s) : parseInt(s);
  }
  nextIsNum () {
    let c;
    while (this.idx < this.len) {
      c = this.pathStr.charCodeAt(this.idx);
      if (c !== this.COMMA && c !== this.SPACE) break;
      this.idx++;
    }
    c = this.pathStr.charCodeAt(this.idx);
    return (c === this.MINUS || (this.DIGIT_0 <= c && c <= this.DIGIT_9));
  }
  getWall () {
    let res = this.transformSVGPath();
    for (let i = 0; i < res.length; i++) {
      let mesh = this.combinedVolume(this.createVolume(this.getNumberPoints(res[i])));
      return mesh;
    }
  }
  getNumberPoints (result) {
    const curves = result.curves;
    const vertices = [];
    for (let i = 0, len = curves.length; i < len; i++) {
      if (Math.abs(curves[i].v1.x - curves[i].v2.x) > Math.abs(curves[i].v1.y - curves[i].v2.y)) {
        for (let j = 1; j <= Math.abs(curves[i].v1.x - curves[i].v2.x); j++) {
          if (curves[i].v1.x - curves[i].v2.x < 0 && curves[i].v1.y - curves[i].v2.y < 0) {
            vertices.push({x: curves[i].v1.x + j, y: 1, z: curves[i].v1.y + (j / (Math.abs(curves[i].v2.x - curves[i].v1.x) / Math.abs(curves[i].v2.y - curves[i].v1.y)))});
          } else if ((curves[i].v1.x - curves[i].v2.x) > 0 && (curves[i].v1.y - curves[i].v2.y) < 0) {
            vertices.push({x: curves[i].v1.x, y: 1, z: curves[i].v1.y + (j / (Math.abs(curves[i].v2.x - curves[i].v1.x) / Math.abs(curves[i].v2.y - curves[i].v1.y)))});
          } else if ((curves[i].v1.x - curves[i].v2.x) > 0 && (curves[i].v1.y - curves[i].v2.y) > 0) {
            vertices.push({x: curves[i].v1.x - j, y: 1, z: curves[i].v1.y - (j / (Math.abs(curves[i].v2.x - curves[i].v1.x) / Math.abs(curves[i].v2.y - curves[i].v1.y)))});
          }
        }
      } else {
        for (let k = 1; k <= Math.abs(curves[i].v1.y - curves[i].v2.y); k++) {
          if (curves[i].v1.x - curves[i].v2.x > 0 && curves[i].v1.y - curves[i].v2.y < 0) {
            vertices.push({x: curves[i].v1.x - (k / (Math.abs(curves[i].v2.y - curves[i].v1.y) / Math.abs(curves[i].v2.x - curves[i].v1.x))), y: 1, z: curves[i].v1.y + k});
          } else if (curves[i].v1.x - curves[i].v2.x > 0 && curves[i].v1.y - curves[i].v2.y > 0) {
            vertices.push({x: curves[i].v1.x - (k / (Math.abs(curves[i].v2.y - curves[i].v1.y) / Math.abs(curves[i].v2.x - curves[i].v1.x))), y: 1, z: curves[i].v1.y - k});
          } else if (curves[i].v1.x - curves[i].v2.x < 0 && curves[i].v1.y - curves[i].v2.y > 0) {
            vertices.push({x: curves[i].v1.x + (k / (Math.abs(curves[i].v2.y - curves[i].v1.y) / Math.abs(curves[i].v2.x - curves[i].v1.x))), y: 1, z: curves[i].v1.y - k});
          }
        }
      }
    }
    return vertices;
  }
  createVolume (result) {
    let boxGeometry = new BoxGeometry(1, 100, 10);
    let material = new MeshBasicMaterial({color: 'red'});
    let mesh = new Mesh(boxGeometry, material);
    for (let i = 0; i < result.length; i++) {
      let meshs = mesh.clone();
      meshs.name = 'wall';
      meshs.position.set(result[i].x, result[i].y, result[i].z);
      this.Geometry.push(meshs);
    }
    return this.Geometry;
  }
  combinedVolume (result) {
    let len = result.length;
    let geometry = new Geometry();
    for (let i = 0; i < len; i++) {
      result[i].updateMatrix();
      geometry.merge(result[i].geometry, result[i].matrix);
    }
    let material = new MeshBasicMaterial({color: 'red'});
    let mesh = new Mesh(geometry, material);
    return mesh;
  }
}

 

相关标签: threejs