동기
생명과학쪽 공부하는 친구가 척추세포의 데이터를 보내주면 정렬해줄 수 있냐고 부탁받음
친구가 원하는것


척추 이미지 1처럼 척추를 찍은 사진이 있는데 빛나는 세포들의 좌표를 마우스로 찍어서 데이터를 저장함
그런데 항상 같은 위치, 같은 크기로 찍은게 아니라서 사진의 크기와 회전각도가 제각각이므로 맞춰주면 좋겠다.
해야할 것
1. csv확장자의 파일을 읽어서 해당 데이터를 배열화 함
2. V를 원점으로 삼기위해 모든 점을 평행이동 함
3. V-D의 거리를 구하고 이것을 이용해서 회전한 각도인 Θ를 구함
4. Θ를 이용해서 모든 데이터를 회전 시킴
5. 크기가 다른 여러 사진의 데이터를 중첩시키기위해서 L과 D의 위치를 고정시키고 그 비율에 맞춰서 데이터 이동
6. csv형식으로 내보내기

완성 예시 (처음 3개의 값은 V, D, L 값/ X,Y 데이터만 결과로 필요)


코드
const fileName = "S2 Br P5 epo";
const fs = require("fs");
const file_csv = fs.readFileSync(`./${fileName}.csv`); //readFile은 비동기 이건 동기
const string_csv = file_csv.toString();
const arr_json = csvToJSON(string_csv);
arr_json.pop(); // 마지막 빈값있길래 지움
// 처음 V값
let originV = [JSON.parse(arr_json[0].X), JSON.parse(arr_json[0].Y)]; // json.parse해서 string을 number로 바꿈
// V를 원점으로 삼기위한 값
let parallelTranslationForOrigin = originV.map((e) => -e);
// 모든 x,y에 대한 데이터
let allXY = [];
arr_json.forEach((e) => allXY.push([JSON.parse(e.X), JSON.parse(e.Y)]));
// 평행이동 시킨 x,y들의 데이터
let parallelTranslationAllXY = allXY.map((e) => [round(e[0] + parallelTranslationForOrigin[0], 1000), round(e[1] + parallelTranslationForOrigin[1], 1000)]);
//시계방향회전인지 여부 판별
let clockwise = true;
if (parallelTranslationAllXY[1][0] < 0) clockwise = false;
// 평행이동한 D값
let parallelTranslationD = [parallelTranslationAllXY[1][0], parallelTranslationAllXY[1][1]];
//V와 D사이거리 구하기
let lengthV_D = round(Math.sqrt(Math.pow(parallelTranslationD[0], 2) + Math.pow(parallelTranslationD[1], 2)), 1000);
//세타 구하기
let Θ = round(90 - (Math.asin(parallelTranslationD[1] / lengthV_D) * 180) / Math.PI, 1000);
if (!clockwise) Θ = -Θ;
//회전시킨 데이터 값들
let rotationTranslationAllXY = parallelTranslationAllXY.map((e) => rotationTranslation(e[0], e[1], Θ));
//기준으로 삼을 최대 Lx, Dy값
let ratioReferenceXY = [200, 530];
//각 데이터에 곱해줄 비율
let rateXY = [Math.abs(ratioReferenceXY[0] / rotationTranslationAllXY[2][0]), Math.abs(ratioReferenceXY[1] / rotationTranslationAllXY[1][1])];
//회전시킨 데이터에 비율따라 곱하기
let resultXY = rotationTranslationAllXY.map((e) => [Math.abs(round(e[0] * rateXY[0], 1)), round(e[1] * rateXY[1], 1)]);
//csv 형식으로 만들기
let result = `,X,Y\r`;
resultXY.forEach((e, index) => {
result += `${index + 1},${e[0]},${e[1]}\r`;
});
//csv 파일 만들기
fs.writeFileSync(`chaged_${fileName}.csv`, result);
//csv를 JSON으로 바꿔주는 함수
function csvToJSON(csv_string) {
const rows = csv_string.split("\r\n");
const jsonArray = [];
const header = rows[0].split(",");
for (let i = 1; i < rows.length; i++) {
let obj = {};
let row = rows[i].split(",");
for (let j = 0; j < header.length; j++) {
obj[header[j]] = row[j];
}
jsonArray.push(obj);
}
return jsonArray;
}
//소수점 반올림 함수
function round(num, digit) {
return Math.round(num * digit) / digit;
}
//데이터 회전 시키는 함수
function rotationTranslation(x, y, Θ) {
let rotationTranslationX = x * Math.cos((Θ * Math.PI) / 180) - y * Math.sin((Θ * Math.PI) / 180);
let rotationTranslationY = x * Math.sin((Θ * Math.PI) / 180) + y * Math.cos((Θ * Math.PI) / 180);
return [round(rotationTranslationX, 1000), round(rotationTranslationY, 1000)];
}
'Project > mini-project' 카테고리의 다른 글
목표 금액이 될 수 있는 경우의 수 찾기 (0) | 2022.12.25 |
---|---|
티스토리 글쓰기 버튼 만들기 (0) | 2022.04.26 |