diff --git a/example/testLayers/czml_simple.ts b/example/testLayers/czml_simple.ts new file mode 100644 index 0000000..0f770de --- /dev/null +++ b/example/testLayers/czml_simple.ts @@ -0,0 +1,345 @@ +import { Layer } from "@reearth/core"; + +const value = `[ + { + "id": "document", + "name": "GeoJSON to CZML", + "version": "1.0" + }, + { + "id": "feature_0", + "position": { + "cartographicDegrees": [ + 30, + 0, + 0 + ] + }, + "point": { + "color": { + "rgba": [ + 0, + 0, + 255, + 255 + ] + }, + "pixelSize": 10 + }, + "properties": { + "title": 3, + "marker-color": "#0000ff", + "marker-size": "medium", + "marker-symbol": "circle" + } + }, + { + "id": "feature_1", + "position": { + "cartographicDegrees": [ + 30, + 1, + 0 + ] + }, + "point": { + "color": { + "rgba": [ + 0, + 255, + 0, + 255 + ] + }, + "pixelSize": 10 + }, + "properties": { + "title": 2, + "marker-color": "#00ff04", + "marker-size": "medium", + "marker-symbol": "circle" + } + }, + { + "id": "feature_2", + "position": { + "cartographicDegrees": [ + 30, + 2, + 0 + ] + }, + "point": { + "color": { + "rgba": [ + 255, + 0, + 0, + 255 + ] + }, + "pixelSize": 10 + }, + "properties": { + "title": 1, + "marker-color": "#ff0000", + "marker-size": "medium", + "marker-symbol": "circle" + } + }, + { + "id": "feature_3", + "polyline": { + "positions": { + "cartographicDegrees": [ + 31, + 2, + 0, + 32, + 2, + 0, + 33, + 2, + 0 + ] + }, + "width": 2, + "material": { + "solidColor": { + "color": { + "rgba": [ + 255, + 0, + 0, + 255 + ] + } + } + } + }, + "properties": { + "title": 1, + "stroke": "#ff0000", + "stroke-width": 2, + "stroke-opacity": 1 + } + }, + { + "id": "feature_4", + "polyline": { + "positions": { + "cartographicDegrees": [ + 31, + 1, + 0, + 32, + 1, + 0, + 33, + 1, + 0 + ] + }, + "width": 2, + "material": { + "solidColor": { + "color": { + "rgba": [ + 0, + 255, + 0, + 255 + ] + } + } + } + }, + "properties": { + "title": 2, + "stroke": "#00ff00", + "stroke-width": 4, + "stroke-opacity": 1 + } + }, + { + "id": "feature_5", + "polyline": { + "positions": { + "cartographicDegrees": [ + 31, + 0, + 0, + 32, + 0, + 0, + 33, + 0, + 0 + ] + }, + "width": 2, + "material": { + "solidColor": { + "color": { + "rgba": [ + 0, + 0, + 255, + 255 + ] + } + } + } + }, + "properties": { + "title": 3, + "stroke": "#0000ff", + "stroke-width": 6, + "stroke-opacity": 1 + } + }, + { + "id": "feature_6", + "polygon": { + "positions": { + "cartographicDegrees": [ + 34, + 2, + 0, + 35, + 2, + 0, + 35, + 3, + 0, + 34, + 3, + 0, + 34, + 2, + 0 + ] + }, + "material": { + "solidColor": { + "color": { + "rgba": [ + 255, + 0, + 0, + 255 + ] + } + } + } + }, + "properties": { + "title": 1, + "stroke": "#ff0000", + "stroke-width": 2, + "stroke-opacity": 1, + "fill": "#ff0000", + "fill-opacity": 0.5 + } + }, + { + "id": "feature_7", + "polygon": { + "positions": { + "cartographicDegrees": [ + 34, + 1, + 0, + 35, + 1, + 0, + 35, + 2, + 0, + 34, + 2, + 0, + 34, + 1, + 0 + ] + }, + "material": { + "solidColor": { + "color": { + "rgba": [ + 0, + 255, + 0, + 255 + ] + } + } + } + }, + "properties": { + "title": 2, + "stroke": "#00ff00", + "stroke-width": 4, + "stroke-opacity": 1, + "fill": "#00ff00", + "fill-opacity": 0.5 + } + }, + { + "id": "feature_8", + "polygon": { + "positions": { + "cartographicDegrees": [ + 34, + 0, + 0, + 35, + 0, + 0, + 35, + 1, + 0, + 34, + 1, + 0, + 34, + 0, + 0 + ] + }, + "material": { + "solidColor": { + "color": { + "rgba": [ + 0, + 0, + 255, + 255 + ] + } + } + } + }, + "properties": { + "title": 3, + "stroke": "#0000ff", + "stroke-width": 8, + "stroke-opacity": 1, + "fill": "#0000ff", + "fill-opacity": 0.5 + } + } +]`; + +export const CZML_SIMPLE: Layer = { + id: "czml_simple", + type: "simple", + data: { + type: "czml", + url: "data:text/plain;charset=UTF-8," + encodeURIComponent(value), + }, + marker: {}, + polygon: {}, + polyline: {}, +}; diff --git a/example/testLayers/index.ts b/example/testLayers/index.ts index 628def5..6b16ba1 100644 --- a/example/testLayers/index.ts +++ b/example/testLayers/index.ts @@ -1,5 +1,6 @@ import { Layer } from "@reearth/core"; +import { CZML_SIMPLE } from "./czml_simple"; import { GEOJSON_MARKER } from "./geojson_marker"; import { GEOJSON_SIMPLE } from "./geojson_simple"; import { GOOGLE_PHOTOREALISTIC_3DTILES } from "./google_photorealistic_3dtiles"; @@ -14,4 +15,5 @@ export const TEST_LAYERS: Layer[] = [ GOOGLE_PHOTOREALISTIC_3DTILES, OSM_BUILDINGS, THREEDTILES_SIMPLE, + CZML_SIMPLE, ]; diff --git a/src/engines/Cesium/Feature/Resource/utils.ts b/src/engines/Cesium/Feature/Resource/utils.ts index 67ccbbf..cc56fe7 100644 --- a/src/engines/Cesium/Feature/Resource/utils.ts +++ b/src/engines/Cesium/Feature/Resource/utils.ts @@ -1,15 +1,9 @@ -import { - Entity, - Cartesian3, - PolygonHierarchy, - PointGraphics, - BillboardGraphics, - JulianDate, -} from "cesium"; +import { Entity, PointGraphics, BillboardGraphics, JulianDate } from "cesium"; import { EvalFeature } from "../../.."; import { AppearanceTypes, ComputedFeature, ComputedLayer, Feature } from "../../../../mantle"; import { heightReference, shadowMode, toColor } from "../../common"; +import { getMarkerCoordinates, getGeometryFromEntity } from "../../helpers/getGeometryFromEntity"; import { convertEntityDescription, convertEntityProperties } from "../../utils/utils"; import { attachTag, extractSimpleLayer, getTag, Tag } from "../utils"; @@ -132,16 +126,14 @@ export const attachStyle = ( const point = hasAppearance(layer, entity, ["marker", "point"]); const billboard = hasAppearance(layer, entity, ["marker", "billboard"]); const label = hasAppearance(layer, entity, ["marker", "label"]); - if (point || billboard || label) { - const position = entity.position?.getValue(currentTime); - const coordinates = [position?.x ?? 0, position?.y ?? 0, position?.z ?? 0]; + if (entity.point || entity.billboard || entity.label) { + const coordinates = getMarkerCoordinates(entity, currentTime); + const geometry = getGeometryFromEntity(currentTime, entity); + const feature: Feature = { type: "feature", id: makeFeatureId(entity), - geometry: { - type: "Point", - coordinates, - }, + geometry, properties: convertEntityProperties(currentTime, entity), metaData: { description: convertEntityDescription(currentTime, entity), @@ -168,10 +160,10 @@ export const attachStyle = ( name: "show", ...(computedFeature?.marker?.style ? { - override: - computedFeature?.marker?.style === "point" && - (computedFeature?.marker.show ?? true), - } + override: + computedFeature?.marker?.style === "point" && + (computedFeature?.marker.show ?? true), + } : {}), }, pixelSize: { @@ -207,10 +199,10 @@ export const attachStyle = ( name: "show", ...(computedFeature?.marker?.style ? { - override: - computedFeature?.marker?.style === "image" && - (computedFeature?.marker.show ?? true), - } + override: + computedFeature?.marker?.style === "image" && + (computedFeature?.marker.show ?? true), + } : {}), }, image: { @@ -261,21 +253,14 @@ export const attachStyle = ( return [feature, computedFeature]; } - if (hasAppearance(layer, entity, ["polyline", "polyline"])) { + if (entity.polyline) { const entityPosition = entity.position?.getValue(currentTime); - const positions = entity.polyline?.positions?.getValue(currentTime) as Cartesian3[]; - const coordinates = positions?.map(position => [ - position?.x ?? 0, - position?.y ?? 0, - position?.z ?? 0, - ]); + const geometry = getGeometryFromEntity(currentTime, entity); + const feature: Feature = { type: "feature", id: makeFeatureId(entity), - geometry: { - type: "LineString", - coordinates, - }, + geometry, properties: convertEntityProperties(currentTime, entity), metaData: { description: convertEntityDescription(currentTime, entity), @@ -290,42 +275,39 @@ export const attachStyle = ( if (!computedFeature) { return; } - attachProperties(entity, computedFeature, ["polyline", "polyline"], { - show: { - name: "show", - default: true, - }, - width: { - name: "strokeWidth", - }, - material: { - name: "strokeColor", - type: "color", - }, - shadows: { - name: "shadows", - type: "shadows", - }, - clampToGround: { - name: "clampToGround", - }, - }); + if (hasAppearance(layer, entity, ["polyline", "polyline"])) { + attachProperties(entity, computedFeature, ["polyline", "polyline"], { + show: { + name: "show", + default: true, + }, + width: { + name: "strokeWidth", + }, + material: { + name: "strokeColor", + type: "color", + }, + shadows: { + name: "shadows", + type: "shadows", + }, + clampToGround: { + name: "clampToGround", + }, + }); + } return [feature, computedFeature]; } - if (hasAppearance(layer, entity, ["polygon", "polygon"])) { + if (entity.polygon) { const entityPosition = entity.position?.getValue(currentTime); - const hierarchy = entity.polygon?.hierarchy?.getValue(currentTime) as PolygonHierarchy; - const coordinates = hierarchy?.holes?.map(hole => - hole.positions.map(position => [position?.x ?? 0, position?.y ?? 0, position?.z ?? 0]), - ); + const geometry = getGeometryFromEntity(currentTime, entity); + const feature: Feature = { type: "feature", id: makeFeatureId(entity), - geometry: { - type: "Polygon", - coordinates, - }, + geometry, properties: convertEntityProperties(currentTime, entity), metaData: { description: convertEntityDescription(currentTime, entity), @@ -340,40 +322,42 @@ export const attachStyle = ( if (!computedFeature) { return; } - attachProperties(entity, computedFeature, ["polygon", "polygon"], { - show: { - name: "show", - default: true, - }, - fill: { - name: "fill", - }, - material: { - name: "fillColor", - type: "color", - }, - outline: { - name: "stroke", - }, - outlineColor: { - name: "strokeColor", - type: "color", - }, - outlineWidth: { - name: "strokeWidth", - }, - shadows: { - name: "shadows", - type: "shadows", - }, - heightReference: { - name: "heightReference", - type: "heightReference", - }, - extrudedHeight: { - name: "extrudedHeight", - }, - }); + if (hasAppearance(layer, entity, ["polygon", "polygon"])) { + attachProperties(entity, computedFeature, ["polygon", "polygon"], { + show: { + name: "show", + default: true, + }, + fill: { + name: "fill", + }, + material: { + name: "fillColor", + type: "color", + }, + outline: { + name: "stroke", + }, + outlineColor: { + name: "strokeColor", + type: "color", + }, + outlineWidth: { + name: "strokeWidth", + }, + shadows: { + name: "shadows", + type: "shadows", + }, + heightReference: { + name: "heightReference", + type: "heightReference", + }, + extrudedHeight: { + name: "extrudedHeight", + }, + }); + } return [feature, computedFeature]; } }; diff --git a/src/engines/Cesium/helpers/getGeometryFromEntity.ts b/src/engines/Cesium/helpers/getGeometryFromEntity.ts new file mode 100644 index 0000000..b9479fd --- /dev/null +++ b/src/engines/Cesium/helpers/getGeometryFromEntity.ts @@ -0,0 +1,55 @@ +import { Cartesian3, Entity, JulianDate, PolygonHierarchy } from "cesium"; + +import { Geometry } from "../../../mantle"; + +export function getMarkerCoordinates( + entity: Entity, + currentTime: JulianDate, +): [number, number, number] { + const position = entity.position?.getValue(currentTime) as Cartesian3 | undefined; + return [position?.x ?? 0, position?.y ?? 0, position?.z ?? 0]; +} + +export function getGeometryFromEntity(currentTime: JulianDate, entity: Entity) { + if (entity.point || entity.billboard || entity.label) { + const coordinates = getMarkerCoordinates(entity, currentTime); + + const geometry: Geometry = { + type: "Point", + coordinates, + }; + return geometry; + } + + if (entity.polyline) { + const positions = entity.polyline?.positions?.getValue(currentTime) as Cartesian3[]; + const coordinates = positions?.map(position => [ + position?.x ?? 0, + position?.y ?? 0, + position?.z ?? 0, + ]); + + const geometry: Geometry = { + type: "LineString", + coordinates, + }; + return geometry; + } + + if (entity.polygon) { + const hierarchy = entity.polygon?.hierarchy?.getValue(currentTime) as PolygonHierarchy; + const coordinates = hierarchy?.positions?.map(position => [ + position?.x ?? 0, + position?.y ?? 0, + position?.z ?? 0, + ]); + + const geometry: Geometry = { + type: "Polygon", + coordinates: [coordinates], + }; + return geometry; + } + + return undefined; +} diff --git a/src/engines/Cesium/hooks/useEngineRef.ts b/src/engines/Cesium/hooks/useEngineRef.ts index 9a60b9c..15eee74 100644 --- a/src/engines/Cesium/hooks/useEngineRef.ts +++ b/src/engines/Cesium/hooks/useEngineRef.ts @@ -46,6 +46,7 @@ import { findEntity, findFeaturesFromLayer, } from "../utils/utils"; +import { getGeometryFromEntity } from "../helpers/getGeometryFromEntity"; export default function useEngineRef( ref: Ref, @@ -847,6 +848,7 @@ export default function useEngineRef( tag.computedFeature ?? { type: "computedFeature", id: tag.featureId, + geometry: getGeometryFromEntity(viewer.clock.currentTime, entity), properties: convertEntityProperties(viewer.clock.currentTime, entity), metaData: { description: convertEntityDescription(viewer.clock.currentTime, entity),