thanroad.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 » thanroad.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 road element. It is a polyline with its corners rounded
with circular arcs of given radius.
"""
from itertools import izip
from math import fabs,hypot,sqrt,pi,cos,sin
from p_ggen import iterby2,iterby3
from p_gmath import thanNearx,thanNear2
import p_ggeom
import thanintall
from thanelem import ThanElement
from thanvar import Canc,tkRoadNode,calcRoadNode,thanCleanLine2
from thantrans import T

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

class ThanRoad(ThanElement):
    "A simple 2d line with line segments and arcs."
    thanTkCompound = 100       # The number of Tkinter objects that make the element. 100=compound (lines etc.)

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

    def thanSet(self, cpr):
        """Sets the attributes of the road.

  cpr is made of points (lists) which have 1 dimension more than simple
  points. The last dimension is the radius of the road curve.
  The radius of the first and the last point are ignored and they should
  be zero.
  """
  assert len(cpr) > 1, "Less than 2 points in ThanRoad!"
  self.cpr = thanCleanLine2(cpr)
  xp = [c1[0] for c1 in self.cpr]
  yp = [c1[1] for c1 in self.cpr]
        self.setBoundBox([min(xp), min(yp), max(xp), max(yp)])
#  self.thanTags = ()            # thanTags is initialised in ThanElement

    def thanIsNormal(self):
        "Returns False if the road is degenerate (only 1 node)."
        if len(self.cp) < 2: return False       # Return False if road is degenerate
  cp = iter(self.cp)
  c1 = cp.next()
  for c2 in cp:
      if not thanNear2(c1, c2): return True
  return False      # All line points are close together

    def thanClean(self):
        "Clean zero lengthed segments."
  self.cpr = thanCleanLine2(self.cpr)

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


    def thanRotate(self):
        "Rotates the element within XY-plane with predefined angle and rotation angle."
        self.thanRotateXyn(self.cpr)


    def thanMirror(self):
        "Mirrors the element within XY-plane with predefined point and unit vector."
        self.thanMirrorXyn(self.cpr)


    def thanScale(self, cs, scale):
        "Scales the element in n-space with defined scale and center of scale."
  for cc in self.cpr:
      cc[:-1] = [cs1+(cc1-cs1)*scale for (cc1,cs1) in izip(cc[:-1], cs)]
      cc[-1] *= scale     # Radius

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

    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.cpr:
          ps.append((fabs(c[0]-ccu[0])+fabs(c[1]-ccu[1]), "end", c[:-1]))
  if "mid" in otypes:
      for ca, cb in iterby2(self.cpr):
    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[:-1]))
  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 thanPntNearest(self, ccu):
        "Finds the nearest point of this road to a point."
        return self.thanPntNearest2(ccu)[0]

    def thanPntNearest2(self, ccu):
        "Finds the nearest point of this road to a point."
  dmax=1e100; cp1 = None; iseg = -1; cp = self.cpr
  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 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 < dmax:
          cp1 = [e+(f-e)*dt/aa for (e,f) in izip(cp[i-1], cp[i])]
    del cp1[-1]
    dmax = dn
    iseg = i
  return cp1, iseg

    def thanSegNearest(self, ccu):
        """Finds the nearest segment of this road 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 cooedinates
  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
  cp = self.cpr
        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][:-1], cp[imax][:-1]

    def thanBreak(self, c1=None, c2=None):
        "Breaks a line to 2 pieces."
  if c1 == None: return True          # Break IS implemented
  cp1, i1 = self.thanPntNearest2(c1)
  cp2, i2 = self.thanPntNearest2(c2)
  if i2 < i1:
      cp1, i1, cp2, i2 = cp2, i2, cp1, i1
  elif i2 == i1:
      i = i1 - 1
      d1 = hypot(cp1[0]-self.cp[i][0], cp1[1]-self.cp[i][1])
      d2 = hypot(cp2[0]-self.cp[i][0], cp2[1]-self.cp[i][1])
      if d2 < d1:
          cp1, i1, cp2, i2 = cp2, i2, cp1, i1
  assert cp1 != None and cp2 != None, "It should have been checked!"
  e1 = ThanLine()
  e1.thanSet(self.cp[:i1+1])
  e1.cp[i1] = cp1
  e2 = ThanLine()
  e2.thanSet(self.cp[i2-1:])         # Note that i2-1 >= 0
  e2.cp[0] = cp2
  return e1, e2

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

    def thanTkGet(self, proj):
        "Gets the attributes of the road interactively from a window."
  g2l = proj[2].than.ct.global2Local
  g2lr= proj[2].than.ct.global2LocalRel
  l2g = proj[2].than.ct.local2Global
  dc = proj[2].than.dc
  fi = proj[2].than.outline
  rdef = 50.0                                             # default radius

        cpr = []; ctr = []
        c1 = proj[2].thanGudGetPoint(T["First road point:"])
        if c1 == Canc: return Canc                              # Road was cancelled
        c1.append(0.0)                                          # radius
  cpr.append(c1); ctr.append(c1)

        while True:
          c1 = proj[2].thanGudGetLine(cpr[-1], "Second road point: ")
          if c1 == Canc: return Canc                            # Road was cancelled
      c1.append(rdef)                                       # radius
    cpr.append(c1); ctr.append(c1)

    c1 = None; r1 = rdef
    proj[2].thanCom.thanAppend("%s%d\n" % (T["Radius="], r1), "info1")
          while True:
            c1, cargo = self.__getPointLin(proj[2], ctr[-2], cpr[-1], c1, r1, len(cpr))
            if c1 == Canc and len(cpr) < 2: return Canc         # Road was cancelled
            if c1 == Canc or c1 == "" or c1 == "c": break       # Road was ended
      if cargo == "r":
          print "r:", c1
          res = proj[2].thanGudGetRoadR(ctr[-2], cpr[-1], c1, r1, T["New radius: "])
    if res != Canc: cpr[-1][-1] = r1 = res
      elif c1 == "r":                                     # Get new radius
          res = proj[2].thanGudGetPosFloat(T["New default radius: "], rdef)
    if res != Canc: rdef = cpr[-1][-1] = r1 = res
    c1 = None
      elif c1 == "u":                                     # Undo last point
          if len(cpr) < 3: break
    dc.delete("e"+str(len(cpr)))
    del cpr[-1], ctr[-1]
            else:                                               # Plot the new point
                c1.append(rdef)                                 # Radius
          cpr.append(c1); ctr.append(c1)

    xp1, yp1 = g2l(ctr[-3][0], ctr[-3][1])
    xp2, yp2 = g2l(cpr[-2][0], cpr[-2][1])
          xp3, yp3 = g2l(c1[0], c1[1])
          rp2, _ = g2lr(cpr[-2][-1], 0.0)
          tags = "e0", "e"+str(len(cpr))
                items, ct = tkRoadNode(xp1, yp1, xp2, yp2, xp3, yp3, rp2, dc, fi, tags)
    dc.delete(items[2])
    ctr[-2] = l2g(*ct)
    print "----------------------------------------------"
    for c1 in cpr: print c1
    c1 = None; r1 = rdef
          proj[2].thanCom.thanAppend("%s%d\n" % (T["Radius="], r1), "info1")
          if c1 == "u":
      del cpr[-1], ctr[-1]
    else:
      break
  if c1 == "c":
      proj[2].thanCom.thanAppend("Road close has not yet been impemented :)\n")

  dc.delete("e0")
        self.thanSet(cpr)
        return True                              # Road OK


    def __getPointLin(self, win, c1, c2, c3, r3, np):
        "Gets a point from the user, with possible options."
  if np == 3:
      stat1 = T["Next road point (radius/undo/<enter>): "]
      return win.thanGudGetRoadP(c1, c2, c3, r3, stat1, options=("radius", "undo", ""))
  else:
      stat1 = T["Next road point (radius/undo/close/<enter>): "]
      return win.thanGudGetRoadP(c1, c2, c3, r3, stat1, options=("radius", "undo", "close", ""))

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

    def thanTkDraw(self, than):
        "Draws the road to a Tk Canvas."
  g2l = than.ct.global2Local
  g2lr = than.ct.global2LocalRel
  dc = than.dc
  fi = than.outline
  tags = self.thanTags
  xp1, yp1 = g2l(self.cpr[0][0], self.cpr[0][1])
  xp2, yp2 = g2l(self.cpr[1][0], self.cpr[1][1])

  n = len(self.cpr)
  if n < 3:
            item = dc.create_line(xp1, yp1, xp2, yp2, fill=fi, tags=tags)
      return
        for i in xrange(1, n-1):
            xp3, yp3 = g2l(self.cpr[i+1][0], self.cpr[i+1][1])
      rp2, _ = g2lr(self.cpr[i][-1], 0.0)
            items, ct = tkRoadNode(xp1, yp1, xp2, yp2, xp3, yp3, rp2, dc, fi, tags)
         if i < n-2: dc.delete(items[2])
      xp1, yp1 = ct
      xp2, yp2 = xp3, yp3

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

    def thanLength(self):
        "Returns the length of the road."
        Tp = le = 0.0
        for a,b,c in iterby3(self.cpr):   #Note that this is not executed if len(cpr) < 3
            nod = calcRoadNode(a[0], a[1], b[0], b[1], c[0], c[1], b[-1])
      ab = hypot(b[0]-a[0], b[1]-a[1])
      le += ab-Tp-nod.T1+nod.LK
      Tp = nod.T1
        a, b = self.cpr[-2:]
  ab = hypot(b[0]-a[0], b[1]-a[1])
  le += ab-Tp        # Note that if len(cpr) < 3, then Tp=0.0 and le=ab
  return le

    def thanArea(self):
        """Finds the area of the curve defined by the road.

  That is if we imagine a line which joins the first and last point
  of the road.
  At first a polygon by the first, all the As end Ts of the circular arcs
  and the last node is constructed, and its area is computed. Then
  the areas between the arcs and the polygon are added.
  """
  cs = [self.cpr[0]]
  aarc = 0.0
        for a,b,c in iterby3(self.cpr):   #Note that this is not executed if len(cpr) < 3
            nod = calcRoadNode(a[0], a[1], b[0], b[1], c[0], c[1], b[-1])
            cs.append([nod.pa.x, nod.pa.y])
      cs.append([nod.pt.x, nod.pt.y])
      asec = nod.phi*0.5*nod.R**2
      atri = nod.R*cos(nod.phi*0.5)*nod.R*sin(nod.phi*0.5)
      aarc += asec-atri
        cs.append(self.cpr[-1])
  cs.append(self.cpr[0])
  return p_ggeom.area(cs) + aarc


    def thanExpDxf(self, fDxf):
        "Exports the road to dxf file."
  if len(self.cpr) < 3:
      for c1 in self.cpr:
          fDxf.thanDxfPlotPolyVertex(c1[0], c1[1], 2)
      fDxf.thanDxfPlotPolyVertex(0.0, 0.0, 999)
      return
        c1 = self.cpr[0]
  fDxf.thanDxfPlotPolyVertex(c1[0], c1[1], 2)
  for i in xrange(2, len(self.cpr)):
      c2 = self.cpr[i-1]
      c3 = self.cpr[i]
      r = c2[-1]
      nod = calcRoadNode(c1[0], c1[1], c2[0], c2[1], c3[0], c3[1], r)
      dchord2 = hypot(nod.pt.x-nod.pa.x, nod.pt.y-nod.pa.y) * 0.5
      dbulge = r - sqrt(r**2 - dchord2**2)
      bulge = dbulge/dchord2 * nod.pr    # nod.pr is the sign

#      fDxf.thanDxfPlotPolyArc(nod.pa.x, nod.pa.y, bulge)
      fDxf.thanDxfPlotPolyVertex(nod.pa.x, nod.pa.y, 2, bulge)

      fDxf.thanDxfPlotPolyVertex(nod.pt.x, nod.pt.y, 2)
      c1 = [nod.pt.x, nod.pt.y, 0.0]
  c1 = self.cpr[-1]
  fDxf.thanDxfPlotPolyVertex(c1[0], c1[1], 2)
  fDxf.thanDxfPlotPolyVertex(0.0, 0.0, 999)

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

    def thanExpBrk(self, than):
        "Exports the road 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 road to a PIL raster image."
  from thandr import ThanLine,ThanArc
  if len(self.cpr) < 3:
      e = ThanLine()
      e.thanSet(self.cpr)
      e.thanExpPil(than)
      return
        c1 = self.cpr[0]
  for i in xrange(2, len(self.cpr)):
      c2 = self.cpr[i-1]
      c3 = self.cpr[i]
      nod = calcRoadNode(c1[0], c1[1], c2[0], c2[1], c3[0], c3[1], c2[-1])
      e = ThanLine()
      e.thanSet([c1, [nod.pa.x, nod.pa.y, 0.0]])
      e.thanExpPil(than)
      e = ThanArc()
      e.thanSet([nod.pc.x, nod.pc.y, 0.0], c2[-1], nod.theta1*pi/180, nod.theta2*pi/180)
      e.thanExpPil(than)
      c1 = [nod.pt.x, nod.pt.y, 0.0]
  e = ThanLine()
  e.thanSet([c1, self.cpr[-1]])
  e.thanExpPil(than)

    def thanList(self, than):
        "Shows information about the road element."
  wr = than.write
  coo = than.strcoo
  dis = than.strdis
  cpr = self.cpr
  than.writecom("Element: ROAD")
  wr("    Layer: % s\n" % than.laypath)
  wr("Length: %s    Area: %s\n" % (dis(self.thanLength()), dis(self.thanArea())))
  wr("Vertices (X Y Z Radius):\n")
  wr("    %s\n" % coo(cpr[0][:-1]))
  n = len(cpr) - 1
        for i in xrange(1, n):
      wr("    %s radius=%s\n" % (coo(cpr[i][:-1]), dis(cpr[i][-1])))
  wr("    %s\n" % coo(cpr[n][:-1]))

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.