Skip to content

Commit

Permalink
feat: replace PDAL with Laspy so that make dependencies simpler (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
HideBa committed Feb 23, 2024
1 parent cbb1e05 commit ce94544
Show file tree
Hide file tree
Showing 17 changed files with 527 additions and 1,022 deletions.
82 changes: 14 additions & 68 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ on:
- "requirements.txt"
- "requirements.dev.txt"
pull_request:
branches:
- main

jobs:
ci:
Expand All @@ -24,49 +22,6 @@ jobs:
with:
python-version: 3.11.1

- name: Install PDAL
run: |
sudo apt-get update
sudo apt-get install -y \
g++ \
cmake \
git \
libgdal-dev \
libgeotiff-dev \
liblaszip-dev \
libboost-all-dev \
libboost-program-options-dev \
libboost-filesystem-dev \
libboost-system-dev \
libsqlite3-dev \
sqlite3 \
libproj-dev \
libcurl4-openssl-dev \
libjsoncpp-dev \
libxml2-dev \
libflann-dev \
libpcl-dev \
libeigen3-dev \
libnitro-dev \
libqhull-dev \
libtbb-dev
- name: Clone PDAL
run: |
git clone https://github.com/PDAL/PDAL.git
cd PDAL
git checkout 2.5-maintenance
mkdir build
cd build
cmake ..
make
sudo make install
sudo ldconfig
pdal --version
- name: Check pdal
run: |
echo "PDAL version -------------"
pdal --version
- name: Cache pip packages
uses: actions/cache@v2
with:
Expand All @@ -84,36 +39,27 @@ jobs:
- name: Install dependencies
run: |
poetry install
# - name: Install dependencies excluding PDAL
# run: |
# poetry add pdal --optional
# poetry install --no-root

# - name: Install PDAL Python package
# run: |
# source .venv/bin/activate
# pip install pdal==3.2.3
- name: Linting
run: |
poetry run pylint ./ahn_cli/**/*.py
make lint
- name: Type checking
run: |
poetry run mypy ./ahn_cli/**/*.py
make type
- name: Testing
run: poetry run pytest ./ahn_cli/**/*.py --cov=./ahn_cli
run: make test

- name: Export requirements
run: |
poetry export --dev --format requirements.txt --output requirements.txt
poetry export --dev --format requirements.txt --output requirements.dev.txt
# - name: Export requirements
# run: |
# poetry export --dev --format requirements.txt --output requirements.txt
# poetry export --dev --format requirements.txt --output requirements.dev.txt

- name: Commit exported requirements
run: |
git config --global user.name "${{ secrets.GH_USER_NAME }}"
git config --global user.email "${{ secrets.GH_USER_EMAIL }}"
git add requirements.txt requirements.dev.txt
git commit -m "Update requirements"
git push origin main
# - name: Commit exported requirements
# run: |
# git config --global user.name "${{ secrets.GH_USER_NAME }}"
# git config --global user.email "${{ secrets.GH_USER_EMAIL }}"
# git add requirements.txt requirements.dev.txt
# git commit -m "Update requirements"
# git push origin main
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -164,3 +164,5 @@ cython_debug/
*.qmd
/testdata
/out
.polyscope.ini
imgui.ini
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Changelog
## [0.1.6] - 2024-02-23
### Changed

### Added
This is the first release of AHN CLI. There are a couple of features which helps users to easily download AHN point cloud data they need.
* Validation of user input
* Multi-thread download to speed up downloading time
* Rasterization of city polygon to reduce time complexity
* Filter points out by parameters such as classification classes, decimate, bounding box, etc
* Preview of downloaded data
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ Options:
-ncc, --no-clip-city Avoid clipping the point cloud data to the city boundary.
-cf, --clip-file <file> Provide a file path for a clipping boundary file to clip
the point cloud data to a specified area.
-r, --radius <radius> Define a radius (in meters) to clip the point cloud data,
-e, --epsg <epsg> Set the EPSG code for user's clip file.
-b, --bbox <bbox> Specify a bounding box to clip the point cloud data. It should be comma-separated list with minx,miny,maxx,maxy
centered on the city polygon.
-p, --preview Preview the point cloud data in a 3D viewer.
-h, --help [category] Show help information. Optionally specify a category for
Expand Down Expand Up @@ -70,9 +71,13 @@ ahn_cli -c delft -o ./delft.laz -i 1,2 -ncc
ahn_cli -c delft -o ./delft.laz -i 1,2 -d 2
```
**Specify a Radius for Clipping:**
**Specify a Bounding box for clipping:**
If you specify a `b`, it will clip the point cloud data with specified bounding box.
```
ahn_cli -c delft -o ./delft.laz -i 1,2 -d 2 -b 194198.302994,443461.343994,194594.109009,443694.838989
```
If you specify a `radius` (in meters), it will clip the point cloud data from the center of the city polygon to the specified radius.
## Reporting Issues
Expand Down
21 changes: 14 additions & 7 deletions ahn_cli/fetcher/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from urllib.parse import urlparse

import requests
from tqdm import tqdm

from ahn_cli.fetcher.geotiles import ahn_subunit_indicies_of_city

Expand All @@ -23,23 +24,29 @@ def fetch(self) -> dict:
logging.info("Start fetching AHN data")
logging.info(f"Fetching {len(self.urls)} tiles")

def req(url: str, nth: int, results: dict, lock: Lock) -> None:
logging.info(f"Fetching tile {nth + 1}/{len(self.urls)}")
print(f"Fetching tile {nth + 1}/{len(self.urls)}")
def req(
url: str, nth: int, results: dict, lock: Lock, pbar: tqdm
) -> None:
res = requests.get(url, stream=True)
with tempfile.NamedTemporaryFile(
delete=False, mode="w+b", suffix=".laz"
) as temp_file:
for chunk in res.iter_content(chunk_size=1024 * 1024):
for chunk in tqdm(
res.iter_content(chunk_size=1024 * 1024),
desc="writing a file",
):
temp_file.write(chunk)
with lock:
results[url] = temp_file.name
pbar.update(1)

results: dict = {}
lock = threading.Lock()
with ThreadPoolExecutor(max_workers=8) as executor:
for i, url in enumerate(self.urls):
executor.submit(req, url, i, results, lock)
with tqdm(total=len(self.urls)) as pbar:
pbar.set_description("Fetching AHN data")
with ThreadPoolExecutor(max_workers=8) as executor:
for i, url in enumerate(self.urls):
executor.submit(req, url, i, results, lock, pbar)
return results

def _check_valid_url(self, url: str) -> bool:
Expand Down
3 changes: 2 additions & 1 deletion ahn_cli/kwargs.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class CLIArgs(TypedDict):
exclude_class: str | None
no_clip_city: bool
clip_file: str | None
epsg: int | None
decimate: int | None
radius: int | None
bbox: list[float] | None
preview: bool
23 changes: 12 additions & 11 deletions ahn_cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
-ncc --no-clip-city Do not clip the point cloud data to the city boundary.
-cf, --clip-file <file> Specify a file path to a clipping boundary file. The tool will
use this file to clip the point cloud data to a specific area.
-e, --epsg <epsg> Set the EPSG code for user's clip file.
-b, --bbox <bbox> Specify a bounding box to clip the point cloud data. It should be comma-separated list with minx,miny,maxx,maxy
-r, --radius <radius> Set the radius of the circle to clip the point cloud data to. Unit is in meter.
-p, --preview Preview the point cloud data in a 3D viewer.
-h, --help [category] Display help information. Optionally, specify a category to get
more detailed help for a specific command.
Expand All @@ -29,7 +29,7 @@


@click.command()
@click.version_option(version="0.1.5", prog_name="ahn_cli")
@click.version_option(version="0.1.6", prog_name="ahn_cli")
@click.option(
"-o",
"--output",
Expand Down Expand Up @@ -69,6 +69,12 @@
type=str,
help="Specify a file path to a clipping boundary file. The tool will use this file to clip the point cloud data to a specific area.",
)
@click.option(
"-e",
"--epsg",
type=int,
help="Set the EPSG code for user's clip file.",
)
@click.option(
"-d",
"--decimate",
Expand All @@ -81,12 +87,6 @@
type=str,
help="Specify a bounding box to clip the point cloud data. It should be comma-separated list with minx,miny,maxx,maxy",
)
@click.option(
"-r",
"--radius",
type=int,
help="Set the radius of the circle to clip the point cloud data to. Unit is in meter.",
)
@click.option(
"-p",
"--preview",
Expand All @@ -110,13 +110,13 @@ def main(**kwargs: Any) -> None:
)
no_clip_city = params.get("no_clip_city")
clip_file = params.get("clip_file")
epsg = params.get("epsg")
decimate = params.get("decimate")
bbox = (
[float(x) for x in str(params.get("bbox", "")).split(",")]
if params.get("bbox", "")
else None
)
radius = params.get("radius")
preview = params.get("preview")
if validate_all(
cfg,
Expand All @@ -126,9 +126,9 @@ def main(**kwargs: Any) -> None:
exclude_classes,
no_clip_city,
clip_file,
epsg,
decimate,
bbox,
radius,
):
process(
cfg.geotiles_base_url,
Expand All @@ -139,8 +139,9 @@ def main(**kwargs: Any) -> None:
exclude_classes,
no_clip_city,
clip_file,
epsg,
decimate,
bbox,
radius,
preview,
)

Expand Down
Loading

0 comments on commit ce94544

Please sign in to comment.