Metadata-Version: 2.4
Name: steam-mongodb-client
Version: 0.4.1
Summary: Simple MongoDB/GridFS client for STEAM partner institutions
Author: GNU STEAM Project
Classifier: Programming Language :: Python :: 3
Classifier: Operating System :: Microsoft :: Windows
Requires-Python: >=3.11
Description-Content-Type: text/markdown
Requires-Dist: pymongo<5,>=4.6
Provides-Extra: pcd
Requires-Dist: open3d>=0.19; extra == "pcd"
Requires-Dist: numpy<3,>=1.26; extra == "pcd"
Provides-Extra: registration
Requires-Dist: open3d>=0.19; extra == "registration"
Requires-Dist: numpy<3,>=1.26; extra == "registration"
Requires-Dist: small-gicp<2,>=1.0.1; extra == "registration"

# STEAM MongoDB Client

타 기관 사용자가 MongoDB/GridFS 기능을 간단한 Python 함수로 사용할 수 있도록 만든 배포용 패키지입니다.

## 1. 사용자 설치

PyPI에 배포한 뒤 사용자는 터미널에서 한 번만 설치합니다.

```powershell
pip install steam-mongodb-client
```

PCD를 Open3D 객체로 직접 읽을 사용자는 다음 중 하나를 실행합니다.

```powershell
pip install "steam-mongodb-client[pcd]"
```

또는

```powershell
pip install open3d
```

ICP 정합 기능까지 사용할 사용자는 다음 명령으로 설치합니다.

```powershell
pip install "steam-mongodb-client[registration]"
```

## 2. 기본 사용 순서

```python
from steam_mongodb import connect, search, download, close

connect(
    host="203.xxx.xxx.xxx",
    username="기관계정",
    password="기관비밀번호",
    ca_file=r"C:\mongodb-certs\ca.pem",
)

files = search(site="site", pcd_type="UAV_PCD")
print(files)

download(
    files[0]["file_id"],
    r"D:\STEAM_DATA\downloaded.pcd",
)

close()
```

## 3. 제공 함수

| 함수 | 용도 |
|---|---|
| `connect()` | MongoDB 연결 |
| `ping()` | 연결 확인 |
| `search()` | 파일 검색/조회 |
| `download()` | 파일 저장 |
| `read_pcd()` | PCD를 Open3D 객체로 읽기 |
| `registration()` | 두 PCD를 ICP 정합하고 Reg_PCD로 저장 |
| `upload()` | 파일 업로드 |
| `update()` | 파일명/메타데이터 수정 |
| `delete()` | GridFS 파일 삭제 |
| `close()` | 연결 종료 |

## 4. 검색 예시

```python
files = search(
    site="site",
    date="2026-08-15",
    pcd_type="UAV_PCD",
)
```

조건은 필요한 것만 입력하면 됩니다.

```python
files = search(site="site")
```

```python
files = search(filename="sample")
```

## 5. PCD 직접 읽기

```python
from steam_mongodb import read_pcd

pcd = read_pcd(file_id)
print(pcd)
```

`read_pcd()`는 임시 PCD 파일을 만든 뒤 Open3D 객체로 읽고 임시 파일을 자동 삭제합니다.

## 6. ICP 정합 및 Reg_PCD 저장

`registration()`은 첫 번째 PCD를 이동시켜 두 번째 PCD의 좌표계에 맞춥니다.
일반적으로 UGV PCD를 첫 번째 PCD로, UAV PCD를 두 번째 PCD로 입력합니다.

```python
from steam_mongodb import registration, search

ugv = search(
    site="서초서리풀",
    date="2025-09-09",
    pcd_type="UGV_PCD",
)

uav = search(
    site="서초서리풀",
    date="2025-09-09",
    pcd_type="UAV_PCD",
)

result = registration(ugv, uav)

print(result["file_id"])
print(result["fitness"])
```

사용자가 파일 번호, file_id, 저장 메타데이터를 따로 입력할 필요가 없습니다.
`registration()`은 `search()`가 반환한 목록에서 가장 최근 파일을 자동 선택하고,
정합 결과를 다음 값으로 MongoDB에 바로 저장합니다.

```text
site: 입력 UGV/UAV의 공통 site
date: 입력 UGV/UAV의 공통 date
pcd_type: Reg_PCD
```

같은 조건의 파일이 여러 개 검색되면 가장 최근에 업로드된 파일을 사용합니다.
검색 결과가 없거나 두 PCD의 `site` 또는 `date`가 서로 다르면 정합을 시작하지 않고
조건을 확인하라는 오류를 표시합니다.

함수 내부에서는 다음 작업이 순서대로 진행됩니다.

1. MongoDB의 두 PCD를 임시 디스크에 순차 저장
2. 원본 전체 구간에서 정합용 대표점 추출 및 다운샘플링
3. 현장 중심을 원점으로 하는 로컬 좌표 변환
4. small_gicp 기반 다단계 GICP 정합(넓은 범위에서 좁은 범위 순서)
5. GICP 결과의 fitness 및 RMSE 신뢰도 평가
6. 원본 UGV PCD를 일정 포인트 단위로 읽어 최종 변환행렬 적용
7. 원본 UAV PCD와 변환된 UGV PCD의 스트리밍 병합
8. `{현장명}_Reg_PCD.pcd`로 MongoDB/GridFS 자동 업로드

대용량 PCD 두 개를 Open3D 메모리에 동시에 올리지 않습니다. 정합 계산용
축소본만 RAM에서 처리하고, 기본값 `output_voxel_size=0.0`에서는 원본의 모든
포인트를 청크 단위로 변환·병합하므로 최종 결과 포인트 수가 유지됩니다.

```text
정합 계산: 대표점 및 다운샘플링 데이터
최종 결과: UAV 원본 포인트 + 변환된 UGV 원본 포인트
```

처리 중에는 UGV, UAV 및 생성 중인 Reg_PCD를 임시 저장하므로 시스템 임시 폴더가
있는 드라이브에 세 파일을 저장할 수 있는 여유 공간이 필요합니다. 작업 성공 또는
오류 종료 후 임시 파일은 자동 삭제됩니다.

두 PCD의 `metadata.site` 값이 다르면 정합하지 않습니다. 정합 결과에는
원본 file_id, `fitness`, `inlier_rmse`, 변환행렬이 metadata로 함께 저장됩니다.

기본 정합 설정은 PCD 좌표 단위가 미터인 현장을 기준으로 합니다. 국가 투영좌표처럼
X/Y 값이 큰 PCD도 정합 계산 중에는 자동으로 현장 중심 로컬 좌표로 변환되며,
사용자는 별도의 초기 변환행렬을 입력하지 않아도 됩니다.

```python
result = registration(
    first_pcd=ugv,
    second_pcd=uav,
    voxel_size=0.25,
    max_correspondence_distance=0.5,
    initial_transform=[
        [1, 0, 0, 0],
        [0, 1, 0, 0],
        [0, 0, 1, 0],
        [0, 0, 0, 1],
    ],
)
```

정합 결과는 두 원본 PCD에 공통으로 존재하는 필드를 유지합니다. 예를 들어 두 파일에
모두 `intensity`가 있으면 결과에도 유지되며, 한 파일에만 존재하는 필드는 병합 가능한
공통 PCD 구조를 만들기 위해 제외됩니다. XYZ 좌표는 항상 저장됩니다.

## 7. 업로드

```python
from steam_mongodb import upload

file_id = upload(
    file_path=r"D:\STEAM_DATA\sample.pcd",
    site="site",
    date="2026-08-15",
    pcd_type="UAV_PCD",
)

print(file_id)
```

## 8. 수정

```python
from steam_mongodb import update

update(
    file_id,
    pcd_type="Reg_PCD",
)
```

## 9. 삭제

```python
from steam_mongodb import delete

delete(file_id)
```

삭제 권한이 있는 계정에서만 제공하는 것을 권장합니다.

## 10. 코드 보호 구조

사용자가 설치하는 wheel에는 `_core.pyx` 원본을 넣지 않고 Cython으로 컴파일된 확장 모듈을 넣도록 구성되어 있습니다.

사용자가 일반적으로 볼 수 있는 `__init__.py`에는 아래와 같이 공개 함수 이름만 존재합니다.

```python
from ._core import connect, search, download, read_pcd, registration, upload, update, delete, close
```

따라서 일반적인 순수 Python 패키지보다 내부 구현 코드를 쉽게 열어보거나 수정하기 어렵습니다.

단, 사용자 PC에 설치된 프로그램을 기술적으로 100% 수정 불가능하게 만드는 것은 불가능합니다. 이 구조의 목적은 **원본 소스 비공개 + 일반 사용자의 임의 수정 방지 + 단순한 함수 호출 인터페이스 제공**입니다.

## 11. GitHub 권장 구조

### 개발 저장소

- GitHub Private Repository
- 관리자/개발자만 접근
- `_core.pyx` 포함
- MongoDB 비밀번호, 인증서 개인키, 실제 기관 비밀번호는 절대 업로드 금지

### 배포

태그를 push하면 GitHub Actions가 Windows용 wheel을 만들고 PyPI에 wheel만 배포하도록 설정되어 있습니다.

```powershell
git tag v0.4.1
git push origin v0.4.1
```

PyPI의 Trusted Publisher 설정이 먼저 필요합니다.

## 12. 중요 보안 원칙

1. MongoDB 관리자 계정 비밀번호를 패키지에 넣지 않기
2. 기관별 계정과 비밀번호를 사용자에게 따로 전달하기
3. 실제 IP, 인증서 개인키, 비밀번호를 GitHub 코드에 하드코딩하지 않기
4. 기관 계정별 MongoDB 권한을 필요한 범위로 제한하기
5. 일반 조회 기관에 `delete()` 권한이 필요 없다면 MongoDB 계정 권한 자체에서 삭제를 막기
6. 소스 배포판(`.tar.gz`)은 공개 배포하지 않고 compiled wheel만 배포하기

## 13. 현재 기본 GridFS 구조

기본 bucket 이름은 `data`입니다.

따라서 MongoDB에서는 일반적으로 다음 두 컬렉션을 사용합니다.

```text
data.files
data.chunks
```

현재 버전의 bucket 이름은 패키지 내부에서 `data`로 고정되어 있습니다.

## 14. 인증 DB가 다른 경우

기본값은 다음과 같습니다.

```python
auth_db="steam_db"
```

기본 설정을 명시적으로 입력하려면 다음과 같이 사용합니다.

```python
connect(
    ...,
    auth_db="steam_db",
)
```

기관 계정이 다른 인증 DB에 생성되어 있다면 해당 DB 이름을 `auth_db`에 입력합니다.
예를 들어 `admin`에서 계정을 생성했다면 `auth_db="admin"`을 사용합니다.
