diff --git a/src/app/page.tsx b/src/app/page.tsx
index c1f0f14..f1f3106 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -6,6 +6,7 @@ import { Paths, Poses } from "@/hooks/use-visualizer";
import PoseControls from "@/components/pose-controls";
import DrawPaths from "@/components/path-overlay";
+
export default function Home() {
const {
poses,
@@ -57,7 +58,7 @@ export default function Home() {
id="field"
/>
-
+
diff --git a/src/components/path-overlay.tsx b/src/components/path-overlay.tsx
index 092c7cc..449ff29 100644
--- a/src/components/path-overlay.tsx
+++ b/src/components/path-overlay.tsx
@@ -1,12 +1,16 @@
'use client';
-import { useEffect, useRef } from "react";
+import { bspline } from "@/lib/bspline";
+import { useEffect, useRef, useState } from "react";
interface PathDrawProps {
poses: Pose[];
+ paths: Path[];
}
-export default function DrawPaths({ poses }: PathDrawProps) {
+export default function DrawPaths({ poses, paths}: PathDrawProps) {
+
+
const canvasRef = useRef(null);
useEffect(() => {
diff --git a/src/lib/bspline.tsx b/src/lib/bspline.tsx
new file mode 100644
index 0000000..eb850cf
--- /dev/null
+++ b/src/lib/bspline.tsx
@@ -0,0 +1,201 @@
+import { useState } from "react";
+
+export function bspline(poses:Pose[]){
+
+
+ const CMatrix = [
+ [-1.0 / 6.0, 3.0 / 6.0, -3.0 / 6.0, 1.0 / 6.0],
+ [3.0 / 6.0, -6.0 / 6.0, 3.0 / 6.0, 0.0],
+ [-3.0 / 6.0, 0.0, 3.0 / 6.0, 0.0],
+ [1.0 / 6.0, 4.0 / 6.0, 1.0 / 6.0, 0.0]
+ ]
+
+ //first, make sure all of the poses have valid values(kinda copied from path-overlay)
+
+ poses.forEach((pose) => {
+ if (pose.x === null || pose.y === null) return;
+ });
+
+ //then, make sure the list has a valid amount of poses
+
+ if(poses.length<2) return;
+
+ //convert all poses to vectors
+
+ const [poseVector,setPoseVector] = useState([]);
+ poses.forEach((pose) => {
+
+ const temp:Vector = {
+ x:pose.x ?? 0, // if pose.x is null, give a value of 0. Our filter above will automatically
+ // return if any of the values are null, so this will never happen, it just lets the Vector class have pure number types instead
+ // of number | null
+ y:pose.y ?? 0
+ };
+
+ setPoseVector((prevVectors)=>{
+
+ return [...prevVectors, temp]
+ })
+
+ });
+
+
+ //the first thing we need to do is to get the ghost points
+
+ //the formula is P_0+(-1(P_1-P_0)) where P_0 is the axis point(that you reflect across, otherwise known as the endpoint)
+ // and P_1 is the point being reflected(otherwise known as the second, or second to last point)
+
+
+
+
+ const [ghostPoints,setGhostPoints] = useState([]);// make a list for the ghost points
+
+ const neg1 = poses.length-1
+ const neg2 = poses.length-2
+
+ //will give error cus the value "might be null" even though we filtered for it already, so just add an if statement
+ if((poseVector[0].x!=null && poseVector[1].x!=null && poseVector[neg1].x!=null && poseVector[neg2].x!=null
+ && poseVector[0].y!=null && poseVector[1].y!=null && poseVector[neg1].y!=null && poseVector[neg2].y!=null)
+ ){
+ setGhostPoints([
+ {
+ x:poseVector[0].x+((poseVector[1].x - poseVector[0].x) * -1),
+ y:poseVector[0].y+((poseVector[1].y - poseVector[0].y) * -1)
+ },
+ {
+ x:poseVector[neg1].x+((poseVector[neg2].x - poseVector[neg1].x) * -1),
+ y:poseVector[neg1].y+((poseVector[neg2].y - poseVector[neg1].y) * -1)
+
+ }
+ ])
+ }
+
+ //now that our ghost points are sorted out, we can make the array that will be put into the spline
+ const [splinePoints,setSplinePoints] = useState([]);
+ // loop twice more than the poseVector array because we have 2 ghost points
+ for(let i = 0; i{
+
+ return[...prevPoints,ghostPoints[0]]
+
+ }
+ )
+ }
+ //adds ghost points at the end
+ else if(i == poseVector.length+1){// because its 0 indexed, the last loop will be when i is 1 less than poseVector.length+2
+
+ setSplinePoints(
+ (prevPoints)=>{
+
+ return [...prevPoints,ghostPoints[1]]
+
+ }
+ )
+ }
+ else{
+
+ setSplinePoints(
+ (prevPoints)=>{
+
+ return [...prevPoints,poseVector[i-1]]//since arrays are 0-indexed, and when the value of i is 0,
+ // the ghost point is added, we need to subtract one to add all elements in the array
+
+ }
+ )
+ }
+ }
+
+
+
+ //now, the control points are in order. Let's make the actual b spline evaluate.
+
+
+ const numSegments = splinePoints.length-3
+ const [cx,setCx] = useState([])
+ const [cy,setCy] = useState([])
+
+
+ //create the b spline segments, 4 control points per segment, each contribute to the whole spline, keeping it 4th degree
+ //as joel's bspline class states in the pathing repo, "they are evaluated using a sliding 4-point window"
+
+ for(let i = 0; i[...prevCx,tempx]
+ )
+ const tempy:number[] = multiplyMatrices(CMatrix,yWindow)
+ setCy(
+ (prevCy)=>[...prevCy,tempy]
+ )
+
+
+
+ }
+
+
+ //evaluate function
+ // copied from joels thing
+ const evaluate = (t:number)=>{
+
+ if (t >= 1.0) t = 0.999999;
+ if (t < 0.0) t = 0.0;
+
+ const continuousIndex = t * numSegments
+ const segment = Math.trunc(continuousIndex) //should do the same thing as type casting to int
+ const localT = continuousIndex - segment
+
+
+ const cX = cx[segment]
+ const cY = cy[segment]
+
+
+ const x = ((cX[0] * localT + cX[1]) * localT + cX[2]) * localT + cX[3]
+ const y = ((cY[0] * localT + cY[1]) * localT + cY[2]) * localT + cY[3]
+
+ const returnValue:Vector = {
+ x:x,
+ y:y
+ }
+ return returnValue;
+ }
+
+ return {evaluate}
+}
+
+
+//this function is made specifically for multiplying the Cmatrix and the windows
+function multiplyMatrices(matrix:number[][], window:number[]){
+
+
+ const [result,setResult] = useState([]);
+
+ for (let i = 0; i < matrix.length; i++) {
+ let sum:number = 0.0;
+ for (let j = 0; j < matrix[0].length; j++) {
+ sum += matrix[i][j] * window[j];
+ }
+ setResult((prevResults)=>{
+ return[...prevResults,sum]
+ })
+ }
+ return result;
+
+
+}
diff --git a/types/poses.ts b/types/poses.ts
index 8a54b50..ea1b11b 100644
--- a/types/poses.ts
+++ b/types/poses.ts
@@ -7,4 +7,11 @@ interface Pose {
radius: number | null
arcPose: boolean
local: boolean
+}
+
+//this interface is for calculating the bspline,
+// as it doesn't need the other things for poses which will just be plugged into the b spline
+interface Vector{
+ x:number //these two values are null to match the type of the poses, it will never actually be null
+ y:number
}
\ No newline at end of file