kaxe 1.5.7.dev0__tar.gz → 1.6.0.dev0__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.
- {kaxe-1.5.7.dev0/src/kaxe.egg-info → kaxe-1.6.0.dev0}/PKG-INFO +1 -1
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/pyproject.toml +1 -1
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/helper.py +35 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/shapes.py +16 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/svg.py +63 -5
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/text.py +30 -1
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/objects/d2/contour.py +75 -27
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/objects/d2/inequality.py +99 -3
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0/src/kaxe.egg-info}/PKG-INFO +1 -1
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/LICENSE +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/MANIFEST.in +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/README.md +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/setup.cfg +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/__init__.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/_require_3d.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/chart/__init__.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/chart/bar.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/chart/box.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/chart/pie.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/chart/qqplot.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/__init__.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/axis.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/bounds.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/color.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/d3/backend.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/d3/camera.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/d3/helper.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/d3/hud.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/d3/objects/__init__.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/d3/objects/color.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/d3/objects/line.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/d3/objects/point.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/d3/objects/pointer.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/d3/objects/triangle.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/d3/openglrender.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/d3/translator.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/draw.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/fileloader.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/ipython_display.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/legend.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/line.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/marker.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/profiler.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/progress.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/round.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/styles.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/svg_pdf.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/symbol.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/core/window.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/data/__init__.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/data/excel.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/objects/__init__.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/objects/_lazy.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/objects/d2/__init__.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/objects/d2/arrow.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/objects/d2/bubble.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/objects/d2/equation.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/objects/d2/fill.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/objects/d2/function.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/objects/d2/map.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/objects/d2/parameter.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/objects/d2/pillar.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/objects/d2/point.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/objects/d3/__init__.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/objects/d3/base.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/objects/d3/function.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/objects/d3/mesh.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/objects/d3/point.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/objects/d3/potato.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/objects/function.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/objects/legend.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/objects/mapdata.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/objects/point.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/objects/text.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/plot/__init__.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/plot/_lazy.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/plot/box.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/plot/constants.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/plot/d3/__init__.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/plot/d3/axes.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/plot/d3/geometry.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/plot/d3/plot3d.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/plot/d3/variants.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/plot/double.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/plot/empty.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/plot/grid.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/plot/log.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/plot/polar.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/plot/standard.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/plot/themes.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/plot/zoom.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/plot/zoom_connector.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/project/__init__.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/project/codec.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/project/context.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/project/document.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/project/registry.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/project/sample.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/project/sampled_curve.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/project/serializers.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/project/window.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/__init__.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/__init__.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.bright-oblique.ttf +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.bright-roman.ttf +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.bright-semibold.ttf +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.bright-semiboldoblique.ttf +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.classical-serif-italic.ttf +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.concrete-bold.ttf +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.concrete-bolditalic.ttf +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.concrete-italic.ttf +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.concrete-roman.ttf +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-bold.ttf +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-boldoblique.ttf +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-demi-condensed-demicondensed.ttf +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-medium.ttf +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-oblique.ttf +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.serif-bold.ttf +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.serif-bolditalic.ttf +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.serif-extra-boldslanted.ttf +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.serif-extra-romanslanted.ttf +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.serif-italic.ttf +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.serif-roman.ttf +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.serif-upright-italic-uprightitalic.ttf +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-bold.ttf +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-bolditalic.ttf +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-italic.ttf +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-light.ttf +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-lightoblique.ttf +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-regular.ttf +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-variable-width-italic.ttf +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-variable-width-medium.ttf +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/readme.txt +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/logo-small.png +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/symbolcross.png +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/symboldonut.png +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/symbollollipop.png +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/symboltriangle.png +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe.egg-info/SOURCES.txt +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe.egg-info/dependency_links.txt +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe.egg-info/requires.txt +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe.egg-info/top_level.txt +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/tests/test.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/tests/test2.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/tests/test3.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/tests/test_4.py +0 -0
- {kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/tests/test_5.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kaxe
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.6.0.dev0
|
|
4
4
|
Summary: A small graphing tool for functions, points, equations and more
|
|
5
5
|
Author-email: Valter Yde Daugberg <valteryde@hotmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/valteryde/kaxe
|
|
@@ -87,6 +87,41 @@ def contour_label_angle(func, parent, px, py, polyline=None, tangent_window=40):
|
|
|
87
87
|
return rotation
|
|
88
88
|
|
|
89
89
|
|
|
90
|
+
def bbox_intersects_box(bbox, box_ltrb):
|
|
91
|
+
"""Return True if bbox intersects box_ltrb.
|
|
92
|
+
|
|
93
|
+
``bbox`` is ``(left, top, width, height)``; ``box_ltrb`` is
|
|
94
|
+
``[left, top, right, bottom]`` (same as ``windowBox``).
|
|
95
|
+
"""
|
|
96
|
+
left, top, width, height = bbox
|
|
97
|
+
right = left + width
|
|
98
|
+
bottom = top + height
|
|
99
|
+
box_left, box_top, box_right, box_bottom = box_ltrb
|
|
100
|
+
return not (
|
|
101
|
+
right <= box_left
|
|
102
|
+
or left >= box_right
|
|
103
|
+
or bottom <= box_top
|
|
104
|
+
or top >= box_bottom
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def intersect_bbox_with_box(bbox, box_ltrb):
|
|
109
|
+
"""Return intersection of bbox with box_ltrb as (left, top, w, h), or None."""
|
|
110
|
+
left, top, width, height = bbox
|
|
111
|
+
right = left + width
|
|
112
|
+
bottom = top + height
|
|
113
|
+
box_left, box_top, box_right, box_bottom = box_ltrb
|
|
114
|
+
|
|
115
|
+
ix0 = max(left, box_left)
|
|
116
|
+
iy0 = max(top, box_top)
|
|
117
|
+
ix1 = min(right, box_right)
|
|
118
|
+
iy1 = min(bottom, box_bottom)
|
|
119
|
+
|
|
120
|
+
if ix0 >= ix1 or iy0 >= iy1:
|
|
121
|
+
return None
|
|
122
|
+
return (int(ix0), int(iy0), int(ix1 - ix0), int(iy1 - iy0))
|
|
123
|
+
|
|
124
|
+
|
|
90
125
|
def bbox_overlaps(a, b, padding=0):
|
|
91
126
|
"""Return True if two axis-aligned boxes overlap.
|
|
92
127
|
|
|
@@ -33,6 +33,22 @@ def blitImageToSurface(surface:Image, image:Image, pos:Union[tuple, list]):
|
|
|
33
33
|
return surface.paste(image, (int(pos[0]), int(pos[1])), image)
|
|
34
34
|
|
|
35
35
|
|
|
36
|
+
def blit_image_clipped(surface, image, dest_left, dest_top, clip_ltrb):
|
|
37
|
+
"""Paste ``image`` at (dest_left, dest_top), clipped to clip_ltrb [l,t,r,b]."""
|
|
38
|
+
from .helper import intersect_bbox_with_box
|
|
39
|
+
|
|
40
|
+
dest_bbox = (int(dest_left), int(dest_top), image.width, image.height)
|
|
41
|
+
intersection = intersect_bbox_with_box(dest_bbox, clip_ltrb)
|
|
42
|
+
if intersection is None:
|
|
43
|
+
return
|
|
44
|
+
|
|
45
|
+
ix, iy, iw, ih = intersection
|
|
46
|
+
src_x = ix - int(dest_left)
|
|
47
|
+
src_y = iy - int(dest_top)
|
|
48
|
+
cropped = image.crop((src_x, src_y, src_x + iw, src_y + ih))
|
|
49
|
+
blitImageToSurface(surface, cropped, (ix, iy))
|
|
50
|
+
|
|
51
|
+
|
|
36
52
|
def newImage(width, height, color):
|
|
37
53
|
img = Image.new('RGBA', (int(width), int(height)), color=color)
|
|
38
54
|
return img
|
|
@@ -57,6 +57,8 @@ class SvgDocument:
|
|
|
57
57
|
self._width, self._height = int(size[0]), int(size[1])
|
|
58
58
|
self._elements: list[ET.Element] = []
|
|
59
59
|
self._fondi_font_css: Optional[str] = None
|
|
60
|
+
self._clip_defs: dict[tuple[int, int, int, int], str] = {}
|
|
61
|
+
self._clip_counter = 0
|
|
60
62
|
|
|
61
63
|
@property
|
|
62
64
|
def height(self) -> int:
|
|
@@ -77,6 +79,42 @@ class SvgDocument:
|
|
|
77
79
|
self._elements.append(el)
|
|
78
80
|
return el
|
|
79
81
|
|
|
82
|
+
def get_clip_id(self, box_ltrb) -> str:
|
|
83
|
+
"""Return a stable clip-path id for a kaxe [left, top, right, bottom] box."""
|
|
84
|
+
key = tuple(int(v) for v in box_ltrb)
|
|
85
|
+
if key in self._clip_defs:
|
|
86
|
+
return self._clip_defs[key]
|
|
87
|
+
|
|
88
|
+
clip_id = f"kaxe-clip-{self._clip_counter}"
|
|
89
|
+
self._clip_counter += 1
|
|
90
|
+
self._clip_defs[key] = clip_id
|
|
91
|
+
return clip_id
|
|
92
|
+
|
|
93
|
+
def _clip_rect_element(self, box_ltrb) -> ET.Element:
|
|
94
|
+
left, top, right, bottom = (int(v) for v in box_ltrb)
|
|
95
|
+
svg_y = self.flip_y(bottom)
|
|
96
|
+
height = bottom - top
|
|
97
|
+
width = right - left
|
|
98
|
+
return ET.Element(
|
|
99
|
+
f"{{{SVG_NS}}}rect",
|
|
100
|
+
{
|
|
101
|
+
"x": str(left),
|
|
102
|
+
"y": str(svg_y),
|
|
103
|
+
"width": str(width),
|
|
104
|
+
"height": str(height),
|
|
105
|
+
},
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
def append_clipped(self, element: ET.Element, box_ltrb) -> None:
|
|
109
|
+
"""Append ``element`` inside a group clipped to ``box_ltrb``."""
|
|
110
|
+
clip_id = self.get_clip_id(box_ltrb)
|
|
111
|
+
group = ET.Element(
|
|
112
|
+
f"{{{SVG_NS}}}g",
|
|
113
|
+
{"clip-path": f"url(#{clip_id})"},
|
|
114
|
+
)
|
|
115
|
+
group.append(element)
|
|
116
|
+
self._elements.append(group)
|
|
117
|
+
|
|
80
118
|
def add_rect(
|
|
81
119
|
self,
|
|
82
120
|
x: float,
|
|
@@ -284,6 +322,7 @@ class SvgDocument:
|
|
|
284
322
|
y_coord: str = "bottom",
|
|
285
323
|
rotate: float = 0,
|
|
286
324
|
rotate_center: Optional[tuple[float, float]] = None,
|
|
325
|
+
clip_box: Optional[list] = None,
|
|
287
326
|
) -> None:
|
|
288
327
|
"""Place an image; y is in kaxe coords (y-up). y_coord='bottom' or 'top'."""
|
|
289
328
|
href = pil_to_data_uri(img)
|
|
@@ -302,7 +341,14 @@ class SvgDocument:
|
|
|
302
341
|
if rotate:
|
|
303
342
|
cx, cy = rotate_center or (x + img.width / 2, svg_top + img.height / 2)
|
|
304
343
|
attribs["transform"] = f"rotate({-rotate},{cx},{cy})"
|
|
305
|
-
|
|
344
|
+
el = ET.Element(
|
|
345
|
+
f"{{{SVG_NS}}}image",
|
|
346
|
+
{k: str(v) for k, v in attribs.items() if v is not None},
|
|
347
|
+
)
|
|
348
|
+
if clip_box is not None:
|
|
349
|
+
self.append_clipped(el, clip_box)
|
|
350
|
+
else:
|
|
351
|
+
self._elements.append(el)
|
|
306
352
|
|
|
307
353
|
def _ensure_fondi_fonts(self) -> None:
|
|
308
354
|
if self._fondi_font_css is not None:
|
|
@@ -319,6 +365,7 @@ class SvgDocument:
|
|
|
319
365
|
*,
|
|
320
366
|
rotate: float = 0,
|
|
321
367
|
rotate_center: Optional[tuple[float, float]] = None,
|
|
368
|
+
clip_box: Optional[list] = None,
|
|
322
369
|
) -> None:
|
|
323
370
|
"""Embed a fondi scene (vector math text) at SVG top-left coordinates."""
|
|
324
371
|
from fondi.backends import render_svg
|
|
@@ -347,7 +394,10 @@ class SvgDocument:
|
|
|
347
394
|
group = ET.Element(f"{{{SVG_NS}}}g", {"transform": transform})
|
|
348
395
|
for child in list(inner):
|
|
349
396
|
group.append(copy.deepcopy(child))
|
|
350
|
-
|
|
397
|
+
if clip_box is not None:
|
|
398
|
+
self.append_clipped(group, clip_box)
|
|
399
|
+
else:
|
|
400
|
+
self._elements.append(group)
|
|
351
401
|
|
|
352
402
|
def serialize(self) -> str:
|
|
353
403
|
root = ET.Element(
|
|
@@ -359,10 +409,18 @@ class SvgDocument:
|
|
|
359
409
|
"viewBox": f"0 0 {self._width} {self._height}",
|
|
360
410
|
},
|
|
361
411
|
)
|
|
362
|
-
if self._fondi_font_css is not None:
|
|
412
|
+
if self._fondi_font_css is not None or self._clip_defs:
|
|
363
413
|
defs = ET.SubElement(root, f"{{{SVG_NS}}}defs")
|
|
364
|
-
|
|
365
|
-
|
|
414
|
+
if self._fondi_font_css is not None:
|
|
415
|
+
style = ET.SubElement(defs, f"{{{SVG_NS}}}style")
|
|
416
|
+
style.text = self._fondi_font_css
|
|
417
|
+
for box_ltrb, clip_id in self._clip_defs.items():
|
|
418
|
+
clip_path = ET.SubElement(
|
|
419
|
+
defs,
|
|
420
|
+
f"{{{SVG_NS}}}clipPath",
|
|
421
|
+
{"id": clip_id},
|
|
422
|
+
)
|
|
423
|
+
clip_path.append(self._clip_rect_element(box_ltrb))
|
|
366
424
|
for el in self._elements:
|
|
367
425
|
root.append(el)
|
|
368
426
|
body = ET.tostring(root, encoding="unicode")
|
|
@@ -76,10 +76,12 @@ class Text(Shape):
|
|
|
76
76
|
anchor_x:str="center",
|
|
77
77
|
anchor_y:str="center",
|
|
78
78
|
cacheImage=True,
|
|
79
|
+
clip_box=None,
|
|
79
80
|
*args, **kwargs
|
|
80
81
|
):
|
|
81
82
|
|
|
82
83
|
self.batch = batch
|
|
84
|
+
self.clip_box = list(clip_box) if clip_box is not None else None
|
|
83
85
|
self.color = color
|
|
84
86
|
self.rotate = rotate
|
|
85
87
|
self.fontSize = fontSize
|
|
@@ -164,9 +166,29 @@ class Text(Shape):
|
|
|
164
166
|
self.__center__[1] = self.__leftTop__[1] - self.height/2
|
|
165
167
|
|
|
166
168
|
|
|
169
|
+
def _pil_clip_box(self, surface):
|
|
170
|
+
if self.clip_box is None:
|
|
171
|
+
return None
|
|
172
|
+
left, top, right, bottom = self.clip_box
|
|
173
|
+
return [
|
|
174
|
+
left,
|
|
175
|
+
surface.height - bottom,
|
|
176
|
+
right,
|
|
177
|
+
surface.height - top,
|
|
178
|
+
]
|
|
179
|
+
|
|
167
180
|
def drawPillow(self, surface):
|
|
168
181
|
[y] = flipHorizontal(surface, self.__center__[1] + self.height/2)
|
|
169
|
-
|
|
182
|
+
if self.clip_box is not None:
|
|
183
|
+
blit_image_clipped(
|
|
184
|
+
surface,
|
|
185
|
+
self.img,
|
|
186
|
+
self.__leftTop__[0],
|
|
187
|
+
y,
|
|
188
|
+
self._pil_clip_box(surface),
|
|
189
|
+
)
|
|
190
|
+
else:
|
|
191
|
+
blitImageToSurface(surface, self.img, (self.__leftTop__[0], y))
|
|
170
192
|
|
|
171
193
|
def drawSvg(self, doc):
|
|
172
194
|
kaxe_top = self.__center__[1] + self.height / 2
|
|
@@ -187,6 +209,7 @@ class Text(Shape):
|
|
|
187
209
|
scene_top,
|
|
188
210
|
rotate=self.rotate,
|
|
189
211
|
rotate_center=rotate_center,
|
|
212
|
+
clip_box=self.clip_box,
|
|
190
213
|
)
|
|
191
214
|
return
|
|
192
215
|
|
|
@@ -197,6 +220,7 @@ class Text(Shape):
|
|
|
197
220
|
y_coord="top",
|
|
198
221
|
rotate=self.rotate,
|
|
199
222
|
rotate_center=rotate_center,
|
|
223
|
+
clip_box=self.clip_box,
|
|
200
224
|
)
|
|
201
225
|
|
|
202
226
|
|
|
@@ -208,6 +232,11 @@ class Text(Shape):
|
|
|
208
232
|
self.__center__[1] += int(y)
|
|
209
233
|
self.__leftTop__[0] += int(x)
|
|
210
234
|
self.__leftTop__[1] += int(y)
|
|
235
|
+
if self.clip_box is not None:
|
|
236
|
+
self.clip_box[0] += int(x)
|
|
237
|
+
self.clip_box[1] += int(y)
|
|
238
|
+
self.clip_box[2] += int(x)
|
|
239
|
+
self.clip_box[3] += int(y)
|
|
211
240
|
|
|
212
241
|
|
|
213
242
|
def getIncludeArguments(self):
|
|
@@ -4,7 +4,7 @@ import math
|
|
|
4
4
|
from ...core.styles import *
|
|
5
5
|
from ...core.shapes import shapes
|
|
6
6
|
from ...core.symbol import symbol as symbols
|
|
7
|
-
from ...core.helper import bbox_overlaps, contour_label_angle
|
|
7
|
+
from ...core.helper import bbox_intersects_box, bbox_overlaps, contour_label_angle
|
|
8
8
|
from ...core.text import Text
|
|
9
9
|
from ...core.round import koundTeX
|
|
10
10
|
from ...plot import identities
|
|
@@ -32,6 +32,56 @@ def _polyline_arc_length(polyline):
|
|
|
32
32
|
return total
|
|
33
33
|
|
|
34
34
|
|
|
35
|
+
def _polyline_is_closed(polyline, tolerance=2.0):
|
|
36
|
+
if len(polyline) < 3:
|
|
37
|
+
return False
|
|
38
|
+
dx = polyline[0][0] - polyline[-1][0]
|
|
39
|
+
dy = polyline[0][1] - polyline[-1][1]
|
|
40
|
+
return math.hypot(dx, dy) <= tolerance
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _polyline_total_arc(polyline, closed):
|
|
44
|
+
arc = _polyline_arc_length(polyline)
|
|
45
|
+
if closed:
|
|
46
|
+
dx = polyline[0][0] - polyline[-1][0]
|
|
47
|
+
dy = polyline[0][1] - polyline[-1][1]
|
|
48
|
+
arc += math.hypot(dx, dy)
|
|
49
|
+
return arc
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _point_at_arc_length(polyline, target, closed=False):
|
|
53
|
+
if not polyline:
|
|
54
|
+
return 0, (0, 0)
|
|
55
|
+
|
|
56
|
+
total = _polyline_total_arc(polyline, closed)
|
|
57
|
+
if total <= 0:
|
|
58
|
+
return 0, polyline[0]
|
|
59
|
+
|
|
60
|
+
if closed:
|
|
61
|
+
target = target % total
|
|
62
|
+
elif target >= total:
|
|
63
|
+
return len(polyline) - 1, polyline[-1]
|
|
64
|
+
|
|
65
|
+
walked = 0.0
|
|
66
|
+
segment_count = len(polyline) - 1 + (1 if closed else 0)
|
|
67
|
+
|
|
68
|
+
for seg in range(segment_count):
|
|
69
|
+
i = seg if seg < len(polyline) - 1 else len(polyline) - 1
|
|
70
|
+
j = (seg + 1) if seg < len(polyline) - 1 else 0
|
|
71
|
+
dx = polyline[j][0] - polyline[i][0]
|
|
72
|
+
dy = polyline[j][1] - polyline[i][1]
|
|
73
|
+
seg_len = math.hypot(dx, dy)
|
|
74
|
+
if seg_len == 0:
|
|
75
|
+
continue
|
|
76
|
+
if walked + seg_len >= target:
|
|
77
|
+
t = (target - walked) / seg_len
|
|
78
|
+
point = (polyline[i][0] + t * dx, polyline[i][1] + t * dy)
|
|
79
|
+
return i, point
|
|
80
|
+
walked += seg_len
|
|
81
|
+
|
|
82
|
+
return len(polyline) - 1, polyline[-1]
|
|
83
|
+
|
|
84
|
+
|
|
35
85
|
def _simplify_polyline(polyline):
|
|
36
86
|
if not polyline:
|
|
37
87
|
return []
|
|
@@ -47,44 +97,34 @@ def _simplify_polyline(polyline):
|
|
|
47
97
|
return simplified
|
|
48
98
|
|
|
49
99
|
|
|
50
|
-
|
|
51
|
-
best_index = 0
|
|
52
|
-
best_dist = float('inf')
|
|
53
|
-
for i, (px, py) in enumerate(polyline):
|
|
54
|
-
dist = (px - point[0]) ** 2 + (py - point[1]) ** 2
|
|
55
|
-
if dist < best_dist:
|
|
56
|
-
best_dist = dist
|
|
57
|
-
best_index = i
|
|
58
|
-
return best_index
|
|
100
|
+
_LABEL_PHASE_GOLDEN = 0.618033988749895
|
|
59
101
|
|
|
60
102
|
|
|
61
|
-
def _label_candidates(polyline, spacing, max_candidates=None):
|
|
103
|
+
def _label_candidates(polyline, spacing, max_candidates=None, phase=0.0):
|
|
62
104
|
polyline = _simplify_polyline(polyline)
|
|
63
105
|
if len(polyline) < 2:
|
|
64
106
|
return []
|
|
65
107
|
|
|
66
|
-
|
|
108
|
+
closed = _polyline_is_closed(polyline)
|
|
109
|
+
arc = _polyline_total_arc(polyline, closed)
|
|
67
110
|
if arc < spacing:
|
|
68
111
|
return []
|
|
69
112
|
|
|
113
|
+
num_labels = max(1, int(arc / spacing))
|
|
114
|
+
if max_candidates is not None:
|
|
115
|
+
num_labels = min(num_labels, max_candidates)
|
|
116
|
+
|
|
70
117
|
candidates = []
|
|
71
|
-
for
|
|
72
|
-
|
|
118
|
+
for k in range(num_labels):
|
|
119
|
+
fraction = (k + 0.5 + phase) / num_labels
|
|
120
|
+
if closed:
|
|
121
|
+
fraction = fraction % 1.0
|
|
122
|
+
elif fraction > 1.0:
|
|
123
|
+
continue
|
|
124
|
+
target = fraction * arc
|
|
125
|
+
index, point = _point_at_arc_length(polyline, target, closed)
|
|
73
126
|
candidates.append((point, index, arc))
|
|
74
127
|
|
|
75
|
-
if not candidates and arc >= spacing:
|
|
76
|
-
mid_index = len(polyline) // 2
|
|
77
|
-
candidates.append((polyline[mid_index], mid_index, arc))
|
|
78
|
-
|
|
79
|
-
if max_candidates is not None and len(candidates) > max_candidates:
|
|
80
|
-
if max_candidates <= 1:
|
|
81
|
-
return candidates[:1]
|
|
82
|
-
last = len(candidates) - 1
|
|
83
|
-
candidates = [
|
|
84
|
-
candidates[int(i * last / (max_candidates - 1))]
|
|
85
|
-
for i in range(max_candidates)
|
|
86
|
-
]
|
|
87
|
-
|
|
88
128
|
return candidates
|
|
89
129
|
|
|
90
130
|
|
|
@@ -236,6 +276,10 @@ class Contour:
|
|
|
236
276
|
polyline,
|
|
237
277
|
self.labelSpacing,
|
|
238
278
|
max_candidates=self.labelMaxPerLevel,
|
|
279
|
+
phase=(
|
|
280
|
+
level_index / max(self.steps, 1)
|
|
281
|
+
+ (level_index * _LABEL_PHASE_GOLDEN) % 1.0
|
|
282
|
+
) % 1.0,
|
|
239
283
|
)
|
|
240
284
|
):
|
|
241
285
|
candidates.append({
|
|
@@ -278,8 +322,12 @@ class Contour:
|
|
|
278
322
|
rotate=round(angle),
|
|
279
323
|
anchor_x='center',
|
|
280
324
|
anchor_y='center',
|
|
325
|
+
clip_box=list(parent.windowBox),
|
|
281
326
|
)
|
|
282
327
|
bbox = text.getBoundingBox()
|
|
328
|
+
if not bbox_intersects_box(bbox, parent.windowBox):
|
|
329
|
+
continue
|
|
330
|
+
|
|
283
331
|
label_padding = max(
|
|
284
332
|
collision_padding,
|
|
285
333
|
int(max(bbox[2], bbox[3]) * 0.15),
|
|
@@ -5,7 +5,7 @@ from ...core.color import to_rgba
|
|
|
5
5
|
from ...core.symbol import symbol
|
|
6
6
|
from ...core.helper import isRealNumber
|
|
7
7
|
from ...plot import identities
|
|
8
|
-
from .equation import Equation
|
|
8
|
+
from .equation import Equation, trace_contour_polylines
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def _as_2d_expr(expr):
|
|
@@ -47,6 +47,81 @@ def _eval_diff(parent, left, right, px, py):
|
|
|
47
47
|
return None
|
|
48
48
|
|
|
49
49
|
|
|
50
|
+
def _point_segment_distance_sq(px, py, x1, y1, x2, y2):
|
|
51
|
+
dx = x2 - x1
|
|
52
|
+
dy = y2 - y1
|
|
53
|
+
if dx == 0 and dy == 0:
|
|
54
|
+
dpx = px - x1
|
|
55
|
+
dpy = py - y1
|
|
56
|
+
return dpx * dpx + dpy * dpy
|
|
57
|
+
t = max(0.0, min(1.0, ((px - x1) * dx + (py - y1) * dy) / (dx * dx + dy * dy)))
|
|
58
|
+
cx = x1 + t * dx
|
|
59
|
+
cy = y1 + t * dy
|
|
60
|
+
dpx = px - cx
|
|
61
|
+
dpy = py - cy
|
|
62
|
+
return dpx * dpx + dpy * dpy
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _min_distance_sq_to_segments(px, py, segments):
|
|
66
|
+
if not segments:
|
|
67
|
+
return float('inf')
|
|
68
|
+
return min(
|
|
69
|
+
_point_segment_distance_sq(px, py, x1, y1, x2, y2)
|
|
70
|
+
for x1, y1, x2, y2 in segments
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _boundary_segments(boundary, parent):
|
|
75
|
+
segments = []
|
|
76
|
+
for polyline in trace_contour_polylines(boundary.dotsPosAbstract, parent):
|
|
77
|
+
if len(polyline) < 2:
|
|
78
|
+
continue
|
|
79
|
+
decimated = _decimate_polyline(polyline, min_step=12)
|
|
80
|
+
for i in range(len(decimated) - 1):
|
|
81
|
+
x1, y1 = decimated[i]
|
|
82
|
+
x2, y2 = decimated[i + 1]
|
|
83
|
+
segments.append((x1, y1, x2, y2))
|
|
84
|
+
return segments
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _decimate_polyline(polyline, min_step=12):
|
|
88
|
+
if len(polyline) < 2:
|
|
89
|
+
return polyline
|
|
90
|
+
result = [polyline[0]]
|
|
91
|
+
last = polyline[0]
|
|
92
|
+
min_step_sq = min_step * min_step
|
|
93
|
+
for point in polyline[1:]:
|
|
94
|
+
dx = point[0] - last[0]
|
|
95
|
+
dy = point[1] - last[1]
|
|
96
|
+
if dx * dx + dy * dy >= min_step_sq:
|
|
97
|
+
result.append(point)
|
|
98
|
+
last = point
|
|
99
|
+
if result[-1] != polyline[-1]:
|
|
100
|
+
result.append(polyline[-1])
|
|
101
|
+
return result
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _build_band_cells(segments, band, x0, y0, x1, y1):
|
|
105
|
+
cell = max(1, int(band / 2))
|
|
106
|
+
band_sq = band * band
|
|
107
|
+
cols = int((x1 - x0) / cell) + 1
|
|
108
|
+
rows = int((y1 - y0) / cell) + 1
|
|
109
|
+
near = set()
|
|
110
|
+
for ci in range(cols):
|
|
111
|
+
for ri in range(rows):
|
|
112
|
+
cx = x0 + ci * cell + cell * 0.5
|
|
113
|
+
cy = y0 + ri * cell + cell * 0.5
|
|
114
|
+
if _min_distance_sq_to_segments(cx, cy, segments) <= band_sq:
|
|
115
|
+
near.add((ci, ri))
|
|
116
|
+
return cell, near, x0, y0
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _point_in_band_cells(px, py, cell, near, origin_x, origin_y):
|
|
120
|
+
ci = int((px - origin_x) // cell)
|
|
121
|
+
ri = int((py - origin_y) // cell)
|
|
122
|
+
return (ci, ri) in near
|
|
123
|
+
|
|
124
|
+
|
|
50
125
|
class Inequality:
|
|
51
126
|
"""
|
|
52
127
|
A class to represent a two-variable inequality ``left op right``.
|
|
@@ -77,6 +152,9 @@ class Inequality:
|
|
|
77
152
|
hatch_angle : float, optional
|
|
78
153
|
Hatch line angle in degrees, measured counter-clockwise from the
|
|
79
154
|
horizontal axis (default is 45).
|
|
155
|
+
hatch_band : float, optional
|
|
156
|
+
Maximum pixel distance from the boundary to draw hatching. When
|
|
157
|
+
omitted, the entire forbidden side is hatched.
|
|
80
158
|
computePadding : int, optional
|
|
81
159
|
Extra padding when sampling the plot area (default is 50).
|
|
82
160
|
|
|
@@ -98,6 +176,7 @@ class Inequality:
|
|
|
98
176
|
hatch_spacing=10,
|
|
99
177
|
hatch_width=1,
|
|
100
178
|
hatch_angle=45,
|
|
179
|
+
hatch_band=None,
|
|
101
180
|
computePadding=50,
|
|
102
181
|
):
|
|
103
182
|
self.left = _as_2d_expr(left)
|
|
@@ -106,6 +185,7 @@ class Inequality:
|
|
|
106
185
|
self.hatch_spacing = hatch_spacing
|
|
107
186
|
self.hatch_width = hatch_width
|
|
108
187
|
self.hatch_angle = hatch_angle
|
|
188
|
+
self.hatch_band = hatch_band
|
|
109
189
|
self.hatch_color = to_rgba(hatch_color)
|
|
110
190
|
|
|
111
191
|
if op not in _OPS:
|
|
@@ -128,12 +208,20 @@ class Inequality:
|
|
|
128
208
|
y0 = box[1] - self.computePadding
|
|
129
209
|
y1 = box[3] + self.computePadding
|
|
130
210
|
|
|
131
|
-
width = x1 - x0
|
|
132
|
-
height = y1 - y0
|
|
133
211
|
spacing = self.hatch_spacing
|
|
134
212
|
sample_step = 2
|
|
135
213
|
eps = 1e-9
|
|
136
214
|
|
|
215
|
+
boundary_segments = None
|
|
216
|
+
band_cells = None
|
|
217
|
+
if self.hatch_band is not None:
|
|
218
|
+
boundary_segments = _boundary_segments(self.boundary, parent)
|
|
219
|
+
if not boundary_segments:
|
|
220
|
+
return
|
|
221
|
+
band_cells = _build_band_cells(
|
|
222
|
+
boundary_segments, self.hatch_band, x0, y0, x1, y1
|
|
223
|
+
)
|
|
224
|
+
|
|
137
225
|
scale = getattr(parent, 'getVisualScale', lambda: 1.0)()
|
|
138
226
|
hatch_width = max(1, int(self.hatch_width * scale))
|
|
139
227
|
|
|
@@ -199,6 +287,14 @@ class Inequality:
|
|
|
199
287
|
forbidden = self._is_forbidden(diff)
|
|
200
288
|
|
|
201
289
|
if forbidden:
|
|
290
|
+
if band_cells is not None:
|
|
291
|
+
cell, near, origin_x, origin_y = band_cells
|
|
292
|
+
if not _point_in_band_cells(px, py, cell, near, origin_x, origin_y):
|
|
293
|
+
if segment_start is not None and last_point is not None:
|
|
294
|
+
self.__add_hatch_segment__(segment_start, last_point, hatch_width)
|
|
295
|
+
segment_start = None
|
|
296
|
+
last_point = None
|
|
297
|
+
continue
|
|
202
298
|
point = (px, py)
|
|
203
299
|
if segment_start is None:
|
|
204
300
|
segment_start = point
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kaxe
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.6.0.dev0
|
|
4
4
|
Summary: A small graphing tool for functions, points, equations and more
|
|
5
5
|
Author-email: Valter Yde Daugberg <valteryde@hotmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/valteryde/kaxe
|
|
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
|
|
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
|
|
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
|
{kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.bright-oblique.ttf
RENAMED
|
File without changes
|
{kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.bright-roman.ttf
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.concrete-bold.ttf
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.concrete-roman.ttf
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.serif-bold.ttf
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.serif-italic.ttf
RENAMED
|
File without changes
|
{kaxe-1.5.7.dev0 → kaxe-1.6.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.serif-roman.ttf
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
|