ocp-vscode 2.2.2__tar.gz → 2.3.1__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.
Files changed (23) hide show
  1. {ocp_vscode-2.2.2 → ocp_vscode-2.3.1}/PKG-INFO +6 -1
  2. {ocp_vscode-2.2.2 → ocp_vscode-2.3.1}/README.md +24 -0
  3. {ocp_vscode-2.2.2 → ocp_vscode-2.3.1}/ocp_vscode/__init__.py +23 -1
  4. {ocp_vscode-2.2.2 → ocp_vscode-2.3.1}/ocp_vscode/comms.py +17 -6
  5. {ocp_vscode-2.2.2 → ocp_vscode-2.3.1}/ocp_vscode/config.py +15 -1
  6. {ocp_vscode-2.2.2 → ocp_vscode-2.3.1}/ocp_vscode/show.py +71 -102
  7. {ocp_vscode-2.2.2 → ocp_vscode-2.3.1}/ocp_vscode.egg-info/PKG-INFO +7 -2
  8. {ocp_vscode-2.2.2 → ocp_vscode-2.3.1}/ocp_vscode.egg-info/SOURCES.txt +0 -1
  9. {ocp_vscode-2.2.2 → ocp_vscode-2.3.1}/ocp_vscode.egg-info/requires.txt +1 -1
  10. {ocp_vscode-2.2.2 → ocp_vscode-2.3.1}/setup.cfg +1 -1
  11. {ocp_vscode-2.2.2 → ocp_vscode-2.3.1}/setup.py +2 -2
  12. ocp_vscode-2.2.2/test/test_serialisation.py +0 -566
  13. {ocp_vscode-2.2.2 → ocp_vscode-2.3.1}/LICENSE +0 -0
  14. {ocp_vscode-2.2.2 → ocp_vscode-2.3.1}/ocp_vscode/animation.py +0 -0
  15. {ocp_vscode-2.2.2 → ocp_vscode-2.3.1}/ocp_vscode/backend.py +0 -0
  16. {ocp_vscode-2.2.2 → ocp_vscode-2.3.1}/ocp_vscode/build123d.py +0 -0
  17. {ocp_vscode-2.2.2 → ocp_vscode-2.3.1}/ocp_vscode/colors.py +0 -0
  18. {ocp_vscode-2.2.2 → ocp_vscode-2.3.1}/ocp_vscode/state.py +0 -0
  19. {ocp_vscode-2.2.2 → ocp_vscode-2.3.1}/ocp_vscode.egg-info/dependency_links.txt +0 -0
  20. {ocp_vscode-2.2.2 → ocp_vscode-2.3.1}/ocp_vscode.egg-info/not-zip-safe +0 -0
  21. {ocp_vscode-2.2.2 → ocp_vscode-2.3.1}/ocp_vscode.egg-info/top_level.txt +0 -0
  22. {ocp_vscode-2.2.2 → ocp_vscode-2.3.1}/test/test_for_backend.py +0 -0
  23. {ocp_vscode-2.2.2 → ocp_vscode-2.3.1}/test/testextension.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ocp_vscode
3
- Version: 2.2.2
3
+ Version: 2.3.1
4
4
  Summary: OCP CAD Viewer for VSCode
5
5
  Home-page: https://github.com/bernhard-42/vscode-ocp-cad-viewer
6
6
  Author: Bernhard Walter
@@ -17,5 +17,10 @@ Classifier: Programming Language :: Python :: 3.10
17
17
  Classifier: Programming Language :: Python :: 3.11
18
18
  Requires-Python: >=3.9
19
19
  License-File: LICENSE
20
+ Requires-Dist: ocp-tessellate<2.4.0,>=2.3.2
21
+ Requires-Dist: requests
22
+ Requires-Dist: ipykernel
23
+ Requires-Dist: orjson
24
+ Requires-Dist: websockets<11.1,>=11.0
20
25
 
21
26
  An extension to show OCP cad CAD objects (CadQuery, build123d) in VS Code via threejs
@@ -185,8 +185,32 @@ You can also use "Library Manager" in the _OCP CAD Viewer_ sidebar to manage the
185
185
  - `reset_camera=Camera.KEEP` will keep position, rotation and panning. However, panning can be problematic. When the next object to be shown is much larger or smaller and the object before was panned, it can happen that nothing is visible (the new object at the pan location is outside of the viewer frustum). OCP CAD Viewer checks whether the bounding box of an object is 2x smaller or larger than the one of the last shown object. If so, it falls back to `Camera.CENTER`. A notification is written to the OCP CAD Viewer output panel.
186
186
  - `reset_camera=Camera.RESET` will ensure that position, rotation and panning will be reset to the initial default
187
187
 
188
+ ## Development
189
+
190
+ Testing:
191
+
192
+ Native tessellator can be set via `NATIVE_TESSELLATOR=1`and Python tessellator via `NATIVE_TESSELLATOR=0`.
193
+
194
+ When `OCP_VSCODE_PYTEST=1` is set, `show` will not send the tessellated results to the viewer, but return it to the caller for inspection.
195
+
196
+ A full test cycle consist of:
197
+
198
+ ```bash
199
+ NATIVE_TESSELLATOR=0 OCP_VSCODE_PYTEST=1 pytest -v -s pytests/
200
+ NATIVE_TESSELLATOR=1 OCP_VSCODE_PYTEST=1 pytest -v -s pytests/
201
+ ```
202
+
188
203
  ## Changes
189
204
 
205
+ v2.3.1
206
+ - Add latest ocp-tessellate to fixed regression with handling instances
207
+ - Make native default if ocp-addons exists
208
+
209
+ v2.3.0
210
+ - Add newest ocp-tessellate to allow using native tessellator from ocp_addons
211
+ - Fine tune communication to ensure the memory view of buffers will be passed through to javascript for performance
212
+ - Use of the new protocol v3 of three-cad-viewer
213
+
190
214
  v2.2.2
191
215
  - Fix regression in measure tools
192
216
 
@@ -15,7 +15,9 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
  #
18
- __version__ = "2.2.2"
18
+ __version__ = "2.3.1"
19
+
20
+ import os
19
21
 
20
22
  from .show import *
21
23
  from .config import *
@@ -24,3 +26,23 @@ from .comms import *
24
26
  from .colors import *
25
27
  from .animation import Animation
26
28
  from ocp_tessellate.cad_objects import ImageFace
29
+
30
+ try:
31
+ from ocp_tessellate.tessellator import (
32
+ enable_native_tessellator,
33
+ disable_native_tessellator,
34
+ is_native_tessellator_enabled,
35
+ )
36
+
37
+ if os.environ.get("NATIVE_TESSELLATOR") == "0":
38
+ disable_native_tessellator()
39
+ else:
40
+ enable_native_tessellator()
41
+
42
+ print(
43
+ "Found and enabled native tessellator.\n"
44
+ "To disable, call `disable_native_tessellator()`\n"
45
+ "To enable, call `enable_native_tessellator()`\n"
46
+ )
47
+ except:
48
+ pass
@@ -20,6 +20,7 @@ from ocp_tessellate.ocp_utils import (
20
20
  )
21
21
  from .state import get_state, update_state, get_config_file
22
22
 
23
+
23
24
  # pylint: disable=unused-import
24
25
  try:
25
26
  from IPython import get_ipython
@@ -34,6 +35,7 @@ CMD_PORT = 3939
34
35
 
35
36
  INIT_DONE = False
36
37
 
38
+
37
39
  #
38
40
  # Send data to the viewer
39
41
  #
@@ -58,9 +60,14 @@ __all__ = [
58
60
  "set_port",
59
61
  "get_port",
60
62
  "listener",
63
+ "is_pytest",
61
64
  ]
62
65
 
63
66
 
67
+ def is_pytest():
68
+ return os.environ.get("OCP_VSCODE_PYTEST") == "1"
69
+
70
+
64
71
  def port_check(port):
65
72
  """Check whether the port is listening"""
66
73
  s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@@ -85,6 +92,9 @@ def default(obj):
85
92
 
86
93
  def get_port():
87
94
  """Get the port"""
95
+ if is_pytest():
96
+ return 3939
97
+
88
98
  if not INIT_DONE:
89
99
  find_and_set_port()
90
100
  set_connection_file()
@@ -131,12 +141,13 @@ def _send(data, message_type, port=None, timeit=False):
131
141
  result = json.loads(ws.recv())
132
142
  except Exception as ex: # pylint: disable=broad-except
133
143
  print(ex)
134
- try:
135
- ws.close()
136
- except: # pylint: disable=bare-except
137
- pass
138
144
 
139
- return result
145
+ # try:
146
+ # ws.close()
147
+ # except Exception as ex: # pylint: disable=bare-except
148
+ # pass
149
+
150
+ return result
140
151
 
141
152
  except Exception as ex: # pylint: disable=broad-except
142
153
  print(
@@ -278,4 +289,4 @@ def set_connection_file():
278
289
  elif not JCONSOLE:
279
290
  print("Jupyter console not installed")
280
291
  else:
281
- print("Jupyter kernel not running")
292
+ print("Jupyter kernel not running")
@@ -18,7 +18,7 @@
18
18
 
19
19
  from enum import Enum
20
20
 
21
- from .comms import send_command, send_config, get_port
21
+ from .comms import send_command, send_config, get_port, is_pytest
22
22
 
23
23
  __all__ = [
24
24
  "workspace_config",
@@ -401,6 +401,10 @@ def ui_filter(conf):
401
401
 
402
402
  def status(port=None, debug=False):
403
403
  """Get viewer status"""
404
+
405
+ if is_pytest():
406
+ return {}
407
+
404
408
  if port is None:
405
409
  port = get_port()
406
410
  try:
@@ -418,6 +422,16 @@ def status(port=None, debug=False):
418
422
 
419
423
  def workspace_config(port=None):
420
424
  """Get viewer workspace config"""
425
+
426
+ if is_pytest():
427
+ return {
428
+ "measure_tools": False,
429
+ "_splash": False,
430
+ "default_facecolor": (1, 234, 56),
431
+ "default_thickedgecolor": (123, 45, 6),
432
+ "default_vertexcolor": (123, 45, 6),
433
+ }
434
+
421
435
  if port is None:
422
436
  port = get_port()
423
437
  try:
@@ -16,7 +16,9 @@
16
16
  # limitations under the License.
17
17
  #
18
18
 
19
+ import os
19
20
  import re
21
+ import types
20
22
 
21
23
  from ocp_tessellate import PartGroup
22
24
  from ocp_tessellate.convert import (
@@ -24,7 +26,6 @@ from ocp_tessellate.convert import (
24
26
  get_normal_len,
25
27
  combined_bb,
26
28
  to_assembly,
27
- mp_get_results,
28
29
  conv,
29
30
  )
30
31
  from ocp_tessellate.utils import numpy_to_buffer_json, Timer, Color
@@ -40,7 +41,6 @@ from ocp_tessellate.ocp_utils import (
40
41
  is_wrapped,
41
42
  )
42
43
 
43
- from ocp_tessellate.mp_tessellator import init_pool, keymap, close_pool
44
44
  from ocp_tessellate.cad_objects import (
45
45
  OCP_PartGroup,
46
46
  OCP_Edges,
@@ -50,7 +50,7 @@ from ocp_tessellate.cad_objects import (
50
50
  )
51
51
  import ocp_tessellate.convert as oc
52
52
 
53
- from .config import (
53
+ from ocp_vscode.config import (
54
54
  preset,
55
55
  get_changed_config,
56
56
  workspace_config,
@@ -61,8 +61,8 @@ from .config import (
61
61
  Collapse,
62
62
  check_deprecated,
63
63
  )
64
- from .comms import send_backend, send_data
65
- from .colors import get_colormap, web_to_rgb, BaseColorMap
64
+ from ocp_vscode.comms import send_backend, send_data, is_pytest
65
+ from ocp_vscode.colors import get_colormap, web_to_rgb, BaseColorMap
66
66
 
67
67
  __all__ = ["show", "show_object", "reset_show", "show_all", "show_clear"]
68
68
 
@@ -140,7 +140,7 @@ def _tessellate(
140
140
 
141
141
  with Timer(timeit, "", "to_assembly", 1):
142
142
  changed_config = get_changed_config()
143
- part_group = to_assembly(
143
+ part_group, instances = to_assembly(
144
144
  *cad_objs,
145
145
  names=names,
146
146
  colors=colors,
@@ -199,30 +199,14 @@ def _tessellate(
199
199
  continue
200
200
  params[k] = v
201
201
 
202
- parallel = preset("parallel", params.get("parallel"))
203
- if parallel and not any(
204
- [isinstance(obj, OCP_PartGroup) for obj in part_group.objects]
205
- ):
206
- print("parallel only works for assemblies, setting it to False")
207
- parallel = False
208
- params["parallel"] = False
209
-
210
202
  if kwargs.get("debug") is not None and kwargs["debug"]:
211
203
  print("\ntessellation parameters:\n", params)
212
204
 
213
205
  with Timer(timeit, "", "tessellate", 1):
214
- if parallel:
215
- init_pool()
216
- keymap.reset()
217
-
218
206
  instances, shapes, states, mapping = tessellate_group(
219
- part_group, params, progress, params.get("timeit")
207
+ part_group, instances, params, progress, params.get("timeit")
220
208
  )
221
209
 
222
- if parallel:
223
- instances, shapes = mp_get_results(instances, shapes, progress)
224
- close_pool()
225
-
226
210
  params["normal_len"] = get_normal_len(
227
211
  preset("render_normals", params.get("render_normals")),
228
212
  shapes,
@@ -230,7 +214,13 @@ def _tessellate(
230
214
  )
231
215
 
232
216
  with Timer(timeit, "", "bb", 1):
233
- bb = combined_bb(shapes).to_dict()
217
+ bb = combined_bb(shapes)
218
+ if bb is None:
219
+ bb = dict(
220
+ xmin=-1e-6, ymin=-1e-6, zmin=-1e-6, xmax=1e-6, ymax=1e-6, zmax=1e-6
221
+ )
222
+ else:
223
+ bb = bb.to_dict()
234
224
 
235
225
  # add global bounding box
236
226
  shapes["bb"] = bb
@@ -272,14 +262,18 @@ def _convert(
272
262
  config["explode"] = kwargs["explode"]
273
263
 
274
264
  with Timer(timeit, "", "create data obj", 1):
265
+ if is_pytest():
266
+ return (instances, shapes, states, config, count_shapes), mapping
267
+
275
268
  return {
276
269
  "data": numpy_to_buffer_json(
277
- dict(instances=instances, shapes=shapes, states=states)
270
+ dict(instances=instances, shapes=shapes, states=states),
278
271
  ),
279
272
  "type": "data",
280
273
  "config": config,
281
274
  "count": count_shapes,
282
275
  }, mapping
276
+ return result
283
277
 
284
278
 
285
279
  class Progress:
@@ -287,7 +281,7 @@ class Progress:
287
281
 
288
282
  def __init__(self, levels=None):
289
283
  if levels is None:
290
- self.levels = ["+", "c", "-"]
284
+ self.levels = ["+c-*"]
291
285
  else:
292
286
  self.levels = levels
293
287
 
@@ -318,7 +312,7 @@ def show(
318
312
  colors=None,
319
313
  alphas=None,
320
314
  port=None,
321
- progress="-+c",
315
+ progress="-+*c",
322
316
  glass=None,
323
317
  tools=None,
324
318
  measure_tools=None,
@@ -371,7 +365,6 @@ def show(
371
365
  render_joints=None,
372
366
  show_parent=None,
373
367
  show_sketch_local=None,
374
- parallel=None,
375
368
  helper_scale=None,
376
369
  mate_scale=None, # DEPRECATED
377
370
  debug=None,
@@ -388,8 +381,11 @@ def show(
388
381
  colors: List of colors for the cad_objs. Needs to have the same length as cad_objs
389
382
  alphas: List of alpha values for the cad_objs. Needs to have the same length as cad_objs
390
383
  port: The port the viewer listens to. Typically use 'set_port(port)' instead
391
- progress: Show progress of tessellation with None is no progress indicator. (default="-+c")
392
- for object: "-": is reference, "+": gets tessellated, "c": from cache
384
+ progress: Show progress of tessellation with None is no progress indicator. (default="-+*c")
385
+ for object: "-": is reference,
386
+ "+": gets tessellated with Python code,
387
+ "*": gets tessellated with native code,
388
+ "c": from cache
393
389
 
394
390
  Valid keywords to configure the viewer (**kwargs):
395
391
  - UI
@@ -459,7 +455,6 @@ def show(
459
455
  render_normals: Render normals (default=False)
460
456
  render_mates: Render mates for MAssemblies (default=False)
461
457
  render_joints: Render build123d joints (default=False)
462
- parallel: Tessellate objects in parallel (default=False)
463
458
  show_parent: Render parent of faces, edges or vertices as wireframe (default=False)
464
459
  show_sketch_local: In build123d show local sketch in addition to relocate sketch (default=True)
465
460
  helper_scale: Scale of rendered helpers (locations, axis, mates for MAssemblies) (default=1)
@@ -552,6 +547,9 @@ def show(
552
547
  else:
553
548
  LAST_CALL = "other"
554
549
 
550
+ if is_pytest():
551
+ return t, mapping
552
+
555
553
  with Timer(timeit, "", "send"):
556
554
  send_data(t, port=port, timeit=timeit)
557
555
 
@@ -574,7 +572,7 @@ def show_object(
574
572
  parent=None,
575
573
  clear=False,
576
574
  port=None,
577
- progress="-+c",
575
+ progress="-+*c",
578
576
  glass=None,
579
577
  tools=None,
580
578
  measure_tools=None,
@@ -624,7 +622,6 @@ def show_object(
624
622
  render_normals=None,
625
623
  render_mates=None,
626
624
  render_joints=None,
627
- parallel=None,
628
625
  show_parent=None,
629
626
  show_sketch_local=None,
630
627
  helper_scale=None,
@@ -646,8 +643,12 @@ def show_object(
646
643
  clear: In interactice mode, clear the stack of objects to be shown
647
644
  (typically used for the first object)
648
645
  port: The port the viewer listens to. Typically use 'set_port(port)' instead
649
- progress: Show progress of tessellation with None is no progress indicator. (default="-+c")
650
- for object: "-": is reference, "+": gets tessellated, "c": from cache
646
+ progress: Show progress of tessellation with None is no progress indicator. (default="-+*c")
647
+ for object: "-": is reference,
648
+ "+": gets tessellated with Python code,
649
+ "*": gets tessellated with native code,
650
+ "c": from cache
651
+
651
652
 
652
653
  Valid keywords to configure the viewer (**kwargs):
653
654
  - UI
@@ -717,7 +718,6 @@ def show_object(
717
718
  render_normals: Render normals (default=False)
718
719
  render_mates: Render mates for MAssemblies (default=False)
719
720
  render_joints: Render build123d joints (default=False)
720
- parallel: Tessellate objects in parallel (default=False)
721
721
  show_parent: Render parent of faces, edges or vertices as wireframe (default=False)
722
722
  show_sketch_local: In build123d show local sketch in addition to relocate sketch (default=True)
723
723
  helper_scale: Scale of rendered helpers (locations, axis, mates for MAssemblies) (default=1)
@@ -778,44 +778,13 @@ def show_clear():
778
778
  send_data(data)
779
779
 
780
780
 
781
- def ocp_group(obj, name):
782
-
783
- def to_group(obj, name, group):
784
- if isinstance(obj, list):
785
- sub_group = OCP_PartGroup([], name=name)
786
- for i, el in enumerate(obj):
787
- new_obj = to_group(el, f"{name}[{i}]", sub_group)
788
- if new_obj is not None:
789
- sub_group.add(new_obj)
790
- group.add(sub_group)
791
- elif isinstance(obj, dict):
792
- sub_group = OCP_PartGroup([], name=name)
793
- for name, el in obj.items():
794
- new_obj = to_group(el, name, sub_group)
795
- if new_obj is not None:
796
- sub_group.add(new_obj)
797
- group.add(sub_group)
798
- else:
799
- if (
800
- (is_wrapped(obj) and not obj.__class__.__name__ == "Color")
801
- or is_build123d(obj)
802
- or is_cadquery(obj)
803
- ):
804
- new_obj = conv(obj)
805
- new_obj.name = name
806
- group.add(new_obj)
807
- else:
808
- ...
809
- # print(
810
- # f"show_all: Type {type(obj)} for name {name} cannot be visualized"
811
- # )
812
-
813
- group = OCP_PartGroup([], name=name)
814
- to_group(obj, name, group)
815
- return group.objects[0]
816
-
817
-
818
- def show_all(variables=None, exclude=None, classes=None, _visual_debug=False, **kwargs):
781
+ def show_all(
782
+ variables=None,
783
+ exclude=None,
784
+ classes=None,
785
+ _visual_debug=False,
786
+ **kwargs,
787
+ ):
819
788
  """Show all variables in the current scope"""
820
789
  import inspect # pylint: disable=import-outside-toplevel
821
790
 
@@ -840,22 +809,23 @@ def show_all(variables=None, exclude=None, classes=None, _visual_debug=False, **
840
809
  names = []
841
810
  for name, obj in variables.items():
842
811
  if (
812
+ # ignore classes and ipython and jupyter variables
843
813
  isinstance(obj, type)
844
- or name in ["_", "__", "___"]
814
+ or name in exclude + ["_", "__", "___", "_ih", "_oh", "_dh", "Out", "In"]
845
815
  or name.startswith("__")
846
816
  or re.search("_\\d+", name) is not None
817
+ # pylint: disable=protected-access
818
+ or (hasattr(obj, "_obj") and obj._obj is None)
819
+ or callable(obj)
820
+ or isinstance(obj, (int, float, str, bool, types.ModuleType))
847
821
  ):
848
- continue # ignore classes and jupyter variables
822
+ continue
823
+
849
824
  if hasattr(obj, "area") and obj.area > 1e99: # inifinite face
850
825
  print(f"infinite face {name} skipped")
851
826
  continue
852
827
 
853
- if name not in exclude and (classes is None or isinstance(obj, tuple(classes))):
854
- if (
855
- hasattr(obj, "_obj")
856
- and obj._obj is None # pylint: disable=protected-access
857
- ):
858
- continue
828
+ if classes is None or isinstance(obj, tuple(classes)):
859
829
 
860
830
  if hasattr(obj, "locations") and hasattr(obj, "local_locations"):
861
831
  obj = obj.locations
@@ -881,6 +851,7 @@ def show_all(variables=None, exclude=None, classes=None, _visual_debug=False, **
881
851
  and hasattr(obj, "position")
882
852
  and hasattr(obj, "direction")
883
853
  )
854
+ or isinstance(obj, (list, tuple, dict))
884
855
  ):
885
856
  objects.append(obj)
886
857
  names.append(name)
@@ -898,27 +869,25 @@ def show_all(variables=None, exclude=None, classes=None, _visual_debug=False, **
898
869
  objects.append(pg)
899
870
  names.append(name)
900
871
 
901
- elif isinstance(obj, (list, tuple, dict)):
902
- if not name in [
903
- "_ih",
904
- "_oh",
905
- "_dh",
906
- "Out",
907
- "In",
908
- ]: # no IPython dicts and lists
909
- obj = ocp_group(obj, name)
910
- if len(obj.objects) > 0:
911
- objects.append(obj)
912
- obj.name = name
913
- names.append(name)
872
+ else:
873
+ print(
874
+ f"show_all: Type {type(obj)} for name {name} cannot be visualized"
875
+ )
914
876
 
915
877
  if len(objects) > 0:
916
- show(
917
- *objects,
918
- names=names,
919
- collapse=Collapse.ROOT,
920
- _force_in_debug=_visual_debug,
921
- **kwargs,
922
- )
878
+ try:
879
+ result = show(
880
+ *objects,
881
+ names=names,
882
+ collapse=Collapse.ROOT,
883
+ _force_in_debug=_visual_debug,
884
+ **kwargs,
885
+ )
886
+ if is_pytest():
887
+ return result
888
+ except Exception as ex: # pylint: disable=broad-exception-caught
889
+ print("show_all:", ex)
923
890
  else:
891
+ if is_pytest():
892
+ return None
924
893
  show_clear()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
- Name: ocp-vscode
3
- Version: 2.2.2
2
+ Name: ocp_vscode
3
+ Version: 2.3.1
4
4
  Summary: OCP CAD Viewer for VSCode
5
5
  Home-page: https://github.com/bernhard-42/vscode-ocp-cad-viewer
6
6
  Author: Bernhard Walter
@@ -17,5 +17,10 @@ Classifier: Programming Language :: Python :: 3.10
17
17
  Classifier: Programming Language :: Python :: 3.11
18
18
  Requires-Python: >=3.9
19
19
  License-File: LICENSE
20
+ Requires-Dist: ocp-tessellate<2.4.0,>=2.3.2
21
+ Requires-Dist: requests
22
+ Requires-Dist: ipykernel
23
+ Requires-Dist: orjson
24
+ Requires-Dist: websockets<11.1,>=11.0
20
25
 
21
26
  An extension to show OCP cad CAD objects (CadQuery, build123d) in VS Code via threejs
@@ -18,5 +18,4 @@ ocp_vscode.egg-info/not-zip-safe
18
18
  ocp_vscode.egg-info/requires.txt
19
19
  ocp_vscode.egg-info/top_level.txt
20
20
  test/test_for_backend.py
21
- test/test_serialisation.py
22
21
  test/testextension.py
@@ -1,4 +1,4 @@
1
- ocp-tessellate<2.3.0,>=2.2.2
1
+ ocp-tessellate<2.4.0,>=2.3.2
2
2
  requests
3
3
  ipykernel
4
4
  orjson
@@ -1,5 +1,5 @@
1
1
  [bumpversion]
2
- current_version = 2.2.2
2
+ current_version = 2.3.1
3
3
  commit = False
4
4
  tag = False
5
5
  parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(?P<release>\D*)(?P<build>\d*)
@@ -2,13 +2,13 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup_args = {
4
4
  "name": "ocp_vscode",
5
- "version": "2.2.2",
5
+ "version": "2.3.1",
6
6
  "description": "OCP CAD Viewer for VSCode",
7
7
  "long_description": "An extension to show OCP cad CAD objects (CadQuery, build123d) in VS Code via threejs",
8
8
  "include_package_data": True,
9
9
  "python_requires": ">=3.9",
10
10
  "install_requires": [
11
- "ocp-tessellate>=2.2.2,<2.3.0",
11
+ "ocp-tessellate>=2.3.2,<2.4.0",
12
12
  "requests",
13
13
  "ipykernel",
14
14
  "orjson",
@@ -1,566 +0,0 @@
1
- # pylint: disable=missing-class-docstring,missing-function-docstring
2
-
3
- import unittest
4
- import pytest
5
- import json
6
- import math
7
- from OCP.BRepPrimAPI import BRepPrimAPI_MakeBox
8
- from OCP.BRepFilletAPI import BRepFilletAPI_MakeFillet
9
- from OCP.gp import gp_Pnt, gp_Vec, gp_Dir
10
- from ocp_vscode.show import _convert
11
- from ocp_vscode.backend import ViewerBackend
12
- from ocp_vscode.comms import default
13
- from ocp_vscode.build123d import *
14
- from ocp_tessellate.ocp_utils import get_edges, get_faces, get_vertices
15
-
16
-
17
- class DirectApiTestCase(unittest.TestCase):
18
- def assertTupleAlmostEquals(self, first, second, places, msg=None):
19
- """Check Tuples"""
20
- self.assertEqual(len(second), len(first))
21
- for i, j in zip(second, first):
22
- self.assertAlmostEqual(i, j, places, msg=msg)
23
-
24
- def assertTupleOfTupleAlmostEquals(self, first, second, places, msg=None):
25
- """Check Tuples"""
26
- self.assertEqual(len(second), len(first))
27
- for i, j in zip(second, first):
28
- self.assertTupleAlmostEquals(i, j, places, msg=msg)
29
-
30
- def assertVectorAlmostEquals(self, first, second, places, msg=None):
31
- second_vector = Vector(second)
32
- self.assertAlmostEqual(first.X, second_vector.X, places, msg=msg)
33
- self.assertAlmostEqual(first.Y, second_vector.Y, places, msg=msg)
34
- self.assertAlmostEqual(first.Z, second_vector.Z, places, msg=msg)
35
-
36
-
37
- class VectorTests(DirectApiTestCase):
38
- def test_tuple(self):
39
- vec = Vector(1, 2, 3)
40
- vec2 = Vector((1, 2, 3))
41
- self.assertTupleAlmostEquals(vec.to_tuple(), (1, 2, 3), 6)
42
- self.assertTupleAlmostEquals(vec2.to_tuple(), (1, 2, 3), 6)
43
-
44
- def test_gp_pnt(self):
45
- vec = Vector(gp_Pnt(1, 2, 3))
46
- self.assertTupleAlmostEquals(vec.to_tuple(), (1, 2, 3), 6)
47
-
48
- def test_gp_vec(self):
49
- vec = Vector(gp_Vec(1, 2, 3))
50
- self.assertTupleAlmostEquals(vec.to_tuple(), (1, 2, 3), 6)
51
-
52
- def test_gp_dir(self):
53
- vec = Vector(gp_Dir(1, 2, 3))
54
- norm = math.sqrt(1**2 + 2**2 + 3**2)
55
- self.assertTupleAlmostEquals(vec.to_tuple(), (1 / norm, 2 / norm, 3 / norm), 6)
56
-
57
- def test_normalized(self):
58
- vec = Vector(gp_Vec(1, 2, 3)).normalized()
59
- vec2 = Vector(gp_Dir(1, 2, 3))
60
- self.assertTupleAlmostEquals(vec.to_tuple(), vec2.to_tuple(), 6)
61
-
62
- def test_angle(self):
63
- vec = Vector(1, 0, 0)
64
- self.assertAlmostEqual(vec.get_angle(Vector(0, 1, 0)), 90, 6)
65
- self.assertAlmostEqual(vec.get_angle(Vector(1, 1, 0)), 45, 6)
66
- self.assertAlmostEqual(vec.get_angle(Vector(1, -1, 0)), 45, 6)
67
-
68
-
69
- class AxisTests(DirectApiTestCase):
70
- def test_axis(self):
71
- a = Axis()
72
- self.assertTupleAlmostEquals(a.position.to_tuple(), (0, 0, 0), 6)
73
- self.assertTupleAlmostEquals(a.direction.to_tuple(), (0, 0, 1), 6)
74
- b = Axis((1, 2, 3), (4, 5, 6))
75
- self.assertTupleAlmostEquals(b.position.to_tuple(), (1, 2, 3), 6)
76
- self.assertTupleAlmostEquals(b.direction.to_tuple(), (4, 5, 6), 6)
77
-
78
- def test_axis_x(self):
79
- a = Axis.X
80
- self.assertTupleAlmostEquals(a.position.to_tuple(), (0, 0, 0), 6)
81
- self.assertTupleAlmostEquals(a.direction.to_tuple(), (1, 0, 0), 6)
82
-
83
- def test_axis_y(self):
84
- a = Axis.Y
85
- self.assertTupleAlmostEquals(a.position.to_tuple(), (0, 0, 0), 6)
86
- self.assertTupleAlmostEquals(a.direction.to_tuple(), (0, 1, 0), 6)
87
-
88
- def test_axis_z(self):
89
- a = Axis.Z
90
- self.assertTupleAlmostEquals(a.position.to_tuple(), (0, 0, 0), 6)
91
- self.assertTupleAlmostEquals(a.direction.to_tuple(), (0, 0, 1), 6)
92
-
93
-
94
- class PlaneTests(DirectApiTestCase):
95
- def test_face(self):
96
- box = BRepPrimAPI_MakeBox(1.0, 2.0, 3.0).Solid()
97
- fillet = BRepFilletAPI_MakeFillet(box)
98
- for edge in get_edges(box):
99
- fillet.Add(0.2, edge)
100
- fillet.Build()
101
- box = Solid(fillet.Shape())
102
-
103
- faces = box.faces()
104
- p = Plane(faces[0])
105
-
106
- self.assertTupleAlmostEquals(p.origin.to_tuple(), (0.0, 1.0, 1.5), 6)
107
- self.assertTupleAlmostEquals(p.x_dir.to_tuple(), (0.0, 0.0, 1.0), 6)
108
- self.assertTupleAlmostEquals(p.z_dir.to_tuple(), (-1.0, 0.0, 0.0), 6)
109
-
110
- p = Plane(faces[23])
111
-
112
- self.assertTupleAlmostEquals(p.origin.to_tuple(), (1.0, 1.0, 1.5), 6)
113
- self.assertTupleAlmostEquals(p.x_dir.to_tuple(), (0.0, 0.0, 1.0), 6)
114
- self.assertTupleAlmostEquals(p.z_dir.to_tuple(), (1.0, 0.0, 0.0), 6)
115
-
116
- p = Plane(faces[10])
117
-
118
- self.assertTupleAlmostEquals(p.origin.to_tuple(), (0.5, 1.0, 3), 6)
119
- self.assertTupleAlmostEquals(p.x_dir.to_tuple(), (1.0, 0.0, 0), 6)
120
- self.assertTupleAlmostEquals(p.z_dir.to_tuple(), (0.0, 0.0, 1.0), 6)
121
-
122
- def test_edge(self):
123
- p = Plane(Vector(1, 1, 1), z_dir=(0, 1, 0))
124
-
125
- self.assertTupleAlmostEquals(p.origin.to_tuple(), (1, 1, 1), 6)
126
- self.assertTupleAlmostEquals(p.x_dir.to_tuple(), (0, 0, 1), 6)
127
- self.assertTupleAlmostEquals(p.z_dir.to_tuple(), (0, 1, 0), 6)
128
-
129
-
130
- class ShapeListTests(DirectApiTestCase):
131
- def test_lists(self):
132
- box = BRepPrimAPI_MakeBox(1.0, 2.0, 3.0).Solid()
133
- fillet = BRepFilletAPI_MakeFillet(box)
134
- for edge in get_edges(box):
135
- fillet.Add(0.2, edge)
136
- fillet.Build()
137
- box = Solid(fillet.Shape())
138
-
139
- faces = box.faces()
140
- edges = box.edges()
141
- vertices = box.vertices()
142
-
143
- self.assertEqual(len(faces), 26)
144
- self.assertEqual(len(edges), 48)
145
- self.assertEqual(len(vertices), 24)
146
-
147
- self.assertEqual(len(box.edges().filter_by("LINE")), 24)
148
- self.assertEqual(len(box.edges().filter_by("CIRCLE")), 24)
149
- self.assertEqual(len(box.edges().filter_by("OTHER")), 0)
150
-
151
- self.assertEqual(len(box.faces().filter_by("PLANE")), 6)
152
- self.assertEqual(len(box.faces().filter_by("CYLINDER")), 12)
153
- self.assertEqual(len(box.faces().filter_by("SPHERE")), 8)
154
- self.assertEqual(len(box.faces().filter_by("OTHER")), 0)
155
-
156
-
157
- class ObjectTests(DirectApiTestCase):
158
- def test_load(self):
159
- box = BRepPrimAPI_MakeBox(1.0, 2.0, 3.0).Solid()
160
- _, mapping = _convert(box)
161
- data = {"model": mapping}
162
- j = json.dumps(data, default=default).encode("utf-8")
163
-
164
- backend = ViewerBackend(9999)
165
- backend.load_model(json.loads(j)["model"])
166
-
167
- self.assertEqual(
168
- list(backend.model.keys()),
169
- [
170
- "/Group/Solid",
171
- "/Group/Solid/faces/faces_0",
172
- "/Group/Solid/faces/faces_1",
173
- "/Group/Solid/faces/faces_2",
174
- "/Group/Solid/faces/faces_3",
175
- "/Group/Solid/faces/faces_4",
176
- "/Group/Solid/faces/faces_5",
177
- "/Group/Solid/edges/edges_0",
178
- "/Group/Solid/edges/edges_1",
179
- "/Group/Solid/edges/edges_2",
180
- "/Group/Solid/edges/edges_3",
181
- "/Group/Solid/edges/edges_4",
182
- "/Group/Solid/edges/edges_5",
183
- "/Group/Solid/edges/edges_6",
184
- "/Group/Solid/edges/edges_7",
185
- "/Group/Solid/edges/edges_8",
186
- "/Group/Solid/edges/edges_9",
187
- "/Group/Solid/edges/edges_10",
188
- "/Group/Solid/edges/edges_11",
189
- "/Group/Solid/vertices/vertices0",
190
- "/Group/Solid/vertices/vertices1",
191
- "/Group/Solid/vertices/vertices2",
192
- "/Group/Solid/vertices/vertices3",
193
- "/Group/Solid/vertices/vertices4",
194
- "/Group/Solid/vertices/vertices5",
195
- "/Group/Solid/vertices/vertices6",
196
- "/Group/Solid/vertices/vertices7",
197
- ],
198
- )
199
- self.assertEqual(
200
- [isinstance(v, Face) for k, v in backend.model.items()],
201
- [
202
- False,
203
- True,
204
- True,
205
- True,
206
- True,
207
- True,
208
- True,
209
- False,
210
- False,
211
- False,
212
- False,
213
- False,
214
- False,
215
- False,
216
- False,
217
- False,
218
- False,
219
- False,
220
- False,
221
- False,
222
- False,
223
- False,
224
- False,
225
- False,
226
- False,
227
- False,
228
- False,
229
- ],
230
- )
231
- self.assertEqual(
232
- [isinstance(v, Edge) for k, v in backend.model.items()],
233
- [
234
- False,
235
- False,
236
- False,
237
- False,
238
- False,
239
- False,
240
- False,
241
- True,
242
- True,
243
- True,
244
- True,
245
- True,
246
- True,
247
- True,
248
- True,
249
- True,
250
- True,
251
- True,
252
- True,
253
- False,
254
- False,
255
- False,
256
- False,
257
- False,
258
- False,
259
- False,
260
- False,
261
- ],
262
- )
263
- self.assertEqual(
264
- [isinstance(v, Vertex) for k, v in backend.model.items()],
265
- [
266
- False,
267
- False,
268
- False,
269
- False,
270
- False,
271
- False,
272
- False,
273
- False,
274
- False,
275
- False,
276
- False,
277
- False,
278
- False,
279
- False,
280
- False,
281
- False,
282
- False,
283
- False,
284
- False,
285
- True,
286
- True,
287
- True,
288
- True,
289
- True,
290
- True,
291
- True,
292
- True,
293
- ],
294
- )
295
- self.assertEqual(
296
- [isinstance(v, Compound) for k, v in backend.model.items()],
297
- [
298
- True,
299
- False,
300
- False,
301
- False,
302
- False,
303
- False,
304
- False,
305
- False,
306
- False,
307
- False,
308
- False,
309
- False,
310
- False,
311
- False,
312
- False,
313
- False,
314
- False,
315
- False,
316
- False,
317
- False,
318
- False,
319
- False,
320
- False,
321
- False,
322
- False,
323
- False,
324
- False,
325
- ],
326
- )
327
- self.assertEqual(
328
- [v.area for k, v in backend.model.items() if isinstance(v, Face)],
329
- [6.0, 6.0, 3.0, 3.0, 2.0, 2.0],
330
- )
331
- self.assertEqual(
332
- [v.length for k, v in backend.model.items() if isinstance(v, Edge)],
333
- [3.0, 2.0, 3.0, 2.0, 3.0, 2.0, 3.0, 2.0, 1.0, 1.0, 1.0, 1.0],
334
- )
335
- self.assertEqual(backend.model["/Group/Solid"].volume, 6)
336
-
337
- def test_fillet(self):
338
- box = BRepPrimAPI_MakeBox(1.0, 2.0, 3.0).Solid()
339
- fillet = BRepFilletAPI_MakeFillet(box)
340
- for edge in get_edges(box):
341
- fillet.Add(0.2, edge)
342
- fillet.Build()
343
- box = Solid(fillet.Shape())
344
- _, mapping = _convert(box)
345
- data = {"model": mapping}
346
- j = json.dumps(data, default=default).encode("utf-8")
347
-
348
- backend = ViewerBackend(9999)
349
- backend.load_model(json.loads(j)["model"])
350
-
351
- self.assertEqual(
352
- [v.geom_type() for k, v in backend.model.items()],
353
- [
354
- "Solid",
355
- "PLANE",
356
- "CYLINDER",
357
- "CYLINDER",
358
- "CYLINDER",
359
- "CYLINDER",
360
- "SPHERE",
361
- "SPHERE",
362
- "PLANE",
363
- "PLANE",
364
- "SPHERE",
365
- "PLANE",
366
- "SPHERE",
367
- "PLANE",
368
- "CYLINDER",
369
- "CYLINDER",
370
- "CYLINDER",
371
- "CYLINDER",
372
- "CYLINDER",
373
- "CYLINDER",
374
- "CYLINDER",
375
- "CYLINDER",
376
- "SPHERE",
377
- "SPHERE",
378
- "PLANE",
379
- "SPHERE",
380
- "SPHERE",
381
- "LINE",
382
- "LINE",
383
- "LINE",
384
- "LINE",
385
- "CIRCLE",
386
- "CIRCLE",
387
- "LINE",
388
- "CIRCLE",
389
- "LINE",
390
- "CIRCLE",
391
- "CIRCLE",
392
- "LINE",
393
- "CIRCLE",
394
- "CIRCLE",
395
- "CIRCLE",
396
- "LINE",
397
- "OTHER",
398
- "CIRCLE",
399
- "OTHER",
400
- "CIRCLE",
401
- "LINE",
402
- "LINE",
403
- "LINE",
404
- "LINE",
405
- "LINE",
406
- "LINE",
407
- "OTHER",
408
- "CIRCLE",
409
- "LINE",
410
- "LINE",
411
- "LINE",
412
- "OTHER",
413
- "CIRCLE",
414
- "LINE",
415
- "LINE",
416
- "LINE",
417
- "CIRCLE",
418
- "CIRCLE",
419
- "LINE",
420
- "CIRCLE",
421
- "CIRCLE",
422
- "CIRCLE",
423
- "CIRCLE",
424
- "LINE",
425
- "CIRCLE",
426
- "CIRCLE",
427
- "CIRCLE",
428
- "LINE",
429
- "CIRCLE",
430
- "LINE",
431
- "CIRCLE",
432
- "CIRCLE",
433
- "OTHER",
434
- "OTHER",
435
- "OTHER",
436
- "OTHER",
437
- "Vertex",
438
- "Vertex",
439
- "Vertex",
440
- "Vertex",
441
- "Vertex",
442
- "Vertex",
443
- "Vertex",
444
- "Vertex",
445
- "Vertex",
446
- "Vertex",
447
- "Vertex",
448
- "Vertex",
449
- "Vertex",
450
- "Vertex",
451
- "Vertex",
452
- "Vertex",
453
- "Vertex",
454
- "Vertex",
455
- "Vertex",
456
- "Vertex",
457
- "Vertex",
458
- "Vertex",
459
- "Vertex",
460
- "Vertex",
461
- ],
462
- )
463
- vec = [v.to_tuple() for v in backend.model.values() if isinstance(v, Vertex)]
464
- self.assertTupleOfTupleAlmostEquals(
465
- vec,
466
- [
467
- (-2.7755575615628914e-17, 0.19999999999999998, 0.19999999999999998),
468
- (-2.7755575615628914e-17, 0.19999999999999998, 2.8),
469
- (-2.7755575615628914e-17, 1.8, 0.19999999999999998),
470
- (-2.7755575615628914e-17, 1.8, 2.8),
471
- (0.19999999999999998, -2.7755575615628914e-17, 0.19999999999999998),
472
- (0.19999999999999998, -2.7755575615628914e-17, 2.8),
473
- (0.19999999999999998, 0.19999999999999998, 0.0),
474
- (0.19999999999999998, 1.8, 0.0),
475
- (0.19999999999999998, 0.19999999999999998, 3.0),
476
- (0.19999999999999998, 1.8, 3.0),
477
- (0.19999999999999998, 2.0, 0.19999999999999998),
478
- (0.19999999999999998, 2.0, 2.8),
479
- (0.8, -2.7755575615628914e-17, 0.19999999999999998),
480
- (0.8, -2.7755575615628914e-17, 2.8),
481
- (0.8, 0.19999999999999998, 0.0),
482
- (0.8, 1.8, 0.0),
483
- (0.8, 0.19999999999999998, 3.0),
484
- (0.8, 1.8, 3.0),
485
- (0.8, 2.0, 0.19999999999999998),
486
- (0.8, 2.0, 2.8),
487
- (1.0, 0.19999999999999998, 0.19999999999999998),
488
- (1.0, 0.19999999999999998, 2.8),
489
- (1.0, 1.8, 0.19999999999999998),
490
- (1.0, 1.8, 2.8),
491
- ],
492
- 6,
493
- )
494
-
495
- vec = [
496
- (v.radius if v.geom_type() in ["CIRCLE"] else -1, v.length)
497
- for v in backend.model.values()
498
- if isinstance(v, Edge)
499
- ]
500
- self.assertTupleOfTupleAlmostEquals(
501
- vec,
502
- [
503
- (-1, 2.5999999999999996),
504
- (-1, 1.6),
505
- (-1, 1.6),
506
- (-1, 2.5999999999999996),
507
- (0.2, 0.3141592653589793),
508
- (0.2, 0.3141592653589793),
509
- (-1, 2.5999999999999996),
510
- (0.2, 0.3141592653589793),
511
- (-1, 1.6),
512
- (0.2, 0.3141592653589793),
513
- (0.2, 0.3141592653589793),
514
- (-1, 1.6),
515
- (0.2, 0.3141592653589793),
516
- (0.2, 0.3141592653589793),
517
- (0.2, 0.3141592653589793),
518
- (-1, 2.5999999999999996),
519
- (-1, 1.92367069372179e-17),
520
- (0.2, 0.3141592653589793),
521
- (-1, 1.92367069372179e-17),
522
- (0.2, 0.3141592653589793),
523
- (-1, 0.6000000000000001),
524
- (-1, 0.6000000000000001),
525
- (-1, 2.5999999999999996),
526
- (-1, 0.6000000000000001),
527
- (-1, 0.6000000000000001),
528
- (-1, 1.6),
529
- (-1, 1.92367069372179e-17),
530
- (0.2, 0.3141592653589793),
531
- (-1, 0.6000000000000001),
532
- (-1, 0.6000000000000001),
533
- (-1, 1.6),
534
- (-1, 1.92367069372179e-17),
535
- (0.2, 0.3141592653589793),
536
- (-1, 0.6000000000000001),
537
- (-1, 0.6000000000000001),
538
- (-1, 2.5999999999999996),
539
- (0.2, 0.3141592653589793),
540
- (0.2, 0.3141592653589793),
541
- (-1, 2.5999999999999996),
542
- (0.2, 0.3141592653589793),
543
- (0.2, 0.3141592653589793),
544
- (0.2, 0.3141592653589793),
545
- (0.2, 0.3141592653589793),
546
- (-1, 1.6),
547
- (0.2, 0.3141592653589793),
548
- (0.2, 0.3141592653589793),
549
- (0.2, 0.3141592653589793),
550
- (-1, 1.6),
551
- (0.2, 0.3141592653589793),
552
- (-1, 2.5999999999999996),
553
- (0.2, 0.3141592653589793),
554
- (0.2, 0.3141592653589793),
555
- (-1, 1.92367069372179e-17),
556
- (-1, 1.92367069372179e-17),
557
- (-1, 1.92367069372179e-17),
558
- (-1, 1.92367069372179e-17),
559
- ],
560
- 6,
561
- )
562
- # vec = [
563
- # (, v.length, v.width, v.area)
564
- # for v in backend.model.values()
565
- # if isinstance(v, Face)
566
- # ]
File without changes