在 OpenSCAD 中,我希望能够创建一个
module
,它接受 string
,然后创建一个 3D 对象,并将该字符串作为 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");
}
更新(2024)原始问题和所有答案已被 OpenSCAD 日常版本中现在存在的
textmetrics()
函数取代。
我找到了一种确定 OpenSCAD 中文本字符宽度的方法。我制作了一个 JavaScript 东西,它可以让你输入字体名称和样式,并输出一个 ascii 和扩展 ascii 字符(代码 0-255)的宽度比例数组。然后,对于任何给定的字符,将此比例乘以字体大小即可得到单个字符的宽度。从那里获取字符串的宽度或围绕圆柱体的字符的角宽度很简单。
生成 OpenSCAD 宽度数组的工具在这里:https://codepen.io/amatulic/pen/eYeBLva
...代码复制如下,您可以从此回复中运行该代码,或粘贴到您自己的 HTML 文件中并在本地加载到您的浏览器中。
只需输入字体属性,点击按钮,向下滚动即可查看使用说明。
秘密在于 JavaScript 的“canvas”支持有一个“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 = 1; 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>