diff --git a/appveyor.yml b/appveyor.yml index a2d205235..cf17d0b1c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -28,7 +28,7 @@ install: - cmd: conda init cmd.exe - conda env create -f environment.yml - conda activate cadquery - - pip install git+https://github.com/CadQuery/OCP-stubs.git@7.5.1 + - pip install git+https://github.com/CadQuery/OCP-stubs.git@7.6.3 build: false diff --git a/cadquery/cq.py b/cadquery/cq.py index e1b58104e..15ff3ad1a 100644 --- a/cadquery/cq.py +++ b/cadquery/cq.py @@ -530,7 +530,7 @@ def workplane( :type invert: boolean or None=False :type centerOption: string or None='ProjectedOrigin' :type origin: Vector or None - :rtype: Workplane object + :rtype: Workplane object The first element on the stack must be a face, a set of co-planar faces or a vertex. If a vertex, then the parent @@ -3019,7 +3019,7 @@ def extrude( passed, the extrusion extends this far and a negative value is in the opposite direction to the normal of the plane. The string "next" extrudes until the next face orthogonal to the wire normal. "last" extrudes to the last face. If a object of type Face is passed then - the extrusion will extend until this face. **Note that the Workplane must contain a Solid for extruding to a given face.** + the extrusion will extend until this face. **Note that the Workplane must contain a Solid for extruding to a given face.** :param combine: True or "a" to combine the resulting solid with parent solids if found, "cut" or "s" to remove the resulting solid from the parent solids if found. False to keep the resulting solid separated from the parent solids. :param boolean clean: call :py:meth:`clean` afterwards to have a clean shape :param boolean both: extrude in both directions symmetrically @@ -3524,7 +3524,7 @@ def loft( :param boolean clean: call :py:meth:`clean` afterwards to have a clean shape :return: a Workplane object containing the created loft - + """ if self.ctx.pendingWires: @@ -3765,7 +3765,7 @@ def interpPlate( ) -> T: """ Returns a plate surface that is 'thickness' thick, enclosed by 'surf_edge_pts' points, and going - through 'surf_pts' points. Using pushPoints directly with interpPlate and combine=True, can be + through 'surf_pts' points. Using pushPoints directly with interpPlate and combine=True, can be very resources intensive depending on the complexity of the shape. In this case set combine=False. :param surf_edges diff --git a/cadquery/occ_impl/jupyter_tools.py b/cadquery/occ_impl/jupyter_tools.py index a4d4827bb..a7c1b415f 100644 --- a/cadquery/occ_impl/jupyter_tools.py +++ b/cadquery/occ_impl/jupyter_tools.py @@ -36,7 +36,7 @@ const mapper = vtk.Rendering.Core.vtkMapper.newInstance(); mapper.setInputConnection(reader.getOutputPort()); mapper.setResolveCoincidentTopologyToPolygonOffset(); - mapper.setResolveCoincidentTopologyPolygonOffsetParameters(0.5,100); + mapper.setResolveCoincidentTopologyPolygonOffsetParameters(0.9,20); const actor = vtk.Rendering.Core.vtkActor.newInstance(); actor.setMapper(mapper); diff --git a/cadquery/occ_impl/shapes.py b/cadquery/occ_impl/shapes.py index 639a941ef..ebaa46a67 100644 --- a/cadquery/occ_impl/shapes.py +++ b/cadquery/occ_impl/shapes.py @@ -19,7 +19,6 @@ from vtkmodules.vtkCommonDataModel import vtkPolyData from vtkmodules.vtkFiltersCore import vtkTriangleFilter, vtkPolyDataNormals - from .geom import Vector, VectorLike, BoundBox, Plane, Location, Matrix from ..utils import cqmultimethod as multimethod @@ -60,8 +59,6 @@ BRepAdaptor_Curve, BRepAdaptor_CompCurve, BRepAdaptor_Surface, - BRepAdaptor_HCurve, - BRepAdaptor_HCompCurve, ) from OCP.BRepBuilderAPI import ( @@ -233,6 +230,10 @@ # for catching exceptions from OCP.Standard import Standard_NoSuchObject, Standard_Failure +from OCP.Prs3d import Prs3d_IsoAspect +from OCP.Quantity import Quantity_Color +from OCP.Aspect import Aspect_TOL_SOLID + from OCP.Interface import Interface_Static from math import pi, sqrt, inf @@ -449,7 +450,7 @@ def exportStl( :param fileName: The path and file name to write the STL output to. :param tolerance: A linear deflection setting which limits the distance between a curve and its tessellation. Setting this value too low will result in large meshes that can consume computing resources. - Setting the value too high can result in meshes with a level of detail that is too low. + Setting the value too high can result in meshes with a level of detail that is too low. Default is 1e-3, which is a good starting point for a range of cases. :param angularTolerance: Angular deflection setting which limits the angle between subsequent segments in a polyline. Default is 0.1. :param ascii: Export the file as ASCII (True) or binary (False) STL format. Default is binary. @@ -1216,7 +1217,9 @@ def tessellate( # add vertices vertices += [ Vector(v.X(), v.Y(), v.Z()) - for v in (v.Transformed(Trsf) for v in poly.Nodes()) + for v in ( + poly.Node(i).Transformed(Trsf) for i in range(1, poly.NbNodes()) + ) ] # add triangles @@ -1240,7 +1243,10 @@ def tessellate( return vertices, triangles def toVtkPolyData( - self, tolerance: float, angularTolerance: float = 0.1, normals: bool = True + self, + tolerance: Optional[float] = None, + angularTolerance: Optional[float] = None, + normals: bool = True, ) -> vtkPolyData: """ Convert shape to vtkPolyData @@ -1248,9 +1254,17 @@ def toVtkPolyData( vtk_shape = IVtkOCC_Shape(self.wrapped) shape_data = IVtkVTK_ShapeData() - shape_mesher = IVtkOCC_ShapeMesher( - tolerance, angularTolerance, theNbUIsos=0, theNbVIsos=0 - ) + shape_mesher = IVtkOCC_ShapeMesher() + + drawer = vtk_shape.Attributes() + drawer.SetUIsoAspect(Prs3d_IsoAspect(Quantity_Color(), Aspect_TOL_SOLID, 1, 0)) + drawer.SetVIsoAspect(Prs3d_IsoAspect(Quantity_Color(), Aspect_TOL_SOLID, 1, 0)) + + if tolerance: + drawer.SetDeviationCoefficient(tolerance) + + if angularTolerance: + drawer.SetDeviationAngle(angularTolerance) shape_mesher.Build(vtk_shape, shape_data) @@ -1338,14 +1352,6 @@ class Mixin1DProtocol(ShapeProtocol, Protocol): def _geomAdaptor(self) -> Union[BRepAdaptor_Curve, BRepAdaptor_CompCurve]: ... - def _geomAdaptorH( - self, - ) -> Tuple[ - Union[BRepAdaptor_Curve, BRepAdaptor_CompCurve], - Union[BRepAdaptor_HCurve, BRepAdaptor_HCompCurve], - ]: - ... - def paramAt(self, d: float) -> float: ... @@ -1546,7 +1552,7 @@ def locationAt( :return: A Location object representing local coordinate system at the specified distance. """ - curve, curveh = self._geomAdaptorH() + curve = self._geomAdaptor() if mode == "length": param = self.paramAt(d) @@ -1559,7 +1565,7 @@ def locationAt( else: law = GeomFill_CorrectedFrenet() - law.SetCurve(curveh) + law.SetCurve(curve) tangent, normal, binormal = gp_Vec(), gp_Vec(), gp_Vec() @@ -1644,15 +1650,6 @@ def _geomAdaptor(self) -> BRepAdaptor_Curve: return BRepAdaptor_Curve(self.wrapped) - def _geomAdaptorH(self) -> Tuple[BRepAdaptor_Curve, BRepAdaptor_HCurve]: - """ - Return the underlying geometry - """ - - curve = self._geomAdaptor() - - return curve, BRepAdaptor_HCurve(curve) - def close(self) -> Union["Edge", "Wire"]: """ Close an Edge @@ -1943,15 +1940,6 @@ def _geomAdaptor(self) -> BRepAdaptor_CompCurve: return BRepAdaptor_CompCurve(self.wrapped) - def _geomAdaptorH(self) -> Tuple[BRepAdaptor_CompCurve, BRepAdaptor_HCompCurve]: - """ - Return the underlying geometry - """ - - curve = self._geomAdaptor() - - return curve, BRepAdaptor_HCompCurve(curve) - def close(self) -> "Wire": """ Close a Wire @@ -2545,7 +2533,7 @@ def constructOn(cls, f: "Face", outer: "Wire", *inner: "Wire") -> "Face": bldr = BRepBuilderAPI_MakeFace(f._geomAdaptor(), outer.wrapped) for w in inner: - bldr.Add(TopoDS.Wire_s(w.wrapped.Reversed())) + bldr.Add(TopoDS.Wire_s(w.wrapped)) return cls(bldr.Face()).fix() diff --git a/conda/meta.yaml b/conda/meta.yaml index 73a0b221a..6d64340f8 100644 --- a/conda/meta.yaml +++ b/conda/meta.yaml @@ -15,8 +15,7 @@ requirements: - setuptools run: - python {{ environ.get('PYTHON_VERSION') }} - - ocp 7.5.3 - - vtk =9.0.1 + - ocp 7.6.* - pyparsing >=2.1.9 - ezdxf - ipython diff --git a/environment.yml b/environment.yml index cb5d50f23..1502664d3 100644 --- a/environment.yml +++ b/environment.yml @@ -6,8 +6,7 @@ channels: dependencies: - python>=3.8 - ipython - - ocp=7.5.3 - - vtk=9.0.1 + - ocp=7.6.* - pyparsing>=2.1.9 - sphinx=5.0.1 - sphinx_rtd_theme diff --git a/tests/test_cadquery.py b/tests/test_cadquery.py index 7e4e10085..ec9eb15a4 100644 --- a/tests/test_cadquery.py +++ b/tests/test_cadquery.py @@ -4,7 +4,6 @@ """ # system modules import math, os.path, time, tempfile -from random import choice from random import random from random import randrange from itertools import product @@ -14,7 +13,6 @@ # my modules from cadquery import * -from cadquery import exporters from cadquery import occ_impl from tests import ( BaseTest, @@ -5479,3 +5477,13 @@ def test_makeNSidedSurface(self): # exception on invalid constraint with raises(ValueError): Face.makeNSidedSurface(outer_w, [[0, 0, 1]]) + + def test_toVtk(self): + + from vtkmodules.vtkCommonDataModel import vtkPolyData + + f = Face.makePlane(2, 2) + vtk = f.toVtkPolyData(normals=False) + + assert isinstance(vtk, vtkPolyData) + assert vtk.GetNumberOfPolys() == 2