<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Cheesy Code</title>
	<atom:link href="http://code.cheesydesign.com/?feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://code.cheesydesign.com</link>
	<description>Programming in C, C++ and C#</description>
	<lastBuildDate>Mon, 09 Aug 2010 17:00:24 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Multi-Column Histograms (EXTENDED_STATS)</title>
		<link>http://code.cheesydesign.com/?p=668</link>
		<comments>http://code.cheesydesign.com/?p=668#comments</comments>
		<pubDate>Mon, 09 Aug 2010 17:00:24 +0000</pubDate>
		<dc:creator>AndrewCocks</dc:creator>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[11gR2]]></category>
		<category><![CDATA[extended_stats]]></category>
		<category><![CDATA[histogram]]></category>

		<guid isPermaLink="false">http://code.cheesydesign.com/?p=668</guid>
		<description><![CDATA[Source: mcol_histogram.sql
When running an OLTP system you may have a transactions table with things like transaction ids, transaction types and states of transaction (open, closed, cancelled, etc).  Different transactions tend to have different usage patterns &#8211; some might be automatically dealt with, others require user interaction, some typically rejected and still others where a [...]]]></description>
			<content:encoded><![CDATA[<p><span style="background-color:#FFFCF0;border: 1px solid grey;margin-right:10px;padding:3px">Source: <a href="http://code.cheesydesign.com/wp-content/uploads/2010/08/mcol_histogram.sql" title="Source">mcol_histogram.sql</a></span></p>
<p><img src="http://code.cheesydesign.com/wp-content/uploads/2010/08/oracle-11g.gif" alt="Oracle 11gR1 icon" style="float: left; padding: 3px 8px 0px 3px;" />When running an OLTP system you may have a transactions table with things like transaction ids, transaction types and states of transaction (open, closed, cancelled, etc).  Different transactions tend to have different usage patterns &#8211; some might be automatically dealt with, others require user interaction, some typically rejected and still others where a lot of mistakes are common so they get cancelled a lot. There are differences in the in-flight and final states between the various transactions but since they are mixed into the one transaction table the skew in the states can be obscured when looking at only a single column.  The skew may be only visible when both the type and state are considered together &#8211; a situation for which extended stats is perfect for.  To test the effect of multi-column histograms or EXTENDED_STATS in this type of scenario we&#8217;ll need a sample table which shows a skew only when multiple columns are considered.  I&#8217;ve got type A transactions which typically have a final state of closed and type B transactions which typically end up getting cancelled.  However a few As (10) do get cancelled and a few Bs (10) make it to a closed state. I have no open or other state transactions.</p>
<p>The test scenario is:</p>
<ol>
<li>Create a transaction table with skewed data, transtype A mostly closed, B mostly cancelled.</li>
<li>Take a look at the data to verify that it has the expected skew.  Note that there are 10 cancelled A transactions.</li>
<li>Explain plan for filter(&#8221;TRANSTYPE&#8221;=&#8217;A&#8217; AND &#8220;STATE&#8221;=&#8217;Cancelled&#8217;) and note the expected row count: 500, which is Oracle&#8217;s best guess based on information available in normal single column histograms.</li>
<li>Try again but with a dynamic_sampling level of 4 and see the correct expected row count (10).</li>
<li>Generate multi-column stats on &#8216;(transtype,state)&#8217;</li>
<li>Retry the query without dynamic sampling and see that Oracle 11g is able to use the new stats to correctly estimate the row count of 10 and uses an index in preference to a table scan.</li>
</ol>
<p>Obviously this is a contrived example which deliberately obscures the skew in the data with perfect balance between the two transaction types but with a larger number of transaction types it is easy for such patterns to be muddied.  With the aid of a histogram on the two critical columns here Oracle was able to see the situation accurately and modify the execution plan accordingly going from a full table scan to an index lookup.  A more accurate picture of the data will result in superior execution plans.  Using the dynamic_sampling hint results in the exact same benefits.  Oracle&#8217;s documentation on <a href="http://download.oracle.com/docs/cd/B19306_01/server.102/b14211/stats.htm#i43032">dynamic sampling levels</a> says of level 4:</p>
<blockquote><p>Level 4: Apply dynamic sampling to all tables that meet Level 3 criteria, plus all tables that have single-table predicates that reference 2 or more columns. The number of blocks sampled is the default number of dynamic sampling blocks. For unanalyzed tables, the number of blocks sampled is two times the default number of dynamic sampling blocks.</p></blockquote>
<p>Note:  The &#8220;estimate&#8221; mentioned in step 6 is the exact number because for the stats gathering parameter estimate_percent I&#8217;ve used NULL or compute which may not be practical in a production system.  You&#8217;ll need to use a percentage which balances accurately modelling the data against stats gathering time.  This <a href="http://www.dbspecialists.com/files/presentations/dbms_stats.html">interesting piece</a> on that topic comes to the conclusion that between 5-20% is the right number but the analysis extends only as far as 10g.</p>
<p>Here are the results of running the SQL script mcol_histogram which you can download from the link up near the start of this post:</p>
<pre class="console">
SQL> set linesize 100 echo on
SQL> @mcol_histogram
SQL> -- Step 1: Create a transaction table with skewed data, transtype A mostly closed, B mostly cancelled
SQL> CREATE TABLE transactions AS
  2  SELECT tmp.*, (CASE WHEN (tmp.transtype = 'A' AND MOD(transid,100) != 0) OR
  3                           (tmp.transtype = 'B' AND MOD(transid,100)  = 0) THEN 'Closed'
  4                      ELSE 'Cancelled'
  5                  END) state FROM
  6      (
  7      SELECT LEVEL transid, DECODE(FLOOR(LEVEL/1001),0,'A','B') transtype
  8        FROM dual
  9      CONNECT BY LEVEL <= 2000
 10      ) tmp;

Table created.

SQL>
SQL> CREATE INDEX ix1transactions ON transactions(transtype, state);

Index created.

SQL>
SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS(ownname => SYS_CONTEXT('USERENV','CURRENT_USER'),
tabname => 'transactions', estimate_percent => NULL, method_opt => 'FOR ALL COLUMNS SIZE SKEWONLY', cascade => true);

PL/SQL procedure successfully completed.

SQL>
SQL> -- Step 2: Take a look at the data to verify that it has the expected skew.
SQL> SELECT transtype, state, COUNT(*)
  2    FROM transactions
  3  GROUP BY transtype, state
  4  ORDER BY transtype, state
  5    ;

T STATE       COUNT(*)
- --------- ----------
A Cancelled         10
A Closed           990
B Cancelled        990
B Closed            10

SQL>
SQL> -- Step 3:  This only returns 10 rows, but we have a full table scan and high cardinality
SQL> EXPLAIN PLAN FOR
  2  SELECT *
  3    FROM transactions t
  4   WHERE transtype = 'A'
  5     AND state = 'Cancelled';

Explained.

SQL>
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
Plan hash value: 1321366336

----------------------------------------------------------------------------------
| Id  | Operation         | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |              |   500 |  7500 |     3   (0)| 00:00:45 |
|*  1 |  TABLE ACCESS FULL| TRANSACTIONS |   500 |  7500 |     3   (0)| 00:00:45 |
----------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------

   1 - filter("TRANSTYPE"='A' AND "STATE"='Cancelled')

13 rows selected.

SQL>
SQL> -- Step 4:  Try again but use dynamic sampling this time and get much better results
SQL> EXPLAIN PLAN FOR
  2  SELECT /*+ dynamic_sampling (4) */ *
  3    FROM transactions t
  4   WHERE transtype = 'A'
  5     AND state = 'Cancelled';

Explained.

SQL>
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
Plan hash value: 278489313

-----------------------------------------------------------------------------------------------
| Id  | Operation                   | Name            | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                 |    10 |   150 |     2   (0)| 00:00:30 |
|   1 |  TABLE ACCESS BY INDEX ROWID| TRANSACTIONS    |    10 |   150 |     2   (0)| 00:00:30 |
|*  2 |   INDEX RANGE SCAN          | IX1TRANSACTIONS |    10 |       |     1   (0)| 00:00:15 |
-----------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
---------------------------------------------------

   2 - access("TRANSTYPE"='A' AND "STATE"='Cancelled')

Note
-----
   - dynamic sampling used for this statement (level=4)

18 rows selected.

SQL>
SQL> -- Step 5:  Generate some multi-column stats
SQL> SELECT DBMS_STATS.CREATE_EXTENDED_STATS (SYS_CONTEXT('USERENV','CURRENT_USER'),'transactions',
'(transtype,state)') FROM dual;

DBMS_STATS.CREATE_EXTENDED_STATS(SYS_CONTEXT('USERENV','CURRENT_USER'),'TRANSACTIONS','(TRANSTYPE,ST
----------------------------------------------------------------------------------------------------
SYS_STUMWLR#03VMK70K_1F3J$2ZMZ

SQL>
SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS(ownname => SYS_CONTEXT('USERENV','CURRENT_USER'),
tabname => 'transactions', estimate_percent => NULL, method_opt => 'FOR ALL COLUMNS SIZE SKEWONLY', cascade => true);

PL/SQL procedure successfully completed.

SQL>
SQL> -- Step 6:  The new extended stats yield a cardinality of 10 and use an index lookup
SQL> EXPLAIN PLAN FOR
  2  SELECT *
  3    FROM transactions t
  4   WHERE transtype = 'A'
  5     AND state = 'Cancelled';

Explained.

SQL>
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
Plan hash value: 278489313

-----------------------------------------------------------------------------------------------
| Id  | Operation                   | Name            | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                 |    10 |   150 |     2   (0)| 00:00:30 |
|   1 |  TABLE ACCESS BY INDEX ROWID| TRANSACTIONS    |    10 |   150 |     2   (0)| 00:00:30 |
|*  2 |   INDEX RANGE SCAN          | IX1TRANSACTIONS |    10 |       |     1   (0)| 00:00:15 |
-----------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
---------------------------------------------------

   2 - access("TRANSTYPE"='A' AND "STATE"='Cancelled')

14 rows selected.

SQL>
SQL> DROP TABLE transactions;

Table dropped.

SQL>
SQL> SELECT * FROM v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
PL/SQL Release 11.2.0.1.0 - Production
CORE    11.2.0.1.0      Production
TNS for Linux: Version 11.2.0.1.0 - Production
NLSRTL Version 11.2.0.1.0 - Production

SQL>
</pre>
<p>
Final Note: The new stats are difficult to understand in the dba_histogram/user_histogram views with the endpoint_value being encoded in a different format to normal stats.  I tried running Tom Kyte&#8217;s <a href="http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:707586567563">hexstr</a> to decode it but was unsuccessful.  Perhaps someone else will have better luck.  Note that only the first 6 characters of endpoint_value can be decoded for normal histogram columns so it is perhaps better to stick to 6 letter transaction states rather than using things like &#8216;cancelled&#8217;.</p>
]]></content:encoded>
			<wfw:commentRss>http://code.cheesydesign.com/?feed=rss2&amp;p=668</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Compound triggers and mutating tables</title>
		<link>http://code.cheesydesign.com/?p=650</link>
		<comments>http://code.cheesydesign.com/?p=650#comments</comments>
		<pubDate>Mon, 02 Aug 2010 17:00:20 +0000</pubDate>
		<dc:creator>AndrewCocks</dc:creator>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[11gR1]]></category>

		<guid isPermaLink="false">http://code.cheesydesign.com/?p=650</guid>
		<description><![CDATA[Source: trigger.sql
If you are in a mutating table situation where your trigger needs to read from the same table that it is firing on your only real option before Oracle 11g was a multi trigger solution with a muddle of row and statement triggers communicating via a package.  But now Oracle 11g comes through [...]]]></description>
			<content:encoded><![CDATA[<p><span style="background-color:#FFFCF0;border: 1px solid grey;margin-right:10px;padding:3px">Source: <a href="http://code.cheesydesign.com/wp-content/uploads/2010/08/trigger.sql" title="Source">trigger.sql</a></span></p>
<p><img src="http://code.cheesydesign.com/wp-content/uploads/2010/08/oracle-11g.gif" alt="Oracle 11gR1 icon" style="float: left; padding: 3px 8px 0px 3px;" />If you are in a mutating table situation where your trigger needs to read from the same table that it is firing on your only real option before Oracle 11g was a multi trigger solution with a muddle of row and statement triggers communicating via a package.  But now Oracle 11g comes through with a great new feature: compound triggers which neatly solve the problem &#8230; or do they.  Well they purport to do so but it isn&#8217;t all smooth sailing: <a href="http://orastory.wordpress.com/2009/01/20/beware-the-compound-trigger/">Beware the compound trigger</a>.  But I figured &#8211; that&#8217;s 11.1.0.6 whereas I&#8217;m using 11.1.0.7 and those particular failure modes don&#8217;t apply to my situation so I&#8217;ll be fine.  Not exactly.  What I have is a normal after statement trigger firing on the &#8220;banner&#8221; column and modifying data in the &#8220;changed&#8221; column and I need to fire a second trigger on that second column.  What I saw was that the compound trigger worked properly once and then not again until it was recompiled.</p>
<p>trg_after => fires on column &#8220;banner&#8221; and modifies column &#8220;changed&#8221;.<br />
trg_compound_row => fires on column &#8220;changed&#8221;<br />
trg_simple_row => fires on same criteria as compound trigger for comparative purposes</p>
<p>The test scenario is:<br />
0)  Create table + triggers<br />
1)  Update table to see triggers firing then rollback to reset<br />
2)  Do step 1 again<br />
3)  Recompile trigger<br />
4)  Do step 1 twice<br />
5)  Drop table</p>
<pre class="console">SQL> set echo on
SQL> @trigger.sql
SQL> SET SERVEROUT ON LINESIZE 200
SQL>
SQL> CREATE table trigger_test AS
  2  SELECT rownum id, banner, 'A' changed FROM v$version;

Table created.

SQL>
SQL> CREATE OR REPLACE TRIGGER trg_after
  2      AFTER UPDATE OF banner ON trigger_test
  3  BEGIN
  4      dbms_output.put_line('Update');
  5      UPDATE trigger_test SET changed = 'B'
  6       WHERE id = 1;
  7  END;
  8  /

Trigger created.

SQL> CREATE OR REPLACE TRIGGER trg_compound_row
  2    FOR UPDATE OF changed ON trigger_test
  3  COMPOUND TRIGGER
  4
  5  AFTER EACH ROW IS BEGIN
  6      dbms_output.put_line('Compound fired <== Should happen every time');
  7  END AFTER EACH ROW;
  8
  9  END trg_compound_row;
 10  /

Trigger created.

SQL> CREATE OR REPLACE TRIGGER trg_simple_row
  2      AFTER UPDATE OF changed ON trigger_test
  3      FOR EACH ROW
  4  BEGIN
  5      dbms_output.put_line('Simple fired');
  6  END;
  7  /

Trigger created.

SQL> SELECT * FROM trigger_test;

        ID BANNER                                                                           C
---------- -------------------------------------------------------------------------------- -
         1 Oracle Database 11g Enterprise Edition Release 11.1.0.7.0 - 64bit Production     A
         2 PL/SQL Release 11.1.0.7.0 - Production                                           A
         3 CORE 11.1.0.7.0      Production                                                       A
         4 TNS for Solaris: Version 11.1.0.7.0 - Production                                 A
         5 NLSRTL Version 11.1.0.7.0 - Production                                           A

SQL>
SQL> UPDATE trigger_test SET banner = banner || ' ' WHERE id = 2;
Update
Compound fired <== Should happen every time
Simple fired

1 row updated.

SQL> ROLLBACK;

Rollback complete.

SQL>
SQL> UPDATE trigger_test SET banner = banner || ' ' WHERE id = 2;
Update
Simple fired

1 row updated.

SQL> ROLLBACK;

Rollback complete.

SQL>
SQL> ALTER TRIGGER trg_compound_row COMPILE;

Trigger altered.

SQL>
SQL> UPDATE trigger_test SET banner = banner || ' ' WHERE id = 2;
Update
Compound fired <== Should happen every time
Simple fired

1 row updated.

SQL> ROLLBACK;

Rollback complete.

SQL>
SQL> UPDATE trigger_test SET banner = banner || ' ' WHERE id = 2;
Update
Simple fired

1 row updated.

SQL> ROLLBACK;

Rollback complete.

SQL>
SQL> DROP TABLE trigger_test;

Table dropped.

SQL></pre>
<p>So the lesson is clear, as Dominic Brooks already stated: Beware the compound trigger.</p>
]]></content:encoded>
			<wfw:commentRss>http://code.cheesydesign.com/?feed=rss2&amp;p=650</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Bing Maps 3D &#8211; A Dashed Line With Constant Spacing</title>
		<link>http://code.cheesydesign.com/?p=640</link>
		<comments>http://code.cheesydesign.com/?p=640#comments</comments>
		<pubDate>Tue, 01 Jun 2010 17:00:00 +0000</pubDate>
		<dc:creator>JohnStewien</dc:creator>
				<category><![CDATA[c#]]></category>
		<category><![CDATA[Bing Maps]]></category>
		<category><![CDATA[C#]]></category>

		<guid isPermaLink="false">http://code.cheesydesign.com/?p=640</guid>
		<description><![CDATA[I was only going to write 3 Bing Maps 3D posts (they start Here), but today I added something that I thought was rather cool.
You can download the source code for this post here 3DViewerBingMaps.zip
In OpenGL you can draw something called a Stippled Line which is basically a dashed line with some extra control over [...]]]></description>
			<content:encoded><![CDATA[<p>I was only going to write 3 Bing Maps 3D posts (they start <a href="http://code.cheesydesign.com/?p=587">Here</a>), but today I added something that I thought was rather cool.</p>
<p>You can download the source code for this post here <a href="http://code.cheesydesign.com/wp-content/uploads/2010/05/3DViewerBingMaps.zip">3DViewerBingMaps.zip</a></p>
<p>In OpenGL you can draw something called a Stippled Line which is basically a dashed line with some extra control over the dash pattern, however in Bing Maps 3D there is no such thing, which is why I wrote my own dashed line mesh class. My class supports the following things:</p>
<p>- Lines are made up of multiple segments<br />
- Dashes and gaps between dashes are independent in size<br />
- You can set an offset each frame allowing for a moving ant effect<br />
- You can set different widths for the start and the end of the line</p>
<p>Here’s 2 pictures of the same line showing the billboard effect of the wide dashes, and the constant dash and gap size:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="DashedLine1" src="http://code.cheesydesign.com/wp-content/uploads/2010/05/DashedLine1.png" border="0" alt="DashedLine1" width="600" height="496" /></p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="DashedLine2" src="http://code.cheesydesign.com/wp-content/uploads/2010/05/DashedLine2.png" border="0" alt="DashedLine2" width="600" height="496" /></p>
<p>If you download the sample at the top of this post you can run the application shown in the screenshots.</p>
<p>Here’s the code snippet for setting up the above Dashed Mesh:</p>
<pre class="sh_csharp">DashedLineMesh dashedLine = new DashedLineMesh();

dashedLine.DashLength = 8;
dashedLine.GapLength = 16;
dashedLine.LineStartWidth = 1;
dashedLine.LineEndWidth = 64;
dashedLine.Color = Color.White;
dashedLine.ZBufferEnable = true;

dashedLine.Points.Clear();
GeodeticViewpoint centrePoint = new GeodeticViewpoint();
double alt = 1000000;
double lat = 45.0;
double lon = 180.0;

for(double i = 0; i&lt;(Math.PI*2); i+=0.103)
{
  double x = 8+30 * Math.Sin(i);
  double y = 8+30 * Math.Cos(i);
  centrePoint.Position.Location = LatLonAlt.CreateUsingDegrees(lat+x, lon+y, alt);
  dashedLine.Points.Add(new Vector3F(centrePoint.Position.Vector));
}</pre>
<p>and as a bonus here’s the complete source code for the DashedLineMesh class</p>
<pre class="sh_csharp">// Dashed Line Mesh by John Stewien 2010

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.MapPoint.Rendering3D.GraphicsProxy;
using Microsoft.MapPoint.Geometry.VectorMath;
using Microsoft.MapPoint.Geometry;
using Microsoft.MapPoint.Graphics3D;
using Microsoft.MapPoint.Rendering3D.State;

namespace _3DViewerBingMaps.Plugin {

  /// &lt;summary&gt;
  /// Draws a multi-segment line that can be broken up into dashes
  /// &lt;/summary&gt;
  public class DashedLineMesh : MeshGraphicsObject&lt;Vertex.PositionOnly, ushort&gt; {

    // ************************************************************************
    // Private Fields
    // ************************************************************************
    #region Private Fields

    /// &lt;summary&gt;
    /// A list of points that make up the line to be drawn. Points are in
    /// Lat, Lon, Alt format.
    /// &lt;/summary&gt;
    private List&lt;Vector3F&gt; points;
    /// &lt;summary&gt;
    /// The starting width of the line in pixels
    /// &lt;/summary&gt;
    private float lineStartWidth = 1f;
    /// &lt;summary&gt;
    /// The ending width of the line in pixels
    /// &lt;/summary&gt;
    private float lineEndWidth = 1f;
    /// &lt;summary&gt;
    /// The length of the dashes in pixels
    /// &lt;/summary&gt;
    private float dashLength = 0f;
    /// &lt;summary&gt;
    /// the length of the gaps between the dashes in pixels
    /// &lt;/summary&gt;
    private float gapLength = 0f;
    /// &lt;summary&gt;
    /// The offset of the dahses in pixels. Incrementing this by .5 every frame
    /// gives a moving and effect.
    /// &lt;/summary&gt;
    private float dashOffset = 0f;
    /// &lt;summary&gt;
    /// Enable alpha blending for this mesh
    /// &lt;/summary&gt;
    private bool alphaEnable = false;
    /// &lt;summary&gt;
    /// Enable using the Depth Buffer for this mesh
    /// &lt;/summary&gt;
    private bool zBufferEnable = true;
    /// &lt;summary&gt;
    /// The color to draw this line in
    /// &lt;/summary&gt;
    private System.Drawing.Color color = System.Drawing.Color.White;

    #endregion Private Fields

    // ************************************************************************
    // Public Methods
    // ************************************************************************
    #region Public Methods

    /// &lt;summary&gt;
    /// Constructor
    /// &lt;/summary&gt;
    /// &lt;param name="radius"&gt;&lt;/param&gt;
    /// &lt;param name="material"&gt;&lt;/param&gt;
    /// &lt;param name="materialId"&gt;&lt;/param&gt;
    public DashedLineMesh()
      : base(GraphicsBufferUsage.Dynamic, GraphicsBufferUsage.Dynamic, 4, 4, true) {

      this.points = new List&lt;Vector3F&gt;();

      if (base.State.Materials.Count == 0) {
        base.State.Materials.Add(new Material());
      }
      base.ProjectionEnabled = false;
      this.UpdateRenderState();
    }

    /// &lt;summary&gt;
    /// Updates the graphic prior to rendering it in a frame. Needs to be
    /// called every frame.
    /// &lt;/summary&gt;
    /// &lt;param name="camera"&gt;&lt;/param&gt;
    /// &lt;param name="transform"&gt;&lt;/param&gt;
    /// &lt;remarks&gt;
    /// Unfortunately the GraphicsObject.UpdateInternalRenderObject method
    /// can't be overriden because of its "internal" protection, so this
    /// needs to be called every frame before the graphics is rendered
    /// &lt;/remarks&gt;
    public void PreRenderUpdate(CameraData camera, Matrix4x4D transform) {
      int width = camera.View.Size.Width;
      int height = camera.View.Size.Height;
      this.UpdateLineGeometry(width, height, transform*camera.Snapshot.TransformMatrix);
    }

    #endregion Public Methods

    // ************************************************************************
    // Private Methods
    // ************************************************************************
    #region Private Methods

    /// &lt;summary&gt;
    /// Calculates the required line width from the user specified value and the
    /// size of the display area
    /// &lt;/summary&gt;
    /// &lt;param name="deviceWidth"&gt;&lt;/param&gt;
    /// &lt;param name="deviceHeight"&gt;&lt;/param&gt;
    /// &lt;returns&gt;&lt;/returns&gt;
    private Vector3F GetWidth(float lineWidth, int deviceWidth, int deviceHeight) {
      float x = lineWidth / ((float)deviceWidth);
      float y = lineWidth / ((float)deviceHeight);
      Vector3F retVal = new Vector3F(x, y, 1f);
      return retVal;
    }

    /// &lt;summary&gt;
    /// Apply the position/scale tranform, and the projection transform to the points
    /// to convert them to screen coordinates
    /// &lt;/summary&gt;
    /// &lt;param name="projectionTransform"&gt;&lt;/param&gt;
    /// &lt;returns&gt;&lt;/returns&gt;
    private IList&lt;Vector3F&gt; TransformedPoints(Matrix4x4D projectionTransform) {
      List&lt;Vector3F&gt; list = new List&lt;Vector3F&gt;(this.points.Count);
      Matrix4x4D matrix = projectionTransform;
      foreach (Vector3F vectorf in this.points) {
        Vector4D vector = new Vector4D((double)vectorf.X, (double)vectorf.Y, (double)vectorf.Z, 1.0);
        vector = Vector4D.TransformCoordinate(ref vector, ref matrix);
        if (vector.W &gt; 0.0) {
          vector.MultiplyBy(1.0 / vector.W);
        } else {
          vector.MultiplyBy(1.0 / -vector.W);
        }
        list.Add(new Vector3F((float)vector.X, (float)vector.Y, (float)vector.Z));
      }
      return list;
    }

    /// &lt;summary&gt;
    /// This method takes all the solid lines and breaks them up into dashes
    /// &lt;/summary&gt;
    /// &lt;param name="lineList"&gt;&lt;/param&gt;
    /// &lt;param name="widthList"&gt;&lt;/param&gt;
    /// &lt;param name="deviceWidth"&gt;&lt;/param&gt;
    /// &lt;param name="deviceHeight"&gt;&lt;/param&gt;
    private bool ConvertToDashed(ref IList&lt;Vector3F&gt; lineList, ref IList&lt;float&gt; widthList, int deviceWidth, int deviceHeight) {
      this.dashOffset = dashOffset % (dashLength + gapLength);

      // Scale everything to viewport space
      float dashStep = 2 * this.dashLength / Math.Min(deviceWidth, deviceHeight);
      float gapStep = 2 * this.gapLength / Math.Min(deviceWidth, deviceHeight);
      float offsetStep = 2 * this.dashOffset / Math.Min(deviceWidth, deviceHeight);

      // Sanity check dashStep and gapStep
      if (dashStep &lt;= 0 || gapStep &lt;= 0) {
        return false;
      }

      // Calculate the initial conditions
      float remainder = offsetStep;
      bool doDash = remainder==0;
      if (remainder &gt; gapStep) {
        remainder -= gapStep;
        doDash = true;
      }

      bool doingJoin = false;

      List&lt;Vector3F&gt; dashedLineList = new List&lt;Vector3F&gt;();
      List&lt;float&gt; dashedWidthList = new List&lt;float&gt;();

      for (int i = 0; i &lt; (lineList.Count - 1); i++) {
        Vector3F fromPoint = lineList[i];
        Vector3F toPoint = lineList[i + 1];

        // Store the original line length. Used for calculating the line width later on.
        float lineLength = Vector3F.Distance(fromPoint, toPoint);

        // Clamp the line to the visible area otherwise a lot more calculation will be done
        // than is required
        if (ClampLineToBox(ref fromPoint, ref toPoint, new Vector2F(-1, -1), new Vector2F(1, 1))) {

          // Need to break up the line in the X-Y direction regardless of Z
          Vector2F segment = new Vector2F(toPoint.X - fromPoint.X, toPoint.Y - fromPoint.Y);
          float segLength = segment.Length();
          if (segLength &gt; 0) {

            float widthDiff = widthList[i + 1] - widthList[i];

            Vector3F step = new Vector3F(segment.X, segment.Y, toPoint.Z - fromPoint.Z) / segLength;

            float distTravelled = 0;
            float nextDash = remainder &gt; 0 ? remainder : dashStep;
            float nextgap = remainder &gt; 0 ? remainder : gapStep;

            // Calcluate the line width for the point we are starting at and
            // Calculate the line width increments for when we iterate over the dashes

            float invLineLength = 1f / lineLength;
            float progressiveWidth = widthList[i] + widthDiff * (remainder + Vector3F.Distance(fromPoint, lineList[i])) * invLineLength;
            float dashDWidth = widthDiff * dashStep * invLineLength;
            float gapDWidth = widthDiff * gapStep * invLineLength;

            // Keep on adding dashes until we reach the end of the line segment
            // Also calculate the line widths for each end of the dashes

            while (distTravelled &lt; segLength) {
              if (doDash) {
                if (doingJoin) {
                  dashedLineList.RemoveAt(dashedLineList.Count - 1);
                  dashedWidthList.RemoveAt(dashedWidthList.Count - 1);
                } else {
                  dashedLineList.Add(distTravelled * step + fromPoint);
                  dashedWidthList.Add(progressiveWidth);
                }

                doingJoin = false;

                distTravelled += nextDash;
                progressiveWidth += dashDWidth;

                dashedLineList.Add(Math.Min(segLength, distTravelled) * step + fromPoint);
                dashedWidthList.Add(progressiveWidth);

                if (distTravelled &gt; segLength &amp;&amp; i &lt; (lineList.Count - 2)) {
                  doingJoin = true;
                }
              } else {
                distTravelled += nextgap;
                progressiveWidth += gapDWidth;
              }
              doDash = !doDash;
              nextDash = dashStep;
              nextgap = gapStep;
            }
            remainder = distTravelled - segLength;
            if (remainder &gt; 0) {
              doDash = !doDash;
            }
          }
        } else {
          doingJoin = false;
        }
      }
      lineList = dashedLineList;
      widthList = dashedWidthList;
      return true;
    }

    /// &lt;summary&gt;
    /// Clamps the line between the 2 vectors passed to be within the box limits passed in.
    /// &lt;/summary&gt;
    /// &lt;param name="from"&gt;&lt;/param&gt;
    /// &lt;param name="to"&gt;&lt;/param&gt;
    /// &lt;param name="min"&gt;&lt;/param&gt;
    /// &lt;param name="max"&gt;&lt;/param&gt;
    /// &lt;returns&gt;
    /// true if the line is visible, false otherwise
    /// &lt;/returns&gt;
    private bool ClampLineToBox(ref Vector3F from, ref Vector3F to, Vector2F boxMin, Vector2F boxMax) {
      // need to limit everything to within -1 to 1 on all dimensions

      // Test if anything is inside the viewbox
      if (Math.Min(from.X, to.X) &gt; boxMax.X || Math.Max(from.X, to.X) &lt; boxMin.X ||
        Math.Min(from.Y, to.Y) &gt; boxMax.Y || Math.Max(from.Y, to.Y) &lt; boxMin.Y) {
        return false;
      }

      // Test if the line is completely contained in the viewbox
      if (Math.Min(from.X, to.X) &gt; boxMin.X &amp;&amp; Math.Max(from.X, to.X) &lt; boxMax.X &amp;&amp;
        Math.Min(from.Y, to.Y) &gt; boxMin.Y &amp;&amp; Math.Max(from.Y, to.Y) &lt; boxMax.Y) {
        return true;
      }

      ClampDestToBox(ref from, ref to, boxMin, boxMax);
      ClampDestToBox(ref to, ref from, boxMin, boxMax);

      return true;
    }

    /// &lt;summary&gt;
    /// Clamps the destination point to the box limits passed in
    /// &lt;/summary&gt;
    /// &lt;param name="from"&gt;&lt;/param&gt;
    /// &lt;param name="dest"&gt;&lt;/param&gt;
    /// &lt;param name="boxMin"&gt;&lt;/param&gt;
    /// &lt;param name="boxMax"&gt;&lt;/param&gt;
    private void ClampDestToBox(ref Vector3F from, ref Vector3F dest, Vector2F boxMin, Vector2F boxMax) {
      Vector3F diff = dest - from;

      if (dest.X &gt; boxMax.X) {
        dest = (boxMax.X - from.X) / diff.X * diff + from;
      } else if (dest.X &lt; boxMin.X) {
        dest = (boxMin.X - from.X) / diff.X * diff + from;
      }
      if (dest.Y &gt; boxMax.Y) {
        dest = (boxMax.Y - from.Y) / diff.Y * diff + from;
      } else if (dest.Y &lt; boxMin.Y) {
        dest = (boxMin.Y - from.Y) / diff.Y * diff + from;
      }
    }

    /// &lt;summary&gt;
    /// Updates the vertex and index buffer for rendering the line for the current viewpoint
    /// &lt;/summary&gt;
    /// &lt;param name="deviceWidth"&gt;&lt;/param&gt;
    /// &lt;param name="deviceHeight"&gt;&lt;/param&gt;
    /// &lt;param name="projectionTransform"&gt;&lt;/param&gt;
    private void UpdateLineGeometry(int deviceWidth, int deviceHeight, Matrix4x4D projectionTransform) {
      this.Indices.Clear();
      this.Vertices.Clear();

      // Get all the points in screen coordinates
      IList&lt;Vector3F&gt; list = this.TransformedPoints(projectionTransform);
      IList&lt;float&gt; widths = this.GetWidths(list);
      bool isDashed = this.ConvertToDashed(ref list, ref widths, deviceWidth, deviceHeight);
      for (int i = 0; i &lt; (list.Count - 1); i++) {
        Vector3F width1 = this.GetWidth(widths[i], deviceWidth, deviceHeight);
        Vector3F width2 = this.GetWidth(widths[i+1], deviceWidth, deviceHeight);
       
        Vector3F difference = list[i + 1] - list[i];
        Vector2F direction = Vector2F.Normalize(new Vector2F(difference.X, difference.Y));
        Vector3F perpendicular1 = new Vector3F(-direction.Y * width1.X, direction.X * width1.Y, 0f);
        Vector3F perpendicular2 = new Vector3F(-direction.Y * width2.X, direction.X * width2.Y, 0f);
        this.Vertices.AddData(new Vertex.PositionOnly(list[i] + perpendicular1));
        this.Vertices.AddData(new Vertex.PositionOnly(list[i] - perpendicular1));
        this.Vertices.AddData(new Vertex.PositionOnly(list[i+1] + perpendicular2));
        this.Vertices.AddData(new Vertex.PositionOnly(list[i+1] - perpendicular2));
        int num2 = i*2;
        ushort[] data = new ushort[] { (ushort)num2, (ushort)(num2 + 2), (ushort)(num2 + 3), (ushort)num2, (ushort)(num2 + 3), (ushort)(num2 + 1) };
        this.Indices.AddDataUnsafe(data, PrimitiveType.TriangleList, 0);
        if (isDashed)
          i++;
      }
    }

    /// &lt;summary&gt;
    /// Creates a list of widths for the points passed in.
    /// &lt;/summary&gt;
    /// &lt;param name="list"&gt;&lt;/param&gt;
    /// &lt;returns&gt;&lt;/returns&gt;
    private IList&lt;float&gt; GetWidths(IList&lt;Vector3F&gt; list) {
      float[] progressiveLength = new float[list.Count];
      float totalLength = 0;
      for (int i = 0; i &lt; (list.Count-1); ++i) {
        progressiveLength[i] = totalLength;
        totalLength += Vector3F.Distance(list[i], list[i + 1]);
      }
      progressiveLength[list.Count - 1] = totalLength;

      if (totalLength &gt; 0) {
        float widthDiff = lineEndWidth - lineStartWidth;
        float invTotalLength = 1f/totalLength;
        for (int i = 0; i &lt; progressiveLength.Length; ++i) {
          progressiveLength[i] = lineStartWidth + widthDiff * progressiveLength[i] * invTotalLength;
        }
      }

      return progressiveLength;
    }

    /// &lt;summary&gt;
    /// Updates the colors, depth buffer, and alpha settings for rendering the mesh
    /// &lt;/summary&gt;
    private void UpdateRenderState() {
      RenderState renderState = base.State.RenderState;
      if (this.alphaEnable) {
        renderState.Alpha.Enabled = true;
        renderState.Alpha.SourceBlend = Blend.SourceAlpha;
        renderState.Alpha.DestinationBlend = Blend.InvSourceAlpha;
      } else {
        renderState.Alpha.Enabled = false;
      }
      renderState.Lighting.Enabled = false;
      renderState.Cull.Enabled = false;
      renderState.Stages[0].Blending.AlphaArgument1 = TextureArgument.TFactor;
      renderState.Stages[0].Blending.AlphaOperation = TextureOperation.SelectArg1;
      renderState.Stages[0].Blending.ColorArgument1 = TextureArgument.TFactor;
      renderState.Stages[0].Blending.ColorOperation = TextureOperation.SelectArg1;
      renderState.Stages[1].Enabled = false;
      renderState.TextureFactor.Value = this.color;
      renderState.ZBuffer.Enabled = zBufferEnable;
      renderState.ZBuffer.ZBufferFunction = Compare.Less;
    }

    #endregion Private Methods

    // ************************************************************************
    // Properties
    // ************************************************************************
    #region Properties

    /// &lt;summary&gt;
    /// A list of points that make up the line to be drawn. Points are in
    /// Lat, Lon, Alt format.
    /// &lt;/summary&gt;
    public List&lt;Vector3F&gt; Points {
      get {
        return points;
      }
    }

    /// &lt;summary&gt;
    /// Gets and Sets the starting width of the line in pixels
    /// &lt;/summary&gt;
    public float LineStartWidth {
      get {
        return this.lineStartWidth;
      }
      set {
        if (value &lt;= 0f) {
          throw new ArgumentOutOfRangeException("value");
        }
        this.lineStartWidth = value;
      }
    }

    /// &lt;summary&gt;
    /// Gets and Sets the end width of the line in pixels
    /// &lt;/summary&gt;
    public float LineEndWidth {
      get {
        return this.lineEndWidth;
      }
      set {
        if (value &lt;= 0f) {
          throw new ArgumentOutOfRangeException("value");
        }
        this.lineEndWidth = value;
      }
    }

    /// &lt;summary&gt;
    /// Gets and Sets the length of the dashes in pixels
    /// &lt;/summary&gt;
    public float DashLength {
      get {
        return dashLength;
      }
      set {
        if (value &lt; 0f) {
          throw new ArgumentOutOfRangeException("value");
        }
        dashLength = value;
      }
    }

    /// &lt;summary&gt;
    /// Gets and Sets the length of the gaps between the dashes in pixels
    /// &lt;/summary&gt;
    public float GapLength {
      get {
        return gapLength;
      }
      set {
        if (value &lt; 0f) {
          throw new ArgumentOutOfRangeException("value");
        }
        gapLength = value;
      }
    }

    /// &lt;summary&gt;
    /// Gets and Sets the offset of the dashes in pixels.
    /// &lt;/summary&gt;
    /// &lt;remarks&gt;
    ///  Incrementing this by .5 every frame gives a moving ant effect.
    /// &lt;/remarks&gt;
    public float DashOffset {
      get {
        return dashOffset;
      }
      set {
        if (value &lt; 0f) {
          throw new ArgumentOutOfRangeException("value");
        }
        dashOffset = value;
      }
    }

    /// &lt;summary&gt;
    /// Gets and Sets if alpha blending is enabled for this line
    /// &lt;/summary&gt;
    public bool AlphaEnable {
      get {
        return this.alphaEnable;
      }
      set {
        if (this.alphaEnable != value) {
          this.alphaEnable = value;
          this.UpdateRenderState();
        }
      }
    }

    /// &lt;summary&gt;
    /// Gets and Sets if the Depth Buffer is enabled for this mesh
    /// &lt;/summary&gt;
    public bool ZBufferEnable {
      get {
        return this.zBufferEnable;
      }
      set {
        if (this.zBufferEnable != value) {
          this.zBufferEnable = value;
          this.UpdateRenderState();
        }
      }
    }

    /// &lt;summary&gt;
    /// Gets and Sets the color to draw this line in
    /// &lt;/summary&gt;
    public System.Drawing.Color Color {
      get {
        return this.color;
      }
      set {
        if (this.color != value) {
          this.color = value;
          this.UpdateRenderState();
        }
      }
    }

    #endregion Properties
  }
}</pre>
<script type="text/javascript" src="/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_csharp.js"></script><script type="text/javascript" src="/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_csharp.js"></script>]]></content:encoded>
			<wfw:commentRss>http://code.cheesydesign.com/?feed=rss2&amp;p=640</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rendering an un-parented WPF Visual to a bitmap</title>
		<link>http://code.cheesydesign.com/?p=629</link>
		<comments>http://code.cheesydesign.com/?p=629#comments</comments>
		<pubDate>Mon, 31 May 2010 15:30:00 +0000</pubDate>
		<dc:creator>JohnStewien</dc:creator>
				<category><![CDATA[c#]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[WPF]]></category>

		<guid isPermaLink="false">http://code.cheesydesign.com/?p=629</guid>
		<description><![CDATA[The source code for this post can be found here ParentlessButton.zip
A co-worker had a problem today and asked for my help. He was using the Chart control from the WPF Toolkit and wanted to render it to a bitmap and save it to a file without actually adding the Chart to the visual tree. There [...]]]></description>
			<content:encoded><![CDATA[<p>The source code for this post can be found here <a href="http://code.cheesydesign.com/wp-content/uploads/2010/05/ParentlessButton.zip">ParentlessButton.zip</a></p>
<p>A co-worker had a problem today and asked for my help. He was using the Chart control from the <a href="http://wpf.codeplex.com/">WPF Toolkit</a> and wanted to render it to a bitmap and save it to a file without actually adding the Chart to the visual tree. There are plenty of samples on how to render a WPF Visual to a bitmap, including <a href="http://johnstewien.spaces.live.com/blog/cns!E6885DB5CEBABBC8!136.entry">This One</a> that I wrote 4 years ago, but they don’t seem to render if the Visual isn’t a child Visual in a WPF visual tree. The reason for this failure to render is because the Visual isn’t told what size container it has to fill and so the ActualWidth and ActualHeight properties are zero.</p>
<p>So how to get around this? We need to perform the same setup that a panel does on the Visual. If we look at the <a href="http://msdn.microsoft.com/en-us/library/ms754152.aspx#Panels_custom_panel_elements">MSDN Documentation For Custom Panels</a> we will find this code:</p>
<pre class="sh_csharp">public class PlotPanel : Panel
{
    // Default public constructor
    public PlotPanel()
        : base()
    {
    }

    // Override the default Measure method of Panel
    protected override Size MeasureOverride(Size availableSize)
    {
        Size panelDesiredSize = new Size();

        // In our example, we just have one child.
        // Report that our panel requires just the size of its only child.
        foreach (UIElement child in InternalChildren)
        {
            child.Measure(availableSize);
            panelDesiredSize = child.DesiredSize;
        }

        return panelDesiredSize ;
    }
    protected override Size ArrangeOverride(Size finalSize)
    {
        foreach (UIElement child in InternalChildren)
        {
            double x = 50;
            double y = 50;

            child.Arrange(new Rect(new Point(x, y), child.DesiredSize));
        }
        return finalSize; // Returns the final Arranged size
    }
}</pre>
<p>Looking at the code above we can see that the methods Measure(Size size) and Arrange(Size size) are called on the child Visuals. Here is some sample code inside an event handler to show how it is done:</p>
<pre class="sh_csharp">private void button1_Click(object sender, RoutedEventArgs e) {

  Button button = new Button();
  button.Content = "Parentless Button";
  double width = 200;
  double height = 200;
  button.Width = width;
  button.Height = height;

  // Cure for getting an ActualWidth and ActualHeight of 0
  button.Measure(new Size(Double.PositiveInfinity,
                         Double.PositiveInfinity));
  button.Arrange(new Rect(button.DesiredSize));

  RenderTargetBitmap rtb = new RenderTargetBitmap((int)width, (int)height, 96.0, 96.0, PixelFormats.Pbgra32);
  rtb.Render(button);
  this.image1.Source = rtb;
}</pre>
<p>You will also find a link at the top to the source code for a sample application that demonstrates rendering an un-parented Button to a Bitmap, and then displaying that Bitmap. When you run the application and click the “Test” button it will look like this:</p>
<p><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="ParentlessButton" src="http://code.cheesydesign.com/wp-content/uploads/2010/05/ParentlessButton.png" border="0" alt="ParentlessButton" width="400" height="400" /></p>
<p>The “Parentless Button” isn’t a button, but just a Bitmap displayed in an image control.</p>
<script type="text/javascript" src="/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_csharp.js"></script><script type="text/javascript" src="/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_csharp.js"></script>]]></content:encoded>
			<wfw:commentRss>http://code.cheesydesign.com/?feed=rss2&amp;p=629</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Bing Maps 3D &#8211; Clipping shapes with an imposter Earth</title>
		<link>http://code.cheesydesign.com/?p=616</link>
		<comments>http://code.cheesydesign.com/?p=616#comments</comments>
		<pubDate>Wed, 26 May 2010 15:33:00 +0000</pubDate>
		<dc:creator>JohnStewien</dc:creator>
				<category><![CDATA[c#]]></category>
		<category><![CDATA[Bing Maps]]></category>
		<category><![CDATA[C#]]></category>

		<guid isPermaLink="false">http://code.cheesydesign.com/?p=616</guid>
		<description><![CDATA[The final source code for these Bing Maps 3D posts can be found here 3DViewerBingMaps.zip. You will also need to install Bing Maps 3D from Microsoft.
This is the 3rd part of my posts on Bing Maps 3D. The 3 parts are:
- Adding Arbitrary Shapes. Creating a Cube mesh and a Sphere mesh. 
- Rendering shapes [...]]]></description>
			<content:encoded><![CDATA[<p>The final source code for these Bing Maps 3D posts can be found here <a href="http://code.cheesydesign.com/wp-content/uploads/2010/05/3DViewerBingMaps.zip">3DViewerBingMaps.zip</a>. You will also need to install Bing Maps 3D from Microsoft.</p>
<p>This is the 3rd part of my posts on Bing Maps 3D. The 3 parts are:</p>
<p><a title="http://code.cheesydesign.com/?p=587" href="http://code.cheesydesign.com/?p=587">- Adding Arbitrary Shapes. Creating a Cube mesh and a Sphere mesh. </a><br />
<a href="http://code.cheesydesign.com/?p=604">- Rendering shapes past the Far Clip. How to render shapes whose coordinates are outside the View Port.</a><br />
<a href="http://code.cheesydesign.com/?p=616">- Clipping shapes with an imposter Earth.</a></p>
<p>In the previous Bing Maps 3D post we had overcome the problem of 3D objects being clipped by the far plane on the horizon, but now we had the problem that they weren’t being clipped by the earth as seen for the yellow cube in the picture below:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Untitled7" src="http://code.cheesydesign.com/wp-content/uploads/2010/05/Untitled7.png" border="0" alt="Untitled7" width="600" height="531" /></p>
<p>The solution to this is to create another sphere to imitate the earth, but smaller and closer to the camera. The sphere should be scaled down by the same factor that the cube is scaled down when it is brought closer to the camera. The sphere rendered for the Earth in Bing Maps 3D isn’t an exact sphere, it is a little bit squashed, so to make sure we get the same shape we measure the earth from within Bing Maps 3D and apply those measurements to our sphere. Here’s where we use the SetToReplaceEarth() method that I included in the Sphere Mesh code in the first post which looks like this:</p>
<pre class="sh_csharp">/// &lt;summary&gt;
/// Scales and positions this sphere such that it replaces the earth
/// &lt;/summary&gt;
public void SetToReplaceEarth() {
  Microsoft.MapPoint.Rendering3D.Cameras.GeodeticViewpoint view = new Microsoft.MapPoint.Rendering3D.Cameras.GeodeticViewpoint();
  Vector3D[] vecs = new Vector3D[6];
  view.Position.Location = LatLonAlt.CreateUsingDegrees(0, 0, 0);
  vecs[0] = view.Position.Vector;

  view.Position.Location = LatLonAlt.CreateUsingDegrees(0,180, 0);
  vecs[1] = view.Position.Vector;

  view.Position.Location = LatLonAlt.CreateUsingDegrees(-90, 0, 0);
  vecs[2] = view.Position.Vector;

  view.Position.Location = LatLonAlt.CreateUsingDegrees(90, 0, 0);
  vecs[3] = view.Position.Vector;

  view.Position.Location = LatLonAlt.CreateUsingDegrees(0, 90, 0);
  vecs[4] = view.Position.Vector;

  view.Position.Location = LatLonAlt.CreateUsingDegrees(0, -90, 0);
  vecs[5] = view.Position.Vector;

  Vector3D average = new Vector3D(0, 0, 0);
  Vector3D min = new Vector3D(double.MaxValue, double.MaxValue, double.MaxValue);
  Vector3D max = new Vector3D(double.MinValue, double.MinValue, double.MinValue);

  for (int i = 0; i &lt; vecs.Length; ++i) {
    average.Add(vecs[i]);
    min = min.Min(vecs[i]);
    max = max.Max(vecs[i]);
  }
  average.MultiplyBy(1.0 / 6.0);

  this.Position = average;

  Vector3D diff = max.Subtract(min);
  diff.MultiplyBy(0.5 / radius);
  this.Scale = diff;

}</pre>
<p>We put this sphere into the scene at 0,0,0, and to make it visible I will give it a very transparent yellow color. Here’s the result:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Untitled9" src="http://code.cheesydesign.com/wp-content/uploads/2010/05/Untitled9.png" border="0" alt="Untitled9" width="600" height="496" /></p>
<p>So it’s working now right? Well not quite, you see I’ve drawn the sphere above to have 20 stacks, 20 slices, so it’s not a very high resolution mesh, so when you get lower the clip is quite a bit under the surface. In the image below the yellow line should stop at the same place as the red cube does:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Untitled10" src="http://code.cheesydesign.com/wp-content/uploads/2010/05/Untitled10.png" border="0" alt="Untitled10" width="600" height="496" /></p>
<p>Easy fix right? Lets change the imitation Earth to a 200&#215;200 mesh:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Untitled8" src="http://code.cheesydesign.com/wp-content/uploads/2010/05/Untitled8.png" border="0" alt="Untitled8" width="600" height="496" /></p>
<p>What happened? Well the old DirectX cards could only handle a 16 bit Index Buffer , which is what we set up our sphere mesh as when we declared it like this:</p>
<pre class="sh_csharp">public class SphereMesh : MeshGraphicsObject&lt;Vertex.PositionNormal, ushort&gt;{
}</pre>
<p>Fortunately for me my video card can handle a 32 bit index buffer, so I change the code throughout to have uint instead of ushort and now it works fine and the error in the clip at low altitude is improved:</p>
<p><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Untitled11" src="http://code.cheesydesign.com/wp-content/uploads/2010/05/Untitled11.png" border="0" alt="Untitled11" width="600" height="496" /></p>
<p>This wraps up my 3 part series on adding 3D Meshes to Bing Maps 3D. Enjoy playing with the sample application attached at the top of all 3 articles.</p>
<script type="text/javascript" src="/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_csharp.js"></script><script type="text/javascript" src="/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_csharp.js"></script>]]></content:encoded>
			<wfw:commentRss>http://code.cheesydesign.com/?feed=rss2&amp;p=616</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Bing Maps 3D &#8211; Rendering shapes past the Far Clip</title>
		<link>http://code.cheesydesign.com/?p=604</link>
		<comments>http://code.cheesydesign.com/?p=604#comments</comments>
		<pubDate>Mon, 24 May 2010 15:30:00 +0000</pubDate>
		<dc:creator>JohnStewien</dc:creator>
				<category><![CDATA[c#]]></category>
		<category><![CDATA[Bing Maps]]></category>
		<category><![CDATA[C#]]></category>

		<guid isPermaLink="false">http://code.cheesydesign.com/?p=604</guid>
		<description><![CDATA[The final source code for these Bing Maps 3D posts can be found here 3DViewerBingMaps.zip
This is the 2nd part of my posts on Bing Maps 3D. The 3 parts are:
- Adding Arbitrary Shapes. Creating a Cube mesh and a Sphere mesh. 
- Rendering shapes past the Far Clip. How to render shapes whose coordinates are [...]]]></description>
			<content:encoded><![CDATA[<p>The final source code for these Bing Maps 3D posts can be found here <a href="http://code.cheesydesign.com/wp-content/uploads/2010/05/3DViewerBingMaps.zip">3DViewerBingMaps.zip</a></p>
<p>This is the 2nd part of my posts on Bing Maps 3D. The 3 parts are:</p>
<p><a title="http://code.cheesydesign.com/?p=587" href="http://code.cheesydesign.com/?p=587">- Adding Arbitrary Shapes. Creating a Cube mesh and a Sphere mesh. </a><br />
<a href="http://code.cheesydesign.com/?p=604">- Rendering shapes past the Far Clip. How to render shapes whose coordinates are outside the View Port.</a><br />
<a href="http://code.cheesydesign.com/?p=616">- Clipping shapes with an imposter Earth.</a></p>
<p>In the previous part we discovered a problem with rendering large shapes on the Earth in Bing Maps that the far clip plane is at the horizon, and so anything drawn past that is clipped, as is seen happening to far corner of the red cube in the screenshot below:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Untitled4" src="http://code.cheesydesign.com/wp-content/uploads/2010/05/Untitled4.jpg" border="0" alt="Untitled4" width="600" height="531" /></p>
<p>To fix this we need to move the cube towards the camera, and shrink it so that the whole cube is in front of the far clip plane, but looks the same. Here’s a diagram showing what we need to do:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Untitled6" src="http://code.cheesydesign.com/wp-content/uploads/2010/05/Untitled6.png" border="0" alt="Untitled6" width="600" height="453" /></p>
<p>The red square in the diagram shows the normal cube being clipped by the far clip plane, and the yellow square shows the fixed version. The blue circle is the camera, and the blue lines are the rays cast from the camera. As you can see from the cameras point of view the yellow square looks to be in the same position as the red square, but it is closer to the camera.</p>
<p>To implement this I wrote a method in my Bing Maps 3D Actor called MoveTowardCamera. This method sets up a post render transform to apply to the cube to move it towards the camera. Strangely the post transform in Bing Maps gets applied before the object is positioned, as I need to know where the object is in order to move it toward the camera, I first translate it to its set position, scale it down, then move it towards the camera in proportion to it’s scale. Here’s the code to do this:</p>
<pre class="sh_csharp">
public static void MoveTowardCamera(WorldGraphicsObject mesh, double scale, SceneState sceneState)
{
  CameraData camera = null;

  if (sceneState.TryGetData&lt;CameraData&gt;(out camera))
  {
    // Calculate a transform that moves the object closer
    // to the camera, but scales it down so it appears
    // to be the same size

    Vector3D cameraPos = camera.Snapshot.Position.Vector;
    Vector3D meshPos = mesh.Position;

    // Transform works about the centre of an object, so to work properly
    // need to move to position, apply scaling towards camera, and then move back

    Matrix4x4D postTransform = Matrix4x4D.Translation(meshPos);
    postTransform.Multiply(Matrix4x4D.Scaling(scale, scale, scale));
    postTransform.Multiply(Matrix4x4D.Translation(cameraPos * (1 - scale)));
    postTransform.Multiply(Matrix4x4D.Translation(-meshPos));

    mesh.PostTransform = postTransform;
  }
}</pre>
<p>Here’s how it looks in 3D:</p>
<p>   <img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Untitled7" src="http://code.cheesydesign.com/wp-content/uploads/2010/05/Untitled7.png" border="0" alt="Untitled7" width="600" height="531" /></p>
<p>The red cube is being clipped by the far clip plane, and the yellow cube is closer to the camera but overlays the red cube correctly. The problem now is that the yellow frame isn’t being clipped by the Earth as it is much closer than the Earth. In my next post I will show how to get the yellow cube to be clipped by the Earth.</p>
<script type="text/javascript" src="/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_csharp.js"></script>]]></content:encoded>
			<wfw:commentRss>http://code.cheesydesign.com/?feed=rss2&amp;p=604</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Convert UTF-8 to Unicode C#</title>
		<link>http://code.cheesydesign.com/?p=591</link>
		<comments>http://code.cheesydesign.com/?p=591#comments</comments>
		<pubDate>Wed, 19 May 2010 17:00:09 +0000</pubDate>
		<dc:creator>AndrewCocks</dc:creator>
				<category><![CDATA[c#]]></category>
		<category><![CDATA[unicode]]></category>
		<category><![CDATA[utf-8]]></category>

		<guid isPermaLink="false">http://code.cheesydesign.com/?p=591</guid>
		<description><![CDATA[I recently needed to convert a large file from UTF-8 to Unicode.  While Notepad actually does a pretty good job of this I wanted it to fit within an automated build script.  After looking around on the web for a while the only thing I found took several minutes to convert a 6MB [...]]]></description>
			<content:encoded><![CDATA[<p>I recently needed to convert a large file from UTF-8 to <a href="http://www.joelonsoftware.com/articles/Unicode.html" title="The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)">Unicode</a>.  While Notepad actually does a pretty good job of this I wanted it to fit within an <a href="http://www.joelonsoftware.com/articles/fog0000000043.html" title="2. Can you make a build in one step?">automated build script</a>.  After looking around on the web for a while the only thing I found took several minutes to convert a 6MB file and got the conversion wrong too.  So I decided to write my own.  The built-in Encoding.Convert function in C# makes things rather easy.  However I wanted my app to be scalable to handle any size file so I couldn&#8217;t just read the whole thing into memory, convert and then write to disk.  I needed to read it into a buffer a chunk at a time, convert it and then write it.  This would decrease the total memory needed to a fixed amount and benefit from both read-ahead caching and Windows write caching.  This is made slightly tricky by the UTF-8 format itself where a single character can be encoded in between one and four bytes.  Any arbitrary sized buffer would chop some characters in half and they wouldn&#8217;t be encoded properly.  So I needed a solution which would:<br />
1)  Read in a fixed amount<br />
2)  Figure out where the last complete character ended<br />
3)  Encode only up until that point<br />
4)  Move whatever half characters were left to the front of the buffer<br />
5)  Repeat</p>
<p>The function to find the end of the last complete character (and thus how many extra bytes are left over) is cntExtraBytes and it takes the last three bytes as parameters to check as that&#8217;s the maximum number of bytes that could possible be a piece of a character.  The rules are derived from the wikipedia&#8217;s description of the <a href="http://en.wikipedia.org/wiki/UTF-8#Description">UTF-8 standard</a> of which bytes start two, three and four byes sequences.  I&#8217;ve put in a few ASSERTs to help clarify what the possible values are of each byte.</p>
<pre class="sh_csharp">
using System;
using System.Linq;
using System.Text;
using System.IO;

namespace UTF8_to_Unicode
{
    class Program
    {
        // UTF-8 is encoded in up to 4 bytes, need to make sure we don't chop a sequence in half
        // 240+: First in a 4 byte sequence
        // 224+: 3 byte sequence
        // 194+: 2 byte sequence
        // 128+: Part of a multi-byte sequence
        // 128-: Not part of a multi-byte sequence
        private static int cntExtraBytes(byte c3, byte c2, byte c1)
        {
            if (c1 < 128) return 0;

            if (c1 >= 192) return 1;

            System.Diagnostics.Debug.Assert(c1 >= 128);
            System.Diagnostics.Debug.Assert(c2 >= 128);
            System.Diagnostics.Debug.Assert(c3 >= 128);

            System.Diagnostics.Debug.Assert( 192 >= c1 &#038;&#038; c1 <= 224);

            if (c2 >= 224) return 2;
            if (c2 >= 192) return 0;

            if (c3 >= 240) return 3;
            if (c3 >= 224) return 0;

            System.Diagnostics.Debug.Assert(c3 <= 192);

            return 0;
        }

        static void Main(string[] args)
        {
            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            System.Diagnostics.Stopwatch swRead = new System.Diagnostics.Stopwatch();
            System.Diagnostics.Stopwatch swEncode = new System.Diagnostics.Stopwatch();
            System.Diagnostics.Stopwatch swWrite = new System.Diagnostics.Stopwatch();
            sw.Start();

            if (args.Count() != 3)
            {
                Console.Out.WriteLine("Usage: buffer_size(kb) UTF8_in Unicode_out");
                Console.Out.WriteLine("Doesn't work for files in excess of 2GB");
                System.Environment.Exit(0);
            }

            FileStream fs = new FileStream(args[0], FileMode.Open, FileAccess.Read, FileShare.None, 1, true);
            FileStream fs_out = new FileStream(args[1], FileMode.CreateNew, FileAccess.Write, FileShare.None,1,true);

            int total = (int)fs.Length;
            int cBytesOut = 0, cBytesIn = 0, cExtraBytes = 0, cLength = 0;
            int piece = Int32.Parse(args[2]) * 1024;
            Console.Out.Write(piece.ToString() + ",");

            byte[] bytes_in = new byte[piece+3];
            byte[] bytes_out = null;

            do
            {
                swRead.Start();

                cLength = fs.Read(bytes_in, cExtraBytes, piece) + cExtraBytes;

                cExtraBytes = cntExtraBytes(bytes_in[cLength - 3], bytes_in[cLength - 2], bytes_in[cLength - 1]);

                swRead.Stop();

                swEncode.Start();
                bytes_out = Encoding.Convert(Encoding.UTF8, Encoding.Unicode, bytes_in, 0, cLength - cExtraBytes);
                swEncode.Stop();

                if (cExtraBytes > 0)
                {
                    Buffer.BlockCopy(bytes_in, cLength - cExtraBytes, bytes_in, 0, cExtraBytes);
                }

                swWrite.Start();
                fs_out.Write(bytes_out, 0, bytes_out.Count());
                swWrite.Stop();

                cBytesOut += bytes_out.Count();
                cBytesIn += piece;
            }
            while (total > cBytesIn);

            fs.Close();
            fs_out.Close();

            sw.Stop();

            Console.Out.Write(total.ToString() + "," + cBytesOut.ToString() + ",");

            Console.Out.Write((sw.ElapsedMilliseconds / 1000.0).ToString() + ",");
            Console.Out.Write((swRead.ElapsedMilliseconds / 1000.0).ToString() + ",");
            Console.Out.Write((swEncode.ElapsedMilliseconds / 1000.0).ToString() + ",");
            Console.Out.WriteLine((swWrite.ElapsedMilliseconds / 1000.0).ToString());
        }
    }
}
</pre>
<p>As you can see there&#8217;s a lot of timing code in there and when run it shows that the reading and writing takes a suspiciously low amount of time, exceeding the throughput of the disks which tells us that it benefiting from both read and write caching.</p>
<p>Interestingly caching makes it rather difficult to accurately measure the performance of your disks but you can use the free version of <a href="http://www.hdtune.com/download.html">HDTune</a> or if you want something with source code then <a href="http://research.microsoft.com/en-us/um/siliconvalley/projects/sequentialio/">diskspd</a> from Microsoft Research.  Both return comparable results but HDTune is more comprehensive and provides pretty graphics.</p>
<p>The program takes three parameters, the first is buffer size in kb, and changing that parameter can greatly affect the performance with larger buffers performing better.  A run with a 256kb buffer size takes only 0.1 secs to read a 6MB file, convert it and write out the resultant 10MB file:</p>
<pre class=console>
C:\data>UTF8_to_Unicode.exe 256 input.u8 output.u16
262144,6152243,10391224,0.1,0.011,0.051,0.035
</pre>
<p>So there it is, fast enough, runnable from a build script and uses only a fixed amount of memory.</p>
<p>Warning: There is no error handling or checking of input parameters of any kind.  You will need to add those in order to use this code.</p>
<script type="text/javascript" src="/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_csharp.js"></script>]]></content:encoded>
			<wfw:commentRss>http://code.cheesydesign.com/?feed=rss2&amp;p=591</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Bing Maps 3D &#8211; Adding Arbitrary Shapes</title>
		<link>http://code.cheesydesign.com/?p=587</link>
		<comments>http://code.cheesydesign.com/?p=587#comments</comments>
		<pubDate>Wed, 12 May 2010 15:30:00 +0000</pubDate>
		<dc:creator>JohnStewien</dc:creator>
				<category><![CDATA[c#]]></category>
		<category><![CDATA[3D Geometry]]></category>
		<category><![CDATA[Bing Maps]]></category>
		<category><![CDATA[C#]]></category>

		<guid isPermaLink="false">http://code.cheesydesign.com/?p=587</guid>
		<description><![CDATA[The final source code for these Bing Maps 3D posts can be found here 3DViewerBingMaps.zip
Recently I have been implementing a 3D Viewer application based on Bing Maps 3D which you can download from Here. From this work I have generated enough material for a few posts, they will be as follows:
- Adding Arbitrary Shapes. Creating [...]]]></description>
			<content:encoded><![CDATA[<p>The final source code for these Bing Maps 3D posts can be found here <a href="http://code.cheesydesign.com/wp-content/uploads/2010/05/3DViewerBingMaps.zip">3DViewerBingMaps.zip</a></p>
<p>Recently I have been implementing a 3D Viewer application based on Bing Maps 3D which you can download from <a href="http://www.microsoft.com/downloads/details.aspx?displaylang=en&amp;FamilyID=e9298080-50c4-4f2e-9fc4-4009074996ba" target="_blank">Here</a>. From this work I have generated enough material for a few posts, they will be as follows:</p>
<p><a title="http://code.cheesydesign.com/?p=587" href="http://code.cheesydesign.com/?p=587">- Adding Arbitrary Shapes. Creating a Cube mesh and a Sphere mesh. </a><br />
<a href="http://code.cheesydesign.com/?p=604">- Rendering shapes past the Far Clip. How to render shapes whose coordinates are outside the View Port.</a><br />
<a href="http://code.cheesydesign.com/?p=616">- Clipping shapes with an imposter Earth.</a></p>
<p>The work I’ve done started off with 2 samples that I got from <a href="http://blogs.msdn.com/virtualearth3d/archive/2008/09/25/current-samples.aspx" target="_blank">Here</a></p>
<p>Here is a screenshot of a translucent cube rendered onto the surface of the Earth:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Untitled" src="http://code.cheesydesign.com/wp-content/uploads/2010/05/Untitled.jpg" border="0" alt="Untitled" width="600" height="520" /></p>
<p>The cube is drawn by a plug-in that implements an “Actor” and is implemented as a MeshGraphicsObject. Here is the source code for the Cube Mesh which is fairly straight forward:</p>
<pre class="sh_csharp">
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.MapPoint.Rendering3D.GraphicsProxy;
using Microsoft.MapPoint.Geometry.VectorMath;
using Microsoft.MapPoint.Geometry;

namespace _3DViewerBingMaps.Plugin {

  /// &lt;summary&gt;
  /// This class is a Mesh for rendering a Cube
  /// &lt;/summary&gt;
  public class CubeMesh : MeshGraphicsObject&lt;Vertex.PositionNormal, ushort&gt; {

    #region Fields

    /// &lt;summary&gt;
    /// The material id for the material attached to this mesh
    /// &lt;/summary&gt;
    private int materialId;

    #endregion Private

    #region Methods

    /// &lt;summary&gt;
    /// Constructor that takes a material
    /// &lt;/summary&gt;
    /// &lt;param name="radius"&gt;&lt;/param&gt;
    /// &lt;param name="material"&gt;&lt;/param&gt;
    public CubeMesh(float radius, Material material) : this(radius, material, -1) { }

    /// &lt;summary&gt;
    /// Constructor that takes a material id
    /// &lt;/summary&gt;
    /// &lt;param name="radius"&gt;&lt;/param&gt;
    /// &lt;param name="materialId"&gt;&lt;/param&gt;
    public CubeMesh(float radius, int materialId) : this(radius, null, materialId) { }

    /// &lt;summary&gt;
    /// Constructor that takes a material and a material id. The material
    /// id is ignored if the material isn't equal to null.
    /// &lt;/summary&gt;
    /// &lt;param name="radius"&gt;&lt;/param&gt;
    /// &lt;param name="material"&gt;&lt;/param&gt;
    /// &lt;param name="materialId"&gt;&lt;/param&gt;
    public CubeMesh(float radius, Material material, int materialId)
      : base(GraphicsBufferUsage.Static, GraphicsBufferUsage.Static, 8, 36, true) {

      // Get the vertices and indices
      List&lt;Vector3F&gt; vertices = new List&lt;Vector3F&gt;();
      List&lt;ushort&gt; indices = new List&lt;ushort&gt;();
      CalculateVerticesIndicies(vertices, indices, radius);

      // Add the vertices to the mesh
      foreach (Vector3F vector in vertices) {
        this.Vertices.AddData(new Vertex.PositionNormal(vector.X, vector.Y, vector.Z, vector.X, vector.Y, vector.Z));
      }

      // Set up the material
      if (material != null) {
        this.materialId = this.Materials.Add(material);
      }
      else {
        this.materialId = materialId;
      }

      // Add the indices to the mesh as a list of triangles
      this.Indices.AddData(indices.ToArray(), PrimitiveType.TriangleList, this.materialId);

    }

    /// &lt;summary&gt;
    /// Calculates the vertices and the indices for the mesh
    /// &lt;/summary&gt;
    /// &lt;param name="vertices"&gt;&lt;/param&gt;
    /// &lt;param name="indices"&gt;&lt;/param&gt;
    /// &lt;param name="radius"&gt;&lt;/param&gt;
    protected virtual void CalculateVerticesIndicies(List&lt;Vector3F&gt; vertices, List&lt;ushort&gt; indices, float radius) {

      // Add all the corners of the cube
      vertices.Add(new Vector3F(-radius, -radius, -radius));
      vertices.Add(new Vector3F(-radius, -radius, radius));
      vertices.Add(new Vector3F(-radius, radius, -radius));
      vertices.Add(new Vector3F(-radius, radius, radius));
      vertices.Add(new Vector3F(radius, -radius, -radius));
      vertices.Add(new Vector3F(radius, -radius, radius));
      vertices.Add(new Vector3F(radius, radius, -radius));
      vertices.Add(new Vector3F(radius, radius, radius));

      // Build a triangle list for the above vertices
      indices.AddRange(new ushort[] {
        0, 2, 1,
        1, 2, 3,
        1, 3, 5,
        5, 3, 7,
        5, 7, 4,
        4, 7, 6,
        4, 6, 0,
        0, 6, 2,
        6, 7, 2,
        2, 7, 3,
        5, 4, 1,
        1, 4, 0
      });
    }

    #endregion Methods

    #region Properties

    /// &lt;summary&gt;
    /// Gets the material id
    /// &lt;/summary&gt;
    public int MaterialId {
      get {
        return this.materialId;
      }
    }

    #endregion Properties
  }
}

 </pre>
<p>That isn’t terribly exciting. What about a Sphere that looks like this:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Untitled2" src="http://code.cheesydesign.com/wp-content/uploads/2010/05/Untitled2.jpg" border="0" alt="Untitled2" width="600" height="496" /></p>
<p>The code for the Sphere Mesh is a bit more interesting:</p>
<pre class="sh_csharp">
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.MapPoint.Rendering3D.GraphicsProxy;
using Microsoft.MapPoint.Geometry.VectorMath;
using Microsoft.MapPoint.Geometry;
using Microsoft.MapPoint.Rendering3D;

namespace _3DViewerBingMaps.Plugin {

  /// &lt;summary&gt;
  /// This class is a mesh for rendering a sphere
  /// &lt;/summary&gt;
  public class SphereMesh : MeshGraphicsObject&lt;Vertex.PositionNormal, ushort&gt; {

    #region Fields

    /// &lt;summary&gt;
    /// The material id for the material attached to this mesh
    /// &lt;/summary&gt;
    private int materialId;
    /// &lt;summary&gt;
    /// The radius of the sphere
    /// &lt;/summary&gt;
    private float radius;

    #endregion Fields

    #region Methods

    /// &lt;summary&gt;
    /// Constructor that takes a material
    /// &lt;/summary&gt;
    /// &lt;param name="radius"&gt;&lt;/param&gt;
    /// &lt;param name="n"&gt;&lt;/param&gt;
    /// &lt;param name="material"&gt;&lt;/param&gt;
    public SphereMesh(float radius, int n, Material material) : this(radius, n, material, -1) { }

    /// &lt;summary&gt;
    /// Constructor that takes a material id
    /// &lt;/summary&gt;
    /// &lt;param name="radius"&gt;&lt;/param&gt;
    /// &lt;param name="n"&gt;&lt;/param&gt;
    /// &lt;param name="materialId"&gt;&lt;/param&gt;
    public SphereMesh(float radius, int n, int materialId) : this(radius, n, null, materialId) { }

    /// &lt;summary&gt;
    /// Constructor that takes a material and a material id. The material id is ignored
    /// if the material isn't null
    /// &lt;/summary&gt;
    /// &lt;param name="radius"&gt;&lt;/param&gt;
    /// &lt;param name="n"&gt;&lt;/param&gt;
    /// &lt;param name="material"&gt;&lt;/param&gt;
    /// &lt;param name="materialId"&gt;&lt;/param&gt;
    protected SphereMesh(float radius, int n, Material material, int materialId)
      : base(GraphicsBufferUsage.Static, GraphicsBufferUsage.Static, 4 * (2 * n * n + 3 * n + 1), 24 * (2 * n * n + 3 * n + 1), true) {

      this.radius = radius;

      // Get the indices and vertices
      List&lt;Vector3F&gt; vertices = new List&lt;Vector3F&gt;();
      List&lt;ushort&gt; indices = new List&lt;ushort&gt;();
      CalculateVerticesIndicies(vertices, indices, radius, n);

      // Add the vertices to the mesh
      foreach (Vector3F vector in vertices) {
        this.Vertices.AddData(new Vertex.PositionNormal(vector.X, vector.Y, vector.Z, vector.X, vector.Y, vector.Z));
      }

      // Set the material
      if (material != null) {
        this.materialId = this.Materials.Add(material);
      }
      else {
        this.materialId = materialId;
      }

      // Add the indices to the mesh as a list of triangles
      this.Indices.AddData(indices.ToArray(), PrimitiveType.TriangleList, this.materialId);

    }

    /// &lt;summary&gt;
    /// Calculates the vertices and indices for rendering this mesh
    /// &lt;/summary&gt;
    /// &lt;param name="vertices"&gt;&lt;/param&gt;
    /// &lt;param name="indices"&gt;&lt;/param&gt;
    /// &lt;param name="radius"&gt;&lt;/param&gt;
    /// &lt;param name="n"&gt;&lt;/param&gt;
    private static void CalculateVerticesIndicies(List&lt;Vector3F&gt; vertices, List&lt;ushort&gt; indices, float radius, int n) {
      double segmentRad = Math.PI / 2 / (n + 1);
      int numberOfSeparators = 4 * n + 4;

      for (int segmentNo = -n; segmentNo &lt;= n; segmentNo++) {
        double r_e = radius * Math.Cos(segmentRad * segmentNo);
        double y_e = radius * Math.Sin(segmentRad * segmentNo);

        for (int s = 0; s &lt;= (numberOfSeparators - 1); s++) {
          double z_s = r_e * Math.Sin(segmentRad * s) * (-1);
          double x_s = r_e * Math.Cos(segmentRad * s);
          vertices.Add(new Vector3F((float)x_s, (float)y_e, (float)z_s));
        }
      }
      vertices.Add(new Vector3F(0, radius, 0));
      vertices.Add(new Vector3F(0, -1 * radius, 0));

      for (int segmentNo = 0; segmentNo &lt; 2 * n; segmentNo++) {
        for (int i = 0; i &lt; numberOfSeparators; i++) {
          indices.Add((ushort)(segmentNo * numberOfSeparators + i));
          indices.Add((ushort)(segmentNo * numberOfSeparators + i +
                              numberOfSeparators));
          indices.Add((ushort)(segmentNo * numberOfSeparators + (i + 1) %
                              numberOfSeparators + numberOfSeparators));

          indices.Add((ushort)(segmentNo * numberOfSeparators + (i + 1) %
                              numberOfSeparators + numberOfSeparators));
          indices.Add((ushort)(segmentNo * numberOfSeparators +
                             (i + 1) % numberOfSeparators));
          indices.Add((ushort)(segmentNo * numberOfSeparators + i));
        }
      }

      for (int i = 0; i &lt; numberOfSeparators; i++) {
        indices.Add((ushort)((2 * n) * numberOfSeparators + i));
        indices.Add((ushort)(numberOfSeparators * (2 * n + 1)));
        indices.Add((ushort)((2 * n) * numberOfSeparators + (i + 1) %
                            numberOfSeparators));
      }

      for (int i = 0; i &lt; numberOfSeparators; i++) {
        indices.Add((ushort)(i));
        indices.Add((ushort)((i + 1) % numberOfSeparators));
        indices.Add((ushort)(numberOfSeparators * (2 * n + 1) + 1));
      }
    }

    /// &lt;summary&gt;
    /// Scales and positions this sphere such that it replaces the earth
    /// &lt;/summary&gt;
    public void SetToReplaceEarth() {
      Microsoft.MapPoint.Rendering3D.Cameras.GeodeticViewpoint view = new Microsoft.MapPoint.Rendering3D.Cameras.GeodeticViewpoint();
      Vector3D[] vecs = new Vector3D[6];
      view.Position.Location = LatLonAlt.CreateUsingDegrees(0, 0, 0);
      vecs[0] = view.Position.Vector;

      view.Position.Location = LatLonAlt.CreateUsingDegrees(0,180, 0);
      vecs[1] = view.Position.Vector;

      view.Position.Location = LatLonAlt.CreateUsingDegrees(-90, 0, 0);
      vecs[2] = view.Position.Vector;

      view.Position.Location = LatLonAlt.CreateUsingDegrees(90, 0, 0);
      vecs[3] = view.Position.Vector;

      view.Position.Location = LatLonAlt.CreateUsingDegrees(0, 90, 0);
      vecs[4] = view.Position.Vector;

      view.Position.Location = LatLonAlt.CreateUsingDegrees(0, -90, 0);
      vecs[5] = view.Position.Vector;

      Vector3D average = new Vector3D(0, 0, 0);
      Vector3D min = new Vector3D(double.MaxValue, double.MaxValue, double.MaxValue);
      Vector3D max = new Vector3D(double.MinValue, double.MinValue, double.MinValue);

      for (int i = 0; i &lt; vecs.Length; ++i) {
        average.Add(vecs[i]);
        min = min.Min(vecs[i]);
        max = max.Max(vecs[i]);
      }
      average.MultiplyBy(1.0 / 6.0);

      this.Position = average;

      Vector3D diff = max.Subtract(min);
      diff.MultiplyBy(0.5 / radius);
      this.Scale = diff;

    }

    #endregion Methods

    #region Properties

    /// &lt;summary&gt;
    /// Gets the material id for the material attached to this mesh
    /// &lt;/summary&gt;
    public int MaterialId {
      get {
        return materialId;
      }
    }

    #endregion Properties
  }
}

 </pre>
<p>You might notice that there is a method in the Sphere mesh class called SetToImitateEarth(). I will use that in 2 posts time.</p>
<p>One of the problems with these shapes though is that as we get closer to the ground the <a href="http://en.wikipedia.org/wiki/Clipping_(computer_graphics)" target="_blank">Far-Clip-Plane</a> in Bing Maps 3D gets closer and cuts off the back of our shape as seen in this screenshot:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Untitled3" src="http://code.cheesydesign.com/wp-content/uploads/2010/05/Untitled3.jpg" border="0" alt="Untitled3" width="600" height="496" /> </p>
<p>In my next Bing Maps 3D article I will show how to get around this limitation.</p>
<script type="text/javascript" src="/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_csharp.js"></script><script type="text/javascript" src="/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_csharp.js"></script>]]></content:encoded>
			<wfw:commentRss>http://code.cheesydesign.com/?feed=rss2&amp;p=587</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Reading the Portable Executable (PE) header in C#</title>
		<link>http://code.cheesydesign.com/?p=572</link>
		<comments>http://code.cheesydesign.com/?p=572#comments</comments>
		<pubDate>Tue, 04 May 2010 17:00:06 +0000</pubDate>
		<dc:creator>JohnStewien</dc:creator>
				<category><![CDATA[c#]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Windows]]></category>

		<guid isPermaLink="false">http://code.cheesydesign.com/?p=572</guid>
		<description><![CDATA[My job consists of writing fully custom applications for groups of people. The time pressure of these projects is quite high, so generally people start using the application while I&#8217;m still writing it, which means I write it modularly and add features as I go along. I also fix bugs as they are discovered. My [...]]]></description>
			<content:encoded><![CDATA[<p>My job consists of writing fully custom applications for groups of people. The time pressure of these projects is quite high, so generally people start using the application while I&#8217;m still writing it, which means I write it modularly and add features as I go along. I also fix bugs as they are discovered. My clients are 2 tiered where expert users get a new build first, they test if for a while, and if they think it&#8217;s acceptable they then pass it on to others.</p>
<p>This method of distribution is quite ad-hoc so when a client rings me up and asks me to view their screen to look at something, it&#8217;s useful to know what build they are running. To facillitate this I print the link date in the main Window Title so I instantly have an idea about how old the version is that I am looking at. This date is calculated at run time. To do this requires reading in the Portable Executable (PE) header from the EXE or DLL file that is responsible for updating the Window. As many of the apps I write are in C# I&#8217;ve written a general purpose PE Header reading class in C# which has a utility method for getting the link date of the Calling Assembly.</p>
<p>To get the date simply do this:</p>
<pre class="sh_csharp">DateTime linkDate = PeHeaderReader.GetCallingAssemblyHeader().TimeStamp;</pre>
<p>Here&#8217;s is the complete code:</p>
<pre class="sh_csharp">using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.IO;

namespace _3DViewerControls.Data {

  // Reads in the header information of the Portable Executable format.
  // Provides information such as the date the assembly was compiled.
  public class PeHeaderReader {
    #region File Header Structures

    public struct IMAGE_DOS_HEADER {      // DOS .EXE header
      public UInt16 e_magic;              // Magic number
      public UInt16 e_cblp;               // Bytes on last page of file
      public UInt16 e_cp;                 // Pages in file
      public UInt16 e_crlc;               // Relocations
      public UInt16 e_cparhdr;            // Size of header in paragraphs
      public UInt16 e_minalloc;           // Minimum extra paragraphs needed
      public UInt16 e_maxalloc;           // Maximum extra paragraphs needed
      public UInt16 e_ss;                 // Initial (relative) SS value
      public UInt16 e_sp;                 // Initial SP value
      public UInt16 e_csum;               // Checksum
      public UInt16 e_ip;                 // Initial IP value
      public UInt16 e_cs;                 // Initial (relative) CS value
      public UInt16 e_lfarlc;             // File address of relocation table
      public UInt16 e_ovno;               // Overlay number
      public UInt16 e_res_0;              // Reserved words
      public UInt16 e_res_1;              // Reserved words
      public UInt16 e_res_2;              // Reserved words
      public UInt16 e_res_3;              // Reserved words
      public UInt16 e_oemid;              // OEM identifier (for e_oeminfo)
      public UInt16 e_oeminfo;            // OEM information; e_oemid specific
      public UInt16 e_res2_0;             // Reserved words
      public UInt16 e_res2_1;             // Reserved words
      public UInt16 e_res2_2;             // Reserved words
      public UInt16 e_res2_3;             // Reserved words
      public UInt16 e_res2_4;             // Reserved words
      public UInt16 e_res2_5;             // Reserved words
      public UInt16 e_res2_6;             // Reserved words
      public UInt16 e_res2_7;             // Reserved words
      public UInt16 e_res2_8;             // Reserved words
      public UInt16 e_res2_9;             // Reserved words
      public UInt32 e_lfanew;             // File address of new exe header
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct IMAGE_OPTIONAL_HEADER32 {
      public UInt16 Magic;
      public Byte MajorLinkerVersion;
      public Byte MinorLinkerVersion;
      public UInt32 SizeOfCode;
      public UInt32 SizeOfInitializedData;
      public UInt32 SizeOfUninitializedData;
      public UInt32 AddressOfEntryPoint;
      public UInt32 BaseOfCode;
      public UInt32 BaseOfData;
      public UInt32 ImageBase;
      public UInt32 SectionAlignment;
      public UInt32 FileAlignment;
      public UInt16 MajorOperatingSystemVersion;
      public UInt16 MinorOperatingSystemVersion;
      public UInt16 MajorImageVersion;
      public UInt16 MinorImageVersion;
      public UInt16 MajorSubsystemVersion;
      public UInt16 MinorSubsystemVersion;
      public UInt32 Win32VersionValue;
      public UInt32 SizeOfImage;
      public UInt32 SizeOfHeaders;
      public UInt32 CheckSum;
      public UInt16 Subsystem;
      public UInt16 DllCharacteristics;
      public UInt32 SizeOfStackReserve;
      public UInt32 SizeOfStackCommit;
      public UInt32 SizeOfHeapReserve;
      public UInt32 SizeOfHeapCommit;
      public UInt32 LoaderFlags;
      public UInt32 NumberOfRvaAndSizes;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct IMAGE_OPTIONAL_HEADER64 {
      public UInt16 Magic;
      public Byte MajorLinkerVersion;
      public Byte MinorLinkerVersion;
      public UInt32 SizeOfCode;
      public UInt32 SizeOfInitializedData;
      public UInt32 SizeOfUninitializedData;
      public UInt32 AddressOfEntryPoint;
      public UInt32 BaseOfCode;
      public UInt64 ImageBase;
      public UInt32 SectionAlignment;
      public UInt32 FileAlignment;
      public UInt16 MajorOperatingSystemVersion;
      public UInt16 MinorOperatingSystemVersion;
      public UInt16 MajorImageVersion;
      public UInt16 MinorImageVersion;
      public UInt16 MajorSubsystemVersion;
      public UInt16 MinorSubsystemVersion;
      public UInt32 Win32VersionValue;
      public UInt32 SizeOfImage;
      public UInt32 SizeOfHeaders;
      public UInt32 CheckSum;
      public UInt16 Subsystem;
      public UInt16 DllCharacteristics;
      public UInt64 SizeOfStackReserve;
      public UInt64 SizeOfStackCommit;
      public UInt64 SizeOfHeapReserve;
      public UInt64 SizeOfHeapCommit;
      public UInt32 LoaderFlags;
      public UInt32 NumberOfRvaAndSizes;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct IMAGE_FILE_HEADER {
      public UInt16 Machine;
      public UInt16 NumberOfSections;
      public UInt32 TimeDateStamp;
      public UInt32 PointerToSymbolTable;
      public UInt32 NumberOfSymbols;
      public UInt16 SizeOfOptionalHeader;
      public UInt16 Characteristics;
    }

    #endregion File Header Structures

    #region Private Fields

    // The DOS header
    private IMAGE_DOS_HEADER dosHeader;
    // The file header
    private IMAGE_FILE_HEADER fileHeader;
    // Optional 32 bit file header
    private IMAGE_OPTIONAL_HEADER32 optionalHeader32;
    // Optional 64 bit file header
    private IMAGE_OPTIONAL_HEADER64 optionalHeader64;

    #endregion Private Fields

    #region Public Methods

    public PeHeaderReader(string filePath) {
      // Read in the DLL or EXE and get the timestamp
      using (FileStream stream = new FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read)) {
        BinaryReader reader = new BinaryReader(stream);
        dosHeader = FromBinaryReader&lt;IMAGE_DOS_HEADER&gt;(reader);

        // Add 4 bytes to the offset
        stream.Seek(dosHeader.e_lfanew, SeekOrigin.Begin);

        UInt32 ntHeadersSignature = reader.ReadUInt32();
        fileHeader = FromBinaryReader&lt;IMAGE_FILE_HEADER&gt;(reader);
        if (this.Is32BitHeader) {
          optionalHeader32 = FromBinaryReader&lt;IMAGE_OPTIONAL_HEADER32&gt;(reader);
        }
        else {
          optionalHeader64 = FromBinaryReader&lt;IMAGE_OPTIONAL_HEADER64&gt;(reader);
        }
      }
    }

    // Gets the header of the .NET assembly that called this function
    public static PeHeaderReader GetCallingAssemblyHeader() {
      string pathCallingAssembly = System.Reflection.Assembly.GetCallingAssembly().Location;

      // Get the path to the calling assembly, which is the path to the
      // DLL or EXE that we want the time of
      string filePath = System.Reflection.Assembly.GetCallingAssembly().Location;

      // Get and return the timestamp
      return new PeHeaderReader(filePath);
    }

    // Reads in a block from a file and converts it to the struct
    // type specified by the template parameter
    public static T FromBinaryReader&lt;T&gt;(BinaryReader reader) {
      // Read in a byte array
      byte[] bytes = reader.ReadBytes(Marshal.SizeOf(typeof(T)));

      // Pin the managed memory while, copy it out the data, then unpin it
      GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
      T theStructure = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
      handle.Free();

      return theStructure;
    }

    #endregion Public Methods

    #region Properties

    // Gets if the file header is 32 bit or not
    public bool Is32BitHeader {
      get {
        UInt16 IMAGE_FILE_32BIT_MACHINE = 0x0100;
        return (IMAGE_FILE_32BIT_MACHINE &amp; FileHeader.Characteristics) == IMAGE_FILE_32BIT_MACHINE;
      }
    }

    // Gets the file header
    public IMAGE_FILE_HEADER FileHeader {
      get {
        return fileHeader;
      }
    }

    // Gets the optional header
    public IMAGE_OPTIONAL_HEADER32 OptionalHeader32 {
      get {
        return optionalHeader32;
      }
    }

    // Gets the optional header
    public IMAGE_OPTIONAL_HEADER64 OptionalHeader64 {
      get {
        return optionalHeader64;
      }
    }

    // Gets the timestamp from the file header
    public DateTime TimeStamp {
      get {
        // Timestamp is a date offset from 1970
        DateTime returnValue = new DateTime(1970, 1, 1, 0, 0, 0);

        // Add in the number of seconds since 1970/1/1
        returnValue = returnValue.AddSeconds(fileHeader.TimeDateStamp);
        // Adjust to local timezone
        returnValue += TimeZone.CurrentTimeZone.GetUtcOffset(returnValue);

        return returnValue;
      }
    }

    #endregion Properties
  }
}</pre>
<p>How it works is that it first reads in the old DOS header, at the end of this header is a file offset to the new NT File Header structure. I seek to that position, and read in the NT File Header. From that header I can get the linker time stamp. As this is a general purpose library I also check whether the header is 32 or 64 bit, and read in either the Optional 32 bit Header, or the Optional 64 bit Header, which can then be used however you like. This is how you would get the 32 bit header:</p>
<pre class="sh_csharp">PeHeaderReader reader = new PeHeaderReader("myDllFileLocation");
if (reader.Is32BitHeader)
{
  PeHeaderReader.IMAGE_OPTIONAL_HEADER32 header32 = reader.OptionalHeader32;
}</pre>
<script type="text/javascript" src="/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_csharp.js"></script><script type="text/javascript" src="/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_csharp.js"></script><script type="text/javascript" src="/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_csharp.js"></script>]]></content:encoded>
			<wfw:commentRss>http://code.cheesydesign.com/?feed=rss2&amp;p=572</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>C# STDEV, Plinq, Parallel.For, ForEach, Invoke</title>
		<link>http://code.cheesydesign.com/?p=537</link>
		<comments>http://code.cheesydesign.com/?p=537#comments</comments>
		<pubDate>Mon, 26 Apr 2010 17:00:10 +0000</pubDate>
		<dc:creator>AndrewCocks</dc:creator>
				<category><![CDATA[c#]]></category>

		<guid isPermaLink="false">http://code.cheesydesign.com/?p=537</guid>
		<description><![CDATA[Source: ParallelComparison.zip (8kb)
After completing the STDEV test on Javascript I wondered how fast I could get the C# version to go using some of the new parallel extensions in C# on my dual core non-HT E4500 (so only two threads).  Of course the first problem is that the Parallel Extensions CTP has been taken [...]]]></description>
			<content:encoded><![CDATA[<p><span style="background-color:#FFFCF0;border: 1px solid grey;margin-right:10px;padding:3px">Source: <a href="http://code.cheesydesign.com/wp-content/uploads/2010/04/ParallelComparison.zip" title="Install">ParallelComparison.zip (8kb)</a></span></p>
<p><img src="http://code.cheesydesign.com/wp-content/uploads/2010/04/Vs2010.png" alt="Vs2010" style="float: left; padding: 3px 8px 0px 3px;" />After completing the <a href="http://code.cheesydesign.com/?p=519">STDEV test on Javascript</a> I wondered how fast I could get the C# version to go using some of the new parallel extensions in C# on my dual core non-HT E4500 (so only two threads).  Of course the first problem is that the Parallel Extensions CTP has been taken down but fortunately there&#8217;s still a way to get PFX via downloading the <a href="http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx">Reactive Framework</a>.  With that done I started out by using Plinq&#8217;s simple AsParallel to directly convert the Alglib STDEV implementation to Linq and then add the AsParallel but soon ran into problem with the execution time ballooning out.  To eliminate variables I reverted to a simple calculation of the mean.  The problem there is that the CPU is so fast that it is difficult to measure so I decided to run the mean over an array of 100M doubles 5 times and take the average.  Since I was doing a comparison of various methods anyway I thought I&#8217;d thrown in some for vs foreach comparisons and try &#8220;hoisting&#8221; the length into a local variable. See also: <a href="http://msmvps.com/blogs/jon_skeet/archive/2009/01/29/for-vs-foreach-on-arrays-and-lists.aspx">Jon Skeet: For vs Foreach (with hoisting)</a>.</p>
<p>The various mean variants I tried are below:
<ul>
<li>calc_mean: Basic calculation of the mean with a for loop</li>
<li>hoist_mean: Take the array.Length out of the loop test into a local variable</li>
<li>func_mean: What&#8217;s the overhead of making a function call, is C# able to inline it?</li>
<li>f_hoist_mean: Use both a functional call and hoist</li>
<li>linq_mean: Use Linq</li>
<li>plinq_mean: Use Parallel Linq</li>
<li>foreach_mean: Same as calc_mean but with foreach rather than for</li>
<li>pfor_mean: Use Parallel.For</li>
<li>pforeach_mean: Use Parallel.ForEach</li>
<li>part_mean: Use Parallel.invoke with custom problem partitioning (split in half)</li>
</ul>
<p>Once the mean was done I tried some stdev variants:</p>
<ul>
<li>calc_stddev: Implementation for Alglib</li>
<li>part_stddev: Parallel invoke with custom partition of the data</li>
<li>part2_stddev: Parallel invoke with custom partition of the algorithm</li>
</ul>
<p>Lastly I used two different timing techniques:</p>
<ul>
<li>Time(Action): Straightforward timing with the Stopwatch (in ms)</li>
<li>pTime(Action): Timing the runs in parallel</li>
</ul>
<p>Here&#8217;s the C# code:</p>
<pre class="sh_csharp">
using System;
using System.Linq;
using System.Text;
using System.Linq.Parallel;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

using System.Reflection;
using System.Collections.Generic;

namespace ParallelComparison
{
    class Program
    {
        static int array_size = (int)1e8; // 800MiB
        static int loop_count = 5;

        #region Mean

        public static double calc_mean(double[] x)
        {
            double mean = 0.0;

            for (int i = 0; i &lt; x.Length; i++)
            {
                mean += x[i];
            }

            return mean / x.Length;
        }

        public static double hoist_mean(double[] x)
        {
            double mean = 0.0;
            int len = x.Length;

            for (int i = 0; i &lt; len; i++)
            {
                mean += x[i];
            }

            return mean / x.Length;
        }

        private static double add(double a, double b) { return a + b; }

        public static double func_mean(double[] x)
        {
            double mean = 0.0;

            for (int i = 0; i &lt; x.Length; i++)
            {
                mean = add(mean, x[i]);
            }

            return mean / x.Length;
        }

        public static double f_hoist_mean(double[] x)
        {
            double mean = 0.0;
            int len = x.Length;

            for (int i = 0; i &lt; len; i++)
            {
                mean = add(mean, x[i]);
            }

            return mean / x.Length;
        }

        public static double linq_mean(double[] x)
        {
            return x.Average&lt;double&gt;(a =&gt; a);
        }

        public static double plinq_mean(double[] x)
        {
            return x.AsParallel().Average&lt;double&gt;(a =&gt; a);
        }

        public static double foreach_mean(double[] x)
        {
            double mean = 0.0;

            foreach (double a in x)
            {
                mean += a;
            }
            return mean / x.Length;
        }

        public static double pfor_mean(double[] x)
        {
            double mean = 0.0;

            object syncObj = new object();

            Parallel.For&lt;double&gt;(0,x.Length,() =&gt; 0.0, (i, ls, sum) =&gt;
            {
                sum += x[i];
                return sum;
            }, sum =&gt; { lock (syncObj) mean += sum; });

            return mean / x.Length;
        }

        public static double pforeach_mean(double[] x)
        {
            double mean = 0.0;

            object syncObj = new object();

            Parallel.ForEach&lt;double, double&gt;(x, () =&gt; 0.0, (a, state, sum) =&gt;
            {
                sum += a;
                return sum;
            }, sum =&gt; { lock (syncObj) mean += sum; });

            return mean / x.Length;
        }

        public static double part_mean2(double[] x, int start, int end)
        {
            double mean = 0.0;

            for (int i = start; i &lt; end; i++)
            {
                mean += x[i];
            }

            return mean;
        }

        public static double part_mean(double[] x)
        {
            double left = 0.0, right = 0.0;

            Parallel.Invoke(() =&gt; left = part_mean2(x, 0, x.Length / 2),
                            () =&gt; right = part_mean2(x, x.Length / 2, x.Length));

            return (left + right) / x.Length;
        }

        #endregion

        #region Timing
        static double Time(Action action)
        {
            var sw = Stopwatch.StartNew();
            for (int i = 0; i &lt; loop_count; i++)
            {
                action();
            }
            return sw.Elapsed.TotalMilliseconds / loop_count;
        }

        static double pTime(Action action)
        {
            var sw = Stopwatch.StartNew();
            Parallel.For(0, loop_count, (a) =&gt; action());
            return sw.Elapsed.TotalMilliseconds / loop_count;
        }
        #endregion

        #region Stdev
        public static void v2_part(double[] x, double mean, out double v1, out double v2, int start, int end)
        {
            v1 = 0.0; v2 = 0.0;
            for(int i = start; i &lt; end; i++) {
                v2 = v2 + (x[i] - mean);
                v1 = v1 + (x[i] - mean) * (x[i] - mean);
            }
        }

        public static double fv1(double[] x, double mean)
        {
            double v1 = 0.0;
            foreach(double a in x) {
                v1 += (a - mean) * (a - mean);
            }

            return v1;
        }

        public static double fv2(double[] x, double mean)
        {
            double v2 = 0.0;
            foreach(double a in x) {
                v2 += (a - mean);
            }
            return v2;
        }

        public static void calc_stddev(double[] x, int n, out double stddev, out double mean, bool fmean)
        {

            double v1 = 0;
            double v2 = 0;
            double variance;
            mean = 0.0; stddev = 0.0;

            if (fmean)
            {
                for (int i = 0; i &lt; x.Length; i++)
                {
                    mean += x[i];
                }
                mean /= x.Length;
            }

            //
            // Variance (using corrected two-pass algorithm)
            //
            if (n != 1)
            {
                v1 = 0; v2 = 0;

                for (int i = 0; i &lt; n; i++)
                {
                    v2 += (x[i] - mean);
                    v1 += (x[i] - mean) * (x[i] - mean);
                }

                v2 = v2 * v2 / n;
                variance = (v1 - v2) / (n - 1);
                if ((double)(variance) &lt; (double)(0))
                {
                    variance = 0;
                }
                stddev = Math.Sqrt(variance);
            }
        }

        public static void part_stddev(double[] x, int n, out double stddev, double mean, bool fmean)
        {
            mean = 0.0; stddev = 0.0;

            if (fmean)
            {
                mean = part_mean(x);
            }

            //
            // Variance (using corrected two-pass algorithm)
            //
            if (n != 1)
            {
                double v1 = 0;
                double v2 = 0;
                double variance;

                double v1_left = 0.0, v1_right = 0.0;
                double v2_left = 0.0, v2_right = 0.0;

                Parallel.Invoke(() =&gt; v2_part(x, mean, out v1_left, out v2_left, 0, x.Length / 2),
                                () =&gt; v2_part(x, mean, out v1_right, out v2_right, x.Length / 2, x.Length));

                v1 = v1_left + v1_right;
                v2 = v2_left + v2_right;

                v2 = v2 * v2 / n;
                variance = (v1 - v2) / (n - 1);
                if ((double)(variance) &lt; (double)(0))
                {
                    variance = 0;
                }
                stddev = Math.Sqrt(variance);
            }
        }

        public static void part2_stddev(double[] x, int n, out double stddev, double mean, bool fmean)
        {
            mean = 0.0; stddev = 0.0;

            if (fmean)
            {
                mean = part_mean(x);
            }

            //
            // Variance (using corrected two-pass algorithm)
            //
            if (n != 1)
            {
                double v1 = 0;
                double v2 = 0;
                double variance;

                Parallel.Invoke(() =&gt; v1 = fv1(x, mean),
                                () =&gt; v2 = fv2(x, mean));

                v2 = v2 * v2 / n;
                variance = (v1 - v2) / (n - 1);
                if ((double)(variance) &lt; (double)(0))
                {
                    variance = 0;
                }
                stddev = Math.Sqrt(variance);
            }
        }
        #endregion

        public struct data { public string name; public double ms; };

        static void Main()
        {
#if(DEBUG)
                    Console.WriteLine(&quot;Warning: benchmarking in debug mode will not produce meaningful results!&quot;);
#endif

            double[] array = new double[array_size];
            for (int i = 0; i &lt; array.Length; ++i)
            {
                array[i] = i%10 + 1000000000;
            }

            int [] nums = {0,1,2,3};

            List&lt;data&gt;[] all = new List&lt;data&gt;[nums.Length];

            foreach (int i in nums)
            {
                Console.WriteLine(loop_count + &quot; loops over &quot; + sizeof(double) * array_size / 1e6 + &quot; MiB, RAM-&gt;CPU predicted memcopy time: &quot; + (sizeof(double) * array_size) / 3.2e6 + &quot; ms&quot;);

                var methods = ((MethodInfo[])typeof(Program).GetMethods(BindingFlags.Public | BindingFlags.Static)).Where((a) =&gt; (a.Name.EndsWith(&quot;_mean&quot;)));

                List&lt;data&gt; trial = new List&lt;data&gt;(methods.Count());

                foreach (var m in methods)
                {
                    trial.Add(new data { name = m.Name, ms = Math.Round(Time(() =&gt; m.Invoke(null, new object[] { array })),i) });
                }

                trial.Add(new data { name = &quot;pTime(foreach)&quot;, ms = Math.Round(pTime(() =&gt; foreach_mean(array)),i) });

                all[i] = trial;

                double stddev = 0.0, mean = 0.0;

                Console.Write(&quot;part_stdev:\t&quot; + Time(() =&gt; part_stddev(array, array.Length, out stddev, mean, true)));
                Console.WriteLine(&quot;\t &quot; + stddev);
                Console.Write(&quot;part2_stdev:\t&quot; + Time(() =&gt; part2_stddev(array, array.Length, out stddev, mean, true)));
                Console.WriteLine(&quot;\t &quot; + stddev);
                Console.Write(&quot;calc_stdev:\t&quot; + Time(() =&gt; calc_stddev(array, array.Length, out stddev, out mean, true)));
                Console.WriteLine(&quot;\t &quot; + stddev);

                array_size /= 10;
                loop_count *= 10;

                Array.Resize&lt;double&gt;(ref array, array_size);
            }

            var q = from a in all[0]
                    join b in all[1] on a.name equals b.name
                    join c in all[2] on a.name equals c.name
                    join d in all[3] on a.name equals d.name
                    orderby a.ms descending
                    select new { a.name, m800 = a.ms, m80 = b.ms, m8 = c.ms, m08 = d.ms };

            Console.WriteLine(); Console.WriteLine(&quot;\t\t800MiB\t80MiB\t8MiB\t0.8MiB&quot;);
            foreach (var r in q) {
                Console.WriteLine(r.name + &quot;\t&quot; + r.m800 + &quot;\t&quot; + r.m80 + &quot;\t&quot; + r.m8 + &quot;\t&quot; + r.m08);
            }
        }
    }
}
</pre>
<p>The first few times I ran this I noticed a problem &#8211; no matter what changes I made, many of the functions all ran at around the same speed.  With 100M doubles basically what is happening is that 800MiB is being shuffled across the front side bus from the memory into the CPU and it turns out the FSB speed is the limiting factor.  Using <a href="">CPU-Z</a> we can see that my machine, while DDR2, has only a single DIMM and is thus only single channel, so while the memory is PC2-6400 with a theoretical max bandwidth of 6.4GB/s my machine can only achieve half that.</p>
<p><div align="center">
<img src="http://code.cheesydesign.com/wp-content/uploads/2010/04/CPUZ_memory.png"/>
</div>
</p>
<p>One way to test the actual memory bandwidth is with the <a href="http://www.streambench.org/">STREAM Benchmark</a> which gives the following results on my machine:</p>
<pre class="console">
C:\Stream>stream5.8_omp-32.exe
Unknown Minor OS Version (6.1)
OS Build number 7600
Service Pack Level:
-------------------------------------------------------------
STREAM version $Revision: 5.8 $
-------------------------------------------------------------
This system uses 8 bytes per DOUBLE PRECISION word.
-------------------------------------------------------------
Array size = 10000000, Offset = 0
Total memory required = 228.9 MB.
Each test is run 40 times, but only
the *best* time for each is used.
-------------------------------------------------------------
Number of Threads requested = 2
-------------------------------------------------------------
Printing one line per active thread....
Printing one line per active thread....
-------------------------------------------------------------
Your clock granularity/precision appears to be 1 microseconds.
Each test below will take on the order of 67617 microseconds.
   (= 67617 clock ticks)
Increase the size of the arrays if this shows that
you are not getting at least 20 clock ticks per test.
-------------------------------------------------------------
WARNING -- The above is only a rough guideline.
For best results, please be sure you know the
precision of your system timer.
-------------------------------------------------------------
Function      Rate (MB/s)   Avg time     Min time     Max time
Copy:        3013.0788       0.0569       0.0531       0.1064
Scale:       3008.6747       0.0570       0.0532       0.0849
Add:         2904.1052       0.0908       0.0826       0.2312
Triad:       2906.7409       0.0886       0.0826       0.1591
-------------------------------------------------------------
Solution Validates
-------------------------------------------------------------
</pre>
<p>I decided to run the program multiple times with different sized input arrays from 800MiB down to 0.8MiB, noting that the L2 cache on this machine is 2MB so hopefully the input array will be cached with the smallest array test.  I ran through 5,50,500 and 5000 loops as the array size decreased.  Here are the results (all times in ms):</p>
<div align="center">
<div style="float:left">
<table border=1>
<tr>
<th colspan=5>VS2010 (.NET 4.0)
<th></tr>
<tr>
<td></td>
<td>800 MiB&nbsp;</td>
<td>80 MiB&nbsp;</td>
<td>8 MiB&nbsp;</td>
<td>0.8 MiB&nbsp;</td>
</tr>
<tr>
<td>plinq_mean</td>
<td>2661</td>
<td>276.3</td>
<td>27.86</td>
<td>2.918</td>
</tr>
<tr>
<td>linq_mean</td>
<td>2636</td>
<td>285.8</td>
<td>28.47</td>
<td>2.819</td>
</tr>
<tr>
<td>pforeach_mean</td>
<td>1369</td>
<td>142</td>
<td>11.98</td>
<td>1.192</td>
</tr>
<tr>
<td>pfor_mean</td>
<td>763</td>
<td>91.6</td>
<td>9.12</td>
<td>0.902</td>
</tr>
<tr>
<td>f_hoist_mean</td>
<td>225</td>
<td>21.9</td>
<td>2.32</td>
<td>0.141</td>
</tr>
<tr>
<td>hoist_mean</td>
<td>220</td>
<td>21.9</td>
<td>2.29</td>
<td>0.142</td>
</tr>
<tr>
<td>part_mean</td>
<td>219</td>
<td>23.4</td>
<td>2.23</td>
<td>0.093</td>
</tr>
<tr>
<td>func_mean</td>
<td>217</td>
<td>21.6</td>
<td>2.26</td>
<td>0.142</td>
</tr>
<tr>
<td>calc_mean</td>
<td>216</td>
<td>21.5</td>
<td>2.29</td>
<td>0.142</td>
</tr>
<tr>
<td>foreach_mean</td>
<td>216</td>
<td>21.5</td>
<td>2.17</td>
<td>0.142</td>
</tr>
<tr>
<td>pTime(foreach)</td>
<td>199</td>
<td>22.7</td>
<td>1.64</td>
<td>0.069</td>
</tr>
</table>
</div>
<div>
<table border=1>
<tr>
<th colspan=5>VS2008 (.NET 3.5 with PFX)
<th></tr>
<tr>
<td></td>
<td>800 MiB&nbsp;</td>
<td>80 MiB&nbsp;</td>
<td>8 MiB&nbsp;</td>
<td>0.8 MiB&nbsp;</td>
</tr>
<tr>
<td>plinq_mean</td>
<td>2877</td>
<td>319.7</td>
<td>27.2</td>
<td>2.77</td>
</tr>
<tr>
<td>linq_mean</td>
<td>2352</td>
<td>259.5</td>
<td>31.71</td>
<td>2.279</td>
</tr>
<tr>
<td>pforeach_mean</td>
<td>1393</td>
<td>119.2</td>
<td>11.93</td>
<td>1.173</td>
</tr>
<tr>
<td>pfor_mean</td>
<td>900</td>
<td>106.3</td>
<td>10.08</td>
<td>0.975</td>
</tr>
<tr>
<td>part_mean</td>
<td>262</td>
<td>26.7</td>
<td>2.26</td>
<td>0.091</td>
</tr>
<tr>
<td>calc_mean</td>
<td>258</td>
<td>32.6</td>
<td>2.34</td>
<td>0.141</td>
</tr>
<tr>
<td>f_hoist_mean</td>
<td>242</td>
<td>28.8</td>
<td>2.21</td>
<td>0.142</td>
</tr>
<tr>
<td>hoist_mean</td>
<td>240</td>
<td>27.7</td>
<td>2.29</td>
<td>0.142</td>
</tr>
<tr>
<td>func_mean</td>
<td>232</td>
<td>26</td>
<td>2.17</td>
<td>0.142</td>
</tr>
<tr>
<td>foreach_mean</td>
<td>223</td>
<td>21.7</td>
<td>2.18</td>
<td>0.141</td>
</tr>
<tr>
<td>pTime(foreach)</td>
<td>219</td>
<td>20.3</td>
<td>1.61</td>
<td>0.07</td>
</tr>
</table>
</div>
</div>
<p>And for the STDEV:</p>
<div align="center">
<div style="float:left">
<table border=1>
<tr>
<th colspan=5>VS2010 (.NET 4.0)
<th></tr>
<tr>
<td></td>
<td>800 MiB&nbsp;</td>
<td>80 MiB&nbsp;</td>
<td>8 MiB&nbsp;</td>
<td>0.8 MiB&nbsp;</td>
</tr>
<tr>
<td>part2_stdev</td>
<td>1009</td>
<td>106.6</td>
<td>10.62</td>
<td>1.132</td>
</tr>
<tr>
<td>calc_stdev</td>
<td>675</td>
<td>98.5</td>
<td>6.73</td>
<td>0.610</td>
</tr>
<tr>
<td>part_stdev</td>
<td>904</td>
<td>89.2</td>
<td>8.98</td>
<td>0.941</td>
</tr>
</table>
</div>
<div>
<table border=1>
<tr>
<th colspan=5>VS2008 (.NET 3.5 with PFX)
<th></tr>
<tr>
<td></td>
<td>800 MiB&nbsp;</td>
<td>80 MiB&nbsp;</td>
<td>8 MiB&nbsp;</td>
<td>0.8 MiB&nbsp;</td>
</tr>
<tr>
<td>part_stdev</td>
<td>908</td>
<td>86.4</td>
<td>8.69</td>
<td>0.890</td>
</tr>
<tr>
<td>calc_stdev</td>
<td>703</td>
<td>248.9</td>
<td>9.88</td>
<td>0.919</td>
</tr>
<tr>
<td>part2_stdev</td>
<td>615</td>
<td>45.9</td>
<td>4.66</td>
<td>0.304</td>
</tr>
</table>
</div>
</div>
<p>We can clearly see the speed limitation imposed by the memory bus bandwidth with many implementations.  For the 800,80,8 and 0.8 data sizes my machine&#8217;s memory bandwidth of 3.2GB/s predicts minimum memory copy times of 250, 25, 2.5 and 0.25 ms.  One way to reduce this would be to copy less data, possibly using ints or even shorts.  I didn&#8217;t want to re-implement using ints so I made a brief investigation of the available Generic Numeric programming techniques available.  Of the two I found, <a href="http://www.yoda.arachsys.com/csharp/miscutil/usage/genericoperators.html">MiscUtil</a> and <a href="http://www.codeproject.com/KB/cs/genericnumerics.aspx">Generic Numerics</a> only the second implemented operators which would allow me to use generics without changing the code, thus allowing it to be turned on and off for comparison.  Conveniently the downloadable project includes a performance comparison between the straight code and generics, and here is the partial result:</p>
<pre class="console">
Non-generic standard deviation of 1000000 int elements
Method TestListSigma took 00:00:00.0079411
Generic standard deviation of 1000000 int elements
Method TestListSigmaG took 00:00:00.0050658
Generic standard deviation of 1000000 int elements using wrapper structs
Method TestListSigmaG2 took 00:00:00.0147550
Generic standard deviation of 1000000 int elements using overflow checks
Method TestListSigmaG3 took 00:00:00.0059253
</pre>
<p>Of these methods it is SigmaG2 which offers the use of standard operators &#8230; and is also the slowest, taking nearly three times longer than the fastest method.  I didn&#8217;t want to make code change just for generics and a factor of 3x slowdown would invalidate any performance differences between data types so I abandoned that approach and stuck with doubles.</p>
<h3>Conclusion</h3>
<p>
<h4>Mean:</h4>
<p>A quick scan of the mean results set shows that VS2010 was generally as fast as VS2008 on everything.  Although the larger sizes do benefit a little  from caching (able to beat their predicted times by small amounts) the test is primarily memory bandwidth limited.  It is only with the smaller tests, where the dataset is cached, that we start to measure the performance of the actual code.  However at no input array size do the parallel versions of the code match the straightforward implementations, except where runs are timed in parallel, rather than the actual function itself being parallel and then the boost is significant.  For large data sets where there isn&#8217;t much work to be done there is no benefit to making the code parallel.  Of interest is the poor performance of the Linq and Plinq variants which are vastly slower than any other method.  MS has a paper describing <a href="http://services.social.microsoft.com/feeds/FeedItem?feedId=639a99a9-ff25-4062-b61d-a86ea9d66a06&#038;itemId=a611e616-779e-4bb9-b88f-8ab228165a82&#038;title=When+Should+I+Use+Parallel.ForEach%3f+When+Should+I+Use+PLINQ%3f&#038;uri=http%3a%2f%2fdownload.microsoft.com%2fdownload%2fB%2fC%2fF%2fBCFD4868-1354-45E3-B71B-B851CD78733D%2fWhenToUseParallelForEachOrPLINQ.pdf&#038;k=gAdKnW7xH8RXzlALrQceTdMvpCzxVujB07sMnqbwvgM%3d">when to use Plinq and when to use Parallel.For</a>.  In my testing Parallel.For and Parallel.ForEach also didn&#8217;t fare well with the various overheads, data partitioning, locking and extra function calls ruining their performance.  While these do offer user defined partitioning <a href="http://www.drdobbs.com/visualstudio/224600406">(Partitioner.Create)</a> Parallel.For and Parallel.Foreach were so slow that I didn&#8217;t bother trying anything other than default partitioning.  However this is an interesting area and the <a href="http://blogs.msdn.com/pfxteam/archive/2009/12/09/9934811.aspx">VisualizePartioning example</a> from the PFX team blog is worth a look.  Here&#8217;s a screenshot showing how the Parallel.For is load balanced where there are 2 cores:</p>
<p>
<div align="center"><img src="http://code.cheesydesign.com/wp-content/uploads/2010/04/VisualizePartitioning.png"/></div>
</p>
<p>
<h4>Stdev:</h4>
<p>The story is different here where there is just enough work to be done for us to start to see a benefit to parallel programming although only with VS 2008.  With VS 2010 the best implementation was single threaded and it took nearly 4x longer to run the part2_stdev function than VS 2008 did.  VS 2010 did have the best performing single threaded results.</p>
<p>
<h4>Overall</h4>
<p>Be careful when performance testing to make sure you test what you planned to, for most array sizes this ended up being a test of how fast the Front Side Bus could push data from memery into the CPU rather than the code&#8217;s speed.  The various for vs foreach vs function calls vs hoisting variants &#8211; little difference on this dataset, although foreach without hoisting or using function calls is consistently near the top.  Don&#8217;t bother with parallel implementations unless there is a lot of varied work going on in each loop.  Making a parallel version of calc_mean was pointless.  Don&#8217;t convert code to use Linq if you are interested in performance as Linq and Plinq turned out to be the slowest variants by far, with the Plinq mean taking 20x as long as the single threaded foreach on 0.8MiB test.  Lastly I&#8217;m not sure what happened with the 80MiB calc_stdev test where it took nearly 250ms, looks like an anomaly but really, what dataset would be complete without at least one unexplained anomaly?</p>
<script type="text/javascript" src="/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_csharp.js"></script>]]></content:encoded>
			<wfw:commentRss>http://code.cheesydesign.com/?feed=rss2&amp;p=537</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>
