xrvg 0.0.6 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES +12 -1
 - data/Rakefile +30 -8
 - data/lib/samplation.rb +10 -2
 - data/lib/trace.rb +1 -0
 - data/lib/utils.rb +24 -1
 - data/test/test_color.rb +19 -13
 - data/test/test_utils.rb +10 -0
 - metadata +2 -17
 - data/lib/bezier.rb +0 -536
 - data/lib/bezierbuilders.rb +0 -210
 - data/lib/beziermotifs.rb +0 -121
 - data/lib/bezierspline.rb +0 -235
 - data/lib/beziertools.rb +0 -245
 - data/lib/color.rb +0 -401
 - data/lib/fitting.rb +0 -203
 - data/lib/frame.rb +0 -33
 - data/lib/geovariety.rb +0 -128
 - data/lib/interbezier.rb +0 -87
 - data/lib/render.rb +0 -266
 - data/lib/shape.rb +0 -421
 - data/lib/spiral.rb +0 -72
 - data/lib/style.rb +0 -76
 - data/lib/xrvg.rb +0 -46
 
    
        data/lib/fitting.rb
    DELETED
    
    | 
         @@ -1,203 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            #
         
     | 
| 
       2 
     | 
    
         
            -
            # Fitting file. See +Fitting+
         
     | 
| 
       3 
     | 
    
         
            -
            #
         
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
            require 'matrix'; # for matrix inversion
         
     | 
| 
       6 
     | 
    
         
            -
            require 'bezier.rb'; # for error computation
         
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
            module XRVG
         
     | 
| 
       9 
     | 
    
         
            -
            #
         
     | 
| 
       10 
     | 
    
         
            -
            # = Fitting computation class
         
     | 
| 
       11 
     | 
    
         
            -
            # == Intro
         
     | 
| 
       12 
     | 
    
         
            -
            # Used to compute cubic curve fitting on a list of points (that is sampling inverse operation). Only 2D.
         
     | 
| 
       13 
     | 
    
         
            -
            # == Example
         
     | 
| 
       14 
     | 
    
         
            -
            # Compute the most fitting single piece bezier curve given list of points
         
     | 
| 
       15 
     | 
    
         
            -
            #  bezier    = Fitting.compute( points )
         
     | 
| 
       16 
     | 
    
         
            -
            # Compute multipieces bezier curve given list of points
         
     | 
| 
       17 
     | 
    
         
            -
            #  bezier    = Fitting.adaptative_compute( points )
         
     | 
| 
       18 
     | 
    
         
            -
            class Fitting
         
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
              # compute first parameter t estimated values from length between consecutive points
         
     | 
| 
       21 
     | 
    
         
            -
              def Fitting.initparameters( pointlist, parameters=nil ) #:nodoc:
         
     | 
| 
       22 
     | 
    
         
            -
                lengths = [0.0]
         
     | 
| 
       23 
     | 
    
         
            -
                pointlist.pairs do |p1, p2|
         
     | 
| 
       24 
     | 
    
         
            -
                  lengths.push( lengths[-1] + (p1-p2).r )
         
     | 
| 
       25 
     | 
    
         
            -
                end
         
     | 
| 
       26 
     | 
    
         
            -
                tlength = lengths[-1]
         
     | 
| 
       27 
     | 
    
         
            -
                if not parameters
         
     | 
| 
       28 
     | 
    
         
            -
                  if not tlength == 0.0
         
     | 
| 
       29 
     | 
    
         
            -
            	parameters = lengths.map {|length| length / tlength}
         
     | 
| 
       30 
     | 
    
         
            -
                  else
         
     | 
| 
       31 
     | 
    
         
            -
            	parameters = [0.0] * pointlist.length
         
     | 
| 
       32 
     | 
    
         
            -
                  end
         
     | 
| 
       33 
     | 
    
         
            -
                end
         
     | 
| 
       34 
     | 
    
         
            -
                return [parameters, tlength]
         
     | 
| 
       35 
     | 
    
         
            -
              end
         
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
              # compute control points from polynomial bezier representation
         
     | 
| 
       38 
     | 
    
         
            -
              #
         
     | 
| 
       39 
     | 
    
         
            -
              # a, b, c, d are such as 
         
     | 
| 
       40 
     | 
    
         
            -
              #  piece( t ) = at3 + bt2 + ct + d
         
     | 
| 
       41 
     | 
    
         
            -
              def Fitting.bezierpiece( a, b, c, d )
         
     | 
| 
       42 
     | 
    
         
            -
                p0 = d
         
     | 
| 
       43 
     | 
    
         
            -
                p1 = p0 + c / 3.0
         
     | 
| 
       44 
     | 
    
         
            -
                p2 = p1 + c / 3.0 + b / 3.0
         
     | 
| 
       45 
     | 
    
         
            -
                p3 = p0 + c + b + a
         
     | 
| 
       46 
     | 
    
         
            -
                return [p0, p1, p2, p3]
         
     | 
| 
       47 
     | 
    
         
            -
              end
         
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
       49 
     | 
    
         
            -
             
     | 
| 
       50 
     | 
    
         
            -
              # Base method
         
     | 
| 
       51 
     | 
    
         
            -
              # 
         
     | 
| 
       52 
     | 
    
         
            -
              # Given a pointlist, compute the closest matching cubic bezier curve
         
     | 
| 
       53 
     | 
    
         
            -
              #
         
     | 
| 
       54 
     | 
    
         
            -
              # Result is in the form [p1, pc1, pc2, p2], with [p1, pc1, pc2, p2] V2D
         
     | 
| 
       55 
     | 
    
         
            -
              #
         
     | 
| 
       56 
     | 
    
         
            -
              # maxerror is normalized with curve length. In case of good match (that is pointlist can be modelized by cubic bezier curve), 
         
     | 
| 
       57 
     | 
    
         
            -
              # result error will be under maxerror. If not, result may be above maxerror. In that case, computation is stopped because error
         
     | 
| 
       58 
     | 
    
         
            -
              # no longer decrease, or because iteration is too long.
         
     | 
| 
       59 
     | 
    
         
            -
              def Fitting.compute( pointlist, maxerror=0.01, maxiter=100 )
         
     | 
| 
       60 
     | 
    
         
            -
                parameters, tlength = Fitting.initparameters( pointlist )
         
     | 
| 
       61 
     | 
    
         
            -
                perror = 1.0
         
     | 
| 
       62 
     | 
    
         
            -
                niter = 0
         
     | 
| 
       63 
     | 
    
         
            -
                while true
         
     | 
| 
       64 
     | 
    
         
            -
                  bezier, coeffs = Fitting.iterate( pointlist, parameters )
         
     | 
| 
       65 
     | 
    
         
            -
                  error = Fitting.error( bezier, pointlist, parameters ) / tlength
         
     | 
| 
       66 
     | 
    
         
            -
                  parameters = Fitting.renormalize( bezier, coeffs, pointlist, parameters )
         
     | 
| 
       67 
     | 
    
         
            -
                  if (error < maxerror || (error-perror).abs < 0.00001 || niter > maxiter )
         
     | 
| 
       68 
     | 
    
         
            -
            	break
         
     | 
| 
       69 
     | 
    
         
            -
                  end
         
     | 
| 
       70 
     | 
    
         
            -
                  niter += 1
         
     | 
| 
       71 
     | 
    
         
            -
                end
         
     | 
| 
       72 
     | 
    
         
            -
                return bezier
         
     | 
| 
       73 
     | 
    
         
            -
              end
         
     | 
| 
       74 
     | 
    
         
            -
             
     | 
| 
       75 
     | 
    
         
            -
              # adaptative computation with automatic splitting if error not low enough, or if convergence is not fast enough
         
     | 
| 
       76 
     | 
    
         
            -
              #
         
     | 
| 
       77 
     | 
    
         
            -
              #
         
     | 
| 
       78 
     | 
    
         
            -
              def Fitting.adaptative_compute( pointlist, maxerror=0.0001, maxiter=10, tlength=nil )
         
     | 
| 
       79 
     | 
    
         
            -
                parameters, tlengthtmp = Fitting.initparameters( pointlist )
         
     | 
| 
       80 
     | 
    
         
            -
                if parameters == [0] * pointlist.length
         
     | 
| 
       81 
     | 
    
         
            -
                  return [Bezier.single(:vector, pointlist[0], V2D::O, pointlist[0], V2D::O),0.0]
         
     | 
| 
       82 
     | 
    
         
            -
                end
         
     | 
| 
       83 
     | 
    
         
            -
                tlength ||= tlengthtmp
         
     | 
| 
       84 
     | 
    
         
            -
                niter = 0
         
     | 
| 
       85 
     | 
    
         
            -
                bezier = nil
         
     | 
| 
       86 
     | 
    
         
            -
                while true
         
     | 
| 
       87 
     | 
    
         
            -
                  bezier, coeffs = Fitting.iterate( pointlist, parameters )
         
     | 
| 
       88 
     | 
    
         
            -
                  error = Fitting.error( bezier, pointlist, parameters ) / tlength
         
     | 
| 
       89 
     | 
    
         
            -
                  parameters = Fitting.renormalize( bezier, coeffs, pointlist, parameters )
         
     | 
| 
       90 
     | 
    
         
            -
             
     | 
| 
       91 
     | 
    
         
            -
                  # pointlist.length > 8 because matching with a bezier needs at least 4 points
         
     | 
| 
       92 
     | 
    
         
            -
                  if (niter > maxiter and error > maxerror and pointlist.length > 8)
         
     | 
| 
       93 
     | 
    
         
            -
            	pointlists = [pointlist[0..pointlist.length/2 - 1], pointlist[pointlist.length/2 - 1 ..-1]]
         
     | 
| 
       94 
     | 
    
         
            -
            	beziers = []
         
     | 
| 
       95 
     | 
    
         
            -
            	errors  = []
         
     | 
| 
       96 
     | 
    
         
            -
            	pointlists.each do |subpointlist|
         
     | 
| 
       97 
     | 
    
         
            -
            	  subbezier, suberror = Fitting.adaptative_compute( subpointlist, maxerror, maxiter, tlength )
         
     | 
| 
       98 
     | 
    
         
            -
            	  beziers << subbezier
         
     | 
| 
       99 
     | 
    
         
            -
            	  errors  << suberror
         
     | 
| 
       100 
     | 
    
         
            -
            	end
         
     | 
| 
       101 
     | 
    
         
            -
            	bezier = beziers.sum
         
     | 
| 
       102 
     | 
    
         
            -
            	error  = errors.max
         
     | 
| 
       103 
     | 
    
         
            -
            	break
         
     | 
| 
       104 
     | 
    
         
            -
                  elsif (error < maxerror || niter > maxiter)
         
     | 
| 
       105 
     | 
    
         
            -
            	break
         
     | 
| 
       106 
     | 
    
         
            -
                  end
         
     | 
| 
       107 
     | 
    
         
            -
                  perror = error
         
     | 
| 
       108 
     | 
    
         
            -
                  niter += 1
         
     | 
| 
       109 
     | 
    
         
            -
                end
         
     | 
| 
       110 
     | 
    
         
            -
                return [bezier, error]
         
     | 
| 
       111 
     | 
    
         
            -
              end
         
     | 
| 
       112 
     | 
    
         
            -
             
     | 
| 
       113 
     | 
    
         
            -
              # algo comes from http://www.tinaja.com/glib/bezdist.pdf
         
     | 
| 
       114 
     | 
    
         
            -
              def Fitting.renormalize( bezier, coeffs, pointlist, parameters )
         
     | 
| 
       115 
     | 
    
         
            -
                a3, a2, a1, a0 = coeffs
         
     | 
| 
       116 
     | 
    
         
            -
                dxdu = Proc.new {|u| 3.0*a3.x*u**2 + 2.0*a2.x*u + a1.x}
         
     | 
| 
       117 
     | 
    
         
            -
                dydu = Proc.new {|u| 3.0*a3.y*u**2 + 2.0*a2.y*u + a1.y}
         
     | 
| 
       118 
     | 
    
         
            -
                container = V2D[]
         
     | 
| 
       119 
     | 
    
         
            -
                z    = Proc.new {|u,p4| p = bezier.point( u, container, :parameter ); (p.x - p4.x) * dxdu.call( u ) + (p.y - p4.y) * dydu.call( u )}
         
     | 
| 
       120 
     | 
    
         
            -
                newparameters = []
         
     | 
| 
       121 
     | 
    
         
            -
                [pointlist, parameters].forzip do |point, parameter|
         
     | 
| 
       122 
     | 
    
         
            -
                  u1 = parameter
         
     | 
| 
       123 
     | 
    
         
            -
                  if parameter < 0.99
         
     | 
| 
       124 
     | 
    
         
            -
            	u2 = parameter + 0.01
         
     | 
| 
       125 
     | 
    
         
            -
                  else
         
     | 
| 
       126 
     | 
    
         
            -
            	u2 = parameter - 0.01
         
     | 
| 
       127 
     | 
    
         
            -
                  end
         
     | 
| 
       128 
     | 
    
         
            -
                  z1 = z.call(u1,point)
         
     | 
| 
       129 
     | 
    
         
            -
                  z2 = z.call(u2,point)
         
     | 
| 
       130 
     | 
    
         
            -
                  if z1 == z2
         
     | 
| 
       131 
     | 
    
         
            -
            	u2 += 0.01
         
     | 
| 
       132 
     | 
    
         
            -
            	z2 = z.call(u2,point)
         
     | 
| 
       133 
     | 
    
         
            -
                  end
         
     | 
| 
       134 
     | 
    
         
            -
                  if z1 == z2
         
     | 
| 
       135 
     | 
    
         
            -
            	u2 -= 0.01
         
     | 
| 
       136 
     | 
    
         
            -
            	z2 = z.call(u2,point)
         
     | 
| 
       137 
     | 
    
         
            -
                  end
         
     | 
| 
       138 
     | 
    
         
            -
                  newparameters << (z2 * u1 - z1 * u2)/(z2-z1)
         
     | 
| 
       139 
     | 
    
         
            -
                end
         
     | 
| 
       140 
     | 
    
         
            -
                return newparameters
         
     | 
| 
       141 
     | 
    
         
            -
              end
         
     | 
| 
       142 
     | 
    
         
            -
              
         
     | 
| 
       143 
     | 
    
         
            -
              # error is max error  between points in pointlist and points sampled from bezier with parameters
         
     | 
| 
       144 
     | 
    
         
            -
              def Fitting.error( bezier, pointlist, parameters )
         
     | 
| 
       145 
     | 
    
         
            -
                maxerror = 0.0
         
     | 
| 
       146 
     | 
    
         
            -
                container = V2D[]
         
     | 
| 
       147 
     | 
    
         
            -
                [pointlist, parameters].forzip do |point, parameter|
         
     | 
| 
       148 
     | 
    
         
            -
                  # Trace("point #{point.inspect} parameter #{parameter}")
         
     | 
| 
       149 
     | 
    
         
            -
                  error = (point - bezier.point( parameter, container, :parameter )).r
         
     | 
| 
       150 
     | 
    
         
            -
                  if error > maxerror
         
     | 
| 
       151 
     | 
    
         
            -
            	maxerror = error
         
     | 
| 
       152 
     | 
    
         
            -
                  end
         
     | 
| 
       153 
     | 
    
         
            -
                end
         
     | 
| 
       154 
     | 
    
         
            -
                # Trace("Fitting.error #{maxerror}")
         
     | 
| 
       155 
     | 
    
         
            -
                return maxerror
         
     | 
| 
       156 
     | 
    
         
            -
              end
         
     | 
| 
       157 
     | 
    
         
            -
             
     | 
| 
       158 
     | 
    
         
            -
              # iterate method compute new bezier parameters from pointlist and previous bezier parameters
         
     | 
| 
       159 
     | 
    
         
            -
              # 
         
     | 
| 
       160 
     | 
    
         
            -
              # Algo comes from http://www.tinaja.com/glib/bezdist.pdf
         
     | 
| 
       161 
     | 
    
         
            -
              #
         
     | 
| 
       162 
     | 
    
         
            -
              # TODO : optimized
         
     | 
| 
       163 
     | 
    
         
            -
              def Fitting.iterate( pointlist, parameters )
         
     | 
| 
       164 
     | 
    
         
            -
                p0 = pointlist[0]
         
     | 
| 
       165 
     | 
    
         
            -
                p1 = pointlist[-1]
         
     | 
| 
       166 
     | 
    
         
            -
             
     | 
| 
       167 
     | 
    
         
            -
                sumt0 = parameters.map{ |t| t**0.0 }.sum
         
     | 
| 
       168 
     | 
    
         
            -
                sumt1 = parameters.map{ |t| t**1.0 }.sum
         
     | 
| 
       169 
     | 
    
         
            -
                sumt2 = parameters.map{ |t| t**2.0 }.sum
         
     | 
| 
       170 
     | 
    
         
            -
                sumt3 = parameters.map{ |t| t**3.0 }.sum
         
     | 
| 
       171 
     | 
    
         
            -
                sumt4 = parameters.map{ |t| t**4.0 }.sum
         
     | 
| 
       172 
     | 
    
         
            -
                sumt5 = parameters.map{ |t| t**5.0 }.sum
         
     | 
| 
       173 
     | 
    
         
            -
                sumt6 = parameters.map{ |t| t**6.0 }.sum
         
     | 
| 
       174 
     | 
    
         
            -
             
     | 
| 
       175 
     | 
    
         
            -
                psumt1 = [pointlist, parameters].forzip.foreach(2).map {|point, t| point * (t**1.0) }.inject(V2D::O){|sum, item| sum + item}
         
     | 
| 
       176 
     | 
    
         
            -
                psumt2 = [pointlist, parameters].forzip.foreach(2).map {|point, t| point * (t**2.0) }.inject(V2D::O){|sum, item| sum + item}
         
     | 
| 
       177 
     | 
    
         
            -
                psumt3 = [pointlist, parameters].forzip.foreach(2).map {|point, t| point * (t**3.0) }.inject(V2D::O){|sum, item| sum + item}
         
     | 
| 
       178 
     | 
    
         
            -
             
     | 
| 
       179 
     | 
    
         
            -
                coeff11 = sumt6 - 2 * sumt4 + sumt2
         
     | 
| 
       180 
     | 
    
         
            -
                coeff12 = sumt5 - sumt4 - sumt3 + sumt2
         
     | 
| 
       181 
     | 
    
         
            -
             
     | 
| 
       182 
     | 
    
         
            -
                coeff21 = coeff12
         
     | 
| 
       183 
     | 
    
         
            -
                coeff22 = sumt4 - 2 * sumt3 + sumt2
         
     | 
| 
       184 
     | 
    
         
            -
             
     | 
| 
       185 
     | 
    
         
            -
                result1 = (p0 - p1) * (sumt4 - sumt2) - p0 * (sumt3 - sumt1) + psumt3 - psumt1
         
     | 
| 
       186 
     | 
    
         
            -
                result2 = (p0 - p1) * (sumt3 - sumt2) - p0 * (sumt2 - sumt1) + psumt2 - psumt1
         
     | 
| 
       187 
     | 
    
         
            -
                
         
     | 
| 
       188 
     | 
    
         
            -
                matrix = Matrix[ [coeff11, coeff12], [coeff21, coeff22] ]
         
     | 
| 
       189 
     | 
    
         
            -
                matrixinv = matrix.inverse
         
     | 
| 
       190 
     | 
    
         
            -
                ax, bx = (matrixinv * Vector[result1.x, result2.x])[0..-1]
         
     | 
| 
       191 
     | 
    
         
            -
                ay, by = (matrixinv * Vector[result1.y, result2.y])[0..-1]
         
     | 
| 
       192 
     | 
    
         
            -
             
     | 
| 
       193 
     | 
    
         
            -
                a = V2D[ax, ay]
         
     | 
| 
       194 
     | 
    
         
            -
                b = V2D[bx, by]
         
     | 
| 
       195 
     | 
    
         
            -
                d = p0
         
     | 
| 
       196 
     | 
    
         
            -
                c = p1- (a + b + p0)
         
     | 
| 
       197 
     | 
    
         
            -
             
     | 
| 
       198 
     | 
    
         
            -
                piece = Fitting.bezierpiece( a, b, c, d )
         
     | 
| 
       199 
     | 
    
         
            -
                return [Bezier.raw( *piece ), [a, b, c, d] ]
         
     | 
| 
       200 
     | 
    
         
            -
              end    
         
     | 
| 
       201 
     | 
    
         
            -
            end
         
     | 
| 
       202 
     | 
    
         
            -
             
     | 
| 
       203 
     | 
    
         
            -
            end # end XRVG
         
     | 
    
        data/lib/frame.rb
    DELETED
    
    | 
         @@ -1,33 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # frame.rb file
         
     | 
| 
       2 
     | 
    
         
            -
            # 
         
     | 
| 
       3 
     | 
    
         
            -
            # See +Frame+
         
     | 
| 
       4 
     | 
    
         
            -
            require 'attributable'
         
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
       6 
     | 
    
         
            -
            module XRVG
         
     | 
| 
       7 
     | 
    
         
            -
            #
         
     | 
| 
       8 
     | 
    
         
            -
            # Frame class
         
     | 
| 
       9 
     | 
    
         
            -
            # = Intro
         
     | 
| 
       10 
     | 
    
         
            -
            # Defines a local geometry. Used by +Curve+ interface.
         
     | 
| 
       11 
     | 
    
         
            -
            # = Attributes
         
     | 
| 
       12 
     | 
    
         
            -
            #   attribute :center
         
     | 
| 
       13 
     | 
    
         
            -
            #   attribute :vector
         
     | 
| 
       14 
     | 
    
         
            -
            #   attribute :rotation
         
     | 
| 
       15 
     | 
    
         
            -
            #   attribute :scale
         
     | 
| 
       16 
     | 
    
         
            -
            class Frame
         
     | 
| 
       17 
     | 
    
         
            -
              include Attributable
         
     | 
| 
       18 
     | 
    
         
            -
              attribute :center
         
     | 
| 
       19 
     | 
    
         
            -
              attribute :vector
         
     | 
| 
       20 
     | 
    
         
            -
              attribute :rotation
         
     | 
| 
       21 
     | 
    
         
            -
              attribute :scale
         
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
              def ==(other)
         
     | 
| 
       24 
     | 
    
         
            -
                if self.center == other.center and
         
     | 
| 
       25 
     | 
    
         
            -
            	self.vector == other.vector and
         
     | 
| 
       26 
     | 
    
         
            -
            	self.rotation == other.rotation and
         
     | 
| 
       27 
     | 
    
         
            -
            	self.scale == other.scale
         
     | 
| 
       28 
     | 
    
         
            -
                  return true
         
     | 
| 
       29 
     | 
    
         
            -
                end
         
     | 
| 
       30 
     | 
    
         
            -
                return false
         
     | 
| 
       31 
     | 
    
         
            -
              end
         
     | 
| 
       32 
     | 
    
         
            -
            end
         
     | 
| 
       33 
     | 
    
         
            -
            end
         
     | 
    
        data/lib/geovariety.rb
    DELETED
    
    | 
         @@ -1,128 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # File for GeoVariety
         
     | 
| 
       2 
     | 
    
         
            -
            # See (also):
         
     | 
| 
       3 
     | 
    
         
            -
            # - InterBezier
         
     | 
| 
       4 
     | 
    
         
            -
            # - Offsetvariety
         
     | 
| 
       5 
     | 
    
         
            -
            # - FuseauVariety
         
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
            require 'interbezier'
         
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
       9 
     | 
    
         
            -
            module XRVG
         
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
            # = GeoVariety abstract module
         
     | 
| 
       12 
     | 
    
         
            -
            # == Principle
         
     | 
| 
       13 
     | 
    
         
            -
            # Base module to define geometrical spaces or canvas different from simple euclidean one to draw curves on.
         
     | 
| 
       14 
     | 
    
         
            -
            # It provides three different services:
         
     | 
| 
       15 
     | 
    
         
            -
            # - point computation
         
     | 
| 
       16 
     | 
    
         
            -
            # - geodesic computation
         
     | 
| 
       17 
     | 
    
         
            -
            # - arbitrary bezier computation, this one by computing sampling of euclidean curve on the variety, and then fitting point
         
     | 
| 
       18 
     | 
    
         
            -
            #   sequence with FitBezierBuilder
         
     | 
| 
       19 
     | 
    
         
            -
            module GeoVariety
         
     | 
| 
       20 
     | 
    
         
            -
              
         
     | 
| 
       21 
     | 
    
         
            -
              # must be overriden
         
     | 
| 
       22 
     | 
    
         
            -
              def point( point )
         
     | 
| 
       23 
     | 
    
         
            -
                raise NotImplementedError.new("#{self.class.name}#point is an abstract method.")
         
     | 
| 
       24 
     | 
    
         
            -
              end
         
     | 
| 
       25 
     | 
    
         
            -
              
         
     | 
| 
       26 
     | 
    
         
            -
              # must be overriden
         
     | 
| 
       27 
     | 
    
         
            -
              def line( x1, x2, y )
         
     | 
| 
       28 
     | 
    
         
            -
                raise NotImplementedError.new("#{self.class.name}#line is an abstract method.")
         
     | 
| 
       29 
     | 
    
         
            -
              end
         
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
              # see GeoVariety module description for algorithm
         
     | 
| 
       32 
     | 
    
         
            -
              def bezier( pointrange, bezier )
         
     | 
| 
       33 
     | 
    
         
            -
                bezier = bezier.similar( pointrange )
         
     | 
| 
       34 
     | 
    
         
            -
                points = bezier.samples( 20 )
         
     | 
| 
       35 
     | 
    
         
            -
                points = points.map {|point| self.point( point )}
         
     | 
| 
       36 
     | 
    
         
            -
                return FitBezierBuilder[ :points, points ]
         
     | 
| 
       37 
     | 
    
         
            -
              end
         
     | 
| 
       38 
     | 
    
         
            -
            end
         
     | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
       40 
     | 
    
         
            -
            # = InterBezier GeoVariety implementation
         
     | 
| 
       41 
     | 
    
         
            -
            # == Principle
         
     | 
| 
       42 
     | 
    
         
            -
            # InterBezier defines a surface by the set of every possible curve sample from one interpolated curve to the other.
         
     | 
| 
       43 
     | 
    
         
            -
            # Geodesic corresponds then to one interpolated result, and point to a point of this curve
         
     | 
| 
       44 
     | 
    
         
            -
            class InterBezier
         
     | 
| 
       45 
     | 
    
         
            -
              include GeoVariety
         
     | 
| 
       46 
     | 
    
         
            -
              
         
     | 
| 
       47 
     | 
    
         
            -
              # Compute the geodesic curve by doing self.sample with y coord, and then compute point of this curve with length "x"
         
     | 
| 
       48 
     | 
    
         
            -
              def point( point )
         
     | 
| 
       49 
     | 
    
         
            -
                curve = self.sample( point.y )
         
     | 
| 
       50 
     | 
    
         
            -
                return curve.point( point.x )
         
     | 
| 
       51 
     | 
    
         
            -
              end
         
     | 
| 
       52 
     | 
    
         
            -
             
     | 
| 
       53 
     | 
    
         
            -
              # Compute the geodesic subcurve with y coord between x1 and x2
         
     | 
| 
       54 
     | 
    
         
            -
              def line( x1, x2, y )
         
     | 
| 
       55 
     | 
    
         
            -
                # Trace("interbezier line x1 #{x1} x2 #{x2} y #{y}")
         
     | 
| 
       56 
     | 
    
         
            -
                curve = self.sample( y )
         
     | 
| 
       57 
     | 
    
         
            -
                result = curve.apply_split( x1, x2 )
         
     | 
| 
       58 
     | 
    
         
            -
                # Trace("interbezier line result #{result.inspect}")
         
     | 
| 
       59 
     | 
    
         
            -
                return result
         
     | 
| 
       60 
     | 
    
         
            -
              end
         
     | 
| 
       61 
     | 
    
         
            -
             
     | 
| 
       62 
     | 
    
         
            -
            end
         
     | 
| 
       63 
     | 
    
         
            -
             
     | 
| 
       64 
     | 
    
         
            -
            # = OffsetVariety implementation
         
     | 
| 
       65 
     | 
    
         
            -
            # == Principle
         
     | 
| 
       66 
     | 
    
         
            -
            # Geovariety is defined by the set of offset curves from -ampl to +ampl
         
     | 
| 
       67 
     | 
    
         
            -
            # == Extension
         
     | 
| 
       68 
     | 
    
         
            -
            # Parameter could be a :samplable parameter : in that case, ampl will vary
         
     | 
| 
       69 
     | 
    
         
            -
            #
         
     | 
| 
       70 
     | 
    
         
            -
            # Another extension would be to parametrize range straightforwardly
         
     | 
| 
       71 
     | 
    
         
            -
            #
         
     | 
| 
       72 
     | 
    
         
            -
            # Finally, the two previous remarks must be synthetized :-)
         
     | 
| 
       73 
     | 
    
         
            -
            class OffsetVariety
         
     | 
| 
       74 
     | 
    
         
            -
              include Attributable
         
     | 
| 
       75 
     | 
    
         
            -
              attribute :support
         
     | 
| 
       76 
     | 
    
         
            -
              attribute :ampl, nil, Float
         
     | 
| 
       77 
     | 
    
         
            -
             
     | 
| 
       78 
     | 
    
         
            -
              include GeoVariety
         
     | 
| 
       79 
     | 
    
         
            -
             
     | 
| 
       80 
     | 
    
         
            -
              # builder: init static offset range with (-self.ampl..self.ampl)
         
     | 
| 
       81 
     | 
    
         
            -
              def initialize( *args )
         
     | 
| 
       82 
     | 
    
         
            -
                super( *args )
         
     | 
| 
       83 
     | 
    
         
            -
                @range = (-self.ampl..self.ampl)
         
     | 
| 
       84 
     | 
    
         
            -
              end
         
     | 
| 
       85 
     | 
    
         
            -
             
     | 
| 
       86 
     | 
    
         
            -
              # point computed by computing offset curve with ampl y coord mapped onto offset range, and then sampling the curve with x coord
         
     | 
| 
       87 
     | 
    
         
            -
              def point( point )
         
     | 
| 
       88 
     | 
    
         
            -
                curve = Offset[ :support, @support, :ampl, @range.sample( point.y ) ]
         
     | 
| 
       89 
     | 
    
         
            -
                return curve.point( point.x )
         
     | 
| 
       90 
     | 
    
         
            -
              end
         
     | 
| 
       91 
     | 
    
         
            -
             
     | 
| 
       92 
     | 
    
         
            -
              # subgeodesic computed by computing offset curve with ampl y coord
         
     | 
| 
       93 
     | 
    
         
            -
              def line( x1, x2, y )
         
     | 
| 
       94 
     | 
    
         
            -
                curve = Offset[ :support, @support, :ampl, @range.sample( y ) ]
         
     | 
| 
       95 
     | 
    
         
            -
                return curve.apply_split( x1, x2 )
         
     | 
| 
       96 
     | 
    
         
            -
              end
         
     | 
| 
       97 
     | 
    
         
            -
              
         
     | 
| 
       98 
     | 
    
         
            -
            end  
         
     | 
| 
       99 
     | 
    
         
            -
             
     | 
| 
       100 
     | 
    
         
            -
            # = FuseauVariety implementation
         
     | 
| 
       101 
     | 
    
         
            -
            # == Principle
         
     | 
| 
       102 
     | 
    
         
            -
            # Same as OffsetVariety, with Fuseau shape, that is with linearly varying ampl range
         
     | 
| 
       103 
     | 
    
         
            -
            class FuseauVariety
         
     | 
| 
       104 
     | 
    
         
            -
              include Attributable
         
     | 
| 
       105 
     | 
    
         
            -
              attribute :support
         
     | 
| 
       106 
     | 
    
         
            -
              attribute :ampl, nil, Float
         
     | 
| 
       107 
     | 
    
         
            -
             
     | 
| 
       108 
     | 
    
         
            -
              include GeoVariety
         
     | 
| 
       109 
     | 
    
         
            -
             
     | 
| 
       110 
     | 
    
         
            -
              def initialize( *args )
         
     | 
| 
       111 
     | 
    
         
            -
                super( *args )
         
     | 
| 
       112 
     | 
    
         
            -
                @range = (-self.ampl..self.ampl)
         
     | 
| 
       113 
     | 
    
         
            -
              end
         
     | 
| 
       114 
     | 
    
         
            -
             
     | 
| 
       115 
     | 
    
         
            -
              def point( point )
         
     | 
| 
       116 
     | 
    
         
            -
                curve = Offset[ :support, @support, :ampl, (0.0..@range.sample( point.y ))]
         
     | 
| 
       117 
     | 
    
         
            -
                return curve.point( point.x )
         
     | 
| 
       118 
     | 
    
         
            -
              end
         
     | 
| 
       119 
     | 
    
         
            -
             
     | 
| 
       120 
     | 
    
         
            -
              def line( x1, x2, y )
         
     | 
| 
       121 
     | 
    
         
            -
                curve = Offset[ :support, @support, :ampl, (0.0..@range.sample( y ))]
         
     | 
| 
       122 
     | 
    
         
            -
                return curve.apply_split( x1, x2 )
         
     | 
| 
       123 
     | 
    
         
            -
              end
         
     | 
| 
       124 
     | 
    
         
            -
            end
         
     | 
| 
       125 
     | 
    
         
            -
             
     | 
| 
       126 
     | 
    
         
            -
            end # XRVG
         
     | 
| 
       127 
     | 
    
         
            -
             
     | 
| 
       128 
     | 
    
         
            -
            # see geovariety_test to see tests
         
     | 
    
        data/lib/interbezier.rb
    DELETED
    
    | 
         @@ -1,87 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require 'bezier'
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            module XRVG
         
     | 
| 
       4 
     | 
    
         
            -
            class InterBezier
         
     | 
| 
       5 
     | 
    
         
            -
              include Attributable
         
     | 
| 
       6 
     | 
    
         
            -
              attribute :bezierlist
         
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
              include Interpolation
         
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
       10 
     | 
    
         
            -
              def initialize( *args )
         
     | 
| 
       11 
     | 
    
         
            -
                super( *args )
         
     | 
| 
       12 
     | 
    
         
            -
                self.init_interpolation_structures
         
     | 
| 
       13 
     | 
    
         
            -
              end
         
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
              def init_interpolation_structures
         
     | 
| 
       16 
     | 
    
         
            -
                beziers = []
         
     | 
| 
       17 
     | 
    
         
            -
                indexes = []
         
     | 
| 
       18 
     | 
    
         
            -
                @bezierlist.foreach do |index, bezier| 
         
     | 
| 
       19 
     | 
    
         
            -
                  beziers.push( bezier )
         
     | 
| 
       20 
     | 
    
         
            -
                  indexes.push( index )
         
     | 
| 
       21 
     | 
    
         
            -
                end
         
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
                lengthH = {}
         
     | 
| 
       24 
     | 
    
         
            -
                alllengths = []
         
     | 
| 
       25 
     | 
    
         
            -
                beziers.each do |bezier|
         
     | 
| 
       26 
     | 
    
         
            -
                  lengths = bezier.piecelengths
         
     | 
| 
       27 
     | 
    
         
            -
                  Trace("bezier lengths #{lengths.inspect}")
         
     | 
| 
       28 
     | 
    
         
            -
                  lengthH[ bezier ] = lengths
         
     | 
| 
       29 
     | 
    
         
            -
                  alllengths += lengths
         
     | 
| 
       30 
     | 
    
         
            -
                end
         
     | 
| 
       31 
     | 
    
         
            -
                alllengths = Float.sort_float_list( alllengths )
         
     | 
| 
       32 
     | 
    
         
            -
                Trace("alllengths #{alllengths.inspect}")
         
     | 
| 
       33 
     | 
    
         
            -
                
         
     | 
| 
       34 
     | 
    
         
            -
                newbezierlist = []
         
     | 
| 
       35 
     | 
    
         
            -
                beziers.each do |bezier|
         
     | 
| 
       36 
     | 
    
         
            -
                  newpieces = []
         
     | 
| 
       37 
     | 
    
         
            -
                  initlengths = lengthH[ bezier ]
         
     | 
| 
       38 
     | 
    
         
            -
                  alllengths.pairs do |l1, l2| 
         
     | 
| 
       39 
     | 
    
         
            -
            	newpieces += bezier.subbezier( l1, l2 ).pieces
         
     | 
| 
       40 
     | 
    
         
            -
                  end
         
     | 
| 
       41 
     | 
    
         
            -
                  newbezier = Bezier[ :pieces, newpieces ]
         
     | 
| 
       42 
     | 
    
         
            -
                  newbezierlist << newbezier
         
     | 
| 
       43 
     | 
    
         
            -
                end
         
     | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
       45 
     | 
    
         
            -
                Trace("newbezierlist #{newbezierlist.length}")
         
     | 
| 
       46 
     | 
    
         
            -
                beziers = newbezierlist
         
     | 
| 
       47 
     | 
    
         
            -
                bezierpointlists = beziers.map {|bezier| bezier.pointlist(:vector) }
         
     | 
| 
       48 
     | 
    
         
            -
                Trace("bezierpointlists #{bezierpointlists.map {|list| list.length}.inspect}")
         
     | 
| 
       49 
     | 
    
         
            -
                pointsequencelist = bezierpointlists.forzip
         
     | 
| 
       50 
     | 
    
         
            -
                @interpolatorlist = []
         
     | 
| 
       51 
     | 
    
         
            -
                pointsequencelist.foreach(beziers.size) do |pointsequence|
         
     | 
| 
       52 
     | 
    
         
            -
                  interlist = [indexes, pointsequence].forzip
         
     | 
| 
       53 
     | 
    
         
            -
                  @interpolatorlist.push( Interpolator.new( :samplelist, interlist ) )
         
     | 
| 
       54 
     | 
    
         
            -
                end
         
     | 
| 
       55 
     | 
    
         
            -
              end
         
     | 
| 
       56 
     | 
    
         
            -
             
     | 
| 
       57 
     | 
    
         
            -
              def interpolate( abs, container=nil )
         
     | 
| 
       58 
     | 
    
         
            -
                pieces = []
         
     | 
| 
       59 
     | 
    
         
            -
                @interpolatorlist.foreach(4) do |interpiece|
         
     | 
| 
       60 
     | 
    
         
            -
                  piece = interpiece.map {|inter| inter.interpolate( abs )}
         
     | 
| 
       61 
     | 
    
         
            -
                  pieces.push( [:vector] + piece )
         
     | 
| 
       62 
     | 
    
         
            -
                end
         
     | 
| 
       63 
     | 
    
         
            -
                return Bezier.multi( pieces )    
         
     | 
| 
       64 
     | 
    
         
            -
              end
         
     | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
       66 
     | 
    
         
            -
              include Samplable
         
     | 
| 
       67 
     | 
    
         
            -
              alias apply_sample interpolate
         
     | 
| 
       68 
     | 
    
         
            -
             
     | 
| 
       69 
     | 
    
         
            -
            end
         
     | 
| 
       70 
     | 
    
         
            -
             
     | 
| 
       71 
     | 
    
         
            -
            class GradientBezier < InterBezier
         
     | 
| 
       72 
     | 
    
         
            -
             
     | 
| 
       73 
     | 
    
         
            -
              # TODO : does not work !!
         
     | 
| 
       74 
     | 
    
         
            -
              def samples( nsamples, &block )
         
     | 
| 
       75 
     | 
    
         
            -
                return super( nsamples + 1, &block )
         
     | 
| 
       76 
     | 
    
         
            -
              end
         
     | 
| 
       77 
     | 
    
         
            -
             
     | 
| 
       78 
     | 
    
         
            -
              def apply_samples( samples )
         
     | 
| 
       79 
     | 
    
         
            -
                samples = super( samples )
         
     | 
| 
       80 
     | 
    
         
            -
                result = []
         
     | 
| 
       81 
     | 
    
         
            -
                samples.pairs do |bezier1, bezier2|
         
     | 
| 
       82 
     | 
    
         
            -
                  result.push( ClosureBezier.build( :bezierlist, [bezier1, bezier2.reverse]) )
         
     | 
| 
       83 
     | 
    
         
            -
                end
         
     | 
| 
       84 
     | 
    
         
            -
                return result
         
     | 
| 
       85 
     | 
    
         
            -
              end
         
     | 
| 
       86 
     | 
    
         
            -
            end
         
     | 
| 
       87 
     | 
    
         
            -
            end # XRVG  
         
     | 
    
        data/lib/render.rb
    DELETED
    
    | 
         @@ -1,266 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # 
         
     | 
| 
       2 
     | 
    
         
            -
            # Render file. See
         
     | 
| 
       3 
     | 
    
         
            -
            # - +Render+ for render "abstraction"
         
     | 
| 
       4 
     | 
    
         
            -
            # - +SVGRender+ for effective SVG render 
         
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
       6 
     | 
    
         
            -
            require 'color'
         
     | 
| 
       7 
     | 
    
         
            -
            require 'style'
         
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
       9 
     | 
    
         
            -
            module XRVG
         
     | 
| 
       10 
     | 
    
         
            -
            # Render abstract class
         
     | 
| 
       11 
     | 
    
         
            -
            #
         
     | 
| 
       12 
     | 
    
         
            -
            # Is pretty useless for the moment
         
     | 
| 
       13 
     | 
    
         
            -
            class Render
         
     | 
| 
       14 
     | 
    
         
            -
              include Attributable
         
     | 
| 
       15 
     | 
    
         
            -
              attr_accessor :width
         
     | 
| 
       16 
     | 
    
         
            -
              attr_accessor :height
         
     | 
| 
       17 
     | 
    
         
            -
            end
         
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
       19 
     | 
    
         
            -
            # SVG Render class
         
     | 
| 
       20 
     | 
    
         
            -
            #
         
     | 
| 
       21 
     | 
    
         
            -
            # In charge of generating a svg output file from different object passed to it
         
     | 
| 
       22 
     | 
    
         
            -
            # = Use
         
     | 
| 
       23 
     | 
    
         
            -
            # Canonical use of the class
         
     | 
| 
       24 
     | 
    
         
            -
            #  render = SVGRender[ :filename, "essai.svg" ]
         
     | 
| 
       25 
     | 
    
         
            -
            #  render.add( Circle[] )
         
     | 
| 
       26 
     | 
    
         
            -
            #  render.end
         
     | 
| 
       27 
     | 
    
         
            -
            # = Improvements
         
     | 
| 
       28 
     | 
    
         
            -
            # Allows also the "with" syntax
         
     | 
| 
       29 
     | 
    
         
            -
            # = Attributes
         
     | 
| 
       30 
     | 
    
         
            -
            #  attribute :filename, "", String
         
     | 
| 
       31 
     | 
    
         
            -
            #  attribute :imagesize, "2cm", String
         
     | 
| 
       32 
     | 
    
         
            -
            #  attribute :background, Color.white, [Color, String]
         
     | 
| 
       33 
     | 
    
         
            -
            class SVGRender < Render
         
     | 
| 
       34 
     | 
    
         
            -
              attribute :filename, "", String
         
     | 
| 
       35 
     | 
    
         
            -
              attribute :imagesize, "2cm", String
         
     | 
| 
       36 
     | 
    
         
            -
              attribute :background, "white", [Color, String]
         
     | 
| 
       37 
     | 
    
         
            -
              attr_reader :viewbox
         
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
              # SVGRender builder
         
     | 
| 
       40 
     | 
    
         
            -
              #
         
     | 
| 
       41 
     | 
    
         
            -
              # Allows to pass a block, to avoid using .end
         
     | 
| 
       42 
     | 
    
         
            -
              #  SVGRender.[] do |render|
         
     | 
| 
       43 
     | 
    
         
            -
              #    render.add( Circle[] )
         
     | 
| 
       44 
     | 
    
         
            -
              #  end
         
     | 
| 
       45 
     | 
    
         
            -
              def SVGRender.[](*args,&block)
         
     | 
| 
       46 
     | 
    
         
            -
                result = self.new( *args )
         
     | 
| 
       47 
     | 
    
         
            -
                if block
         
     | 
| 
       48 
     | 
    
         
            -
                  yield result
         
     | 
| 
       49 
     | 
    
         
            -
                  result.end
         
     | 
| 
       50 
     | 
    
         
            -
                end
         
     | 
| 
       51 
     | 
    
         
            -
                return result
         
     | 
| 
       52 
     | 
    
         
            -
              end
         
     | 
| 
       53 
     | 
    
         
            -
             
     | 
| 
       54 
     | 
    
         
            -
              
         
     | 
| 
       55 
     | 
    
         
            -
              def initialize ( *args, &block ) #:nodoc:
         
     | 
| 
       56 
     | 
    
         
            -
                super( *args )
         
     | 
| 
       57 
     | 
    
         
            -
                @layers  = {}
         
     | 
| 
       58 
     | 
    
         
            -
                @defs    = ""
         
     | 
| 
       59 
     | 
    
         
            -
                @ngradients = 0
         
     | 
| 
       60 
     | 
    
         
            -
                if @filename.length == 0
         
     | 
| 
       61 
     | 
    
         
            -
                  @filename = $0.split(".")[0..-2].join(".") + ".svg"
         
     | 
| 
       62 
     | 
    
         
            -
                  Trace("filename is #{filename}")
         
     | 
| 
       63 
     | 
    
         
            -
                end
         
     | 
| 
       64 
     | 
    
         
            -
              end
         
     | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
       66 
     | 
    
         
            -
              def layers=( backtofront ) #:nodoc:
         
     | 
| 
       67 
     | 
    
         
            -
                @sortlayers = backtofront
         
     | 
| 
       68 
     | 
    
         
            -
                @sortlayers.each do |key|
         
     | 
| 
       69 
     | 
    
         
            -
                  @layers[ key ] = ""
         
     | 
| 
       70 
     | 
    
         
            -
                end
         
     | 
| 
       71 
     | 
    
         
            -
              end
         
     | 
| 
       72 
     | 
    
         
            -
              
         
     | 
| 
       73 
     | 
    
         
            -
              def add_content (string, layer) #:nodoc:
         
     | 
| 
       74 
     | 
    
         
            -
                if not @layers.key? layer
         
     | 
| 
       75 
     | 
    
         
            -
                  @layers[ layer ] = ""
         
     | 
| 
       76 
     | 
    
         
            -
                end
         
     | 
| 
       77 
     | 
    
         
            -
                @layers[ layer ] += string
         
     | 
| 
       78 
     | 
    
         
            -
              end
         
     | 
| 
       79 
     | 
    
         
            -
             
     | 
| 
       80 
     | 
    
         
            -
              def svg_template #:nodoc:
         
     | 
| 
       81 
     | 
    
         
            -
                return '<?xml version="1.0" standalone="no"?>
         
     | 
| 
       82 
     | 
    
         
            -
            <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
         
     | 
| 
       83 
     | 
    
         
            -
            <svg width="%SIZE%" height="%SIZE%" %VIEWBOX% version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
         
     | 
| 
       84 
     | 
    
         
            -
                %DEFS%
         
     | 
| 
       85 
     | 
    
         
            -
                %BACKGROUND%
         
     | 
| 
       86 
     | 
    
         
            -
                %CONTENT%
         
     | 
| 
       87 
     | 
    
         
            -
            </svg>'
         
     | 
| 
       88 
     | 
    
         
            -
              end
         
     | 
| 
       89 
     | 
    
         
            -
              
         
     | 
| 
       90 
     | 
    
         
            -
              def add_def (object) #:nodoc:
         
     | 
| 
       91 
     | 
    
         
            -
                @defs += object
         
     | 
| 
       92 
     | 
    
         
            -
              end
         
     | 
| 
       93 
     | 
    
         
            -
             
     | 
| 
       94 
     | 
    
         
            -
              def add_gradient( gradient ) #:nodoc:
         
     | 
| 
       95 
     | 
    
         
            -
                id = "gradient#{@ngradients}"
         
     | 
| 
       96 
     | 
    
         
            -
                add_def( gradient.svgdef.subreplace( {"%ID%" => id} ) )
         
     | 
| 
       97 
     | 
    
         
            -
                @ngradients += 1
         
     | 
| 
       98 
     | 
    
         
            -
                return id
         
     | 
| 
       99 
     | 
    
         
            -
              end
         
     | 
| 
       100 
     | 
    
         
            -
             
     | 
| 
       101 
     | 
    
         
            -
              # render fundamental method
         
     | 
| 
       102 
     | 
    
         
            -
              # 
         
     | 
| 
       103 
     | 
    
         
            -
              # used to render an object, with a particular style, on an optional layer.
         
     | 
| 
       104 
     | 
    
         
            -
              #  render.add( Circle[], Style[ :fill, Color.black ], 1 )
         
     | 
| 
       105 
     | 
    
         
            -
              # If style is not provided, render asked to object its default_style, if any
         
     | 
| 
       106 
     | 
    
         
            -
              def add(object, style=nil, layer=0, type=:object)
         
     | 
| 
       107 
     | 
    
         
            -
                add_content( render( object, style ), layer)
         
     | 
| 
       108 
     | 
    
         
            -
                refresh_viewbox( object )
         
     | 
| 
       109 
     | 
    
         
            -
              end
         
     | 
| 
       110 
     | 
    
         
            -
              
         
     | 
| 
       111 
     | 
    
         
            -
              def render (object, style=nil) #:nodoc:
         
     | 
| 
       112 
     | 
    
         
            -
                owidth, oheight = object.size
         
     | 
| 
       113 
     | 
    
         
            -
             
     | 
| 
       114 
     | 
    
         
            -
                res     = 0.0000001
         
     | 
| 
       115 
     | 
    
         
            -
                if owidth < res and oheight < res
         
     | 
| 
       116 
     | 
    
         
            -
                  return ""
         
     | 
| 
       117 
     | 
    
         
            -
                end
         
     | 
| 
       118 
     | 
    
         
            -
             
     | 
| 
       119 
     | 
    
         
            -
                if not style
         
     | 
| 
       120 
     | 
    
         
            -
                  style = object.default_style
         
     | 
| 
       121 
     | 
    
         
            -
                end
         
     | 
| 
       122 
     | 
    
         
            -
             
     | 
| 
       123 
     | 
    
         
            -
                result  = "<g #{style.svgline}>\n"
         
     | 
| 
       124 
     | 
    
         
            -
                result += object.svg + "\n"
         
     | 
| 
       125 
     | 
    
         
            -
                result += "</g>\n"
         
     | 
| 
       126 
     | 
    
         
            -
             
     | 
| 
       127 
     | 
    
         
            -
                # puts "result #{result}"
         
     | 
| 
       128 
     | 
    
         
            -
             
     | 
| 
       129 
     | 
    
         
            -
                if style.fill.is_a? Gradient
         
     | 
| 
       130 
     | 
    
         
            -
                  gradientID = add_gradient( style.fill )
         
     | 
| 
       131 
     | 
    
         
            -
                  result = result.subreplace( {"%fillgradient%" => "url(##{gradientID})"} )
         
     | 
| 
       132 
     | 
    
         
            -
                end
         
     | 
| 
       133 
     | 
    
         
            -
                
         
     | 
| 
       134 
     | 
    
         
            -
                if style.stroke.is_a? Gradient
         
     | 
| 
       135 
     | 
    
         
            -
                  gradientID = add_gradient( style.stroke )
         
     | 
| 
       136 
     | 
    
         
            -
                  result = result.subreplace( {"%strokegradient%" => "url(##{gradientID})"} )
         
     | 
| 
       137 
     | 
    
         
            -
                end
         
     | 
| 
       138 
     | 
    
         
            -
                return result
         
     | 
| 
       139 
     | 
    
         
            -
              end
         
     | 
| 
       140 
     | 
    
         
            -
             
     | 
| 
       141 
     | 
    
         
            -
              def viewbox #:nodoc:
         
     | 
| 
       142 
     | 
    
         
            -
                return @viewbox
         
     | 
| 
       143 
     | 
    
         
            -
              end
         
     | 
| 
       144 
     | 
    
         
            -
             
     | 
| 
       145 
     | 
    
         
            -
              def size #:nodoc:
         
     | 
| 
       146 
     | 
    
         
            -
                xmin, ymin, xmax, ymax  = viewbox
         
     | 
| 
       147 
     | 
    
         
            -
                return [xmax - xmin, ymax - ymin]
         
     | 
| 
       148 
     | 
    
         
            -
              end
         
     | 
| 
       149 
     | 
    
         
            -
             
     | 
| 
       150 
     | 
    
         
            -
              def refresh_viewbox (object) #:nodoc:
         
     | 
| 
       151 
     | 
    
         
            -
                newviewbox = object.viewbox
         
     | 
| 
       152 
     | 
    
         
            -
                if newviewbox.length > 0
         
     | 
| 
       153 
     | 
    
         
            -
                  if @viewbox == nil
         
     | 
| 
       154 
     | 
    
         
            -
            	@viewbox = newviewbox
         
     | 
| 
       155 
     | 
    
         
            -
                  else
         
     | 
| 
       156 
     | 
    
         
            -
            	newxmin, newymin, newxmax, newymax = newviewbox
         
     | 
| 
       157 
     | 
    
         
            -
            	xmin, ymin, xmax, ymax = viewbox
         
     | 
| 
       158 
     | 
    
         
            -
            	
         
     | 
| 
       159 
     | 
    
         
            -
            	if newxmin < xmin 
         
     | 
| 
       160 
     | 
    
         
            -
            	  xmin = newxmin
         
     | 
| 
       161 
     | 
    
         
            -
            	end
         
     | 
| 
       162 
     | 
    
         
            -
            	if newymin < ymin 
         
     | 
| 
       163 
     | 
    
         
            -
            	  ymin = newymin
         
     | 
| 
       164 
     | 
    
         
            -
            	end
         
     | 
| 
       165 
     | 
    
         
            -
            	if newxmax > xmax
         
     | 
| 
       166 
     | 
    
         
            -
            	  xmax = newxmax
         
     | 
| 
       167 
     | 
    
         
            -
            	end
         
     | 
| 
       168 
     | 
    
         
            -
            	if newymax > ymax
         
     | 
| 
       169 
     | 
    
         
            -
            	  ymax = newymax
         
     | 
| 
       170 
     | 
    
         
            -
            	end
         
     | 
| 
       171 
     | 
    
         
            -
             
     | 
| 
       172 
     | 
    
         
            -
            	@viewbox = [xmin, ymin, xmax, ymax]
         
     | 
| 
       173 
     | 
    
         
            -
                  end
         
     | 
| 
       174 
     | 
    
         
            -
                end
         
     | 
| 
       175 
     | 
    
         
            -
              end
         
     | 
| 
       176 
     | 
    
         
            -
              
         
     | 
| 
       177 
     | 
    
         
            -
              def get_background_svg #:nodoc:
         
     | 
| 
       178 
     | 
    
         
            -
                xmin, ymin, width, height = get_carre_viewbox( get_final_viewbox() )
         
     | 
| 
       179 
     | 
    
         
            -
                template = '<rect x="%x%" y="%y%" width="%width%" height="%height%" fill="%fill%"/>' 
         
     | 
| 
       180 
     | 
    
         
            -
                bg = self.background
         
     | 
| 
       181 
     | 
    
         
            -
                if bg.respond_to? :svg
         
     | 
| 
       182 
     | 
    
         
            -
                  bg = bg.svg
         
     | 
| 
       183 
     | 
    
         
            -
                end
         
     | 
| 
       184 
     | 
    
         
            -
                return template.subreplace( {"%x%"      => xmin,
         
     | 
| 
       185 
     | 
    
         
            -
            				 "%y%"      => ymin,
         
     | 
| 
       186 
     | 
    
         
            -
            				 "%width%"  => width,
         
     | 
| 
       187 
     | 
    
         
            -
            				 "%height%" => height,
         
     | 
| 
       188 
     | 
    
         
            -
            				 "%fill%"   => bg} )
         
     | 
| 
       189 
     | 
    
         
            -
              end
         
     | 
| 
       190 
     | 
    
         
            -
             
     | 
| 
       191 
     | 
    
         
            -
              def get_final_viewbox #:nodoc:
         
     | 
| 
       192 
     | 
    
         
            -
                marginfactor = 0.2
         
     | 
| 
       193 
     | 
    
         
            -
                xmin, ymin, xmax, ymax = viewbox()
         
     | 
| 
       194 
     | 
    
         
            -
                width, height          = size()
         
     | 
| 
       195 
     | 
    
         
            -
                
         
     | 
| 
       196 
     | 
    
         
            -
                xcenter = (xmin + xmax)/2.0
         
     | 
| 
       197 
     | 
    
         
            -
                ycenter = (ymin + ymax)/2.0
         
     | 
| 
       198 
     | 
    
         
            -
                
         
     | 
| 
       199 
     | 
    
         
            -
                width  *= 1.0 + marginfactor
         
     | 
| 
       200 
     | 
    
         
            -
                height *= 1.0 + marginfactor
         
     | 
| 
       201 
     | 
    
         
            -
                
         
     | 
| 
       202 
     | 
    
         
            -
                if width == 0.0
         
     | 
| 
       203 
     | 
    
         
            -
                  width = 1.0
         
     | 
| 
       204 
     | 
    
         
            -
                end
         
     | 
| 
       205 
     | 
    
         
            -
                if height == 0.0
         
     | 
| 
       206 
     | 
    
         
            -
                  height = 1.0
         
     | 
| 
       207 
     | 
    
         
            -
                end
         
     | 
| 
       208 
     | 
    
         
            -
             
     | 
| 
       209 
     | 
    
         
            -
                xmin = xcenter - width  / 2.0
         
     | 
| 
       210 
     | 
    
         
            -
                ymin = ycenter - height / 2.0
         
     | 
| 
       211 
     | 
    
         
            -
            									
         
     | 
| 
       212 
     | 
    
         
            -
                return xmin, ymin, width, height
         
     | 
| 
       213 
     | 
    
         
            -
              end
         
     | 
| 
       214 
     | 
    
         
            -
             
     | 
| 
       215 
     | 
    
         
            -
              def get_viewbox_svg #:nodoc:
         
     | 
| 
       216 
     | 
    
         
            -
                return viewbox_svg( get_final_viewbox() )
         
     | 
| 
       217 
     | 
    
         
            -
              end
         
     | 
| 
       218 
     | 
    
         
            -
             
     | 
| 
       219 
     | 
    
         
            -
              def get_carre_viewbox( viewbox ) #:nodoc:
         
     | 
| 
       220 
     | 
    
         
            -
                xmin, ymin, width, height = viewbox
         
     | 
| 
       221 
     | 
    
         
            -
                xcenter = xmin + width  / 2.0
         
     | 
| 
       222 
     | 
    
         
            -
                ycenter = ymin + height / 2.0
         
     | 
| 
       223 
     | 
    
         
            -
                maxsize = width < height ? height : width
         
     | 
| 
       224 
     | 
    
         
            -
                return [xcenter - maxsize/2.0, ycenter - maxsize/2.0, maxsize, maxsize]
         
     | 
| 
       225 
     | 
    
         
            -
              end
         
     | 
| 
       226 
     | 
    
         
            -
             
     | 
| 
       227 
     | 
    
         
            -
              def viewbox_svg( viewbox ) #:nodoc:
         
     | 
| 
       228 
     | 
    
         
            -
                xmin, ymin, width, height = viewbox
         
     | 
| 
       229 
     | 
    
         
            -
                return "viewBox=\"#{xmin} #{ymin} #{width} #{height}\""
         
     | 
| 
       230 
     | 
    
         
            -
              end
         
     | 
| 
       231 
     | 
    
         
            -
             
     | 
| 
       232 
     | 
    
         
            -
              def content #:nodoc:
         
     | 
| 
       233 
     | 
    
         
            -
                keys = @sortlayers ? @sortlayers : @layers.keys.sort
         
     | 
| 
       234 
     | 
    
         
            -
                return keys.inject("") {|result,key| result += @layers[key]}
         
     | 
| 
       235 
     | 
    
         
            -
              end
         
     | 
| 
       236 
     | 
    
         
            -
             
     | 
| 
       237 
     | 
    
         
            -
              def svgdef #:nodoc:
         
     | 
| 
       238 
     | 
    
         
            -
                return "<defs>\n#{@defs}\n</defs>\n"
         
     | 
| 
       239 
     | 
    
         
            -
              end
         
     | 
| 
       240 
     | 
    
         
            -
             
     | 
| 
       241 
     | 
    
         
            -
              def end () #:nodoc:
         
     | 
| 
       242 
     | 
    
         
            -
                svgcontent    = content()
         
     | 
| 
       243 
     | 
    
         
            -
                svgviewbox    = get_viewbox_svg()
         
     | 
| 
       244 
     | 
    
         
            -
                svgbackground = get_background_svg()
         
     | 
| 
       245 
     | 
    
         
            -
             
     | 
| 
       246 
     | 
    
         
            -
                content = svg_template().subreplace( {"%VIEWBOX%"    => svgviewbox,
         
     | 
| 
       247 
     | 
    
         
            -
            					  "%SIZE%"       => @imagesize,
         
     | 
| 
       248 
     | 
    
         
            -
            					  "%DEFS%"       => svgdef,
         
     | 
| 
       249 
     | 
    
         
            -
            					  "%BACKGROUND%" => svgbackground,
         
     | 
| 
       250 
     | 
    
         
            -
            					  "%CONTENT%"    => svgcontent})
         
     | 
| 
       251 
     | 
    
         
            -
                
         
     | 
| 
       252 
     | 
    
         
            -
                File.open(filename(), "w") do |f|
         
     | 
| 
       253 
     | 
    
         
            -
                  f << content
         
     | 
| 
       254 
     | 
    
         
            -
                end
         
     | 
| 
       255 
     | 
    
         
            -
               
         
     | 
| 
       256 
     | 
    
         
            -
                puts "render #{filename()} OK"; # necessary for Emacs to get output name !!!!
         
     | 
| 
       257 
     | 
    
         
            -
              end
         
     | 
| 
       258 
     | 
    
         
            -
              
         
     | 
| 
       259 
     | 
    
         
            -
              def raster () #:nodoc:
         
     | 
| 
       260 
     | 
    
         
            -
                # bg = background.format255
         
     | 
| 
       261 
     | 
    
         
            -
             
     | 
| 
       262 
     | 
    
         
            -
                # Kernel.system( "ruby", "svg2png.rb", filename(), "2.0" )
         
     | 
| 
       263 
     | 
    
         
            -
                # Kernel.system( "i_view32", filename().subreplace( ".svg" => ".png" ), "/fs" )
         
     | 
| 
       264 
     | 
    
         
            -
              end
         
     | 
| 
       265 
     | 
    
         
            -
            end
         
     | 
| 
       266 
     | 
    
         
            -
            end
         
     |