icplot 0.2.4__py3-none-any.whl → 0.3.1__py3-none-any.whl
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.
- icplot/{gantt → charts}/gantt.py +2 -3
- icplot/{tree.py → charts/tree.py} +2 -3
- icplot/converter/__init__.py +3 -0
- icplot/converter/cli.py +27 -0
- icplot/converter/convert.py +32 -0
- icplot/{image_utils.py → converter/image.py} +26 -10
- icplot/geometry/base.py +6 -0
- icplot/{mesh → geometry/mesh}/edge.py +1 -1
- icplot/{mesh → geometry/mesh}/mesh.py +30 -4
- icplot/{mesh → geometry/mesh}/openfoam/blockmesh.py +2 -3
- icplot/{mesh → geometry/mesh}/openfoam/polymesh.py +4 -6
- icplot/{mesh → geometry/mesh}/shapes.py +87 -7
- icplot/{mesh → geometry/mesh}/vertex.py +16 -1
- icplot/geometry/shapes.py +29 -0
- icplot/geometry/transform.py +2 -2
- icplot/graph/__init__.py +3 -4
- icplot/graph/plot.py +2 -53
- icplot/graph/plot_group.py +1 -1
- icplot/graph/series.py +3 -4
- icplot/main_cli.py +13 -62
- icplot/renderer/__init__.py +5 -0
- icplot/renderer/charts/pgfgantt.py +71 -0
- icplot/{gantt/gantt_renderer.py → renderer/charts/svggantt.py} +8 -6
- icplot/renderer/cli.py +58 -0
- icplot/renderer/config.py +41 -0
- icplot/renderer/formats/__init__.py +1 -0
- icplot/renderer/formats/mermaid.py +47 -0
- icplot/renderer/formats/plantuml.py +37 -0
- icplot/renderer/formats/tex.py +120 -0
- icplot/renderer/graph/__init__.py +3 -0
- icplot/renderer/graph/color.py +17 -0
- icplot/{graph → renderer/graph}/matplotlib.py +15 -7
- icplot/{graph → renderer/graph}/mpl.py +8 -8
- icplot/{graph/generator.py → renderer/graph/renderer.py} +43 -8
- icplot/{graph → renderer/graph}/vtk.py +2 -3
- icplot/renderer/render.py +149 -0
- icplot/{cairo_interface.py → renderer/scene/cairo.py} +5 -5
- icplot/{graph → renderer}/video.py +2 -3
- icplot/scene.py +1 -1
- icplot/theme/__init__.py +0 -0
- icplot/theme/cli.py +50 -0
- icplot/theme/color.py +97 -0
- icplot/theme/templates/puml.j2 +91 -0
- icplot/theme/templates/tikz.j2 +100 -0
- icplot/theme/theme.json +81 -0
- icplot/theme/theme.py +117 -0
- icplot/theme/theme_generator.py +119 -0
- {icplot-0.2.4.dist-info → icplot-0.3.1.dist-info}/METADATA +66 -18
- icplot-0.3.1.dist-info/RECORD +65 -0
- {icplot-0.2.4.dist-info → icplot-0.3.1.dist-info}/WHEEL +1 -1
- icplot/color.py +0 -50
- icplot/convert.py +0 -51
- icplot/gantt/__init__.py +0 -1
- icplot/gantt/pgfgantt.py +0 -15
- icplot/mermaid.py +0 -39
- icplot/tex.py +0 -78
- icplot/trace/__init__.py +0 -1
- icplot-0.2.4.dist-info/RECORD +0 -50
- icplot/{trace/trace.py → charts/__init__.py} +0 -0
- icplot/{mesh → geometry/mesh}/__init__.py +1 -1
- icplot/{mesh → geometry/mesh}/cell.py +0 -0
- icplot/{mesh → geometry/mesh}/openfoam/__init__.py +1 -1
- icplot/{mesh → geometry/mesh}/openfoam/foamfile.py +0 -0
- icplot/{mesh → geometry/mesh}/operations.py +1 -1
- icplot/{mesh → geometry/mesh}/vtk.py +2 -2
- {icplot-0.2.4.dist-info → icplot-0.3.1.dist-info}/entry_points.txt +0 -0
- {icplot-0.2.4.dist-info → icplot-0.3.1.dist-info}/licenses/LICENSE +0 -0
- {icplot-0.2.4.dist-info → icplot-0.3.1.dist-info}/top_level.txt +0 -0
icplot/{gantt → charts}/gantt.py
RENAMED
|
@@ -4,11 +4,10 @@ This module represents a gantt chard
|
|
|
4
4
|
|
|
5
5
|
from datetime import datetime
|
|
6
6
|
|
|
7
|
-
from pydantic import BaseModel
|
|
8
|
-
|
|
9
7
|
from iccore.project import Milestone
|
|
8
|
+
from pydantic import BaseModel
|
|
10
9
|
|
|
11
|
-
from icplot.color import Color
|
|
10
|
+
from icplot.theme.color import Color
|
|
12
11
|
|
|
13
12
|
|
|
14
13
|
class GanttChart(BaseModel, frozen=True):
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
import os
|
|
2
3
|
import shutil
|
|
3
|
-
import logging
|
|
4
4
|
from dataclasses import dataclass
|
|
5
|
-
from typing import Callable
|
|
6
5
|
from pathlib import Path
|
|
6
|
+
from typing import Callable
|
|
7
7
|
|
|
8
8
|
import graphviz
|
|
9
9
|
|
|
10
|
-
|
|
11
10
|
logger = logging.getLogger(__name__)
|
|
12
11
|
|
|
13
12
|
|
icplot/converter/cli.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from .convert import convert
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def convert_cli(args):
|
|
7
|
+
|
|
8
|
+
source = args.source.resolve()
|
|
9
|
+
target = Path(args.target).resolve() if args.target else None
|
|
10
|
+
convert(source, target)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def register_parser(subparsers):
|
|
14
|
+
|
|
15
|
+
convert_parser = subparsers.add_parser("convert")
|
|
16
|
+
convert_parser.add_argument(
|
|
17
|
+
"source",
|
|
18
|
+
type=Path,
|
|
19
|
+
help="Path to file to be converted from",
|
|
20
|
+
)
|
|
21
|
+
convert_parser.add_argument(
|
|
22
|
+
"--target",
|
|
23
|
+
type=str,
|
|
24
|
+
default="",
|
|
25
|
+
help="Path to file to be converted to",
|
|
26
|
+
)
|
|
27
|
+
convert_parser.set_defaults(func=convert_cli)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module supporting conversion between image formats
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from .image import pdf_to_png, svg_to_pdf, svg_to_png
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def convert(source: Path, target: Path | None = None):
|
|
14
|
+
"""
|
|
15
|
+
Convert between image formats using the source and target
|
|
16
|
+
file extensions as format hints.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
logger.info("Converting %s", source)
|
|
20
|
+
|
|
21
|
+
if source.suffix == ".pdf":
|
|
22
|
+
pdf_to_png(source, target)
|
|
23
|
+
elif source.suffix == ".svg":
|
|
24
|
+
if target:
|
|
25
|
+
if target.suffix == ".png":
|
|
26
|
+
svg_to_png(source, target)
|
|
27
|
+
elif target.suffix == ".pdf":
|
|
28
|
+
svg_to_pdf(source, target)
|
|
29
|
+
else:
|
|
30
|
+
svg_to_png(source)
|
|
31
|
+
|
|
32
|
+
logger.info("Finished conversion")
|
|
@@ -5,34 +5,36 @@ formats
|
|
|
5
5
|
|
|
6
6
|
import logging
|
|
7
7
|
import os
|
|
8
|
+
import shutil
|
|
9
|
+
import subprocess
|
|
8
10
|
from pathlib import Path
|
|
9
11
|
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
10
14
|
_HAS_WAND = True
|
|
11
15
|
try:
|
|
12
|
-
from wand.image import Image
|
|
13
16
|
from wand.color import Color
|
|
17
|
+
from wand.image import Image
|
|
14
18
|
except ImportError as e:
|
|
15
|
-
|
|
16
|
-
"Disabling Wand stupport. Failed to load with: %s", e
|
|
17
|
-
)
|
|
19
|
+
logger.debug("wand not available: %s", e)
|
|
18
20
|
_HAS_WAND = False
|
|
19
21
|
|
|
20
22
|
_HAS_CAIRO_SVG = True
|
|
21
23
|
try:
|
|
22
24
|
import cairosvg
|
|
23
25
|
except ImportError as e:
|
|
24
|
-
|
|
25
|
-
"Disabling CairoSVG stupport. Failed to load with: %s", e
|
|
26
|
-
)
|
|
26
|
+
logger.debug("cairosvg not available: %s", e)
|
|
27
27
|
_HAS_CAIRO_SVG = False
|
|
28
28
|
|
|
29
|
-
logger = logging.getLogger(__name__)
|
|
30
|
-
|
|
31
29
|
|
|
32
30
|
def has_wand() -> bool:
|
|
33
31
|
return _HAS_WAND
|
|
34
32
|
|
|
35
33
|
|
|
34
|
+
def has_magick() -> bool:
|
|
35
|
+
return bool(shutil.which("magick"))
|
|
36
|
+
|
|
37
|
+
|
|
36
38
|
def has_cairo_svg() -> bool:
|
|
37
39
|
return _HAS_CAIRO_SVG
|
|
38
40
|
|
|
@@ -43,13 +45,27 @@ def _get_out_filename(source: Path, target: Path | None, extension: str) -> Path
|
|
|
43
45
|
return source.parent / f"{source.stem}.{extension}"
|
|
44
46
|
|
|
45
47
|
|
|
48
|
+
def _pdf_to_png(source: Path, target: Path | None = None, resolution: int = 300):
|
|
49
|
+
|
|
50
|
+
outfile = _get_out_filename(source, target, "png")
|
|
51
|
+
os.makedirs(outfile.parent, exist_ok=True)
|
|
52
|
+
cmd = (
|
|
53
|
+
f"magick -density {resolution} -background white -alpha off {source} {outfile}"
|
|
54
|
+
)
|
|
55
|
+
subprocess.run(cmd, shell=True, check=True)
|
|
56
|
+
|
|
57
|
+
|
|
46
58
|
def pdf_to_png(source: Path, target: Path | None = None, resolution: int = 300):
|
|
47
59
|
"""
|
|
48
60
|
Convert a pdf to png with white background
|
|
49
61
|
"""
|
|
50
62
|
|
|
51
63
|
if not has_wand():
|
|
52
|
-
|
|
64
|
+
if has_magick():
|
|
65
|
+
_pdf_to_png(source, target, resolution)
|
|
66
|
+
return
|
|
67
|
+
else:
|
|
68
|
+
raise RuntimeError("Loading Wand failed - no pdf to png support")
|
|
53
69
|
|
|
54
70
|
outfile = _get_out_filename(source, target, "png")
|
|
55
71
|
os.makedirs(outfile.parent, exist_ok=True)
|
icplot/geometry/base.py
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
+
|
|
2
3
|
from dataclasses import dataclass
|
|
3
4
|
|
|
4
5
|
import numpy as np
|
|
5
6
|
|
|
7
|
+
from .operations import get_point_distance
|
|
8
|
+
|
|
6
9
|
|
|
7
10
|
@dataclass(frozen=True)
|
|
8
11
|
class Vector:
|
|
@@ -47,6 +50,9 @@ class Point:
|
|
|
47
50
|
def subtract(self, v: Vector) -> Vector:
|
|
48
51
|
return Vector(self.x - v.x, self.y - v.y, self.z - v.z)
|
|
49
52
|
|
|
53
|
+
def get_distance(self, p: Point) -> float:
|
|
54
|
+
return get_point_distance(p.as_array(), self.as_array())
|
|
55
|
+
|
|
50
56
|
|
|
51
57
|
@dataclass(frozen=True)
|
|
52
58
|
class Bounds:
|
|
@@ -4,13 +4,14 @@ over performance. Consider something else for high performance meshing.
|
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
6
|
from __future__ import annotations
|
|
7
|
+
|
|
7
8
|
from dataclasses import dataclass
|
|
8
9
|
|
|
9
|
-
from icplot.geometry import Point,
|
|
10
|
+
from icplot.geometry import Bounds, Point, Shape, Transform, Vector
|
|
10
11
|
|
|
11
|
-
from .vertex import Vertex, find_closest_vertex
|
|
12
12
|
from .cell import Cell, flip_normals
|
|
13
13
|
from .edge import Edge, contains_point, get_distance
|
|
14
|
+
from .vertex import Vertex, find_closest_vertex
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
@dataclass(frozen=True)
|
|
@@ -49,7 +50,7 @@ class Mesh:
|
|
|
49
50
|
ymin = min(ymin, v.y)
|
|
50
51
|
ymax = max(ymax, v.y)
|
|
51
52
|
zmin = min(zmin, v.z)
|
|
52
|
-
zmax =
|
|
53
|
+
zmax = max(zmax, v.z)
|
|
53
54
|
return Bounds(xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax, zmin=zmin, zmax=zmax)
|
|
54
55
|
|
|
55
56
|
def flip_normals(self) -> Mesh:
|
|
@@ -67,8 +68,28 @@ class Mesh:
|
|
|
67
68
|
vertices=tuple(v.translate(delta) for v in self.vertices), cells=self.cells
|
|
68
69
|
)
|
|
69
70
|
|
|
70
|
-
def
|
|
71
|
+
def scale_by(self, factor: float) -> Mesh:
|
|
72
|
+
return Mesh(
|
|
73
|
+
vertices=tuple(v.scale(factor) for v in self.vertices), cells=self.cells
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
def rotate_to(self, vec: Vector) -> Mesh:
|
|
77
|
+
return Mesh(
|
|
78
|
+
vertices=tuple(v.rotate_to(vec) for v in self.vertices), cells=self.cells
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
def move_by(
|
|
82
|
+
self, x: float, y: float, z: float, selection: list[int] | None = None
|
|
83
|
+
) -> Mesh:
|
|
71
84
|
delta = Vector(x, y, z)
|
|
85
|
+
if selection:
|
|
86
|
+
return Mesh(
|
|
87
|
+
vertices=tuple(
|
|
88
|
+
v.translate(delta) if v.id in selection else v.copy()
|
|
89
|
+
for v in self.vertices
|
|
90
|
+
),
|
|
91
|
+
cells=self.cells,
|
|
92
|
+
)
|
|
72
93
|
return Mesh(
|
|
73
94
|
vertices=tuple(v.translate(delta) for v in self.vertices), cells=self.cells
|
|
74
95
|
)
|
|
@@ -105,3 +126,8 @@ class Mesh:
|
|
|
105
126
|
vertices=tuple(Vertex(v.x, v.y, v.z, v.id) for v in self.vertices),
|
|
106
127
|
cells=tuple(Cell(c.vertices, c.type) for c in self.cells),
|
|
107
128
|
)
|
|
129
|
+
|
|
130
|
+
def select_region(self, region: Shape) -> list[int]:
|
|
131
|
+
return [
|
|
132
|
+
v.id for v in self.vertices if region.contains_point(Point(v.x, v.y, v.z))
|
|
133
|
+
]
|
|
@@ -2,14 +2,13 @@
|
|
|
2
2
|
Meshing utilities for use in openfoam
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
import os
|
|
5
6
|
import shutil
|
|
6
7
|
import subprocess
|
|
7
|
-
import os
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
from typing import cast
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
from icplot.mesh import Edge, HexCell, Mesh, Patch
|
|
11
|
+
from icplot.geometry.mesh import Edge, HexCell, Mesh, Patch
|
|
13
12
|
|
|
14
13
|
from .foamfile import FoamFile, write_header
|
|
15
14
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
|
-
from pathlib import Path
|
|
3
2
|
from functools import cmp_to_key
|
|
3
|
+
from pathlib import Path
|
|
4
4
|
|
|
5
5
|
from icplot.geometry import Point
|
|
6
|
-
from icplot.mesh import
|
|
6
|
+
from icplot.geometry.mesh import Mesh, Vertex, get_hex_faces
|
|
7
7
|
|
|
8
|
-
from .foamfile import
|
|
8
|
+
from .foamfile import FoamFile, read_foamfile, write_header
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
@dataclass(frozen=True)
|
|
@@ -65,10 +65,8 @@ class PolymeshPatch:
|
|
|
65
65
|
|
|
66
66
|
def read_polymesh(path: Path) -> Polymesh:
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
_ = read_foamfile(path / "points")
|
|
69
69
|
# faces_file = read_foamfile(path / "faces")
|
|
70
|
-
print(points_file)
|
|
71
|
-
# print(faces_file)
|
|
72
70
|
return Polymesh((), (), ())
|
|
73
71
|
|
|
74
72
|
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import numpy as np
|
|
2
2
|
|
|
3
3
|
from icplot.geometry import (
|
|
4
|
-
Point,
|
|
5
|
-
Quad,
|
|
6
4
|
Annulus,
|
|
7
|
-
Transform,
|
|
8
5
|
Circle,
|
|
9
6
|
Cuboid,
|
|
10
|
-
Vector,
|
|
11
7
|
Cylinder,
|
|
8
|
+
Point,
|
|
9
|
+
Quad,
|
|
10
|
+
Shape,
|
|
11
|
+
Transform,
|
|
12
|
+
Vector,
|
|
12
13
|
)
|
|
13
14
|
|
|
15
|
+
from .cell import Cell, HexCell
|
|
14
16
|
from .mesh import Mesh
|
|
17
|
+
from .operations import close_mesh, map_radial, merge_meshes, mesh_extrude
|
|
15
18
|
from .vertex import Vertex, find_closest
|
|
16
|
-
from .cell import Cell, HexCell
|
|
17
|
-
|
|
18
|
-
from .operations import map_radial, close_mesh, merge_meshes, mesh_extrude
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
def mesh_rectangle(rect: Quad, num_width: int = 10, num_height: int = 10) -> Mesh:
|
|
@@ -187,6 +187,73 @@ def mesh_cylinder_basic(
|
|
|
187
187
|
)
|
|
188
188
|
|
|
189
189
|
|
|
190
|
+
"""
|
|
191
|
+
def _mesh_cylinder_block(radius,
|
|
192
|
+
top_loc,
|
|
193
|
+
bottom_loc,
|
|
194
|
+
boundary_fraction,
|
|
195
|
+
num_radial,
|
|
196
|
+
num_circumferential,
|
|
197
|
+
cell_height,
|
|
198
|
+
top_hole: Hole | None = None,
|
|
199
|
+
bottom_hole: Hole | None = None) -> Mesh:
|
|
200
|
+
length = height - hole_loc.z
|
|
201
|
+
num_cells_in_block = int(num_height*length/height) + 1
|
|
202
|
+
block = mesh_cylinder_basic(Cylinder(diameter=radius*2, length=length),
|
|
203
|
+
boundary_fraction,
|
|
204
|
+
num_radial,
|
|
205
|
+
num_circumferential,
|
|
206
|
+
num_cells_in_block)
|
|
207
|
+
block = block.move_by(0.0, 0.0, hole_loc.z)
|
|
208
|
+
selection = block.select_region(holes[0])
|
|
209
|
+
block = block.move_by(0.0, 0.0, (length/num_cells_in_block)/8.0, selection)
|
|
210
|
+
"""
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def _mesh_compound_cylinder_with_holes(
|
|
214
|
+
inlet_radius,
|
|
215
|
+
inlet_height,
|
|
216
|
+
radius,
|
|
217
|
+
height,
|
|
218
|
+
boundary_fraction,
|
|
219
|
+
num_circumferential,
|
|
220
|
+
num_radial,
|
|
221
|
+
num_height,
|
|
222
|
+
holes: list[Shape],
|
|
223
|
+
) -> Mesh:
|
|
224
|
+
|
|
225
|
+
# Mesh the core cylinder in blocks at the hole locations
|
|
226
|
+
hole_loc = holes[0].transform.location
|
|
227
|
+
|
|
228
|
+
length = height - hole_loc.z
|
|
229
|
+
num_cells_in_block = int(num_height * length / height) + 1
|
|
230
|
+
block = mesh_cylinder_basic(
|
|
231
|
+
Cylinder(diameter=radius * 2, length=length),
|
|
232
|
+
boundary_fraction,
|
|
233
|
+
num_radial,
|
|
234
|
+
num_circumferential,
|
|
235
|
+
num_cells_in_block,
|
|
236
|
+
)
|
|
237
|
+
block = block.move_by(0.0, 0.0, hole_loc.z)
|
|
238
|
+
selection = block.select_region(holes[0])
|
|
239
|
+
block = block.move_by(0.0, 0.0, (length / num_cells_in_block) / 8.0, selection)
|
|
240
|
+
|
|
241
|
+
length = hole_loc.z
|
|
242
|
+
num_cells_in_block = int(num_height * length / height) + 1
|
|
243
|
+
block = mesh_cylinder_basic(
|
|
244
|
+
Cylinder(diameter=radius * 2, length=length),
|
|
245
|
+
boundary_fraction,
|
|
246
|
+
num_radial,
|
|
247
|
+
num_circumferential,
|
|
248
|
+
num_cells_in_block,
|
|
249
|
+
)
|
|
250
|
+
block = block.move_by(0.0, 0.0, 0.0)
|
|
251
|
+
selection = block.select_region(holes[0])
|
|
252
|
+
block = block.move_by(0.0, 0.0, -(length / num_cells_in_block) / 8.0, selection)
|
|
253
|
+
|
|
254
|
+
return merge_meshes(block, block)
|
|
255
|
+
|
|
256
|
+
|
|
190
257
|
def mesh_compound_cylinder(
|
|
191
258
|
inlet_radius,
|
|
192
259
|
inlet_height,
|
|
@@ -196,8 +263,21 @@ def mesh_compound_cylinder(
|
|
|
196
263
|
num_circumferential,
|
|
197
264
|
num_radial,
|
|
198
265
|
num_height,
|
|
266
|
+
holes: list[Shape] | None = None,
|
|
199
267
|
) -> Mesh:
|
|
200
268
|
|
|
269
|
+
if holes:
|
|
270
|
+
return _mesh_compound_cylinder_with_holes(
|
|
271
|
+
inlet_radius,
|
|
272
|
+
inlet_height,
|
|
273
|
+
radius,
|
|
274
|
+
height,
|
|
275
|
+
boundary_fraction,
|
|
276
|
+
num_circumferential,
|
|
277
|
+
num_radial,
|
|
278
|
+
num_height,
|
|
279
|
+
holes,
|
|
280
|
+
)
|
|
201
281
|
inner = mesh_cylinder_basic(
|
|
202
282
|
Cylinder(diameter=inlet_radius * 2, length=2 * inlet_height + height),
|
|
203
283
|
boundary_fraction,
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
+
|
|
2
3
|
from dataclasses import dataclass
|
|
3
4
|
|
|
4
5
|
import numpy as np
|
|
5
6
|
|
|
6
|
-
from icplot.geometry import Point, Vector, get_point_distance
|
|
7
|
+
from icplot.geometry import Point, Vector, get_point_distance, get_rotation_matrix
|
|
8
|
+
|
|
9
|
+
_GLOBAL_Z = np.array([0.0, 0.0, 1.0])
|
|
7
10
|
|
|
8
11
|
|
|
9
12
|
@dataclass(frozen=True)
|
|
@@ -21,6 +24,9 @@ class Vertex:
|
|
|
21
24
|
def from_point(p: Point, id: int = -1) -> Vertex:
|
|
22
25
|
return Vertex(p.x, p.y, p.z, id)
|
|
23
26
|
|
|
27
|
+
def copy(self) -> Vertex:
|
|
28
|
+
return Vertex(self.x, self.y, self.z, self.id)
|
|
29
|
+
|
|
24
30
|
def as_array(self) -> np.ndarray:
|
|
25
31
|
return np.array([self.x, self.y, self.z])
|
|
26
32
|
|
|
@@ -33,6 +39,15 @@ class Vertex:
|
|
|
33
39
|
def translate(self, v: Vector) -> Vertex:
|
|
34
40
|
return Vertex(self.x + v.x, self.y + v.y, self.z + v.z, self.id)
|
|
35
41
|
|
|
42
|
+
def scale(self, factor: float) -> Vertex:
|
|
43
|
+
return Vertex(self.x * factor, self.y * factor, self.z * factor, self.id)
|
|
44
|
+
|
|
45
|
+
def rotate_to(self, v: Vector) -> Vertex:
|
|
46
|
+
loc = np.array([self.x, self.y, self.z])
|
|
47
|
+
rot = get_rotation_matrix(_GLOBAL_Z, v.as_array())
|
|
48
|
+
loc_rot = rot.dot(loc)
|
|
49
|
+
return Vertex(loc_rot[0], loc_rot[1], loc_rot[2], self.id)
|
|
50
|
+
|
|
36
51
|
|
|
37
52
|
def find_closest(verts: list[Vertex], point: Point) -> int:
|
|
38
53
|
|
icplot/geometry/shapes.py
CHANGED
|
@@ -5,6 +5,7 @@ dependent work.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
from __future__ import annotations
|
|
8
|
+
|
|
8
9
|
from dataclasses import dataclass
|
|
9
10
|
|
|
10
11
|
from .base import Point, Vector
|
|
@@ -19,6 +20,9 @@ class Shape:
|
|
|
19
20
|
|
|
20
21
|
transform: Transform = Transform()
|
|
21
22
|
|
|
23
|
+
def contains_point(self, p: Point) -> bool:
|
|
24
|
+
raise NotImplementedError()
|
|
25
|
+
|
|
22
26
|
|
|
23
27
|
@dataclass(frozen=True)
|
|
24
28
|
class Circle(Shape):
|
|
@@ -75,6 +79,21 @@ class Cuboid(Shape):
|
|
|
75
79
|
def translate(self, v: Vector) -> Cuboid:
|
|
76
80
|
return Cuboid(self.transform.translate(v), self.width, self.height, self.depth)
|
|
77
81
|
|
|
82
|
+
def contains_point(self, p: Point) -> bool:
|
|
83
|
+
in_x = (
|
|
84
|
+
p.x >= self.transform.location.x
|
|
85
|
+
and p.x <= self.transform.location.x + self.width
|
|
86
|
+
)
|
|
87
|
+
in_y = (
|
|
88
|
+
p.y >= self.transform.location.y
|
|
89
|
+
and p.y <= self.transform.location.y + self.height
|
|
90
|
+
)
|
|
91
|
+
in_z = (
|
|
92
|
+
p.z >= self.transform.location.z
|
|
93
|
+
and p.z <= self.transform.location.z + self.depth
|
|
94
|
+
)
|
|
95
|
+
return in_x and in_y and in_z
|
|
96
|
+
|
|
78
97
|
@property
|
|
79
98
|
def points(self) -> list[Point]:
|
|
80
99
|
|
|
@@ -110,6 +129,16 @@ class Cylinder(Shape):
|
|
|
110
129
|
def end(self) -> Point:
|
|
111
130
|
return self.transform.get_point_at_normal_offset(self.length)
|
|
112
131
|
|
|
132
|
+
def contains_point(self, p: Point) -> bool:
|
|
133
|
+
in_radius = p.get_distance(self.transform.location) <= self.diameter / 2.0
|
|
134
|
+
if not in_radius:
|
|
135
|
+
return False
|
|
136
|
+
in_height = (
|
|
137
|
+
p.z >= self.transform.location.z
|
|
138
|
+
and p.z <= self.transform.location.z + self.length
|
|
139
|
+
)
|
|
140
|
+
return in_height
|
|
141
|
+
|
|
113
142
|
|
|
114
143
|
@dataclass(frozen=True)
|
|
115
144
|
class Revolution(Shape):
|
icplot/geometry/transform.py
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
+
|
|
2
3
|
from dataclasses import dataclass
|
|
3
4
|
|
|
4
5
|
import numpy as np
|
|
5
6
|
|
|
6
7
|
from .base import Point, Vector
|
|
7
|
-
from .operations import
|
|
8
|
-
|
|
8
|
+
from .operations import get_rotation_matrix, get_three_point_normal
|
|
9
9
|
|
|
10
10
|
_GLOBAL_Z = np.array([0.0, 0.0, 1.0])
|
|
11
11
|
|
icplot/graph/__init__.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
from .plot import * # NOQA
|
|
2
|
-
from .series import * # NOQA
|
|
3
1
|
from .axis import * # NOQA
|
|
4
|
-
from .
|
|
2
|
+
from .plot import * # NOQA
|
|
5
3
|
from .plot_group import PlotGroupCreate, PlotGroupPublic
|
|
4
|
+
from .series import * # NOQA
|
|
6
5
|
|
|
7
|
-
__all__ = ["
|
|
6
|
+
__all__ = ["PlotGroupCreate", "PlotGroupPublic"]
|
icplot/graph/plot.py
CHANGED
|
@@ -3,20 +3,11 @@ This module has content for generating plots
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import random
|
|
6
|
-
from pathlib import Path
|
|
7
|
-
import os
|
|
8
6
|
|
|
9
7
|
from pydantic import BaseModel
|
|
10
8
|
|
|
11
|
-
from iccore.data import Series
|
|
12
|
-
from iccore.data.series import convert_units
|
|
13
|
-
|
|
14
|
-
from icplot.color import ColorMap, Color
|
|
15
|
-
from icplot.graph import mpl, vtk
|
|
16
|
-
|
|
17
9
|
from .axis import PlotAxis
|
|
18
|
-
from .series import LinePlotSeries, ScatterPlotSeries
|
|
19
|
-
from .plot_group import PlotGroupPublic, PlotSeriesPublic
|
|
10
|
+
from .series import ImageSeries, LinePlotSeries, ScatterPlotSeries
|
|
20
11
|
|
|
21
12
|
|
|
22
13
|
class Plot(BaseModel, frozen=True):
|
|
@@ -52,7 +43,7 @@ class GridPlot(Plot, frozen=True):
|
|
|
52
43
|
data: list = []
|
|
53
44
|
|
|
54
45
|
def get_series_indices(self, num_samples: int = 0):
|
|
55
|
-
rows = num_samples // self.stride
|
|
46
|
+
rows = max(1, num_samples // self.stride)
|
|
56
47
|
cols = num_samples // rows
|
|
57
48
|
len_data = len(self.data)
|
|
58
49
|
|
|
@@ -78,45 +69,3 @@ class GridPlot(Plot, frozen=True):
|
|
|
78
69
|
subplots.append(self.data[index])
|
|
79
70
|
count += 1
|
|
80
71
|
return rows, cols, subplots
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
def get_series_colors(cmap: ColorMap, plot: Plot) -> list[Color]:
|
|
84
|
-
|
|
85
|
-
count = 0
|
|
86
|
-
num_colorable = len([s for s in plot.series if not s.highlight])
|
|
87
|
-
colors = []
|
|
88
|
-
for s in plot.series:
|
|
89
|
-
if not s.highlight:
|
|
90
|
-
color = cmap.get_color(count, num_colorable)
|
|
91
|
-
count = count + 1
|
|
92
|
-
else:
|
|
93
|
-
color = s.color
|
|
94
|
-
colors.append(color)
|
|
95
|
-
return colors
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
def plot_series(
|
|
99
|
-
path: Path,
|
|
100
|
-
group: PlotGroupPublic,
|
|
101
|
-
series: PlotSeriesPublic,
|
|
102
|
-
data_series: Series,
|
|
103
|
-
):
|
|
104
|
-
|
|
105
|
-
output_path = path / series.measurement.product_name
|
|
106
|
-
|
|
107
|
-
os.makedirs(output_path, exist_ok=True)
|
|
108
|
-
|
|
109
|
-
# Convert units
|
|
110
|
-
if series.measurement.unit != series.unit:
|
|
111
|
-
converted_data_series = convert_units(
|
|
112
|
-
data_series,
|
|
113
|
-
((series.measurement.name, series.measurement.unit, series.unit),),
|
|
114
|
-
)
|
|
115
|
-
else:
|
|
116
|
-
converted_data_series = data_series
|
|
117
|
-
|
|
118
|
-
if "mpl" in group.formats:
|
|
119
|
-
mpl.plot(output_path, group, series, converted_data_series)
|
|
120
|
-
|
|
121
|
-
if "vtk" in group.formats and data_series.y:
|
|
122
|
-
vtk.save(output_path, group, series, converted_data_series)
|
icplot/graph/plot_group.py
CHANGED
icplot/graph/series.py
CHANGED
|
@@ -4,16 +4,15 @@ A data series in a plot
|
|
|
4
4
|
|
|
5
5
|
import typing
|
|
6
6
|
|
|
7
|
-
from pydantic import BaseModel
|
|
8
|
-
|
|
9
7
|
from iccore.data import (
|
|
10
|
-
ProductPublicWithMeasurements,
|
|
11
8
|
MeasurementPublicWithUnits,
|
|
9
|
+
ProductPublicWithMeasurements,
|
|
12
10
|
Unit,
|
|
13
11
|
UnitPublic,
|
|
14
12
|
)
|
|
13
|
+
from pydantic import BaseModel
|
|
15
14
|
|
|
16
|
-
from icplot.color import Color
|
|
15
|
+
from icplot.theme.color import Color
|
|
17
16
|
|
|
18
17
|
|
|
19
18
|
class PlotSeriesBase(BaseModel, frozen=True):
|