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

all the moulding sections

This commit is contained in:
Pomax
2016-01-07 14:08:16 -08:00
parent 4f3c475691
commit f08e3d222a
16 changed files with 1425 additions and 465 deletions

View File

@@ -63,7 +63,7 @@
var React = __webpack_require__(9); var React = __webpack_require__(9);
var ReactDOM = __webpack_require__(166); var ReactDOM = __webpack_require__(166);
var Article = __webpack_require__(167); var Article = __webpack_require__(167);
var style = __webpack_require__(203); var style = __webpack_require__(205);
ReactDOM.render(React.createElement(Article, null), document.getElementById("article"), function () { ReactDOM.render(React.createElement(Article, null), document.getElementById("article"), function () {
// trigger a #hash navigation // trigger a #hash navigation
@@ -19817,12 +19817,13 @@
intersections: __webpack_require__(200), intersections: __webpack_require__(200),
curveintersection: __webpack_require__(201), curveintersection: __webpack_require__(201),
moulding: __webpack_require__(202)
abc: __webpack_require__(202),
moulding: __webpack_require__(203),
pointcurves: __webpack_require__(204)
}; };
/* /*
pointcurves: require("./pointcurves"),
catmullconv: require("./catmullconv"), catmullconv: require("./catmullconv"),
catmullmoulding: require("./catmullmoulding"), catmullmoulding: require("./catmullmoulding"),
@@ -19840,8 +19841,7 @@
*/ */
/* /*
Curve moulding (using the projection ratio)
Creating a curve from three points
Bézier curves and Catmull-Rom curves Bézier curves and Catmull-Rom curves
Creating a Catmull-Rom curve from three points Creating a Catmull-Rom curve from three points
Forming poly-Bézier curves Forming poly-Bézier curves
@@ -20063,13 +20063,16 @@
e.offsetY = e.clientY - rect.top; e.offsetY = e.clientY - rect.top;
}; };
var Bezier = __webpack_require__(175);
var Graphic = React.createClass({ var Graphic = React.createClass({
displayName: "Graphic", displayName: "Graphic",
defaultWidth: 275, defaultWidth: 275,
defaultHeight: 275, defaultHeight: 275,
Bezier: __webpack_require__(175), Bezier: Bezier,
utils: Bezier.getUtils(),
curve: false, curve: false,
mx: 0, mx: 0,
my: 0, my: 0,
@@ -20218,7 +20221,7 @@
break; break;
} }
} }
} else { } else if (this.curve && this.curve.update) {
this.curve.update(); this.curve.update();
} }
} }
@@ -20239,7 +20242,6 @@
mouseUp: function mouseUp(evt) { mouseUp: function mouseUp(evt) {
this.down = false; this.down = false;
this.dragging = false;
if (!this.moving) { if (!this.moving) {
if (this.props.onMouseUp) { if (this.props.onMouseUp) {
this.props.onMouseUp(evt, this); this.props.onMouseUp(evt, this);
@@ -20607,13 +20609,13 @@
this.ctx.stroke(); this.ctx.stroke();
}, },
text: function text(_text, offset) { text: function text(_text, coord, offset) {
offset = offset || { x: 0, y: 0 }; offset = offset || { x: 0, y: 0 };
if (this.offset) { if (this.offset) {
offset.x += this.offset.x; offset.x += this.offset.x;
offset.y += this.offset.y; offset.y += this.offset.y;
} }
this.ctx.fillText(_text, offset.x, offset.y); this.ctx.fillText(_text, coord.x + offset.x, coord.y + offset.y);
}, },
image: function image(_image, offset) { image: function image(_image, offset) {
@@ -30159,7 +30161,6 @@
var curve = api.getDefaultCubic(); var curve = api.getDefaultCubic();
api.setCurve(curve); api.setCurve(curve);
api.steps = 8; api.steps = 8;
this.map = curve.getUtils().map;
}, },
generate: function generate(api, curve, offset, pad, fwh) { generate: function generate(api, curve, offset, pad, fwh) {
@@ -30171,8 +30172,8 @@
t = v / 100; t = v / 100;
d = curve.split(t).left.length(); d = curve.split(t).left.length();
pts.push({ pts.push({
x: this.map(t, 0, 1, 0, fwh), x: api.utils.map(t, 0, 1, 0, fwh),
y: this.map(d, 0, len, 0, fwh), y: api.utils.map(d, 0, len, 0, fwh),
d: d, d: d,
t: t t: t
}); });
@@ -30225,8 +30226,6 @@
}, },
drawColoured: function drawColoured(api, curve) { drawColoured: function drawColoured(api, curve) {
var _this = this;
api.setPanelCount(3); api.setPanelCount(3);
var w = api.getPanelWidth(); var w = api.getPanelWidth();
var h = api.getPanelHeight(); var h = api.getPanelHeight();
@@ -30259,8 +30258,8 @@
} }
ts.forEach(function (p) { ts.forEach(function (p) {
var pt = { x: _this.map(p.t, 0, 1, 0, fwh), y: 0 }; var pt = { x: api.utils.map(p.t, 0, 1, 0, fwh), y: 0 };
var pd = { x: 0, y: _this.map(p.d, 0, len, 0, fwh) }; var pd = { x: 0, y: api.utils.map(p.d, 0, len, 0, fwh) };
api.setColor("black"); api.setColor("black");
api.drawCircle(pt, 3, offset); api.drawCircle(pt, 3, offset);
api.drawCircle(pd, 3, offset); api.drawCircle(pd, 3, offset);
@@ -30438,7 +30437,7 @@
drawLineIntersection: function drawLineIntersection(api, curves) { drawLineIntersection: function drawLineIntersection(api, curves) {
api.reset(); api.reset();
var lli = curves[0].getUtils().lli4; var lli = api.utils.lli4;
var p = lli(curves[0].points[0], curves[0].points[1], curves[1].points[0], curves[1].points[1]); var p = lli(curves[0].points[0], curves[0].points[1], curves[1].points[0], curves[1].points[1]);
var mark = 0; var mark = 0;
@@ -30484,7 +30483,7 @@
api.drawCurve(curve); api.drawCurve(curve);
}); });
var utils = curves[0].getUtils(); var utils = api.utils;
var line = { p1: curves[1].points[0], p2: curves[1].points[1] }; var line = { p1: curves[1].points[0], p2: curves[1].points[1] };
var acpts = utils.align(curves[0].points, line); var acpts = utils.align(curves[0].points, line);
var nB = new api.Bezier(acpts); var nB = new api.Bezier(acpts);
@@ -31020,15 +31019,21 @@
var abs = Math.abs; var abs = Math.abs;
var Moulding = React.createClass({ var ABC = React.createClass({
displayName: "Moulding", displayName: "ABC",
getDefaultProps: function getDefaultProps() { getDefaultProps: function getDefaultProps() {
return { return {
title: "Moulding a curve" title: "The 'ABC' curve identity"
}; };
}, },
onClick: function onClick(evt, api) {
api.t = api.curve.on({ x: evt.offsetX, y: evt.offsetY }, 7);
if (api.t < 0.05 || api.t > 0.95) api.t = false;
api.redraw();
},
setupQuadratic: function setupQuadratic(api) { setupQuadratic: function setupQuadratic(api) {
var curve = api.getDefaultQuadratic(); var curve = api.getDefaultQuadratic();
curve.points[0].y -= 10; curve.points[0].y -= 10;
@@ -31054,7 +31059,7 @@
api.drawCircle(api.curve.get(api.t), 3); api.drawCircle(api.curve.get(api.t), 3);
api.setColor("lightgrey"); api.setColor("lightgrey");
var hull = api.drawHull(curve, api.t); var hull = api.drawHull(curve, api.t);
var utils = api.curve.getUtils(); var utils = api.utils;
var A, B, C; var A, B, C;
@@ -31088,159 +31093,7 @@
var d2 = utils.dist(B, C); var d2 = utils.dist(B, C);
var ratio = d1 / d2; var ratio = d1 / d2;
api.text("d1 (A-B): " + utils.round(d1, 2) + ", d2 (B-C): " + utils.round(d2, 2) + ", ratio (d1/d2): " + utils.round(ratio, 4), { x: 10, y: h - 2 }); api.text("d1 (A-B): " + utils.round(d1, 2) + ", d2 (B-C): " + utils.round(d2, 2) + ", ratio (d1/d2): " + utils.round(ratio, 4), { x: 10, y: h - 7 });
}
},
onClickWithRedraw: function onClickWithRedraw(evt, api) {
this.onClick(evt, api);
api.redraw();
},
onClick: function onClick(evt, api) {
api.t = api.curve.on({ x: evt.offsetX, y: evt.offsetY }, 7);
if (api.t < 0.05 || api.t > 0.95) api.t = false;
},
markQB: function markQB(evt, api) {
this.onClick(evt, api);
if (api.t) {
var t = api.t,
t2 = 2 * t,
top = t2 * t - t2,
bottom = top + 1,
ratio = abs(top / bottom),
curve = api.curve,
A = api.A = curve.points[1],
B = api.B = curve.get(t);
api.C = curve.getUtils().lli4(A, B, curve.points[0], curve.points[2]);
api.ratio = ratio;
}
},
markCB: function markCB(evt, api) {
this.onClick(evt, api);
if (api.t) {
var t = api.t,
mt = 1 - t,
t3 = t * t * t,
mt3 = mt * mt * mt,
bottom = t3 + mt3,
top = bottom - 1,
ratio = abs(top / bottom),
curve = api.curve,
hull = curve.hull(t),
A = api.A = hull[5],
B = api.B = curve.get(t),
db = api.db = curve.derivative(t);
api.C = curve.getUtils().lli4(A, B, curve.points[0], curve.points[3]);
api.ratio = ratio;
}
},
drag: function drag(evt, api) {
if (!api.t) return;
var newB = api.newB = {
x: evt.offsetX,
y: evt.offsetY
};
// find the current ABC and ratio values:
var A = api.A;
var B = api.B;
var C = api.C;
// now that we know A, B, C and the AB:BC ratio, we can compute the new A' based on the desired B'
var newA = api.newA = {
x: newB.x - (C.x - newB.x) / api.ratio,
y: newB.y - (C.y - newB.y) / api.ratio
};
},
dragQB: function dragQB(evt, api) {
if (!api.t) return;
this.drag(evt, api);
var curve = api.curve;
api.update = [api.newA];
},
dragCB: function dragCB(evt, api) {
if (!api.t) return;
this.drag(evt, api);
// preserve struts for B when repositioning
var curve = api.curve,
hull = curve.hull(api.t),
B = api.B,
Bl = hull[7],
Br = hull[8],
dbl = { x: Bl.x - B.x, y: Bl.y - B.y },
dbr = { x: Br.x - B.x, y: Br.y - B.y },
pts = curve.points,
// find new point on s--c1
p1 = { x: api.newB.x + dbl.x, y: api.newB.y + dbl.y },
sc1 = {
x: api.newA.x - (api.newA.x - p1.x) / (1 - api.t),
y: api.newA.y - (api.newA.y - p1.y) / (1 - api.t)
},
// find new point on c2--e
p2 = { x: api.newB.x + dbr.x, y: api.newB.y + dbr.y },
sc2 = {
x: api.newA.x + (p2.x - api.newA.x) / api.t,
y: api.newA.y + (p2.y - api.newA.y) / api.t
},
// construct new c1` based on the fact that s--sc1 is s--c1 * t
nc1 = {
x: pts[0].x + (sc1.x - pts[0].x) / api.t,
y: pts[0].y + (sc1.y - pts[0].y) / api.t
},
// construct new c2` based on the fact that e--sc2 is e--c2 * (1-t)
nc2 = {
x: pts[3].x - (pts[3].x - sc2.x) / (1 - api.t),
y: pts[3].y - (pts[3].y - sc2.y) / (1 - api.t)
};
api.p1 = p1;
api.p2 = p2;
api.sc1 = sc1;
api.sc2 = sc2;
api.nc1 = nc1;
api.nc2 = nc2;
api.update = [nc1, nc2];
},
commit: function commit(evt, api) {
if (!api.t) return;
api.setCurve(api.newcurve);
api.t = false;
api.redraw();
},
drawMould: function drawMould(api, curve) {
api.reset();
api.drawSkeleton(curve);
api.drawCurve(curve);
if (api.t) {
api.npts = [curve.points[0]].concat(api.update).concat([curve.points.slice(-1)[0]]);
api.newcurve = new api.Bezier(api.npts);
api.drawCurve(api.newcurve);
api.setColor("lightgrey");
api.drawHull(api.newcurve, api.t);
api.drawLine(api.npts[0], api.npts.slice(-1)[0]);
api.drawLine(api.newA, api.C);
api.setColor("grey");
api.drawCircle(api.newB, 3);
api.drawCircle(api.newA, 3);
api.drawCircle(api.C, 3);
} }
}, },
@@ -31303,9 +31156,9 @@
"div", "div",
{ className: "figure" }, { className: "figure" },
React.createElement(Graphic, { inline: true, preset: "abc", title: "Projections in a quadratic Bézier curve", React.createElement(Graphic, { inline: true, preset: "abc", title: "Projections in a quadratic Bézier curve",
setup: this.setupQuadratic, draw: this.draw, onClick: this.onClickWithRedraw }), setup: this.setupQuadratic, draw: this.draw, onClick: this.onClick }),
React.createElement(Graphic, { inline: true, preset: "abc", title: "Projections in a cubic Bézier curve", React.createElement(Graphic, { inline: true, preset: "abc", title: "Projections in a cubic Bézier curve",
setup: this.setupCubic, draw: this.draw, onClick: this.onClickWithRedraw }) setup: this.setupCubic, draw: this.draw, onClick: this.onClick })
), ),
React.createElement( React.createElement(
"p", "p",
@@ -31521,33 +31374,315 @@
), ),
" onto the line between start and end may actually lie on that line before the start, or after the end, and there are no simple ratios that we can exploit." " onto the line between start and end may actually lie on that line before the start, or after the end, and there are no simple ratios that we can exploit."
) )
)
);
}
});
module.exports = ABC;
/***/ },
/* 203 */
/***/ function(module, exports, __webpack_require__) {
"use strict";
var React = __webpack_require__(9);
var Graphic = __webpack_require__(172);
var SectionHeader = __webpack_require__(177);
var abs = Math.abs;
var Moulding = React.createClass({
displayName: "Moulding",
getDefaultProps: function getDefaultProps() {
return {
title: "Manipulating a curve"
};
},
setupQuadratic: function setupQuadratic(api) {
api.setPanelCount(3);
var curve = api.getDefaultQuadratic();
curve.points[2].x -= 30;
api.setCurve(curve);
},
setupCubic: function setupCubic(api) {
api.setPanelCount(3);
var curve = new api.Bezier([100, 230, 30, 160, 200, 50, 210, 160]);
curve.points[2].y -= 20;
api.setCurve(curve);
api.lut = curve.getLUT(100);
},
saveCurve: function saveCurve(evt, api) {
if (!api.t) return;
api.setCurve(api.newcurve);
api.t = false;
api.redraw();
},
findTValue: function findTValue(evt, api) {
var t = api.curve.on({ x: evt.offsetX, y: evt.offsetY }, 7);
if (t < 0.05 || t > 0.95) return false;
return t;
},
markQB: function markQB(evt, api) {
api.t = this.findTValue(evt, api);
if (api.t) {
var t = api.t,
t2 = 2 * t,
top = t2 * t - t2,
bottom = top + 1,
ratio = abs(top / bottom),
curve = api.curve,
A = api.A = curve.points[1],
B = api.B = curve.get(t);
api.C = api.utils.lli4(A, B, curve.points[0], curve.points[2]);
api.ratio = ratio;
}
},
markCB: function markCB(evt, api) {
api.t = this.findTValue(evt, api);
if (api.t) {
var t = api.t,
mt = 1 - t,
t3 = t * t * t,
mt3 = mt * mt * mt,
bottom = t3 + mt3,
top = bottom - 1,
ratio = abs(top / bottom),
curve = api.curve,
hull = curve.hull(t),
A = api.A = hull[5],
B = api.B = curve.get(t),
db = api.db = curve.derivative(t);
api.C = api.utils.lli4(A, B, curve.points[0], curve.points[3]);
api.ratio = ratio;
}
},
drag: function drag(evt, api) {
if (!api.t) return;
var newB = api.newB = {
x: evt.offsetX,
y: evt.offsetY
};
// find the current ABC and ratio values:
var A = api.A;
var B = api.B;
var C = api.C;
// now that we know A, B, C and the AB:BC ratio, we can compute the new A' based on the desired B'
var newA = api.newA = {
x: newB.x - (C.x - newB.x) / api.ratio,
y: newB.y - (C.y - newB.y) / api.ratio
};
},
dragQB: function dragQB(evt, api) {
if (!api.t) return;
this.drag(evt, api);
var curve = api.curve;
api.update = [api.newA];
},
dragCB: function dragCB(evt, api) {
if (!api.t) return;
this.drag(evt, api);
// preserve struts for B when repositioning
var curve = api.curve,
hull = curve.hull(api.t),
B = api.B,
Bl = hull[7],
Br = hull[8],
dbl = { x: Bl.x - B.x, y: Bl.y - B.y },
dbr = { x: Br.x - B.x, y: Br.y - B.y },
pts = curve.points,
// find new point on s--c1
p1 = { x: api.newB.x + dbl.x, y: api.newB.y + dbl.y },
sc1 = {
x: api.newA.x - (api.newA.x - p1.x) / (1 - api.t),
y: api.newA.y - (api.newA.y - p1.y) / (1 - api.t)
},
// find new point on c2--e
p2 = { x: api.newB.x + dbr.x, y: api.newB.y + dbr.y },
sc2 = {
x: api.newA.x + (p2.x - api.newA.x) / api.t,
y: api.newA.y + (p2.y - api.newA.y) / api.t
},
// construct new c1` based on the fact that s--sc1 is s--c1 * t
nc1 = {
x: pts[0].x + (sc1.x - pts[0].x) / api.t,
y: pts[0].y + (sc1.y - pts[0].y) / api.t
},
// construct new c2` based on the fact that e--sc2 is e--c2 * (1-t)
nc2 = {
x: pts[3].x - (pts[3].x - sc2.x) / (1 - api.t),
y: pts[3].y - (pts[3].y - sc2.y) / (1 - api.t)
};
api.p1 = p1;
api.p2 = p2;
api.sc1 = sc1;
api.sc2 = sc2;
api.nc1 = nc1;
api.nc2 = nc2;
api.update = [nc1, nc2];
},
drawMould: function drawMould(api, curve) {
api.reset();
api.drawSkeleton(curve);
api.drawCurve(curve);
var w = api.getPanelWidth(),
h = api.getPanelHeight(),
offset = { x: w, y: 0 },
round = api.utils.round;
api.setColor("black");
api.drawLine({ x: 0, y: 0 }, { x: 0, y: h }, offset);
api.drawLine({ x: w, y: 0 }, { x: w, y: h }, offset);
if (api.t) {
api.drawCircle(curve.get(api.t), 3);
api.npts = [curve.points[0]].concat(api.update).concat([curve.points.slice(-1)[0]]);
api.newcurve = new api.Bezier(api.npts);
api.setColor("lightgrey");
api.drawCurve(api.newcurve);
var newhull = api.drawHull(api.newcurve, api.t, offset);
api.drawLine(api.npts[0], api.npts.slice(-1)[0], offset);
api.drawLine(api.newA, api.newB, offset);
api.setColor("grey");
api.drawCircle(api.newA, 3, offset);
api.setColor("blue");
api.drawCircle(api.B, 3, offset);
api.drawCircle(api.C, 3, offset);
api.drawCircle(api.newB, 3, offset);
api.drawLine(api.B, api.C, offset);
api.drawLine(api.newB, api.C, offset);
api.setFill("black");
api.text("A'", api.newA, { x: offset.x + 7, y: offset.y + 1 });
api.text("start", curve.get(0), { x: offset.x + 7, y: offset.y + 1 });
api.text("end", curve.get(1), { x: offset.x + 7, y: offset.y + 1 });
api.setFill("blue");
api.text("B'", api.newB, { x: offset.x + 7, y: offset.y + 1 });
api.text("B, at t = " + round(api.t, 2), api.B, { x: offset.x + 7, y: offset.y + 1 });
api.text("C", api.C, { x: offset.x + 7, y: offset.y + 1 });
if (curve.order === 3) {
var hull = curve.hull(api.t);
api.drawLine(hull[7], hull[8], offset);
api.drawLine(newhull[7], newhull[8], offset);
api.drawCircle(newhull[7], 3, offset);
api.drawCircle(newhull[8], 3, offset);
api.text("e1", newhull[7], { x: offset.x + 7, y: offset.y + 1 });
api.text("e2", newhull[8], { x: offset.x + 7, y: offset.y + 1 });
}
offset.x += w;
api.setColor("lightgrey");
api.drawSkeleton(api.newcurve, offset);
api.setColor("black");
api.drawCurve(api.newcurve, offset);
} else {
offset.x += w;
api.drawCurve(curve, offset);
}
},
render: function render() {
return React.createElement(
"section",
null,
React.createElement(SectionHeader, this.props),
React.createElement(
"p",
null,
"Armed with knowledge of the \"ABC\" relation, we can now update a curve interactively, by letting people click anywhere on the curve, find the ",
React.createElement(
"em",
null,
"t"
),
"-value matching that coordinate, and then letting them drag that point around. With every drag update we'll have a new point \"B\", which we can combine with the fixed point \"C\" to find our new point A. Once we have those, we can reconstruct the de Casteljau skeleton and thus construct a new curve with the same start/end points as the original curve, passing through the user-selected point B, with correct new control points."
),
React.createElement(Graphic, { preset: "moulding", title: "Moulding a quadratic Bézier curve",
setup: this.setupQuadratic, draw: this.drawMould,
onClick: this.placeMouldPoint, onMouseDown: this.markQB, onMouseDrag: this.dragQB, onMouseUp: this.saveCurve }),
React.createElement(
"p",
null,
"Click-dragging a point on the curve shows what we're using to compute the new coordinates: while dragging you will see the original points B and its corresponding ",
React.createElement(
"i",
null,
"t"
),
"-value, the original point C for that ",
React.createElement(
"i",
null,
"t"
),
"-value, as well as the new point B' based on the mouse cursor. Since we know the ",
React.createElement(
"i",
null,
"t"
),
"-value for this configuration, we can compute the ABC ratio for this configuration, and we know that our new point A' should like at a distance:"
), ),
React.createElement( React.createElement(
"p", "p",
null, null,
"So, with this knowledge, let's change a curve's shape by click-dragging some part of it. The follow graphics let us click-drag somewhere on the curve, repositioning point ", React.createElement("img", { className: "LaTeX SVG", src: "images/latex/462bb8410d6ca4437b8f47450ce72683c61a673e.svg", style: { width: "15.975rem", height: "2.3998500000000003rem" } })
),
React.createElement( React.createElement(
"i", "p",
null, null,
"B" "For quadratic curves, this means we're done, since the new point A' is equivalent to the new quadratic control point. For cubic curves, we need to do a little more work:"
), ),
" according to a simple rule: we keep the original point ", React.createElement(Graphic, { preset: "moulding", title: "Moulding a cubic Bézier curve",
React.createElement(
"i",
null,
"B"
),
"'s tangent:"
),
React.createElement(
"div",
{ className: "figure" },
React.createElement(Graphic, { inline: true, preset: "moulding", title: "Moulding a quadratic Bézier curve",
setup: this.setupQuadratic, draw: this.drawMould,
onClick: this.placeMouldPoint, onMouseDown: this.markQB, onMouseDrag: this.dragQB, onMouseUp: this.commit }),
React.createElement(Graphic, { inline: true, preset: "moulding", title: "Moulding a cubic Bézier curve",
setup: this.setupCubic, draw: this.drawMould, setup: this.setupCubic, draw: this.drawMould,
onClick: this.placeMouldPoint, onMouseDown: this.markCB, onMouseDrag: this.dragCB, onMouseUp: this.commit }) onClick: this.placeMouldPoint, onMouseDown: this.markCB, onMouseDrag: this.dragCB, onMouseUp: this.saveCurve }),
React.createElement(
"p",
null,
"To help understand what's going on, the cubic graphic shows the full de Casteljau construction \"hull\" when repositioning point B. We compute A` in exactly the same way as before, but we also record the final strut line that forms B in the original curve. Given A', B', and the endpoints e1 and e2 of the strut line relative to B', we can now compute where the new control points should be. Remember that B' lies on line e1--e2 at a distance ",
React.createElement(
"i",
null,
"t"
),
", because that's how Bézier curves work. In the same manner, we know the distance A--e1 is only line-interval [0,t] of the full segment, and A--e2 is only line-interval [t,1], so constructing the new control points is fairly easy:"
),
React.createElement(
"p",
null,
React.createElement("img", { className: "LaTeX SVG", src: "images/latex/f01b855b4fca9fd7a54779aafc8a3b780eba5848.svg", style: { width: "9.59985rem", height: "5.09985rem" } })
),
React.createElement(
"p",
null,
"And that's cubic curve manipulation."
) )
); );
} }
@@ -31556,16 +31691,249 @@
module.exports = Moulding; module.exports = Moulding;
/***/ }, /***/ },
/* 203 */ /* 204 */
/***/ function(module, exports, __webpack_require__) {
"use strict";
var React = __webpack_require__(9);
var Graphic = __webpack_require__(172);
var SectionHeader = __webpack_require__(177);
var abs = Math.abs;
var PointCurves = React.createClass({
displayName: "PointCurves",
getDefaultProps: function getDefaultProps() {
return {
title: "Creating a curve from three points"
};
},
setup: function setup(api) {
api.lpts = [];
},
onClick: function onClick(evt, api) {
if (api.lpts.length == 3) {
api.lpts = [];
}
api.lpts.push({
x: evt.offsetX,
y: evt.offsetY
});
api.redraw();
},
getQRatio: function getQRatio(t) {
var t2 = 2 * t,
top = t2 * t - t2,
bottom = top + 1;
return abs(top / bottom);
},
getCRatio: function getCRatio(t) {
var mt = 1 - t,
t3 = t * t * t,
mt3 = mt * mt * mt,
bottom = t3 + mt3,
top = bottom - 1;
return abs(top / bottom);
},
drawQuadratic: function drawQuadratic(api, curve) {
var w = api.getPanelWidth(),
h = api.getPanelHeight(),
offset = { x: w, y: 0 },
labels = ["start", "t=0.5", "end"];
api.reset();
api.setFill("black");
api.lpts.forEach(function (p, i) {
api.drawCircle(p, 3);
api.text(labels[i], p, { x: 5, y: 2 });
});
api.setColor("black");
api.drawLine({ x: 0, y: 0 }, { x: 0, y: h }, offset);
api.drawLine({ x: w, y: 0 }, { x: w, y: h }, offset);
if (api.lpts.length === 3) {
var S = api.lpts[0],
E = api.lpts[2],
B = api.lpts[1],
C = {
x: (S.x + E.x) / 2,
y: (S.y + E.y) / 2
};
api.setColor("blue");
api.drawLine(S, E);
api.drawLine(B, C);
api.drawCircle(C, 3);
var ratio = this.getQRatio(0.5),
A = {
x: B.x + (B.x - C.x) / ratio,
y: B.y + (B.y - C.y) / ratio
},
curve = new api.Bezier([S, A, E]);
api.setColor("lightgrey");
api.drawLine(A, B);
api.drawLine(A, S);
api.drawLine(A, E);
api.setColor("black");
api.drawCircle(A, 3);
api.drawCurve(curve);
}
},
drawCubic: function drawCubic(api, curve) {
var w = api.getPanelWidth(),
h = api.getPanelHeight(),
offset = { x: w, y: 0 },
labels = ["start", "t=0.5", "end"];
api.reset();
api.setFill("black");
api.lpts.forEach(function (p, i) {
api.drawCircle(p, 3);
api.text(labels[i], p, { x: 5, y: 2 });
});
api.setColor("black");
api.drawLine({ x: 0, y: 0 }, { x: 0, y: h }, offset);
api.drawLine({ x: w, y: 0 }, { x: w, y: h }, offset);
if (api.lpts.length === 3) {
var S = api.lpts[0],
E = api.lpts[2],
B = api.lpts[1],
C = {
x: (S.x + E.x) / 2,
y: (S.y + E.y) / 2
};
api.setColor("blue");
api.drawLine(S, E);
api.drawLine(B, C);
api.drawCircle(C, 3);
var ratio = this.getCRatio(0.5),
A = {
x: B.x + (B.x - C.x) / ratio,
y: B.y + (B.y - C.y) / ratio
},
e1 = {
x: B.x - (E.x - S.x) / 4,
y: B.y - (E.y - S.y) / 4
},
e2 = {
x: B.x + (E.x - S.x) / 4,
y: B.y + (E.y - S.y) / 4
},
v1 = {
x: A.x + (e1.x - A.x) * 2,
y: A.y + (e1.y - A.y) * 2
},
v2 = {
x: A.x + (e2.x - A.x) * 2,
y: A.y + (e2.y - A.y) * 2
},
nc1 = {
x: S.x + (v1.x - S.x) * 2,
y: S.y + (v1.y - S.y) * 2
},
nc2 = {
x: E.x + (v2.x - E.x) * 2,
y: E.y + (v2.y - E.y) * 2
},
curve = new api.Bezier([S, nc1, nc2, E]);
api.drawLine(e1, e2);
api.setColor("lightgrey");
api.drawLine(A, C);
api.drawLine(A, v1);
api.drawLine(A, v2);
api.drawLine(S, nc1);
api.drawLine(E, nc2);
api.drawLine(nc1, nc2);
api.setColor("black");
api.drawCircle(A, 3);
api.drawCircle(nc1, 3);
api.drawCircle(nc2, 3);
api.drawCurve(curve);
}
},
render: function render() {
return React.createElement(
"section",
null,
React.createElement(SectionHeader, this.props),
React.createElement(
"p",
null,
"Given the preceding section on curve manipulation, we can also generate quadratic and cubic curves from any three points. However, unlike circle-fitting, which requires only three points, Bézier curve fitting requires three points, as well as a ",
React.createElement(
"i",
null,
"t"
),
" value (so we can figure out where point 'C' needs to be) and in cade of quadratic curves, a tangent that lets us place those points 'e1' and 'e2' around our point 'B'."
),
React.createElement(
"p",
null,
"There's some freedom here, so for illustrative purposes we're going to pretend ",
React.createElement(
"i",
null,
"t"
),
" is simply 0.5, which puts C in the middle of the start--end line segment, and then we'll also set the cubic curve's tangent to half the length of start--end, centered on B."
),
React.createElement(
"p",
null,
"Using these \"default\" values for curve creation, we can already get fairly respectable curves; Click three times on each of the following sketches to set up the points that should be used to form a quadratic and cubic curve, respectively:"
),
React.createElement(Graphic, { preset: "generate", title: "Fitting a quadratic Bézier curve", setup: this.setup, draw: this.drawQuadratic,
onClick: this.onClick }),
React.createElement(Graphic, { preset: "generate", title: "Fitting a cubic Bézier curve", setup: this.setup, draw: this.drawCubic,
onClick: this.onClick }),
React.createElement(
"p",
null,
"In each graphic, the blue parts are the values that we \"just have\" simply by setting up our three points, and deciding on which ",
React.createElement(
"i",
null,
"t"
),
"-value (and tangent, for cubic curves) we're working with. There are many ways to determine a combination of ",
React.createElement(
"i",
null,
"t"
),
" and tangent values that lead to a more \"aesthetic\" curve, but this will be left as an exercise to the reader, since there are many, and aesthetics are often quite personal."
)
);
}
});
module.exports = PointCurves;
/***/ },
/* 205 */
/***/ function(module, exports, __webpack_require__) { /***/ function(module, exports, __webpack_require__) {
// style-loader: Adds some css to the DOM by adding a <style> tag // style-loader: Adds some css to the DOM by adding a <style> tag
// load the styles // load the styles
var content = __webpack_require__(204); var content = __webpack_require__(206);
if(typeof content === 'string') content = [[module.id, content, '']]; if(typeof content === 'string') content = [[module.id, content, '']];
// add the styles to the DOM // add the styles to the DOM
var update = __webpack_require__(207)(content, {}); var update = __webpack_require__(209)(content, {});
if(content.locals) module.exports = content.locals; if(content.locals) module.exports = content.locals;
// Hot Module Replacement // Hot Module Replacement
if(false) { if(false) {
@@ -31582,21 +31950,21 @@
} }
/***/ }, /***/ },
/* 204 */ /* 206 */
/***/ function(module, exports, __webpack_require__) { /***/ function(module, exports, __webpack_require__) {
exports = module.exports = __webpack_require__(205)(); exports = module.exports = __webpack_require__(207)();
// imports // imports
// module // module
exports.push([module.id, "html,\nbody {\n font-family: Verdana;\n width: 100%;\n margin: 0;\n padding: 0;\n}\nbody {\n background: url(" + __webpack_require__(206) + ");\n font-size: 16px;\n}\nheader,\nsection,\nfooter {\n width: 960px;\n margin: 0 auto;\n}\nheader {\n font-family: Times;\n text-align: center;\n margin-bottom: 2rem;\n}\nheader h1 {\n font-size: 360%;\n margin: 0;\n margin-bottom: 1rem;\n}\nheader h2 {\n font-size: 125%;\n margin: 0;\n}\narticle {\n font-family: Verdana;\n width: 960px;\n height: auto;\n margin: auto;\n background: rgba(255, 255, 255, 0.74);\n border: solid rgba(255, 0, 0, 0.35);\n border-width: 0;\n border-left-width: 1px;\n padding: 1em;\n box-shadow: 25px 0px 25px 25px rgba(255, 255, 255, 0.74);\n}\na,\na:visited {\n color: #0000c8;\n text-decoration: none;\n}\nfooter {\n font-style: italic;\n margin: 2em 0 1em 0;\n background: inherit;\n}\n.ribbon {\n position: fixed;\n top: 0;\n right: 0;\n}\n.ribbon img {\n position: relative;\n z-index: 999;\n}\nnavigation {\n font-family: Georgia;\n display: block;\n width: 70%;\n margin: 0 auto;\n padding: 0;\n border: 1px solid grey;\n}\nnavigation ul {\n background: #F2F2F9;\n list-style: none;\n margin: 0;\n padding: 0.5em 1em;\n}\nnavigation ul li:nth-child(n+2):before {\n content: \"\\A7\" attr(data-number) \". \";\n}\nsection {\n margin-top: 4em;\n}\nsection p {\n text-align: justify;\n}\nsection h2[data-num] {\n border-bottom: 1px solid grey;\n}\nsection h2[data-num]:before {\n content: \"\\A7\" attr(data-num) \" \\2014 \";\n}\nsection h2 a,\nsection h2 a:active,\nsection h2 a:hover,\nsection h2 a:visited {\n text-decoration: none;\n color: inherit;\n}\ndiv.note {\n font-size: 90%;\n margin: 1em 2em;\n padding: 1em;\n border: 1px solid grey;\n background: rgba(150, 150, 50, 0.05);\n}\ndiv.note * {\n margin: 0;\n padding: 0;\n}\ndiv.note p {\n margin: 1em 0;\n}\ndiv.note div.MathJax_Display {\n margin: 1em 0;\n}\n.howtocode {\n border: 1px solid #8d94bd;\n padding: 0 1em;\n margin: 0 2em;\n overflow-x: hidden;\n}\n.howtocode h3 {\n margin: 0 -1em;\n padding: 0;\n background: #91bef7;\n padding-left: 0.5em;\n color: white;\n text-shadow: 1px 1px 0 #000000;\n cursor: pointer;\n}\n.howtocode pre {\n border: 1px solid #8d94bd;\n background: rgba(223, 226, 243, 0.32);\n margin: 0.5em;\n padding: 0.5em;\n}\nfigure {\n display: inline-block;\n border: 1px solid grey;\n background: #F0F0F0;\n padding: 0.5em 0.5em 0 0.5em;\n text-align: center;\n}\nfigure.inline {\n border: none;\n margin: 0;\n}\nfigure canvas {\n display: inline-block;\n background: white;\n border: 1px solid lightgrey;\n}\nfigure canvas:focus {\n border: 1px solid grey;\n}\nfigure figcaption {\n text-align: center;\n padding: 0.5em 0;\n font-style: italic;\n font-size: 90%;\n}\nfigure:not([class=inline]) + figure:not([class=inline]) {\n margin-top: 2em;\n}\ndiv.figure {\n display: inline-block;\n border: 1px solid grey;\n text-align: center;\n}\ngithub-issues {\n position: relative;\n display: block;\n width: 100%;\n border: 1px solid #EEE;\n border-left: 0.3em solid #e5ecf3;\n background: white;\n padding: 0 0.3em;\n width: 95%;\n margin: auto;\n min-height: 33px;\n font: 13px Helvetica, arial, freesans, clean, sans-serif;\n}\ngithub-issues github-issue + github-issue {\n margin-top: 1em;\n}\ngithub-issues github-issue h3 {\n font-size: 100%;\n background: #e5ecf3;\n margin: 0;\n position: relative;\n left: -0.5%;\n width: 101%;\n font-weight: bold;\n border-bottom: 1px solid #999;\n}\ngithub-issues github-issue a {\n position: absolute;\n top: 2px;\n right: 10px;\n padding: 0 4px;\n color: #4183C4!important;\n background: white;\n line-height: 10px;\n font-size: 10px;\n}\nimg.LaTeX {\n display: block;\n margin-left: 2em;\n}\n", ""]); exports.push([module.id, "html,\nbody {\n font-family: Verdana;\n width: 100%;\n margin: 0;\n padding: 0;\n}\nbody {\n background: url(" + __webpack_require__(208) + ");\n font-size: 16px;\n}\nheader,\nsection,\nfooter {\n width: 960px;\n margin: 0 auto;\n}\nheader {\n font-family: Times;\n text-align: center;\n margin-bottom: 2rem;\n}\nheader h1 {\n font-size: 360%;\n margin: 0;\n margin-bottom: 1rem;\n}\nheader h2 {\n font-size: 125%;\n margin: 0;\n}\narticle {\n font-family: Verdana;\n width: 960px;\n height: auto;\n margin: auto;\n background: rgba(255, 255, 255, 0.74);\n border: solid rgba(255, 0, 0, 0.35);\n border-width: 0;\n border-left-width: 1px;\n padding: 1em;\n box-shadow: 25px 0px 25px 25px rgba(255, 255, 255, 0.74);\n}\na,\na:visited {\n color: #0000c8;\n text-decoration: none;\n}\nfooter {\n font-style: italic;\n margin: 2em 0 1em 0;\n background: inherit;\n}\n.ribbon {\n position: fixed;\n top: 0;\n right: 0;\n}\n.ribbon img {\n position: relative;\n z-index: 999;\n}\nnavigation {\n font-family: Georgia;\n display: block;\n width: 70%;\n margin: 0 auto;\n padding: 0;\n border: 1px solid grey;\n}\nnavigation ul {\n background: #F2F2F9;\n list-style: none;\n margin: 0;\n padding: 0.5em 1em;\n}\nnavigation ul li:nth-child(n+2):before {\n content: \"\\A7\" attr(data-number) \". \";\n}\nsection {\n margin-top: 4em;\n}\nsection p {\n text-align: justify;\n}\nsection h2[data-num] {\n border-bottom: 1px solid grey;\n}\nsection h2[data-num]:before {\n content: \"\\A7\" attr(data-num) \" \\2014 \";\n}\nsection h2 a,\nsection h2 a:active,\nsection h2 a:hover,\nsection h2 a:visited {\n text-decoration: none;\n color: inherit;\n}\ndiv.note {\n font-size: 90%;\n margin: 1em 2em;\n padding: 1em;\n border: 1px solid grey;\n background: rgba(150, 150, 50, 0.05);\n}\ndiv.note * {\n margin: 0;\n padding: 0;\n}\ndiv.note p {\n margin: 1em 0;\n}\ndiv.note div.MathJax_Display {\n margin: 1em 0;\n}\n.howtocode {\n border: 1px solid #8d94bd;\n padding: 0 1em;\n margin: 0 2em;\n overflow-x: hidden;\n}\n.howtocode h3 {\n margin: 0 -1em;\n padding: 0;\n background: #91bef7;\n padding-left: 0.5em;\n color: white;\n text-shadow: 1px 1px 0 #000000;\n cursor: pointer;\n}\n.howtocode pre {\n border: 1px solid #8d94bd;\n background: rgba(223, 226, 243, 0.32);\n margin: 0.5em;\n padding: 0.5em;\n}\nfigure {\n display: inline-block;\n border: 1px solid grey;\n background: #F0F0F0;\n padding: 0.5em 0.5em 0 0.5em;\n text-align: center;\n}\nfigure.inline {\n border: none;\n margin: 0;\n}\nfigure canvas {\n display: inline-block;\n background: white;\n border: 1px solid lightgrey;\n}\nfigure canvas:focus {\n border: 1px solid grey;\n}\nfigure figcaption {\n text-align: center;\n padding: 0.5em 0;\n font-style: italic;\n font-size: 90%;\n}\nfigure:not([class=inline]) + figure:not([class=inline]) {\n margin-top: 2em;\n}\ndiv.figure {\n display: inline-block;\n border: 1px solid grey;\n text-align: center;\n}\ngithub-issues {\n position: relative;\n display: block;\n width: 100%;\n border: 1px solid #EEE;\n border-left: 0.3em solid #e5ecf3;\n background: white;\n padding: 0 0.3em;\n width: 95%;\n margin: auto;\n min-height: 33px;\n font: 13px Helvetica, arial, freesans, clean, sans-serif;\n}\ngithub-issues github-issue + github-issue {\n margin-top: 1em;\n}\ngithub-issues github-issue h3 {\n font-size: 100%;\n background: #e5ecf3;\n margin: 0;\n position: relative;\n left: -0.5%;\n width: 101%;\n font-weight: bold;\n border-bottom: 1px solid #999;\n}\ngithub-issues github-issue a {\n position: absolute;\n top: 2px;\n right: 10px;\n padding: 0 4px;\n color: #4183C4!important;\n background: white;\n line-height: 10px;\n font-size: 10px;\n}\nimg.LaTeX {\n display: block;\n margin-left: 2em;\n}\n", ""]);
// exports // exports
/***/ }, /***/ },
/* 205 */ /* 207 */
/***/ function(module, exports) { /***/ function(module, exports) {
/* /*
@@ -31652,13 +32020,13 @@
/***/ }, /***/ },
/* 206 */ /* 208 */
/***/ function(module, exports, __webpack_require__) { /***/ function(module, exports, __webpack_require__) {
module.exports = __webpack_require__.p + "images/packed/7d3b28205544712db60d1bb7973f10f3.png"; module.exports = __webpack_require__.p + "images/packed/7d3b28205544712db60d1bb7973f10f3.png";
/***/ }, /***/ },
/* 207 */ /* 209 */
/***/ function(module, exports, __webpack_require__) { /***/ function(module, exports, __webpack_require__) {
/* /*

View File

@@ -11,12 +11,15 @@ var fix = function(e) {
}; };
var Bezier = require("bezier-js");
var Graphic = React.createClass({ var Graphic = React.createClass({
defaultWidth: 275, defaultWidth: 275,
defaultHeight: 275, defaultHeight: 275,
Bezier: require("bezier-js"), Bezier: Bezier,
utils: Bezier.getUtils(),
curve: false, curve: false,
mx:0, mx:0,
my:0, my:0,
@@ -145,7 +148,7 @@ var Graphic = React.createClass({
break; break;
} }
} }
} else { this.curve.update(); } } else if (this.curve && this.curve.update) { this.curve.update(); }
} }
} }
@@ -164,7 +167,6 @@ var Graphic = React.createClass({
mouseUp: function(evt) { mouseUp: function(evt) {
this.down = false; this.down = false;
this.dragging = false;
if(!this.moving) { if(!this.moving) {
if (this.props.onMouseUp) { if (this.props.onMouseUp) {
this.props.onMouseUp(evt, this); this.props.onMouseUp(evt, this);
@@ -546,13 +548,13 @@ var Graphic = React.createClass({
this.ctx.stroke(); this.ctx.stroke();
}, },
text: function(text, offset) { text: function(text, coord, offset) {
offset = offset || { x:0, y:0 }; offset = offset || { x:0, y:0 };
if (this.offset) { if (this.offset) {
offset.x += this.offset.x; offset.x += this.offset.x;
offset.y += this.offset.y; offset.y += this.offset.y;
} }
this.ctx.fillText(text, offset.x, offset.y); this.ctx.fillText(text, coord.x + offset.x, coord.y + offset.y);
}, },
image: function(image, offset) { image: function(image, offset) {

View File

@@ -1,3 +1,90 @@
var React = require("react");
var Graphic = require("../../Graphic.jsx");
var SectionHeader = require("../../SectionHeader.jsx");
var abs = Math.abs;
var ABC = React.createClass({
getDefaultProps: function() {
return {
title: "The 'ABC' curve identity"
};
},
onClick: function(evt, api) {
api.t = api.curve.on({x: evt.offsetX, y: evt.offsetY},7);
if (api.t < 0.05 || api.t > 0.95) api.t = false;
api.redraw();
},
setupQuadratic: function(api) {
var curve = api.getDefaultQuadratic();
curve.points[0].y -= 10;
api.setCurve(curve);
},
setupCubic: function(api) {
var curve = api.getDefaultCubic();
curve.points[2].y -= 20;
api.setCurve(curve);
api.lut = curve.getLUT(100);
},
draw: function(api, curve) {
api.reset();
api.drawSkeleton(curve);
api.drawCurve(curve);
var h = api.getPanelHeight();
api.setColor("black");
if (!!api.t) {
api.drawCircle(api.curve.get(api.t),3);
api.setColor("lightgrey");
var hull = api.drawHull(curve, api.t);
var utils = api.utils;
var A, B, C;
if(hull.length === 6) {
A = curve.points[1];
B = hull[5];
C = utils.lli4(A, B, curve.points[0], curve.points[2]);
api.setColor("lightgrey");
api.drawLine(curve.points[0], curve.points[2]);
} else if(hull.length === 10) {
A = hull[5]
B = hull[9];
C = utils.lli4(A, B, curve.points[0], curve.points[3]);
api.setColor("lightgrey");
api.drawLine(curve.points[0], curve.points[3]);
}
api.setColor("#00FF00");
api.drawLine(A,B);
api.setColor("red");
api.drawLine(B,C);
api.setColor("black");
api.drawCircle(C,3);
api.setFill("black");
api.text("A", {x:10 + A.x, y: A.y});
api.text("B", {x:10 + B.x, y: B.y});
api.text("C", {x:10 + C.x, y: C.y});
var d1 = utils.dist(A, B);
var d2 = utils.dist(B, C);
var ratio = d1/d2;
api.text("d1 (A-B): " + utils.round(d1,2) + ", d2 (B-C): "+ utils.round(d2,2) + ", ratio (d1/d2): " + utils.round(ratio,4), {x:10, y:h-7});
}
},
render: function() {
return (
<section>
<SectionHeader {...this.props} />
<p>De Casteljau's algorithm is the pivotal algorithm when it comes to Bézier curves. You can use it not just to split <p>De Casteljau's algorithm is the pivotal algorithm when it comes to Bézier curves. You can use it not just to split
curves, but also to draw them efficiently (especially for high-order Bézier curves), as well as to come up with curves curves, but also to draw them efficiently (especially for high-order Bézier curves), as well as to come up with curves
based on three points and a tangent. Particularly this last thing is really useful because it lets us "mould" a curve, based on three points and a tangent. Particularly this last thing is really useful because it lets us "mould" a curve,
@@ -8,48 +95,27 @@
<p>Let's start out with a pre-existing curve, defined by <i>start</i>, two control points, and <i>end</i>. We can <p>Let's start out with a pre-existing curve, defined by <i>start</i>, two control points, and <i>end</i>. We can
mould this curve by picking a point somewhere on the curve, at some <i>t</i> value, and the moving it to a new mould this curve by picking a point somewhere on the curve, at some <i>t</i> value, and the moving it to a new
location and reconstructing the curve that goes through <i>start</i>, our new point with the original tangent, location and reconstructing the curve that goes through <i>start</i>, our new point with the original tangent,
and </i>end</i>. In order to see how and why we can do this, let's look at some identity information for Bézier and <i>end</i>. In order to see how and why we can do this, let's look at some identity information for Bézier
curves. There's actually a hidden goldmine of identities that we can exploit when doing Bézier operations, and curves. There's actually a hidden goldmine of identities that we can exploit when doing Bézier operations, and
this will only scratch the surface. But, in a good way!</p> this will only scratch the surface. But, in a good way!</p>
<p>In the following graphic, click anywhere on the curves to see the identity information that we'll <p>In the following graphic, click anywhere on the curves to see the identity information that we'll
be using to run de Casteljau in reverse:</p> be using to run de Casteljau in reverse (you can manipulate the curve even after picking a point.
Note the "ratio" value when you do so: does it change?):</p>
<textarea class="sketch-code" data-sketch-preset="abc" data-sketch-title="Projections in a quadratic Bézier curve"> <div className="figure">
void setupCurve() { <Graphic inline={true} preset="abc" title="Projections in a quadratic Bézier curve"
setupDefaultQuadratic(); setup={this.setupQuadratic} draw={this.draw} onClick={this.onClick} />
} <Graphic inline={true} preset="abc" title="Projections in a cubic Bézier curve"
setup={this.setupCubic} draw={this.draw} onClick={this.onClick} />
</div>
void drawCurve(BezierCurve curve) { <p>So, what exactly do we see in these graphics? First off, there's the three points <i>A</i>, <i>B</i> and <i>C</i>.</p>
curve.draw();
if(Bt != -1) {
Point[] abc = curve.getABC(Bt);
drawABC(curve, abc);
}
}</textarea>
<textarea class="sketch-code" data-sketch-preset="abc" data-sketch-title="Projections in a cubic Bézier curve">
void setupCurve() {
setupDefaultCubic();
}
void drawCurve(BezierCurve curve) {
curve.draw();
if(Bt != -1) {
Point[] abc = curve.getABC(Bt);
drawABC(curve, abc);
}
}</textarea>
<p>So, what exactly do we see in these graphics? First off, there's the three points <i>A</i>, <i>B</i> and
<i>C</i>.</p>
<p>Point <i>B</i> is our "on curve" point, A is the first "strut" point when running de Casteljau's <p>Point <i>B</i> is our "on curve" point, A is the first "strut" point when running de Casteljau's
algorithm in reverse; for quadratic curves, this happens to also be the curve's control point. For cubic algorithm in reverse; for quadratic curves, this happens to also be the curve's control point. For cubic
curves, it's the "top of the triangle" for the struts that lead to point <i>B</i>. Point curves, it's the "top of the triangle" for the struts that lead to point <i>B</i>. Point <i>C</i>, finally,
<i>C</i>, finally, is the intersection of the line that goes through <i>A</i> and <i>B</i> and the baseline, is the intersection of the line that goes through <i>A</i> and <i>B</i> and the baseline,
between our start and end points.</p> between our start and end points.</p>
<p>There is some important identity information here: as long as we don't pick a new <i>t</i> coordinate, <p>There is some important identity information here: as long as we don't pick a new <i>t</i> coordinate,
@@ -63,7 +129,7 @@
ratio between them, <i>d1/d2</i>, is a constant value. We can drag any of the start, end, or control points ratio between them, <i>d1/d2</i>, is a constant value. We can drag any of the start, end, or control points
around as much as we like, but that value also stays the same.</p> around as much as we like, but that value also stays the same.</p>
<div class="note"> <div className="note">
<p>In fact, because the distance ratio is a fixed value for each point <i>B</i>, which we get by picking <p>In fact, because the distance ratio is a fixed value for each point <i>B</i>, which we get by picking
some <i>t</i> value on our curve, the distance ratio is actually an identity function for Bézier curves. some <i>t</i> value on our curve, the distance ratio is actually an identity function for Bézier curves.
If we were to plot all the ratio values for all possible <i>t</i> values for quadratic and cubic curves, If we were to plot all the ratio values for all possible <i>t</i> values for quadratic and cubic curves,
@@ -75,15 +141,21 @@
<a href="http://mathoverflow.net/questions/122257/finding-the-formula-for-Bézier-curve-ratios-hull-point-point-baseline">Boris <a href="http://mathoverflow.net/questions/122257/finding-the-formula-for-Bézier-curve-ratios-hull-point-point-baseline">Boris
Zbarsky</a> we can see that the ratio functions are actually remarkably simple:</p> Zbarsky</a> we can see that the ratio functions are actually remarkably simple:</p>
<table style="width:100%; border:0"><tr><td> <table style={{width:"100%", border:0}}>
<tbody>
<tr>
<td>
<p>Quadratic curves:\[ <p>Quadratic curves:\[
ratio(t)_2 = \left | \frac{2t^2 - 2t}{2t^2 - 2t + 1} \right | ratio(t)_2 = \left | \frac{2t^2 - 2t}{2t^2 - 2t + 1} \right |
\]</p> \]</p>
</td><td> </td><td>
<p>Cubic curves: \[ <p>Cubic curves: \[
ratio(t)_3 = \left | \frac{t^3 + (1-t)^3}{t^3 + (1-t)^3 - 1} \right | ratio(t)_3 = \left | \frac{t^3 + (1-t)^3 - 1}{t^3 + (1-t)^3} \right |
\]</p> \]</p>
</td></tr></table> </td>
</tr>
</tbody>
</table>
<p>Unfortunately, this trick only works for quadratic and cubic curves. Once we hit higher order curves, <p>Unfortunately, this trick only works for quadratic and cubic curves. Once we hit higher order curves,
things become a lot less predictable; the "fixed point <i>C</i>" is no longer fixed, moving around as we things become a lot less predictable; the "fixed point <i>C</i>" is no longer fixed, moving around as we
@@ -91,40 +163,10 @@
lie on that line before the start, or after the end, and there are no simple ratios that we can exploit.</p> lie on that line before the start, or after the end, and there are no simple ratios that we can exploit.</p>
</div> </div>
<p>So, with this knowledge, let's change a curve's shape by click-dragging some part of it. The follow </section>
graphics let us click-drag somewhere on the curve, repositioning point <i>B</i> according to a simple );
rule: we keep the original point <i>B</i>'s tangent:</p>
<textarea class="sketch-code" data-sketch-preset="moulding" data-sketch-title="Moulding a quadratic Bézier curve">
void setupCurve() {
setupDefaultQuadratic();
mould();
span();
additionals();
} }
});
void mouldCurve(BezierCurve curve, int mx, int my) { module.exports = ABC;
if(Bt != -1) {
B = new Point(mx, my);
BezierCurve newcurve = comp.generateCurve(curve.order, curve.points[0], B, curve.points[curve.order], Bt);
curves.clear();
curves.add(newcurve);
}
}</textarea>
<textarea class="sketch-code" data-sketch-preset="moulding" data-sketch-title="Moulding a cubic Bézier curve">
void setupCurve() {
setupDefaultCubic();
mould();
span();
additionals();
}
void mouldCurve(BezierCurve curve, int mx, int my) {
if(Bt != -1) {
B = new Point(mx, my);
BezierCurve newcurve = comp.generateCurve(curve.order, curve.points[0], B, curve.points[curve.order], Bt, tangents);
curves.clear();
curves.add(newcurve);
}
}</textarea>

View File

@@ -31,13 +31,14 @@ module.exports = {
intersections: require("./intersections"), intersections: require("./intersections"),
curveintersection: require("./curveintersection"), curveintersection: require("./curveintersection"),
moulding: require("./moulding")
abc: require("./abc"),
moulding: require("./moulding"),
pointcurves: require("./pointcurves")
}; };
/* /*
pointcurves: require("./pointcurves"),
catmullconv: require("./catmullconv"), catmullconv: require("./catmullconv"),
catmullmoulding: require("./catmullmoulding"), catmullmoulding: require("./catmullmoulding"),
@@ -55,8 +56,7 @@ module.exports = {
*/ */
/* /*
Curve moulding (using the projection ratio)
Creating a curve from three points
Bézier curves and Catmull-Rom curves Bézier curves and Catmull-Rom curves
Creating a Catmull-Rom curve from three points Creating a Catmull-Rom curve from three points
Forming poly-Bézier curves Forming poly-Bézier curves

View File

@@ -20,7 +20,7 @@ var Intersections = React.createClass({
drawLineIntersection: function(api, curves) { drawLineIntersection: function(api, curves) {
api.reset(); api.reset();
var lli = curves[0].getUtils().lli4; var lli = api.utils.lli4;
var p = lli( var p = lli(
curves[0].points[0], curves[0].points[0],
curves[0].points[1], curves[0].points[1],
@@ -71,7 +71,7 @@ var Intersections = React.createClass({
api.drawCurve(curve); api.drawCurve(curve);
}); });
var utils = curves[0].getUtils(); var utils = api.utils;
var line = { p1: curves[1].points[0], p2: curves[1].points[1] }; var line = { p1: curves[1].points[0], p2: curves[1].points[1] };
var acpts = utils.align(curves[0].points, line); var acpts = utils.align(curves[0].points, line);
var nB = new api.Bezier(acpts); var nB = new api.Bezier(acpts);

View File

@@ -7,85 +7,40 @@ var abs = Math.abs;
var Moulding = React.createClass({ var Moulding = React.createClass({
getDefaultProps: function() { getDefaultProps: function() {
return { return {
title: "Moulding a curve" title: "Manipulating a curve"
}; };
}, },
setupQuadratic: function(api) { setupQuadratic: function(api) {
api.setPanelCount(3);
var curve = api.getDefaultQuadratic(); var curve = api.getDefaultQuadratic();
curve.points[0].y -= 10; curve.points[2].x -= 30;
api.setCurve(curve); api.setCurve(curve);
}, },
setupCubic: function(api) { setupCubic: function(api) {
var curve = api.getDefaultCubic(); api.setPanelCount(3);
var curve = new api.Bezier([100,230, 30,160, 200,50, 210,160]);
curve.points[2].y -= 20; curve.points[2].y -= 20;
api.setCurve(curve); api.setCurve(curve);
api.lut = curve.getLUT(100); api.lut = curve.getLUT(100);
}, },
draw: function(api, curve) { saveCurve: function(evt, api) {
api.reset(); if (!api.t) return;
api.drawSkeleton(curve); api.setCurve(api.newcurve);
api.drawCurve(curve); api.t = false;
var h = api.getPanelHeight();
api.setColor("black");
if (!!api.t) {
api.drawCircle(api.curve.get(api.t),3);
api.setColor("lightgrey");
var hull = api.drawHull(curve, api.t);
var utils = api.curve.getUtils();
var A, B, C;
if(hull.length === 6) {
A = curve.points[1];
B = hull[5];
C = utils.lli4(A, B, curve.points[0], curve.points[2]);
api.setColor("lightgrey");
api.drawLine(curve.points[0], curve.points[2]);
} else if(hull.length === 10) {
A = hull[5]
B = hull[9];
C = utils.lli4(A, B, curve.points[0], curve.points[3]);
api.setColor("lightgrey");
api.drawLine(curve.points[0], curve.points[3]);
}
api.setColor("#00FF00");
api.drawLine(A,B);
api.setColor("red");
api.drawLine(B,C);
api.setColor("black");
api.drawCircle(C,3);
api.setFill("black");
api.text("A", {x:10 + A.x, y: A.y});
api.text("B", {x:10 + B.x, y: B.y});
api.text("C", {x:10 + C.x, y: C.y});
var d1 = utils.dist(A, B);
var d2 = utils.dist(B, C);
var ratio = d1/d2;
api.text("d1 (A-B): " + utils.round(d1,2) + ", d2 (B-C): "+ utils.round(d2,2) + ", ratio (d1/d2): " + utils.round(ratio,4), {x:10, y:h-2});
}
},
onClickWithRedraw: function(evt, api) {
this.onClick(evt, api);
api.redraw(); api.redraw();
}, },
onClick: function(evt, api) { findTValue: function(evt, api) {
api.t = api.curve.on({x: evt.offsetX, y: evt.offsetY},7); var t = api.curve.on({x: evt.offsetX, y: evt.offsetY},7);
if (api.t < 0.05 || api.t > 0.95) api.t = false; if (t < 0.05 || t > 0.95) return false;
return t;
}, },
markQB: function(evt, api) { markQB: function(evt, api) {
this.onClick(evt, api); api.t = this.findTValue(evt, api);
if(api.t) { if(api.t) {
var t = api.t, var t = api.t,
t2 = 2*t, t2 = 2*t,
@@ -95,13 +50,13 @@ var Moulding = React.createClass({
curve = api.curve, curve = api.curve,
A = api.A = curve.points[1], A = api.A = curve.points[1],
B = api.B = curve.get(t); B = api.B = curve.get(t);
api.C = curve.getUtils().lli4(A, B, curve.points[0], curve.points[2]); api.C = api.utils.lli4(A, B, curve.points[0], curve.points[2]);
api.ratio = ratio; api.ratio = ratio;
} }
}, },
markCB: function(evt, api) { markCB: function(evt, api) {
this.onClick(evt, api); api.t = this.findTValue(evt, api);
if(api.t) { if(api.t) {
var t = api.t, var t = api.t,
mt = (1-t), mt = (1-t),
@@ -115,7 +70,7 @@ var Moulding = React.createClass({
A = api.A = hull[5], A = api.A = hull[5],
B = api.B = curve.get(t), B = api.B = curve.get(t),
db = api.db = curve.derivative(t); db = api.db = curve.derivative(t);
api.C = curve.getUtils().lli4(A, B, curve.points[0], curve.points[3]); api.C = api.utils.lli4(A, B, curve.points[0], curve.points[3]);
api.ratio = ratio; api.ratio = ratio;
} }
}, },
@@ -193,32 +148,68 @@ var Moulding = React.createClass({
api.update = [nc1, nc2]; api.update = [nc1, nc2];
}, },
commit: function(evt, api) {
if (!api.t) return;
api.setCurve(api.newcurve);
api.t = false;
api.redraw();
},
drawMould: function(api, curve) { drawMould: function(api, curve) {
api.reset(); api.reset();
api.drawSkeleton(curve); api.drawSkeleton(curve);
api.drawCurve(curve); api.drawCurve(curve);
var w = api.getPanelWidth(),
h = api.getPanelHeight(),
offset = {x:w, y:0},
round = api.utils.round;
api.setColor("black");
api.drawLine({x:0,y:0},{x:0,y:h}, offset);
api.drawLine({x:w,y:0},{x:w,y:h}, offset);
if (api.t) { if (api.t) {
api.drawCircle(curve.get(api.t),3);
api.npts = [curve.points[0]].concat(api.update).concat([curve.points.slice(-1)[0]]); api.npts = [curve.points[0]].concat(api.update).concat([curve.points.slice(-1)[0]]);
api.newcurve = new api.Bezier(api.npts); api.newcurve = new api.Bezier(api.npts);
api.drawCurve(api.newcurve);
api.setColor("lightgrey"); api.setColor("lightgrey");
api.drawHull(api.newcurve, api.t); api.drawCurve(api.newcurve);
api.drawLine(api.npts[0], api.npts.slice(-1)[0]); var newhull = api.drawHull(api.newcurve, api.t, offset);
api.drawLine(api.newA, api.C); api.drawLine(api.npts[0], api.npts.slice(-1)[0], offset);
api.drawLine(api.newA, api.newB, offset);
api.setColor("grey"); api.setColor("grey");
api.drawCircle(api.newB, 3); api.drawCircle(api.newA, 3, offset);
api.drawCircle(api.newA, 3); api.setColor("blue");
api.drawCircle(api.C, 3); api.drawCircle(api.B, 3, offset);
api.drawCircle(api.C, 3, offset);
api.drawCircle(api.newB, 3, offset);
api.drawLine(api.B, api.C, offset);
api.drawLine(api.newB, api.C, offset);
api.setFill("black");
api.text("A'", api.newA, {x:offset.x + 7, y:offset.y + 1});
api.text("start", curve.get(0), {x:offset.x + 7, y:offset.y + 1});
api.text("end", curve.get(1), {x:offset.x + 7, y:offset.y + 1});
api.setFill("blue");
api.text("B'", api.newB, {x:offset.x + 7, y:offset.y + 1});
api.text("B, at t = "+round(api.t,2), api.B, {x:offset.x + 7, y:offset.y + 1});
api.text("C", api.C, {x:offset.x + 7, y:offset.y + 1});
if(curve.order === 3) {
var hull = curve.hull(api.t);
api.drawLine(hull[7], hull[8], offset);
api.drawLine(newhull[7], newhull[8], offset);
api.drawCircle(newhull[7], 3, offset);
api.drawCircle(newhull[8], 3, offset);
api.text("e1", newhull[7], {x:offset.x + 7, y:offset.y + 1});
api.text("e2", newhull[8], {x:offset.x + 7, y:offset.y + 1});
}
offset.x += w;
api.setColor("lightgrey");
api.drawSkeleton(api.newcurve, offset);
api.setColor("black");
api.drawCurve(api.newcurve, offset);
} else {
offset.x += w;
api.drawCurve(curve, offset);
} }
}, },
@@ -227,98 +218,45 @@ var Moulding = React.createClass({
<section> <section>
<SectionHeader {...this.props} /> <SectionHeader {...this.props} />
<p>De Casteljau's algorithm is the pivotal algorithm when it comes to Bézier curves. You can use it not just to split <p>Armed with knowledge of the "ABC" relation, we can now update a curve interactively, by letting people click anywhere
curves, but also to draw them efficiently (especially for high-order Bézier curves), as well as to come up with curves on the curve, find the <em>t</em>-value matching that coordinate, and then letting them drag that point around. With every
based on three points and a tangent. Particularly this last thing is really useful because it lets us "mould" a curve, drag update we'll have a new point "B", which we can combine with the fixed point "C" to find our new point A. Once we have
by picking it up at some point, and dragging that point around to change the curve's shape.</p> those, we can reconstruct the de Casteljau skeleton and thus construct a new curve with the same start/end points as the
original curve, passing through the user-selected point B, with correct new control points.</p>
<p>How does that work? Succinctly: we run de Casteljau's algorithm in reverse!</p> <Graphic preset="moulding" title="Moulding a quadratic Bézier curve"
<p>Let's start out with a pre-existing curve, defined by <i>start</i>, two control points, and <i>end</i>. We can
mould this curve by picking a point somewhere on the curve, at some <i>t</i> value, and the moving it to a new
location and reconstructing the curve that goes through <i>start</i>, our new point with the original tangent,
and <i>end</i>. In order to see how and why we can do this, let's look at some identity information for Bézier
curves. There's actually a hidden goldmine of identities that we can exploit when doing Bézier operations, and
this will only scratch the surface. But, in a good way!</p>
<p>In the following graphic, click anywhere on the curves to see the identity information that we'll
be using to run de Casteljau in reverse (you can manipulate the curve even after picking a point.
Note the "ratio" value when you do so: does it change?):</p>
<div className="figure">
<Graphic inline={true} preset="abc" title="Projections in a quadratic Bézier curve"
setup={this.setupQuadratic} draw={this.draw} onClick={this.onClickWithRedraw} />
<Graphic inline={true} preset="abc" title="Projections in a cubic Bézier curve"
setup={this.setupCubic} draw={this.draw} onClick={this.onClickWithRedraw} />
</div>
<p>So, what exactly do we see in these graphics? First off, there's the three points <i>A</i>, <i>B</i> and <i>C</i>.</p>
<p>Point <i>B</i> is our "on curve" point, A is the first "strut" point when running de Casteljau's
algorithm in reverse; for quadratic curves, this happens to also be the curve's control point. For cubic
curves, it's the "top of the triangle" for the struts that lead to point <i>B</i>. Point <i>C</i>, finally,
is the intersection of the line that goes through <i>A</i> and <i>B</i> and the baseline,
between our start and end points.</p>
<p>There is some important identity information here: as long as we don't pick a new <i>t</i> coordinate,
the location of point <i>C</i> on the line <i>start-end</i> represents a fixed ratio distance. We can drag
around the control points as much as we like, that point won't move at all, and if we can drag around
the start or end point, C will stay at the same ratio-value. For instance, if it was located midway between
start and end, it'll stay midway between start and end, even if the line segment between start and end
becomes longer or shorter.</p>
<p>We can also see that the distances for the lines <i>d1 = A-B</i> and <i>d2 = B-C</i> may vary, but the
ratio between them, <i>d1/d2</i>, is a constant value. We can drag any of the start, end, or control points
around as much as we like, but that value also stays the same.</p>
<div className="note">
<p>In fact, because the distance ratio is a fixed value for each point <i>B</i>, which we get by picking
some <i>t</i> value on our curve, the distance ratio is actually an identity function for Bézier curves.
If we were to plot all the ratio values for all possible <i>t</i> values for quadratic and cubic curves,
we'd see two very interesting functions: asymptotic at <i>t=0</i> and <i>t=1</i>, tending towards positive
infinity, with a zero-derivative minimum at <i>t=0.5</i>.</p>
<p>Since these are ratios, we can actually express the ratio values as a function of <i>t</i>. I actually
failed at coming up with the precise functions, but thanks to some help from
<a href="http://mathoverflow.net/questions/122257/finding-the-formula-for-Bézier-curve-ratios-hull-point-point-baseline">Boris
Zbarsky</a> we can see that the ratio functions are actually remarkably simple:</p>
<table style={{width:"100%", border:0}}>
<tbody>
<tr>
<td>
<p>Quadratic curves:\[
ratio(t)_2 = \left | \frac{2t^2 - 2t}{2t^2 - 2t + 1} \right |
\]</p>
</td><td>
<p>Cubic curves: \[
ratio(t)_3 = \left | \frac{t^3 + (1-t)^3 - 1}{t^3 + (1-t)^3} \right |
\]</p>
</td>
</tr>
</tbody>
</table>
<p>Unfortunately, this trick only works for quadratic and cubic curves. Once we hit higher order curves,
things become a lot less predictable; the "fixed point <i>C</i>" is no longer fixed, moving around as we
move the control points, and projections of <i>B</i> onto the line between start and end may actually
lie on that line before the start, or after the end, and there are no simple ratios that we can exploit.</p>
</div>
<p>So, with this knowledge, let's change a curve's shape by click-dragging some part of it. The follow
graphics let us click-drag somewhere on the curve, repositioning point <i>B</i> according to a simple
rule: we keep the original point <i>B</i>'s tangent:</p>
<div className="figure">
<Graphic inline={true} preset="moulding" title="Moulding a quadratic Bézier curve"
setup={this.setupQuadratic} draw={this.drawMould} setup={this.setupQuadratic} draw={this.drawMould}
onClick={this.placeMouldPoint} onMouseDown={this.markQB} onMouseDrag={this.dragQB} onMouseUp={this.commit}/> onClick={this.placeMouldPoint} onMouseDown={this.markQB} onMouseDrag={this.dragQB} onMouseUp={this.saveCurve}/>
<Graphic inline={true} preset="moulding" title="Moulding a cubic Bézier curve" <p>Click-dragging a point on the curve shows what we're using to compute the new coordinates: while dragging you will
see the original points B and its corresponding <i>t</i>-value, the original point C for that <i>t</i>-value,
as well as the new point B' based on the mouse cursor. Since we know the <i>t</i>-value for this configuration,
we can compute the ABC ratio for this configuration, and we know that our new point A' should like at a distance:</p>
<p>\[
A' = B' + \frac{B' - C}{ratio} = B' - \frac{C - B'}{ratio}
\]</p>
<p>For quadratic curves, this means we're done, since the new point A' is equivalent to the new quadratic control point.
For cubic curves, we need to do a little more work:</p>
<Graphic preset="moulding" title="Moulding a cubic Bézier curve"
setup={this.setupCubic} draw={this.drawMould} setup={this.setupCubic} draw={this.drawMould}
onClick={this.placeMouldPoint} onMouseDown={this.markCB} onMouseDrag={this.dragCB} onMouseUp={this.commit}/> onClick={this.placeMouldPoint} onMouseDown={this.markCB} onMouseDrag={this.dragCB} onMouseUp={this.saveCurve}/>
</div>
<p>To help understand what's going on, the cubic graphic shows the full de Casteljau construction "hull" when repositioning
point B. We compute A` in exactly the same way as before, but we also record the final strut line that forms B in the original
curve. Given A', B', and the endpoints e1 and e2 of the strut line relative to B', we can now compute where the new control points
should be. Remember that B' lies on line e1--e2 at a distance <i>t</i>, because that's how Bézier curves work. In the same manner,
we know the distance A--e1 is only line-interval [0,t] of the full segment, and A--e2 is only line-interval [t,1], so constructing
the new control points is fairly easy:</p>
<p>\[\begin{align}
C1' &= A' + \frac{e1 - A'}{t} \\
C2' &= A' + \frac{e2 - A'}{1 - t}
\end{align}\]</p>
<p>And that's cubic curve manipulation.</p>
</section> </section>
); );
} }

View File

@@ -0,0 +1,199 @@
var React = require("react");
var Graphic = require("../../Graphic.jsx");
var SectionHeader = require("../../SectionHeader.jsx");
var abs = Math.abs;
var PointCurves = React.createClass({
getDefaultProps: function() {
return {
title: "Creating a curve from three points"
};
},
setup: function(api) {
api.lpts = [];
},
onClick: function(evt, api) {
if (api.lpts.length==3) { api.lpts = []; }
api.lpts.push({
x: evt.offsetX,
y: evt.offsetY
});
api.redraw();
},
getQRatio: function(t) {
var t2 = 2*t,
top = t2*t - t2,
bottom = top + 1;
return abs(top/bottom);
},
getCRatio: function(t) {
var mt = (1-t),
t3 = t*t*t,
mt3 = mt*mt*mt,
bottom = t3 + mt3,
top = bottom - 1
return abs(top/bottom);
},
drawQuadratic: function(api, curve) {
var w = api.getPanelWidth(),
h = api.getPanelHeight(),
offset = {x:w, y:0},
labels = ["start","t=0.5","end"];
api.reset();
api.setFill("black");
api.lpts.forEach((p,i) => {
api.drawCircle(p,3);
api.text(labels[i], p, {x:5, y:2});
});
api.setColor("black");
api.drawLine({x:0,y:0},{x:0,y:h}, offset);
api.drawLine({x:w,y:0},{x:w,y:h}, offset);
if(api.lpts.length === 3) {
var S = api.lpts[0],
E = api.lpts[2],
B = api.lpts[1],
C = {
x: (S.x + E.x)/2,
y: (S.y + E.y)/2,
};
api.setColor("blue");
api.drawLine(S, E);
api.drawLine(B, C);
api.drawCircle(C, 3);
var ratio = this.getQRatio(0.5),
A = {
x: B.x + (B.x-C.x)/ratio,
y: B.y + (B.y-C.y)/ratio
},
curve = new api.Bezier([S, A, E]);
api.setColor("lightgrey");
api.drawLine(A, B);
api.drawLine(A, S);
api.drawLine(A, E);
api.setColor("black");
api.drawCircle(A, 3);
api.drawCurve(curve);
}
},
drawCubic: function(api, curve) {
var w = api.getPanelWidth(),
h = api.getPanelHeight(),
offset = {x:w, y:0},
labels = ["start","t=0.5","end"];
api.reset();
api.setFill("black");
api.lpts.forEach((p,i) => {
api.drawCircle(p,3);
api.text(labels[i], p, {x:5, y:2});
});
api.setColor("black");
api.drawLine({x:0,y:0},{x:0,y:h}, offset);
api.drawLine({x:w,y:0},{x:w,y:h}, offset);
if(api.lpts.length === 3) {
var S = api.lpts[0],
E = api.lpts[2],
B = api.lpts[1],
C = {
x: (S.x + E.x)/2,
y: (S.y + E.y)/2,
};
api.setColor("blue");
api.drawLine(S, E);
api.drawLine(B, C);
api.drawCircle(C, 3);
var ratio = this.getCRatio(0.5),
A = {
x: B.x + (B.x-C.x)/ratio,
y: B.y + (B.y-C.y)/ratio
},
e1 = {
x: B.x - (E.x-S.x)/4,
y: B.y - (E.y-S.y)/4
},
e2 = {
x: B.x + (E.x-S.x)/4,
y: B.y + (E.y-S.y)/4
},
v1 = {
x: A.x + (e1.x-A.x)*2,
y: A.y + (e1.y-A.y)*2
},
v2 = {
x: A.x + (e2.x-A.x)*2,
y: A.y + (e2.y-A.y)*2
},
nc1 = {
x: S.x + (v1.x-S.x)*2,
y: S.y + (v1.y-S.y)*2
},
nc2 = {
x: E.x + (v2.x-E.x)*2,
y: E.y + (v2.y-E.y)*2
},
curve = new api.Bezier([S, nc1, nc2, E]);
api.drawLine(e1, e2);
api.setColor("lightgrey");
api.drawLine(A, C);
api.drawLine(A, v1);
api.drawLine(A, v2);
api.drawLine(S, nc1);
api.drawLine(E, nc2);
api.drawLine(nc1, nc2);
api.setColor("black");
api.drawCircle(A, 3);
api.drawCircle(nc1, 3);
api.drawCircle(nc2, 3);
api.drawCurve(curve);
}
},
render: function() {
return (
<section>
<SectionHeader {...this.props} />
<p>Given the preceding section on curve manipulation, we can also generate quadratic and cubic
curves from any three points. However, unlike circle-fitting, which requires only three points,
Bézier curve fitting requires three points, as well as a <i>t</i> value (so we can figure out
where point 'C' needs to be) and in cade of quadratic curves, a tangent that lets us place
those points 'e1' and 'e2' around our point 'B'.</p>
<p>There's some freedom here, so for illustrative purposes we're going to pretend <i>t</i> is
simply 0.5, which puts C in the middle of the start--end line segment, and then we'll also set
the cubic curve's tangent to half the length of start--end, centered on B.</p>
<p>Using these "default" values for curve creation, we can already get fairly respectable
curves; Click three times on each of the following sketches to set up the points
that should be used to form a quadratic and cubic curve, respectively:</p>
<Graphic preset="generate" title="Fitting a quadratic Bézier curve" setup={this.setup} draw={this.drawQuadratic}
onClick={this.onClick} />
<Graphic preset="generate" title="Fitting a cubic Bézier curve" setup={this.setup} draw={this.drawCubic}
onClick={this.onClick} />
<p>In each graphic, the blue parts are the values that we "just have" simply by setting up
our three points, and deciding on which <i>t</i>-value (and tangent, for cubic curves)
we're working with. There are many ways to determine a combination of <i>t</i> and tangent
values that lead to a more "aesthetic" curve, but this will be left as an exercise to the
reader, since there are many, and aesthetics are often quite personal.</p>
</section>
);
}
});
module.exports = PointCurves;

View File

@@ -13,7 +13,6 @@ var Tracing = React.createClass({
var curve = api.getDefaultCubic(); var curve = api.getDefaultCubic();
api.setCurve(curve); api.setCurve(curve);
api.steps = 8; api.steps = 8;
this.map = curve.getUtils().map;
}, },
generate: function(api, curve, offset, pad, fwh) { generate: function(api, curve, offset, pad, fwh) {
@@ -25,8 +24,8 @@ var Tracing = React.createClass({
t = v/100; t = v/100;
d = curve.split(t).left.length(); d = curve.split(t).left.length();
pts.push({ pts.push({
x: this.map(t, 0,1, 0,fwh), x: api.utils.map(t, 0,1, 0,fwh),
y: this.map(d, 0,len, 0,fwh), y: api.utils.map(d, 0,len, 0,fwh),
d: d, d: d,
t: t t: t
}); });
@@ -108,8 +107,8 @@ var Tracing = React.createClass({
} }
ts.forEach(p => { ts.forEach(p => {
var pt = { x: this.map(p.t,0,1,0,fwh), y: 0 }; var pt = { x: api.utils.map(p.t,0,1,0,fwh), y: 0 };
var pd = { x: 0, y: this.map(p.d,0,len,0,fwh) }; var pd = { x: 0, y: api.utils.map(p.d,0,len,0,fwh) };
api.setColor("black"); api.setColor("black");
api.drawCircle(pt, 3, offset); api.drawCircle(pt, 3, offset);
api.drawCircle(pd, 3, offset); api.drawCircle(pd, 3, offset);

View File

@@ -0,0 +1,36 @@
<svg xmlns:xlink="http://www.w3.org/1999/xlink" width="17.333ex" height="2.833ex" style="vertical-align: -0.5ex; margin-left: 0ex; margin-right: 0ex; margin-bottom: 1px; margin-top: 1px;" viewBox="0 -962.8 7467 1191.8" xmlns="http://www.w3.org/2000/svg">
<defs>
<path stroke-width="10" id="E1-LATINMODERNNORMAL-1D454" d="M474 395c0 -7 -2 -12 -3 -18l-111 -444c-15 -60 -87 -138 -212 -138c-96 0 -133 20 -133 61c0 40 32 58 54 58c27 0 38 -19 38 -35c0 -17 -11 -43 -41 -52c28 -9 61 -10 80 -10c106 0 140 99 144 108l33 132l-1 1c-10 -11 -57 -58 -116 -58c-72 0 -133 59 -133 158 c0 144 124 284 238 284c40 0 75 -26 93 -63c4 36 31 43 41 43c17 0 29 -10 29 -27zM392 334c0 5 -14 86 -80 86c-42 0 -85 -40 -112 -89c-27 -51 -56 -169 -56 -217c0 -40 15 -92 65 -92c29 0 60 18 81 36c22 19 45 44 51 70l48 191c1 4 3 10 3 15Z"></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-1D463" d="M468 372c0 -52 -57 -383 -225 -383c-46 0 -134 16 -134 124c0 43 13 89 57 205c7 18 17 45 17 70c0 32 -17 32 -25 32c-29 0 -72 -23 -101 -124c-5 -16 -6 -18 -16 -18c0 0 -12 0 -12 10c0 9 38 154 132 154c50 0 82 -37 82 -82c0 -19 -5 -33 -12 -50 c-31 -83 -58 -156 -58 -212c0 -52 23 -87 74 -87c117 0 178 229 178 271c0 36 -13 62 -34 82c-11 11 -16 17 -16 30c0 22 24 48 49 48c18 0 44 -16 44 -70Z"></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-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-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-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-2C" d="M203 1c0 -117 -80 -194 -91 -194c-5 0 -10 4 -10 11c0 3 0 5 11 16c33 33 68 93 68 167c0 14 -2 15 -2 15s-2 -1 -5 -3c-10 -9 -23 -13 -35 -13c-33 0 -53 26 -53 53c0 28 20 53 53 53c39 0 64 -39 64 -105Z"></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-1D450" d="M430 107c0 -12 -84 -118 -227 -118c-104 0 -162 79 -162 169c0 141 133 284 268 284c71 0 118 -37 118 -86c0 -40 -27 -64 -56 -64c-19 0 -37 11 -37 35c0 7 2 24 18 39c14 14 28 14 44 14c-14 27 -52 40 -86 40c-55 0 -110 -43 -141 -100c-34 -62 -54 -159 -54 -200 c0 -60 27 -109 90 -109c12 0 121 0 200 99c6 8 8 10 13 10c6 0 12 -7 12 -13Z"></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-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>
</defs>
<g stroke="currentColor" fill="currentColor" stroke-width="0" transform="matrix(1 0 0 -1 0 0)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D454" x="0" y="0"></use>
<use xlink:href="#E1-LATINMODERNNORMAL-1D456" x="482" y="0"></use>
<use xlink:href="#E1-LATINMODERNNORMAL-1D463" x="832" y="0"></use>
<use xlink:href="#E1-LATINMODERNNORMAL-1D452" x="1322" y="0"></use>
<use xlink:href="#E1-LATINMODERNNORMAL-1D45B" x="1793" y="0"></use>
<g transform="translate(2398,0)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D434" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNMAIN-2032" x="1067" y="583"></use>
</g>
<use xlink:href="#E1-LATINMODERNMAIN-2C" x="3476" y="0"></use>
<g transform="translate(3926,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-2C" x="5013" y="0"></use>
<use xlink:href="#E1-LATINMODERNNORMAL-1D450" x="5463" y="0"></use>
<use xlink:href="#E1-LATINMODERNMAIN-31" x="5901" y="0"></use>
<use xlink:href="#E1-LATINMODERNMAIN-3D" x="6684" y="0"></use>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@@ -0,0 +1,70 @@
<svg xmlns:xlink="http://www.w3.org/1999/xlink" width="35.5ex" height="5.333ex" style="vertical-align: -1.667ex; margin-left: 0ex; margin-right: 0ex; margin-bottom: 1px; margin-top: 1px;" viewBox="0 -1589.3 15265.1 2314.7" xmlns="http://www.w3.org/2000/svg">
<defs>
<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-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-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-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-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-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-1D436" d="M760 695l-63 -255c-5 -18 -5 -20 -18 -20c-4 0 -15 0 -15 10s3 11 3 51c0 116 -59 193 -161 193c-89 0 -183 -50 -244 -121c-100 -117 -121 -279 -121 -336c0 -156 106 -208 196 -208c52 0 115 17 184 73c69 58 92 129 101 158c2 8 7 10 13 10c0 0 12 0 12 -10 c0 -3 -17 -94 -110 -176c-53 -46 -129 -86 -216 -86c-153 0 -271 109 -271 274c0 232 225 453 448 453c111 0 157 -75 166 -89l70 77c11 11 12 12 15 12c9 0 11 -7 11 -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-1D44E" d="M498 143c0 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 293c45 0 74 -27 92 -64c3 22 18 44 42 44c17 0 29 -10 29 -27c0 -4 0 -6 -7 -34l-36 -140l-22 -90 c-11 -44 -13 -52 -13 -74c0 -20 3 -46 30 -46c41 0 59 59 76 124c3 14 4 18 14 18c3 0 12 0 12 -10zM361 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 37l50 196c1 5 3 11 3 17Z"></path>
<path stroke-width="10" id="E1-LATINMODERNNORMAL-1D461" d="M330 420c0 -20 -10 -20 -30 -20h-94l-74 -295c-4 -17 -6 -24 -6 -48c0 -33 10 -46 31 -46c34 0 87 24 130 128c5 11 6 14 15 14c4 0 12 0 12 -10c0 -8 -57 -154 -159 -154c-54 0 -92 38 -92 92c0 18 4 35 76 319h-88c-20 0 -28 0 -28 12c0 19 10 19 30 19h94l39 159 c9 35 37 36 40 36c17 0 29 -10 29 -27c0 -6 -5 -26 -41 -168h88c18 0 28 0 28 -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-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>
</defs>
<g stroke="currentColor" fill="currentColor" stroke-width="0" transform="matrix(1 0 0 -1 0 0)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D434" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNMAIN-2032" x="1067" y="583"></use>
<use xlink:href="#E1-LATINMODERNMAIN-3D" x="1356" y="0"></use>
<g transform="translate(2417,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-2B" x="3726" y="0"></use>
<g transform="translate(4509,0)">
<g transform="translate(342,0)">
<rect stroke="none" width="3199" height="60" x="0" y="220"></rect>
<g transform="translate(60,676)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D435" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNMAIN-2032" x="1080" y="513"></use>
<use xlink:href="#E1-LATINMODERNMAIN-2212" x="1309" y="0"></use>
<use xlink:href="#E1-LATINMODERNNORMAL-1D436" x="2314" y="0"></use>
</g>
<g transform="translate(501,-691)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D45F" x="0" y="0"></use>
<use xlink:href="#E1-LATINMODERNNORMAL-1D44E" x="456" y="0"></use>
<use xlink:href="#E1-LATINMODERNNORMAL-1D461" x="990" y="0"></use>
<use xlink:href="#E1-LATINMODERNNORMAL-1D456" x="1356" y="0"></use>
<use xlink:href="#E1-LATINMODERNNORMAL-1D45C" x="1706" y="0"></use>
</g>
</g>
</g>
<use xlink:href="#E1-LATINMODERNMAIN-3D" x="8449" y="0"></use>
<g transform="translate(9510,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-2212" x="10820" y="0"></use>
<g transform="translate(11603,0)">
<g transform="translate(342,0)">
<rect stroke="none" width="3199" height="60" x="0" y="220"></rect>
<g transform="translate(60,676)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D436" x="0" y="0"></use>
<use xlink:href="#E1-LATINMODERNMAIN-2212" x="987" y="0"></use>
<g transform="translate(1992,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="513"></use>
</g>
</g>
<g transform="translate(501,-691)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D45F" x="0" y="0"></use>
<use xlink:href="#E1-LATINMODERNNORMAL-1D44E" x="456" y="0"></use>
<use xlink:href="#E1-LATINMODERNNORMAL-1D461" x="990" y="0"></use>
<use xlink:href="#E1-LATINMODERNNORMAL-1D456" x="1356" y="0"></use>
<use xlink:href="#E1-LATINMODERNNORMAL-1D45C" x="1706" y="0"></use>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

@@ -0,0 +1,4 @@
<svg xmlns:xlink="http://www.w3.org/1999/xlink" width="0ex" height="0ex" style="vertical-align: 0ex; margin-left: 0ex; margin-right: 0ex; margin-bottom: 1px; margin-top: 1px;" viewBox="0 -13.9 0 27.9" xmlns="http://www.w3.org/2000/svg">
<defs></defs>
<g stroke="currentColor" fill="currentColor" stroke-width="0" transform="matrix(1 0 0 -1 0 0)"></g>
</svg>

After

Width:  |  Height:  |  Size: 357 B

View File

@@ -0,0 +1,96 @@
<svg xmlns:xlink="http://www.w3.org/1999/xlink" width="20.5ex" height="8.5ex" style="vertical-align: -3.667ex; margin-left: 0ex; margin-right: 0ex; margin-bottom: 0ex; margin-top: 1px;" viewBox="0 -2073.4 8858.2 3646.9" xmlns="http://www.w3.org/2000/svg">
<defs>
<path stroke-width="10" id="E1-LATINMODERNMAIN-7B" d="M425 -238c0 -7 -5 -12 -12 -12c-105 0 -196 52 -196 125v250c0 58 -55 113 -130 113c-7 0 -12 5 -12 12s5 12 12 12c75 0 130 55 130 113v250c0 73 91 125 196 125c7 0 12 -5 12 -12s-5 -12 -12 -12c-75 0 -130 -49 -130 -101v-250c0 -58 -48 -104 -115 -125 c67 -21 115 -67 115 -125v-250c0 -52 55 -101 130 -101c7 0 12 -5 12 -12Z"></path>
<path stroke-width="10" id="E1-LATINMODERNNORMAL-1D436" d="M760 695l-63 -255c-5 -18 -5 -20 -18 -20c-4 0 -15 0 -15 10s3 11 3 51c0 116 -59 193 -161 193c-89 0 -183 -50 -244 -121c-100 -117 -121 -279 -121 -336c0 -156 106 -208 196 -208c52 0 115 17 184 73c69 58 92 129 101 158c2 8 7 10 13 10c0 0 12 0 12 -10 c0 -3 -17 -94 -110 -176c-53 -46 -129 -86 -216 -86c-153 0 -271 109 -271 274c0 232 225 453 448 453c111 0 157 -75 166 -89l70 77c11 11 12 12 15 12c9 0 11 -7 11 -10Z"></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-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-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-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-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-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-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-1D461" d="M330 420c0 -20 -10 -20 -30 -20h-94l-74 -295c-4 -17 -6 -24 -6 -48c0 -33 10 -46 31 -46c34 0 87 24 130 128c5 11 6 14 15 14c4 0 12 0 12 -10c0 -8 -57 -154 -159 -154c-54 0 -92 38 -92 92c0 18 4 35 76 319h-88c-20 0 -28 0 -28 12c0 19 10 19 30 19h94l39 159 c9 35 37 36 40 36c17 0 29 -10 29 -27c0 -6 -5 -26 -41 -168h88c18 0 28 0 28 -11Z"></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>
<path stroke-width="10" id="E1-LATINMODERNSYMBOLS-23A7" d="M755 724c0 -11 -7 -21 -17 -24c-138 -51 -236 -202 -236 -325v-375h-102v375c0 151 151 312 320 373c3 1 6 2 9 2c14 0 26 -12 26 -26Z"></path>
<path stroke-width="10" id="E1-LATINMODERNSYMBOLS-23A9" d="M755 26c0 -14 -12 -26 -26 -26c-3 0 -6 1 -9 2c-169 61 -320 222 -320 373v375h102v-375c0 -123 98 -274 236 -325c10 -3 17 -13 17 -24Z"></path>
<path stroke-width="10" id="E1-LATINMODERNSYMBOLS-23A8" d="M502 1500v-375c0 -147 -120 -300 -265 -375c145 -75 265 -228 265 -375v-375h-102v375c0 137 -97 300 -236 351c-10 3 -17 13 -17 24s7 21 17 24c139 51 236 214 236 351v375h102Z"></path>
<path stroke-width="10" id="E1-LATINMODERNSIZE7-E003" d="M502 0h-102v748h102v-748Z"></path>
</defs>
<g stroke="currentColor" fill="currentColor" stroke-width="0" transform="matrix(1 0 0 -1 0 0)">
<g transform="translate(0,2059)">
<use xlink:href="#E1-LATINMODERNSYMBOLS-23A7" x="0" y="-760"></use>
<g transform="translate(0,-1094.567566016018) scale(1,0.4941524617625568)">
<use xlink:href="#E1-LATINMODERNSIZE7-E003"></use>
</g>
<use xlink:href="#E1-LATINMODERNSYMBOLS-23A8" x="0" y="-2560"></use>
<g transform="translate(0,-2894.076656649662) scale(1,0.4941524617625568)">
<use xlink:href="#E1-LATINMODERNSIZE7-E003"></use>
</g>
<use xlink:href="#E1-LATINMODERNSYMBOLS-23A9" x="0" y="-3610"></use>
</g>
<g transform="translate(1074,0)">
<g transform="translate(-11,0)">
<g transform="translate(0,873)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D436" x="0" y="0"></use>
<g transform="translate(765,0)">
<use xlink:href="#E1-LATINMODERNMAIN-31" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNMAIN-2032" x="714" y="569"></use>
</g>
<use xlink:href="#E1-LATINMODERNMAIN-3D" x="1871" y="0"></use>
<g transform="translate(2932,0)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D434" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNMAIN-2032" x="1067" y="513"></use>
</g>
<use xlink:href="#E1-LATINMODERNMAIN-2B" x="4232" y="0"></use>
<g transform="translate(5015,0)">
<g transform="translate(342,0)">
<rect stroke="none" width="2149" height="60" x="0" y="220"></rect>
<g transform="translate(60,459)">
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNNORMAL-1D452" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNMAIN-31" x="471" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNMAIN-2212" x="976" y="0"></use>
<g transform="translate(1243,0)">
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNNORMAL-1D434" x="0" y="0"></use>
<use transform="scale(0.574)" xlink:href="#E1-LATINMODERNMAIN-2032" x="929" y="508"></use>
</g>
</g>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNNORMAL-1D461" x="1337" y="-558"></use>
</g>
</g>
</g>
<g transform="translate(0,-1123)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D436" x="0" y="0"></use>
<g transform="translate(765,0)">
<use xlink:href="#E1-LATINMODERNMAIN-32" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNMAIN-2032" x="714" y="569"></use>
</g>
<use xlink:href="#E1-LATINMODERNMAIN-3D" x="1871" y="0"></use>
<g transform="translate(2932,0)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D434" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNMAIN-2032" x="1067" y="513"></use>
</g>
<use xlink:href="#E1-LATINMODERNMAIN-2B" x="4232" y="0"></use>
<g transform="translate(5015,0)">
<g transform="translate(342,0)">
<rect stroke="none" width="2149" height="60" x="0" y="220"></rect>
<g transform="translate(60,459)">
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNNORMAL-1D452" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNMAIN-32" x="471" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNMAIN-2212" x="976" y="0"></use>
<g transform="translate(1243,0)">
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNNORMAL-1D434" x="0" y="0"></use>
<use transform="scale(0.574)" xlink:href="#E1-LATINMODERNMAIN-2032" x="929" y="508"></use>
</g>
</g>
<g transform="translate(490,-423)">
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNMAIN-31" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNMAIN-2212" x="505" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNNORMAL-1D461" x="1288" y="0"></use>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.0 KiB

View File

@@ -0,0 +1,44 @@
<svg xmlns:xlink="http://www.w3.org/1999/xlink" width="19ex" height="5.333ex" style="vertical-align: -1.667ex; margin-left: 0ex; margin-right: 0ex; margin-bottom: 1px; margin-top: 1px;" viewBox="0 -1589.3 8171.8 2314.7" xmlns="http://www.w3.org/2000/svg">
<defs>
<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-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-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-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-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-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-1D436" d="M760 695l-63 -255c-5 -18 -5 -20 -18 -20c-4 0 -15 0 -15 10s3 11 3 51c0 116 -59 193 -161 193c-89 0 -183 -50 -244 -121c-100 -117 -121 -279 -121 -336c0 -156 106 -208 196 -208c52 0 115 17 184 73c69 58 92 129 101 158c2 8 7 10 13 10c0 0 12 0 12 -10 c0 -3 -17 -94 -110 -176c-53 -46 -129 -86 -216 -86c-153 0 -271 109 -271 274c0 232 225 453 448 453c111 0 157 -75 166 -89l70 77c11 11 12 12 15 12c9 0 11 -7 11 -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-1D44E" d="M498 143c0 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 293c45 0 74 -27 92 -64c3 22 18 44 42 44c17 0 29 -10 29 -27c0 -4 0 -6 -7 -34l-36 -140l-22 -90 c-11 -44 -13 -52 -13 -74c0 -20 3 -46 30 -46c41 0 59 59 76 124c3 14 4 18 14 18c3 0 12 0 12 -10zM361 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 37l50 196c1 5 3 11 3 17Z"></path>
<path stroke-width="10" id="E1-LATINMODERNNORMAL-1D461" d="M330 420c0 -20 -10 -20 -30 -20h-94l-74 -295c-4 -17 -6 -24 -6 -48c0 -33 10 -46 31 -46c34 0 87 24 130 128c5 11 6 14 15 14c4 0 12 0 12 -10c0 -8 -57 -154 -159 -154c-54 0 -92 38 -92 92c0 18 4 35 76 319h-88c-20 0 -28 0 -28 12c0 19 10 19 30 19h94l39 159 c9 35 37 36 40 36c17 0 29 -10 29 -27c0 -6 -5 -26 -41 -168h88c18 0 28 0 28 -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-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>
</defs>
<g stroke="currentColor" fill="currentColor" stroke-width="0" transform="matrix(1 0 0 -1 0 0)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D434" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNMAIN-2032" x="1067" y="583"></use>
<use xlink:href="#E1-LATINMODERNMAIN-3D" x="1356" y="0"></use>
<g transform="translate(2417,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-2B" x="3726" y="0"></use>
<g transform="translate(4509,0)">
<g transform="translate(342,0)">
<rect stroke="none" width="3199" height="60" x="0" y="220"></rect>
<g transform="translate(60,676)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D435" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNMAIN-2032" x="1080" y="513"></use>
<use xlink:href="#E1-LATINMODERNMAIN-2212" x="1309" y="0"></use>
<use xlink:href="#E1-LATINMODERNNORMAL-1D436" x="2314" y="0"></use>
</g>
<g transform="translate(501,-691)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D45F" x="0" y="0"></use>
<use xlink:href="#E1-LATINMODERNNORMAL-1D44E" x="456" y="0"></use>
<use xlink:href="#E1-LATINMODERNNORMAL-1D461" x="990" y="0"></use>
<use xlink:href="#E1-LATINMODERNNORMAL-1D456" x="1356" y="0"></use>
<use xlink:href="#E1-LATINMODERNNORMAL-1D45C" x="1706" y="0"></use>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@@ -0,0 +1,76 @@
<svg xmlns:xlink="http://www.w3.org/1999/xlink" width="100ex" height="11.667ex" style="vertical-align: -8ex; margin-left: 0ex; margin-right: 0ex; margin-bottom: 1px; margin-top: 1px;" viewBox="0 -1589.3 43055.4 5032.5" xmlns="http://www.w3.org/2000/svg">
<defs>
<path stroke-width="10" id="E1-LATINMODERNNORMAL-1D436" d="M760 695l-63 -255c-5 -18 -5 -20 -18 -20c-4 0 -15 0 -15 10s3 11 3 51c0 116 -59 193 -161 193c-89 0 -183 -50 -244 -121c-100 -117 -121 -279 -121 -336c0 -156 106 -208 196 -208c52 0 115 17 184 73c69 58 92 129 101 158c2 8 7 10 13 10c0 0 12 0 12 -10 c0 -3 -17 -94 -110 -176c-53 -46 -129 -86 -216 -86c-153 0 -271 109 -271 274c0 232 225 453 448 453c111 0 157 -75 166 -89l70 77c11 11 12 12 15 12c9 0 11 -7 11 -10Z"></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-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-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-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-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-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-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-1D461" d="M330 420c0 -20 -10 -20 -30 -20h-94l-74 -295c-4 -17 -6 -24 -6 -48c0 -33 10 -46 31 -46c34 0 87 24 130 128c5 11 6 14 15 14c4 0 12 0 12 -10c0 -8 -57 -154 -159 -154c-54 0 -92 38 -92 92c0 18 4 35 76 319h-88c-20 0 -28 0 -28 12c0 19 10 19 30 19h94l39 159 c9 35 37 36 40 36c17 0 29 -10 29 -27c0 -6 -5 -26 -41 -168h88c18 0 28 0 28 -11Z"></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)">
<g transform="translate(17087,0)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D436" x="0" y="0"></use>
<g transform="translate(765,0)">
<use xlink:href="#E1-LATINMODERNMAIN-31" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNMAIN-2032" x="714" y="583"></use>
</g>
<use xlink:href="#E1-LATINMODERNMAIN-3D" x="1871" y="0"></use>
<g transform="translate(2932,0)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D434" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNMAIN-2032" x="1067" y="583"></use>
</g>
<use xlink:href="#E1-LATINMODERNMAIN-2B" x="4232" y="0"></use>
<g transform="translate(5015,0)">
<g transform="translate(342,0)">
<rect stroke="none" width="3401" height="60" x="0" y="220"></rect>
<g transform="translate(60,676)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D452" x="0" y="0"></use>
<use xlink:href="#E1-LATINMODERNMAIN-31" x="471" y="0"></use>
<use xlink:href="#E1-LATINMODERNMAIN-2212" x="1198" y="0"></use>
<g transform="translate(2203,0)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D434" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNMAIN-2032" x="1067" y="513"></use>
</g>
</g>
<use xlink:href="#E1-LATINMODERNNORMAL-1D461" x="1517" y="-686"></use>
</g>
</g>
</g>
<g transform="translate(17087,-2713)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D436" x="0" y="0"></use>
<g transform="translate(765,0)">
<use xlink:href="#E1-LATINMODERNMAIN-32" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNMAIN-2032" x="714" y="583"></use>
</g>
<use xlink:href="#E1-LATINMODERNMAIN-3D" x="1871" y="0"></use>
<g transform="translate(2932,0)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D434" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNMAIN-2032" x="1067" y="583"></use>
</g>
<use xlink:href="#E1-LATINMODERNMAIN-2B" x="4232" y="0"></use>
<g transform="translate(5015,0)">
<g transform="translate(342,0)">
<rect stroke="none" width="3401" height="60" x="0" y="220"></rect>
<g transform="translate(60,676)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D452" x="0" y="0"></use>
<use xlink:href="#E1-LATINMODERNMAIN-32" x="471" y="0"></use>
<use xlink:href="#E1-LATINMODERNMAIN-2212" x="1198" y="0"></use>
<g transform="translate(2203,0)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D434" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNMAIN-2032" x="1067" y="513"></use>
</g>
</g>
<g transform="translate(651,-696)">
<use xlink:href="#E1-LATINMODERNMAIN-31" x="0" y="0"></use>
<use xlink:href="#E1-LATINMODERNMAIN-2212" x="727" y="0"></use>
<use xlink:href="#E1-LATINMODERNNORMAL-1D461" x="1732" y="0"></use>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

@@ -0,0 +1,86 @@
<svg xmlns:xlink="http://www.w3.org/1999/xlink" width="21.333ex" height="11.333ex" style="vertical-align: -5.167ex; margin-left: 0ex; margin-right: 0ex; margin-bottom: 1px; margin-top: 1px;" viewBox="0 -2701 9203.3 4902" xmlns="http://www.w3.org/2000/svg">
<defs>
<path stroke-width="10" id="E1-LATINMODERNNORMAL-1D436" d="M760 695l-63 -255c-5 -18 -5 -20 -18 -20c-4 0 -15 0 -15 10s3 11 3 51c0 116 -59 193 -161 193c-89 0 -183 -50 -244 -121c-100 -117 -121 -279 -121 -336c0 -156 106 -208 196 -208c52 0 115 17 184 73c69 58 92 129 101 158c2 8 7 10 13 10c0 0 12 0 12 -10 c0 -3 -17 -94 -110 -176c-53 -46 -129 -86 -216 -86c-153 0 -271 109 -271 274c0 232 225 453 448 453c111 0 157 -75 166 -89l70 77c11 11 12 12 15 12c9 0 11 -7 11 -10Z"></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-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-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-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-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-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-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-1D461" d="M330 420c0 -20 -10 -20 -30 -20h-94l-74 -295c-4 -17 -6 -24 -6 -48c0 -33 10 -46 31 -46c34 0 87 24 130 128c5 11 6 14 15 14c4 0 12 0 12 -10c0 -8 -57 -154 -159 -154c-54 0 -92 38 -92 92c0 18 4 35 76 319h-88c-20 0 -28 0 -28 12c0 19 10 19 30 19h94l39 159 c9 35 37 36 40 36c17 0 29 -10 29 -27c0 -6 -5 -26 -41 -168h88c18 0 28 0 28 -11Z"></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)">
<g transform="translate(167,0)">
<g transform="translate(-11,0)">
<g transform="translate(0,1111)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D436" x="0" y="0"></use>
<g transform="translate(765,0)">
<use xlink:href="#E1-LATINMODERNMAIN-31" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNMAIN-2032" x="714" y="583"></use>
</g>
</g>
<g transform="translate(0,-1471)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D436" x="0" y="0"></use>
<g transform="translate(765,0)">
<use xlink:href="#E1-LATINMODERNMAIN-32" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNMAIN-2032" x="714" y="583"></use>
</g>
</g>
</g>
<g transform="translate(1582,0)">
<g transform="translate(0,1111)">
<use xlink:href="#E1-LATINMODERNMAIN-3D" x="277" y="0"></use>
<g transform="translate(1338,0)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D434" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNMAIN-2032" x="1067" y="583"></use>
</g>
<use xlink:href="#E1-LATINMODERNMAIN-2B" x="2639" y="0"></use>
<g transform="translate(3422,0)">
<g transform="translate(342,0)">
<rect stroke="none" width="3401" height="60" x="0" y="220"></rect>
<g transform="translate(60,676)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D452" x="0" y="0"></use>
<use xlink:href="#E1-LATINMODERNMAIN-31" x="471" y="0"></use>
<use xlink:href="#E1-LATINMODERNMAIN-2212" x="1198" y="0"></use>
<g transform="translate(2203,0)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D434" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNMAIN-2032" x="1067" y="513"></use>
</g>
</g>
<use xlink:href="#E1-LATINMODERNNORMAL-1D461" x="1517" y="-686"></use>
</g>
</g>
</g>
<g transform="translate(0,-1471)">
<use xlink:href="#E1-LATINMODERNMAIN-3D" x="277" y="0"></use>
<g transform="translate(1338,0)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D434" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNMAIN-2032" x="1067" y="583"></use>
</g>
<use xlink:href="#E1-LATINMODERNMAIN-2B" x="2639" y="0"></use>
<g transform="translate(3422,0)">
<g transform="translate(342,0)">
<rect stroke="none" width="3401" height="60" x="0" y="220"></rect>
<g transform="translate(60,676)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D452" x="0" y="0"></use>
<use xlink:href="#E1-LATINMODERNMAIN-32" x="471" y="0"></use>
<use xlink:href="#E1-LATINMODERNMAIN-2212" x="1198" y="0"></use>
<g transform="translate(2203,0)">
<use xlink:href="#E1-LATINMODERNNORMAL-1D434" x="0" y="0"></use>
<use transform="scale(0.707)" xlink:href="#E1-LATINMODERNMAIN-2032" x="1067" y="513"></use>
</g>
</g>
<g transform="translate(651,-696)">
<use xlink:href="#E1-LATINMODERNMAIN-31" x="0" y="0"></use>
<use xlink:href="#E1-LATINMODERNMAIN-2212" x="727" y="0"></use>
<use xlink:href="#E1-LATINMODERNNORMAL-1D461" x="1732" y="0"></use>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

@@ -23,7 +23,7 @@
header h1, header h2 { text-align: center; } header h1, header h2 { text-align: center; }
header h1 { font-size: 300%; margin: 0.2em; } header h1 { font-size: 300%; margin: 0.2em; }
p.jsnote { margin: 2em; text-align: justify; } p.jsnote { margin: 2em; text-align: justify; }
p.jsnote:first-child { width:10em; margin: auto; } p.jsnote:first-child { width: 13em; margin: auto; }
</style> </style>
</head> </head>
<body> <body>