Skip to content

Commit

Permalink
v.fill.holes: Add new tool to remove inner isles, keep outer boundary (
Browse files Browse the repository at this point in the history
…#2486)

* Write boundaries of areas with centroids.
* Writes each boundary only once using index of already written boundaries.
* Copies attributes.
* Has tests for removal of holes are preservation of attributes.
* Has documentation including an image and a notebook to generate the image.
* Does not free memory at the end as in many existing modules.
  • Loading branch information
wenzeslaus committed Jul 22, 2023
1 parent 44e87d8 commit 3083e78
Show file tree
Hide file tree
Showing 14 changed files with 932 additions and 2 deletions.
3 changes: 3 additions & 0 deletions gui/wxpython/xml/toolboxes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1214,6 +1214,9 @@
<module-item name="v.clean">
<label>Clean vector map</label>
</module-item>
<module-item name="v.fill.holes">
<label>Fill holes in areas</label>
</module-item>
<module-item name="v.generalize">
<label>Smooth or simplify</label>
</module-item>
Expand Down
3 changes: 2 additions & 1 deletion raster/r.fill.stats/r.fill.stats.html
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,8 @@ <h2>SEE ALSO</h2>
<a href="r.surf.idw.html">r.surf.idw</a>,
<a href="v.surf.bspline.html">v.surf.bspline</a>,
<a href="v.surf.idw.html">v.surf.idw</a>,
<a href="v.surf.rst.html">v.surf.rst</a>
<a href="v.surf.rst.html">v.surf.rst</a>,
<a href="v.fill.holes.html">v.fill.holes</a>
</em>

<p>
Expand Down
3 changes: 2 additions & 1 deletion scripts/r.fillnulls/r.fillnulls.html
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ <h2>SEE ALSO</h2>
<a href="r.mapcalc.html">r.mapcalc</a>,
<a href="r.resamp.bspline.html">r.resamp.bspline</a>,
<a href="v.surf.bspline.html">v.surf.bspline</a>,
<a href="v.surf.rst.html">v.surf.rst</a>
<a href="v.surf.rst.html">v.surf.rst</a>,
<a href="v.fill.holes.html">v.fill.holes</a>
</em>

<h2>AUTHORS</h2>
Expand Down
1 change: 1 addition & 0 deletions vector/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ SUBDIRS = \
v.edit \
v.extract \
v.extrude \
v.fill.holes \
v.generalize \
v.hull \
v.info \
Expand Down
1 change: 1 addition & 0 deletions vector/v.clean/v.clean.html
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,7 @@ <h2>SEE ALSO</h2>
<a href="v.build.html">v.build</a>,
<a href="g.gui.vdigit.html">g.gui.vdigit</a>,
<a href="v.edit.html">v.edit</a>,
<a href="v.fill.holes.html">v.fill.holes</a>,
<a href="v.generalize.html">v.generalize</a>
</em>

Expand Down
12 changes: 12 additions & 0 deletions vector/v.fill.holes/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
MODULE_TOPDIR = ../..

PGM = v.fill.holes

LIBES = $(VECTORLIB) $(DBMILIB) $(GISLIB)
DEPENDENCIES = $(VECTORDEP) $(DBMIDEP) $(GISDEP)
EXTRA_INC = $(VECT_INC)
EXTRA_CFLAGS = $(VECT_CFLAGS)

include $(MODULE_TOPDIR)/include/Make/Module.make

default: cmd
301 changes: 301 additions & 0 deletions vector/v.fill.holes/examples.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,301 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Graphics for Documentation of _v.fill.holes_\n",
"\n",
"Requires _pngquant_, _optipng_ and _ImageMagic_ (_mogrify_, _montage_)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import sys\n",
"\n",
"from IPython.display import Image\n",
"\n",
"import grass.script as gs\n",
"import grass.jupyter as gj"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"gj.init(\"~/grassdata/nc_spm_08_grass7/user1\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Explanation Plots"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Use data and import code from tests.\n",
"sys.path.append(\"./tests\")\n",
"import conftest\n",
"from pathlib import Path"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"work_dir = Path(\".\")\n",
"conftest.import_data(\n",
" path=work_dir,\n",
" areas_name=\"data\",\n",
" areas_with_space_in_between=\"dissolve_data\",\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!v.fill.holes input=data output=data_filled"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!g.region vector=data grow=3 res=1\n",
"text_position = (75,5)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plot = gj.Map(use_region=True, width=700)\n",
"plot.d_background(color=\"white\")\n",
"plot.d_vect(map=\"data\")\n",
"plot.d_text(at=text_position, color=\"black\", text=\"(a) Original\")\n",
"plot.save(\"original.png\")\n",
"plot.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plot = gj.Map(use_region=True, width=700)\n",
"plot.d_background(color=\"white\")\n",
"plot.d_vect(map=\"data_filled\")\n",
"plot.d_text(at=text_position, color=\"black\", text=\"(b) Filled\")\n",
"plot.save(\"new.png\")\n",
"plot.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"example_1 = \"v_fill_holes_filled.png\"\n",
"!montage original.png new.png -tile 2x1 -geometry +0+0 {example_1}\n",
"Image(example_1)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!v.fill.holes input=dissolve_data output=dissolve_data_filled\n",
"!v.db.update map=dissolve_data column=name value=\"area\"\n",
"!v.dissolve input=dissolve_data output=dissolved_data column=name\n",
"!v.fill.holes input=dissolved_data output=dissolved_data_filled"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!g.region vector=dissolve_data grow=2 res=1\n",
"\n",
"text_position = (75,5)\n",
"\n",
"plot = gj.Map(use_region=True, width=700)\n",
"plot.d_background(color=\"white\")\n",
"plot.d_vect(map=\"dissolve_data\")\n",
"plot.d_text(at=text_position, color=\"black\", text=\"(a) Original\")\n",
"plot.save(\"original.png\")\n",
"\n",
"plot = gj.Map(use_region=True, width=700)\n",
"plot.d_background(color=\"white\")\n",
"plot.d_vect(map=\"dissolve_data_filled\")\n",
"plot.d_text(at=text_position, color=\"black\", text=\"() Filled without dissolve\")\n",
"plot.save(\"not_working.png\")\n",
"\n",
"plot = gj.Map(use_region=True, width=700)\n",
"plot.d_background(color=\"white\")\n",
"plot.d_vect(map=\"dissolved_data\")\n",
"plot.d_text(at=text_position, color=\"black\", text=\"(b) Dissloved\")\n",
"plot.save(\"dissolved.png\")\n",
"\n",
"plot = gj.Map(use_region=True, width=700)\n",
"plot.d_background(color=\"white\")\n",
"plot.d_vect(map=\"dissolved_data_filled\")\n",
"plot.d_text(at=text_position, color=\"black\", text=\"(c) Filled\")\n",
"plot.save(\"filled.png\")\n",
"\n",
"example_2 = \"v_fill_holes_filled_with_dissolve.png\"\n",
"!montage original.png dissolved.png filled.png -tile 3x1 -geometry +0+0 {example_2}\n",
"Image(example_2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Example"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!v.extract --overwrite input=lakes where=\"FTYPE != 'ROCK/ISLAND'\" output=lakes_only --qq"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!g.region n=243300 s=242950 w=647200 e=648000"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plot = gj.Map(use_region=True, width=700)\n",
"plot.d_background(color=\"white\")\n",
"plot.d_vect(map=\"lakes_only\", legend_label=\"Original\")\n",
"plot.d_legend_vect(flags=\"b\", at=(60,10))\n",
"plot.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!v.fill.holes input=lakes_only output=lakes_filled"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plot = gj.Map(use_region=True, width=700)\n",
"plot.d_background(color=\"white\")\n",
"plot.d_vect(map=\"lakes_filled\", legend_label=\"Filled\")\n",
"plot.d_legend_vect(flags=\"b\", at=(60,10))\n",
"plot.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!v.dissolve input=lakes_filled column=NAME output=lakes_dissolved --qq"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plot = gj.Map(use_region=True, width=700)\n",
"plot.d_background(color=\"white\")\n",
"plot.d_vect(map=\"lakes_dissolved\", legend_label=\"Dissolved\")\n",
"plot.d_legend_vect(flags=\"b\", at=(60,10))\n",
"plot.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plot = gj.Map(use_region=True, width=1024)\n",
"plot.d_background(color=\"#E28A2B\")\n",
"plot.d_vect(map=\"lakes_filled\", color=\"none\", fill_color=\"#384C6B\", legend_label=\"Filled\")\n",
"plot.d_vect(map=\"lakes_only\", color=\"#859BBA\", fill_color=\"none\", width=2, legend_label=\"Original\")\n",
"plot.d_legend_vect(flags=\"b\", at=(80,85), fontsize=22, symbol_size=35)\n",
"filename = \"v_fill_holes.png\"\n",
"plot.save(filename)\n",
"!mogrify -trim {filename}\n",
"!pngquant --ext \".png\" -f {filename}\n",
"!optipng -o7 {filename}\n",
"Image(filename)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.10"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

0 comments on commit 3083e78

Please sign in to comment.