Skip to content

Commit

Permalink
finalize the tutorial for the ezdxf.select module
Browse files Browse the repository at this point in the history
  • Loading branch information
mozman committed Mar 18, 2024
1 parent 553a92b commit 2d6e714
Show file tree
Hide file tree
Showing 10 changed files with 270 additions and 0 deletions.
160 changes: 160 additions & 0 deletions docs/source/tutorials/entity_selection.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,22 @@ This tutorial shows how to use the :mod:`ezdxf.select` module, which provides fu
to select entities based on various shapes. These selection functions offer a way to
filter entities based on their spatial location.

This is the base document for this tutorial:

.. figure:: gfx/select-base.png

Why Bounding Boxes?
-------------------

The :mod:`~ezdxf.select` module primarily relies on bounding boxes to perform selections.
Bounding boxes offer a fast way to identify potential overlaps between entities and the
selection shape. This approach prioritizes performance over absolute accuracy.

.. note::

The bounding boxes for text-based entities and entities containing curves are not
accurate! For more information read the docs for the :mod:`ezdxf.bbox` module.

Source of Entities
------------------

Expand Down Expand Up @@ -53,11 +62,47 @@ Bounding Box Inside Selection

Selects entities which bounding boxes are completely within the selection shape.

Example to select entities inside a window:

.. figure:: gfx/select-inside-window.png


.. code-block:: Python
import ezdxf
from ezdxf import select
doc = ezdxf.readfile("base.dxf")
msp 0 doc.modelspace()
window = select.Window((150, 105), (280, 240))
for entity in select.bbox_inside(window, msp):
print(str(entity))
output::

CIRCLE(#9D)
LWPOLYLINE(#9E)

Bounding Box Outside Selection
------------------------------

Selects entities whose bounding box is completely outside the selection shape.

.. figure:: gfx/select-outside-window.png

.. code-block:: Python
window = select.Window((185, 105), (245, 240))
for entity in select.bbox_outside(window, msp):
print(str(entity))
output::

TEXT(#9F)
SPLINE(#A0)
LINE(#A1)

Bounding Box Overlap Selection
------------------------------

Expand All @@ -69,19 +114,134 @@ selection shape. This will also select elements where all of the entity geometr
outside the selection shape, but the bounding box overlaps the selection shape,
e.g. border polylines.

.. figure:: gfx/select-inside-window.png

.. code-block:: Python
window = select.Window((150, 105), (280, 240))
for entity in select.bbox_overlap(window, msp):
print(str(entity))
output::

CIRCLE(#9D)
LWPOLYLINE(#9E)
TEXT(#9F)
SPLINE(#A0)
LINE(#A1)
LWPOLYLINE(#A2)

Bounding Box Chained Selection
------------------------------

Selects elements that are directly or indirectly connected to each other by overlapping
bounding boxes. The selection begins at the specified starting element.

.. figure:: gfx/select-chained.png

.. code-block:: Python
# choose entity for the beginning of the chain:
line = msp.query("LINE").first
for entity in select.bbox_chained(line, msp):
print(str(entity))
output::

LINE(#A1)
CIRCLE(#9D)
LWPOLYLINE(#9E)
SPLINE(#A0)

Bounding Box Crosses Fence
--------------------------

Selects entities whose bounding box intersects an open polyline.

.. figure:: gfx/select-fence.png

.. code-block:: Python
for entity in select.bbox_crosses_fence([(83, 101), (186, 193), (300, 107)], msp):
print(str(entity))
output::

CIRCLE(#9D)
LWPOLYLINE(#9E)
SPLINE(#A0)
LINE(#A1)

.. note::

The polyline does not cross the entity geometry itself!

Point In Bounding Box Selection
-------------------------------

Selects entities where the selection point lies within the bounding box.

.. figure:: gfx/select-point.png

.. code-block:: Python
for entity in select.bbox_point((264, 140), msp):
print(str(entity))
output::

LWPOLYLINE(#9E)
SPLINE(#A0)

Circle Selection
----------------

For the circle shape, the selection tests are carried out on the real circlar area.

This example selects all entities around the CIRCLE entity within a 60 unit radius
whose bounding box overlaps the circle selection:

.. figure:: gfx/select-by-circle.png

.. code-block:: Python
entity = msp.query("CIRCLE").first
circle = select.Circle(entity.dxf.center, radius=60)
for entity in select.bbox_overlap(circle, msp):
print(str(entity))
output::

CIRCLE(#9D)
LWPOLYLINE(#9E)
TEXT(#9F)
SPLINE(#A0)

Polygon Selection
-----------------

As for the circle shape, the polygon selection tests are carried out on the real polygon
area.

.. note::

This may not work 100% correctly if the selection polygon has a complex convex shape!

This example selects all entities whose bounding box lies entirely within the selection
polygon:

.. figure:: gfx/select-by-polygon.png

.. code-block:: Python
polygon = select.Polygon([(110, 168), (110, 107), (316, 107), (316, 243), (236, 243)])
for entity in select.bbox_inside(polygon, msp):
print(str(entity))
output::

LWPOLYLINE(#9E)
SPLINE(#A0)
LINE(#A1)

Binary file added docs/source/tutorials/gfx/select-base.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/tutorials/gfx/select-by-circle.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/tutorials/gfx/select-by-polygon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/tutorials/gfx/select-chained.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/tutorials/gfx/select-fence.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/tutorials/gfx/select-point.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
110 changes: 110 additions & 0 deletions docs/source/tutorials/src/select.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# Copyright (c) 2024, Manfred Moitzi
# License: MIT License
from pathlib import Path
import ezdxf
from ezdxf import bbox, select

CWD = Path("~/Desktop/Now/ezdxf/select").expanduser()
if not CWD.exists():
CWD = Path(".")

BASE = "base.dxf"


def select_inside_window():
print("\nselect inside window:")
doc = ezdxf.readfile(CWD / BASE)

window = select.Window((150, 105), (280, 240))
for entity in select.bbox_inside(window, doc.modelspace()):
print(str(entity))


def select_outside_window():
print("\nselect outside window:")
doc = ezdxf.readfile(CWD / BASE)

window = select.Window((185, 105), (245, 240))
for entity in select.bbox_outside(window, doc.modelspace()):
print(str(entity))


def select_overlap_window():
print("\nselect overlap window:")
doc = ezdxf.readfile(CWD / BASE)

window = select.Window((150, 105), (280, 240))
for entity in select.bbox_overlap(window, doc.modelspace()):
print(str(entity))


def select_crosses_fence():
print("\nselect crossing fence:")
doc = ezdxf.readfile(CWD / BASE)
msp = doc.modelspace()

for entity in select.bbox_crosses_fence(
[(83, 101), (186, 193), (300, 107)], msp.query("*").layer == "Entities"
):
print(str(entity))


def select_chained():
print("\nselect chained entities:")
doc = ezdxf.readfile(CWD / "chained.dxf")
msp = doc.modelspace()
line = msp.query("LINE").first
for entity in select.bbox_chained(line, msp.query("*").layer == "Entities"):
print(str(entity))


def select_point():
print("\nselect entities by point in bbox:")
doc = ezdxf.readfile(CWD / "point.dxf")
msp = doc.modelspace()
for entity in select.point_in_bbox((264, 140), msp.query("*").layer == "Entities"):
print(str(entity))


def select_by_circle():
print("\nselect by circle:")
doc = ezdxf.readfile(CWD / BASE)
msp = doc.modelspace()
entity = msp.query("CIRCLE").first
circle = select.Circle(entity.dxf.center, radius=60)
for entity in select.bbox_overlap(circle, msp.query("*").layer == "Entities"):
print(str(entity))


def select_by_polygon():
print("\nselect by polygon:")
doc = ezdxf.readfile(CWD / BASE)
msp = doc.modelspace()

vertices = [(110, 168), (110, 107), (316, 107), (316, 243), (236, 243)]
polygon = select.Polygon(vertices)
for entity in select.bbox_inside(polygon, msp):
print(str(entity))


def draw_bboxes(filename: str) -> None:
doc = ezdxf.readfile(CWD / filename)
msp = doc.modelspace()
for entity in msp.query("*").layer == "Entities":
box = bbox.extents((entity,))
msp.add_lwpolyline(
box.rect_vertices(), close=True, dxfattribs={"layer": "BoundingBox"}
)
doc.saveas(CWD / "bboxes.dxf")


if __name__ == "__main__":
draw_bboxes(BASE)
select_inside_window()
select_outside_window()
select_overlap_window()
select_crosses_fence()
select_chained()
select_point()
select_by_circle()
select_by_polygon()

0 comments on commit 2d6e714

Please sign in to comment.