APIドキュメント

HTTPサービスとしてのオプティマイザー: カットリストと母材を送信し、検証済みの切断計画または印刷用のPDFを受信します。安定性、バージョン管理、後方互換性あり: フィールドは追加されるのみで、削除されることはありません。

概要

ベースURLはhttps://api.linearcutting.com。PDFエンドポイントを除き、すべてJSON形式です。リクエストはステートレスで、カットリストが保存されることはありません。

試用にAPIキーは不要です。 下の行をそのままターミナルに貼り付けて実行してください。

Copy, paste, run
curl -X POST https://api.linearcutting.com/v1/optimise \
  -H "Content-Type: application/json" \
  -d '{"parts": "2400x5, 1800x3", "stock": 6000}'

これは完全なカットリストです。2400mmが5本、1800mmが3本、6000mmの定尺材から切り出します。レイアウト、必要な定尺材の本数、屑の量、そして計画が証明可能な最適解であるかどうかが返されます。

認証なしのコールは無料の公開プランで実行されるため、購入前に評価できます。IPアドレスごとに1時間あたり30リクエスト、1暦月あたり250リクエストまで。上限を超えると429エラーが返され、リセットされる時刻が通知されます。失敗したコールはカウントされません。本格的に利用する場合は、月額5ドルからキーを取得してください。両方の上限が引き上げられ、規模の上限も上がり、専用の同時実行性が確保されるため、公開プランが混み合っても影響を受けません。

公式クライアント

依存関係なし、MITライセンス、キー不要。PythonやJavaScriptをお使いなら、fetchを自作する必要はありません。

pip install linearcutting
import linearcutting as lc

plan = lc.optimise(parts="2400x5, 1800x3", stock=6000)
plan.bars_used   # 4
plan.optimal     # True, proved, not guessed
npm install linearcutting
import { optimise } from "linearcutting";

const plan = await optimise({ parts: "2400x5, 1800x3", stock: 6000 });
plan.barsUsed;   // 4
plan.optimal;    // true

PyPIのPython · npmのJavaScript · Pythonソース · JavaScriptソース

信頼できる2つの保証。verifiedは成功時に常にtrueです。全ての計画は返される前に入力に対して再監査されるため、リスト通りに切断できない計画が届くことはありません。optimalは推測ではなく証明です。可能性を尽くすか証明書によってこれ以上良い計画が存在しないと確定した場合にのみtrueになります。時間内に証明できない場合は、期待的観測でなくfalseを返します。

optimalとstockBarsLowerBoundは意図的に異なる値を返します。 下限値は緩和計算(総長 ÷ 母材長)であり、多くの場合達成不可能です。2400mmが5本と1800mmが3本で合計17,400mm、6000mmの母材なら2.9本分なので下限は3本です。しかし、実際にこれらの部品を3本の母材から切り出すことはできず、真の最小値は4本です。ソルバーはそれを証明します。したがって、stockBarsUsed: 4stockBarsLowerBound: 3optimal: trueは矛盾ではなく、計画が悪いのではなく下限値が緩かったことを意味します。探索を続けるかどうかの判断にはoptimalを、正気度チェックにのみ下限値を使用してください。

短縮記法

通常形式は冗長で少し長めです。一般的なケースでは、数値を長さ、xを数量として短縮記法が使えます:

The short form
{"parts": "2400x5, 1800x3, 600", "stock": 6000}

これらはすべて同じ意味なので、コーディングのスタイルに合わせて使い分けてください:

All equivalent
{"parts": "2400x5"}
{"parts": ["2400x5"]}
{"parts": [[2400, 5]]}
{"parts": [{"length": 2400, "quantity": 5}]}

3番目の要素は部品のラベル、または母材の価格です:[2400, 5, "rail"][6000, 20, 45.50]。また、stockは古いstockLength / stocks分割に代わる分かりやすい名前で、単一の数値は「この長さ、必要なだけ購入」を意味します。

短縮記法は他の処理に先立って展開されるため、異なるモードではなく入力方法の一つです。短縮リクエストと、それが展開された通常リクエストは、バイト単位で同一の計画を返します。自由に組み合わせて使用でき、既存のリクエストもすべて従来通りに機能します。

URLでのカットリスト指定

小規模なジョブはクエリ文字列に収まるため、GET も使用できます。共有、引用、またはバグレポートに含めたいリンクに便利です。

GET /v1/optimise
curl "https://api.linearcutting.com/v1/optimise?parts=2400x5,1800x3&stock=6000"

認証、制限、プランは POST と同じです。必要であればブラウザで開いてください。

認証

公開層にキーは不要です。有料層はヘッダーでキーを送信します。キーには許可されたブラウザのオリジンも含まれるため、プロキシなしで自社サイトから呼び出しが機能します。

http
X-API-Key: lk_live_9f2c...

キーが不正または期限切れの場合は 401 が返されます。キーはワークスペースごとに発行されます: プランを見る

POST /v1/optimise

カットリストを解決します。切断計画、統計、および証明可能な範囲を返します。

リクエストボディ

フィールドタイプデフォルト説明
parts 必須 array- 必要な部品。各項目: length (> 0)、quantity (整数 ≥ 1)、オプションで labelmaterialleftAnglerightAngle
stockLength number- 単一の無制限の母材長。これまたは stocks のいずれかを使用し、両方は使用しません。
stocks array- 購入可能な定尺材。各項目: lengthquantity (null = 無制限)、price (null = 金額ではなく材料を最適化)、オプションで materialprioritybundleSize (method: "bundle" の場合、バンドルあたりの本数)。
offcuts array[] 所有済みの端材: lengthquantity、オプションで materialpriority。無料の材料であり、購入数には計上されません。
kerfnumber ≥ 00切断1回あたりの刃幅。
trimbooleanfalse切断前に、各母材の両端を切り揃えます。
methodstringbalanced balancedleast_wasteoffcuts_firstfewest_setups (エイリアス: fewest_setups)、bundle (stocks[].bundleSize が必要)。stocks に価格が設定されている場合、balanced は最低コストに切り替わります。
minRemnantnumber ≥ 00この長さ以上の残材は、廃棄ではなく usableRemnants (利用可能な端材) として返されます。
angleCutsobjectoff{enabled, width, axialSymmetry}角度切りを参照してください。
unitstring"mm"PDFにそのまま反映・印刷されます。単位変換は行われません。
unitFormatstringdecimalfractionは、PDFの寸法を最も近い1/64の分数で表示します。
timeLimitsecondsauto計算時間。プランの上限による。計算時間が長いほど、結果の精度が向上します。

レスポンス

200 application/json
{
  "plan": {
    "combinations": [
      {
        "usedComb": {
          "combination": [2400, 2400, 1200],
          "length": 6500,
          "source": "stock",
          "waste": { "total": 492, "remnant": 484, "saw": 8 }
        },
        "count": 2
      }
    ],
    "purchases":      [{ "length": 6500, "count": 2 }],
    "usableRemnants": [],
    "unusedOffcuts":  [],
    "stockBarsUsed":  2,
    "stockBarsLowerBound": 2,
    "totalWaste":     984,
    "optimal":        true,
    "verified":       true,
    "solveTimeMs":    12.5
  },
  "stats": {
    "totalParts": 8, "totalPartsLength": 15600, "totalUsedLength": 16600,
    "yieldPercent": 93.98, "cutCount": 8, "layoutCount": 1,
    "totalCost": null, "trueWaste": 984
  },
  "costLowerBound": null,
  "meta": { "method": "balanced", "kerf": 4, "tier": "public",
            "poweredBy": "linearcutting.com" }
}
フィールド説明
plan.combinations[]個別のレイアウトごとのエントリー。usedComb.combinationはその母材からカットされる部品リスト、lengthは材料長、sourcestock(母材)またはoffcut(残材)、countはその方法でカットする母材の本数です。
usedComb.wastetotal = 材料長 - 部品長。saw(切り代 + 端切り)とremnant(末端の残り)に分けられます。
plan.purchases[]購入リスト:length(長さ)、count(本数)、価格を指定した場合はprice/cost(単価/コスト)が含まれます。
plan.usableRemnantsminRemnant以上の残材。大きいものから順に表示。次回の残材在庫になります。
plan.unusedOffcuts計画で使用されなかった残材。
plan.stockBarsUsed購入する母材の合計本数。
plan.optimal証明。 計画が証明可能な下限値に達した場合(または全探索が完了した場合)にのみ真となります。「最適解」としてユーザーに表示して問題ありません。
plan.verified成功時は常に真:需要との一致、全レイアウトの物理的な整合性、残材供給の遵守が確認されています。
plan.stockBarsLowerBound, costLowerBound証明可能な最小値。optimalが偽の場合、この差が計画の最大誤差を示します。
statsジョブ合計:部品、母材、yieldPercent (歩留まり)、cutCount (切断数)、layoutCount (レイアウト数)、totalCost (総コスト)、trueWaste (廃棄量)、材料グループ使用時はbyMaterial

POST /v1/optimise/pdf

リクエストボディは同じ、オプションでjobNameを追加可能。application/pdfを返す。1ページ目はプロジェクト管理者向けの要約(発注書、コスト、最適性証明書)。2ページ目以降は、のこ盤オペレーター向けのシートで、切断位置、部品ラベル、母材ごとのチェックボックスが記載される。キーを持つ呼び出し元は、その属性やブランドが表示される。

bash
curl -X POST https://api.linearcutting.com/v1/optimise/pdf \
  -H "Content-Type: application/json" \
  -H "X-API-Key: lk_live_9f2c..." \
  -d '{ "parts": [{"length": 2400, "quantity": 4}], "stockLength": 6500,
       "kerf": 4, "jobName": "Smith deck order" }' \
  --output cutting-plan.pdf

GET /v1/health

json
{ "status": "ok", "version": "1.3.0", "solver": "Linear Cutlist Optimizer v2" }

材料グループ

partsstocksoffcutsmaterialタグを付けると、材料ごとに個別のジョブとして扱われます。カットは同じ材料の母材にのみ割り当てられます。レイアウトと購入数はタグ付けされて返され、stats.byMaterialでグループ別の内訳が確認できます。

json
{
  "parts": [
    { "length": 2400, "quantity": 4, "material": "40x40 SHS" },
    { "length": 1300, "quantity": 6, "material": "Pine 90x45" }
  ],
  "stocks": [
    { "length": 6500, "quantity": null, "material": "40x40 SHS" },
    { "length": 5400, "quantity": null, "material": "Pine 90x45", "priority": true }
  ],
  "kerf": 3
}

母材や端材にpriority: trueを設定すると、緩やかな優先指定として機能します。同品質の切断計画が複数ある場合、優先度の高い材料が先に使用されます。これにより最適性が損なわれることはありません。

角度切り / 留め切り

部品にleftAnglerightAngleを指定し、angleCutsを有効化します。角度は、部材を水平に置いた際の底角を指します。上角は負数で入力してください(例: 120度と-60度は同一のカット)。変換後の有効範囲は10~170度です。

angleCuts field説明
enabled全体の有効化スイッチ。trueの場合のみ、部品の角度指定が処理されます。
width材料の幅。長さと同じ単位で指定します。角度切断で横方向に必要となる寸法は width / tan(angle) で計算されます。
axialSymmetrynoneXYZXYZのいずれかで、材料の反転可能な軸を指定します。これにより、留め切りのネスティング方法が決まります。角パイプは通常XYZ、片面仕上げ材はnoneです。

隣接する2つの留め切りが平行な場合、1回の切断で両方の木口を加工できます。角度モードのレイアウトには、使用された向きを含む順序付きのparts配列と、cutPositionsが追加されます。各切断位置は母材のゼロ点からの距離で示され、角度がある場合は[上辺, 下辺]のペア、直角の場合は単一の数値となります。

angle-mode layout (excerpt)
"cutPositions": [[1200, 1300], [2442.265, 2500], 3300]

エラー

エラー本体の形式は { "error": "...", "detail": "..." } です。detailは人間が読むためのもので、問題のある部品や材料名を特定します。

ステータスエラー発生条件
400validation長さや数量が不正、不明なメソッド、どの母材にも収まらない部品、有限の母材で需要を満たせない、角度のルール違反、stocksstockLengthが両方送信された場合。
401badKeyAPIキーが欠落、不明、または無効です。
413partsLimitご利用のプランの上限を超える部品数です。
429rateLimitedレートまたは月間上限に達しました。Retry-Afterに従ってください。
503busyソルバーが処理能力の上限に達しています。しばらくしてから再試行してください。

レート制限

制限はスロットルとして機能し、超過料金は発生しません。検証に失敗したリクエストは月間上限にはカウントされません。詳細な数値は料金プランページで確認できます。

ガード無料有料プラン
レートIPあたり30回/時プランにより20-240回/分
総部品数300500 - 5,000
個別部品の種類60最大1,000
計算時間20 s60 - 300 s

計算コストは長さの多様性に依存するため、総部品数だけでなく個別部品の種類にも上限があります。同じ長さ300個の切断はミリ秒で最適化できますが、300個の異なる長さではそうはいきません。

使用例

複数種類の母材から最も安価な組み合わせを計算 (JavaScript)

javascript
const res = await fetch("https://api.linearcutting.com/v1/optimise", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-API-Key": "lk_live_9f2c...",
  },
  body: JSON.stringify({
    parts: [
      { length: 3000, quantity: 8 },
      { length: 1200, quantity: 10 },
    ],
    stocks: [
      { length: 6500, quantity: null, price: 45 },   // unlimited
      { length: 12000, quantity: 4, price: 70 },     // only four on hand
    ],
    offcuts: [{ length: 2600, quantity: 1 }],
    kerf: 4,
    minRemnant: 400,
    method: "balanced",   // prices present -> optimises dollars
  }),
});

const { plan, stats } = await res.json();
console.log(plan.purchases);     // what to buy
console.log(stats.totalCost);    // what it costs
console.log(plan.optimal);       // true = provably the cheapest

留め継ぎフレームの部品 (Python)

python
import requests

r = requests.post(
    "https://api.linearcutting.com/v1/optimise",
    json={
        "parts": [
            {"length": 1300, "quantity": 2, "leftAngle": 90, "rightAngle": 45},
            {"length": 1200, "quantity": 2, "leftAngle": 135, "rightAngle": 60},
        ],
        "stockLength": 3310,
        "kerf": 0,
        "angleCuts": {"enabled": True, "width": 100, "axialSymmetry": "none"},
    },
    timeout=30,
)
r.raise_for_status()

for combo in r.json()["plan"]["combinations"]:
    print(combo["count"], "x", combo["usedComb"]["cutPositions"])

バンドル一括切断 (メソッド "bundle")

母材は物理的なバンドルで入荷することが多い。バンドル全体を同一パターンで切断すれば、段取りはバンドル全体で1回で済みます。method: "bundle" は、需要が許す限り多くのフルバンドルを充填し (各母材は固有の bundleSize を持つ)、残りは fewest_setups を使って単体として処理します。レスポンスの各レイアウトは bundleBars (フルバンドルから切り出された母材の本数) を報告し、統計情報には fullBundleBarssingleBarsbundleEfficiency が追加されます。stockLength の代わりに stocks[] が必要です。角度切りと材料グループはまだこれと組み合わせることはできません。

POST /v1/optimise
{
  "parts": [
    { "length": 3000, "quantity": 14 },
    { "length": 1200, "quantity": 9 }
  ],
  "stocks": [
    { "length": 6000, "quantity": null, "bundleSize": 3 },
    { "length": 4000, "quantity": 10, "bundleSize": 2 }
  ],
  "kerf": 4,
  "method": "bundle"
}

大規模で時間のかかるジョブの処理

大規模なリストは数秒から数分かかることがあります。探索はいつでも中断可能なので、UIが待機できる時間にtimeLimitを設定し、optimalを表示して、解が証明済みか、単に現時点での最良解かを利用者に伝えてください。

json
{ "parts": [ /* 900 parts */ ], "stockLength": 6500,
  "kerf": 4, "timeLimit": 60 }