thanline.py :  » Business-Application » ThanCad » thancad-0.0.9 » thandr » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Business Application » ThanCad 
ThanCad » thancad 0.0.9 » thandr » thanline.py
##############################################################################
# ThanCad 0.0.9 "DoesSomething": 2dimensional CAD with raster support for engineers.
# 
# Copyright (c) 2001-2009 Thanasis Stamos,  August 23, 2009
# URL:     http://thancad.sourceforge.net
# e-mail:  cyberthanasis@excite.com
# 
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
# 
# This program 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 General Public License for more details (www.gnu.org/licenses/gpl.html).
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
##############################################################################

"""\
ThanCad 0.0.9 "DoesSomething": 2dimensional CAD with raster support for engineers.

This module defines the polyline element.
"""
from itertools import izip,islice
from math import fabs,hypot,pi,atan2
import weakref, bisect
from p_ggen import iterby2
from p_gmath import dpt,PI2,thanNearx,thanNear2,thanNear3
import p_ggeom
import thanintall
from thanelem import ThanElement
from thanvar import Canc,thanCleanLine3
from thanvar.thanoffset import thanOffsetLine
from thantrans import T
try: import pyx
except ImportError: pass


class ThanLine(ThanElement):
    "A Basic simple 2d line."

    def thanSet (self, cp):
        """Sets the attributes of the line.
  If len(cp) == 0 or == 1, all the methods work (they produce nothing)
  except the thanBreak, thanSegNearest, thanTkContinue, thanTkDraw and others.
  Thus it is imperative to call thanIsNormal() to see if the line is degenerate
  before attempting any of the above functions.
  """
  self.cp = thanCleanLine3(cp)        #FIXME: thanCleanLine3 cleans 3dimensional degenerate segments;..
  if len(self.cp) > 0:                #..
      xp = [c1[0] for c1 in self.cp]  #Thus 2d algorithms may fail if deltax==deltay==0 CHECK ALL THE OPERATIONS..
      yp = [c1[1] for c1 in self.cp]  #Is thanCleanLine still necessary (it is used in ThanRoad only)???
            self.setBoundBox([min(xp), min(yp), max(xp), max(yp)])
#  self.thanTags = ()            # thanTags is initialised in ThanElement

    def thanIsNormal(self):
        "Returns False if the line is degenerate (it has only one point)."
#       if len(cp) == 2 and it is closed then it is degenerate and this function returns false
#       if len(cp) == 3 and it is closed then it is degenerate polygon but
#       a good line, so this function returns True
        if len(self.cp) < 2: return False   # Return False if line is degenerate
  cp = iter(self.cp)
  c1 = cp.next()
  for c2 in cp:
      if not thanNear3(c1, c2): return True
  return False      # All line points are close together

    def thanClean(self):
        "Clean zero lengthed segments."
        self.cp = thanCleanLine3(self.cp)


    def thanClone(self):
        "Makes a geometric clone of itself."
        el = self.__class__()
        el.thanSet(self.cp)
        return el


    def thanRotate(self):
        "Rotates the element within XY-plane with predefined angle and rotation angle."
        self.thanRotateXyn(self.cp)
        xp = [c1[0] for c1 in self.cp]
        yp = [c1[1] for c1 in self.cp]
        self.setBoundBox([min(xp), min(yp), max(xp), max(yp)])


    def thanMirror(self):
        "Mirrors the element within XY-plane with predefined point and unit vector."
        self.thanMirrorXyn(self.cp)
        xp = [c1[0] for c1 in self.cp]
        yp = [c1[1] for c1 in self.cp]
        self.setBoundBox([min(xp), min(yp), max(xp), max(yp)])


    def thanScale(self, cs, scale):
        "Scales the ele`ment in n-space with defined scale and center of scale."
  for cc in self.cp:
      cc[:] = [cs1+(cc1-cs1)*scale for (cc1,cs1) in izip(cc, cs)]
  cscs = [cs[0], cs[1], cs[0], cs[1]]
  self.thanXymm[:] = [cs1+(cc1-cs1)*scale for (cc1,cs1) in izip(self.thanXymm, cscs)]

    def thanMove(self, dc):
        "Moves the element with defined n-dimensional distance."
  for cc in self.cp:
      cc[:] = [cc1+dd1 for (cc1,dd1) in izip(cc, dc)]
  dcdc = [dc[0], dc[1], dc[0], dc[1]]
  self.thanXymm[:] = [cc1+dd1 for (cc1,dd1) in izip(self.thanXymm, dcdc)]


    def thanOsnap(self, proj, otypes, ccu, eother, cori):
        "Return a point of type otype nearest to ccu."
        if "ena" not in otypes: return None            # Object snap is disabled
        ps = []
        if "end" in otypes:       # type "end" without type "int"
            for c in self.cp:
                ps.append((fabs(c[0]-ccu[0])+fabs(c[1]-ccu[1]), "end", c))
        if "mid" in otypes:
            for ca, cb in iterby2(self.cp):
                c = [(ca1+cb1)*0.5 for (ca1,cb1) in izip(ca, cb)]
                ps.append((fabs(c[0]-ccu[0])+fabs(c[1]-ccu[1]), "mid", c))
        if "nea" in otypes:
            c = self.thanPntNearest(ccu)
            if c != None:
                ps.append((fabs(c[0]-ccu[0])+fabs(c[1]-ccu[1]), "nea", c))
        if cori != None and "per" in otypes:
            for c in self.thanPerpPoints(cori):
                ps.append((fabs(c[0]-ccu[0])+fabs(c[1]-ccu[1]), "per", c))
        if eother != None and "int" in otypes:
            ps.extend(thanintall.thanIntsnap(self, eother, ccu, proj))
        if len(ps) < 1: return None
        return min(ps)


    def thanPntNearest(self, ccu):
        "Finds the nearest point of this line to a point."
        return thanPntNearest2(self.cp, ccu)[0]
    def thanPntNearest2(self, ccu):
        "Finds the nearest point of this line to a point."
        return thanPntNearest2(self.cp, ccu)
    def thanPerpPoints(self, ccu):
        "Finds perpendicular point from ccu to polyline."
        return thanPerpPoints(self.cp, ccu)
    def thanSegNearest(self, ccu):
        """Finds the nearest segment of this line to a point."""
        return thanSegNearest(self.cp, ccu)


    def thanTrim(self, ct, cnear):
        "Breaks the line into multiple segments and deletes the segment nearest to cnear."
        cp = []
        for c in ct:
            cn, i, t = self.thanPntNearest2(c)
            cp.append((t, i, c))
            assert cn != None, "It should have been checked (that ct are indeed near line)!"
        cp.sort()
        cn, i, t = self.thanPntNearest2(cnear)
        cpnear = t, i, cn
        assert cpnear[2] != None, "It should have been checked (that cnear are indeed near line)!"
        i = bisect.bisect_right(cp, cpnear)
        if i == 0:
            return self.thanBreak(self.cp[0], cp[0][2])  # User selected the segment before the first intesection (ct)
        elif i == len(cp):
            return self.thanBreak(cp[-1][2], self.cp[-1])# User selected the segment after the last intesection (ct)
        else:
            return self.thanBreak(cp[i-1][2], cp[i][2])  # User selected the segment between i-1 and i intesections (ct)


    def thanBreak(self, c1=None, c2=None):
        "Breaks a line to 2 pieces; c1 and c2 may be identical."
  if c1 == None: return True                 # Report that break IS implemented
  cp1, i1, tcp1 = self.thanPntNearest2(c1)
  cp2, i2, tcp2 = self.thanPntNearest2(c2)
  if tcp2 < tcp1:
      cp1, i1, cp2, i2 = cp2, i2, cp1, i1
  assert cp1 != None and cp2 != None, "It should have been checked (that c1 and c2 are indeed near line)!"
  cs1 = self.cp[:i1]
  if len(cs1) > 0:
      cs1.append(cp1)
      e1 = ThanLine()
      e1.thanSet(cs1)
      if not e1.thanIsNormal(): e1 = None    # A tiny segment was left
  else:
      e1 = None
  cs1 = self.cp[i2:]
  if len(cs1) > 0:
      cs1.insert(0, cp2)
      e2 = ThanLine()
      e2.thanSet(cs1)
      if not e2.thanIsNormal(): e2 = None    # A tiny segment was left
  else:
      e2 = None
  return e1, e2                              # If both are None, then "break" left nothing


    def thanOffset(self, dis):
        "Offset line by distance dis; to the right if dis>0 and to the left otherwise."
  if dis == None: return True                # Offset is implemented
  cs = thanOffsetLine(self.cp, dis)
  e = ThanLine()
  e.thanSet(cs)
  if e.thanIsNormal(): return e
  return None


    def thanLength(self):
        "Returns the length of the polyline."
  al = 0.0
  for ca, cb in iterby2(self.cp):
      al += hypot(cb[0]-ca[0], cb[1]-ca[1])
  return al

    def thanArea(self):
        "Returns the area of the polyline."
  return p_ggeom.area(self.cp)

#===========================================================================

    def thanTkGet(self, proj):
        "Gets the attributes of the line interactively from a window."
        cp = []
  while True:
      c1 = proj[2].thanGudGetPoint(T["First line point (c=continue "
         "previous/e=extend other): "], options=("continue", "extend"))
            if c1 == Canc: return Canc                              # Line cancelled
         if c1 == "c":
          proj[2].thanGudCommandBegin("continueline")
          return Canc
      elif c1 == "e":
          proj[2].thanGudCommandBegin("extendline")
          return Canc
      break
        cp.append(c1)
  res = self.__tkGetn(proj, cp)
  if res == Canc: return Canc
  proj[1].thanPrevLine = weakref.ref(self)


    def thanTkContinue(self, proj):
        "Gets the attributes of the line interactively from a window."
        dc = proj[2].than.dc
  dc.delete(self.thanTags[0])
  g2l = proj[2].than.ct.global2Local
  cl = proj[2].than.dc.create_line
  fi = proj[2].than.outline
  cp = list(self.cp)
        x1, y1 = g2l(cp[0][0], cp[0][1])
  for i in xrange(1, len(cp)):
            tags = "e0", "e"+str(i+1)
            x2, y2 = g2l(cp[i][0], cp[i][1])
            temp = cl(x1, y1, x2, y2, fill=fi, tags=tags)
      x1 = x2; y1 = y2
        res = self.__tkGetn(proj, cp)
  if res == Canc: return Canc
  self.thanTkDraw(proj[2].than)
  return res


    def __tkGetn(self, proj, cp):
        "Gets the following points of the line interactively from a window."
        cla = proj[1].thanLayerTree.thanCur
  g2l = proj[2].than.ct.global2Local
  cl = proj[2].than.dc.create_line
  delete = proj[2].than.dc.delete
  fi = proj[2].than.outline
  wpix = proj[2].than.tkThick
  c1 = cp[-1]
        while True:
            res = self.__getPointLin(proj[2], c1, len(cp))
            if res == Canc and len(cp) < 2: return Canc          # Line cancelled
            if res == Canc or res == "" or res == "c": break     # Line ended (we know that line has more than 1 point)
      if res == "u":
    delete("e"+str(len(cp)))
          c1 = cp[-2]
    del cp[-1]
            else:
                c1 = res
                cp.append(c1)
          tags = "e0", cla.thanTag, "e"+str(len(cp))
                temp = cl((g2l(cp[-2][0], cp[-2][1]), g2l(c1[0], c1[1])), fill=fi, width=wpix, tags=tags)
#               print "line:thantkget:fi=", fi
  if res == "c":
      cp.append(list(cp[0]))
#           Note that if we did: cp.append(cp[0])
#           then if we changed the coordinates of cp[0], the coordinates of cp[-1]
#           would also change. This means that the line would always be closed.
#           Also, thanClone should check for this, since the cloned line would have
#           independent coordinates in cp[0] and cp[1]. Also, all the modifications
#           (move, rotate etc.) should be careful not to apply the modification
#           to both cp[0] and cp[-1], as it would make the modification twice.

  delete("e0")
        self.thanSet(cp)
        return True        # Line OK (note that it will have at least 2 points)

    def __getPointLin(win, c1, np):
        "Gets a point from the user, with possible options."
  if np == 1:
      stat1 = T["Next line point: "]
      return win.thanGudGetLine(c1, stat1)
  elif np == 2:
      stat1 = T["Next line point (undo/<enter>): "]
      return win.thanGudGetLine(c1, stat1, options=("", "undo"))
  else:
      stat1 = T["Next line point (undo/close/<enter>): "]
      return win.thanGudGetLine(c1, stat1, options=("", "undo", "close"))
    __getPointLin = staticmethod(__getPointLin)

#===========================================================================

    def thanTkDraw(self, than):
        "Draws the line to a Tk Canvas."
        g2l = than.ct.global2Local
        w = than.tkThick
        xy1 = [g2l(c1[0], c1[1]) for c1 in self.cp]
        if thanNear2(self.cp[0], self.cp[-1]):   # Even if fill="", which means no fill
#            temp = than.dc.create_polygon(xy1, outline=than.outline, fill=than.fill, tags=self.thanTags, width=w)
            temp = than.dc.create_line(   xy1,                       fill=than.outline, tags=self.thanTags, width=w)
        else:
            temp = than.dc.create_line(   xy1,                       fill=than.outline, tags=self.thanTags, width=w)


    def thanTkHiwin(self, than):
        "Highlights with a (small) window very small elements so that they become visible."
        self.thanTkHiwinDo(than, self.thanLength(), self.cp[0])

    def thanExpDxf(self, fDxf):
        "Exports the line to dxf file."
  #FIXME: report width of polyline
  xp = [c1[0] for c1 in self.cp]
  yp = [c1[1] for c1 in self.cp]
  zp = [c1[2] for c1 in self.cp]
        fDxf.thanDxfPlotPolyline3(xp, yp, zp)


    def thanExpSyk(self, than):
        "Exports the line to syk file."
        than.write("%15.3f  %s\n" % (self.cp[0][2], than.layname))
        for cp1 in self.cp:
            than.write("%15.3f%15.3f\n" % (cp1[0], cp1[1]))
        than.write("$\n")


    def thanExpBrk(self, than):
        "Exports the line to brk file."
        for cp1 in self.cp:
            than.ibr += 1
            than.write(than.form % (than.ibr, cp1[0], cp1[1], cp1[2]))
        than.write("$\n")


    def thanExpPil(self, than):
        """Exports the line to a PIL raster image.

        There seems to be a bug in the PIL which chaotically affects the width
        of the line. Thus, this code is not used. But it should be checked
        with future versions of PIL.
        """
        g2l = than.ct.global2Local
        xy1 = [g2l(c1[0], c1[1]) for c1 in self.cp]
        if thanNear2(self.cp[0], self.cp[-1]) and not than.fill:
            than.dc.polygon(xy1, outline=than.outline, fill=than.fill) # width=than.width)
        else:
            than.dc.line(xy1, fill=than.outline, width=than.width)


    def thanExpPilworkaround(self, than):
        "Exports the line to a PIL raster image; 2008_10_07:no longer valid."
  w, _ = than.ct.global2LocalRel(self.width, self.width)
  if w < than.rwidth: w = than.rwidth
  if w <= 1.5:
      g2l = than.ct.global2Locali
            xy1 = [g2l(c1[0], c1[1]) for c1 in self.cp]
      than.dc.line(xy1, fill=than.outline)
      return
        w2, _ = than.ct.local2GlobalRel(w*0.5, w)
        for i in xrange(1, len(self.cp)):
      x1, y1 = self.cp[i-1][0], self.cp[i-1][1]
      x2, y2 = self.cp[i][0], self.cp[i][1]
      dx, dy = x2-x1, y2-y1
      r = hypot(dx, dy)
      if r <= 0.0: continue
            tx, ty = dx/r, dy/r
         nx, ny = -ty*w2, tx*w2
      cr = (x1-nx,y1-ny), (x2-nx,y2-ny), (x2+nx,y2+ny), (x1+nx,y1+ny)
            xy1 = [than.ct.global2Locali(x1, y1) for x1,y1 in cr]
      than.dc.polygon(xy1, outline=than.outline, fill=than.outline)

    def thanPlotPdf(self, than):
        "Plots the line to a pdf file."
  #FIXME: report width of polyline
  if len(self.cp) < 2: return
  g2l = than.ct.global2Local
  if len(self.cp) == 2:
      ca = g2l(self.cp[0][0], self.cp[0][1])
      cb = g2l(self.cp[1][0], self.cp[1][1])
      p = pyx.path.line(ca[0], ca[1], cb[0], cb[1])
  else:
      lineto = pyx.path.lineto
      moveto = pyx.path.moveto
            xy1 = [lineto(*g2l(c1[0], c1[1])) for c1 in islice(self.cp, 1, None)]
      xy1.insert(0, moveto(*g2l(self.cp[0][0], self.cp[0][1])))
      if thanNear2(self.cp[0], self.cp[-1]): xy1[-1] = pyx.path.closepath()
      p = pyx.path.path(*xy1)
  than.dc.stroke(p)

    def thanList(self, than):
        "Shows information about the line element."
        than.writecom("Element: LINE")
        if thanNear2(self.cp[0], self.cp[-1]): oc = "closed"
        else:                                  oc = "open"
        than.write(" (%s)    Layer: %s\n" % (oc, than.laypath))
        than.write("Length: %s    Area: %s\n" % (than.strdis(self.thanLength()), than.strdis(self.thanArea())))
        than.write("Vertices (%d):\n" % len(self.cp))
        for i,c1 in enumerate(self.cp):
            than.write("    %s\n" % than.strcoo(c1))
            if i % 20 == 19:
                c = than.read("Press enter to continue..")
                if c == Canc: break


    def __del__(self):
        print "ThanLine", self, "is deleted"


##############################################################################
##############################################################################

class ThanLineFilled(ThanLine):
    "A closed polyline which is filled with colour."

    def thanTkDraw(self, than):
        "Draws the filled line to a Tk Canvas."
        g2l = than.ct.global2Local
        w = than.tkThick
        xy1 = [g2l(c1[0], c1[1]) for c1 in self.cp]
        fill = than.fill
        if not fill: fill = than.outline
        temp = than.dc.create_polygon(xy1, outline=than.outline, fill=fill, tags=self.thanTags, width=w)


    def thanExpPil(self, than):
        """Exports the filled line to a PIL raster image."""
        g2l = than.ct.global2Local
        xy1 = [g2l(c1[0], c1[1]) for c1 in self.cp]
        fill = than.fill
        if not fill: fill = than.outline
        than.dc.polygon(xy1, outline=than.outline, fill=fill) # width=than.width)


    def thanExpDxf(self, fDxf):
        "Exports the filled line to dxf file; if it has 3 or 4 points then as a solid."
        if not thanNear2(self.cp[0], self.cp[-1]):
            ThanLine.thanExpDxf(self, fDxf)
        elif len(self.cp) == 4:
            c1, c2, c3 = self.cp[:3]
            fDxf.thanDxfPlotSolid3(c1[0], c1[1], c2[0], c2[1], c3[0], c3[1])
        elif len(self.cp) == 5:
            c1, c2, c3, c4 = self.cp[:4]
            fDxf.thanDxfPlotSolid4(c1[0], c1[1], c2[0], c2[1], c3[0], c3[1], c4[0], c4[1])
        else:
            ThanLine.thanExpDxf(self, fDxf)


    def thanList(self, than):
        "Shows information about the filled line element."
        than.writecom("Element: LINE FILLED (SOLID)")
        than.write("    Layer: %s\n" % than.laypath)
        than.write("Length: %s    Area: %s\n" % (than.strdis(self.thanLength()), than.strdis(self.thanArea())))
        than.write("Vertices (%d):\n" % len(self.cp))
        for i,c1 in enumerate(self.cp):
            than.write("    %s\n" % than.strcoo(c1))
            if i % 20 == 19:
                c = than.read("Press enter to continue..")
                if c == Canc: break


##############################################################################
##############################################################################

class ThanCurve(ThanLine):
    """A curve which is simulated by a large number of cosecutive linear segments.

    Basically an ordinary polyline, with the difference that osnap does not snap
    to the end points and midpoints of the linear segments.
    For the tangent osnap to work, it is supposed that the curve is continuous (it has
    to be, noncontinuous can not be represented by a ThanLine) and that the line segments
    which simulate the curve are dense enough to show the smooth character of the curve,
    (where the curve is indeed smooth). If the curve has some real corners, these are taken
    into account by the threshold of the difference between tagents.
    """

    def thanMidPoint(self):
        "Finds the midpoint of the curve."
        alm = self.thanLength()*0.5
        ala = 0.0
        for ca, cb in iterby2(self.cp):
            alb = ala + hypot(cb[0]-ca[0], cb[1]-ca[1])
            if alb >= alm: break
            ala = alb
        else:
            assert False, "What? Half length is bigger than length?!"
        if thanNearx(ala, alb):       # In case of zero length segment
            c = [(za+zb)*0.5 for (za, zb) in zip(ca, cb)]
        else:
            c = [za+(zb-za)/(alb-ala)*(alm-ala) for (za, zb) in zip(ca, cb)]
        return c


    def thanTanPoints(self, cori):
        """Finds the tangent to the curve from cori to the curve.

        If more than 1 tangents are found, all are returned.
        """
        thtol = 0.5*pi/180.0       # Tolerance is 0.5 degrees
        ps = []
        for ca, cb in iterby2(self.cp):
            thcurv = atan2(cb[1]-ca[1], cb[0]-ca[0])
            thtan  = atan2(ca[1]-cori[1], ca[0]-cori[0])
            dth = dpt(thcurv-thtan)
            if dth < thtol or PI2-dth < thtol or fabs(dth-pi) < thtol: ps.append(ca)
        return ps


    def thanCenterPoint(self, ccu):
        "Finds the center and the radius of the circle which is tangent to point nearest to ccu."
        from p_gvec import Vector2
        thtol = 2.0*pi/180.0       # Tolerance is 2.0 degrees
        cp1, i, tcp1 = self.thanPntNearest2(ccu)
        if cp1 == None: return None, None, None
        if i+1 >= len(self.cp): return None, None, None
        ca, cb, cc = self.cp[i-1:i+2]
        a = hypot(cb[0]-ca[0], cb[1]-ca[1])
        th1 = atan2(cb[1]-ca[1], cb[0]-ca[0])
        th2 = atan2(cc[1]-cb[1], cc[0]-cb[0])
        dth = dpt(th2-th1)
        if dth > pi: dth = fabs(dth-PI2)
        if dth > thtol: return None, None, None                # not smooth; it is a corner
        if thanNearx(dth, 0.0): return None, None, None        # Straight line, radius is infinite
        r = a / dth
        va = Vector2(ca[0], ca[1])
        vb = Vector2(cb[0], cb[1])
        vc = Vector2(cc[0], cc[1])
        t1 = (va-vb).unit()
        t2 = (vc-vb).unit()
        t = (t1+t2).unit()
        vcen = vb + r*t
        ccen = list(cb)
        ccen[:2] = vcen.x, vcen.y
        return ccen, r, cb


    def thanOsnap(self, proj, otypes, ccu, eother, cori):
        "Return a point of type otype nearest to xcu, ycu."
        if "ena" not in otypes: return None            # Object snap is disabled
        ps = []
        if "end" in otypes:       # type "end" without type "int"
            for c in self.cp[0], self.cp[-1]:
                ps.append((fabs(c[0]-ccu[0])+fabs(c[1]-ccu[1]), "end", c))
        if "mid" in otypes:
            c = self.thanMidPoint()
            ps.append((fabs(c[0]-ccu[0])+fabs(c[1]-ccu[1]), "mid", c))
        if "tan" in otypes:
            if cori != None:
                for c in self.thanTanPoints(cori):
                    ps.append((fabs(c[0]-ccu[0])+fabs(c[1]-ccu[1]), "tan", c))
        if "cen" in otypes:
            c, r, ctang = self.thanCenterPoint(ccu)
            print c, r
            if c != None:
                ps.append((fabs(ctang[0]-ccu[0])+fabs(ctang[1]-ccu[1]), "cen", c))
        if "nea" in otypes:
            c = self.thanPntNearest(ccu)
            if c != None:
                ps.append((fabs(c[0]-ccu[0])+fabs(c[1]-ccu[1]), "nea", c))
        if eother != None and "int" in otypes:
            ps.extend(thanintall.thanIntsnap(self, eother, ccu, proj))
        if len(ps) < 1: return None
        return min(ps)


    def thanList(self, than):
        "Shows information about the curve element."
        than.writecom("Element: CURVE")
        than.write("    Layer: %s\n" % than.laypath)
        than.write("Length: %s    Area: %s\n" % (than.strdis(self.thanLength()), than.strdis(self.thanArea())))



##############################################################################
##############################################################################

def thanPntNearest(cp, ccu):
        "Finds the nearest point of this line to a point."
        return thanPntNearest2(cp, ccu)[0]


def thanPntNearest2(cp, ccu):
        "Finds the nearest point of this line to a point."
  dmin=1e100; cp1 = None; iseg = -1; tcp1 = -1.0
  tall = 0.0
  for i in xrange(1, len(cp)):
      a = cp[i][0]-cp[i-1][0], cp[i][1]-cp[i-1][1]
      aa = hypot(*a)
      tall += aa
      if thanNearx(aa, 0.0): continue      # Segment has zero length
      ta = a[0]/aa, a[1]/aa
      b = ccu[0]-cp[i-1][0], ccu[1]-cp[i-1][1]
      dt = ta[0]*b[0]+ta[1]*b[1]
      if   thanNearx(dt, 0.0) : dt = 0.0
      elif thanNearx(dt, aa)  : dt = aa
      elif dt < 0.0 or dt > aa: continue
      dn = fabs(-ta[1]*b[0]+ta[0]*b[1])
      if dn < dmin:
          cp1 = [e+(f-e)*dt/aa for (e,f) in izip(cp[i-1], cp[i])]
    dmin = dn
    iseg = i
    tcp1 = tall - aa + dt
  return cp1, iseg, tcp1


def thanSegNearest(cp, ccu):
        """Finds the nearest segment of this line to a point.

  It is an optimisation of thanPntNearest2(), if the nearest point is
  not needed.
  This function is used in thanintall in order to find the intersection
  of a line and another ThanCad element, when object snap intersection
  is enabled. We take advantage of the fact that the mouse coordinates
  ccu are already very near the line (and the other element). Thus, we
  don't check if the projection of the ccu to the line segment is indeed
  between the end of the line segment. However thanintall will ensure
  that the intersection point will belong to both elements.
  """
        dmax=1e100
        for i in xrange(1, len(cp)):
            a = cp[i][0]-cp[i-1][0], cp[i][1]-cp[i-1][1]
      aa = hypot(*a)
      if aa == 0.0: continue              # Segment has zero length
            b = ccu[0]-cp[i-1][0], ccu[1]-cp[i-1][1]
            dn = fabs(a[0]*b[1]-a[1]*b[0]) / aa
      if dn < dmax: imax=i; dmax=dn
  return cp[imax-1], cp[imax]


def thanPerpPoints(cp, ccu):
        "Finds perpendicular point from ccu to polyline."
        ps = []
        tall = 0.0
        for i in xrange(1, len(cp)):
            a = cp[i][0]-cp[i-1][0], cp[i][1]-cp[i-1][1]
            aa = hypot(*a)
            tall += aa
            if thanNearx(aa, 0.0): continue      # Segment has zero length
            ta = a[0]/aa, a[1]/aa
            b = ccu[0]-cp[i-1][0], ccu[1]-cp[i-1][1]
            dt = ta[0]*b[0]+ta[1]*b[1]
            if   thanNearx(dt, 0.0) : dt = 0.0
            elif thanNearx(dt, aa)  : dt = aa
            elif dt < 0.0 or dt > aa: continue
            dn = fabs(-ta[1]*b[0]+ta[0]*b[1])
            cp1 = [e+(f-e)*dt/aa for (e,f) in izip(cp[i-1], cp[i])]
            ps.append(cp1)
        return ps


if __name__ == "__main__":
    print __doc__
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.