| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694 |
- import { genCache, validNum } from "@/utils/shared";
- import {
- BorderTaggingInfo,
- CoverLine,
- getSceneApi,
- ResourceArgs,
- Scene,
- SceneResource,
- TaggingInfo,
- WallTaggingInfo,
- } from "./platform-resource";
- import { lineLen, Pos, zeroEq } from "@/utils/math";
- import {
- aiIconMap,
- getIconItem,
- styleIconMap,
- traceIconMap,
- } from "../constant";
- import {
- Euler,
- MathUtils,
- Matrix4,
- Matrix4Tuple,
- Object3D,
- Quaternion,
- Vector3,
- } from "three";
- import { extractConnectedSegments } from "@/utils/polygon";
- const fetchResource = genCache(
- (scene: Scene) => scene.m,
- async (scene: Scene) => {
- const prev = `${scene.mapping ? "/" + scene.mapping : ""}/scene_view_data/${
- scene.m
- }`;
- let version = Date.now();
- const get = (url: string, def?: any) =>
- getSceneApi("oss", `${prev}${url}?_=${version}`)
- .then((url) => fetch(url))
- .then((res) => res.json())
- .catch(() => def);
- const config = await get(`/data/scene.json`, {
- version: 0,
- billboards: 0,
- tags: 0,
- });
- version = config.version;
- const [
- userFloorpan,
- floorplan,
- hots,
- billboards,
- ais,
- cadInfo,
- cad,
- traces,
- detects,
- ] = await Promise.all([
- get("/user/floorplan.json", {}),
- get("/data/floorplan.json", { floors: [] }),
- get("/user/hot.json", []),
- get("/user/billboards.json", []),
- get("/data/floorplan/ai.json", []),
- get("/data/floorplan/info.json", { floors: [] }),
- get("/data/floorplan_cad.json", { floors: [] }),
- get("/user/evidence.json", []),
- get("/images/ai/detect/detect-ai.json", []),
- ]);
- return {
- userFloorpan,
- hots,
- billboards,
- ais,
- floorplan,
- cad,
- cadInfo,
- config,
- traces,
- detects,
- };
- },
- 150000
- );
- export const getFloors = async (scene: Scene) => {
- const { floorplan } = await fetchResource(scene);
- return floorplan.floors;
- };
- export const getCoverLine = async (
- scene: Scene,
- subgroup: any,
- scale: number
- ) => {
- const { cadInfo, cad } = await fetchResource(scene);
- const floors = cad.floors;
- let info: CoverLine;
- const reqs: Promise<any>[] = [];
- for (let i = 0; i < floors.length; i++) {
- const floor = floors[i];
- if (floor.subgroup !== subgroup) continue;
- const floorInfo = cadInfo.floors.find(
- (item: any) => item.subgroup === floor.subgroup
- );
- const geos = extractConnectedSegments(floor.segment).map((geo) => {
- return geo.map((id) => {
- const p = floor["vertex-xy"].find((item: any) => item.id === id);
- return { x: p.x * scale, y: -p.y * scale, key: id.toString() };
- });
- });
- let bound = {
- ...(floor.cadInfo.cadBoundingBox || {}),
- ...floorInfo?.bound,
- };
- if (!bound || !("x_max" in bound)) {
- const xs = geos.flatMap((item) => item.map((p) => p.x));
- const ys = geos.flatMap((item) => item.map((p) => p.y));
- bound = {
- x_min: Math.min(...xs),
- x_max: Math.max(...xs),
- y_min: Math.min(...ys),
- y_max: Math.max(...ys),
- };
- } else {
- bound = {
- x_min: bound.x_min * scale,
- x_max: bound.x_max * scale,
- y_min: bound.y_min * scale,
- y_max: bound.y_max * scale,
- };
- }
- const item = {
- name: floor.name,
- subgroup: Number(floor.subgroup),
- thumb: "",
- bound,
- geos,
- };
- info = item;
- reqs.push(
- getSceneApi(
- "oss",
- `${scene.mapping ? "/" + scene.mapping : ""}/scene_view_data/${
- scene.m
- }/data/floorplan/floor_${floor.subgroup}.png`
- )
- .then((url) => (item.thumb = url))
- .catch(() => {})
- );
- }
- await Promise.all(reqs);
- return info!;
- };
- export const getCompass = async (scene: Scene) => {
- const { config, userFloorpan } = await fetchResource(scene);
- return "compass" in userFloorpan
- ? userFloorpan?.compass
- : MathUtils.radToDeg(Number(config.orientation || 0));
- };
- export const getHotTaggingInfos = async (scene: Scene, scale: number) => {
- const { hots } = await fetchResource(scene);
- const infos: TaggingInfo[] = [];
- const reqs: Promise<any>[] = [];
- for (const hot of hots) {
- if (!validNum(hot.position.x) || !validNum(hot.position.y)) continue;
- reqs.push(
- getSceneApi(
- "oss",
- `${scene.mapping ? "/" + scene.mapping : ""}/scene_view_data/${
- scene.m
- }/user/${hot.icon}`
- )
- .then((url) =>
- infos.push({
- position: { x: hot.position.x * scale, y: hot.position.y * scale },
- url,
- })
- )
- .catch(() => {})
- );
- }
- await Promise.all(reqs);
- return infos;
- };
- const getTraceAttri = async (icon: string, trace: any) => {
- const size = {
- width: trace.visiSetting.scale,
- height: trace.visiSetting.scale,
- };
- const attrib: any = {
- url: icon,
- size,
- angle: trace.visiSetting.angle,
- };
- if (trace.iconType === 2 || !trace.tag3d?.object) {
- return attrib;
- }
- const getPath = (children: any, name: string): any[] | undefined => {
- for (const item of children) {
- if (item.name === name) {
- return [item];
- } else if (item.children) {
- const childPath = getPath(item.children, name);
- if (childPath) {
- return [item, ...childPath];
- }
- }
- }
- };
- const path = getPath([trace.tag3d.object], "sprite");
- if (!path) return attrib;
- const mat = new Matrix4();
- for (const node of path) {
- mat.multiply(new Matrix4(...(node.matrix as Matrix4Tuple)));
- }
- const position = new Vector3();
- const quat = new Quaternion();
- const scale = new Vector3();
- mat.decompose(position, quat, scale);
- const euler = new Euler().setFromQuaternion(quat, "XYZ");
- return {
- ...attrib,
- angle: MathUtils.radToDeg(euler.y),
- };
- };
- // 痕迹物证
- export const getTraceTaggingInfos = async (
- scene: Scene,
- scale: number,
- floorIndex: number
- ) => {
- const { traces } = await fetchResource(scene);
- const infos: TaggingInfo[] = [];
- const reqs: Promise<any>[] = [];
- for (const trace of traces) {
- if (
- !validNum(trace.position?.x) ||
- !validNum(trace.position?.z) ||
- ("floorIndex" in trace && trace.floorIndex !== floorIndex) ||
- trace.iconType === 0
- )
- continue;
- const isSys = trace.icon.indexOf("/") > -1;
- const icon = isSys
- ? trace.icon.substring(trace.icon.lastIndexOf("/") + 1)
- : trace.icon;
- const styleMap = (traceIconMap as any)[icon];
- if (!icon) continue;
- const getIcon = isSys
- ? styleMap
- ? Promise.resolve(`./icons/${styleMap}.svg`)
- : getSceneApi("./", `./traces/${icon}.svg`)
- : getSceneApi(
- "oss",
- `${scene.mapping ? "/" + scene.mapping : ""}/scene_edit_data/${
- scene.m
- }/user/${icon}`
- );
- const name = (styleMap && getIconItem(styleMap)?.name) || "";
- const getAttr = getIcon.then(async (url) => getTraceAttri(url, trace));
- reqs.push(
- getAttr
- .then((attr) => ({
- url: attr.url,
- name: trace.title || name,
- position: {
- x: trace.position.x * scale,
- y: trace.position.z * scale,
- z:
- trace.position.y < 0
- ? Math.ceil(trace.position.y * scale * 10) / 10
- : Math.floor(trace.position.y * scale * 10) / 10,
- },
- key: "trace",
- rotate: attr.angle,
- size: {
- width: attr.size.width * scale,
- height: attr.size.height * scale,
- },
- }))
- .then((info) => infos.push(info))
- .catch(() => {})
- );
- }
- await Promise.all(reqs);
- return infos;
- };
- const getBillYaw = (bill: any) => {
- function isLieDown(quaternion: Quaternion) {
- let direction = new Vector3(0, 0, -1).applyQuaternion(quaternion);
- return Math.abs(direction.y) > 0.9;
- }
- let billboard = new Object3D();
- let plane = new Object3D();
- billboard.add(plane);
- billboard.quaternion
- .copy({ x: bill.qua[0], y: bill.qua[1], z: bill.qua[2], w: bill.qua[3] })
- .normalize(); //qua数据里的
- plane.quaternion.setFromAxisAngle(
- new Vector3(0, 0, 1),
- MathUtils.degToRad(-bill.faceAngle)
- );
- const up = new Vector3(0, 1, 0); //plane的上方指示着方向
- const right = new Vector3(1, 0, 0); //令躺倒时的旋转轴
- let qua = plane.getWorldQuaternion(new Quaternion());
- const ld = isLieDown(billboard.quaternion);
- if (!ld) {
- //使朝其后方躺倒后再求angle
- let rotAxis = right.clone().applyQuaternion(qua); //旋转轴
- (rotAxis.y = 0), rotAxis.normalize();
- let rot = new Quaternion().setFromAxisAngle(rotAxis, Math.PI / 2);
- qua.premultiply(rot);
- }
- let dir = up.clone().applyQuaternion(qua); //在墙面朝x时正反得到的一样,很奇怪,所以得到的会反向
- let yaw = Math.atan2(-dir.z, dir.x) - Math.PI / 2;
- return -yaw;
- };
- export const getBillTaggingInfos = async (
- scene: Scene,
- scale: number,
- subgroup: number
- ) => {
- const { billboards } = await fetchResource(scene);
- const infos: TaggingInfo[] = [];
- const reqs: Promise<any>[] = [];
- for (const bill of billboards) {
- if (
- !validNum(bill.pos[0]) ||
- !validNum(bill.pos[2]) ||
- ("subgroup" in bill && bill.subgroup !== subgroup)
- )
- continue;
- const styleMap = (styleIconMap as any)[bill.icon];
- const getIcon =
- bill.icon.indexOf("style-") === 0
- ? styleMap
- ? Promise.resolve(`./icons/${styleMap}.svg`)
- : getSceneApi("./", `./styles/${bill.icon}.svg`).catch((e) => {
- return getSceneApi(
- "ossRoot",
- `/sdk/images/billboard/${bill.icon}.png`
- );
- })
- : getSceneApi(
- "oss",
- `${scene.mapping ? "/" + scene.mapping : ""}/scene_view_data/${
- scene.m
- }/user/${bill.icon}`
- );
- const yRotate = getBillYaw(bill);
- const name = (styleMap && getIconItem(styleMap)?.name) || "";
- reqs.push(
- getIcon
- .then((url) => ({
- url,
- name,
- position: {
- x: bill.pos[0] * scale,
- y: bill.pos[2] * scale,
- z:
- bill.pos[1] < 0
- ? Math.ceil(bill.pos[1] * scale * 10) / 10
- : Math.floor(bill.pos[1] * scale * 10) / 10,
- },
- rotate: yRotate,
- size: {
- width: bill.width * scale,
- height: bill.height * scale,
- },
- }))
- .then((info) => infos.push(info))
- .catch(() => {})
- );
- }
- await Promise.all(reqs);
- return infos;
- };
- export const getAITaggingInfos = async (
- scene: Scene,
- subgroup: any,
- bound: Record<string, number>
- ) => {
- const { ais } = await fetchResource(scene);
- const infos: TaggingInfo[] = [];
- const drawBound = {
- x: bound.x_min,
- y: bound.y_min,
- w: bound.x_max - bound.x_min,
- h: bound.y_max - bound.y_min,
- };
- for (const data of ais) {
- if (data.imagePath) {
- const reg = data.imagePath.match(/floor_(\d)\.png/);
- const curSubgroup = reg ? Number(reg[1]) : undefined;
- if (curSubgroup !== subgroup) continue;
- }
- for (const shape of data.shapes) {
- const icon =
- shape.category in aiIconMap
- ? (aiIconMap as any)[shape.category]
- : shape.category;
- const itemIcon = getIconItem(icon);
- const isWall = itemIcon && "wall" in itemIcon ? itemIcon.wall : false;
- if (isWall) continue;
- const name = itemIcon?.name || "";
- const isTag = icon === "Tag";
- if (!name && !isTag) continue;
- const pixelCenter = {
- x: (shape.bbox[0] + shape.bbox[2]) / 2 / data.imageWidth,
- y: (shape.bbox[1] + shape.bbox[3]) / 2 / data.imageHeight,
- };
- const center = {
- x: pixelCenter.x * drawBound.w + drawBound.x,
- y: pixelCenter.y * drawBound.h + drawBound.y,
- };
- const size = {
- width:
- ((shape.bbox[2] - shape.bbox[0]) / data.imageWidth) * drawBound.w,
- height:
- ((shape.bbox[3] - shape.bbox[1]) / data.imageHeight) * drawBound.h,
- };
- infos.push({
- isText: isTag,
- position: center,
- rotate: 0,
- url: isTag ? shape.name : `./icons/${icon ? icon : "circle"}.svg`,
- name,
- size,
- });
- }
- }
- return infos;
- };
- export const getAIBorderTaggingInfos = async (
- scene: Scene,
- subgroup: any,
- bound: Record<string, number>,
- scale: number
- ) => {
- const { detects } = await fetchResource(scene);
- const infos: BorderTaggingInfo[] = [];
- const drawBound = {
- x: bound.x_min,
- y: bound.y_min,
- w: bound.x_max - bound.x_min,
- h: bound.y_max - bound.y_min,
- };
- // console.log(drawBound);
- for (const shape of detects) {
- // if (data.imagePath) {
- // const reg = data.imagePath.match(/floor_(\d)\.png/);
- // const curSubgroup = reg ? Number(reg[1]) : undefined;
- // if (curSubgroup !== subgroup) continue;
- // }
- const min = { x: shape.bbox[0][0], y: shape.bbox[0][2] };
- const max = { x: shape.bbox[0][0], y: shape.bbox[0][2] };
- for (const box of shape.bbox) {
- min.x = Math.min(box[0], min.x);
- min.y = Math.min(box[2], min.y);
- max.x = Math.max(box[0], max.x);
- max.y = Math.max(box[2], max.y);
- }
- min.x *= scale;
- min.y *= scale;
- max.x *= scale;
- max.y *= scale;
- const center = {
- x: (min.x + max.x) / 2,
- y: (min.y + max.y) / 2,
- };
- const size = {
- width: max.x - min.x,
- height: max.y - min.y,
- };
- infos.push({
- text: shape.name,
- points: [
- { x: center.x - size.width / 2, y: center.y - size.height / 2 },
- { x: center.x + size.width / 2, y: center.y - size.height / 2 },
- { x: center.x + size.width / 2, y: center.y + size.height / 2 },
- { x: center.x - size.width / 2, y: center.y + size.height / 2 },
- ],
- center,
- });
- }
- return infos;
- };
- export const getWallAITaggingInfos = async (
- scene: Scene,
- subgroup: any,
- scale: number,
- cover: CoverLine
- ) => {
- const { floorplan } = await fetchResource(scene);
- const infos: WallTaggingInfo[] = [];
- const getCoverLine = (wall: Pos[]) => {
- type Info = { p: Pos & { key: string }; len: number };
- const infos: { start: Info; end: Info; inv: boolean }[] = [];
- for (let i = 0; i < cover.geos.length; i++) {
- const geo = cover.geos[i];
- for (let j = 0; j < geo.length - 1; j++) {
- const len00 = lineLen(geo[j], wall[0]);
- const len10 = lineLen(geo[j + 1], wall[0]);
- const len01 = lineLen(geo[j], wall[1]);
- const len11 = lineLen(geo[j + 1], wall[1]);
- let start: Info, end: Info, inv: boolean;
- if (len00 + len11 < len10 + len01) {
- inv = false;
- start = { p: geo[j], len: len00 };
- end = { p: geo[j + 1], len: len11 };
- } else {
- inv = true;
- start = { p: geo[j + 1], len: len10 };
- end = { p: geo[j], len: len01 };
- }
- if (zeroEq(start.len) && zeroEq(end.len)) {
- return { points: [start.p, end.p], inv };
- }
- infos.push({ start, end, inv });
- }
- }
- const sortInfos = [...infos].sort(
- (a, b) => a.start.len + a.end.len - (b.start.len + b.end.len)
- );
- const target = sortInfos[0];
- if (target.start.len + target.end.len < 10) {
- return { points: [target.start.p, target.end.p], inv: target.inv };
- }
- };
- for (const floor of floorplan.floors) {
- if (floor.subgroup !== subgroup) continue;
- for (const key in floor.symbols) {
- const item = floor.symbols[key];
- const icon =
- item.geoType in aiIconMap
- ? (aiIconMap as any)[item.geoType]
- : item.geoType;
- const itemIcon = getIconItem(icon);
- let name = itemIcon?.name;
- const isWall = itemIcon && "wall" in itemIcon ? itemIcon.wall : false;
- if (!isWall) continue;
- const cadWall = [
- floor.points[floor.walls[item.parent].start],
- floor.points[floor.walls[item.parent].end],
- ].map((p) => ({
- x: p.x * scale,
- y: -p.y * scale,
- }));
- const wall = getCoverLine(cadWall);
- const line = [item.startPoint, item.endPoint].map((p) => ({
- x: p.x * scale,
- y: -p.y * scale,
- }));
- if (!wall) {
- continue;
- }
- const points = wall.inv ? wall.points.reverse() : wall.points;
- infos.push({
- name: name,
- url: `./icons/${icon ? icon : "circle"}.svg`,
- startLen: lineLen(points[0], line[0]),
- endLen: lineLen(points[0], line[1]),
- openSide: item.openSide,
- height: itemIcon?.parse?.height,
- type: itemIcon?.parse?.type || "full",
- pointIds: points.map((item) => item.key),
- });
- }
- }
- return infos;
- };
- export const getResource = async ({
- scene,
- floorName,
- syncs,
- scale,
- }: ResourceArgs) => {
- const data = await fetchResource(scene);
- const floorIndex = data.floorplan.floors.findIndex(
- (item: any) => item.name === floorName
- );
- const floor = data.floorplan.floors[floorIndex];
- const key = floor.subgroup;
- const taggings: TaggingInfo[] = [];
- const wallTaggings: WallTaggingInfo[] = [];
- const borderTaggings: BorderTaggingInfo[] = [];
- let coverLine: CoverLine;
- const compass = await getCompass(scene);
- console.log(compass);
- const reqs: Promise<any>[] = [
- getCompass(scene),
- getCoverLine(scene, key, scale)
- .then((lines) => (coverLine = lines))
- .then((cover) =>
- Promise.all([
- getWallAITaggingInfos(scene, key, scale, cover).then((ts) =>
- wallTaggings.push(...ts)
- ),
- getAITaggingInfos(scene, key, cover.bound).then((ts) =>
- taggings.push(...ts)
- ),
- getAIBorderTaggingInfos(scene, key, cover.bound, scale).then((ts) =>
- borderTaggings.push(...ts)
- ),
- ])
- ),
- ];
- if (syncs.includes("hot")) {
- reqs.push(
- getHotTaggingInfos(scene, scale).then((ts) => taggings.push(...ts))
- );
- }
- if (syncs.includes("signage")) {
- reqs.push(
- getBillTaggingInfos(scene, scale, key).then((ts) => taggings.push(...ts))
- );
- }
- if (syncs.includes("traces")) {
- reqs.push(
- getTraceTaggingInfos(scene, scale, floorIndex).then((ts) =>
- taggings.push(...ts)
- )
- );
- }
- await Promise.all(reqs);
- return {
- taggings: taggings,
- borderTaggings,
- wallTaggings,
- cover: coverLine!,
- compass: compass,
- } as SceneResource;
- };
|