0001###########################################################################
0002# PyGeo - a dynamic geometry toolkit
0003# Copyright (C) 2005 Arthur Siegel (ajsiegel@optonline.com)
0004#
0005# This library is free software; you can redistribute it and/or
0006# modify it under the terms of the GNU Lesser General Public
0007# License as published by the Free Software Foundation; either
0008# version 2.1 of the License, or (at your option) any later version.
0009#
0010# This library is distributed in the hope that it will be useful,
0011# but WITHOUT ANY WARRANTY; without even the implied warranty of
0012# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013# Lesser General Public License for more details.
0014#
0015# You should have received a copy of the GNU Lesser General Public
0016# License along with this library; if not, write to the Free Software
0017# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
0018#
0019#PyGeo homepage: http://pygeo.sourceforge.net
0020###########################################################################
0021
0022"""drawing and graphics related routines to use as mixin classes with objects of the
0023complex plane"""
0024
0025
0026from pygeo.base.support.pygeoconstants import DIAMOND, FILL, LINES
0027from pygeo.base.analytics.pygeomath import *
0028from pygeoprimitives import *
0029from pygeo.base.analytics._position3 import Position3
0030from pygeo.base.support.pygeoopts import EPS, COMPLEX_MAX, TEST_MAX
0031
0032def constrain_draw(pos):
0033    """for constraining the drawing position of points where largs values 
0034    relative to the scene scale can cause display prblems.  The option to 
0035    turn off drawing constraints and the 'MAX' constant is by editing the
0036    pygeoopts.py file"""
0037
0038    if TEST_MAX:
0039        try:
0040            m=max(absolute(pos))
0041            if m > COMPLEX_MAX:
0042                return (pos/m)*COMPLEX_MAX
0043            else:
0044                return pos
0045        except OverflowError:
0046             return (COMPLEX_MAX,COMPLEX_MAX,COMPLEX_MAX)
0047    else:
0048        return pos
0049
0050class zdrawPoint:
0051    """drawing back-end for objects derived from the _zPoint class"""
0052
0053    def _redraw(self):
0054        """send current position in scene to render object, and render
0055        in accordance with style sttribute"""
0056
0057        if self.init_draw:
0058            if self.style==DIAMOND:
0059                #for r in self.rend:
0060                self.f.pos=constrain_draw(self.pos)
0061            else:
0062                self.rend[0].pos =constrain_draw(self.pos)
0063            if self.label:
0064                self.lab.pos= constrain_draw(self.pos)
0065
0066    def do_trace(self):
0067        """
0068        If on update, traced point has moved within limits defined by
0069        'mintrace' and 'maxtrace' append its new position to the trace
0070        curve
0071        """
0072
0073        delta= self.distance(self.tmparray)
0074        if (self.mintrace < delta < self.maxtrace):
0075            from pygeo.base.geometry_complex.z_points import zFixedPoint
0076            self.rtrace.append(zFixedPoint(self.real,self.imag,pointsize=self.pointsize,color=self.tracecolor,
0077                   level=self.level))
0078            if self.tracecurve:
0079                self.ntrace.append(pos=constrain_draw(self.pos))
0080        self.tmparray.set(self)
0081
0082    def reset_trace(self):
0083        """Re-intialize list of loci points to None"""
0084
0085        if self.trace:
0086            for r in self.rtrace:
0087               r.show=False
0088               r.setshow()
0089            self.rtrace=[]
0090            self.tmparrayset(self)
0091
0092    def reset_trace_curves(self):
0093        """Re-intialize list of traced curves to None"""
0094
0095        if self.trace:
0096            self.ntrace.pos=[]
0097
0098    def draw(self):
0099        """For consistency in iterating Element's rendering objects, all elements
0100        rendering information is in a list called self.rend. In the case of Points,
0101        it is either a single element list, containing a cvisual sphere object, or a 
0102        2 element list with each element an oriented cvisual pyramid object, which together
0103        form a diamond shape representing the point"""
0104
0105        if self.style==DIAMOND:
0106            self.f=frame()
0107            self.f.rotate(angle=PI/4.,axis=(1,0,0),pos=(0,0,0))
0108            ps=self.pointsize
0109            self.rend.append(pyramid(frame=self.f,size=(ps,sqrt(2)*ps,sqrt(2)*ps)))
0110            self.rend.append(pyramid(frame=self.f,size=(-ps,sqrt(2)*ps,sqrt(2)*ps)))
0111            for r in self.rend:
0112                r.color=r.initcolor=self.color
0113        else:
0114            self.rend.append(sphere(radius=self.pointsize))
0115            self.rend[0].color=self.rend[0].initcolor=self.color
0116        if self.label:
0117            self.lab=label(box=False, opacity=0.,
0118                         color=self.fontcolor,text=self.label,
0119                         xoffset=self.fontXoffset,yoffset= self.fontYoffset,
0120                         space=.5, height=self.fontsize, border=2)
0121        if self.trace:
0122            if self.tracecurve:
0123                self.ntrace = curve(radius=self.tracewidth,
0124                                    color=self.tracecolor)
0125        self.init_draw=True
0126
0127    def povout(self,buf):
0128        """ export the scene's points to PovRay SDL"""
0129
0130        color=self.color
0131        size=self.pointsize
0132        print >>buf,"//POINT"
0133        if hasattr(self,'complex'):
0134            x=self.real
0135            y=self.imag
0136            z=0
0137        else:
0138            x=self.x
0139            y=self.y
0140            z=self.z
0141        if not self.style==DIAMOND:
0142            print >>buf,"""
0143sphere {
0144    <%f, %f, %f> , %f
0145    pigment {
0146        color rgb <%f, %f, %f> filter 0 transmit  0.0 }}
0147    """     %(x,y,z,
0148                size,color[0],color[1],color[2])
0149            if self.trace:
0150                print >>buf,"//POINT TRACE"
0151                for trace in self.rtrace:
0152                    trace.povout(buf)
0153                i=0
0154                while i < len(self.ntrace.pos)-1:
0155                    p1=self.ntrace.pos[i]
0156                    p2=self.ntrace.pos[i+1]
0157                    print >> buf, """
0158cylinder{
0159    <%f, %f, %f> , <%f, %f, %f>, %f
0160    pigment {color rgb <%f, %f, %f> filter 0 transmit  0.0}}
0161    """     %(p1[0],p1[1],p1[2],
0162                p2[0],p2[1],p2[2],
0163                self.tracewidth,self.tracecolor[0],
0164                self.tracecolor[1],self.tracecolor[2])
0165                    print >>buf,"""
0166sphere {
0167    <%f, %f, %f> , %f
0168    pigment {color rgb <%f, %f, %f> filter 0 transmit  0.0 }}
0169    """     %(p1[0],p1[1],p1[2],
0170                self.tracewidth,self.tracecolor[0],
0171                self.tracecolor[1],self.tracecolor[2])
0172                    i+=1
0173        else:
0174            print >>buf,"""
0175union{
0176    prism {
0177        conic_sweep
0178        linear_spline
0179        0, // height 1
0180        1, // height 2
0181        5, // the number of points making up the shape...
0182        <1,0>,<0,1>,<-1,0>,<0,-1>,<1,0>
0183        translate <0, -1, 0>
0184        pigment { color rgb <%f, %f, %f> filter 0 transmit  0.0}
0185     } 
0186
0187    prism {
0188        conic_sweep
0189        linear_spline
0190        0, // height 1
0191        1, // height 2
0192        5, // the number of points making up the shape...
0193        <1,0>,<0,1>,<-1,0>,<0,-1>,<1,0>
0194        rotate <180, 0, 0>
0195        translate <0, 1, 0>
0196        pigment { color rgb <%f, %f, %f> filter 0 transmit  0.0 }
0197
0198     }   
0199    scale <%f,%f,%f>
0200    translate <%f, %f, %f>
0201
0202}
0203    """    %(color[0],color[1],color[2],color[0],color[1],color[2],
0204               size,size,size,x,y,z)
0205
0206class zdrawLine:
0207    """drawing back-end for objects derived from the _zLine class"""
0208
0209    def _redraw(self):
0210        """send current position of line frame's axis and position based on the line's current
0211        defining Hermitian matrix"""
0212
0213        h=self._hermitian
0214        b = h.C*1j
0215        c= -h.D/(2*h.B)
0216        self.f.axis=vector(b.real,b.imag,0)
0217        self.f.pos=vector(c.real,c.imag,0)
0218        self.rend[0].pos=self.m
0219        if self.label:
0220            self.setlabel()
0221
0222    def setlabel(self):
0223        """set position of line's lab, if any"""
0224
0225        labelpos=add(multiply(1-self.lratio,self.p1),
0226                     multiply(self.lratio,self.p2))
0227        self.lab.pos=labelpos
0228
0229    def draw(self):
0230        """for consistency in iterating Element's rendering objects, all elements
0231        rendering information is in a list called self.rend. In the case of zLines,
0232        it is a single element list containing a cvisual curve object"""
0233
0234        self.f=frame()
0235        self.m = array([[COMPLEX_MAX,0.,0.],[-COMPLEX_MAX,0,0]])
0236        self.rend=[curve(frame=self.f,color=self.color,
0237                        radius=self.linewidth)]
0238        if self.label:
0239            self.lab=label(frame=self.f,box=False, opacity=0.,
0240                           color=self.fontcolor,text=self.label,
0241                           xoffset=self.fontXoffset,yoffset= self.fontYoffset,
0242                           space=.5, height=self.fontsize, border=2)
0243
0244        self.init_draw=True
0245
0246    def povout(self,buf):
0247        """ export the scene's lines to PovRay SDL"""
0248
0249        print >> buf, "//LINE"
0250        p1=self.rend[0].pos[0]
0251        p2=self.rend[0].pos[1]
0252        pos=self.f.pos
0253        theta,phi=Position3(self.f.axis).polar()
0254        d_convert=180/PI
0255        theta*=d_convert
0256        phi*=d_convert
0257        rotate = "rotate<%f,%f,%f>" %(0.,90.+theta,phi)
0258        translate="translate<%f,%f,%f>" %(pos.x,pos.y,0.)
0259        if max(absolute(p1-p2)) > EPS:
0260            print >> buf, """
0261cylinder{
0262<%f, %f, %f> , <%f, %f, %f>, %f
0263%s
0264%s
0265pigment {color rgb <%f, %f, %f> filter 0 transmit  0.0
0266
0267}"""     %(p1[0],p1[1],p1[2],
0268                 p2[0],p2[1],p2[2],self.linewidth,
0269                 rotate,
0270                 translate,
0271                 self.color[0],self.color[1],self.color[2])
0272
0273class zdrawCircle:
0274    """drawing back-end for objects derived from the _zCircle class"""
0275
0276    def _redraw(self):
0277        """send current position of circle's center position and radius based of the circle's
0278        defining Hermitian matrix"""
0279
0280        try:
0281            h= self._hermitian
0282        except AttributeError:
0283            return
0284        if absolute(h.A) > .001:
0285            if self._radius > COMPLEX_MAX:
0286                radius= COMPLEX_MAX
0287            else:
0288                radius=self._radius
0289            self.f.pos=constrain_draw(self._center.pos)
0290            self.rend[0].pos=constrain_draw((self.c*radius))
0291
0292        else:
0293            b = h.C*1j
0294            try:
0295                c= -h.D/(2*h.B)
0296            except ZeroDivisionError:
0297                c=COMPLEX_MAX
0298            self.f.axis=vector(b.real,b.imag,0)
0299            self.f.pos=vector(c.real,c.imag,0)
0300            self.rend[0].pos=self.m
0301
0302    def draw(self):
0303        """the circle object is represented either by a convex polygon or as curve - 
0304        we take advantage of the cvisual frame object, assigning the drawing primitives to one
0305        frame, so that further manipulation is of the frame, not the primtives themselves"""
0306
0307        self.f = frame()
0308        div=2*PI/self.precision
0309        t = arrayrange(div,2*PI+2*div,div)
0310        self.m = array([[COMPLEX_MAX,0.,0.],[-COMPLEX_MAX,0,0]])
0311        self.c = transpose( (sin(t), cos(t),0*t) )
0312        if self.style==FILL:
0313            self.rend=[convex(frame=self.f,color=self.color)]
0314        else:
0315            self.rend=[curve(frame=self.f,color=self.color,
0316                            radius=self.linewidth)]
0317        if self.show_normal:
0318            self.nrend=arrow(pos=(0,0,0),shaftwidth=self.normal_width,
0319                             color=self.color)
0320        self.init_draw=True
0321
0322    def povout(self,buf):
0323        """ export the scene's circles to PovRay SDL"""
0324
0325        print >> buf, "//CIRCLE"
0326        center=self._center
0327        if hasattr(self._radius,'real'):
0328            radius=self._radius.real
0329        else:
0330            radius = self._radius
0331        color=self.color
0332        translate="translate<%f,%f,%f>" %(center.x,center.y,0.)
0333        if self._hermitian.A <> 0:
0334            if self.style==LINES:
0335                print >> buf,"""
0336torus {
0337    %f, %f
0338    rotate <90,0,00>
0339    %s
0340    pigment {color rgb <%f, %f, %f> filter 0 transmit  0.0
0341}
0342}"""   %(radius,self.linewidth,translate,
0343            color[0],color[1],color[2])
0344            else:
0345                poly=""
0346                for pos in self.rend[0].pos:
0347                    poly = poly +   "<%f,%f,%f>" %(pos[0],pos[1],pos[2])
0348                print >> buf,"""
0349polygon{
0350   %i,
0351   %s
0352   %s
0353   pigment {color rgb <%f, %f, %f> filter 0 transmit  0.0
0354 }
0355}"""     %(len(self.rend[0].pos),poly,translate,
0356               self.color[0],self.color[1],self.color[2])
0357        else:
0358            print >> buf, "//LINE"
0359            p1=self.rend[0].pos[0]
0360            p2=self.rend[0].pos[1]
0361            pos=self.f.pos
0362            theta,phi=Position3(self.f.axis).polar()
0363            d_convert=180/PI
0364            theta*=d_convert
0365            phi*=d_convert
0366            rotate = "rotate<%f,%f,%f>" %(0.,90.+theta,phi)
0367            translate="translate<%f,%f,%f>" %(pos.x,pos.y,0.)
0368            if max(absolute(p1-p2)) > EPS:
0369                print >> buf, """
0370cylinder{
0371<%f, %f, %f> , <%f, %f, %f>, %f
0372%s
0373%s
0374pigment {color rgb <%f, %f, %f> filter 0 transmit  0.0
0375
0376}"""     %(p1[0],p1[1],p1[2],
0377                 p2[0],p2[1],p2[2],self.linewidth,
0378                 rotate,
0379                 translate,
0380                 self.color[0],self.color[1],self.color[2])
0381
0382class zdrawArray:
0383    """generalized drawing back-end for array objects, i.e. _zLineArray, _zCirclePencil ,etc. """
0384
0385    def _redraw(self):
0386        """iterate through the objects of the array and call the objects _redraw routine to redraw
0387        at its current position"""
0388
0389        for object in self:
0390            object._redraw()
0391
0392    def draw(self):
0393        """the objects of the array get initialized on creation by the array's init() method - this is only
0394        to mark the array itself as initialized """
0395
0396        self.init_draw=True
0397
0398    def povout(self,buf):
0399        """ export the objects of the scene's arrays to PovRay SDL"""
0400        if hasattr(self,'zpoints'):
0401            objects=self.zpoints
0402        if hasattr(self,'zcircles'):
0403            objects=self.zcircles
0404        if hasattr(self,'zlines'):
0405            objects=self.zlines
0406
0407        print >> buf,"//BEGIN ARRAY//"
0408        for object in self:
0409            object.povout(buf)
0410
0411# module attributes
0412__author__ = "Arthur Siegel <ajsiegel@optonline.com>"
0413__date__ = "Date: 2006-02-02 "
0414__revision__ = "Revision: a1"
0415__url__ = "URL: http://source.net/projects/pygeo"
0416__copyright__ ="GPL <http://www.opensource.org/licenses/gpl-license.php>"