{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from jupyter_cadquery import show, open_viewer\n", "open_viewer(\"OCC\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# OCC bottle (ported over to OCP)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import math\n", "\n", "from OCP.gp import gp_Pnt, gp_Vec, gp_Trsf, gp_Ax2, gp_Ax3, gp_Pnt2d, gp_Dir2d, gp_Ax2d, gp, gp_Pln\n", "from OCP.GC import GC_MakeArcOfCircle, GC_MakeSegment\n", "from OCP.GCE2d import GCE2d_MakeSegment\n", "from OCP.Geom import Geom_Plane, Geom_CylindricalSurface\n", "from OCP.Geom2d import Geom2d_Ellipse, Geom2d_TrimmedCurve\n", "from OCP.GeomAbs import GeomAbs_Plane\n", "from OCP.BRepBuilderAPI import (BRepBuilderAPI_MakeEdge, BRepBuilderAPI_MakeWire,\n", " BRepBuilderAPI_MakeFace, BRepBuilderAPI_Transform)\n", "from OCP.BRepPrimAPI import BRepPrimAPI_MakePrism, BRepPrimAPI_MakeCylinder\n", "from OCP.BRepFilletAPI import BRepFilletAPI_MakeFillet\n", "from OCP.BRepAlgoAPI import BRepAlgoAPI_Fuse\n", "from OCP.BRepOffsetAPI import BRepOffsetAPI_MakeThickSolid, BRepOffsetAPI_ThruSections\n", "from OCP.BRepAdaptor import BRepAdaptor_Surface\n", "from OCP.BRepLib import BRepLib\n", "from OCP.BRep import BRep_Tool\n", "from OCP.BRep import BRep_Builder\n", "from OCP.TopoDS import TopoDS, TopoDS_Compound, TopoDS_Builder, TopoDS_Face\n", "from OCP.TopExp import TopExp_Explorer\n", "from OCP.TopAbs import TopAbs_EDGE, TopAbs_FACE\n", "from OCP.TopTools import TopTools_ListOfShape\n", "\n", "\n", "def face_is_plane(face: TopoDS_Face) -> bool:\n", " \"\"\"\n", " Returns True if the TopoDS_Face is a plane, False otherwise\n", " \"\"\"\n", " surf = BRepAdaptor_Surface(face, True)\n", " surf_type = surf.GetType()\n", " return surf_type == GeomAbs_Plane\n", "\n", "\n", "def geom_plane_from_face(aFace: TopoDS_Face) -> gp_Pln:\n", " \"\"\"\n", " Returns the geometric plane entity from a planar surface\n", " \"\"\"\n", " return BRepAdaptor_Surface(aFace, True).Plane()\n", "\n", "\n", "height = 70\n", "width = 50\n", "thickness = 30\n", "\n", "print(\"creating bottle\")\n", "# The points we'll use to create the profile of the bottle's body\n", "aPnt1 = gp_Pnt(-width / 2.0, 0, 0)\n", "aPnt2 = gp_Pnt(-width / 2.0, -thickness / 4.0, 0)\n", "aPnt3 = gp_Pnt(0, -thickness / 2.0, 0)\n", "aPnt4 = gp_Pnt(width / 2.0, -thickness / 4.0, 0)\n", "aPnt5 = gp_Pnt(width / 2.0, 0, 0)\n", "\n", "aArcOfCircle = GC_MakeArcOfCircle(aPnt2, aPnt3, aPnt4)\n", "aSegment1 = GC_MakeSegment(aPnt1, aPnt2)\n", "aSegment2 = GC_MakeSegment(aPnt4, aPnt5)\n", "\n", "# Could also construct the line edges directly using the points instead of the resulting line\n", "aEdge1 = BRepBuilderAPI_MakeEdge(aSegment1.Value())\n", "aEdge2 = BRepBuilderAPI_MakeEdge(aArcOfCircle.Value())\n", "aEdge3 = BRepBuilderAPI_MakeEdge(aSegment2.Value())\n", "\n", "# Create a wire out of the edges\n", "aWire = BRepBuilderAPI_MakeWire(aEdge1.Edge(), aEdge2.Edge(), aEdge3.Edge())\n", "\n", "# Quick way to specify the X axis\n", "xAxis = gp.OX_s()\n", "\n", "# Set up the mirror\n", "aTrsf = gp_Trsf()\n", "aTrsf.SetMirror(xAxis)\n", "\n", "# Apply the mirror transformation\n", "aBRespTrsf = BRepBuilderAPI_Transform(aWire.Wire(), aTrsf)\n", "\n", "# Get the mirrored shape back out of the transformation and convert back to a wire\n", "aMirroredShape = aBRespTrsf.Shape()\n", "\n", "# A wire instead of a generic shape now\n", "aMirroredWire = TopoDS.Wire_s(aMirroredShape)\n", "\n", "# Combine the two constituent wires\n", "mkWire = BRepBuilderAPI_MakeWire()\n", "mkWire.Add(aWire.Wire())\n", "mkWire.Add(aMirroredWire)\n", "myWireProfile = mkWire.Wire()\n", "\n", "# The face that we'll sweep to make the prism\n", "myFaceProfile = BRepBuilderAPI_MakeFace(myWireProfile)\n", "\n", "# We want to sweep the face along the Z axis to the height\n", "aPrismVec = gp_Vec(0, 0, height)\n", "myBody_step1 = BRepPrimAPI_MakePrism(myFaceProfile.Face(), aPrismVec)\n", "\n", "# Add fillets to all edges through the explorer\n", "mkFillet = BRepFilletAPI_MakeFillet(myBody_step1.Shape())\n", "anEdgeExplorer = TopExp_Explorer(myBody_step1.Shape(), TopAbs_EDGE)\n", "\n", "while anEdgeExplorer.More():\n", " anEdge = TopoDS.Edge_s(anEdgeExplorer.Current())\n", " mkFillet.Add(thickness / 12.0, anEdge)\n", "\n", " anEdgeExplorer.Next()\n", "\n", "# Create the neck of the bottle\n", "neckLocation = gp_Pnt(0, 0, height)\n", "neckAxis = gp.DZ_s()\n", "neckAx2 = gp_Ax2(neckLocation, neckAxis)\n", "\n", "myNeckRadius = thickness / 4.0\n", "myNeckHeight = height / 10.0\n", "\n", "mkCylinder = BRepPrimAPI_MakeCylinder(neckAx2, myNeckRadius, myNeckHeight)\n", "\n", "myBody_step2 = BRepAlgoAPI_Fuse(mkFillet.Shape(), mkCylinder.Shape())\n", "\n", "# Our goal is to find the highest Z face and remove it\n", "zMax = -1.0\n", "\n", "# We have to work our way through all the faces to find the highest Z face so we can remove it for the shell\n", "aFaceExplorer = TopExp_Explorer(myBody_step2.Shape(), TopAbs_FACE)\n", "while aFaceExplorer.More():\n", " aFace = TopoDS.Face_s(aFaceExplorer.Current())\n", " if face_is_plane(aFace):\n", " aPlane = geom_plane_from_face(aFace)\n", "\n", " # We want the highest Z face, so compare this to the previous faces\n", " aPntLoc = aPlane.Location()\n", " aZ = aPntLoc.Z()\n", " if aZ > zMax:\n", " zMax = aZ\n", " aFaceExplorer.Next()\n", "\n", "facesToRemove = TopTools_ListOfShape()\n", "facesToRemove.Append(aFace)\n", "\n", "mk_thick_solid = BRepOffsetAPI_MakeThickSolid()\n", "mk_thick_solid.MakeThickSolidByJoin(\n", " myBody_step2.Shape(), facesToRemove, -thickness / 50.0, 0.001\n", ")\n", "mk_thick_solid.Build()\n", "myBody_step3 = mk_thick_solid.Shape()\n", "\n", "# Set up our surfaces for the threading on the neck\n", "neckAx2_Ax3 = gp_Ax3(neckLocation, gp.DZ_s())\n", "aCyl1 = Geom_CylindricalSurface(neckAx2_Ax3, myNeckRadius * 0.99)\n", "aCyl2 = Geom_CylindricalSurface(neckAx2_Ax3, myNeckRadius * 1.05)\n", "\n", "# Set up the curves for the threads on the bottle's neck\n", "aPnt = gp_Pnt2d(2.0 * math.pi, myNeckHeight / 2.0)\n", "aDir = gp_Dir2d(2.0 * math.pi, myNeckHeight / 4.0)\n", "anAx2d = gp_Ax2d(aPnt, aDir)\n", "\n", "aMajor = 2.0 * math.pi\n", "aMinor = myNeckHeight / 10.0\n", "\n", "anEllipse1 = Geom2d_Ellipse(anAx2d, aMajor, aMinor)\n", "anEllipse2 = Geom2d_Ellipse(anAx2d, aMajor, aMinor / 4.0)\n", "\n", "anArc1 = Geom2d_TrimmedCurve(anEllipse1, 0, math.pi)\n", "anArc2 = Geom2d_TrimmedCurve(anEllipse2, 0, math.pi)\n", "\n", "anEllipsePnt1 = anEllipse1.Value(0)\n", "anEllipsePnt2 = anEllipse1.Value(math.pi)\n", "\n", "aSegment = GCE2d_MakeSegment(anEllipsePnt1, anEllipsePnt2)\n", "\n", "# Build edges and wires for threading\n", "anEdge1OnSurf1 = BRepBuilderAPI_MakeEdge(anArc1, aCyl1)\n", "anEdge2OnSurf1 = BRepBuilderAPI_MakeEdge(aSegment.Value(), aCyl1)\n", "anEdge1OnSurf2 = BRepBuilderAPI_MakeEdge(anArc2, aCyl2)\n", "anEdge2OnSurf2 = BRepBuilderAPI_MakeEdge(aSegment.Value(), aCyl2)\n", "\n", "threadingWire1 = BRepBuilderAPI_MakeWire(anEdge1OnSurf1.Edge(), anEdge2OnSurf1.Edge())\n", "threadingWire2 = BRepBuilderAPI_MakeWire(anEdge1OnSurf2.Edge(), anEdge2OnSurf2.Edge())\n", "\n", "# Compute the 3D representations of the edges/wires\n", "BRepLib.BuildCurves3d_s(threadingWire1.Shape())\n", "BRepLib.BuildCurves3d_s(threadingWire2.Shape())\n", "\n", "# Create the surfaces of the threading\n", "aTool = BRepOffsetAPI_ThruSections(True)\n", "aTool.AddWire(threadingWire1.Wire())\n", "aTool.AddWire(threadingWire2.Wire())\n", "aTool.CheckCompatibility(False)\n", "myThreading = aTool.Shape()\n", "\n", "# Build the resulting compound\n", "bottle = TopoDS_Compound()\n", "aBuilder = BRep_Builder()\n", "aBuilder.MakeCompound(bottle)\n", "aBuilder.Add(bottle, myBody_step3)\n", "aBuilder.Add(bottle, myThreading)\n", "print(\"bottle finished\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "show(bottle, colors=[\"aliceblue\"], ambient_intensity=0.6, direct_intensity=0.18)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "language_info": { "name": "python", "pygments_lexer": "ipython3" }, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" } }, "nbformat": 4, "nbformat_minor": 4 }