sublime text editor
需求:
你有一块布,布的长度和门幅确定,问怎么对裙片进行排版,可以使得用料最省?
裙片是一个扇环。
需要用到三角函数,勾股定理。
输入参数:
布匹长度: len
布匹门幅(宽度): width
裙片的内圆半径(一般是13厘米左右): r2
裙片的外圆半径: r1
裙片的角的大小(一般是180度到45度,角度制): angle
是否从半片开始(堆叠裁剪,工厂裁剪都是从半片开始):startWithHalf
输出
布匹的最大利用率:unitUsage
布匹的实际利用率:usagePercent
工厂一般采用堆叠裁剪,先把布匹Z型堆叠,然后从半片开始裁剪,追求布匹的最大利用率。
裙子长度 = 裙片的外圆半径 - 裙片的内圆半径
其他参数说明:
裙片排版宽度的一半:eLen
裙片排版高度:singePartHeight
裙片的拼接方式主要有两种:
1. 圆弧拼接 arcMatching()
2. 半径拼接 radiusMatching()
最经济的拼接方式应该是圆弧拼接,当r1 == width, 裙片的角为180度时,最大利用率unitUsage = 0.8948967025354823
当裙片的角为30度时,进行半径拼接,最大利用率虽然可以达到0.96,但是裙片变小变多,需要进行更多的缝纫,另外太多的缝和,使得成品不够美观,档次被拉低了
<!DOCTYPE html>
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<head>
</head>
<body style="font-family:'lucida grande', tahoma, verdana, arial, sans-serif;background-color: #f7f7f7;color: #333;">
<img id="spacebg" src="https://img-my.csdn.net/uploads/201207/02/1341222679_9916.jpg" style="display:none" />
<canvas id="canvas" width="660" height="510" style="border:1px dotted;float:left"></canvas>
<br>
<form action="action_page.php">
inner radius (cm):<br>
<input type="text" id="innerR" value="13">
<br>
outer radius (cm):<br>
<input type="text" id="outerR" value="113">
<br>
skirt part angle (degree):<br>
<input type="text" id="angleInput" value="90">
<br>
cloth width (cm):<br>
<input type="text" id="widthInput" value="140">
<br>
cloth length (cm):<br>
<input type="text" id="lengthInput" value="500">
<br>
start with half part:
<input type="checkbox" name="startWithHalfCb" checked="checked" id="cb1">
<br><br>
<span>Total usage:</span> <span id="usage">0</span><br>
<span>Unit usage:</span> <span id="unitUsage">0</span> <br>
<span>Half parts:</span> <span id="halfParts">0</span> <br>
<br><br>
<!-- <input type="submit" value="Submit" onclick="start()"> -->
</form>
<input type="button" value="start" onclick="start()" id="startBtn" />
<script>
var r1 = 90;
var r2 = 20;
var angle = 180;
var width = 140;
var len = 500;
var angleBeta = (180 - angle) / 2;
var d1, d2, stepLen, eLen;
var skirtPartArea;
var startWithHalf = true;
var halfCount = 0;
function drawSkirtPart(ctx, x, y, startRadian, endRadian) {
ctx.beginPath();
ctx.moveTo(x, y);
ctx.arc(x, y, r1, startRadian, endRadian, false);
ctx.fillStyle="#009900";
ctx.closePath();
ctx.fill();
ctx.beginPath();
ctx.moveTo(x, y);
ctx.arc(x, y, r2, startRadian, endRadian, false);
ctx.fillStyle="white";
ctx.closePath();
ctx.fill();
}
function initParams () {
r1 = parseInt(document.getElementById("outerR").value);
r2 = parseInt(document.getElementById("innerR").value);
angle = parseInt(document.getElementById("angleInput").value);
width = parseInt(document.getElementById("widthInput").value);
len = parseInt(document.getElementById("lengthInput").value);
var cbs = document.getElementsByName('startWithHalfCb');
for(var i=0;i<cbs.length;i++){
startWithHalf = cbs[i].checked;
}
angleBeta = (180 - angle) / 2;
}
function draw() {
var canvas = document.getElementById("canvas");
if (canvas == null) {
return;
}
var ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, 600, 600);
ctx.strokeRect(0, 0, len, width);
if (halfCount == 0) {
return;
}
var start1 = degreeToRadian(angleBeta);
var end1 = degreeToRadian(angleBeta + angle);
var count = halfCount;
if (startWithHalf) {
drawSkirtPart(ctx, 0, -d1, start1, Math.PI / 2);
count--;
var drawDown = true;
for (var i=1; count > 0; count -= 2) {
if (count > 1) {
if (drawDown) {
drawSkirtPart(ctx, stepLen * i, width + d1, start1 + Math.PI, end1 + Math.PI);
} else {
drawSkirtPart(ctx, stepLen * i, -d1, start1, end1);
}
} else {
if (drawDown) {
drawSkirtPart(ctx, stepLen * i, width + d1, start1 + Math.PI, Math.PI * 1.5);
} else {
drawSkirtPart(ctx, stepLen * i, -d1, Math.PI / 2, end1);
}
}
drawDown = !drawDown;
i++;
}
} else {
if (halfCount > 1) {
drawSkirtPart(ctx, eLen, -d1, start1, end1);
count -= 2;
} else {
drawSkirtPart(ctx, eLen, -d1, Math.PI / 2, end1);
count--;
}
var drawDown = true;
for (var i=1; count > 0; count -= 2) {
if (count > 1) {
if (drawDown) {
drawSkirtPart(ctx, stepLen * i + eLen, width + d1, start1 + Math.PI, end1 + Math.PI);
} else {
drawSkirtPart(ctx, stepLen * i + eLen, -d1, start1, end1);
}
} else {
if (drawDown) {
drawSkirtPart(ctx, stepLen * i + eLen, width + d1, start1 + Math.PI, Math.PI * 1.5);
} else {
drawSkirtPart(ctx, stepLen * i + eLen, -d1, Math.PI / 2, end1);
}
}
drawDown = !drawDown;
i++;
}
}
}
function draw2() {
var canvas = document.getElementById("canvas");
if (canvas == null) {
return;
}
var ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, 600, 600);
ctx.strokeRect(0, 0, len, width);
if (halfCount == 0) {
return;
}
var start1 = degreeToRadian(angleBeta) + Math.PI;
var end1 = start1 + degreeToRadian(angle);
var count = halfCount;
if (startWithHalf) {
drawSkirtPart(ctx, 0, r1, Math.PI*1.5, end1);
count--;
var drawDown = true;
for (var i=1; count > 0; count -= 2) {
if (count > 1) {
if (drawDown) {
drawSkirtPart(ctx, stepLen * i, extraH, start1 - Math.PI, end1 - Math.PI);
} else {
drawSkirtPart(ctx, stepLen * i, r1, start1, end1);
}
} else {
if (drawDown) {
drawSkirtPart(ctx, stepLen * i, extraH, Math.PI / 2, end1 - Math.PI);
} else {
drawSkirtPart(ctx, stepLen * i, r1, start1, Math.PI * 1.5);
}
}
drawDown = !drawDown;
i++;
}
} else {
if (halfCount > 1) {
drawSkirtPart(ctx, eLen, r1, start1, end1);
count -= 2;
} else {
drawSkirtPart(ctx, eLen, r1, start1, Math.PI * 1.5);
count--;
}
var drawDown = true;
for (var i=1; count > 0; count -= 2) {
if (count > 1) {
if (drawDown) {
drawSkirtPart(ctx, stepLen * i + eLen, extraH, start1 - Math.PI, end1 - Math.PI);
} else {
drawSkirtPart(ctx, stepLen * i + eLen, r1, start1, end1);
}
} else {
if (drawDown) {
drawSkirtPart(ctx, stepLen * i + eLen, extraH, Math.PI / 2, end1 - Math.PI);
} else {
drawSkirtPart(ctx, stepLen * i + eLen, r1, start1, Math.PI * 1.5);
}
}
drawDown = !drawDown;
i++;
}
}
}
var isLineMatching;
function start() {
initParams ();
eLen = r1 * Math.sin(degreeToRadian( angle/2 ));
var totalArea = width * len;
var singePartHeight = r1 - r2 * Math.sin(degreeToRadian(angleBeta));
if (singePartHeight > width) {
alert("cloth not support such long skirt part!");
}
var stepLenRadius = radiusMatching();
var stepLenArc = arcMatching();
if (stepLenRadius <= stepLenArc) {
stepLen = stepLenRadius;
isLineMatching = true;
} else {
stepLen = stepLenArc;
isLineMatching = false;
}
skirtPartArea = Math.PI * (r1 * r1 - r2 * r2) * (angle / 360);
// alert("stepLen: " + stepLen + ", eLen: " + eLen);
if (startWithHalf) {
halfCount = getHalfPartsCount(len, stepLen, eLen);
} else {
halfCount = getHalfPartsCount(len - eLen, stepLen, eLen);
halfCount ++;
}
var usagePercent = (skirtPartArea * halfCount / 2) / totalArea;
var unitUsage = skirtPartArea / (width * stepLen);
// alert("unitUsage: " + unitUsage + ", usagePercent: " + usagePercent + ", halfCount: " + halfCount);
document.getElementById("unitUsage").innerHTML = unitUsage;
document.getElementById("usage").innerHTML = usagePercent;
document.getElementById("halfParts").innerHTML = halfCount;
if (isLineMatching) {
draw2();
} else {
draw();
}
}
var extraH;
function radiusMatching() {
var stepLength;
extraH = r1 - r1 * Math.sin(degreeToRadian(angleBeta));
var h2 = r1 + extraH;
if (h2 <= width) {
stepLength = r1 * Math.cos(degreeToRadian(angleBeta));
} else {
var len2 = width / Math.sin(degreeToRadian(angleBeta));
var ret1 = (len2 + 2 * r2) * Math.cos(degreeToRadian(angleBeta));
var dh = width - r1;
var h2 = width - 2 * dh;
var ret2 = h2 / Math.tan(degreeToRadian(angleBeta));
if (ret1 <= ret2) {
stepLength = ret1;
} else {
stepLength = ret2;
extraH = dh;
}
}
return stepLength;
}
function arcMatching() {
d1 = r2 * Math.sin(degreeToRadian(angleBeta));
var d2 = width + 2 * d1;
var hypotenuse = 2 * r1;
var stepLength = Math.sqrt(hypotenuse*hypotenuse - d2 * d2);
var minStepLen = r1 * Math.cos(angleBeta);
if (stepLength < minStepLen) {
stepLength = minStepLen;
}
return stepLength;
}
function degreeToRadian(degree) {
return (degree / 180) * Math.PI;
}
function getHalfPartsCount(length, stepLength, halfPartWidth) {
// if (stepLength < halfPartWidth) {
// return 0;
// }
var c = parseInt(length / stepLength);
var remain = length - c * stepLength;
var halfCount = c * 2;
if (remain >= halfPartWidth) {
halfCount ++;
}
return halfCount;
}
// window.onload=init;
</script>
</body>
</html>