Skip to content

Commit cc57bb1

Browse files
authored
Merge pull request #9 from MetacityTools/dev
Release version 0.1.0
2 parents bcf388f + fa746e1 commit cc57bb1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+1518
-660
lines changed

README.md

Lines changed: 60 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,64 @@
1-
# 🏡 Metacity Studio
1+
# 🏡 [Metacity Studio](https://studio.metacity.cc)
22

33
![Screenshot](src/assets/splash/screen.png)
44

55
Metacity Studio is an online tool for integrating and visualizing spatial and tabular data.
66

7-
## How does it work?
8-
9-
Open the app, upload your data, see what's there. That's it.
7+
Running at [studio.metacity.cc](https://studio.metacity.cc)
108

11-
The application is front-end only, all the data processing is done in the browser.
9+
## How does it work?
1210

13-
It may seem crazy, mangling large datasets in the browser, computing geometry and on top of that, rendering it all in a 3D environment.
11+
Prepare urban visualizations online. Load your data, align it, and export it for viewing online.
1412

15-
Only time will tell if this is a good idea.
13+
- works best with small to medium-sized datasets
14+
- allows yout to connect 3D models and tabular data
1615

1716
## What formats can you load in?
1817

1918
Currently:
2019

21-
- SHP (Polygons and MultiPatch only)
20+
- SHP (Polygons and MultiPatch only for now)
2221
- IFC
2322
- GLTF (triangles only)
2423

2524
## Roadmap
2625

27-
- [x] Grid in the background
28-
- [x] Translucent models to see wirefame in the background
29-
- [x] Snap vertices
30-
- [x] Translation - scale - rotate
31-
- [x] Split models
32-
- [x] Hide models
33-
- [x] Delete model
26+
The project is in active development. The roadmap is as follows:
27+
28+
### v0.1.2
29+
30+
- [ ] Connect tabular data
31+
- [ ] Project export
32+
- [ ] Project import
33+
34+
### v0.1.1
35+
36+
- [ ] Baking/Transforming models to Table-like format
37+
- [ ] Allow labeling geometry
38+
39+
### v0.1.0 - 👨‍💻 In progress
40+
41+
- [x] Rectangular select
42+
- [x] Merge submodels
43+
- [x] Delete selected submodel
44+
- [x] Context Help
45+
46+
### v0.0.4 - ✅ Released
47+
48+
- [x] Removed IFC metadata loading to optimize memory usage
49+
50+
### v0.0.3 - ✅ Released
51+
52+
- [x] Selecting alignment for loaded models
53+
- [x] Worker pool for loading
54+
- [x] Status - counter, update global loading status
55+
- [x] Reading metadata from IFC files - inspeciton of metadata?
56+
- [x] CI na githubu autodeploy
57+
- [x] Uniforms copy on model add
58+
- [x] Rotate Splash screen bug
59+
60+
### v0.0.2 - ✅ Released
61+
3462
- [x] Loading SHP - _needs our own library to load, noone supports multipatch_
3563
- [x] BVH build into worker
3664
- [x] Loading screen + Add chicken
@@ -39,26 +67,22 @@ Currently:
3967
- [x] Redesign
4068
- [x] Sidepanel view settings
4169
- [x] Intro screen
42-
- [x] Selecting alignment for loaded models
43-
- [x] Worker pool for loading
44-
- [x] Status - counter, update global loading status
45-
- [x] Reading metadata from IFC files - inspeciton of metadata?
46-
- [x] CI na githubu autodeploy
47-
- [x] Uniforms copy on model add
48-
- [x] Rotate Splash screen bug
49-
- [ ] Loading points and lines from SHP
50-
- [ ] Loading GeoJSON
51-
- [ ] Project export
52-
- [ ] Project import
53-
- [ ] Allow labeling geometry
54-
- [ ] delete selected submodel
55-
- [ ] merge submodels
5670

57-
### Backlog
71+
### v0.0.1 - ✅ Released
5872

59-
- [ ] IFC metadata loading (memory-efficiency???)
60-
- [ ] BVH
61-
- [ ] remesh models - intersection of triangles
62-
- [ ] delete submodel - _for now as (split + delete)_
63-
- [ ] frustum culling
64-
- [ ] rectangular select
73+
- [x] Grid in the background
74+
- [x] Translucent models to see wirefame in the background
75+
- [x] Snap vertices
76+
- [x] Translation - scale - rotate
77+
- [x] Split models
78+
- [x] Hide models
79+
- [x] Delete model
80+
81+
## Backlog
82+
83+
- [ ] Merge whole models
84+
- [ ] Loading points and lines from SHP
85+
- [ ] Loading GeoJSON
86+
- [ ] Loading IFC metadata loading (memory-efficiency???)
87+
- [ ] Remesh models - intersection of triangles
88+
- [ ] Frustum culling

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "metacity-studio",
33
"private": true,
4-
"version": "0.0.4",
4+
"version": "0.1.0",
55
"type": "module",
66
"scripts": {
77
"dev": "vite",
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import React from 'react';
2+
3+
import { EditorModel } from '@utils/models/models/EditorModel';
4+
5+
import * as GL from '@bananagl/bananagl';
6+
7+
import { EditorContext } from '../Context';
8+
9+
function primitiveIndicesToSubmodelIndices(object: EditorModel, indices: number[]) {
10+
const submodel = object.attributes.getAttribute('submodel') as GL.Attribute;
11+
const submodelIds = submodel.buffer.getView(Uint32Array);
12+
const submodelIDs = new Set<number>();
13+
for (const idx of indices) submodelIDs.add(submodelIds[idx * 3]);
14+
return Array.from(submodelIDs);
15+
}
16+
17+
function selectionFlags(multiselect: boolean, shiftKey: boolean) {
18+
let toggle = false;
19+
let extend = false;
20+
21+
if (multiselect) {
22+
if (shiftKey) extend = true;
23+
else toggle = true;
24+
} else if (shiftKey) toggle = true;
25+
return { toggle, extend };
26+
}
27+
28+
export function Canvas(props: { canvasRef: React.RefObject<HTMLCanvasElement> }) {
29+
const ctx = React.useContext(EditorContext);
30+
31+
function handlePick(object: EditorModel, indices: number | number[], shiftKey: boolean) {
32+
const multiselect = Array.isArray(indices);
33+
const arrIdxs = multiselect ? indices : [indices];
34+
const submodelIDs = primitiveIndicesToSubmodelIndices(object, arrIdxs);
35+
let { toggle, extend } = selectionFlags(multiselect, shiftKey);
36+
ctx.select(object as EditorModel, submodelIDs, toggle, extend);
37+
}
38+
39+
const handleWheel = (event: WheelEvent) => {
40+
event.preventDefault();
41+
};
42+
43+
React.useEffect(() => {
44+
const canvas = props.canvasRef.current;
45+
if (!canvas) return;
46+
canvas.addEventListener('wheel', handleWheel);
47+
return () => {
48+
canvas.removeEventListener('wheel', handleWheel);
49+
};
50+
}, [props.canvasRef]);
51+
52+
return (
53+
<canvas
54+
ref={props.canvasRef}
55+
key="canvas"
56+
tabIndex={1000}
57+
className="w-full h-full outline-none"
58+
onPointerDown={(e) => {
59+
ctx.renderer.windowNullable?.controls?.pointerDown(e.nativeEvent);
60+
}}
61+
onPointerMove={(e) => {
62+
ctx.renderer.windowNullable?.controls?.pointerMove(e.nativeEvent);
63+
}}
64+
onPointerUp={(e) => {
65+
const selection = ctx.renderer.windowNullable?.controls?.pointerUp(e.nativeEvent);
66+
const shift = ctx.renderer.windowNullable?.controls?.keyboard.keyMap.shift ?? false;
67+
if (selection)
68+
handlePick(selection.object as EditorModel, selection.primitiveIndices, shift);
69+
}}
70+
onWheel={(e) => {
71+
ctx.renderer.windowNullable?.controls?.wheel(e.nativeEvent);
72+
}}
73+
onPointerOut={(e) => {
74+
ctx.renderer.windowNullable?.controls?.pointerOut(e.nativeEvent);
75+
}}
76+
onContextMenu={(e) => {
77+
ctx.renderer.windowNullable?.controls?.contextMenu(e.nativeEvent);
78+
}}
79+
/>
80+
);
81+
}

src/Components/Editor/Canvas.tsx renamed to src/Components/Editor/Canvas/CanvasWrapper.tsx

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ import { GridModel } from '@utils/models/models/GridModel';
44

55
import * as GL from '@bananagl/bananagl';
66

7-
import { EditorContext } from './Context';
7+
import { EditorContext } from '../Context';
8+
import { Canvas } from './Canvas';
89

9-
export function Canvas() {
10+
export function CanvasWrapper() {
1011
const canvasRef = React.useRef<HTMLCanvasElement>(null);
1112
const ctx = React.useContext(EditorContext);
1213

1314
React.useEffect(() => {
14-
if (!ctx) return;
1515
const { renderer, scene } = ctx;
1616

1717
if (canvasRef.current && renderer) {
@@ -35,23 +35,25 @@ export function Canvas() {
3535
scene.add(grid);
3636
renderer.clearColor = [1, 1, 1, 1];
3737

38+
const down = (e: KeyboardEvent) => {
39+
renderer.window.controls.keydown(e);
40+
};
41+
42+
const up = (e: KeyboardEvent) => {
43+
renderer.window.controls.keyup(e);
44+
};
45+
46+
document.addEventListener('keydown', down);
47+
document.addEventListener('keyup', up);
48+
3849
return () => {
50+
document.removeEventListener('keydown', down);
51+
document.removeEventListener('keyup', up);
3952
GL.unmountRenderer(renderer);
4053
scene.remove(grid);
4154
};
4255
}
43-
}, [ctx?.renderer, ctx?.scene]);
44-
45-
return (
46-
<canvas
47-
ref={canvasRef}
48-
key="canvas"
49-
tabIndex={1000}
50-
style={{
51-
width: '100%',
52-
height: '100%',
53-
outline: 'none',
54-
}}
55-
/>
56-
);
56+
}, [ctx.renderer, ctx.scene]);
57+
58+
return <Canvas canvasRef={canvasRef} />;
5759
}

0 commit comments

Comments
 (0)