1#!/usr/local/bin/python3.8
2# -*- coding: utf-8 -*-
3# SPDX-FileCopyrightText: 2005 Maurizio Paolini-Daniele Zambelli
4# SPDX-FileCopyrightText: 2011 Bartosz Dziewoński
5# (licensed under GPL)
6
7version="0.2.11"
8
9#####
10# Type constants
11#####
12TI=type(0)
13TF=type(0.)
14TS=type("")
15TT=type((0, 0))
16
17#####
18# Constants: Point Style, Line Style, default values...
19#####
20PS=("Round", "RoundEmpty", "Rectangular", "RectangularEmpty", "Cross")
21LS=("SolidLine", "DashLine", "DashDotLine", "DashDotDotLine", "DotLine")
22KIGTRUE="true"
23KIGFALSE="false"
24DEFWIDTH=-1
25DEFCOLOR="#0000ff"
26DEFNAME="none"
27PROPERTY_INI="Property which"
28OBJECT_INI="Object type"
29PROPERTY_END="Property"
30OBJECT_END="Object"
31
32#
33# this is a trick to allow definitions like "p=Point(0,0,HIDDEN)"
34#
35HIDDEN=KIGFALSE
36VISIBLE=KIGTRUE
37
38#####
39# Validating parameters
40#####
41
42def parameter(val, defval):
43  if val==None: return defval
44  else:         return val
45
46def validshown(shown):
47  if shown==KIGTRUE or shown==KIGFALSE: return shown
48
49def validwidth(width):
50  if type(width)==TI: return width
51
52def validpointstyle(ps):
53  if ps in PS: return ps
54
55def validname(name):
56  if type(name)==TS: return name
57
58def validlinestyle(ls):
59  if ls in LS: return ls
60
61def validcolor(color):
62  if type(color)==TS: return color
63
64#####
65# if as a function
66#####
67
68def rif(condition, val1, val2):
69  """Return val1 if condition is True; else return val2."""
70  if condition: return val1
71  else:         return val2
72
73#####
74# Force some Python variables as kig variables
75#####
76
77def kig_double(val):
78  tp=type(val)
79  if tp==TI or tp==TF: return Double(val)
80  else:                return val
81
82def kig_int(val):
83  tp=type(val)
84  if tp==TI:           return Int(val)
85  else:                return val
86
87def kig_string(val):
88  tp=type(val)
89  if tp==TS:           return String(val)
90  else:                return val
91
92def kig_point(val):
93  tp=type(val)
94  if tp==TT:
95    x, y = val
96    return Point(x, y, internal=True)
97  else:
98    return val
99
100def kig_relpoint(obj, displ):
101  x, y = displ
102  return RelativePoint(x, y, obj, internal=True)
103
104#####
105# base classes
106#####
107
108#####
109# KigDocument class
110#####
111
112class KigDocument(object):
113  """A class representing a Kig document.
114
115    ancestor chain:
116      KigDocument <- object
117
118    class attributes:
119
120    attributes:
121      axes
122      grid
123      outfilename
124      outfile
125      callkig
126      of
127      viewkig
128      hierarchy
129      internal
130      width
131      pointstyle
132      name
133      linestyle
134      shown
135      color
136
137    methods:
138      viewappend
139      hierarchyappend
140      setcallkig
141      setof
142      str_open
143      close
144      noaxes
145      nogrid
146      hideobjects
147      showobjects
148      setwidth
149      setpointstyle
150      setname
151      setlinestyle
152      setshown
153      setcolor
154      setinternal
155  """
156
157  def __init__(self, outfilename, callkig=True, of=False):
158#    print "KigDocument.__init__()"
159    self.axes = "1"
160    self.grid = "1"
161    self.outfilename=outfilename
162    self.callkig=callkig
163    self.of=of
164    try:
165      self.outfile = open(outfilename, 'w')
166    except IOError as value:
167#      print >> sys.stderr, outfilename, 'unwritable'
168      print(value,  file=sys.stderr)
169      sys.exit(2)
170#    KigOut._kigdocument=self
171    KigDOP._kd=self
172    KigView._kd=self
173    self.viewkig=[]
174    self.hierarchy=[]
175# Default values
176    self.internal=False
177    self.width=DEFWIDTH
178    self.pointstyle=PS[0]
179    self.name=DEFNAME
180    self.linestyle=LS[0]
181    self.shown=VISIBLE
182    self.color=DEFCOLOR
183
184
185  def viewappend(self, e):          self.viewkig.append(e)
186  def hierarchyappend(self, e):     self.hierarchy.append(e)
187  def setcallkig(v):                self.callkig=v
188  def setof(v):                     self.of=v
189
190  def str_open(self):
191    return """<?xml version="1.0" encoding="utf-8"?>
192<!DOCTYPE KigDocument>
193<KigDocument axes="%s" grid="%s" CompatibilityVersion="0.7.0" Version="0.9.1" >
194 <CoordinateSystem>Euclidean</CoordinateSystem>
195 <Hierarchy>
196""" % (self.axes, self.grid)
197
198  def close(self):
199    try:
200      self.outfile.write(self.str_open())
201      self.outfile.writelines(self.hierarchy)
202      self.outfile.write(" </Hierarchy>\n <View>\n")
203      for f in self.viewkig:
204        self.outfile.write(f.str_view())
205      self.outfile.write(" </View>\n</KigDocument>\n")
206      if self.outfile != sys.stdout:
207        self.outfile.close()
208    except IOError as value:
209      print(value, file=sys.stderr)
210      sys.exit(2)
211    try:
212      if self.callkig:
213        err = os.system('kig ' + self.outfilename)
214    except Exception as value:
215      print(value, file=sys.stderr)
216    if not self.of:
217      os.system('rm ' + self.outfilename)
218
219  def noaxes(self):            self.axes="0"
220  def nogrid(self):            self.grid="0"
221  def hideobjects(self):       self.shown=HIDDEN
222  def showobjects(self):       self.shown=VISIBLE
223  def setwidth(self, w):       self.width=w
224  def setpointstyle(self, ps): self.pointstyle=ps
225  def setname(self, n):        self.name=n
226  def setlinestyle(self, ls):  self.linestyle=ls
227  def setshown(self, s):       self.shown=s
228  def setcolor(self, c):       self.color=c
229  def setinternal(self, v):    self.internal=v
230
231#####
232# KigDOP class
233#####
234
235#class KigDOP(KigOut):
236class KigDOP(object):
237  """An class from which all elements having an id (Data, Object, Property) inherit.
238
239    ancestor chain:
240      KigDOP <- object
241
242    class attributes:
243      id-counter
244
245    attributes:
246      id
247      type
248
249    methods:
250      getid
251      str_hierarchy
252  """
253  _kd=None
254  _id_counter=0
255
256  def __init__(self, type):
257    KigDOP._id_counter+=1
258    self.id=KigDOP._id_counter
259    self._type=type
260#    self.getkigdocument().hierarchyappend(self.str_hierarchy())
261    KigDOP._kd.hierarchyappend(self.str_hierarchy())
262
263  def getid(self):          return str(self.id)
264  def str_hierarchy(self):  pass
265
266#####
267# KigView class
268#####
269
270#class KigView(KigOut):
271class KigView(object):
272  """A class containing visualization data.
273
274    ancestor chain:
275      KigView <- object
276
277    class attributes:
278      _kd
279
280    attributes:
281      shown
282      width
283      style
284      color
285      name
286      pointstyle
287
288    methods:
289      str_view
290      show
291      hide
292  """
293  _kd=None
294
295  def __init__(self, object, shown, name, width, pointstyle, linestyle, color):
296    self.object=object
297    self.shown      = parameter(shown, KigView._kd.shown)
298    self.width      = parameter(width, KigView._kd.width)
299    self.pointstyle = parameter(pointstyle, KigView._kd.pointstyle)
300    self.linestyle  = parameter(linestyle, KigView._kd.linestyle)
301    self.color      = parameter(color, KigView._kd.color)
302    self.name       = parameter(name, KigView._kd.name)
303    KigView._kd.viewappend(self)
304
305  def str_view(self):
306    """Returns a string which can be placed inside <View> tags.
307
308    example:
309  <Draw width="-1" point-style="Round" namecalcer="none"
310style="SolidLine" shown=None color="#0000ff" object="3" />
311"""
312
313    return '  <Draw width="%s" point-style="%s" namecalcer="%s"\
314 style="%s" shown="%s" color="%s" object="%s" />\n' %\
315           (self.width, self.pointstyle, self.name,
316            self.linestyle, self.shown, self.color, self.object.getid())
317
318#####
319# Data class
320#####
321
322class Data(KigDOP):
323  """An class from which all Data elements inherit.
324
325    ancestor chain:
326      Data <- KigDOP <- object
327
328    attributes:
329      val
330
331    methods:
332      str_hierarchy
333"""
334  def __init__(self, type, val):
335    self.val=val
336    KigDOP.__init__(self, type)
337
338  def str_hierarchy(self):
339    """Returns a string which can be placed inside <Hierarchy> tags.
340
341    example:
342  <Data type="double" id="170" >0.1</Data>
343"""
344    return '  <Data type="%s" id="%s" >%s</Data>\n' % \
345          (self._type, self.getid(), self.val)
346
347#####
348# PropObj class
349#####
350
351class PropObj(KigDOP):
352  """A class from which all visible elements inherit.
353
354    ancestor chain:
355      PropObj <- KigDOP <- object
356
357    class attributes:
358
359    attributes:
360      prop
361      objvec
362      view
363
364    methods:
365      str_hierarchy
366      showname(self, n)
367      show(self)
368      hide(self)
369      setwidth(self, width)
370      setcolor(self, color)
371      setlinestyle(self, linestyle)
372      setpointstyle(self, pointstyle)
373      setname(self, n)
374      setshown(self, s)
375      getwidth(self)
376      getcolor(self)
377      getlinestyle(self)
378      getpointstyle(self)
379  """
380
381  def __init__(self, prop, type, objvec, shown, name, internal,
382               width, pointstyle, linestyle, color):
383    self.prop=prop
384    self.objvec=objvec
385    self.n_lb=None
386    KigDOP.__init__(self, type)
387    internal=parameter(internal, KigDOP._kd.internal)
388    if internal:
389      self.view = None
390    else:
391# Here we assume that, if we're given a name of an object,
392# we want to visualize the name as well
393      if name: n_id=self.showname(name, shown, width, pointstyle, linestyle,
394                                  color)
395      else:    n_id=None
396      self.view = KigView(self, shown, n_id, width, pointstyle, linestyle,
397                          color)
398
399  def str_hierarchy(self):
400    """Returns a string which can be placed inside <Hierarchy> tags.
401
402    example:
403  <Property which="mid-point" id="170" >
404   <Parent id="..." />
405  </Property>
406
407    example:
408  <Object type="ConstrainedPoint" id="14" >
409   <Parent id="13" />
410   <Parent id="10" />
411  </Object>
412"""
413    retstring = '  <%s="%s" id="%s" >' %\
414                ((self.prop and PROPERTY_INI or OBJECT_INI),
415                 self._type, self.getid())
416    for p in self.objvec:
417      retstring = retstring + '\n   <Parent id="%s" />' % p.getid()
418    retstring = retstring + '\n  </%s>\n' % (self.prop and PROPERTY_END or
419                                                         OBJECT_END)
420    return retstring
421
422  def showname(self, name, shown, width, pointstyle, linestyle, color):
423    n=String(name)
424    self.n_lb=Label(self, (0, 0), n, 0, shown, None, False,
425                    width, pointstyle, linestyle, color)
426    return n.getid()
427
428  def show(self):
429    if self.view:                  self.view.shown=None
430  def hide(self):
431    if self.view:                  self.view.shown=KIGFALSE
432  def setwidth(self, width):       self.view.width=width
433  def setcolor(self, color):       self.view.color=color
434  def setlinestyle(self, linestyle):
435    if linestyle in LS:            self.view.linestyle=linestyle
436  def setpointstyle(self, pointstyle):
437    if pointstyle in PS:           self.view.pointstyle=pointstyle
438  def type(self):                  return Type(self)
439  def setname(self, n):
440    v=self.view
441    v.name=self.showname(n, v.shown, v.width, v.pointstyle, v.linestyle,
442                         v.color)
443  def setshown(self, s):           self.view.shown=s
444
445#####
446# Property class
447#####
448
449class Property(PropObj):
450  """A class from which all Property elements inherit.
451
452    ancestor chain:
453      Property <- PropObj <- KigDOP <- object
454  """
455  def __init__(self, type, parent, shown, name, internal,
456               width, pointstyle, linestyle, color):
457    PropObj.__init__(self, True, type, (parent,), shown, name, internal,
458               width, pointstyle, linestyle, color)
459#    print shown
460
461#####
462# Object class
463#####
464
465class Object(PropObj):
466  """A class from which all Object elements inherit.
467
468    ancestor chain:
469      Object <- PropObj <- KigDOP <- object
470  """
471
472  def __init__(self, type, objvec, shown, name, internal,
473               width, pointstyle, linestyle, color):
474    PropObj.__init__(self, False, type, objvec, shown, name, internal,
475               width, pointstyle, linestyle, color)
476
477#####
478# Data
479#####
480
481data=(\
482("Int",    "int",    "val"),
483("Double", "double", "val"),
484("String", "string", "xml.sax.saxutils.escape(val)"),
485)
486
487def databuild(nomeclasse, nomekig, v="val"):
488  """Create string with a Data class definition."""
489  return """class %s(Data):
490
491  def __init__(self, val):
492    Data.__init__(self, "%s", %s)
493""" % (nomeclasse, nomekig, v)
494
495for d in data:
496  p1, p2, p3 = d
497  exec (databuild(p1, p2, p3))
498
499#####
500# Objects
501#####
502"""To add:
503("ConvexHull", "ConvexHull", "polygon,", "(polygon,),"),
504("EllipseByFocusFocusPoint", "EllipseBFFP", "p1, p2, p3,", "(p1, p2, p3,),"),
505("HyperbolaByFocusFocusPoint", "HyperbolaBFFP", "p1, p2, p3,", "(p1, p2, p3,),"),
506("ConicBy5Points", "ConicB5P", "p1, p2, p3, p4, p5,", "(p1, p2, p3, p4, p5),"),
507("ParabolaBy3Points", "ParabolaBTP", "p1, p2, p3,", "(p1, p2, p3,),"),
508("CocCurve", "CocCurve", "line, point,", "(line, point,),"),
509"""
510objects=(\
511###### Points class
512("Point",           "FixedPoint", "x, y,", "(kig_double(x), kig_double(y)),"),
513("ConstrainedPoint", "ConstrainedPoint",
514                    "t, curve,", "(kig_double(t), curve),"),
515("RelativePoint",   "RelativePoint",
516                    "x, y, p,", "(kig_double(x), kig_double(y), p),"),
517###### Segments, rays, lines
518("Line",            "LineAB", "p1, p2,", "(p1, p2),"),
519("Segment",         "SegmentAB", "p1, p2,", "(p1, p2),"),
520("Ray",             "RayAB", "p1, p2,", "(p1, p2),"),
521("Orthogonal",      "LinePerpend", "line, point,", "(line, point,),"),
522("Parallel",        "LineParallel", "line, point,", "(line, point,),"),
523###### Circles, arcs, ...
524("Circle",          "CircleBCP", "center, point,", "(center, point,),"),
525("CircleByCenterPoint",          "CircleBCP", "center, point,", "(center, point,),"),
526("CircleByCenterRadius", "CircleBPR", "center, radius,", "(center, radius,),"),
527("CircleBy3Points",  "CircleBTP", "p1, p2, p3,", "(p1, p2, p3,),"),
528("ArcBy3Points",    "ArcBTP", "p1, p2, p3,", "(p1, p2, p3,),"),
529("ArcByCenterPointAngle", "ArcBCPA",
530                    "center, point, angle,", "(center, point, angle),"),
531###### Conics...
532("ParabolaByDirectrixFocus", "ParabolaBDP", "line, point,", "(line, point,),"),
533("VerticalCubic", "VerticalCubicB4P", "p1, p2, p3, p4,", "(p1, p2, p3, p4,),"),
534("ConicArc", "ConicArcBTPC", "p1, p2, p3, center,", "(p1, p2, p3, center),"),
535("ConicBy5Points", "ConicB5P", "p1, p2, p3, p4, p5,", "(p1, p2, p3, p4, p5,),"),
536("EllipseByFocusFocusPoint", "EllipseBFFP", "p1, p2, p3,", "(p1, p2, p3,),"),
537("ParabolaBy3Points", "ParabolaBTP", "p1, p2, p3,", "(p1, p2, p3,),"),
538("HyperbolaByFocusFocusPoint", "HyperbolaBFFP", "p1, p2, p3,", "(p1, p2, p3,),"),
539#### Cubics
540("CubicBy9Points", "CubicB9P", "p1, p2, p3, p4, p5, p6, p7, p8, p9,","(p1, p2, p3, p4, p5, p6, p7, p8, p9,)," ),
541#####
542# Intersections.  The only standard object is the intersection
543# of two lines, which always gives one single point.
544#####
545("LineLineIntersection", "LineLineIntersection", "l1, l2,", "(l1, l2),"),
546#####
547# CircleCircleIntersection and ConicLineIntersection classes
548# The "which" argument takes values of 1 or -1, to indicate
549# which of the intersections you want to get.
550#####
551("CircleCircleIntersection", "CircleCircleIntersection",
552                    "c1, c2, which,", "(c1, c2, Int(which),),"),
553("ConicLineIntersection", "ConicLineIntersection",
554                    "conic, line, which,", "(conic, line, Int(which),),"),
555("ConicLineOtherIntersection", "ConicLineOtherIntersection",
556           	    "conic, line, p,", "(conic, line, p),"),
557("LineCubicIntersection", "CubicLineIntersection",
558                    "cubic, line, which,", "(cubic, line, Int(which),),"),
559("CubicLineIntersection", "CubicLineIntersection",
560                    "cubic, line, which,", "(cubic, line, Int(which),),"),
561("CubicLineOtherIntersection", "CubicLineOtherIntersection", "cubic, line, p1, p2,", "(cubic, line, p1, p2),"),
562###### Triangle class
563("Triangle",        "TriangleB3P", "p1, p2, p3,", "(p1, p2, p3),"),
564###### Polygon class   (the only argument is a points vect)
565("Polygon",         "PolygonBNP", "pvec,", "pvec,"),
566###### PolygonBCV class
567# Regular polygon data - center and a vertex. The third argument
568# is an integer signifying the number of sides.
569("PolygonBCV",      "PoligonBCV",
570                    "center, vertex, n,", "(center, vertex, Int(n)),"),
571##### PolygonVertex class    (polygon, integer >= 0)
572("PolygonVertex",   "PolygonVertex",
573                    "polygon, i,", "(polygon, Int(i)),"),
574##### PolygonSide class    (polygon, integer >= 0)
575("PolygonSide",     "PolygonSide",
576                    "polygon, i,", "(polygon, Int(i)),"),
577###### Vector, angle,...
578("Vector",          "Vector", "p1, p2,", "(p1, p2),"),
579("Angle",           "Angle", "p1, v, p2,", "(p1, v, p2),"),
580###### Transformations
581("Translate",       "Translation", "obj, vector,", "(obj, vector),"),
582("CentralSymmetry", "PointReflection", "obj, center,", "(obj, center),"),
583("AxialSymmetry",   "LineReflection", "obj, center,", "(obj, center),"),
584("Rotate",          "Rotation",
585                    "obj, center, angle,", "(obj, center, angle),"),
586("Scale",           "ScalingOverCenter",
587                    "obj, center, segment,", "(obj, center, segment),"),
588("Scale2",          "ScalingOverCenter2",
589                    "obj, center, s1, s2,", "(obj, center, s1, s2),"),
590("Stretch",         "ScalingOverLine",
591                    "obj, line, segment,", "(obj, line, segment),"),
592("Stretch2",        "ScalingOverLine2",
593                    "obj, line, s1, s2,", "(obj, line, s1, s2),"),
594("InvertPoint",     "InvertPoint",
595                    "point, circle,", "(point, circle),"),
596("CircularInversion", "CircularInversion",
597                    "objecttoinvert, circle,", "(objecttoinvert, circle),"),
598("InvertLine",      "InvertLine",
599                    "line, circle,", "(line, circle),"),
600("InvertCircle",    "InvertCircle",
601                    "circletoinvert, circle,", "(circletoinvert, circle),"),
602("InvertArc",       "InvertArc",
603                    "arctoinvert, circle,", "(arctoinvert, circle),"),
604("InvertSegment",   "InvertSegment",
605                    "segment, circle,", "(segment, circle),"),
606###### Text, Label, ...
607("Text",            "Label",
608                    "point, string, boxed=0,",
609                    "(Int(boxed), kig_point(point), kig_string(string)),"),
610("Label",           "Label",
611                    "obj, displ, string, boxed=0,",
612                    "(Int(boxed),kig_relpoint(obj, displ),kig_string(string)),"),
613("VarText",         "Label",
614                    "point, string, vars, boxed=0,",
615                    "(Int(boxed), kig_point(point), \
616                    kig_string(string))+tuple(vars),"),
617("VarLabel",        "Label",
618                    "obj, displ, string, vars, boxed=0,",
619                    "(Int(boxed), kig_relpoint(obj, displ), \
620                    kig_string(string))+tuple(vars),"),
621###### Python scripting... we need some work here...
622("PythonScript",    "PythonExecuteType",
623                    "script, argvec,",
624                    '(Object("PythonCompileType", (kig_string(script),), shown,\
625                             name, internal, width, pointstyle, linestyle,\
626                             color),)+tuple(argvec),'),
627)
628
629def objectbuild(nameclass, namekig, params, objparams):
630  """Create string with a Object class definition."""
631  return """class %s(Object):
632
633  def __init__(self, %s shown=None, name=None, internal=None,
634               width=None, pointstyle=None, linestyle=None, color=None):
635    Object.__init__(self, "%s", %s shown, name, internal,
636                    width, pointstyle, linestyle, color)
637""" % (nameclass, params, namekig, objparams)
638
639for o in objects:
640  p1, p2, p3, p4 = o
641  exec (objectbuild(p1, p2, p3, p4))
642
643#####
644# Properties
645#####
646
647property=(\
648("Type",            "base-object-type", "o,", "o,"),
649("Coordinate",      "coordinate", "point,", "point,"),
650("XCoord",          "coordinate-x", "point,", "point,"),
651("YCoord",          "coordinate-y", "point,", "point,"),
652("MidPoints",       "mid-point", "a, b,", "Segment(a, b, internal=True),"),
653("MidPoint",        "mid-point", "segment,", "segment,"),
654("MidPointAB",      "mid-point", "a, b,", "Segment(a, b, internal=True),"),
655("MidPointSegment", "mid-point", "segment,", "segment,"),
656("EndPointA",       "end-point-A", "segment,", "segment,"),
657("EndPointB",       "end-point-B", "segment,", "segment,"),
658("Length",          "length", "segment,", "segment,"),
659("Equation",        "equation", "segment,", "segment,"),
660("Slope",           "slope", "segment,", "segment,"),
661("NumOfSides",      "polygon-number-of-sides", "poly,", "poly,"),
662("Perimeter",       "polygon-perimeter", "poly,", "poly,"),
663("Surface",         "polygon-surface", "poly,", "poly,"),
664("CenterOfMass",    "polygon-center-of-mass", "poly,", "poly,"),
665("WindingNumber",   "polygon-winding-number", "poly,", "poly,"),
666("Radius",          "radius", "circle,", "circle,"),
667("Center",          "center", "circle,", "circle,"),
668("Bisector",        "angle-bisector", "angle,", "angle,"),
669("Support",         "support", "object,", "object,"),
670)
671
672def propertybuild(nameclass, namekig, params, objparams):
673  """Create string with a Property class definition."""
674  return """class %s(Property):
675
676  def __init__(self, %s shown=None, name=None, internal=False,
677               width=None, pointstyle=None, linestyle=None, color=None):
678    Property.__init__(self, "%s", %s shown, name, internal,
679                    width, pointstyle, linestyle, color)
680""" % (nameclass, params, namekig, objparams)
681
682for p in property:
683  p1, p2, p3, p4 = p
684  exec (propertybuild(p1, p2, p3, p4))
685
686#####
687# Start of properties definitions as Object's methods
688#####
689# to be cleaned up!
690points  =(Point, ConstrainedPoint, RelativePoint, PolygonVertex)
691lines=(Segment, Ray, Vector, InvertLine)
692segments=(Segment, Vector, PolygonSide, InvertSegment)
693circles =(CircleByCenterPoint, CircleBy3Points, CircularInversion, ArcBy3Points,
694          ArcByCenterPointAngle, InvertCircle)
695polygons=(Polygon, PolygonBCV, Triangle)
696angles  =(Angle,)
697supp    = circles+lines
698
699methods=(\
700("coordinate", "coordinate", points),
701("coordinate-x", "xcoord", points),
702("coordinate-y", "ycoord", points),
703("mid-point", "midpoint", segments),
704("end-point-A", "endpointA", segments),
705("end-point-B", "endpointB", segments),
706("length", "length", segments),
707("equation", "equation", lines),
708("slope", "slope", lines),
709("polygon-number-of-sides", "numofsides", polygons),
710("polygon-perimeter", "perimeter", polygons),
711("polygon-surface", "surface", polygons),
712("polygon-center-of-mass", "centerofmass", polygons),
713("polygon-winding-number", "windingnumber", polygons),
714("center", "center", polygons),
715("center", "center", circles),
716("angle-bisector", "bisector", angles),
717("support", "support",  supp),
718)
719
720def methodsbuild(namekig):
721  """Create string with a method class definition."""
722  return """def method(self,shown=None, name=None, internal=False,
723               width=None, pointstyle=None, linestyle=None, color=None):
724    return Property("%s", self, shown, name, internal,
725                    width, pointstyle, linestyle, color)
726""" % (namekig, )
727
728for p in methods:
729  p1, p2, cl = p
730  exec (methodsbuild(p1))
731  for c in cl:
732    setattr(c, p2, method)
733
734#####
735# Usage
736#####
737
738def usage(codexit):
739  print ("""
740usage: pykig.py [options...] file ...
741
742Options:
743    -h, --help          Show this text.
744    -o <kig_file>
745    --output <kig_file> Output to <kig_file> and don't call Kig.
746    -v, --version       Output version and exit.
747    -n, --nokig         Don't call Kig.
748
749examples:
750    $ pykig.py my_file.kpy
751    $ pykig.py -o output_file.kig my_file.kpy
752    $ ...
753""", file=sys.stderr)
754  sys.exit(codexit)
755
756#####
757# Main body
758#####
759
760import sys, traceback, os
761#from math import *    # for user's programs
762import math            # for user's programs
763import getopt
764import atexit
765import xml.sax.saxutils
766
767def prog():
768  try:
769    _opts, _args = getopt.getopt(sys.argv[1:], "hvno:",\
770                                 ["help", "version", "nokig", "output="])
771  except getopt.GetoptError:
772    print ("GetoptError")
773    usage(2)
774  _callKig=True
775  _of=False
776  for _opt, _arg in _opts:
777    if _opt in ("-h", "--help"):
778      usage(0)
779    if _opt in ("-v", "--version"):
780      print ("Version:", version)
781      sys.exit(0)
782    if _opt in ("-n", "--nokig"):
783      _callKig=False
784    elif _opt in ("-o", "--output"):
785      _outfilename=_arg
786      _of=True
787      _callKig=False   # if there's an output file, don't call Kig
788  if len(_args)==0:
789    _infilename=input("Input file name: ")
790    if not _infilename:
791      print ("No input file name.")
792      usage(2)
793  elif len(_args)==1:
794    _infilename=_args[0]
795  else:
796    print ("No input file name.")
797    usage(2)
798  try:
799    _infile = open(_infilename, 'r')
800  except:
801    print (_infilename, "input file can't be read.", file=sys.stderr)
802    sys.exit(2)
803  if _of:
804    if _outfilename=="-":
805      _n, _e = os.path.splitext(_infilename)
806      _outfilename=_n+'.kig'
807  else:
808    _outfilename="/tmp/pykig" + str(os.getpid()) + ".kig"
809  global kigdocument
810  kigdocument=KigDocument(_outfilename, _callKig, _of)
811  kd=kigdocument
812  try:
813    exec(open(_infilename).read(), globals())
814  except:
815    print ('Syntax error in', _infilename, file=sys.stderr)
816    _info = sys.exc_info()    # print out the traceback
817    traceback.print_exc()
818    sys.exit(3)
819  kigdocument.close()
820
821  if _infile != sys.stdin:
822    _infile.close()
823
824def lib():
825  _outfilename="/tmp/pykig" + str(os.getpid()) + ".kig"
826  global kigdocument
827  kigdocument=KigDocument(_outfilename)
828  kd=kigdocument
829  atexit.register(kigdocument.close)
830
831if __name__ == "__main__":
832  prog()
833else:
834  lib()
835