@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
187 lines (186 loc) • 8.22 kB
JavaScript
"use strict";
import { Box2, Mesh, Matrix4, Vector2, Vector3, PlaneGeometry } from "three";
import mapboxgl from "mapbox-gl";
import { ObjectType } from "../../../core/geometry/Constant";
import { CoreMath } from "../../../core/math/_Module";
import { NodeParamsConfig, ParamConfig } from "../utils/params/ParamsConfig";
import { MapboxPlaneHexagonsController } from "../../../core/thirdParty/Mapbox/plane/HexagonsController";
import { isBooleanTrue } from "../../../core/Type";
import { MapboxMapsController } from "../../../core/thirdParty/Mapbox/MapboxMapsController";
import { CoreMapboxTransform } from "../../../core/thirdParty/Mapbox/Transform";
import { TypedSopNode } from "./_Base";
import { CoreMapboxUtils } from "../../../core/thirdParty/Mapbox/Utils";
import { ThreejsPoint } from "../../../core/geometry/modules/three/ThreejsPoint";
const dummyMesh = new Mesh();
const SCALE_ATTRIB_NAME = "scale";
const NORMAL_ATTRIB_NAME = "normal";
const R_MAT_WORLD = new Matrix4().makeRotationAxis(new Vector3(1, 0, 0), Math.PI * 0.5);
var MapboxPlaneType = /* @__PURE__ */ ((MapboxPlaneType2) => {
MapboxPlaneType2["PLANE"] = "plane";
MapboxPlaneType2["HEXAGONS"] = "hexagon";
return MapboxPlaneType2;
})(MapboxPlaneType || {});
const MAPBOX_PLANE_TYPES = ["plane" /* PLANE */, "hexagon" /* HEXAGONS */];
const _mapCenter3D = new Vector3();
const _mapCenter2D = new Vector2();
class MapboxPlaneSopParamsConfig extends NodeParamsConfig {
constructor() {
super(...arguments);
/** @param camera lng lat */
// lngLat = ParamConfig.VECTOR2([0, 0]);
/** @param type of plane (grid or hexagons) */
this.type = ParamConfig.INTEGER(0, {
menu: {
entries: MAPBOX_PLANE_TYPES.map((name, i) => {
return { name, value: i };
})
}
});
/** @param plane resolution */
this.resolution = ParamConfig.INTEGER(10, {
range: [1, 20],
rangeLocked: [true, false]
});
/** @param multiplies the size of the plane. This can be useful to scale down the plane. While it would cover a smaller part of the view, it would be faster to create */
this.sizeMult = ParamConfig.FLOAT(1, {
range: [0, 1],
rangeLocked: [true, false]
});
/** @param toggle on to make sure the plane will cover the full view */
this.fullView = ParamConfig.BOOLEAN(1);
// delete_out_of_view = ParamConfig.BOOLEAN(1);
/** @param do not create polygons, only points */
this.asPoints = ParamConfig.BOOLEAN(0, {
visibleIf: {
type: MAPBOX_PLANE_TYPES.indexOf("plane" /* PLANE */)
}
});
}
/** @param creates within mapbox camera space */
// mapboxTransform = ParamConfig.BOOLEAN(1);
}
const ParamsConfig = new MapboxPlaneSopParamsConfig();
export class MapboxPlaneSopNode extends TypedSopNode {
constructor() {
super(...arguments);
this.paramsConfig = ParamsConfig;
this._hexagonsController = new MapboxPlaneHexagonsController();
this.transformer = new CoreMapboxTransform();
}
static type() {
return "mapboxPlane";
}
async cook() {
const map = await MapboxMapsController.waitForMap();
if (!map) {
this.states.error.set("map not initialized yet");
return;
}
const geometry = this._buildPlane(map);
if (geometry) {
let type = ObjectType.MESH;
if (isBooleanTrue(this.pv.asPoints) || this._asHexagons()) {
type = ObjectType.POINTS;
}
const object = this.createObject(geometry, type);
this.setObject(object);
}
}
_buildPlane(map) {
const center = map.getCenter();
this.transformer.setLngLat(center);
_mapCenter3D.set(center.lng, 0, center.lat);
_mapCenter2D.set(center.lng, center.lat);
this.transformer.transform_position_FINAL(_mapCenter3D);
const vertical_far_lng_lat_points = CoreMapboxUtils.verticalFarLngLatPoints(map);
const vertical_near_lng_lat_points = CoreMapboxUtils.verticalNearLngLatPoints(map);
const lng_lat_points = this.pv.fullView ? vertical_far_lng_lat_points : vertical_near_lng_lat_points;
if (!lng_lat_points) {
return;
}
const mirrored_near_lng_lat_points = lng_lat_points.map((p) => this._mirrorLngLat(p, center));
lng_lat_points.push(center);
for (const p of mirrored_near_lng_lat_points) {
lng_lat_points.push(p);
}
const box = new Box2();
for (const p of lng_lat_points) {
box.expandByPoint(new Vector2(p.lng, p.lat));
}
const mapbox_box = new Box2();
for (const p of lng_lat_points) {
const pt3d = new Vector3(p.lng, 0, p.lat);
this.transformer.transform_position_FINAL(pt3d);
mapbox_box.expandByPoint(new Vector2(pt3d.x, pt3d.z));
}
const mapbox_dimensions = new Vector2();
mapbox_box.getSize(mapbox_dimensions);
const horizontal_lng_lat_points = CoreMapboxUtils.horizontalLngLatPoints(map);
if (!horizontal_lng_lat_points) {
return;
}
const mapbox_horizontal_lng_lat_points = horizontal_lng_lat_points.map((p) => {
const pt3d = new Vector3(p.lng, 0, p.lat);
this.transformer.transform_position_FINAL(pt3d);
return { lng: pt3d.x, lat: pt3d.z };
});
const mapbox_horizontal_distances = {
lng: Math.abs(mapbox_horizontal_lng_lat_points[0].lng - mapbox_horizontal_lng_lat_points[1].lng),
lat: Math.abs(mapbox_horizontal_lng_lat_points[0].lat - mapbox_horizontal_lng_lat_points[1].lat)
};
const mapbox_horizontal_distance = Math.sqrt(
mapbox_horizontal_distances.lng * mapbox_horizontal_distances.lng + mapbox_horizontal_distances.lat * mapbox_horizontal_distances.lat
);
const mapbox_segment_size = mapbox_horizontal_distance / this.pv.resolution;
const segments_counts = {
x: CoreMath.highestEven(this.pv.sizeMult * Math.ceil(mapbox_dimensions.x / mapbox_segment_size)),
y: CoreMath.highestEven(this.pv.sizeMult * Math.ceil(mapbox_dimensions.y / mapbox_segment_size))
};
mapbox_dimensions.x = segments_counts.x * mapbox_segment_size;
mapbox_dimensions.y = segments_counts.y * mapbox_segment_size;
const mapbox_box_untransformed = new Box2();
const mapbox_corners = [
_mapCenter2D.clone().sub(mapbox_dimensions.clone().multiplyScalar(0.5)),
_mapCenter2D.clone().sub(mapbox_dimensions.clone().multiplyScalar(-0.5)),
_mapCenter2D.clone().add(mapbox_dimensions.clone().multiplyScalar(0.5)),
_mapCenter2D.clone().add(mapbox_dimensions.clone().multiplyScalar(-0.5))
];
for (const p of mapbox_corners) {
const untransformed_3d = this.transformer.untransform_position_FINAL(new Vector3(p.x, 0, p.y));
const untransformed = new Vector2(untransformed_3d.x, untransformed_3d.z);
mapbox_box_untransformed.expandByPoint(untransformed);
}
const world_dimensions = new Vector2();
mapbox_box_untransformed.getSize(world_dimensions);
const world_plane_center = new Vector2(center.lng, center.lat);
const horizontal_scale = mapbox_dimensions.x / segments_counts.x;
const plane_dimensions = world_dimensions;
const rotation_matrix = R_MAT_WORLD;
const geometry_center = world_plane_center;
let geometry;
if (this._asHexagons()) {
geometry = this._hexagonsController.geometry(plane_dimensions, segments_counts, false);
} else {
geometry = new PlaneGeometry(plane_dimensions.x, plane_dimensions.y, segments_counts.x, segments_counts.y);
geometry.applyMatrix4(rotation_matrix);
}
geometry.translate(geometry_center.x, 0, geometry_center.y);
const z_scale = [horizontal_scale, 1][0];
const scale = [horizontal_scale, horizontal_scale, z_scale];
dummyMesh.geometry = geometry;
const corePointClass = ThreejsPoint;
corePointClass.addNumericAttribute(dummyMesh, SCALE_ATTRIB_NAME, 3, scale);
corePointClass.addNumericAttribute(dummyMesh, NORMAL_ATTRIB_NAME, 3, [0, 1, 0]);
return geometry;
}
_mirrorLngLat(p, map_center) {
const delta = {
lng: map_center.lng - p.lng,
lat: map_center.lat - p.lat
};
return new mapboxgl.LngLat(map_center.lng + delta.lng, map_center.lat + delta.lat);
}
_asHexagons() {
return this.pv.type == MAPBOX_PLANE_TYPES.indexOf("hexagon" /* HEXAGONS */);
}
}