Sample

Schnappinger/aoi/artofillusion.RotateObjectTool

Human rating uses the original dataset scale.

Human2.01
Lines313

Scores

MethodScoreScaleDataset rank
(0–100)
Posnett00–1; higher is more readable
14.0Δ 8.1
Scalabrino0.5050–1; higher is more readable
9.9Δ 4.0
Dorn0.010–1; higher is more readable
20.1Δ 14.2
Mi0.7270–1; higher is more readable
87.1Δ 81.2
LLOC191Logical lines; fewer is more readable
13.7Δ 7.8
DeepSeek V4 Pro13.670–20; mean of three runs
26.9Δ 21.0
GPT-6.1 Sol140–20; mean of three runs
16.2Δ 10.2
BTTF0.1110–1; higher is more readable
3.3Δ 2.6
Human2.011–4; original rating
5.9

Views

Source code

/* Copyright (C) 1999-2007 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.math.*; import artofillusion.object.*; import artofillusion.ui.*; import buoy.event.*; import buoy.widget.*; import java.awt.*; import java.util.Vector; /** RotateObjectTool is an EditingTool used for rotating objects in a scene. */ public class RotateObjectTool extends EditingTool { static final int X_ONLY = 1; static final int Y_ONLY = 2; static final int Z_ONLY = 3; static final int ALL_AXES = 4; static final int OBJECT_CENTER = 0; static final int PARENT_CENTER = 1; static final int SELECTION_CENTER = 2; static final double DRAG_SCALE = Math.PI/360.0; Point clickPoint; Vector<ObjectInfo> toMove; ObjectInfo clickedObject; int whichAxes, rotateAround = PARENT_CENTER; boolean dragged, applyToChildren = true; Vec3 rotAxis, rotationCenter[]; CoordinateSystem objectCoords[]; public RotateObjectTool(EditingWindow fr) { super(fr); initButton("rotate"); } public void activate() { super.activate(); theWindow.setHelpText(Translate.text("rotateObjectTool.helpText")); } public int whichClicks() { return OBJECT_CLICKS+HANDLE_CLICKS; } public boolean allowSelectionChanges() { return true; } public String getToolTipText() { return Translate.text("rotateObjectTool.tipText"); } public void mousePressedOnObject(WidgetMouseEvent e, ViewerCanvas view, int obj) { Scene theScene = theWindow.getScene(); int i, numSelected = 0, sel[]; Vec3 center = new Vec3(); toMove = new Vector<ObjectInfo>(); clickedObject = theScene.getObject(obj); if (applyToChildren) sel = theScene.getSelectionWithChildren(); else sel = theScene.getSelection(); for (i = 0; i < sel.length; i++) toMove.addElement(theScene.getObject(sel[i])); objectCoords = new CoordinateSystem [toMove.size()]; rotationCenter = new Vec3 [toMove.size()]; for (i = 0; i < objectCoords.length; i++) { ObjectInfo info = (ObjectInfo) toMove.elementAt(i), parent = info; objectCoords[i] = info.getCoords().duplicate(); if (rotateAround == SELECTION_CENTER) { rotationCenter[i] = center; if (info.selected) { center.add(info.getCoords().getOrigin()); numSelected++; } } else rotationCenter[i] = info.getCoords().getOrigin(); if (rotateAround == PARENT_CENTER) while (parent.getParent() != null) { parent = parent.getParent(); if (parent.selected) rotationCenter[i] = parent.getCoords().getOrigin(); } } if (numSelected > 0) center.scale(1.0/numSelected); clickPoint = e.getPoint(); dragged = false; whichAxes = ALL_AXES; } public void mousePressedOnHandle(WidgetMouseEvent e, ViewerCanvas view, int obj, int handle) { mousePressedOnObject(e, view, obj); if (handle == 1 || handle == 6) { whichAxes = X_ONLY; rotAxis = new Vec3(1.0, 0.0, 0.0); } else if (handle == 3 || handle == 4) { whichAxes = Y_ONLY; rotAxis = new Vec3(0.0, -1.0, 0.0); } else { whichAxes = Z_ONLY; if (handle < 4) rotAxis = new Vec3(0.0, 0.0, 1.0); else rotAxis = new Vec3(0.0, 0.0, -1.0); } rotAxis = view.getCamera().getViewToWorld().timesDirection(rotAxis); } public void mouseDragged(final WidgetMouseEvent e, final ViewerCanvas view) { Point dragPoint = e.getPoint(); CoordinateSystem c; UndoRecord undo; double angle; int i; Vec3 origin; Mat4 rotMatrix; if (!dragged) { theWindow.setUndoRecord(undo = new UndoRecord(theWindow, false)); for (i = 0; i < toMove.size(); i++) { ObjectInfo info = (ObjectInfo) toMove.elementAt(i); c = info.getCoords(); undo.addCommand(UndoRecord.COPY_COORDS, new Object [] {c, c.duplicate()}); } dragged = true; } if (whichAxes == X_ONLY) angle = (clickPoint.y-dragPoint.y)*DRAG_SCALE; else if (whichAxes == Y_ONLY) angle = (clickPoint.x-dragPoint.x)*DRAG_SCALE; else if (whichAxes == Z_ONLY) angle = (dragPoint.x-clickPoint.x)*DRAG_SCALE; else { rotAxis = new Vec3((clickPoint.y-dragPoint.y)*DRAG_SCALE, (dragPoint.x-clickPoint.x)*DRAG_SCALE, 0.0); angle = rotAxis.length(); rotAxis = rotAxis.times(1.0/angle); rotAxis = view.getCamera().getViewToWorld().timesDirection(rotAxis); } if (angle != 0.0) { for (i = 0; i < toMove.size(); i++) { ObjectInfo info = (ObjectInfo) toMove.elementAt(i); c = info.getCoords(); origin = rotationCenter[i]; rotMatrix = Mat4.translation(origin.x, origin.y, origin.z).times(Mat4.axisRotation(rotAxis, angle)).times(Mat4.translation(-origin.x, -origin.y, -origin.z)); c.copyCoords(objectCoords[i]); c.transformCoordinates(rotMatrix); } } theWindow.setModified(); theWindow.updateImage(); theWindow.setHelpText(Translate.text("rotateMeshTool.dragText", Double.toString(Math.round(angle*1e5*180.0/Math.PI)/1e5))); } public void mouseReleased(WidgetMouseEvent e, ViewerCanvas view) { theWindow.getScene().applyTracksAfterModification(toMove); theWindow.setHelpText(Translate.text("rotateObjectTool.helpText")); toMove = null; objectCoords = null; rotationCenter = null; theWindow.updateImage(); } public void keyPressed(KeyPressedEvent e, ViewerCanvas view) { Scene theScene = theWindow.getScene(); CoordinateSystem c; UndoRecord undo; Vec3 origin, center = new Vec3(); Mat4 rotMatrix; int key = e.getKeyCode(), numSelected = 0, sel[]; // Find the axis to rotate around. if (e.isControlDown()) { if (key == KeyPressedEvent.VK_UP || key == KeyPressedEvent.VK_RIGHT) rotAxis = new Vec3(0.0, 0.0, 1.0); else if (key == KeyPressedEvent.VK_DOWN || key == KeyPressedEvent.VK_LEFT) rotAxis = new Vec3(0.0, 0.0, -1.0); else return; } else if (key == KeyPressedEvent.VK_UP) rotAxis = new Vec3(1.0, 0.0, 0.0); else if (key == KeyPressedEvent.VK_DOWN) rotAxis = new Vec3(-1.0, 0.0, 0.0); else if (key == KeyPressedEvent.VK_LEFT) rotAxis = new Vec3(0.0, -1.0, 0.0); else if (key == KeyPressedEvent.VK_RIGHT) rotAxis = new Vec3(0.0, 1.0, 0.0); else return; e.consume(); rotAxis = view.getCamera().getViewToWorld().timesDirection(rotAxis); // Find the rotation center for every object. if (applyToChildren) sel = theScene.getSelectionWithChildren(); else sel = theScene.getSelection(); toMove = new Vector<ObjectInfo>(); for (int i = 0; i < sel.length; i++) toMove.addElement(theScene.getObject(sel[i])); rotationCenter = new Vec3 [toMove.size()]; for (int i = 0; i < rotationCenter.length; i++) { ObjectInfo info = (ObjectInfo) toMove.elementAt(i), parent = info; if (rotateAround == SELECTION_CENTER) { rotationCenter[i] = center; if (info.selected) { center.add(info.getCoords().getOrigin()); numSelected++; } } else rotationCenter[i] = info.getCoords().getOrigin(); if (rotateAround == PARENT_CENTER) while (parent.getParent() != null) { parent = parent.getParent(); if (parent.selected) rotationCenter[i] = parent.getCoords().getOrigin(); } } if (numSelected > 0) center.scale(1.0/numSelected); // Rotate every object by 0.5 degrees. theWindow.setUndoRecord(undo = new UndoRecord(theWindow, false)); double angle = DRAG_SCALE; if (e.isAltDown()) angle *= 10.0; for (int i = 0; i < toMove.size(); i++) { ObjectInfo info = (ObjectInfo) toMove.elementAt(i); c = info.getCoords(); origin = rotationCenter[i]; rotMatrix = Mat4.translation(origin.x, origin.y, origin.z).times(Mat4.axisRotation(rotAxis, angle)).times(Mat4.translation(-origin.x, -origin.y, -origin.z)); undo.addCommand(UndoRecord.COPY_COORDS, new Object [] {c, c.duplicate()}); c.transformCoordinates(rotMatrix); } theWindow.getScene().applyTracksAfterModification(toMove); theWindow.updateImage(); theWindow.setHelpText(Translate.text("rotateObjectTool.helpText")); toMove = null; rotationCenter = null; } /* Allow the user to set options. */ public void iconDoubleClicked() { BCheckBox childrenBox = new BCheckBox(Translate.text("applyToUnselectedChildren"), applyToChildren); BComboBox centerChoice = new BComboBox(new String [] { Translate.text("individualObjectCenters"), Translate.text("parentObject"), Translate.text("centerOfSelection") }); centerChoice.setSelectedIndex(rotateAround); RowContainer row = new RowContainer(); row.add(Translate.label("rotateAround")); row.add(centerChoice); ComponentsDialog dlg = new ComponentsDialog(theFrame, Translate.text("rotateToolTitle"), new Widget [] {childrenBox, row}, new String [] {null, null}); if (!dlg.clickedOk()) return; applyToChildren = childrenBox.getState(); rotateAround = centerChoice.getSelectedIndex(); } }

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.15419.12−508.831
Source linesThe number of non-empty source lines.313+125.2
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.867−7.3

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

Score0.505

Feature contributions

FeatureValueContribution
(log-odds)
Comment layout frequencyHow frequently the layout switches between lines containing only comments or whitespace and lines containing code.313−10.046
Indentation frequencyHow rapidly indentation changes from line to line.302+9.709
Number layout frequencyHow rapidly the number of numeric values per line changes through the code.302−6.509
Identifier layout (vertical)How rapidly the visual pattern of identifier characters changes from top to bottom.311.753+3.948
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.168.968−3.492
Comment layout (horizontal)How rapidly the visual pattern of comment characters changes from left to right.168.997+1.922
Operator visual areaThe share of the code’s visual area occupied by operators such as +, =, and *.0.116−0.187

Intercept 0.07 + feature contributions = -4.585 (log-odds).
Score = sigmoid(-4.585) = 0.01.

Score0.727
Score191
Run 1

The code has clear structure with logical method organization and good naming, but suffers from several readability issues. Deep nesting appears in mouseDragged and keyPressed methods with multiple nested if-else blocks and loops. The intent is generally clear from method names and comments, though complex rotation logic could benefit from more explanation. Code length is moderate but some methods like mouseDragged and keyPressed are overly long. Action granularity is inconsistent - some lines combine multiple operations while others are well-separated. Reading flow is disrupted by long nested blocks and complex mathematical operations that could be extracted into helper methods. The rotation center calculation logic is duplicated in mousePressedOnObject and keyPressed, indicating opportunities for refactoring. Variable declarations at method tops are old-style and don't aid readability. The code is functional but would benefit from extracting helper methods and reducing nesting depth.

Run 2

The code is moderately readable but has several issues. The class structure is logical with clear method separation, and constants are well-named. However, there are significant problems: deeply nested conditional blocks in mouseDragged and keyPressed methods make the logic hard to follow. Multiple actions are crammed into single lines (especially in loops and method calls), reducing clarity. Variable declarations are scattered (e.g., 'c' and 'undo' declared at top but used much later). The mouseDragged method has complex rotation logic buried in nested if-else chains. Some methods like mousePressedOnObject and keyPressed duplicate the same rotation-center calculation code, indicating poor abstraction. Comments are sparse and the action granularity is inconsistent. The code would benefit from extracting smaller helper methods and breaking up compound statements.

Run 3

The code is generally clear but has several readability issues. The class structure and method organization are logical, and the intent is mostly clear. However, methods like mousePressedOnObject and mouseDragged are long with multiple mixed responsibilities, reducing clarity. There is duplicated logic between mousePressedOnObject and keyPressed for computing rotation centers, which could be extracted into a helper. Some lines are dense, combining variable declarations with assignments and side effects (e.g., 'ObjectInfo info = (ObjectInfo) toMove.elementAt(i), parent = info;'). Nesting is moderate but repeated within loops. Action granularity is inconsistent; some lines perform multiple operations. The reading flow is natural in some parts but disrupted by verbose matrix calculations and inlined logic. Comments are minimal and could better explain complex transformations. Overall, the code is understandable for an experienced developer but would benefit from refactoring to reduce duplication and improve modularity.

Run 1

Code Structure: Event-handler methods organize responsibilities logically, but rotation-center calculation is duplicated and longer handlers mix selection, undo, and transformation logic. Nesting: Generally moderate, with deeper conditional and loop combinations in center calculation requiring extra attention. Clarity of intent: Descriptive method names, named constants, and section comments communicate purpose; abbreviated variables, numeric handle mappings, and shared mutable state obscure details. Code length: Reasonable for the functionality, but duplicated setup and transformation logic could be extracted into helpers. Action granularity: Most statements perform one action, though assignment inside method calls, combined declarations, and long matrix-expression chains reduce clarity. Reading flow: Lifecycle ordering is natural and formatting mostly consistent, but long lines, occasional indentation inconsistencies, and subtle shared-center references interrupt comprehension.

Run 2

Code Structure: Event handlers provide logical organization, but selection and rotation-center calculations are duplicated rather than extracted into helpers. Nesting: Generally moderate, with deeper conditional and parent-traversal nesting making some sections harder to follow. Clarity of intent: Descriptive handler names, axis constants, and section comments communicate the purpose well; abbreviated variables, numeric handle mappings, and shared mutable state require extra interpretation. Code length: Reasonable for the functionality, but duplicated logic and long matrix expressions add avoidable bulk. Action granularity: Most lines perform one action, although combined declarations, assignment within method calls, and chained matrix operations reduce clarity. Reading flow: Interaction proceeds naturally from press through drag and release, and keyboard handling has useful section comments. However, inconsistent indentation, omitted braces, and dense expressions interrupt otherwise coherent flow.

Run 3

Code Structure: Event-handler methods organize responsibilities logically, but rotation-center calculation is duplicated and larger handlers mix selection, geometry, undo, and UI updates. Nesting: Mostly moderate, with deeper loop/conditional combinations in center calculation and parent traversal. Clarity of intent: Descriptive method names, axis constants, and section comments explain the tool well; terse variables, numeric handle mappings, shared mutable state, and dense matrix expressions require extra interpretation. Code length: Reasonable for the functionality, though duplicated logic and repetitive axis branches could be extracted into helpers. Action granularity: Most statements perform one action per line, but combined declarations, assignment within method calls, and chained transformations reduce clarity. Reading flow: The press-drag-release lifecycle and keyboard sections are natural to follow; inconsistent indentation, omitted braces, and long expressions interrupt otherwise coherent flow.