CadQuery / cadquery

A python parametric CAD scripting framework based on OCCT
https://cadquery.readthedocs.io
Other
3.2k stars 290 forks source link

Ray casting On An Object with Holes #1413

Open derusermus opened 1 year ago

derusermus commented 1 year ago
def raycast(pnt1: list[float, float, float], pnt2: list[float, float, float], shape: cq.Workplane()) -> dict:
  shape_wrapped = shape.val()

      intersection_pnts = {}

      for e,f in enumerate(shape_wrapped.Faces()):
          show_object(f.Wires())

          surface = OCP.BRepAdaptor.BRepAdaptor_Surface(f.wrapped)

          edge = OCP.BRepAdaptor.BRepAdaptor_Curve( OCP.BRepBuilderAPI.BRepBuilderAPI_MakeEdge(OCP.gp.gp_Pnt(*pnt1), OCP.gp.gp_Pnt(*pnt2)).Edge())

          inter = OCP.IntCurveSurface.IntCurveSurface_HInter()

          inter.Perform(edge, surface)

          # print(inter.IsDone())
          while not inter.IsDone():
              print('Not Done')
              pass

          intersection_pnts[e] = {}

          if inter.NbPoints() > 0:
              for i in range(1, inter.NbPoints() + 1):
                  pnt = inter.Point(i).Pnt()
                  intersection_pnts[e][i] = (pnt.X(), pnt.Y(),pnt.Z())

      return intersection_pnts

result = Workplane("XY").box(length,height,thickness).faces(">Z").workplane().hole(diam)\
        .faces(">Z").workplane() \
        .rect(length-padding,height-padding,forConstruction=True) \
        .vertices().cboreHole(2.4,4.4,2.1)
ray = raycast([0,0,-10],[0,0,10],result)

Trying to do ray casting and through my research I came up with this code. The problem is that it seems to find collisions where there should be holes. When I run the code above it gives back a point at 0,0,-5 and 0,0,5 which are in the center hole and not on a face. Is there a way to account for this?

lorenzncode commented 1 year ago

Please provide minimal reproducible examples that are complete with var definitions, and imports. I came up with this MRE:

import cadquery as cq
import OCP

result = cq.Workplane().circle(20).circle(5).extrude(5)

face = result.faces(">Z").val()

pnt1 = (0, 0, -10)
pnt2 = (0, 0, 10)
edge = cq.Edge.makeLine(pnt1, pnt2)
curve = OCP.BRepAdaptor.BRepAdaptor_Curve(edge.wrapped)

surface = OCP.BRepAdaptor.BRepAdaptor_Surface(face.wrapped)

inter = OCP.IntCurveSurface.IntCurveSurface_HInter()
inter.Perform(curve, surface)

if not inter.IsDone():
    raise ValueError("inter failed")

intersection_pnts = []
if inter.NbPoints() > 0:
    for i in range(1, inter.NbPoints() + 1):
        pnt = inter.Point(i).Pnt()
        intersection_pnts.append((pnt.X(), pnt.Y(), pnt.Z()))

# show_object(result, name="result")
# show_object(edge, name="edge")
# for i, p in enumerate(intersection_pnts):
#    show_object(cq.Vertex.makeVertex(*p), name=f"p{i}")

I'm not an OCCT expert so there may be better solutions within OCCT. I found one way could be to use BRepClass_FaceClassifier().

import cadquery as cq
import OCP
from OCP.BRepClass import BRepClass_FaceClassifier
import OCP.TopAbs as ta

result = cq.Workplane().circle(20).circle(5).extrude(5)
# result = cq.Workplane().circle(20).extrude(5)

face = result.faces(">Z").val()

pnt1 = (0, 0, -10)
pnt2 = (0, 0, 10)
edge = cq.Edge.makeLine(pnt1, pnt2)
curve = OCP.BRepAdaptor.BRepAdaptor_Curve(edge.wrapped)

surface = OCP.BRepAdaptor.BRepAdaptor_Surface(face.wrapped)

inter = OCP.IntCurveSurface.IntCurveSurface_HInter()
inter.Perform(curve, surface)

if not inter.IsDone():
    raise ValueError("inter failed")

intersection_pnts = []
if inter.NbPoints() > 0:
    for i in range(1, inter.NbPoints() + 1):
        pnt = inter.Point(i).Pnt()
        face_classifier = BRepClass_FaceClassifier()
        face_classifier.Perform(face.wrapped, pnt, 1e-6)
        if face_classifier.State() == ta.TopAbs_IN:
            intersection_pnts.append((pnt.X(), pnt.Y(), pnt.Z()))

# show_object(result, name="result")
# show_object(edge, name="edge")
# for i, p in enumerate(intersection_pnts):
#    show_object(cq.Vertex.makeVertex(*p), name=f"p{i}")