Sample

Schnappinger/aoi/artofillusion.animation.FilterParameterTrack

Human rating uses the original dataset scale.

Human2.99
Lines409

Scores

MethodScoreScaleDataset rank
(0–100)
Posnett00–1; higher is more readable
12.4Δ 12.0
Scalabrino0.80–1; higher is more readable
62.0Δ 37.6
Dorn0.0140–1; higher is more readable
22.1Δ 2.3
Mi0.6830–1; higher is more readable
79.2Δ 54.8
LLOC208Logical lines; fewer is more readable
12.5Δ 11.9
DeepSeek V4 Pro170–20; mean of three runs
66.8Δ 42.4
GPT-6.1 Sol160–20; mean of three runs
38.9Δ 14.5
BTTF0.1440–1; higher is more readable
6.3Δ 18.2
Human2.991–4; original rating
24.4

Views

Source code

/* Copyright (C) 2003-2009 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.animation; import artofillusion.*; import artofillusion.math.*; import artofillusion.image.filter.*; import artofillusion.ui.*; import buoy.event.*; import buoy.widget.*; import java.io.*; import java.util.*; /** This is a Track which allows the parameters of an ImageFilter to be keyframed. */ public class FilterParameterTrack extends Track { private Object parent; private ImageFilter filter; private Timecourse tc; private int smoothingMethod; /** Create a new FilterParameterTrack. */ public FilterParameterTrack(Object parent, ImageFilter filter) { super(filter.getName()); this.parent = parent; this.filter = filter; tc = new Timecourse(new Keyframe [0], new double [0], new Smoothness [0]); smoothingMethod = Timecourse.INTERPOLATING; } /** Get the filter corresponding to this track. */ public ImageFilter getFilter() { return filter; } /** Modify the pose of the object. */ public void apply(double time) { ArrayKeyframe k = (ArrayKeyframe) tc.evaluate(time, smoothingMethod); if (k == null) return; int index = 0; Property[] properties = filter.getProperties(); for (int i = 0; i < properties.length; i++) { if (properties[i].getType() == Property.DOUBLE) filter.setPropertyValue(i, k.val[index++]); else if (properties[i].getType() == Property.COLOR) filter.setPropertyValue(i, new RGBColor(k.val[index++], k.val[index++], k.val[index++])); } } /** Create a duplicate of this track. */ public Track duplicate(Object obj) { FilterParameterTrack t = new FilterParameterTrack(obj, filter); t.name = name; t.enabled = enabled; t.quantized = quantized; t.smoothingMethod = smoothingMethod; t.tc = tc.duplicate(filter); return t; } /** Make this track identical to another one. */ public void copy(Track tr) { FilterParameterTrack t = (FilterParameterTrack) tr; name = t.name; enabled = t.enabled; quantized = t.quantized; smoothingMethod = t.smoothingMethod; tc = t.tc.duplicate(filter); } /** Get a list of all keyframe times for this track. */ public double [] getKeyTimes() { return tc.getTimes(); } /** Get the timecourse describing this track. */ public Timecourse getTimecourse() { return tc; } /** Set a keyframe at the specified time. */ public void setKeyframe(double time, Keyframe k, Smoothness s) { tc.addTimepoint(k, time, s); } /** Set a keyframe at the specified time, based on the current state of the Scene. */ public Keyframe setKeyframe(double time, Scene sc) { double key[] = getCurrentValues(); Keyframe k = new ArrayKeyframe(key); tc.addTimepoint(k, time, new Smoothness()); return k; } /** Set a keyframe at the specified time, based on the current state of the Scene, if and only if the Scene does not match the current state of the track. Return the new Keyframe, or null if none was set. */ public Keyframe setKeyframeIfModified(double time, Scene sc) { if (tc.getTimes().length == 0) return setKeyframe(time, sc); double val1[] = ((ArrayKeyframe) tc.evaluate(time, smoothingMethod)).val; double val2[] = getCurrentValues(); for (int i = 0; i < val1.length; i++) if (val1[i] != val2[i]) return setKeyframe(time, sc); return null; } /** Look up the current values from the filter. */ private double[] getCurrentValues() { ArrayList<Double> values = new ArrayList<Double>(); Property properties[] = filter.getProperties(); for (int i = 0; i < properties.length; i++) { if (properties[i].getType() == Property.DOUBLE) values.add((Double) filter.getPropertyValue(i)); else if (properties[i].getType() == Property.COLOR) { RGBColor color = (RGBColor) filter.getPropertyValue(i); values.add(Double.valueOf(color.getRed())); values.add(Double.valueOf(color.getGreen())); values.add(Double.valueOf(color.getBlue())); } } double val[] = new double[values.size()]; for (int i = 0; i < values.size(); i++) val[i] = values.get(i); return val; } /** Move a keyframe to a new time, and return its new position in the list. */ public int moveKeyframe(int which, double time) { return tc.moveTimepoint(which, time); } /** Delete the specified keyframe. */ public void deleteKeyframe(int which) { tc.removeTimepoint(which); } /** This track is null if it has no keyframes. */ public boolean isNullTrack() { return (tc.getTimes().length == 0); } /** This has no child tracks. */ public Track [] getSubtracks() { return new Track [0]; } /** Determine whether this track can be added as a child of an object. */ public boolean canAcceptAsParent(Object obj) { return false; } /** Get the parent object of this track. */ public Object getParent() { return parent; } /** Set the parent object of this track. */ public void setParent(Object obj) { parent = obj; } /** Get the smoothing method for this track. */ public int getSmoothingMethod() { return smoothingMethod; } /** Set the smoothing method for this track. */ public void setSmoothingMethod(int method) { smoothingMethod = method; } /** Get the names of all graphable values for this track. */ public String [] getValueNames() { ArrayList<String> names = new ArrayList<String>(); for (Property property : filter.getProperties()) { if (property.getType() == Property.DOUBLE) names.add(property.getName()); else if (property.getType() == Property.COLOR) { names.add(property.getName()+" ("+Translate.text("Red")+")"); names.add(property.getName()+" ("+Translate.text("Green")+")"); names.add(property.getName()+" ("+Translate.text("Blue")+")"); } } return names.toArray(new String[names.size()]); } /** Get the default list of graphable values (for a track which has no keyframes). */ public double [] getDefaultGraphValues() { return getCurrentValues(); } /** Get the allowed range for graphable values. This returns a 2D array, where elements [n][0] and [n][1] are the minimum and maximum allowed values, respectively, for the nth graphable value. */ public double[][] getValueRange() { ArrayList<double[]> ranges = new ArrayList<double[]>(); for (Property property : filter.getProperties()) { if (property.getType() == Property.DOUBLE) ranges.add(new double[] {property.getMinimum(), property.getMaximum()}); else if (property.getType() == Property.COLOR) { ranges.add(new double[] {0.0, Double.MAX_VALUE}); ranges.add(new double[] {0.0, Double.MAX_VALUE}); ranges.add(new double[] {0.0, Double.MAX_VALUE}); } } return ranges.toArray(new double[ranges.size()][]); } /** Write a serialized representation of this track to a stream. */ public void writeToStream(DataOutputStream out, Scene sc) throws IOException { double t[] = tc.getTimes(); Smoothness s[] = tc.getSmoothness(); Keyframe v[] = tc.getValues(); out.writeShort(0); // Version number out.writeUTF(name); out.writeBoolean(enabled); out.writeInt(smoothingMethod); out.writeInt(t.length); for (int i = 0; i < t.length; i++) { out.writeDouble(t[i]); v[i].writeToStream(out); s[i].writeToStream(out); } } /** Initialize this tracked based on its serialized representation as written by writeToStream(). */ public void initFromStream(DataInputStream in, Scene scene) throws IOException, InvalidObjectException { short version = in.readShort(); if (version != 0) throw new InvalidObjectException(""); name = in.readUTF(); enabled = in.readBoolean(); smoothingMethod = in.readInt(); int keys = in.readInt(); double t[] = new double [keys]; Smoothness s[] = new Smoothness [keys]; Keyframe v[] = new Keyframe [keys]; for (int i = 0; i < keys; i++) { t[i] = in.readDouble(); v[i] = new ArrayKeyframe(in, filter); s[i] = new Smoothness(in); } tc = new Timecourse(v, t, s); } /** Present a window in which the user can edit the specified keyframe. */ public void editKeyframe(LayoutWindow win, int which) { ArrayKeyframe key = (ArrayKeyframe) tc.getValues()[which]; Smoothness s = tc.getSmoothness()[which]; double time = tc.getTimes()[which]; ValueField timeField = new ValueField(time, ValueField.NONE, 5); ValueSlider s1Slider = new ValueSlider(0.0, 1.0, 100, s.getLeftSmoothness()); final ValueSlider s2Slider = new ValueSlider(0.0, 1.0, 100, s.getRightSmoothness()); final BCheckBox sameBox = new BCheckBox(Translate.text("separateSmoothness"), !s.isForceSame()); Property properties[] = filter.getProperties(); ArrayList<PropertyEditor> editors = new ArrayList<PropertyEditor>(); int index = 0; for (Property property : properties) { if (property.getType() == Property.DOUBLE) editors.add(new PropertyEditor(property, key.val[index++])); else if (property.getType() == Property.COLOR) editors.add(new PropertyEditor(property, new RGBColor(key.val[index++], key.val[index++], key.val[index++]))); } Widget widget[] = new Widget [editors.size()+5]; String label[] = new String [editors.size()+5]; for (int i = 0; i < editors.size(); i++) { widget[i] = editors.get(i).getWidget(); label[i] = editors.get(i).getLabel(); } sameBox.addEventLink(ValueChangedEvent.class, new Object() { void processEvent() { s2Slider.setEnabled(sameBox.getState()); } }); s2Slider.setEnabled(sameBox.getState()); int n = editors.size(); widget[n] = timeField; widget[n+1] = sameBox; widget[n+2] = new BLabel(Translate.text("Smoothness")+':'); widget[n+3] = s1Slider; widget[n+4] = s2Slider; label[n] = Translate.text("Time"); label[n+3] = "("+Translate.text("left")+")"; label[n+4] = "("+Translate.text("right")+")"; ComponentsDialog dlg = new ComponentsDialog(win, Translate.text("editKeyframe"), widget, label); if (!dlg.clickedOk()) return; win.setUndoRecord(new UndoRecord(win, false, UndoRecord.COPY_TRACK, new Object [] {this, duplicate(filter)})); index = 0; for (PropertyEditor editor : editors) { if (editor.getProperty().getType() == Property.DOUBLE) key.val[index++] = (Double) editor.getValue(); else { RGBColor color = (RGBColor) editor.getValue(); key.val[index++] = color.getRed(); key.val[index++] = color.getGreen(); key.val[index++] = color.getBlue(); } } if (sameBox.getState()) s.setSmoothness(s1Slider.getValue(), s2Slider.getValue()); else s.setSmoothness(s1Slider.getValue()); moveKeyframe(which, timeField.getValue()); } /** This method presents a window in which the user can edit the track. */ public void edit(LayoutWindow win) { BTextField nameField = new BTextField(FilterParameterTrack.this.getName()); BComboBox smoothChoice = new BComboBox(new String [] { Translate.text("Discontinuous"), Translate.text("Linear"), Translate.text("Interpolating"), Translate.text("Approximating") }); smoothChoice.setSelectedIndex(smoothingMethod); ComponentsDialog dlg = new ComponentsDialog(win, Translate.text("filterTrackTitle"), new Widget [] {nameField, smoothChoice}, new String [] {Translate.text("trackName"), Translate.text("SmoothingMethod")}); if (!dlg.clickedOk()) return; win.setUndoRecord(new UndoRecord(win, false, UndoRecord.COPY_TRACK, new Object [] {this, duplicate(filter)})); this.setName(nameField.getText()); smoothingMethod = smoothChoice.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.19526.738−644.382
Source linesThe number of non-empty source lines.409+163.6
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.904−7.356

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

Score0.8

Feature contributions

FeatureValueContribution
(log-odds)
Comment layout frequencyHow frequently the layout switches between lines containing only comments or whitespace and lines containing code.410−13.481
Indentation frequencyHow rapidly indentation changes from line to line.396+12.96
Number layout frequencyHow rapidly the number of numeric values per line changes through the code.396−8.666
Identifier layout (vertical)How rapidly the visual pattern of identifier characters changes from top to bottom.408.908+5.306
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.117.976−1.332
Comment layout (horizontal)How rapidly the visual pattern of comment characters changes from left to right.117.971+1.099
Operator visual areaThe share of the code’s visual area occupied by operators such as +, =, and *.0.116−0.188

Intercept 0.07 + feature contributions = -4.232 (log-odds).
Score = sigmoid(-4.232) = 0.014.

Score0.683
Score208
Run 1

The code is well-structured with clear class organization, descriptive method names, and good use of whitespace. It follows consistent patterns like single-responsibility methods and Javadoc comments. However, some sections break readability: `apply` and `editKeyframe` contain multi-action loops and conditionals that mix concerns, and `getCurrentValues` uses redundant boxing/unboxing and two-pass collection conversion. The `editKeyframe` method is notably long with UI setup, event wiring, and data mutation combined. Nesting is mostly flat, but `apply` and `setKeyframeIfModified` have slightly deeper logic. Action granularity is generally good, though some lines pack multiple operations. Overall, it is maintainable but could be improved by extracting helper methods and simplifying value collection logic.

Run 2

The code is well-structured and highly readable. It has clear class and method organization, flat nesting with early returns, and descriptive naming. Each method has a single responsibility, and most operations are concise. The use of helper methods like getCurrentValues() and consistent documentation improves clarity. Minor issues include some repetitive property-type checks and the long editKeyframe() method, which slightly reduces readability. Overall, the code is maintainable, follows clean coding practices, and is easy to follow.

Run 3

The code demonstrates good readability through consistent structure, clear method separation, and descriptive naming. Methods are logically organized and single-purpose, with Javadoc comments explaining intent throughout. The nesting depth is minimal and reasonable, with early returns reducing indentation in several places. Action granularity is well-maintained, with most lines performing one operation. The code length is appropriate for the functionality, avoiding unnecessary verbosity while maintaining clarity. The reading flow is natural and follows a logical progression from constructor to core operations to utility methods and serialization. Minor issues include some repetition in property type handling, but this pattern is consistent and clear.

Run 1

Code Structure: Well-separated methods organize keyframe operations, property conversion, serialization, and editing, though UI and track logic share one class. Nesting: Mostly shallow loops and conditionals; early returns keep control flow straightforward. Clarity of intent: Descriptive method names and documentation explain the purpose, but abbreviated variables such as tc, k, s, and v, generic parent typing, and implicit RGB index mappings require extra interpretation. Code length: Most methods are concise, but editKeyframe is lengthy and repeated property-type handling could be factored into helpers. Action granularity: Generally one statement per line, although multiple index++ operations inside RGB constructors combine state changes with value construction. Reading flow: Consistent spacing and method comments support scanning, while inconsistent brace indentation, omitted conditional braces, and dense UI construction expressions occasionally interrupt the flow.

Run 2

Code Structure: Well-separated, purpose-specific methods organize track operations, serialization, and editing, though editKeyframe mixes UI construction and state updates. Nesting: Mostly shallow loops and conditionals, with early returns keeping control flow manageable. Clarity of intent: Descriptive method names and documentation explain most behavior; abbreviated variables such as tc, k, s, and v, implicit array layouts, and occasional inaccurate comments reduce clarity. Code length: Most methods are concise, but repetitive property-type handling and the lengthy editKeyframe method add avoidable bulk. Action granularity: Generally one statement per line, although multiple index++ operations inside RGBColor constructor calls combine data access and mutation. Reading flow: Method-level flow is natural and formatting mostly consistent; omitted braces, inconsistent array declaration styles, long expressions, and manual widget-array indexing introduce friction.

Run 3

Code Structure: Well-separated methods organize keyframe operations, property extraction, serialization, and editing, though UI and track logic share one class. Nesting: Generally shallow, with straightforward loops, conditionals, and early returns; the event callback adds little complexity. Clarity of intent: Descriptive method names and documentation communicate the purpose, but abbreviated variables such as tc, k, t, and s, plus implicit RGB array packing, require extra interpretation. Code length: Most methods are concise, but editKeyframe is lengthy and property-type handling repeats across several methods. Action granularity: Usually one statement per line; multiple index++ operations within RGBColor construction obscure individual actions. Reading flow: Consistent method-level organization and whitespace make navigation easy, while inconsistent brace indentation, parallel widget/label arrays, positional offsets, and long constructor expressions interrupt the flow.