cadquery icon indicating copy to clipboard operation
cadquery copied to clipboard

BRep_Tool:: TopoDS_Vertex hasn't gp_Pnt when making a plate from a wire

Open jalovisko opened this issue 3 years ago • 4 comments

I am attempting to generate a plate with a given thickness based on a closed wire such as in the example below:

import cadquery as cq

from math import sqrt
import numpy as np

unit_cell_size = 10
thickness = 1

delta_radius = 0.5 - 0.5/sqrt(2)
edge_points = [
    [[0.0, 0.5],
     [delta_radius, delta_radius],
     [0.5, 0.0]],
    [[0.0, 0.5],
     [delta_radius, delta_radius],
     [0.5, 0.0]],
    [[0.0, 0.5],
     [delta_radius, delta_radius],
     [0.5, 0.0]],
    [[-0.5, 0.0],
     [-delta_radius,-delta_radius],
     [0.0, -0.5]],
    [[-0.5, 0.0],
     [-delta_radius,-delta_radius],
     [0.0, -0.5]],
    [[-0.5, 0.0],
     [-delta_radius,-delta_radius],
     [0.0, -0.5]]
]
edge_points = np.array(edge_points) * unit_cell_size

plane_list = ["XZ", "XY", "YZ", "XZ", "YZ", "XY"]
offset_list = [- 1, 1, 1, 1, - 1, - 1]
offset_list = np.array(offset_list) * unit_cell_size * 0.5
edge_wire = (
    cq.Workplane(plane_list[0])
    .workplane(offset = - offset_list[0])
    .spline(edge_points[0])
)
for i in range(len(edge_points) - 1):
    edge_wire = edge_wire.add(
        cq.Workplane(plane_list[i + 1])
        .workplane(offset = - offset_list[i + 1])
        .spline(edge_points[i + 1])
    )
surface_points = [[0, 0, 0]]
plate = cq.Workplane("XY")
plate = plate.interpPlate(edge_wire, surface_points, thickness)

However, I see the following error when I try to make an interpPlate:

plate = plate.interpPlate(edge_wire, surface_points, thickness)
------------------------
Standard_NullObjectTraceback (most recent call last)
<ipython-input-4-03580d26568b> in <module>
     63 surface_points = [[0, 0, 0]]
     64 plate = cq.Workplane("XY")
---> 65 plate = plate.interpPlate(edge_wire, surface_points, thickness)

~/anaconda3/envs/cqgui/lib/python3.8/site-packages/cadquery/cq.py in interpPlate(self, surf_edges, surf_pts, thickness, combine, clean, degree, nbPtsOnCur, nbIter, anisotropy, tol2d, tol3d, tolAng, tolCurv, maxDeg, maxSegments)
   3314 
   3315         # Creates interpolated plate
-> 3316         p = Solid.interpPlate(
   3317             surf_edges,
   3318             surf_pts,

~/anaconda3/envs/cqgui/lib/python3.8/site-packages/cadquery/occ_impl/shapes.py in interpPlate(cls, surf_edges, surf_pts, thickness, degree, nbPtsOnCur, nbIter, anisotropy, tol2d, tol3d, tolAng, tolCurv, maxDeg, maxSegments)
   2158                 True,
   2159             )  # The last True is important to make solid
-> 2160             solid.MakeOffsetShape()
   2161             return cls(solid.Shape())
   2162         else:  # Return 2D surface only

Standard_NullObject: BRep_Tool:: TopoDS_Vertex hasn't gp_Pnt

The edge_wire itself is generated with no problems and looks like this: 2021-09-22_22-18

This is looks strange for me because the same code works perfectly for another set of points:

edge_points = [
        [[0.5, 0.5],
         [0.25, 0.0],
         [0.5, - 0.5]],
        [[- 0.5, - 0.5],
         [0.0, - 0.25],
         [0.5, - 0.5]],
        [[- 0.5, - 0.5],
         [0.0, - 0.25],
         [0.5, - 0.5]],
        [[- 0.5, - 0.5],
         [- 0.25, 0.0],
         [- 0.5, 0.5]],
        [[0.5, 0.5],
         [0.0, 0.25],
         [- 0.5, 0.5]],
        [[0.5, 0.5],
         [0.0, 0.25],
         [- 0.5, 0.5]],
    ]

and the result in this case is very nice. 2021-09-22_22-23

Perhaps I am missing something?

jalovisko avatar Sep 23 '21 02:09 jalovisko

I managed find a workaround for it by using arcs instead of splines for the wire:

delta_radius = 0.5 - 0.5/sqrt(2)
convex_pnts = [[0.0, 0.5],
               [delta_radius, delta_radius],
               [0.5, 0.0]]
nonconvex_pnts = [[-0.5, 0.0],
                  [-delta_radius,-delta_radius],
                  [0.0, -0.5]]
edge_points = [convex_pnts,
               nonconvex_pnts,
               convex_pnts,
               nonconvex_pnts,
               convex_pnts,
               nonconvex_pnts]
edge_points = np.array(edge_points) * unit_cell_size

plane_list = ["XZ", "XY", "YZ", "XZ", "XY", "YZ"]
offset_list = [- 1, - 1, 1, 1, 1, - 1]
offset_list = np.array(offset_list) * unit_cell_size * 0.5

edge_wire = (
    cq.Workplane(plane_list[0])
    .workplane(offset = - offset_list[0])
    .moveTo(edge_points[0][0][0],
            edge_points[0][0][1])
    .threePointArc(tuple(edge_points[0][1]),
                   tuple(edge_points[0][2]))
)

for i in range(len(edge_points) - 1):
    edge_wire = edge_wire.add(
        cq.Workplane(plane_list[i + 1])
        .workplane(offset = - offset_list[i + 1])
        .moveTo(edge_points[i + 1][0][0],
                edge_points[i + 1][0][1])
        .threePointArc(tuple(edge_points[i + 1][1]),
                       tuple(edge_points[i + 1][2]))
    )

surface_points = [[0, 0, 0]]
plate_4 = cq.Workplane("XY")
plate_4 = plate_4.interpPlate(edge_wire, surface_points, thickness)

2021-09-23_15-48 But I still wonder why there are issues with splines? I wonder if OpenCascade having troubles connecting the splines or I do something wrong?

jalovisko avatar Sep 23 '21 19:09 jalovisko

I wonder if OpenCascade having troubles connecting the splines

It could be that with splines the wire was not being closed properly for some reason.

jmwright avatar Sep 24 '21 10:09 jmwright

Looks like the issue occur in the offset generation part. Do you get a correct surface without the offset?

adam-urbanczyk avatar Sep 25 '21 09:09 adam-urbanczyk

The following might be a solution, at least it worked for me. In shapes.py, I modified the assembleEdges() method by replacing:

    for e in listOfEdges:
        wire_builder.Add(e.wrapped)

with

    occ_edges_list = TopTools_ListOfShape()
    for e in listOfEdges:
        occ_edges_list.Append(e.wrapped)
    wire_builder.Add(occ_edges_list)

my two cents is that it might take advantage of the following property : The edges are not to be consecutive (https://dev.opencascade.org/doc/refman/html/class_b_rep_builder_a_p_i___make_wire.html#ae9dd6e34dfd1bc0df8dc3b9c01bb97c2)

void BRepBuilderAPI_MakeWire::Add	(const TopTools_ListOfShape & L)	

Adds the edges of <L> to the current wire. The edges are not to be consecutive. 
But they are to be all connected geometrically or topologically. 
If some of them are not connected the Status give DisconnectedWire 
but the "Maker" is Done() and you can get the partial result.
(ie connected to the first edgeof the list <L>)

bragostin avatar Feb 06 '22 09:02 bragostin

This is working in current master with change to surface_points as follows: surface_points = [[0, 0, 0]] -> surface_points = [(0, 0, 0)]

lorenzncode avatar Sep 23 '22 02:09 lorenzncode

Thanks for checking @lorenzncode !

adam-urbanczyk avatar Sep 23 '22 05:09 adam-urbanczyk