diff --git a/PluginCommon/VisWireframe.cs b/PluginCommon/VisWireframe.cs
index 9e56383..558d340 100644
--- a/PluginCommon/VisWireframe.cs
+++ b/PluginCommon/VisWireframe.cs
@@ -140,7 +140,8 @@ namespace PluginCommon {
foreach (IntPair ip in mEdges) {
if (ip.Val0 < 0 || ip.Val0 >= vertexCount ||
ip.Val1 < 0 || ip.Val1 >= vertexCount) {
- msg = "invalid edge";
+ msg = "invalid edge (vertices " + ip.Val0 + ", " + ip.Val1 +
+ "; count=" + vertexCount + ")";
return false;
}
}
@@ -149,7 +150,7 @@ namespace PluginCommon {
foreach (IntPair ip in mVertexFaces) {
if (ip.Val0 < 0 || ip.Val0 >= vertexCount ||
ip.Val1 < 0 || ip.Val1 >= faceCount) {
- msg = "invalid vertex-face";
+ msg = "invalid vertex-face (v=" + ip.Val0 + ", f=" + ip.Val1 + ")";
return false;
}
}
@@ -158,7 +159,7 @@ namespace PluginCommon {
foreach (IntPair ip in mVertexFaces) {
if (ip.Val0 < 0 || ip.Val0 >= edgeCount ||
ip.Val1 < 0 || ip.Val1 >= faceCount) {
- msg = "invalid edge-face";
+ msg = "invalid edge-face (e=" + ip.Val0 + ", f=" + ip.Val1 + ")";
return false;
}
}
diff --git a/SourceGen/VisWireframeAnimation.cs b/SourceGen/VisWireframeAnimation.cs
index 52242cf..b6d0a8b 100644
--- a/SourceGen/VisWireframeAnimation.cs
+++ b/SourceGen/VisWireframeAnimation.cs
@@ -51,7 +51,7 @@ namespace SourceGen {
public const string P_DELTA_ROT_Y = "_deltaRotY";
public const string P_DELTA_ROT_Z = "_deltaRotZ";
- private IVisualizationWireframe mVisWire;
+ private WireframeObject mWireObj;
///
@@ -59,10 +59,10 @@ namespace SourceGen {
///
public VisWireframeAnimation(string tag, string visGenIdent,
ReadOnlyDictionary visGenParams, Visualization oldObj,
- IVisualizationWireframe visWire)
+ WireframeObject wireObj)
: base(tag, visGenIdent, visGenParams, oldObj) {
- // visWire may be null when loading from project file
- mVisWire = visWire;
+ // wireObj may be null when loading from project file
+ mWireObj = wireObj;
OverlayImage = ANIM_OVERLAY_IMAGE;
}
@@ -71,7 +71,7 @@ namespace SourceGen {
///
///
/// We override it because this is our first opportunity to capture the
- /// IVisualizationWireframe reference when the object was created during project
+ /// wireframe object reference if the object was created during project
/// file loading.
///
/// Reference to wireframe data generated by plugin.
@@ -79,7 +79,7 @@ namespace SourceGen {
public override void SetThumbnail(IVisualizationWireframe visWire,
ReadOnlyDictionary parms) {
base.SetThumbnail(visWire, parms);
- mVisWire = visWire;
+ mWireObj = WireframeObject.Create(visWire);
}
///
@@ -100,7 +100,7 @@ namespace SourceGen {
bool doBfc = Util.GetFromObjDict(VisGenParams, VisWireframe.P_IS_BFC_ENABLED, false);
for (int frame = 0; frame < frameCount; frame++) {
- BitmapSource bs = GenerateWireframeImage(mVisWire, dim,
+ BitmapSource bs = GenerateWireframeImage(mWireObj, dim,
curX, curY, curZ, doPersp, doBfc);
encoder.AddFrame(BitmapFrame.Create(bs), frameDelayMsec);
diff --git a/SourceGen/Visualization.cs b/SourceGen/Visualization.cs
index 9d51c5e..540e57f 100644
--- a/SourceGen/Visualization.cs
+++ b/SourceGen/Visualization.cs
@@ -196,7 +196,8 @@ namespace SourceGen {
ReadOnlyDictionary parms) {
Debug.Assert(visWire != null);
Debug.Assert(parms != null);
- CachedImage = GenerateWireframeImage(visWire, THUMBNAIL_DIM, parms);
+ WireframeObject wireObj = WireframeObject.Create(visWire);
+ CachedImage = GenerateWireframeImage(wireObj, THUMBNAIL_DIM, parms);
}
///
@@ -257,30 +258,30 @@ namespace SourceGen {
/// Output bitmap dimension (width and height).
/// Parameter set, for rotations and render options.
/// Rendered bitmap.
- public static BitmapSource GenerateWireframeImage(IVisualizationWireframe visWire,
+ public static BitmapSource GenerateWireframeImage(WireframeObject wireObj,
double dim, ReadOnlyDictionary parms) {
int eulerX = Util.GetFromObjDict(parms, VisWireframeAnimation.P_EULER_ROT_X, 0);
int eulerY = Util.GetFromObjDict(parms, VisWireframeAnimation.P_EULER_ROT_Y, 0);
int eulerZ = Util.GetFromObjDict(parms, VisWireframeAnimation.P_EULER_ROT_Z, 0);
bool doPersp = Util.GetFromObjDict(parms, VisWireframe.P_IS_PERSPECTIVE, false);
bool doBfc = Util.GetFromObjDict(parms, VisWireframe.P_IS_BFC_ENABLED, false);
- return GenerateWireframeImage(visWire, dim, eulerX, eulerY, eulerZ, doPersp, doBfc);
+ return GenerateWireframeImage(wireObj, dim, eulerX, eulerY, eulerZ, doPersp, doBfc);
}
///
/// Generates a BitmapSource from IVisualizationWireframe data. Useful for thumbnails
/// and GIF exports.
///
- public static BitmapSource GenerateWireframeImage(IVisualizationWireframe visWire,
+ public static BitmapSource GenerateWireframeImage(WireframeObject wireObj,
double dim, int eulerX, int eulerY, int eulerZ, bool doPersp, bool doBfc) {
// Generate the path geometry.
- GeometryGroup geo = GenerateWireframePath(visWire, dim, eulerX, eulerY, eulerZ,
+ GeometryGroup geo = GenerateWireframePath(wireObj, dim, eulerX, eulerY, eulerZ,
doPersp, doBfc);
// Render Path to bitmap -- https://stackoverflow.com/a/23582564/294248
Rect bounds = geo.GetRenderBounds(null);
- Debug.WriteLine("RenderWF dim=" + dim + " bounds=" + bounds + ": " + visWire);
+ Debug.WriteLine("RenderWF dim=" + dim + " bounds=" + bounds + ": " + wireObj);
// Create bitmap.
RenderTargetBitmap bitmap = new RenderTargetBitmap(
@@ -319,14 +320,14 @@ namespace SourceGen {
/// Visualization data.
/// Width/height to use for path area.
/// Visualization parameters.
- public static GeometryGroup GenerateWireframePath(IVisualizationWireframe visWire,
+ public static GeometryGroup GenerateWireframePath(WireframeObject wireObj,
double dim, ReadOnlyDictionary parms) {
int eulerX = Util.GetFromObjDict(parms, VisWireframeAnimation.P_EULER_ROT_X, 0);
int eulerY = Util.GetFromObjDict(parms, VisWireframeAnimation.P_EULER_ROT_Y, 0);
int eulerZ = Util.GetFromObjDict(parms, VisWireframeAnimation.P_EULER_ROT_Z, 0);
bool doPersp = Util.GetFromObjDict(parms, VisWireframe.P_IS_PERSPECTIVE, false);
bool doBfc = Util.GetFromObjDict(parms, VisWireframe.P_IS_BFC_ENABLED, false);
- return GenerateWireframePath(visWire, dim, eulerX, eulerY, eulerZ, doPersp, doBfc);
+ return GenerateWireframePath(wireObj, dim, eulerX, eulerY, eulerZ, doPersp, doBfc);
}
///
@@ -334,20 +335,21 @@ namespace SourceGen {
/// scaled if the output area is larger or smaller than the path bounds, so this scales
/// coordinates so they fit within the box.
///
- public static GeometryGroup GenerateWireframePath(IVisualizationWireframe visWire,
+ public static GeometryGroup GenerateWireframePath(WireframeObject wireObj,
double dim, int eulerX, int eulerY, int eulerZ, bool doPersp, bool doBfc) {
// WPF path drawing is based on a system where a pixel is drawn at the center
- // of the coordinate, and integer coordinates start at the top left edge. If
- // you draw a pixel at (0,0), most of the pixel will be outside the window
- // (visible or not based on ClipToBounds).
+ // of its coordinates, and integer coordinates start at the top left edge of
+ // the drawing area. If you draw a pixel at (0,0), 3/4ths of the pixel will be
+ // outside the window (visible or not based on ClipToBounds).
//
// If you draw a line from (1,1 to 4,1), the line's length will appear to
// be (4 - 1) = 3. It touches four pixels -- the end point is not exclusive --
- // but because the thickness doesn't extend past the endpoints, the filled
- // area is only three. If you have a window of size 10x10, and you draw from
- // 0,0 to 9,9, the line will extend for half a line-thickness off the top,
- // but will not go past the right/left edges. (This becomes very obvious when
- // you're working with an up-scaled 8x8 path.)
+ // but the filled area is only three, because the thickness doesn't extend the
+ // line's length, and the line stops at the coordinate at the center of the pixel.
+ // You're not drawing N pixels, you're drawing from one coordinate point to another.
+ // If you have a window of size 8x8, and you draw from 0,0 to 7,0, the line will
+ // extend for half a line-thickness off the top, but will not go past the right/left
+ // edges. (This becomes very obvious when you're working with an up-scaled 8x8 path.)
//
// Similarly, drawing a horizontal line two units long results in a square, and
// drawing a line that starts and ends at the same point doesn't appear to
@@ -357,12 +359,13 @@ namespace SourceGen {
// This turns out to be important for another reason: a line from (1,1) to (9,1)
// shows up as a double-wide half-bright line, while a line from (1.5,1.5) to
// (9.5,1.5) is drawn as a single-wide full-brightness line. This is because of
- // the anti-aliasing.
+ // the anti-aliasing. Anti-aliasing can be disabled, but the lines look much
+ // nicer with it enabled.
//
// The path has an axis-aligned bounding box that covers the pixel centers. If we
- // want a path-drawn shape to animate smoothly we want to ensure that the bounds
+ // want a path-drawn mesh to animate smoothly we want to ensure that the bounds
// are constant across all renderings of a shape (which could get thinner or wider
- // as it rotates), so we draw an invisible pixel in our desired bottom-right corner.
+ // as it rotates), so we plot an invisible point in our desired bottom-right corner.
//
// If we want an 8x8 bitmap, we draw a line from (8,8) to (8,8) to establish the
// bounds, then draw lines with coordinates from 0.5 to 7.5.
@@ -377,7 +380,6 @@ namespace SourceGen {
// Generate a list of clip-space line segments. Coordinate values are in the
// range [-1,1], with +X to the right and +Y upward.
- WireframeObject wireObj = WireframeObject.Create(visWire);
List segs = wireObj.Generate(eulerX, eulerY, eulerZ,
doPersp, doBfc);
diff --git a/SourceGen/WpfGui/EditVisualization.xaml.cs b/SourceGen/WpfGui/EditVisualization.xaml.cs
index f3802e3..5a1e9b4 100644
--- a/SourceGen/WpfGui/EditVisualization.xaml.cs
+++ b/SourceGen/WpfGui/EditVisualization.xaml.cs
@@ -52,8 +52,8 @@ namespace SourceGen.WpfGui {
private SortedList mEditedList;
private Visualization mOrigVis;
- // IVisualization2d or IVisualizationWireframe
- public object mVisObj;
+ private BitmapSource mThumbnail;
+ private WireframeObject mWireObj;
///
/// Visualization generation identifier for the last visualizer we used, for the benefit
@@ -384,19 +384,19 @@ namespace SourceGen.WpfGui {
Debug.Assert(isTagValid);
if (isWireframe && IsWireframeAnimated) {
NewVis = new VisWireframeAnimation(trimTag, item.VisDescriptor.Ident, valueDict,
- mOrigVis, (IVisualizationWireframe) mVisObj);
+ mOrigVis, mWireObj);
} else {
NewVis = new Visualization(trimTag, item.VisDescriptor.Ident, valueDict, mOrigVis);
}
+
+ // Set the thumbnail image.
if (isWireframe) {
- Debug.Assert(mVisObj is IVisualizationWireframe);
- NewVis.CachedImage =
- Visualization.GenerateWireframeImage((IVisualizationWireframe)mVisObj,
- Visualization.THUMBNAIL_DIM, valueDict);
+ Debug.Assert(mWireObj != null);
+ NewVis.CachedImage = Visualization.GenerateWireframeImage(mWireObj,
+ Visualization.THUMBNAIL_DIM, valueDict);
} else {
- Debug.Assert(mVisObj is IVisualization2d);
- NewVis.CachedImage =
- Visualization.ConvertToBitmapSource((IVisualization2d)mVisObj);
+ Debug.Assert(mThumbnail != null);
+ NewVis.CachedImage = mThumbnail;
}
sLastVisIdent = NewVis.VisGenIdent;
@@ -600,16 +600,17 @@ namespace SourceGen.WpfGui {
BitmapDimensions = string.Format("{0}x{1}",
previewImage.Source.Width, previewImage.Source.Height);
- mVisObj = vis2d;
+ mThumbnail = (BitmapSource)previewImage.Source;
} else {
previewGrid.Background = Brushes.Black;
previewImage.Source = Visualization.BLANK_IMAGE;
double dim = Math.Floor(
Math.Min(previewImage.ActualWidth, previewImage.ActualHeight));
- wireframePath.Data = Visualization.GenerateWireframePath(visWire, dim, parms);
+ WireframeObject wireObj = WireframeObject.Create(visWire);
+ wireframePath.Data = Visualization.GenerateWireframePath(wireObj, dim, parms);
BitmapDimensions = "n/a";
- mVisObj = visWire;
+ mWireObj = wireObj;
}
}
@@ -690,7 +691,7 @@ namespace SourceGen.WpfGui {
}
private void TestAnim_Click(object sender, RoutedEventArgs e) {
- ShowWireframeAnimation dlg = new ShowWireframeAnimation(this, (IVisualizationWireframe)mVisObj,
+ ShowWireframeAnimation dlg = new ShowWireframeAnimation(this, mWireObj,
CreateVisGenParams(true));
dlg.ShowDialog();
}
diff --git a/SourceGen/WpfGui/ShowWireframeAnimation.xaml.cs b/SourceGen/WpfGui/ShowWireframeAnimation.xaml.cs
index 4e706fa..eaf707f 100644
--- a/SourceGen/WpfGui/ShowWireframeAnimation.xaml.cs
+++ b/SourceGen/WpfGui/ShowWireframeAnimation.xaml.cs
@@ -33,7 +33,7 @@ namespace SourceGen.WpfGui {
///
private DispatcherTimer mTimer;
- IVisualizationWireframe mVisWire;
+ WireframeObject mWireObj;
private int mFrameCount;
private int mInitialX, mInitialY, mInitialZ;
private int mDeltaX, mDeltaY, mDeltaZ;
@@ -43,12 +43,12 @@ namespace SourceGen.WpfGui {
private int mCurFrame;
- public ShowWireframeAnimation(Window owner, IVisualizationWireframe visWire,
+ public ShowWireframeAnimation(Window owner, WireframeObject wireObj,
ReadOnlyDictionary parms) {
InitializeComponent();
Owner = owner;
- mVisWire = visWire;
+ mWireObj = wireObj;
mCurX = mInitialX = Util.GetFromObjDict(parms, VisWireframeAnimation.P_EULER_ROT_X, 0);
mCurY = mInitialY = Util.GetFromObjDict(parms, VisWireframeAnimation.P_EULER_ROT_Y, 0);
@@ -98,7 +98,7 @@ namespace SourceGen.WpfGui {
// We use the dimensions of the Border surrounding the ViewBox, rather than the
// ViewBox itself, because on the first iteration the ViewBox has a size of zero.
double dim = Math.Floor(Math.Min(testBorder.ActualWidth, testBorder.ActualHeight));
- wireframePath.Data = Visualization.GenerateWireframePath(mVisWire, dim,
+ wireframePath.Data = Visualization.GenerateWireframePath(mWireObj, dim,
mCurX, mCurY, mCurZ, mDoPersp, mDoBfc);
}
}