Merge pull request #106 from CadQuery/adam-urbanczyk-text-rendering
Support for text rendering
This commit is contained in:
		@ -2268,6 +2268,20 @@ class Workplane(CQ):
 | 
			
		||||
            r = baseSolid.fuse(obj)
 | 
			
		||||
 | 
			
		||||
        return self.newObject([r])
 | 
			
		||||
      
 | 
			
		||||
    def _cutFromBase(self, obj):
 | 
			
		||||
        """
 | 
			
		||||
        Cuts the provided object from the base solid, if one can be found.
 | 
			
		||||
        :param obj:
 | 
			
		||||
        :return: a new object that represents the result of combining the base object with obj,
 | 
			
		||||
           or obj if one could not be found
 | 
			
		||||
        """
 | 
			
		||||
        baseSolid = self.findSolid(searchParents=True)
 | 
			
		||||
        r = obj
 | 
			
		||||
        if baseSolid is not None:
 | 
			
		||||
            r = baseSolid.cut(obj)
 | 
			
		||||
 | 
			
		||||
        return self.newObject([r])
 | 
			
		||||
 | 
			
		||||
    def combine(self, clean=True):
 | 
			
		||||
        """
 | 
			
		||||
@ -2770,6 +2784,45 @@ class Workplane(CQ):
 | 
			
		||||
            raise AttributeError(
 | 
			
		||||
                "%s object doesn't support `clean()` method!" % obj.ShapeType())
 | 
			
		||||
        return self.newObject(cleanObjects)
 | 
			
		||||
      
 | 
			
		||||
    def text(self, txt, fontsize, distance, cut=True, combine=False, clean=True,
 | 
			
		||||
             font="Arial", kind='regular'):
 | 
			
		||||
        """
 | 
			
		||||
        Create a 3D text
 | 
			
		||||
 | 
			
		||||
        :param str txt: text to be rendered
 | 
			
		||||
        :param distance: the distance to extrude, normal to the workplane plane
 | 
			
		||||
        :type distance: float, negative means opposite the normal direction
 | 
			
		||||
        :param float fontsize: size of the font
 | 
			
		||||
        :param boolean cut: True to cut the resulting solid from the parent solids if found.
 | 
			
		||||
        :param boolean combine: True to combine the resulting solid with parent solids if found.
 | 
			
		||||
        :param boolean clean: call :py:meth:`clean` afterwards to have a clean shape
 | 
			
		||||
        :param str font: fontname (default: Arial)
 | 
			
		||||
        :param str kind: font type (default: Normal)
 | 
			
		||||
        :return: a CQ object with the resulting solid selected.
 | 
			
		||||
 | 
			
		||||
        extrude always *adds* material to a part.
 | 
			
		||||
 | 
			
		||||
        The returned object is always a CQ object, and depends on wither combine is True, and
 | 
			
		||||
        whether a context solid is already defined:
 | 
			
		||||
 | 
			
		||||
        *  if combine is False, the new value is pushed onto the stack.
 | 
			
		||||
        *  if combine is true, the value is combined with the context solid if it exists,
 | 
			
		||||
           and the resulting solid becomes the new context solid.
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        r = Compound.makeText(txt,fontsize,distance,font=font,kind=kind,
 | 
			
		||||
                              position=self.plane)
 | 
			
		||||
        
 | 
			
		||||
        if cut:
 | 
			
		||||
            newS = self._cutFromBase(r)
 | 
			
		||||
        elif combine:
 | 
			
		||||
            newS = self._combineWithBase(r)
 | 
			
		||||
        else:
 | 
			
		||||
            newS = self.newObject([r])
 | 
			
		||||
        if clean:
 | 
			
		||||
            newS = newS.clean()
 | 
			
		||||
        return newS
 | 
			
		||||
        
 | 
			
		||||
    def _repr_html_(self):
 | 
			
		||||
        """
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
from cadquery import Vector, BoundBox
 | 
			
		||||
from cadquery import Vector, BoundBox, Plane
 | 
			
		||||
 | 
			
		||||
import OCC.Core.TopAbs as ta  # Tolopolgy type enum
 | 
			
		||||
import OCC.Core.GeomAbs as ga  # Geometry type enum
 | 
			
		||||
@ -106,6 +106,11 @@ from OCC.LocOpe import LocOpe_DPrism
 | 
			
		||||
 | 
			
		||||
from OCC.BRepCheck import BRepCheck_Analyzer
 | 
			
		||||
 | 
			
		||||
from OCC.Core.Addons import (text_to_brep,
 | 
			
		||||
                             Font_FA_Regular,
 | 
			
		||||
                             Font_FA_Italic,
 | 
			
		||||
                             Font_FA_Bold)
 | 
			
		||||
 | 
			
		||||
from math import pi, sqrt
 | 
			
		||||
 | 
			
		||||
TOLERANCE = 1e-6
 | 
			
		||||
@ -1451,6 +1456,24 @@ class Compound(Shape, Mixin3D):
 | 
			
		||||
            comp_builder.Add(comp, s.wrapped)
 | 
			
		||||
 | 
			
		||||
        return cls(comp)
 | 
			
		||||
      
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def makeText(cls, text, size, height, font="Arial", kind='regular',
 | 
			
		||||
                 position=Plane.XY()):
 | 
			
		||||
        """
 | 
			
		||||
        Create a 3D text
 | 
			
		||||
        """
 | 
			
		||||
        
 | 
			
		||||
        font_kind = {'regular' : Font_FA_Regular,
 | 
			
		||||
                     'bold'    : Font_FA_Bold,
 | 
			
		||||
                     'italic'  : Font_FA_Italic}[kind]
 | 
			
		||||
        
 | 
			
		||||
        text_flat = Shape(text_to_brep(text, font, font_kind, size, False))
 | 
			
		||||
        vecNormal = text_flat.Faces()[0].normalAt()*height
 | 
			
		||||
        
 | 
			
		||||
        text_3d = BRepPrimAPI_MakePrism(text_flat.wrapped, vecNormal.wrapped)
 | 
			
		||||
        
 | 
			
		||||
        return cls(text_3d.Shape()).transformShape(position.rG)
 | 
			
		||||
 | 
			
		||||
# TODO this is likely not needed if sing PythonOCC.Core.correclty but we will see
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1800,3 +1800,27 @@ class TestCadQuery(BaseTest):
 | 
			
		||||
 | 
			
		||||
        # The obj1 shape shall have the same volume as the obj2 shape.
 | 
			
		||||
        self.assertAlmostEqual(obj1.val().Volume(), obj2.val().Volume())
 | 
			
		||||
        
 | 
			
		||||
    def testText(self):
 | 
			
		||||
      
 | 
			
		||||
        box = Workplane("XY" ).box(4, 4, 0.5)
 | 
			
		||||
        
 | 
			
		||||
        obj1 = box.faces('>Z').workplane().text('CQ 2.0',0.5,-.05,cut=True)
 | 
			
		||||
        
 | 
			
		||||
        #combined object should have smaller volume
 | 
			
		||||
        self.assertGreater(box.val().Volume(),obj1.val().Volume())
 | 
			
		||||
        
 | 
			
		||||
        obj2 = box.faces('>Z').workplane()\
 | 
			
		||||
            .text('CQ 2.0',0.5,.05,cut=False,combine=True)
 | 
			
		||||
        
 | 
			
		||||
        #combined object should have bigger volume
 | 
			
		||||
        self.assertLess(box.val().Volume(),obj2.val().Volume())
 | 
			
		||||
        
 | 
			
		||||
        #verify that the number of top faces is correct (NB: this is font specific)
 | 
			
		||||
        self.assertEqual(len(obj2.faces('>Z').vals()),5)
 | 
			
		||||
        
 | 
			
		||||
        obj3 = box.faces('>Z').workplane()\
 | 
			
		||||
            .text('CQ 2.0',0.5,.05,cut=False,combine=False)
 | 
			
		||||
            
 | 
			
		||||
        #verify that the number of solids is correct
 | 
			
		||||
        self.assertEqual(len(obj3.solids().vals()),5)
 | 
			
		||||
		Reference in New Issue
	
	Block a user