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

折り方部分のリファクタ #61

Merged
merged 10 commits into from
Jan 1, 2025
93 changes: 93 additions & 0 deletions src/components/OrigamiPost/hooks/useDecideFoldMethod/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { Board, Point } from "@/types/three";
import { Procedure } from "@/types/model";
import { rotateBoards } from "../../logics/rotateBoards";
import { Step } from "../../FoldMethodControlPanel";
import { decideNewProcedure } from "../../logics/decideNewProcedure";

type UseDecideFoldMethod = (props: {
fixBoards: Board[];
moveBoards: Board[];
numberOfMoveBoards: number;
rotateAxis: [Point, Point] | [];
isFoldingDirectionFront: boolean;
isMoveBoardsRight: boolean;
origamiDescription: string;
foldingAngle: number;
procedureIndex: number;
procedure: Procedure;
setInputStep: React.Dispatch<React.SetStateAction<Step>>;
setProcedureIndex: React.Dispatch<React.SetStateAction<number>>;
setProcedure: React.Dispatch<React.SetStateAction<Procedure>>;
setFixBoards: React.Dispatch<React.SetStateAction<Board[]>>;
setMoveBoards: React.Dispatch<React.SetStateAction<Board[]>>;
}) => {
handleDecideFoldMethod: () => void;
};

export const useDecideFoldMethod: UseDecideFoldMethod = ({
fixBoards,
moveBoards,
numberOfMoveBoards,
rotateAxis,
isFoldingDirectionFront,
isMoveBoardsRight,
origamiDescription,
foldingAngle,
procedureIndex,
procedure,
setInputStep,
setProcedureIndex,
setProcedure,
setFixBoards,
setMoveBoards,
}) => {
const handleDecideFoldMethod = () => {
// moveBoardsを回転した後の板を、fixBoardsに追加する
if (moveBoards.length === 0) return;
if (rotateAxis.length === 0) return;

// xy平面上の板のうち、z座標が大きい順に、numberOfMoveBoards枚を折る
// それ以外の板は無条件で折る
const { foldBoards, notFoldBoards, newProcedure } = decideNewProcedure({
fixBoards,
moveBoards,
numberOfMoveBoards,
rotateAxis,
isFoldingDirectionFront,
isMoveBoardsRight,
origamiDescription,
});

const rotatedBoards = rotateBoards({
boards: foldBoards,
rotateAxis,
angle: foldingAngle,
isFoldingDirectionFront: isFoldingDirectionFront,
isMoveBoardsRight,
});
const boards = [...fixBoards, ...rotatedBoards, ...notFoldBoards];

// boardsの格値を少数第3位までにする
// これをしないとe^-16のような値が出てきて、板が重なっているかどうかの判定がうまくいかない
const roundedBoards = boards.map((board) =>
board.map(
(point) => point.map((v) => Math.round(v * 1000) / 1000) as Point
)
);

// setRotateAxis([]);
// setSelectedPoints([]);
// setNumberOfMoveBoards(0);
// setOrigamiDescription("");
// setFoldingAngle(180);
setFixBoards(roundedBoards);
setMoveBoards([]);
setInputStep("axis");
setProcedureIndex(procedureIndex + 1);
setProcedure({ ...procedure, [procedureIndex]: newProcedure });
};

return {
handleDecideFoldMethod,
};
};
147 changes: 147 additions & 0 deletions src/components/OrigamiPost/hooks/useDecideRotateAxis/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import { Point, Board } from "@/types/three";
import * as THREE from "three";
import { getAllIntersections } from "../../logics/getAllIntersections";
import { separateBoard } from "../../logics/separateBoard";
import { useState } from "react";
import { isOnLeftSide } from "../../logics/isOnLeftSide";
import { LineGeometry } from "three/examples/jsm/Addons.js";
import { LineMaterial } from "three/examples/jsm/Addons.js";
import { Line2 } from "three/examples/jsm/Addons.js";
import { renderBoard } from "../../logics/renderBoard";
import { Step } from "../../FoldMethodControlPanel";

type UseDecideRotateAxis = (props: {
selectedPoints: Point[];
fixBoards: Board[];
setInputStep: React.Dispatch<React.SetStateAction<Step>>;
origamiColor: string;
}) => {
handleDecideRotateAxis: (scene: THREE.Scene) => void;
handleCancelRotateAxis: () => void;
leftBoards: Board[];
rightBoards: Board[];
rotateAxis: [Point, Point] | [];
};

export const useDecideRotateAxis: UseDecideRotateAxis = ({
selectedPoints,
fixBoards,
setInputStep,
origamiColor,
}) => {
const [leftBoards, setLeftBoards] = useState<Board[]>([]);
const [rightBoards, setRightBoards] = useState<Board[]>([]);
const [rotateAxis, setRotateAxis] = useState<[Point, Point] | []>([]);

const handleDecideRotateAxis = (scene: THREE.Scene) => {
if (selectedPoints.length < 2)
return console.error("点が2つ選択されていません");

const axis: [Point, Point] = [
[...selectedPoints[0]],
[...selectedPoints[1]],
];

const lefts: Board[] = [];
const rights: Board[] = [];

for (let i = 0; i < fixBoards.length; i++) {
const board = fixBoards[i];
const intersections = getAllIntersections({
board,
rotateAxis: axis,
});
if (intersections.length === 2) {
// 板を分割する場合
const separatedBoard = separateBoard({
board,
rotateAxis: axis,
});
if (!separatedBoard) return alert("Failed to separate board.");
const { leftBoard, rightBoard } = separatedBoard;
lefts.push(leftBoard);
rights.push(rightBoard);
} else {
// 板を分割しない場合
// 板が回転軸の左側にあるか、右側にあるかを判定
// TODO: 一部分だけ回転軸の左右にある場合はエラーになる。

const isLeftSide = board.map((point) =>
isOnLeftSide({
point,
axis1: axis[0],
axis2: axis[1],
})
);

const isAllLeft = isLeftSide.every((b) => b);
const isAllRight = isLeftSide.every((b) => !b);

if (isAllLeft) {
lefts.push(board);
} else if (isAllRight) {
rights.push(board);
} else {
// return setPopup({
// message: "板が回転軸の左右にまたがっているため、分割できません。",
// type: "error",
// });
}
}
}
// sceneから板、線を削除
scene.children = scene.children.filter(
(child) => child.type !== "Mesh" && child.type !== "LineSegments"
);
// pointを削除する
scene.children = scene.children.filter((child) => child.type !== "Points");

// 折り線を描画
const lineGeometry = new LineGeometry();
lineGeometry.setPositions([
axis[0][0],
axis[0][1],
axis[0][2],
axis[1][0],
axis[1][1],
axis[1][2],
]);
const lineMaterial = new LineMaterial({
color: 0xff00ff,
linewidth: 3,
});
const lineMesh = new Line2(lineGeometry, lineMaterial);
lineMesh.name = "Axis";
scene.add(lineMesh);

setRotateAxis(axis);
setInputStep("target");
lefts.forEach((board) =>
renderBoard({ scene, board, color: origamiColor })
);
rights.forEach((board) =>
renderBoard({ scene, board, color: origamiColor })
);

console.log("lefts", lefts);
console.log("rights", rights);
setLeftBoards(lefts);
setRightBoards(rights);
};

const handleCancelRotateAxis = () => {
setRotateAxis([]);
// TODO: 状態を保持しておいて、一個前の状態に戻すようにする
// setFixBoards([initialBoard]);
// setMoveBoards([]);
setInputStep("axis");
};

return {
handleDecideRotateAxis,
handleCancelRotateAxis,
leftBoards,
rightBoards,
rotateAxis,
};
};
Loading