##############################################################################
# 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.
Package which processes commands entered by the user.
This module provides for a modification commands.
"""
from math import pi,hypot
from itertools import izip
from p_gmath import thanNear2
from thanvar import Canc,thanFiletCalc,ThanLayerError
from thantrans import T
import thancomsel
from selutil import thanSel1line,thanSel1breakable,thanSel2linsegs,thanSelCutting,thanSelMultlines
def thanModContline(proj):
"Continues a previous line."
lin = proj[1].thanPrevLine()
if lin == None: return thanModCanc(proj, T["Invalid previous line."])
proj[2].thanTkSet(lin) # Set the attributes of lin's layer
lin.thanTkContinue(proj)
proj[2].thanTkSet() # Set the attribute of current layer
thanModEnd(proj) # 'Reset color' is not needed, but it is called for only 1..
# ..element, so it is fast
def thanModExtendline(proj):
"Continues a previous line."
lin = thanSel1line(proj, T["Select a line to extend:\n"])
if lin == Canc: return thanModCanc(proj) # Line continue was cancelled
proj[2].thanTkSet(lin) # Set the attributes of lin's layer
lin.thanTkContinue(proj)
proj[2].thanTkSet() # Set the attribute of current layer
thanModEnd(proj) # 'Reset color' has already been called, but it is called again for only 1..
# ..element, so it is fast
#=============================================================================
def thanModBreak(proj):
"Breaks an element to 2 pieces if possible."
elem = thanSel1breakable(proj, "%s\n" % T["Select an element to break"])
if elem == Canc: return thanModCanc(proj) # Break was cancelled
c1 = proj[2].thanSel1coor
if c1 == None or elem.thanPntNearest(c1) == None:
c1 = __getNearPnt(proj, elem, T["First point of element to break: "])
if c1 == Canc: return thanModCanc(proj) # Break was cancelled
c2 = __getNearPnt(proj, elem, T["Second point of element to break: "])
if c2 == Canc: return thanModCanc(proj) # Break was cancelled
else:
c2 = __getNearPnt(proj, elem, T["Second point of element to break (F for first point): "], options=("first",))
if c2 == Canc: return thanModCanc(proj) # Break was cancelled
if c2 == "f":
c1 = __getNearPnt(proj, elem, T["First point of element to break: "])
if c1 == Canc: return thanModCanc(proj) # Break was cancelled
c2 = __getNearPnt(proj, elem, T["Second point of element to break: "])
if c2 == Canc: return thanModCanc(proj) # Break was cancelled
e1, e2 = elem.thanBreak(c1, c2)
if e1 == None and e2 == None: return thanModCanc(proj, T["Element can not be deleted; use 'ERASE'."])
__modBreakDo(proj, elem, e1, e2)
# proj[1].thanDoundo.thanAdd("break", thanModBreakRedo, (elems, c1, phi),
# thanModBreakUndo, (elems, c1, phi, selold))
thanModEnd(proj) # 'Reset color' is ????
def __getNearPnt(proj, elem, stat1, options=()):
"Get a point and check if it is near the element."
statonce = ""
while True:
res = proj[2].thanGudGetPoint(stat1, statonce, options=options)
if res == Canc: return Canc # Break was cancelled
for opt in options:
if res == opt[:1]: return res
if elem.thanPntNearest(res) != None: return res
statonce = T["Point is not near element. Try again.\n"]
def __modBreakDo(proj, elem, e1, e2):
"Breaks selected elements; it actualy does the job."
import time
t1 = time.time(); proj[2].thanGudSetSelDel()
t2 = time.time(); proj[1].thanReplaceSel(proj, elem, e1, e2) # ThanTouch is implicitely called
t3 = time.time()
print "Break time: canvas=%.2f elements=%.2f sum=%.2f (secs)" % (t2-t1, t3-t2, t3-t1)
def thanModBreakRedo(proj, elems, xc, yc, phi):
"Rebreaks the previously glued element."
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(elems)
__modRotateDo(proj, xc, yc, phi)
def thanModBreakUndo(proj, elems, xc, yc, phi, selold):
"Glues the oreviously broken element."
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(elems)
__modRotateDo(proj, xc, yc, -phi)
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(selold)
#=============================================================================
def thanModTrim(proj):
"""Trims elements using other elements as cutting edges, if possible.
Note that the selection this command does, is the selection of the cutting
edges. This selection is cancelled if the command is cancelled. And this
is the "previous" selection of next command to be given to ThanCad.
The selections of 1 breakable element are not recorded.
"""
from thandr import thanintall
selallold = proj[2].thanSelall
elcut = thanSelCutting(proj, T["Select elements to be used as cutting edges:\n"])
if elcut == Canc: return thanModCanc(proj) # Trim was cancelled
# proj[2].thanGudResetSelColor() # Leave the cutting edges marked
proj[2].thanUpdateLayerButton() # Show current layer again
opts = [""]
iel = 0
dodo = [] # Undo/Redo list
mes1 = T["Select an element to trim"]
while True:
opts = []
if iel > 0: opts.append("undo")
if len(dodo) > iel: opts.append("redo")
if len(opts) > 0: mes = "%s (%s): " % (mes1, "/".join(opts))
else: mes = "%s: " % mes1
opts.append("")
res = thancomsel.thanSelect1Gen(proj, mes, filter=lambda e: e.thanBreak(), options=opts)
if res == Canc: break # Trim was cancelled/ended
if res == "": break # Trim was cancelled/ended
if res == "u":
iel -= 1
elem, e1, e2 = dodo[iel]
proj[1].thanElementDelete((e for e in (e1, e2) if e != None), proj)
proj[1].thanElementRestore((elem,), proj)
proj[2].thanGudSetSelRestore() # Restores previous selection (the cutting edges)
continue
if res == "r":
elem, e1, e2 = dodo[iel]
proj[1].thanElementDelete((elem,), proj)
proj[1].thanElementRestore((e for e in (e1, e2) if e != None), proj)
iel += 1
proj[2].thanGudSetSelRestore() # Restores previous selection (the cutting edges)
continue
c1 = proj[2].thanSel1coor
assert c1 != None, "thancomsel.thanSelect1Gen does not work well!"
for elem in proj[2].thanSelall: break # Get the element
ps = []
for elcut1 in elcut:
ps.extend(thanintall.thanInt(elem, elcut1, proj))
if len(ps) < 1:
proj[2].thanCom.thanAppend(T["Element does not intersect cutting edges\n"], "can")
proj[2].thanGudResetSelColor() # Unmarks the selection
proj[2].thanGudSetSelRestore() # Restores previous selection (the cutting edges)
proj[2].thanUpdateLayerButton() # Show current layer again
continue
e1, e2 = elem.thanTrim(ps, c1)
if e1 == None and e2 == None:
proj[2].thanCom.thanAppend(T["Element can not be deleted; use 'ERASE' instead.\n"], "can")
proj[2].thanGudResetSelColor() # Unmarks the selection
proj[2].thanGudSetSelRestore() # Restores previous selection (the cutting edges)
proj[2].thanUpdateLayerButton() # Show current layer again
continue
__modBreakDo(proj, elem, e1, e2)
# proj[2].thanGudResetSelColor() # Unmarks the selection; not needed: the element is deleted
proj[2].thanGudSetSelRestore() # Restores previous selection (the cutting edges)
proj[2].thanUpdateLayerButton() # Show current layer again
del dodo[iel:]
dodo.append((elem, e1, e2))
iel += 1
# proj[1].thanDoundo.thanAdd("trim", thanModBreakRedo, (elems, c1, phi),
# thanModBreakUndo, (elems, c1, phi, selold))
proj[2].thanGudResetSelColor() # Unmarks the selection
proj[2].thanGudSetSelRestore() # Restores previous selection (the cutting edges)
proj[2].thanGudResetSelColor() # Unmarks the selection (the cutting edges)
proj[2].thanUpdateLayerButton() # Show current layer again
proj[2].thanGudSetSeloldElem(selallold) # The selection before the command trim started
if iel == 0: return thanModCanc(proj) # Trim was cancelled: unselect cutting edges
thanModEnd(proj) # 'Reset color' is ????
#=============================================================================
def thanModRotate(proj):
"Rotates selected elements."
res = thancomsel.thanSelectGen(proj, standalone=False)
if res == Canc: return thanModCanc(proj) # Rotation cancelled
elems = proj[2].thanSelall
selold = proj[2].thanSelold
c1 = proj[2].thanGudGetPoint(T["Origin of rotation: "])
if c1 == Canc: return thanModCanc(proj) # Rotation cancelled
un = proj[1].thanUnits
st = "%s(%s): " % (T["Rotation angle"], un.anglunit)
phi = un.rad2unit(0.5*pi)
phi = proj[2].thanGudGetFloat(st, phi)
if phi == Canc: return thanModCanc(proj) # Rotation cancelled
phi = un.unit2rad(phi)
__modRotateDo(proj, c1, phi)
proj[1].thanDoundo.thanAdd("rotate", thanModRotateRedo, (elems, c1, phi),
thanModRotateUndo, (elems, c1, phi, selold))
thanModEnd(proj) # 'Reset color' is necessary here; OK!
def thanModEnd(proj, mes=None, mestype="can"):
"House keeping for normal end."
proj[2].thanGudResetSelColor() # Unmarks the selection
proj[2].thanUpdateLayerButton() # Show current layer again
proj[2].thanGudCommandEnd(mes, mestype)
def thanModCanc(proj, mes=None, mestype="can"):
"House keeping for user cancel."
proj[2].thanGudResetSelColor() # Unmarks the selection
proj[2].thanGudSetSelRestore() # Restores previous selection
proj[2].thanUpdateLayerButton() # Show current layer again
proj[2].thanGudCommandCan(mes, mestype) # Show prompt
def __modRotateDo(proj, cc, phi):
"Rotates selected elements; it actualy does the job."
import time
t1 = time.time(); proj[2].thanGudSetSelRotate(cc[0], cc[1], phi)
t2 = time.time(); proj[1].thanRotateSel(proj[2].thanSelall, cc, phi) # ThanTouch is implicitely called
t3 = time.time()
print "Rotate time: canvas=%.2f elements=%.2f sum=%.2f (secs)" % (t2-t1, t3-t2, t3-t1)
def thanModRotateRedo(proj, elems, cc, phi):
"Re-rotates the previously un-rotated elements."
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(elems)
__modRotateDo(proj, cc, phi)
def thanModRotateUndo(proj, elems, cc, phi, selold):
"Un-rotates the previously rotated elements."
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(elems)
__modRotateDo(proj, cc, -phi)
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(selold)
#=============================================================================
def thanModMirror(proj):
"Mirrors the selected elements."
res = thancomsel.thanSelectGen(proj, standalone=False)
if res == Canc: return thanModCanc(proj) # Mirror cancelled
elems = proj[2].thanSelall
selold = proj[2].thanSelold
c1 = proj[2].thanGudGetPoint(T["First point of mirror line: "])
if c1 == Canc: return thanModCanc(proj) # Mirror cancelled
while True:
c2 = proj[2].thanGudGetLine(c1, T["Second point of mirror line: "])
if c2 == Canc: return thanModCanc(proj) # Mirror cancelled
if not thanNear2(c1, c2): break
proj[2].thanCom.thanAppend("Second point coincides with first. Try again.\n", "can")
keeporig = proj[2].thanGudGetYesno(T["Keep original elements (<yes>/no): "], default="yes")
if keeporig == Canc: return thanModCanc(proj) # Mirror cancelled
t = [c2[0]-c1[0], c2[1]-c1[1]]
tt = hypot(t[0], t[1])
t[0] /= tt
t[1] /= tt
if keeporig:
dc = [0.0]*len(c1)
copelems = __modMirrorCopyDo(proj, elems, c1, t)
proj[1].thanDoundo.thanAdd("mirror", thanModCopyRedo, (elems, copelems),
thanModCopyUndo, (copelems, selold))
else:
__modMirrorDo(proj, c1, t)
proj[1].thanDoundo.thanAdd("mirror", thanModMirrorRedo, (elems, c1, t),
thanModMirrorUndo, (elems, c1, t, selold))
thanModEnd(proj) # 'Reset color' is necessary here; OK!
def __modMirrorCopyDo(proj, elems, c1, t):
"Copies selected elements; it actualy does the job."
import time
t1 = time.time();
dc = [0.0]*len(c1)
copelems = proj[1].thanCopySel(elems, dc) # thanTouch is implicitely called
proj[1].thanMirrorSel(copelems, c1, t)
t2 = time.time(); proj[2].thanGudDrawElemsMany(copelems)
t3 = time.time()
print "Mirror time: canvas=%.2f elements=%.2f sum=%.2f (secs)" % (t3-t2, t2-t1, t3-t1)
return copelems
def __modMirrorDo(proj, c1, t):
"Mirrors selected elements; it actualy does the job."
import time
t1 = time.time(); proj[2].thanGudSetSelMirror(c1[0], c1[1], t)
t2 = time.time(); proj[1].thanMirrorSel(proj[2].thanSelall, c1, t) # ThanTouch is implicitely called
t3 = time.time()
print "Mirror time: canvas=%.2f elements=%.2f sum=%.2f (secs)" % (t2-t1, t3-t2, t3-t1)
def thanModMirrorRedo(proj, elems, c1, t):
"Re-mirrors the previously un-mirrored elements."
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(elems)
__modMirrorDo(proj, c1, t)
def thanModMirrorUndo(proj, elems, c1, t, selold):
"Un-mirrors the previously mirrored elements."
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(elems)
__modMirrorDo(proj, c1, t)
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(selold)
#=============================================================================
def thanModReverse(proj):
"Reverses the orientation of the direction of lines."
res = thanSelMultlines(proj, 1, T["Select lines to reverse orientation of direction\n"], strict=False)
if res == Canc: return thanModCanc(proj) # Reverse cancelled
elems = proj[2].thanSelall
selold = proj[2].thanSelold #FIXME:This makes nose enese since thaSelMultlines
#may call thanselectgen many times
__modReverseDo(proj)
proj[1].thanDoundo.thanAdd("reverse", thanModReverseRedo, (elems, ),
thanModReverseUndo, (elems, selold))
thanModEnd(proj) # 'Reset color' is necessary here; OK!
def __modReverseDo(proj):
"Rotates selected elements; it actualy does the job."
import time
t1 = time.time() # nothing to do on the canvas
t2 = time.time(); proj[1].thanReverseSel(proj[2].thanSelall) # ThanTouch is implicitely called
t3 = time.time()
print "Reverse time: canvas=%.2f elements=%.2f sum=%.2f (secs)" % (t2-t1, t3-t2, t3-t1)
def thanModReverseRedo(proj, elems):
"Re-rotates the previously un-rotated elements."
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(elems)
__modReverseDo(proj, cc, phi)
def thanModReverseUndo(proj, elems, selold):
"Un-rotates the oreviously rotated elements."
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(elems)
__modReverseDo(proj)
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(selold)
#=============================================================================
def thanModExplode(proj):
"Explodes elements to (1 level) smaller elements."
res = thancomsel.thanSelectGen(proj, standalone=False)
if res == Canc: return thanModCanc(proj) # Explode was cancelled
elems = proj[2].thanSelall
selold = proj[2].thanSelold
__modExplodeDo(proj)
# proj[1].thanDoundo.thanAdd("rotate", thanModExplodeRedo, (elems, x1, y1, phi),
# thanModExplodeUndo, (elems, x1, y1, phi, selold))
thanModEnd(proj) # 'Reset color' is not needed since the exploded fragments are redrawn. So..
# ..if a large number of elements are exploded, this will slow down..
# the command. Here, there is room for optimisation!
def __modExplodeDo(proj):
"Rotates selected elements; it actualy does the job."
import time
t1 = time.time(); proj[2].thanGudSetSelDel()
t2 = time.time(); proj[1].thanExplodeSel(proj, proj[2].thanSelall) # ThanTouch is implicitely called
t3 = time.time()
print "Explode time: canvas=%.2f elements=%.2f sum=%.2f (secs)" % (t2-t1, t3-t2, t3-t1)
def thanModExplodeRedo(proj, elems, xc, yc, phi):
"Re-rotates the previously un-rotated elements."
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(elems)
__modRotateDo(proj, xc, yc, phi)
def thanModExplodeUndo(proj, elems, xc, yc, phi, selold):
"Un-rotates the oreviously rotated elements."
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(elems)
__modRotateDo(proj, xc, yc, -phi)
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(selold)
#=============================================================================
def thanModJoin(proj):
"Joins elements (lines) to bigger ones."
res = thancomsel.thanSelectGen(proj, standalone=False)
if res == Canc: return thanModCanc(proj) # Rotation cancelled
elems = proj[2].thanSelall
selold = proj[2].thanSelold
n = __modJoinDo(proj)
# proj[1].thanDoundo.thanAdd("rotate", thanModJoinRedo, (elems, x1, y1, phi),
# thanModJoinUndo, (elems, x1, y1, phi, selold))
thanModEnd(proj, "%d joined lines were produced." % n) # 'Reset color' is not needed..
# since the joined elements are redrawn. So if a large number of elements..
# (unlikely) are joined, this will slow down the command. Here,
# there is room for optimisation!
def __modJoinDo(proj):
"Rotates selected elements; it actualy does the job."
import time
t1 = time.time(); proj[2].thanGudSetSelDel()
t2 = time.time(); n=proj[1].thanJoinSel(proj, proj[2].thanSelall) # ThanTouch is implicitely called
t3 = time.time()
print "Explode time: canvas=%.2f elements=%.2f sum=%.2f (secs)" % (t2-t1, t3-t2, t3-t1)
return n
def thanModJoinRedo(proj, elems, xc, yc, phi):
"Re-rotates the previously un-rotated elements."
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(elems)
__modRotateDo(proj, xc, yc, phi)
def thanModJoinUndo(proj, elems, xc, yc, phi, selold):
"Un-rotates the oreviously rotated elements."
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(elems)
__modRotateDo(proj, xc, yc, -phi)
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(selold)
#=============================================================================
def thanModChlayer(proj):
"Changes the layer of selected elements."
res = thancomsel.thanSelectGen(proj, standalone=False)
if res == Canc: return thanModCanc(proj) # Rotation cancelled
elems = proj[2].thanSelall
selold = proj[2].thanSelold
res = proj[2].thanGudGetLayerleaf(T["Select new layer for the elements"])
if res == Canc: return thanModCanc(proj) # Rotation cancelled
laynew = res
__modChlayerDo(proj, laynew)
# proj[1].thanDoundo.thanAdd("chlayer", thanModChlayerRedo, (elems, laynew),
# thanModChlayerUndo, (elems, laynew, selold))
thanModEnd(proj) # 'Reset color' is necessary here (in fact, _it_ _is_ optimisation
def __modChlayerDo(proj, laynew):
"Changes the layer of selected elements; it actualy does the job."
import thanlayer, time
t1 = time.time()
if laynew.thanAtts["frozen"].thanVal:
proj[2].thanGudSetSelDel() # Deletes the canvas items, because the new layer is frozen
else:
tlays = set(elem.thanTags[1] for elem in proj[2].thanSelall)
assert len(tlays) > 0, "How come that no layers were found, when there is at least one element????"
dilay = proj[1].thanLayerTree.dilay
draworder = False
for tlay in tlays: # Find only the attributes which differ (and thus they must be changed)
lay = dilay[tlay]
tagged = False
for a in thanlayer.thanlayatts.thanLayAttsNames[2:]: # We know that lay is NOT frozen (otherwise the elements could not be selected:) )
nval = laynew.thanAtts[a].thanVal
val = lay.thanAtts[a].thanAct
if nval != val:
if a == "moncolor":
if False: # Optimisation: Since thanGudResetSelColor will be called, no need to change colour now
if not tagged: proj[2].thanGudGetSelLayerxs(lay.thanTag); tagged = True
from thandefs.thanatt import ThanAttCol
proj[2].thanGudSetSelColorx(ThanAttCol(nval).thanTk)
elif a == "draworder":
draworder = True
elif a == "penthick":
pass # Nothing visible changes
proj[2].thanGudSetSelLayertag(laynew.thanTag)
if draworder: proj[2].thanRedraw()
t2 = time.time()
for elem in proj[2].thanSelall:
tags = list(elem.thanTags)
lay = dilay[tags[1]]
lay.thanQuad.remove(elem)
laynew.thanQuad.add(elem)
tags[1] = laynew.thanTag
elem.thanTags = tuple(tags)
proj[1].thanTouch()
t3 = time.time()
print "Change layer time: canvas=%.2f elements=%.2f sum=%.2f (secs)" % (t2-t1, t3-t2, t3-t1)
def thanModChlayerRedo(proj, elems, laynew):
"Re-rotates the previously un-rotated elements."
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(elems)
__modRotateDo(proj, xc, yc, phi)
def thanModChlayerUndo(proj, elems, laynew, selold):
"Un-rotates the oreviously rotated elements."
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(elems)
__modRotateDo(proj, xc, yc, -phi)
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(selold)
#=============================================================================
def thanModScale(proj):
"""Scales selected elements.
FIXME: The limits (area iterated) of the visible drawing are probably changed
as well. It must be checked.
"""
res = thancomsel.thanSelectGen(proj, standalone=False)
if res == Canc: return thanModCanc(proj) # Scale was cancelled
elems = proj[2].thanSelall
selold = proj[2].thanSelold
c1 = proj[2].thanGudGetPoint(T["Origin of scale: "])
if c1 == Canc: return thanModCanc(proj) # Scale was cancelled
fact = 1.0
fact = proj[2].thanGudGetPosFloat(T["Scale factor: "], fact)
if fact == Canc: return thanModCanc(proj) # Scale was cancelled
__modScaleDo(proj, c1, fact)
proj[1].thanDoundo.thanAdd("scale", thanModScaleRedo, (elems, c1, fact),
thanModScaleUndo, (elems, c1, fact, selold))
thanModEnd(proj) # 'Reset color' is necessary here
def __modScaleDo(proj, cc, fact):
"Scales selected elements; it actualy does the job."
import time # thanScaleSel is called first, because thanGudSetSelScale call thanautoregen to re-render the images
t1 = time.time(); proj[1].thanScaleSel(proj[2].thanSelall, cc, fact) # ThanTouch is implicitely called
t2 = time.time(); proj[2].thanGudSetSelScale(cc[0], cc[1], fact)
t3 = time.time()
print "Scale time: canvas=%.2f elements=%.2f sum=%.2f (secs)" % (t3-t2, t2-t1, t3-t1)
def thanModScaleRedo(proj, elems, cc, fact):
"Re-scales the previously un-scaled elements."
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(elems)
__modScaleDo(proj, cc, fact)
def thanModScaleUndo(proj, elems, cc, fact, selold):
"Un-scales the oreviously scaled elements."
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(elems)
__modScaleDo(proj, cc, 1.0/fact)
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(selold)
#=============================================================================
def thanModMove(proj):
"Moves slelected elements."
res = thancomsel.thanSelectGen(proj, standalone=False)
if res == Canc: return thanModCanc(proj) # Move was cancelled
elems = proj[2].thanSelall
selold = proj[2].thanSelold
stat1 = T["Destination or <enter>: "]
# n = proj[1].thanVar["dimensionality"]
# dc = [0.0] * n
res = proj[2].thanGudGetPoint(T["Origin or Delta coordinates: "])
if res == Canc: return thanModCanc(proj) # Move was cancelled
dc = res
res = proj[2].thanGudGetMovend(dc, stat1, options=("",))
if res == Canc: return thanModCanc(proj) # Move was cancelled
if res != "":
for i in xrange(len(dc)): dc[i] = res[i] - dc[i]
__modMoveDo(proj, dc)
# proj[1].thanDoundo.thanAdd("move", thanModMoveRedo, (elems, dc),
# thanModMoveUndo, (elems, dc, selold))
thanModEnd(proj) # 'Reset color' is necessary here
def __modMoveDo(proj, dc):
"Moves selected elements; it actualy does the job."
import time
t1 = time.time(); proj[2].thanGudSetSelMove(dc[0], dc[1])
t2 = time.time(); proj[1].thanMoveSel(proj[2].thanSelall, dc) # thanTouch is implicitely called
t3 = time.time()
print "Move time: canvas=%.2f elements=%.2f sum=%.2f (secs)" % (t2-t1, t3-t2, t3-t1)
def thanModMoveRedo(proj, elems, cc, phi):
"Re-rotates the previously un-rotated elements."
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(elems)
__modRotateDo(proj, cc, phi)
#=============================================================================
def thanModCopy(proj):
"Copies selected elements."
res = thancomsel.thanSelectGen(proj, standalone=False)
if res == Canc: return thanModCanc(proj) # Copy was cancelled
elems = proj[2].thanSelall
selold = proj[2].thanSelold
stat1 = T["Destination or <enter>: "]
c1 = proj[2].thanGudGetPoint(T["Origin or Delta coordinates: "])
if c1 == Canc: return thanModCanc(proj) # Copy was cancelled
res = proj[2].thanGudGetMovend(c1, stat1, options=("",))
if res == Canc: return thanModCanc(proj) # Copy was cancelled
if res == "":
copelems = __modCopyDo(proj, elems, c1)
else:
dc = [b-a for a,b in izip(c1, res)]
copelems = __modCopyDo(proj, elems, dc)
while True: # Copy multiple mode
res = proj[2].thanGudGetMovend(c1, stat1, options=("",))
if res == Canc or res == "": break # Copy is ended
dc = [b-a for a,b in izip(c1, res)]
e1 = __modCopyDo(proj, elems, dc)
copelems.extend(e1)
proj[1].thanDoundo.thanAdd("copy", thanModCopyRedo, (elems, copelems),
thanModCopyUndo, (copelems, selold))
thanModEnd(proj) # 'Reset color' is necessary here
def __modCopyDo(proj, elems, dc):
"Copies selected elements; it actualy does the job."
import time
t1 = time.time(); copelems = proj[1].thanCopySel(elems, dc) # thanTouch is implicitely called
t2 = time.time(); proj[2].thanGudDrawElemsMany(copelems)
t3 = time.time()
print "Move time: canvas=%.2f elements=%.2f sum=%.2f (secs)" % (t3-t2, t2-t1, t3-t1)
return copelems
def thanModCopyRedo(proj, elems, copelems):
"Recopies the previously uncopied elements."
proj[1].thanElementRestore(copelems, proj)
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(elems)
def thanModCopyUndo(proj, copelems, selold):
"Uncopies the previously copied elements."
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(copelems)
__modEraseDo(proj)
proj[2].thanGudSetSelElem(selold)
#=============================================================================
def thanModOffset(proj):
"Offsets elements (1 by 1 to be compatible with thAtCad - WARNING CODE NOT FINISED."
vdef = proj[1].thanVar["useroffsetdistance"]
cdef = proj[1].thanUnits.strdis(vdef)
mes = "%s (%s/<%s>): " % (T["Distance to offset"], T["Through point"], cdef)
dis = proj[2].thanGudGetPosFloat(mes, default=vdef, options=("through",))
if dis == Canc: return thanModCanc(proj) # Offset cancelled
while True:
elem = thanSelect1(T["Select element to offset: "], options=("",))
if elem == Canc: return thanModCanc(proj) # Offset cancelled
if elem == "": return thanModEnd(proj) # Offset ended
if dis == "t":
ct = proj[2].thanGudGetPoint(T["Through point: "])
if ct == Canc: continue # Offset of _this_ element was cancelled
else:
proj[1].thanVar["useroffsetdistance"] = dis # Set new default only if user did not cancel
ct = proj[2].thanGudGetPoint(T["Choose direction of offset: "])
if ct == Canc: continue # Offset of _this_ element was cancelled
res = thancomsel.thanSelectGen(proj, standalone=False)
if res == Canc: return thanModCanc(proj) # Mirror cancelled
elems = proj[2].thanSelall
selold = proj[2].thanSelold
c1 = proj[2].thanGudGetPoint(T["First point of mirror line: "])
if c1 == Canc: return thanModCanc(proj) # Mirror cancelled
while True:
c2 = proj[2].thanGudGetLine(c1, T["Second point of mirror line: "])
if c2 == Canc: return thanModCanc(proj) # Mirror cancelled
if not thanNear2(c1, c2): break
proj[2].thanCom.thanAppend("Second point coincides with first. Try again.\n", "can")
keeporig = proj[2].thanGudGetYesno(T["Keep original elements (<yes>/no): "], default="yes")
if keeporig == Canc: return thanModCanc(proj) # Mirror cancelled
t = [c2[0]-c1[0], c2[1]-c1[1]]
tt = hypot(t[0], t[1])
t[0] /= tt
t[1] /= tt
if keeporig:
dc = [0.0]*len(c1)
copelems = __modMirrorCopyDo(proj, elems, c1, t)
proj[1].thanDoundo.thanAdd("mirror", thanModCopyRedo, (elems, copelems),
thanModCopyUndo, (copelems, selold))
else:
__modMirrorDo(proj, c1, t)
proj[1].thanDoundo.thanAdd("mirror", thanModMirrorRedo, (elems, c1, t),
thanModMirrorUndo, (elems, c1, t, selold))
thanModEnd(proj) # 'Reset color' is necessary here; OK!
def __modMirrorCopyDo(proj, elems, c1, t):
"Copies selected elements; it actualy does the job."
import time
t1 = time.time();
dc = [0.0]*len(c1)
copelems = proj[1].thanCopySel(elems, dc) # thanTouch is implicitely called
proj[1].thanMirrorSel(copelems, c1, t)
t2 = time.time(); proj[2].thanGudDrawElemsMany(copelems)
t3 = time.time()
print "Mirror time: canvas=%.2f elements=%.2f sum=%.2f (secs)" % (t3-t2, t2-t1, t3-t1)
return copelems
def __modMirrorDo(proj, c1, t):
"Mirrors selected elements; it actualy does the job."
import time
t1 = time.time(); proj[2].thanGudSetSelMirror(c1[0], c1[1], t)
t2 = time.time(); proj[1].thanMirrorSel(proj[2].thanSelall, c1, t) # ThanTouch is implicitely called
t3 = time.time()
print "Mirror time: canvas=%.2f elements=%.2f sum=%.2f (secs)" % (t2-t1, t3-t2, t3-t1)
def thanModMirrorRedo(proj, elems, c1, t):
"Re-mirrors the previously un-mirrored elements."
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(elems)
__modMirrorDo(proj, c1, t)
def thanModMirrorUndo(proj, elems, c1, t, selold):
"Un-mirrors the previously mirrored elements."
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(elems)
__modMirrorDo(proj, c1, t)
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(selold)
#=============================================================================
def thanModDDedit(proj):
"Prompts the user to alter the text of a ThanText object."
from thandr import ThanText
first = True
while True:
elem = thancomsel.thanSelect1(proj, T["Select text to edit: "], filter=lambda e: isinstance(e, ThanText))
if elem == Canc:
if first: return thanModCanc(proj) # DDedit cancelled
else: break # DDedit ended
textold = elem.text
textnew = proj[2].thanGudGetText1(T["Edit text"], textDefault=textold)
if textnew == Canc: continue # DDedit of this text was cancelled; ask for other
elems = [elem]
selold = proj[2].thanSelold
__modDDeditDo(proj, elem, textnew)
proj[1].thanDoundo.thanAdd("ddedit", thanModDDeditRedo, (elems, textnew),
thanModDDeditUndo, (elems, textold, selold))
first = False
thanModEnd(proj, "")
def __modDDeditDo(proj, elem, text):
"Rotates selected elements; it actualy does the job."
than = proj[2].than
lt = proj[1].thanLayerTree
thanCur1 = lt.thanCur
dilay = lt.dilay
lay = dilay[elem.thanTags[1]]
if lay != thanCur1: lay.thanTkSet(than, proj[1].thanTstyles)
elem.thanSet(text, elem.c1, elem.size, elem.theta)
proj[2].thanGudSetSelDel() # Delete the text from the canvas
elem.thanTkDraw(than) # Draw the new text
if lay != thanCur1: thanCur1.thanTkSet(than, proj[1].thanTstyles)
proj[1].thanTouch()
def thanModDDeditRedo(proj, elems, text):
"Re-rotates the previously un-rotated elements."
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(elems)
__modDDeditDo(proj, elems[0], text)
def thanModDDeditUndo(proj, elems, textold, selold):
"Un-rotates the previously rotated elements."
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(elems)
__modDDeditDo(proj, elems[0], textold)
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(selold)
#=============================================================================
def thanModErase(proj):
"Erases selected elements."
res = thancomsel.thanSelectGen(proj, standalone=False)
if res == Canc: return thanModCanc(proj) # Erase was cancelled
elems = proj[2].thanSelall
selold = proj[2].thanSelold
__modEraseDo(proj)
proj[1].thanDoundo.thanAdd("erase", thanModEraseRedo, (elems,),
thanModEraseUndo, (elems, selold))
thanModEnd(proj) # 'Reset color' is completely unnecessary here, and it will slow..
# ..e command down. Room for optimisation here.
def __modEraseDo(proj):
"Erases selected elements; it actualy does the job."
import time
t1 = time.time(); proj[2].thanGudSetSelDel()
t2 = time.time(); proj[1].thanDelSel(proj[2].thanSelall) # thanTouch is implicitely called
t3 = time.time()
print "Erase time: canvas=%.2f elements=%.2f sum=%.2f (secs)" % (t2-t1, t3-t2, t3-t1)
proj[2].thanGudSetSelClear()
def thanModEraseRedo(proj, elems):
"Erases selected elements; it actualy does the job."
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(elems)
__modEraseDo(proj)
def thanModEraseUndo(proj, elems, selold):
"UnErases elements; elements' structure is considered complete."
proj[1].thanElementRestore(elems, proj)
proj[2].thanGudSetSelClear()
proj[2].thanGudSetSelElem(selold)
#=============================================================================
def thanModPurge(proj):
"Purges unused declarations; for the moment unused layer declarations (but not the currrent and its parents)."
lt = proj[1].thanLayerTree
cl = proj[1].thanLayerTree.thanCur
cl.thanQuad.add(None) # Make current layer non Empty
delnot = set((lt.thanRoot, lt.thanRoot.thanChildren[0])) # Layers which must not be deleted
delyes = set() # Layers that are going to deleted
try:
emptyFound = __purgeLay(proj, lt.thanRoot, delnot, delyes)
except ThanLayerError:
cl.thanQuad.remove(None)
return thanModCanc(proj) # user cancelled purge
if not emptyFound:
cl.thanQuad.remove(None)
return proj[2].thanGudCommandEnd("No unused layers.")
if len(delyes) == 0:
cl.thanQuad.remove(None)
return proj[2].thanGudCommandEnd("No layers were purged.")
for chlay in delyes:
lay = chlay.thanParent
chlay.thanUnlink() # remove chlay and hierarchy from parent's children
chlay.thanDestroy() # Delete chaly and hierarchy
if len(lay.thanChildren) == 0: # This is leaf layer now; it can hold elements
lay.thanQuad = set()
lay.thanTag = lay.lt.thanIdLay.new() # In order to exploit TK mechanism
cl.thanQuad.remove(None)
lt.thanDictRebuild() # Inform about the new leaf layers
proj[1].thanTouch() # Drawinh has been modified
proj[2].thanGudCommandEnd() # thanModEnd() does not carry a benefit here; no elements were selected..
def __purgeLay(proj, lay, delnot, delyes):
"Ask recursively the empty layers to be deleted."
emptyFound = False
for chlay in lay.thanChildren:
if chlay in delnot: continue # These layers can not be deleted
if not chlay.thanIsEmpty(): continue # Layer not empty
emptyFound = True
ans = proj[2].thanGudGetYesno(T["Delete empty layer %s (enter=no): "] %
chlay.thanGetPathname(), default="no")
if ans == Canc: raise ThanLayerError, "User cancelled purge"
if ans: delyes.add(chlay)
for chlay in lay.thanChildren:
if chlay in delyes: continue # Already marked for deletion
emptyFound1 = __purgeLay(proj, chlay, delnot, delyes)
emptyFound = emptyFound or emptyFound1
return emptyFound
#=============================================================================
def thanModFilet(proj):
"Xtends and joins 2 line segments with circular arc."
res = thanSel2linsegs(proj, T["Select two sinle segment lines to filet:\n"])
if res == Canc: return thanModCanc(proj) # Filet was cancelled
aa, bb = proj[2].thanSelall
a, b = aa.thanClone(), bb.thanClone()
rr = 5.0
ierr, obj = thanFiletCalc(a, b, rr)
if ierr == 1: return thanModCanc(T["End lines are parallel and do not intersect"])
if ierr == 2: return thanModCanc(T["Circular arc lies beyond the line segments"])
assert ierr == 0
a.thanTags = aa.thanTags
b.thanTags = bb.thanTags
elems = proj[2].thanSelall
selold = proj[2].thanSelold
__modFiletDo(proj, a, b, obj)
# proj[1].thanDoundo.thanAdd("filet", thanModEraseRedo, (elems,),
# thanModEraseUndo, (elems, selold))
thanModEnd(proj) # 'Reset color' is completely unnecessary here, and it will slow..
# ..e command down. Room for optimisation here.
def __modFiletDo(proj, a, b, obj):
"Erases selected elements; it actualy does the job."
import time
from thandr import ThanArc
proj[2].thanGudSetSelDel()
a.thanTkDraw(proj[2].than)
b.thanTkDraw(proj[2].than)
if obj == None: return
arc = ThanArc()
arc.thanSet(*obj)
proj[1].thanElementAdd(a)
arc.thanTkDraw(proj[2].than)
#def __sel2lines(proj):
# "Selects 2 lines to filet."
# from thandr import ThanLine
# while True:
# elems = []
# proj[2].thanCom.thanAppend(T["Select two sinle segment lines to filet:\n"], "info1")
# res = thancomsel.thanSelectGen(proj, standalone=False)
# proj[2].thanGudResetSelColor()
# if res == Canc: return Canc
# for elem in proj[2].thanSelall:
# if isinstance(elem, ThanLine) and len(elem.cp) == 2: elems.append(elem)
# if len(elems) == 2: break
# proj[2].thanCom.thanAppend(T["Two single segment line is required (%d found). Try again.\n"]%len(elems), "can")
# return True
|