"use client"
import { Canvas } from '@react-three/fiber'
import { OrbitControls } from '@react-three/drei'
import { Leva, useControls } from 'leva'
import { useMemo, StrictMode } from 'react'
import * as THREE from 'three'

export const BasementWall = ({ width, wallThk, slabThk, slabElevs }) => {
  const tw = wallThk / 12
  const wallHeight = Math.max(...slabElevs) - Math.min(...slabElevs)
  const slabWidth = 6 + tw
  const ftgThk = 1 + tw
  const ftgWidth = 2 * ftgThk

  return (
    <group>
      {/* Main wall */}
      <mesh position={[0, (wallHeight - slabThk) / 2, 0]}>
        <boxGeometry args={[width, wallHeight - slabThk, tw]} />
        <meshStandardMaterial color="#8b8c89" />
      </mesh>

      {/* Footing */}
      <mesh position={[0, -ftgThk / 2, (tw - ftgWidth) / 2]}>
        <boxGeometry args={[width, ftgThk, ftgWidth]} />
        <meshStandardMaterial color="#a8a9ad" />
      </mesh>

      {/* Slabs */}
      {slabElevs
        .filter((e) => e != 0)
        .map((elev) => (
          <mesh key={elev} position={[0, elev - slabThk / 2, -slabWidth / 2 + tw / 2]}>
            <boxGeometry args={[width * 1.01, slabThk, slabWidth * 1.01]} />
            <meshStandardMaterial color="#a8a9ad" />
          </mesh>
        ))}
    </group>
  )
}

export const Triangle = ({ vertices, color = '#5243aa' }) => {
  let convertedVertices = vertices.map((v) => new THREE.Vector3(...v))

  const f32array = useMemo(() => Float32Array.from(new Array(convertedVertices.length).fill().flatMap((item, index) => convertedVertices[index].toArray())), [vertices])

  return (
    <mesh position={[0, 0, 0]}>
      <bufferGeometry attach="geometry">
        <bufferAttribute attachObject={['attributes', 'position']} args={[f32array, 3]} />
      </bufferGeometry>
      <meshBasicMaterial attach="material" color={color} wireframe={false} side={THREE.DoubleSide} />
    </mesh>
  )
}

export const LateralEarthPressure = ({ qH, qE, slabElevs, wallThk }) => {
  //make qh ~ 1/3 of H for visibility
  const SF = 10 / Math.max(qH, qE)
  const H = Math.max(...slabElevs)
  const offset = wallThk / 12
  const vertices1 = [
    [-2, 0, offset],
    [-2, H, offset],
    [-2, 0, SF * qH + offset]
  ]
  const vertices2 = [
    [2, 0, offset],
    [2, H, offset],
    [2, H, SF * qE + offset]
  ]
  return (
    <>
      <Triangle vertices={vertices2} color="red" />
      <Triangle vertices={vertices1} color="blue" />
    </>
  )
}

export function Experience() {
  const { width, wallThk, numFloors, floorHeight, slabThk, qH, qE } = useControls({
    slabThk: 1,
    width: { value: 10, min: 1, max: 50, step: 1 },
    wallThk: { value: 12, min: 6, max: 60, step: 1 },
    numFloors: { options: [1, 2, 3, 4, 5, 6, 7, 8], value: 3 },
    floorHeight: { value: 10, min: 1, max: 50, step: 1 / 12 },
    qH: { value: 10, min: 0, max: 50, step: 1 },
    qE: { value: 5, min: 0, max: 50, step: 1 }
  })
  let slabElevs = []
  for (let aa = 0; aa < numFloors + 1; aa++) {
    slabElevs.push(aa * floorHeight)
  }
  const Hw = Math.max(...slabElevs)
  const midpoint = [0, Hw / 2, 0]
  const position = [100, 50, 25]
  const props = { width, wallThk, numFloors, floorHeight, slabThk, slabElevs, qH, qE }

  return <>
    <color attach="background" args={['#2a2b2d']} />
    <ambientLight intensity={Math.PI / 2} />
    <BasementWall {...props} />
    <LateralEarthPressure {...props} />
    <OrbitControls enableDamping dampingFactor={0.25} target={midpoint} />
    <gridHelper args={[width + 10, width + 10, '#888888', '#444444']} />
    <axesHelper args={[5]} />
  </>
}

export default function App() {
  return (
    <StrictMode>
      <Leva flat />
      <Canvas camera={{ fov: 45, near: 0.1, far: 200, position: [100, 50, 25] }}>
        <Experience />
      </Canvas>
    </StrictMode>
  )
}

Comments (0)

Loading comments...