Skip to content

Commit

Permalink
CLN: turn cut-format-ratio into ensure-squared (#72)
Browse files Browse the repository at this point in the history
  • Loading branch information
fgebhart committed Mar 27, 2023
1 parent 0e1cf42 commit 8ae842a
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 305 deletions.
55 changes: 24 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,37 +66,29 @@ Usage: dem2stl [OPTIONS]
🌍 Convert DEM data into STL files 🌏
Options:
--input TEXT Path to input TIFF file.
--output TEXT Path to output STL file.
--as-ascii Save output STL as ascii file. If not provided,
output file will be binary.
--model-size INTEGER Desired size of the generated 3d model in
millimeter.
--max-res Whether maximum resolution should be used. Note,
that this flag potentially increases compute
time dramatically. The default behavior (i.e.
max_res=False) should return 3d models with
sufficient resolution, while the output stl file
should be < ~400 MB.
--z-offset FLOAT Offset distance in millimeter to be put below
the 3d model. Defaults to 4.0. Is not influenced
by z-scale.
--z-scale FLOAT Value to be multiplied to the z-axis elevation
data to scale up the height of the model.
Defaults to 1.0.
--demo Converts a demo tiff of Hawaii into a STL file.
--cut-to-format-ratio TEXT Cut the input tiff file to a specified format.
Set to `1` if you want the output model to be
squared. Set to `0.5` if you want one side to be
half the length of the other side. Omit this
flag to keep the input format. This option is
particularly useful when an exact output format
ratio is required for example when planning to
put the 3d printed model into a picture frame.
Using this option will always try to cut the
shorter side of the input tiff.
--version Show the version and exit.
--help Show this message and exit.
--input TEXT Path to input TIFF file.
--output TEXT Path to output STL file.
--as-ascii Save output STL as ascii file. If not provided, output
file will be binary.
--model-size INTEGER Desired size of the (larger side of the) generated 3d
model in millimeter.
--max-res Whether maximum resolution should be used. Note, that
this flag potentially increases compute time
dramatically. The default behavior (i.e.
max_res=False) should return 3d models with sufficient
resolution, while the output stl file should be < ~400
MB.
--z-offset FLOAT Offset distance in millimeter to be put below the 3d
model. Defaults to 4.0. Is not influenced by z-scale.
--z-scale FLOAT Value to be multiplied to the z-axis elevation data to
scale up the height of the model. Defaults to 1.0.
--demo Converts a demo tif of Hawaii into a STL file.
--ensure-squared Flag to toggle whether the output model should be
squared in x- and y-dimension. When enabled it will
remove pixels from one side to ensure same length for
both sides.
--version Show the version and exit.
--help Show this message and exit.
```

### 4. Using `mapa` as python library 📚
Expand All @@ -112,6 +104,7 @@ path_to_stl = convert_tiff_to_stl(
max_res=False,
z_offset=3.0,
z_scale=1.5,
ensure_squared: bool = False,
)
```

Expand Down
33 changes: 15 additions & 18 deletions mapa/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from mapa.caching import get_hash_of_geojson, tiff_for_bbox_is_cached
from mapa.raster import (
clip_tiff_to_bbox,
cut_array_to_format,
cut_array_to_square,
determine_elevation_scale,
merge_tiffs,
remove_empty_first_and_last_rows_and_cols,
Expand Down Expand Up @@ -64,9 +64,9 @@ def convert_array_to_stl(
return Path(output_file)


def _get_desired_size(array: np.ndarray, x: float, y: float, cut_to_format_ratio: Union[None, float]) -> ModelSize:
if cut_to_format_ratio:
return ModelSize(x=x, y=y * cut_to_format_ratio)
def _get_desired_size(array: np.ndarray, x: float, y: float, ensure_squared: bool) -> ModelSize:
if ensure_squared:
return ModelSize(x=x, y=y)
else:
rows, cols = array.shape
return ModelSize(x=x, y=y / rows * cols)
Expand All @@ -80,7 +80,7 @@ def convert_tiff_to_stl(
max_res: bool,
z_offset: Union[None, float],
z_scale: float,
cut_to_format_ratio: Union[None, float],
ensure_squared: bool = False,
) -> Path:

output_file = verify_input_and_output_are_valid(input=input_file, output=output_file)
Expand All @@ -89,9 +89,9 @@ def convert_tiff_to_stl(
elevation_scale = determine_elevation_scale(tiff, model_size)
array = tiff_to_array(tiff)

if cut_to_format_ratio:
array = cut_array_to_format(array, cut_to_format_ratio)
desired_size = _get_desired_size(array=array, x=model_size, y=model_size, cut_to_format_ratio=cut_to_format_ratio)
if ensure_squared:
array = cut_array_to_square(array)
desired_size = _get_desired_size(array=array, x=model_size, y=model_size, ensure_squared=ensure_squared)

return convert_array_to_stl(
array=array,
Expand Down Expand Up @@ -139,7 +139,7 @@ def convert_bbox_to_stl(
max_res: bool = False,
z_offset: Union[None, float] = 0.0,
z_scale: float = 1.0,
cut_to_format_ratio: Union[None, float] = None,
ensure_squared: bool = False,
split_area_in_tiles: str = "1x1",
compress: bool = True,
allow_caching: bool = True,
Expand Down Expand Up @@ -172,12 +172,9 @@ def convert_bbox_to_stl(
By default 0.0
z_scale : float, optional
Value to be multiplied to the z-axis elevation data to scale up the height of the model. By default 1.0
cut_to_format_ratio : Union[None, float], optional
Cut the input tiff file to a specified format. Set to `1` if you want the output model to be squared.
Set to `0.5` if you want one side to be half the length of the other side. Omit this flag to keep the
input format. This option is particularly useful when an exact output format ratio is required for
example when planning to put the 3d printed model into a picture frame. Using this option will always
try to cut the shorter side of the input tiff. By default None
ensure_squared : bool, optional
Boolean flag to toggle whether the output model should be squared in x- and y-dimension. When enabled
it will remove pixels from one side to ensure same length for both sides. By default False
split_area_in_tiles : str, optional
Split the selected bounding box into tiles with this option. The allowed format of a given string is
"nxm" e.g. "1x1", "2x3", "4x4" or similar, where "1x1" would not split at all and result in only
Expand Down Expand Up @@ -219,14 +216,14 @@ def convert_bbox_to_stl(
tiff = rio.open(path_to_tiff)
elevation_scale = determine_elevation_scale(tiff, model_size)
array = tiff_to_array(tiff)
if cut_to_format_ratio:
array = cut_array_to_format(array, cut_to_format_ratio)
if ensure_squared:
array = cut_array_to_square(array)

desired_size = _get_desired_size(
array=array,
x=model_size / tiles.x,
y=model_size / tiles.y,
cut_to_format_ratio=cut_to_format_ratio,
ensure_squared=ensure_squared,
)

tiled_arrays = split_array_into_tiles(array, tiles)
Expand Down
15 changes: 6 additions & 9 deletions mapa/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,11 @@
)
@click.option("--demo", is_flag=True, help="Converts a demo tif of Hawaii into a STL file.")
@click.option(
"--cut-to-format-ratio",
default=None,
"--ensure-squared",
is_flag=True,
help=(
"Cut the input tiff file to a specified format. Set to `1` if you want the output model to be squared. Set to "
"`0.5` if you want one side to be half the length of the other side. Omit this flag to keep the input format. "
"This option is particularly useful when an exact output format ratio is required for example when planning to "
"put the 3d printed model into a picture frame. Using this option will always try to cut the shorter side of "
"the input tiff."
"Flag to toggle whether the output model should be squared in x- and y-dimension. "
"When enabled it will remove pixels from one side to ensure same length for both sides."
),
)
@click.version_option()
Expand All @@ -68,7 +65,7 @@ def dem2stl(
demo: bool = False,
as_ascii: bool = False,
model_size: int = conf.DEFAULT_MODEL_OUTPUT_SIZE_IN_MM,
cut_to_format_ratio: Union[None, float] = None,
ensure_squared: bool = False,
) -> None:
if demo is False and input is None:
log.error("💥 Either of --input or --demo is required, try --help.")
Expand All @@ -81,7 +78,7 @@ def dem2stl(
max_res = True
z_scale = 2.5

convert_tiff_to_stl(input, as_ascii, model_size, output, max_res, z_offset, z_scale, cut_to_format_ratio)
convert_tiff_to_stl(input, as_ascii, model_size, output, max_res, z_offset, z_scale, ensure_squared)


@click.command(help="🗺 Draw a bounding box on a map and turn it into a STL file 🗺")
Expand Down
30 changes: 12 additions & 18 deletions mapa/mapa.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": 1,
"id": "9db38262",
"metadata": {},
"outputs": [],
Expand All @@ -23,7 +23,7 @@
},
{
"cell_type": "code",
"execution_count": 5,
"execution_count": 2,
"id": "7eac4bec",
"metadata": {
"scrolled": false
Expand All @@ -32,7 +32,7 @@
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "b2aebbf8442a47cfb27c644372ea2eb6",
"model_id": "4852dbe068704ce2bcbb5d7128dda91f",
"version_major": 2,
"version_minor": 0
},
Expand All @@ -47,6 +47,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Rectangle detected, execute next cells to continue!\n",
"Rectangle detected, execute next cells to continue!\n"
]
}
Expand All @@ -66,7 +67,7 @@
},
{
"cell_type": "code",
"execution_count": 9,
"execution_count": 4,
"id": "39c8fef3",
"metadata": {
"scrolled": true
Expand All @@ -76,12 +77,8 @@
"name": "stderr",
"output_type": "stream",
"text": [
"INFO:mapa:⏳ converting bounding box to STL file with arguments: {'bbox_geometry': {'type': 'Polygon', 'coordinates': [[[8.184646, 46.597374], [8.184646, 47.108271], [9.085494, 47.108271], [9.085494, 46.597374], [8.184646, 46.597374]]]}, 'as_ascii': False, 'model_size': 150, 'output_file': 'mapa_output', 'max_res': False, 'z_offset': 3.0, 'z_scale': 2.0, 'cut_to_format_ratio': None, 'split_area_in_tiles': '1x1', 'compress': False, 'allow_caching': True, 'cache_dir': '/home/fabian/make/mapa/cache/', 'tiles': TileFormat(x=1, y=1)}\n",
"INFO:mapa.stac:⬇️ fetching 4 stac items...\n",
"INFO:mapa.stac:🚀 1/4 using cached stac item ALPSMLC30_N047E009_DSM\n",
"INFO:mapa.stac:🚀 2/4 using cached stac item ALPSMLC30_N047E008_DSM\n",
"INFO:mapa.stac:🚀 3/4 using cached stac item ALPSMLC30_N046E009_DSM\n",
"INFO:mapa.stac:🚀 4/4 using cached stac item ALPSMLC30_N046E008_DSM\n",
"INFO:mapa:⏳ converting bounding box to STL file with arguments: {'bbox_geometry': {'type': 'Polygon', 'coordinates': [[[5.457402, 44.910359], [5.457402, 45.228674], [6.80603, 45.228674], [6.80603, 44.910359], [5.457402, 44.910359]]]}, 'as_ascii': False, 'model_size': 150, 'output_file': 'mapa_output', 'max_res': False, 'z_offset': 3.0, 'z_scale': 2.0, 'ensure_squared': True, 'split_area_in_tiles': '1x1', 'compress': False, 'allow_caching': True, 'cache_dir': '/home/fabian/make/mapa/cache/', 'tiles': TileFormat(x=1, y=1)}\n",
"INFO:mapa:🚀 using cached tiff!\n",
"INFO:mapa:🎉 successfully generated STL file: /home/fabian/make/mapa/mapa/mapa_output.stl\n"
]
}
Expand All @@ -94,7 +91,7 @@
" z_offset=3.0,\n",
" z_scale=2.0,\n",
" max_res=False,\n",
" cut_to_format_ratio=None,\n",
" ensure_squared=False,\n",
" split_area_in_tiles=\"1x1\",\n",
" compress=False,\n",
" cache_dir=\"/home/fabian/make/mapa/cache/\"\n",
Expand All @@ -116,7 +113,7 @@
},
{
"cell_type": "code",
"execution_count": 7,
"execution_count": 4,
"id": "cd7e9b13",
"metadata": {},
"outputs": [
Expand Down Expand Up @@ -150,12 +147,9 @@
" By default 0.0\n",
" z_scale : float, optional\n",
" Value to be multiplied to the z-axis elevation data to scale up the height of the model. By default 1.0\n",
" cut_to_format_ratio : Union[None, float], optional\n",
" Cut the input tiff file to a specified format. Set to `1` if you want the output model to be squared.\n",
" Set to `0.5` if you want one side to be half the length of the other side. Omit this flag to keep the\n",
" input format. This option is particularly useful when an exact output format ratio is required for\n",
" example when planning to put the 3d printed model into a picture frame. Using this option will always\n",
" try to cut the shorter side of the input tiff. By default None\n",
" ensure_squared : bool, optional\n",
" Boolean flag to toggle whether the output model should be squared in x- and y-dimension. When enabled\n",
" it will remove pixels from one side to ensure same length for both sides. By default False\n",
" split_area_in_tiles : str, optional\n",
" Split the selected bounding box into tiles with this option. The allowed format of a given string is\n",
" \"nxm\" e.g. \"1x1\", \"2x3\", \"4x4\" or similar, where \"1x1\" would not split at all and result in only\n",
Expand Down
33 changes: 1 addition & 32 deletions mapa/raster.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def remove_empty_first_and_last_rows_and_cols(array: npt.ArrayLike) -> np.ndarra
return array


def _cut_array_to_square(array: npt.ArrayLike) -> np.ndarray:
def cut_array_to_square(array: npt.ArrayLike) -> np.ndarray:
rows, cols = array.shape
if rows > cols:
diff = rows - cols
Expand All @@ -71,37 +71,6 @@ def _cut_array_to_square(array: npt.ArrayLike) -> np.ndarray:
return array


def _cut_array_to_rectangular_shape(array: npt.ArrayLike, cut_to_format_ratio: float) -> np.ndarray:
rows, cols = array.shape
if rows / cols == cut_to_format_ratio or cols / rows == cut_to_format_ratio:
# input array has already desired format ratio
return array
elif rows > cols:
# cut cols
desired_n_cols = int(rows * cut_to_format_ratio)
return array[:, :desired_n_cols]
elif cols > rows:
# cut rows
desired_n_rows = int(cols * cut_to_format_ratio)
return array[:desired_n_rows, :]
else:
# cut cols anyway
desired_n_cols = int(rows * cut_to_format_ratio)
return array[:, :desired_n_cols]


def cut_array_to_format(array: npt.ArrayLike, cut_to_format_ratio: float) -> np.ndarray:
if cut_to_format_ratio == 1.0:
return _cut_array_to_square(array)
if cut_to_format_ratio == 0.0:
raise ValueError("Cannot cut array to format with ratio 0.0. Choose a format ratio between 0.0 and 1.0")
else:
if cut_to_format_ratio > 1.0:
# ensure ratio is between 0.0 and 1.0 and transpose ratio
cut_to_format_ratio = cut_to_format_ratio**-1
return _cut_array_to_rectangular_shape(array, cut_to_format_ratio)


def _get_coordinate_of_pixel(row: int, col: int, tiff: DatasetReader) -> Tuple[float]:
meta = tiff.meta
window = Window(0, 0, meta["width"], meta["height"])
Expand Down
12 changes: 6 additions & 6 deletions tests/test_dem2stl.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def test_verify_model_size(clipped_tiff, tmpdir) -> None:
max_res=True,
z_offset=0.1,
z_scale=1.0,
cut_to_format_ratio=None, # don't enforce square
ensure_squared=False, # don't enforce square
)
dims = get_dimensions_of_stl_file(output_file)
assert model_size in dims
Expand All @@ -36,7 +36,7 @@ def test_verify_model_size(clipped_tiff, tmpdir) -> None:
max_res=True,
z_offset=0.0,
z_scale=1.0,
cut_to_format_ratio=1.0, # enforce square
ensure_squared=True, # enforce square
)
dims = get_dimensions_of_stl_file(output_file)
assert model_size in dims
Expand All @@ -56,7 +56,7 @@ def test_verify_model_size(clipped_tiff, tmpdir) -> None:
max_res=True,
z_offset=0.0,
z_scale=1.0,
cut_to_format_ratio=1.0,
ensure_squared=True, # enforce square
)
dims = get_dimensions_of_stl_file(output_file)
assert model_size in dims
Expand All @@ -79,7 +79,7 @@ def test_verify_model_size(clipped_tiff, tmpdir) -> None:
max_res=True,
z_offset=0.0,
z_scale=2.0,
cut_to_format_ratio=1.0,
ensure_squared=True, # enforce square
)
x, y, z_scale_2 = get_dimensions_of_stl_file(output_file)
assert z_scale_2 > z_scale_1
Expand All @@ -94,7 +94,7 @@ def test_verify_model_size(clipped_tiff, tmpdir) -> None:
max_res=True,
z_offset=0.0,
z_scale=1.0,
cut_to_format_ratio=1.0,
ensure_squared=True, # enforce square
)
x_coarse_1, y_coarse_1, z_coarse_1 = get_dimensions_of_stl_file(output_file)
convert_tiff_to_stl(
Expand All @@ -105,7 +105,7 @@ def test_verify_model_size(clipped_tiff, tmpdir) -> None:
max_res=False,
z_offset=0.0,
z_scale=1.0,
cut_to_format_ratio=1.0,
ensure_squared=True, # enforce square
)
x_coarse_2, y_coarse_2, z_coarse_2 = get_dimensions_of_stl_file(output_file)
assert x_coarse_1 == x_coarse_2
Expand Down
Loading

0 comments on commit 8ae842a

Please sign in to comment.