]> git.saurik.com Git - wxWidgets.git/blobdiff - wxPython/wx/lib/ogl/_oglmisc.py
Since everything in the submodules is to appear in the pacakge
[wxWidgets.git] / wxPython / wx / lib / ogl / _oglmisc.py
diff --git a/wxPython/wx/lib/ogl/_oglmisc.py b/wxPython/wx/lib/ogl/_oglmisc.py
new file mode 100644 (file)
index 0000000..42a79b2
--- /dev/null
@@ -0,0 +1,416 @@
+# -*- coding: iso-8859-1 -*-
+#----------------------------------------------------------------------------
+# Name:         oglmisc.py
+# Purpose:      Miscellaneous OGL support functions
+#
+# Author:       Pierre Hjälm (from C++ original by Julian Smart)
+#
+# Created:      2004-05-08
+# RCS-ID:       $Id$
+# Copyright:    (c) 2004 Pierre Hjälm - 1998 Julian Smart
+# Licence:      wxWindows license
+#----------------------------------------------------------------------------
+
+from __future__ import division
+import math
+
+import wx
+
+# Control point types
+# Rectangle and most other shapes
+CONTROL_POINT_VERTICAL = 1
+CONTROL_POINT_HORIZONTAL = 2
+CONTROL_POINT_DIAGONAL = 3
+
+# Line
+CONTROL_POINT_ENDPOINT_TO = 4
+CONTROL_POINT_ENDPOINT_FROM = 5
+CONTROL_POINT_LINE = 6
+
+# Types of formatting: can be combined in a bit list
+FORMAT_NONE = 0             # Left justification
+FORMAT_CENTRE_HORIZ = 1     # Centre horizontally
+FORMAT_CENTRE_VERT = 2      # Centre vertically
+FORMAT_SIZE_TO_CONTENTS = 4 # Resize shape to contents
+
+# Attachment modes
+ATTACHMENT_MODE_NONE, ATTACHMENT_MODE_EDGE, ATTACHMENT_MODE_BRANCHING = 0, 1, 2
+
+# Shadow mode
+SHADOW_NONE, SHADOW_LEFT, SHADOW_RIGHT = 0, 1, 2
+
+OP_CLICK_LEFT, OP_CLICK_RIGHT, OP_DRAG_LEFT, OP_DRAG_RIGHT = 1, 2, 4, 8
+OP_ALL = OP_CLICK_LEFT | OP_CLICK_RIGHT | OP_DRAG_LEFT | OP_DRAG_RIGHT
+
+# Sub-modes for branching attachment mode
+BRANCHING_ATTACHMENT_NORMAL = 1
+BRANCHING_ATTACHMENT_BLOB = 2
+
+# logical function to use when drawing rubberband boxes, etc.
+OGLRBLF = wx.INVERT
+
+CONTROL_POINT_SIZE = 6
+
+# Types of arrowhead
+# (i) Built-in
+ARROW_HOLLOW_CIRCLE   = 1
+ARROW_FILLED_CIRCLE   = 2
+ARROW_ARROW           = 3
+ARROW_SINGLE_OBLIQUE  = 4
+ARROW_DOUBLE_OBLIQUE  = 5
+# (ii) Custom
+ARROW_METAFILE        = 20
+
+# Position of arrow on line
+ARROW_POSITION_START  = 0
+ARROW_POSITION_END    = 1
+ARROW_POSITION_MIDDLE = 2
+
+# Line alignment flags
+# Vertical by default
+LINE_ALIGNMENT_HORIZ              = 1
+LINE_ALIGNMENT_VERT               = 0
+LINE_ALIGNMENT_TO_NEXT_HANDLE     = 2
+LINE_ALIGNMENT_NONE               = 0
+
+
+
+# Format a string to a list of strings that fit in the given box.
+# Interpret %n and 10 or 13 as a new line.
+def FormatText(dc, text, width, height, formatMode):
+    i = 0
+    word=""
+    word_list = []
+    end_word = False
+    new_line = False
+    while i<len(text):
+        if text[i]=="%":
+            i += 1
+            if i == len(text):
+                word+="%"
+            else:
+                if text[i]=="n":
+                    new_line = True
+                    end_word = True
+                    i += 1
+                else:
+                    word+="%"+text[i]
+                    i += 1
+        elif text[i] in ["\012","\015"]:
+            new_line = True
+            end_word = True
+            i += 1
+        elif text[i]==" ":
+            end_word = True
+            i += 1
+        else:
+            word += text[i]
+            i += 1
+
+        if i == len(text):
+            end_word = True
+
+        if end_word:
+            word_list.append(word)
+            word=""
+            end_word = False
+        if new_line:
+            word_list.append(None)
+            new_line = False
+
+    # Now, make a list of strings which can fit in the box
+    string_list = []
+    buffer=""
+    for s in word_list:
+        oldBuffer = buffer
+        if s is None:
+            # FORCE NEW LINE
+            if len(buffer)>0:
+                string_list.append(buffer)
+            buffer=""
+        else:
+            if len(buffer):
+                buffer+=" "
+            buffer += s
+            x, y = dc.GetTextExtent(buffer)
+
+            # Don't fit within the bounding box if we're fitting
+            # shape to contents
+            if (x>width) and not (formatMode & FORMAT_SIZE_TO_CONTENTS):
+                # Deal with first word being wider than box
+                if len(oldBuffer):
+                    string_list.append(oldBuffer)
+                buffer = s
+    if len(buffer):
+        string_list.append(buffer)
+
+    return string_list
+
+
+
+def GetCentredTextExtent(dc, text_list, xpos = 0, ypos = 0, width = 0, height = 0):
+    if not text_list:
+        return 0, 0
+
+    max_width = 0
+    for line in text_list:
+        current_width, char_height = dc.GetTextExtent(line)
+        if current_width>max_width:
+            max_width = current_width
+
+    return max_width, len(text_list) * char_height
+
+
+
+def CentreText(dc, text_list, xpos, ypos, width, height, formatMode):
+    if not text_list:
+        return
+
+    # First, get maximum dimensions of box enclosing text
+    char_height = 0
+    max_width = 0
+    current_width = 0
+
+    # Store text extents for speed
+    widths = []
+    for line in text_list:
+        current_width, char_height = dc.GetTextExtent(line.GetText())
+        widths.append(current_width)
+        if current_width>max_width:
+            max_width = current_width
+
+    max_height = len(text_list) * char_height
+
+    if formatMode & FORMAT_CENTRE_VERT:
+        if max_height<height:
+            yoffset = ypos - height / 2 + (height - max_height) / 2
+        else:
+            yoffset = ypos - height / 2
+        yOffset = ypos
+    else:
+        yoffset = 0.0
+        yOffset = 0.0
+
+    if formatMode & FORMAT_CENTRE_HORIZ:
+        xoffset = xpos - width / 2
+        xOffset = xpos
+    else:
+        xoffset = 0.0
+        xOffset = 0.0
+
+    for i, line in enumerate(text_list):
+        if formatMode & FORMAT_CENTRE_HORIZ and widths[i]<width:
+            x = (width - widths[i]) / 2 + xoffset
+        else:
+            x = xoffset
+        y = i * char_height + yoffset
+
+        line.SetX(x - xOffset)
+        line.SetY(y - yOffset)
+        
+
+
+def DrawFormattedText(dc, text_list, xpos, ypos, width, height, formatMode):
+    if formatMode & FORMAT_CENTRE_HORIZ:
+        xoffset = xpos
+    else:
+        xoffset = xpos - width / 2
+
+    if formatMode & FORMAT_CENTRE_VERT:
+        yoffset = ypos
+    else:
+        yoffset = ypos - height / 2
+
+    # +1 to allow for rounding errors
+    dc.SetClippingRegion(xpos - width / 2, ypos - height / 2, width + 1, height + 1)
+
+    for line in text_list:
+        dc.DrawText(line.GetText(), xoffset + line.GetX(), yoffset + line.GetY())
+
+    dc.DestroyClippingRegion()
+
+
+
+def RoughlyEqual(val1, val2, tol = 0.00001):
+    return val1<(val2 + tol) and val1>(val2 - tol) and \
+           val2<(val1 + tol) and val2>(val1 - tol)
+
+
+
+def FindEndForBox(width, height, x1, y1, x2, y2):
+    xvec = [x1 - width / 2, x1 - width / 2, x1 + width / 2, x1 + width / 2, x1 - width / 2]
+    yvec = [y1 - height / 2, y1 + height / 2, y1 + height / 2, y1 - height / 2, y1 - height / 2]
+
+    return FindEndForPolyline(xvec, yvec, x2, y2, x1, y1)
+
+
+
+def CheckLineIntersection(x1, y1, x2, y2, x3, y3, x4, y4):
+    denominator_term = (y4 - y3) * (x2 - x1) - (y2 - y1) * (x4 - x3)
+    numerator_term = (x3 - x1) * (y4 - y3) + (x4 - x3) * (y1 - y3)
+
+    length_ratio = 1.0
+    k_line = 1.0
+
+    # Check for parallel lines
+    if denominator_term<0.005 and denominator_term>-0.005:
+        line_constant=-1.0
+    else:
+        line_constant = float(numerator_term) / denominator_term
+
+    # Check for intersection
+    if line_constant<1.0 and line_constant>0.0:
+        # Now must check that other line hits
+        if (y4 - y3)<0.005 and (y4 - y3)>-0.005:
+            k_line = (x1 - x3 + line_constant * (x2 - x1)) / (x4 - x3)
+        else:
+            k_line = (y1 - y3 + line_constant * (y2 - y1)) / (y4 - y3)
+        if k_line >= 0 and k_line<1:
+            length_ratio = line_constant
+        else:
+            k_line = 1
+
+    return length_ratio, k_line
+
+
+
+def FindEndForPolyline(xvec, yvec, x1, y1, x2, y2):
+    lastx = xvec[0]
+    lasty = yvec[0]
+
+    min_ratio = 1.0
+
+    for i in range(1, len(xvec)):
+        line_ratio, other_ratio = CheckLineIntersection(x1, y1, x2, y2, lastx, lasty, xvec[i], yvec[i])
+        lastx = xvec[i]
+        lasty = yvec[i]
+
+        if line_ratio<min_ratio:
+            min_ratio = line_ratio
+
+    # Do last (implicit) line if last and first doubles are not identical
+    if not (xvec[0] == lastx and yvec[0] == lasty):
+        line_ratio, other_ratio = CheckLineIntersection(x1, y1, x2, y2, lastx, lasty, xvec[0], yvec[0])
+        if line_ratio<min_ratio:
+            min_ratio = line_ratio
+
+    return x1 + (x2 - x1) * min_ratio, y1 + (y2 - y1) * min_ratio
+
+
+
+def PolylineHitTest(xvec, yvec, x1, y1, x2, y2):
+    isAHit = False
+    lastx = xvec[0]
+    lasty = yvec[0]
+
+    min_ratio = 1.0
+
+    for i in range(1, len(xvec)):
+        line_ratio, other_ratio = CheckLineIntersection(x1, y1, x2, y2, lastx, lasty, xvec[i], yvec[i])
+        if line_ratio != 1.0:
+            isAHit = True
+        lastx = xvec[i]
+        lasty = yvec[i]
+
+        if line_ratio<min_ratio:
+            min_ratio = line_ratio
+
+    # Do last (implicit) line if last and first doubles are not identical
+    if not (xvec[0] == lastx and yvec[0] == lasty):
+        line_ratio, other_ratio = CheckLineIntersection(x1, y1, x2, y2, lastx, lasty, xvec[0], yvec[0])
+        if line_ratio != 1.0:
+            isAHit = True
+
+    return isAHit
+
+
+
+def GraphicsStraightenLine(point1, point2):
+    dx = point2[0] - point1[0]
+    dy = point2[1] - point1[1]
+
+    if dx == 0:
+        return
+    elif abs(dy / dx)>1:
+        point2[0] = point1[0]
+    else:
+        point2[1] = point1[0]
+
+
+
+def GetPointOnLine(x1, y1, x2, y2, length):
+    l = math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1))
+    if l<0.01:
+        l = 0.01
+
+    i_bar = (x2 - x1) / l
+    j_bar = (y2 - y1) / l
+
+    return -length * i_bar + x2,-length * j_bar + y2
+
+
+
+def GetArrowPoints(x1, y1, x2, y2, length, width):
+    l = math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1))
+
+    if l<0.01:
+        l = 0.01
+
+    i_bar = (x2 - x1) / l
+    j_bar = (y2 - y1) / l
+    
+    x3=-length * i_bar + x2
+    y3=-length * j_bar + y2
+
+    return x2, y2, width*-j_bar + x3, width * i_bar + y3,-width*-j_bar + x3,-width * i_bar + y3
+
+
+
+def DrawArcToEllipse(x1, y1, width1, height1, x2, y2, x3, y3):
+    a1 = width1 / 2
+    b1 = height1 / 2
+
+    # Check that x2 != x3
+    if abs(x2 - x3)<0.05:
+        x4 = x2
+        if y3>y2:
+            y4 = y1 - math.sqrt((b1 * b1 - (((x2 - x1) * (x2 - x1)) * (b1 * b1) / (a1 * a1))))
+        else:
+            y4 = y1 + math.sqrt((b1 * b1 - (((x2 - x1) * (x2 - x1)) * (b1 * b1) / (a1 * a1))))
+        return x4, y4
+
+    # Calculate the x and y coordinates of the point where arc intersects ellipse
+    A = (1 / (a1 * a1))
+    B = ((y3 - y2) * (y3 - y2)) / ((x3 - x2) * (x3 - x2) * b1 * b1)
+    C = (2 * (y3 - y2) * (y2 - y1)) / ((x3 - x2) * b1 * b1)
+    D = ((y2 - y1) * (y2 - y1)) / (b1 * b1)
+    E = (A + B)
+    F = (C - (2 * A * x1) - (2 * B * x2))
+    G = ((A * x1 * x1) + (B * x2 * x2) - (C * x2) + D - 1)
+    H = ((y3 - y2) / (x2 - x2))
+    K = ((F * F) - (4 * E * G))
+
+    if K >= 0:
+        # In this case the line intersects the ellipse, so calculate intersection
+        if x2 >= x1:
+            ellipse1_x = ((F*-1) + math.sqrt(K)) / (2 * E)
+            ellipse1_y = ((H * (ellipse1_x - x2)) + y2)
+        else:
+            ellipse1_x = (((F*-1) - math.sqrt(K)) / (2 * E))
+            ellipse1_y = ((H * (ellipse1_x - x2)) + y2)
+    else:
+        # in this case, arc does not intersect ellipse, so just draw arc
+        ellipse1_x = x3
+        ellipse1_y = y3
+
+    return ellipse1_x, ellipse1_y
+
+
+
+def FindEndForCircle(radius, x1, y1, x2, y2):
+    H = math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1))
+
+    if H == 0:
+        return x1, y1
+    else:
+        return radius * (x2 - x1) / H + x1, radius * (y2 - y1) / H + y1