裙片排版小程序

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>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章