Merge 'fatline/master'

This commit is contained in:
Jürg Lehni 2013-05-24 16:59:45 -07:00
commit c8724aafad
5 changed files with 1726 additions and 0 deletions

9
fatline/COPYING Normal file
View file

@ -0,0 +1,9 @@
The MIT License (MIT)
Copyright (c) 2013 Harikrishnan Gopalakrishnan
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

416
fatline/Intersect.js Normal file
View file

@ -0,0 +1,416 @@
var EPSILON = 10e-12;
var TOLERANCE = 10e-6;
var MAX_RECURSE = 20;
var MAX_ITERATE = 20;
/**
* This method is analogous to paperjs#PathItem.getIntersections
*/
function getIntersections2( path1, path2 ){
// First check the bounds of the two paths. If they don't intersect,
// we don't need to iterate through their curves.
if (!path1.getBounds().touches(path2.getBounds()))
return [];
var locations = [],
curves1 = path1.getCurves(),
curves2 = path2.getCurves(),
length2 = curves2.length,
values2 = [], i;
for (i = 0; i < length2; i++)
values2[i] = curves2[i].getValues();
for (i = 0, l = curves1.length; i < l; i++) {
var curve1 = curves1[i],
values1 = curve1.getValues();
var v1Linear = Curve.isLinear(values1);
for (var j = 0; j < length2; j++){
value2 = values2[j];
var v2Linear = Curve.isLinear(value2);
if( v1Linear && v2Linear ){
_getLineLineIntersection(values1, value2, curve1, curves2[j], locations);
} else if ( v1Linear || v2Linear ){
_getCurveLineIntersection(values1, value2, curve1, curves2[j], locations);
} else {
Curve.getIntersections2(values1, value2, curve1, curves2[j], locations);
}
}
}
return locations;
}
/**
* This method is analogous to paperjs#Curve.getIntersections
* @param {[type]} v1
* @param {[type]} v2
* @param {[type]} curve1
* @param {[type]} curve2
* @param {[type]} locations
* @param {[type]} _v1t - Only used for recusion
* @param {[type]} _v2t - Only used for recusion
*/
paper.Curve.getIntersections2 = function( v1, v2, curve1, curve2, locations, _v1t, _v2t, _recurseDepth ) {
_recurseDepth = _recurseDepth ? _recurseDepth + 1 : 1;
// Avoid endless recursion.
// Perhaps we should fall back to a more expensive method after this, but
// so far endless recursion happens only when there is no real intersection and
// the infinite fatline continue to intersect with the other curve outside its bounds!
if( _recurseDepth > MAX_RECURSE ) return;
// cache the original parameter range.
_v1t = _v1t || { t1: 0, t2: 1 };
_v2t = _v2t || { t1: 0, t2: 1 };
var v1t = { t1: _v1t.t1, t2: _v1t.t2 };
var v2t = { t1: _v2t.t1, t2: _v2t.t2 };
// Get the clipped parts from the original curve, to avoid cumulative errors
var _v1 = Curve.getPart( v1, v1t.t1, v1t.t2 );
var _v2 = Curve.getPart( v2, v2t.t1, v2t.t2 );
// markCurve( _v1, '#f0f', true );
// markCurve( _v2, '#0ff', false );
var nuT, parts, tmpt = { t1:null, t2:null }, iterate = 0;
// Loop until both parameter range converge. We have to handle the degenerate case
// seperately, where fat-line clipping can become numerically unstable when one of the
// curves has converged to a point and the other hasn't.
while( iterate < MAX_ITERATE &&
( Math.abs(v1t.t2 - v1t.t1) > TOLERANCE || Math.abs(v2t.t2 - v2t.t1) > TOLERANCE ) ){
++iterate;
// First we clip v2 with v1's fat-line
tmpt.t1 = v2t.t1; tmpt.t2 = v2t.t2;
var intersects1 = _clipBezierFatLine( _v1, _v2, tmpt );
// Stop if there are no possible intersections
if( intersects1 === 0 ){
return;
} else if( intersects1 > 0 ){
// Get the clipped parts from the original v2, to avoid cumulative errors
// ...and reuse some objects.
v2t.t1 = tmpt.t1; v2t.t2 = tmpt.t2;
_v2 = Curve.getPart( v2, v2t.t1, v2t.t2 );
// markCurve( _v2, '#0ff', false );
// Next we clip v1 with nuv2's fat-line
tmpt.t1 = v1t.t1; tmpt.t2 = v1t.t2;
var intersects2 = _clipBezierFatLine( _v2, _v1, tmpt );
// Stop if there are no possible intersections
if( intersects2 === 0 ){
return;
}else if( intersects1 > 0 ){
// Get the clipped parts from the original v2, to avoid cumulative errors
v1t.t1 = tmpt.t1; v1t.t2 = tmpt.t2;
_v1 = Curve.getPart( v1, v1t.t1, v1t.t2 );
}
// markCurve( _v1, '#f0f', true );
}
// Get the clipped parts from the original v1
// Check if there could be multiple intersections
if( intersects1 < 0 || intersects2 < 0 ){
// Subdivide the curve which has converged the least from the original range [0,1],
// which would be the curve with the largest parameter range after clipping
if( v1t.t2 - v1t.t1 > v2t.t2 - v2t.t1 ){
// subdivide _v1 and recurse
nuT = ( _v1t.t1 + _v1t.t2 ) / 2.0;
Curve.getIntersections2( v1, v2, curve1, curve2, locations, { t1: _v1t.t1, t2: nuT }, _v2t, _recurseDepth );
Curve.getIntersections2( v1, v2, curve1, curve2, locations, { t1: nuT, t2: _v1t.t2 }, _v2t, _recurseDepth );
return;
} else {
// subdivide _v2 and recurse
nuT = ( _v2t.t1 + _v2t.t2 ) / 2.0;
Curve.getIntersections2( v1, v2, curve1, curve2, locations, _v1t, { t1: _v2t.t1, t2: nuT }, _recurseDepth );
Curve.getIntersections2( v1, v2, curve1, curve2, locations, _v1t, { t1: nuT, t2: _v2t.t2 }, _recurseDepth );
return;
}
}
// We need to bailout of clipping and try a numerically stable method if
// any of the following are true.
// 1. One of the parameter ranges is converged to a point.
// 2. Both of the parameter ranges have converged reasonably well ( according to TOLERENCE ).
// 3. One of the parameter range is converged enough so that it is *flat enough* to
// calculate line curve intersection implicitly.
//
// Check if one of the parameter range has converged completely to a point.
// Now things could get only worse if we iterate more for the other
// curve to converge if it hasn't yet happened so.
var v1Converged = (Math.abs(v1t.t2 - v1t.t1) < EPSILON),
v2Converged = (Math.abs(v2t.t2 - v2t.t1) < EPSILON);
if( v1Converged || v2Converged ){
var first = locations[0],
last = locations[locations.length - 1];
if ((!first || !point.equals(first._point))
&& (!last || !point.equals(last._point))){
var point = (v1Converged)? curve1.getPointAt(v1t.t1, true) : curve2.getPointAt(v2t.t1, true);
locations.push(new CurveLocation(curve1, null, point, curve2));
}
return;
}
// Check to see if both parameter ranges have converged or else,
// see if either or both of the curves are flat enough to be treated as lines
if( Math.abs(v1t.t2 - v1t.t1) <= TOLERANCE && Math.abs(v2t.t2 - v2t.t1) <= TOLERANCE ){
locations.push(new CurveLocation(curve1, v1t.t1, curve1.getPointAt(v1t.t1, true), curve2));
return;
} else {
var curve1Flat = Curve.isFlatEnough( _v1, /*#=*/ TOLERANCE );
var curve2Flat = Curve.isFlatEnough( _v2, /*#=*/ TOLERANCE );
if ( curve1Flat && curve2Flat ) {
_getLineLineIntersection( _v1, _v2, curve1, curve2, locations );
return;
} else if( curve1Flat || curve2Flat ){
// Use curve line intersection method while specifying which curve to be treated as line
_getCurveLineIntersection( _v1, _v2, curve1, curve2, locations, curve1Flat );
return;
}
}
}
};
/**
* Clip curve V2 with fat-line of v1
* @param {Array} v1 - Section of the first curve, for which we will make a fat-line
* @param {Array} v2 - Section of the second curve; we will clip this curve with the fat-line of v1
* @param {Object} v2t - The parameter range of v2
* @return {number} -> 0 -no Intersection, 1 -one intersection, -1 -more than one intersection
*/
function _clipBezierFatLine( v1, v2, v2t ){
// first curve, P
var p0x = v1[0], p0y = v1[1], p3x = v1[6], p3y = v1[7];
var p1x = v1[2], p1y = v1[3], p2x = v1[4], p2y = v1[5];
// second curve, Q
var q0x = v2[0], q0y = v2[1], q3x = v2[6], q3y = v2[7];
var q1x = v2[2], q1y = v2[3], q2x = v2[4], q2y = v2[5];
// Calculate the fat-line L for P is the baseline l and two
// offsets which completely encloses the curve P.
var d1 = _getSignedDist( p0x, p0y, p3x, p3y, p1x, p1y ) || 0;
var d2 = _getSignedDist( p0x, p0y, p3x, p3y, p2x, p2y ) || 0;
var dmin, dmax;
if( d1 * d2 > 0){
// 3/4 * min{0, d1, d2}
dmin = 0.75 * Math.min( 0, d1, d2 );
dmax = 0.75 * Math.max( 0, d1, d2 );
} else {
// 4/9 * min{0, d1, d2}
dmin = 0.4444444444444444 * Math.min( 0, d1, d2 );
dmax = 0.4444444444444444 * Math.max( 0, d1, d2 );
}
// Calculate non-parametric bezier curve D(ti, di(t)) -
// di(t) is the distance of Q from the baseline l of the fat-line,
// ti is equally spaced in [0,1]
var dq0 = _getSignedDist( p0x, p0y, p3x, p3y, q0x, q0y );
var dq1 = _getSignedDist( p0x, p0y, p3x, p3y, q1x, q1y );
var dq2 = _getSignedDist( p0x, p0y, p3x, p3y, q2x, q2y );
var dq3 = _getSignedDist( p0x, p0y, p3x, p3y, q3x, q3y );
// Find the minimum and maximum distances from l,
// this is useful for checking whether the curves intersect with each other or not.
var mindist = Math.min( dq0, dq1, dq2, dq3 );
var maxdist = Math.max( dq0, dq1, dq2, dq3 );
// If the fatlines don't overlap, we have no intersections!
if( dmin > maxdist || dmax < mindist ){
return 0;
}
var tmp;
if( dq3 < dq0 ){
tmp = dmin; dmin = dmax; dmax = tmp;
}
var Dt = _convexhull( dq0, dq1, dq2, dq3 );
// Calculate the convex hull for non-parametric bezier curve D(ti, di(t))
// Now we clip the convex hulls for D(ti, di(t)) with dmin and dmax
// for the coorresponding t values (tmin, tmax):
// Portions of curve v2 before tmin and after tmax can safely be clipped away
var tmaxdmin = -Infinity, ixd, ixdx, i, len, inv_m;
var tmin = Infinity, tmax = -Infinity, Dtl, dtlx1, dtly1, dtlx2, dtly2;
for (i = 0, len = Dt.length; i < len; i++) {
Dtl = Dt[i];
dtlx1 = Dtl[0]; dtly1 = Dtl[1]; dtlx2 = Dtl[2]; dtly2 = Dtl[3];
if( dtly2 < dtly1 ){
tmp = dtly2; dtly2 = dtly1; dtly1 = tmp;
tmp = dtlx2; dtlx2 = dtlx1; dtlx1 = tmp;
}
// we know that (dtlx2 - dtlx1) is never 0
inv_m = (dtly2 - dtly1) / (dtlx2 - dtlx1);
if( dmin >= dtly1 && dmin <= dtly2 ){
ixdx = dtlx1 + (dmin - dtly1) / inv_m;
if ( ixdx < tmin ) tmin = ixdx;
if ( ixdx > tmaxdmin ) tmaxdmin = ixdx;
}
if( dmax >= dtly1 && dmax <= dtly2 ){
ixdx = dtlx1 + (dmax - dtly1) / inv_m;
if( ixdx > tmax ) tmax = ixdx;
if( ixdx < tmin ) tmin = 0;
}
}
// Return the parameter values for v2 for which we can be sure that the
// intersection with v1 lies within.
if(tmin !== Infinity && tmax !== -Infinity){
var mindmin = Math.min(dmin, dmax);
var mindmax = Math.max(dmin, dmax);
if( dq3 > mindmin && dq3 < mindmax ){
tmax = 1;
}
if( dq0 > mindmin && dq0 < mindmax ){
tmin = 0;
}
if( tmaxdmin > tmax ){ tmax = 1; }
// Debug: Plot the non-parametric graph and hull
// plotD_vs_t( 500, 110, Dt, [dq0, dq1, dq2, dq3], v1, dmin, dmax, tmin, tmax, 1.0 / ( tmax - tmin + 0.3 ) )
// tmin and tmax are within the range (0, 1). We need to project it to the original
// parameter range for v2.
var v2tmin = v2t.t1;
var tdiff = ( v2t.t2 - v2tmin );
v2t.t1 = v2tmin + tmin * tdiff;
v2t.t2 = v2tmin + tmax * tdiff;
// If the new parameter range fails to converge by atleast 20% of the original range,
// possibly we have multiple intersections. We need to subdivide one of the curves.
if( (tdiff - ( v2t.t2 - v2t.t1 ))/tdiff >= 0.2 ){
return 1;
}
}
// TODO: Try checking with a perpendicular fatline to see if the curves overlap
// if it is any faster than this
if( Curve.getBounds( v1 ).touches( Curve.getBounds( v2 ) ) ){
return -1;
}
return 0;
}
/**
* Calculate the convex hull for the non-paramertic bezier curve D(ti, di(t)).
* The ti is equally spaced across [0..1] [0, 1/3, 2/3, 1] for
* di(t), [dq0, dq1, dq2, dq3] respectively. In other words our CVs for the curve are
* already sorted in the X axis in the increasing order. Calculating convex-hull is
* much easier than a set of arbitrary points.
*/
function _convexhull( dq0, dq1, dq2, dq3 ){
var distq1 = _getSignedDist( 0.0, dq0, 1.0, dq3, 0.3333333333333333, dq1 );
var distq2 = _getSignedDist( 0.0, dq0, 1.0, dq3, 0.6666666666666666, dq2 );
// Check if [1/3, dq1] and [2/3, dq2] are on the same side of line [0,dq0, 1,dq3]
if( distq1 * distq2 < 0 ) {
// dq1 and dq2 lie on different sides on [0, q0, 1, q3]
// Convexhull is a quadrilateral and line [0, q0, 1, q3] is NOT part of the convexhull
// so we are pretty much done here.
Dt = [
[ 0.0, dq0, 0.3333333333333333, dq1 ],
[ 0.3333333333333333, dq1, 1.0, dq3 ],
[ 0.6666666666666666, dq2, 0.0, dq0 ],
[ 1.0, dq3, 0.6666666666666666, dq2 ]
];
} else {
// dq1 and dq2 lie on the same sides on [0, q0, 1, q3]
// Convexhull can be a triangle or a quadrilateral and
// line [0, q0, 1, q3] is part of the convexhull.
// Check if the hull is a triangle or a quadrilateral
var dqmin, dqmax, dqapex1, dqapex2;
distq1 = Math.abs(distq1);
distq2 = Math.abs(distq2);
var vqa1a2x, vqa1a2y, vqa1Maxx, vqa1Maxy, vqa1Minx, vqa1Miny;
if( distq1 > distq2 ){
dqmin = [ 0.6666666666666666, dq2 ];
dqmax = [ 0.3333333333333333, dq1 ];
// apex is dq3 and the other apex point is dq0
// vector dqapex->dqapex2 or the base vector which is already part of c-hull
vqa1a2x = 1.0, vqa1a2y = dq3 - dq0;
// vector dqapex->dqmax
vqa1Maxx = 0.6666666666666666, vqa1Maxy = dq3 - dq1;
// vector dqapex->dqmin
vqa1Minx = 0.3333333333333333, vqa1Miny = dq3 - dq2;
} else {
dqmin = [ 0.3333333333333333, dq1 ];
dqmax = [ 0.6666666666666666, dq2 ];
// apex is dq0 in this case, and the other apex point is dq3
// vector dqapex->dqapex2 or the base vector which is already part of c-hull
vqa1a2x = -1.0, vqa1a2y = dq0 - dq3;
// vector dqapex->dqmax
vqa1Maxx = -0.6666666666666666, vqa1Maxy = dq0 - dq2;
// vector dqapex->dqmin
vqa1Minx = -0.3333333333333333, vqa1Miny = dq0 - dq1;
}
// compare cross products of these vectors to determine, if
// point is in triangles [ dq3, dqMax, dq0 ] or [ dq0, dqMax, dq3 ]
var vcrossa1a2_a1Min = vqa1a2x * vqa1Miny - vqa1a2y * vqa1Minx;
var vcrossa1Max_a1Min = vqa1Maxx * vqa1Miny - vqa1Maxy * vqa1Minx;
if( vcrossa1Max_a1Min * vcrossa1a2_a1Min < 0 ){
// Point [2/3, dq2] is inside the triangle and the convex hull is a triangle
Dt = [
[ 0.0, dq0, dqmax[0], dqmax[1] ],
[ dqmax[0], dqmax[1], 1.0, dq3 ],
[ 1.0, dq3, 0.0, dq0 ]
];
} else {
// Convexhull is a quadrilateral and we need all lines in the correct order where
// line [0, q0, 1, q3] is part of the convex hull
Dt = [
[ 0.0, dq0, 0.3333333333333333, dq1 ],
[ 0.3333333333333333, dq1, 0.6666666666666666, dq2 ],
[ 0.6666666666666666, dq2, 1.0, dq3 ],
[ 1.0, dq3, 0.0, dq0 ]
];
}
}
return Dt;
}
// This is basically an "unrolled" version of #Line.getDistance() with sign
// May be a static method could be better!
var _getSignedDist = function( a1x, a1y, a2x, a2y, bx, by ){
var vx = a2x - a1x, vy = a2y - a1y;
var m = vy / vx, b = a1y - ( m * a1x );
return ( by - ( m * bx ) - b ) / Math.sqrt( m*m + 1 );
};
/**
* Intersections between curve and line becomes rather simple here mostly
* because of paperjs Numerical class. We can rotate the curve and line so that
* the line is on X axis, and solve the implicit equations for X axis and the curve
*/
var _getCurveLineIntersection = function( v1, v2, curve1, curve2, locations, _other ){
var i, root, point, vc = v1, vl = v2;
var other = ( _other === undefined )? Curve.isLinear( v1 ) : _other;
if( other ){
vl = v1;
vc = v2;
}
var l1x = vl[0], l1y = vl[1], l2x = vl[6], l2y = vl[7];
// rotate both the curve and line around l1 so that line is on x axis
var lvx = l2x - l1x, lvy = l2y - l1y;
// Angle with x axis (1, 0)
var angle = Math.atan2( -lvy, lvx ), sina = Math.sin( angle ), cosa = Math.cos( angle );
// rotated line and curve values
// (rl1x, rl1y) = (0, 0)
var rl2x = lvx * cosa - lvy * sina, rl2y = lvy * cosa + lvx * sina;
var rvc = [];
for( i=0; i<8; i+=2 ){
var vcx = vc[i] - l1x, vcy = vc[i+1] - l1y;
rvc.push( vcx * cosa - vcy * sina );
rvc.push( vcy * cosa + vcx * sina );
}
var roots = [];
Curve.solveCubic(rvc, 1, 0, roots);
i = roots.length;
while( i-- ){
root = roots[i];
if( root >= 0 && root <= 1 ){
point = Curve.evaluate(rvc, root, true, 0);
// We do have a point on the infinite line. Check if it falls on the line *segment*.
if( point.x >= 0 && point.x <= rl2x ){
// The actual intersection point
point = Curve.evaluate(vc, root, true, 0);
if( other ) root = null;
var first = locations[0],
last = locations[locations.length - 1];
if ((!first || !point.equals(first._point))
&& (!last || !point.equals(last._point)))
locations.push( new CurveLocation( curve1, root, point, curve2 ) );
}
}
}
};
var _getLineLineIntersection = function( v1, v2, curve1, curve2, locations ){
var point = Line.intersect(
v1[0], v1[1], v1[6], v1[7],
v2[0], v2[1], v2[6], v2[7], false);
if (point) {
// Avoid duplicates when hitting segments (closed paths too)
var first = locations[0],
last = locations[locations.length - 1];
if ((!first || !point.equals(first._point))
&& (!last || !point.equals(last._point)))
// Passing null for parameter leads to lazy determination
// of parameter values in CurveLocation#getParameter()
// only once they are requested.
locations.push(new CurveLocation(curve1, null, point, curve2));
}
};

4
fatline/README.md Normal file
View file

@ -0,0 +1,4 @@
------
Harikrishnan Gopalakrishnan

471
fatline/intersectStudy.html Normal file
View file

@ -0,0 +1,471 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Poly-bézier path Intersection Study</title>
<script type="text/javascript" src="../paperjs/lib/prepro.js"></script>
<script type="text/javascript" src="../paperjs/src/load.js"></script>
<script type="text/javascript" src="Intersect.js"></script>
<script type="text/javascript" src="intersectTests.js"></script>
<style>
body { height: 100%; overflow: auto; }
#container { display: block; width: 1000px; margin: 0 auto 50px; }
h1, h3 { font-family: 'Helvetica Neue'; font-weight: 300; margin: 50px 0 20px; }
footer{display: block; width: 1000px; margin: 30px auto; color: #999; }
footer p, footer a { font-family: 'Helvetica Neue'; font-style: italic; font-weight: 300; }
canvas { cursor: crosshair; width: 100%; height: 220px; margin: 5px 0;} canvas.big { height: 400px;}
footer ul{ list-style: none; padding: 0; } footer ul li p, footer ul li a{ font-style: normal; }
footer ul li a{ margin-left: 2em; } canvas.big2 { height: 300px;}
footer ul li.caption p {font-weight: bold; opacity: 0.6; }
.error { color: #a00; } .hide{ display: none; }
</style>
</head>
<body>
<div id="container">
<h1>Cubic bézier fat-line clipping study (using paperjs)</h1>
<button id="testStart" value="Start tests" onClick="runTests();">Start tests</button>
</div>
<footer>
<p>Fat-line clipping and other operations on cubic bézier curves.</p>
<ul>
<li class="caption"><p>References</p></li>
<li><a href="http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf">T. W. Sederberg, T. Nishita Curve intersection using bezier clipping.</a></li>
</ul>
<p>--<br />
hari</p>
</footer>
<svg class="hide" version="1.1" id="svgrandom2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="200px" height="200px" viewBox="0 0 200 200" enable-background="new 0 0 200 200" xml:space="preserve">
</svg>
<svg class="hide" version="1.1" id="svgrandom1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="200px" height="200px" viewBox="0 0 200 200" enable-background="new 0 0 200 200" xml:space="preserve">
<path d="M121.938,15.632c-13.717-12.536 -86.488,106.314 -97.28853,96.70168c-10.79979,-9.61253 74.75206,22.03522 62.05339,14.94206c-12.69866,-7.09316 -39.33589,-120.29063 -50.13215,-122.55235c-10.79626,-2.26173 20.61549,120.92844 6.21122,120.91582c-14.40427,-0.01263 95.8736,-97.47028 79.15607,-110.0072z" />
<path d="M112.56135,26.45534c-11.3324,-19.66938 2.46546,15.5079 -15.74899,1.46029c-18.21444,-14.04761 -66.32694,49.96681 -85.68888,45.03851c-19.36194,-4.9283 25.00762,66.13871 9.65758,51.54906c-15.35004,-14.58966 80.2128,-61.80948 76.57166,-81.27628c-3.64115,-19.4668 26.54102,2.89779 15.20863,-16.77158z" />
</svg>
<svg class="hide" version="1.1" id="glyphsys" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="200px" height="200px" viewBox="0 0 200 200" enable-background="new 0 0 200 200" xml:space="preserve">
<path fill="none" d="M68.836,146.216c8.889,5.698,21.647,10.021,35.324,10.021c20.283,0,32.142-10.689,32.142-26.203
c0-14.122-8.203-22.557-28.949-30.305c-25.072-9.121-40.577-22.343-40.577-43.759c0-23.93,19.829-41.708,49.688-41.708
c15.495,0,27.112,3.646,33.719,7.516l-5.456,16.182c-4.787-2.959-15.031-7.293-28.949-7.293c-20.961,0-28.94,12.536-28.94,23.021
c0,14.354,9.344,21.425,30.536,29.627c25.981,10.03,38.971,22.565,38.971,45.123c0,23.717-17.313,44.444-53.557,44.444
c-14.809,0-30.991-4.546-39.194-10.039L68.836,146.216z"/>
<path fill="none" d="M82.734,183.337v-66.265L33.15,27.158h23.17l22.009,43.104c5.792,11.811,10.66,21.321,15.528,32.207h0.462
c4.17-10.207,9.736-20.396,15.764-32.207l22.473-43.104h22.707l-52.131,89.669v66.51H82.734z"/>
</svg>
<svg class="hide" version="1.1" id="glyphsacirc" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="200px" height="200px" viewBox="0 0 200 200" enable-background="new 0 0 200 200" xml:space="preserve">
<path fill="none" d="M107.585,161.74c-3.868,0-9.281-2.318-12.117-5.156c-3.351-3.35-4.898-6.961-6.186-11.342
c-10.312,6.961-22.688,16.498-30.421,16.498c-18.304,0-30.935-15.211-30.935-31.451c0-12.631,6.703-20.621,20.881-25.52
c15.468-5.157,34.287-12.118,39.958-16.757v-4.383c0-18.818-8.766-29.13-21.913-29.13c-4.898,0-8.765,1.805-11.601,4.898
c-3.093,3.609-5.413,9.281-7.476,17.015c-1.288,4.124-3.868,5.929-7.477,5.929c-4.64,0-11.084-4.898-11.084-11.085
c0-3.609,3.094-6.703,7.991-10.312c6.961-5.156,23.976-14.952,38.67-18.045c7.733,0,15.466,2.321,21.139,6.961
c9.024,7.733,11.601,18.045,11.601,31.708v47.693c0,11.6,4.64,15.467,9.024,15.467c3.094,0,6.7-1.289,9.279-2.836l2.577,6.703
L107.585,161.74z M88.766,96.778c-5.415,2.835-17.788,8.248-23.202,10.828c-10.054,4.639-15.725,9.537-15.725,19.076
c0,13.146,10.31,19.592,18.303,19.592c6.701,0,15.725-4.383,20.623-9.279V96.778z"/>
<circle fill="none" cx="112.681" cy="105.821" r="52.076"/>
</svg>
<svg class="hide" version="1.1" id="svggears" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="200px" height="200px" viewBox="0 0 200 200" enable-background="new 0 0 200 200" xml:space="preserve">
<path fill="none" d="M127.11,135.58c0.899,0.19,2.568,0.312,3.713,0.269l1.001-0.038c1.145-0.043,2.215-1.005,2.381-2.138
l0.588-5.705c0.071-1.142-0.778-2.305-1.888-2.585l-0.956-0.242c-1.11-0.279-2.77-0.509-3.689-0.509s-1.724-0.936-1.785-2.077
l-0.674-6.489c-0.181-1.13,0.407-2.211,1.305-2.401c0.899-0.191,2.475-0.76,3.5-1.266l0.901-0.441
c1.026-0.505,1.617-1.819,1.311-2.923l-1.762-5.453c-0.397-1.072-1.644-1.791-2.771-1.597l-1.005,0.176
c-1.127,0.194-2.737,0.66-3.578,1.034c-0.84,0.375-1.954-0.152-2.475-1.172l-3.263-5.647c-0.625-0.958-0.525-2.186,0.221-2.728
c0.744-0.542,1.954-1.704,2.687-2.582l0.641-0.769c0.734-0.879,0.735-2.318,0.004-3.198l-3.842-4.259
c-0.8-0.817-2.232-0.964-3.184-0.327l-0.823,0.552c-0.95,0.637-2.232,1.718-2.849,2.402c-0.615,0.685-1.849,0.655-2.737-0.064
l-5.276-3.833c-0.96-0.623-1.37-1.785-0.908-2.583c0.459-0.797,1.092-2.35,1.403-3.451l0.275-0.974
c0.313-1.101-0.271-2.417-1.296-2.925l-5.237-2.329c-1.064-0.42-2.433,0.027-3.042,0.996l-0.536,0.853
c-0.609,0.968-1.34,2.476-1.624,3.35c-0.285,0.874-1.421,1.346-2.525,1.047l-6.383-1.349c-1.13-0.18-1.976-1.075-1.879-1.989
c0.096-0.914,0.042-2.588-0.121-3.72l-0.141-0.983c-0.163-1.132-1.229-2.122-2.371-2.199c0,0-1.201-0.081-2.866-0.081
c-1.669,0-2.876,0.081-2.876,0.081c-1.141,0.077-2.208,1.067-2.371,2.199l-0.141,0.982c-0.163,1.132-0.217,2.807-0.121,3.721
c0.096,0.914-0.75,1.81-1.879,1.99l-6.383,1.35c-1.105,0.298-2.241-0.173-2.525-1.046c-0.284-0.874-1.015-2.381-1.624-3.35
l-0.537-0.854c-0.609-0.969-1.978-1.417-3.041-0.996l-5.238,2.331c-1.024,0.508-1.608,1.825-1.295,2.925l0.275,0.973
c0.313,1.1,0.945,2.653,1.406,3.452c0.46,0.798,0.052,1.96-0.907,2.583l-5.278,3.834c-0.889,0.72-2.122,0.75-2.737,0.065
c-0.616-0.684-1.897-1.765-2.848-2.402L36.61,82.52c-0.951-0.637-2.384-0.49-3.185,0.327l-3.841,4.26
c-0.73,0.881-0.729,2.32,0.004,3.199l0.641,0.768c0.733,0.878,1.943,2.041,2.688,2.582c0.746,0.542,0.845,1.77,0.221,2.729
l-3.263,5.649c-0.52,1.019-1.633,1.547-2.473,1.173c-0.841-0.374-2.45-0.84-3.577-1.035l-1.006-0.175
c-1.127-0.196-2.375,0.522-2.771,1.596l-1.762,5.455c-0.306,1.102,0.285,2.417,1.312,2.921l0.899,0.441
c1.027,0.505,2.602,1.074,3.5,1.265c0.899,0.191,1.487,1.271,1.306,2.401c0,0-0.784,4.917-0.784,8.558c0,0.003,0,0.003,0,0.003
c0,0.004-0.751,0.007-1.671,0.007s-2.579,0.23-3.688,0.509l-0.959,0.242c-1.109,0.28-1.958,1.443-1.887,2.586l0.59,5.706
c0.166,1.132,1.237,2.093,2.38,2.137l1.001,0.037c1.144,0.043,2.814-0.078,3.713-0.269c0.898-0.19,1.877,0.557,2.175,1.662
l2.015,6.205c0.412,1.067,0.062,2.246-0.778,2.621c-0.84,0.373-2.263,1.258-3.163,1.965l-0.796,0.626
c-0.9,0.706-1.2,2.114-0.667,3.126l2.872,4.963c0.615,0.966,1.986,1.406,3.049,0.981l0.926-0.372
c1.062-0.425,2.541-1.218,3.287-1.758c0.746-0.542,1.945-0.258,2.665,0.631l4.365,4.848c0.808,0.81,0.966,2.031,0.35,2.716
s-1.557,2.071-2.091,3.083l-0.463,0.877c-0.534,1.012-0.239,2.424,0.655,3.137l4.633,3.378c0.951,0.637,2.38,0.486,3.178-0.334
l0.708-0.729c0.797-0.821,1.826-2.145,2.287-2.943c0.46-0.797,1.67-1.023,2.689-0.502l5.959,2.653
c1.067,0.412,1.708,1.462,1.425,2.335c-0.283,0.875-0.578,2.522-0.654,3.665l-0.068,1.012c-0.076,1.141,0.768,2.307,1.876,2.589
l5.611,1.181c1.128,0.189,2.374-0.535,2.769-1.609l0.343-0.933c0.395-1.074,0.796-2.701,0.892-3.614
c0.097-0.914,1.108-1.589,2.249-1.499c0,0,1.458,0.114,3.26,0.114c1.805,0,3.271-0.115,3.271-0.115
c1.141-0.09,2.152,0.584,2.248,1.497c0.097,0.914,0.498,2.541,0.892,3.614l0.344,0.935c0.394,1.073,1.64,1.798,2.769,1.608
l5.61-1.182c1.108-0.282,1.953-1.448,1.876-2.59l-0.067-1.009c-0.077-1.143-0.372-2.791-0.656-3.665s0.358-1.926,1.425-2.337
l5.958-2.656c1.019-0.521,2.228-0.296,2.689,0.501c0.46,0.799,1.489,2.122,2.287,2.943l0.708,0.729
c0.799,0.82,2.227,0.97,3.178,0.334l4.632-3.379c0.895-0.714,1.188-2.125,0.655-3.137l-0.462-0.877
c-0.534-1.011-1.477-2.398-2.092-3.082c-0.617-0.686-0.46-1.907,0.349-2.718l4.364-4.848c0.719-0.89,1.918-1.175,2.663-0.634
c0.745,0.543,2.224,1.333,3.286,1.758l0.927,0.373c1.063,0.425,2.435-0.017,3.05-0.981l2.87-4.963
c0.532-1.014,0.231-2.42-0.668-3.127l-0.795-0.625c-0.899-0.706-2.323-1.591-3.164-1.966c-0.84-0.374-1.19-1.554-0.778-2.621
l2.013-6.206C125.234,136.137,126.212,135.39,127.11,135.58z"/>
<path fill="none" d="M175.403,87.286c0.899,0.19,2.568,0.311,3.713,0.268l1.002-0.038c1.145-0.042,2.215-1.005,2.381-2.137
l0.587-5.705c0.072-1.141-0.777-2.305-1.888-2.585l-0.956-0.242c-1.109-0.279-2.769-0.509-3.689-0.509
c-0.919,0-1.723-0.935-1.785-2.077l-0.673-6.489c-0.181-1.13,0.406-2.211,1.305-2.401c0.898-0.192,2.474-0.76,3.5-1.266l0.901-0.442
c1.025-0.504,1.616-1.819,1.311-2.922l-1.763-5.453c-0.396-1.073-1.644-1.792-2.771-1.596l-1.004,0.175
c-1.127,0.195-2.738,0.66-3.579,1.035c-0.839,0.375-1.954-0.152-2.474-1.171l-3.264-5.648c-0.624-0.958-0.524-2.186,0.221-2.728
c0.744-0.542,1.954-1.704,2.688-2.582l0.64-0.769c0.734-0.879,0.735-2.318,0.005-3.198l-3.842-4.26
c-0.801-0.816-2.233-0.964-3.184-0.327l-0.823,0.552c-0.951,0.637-2.233,1.718-2.849,2.402s-1.849,0.655-2.737-0.064l-5.277-3.833
c-0.96-0.623-1.37-1.785-0.908-2.583c0.46-0.797,1.092-2.35,1.404-3.451l0.275-0.974c0.312-1.101-0.271-2.417-1.296-2.925
l-5.237-2.329c-1.063-0.42-2.434,0.027-3.042,0.996l-0.536,0.853c-0.608,0.968-1.34,2.476-1.624,3.35
c-0.285,0.875-1.421,1.346-2.524,1.048l-6.384-1.349c-1.13-0.18-1.976-1.075-1.879-1.989c0.096-0.914,0.042-2.588-0.121-3.72
l-0.142-0.983c-0.162-1.132-1.229-2.122-2.369-2.199c0,0-1.202-0.081-2.867-0.081c-1.669,0-2.876,0.082-2.876,0.082
c-1.142,0.077-2.209,1.066-2.371,2.199l-0.142,0.982c-0.161,1.132-0.217,2.807-0.121,3.721c0.097,0.914-0.749,1.81-1.879,1.99
l-6.384,1.351c-1.105,0.298-2.24-0.173-2.524-1.046c-0.284-0.874-1.016-2.381-1.623-3.35l-0.538-0.854
c-0.607-0.969-1.978-1.417-3.04-0.996l-5.238,2.33c-1.024,0.509-1.608,1.825-1.295,2.926l0.275,0.973
c0.313,1.1,0.945,2.653,1.406,3.452c0.46,0.797,0.052,1.96-0.907,2.583l-5.278,3.834c-0.889,0.72-2.122,0.75-2.737,0.065
c-0.616-0.684-1.897-1.765-2.848-2.402l-0.823-0.553c-0.951-0.637-2.384-0.49-3.185,0.327l-3.841,4.261
c-0.73,0.881-0.729,2.32,0.004,3.199l0.641,0.768c0.733,0.878,1.943,2.041,2.688,2.582c0.746,0.542,0.845,1.77,0.221,2.729
l-3.263,5.649c-0.52,1.019-1.633,1.547-2.473,1.173c-0.841-0.374-2.45-0.84-3.577-1.035l-1.006-0.175
c-1.127-0.196-2.375,0.522-2.771,1.595l-1.762,5.455c-0.306,1.102,0.285,2.417,1.312,2.921l0.899,0.442
c1.027,0.504,2.602,1.074,3.5,1.265c0.899,0.19,1.487,1.271,1.306,2.401c0,0-0.784,4.917-0.784,8.557c0,0.003,0,0.003,0,0.003
c0,0.003-0.751,0.007-1.671,0.007s-2.579,0.23-3.688,0.509L66.496,77.1c-1.109,0.28-1.958,1.442-1.887,2.585l0.59,5.706
c0.166,1.132,1.237,2.094,2.38,2.136l1.001,0.038c1.144,0.043,2.814-0.078,3.713-0.269c0.898-0.19,1.877,0.556,2.175,1.661
l2.015,6.206c0.412,1.067,0.062,2.247-0.778,2.621c-0.84,0.373-2.263,1.258-3.163,1.964l-0.796,0.625
c-0.9,0.706-1.2,2.114-0.667,3.128l2.872,4.962c0.615,0.966,1.986,1.405,3.049,0.981l0.926-0.372
c1.062-0.426,2.541-1.217,3.287-1.758c0.746-0.542,1.945-0.258,2.665,0.63l4.365,4.848c0.808,0.81,0.966,2.031,0.35,2.718
c-0.616,0.684-1.557,2.069-2.091,3.083l-0.463,0.877c-0.534,1.011-0.239,2.424,0.655,3.137l4.633,3.376
c0.951,0.637,2.38,0.487,3.178-0.334l0.708-0.729c0.797-0.82,1.826-2.144,2.287-2.941c0.46-0.799,1.67-1.025,2.689-0.503
l5.959,2.653c1.066,0.412,1.708,1.462,1.426,2.336c-0.285,0.874-0.579,2.522-0.655,3.664l-0.068,1.011
c-0.076,1.142,0.769,2.308,1.877,2.59l5.611,1.182c1.129,0.188,2.374-0.536,2.769-1.61l0.343-0.933
c0.396-1.074,0.797-2.701,0.892-3.614c0.097-0.915,1.108-1.59,2.249-1.5c0,0,1.458,0.114,3.26,0.114
c1.805,0,3.271-0.114,3.271-0.114c1.142-0.09,2.152,0.583,2.249,1.498c0.096,0.912,0.497,2.54,0.893,3.614l0.343,0.933
c0.395,1.074,1.641,1.798,2.769,1.61l5.61-1.182c1.109-0.283,1.954-1.449,1.876-2.59l-0.066-1.009
c-0.076-1.144-0.373-2.792-0.655-3.666c-0.284-0.875,0.356-1.927,1.424-2.337l5.96-2.656c1.018-0.521,2.228-0.296,2.688,0.502
c0.459,0.798,1.488,2.121,2.286,2.941l0.709,0.731c0.798,0.82,2.227,0.968,3.177,0.334l4.633-3.379
c0.895-0.716,1.188-2.126,0.654-3.137l-0.462-0.877c-0.533-1.011-1.477-2.399-2.092-3.083c-0.616-0.687-0.46-1.908,0.349-2.718
l4.364-4.847c0.719-0.891,1.918-1.176,2.664-0.635c0.744,0.542,2.223,1.334,3.286,1.758l0.927,0.372
c1.062,0.426,2.434-0.016,3.049-0.979l2.87-4.965c0.532-1.013,0.232-2.419-0.668-3.125l-0.795-0.626
c-0.899-0.706-2.323-1.592-3.163-1.966s-1.191-1.554-0.778-2.621l2.012-6.206C173.528,87.844,174.506,87.095,175.403,87.286z"/>
</svg>
<svg class="hide" version="1.1" id="svggreenland" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="200px" height="200px" viewBox="0 0 200 200" enable-background="new 0 0 200 200" xml:space="preserve">
<path fill="none" d="M172.189,76.894c-0.651,0.691-2.171,0.642-3.206,0.797c-0.596,0.087-1.085,0.335-1.678,0.422
c-0.75,0.111-1.668-0.134-2.337,0.133c0.275,0.186,0.555,0.276,0.84,0.27c-0.22,0.446-1.029,0.344-1.575,0.335
c-0.67-0.016-1.193,0.186-1.808,0.273c-1.274,0.18-2.74-0.13-4.092-0.149c-0.53-0.006-0.801,0.35-1.287,0.434
c-0.604,0.102-1.296,0.062-1.979,0.006c-1.745-0.139-3.273-0.006-4.852,0.183c1.095,0.127,1.975-0.118,2.954-0.205
c0.875-0.074,1.857,0.074,2.797,0.164c2.257,0.217,4.241-0.288,6.573,0.174c-1.358,0.654-2.937,0.788-4.729,0.806
c-1.193,0.009-2.533-0.254-3.695-0.195c-0.8,0.041-1.38,0.397-2.155,0.471c0.794,0.137-0.183,0.409-0.418,0.617
c0.657-0.022,0.958,0.263,1.605,0.056c-0.821,0.133,0.258-0.456,0.543-0.515c0.555-0.115,1.19-0.103,1.811-0.093
c1.169,0.019,2.533-0.635,3.882,0.105c-1.253,0.515-2.348,0.654-3.956,0.624c-0.887-0.019-0.89,0.313-1.451,0.573
c-0.195,0.09,0.167,0.192,0.09,0.307c-0.111,0.18-0.279,0.326-0.499,0.434c0.666,0.049,0.921-0.366,1.792-0.192
c-0.195,0.292-0.385,0-0.707,0.084c-0.267,0.068-0.348,0.282-0.614,0.35c-0.418,0.108-0.8-0.019-0.911,0.341
c-0.121,0.387-0.871,0.248-1.37,0.189c-0.556-0.068-1.032,0.118-1.491,0.202c1.026,0.074-0.258,0.362-0.416,0.434
c0.232-0.087,0.496-0.05,0.791,0.108c-0.248,0.09-0.837,0.359-0.731,0.645c0.167,0.446-0.58,0.381-0.971,0.409
c0.254,0.019,0.505,0.037,0.76,0.056c-0.593,0.26-1.163,0.558-1.51,1.001c0.181,0,1.371,0.042,1.148,0.226
c0.434-0.215,0.578-0.676,1.108-0.846c0.533-0.17,1.125,0.043,1.764,0.118c0.134,0.015,0.327,0.024,0.541,0.035
c-0.269-0.055-0.539-0.119-0.808-0.211c0.633-0.081,2.053-0.068,2.729,0.406c-0.084-0.005-0.168-0.01-0.251-0.014
c0.397,0.09,0.74,0.225,0.911,0.448c-1.447,0.09-3.175-0.465-4.479-0.108c0.449-0.041,1.104,0.031,1.603,0.245
c-0.146-0.021-1.364-0.031-0.359,0.109c-0.462,0.059-1.002-0.075-1.482-0.056c0.794,0.103,1.56,0.105,2.362,0.245
c-0.028,0.006-0.062,0.004-0.092,0.008c0.447-0.001,0.89,0.038,1.187,0.203c0.366,0.201,0.831,0.416,1.166,0.208
c0.679-0.421,3.045,0.068,2.154,0.946c-0.449,0.45-2.089,0.09-2.88-0.034c-1.259-0.192-2.747-0.434-3.776-0.14
c0.229-0.043,0.483-0.019,0.757,0.081c-0.238,0.155-0.595,0.158-0.979,0.127c0.132,0.02,0.264,0.043,0.401,0.09
c-0.552,0.155-1.259,0.515-1.996,0.366c-0.413-0.083-0.8-0.496-1.24-0.462c-0.189,0.016-0.819,0.363-0.905,0.478
c0.288,0.019,0.579,0.17,0.769,0.378c0.124-0.394,1.33-0.146,0.686-0.056c0.214-0.074,0.462-0.056,0.744,0.056
c-0.224,0.034-0.44,0.077-0.648,0.136c0.22-0.05,0.462-0.068,0.723-0.056c-0.446,0.232-1.303-0.14-1.702,0.136
c0.558-0.012,1.28-0.152,1.916,0.161c-0.05,0.103-0.103,0.202-0.161,0.298c0.549,0.09,0.908-0.152,1.451-0.081
c0.515,0.068,1.051,0.369,1.54,0.325c-0.533-0.09-1.075-0.332-1.611-0.406c0.312-0.056,0.667-0.029,1.029,0.011
c-0.197-0.048-0.394-0.088-0.593-0.147c0.245,0.011,0.498,0.082,0.75,0.162c0.436,0.052,0.877,0.117,1.274,0.095
c0.657-0.037,1.256,0.493,0.432,0.484c-0.475-0.006-0.901,0.084-1.343,0.156c0.807,0.056,1.61,0.223,2.347,0.646
c-0.087,0.053-0.174,0.108-0.26,0.161c0.629,0.245,0.691,0.85,0.437,1.11c-0.264,0.272-0.877,0.232-1.383,0.108
c0.224-0.527-1.984-0.351-2.428-0.487c-0.89-0.276-2.093-0.915-2.855-0.651c0.54,0.083,1.11,0.118,1.628,0.462
c-0.518-0.1-0.974-0.034-1.473-0.081c1.293,0.251,2.602,0.121,3.879,0.865c-0.71,0.217-1.659,0.071-2.385,0.282
c-0.691,0.192-1.199-0.279-1.912-0.307c0.703,0.056,1.156,0.571,1.891,0.443c0.713-0.133,1.314-0.313,2.161-0.226
c-0.158,0.22-0.499,0.511,0.04,0.784c-0.254,0.152-0.62,0.183-0.979,0.199c0.735,0.081,1.38-0.295,2.151-0.043
c0.775,0.254,1.266-0.009,1.947-0.031c0.016,0.316,0.53,0.468,0.865,0.447c-0.57,0.257-0.998,0.629-1.82,0.573
c-0.288-0.019-0.583,0.006-0.88-0.081c-0.264-0.074-0.574-0.394-0.847-0.394c-0.896,0-1.798-0.034-2.691-0.019
c-0.471,0.006-0.861-0.341-1.271-0.304c0.285,0.078,0.561,0.229,0.74,0.422c-0.396,0.22-1.026,0.297-1.618,0.22
c0.279,0.021,0.546,0.102,0.8,0.248c-0.077,0.316-0.552,0.226-0.896,0.297c1.094,0.223,1.37,0.208,1.562,0.989
c0.778-0.118-0.81-0.937,0.316-0.946c1.007-0.006,2.198,0.381,3.249,0.403c0.062,0.291-0.338,0.394-0.412,0.632
c-0.105,0.35,0.248,0.391-0.45,0.431c-0.85,0.049-1.637-0.143-2.35,0.111c-1.736,0.62-3.37,0.103-5.513-0.508
c0.062-0.468,1.072-0.267,1.597-0.158c0.955,0.198,1.711,0.313,2.521,0.108c-0.971,0.016-1.699,0.003-2.737-0.205
c-0.698-0.143-1.612-0.359-2.093-0.065c-0.372,0.229-0.633,0.642-1.374,0.294c-0.471-0.223-1.413-0.859-1.882-0.667
c0.623,0.391,1.634,0.66,2.325,0.939c-0.545,0.043-1.178-0.003-1.612,0.192c-0.428,0.189-0.669,0.403-1.265,0.431
c-0.645,0.028-1.392-0.18-2.068-0.22c-0.514-0.031-1.19-0.524-1.611-0.304c0.747,0.146,1.491,0.412,2.204,0.397
c-0.264,0.313-0.555,0.381-1.172,0.267c-0.53-0.103-0.939,0.068-1.43,0.053c0.478-0.009,0.694,0.406,0.311,0.496
c0.425,0.034,0.502-0.254,0.771-0.378c0.372-0.167,1.11-0.021,1.572-0.124c0.666-0.149,1.305-0.037,2.086,0.105
c0.487,0.09,0.943-0.009,1.442,0.174c-0.189,0.341-0.747,0.307-1.231,0.347c-0.471,0.037-0.809,0.245-1.283,0.279
s-1.001-0.205-1.485-0.205c-0.539,0-1.051,0.053-1.603,0.025c0.766,0.254,1.389,0,2.143,0.173c-0.189,0.078-0.403,0.127-0.636,0.149
c0.354,0,0.716,0.009,1.051-0.025c-0.059,0.093-0.124,0.183-0.192,0.273c0.623-0.214,3.061-1.014,3.91,0.013
c0.459,0.558-2.288,0.465-2.604,0.456c0.385,0.118,0.707,0.041,1.054,0.05c0.022,0.201-0.077,0.372-0.267,0.471
c0.784-0.078,1.032-0.704,2.034-0.471c0.589,0.139,1.628,0.583,2.124,0.396c0.117,0.385,0.84,0.254,1.383,0.533
c0.452,0.233,1.02,0.031,1.568,0.335c-0.418,0.041-1.256,0.208-1.243,0.592c0.372-0.117,0.753-0.354,1.274-0.223
c-0.239,0.034-0.359,0.161-0.229,0.372c0.396-0.307,0.942-0.332,1.554-0.322c-0.85,0.137-1.414,0.369-1.237,1.092
c0.518-0.41,0.914-0.559,1.845-0.372c-0.438,0.065-0.409,0.13,0.077,0.198c-0.183,0.071-0.385,0.121-0.604,0.148
c0.248-0.037,0.446,0.057,0.521,0.273c-0.409-0.162-0.883,0.186-1.19,0.244c0.329,0.01,0.639-0.024,0.955-0.049
c-0.071,0.084-0.143,0.167-0.214,0.248c0.217-0.034,0.449-0.028,0.701,0.024c-0.264,0.099-0.248,0.524-0.701,0.372
c0.248,0.043,0.496,0.111,0.738,0.199c-0.276-0.016-0.425,0.117-0.403,0.322c0.868-0.105-0.028,0.924-0.509,0.369
c-0.275-0.314-1.534,0.223-1.146-0.816c-0.747-0.31-0.195,0.57-0.376,0.757c-0.278,0.298-1.444,0.081-1.925-0.024
c-0.858-0.193-1.705-0.326-1.876-1.095c-0.093-0.419-1.014-1.023-1.553-0.986c-0.939,0.065-1.777-0.495-2.731-0.558
c-0.348-0.021-0.754-0.171-1.082-0.148c-0.248,0.018-0.366,0.158-0.599,0.188c-0.564,0.068-1.541-0.58-2.14-0.788
c-0.8-0.282-1.516-0.359-2.354-0.639c0.354,0.109,0.524,0.307,0.376,0.496c0.449-0.012,0.917-0.015,1.407,0.075
c-0.934-0.09,0.937,0.403,1.2,0.443c-0.075,0.153-0.278,0.237-0.534,0.288c0.245,0.006,1.548,0.002,0.757,0.184
c0.701,0,1.442,0.102,2.143,0.107c0.422,0.007,0.8-0.102,1.253-0.018c0.26,0.049,0.731,0.17,0.868,0.406
c0.251,0.418-0.546,0.053-0.571,0.226c-0.08,0.593-2.188,0.7-2.954,0.714c-0.406,0.006-0.952,0.102-1.396-0.152
c-0.282-0.164-0.57-0.416-0.884-0.344c0.131,0.188,0.369,0.338,0.627,0.396c-0.425,0.123-1.135,0.096-1.678-0.025
c1.433,0.348,0.391,0.599,0.065,0.949c-0.329,0.354-1.427,0.375-2.071,0.338c0.438,0.223,1.417,0.034,1.742-0.068
c0.276-0.087,0.276,0.229,0.596,0.254c0.338,0.025,0.636-0.021,0.945-0.049c0.02-0.002,0.045-0.006,0.065-0.008
c-0.244-0.02-0.489-0.062-0.735-0.154c0.267-0.064,0.189-0.347,0.465-0.394c0.192-0.028,0.379-0.059,0.562-0.096
c0.567-0.14,0.964-0.456,1.581-0.549c0.651-0.097,1.321-0.022,1.926-0.204c0.356-0.112,0.747-0.225,1.188-0.218
c-0.01,0.075-0.016,0.149-0.021,0.224c0.399-0.047,1.215,0.471,0.576,0.521c0.14,0.074,0.276,0.149,0.412,0.224
c-1.078,0.362-2.378,0.285-3.615,0.381c-0.026,0.002-0.054,0.007-0.079,0.01c0.418,0.01,0.821,0.079,1.152,0.275
c-0.362,0.311-0.967,0.177-1.525,0.224c-0.412,0.034-0.738,0.198-1.061,0.338c-0.521,0.229-1.854,0.285-2.576,0.204
c0.57,0.205,1.581,0.208,2.064,0.134c0.556-0.084,0.894,0.255,1.297-0.158c0.515-0.54,1.624-0.226,2.468-0.369
c0.645-0.111,1.196-0.437,1.978-0.322c-0.046,0.093-0.103,0.183-0.161,0.272c0.636-0.136,1.15-0.17,1.922,0.09
c0.646,0.221,1.256,0.112,1.892,0.252c0.726,0.158,1.56,0.18,2.214,0.114c0.381-0.04,0.995-0.204,1.426,0.087
c-0.446,0.312-1.785,0.44-2.455,0.478c0.227-0.022,0.449,0.024,0.673,0.14c-0.285,0.143-0.683-0.053-1.014-0.14
c0.297,0.425-0.928,0.276-1.203,0.257c0.526-0.002,0.756,0.292,0.384,0.479c-0.248,0.12-0.924-0.041-1.277-0.06
c0.825,0.118-0.006,0.385-0.241,0.403c-0.298,0.019-0.633,0.006-0.952-0.053c0.66,0.428-0.558,0.27,0.27,0.372
c-0.391,0.111-1.022-0.235-1.265,0.071c0.58-0.065,0.369,0.235,0.134,0.272c-0.354,0.056-0.636-0.226-0.354,0.192
c-0.369-0.093-1.34,0.09-0.586,0.071c-0.577,0.103-0.847,0.512-1.504,0.512c-0.311,0-0.348,0.226-0.604,0.285
c-0.341,0.077-0.757-0.016-1.095,0.077c-0.465,0.127-0.961,0.041-1.398,0.174c-0.27,0.084-1.011,0.245-1.357-0.021
c0.105,0.227-0.087,0.35-0.4,0.248c-0.351-0.111-0.493,0.049-0.729,0.124c-0.44,0.136-1.001,0.278-1.594,0.046
c0.348,0.472-0.893,0.373-1.222,0.289c-0.167-0.041-0.797-0.416-0.787-0.158c0.013,0.304-0.366,0.152-0.651,0.195
c0.261,0.003,0.506,0.137,0.633,0.328c-0.288,0.016-0.536,0.094-0.871-0.018c-0.304-0.1-0.533-0.299-0.856-0.311
c0.264,0.077,0.493,0.201,0.683,0.375c-0.704,0.117-1.464,0.062-2.227,0.064c-0.412,0-1.066-0.328-0.439-0.368
c-0.63-0.151-0.992,0.013-1.327-0.562c-0.323,0.242-0.493-0.133-0.694-0.372c0.074,0.255-0.354,0.202-0.158,0.472
c0.13,0.18,0.61,0.248,0.809,0.391c-0.158,0.09-0.359,0.115-0.604,0.071c0.335,0.136,0.772,0.09,0.952,0.419
c-0.406-0.068-0.202,0.217-0.242,0.384c-0.05,0.211-0.8,0.047-1.042,0.128c-0.359,0.12-1.032,0.223-1.305,0.387
c-0.227,0.133-0.164,0.412-0.63,0.313c0.189,0.257,0.056,0.552-0.372,0.421c0.348,0.273-0.102,0.271-0.037,0.521
c0.078,0.316-1.433,0.174-0.766,0.502c-0.483-0.13-0.385,0.242-0.198,0.469c-0.409-0.192-0.683,0.318-0.878,0.418
c0.214-0.496-0.108,0.162-0.301-0.371c-0.198,0.099-0.217,0.285,0.078,0.465c-0.245,0.033-1.575,0.977-1.733,0.303
c-0.223,0.104-0.201,0.283,0.127,0.443c-0.31-0.002-0.647-0.033-0.977-0.129c-0.412-0.121-0.546-0.49-0.831-0.268
c0.519,0.121,0.363,0.4,0.654,0.654c-0.48,0.078-0.617-0.021-0.905,0.273c-0.217,0.223-0.713,0.086-0.971,0.26
c0.022-0.186-0.167-0.354-0.446-0.418c0.189,0.514-0.893,0.232-1.014,0.582c-0.248-0.167-0.27-0.35-0.118-0.465
c-0.592-0.037,0.1,0.555-0.415,0.509c-0.378-0.031-1.156-0.362-1.38-0.183c-0.14-0.521,0.862-0.971,1.451-1.002
c-0.734-0.006-1.538-0.18-2.264-0.164c0.242,0.105,0.484,0.168,0.723,0.186c-0.254,0.094-0.121,0.403-0.412,0.443
c-0.359,0.047,0.124,0.184,0.024,0.305c-0.164,0.201-0.781,0.402-1.048-0.072c-0.214,0.292,0.366,0.416,0.686,0.516
c-0.04,0.533-0.596,0.25-0.815,0.536c-0.108-0.394-0.248-0.202-0.645-0.211c0.13,0.077,0.26,0.155,0.391,0.232
c-0.559,0.028-1.104-0.151-1.702-0.304c0.394,0.26,0.062,0.465-0.252,0.422c-0.204-0.028-0.319-0.32-0.555-0.335
c-0.298-0.016-0.177,0.344-0.425,0.375c-0.312,0.04-0.766-0.271-0.691,0.146c0.264,0.043,0.527,0.1,0.797,0.164
c-0.087,0.044-0.17,0.09-0.251,0.14c0.118,0.081,0.235,0.158,0.359,0.233c-0.499-0.105-0.431,0.31-0.865,0.257
c0.744,0.22-0.248,0.384-0.474,0.315c-0.184-0.052-0.503-0.275-0.673-0.229c-0.235,0.064-0.942-0.068-0.992,0.161
c-0.034,0.151,0.13,0.251-0.164,0.282c0.496,0.394,1.454,0.586,1.116,1.092c0.235,0.009,0.424,0.114,0.523,0.287
c-0.388,0.094-0.84-0.148-1.243-0.009c-0.412,0.143-1.179-0.121-1.398,0.211c0.593,0.369,1.141,0.188,1.693,0.226
c0.688,0.047,0.483,0.481,0.096,0.531c0.475,0.084,0.311,0.354,0.499,0.576c-0.478-0.117-0.865,0.016-1.339-0.084
c-0.369-0.074-1.015-0.341-1.179-0.07c0.443-0.078,1.671,0.136,2.006,0.579c-0.121,0.024-0.598-0.111-0.636-0.003
c-0.056,0.174-0.154,0.205-0.443,0.047c0.841,0.514-0.245,0.027-0.399-0.044c0.217,0.248,0.148,0.298-0.211,0.155
c0.26,0.086,0.512,0.198,0.75,0.334c-0.347-0.129-0.694-0.275-1.051-0.355c0.121,0.046,1.203,0.514,1.116,0.586
c-0.227,0.191-1.398-0.426-1.718-0.518c0.025,0.455,0.884,0.176,0.958,0.691c0.038,0.272-0.853-0.137-1.048-0.137
c0.251,0.059,0.493,0.198,0.627,0.378c-0.289,0.084-1.029-0.103-1.309-0.356c-0.059,0.567,1.082,0.186,1.212,0.67
c-0.188-0.062-0.567,0.148-0.757,0.18c-0.468,0.077-0.026,0.05-0.098,0.125c0.011,0.001,0.022,0.003,0.033,0.005
c-0.028,0.011-0.061,0.019-0.089,0.028c-0.042,0.02-0.102,0.042-0.2,0.071c-0.013,0.004-0.03,0.003-0.043,0.007
c-0.189,0.055-0.389,0.098-0.621,0.095c-0.002,0-0.004,0.001-0.006,0.001c-0.001,0-0.001,0-0.002,0
c-0.008-0.066,0.012-0.113,0.042-0.151c0.004-0.005,0.007-0.009,0.011-0.013c0.067-0.072,0.194-0.1,0.346-0.1
c0.008,0,0.015,0,0.022,0c0.072,0.001,0.147,0.006,0.224,0.015c-0.401-0.165-0.707-0.12-1.088-0.173
c0.434,0.08,0.444,0.117,0.028,0.108c0.093,0.074,0.14,0.148,0.137,0.226c-0.028,0.097-0.22,0.104-0.348,0.104
c-0.334-0.004-0.753-0.06-1.116-0.171c0.323,0.186,0.946,0.452,1.281,0.431c0.347-0.025,0.946,0.304,0.319,0.214
c0.229,0.09,0.461,0.174,0.694,0.245c-0.526,0.152-1.298-0.267-1.906-0.312c0.391,0.173,1.206,0.263,1.514,0.526
c0.391,0.338-0.208,0.647-0.404,0.788c0.199-0.051,0.406-0.097,0.617-0.134c0.193,0.192,0.134,0.304-0.148,0.267
c0.815,0.552-0.936,0.311-1.209,0.312c0.416,0.174,0.927,0.332,1.219,0.156c-0.232,0.08-0.211,0.328-0.453,0.396
c-0.313,0.09-0.955-0.028-1.342-0.084c0.418,0.248,0.843,0.154,1.215,0.154c0.49,0.721-1.001,0.487-1.532,0.443
c0.214,0.051,1.376,0.1,0.726,0.246c0.189,0.006,0.375,0,0.549-0.021c-0.105,0.281-0.778,0.111-1.128,0.111
c0.325,0.043,0.654,0.086,0.989,0.154c-0.478,0.279-1.386-0.003-2.028,0.025c0.667,0.167,1.504,0.27,2.071,0.176
c-0.292,0.097-0.232,0.379-0.608,0.406c-0.353,0.028-0.763-0.024-1.163-0.117c0.558,0.201,1.079,0.174,1.628,0.312
c-0.381,0.149-0.999,0.004-1.488-0.046c0.428,0.103,0.815,0.056,1.247,0.18c0.118,0.391-0.524,0.248-0.872,0.224
c0.462,0.108,0.81,0.09,1.129-0.047c-0.087,0.236-0.425,0.242-0.766,0.201c0.211,0.037,0.419,0.06,0.624,0.065
c-0.323,0.103-0.72,0.155-1.15,0.068c0.822,0.208-0.453,0.241-0.806-0.202c-0.118,0.279-0.719,0.143-1.101,0.047
c0.558,0.227,1.085,0.205,1.637,0.335c-0.043,0.161-0.165,0.294-0.338,0.378c0.267-0.053,0.481-0.167,0.766-0.201
c-0.505,0.115,0.13,0.124,0.391,0.379c-0.217-0.022-0.4,0.009-0.54,0.09c0.202-0.041,0.394,0.046,0.53,0.223
c-0.133,0.082-0.307,0.092-0.497,0.073c0.019,0.006,0.034,0.014,0.052,0.021c0.018,0.006,0.033,0.013,0.05,0.02
c0.043,0.018,0.088,0.035,0.123,0.055c0.062,0.035,0.113,0.074,0.142,0.121c-0.288,0.006-0.599-0.103-0.902-0.177
c0.018,0.024,0.017,0.04,0.029,0.062c0.021,0.039,0.044,0.078,0.05,0.107c0.003,0.015-0.003,0.025-0.004,0.039
c-0.002,0.026-0.008,0.051-0.026,0.067c-0.012,0.013-0.029,0.021-0.047,0.029c-0.016,0.006-0.031,0.012-0.05,0.015
c-0.074,0.018-0.166,0.022-0.287,0.002c-0.179-0.03-0.482-0.072-0.512-0.131c-0.014-0.005-0.031-0.01-0.043-0.014
c0.02-0.007,0.039-0.014,0.058-0.021c0.026-0.021,0.083-0.042,0.19-0.066c0.004-0.001,0.008-0.003,0.012-0.004
c-0.025,0.001-0.052-0.007-0.078-0.008c-0.13-0.003-0.261-0.03-0.395-0.077c-0.064-0.021-0.128-0.038-0.194-0.07
c0.002-0.003,0.011-0.005,0.014-0.008c0.083-0.127,0.242-0.171,0.479-0.125c-0.18-0.021-0.36-0.043-0.542-0.068
c0.105-0.117,0.13-0.267,0.077-0.443c0.019,0.229-0.146,0.258-0.44,0.068c0.217,0.385-0.192,0.291-0.416,0.443
c-0.09,0.062-0.608,0.719-0.558,0.155c0,0.229-0.251,0.304-0.478,0c-0.083,0.173-0.322,0.157-0.574-0.022
c0.422-0.387,1.079-0.582,1.495-1.001c-0.58,0.14-1.048,0.617-1.532,0.868c-0.102-0.344,0.391-0.469,0.567-0.676
c0.177-0.205,0.167-0.506,0.434-0.66c-0.617,0.064-0.657,0.619-1.367,0.602c0.037-0.164,0.155-0.298,0.329-0.379
c-0.267,0.078-0.474,0.215-0.741,0.291c0.102-0.21,0.307-0.368,0.617-0.424c-0.49-0.034-0.698,0.207-0.887,0.446
c-0.161-0.388-0.62-0.14-0.177-0.378c-0.344-0.028-0.391,0.264-0.775,0.176c0.223-0.105,0.458-0.204,0.729-0.266
c-0.67,0,0.177-0.336,0.344-0.41c0.232-0.107,0.793,0.004,0.347-0.347c-0.298,0.232-0.592,0.592-1.153,0.577
c0.074-0.057,0.146-0.115,0.214-0.178c-0.527-0.143-0.54,0.391-1.045,0.202c0.174-0.155,0.468-0.202,0.713-0.292
c-0.214-0.016-0.396,0.016-0.542,0.09c0.502-0.502,1.913-0.198,2.173-0.89c-0.235,0.146-0.378,0.316-0.62-0.046
c0.013,0.529-0.8,0.505-1.249,0.713c-0.133-0.396,0.595-0.289,0.713-0.559c-0.124-0.049-0.245-0.102-0.369-0.154
c0.056-0.078,0.121-0.152,0.189-0.224c-0.329-0.021-0.416,0.251-0.803,0.134c0.673,0.086,0.056,0.536-0.434,0.402
c0.515,0.118,0.369,0.199,0.149,0.268c-0.403-0.521-1.026,0.127-1.42,0.09c0.341,0.318-0.105,0.381-0.44,0.22
c0.062-0.068,0.13-0.134,0.199-0.198c-0.729-0.072-1.371,0.009-2.025,0.064c0.338,0.103,0.614,0.047,0.893,0.025
c-0.104,0.152-0.501,0.197-0.927,0.2c0.03,0.008,0.058,0.01,0.089,0.02c-0.021,0.331-0.626,0.413-1.032,0.024
c0.086-0.024,0.177-0.047,0.271-0.064c-0.145-0.009-0.279-0.019-0.376-0.025c0.351-0.198,0.834-0.266,1.228-0.424
c-0.48,0-0.939,0.037-1.414,0.046c0.248-0.136,1.293,0.044,1.088-0.378c-0.248,0.074-0.527,0.183-0.856-0.111
c0.248-0.1,0.341-0.332,0.688-0.336c-0.769-0.105-0.527,0.496-1.008,0.469c0.041-0.074,0.084-0.148,0.127-0.223
c-0.183,0.07-0.577,0.176-0.71-0.156c0.242,0.022,0.412-0.03,0.505-0.154c-0.478-0.111-1.166-0.254-1.43-0.025
c0.162-0.391,0.992-0.355,1.529-0.399c-0.381,0-0.397-0.031-0.053-0.09c-0.698-0.028-1.197,0.44-2.046,0.046
c0.211-0.257,0.937-0.133,1.336-0.201c-0.298-0.006-0.567,0.037-0.88,0c0.031-0.164,0.146-0.297,0.319-0.378
c-0.14,0.093-0.323,0.136-0.549,0.134c-0.09-0.299,0.409-0.496,0.704-0.556c-0.729-0.211-0.589,0.475-1.101,0.512
c0.019-0.084,0.041-0.165,0.059-0.245c-0.502,0.307-0.056-0.285,0.136-0.365c0.232-0.094,0.521-0.174,0.837-0.171
c-0.229,0.013-0.394-0.087-0.44-0.267c-0.282,0.068-0.264,0.328-0.54,0.4c-0.254,0.067-0.629-0.047-0.846,0.067
c0.201-0.13,0.3-0.183-0.143-0.245c0.205-0.154,0.636,0.037,0.853-0.111c-0.22-0.037-0.431-0.053-0.629-0.043
c0.059-0.146,0.226-0.236,0.487-0.202c-0.292-0.05-2.301-0.232-2.208-0.71c0.077-0.406,0.685-0.57,0.958-0.871
c-0.242,0.18-0.543,0.351-0.967,0.356c0.118-0.226,0.347-0.394,0.601-0.533c-0.394-0.028-0.493,0.224-0.707,0.356
c0.037-0.174,0.108-0.328,0.21-0.468c-0.093,0.148-0.759,0.059-0.685-0.174c0.056-0.177,0.694-0.292,0.912-0.362
c-0.356,0.006-0.716,0.006-1.061,0.031c-0.164,0.009-1.029,0.241-0.453-0.053c-0.127,0.102-0.793,0.012-0.626-0.187
c0.094-0.113,0.33-0.133,0.597-0.134c-0.282-0.027-0.575-0.185-0.848-0.17c0.289-0.14,0.71-0.143,1.039-0.245
c-0.27,0.03-0.552,0.046-0.84,0.046c-0.075-0.402,0.905-0.201,1.23-0.312c-0.421,0.025-1.593-0.133-1.448,0.335
c-0.292-0.181-1.138-0.403-0.561-0.49c-0.794,0.128,0.403-0.151,0.499-0.177c0.261-0.074,0.434-0.22,0.694-0.291
c-0.322,0.056-0.672,0.27-1.134,0.09c0.155-0.164,0.006-0.307-0.351-0.379c0.713,0.115,1.401-0.055,1.907-0.223
c0.229-0.074,1.342-0.146,1.625,0c-0.279-0.381-0.793-0.111-1.113-0.155c0.139-0.105,0.267-0.214,0.381-0.335
c-0.53,0.41-1.848,0.915-2.998,0.533c0.133-0.086,0.31-0.13,0.527-0.133c-0.223-0.016-0.443-0.028-0.667-0.043
c0.602-0.137,1.6,0.201,2.003-0.156c-0.837-0.17,0.242-0.331,0.508-0.322c0.413,0.02,0.937,0.09,1.051-0.191
c-0.239,0.108-1.38-0.021-0.726-0.134c-0.254-0.074-0.508-0.158-0.763-0.245c0.124-0.019,1.42-0.009,0.533-0.133
c0.512-0.174,0.632,0.198,1.073,0.468c0.384,0.235,0.89,0.295,1.296,0.4c-0.211-0.45-1.594-0.466-0.89-0.89
c-0.639,0.183-0.149-0.336-0.006-0.4c-0.409,0.124-0.887,0.543-1.532-0.04c-0.051-0.046-0.101-0.101-0.147-0.157
c0.017,0.036,0.039,0.062,0.051,0.107c0.118,0.434-0.676,0.754-1.255,0.691c0.046-0.152,0.18-0.267,0.388-0.313
c-1.377-0.351-1.001,1.349-2.18,1.293c-0.13-0.158-0.422-1.106-0.304-1.209c0.228-0.192,0.685-0.334,1.137-0.45
c0.052-0.052,0.101-0.107,0.141-0.167c-0.508-0.217-0.713,0.178-1.003,0.358c-0.086,0.012-0.336,0.032-0.402-0.166
c-0.003-0.1,0.078-0.143,0.239-0.127c-0.508-0.4-0.239-0.639,0.006-0.834c-0.133,0.08-0.285,0.148-0.45,0.207
c0.025-0.074,0.043-0.151,0.053-0.232c-0.478-0.167-0.493,0.187-0.729,0.279c0.17-0.102,0.006-0.387,0.205-0.465
c0.223-0.053,0.431-0.117,0.623-0.198c0.282-0.171,0.642-0.181,0.847-0.415c0.57-0.648,1.993,0.002,2.93-0.134
c-0.307,0.021-0.403-0.034-0.282-0.161c-0.518,0.09-1.231-0.174-1.767-0.068c-0.422,0.08-0.871,0.183-1.116,0.409
c-0.22,0.204-0.44,0.335-0.843,0.394c-0.198,0.021-0.394,0.05-0.586,0.08c0.155-0.244,0.071-0.307-0.245-0.186
c0.133-0.133,0.242-0.281,0.323-0.443c-0.149,0.152-0.289,0.443-0.757,0.279c0.1-0.087,0.853-0.341,0.109-0.279
c0.214-0.024,0.263-0.143,0.133-0.325c-0.105,0.27-0.524,0.44-1.088,0.187c0.245,0.002,0.428-0.051,0.542-0.165
c-0.164,0.068-0.372,0.084-0.623,0.046c0.372-0.176,0.803-0.27,1.349-0.263c0.074,0,0.713,0.105,0.766,0.067
c0.205-0.145,0.267-0.291,0.62-0.331c0.316-0.037,0.822,0.204,0.552-0.195c-0.341,0.093-0.781,0.127-1.066,0.272
c-0.397,0.199-0.22-0.053-0.654-0.086c-0.598-0.044-0.952,0.535-1.711,0.186c0.147-0.038,0.276-0.092,0.412-0.141
c-0.218,0.074-0.467,0.123-0.809-0.045c0.223,0.012,0.415-0.01,0.577-0.068c-0.217-0.01-0.44-0.035-0.673-0.072
c0.552-0.22,1.392-0.22,1.742-0.604c0.06-0.064,0.154-0.1,0.244-0.139c-0.177,0.053-0.348,0.11-0.495,0.185
c-0.453,0.229-1.066,0.604-1.916,0.372c0.183-0.301,0.75-0.301,1.203-0.372c-0.065,0.003-1.724,0.103-1.352-0.183
c0.174-0.133,0.26-0.348,0.54-0.409c0.121-0.028,1.039,0.03,0.279,0.03c0.502,0.1,1.805,0.031,2.118-0.093
c-0.48,0.075-1.733,0.174-2.375-0.232c0.505-0.167,1.268-0.037,1.789-0.187c-0.332-0.018-0.583,0.094-0.974-0.024
c0.27-0.062,0.664,0,0.803-0.186c-0.22-0.013-0.446-0.034-0.679-0.068c0.388,0.062,0.626-0.065,0.986-0.044
c0.313,0.021,0.691,0.165,0.905,0.044c-0.487-0.077-0.543-0.149-0.177-0.211c-0.479-0.224-1.15-0.11-1.735,0.039
c-0.602-0.031-1.167-0.001-1.843-0.179c0.422,0,0.828-0.019,1.228-0.047c-0.341-0.03-0.651,0.016-1.045-0.164
c0.319,0.01,0.623-0.012,0.868-0.093c-0.363,0.068-0.769,0.108-1.265-0.046c0.236-0.189,0.747-0.109,1.104-0.187
c-0.952-0.022,0.307-0.118,0.391-0.124c0.394-0.031,0.8-0.043,1.19-0.074c0.698-0.057,1.432-0.062,2.127-0.115
c0.744-0.056,0.716,0.059,1.429,0.435c0.487,0.257,1.584-0.06,1.959-0.1c-0.912-0.177-1.56,0.48-2.496-0.394
c0.307-0.016,0.589-0.062,0.84-0.143c-1.101,0.227-2.552-0.01-3.667,0.214c-0.465,0.097-1.054-0.053-1.513,0.028
c-0.391,0.07-0.707,0.211-1.104,0.272c-0.419-0.442,0.312-0.668,0.651-0.776c-0.118,0.022-0.228,0.054-0.373,0.051
c-0.418-0.438,0.602-0.273,0.149-0.604c-0.676-0.452,1.547,0.294,0.471-0.325c0.341,0.13,1.023-0.065,0.267-0.047
c0.217-0.115,0.533-0.137,0.815-0.189c-0.211,0.013-0.44-0.009-0.691-0.068c0.325-0.059,0.717-0.004,1.117,0.063
c-0.134-0.035-0.268-0.071-0.407-0.132c-0.44-0.188-0.607-0.281-1.042-0.281c0.645-0.134,1.56,0.096,2.365,0.257
c-0.27-0.111-0.542-0.198-0.815-0.257c0.453-0.14,1.163,0.183,1.73,0.257c0.524,0.068,1.011,0.047,1.466,0.013
c0.899-0.074,2.089,0.455,2.948,0.312c-0.933-0.059-1.962-0.439-2.933-0.604c0.229-0.115,0.62-0.02,0.945,0
c-0.242-0.068-0.483-0.121-0.722-0.165c0.304-0.03,0.164-0.263,0.366-0.356c0.217-0.1,0.537-0.102,0.75-0.201
c-0.648,0.009-1.101,0.279-1.86,0.139c0.273,0.141,0.527,0.195,0.756,0.162c-0.058,0.177-0.311,0.24-0.614,0.265
c-0.239,0.245-0.831,0.291-1.302,0.321c0.629-0.273-0.14-0.065-0.45-0.164c0.495-0.035,0.987-0.077,1.458-0.143
c-0.29,0.005-0.588-0.004-0.794,0.021c-0.465,0.053-1.705-0.254-1.885,0.027c0.043-0.164,0.223-0.264,0.493-0.258
c-0.604-0.096-1.001,0.105-1.55,0.094c0.319-0.143,0.76-0.18,1.16-0.251c0.149-0.024,1.268-0.261,0.462-0.261
c0.298-0.146,0.757-0.183,1.203-0.164c-0.239-0.021-0.465-0.031-0.685-0.021c0.276-0.199,0.877,0.016,1.184-0.143
c-0.136,0.07-0.294,0.123-0.468,0.164c0.413-0.084,1.023,0.031,1.52,0.062c0.493,0.033,0.722-0.305,1.292-0.156
c-0.48-0.325,0.038-0.396,0.267-0.465c-0.422,0.016-0.695,0.221-1.191,0.14c0.016-0.245,0.465-0.214,0.416-0.465
c-0.053-0.276,0.093-0.503,0.546-0.422c-0.056,0.062-0.118,0.124-0.18,0.187c0.351-0.02,0.859-0.174,1.185,0.257
c0.103-0.114,0.27-0.167,0.505-0.164c-0.248-0.09-0.49-0.143-0.726-0.165c0.143-0.182,0.558-0.083,0.797-0.186
c-0.289-0.04-0.549-0.328-0.784-0.328c-0.53,0-0.62,0.348-1.296,0.214c0.313-0.429,0.996-0.837,1.947-0.723
c-0.468-0.187-0.89,0-1.265,0c-0.288-0.446,0.527-0.288,0.924-0.232c-0.279-0.149-0.527-0.195-0.744-0.143
c0.21-0.276,0.669-0.229,1.184-0.208c-0.053-0.189-0.273-0.332-0.549-0.35c0.121-0.125,0.48-0.141,0.478-0.336
c-0.855-0.024-1.46,0.255-2.356,0.171c0.177-0.05,0.363-0.09,0.558-0.12c-0.536-0.255-0.735,0.023-0.995,0.12
c-0.103,0.034-0.483-0.062-0.62-0.081c-0.837-0.107-1.206-0.006-2.142-0.449c-1.026-0.48-1.888-0.344-2.8-0.49
c-0.664-0.105-1.333-0.449-2.015-0.709c0.375-0.438,1.395-0.41,2.375-0.242c1.054,0.18,1.771-0.115,2.924,0.238
c1.169,0.359,1.885,0.524,2.979,0.695c0.31,0.046,1.101,0.27,1.194,0.07c0.068-0.136-0.022-0.301,0.108-0.418
c-0.214,0.232-0.604,0.388-1.234,0.148c0.862,0.057-0.264-0.167-0.524-0.272c0.356-0.031,0.902-0.04,1.361,0.099
c-0.17-0.077-0.338-0.16-0.505-0.244c0.208-0.031,0.44-0.031,0.691,0c-0.446-0.1-1.417-0.074-1.808-0.273
c0.425-0.006,0.679-0.13,1.209,0.016c0.307,0.087,0.521-0.198,0.124-0.267c-0.366-0.059-0.732-0.062-1.07-0.077
c-0.502-0.021-1.029-0.232-1.569-0.342c0.478-0.365,1.932,0.416,2.394,0c-0.195,0.022-1.625-0.09-0.877-0.272
c-0.54,0.024-1.333,0.295-2.065-0.024c0.298-0.124,0.623-0.227,1.023-0.261c0.496,0.105,0.567,0.019,0.21-0.257
c-0.623,0.077-1.091,0.716-2.049,0.369c0.524-0.081,0.685-0.432,1.203-0.518c0.474-0.081,1.24,0.074,1.562-0.149
c-1.429-0.248-2.508,0.241-3.854,0.173c0.732-0.489,2.639-0.039,3.11-0.719c-0.691-0.14-0.979,0.258-1.603,0.217
c-0.36-0.024-0.742-0.059-1.126-0.096c-0.247,0.165-0.59,0.278-0.979,0.326c-0.31,0.012-0.694-0.233-0.418-0.336
c0.273-0.105,0.819-0.005,1.229-0.006c-0.281-0.027-0.563-0.055-0.836-0.08c0.155-0.255,0.775-0.54,1.101-0.695
c-0.48,0.059-0.989,0.316-1.321,0.496c-0.239-0.624-1.838-1.352-0.651-1.386c-0.366,0-0.744-0.081-0.626,0.248
c0.105,0.301,0.478,0.372,0.766,0.648c0.8,0.772-1.299,0.363-0.53,0.812c-0.229,0.051-0.499-0.009-0.812-0.173
c0.105,0.443,0.837,0.458,0.273,0.713c-0.208,0.093-0.468,0.146-0.75,0.171c-0.617,0.053-1.46-0.007-2.278-0.338
c0.781,0.452-0.18,0.281-0.509,0.055c-0.288-0.197-0.53-0.449-0.905-0.502c0.217-0.325,0.999-0.456,1.578-0.508
c0.905-0.086,1.299-0.332,1.764-0.753c-0.806,0.27-1.079,0.937-2.564,0.521c0.096-0.276,0.632-0.372,0.983-0.483
c0.369-0.118,0.458-0.431,0.945-0.459c-0.75-0.292-1.42,0.173-2.22-0.199c0.682-0.369,2.186,0.09,3.06-0.099
c-0.508-0.056-0.992-0.078-1.522-0.173c0.391-0.118,0.515-0.413,0.893-0.543c-0.13,0.105-0.35,0.112-0.654,0.025
c0.521-0.034,0.534-0.48-0.31-0.669c-0.555-0.127-0.834,0.056-1.513-0.149c0.561,0.146,0.542-0.202,0.871-0.273
c-0.921-0.124,0.13-0.381,0.48-0.27c-0.316-0.257-2.539-0.682-1.851-0.794c-1.011-0.074,0.57-0.074,0.632-0.099
c-0.583-0.04-0.632-0.344-0.254-0.372c-0.217-0.021-1.374-0.282-0.626-0.344c-0.264-0.003-0.552-0.046-0.862-0.124
c0.192-0.086,0.31-0.226,0.341-0.396c-0.753,0.189-1.5,0.44-2.57,0.322c0.676-0.251,1.689-0.217,2.4-0.446
c-0.22,0.049-0.487,0.015-0.81-0.1c0.326-0.034,0.741,0.013,0.921-0.148c-0.326,0.037-0.682,0.062-1.141-0.1
c0.487,0.059,1.082,0.031,1.188-0.22c-0.334,0.115-1.395-0.599-1.758-0.273c-0.322-0.341,0.264-0.26,0.406-0.397
c-0.986-0.505-2.021-0.316-3.042-0.648c0.031-0.074,0.068-0.146,0.108-0.217c-0.536,0.04-0.756-0.419-0.567-0.54
c-0.391-0.016-0.437,0.235-0.955,0.108c0.31-0.121,1.067-0.021,0.896-0.425c-0.196-0.456-1.231-0.282-0.53-0.496
c-0.36-0.009-0.608,0.081-0.974,0.068c-0.292-0.013-1.284-0.344-0.583-0.366c-0.602-0.115-0.868,0.093-1.476-0.028
c0.019-0.083,0.04-0.164,0.071-0.242c-0.195,0.041-0.413,0.068-0.651,0.081c-0.285-0.443-1.531-0.186-1.95-0.245
c-0.028-0.09-0.062-0.18-0.096-0.27c-0.989-0.146-1.771-0.074-2.747-0.202c-0.685-0.09-1.699-0.276-1.829,0.065
c-0.558-0.84-2.917,0.115-3.153,0.108c-0.459-0.443-0.949-0.335-1.321-0.251c-0.164,0.037,0.074,0.242-0.198,0.22
c-0.211-0.041-0.372-0.041-0.493-0.003c-0.118,0.108-0.974-0.053-0.955,0.031c0.068,0.307-0.297,0.434-1.066,0.167
c0.013-0.162,0.112-0.279,0.294-0.354c-1.184-0.344-1.336,0.511-2.074,0.257c-1.172-0.409-1.02-0.227-1.758-0.149
c0.478,0.034,1.101,0.369,1.628,0.487c-0.471,0.254-1.823-0.108-2.635-0.124c-0.375-0.006-0.732,0.003-1.153-0.043
c-0.289-0.031-1.185-0.121-0.577-0.239c-0.676-0.019-1.892-0.22-2.834-0.595c0.363-0.273,1.457-0.484,2.254-0.471
c0.422,0.006,1.95,0.248,1.367-0.289c-1.314,0.115-2.796,0.115-4.57-0.161c-0.099-0.347,0.471-0.536,1.004-0.54
c-1.652-0.359-1.107,1.11-3.32,0.217c0.239-0.012,0.458-0.041,0.651-0.081c-0.335,0.028-0.868-0.115-1.166-0.056
c-1.752-1.2,11.112-0.13,11.815-0.596c-0.989,0.236-2.545-0.031-3.773,0.006c-0.769,0.022-1.656,0.189-2.855-0.223
c0.942-0.18,2.151-0.214,3.308-0.242c0.862-0.022,2.468,0.403,3.128,0.27c-0.387,0.043-1.02-0.384-0.595-0.372
c0.394,0.009,1.008,0.019,1.144-0.143c-1.06-0.701-2.031-0.496-2.48-0.354c-0.679,0.214-1.312,0.428-2.443,0.323
c-0.344-0.031-1.476-0.515-1.364-0.245c0.115,0.282,0.031,0.313-0.406,0.341c-0.915,0.059-2.059-0.006-3.317-0.254
c0.562-0.1,1.46-0.043,1.628-0.381c-0.443,0.22-1.436,0.322-2.496,0.056c0.552-0.068,1.07-0.17,1.492-0.326
c-1.299-0.077-1.907,0.372-3.401,0.137c0.14-0.078,0.292-0.149,0.45-0.217c-0.484,0.053-1.219,0.053-1.95-0.108
c-0.766-0.167-1.609-0.505-2.322-0.595c0.394,0.065,1.705-0.251,0.546-0.406c0.483-0.031,0.363-0.391,0.837-0.428
c0.515-0.041,1.091-0.031,1.557-0.105c0.71-0.118,1.578-0.013,2.344-0.065c0.375-0.028,0.45-0.273,0.818-0.326
C33.521,84,34.023,84,34.432,83.938c0.502-0.078,1.131-0.065,1.671-0.115c0.149-0.013,1.423-0.103,0.223-0.224
c0.782-0.254,2.019-0.195,3.026-0.294c0.769-0.074,1.299-0.242,2.254-0.183c1.714,0.108,2.576-0.137,3.789-0.381
c0.502-0.103,1.107-0.205,1.237-0.518c0.096-0.229-0.4-0.611-0.319-0.85c0.108-0.654,1.63-0.663,2.774-0.626
c-1.813-0.232-2.799,0.326-4.393,0.285c-0.669-0.016-1.445-0.183-2.034-0.124c-0.562,0.056-1.495-0.304-1.984-0.264
c-0.478-0.651,0.707-0.759,1.215-0.874c0.939-0.211,1.885-0.406,2.905-0.564c1.218-0.189,2.009-0.664,3.271-0.828
c0.443-0.059,0.927-0.5,1.78-0.133c0.599,0.257,1.197,0.617,1.789,0.846c-0.434-0.257-1.488-0.741-1.358-0.983
c0.18-0.329,1.057-0.217,1.727-0.18c1.29,0.071,3.181,0.502,3.919,0.115c-0.226-0.112-0.456-0.223-0.682-0.338
c-0.006-0.375,0.735-0.282,0.977-0.505c-1.885-0.211-0.899-1.014-0.323-1.085c0.933-0.108,2.146,0.022,3.274,0.084
c0.456,0.025,1.026-0.103,1.724,0.273c0.645,0.347,0.877,0.425,1.404,0.449c1.188,0.053,2.834,0.583,3.91,0.549
c-0.75-0.139-1.584-0.391-2.35-0.545c-0.502-0.103-0.936-0.037-1.491-0.22c-0.512-0.167-1.107-0.484-1.59-0.586
c-0.524-0.112-0.868-0.037-1.417-0.17c1.625-0.388,3.764-0.357,5.714-0.484c0.726-0.046,1.553,0.046,2.254-0.025
c0.285-0.028,2.453-0.257,1.364-0.201c0.406-0.034,3.808-0.534,4.502,0.511c0.44,0.67-0.552,0.744-0.326,1.314
c0.719,0.1,1.098-0.474,1.578-0.614c0.341-0.096,0.18-0.487,0.502-0.577c0.02-0.005,0.053-0.002,0.077-0.006
c-0.391-0.095-0.782-0.217-1.159-0.394c0.09-0.48,1.156-0.478,2.22-0.037c1.07,0.449,1.609,0.012,2.729,0.545
c-0.38,0.046-0.896,0.1-1.48,0.114c0.773,0.073,1.555,0.147,2.367,0.292c0.974,0.177,2.136,0.639,2.799,0.44
c-1.11-0.381-2.009-0.394-3.131-0.778c1.396,0.223,2.865,0.363,3.714,0.034c-0.735-0.108-1.727-0.208-2.583-0.521
c-0.53-0.192-0.775-0.607-1.355-0.831c1.268-0.152,2.691-0.217,4.347,0.034c1.234,0.186,2.669,0.319,3.975,0.642
c1.386,0.347,2.437,0.223,3.835,0.577c1.681,0.428,3.138,0.66,4.25,0.369c-0.245-0.009-1.358-0.037-0.676-0.304
c-0.279-0.021-0.558-0.043-0.84-0.068c0.162-0.229,0.642-0.195,0.989-0.27c-1.014-0.065-0.319-0.49-0.078-0.533
c0.403-0.078,0.943-0.013,1.46,0.046c1.243,0.143,2.505,0.248,3.575,0.183c-1.268-0.202-2.322-0.109-3.59-0.304
c0.871-0.226-0.54-0.257-0.803-0.294c-0.372-0.056-0.75-0.115-1.129-0.177c-0.75-0.121-1.513-0.26-2.3-0.44
c0.549-0.335,1.833-0.093,2.722-0.105c0.986-0.013,1.975-0.022,2.942-0.053c0.787-0.028,1.671-0.087,2.639,0.121
c0.328,0.068,1.605,1.12,1.203,0.273c-0.184-0.074-0.369-0.14-0.553-0.201c0.553-0.298,2.019-0.01,2.979,0.205
c0.484,0.105,1.058,0.242,1.575,0.515c0.307,0.161,0.797-0.217-0.08-0.316c0.812-0.326-1.768-0.549-2.09-0.558
c-0.952-0.025-1.973-0.14-2.93-0.174c-2.385-0.083-4.664-0.04-7.072-0.146c1.193,0.195-0.208,0.155-0.357,0.158
c-0.425,0.012-0.865,0.009-1.299,0.009c-0.694,0.006-1.429,0.037-2.332-0.236c0.45-0.136,1.193,0.041,1.798,0.068
c-0.542-0.17-1.029-0.223-1.436-0.202c0.607-0.416,2.031-0.096,3.138-0.009c0.93,0.068,1.82,0.093,2.759,0.177
c-1.128-0.198-2.139-0.22-3.333-0.505c1.188,0.146,1.987-0.127,3.119-0.043c1.091,0.081,2.127,0.093,3.19,0.143
c-0.828-0.133-1.503-0.034-2.399-0.27c0.759,0,1.615,0.103,2.279,0c-0.341-0.031-0.67-0.041-0.98-0.034
c0.45-0.229,1.315-0.192,2.043-0.143c0.304,0.021,2.347,0.288,1.33,0.446c1.182-0.272,3.141,0.341,4.526,0.301
c0.607-0.019,1.193-0.037,1.96,0.189c0.492,0.146,1.345,0.449,1.494,0.152c-0.394,0.083-1.005-0.323-1.473-0.372
c0.401-0.112,0.879-0.146,1.375-0.157c-0.121-0.016-0.232-0.019-0.361-0.045c1.327-0.115,2.958,0.103,4.12-0.205
c-0.468,0.056-3.969,0.174-4.384-0.642c1.069,0.102,1.879-0.087,2.803-0.158c0.881-0.068,2.127,0.403,2.974,0.294
c-0.356-0.152-0.691-0.242-1.008-0.27c1.058-0.425,2.933-0.065,4.328-0.121c0.428-0.016,1.141-0.177,1.562-0.115
c0.49,0.071,0.995,0.409,1.398,0.236c-0.205-0.068-0.406-0.137-0.611-0.205c2.06-0.18,4.366-0.021,6.595,0.034
c1.116,0.031,2.168-0.034,3.262-0.034c0.536,0,1.169,0.211,1.718,0.239c0.499,0.025,0.821-0.173,1.407,0
c-0.285-0.012-0.558,0-0.815,0.034c0.268,0.046,2.44,0.121,1.219,0c2.047,0.059,4.037-0.356,6.402,0.438
c-2.982,0.387-6.321,0.239-9.556,0.239c-1.463,0-2.877,0.074-4.244,0.201c-1.354,0.127-2.97-0.133-4.412-0.133
c0.624,0.062,1.185,0.009,1.895,0.27c-2.372,0-4.731,0.037-6.889,0.304c1.004,0.083-0.04,0.264-0.224,0.304
c1.073,0.006,1.848-0.356,2.964-0.341c0.165,0,1.216,0.242,1.287,0.167c0.267-0.273,0.651-0.264,1.185-0.273
c2.183-0.043,4.188-0.093,6.253-0.279c2.385-0.214,5.008,0.016,7.531,0.016c2.03,0,3.983-0.664,6.399,0.167
c-0.788,0.26-1.606,0.49-2.555,0.54c1.634,0.046,2.861-0.716,4.712-0.27c-0.09,0.105-0.186,0.208-0.288,0.304
c1.86-0.202,4.071-0.425,6.337,0.372c-0.523,0.334-1.51,0.304-2.16,0.499c-0.899,0.27-1.963,0.229-3.032,0.235
c-2.195,0.006-4.186,0.344-6.378,0.351c-2.267,0.009-4.632-0.155-6.803,0.006c-0.964,0.071-2.031-0.018-3.087-0.091
c0.244,0.057,0.49,0.132,0.74,0.252c-1.352,0.335-3.004,0.282-4.585,0.304c-0.71,0.012-2.744-0.074-2.469,0.741
c2.999-0.41,6.204-0.537,9.302-0.837c1.621-0.158,3.423-0.093,5.168-0.062c0.965,0.016,2.81-0.338,3.96,0.257
c-0.06,0.778-1.675,0.614-2.453,0.695c-0.979,0.099-2.402-0.031-3.075,0.421c0.288,0.009,0.592,0.065,0.911,0.167
c-0.238,0.031-0.489,0.041-0.753,0.034c1.299,0.183,2.434-0.285,3.581-0.381c1.165-0.093,2.191-0.344,3.407-0.36
c1.008-0.012,0.97-0.716,1.808-0.862c0.731-0.127,1.634-0.102,2.421-0.149c0.375-0.021,2.05,0.016,2.013,0.741
c-0.025,0.459-0.577,0.738-0.955,0.936c-0.651,0.344-1.485,0.478-2.155,0.8c-0.827,0.396-1.581,0.877-2.561,1.101
c1.048-0.031,0.006,0.279-0.158,0.372c0.881-0.229,1.488-0.524,2.248-0.875c0.713-0.326,1.845-0.425,2.657-0.679
c1.829-0.571,3.674-1.058,5.751-1.321c-0.372,0.071-0.741,0.22-0.707,0.607c0.75-0.053,1.352-0.335,2.121-0.359
c0.492-0.019,1.014,0.158,1.528,0.226c0.902,0.121,2.067,0.022,2.666-0.338c-0.998,0.065,0.232-0.257,0.636-0.236
c-0.14-0.111-0.276-0.226-0.412-0.338c2.285-0.186,4.585-0.356,7.034-0.167C168.128,76.345,170.205,76.751,172.189,76.894z"/>
<circle fill="none" cx="99.197" cy="100.656" r="82.295"/>
</svg>
</body>
</html>

826
fatline/intersectTests.js Normal file
View file

@ -0,0 +1,826 @@
paper.install(window);
/**
* http://stackoverflow.com/questions/6875625/does-javascript-provide-a-high-resolution-timer
*/
if (window.performance && window.performance.now) {
console.log("Using high performance timer");
getTimestamp = function() { return window.performance.now(); };
} else {
if (window.performance && window.performance.webkitNow) {
console.log("Using webkit high performance timer");
getTimestamp = function() { return window.performance.webkitNow(); };
} else {
console.log("Using low performance timer");
getTimestamp = function() { return new Date().getTime(); };
}
}
function runTests() {
var caption, pathA, pathB, group, testdata = [], randomtestdata = [], testQueued = 0, testExecuted = 0;
var container = document.getElementById( 'container' );
function runTest(testName, handler) {
var caption = document.createElement('h3');
var canvas = document.createElement('canvas');
caption.appendChild(document.createTextNode(testName));
container.appendChild(caption);
container.appendChild(canvas);
++testQueued;
setTimeout(function() {
console.log('\n' + testName);
paper.setup(canvas);
var paths = handler();
var success = testIntersections(paths[0], paths[1], caption, testName, testdata);
if( !success ){
window.p1 = paths[0].exportSVG();
window.p2 = paths[1].exportSVG();
}
testExecuted++;
if( testExecuted === testQueued ){
plotData();
}
}, 0);
return caption;
}
var caption = document.createElement('h3');
caption.appendChild(document.createTextNode("Randomised tests (may take a while...)"));
container.appendChild(caption);
var canvas = document.createElement('CANVAS');
container.appendChild( canvas );
paper.setup( canvas );
doRandomTests( randomtestdata );
window.d = randomtestdata;
container.removeChild( canvas );
runTest('random', function(){
pathA = getRandomPath(20);
pathB = getRandomPath(20);
return [pathA, pathB];
});
runTest('failcase 1', function(){
group = paper.project.importSVG( document.getElementById( 'svgrandom1' ) );
pathA = group.children[0];
pathB = group.children[1];
pathA.style = pathB.style = null;
return [pathA, pathB];
});
runTest('Overlapping circles', function(){
pathA = new Path.Circle(new Point(80, 110), 50);
pathB = new Path.Circle(new Point(150, 110), 70);
return [pathA, pathB];
});
runTest('Polygon and square', function(){
pathA = new Path.RegularPolygon(new Point(80, 110), 12, 80);
pathB = new Path.Rectangle(new Point(100, 80), [80, 80] );
return [pathA, pathB];
});
runTest('Circle and square (overlaps exactly on existing segments)', function(){
pathA = new Path.Circle(new Point(110, 110), 80);
pathB = new Path.Rectangle(new Point(110, 110), [80, 80] );
return [pathA, pathB];
});
runTest('Circle and square (existing segments overlaps on curves)', function(){
pathA = new Path.Circle(new Point(110, 110), 80);
pathB = new Path.Rectangle(new Point(110, 110), [100, 100] );
return [pathA, pathB];
});
runTest('Square and square (one segment overlaps on a line)', function(){
pathA = new Path.Rectangle(new Point(80, 125), [50, 50] );
pathA.rotate( 45 );
pathB = new Path.Rectangle(new Point(pathA.segments[2].point.x, 110), [80, 80] );
return [pathA, pathB];
});
runTest('Rectangle and rectangle (overlaps exactly on existing curves)', function(){
pathA = new Path.Rectangle(new Point(30.5, 50.5), [100, 150]);
pathB = new Path.Rectangle(new Point(130.5, 60.5), [100, 150]);
return [pathA, pathB];
});
runTest('Overlapping stars 1', function(){
pathA = new Path.Star(new Point(80, 110), 10, 20, 80);
pathB = new Path.Star(new Point(120, 110), 10, 30, 100);
return [pathA, pathB];
});
runTest('Overlapping stars 2', function(){
pathA = new Path.Star(new Point(110, 110), 20, 20, 80);
pathB = new Path.Star(new Point(110, 110), 6, 30, 100);
return [pathA, pathB];
});
runTest('Circle and banana (multiple intersections within same curve segment)', function(){
pathA = new Path.Circle(new Point(80, 110), 80);
pathB = new Path.Circle(new Point(130, 110), 80 );
pathB.segments[3].point = pathB.segments[3].point.add( [ 0, -120 ] );
return [pathA, pathB];
});
runTest('Maximum possible intersections between 2 cubic bezier curve segments - 9', function(){
pathA = new Path();
pathA.add( new Segment( [173, 44], [-281, 268], [-86, 152] ) );
pathA.add( new Segment( [47, 93], [-89, 100], [240, -239] ) );
pathA.closed = true;
pathB = pathA.clone();
pathB.rotate( -90 );
pathA.translate( [-10,0] );
pathB.translate( [10,0] );
return [pathA, pathB];
});
runTest('SVG gears', function(){
group = paper.project.importSVG( document.getElementById( 'svggears' ) );
pathA = group.children[0];
pathB = group.children[1];
return [pathA, pathB];
});
runTest('Glyphs imported from SVG', function(){
group = paper.project.importSVG( document.getElementById( 'glyphsys' ) );
pathA = group.children[0];
pathB = group.children[1];
return [pathA, pathB];
});
runTest('CompoundPaths 1', function(){
group = paper.project.importSVG( document.getElementById( 'glyphsacirc' ) );
pathA = group.children[0];
pathB = group.children[1];
return [pathA, pathB];
});
runTest('CompoundPaths 2 - holes', function(){
group = paper.project.importSVG( document.getElementById( 'glyphsacirc' ) );
pathA = group.children[0];
pathB = new CompoundPath();
group.children[1].clockwise = true;
pathB.addChild(group.children[1]);
var npath = new Path.Circle([110, 110], 30);
pathB.addChild( npath );
return [pathA, pathB];
});
runTest('CompoundPaths 3 !', function(){
group = paper.project.importSVG( document.getElementById( 'svggreenland' ) );
pathA = group.children[0];
pathB = group.children[1];
pathB.scale( 0.5, 1 ).translate( [25.5, 0] );
// pathA.scale( 2 );
// pathB.scale( 2 );
return [pathA, pathB];
});
runTest('CompoundPaths 4 - holes and islands 1', function(){
group = paper.project.importSVG( document.getElementById( 'glyphsacirc' ) );
pathA = group.children[0];
pathB = new CompoundPath();
group.children[1].clockwise = true;
pathB.addChild(group.children[1]);
var npath = new Path.Circle([40, 80], 20);
pathB.addChild( npath );
return [pathA, pathB];
});
runTest('CompoundPaths 5 - holes and islands 2', function(){
group = paper.project.importSVG( document.getElementById( 'glyphsacirc' ) );
pathA = group.children[0];
pathB = new CompoundPath();
group.children[1].clockwise = true;
pathB.addChild(group.children[1]);
var npath = new Path.Circle([40, 80], 20);
pathB.addChild( npath );
npath = new Path.Circle([120, 110], 30);
pathB.addChild( npath );
return [pathA, pathB];
});
runTest('CompoundPaths 6 - holes and islands 3', function(){
group = paper.project.importSVG( document.getElementById( 'glyphsacirc' ) );
pathA = group.children[0];
pathB = new CompoundPath();
var npath = new Path.Circle([110, 110], 100);
pathB.addChild( npath );
npath = new Path.Circle([110, 110], 60);
pathB.addChild( npath );
npath = new Path.Circle([110, 110], 30);
pathB.addChild( npath );
return [pathA, pathB];
});
runTest('CompoundPaths 6 - holes and islands 4 (curves overlap exactly on existing curves)', function(){
pathA = new Path.Rectangle(new Point(50.5, 50.5), [100, 120]);
pathB = new CompoundPath();
pathB.addChild( new Path.Rectangle(new Point(140.5, 30.5), [100, 150]) );
pathB.addChild( new Path.Rectangle(new Point(150.5, 65.5), [50, 100]) );
// pathB = new Path.Rectangle(new Point(150.5, 80.5), [80, 80] );
return [pathA, pathB];
});
// Plot the run times
function plotData(){
prepareTest( 'Results - Random tests ( Intersections/Curve vs Time)', container, 'big2' );
plotDataRandom( randomtestdata );
prepareTest( 'Results - Boolean tests ( Time taken per test )', container, 'big' );
var x = 80.5, y = 15.5, width = 500, height = 190, i, txt, ny,
yy = y + height, xx = x + width;
var ppaperfill = new Path(), pfatfill = new Path();
var ppaper = new Path(), pfat = new Path();
var max = testdata.reduce(function( a, b ){ return Math.max( a, b.paperTime + b.fatTime ); }, 0) + 20;
var vscale = height / max, hscale = width / testdata.length;
var caxes = '#999', ctxt = '#222', ctxt2 = '#555', cpaper = '#268BD2', cpaperfill ='#B5E1FF',
cfat = '#D33682', cfatfill = '#FFADD4';
new Path.Line( x, yy, xx, yy ).style.strokeColor = caxes;
new Path.Line( x, yy, x, y ).style.strokeColor = caxes;
for( i = 0; i < 10 ; i++ ){
ny = yy - vscale * max * i / 10;
new Path.Line( x, ny, x-5, ny ).style.strokeColor = caxes;
txt = new PointText( [x-10, ny] );
txt.justification = 'right';
txt.fillColor = (i%2)? ctxt: ctxt2;
txt.content = (max * i / 10).toFixed(1) + ((!i)? ' ms' : '');
}
ppaperfill.add( new Segment( x, yy ) );
pfatfill.add( new Segment( x, yy ) );
var vx = x, clr = ctxt;
var coords = [], avgPaper = 0, avgFat = 0,
maxSpeedup = -Infinity, minSpeedup = Infinity, avgSpeedup = 0;
testdata.map(function(data){
avgPaper += data.paperTime;
ny = yy - (data.paperTime + data.fatTime) * vscale;
ppaper.add( new Segment([vx, ny]) );
ppaperfill.add( new Segment([vx, ny]) );
var np = new Point( vx, ny );
np._data = data;
np._datatype = 'paper';
coords.push( np );
avgFat += data.fatTime;
ny = yy - (data.fatTime) * vscale;
pfat.add( new Segment([vx, ny]) );
pfatfill.add( new Segment([vx, ny]) );
np = new Point( vx, ny );
np._data = data;
np._datatype = 'fat';
coords.push( np );
var speedup = data.paperTime / data.fatTime;
if( speedup > maxSpeedup ) maxSpeedup = speedup;
if( speedup < minSpeedup ) minSpeedup = speedup;
avgSpeedup += speedup;
new Path.Line( vx, yy, vx, yy + 5 ).style.strokeColor = caxes;
txt = new PointText( [vx, yy+18] );
txt.justification = 'left';
txt.fillColor = clr;
txt.content = data.name;
txt.rotate( 30, new Point(vx, yy+10) );
if( !data.success ){
var p = new Path.Line( vx, y, vx, yy );
p.style.strokeWidth = 5;
p.style.strokeColor = '#f00';
}
clr = ( clr === ctxt )? ctxt2 : ctxt;
vx += hscale;
});
ppaper.style.strokeWidth = 2;
ppaper.style.strokeColor = cpaper;
ppaperfill.add( new Segment( vx-hscale, yy ) );
ppaperfill.closed = true;
ppaperfill.style.fillColor = cpaperfill;
pfat.style.strokeWidth = 2;
pfat.style.strokeColor = cfat;
pfatfill.add( new Segment( vx-hscale, yy ) );
pfatfill.closed = true;
pfatfill.style.fillColor = cfatfill;
avgPaper/= testdata.length;
avgFat/= testdata.length;
avgSpeedup = Math.round(avgSpeedup / testdata.length);
maxSpeedup = Math.round( maxSpeedup );
minSpeedup = Math.round( minSpeedup );
ny = Math.round(yy - avgPaper * vscale) + 0.5;
new Path.Line(x, ny, xx, ny).style.strokeColor = cpaper;
txt = new PointText( [xx, ny] );
txt.justification = 'right';
txt.fillColor = cpaper;
txt.content = avgPaper.toFixed(1);
ny = Math.round(yy - avgFat * vscale) + 0.5;
new Path.Line(x, ny, xx, ny).style.strokeColor = cfat;
txt = new PointText( [xx, ny] );
txt.justification = 'right';
txt.fillColor = cfat;
txt.content = avgFat.toFixed(1);
txt = new PointText([610, 75]);
txt.justification = 'center';
txt.fillColor = '#000';
txt.content = 'fatline vs subdiv';
new Path.Rectangle( [600, 90], [20, 100] ).style = { fillColor: '#ccc', strokeColor: '#000' };
ny = 190 - (avgSpeedup - minSpeedup) * 100.0 / (maxSpeedup - minSpeedup);
new Path.Line( [600, ny], [620, ny] ).style = { strokeWidth: 2, strokeColor: '#000' };
txt = new PointText([630, 95]);
txt.fillColor = '#000';
txt.content = maxSpeedup;
txt = new PointText([630, 195]);
txt.fillColor = '#000';
txt.content = minSpeedup;
txt = new PointText([630, ny+5]);
txt.fillColor = '#000';
txt.content = avgSpeedup + ' times';
view.draw();
var tool = new Tool();
tool.onMouseMove = function( e ){
var len = coords.length;
var data = null, dist = Infinity, dst, pnt = null, type = 'paper';
while( len-- ){
dst = e.point.getDistance( coords[len], true );
if( dst < dist ){
pnt = coords[len];
data = coords[len]._data;
type = coords[len]._datatype;
dist = dst;
}
}
if( dist > 500 ){ return; }
if( pnt && data ){
var p = new Path.Line( pnt.x+0.5, y, pnt.x+0.5, yy );
p.style.strokeColor = '#000';
p.removeOnMove();
p = new Path.Circle( pnt, 3 );
p.style.fillColor = (type === 'fat')? '#D33682' :'#268BD2';
p.removeOnMove();
var txt = new PointText( [ 500, 20 ] );
txt.content = 'subdiv : ' + data.paperTime.toFixed(1) + ' ms';
txt.fillColor = '#222';
txt.removeOnMove();
txt = new PointText( [ 500, 36 ] );
txt.content = 'fatline : ' + data.fatTime.toFixed(1) + ' ms';
txt.fillColor = '#222';
txt.removeOnMove();
}
};
}
function prepareTest( testName, parentNode, _big ){
console.log( '\n' + testName );
var caption = document.createElement('h3');
caption.appendChild( document.createTextNode( testName ) );
var canvas = document.createElement('CANVAS');
canvas.className += ' ' + _big;
parentNode.appendChild( caption );
parentNode.appendChild( canvas );
paper.setup( canvas );
return caption;
}
}
var pathStyleIx = {
fillColor: new Color( 0.8, 0, 0 ),
strokeColor: new Color( 0, 0, 0 )
};
var pathStyleNormal = {
strokeColor: new Color( 0, 0, 0 ),
// fillColor: new Color( 0, 0, 0, 0.1 ),
strokeWidth: 1
};
var pathStyleBoolean = {
strokeColor: new Color( 0,0,0,0.4 ),
fillColor: new Color( 0, 0, 0, 0.0 ),
strokeWidth: 1
};
// Better if path1 and path2 fit nicely inside a 200x200 pixels rect
function testIntersections( path1, path2, caption, testname, testdata, nomark) {
var i, l, maxCount = 10, count = maxCount, st, t1, t2,
ixsPaper, ixsFatline, success = false, maxdiff = -Infinity;
try{
path1.style = path2.style = pathStyleNormal;
if( !nomark ) console.time('paperjs x ' + maxCount);
st = getTimestamp();
while(count--){
ixsPaper = path1.getIntersections( path2 );
}
t1 = (getTimestamp() - st) / maxCount;
if( !nomark ) console.timeEnd('paperjs x ' + maxCount);
count = maxCount;
if( !nomark ) console.time('fatline x ' + maxCount);
st = getTimestamp();
while(count--){
ixsFatline = getIntersections2( path1, path2 );
}
t2 = (getTimestamp() - st) / maxCount;
if( !nomark ) console.timeEnd('fatline x ' + maxCount);
var found = 0, tol = 0.1;
if( ixsFatline.length === ixsPaper.length ){
for(i=0, l=ixsFatline.length; i<l; i++){
pa = ixsFatline[i].point;
for (j = 0; j < ixsPaper.length; j++) {
if( !ixsPaper[j]._found ){
pb = ixsPaper[j].point;
if( Math.abs( pa.x - pb.x ) < tol && Math.abs( pa.y - pb.y ) < tol ){
++found;
ixsPaper[j]._found = true;
}
}
}
}
}
success = ixsPaper.length === found;
window.pap = ixsPaper;
window.fat = ixsFatline;
if( !nomark ){
markIntersections( ixsPaper, '#00f', 'paperjs' );
markIntersections( ixsFatline, '#f00', 'fatline' );
}
} catch(e){
console.timeEnd('paperjs x ' + maxCount);
console.timeEnd('fatline x ' + maxCount);
t1 = t2 = 0;
console.error( e.name + ": " + e.message );
if( caption ) { caption.className += ' error'; }
}finally{
view.draw();
testdata.push({
name: testname,
ratio: ixsFatline.length / (path1.curves.length + path2.curves.length),
paperTime: t1,
fatTime: t2,
success: success
});
console.log( found );
}
return success;
}
function doRandomTests( testdata ){
var p1 = new Path(), p2 = new Path(), ixspaper, ixsfat;
var seg = 5, maxseg = 30, maxiter = 10;
var i, j, halfseg = (maxseg / 2) | 0;
var p, hi, ho, st, t1, t2, success;
while( seg <= maxseg ){
for (i = 0; i < maxiter; i++) {
p1.removeSegments();
p2.removeSegments();
for (j = 0; j < seg; j++) {
p = new Point.random().multiply( [100, 100] );
v = new Point.random().multiply( [20, 20] );
p1.add( new Segment( p, v, v.multiply(-1) ) );
p1.closed = true;
p = new Point.random().multiply( [100, 100] );
v = new Point.random().multiply( [20, 20] );
p2.add( new Segment( p, v, v.multiply(-1) ) );
p2.closed = true;
}
st = getTimestamp();
ixspaper = p1.getIntersections( p2 );
t1 = (getTimestamp() - st);
st = getTimestamp();
ixsfat = getIntersections2( p1, p2 );
t2 = (getTimestamp() - st);
// Check against paperjs output
// tol - tolerence for computed points with in 1/10 th of a pixel
var found = 0, tol = 0.1;
if( ixsfat.length === ixspaper.length ){
for(i=0, l=ixsfat.length; i<l; i++){
pa = ixsfat[i].point;
for (j = 0; j < ixspaper.length; j++) {
if( !ixspaper[j]._found ){
pb = ixspaper[j].point;
if( Math.abs( pa.x - pb.x ) < tol && Math.abs( pa.y - pb.y ) < tol ){
++found;
ixspaper[j]._found = true;
}
}
}
}
}
success = ixspaper.length === found;
testdata.push({
curves: p1.curves.length + p2.curves.length,
ixsfat: ixsfat.length,
ixspaper: ixspaper.length,
ratio: ixsfat.length / (seg),
paperTime: t1,
fatTime: t2,
speedup: t1 / t2,
success: success
});
}
++seg;
if( seg === halfseg ) maxiter = (maxiter / 2) | 0;
}
}
function getRandomPath(seg){
seg = seg || 3;
var p = new Path(), pnt, hi, ho, v;
for (j = 0; j < seg; j++) {
pnt = new Point.random().multiply( [130, 130] );
v = new Point.random().multiply( [20, 20] );
p.add( new Segment( pnt, v, v.multiply(-1) ) );
p.closed = true;
}
return p;
}
function markIntersections( ixs, c, txt ){
for (i = 0, len = ixs.length; i < len; i++) {
// force calculate the parameter for debugging
var a = ixs[i].parameter;
// markPoint( ixs[i].point, ixs[i].parameter );
markPoint( ixs[i].point, ' ', c, null, false );
// console.log( txt , ixs[i].parameter )
}
}
// ==============================================================
// On screen debug helpers
function markPoint( pnt, t, c, tc, remove ) {
if( !pnt ) return;
c = c || '#000';
if( remove === undefined ){ remove = true; }
var cir = new Path.Circle( pnt, 2 );
cir.style.fillColor = c;
cir.style.strokeColor = tc;
if( t !== undefined || t !== null ){
var text = new PointText( pnt.add([0, -3]) );
text.justification = 'center';
text.fillColor = c;
text.content = t;
if( remove ){
text.removeOnMove();
}
}
if( remove ) {
cir.removeOnMove();
}
}
function markCurve( crv, c, flag) {
if( !crv ) return;
c = c || '#000';
if( flag ){
if( window.__p1 ) window.__p1.remove();
window.__p1 = new Path(
new Segment( [crv[0], crv[1]], null, [crv[2] - crv[0], crv[3] - crv[1]] ),
new Segment( [crv[6], crv[7]], [crv[4] - crv[6], crv[5] - crv[7]], null )
);
window.__p1.style.strokeColor = c;
// window.__p1.fullySelected = true;
} else {
if( window.__p2 ) window.__p2.remove();
window.__p2 = new Path(
new Segment( [crv[0], crv[1]], null, [crv[2] - crv[0], crv[3] - crv[1]] ),
new Segment( [crv[6], crv[7]], [crv[4] - crv[6], crv[5] - crv[7]], null )
);
window.__p2.style.strokeColor = c;
// window.__p2.fullySelected = true;
}
view.draw();
}
function annotatePath( path, t, c, tc, remove ) {
if( !path ) return;
var crvs = path.curves;
for (i = crvs.length - 1; i >= 0; i--) {
annotateCurve( crvs[i], t, c, tc, remove );
}
var segs = path.segments;
for (i = segs.length - 1; i >= 0; i--) {
annotateSegment( segs[i], t, c, tc, remove, true );
}
}
function annotateSegment( s, t, c, tc, remove, skipCurves ) {
if( !s ) return;
c = c || '#000';
tc = tc || '#ccc';
t = t || s.index;
if( remove === undefined ){ remove = true; }
var crv = s.curve;
var t1 = crv.getNormal( 0 ).normalize( 10 );
var p = s.point.clone().add( t1 );
var cir = new Path.Circle( s.point, 2 );
cir.style.fillColor = c;
cir.style.strokeColor = tc;
var text = new PointText( p );
text.justification = 'center';
text.fillColor = c;
text.content = t;
if( remove ) {
cir.removeOnMove();
text.removeOnMove();
}
if( !skipCurves ) {
annotateCurve( s.curveIn, null, c, tc, remove );
annotateCurve( s.curveOut, null, c, tc, remove );
}
}
function annotateCurve( crv, t, c, tc, remove ) {
if( !crv ) return;
c = c || '#000';
tc = tc || '#ccc';
t = t || crv.index;
if( remove === undefined ){ remove = true; }
var p = crv.getPoint( 0.57 );
var t1 = crv.getTangent( 0.57 ).normalize( -10 );
var p2 = p.clone().add( t1 );
var l = new Path.Line( p, p2 ).rotate( 30, p );
var l2 = new Path.Line( p, p2 ).rotate( -30, p );
p = crv.getPoint( 0.43 );
var cir = new Path.Circle( p, 8 );
var text = new PointText( p.subtract( [0, -4] ) );
text.justification = 'center';
text.fillColor = tc;
text.content = t;
l.style.strokeColor = l2.style.strokeColor = c;
cir.style.fillColor = c;
if( remove ) {
l.removeOnMove();
l2.removeOnMove();
cir.removeOnMove();
text.removeOnMove();
}
}
// Plot the run times
function plotDataRandom( testdata ){
var x = 80.5, y = 15.5, width = 500, height = 190, i, txt, ny,
yy = y + height, xx = x + width;
var ppaper = new Path(), pfat = new Path();
var max = testdata.reduce(function( a, b ){ return Math.max( a, b.paperTime, b.fatTime ); }, 0) + 20;
testdata.sort( function(a,b){ return a.ratio - b.ratio; } );
var vscale = height / max, hscale = width / testdata.length;
var caxes = '#999', ctxt = '#222', cpaper = '#268BD2', cfat = '#D33682';
new Path.Line( x, yy, xx, yy ).style.strokeColor = caxes;
new Path.Line( x, yy, x, y ).style.strokeColor = caxes;
for( i = 0; i < 10 ; i++ ){
ny = yy - vscale * max * i / 10;
new Path.Line( x, ny, x-5, ny ).style.strokeColor = caxes;
txt = new PointText( [x-10, ny] );
txt.justification = 'right';
txt.fillColor = ctxt;
txt.content = (max * i / 10).toFixed(1) + ((!i)? ' ms' : '');
}
txt = new PointText([xx + 20, yy + 18 ]);
txt.justification = 'left';
txt.fillColor = ctxt;
txt.content = 'ixs / curve';
txt = new PointText([xx + 20, yy + 40]);
txt.justification = 'left';
txt.fillColor = '#999';
txt.content = '( Total Curves )';
var vx = x, step = 15, count = 0;
var avgPaper = 0, avgFat = 0;
testdata.map(function(data){
avgPaper += data.paperTime;
ny = yy - (data.paperTime + data.fatTime) * vscale;
ppaper.add( new Segment([vx, ny]) );
avgFat += data.fatTime;
ny = yy - (data.fatTime) * vscale;
pfat.add( new Segment([vx, ny]) );
new Path.Line( vx, yy, vx, yy + 5 + ((count%2)? step:0) ).style.strokeColor = caxes;
txt = new PointText( [vx, yy+18 + ((count%2)? step:0) ] );
txt.justification = 'center';
txt.fillColor = ctxt;
txt.content = data.ratio.toFixed(1);
txt = new PointText( [vx -5, yy+40 ] );
txt.justification = 'left';
txt.fillColor = '#999';
txt.content = data.curves;
txt.rotate( 90, [vx-5, yy+40 ] );
if( !data.success ){
var p = new Path.Line( vx, y, vx, yy );
p.style.strokeWidth = 5;
p.style.strokeColor = '#f00';
}
++count;
vx += hscale;
});
ppaper.smooth();
ppaper.style.strokeWidth = 2;
ppaper.style.strokeColor = cpaper;
pfat.smooth();
pfat.style.strokeWidth = 2;
pfat.style.strokeColor = cfat;
avgPaper/= testdata.length;
avgFat/= testdata.length;
ny = Math.round(yy - avgPaper * vscale) + 0.5;
new Path.Line(x, ny, xx, ny).style.strokeColor = cpaper;
txt = new PointText( [xx, ny] );
txt.justification = 'right';
txt.fillColor = cpaper;
txt.content = avgPaper.toFixed(1);
ny = Math.round(yy - avgFat * vscale) + 0.5;
new Path.Line(x, ny, xx, ny).style.strokeColor = cfat;
txt = new PointText( [xx, ny] );
txt.justification = 'right';
txt.fillColor = cfat;
txt.content = avgFat.toFixed(1);
view.draw();
}
function drawFatline( v1 ) {
function signum(num) {
return ( num > 0 )? 1 : ( num < 0 )? -1 : 0;
}
var l = new Line( [v1[0], v1[1]], [v1[6], v1[7]], false );
var p1 = new Point( v1[2], v1[3] ), p2 = new Point( v1[4], v1[5] );
var d1 = l.getSide( p1 ) * l.getDistance( p1 ) || 0;
var d2 = l.getSide( p2 ) * l.getDistance( p2 ) || 0;
var dmin, dmax;
if( d1 * d2 > 0){
// 3/4 * min{0, d1, d2}
dmin = 0.75 * Math.min( 0, d1, d2 );
dmax = 0.75 * Math.max( 0, d1, d2 );
} else {
// 4/9 * min{0, d1, d2}
dmin = 4 * Math.min( 0, d1, d2 ) / 9.0;
dmax = 4 * Math.max( 0, d1, d2 ) / 9.0;
}
var ll = new Path.Line( v1[0], v1[1], v1[6], v1[7] );
window.__p3.push( ll );
window.__p3[window.__p3.length-1].style.strokeColor = new Color( 0,0,0.9, 0.8);
var lp1 = ll.segments[0].point;
var lp2 = ll.segments[1].point;
var pm = l.vector, pm1 = pm.rotate( signum( dmin ) * -90 ), pm2 = pm.rotate( signum( dmax ) * -90 );
var p11 = lp1.add( pm1.normalize( Math.abs(dmin) ) );
var p12 = lp2.add( pm1.normalize( Math.abs(dmin) ) );
var p21 = lp1.add( pm2.normalize( Math.abs(dmax) ) );
var p22 = lp2.add( pm2.normalize( Math.abs(dmax) ) );
window.__p3.push( new Path.Line( p11, p12 ) );
window.__p3[window.__p3.length-1].style.strokeColor = new Color( 0,0,0.9);
window.__p3.push( new Path.Line( p21, p22 ) );
window.__p3[window.__p3.length-1].style.strokeColor = new Color( 0,0,0.9);
}
function plotD_vs_t( x, y, arr, arr2, v, dmin, dmax, tmin, tmax, yscale, tvalue ){
yscale = yscale || 1;
new Path.Line( x, y-100, x, y+100 ).style.strokeColor = '#aaa';
new Path.Line( x, y, x + 200, y ).style.strokeColor = '#aaa';
var clr = (tvalue)? '#a00' : '#00a';
if( window.__p3 ) window.__p3.map(function(a){a.remove();});
window.__p3 = [];
drawFatline( v );
window.__p3.push( new Path.Line( x, y + dmin * yscale, x + 200, y + dmin * yscale ) );
window.__p3[window.__p3.length-1].style.strokeColor = '#000'
window.__p3.push( new Path.Line( x, y + dmax * yscale, x + 200, y + dmax * yscale ) );
window.__p3[window.__p3.length-1].style.strokeColor = '#000'
window.__p3.push( new Path.Line( x + tmin * 190, y-100, x + tmin * 190, y+100 ) );
window.__p3[window.__p3.length-1].style.strokeColor = clr
window.__p3.push( new Path.Line( x + tmax * 190, y-100, x + tmax * 190, y+100 ) );
window.__p3[window.__p3.length-1].style.strokeColor = clr
for (var i = 0; i < arr.length; i++) {
window.__p3.push( new Path.Line( new Point( x + arr[i][0] * 190, y + arr[i][1] * yscale ),
new Point( x + arr[i][2] * 190, y + arr[i][3] * yscale ) ) );
window.__p3[window.__p3.length-1].style.strokeColor = '#999';
}
var pnt = [];
var arr2x = [ 0.0, 0.333333333, 0.6666666666, 1.0 ];
for (var i = 0; i < arr2.length; i++) {
pnt.push( new Point( x + arr2x[i] * 190, y + arr2[i] * yscale ) );
window.__p3.push( new Path.Circle( pnt[pnt.length-1], 2 ) );
window.__p3[window.__p3.length-1].style.fillColor = '#000'
}
// var pth = new Path( pnt[0], pnt[1], pnt[2], pnt[3] );
// pth.closed = true;
window.__p3.push( new Path( new Segment(pnt[0], null, pnt[1].subtract(pnt[0])), new Segment( pnt[3], pnt[2].subtract(pnt[3]), null ) ) );
window.__p3[window.__p3.length-1].style.strokeColor = clr
view.draw();
}