在 OpenSCAD 中,我希望能够创建一个module
接受 astring
然后创建一个 3-D 对象,该字符串作为text
. 我希望对象比 略大text
,所以我需要知道 的宽度text
以便创建大小合适的对象。
我不确定如何查询宽度text
(高度由输入变量设置),或者是否可能。
如果不可能,是否有一个函数可以接受字符串和字体并预测渲染文本的宽度?
目前无法查询生成的文本几何图形的实际大小。但是,根据将要创建的模型,计算粗略估计并用于scale()
使文本适合已知大小可能就足够了。
// Fit text into a randomly generated area
r = rands(10, 20, 2);
length = 3 * r[0];
w = r[1];
difference() {
cube([length, w, 1]);
color("white")
translate([0, w / 2, 0.6])
linear_extrude(1, convexity = 4)
resize([length, 0], auto = true)
text("This is a Test", valign = "center");
}
我找到了一种方法来确定 OpenSCAD 中文本字符的宽度。我做了一个 JavaScript 东西,可以让你输入字体名称和样式,它会输出一个 ascii 和扩展 ascii 字符(代码 0-255)的宽度比例数组。然后对于任何给定的字符,将此比例乘以字体大小以获得单个字符的宽度。从那里获得字符串的宽度或围绕圆柱体缠绕的字符的角宽度是微不足道的。
生成 OpenSCAD 宽度数组的工具在这里:https ://codepen.io/amatulic/pen/eYeBLva
...并且代码在下面复制,您可以从这个回复中运行,或者粘贴到您自己的 HTML 文件中并在本地加载到您的浏览器中。
只需输入字体属性,单击按钮,然后向下滚动即可查看使用说明。
秘诀在于 JavaScript 的“画布”支持有一个“measureText()”方法,可以测量给定字体的任何文本的像素长度,使用如下:
canvasContext.measureText(string).width
所以这段代码的作用是在页面上使用一个虚拟画布来获取分配字体的上下文,任意 20 像素大小。然后它为从 0 到 255 的每个字符生成一个宽度数组,将每个字符除以 20 以获得与字体大小相比的无单位宽度比例。然后它会输出一行 OpenSCAD 代码,您可以将其粘贴到您的 OpenSCAD 脚本中。然后使用 OpenSCAD 的ord()
函数将任何字符转换为数字代码,然后将其用作宽度数组的索引。然后将此宽度乘以字体大小以获得字符宽度。
<html>
<!--
by Alex Matulich, February 2022
Thingiverse: https://www.thingiverse.com/amatulic/designs
Website: https://www.nablu.com
-->
<head>
<script type="text/javascript">
var sctx;
function initialize() {
var canvas = document.getElementById("canvas");
sctx = canvas.getContext("2d");
}
function charwidth(fontname, style) {
sctx.font = (style + " 20px " + fontname).trim();
var charlen = [];
for (i = 0; i < 256; ++i) //{ charlen[i] = 10; console.log(i); }
charlen[i] = sctx.measureText(String.fromCharCode(i)).width / 20;
return charlen;
}
function generate() {
var fontname = document.getElementById("fontname").value;
var fontstyle = document.getElementById("fontstyle").value;
var widths = charwidth(fontname, fontstyle);
var arrayname = toCamelCase(fontname) + toCamelCase(fontstyle);
var outputhtml = arrayname + " = [<br/>\n" + widths[0].toString();
var len = widths.length;
for (i = 0; i < len; ++i) outputhtml += ', ' + widths[i].toString();
outputhtml += "<br/>\n];\n";
document.getElementById("output").innerHTML = outputhtml;
document.getElementById('usage').innerHTML = "<h3>Usage</h3>\n<p>The array above shows character width as a multiple of font size. To get the width of a character <code><char></code> given font size <code><fontsize></code> using the font \"" + fontname + " " + fontstyle + "\":</p>\n<p><code> charwidth = " + arrayname + "[ord(char)] * fontsize;<code></p>\n";
document.getElementById('sample').innerHTML = "<h3>Font sample</h3>\n<p style=\"font: " + fontstyle + " 20px " + fontname + ";\">" + fontname + " " + fontstyle + ": 0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz</p>\n";
}
// convert the input array to camel case
function toCamelCase(stringinput) {
if (stringinput.length == 0) return '';
var inputArray = stringinput.match(/[A-Z\xC0-\xD6\xD8-\xDE]?[a-z\xDF-\xF6\xF8-\xFF]+|[A-Z\xC0-\xD6\xD8-\xDE]+(?![a-z\xDF-\xF6\xF8-\xFF])|\d+/g);
result = "";
for (let i = 0, len = inputArray.length; i < len; i++) {
let currentStr = inputArray[i];
let tempStr = currentStr.toLowerCase();
// convert first letter to upper case (the word is in lowercase)
tempStr = tempStr.substr(0, 1).toUpperCase() + tempStr.substr(1);
result += tempStr;
}
return result;
}
</script>
</head>
<body onload="initialize()">
<h1>OpenSCAD proportional font widths</h1>
<form>
<fieldset>
<legend>Identify the font</legend>
<input type="text" id="fontname" name="fontname" value="Liberation Sans">
<label for="fontname">Font name</label><br />
<input type="text" id="fontstyle" name="fontstyle" value="bold">
<label for="fontstyle">Font style (bold, italic, etc. or leave blank)<br />
</fieldset>
<input type="button" onclick="generate()" value="Generate OpenSCAD font width proportions">
</form>
<h2>Copy and paste this code into OpenSCAD</h2>
<div id="output" style="border:5px ridge silver; padding:1em; font-family:monospace;">
</div>
<div id="usage">
</div>
<div id="sample">
</div>
<canvas id="canvas"></canvas>
</body>
</html>