first commit.
This commit is contained in:
142
src/nimgcenter/NimgcenterBrainConv.tsx
Normal file
142
src/nimgcenter/NimgcenterBrainConv.tsx
Normal file
@@ -0,0 +1,142 @@
|
||||
import React, { useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { MultiLang } from "../config";
|
||||
import BrainCoordinateUtil, { BrainCoordinate, ConversionType } from "./lib/BrainCoordinateUtil";
|
||||
|
||||
interface Props {
|
||||
lang: MultiLang;
|
||||
}
|
||||
|
||||
const NimgcenterBrainConv: React.FC<Props> = (props: Props) => {
|
||||
const defaultInputFormat = "\\d+\\.?\\d*";
|
||||
const defaultOutputFormat = "%x,%y,%z\\n";
|
||||
|
||||
const [inputFormat, setInputFormat] = useState<string>(defaultInputFormat);
|
||||
const [inputArea, setInputArea] = useState<string>("");
|
||||
const [outputFormat, setOutputFormat] = useState<string>(defaultOutputFormat);
|
||||
const [outputArea, setOutputArea] = useState<string>("");
|
||||
const [conversionType, setConversionType] = useState<ConversionType>("icbm_spm2tal");
|
||||
|
||||
const parseInput = (input: string, format: string): BrainCoordinate[] => {
|
||||
const ret: BrainCoordinate[] = [];
|
||||
const regObj = new RegExp(format, "g");
|
||||
const values = input.match(regObj) || [];
|
||||
for (let i = 0; i + 2 < values.length; i += 3) {
|
||||
ret.push({ x: parseFloat(values[i]), y: parseFloat(values[i + 1]), z: parseFloat(values[i + 2]) });
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
const formatNumber = (value: number): string => {
|
||||
const digit = 4;
|
||||
const width = 7;
|
||||
const ret = value.toFixed(digit);
|
||||
return ret.length < width ? " ".repeat(width - ret.length) + ret : ret;
|
||||
};
|
||||
|
||||
const onChangeInputFormat = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setInputFormat(event.target.value);
|
||||
};
|
||||
|
||||
const onClickDefaultInputFormatButton = (event: React.MouseEvent<HTMLInputElement, MouseEvent>) => {
|
||||
setInputFormat(defaultInputFormat);
|
||||
};
|
||||
|
||||
const onChangeInputArea = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||
setInputArea(event.target.value);
|
||||
};
|
||||
|
||||
const onChangeOutputFormat = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setOutputFormat(event.target.value);
|
||||
};
|
||||
|
||||
const onClickDefaultOutputFormatButton = (event: React.MouseEvent<HTMLInputElement, MouseEvent>) => {
|
||||
setOutputFormat(defaultOutputFormat);
|
||||
};
|
||||
|
||||
const onChangeMatrixType = (event: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
if (BrainCoordinateUtil.isConversionType(event.target.value)) {
|
||||
setConversionType(event.target.value as ConversionType);
|
||||
}
|
||||
};
|
||||
|
||||
const onClickClearButton = (event: React.MouseEvent<HTMLInputElement, MouseEvent>) => {
|
||||
setInputArea("");
|
||||
setOutputArea("");
|
||||
};
|
||||
|
||||
const onClickConvertButton = (event: React.MouseEvent<HTMLInputElement, MouseEvent>) => {
|
||||
const inputValues = parseInput(inputArea, inputFormat);
|
||||
const outputValues = inputValues.map((inputValue) => BrainCoordinateUtil.convertCoordinate(conversionType, inputValue));
|
||||
const outputTextArea = outputValues
|
||||
.map((value) => {
|
||||
return outputFormat.replace("%x", formatNumber(value.x)).replace("%y", formatNumber(value.y)).replace("%z", formatNumber(value.z)).replace("\\n", "\n");
|
||||
})
|
||||
.join("");
|
||||
setOutputArea(outputTextArea);
|
||||
};
|
||||
|
||||
const matrix = BrainCoordinateUtil.getConversionMatrix(conversionType);
|
||||
const matrixArea = "Conversion Matrix:\n" + matrix.map((vect) => " " + vect.map((value) => formatNumber(value)).join(", ")).join("\n");
|
||||
return (
|
||||
<div style={{ textAlign: "center" }}>
|
||||
<div style={{ background: "navajowhite", padding: "3px 0" }}>
|
||||
Brain Coordinate Converter is able to convert list of brain coordinate. <Link to="./howtouse.php">How To Use</Link>
|
||||
</div>
|
||||
<table style={{ textAlign: "left" }}>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<b>Input format: (Regular expression).</b>
|
||||
<br />
|
||||
<input type="text" value={inputFormat} onChange={onChangeInputFormat} />
|
||||
<input type="button" onClick={onClickDefaultInputFormatButton} value="Default" />
|
||||
</td>
|
||||
<td>
|
||||
<b>Output format: (%x,%y,%z is replaced. and \n)</b>
|
||||
<br />
|
||||
<input type="text" value={outputFormat} onChange={onChangeOutputFormat} />
|
||||
<input type="button" onClick={onClickDefaultOutputFormatButton} value="Default" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<b>Input:</b>
|
||||
<br />
|
||||
<textarea cols={37} rows={10} wrap="off" value={inputArea} onChange={onChangeInputArea} />
|
||||
</td>
|
||||
<td>
|
||||
<b>Results:</b>
|
||||
<br />
|
||||
<textarea cols={37} rows={10} wrap="off" value={outputArea} readOnly />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<select size={8} onChange={onChangeMatrixType} value={conversionType}>
|
||||
{BrainCoordinateUtil.getConversionTypes().map((type) => (
|
||||
<option key={type} value={type}>
|
||||
{BrainCoordinateUtil.getConversionLabel(type)}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<textarea cols={37} rows={5} wrap="off" value={matrixArea} readOnly />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<input type="button" onClick={onClickConvertButton} value="Convert" />
|
||||
</td>
|
||||
<td>
|
||||
<input type="button" onClick={onClickClearButton} value="Clear" />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default NimgcenterBrainConv;
|
34
src/nimgcenter/NimgenterUtilities.tsx
Normal file
34
src/nimgcenter/NimgenterUtilities.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import React from "react";
|
||||
import { Helmet } from "react-helmet-async";
|
||||
import { Navigate, Route, Routes } from "react-router-dom";
|
||||
import PageNotFound from "../common/lib/PageNotFound";
|
||||
import XoopsCode from "../common/lib/XoopsCode";
|
||||
import { MultiLang } from "../config";
|
||||
import jsonHowToUse from "./assets/howtouse.json";
|
||||
import jsonUtilities from "./assets/utilities.json";
|
||||
import NimgcenterBrainConv from "./NimgcenterBrainConv";
|
||||
|
||||
interface Props {
|
||||
lang: MultiLang;
|
||||
}
|
||||
|
||||
const NimgcenterUtilities: React.FC<Props> = (props: Props) => {
|
||||
const { lang } = props;
|
||||
return (
|
||||
<>
|
||||
<Helmet>
|
||||
<title>NIMG Utilities</title>
|
||||
</Helmet>
|
||||
<Routes>
|
||||
<Route path="" element={<XoopsCode lang={lang} text={jsonUtilities[lang]} dohtml={true} />} />
|
||||
<Route path="brain_conv/" element={<NimgcenterBrainConv lang={lang} />} />
|
||||
<Route path="brain_conv/howtouse.php" element={<XoopsCode lang={lang} text={jsonHowToUse[lang]} dohtml={true} />} />
|
||||
<Route path="index.php" element={<Navigate to="/modules/xnpnimgcenter/utilities/" />} />
|
||||
<Route path="brain_conv/index.php" element={<Navigate to="/modules/xnpnimgcenter/utilities/brain_conv/" />} />
|
||||
<Route path="*" element={<PageNotFound lang={lang} />} />
|
||||
</Routes>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default NimgcenterUtilities;
|
1
src/nimgcenter/assets/howtouse.json
Normal file
1
src/nimgcenter/assets/howtouse.json
Normal file
File diff suppressed because one or more lines are too long
1
src/nimgcenter/assets/utilities.json
Normal file
1
src/nimgcenter/assets/utilities.json
Normal file
@@ -0,0 +1 @@
|
||||
{"en":"<h1>\n Utilities\n<\/h1><br \/>\n<br \/>\n<table class=\"outer\">\n <tbody>\n <tr>\n <td width=\"10%\" style=\"vertical-align:middle; text-align:center;\">\n <a href=\"\/modules\/xnpnimgcenter\/utilities\/brain_conv\/\"><img src=\"\/modules\/xnpnimgcenter\/utilities\/images\/brain_conv_ss.png\" alt=\"brainconv\" \/><\/a>\n <\/td>\n <td width=\"90%\">\n <a href=\"\/modules\/xnpnimgcenter\/utilities\/brain_conv\/\">Brain Coordinate Converter<\/a><br \/>\n This utility is able to mutually convert several types of brain coordinates(Requires JavaScript).<br \/>\n <a href=\"\/modules\/xnpnimgcenter\/utilities\/brain_conv\/howtouse.php\">How to use<\/a>\n <\/td>\n <\/tr>\n <\/tbody>\n<\/table>","ja":"<h1>\n ユーティリティ\n<\/h1><br \/>\n<br \/>\n<table class=\"outer\">\n <tbody>\n <tr>\n <td width=\"10%\" style=\"vertical-align:middle; text-align:center;\">\n <a href=\"\/modules\/xnpnimgcenter\/utilities\/brain_conv\/\"><img src=\"\/modules\/xnpnimgcenter\/utilities\/images\/brain_conv_ss.png\" alt=\"brainconv\" \/><\/a>\n <\/td>\n <td width=\"90%\">\n <a href=\"\/modules\/xnpnimgcenter\/utilities\/brain_conv\/\">脳座標変換ツール<\/a><br \/>\n 数種類の脳座間の変換が行えます(要Javascript)。<br \/>\n <a href=\"\/modules\/xnpnimgcenter\/utilities\/brain_conv\/howtouse.php\">使い方<\/a>\n <\/td>\n <\/tr>\n <\/tbody>\n<\/table>"}
|
152
src/nimgcenter/lib/BrainCoordinateUtil.ts
Normal file
152
src/nimgcenter/lib/BrainCoordinateUtil.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
export interface BrainCoordinate {
|
||||
x: number;
|
||||
y: number;
|
||||
z: number;
|
||||
}
|
||||
export type ConversionType = "icbm_spm2tal" | "tal2icbm_spm" | "icbm_fsl2tal" | "tal2icbm_fsl" | "icbm_other2tal" | "tal2icbm_other";
|
||||
type ConversionVector = readonly [number, number, number, number];
|
||||
type ConversionMatrix = readonly [ConversionVector, ConversionVector, ConversionVector, ConversionVector];
|
||||
|
||||
interface ConversionMatrixData {
|
||||
[key: string]: {
|
||||
label: string;
|
||||
matrix: ConversionMatrix;
|
||||
};
|
||||
}
|
||||
|
||||
const conversionMatrix: ConversionMatrixData = {
|
||||
icbm_spm2tal: {
|
||||
label: "icbm_spm => Talairach",
|
||||
matrix: [
|
||||
[0.9254, 0.0024, -0.0118, -1.0207],
|
||||
[-0.0048, 0.9316, -0.0871, -1.7667],
|
||||
[0.0152, 0.0883, 0.8924, 4.0926],
|
||||
[0.0, 0.0, 0.0, 1.0],
|
||||
],
|
||||
},
|
||||
tal2icbm_spm: {
|
||||
label: "Talairach => icbm_spm",
|
||||
matrix: [
|
||||
[1.0804, -0.0041, 0.0139, 1.0387],
|
||||
[0.0038, 1.0636, 0.1039, 1.4579],
|
||||
[-0.0188, -0.1052, 1.1101, -4.748],
|
||||
[0.0, 0.0, 0.0, 1.0],
|
||||
],
|
||||
},
|
||||
icbm_fsl2tal: {
|
||||
label: "icbm_fsl => Talairach",
|
||||
matrix: [
|
||||
[0.9464, 0.0034, -0.0026, -1.068],
|
||||
[-0.0083, 0.9479, -0.058, -1.0239],
|
||||
[0.0053, 0.0617, 0.901, 3.1883],
|
||||
[0.0, 0.0, 0.0, 1.0],
|
||||
],
|
||||
},
|
||||
tal2icbm_fsl: {
|
||||
label: "Talairach => icbm_fsl",
|
||||
matrix: [
|
||||
[1.0566, -0.004, 0.0028, 1.1155],
|
||||
[0.0088, 1.0505, 0.0677, 0.8694],
|
||||
[-0.0068, -0.0719, 1.1052, -3.6047],
|
||||
[0.0, 0.0, 0.0, 1.0],
|
||||
],
|
||||
},
|
||||
icbm_other2tal: {
|
||||
label: "other(SPM99,Brain Voyager) => Talairach",
|
||||
matrix: [
|
||||
[0.9357, 0.0029, -0.0072, -1.0423],
|
||||
[-0.0065, 0.9396, -0.0726, -1.394],
|
||||
[0.0103, 0.0752, 0.8967, 3.6475],
|
||||
[0.0, 0.0, 0.0, 1.0],
|
||||
],
|
||||
},
|
||||
tal2icbm_other: {
|
||||
label: "Talairach => other(SPM99,Brain Voyager)",
|
||||
matrix: [
|
||||
[1.0686, -0.004, 0.0083, 1.0782],
|
||||
[0.0064, 1.0574, 0.0857, 1.1682],
|
||||
[-0.0128, -0.0886, 1.1079, -4.178],
|
||||
[0.0, 0.0, 0.0, 1.0],
|
||||
],
|
||||
},
|
||||
/*
|
||||
tal2mni: {
|
||||
label: 'Talairach => MNI(Matthew Brett,99)',
|
||||
matrix: null // See also, http://eeg.sourceforge.net/doc_m2html/bioelectromagnetism/tal2mni.html
|
||||
},
|
||||
mni2tal: {
|
||||
label: 'MNI => Talairach(Matthew Brett,99)',
|
||||
matrix: null // See also, http://eeg.sourceforge.net/doc_m2html/bioelectromagnetism/mni2tal.html
|
||||
}
|
||||
*/
|
||||
};
|
||||
|
||||
const isConversionType = (type: string): boolean => {
|
||||
return type in conversionMatrix;
|
||||
};
|
||||
|
||||
const getConversionTypes = (): ConversionType[] => {
|
||||
return Object.keys(conversionMatrix) as ConversionType[];
|
||||
};
|
||||
|
||||
const getConversionLabel = (type: ConversionType): string => {
|
||||
return conversionMatrix[type].label;
|
||||
};
|
||||
|
||||
const getConversionMatrix = (type: ConversionType): ConversionMatrix => {
|
||||
return conversionMatrix[type].matrix;
|
||||
};
|
||||
|
||||
const mulMatrix = (mat: ConversionMatrix, vec: ConversionVector): ConversionVector => {
|
||||
return [mat[0][0] * vec[0] + mat[0][1] * vec[1] + mat[0][2] * vec[2] + mat[0][3] * vec[3], mat[1][0] * vec[0] + mat[1][1] * vec[1] + mat[1][2] * vec[2] + mat[1][3] * vec[3], mat[2][0] * vec[0] + mat[2][1] * vec[1] + mat[2][2] * vec[2] + mat[2][3] * vec[3], mat[3][0] * vec[0] + mat[3][1] * vec[1] + mat[3][2] * vec[2] + mat[3][3] * vec[3]];
|
||||
};
|
||||
|
||||
const convertCoordinate = (type: ConversionType, coord: BrainCoordinate): BrainCoordinate => {
|
||||
const vec: ConversionVector = [coord.x, coord.y, coord.z, 1.0];
|
||||
const res = mulMatrix(conversionMatrix[type].matrix, vec);
|
||||
return { x: res[0], y: res[1], z: res[2] };
|
||||
};
|
||||
|
||||
/*
|
||||
function mni2tal(v) {
|
||||
if (v[2] < 0) {
|
||||
return new Array(
|
||||
0.9900 * v[0],
|
||||
0.9688 * v[1] + 0.0420 * v[2],
|
||||
-0.0485 * v[1] + 0.8390 * v[2]
|
||||
);
|
||||
} else {
|
||||
return new Array(
|
||||
0.9900 * v[0],
|
||||
0.9688 * v[1] + 0.0460 * v[2],
|
||||
-0.0485 * v[1] + 0.9189 * v[2]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function tal2mni(v) {
|
||||
if (v[2] < 0) {
|
||||
return new Array(
|
||||
1.0101 * v[0],
|
||||
0.9688 * v[1] + 0.0460 * v[2],
|
||||
-0.0485 * v[1] + 0.9189 * v[2]
|
||||
);
|
||||
} else {
|
||||
return new Array(
|
||||
1.0101 * v[0],
|
||||
0.9712 * v[1] + 0.0501 * v[2],
|
||||
-0.0485 * v[1] + 0.8390 * v[2]
|
||||
);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
const BrainCoordinateUtil = {
|
||||
isConversionType,
|
||||
getConversionTypes,
|
||||
getConversionLabel,
|
||||
getConversionMatrix,
|
||||
convertCoordinate,
|
||||
};
|
||||
|
||||
export default BrainCoordinateUtil;
|
Reference in New Issue
Block a user