Implement importBrep and vtkPolyData export (#735)
* Implement importBrep * Implement rw to/from stream * Implement toVtkPolyData * Implemented VTP export * Added normals calculation * use VTK for rendering in jupyter * Added orientation marker * Assy rendering in notebooks * Implement export to vtkjs * Store the env in the cqgi result * VTK-based cq directive * Support show_object and assy * assy vrml export via vtk * Use vtk in the docs * Add slot dxf file * Add vtk.js to the static files * Use single renderer * Ignore cq_directive code coverage * Ignore missing docutils stubs * Implement select * Disable interaction dynamically * Mention VTP in the docs * Add path to the test reqs
This commit is contained in:
		@ -3,8 +3,13 @@ import os
 | 
			
		||||
from itertools import product
 | 
			
		||||
 | 
			
		||||
import cadquery as cq
 | 
			
		||||
from cadquery.occ_impl.exporters.assembly import exportAssembly, exportCAF
 | 
			
		||||
 | 
			
		||||
from cadquery.occ_impl.exporters.assembly import (
 | 
			
		||||
    exportAssembly,
 | 
			
		||||
    exportCAF,
 | 
			
		||||
    exportVTKJS,
 | 
			
		||||
    exportVRML,
 | 
			
		||||
)
 | 
			
		||||
from cadquery.occ_impl.assembly import toJSON
 | 
			
		||||
from OCP.gp import gp_XYZ
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -44,6 +49,17 @@ def nested_assy():
 | 
			
		||||
    return assy
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def empty_top_assy():
 | 
			
		||||
 | 
			
		||||
    b1 = cq.Workplane().box(1, 1, 1)
 | 
			
		||||
 | 
			
		||||
    assy = cq.Assembly()
 | 
			
		||||
    assy.add(b1, color=cq.Color("green"))
 | 
			
		||||
 | 
			
		||||
    return assy
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def box_and_vertex():
 | 
			
		||||
 | 
			
		||||
@ -115,6 +131,33 @@ def test_native_export(simple_assy):
 | 
			
		||||
    assert os.path.exists("assy.xml")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_vtkjs_export(nested_assy):
 | 
			
		||||
 | 
			
		||||
    exportVTKJS(nested_assy, "assy")
 | 
			
		||||
 | 
			
		||||
    # only sanity check for now
 | 
			
		||||
    assert os.path.exists("assy.zip")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_vrml_export(simple_assy):
 | 
			
		||||
 | 
			
		||||
    exportVRML(simple_assy, "assy.wrl")
 | 
			
		||||
 | 
			
		||||
    # only sanity check for now
 | 
			
		||||
    assert os.path.exists("assy.wrl")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_toJSON(simple_assy, nested_assy, empty_top_assy):
 | 
			
		||||
 | 
			
		||||
    r1 = toJSON(simple_assy)
 | 
			
		||||
    r2 = toJSON(simple_assy)
 | 
			
		||||
    r3 = toJSON(empty_top_assy)
 | 
			
		||||
 | 
			
		||||
    assert len(r1) == 3
 | 
			
		||||
    assert len(r2) == 3
 | 
			
		||||
    assert len(r3) == 1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_save(simple_assy, nested_assy):
 | 
			
		||||
 | 
			
		||||
    simple_assy.save("simple.step")
 | 
			
		||||
 | 
			
		||||
@ -4571,3 +4571,27 @@ class TestCadQuery(BaseTest):
 | 
			
		||||
        self.assertEqual(len(edges), len(vertices) + 1)
 | 
			
		||||
        endpoints = [e.endPoint() for e in edges]
 | 
			
		||||
        self.assertTrue(all([v in endpoints for v in vecs]))
 | 
			
		||||
 | 
			
		||||
    def testBrepImportExport(self):
 | 
			
		||||
 | 
			
		||||
        # import/export to file
 | 
			
		||||
        s = Workplane().box(1, 1, 1).val()
 | 
			
		||||
 | 
			
		||||
        s.exportBrep("test.brep")
 | 
			
		||||
        si = Shape.importBrep("test.brep")
 | 
			
		||||
 | 
			
		||||
        self.assertTrue(si.isValid())
 | 
			
		||||
        self.assertAlmostEqual(si.Volume(), 1)
 | 
			
		||||
 | 
			
		||||
        # import/export to BytesIO
 | 
			
		||||
        from io import BytesIO
 | 
			
		||||
 | 
			
		||||
        bio = BytesIO()
 | 
			
		||||
 | 
			
		||||
        s.exportBrep(bio)
 | 
			
		||||
        bio.seek(0)
 | 
			
		||||
 | 
			
		||||
        si = Shape.importBrep("test.brep")
 | 
			
		||||
 | 
			
		||||
        self.assertTrue(si.isValid())
 | 
			
		||||
        self.assertAlmostEqual(si.Volume(), 1)
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,9 @@ import pytest
 | 
			
		||||
from glob import glob
 | 
			
		||||
from itertools import chain, count
 | 
			
		||||
 | 
			
		||||
from docutils.parsers.rst import directives, Directive
 | 
			
		||||
from path import Path
 | 
			
		||||
 | 
			
		||||
from docutils.parsers.rst import directives
 | 
			
		||||
from docutils.core import publish_doctree
 | 
			
		||||
from docutils.utils import Reporter
 | 
			
		||||
 | 
			
		||||
@ -12,16 +14,16 @@ from cadquery import cqgi
 | 
			
		||||
from cadquery.cq_directive import cq_directive
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def find_examples(pattern="examples/*.py"):
 | 
			
		||||
def find_examples(pattern="examples/*.py", path=Path("examples")):
 | 
			
		||||
 | 
			
		||||
    for p in glob(pattern):
 | 
			
		||||
        with open(p, encoding="UTF-8") as f:
 | 
			
		||||
            code = f.read()
 | 
			
		||||
 | 
			
		||||
        yield code
 | 
			
		||||
        yield code, path
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def find_examples_in_docs(pattern="doc/*.rst"):
 | 
			
		||||
def find_examples_in_docs(pattern="doc/*.rst", path=Path("doc")):
 | 
			
		||||
 | 
			
		||||
    # dummy CQ directive for code
 | 
			
		||||
    class dummy_cq_directive(cq_directive):
 | 
			
		||||
@ -48,16 +50,17 @@ def find_examples_in_docs(pattern="doc/*.rst"):
 | 
			
		||||
    # yield all code snippets
 | 
			
		||||
    for c in dummy_cq_directive.codes:
 | 
			
		||||
 | 
			
		||||
        yield c
 | 
			
		||||
        yield c, path
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize(
 | 
			
		||||
    "code", chain(find_examples(), find_examples_in_docs()), ids=count(0)
 | 
			
		||||
    "code, path", chain(find_examples(), find_examples_in_docs()), ids=count(0)
 | 
			
		||||
)
 | 
			
		||||
def test_example(code):
 | 
			
		||||
def test_example(code, path):
 | 
			
		||||
 | 
			
		||||
    # build
 | 
			
		||||
    res = cqgi.parse(code).build()
 | 
			
		||||
    with path:
 | 
			
		||||
        res = cqgi.parse(code).build()
 | 
			
		||||
 | 
			
		||||
    assert res.exception is None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -98,6 +98,15 @@ class TestExporters(BaseTest):
 | 
			
		||||
        # export again to trigger all paths in the code
 | 
			
		||||
        exporters.export(self._box(), "out.vrml")
 | 
			
		||||
 | 
			
		||||
    def testVTP(self):
 | 
			
		||||
 | 
			
		||||
        exporters.export(self._box(), "out.vtp")
 | 
			
		||||
 | 
			
		||||
        with open("out.vtp") as f:
 | 
			
		||||
            res = f.read(100)
 | 
			
		||||
 | 
			
		||||
        assert res.startswith('<?xml version="1.0"?>\n<VTKFile')
 | 
			
		||||
 | 
			
		||||
    def testDXF(self):
 | 
			
		||||
 | 
			
		||||
        exporters.export(self._box().section(), "out.dxf")
 | 
			
		||||
 | 
			
		||||
@ -1,14 +1,27 @@
 | 
			
		||||
from tests import BaseTest
 | 
			
		||||
 | 
			
		||||
import cadquery
 | 
			
		||||
import cadquery as cq
 | 
			
		||||
from cadquery.occ_impl.jupyter_tools import display
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestJupyter(BaseTest):
 | 
			
		||||
    def test_repr_html(self):
 | 
			
		||||
        cube = cadquery.Workplane("XY").box(1, 1, 1)
 | 
			
		||||
    def test_repr_javascript(self):
 | 
			
		||||
        cube = cq.Workplane("XY").box(1, 1, 1)
 | 
			
		||||
        assy = cq.Assembly().add(cube)
 | 
			
		||||
        shape = cube.val()
 | 
			
		||||
        self.assertIsInstance(shape, cadquery.occ_impl.shapes.Solid)
 | 
			
		||||
 | 
			
		||||
        # Test no exception on rendering to html
 | 
			
		||||
        html = shape._repr_html_()
 | 
			
		||||
        # TODO: verification improvement: test for valid html
 | 
			
		||||
        self.assertIsInstance(shape, cq.occ_impl.shapes.Solid)
 | 
			
		||||
 | 
			
		||||
        # Test no exception on rendering to js
 | 
			
		||||
        js1 = shape._repr_javascript_()
 | 
			
		||||
        js2 = cube._repr_javascript_()
 | 
			
		||||
        js3 = assy._repr_javascript_()
 | 
			
		||||
 | 
			
		||||
        assert "function render" in js1
 | 
			
		||||
        assert "function render" in js2
 | 
			
		||||
        assert "function render" in js3
 | 
			
		||||
 | 
			
		||||
    def test_display_error(self):
 | 
			
		||||
 | 
			
		||||
        with self.assertRaises(ValueError):
 | 
			
		||||
            display(cq.Vector())
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user