Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions documentation/Example Prompts.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,18 @@ Plot the parametric curve x(t) = cos(t), y(t) = sin(t), then draw the tangent at
Create an ellipse e1 with radii 4 and 2, draw the normal line at angle pi/2.
Draw a tangent line to the function f1 at x = 1 with length 6 in blue.

# Geometric Constructions
Create points A(0,0) and B(6,0), draw segment AB, then find the midpoint of AB.
Find the midpoint between points P and Q.
Draw the perpendicular bisector of segment AB.
Drop a perpendicular from point C to segment AB.
Create points A(0,0), B(4,0), C(0,3) and bisect the angle at A defined by B and C.
Draw a line through point P parallel to segment AB.
Construct the perpendicular bisector of segment s1 with length 10 in blue.
Create a triangle with vertices A(0,0), B(4,0), C(0,3) and construct its circumcircle.
Construct the incircle of triangle ABC.
Create points P(0,0), Q(6,0), R(3,5) and draw the circle passing through all three.

# Regression Analysis
Fit a linear regression to x_data=[1,2,3,4,5] and y_data=[2.1,3.9,6.2,7.8,10.1]. Show the data points and fitted curve.
Fit a quadratic polynomial (degree 2) to x_data=[0,1,2,3,4] and y_data=[0,1,4,9,16]. Report the R-squared value.
Expand Down
18 changes: 18 additions & 0 deletions documentation/Reference Manual.txt
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,13 @@ Attributes:
- `update_parametric_function(name, new_color=None, new_t_min=None, new_t_max=None)`: Update editable properties of an existing parametric function
- `draw_tangent_line(curve_name, parameter, name=None, length=4.0, color=None)`: Draw a tangent line segment to a curve at a specified point. For functions y=f(x), parameter is the x-coordinate. For parametric curves, it's the t value. For circles/ellipses, it's the angle in radians from the positive x-axis.
- `draw_normal_line(curve_name, parameter, name=None, length=4.0, color=None)`: Draw a normal line segment (perpendicular to tangent) to a curve at a specified point. Same parameter conventions as draw_tangent_line.
- `construct_midpoint(p1_name=None, p2_name=None, segment_name=None, name=None, color=None)`: Construct a point at the midpoint of a segment or between two named points. Provide either `segment_name` or both `p1_name` and `p2_name`.
- `construct_perpendicular_bisector(segment_name, length=6.0, name=None, color=None)`: Construct the perpendicular bisector of a segment. Creates a new segment passing through the midpoint, perpendicular to the original.
- `construct_perpendicular_from_point(point_name, segment_name, name=None, color=None)`: Drop a perpendicular from a point to a segment. Creates the foot point on the line and a segment from the original point to the foot (single undo step).
- `construct_angle_bisector(vertex_name=None, p1_name=None, p2_name=None, angle_name=None, length=6.0, name=None, color=None)`: Construct a segment along the angle bisector. Provide either `angle_name` or all three point names (`vertex_name`, `p1_name`, `p2_name`).
- `construct_parallel_line(segment_name, point_name, length=6.0, name=None, color=None)`: Construct a segment through a point, parallel to a given segment. The new segment is centered on the specified point.
- `construct_circumcircle(triangle_name=None, p1_name=None, p2_name=None, p3_name=None, name=None, color=None)`: Construct the circumscribed circle (circumcircle) of a triangle or three points. The circumcircle passes through all three vertices. Provide either `triangle_name` or all three point names.
- `construct_incircle(triangle_name, name=None, color=None)`: Construct the inscribed circle (incircle) of a triangle. The incircle is tangent to all three sides.
- `plot_distribution(name=None, representation="continuous", distribution_type="normal", distribution_params=None, plot_bounds=None, shade_bounds=None, curve_color=None, fill_color=None, fill_opacity=None, bar_count=None)`: Plot a probability distribution. For representation="continuous", `plot_bounds` controls the curve domain, while `shade_bounds` controls the shaded interval under the curve (clamped into `plot_bounds`). For representation="discrete", `plot_bounds` controls the bar span and `shade_bounds` is ignored. Discrete distribution plots create a `DiscretePlot` composite plus derived `Bar` drawables for rendering; derived bars are regenerated on workspace load and may be omitted from serialized canvas state to keep prompts compact.
- `plot_bars(name=None, values=None, labels_below=None, labels_above=None, bar_spacing=None, bar_width=None, stroke_color=None, fill_color=None, fill_opacity=None, x_start=None, y_base=None)`: Plot a bar chart (`BarsPlot` composite plus derived `Bar` drawables). Derived bars are regenerated on workspace load and may be omitted from serialized canvas state to keep prompts compact.
- `fit_regression(name=None, x_data=None, y_data=None, model_type="linear", degree=None, plot_bounds=None, curve_color=None, show_points=True, point_color=None)`: Fit a regression model to data and plot the resulting curve. Supported model types: "linear" (y=mx+b), "polynomial" (y=a0+a1*x+...+an*x^n, requires `degree`), "exponential" (y=a*e^(bx), requires positive y), "logarithmic" (y=a+b*ln(x), requires positive x), "power" (y=a*x^b, requires positive x and y), "logistic" (y=L/(1+e^(-k(x-x0)))), and "sinusoidal" (y=a*sin(bx+c)+d, requires at least 4 points). Returns function_name, expression, coefficients, r_squared, model_type, bounds, and optionally point_names. Use `delete_function` to remove the curve; delete points individually.
Expand Down Expand Up @@ -4496,6 +4503,17 @@ Key Features:
- `logistic`: Logistic growth (y = L/(1+e^(-k(x-x0))))
- `sinusoidal`: Sinusoidal regression (y = a*sin(bx+c)+d)

#### Construction Manager (`managers/construction_manager.py`)

Manages geometric constructions (midpoints, perpendicular bisectors, angle bisectors, perpendicular/parallel lines) by computing coordinates and creating standard Point and Segment drawables via existing managers. Constructions produce static snapshots — no reactive re-computation when source objects move.

**Key Methods:**
- `create_midpoint(p1_name, p2_name, segment_name, name, color)`: Create a point at the midpoint of two points or a segment
- `create_perpendicular_bisector(segment_name, length, name, color)`: Create the perpendicular bisector of a segment
- `create_perpendicular_from_point(point_name, segment_name, name, color)`: Drop a perpendicular from a point to a segment (creates foot point + segment as single undo step)
- `create_angle_bisector(vertex_name, p1_name, p2_name, angle_name, length, name, color)`: Create a segment along the angle bisector
- `create_parallel_line(segment_name, point_name, length, name, color)`: Create a segment through a point parallel to a given segment

#### Polygon Type (`managers/polygon_type.py`)

```
Expand Down
2 changes: 1 addition & 1 deletion documentation/todo.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
- tabular workflow: create/query/update data tables from chat with HUD-linked previews
- CSV workflow: import/export datasets through chat commands with validation and schema feedback
- plotting suite: scatter/histogram/box plots, polar plots, implicit plots from natural language intents
- geometric construction toolkit: midpoint/perpendicular/parallel/bisectors/circle-through-3-points through declarative commands
- [done] geometric construction toolkit: midpoint/perpendicular/parallel/bisectors/circumcircle/incircle through declarative commands (PR #41 + circumcircle/incircle follow-up)
- relation inspector: explain and verify geometric relations (parallel/perpendicular/collinear/concyclic/equal-length) on demand
- transform workflows: reflection/dilation/shear/rotation/translation using object references and constraint-aware execution
- interaction tools: tracing, root/extrema/intersection discovery, parameter sweeps, and dynamic slider orchestration from chat
Expand Down
4 changes: 2 additions & 2 deletions server_tests/data/tool_discovery_cases.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"metadata": {
"schema_version": 1,
"description": "Tool discovery benchmark cases for search_tools semantic routing.",
"expected_tool_count": 79,
"expected_tool_hash": "ae51bab482526d31320b100c85238a6db4ab9aa5c6c6a9037494d4c0686a6675",
"expected_tool_count": 87,
"expected_tool_hash": "932b5456edb8acedd97213b4f7fc186b483f1439c437f04fe63f7e3ad0395462",
"confusion_clusters": {
"convert_cluster": [
"convert",
Expand Down
102 changes: 102 additions & 0 deletions static/client/canvas.py
Original file line number Diff line number Diff line change
Expand Up @@ -1436,6 +1436,108 @@ def create_normal_line(
curve_name, parameter, name=name, length=length, color=color
)

# ------------------- Construction Methods -------------------

def create_midpoint(
self,
p1_name: Optional[str] = None,
p2_name: Optional[str] = None,
*,
segment_name: Optional[str] = None,
name: Optional[str] = None,
color: Optional[str] = None,
) -> "Drawable":
"""Create a point at the midpoint of two points or a segment."""
return self.drawable_manager.create_midpoint(
p1_name, p2_name, segment_name=segment_name, name=name, color=color
)

def create_perpendicular_bisector(
self,
segment_name: str,
*,
length: Optional[float] = None,
name: Optional[str] = None,
color: Optional[str] = None,
) -> "Drawable":
"""Create the perpendicular bisector of a segment."""
return self.drawable_manager.create_perpendicular_bisector(
segment_name, length=length, name=name, color=color
)

def create_perpendicular_from_point(
self,
point_name: str,
segment_name: str,
*,
name: Optional[str] = None,
color: Optional[str] = None,
) -> Dict[str, Any]:
"""Drop a perpendicular from a point to a segment."""
return self.drawable_manager.create_perpendicular_from_point(
point_name, segment_name, name=name, color=color
)

def create_angle_bisector(
self,
vertex_name: Optional[str] = None,
p1_name: Optional[str] = None,
p2_name: Optional[str] = None,
*,
angle_name: Optional[str] = None,
length: Optional[float] = None,
name: Optional[str] = None,
color: Optional[str] = None,
) -> "Drawable":
"""Create a segment along the bisector of an angle."""
return self.drawable_manager.create_angle_bisector(
vertex_name, p1_name, p2_name,
angle_name=angle_name, length=length, name=name, color=color
)

def create_parallel_line(
self,
segment_name: str,
point_name: str,
*,
length: Optional[float] = None,
name: Optional[str] = None,
color: Optional[str] = None,
) -> "Drawable":
"""Create a segment through a point, parallel to a given segment."""
return self.drawable_manager.create_parallel_line(
segment_name, point_name, length=length, name=name, color=color
)

def create_circumcircle(
self,
*,
triangle_name: Optional[str] = None,
p1_name: Optional[str] = None,
p2_name: Optional[str] = None,
p3_name: Optional[str] = None,
name: Optional[str] = None,
color: Optional[str] = None,
) -> "Drawable":
"""Create the circumscribed circle of a triangle or three points."""
return self.drawable_manager.create_circumcircle(
triangle_name=triangle_name,
p1_name=p1_name, p2_name=p2_name, p3_name=p3_name,
name=name, color=color,
)

def create_incircle(
self,
triangle_name: str,
*,
name: Optional[str] = None,
color: Optional[str] = None,
) -> "Drawable":
"""Create the inscribed circle of a triangle."""
return self.drawable_manager.create_incircle(
triangle_name, name=name, color=color,
)

def translate_object(self, name: str, x_offset: float, y_offset: float) -> bool:
"""Translates a drawable object by the specified offset"""
return bool(self.transformations_manager.translate_object(name, x_offset, y_offset))
Expand Down
Loading