Release MaxMath 1.1.1 3D plotting improvements - #5
Merged
Conversation
3D/contour rendering ran the AST interpreter 14,400 times per plot and allocated roughly 45 matrices per frame on the GL thread, and the plot carried no numeric scale at all -- three fixed lines that matched no data value. Dragging a contour only moved a mesh built once over the original range, so you could drag off the edge into blank space. Performance - CompiledExpr compiles the AST once into positional-slot nodes: no string parsing, no boxed map lookups, no per-call List. MathFunctions is the single source for the unary formulas so Evaluator and CompiledExpr cannot diverge; Evaluator stays as the readable reference and the parity target. - Contour marching is cell-major with level pruning: ~141,610 cell visits become ~14,161. - Mat4 works in place; the renderer builds the camera once per frame and caches the projection. Blend is enabled only around the contour heatmap, the only geometry with alpha < 1. Presentation - Contour pan/zoom is folded back into a data range on release and the mesh is re-evaluated there. 3D zoom raises grid density instead, holding the range fixed -- rotating something whose axes silently rescale is disorienting. - Both modes draw a bounding box at the data bounds with tick marks and numeric labels, sharing PlotTicks with the 2D canvas so the same function shows the same ticks in either mode. Labels render through a GL glyph atlas so they appear in the glReadPixels PNG export. Defects found in review - resample no longer shares a Job with regenerate. Tapping Plot and then dragging before the build finished cancelled the redraw on a path that never clears `loading`, stranding the progress spinner. - 2D zero/extremum labels use the new PlotTicks.formatValue (4 significant digits); routing them through the tick formatter printed a root at 0.000123 as 0.0001. Both formatters pin Locale.ROOT, which "%.4g" did not. - 3D zoom was applied twice -- model scale and camera dolly -- so a 2x pinch magnified 4x and the box's nearest corner crossed the near plane at zoom ~1.7, inside the 8x gesture range. Zoom is now applied once by narrowing the field of view with the camera fixed, and near/far come from the content radius (3.10..7.61 instead of 0.1..100). - CompiledExprTest iterated a hand-copied function-name list, so a name added to the parser was never checked. It now iterates the real MathParser.FUNCTION_NAMES. Structure - PlotGlModels.kt holds the model matrices formerly on the renderer companion; PlotGlRendererTest becomes PlotGlModelsTest. - GlyphMetrics splits the pure vertex layout out of GlyphAtlas's GL upload, which is what makes it testable at all. Note: contour segments now come out cell-major rather than level-major. They are drawn as independent GL_LINES in one colour, so the image is identical, but it is an observable array-order change. Verification: this has NOT been compiled -- there is no JDK or Android SDK on this machine, so CI is the first compiler. Node cross-checks confirm the new projection magnifies linearly in zoom (2.8e-16 deviation) and that no point at the content radius crosses near or far at any zoom, that the contour range inverse round-trips to 1.7e-8 px, and that in-place translate and scale are bit-identical to the allocating originals. The new unit tests are the real gate. Known limitation: in portrait the horizontal field of view contains only radius ~1.0-1.2 at zoom 1 while the axis geometry reaches 2.03, so corner labels can sit off-screen. Pre-existing framing behaviour, but the new labels make it matter; fixing it trades plot size for label visibility and needs a separate decision. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The previous commit's "known limitation" was wrong, and so was the KDoc on EYE_DISTANCE. Both claimed that in portrait the horizontal field of view is too narrow and corner labels fall off-screen. That reasoning assumed the GL surface fills a portrait screen (aspect ~0.5). It does not: PlotScreen wraps it in fillMaxWidth().aspectRatio(Sizing.PLOT_ASPECT) with PLOT_ASPECT = 3/2, so the aspect is 1.5 regardless of device orientation. Recomputed with the real geometry and real rotations rather than a bounding sphere: at aspect 1.5 the worst orientation needs eye distance 5.11 against the 5.36 in use, and the worst |ndc| over 64,800 orientations is 0.939. Everything is framed, at every orientation. There is nothing to fix. The actual defect was that this was verified by hand, so: - PlotGlCamera holds FOV, CONTENT_RADIUS, EYE_DISTANCE, NEAR/FAR and fovForZoom, out of the renderer's companion where nothing could reach them. - PlotGlCameraTest projects every PlotGlAxes vertex and label anchor through the real Mat4 pipeline at Sizing.PLOT_ASPECT across azimuth 0..360 and elevation 0..180, asserting |ndc| <= 1 and w > 0. It also pins that nothing crosses near/far at any zoom, that magnification is proportional to zoom, and that fovForZoom survives zoom = 0. The test imports Sizing.PLOT_ASPECT rather than hardcoding 1.5, so changing the plot area's aspect ratio now fails the framing test instead of silently cropping the axes. Not compiled -- no JDK or Android SDK here. The Node cross-check that produced the numbers above is the only thing that has actually run. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ParuhParhat
marked this pull request as ready for review
August 8, 2026 15:23
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary / 摘要
Release MaxMath 1.1.1 with a substantially leaner 3D/contour rendering path, data-aware gesture resampling, and visible numeric axes.
发布 MaxMath 1.1.1:优化 3D/等高线渲染热路径,加入跟随数据范围的手势重采样,并显示完整数值坐标轴。
What changed / 改动
Added
CompiledExpr, which compiles the parsed AST once into positional-slot nodes for 3D and contour grid evaluation.Reworked contour marching to traverse cells once and prune levels outside each cell's value range.
Added in-place matrix operations, cached camera/projection work, and limited blending to the translucent heatmap pass.
Re-evaluates contour meshes over the transformed data range after pan/zoom; 3D zoom keeps the range fixed and increases grid density.
Added bounding boxes, tick marks, and numeric labels to 3D and contour plots using shared
PlotTickslogic and a GL glyph atlas, so labels are included in PNG exports.Fixed stuck loading state during overlapping redraws, double-applied 3D zoom, near/far clipping, and precision loss in small 2D root labels.
Added parity, tick, gesture, matrix, mesh, axes, glyph-layout, and full-rotation camera-framing tests.
Bumped the app to 1.1.1 (
versionCode 17) and updated both README languages and release notes.新增
CompiledExpr,将解析后的 AST 一次编译为定长变量槽位,用于 3D/等高线网格求值。等高线遍历改为按单元执行,并跳过超出单元值域的等值层级。
加入原地矩阵运算、相机/投影缓存,并只在半透明热力图阶段启用混合。
等高线平移/缩放结束后按变换后的数据范围重新采样;3D 放大保持范围不变并提高网格密度。
3D 与等高线新增边界框、刻度及数值标签,共用
PlotTicks并通过 GL 字形图集绘制,因此 PNG 导出也保留标签。修复重绘竞争导致加载状态卡住、3D 双重缩放、近远裁剪及小数零点标签精度问题。
新增表达式一致性、刻度、手势、矩阵、网格、坐标轴、字形布局和全旋转相机取景测试。
版本更新为 1.1.1(
versionCode 17),同步中英文 README 与发布记录。Why / 原因
The previous 3D path interpreted the AST at every sample, allocated avoidable matrices on the GL thread, and showed only fixed axis lines without numeric scale. Contour gestures transformed a mesh sampled over the original range, so panning could expose blank space. Several redraw and camera issues were found while making the new axes testable.
旧 3D 路径会在每个采样点重复解释 AST,并在 GL 线程分配不必要的矩阵;坐标轴也只有固定线条而没有数值尺度。等高线手势只变换原始范围生成的网格,拖动后可能露出空白。为新坐标轴建立测试时还发现了多项重绘与相机问题,本次一并修复。
These are structural performance improvements; no device benchmark claim is made in this PR.
这些属于结构性性能优化,本 PR 不宣称尚未实测的设备端性能数字。
Validation / 验证
git diff --check origin/main..HEADpassed.1598528F39F3BC814540DA5968B4115C6453F77ECE2DC68BB8700AC50DC33CAF.assembleDebug, and Android lint for this PR.