PartSegCore-compiled-backend 0.15.11__tar.gz → 0.15.13__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/.pre-commit-config.yaml +3 -6
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/PKG-INFO +30 -5
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/Readme.md +25 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/pyproject.toml +7 -1
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/_fast_unique.pyx +1 -1
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/multiscale_opening/mso.h +1 -1
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/sprawl_utils/find_split.py +0 -2
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/triangulation/intersection.hpp +23 -15
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/triangulation/point.hpp +13 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/triangulation/triangulate.hpp +63 -11
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/version.py +9 -4
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/tests/test_triangulate.py +53 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/.gitignore +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/CMakeLists.txt +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/LICENSE.txt +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/MANIFEST.in +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/docs/Makefile +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/docs/calc_bounds.rst +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/docs/conf.py +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/docs/fast_unique.rst +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/docs/index.rst +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/docs/make.bat +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/docs/napari_mapping.rst +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/docs/sprawl_utils.rst +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/__init__.py +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/_fast_unique.pyi +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/_napari_mapping.pyx +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/calc_bounds.pyi +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/calc_bounds.pyx +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/color_image_cython.pyi +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/color_image_cython.pyx +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/fast_unique.py +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/multiscale_opening/__init__.py +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/multiscale_opening/mso_bind.pyi +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/multiscale_opening/mso_bind.pyx +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/multiscale_opening/my_queue.h +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/napari_mapping.py +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/sprawl_utils/__init__.py +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/sprawl_utils/distance_utils.pxd +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/sprawl_utils/euclidean_cython.pyi +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/sprawl_utils/euclidean_cython.pyx +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/sprawl_utils/find_split.pyi +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/sprawl_utils/fuzzy_distance.pyx +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/sprawl_utils/global_consts.h +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/sprawl_utils/my_queue.h +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/sprawl_utils/path_sprawl_cython.pyi +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/sprawl_utils/path_sprawl_cython.pyx +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/sprawl_utils/put_borders_in_queue.pyx +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/sprawl_utils/sprawl_utils.pyi +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/sprawl_utils/sprawl_utils.pyx +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/triangulate.pyx +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/triangulation/debug_util.hpp +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/PartSegCore_compiled_backend/utils.py +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/tests/test_calc_bounds.py +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/tests/test_coloring.py +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/tests/test_fast_unique.py +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/tests/test_napari_mapping.py +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/tests/test_sprawl_utils/__init__.py +0 -0
- {partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/src/tests/test_sprawl_utils/test_euclidean.py +0 -0
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
default_language_version:
|
|
2
|
-
python: python3.9
|
|
3
|
-
|
|
4
1
|
repos:
|
|
5
2
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
6
3
|
# Ruff version.
|
|
7
|
-
rev: v0.
|
|
4
|
+
rev: v0.12.0
|
|
8
5
|
hooks:
|
|
9
6
|
# Run the linter.
|
|
10
7
|
- id: ruff
|
|
@@ -30,13 +27,13 @@ repos:
|
|
|
30
27
|
hooks:
|
|
31
28
|
- id: markdownlint
|
|
32
29
|
- repo: https://github.com/codespell-project/codespell
|
|
33
|
-
rev: v2.
|
|
30
|
+
rev: v2.4.1
|
|
34
31
|
hooks:
|
|
35
32
|
- id: codespell
|
|
36
33
|
additional_dependencies:
|
|
37
34
|
- tomli
|
|
38
35
|
- repo: https://github.com/pre-commit/mirrors-clang-format
|
|
39
|
-
rev:
|
|
36
|
+
rev: v20.1.6 # Use the sha / tag you want to point at
|
|
40
37
|
hooks:
|
|
41
38
|
- id: clang-format
|
|
42
39
|
args: ["-style=Google"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: PartSegCore_compiled_backend
|
|
3
|
-
Version: 0.15.
|
|
3
|
+
Version: 0.15.13
|
|
4
4
|
Summary: PartSegCore compiled backend,
|
|
5
5
|
Keywords: bioimaging
|
|
6
6
|
Author-Email: Grzegorz Bokota <g.bokota@cent.uw.edu.pl>
|
|
@@ -18,13 +18,13 @@ Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
|
18
18
|
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
19
19
|
Project-URL: Homepage, https://4dnucleome.cent.uw.edu.pl/PartSeg/
|
|
20
20
|
Project-URL: Documentation, https://partsegcore-compiled-backend.readthedocs.io/en/stable/
|
|
21
|
-
Project-URL: Source
|
|
21
|
+
Project-URL: Source Code, https://github.com/4DNucleome/PartSegCore-compiled-backend
|
|
22
22
|
Requires-Python: >=3.9
|
|
23
23
|
Requires-Dist: numpy>=1.23.5
|
|
24
|
-
Requires-Dist: pytest>=7.0.0; extra == "test"
|
|
25
|
-
Requires-Dist: sphinx>=5.0.0; extra == "docs"
|
|
26
24
|
Provides-Extra: test
|
|
25
|
+
Requires-Dist: pytest>=7.0.0; extra == "test"
|
|
27
26
|
Provides-Extra: docs
|
|
27
|
+
Requires-Dist: sphinx>=5.0.0; extra == "docs"
|
|
28
28
|
Description-Content-Type: text/markdown
|
|
29
29
|
|
|
30
30
|
# PartSegCore_compiled_backend
|
|
@@ -61,6 +61,31 @@ pip install .
|
|
|
61
61
|
As currently there is no wheel for macOS ARM64
|
|
62
62
|
it is required to build package from source.
|
|
63
63
|
|
|
64
|
+
## Development in Clion
|
|
65
|
+
|
|
66
|
+
To install Python build dependencies, run:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
pip install scikit-build-core cython cython-cmake numpy setuptools-scm
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Then, install the package in development mode:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
pip install --no-build-isolation --config-settings=editable.rebuild=true\
|
|
76
|
+
-Cbuild-dir=build -ve .
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
vendor `FindCython.cmake` from cython-cmake to `cmake` directory.
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
mkdir cmake && cython-cmake vendor cmake
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Set `CUSTOM_MODULE_PATH` environment variable to full path to cmake directory.
|
|
86
|
+
|
|
87
|
+
Set it in Settings → Build, Execution, Deployment → CMake → Environment
|
|
88
|
+
|
|
64
89
|
## Cite as
|
|
65
90
|
|
|
66
91
|
Bokota, G., Sroka, J., Basu, S. et al. PartSeg: a tool for quantitative feature extraction
|
|
@@ -32,6 +32,31 @@ pip install .
|
|
|
32
32
|
As currently there is no wheel for macOS ARM64
|
|
33
33
|
it is required to build package from source.
|
|
34
34
|
|
|
35
|
+
## Development in Clion
|
|
36
|
+
|
|
37
|
+
To install Python build dependencies, run:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install scikit-build-core cython cython-cmake numpy setuptools-scm
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Then, install the package in development mode:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install --no-build-isolation --config-settings=editable.rebuild=true\
|
|
47
|
+
-Cbuild-dir=build -ve .
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
vendor `FindCython.cmake` from cython-cmake to `cmake` directory.
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
mkdir cmake && cython-cmake vendor cmake
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Set `CUSTOM_MODULE_PATH` environment variable to full path to cmake directory.
|
|
57
|
+
|
|
58
|
+
Set it in Settings → Build, Execution, Deployment → CMake → Environment
|
|
59
|
+
|
|
35
60
|
## Cite as
|
|
36
61
|
|
|
37
62
|
Bokota, G., Sroka, J., Basu, S. et al. PartSeg: a tool for quantitative feature extraction
|
{partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/pyproject.toml
RENAMED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
[build-system]
|
|
2
2
|
# Minimum requirements for the build system to execute.
|
|
3
|
-
requires = [
|
|
3
|
+
requires = [
|
|
4
|
+
"scikit-build-core",
|
|
5
|
+
"Cython",
|
|
6
|
+
"cython-cmake",
|
|
7
|
+
"numpy>=2",
|
|
8
|
+
"setuptools_scm[toml]>=8.1"
|
|
9
|
+
] # PEP 508 specifications.
|
|
4
10
|
build-backend = "scikit_build_core.build"
|
|
5
11
|
|
|
6
12
|
[tool.scikit-build]
|
|
@@ -27,7 +27,7 @@ ctypedef fused numpy_int_types:
|
|
|
27
27
|
def unique1d(np.ndarray[numpy_int_types, ndim=1] array):
|
|
28
28
|
cdef unordered_set[numpy_int_types] unique_values
|
|
29
29
|
cdef vector[unordered_set[numpy_int_types]] unique_values_vector
|
|
30
|
-
cdef Py_ssize_t i, j, n_rows, n_cols, id_num
|
|
30
|
+
cdef Py_ssize_t i, j, n_rows, n_cols, id_num, n_items
|
|
31
31
|
cdef numpy_int_types prev_val, v
|
|
32
32
|
n_items = array.shape[0]
|
|
33
33
|
unique_values_vector.resize(50) # openmp.omp_get_num_threads())
|
|
@@ -580,7 +580,7 @@ class MSO {
|
|
|
580
580
|
queue_copy = queue;
|
|
581
581
|
// std::cerr << "# Queue1 " << queue.get_size() << " Queue2 " <<
|
|
582
582
|
// queue_copy.get_size() << std::endl;
|
|
583
|
-
// Calculate area which can be reached by monoticall path (
|
|
583
|
+
// Calculate area which can be reached by monoticall path (first part of
|
|
584
584
|
// Morphological neighborhood)
|
|
585
585
|
while (!queue.empty()) {
|
|
586
586
|
coord = queue.front();
|
|
@@ -4,7 +4,6 @@ This module contains function to perform multiple component sprawl (watershed li
|
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
|
-
import logging
|
|
8
7
|
import os
|
|
9
8
|
import typing
|
|
10
9
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
@@ -385,7 +384,6 @@ def reverse_permutation(perm: list[int]) -> list[int]:
|
|
|
385
384
|
|
|
386
385
|
|
|
387
386
|
def relabel_with_perm(labeling: list, perm: list) -> list:
|
|
388
|
-
logging.debug('%(labeling), %(perm)', extra={'labeling': labeling, 'perm': perm})
|
|
389
387
|
perm = reverse_permutation(perm)
|
|
390
388
|
return [perm[x] for x in labeling]
|
|
391
389
|
|
|
@@ -112,6 +112,12 @@ inline int64_t double_as_hex(double d) {
|
|
|
112
112
|
return result;
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
enum Orientation {
|
|
116
|
+
COLLINEAR = 0,
|
|
117
|
+
CLOCKWISE = 1,
|
|
118
|
+
COUNTERCLOCKWISE = 2,
|
|
119
|
+
};
|
|
120
|
+
|
|
115
121
|
/**
|
|
116
122
|
* Determines the orientation of the triplet (p, q, r).
|
|
117
123
|
*
|
|
@@ -119,12 +125,14 @@ inline int64_t double_as_hex(double d) {
|
|
|
119
125
|
* @param q The second point.
|
|
120
126
|
* @param r The third point.
|
|
121
127
|
*
|
|
122
|
-
* @return
|
|
123
|
-
*
|
|
124
|
-
*
|
|
128
|
+
* @return Orientation::COLLINEAR if p, q and r are collinear.
|
|
129
|
+
* Orientation::CLOCKWISE if the triplet (p, q, r) is in a clockwise
|
|
130
|
+
* orientation.
|
|
131
|
+
* Orientation::COUNTERCLOCKWISE if the triplet (p, q, r) is in a
|
|
132
|
+
* counterclockwise orientation.
|
|
125
133
|
*/
|
|
126
|
-
inline
|
|
127
|
-
|
|
134
|
+
inline Orientation _orientation(const point::Point &p, const point::Point &q,
|
|
135
|
+
const point::Point &r) {
|
|
128
136
|
double val1 = ((q.y - p.y) * (r.x - q.x));
|
|
129
137
|
double val2 = ((r.y - q.y) * (q.x - p.x));
|
|
130
138
|
// This commented code if for debugging purposes of differences between macOS
|
|
@@ -142,8 +150,8 @@ inline int _orientation(const point::Point &p, const point::Point &q,
|
|
|
142
150
|
// }
|
|
143
151
|
// Instead of using classical equation, we need to use two variables
|
|
144
152
|
// to handle problem with strange behavior on macOS.
|
|
145
|
-
if (val1 == val2) return
|
|
146
|
-
return (val1 > val2) ?
|
|
153
|
+
if (val1 == val2) return Orientation::COLLINEAR;
|
|
154
|
+
return (val1 > val2) ? Orientation::CLOCKWISE : Orientation::COUNTERCLOCKWISE;
|
|
147
155
|
}
|
|
148
156
|
|
|
149
157
|
/**
|
|
@@ -163,17 +171,17 @@ inline bool _do_intersect(const point::Segment &s1, const point::Segment &s2) {
|
|
|
163
171
|
const point::Point &p2 = s2.bottom;
|
|
164
172
|
const point::Point &q2 = s2.top;
|
|
165
173
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
174
|
+
Orientation o1 = _orientation(p1, q1, p2);
|
|
175
|
+
Orientation o2 = _orientation(p1, q1, q2);
|
|
176
|
+
Orientation o3 = _orientation(p2, q2, p1);
|
|
177
|
+
Orientation o4 = _orientation(p2, q2, q1);
|
|
170
178
|
|
|
171
179
|
if (o1 != o2 && o3 != o4) return true;
|
|
172
180
|
|
|
173
|
-
if (o1 ==
|
|
174
|
-
if (o2 ==
|
|
175
|
-
if (o3 ==
|
|
176
|
-
if (o4 ==
|
|
181
|
+
if (o1 == Orientation::COLLINEAR && _on_segment(p1, p2, q1)) return true;
|
|
182
|
+
if (o2 == Orientation::COLLINEAR && _on_segment(p1, q2, q1)) return true;
|
|
183
|
+
if (o3 == Orientation::COLLINEAR && _on_segment(p2, p1, q2)) return true;
|
|
184
|
+
if (o4 == Orientation::COLLINEAR && _on_segment(p2, q1, q2)) return true;
|
|
177
185
|
|
|
178
186
|
return false;
|
|
179
187
|
}
|
|
@@ -208,6 +208,19 @@ struct Segment {
|
|
|
208
208
|
}
|
|
209
209
|
};
|
|
210
210
|
};
|
|
211
|
+
Point centroid(const std::vector<Point> &point_list) {
|
|
212
|
+
if (point_list.empty()) {
|
|
213
|
+
return {0, 0};
|
|
214
|
+
}
|
|
215
|
+
Point res(0, 0);
|
|
216
|
+
for (auto &point : point_list) {
|
|
217
|
+
res.x += point.x;
|
|
218
|
+
res.y += point.y;
|
|
219
|
+
}
|
|
220
|
+
res.x /= float(point_list.size());
|
|
221
|
+
res.y /= float(point_list.size());
|
|
222
|
+
return res;
|
|
223
|
+
}
|
|
211
224
|
} // namespace partsegcore::point
|
|
212
225
|
|
|
213
226
|
// overload of hash function for
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
#define PARTSEGCORE_TRIANGULATE_H
|
|
3
3
|
|
|
4
4
|
#include <algorithm>
|
|
5
|
+
#include <cmath>
|
|
5
6
|
#include <map>
|
|
6
7
|
#include <memory> // memory header is required on linux, and not on macos
|
|
7
8
|
#include <set>
|
|
@@ -602,6 +603,36 @@ struct MonotonePolygonBuilder {
|
|
|
602
603
|
};
|
|
603
604
|
};
|
|
604
605
|
|
|
606
|
+
/*
|
|
607
|
+
* Check if the polygon, that all angles have the same orientation
|
|
608
|
+
* do not have self-intersections
|
|
609
|
+
*
|
|
610
|
+
* @param begin Iterator to the first point of the polygon
|
|
611
|
+
* @param end Iterator to the end of the polygon
|
|
612
|
+
* @param centroid Centroid of the polygon
|
|
613
|
+
*
|
|
614
|
+
* @return True if the polygon is simple, false otherwise
|
|
615
|
+
*/
|
|
616
|
+
template <typename Iterator>
|
|
617
|
+
bool is_simple_polygon(Iterator begin, Iterator end, point::Point centroid) {
|
|
618
|
+
double start_angle = std::atan2(begin->y - centroid.y, begin->x - centroid.x);
|
|
619
|
+
double prev_angle = 0;
|
|
620
|
+
begin++;
|
|
621
|
+
for (; begin != end; begin++) {
|
|
622
|
+
double angle =
|
|
623
|
+
std::atan2(begin->y - centroid.y, begin->x - centroid.x) - start_angle;
|
|
624
|
+
if (angle < 0) {
|
|
625
|
+
angle += 2 * M_PI;
|
|
626
|
+
}
|
|
627
|
+
if (angle < prev_angle) {
|
|
628
|
+
return false;
|
|
629
|
+
} else {
|
|
630
|
+
prev_angle = angle;
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
return true;
|
|
634
|
+
}
|
|
635
|
+
|
|
605
636
|
/**
|
|
606
637
|
* Checks if a given polygon is convex.
|
|
607
638
|
*
|
|
@@ -615,26 +646,47 @@ struct MonotonePolygonBuilder {
|
|
|
615
646
|
* @return True if the polygon is convex, false otherwise.
|
|
616
647
|
*/
|
|
617
648
|
inline bool _is_convex(const std::vector<point::Point> &polygon) {
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
649
|
+
if (polygon.size() < 3) return false;
|
|
650
|
+
if (polygon.size() == 3) return true;
|
|
651
|
+
intersection::Orientation orientation = intersection::Orientation::COLLINEAR;
|
|
652
|
+
intersection::Orientation triangle_orientation;
|
|
653
|
+
size_t idx = 0;
|
|
654
|
+
for (; idx < polygon.size() - 2; idx++) {
|
|
655
|
+
triangle_orientation = intersection::_orientation(
|
|
656
|
+
polygon[idx], polygon[(idx + 1)], polygon[(idx + 2)]);
|
|
657
|
+
if (triangle_orientation != intersection::Orientation::COLLINEAR) {
|
|
625
658
|
orientation = triangle_orientation;
|
|
626
|
-
|
|
659
|
+
break;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
if (orientation == intersection::Orientation::COLLINEAR) {
|
|
663
|
+
return false;
|
|
664
|
+
}
|
|
665
|
+
for (; idx < polygon.size() - 2; idx++) {
|
|
666
|
+
triangle_orientation = intersection::_orientation(
|
|
667
|
+
polygon[idx], polygon[(idx + 1)], polygon[(idx + 2)]);
|
|
668
|
+
if (triangle_orientation != 0 && triangle_orientation != orientation) {
|
|
627
669
|
return false;
|
|
670
|
+
}
|
|
628
671
|
}
|
|
629
672
|
triangle_orientation = intersection::_orientation(
|
|
630
673
|
polygon[polygon.size() - 2], polygon[polygon.size() - 1], polygon[0]);
|
|
631
|
-
if (triangle_orientation != 0 && triangle_orientation != orientation)
|
|
674
|
+
if (triangle_orientation != 0 && triangle_orientation != orientation) {
|
|
632
675
|
return false;
|
|
676
|
+
}
|
|
633
677
|
triangle_orientation = intersection::_orientation(polygon[polygon.size() - 1],
|
|
634
678
|
polygon[0], polygon[1]);
|
|
635
|
-
if (triangle_orientation != 0 && triangle_orientation != orientation)
|
|
679
|
+
if (triangle_orientation != 0 && triangle_orientation != orientation) {
|
|
636
680
|
return false;
|
|
637
|
-
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
point::Point centroid = point::centroid(polygon);
|
|
684
|
+
|
|
685
|
+
if (orientation == intersection::Orientation::COUNTERCLOCKWISE) {
|
|
686
|
+
return is_simple_polygon(polygon.begin(), polygon.end(), centroid);
|
|
687
|
+
} else {
|
|
688
|
+
return is_simple_polygon(polygon.rbegin(), polygon.rend(), centroid);
|
|
689
|
+
}
|
|
638
690
|
}
|
|
639
691
|
|
|
640
692
|
/**
|
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
# file generated by
|
|
1
|
+
# file generated by setuptools-scm
|
|
2
2
|
# don't change, don't track in version control
|
|
3
|
+
|
|
4
|
+
__all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
|
|
5
|
+
|
|
3
6
|
TYPE_CHECKING = False
|
|
4
7
|
if TYPE_CHECKING:
|
|
5
|
-
from typing import Tuple
|
|
8
|
+
from typing import Tuple
|
|
9
|
+
from typing import Union
|
|
10
|
+
|
|
6
11
|
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
7
12
|
else:
|
|
8
13
|
VERSION_TUPLE = object
|
|
@@ -12,5 +17,5 @@ __version__: str
|
|
|
12
17
|
__version_tuple__: VERSION_TUPLE
|
|
13
18
|
version_tuple: VERSION_TUPLE
|
|
14
19
|
|
|
15
|
-
__version__ = version = '0.15.
|
|
16
|
-
__version_tuple__ = version_tuple = (0, 15,
|
|
20
|
+
__version__ = version = '0.15.13'
|
|
21
|
+
__version_tuple__ = version_tuple = (0, 15, 13)
|
|
@@ -208,6 +208,7 @@ def test_triangle_convex_polygon():
|
|
|
208
208
|
],
|
|
209
209
|
)
|
|
210
210
|
def test_triangulate_polygon_py_convex(polygon, expected):
|
|
211
|
+
assert is_convex(polygon)
|
|
211
212
|
assert triangulate_polygon_py(polygon)[0] == expected
|
|
212
213
|
|
|
213
214
|
|
|
@@ -691,3 +692,55 @@ def test_splitting_edges(split_edges, triangles):
|
|
|
691
692
|
)
|
|
692
693
|
triangles_ = triangulate_polygon_with_edge_numpy_li([polygon], split_edges=split_edges)[1][2]
|
|
693
694
|
assert len(triangles_) == triangles
|
|
695
|
+
|
|
696
|
+
|
|
697
|
+
def generate_regular_polygon(n: int, reverse: bool, radius: int = 1) -> np.ndarray:
|
|
698
|
+
angles = np.linspace(0, 2 * np.pi, n, endpoint=False)
|
|
699
|
+
if reverse:
|
|
700
|
+
angles = angles[::-1]
|
|
701
|
+
return np.column_stack((radius * np.cos(angles), radius * np.sin(angles)))
|
|
702
|
+
|
|
703
|
+
|
|
704
|
+
def generate_self_intersecting_polygon(n: int, reverse: bool, radius: int = 1) -> np.ndarray:
|
|
705
|
+
"""Generate self-intersecting polygon with n vertices
|
|
706
|
+
|
|
707
|
+
The polygon is generated by doubling the angle range of a regular polygon
|
|
708
|
+
"""
|
|
709
|
+
assert n % 2 == 1, 'an odd number is required to generate a self-intersecting polygon'
|
|
710
|
+
angles = np.linspace(0, 4 * np.pi, n, endpoint=False)
|
|
711
|
+
if reverse:
|
|
712
|
+
angles = angles[::-1]
|
|
713
|
+
return np.column_stack((radius * np.cos(angles), radius * np.sin(angles)))
|
|
714
|
+
|
|
715
|
+
|
|
716
|
+
def rotation_matrix(angle: float) -> np.ndarray:
|
|
717
|
+
"""Create a 2D rotation matrix for the given angle in degrees."""
|
|
718
|
+
return np.array(
|
|
719
|
+
[
|
|
720
|
+
[np.cos(np.radians(angle)), -np.sin(np.radians(angle))],
|
|
721
|
+
[np.sin(np.radians(angle)), np.cos(np.radians(angle))],
|
|
722
|
+
]
|
|
723
|
+
)
|
|
724
|
+
|
|
725
|
+
|
|
726
|
+
ANGLES = [0, 5, 75, 95, 355]
|
|
727
|
+
|
|
728
|
+
|
|
729
|
+
@pytest.mark.parametrize('angle', ANGLES, ids=str)
|
|
730
|
+
@pytest.mark.parametrize('n_vertex', [5, 7, 19])
|
|
731
|
+
@pytest.mark.parametrize('reverse', [False, True])
|
|
732
|
+
def test_is_convex_self_intersection(angle, n_vertex, reverse):
|
|
733
|
+
p = generate_self_intersecting_polygon(n_vertex, reverse)
|
|
734
|
+
rot = rotation_matrix(angle)
|
|
735
|
+
data = np.dot(p, rot)
|
|
736
|
+
assert not is_convex(data)
|
|
737
|
+
|
|
738
|
+
|
|
739
|
+
@pytest.mark.parametrize('angle', ANGLES, ids=str)
|
|
740
|
+
@pytest.mark.parametrize('n_vertex', [3, 4, 7, 12, 15, 20])
|
|
741
|
+
@pytest.mark.parametrize('reverse', [False, True])
|
|
742
|
+
def test_is_convex_regular_polygon(angle, n_vertex, reverse):
|
|
743
|
+
poly = generate_regular_polygon(n_vertex, reverse=reverse)
|
|
744
|
+
rot = rotation_matrix(angle)
|
|
745
|
+
rotated_poly = np.dot(poly, rot)
|
|
746
|
+
assert is_convex(rotated_poly)
|
|
File without changes
|
{partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/CMakeLists.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/docs/calc_bounds.rst
RENAMED
|
File without changes
|
|
File without changes
|
{partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/docs/fast_unique.rst
RENAMED
|
File without changes
|
{partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/docs/index.rst
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{partsegcore_compiled_backend-0.15.11 → partsegcore_compiled_backend-0.15.13}/docs/sprawl_utils.rst
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|