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 docs/scripting.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,25 @@ Use **`ezy.help()`** or **`help()`** in either console for the built-in reminder
| `view.get_camera()` | Camera vectors: `eye`, `center`, and `up` |
| `view.set_camera(ex, ey, ez, cx, cy, cz, ux, uy, uz)` | Set camera vectors |

**Sketch inspection and creation** (Lua and Python; indices are **1-based** in Lua, **0-based** in Python):

| Method | Purpose |
| --- | --- |
| `view.curr_sketch_node_count()` / `view.curr_sketch_node(i)` | Read nodes `(x, y)` on the current sketch plane |
| `view.curr_sketch_dim_count()` / `view.curr_sketch_dim(i)` | Read length dimensions |
| `view.add_sketch(plane, offset, base_name)` | New sketch on `XY`, `XZ`, or `YZ` (`offset` in display units; optional name) |
| `view.add_edge(x1, y1, x2, y2)` | Add a linear edge to the current sketch |
| `view.finish_sketch_edges()` | Rebuild closed-face topology after bulk edge import |

**Lua only:** global **`print`** is routed to **`ezy.log`**.
**Python only:** **`print`** is similarly redirected to **`ezy.log`** after bootstrap.

## Sample scripts

- **`res/scripts/lua/basic.lua`** - Defines **`kv(obj)`** to dump tables or list userdata methods via **`ezy.log`**.
- **`res/scripts/lua/sierpinski.lua`** - Generates a Sierpinski triangle; call **`create_sierpinski_sketch()`** to build it as a sketch.
- **`res/scripts/python/basic.py`** - Example **`dump_view()`** using **`ezy.log`** and **`view`**.
- **`res/scripts/python/sierpinski.py`** - Generates a Sierpinski triangle; call **`create_sierpinski_sketch()`** to build it as a sketch.

Copy these as templates for your own files in the same folders.

Expand Down
113 changes: 113 additions & 0 deletions res/scripts/lua/sierpinski.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
-- Sierpinski triangle sketch generator for EzyCad Lua console.
-- Just for fun!
--
-- Usage (runs on startup, or call from the console):
-- create_sierpinski(3, 20.0) -- log nodes and segments
-- create_sierpinski_sketch(3, 20.0) -- build as a new sketch

local function mid(a, b)
return { (a[1] + b[1]) / 2.0, (a[2] + b[2]) / 2.0 }
end

local function append_sierpinski_segments(order, p1, p2, p3, lines)
if order <= 0 then
lines[#lines + 1] = { p1, p2 }
lines[#lines + 1] = { p2, p3 }
lines[#lines + 1] = { p3, p1 }
return
end
local m12 = mid(p1, p2)
local m23 = mid(p2, p3)
local m31 = mid(p3, p1)
append_sierpinski_segments(order - 1, p1, m12, m31, lines)
append_sierpinski_segments(order - 1, p2, m23, m12, lines)
append_sierpinski_segments(order - 1, p3, m31, m23, lines)
end

local function line_key(a, b)
if a[1] < b[1] or (a[1] == b[1] and a[2] < b[2]) then
return string.format("%.9g,%.9g|%.9g,%.9g", a[1], a[2], b[1], b[2])
end
return string.format("%.9g,%.9g|%.9g,%.9g", b[1], b[2], a[1], a[2])
end

function create_sierpinski(order, size, center)
order = order or 3
size = size or 20.0
center = center or { 0.0, 0.0 }
local cx, cy = center[1], center[2]
local h = size * math.sqrt(3.0) / 2.0
local p1 = { cx - size / 2.0, cy - h / 3.0 }
local p2 = { cx + size / 2.0, cy - h / 3.0 }
local p3 = { cx, cy + 2.0 * h / 3.0 }

local lines = {}
append_sierpinski_segments(order, p1, p2, p3, lines)

local seen = {}
local unique_lines = {}
for _, seg in ipairs(lines) do
local a, b = seg[1], seg[2]
local key = line_key(a, b)
if not seen[key] then
seen[key] = true
unique_lines[#unique_lines + 1] = { a, b }
end
end

local node_map = {}
for _, seg in ipairs(unique_lines) do
node_map[string.format("%.9g,%.9g", seg[1][1], seg[1][2])] = seg[1]
node_map[string.format("%.9g,%.9g", seg[2][1], seg[2][2])] = seg[2]
end
local node_list = {}
for _, pt in pairs(node_map) do
node_list[#node_list + 1] = pt
end
table.sort(node_list, function(u, v)
if u[2] ~= v[2] then return u[2] < v[2] end
return u[1] < v[1]
end)

ezy.log(string.format("Sierpinski triangle: order=%d, size=%g, center=(%g, %g)", order, size, cx, cy))
ezy.log(string.format(" unique nodes: %d", #node_list))
for i, pt in ipairs(node_list) do
ezy.log(string.format(" [%d] (%.6f, %.6f)", i, pt[1], pt[2]))
end
ezy.log(string.format(" line segments: %d", #unique_lines))
for i, seg in ipairs(unique_lines) do
local a, b = seg[1], seg[2]
ezy.log(string.format(" [%d] (%.6f,%.6f) -> (%.6f,%.6f)", i, a[1], a[2], b[1], b[2]))
end
ezy.log("To build the sketch: create_sierpinski_sketch(order, size, center)")

sierpinski_nodes = node_list
sierpinski_lines = unique_lines
return node_list, unique_lines
end

function create_sierpinski_sketch(order, size, center, plane, offset, name)
order = order or 3
size = size or 20.0
center = center or { 0.0, 0.0 }
plane = plane or "XY"
offset = offset or 0.0
name = name or "Sierpinski"
local node_list, unique_lines = create_sierpinski(order, size, center)
view.add_sketch(plane, offset, name)
for _, seg in ipairs(unique_lines) do
local a, b = seg[1], seg[2]
view.add_edge(a[1], a[2], b[1], b[2])
end
view.finish_sketch_edges()
ezy.log(string.format("Created sketch '%s' with %d edges.", view.curr_sketch_name(), #unique_lines))
return node_list, unique_lines
end

-- Small default on load so output is visible without spamming.
local ok, err = pcall(function()
create_sierpinski(2, 10.0)
end)
if not ok then
ezy.log("sierpinski auto-gen error: " .. tostring(err))
end
25 changes: 13 additions & 12 deletions res/scripts/python/sierpinski.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,8 @@
# Just for fun!
#
# Usage (after opening Python console, or it runs on load):
# create_sierpinski(order=3, size=20.0)
#
# It will log the unique nodes and the line segments (as pairs of points).
# You can then:
# 1. Create a new sketch in the UI (or use ezy.set_mode("Sketch_add_edge") etc.)
# 2. Use the logged coordinates to add nodes/edges manually, or copy into
# a small loop if more Python bindings for sketch creation are added later.
# create_sierpinski(order=3, size=20.0) # log nodes and segments
# create_sierpinski_sketch(order=3, size=20.0) # build as a new sketch
#
# The recursion draws the standard Sierpinski gasket lines (connect midpoints
# recursively, resulting in 3**order small upward triangles' boundaries).
Expand Down Expand Up @@ -70,11 +65,7 @@ def create_sierpinski(order=3, size=20.0, center=(0.0, 0.0)):
for i, (a, b) in enumerate(unique_lines):
ezy.log(f" [{i}] ({a[0]:.6f},{a[1]:.6f}) -> ({b[0]:.6f},{b[1]:.6f})")

ezy.log("To build the sketch:")
ezy.log(" - Create or switch to a sketch (e.g. via UI or ezy.set_mode('Sketch_add_edge'))")
ezy.log(" - Use the node list above to place points (add-node tool or line tool).")
ezy.log(" - Connect them using the listed segments.")
ezy.log(" - Or extend the Python bindings to support sketch creation from code!")
ezy.log("To build the sketch: create_sierpinski_sketch(order, size, center)")

# For convenience, also stash the data on the main module so you can access from console
import __main__
Expand All @@ -83,6 +74,16 @@ def create_sierpinski(order=3, size=20.0, center=(0.0, 0.0)):

return node_list, unique_lines

def create_sierpinski_sketch(order=3, size=20.0, center=(0.0, 0.0), plane="XY", offset=0.0, name="Sierpinski"):
"""Generate a Sierpinski triangle and add it as a new sketch."""
node_list, unique_lines = create_sierpinski(order, size, center)
view.add_sketch(plane, offset, name)
for (a, b) in unique_lines:
view.add_edge(a[0], a[1], b[0], b[1])
view.finish_sketch_edges()
ezy.log(f"Created sketch '{view.curr_sketch_name()}' with {len(unique_lines)} edges.")
return node_list, unique_lines

# Auto-generate a small example on script load (so it's immediately visible in the console tab)
# You can call create_sierpinski(4) yourself for higher detail (gets dense quickly).
if __name__ == "__main__" or True: # always run on exec
Expand Down
14 changes: 11 additions & 3 deletions src/doc/script.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,14 +95,22 @@ Lua overrides global `print` to call `ezy.log`. Python bootstrap assigns `builti
| `set_camera(ex,ey,ez,cx,cy,cz,ux,uy,uz)` | `Occt_view::set_camera` |
| `get_shape(i)` | Returns `Shp` wrapper |

**Python only** (current sketch inspection):
**Lua and Python** (current sketch inspection):

| Method | Returns |
| --- | --- |
| `curr_sketch_node_count()` | Node count |
| `curr_sketch_node(i)` | `(x, y)` plane coords |
| `curr_sketch_node(i)` | `(x, y)` plane coords (Lua: 1-based index; Python: 0-based) |
| `curr_sketch_dim_count()` | Length dimension count |
| `curr_sketch_dim(i)` | `(lo, hi, visible, offset, name, distance)` |
| `curr_sketch_dim(i)` | `(lo, hi, visible, offset, name, distance)` (Lua: 1-based indices) |

**Lua and Python** (sketch creation):

| Method | Notes |
| --- | --- |
| `add_sketch(plane, offset, base_name)` | `Occt_view::add_sketch_on_ref_plane`; plane `XY`/`XZ`/`YZ` |
| `add_edge(x1,y1,x2,y2)` | `Occt_view::curr_sketch_add_edge` |
| `finish_sketch_edges()` | `Occt_view::curr_sketch_rebuild_faces` |

### `Shp` object

Expand Down
13 changes: 13 additions & 0 deletions src/gui_occt_view.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,19 @@ void Occt_view::add_sketch(const gp_Pln& pln, const std::string& base_name)
m_gui.set_mode(Mode::Sketch_inspection_mode);
}

void Occt_view::add_sketch_on_ref_plane(Sketch_ref_plane plane, double offset_display, const std::string& base_name)
{
const gp_Pln pln = sketch_reference_plane(plane, offset_display * get_dimension_scale());
add_sketch(pln, base_name);
}

void Occt_view::curr_sketch_add_edge(double x1, double y1, double x2, double y2)
{
curr_sketch().add_linear_edge(gp_Pnt2d(x1, y1), gp_Pnt2d(x2, y2));
}

void Occt_view::curr_sketch_rebuild_faces() { curr_sketch().rebuild_faces(); }

// Query related
AIS_Shape_ptr Occt_view::get_shape(const ScreenCoords& screen_coords)
{
Expand Down
5 changes: 5 additions & 0 deletions src/gui_occt_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "shp_scale.h"
#include "utl_types.h"
#include "utl_asset_store.h"
#include "utl_geom.h"

class Delta;
class GUI;
Expand Down Expand Up @@ -140,6 +141,10 @@ class Occt_view : protected AIS_ViewController
void remove_sketch(const Sketch_ptr& sketch);
/// Empty sketch on \a pln; \a base_name is uniquified (e.g. Sketch_xy, Sketch_xy.001).
void add_sketch(const gp_Pln& pln, const std::string& base_name);
/// Like add_sketch; \a offset_display is multiplied by get_dimension_scale().
void add_sketch_on_ref_plane(Sketch_ref_plane plane, double offset_display, const std::string& base_name);
void curr_sketch_add_edge(double x1, double y1, double x2, double y2);
void curr_sketch_rebuild_faces();
Sketch& curr_sketch();
Sketch_ptr curr_sketch_shared() const;
/// Non-owning; null when none selected. Does not create a default sketch.
Expand Down
2 changes: 1 addition & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
#include "imgui.h"
#include "imgui_impl_glfw.h"
#include "imgui_impl_opengl3.h"
#include "ui_font.h"
#define GL_SILENCE_DEPRECATION
#if defined(IMGUI_IMPL_OPENGL_ES2)
#include <GLES2/gl2.h>
Expand Down Expand Up @@ -204,6 +203,7 @@ int main(int argc, char** argv)
#endif

// DroidSans at logical px; do not multiply by main_scale - FontScaleDpi applies HiDPI.
constexpr float k_imgui_base_font_size_px = 13.0f;
{
#ifdef __EMSCRIPTEN__
ImFont* font = io.Fonts->AddFontFromFileTTF("/DroidSans.ttf", k_imgui_base_font_size_px);
Expand Down
Loading
Loading