@lydt/geogebra-studio 0.0.0-stage → 0.4.0-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. package/.agents/plugins/marketplace.json +21 -0
  2. package/.codex-plugin/plugin.json +21 -0
  3. package/.mcp.json +18 -0
  4. package/LICENSE +339 -0
  5. package/LICENSE-MIT +21 -0
  6. package/README.md +108 -2
  7. package/README.zh-CN.md +89 -0
  8. package/THIRD_PARTY_NOTICES.md +35 -0
  9. package/dist/cli.d.ts +27 -0
  10. package/dist/cli.d.ts.map +1 -0
  11. package/dist/cli.js +234 -0
  12. package/dist/cli.js.map +1 -0
  13. package/dist/export/files.d.ts +4 -0
  14. package/dist/export/files.d.ts.map +1 -0
  15. package/dist/export/files.js +44 -0
  16. package/dist/export/files.js.map +1 -0
  17. package/dist/export/gikz.d.ts +11 -0
  18. package/dist/export/gikz.d.ts.map +1 -0
  19. package/dist/export/gikz.js +28 -0
  20. package/dist/export/gikz.js.map +1 -0
  21. package/dist/export/html.d.ts +14 -0
  22. package/dist/export/html.d.ts.map +1 -0
  23. package/dist/export/html.js +97 -0
  24. package/dist/export/html.js.map +1 -0
  25. package/dist/export/semantic.d.ts +43 -0
  26. package/dist/export/semantic.d.ts.map +1 -0
  27. package/dist/export/semantic.js +212 -0
  28. package/dist/export/semantic.js.map +1 -0
  29. package/dist/export/viewer-themes.d.ts +76 -0
  30. package/dist/export/viewer-themes.d.ts.map +1 -0
  31. package/dist/export/viewer-themes.js +169 -0
  32. package/dist/export/viewer-themes.js.map +1 -0
  33. package/dist/export/workspace.d.ts +4 -0
  34. package/dist/export/workspace.d.ts.map +1 -0
  35. package/dist/export/workspace.js +25 -0
  36. package/dist/export/workspace.js.map +1 -0
  37. package/dist/gikz-browser.js +770 -0
  38. package/dist/index.d.ts +5 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +84 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/server.d.ts +35 -0
  43. package/dist/server.d.ts.map +1 -0
  44. package/dist/server.js +187 -0
  45. package/dist/server.js.map +1 -0
  46. package/dist/studio/artifact.d.ts +37 -0
  47. package/dist/studio/artifact.d.ts.map +1 -0
  48. package/dist/studio/artifact.js +61 -0
  49. package/dist/studio/artifact.js.map +1 -0
  50. package/dist/studio/browser.d.ts +7 -0
  51. package/dist/studio/browser.d.ts.map +1 -0
  52. package/dist/studio/browser.js +67 -0
  53. package/dist/studio/browser.js.map +1 -0
  54. package/dist/studio/install.d.ts +4 -0
  55. package/dist/studio/install.d.ts.map +1 -0
  56. package/dist/studio/install.js +60 -0
  57. package/dist/studio/install.js.map +1 -0
  58. package/dist/tools/apps-api-tools.d.ts +4 -0
  59. package/dist/tools/apps-api-tools.d.ts.map +1 -0
  60. package/dist/tools/apps-api-tools.js +96 -0
  61. package/dist/tools/apps-api-tools.js.map +1 -0
  62. package/dist/tools/educational-templates.d.ts +33 -0
  63. package/dist/tools/educational-templates.d.ts.map +1 -0
  64. package/dist/tools/educational-templates.js +261 -0
  65. package/dist/tools/educational-templates.js.map +1 -0
  66. package/dist/tools/export-tools.d.ts +3 -0
  67. package/dist/tools/export-tools.d.ts.map +1 -0
  68. package/dist/tools/export-tools.js +118 -0
  69. package/dist/tools/export-tools.js.map +1 -0
  70. package/dist/tools/geogebra-tools.d.ts +15 -0
  71. package/dist/tools/geogebra-tools.d.ts.map +1 -0
  72. package/dist/tools/geogebra-tools.js +3442 -0
  73. package/dist/tools/geogebra-tools.js.map +1 -0
  74. package/dist/tools/index.d.ts +43 -0
  75. package/dist/tools/index.d.ts.map +1 -0
  76. package/dist/tools/index.js +183 -0
  77. package/dist/tools/index.js.map +1 -0
  78. package/dist/tools/performance-tools.d.ts +7 -0
  79. package/dist/tools/performance-tools.d.ts.map +1 -0
  80. package/dist/tools/performance-tools.js +312 -0
  81. package/dist/tools/performance-tools.js.map +1 -0
  82. package/dist/tools/templates/algebra-templates.d.ts +7 -0
  83. package/dist/tools/templates/algebra-templates.d.ts.map +1 -0
  84. package/dist/tools/templates/algebra-templates.js +568 -0
  85. package/dist/tools/templates/algebra-templates.js.map +1 -0
  86. package/dist/tools/templates/geometry-templates.d.ts +7 -0
  87. package/dist/tools/templates/geometry-templates.d.ts.map +1 -0
  88. package/dist/tools/templates/geometry-templates.js +492 -0
  89. package/dist/tools/templates/geometry-templates.js.map +1 -0
  90. package/dist/types/geogebra.d.ts +103 -0
  91. package/dist/types/geogebra.d.ts.map +1 -0
  92. package/dist/types/geogebra.js +34 -0
  93. package/dist/types/geogebra.js.map +1 -0
  94. package/dist/types/mcp.d.ts +125 -0
  95. package/dist/types/mcp.d.ts.map +1 -0
  96. package/dist/types/mcp.js +19 -0
  97. package/dist/types/mcp.js.map +1 -0
  98. package/dist/utils/app-info.d.ts +12 -0
  99. package/dist/utils/app-info.d.ts.map +1 -0
  100. package/dist/utils/app-info.js +30 -0
  101. package/dist/utils/app-info.js.map +1 -0
  102. package/dist/utils/errors.d.ts +37 -0
  103. package/dist/utils/errors.d.ts.map +1 -0
  104. package/dist/utils/errors.js +72 -0
  105. package/dist/utils/errors.js.map +1 -0
  106. package/dist/utils/gemini-compatibility.d.ts +39 -0
  107. package/dist/utils/gemini-compatibility.d.ts.map +1 -0
  108. package/dist/utils/gemini-compatibility.js +154 -0
  109. package/dist/utils/gemini-compatibility.js.map +1 -0
  110. package/dist/utils/geogebra-instance.d.ts +252 -0
  111. package/dist/utils/geogebra-instance.d.ts.map +1 -0
  112. package/dist/utils/geogebra-instance.js +1560 -0
  113. package/dist/utils/geogebra-instance.js.map +1 -0
  114. package/dist/utils/geogebra-mock.d.ts +172 -0
  115. package/dist/utils/geogebra-mock.d.ts.map +1 -0
  116. package/dist/utils/geogebra-mock.js +732 -0
  117. package/dist/utils/geogebra-mock.js.map +1 -0
  118. package/dist/utils/logger.d.ts +4 -0
  119. package/dist/utils/logger.d.ts.map +1 -0
  120. package/dist/utils/logger.js +46 -0
  121. package/dist/utils/logger.js.map +1 -0
  122. package/dist/utils/performance/index.d.ts +76 -0
  123. package/dist/utils/performance/index.d.ts.map +1 -0
  124. package/dist/utils/performance/index.js +163 -0
  125. package/dist/utils/performance/index.js.map +1 -0
  126. package/dist/utils/performance/instance-pool.d.ts +78 -0
  127. package/dist/utils/performance/instance-pool.d.ts.map +1 -0
  128. package/dist/utils/performance/instance-pool.js +268 -0
  129. package/dist/utils/performance/instance-pool.js.map +1 -0
  130. package/dist/utils/validation.d.ts +92 -0
  131. package/dist/utils/validation.d.ts.map +1 -0
  132. package/dist/utils/validation.js +557 -0
  133. package/dist/utils/validation.js.map +1 -0
  134. package/dist/widget.html +110 -0
  135. package/docs/APPS-API-BRIDGE.md +28 -0
  136. package/docs/MODERNIZATION.md +15 -0
  137. package/docs/TANGENT-REGRESSION.md +34 -0
  138. package/docs/VALIDATION.md +26 -0
  139. package/docs/VISUAL-STANDARD.md +26 -0
  140. package/docs/images/native-construction.png +0 -0
  141. package/examples/tangent-construction.json +26 -0
  142. package/gikz/LICENSE +339 -0
  143. package/gikz/PROVENANCE.md +8 -0
  144. package/gikz/browser.cjs +2 -0
  145. package/gikz/cli.cjs +195 -0
  146. package/gikz/core.cjs +806 -0
  147. package/mcp.json +20 -0
  148. package/package.json +107 -4
  149. package/plugin.json +35 -0
  150. package/runtime/package.json +4 -0
  151. package/scripts/build-plugin.cjs +15 -0
  152. package/scripts/build-widget.cjs +7 -0
  153. package/skills/geogebra-construct/SKILL.md +40 -0
  154. package/skills/geogebra-setup/SKILL.md +37 -0
  155. package/skills/geometry-export/SKILL.md +31 -0
  156. package/src/cli.ts +212 -0
  157. package/src/export/files.ts +26 -0
  158. package/src/export/gikz.ts +22 -0
  159. package/src/export/html.ts +108 -0
  160. package/src/export/semantic.ts +180 -0
  161. package/src/export/viewer-themes.ts +165 -0
  162. package/src/export/workspace.ts +15 -0
  163. package/src/index.ts +71 -0
  164. package/src/server.ts +168 -0
  165. package/src/studio/artifact.ts +50 -0
  166. package/src/studio/browser.ts +38 -0
  167. package/src/studio/install.ts +43 -0
  168. package/src/tools/apps-api-tools.ts +96 -0
  169. package/src/tools/educational-templates.ts +299 -0
  170. package/src/tools/export-tools.ts +110 -0
  171. package/src/tools/geogebra-tools.ts +3836 -0
  172. package/src/tools/index.ts +192 -0
  173. package/src/tools/performance-tools.ts +322 -0
  174. package/src/tools/templates/algebra-templates.ts +619 -0
  175. package/src/tools/templates/geometry-templates.ts +550 -0
  176. package/src/types/geogebra.ts +140 -0
  177. package/src/types/global.d.ts +31 -0
  178. package/src/types/mcp.ts +141 -0
  179. package/src/utils/app-info.ts +35 -0
  180. package/src/utils/errors.ts +97 -0
  181. package/src/utils/gemini-compatibility.ts +193 -0
  182. package/src/utils/geogebra-instance.ts +1712 -0
  183. package/src/utils/geogebra-mock.ts +867 -0
  184. package/src/utils/logger.ts +60 -0
  185. package/src/utils/performance/index.ts +211 -0
  186. package/src/utils/performance/instance-pool.ts +323 -0
  187. package/src/utils/validation.ts +647 -0
  188. package/tsconfig.json +35 -0
  189. package/widget/main.ts +12 -0
@@ -0,0 +1,770 @@
1
+ "use strict";
2
+ (() => {
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __commonJS = (cb, mod) => function __require() {
5
+ try {
6
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
7
+ } catch (e) {
8
+ throw mod = 0, e;
9
+ }
10
+ };
11
+
12
+ // gikz/core.cjs
13
+ var require_core = __commonJS({
14
+ "gikz/core.cjs"(exports, module) {
15
+ "use strict";
16
+ function roundToThreeDecimals(num) {
17
+ return Math.round(num * 1e3) / 1e3;
18
+ }
19
+ function formatCoordinate(coordStr, shouldRound) {
20
+ const match = coordStr.match(/\(([^,]+),([^)]+)\)/);
21
+ if (!match) return coordStr;
22
+ let x = parseFloat(match[1]);
23
+ let y = parseFloat(match[2]);
24
+ if (shouldRound) {
25
+ x = roundToThreeDecimals(x);
26
+ y = roundToThreeDecimals(y);
27
+ }
28
+ return `(${x},${y})`;
29
+ }
30
+ function getSmartLabelPosition(x, y, allPoints) {
31
+ const xCoords = allPoints.map((p) => p.x);
32
+ const yCoords = allPoints.map((p) => p.y);
33
+ const minX = Math.min(...xCoords);
34
+ const maxX = Math.max(...xCoords);
35
+ const minY = Math.min(...yCoords);
36
+ const maxY = Math.max(...yCoords);
37
+ const centerX = (minX + maxX) / 2;
38
+ const centerY = (minY + maxY) / 2;
39
+ let position = "above";
40
+ if (Math.abs(x - minX) < 0.1) {
41
+ position = "left";
42
+ } else if (Math.abs(x - maxX) < 0.1) {
43
+ position = "right";
44
+ } else if (Math.abs(y - minY) < 0.1) {
45
+ position = "below";
46
+ } else if (Math.abs(y - maxY) < 0.1) {
47
+ position = "above";
48
+ } else {
49
+ if (x > centerX && y > centerY) position = "above right";
50
+ else if (x > centerX && y <= centerY) position = "below right";
51
+ else if (x <= centerX && y > centerY) position = "above left";
52
+ else position = "below left";
53
+ }
54
+ return position;
55
+ }
56
+ var convertLineStyle = (style) => {
57
+ if (!style) return "";
58
+ let lineStyle = style.replace(/line width=[^,\]]+,?/g, "");
59
+ lineStyle = lineStyle.replace(/,\s*$/g, "");
60
+ lineStyle = lineStyle.replace(/\[\s*,\s*/g, "[");
61
+ if (lineStyle.includes("dash pattern=on 1pt off 1pt on 1pt off 4pt")) return "dash dot";
62
+ if (lineStyle.includes("dash pattern=on 1pt off 1pt")) return "dashed";
63
+ if (lineStyle.includes("dotted")) return "dotted";
64
+ if (lineStyle.includes("dash")) return "dashed";
65
+ return "";
66
+ };
67
+ function extractQuadraticFunctions(code, shouldRound) {
68
+ try {
69
+ const quadraticRegex = /\\draw\s*\[([^\]]+)\]\s*plot\s*\(\\x,\{\(\\x\)\^2\/2\/([^}]+)\}\)/g;
70
+ const quadraticMatches = [...code.matchAll(quadraticRegex)];
71
+ const quadraticFunctions = [];
72
+ quadraticMatches.forEach((match) => {
73
+ const options = match[1];
74
+ let denominator = match[2];
75
+ const samplesMatch = options.match(/samples=(\d+)/);
76
+ const rotateMatch = options.match(/rotate around=\{([^:]+):\(([^,]+),([^)]+)\)\}/);
77
+ const xshiftMatch = options.match(/xshift=([^,]+)cm/);
78
+ const yshiftMatch = options.match(/yshift=([^,]+)cm/);
79
+ const domainMatch = options.match(/domain=([^:)]+):([^)]+)\)?/);
80
+ if (domainMatch) {
81
+ let angle = "0", centerX = "0", centerY = "0";
82
+ if (rotateMatch) {
83
+ angle = rotateMatch[1];
84
+ centerX = rotateMatch[2];
85
+ centerY = rotateMatch[3];
86
+ }
87
+ let xshift = "0", yshift = "0";
88
+ if (xshiftMatch) xshift = xshiftMatch[1];
89
+ if (yshiftMatch) yshift = yshiftMatch[1];
90
+ let domainStart = domainMatch[1];
91
+ let domainEnd = domainMatch[2];
92
+ if (domainEnd.includes(")")) domainEnd = domainEnd.replace(")", "");
93
+ if (shouldRound) {
94
+ if (centerX !== "0") centerX = roundToThreeDecimals(parseFloat(centerX));
95
+ if (centerY !== "0") centerY = roundToThreeDecimals(parseFloat(centerY));
96
+ if (xshift !== "0") xshift = roundToThreeDecimals(parseFloat(xshift));
97
+ if (yshift !== "0") yshift = roundToThreeDecimals(parseFloat(yshift));
98
+ denominator = roundToThreeDecimals(parseFloat(denominator));
99
+ domainStart = roundToThreeDecimals(parseFloat(domainStart));
100
+ domainEnd = roundToThreeDecimals(parseFloat(domainEnd));
101
+ xshift += "cm";
102
+ yshift += "cm";
103
+ }
104
+ let newOptions = "smooth,samples=500";
105
+ if (rotateMatch) newOptions += `,rotate around={${angle}:(${centerX},${centerY})}`;
106
+ if (xshiftMatch && xshift !== "0cm" || yshiftMatch && yshift !== "0cm")
107
+ newOptions += `,xshift=${xshift},yshift=${yshift}`;
108
+ newOptions += `,domain=${domainStart}:${domainEnd}`;
109
+ quadraticFunctions.push({ original: match[0], options: newOptions, expression: `(\\x)^2/2/${denominator}` });
110
+ }
111
+ });
112
+ return { hasQuadratic: quadraticFunctions.length > 0, quadraticFunctions };
113
+ } catch (error) {
114
+ return { hasQuadratic: false, quadraticFunctions: [] };
115
+ }
116
+ }
117
+ function extractFunctionPlots(code, shouldRound) {
118
+ try {
119
+ const clipRegex = /\\clip\(([^,]+),([^)]+)\)\s*rectangle\s*\(([^,]+),([^)]+)\);/;
120
+ const clipMatch = code.match(clipRegex);
121
+ if (!clipMatch) {
122
+ return { hasFunctions: false, scopeCode: "", clipArea: "", normalFunctionCount: 0, quadraticFunctionCount: 0 };
123
+ }
124
+ const clipX1 = shouldRound ? roundToThreeDecimals(parseFloat(clipMatch[1])) : parseFloat(clipMatch[1]);
125
+ const clipY1 = shouldRound ? roundToThreeDecimals(parseFloat(clipMatch[2])) : parseFloat(clipMatch[2]);
126
+ const clipX2 = shouldRound ? roundToThreeDecimals(parseFloat(clipMatch[3])) : parseFloat(clipMatch[3]);
127
+ const clipY2 = shouldRound ? roundToThreeDecimals(parseFloat(clipMatch[4])) : parseFloat(clipMatch[4]);
128
+ const functionPlotRegex = /\\draw\[([^\]]*)\]\s*plot\s*\(\\x,\{([^}]*)\}\)/g;
129
+ const functionMatches = [...code.matchAll(functionPlotRegex)];
130
+ const functions = [];
131
+ const containsLnRegex = /ln\s*\(/i;
132
+ functionMatches.forEach((match) => {
133
+ const options = match[1];
134
+ const functionExpression = match[2];
135
+ const domainRegex = /domain=([^:]+):([^,\]]+)/;
136
+ const domainMatch = options.match(domainRegex);
137
+ if (domainMatch) {
138
+ let domainStart = domainMatch[1], domainEnd = domainMatch[2];
139
+ if (containsLnRegex.test(functionExpression)) {
140
+ if (Math.abs(parseFloat(domainStart)) < 1e-3) domainStart = "0.001";
141
+ }
142
+ if (shouldRound) {
143
+ const s = parseFloat(domainStart), e = parseFloat(domainEnd);
144
+ if (!isNaN(s)) domainStart = roundToThreeDecimals(s).toString();
145
+ if (!isNaN(e)) domainEnd = roundToThreeDecimals(e).toString();
146
+ }
147
+ let lineStyle = "";
148
+ if (options.includes("dash pattern=on 1pt off 1pt on 1pt off 4pt")) lineStyle = "dash dot";
149
+ else if (options.includes("dash pattern=on 1pt off 1pt")) lineStyle = "dashed";
150
+ else if (options.includes("dotted")) lineStyle = "dotted";
151
+ let newOptions = "smooth,samples=500";
152
+ if (lineStyle) newOptions = lineStyle + "," + newOptions;
153
+ functions.push({ original: match[0], options: newOptions, domainStart, domainEnd, expression: functionExpression, lineStyle });
154
+ }
155
+ });
156
+ const quadraticResult = extractQuadraticFunctions(code, shouldRound);
157
+ let result = " \\begin{scope}\n";
158
+ result += ` \\clip(${clipX1},${clipY1}) rectangle (${clipX2},${clipY2});
159
+ `;
160
+ functions.forEach((func) => {
161
+ result += ` \\draw[${func.options},domain=${func.domainStart}:${func.domainEnd}] plot(\\x,{${func.expression}});
162
+ `;
163
+ });
164
+ if (quadraticResult.hasQuadratic) {
165
+ quadraticResult.quadraticFunctions.forEach((quad) => {
166
+ result += ` \\draw[${quad.options}] plot(\\x,{${quad.expression}});
167
+ `;
168
+ });
169
+ }
170
+ result += " \\end{scope}\n";
171
+ return {
172
+ hasFunctions: functions.length > 0 || quadraticResult.hasQuadratic,
173
+ scopeCode: result,
174
+ clipArea: `(${clipX1},${clipY1}) rectangle (${clipX2},${clipY2})`,
175
+ normalFunctionCount: functions.length,
176
+ quadraticFunctionCount: quadraticResult.quadraticFunctions.length
177
+ };
178
+ } catch (error) {
179
+ return { hasFunctions: false, scopeCode: "", clipArea: "", normalFunctionCount: 0, quadraticFunctionCount: 0 };
180
+ }
181
+ }
182
+ function extractParametricPlots(code, shouldRound) {
183
+ try {
184
+ const parametricRegex = /\\draw\[([^\]]*)\]\s*plot\[parametric\]\s*function\{([^}]+)\};/g;
185
+ const matches = [...code.matchAll(parametricRegex)];
186
+ const plots = [];
187
+ matches.forEach((match) => {
188
+ const options = match[1];
189
+ const functionStr = match[2];
190
+ const commaMatch = functionStr.match(/([^,]+),([^,]+)/);
191
+ if (!commaMatch) return;
192
+ let xExpr = commaMatch[1].trim(), yExpr = commaMatch[2].trim();
193
+ if (shouldRound) {
194
+ xExpr = xExpr.replace(/(\d+\.\d{4,})/g, (m) => roundToThreeDecimals(parseFloat(m)).toString());
195
+ yExpr = yExpr.replace(/(\d+\.\d{4,})/g, (m) => roundToThreeDecimals(parseFloat(m)).toString());
196
+ }
197
+ xExpr = xExpr.replace(/t\*\*\((\d+)\)/g, "\\t^$1");
198
+ xExpr = xExpr.replace(/\(1-t\)\*\*\((\d+)\)/g, "(1-\\t)^$1");
199
+ yExpr = yExpr.replace(/t\*\*\((\d+)\)/g, "\\t^$1");
200
+ yExpr = yExpr.replace(/\(1-t\)\*\*\((\d+)\)/g, "(1-\\t)^$1");
201
+ xExpr = xExpr.replace(/([ (+\-*/,])t(?!\w)/g, "$1\\t");
202
+ yExpr = yExpr.replace(/([ (+\-*/,])t(?!\w)/g, "$1\\t");
203
+ xExpr = xExpr.replace(/^t(?!\w)/, "\\t");
204
+ yExpr = yExpr.replace(/^t(?!\w)/, "\\t");
205
+ const lineStyle = convertLineStyle(options);
206
+ plots.push({ original: match[0], options, xExpression: xExpr, yExpression: yExpr, lineStyle });
207
+ });
208
+ return { hasParametricPlots: plots.length > 0, plots };
209
+ } catch (error) {
210
+ return { hasParametricPlots: false, plots: [] };
211
+ }
212
+ }
213
+ function cleanTikZCode(code, opts = {}) {
214
+ code = code.replace(/\\draw\s+\[/g, "\\\\draw[");
215
+ const shouldRound = opts.round !== false;
216
+ const includePoints = opts.points !== false;
217
+ const includeLabels = opts.labels !== false;
218
+ const tikzMatch = code.match(/\\begin\{tikzpicture\}([\s\S]*?)\\end\{tikzpicture\}/);
219
+ if (!tikzMatch) throw new Error("\u672A\u627E\u5230 tikzpicture \u73AF\u5883");
220
+ const pointRegex = /\\draw\s*\[fill=[^\]]+\]\s*\(([^)]+)\)\s*circle\s*\(([^)]+)\);/g;
221
+ const nodeRegex = /\\draw\[color=[^\]]+\]\s*\([^)]+\)\s*node\s*\{\$(?!.*\\textrm\{\\degre\})([^$]+(?:\{[^}]*\})?[^$]*)\$\}/g;
222
+ const pointMap = /* @__PURE__ */ new Map();
223
+ const pointMatches = [...code.matchAll(pointRegex)];
224
+ const nodeMatches = [...code.matchAll(nodeRegex)];
225
+ const anchoredNodes = [...code.matchAll(/\\draw\s*(?:\[[^\]]*\])?\s*\(([^)]+)\)\s*node\s*\[([^\]]+)\]\s*\{([^\r\n]*)\};/g)];
226
+ const usedAnchoredNodes = /* @__PURE__ */ new Set();
227
+ const allPoints = [];
228
+ pointMatches.forEach((match) => {
229
+ const coords = match[1];
230
+ const formattedCoords = formatCoordinate(`(${coords})`, shouldRound);
231
+ allPoints.push({ original: coords, formatted: formattedCoords.slice(1, -1) });
232
+ });
233
+ allPoints.forEach((point, index) => {
234
+ const [x, y] = point.original.split(",").map(Number);
235
+ const candidates = anchoredNodes.map((node, i) => {
236
+ const label = node[3].match(/^\$\\mathit\{([A-Za-z][A-Za-z0-9_]*)\}\$$/)?.[1] || node[3].match(/^\$([A-Za-z][A-Za-z0-9_]*)\$$/)?.[1];
237
+ const [nx, ny] = node[1].split(",").map(Number);
238
+ return { i, label, distance: Math.hypot(nx - x, ny - y) };
239
+ }).filter((n) => n.label && !usedAnchoredNodes.has(n.i)).sort((a, b) => a.distance - b.distance);
240
+ if (candidates.length && candidates[0].distance < 1) {
241
+ pointMap.set(candidates[0].label, point.formatted);
242
+ usedAnchoredNodes.add(candidates[0].i);
243
+ } else if (index < nodeMatches.length) {
244
+ pointMap.set(nodeMatches[index][1], point.formatted);
245
+ } else {
246
+ pointMap.set(`gikzPoint${index}`, point.formatted);
247
+ }
248
+ });
249
+ const functionPlotsResult = extractFunctionPlots(code, shouldRound);
250
+ const parametricPlotResult = extractParametricPlots(code, shouldRound);
251
+ const textLabels = anchoredNodes.filter((_, i) => !usedAnchoredNodes.has(i)).map((match) => ({
252
+ coords: formatCoordinate(`(${match[1]})`, shouldRound),
253
+ options: match[2],
254
+ content: match[3]
255
+ }));
256
+ const angleLabelRegex = /\\draw\[color=([^\]]+)\]\s*\(([^)]+)\)\s*node\s*\{\$([^}]+)\\textrm\{\\degre\}\$\};/g;
257
+ const angleLabelMatches = [...code.matchAll(angleLabelRegex)];
258
+ const angleLabels = [];
259
+ angleLabelMatches.forEach((match) => {
260
+ angleLabels.push({
261
+ color: match[1],
262
+ coords: formatCoordinate(`(${match[2]})`, shouldRound),
263
+ content: match[3]
264
+ });
265
+ });
266
+ const lineRegex = /\\draw\s*(\[[^\]]+\])?\s*\(([^)]+)\)\s*--\s*\(([^)]+)\);/g;
267
+ const lineMatches = [...code.matchAll(lineRegex)];
268
+ const circleRegex = /\\draw\s*\[([^\]]*line[^\]]*)\]\s*\(([^)]+)\)\s*circle\s*\(([^)]+)\);/g;
269
+ const circleMatches = [...code.matchAll(circleRegex)];
270
+ const circles = [];
271
+ circleMatches.forEach((match) => {
272
+ const options = match[1];
273
+ const centerCoords = match[2];
274
+ const radius = match[3];
275
+ const formattedCenter = formatCoordinate(`(${centerCoords})`, shouldRound);
276
+ const lineStyle = convertLineStyle(options);
277
+ let centerLabel = null;
278
+ for (const [label, coords] of pointMap) {
279
+ const coordStr = coords.includes("(") ? coords : `(${coords})`;
280
+ if (coordStr.includes(centerCoords.trim()) || formattedCenter.includes(coords)) {
281
+ centerLabel = label;
282
+ break;
283
+ }
284
+ }
285
+ circles.push({
286
+ center: centerLabel ? `(${centerLabel})` : formattedCenter,
287
+ radius: shouldRound ? roundToThreeDecimals(parseFloat(radius)) + (radius.includes("cm") ? "cm" : "") : radius,
288
+ lineStyle
289
+ });
290
+ });
291
+ const arcRegex = /\\draw\s*(\[[^\]]*\])?\s*plot\[domain=([^:]+):([^,]+),variable=\\t\]\(\{1\*([^\*]+)\*cos\(\\t r\)\+0\*[^\*]+\*sin\(\\t r\)\},\{0\*[^\*]+\*cos\(\\t r\)\+1\*[^\*]+\*sin\(\\t r\)\}\);/g;
292
+ const arcMatches = [...code.matchAll(arcRegex)];
293
+ const arcs = [];
294
+ arcMatches.forEach((match) => {
295
+ const style = match[1] || "";
296
+ const rv = (val) => shouldRound ? roundToThreeDecimals(parseFloat(val)) : val;
297
+ let lineStyle = "";
298
+ if (style.includes("dash pattern=on 1pt off 1pt on 1pt off 4pt")) lineStyle = "dash dot";
299
+ else if (style.includes("dash pattern=on 1pt off 1pt")) lineStyle = "dashed";
300
+ else if (style.includes("dotted")) lineStyle = "dotted";
301
+ const shiftRegex = /shift=\{\(([^,]+),([^)]+)\)\}/;
302
+ const shiftMatch = style.match(shiftRegex);
303
+ let styleParts = [];
304
+ if (lineStyle) styleParts.push(lineStyle);
305
+ if (shiftMatch) styleParts.push(`shift={(${rv(shiftMatch[1])},${rv(shiftMatch[2])})}`);
306
+ styleParts.push("smooth");
307
+ let newStyle = styleParts.length > 0 ? "[" + styleParts.join(", ") + "]" : "";
308
+ arcs.push({ style: newStyle, startAngle: rv(match[2]), endAngle: rv(match[3]), radius: rv(match[4]) });
309
+ });
310
+ const sectorRegex = /\\draw\s*\[shift=\{\(([^,]+),([^)]+)\)\}[^\]]*\]\s*\(0,0\)\s*--\s*plot\[domain=([^:]+):([^,\]]+),variable=\\t\]\(\{1\*([^\*]+)\*cos\(\\t r\)\+0\*[^\*]+\*sin\(\\t r\)\},\{0\*[^\*]+\*cos\(\\t r\)\+1\*[^\*]+\*sin\(\\t r\)\}\)\s*--\s*cycle\s*;/g;
311
+ const sectorMatches = [...code.matchAll(sectorRegex)];
312
+ const sectors = [];
313
+ sectorMatches.forEach((match) => {
314
+ const rv = (val) => shouldRound ? roundToThreeDecimals(parseFloat(val)) : val;
315
+ const style = match[0].match(/\\draw\s*\[([^\]]+)\]/)[1];
316
+ sectors.push({
317
+ shiftX: rv(match[1].trim()),
318
+ shiftY: rv(match[2].trim()),
319
+ startAngle: rv(match[3].trim()),
320
+ endAngle: rv(match[4].trim()),
321
+ radius: rv(match[5].trim()),
322
+ lineStyle: convertLineStyle(style)
323
+ });
324
+ });
325
+ const ellipseRegex = /\\draw\s*\[([^\]]*)\]\s*\(([^)]+)\)\s*ellipse\s*\(([^)]+)\);/g;
326
+ const ellipseMatches = [...code.matchAll(ellipseRegex)];
327
+ const ellipses = [];
328
+ ellipseMatches.forEach((match) => {
329
+ const options = match[1], centerCoords = match[2], radii = match[3];
330
+ const radiusParts = radii.split(" and ");
331
+ let xR = radiusParts[0]?.trim() || "", yR = radiusParts[1]?.trim() || "";
332
+ const formattedCenter = formatCoordinate(`(${centerCoords})`, shouldRound);
333
+ let centerLabel = null;
334
+ for (const [label, coords] of pointMap) {
335
+ const cs = coords.includes("(") ? coords : `(${coords})`;
336
+ if (cs.includes(centerCoords.trim()) || formattedCenter.includes(coords)) {
337
+ centerLabel = label;
338
+ break;
339
+ }
340
+ }
341
+ let rotationAngle = 0, rotationCenter = null;
342
+ const rotateMatch = options.match(/rotate around=\{([^:]+):\(([^)]+)\)\}/);
343
+ if (rotateMatch) {
344
+ rotationAngle = parseFloat(rotateMatch[1]);
345
+ if (shouldRound) rotationAngle = roundToThreeDecimals(rotationAngle);
346
+ const rc = rotateMatch[2];
347
+ const frc = formatCoordinate(`(${rc})`, shouldRound);
348
+ for (const [label, coords] of pointMap) {
349
+ const cs = coords.includes("(") ? coords : `(${coords})`;
350
+ if (cs.includes(rc.trim()) || frc.includes(coords)) {
351
+ rotationCenter = label;
352
+ break;
353
+ }
354
+ }
355
+ if (!rotationCenter) rotationCenter = frc;
356
+ }
357
+ const lineStyle = convertLineStyle(options);
358
+ if (shouldRound && xR && yR) {
359
+ const xU = xR.replace(/[0-9.\-\s]/g, ""), yU = yR.replace(/[0-9.\-\s]/g, "");
360
+ xR = roundToThreeDecimals(parseFloat(xR)) + xU;
361
+ yR = roundToThreeDecimals(parseFloat(yR)) + yU;
362
+ }
363
+ const obj = { center: centerLabel ? `(${centerLabel})` : formattedCenter, xRadius: xR, yRadius: yR, lineStyle, hasRotation: !!rotateMatch };
364
+ if (rotateMatch) {
365
+ obj.rotationAngle = rotationAngle;
366
+ obj.rotationCenter = rotationCenter ? `(${rotationCenter})` : formattedCenter;
367
+ }
368
+ ellipses.push(obj);
369
+ });
370
+ const angleRegex = /\\draw\s*\[shift=\{\(([^,]+),([^)]+)\)\}[^\]]*\]\s*\(0,0\)\s*--\s*\(([^:]+):([^)]+)\)\s*arc\s*\(([^:]+):([^)]+):([^)]+)\)\s*--\s*cycle;/g;
371
+ const angleMatches = [...code.matchAll(angleRegex)];
372
+ const angles = [];
373
+ angleMatches.forEach((match) => {
374
+ const cX = match[1].trim(), cY = match[2].trim();
375
+ const formattedCenter = formatCoordinate(`(${cX},${cY})`, shouldRound);
376
+ let centerLabel = null;
377
+ for (const [label, coords] of pointMap) {
378
+ const cs = coords.includes("(") ? coords : `(${coords})`;
379
+ if (cs.includes(`${cX},${cY}`) || formattedCenter.includes(coords)) {
380
+ centerLabel = label;
381
+ break;
382
+ }
383
+ }
384
+ const rv = (v) => shouldRound ? roundToThreeDecimals(parseFloat(v)) : v;
385
+ angles.push({
386
+ center: centerLabel ? `(${centerLabel})` : formattedCenter,
387
+ startAngle: rv(match[3].trim()),
388
+ endAngle: rv(match[6].trim()),
389
+ radius: rv(match[4].trim())
390
+ });
391
+ });
392
+ let result = "\\begin{tikzpicture}[scale=1]\n";
393
+ if (pointMap.size > 0) {
394
+ result += " % \u5750\u6807\u70B9\u5B9A\u4E49\n";
395
+ for (const [label, coords] of pointMap) {
396
+ result += ` \\coordinate (${label}) at ${coords.includes("(") ? coords : `(${coords})`};
397
+ `;
398
+ }
399
+ result += "\n";
400
+ }
401
+ if (functionPlotsResult.hasFunctions) {
402
+ result += " % \u51FD\u6570\u56FE\u50CF\n" + functionPlotsResult.scopeCode + "\n";
403
+ }
404
+ if (parametricPlotResult.hasParametricPlots) {
405
+ result += " % \u8D1D\u585E\u5C14\u66F2\u7EBF\n";
406
+ parametricPlotResult.plots.forEach((plot) => {
407
+ const ls = plot.lineStyle ? `[${plot.lineStyle}, smooth, samples=100, domain=0:1, variable=\\t]` : "[smooth, samples=100, domain=0:1, variable=\\t]";
408
+ result += ` \\draw${ls} plot
409
+ ({${plot.xExpression}},
410
+ {${plot.yExpression}});
411
+
412
+ `;
413
+ });
414
+ }
415
+ if (lineMatches.length > 0 || circles.length > 0 || arcs.length > 0 || ellipses.length > 0 || angles.length > 0 || angleLabels.length > 0 || sectors.length > 0) {
416
+ result += " % \u51E0\u4F55\u5143\u7D20\n";
417
+ if (angles.length > 0) {
418
+ result += " % \u89D2\u5EA6\n";
419
+ angles.forEach((a) => {
420
+ result += ` \\fill [shift=${a.center}, gray!30] (0,0) -- (${a.startAngle}:${a.radius}) arc (${a.startAngle}:${a.endAngle}:${a.radius}) -- cycle;
421
+ `;
422
+ });
423
+ result += "\n";
424
+ }
425
+ if (sectors.length > 0) {
426
+ result += " % \u6247\u5F62\u7ED8\u5236\n";
427
+ sectors.forEach((s) => {
428
+ const st = s.lineStyle ? `[${s.lineStyle}]` : "";
429
+ result += ` \\draw${st} [shift={(${s.shiftX},${s.shiftY})}] (0,0) -- plot[domain=${s.startAngle}:${s.endAngle}]({1*${s.radius}*cos(\\x r)+0*${s.radius}*sin(\\x r)},{0*${s.radius}*cos(\\x r)+1*${s.radius}*sin(\\x r)}) -- cycle;
430
+ `;
431
+ });
432
+ if (lineMatches.length > 0) result += "\n";
433
+ }
434
+ if (circles.length > 0) {
435
+ circles.forEach((c) => {
436
+ result += c.lineStyle ? ` \\draw[${c.lineStyle}] ${c.center} circle (${c.radius});
437
+ ` : ` \\draw ${c.center} circle (${c.radius});
438
+ `;
439
+ });
440
+ if (lineMatches.length > 0 || arcs.length > 0) result += "\n";
441
+ }
442
+ if (ellipses.length > 0) {
443
+ result += " % \u692D\u5706\n";
444
+ ellipses.forEach((e) => {
445
+ const drawOpts = [];
446
+ if (e.lineStyle) drawOpts.push(e.lineStyle);
447
+ if (e.hasRotation) drawOpts.push(`rotate around={${e.rotationAngle}:${e.rotationCenter}}`);
448
+ result += drawOpts.length > 0 ? ` \\draw[${drawOpts.join(", ")}] ${e.center} ellipse (${e.xRadius} and ${e.yRadius});
449
+ ` : ` \\draw ${e.center} ellipse (${e.xRadius} and ${e.yRadius});
450
+ `;
451
+ });
452
+ if (lineMatches.length > 0 || arcs.length > 0) result += "\n";
453
+ }
454
+ if (arcs.length > 0) {
455
+ result += " % \u5706\u5F27\u7ED8\u5236\n";
456
+ arcs.forEach((arc) => {
457
+ const s = arc.style.trim() ? arc.style : "";
458
+ result += ` \\draw${s} plot[domain=${arc.startAngle}:${arc.endAngle}]({1*${arc.radius}*cos(\\x r)+0*${arc.radius}*sin(\\x r)},{0*${arc.radius}*cos(\\x r)+1*${arc.radius}*sin(\\x r)});
459
+ `;
460
+ });
461
+ if (lineMatches.length > 0) result += "\n";
462
+ }
463
+ const processedLines = /* @__PURE__ */ new Set();
464
+ const parseCoords = (str) => {
465
+ const m = str.match(/\(([^,]+),([^)]+)\)/);
466
+ return m ? { x: parseFloat(m[1]), y: parseFloat(m[2]) } : null;
467
+ };
468
+ lineMatches.forEach((match) => {
469
+ const style = match[1] || "";
470
+ const coord1 = match[2], coord2 = match[3];
471
+ const convertedStyle = convertLineStyle(style);
472
+ let label1 = null, label2 = null;
473
+ const tc1 = formatCoordinate(`(${coord1})`, shouldRound);
474
+ const tc2 = formatCoordinate(`(${coord2})`, shouldRound);
475
+ const t1 = parseCoords(tc1), t2 = parseCoords(tc2);
476
+ for (const [label, coords] of pointMap) {
477
+ const pcs = coords.includes("(") ? coords : `(${coords})`;
478
+ const p = parseCoords(pcs);
479
+ if (p && t1 && Math.abs(p.x - t1.x) < 1e-3 && Math.abs(p.y - t1.y) < 1e-3) label1 = label;
480
+ if (p && t2 && Math.abs(p.x - t2.x) < 1e-3 && Math.abs(p.y - t2.y) < 1e-3) label2 = label;
481
+ }
482
+ if (label1 && label2) {
483
+ const key = `${label1}-${label2}`, rev = `${label2}-${label1}`;
484
+ if (!processedLines.has(key) && !processedLines.has(rev)) {
485
+ result += convertedStyle ? ` \\draw[${convertedStyle}] (${label1}) -- (${label2});
486
+ ` : ` \\draw (${label1}) -- (${label2});
487
+ `;
488
+ processedLines.add(key);
489
+ }
490
+ } else {
491
+ const fc1 = formatCoordinate(`(${coord1})`, shouldRound);
492
+ const fc2 = formatCoordinate(`(${coord2})`, shouldRound);
493
+ result += convertedStyle ? ` \\draw[${convertedStyle}] ${fc1} -- ${fc2};
494
+ ` : ` \\draw ${fc1} -- ${fc2};
495
+ `;
496
+ }
497
+ });
498
+ }
499
+ if (includePoints && pointMap.size > 0) {
500
+ result += "\n % \u70B9\u6807\u8BB0\n";
501
+ for (const [label] of pointMap) {
502
+ result += ` \\draw[fill=black] (${label}) circle (1pt);
503
+ `;
504
+ }
505
+ }
506
+ if (includeLabels && pointMap.size > 0) {
507
+ result += "\n % \u70B9\u6807\u7B7E\n";
508
+ const allPointsData = [];
509
+ for (const [label, coords] of pointMap) {
510
+ const m = coords.match(/\(?([^,]+),([^)]+)\)?/);
511
+ if (m) allPointsData.push({ label, x: parseFloat(m[1]), y: parseFloat(m[2]) });
512
+ }
513
+ for (const point of allPointsData) {
514
+ if (/^gikzPoint\d+$/.test(point.label)) continue;
515
+ const pos = getSmartLabelPosition(point.x, point.y, allPointsData);
516
+ result += ` \\node [${pos}] at (${point.label}) {$${point.label}$};
517
+ `;
518
+ }
519
+ }
520
+ if (angleLabels.length > 0) {
521
+ result += "\n % \u89D2\u5EA6\u6807\u7B7E\n";
522
+ angleLabels.forEach((l) => {
523
+ result += ` \\draw ${l.coords} node {$${l.content}^{\\circ}$};
524
+ `;
525
+ });
526
+ }
527
+ if (textLabels.length > 0) {
528
+ result += "\n % \u6587\u672C\u6807\u7B7E\n";
529
+ textLabels.forEach((l) => {
530
+ result += ` \\draw ${l.coords} node[${l.options}] {${l.content}};
531
+ `;
532
+ });
533
+ }
534
+ result += "\\end{tikzpicture}";
535
+ return result;
536
+ }
537
+ function convertGeoGebraXML(xmlStr, opts = {}) {
538
+ const shouldRound = opts.round !== false;
539
+ const includePoints = opts.points !== false;
540
+ const includeLabels = opts.labels !== false;
541
+ const rv = (v) => shouldRound ? roundToThreeDecimals(v) : v;
542
+ const de = (s) => s.replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&apos;/g, "'").replace(/&quot;/g, '"');
543
+ const constrM = xmlStr.match(/<construction[^>]*>([\s\S]*?)<\/construction>/);
544
+ if (!constrM) throw new Error("XML \u4E2D\u672A\u627E\u5230 construction \u5757");
545
+ const constr = constrM[1];
546
+ const elements = /* @__PURE__ */ new Map();
547
+ const elRe = /<element\s+type="([^"]+)"\s+label="([^"]+)">([\s\S]*?)<\/element>/g;
548
+ let m;
549
+ while (m = elRe.exec(constr)) {
550
+ const label = de(m[2]), body = m[3];
551
+ const el = { type: m[1], label };
552
+ const showM = body.match(/<show\s+object="([^"]+)"\s+label="([^"]+)"/);
553
+ el.visible = showM ? showM[1] === "true" : false;
554
+ el.showLabel = showM ? showM[2] === "true" : false;
555
+ const coordsM = body.match(/<coords\s+x="([^"]+)"\s+y="([^"]+)"\s+z="([^"]+)"/);
556
+ if (coordsM) {
557
+ const z = parseFloat(coordsM[3]) || 1;
558
+ el.x = parseFloat(coordsM[1]) / z;
559
+ el.y = parseFloat(coordsM[2]) / z;
560
+ }
561
+ const valM = body.match(/<value\s+val="([^"]+)"/);
562
+ if (valM) el.value = parseFloat(valM[1]);
563
+ const arcM = body.match(/<arcSize\s+val="([^"]+)"/);
564
+ if (arcM) el.arcSize = parseInt(arcM[1]);
565
+ const colM = body.match(/<objColor[^>]+alpha="([^"]+)"/);
566
+ if (colM) el.alpha = parseFloat(colM[1]);
567
+ const lineM = body.match(/<lineStyle\s+thickness="([^"]+)"\s+type="([^"]+)"/);
568
+ if (lineM) {
569
+ el.lineThickness = parseInt(lineM[1]);
570
+ el.lineType = parseInt(lineM[2]);
571
+ }
572
+ if (el.x !== void 0 && (isNaN(el.x) || isNaN(el.y))) continue;
573
+ elements.set(label, el);
574
+ }
575
+ const commands = [];
576
+ const cmdRe = /<command\s+name="([^"]+)">([\s\S]*?)<\/command>/g;
577
+ while (m = cmdRe.exec(constr)) {
578
+ const cmd = { name: m[1], inputs: [], outputs: [] };
579
+ const inM = m[2].match(/<input\s+([^/]*)\/>/);
580
+ if (inM) {
581
+ const r = /a(\d+)="([^"]+)"/g;
582
+ let a;
583
+ while (a = r.exec(inM[1])) cmd.inputs[+a[1]] = de(a[2]);
584
+ }
585
+ const outM = m[2].match(/<output\s+([^/]*)\/>/);
586
+ if (outM) {
587
+ const r = /a(\d+)="([^"]+)"/g;
588
+ let a;
589
+ while (a = r.exec(outM[1])) cmd.outputs[+a[1]] = de(a[2]);
590
+ }
591
+ commands.push(cmd);
592
+ }
593
+ const cmdByOut = /* @__PURE__ */ new Map();
594
+ for (const cmd of commands)
595
+ for (const lbl of cmd.outputs) if (lbl) cmdByOut.set(lbl, cmd);
596
+ const polyEdges = /* @__PURE__ */ new Set();
597
+ for (const cmd of commands) {
598
+ if (cmd.name === "Polygon") {
599
+ for (let i = 1; i < cmd.outputs.length; i++) if (cmd.outputs[i]) polyEdges.add(cmd.outputs[i]);
600
+ }
601
+ }
602
+ const refPts = /* @__PURE__ */ new Set();
603
+ const lsName = (t) => {
604
+ switch (t) {
605
+ case 10:
606
+ case 15:
607
+ return "dashed";
608
+ case 20:
609
+ return "dotted";
610
+ case 30:
611
+ return "dash dot";
612
+ default:
613
+ return "";
614
+ }
615
+ };
616
+ const segs = [];
617
+ for (const [label, el] of elements) {
618
+ if (!el.visible || el.type !== "segment" || polyEdges.has(label)) continue;
619
+ const cmd = cmdByOut.get(label);
620
+ if (cmd && cmd.name === "Segment" && cmd.inputs[0] && cmd.inputs[1]) {
621
+ segs.push({ from: cmd.inputs[0], to: cmd.inputs[1], ls: lsName(el.lineType || 0) });
622
+ refPts.add(cmd.inputs[0]);
623
+ refPts.add(cmd.inputs[1]);
624
+ }
625
+ }
626
+ const circs = [];
627
+ for (const [label, el] of elements) {
628
+ if (!el.visible || el.type !== "conic") continue;
629
+ const cmd = cmdByOut.get(label);
630
+ if (cmd && cmd.name === "Circle") {
631
+ const cEl = elements.get(cmd.inputs[0]), tEl = elements.get(cmd.inputs[1]);
632
+ if (cEl && tEl && cEl.x !== void 0 && tEl.x !== void 0) {
633
+ const dx = tEl.x - cEl.x, dy = tEl.y - cEl.y;
634
+ circs.push({ center: cmd.inputs[0], radius: rv(Math.sqrt(dx * dx + dy * dy)) });
635
+ refPts.add(cmd.inputs[0]);
636
+ }
637
+ }
638
+ }
639
+ const polys = [];
640
+ for (const [label, el] of elements) {
641
+ if (!el.visible || el.type !== "polygon") continue;
642
+ const cmd = cmdByOut.get(label);
643
+ if (cmd && cmd.name === "Polygon") {
644
+ const verts = [];
645
+ for (let i = 0; cmd.inputs[i]; i++) {
646
+ verts.push(cmd.inputs[i]);
647
+ refPts.add(cmd.inputs[i]);
648
+ }
649
+ polys.push({ vertices: verts, alpha: el.alpha || 0 });
650
+ }
651
+ }
652
+ const angs = [];
653
+ for (const [label, el] of elements) {
654
+ if (!el.visible || el.type !== "angle") continue;
655
+ const cmd = cmdByOut.get(label);
656
+ if (cmd && cmd.name === "Angle") {
657
+ angs.push({ ptA: cmd.inputs[0], vertex: cmd.inputs[1], ptC: cmd.inputs[2], value: el.value });
658
+ refPts.add(cmd.inputs[0]);
659
+ refPts.add(cmd.inputs[1]);
660
+ refPts.add(cmd.inputs[2]);
661
+ }
662
+ }
663
+ for (const [label, el] of elements)
664
+ if (el.type === "point" && (el.visible || el.showLabel)) refPts.add(label);
665
+ const coords = [];
666
+ for (const label of refPts) {
667
+ const el = elements.get(label);
668
+ if (el && el.type === "point" && el.x !== void 0) coords.push({ label, x: rv(el.x), y: rv(el.y) });
669
+ }
670
+ coords.sort((a, b) => a.label.localeCompare(b.label));
671
+ let out = "\\begin{tikzpicture}[scale=1]\n";
672
+ if (coords.length > 0) {
673
+ out += " % \u5750\u6807\u70B9\u5B9A\u4E49\n";
674
+ for (const c of coords) out += ` \\coordinate (${c.label}) at (${c.x},${c.y});
675
+ `;
676
+ out += "\n";
677
+ }
678
+ out += " % \u51E0\u4F55\u5143\u7D20\n";
679
+ if (angs.length > 0) {
680
+ for (const ang of angs) {
681
+ const vEl = elements.get(ang.vertex), aEl = elements.get(ang.ptA), cEl = elements.get(ang.ptC);
682
+ if (!vEl || !aEl || !cEl) continue;
683
+ let sa = rv(Math.atan2(aEl.y - vEl.y, aEl.x - vEl.x) * 180 / Math.PI);
684
+ let ea = rv(Math.atan2(cEl.y - vEl.y, cEl.x - vEl.x) * 180 / Math.PI);
685
+ if (ea <= sa) ea += 360;
686
+ out += ` \\fill[green!10] (${ang.vertex}) -- ++(${sa}:0.4) arc (${sa}:${ea}:0.4) -- cycle;
687
+ `;
688
+ }
689
+ out += "\n";
690
+ }
691
+ if (polys.length > 0) {
692
+ for (const p of polys) {
693
+ if (p.alpha > 0) {
694
+ const pth = p.vertices.map((v) => `(${v})`).join(" -- ") + " -- cycle";
695
+ out += ` \\fill[gray!20, fill opacity=${rv(p.alpha)}] ${pth};
696
+ `;
697
+ }
698
+ }
699
+ out += "\n";
700
+ }
701
+ if (circs.length > 0) {
702
+ for (const c of circs) out += ` \\draw (${c.center}) circle (${c.radius});
703
+ `;
704
+ out += "\n";
705
+ }
706
+ if (segs.length > 0) {
707
+ const drawn = /* @__PURE__ */ new Set();
708
+ for (const s of segs) {
709
+ const k = [s.from, s.to].sort().join("|");
710
+ if (drawn.has(k)) continue;
711
+ drawn.add(k);
712
+ out += s.ls ? ` \\draw[${s.ls}] (${s.from}) -- (${s.to});
713
+ ` : ` \\draw (${s.from}) -- (${s.to});
714
+ `;
715
+ }
716
+ out += "\n";
717
+ }
718
+ if (includePoints) {
719
+ const visPts = coords.filter((c) => {
720
+ const e = elements.get(c.label);
721
+ return e && e.visible;
722
+ });
723
+ if (visPts.length > 0) {
724
+ out += " % \u70B9\u6807\u8BB0\n";
725
+ for (const p of visPts) out += ` \\draw[fill=black] (${p.label}) circle (1pt);
726
+ `;
727
+ out += "\n";
728
+ }
729
+ }
730
+ if (includeLabels) {
731
+ const lblPts = coords.filter((c) => {
732
+ const e = elements.get(c.label);
733
+ return e && (e.visible || e.showLabel);
734
+ });
735
+ if (lblPts.length > 0) {
736
+ out += " % \u70B9\u6807\u7B7E\n";
737
+ for (const p of lblPts) {
738
+ const pos = getSmartLabelPosition(p.x, p.y, coords);
739
+ out += ` \\node[${pos}] at (${p.label}) {$${p.label}$};
740
+ `;
741
+ }
742
+ }
743
+ }
744
+ out += "\\end{tikzpicture}";
745
+ return out;
746
+ }
747
+ function wrapStandalone(tikzCode) {
748
+ return `\\documentclass[border=5pt]{standalone}
749
+ \\usepackage{tikz}
750
+ \\usepackage{pgfplots}
751
+ \\pgfplotsset{compat=1.15}
752
+ \\usetikzlibrary{arrows.meta}
753
+
754
+ \\begin{document}
755
+ ${tikzCode}
756
+ \\end{document}
757
+ `;
758
+ }
759
+ module.exports = { cleanTikZCode, wrapStandalone, convertGeoGebraXML };
760
+ }
761
+ });
762
+
763
+ // gikz/browser.cjs
764
+ var require_browser = __commonJS({
765
+ "gikz/browser.cjs"() {
766
+ globalThis.Gikz = Object.freeze(require_core());
767
+ }
768
+ });
769
+ require_browser();
770
+ })();