1
0
mirror of https://github.com/Pomax/BezierInfo-2.git synced 2025-08-23 00:33:12 +02:00

polybezier

This commit is contained in:
Pomax
2016-01-10 13:46:59 -08:00
parent d6a335006e
commit 3c190e630c
7 changed files with 416 additions and 99 deletions

File diff suppressed because one or more lines are too long

View File

@@ -24,7 +24,7 @@ var Graphic = React.createClass({
my:0,
cx:0,
cy:0,
mp: { x: 0, y: 0},
mp: false,
offset: { x: 0, y: 0},
lpts: [],
colorSeed: 0,
@@ -96,10 +96,11 @@ var Graphic = React.createClass({
this.dragging = false;
this.down = true;
this.lpts.forEach(p => {
this.lpts.forEach((p,idx) => {
if(Math.abs(this.mx - p.x)<10 && Math.abs(this.my - p.y)<10) {
this.moving = true;
this.mp = p;
this.mp_idx = idx;
this.cx = p.x;
this.cy = p.y;
}

View File

@@ -39,10 +39,7 @@ module.exports = {
catmullconv: require("./catmullconv"),
catmullmoulding: require("./catmullmoulding"),
/*
// This requires bezier.js to have a proper poly implementation
polybezier: require("./polybezier"),
*/
polybezier: require("./polybezier"),
/*
// This section is way too much work to port, and not worth implementing given paper.js etc.

View File

@@ -2,6 +2,8 @@ var React = require("react");
var Graphic = require("../../Graphic.jsx");
var SectionHeader = require("../../SectionHeader.jsx");
var atan2 = Math.atan2, sqrt = Math.sqrt, sin = Math.sin, cos = Math.cos;
var PolyBezier = React.createClass({
getDefaultProps: function() {
return {
@@ -27,27 +29,213 @@ var PolyBezier = React.createClass({
},
setupCubic: function(api) {
var w = api.getPanelWidth(),
h = api.getPanelHeight(),
cx = w/2, cy = h/2, pad = 40,
r = (w - 2*pad)/2,
k = 0.55228,
kr = k*r,
pts = [
// first curve:
{x:cx,y:pad}, {x:cx+kr,y:pad}, {x:w-pad,y:cy-kr}, {x:w-pad,y:cy},
// subsequent curve
{x:w-pad,y:cy+kr}, {x:cx+kr,y:h-pad}, {x:cx,y:h-pad},
// subsequent curve
{x:cx-kr,y:h-pad}, {x:pad,y:cy+kr}, {x:pad,y:cy},
// final curve control point
{x:pad,y:cy-kr}, {x:cx-kr,y:pad}
];
api.lpts = pts;
},
movePointsQuadraticLD: function(api, i) {
// ...we need to move _everything_
var anchor, fixed, toMove;
for(var p=1; p<4; p++) {
anchor = i + (2*p - 2) + api.lpts.length;
anchor = api.lpts[anchor % api.lpts.length];
fixed = i + (2*p - 1);
fixed = api.lpts[fixed % api.lpts.length];
toMove = i + 2*p;
toMove = api.lpts[toMove % api.lpts.length];
toMove.x = fixed.x + (fixed.x - anchor.x);
toMove.y = fixed.y + (fixed.y - anchor.y);
}
},
movePointsCubicLD: function(api, i) {
var toMove, fixed;
if (i%3 === 1) {
fixed = i-1;
fixed += (fixed < 0) ? api.lpts.length : 0;
toMove = i-2;
toMove += (toMove < 0) ? api.lpts.length : 0;
} else {
fixed = (i+1) % api.lpts.length;
toMove = (i+2) % api.lpts.length;
}
fixed = api.lpts[fixed];
toMove = api.lpts[toMove];
toMove.x = fixed.x + (fixed.x - api.mp.x);
toMove.y = fixed.y + (fixed.y - api.mp.y);
},
linkDerivatives: function(evt, api) {
if (api.mp) {
var quad = api.lpts.length === 8;
var i = api.mp_idx;
if (quad && i%2 !== 0) { this.movePointsQuadraticLD(api, i); }
else if(i%3 !== 0) { this.movePointsCubicLD(api, i); }
}
},
movePointsQuadraticDirOnly: function(api, i) {
// ...we need to move _everything_ ...again
var anchor, fixed, toMove;
// move left and right
[-1,1].forEach(v => {
anchor = api.mp;
fixed = i + v + api.lpts.length;
fixed = api.lpts[fixed % api.lpts.length];
toMove = i + 2*v + api.lpts.length;
toMove = api.lpts[toMove % api.lpts.length];
var a = atan2(fixed.y - anchor.y, fixed.x - anchor.x),
dx = toMove.x - fixed.x,
dy = toMove.y - fixed.y,
d = sqrt(dx*dx + dy*dy);
toMove.x = fixed.x + d*cos(a);
toMove.y = fixed.y + d*sin(a);
});
// then, the furthest point cannot be computed properly!
toMove = i + 4;
toMove = api.lpts[toMove % api.lpts.length];
api.problem = toMove;
},
movePointsCubicDirOnly: function(api, i) {
var toMove, fixed;
if (i%3 === 1) {
fixed = i-1;
fixed += (fixed < 0) ? api.lpts.length : 0;
toMove = i-2;
toMove += (toMove < 0) ? api.lpts.length : 0;
} else {
fixed = (i+1) % api.lpts.length;
toMove = (i+2) % api.lpts.length;
}
fixed = api.lpts[fixed];
toMove = api.lpts[toMove];
var a = atan2(fixed.y - api.mp.y, fixed.x - api.mp.x),
dx = toMove.x - fixed.x,
dy = toMove.y - fixed.y,
d = sqrt(dx*dx + dy*dy);
toMove.x = fixed.x + d*cos(a);
toMove.y = fixed.y + d*sin(a);
},
linkDirection: function(evt, api) {
if (api.mp) {
var quad = api.lpts.length === 8;
var i = api.mp_idx;
if (quad && i%2 !== 0) { this.movePointsQuadraticDirOnly(api, i); }
else if(i%3 !== 0) { this.movePointsCubicDirOnly(api, i); }
}
},
bufferPoints: function(evt, api) {
api.bpts = JSON.parse(JSON.stringify(api.lpts));
},
moveQuadraticPoint: function(api, i) {
this.moveCubicPoint(api,i), anchor, toMove, fixed;
// then move the other control points
[-1,1].forEach(v => {
anchor = i - v + api.lpts.length;
anchor = api.lpts[anchor % api.lpts.length];
fixed = i - 2*v + api.lpts.length;
fixed = api.lpts[fixed % api.lpts.length];
toMove = i - 3*v + api.lpts.length;
toMove = api.lpts[toMove % api.lpts.length];
var a = atan2(fixed.y - anchor.y, fixed.x - anchor.x),
dx = toMove.x - fixed.x,
dy = toMove.y - fixed.y,
d = sqrt(dx*dx + dy*dy);
toMove.x = fixed.x + d*cos(a);
toMove.y = fixed.y + d*sin(a);
});
// then signal a problem
var toMove = i + 4;
toMove = api.lpts[toMove % api.lpts.length];
api.problem = toMove;
},
moveCubicPoint: function(api, i) {
var op = api.bpts[i],
np = api.lpts[i],
dx = np.x - op.x,
dy = np.y - op.y,
len = api.lpts.length,
l = i-1+len,
r = i+1,
// original left and right
ol = api.bpts[l % len],
or = api.bpts[r % len],
// current left and right
nl = api.lpts[l % len],
nr = api.lpts[r % len];
// update current left
nl.x = ol.x + dx;
nl.y = ol.y + dy;
// update current right
nr.x = or.x + dx;
nr.y = or.y + dy;
return {x:dx, y:dy};
},
modelCurve: function(evt, api) {
if (api.mp) {
var quad = api.lpts.length === 8;
var i = api.mp_idx;
if (quad) {
if (i%2 !== 0) { this.movePointsQuadraticDirOnly(api, i); }
else { this.moveQuadraticPoint(api, i); }
}
else {
if(i%3 !== 0) { this.movePointsCubicDirOnly(api, i); }
else { this.moveCubicPoint(api, i); }
}
}
},
draw: function(api, curves) {
api.reset();
var pts = api.lpts;
var quad = pts.length === 8;
var c1 = new api.Bezier(pts[0],pts[1],pts[2]);
api.drawSkeleton(c1);
var c1 = quad ? new api.Bezier(pts[0],pts[1],pts[2]) : new api.Bezier(pts[0],pts[1],pts[2],pts[3]);
api.drawSkeleton(c1, false, true);
api.drawCurve(c1);
var c2 = new api.Bezier(pts[2],pts[3],pts[4]);
api.drawSkeleton(c2);
var c2 = quad ? new api.Bezier(pts[2],pts[3],pts[4]) : new api.Bezier(pts[3],pts[4],pts[5],pts[6]);
api.drawSkeleton(c2, false, true);
api.drawCurve(c2);
var c3 = new api.Bezier(pts[4],pts[5],pts[6]);
api.drawSkeleton(c3);
var c3 = quad ? new api.Bezier(pts[4],pts[5],pts[6]) : new api.Bezier(pts[6],pts[7],pts[8],pts[9]);
api.drawSkeleton(c3, false, true);
api.drawCurve(c3);
var c4 = new api.Bezier(pts[6],pts[7],pts[0]);
api.drawSkeleton(c4);
var c4 = quad ? new api.Bezier(pts[6],pts[7],pts[0]) : new api.Bezier(pts[9],pts[10],pts[11],pts[0]);
api.drawSkeleton(c4, false, true);
api.drawCurve(c4);
if (api.problem) {
api.setColor("red");
api.drawCircle(api.problem,5);
}
},
render: function() {
@@ -56,22 +244,37 @@ var PolyBezier = React.createClass({
<SectionHeader {...this.props} />
<p>Much like lines can be chained together to form polygons, Bézier curves can be chained together
to form poly-Béziers, and the only trick required is to make sure that: A) the end point of each
section is the starting point of the following section, and B) the derivatives across that
dual point line up. Unless, of course, you want discontinuities; then you don't even need (B).</p>
to form poly-Béziers, and the only trick required is to make sure that:</p>
<ol>
<li>the end point of each section is the starting point of the following section, and</li>
<li>the derivatives across that dual point line up.</li>
</ol>
<p>Unless, of course, you want discontinuities; then you don't even need 2.</p>
<p>We'll cover three forms of poly-Bézier curves in this section. First, we'll look at the kind
that enforces "the outgoing derivative is the same as the incoming derivative" across sections:</p>
that just follows point 1. where the end point of a segment is the same point as the start point
of the next segment. This leads to poly-Béziers that are pretty hard to work with, but they're
the easiest to implement:</p>
<Graphic preset="poly" title="Loosely connected quadratic poly-Bézier" setup={this.setupQuadratic} draw={this.draw}/>
<Graphic preset="poly" title="Loosely connected cubic poly-Bézier" setup={this.setupCubic} draw={this.draw}/>
<p>Dragging the control points around only affects the curve segments that the control point belongs
to, and moving an on-curve point leaves the control points where they are, which is not the most useful
for practical modelling purposes. So, let's add in the logic we need to make things a little better.
We'll start by linking up control points by ensuring that the "incoming" derivative at an on-curve
point is the same as it's "outgoing" derivative:</p>
<p>\[
B'(1)_n = B'(0)_{n+1}
\]</p>
<p>We can actually guarantee this really easily, because we know that the vector from a curve's
last control point to its last on-curve point is equal to the derivative vector. If we want to
ensure that the first control point of the next curve matches that, all we have to do is mirror
that last control point through the last on-curve point. And mirroring any point A through any
point B is really simple:</p>
<p>We can effect this quite easily, because we know that the vector from a curve's last control point
to its last on-curve point is equal to the derivative vector. If we want to ensure that the first control
point of the next curve matches that, all we have to do is mirror that last control point through the
last on-curve point. And mirroring any point A through any point B is really simple:</p>
<p>\[
Mirrored = \left [
@@ -82,20 +285,13 @@ var PolyBezier = React.createClass({
\]</p>
<p>So let's implement that and see what it gets us. The following two graphics show a quadratic
and a cubic poly-Bézier curve; both consist of multiple sub-curves, but because of our constraint,
not all points on the curves can be moved around freely. Some points, when moved, will move other
points by virtue of changing the curve across sections.</p>
and a cubic poly-Bézier curve again, but this time moving the control points around moves others,
too. However, you might see something unexpected going on for quadratic curves...</p>
<Graphic preset="poly" title="Forming a quadratic poly-Bézier" setup={this.setupQuadratic} draw={this.draw}/>
<textarea className="sketch-code" data-sketch-preset="poly" data-sketch-title="Forming a cubic poly-Bézier">
void setupCurve() {
setupDefaultCubicPoly();
}
void movePoint(PolyBezierCurve p, int pt, int mx, int my) {
p.movePointConstrained(pt, mx, my);
}</textarea>
<Graphic preset="poly" title="Loosely connected quadratic poly-Bézier" setup={this.setupQuadratic} draw={this.draw}
onMouseMove={this.linkDerivatives}/>
<Graphic preset="poly" title="Loosely connected cubic poly-Bézier" setup={this.setupCubic} draw={this.draw}
onMouseMove={this.linkDerivatives}/>
<p>As you can see, quadratic curves are particularly ill-suited for poly-Bézier curves, as all
the control points are effectively linked. Move one of them, and you move all of them. This means
@@ -104,66 +300,40 @@ var PolyBezier = React.createClass({
that the derivatives are linked means we can't manipulate curves as well as we might if we
relaxed the constraints a little.</p>
<p>So: let's relax them!</p>
<p>So: let's relax the requirement a little.</p>
<p>We can change the constraint so that we still preserve the angle of the derivatives across
sections (so transitions from one section to the next will still look natural), but give up
the requirement that they should also have the same vector length. Doing so will give us
a much more a useful kind of poly-Bézier curve:</p>
<p>We can change the constraint so that we still preserve the <em>angle</em> of the derivatives across
sections (so transitions from one section to the next will still look natural), but give up the
requirement that they should also have the same <em>vector length</em>. Doing so will give us a much
more useful kind of poly-Bézier curve:</p>
<textarea className="sketch-code" data-sketch-preset="poly" data-sketch-title="A half-constrained quadratic poly-Bézier">
void setupCurve() {
setupDefaultQuadraticPoly();
}
<Graphic preset="poly" title="Loosely connected quadratic poly-Bézier" setup={this.setupQuadratic} draw={this.draw} onMouseMove={this.linkDirection}/>
<Graphic preset="poly" title="Loosely connected cubic poly-Bézier" setup={this.setupCubic} draw={this.draw} onMouseMove={this.linkDirection}/>
void movePoint(PolyBezierCurve p, int pt, int mx, int my) {
p.movePointHalfConstrained(pt, mx, my);
}</textarea>
<p>Cubic curves are now better behaved when it comes to dragging control points around, but the
quadratic poly-Bézier has a problem: in the example shape, moving one control points will move
the control points around it properly, but they in turn define "the next" control point and they
do so in incompatible ways! This is one of the many reasons why quadratic curves are not really
useful to work with.</p>
<textarea className="sketch-code" data-sketch-preset="poly" data-sketch-title="A half-constrained cubic poly-Bézier">
void setupCurve() {
setupDefaultCubicPoly();
}
<p>Finally, we also want to make sure that moving the on-curve coordinates preserves the relative
positions of the associated control points. With that, we get to the kind of curve control that you
might be familiar with from applications like Photoshop, Inkscape, Blender, etc.</p>
void movePoint(PolyBezierCurve p, int pt, int mx, int my) {
p.movePointHalfConstrained(pt, mx, my);
}</textarea>
<p>Quadratic curves are still silly, but cubic curves are now much more controllable.</p>
<p>If we want even more control, we could just abandon the derivative constraints entirely,
and simply assure that the end point of one section is the same as the start point of the next section,
and then keep it at that. This gives us the greatest degree of freedom when it comes to modelling
shapes, but also means that our poly-Bézier constructs are no longer continuous curves. Sometimes
this is exactly what you want (because it lets you add corners to a shape, while still only using
Bézier curves).</p>
<textarea className="sketch-code" data-sketch-preset="poly" data-sketch-title="An unconstrained quadratic poly-Bézier">
void setupCurve() {
setupDefaultQuadraticPoly();
}
void movePoint(PolyBezierCurve p, int pt, int mx, int my) {
p.movePoint(pvt, mx, my);
}</textarea>
<textarea className="sketch-code" data-sketch-preset="poly" data-sketch-title="An unconstrained cubic poly-Bézier">
void setupCurve() {
setupDefaultCubicPoly();
}
void movePoint(PolyBezierCurve p, int pt, int mx, int my) {
p.movePoint(pvt, mx, my);
}</textarea>
<p>When doing any kind of modelling, you generally don't want a poly-Bézier that will only let you
pick one of the three forms for all your points; most graphics applications that deal with Bézier
curves will actually let you pick, per on-curve point, how to deal with the control points around it:
fully constrained, loosely constrained, or completely unconstrained. The best shape modelling comes
from having a curve that will let you pick what you need, when you need it, without having to start
a new poly-Bézier curve.</p>
<Graphic preset="poly" title="Loosely connected quadratic poly-Bézier" setup={this.setupQuadratic} draw={this.draw}
onMouseDown={this.bufferPoints} onMouseMove={this.modelCurve}/>
<Graphic preset="poly" title="Loosely connected cubic poly-Bézier" setup={this.setupCubic} draw={this.draw}
onMouseDown={this.bufferPoints} onMouseMove={this.modelCurve}/>
<p>Again, we see that cubic curves are now rather nice to work with, but quadratic curves have a
serious problem: we can move an on-curve point in such a way that we can't compute what needs to
"happen next". Move the top point down, below the left and right points, for instance. There
is no way to preserve correct control points without a kink at the bottom point. Quadratic curves:
just not that good...</p>
<p>A final improvement is to offer fine-level control over which points behave which, so that you can
have "kinks" or individually controlled segments when you need them, with nicely well-behaved curves
for the rest of the path. Implementing that, is left as an excercise for the reader.</p>
</section>
);
}

View File

@@ -46,6 +46,7 @@ var Projections = React.createClass({
api.drawCurve(curve);
if (api.mousePt) {
api.setColor("red");
api.setFill("red");
api.drawCircle(api.mousePt, 3);
// naive t value
var t = this.findClosest(api._lut, api.mousePt, api.utils.dist);
@@ -53,6 +54,7 @@ var Projections = React.createClass({
var p = curve.get(t);
api.drawLine(p, api.mousePt);
api.drawCircle(p, 3);
api.text("t = "+api.utils.round(t,2), p, {x:10, y:3});
}
},

View File

@@ -0,0 +1,108 @@
<svg xmlns:xlink="http://www.w3.org/1999/xlink" width="48.833ex" height="6ex" style="vertical-align: -2.5ex; margin-left: 0ex; margin-right: 0ex; margin-bottom: 1px; margin-top: 1px;" viewBox="0 -1543.9 21026.5 2587.9" xmlns="http://www.w3.org/2000/svg">
<defs>
<path stroke-width="10" id="E1-LATINMODERNNORMAL-1D440" d="M1044 672c0 -20 -9 -20 -32 -20c-75 0 -77 -10 -86 -46l-133 -533c-5 -18 -5 -20 -5 -24c0 -18 28 -18 65 -18c19 0 28 0 28 -11c0 -20 -13 -20 -19 -20c-41 0 -84 3 -125 3l-124 -3c-3 0 -15 0 -15 12c0 19 11 19 28 19c79 0 81 8 91 47l143 573h-1l-404 -633 c-5 -7 -11 -18 -22 -18c-12 0 -13 11 -15 23l-86 620h-1l-136 -545c-3 -11 -4 -16 -4 -23c0 -23 11 -43 68 -44c7 0 18 0 18 -11c0 -20 -13 -20 -18 -20c-33 0 -69 3 -103 3c-33 0 -68 -3 -100 -3c-8 0 -14 3 -14 12c0 18 13 19 18 19c81 3 98 35 108 75l127 509 c3 12 4 15 4 19c0 11 -6 14 -22 16c-12 1 -30 2 -43 2c-20 0 -29 0 -29 12c0 19 11 19 30 19h137c26 0 28 0 31 -23l78 -566l365 570c12 19 13 19 39 19h132c17 0 27 0 27 -11Z"></path>
<path stroke-width="10" id="E1-LATINMODERNNORMAL-1D456" d="M284 625c0 -30 -30 -53 -53 -53c-24 0 -38 17 -38 36c0 27 27 53 54 53c23 0 37 -16 37 -36zM293 143c0 -9 -37 -154 -131 -154c-48 0 -82 35 -82 82c0 21 13 54 23 80c16 43 61 159 69 185c4 10 11 31 11 52c0 32 -17 32 -25 32c-34 0 -74 -30 -101 -124 c-5 -16 -6 -18 -16 -18c0 0 -12 0 -12 10c0 9 38 154 132 154c50 0 82 -37 82 -82c0 -19 -5 -33 -13 -53c-10 -27 -10 -29 -22 -58l-39 -105c-23 -61 -29 -75 -29 -100c0 -23 7 -33 24 -33c51 0 84 61 102 124c5 15 5 18 15 18c3 0 12 0 12 -10Z"></path>
<path stroke-width="10" id="E1-LATINMODERNNORMAL-1D45F" d="M436 377c0 -36 -28 -59 -55 -59s-38 19 -38 35c0 26 22 50 52 55c0 0 -16 12 -42 12c-43 0 -72 -26 -80 -33c-24 -22 -52 -69 -56 -82l-32 -130c-4 -18 -38 -154 -40 -158c-7 -20 -25 -28 -37 -28c-15 0 -29 9 -29 27c0 5 6 28 9 43l58 231c13 52 16 63 16 84 c0 38 -14 46 -31 46c-36 0 -56 -48 -73 -119c-6 -22 -7 -23 -17 -23c0 0 -12 0 -12 10c0 3 13 63 31 97c9 18 28 57 74 57c47 0 83 -32 91 -77c19 28 63 77 128 77c51 0 83 -30 83 -65Z"></path>
<path stroke-width="10" id="E1-LATINMODERNNORMAL-1D45C" d="M469 273c0 -146 -135 -284 -268 -284c-93 0 -160 70 -160 169c0 142 134 284 268 284c90 0 160 -65 160 -169zM396 312c0 60 -30 108 -88 108c-28 0 -85 -15 -135 -92c-32 -51 -58 -159 -58 -208c0 -78 44 -109 87 -109c46 0 101 34 136 92c38 65 58 170 58 209Z"></path>
<path stroke-width="10" id="E1-LATINMODERNNORMAL-1D452" d="M430 107c0 -12 -84 -118 -227 -118c-98 0 -157 79 -157 181c0 175 151 272 262 272c69 0 107 -41 107 -85c0 -14 -5 -73 -75 -103c-50 -21 -124 -23 -153 -23h-53c-15 -61 -16 -92 -16 -104c0 -32 9 -116 87 -116c12 0 121 0 200 99c6 8 8 10 13 10c6 0 12 -7 12 -13z M382 357c0 34 -27 63 -74 63c-26 0 -129 -15 -168 -167h41c41 0 201 0 201 104Z"></path>
<path stroke-width="10" id="E1-LATINMODERNNORMAL-1D451" d="M516 683l-144 -578c-4 -17 -6 -24 -6 -48c0 -20 3 -46 30 -46c41 0 59 59 76 124c3 14 4 18 14 18c3 0 12 0 12 -10c0 0 -13 -63 -30 -99c-16 -32 -39 -55 -74 -55c-48 0 -83 33 -91 75c-60 -71 -110 -75 -130 -75c-78 0 -133 66 -133 160c0 146 124 293 241 293 c45 0 74 -27 92 -64l60 237l3 20c0 10 -2 17 -50 17c-15 0 -24 0 -24 12c0 13 6 18 14 19c17 2 112 11 127 11c13 0 13 -11 13 -11zM361 332c0 6 -14 88 -79 88c-40 0 -85 -37 -116 -96c-23 -46 -55 -169 -55 -219c0 -39 14 -94 64 -94c28 0 69 16 113 71c15 17 15 19 20 37 l50 196c1 5 3 11 3 17Z"></path>
<path stroke-width="10" id="E1-LATINMODERNMAIN-3D" d="M722 347c0 -11 -9 -20 -20 -20h-626c-11 0 -20 9 -20 20s9 20 20 20h626c11 0 20 -9 20 -20zM722 153c0 -11 -9 -20 -20 -20h-626c-11 0 -20 9 -20 20s9 20 20 20h626c11 0 20 -9 20 -20Z"></path>
<path stroke-width="10" id="E1-LATINMODERNMAIN-5B" d="M256 -230c0 -11 -9 -20 -20 -20h-122v1000h122c11 0 20 -9 20 -20s-9 -20 -20 -20h-82v-920h82c11 0 20 -9 20 -20Z"></path>
<path stroke-width="10" id="E1-LATINMODERNNORMAL-1D435" d="M756 545c0 -95 -105 -169 -209 -188c97 -11 155 -69 155 -141c0 -98 -118 -216 -276 -216h-357c-18 0 -27 0 -27 11c0 20 10 20 27 20c79 0 81 8 91 47l134 537c3 12 4 15 4 19c0 13 -9 14 -27 16c-17 2 -38 2 -38 2c-19 0 -28 0 -28 11c0 20 10 20 29 20h336 c120 0 186 -64 186 -138zM665 549c0 44 -21 103 -109 103h-129c-43 0 -45 -3 -54 -38l-62 -248h146c122 0 208 95 208 183zM609 227c0 43 -19 117 -115 117h-189l-69 -279c-5 -18 -5 -20 -5 -23c0 -8 3 -9 13 -10c6 -1 8 -1 22 -1h136c118 0 207 97 207 196Z"></path>
<path stroke-width="10" id="E1-LATINMODERNNORMAL-1D465" d="M527 376c0 -40 -32 -58 -54 -58c-27 0 -38 19 -38 35c0 24 20 49 48 54c-21 13 -45 13 -50 13c-70 0 -93 -92 -99 -118l-34 -137c-11 -44 -17 -66 -17 -88c0 -34 16 -66 55 -66c32 0 100 24 133 131c2 7 4 11 13 11c3 0 12 0 12 -10c0 -25 -57 -154 -160 -154 c-60 0 -96 39 -108 76c-3 -6 -39 -76 -105 -76c-44 0 -94 20 -94 66c0 32 25 58 55 58c15 0 37 -8 37 -35c0 -28 -22 -49 -47 -54c21 -13 44 -13 50 -13c44 0 79 42 95 104c37 140 54 207 54 238c0 58 -35 67 -54 67c-34 0 -100 -25 -134 -131c-2 -9 -5 -11 -13 -11 c0 0 -12 0 -12 10c0 25 57 154 161 154c29 0 83 -10 108 -76c12 23 47 76 105 76c34 0 93 -14 93 -66Z"></path>
<path stroke-width="10" id="E1-LATINMODERNMAIN-2B" d="M722 250c0 -11 -9 -20 -20 -20h-293v-293c0 -11 -9 -20 -20 -20s-20 9 -20 20v293h-293c-11 0 -20 9 -20 20s9 20 20 20h293v293c0 11 9 20 20 20s20 -9 20 -20v-293h293c11 0 20 -9 20 -20Z"></path>
<path stroke-width="10" id="E1-LATINMODERNMAIN-28" d="M332 -238c0 -5 -5 -10 -10 -10c-2 0 -4 1 -6 2c-110 83 -215 283 -215 454v84c0 171 105 371 215 454c2 1 4 2 6 2c5 0 10 -5 10 -10c0 -3 -2 -6 -4 -8c-104 -78 -173 -278 -173 -438v-84c0 -160 69 -360 173 -438c2 -2 4 -5 4 -8Z"></path>
<path stroke-width="10" id="E1-LATINMODERNMAIN-2212" d="M722 250c0 -11 -9 -20 -20 -20h-626c-11 0 -20 9 -20 20s9 20 20 20h626c11 0 20 -9 20 -20Z"></path>
<path stroke-width="10" id="E1-LATINMODERNNORMAL-1D434" d="M721 20c0 -20 -12 -20 -18 -20c-25 0 -88 3 -113 3c-41 0 -84 -3 -125 -3c0 0 -14 0 -14 11c0 20 10 20 24 20c20 0 72 3 72 33c0 10 -14 146 -16 167h-251c-68 -116 -69 -116 -76 -128c-8 -14 -14 -25 -14 -37c0 -25 24 -33 47 -35c7 0 16 -1 16 -12 c0 -19 -13 -19 -19 -19c-32 0 -67 3 -100 3c-28 0 -59 -3 -86 -3c-8 0 -13 5 -13 11c0 19 9 19 21 20c44 3 83 17 123 84l348 584c6 10 10 17 26 17c17 0 17 -4 19 -24l61 -625c3 -29 3 -36 65 -36c13 0 23 0 23 -11zM528 262l-32 330l-197 -330h229Z"></path>
<path stroke-width="10" id="E1-LATINMODERNMAIN-29" d="M288 208c0 -171 -105 -371 -215 -454c-2 -1 -4 -2 -6 -2c-5 0 -10 5 -10 10c0 3 2 6 4 8c104 78 173 278 173 438v84c0 160 -69 360 -173 438c-2 2 -4 5 -4 8c0 5 5 10 10 10c2 0 4 -1 6 -2c110 -83 215 -283 215 -454v-84Z"></path>
<path stroke-width="10" id="E1-LATINMODERNNORMAL-1D466" d="M490 404c0 -7 0 -9 -4 -23l-96 -382c-28 -113 -131 -204 -234 -204c-62 0 -106 37 -106 87c0 49 33 65 56 65c10 0 37 -4 37 -35c0 -19 -10 -32 -20 -41c-14 -12 -27 -12 -43 -12c17 -39 62 -42 76 -42c46 0 84 29 110 63c40 53 52 102 65 154c-28 -28 -62 -45 -101 -45 c-59 0 -122 30 -122 119c0 47 18 104 58 210c7 19 17 45 17 70c0 32 -17 32 -25 32c-34 0 -74 -30 -101 -124c-5 -16 -6 -18 -16 -18c0 0 -12 0 -12 10c0 9 37 154 132 154c50 0 82 -37 82 -82c0 -20 -4 -31 -20 -72c-34 -88 -51 -150 -51 -196c0 -37 11 -81 62 -81 c66 0 109 70 113 85l45 180l20 80c4 18 12 49 14 54c9 15 25 21 35 21c15 0 29 -9 29 -27Z"></path>
<path stroke-width="10" id="E1-LATINMODERNMAIN-5D" d="M164 -250h-122c-11 0 -20 9 -20 20s9 20 20 20h82v920h-82c-11 0 -20 9 -20 20s9 20 20 20h122v-1000Z"></path>
<path stroke-width="10" id="E1-LATINMODERNSIZE6-5B" d="M509 -921c0 -16 -13 -29 -29 -29h-247v2400h247c16 0 29 -13 29 -29s-13 -29 -29 -29h-189v-2284h189c16 0 29 -13 29 -29Z"></path>
<path stroke-width="10" id="E1-LATINMODERNSIZE6-5D" d="M295 1450v-2400h-247c-16 0 -29 13 -29 29s13 29 29 29h189v2284h-189c-16 0 -29 13 -29 29s13 29 29 29h247Z"></path>
<path stroke-width="10" id="E1-LATINMODERNMAIN-32" d="M449 174l-28 -174h-371c0 24 0 26 11 37l192 214c55 62 105 141 105 221c0 82 -43 163 -134 163c-58 0 -112 -37 -135 -102c3 1 5 1 13 1c35 0 53 -26 53 -52c0 -41 -35 -53 -52 -53c-3 0 -53 0 -53 56c0 89 74 181 187 181c122 0 212 -80 212 -194 c0 -100 -60 -154 -216 -292l-106 -103h180c22 0 88 0 95 8c10 15 17 59 22 89h25Z"></path>
</defs>
<g stroke="currentColor" fill="currentColor" stroke-width="0" transform="matrix(1 0 0 -1 0 0)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D440" x="0" y="0"></use>
<use xlink:href="#E1-LATINMODERNNORMAL-1D456" x="1049" y="0"></use>
<use xlink:href="#E1-LATINMODERNNORMAL-1D45F" x="1399" y="0"></use>
<use xlink:href="#E1-LATINMODERNNORMAL-1D45F" x="1855" y="0"></use>
<use xlink:href="#E1-LATINMODERNNORMAL-1D45C" x="2311" y="0"></use>
<use xlink:href="#E1-LATINMODERNNORMAL-1D45F" x="2801" y="0"></use>
<use xlink:href="#E1-LATINMODERNNORMAL-1D452" x="3257" y="0"></use>
<use xlink:href="#E1-LATINMODERNNORMAL-1D451" x="3728" y="0"></use>
<use xlink:href="#E1-LATINMODERNMAIN-3D" x="4530" y="0"></use>
<g transform="translate(5591,0)">
<use xlink:href="#E1-LATINMODERNSIZE6-5B"></use>
<g transform="translate(700,0)">
<g transform="translate(-11,0)">
<g transform="translate(0,730)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D435" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNNORMAL-1D465" x="1080" y="-213"></use>
<use xlink:href="#E1-LATINMODERNMAIN-2B" x="1494" y="0"></use>
<use xlink:href="#E1-LATINMODERNMAIN-28" x="2499" y="0"></use>
<g transform="translate(2893,0)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D435" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNNORMAL-1D465" x="1080" y="-213"></use>
</g>
<use xlink:href="#E1-LATINMODERNMAIN-2212" x="4387" y="0"></use>
<g transform="translate(5392,0)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D434" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNNORMAL-1D465" x="1067" y="-213"></use>
</g>
<use xlink:href="#E1-LATINMODERNMAIN-29" x="6655" y="0"></use>
</g>
<g transform="translate(86,-728)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D435" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNNORMAL-1D466" x="1080" y="-213"></use>
<use xlink:href="#E1-LATINMODERNMAIN-2B" x="1436" y="0"></use>
<use xlink:href="#E1-LATINMODERNMAIN-28" x="2441" y="0"></use>
<g transform="translate(2835,0)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D435" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNNORMAL-1D466" x="1080" y="-213"></use>
</g>
<use xlink:href="#E1-LATINMODERNMAIN-2212" x="4271" y="0"></use>
<g transform="translate(5276,0)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D434" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNNORMAL-1D466" x="1067" y="-213"></use>
</g>
<use xlink:href="#E1-LATINMODERNMAIN-29" x="6481" y="0"></use>
</g>
</g>
</g>
<use xlink:href="#E1-LATINMODERNSIZE6-5D" x="7906" y="0"></use>
</g>
<use xlink:href="#E1-LATINMODERNMAIN-3D" x="14308" y="0"></use>
<g transform="translate(15369,0)">
<use xlink:href="#E1-LATINMODERNSIZE6-5B"></use>
<g transform="translate(700,0)">
<g transform="translate(-11,0)">
<g transform="translate(0,701)">
<use xlink:href="#E1-LATINMODERNMAIN-32" x="0" y="0"></use>
<g transform="translate(505,0)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D435" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNNORMAL-1D465" x="1080" y="-213"></use>
</g>
<use xlink:href="#E1-LATINMODERNMAIN-2212" x="1999" y="0"></use>
<g transform="translate(3004,0)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D434" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNNORMAL-1D465" x="1067" y="-213"></use>
</g>
</g>
<g transform="translate(57,-699)">
<use xlink:href="#E1-LATINMODERNMAIN-32" x="0" y="0"></use>
<g transform="translate(505,0)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D435" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNNORMAL-1D466" x="1080" y="-213"></use>
</g>
<use xlink:href="#E1-LATINMODERNMAIN-2212" x="1941" y="0"></use>
<g transform="translate(2946,0)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D434" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNNORMAL-1D466" x="1067" y="-213"></use>
</g>
</g>
</g>
</g>
<use xlink:href="#E1-LATINMODERNSIZE6-5D" x="5123" y="0"></use>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,38 @@
<svg xmlns:xlink="http://www.w3.org/1999/xlink" width="18.667ex" height="2.833ex" style="vertical-align: -0.667ex; margin-left: 0ex; margin-right: 0ex; margin-bottom: 1px; margin-top: 1px;" viewBox="0 -962.8 8065.8 1234.8" xmlns="http://www.w3.org/2000/svg">
<defs>
<path stroke-width="10" id="E1-LATINMODERNNORMAL-1D435" d="M756 545c0 -95 -105 -169 -209 -188c97 -11 155 -69 155 -141c0 -98 -118 -216 -276 -216h-357c-18 0 -27 0 -27 11c0 20 10 20 27 20c79 0 81 8 91 47l134 537c3 12 4 15 4 19c0 13 -9 14 -27 16c-17 2 -38 2 -38 2c-19 0 -28 0 -28 11c0 20 10 20 29 20h336 c120 0 186 -64 186 -138zM665 549c0 44 -21 103 -109 103h-129c-43 0 -45 -3 -54 -38l-62 -248h146c122 0 208 95 208 183zM609 227c0 43 -19 117 -115 117h-189l-69 -279c-5 -18 -5 -20 -5 -23c0 -8 3 -9 13 -10c6 -1 8 -1 22 -1h136c118 0 207 97 207 196Z"></path>
<path stroke-width="10" id="E1-LATINMODERNMAIN-2032" d="M251 710c0 -7 -2 -14 -6 -19l-158 -261h-27l120 297c4 11 18 21 33 21c21 0 38 -17 38 -38Z"></path>
<path stroke-width="10" id="E1-LATINMODERNMAIN-28" d="M332 -238c0 -5 -5 -10 -10 -10c-2 0 -4 1 -6 2c-110 83 -215 283 -215 454v84c0 171 105 371 215 454c2 1 4 2 6 2c5 0 10 -5 10 -10c0 -3 -2 -6 -4 -8c-104 -78 -173 -278 -173 -438v-84c0 -160 69 -360 173 -438c2 -2 4 -5 4 -8Z"></path>
<path stroke-width="10" id="E1-LATINMODERNMAIN-31" d="M419 0c-35 3 -122 3 -162 3s-127 0 -162 -3v31h32c90 0 93 12 93 48v518c-52 -26 -111 -26 -131 -26v31c32 0 120 0 182 64c23 0 23 -2 23 -26v-561c0 -37 3 -48 93 -48h32v-31Z"></path>
<path stroke-width="10" id="E1-LATINMODERNMAIN-29" d="M288 208c0 -171 -105 -371 -215 -454c-2 -1 -4 -2 -6 -2c-5 0 -10 5 -10 10c0 3 2 6 4 8c104 78 173 278 173 438v84c0 160 -69 360 -173 438c-2 2 -4 5 -4 8c0 5 5 10 10 10c2 0 4 -1 6 -2c110 -83 215 -283 215 -454v-84Z"></path>
<path stroke-width="10" id="E1-LATINMODERNNORMAL-1D45B" d="M571 143c0 -8 -37 -154 -131 -154c-47 0 -82 35 -82 82c0 11 1 23 10 46c16 43 65 171 65 233c0 33 -9 70 -54 70c-95 0 -148 -91 -163 -122l-13 -50c-5 -23 -11 -45 -17 -67l-22 -90c-6 -25 -18 -72 -19 -74c-7 -20 -25 -28 -37 -28c-15 0 -29 9 -29 27c0 5 6 28 9 43 l58 231c13 52 16 63 16 84c0 33 -11 46 -31 46c-36 0 -56 -48 -73 -119c-6 -22 -7 -23 -17 -23c0 0 -12 0 -12 10c0 4 14 63 30 97c10 18 29 57 75 57s87 -31 92 -87c17 23 66 87 156 87c72 0 115 -40 115 -107c0 -57 -42 -167 -61 -220c-9 -22 -18 -46 -18 -71 c0 -23 7 -33 24 -33c49 0 82 56 102 124c5 15 5 18 15 18c3 0 12 0 12 -10Z"></path>
<path stroke-width="10" id="E1-LATINMODERNMAIN-3D" d="M722 347c0 -11 -9 -20 -20 -20h-626c-11 0 -20 9 -20 20s9 20 20 20h626c11 0 20 -9 20 -20zM722 153c0 -11 -9 -20 -20 -20h-626c-11 0 -20 9 -20 20s9 20 20 20h626c11 0 20 -9 20 -20Z"></path>
<path stroke-width="10" id="E1-LATINMODERNMAIN-30" d="M460 320c0 -79 -5 -157 -37 -226c-44 -95 -120 -116 -174 -116c-49 0 -122 20 -165 101c-41 76 -45 166 -45 241c0 80 5 158 37 227c41 93 114 119 174 119c42 0 124 -16 170 -112c35 -74 40 -154 40 -234zM377 332c0 63 0 139 -10 195c-19 99 -85 117 -118 117 c-25 0 -100 -9 -119 -128c-8 -54 -8 -120 -8 -184c0 -59 0 -151 11 -211c18 -96 77 -121 116 -121c45 0 102 30 117 125c11 64 11 132 11 207Z"></path>
<path stroke-width="10" id="E1-LATINMODERNMAIN-2B" d="M722 250c0 -11 -9 -20 -20 -20h-293v-293c0 -11 -9 -20 -20 -20s-20 9 -20 20v293h-293c-11 0 -20 9 -20 20s9 20 20 20h293v293c0 11 9 20 20 20s20 -9 20 -20v-293h293c11 0 20 -9 20 -20Z"></path>
</defs>
<g stroke="currentColor" fill="currentColor" stroke-width="0" transform="matrix(1 0 0 -1 0 0)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D435" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNMAIN-2032" x="1080" y="583"></use>
<use xlink:href="#E1-LATINMODERNMAIN-28" x="1087" y="0"></use>
<use xlink:href="#E1-LATINMODERNMAIN-31" x="1481" y="0"></use>
<g transform="translate(1986,0)">
<use xlink:href="#E1-LATINMODERNMAIN-29" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNNORMAL-1D45B" x="557" y="-213"></use>
</g>
<use xlink:href="#E1-LATINMODERNMAIN-3D" x="3186" y="0"></use>
<g transform="translate(4246,0)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D435" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNMAIN-2032" x="1080" y="583"></use>
</g>
<use xlink:href="#E1-LATINMODERNMAIN-28" x="5334" y="0"></use>
<use xlink:href="#E1-LATINMODERNMAIN-30" x="5728" y="0"></use>
<g transform="translate(6233,0)">
<use xlink:href="#E1-LATINMODERNMAIN-29" x="0" y="0"></use>
<g transform="translate(394,-150)">
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNNORMAL-1D45B" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNMAIN-2B" x="605" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNMAIN-31" x="1388" y="0"></use>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.6 KiB