API-Dokumentation
Der Optimierer als HTTP-Dienst: Senden Sie Zuschnitte und Rohmaterial und Sie erhalten einen geprüften Schnittplan oder ein druckfertiges PDF. Stabil, versioniert und abwärtskompatibel: Felder werden nur hinzugefügt, niemals entfernt.
Einführung
Basis-URL https://api.linearcutting.com. Alles ist JSON, außer dem PDF-Endpunkt. Anfragen sind zustandslos: Wir speichern Ihre Zuschnittlisten nicht.
Sie brauchen keinen API-Schlüssel, um dies zu testen. Die folgende Zeile kann sofort unverändert ausgeführt werden. Fügen Sie sie in ein Terminal ein.
curl -X POST https://api.linearcutting.com/v1/optimise \
-H "Content-Type: application/json" \
-d '{"parts": "2400x5, 1800x3", "stock": 6000}' Das ist eine vollständige Zuschnittliste: fünf Teile zu 2400, drei zu 1800, aus 6000-mm-Stangen geschnitten. Sie erhalten die Layouts, die Anzahl der benötigten Stangen, die Abfallmenge und die Information, ob der Plan nachweislich optimal ist.
Anfragen ohne Schlüssel sind kostenlos zum Testen: 30 Anfragen pro Stunde, 250 pro Monat und IP-Adresse. Bei Überschreitung meldet Fehler 429 die Rücksetzzeit. Fehlgeschlagene Anfragen zählen nicht. Für den Praxiseinsatz brauchen Sie einen Schlüssel (ab 5 $/Monat). Er hebt alle Limits auf, erhöht die maximale Auftragsgröße und gibt Ihnen eigene Rechenleistung, damit Sie nicht im allgemeinen Betrieb ausgebremst werden.
Offizielle Clients
Keine Abhängigkeiten, MIT-lizenziert, und sie benötigen auch keinen Schlüssel. Wenn Sie Python oder JavaScript verwenden, schreiben Sie nicht von Hand einen fetch:
import linearcutting as lc
plan = lc.optimise(parts="2400x5, 1800x3", stock=6000)
plan.bars_used # 4
plan.optimal # True, proved, not guessed import { optimise } from "linearcutting";
const plan = await optimise({ parts: "2400x5, 1800x3", stock: 6000 });
plan.barsUsed; // 4
plan.optimal; // true Python auf PyPI · JavaScript auf npm · Python-Quellcode · JavaScript-Quellcode
Zwei Garantien, auf die Sie sich verlassen können. verifiziert ist bei Erfolg immer „wahr“: Jeder Plan wird anhand Ihrer Eingaben erneut geprüft, bevor er zurückgegeben wird. So kann Sie kein Plan erreichen, der Ihre Zuschnittliste nicht erfüllt. optimal ist ein Beweis, keine Schätzung. Es ist nur dann „wahr“, wenn die Suche ergeben hat, dass kein besserer Plan existiert, sei es durch das Ausschöpfen aller Möglichkeiten oder durch ein Zertifikat. Wenn dies im Zeitrahmen nicht bewiesen werden kann, geben wir false zurück, anstatt zu hoffen.
optimal und stockBarsLowerBound sind zwei verschiedene Dinge, und sie weichen absichtlich voneinander ab. Die untere Schranke ist eine Vereinfachung, grob gesagt „Gesamtlänge ÷ Stangenlänge“, und sie ist oft nicht erreichbar. Fünf Teile à 2400 und drei à 1800 sind 17.400 mm, was 2,9 Stangen à 6000 entspricht, also sagt die Schranke 3. Tatsächlich können Sie diese Teile nicht aus 3 Stangen schneiden; 4 ist das wahre Minimum, und der Solver beweist es. Daher ist stockBarsUsed: 4 mit stockBarsLowerBound: 3 und optimal: true kein Widerspruch. Es bedeutet, dass die Schranke ungenau war, nicht der Plan. Verwenden Sie optimal, um zu entscheiden, ob die Suche fortgesetzt werden soll; verwenden Sie die Schranke nur zur Plausibilitätsprüfung.
Kurzschreibweise
Die Langform ist explizit und etwas umständlich. Für den Normalfall gibt es die Kurzform: eine Zahl ist eine Länge, und x bedeutet die Anzahl:
{"parts": "2400x5, 1800x3, 600", "stock": 6000} Jeder dieser Ausdrücke bedeutet dasselbe, verwenden Sie also den, der am besten zu Ihrem Code passt:
{"parts": "2400x5"}
{"parts": ["2400x5"]}
{"parts": [[2400, 5]]}
{"parts": [{"length": 2400, "quantity": 5}]} Ein drittes Element ist eine Bezeichnung für ein Teil und ein Preis für Rohmaterial: [2400, 5, "rail"], [6000, 20, 45.50]. Und stock ist die Kurzform für die alte Trennung in stockLength / stocks. Eine einzelne Zahl bedeutet „diese Länge, unbegrenzte Anzahl“.
Die Kurzschreibweise wird zuerst erweitert. Sie ist also eine Eingabeerleichterung und kein anderer Modus: eine kurze Anfrage und die lange Anfrage, zu der sie erweitert wird, geben byte-identische Pläne zurück. Beide Schreibweisen sind frei kombinierbar. Jede bestehende Anfrage funktioniert weiterhin genau wie bisher.
Zuschnittliste in einer URL
Kleine Aufträge passen in einen Query-String, daher funktioniert auch GET. Das ist praktisch für Links zum Teilen, für Angebote oder für Fehlermeldungen:
curl "https://api.linearcutting.com/v1/optimise?parts=2400x5,1800x3&stock=6000" Gleiche Authentifizierung, gleiche Limits, gleicher Plan wie bei POST. Kann auch im Browser geöffnet werden.
Authentifizierung
Der öffentliche Tarif benötigt keinen Schlüssel. Kostenpflichtige Tarife senden ihren Schlüssel in einem Header; die Schlüssel enthalten auch Ihre erlaubten Browser-Origins, sodass Anrufe von Ihrer eigenen Website ohne Proxy funktionieren.
X-API-Key: lk_live_9f2c... Ein ungültiger oder abgelaufener Schlüssel gibt 401 zurück. Schlüssel werden pro Arbeitsbereich ausgestellt: siehe Tarife.
POST /v1/optimise
Löst eine Zuschnittliste. Gibt den Plan, Statistiken und beweisbare Schranken zurück.
Anfragekörper
| Field | Typ | Standard | Beschreibung |
|---|---|---|---|
parts erforderlich | Array | - | Die benötigten Teile. Jeweils: length (> 0), quantity (Ganzzahl ≥ 1), optional label, material, leftAngle, rightAngle. |
stockLength | Zahl | - | Eine einzelne Stangenlänge in unbegrenzter Stückzahl. Entweder diesen Parameter oder stocks verwenden, nicht beide. |
stocks | array | - | Käufliche Stangenlängen. Jeweils: length, quantity (null = unbegrenzt), price (null = Material statt Kosten optimieren), optional material, priority. |
offcuts | array | [] | Stangenlängen aus Ihrem Bestand: length, quantity, optional material, priority. Kostenloses Material, wird nie als Kauf gezählt. |
kerf | Zahl ≥ 0 | 0 | Schnittbreite des Sägeblatts. |
trim | boolean | false | Jedes Rohmaterial an beiden Enden besäumen. |
method | string | balanced | balanced, least_waste, offcuts_first, fewest_setups (Alias: fewest_setups). Preise in stocks schalten balanced auf niedrigste Kosten um. |
minRemnant | Zahl ≥ 0 | 0 | Reststücke ab dieser Länge gelten als usableRemnants und nicht als Abfall. |
angleCuts | Objekt | aus | {enabled, width, axialSymmetry}. Siehe Winkelschnitte. |
unit | string | "mm" | Wird zurückgegeben und auf PDFs gedruckt. Nimmt keine Umrechnungen vor. |
unitFormat | string | decimal | fraction stellt PDF-Maße als auf 1/64 gerundete Brüche dar. |
timeLimit | Sekunden | auto | Rechenzeit, durch Tarif begrenzt. Die Suche ist "Anytime": Eine längere Rechenzeit kann das Ergebnis nur verbessern. |
Antwort
{
"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" }
} | Field | Beschreibung |
|---|---|
plan.combinations[] | Ein Eintrag pro eindeutigem Layout. usedComb.combination listet die aus dieser Stange geschnittenen Teile auf, length ist die Quelle, source ist stock oder offcut, und count gibt an, wie viele Stangen auf diese Weise zugeschnitten werden. |
usedComb.waste | total = Quelle − Teile; aufgeteilt in saw (Sägeschnittbreite + Anschnitt) und remnant (das übrig gebliebene Ende). |
plan.purchases[] | Die Einkaufsliste: length, count, plus price/cost, wenn Sie Preise angegeben haben. |
plan.usableRemnants | Reststücke ≥ minRemnant, die größten zuerst: Ihr Reststücklager für morgen. |
plan.unusedOffcuts | Reststücke, die der Plan nicht benötigt hat. |
plan.stockBarsUsed | Gesamtzahl der zu kaufenden Stangen. |
plan.optimal | Nachweis. Nur „wahr“, wenn der Plan eine nachweisbare Untergrenze erreicht hat (oder die Suche vollständig abgeschlossen wurde). Kann dem Benutzer als „bestmöglich“ angezeigt werden. |
plan.verified | Immer „wahr“ bei Erfolg: Bedarf gedeckt, jedes Layout passt physisch, Reststückvorrat berücksichtigt. |
plan.stockBarsLowerBound, costLowerBound | Nachweisbare Minima. Wenn optimal „falsch“ ist, zeigt die Lücke, um wie viel dieser Plan höchstens abweichen könnte. |
stats | Auftragssummen: Teile, Längen, yieldPercent (Materialausnutzung), cutCount, layoutCount, totalCost, trueWaste, und byMaterial bei Verwendung von Materialgruppen. |
POST /v1/optimise/pdf
Gleicher Anfrage-Body, plus ein optionales jobName. Gibt application/pdf zurück: Seite 1 ist eine Zusammenfassung für den Projektmanager (Bestellung, Kosten, Optimalitätszertifikat); die folgenden Seiten sind Arbeitsblätter für den Sägenbediener mit laufenden Schnittpositionen, Teile-Etiketten und einem Kontrollkästchen pro Stange. Bei Aufrufern mit Schlüssel wird deren Namensnennung oder Branding gerendert.
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
{ "status": "ok", "version": "1.3.0", "solver": "Linear Cutlist Optimizer v2" } Materialgruppen
Markieren Sie parts, stocks und offcuts mit material, und jedes Material wird als eigener Job innerhalb einer Anfrage gelöst: Zuschnitte landen immer nur auf Rohmaterial desselben Materials. Zuschnittpläne und Einkäufe kommen markiert zurück, und stats.byMaterial schlüsselt die Zahlen pro Gruppe auf.
{
"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 für Rohmaterial oder Reststück ist eine bevorzugte Verwendung: Unter gleichwertigen Plänen werden priorisierte Posten zuerst verwendet. Die Planqualität wird dadurch niemals beeinträchtigt.
Winkel- / Gehrungsschnitte
Geben Sie Teilen leftAngle und rightAngle und aktivieren Sie angleCuts. Winkel sind die unteren Winkel des liegenden Teils; geben Sie einen oberen Winkel als negative Zahl ein (120 und -60 sind derselbe Schnitt). Gültiger Bereich nach dieser Umwandlung: 10 bis 170 Grad.
| angleCuts field | Beschreibung |
|---|---|
enabled | Hauptschalter. Winkel bei Teilen werden nur akzeptiert, wenn auf true gesetzt. |
width | Materialbreite, gleiche Einheit wie Längen. Ein Winkelschnitt ragt seitlich um width / tan(angle) hinaus. |
axialSymmetry | none, X, Y, Z oder XYZ: gibt an, welche Umdrehungen das Material erlaubt, was wiederum bestimmt, wie Gehrungen verschachtelt werden können. Vierkantrohr ist typischerweise XYZ; einseitiges Material ist none. |
Wo zwei benachbarte Gehrungen parallel sind, erzeugt ein Sägeschnitt beide Kanten. Layouts im Winkelmodus fügen ein geordnetes parts-Array (mit der verwendeten Ausrichtung) und cutPositions hinzu: jeder Schnitt gemessen vom Nullpunkt der Stangenlänge, als [oben, unten]-Paar bei einem Winkelschnitt, oder als einzelne Zahl bei einem geraden Schnitt.
"cutPositions": [[1200, 1300], [2442.265, 2500], 3300] Fehler
Fehlermeldungen haben den Aufbau { "error": "...", "detail": "..." }. Das detail ist für einen Menschen geschrieben: es benennt das fehlerhafte Teil oder Material.
| Status | Fehler | Wann |
|---|---|---|
| 400 | validation | Falsche Längen oder Mengen, unbekannte Methode, ein Teil, das auf kein Rohmaterial passt, Bedarf übersteigt endlichen Vorrat, Winkelregeln verletzt, stocks und stockLength beide gesendet. |
| 401 | badKey | Fehlender, unbekannter oder deaktivierter API-Schlüssel. |
| 413 | partsLimit | Mehr Teile, als Ihr Tarif erlaubt. |
| 429 | rateLimited | Raten- oder monatliches Limit erreicht. Retry-After beachten. |
| 503 | busy | Solver ausgelastet. Bald erneut versuchen. |
Ratenlimits
Limits drosseln; sie erzeugen niemals eine Nachzahlung. Anfragen, deren Validierung fehlschlägt, werden nicht auf Ihr monatliches Kontingent angerechnet. Alle Zahlen stehen auf der Seite mit den Plänen.
| Guard | Kostenlos | Bezahl-Tarife |
|---|---|---|
| Anfragerate | 10 Anfragen / 5 Min. pro IP | 20-240 / Min. je nach Tarif |
| Teile gesamt | 300 | 500 - 5,000 |
| Einzelne Teileeinträge | 60 | bis zu 400 |
| Rechenzeit | 20 s | 60 - 300 s |
Die Obergrenze gilt für einzelne Teileeinträge wie auch für die Gesamtzahl der Teile, da die Rechenkosten von der Längenvielfalt abhängen: 300 identische Zuschnitte sind in Millisekunden optimiert, 300 verschiedene nicht.
Beispiele
Günstigste Mischung aus mehreren Stangenlängen (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 Rahmenteile mit Gehrungsschnitt (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"]) Umgang mit großen, langsamen Aufträgen
Große Listen können Sekunden bis Minuten dauern. Die Suche ist jederzeit unterbrechbar, setzen Sie also timeLimit auf die Wartezeit Ihrer Benutzeroberfläche und zeigen Sie optimal an, um dem Benutzer mitzuteilen, ob die Lösung erwiesen oder nur die bisher beste ist.
{ "parts": [ /* 900 parts */ ], "stockLength": 6500,
"kerf": 4, "timeLimit": 60 }