示例#1
0
    def _calcTransforms(self):
        """Computes transformation matrices to convert between coordinates

        Computes transformation matrices to convert between local and global
        coordinates.
        """
        # r is the forward transformation matrix from world to local coordinates
        # ok i will be really honest, i cannot understand exactly why this works
        # something bout the order of the translation and the rotation.
        # the double-inverting is strange, and I don't understand it.
        forward = Matrix()
        inverse = Matrix()

        forwardT = gp_Trsf()
        inverseT = gp_Trsf()

        global_coord_system = gp_Ax3()
        local_coord_system = gp_Ax3(
            gp_Pnt(*self.origin.toTuple()),
            gp_Dir(*self.zDir.toTuple()),
            gp_Dir(*self.xDir.toTuple()),
        )

        forwardT.SetTransformation(global_coord_system, local_coord_system)
        forward.wrapped = gp_GTrsf(forwardT)

        inverseT.SetTransformation(local_coord_system, global_coord_system)
        inverse.wrapped = gp_GTrsf(inverseT)

        self.lcs = local_coord_system
        self.rG = inverse
        self.fG = forward
    def tessellate(self):
        self.vertices = []
        self.triangles = []
        self.normals = []

        # global buffers
        p_buf = gp_Pnt()
        n_buf = gp_Vec()
        loc_buf = TopLoc_Location()

        offset = -1

        # every line below is selected for performance. Do not introduce functions to "beautify" the code

        for face in get_faces(self.shape):
            if face.Orientation() == TopAbs_Orientation.TopAbs_REVERSED:
                i1, i2 = 2, 1
            else:
                i1, i2 = 1, 2

            internal = face.Orientation() == TopAbs_Orientation.TopAbs_INTERNAL

            poly = BRep_Tool.Triangulation_s(face, loc_buf)
            if poly is not None:
                Trsf = loc_buf.Transformation()

                # add vertices
                flat = []
                for i in range(1, poly.NbNodes() + 1):
                    flat.extend(poly.Node(i).Transformed(Trsf).Coord())
                self.vertices.extend(flat)

                # add triangles
                flat = []
                for i in range(1, poly.NbTriangles() + 1):
                    coord = poly.Triangle(i).Get()
                    flat.extend((coord[0] + offset, coord[i1] + offset,
                                 coord[i2] + offset))
                self.triangles.extend(flat)

                # add normals
                if poly.HasUVNodes():
                    prop = BRepGProp_Face(face)
                    flat = []
                    for i in range(1, poly.NbNodes() + 1):
                        u, v = poly.UVNode(i).Coord()
                        prop.Normal(u, v, p_buf, n_buf)
                        if n_buf.SquareMagnitude() > 0:
                            n_buf.Normalize()
                        flat.extend(n_buf.Reverse().Coord(
                        ) if internal else n_buf.Coord())
                    self.normals.extend(flat)

                offset += poly.NbNodes()
示例#3
0
    def rotated(self, rotate=(0, 0, 0)):
        """Returns a copy of this plane, rotated about the specified axes

        Since the z axis is always normal the plane, rotating around Z will
        always produce a plane that is parallel to this one.

        The origin of the workplane is unaffected by the rotation.

        Rotations are done in order x, y, z. If you need a different order,
        manually chain together multiple rotate() commands.

        :param rotate: Vector [xDegrees, yDegrees, zDegrees]
        :return: a copy of this plane rotated as requested.
        """
        # NB: this is not a geometric Vector
        rotate = Vector(rotate)
        # Convert to radians.
        rotate = rotate.multiply(math.pi / 180.0)

        # Compute rotation matrix.
        T1 = gp_Trsf()
        T1.SetRotation(
            gp_Ax1(gp_Pnt(*(0, 0, 0)), gp_Dir(*self.xDir.toTuple())), rotate.x)
        T2 = gp_Trsf()
        T2.SetRotation(
            gp_Ax1(gp_Pnt(*(0, 0, 0)), gp_Dir(*self.yDir.toTuple())), rotate.y)
        T3 = gp_Trsf()
        T3.SetRotation(
            gp_Ax1(gp_Pnt(*(0, 0, 0)), gp_Dir(*self.zDir.toTuple())), rotate.z)
        T = Matrix(gp_GTrsf(T1 * T2 * T3))

        # Compute the new plane.
        newXdir = self.xDir.transform(T)
        newZdir = self.zDir.transform(T)

        return Plane(self.origin, newXdir, newZdir)
示例#4
0
def _dxf_spline(el):

    try:
        degree = el.dxf.degree
        periodic = el.closed
        rational = False

        knots_unique = OrderedDict()
        for k in el.knots:
            if k in knots_unique:
                knots_unique[k] += 1
            else:
                knots_unique[k] = 1

        # assmble knots
        knots = TColStd_Array1OfReal(1, len(knots_unique))
        multiplicities = TColStd_Array1OfInteger(1, len(knots_unique))
        for i, (k, m) in enumerate(knots_unique.items()):
            knots.SetValue(i + 1, k)
            multiplicities.SetValue(i + 1, m)

        # assemble weights if present:
        if el.weights:
            rational = True

            weights = TColStd_Array1OfReal(1, len(el.weights))
            for i, w in enumerate(el.weights):
                weights.SetValue(i + 1, w)

        # assemble control points
        pts = TColgp_Array1OfPnt(1, len(el.control_points))
        for i, p in enumerate(el.control_points):
            pts.SetValue(i + 1, gp_Pnt(*p))

        if rational:
            spline = Geom_BSplineCurve(pts, weights, knots, multiplicities,
                                       degree, periodic)
        else:
            spline = Geom_BSplineCurve(pts, knots, multiplicities, degree,
                                       periodic)

        return (Edge(BRepBuilderAPI_MakeEdge(spline).Edge()), )

    except Exception:
        return ()
示例#5
0
    def addLines(self):

        origin = (0, 0, 0)
        ais_list = []

        for name, color, direction in zip(('X', 'Y', 'Z'),
                                          ('red', 'lawngreen', 'blue'),
                                          ((1, 0, 0), (0, 1, 0), (0, 0, 1))):
            line_placement = Geom_Line(
                gp_Ax1(gp_Pnt(*origin), gp_Dir(*direction)))
            line = AIS_Line(line_placement)
            line.SetColor(to_occ_color(color))

            self.Helpers.addChild(ObjectTreeItem(name, ais=line))

            ais_list.append(line)

        self.sigObjectsAdded.emit(ais_list)
示例#6
0
 def testVertices(self):
     e = Shape.cast(
         BRepBuilderAPI_MakeEdge(gp_Pnt(0, 0, 0), gp_Pnt(1, 1, 0)).Edge())
     self.assertEqual(2, len(e.Vertices()))
示例#7
0
    def _make_ellipse(self):

        ellipse = gp_Elips(gp_Ax2(gp_Pnt(1, 2, 3), gp.DZ_s()), 4.0, 2.0)
        return Shape.cast(BRepBuilderAPI_MakeEdge(ellipse).Edge())
示例#8
0
    def _make_circle(self):

        circle = gp_Circ(gp_Ax2(gp_Pnt(1, 2, 3), gp.DZ_s()), 2.0)
        return Shape.cast(BRepBuilderAPI_MakeEdge(circle).Edge())
示例#9
0
    def toPnt(self) -> gp_Pnt:

        return gp_Pnt(self.wrapped.XYZ())
示例#10
0
    def tessellate(self):
        self.vertices = array("f")
        self.triangles = array("f")
        self.normals = array("f")

        # global buffers
        p_buf = gp_Pnt()
        n_buf = gp_Vec()
        loc_buf = TopLoc_Location()

        offset = -1

        # every line below is selected for performance. Do not introduce functions to "beautify" the code

        for face in get_faces(self.shape):
            if face.Orientation() == TopAbs_Orientation.TopAbs_REVERSED:
                i1, i2 = 2, 1
            else:
                i1, i2 = 1, 2

            internal = face.Orientation() == TopAbs_Orientation.TopAbs_INTERNAL

            poly = BRep_Tool.Triangulation_s(face, loc_buf)
            if poly is not None:
                Trsf = loc_buf.Transformation()

                # add vertices
                # [node.Transformed(Trsf).Coord() for node in poly.Nodes()] is 5-8 times slower!
                items = poly.Nodes()
                coords = [items.Value(i).Transformed(Trsf).Coord() for i in range(items.Lower(), items.Upper() + 1)]
                flat = []
                for coord in coords:
                    flat += coord
                self.vertices.extend(flat)

                # add triangles
                items = poly.Triangles()
                coords = [items.Value(i).Get() for i in range(items.Lower(), items.Upper() + 1)]
                flat = []
                for coord in coords:
                    flat += (coord[0] + offset, coord[i1] + offset, coord[i2] + offset)
                self.triangles.extend(flat)

                # add normals
                if poly.HasUVNodes():

                    def extract(uv0, uv1):
                        prop.Normal(uv0, uv1, p_buf, n_buf)
                        if n_buf.SquareMagnitude() > 0:
                            n_buf.Normalize()
                        return n_buf.Reverse().Coord() if internal else n_buf.Coord()

                    prop = BRepGProp_Face(face)
                    items = poly.UVNodes()

                    uvs = [items.Value(i).Coord() for i in range(items.Lower(), items.Upper() + 1)]
                    flat = []
                    for uv1, uv2 in uvs:
                        flat += extract(uv1, uv2)
                    self.normals.extend(flat)

                offset += poly.NbNodes()
示例#11
0
    def show_axis(self,origin = (0,0,0), direction=(0,0,1)):

        ax_placement = Geom_Axis1Placement(gp_Ax1(gp_Pnt(*origin),
                                                  gp_Dir(*direction)))
        ax = AIS_Axis(ax_placement)
        self._display_ais(ax)
示例#12
0
def tessellate(shape, tolerance: float, angularTolerance: float = 0.1):

    # Remove previous mesh data
    BRepTools.Clean_s(shape)

    triangulated = BRepTools.Triangulation_s(shape, tolerance)
    if not triangulated:
        # this will add mesh data to the shape and prevent calculating an exact bounding box after this call
        BRepMesh_IncrementalMesh(shape, tolerance, True, angularTolerance)

    vertices = []
    triangles = []
    normals = []

    offset = 0

    for face in get_faces(shape):
        loc = TopLoc_Location()
        poly = BRep_Tool.Triangulation_s(face, loc)
        Trsf = loc.Transformation()

        reverse = face.Orientation() == TopAbs_Orientation.TopAbs_REVERSED
        internal = face.Orientation() == TopAbs_Orientation.TopAbs_INTERNAL

        # add vertices
        if poly is not None:
            vertices += [(v.X(), v.Y(), v.Z())
                         for v in (v.Transformed(Trsf) for v in poly.Nodes())]

            # add triangles
            triangles += [(
                t.Value(1) + offset - 1,
                t.Value(3 if reverse else 2) + offset - 1,
                t.Value(2 if reverse else 3) + offset - 1,
            ) for t in poly.Triangles()]

            # add normals
            if poly.HasUVNodes():
                prop = BRepGProp_Face(face)
                uvnodes = poly.UVNodes()
                for uvnode in uvnodes:
                    p = gp_Pnt()
                    n = gp_Vec()
                    prop.Normal(uvnode.X(), uvnode.Y(), p, n)

                    if n.SquareMagnitude() > 0:
                        n.Normalize()
                    if internal:
                        n.Reverse()

                    normals.append((n.X(), n.Y(), n.Z()))

            offset += poly.NbNodes()

    if not triangulated:
        # Remove the mesh data again
        BRepTools.Clean_s(shape)

    return (
        np.asarray(vertices, dtype=np.float32),
        np.asarray(triangles, dtype=np.uint32),
        np.asarray(normals, dtype=np.float32),
    )
示例#13
0
def getSVG(shape, opts=None):
    """
        Export a shape to SVG
    """

    d = {"width": 800, "height": 240, "marginLeft": 200, "marginTop": 20}

    if opts:
        d.update(opts)

    # need to guess the scale and the coordinate center
    uom = guessUnitOfMeasure(shape)

    width = float(d["width"])
    height = float(d["height"])
    marginLeft = float(d["marginLeft"])
    marginTop = float(d["marginTop"])

    hlr = HLRBRep_Algo()
    hlr.Add(shape.wrapped)

    projector = HLRAlgo_Projector(gp_Ax2(gp_Pnt(), DEFAULT_DIR))

    hlr.Projector(projector)
    hlr.Update()
    hlr.Hide()

    hlr_shapes = HLRBRep_HLRToShape(hlr)

    visible = []

    visible_sharp_edges = hlr_shapes.VCompound()
    if not visible_sharp_edges.IsNull():
        visible.append(visible_sharp_edges)

    visible_smooth_edges = hlr_shapes.Rg1LineVCompound()
    if not visible_smooth_edges.IsNull():
        visible.append(visible_smooth_edges)

    visible_contour_edges = hlr_shapes.OutLineVCompound()
    if not visible_contour_edges.IsNull():
        visible.append(visible_contour_edges)

    hidden = []

    hidden_sharp_edges = hlr_shapes.HCompound()
    if not hidden_sharp_edges.IsNull():
        hidden.append(hidden_sharp_edges)

    hidden_contour_edges = hlr_shapes.OutLineHCompound()
    if not hidden_contour_edges.IsNull():
        hidden.append(hidden_contour_edges)

    # Fix the underlying geometry - otherwise we will get segfaults
    for el in visible:
        BRepLib.BuildCurves3d_s(el, TOLERANCE)
    for el in hidden:
        BRepLib.BuildCurves3d_s(el, TOLERANCE)

    # convert to native CQ objects
    visible = list(map(Shape, visible))
    hidden = list(map(Shape, hidden))
    (hiddenPaths, visiblePaths) = getPaths(visible, hidden)

    # get bounding box -- these are all in 2-d space
    bb = Compound.makeCompound(hidden + visible).BoundingBox()

    # width pixels for x, height pixesl for y
    unitScale = min(width / bb.xlen * 0.75, height / bb.ylen * 0.75)

    # compute amount to translate-- move the top left into view
    (xTranslate, yTranslate) = (
        (0 - bb.xmin) + marginLeft / unitScale,
        (0 - bb.ymax) - marginTop / unitScale,
    )

    # compute paths ( again -- had to strip out freecad crap )
    hiddenContent = ""
    for p in hiddenPaths:
        hiddenContent += PATHTEMPLATE % p

    visibleContent = ""
    for p in visiblePaths:
        visibleContent += PATHTEMPLATE % p

    svg = SVG_TEMPLATE % ({
        "unitScale": str(unitScale),
        "strokeWidth": str(1.0 / unitScale),
        "hiddenContent": hiddenContent,
        "visibleContent": visibleContent,
        "xTranslate": str(xTranslate),
        "yTranslate": str(yTranslate),
        "width": str(width),
        "height": str(height),
        "textboxY": str(height - 30),
        "uom": str(uom),
    })
    # svg = SVG_TEMPLATE % (
    #    {"content": projectedContent}
    # )
    return svg
示例#14
0
    def show_line(self,origin = (0,0,0), direction=(0,0,1)):

        line_placement = Geom_Line(gp_Ax1(gp_Pnt(*origin),
                                   gp_Dir(*direction)))
        line = AIS_Line(line_placement)
        self._display_ais(line)
示例#15
0
def getSVG(shape, opts=None):
    """
    Export a shape to SVG text.

    :param shape: A CadQuery shape object to convert to an SVG string.
    :type Shape: Vertex, Edge, Wire, Face, Shell, Solid, or Compound.
    :param opts: An options dictionary that influences the SVG that is output.
    :type opts: Dictionary, keys are as follows:
        width: Document width of the resulting image.
        height: Document height of the resulting image.
        marginLeft: Inset margin from the left side of the document.
        marginTop: Inset margin from the top side of the document.
        projectionDir: Direction the camera will view the shape from.
        showAxes: Whether or not to show the axes indicator, which will only be
                  visible when the projectionDir is also at the default.
        strokeWidth: Width of the line that visible edges are drawn with.
        strokeColor: Color of the line that visible edges are drawn with.
        hiddenColor: Color of the line that hidden edges are drawn with.
        showHidden: Whether or not to show hidden lines.
    """

    # Available options and their defaults
    d = {
        "width": 800,
        "height": 240,
        "marginLeft": 200,
        "marginTop": 20,
        "projectionDir": (-1.75, 1.1, 5),
        "showAxes": True,
        "strokeWidth": -1.0,  # -1 = calculated based on unitScale
        "strokeColor": (0, 0, 0),  # RGB 0-255
        "hiddenColor": (160, 160, 160),  # RGB 0-255
        "showHidden": True,
    }

    if opts:
        d.update(opts)

    # need to guess the scale and the coordinate center
    uom = guessUnitOfMeasure(shape)

    width = float(d["width"])
    height = float(d["height"])
    marginLeft = float(d["marginLeft"])
    marginTop = float(d["marginTop"])
    projectionDir = tuple(d["projectionDir"])
    showAxes = bool(d["showAxes"])
    strokeWidth = float(d["strokeWidth"])
    strokeColor = tuple(d["strokeColor"])
    hiddenColor = tuple(d["hiddenColor"])
    showHidden = bool(d["showHidden"])

    hlr = HLRBRep_Algo()
    hlr.Add(shape.wrapped)

    projector = HLRAlgo_Projector(gp_Ax2(gp_Pnt(), gp_Dir(*projectionDir)))

    hlr.Projector(projector)
    hlr.Update()
    hlr.Hide()

    hlr_shapes = HLRBRep_HLRToShape(hlr)

    visible = []

    visible_sharp_edges = hlr_shapes.VCompound()
    if not visible_sharp_edges.IsNull():
        visible.append(visible_sharp_edges)

    visible_smooth_edges = hlr_shapes.Rg1LineVCompound()
    if not visible_smooth_edges.IsNull():
        visible.append(visible_smooth_edges)

    visible_contour_edges = hlr_shapes.OutLineVCompound()
    if not visible_contour_edges.IsNull():
        visible.append(visible_contour_edges)

    hidden = []

    hidden_sharp_edges = hlr_shapes.HCompound()
    if not hidden_sharp_edges.IsNull():
        hidden.append(hidden_sharp_edges)

    hidden_contour_edges = hlr_shapes.OutLineHCompound()
    if not hidden_contour_edges.IsNull():
        hidden.append(hidden_contour_edges)

    # Fix the underlying geometry - otherwise we will get segfaults
    for el in visible:
        BRepLib.BuildCurves3d_s(el, TOLERANCE)
    for el in hidden:
        BRepLib.BuildCurves3d_s(el, TOLERANCE)

    # convert to native CQ objects
    visible = list(map(Shape, visible))
    hidden = list(map(Shape, hidden))
    (hiddenPaths, visiblePaths) = getPaths(visible, hidden)

    # get bounding box -- these are all in 2D space
    bb = Compound.makeCompound(hidden + visible).BoundingBox()

    # width pixels for x, height pixels for y
    unitScale = min(width / bb.xlen * 0.75, height / bb.ylen * 0.75)

    # compute amount to translate-- move the top left into view
    (xTranslate, yTranslate) = (
        (0 - bb.xmin) + marginLeft / unitScale,
        (0 - bb.ymax) - marginTop / unitScale,
    )

    # If the user did not specify a stroke width, calculate it based on the unit scale
    if strokeWidth == -1.0:
        strokeWidth = 1.0 / unitScale

    # compute paths
    hiddenContent = ""

    # Prevent hidden paths from being added if the user disabled them
    if showHidden:
        for p in hiddenPaths:
            hiddenContent += PATHTEMPLATE % p

    visibleContent = ""
    for p in visiblePaths:
        visibleContent += PATHTEMPLATE % p

    # If the caller wants the axes indicator and is using the default direction, add in the indicator
    if showAxes and projectionDir == (-1.75, 1.1, 5):
        axesIndicator = AXES_TEMPLATE % ({
            "unitScale": str(unitScale),
            "textboxY": str(height - 30),
            "uom": str(uom)
        })
    else:
        axesIndicator = ""

    svg = SVG_TEMPLATE % (
        {
            "unitScale": str(unitScale),
            "strokeWidth": str(strokeWidth),
            "strokeColor": ",".join([str(x) for x in strokeColor]),
            "hiddenColor": ",".join([str(x) for x in hiddenColor]),
            "hiddenContent": hiddenContent,
            "visibleContent": visibleContent,
            "xTranslate": str(xTranslate),
            "yTranslate": str(yTranslate),
            "width": str(width),
            "height": str(height),
            "textboxY": str(height - 30),
            "uom": str(uom),
            "axesIndicator": axesIndicator,
        })

    return svg