+++ /dev/null
-# -*- 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
-#----------------------------------------------------------------------------
-
-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.GetText())
- 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.0 + (height - max_height) / 2.0
- else:
- yoffset = ypos - height / 2.0
- yOffset = ypos
- else:
- yoffset = 0.0
- yOffset = 0.0
-
- if formatMode & FORMAT_CENTRE_HORIZ:
- xoffset = xpos - width / 2.0
- 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.0 + 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.0
-
- if formatMode & FORMAT_CENTRE_VERT:
- yoffset = ypos
- else:
- yoffset = ypos - height / 2.0
-
- # +1 to allow for rounding errors
- dc.SetClippingRegion(xpos - width / 2.0, ypos - height / 2.0, 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.0, x1 - width / 2.0, x1 + width / 2.0, x1 + width / 2.0, x1 - width / 2.0]
- yvec = [y1 - height / 2.0, y1 + height / 2.0, y1 + height / 2.0, y1 - height / 2.0, y1 - height / 2.0]
-
- 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(float(dy) / dx) > 1:
- point2[0] = point1[0]
- else:
- point2[1] = point1[1]
-
-
-
-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.0
- b1 = height1 / 2.0
-
- # 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 = (float(y3 - y2) / (x3 - 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