#
# Copyright (c) 2002, 2003, 2004, 2005, 2006 Art Haas
#
# This file is part of PythonCAD.
#
# PythonCAD 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.
#
# PythonCAD 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.
#
# You should have received a copy of the GNU General Public License
# along with PythonCAD; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#
# The Layer class
#

import sys
import types

from PythonCAD.Generic import color
from PythonCAD.Generic import linetype
from PythonCAD.Generic import style
from PythonCAD.Generic import point
from PythonCAD.Generic import segment
from PythonCAD.Generic import circle
from PythonCAD.Generic import arc
from PythonCAD.Generic import hcline
from PythonCAD.Generic import vcline
from PythonCAD.Generic import acline
from PythonCAD.Generic import cline
from PythonCAD.Generic import ccircle
from PythonCAD.Generic import segjoint
from PythonCAD.Generic import leader
from PythonCAD.Generic import polyline
from PythonCAD.Generic import text
from PythonCAD.Generic import dimension
from PythonCAD.Generic import dimtrees
from PythonCAD.Generic import tolerance
from PythonCAD.Generic import entity
from PythonCAD.Generic import logger
from PythonCAD.Generic import graphicobject
from PythonCAD.Generic import units
from PythonCAD.Generic import util

class Layer(entity.Entity):
    """The Layer class.

A Layer object holds all the various entities that can be
in a drawing. Each layer can have sublayers, and there is
no limit to the depth of the sublayering.

A Layer object has several attributes:

name: The Layer's name
parent: The parent Layer of the Layer
scale: The scale factor for object contained in the Layer

A Layer object has the following methods:

{get/set}Name(): Get/Set the Layer's name.
{get/set}ParentLayer(): Get/Set the Layer's parent.
{add/del}Sublayer(): Add/Remove a sublayer to this Layer.
hasSublayers(): Test if this Layer has sublayers.
getSublayers(): Return any sublayers of this Layer.
{add/del}Object(): Store/Remove a Point, Segment, etc. in the Layer.
findObject(): Return an object in the layer equivalent to a test object.
find(): Search for an object within the Layer.
getObject(): Return an object with a specified ID
mapPoint(): See if a non-Point object in the layer crosses some location.
hasEntities(): Test if the Layer contains any entities
hasEntityType(): Test if the Layer contains a particular entity type.
getLayerEntities(): Return all the instances of an entity within the Layer.
getBoundary(): Find the maximum and minimum coordinates of the Layer.
objsInRegion(): Return all the objects in the Layer that can be seen
                within some view.
{get/set}DeletedEntityData(): Get/Set the deleted entity values in the Layer
    """

    __messages = {
        'name_changed' : True,
        'scale_changed' : True,
        'added_sublayer' : True,
        'deleted_sublayer' : True,
        }
    
    def __init__(self, name=None, **kw):
        """Initializee a Layer.

Layer([name)

Argument name is optional. The name should be a unicode string
if specified, otherwise a default name of 'Layer' is given.
        """
        _n = name
        if _n is None:
            _n = u'Layer'
        if not isinstance(_n, types.StringTypes):
            raise TypeError, "Invalid layer name type: " + `type(name)`
        if isinstance(name, str):
            _n = unicode(name)
        super(Layer, self).__init__(**kw)
        self.__name = _n
        self.__points = point.PointQuadtree()
        self.__segments = segment.SegmentQuadtree()
        self.__circles = circle.CircleQuadtree()
        self.__arcs = arc.ArcQuadtree()
        self.__hclines = hcline.HCLineQuadtree()
        self.__vclines = vcline.VCLineQuadtree()
        self.__aclines = acline.ACLineQuadtree()
        self.__clines = cline.CLineQuadtree()
        self.__ccircles = ccircle.CCircleQuadtree()
        self.__chamfers = [] # should be Quadtree
        self.__fillets = [] # should be Quadtree
        self.__leaders = leader.LeaderQuadtree()
        self.__polylines = polyline.PolylineQuadtree()
        self.__textblocks = [] # should be Quadtree
        self.__ldims = dimtrees.LDimQuadtree()
        self.__hdims = dimtrees.HDimQuadtree()
        self.__vdims = dimtrees.VDimQuadtree()
        self.__rdims = dimtrees.RDimQuadtree()
        self.__adims = dimtrees.ADimQuadtree()
        self.__scale = 1.0
        self.__parent_layer = None
        self.__sublayers = None
        #
        # self.__objects keeps a reference to all objects stored in the layer
        #
        self.__objects = {}
        self.__objids = {}
        self.__logs = {}

    def __str__(self):
        _p = self.__parent_layer
        if _p is None:
            _s = "Layer: %s [No Parent Layer]" % self.__name
        else:
            _s = "Layer: %s; Parent Layer: %s" % (self.__name, _p.getName())
        return _s

    def __contains__(self, obj):
        """Find an object in the Layer.

This method permits the use of 'in' for test conditions.

if obj in layer:
    ....

This function tests for Point, Segment, Circle, etc. It returns
True if there is an equivalent object held in the Layer. Otherwise
the function returns False.
        """
        _seen = False
        if id(obj) in self.__objects:
            _seen = True
        if not _seen:
            if isinstance(obj, point.Point):
                _x, _y = obj.getCoords()
                _seen = (len((self.__points.find(_x, _y))) > 0)
            elif isinstance(obj, segment.Segment):
                _p1, _p2 = obj.getEndpoints()
                _x1, _y1 = _p1.getCoords()
                _x2, _y2 = _p2.getCoords()
                _seen = (len(self.__segments.find(_x1, _y1, _x2, _y2)) > 0)
            elif isinstance(obj, arc.Arc):
                _x, _y = obj.getCenter().getCoords()
                _r = obj.getRadius()
                _sa = obj.getStartAngle()
                _ea = obj.getEndAngle()
                _seen = (len(self.__arcs.find(_x, _y, _r, _sa, _ea)) > 0)
            elif isinstance(obj, circle.Circle):
                _x, _y = obj.getCenter().getCoords()
                _r = obj.getRadius()
                _seen = (len(self.__circles.find(_x, _y, _r)) > 0)
            elif isinstance(obj, hcline.HCLine):
                _y = obj.getLocation().y
                _seen = (len(self.__hclines.find(_y)) > 0)
            elif isinstance(obj, vcline.VCLine):
                _x = obj.getLocation().x
                _seen = (len(self.__vclines.find(_x)) > 0)
            elif isinstance(obj, acline.ACLine):
                _x, _y = obj.getLocation().getCoords()
                _angle = obj.getAngle()
                _seen = (len(self.__aclines.find(_x, _y, _angle)) > 0)
            elif isinstance(obj, cline.CLine):
                _p1, _p2 = obj.getKeypoints()
                _x1, _y1 = _p1.getCoords()
                _x2, _y2 = _p2.getCoords()
                _seen = (len(self.__clines.find(_x1, _y1, _x2, _y2)) > 0)
            elif isinstance(obj, ccircle.CCircle):
                _x, _y = obj.getCenter().getCoords()
                _r = obj.getRadius()
                _seen = (len(self.__ccircles.find(_x, _y, _r)) > 0)
            elif isinstance(obj, segjoint.Fillet):
                _seen = obj in self.__fillets
            elif isinstance(obj, segjoint.Chamfer):
                _seen = obj in self.__chamfers
            elif isinstance(obj, leader.Leader):
                _p1, _p2, _p3 = obj.getPoints()
                _x1, _y1 = _p1.getCoords()
                _x2, _y2 = _p2.getCoords()
                _x3, _y3 = _p3.getCoords()
                _seen = (len(self.__leaders.find(_x1, _y1, _x2, _y2,
                                                 _x3, _y3)) > 0)
            elif isinstance(obj, polyline.Polyline):
                _coords = []
                for _pt in obj.getPoints():
                    _coords.extend(_pt.getCoords())
                _seen = (len(self.__polylines.find(_coords)) > 0)
            elif isinstance(obj, text.TextBlock):
                _seen = obj in self.__textblocks
            elif isinstance(obj, dimension.HorizontalDimension):
                _l1, _l2 = obj.getDimLayers()
                _p1, _p2 = obj.getDimPoints()
                _seen = (len(self.__hdims.find(_l1, _p1, _l2, _p2)) > 0)
            elif isinstance(obj, dimension.VerticalDimension):
                _l1, _l2 = obj.getDimLayers()
                _p1, _p2 = obj.getDimPoints()
                _seen = (len(self.__vdims.find(_l1, _p1, _l2, _p2)) > 0)
            elif isinstance(obj, dimension.LinearDimension):
                _l1, _l2 = obj.getDimLayers()
                _p1, _p2 = obj.getDimPoints()
                _seen = (len(self.__ldims.find(_l1, _p1, _l2, _p2)) > 0)
            elif isinstance(obj, dimension.RadialDimension):
                _l1 = obj.getDimLayer()
                _c1 = obj.getDimCircles()
                _seen = (len(self.__rdims.find(_l1, _c1)) > 0)
            elif isinstance(obj, dimension.AngularDimension):
                _vl, _l1, _l2 = obj.getDimLayers()
                _vp, _p1, _p2 = obj.getDimPoints()
                _dims = self.__adims.find(_vl, _vp, _l1, _p1, _l2, _p2)
                _seen = len(_dims) > 0
            else:
                raise TypeError, "Invalid type for in operation: " + `type(obj)`
        return _seen

    def clear(self):
        """Remove all the entities stored in this layer

clear()
        """
        if self.isLocked():
            raise RuntimeError, "Clearing layer not allowed - layer locked."
        for _obj in self.__adims.getObjects():
            self.delObject(_obj)
        for _obj in self.__rdims.getObjects():
            self.delObject(_obj)
        for _obj in self.__vdims.getObjects():
            self.delObject(_obj)
        for _obj in self.__hdims.getObjects():
            self.delObject(_obj)
        for _obj in self.__ldims.getObjects():
            self.delObject(_obj)
        for _obj in self.__textblocks:
            self.delObject(_obj)
        for _obj in self.__polylines.getObjects():
            self.delObject(_obj)
        for _obj in self.__leaders.getObjects():
            self.delObject(_obj)
        for _obj in self.__chamfers:
            self.delObject(_obj)
        for _obj in self.__fillets:
            self.delObject(_obj)
        for _obj in self.__ccircles.getObjects():
            self.delObject(_obj)
        for _obj in self.__clines.getObjects():
            self.delObject(_obj)
        for _obj in self.__aclines.getObjects():
            self.delObject(_obj)
        for _obj in self.__vclines.getObjects():
            self.delObject(_obj)
        for _obj in self.__hclines.getObjects():
            self.delObject(_obj)
        for _obj in self.__arcs.getObjects():
            self.delObject(_obj)
        for _obj in self.__circles.getObjects():
            self.delObject(_obj)
        for _obj in self.__segments.getObjects():
            self.delObject(_obj)
        for _obj in self.__points.getObjects():
            self.delObject(_obj)
        self.setScale(1.0)

    def getName(self):
        """Return the name of the Layer.

getName()
        """
        return self.__name

    def setName(self, name):
        """Set the name of the Layer.

setName(name)

The new must be a string, and cannot be None.
        """
        _n = name
        if _n is None:
            raise ValueError, "Layers must have a name."
        if not isinstance(_n, types.StringTypes):
            raise TypeError, "Invalid name type: " + `type(_n)`
        if isinstance(_n, str):
            _n = unicode(_n)
        _on = self.__name
        if _on != _n:
            self.startChange('name_changed')
            self.__name = _n
            self.endChange('name_changed')
            self.sendMessage('name_changed', _on)
            self.modified()

    name = property(getName, setName, None, "Layer name.")

    def getValues(self):
        """Return values comprising the Layer.

getValues()

This method extends the Entity::getValues() method.
        """
        _data = super(Layer, self).getValues()
        _data.setValue('type', 'layer')        
        _pid = None
        if self.__parent_layer is not None:
            _pid = self.__parent_layer.getID()
        _data.setValue('parent_layer', _pid)
        _data.setValue('name', self.__name)
        _data.setValue('scale', self.__scale)
        return _data

    def setDeletedEntityData(self, data):
        """Fill in the deleted entity data.

setDeletedEntityData(data)

Argument 'data' must be a dictionary with the keys being
entity id values (integers) and the dictionary values as Logger
instances.
        """
        if not isinstance(data, dict):
            raise TypeError, "Invalid dictionary type: " + `type(data)`
        if len(self.__logs) != 0:
            raise ValueError, "Deleted data already stored"
        for _key in data:
            if not isinstance(_key, int):
                raise TypeError, "Invalid entity id type: " + `type(_key)`
            _val = data[_key]
            if not isinstance(_val, logger.Logger):
                raise TypeError, "Invalid entity log type: " + `type(_val)`
            self.__logs[_key] = _val
        
    def getDeletedEntityData(self):
        """Return the stored log data for deleted entities.

getDeletedEntityData()

This method returns a dictionary.
        """
        return self.__logs.copy()
    
    def addObject(self, obj):
        """Add an object to this Layer.

addObject(obj)

The object should be a Point, Segment, Arc, Circle,
HCLine, VCLine, ACLine, CLine, CCircle, TextBlock, Chamfer,
Fillet, Leader, Polyline, or Dimension. Anything else raises
a TypeError exception.
        """
        if self.isLocked():
            raise RuntimeError, "Adding entity not allowed - layer locked."
        if id(obj) in self.__objects:
            return
        if isinstance(obj, point.Point):
            _res = self._addPoint(obj)
        elif isinstance(obj, segment.Segment):
            _res = self._addSegment(obj)
        elif isinstance(obj, arc.Arc):
            _res = self._addArc(obj)
        elif isinstance(obj, circle.Circle):
            _res = self._addCircle(obj)
        elif isinstance(obj, hcline.HCLine):
            _res = self._addHCLine(obj)
        elif isinstance(obj, vcline.VCLine):
            _res = self._addVCLine(obj)
        elif isinstance(obj, acline.ACLine):
            _res = self._addACLine(obj)
        elif isinstance(obj, ccircle.CCircle):
            _res = self._addCCircle(obj)
        elif isinstance(obj, cline.CLine):
            _res = self._addCLine(obj)
        elif isinstance(obj, segjoint.Chamfer):
            _res = self._addChamfer(obj)
        elif isinstance(obj, segjoint.Fillet):
            _res = self._addFillet(obj)
        elif isinstance(obj, leader.Leader):
            _res = self._addLeader(obj)
        elif isinstance(obj, polyline.Polyline):
            _res = self._addPolyline(obj)
        elif isinstance(obj, text.TextBlock):
            _res = self._addTextBlock(obj)
        elif isinstance(obj, dimension.AngularDimension):
            _res = self._addAngularDimension(obj)
        elif isinstance(obj, dimension.RadialDimension):
            _res = self._addRadialDimension(obj)
        elif isinstance(obj, dimension.HorizontalDimension):
            _res = self._addHorizontalDimension(obj)
        elif isinstance(obj, dimension.VerticalDimension):
            _res = self._addVerticalDimension(obj)
        elif isinstance(obj, dimension.LinearDimension):
            _res = self._addLinearDimension(obj)
        else:
            raise TypeError, "Invalid object type for storage: " + `type(obj)`
        if _res:
            #
            # call setParent() before connecting to layer log (if
            # it exists) so that the log will not recieve a 'modified'
            # message ...
            #
            self.__objects[id(obj)] = obj
            _oid = obj.getID()
            self.__objids[_oid] = obj
            obj.setParent(self)
            _log = obj.getLog()
            if _log is not None: # make this an error?
                _oldlog = self.__logs.get(_oid)
                if _oldlog is not None: # re-attach old log
                    _log.transferData(_oldlog)
                    del self.__logs[_oid]
            if isinstance(obj, dimension.Dimension):
                _ds1, _ds2 = obj.getDimstrings()
                _oid = _ds1.getID()
                _log = _ds1.getLog()
                if _log is not None:
                    _oldlog = self.__logs.get(_oid)
                    if _oldlog is not None:
                        _log.transferData(_oldlog)
                        del self.__logs[_oid]
                _oid = _ds2.getID()
                _log = _ds2.getLog()
                if _log is not None:
                    _oldlog = self.__logs.get(_oid)
                    if _oldlog is not None:
                        _log.transferData(_oldlog)
                        del self.__logs[_oid]

    def _addPoint(self, p):
        """Add a Point object to the Layer.

_addPoint(p)

This method is private to the Layer object.
        """
        self.__points.addObject(p)
        if p.getLog() is None:
            _log = point.PointLog(p)
            p.setLog(_log)
        return True

    def _addSegment(self, s):
        """Add a Segment object to the Layer.

_addSegment(s)

This method is private to the Layer object.
        """
        _p1, _p2 = s.getEndpoints()
        if id(_p1) not in self.__objects:
            raise ValueError, "Segment p1 Point not found in Layer."
        if id(_p2) not in self.__objects:
            raise ValueError, "Segment p2 Point not found in Layer."
        self.__segments.addObject(s)
        if s.getLog() is None:
            _log = segment.SegmentLog(s)
            s.setLog(_log)
        return True

    def _addCircle(self, c):
        """Add a Circle object to the Layer.

_addCircle(c)

This method is private to the layer object.
        """
        _cp = c.getCenter()
        if id(_cp) not in self.__objects:
            raise ValueError, "Circle center Point not found in Layer."
        self.__circles.addObject(c)
        if c.getLog() is None:
            _log = circle.CircleLog(c)
            c.setLog(_log)
        return True

    def _addArc(self, a):
        """Add an Arc object to the Layer.

_addArc(a)

This method is private to the Layer object.
        """
        _cp = a.getCenter()
        if id(_cp) not in self.__objects:
            raise ValueError, "Arc center Point not found in Layer."
        self.__arcs.addObject(a)
        if a.getLog() is None:
            _log = arc.ArcLog(a)
            a.setLog(_log)
        for _ex, _ey in a.getEndpoints():
            _pts = self.__points.find(_ex, _ey)
            if len(_pts) == 0:
                _lp = point.Point(_ex, _ey)
                self.addObject(_lp)
            else:
                _lp = _pts.pop()
                _max = _lp.countUsers()
                for _pt in _pts:
                    _count = _pt.countUsers()
                    if _count > _max:
                        _max = _count
                        _lp = _pt
            _lp.storeUser(a)
        return True

    def _addHCLine(self, hcl):
        """Add an HCLine object to the Layer.

_addHCLine(hcl)

This method is private to the Layer object.
        """
        _lp = hcl.getLocation()
        if id(_lp) not in self.__objects:
            raise ValueError, "HCLine location Point not found in Layer."
        self.__hclines.addObject(hcl)
        if hcl.getLog() is None:
            _log = hcline.HCLineLog(hcl)
            hcl.setLog(_log)
        return True

    def _addVCLine(self, vcl):
        """Add an VCLine object to the Layer.

_addVCLine(vcl)

This method is private to the Layer object.
        """
        _lp = vcl.getLocation()
        if id(_lp) not in self.__objects:
            raise ValueError, "VCLine location Point not found in Layer."
        self.__vclines.addObject(vcl)
        if vcl.getLog() is None:
            _log = vcline.VCLineLog(vcl)
            vcl.setLog(_log)
        return True

    def _addACLine(self, acl):
        """Add an ACLine object to the Layer.

_addACLine(acl)

This method is private to the Layer object.
        """
        _lp = acl.getLocation()
        if id(_lp) not in self.__objects:
            raise ValueError, "ACLine location Point not found in Layer."
        self.__aclines.addObject(acl)
        if acl.getLog() is None:
            _log = acline.ACLineLog(acl)
            acl.setLog(_log)
        return True

    def _addCCircle(self, cc):
        """Add an CCircle object to the Layer.

_addCCircle(cc)

This method is private to the Layer object.
        """
        _cp = cc.getCenter()
        if id(_cp) not in self.__objects:
            raise ValueError, "CCircle center Point not found in Layer."
        self.__ccircles.addObject(cc)
        if cc.getLog() is None:
            _log = ccircle.CCircleLog(cc)
            cc.setLog(_log)
        return True

    def _addCLine(self, cl):
        """Add an CLine object to the Layer.

_addCLine(cl)

This method is private to the Layer object.
        """
        _p1, _p2 = cl.getKeypoints()
        if id(_p1) not in self.__objects:
            raise ValueError, "CLine p1 Point not found in Layer."
        if id(_p2) not in self.__objects:
            raise ValueError, "CLine p2 Point not found in Layer."
        self.__clines.addObject(cl)
        if cl.getLog() is None:
            _log = cline.CLineLog(cl)
            cl.setLog(_log)
        return True

    def _addChamfer(self, ch):
        """Add a Chamfer object to the Layer.

_addChamfer(ch)

This method is private to the Layer object.
        """
        _s1, _s2 = ch.getSegments()
        if id(_s1) not in self.__objects:
            raise ValueError, "Chamfer s1 Segment not found in Layer."
        if id(_s2) not in self.__objects:
            raise ValueError, "Chamfer s2 Segment not found in Layer."
        self.__chamfers.append(ch)
        if ch.getLog() is None:
            _log = segjoint.ChamferLog(ch)
            ch.setLog(_log)
        return True

    def _addFillet(self, f):
        """Add a Fillet object to the Layer.

_addFillet(f)

This method is private to the Layer object.
        """
        _s1, _s2 = f.getSegments()
        if id(_s1) not in self.__objects:
            raise ValueError, "Fillet s1 Segment not found in Layer."
        if id(_s2) not in self.__objects:
            raise ValueError, "Fillet s2 Segment not found in Layer."
        self.__fillets.append(f)
        if f.getLog() is None:
            _log = segjoint.FilletLog(f)
            f.setLog(_log)
        return True

    def _addLeader(self, l):
        """Add a Leader object to the Layer.

_addLeader(l)

This method is private to the Layer object.
        """
        _p1, _p2, _p3 = l.getPoints()
        if id(_p1) not in self.__objects:
            raise ValueError, "Leader p1 Point not found in Layer."
        if id(_p2) not in self.__objects:
            raise ValueError, "Leader p2 Point not found in Layer."
        if id(_p3) not in self.__objects:
            raise ValueError, "Leader p3 Point not found in Layer."
        self.__leaders.addObject(l)
        if l.getLog() is None:
            _log = leader.LeaderLog(l)
            l.setLog(_log)
        return True

    def _addPolyline(self, pl):
        """Add a Polyline object to the Layer.

_addPolyline(pl)

This method is private to the Layer object.
        """
        for _pt in pl.getPoints():
            if id(_pt) not in self.__objects:
                raise ValueError, "Polyline point not in layer: " + str(_pt)
        self.__polylines.addObject(pl)
        if pl.getLog() is None:
            _log = polyline.PolylineLog(pl)
            pl.setLog(_log)
        return True

    def _addTextBlock(self, tb):
        """Add a TextBlock object to the Layer.

_addTextBlock(tb)

The TextBlock object 'tb' is added to the layer if there is not
already a TextBlock in the layer at the same location and with the
same text.
        """
        self.__textblocks.append(tb)
        if tb.getLog() is None:
            _log = text.TextBlockLog(tb)
            tb.setLog(_log)
        return True

    def _addAngularDimension(self, adim):
        """Add an AngularDimension object to the Layer.

_addAngularDimension(adim)

This method is private to the Layer object.
        """
        _p1, _p2, _p3 = adim.getDimPoints()
        _l1, _l2, _l3 = adim.getDimLayers()
        _lp = _l1.findObject(_p1)
        if _lp is not _p1:
            raise ValueError, "Dimension Point p1 not found in layer"
        _lp = _l2.findObject(_p2)
        if _lp is not _p2:
            raise ValueError, "Dimension Point p2 not found in layer!"
        _lp = _l3.findObject(_p3)
        if _lp is not _p3:
            raise ValueError, "Dimension Point p3 not found in layer!"
        self.__adims.addObject(adim)
        if adim.getLog() is None:
            _log = dimension.DimLog(adim)
            adim.setLog(_log)
            _ds1, _ds2 = adim.getDimstrings()
            _log = dimension.DimStringLog(_ds1)
            _ds1.setLog(_log)
            _log = dimension.DimStringLog(_ds2)
            _ds2.setLog(_log)
        return True

    def _addRadialDimension(self, rdim):
        """Add a RadialDimension object to the Layer.

_addRadialDimension(rdim)

This method is private to the Layer object.
        """
        _dc = rdim.getDimCircle()
        _dl = rdim.getDimLayer()
        _lc = _dl.findObject(_dc)
        if _lc is not _dc:
            raise ValueError, "RadialDimension circular object not found in layer"
        self.__rdims.addObject(rdim)
        if rdim.getLog() is None:        
            _log = dimension.DimLog(rdim)
            rdim.setLog(_log)
            _ds1, _ds2 = rdim.getDimstrings()
            _log = dimension.DimStringLog(_ds1)
            _ds1.setLog(_log)
            _log = dimension.DimStringLog(_ds2)
            _ds2.setLog(_log)
        return True

    def _addHorizontalDimension(self, hdim):
        """Add a HorizontalDimension object to the Layer.

_addHorizontalDimension(hdim)

This method is private to the Layer object.
        """
        _l1, _l2 = hdim.getDimLayers()
        _p1, _p2 = hdim.getDimPoints()
        _lp = _l1.findObject(_p1)
        if _lp is not _p1:
            raise ValueError, "HorizontalDimension Point p1 not found in layer"
        _lp = _l2.findObject(_p2)
        if _lp is not _p2:
            raise ValueError, "HorizontalDimension Point p2 not found in layer"
        self.__hdims.addObject(hdim)
        if hdim.getLog() is None:
            _log = dimension.DimLog(hdim)
            hdim.setLog(_log)
            _ds1, _ds2 = hdim.getDimstrings()
            _log = dimension.DimStringLog(_ds1)
            _ds1.setLog(_log)
            _log = dimension.DimStringLog(_ds2)
            _ds2.setLog(_log)
        return True

    def _addVerticalDimension(self, vdim):
        """Add a VerticalDimension object to the Layer.

_addVerticalDimension(vdim)

This method is private to the Layer object.
        """
        _l1, _l2 = vdim.getDimLayers()
        _p1, _p2 = vdim.getDimPoints()
        _lp = _l1.findObject(_p1)
        if _lp is not _p1:
            raise ValueError, "VerticalDimension Point p1 not found in layer"
        _lp = _l2.findObject(_p2)
        if _lp is not _p2:
            raise ValueError, "VerticalDimension Point p2 not found in layer"
        self.__vdims.addObject(vdim)
        if vdim.getLog() is None:
            _log = dimension.DimLog(vdim)
            vdim.setLog(_log)
            _ds1, _ds2 = vdim.getDimstrings()
            _log = dimension.DimStringLog(_ds1)
            _ds1.setLog(_log)
            _log = dimension.DimStringLog(_ds2)
            _ds2.setLog(_log)
        return True

    def _addLinearDimension(self, ldim):
        """Add a LinearDimension object to the Layer.

_addLinearDimension(ldim)

This method is private to the Layer object.
        """
        _l1, _l2 = ldim.getDimLayers()
        _p1, _p2 = ldim.getDimPoints()
        _lp = _l1.findObject(_p1)
        if _lp is not _p1:
            raise ValueError, "LinearDimension Point p1 not found in layer"
        _lp = _l2.findObject(_p2)
        if _lp is not _p2:
            raise ValueError, "LinearDimension Point p2 not found in layer"
        self.__ldims.addObject(ldim)
        if ldim.getLog() is None:
            _log = dimension.DimLog(ldim)
            ldim.setLog(_log)
            _ds1, _ds2 = ldim.getDimstrings()
            _log = dimension.DimStringLog(_ds1)
            _ds1.setLog(_log)
            _log = dimension.DimStringLog(_ds2)
            _ds2.setLog(_log)
        return True

    def delObject(self, obj):
        """Remove an object from this Layer.

delObject(obj)

The object should be a Point, Segment, Arc, Circle,
HCLine, VCLine, ACLine, CLine, CCircle, Chamfer,
Fillet, Leader, or Dimension. Anything else raises
a TypeError exception.
        """
        if self.isLocked():
            raise RuntimeError, "Deleting entity not allowed - layer locked."
        if id(obj) not in self.__objects:
            raise ValueError, "Object not found in layer: " + `obj`
        if isinstance(obj, point.Point):
            self._delPoint(obj)
        elif isinstance(obj, segment.Segment):
            self._delSegment(obj)
        elif isinstance(obj, arc.Arc):
            self._delArc(obj)
        elif isinstance(obj, circle.Circle):
            self._delCircle(obj)
        elif isinstance(obj, hcline.HCLine):
            self._delHCLine(obj)
        elif isinstance(obj, vcline.VCLine):
            self._delVCLine(obj)
        elif isinstance(obj, acline.ACLine):
            self._delACLine(obj)
        elif isinstance(obj, cline.CLine):
            self._delCLine(obj)
        elif isinstance(obj, ccircle.CCircle):
            self._delCCircle(obj)
        elif isinstance(obj, segjoint.Chamfer):
            self._delChamfer(obj)
        elif isinstance(obj, segjoint.Fillet):
            self._delFillet(obj)
        elif isinstance(obj, leader.Leader):
            self._delLeader(obj)
        elif isinstance(obj, polyline.Polyline):
            self._delPolyline(obj)
        elif isinstance(obj, text.TextBlock):
            self._delTextBlock(obj)
        elif isinstance(obj, dimension.AngularDimension):
            self._delAngularDimension(obj)
        elif isinstance(obj, dimension.RadialDimension):
            self._delRadialDimension(obj)
        elif isinstance(obj, dimension.HorizontalDimension):
            self._delHorizontalDimension(obj)
        elif isinstance(obj, dimension.VerticalDimension):
            self._delVerticalDimension(obj)
        elif isinstance(obj, dimension.LinearDimension):
            self._delLinearDimension(obj)
        else:
            raise TypeError, "Invalid object type for removal: " + `type(obj)`

    def _freeObj(self, obj):
        #
        # disconnect object before calling setParent() so that
        # the layer log will not recieve a 'modified' message
        # from the object ...
        #
        del self.__objects[id(obj)]
        _oid = obj.getID()
        del self.__objids[_oid]
        _log = obj.getLog()
        if _log is not None: # store the object's log
            _log.detatch()
            self.__logs[_oid] = _log
            obj.setLog(None)
        if isinstance(obj, dimension.Dimension):
            _ds1, _ds2 = obj.getDimstrings()
            _oid = _ds1.getID()
            self.__logs[_oid] = _ds1.getLog()
            _oid = _ds2.getID()
            self.__logs[_oid] = _ds2.getLog()
        _log = self.getLog()        
        if _log is not None:
            obj.disconnect(_log)
        obj.setParent(None)
        
    def _delPoint(self, p):
        """Delete a Point from the Layer.

_delPoint(p)

This method is private to the Layer object.
        """
        _delete = True
        _users = p.getUsers()
        for _uref in _users:
            _user = _uref()
            if _user is not None:
                if not isinstance(_user, dimension.Dimension):
                    _delete = False
                    break
        if _delete:
            _extdims = {}
            for _uref in _users:
                _user = _uref()
                if _user is not None:
                    _uid = id(_user)
                    if isinstance(_user, dimension.Dimension):
                        if _uid not in self.__objects:
                            _extdims[_uid] = _user
                    else:
                        if _uid not in self.__objects:
                            print "point bound to non-layer object: " + `_user`
                            _delete = False
                            break
            if _delete:
                for _uref in _users:
                    _user = _uref()
                    if _user is not None:
                        if id(_user) not in _extdims:
                            self.delObject(_user)
                if len(_extdims):
                    _parent = self.getParent()
                    _top = self
                    while _parent is not None:
                        _top = _parent
                        _parent = _top.getParent()
                    _layers = []
                    _layers.append(_top)
                    while len(_layers):
                        _layer = _layers.pop(0)
                        _dimids = _extdims.keys()
                        for _dimid in _dimids:
                            _dim = _extdims[_dimid]
                            if _dim in _layer:
                                del _extdims[_dimid]
                                _layer.delObject(_dim)
                        if len(_extdims):
                            _layers.extend(_layer.getSublayers())
                self.__points.delObject(p)
                self._freeObj(p)
                p.finish()

    def _delSegment(self, s):
        """Delete a Segment from the Layer.

_delSegment(s)

This method is private to the Layer object.
        """
        for _uref in s.getUsers(): # chamfers, fillets, or hatching
            _user = _uref()
            if _user is not None:
                self.delObject(_user) # restore other segments?
        _p1, _p2 = s.getEndpoints()
        assert id(_p1) in self.__objects, "Segment p1 Point not in objects"
        assert id(_p2) in self.__objects, "Segment p2 Point not in objects"
        self.__segments.delObject(s)
        self._freeObj(s)
        s.finish()
        if not self.inUndo() and not self.inRedo():
            self.delObject(_p1) # remove possibly unused point _p1
            self.delObject(_p2) # remove possibly unused point _p2

    def _delCircle(self, c):
        """Delete a Circle from the Layer.

_delCircle(c)

This method is private to the Layer object.
        """
        assert not isinstance(c, arc.Arc), "Arc in _delCircle()"
        _extdims = {}
        for _uref in c.getUsers(): # dimensions or hatching
            _user = _uref()
            if _user is not None:
                _uid = id(_user)
                if isinstance(_user, dimension.RadialDimension):
                    if _uid not in self.__objects:
                        _extdims[_uid] = _user
                    else:
                        self.delObject(_user)
        if len(_extdims):
            _parent = self.getParent()
            _top = self
            while _parent is not None:
                _top = _parent
                _parent = _top.getParent()
            _layers = []
            _layers.append(_top)
            while len(_layers):
                _layer = _layers.pop(0)
                _dimids = _extdims.keys()
                for _dimid in _dimids:
                    _dim = _extdims[_dimid]
                    if _dim in _layer:
                        del _extdims[_dimid]
                        _layer.delObject(_dim)
                if len(_extdims):
                    _layers.extend(_layer.getSublayers())
        _cp = c.getCenter()
        assert id(_cp) in self.__objects, "Circle center point not in objects"
        self.__circles.delObject(c)
        self._freeObj(c)
        c.finish()
        if not self.inUndo() and not self.inRedo():
            self.delObject(_cp) # remove possibly unused point _cp

    def _delArc(self, a):
        """Delete an Arc from the Layer.

_delArc(a)

This method is private to the Layer object.
        """
        _extdims = {}
        for _uref in a.getUsers(): # dimensions or hatching
            _user = _uref()
            if _user is not None:
                _uid = id(_user)
                if isinstance(_user, dimension.RadialDimension):
                    if _uid not in self.__objects:
                        _extdims[_uid] = _user
                    else:
                        self.delObject(_user)
        if len(_extdims):
            _parent = self.getParent()
            _top = self
            while _parent is not None:
                _top = _parent
                _parent = _top.getParent()
            _layers = []
            _layers.append(_top)
            while len(_layers):
                _layer = _layers.pop(0)
                _dimids = _extdims.keys()
                for _dimid in _dimids:
                    _dim = _extdims[_dimid]
                    if _dim in _layer:
                        del _extdims[_dimid]
                        _layer.delObject(_dim)
                if len(_extdims):
                    _layers.extend(_layer.getSublayers())
        _cp = a.getCenter()
        assert id(_cp) in self.__objects, "Arc center point not in objects"
        self.__arcs.delObject(a)
        self._freeObj(a)
        for _ep in a.getEndpoints():
            _pts = self.find('point', _ep[0], _ep[1])
            _p = None
            for _pt in _pts:
                for _uref in _pt.getUsers():
                    _user = _uref()
                    if _user is not None and _user is a:
                        _p = _pt
                        break
                if _p is not None:
                    break
            assert _p is not None, "Arc endpoint not found in layer"
            assert id(_p) in self.__objects, "Arc endpoint not in objects"
            _p.disconnect(a)
            _p.freeUser(a)
            if not self.inUndo() and not self.inRedo():
                self.delObject(_p) # remove possibly unused point _p
        a.finish()
        if not self.inUndo() and not self.inRedo():
            self.delObject(_cp) # remove possibly unused point _cp

    def _delHCLine(self, hcl):
        """Remove a HCLine object from the Layer.

_delHCLine(hcl)

This method is private to the Layer object.
        """
        _lp = hcl.getLocation()
        assert id(_lp) in self.__objects, "HCLine point not in objects"
        self.__hclines.delObject(hcl)
        self._freeObj(hcl)
        hcl.finish()
        if not self.inUndo() and not self.inRedo():
            self.delObject(_lp) # remove possibly unused point _lp

    def _delVCLine(self, vcl):
        """Remove a VCLine object from the Layer.

_delVCLine(vcl)

This method is private to the Layer object.
        """
        _lp = vcl.getLocation()
        assert id(_lp) in self.__objects, "VCLine point not in objects"
        self.__vclines.delObject(vcl)
        self._freeObj(vcl)
        vcl.finish()
        if not self.inUndo() and not self.inRedo():
            self.delObject(_lp) # remove possibly unused point _lp

    def _delACLine(self, acl):
        """Remove an ACLine object from the Layer.

_delACLine(acl)

This method is private to the Layer object.
        """
        _lp = acl.getLocation()
        assert id(_lp) in self.__objects, "ACLine point not in objects"
        self.__aclines.delObject(acl)
        self._freeObj(acl)
        acl.finish()
        if not self.inUndo() and not self.inRedo():
            self.delObject(_lp) # remove possibly unused point _lp

    def _delCLine(self, cl):
        """Delete a CLine from the Layer.

_delCLine(cl)

This method is private to the Layer object.
        """
        _p1, _p2 = cl.getKeypoints()
        assert id(_p1) in self.__objects, "CLine point p1 not in objects"
        assert id(_p2) in self.__objects, "CLine point p2 not in objects"
        self.__clines.delObject(cl)
        self._freeObj(cl)
        cl.finish()
        if not self.inUndo() and not self.inRedo():
            self.delObject(_p1) # remove possibly unused point _p1
            self.delObject(_p2) # remove possibly unused point _p2

    def _delCCircle(self, cc):
        """Delete a CCircle from the Layer.

_delCCircle(cc)

This method is private to the Layer object.
        """
        _cp = cc.getCenter()
        assert id(_cp) in self.__objects, "CCircle center point not in objects"
        self.__ccircles.delObject(cc)
        self._freeObj(cc)
        cc.finish()
        if not self.inUndo() and not self.inRedo():
            self.delObject(_cp) # remove possibly unused point _cp

    def _delChamfer(self, ch):
        """Remove a Chamfer from the Layer.

_delChamfer(ch)

This method is private to the Layer.
        """
        _chamfers = self.__chamfers
        _idx = None
        for _i in range(len(_chamfers)):
            if ch is _chamfers[_i]:
                _idx = _i
                break
        assert _idx is not None, "lost chamfer from list"
        for _uref in ch.getUsers(): # could be hatching ...
            _user = _uref()
            if _user is not None:
                self.delObject(_user)
        _s1, _s2 = ch.getSegments()
        assert id(_s1) in self.__objects, "Chamfer s1 segment not in objects"
        assert id(_s2) in self.__objects, "Chamfer s2 segment not in objects"
        del _chamfers[_idx] # restore the things the chamfer connects?
        self._freeObj(ch)
        ch.finish()

    def _delFillet(self, f):
        """Remove a Fillet from the Layer.

_delFillet(f)

This method is private to the Layer.
        """
        _fillets = self.__fillets
        _idx = None
        for _i in range(len(_fillets)):
            if f is _fillets[_i]:
                _idx = _i
                break
        assert _idx is not None, "lost fillet from list"
        for _uref in f.getUsers(): # could be hatching ...
            _user = _uref()
            if _user is not None:
                self.delObject(_user)
        _s1, _s2 = f.getSegments()
        assert id(_s1) in self.__objects, "Fillet s1 segment not in objects"
        assert id(_s2) in self.__objects, "Fillet s2 segment not in objects"
        del _fillets[_idx] # restore the things the fillet connects?
        self._freeObj(f)
        f.finish()

    def _delLeader(self, l):
        """Delete a Leader from the Layer.

_delLeader(l)

This method is private to the Layer object.
        """
        _p1, _p2, _p3 = l.getPoints()
        assert id(_p1) in self.__objects, "Leader p1 Point not in objects"
        assert id(_p2) in self.__objects, "Leader p2 Point not in objects"
        assert id(_p3) in self.__objects, "Leader p3 Point not in objects"
        self.__leaders.delObject(l)
        self._freeObj(l)
        l.finish()
        if not self.inUndo() and not self.inRedo():
            self.delObject(_p1) # remove possibly unused point _p1
            self.delObject(_p2) # remove possibly unused point _p2
            self.delObject(_p3) # remove possibly unused point _p3

    def _delPolyline(self, pl):
        """Delete a Polyline from the Layer.

_delPolyline(pl)

This method is private to the Layer object.
        """
        for _uref in pl.getUsers(): # could be hatching
            _user = _uref()
            if _user is not None:
                self.delObject(_user)
        _pts = pl.getPoints()
        for _pt in _pts:
            assert id(_pt) in self.__objects, "Polyline point not in objects"
        self.__polylines.delObject(pl)
        self._freeObj(pl)
        pl.finish()
        if not self.inUndo() and not self.inRedo():
            for _pt in _pts:
                self.delObject(_pt) # remove possibly unused point _pt

    def _delTextBlock(self, tb):
        """Delete a TextBlock from the Layer.

_delTextBlock(tb)

This method is private to the Layer object.
        """
        _tbs = self.__textblocks
        _idx = None
        for _i in range(len(_tbs)):
            if tb is _tbs[_i]:
                _idx = _i
                break
        assert _idx is not None, "lost textblock in list"
        del _tbs[_idx]
        self._freeObj(tb)

    def _delAngularDimension(self, adim):
        """Delete an AngularDimension from the Layer.

_delAngularDimension(adim)

This method is private to the Layer object.
        """
        _l1, _l2, _l3 = adim.getDimLayers()
        _p1, _p2, _p3 = adim.getDimPoints()
        if _l1 is self:
            assert id(_p1) in self.__objects, "ADim p1 not in objects"
        if _l2 is self:
            assert id(_p2) in self.__objects, "ADim p2 not in objects"
        if _l3 is self:
            assert id(_p3) in self.__objects, "ADim p3 not in objects"
        self.__adims.delObject(adim)
        self._freeObj(adim)
        adim.finish()

    def _delRadialDimension(self, rdim):
        """Delete a RadialDimension from the Layer.

_delRadialDimension(rdim)

This method is private to the Layer object.
        """
        _layer = rdim.getDimLayer()
        _circ = rdim.getDimCircle()
        if _layer is self:
            assert id(_circ) in self.__objects, "RDim circle not in objects"
        self.__rdims.delObject(rdim)
        self._freeObj(rdim)
        rdim.finish()

    def _delHorizontalDimension(self, hdim):
        """Delete an HorizontalDimension from the Layer.

_delHorizontalDimension(hdim)

This method is private to the Layer object.
        """
        _l1, _l2 = hdim.getDimLayers()
        _p1, _p2 = hdim.getDimPoints()
        if _l1 is self:
            assert id(_p1) in self.__objects, "HDim P1 not in objects"
        if _l2 is self:
            assert id(_p2) in self.__objects, "HDim P2 not in objects"
        self.__hdims.delObject(hdim)
        self._freeObj(hdim)
        hdim.finish()

    def _delVerticalDimension(self, vdim):
        """Delete an VerticalDimension from the Layer.

_delVerticalDimension(vdim)

This method is private to the Layer object.
        """
        _l1, _l2 = vdim.getDimLayers()
        _p1, _p2 = vdim.getDimPoints()
        if _l1 is self:
            assert id(_p1) in self.__objects, "VDim P1 not in objects"
        if _l2 is self:
            assert id(_p2) in self.__objects, "VDim P2 not in objects"
        self.__vdims.delObject(vdim)
        self._freeObj(vdim)
        vdim.finish()

    def _delLinearDimension(self, ldim):
        """Delete an LinearDimension from the Layer.

_delLinearDimension(ldim)

This method is private to the Layer object.
        """
        _l1, _l2 = ldim.getDimLayers()
        _p1, _p2 = ldim.getDimPoints()
        if _l1 is self:
            assert id(_p1) in self.__objects, "LDim P1 not in objects"
        if _l2 is self:
            assert id(_p2) in self.__objects, "LDim P2 not in objects"
        self.__ldims.delObject(ldim)
        self._freeObj(ldim)
        ldim.finish()

    def getObject(self, eid):
        """Return an object of with a specified entity ID.

getObject(eid)

Argument eid is an entity ID.
        """
        return self.__objids.get(eid)

    def hasObject(self, eid):
        """

hasObject(eid)

Argument eid is an entity ID.
        """
        return eid in self.__objids

    def findObject(self, obj):
        """Return an object in the layer that is equivalent to a test object.

findObject(obj)

This method returns None if a suitable object is not found.
        """
        _retobj = None
        if id(obj) in self.__objects:
            _retobj = obj
        else:
            _objs = []
            if isinstance(obj, point.Point):
                _x, _y = obj.getCoords()
                _objs.extend(self.__points.find(_x, _y))
            elif isinstance(obj, segment.Segment):
                _p1, _p2 = obj.getEndpoints()
                _x1, _y1 = _p1.getCoords()
                _x2, _y2 = _p2.getCoords()
                _objs.extend(self.__segments.find(_x1, _y1, _x2, _y2))
            elif isinstance(obj, arc.Arc):
                _x, _y = obj.getCenter().getCoords()
                _r = obj.getRadius()
                _sa = obj.getStartAngle()
                _ea = obj.getEndAngle()
                _objs.extend(self.__arcs.find(_x, _y, _r, _sa, _ea))
            elif isinstance(obj, circle.Circle):
                _x, _y = obj.getCenter().getCoords()
                _r = obj.getRadius()
                _objs.extend(self.__circles.find(_x, _y, _r))
            elif isinstance(obj, hcline.HCLine):
                _y = obj.getLocation().y
                _objs.extend(self.__hclines.find(_y))
            elif isinstance(obj, vcline.VCLine):
                _x = obj.getLocation().x
                _objs.extend(self.__vclines.find(_x))
            elif isinstance(obj, acline.ACLine):
                _x, _y = obj.getLocation().getCoords()
                _angle = obj.getAngle()
                _objs.extend(self.__aclines.find(_x, _y, _angle))
            elif isinstance(obj, cline.CLine):
                _p1, _p2 = obj.getKeypoints()
                _x1, _y1 = _p1.getCoords()
                _x2, _y2 = _p2.getCoords()
                _objs.extend(self.__clines.find(_x1, _y1, _x2, _y2))
            elif isinstance(obj, ccircle.CCircle):
                _x, _y = obj.getCenter().getCoords()
                _r = obj.getRadius()
                _objs.extend(self.__ccircles.find(_x, _y, _r))
            elif isinstance(obj, segjoint.Fillet):
                for _f in self.__fillets:
                    if _f is obj:
                        _retobj = _f
                        break
            elif isinstance(obj, segjoint.Chamfer):
                for _c in self.__chamfers:
                    if _c == obj:
                        _retobj = _f
                        break
            elif isinstance(obj, leader.Leader):
                _p1, _p2, _p3 = obj.getPoints()
                _x1, _y1 = _p1.getCoords()
                _x2, _y2 = _p2.getCoords()
                _x3, _y3 = _p3.getCoords()
                _objs.extend(self.__leaders.find(_x1, _y1, _x2, _y2, _x3, _y3))
            elif isinstance(obj, polyline.Polyline):
                _coords = []
                for _pt in obj.getPoints():
                    _coords.append(_pt.getCoords())
                _objs.extend(self.__polylines.find(_coords))
            elif isinstance(obj, text.TextBlock):
                for _tb in self.__textblocks:
                    if _tb == obj:
                        _retobj = _f
                        break
            elif isinstance(obj, dimension.HorizontalDimension):
                _l1, _l2 = obj.getDimLayers()
                _p1, _p2 = obj.getDimPoints()
                _objs.extend(self.__hdims.find(_l1, _p1, _l2, _p2))
            elif isinstance(obj, dimension.VerticalDimension):
                _l1, _l2 = obj.getDimLayers()
                _p1, _p2 = obj.getDimPoints()
                _objs.extend(self.__hdims.find(_l1, _p1, _l2, _p2))
            elif isinstance(obj, dimension.LinearDimension):
                _l1, _l2 = obj.getDimLayers()
                _p1, _p2 = obj.getDimPoints()
                _objs.extend(self.__hdims.find(_l1, _p1, _l2, _p2))
            elif isinstance(obj, dimension.RadialDimension):
                _l1 = obj.getDimLayer()
                _c1 = obj.getDimCircle()
                _objs.extend(self.__rdims.find(_l1, _c1))
            elif isinstance(obj, dimension.AngularDimension):
                _vl, _l1, _l2 = obj.getDimLayers()
                _vp, _p1, _p2 = obj.getDimPoints()
                _objs.extend(self.__hdims.find(_vl, _vp, _l1, _p1, _l2, _p2))
            else:
                raise TypeError, "Invalid object type: " + `type(obj)`
            if _retobj is not None:
                for _obj in _objs:
                    if _obj is obj:
                        _retobj = _obj
                        break
        return _retobj

    def find(self, typestr, *args):
        """Find an existing entity in the drawing.

find(typestr, *args)

typestr: A string giving the type of entity to find
*args: A variable number of arguments used for searching
        """
        if not isinstance(typestr, str):
            raise TypeError, "Invalid type string: " + `type(typestr)`
        _objs = []
        if typestr == 'point':
            _objs.extend(self.__points.find(*args))
        elif typestr == 'segment':
            _objs.extend(self.__segments.find(*args))
        elif typestr == 'circle':
            _objs.extend(self.__circles.find(*args))
        elif typestr == 'arc':
            _objs.extend(self.__arcs.find(*args))
        elif typestr == 'hcline':
            _objs.extend(self.__hclines.find(*args))
        elif typestr == 'vcline':
            _objs.extend(self.__vclines.find(*args))
        elif typestr == 'acline':
            _objs.extend(self.__aclines.find(*args))
        elif typestr == 'cline':
            _objs.extend(self.__clines.find(*args))
        elif typestr == 'ccircle':
            _objs.extend(self.__ccircles.find(*args))
        elif typestr == 'leader':
            _objs.extend(self.__leaders.find(*args))
        elif typestr == 'polyline':
            _objs.extend(self.__polylines.find(*args))
        elif typestr == 'ldim':
            _objs.extend(self.__ldims.find(*args))
        elif typestr == 'hdim':
            _objs.extend(self.__hdims.find(*args))
        elif typestr == 'vdim':
            _objs.extend(self.__vdims.find(*args))
        elif typestr == 'rdim':
            _objs.extend(self.__rdims.find(*args))
        elif typestr == 'adim':
            _objs.extend(self.__adims.find(*args))
        else:
            raise ValueError, "Unexpected type string '%s'" % typestr
        return _objs

    def mapPoint(self, p, tol=tolerance.TOL, count=2):
        """Find a Point in the layer

mapPoint(p [,tol, count])

There is a single required argument:

p: Either a Point object or a tuple of two-floats

There are two optional arguments:

tol: A float equal or greater than 0 for distance tolerance comparisons.
count: An integer value indicating the largest number of objects to
       return. By default this value is 2.

Setting 'count' to None or a negative value will result in the maximum
number of objects being unlimited.

This method tests the objects in the Layer to see if the
Point can can be mapped on to any of them. The returned list
consists of tuples in the form:

(obj, pt)

Where 'obj' is the object the point was mapped to and 'pt'
is the projected point on the object.
        """
        _hits = []
        _p = p
        if not isinstance(_p, point.Point):
            _p = point.Point(p)
        _t = tolerance.toltest(tol)
        _count = count
        if _count is None:
            _count = sys.maxint
        else:
            if not isinstance(_count, int):
                _count = int(count)
            if _count < 0:
                _count = sys.maxint
        if _count < 1: # bail out, but why set count to this value?
            return _hits
        _x, _y = _p.getCoords()
        _xmin = _x - _t
        _xmax = _x + _t
        _ymin = _y - _t
        _ymax = _y + _t
        #
        # scan for non-point objects first, then look at points,
        # because there will not be any way the same object can
        # be found in differnt trees/lists
        #
        for _obj in self.__segments.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _pt = _obj.mapCoords(_x, _y, _t)
            if _pt is not None:
                _px, _py = _pt
                _pts = self.__points.find(_px, _py)
                if len(_pts) == 0:
                    _pts.append(point.Point(_px, _py))
                for _pt in _pts:
                    _hits.append((_obj, _pt))
                    if len(_hits) == _count:
                        return _hits
        for _obj in self.__circles.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _pt = _obj.mapCoords(_x, _y, _t)
            if _pt is not None:
                _px, _py = _pt
                _pts = self.__points.find(_px, _py)
                if len(_pts) == 0:
                    _pts.append(point.Point(_px, _py))
                for _pt in _pts:
                    _hits.append((_obj, _pt))
                    if len(_hits) == _count:
                        return _hits
        for _obj in self.__arcs.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _pt = _obj.mapCoords(_x, _y, _t)
            if _pt is not None:
                _px, _py = _pt
                _pts = self.__points.find(_px, _py)
                if len(_pts) == 0:
                    _pts.append(point.Point(_px, _py))
                for _pt in _pts:
                    _hits.append((_obj, _pt))
                    if len(_hits) == _count:
                        return _hits
        for _obj in self.__hclines.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _pt = _obj.mapCoords(_x, _y, _t)
            if _pt is not None:
                _px, _py = _pt
                _pts = self.__points.find(_px, _py)
                if len(_pts) == 0:
                    _pts.append(point.Point(_px, _py))
                for _pt in _pts:
                    _hits.append((_obj, _pt))
                    if len(_hits) == _count:
                        return _hits
        for _obj in self.__vclines.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _pt = _obj.mapCoords(_x, _y, _t)
            if _pt is not None:
                _px, _py = _pt
                _pts = self.__points.find(_px, _py)
                if len(_pts) == 0:
                    _pts.append(point.Point(_px, _py))
                for _pt in _pts:
                    _hits.append((_obj, _pt))
                    if len(_hits) == _count:
                        return _hits
        for _obj in self.__aclines.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _pt = _obj.mapCoords(_x, _y, _t)
            if _pt is not None:
                _px, _py = _pt
                _pts = self.__points.find(_px, _py)
                if len(_pts) == 0:
                    _pts.append(point.Point(_px, _py))
                for _pt in _pts:
                    _hits.append((_obj, _pt))
                    if len(_hits) == _count:
                        return _hits
        for _obj in self.__ccircles.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _pt = _obj.mapCoords(_x, _y, _t)
            if _pt is not None:
                _px, _py = _pt
                _pts = self.__points.find(_px, _py)
                if len(_pts) == 0:
                    _pts.append(point.Point(_px, _py))
                for _pt in _pts:
                    _hits.append((_obj, _pt))
                    if len(_hits) == _count:
                        return _hits
        for _obj in self.__clines.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _pt = _obj.mapCoords(_x, _y, _t)
            if _pt is not None:
                _px, _py = _pt
                _pts = self.__points.find(_px, _py)
                if len(_pts) == 0:
                    _pts.append(point.Point(_px, _py))
                for _pt in _pts:
                    _hits.append((_obj, _pt))
                    if len(_hits) == _count:
                        return _hits
        for _obj in self.__leaders.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _pt = _obj.mapCoords(_x, _y, _t)
            if _pt is not None:
                _px, _py = _pt
                _pts = self.__points.find(_px, _py)
                if len(_pts) == 0:
                    _pts.append(point.Point(_px, _py))
                for _pt in _pts:
                    _hits.append((_obj, _pt))
                    if len(_hits) == _count:
                        return _hits
        for _obj in self.__polylines.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _pt = _obj.mapCoords(_x, _y, _t)
            if _pt is not None:
                _px, _py = _pt
                _pts = self.__points.find(_px, _py)
                if len(_pts) == 0:
                    _pts.append(point.Point(_px, _py))
                for _pt in _pts:
                    _hits.append((_obj, _pt))
                    if len(_hits) == _count:
                        return _hits
        for _obj in self.__ldims.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _pt = _obj.mapCoords(_x, _y, _t)
            if _pt is not None:
                _px, _py = _pt
                _pts = self.__points.find(_px, _py)
                if len(_pts) == 0:
                    _pts.append(point.Point(_px, _py))
                for _pt in _pts:
                    _hits.append((_obj, _pt))
                    if len(_hits) == _count:
                        return _hits
        for _obj in self.__hdims.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _pt = _obj.mapCoords(_x, _y, _t)
            if _pt is not None:
                _px, _py = _pt
                _pts = self.__points.find(_px, _py)
                if len(_pts) == 0:
                    _pts.append(point.Point(_px, _py))
                for _pt in _pts:
                    _hits.append((_obj, _pt))
                    if len(_hits) == _count:
                        return _hits
        for _obj in self.__vdims.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _pt = _obj.mapCoords(_x, _y, _t)
            if _pt is not None:
                _px, _py = _pt
                _pts = self.__points.find(_px, _py)
                if len(_pts) == 0:
                    _pts.append(point.Point(_px, _py))
                for _pt in _pts:
                    _hits.append((_obj, _pt))
                    if len(_hits) == _count:
                        return _hits
        for _obj in self.__rdims.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _pt = _obj.mapCoords(_x, _y, _t)
            if _pt is not None:
                _px, _py = _pt
                _pts = self.__points.find(_px, _py)
                if len(_pts) == 0:
                    _pts.append(point.Point(_px, _py))
                for _pt in _pts:
                    _hits.append((_obj, _pt))
                    if len(_hits) == _count:
                        return _hits
        for _obj in self.__adims.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _pt = _obj.mapCoords(_x, _y, _t)
            if _pt is not None:
                _px, _py = _pt
                _pts = self.__points.find(_px, _py)
                if len(_pts) == 0:
                    _pts.append(point.Point(_px, _py))
                for _pt in _pts:
                    _hits.append((_obj, _pt))
                    if len(_hits) == _count:
                        return _hits
        #
        # scan for point, but do not append any object that
        # has already been added to the hit list
        #
        _objs = {}
        for _obj, _pt in _hits:
            _objs[id(_obj)] = True
        _pts = self.find('point', _x, _y, _t)
        if len(_pts) != 0:
            for _pt in _pts:
                assert id(_pt) in self.__objects, "Point not in objects"
                for _uref in _pt.getUsers():
                    _user = _uref()
                    if _user is not None:
                        _uid = id(_user)
                        if _uid not in _objs:
                            _objs[_uid] = True
                            _hits.append((_user, _pt))
                            if len(_hits) == _count:
                                break
        return _hits

    def mapCoords(self, x, y, **kw):
        """Find objects at coordinates in the Layer.

mapCoords(x, y, **kw)

Arguments 'x' and 'y' are mandatory and should be float values.
Non-float values will be converted to that type if possible.

There are several optional keyword arguments:

tolerance: A float equal or greater than 0 for distance tolerance comparisons.
count: An integer value indicating the largest number of objects to
       return. By default this value is the sys.maxint value, essentially
       making the count unlimited.
types: A dictionary containing key/value pairs. If any key is given a
       value of 'True', only types for keys with 'True' values are examined.
       If any  key is given a 'False' value, the type corresponding to that
       key is skipped.

This method tests the objects in the Layer to see if the specified
x/y coordiantes can can be mapped on to any of them. The returned list
consists of tuples in the form:

(obj, {var})

Where 'obj' is the object the point was mapped to and '{var}'
is either an existing Point in the Layer or a tuple of the
form (x, y) giving the coordinates where a new Point can be
added.
        """
        #
        # utility function for testing whether or not an entity type
        # is to be examined
        #
        def _test_entity(tdict, skip, etype):
            _rv = True
            if tdict is not None:
                if skip is True:
                    if not tdict.has_key(etype) or tdict[etype] is not True:
                        _rv = False
                else:
                    if tdict.has_key(etype) and tdict[etype] is False:
                        _rv = False
            return _rv
        _x = util.get_float(x)
        _y = util.get_float(y)
        _t = 1e-10
        _types = None
        _skip = False
        _count = sys.maxint
        if 'tolerance' in kw:
            _val = util.get_float(kw['tolerance'])
            if _val < 0.0:
                raise ValueError, "Invalid negative tolerance: %f" % _val
            _t = _val
        if 'count' in kw:
            _val = kw['count']
            if not isinstance(_val, int):
                _val = int(kw['count'])
            if _val < 0:
                raise ValueError, "Invalid negative entity count %d" % _val
        if 'types' in kw:
            _val = kw['types']
            if not isinstance(_val, dict):
                raise TypeError, "Invalid 'types' dictionary: " + `type(_val)`
            for _k, _v in _val.items():
                if not isinstance(_k, str):
                    raise TypeError, "Invalid key %s type: %s " (str(_k), `type(_k)`)
                util.test_boolean(_v)
                if _skip is False and _v is True:
                    _skip = True
            _types = _val
        _hits = []
        if _count == 0:
            return _hits
        _xmin = _x - _t
        _xmax = _x + _t
        _ymin = _y - _t
        _ymax = _y + _t
        #
        # start testing entities
        #
        if _test_entity(_types, _skip, 'point'):
            _pts = self.__points.getInRegion(_xmin, _ymin, _xmax, _ymax)
            if len(_pts):
                _plist = []
                for _pt in _pts:
                    _sqlen = pow((_x - _pt.x), 2) + pow((_y - _pt.y), 2)
                    _plist.append((_sqlen, _pt))
                _plist.sort() # sorts tuples by first value!
                for _sqlen, _pt in _plist:
                    _hits.append((_pt, _pt))
                    if len(_hits) == _count:
                        return _hits
                # _users = {}
                # for _i in range(len(_pts)):
                    # _pt = _pts[_i]
                    # _count = _pt.countUsers()
                    # _ulist = _users.setdefault(_count, [])
                    # _ulist.append(_pt)
                # _counts = _users.keys()
                # _counts.sort(lambda _a, _b: cmp(_b, _a)) # largest to smallest
                # for _i in range(len(_counts)):
                    # _count = _counts[_i]
                    # for _pt in _users[_count]:
                        # _hits.append((_pt, _pt))
                        # if len(_hits) == _count:
                            # return _hits
        if _test_entity(_types, _skip, 'segment'):
            for _obj in self.__segments.getInRegion(_xmin, _ymin, _xmax, _ymax):
                _pt = _obj.mapCoords(_x, _y, _t)
                if _pt is not None:
                    _px, _py = _pt
                    _p1, _p2 = _obj.getEndpoints()
                    if ((abs(_px - _p1.x) < _t) and (abs(_py - _p1.y) < _t)):
                        _hits.append((_obj, _p1))
                    elif ((abs(_px - _p2.x) < _t) and (abs(_py - _p2.y) < _t)):
                        _hits.append((_obj, _p2))
                    else:
                        _hits.append((_obj, (_px, _py)))
                    if len(_hits) == _count:
                        return _hits
        if _test_entity(_types, _skip, 'circle'):
            for _obj in self.__circles.getInRegion(_xmin, _ymin, _xmax, _ymax):
                _pt = _obj.mapCoords(_x, _y, _t)
                if _pt is not None:
                    _hits.append((_obj, (_pt[0], _pt[1])))
                    if len(_hits) == _count:
                        return _hits
        if _test_entity(_types, _skip, 'arc'):
            for _obj in self.__arcs.getInRegion(_xmin, _ymin, _xmax, _ymax):
                _pt = _obj.mapCoords(_x, _y, _t)
                if _pt is not None:
                    _hits.append((_obj, (_pt[0], _pt[1])))
                    if len(_hits) == _count:
                        return _hits
        if _test_entity(_types, _skip, 'hcline'):
            for _obj in self.__hclines.getInRegion(_xmin, _ymin, _xmax, _ymax):
                _pt = _obj.mapCoords(_x, _y, _t)
                if _pt is not None:
                    _px, _py = _pt
                    _lp = _obj.getLocation()
                    if ((abs(_px - _lp.x) < _t) and (abs(_py - _lp.y) < _t)):
                        _hits.append((_obj, _lp))
                    else:
                        _hits.append((_obj, (_px, _py)))
                    if len(_hits) == _count:
                        return _hits
        if _test_entity(_types, _skip, 'vcline'):
            for _obj in self.__vclines.getInRegion(_xmin, _ymin, _xmax, _ymax):
                _pt = _obj.mapCoords(_x, _y, _t)
                if _pt is not None:
                    _px, _py = _pt
                    _lp = _obj.getLocation()
                    if ((abs(_px - _lp.x) < _t) and (abs(_py - _lp.y) < _t)):
                        _hits.append((_obj, _lp))
                    else:
                        _hits.append((_obj, (_px, _py)))
                    if len(_hits) == _count:
                        return _hits
        if _test_entity(_types, _skip, 'acline'):
            for _obj in self.__aclines.getInRegion(_xmin, _ymin, _xmax, _ymax):
                _pt = _obj.mapCoords(_x, _y, _t)
                if _pt is not None:
                    _px, _py = _pt
                    _lp = _obj.getLocation()
                    if ((abs(_px - _lp.x) < _t) and (abs(_py - _lp.y) < _t)):
                        _hits.append((_obj, _lp))
                    else:
                        _hits.append((_obj, (_px, _py)))
                    if len(_hits) == _count:
                        return _hits
        if _test_entity(_types, _skip, 'ccircle'):
            for _obj in self.__ccircles.getInRegion(_xmin, _ymin, _xmax, _ymax):
                _pt = _obj.mapCoords(_x, _y, _t)
                if _pt is not None:
                    _hits.append((_obj, (_pt[0], _pt[1])))
                    if len(_hits) == _count:
                        return _hits
        if _test_entity(_types, _skip, 'cline'):
            for _obj in self.__clines.getInRegion(_xmin, _ymin, _xmax, _ymax):
                _pt = _obj.mapCoords(_x, _y, _t)
                if _pt is not None:
                    _px, _py = _pt
                    _p1, _p2 = _obj.getKeypoints()
                    if ((abs(_px - _p1.x) < _t) and (abs(_py - _p1.y) < _t)):
                        _hits.append((_obj, _p1))
                    elif ((abs(_px - _p2.x) < _t) and (abs(_py - _p2.y) < _t)):
                        _hits.append((_obj, _p2))
                    else:
                        _hits.append((_obj, (_px, _py)))
                    if len(_hits) == _count:
                        return _hits
        if _test_entity(_types, _skip, 'leader'):
            for _obj in self.__leaders.getInRegion(_xmin, _ymin, _xmax, _ymax):
                _pt = _obj.mapCoords(_x, _y, _t)
                if _pt is not None:
                    _px, _py = _pt
                    _p1, _p2, _p3 = _obj.getPoints()
                    if ((abs(_px - _p1.x) < _t) and (abs(_py - _p1.y) < _t)):
                        _hits.append((_obj, _p1))
                    elif ((abs(_px - _p2.x) < _t) and (abs(_py - _p2.y) < _t)):
                        _hits.append((_obj, _p2))
                    elif ((abs(_px - _p3.x) < _t) and (abs(_py - _p3.y) < _t)):
                        _hits.append((_obj, _p3))
                    else:
                        _hits.append((_obj, (_px, _py)))
                    if len(_hits) == _count:
                        return _hits
        if _test_entity(_types, _skip, 'polyline'):
            for _obj in self.__polylines.getInRegion(_xmin, _ymin, _xmax, _ymax):
                _pt = _obj.mapCoords(_x, _y, _t)
                if _pt is not None:
                    _px, _py = _pt
                    _pp = None
                    for _tp in _obj.getPoints():
                        if ((abs(_px - _tp.x) < _t) and
                            (abs(_py - _tp.y) < _t)):
                            _pp = _tp
                            break
                    if _pp is not None:
                        _hits.append((_obj, _pp))
                    else:
                        _hits.append((_obj, (_px, _py)))
                    if len(_hits) == _count:
                        return _hits
        if _test_entity(_types, _skip, 'linear_dimension'):
            for _obj in self.__ldims.getInRegion(_xmin, _ymin, _xmax, _ymax):
                _pt = _obj.mapCoords(_x, _y, _t)
                if _pt is not None:
                    _hits.append((_obj, (_pt[0], _pt[1])))
                    if len(_hits) == _count:
                        return _hits
        if _test_entity(_types, _skip, 'horizontal_dimension'):
            for _obj in self.__hdims.getInRegion(_xmin, _ymin, _xmax, _ymax):
                _pt = _obj.mapCoords(_x, _y, _t)
                if _pt is not None:
                    _hits.append((_obj, (_pt[0], _pt[1])))
                    if len(_hits) == _count:
                        return _hits
        if _test_entity(_types, _skip, 'vertical_dimension'):
            for _obj in self.__vdims.getInRegion(_xmin, _ymin, _xmax, _ymax):
                _pt = _obj.mapCoords(_x, _y, _t)
                if _pt is not None:
                    _hits.append((_obj, (_pt[0], _pt[1])))
                    if len(_hits) == _count:
                        return _hits
        if _test_entity(_types, _skip, 'radial_dimension'):
            for _obj in self.__rdims.getInRegion(_xmin, _ymin, _xmax, _ymax):
                _pt = _obj.mapCoords(_x, _y, _t)
                if _pt is not None:
                    _hits.append((_obj, (_pt[0], _pt[1])))
                    if len(_hits) == _count:
                        return _hits
        if _test_entity(_types, _skip, 'angular_dimension'):
            for _obj in self.__adims.getInRegion(_xmin, _ymin, _xmax, _ymax):
                _pt = _obj.mapCoords(_x, _y, _t)
                if _pt is not None:
                    _hits.append((_obj, (_pt[0], _pt[1])))
                    if len(_hits) == _count:
                        return _hits
        return _hits

    def hasEntities(self):
        """Test if the Layer has entities.

hasEntities():

This method returns a boolean
        """
        if (self.__points or
            self.__segments or
            self.__circles or
            self.__arcs or
            self.__leaders or
            self.__polylines or
            self.__hclines or
            self.__vclines or
            self.__aclines or
            self.__clines or
            self.__ccircles or
            (len(self.__chamfers) > 0) or
            (len(self.__fillets) > 0) or
            (len(self.__textblocks) > 0) or
            self.__ldims or
            self.__hdims or
            self.__vdims or
            self.__rdims or
            self.__adims):
            return True
        return False

    def getEntityCount(self, etype):
        """Return the number of an entity type stored in the  Layer

getEntityCount(etype)

The argument 'etype' should be one of the following:
point, segment, circle, arc, hcline, vcline, acline,
cline, ccircle, chamfer, fillet, leader, polyline,
textblock, linear_dimension, horizontal_dimenions,
vertical_dimension, radial_dimension, or angular_dimension.
        """
        if etype == "point":
            _res = len(self.__points)
        elif etype == "segment":
            _res = len(self.__segments)
        elif etype == "circle":
            _res = len(self.__circles)
        elif etype == "arc":
            _res = len(self.__arcs)
        elif etype == "leader":
            _res = len(self.__leaders)
        elif etype == "polyline":
            _res = len(self.__polylines)
        elif etype == "chamfer":
            _res = len(self.__chamfers)
        elif etype == "fillet":
            _res = len(self.__fillets)
        elif etype == "hcline":
            _res = len(self.__hclines)
        elif etype == "vcline":
            _res = len(self.__vclines)
        elif etype == "acline":
            _res = len(self.__aclines)
        elif etype == "cline":
            _res = len(self.__clines)
        elif etype == "ccircle":
            _res = len(self.__ccircles)
        elif etype == "text" or etype == 'textblock':
            _res = len(self.__textblocks)
        elif etype == "linear_dimension":
            _res = len(self.__ldims)
        elif etype == "horizontal_dimension":
            _res = len(self.__hdims)
        elif etype == "vertical_dimension":
            _res = len(self.__vdims)
        elif etype == "radial_dimension":
            _res = len(self.__rdims)
        elif etype == "angular_dimension":
            _res = len(self.__adims)
        else:
            raise ValueError, "Unexpected entity type string'%s'" % etype
        return _res
    
    def getLayerEntities(self, entity):
        """Get all of a particular type of entity in the Layer.

getLayerEntities(entity)

The argument 'entity' should be one of the following:
point, segment, circle, arc, hcline, vcline, acline,
cline, ccircle, chamfer, fillet, leader, polyline,
textblock, linear_dimension, horizontal_dimenions,
vertical_dimension, radial_dimension, or angular_dimension.
        """
        if not isinstance(entity, str):
            raise TypeError, "Invalid entity type: " + `type(entity)`
        if entity == "point":
            _objs = self.__points.getObjects()
        elif entity == "segment":
            _objs = self.__segments.getObjects()
        elif entity == "circle":
            _objs = self.__circles.getObjects()
        elif entity == "arc":
            _objs = self.__arcs.getObjects()
        elif entity == "hcline":
            _objs = self.__hclines.getObjects()
        elif entity == "vcline":
            _objs = self.__vclines.getObjects()
        elif entity == "acline":
            _objs = self.__aclines.getObjects()
        elif entity == "cline":
            _objs = self.__clines.getObjects()
        elif entity == "ccircle":
            _objs = self.__ccircles.getObjects()
        elif entity == "chamfer":
            _objs = self.__chamfers[:]
        elif entity == "fillet":
            _objs = self.__fillets[:]
        elif entity == "leader":
            _objs = self.__leaders.getObjects()
        elif entity == "polyline":
            _objs = self.__polylines.getObjects()
        elif entity == "text" or entity == 'textblock':
            _objs = self.__textblocks[:]
        elif entity == "linear_dimension":
            _objs = self.__ldims.getObjects()
        elif entity == "horizontal_dimension":
            _objs = self.__hdims.getObjects()
        elif entity == "vertical_dimension":
            _objs = self.__vdims.getObjects()
        elif entity == "radial_dimension":
            _objs = self.__rdims.getObjects()
        elif entity == "angular_dimension":
            _objs = self.__adims.getObjects()
        else:
            raise ValueError, "Invalid layer entity '%s'" % entity
        return _objs

    def canParent(self, obj):
        """Test if an Entity can be the parent of another Entity.

canParent(obj)

This method overrides the Entity::canParent() method. A layer can
be the parent of any object contained within itself.
        """
        return isinstance(obj, (point.Point, segment.Segment,
                                circle.Circle, arc.Arc,
                                leader.Leader, polyline.Polyline,
                                hcline.HCLine, vcline.VCLine,
                                acline.ACLine, cline.CLine, segjoint.SegJoint,
                                ccircle.CCircle, dimension.Dimension,
                                dimension.DimString, # ???
                                text.TextBlock))


    def setParentLayer(self, parent):
        """Store the parent layer of a layer within itself.

setParentLayer(parent)

Argument 'parent' must be either another Layer or None.
        """
        if parent is not None and not isinstance(parent, Layer):
            raise TypeError, "Invalid layer type: " + `type(parent)`
        _p = self.__parent_layer
        if _p is not parent:
            if _p is not None:
                _p.delSublayer(self)
            if parent is not None:
                parent.addSublayer(self)
            self.__parent_layer = parent
            self.sendMessage('reparented', _p)
            self.modified()

    def getParentLayer(self):
        return self.__parent_layer

    def addSublayer(self, l):
        if l is not None and not isinstance(l, Layer):
            raise TypeError, "Invalid layer type: " + `type(l)`
        if self.__sublayers is None:
            self.__sublayers = []
        if l in self.__sublayers:
            raise ValueError, "Layer already a sublayer: " + `l`
        self.__sublayers.append(l)
        self.sendMessage('added_sublayer', l)
        self.modified()

    def delSublayer(self, l):
        if l is not None and not isinstance(l, Layer):
            raise TypeError, "Invalid layer type: " + `type(l)`
        if self.__sublayers is None:
            raise ValueError, "Layer has no sublayers: " + `self`
        if l not in self.__sublayers:
            raise ValueError, "Layer not a sublayer: " + `l`
        self.__sublayers.remove(l)
        if len(self.__sublayers) == 0:
            self.__sublayers = None
        self.sendMessage('deleted_sublayer', l)
        self.modified()

    def hasSublayers(self):
        return self.__sublayers is not None and len(self.__sublayers) > 0

    def getSublayers(self):
        if self.__sublayers is not None:
            return self.__sublayers[:]
        return []

    def getScale(self):
        """Return the scale factor of the Layer.

getScale()
        """
        return self.__scale

    def setScale(self, scale):
        """Set the scale factor for the Layer.

setScale(scale)

The scale factor must be a positive float value greater than 0.0
        """
        _s = util.get_float(scale)
        if _s < 1e-10:
            raise ValueError, "Invalid scale factor: %g" % _s
        _os = self.__scale
        if abs(_os - _s) > 1e-10:
            self.startChange('scale_changed')
            self.__scale = _s
            self.endChange('scale_changed')
            self.sendMessage('scale_changed', _os)
            self.modified()

    scale = property(getScale, setScale, None, "Layer scale factor.")

    def getBoundary(self):
        """Return the maximum and minimum values of the object in the Layer.

getBoundary()

The function returns a tuple holding four float values:

(xmin, ymin, xmax, _ymax)

A default value of (-1.0, -1.0, 1.0, 1.0) is returned for a Layer
containing no objects.
        """
        _xmin = None
        _ymin = None
        _xmax = None
        _ymax = None
        for _obj in self.__points.getObjects():
            _x, _y = _obj.getCoords()
            if _xmin is None or _x < _xmin:
                _xmin = _x
            if _ymin is None or _y < _ymin:
                _ymin = _y
            if _xmax is None or _x > _xmax:
                _xmax = _x
            if _ymax is None or _y > _ymax:
                _ymax = _y
        for _obj in self.__arcs.getObjects():
            _axmin, _aymin, _axmax, _aymax = _obj.getBounds()
            if _xmin is None or _axmin < _xmin:
                _xmin = _axmin
            if _ymin is None or _aymin < _ymin:
                _ymin = _aymin
            if _xmax is None or _axmax > _xmax:
                _xmax = _axmax
            if _ymax is None or _aymax > _ymax:
                _ymax = _aymax
        for _obj in self.__circles.getObjects() + self.__ccircles.getObjects():
            _x, _y = _obj.getCenter().getCoords()
            _r = _obj.getRadius()
            _val = _x - _r
            if _xmin is None or _val < _xmin:
                _xmin = _val
            _val = _y - _r
            if _ymin is None or _val < _ymin:
                _ymin = _val
            _val = _x + _r
            if _xmax is None or _val > _xmax:
                _xmax = _val
            _val = _y + _r
            if _ymax is None or _val > _ymax:
                _ymax = _val
        _dims = (self.__ldims.getObjects() +
                 self.__hdims.getObjects() +
                 self.__vdims.getObjects() +
                 self.__rdims.getObjects() +
                 self.__adims.getObjects())
        for _obj in _dims:
            _dxmin, _dymin, _dxmax, _dymax = _obj.getBounds()
            if _xmin is None or _dxmin < _xmin:
                _xmin = _dxmin
            if _ymin is None or _dymin < _ymin:
                _ymin = _dymin
            if _xmax is None or _dxmax > _xmax:
                _xmax = _dxmax
            if _ymax is None or _dymax > _ymax:
                _ymax = _dymax
            _ds1, _ds2 = _obj.getDimstrings()
            _x, _y = _ds1.getLocation()
            _bounds = _ds1.getBounds()
            if _bounds is not None:
                _w, _h = _bounds
                if _x < _xmin:
                    _xmin = _x
                if (_y - _h) < _ymin:
                    _ymin = (_y - _h)
                if (_x + _w) > _xmax:
                    _xmax = (_x + _w)
                if _y > _ymax:
                    _ymax = _y
            if _obj.getDualDimMode():
                _x, _y = _ds2.getLocation()
                _bounds = _ds2.getBounds()
                if _bounds is not None:
                    _w, _h = _bounds
                    if _x < _xmin:
                        _xmin = _x
                    if (_y - _h) < _ymin:
                        _ymin = (_y - _h)
                    if (_x + _w) > _xmax:
                        _xmax = (_x + _w)
                    if _y > _ymax:
                        _ymax = _y
        for _textblock in self.__textblocks:
            _x, _y = _textblock.getLocation() # upper left corner
            _w = _h = 0.0
            _bounds = _textblock.getBounds()
            if _bounds is not None:
                _w, _h = _bounds
                _align = _textblock.getAlignment()
                if _align != text.TextStyle.ALIGN_LEFT:
                    if _align == text.TextStyle.ALIGN_CENTER:
                        _x = _x - _w/2.0
                    elif _align == text.TextStyle.ALIGN_RIGHT:
                        _x = _x - _w
            if _xmin is None or _x < _xmin:
                _xmin = _x
            if _ymin is None or (_y - _h) < _ymin:
                _ymin = (_y - _h)
            if _xmax is None or (_x + _w) > _xmax:
                _xmax = (_x + _w)
            if _ymax is None or _y > _ymax:
                _ymax = _y
        if _xmin is None: _xmin = -1.0
        if _ymin is None: _ymin = -1.0
        if _xmax is None: _xmax = 1.0
        if _ymax is None: _ymax = 1.0
        return _xmin, _ymin, _xmax, _ymax

    def objsInRegion(self, xmin, ymin, xmax, ymax, fully=False):
        """Return a all the objects in the Layer visible within the bounds.

objsInRegion(xmin, ymin, xmax, ymax[, fully])

The function has four required arguments:

xmin: The minimum x-value of the region
ymin: The minimum y-value of the region
xmax: The maximum x-value of the region
ymax: The maximum y-value of the region

There is a single optional argument:

fully: A True/False value indicating if the object must be
       entirely within the region [fully=True], or can
       merely pass through [fully=False]. The default value
       is False.

The function returns a list of objects.
        """
        _xmin = util.get_float(xmin)
        _ymin = util.get_float(ymin)
        _xmax = util.get_float(xmax)
        if xmax < xmin:
            raise ValueError, "Value error: xmax < xmin"
        _ymax = util.get_float(ymax)
        if _ymax < _ymin:
            raise ValueError, "Value error: ymax < ymin"
        util.test_boolean(fully)
        _objs = []
        _objs.extend(self.__points.getInRegion(_xmin, _ymin, _xmax, _ymax))
        _objs.extend(self.__segments.getInRegion(_xmin, _ymin, _xmax, _ymax))
        _objs.extend(self.__circles.getInRegion(_xmin, _ymin, _xmax, _ymax))
        _objs.extend(self.__arcs.getInRegion(_xmin, _ymin, _xmax, _ymax))
        _objs.extend(self.__hclines.getInRegion(_xmin, _ymin, _xmax, _ymax))
        _objs.extend(self.__vclines.getInRegion(_xmin, _ymin, _xmax, _ymax))
        _objs.extend(self.__aclines.getInRegion(_xmin, _ymin, _xmax, _ymax))
        _objs.extend(self.__clines.getInRegion(_xmin, _ymin, _xmax, _ymax))
        _objs.extend(self.__ccircles.getInRegion(_xmin, _ymin, _xmax, _ymax))
        for _obj in self.__chamfers:
            if _obj.inRegion(_xmin, _ymin, _xmax, _ymax):
                _objs.append(_obj)
        _objs.extend(self.__leaders.getInRegion(_xmin, _ymin, _xmax, _ymax))
        _objs.extend(self.__polylines.getInRegion(_xmin, _ymin, _xmax, _ymax))
        for _obj in self.__fillets:
            if _obj.inRegion(_xmin, _ymin, _xmax, _ymax):
                _objs.append(_obj)
        for _obj in self.__ldims.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _objs.append(_obj)
            _ds1, _ds2 = _obj.getDimstrings()
            _objs.append(_ds1)
            if _obj.getDualDimMode():
                _objs.append(_ds2)
        for _obj in self.__hdims.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _objs.append(_obj)
            _ds1, _ds2 = _obj.getDimstrings()
            _objs.append(_ds1)
            if _obj.getDualDimMode():
                _objs.append(_ds2)
        for _obj in self.__vdims.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _objs.append(_obj)
            _ds1, _ds2 = _obj.getDimstrings()
            _objs.append(_ds1)
            if _obj.getDualDimMode():
                _objs.append(_ds2)
        for _obj in self.__rdims.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _objs.append(_obj)
            _ds1, _ds2 = _obj.getDimstrings()
            _objs.append(_ds1)
            if _obj.getDualDimMode():
                _objs.append(_ds2)
        for _obj in self.__adims.getInRegion(_xmin, _ymin, _xmax, _ymax):
            _objs.append(_obj)
            _ds1, _ds2 = _obj.getDimstrings()
            _objs.append(_ds1)
            if _obj.getDualDimMode():
                _objs.append(_ds2)
        for _obj in self.__textblocks:
            _x, _y = _obj.getLocation()
            _bounds = _obj.getBounds()
            if _bounds is not None:
                _w, _h = _bounds
            else:
                _w = _h = 0                
            _txmin = _x
            _txmax = _x + _w
            _tymin = _y - _h
            _tymax = _y
            if not ((_txmax < _xmin) or
                    (_txmin > _xmax) or
                    (_tymax < _ymin) or
                    (_tymin > _ymax)):
                _objs.append(_obj)
        return _objs

    def sendsMessage(self, m):
        if m in Layer.__messages:
            return True
        return super(Layer, self).sendsMessage(m)

    def update(self):
        """Check that the objects in this layer are stored correctly.

update()

This function checks that the objects held in this layer are kept
in the proper order. Also, any duplicated objects that may have
be created due to modifying entities in the layer are removed.
        """
        raise RuntimeError, "Layer::update() called."

#
# Layer history class
#

class LayerLog(entity.EntityLog):
    def __init__(self, l):
        if not isinstance(l, Layer):
            raise TypeError, "Invalid layer type: " + `type(l)`
        super(LayerLog, self).__init__(l)
        l.connect('scale_changed', self._scaleChanged)
        l.connect('name_changed', self._nameChanged)
        l.connect('added_child', self._addedChild)
        l.connect('removed_child', self._removedChild)

    def _addedChild(self, l, *args):
        _alen = len(args)
        if _alen < 1:
            raise ValueError, "Invalid argument count: %d" % _alen
        _obj = args[0]
        _vals = _obj.getValues()
        if not isinstance(_vals, entity.EntityData):
            raise TypeError, "Unexpected type for values: " + `type(_obj)`
        _vals.lock()
        self.saveUndoData('added_child', _vals)

    def _removedChild(self, l, *args):
        _alen = len(args)
        if _alen < 1:
            raise ValueError, "Invalid argument count: %d" % _alen
        _obj = args[0]
        _vals = _obj.getValues()
        if not isinstance(_vals, entity.EntityData):
            raise TypeError, "Unexpected type for values: " + `type(_obj)`
        _vals.lock()
        self.saveUndoData('removed_child', _vals)

    def _nameChanged(self, l, *args):
        _alen = len(args)
        if _alen < 1:
            raise ValueError, "Invalid argument count: %d" % _alen
        _name = args[0]
        if not isinstance(_name, types.StringTypes):
            raise TypeError, "Unexpected type for name: " + `type(_name)`
        self.saveUndoData('name_changed', _name)

    def _scaleChanged(self, l, *args):
        _alen = len(args)
        if _alen < 1:
            raise ValueError, "Invalid argument count: %d" % _alen
        _scale = args[0]
        if not isinstance(_scale, float):
            raise TypeError, "Unexpected type for scale: " + `type(_scale)`
        if _scale < 1e-10:
            raise ValueError, "Invalid scale: %g" % _scale
        self.saveUndoData('scale_changed', _scale)

    def execute(self, undo, *args):
        # print "LayerLog::execute() ..."
        # print args
        util.test_boolean(undo)
        _alen = len(args)
        if len(args) == 0:
            raise ValueError, "No arguments to execute()"
        _l = self.getObject()
        _op = args[0]
        if _op == 'name_changed':
            if len(args) < 2:
                raise ValueError, "Invalid argument count: %d" % _alen
            _sdata = _l.getName()
            self.ignore(_op)
            try:
                _name = args[1]
                if undo:
                    _l.startUndo()
                    try:
                        _l.setName(_name)
                    finally:
                        _l.endUndo()
                else:
                    _l.startRedo()
                    try:
                        _l.setName(_name)
                    finally:
                        _l.endRedo()
            finally:
                self.receive(_op)
            self.saveData(undo, _op, _sdata)
        elif _op == 'scale_changed':
            if len(args) < 2:
                raise ValueError, "Invalid argument count: %d" % _alen
            _sdata = _l.getScale()
            self.ignore(_op)
            try:
                _scale = args[1]
                if undo:
                    _l.startUndo()
                    try:
                        _l.setScale(_scale)
                    finally:
                        _l.endUndo()
                else:
                    _l.startRedo()
                    try:
                        _l.setScale(_scale)
                    finally:
                        _l.endRedo()
            finally:
                self.receive(_op)
            self.saveData(undo, _op, _sdata)
        elif _op == 'added_child':
            if len(args) < 2:
                raise ValueError, "Invalid argument count: %d" % _alen
            _vals = args[1]
            if not isinstance(_vals, entity.EntityData):
                raise TypeError, "Unexpected type for values: " + `type(_vals)`
            self.ignore('modified')
            try:
                if undo:
                    _sdata = _vals
                    self.ignore('removed_child')
                    try:
                        self._delObject(undo, _vals)
                    finally:
                        self.receive('removed_child')
                else:
                    _obj = self._makeObject(_vals)
                    self.ignore(_op)
                    try:
                        _l.addObject(_obj)
                    finally:
                        self.receive(_op)
                    _sdata = _obj.getValues()
                    _sdata.lock()
            finally:
                self.receive('modified')
            self.saveData(undo, _op, _sdata)
        elif _op == 'removed_child':
            if len(args) < 2:
                raise ValueError, "Invalid argument count: %d" % _alen
            _vals = args[1]
            if not isinstance(_vals, entity.EntityData):
                raise TypeError, "Unexpected type for values: " + `type(_vals)`
            self.ignore('modified')
            try:
                if undo:
                    _obj = self._makeObject(_vals)
                    self.ignore('added_child')
                    try:
                        _l.startUndo()
                        try:
                            _l.addObject(_obj)
                        finally:
                            _l.endUndo()
                        _sdata = _obj.getValues()
                        _sdata.lock()
                    finally:
                        self.receive('added_child')
                else:
                    _sdata = _vals
                    self.ignore(_op)
                    try:
                        self._delObject(undo, _vals)
                    finally:
                        self.receive(_op)
            finally:
                self.receive('modified')
            self.saveData(undo, _op, _sdata)
        else:
            super(LayerLog, self).execute(undo, *args)

    def _getImageColor(self, r, g, b):
        _image = self.getObject().getParent()
        _color = None
        if _image is not None:
            for _ic in _image.getImageEntities('color'):
                if _ic.r == r and _ic.g == g and _ic.b == b:
                    _color = _ic
                    break
        if _color is None:
            _color = color.Color(r, g, b)
        return _color

    def _makeImageColor(self, values):
        # print "LayerLog::_makeImageColor() ..."
        _image = self.getObject().getParent()
        _cdata = values.get('color')
        _color = None
        if _image is not None and _cdata is not None:
            # print "restoring image color: " + str(_cdata)
            _r, _g, _b = _cdata
            for _ic in _image.getImageEntities('color'):
                if _ic.r == _r and _ic.g == _g and _ic.b == _b:
                    _color = _ic
                    break
        if _color is None and _cdata is not None: # make one
            _r, _g, _b = _cdata
            _color = color.Color(_r, _g, _b)
        return _color
        
    def _makeGraphicLinetype(self, values):
        # print "LayerLog::_makeGraphicLinetype() ..."
        _image = self.getObject().getParent()
        _ltdata = values.get('linetype')
        _linetype = None
        if _image is not None and _ltdata is not None:
            # print "restoring graphic linetype: " + str(_ltdata)
            _name, _dlist = _ltdata
            for _ilt in _image.getImageEntities('linetype'):
                if ((_ilt.getName() == _name) and (_ilt.getList() == _dlist)):
                    _linetype = _ilt
                    break
        if _linetype is None and _ltdata is not None: # make one
            _name, _dlist = _ltdata
            _linetype = linetype.Linetype(_name, _dlist)
        return _linetype
    
    def _makeGraphicStyle(self, values):
        # print "LayerLog::_makeGraphicStyle() ..."
        _image = self.getObject().getParent()
        _sdata = values.get('style')
        _style = None
        if _image is not None and _sdata is not None:
            # print "restoring graphic style: " + str(_sdata)
            _name, _lt, _col, _th = _sdata
            _ln, _ld = _lt
            for _istyle in _image.getImageEntities('style'):
                if _istyle.getName() != _name:
                    continue
                _ilt = _istyle.getLinetype()
                if ((_ilt.getName() != _ln) or (_ilt.getList() != _ld)):
                    continue
                if _istyle.getColor().getColors() != _col:
                    continue
                if abs(_istyle.getThickness() - _th) > 1e-10:
                    continue
                _style = _istyle
                break
        if _style is None and _sdata is not None: # make one
            _name, _lt, _col, _th = _sdata
            _r, _g, _b = _col
            _color = self._getImageColor(_r, _g, _b)
            _linetype = linetype.Linetype(_lt[0], _lt[1])
            _style = style.Style(_name, _linetype, _color, _th)
        return _style

    def _resetGraphicValues(self, obj, values):
        # print "_resetGraphicValues() ..."
        _style = self._makeGraphicStyle(values)
        if _style is not None:
            # print "resetting style ..."
            obj.setStyle(_style)
        _linetype = self._makeGraphicLinetype(values)
        if _linetype is not None:
            # print "resetting linetype ..."
            obj.setLinetype(_linetype)
        _color = self._makeImageColor(values)
        if _color is not None:
            # print "resetting color ..."
            obj.setColor(_color)
        _thickness = values.get('thickness')
        if _thickness is not None:
            # print "resetting thickness ..."
            obj.setThickness(_thickness)
        
    def _makeTextStyle(self, values):
        # print "LayerLog::_makeTextStyle() ..."
        _image = self.getObject().getParent()
        _tdata = values.get('textstyle')
        _textstyle = None
        if _image is not None and _tdata is not None:
            # print "restoring textstyle: " + str(_tdata)
            for _ts in _image.getImageEntities('textstyle'):
                # print "Comparing stored TextStyle: %s " % _ts.getName()
                if _ts.getName() != _tdata['name']:
                    # print "name differs"
                    continue
                if _ts.getFamily() != _tdata['family']:
                    # print "family differs"
                    continue
                if _ts.getStyle() != _tdata['style']:
                    # print "style differs"
                    continue
                _c = _ts.getColor()
                _r, _g, _b = _tdata['color']
                if ((_c.r != _r) or (_c.g != _g) or (_c.b != _b)):
                    # print "color differs"
                    continue
                if abs(_ts.getSize() - _tdata['size']) > 1e-10:
                    # print "size differs"
                    continue
                if abs(_ts.getAngle() - _tdata['angle']) > 1e-10:
                    # print "angle differs"
                    continue
                if _ts.getAlignment() != _tdata['align']:
                    # print "alignment differs"
                    continue
                _textstyle = _ts
                break
        if _textstyle is None and _tdata is not None: # make one
            # print "Creating new TextStyle instance"
            _r, _g, _b = _tdata['color']
            _color = self._getImageColor(_r, _g, _b)
            _textstyle = text.TextStyle(_tdata['name'],
                                        family=_tdata['family'],
                                        style=_tdata['style'],
                                        weight=_tdata['weight'],
                                        color=_color,
                                        size=_tdata['size'],
                                        angle=_tdata['angle'],
                                        align=_tdata['align'])
        return _textstyle

    def _makeDimStyle(self, values):
        # print "LayerLog::_makeDimStyle() ..."
        _image = self.getObject().getParent()
        _dsdata = values.get('dimstyle')
        _dimstyle = None
        if _image is not None and _dsdata is not None:
            # print "restoring dimstylstyle: " + str(_tdata)
            _name = _dsdata['name']
            _dscopy = {}
            for _key in _dsdata.keys():
                if _key != 'name':
                    _dscopy[_key] = _dsdata[_key]
            for _ds in _image.getImageEntities('dimstyle'):
                if _ds.getName() != _name:
                    continue
                _keys = _ds.getKeys()
                _seen = True
                for _key in _keys:
                    if _key not in _dscopy:
                        _seen = False
                        break
                if not _seen:
                    continue
                for _key in _dscopy:
                    if _key not in _keys:
                        _seen = False
                        break
                if not _seen:
                    continue
                _hit = True
                for _key, _val in _dscopy.items():
                    _dsv = _ds.getValue(_key)
                    if ((_key == 'DIM_COLOR') or
                        (_key == 'DIM_PRIMARY_FONT_COLOR') or
                        (_key == 'DIM_SECONDARY_FONT_COLOR')):
                        if _dsv.getColors() != _val:
                            _hit = False
                            break
                    else:
                        if _dsv != _val:
                            _hit = False
                            break
                if not _hit:
                    continue
                # print "hit on existing DimStyle ..."
                _dimstyle = _ds
                break
        if _dimstyle is None and _dsdata is not None: # make one
            # print "making new DimStyle ..."
            _name = _dsdata['name']
            _vals = {}
            for _key in _dsdata.keys():
                if _key != 'name':
                    _val = _dsdata[_key]
                    if ((_key == 'DIM_COLOR') or
                        (_key == 'DIM_PRIMARY_FONT_COLOR') or
                        (_key == 'DIM_SECONDARY_FONT_COLOR')):
                        _r, _g, _b = _val
                        _color = self._getImageColor(_r, _g, _b)
                        _vals[_key] = _color
                    else:
                        _vals[_key] = _val
            _dimstyle = dimension.DimStyle(_name, _vals)
        return _dimstyle
        
    def _makeDimString(self, values):
        # print "LayerLog::_makeDimString() ..."
        _textstyle = self._makeTextStyle(values)
        _id = values.get('id')
        if _id is None:
            raise ValueError, "Lost 'id' for recreating DimString"
        _val = values.get('location')
        if _val is None:
            raise ValueError, "Lost 'location' value for DimString"
        _x, _y = _val
        _ds = dimension.DimString(_x, _y, textstyle=_textstyle, id=_id)
        #
        # TextBlock info
        #
        _val = values.get('family')
        if _val is not None:
            _ds.setFamily(_val)
        _val = values.get('style')
        if _val is not None:
            _ds.setStyle(_val)
        _val = values.get('weight')
        if _val is not None:
            _ds.setWeight(_val)
        _val = values.get('color')
        if _val is not None:
            _r, _g, _b = _val
            _ds.setColor(self._getImageColor(_r, _g, _b))
        _val = values.get('size')
        if _val is not None:
            _ds.setSize(_val)
        _val = values.get('angle')
        if _val is not None:
            _ds.setAngle(_val)
        _val = values.get('alignment')
        if _val is not None:
            _ds.setAlignment(_val)
        #
        # DimString info
        #
        _val = values.get('prefix')
        if _val is None:
            raise ValueError, "Lost 'prefix' value for DimString"
        _ds.setPrefix(_val)
        _val = values.get('suffix')
        if _val is None:
            raise ValueError, "Lost 'suffix' value for DimString"
        _ds.setSuffix(_val)
        _val = values.get('units')
        if _val is None:
            raise ValueError, "Lost 'units' value for DimString"
        if _val == 'millimeters':
            _unit = units.MILLIMETERS
        elif _val == 'micrometers':
            _unit = units.MICROMETERS
        elif _val == 'meters':
            _unit = units.METERS
        elif _val == 'kilometers':
            _unit = units.KILOMETERS
        elif _val == 'inches':
            _unit = units.INCHES
        elif _val == 'feet':
            _unit = units.FEET
        elif _val == 'yards':
            _unit = units.YARDS
        elif _val == 'miles':
            _unit = units.MILES
        else:
            raise ValueError, "Unexpected unit: %s" % _val
        _ds.setUnits(_unit)
        _val = values.get('precision')
        if _val is None:
            raise ValueError, "Lost 'precision' value for DimString"
        _ds.setPrecision(_val)
        _val = values.get('print_zero')
        if _val is None:
            raise ValueError, "Lost 'print_zero' value for DimString"
        _ds.setPrintZero(_val)
        _val = values.get('print_decimal')
        if _val is None:
            raise ValueError, "Lost 'print_decimal' value for DimString"
        _ds.setPrintDecimal(_val)
        return _ds

    def _adjustDimension(self, obj, values):
        # print "LayerLog::_adjustDimension() ..."
        _val = values.get('offset')
        if _val is not None:
            obj.setOffset(_val)
        _val = values.get('extension')
        if _val is not None:
            obj.setExtension(_val)
        _val = values.get('position')
        if _val is not None:
            obj.setPosition(_val)
        _val = values.get('eptype')
        if _val is not None:
            obj.setEndpointType(_val)
        _val = values.get('epsize')
        if _val is not None:
            obj.setEndpointSize(_val)
        _val = values.get('color')
        if _val is not None:
            _r, _g, _b = _val
            obj.setColor(self._getImageColor(_r, _g, _b))
        _val = values.get('dualmode')
        if _val is not None:
            obj.setDualDimMode(_val)
        _val = values.get('poffset')
        if _val is not None:
            obj.setPositionOffset(_val)
        _val = values.get('dmoffset')
        if _val is not None:
            obj.setDualModeOffset(_val)
        _val = values.get('thickness')
        if _val is not None:
            obj.setThickness(_val)
        
    def _makeObject(self, values):
        _type = values.get('type')
        if _type is None:
            _keys = values.keys()
            _keys.sort()
            for _key in _keys:
                print "key: %s: value: %s" % (_key, str(values.get(_key)))
            raise RuntimeError, "No type defined for these values"
        _id = values.get('id')
        if _id is None:
            raise ValueError, "Lost 'id' for recreating object"
        _l = self.getObject()
        _obj = None
        #
        if _type == 'point':
            _x = values.get('x')
            if _x is None:
                raise ValueError, "Lost 'x' value for Point"
            _y = values.get('y')
            if _y is None:
                raise ValueError, "Lost 'y' value for Point"
            _obj = point.Point(_x, _y, id=_id)
        elif _type == 'segment':
            _p1id = values.get('p1')
            if _p1id is None:
                raise ValueError, "Lost 'p1' value for Segment"
            _p1 = _l.getObject(_p1id)
            if _p1 is None or not isinstance(_p1, point.Point):
                raise ValueError, "Segment P1 point missing; id=%d" % _p1id
            _p2id = values.get('p2')
            if _p2id is None:
                raise ValueError, "Lost 'p2' value for Segment"
            _p2 = _l.getObject(_p2id)
            if _p2 is None or not isinstance(_p2, point.Point):
                raise ValueError, "Segment P2 point missing; id=%d" % _p2id
            _obj = segment.Segment(_p1, _p2, id=_id)
            self._resetGraphicValues(_obj, values)
        elif _type == 'circle':
            _cid = values.get('center')
            if _cid is None:
                raise ValueError, "Lost 'center' value for Circle"
            _cp = _l.getObject(_cid)
            if _cp is None or not isinstance(_cp, point.Point):
                raise ValueError, "Circle center missing: id=%d" % _cid
            _r = values.get('radius')
            if _r is None:
                raise ValueError, "Lost 'radius' value for Circle"
            _obj = circle.Circle(_cp, _r, id=_id)
            self._resetGraphicValues(_obj, values)
        elif _type == 'arc':
            _cid = values.get('center')
            if _cid is None:
                raise ValueError, "Lost 'center' value for Arc."
            _cp = _l.getObject(_cid)
            if _cp is None or not isinstance(_cp, point.Point):
                raise ValueError, "Arc center missing: id=%d" % _cid
            _r = values.get('radius')
            if _r is None:
                raise ValueError, "Lost 'radius' value for Arc."
            _sa = values.get('start_angle')
            if _sa is None:
                raise ValueError, "Lost 'start_angle' value for Arc."
            _ea = values.get('end_angle')
            if _ea is None:
                raise ValueError, "Lost 'end_angle' value for Arc."
            _obj = arc.Arc(_cp, _r, _sa, _ea, id=_id)
            self._resetGraphicValues(_obj, values)
        elif _type == 'ellipse':
            raise TypeError, "Ellipse not yet handled ..."
        elif _type == 'leader':
            _p1id = values.get('p1')
            if _p1id is None:
                raise ValueError, "Lost 'p1' value for Leader."
            _p1 = _l.getObject(_p1id)
            if _p1 is None or not isinstance(_p1, point.Point):
                raise ValueError, "Leader P1 point missing: id=%d" % _p1id
            _p2id = values.get('p2')
            if _p2id is None:
                raise ValueError, "Lost 'p2' value for Leader."
            _p2 = _l.getObject(_p2id)
            if _p2 is None or not isinstance(_p2, point.Point):
                raise ValueError, "Leader P2 point missing: id=%d" % _p2id
            _p3id = values.get('p3')
            if _p3id is None:
                raise ValueError, "Lost 'p3' value for Leader."
            _p3 = _l.getObject(_p3id)
            if _p3 is None or not isinstance(_p3, point.Point):
                raise ValueError, "Leader P3 point missing: id=%d" % _p3id
            _size = values.get('size')
            if _size is None:
                raise ValueError, "Lost 'size' value for Leader."
            _obj = leader.Leader(_p1, _p2, _p3, _size, id=_id)
            self._resetGraphicValues(_obj, values)
        elif _type == 'polyline':
            _pids = values.get('points')
            _pts = []
            for _ptid in _pids:
                _p = _l.getObject(_ptid)
                if _p is None or not isinstance(_p, point.Point):
                    raise ValueError, "Polyline point missing: id=%d" % _ptid
                _pts.append(_p)
            _obj = polyline.Polyline(_pts, id=_id)
            self._resetGraphicValues(_obj, values)
        elif _type == 'textblock':
            _loc = values.get('location')
            if _loc is None:
                raise ValueError, "Lost 'location' value for TextBlock."
            _x, _y = _loc
            _text = values.get('text')
            if _text is None:
                raise ValueError, "Lost 'text' value for TextBlock."
            _tstyle = self._makeTextStyle(values)
            _obj = text.TextBlock(_x, _y, _text, textstyle=_tstyle, id=_id)
            _val = values.get('family')
            if _val is not None:
                _obj.setFamily(_val)
            _val = values.get('style')
            if _val is not None:
                _obj.setStyle(_val)
            _val = values.get('weight')
            if _val is not None:
                _obj.setWeight(_val)
            _val = values.get('color')
            if _val is not None:
                _r, _g, _b = _val
                _obj.setColor(self._getImageColor(_r, _g, _b))
            _val = values.get('size')
            if _val is not None:
                _obj.setSize(_val)
            _val = values.get('angle')
            if _val is not None:
                _obj.setAngle(_val)
            _val = values.get('alignment')
            if _val is not None:
                _obj.setAlignment(_val)
        elif _type == 'hcline':
            _kid = values.get('keypoint')
            if _kid is None:
                raise ValueError, "Lost 'keypoint' value for HCLine."
            _p = _l.getObject(_kid)
            if _p is None or not isinstance(_p, point.Point):
                raise ValueError, "HCLine point missing: id=%d" % _kid
            _obj = hcline.HCLine(_p, id=_id)
        elif _type == 'vcline':
            _kid = values.get('keypoint')
            if _kid is None:
                raise ValueError, "Lost 'keypoint' value for VCLine."
            _p = _l.getObject(_kid)
            if _p is None or not isinstance(_p, point.Point):
                raise ValueError, "VCLine point missing: id=%d" % _kid
            _obj = vcline.VCLine(_p, id=_id)
        elif _type == 'acline':
            _kid = values.get('keypoint')
            if _kid is None:
                raise ValueError, "Lost 'keypoint' value for ACLine."
            _p = _l.getObject(_kid)
            if _p is None or not isinstance(_p, point.Point):
                raise ValueError, "ACLine point missing: id=%d" % _kid
            _angle = values.get('angle')
            if _angle is None:
                raise ValueError, "Lost 'angle' value for ACLine."
            _obj = acline.ACLine(_p, _angle, id=_id)
        elif _type == 'cline':
            _p1id = values.get('p1')
            if _p1id is None:
                raise ValueError, "Lost 'p1' value for CLine"
            _p1 = _l.getObject(_p1id)
            if _p1 is None or not isinstance(_p1, point.Point):
                raise ValueError, "CLine P1 point missing: id=%d" % _p1id
            _p2id = values.get('p2')
            if _p2id is None:
                raise ValueError, "Lost 'p2' value for CLine"
            _p2 = _l.getObject(_p2id)
            if _p2 is None or not isinstance(_p2, point.Point):
                raise ValueError, "CLine P2 point missing: id=%d" % _p2id
            _obj = cline.CLine(_p1, _p2, id=_id)
        elif _type == 'ccircle':
            _cid = values.get('center')
            if _cid is None:
                raise ValueError, "Lost 'center' value for CCircle"
            _cp = _l.getObject(_cid)
            if _cp is None or not isinstance(_cp, point.Point):
                raise ValueError, "CCircle center missing: id=%d" % _cid
            _r = values.get('radius')
            if _r is None:
                raise ValueError, "Lost 'radius' value for CCircle"
            _obj = ccircle.CCircle(_cp, _r, id=_id)
        elif _type == 'fillet':
            _s1id = values.get('s1')
            if _s1id is None:
                raise ValueError, "Lost 's1' value for Fillet"
            _s1 = _l.getObject(_s1id)
            if _s1 is None or not isinstance(_s1, segment.Segment):
                raise ValueError, "Fillet S1 segment missing: id=%d" % _s1id
            _s2id = values.get('s2')
            if _s2id is None:
                raise ValueError, "Lost 's2' value for Fillet"
            _s2 = _l.getObject(_s2id)
            if _s2 is None or not isinstance(_s2, segment.Segment):
                raise ValueError, "Fillet S2 segment missing: id=%d" % _s2id
            _r = values.get('radius')
            if _r is None:
                raise ValueError, "Lost 'radius' value for Fillet"
            _obj = segjoint.Fillet(_s1, _s2, _r, id=_id)
        elif _type == 'chamfer':
            _s1id = values.get('s1')
            if _s1id is None:
                raise ValueError, "Lost 's1' value for Chamfer"
            _s1 = _l.getObject(_s1id)
            if _s1 is None or not isinstance(_s1, segment.Segment):
                raise ValueError, "Fillet S1 segment missing: id=%d" % _s1id
            _s2id = values.get('s2')
            if _s2id is None:
                raise ValueError, "Lost 's2' value for Chamfer"
            _s2 = _l.getObject(_s2id)
            if _s2 is None or not isinstance(_s2, segment.Segment):
                raise ValueError, "Fillet S2 segment missing: id=%d" % _s2id
            _len = values.get('length')
            if _len is None:
                raise ValueError, "Lost 'length' value for Chamfer"
            _obj = segjoint.Chamfer(_s1, _s2, _len, id=_id)
        elif _type == 'ldim' or _type == 'hdim' or _type == 'vdim':
            _loc = values.get('location')
            if _loc is None:
                raise ValueError, "Lost 'location' value for L/H/V Dimension."
            _x, _y = _loc
            _l1id = values.get('l1')
            if _l1id is None:
                raise ValueError, "Lost 'l1' value for L/H/V Dimension."
            _p1id = values.get('p1')
            if _p1id is None:
                raise ValueError, "Lost 'p1' value for L/H/V Dimension."
            _l2id = values.get('l2')
            if _l2id is None:
                raise ValueError, "Lost 'l2' value for L/H/V Dimension."
            _p2id = values.get('p2')
            if _p2id is None:
                raise ValueError, "Lost 'p2' value for L/H/V Dimension."
            _l1 = _p1 = _l2 = _p2 = None
            _lid = _l.getID()
            _img = _l.getParent()
            if _img is None:
                raise ValueError, "Layer has no parent Image"
            if _l1id == _lid:
                _l1 = _l
            else:
                _l1 = _img.getObject(_l1id)
                if _l1 is None or not isinstance(_l1, Layer):
                    raise ValueError, "Dimension L1 layer missing: id=%d" % _l1id
            _p1 = _l1.getObject(_p1id)
            if _p1 is None or not isinstance(_p1, point.Point):
                raise ValueError, "Dimension P1 point missing: id=%d" % _p1id
            if _l2id == _lid:
                _l2 = _l
            else:
                _l2 = _img.getObject(_l2id)
                if _l2 is None or not isinstance(_l2, Layer):
                    raise ValueError, "Dimension L2 layer missing: id=%d" % _l2id
            _p2 = _l2.getObject(_p2id)
            if _p2 is None or not isinstance(_p2, point.Point):
                raise ValueError, "Dimension P2 point missing: id=%d" % _p2id
            _ds = self._makeDimStyle(values)
            _dsdata = values.get('ds1')
            if _dsdata is None:
                raise ValueError, "Lost 'ds1' value for L/H/V Dimension."
            _ds1 = self._makeDimString(_dsdata)
            _dsdata = values.get('ds2')
            if _dsdata is None:
                raise ValueError, "Lost 'ds2' value for L/H/V Dimension."
            _ds2 = self._makeDimString(_dsdata)
            if _ds is None:
                _ds = _img.getOption('DIM_STYLE')
            if _type == 'ldim':
                _objtype = dimension.LinearDimension
            elif _type == 'hdim':
                _objtype = dimension.HorizontalDimension
            elif _type == 'vdim':
                _objtype = dimension.VerticalDimension
            else:
                raise ValueError, "Unexpected type: %s" % _type
            _obj = _objtype(_l1, _p1, _l2, _p2, _x, _y, _ds,
                            ds1=_ds1, ds2=_ds2, id=_id)
            self._adjustDimension(_obj, values)
        elif _type == 'rdim':
            _loc = values.get('location')
            if _loc is None:
                raise ValueError, "Lost 'location' value for RadialDimension."
            _x, _y = _loc
            _lid = values.get('layer')
            if _lid is None:
                raise ValueError, "Lost 'layer' value for RadialDimension."
            _cid = values.get('circle')
            if _cid is None:
                raise ValueError, "Lost 'circle' value for RadialDimension."
            _cl = _c = None
            _img = _l.getParent()
            if _img is None:
                raise ValueError, "Layer has no parent Image"
            if _lid == _l.getID():
                _cl = _l
            else:
                _cl = _img.getObject(_lid)
                if _cl is None or not isinstance(_cl, Layer):
                    raise ValueError, "Dimension Layer missing: id=%d" % _lid
            _c = _cl.getObject(_cid)
            if _c is None or not isinstance(_c, (circle.Circle, arc.Arc)):
                raise ValueError, "Dimension Circle/Arc missing: id=%d" % _cid
            _ds = self._makeDimStyle(values)
            _dsdata = values.get('ds1')
            if _dsdata is None:
                raise ValueError, "Lost 'ds1' value for RadialDimension."
            _ds1 = self._makeDimString(_dsdata)
            _dsdata = values.get('ds2')
            if _dsdata is None:
                raise ValueError, "Lost 'ds2' value for RadialDimension."
            _ds2 = self._makeDimString(values.get('ds2'))
            _obj = dimension.RadialDimension(_cl, _c, _x, _y, _ds,
                                             ds1=_ds1, ds2=_ds2, id=_id)
            self._adjustDimension(_obj, values)
        elif _type == 'adim':
            _x, _y = values.get('location')
            _vlid = values.get('vl')
            if _vlid is None:
                raise ValueError, "Lost 'vl' value for AngularDimension."
            _vpid = values.get('vp')
            if _vpid is None:
                raise ValueError, "Lost 'vp' value for AngularDimension."
            _l1id = values.get('l1')
            if _l1id is None:
                raise ValueError, "Lost 'l1' value for AngularDimension."
            _p1id = values.get('p1')
            if _p1id is None:
                raise ValueError, "Lost 'p1' value for AngularDimension."
            _l2id = values.get('l2')
            if _l2id is None:
                raise ValueError, "Lost 'l2' value for AngularDimension."
            _p2id = values.get('p2')
            if _p2id is None:
                raise ValueError, "Lost 'p2' value for AngularDimension."
            _vl = _vp = _l1 = _p1 = _l2 = _p2 = None
            _lid = _l.getID()
            _img = _l.getParent()
            if _img is None:
                raise ValueError, "Layer has no parent Image"
            if _vlid == _lid:
                _vl = _l
            else:
                _vl = _img.getObject(_vlid)
                if _vl is None or not isinstance(_vl, Layer):
                    raise ValueError, "Dimension vertex layer missing: id=%d" % _vlid
            _vp = _vl.getObject(_vpid)
            if _vp is None or not isinstance(_vp, point.Point):
                raise ValueError, "Dimension vertex point missing: id=%d" % _vpid
            if _l1id == _lid:
                _l1 = _l
            else:
                _l1 = _img.getObject(_l1id)
                if _l1 is None or not isinstance(_l1, Layer):
                    raise ValueError, "Dimension L1 layer missing: id=%d" % _l1id
            _p1 = _l1.getObject(_p1id)
            if _p1 is None or not isinstance(_p1, point.Point):
                raise ValueError, "Dimension P1 point missing: id=%d" % _p1id
            if _l2id == _lid:
                _l2 = _l
            else:
                _l2 = _img.getObject(_l2id)
                if _l2 is None or not isinstance(_l2, Layer):
                    raise ValueError, "Dimension L2 layer missing: id=%d" % _l2id
            _p2 = _l2.getObject(_p2id)
            if _p2 is None or not isinstance(_p2, point.Point):
                raise ValueError, "Dimension P2 point missing: id=%d" % _p2id
            _ds = self._makeDimStyle(values)
            _dsdata = values.get('ds1')
            if _dsdata is None:
                raise ValueError, "Lost 'ds1' value for AngularDimension."
            _ds1 = self._makeDimString(_dsdata)
            _dsdata = values.get('ds2')
            if _dsdata is None:
                raise ValueError, "Lost 'ds2' value for AngularDimension."
            _ds2 = self._makeDimString(values.get('ds2'))
            _obj = dimension.AngularDimension(_vl, _vp, _l1, _p1, _l2, _p2,
                                              _x, _y, _ds,
                                              ds1=_ds1, ds2=_ds2, id=_id)
            self._adjustDimension(_obj, values)
        else:
            raise TypeError, "Unexpected type: %s"  % _type
        return _obj

    def _delObject(self, undo, values):
        # print "_delObject() ..."
        _type = values.get('type')
        _id = values.get('id')
        # print "id: %d" % _id
        _l = self.getObject()
        _obj = _l.getObject(_id)
        if _obj is None:
            raise ValueError, "Missed object: %d, %s" % (_id, _type)
        #
        # layer still has to send messages out like  'deleted_child'
        #
        if undo:
            _l.startUndo()
            try:
                _l.delObject(_obj)
            finally:
                _l.endUndo()
        else:
            _l.startRedo()
            try:
                _l.delObject(_obj)
            finally:
                _l.endRedo()
