تخطَّ إلى المحتوى
CADCAMFUN
الوثائق

الوثائق

رسم حلالا

2رسومات تخطيطية مقيدة تم حلها بواسطة Levenberg–Marquardt، مع درجات الحرية والنقاط الحرة والتعارضات المسماة.

مترجم تلقائيًا من الإنجليزية. عرض الأصل بالإنجليزية

ماذا يفعل الحلال

يقوم برنامج حل الرسومات بتحويل مجموعة من النقاط والخطوط والدوائر والأقواس بالإضافة إلى القيود الهندسية والأبعاد إلى إحداثيات ملموسة. يعيش في packages/core/src/cad/sketch.ts (522 سطر) ويتم التصدير من @cadcamfun/core كـ solveSketch, sketchProfiles و polygonArea. التاريخ البارامتري يحل تعبيراته إلى أرقام أولا، ثم يستدعي الحل؛ يتم تغذية الملامح التي تم حلها بالبثق والتدوير والجيوب.

مدخلالإخراج
الكيانات: النقاط والخطوط والدوائر والأقواسنفس الكيانات مع الإحداثيات وأنصاف الأقطار التي تم حلها
القيود: 24 أنواع، مسماة اختياريًاالحالة، درجات الحرية، النقاط الحرة، المعادلات الزائدة، الصراعات
options: maxIterations (200), tolerance (1e-9)التكرارات المستخدمة وأكبر المتبقية
رسم تم حله مقذوف اسحب إلى المدار · قم بالتمرير للتكبير · اسحب بزر الماوس الأيمن للتحريك
The fully constrained 40 × 25 rectangle with a Ø10 hole at (20, 12.5), exactly as sketchProfiles returned it (the circle is a 50-point loop at the default 0.01 mm tolerance), extruded 6 mm.

نموذج البيانات

النقاط هي المجهولة. يشير كل خط ودائرة وقوس إلى نقاط حسب المعرف، لذا فإن الخطين اللذين يشتركان في النهاية يشتركان في النقطة ويتحركان معًا. تضيف الدائرة شيئًا آخر غير معروف، وهو نصف قطرها. القوس هو مركز ونقطتين على الدائرة، عكس اتجاه عقارب الساعة من start إلى end; نصف قطرها هو |البداية − المركز| ويضيف الحل حفظ المعادلة الخاصة به end على نفس الدائرة.

أنواع الكيانات والرسم (sketch.ts)
export interface SketchPoint  { id: string; kind: "point";  x: number; y: number }
export interface SketchLine   { id: string; kind: "line";   p1: PointId; p2: PointId }
export interface SketchCircle { id: string; kind: "circle"; center: PointId; radius: number }
/** Counter-clockwise from `start` to `end` about `center`. */
export interface SketchArc    { id: string; kind: "arc";    center: PointId; start: PointId; end: PointId }

export interface Sketch {
  readonly entities: ReadonlyArray<SketchEntity>
  readonly constraints: ReadonlyArray<Constraint>
}

تم وضع المتجه المجهول مثل كل نقطة x, y بترتيب الكيان، ثم كل دائرة r. مستطيل من أربع نقاط له 8 مجهول؛ أضف دائرة بمركزها الخاص ولها 11.

كتالوج القيود

يساهم كل قيد بمعادلات متبقية تكون صفرًا عند الاحتفاظ به. يمكن أن يحمل القيد id; بدون واحد يتم تسميته type#index (على سبيل المثال vertical#2) في تقارير الصراع.

يكتبالحقولمعنىالمعادلات
fixedنقطة، س؟، ذ؟دبابيس نقطة (إما التنسيق اختياري)1–2
coincidenta, bنقطتان واحدة2
horizontal / verticalخطالخط مستوي أو راسيا1
horizontalPoints / verticalPointsa, bنقطتين حصة ص / س1
distanceأ، ب، القيمةالمسافة من نقطة إلى نقطة1
distanceX / distanceYأ، ب، القيمةوقعت إزاحة على طول محور واحد1
lengthالخط، القيمةطول الخط1
parallel / perpendiculara, bبين سطرين1
equalLengtha, bسطرين1
equalRadiusa, bدائرتين أو أقواس1
radius / diameterدائرة، قيمةحجم الدائرة أو القوس1
angleأ، ب، القيمةمن الخط أ إلى الخط ب، عكس اتجاه عقارب الساعة، راديان1
pointOnLine / pointOnCircleنقطة، خط | دائرةحدوث1
midpointنقطة، خطنقطة في منتصف السطر2
symmetricأ، ب، سطرزوج المرآة حول الخط2
tangentLineCircleخط، دائرةالخط يلامس الدائرة1
tangentCirclesأ، ب، داخلي؟خارجي r1 + r2 أو داخلي |r1 − r2|1
concentrica, bتتزامن المراكز2

الحل: ليفنبرج-ماركوارت

يقوم الحل بتقليل مجموع القيم التربيعية المتبقية باستخدام Levenberg-Marquardt والفرق المركزي Jacobian. كل خطوة تحل المعادلات العادية المخمدة عن طريق تحليل تشوليسكي؛ يتم قبول الخطوة التي تخفض المتبقي ويسقط التخميد، والخطوة التي لا يتم رفضها وينمو التخميد. نظرًا لأن كل خطوة هي أصغر تغيير يقلل من البقايا، فإن النقطة المسحوبة تسحب بقية الرسم بنفس الطريقة التي تظهر بها على لوحة الرسم.

  1. أنشئ الدالة المتبقية لكل قيد، وسجل القيد الذي يمتلك كل معادلة.
  2. Start with λ = 1e-3. Solve (JᵀJ + λ·max(1, diag)) Δx = −Jᵀr; if Cholesky fails, multiply λ by 10 and retry.
  3. Accept the step if the residual norm drops (λ = max(λ/5, 1e-12)); otherwise λ ×= 10.
  4. توقف عندما يكون المتبقي أدناه tolerance (1e-9) أو بعد ذلك maxIterations (200).
  5. Analyse the Jacobian at the solution: rank by Gaussian elimination with full pivoting (tolerance 1e-7), null-space basis, free unknowns (component above 1e-6).
ثابتقيمةأين
الحد الأقصى للتكرارات الافتراضية200SolveOptions
التسامح الافتراضي1e-9SolveOptions
التخميد الأولي π1e-3solveSketch
أرضية التخميد1e-12solveSketch
حلها إذا المتبقية ≥1e-6حالة
التسامح رتبة1e-7nullSpace
عتبة حرة غير معروفة1e-6نقاط مجانية
عتبة التعارض (لكل معادلة)1e-6الصراعات

الحالة والتشخيص

بعد الحل درجات الحرية = المجهولة - الرتبة والمعادلات الزائدة = المعادلات - الرتبة. تتبع الحالة هذين الرقمين ومن ما إذا كان المتبقي قد وصل إلى 1e-6.

حالةحالةما يجب القيام به
fully-constrainedتم الحل، dof 0، بدون تكرارلا شئ
under-constrainedتم الحل، dof > 0إضافة أبعاد للمعرفات في free
over-constrainedتم الحل، زائدة عن الحاجة > 0إزالة قيد مكرر (غير ضار ولكنه صاخب)
conflictingلم يتم حلها، زائدة عن الحاجة > 0إصلاح القيد في conflicts[0]
failedلم تحل، لا التكرارابدأ بالقرب من الشكل المقصود أو ارفع الحد الأقصى للتكرارات

These results come from running the solver on a rectangle drawn slightly askew: a(0,0) b(38,2) c(41,27) d(−1,24), with a fixed at the origin and the four lines horizontal/vertical.

نتائج حقيقية، واحدة لكل قيد إضافي
// + length(l1) = 40
{"status":"under-constrained","dof":1,"free":["c","d"],"iterations":3,"redundant":0}
// + length(l2) = 25
{"status":"fully-constrained","dof":0,"iterations":3,"residual":7.95e-12,
 "points":[["a",0,0],["b",40,0],["c",40,25],["d",0,25]]}
// + length(l3) = 40   (implied by the others)
{"status":"over-constrained","dof":0,"redundant":1}
// + length(l3) = 30   named "bad"
{"status":"conflicting","redundant":1,
 "conflicts":["bad","vertical#2","length#5","vertical#4"],
 "message":"The constraints cannot all hold; the worst miss is bad"}

أقل تغيير، وليس أقلها مفاجأة

With height still free, moving c to (55, 31) and solving gave c = (40, 27.5) and d = (0, 27.5): the free height settled at the mean of the dragged c.y (31) and the old d.y (24), because Levenberg–Marquardt makes the smallest change that satisfies the constraints.

API

التوقيعات
export const solveSketch: (sketch: Sketch, options?: SolveOptions) => SolveResult
export const sketchProfiles: (sketch: Sketch, tolerance?: number /* 0.01 */) =>
  { readonly loops: Vec2[][]; readonly open: Vec2[][] }
export const polygonArea: (ring: ReadonlyArray<Vec2>) => number   // positive counter-clockwise
export class SketchError extends Error {}

export interface SolveResult {
  sketch: Sketch; status: SolveStatus; dof: number; iterations: number
  residual: number          // largest absolute residual left
  free: string[]            // points and circles that can still move
  conflicts: string[]       // worst first, only when not solved
  redundant: number
  message?: string
}
لوحة مع ثقب، من النهاية إلى النهاية
import { solveSketch, sketchProfiles, polygonArea } from "@cadcamfun/core"

const P = (id: string, x: number, y: number) => ({ id, kind: "point" as const, x, y })
const L = (id: string, p1: string, p2: string) => ({ id, kind: "line" as const, p1, p2 })

const result = solveSketch({
  entities: [P("a", 0, 0), P("b", 38, 2), P("c", 41, 27), P("d", -1, 24),
    L("l1", "a", "b"), L("l2", "b", "c"), L("l3", "c", "d"), L("l4", "d", "a"),
    P("o", 20, 12), { id: "h", kind: "circle", center: "o", radius: 4 }],
  constraints: [
    { type: "fixed", point: "a", x: 0, y: 0 },
    { type: "horizontal", line: "l1" }, { type: "vertical", line: "l2" },
    { type: "horizontal", line: "l3" }, { type: "vertical", line: "l4" },
    { type: "length", line: "l1", value: 40 }, { type: "length", line: "l2", value: 25 },
    { type: "distanceX", a: "a", b: "o", value: 20 }, { type: "distanceY", a: "a", b: "o", value: 12.5 },
    { type: "diameter", circle: "h", value: 10 },
  ],
})
result.status                       // "fully-constrained", dof 0
const { loops } = sketchProfiles(result.sketch)
loops.map((l) => [l.length, polygonArea(l)])
// [[50, 78.333], [4, 1000]]   circle: 50 points; rectangle: 4 points, area 1000

من الرسم إلى الملفات الشخصية

sketchProfiles تنتهي خطوط السلاسل والأقواس من خلال معرفات النقاط المشتركة الخاصة بها في حلقات مغلقة، وتعيد كل دائرة كحلقة خاصة بها. يصبح القوس نقاطًا متباعدة بحيث يبقى الوتر بداخله tolerance of the true arc (n = ⌈sweep / (2·acos(1 − tol/r))⌉, at least 2); a full circle gets at least 8 points. A chain that does not close is returned in open بدلا من أن يتم إسقاطها.
فتحة من قوسين وخطين اسحب إلى المدار · قم بالتمرير للتكبير · اسحب بزر الماوس الأيمن للتحريك
فتحة 30 مم من نصف القطر 8: قوسان وخطان يتقاسمان نقاط النهاية، تم حلها وربطها بواسطة ملفات رسم تخطيطية في حلقة واحدة بنقطة 66 (المساحة 680.739 مم² مقابل 681.062 مم² بالضبط؛ تم إدراج المضلع، لذا فهو دائمًا أصغر قليلاً).

تم حل الفتحة أعلاه كـ over-constrained مع dof 0 و1 معادلة زائدة عن الحاجة: صنع top يتم تضمين الأفقي بمجرد أن يكون c1 –a1 وc2 –b1 عموديًا وc1، c2 يتشاركان في y. الحل لا يزال ناجحا. تشير الحالة إلى التكرار فقط.

استكشاف الأخطاء وإصلاحها

أعراضسببيصلح
SketchError: Duplicate entity idكيانان يشتركان في معرفالمعرفات فريدة عبر النقاط والخطوط والدوائر والأقواس
SketchError: Unknown unknownيسمي القيد نقطة أو دائرة غير موجودةتحقق من المعرفات في القيد
conflicting مع قائمة الصراعات الطويلةبعد واحد خاطئ يسحب عدة معادلات من الصفرإصلاح الإدخال الأول؛ والباقي عادة ما يكون ضمانات
failedالبداية بعيدة عن أي حلالتقرب من الشكل المقصود؛ رفع الحد الأقصى للتكرارات
الملف الشخصي مفقود من loopsالسلسلة لا تغلق: إنها موجودة openجعل نقاط النهاية معرفات مشتركة، أو إضافة قيد متزامن
تحتوي الدائرة على عدد قليل جدًا من النقاطالتسامح خشن جدًا بالنسبة لنصف قطر صغيرتمرير تسامح أصغر إلى SketchProfiles