Sample

Schnappinger/aoi/artofillusion.TubeEditorWindow

Human rating uses the original dataset scale.

Human2.07
Lines415

Scores

MethodScoreScaleDataset rank
(0–100)
Posnett00–1; higher is more readable
4.5Δ 3.7
Scalabrino0.290–1; higher is more readable
2.1Δ 6.2
Dorn0.0040–1; higher is more readable
15.2Δ 6.9
Mi0.030–1; higher is more readable
4.6Δ 3.6
LLOC285Logical lines; fewer is more readable
7.6Δ 0.7
DeepSeek V4 Pro120–20; mean of three runs
15.5Δ 7.3
GPT-6.1 Sol120–20; mean of three runs
5.6Δ 2.6
BTTF0.0870–1; higher is more readable
2.3Δ 5.9
Human2.071–4; original rating
8.3

Views

Source code

/* Copyright (C) 2002-2008 by Peter Eastman This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ package artofillusion; import artofillusion.object.*; import artofillusion.texture.*; import artofillusion.ui.*; import buoy.event.*; import buoy.widget.*; import java.awt.*; /** The TubeEditorWindow class represents the window for editing Tube objects. */ public class TubeEditorWindow extends CurveEditorWindow { private BCheckBoxMenuItem endsItem[]; private boolean topology; public TubeEditorWindow(EditingWindow parent, String title, ObjectInfo obj, Runnable onClose, boolean allowTopology) { super(parent, title, obj); this.onClose = onClose; topology = allowTopology; FormContainer content = new FormContainer(new double [] {0, 1}, new double [] {1, 0, 0}); setContent(content); content.setDefaultLayout(new LayoutInfo(LayoutInfo.CENTER, LayoutInfo.BOTH, null, null)); content.add(helpText = new BLabel(), 0, 1, 2, 1); content.add(viewsContainer, 1, 0); RowContainer buttons = new RowContainer(); buttons.add(Translate.button("ok", this, "doOk")); buttons.add(Translate.button("cancel", this, "doCancel")); content.add(buttons, 0, 2, 2, 1, new LayoutInfo()); content.add(tools = new ToolPalette(1, 7), 0, 0, new LayoutInfo(LayoutInfo.NORTH, LayoutInfo.NONE, null, null)); EditingTool metaTool, altTool, compoundTool; tools.addTool(defaultTool = new ReshapeMeshTool(this, this)); tools.addTool(new ScaleMeshTool(this, this)); tools.addTool(new RotateMeshTool(this, this, false)); tools.addTool(new SkewMeshTool(this, this)); tools.addTool(new TaperMeshTool(this, this)); tools.addTool(compoundTool = new MoveScaleRotateMeshTool(this, this)); if (ArtOfIllusion.getPreferences().getUseCompoundMeshTool()) defaultTool = compoundTool; tools.addTool(metaTool = new MoveViewTool(this)); tools.addTool(altTool = new RotateViewTool(this)); tools.setDefaultTool(defaultTool); tools.selectTool(defaultTool); for (int i = 0; i < theView.length; i++) { MeshViewer view = (MeshViewer) theView[i]; view.setMetaTool(metaTool); view.setAltTool(altTool); view.setScene(parent.getScene(), obj); } createEditMenu(); createMeshMenu((Tube) obj.getObject()); createViewMenu(); recursivelyAddListeners(this); UIUtilities.applyDefaultFont(content); UIUtilities.applyDefaultBackground(content); Rectangle screenBounds = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds(); Dimension windowDim = new Dimension((screenBounds.width*3)/4, (screenBounds.height*3)/4); setBounds(new Rectangle((screenBounds.width-windowDim.width)/2, (screenBounds.height-windowDim.height)/2, windowDim.width, windowDim.height)); tools.requestFocus(); selected = new boolean [((Tube) obj.getObject()).getVertices().length]; findSelectionDistance(); updateMenus(); } void createMeshMenu(Tube obj) { meshMenu = Translate.menu("tube"); menubar.add(meshMenu); meshMenuItem = new BMenuItem [8]; meshMenuItem[0] = Translate.menuItem("deletePoints", this, "deleteCommand"); if (topology) meshMenu.add(meshMenuItem[0]); meshMenuItem[1] = Translate.menuItem("subdivide", this, "subdivideCommand"); if (topology) meshMenu.add(meshMenuItem[1]); meshMenu.add(meshMenuItem[2] = Translate.menuItem("editPoints", this, "setPointsCommand")); meshMenu.add(meshMenuItem[3] = Translate.menuItem("transformPoints", this, "transformPointsCommand")); meshMenu.add(meshMenuItem[4] = Translate.menuItem("randomize", this, "randomizeCommand")); meshMenu.add(meshMenuItem[5] = Translate.menuItem("parameters", this, "setParametersCommand")); meshMenu.add(meshMenuItem[6] = Translate.menuItem("thickness", this, "setThicknessCommand")); meshMenu.add(Translate.menuItem("centerTube", this, "centerCommand")); meshMenu.addSeparator(); meshMenu.add(meshMenuItem[7] = Translate.menuItem("smoothness", this, "setSmoothnessCommand")); meshMenu.add(smoothMenu = Translate.menu("smoothingMethod")); smoothItem = new BCheckBoxMenuItem [3]; smoothMenu.add(smoothItem[0] = Translate.checkboxMenuItem("none", this, "smoothingChanged", obj.getSmoothingMethod() == Curve.NO_SMOOTHING)); smoothMenu.add(smoothItem[1] = Translate.checkboxMenuItem("interpolating", this, "smoothingChanged", obj.getSmoothingMethod() == Curve.INTERPOLATING)); smoothMenu.add(smoothItem[2] = Translate.checkboxMenuItem("approximating", this, "smoothingChanged", obj.getSmoothingMethod() == Curve.APPROXIMATING)); endsItem = new BCheckBoxMenuItem [3]; BMenu endsMenu = Translate.menu("endsStyle"); meshMenu.add(endsMenu); endsMenu.add(endsItem[0] = Translate.checkboxMenuItem("openEnds", this, "endsStyleChanged", obj.getEndsStyle() == Tube.OPEN_ENDS)); endsMenu.add(endsItem[1] = Translate.checkboxMenuItem("closedEnds", this, "endsStyleChanged", obj.getEndsStyle() == Tube.CLOSED_ENDS)); endsMenu.add(endsItem[2] = Translate.checkboxMenuItem("flatEnds", this, "endsStyleChanged", obj.getEndsStyle() == Tube.FLAT_ENDS)); } protected BMenu createShowMenu() { BMenu menu = Translate.menu("show"); MeshViewer view = (MeshViewer) theView[currentView]; showItem = new BCheckBoxMenuItem [4]; menu.add(showItem[0] = Translate.checkboxMenuItem("curve", this, "shownItemChanged", view.getMeshVisible())); menu.add(showItem[1] = Translate.checkboxMenuItem("surface", this, "shownItemChanged", view.getSurfaceVisible())); menu.add(showItem[3] = Translate.checkboxMenuItem("entireScene", this, "shownItemChanged", view.getSceneVisible())); return menu; } public void updateMenus() { super.updateMenus(); int i; for (i = 0; i < selected.length && !selected[i]; i++); if (i < selected.length) { editMenuItem[0].setEnabled(true); for (i = 0; i < meshMenuItem.length; i++) meshMenuItem[i].setEnabled(true); } else { editMenuItem[0].setEnabled(false); for (i = 0; i < meshMenuItem.length; i++) meshMenuItem[i].setEnabled(false); } } private void endsStyleChanged(WidgetEvent ev) { Widget source = ev.getWidget(); for (int i = 0; i < endsItem.length; i++) if (source == endsItem[i]) { for (int j = 0; j < endsItem.length; j++) endsItem[j].setState(false); endsItem[i].setState(true); ((Tube) objInfo.getObject()).setEndsStyle(i); objectChanged(); updateImage(); } } protected void doOk() { Tube theMesh = (Tube) objInfo.getObject(); if (((Tube) oldMesh).getMaterial() != null) { if (!theMesh.isClosed()) { String options[] = new String [] {Translate.text("button.ok"), Translate.text("button.cancel")}; BStandardDialog dlg = new BStandardDialog("", UIUtilities.breakString(Translate.text("surfaceNoLongerClosed")), BStandardDialog.WARNING); int choice = dlg.showOptionDialog(this, options, options[0]); if (choice == 1) return; theMesh.setMaterial(null, null); } else theMesh.setMaterial(((Tube) oldMesh).getMaterial(), ((Tube) oldMesh).getMaterialMapping()); } oldMesh.copyObject(theMesh); oldMesh = null; dispose(); onClose.run(); } protected void doCancel() { oldMesh = null; dispose(); } /** Delete the selected vertices. */ public void deleteCommand() { if (!topology) return; int i, j, num = 0; Tube theTube = (Tube) objInfo.getObject(); boolean newsel[]; MeshVertex vt[] = theTube.getVertices(), newv[]; double t[] = theTube.getThickness(), newt[]; float s[] = theTube.getSmoothness(), news[]; for (i = 0; i < selected.length; i++) if (selected[i]) num++; if (num == 0) return; if (theTube.getEndsStyle() != Tube.CLOSED_ENDS && selected.length-num < 2) { new BStandardDialog("", Translate.text("tubeNeeds2Points"), BStandardDialog.INFORMATION).showMessageDialog(this); return; } if (theTube.getEndsStyle() == Tube.CLOSED_ENDS && selected.length-num < 3) { new BStandardDialog("", Translate.text("tubeNeeds3Points"), BStandardDialog.INFORMATION).showMessageDialog(this); return; } setUndoRecord(new UndoRecord(this, false, UndoRecord.COPY_OBJECT, new Object [] {theTube, theTube.duplicate()})); newv = new MeshVertex [vt.length-num]; newt = new double [vt.length-num]; news = new float [vt.length-num]; newsel = new boolean [vt.length-num]; for (i = 0, j = 0; i < vt.length; i++) { if (!selected[i]) { newsel[j] = selected[i]; newt[j] = t[i]; news[j] = s[i]; newv[j++] = vt[i]; } } theTube.setShape(newv, news, newt); setSelection(newsel); objectChanged(); updateImage(); } /** Subdivide the tube between the selected vertices. */ public void subdivideCommand() { Tube theTube = (Tube) objInfo.getObject(); MeshVertex vt[] = theTube.getVertices(), newpos[]; float s[] = theTube.getSmoothness(), news[]; double t[] = theTube.getThickness(), newt[]; int numParam = (theTube.getParameters() == null ? 0 : theTube.getParameters().length); double param[][], newparam[][], paramTemp[] = new double [numParam]; boolean newsel[], split[]; int i, j, p1, p3, p4, splitcount = 0, method = theTube.getSmoothingMethod(); // Record parameter values. param = new double [vt.length][numParam]; ParameterValue paramValue[] = theTube.getParameterValues(); for (i = 0; i < numParam; i++) { if (paramValue[i] instanceof VertexParameterValue) { double val[] = ((VertexParameterValue) paramValue[i]).getValue(); for (j = 0; j < val.length; j++) param[j][i] = val[j]; } } // Determine which parts need to be subdivided. if (theTube.getEndsStyle() == Tube.CLOSED_ENDS) split = new boolean [vt.length]; else split = new boolean [vt.length-1]; for (i = 0; i < split.length; i++) if (selected[i] && selected[(i+1)%selected.length]) { split[i] = true; splitcount++; } newpos = new MeshVertex [vt.length+splitcount]; news = new float [vt.length+splitcount]; newt = new double [vt.length+splitcount]; newparam = new double [vt.length+splitcount][numParam]; newsel = new boolean [vt.length+splitcount]; // Do the subdivision. for (i = 0, j = 0; i < split.length; i++) { newsel[j] = selected[i]; p1 = i-1; if (p1 < 0) { if (theTube.getEndsStyle() == Tube.CLOSED_ENDS) p1 = vt.length-1; else p1 = 0; } if (i < vt.length-1) p3 = i+1; else { if (theTube.getEndsStyle() == Tube.CLOSED_ENDS) p3 = 0; else p3 = vt.length-1; } if (selected[i] && method == Mesh.APPROXIMATING) { newpos[j] = SplineMesh.calcApproxPoint(vt, s, param, paramTemp, p1, i, p3); newt[j] = Tube.calcApproxThickness(t, s, p1, i, p3); for (int k = 0; k < numParam; k++) newparam[j][k] = paramTemp[k]; } else { newpos[j] = vt[i]; newt[j] = t[i]; newparam[j] = param[i]; } if (selected[i]) news[j] = Math.min(s[i]*2.0f, 1.0f); else news[j] = s[i]; if (!split[i]) { j++; continue; } if (method == Mesh.NO_SMOOTHING) { newpos[j+1] = MeshVertex.blend(vt[i], vt[p3], 0.5, 0.5); for (int k = 0; k < numParam; k++) newparam[j+1][k] = 0.5*(param[i][k]+param[p3][k]); } else if (method == Mesh.INTERPOLATING) { if (i < vt.length-2) p4 = i+2; else { if (theTube.getEndsStyle() == Tube.CLOSED_ENDS) p4 = (i+2)%vt.length; else p4 = vt.length-1; } newpos[j+1] = SplineMesh.calcInterpPoint(vt, s, param, paramTemp, p1, i, p3, p4); newt[j+1] = Tube.calcInterpThickness(t, s, p1, i, p3, p4); for (int k = 0; k < numParam; k++) newparam[j+1][k] = paramTemp[k]; } else { newpos[j+1] = MeshVertex.blend(vt[i], vt[p3], 0.5, 0.5); newt[j+1] = 0.5*(t[i]+t[p3]); for (int k = 0; k < numParam; k++) newparam[j+1][k] = 0.5*(param[i][k]+param[p3][k]); } news[j+1] = 1.0f; newsel[j+1] = true; j += 2; } if (theTube.getEndsStyle() != Tube.CLOSED_ENDS) { newpos[0] = vt[0]; newpos[j] = vt[i]; newt[0] = t[0]; newt[j] = t[i]; news[j] = s[i]; newparam[0] = param[0]; newparam[j] = param[i]; newsel[j] = selected[i]; } setUndoRecord(new UndoRecord(this, false, UndoRecord.COPY_OBJECT, new Object [] {theTube, theTube.duplicate()})); theTube.setShape(newpos, news, newt); for (i = 0; i < numParam; i++) { if (paramValue[i] instanceof VertexParameterValue) { double val[] = new double [newpos.length]; for (j = 0; j < val.length; j++) val[j] = newparam[j][i]; paramValue[i] = new VertexParameterValue(val); } } theTube.setParameterValues(paramValue); setSelection(newsel); objectChanged(); updateImage(); } /** Allow the user to set the thickness for selected vertices. */ public void setThicknessCommand() { Tube theTube = (Tube) objInfo.getObject(); double thickness[] = theTube.getThickness(), initial = -1; int selectDist[] = getSelectionDistance(); for (int i = 0; i < selectDist.length; i++) if (selectDist[i] == 0) { if (initial == -1) initial = thickness[i]; else if (initial != thickness[i]) initial = Double.NaN; } if (initial == -1) return; // No selected vertices. ValueField thicknessField = new ValueField(initial, ValueField.NONNEGATIVE, 5); ComponentsDialog dlg = new ComponentsDialog(this, Translate.text("setThicknessTitle"), new Widget [] {thicknessField}, new String [] {Translate.text("Thickness")}); if (!dlg.clickedOk() || Double.isNaN(thicknessField.getValue())) return; setUndoRecord(new UndoRecord(this, false, UndoRecord.COPY_OBJECT, new Object [] {theTube, theTube.duplicate()})); for (int i = 0; i < selectDist.length; i++) if (selectDist[i] == 0) thickness[i] = thicknessField.getValue(); theTube.setThickness(thickness); objectChanged(); updateImage(); } }

Loading feature diagnosis…

Source regions

Feature contributions

Feature contributions

FeatureValueContribution
(log-odds)
Halstead volumeHow much symbolic information the code contains. It combines the total number of operators and values with the number of distinct ones.29586.846−976.366
Source linesThe number of non-empty source lines.415+166
Byte entropyHow varied the bytes in the source text are. Repeated bytes give a lower value; a more even mixture gives a higher value.4.955−7.433

Intercept 8.87 + feature contributions = -808.929 (log-odds).
Score = sigmoid(-808.929) = 0.

Score0.29

Feature contributions

FeatureValueContribution
(log-odds)
Comment layout frequencyHow frequently the layout switches between lines containing only comments or whitespace and lines containing code.415−13.658
Indentation frequencyHow rapidly indentation changes from line to line.403+13.202
Number layout frequencyHow rapidly the number of numeric values per line changes through the code.403−8.827
Identifier layout (vertical)How rapidly the visual pattern of identifier characters changes from top to bottom.413.929+5.376
Identifier layout (horizontal)How rapidly the visual pattern of identifier characters changes from left to right. It measures spatial frequency, not the meaning of the names.154.971−2.899
Comment layout (horizontal)How rapidly the visual pattern of comment characters changes from left to right.154.993+1.696
Operator visual areaThe share of the code’s visual area occupied by operators such as +, =, and *.0.142−0.433

Intercept 0.07 + feature contributions = -5.472 (log-odds).
Score = sigmoid(-5.472) = 0.004.

Score0.03
Score285
Run 1

The code has some clear structure and consistent naming, but readability suffers from multiple issues. The constructor is very long and mixes UI setup, tool creation, and initialization, making it hard to follow. Deeply nested conditionals appear in methods like subdivideCommand and deleteCommand, with complex index arithmetic and branching logic. Variable names like p1, p3, p4 and split are cryptic without context. Several methods contain multiple actions per line and dense array manipulation that obscures intent. The createMeshMenu method has repetitive menu-item creation with manual array indexing, and magic numbers for array sizes reduce clarity. While comments exist, they don't offset the heavy procedural complexity. The reading flow is disrupted by long methods and tangled state management, though some separation of concerns is present through method extraction. Overall, the code is functional but difficult to read and maintain.

Run 2

The code has clear structure with well-named methods representing distinct UI commands, good use of helper methods, and consistent formatting. However, readability suffers in several areas: deeply nested conditionals (especially in subdivideCommand with up to 4 levels), long methods that mix UI setup with business logic, multiple operations per line in places, and heavy use of array indexing that obscures intent. The constructor is very long, combining layout, tool initialization, and dialog setup. Complex math operations like SplineMesh.calcApproxPoint lack explanatory comments. Variable names are sometimes unclear (p1, p3, p4). While the code follows consistent conventions and has good separation between menu creation methods, the overall flow is somewhat tangled due to the density of operations and nesting depth.

Run 3

The code shows reasonable organization with clear method separation and some useful comments explaining complex algorithms. However, it suffers from significant readability issues. Methods like `subdivideCommand()` and `deleteCommand()` are extremely long (60+ lines) and contain deeply nested conditional logic, making them hard to follow. The constructor is bloated with UI setup code mixing multiple concerns. While variable names are mostly descriptive, there are cryptic ones like `p1`, `p3`, `p4`, `t[]`, `s[]`, and `vt[]` that require domain knowledge. The code frequently chains multiple operations per line (e.g., `meshMenu.add(meshMenuItem[0] = Translate.menuItem(...))`), violating the one-action-per-line principle. Some duplication exists between `deleteCommand()` and `subdivideCommand()` that could be refactored. The reading flow is disrupted by large blocks of array indexing and conditional statements. Overall, the code is functional but would benefit from method extraction, reduced nesting, and more consistent formatting.

Run 1

Code Structure: Methods separate UI setup, menu handling, and editing commands logically, but the constructor and subdivision method combine too many responsibilities. Nesting: Most methods are shallow, while subdivision contains several nested loops and conditional branches that require careful tracking. Clarity of intent: Method names and section comments explain major operations, but abbreviated variables such as vt, s, t, p1, and newt, plus numeric menu indices, obscure details. Code length: Repetitive menu construction and lengthy subdivision logic could be shortened through helper methods. Action granularity: Most statements occupy individual lines, but assignments inside method calls, grouped declarations, and incrementing indices during assignment combine actions. Reading flow: Consistent formatting and sequential setup help navigation; the empty-body selection loop, omitted braces, reused indices, and parallel-array updates interrupt otherwise natural flow.

Run 2

Code Structure: Methods separate UI setup and editing commands logically, but the constructor and subdivision method combine many responsibilities. Nesting: Most methods are shallow; subdivision contains several nested loops and conditionals that complicate tracing. Clarity of intent: Descriptive method names and section comments explain overall purposes, but abbreviated variables, numeric menu indexes, and implicit inherited state obscure details. Code length: UI boilerplate is understandable, yet repeated menu setup, array copying, and boundary handling make the code lengthy and suggest opportunities for helper methods. Action granularity: Most statements occupy individual lines, but assignments embedded in method arguments, grouped declarations, and index increments mixed with assignments combine actions. Reading flow: Method ordering and subdivision phase comments provide a coherent progression, while long lines, inconsistent indentation, omitted braces, and an empty-body selection-search loop interrupt readability.

Run 3

Code Structure: Methods separate UI setup, menu handling, and editing commands logically, but the constructor and subdivision routine combine many responsibilities. Nesting: Most handlers are shallow, while subdivision contains several nested loops and conditionals that increase tracking effort. Clarity of intent: Descriptive method names and section comments explain the overall purpose; abbreviated variables, numeric menu indices, and inherited state obscure details. Code length: UI boilerplate is understandable, but repeated array copying, menu configuration, and boundary handling make some methods unnecessarily long. Action granularity: Most statements occupy separate lines, although assignment within method arguments, grouped declarations, and index increments embedded in assignments combine actions. Reading flow: Consistent method organization and comments support navigation, but long lines, omitted braces, an empty-body selection loop, and parallel arrays interrupt otherwise natural flow.