Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

change visualization parameters #10

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 24 additions & 6 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from "react";
import clsx from "clsx";
import { makeStyles, Theme, createStyles } from "@material-ui/core/styles";
import { createStyles, makeStyles, Theme } from "@material-ui/core/styles";
import Drawer from "@material-ui/core/Drawer";
import AppBar from "@material-ui/core/AppBar";
import Toolbar from "@material-ui/core/Toolbar";
Expand All @@ -11,8 +11,8 @@ import MenuIcon from "@material-ui/icons/Menu";
import ChevronLeftIcon from "@material-ui/icons/ChevronLeft";
import ThreeCanvas from "./components/ThreeCanvas";
import Upload from "./components/Upload";
import BasicSettings from "./components/BasicSettings";
import RegionSettings from "./components/RegionSettings";
import GlobalSettings from "./components/GlobalSettings";
import RegionSettings, { Region } from "./components/RegionSettings";

const drawerWidth = 360;
const appBarHeight = 60;
Expand Down Expand Up @@ -74,6 +74,9 @@ const useStyles = makeStyles((theme: Theme) =>
export default function App() {
const classes = useStyles();
const [open, setOpen] = React.useState(true);
const [brightness, setBrightness] = React.useState(50);
const [cut, setCut] = React.useState(0);
const [regions, setRegions] = React.useState<Array<Region>>([]);

const handleDrawerOpen = () => {
setOpen(true);
Expand Down Expand Up @@ -124,16 +127,31 @@ export default function App() {
<Divider />

<Upload />
<BasicSettings />
<GlobalSettings
brightness={brightness}
cut={cut}
//@ts-ignore
onBrightnessChange={(event, newValue) =>
setBrightness(newValue as number)
}
//@ts-ignore
onCutChange={(event, newValue) => setCut(newValue as number)}
/>
<Divider />
<RegionSettings
regions={[]}
selectedRegions={regions}
selectableRegions={["maxilla", "jawbone"]}
onRegionsChange={setRegions}
/>
</Drawer>

<div className={classes.header} />
<ThreeCanvas appBarHeight={appBarHeight} />
<ThreeCanvas
appBarHeight={appBarHeight}
colorIntensity={brightness / 100}
opacity={regions.length > 0 ? regions[0].transparency / 100 : 0.8}
Comment on lines +151 to +152
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Według mnie lepiej przekazywać brightness itransperency od razu w procentach, żeby w przypadku jeśli będziemy chcieli jeszcze gdzieś tego użyć nie musieliśmy znowu dzielić przez 100.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Slider przechowuje wartości 0-100, więc chyba lepiej tak jak jest zostawic.

radius={cut / 50}
/>
</div>
);
}
33 changes: 0 additions & 33 deletions src/components/BasicSettings.tsx

This file was deleted.

12 changes: 8 additions & 4 deletions src/components/ColorPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@ import styled from "styled-components";

interface ColorPickerProps {
regionId: string;
color: RGBColor;
rgbColor: RGBColor;
onChange: (id: string, color: RGBColor) => void;
}

export default function ColorPicker(props: ColorPickerProps) {
export default function ColorPicker({
regionId,
rgbColor,
onChange,
}: ColorPickerProps) {
const [display, setDisplay] = useState(false);
const [color, setColor] = useState(props.color);
const [color, setColor] = useState(rgbColor);

const PickerFrame = styled.div`
padding: 5px;
Expand All @@ -30,7 +34,7 @@ export default function ColorPicker(props: ColorPickerProps) {
`;

const handleClick = () => {
display && props.onChange(props.regionId, color);
display && onChange(regionId, color);
setDisplay(!display);
};

Expand Down
57 changes: 57 additions & 0 deletions src/components/GlobalSettings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React, { FormEventHandler } from "react";
import Typography from "@material-ui/core/Typography";
import BrightnessHighIcon from "@material-ui/icons/BrightnessHigh";
import BrightnessLowIcon from "@material-ui/icons/BrightnessLow";
import AddIcon from "@material-ui/icons/Add";
import RemoveIcon from "@material-ui/icons/Remove";
import ContinuousSlider from "./Slider";
import styled from "styled-components";

interface GlobalSettingsProps {
brightness: number;
onBrightnessChange: ((
event: React.ChangeEvent<{}>,
value: number | number[]
) => void) &
FormEventHandler<HTMLSpanElement>;
cut: number;
onCutChange: ((
event: React.ChangeEvent<{}>,
value: number | number[]
) => void) &
FormEventHandler<HTMLSpanElement>;
}

export default function GlobalSettings({
brightness,
onBrightnessChange,
cut,
onCutChange,
}: GlobalSettingsProps) {
const GlobalSettingsDiv = styled.div`
width: 320px;
padding: 20px;
`;

return (
<GlobalSettingsDiv>
<Typography>
<h2>Global Settings</h2>
</Typography>
<ContinuousSlider
title="Brightness"
leftIcon={<BrightnessLowIcon />}
rightIcon={<BrightnessHighIcon />}
value={brightness}
onChange={onBrightnessChange}
/>
<ContinuousSlider
title="Cut"
leftIcon={<RemoveIcon />}
rightIcon={<AddIcon />}
value={cut}
onChange={onCutChange}
/>
</GlobalSettingsDiv>
);
}
18 changes: 12 additions & 6 deletions src/components/RegionSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import ColorPicker from "./ColorPicker";
import { RGBColor } from "react-color";
import styled from "styled-components";

interface Region {
export interface Region {
id: string;
type: string;
transparency: number;
Expand All @@ -23,12 +23,17 @@ interface Region {
}

interface RegionSettingsProps {
regions: Array<Region>;
selectedRegions: Array<Region>;
selectableRegions: Array<string>;
onRegionsChange: (regions: Array<Region>) => void;
}

export default function RegionSettings(props: RegionSettingsProps) {
const [regions, setRegions] = React.useState<Array<Region>>(props.regions);
export default function RegionSettings({
selectedRegions,
selectableRegions,
onRegionsChange,
}: RegionSettingsProps) {
const [regions, setRegions] = React.useState<Array<Region>>(selectedRegions);
const addNewRegion = (e: MouseEvent<HTMLButtonElement>) => {
setRegions([
...regions,
Expand Down Expand Up @@ -78,6 +83,7 @@ export default function RegionSettings(props: RegionSettingsProps) {
r.id === id ? { ...r, transparency: newValue } : r
);
setRegions(newRegions);
onRegionsChange(newRegions);
};

function handleColorChange(id: string, newColor: RGBColor) {
Expand Down Expand Up @@ -149,7 +155,7 @@ export default function RegionSettings(props: RegionSettingsProps) {
<MenuItem value="None">
<em>None</em>
</MenuItem>
{props.selectableRegions.map((x) => (
{selectableRegions.map((x) => (
<MenuItem value={x}>{x}</MenuItem>
))}
</Select>
Expand All @@ -164,7 +170,7 @@ export default function RegionSettings(props: RegionSettingsProps) {
<Grid item xs={3}>
<ColorPicker
regionId={region.id}
color={region.color}
rgbColor={region.color}
onChange={handleColorChange}
/>
</Grid>
Expand Down
18 changes: 7 additions & 11 deletions src/components/Slider.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,21 @@
import Grid from "@material-ui/core/Grid";
import Slider from "@material-ui/core/Slider";
import Slider, { SliderProps } from "@material-ui/core/Slider";
import Typography from "@material-ui/core/Typography";
import React, { SVGProps } from "react";

type SliderProps = {
export interface ContinuousSliderProps extends SliderProps {
title: string;
leftIcon: SVGProps<SVGElement>;
rightIcon: SVGProps<SVGElement>;
};
}

export default function ContinuousSlider({
title,
leftIcon,
rightIcon,
}: SliderProps) {
const [value, setValue] = React.useState<number>(50);

const handleChange = (event: unknown, newValue: number | number[]) => {
setValue(newValue as number);
};

value,
onChange,
}: ContinuousSliderProps) {
return (
<div>
<Typography id="continuous-slider" gutterBottom>
Expand All @@ -30,7 +26,7 @@ export default function ContinuousSlider({
<Grid item xs>
<Slider
value={value}
onChange={handleChange}
onChange={onChange}
aria-labelledby="continuous-slider"
/>
</Grid>
Expand Down
71 changes: 64 additions & 7 deletions src/components/ThreeCanvas.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,76 @@
import { Suspense, useEffect, useState } from "react";
import { Canvas, useLoader } from "@react-three/fiber";
import { Canvas, useLoader, useThree } from "@react-three/fiber";
import { OrbitControls } from "@react-three/drei";
import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader";
import styled from "styled-components";
import * as THREE from "three";
import { Plane, Vector3 } from "three";

const Model = () => {
interface ModelProps {
opacity: number;
radius: number;
}

interface ClippingPlaneProps {
startPoint: number;
radius: number;
}

function ClippingPlane(props: ClippingPlaneProps) {
const { gl } = useThree();
let plane = new Plane(new Vector3(0, 0, -1), props.startPoint - props.radius);
gl.clippingPlanes = [plane];
gl.localClippingEnabled = true;
return <></>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nie powinnaś zwracać Plane?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nie. Wystarczy, by funkcja się uruchomiła.

}

function Model(props: ModelProps) {
const obj = useLoader(OBJLoader, "skull.OBJ");
return <primitive object={obj} scale={0.6} position={[0, -1.5, 0]} />;
};
var startPoint = 0;
obj.traverse(function (child) {
if (child instanceof THREE.Mesh) {
const material = child.material;
material.transparent = true;
material.opacity = props.opacity;
child.material = material;
const xPoints = child.geometry.attributes.position.array.filter(
(element: number, index: number) => index % 3 === 0
);
startPoint = findMax(xPoints);
}
});

return (
<>
<primitive object={obj} scale={0.6} position={[0, -1.5, 0]} />
<ClippingPlane startPoint={startPoint} radius={props.radius} />
</>
);

function findMax(xPoints: Array<number>) {
let max = xPoints[0];
for (let i = 1; i < xPoints.length; ++i) {
if (xPoints[i] > max) {
max = xPoints[i];
}
}
return max;
}
}

interface ThreeCanvasProps {
appBarHeight: number;
colorIntensity: number;
opacity: number;
radius: number;
}

export default function ThreeCanvas({ appBarHeight }: ThreeCanvasProps) {
export default function ThreeCanvas({
appBarHeight,
colorIntensity,
opacity,
radius,
}: ThreeCanvasProps) {
const [dimensions, setDimensions] = useState({
height: window.innerHeight,
width: window.innerWidth,
Expand Down Expand Up @@ -46,11 +103,11 @@ export default function ThreeCanvas({ appBarHeight }: ThreeCanvasProps) {
}}
>
<Suspense fallback={null}>
<ambientLight intensity={0.2} />
<ambientLight intensity={colorIntensity} />
<pointLight position={[10, 10, 10]} />
<pointLight position={[-10, -10, -10]} />
<OrbitControls />
<Model />
<Model opacity={opacity} radius={radius} />
</Suspense>
</StyledCanvas>
);
Expand Down