Danny.OOo.DrawLib.py

From Apache OpenOffice Wiki
Revision as of 19:58, 17 February 2015 by JZA (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

This module has routines to make programming OOo Drawing documents easier. Much of this code was derrived from Basic code, that also appears in Danny's Draw Power Tools found at OOoMacros.org.

This module depends upon the modules...

presented elsewhere in this thread.


#********************************************************************** 
# 
#   Danny.OOo.DrawLib.py 
# 
#   A module to easily work with OOo Drawings. 
# 
#********************************************************************** 
#   Copyright (c) 2003-2004 Danny Brewer 
#   d29583@groovegarden.com 
# 
#   This library is free software; you can redistribute it and/or 
#   modify it under the terms of the GNU Lesser General Public 
#   License as published by the Free Software Foundation; either 
#   version 2.1 of the License, or (at your option) any later version. 
# 
#   This library is distributed in the hope that it will be useful, 
#   but WITHOUT ANY WARRANTY; without even the implied warranty of 
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
#   Lesser General Public License for more details. 
# 
#   You should have received a copy of the GNU Lesser General Public 
#   License along with this library; if not, write to the Free Software 
#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
# 
#   See:  http://www.gnu.org/licenses/lgpl.html 
# 
#********************************************************************** 
#   If you make changes, please append to the change log below. 
# 
#   Change Log 
#   Danny Brewer         Revised 2004-05-24-01 
# 
#********************************************************************** 
 
 
 
# Python libraries 
import math 
import string 
 
# Danny's libraries 
from Danny import HSBConversions 
from Danny.OOo.OOoLib import * 
 
# OOo's libraries 
import uno 
 
 
 
#------------------------------------------------------------ 
#   Functions for working with Draw documents. 
#------------------------------------------------------------ 
 
 
 
def makeDrawDocument(): 
    """Create a new OOo Draw document.""" 
    return loadComponentFromURL( "private:factory/sdraw" ) 
 
def makeImpressDocument(): 
    """Create a new OOo Impress document.""" 
    return loadComponentFromURL( "private:factory/simpress" ) 
 
 
# Notes about some properties and constants for shape objects... 
 
    # LineStyle can be one of... 
    #   com.sun.star.drawing.LineStyle.NONE 
    #   com.sun.star.drawing.LineStyle.SOLID 
    #   com.sun.star.drawing.LineStyle.DASH 
 
    # CircleKind can be one of... 
    #   com.sun.star.drawing.CircleKind.FULL 
    #   com.sun.star.drawing.CircleKind.SECTION   ' a circle with a cut connected by two lines 
    #   com.sun.star.drawing.CircleKind.CUT ' a circle with a cut connected by a line 
    #   com.sun.star.drawing.CircleKind.ARC ' a circle with an open cut 
 
    # FillStyle can be one of... 
    #   com.sun.star.drawing.FillStyle.NONE 
    #   com.sun.star.drawing.FillStyle.SOLID 
    #   com.sun.star.drawing.FillStyle.GRADIENT 
    #   com.sun.star.drawing.FillStyle.HATCH 
    #   com.sun.star.drawing.FillStyle.BITMAP 
 
    # TextHorizontalAdjust can be one of... 
    #   com.sun.star.drawing.TextHorizontalAdjust.LEFT 
    #   com.sun.star.drawing.TextHorizontalAdjust.CENTER 
    #   com.sun.star.drawing.TextHorizontalAdjust.RIGHT 
    #   com.sun.star.drawing.TextHorizontalAdjust.BLOCK 
 
    # TextVerticalAdjust can be one of... 
    #   com.sun.star.drawing.TextVerticalAdjust.TOP 
    #   com.sun.star.drawing.TextVerticalAdjust.CENTER 
    #   com.sun.star.drawing.TextVerticalAdjust.BOTTOM 
    #   com.sun.star.drawing.TextVerticalAdjust.BLOCK 
 
    # TextFitToSize can be one of... 
    #    com.sun.star.drawing.TextFitToSizeType.NONE 
    #    com.sun.star.drawing.TextFitToSizeType.PROPORTIONAL 
    #    com.sun.star.drawing.TextFitToSizeType.ALLLINES 
    #    com.sun.star.drawing.TextFitToSizeType.RESIZEATTR 
 
# Useful code snippets... 
 
    # Accessing pages of a drawing document. 
    #   oDrawPage = oDrawDoc.getDrawPages().getByIndex( 0 ) 
    #   oDrawPage = oDrawDoc.getDrawPages().getCount() 
    #   oDrawPage = oDrawDoc.getDrawPages().insertByIndex( 1 ) 
 
 
 
#------------------------------------------------------------ 
#   Document functions 
#------------------------------------------------------------ 
 
 
def setDrawPageOrientationLandscape( oDrawPage ): 
    """Pass in any GenericDrawPage object, and this changes it to landscape orientation, 
     in addition to swapping the height/width as you would expect. 
    """ 
    # Save some settings 
    nOldWidth = oDrawPage.Width 
    nOldHeight = oDrawPage.Height 
    nOldBorderTop = oDrawPage.BorderTop 
    nOldBorderLeft = oDrawPage.BorderLeft 
    nOldBorderRight = oDrawPage.BorderRight 
    nOldBorderBottom = oDrawPage.BorderBottom 
 
    # Change so that it will PRINT in landscape 
    oDrawPage.Orientation = uno.getConstantByName( "com.sun.star.view.PaperOrientation.LANDSCAPE" ) 
 
    # Now change some paper dimensions to match 
    oDrawPage.Width = nOldHeight 
    oDrawPage.Height = nOldWidth 
    oDrawPage.BorderTop = nOldBorderRight 
    oDrawPage.BorderLeft = nOldBorderTop 
    oDrawPage.BorderRight = nOldBorderBottom 
    oDrawPage.BorderBottom = nOldBorderLeft 
 
 
 
#------------------------------------------------------------ 
#   Shape functions 
#------------------------------------------------------------ 
 
 
 
def makeRectangleShape( oDrawDoc, oPosition=None, oSize=None ): 
    """Create a new RectangleShape with an optional position and size.""" 
    oShape = makeShape( oDrawDoc, "com.sun.star.drawing.RectangleShape", oPosition, oSize ) 
    return oShape 
 
 
def makeEllipseShape( oDrawDoc, oPosition=None, oSize=None ): 
    """Create a new EllipseShape with an optional position and size.""" 
    oShape = makeShape( oDrawDoc, "com.sun.star.drawing.EllipseShape", oPosition, oSize ) 
    return oShape 
 
 
def makeLineShape( oDrawDoc, oPosition=None, oSize=None ): 
    """Create a new LineShape with an optional position and size.""" 
    oShape = makeShape( oDrawDoc, "com.sun.star.drawing.LineShape", oPosition, oSize ) 
    return oShape 
 
 
def makeTextShape( oDrawDoc, oPosition=None, oSize=None ): 
    """Create a new TextShape with an optional position and size.""" 
    oShape = makeShape( oDrawDoc, "com.sun.star.drawing.TextShape", oPosition, oSize ) 
    return oShape 
 
 
def findShapeByName( oShapes, cShapeName ): 
    """Find a named shape within an XShapes interface. 
    oShapes can be a drawing page, which supports the XShapes interface. 
    Thus, you can find a named shape within a draw page, or within a grouped shape, 
     or within a selection of sseveral shapes. 
    """ 
    nNumShapes = oShapes.getCount() 
    for i in range( nNumShapes ): 
        oShape = oShapes.getByIndex( i ) 
        cTheShapeName = oShape.getName() 
        if cTheShapeName == cShapeName: 
            return oShape 
    return None 
 
 
def makeShape( oDrawDoc, cShapeClassName, oPosition=None, oSize=None ): 
    """Create a new shape of the specified class. 
    Position and size arguments are optional. 
    """ 
    oShape = oDrawDoc.createInstance( cShapeClassName ) 
 
    if oPosition != None: 
        oShape.Position = oPosition 
    if oSize != None: 
        oShape.Size = oSize 
 
    return oShape 
 
 
 
#------------------------------------------------------------ 
#   Color manipulation 
#------------------------------------------------------------ 
 
 
def rgbColor( nRed, nGreen, nBlue ): 
    """Return an integer which repsents a color. 
    The color is specified in RGB notation. 
    Each of nRed, nGreen and nBlue must be a number from 0 to 255. 
    """ 
    return (int( nRed ) & 255) << 16 | (int( nGreen ) & 255) << 8 | (int( nBlue ) & 255) 
 
 
def hsbColor( nHue, nSaturation, nBrightness ): 
    """Return an integer which repsents a color. 
    The color is specified in HSB notation. 
    Each of nHue, nSaturation and nBrightness must be a number from 0.0 to 1.0. 
    """ 
    nRed, nGreen, nBlue = HSBConversions.HSBtoRGB( nHue, nSaturation, nBrightness ) 
    return rgbColor( nRed, nGreen, nBlue ) 
 
 
def redColor( nColor ): 
    """Return the Red component of a color as an integer from 0 to 255. 
    nColor is an integer representing a color. 
    This function is complimentary to the rgbColor function. 
    """ 
    return (int( nColor ) >> 16) & 255 
 
 
def greenColor( nColor ): 
    """Return the Green component of a color as an integer from 0 to 255. 
    nColor is an integer representing a color. 
    This function is complimentary to the rgbColor function. 
    """ 
    return (int( nColor ) >> 8) & 255 
 
 
def blueColor( nColor ): 
    """Return the Blue component of a color as an integer from 0 to 255. 
    nColor is an integer representing a color. 
    This function is complimentary to the rgbColor function. 
    """ 
    return int( nColor ) & 255 
 
 
 
 
 
#------------------------------------------------------------ 
#   Drawing routines 
#------------------------------------------------------------ 
 
 
# Multiply this number by an OOo angle in 100'ths of a degree 
#  to convert to radians. 
nRadiansPerHundredthDegree = math.pi / 18000 
 
 
def drawLine( oDrawDoc, oDrawPage, x1,y1, x2,y2, nLineColor=None ): 
    """Draw a line from x1,y1 to x2,y2.  Optionally specify line color. 
    This adds the LineShape to the page. 
    The LineShape is returned. 
    """ 
    # make sure size is non-zero 
    #if x1 = x2: x2 = x1 + 1 
    #if y1 = y2: y2 = y1 + 1 
 
    oPosition = makePoint( x1, y1 ) 
    oSize = makeSize( x2-x1, y2-y1 ) 
 
    oShape = makeLineShape( oDrawDoc, oPosition, oSize ) 
 
    if nLineColor != None: 
        oShape.LineColor = nLineColor 
    #oShape.LineWidth = 0 
 
    oDrawPage.add( oShape ) 
    return oShape 
 
 
def drawLineVector( oDrawDoc, oDrawPage, x1,y1, nAngle,nDistance, nLineColor=None ): 
    """Draw a line from x1,y1 in the direction of nAngle, for a distance of nDistance. 
    nAngle is measured in radians, clockwise from the 3 O'Clock (east) direction. 
    nDistance is in 1000ths of a centimeter. 
    This adds the LineShape to the page. 
    The LineShape is returned. 
    """ 
    nDX = math.cos( nAngle ) * nDistance 
    nDY = math.sin( nAngle ) * nDistance 
 
    return drawLine( oDrawDoc, oDrawPage, x1,y1, x1+nDX,y1+nDY, nLineColor ) 
 
 
def drawAutoSizingText( oDrawDoc, oDrawPage, 
                        cText, nHeight, nExtraWidthPercent=40 ): 
    """Create a TextShape that will automatically resize its characters 
     to its shape bounding rectangle. 
    The TextShape is created with a specified height. 
    The width is determined based on the natural character width of the 
     text. 
    The initial position of the text is -10000,-10000, so that the text is not visible. 
    This returns the TextShape, which has already been added to the drawing page, 
     at coordinates which make it invisible. 
    You must set the object's Position property to make the text visible. 
    (Hint: You may look at the Size property to help you determine where 
     you want to place the text, for instance if you are trying to center 
     it, or place it relative to some other shape object.) 
    If you don't supply nExtraWidthPercent, then a default fudge factor is used. 
    This is the percentage of the average character width, which is added to the shape's 
     total width. 
    """ 
    # Create TextShape 
    oShape = makeTextShape( oDrawDoc, makePoint( -10000, -10000 ), makeSize( 1, 1 ) ) 
 
    # Add it to the page. 
    oDrawPage.add( oShape ) 
 
    # Make text stick to upper left corner of the shape rather than centered within the shape. 
    oShape.TextHorizontalAdjust = uno.getConstantByName( "com.sun.star.drawing.TextHorizontalAdjust.LEFT" ) 
    oShape.TextVerticalAdjust = uno.getConstantByName( "com.sun.star.drawing.TextVerticalAdjust.TOP" ) 
 
    # Make the shape auto-grow in size, based on the text. 
    # Once we set the text, in the next step, the shape will grow to some 
    #  unknown size, based on the current font in use. 
    #oShape.TextAutoGrowHeight = True 
    oShape.TextAutoGrowWidth = True 
 
    # Set the text of the TextShape. 
    # Because of the TextAutoGrowWidth, the shape now occupies some unknown size. 
    oShape.setString( cText ) 
 
    # Get the shape's current size. 
    nSaveHeight = oShape.Size.Height 
    nSaveWidth = oShape.Size.Width 
 
    # Make the shape NOT auto-grow in size, based on the text. 
    #oShape.TextAutoGrowHeight = False 
    oShape.TextAutoGrowWidth = False 
 
    # This next setting causes the TextShape to automatically resize its characters 
    #  to fit the size of the text shape. 
    oShape.TextFitToSize = uno.getConstantByName( "com.sun.star.drawing.TextFitToSizeType.PROPORTIONAL" ) 
 
    # Calculate the new width, based on the desired height, 
    #  and saved width/height ratio for the current font in use. 
    nWidth = nSaveWidth * (float(nHeight) / nSaveHeight) 
 
    nAverageCharacterWidth = nWidth / len( cText ) 
 
    nExtraWidth = nAverageCharacterWidth * (nExtraWidthPercent / 100.0) 
 
    oShape.TextLeftDistance = nExtraWidth 
    oShape.TextRightDistance = nExtraWidth 
    nWidth = nWidth + 2 * nExtraWidth 
 
    # Now resize the TextShape. 
    oShape.Size.Width = nWidth 
    oShape.Size.Height = nHeight 
 
    return oShape 
 
 
def drawArcPath( oDrawDoc, oDrawPage, 
                 nStartX, nStartY, nStartAngle, 
                 nArcAngle, nArcRadius, bTurnLeft ): 
    """Draw an arc of a circle from a starting position and direction. 
    The arc has a certian radius and arc angle, 
     and turns either to the left or to the right. 
    Parameters: 
    nStartX and nStartY are the starting position of the "turtle". 
    nStartAngle is the angle direction that the turtle is pointing, 
     in 100'ths of a degree. 
    An arc is drawn by moving the turtle forward and turning either left or right as it moves. 
    nArcAngle is the angle of the arc describing the turtle's path, 
     in 100'ths of a degree. 
    nArcRadius is the radius of the arc describing the turtle's path. 
    bTurnLeft is True if the turtle turns to the left, or False to turn to the right. 
    Four values are returned. 
    (1) the circle shape, (2) the new X position, (3) new Y position, and (4) new angle. 
    Use the last three return values as initial values to draw another arc 
     which is connected to the ending position of the arc just drawn. 
    """ 
 
    # Figure out how big of a circle that the arc is a part of. 
    nCircleDiameter = nArcRadius + nArcRadius 
    oCircleSize = makeSize( nCircleDiameter, nCircleDiameter ) 
 
    # Figure out the position of the circle (ellipse) shape object. 
    # 
    # Determine the angle of the center point from the starting position. 
    if bTurnLeft: 
        nCenterPointAngle = nStartAngle + 9000 
    else: 
        nCenterPointAngle = nStartAngle - 9000 
    # Convert to radians. 
    nCenterPointAngle = nCenterPointAngle * nRadiansPerHundredthDegree 
    # Determine where the center of the circle shape should be. 
    nCenterX = nStartX + (nArcRadius * math.cos( nCenterPointAngle )) 
    nCenterY = nStartY - (nArcRadius * math.sin( nCenterPointAngle )) 
    oCirclePosition = makePoint( nCenterX - nArcRadius, nCenterY - nArcRadius ) 
 
    # Figure out what arc portion of the circle needs to be drawn. 
    # Angles measures in 100'ths of a degree. 
    if bTurnLeft: 
        nCircleStartAngle = nStartAngle - 9000 
        nCircleEndAngle = nCircleStartAngle + nArcAngle 
    else: 
        nCircleEndAngle = nStartAngle + 9000 
        nCircleStartAngle = nCircleEndAngle - nArcAngle 
 
    # Make the circle shape. 
    oCircle = makeEllipseShape( oDrawDoc, oCirclePosition, oCircleSize ) 
    # Fill in its properties 
    oCircle.FillStyle = uno.getConstantByName( "com.sun.star.drawing.FillStyle.NONE" ) 
    oCircle.CircleKind = uno.getConstantByName( "com.sun.star.drawing.CircleKind.ARC" ) 
    oCircle.CircleStartAngle = nCircleStartAngle 
    oCircle.CircleEndAngle = nCircleEndAngle 
    # Put it on the drawing 
    oDrawPage.add( oCircle ) 
 
    # Figure out the ending turtle location and direction. 
    if bTurnLeft: 
        nEndAngle = nStartAngle - 9000 + nArcAngle 
    else: 
        nEndAngle = nStartAngle + 9000 - nArcAngle 
    # Convert to radians 
    nEndAngleRad = nEndAngle * nRadiansPerHundredthDegree 
    # Ending Position 
    nEndX = nCenterX + (nArcRadius * math.cos( nEndAngleRad )) 
    nEndY = nCenterY - (nArcRadius * math.sin( nEndAngleRad )) 
    # Ending angle 
    if bTurnLeft: 
        nEndAngle = normalizeOOoAngle( nEndAngle + 9000 ) 
    else: 
        nEndAngle = normalizeOOoAngle( nEndAngle - 9000 ) 
 
    return oCircle, nEndX, nEndY, nEndAngle 
 
 
def drawSpiralOfArcs( oDrawDoc, oDrawPage, 
                      nStartX, nStartY, nStartAngle, 
                      nArcAngle, nArcRadius, bTurnLeft, 
                      nNumArcs, 
                      nRadiusGrowthMultiplier=1.0, nRadiusGrowthAddIn=0 ): 
    """Draw a spiral starting from a certian position and direction. 
    The spiral turns either towards the left or towards the right. 
    Parameters: 
    nStartX and nStartY are the starting position of the "turtle". 
    nStartAngle is the angle direction that the turtle is pointing, 
     in 100'ths of a degree. 
    A spiral is drawn by moving the turtle forward and turning either left or right as it moves. 
    nArcAngle is the angle of the first arc of the spiral, 
     in 100'ths of a degree. 
    nArcRadius is the radius of the first arc of the spiral. 
    bTurnLeft is True if the turtle turns to the left, or False to turn to the right. 
    nNumArcs is the number of arcs which are drawn. 
    nRadiusGrowthMultiplier - the radius of the arc is multiplied by this after each arc is drawn. 
     Use a number such as 1.1 to cause the radius to grow geometrically as the spiral turns. 
    nRadiusGrowthAddIn - this is added to the radius after each arc. 
     Use a number, such as the original nArcRadius / number of arcs in a complete circle to cause the radius to grow arithmeteically as the spiral turns. 
    Four values are returned. 
    (1) the spiral shape, (2) the new X position, (3) new Y position, and (4) new angle. 
    Use the last three return values as initial values to draw another arc 
     which is connected to the ending position of the arc just drawn. 
    """ 
    nX = nStartX 
    nY = nStartY 
    nAngle = nStartAngle 
 
    oShapesToGroup = createUnoService( "com.sun.star.drawing.ShapeCollection" ) 
    for i in range( nNumArcs - 1 ): 
        oArcShape, nX, nY, nAngle = drawArcPath( oDrawDoc, oDrawPage, nX, nY, nAngle, nArcAngle, nArcRadius, bTurnLeft ) 
        nArcRadius = nArcRadius * nRadiusGrowthMultiplier + nRadiusGrowthAddIn 
 
        oShapesToGroup.add( oArcShape ) 
    oSpiralShape = oDrawPage.group( oShapesToGroup ) 
    return oSpiralShape, nX, nY, nAngle 
 
 
 
#------------------------------------------------------------ 
#   Styles 
#------------------------------------------------------------ 
 
 
def defineGraphicsStyle( oDrawDoc, cStyleName, cParentStyleName=None ): 
    """Add a new style to the style catalog if it is not already present. 
    This returns the style object so that you can alter its properties. 
    """ 
    return defineStyle( oDrawDoc, "graphics", cStyleName, cParentStyleName ) 
 
 
def getGraphicsStyle( oDrawDoc, cStyleName ): 
    """Lookup and return a graphics style from the document. 
    """ 
    return getStyle( oDrawDoc, "graphics", cStyleName ) 
 
 
 
 
 
#------------------------------------------------------------ 
#   General Utility functions 
#------------------------------------------------------------ 
 
def normalizeOOoAngle( nAngleOOo ): 
    """Given an angle in 100'ths of a degree, 
    adjust it to be from 0 to 360 degrees.""" 
    if nAngleOOo < 0: 
        nSign = -1 
    else: 
        nSign = 1 
    nAngleOOo = nAngleOOo - (int( abs( nAngleOOo ) / 36000.0 ) * 36000 * nSign) 
    if nAngleOOo < 0: 
        nAngleOOo += 36000 
    return nAngleOOo
Personal tools